Skip to content
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
10 changes: 10 additions & 0 deletions compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -751,6 +751,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
)
});

for param in &fdec.inputs {
self.lower_attrs_with_extra(
hir_id,
param.attrs(),
param.span,
Target::Param,
attrs,
);
}

// Unmarked safety in unsafe block defaults to unsafe.
let header = self.lower_fn_header(sig.header, hir::Safety::Unsafe, attrs);

Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
tcx.features(),
registered_tools,
Late,
tcx.dcx(),
),
delayed_lints: Vec::new(),
}
Expand Down Expand Up @@ -1349,6 +1350,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
hir::TyKind::Path(path)
}
TyKind::FnPtr(f) => {
let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
for param in &f.decl.inputs {
// Attrs on FnPtr need to be lowered, see RFC #2565
self.lower_attrs(hir_id, param.attrs(), param.span, Target::Param);
}

let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params);
hir::TyKind::FnPtr(self.arena.alloc(hir::FnPtrTy {
generic_params,
Expand Down
10 changes: 8 additions & 2 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
//! constructions produced by proc macros. This pass is only intended for simple checks that do not
//! require name resolution or type checking, or other kinds of complex analysis.

use core::slice;
use std::mem;
use std::ops::{Deref, DerefMut};
use std::str::FromStr;
Expand All @@ -25,7 +26,7 @@ use rustc_abi::{CVariadicStatus, CanonAbi, ExternAbi, InterruptKind};
use rustc_ast::visit::{AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor, walk_list};
use rustc_ast::*;
use rustc_ast_pretty::pprust::{self, State};
use rustc_attr_parsing::validate_attr;
use rustc_attr_parsing::{AttributeParser, Late, validate_attr};
use rustc_data_structures::fx::FxIndexMap;
use rustc_errors::{DiagCtxtHandle, LintBuffer};
use rustc_feature::Features;
Expand Down Expand Up @@ -373,7 +374,12 @@ impl<'a> AstValidator<'a> {
sym::forbid,
sym::warn,
];
!attr.has_any_name(&arr) && rustc_attr_parsing::is_builtin_attr(*attr)
!attr.has_any_name(&arr)
&& rustc_attr_parsing::is_builtin_attr(*attr)
// Only emit this for non-parsed attrs, because parsed attrs have better lints for this
&& !attr.name()
.as_ref()
.is_some_and(|name| AttributeParser::<Late>::is_parsed_attribute(slice::from_ref(name)))
})
.for_each(|attr| {
if attr.is_doc_comment() {
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_attr_parsing/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,10 @@ attr_parsing_stability_outside_std = stability attributes may not be used outsid
attr_parsing_suffixed_literal_in_attribute = suffixed literals are not allowed in attributes
.help = instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)

attr_parsing_target_regression = attribute parser for `#[{$attribute_symbol}]` uses `AllowedTargets::AllowListWarnRest` but does not specify `Allow` or `Error` for target: `{$target}`
.help = this target is already emitting errs for all unparsed attrs so omitting it in `AllowListWarnRest` would mean a regression from emitting an error, to emitting a warn
.note = this is an internal rustc lint

attr_parsing_unknown_version_literal =
unknown version literal format, assuming it refers to a future version

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 @@ -7,6 +7,7 @@ impl<S: Stage> SingleAttributeParser<S> for CfiEncodingParser {
Allow(Target::ForeignTy),
Allow(Target::Enum),
Allow(Target::Union),
Error(Target::Param),
]);
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for ColdParser {
Allow(Target::Method(MethodKind::Inherent)),
Allow(Target::ForeignFn),
Allow(Target::Closure),
Error(Target::Param),
]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::Cold;
}
Expand Down Expand Up @@ -364,6 +365,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for NoMangleParser {
Allow(Target::Method(MethodKind::TraitImpl)),
AllowSilent(Target::Const), // Handled in the `InvalidNoMangleItems` pass
Error(Target::Closure),
Error(Target::Param),
]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoMangle;
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_attr_parsing/src/attributes/deprecation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
Allow(Target::Impl { of_trait: false }),
Allow(Target::Crate),
Error(Target::WherePredicate),
Error(Target::Param),
]);
const TEMPLATE: AttributeTemplate = template!(
Word,
Expand Down
71 changes: 38 additions & 33 deletions compiler/rustc_attr_parsing/src/attributes/doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use rustc_hir::lints::AttributeLintKind;
use rustc_span::{Span, Symbol, edition, sym};
use thin_vec::ThinVec;

use super::prelude::{ALL_TARGETS, AllowedTargets};
use super::prelude::*;
use super::{AcceptMapping, AttributeParser};
use crate::context::{AcceptContext, FinalizeContext, Stage};
use crate::parser::{ArgParser, MetaItemOrLitParser, MetaItemParser, OwnedPathParser};
Expand Down Expand Up @@ -584,38 +584,43 @@ impl<S: Stage> AttributeParser<S> for DocParser {
},
)];
// FIXME: Currently emitted from 2 different places, generating duplicated warnings.
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
// const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
// Allow(Target::ExternCrate),
// Allow(Target::Use),
// Allow(Target::Static),
// Allow(Target::Const),
// Allow(Target::Fn),
// Allow(Target::Mod),
// Allow(Target::ForeignMod),
// Allow(Target::TyAlias),
// Allow(Target::Enum),
// Allow(Target::Variant),
// Allow(Target::Struct),
// Allow(Target::Field),
// Allow(Target::Union),
// Allow(Target::Trait),
// Allow(Target::TraitAlias),
// Allow(Target::Impl { of_trait: true }),
// Allow(Target::Impl { of_trait: false }),
// Allow(Target::AssocConst),
// Allow(Target::Method(MethodKind::Inherent)),
// Allow(Target::Method(MethodKind::Trait { body: true })),
// Allow(Target::Method(MethodKind::Trait { body: false })),
// Allow(Target::Method(MethodKind::TraitImpl)),
// Allow(Target::AssocTy),
// Allow(Target::ForeignFn),
// Allow(Target::ForeignStatic),
// Allow(Target::ForeignTy),
// Allow(Target::MacroDef),
// Allow(Target::Crate),
// Error(Target::WherePredicate),
// ]);
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
Allow(Target::ExternCrate),
Allow(Target::Use),
Allow(Target::Static),
Allow(Target::Const),
Allow(Target::Fn),
Allow(Target::Mod),
Allow(Target::ForeignMod),
Allow(Target::TyAlias),
Allow(Target::Enum),
Allow(Target::Variant),
Allow(Target::Struct),
Allow(Target::Field),
Allow(Target::Union),
Allow(Target::Trait),
Allow(Target::TraitAlias),
Allow(Target::Impl { of_trait: true }),
Allow(Target::Impl { of_trait: false }),
Allow(Target::AssocConst),
Allow(Target::Method(MethodKind::Inherent)),
Allow(Target::Method(MethodKind::Trait { body: true })),
Allow(Target::Method(MethodKind::Trait { body: false })),
Allow(Target::Method(MethodKind::TraitImpl)),
Allow(Target::AssocTy),
Allow(Target::ForeignFn),
Allow(Target::ForeignStatic),
Allow(Target::ForeignTy),
Allow(Target::MacroDef),
Allow(Target::Crate),
Allow(Target::Expression),
Allow(Target::ExprField),
Allow(Target::Arm),
Allow(Target::Statement),
Allow(Target::PatField),
Error(Target::WherePredicate),
Error(Target::Param),
]);

fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
if self.nb_doc_attrs != 0 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ impl<S: Stage> SingleAttributeParser<S> for InstructionSetParser {
Allow(Target::Method(MethodKind::Inherent)),
Allow(Target::Method(MethodKind::TraitImpl)),
Allow(Target::Method(MethodKind::Trait { body: true })),
Error(Target::Param),
]);
const TEMPLATE: AttributeTemplate = template!(List: &["set"], "https://doc.rust-lang.org/reference/attributes/codegen.html#the-instruction_set-attribute");
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_attr_parsing/src/attributes/link_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ impl<S: Stage> SingleAttributeParser<S> for LinkNameParser {
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
Allow(Target::ForeignFn),
Allow(Target::ForeignStatic),
Error(Target::Param),
]);
const TEMPLATE: AttributeTemplate = template!(
NameValueStr: "name",
Expand Down Expand Up @@ -471,6 +472,7 @@ impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser {
Allow(Target::Method(MethodKind::Inherent)),
Allow(Target::Method(MethodKind::Trait { body: true })),
Allow(Target::Method(MethodKind::TraitImpl)),
Error(Target::Param),
]);
const TEMPLATE: AttributeTemplate = template!(
NameValueStr: "name",
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for AutomaticallyDerivedParser {
Allow(Target::Impl { of_trait: true }),
Error(Target::Crate),
Error(Target::WherePredicate),
Error(Target::Param),
]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::AutomaticallyDerived;
}
2 changes: 2 additions & 0 deletions compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const MACRO_USE_ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnR
Allow(Target::ExternCrate),
Allow(Target::Crate),
Error(Target::WherePredicate),
Error(Target::Param),
]);

