Skip to content
Merged
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
27 changes: 25 additions & 2 deletions compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::attributes::AttributeSafety;
use crate::session_diagnostics::{
EmptyExportName, NakedFunctionIncompatibleAttribute, NullOnExport, NullOnObjcClass,
NullOnObjcSelector, ObjcClassExpectedStringLiteral, ObjcSelectorExpectedStringLiteral,
SanitizeInvalidStatic,
};
use crate::target_checking::Policy::AllowSilent;

Expand Down Expand Up @@ -566,8 +567,18 @@ pub(crate) struct SanitizeParser;

impl SingleAttributeParser for SanitizeParser {
const PATH: &[Symbol] = &[sym::sanitize];
// FIXME: still checked in check_attrs.rs
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Closure),
Allow(Target::Method(MethodKind::Inherent)),
Allow(Target::Method(MethodKind::Trait { body: true })),
Allow(Target::Method(MethodKind::TraitImpl)),
Allow(Target::Impl { of_trait: false }),
Allow(Target::Impl { of_trait: true }),
Allow(Target::Mod),
Allow(Target::Crate),
Allow(Target::Static),
Copy link
Copy Markdown
Contributor Author

@JonathanBrouwer JonathanBrouwer Jun 2, 2026

Choose a reason for hiding this comment

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

Note that attribute parsing has slightly better/different target information than check_attr.rs does

  • We allow Target::Crate here, which falls under Target::Mod in check_attr.rs
  • We allow Target::Method(MethodKind::TraitImpl) here, which falls under Target::Impl { of_trait: true } in check_attr.rs

View changes since the review

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Okay, I raised some concerns on the tracking issue. #39699 (comment)

This pr won't change the behavior and sanitize is still unstable so I don't mind proceeding.

]);
const TEMPLATE: AttributeTemplate = template!(List: &[
r#"address = "on|off""#,
r#"kernel_address = "on|off""#,
Expand Down Expand Up @@ -668,6 +679,18 @@ impl SingleAttributeParser for SanitizeParser {
}
}

// The sanitizer attribute is only allowed on statics, if only address bits are set
let all_set_except_address =
(on_set | off_set) & !(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS);
if cx.target == Target::Static
&& let Some(set) = all_set_except_address.iter().next()
{
cx.emit_err(SanitizeInvalidStatic {
span: cx.attr_span,
field: set.as_str().expect("Since this `SanitizerSet` is returned from an iterator, exactly one field is set")
});
}

Some(AttributeKind::Sanitize { on_set, off_set, rtsan, span: cx.attr_span })
}
}
Expand Down
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 @@ -1023,3 +1023,12 @@ pub(crate) enum InvalidMachoSectionReason {
#[note("section name `{$section}` is longer than 16 bytes")]
SectionTooLong { section: String },
}

#[derive(Diagnostic)]
#[diag("`#[sanitize({$field} = ...)]` attribute cannot be used on statics")]
#[help("`#[sanitize]` can be used on statics if only the address is sanitized")]
pub(crate) struct SanitizeInvalidStatic {
#[primary_span]
pub span: Span,
pub field: &'static str,
}
Comment on lines +1027 to +1034
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You can have multiple fields in this attribute, how does this error display in that case?

Copy link
Copy Markdown
Contributor Author

@JonathanBrouwer JonathanBrouwer Jun 3, 2026

Choose a reason for hiding this comment

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

It currently only complains about the first one it finds, I was considering generating a diagnostic for every one but that feels like it would get spammy very quickly

