Skip to content

Commit be02b70

Browse files
Port #[used] to new attribute parsing infrastructure
Signed-off-by: Jonathan Brouwer <[email protected]>
1 parent 22be76b commit be02b70

File tree

14 files changed

+195
-128
lines changed

14 files changed

+195
-128
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(linker)]` 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
@@ -262,5 +273,8 @@ pub enum AttributeKind {
262273
/// Span of the attribute.
263274
span: Span,
264275
},
276+
277+
/// Represents `#[used]`
278+
Used { used_by: UsedBy, span: Span },
265279
// tidy-alphabetical-end
266280
}

compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs

Lines changed: 93 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
use rustc_attr_data_structures::{AttributeKind, OptimizeAttr};
1+
use rustc_attr_data_structures::lints::AttributeLintKind;
2+
use rustc_attr_data_structures::{AttributeKind, OptimizeAttr, UsedBy};
23
use rustc_feature::{AttributeTemplate, template};
3-
use rustc_span::sym;
4+
use rustc_session::parse::feature_err;
5+
use rustc_span::{Span, sym};
46

5-
use super::{AttributeOrder, OnDuplicate, SingleAttributeParser};
6-
use crate::context::{AcceptContext, Stage};
7+
use super::{AcceptMapping, AttributeOrder, AttributeParser, OnDuplicate, SingleAttributeParser};
8+
use crate::context::{AcceptContext, FinalizeContext, Stage};
79
use crate::parser::ArgParser;
810

911
pub(crate) struct OptimizeParser;
@@ -74,3 +76,90 @@ impl<S: Stage> SingleAttributeParser<S> for NoMangleParser {
7476
Some(AttributeKind::NoMangle(cx.attr_span))
7577
}
7678
}
79+
80+
#[derive(Default)]
81+
pub(crate) struct UsedParser {
82+
first_compiler: Option<Span>,
83+
first_linker: Option<Span>,
84+
}
85+
86+
// A custom `AttributeParser` is used rather than a Simple attribute parser because
87+
// - Specifying two `#[used]` attributes is a warning (but will be an error in the future)
88+
// - But specifying two conflicting attributes: `#[used(compiler)]` and `#[used(linker)]` is already an error today
89+
// We can change this to a Simple parser once the warning becomes an error
90+
impl<S: Stage> AttributeParser<S> for UsedParser {
91+
const ATTRIBUTES: AcceptMapping<Self, S> = &[(
92+
&[sym::used],
93+
template!(Word, List: "compiler|linker"),
94+
|group: &mut Self, cx, args| {
95+
let used_by = match args {
96+
ArgParser::NoArgs => UsedBy::Linker,
97+
ArgParser::List(list) => {
98+
let Some(l) = list.single() else {
99+
cx.expected_single_argument(list.span);
100+
return;
101+
};
102+
103+
match l.meta_item().and_then(|i| i.path().word_sym()) {
104+
Some(sym::compiler) => {
105+
if !cx.features().used_with_arg() {
106+
feature_err(
107+
&cx.sess(),
108+
sym::used_with_arg,
109+
cx.attr_span,
110+
"`#[used(compiler)]` is currently unstable",
111+
)
112+
.emit();
113+
}
114+
UsedBy::Compiler
115+
}
116+
Some(sym::linker) => {
117+
if !cx.features().used_with_arg() {
118+
feature_err(
119+
&cx.sess(),
120+
sym::used_with_arg,
121+
cx.attr_span,
122+
"`#[used(linker)]` is currently unstable",
123+
)
124+
.emit();
125+
}
126+
UsedBy::Linker
127+
}
128+
_ => {
129+
cx.expected_specific_argument(l.span(), vec!["compiler", "linker"]);
130+
return;
131+
}
132+
}
133+
}
134+
ArgParser::NameValue(_) => return,
135+
};
136+
137+
let target = match used_by {
138+
UsedBy::Compiler => &mut group.first_compiler,
139+
UsedBy::Linker => &mut group.first_linker,
140+
};
141+
142+
if let Some(prev) = *target {
143+
cx.emit_lint(
144+
AttributeLintKind::UnusedDuplicate {
145+
this: cx.attr_span,
146+
other: prev,
147+
warning: false,
148+
},
149+
cx.attr_span,
150+
);
151+
} else {
152+
*target = Some(cx.attr_span);
153+
}
154+
},
155+
)];
156+
157+
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
158+
// Ratcheting behaviour, if both `linker` and `compiler` are specified, use `linker`
159+
Some(match (self.first_compiler, self.first_linker) {
160+
(_, Some(span)) => AttributeKind::Used { used_by: UsedBy::Linker, span },
161+
(Some(span), _) => AttributeKind::Used { used_by: UsedBy::Compiler, span },
162+
(None, None) => return None,
163+
})
164+
}
165+
}

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc_session::Session;
1515
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
1616

