diff options
| author | Stuart Cook <Zalathar@users.noreply.github.com> | 2025-08-19 14:18:16 +1000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-08-19 14:18:16 +1000 |
| commit | 633cc0cc6cfc6b77da14864dbefb1dab25dcb8d0 (patch) | |
| tree | 145a2b42a2741b0f113868938d76e060d6988292 /compiler | |
| parent | 027c7a5d857ff9692ce40bfd3bc9a90ef3764232 (diff) | |
| parent | 95bdb34494ad795f552cab7a0eb7bfd2e98ef033 (diff) | |
| download | rust-633cc0cc6cfc6b77da14864dbefb1dab25dcb8d0.tar.gz rust-633cc0cc6cfc6b77da14864dbefb1dab25dcb8d0.zip | |
Rollup merge of #142681 - 1c3t3a:sanitize-off-on, r=rcvalle
Remove the `#[no_sanitize]` attribute in favor of `#[sanitize(xyz = "on|off")]`
This came up during the sanitizer stabilization (rust-lang/rust#123617). Instead of a `#[no_sanitize(xyz)]` attribute, we would like to have a `#[sanitize(xyz = "on|off")]` attribute, which is more powerful and allows to be extended in the future (instead
of just focusing on turning sanitizers off). The implementation is done according to what was [discussed on Zulip](https://rust-lang.zulipchat.com/#narrow/channel/343119-project-exploit-mitigations/topic/Stabilize.20the.20.60no_sanitize.60.20attribute/with/495377292)).
The new attribute also works on modules, traits and impl items and thus enables usage as the following:
```rust
#[sanitize(address = "off")]
mod foo {
fn unsanitized(..) {}
#[sanitize(address = "on")]
fn sanitized(..) {}
}
trait MyTrait {
#[sanitize(address = "off")]
fn unsanitized_default(..) {}
}
#[sanitize(thread = "off")]
impl MyTrait for () {
...
}
```
r? ```@rcvalle```
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_codegen_ssa/messages.ftl | 4 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 136 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/errors.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_feature/src/builtin_attrs.rs | 5 | ||||
| -rw-r--r-- | compiler/rustc_feature/src/removed.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_feature/src/unstable.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_lint_defs/src/builtin.rs | 12 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/middle/codegen_fn_attrs.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/query/erase.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/query/mod.rs | 12 | ||||
| -rw-r--r-- | compiler/rustc_passes/messages.ftl | 10 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/check_attr.rs | 61 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/errors.rs | 18 | ||||
| -rw-r--r-- | compiler/rustc_span/src/symbol.rs | 1 |
14 files changed, 182 insertions, 93 deletions
diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index b6cfea88363..42ba0154192 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -171,8 +171,8 @@ codegen_ssa_invalid_monomorphization_unsupported_symbol = invalid monomorphizati codegen_ssa_invalid_monomorphization_unsupported_symbol_of_size = invalid monomorphization of `{$name}` intrinsic: unsupported {$symbol} from `{$in_ty}` with element `{$in_elem}` of size `{$size}` to `{$ret_ty}` -codegen_ssa_invalid_no_sanitize = invalid argument for `no_sanitize` - .note = expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread` +codegen_ssa_invalid_sanitize = invalid argument for `sanitize` + .note = expected one of: `address`, `kernel_address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow_call_stack`, or `thread` codegen_ssa_invalid_windows_subsystem = invalid windows subsystem `{$subsystem}`, only `windows` and `console` are allowed diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index af70f0deb07..bf14c02a09c 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -77,32 +77,6 @@ fn parse_instruction_set_attr(tcx: TyCtxt<'_>, attr: &Attribute) -> Option<Instr } } -// FIXME(jdonszelmann): remove when no_sanitize becomes a parsed attr -fn parse_no_sanitize_attr(tcx: TyCtxt<'_>, attr: &Attribute) -> Option<SanitizerSet> { - let list = attr.meta_item_list()?; - let mut sanitizer_set = SanitizerSet::empty(); - - for item in list.iter() { - match item.name() { - Some(sym::address) => { - sanitizer_set |= SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS - } - Some(sym::cfi) => sanitizer_set |= SanitizerSet::CFI, - Some(sym::kcfi) => sanitizer_set |= SanitizerSet::KCFI, - Some(sym::memory) => sanitizer_set |= SanitizerSet::MEMORY, - Some(sym::memtag) => sanitizer_set |= SanitizerSet::MEMTAG, - Some(sym::shadow_call_stack) => sanitizer_set |= SanitizerSet::SHADOWCALLSTACK, - Some(sym::thread) => sanitizer_set |= SanitizerSet::THREAD, - Some(sym::hwaddress) => sanitizer_set |= SanitizerSet::HWADDRESS, - _ => { - tcx.dcx().emit_err(errors::InvalidNoSanitize { span: item.span() }); - } - } - } - - Some(sanitizer_set) -} - // FIXME(jdonszelmann): remove when patchable_function_entry becomes a parsed attr fn parse_patchable_function_entry( tcx: TyCtxt<'_>, @@ -161,7 +135,7 @@ fn parse_patchable_function_entry( #[derive(Default)] struct InterestingAttributeDiagnosticSpans { link_ordinal: Option<Span>, - no_sanitize: Option<Span>, + sanitize: Option<Span>, inline: Option<Span>, no_mangle: Option<Span>, } @@ -330,11 +304,7 @@ fn process_builtin_attrs( codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED } sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL, - sym::no_sanitize => { - interesting_spans.no_sanitize = Some(attr.span()); - codegen_fn_attrs.no_sanitize |= - parse_no_sanitize_attr(tcx, attr).unwrap_or_default(); - } + sym::sanitize => interesting_spans.sanitize = Some(attr.span()), sym::instruction_set => { codegen_fn_attrs.instruction_set = parse_instruction_set_attr(tcx, attr) } @@ -358,6 +328,8 @@ fn apply_overrides(tcx: TyCtxt<'_>, did: LocalDefId, codegen_fn_attrs: &mut Code codegen_fn_attrs.alignment = Ord::max(codegen_fn_attrs.alignment, tcx.sess.opts.unstable_opts.min_function_alignment); + // Compute the disabled sanitizers. + codegen_fn_attrs.no_sanitize |= tcx.disabled_sanitizers_for(did); // On trait methods, inherit the `#[align]` of the trait's method prototype. codegen_fn_attrs.alignment = Ord::max(codegen_fn_attrs.alignment, tcx.inherited_align(did)); @@ -455,11 +427,11 @@ fn check_result( if !codegen_fn_attrs.no_sanitize.is_empty() && codegen_fn_attrs.inline.always() && let (Some(no_sanitize_span), Some(inline_span)) = - (interesting_spans.no_sanitize, interesting_spans.inline) + (interesting_spans.sanitize, interesting_spans.inline) { let hir_id = tcx.local_def_id_to_hir_id(did); tcx.node_span_lint(lint::builtin::INLINE_NO_SANITIZE, hir_id, no_sanitize_span, |lint| { - lint.primary_message("`no_sanitize` will have no effect after inlining"); + lint.primary_message("setting `sanitize` off will have no effect after inlining"); lint.span_note(inline_span, "inlining requested here"); }) } @@ -585,6 +557,93 @@ fn opt_trait_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> { } } +/// For an attr that has the `sanitize` attribute, read the list of +/// disabled sanitizers. `current_attr` holds the information about +/// previously parsed attributes. +fn parse_sanitize_attr( + tcx: TyCtxt<'_>, + attr: &Attribute, + current_attr: SanitizerSet, +) -> SanitizerSet { + let mut result = current_attr; + if let Some(list) = attr.meta_item_list() { + for item in list.iter() { + let MetaItemInner::MetaItem(set) = item else { + tcx.dcx().emit_err(errors::InvalidSanitize { span: attr.span() }); + break; + }; + let segments = set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>(); + match segments.as_slice() { + // Similar to clang, sanitize(address = ..) and + // sanitize(kernel_address = ..) control both ASan and KASan + // Source: https://reviews.llvm.org/D44981. + [sym::address] | [sym::kernel_address] if set.value_str() == Some(sym::off) => { + result |= SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS + } + [sym::address] | [sym::kernel_address] if set.value_str() == Some(sym::on) => { + result &= !SanitizerSet::ADDRESS; + result &= !SanitizerSet::KERNELADDRESS; + } + [sym::cfi] if set.value_str() == Some(sym::off) => result |= SanitizerSet::CFI, + [sym::cfi] if set.value_str() == Some(sym::on) => result &= !SanitizerSet::CFI, + [sym::kcfi] if set.value_str() == Some(sym::off) => result |= SanitizerSet::KCFI, + [sym::kcfi] if set.value_str() == Some(sym::on) => result &= !SanitizerSet::KCFI, + [sym::memory] if set.value_str() == Some(sym::off) => { + result |= SanitizerSet::MEMORY + } + [sym::memory] if set.value_str() == Some(sym::on) => { + result &= !SanitizerSet::MEMORY + } + [sym::memtag] if set.value_str() == Some(sym::off) => { + result |= SanitizerSet::MEMTAG + } + [sym::memtag] if set.value_str() == Some(sym::on) => { + result &= !SanitizerSet::MEMTAG + } + [sym::shadow_call_stack] if set.value_str() == Some(sym::off) => { + result |= SanitizerSet::SHADOWCALLSTACK + } + [sym::shadow_call_stack] if set.value_str() == Some(sym::on) => { + result &= !SanitizerSet::SHADOWCALLSTACK + } + [sym::thread] if set.value_str() == Some(sym::off) => { + result |= SanitizerSet::THREAD + } + [sym::thread] if set.value_str() == Some(sym::on) => { + result &= !SanitizerSet::THREAD + } + [sym::hwaddress] if set.value_str() == Some(sym::off) => { + result |= SanitizerSet::HWADDRESS + } + [sym::hwaddress] if set.value_str() == Some(sym::on) => { + result &= !SanitizerSet::HWADDRESS + } + _ => { + tcx.dcx().emit_err(errors::InvalidSanitize { span: attr.span() }); + } + } + } + } + result +} + +fn disabled_sanitizers_for(tcx: TyCtxt<'_>, did: LocalDefId) -> SanitizerSet { + // Backtrack to the crate root. + let disabled = match tcx.opt_local_parent(did) { + // Check the parent (recursively). + Some(parent) => tcx.disabled_sanitizers_for(parent), + // We reached the crate root without seeing an attribute, so + // there is no sanitizers to exclude. + None => SanitizerSet::empty(), + }; + + // Check for a sanitize annotation directly on this def. + if let Some(attr) = tcx.get_attr(did, sym::sanitize) { + return parse_sanitize_attr(tcx, attr, disabled); + } + disabled +} + /// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller /// applied to the method prototype. fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool { @@ -709,6 +768,11 @@ pub fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option<AutoDiffAttrs> { } pub(crate) fn provide(providers: &mut Providers) { - *providers = - Providers { codegen_fn_attrs, should_inherit_track_caller, inherited_align, ..*providers }; + *providers = Providers { + codegen_fn_attrs, + should_inherit_track_caller, + inherited_align, + disabled_sanitizers_for, + ..*providers + }; } diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 7ac830bcda9..209c78ddeda 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -1121,9 +1121,9 @@ impl IntoDiagArg for ExpectedPointerMutability { } #[derive(Diagnostic)] -#[diag(codegen_ssa_invalid_no_sanitize)] +#[diag(codegen_ssa_invalid_sanitize)] #[note] -pub(crate) struct InvalidNoSanitize { +pub(crate) struct InvalidSanitize { #[primary_span] pub span: Span, } diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 6fbedaf5b10..9749028adb0 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -741,9 +741,8 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ErrorPreceding, EncodeCrossCrate::No ), gated!( - no_sanitize, Normal, - template!(List: &["address, kcfi, memory, thread"]), DuplicatesOk, - EncodeCrossCrate::No, experimental!(no_sanitize) + sanitize, Normal, template!(List: &[r#"address = "on|off""#, r#"kernel_address = "on|off""#, r#"cfi = "on|off""#, r#"hwaddress = "on|off""#, r#"kcfi = "on|off""#, r#"memory = "on|off""#, r#"memtag = "on|off""#, r#"shadow_call_stack = "on|off""#, r#"thread = "on|off""#]), ErrorPreceding, + EncodeCrossCrate::No, sanitize, experimental!(sanitize), ), gated!( coverage, Normal, template!(OneOf: &[sym::off, sym::on]), diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 04f261ada06..e37fc6b7bfc 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -190,6 +190,9 @@ declare_features! ( (removed, no_coverage, "1.74.0", Some(84605), Some("renamed to `coverage_attribute`"), 114656), /// Allows `#[no_debug]`. (removed, no_debug, "1.43.0", Some(29721), Some("removed due to lack of demand"), 69667), + // Allows the use of `no_sanitize` attribute. + /// The feature was renamed to `sanitize` and the attribute to `#[sanitize(xyz = "on|off")]` + (removed, no_sanitize, "CURRENT_RUSTC_VERSION", Some(39699), Some(r#"renamed to sanitize(xyz = "on|off")"#), 142681), /// Note: this feature was previously recorded in a separate /// `STABLE_REMOVED` list because it, uniquely, was once stable but was /// then removed. But there was no utility storing it separately, so now diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index f2b9121ffa7..746871982ce 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -594,8 +594,6 @@ declare_features! ( (unstable, new_range, "1.86.0", Some(123741)), /// Allows `#![no_core]`. (unstable, no_core, "1.3.0", Some(29639)), - /// Allows the use of `no_sanitize` attribute. - (unstable, no_sanitize, "1.42.0", Some(39699)), /// Allows using the `non_exhaustive_omitted_patterns` lint. (unstable, non_exhaustive_omitted_patterns_lint, "1.57.0", Some(89554)), /// Allows `for<T>` binders in where-clauses @@ -628,6 +626,8 @@ declare_features! ( (unstable, return_type_notation, "1.70.0", Some(109417)), /// Allows `extern "rust-cold"`. (unstable, rust_cold_cc, "1.63.0", Some(97544)), + /// Allows the use of the `sanitize` attribute. + (unstable, sanitize, "CURRENT_RUSTC_VERSION", Some(39699)), /// Allows the use of SIMD types in functions declared in `extern` blocks. (unstable, simd_ffi, "1.0.0", Some(27731)), /// Allows specialization of implementations (RFC 1210). diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index a0083a7df3d..97aa1065967 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -2301,18 +2301,18 @@ declare_lint! { declare_lint! { /// The `inline_no_sanitize` lint detects incompatible use of - /// [`#[inline(always)]`][inline] and [`#[no_sanitize(...)]`][no_sanitize]. + /// [`#[inline(always)]`][inline] and [`#[sanitize(xyz = "off")]`][sanitize]. /// /// [inline]: https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute - /// [no_sanitize]: https://doc.rust-lang.org/nightly/unstable-book/language-features/no-sanitize.html + /// [sanitize]: https://doc.rust-lang.org/nightly/unstable-book/language-features/no-sanitize.html /// /// ### Example /// /// ```rust - /// #![feature(no_sanitize)] + /// #![feature(sanitize)] /// /// #[inline(always)] - /// #[no_sanitize(address)] + /// #[sanitize(address = "off")] /// fn x() {} /// /// fn main() { @@ -2325,11 +2325,11 @@ declare_lint! { /// ### Explanation /// /// The use of the [`#[inline(always)]`][inline] attribute prevents the - /// the [`#[no_sanitize(...)]`][no_sanitize] attribute from working. + /// the [`#[sanitize(xyz = "off")]`][sanitize] attribute from working. /// Consider temporarily removing `inline` attribute. pub INLINE_NO_SANITIZE, Warn, - "detects incompatible use of `#[inline(always)]` and `#[no_sanitize(...)]`", + r#"detects incompatible use of `#[inline(always)]` and `#[sanitize(... = "off")]`"#, } declare_lint! { diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 7d2fc0995aa..da17ac04c76 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -61,8 +61,8 @@ pub struct CodegenFnAttrs { /// The `#[link_section = "..."]` attribute, or what executable section this /// should be placed in. pub link_section: Option<Symbol>, - /// The `#[no_sanitize(...)]` attribute. Indicates sanitizers for which - /// instrumentation should be disabled inside the annotated function. + /// The `#[sanitize(xyz = "off")]` attribute. Indicates sanitizers for which + /// instrumentation should be disabled inside the function. pub no_sanitize: SanitizerSet, /// The `#[instruction_set(set)]` attribute. Indicates if the generated code should /// be generated against a specific instruction set. Only usable on architectures which allow diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index a8b357bf105..ea62461ebeb 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -343,6 +343,7 @@ trivial! { rustc_span::Symbol, rustc_span::Ident, rustc_target::spec::PanicStrategy, + rustc_target::spec::SanitizerSet, rustc_type_ir::Variance, u32, usize, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index f4d0120a2e7..3bb8353f49e 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -100,7 +100,7 @@ use rustc_session::lint::LintExpectationId; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::source_map::Spanned; use rustc_span::{DUMMY_SP, Span, Symbol}; -use rustc_target::spec::PanicStrategy; +use rustc_target::spec::{PanicStrategy, SanitizerSet}; use {rustc_abi as abi, rustc_ast as ast, rustc_hir as hir}; use crate::infer::canonical::{self, Canonical}; @@ -2686,6 +2686,16 @@ rustc_queries! { desc { |tcx| "looking up anon const kind of `{}`", tcx.def_path_str(def_id) } separate_provide_extern } + + /// Checks for the nearest `#[sanitize(xyz = "off")]` or + /// `#[sanitize(xyz = "on")]` on this def and any enclosing defs, up to the + /// crate root. + /// + /// Returns the set of sanitizers that is explicitly disabled for this def. + query disabled_sanitizers_for(key: LocalDefId) -> SanitizerSet { + desc { |tcx| "checking what set of sanitizers are enabled on `{}`", tcx.def_path_str(key) } + feedable + } } rustc_with_all_queries! { define_callbacks! } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index f7a5ba8194b..03096f205c6 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -454,10 +454,6 @@ passes_no_main_function = .teach_note = If you don't know the basics of Rust, you can go look to the Rust Book to get started: https://doc.rust-lang.org/book/ .non_function_main = non-function item at `crate::main` is found -passes_no_sanitize = - `#[no_sanitize({$attr_str})]` should be applied to {$accepted_kind} - .label = not {$accepted_kind} - passes_non_exhaustive_with_default_field_values = `#[non_exhaustive]` can't be used to annotate items with default field values .label = this struct has default field values @@ -552,6 +548,12 @@ passes_rustc_pub_transparent = attribute should be applied to `#[repr(transparent)]` types .label = not a `#[repr(transparent)]` type +passes_sanitize_attribute_not_allowed = + sanitize attribute not allowed here + .not_fn_impl_mod = not a function, impl block, or module + .no_body = function has no body + .help = sanitize attribute can be applied to a function (with body), impl block, or module + passes_should_be_applied_to_fn = attribute should be applied to a function definition .label = {$on_crate -> diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 3c329d20700..c1a212d7ab5 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -260,8 +260,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::diagnostic, sym::on_unimplemented, ..] => { self.check_diagnostic_on_unimplemented(attr.span(), hir_id, target) } - [sym::no_sanitize, ..] => { - self.check_no_sanitize(attr, span, target) + [sym::sanitize, ..] => { + self.check_sanitize(attr, span, target) } [sym::thread_local, ..] => self.check_thread_local(attr, span, target), [sym::doc, ..] => self.check_doc_attrs( @@ -483,39 +483,43 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_no_sanitize(&self, attr: &Attribute, span: Span, target: Target) { + /// Checks that the `#[sanitize(..)]` attribute is applied to a + /// function/closure/method, or to an impl block or module. + fn check_sanitize(&self, attr: &Attribute, target_span: Span, target: Target) { + let mut not_fn_impl_mod = None; + let mut no_body = None; + if let Some(list) = attr.meta_item_list() { for item in list.iter() { - let sym = item.name(); - match sym { - Some(s @ sym::address | s @ sym::hwaddress) => { - let is_valid = - matches!(target, Target::Fn | Target::Method(..) | Target::Static); - if !is_valid { - self.dcx().emit_err(errors::NoSanitize { - attr_span: item.span(), - defn_span: span, - accepted_kind: "a function or static", - attr_str: s.as_str(), - }); - } + let MetaItemInner::MetaItem(set) = item else { + return; + }; + let segments = set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>(); + match target { + Target::Fn + | Target::Closure + | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) + | Target::Impl { .. } + | Target::Mod => return, + Target::Static if matches!(segments.as_slice(), [sym::address]) => return, + + // These are "functions", but they aren't allowed because they don't + // have a body, so the usual explanation would be confusing. + Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => { + no_body = Some(target_span); } + _ => { - let is_valid = matches!(target, Target::Fn | Target::Method(..)); - if !is_valid { - self.dcx().emit_err(errors::NoSanitize { - attr_span: item.span(), - defn_span: span, - accepted_kind: "a function", - attr_str: &match sym { - Some(name) => name.to_string(), - None => "...".to_string(), - }, - }); - } + not_fn_impl_mod = Some(target_span); } } } + self.dcx().emit_err(errors::SanitizeAttributeNotAllowed { + attr_span: attr.span(), + not_fn_impl_mod, + no_body, + help: (), + }); } } @@ -562,7 +566,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } } - /// Checks if `#[collapse_debuginfo]` is applied to a macro. fn check_collapse_debuginfo(&self, attr: &Attribute, span: Span, target: Target) { match target { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index f8ecf10714a..ab46ac2dd8b 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1489,15 +1489,21 @@ pub(crate) struct AttrCrateLevelOnlySugg { pub attr: Span, } +/// "sanitize attribute not allowed here" #[derive(Diagnostic)] -#[diag(passes_no_sanitize)] -pub(crate) struct NoSanitize<'a> { +#[diag(passes_sanitize_attribute_not_allowed)] +pub(crate) struct SanitizeAttributeNotAllowed { #[primary_span] pub attr_span: Span, - #[label] - pub defn_span: Span, - pub accepted_kind: &'a str, - pub attr_str: &'a str, + /// "not a function, impl block, or module" + #[label(passes_not_fn_impl_mod)] + pub not_fn_impl_mod: Option<Span>, + /// "function has no body" + #[label(passes_no_body)] + pub no_body: Option<Span>, + /// "sanitize attribute can be applied to a function (with body), impl block, or module" + #[help] + pub help: (), } // FIXME(jdonszelmann): move back to rustc_attr diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 3ed483db3c4..65a52b27d3b 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1261,6 +1261,7 @@ symbols! { iterator, iterator_collect_fn, kcfi, + kernel_address, keylocker_x86, keyword, kind, |