impl<S: Stage> AttributeParser<S> for MacroUseParser {
Expand Down Expand Up @@ -137,6 +138,7 @@ impl<S: Stage> SingleAttributeParser<S> for MacroExportParser {
Allow(Target::MacroDef),
Error(Target::WherePredicate),
Error(Target::Crate),
Error(Target::Param),
]);

fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_attr_parsing/src/attributes/must_use.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ impl<S: Stage> SingleAttributeParser<S> for MustUseParser {
// `#[must_use]`
Allow(Target::Trait),
Error(Target::WherePredicate),
Error(Target::Param),
]);
const TEMPLATE: AttributeTemplate = template!(
Word, NameValueStr: "reason",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ pub(crate) struct NoImplicitPreludeParser;
impl<S: Stage> NoArgsAttributeParser<S> for NoImplicitPreludeParser {
const PATH: &[rustc_span::Symbol] = &[sym::no_implicit_prelude];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowListWarnRest(&[Allow(Target::Mod), Allow(Target::Crate)]);
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
Allow(Target::Mod),
Allow(Target::Crate),
Error(Target::Param),
]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoImplicitPrelude;
}
7 changes: 5 additions & 2 deletions compiler/rustc_attr_parsing/src/attributes/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@ impl<S: Stage> SingleAttributeParser<S> for PathParser {
const PATH: &[Symbol] = &[sym::path];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowListWarnRest(&[Allow(Target::Mod), Error(Target::Crate)]);
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
Allow(Target::Mod),
Error(Target::Crate),
Error(Target::Param),
]);
const TEMPLATE: AttributeTemplate = template!(
NameValueStr: "file",
"https://doc.rust-lang.org/reference/items/modules.html#the-path-attribute"
Expand Down
14 changes: 10 additions & 4 deletions compiler/rustc_attr_parsing/src/attributes/test_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@ impl<S: Stage> SingleAttributeParser<S> for IgnoreParser {
const PATH: &[Symbol] = &[sym::ignore];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowListWarnRest(&[Allow(Target::Fn), Error(Target::WherePredicate)]);
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
Allow(Target::Fn),
Error(Target::WherePredicate),
Error(Target::Param),
]);
const TEMPLATE: AttributeTemplate = template!(
Word, NameValueStr: "reason",
"https://doc.rust-lang.org/reference/attributes/testing.html#the-ignore-attribute"
Expand Down Expand Up @@ -42,8 +45,11 @@ impl<S: Stage> SingleAttributeParser<S> for ShouldPanicParser {
const PATH: &[Symbol] = &[sym::should_panic];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowListWarnRest(&[Allow(Target::Fn), Error(Target::WherePredicate)]);
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
Allow(Target::Fn),
Error(Target::WherePredicate),
Error(Target::Param),
]);
const TEMPLATE: AttributeTemplate = template!(
Word, List: &[r#"expected = "reason""#], NameValueStr: "reason",
"https://doc.rust-lang.org/reference/attributes/testing.html#the-should_panic-attribute"
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ use crate::session_diagnostics::{
};
use crate::target_checking::AllowedTargets;

type GroupType<S> = LazyLock<GroupTypeInner<S>>;
pub(crate) type GroupType<S> = LazyLock<GroupTypeInner<S>>;

pub(super) struct GroupTypeInner<S: Stage> {
pub(super) accepters: BTreeMap<&'static [Symbol], Vec<GroupTypeInnerAccept<S>>>,
Expand Down
34 changes: 32 additions & 2 deletions compiler/rustc_attr_parsing/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ use rustc_session::Session;
use rustc_session::lint::BuiltinLintDiag;
use rustc_span::{DUMMY_SP, Span, Symbol, sym};

use crate::context::{AcceptContext, FinalizeContext, SharedContext, Stage};
use crate::context::{AcceptContext, FinalizeContext, GroupType, SharedContext, Stage};
use crate::early_parsed::{EARLY_PARSED_ATTRIBUTES, EarlyParsedState};
use crate::parser::{ArgParser, PathParser, RefPathParser};
use crate::session_diagnostics::ParsedDescription;
use crate::session_diagnostics::{AttributeTargetRegression, ParsedDescription};
use crate::target_checking::AllowedTargets;
use crate::{Early, Late, OmitDoc, ShouldEmit};

/// Context created once, for example as part of the ast lowering
Expand Down Expand Up @@ -237,7 +238,9 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
features: &'sess Features,
tools: Vec<Symbol>,
stage: S,
dcx: DiagCtxtHandle<'_>,
) -> Self {
Self::check_allowed_attrs(S::parsers(), dcx);
Self { features: Some(features), tools, parse_only: None, sess, stage }
}

Expand Down Expand Up @@ -486,4 +489,31 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
}
}
}

