Skip to content

Port #[target_feature] to new attribute parsing infrastructure #142876

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
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4555,6 +4555,7 @@ dependencies = [
"itertools",
"rustc_abi",
"rustc_ast",
"rustc_attr_data_structures",
"rustc_data_structures",
"rustc_errors",
"rustc_fluent_macro",
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use rustc_abi::ExternAbi;
use rustc_ast::ptr::P;
use rustc_ast::visit::AssocCtxt;
use rustc_ast::*;
use rustc_attr_data_structures::{AttributeKind, find_attr};
use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err};
use rustc_hir::def::{DefKind, PerNS, Res};
use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
Expand Down Expand Up @@ -1621,7 +1622,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let safety = self.lower_safety(h.safety, default_safety);

// Treat safe `#[target_feature]` functions as unsafe, but also remember that we did so.
let safety = if attrs.iter().any(|attr| attr.has_name(sym::target_feature))
let safety = if find_attr!(attrs, AttributeKind::TargetFeature { .. })
&& safety.is_safe()
&& !self.tcx.sess.target.is_like_wasm
{
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_attr_data_structures/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ pub enum AttributeKind {
AllowConstFnUnstable(ThinVec<Symbol>),

/// Represents `#[allow_internal_unstable]`.
AllowInternalUnstable(ThinVec<(Symbol, Span)>),
AllowInternalUnstable(ThinVec<(Symbol, Span)>, Span),

/// Represents `#[rustc_as_ptr]` (used by the `dangling_pointers_from_temporaries` lint).
AsPtr(Span),
Expand Down Expand Up @@ -294,6 +294,9 @@ pub enum AttributeKind {
span: Span,
},

/// Represents `#[target_feature(enable = "...")]`
TargetFeature(ThinVec<(Symbol, Span)>, Span),

/// Represents `#[track_caller]`
TrackCaller(Span),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ impl AttributeKind {
Optimize(..) => No,
PubTransparent(..) => Yes,
SkipDuringMethodDispatch { .. } => No,
TargetFeature(..) => No,
TrackCaller(..) => Yes,
Used { .. } => No,
}
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ pub(crate) struct AllowInternalUnstableParser;
impl<S: Stage> CombineAttributeParser<S> for AllowInternalUnstableParser {
const PATH: &[Symbol] = &[sym::allow_internal_unstable];
type Item = (Symbol, Span);
const CONVERT: ConvertFn<Self::Item> = AttributeKind::AllowInternalUnstable;
const CONVERT: ConvertFn<Self::Item> =
ConvertFn::WithFirstAttributeSpan(AttributeKind::AllowInternalUnstable);
const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ...");

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

fn extend<'c>(
Expand Down
56 changes: 55 additions & 1 deletion compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ use rustc_feature::{AttributeTemplate, template};
use rustc_session::parse::feature_err;
use rustc_span::{Span, Symbol, sym};

use super::{AcceptMapping, AttributeOrder, AttributeParser, OnDuplicate, SingleAttributeParser};
use super::{
AcceptMapping, AttributeOrder, AttributeParser, CombineAttributeParser, ConvertFn, OnDuplicate,
SingleAttributeParser,
};
use crate::context::{AcceptContext, FinalizeContext, Stage};
use crate::parser::ArgParser;
use crate::session_diagnostics::{NakedFunctionIncompatibleAttribute, NullOnExport};
Expand Down Expand Up @@ -309,3 +312,54 @@ impl<S: Stage> AttributeParser<S> for UsedParser {
})
}
}

pub(crate) struct TargetFeatureParser;

impl<S: Stage> CombineAttributeParser<S> for TargetFeatureParser {
type Item = (Symbol, Span);
const PATH: &[Symbol] = &[sym::target_feature];
const CONVERT: ConvertFn<Self::Item> =
ConvertFn::WithFirstAttributeSpan(AttributeKind::TargetFeature);
const TEMPLATE: AttributeTemplate = template!(List: "enable = \"feat1, feat2\"");

fn extend<'c>(
cx: &'c mut AcceptContext<'_, '_, S>,
args: &'c ArgParser<'_>,
) -> impl IntoIterator<Item = Self::Item> + 'c {
let mut features = Vec::new();
let ArgParser::List(list) = args else {
cx.expected_list(cx.attr_span);
return features;
};
for item in list.mixed() {
let Some(name_value) = item.meta_item() else {
cx.expected_name_value(item.span(), Some(sym::enable));
return features;
};

// Validate name
let Some(name) = name_value.path().word_sym() else {
cx.expected_name_value(name_value.path().span(), Some(sym::enable));
return features;
};
if name != sym::enable {
cx.expected_name_value(name_value.path().span(), Some(sym::enable));
return features;
}

// Use value
let Some(name_value) = name_value.args().name_value() else {
cx.expected_name_value(item.span(), Some(sym::enable));
return features;
};
let Some(value_str) = name_value.value_as_str() else {
cx.expected_string_literal(name_value.value_span, Some(name_value.value_as_lit()));
return features;
};
for feature in value_str.as_str().split(",") {
features.push((Symbol::intern(feature), item.span()));
}
}
features
}
}
25 changes: 21 additions & 4 deletions compiler/rustc_attr_parsing/src/attributes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,10 @@ pub(crate) enum AttributeOrder {
KeepLast,
}

