diff options
Diffstat (limited to 'compiler/rustc_passes/src/check_attr.rs')
| -rw-r--r-- | compiler/rustc_passes/src/check_attr.rs | 180 |
1 files changed, 105 insertions, 75 deletions
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 1254ae8cfc8..4fe84b91b8b 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -11,14 +11,15 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::StashKey; use rustc_errors::{Applicability, DiagCtxt, IntoDiagArg, MultiSpan}; use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; -use rustc_hir as hir; use rustc_hir::def_id::LocalModDefId; use rustc_hir::intravisit::{self, Visitor}; +use rustc_hir::{self as hir}; use rustc_hir::{ self, FnSig, ForeignItem, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID, CRATE_OWNER_ID, }; -use rustc_hir::{MethodKind, Target, Unsafety}; +use rustc_hir::{MethodKind, Safety, Target}; use rustc_macros::LintDiagnostic; +use rustc_middle::bug; use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault; use rustc_middle::query::Providers; @@ -38,15 +39,13 @@ use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::ObligationCtxt; use std::cell::Cell; use std::collections::hash_map::Entry; +use tracing::debug; #[derive(LintDiagnostic)] #[diag(passes_diagnostic_diagnostic_on_unimplemented_only_for_traits)] -pub struct DiagnosticOnUnimplementedOnlyForTraits; +struct DiagnosticOnUnimplementedOnlyForTraits; -pub(crate) fn target_from_impl_item<'tcx>( - tcx: TyCtxt<'tcx>, - impl_item: &hir::ImplItem<'_>, -) -> Target { +fn target_from_impl_item<'tcx>(tcx: TyCtxt<'tcx>, impl_item: &hir::ImplItem<'_>) -> Target { match impl_item.kind { hir::ImplItemKind::Const(..) => Target::AssocConst, hir::ImplItemKind::Fn(..) => { @@ -98,7 +97,7 @@ struct CheckAttrVisitor<'tcx> { } impl<'tcx> CheckAttrVisitor<'tcx> { - pub fn dcx(&self) -> &'tcx DiagCtxt { + fn dcx(&self) -> &'tcx DiagCtxt { self.tcx.dcx() } @@ -115,92 +114,96 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let mut seen = FxHashMap::default(); let attrs = self.tcx.hir().attrs(hir_id); for attr in attrs { - if attr.path_matches(&[sym::diagnostic, sym::on_unimplemented]) { - self.check_diagnostic_on_unimplemented(attr.span, hir_id, target); - } - match attr.name_or_empty() { - sym::do_not_recommend => self.check_do_not_recommend(attr.span, target), - sym::inline => self.check_inline(hir_id, attr, span, target), - sym::coverage => self.check_coverage(hir_id, attr, span, target), - sym::non_exhaustive => self.check_non_exhaustive(hir_id, attr, span, target), - sym::marker => self.check_marker(hir_id, attr, span, target), - sym::target_feature => self.check_target_feature(hir_id, attr, span, target, attrs), - sym::thread_local => self.check_thread_local(attr, span, target), - sym::track_caller => { + match attr.path().as_slice() { + [sym::diagnostic, sym::do_not_recommend] => { + self.check_do_not_recommend(attr.span, hir_id, target) + } + [sym::diagnostic, sym::on_unimplemented] => { + self.check_diagnostic_on_unimplemented(attr.span, hir_id, target) + } + [sym::inline] => self.check_inline(hir_id, attr, span, target), + [sym::coverage] => self.check_coverage(hir_id, attr, span, target), + [sym::non_exhaustive] => self.check_non_exhaustive(hir_id, attr, span, target), + [sym::marker] => self.check_marker(hir_id, attr, span, target), + [sym::target_feature] => { + 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( + [sym::doc] => self.check_doc_attrs( attr, hir_id, target, &mut specified_inline, &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 => { + [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::allow_internal_unstable => { + [sym::allow_internal_unstable] => { self.check_allow_internal_unstable(hir_id, attr, span, target, attrs) } - sym::debugger_visualizer => self.check_debugger_visualizer(attr, target), - sym::rustc_allow_const_fn_unstable => { + [sym::debugger_visualizer] => self.check_debugger_visualizer(attr, target), + [sym::rustc_allow_const_fn_unstable] => { self.check_rustc_allow_const_fn_unstable(hir_id, attr, span, target) } - sym::rustc_std_internal_symbol => { + [sym::rustc_std_internal_symbol] => { self.check_rustc_std_internal_symbol(attr, span, target) } - sym::naked => self.check_naked(hir_id, attr, span, target), - sym::rustc_never_returns_null_ptr => { + [sym::naked] => self.check_naked(hir_id, attr, span, target), + [sym::rustc_never_returns_null_ptr] => { self.check_applied_to_fn_or_method(hir_id, attr, span, target) } - sym::rustc_legacy_const_generics => { + [sym::rustc_legacy_const_generics] => { self.check_rustc_legacy_const_generics(hir_id, attr, span, target, item) } - sym::rustc_lint_query_instability => { + [sym::rustc_lint_query_instability] => { self.check_rustc_lint_query_instability(hir_id, attr, span, target) } - sym::rustc_lint_diagnostics => { + [sym::rustc_lint_diagnostics] => { self.check_rustc_lint_diagnostics(hir_id, attr, span, target) } - sym::rustc_lint_opt_ty => self.check_rustc_lint_opt_ty(attr, span, target), - sym::rustc_lint_opt_deny_field_access => { + [sym::rustc_lint_opt_ty] => self.check_rustc_lint_opt_ty(attr, span, target), + [sym::rustc_lint_opt_deny_field_access] => { self.check_rustc_lint_opt_deny_field_access(attr, span, target) } - sym::rustc_clean - | sym::rustc_dirty - | sym::rustc_if_this_changed - | sym::rustc_then_this_would_need => self.check_rustc_dirty_clean(attr), - sym::rustc_coinductive - | sym::rustc_must_implement_one_of - | sym::rustc_deny_explicit_impl - | sym::const_trait => self.check_must_be_applied_to_trait(attr, span, target), - sym::cmse_nonsecure_entry => { + [sym::rustc_clean] + | [sym::rustc_dirty] + | [sym::rustc_if_this_changed] + | [sym::rustc_then_this_would_need] => self.check_rustc_dirty_clean(attr), + [sym::rustc_coinductive] + | [sym::rustc_must_implement_one_of] + | [sym::rustc_deny_explicit_impl] + | [sym::const_trait] => self.check_must_be_applied_to_trait(attr, span, target), + [sym::cmse_nonsecure_entry] => { self.check_cmse_nonsecure_entry(hir_id, attr, 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::must_use => self.check_must_use(hir_id, attr, target), - sym::rustc_pass_by_value => self.check_pass_by_value(attr, span, target), - sym::rustc_allow_incoherent_impl => { + [sym::collapse_debuginfo] => self.check_collapse_debuginfo(attr, span, target), + [sym::must_not_suspend] => self.check_must_not_suspend(attr, span, target), + [sym::must_use] => self.check_must_use(hir_id, attr, target), + [sym::rustc_pass_by_value] => self.check_pass_by_value(attr, span, target), + [sym::rustc_allow_incoherent_impl] => { self.check_allow_incoherent_impl(attr, span, target) } - sym::rustc_has_incoherent_inherent_impls => { + [sym::rustc_has_incoherent_inherent_impls] => { self.check_has_incoherent_inherent_impls(attr, span, target) } - sym::ffi_pure => self.check_ffi_pure(attr.span, attrs, target), - sym::ffi_const => self.check_ffi_const(attr.span, target), - sym::rustc_const_unstable - | sym::rustc_const_stable - | sym::unstable - | sym::stable - | sym::rustc_allowed_through_unstable_modules - | sym::rustc_promotable => self.check_stability_promotable(attr, target), - sym::link_ordinal => self.check_link_ordinal(attr, span, target), - sym::rustc_confusables => self.check_confusables(attr, target), - sym::rustc_safe_intrinsic => { + [sym::ffi_pure] => self.check_ffi_pure(attr.span, attrs, target), + [sym::ffi_const] => self.check_ffi_const(attr.span, target), + [sym::rustc_const_unstable] + | [sym::rustc_const_stable] + | [sym::unstable] + | [sym::stable] + | [sym::rustc_allowed_through_unstable_modules] + | [sym::rustc_promotable] => self.check_stability_promotable(attr, target), + [sym::link_ordinal] => self.check_link_ordinal(attr, span, target), + [sym::rustc_confusables] => self.check_confusables(attr, target), + [sym::rustc_safe_intrinsic] => { self.check_rustc_safe_intrinsic(hir_id, attr, span, target) } _ => true, @@ -292,18 +295,26 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ); } - /// Checks if `#[do_not_recommend]` is applied on a trait impl. - fn check_do_not_recommend(&self, attr_span: Span, target: Target) -> bool { - if let Target::Impl = target { - true - } else { - self.dcx().emit_err(errors::IncorrectDoNotRecommendLocation { span: attr_span }); - false + /// Checks if `#[diagnostic::do_not_recommend]` is applied on a trait impl. + fn check_do_not_recommend(&self, attr_span: Span, hir_id: HirId, target: Target) -> bool { + if !matches!(target, Target::Impl) { + self.tcx.emit_node_span_lint( + UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + hir_id, + attr_span, + errors::IncorrectDoNotRecommendLocation, + ); } + true } /// Checks if `#[diagnostic::on_unimplemented]` is applied to a trait definition - fn check_diagnostic_on_unimplemented(&self, attr_span: Span, hir_id: HirId, target: Target) { + fn check_diagnostic_on_unimplemented( + &self, + attr_span: Span, + hir_id: HirId, + target: Target, + ) -> bool { if !matches!(target, Target::Trait) { self.tcx.emit_node_span_lint( UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, @@ -312,6 +323,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { DiagnosticOnUnimplementedOnlyForTraits, ); } + true } /// Checks if an `#[inline]` is applied to a function or a closure. Returns `true` if valid. @@ -519,7 +531,26 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.dcx().emit_err(errors::NakedTrackedCaller { attr_span }); false } - Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => true, + Target::Fn => { + // `#[track_caller]` is not valid on weak lang items because they are called via + // `extern` declarations and `#[track_caller]` would alter their ABI. + if let Some((lang_item, _)) = hir::lang_items::extract(attrs) + && let Some(item) = hir::LangItem::from_name(lang_item) + && item.is_weak() + { + let sig = self.tcx.hir_node(hir_id).fn_sig().unwrap(); + + self.dcx().emit_err(errors::LangItemWithTrackCaller { + attr_span, + name: lang_item, + sig_span: sig.span, + }); + false + } else { + true + } + } + Target::Method(..) | Target::ForeignFn | Target::Closure => true, // FIXME(#80564): We permit struct fields, match arms and macro defs to have an // `#[track_caller]` attribute with just a lint, because we previously // erroneously allowed it and some crates used it accidentally, to be compatible @@ -602,7 +633,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ) -> bool { match target { Target::Fn => { - // `#[target_feature]` is not allowed in language items. + // `#[target_feature]` is not allowed in lang items. if let Some((lang_item, _)) = hir::lang_items::extract(attrs) // Calling functions with `#[target_feature]` is // not unsafe on WASM, see #84988 @@ -2315,7 +2346,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { }), token_stream, false, - Unsafety::Normal, + Safety::Safe, Abi::Rust, ); @@ -2342,7 +2373,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { cause.span = ty.span; } } - TypeError::UnsafetyMismatch(_) => { + TypeError::SafetyMismatch(_) => { // FIXME: Would be nice if we had a span here.. } TypeError::AbiMismatch(_) => { @@ -2503,7 +2534,6 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { sym::automatically_derived, sym::start, sym::rustc_main, - sym::unix_sigpipe, sym::derive, sym::test, sym::test_case, |
