Skip to content

Port #[used] to new attribute parsing infrastructure #142818

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions compiler/rustc_attr_data_structures/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,17 @@ impl Deprecation {
}
}

/// There are three valid forms of the attribute:
/// `#[used]`, which is semantically equivalent to `#[used(linker)]` except that the latter is currently unstable.
/// `#[used(compiler)]`
/// `#[used(linker)]`
#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[derive(HashStable_Generic, PrintAttribute)]
pub enum UsedBy {
Compiler,
Linker,
}

/// Represents parsed *built-in* inert attributes.
///
/// ## Overview
Expand Down Expand Up @@ -252,5 +263,8 @@ pub enum AttributeKind {
/// Span of the attribute.
span: Span,
},

/// Represents `#[used]`
Used { used_by: UsedBy, span: Span },
// tidy-alphabetical-end
}
97 changes: 93 additions & 4 deletions compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use rustc_attr_data_structures::{AttributeKind, OptimizeAttr};
use rustc_attr_data_structures::lints::AttributeLintKind;
use rustc_attr_data_structures::{AttributeKind, OptimizeAttr, UsedBy};
use rustc_feature::{AttributeTemplate, template};
use rustc_span::sym;
use rustc_session::parse::feature_err;
use rustc_span::{Span, sym};

use super::{AttributeOrder, OnDuplicate, SingleAttributeParser};
use crate::context::{AcceptContext, Stage};
use super::{AcceptMapping, AttributeOrder, AttributeParser, OnDuplicate, SingleAttributeParser};
use crate::context::{AcceptContext, FinalizeContext, Stage};
use crate::parser::ArgParser;

pub(crate) struct OptimizeParser;
Expand Down Expand Up @@ -56,3 +58,90 @@ impl<S: Stage> SingleAttributeParser<S> for ColdParser {
Some(AttributeKind::Cold(cx.attr_span))
}
}

#[derive(Default)]
pub(crate) struct UsedParser {
first_compiler: Option<Span>,
first_linker: Option<Span>,
}

// A custom `AttributeParser` is used rather than a Simple attribute parser because
// - Specifying two `#[used]` attributes is a warning (but will be an error in the future)
// - But specifying two conflicting attributes: `#[used(compiler)]` and `#[used(linker)]` is already an error today
// We can change this to a Simple parser once the warning becomes an error
impl<S: Stage> AttributeParser<S> for UsedParser {
const ATTRIBUTES: AcceptMapping<Self, S> = &[(
&[sym::used],
template!(Word, List: "compiler|linker"),
|group: &mut Self, cx, args| {
let used_by = match args {
ArgParser::NoArgs => UsedBy::Linker,
ArgParser::List(list) => {
let Some(l) = list.single() else {
cx.expected_single_argument(list.span);
return;
};

match l.meta_item().and_then(|i| i.path().word_sym()) {
Some(sym::compiler) => {
if !cx.features().used_with_arg() {
feature_err(
&cx.sess(),
sym::used_with_arg,
cx.attr_span,
"`#[used(compiler)]` is currently unstable",
)
.emit();
}
UsedBy::Compiler
}
Some(sym::linker) => {
if !cx.features().used_with_arg() {
feature_err(
&cx.sess(),
sym::used_with_arg,
cx.attr_span,
"`#[used(linker)]` is currently unstable",
)
.emit();
}
UsedBy::Linker
}
_ => {
cx.expected_specific_argument(l.span(), vec!["compiler", "linker"]);
return;
}
}
}
ArgParser::NameValue(_) => return,
};

let target = match used_by {
UsedBy::Compiler => &mut group.first_compiler,
UsedBy::Linker => &mut group.first_linker,
};

if let Some(prev) = *target {
cx.emit_lint(
AttributeLintKind::UnusedDuplicate {
this: cx.attr_span,
other: prev,
warning: false,
},
cx.attr_span,
);
} else {
*target = Some(cx.attr_span);
}
},
)];

fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
// Ratcheting behaviour, if both `linker` and `compiler` are specified, use `linker`
Some(match (self.first_compiler, self.first_linker) {
(_, Some(span)) => AttributeKind::Used { used_by: UsedBy::Linker, span },
(Some(span), _) => AttributeKind::Used { used_by: UsedBy::Compiler, span },
(None, None) => return None,
})
}
}
3 changes: 2 additions & 1 deletion compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use rustc_session::Session;
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};