1717
use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser};
18-
use crate::attributes::codegen_attrs::{ColdParser, NoMangleParser, OptimizeParser};
18+
use crate::attributes::codegen_attrs::{ColdParser, NoMangleParser, OptimizeParser, UsedParser};
1919
use crate::attributes::confusables::ConfusablesParser;
2020
use crate::attributes::deprecation::DeprecationParser;
2121
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
@@ -98,6 +98,7 @@ attribute_parsers!(
9898
ConfusablesParser,
9999
ConstStabilityParser,
100100
StabilityParser,
101+
UsedParser,
101102
// tidy-alphabetical-end
102103

103104
// 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};
@@ -141,6 +141,10 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
141141
});
142142
}
143143
}
144+
AttributeKind::Used { used_by, .. } => match used_by {
145+
UsedBy::Compiler => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_COMPILER,
146+
UsedBy::Linker => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER,
147+
},
144148
_ => {}
145149
}
146150
}
@@ -169,44 +173,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
169173
sym::rustc_std_internal_symbol => {
170174
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL
171175
}
172-
sym::used => {
173-
let inner = attr.meta_item_list();
174-
match inner.as_deref() {
175-
Some([item]) if item.has_name(sym::linker) => {
176-
if !tcx.features().used_with_arg() {
177-
feature_err(
178-
&tcx.sess,
179-
sym::used_with_arg,
180-
attr.span(),
181-
"`#[used(linker)]` is currently unstable",
182-
)
183-
.emit();
184-
}
185-
codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER;
186-
}
187-
Some([item]) if item.has_name(sym::compiler) => {
188-
if !tcx.features().used_with_arg() {
189-
feature_err(
190-
&tcx.sess,
191-
sym::used_with_arg,
192-
attr.span(),
193-
"`#[used(compiler)]` is currently unstable",
194-
)
195-
.emit();
196-
}
197-
codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_COMPILER;
198-
}
199-
Some(_) => {
200-
tcx.dcx().emit_err(errors::ExpectedUsedSymbol { span: attr.span() });
201-
}
202-
None => {
203-
// Unconditionally using `llvm.used` causes issues in handling
204-
// `.init_array` with the gold linker. Luckily gold has been
205-
// deprecated with GCC 15 and rustc now warns about using gold.
206-
codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER
207-
}
208-
}
209-
}
210176
sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL,
211177
sym::track_caller => {
212178
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
@@ -177,6 +177,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
177177
Attribute::Parsed(AttributeKind::NoMangle(attr_span)) => {
178178
self.check_no_mangle(hir_id, *attr_span, span, target)
179179
}
180+
Attribute::Parsed(AttributeKind::Used { span: attr_span, .. }) => {
181+
self.check_used(*attr_span, target, span);
182+
}
180183
Attribute::Unparsed(attr_item) => {
181184
style = Some(attr_item.style);
182185
match attr.path().as_slice() {
@@ -315,7 +318,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
315318
| sym::cfi_encoding // FIXME(cfi_encoding)
316319
| sym::pointee // FIXME(derive_coerce_pointee)
317320
| sym::omit_gdb_pretty_printer_section // FIXME(omit_gdb_pretty_printer_section)
318-
| sym::used // handled elsewhere to restrict to static items
319321
| sym::instruction_set // broken on stable!!!
320322
| sym::windows_subsystem // broken on stable!!!
321323
| sym::patchable_function_entry // FIXME(patchable_function_entry)
@@ -385,7 +387,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
385387
}
386388

387389
self.check_repr(attrs, span, target, item, hir_id);
388-
self.check_used(attrs, target, span);
389390
self.check_rustc_force_inline(hir_id, attrs, span, target);
390391
}
391392

@@ -2208,44 +2209,13 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
22082209
}
22092210
}
22102211