14 changes: 14 additions & 0 deletions compiler/rustc_attr_parsing/src/target_checking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,13 @@ pub(crate) fn allowed_targets_applied(
Target::Method(MethodKind::Trait { body: true }),
Target::Method(MethodKind::TraitImpl),
];
const FUNCTION_WITH_BODY_LIKE: &[Target] = &[
Target::Fn,
Target::Closure,
Target::Method(MethodKind::Inherent),
Target::Method(MethodKind::Trait { body: true }),
Target::Method(MethodKind::TraitImpl),
];
const METHOD_LIKE: &[Target] = &[
Target::Method(MethodKind::Inherent),
Target::Method(MethodKind::Trait { body: false }),
Expand All @@ -379,6 +386,13 @@ pub(crate) fn allowed_targets_applied(
target,
&mut added_fake_targets,
);
filter_targets(
&mut allowed_targets,
FUNCTION_WITH_BODY_LIKE,
"functions with a body",
target,
&mut added_fake_targets,
);
filter_targets(&mut allowed_targets, METHOD_LIKE, "methods", target, &mut added_fake_targets);
filter_targets(&mut allowed_targets, IMPL_LIKE, "impl blocks", target, &mut added_fake_targets);
filter_targets(&mut allowed_targets, ADT_LIKE, "data types", target, &mut added_fake_targets);
Expand Down
52 changes: 2 additions & 50 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use rustc_feature::BUILTIN_ATTRIBUTE_MAP;
use rustc_hir::attrs::diagnostic::Directive;
use rustc_hir::attrs::{
AttributeKind, DocAttribute, DocInline, EiiDecl, EiiImpl, EiiImplResolution, InlineAttr,
ReprAttr, SanitizerSet,
ReprAttr,
};
use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalModDefId;
Expand Down Expand Up @@ -227,9 +227,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
}
&AttributeKind::FfiPure(attr_span) => self.check_ffi_pure(attr_span, attrs),
AttributeKind::MayDangle(attr_span) => self.check_may_dangle(hir_id, *attr_span),
&AttributeKind::Sanitize { on_set, off_set, rtsan: _, span: attr_span } => {
self.check_sanitize(attr_span, on_set | off_set, span, target);
}
AttributeKind::Link(_, attr_span) => self.check_link(hir_id, *attr_span, target),
AttributeKind::MacroExport { span, .. } => {
self.check_macro_export(hir_id, *span, target)
Expand Down Expand Up @@ -401,6 +398,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
AttributeKind::RustcThenThisWouldNeed(..) => (),
AttributeKind::RustcTrivialFieldReads => (),
AttributeKind::RustcUnsafeSpecializationMarker => (),
AttributeKind::Sanitize { .. } => {}
AttributeKind::ShouldPanic { .. } => (),
AttributeKind::Stability { .. } => (),
AttributeKind::TestRunner(..) => (),
Expand Down Expand Up @@ -627,52 +625,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
}
}

/// Checks that the `#[sanitize(..)]` attribute is applied to a
/// function/closure/method, or to an impl block or module.
fn check_sanitize(
&self,
attr_span: Span,
set: SanitizerSet,
target_span: Span,
target: Target,
) {
let mut not_fn_impl_mod = None;
let mut no_body = None;

match target {
Target::Fn
| Target::Closure
| Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent)
| Target::Impl { .. }
| Target::Mod => return,
Target::Static
// if we mask out the address bits, i.e. *only* address was set,
// we allow it
if set & !(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS)
== SanitizerSet::empty() =>
{
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);
}

_ => {
not_fn_impl_mod = Some(target_span);
}
}

self.dcx().emit_err(errors::SanitizeAttributeNotAllowed {
attr_span,
not_fn_impl_mod,
no_body,
help: (),
});
}

/// Checks if `#[naked]` is applied to a function definition.
fn check_naked(&self, hir_id: HirId, target: Target) {
match target {
Expand Down
13 changes: 0 additions & 13 deletions compiler/rustc_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1049,19 +1049,6 @@ pub(crate) struct UnnecessaryPartialStableFeature {
#[note("see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information")]
pub(crate) struct IneffectiveUnstableImpl;

#[derive(Diagnostic)]
#[diag("sanitize attribute not allowed here")]
pub(crate) struct SanitizeAttributeNotAllowed {
#[primary_span]
pub attr_span: Span,
#[label("not a function, impl block, or module")]
pub not_fn_impl_mod: Option<Span>,
#[label("function has no body")]
pub no_body: Option<Span>,
#[help("sanitize attribute can be applied to a function (with body), impl block, or module")]
pub help: (),
}

// FIXME(jdonszelmann): move back to rustc_attr
#[derive(Diagnostic)]
#[diag(
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/asm/naked-invalid-attr.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ error: `#[naked]` attribute cannot be used on foreign functions
LL | #[unsafe(naked)]
| ^^^^^^^^^^^^^^^^
|
= help: `#[naked]` can be applied to functions and methods
= help: `#[naked]` can only be applied to functions with a body

error: `#[naked]` attribute cannot be used on structs
--> $DIR/naked-invalid-attr.rs:14:1
Expand All @@ -42,7 +42,7 @@ error: `#[naked]` attribute cannot be used on required trait methods
LL | #[unsafe(naked)]
| ^^^^^^^^^^^^^^^^
|
= help: `#[naked]` can be applied to functions, inherent methods, provided trait methods, and trait methods in impl blocks
= help: `#[naked]` can only be applied to functions with a body

error: `#[naked]` attribute cannot be used on closures
--> $DIR/naked-invalid-attr.rs:52:5
Expand Down
5 changes: 4 additions & 1 deletion tests/ui/attributes/attr-on-mac-call.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//@ check-pass
//@ check-fail
// Regression test for https://github.com/rust-lang/rust/issues/145779
#![warn(unused_attributes)]
#![feature(sanitize)]

fn main() {
#[export_name = "x"]
Expand Down Expand Up @@ -72,6 +73,8 @@ fn main() {
#[link_name = "x"]
//~^ WARN attribute cannot be used on macro calls
//~| WARN previously accepted
#[sanitize(address = "off")]
//~^ ERROR attribute cannot be used on macro calls
unreachable!();

#[repr()]
Expand Down
Loading
Loading