fn check_allowed_attrs(parsers: &'static GroupType<S>, dcx: DiagCtxtHandle<'_>) {
use crate::target_checking::Policy::{Allow, Error, Warn};
let targets = [Target::Param];
for (syms, accepters) in &parsers.accepters {
for accept in accepters {
let AllowedTargets::AllowListWarnRest(allow_list) = accept.allowed_targets else {
continue;
};

let missing_targets = targets.into_iter().flat_map(|target| {
(!allow_list.iter().any(|policy| {
[Allow(target), Warn(target), Error(target)].contains(policy)
}))
.then_some(target)
});
for target in missing_targets {
for sym in *syms {
dcx.emit_warn(AttributeTargetRegression {
attribute_symbol: *sym,
target: target.name(),
});
}
}
}
}
}
}
9 changes: 9 additions & 0 deletions compiler/rustc_attr_parsing/src/session_diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -946,3 +946,12 @@ pub(crate) struct UnsupportedInstructionSet<'a> {
pub instruction_set: Symbol,
pub current_target: &'a TargetTuple,
}

#[derive(Diagnostic)]
#[diag(attr_parsing_target_regression)]
#[help]
#[note]
pub(crate) struct AttributeTargetRegression {
pub attribute_symbol: Symbol,
pub target: &'static str,
}
1 change: 1 addition & 0 deletions compiler/rustc_resolve/src/def_collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
self.resolver.tcx.features(),
Vec::new(),
Early { emit_errors: ShouldEmit::Nothing },
self.resolver.dcx(),
);
let attrs = parser.parse_attribute_list(
&i.attrs,
Expand Down
Loading
Loading