Skip to content

Commit 41bc0af

Browse files
borsJonathanBrouwer
authored andcommitted
Port #[target_feature] to new attribute parsing infrastructure
Signed-off-by: Jonathan Brouwer <[email protected]>
2 parents e4b9d01 + 7b864ac commit 41bc0af

File tree

72 files changed

+1033
-479
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+1033
-479
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3282,6 +3282,7 @@ dependencies = [
32823282
"rustc_abi",
32833283
"rustc_ast",
32843284
"rustc_ast_pretty",
3285+
"rustc_attr_data_structures",
32853286
"rustc_attr_parsing",
32863287
"rustc_data_structures",
32873288
"rustc_errors",
@@ -4553,6 +4554,7 @@ dependencies = [
45534554
"itertools",
45544555
"rustc_abi",
45554556
"rustc_ast",
4557+
"rustc_attr_data_structures",
45564558
"rustc_data_structures",
45574559
"rustc_errors",
45584560
"rustc_fluent_macro",

compiler/rustc_ast_lowering/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ doctest = false
1111
rustc_abi = { path = "../rustc_abi" }
1212
rustc_ast = { path = "../rustc_ast" }
1313
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
14+
rustc_attr_data_structures = {path = "../rustc_attr_data_structures"}
1415
rustc_attr_parsing = { path = "../rustc_attr_parsing" }
1516
rustc_data_structures = { path = "../rustc_data_structures" }
1617
rustc_errors = { path = "../rustc_errors" }

compiler/rustc_ast_lowering/src/item.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use rustc_abi::ExternAbi;
22
use rustc_ast::ptr::P;
33
use rustc_ast::visit::AssocCtxt;
44
use rustc_ast::*;
5+
use rustc_attr_data_structures::{AttributeKind, find_attr};
56
use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err};
67
use rustc_hir::def::{DefKind, PerNS, Res};
78
use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
@@ -1621,7 +1622,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
16211622
let safety = self.lower_safety(h.safety, default_safety);
16221623

16231624
// Treat safe `#[target_feature]` functions as unsafe, but also remember that we did so.
1624-
let safety = if attrs.iter().any(|attr| attr.has_name(sym::target_feature))
1625+
let safety = if find_attr!(attrs, AttributeKind::TargetFeature { .. })
16251626
&& safety.is_safe()
16261627
&& !self.tcx.sess.target.is_like_wasm
16271628
{

compiler/rustc_attr_data_structures/src/attributes.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ pub enum AttributeKind {
190190
AllowConstFnUnstable(ThinVec<Symbol>),
191191

192192
/// Represents `#[allow_internal_unstable]`.
193-
AllowInternalUnstable(ThinVec<(Symbol, Span)>),
193+
AllowInternalUnstable(ThinVec<(Symbol, Span)>, Span),
194194

195195
/// Represents `#[rustc_as_ptr]` (used by the `dangling_pointers_from_temporaries` lint).
196196
AsPtr(Span),
@@ -259,11 +259,17 @@ pub enum AttributeKind {
259259
/// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations).
260260
Repr(ThinVec<(ReprAttr, Span)>),
261261

262+
/// Represents `#[rustc_skip_during_method_dispatch]`.
263+
SkipDuringMethodDispatch { array: bool, boxed_slice: bool, span: Span },
264+
262265
/// Represents `#[stable]`, `#[unstable]` and `#[rustc_allowed_through_unstable_modules]`.
263266
Stability {
264267
stability: Stability,
265268
/// Span of the attribute.
266269
span: Span,
267270
},
271+
272+
/// Represents `#[target_feature(enable = "...")]`
273+
TargetFeature(ThinVec<(Symbol, Span)>, Span),
268274
// tidy-alphabetical-end
269275
}

compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ pub(crate) struct AllowInternalUnstableParser;
1313
impl<S: Stage> CombineAttributeParser<S> for AllowInternalUnstableParser {
1414
const PATH: &[Symbol] = &[sym::allow_internal_unstable];
1515
type Item = (Symbol, Span);
16-
const CONVERT: ConvertFn<Self::Item> = AttributeKind::AllowInternalUnstable;
16+
const CONVERT: ConvertFn<Self::Item> =
17+
ConvertFn::WithFirstAttributeSpan(AttributeKind::AllowInternalUnstable);
1718
const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ...");
1819

1920
fn extend<'c>(
@@ -30,7 +31,7 @@ pub(crate) struct AllowConstFnUnstableParser;
3031
impl<S: Stage> CombineAttributeParser<S> for AllowConstFnUnstableParser {
3132
const PATH: &[Symbol] = &[sym::rustc_allow_const_fn_unstable];
3233
type Item = Symbol;
33-
const CONVERT: ConvertFn<Self::Item> = AttributeKind::AllowConstFnUnstable;
34+
const CONVERT: ConvertFn<Self::Item> = ConvertFn::Simple(AttributeKind::AllowConstFnUnstable);
3435
const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ...");
3536

3637
fn extend<'c>(

compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
use rustc_attr_data_structures::{AttributeKind, OptimizeAttr};
22
use rustc_feature::{AttributeTemplate, template};
33
use rustc_session::parse::feature_err;
4-
use rustc_span::{Span, sym};
4+
use rustc_span::{Span, Symbol, sym};
55

6-
use super::{AcceptMapping, AttributeOrder, AttributeParser, OnDuplicate, SingleAttributeParser};
6+
use super::{
7+
AcceptMapping, AttributeOrder, AttributeParser, CombineAttributeParser, ConvertFn, OnDuplicate,
8+
SingleAttributeParser,
9+
};
710
use crate::context::{AcceptContext, FinalizeContext, Stage};
811
use crate::parser::ArgParser;
912
use crate::session_diagnostics::NakedFunctionIncompatibleAttribute;
@@ -50,8 +53,8 @@ impl<S: Stage> SingleAttributeParser<S> for ColdParser {
5053
const TEMPLATE: AttributeTemplate = template!(Word);
5154

5255
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
53-
if !args.no_args() {
54-
cx.expected_no_args(args.span().unwrap_or(cx.attr_span));
56+
if let Err(span) = args.no_args() {
57+
cx.expected_no_args(span);
5558
return None;
5659
}
5760

@@ -67,8 +70,8 @@ pub(crate) struct NakedParser {
6770
impl<S: Stage> AttributeParser<S> for NakedParser {
6871
const ATTRIBUTES: AcceptMapping<Self, S> =
6972
&[(&[sym::naked], template!(Word), |this, cx, args| {
70-
if !args.no_args() {
71-
cx.expected_no_args(args.span().unwrap_or(cx.attr_span));
73+
if let Err(span) = args.no_args() {
74+
cx.expected_no_args(span);
7275
return;
7376
}
7477

@@ -175,11 +178,62 @@ impl<S: Stage> SingleAttributeParser<S> for NoMangleParser {
175178
const TEMPLATE: AttributeTemplate = template!(Word);
176179

177180
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
178-
if !args.no_args() {
179-
cx.expected_no_args(args.span().unwrap_or(cx.attr_span));
181+
if let Err(span) = args.no_args() {
182+
cx.expected_no_args(span);
180183
return None;
181-
};
184+
}
182185

183186
Some(AttributeKind::NoMangle(cx.attr_span))
184187
}
185188
}
189+
190+
pub(crate) struct TargetFeatureParser;
191+
192+
impl<S: Stage> CombineAttributeParser<S> for TargetFeatureParser {
193+
type Item = (Symbol, Span);
194+
const PATH: &[Symbol] = &[sym::target_feature];
195+
const CONVERT: ConvertFn<Self::Item> =
196+
ConvertFn::WithFirstAttributeSpan(AttributeKind::TargetFeature);
197+
const TEMPLATE: AttributeTemplate = template!(List: "enable = \"feat1, feat2\"");
198+
199+
fn extend<'c>(
200+
cx: &'c mut AcceptContext<'_, '_, S>,
201+
args: &'c ArgParser<'_>,
202+
) -> impl IntoIterator<Item = Self::Item> + 'c {
203+
let mut features = Vec::new();
204+
let ArgParser::List(list) = args else {
205+
cx.expected_list(cx.attr_span);
206+
return features;
207+
};
208+
for item in list.mixed() {
209+
let Some(name_value) = item.meta_item() else {
210+
cx.expected_name_value(item.span(), Some(sym::enable));
211+
return features;
212+
};
213+
214+
// Validate name
215+
let Some(name) = name_value.path().word_sym() else {
216+
cx.expected_name_value(name_value.path().span(), Some(sym::enable));
217+
return features;
218+
};
219+
if name != sym::enable {
220+
cx.expected_name_value(name_value.path().span(), Some(sym::enable));
221+
return features;
222+
}
223+
224+
// Use value
225+
let Some(name_value) = name_value.args().name_value() else {
226+
cx.expected_name_value(item.span(), Some(sym::enable));
227+
return features;
228+
};
229+
let Some(value_str) = name_value.value_as_str() else {
230+
cx.expected_string_literal(name_value.value_span, Some(name_value.value_as_lit()));
231+
return features;
232+
};
233+
for feature in value_str.as_str().split(",") {
234+
features.push((Symbol::intern(feature), item.span()));
235+
}
236+
}
237+
features
238+
}
239+
}

compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@ impl<S: Stage> SingleAttributeParser<S> for AsPtrParser {
1414
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
1515
const TEMPLATE: AttributeTemplate = template!(Word);
1616

17-
fn convert(cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> {
18-
// FIXME: check that there's no args (this is currently checked elsewhere)
17+
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
18+
if let Err(span) = args.no_args() {
19+
cx.expected_no_args(span);
20+
}
1921
Some(AttributeKind::AsPtr(cx.attr_span))
2022
}
2123
}
@@ -27,8 +29,10 @@ impl<S: Stage> SingleAttributeParser<S> for PubTransparentParser {
2729
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
2830
const TEMPLATE: AttributeTemplate = template!(Word);
2931

30-
fn convert(cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> {
31-
// FIXME: check that there's no args (this is currently checked elsewhere)
32+
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
33+
if let Err(span) = args.no_args() {
34+
cx.expected_no_args(span);
35+
}
3236
Some(AttributeKind::PubTransparent(cx.attr_span))
3337
}
3438
}

compiler/rustc_attr_parsing/src/attributes/mod.rs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ pub(crate) mod must_use;
3636
pub(crate) mod repr;
3737
pub(crate) mod semantics;
3838
pub(crate) mod stability;
39+
pub(crate) mod traits;
3940
pub(crate) mod transparency;
4041
pub(crate) mod util;
4142

@@ -225,7 +226,10 @@ pub(crate) enum AttributeOrder {
225226
KeepLast,
226227
}
227228

228-
type ConvertFn<E> = fn(ThinVec<E>) -> AttributeKind;
229+
pub(crate) enum ConvertFn<E> {
230+
Simple(fn(ThinVec<E>) -> AttributeKind),
231+
WithFirstAttributeSpan(fn(ThinVec<E>, Span) -> AttributeKind),
232+
}
229233

230234
/// Alternative to [`AttributeParser`] that automatically handles state management.
231235
/// If multiple attributes appear on an element, combines the values of each into a
@@ -259,22 +263,36 @@ pub(crate) trait CombineAttributeParser<S: Stage>: 'static {
259263
pub(crate) struct Combine<T: CombineAttributeParser<S>, S: Stage>(
260264
PhantomData<(S, T)>,
261265
ThinVec<<T as CombineAttributeParser<S>>::Item>,
266+
Option<Span>,
262267
);
263268

264269
impl<T: CombineAttributeParser<S>, S: Stage> Default for Combine<T, S> {
265270
fn default() -> Self {
266-
Self(Default::default(), Default::default())
271+
Self(Default::default(), Default::default(), Default::default())
267272
}
268273
}
269274

270275
impl<T: CombineAttributeParser<S>, S: Stage> AttributeParser<S> for Combine<T, S> {
271276
const ATTRIBUTES: AcceptMapping<Self, S> = &[(
272277
T::PATH,
273278
<T as CombineAttributeParser<S>>::TEMPLATE,
274-
|group: &mut Combine<T, S>, cx, args| group.1.extend(T::extend(cx, args)),
279+
|group: &mut Combine<T, S>, cx, args| {
280+
// Keep track of the span of the first attribute, for diagnostics
281+
if group.2.is_none() {
282+
group.2 = Some(cx.attr_span);
283+
}
284+
group.1.extend(T::extend(cx, args))
285+
},
275286
)];
276287

277288
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
278-
if self.1.is_empty() { None } else { Some(T::CONVERT(self.1)) }
289+
if let Some(first_span) = self.2 {
290+
Some(match T::CONVERT {
291+
ConvertFn::Simple(f) => f(self.1),
292+
ConvertFn::WithFirstAttributeSpan(f) => f(self.1, first_span),
293+
})
294+
} else {
295+
None
296+
}
279297
}
280298
}

compiler/rustc_attr_parsing/src/attributes/repr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ pub(crate) struct ReprParser;
2323
impl<S: Stage> CombineAttributeParser<S> for ReprParser {
2424
type Item = (ReprAttr, Span);
2525
const PATH: &[Symbol] = &[sym::repr];
26-
const CONVERT: ConvertFn<Self::Item> = AttributeKind::Repr;
26+
const CONVERT: ConvertFn<Self::Item> = ConvertFn::Simple(AttributeKind::Repr);
2727
// FIXME(jdonszelmann): never used
2828
const TEMPLATE: AttributeTemplate =
2929
template!(List: "C | Rust | align(...) | packed(...) | <integer type> | transparent");

compiler/rustc_attr_parsing/src/attributes/semantics.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ impl<S: Stage> SingleAttributeParser<S> for MayDangleParser {
1313
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
1414
const TEMPLATE: AttributeTemplate = template!(Word);
1515

16-
fn convert(cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> {
16+
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
17+
if let Err(span) = args.no_args() {
18+
cx.expected_no_args(span);
19+
}
1720
Some(AttributeKind::MayDangle(cx.attr_span))
1821
}
1922
}

compiler/rustc_attr_parsing/src/attributes/stability.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,10 @@ impl<S: Stage> SingleAttributeParser<S> for ConstStabilityIndirectParser {
139139
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Ignore;
140140
const TEMPLATE: AttributeTemplate = template!(Word);
141141

142-
fn convert(_cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> {
142+
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
143+
if let Err(span) = args.no_args() {
144+
cx.expected_no_args(span);
145+
}
143146
Some(AttributeKind::ConstStabilityIndirect)
144147
}
145148
}
@@ -361,8 +364,8 @@ pub(crate) fn parse_unstability<S: Stage>(
361364
};
362365
}
363366
Some(sym::soft) => {
364-
if !param.args().no_args() {
365-
cx.emit_err(session_diagnostics::SoftNoArgs { span: param.span() });
367+
if let Err(span) = args.no_args() {
368+
cx.emit_err(session_diagnostics::SoftNoArgs { span });
366369
}
367370
is_soft = true;
368371
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
use core::mem;
2+
3+
use rustc_attr_data_structures::AttributeKind;
4+
use rustc_feature::{AttributeTemplate, template};
5+
use rustc_span::{Symbol, sym};
6+
7+
use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
8+
use crate::context::{AcceptContext, Stage};
9+
use crate::parser::ArgParser;
10+
11+
pub(crate) struct SkipDuringMethodDispatchParser;
12+
13+
impl<S: Stage> SingleAttributeParser<S> for SkipDuringMethodDispatchParser {
14+
const PATH: &[Symbol] = &[sym::rustc_skip_during_method_dispatch];
15+
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
16+
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
17+
18+
const TEMPLATE: AttributeTemplate = template!(List: "array, boxed_slice");
19+
20+
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
21+
let mut array = false;
22+
let mut boxed_slice = false;
23+
let Some(args) = args.list() else {
24+
cx.expected_list(cx.attr_span);
25+
return None;
26+
};
27+
if args.is_empty() {
28+
cx.expected_at_least_one_argument(args.span);
29+
return None;
30+
}
31+
for arg in args.mixed() {
32+
let Some(arg) = arg.meta_item() else {
33+
cx.unexpected_literal(arg.span());
34+
continue;
35+
};
36+
if let Err(span) = arg.args().no_args() {
37+
cx.expected_no_args(span);
38+
}
39+
let path = arg.path();
40+
let (key, skip): (Symbol, &mut bool) = match path.word_sym() {
41+
Some(key @ sym::array) => (key, &mut array),
42+
Some(key @ sym::boxed_slice) => (key, &mut boxed_slice),
43+
_ => {
44+
cx.expected_specific_argument(path.span(), vec!["array", "boxed_slice"]);
45+
continue;
46+
}
47+
};
48+
if mem::replace(skip, true) {
49+
cx.duplicate_key(arg.span(), key);
50+
}
51+
}
52+
Some(AttributeKind::SkipDuringMethodDispatch { array, boxed_slice, span: cx.attr_span })
53+
}
54+
}

0 commit comments

Comments
 (0)