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

#[used(linker)] attribute #91504

Merged
merged 5 commits into from
Feb 10, 2022
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
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_gcc/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> {
// TODO(antoyo): set link section.
}

if attrs.flags.contains(CodegenFnAttrFlags::USED) {
if attrs.flags.contains(CodegenFnAttrFlags::USED) || attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) {
self.add_used_global(global.to_rvalue());
}
}
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_codegen_llvm/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,9 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> {
}

if attrs.flags.contains(CodegenFnAttrFlags::USED) {
// `USED` and `USED_LINKER` can't be used together.
assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER));
cynecx marked this conversation as resolved.
Show resolved Hide resolved

// The semantics of #[used] in Rust only require the symbol to make it into the
// object file. It is explicitly allowed for the linker to strip the symbol if it
// is dead. As such, use llvm.compiler.used instead of llvm.used.
Expand All @@ -530,6 +533,12 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> {
// in some versions of the gold linker.
self.add_compiler_used_global(g);
}
if attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) {
// `USED` and `USED_LINKER` can't be used together.
assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED));

self.add_used_global(g);
}
}
}

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 @@ -533,6 +533,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 the `#[used(linker)]` (or `#[used(compiler)]`) attribute.
(active, used_with_arg, "1.60.0", Some(93798), None),
/// Allows `extern "wasm" fn`
(active, wasm_abi, "1.53.0", Some(83788), None),
// !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
ungated!(export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
ungated!(link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
ungated!(no_mangle, Normal, template!(Word), WarnFollowing),
ungated!(used, Normal, template!(Word), WarnFollowing),
ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing),

// Limits:
ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing),
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 @@ -89,6 +89,8 @@ bitflags! {
/// the MIR `InstrumentCoverage` pass and not added to the coverage map
/// during codegen.
const NO_COVERAGE = 1 << 15;
/// `#[used(linker)]`: indicates that LLVM nor the linker can eliminate this function.
const USED_LINKER = 1 << 16;
}
}

Expand Down
34 changes: 34 additions & 0 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1741,12 +1741,46 @@ impl CheckAttrVisitor<'_> {
}

