Skip to content

Commit 44fa5f0

Browse files
Port #[used] to new attribute parsing infrastructure
Signed-off-by: Jonathan Brouwer <jonathantbrouwer@gmail.com>
1 parent 15c701f commit 44fa5f0

File tree

15 files changed

+175
-113
lines changed

15 files changed

+175
-113
lines changed

compiler/rustc_attr_data_structures/src/attributes.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,17 @@ impl Deprecation {
131131
}
132132
}
133133

134+
/// There are three valid forms of the attribute:
135+
/// `#[used]`, which is semantically equivalent to `#[used(compiler)]` except that the latter is currently unstable.
136+
/// `#[used(compiler)]`
137+
/// `#[used(linker)]`
138+
#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
139+
#[derive(HashStable_Generic, PrintAttribute)]
140+
pub enum UsedBy {
141+
Compiler,
142+
Linker,
143+
}
144+
134145
/// Represents parsed *built-in* inert attributes.
135146
///
136147
/// ## Overview
@@ -244,5 +255,8 @@ pub enum AttributeKind {
244255
/// Span of the attribute.
245256
span: Span,
246257
},
258+
259+
/// Represents `#[used]`
260+
Used { used_by: UsedBy, span: Span },
247261
// tidy-alphabetical-end
248262
}

compiler/rustc_attr_parsing/messages.ftl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,3 +142,6 @@ attr_parsing_unused_multiple =
142142
143143
-attr_parsing_perviously_accepted =
144144
this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
145+
146+
attr_parsing_used_compiler_linker =
147+
`used(compiler)` and `used(linker)` can't be used together

compiler/rustc_attr_parsing/src/attributes/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ pub(crate) mod lint_helpers;
3636
pub(crate) mod repr;
3737
pub(crate) mod stability;
3838
pub(crate) mod transparency;
39+
pub(crate) mod used;
3940
pub(crate) mod util;
4041

