Skip to content
Draft
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
11 changes: 1 addition & 10 deletions compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
use rustc_ast::{self as ast, AttrVec, GenericBound, NodeId, PatKind, attr, token};
use rustc_attr_parsing::AttributeParser;
use rustc_errors::msg;
use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, Features};
use rustc_feature::Features;
use rustc_hir::Attribute;
use rustc_hir::attrs::AttributeKind;
use rustc_session::Session;
Expand Down Expand Up @@ -155,15 +155,6 @@ impl<'a> PostExpansionVisitor<'a> {

impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
fn visit_attribute(&mut self, attr: &ast::Attribute) {
let attr_info = attr.name().and_then(|name| BUILTIN_ATTRIBUTE_MAP.get(&name));
// Check feature gates for built-in attributes.
if let Some(BuiltinAttribute {
gate: AttributeGate::Gated { feature, message, check, notes, .. },
..
}) = attr_info
{
gate_alt!(self, check(self.features), *feature, attr.span, *message, *notes);
}
Comment on lines -158 to -166
Copy link
Copy Markdown
Contributor Author

@Bryntet Bryntet Apr 14, 2026

Choose a reason for hiding this comment

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

this logic is moved to rustc_attr_parsing/src/feature_gate.rs which gets called from rustc_attr_parsing/src/interface.rs

// Check unstable flavors of the `#[doc]` attribute.
if attr.has_name(sym::doc) {
for meta_item_inner in attr.meta_item_list().unwrap_or_default() {
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ pub(crate) struct AllowInternalUnstableParser;
impl<S: Stage> CombineAttributeParser<S> for AllowInternalUnstableParser {
const PATH: &[Symbol] = &[sym::allow_internal_unstable];
type Item = (Symbol, Span);
const GATED: AttributeGate = gated!(
allow_internal_unstable,
"allow_internal_unstable side-steps feature gating and stability checks"
);
const CONVERT: ConvertFn<Self::Item> =
|items, span| AttributeKind::AllowInternalUnstable(items, span);
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Expand All @@ -31,6 +35,7 @@ pub(crate) struct UnstableFeatureBoundParser;
impl<S: Stage> CombineAttributeParser<S> for UnstableFeatureBoundParser {
const PATH: &[rustc_span::Symbol] = &[sym::unstable_feature_bound];
type Item = (Symbol, Span);
const GATED: AttributeGate = Ungated;
const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::UnstableFeatureBound(items);
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Expand All @@ -56,6 +61,10 @@ pub(crate) struct RustcAllowConstFnUnstableParser;
impl<S: Stage> CombineAttributeParser<S> for RustcAllowConstFnUnstableParser {
const PATH: &[Symbol] = &[sym::rustc_allow_const_fn_unstable];
type Item = Symbol;
const GATED: AttributeGate = gated_rustc_attr!(
rustc_allow_const_fn_unstable,
"rustc_allow_const_fn_unstable side-steps feature gating and stability checks"
);
const CONVERT: ConvertFn<Self::Item> =
|items, first_span| AttributeKind::RustcAllowConstFnUnstable(items, first_span);
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Expand Down
8 changes: 3 additions & 5 deletions compiler/rustc_attr_parsing/src/attributes/autodiff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,15 @@ use rustc_hir::{MethodKind, Target};
use rustc_span::{Symbol, sym};
use thin_vec::ThinVec;

use crate::attributes::prelude::Allow;
use crate::attributes::{OnDuplicate, SingleAttributeParser};
use crate::context::{AcceptContext, Stage};
use crate::parser::{ArgParser, MetaItemOrLitParser};
use crate::target_checking::AllowedTargets;
use super::prelude::*;

pub(crate) struct RustcAutodiffParser;

impl<S: Stage> SingleAttributeParser<S> for RustcAutodiffParser {
const PATH: &[Symbol] = &[sym::rustc_autodiff];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
// This is actually gated on a std libs feature called `autodiff`
const GATED: AttributeGate = Ungated;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::Inherent)),
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_attr_parsing/src/attributes/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub(crate) struct CoroutineParser;
impl<S: Stage> NoArgsAttributeParser<S> for CoroutineParser {
const PATH: &[Symbol] = &[sym::coroutine];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const GATED: AttributeGate = gated!(coroutines, experimental!(coroutine));
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Closure)]);
const CREATE: fn(rustc_span::Span) -> AttributeKind = |span| AttributeKind::Coroutine(span);
}
3 changes: 3 additions & 0 deletions compiler/rustc_attr_parsing/src/attributes/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use rustc_session::parse::{ParseSess, feature_err};
use rustc_span::{ErrorGuaranteed, Span, Symbol, sym};
use thin_vec::ThinVec;

use super::prelude::*;
use crate::context::{AcceptContext, ShouldEmit, Stage};
use crate::parser::{
AllowExprMetavar, ArgParser, MetaItemListParser, MetaItemOrLitParser, NameValueParser,
Expand Down Expand Up @@ -410,6 +411,8 @@ fn parse_cfg_attr_internal<'a>(
attribute.style,
AttrPath { segments: attribute.path().into_boxed_slice(), span: attribute.span },
Some(attribute.get_normal_item().unsafety),
AttributeSafety::Normal,
Ungated,
ParsedDescription::Attribute,
pred_span,
lint_node_id,
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_attr_parsing/src/attributes/cfg_select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use rustc_session::Session;
use rustc_session::lint::builtin::UNREACHABLE_CFG_SELECT_PREDICATES;
use rustc_span::{ErrorGuaranteed, Span, Symbol, sym};

use super::prelude::*;
use crate::parser::{AllowExprMetavar, MetaItemOrLitParser};
use crate::{AttributeParser, ParsedDescription, ShouldEmit, errors, parse_cfg_entry};

Expand Down Expand Up @@ -105,6 +106,8 @@ pub fn parse_cfg_select(
AttrStyle::Inner,
AttrPath { segments: vec![sym::cfg_select].into_boxed_slice(), span: cfg_span },
None,
AttributeSafety::Normal,
Ungated,
ParsedDescription::Macro,
cfg_span,
lint_node_id,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_attr_parsing/src/attributes/cfi_encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use super::prelude::*;
pub(crate) struct CfiEncodingParser;
impl<S: Stage> SingleAttributeParser<S> for CfiEncodingParser {
const PATH: &[Symbol] = &[sym::cfi_encoding];
const GATED: AttributeGate = gated!(cfi_encoding);
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
Allow(Target::Struct),
Allow(Target::ForeignTy),
Expand Down
35 changes: 34 additions & 1 deletion compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use rustc_hir::attrs::{CoverageAttrKind, OptimizeAttr, RtsanSetting, SanitizerSet, UsedBy};
use rustc_session::parse::feature_err;
use rustc_span::edition::Edition::Edition2024;

use super::prelude::*;
use crate::session_diagnostics::{
Expand All @@ -10,9 +11,11 @@ use crate::target_checking::Policy::AllowSilent;

pub(crate) struct OptimizeParser;

// RFC 2412
impl<S: Stage> SingleAttributeParser<S> for OptimizeParser {
const PATH: &[Symbol] = &[sym::optimize];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const GATED: AttributeGate = gated!(optimize_attribute, experimental!(optimize));
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Closure),
Expand Down Expand Up @@ -45,6 +48,7 @@ pub(crate) struct ColdParser;
impl<S: Stage> NoArgsAttributeParser<S> for ColdParser {
const PATH: &[Symbol] = &[sym::cold];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const GATED: AttributeGate = Ungated;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::Trait { body: true })),
Expand All @@ -61,6 +65,7 @@ pub(crate) struct CoverageParser;
impl<S: Stage> SingleAttributeParser<S> for CoverageParser {
const PATH: &[Symbol] = &[sym::coverage];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const GATED: AttributeGate = gated!(coverage_attribute, experimental!(coverage));
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Closure),
Expand Down Expand Up @@ -103,6 +108,8 @@ pub(crate) struct ExportNameParser;
impl<S: Stage> SingleAttributeParser<S> for ExportNameParser {
const PATH: &[rustc_span::Symbol] = &[sym::export_name];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: Some(Edition2024) };
const GATED: AttributeGate = Ungated;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Static),
Allow(Target::Fn),
Expand Down Expand Up @@ -141,6 +148,7 @@ pub(crate) struct RustcObjcClassParser;
impl<S: Stage> SingleAttributeParser<S> for RustcObjcClassParser {
const PATH: &[rustc_span::Symbol] = &[sym::rustc_objc_class];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const GATED: AttributeGate = gated_rustc_attr!(rustc_objc_class);
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::ForeignStatic)]);
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "ClassName");
Expand Down Expand Up @@ -173,6 +181,7 @@ pub(crate) struct RustcObjcSelectorParser;
impl<S: Stage> SingleAttributeParser<S> for RustcObjcSelectorParser {
const PATH: &[rustc_span::Symbol] = &[sym::rustc_objc_selector];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const GATED: AttributeGate = gated_rustc_attr!(rustc_objc_selector);
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::ForeignStatic)]);
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "methodName");
Expand Down Expand Up @@ -207,7 +216,7 @@ pub(crate) struct NakedParser {

impl<S: Stage> AttributeParser<S> for NakedParser {
const ATTRIBUTES: AcceptMapping<Self, S> =
&[(&[sym::naked], template!(Word), |this, cx, args| {
&[(&[sym::naked], template!(Word), Ungated, |this, cx, args| {
if let Err(span) = args.no_args() {
cx.adcx().expected_no_args(span);
return;
Expand All @@ -220,6 +229,7 @@ impl<S: Stage> AttributeParser<S> for NakedParser {
this.span = Some(cx.attr_span);
}
})];
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::Inherent)),
Expand Down Expand Up @@ -320,6 +330,7 @@ pub(crate) struct TrackCallerParser;
impl<S: Stage> NoArgsAttributeParser<S> for TrackCallerParser {
const PATH: &[Symbol] = &[sym::track_caller];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const GATED: AttributeGate = Ungated;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::Inherent)),
Expand All @@ -340,6 +351,8 @@ pub(crate) struct NoMangleParser;
impl<S: Stage> NoArgsAttributeParser<S> for NoMangleParser {
const PATH: &[Symbol] = &[sym::no_mangle];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: Some(Edition2024) };
const GATED: AttributeGate = Ungated;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
Allow(Target::Fn),
Allow(Target::Static),
Expand All @@ -366,6 +379,7 @@ impl<S: Stage> AttributeParser<S> for UsedParser {
const ATTRIBUTES: AcceptMapping<Self, S> = &[(
&[sym::used],
template!(Word, List: &["compiler", "linker"]),
Ungated,
|group: &mut Self, cx, args| {
let used_by = match args {
ArgParser::NoArgs => UsedBy::Default,
Expand Down Expand Up @@ -510,6 +524,7 @@ pub(crate) struct TargetFeatureParser;
impl<S: Stage> CombineAttributeParser<S> for TargetFeatureParser {
type Item = (Symbol, Span);
const PATH: &[Symbol] = &[sym::target_feature];
const GATED: AttributeGate = Ungated;
const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature {
features: items,
attr_span: span,
Expand Down Expand Up @@ -542,6 +557,9 @@ pub(crate) struct ForceTargetFeatureParser;
impl<S: Stage> CombineAttributeParser<S> for ForceTargetFeatureParser {
type Item = (Symbol, Span);
const PATH: &[Symbol] = &[sym::force_target_feature];
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
const GATED: AttributeGate =
gated!(effective_target_features, experimental!(force_target_feature));
const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature {
features: items,
attr_span: span,
Expand Down Expand Up @@ -587,6 +605,8 @@ impl<S: Stage> SingleAttributeParser<S> for SanitizeParser {

const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;

const GATED: AttributeGate = gated!(sanitize);

fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
let Some(list) = args.list() else {
let attr_span = cx.attr_span;
Expand Down Expand Up @@ -690,6 +710,10 @@ pub(crate) struct ThreadLocalParser;
impl<S: Stage> NoArgsAttributeParser<S> for ThreadLocalParser {
const PATH: &[Symbol] = &[sym::thread_local];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const GATED: AttributeGate = gated!(
thread_local,
"`#[thread_local]` is an experimental feature, and does not currently handle destructors"
);
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::Static), Allow(Target::ForeignStatic)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ThreadLocal;
Expand All @@ -701,6 +725,10 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcPassIndirectlyInNonRusticAbisPa
const PATH: &[Symbol] = &[sym::rustc_pass_indirectly_in_non_rustic_abis];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
const GATED: AttributeGate = gated_rustc_attr!(
rustc_pass_indirectly_in_non_rustic_abis,
"types marked with `#[rustc_pass_indirectly_in_non_rustic_abis]` are always passed indirectly by non-Rustic ABIs"
);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPassIndirectlyInNonRusticAbis;
}

Expand All @@ -709,6 +737,10 @@ pub(crate) struct RustcEiiForeignItemParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcEiiForeignItemParser {
const PATH: &[Symbol] = &[sym::rustc_eii_foreign_item];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const GATED: AttributeGate = gated!(
eii_internals,
"used internally to mark types with a `transparent` representation when it is guaranteed by the documentation"
);
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::ForeignFn), Allow(Target::ForeignStatic)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcEiiForeignItem;
Expand All @@ -719,6 +751,7 @@ pub(crate) struct PatchableFunctionEntryParser;
impl<S: Stage> SingleAttributeParser<S> for PatchableFunctionEntryParser {
const PATH: &[Symbol] = &[sym::patchable_function_entry];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const GATED: AttributeGate = gated!(patchable_function_entry);
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
const TEMPLATE: AttributeTemplate = template!(List: &["prefix_nops = m, entry_nops = n"]);

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_attr_parsing/src/attributes/confusables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ impl<S: Stage> AttributeParser<S> for ConfusablesParser {
const ATTRIBUTES: AcceptMapping<Self, S> = &[(
&[sym::rustc_confusables],
template!(List: &[r#""name1", "name2", ..."#]),
gated_rustc_attr!(rustc_confusables),
|this, cx, args| {
let Some(list) = args.list() else {
let attr_span = cx.attr_span;
Expand Down
Loading
Loading