type ConvertFn<E> = fn(ThinVec<E>) -> AttributeKind;
pub(crate) enum ConvertFn<E> {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've changed ConvertFn to an enum so I can also keep track of the span of the first attribute. I use this span to lint on the attribute itselfs (rather than one of the elements) for a few of the diagnostics. Does this seem reasonsable?

Simple(fn(ThinVec<E>) -> AttributeKind),
WithFirstAttributeSpan(fn(ThinVec<E>, Span) -> AttributeKind),
}

/// Alternative to [`AttributeParser`] that automatically handles state management.
/// If multiple attributes appear on an element, combines the values of each into a
Expand Down Expand Up @@ -261,22 +264,36 @@ pub(crate) trait CombineAttributeParser<S: Stage>: 'static {
pub(crate) struct Combine<T: CombineAttributeParser<S>, S: Stage>(
PhantomData<(S, T)>,
ThinVec<<T as CombineAttributeParser<S>>::Item>,
Option<Span>,
);

impl<T: CombineAttributeParser<S>, S: Stage> Default for Combine<T, S> {
fn default() -> Self {
Self(Default::default(), Default::default())
Self(Default::default(), Default::default(), Default::default())
}
}

impl<T: CombineAttributeParser<S>, S: Stage> AttributeParser<S> for Combine<T, S> {
const ATTRIBUTES: AcceptMapping<Self, S> = &[(
T::PATH,
<T as CombineAttributeParser<S>>::TEMPLATE,
|group: &mut Combine<T, S>, cx, args| group.1.extend(T::extend(cx, args)),
|group: &mut Combine<T, S>, cx, args| {
// Keep track of the span of the first attribute, for diagnostics
if group.2.is_none() {
group.2 = Some(cx.attr_span);
}
group.1.extend(T::extend(cx, args))
},
)];

fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
if self.1.is_empty() { None } else { Some(T::CONVERT(self.1)) }
if let Some(first_span) = self.2 {
Some(match T::CONVERT {
ConvertFn::Simple(f) => f(self.1),
ConvertFn::WithFirstAttributeSpan(f) => f(self.1, first_span),
})
} else {
None
}
}
}
2 changes: 1 addition & 1 deletion compiler/rustc_attr_parsing/src/attributes/repr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub(crate) struct ReprParser;
impl<S: Stage> CombineAttributeParser<S> for ReprParser {
type Item = (ReprAttr, Span);
const PATH: &[Symbol] = &[sym::repr];
const CONVERT: ConvertFn<Self::Item> = AttributeKind::Repr;
const CONVERT: ConvertFn<Self::Item> = ConvertFn::Simple(AttributeKind::Repr);
// FIXME(jdonszelmann): never used
const TEMPLATE: AttributeTemplate =
template!(List: "C | Rust | align(...) | packed(...) | <integer type> | transparent");
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};

use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser};
use crate::attributes::codegen_attrs::{
ColdParser, ExportNameParser, NakedParser, NoMangleParser, OptimizeParser, TrackCallerParser,
UsedParser,
ColdParser, ExportNameParser, NakedParser, NoMangleParser, OptimizeParser, TargetFeatureParser,
TrackCallerParser, UsedParser,
};
use crate::attributes::confusables::ConfusablesParser;
use crate::attributes::deprecation::DeprecationParser;
Expand Down Expand Up @@ -111,6 +111,7 @@ attribute_parsers!(
Combine<AllowConstFnUnstableParser>,
Combine<AllowInternalUnstableParser>,
Combine<ReprParser>,
Combine<TargetFeatureParser>,
// tidy-alphabetical-end

// tidy-alphabetical-start
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_codegen_ssa/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ codegen_ssa_failed_to_get_layout = failed to get layout for {$ty}: {$err}

codegen_ssa_failed_to_write = failed to write {$path}: {$error}

codegen_ssa_feature_not_valid = the feature named `{$feature}` is not valid for this target
.label = `{$feature}` is not valid for this target
.help = consider removing the leading `+` in the feature name

codegen_ssa_field_associated_value_expected = associated value expected for `{$name}`

codegen_ssa_forbidden_ctarget_feature =
Expand Down
Loading
Loading