Skip to content

Commit

Permalink
Rollup merge of #91504 - cynecx:used_retain, r=nikic
Browse files Browse the repository at this point in the history
`#[used(linker)]` attribute

See dtolnay/linkme#41 (comment).
  • Loading branch information
matthiaskrgr authored Feb 9, 2022
2 parents 9634559 + 1705933 commit 3f4aaf4
Show file tree
Hide file tree
Showing 16 changed files with 182 additions and 4 deletions.
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));

// 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 @@ -531,6 +531,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 @@ -818,6 +819,7 @@ symbols! {
link_ordinal,
link_section,
linkage,
linker,
lint_reasons,
literal,
load,
Expand Down Expand Up @@ -1466,6 +1468,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 @@ -2856,7 +2857,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();
}
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`.

0 comments on commit 3f4aaf4

Please sign in to comment.