4142
type AcceptFn<T, S> = for<'sess> fn(&mut T, &mut AcceptContext<'_, 'sess, S>, &ArgParser<'_>);
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
use rustc_attr_data_structures::lints::AttributeLintKind;
2+
use rustc_attr_data_structures::{AttributeKind, UsedBy};
3+
use rustc_feature::template;
4+
use rustc_macros::Diagnostic;
5+
use rustc_session::parse::feature_err;
6+
use rustc_span::{Span, sym};
7+
8+
use crate::attributes::{AcceptMapping, AttributeParser};
9+
use crate::context::{FinalizeContext, Stage};
10+
use crate::parser::ArgParser;
11+
12+
#[derive(Diagnostic)]
13+
#[diag(attr_parsing_used_compiler_linker)]
14+
pub(crate) struct UsedCompilerLinker {
15+
#[primary_span]
16+
pub spans: Vec<Span>,
17+
}
18+
19+
#[derive(Default)]
20+
pub(crate) struct UsedParser {
21+
first_compiler: Option<Span>,
22+
first_linker: Option<Span>,
23+
result: Option<(UsedBy, Span)>,
24+
}
25+
26+
// A custom `AttributeParser` is used rather than a Simple attribute parser because
27+
// - Specifying two `#[used]` attributes is a warning (but will be an error in the future)
28+
// - But specifying two conflicting attributes: `#[used(compiler)]` and `#[used(linker)]` is already an error today
29+
// We can change this to a Simple parser once the warning becomes an error
30+
impl<S: Stage> AttributeParser<S> for UsedParser {
31+
const ATTRIBUTES: AcceptMapping<Self, S> = &[(
32+
&[sym::used],
33+
template!(Word, List: "compiler|linker"),
34+
|group: &mut Self, cx, args| {
35+
let used_by = match args {
36+
ArgParser::NoArgs => UsedBy::Compiler,
37+
ArgParser::List(list) => {
38+
let Some(l) = list.single() else {
39+
cx.expected_single_argument(list.span);
40+
return;
41+
};
42+
43+
match l.meta_item().and_then(|i| i.path().word_sym()) {
44+
Some(sym::compiler) => {
45+
if !cx.features().used_with_arg() {
46+
feature_err(
47+
&cx.sess(),
48+
sym::used_with_arg,
49+
cx.attr_span,
50+
"`#[used(compiler)]` is currently unstable",
51+
)
52+
.emit();
53+
}
54+
UsedBy::Compiler
55+
}
56+
Some(sym::linker) => {
57+
if !cx.features().used_with_arg() {
58+
feature_err(
59+
&cx.sess(),
60+
sym::used_with_arg,
61+
cx.attr_span,
62+
"`#[used(linker)]` is currently unstable",
63+
)
64+
.emit();
65+
}
66+
UsedBy::Linker
67+
}
68+
_ => {
69+
cx.expected_specific_argument(l.span(), vec!["compiler", "linker"]);
70+
return;
71+
}
72+
}
73+
}
74+
ArgParser::NameValue(_) => return,
75+
};
76+
77+
match used_by {
78+
UsedBy::Compiler { .. } => {
79+
if group.first_compiler.is_none() {
80+
group.first_compiler = Some(cx.attr_span);
81+
}
82+
}
83+
UsedBy::Linker => {
84+
if group.first_linker.is_none() {
85+
group.first_linker = Some(cx.attr_span);
86+
}
87+
}
88+
}
89+
90+
if let Some(prev) = &group.result {
91+
cx.emit_lint(
92+
AttributeLintKind::UnusedDuplicate {
93+
this: cx.attr_span,
94+
other: prev.1,
95+
warning: true,
96+
},
97+
cx.attr_span,
98+
);
99+
} else {
100+
group.result = Some((used_by, cx.attr_span))
101+
}
102+
},
103+
)];
104+
105+
fn finalize(self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
106+
if let (Some(linker_span), Some(compiler_span)) = (self.first_linker, self.first_compiler) {
107+
cx.dcx().emit_err(UsedCompilerLinker { spans: vec![linker_span, compiler_span] });
108+
}
109+
self.result.map(|(used_by, span)| AttributeKind::Used { used_by, span })
110+
}
111+
}

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use crate::attributes::stability::{
2525
BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser,
2626
};
2727
use crate::attributes::transparency::TransparencyParser;
28+
use crate::attributes::used::UsedParser;
2829
use crate::attributes::{AttributeParser as _, Combine, Single};
2930
use crate::parser::{ArgParser, MetaItemParser};
3031
use crate::session_diagnostics::{AttributeParseError, AttributeParseErrorReason, UnknownMetaItem};
@@ -96,6 +97,7 @@ attribute_parsers!(
9697
ConfusablesParser,
9798
ConstStabilityParser,
9899
StabilityParser,
100+
UsedParser,
99101
// tidy-alphabetical-end
100102

101103
// tidy-alphabetical-start

compiler/rustc_codegen_ssa/messages.ftl

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,6 @@ codegen_ssa_error_writing_def_file =
4848
4949
codegen_ssa_expected_name_value_pair = expected name value pair
5050
51-
codegen_ssa_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
52-
5351
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
5452
5553
codegen_ssa_extract_bundled_libs_archive_member = failed to get data from archive member '{$rlib}': {$error}

compiler/rustc_codegen_ssa/src/codegen_attrs.rs

Lines changed: 5 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use rustc_abi::ExternAbi;
44
use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode};
55
use rustc_ast::{LitKind, MetaItem, MetaItemInner, attr};
66
use rustc_attr_data_structures::{
7-
AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr, ReprAttr, find_attr,
7+
AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr, ReprAttr, UsedBy, find_attr,
88
};
99
use rustc_hir::def::DefKind;
1010
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
@@ -122,6 +122,10 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
122122
}
123123
AttributeKind::Cold(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD,
124124
AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align),
125+
AttributeKind::Used { used_by, .. } => match used_by {
126+
UsedBy::Compiler => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_COMPILER,
127+
UsedBy::Linker => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER,
128+
},
125129
_ => {}
126130
}
127131
}
@@ -166,44 +170,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
166170
sym::rustc_std_internal_symbol => {
167171
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL
168172
}
169-
sym::used => {
170-
let inner = attr.meta_item_list();
171-
match inner.as_deref() {
172-
Some([item]) if item.has_name(sym::linker) => {
173-
if !tcx.features().used_with_arg() {
174-
feature_err(
175-
&tcx.sess,
176-
sym::used_with_arg,
177-
attr.span(),
178-
"`#[used(linker)]` is currently unstable",
179-
)
180-
.emit();
181-
}
182-
codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER;
183-
}
184-
Some([item]) if item.has_name(sym::compiler) => {
185-
if !tcx.features().used_with_arg() {
186-
feature_err(
187-
&tcx.sess,
188-
sym::used_with_arg,
189-
attr.span(),
190-
"`#[used(compiler)]` is currently unstable",
191-
)
192-
.emit();
193-
}
194-
codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_COMPILER;
195-
}
196-
Some(_) => {
197-
tcx.dcx().emit_err(errors::ExpectedUsedSymbol { span: attr.span() });
198-
}
199-
None => {
200-
// Unconditionally using `llvm.used` causes issues in handling
201-
// `.init_array` with the gold linker. Luckily gold has been
202-
// deprecated with GCC 15 and rustc now warns about using gold.
203-
codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER
204-
}
205-
}
206-
}
207173
sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL,
208174
sym::track_caller => {
209175
let is_closure = tcx.is_closure_like(did.to_def_id());

compiler/rustc_codegen_ssa/src/errors.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -733,13 +733,6 @@ pub struct UnknownArchiveKind<'a> {
733733
pub kind: &'a str,
734734
}
735735

