diff options
Diffstat (limited to 'compiler/rustc_passes/src/check_attr.rs')
| -rw-r--r-- | compiler/rustc_passes/src/check_attr.rs | 234 |
1 files changed, 131 insertions, 103 deletions
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index c2a58b4cd7d..1b965b9545c 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -9,7 +9,7 @@ use std::cell::Cell; use std::collections::hash_map::Entry; use rustc_abi::{Align, ExternAbi, Size}; -use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, MetaItemLit, ast}; +use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, ast}; use rustc_attr_data_structures::{AttributeKind, InlineAttr, ReprAttr, find_attr}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey}; @@ -30,11 +30,13 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, TyCtxt, TypingMode}; use rustc_middle::{bug, span_bug}; use rustc_session::config::CrateType; +use rustc_session::lint; use rustc_session::lint::builtin::{ CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS, UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES, }; use rustc_session::parse::feature_err; +use rustc_span::edition::Edition; use rustc_span::{BytePos, DUMMY_SP, Span, Symbol, edition, sym}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs}; @@ -118,6 +120,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> { for attr in attrs { let mut style = None; match attr { + Attribute::Parsed(AttributeKind::SkipDuringMethodDispatch { + span: attr_span, + .. + }) => { + self.check_must_be_applied_to_trait(*attr_span, span, target); + } Attribute::Parsed(AttributeKind::Confusables { first_span, .. }) => { self.check_confusables(*first_span, target); } @@ -132,6 +140,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::Optimize(_, attr_span)) => { self.check_optimize(hir_id, *attr_span, span, target) } + Attribute::Parsed(AttributeKind::LoopMatch(attr_span)) => { + self.check_loop_match(hir_id, *attr_span, target) + } + Attribute::Parsed(AttributeKind::ConstContinue(attr_span)) => { + self.check_const_continue(hir_id, *attr_span, target) + } Attribute::Parsed(AttributeKind::AllowInternalUnstable(syms)) => self .check_allow_internal_unstable( hir_id, @@ -150,19 +164,34 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } Attribute::Parsed(AttributeKind::Repr(_)) => { /* handled below this loop and elsewhere */ } - + Attribute::Parsed(AttributeKind::RustcObjectLifetimeDefault) => { + self.check_object_lifetime_default(hir_id); + } &Attribute::Parsed(AttributeKind::PubTransparent(attr_span)) => { self.check_rustc_pub_transparent(attr_span, span, attrs) } Attribute::Parsed(AttributeKind::Cold(attr_span)) => { self.check_cold(hir_id, *attr_span, span, target) } + Attribute::Parsed(AttributeKind::ExportName { span: attr_span, .. }) => { + self.check_export_name(hir_id, *attr_span, span, target) + } Attribute::Parsed(AttributeKind::Align { align, span: repr_span }) => { self.check_align(span, target, *align, *repr_span) } + Attribute::Parsed(AttributeKind::LinkSection { span: attr_span, .. }) => { + self.check_link_section(hir_id, *attr_span, span, target) + } Attribute::Parsed(AttributeKind::Naked(attr_span)) => { self.check_naked(hir_id, *attr_span, span, target) } + Attribute::Parsed(AttributeKind::TrackCaller(attr_span)) => { + self.check_track_caller(hir_id, *attr_span, attrs, span, target) + } + Attribute::Parsed( + AttributeKind::RustcLayoutScalarValidRangeStart(_num, attr_span) + | AttributeKind::RustcLayoutScalarValidRangeEnd(_num, attr_span), + ) => self.check_rustc_layout_scalar_valid_range(*attr_span, span, target), Attribute::Parsed( AttributeKind::BodyStability { .. } | AttributeKind::ConstStabilityIndirect @@ -171,6 +200,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::AsPtr(attr_span)) => { self.check_applied_to_fn_or_method(hir_id, *attr_span, span, target) } + Attribute::Parsed(AttributeKind::LinkName { span: attr_span, name }) => { + self.check_link_name(hir_id, *attr_span, *name, span, target) + } Attribute::Parsed(AttributeKind::MayDangle(attr_span)) => { self.check_may_dangle(hir_id, *attr_span) } @@ -180,6 +212,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::NoMangle(attr_span)) => { self.check_no_mangle(hir_id, *attr_span, span, target) } + Attribute::Parsed(AttributeKind::Used { span: attr_span, .. }) => { + self.check_used(*attr_span, target, span); + } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); match attr.path().as_slice() { @@ -199,9 +234,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.check_target_feature(hir_id, attr, span, target, attrs) } [sym::thread_local, ..] => self.check_thread_local(attr, span, target), - [sym::track_caller, ..] => { - self.check_track_caller(hir_id, attr.span(), attrs, span, target) - } [sym::doc, ..] => self.check_doc_attrs( attr, attr_item.style, @@ -211,11 +243,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { &mut doc_aliases, ), [sym::no_link, ..] => self.check_no_link(hir_id, attr, span, target), - [sym::export_name, ..] => self.check_export_name(hir_id, attr, span, target), - [sym::rustc_layout_scalar_valid_range_start, ..] - | [sym::rustc_layout_scalar_valid_range_end, ..] => { - self.check_rustc_layout_scalar_valid_range(attr, span, target) - } [sym::debugger_visualizer, ..] => self.check_debugger_visualizer(attr, target), [sym::rustc_std_internal_symbol, ..] => { self.check_rustc_std_internal_symbol(attr, span, target) @@ -250,7 +277,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | [sym::rustc_must_implement_one_of, ..] | [sym::rustc_deny_explicit_impl, ..] | [sym::rustc_do_not_implement_via_object, ..] - | [sym::const_trait, ..] => self.check_must_be_applied_to_trait(attr, span, target), + | [sym::const_trait, ..] => self.check_must_be_applied_to_trait(attr.span(), span, target), [sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target), [sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target), [sym::rustc_pass_by_value, ..] => self.check_pass_by_value(attr, span, target), @@ -264,8 +291,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::ffi_const, ..] => self.check_ffi_const(attr.span(), target), [sym::link_ordinal, ..] => self.check_link_ordinal(attr, span, target), [sym::link, ..] => self.check_link(hir_id, attr, span, target), - [sym::link_name, ..] => self.check_link_name(hir_id, attr, span, target), - [sym::link_section, ..] => self.check_link_section(hir_id, attr, span, target), [sym::macro_use, ..] | [sym::macro_escape, ..] => { self.check_macro_use(hir_id, attr, target) } @@ -280,7 +305,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::no_implicit_prelude, ..] => { self.check_generic_attr(hir_id, attr, target, Target::Mod) } - [sym::rustc_object_lifetime_default, ..] => self.check_object_lifetime_default(hir_id), [sym::proc_macro, ..] => { self.check_proc_macro(hir_id, target, ProcMacroKind::FunctionLike) } @@ -317,7 +341,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::cfi_encoding // FIXME(cfi_encoding) | sym::pointee // FIXME(derive_coerce_pointee) | sym::omit_gdb_pretty_printer_section // FIXME(omit_gdb_pretty_printer_section) - | sym::used // handled elsewhere to restrict to static items | sym::instruction_set // broken on stable!!! | sym::windows_subsystem // broken on stable!!! | sym::patchable_function_entry // FIXME(patchable_function_entry) @@ -387,8 +410,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } self.check_repr(attrs, span, target, item, hir_id); - self.check_used(attrs, target, span); self.check_rustc_force_inline(hir_id, attrs, span, target); + self.check_mix_no_mangle_export(hir_id, attrs); } fn inline_attr_str_error_with_macro_def(&self, hir_id: HirId, attr_span: Span, sym: &str) { @@ -716,9 +739,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { - for attr in attrs { - self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "track_caller"); - } + self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "track_caller"); } _ => { self.dcx().emit_err(errors::TrackedCallerWrongLocation { @@ -1588,7 +1609,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if `#[link_name]` is applied to an item other than a foreign function or static. - fn check_link_name(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) { + fn check_link_name( + &self, + hir_id: HirId, + attr_span: Span, + name: Symbol, + span: Span, + target: Target, + ) { match target { Target::ForeignFn | Target::ForeignStatic => {} // FIXME(#80564): We permit struct fields, match arms and macro defs to have an @@ -1596,27 +1624,18 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "link_name"); + self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "link_name"); } _ => { - // FIXME: #[cold] was previously allowed on non-functions/statics and some crates + // FIXME: #[link_name] was previously allowed on non-functions/statics and some crates // used this, so only emit a warning. - let attr_span = matches!(target, Target::ForeignMod).then_some(attr.span()); - if let Some(s) = attr.value_str() { - self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr.span(), - errors::LinkName { span, attr_span, value: s.as_str() }, - ); - } else { - self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr.span(), - errors::LinkName { span, attr_span, value: "..." }, - ); - }; + let help_span = matches!(target, Target::ForeignMod).then_some(attr_span); + self.tcx.emit_node_span_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr_span, + errors::LinkName { span, help_span, value: name.as_str() }, + ); } } } @@ -1643,7 +1662,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if `#[export_name]` is applied to a function or static. - fn check_export_name(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) { + fn check_export_name(&self, hir_id: HirId, attr_span: Span, span: Span, target: Target) { match target { Target::Static | Target::Fn => {} Target::Method(..) if self.is_impl_item(hir_id) => {} @@ -1652,32 +1671,19 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "export_name"); + self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "export_name"); } _ => { - self.dcx().emit_err(errors::ExportName { attr_span: attr.span(), span }); + self.dcx().emit_err(errors::ExportName { attr_span, span }); } } } - fn check_rustc_layout_scalar_valid_range(&self, attr: &Attribute, span: Span, target: Target) { + fn check_rustc_layout_scalar_valid_range(&self, attr_span: Span, span: Span, target: Target) { if target != Target::Struct { - self.dcx().emit_err(errors::RustcLayoutScalarValidRangeNotStruct { - attr_span: attr.span(), - span, - }); + self.dcx().emit_err(errors::RustcLayoutScalarValidRangeNotStruct { attr_span, span }); return; } - - let Some(list) = attr.meta_item_list() else { - return; - }; - - if !matches!(&list[..], &[MetaItemInner::Lit(MetaItemLit { kind: LitKind::Int(..), .. })]) { - self.tcx - .dcx() - .emit_err(errors::RustcLayoutScalarValidRangeArg { attr_span: attr.span() }); - } } /// Checks if `#[rustc_legacy_const_generics]` is applied to a function and has a valid argument. @@ -1805,20 +1811,17 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if the attribute is applied to a trait. - fn check_must_be_applied_to_trait(&self, attr: &Attribute, span: Span, target: Target) { + fn check_must_be_applied_to_trait(&self, attr_span: Span, defn_span: Span, target: Target) { match target { Target::Trait => {} _ => { - self.dcx().emit_err(errors::AttrShouldBeAppliedToTrait { - attr_span: attr.span(), - defn_span: span, - }); + self.dcx().emit_err(errors::AttrShouldBeAppliedToTrait { attr_span, defn_span }); } } } /// Checks if `#[link_section]` is applied to a function or static. - fn check_link_section(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) { + fn check_link_section(&self, hir_id: HirId, attr_span: Span, span: Span, target: Target) { match target { Target::Static | Target::Fn | Target::Method(..) => {} // FIXME(#80564): We permit struct fields, match arms and macro defs to have an @@ -1826,7 +1829,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "link_section"); + self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "link_section"); } _ => { // FIXME: #[link_section] was previously allowed on non-functions/statics and some @@ -1834,7 +1837,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr_span, errors::LinkSection { span }, ); } @@ -2095,44 +2098,13 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_used(&self, attrs: &[Attribute], target: Target, target_span: Span) { - let mut used_linker_span = None; - let mut used_compiler_span = None; - for attr in attrs.iter().filter(|attr| attr.has_name(sym::used)) { - if target != Target::Static { - self.dcx().emit_err(errors::UsedStatic { - attr_span: attr.span(), - span: target_span, - target: target.name(), - }); - } - let inner = attr.meta_item_list(); - match inner.as_deref() { - Some([item]) if item.has_name(sym::linker) => { - if used_linker_span.is_none() { - used_linker_span = Some(attr.span()); - } - } - Some([item]) if item.has_name(sym::compiler) => { - if used_compiler_span.is_none() { - used_compiler_span = Some(attr.span()); - } - } - Some(_) => { - // This error case is handled in rustc_hir_analysis::collect. - } - None => { - // Default case (compiler) when arg isn't defined. - if used_compiler_span.is_none() { - used_compiler_span = Some(attr.span()); - } - } - } - } - if let (Some(linker_span), Some(compiler_span)) = (used_linker_span, used_compiler_span) { - self.tcx - .dcx() - .emit_err(errors::UsedCompilerLinker { spans: vec![linker_span, compiler_span] }); + fn check_used(&self, attr_span: Span, target: Target, target_span: Span) { + if target != Target::Static { + self.dcx().emit_err(errors::UsedStatic { + attr_span, + span: target_span, + target: target.name(), + }); } } @@ -2619,6 +2591,36 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } + fn check_mix_no_mangle_export(&self, hir_id: HirId, attrs: &[Attribute]) { + if let Some(export_name_span) = find_attr!(attrs, AttributeKind::ExportName { span: export_name_span, .. } => *export_name_span) + && let Some(no_mangle_span) = + find_attr!(attrs, AttributeKind::NoMangle(no_mangle_span) => *no_mangle_span) + { + let no_mangle_attr = if no_mangle_span.edition() >= Edition::Edition2024 { + "#[unsafe(no_mangle)]" + } else { + "#[no_mangle]" + }; + let export_name_attr = if export_name_span.edition() >= Edition::Edition2024 { + "#[unsafe(export_name)]" + } else { + "#[export_name]" + }; + + self.tcx.emit_node_span_lint( + lint::builtin::UNUSED_ATTRIBUTES, + hir_id, + no_mangle_span, + errors::MixedExportNameAndNoMangle { + no_mangle_span, + export_name_span, + no_mangle_attr, + export_name_attr, + }, + ); + } + } + /// Checks if `#[autodiff]` is applied to an item other than a function item. fn check_autodiff(&self, _hir_id: HirId, _attr: &Attribute, span: Span, target: Target) { debug!("check_autodiff"); @@ -2630,6 +2632,32 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } } + + fn check_loop_match(&self, hir_id: HirId, attr_span: Span, target: Target) { + let node_span = self.tcx.hir_span(hir_id); + + if !matches!(target, Target::Expression) { + self.dcx().emit_err(errors::LoopMatchAttr { attr_span, node_span }); + return; + } + + if !matches!(self.tcx.hir_expect_expr(hir_id).kind, hir::ExprKind::Loop(..)) { + self.dcx().emit_err(errors::LoopMatchAttr { attr_span, node_span }); + }; + } + + fn check_const_continue(&self, hir_id: HirId, attr_span: Span, target: Target) { + let node_span = self.tcx.hir_span(hir_id); + + if !matches!(target, Target::Expression) { + self.dcx().emit_err(errors::ConstContinueAttr { attr_span, node_span }); + return; + } + + if !matches!(self.tcx.hir_expect_expr(hir_id).kind, hir::ExprKind::Break(..)) { + self.dcx().emit_err(errors::ConstContinueAttr { attr_span, node_span }); + }; + } } impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { @@ -2804,7 +2832,7 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { .find(|item| !item.span.is_dummy()) // Skip prelude `use`s .map(|item| errors::ItemFollowingInnerAttr { span: if let Some(ident) = item.kind.ident() { ident.span } else { item.span }, - kind: item.kind.descr(), + kind: tcx.def_descr(item.owner_id.to_def_id()), }); let err = tcx.dcx().create_err(errors::InvalidAttrAtCrateLevel { span, |
