Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement used_on_fn_def #95329

Closed
wants to merge 1 commit into from
Closed
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
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_gcc/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
self.codegen_unit
}

fn used_statics(&self) -> &RefCell<Vec<RValue<'gcc>>> {
fn used_globals(&self) -> &RefCell<Vec<RValue<'gcc>>> {
unimplemented!();
}

Expand Down Expand Up @@ -351,7 +351,7 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
}
}

fn compiler_used_statics(&self) -> &RefCell<Vec<RValue<'gcc>>> {
fn compiler_used_globals(&self) -> &RefCell<Vec<RValue<'gcc>>> {
unimplemented!()
}

Expand Down
13 changes: 13 additions & 0 deletions compiler/rustc_codegen_llvm/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_llvm/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}

Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_llvm/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
20 changes: 10 additions & 10 deletions compiler/rustc_codegen_llvm/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,11 @@ pub struct CodegenCx<'ll, 'tcx> {

/// Statics that will be placed in the llvm.used variable
/// See <https://llvm.org/docs/LangRef.html#the-llvm-used-global-variable> for details
pub used_statics: RefCell<Vec<&'ll Value>>,
pub used_globals: RefCell<Vec<&'ll Value>>,

/// Statics that will be placed in the llvm.compiler.used variable
/// See <https://llvm.org/docs/LangRef.html#the-llvm-compiler-used-global-variable> for details
pub compiler_used_statics: RefCell<Vec<&'ll Value>>,
pub compiler_used_globals: RefCell<Vec<&'ll Value>>,

/// Mapping of non-scalar types to llvm types and field remapping if needed.
pub type_lowering: RefCell<FxHashMap<(Ty<'tcx>, Option<VariantIdx>), TypeLowering<'ll>>>,
Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -546,12 +546,12 @@ impl<'ll, 'tcx> MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
self.codegen_unit
}

fn used_statics(&self) -> &RefCell<Vec<&'ll Value>> {
&self.used_statics
fn used_globals(&self) -> &RefCell<Vec<&'ll Value>> {
&self.used_globals
}

fn compiler_used_statics(&self) -> &RefCell<Vec<&'ll Value>> {
&self.compiler_used_statics
fn compiler_used_globals(&self) -> &RefCell<Vec<&'ll Value>> {
&self.compiler_used_globals
}

fn set_frame_pointer_type(&self, llfn: &'ll Value) {
Expand All @@ -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(),
);
}

Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_ssa/src/traits/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Vec<Self::Value>>;
fn compiler_used_statics(&self) -> &RefCell<Vec<Self::Value>>;
fn used_globals(&self) -> &RefCell<Vec<Self::Value>>;
fn compiler_used_globals(&self) -> &RefCell<Vec<Self::Value>>;
fn set_frame_pointer_type(&self, llfn: Self::Function);
fn apply_target_cpu_attr(&self, llfn: Self::Function);
fn create_used_variable(&self);
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/active.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
23 changes: 20 additions & 3 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
6 changes: 1 addition & 5 deletions compiler/rustc_passes/src/dead.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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;
}

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1486,6 +1486,7 @@ symbols! {
use_extern_macros,
use_nested_groups,
used,
used_on_fn_def,
used_with_arg,
usize,
v1,
Expand Down
17 changes: 17 additions & 0 deletions src/test/codegen/used_on_fn_def.rs
Original file line number Diff line number Diff line change
@@ -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() {}

4 changes: 4 additions & 0 deletions src/test/ui/feature-gates/feature-gate-used-on-fn-def.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#[used] //~ ERROR `#[used]` on a function definition is currently unstable
fn foo() {}

fn main() {}
12 changes: 12 additions & 0 deletions src/test/ui/feature-gates/feature-gate-used-on-fn-def.stderr
Original file line number Diff line number Diff line change
@@ -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 <https://github.com/rust-lang/rust/issues/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`.
18 changes: 18 additions & 0 deletions src/test/ui/used_on_fn_def.rs
Original file line number Diff line number Diff line change
@@ -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() {}
20 changes: 20 additions & 0 deletions src/test/ui/used_on_fn_def.stderr
Original file line number Diff line number Diff line change
@@ -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