736-
#[derive(Diagnostic)]
737-
#[diag(codegen_ssa_expected_used_symbol)]
738-
pub(crate) struct ExpectedUsedSymbol {
739-
#[primary_span]
740-
pub span: Span,
741-
}
742-
743736
#[derive(Diagnostic)]
744737
#[diag(codegen_ssa_multiple_main_functions)]
745738
#[help]

compiler/rustc_passes/messages.ftl

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -809,9 +809,6 @@ passes_unused_variable_try_prefix = unused variable: `{$name}`
809809
.suggestion = if this is intentional, prefix it with an underscore
810810
811811
812-
passes_used_compiler_linker =
813-
`used(compiler)` and `used(linker)` can't be used together
814-
815812
passes_used_static =
816813
attribute must be applied to a `static` variable
817814
.label = but this is a {$target}

compiler/rustc_passes/src/check_attr.rs

Lines changed: 10 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
163163
Attribute::Parsed(AttributeKind::AsPtr(attr_span)) => {
164164
self.check_applied_to_fn_or_method(hir_id, *attr_span, span, target)
165165
}
166+
Attribute::Parsed(AttributeKind::Used { span: attr_span, .. }) => {
167+
self.check_used(*attr_span, target, span);
168+
}
166169
Attribute::Unparsed(_) => {
167170
match attr.path().as_slice() {
168171
[sym::diagnostic, sym::do_not_recommend, ..] => {
@@ -303,7 +306,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
303306
| sym::cfi_encoding // FIXME(cfi_encoding)
304307
| sym::pointee // FIXME(derive_coerce_pointee)
305308
| sym::omit_gdb_pretty_printer_section // FIXME(omit_gdb_pretty_printer_section)
306-
| sym::used // handled elsewhere to restrict to static items
307309
| sym::instruction_set // broken on stable!!!
308310
| sym::windows_subsystem // broken on stable!!!
309311
| sym::patchable_function_entry // FIXME(patchable_function_entry)
@@ -373,7 +375,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
373375
}
374376

375377
self.check_repr(attrs, span, target, item, hir_id);
376-
self.check_used(attrs, target, span);
377378
self.check_rustc_force_inline(hir_id, attrs, span, target);
378379
}
379380

@@ -2189,44 +2190,13 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
21892190
}
21902191
}
21912192