use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser};
use crate::attributes::codegen_attrs::{ColdParser, OptimizeParser};
use crate::attributes::codegen_attrs::{ColdParser, OptimizeParser, UsedParser};
use crate::attributes::confusables::ConfusablesParser;
use crate::attributes::deprecation::DeprecationParser;
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
Expand Down Expand Up @@ -97,6 +97,7 @@ attribute_parsers!(
ConfusablesParser,
ConstStabilityParser,
StabilityParser,
UsedParser,
// tidy-alphabetical-end

// tidy-alphabetical-start
Expand Down
2 changes: 0 additions & 2 deletions compiler/rustc_codegen_ssa/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,6 @@ codegen_ssa_error_writing_def_file =

codegen_ssa_expected_name_value_pair = expected name value pair

codegen_ssa_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`

codegen_ssa_extern_funcs_not_found = some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified

codegen_ssa_extract_bundled_libs_archive_member = failed to get data from archive member '{$rlib}': {$error}
Expand Down
44 changes: 5 additions & 39 deletions compiler/rustc_codegen_ssa/src/codegen_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use rustc_abi::ExternAbi;
use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode};
use rustc_ast::{LitKind, MetaItem, MetaItemInner, attr};
use rustc_attr_data_structures::{
AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr, ReprAttr, find_attr,
AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr, ReprAttr, UsedBy, find_attr,
};
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
Expand Down Expand Up @@ -122,6 +122,10 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
}
AttributeKind::Cold(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD,
AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align),
AttributeKind::Used { used_by, .. } => match used_by {
UsedBy::Compiler => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_COMPILER,
UsedBy::Linker => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER,
},
_ => {}
}
}
Expand Down Expand Up @@ -166,44 +170,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
sym::rustc_std_internal_symbol => {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL
}
sym::used => {
let inner = attr.meta_item_list();
match inner.as_deref() {
Some([item]) if item.has_name(sym::linker) => {
if !tcx.features().used_with_arg() {
feature_err(
&tcx.sess,
sym::used_with_arg,
attr.span(),
"`#[used(linker)]` is currently unstable",
)
.emit();
}
codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER;
}
Some([item]) if item.has_name(sym::compiler) => {
if !tcx.features().used_with_arg() {
feature_err(
&tcx.sess,
sym::used_with_arg,
attr.span(),
"`#[used(compiler)]` is currently unstable",
)
.emit();
}
codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_COMPILER;
}
Some(_) => {
tcx.dcx().emit_err(errors::ExpectedUsedSymbol { span: attr.span() });
}
None => {
// Unconditionally using `llvm.used` causes issues in handling
// `.init_array` with the gold linker. Luckily gold has been
// deprecated with GCC 15 and rustc now warns about using gold.
codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER
}
}
}
sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL,
sym::track_caller => {
let is_closure = tcx.is_closure_like(did.to_def_id());
Expand Down
7 changes: 0 additions & 7 deletions compiler/rustc_codegen_ssa/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -733,13 +733,6 @@ pub struct UnknownArchiveKind<'a> {
pub kind: &'a str,
}

#[derive(Diagnostic)]
#[diag(codegen_ssa_expected_used_symbol)]
pub(crate) struct ExpectedUsedSymbol {
#[primary_span]
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(codegen_ssa_multiple_main_functions)]
#[help]
Expand Down
3 changes: 0 additions & 3 deletions compiler/rustc_passes/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -809,9 +809,6 @@ passes_unused_variable_try_prefix = unused variable: `{$name}`
.suggestion = if this is intentional, prefix it with an underscore


passes_used_compiler_linker =
`used(compiler)` and `used(linker)` can't be used together