2211-
fn check_used(&self, attrs: &[Attribute], target: Target, target_span: Span) {
2212-
let mut used_linker_span = None;
2213-
let mut used_compiler_span = None;
2214-
for attr in attrs.iter().filter(|attr| attr.has_name(sym::used)) {
2215-
if target != Target::Static {
2216-
self.dcx().emit_err(errors::UsedStatic {
2217-
attr_span: attr.span(),
2218-
span: target_span,
2219-
target: target.name(),
2220-
});
2221-
}
2222-
let inner = attr.meta_item_list();
2223-
match inner.as_deref() {
2224-
Some([item]) if item.has_name(sym::linker) => {
2225-
if used_linker_span.is_none() {
2226-
used_linker_span = Some(attr.span());
2227-
}
2228-
}
2229-
Some([item]) if item.has_name(sym::compiler) => {
2230-
if used_compiler_span.is_none() {
2231-
used_compiler_span = Some(attr.span());
2232-
}
2233-
}
2234-
Some(_) => {
2235-
// This error case is handled in rustc_hir_analysis::collect.
2236-
}
2237-
None => {
2238-
// Default case (compiler) when arg isn't defined.
2239-
if used_compiler_span.is_none() {
2240-
used_compiler_span = Some(attr.span());
2241-
}
2242-
}
2243-
}
2244-
}
2245-
if let (Some(linker_span), Some(compiler_span)) = (used_linker_span, used_compiler_span) {
2246-
self.tcx
2247-
.dcx()
2248-
.emit_err(errors::UsedCompilerLinker { spans: vec![linker_span, compiler_span] });
2212+
fn check_used(&self, attr_span: Span, target: Target, target_span: Span) {
2213+
if target != Target::Static {
2214+
self.dcx().emit_err(errors::UsedStatic {
2215+
attr_span,
2216+
span: target_span,
2217+
target: target.name(),
2218+
});
22492219
}
22502220
}
22512221

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 {

tests/ui/attributes/used_with_arg.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#![deny(unused_attributes)]
12
#![feature(used_with_arg)]
23

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

9-
#[used(compiler)] //~ ERROR `used(compiler)` and `used(linker)` can't be used together
10+
#[used(compiler)]
1011
#[used(linker)]
1112
static mut USED_COMPILER_LINKER2: [usize; 1] = [0];
1213

13-
#[used(compiler)] //~ ERROR `used(compiler)` and `used(linker)` can't be used together
14-
#[used(linker)]
1514
#[used(compiler)]
1615
#[used(linker)]
16+
#[used(compiler)] //~ ERROR unused attribute
17+
#[used(linker)] //~ ERROR unused attribute
1718
static mut USED_COMPILER_LINKER3: [usize; 1] = [0];
1819

20+
#[used(compiler)]
21+
#[used]
22+
static mut USED_WITHOUT_ATTR1: [usize; 1] = [0];
23+
24+
#[used(linker)]
25+
#[used] //~ ERROR unused attribute
26+
static mut USED_WITHOUT_ATTR2: [usize; 1] = [0];
27+
1928
fn main() {}

0 commit comments

Comments
 (0)