diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index 6c1dce969f0f5..47df5cb8302ad 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -323,7 +323,7 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> { self.codegen_unit } - fn used_statics(&self) -> &RefCell>> { + fn used_globals(&self) -> &RefCell>> { unimplemented!(); } @@ -351,7 +351,7 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } } - fn compiler_used_statics(&self) -> &RefCell>> { + fn compiler_used_globals(&self) -> &RefCell>> { unimplemented!() } diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 101da0012cb4b..b72368758690d 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -386,6 +386,19 @@ pub fn from_fn_attrs<'ll, 'tcx>( to_add.push(llvm::CreateAttrStringValue(cx.llcx, "target-features", &target_features)); } + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::USED) { + // `USED` and `USED_LINKER` can't be used together. + assert!(!codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)); + + cx.add_compiler_used_global(llfn); + } + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) { + // `USED` and `USED_LINKER` can't be used together. + assert!(!codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::USED)); + + cx.add_used_global(llfn); + } + attributes::apply_to_llfn(llfn, Function, &to_add); } diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index dd3ada443895f..97911db1911f2 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -115,10 +115,10 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol) -> (ModuleCodegen } // Create the llvm.used and llvm.compiler.used variables. - if !cx.used_statics().borrow().is_empty() { + if !cx.used_globals().borrow().is_empty() { cx.create_used_variable() } - if !cx.compiler_used_statics().borrow().is_empty() { + if !cx.compiler_used_globals().borrow().is_empty() { cx.create_compiler_used_variable() } diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 413ef0ba76464..d4d74ddf0742f 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -543,13 +543,13 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> { /// Add a global value to a list to be stored in the `llvm.used` variable, an array of i8*. fn add_used_global(&self, global: &'ll Value) { let cast = unsafe { llvm::LLVMConstPointerCast(global, self.type_i8p()) }; - self.used_statics.borrow_mut().push(cast); + self.used_globals.borrow_mut().push(cast); } /// Add a global value to a list to be stored in the `llvm.compiler.used` variable, /// an array of i8*. fn add_compiler_used_global(&self, global: &'ll Value) { let cast = unsafe { llvm::LLVMConstPointerCast(global, self.type_i8p()) }; - self.compiler_used_statics.borrow_mut().push(cast); + self.compiler_used_globals.borrow_mut().push(cast); } } diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 9fbc33d4b05d4..c963829c1b43a 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -79,11 +79,11 @@ pub struct CodegenCx<'ll, 'tcx> { /// Statics that will be placed in the llvm.used variable /// See for details - pub used_statics: RefCell>, + pub used_globals: RefCell>, /// Statics that will be placed in the llvm.compiler.used variable /// See for details - pub compiler_used_statics: RefCell>, + pub compiler_used_globals: RefCell>, /// Mapping of non-scalar types to llvm types and field remapping if needed. pub type_lowering: RefCell, Option), TypeLowering<'ll>>>, @@ -423,8 +423,8 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { const_unsized: Default::default(), const_globals: Default::default(), statics_to_rauw: RefCell::new(Vec::new()), - used_statics: RefCell::new(Vec::new()), - compiler_used_statics: RefCell::new(Vec::new()), + used_globals: RefCell::new(Vec::new()), + compiler_used_globals: RefCell::new(Vec::new()), type_lowering: Default::default(), scalar_lltypes: Default::default(), pointee_infos: Default::default(), @@ -546,12 +546,12 @@ impl<'ll, 'tcx> MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> { self.codegen_unit } - fn used_statics(&self) -> &RefCell> { - &self.used_statics + fn used_globals(&self) -> &RefCell> { + &self.used_globals } - fn compiler_used_statics(&self) -> &RefCell> { - &self.compiler_used_statics + fn compiler_used_globals(&self) -> &RefCell> { + &self.compiler_used_globals } fn set_frame_pointer_type(&self, llfn: &'ll Value) { @@ -568,13 +568,13 @@ impl<'ll, 'tcx> MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> { } fn create_used_variable(&self) { - self.create_used_variable_impl(cstr!("llvm.used"), &*self.used_statics.borrow()); + self.create_used_variable_impl(cstr!("llvm.used"), &*self.used_globals.borrow()); } fn create_compiler_used_variable(&self) { self.create_used_variable_impl( cstr!("llvm.compiler.used"), - &*self.compiler_used_statics.borrow(), + &*self.compiler_used_globals.borrow(), ); } diff --git a/compiler/rustc_codegen_ssa/src/traits/misc.rs b/compiler/rustc_codegen_ssa/src/traits/misc.rs index 4266e42ec2b50..d674321af05d4 100644 --- a/compiler/rustc_codegen_ssa/src/traits/misc.rs +++ b/compiler/rustc_codegen_ssa/src/traits/misc.rs @@ -15,8 +15,8 @@ pub trait MiscMethods<'tcx>: BackendTypes { fn eh_personality(&self) -> Self::Value; fn sess(&self) -> &Session; fn codegen_unit(&self) -> &'tcx CodegenUnit<'tcx>; - fn used_statics(&self) -> &RefCell>; - fn compiler_used_statics(&self) -> &RefCell>; + fn used_globals(&self) -> &RefCell>; + fn compiler_used_globals(&self) -> &RefCell>; fn set_frame_pointer_type(&self, llfn: Self::Function); fn apply_target_cpu_attr(&self, llfn: Self::Function); fn create_used_variable(&self); diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index feef7295254a9..ef51aef8a158b 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -542,6 +542,8 @@ declare_features! ( /// /// NOTE: A limited form of `union U { ... }` was accepted in 1.19.0. (active, untagged_unions, "1.13.0", Some(55149), None), + /// Allows using `#[used]` on a function defintion + (active, used_on_fn_def, "1.60.0", Some(00000), None), /// Allows using the `#[used(linker)]` (or `#[used(compiler)]`) attribute. (active, used_with_arg, "1.60.0", Some(93798), None), /// Allows `extern "wasm" fn` diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 54eb2dc9e2890..7eab37cb972d6 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -127,6 +127,8 @@ impl CodegenFnAttrs { /// * `#[linkage]` is present pub fn contains_extern_indicator(&self) -> bool { self.flags.contains(CodegenFnAttrFlags::NO_MANGLE) + || self.flags.contains(CodegenFnAttrFlags::USED) + || self.flags.contains(CodegenFnAttrFlags::USED_LINKER) || self.export_name.is_some() || match self.linkage { // These are private, so make sure we don't try to consider diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 4f9e1d3fa3bca..a4956cf7f52ef 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1742,9 +1742,26 @@ impl CheckAttrVisitor<'_> { let mut used_compiler_span = None; for attr in attrs.iter().filter(|attr| attr.has_name(sym::used)) { if target != Target::Static { - self.tcx - .sess - .span_err(attr.span, "attribute must be applied to a `static` variable"); + if target == Target::Fn { + if !self.tcx.features().used_on_fn_def { + feature_err( + &self.tcx.sess.parse_sess, + sym::used_on_fn_def, + attr.span, + "`#[used]` on a function definition is currently unstable", + ) + .emit(); + } + } else if self.tcx.features().used_on_fn_def { + self.tcx.sess.span_err( + attr.span, + "attribute must be applied to a `static` variable or a function definition", + ); + } else { + self.tcx + .sess + .span_err(attr.span, "attribute must be applied to a `static` variable"); + } } let inner = attr.meta_item_list(); match inner.as_deref() { diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index c777074df4641..8617b61bad28a 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -11,7 +11,6 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::{Node, PatKind, TyKind}; use rustc_middle::hir::nested_filter; -use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::privacy; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, DefIdTree, TyCtxt}; @@ -466,10 +465,7 @@ fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { // #[used], #[no_mangle], #[export_name], etc also keeps the item alive // forcefully, e.g., for placing it in a specific section. - if cg_attrs.contains_extern_indicator() - || cg_attrs.flags.contains(CodegenFnAttrFlags::USED) - || cg_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) - { + if cg_attrs.contains_extern_indicator() { return true; } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 5cf362bfa7e98..4a4da0eedeb9a 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1486,6 +1486,7 @@ symbols! { use_extern_macros, use_nested_groups, used, + used_on_fn_def, used_with_arg, usize, v1, diff --git a/src/test/codegen/used_on_fn_def.rs b/src/test/codegen/used_on_fn_def.rs new file mode 100644 index 0000000000000..3e3cc251b5e17 --- /dev/null +++ b/src/test/codegen/used_on_fn_def.rs @@ -0,0 +1,17 @@ +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(used_with_arg)] +#![feature(used_on_fn_def)] + +// we explicitly don't add #[no_mangle] here as +// that puts the function as in the reachable set + +// CHECK: @llvm.used = appending global [1 x i8*]{{.*}}used_linker +#[used(linker)] +fn used_linker() {} + +// CHECK: @llvm.compiler.used = appending global [1 x i8*]{{.*}}used_compiler +#[used(compiler)] +fn used_compiler() {} + diff --git a/src/test/ui/feature-gates/feature-gate-used-on-fn-def.rs b/src/test/ui/feature-gates/feature-gate-used-on-fn-def.rs new file mode 100644 index 0000000000000..c8e3720ad930f --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-used-on-fn-def.rs @@ -0,0 +1,4 @@ +#[used] //~ ERROR `#[used]` on a function definition is currently unstable +fn foo() {} + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-used-on-fn-def.stderr b/src/test/ui/feature-gates/feature-gate-used-on-fn-def.stderr new file mode 100644 index 0000000000000..f81aeeb587738 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-used-on-fn-def.stderr @@ -0,0 +1,12 @@ +error[E0658]: `#[used]` on a function definition is currently unstable + --> $DIR/feature-gate-used-on-fn-def.rs:1:1 + | +LL | #[used] + | ^^^^^^^ + | + = note: see issue #93798 for more information + = help: add `#![feature(used_on_fn_def)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/used_on_fn_def.rs b/src/test/ui/used_on_fn_def.rs new file mode 100644 index 0000000000000..3a579c481f704 --- /dev/null +++ b/src/test/ui/used_on_fn_def.rs @@ -0,0 +1,18 @@ +#![feature(used_on_fn_def)] + +#[used] +static FOO: u32 = 0; // OK + +#[used] +fn foo() {} // OK + +#[used] //~ ERROR attribute must be applied to a `static` variable or a function definition +struct Foo {} + +#[used] //~ ERROR attribute must be applied to a `static` variable or a function definition +trait Bar {} + +#[used] //~ ERROR attribute must be applied to a `static` variable or a function definition +impl Bar for Foo {} + +fn main() {} diff --git a/src/test/ui/used_on_fn_def.stderr b/src/test/ui/used_on_fn_def.stderr new file mode 100644 index 0000000000000..efd97fdaf68a4 --- /dev/null +++ b/src/test/ui/used_on_fn_def.stderr @@ -0,0 +1,20 @@ +error: attribute must be applied to a `static` variable or a function definition + --> $DIR/used_on_fn_def.rs:9:1 + | +LL | #[used] + | ^^^^^^^ + +error: attribute must be applied to a `static` variable or a function definition + --> $DIR/used_on_fn_def.rs:12:1 + | +LL | #[used] + | ^^^^^^^ + +error: attribute must be applied to a `static` variable or a function definition + --> $DIR/used_on_fn_def.rs:15:1 + | +LL | #[used] + | ^^^^^^^ + +error: aborting due to 3 previous errors +