From 34be05e0970b1c50e1174c431d6a0303d72df4d2 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Mon, 13 Mar 2023 18:32:25 +0000 Subject: [PATCH] Gracefully handle `#[target_feature]` on statics The was careful around not calling `fn_sig` on not-functions but well, it wasn't careful enough. This commit makes it a little more careful and also adds tests for a bunch more item kinds. --- .../rustc_codegen_ssa/src/codegen_attrs.rs | 45 +++++---- tests/ui/target-feature/invalid-attribute.rs | 35 +++++++ .../target-feature/invalid-attribute.stderr | 95 +++++++++++++++---- 3 files changed, 139 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index c62968e5354..b75ced4a6dd 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -61,25 +61,29 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { let supported_target_features = tcx.supported_target_features(LOCAL_CRATE); - // In some cases, attribute are only valid on functions, but it's the `check_attr` - // pass that check that they aren't used anywhere else, rather this module. - // In these cases, we bail from performing further checks that are only meaningful for - // functions (such as calling `fn_sig`, which ICEs if given a non-function). We also - // report a delayed bug, just in case `check_attr` isn't doing its job. - let validate_fn_only_attr = |attr_sp| -> bool { - let def_kind = tcx.def_kind(did); - if let DefKind::Fn | DefKind::AssocFn | DefKind::Variant | DefKind::Ctor(..) = def_kind { - true - } else { - tcx.sess.delay_span_bug(attr_sp, "this attribute can only be applied to functions"); - false - } - }; - let mut inline_span = None; let mut link_ordinal_span = None; let mut no_sanitize_span = None; + for attr in attrs.iter() { + // In some cases, attribute are only valid on functions, but it's the `check_attr` + // pass that check that they aren't used anywhere else, rather this module. + // In these cases, we bail from performing further checks that are only meaningful for + // functions (such as calling `fn_sig`, which ICEs if given a non-function). We also + // report a delayed bug, just in case `check_attr` isn't doing its job. + let fn_sig = || { + use DefKind::*; + + let def_kind = tcx.def_kind(did); + if let Fn | AssocFn | Variant | Ctor(..) = def_kind { + Some(tcx.fn_sig(did)) + } else { + tcx.sess + .delay_span_bug(attr.span, "this attribute can only be applied to functions"); + None + } + }; + if attr.has_name(sym::cold) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD; } else if attr.has_name(sym::rustc_allocator) { @@ -169,8 +173,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { } } } else if attr.has_name(sym::cmse_nonsecure_entry) { - if validate_fn_only_attr(attr.span) - && !matches!(tcx.fn_sig(did).skip_binder().abi(), abi::Abi::C { .. }) + if let Some(fn_sig) = fn_sig() + && !matches!(fn_sig.skip_binder().abi(), abi::Abi::C { .. }) { struct_span_err!( tcx.sess, @@ -189,8 +193,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL; } else if attr.has_name(sym::track_caller) { if !tcx.is_closure(did.to_def_id()) - && validate_fn_only_attr(attr.span) - && tcx.fn_sig(did).skip_binder().abi() != abi::Abi::Rust + && let Some(fn_sig) = fn_sig() + && fn_sig.skip_binder().abi() != abi::Abi::Rust { struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI") .emit(); @@ -222,7 +226,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { } } else if attr.has_name(sym::target_feature) { if !tcx.is_closure(did.to_def_id()) - && tcx.fn_sig(did).skip_binder().unsafety() == hir::Unsafety::Normal + && let Some(fn_sig) = fn_sig() + && fn_sig.skip_binder().unsafety() == hir::Unsafety::Normal { if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc { // The `#[target_feature]` attribute is allowed on diff --git a/tests/ui/target-feature/invalid-attribute.rs b/tests/ui/target-feature/invalid-attribute.rs index ad1b6e96be6..0c400d7bf97 100644 --- a/tests/ui/target-feature/invalid-attribute.rs +++ b/tests/ui/target-feature/invalid-attribute.rs @@ -14,6 +14,21 @@ #![warn(unused_attributes)] +#[target_feature(enable = "sse2")] +//~^ ERROR attribute should be applied to a function +extern crate alloc; +//~^ NOTE not a function + +#[target_feature(enable = "sse2")] +//~^ ERROR attribute should be applied to a function +use alloc::alloc::alloc; +//~^ NOTE not a function + +#[target_feature(enable = "sse2")] +//~^ ERROR attribute should be applied to a function +extern "Rust" {} +//~^ NOTE not a function + #[target_feature = "+sse2"] //~^ ERROR malformed `target_feature` attribute #[target_feature(enable = "foo")] @@ -59,6 +74,11 @@ union Qux { f2: u16, } +#[target_feature(enable = "sse2")] +//~^ ERROR attribute should be applied to a function +type Uwu = (); +//~^ NOTE not a function + #[target_feature(enable = "sse2")] //~^ ERROR attribute should be applied to a function trait Baz {} @@ -69,6 +89,21 @@ trait Baz {} #[target_feature(enable = "sse2")] unsafe fn test() {} +#[target_feature(enable = "sse2")] +//~^ ERROR attribute should be applied to a function +static A: () = (); +//~^ NOTE not a function + +#[target_feature(enable = "sse2")] +//~^ ERROR attribute should be applied to a function +impl Quux for u8 {} +//~^ NOTE not a function + +#[target_feature(enable = "sse2")] +//~^ ERROR attribute should be applied to a function +impl Foo {} +//~^ NOTE not a function + trait Quux { fn foo(); } diff --git a/tests/ui/target-feature/invalid-attribute.stderr b/tests/ui/target-feature/invalid-attribute.stderr index a2adfc67f08..6d37d0917bc 100644 --- a/tests/ui/target-feature/invalid-attribute.stderr +++ b/tests/ui/target-feature/invalid-attribute.stderr @@ -1,11 +1,38 @@ error: malformed `target_feature` attribute input - --> $DIR/invalid-attribute.rs:17:1 + --> $DIR/invalid-attribute.rs:32:1 | LL | #[target_feature = "+sse2"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[target_feature(enable = "name")]` error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:34:1 + --> $DIR/invalid-attribute.rs:17:1 + | +LL | #[target_feature(enable = "sse2")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | extern crate alloc; + | ------------------- not a function definition + +error: attribute should be applied to a function definition + --> $DIR/invalid-attribute.rs:22:1 + | +LL | #[target_feature(enable = "sse2")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | use alloc::alloc::alloc; + | ------------------------ not a function definition + +error: attribute should be applied to a function definition + --> $DIR/invalid-attribute.rs:27:1 + | +LL | #[target_feature(enable = "sse2")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | extern "Rust" {} + | ---------------- not a function definition + +error: attribute should be applied to a function definition + --> $DIR/invalid-attribute.rs:49:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -14,7 +41,7 @@ LL | mod another {} | -------------- not a function definition error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:39:1 + --> $DIR/invalid-attribute.rs:54:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -23,7 +50,7 @@ LL | const FOO: usize = 7; | --------------------- not a function definition error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:44:1 + --> $DIR/invalid-attribute.rs:59:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -32,7 +59,7 @@ LL | struct Foo; | ----------- not a function definition error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:49:1 + --> $DIR/invalid-attribute.rs:64:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -41,7 +68,7 @@ LL | enum Bar {} | ----------- not a function definition error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:54:1 + --> $DIR/invalid-attribute.rs:69:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -54,7 +81,16 @@ LL | | } | |_- not a function definition error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:62:1 + --> $DIR/invalid-attribute.rs:77:1 + | +LL | #[target_feature(enable = "sse2")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | type Uwu = (); + | -------------- not a function definition + +error: attribute should be applied to a function definition + --> $DIR/invalid-attribute.rs:82:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -63,7 +99,34 @@ LL | trait Baz {} | ------------ not a function definition error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:85:5 + --> $DIR/invalid-attribute.rs:92:1 + | +LL | #[target_feature(enable = "sse2")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | static A: () = (); + | ------------------ not a function definition + +error: attribute should be applied to a function definition + --> $DIR/invalid-attribute.rs:97:1 + | +LL | #[target_feature(enable = "sse2")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | impl Quux for u8 {} + | ------------------- not a function definition + +error: attribute should be applied to a function definition + --> $DIR/invalid-attribute.rs:102:1 + | +LL | #[target_feature(enable = "sse2")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | impl Foo {} + | ----------- not a function definition + +error: attribute should be applied to a function definition + --> $DIR/invalid-attribute.rs:120:5 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -75,7 +138,7 @@ LL | | } | |_____- not a function definition error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:93:5 + --> $DIR/invalid-attribute.rs:128:5 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -84,25 +147,25 @@ LL | || {}; | ----- not a function definition error: the feature named `foo` is not valid for this target - --> $DIR/invalid-attribute.rs:19:18 + --> $DIR/invalid-attribute.rs:34:18 | LL | #[target_feature(enable = "foo")] | ^^^^^^^^^^^^^^ `foo` is not valid for this target error: malformed `target_feature` attribute input - --> $DIR/invalid-attribute.rs:22:18 + --> $DIR/invalid-attribute.rs:37:18 | LL | #[target_feature(bar)] | ^^^ help: must be of the form: `enable = ".."` error: malformed `target_feature` attribute input - --> $DIR/invalid-attribute.rs:24:18 + --> $DIR/invalid-attribute.rs:39:18 | LL | #[target_feature(disable = "baz")] | ^^^^^^^^^^^^^^^ help: must be of the form: `enable = ".."` error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions - --> $DIR/invalid-attribute.rs:28:1 + --> $DIR/invalid-attribute.rs:43:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -114,13 +177,13 @@ LL | fn bar() {} = help: add `#![feature(target_feature_11)]` to the crate attributes to enable error: cannot use `#[inline(always)]` with `#[target_feature]` - --> $DIR/invalid-attribute.rs:67:1 + --> $DIR/invalid-attribute.rs:87:1 | LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions - --> $DIR/invalid-attribute.rs:77:5 + --> $DIR/invalid-attribute.rs:112:5 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -131,6 +194,6 @@ LL | fn foo() {} = note: see issue #69098 for more information = help: add `#![feature(target_feature_11)]` to the crate attributes to enable -error: aborting due to 15 previous errors +error: aborting due to 22 previous errors For more information about this error, try `rustc --explain E0658`.