Skip to content

Commit 33e67cb

Browse files
Port #[target_feature] to new attribute parsing infrastructure
Signed-off-by: Jonathan Brouwer <[email protected]>
1 parent 111e9bc commit 33e67cb

File tree

22 files changed

+339
-245
lines changed

22 files changed

+339
-245
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::ErrorGuaranteed;
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: 4 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,5 +259,8 @@ pub enum AttributeKind {
259259
/// Span of the attribute.
260260
span: Span,
261261
},
262+
263+
/// Represents `#[target_feature(enable = "...")]`
264+
TargetFeature(ThinVec<(Symbol, Span)>, Span),
262265
// tidy-alphabetical-end
263266
}

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: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
use rustc_attr_data_structures::{AttributeKind, OptimizeAttr};
22
use rustc_feature::{AttributeTemplate, template};
3-
use rustc_span::sym;
3+
use rustc_span::{Span, Symbol, sym};
44

5-
use super::{AttributeOrder, OnDuplicate, SingleAttributeParser};
5+
use super::{
6+
AttributeOrder, CombineAttributeParser, ConvertFn, OnDuplicate, SingleAttributeParser,
7+
};
68
use crate::context::{AcceptContext, Stage};
79
use crate::parser::ArgParser;
810

@@ -56,3 +58,54 @@ impl<S: Stage> SingleAttributeParser<S> for ColdParser {
5658
Some(AttributeKind::Cold(cx.attr_span))
5759
}
5860
}
61+
62+
pub(crate) struct TargetFeatureParser;
63+
64+
impl<S: Stage> CombineAttributeParser<S> for TargetFeatureParser {
65+
type Item = (Symbol, Span);
66+
const PATH: &[Symbol] = &[sym::target_feature];
67+
const CONVERT: ConvertFn<Self::Item> =
68+
ConvertFn::WithFirstAttributeSpan(AttributeKind::TargetFeature);
69+
const TEMPLATE: AttributeTemplate = template!(List: "enable = \"feat1, feat2\"");
70+
71+
fn extend<'c>(
72+
cx: &'c mut AcceptContext<'_, '_, S>,
73+
args: &'c ArgParser<'_>,
74+
) -> impl IntoIterator<Item = Self::Item> + 'c {
75+
let mut features = Vec::new();
76+
let ArgParser::List(list) = args else {
77+
cx.expected_list(cx.attr_span);
78+
return features;
79+
};
80+
for item in list.mixed() {
81+
let Some(name_value) = item.meta_item() else {
82+
cx.expected_name_value(item.span(), Some(sym::enable));
83+
return features;
84+
};
85+
86+
// Validate name
87+
let Some(name) = name_value.path().word_sym() else {
88+
cx.expected_name_value(name_value.path().span(), Some(sym::enable));
89+
return features;
90+
};
91+
if name != sym::enable {
92+
cx.expected_name_value(name_value.path().span(), Some(sym::enable));
93+
return features;
94+
}
95+
96+
// Use value
97+
let Some(name_value) = name_value.args().name_value() else {
98+
cx.expected_name_value(item.span(), Some(sym::enable));
99+
return features;
100+
};
101+
let Some(value_str) = name_value.value_as_str() else {
102+
cx.expected_string_literal(name_value.value_span, Some(name_value.value_as_lit()));
103+
return features;
104+
};
105+
for feature in value_str.as_str().split(",") {
106+
features.push((Symbol::intern(feature), item.span()));
107+
}
108+
}
109+
features
110+
}
111+
}

compiler/rustc_attr_parsing/src/attributes/mod.rs

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,10 @@ pub(crate) enum AttributeOrder {
232232
KeepLast,
233233
}
234234

235-
type ConvertFn<E> = fn(ThinVec<E>) -> AttributeKind;
235+
pub(crate) enum ConvertFn<E> {
236+
Simple(fn(ThinVec<E>) -> AttributeKind),
237+
WithFirstAttributeSpan(fn(ThinVec<E>, Span) -> AttributeKind),
238+
}
236239

237240
/// Alternative to [`AttributeParser`] that automatically handles state management.
238241
/// If multiple attributes appear on an element, combines the values of each into a
@@ -266,22 +269,36 @@ pub(crate) trait CombineAttributeParser<S: Stage>: 'static {
266269
pub(crate) struct Combine<T: CombineAttributeParser<S>, S: Stage>(
267270
PhantomData<(S, T)>,
268271
ThinVec<<T as CombineAttributeParser<S>>::Item>,
272+
Option<Span>,
269273
);
270274

271275
impl<T: CombineAttributeParser<S>, S: Stage> Default for Combine<T, S> {
272276
fn default() -> Self {
273-
Self(Default::default(), Default::default())
277+
Self(Default::default(), Default::default(), Default::default())
274278
}
275279
}
276280

277281
impl<T: CombineAttributeParser<S>, S: Stage> AttributeParser<S> for Combine<T, S> {
278282
const ATTRIBUTES: AcceptMapping<Self, S> = &[(
279283
T::PATH,
280284
<T as CombineAttributeParser<S>>::TEMPLATE,
281-
|group: &mut Combine<T, S>, cx, args| group.1.extend(T::extend(cx, args)),
285+
|group: &mut Combine<T, S>, cx, args| {
286+
// Keep track of the span of the first attribute, for diagnostics
287+
if group.2.is_none() {
288+
group.2 = Some(cx.attr_span);
289+
}
290+
group.1.extend(T::extend(cx, args))
291+
},
282292
)];
283293

284294
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
285-
if self.1.is_empty() { None } else { Some(T::CONVERT(self.1)) }
295+
if let Some(first_span) = self.2 {
296+
Some(match T::CONVERT {
297+
ConvertFn::Simple(f) => f(self.1),
298+
ConvertFn::WithFirstAttributeSpan(f) => f(self.1, first_span),
299+
})
300+
} else {
301+
None
302+
}
286303
}
287304
}

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/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, OptimizeParser};
18+
use crate::attributes::codegen_attrs::{ColdParser, OptimizeParser, TargetFeatureParser};
1919
use crate::attributes::confusables::ConfusablesParser;
2020
use crate::attributes::deprecation::DeprecationParser;
2121
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
@@ -104,6 +104,7 @@ attribute_parsers!(
104104
Combine<AllowConstFnUnstableParser>,
105105
Combine<AllowInternalUnstableParser>,
106106
Combine<ReprParser>,
107+
Combine<TargetFeatureParser>,
107108
// tidy-alphabetical-end
108109

109110
// tidy-alphabetical-start

compiler/rustc_codegen_ssa/messages.ftl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ codegen_ssa_failed_to_get_layout = failed to get layout for {$ty}: {$err}
6464
6565
codegen_ssa_failed_to_write = failed to write {$path}: {$error}
6666
67+
codegen_ssa_feature_not_valid = the feature named `{$feature}` is not valid for this target
68+
.label = `{$feature}` is not valid for this target
69+
.help = consider removing the leading `+` in the feature name
70+
6771
codegen_ssa_field_associated_value_expected = associated value expected for `{$name}`
6872
6973
codegen_ssa_forbidden_ctarget_feature =

0 commit comments

Comments
 (0)