2192-
fn check_used(&self, attrs: &[Attribute], target: Target, target_span: Span) {
2193-
let mut used_linker_span = None;
2194-
let mut used_compiler_span = None;
2195-
for attr in attrs.iter().filter(|attr| attr.has_name(sym::used)) {
2196-
if target != Target::Static {
2197-
self.dcx().emit_err(errors::UsedStatic {
2198-
attr_span: attr.span(),
2199-
span: target_span,
2200-
target: target.name(),
2201-
});
2202-
}
2203-
let inner = attr.meta_item_list();
2204-
match inner.as_deref() {
2205-
Some([item]) if item.has_name(sym::linker) => {
2206-
if used_linker_span.is_none() {
2207-
used_linker_span = Some(attr.span());
2208-
}
2209-
}
2210-
Some([item]) if item.has_name(sym::compiler) => {
2211-
if used_compiler_span.is_none() {
2212-
used_compiler_span = Some(attr.span());
2213-
}
2214-
}
2215-
Some(_) => {
2216-
// This error case is handled in rustc_hir_analysis::collect.
2217-
}
2218-
None => {
2219-
// Default case (compiler) when arg isn't defined.
2220-
if used_compiler_span.is_none() {
2221-
used_compiler_span = Some(attr.span());
2222-
}
2223-
}
2224-
}
2225-
}
2226-
if let (Some(linker_span), Some(compiler_span)) = (used_linker_span, used_compiler_span) {
2227-
self.tcx
2228-
.dcx()
2229-
.emit_err(errors::UsedCompilerLinker { spans: vec![linker_span, compiler_span] });
2193+
fn check_used(&self, attr_span: Span, target: Target, target_span: Span) {
2194+
if target != Target::Static {
2195+
self.dcx().emit_err(errors::UsedStatic {
2196+
attr_span,
2197+
span: target_span,
2198+
target: target.name(),
2199+
});
22302200
}
22312201
}
22322202

compiler/rustc_passes/src/errors.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -611,13 +611,6 @@ pub(crate) struct UsedStatic {
611611
pub target: &'static str,
612612
}
613613

614-
#[derive(Diagnostic)]
615-
#[diag(passes_used_compiler_linker)]
616-
pub(crate) struct UsedCompilerLinker {
617-
#[primary_span]
618-
pub spans: Vec<Span>,
619-
}
620-
621614
#[derive(Diagnostic)]
622615
#[diag(passes_allow_internal_unstable)]
623616
pub(crate) struct AllowInternalUnstable {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#![feature(used_with_arg)]
22

3-
#[used(compiler, linker)] //~ ERROR expected `used`, `used(compiler)` or `used(linker)`
3+
#[used(compiler, linker)] //~ ERROR malformed `used` attribute input
44
static mut USED_COMPILER_LINKER: [usize; 1] = [0];
55

66
fn main() {}
Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,20 @@
1-
error: expected `used`, `used(compiler)` or `used(linker)`
1+
error[E0805]: malformed `used` attribute input
22
--> $DIR/used_with_multi_args.rs:3:1
33
|
44
LL | #[used(compiler, linker)]
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^
5+
| ^^^^^^------------------^
6+
| |
7+
| expected a single argument here
8+
|
9+
help: try changing it to one of the following valid forms of the attribute
10+
|
11+
LL - #[used(compiler, linker)]
12+
LL + #[used(compiler|linker)]
13+
|
14+
LL - #[used(compiler, linker)]
15+
LL + #[used]
16+
|
617

718
error: aborting due to 1 previous error
819

20+
For more information about this error, try `rustc --explain E0805`.

tests/ui/lint/unused/unused-attr-duplicate.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ pub fn no_mangle_test() {}
100100

101101
#[used]
102102
#[used] //~ ERROR unused attribute
103+
//~^ WARN this was previously accepted
103104
static FOO: u32 = 0;
104105

105106
fn main() {}

0 commit comments

Comments
 (0)