fn check_used(&self, attrs: &[Attribute], target: Target) {
let mut used_linker_span = None;
let mut used_compiler_span = None;
for attr in attrs {
if attr.has_name(sym::used) && target != Target::Static {
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() {
Some([item]) if item.has_name(sym::linker) => {
if used_linker_span.is_none() {
used_linker_span = Some(attr.span);
}
}
Some([item]) if item.has_name(sym::compiler) => {
if used_compiler_span.is_none() {
used_compiler_span = Some(attr.span);
}
}
Some(_) => {
// This error case is handled in rustc_typeck::collect.
}
None => {
// Default case (compiler) when arg isn't defined.
if used_compiler_span.is_none() {
used_compiler_span = Some(attr.span);
}
}
}
}
if let (Some(linker_span), Some(compiler_span)) = (used_linker_span, used_compiler_span) {
let spans = vec![linker_span, compiler_span];
self.tcx
.sess
.struct_span_err(
spans,
"`used(compiler)` and `used(linker)` can't be used together",
)
.emit();
}
}

Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_passes/src/dead.rs
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,10 @@ 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) {
if cg_attrs.contains_extern_indicator()
|| cg_attrs.flags.contains(CodegenFnAttrFlags::USED)
|| cg_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
{
return true;
}

Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,7 @@ symbols! {
compare_exchange_weak,
compile_error,
compile_error_macro,
compiler,
compiler_builtins,
compiler_fence,
concat,
Expand Down Expand Up @@ -815,6 +816,7 @@ symbols! {
link_ordinal,
link_section,
linkage,
linker,
lint_reasons,
literal,
load,
Expand Down Expand Up @@ -1458,6 +1460,7 @@ symbols! {
use_extern_macros,
use_nested_groups,
used,
used_with_arg,
usize,
v1,
va_arg,
Expand Down
38 changes: 37 additions & 1 deletion compiler/rustc_typeck/src/collect.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// ignore-tidy-filelength
//! "Collection" is the process of determining the type and other external
//! details of each item in Rust. Collection is specifically concerned
//! with *inter-procedural* things -- for example, for a function
Expand Down Expand Up @@ -2849,7 +2850,42 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
} else if attr.has_name(sym::rustc_std_internal_symbol) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
} else if attr.has_name(sym::used) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED;
let inner = attr.meta_item_list();
match inner.as_deref() {
Some([item]) if item.has_name(sym::linker) => {
if !tcx.features().used_with_arg {
feature_err(
&tcx.sess.parse_sess,
sym::used_with_arg,
attr.span,
"`#[used(linker)]` is currently unstable",
)
.emit();
}
codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER;
}
Some([item]) if item.has_name(sym::compiler) => {
if !tcx.features().used_with_arg {
feature_err(
&tcx.sess.parse_sess,
sym::used_with_arg,
attr.span,
"`#[used(compiler)]` is currently unstable",
)
.emit();
}
codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED;
}
Some(_) => {
tcx.sess
.struct_span_err(
attr.span,
"expected `used`, `used(compiler)` or `used(linker)`",
)
.emit();
cynecx marked this conversation as resolved.
Show resolved Hide resolved
}
None => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED,
}
} else if attr.has_name(sym::cmse_nonsecure_entry) {
if !matches!(tcx.fn_sig(id).abi(), abi::Abi::C { .. }) {
struct_span_err!(
Expand Down
10 changes: 10 additions & 0 deletions src/test/codegen/used_with_arg.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#![crate_type = "lib"]
#![feature(used_with_arg)]

// CHECK: @llvm.used = appending global [1 x i8*]{{.*}}USED_LINKER
#[used(linker)]
static mut USED_LINKER: [usize; 1] = [0];

// CHECK-NEXT: @llvm.compiler.used = appending global [1 x i8*]{{.*}}USED_COMPILER
#[used(compiler)]
static mut USED_COMPILER: [usize; 1] = [0];
19 changes: 19 additions & 0 deletions src/test/ui/attributes/used_with_arg.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#![feature(used_with_arg)]

#[used(linker)]
static mut USED_LINKER: [usize; 1] = [0];

#[used(compiler)]
static mut USED_COMPILER: [usize; 1] = [0];

#[used(compiler)] //~ ERROR `used(compiler)` and `used(linker)` can't be used together
#[used(linker)]
static mut USED_COMPILER_LINKER2: [usize; 1] = [0];

#[used(compiler)] //~ ERROR `used(compiler)` and `used(linker)` can't be used together
#[used(linker)]
#[used(compiler)]
#[used(linker)]
static mut USED_COMPILER_LINKER3: [usize; 1] = [0];

fn main() {}
18 changes: 18 additions & 0 deletions src/test/ui/attributes/used_with_arg.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
error: `used(compiler)` and `used(linker)` can't be used together
--> $DIR/used_with_arg.rs:9:1
|
LL | #[used(compiler)]
| ^^^^^^^^^^^^^^^^^
LL | #[used(linker)]
| ^^^^^^^^^^^^^^^

error: `used(compiler)` and `used(linker)` can't be used together
--> $DIR/used_with_arg.rs:13:1
|
LL | #[used(compiler)]
| ^^^^^^^^^^^^^^^^^
LL | #[used(linker)]
| ^^^^^^^^^^^^^^^

error: aborting due to 2 previous errors

6 changes: 6 additions & 0 deletions src/test/ui/attributes/used_with_multi_args.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#![feature(used_with_arg)]

#[used(compiler, linker)] //~ expected `used`, `used(compiler)` or `used(linker)`
static mut USED_COMPILER_LINKER: [usize; 1] = [0];

fn main() {}
8 changes: 8 additions & 0 deletions src/test/ui/attributes/used_with_multi_args.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
error: expected `used`, `used(compiler)` or `used(linker)`
--> $DIR/used_with_multi_args.rs:3:1
|
LL | #[used(compiler, linker)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

7 changes: 7 additions & 0 deletions src/test/ui/feature-gates/feature-gate-used_with_arg.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#[used(linker)] //~ ERROR `#[used(linker)]` is currently unstable
static mut USED_LINKER: [usize; 1] = [0];

#[used(compiler)] //~ ERROR `#[used(compiler)]` is currently unstable
static mut USED_COMPILER: [usize; 1] = [0];

fn main() {}
21 changes: 21 additions & 0 deletions src/test/ui/feature-gates/feature-gate-used_with_arg.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
error[E0658]: `#[used(linker)]` is currently unstable
--> $DIR/feature-gate-used_with_arg.rs:1:1
|
LL | #[used(linker)]
| ^^^^^^^^^^^^^^^
|
= note: see issue #93798 <https://github.com/rust-lang/rust/issues/93798> for more information
= help: add `#![feature(used_with_arg)]` to the crate attributes to enable

error[E0658]: `#[used(compiler)]` is currently unstable
--> $DIR/feature-gate-used_with_arg.rs:4:1
|
LL | #[used(compiler)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #93798 <https://github.com/rust-lang/rust/issues/93798> for more information
= help: add `#![feature(used_with_arg)]` to the crate attributes to enable

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0658`.