passes_used_static =
attribute must be applied to a `static` variable
.label = but this is a {$target}
Expand Down
50 changes: 10 additions & 40 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
Attribute::Parsed(AttributeKind::MayDangle(attr_span)) => {
self.check_may_dangle(hir_id, *attr_span)
}
Attribute::Parsed(AttributeKind::Used { span: attr_span, .. }) => {
self.check_used(*attr_span, target, span);
}
Attribute::Unparsed(attr_item) => {
style = Some(attr_item.style);
match attr.path().as_slice() {
Expand Down Expand Up @@ -311,7 +314,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
| sym::cfi_encoding // FIXME(cfi_encoding)
| sym::pointee // FIXME(derive_coerce_pointee)
| sym::omit_gdb_pretty_printer_section // FIXME(omit_gdb_pretty_printer_section)
| sym::used // handled elsewhere to restrict to static items
| sym::instruction_set // broken on stable!!!
| sym::windows_subsystem // broken on stable!!!
| sym::patchable_function_entry // FIXME(patchable_function_entry)
Expand Down Expand Up @@ -381,7 +383,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
}

self.check_repr(attrs, span, target, item, hir_id);
self.check_used(attrs, target, span);
self.check_rustc_force_inline(hir_id, attrs, span, target);
}

Expand Down Expand Up @@ -2202,44 +2203,13 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
}
}

fn check_used(&self, attrs: &[Attribute], target: Target, target_span: Span) {
let mut used_linker_span = None;
let mut used_compiler_span = None;
for attr in attrs.iter().filter(|attr| attr.has_name(sym::used)) {
if target != Target::Static {
self.dcx().emit_err(errors::UsedStatic {
attr_span: attr.span(),
span: target_span,
target: target.name(),
});
}
let inner = attr.meta_item_list();
match inner.as_deref() {
Some([item]) if item.has_name(sym::linker) => {
if used_linker_span.is_none() {
used_linker_span = Some(attr.span());
}
}
Some([item]) if item.has_name(sym::compiler) => {
if used_compiler_span.is_none() {
used_compiler_span = Some(attr.span());
}
}
Some(_) => {
// This error case is handled in rustc_hir_analysis::collect.
}
None => {
// Default case (compiler) when arg isn't defined.
if used_compiler_span.is_none() {
used_compiler_span = Some(attr.span());
}
}
}
}
if let (Some(linker_span), Some(compiler_span)) = (used_linker_span, used_compiler_span) {
self.tcx
.dcx()
.emit_err(errors::UsedCompilerLinker { spans: vec![linker_span, compiler_span] });
fn check_used(&self, attr_span: Span, target: Target, target_span: Span) {
if target != Target::Static {
self.dcx().emit_err(errors::UsedStatic {
attr_span,
span: target_span,
target: target.name(),
});
}
}

Expand Down
7 changes: 0 additions & 7 deletions compiler/rustc_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -611,13 +611,6 @@ pub(crate) struct UsedStatic {
pub target: &'static str,
}

#[derive(Diagnostic)]
#[diag(passes_used_compiler_linker)]
pub(crate) struct UsedCompilerLinker {
#[primary_span]
pub spans: Vec<Span>,
}

#[derive(Diagnostic)]
#[diag(passes_allow_internal_unstable)]
pub(crate) struct AllowInternalUnstable {
Expand Down
15 changes: 12 additions & 3 deletions tests/ui/attributes/used_with_arg.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![deny(unused_attributes)]
#![feature(used_with_arg)]

#[used(linker)]
Expand All @@ -6,14 +7,22 @@ static mut USED_LINKER: [usize; 1] = [0];
#[used(compiler)]
static mut USED_COMPILER: [usize; 1] = [0];

#[used(compiler)] //~ ERROR `used(compiler)` and `used(linker)` can't be used together
#[used(compiler)]
#[used(linker)]
static mut USED_COMPILER_LINKER2: [usize; 1] = [0];

#[used(compiler)] //~ ERROR `used(compiler)` and `used(linker)` can't be used together
#[used(linker)]
#[used(compiler)]
#[used(linker)]
#[used(compiler)] //~ ERROR unused attribute
#[used(linker)] //~ ERROR unused attribute
static mut USED_COMPILER_LINKER3: [usize; 1] = [0];

#[used(compiler)]
#[used]
static mut USED_WITHOUT_ATTR1: [usize; 1] = [0];

#[used(linker)]
#[used] //~ ERROR unused attribute
static mut USED_WITHOUT_ATTR2: [usize; 1] = [0];

fn main() {}
Loading
Loading