mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-24 12:54:00 +00:00
Rollup merge of #91504 - cynecx:used_retain, r=nikic
`#[used(linker)]` attribute See https://github.com/dtolnay/linkme/issues/41#issuecomment-927255631.
This commit is contained in:
commit
3f4aaf4f2e
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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),
|
||||
// !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
|
||||
|
@ -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),
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -449,6 +449,7 @@ symbols! {
|
||||
compare_exchange_weak,
|
||||
compile_error,
|
||||
compile_error_macro,
|
||||
compiler,
|
||||
compiler_builtins,
|
||||
compiler_fence,
|
||||
concat,
|
||||
@ -818,6 +819,7 @@ symbols! {
|
||||
link_ordinal,
|
||||
link_section,
|
||||
linkage,
|
||||
linker,
|
||||
lint_reasons,
|
||||
literal,
|
||||
load,
|
||||
@ -1466,6 +1468,7 @@ symbols! {
|
||||
use_extern_macros,
|
||||
use_nested_groups,
|
||||
used,
|
||||
used_with_arg,
|
||||
usize,
|
||||
v1,
|
||||
va_arg,
|
||||
|
@ -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
|
||||
@ -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!(
|
||||
|
10
src/test/codegen/used_with_arg.rs
Normal file
10
src/test/codegen/used_with_arg.rs
Normal file
@ -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
src/test/ui/attributes/used_with_arg.rs
Normal file
19
src/test/ui/attributes/used_with_arg.rs
Normal file
@ -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
src/test/ui/attributes/used_with_arg.stderr
Normal file
18
src/test/ui/attributes/used_with_arg.stderr
Normal file
@ -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
src/test/ui/attributes/used_with_multi_args.rs
Normal file
6
src/test/ui/attributes/used_with_multi_args.rs
Normal file
@ -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
src/test/ui/attributes/used_with_multi_args.stderr
Normal file
8
src/test/ui/attributes/used_with_multi_args.stderr
Normal file
@ -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
src/test/ui/feature-gates/feature-gate-used_with_arg.rs
Normal file
7
src/test/ui/feature-gates/feature-gate-used_with_arg.rs
Normal file
@ -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
src/test/ui/feature-gates/feature-gate-used_with_arg.stderr
Normal file
21
src/test/ui/feature-gates/feature-gate-used_with_arg.stderr
Normal file
@ -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`.
|
Loading…
Reference in New Issue
Block a user