Skip to content

Commit ecb1666

Browse files
committed
interpret #[used] as #[used(compiler)] on illumos
illumos' `ld` does not support a flag like either SHF_GNU_RETAIN or SHF_SUNW_NODISCARD, so there is no way to communicate `#[used(linker)]` for that target. Setting `USED_LINKER` to try results in LLVM setting SHF_SUNW_NODISCARD for Solaris-like targets, which is an unknown section header flag for illumos `ld` and prevents sections from being merged that otherwise would. As a motivating example, the `inventory` crate produces `#[used]` items to merge into `.init_array`. Because those items have an unknown section header flag they are not merged with the default `.init_array` with `frame_dummy`, and end up never executed. Downgrading `#[used]` to `#[used(compiler)]` on illumos keeps so-attributed items as preserved as they had been before #140872. As was the case before that change, because rustc passes `-z ignore` to illumos `ld`, it's possible that `used` sections are GC'd at link time. #146169 describes this unfortunate circumstance.
1 parent e131842 commit ecb1666

File tree

3 files changed

+25
-7
lines changed

3 files changed

+25
-7
lines changed

compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for NoMangleParser {
370370
pub(crate) struct UsedParser {
371371
first_compiler: Option<Span>,
372372
first_linker: Option<Span>,
373+
first_generic: Option<Span>,
373374
}
374375

375376
// A custom `AttributeParser` is used rather than a Simple attribute parser because
@@ -382,7 +383,7 @@ impl<S: Stage> AttributeParser<S> for UsedParser {
382383
template!(Word, List: &["compiler", "linker"]),
383384
|group: &mut Self, cx, args| {
384385
let used_by = match args {
385-
ArgParser::NoArgs => UsedBy::Linker,
386+
ArgParser::NoArgs => UsedBy::Any,
386387
ArgParser::List(list) => {
387388
let Some(l) = list.single() else {
388389
cx.expected_single_argument(list.span);
@@ -426,6 +427,7 @@ impl<S: Stage> AttributeParser<S> for UsedParser {
426427
let target = match used_by {
427428
UsedBy::Compiler => &mut group.first_compiler,
428429
UsedBy::Linker => &mut group.first_linker,
430+
UsedBy::Any => &mut group.first_generic,
429431
};
430432

431433
let attr_span = cx.attr_span;
@@ -440,11 +442,13 @@ impl<S: Stage> AttributeParser<S> for UsedParser {
440442
AllowedTargets::AllowList(&[Allow(Target::Static), Warn(Target::MacroCall)]);
441443

442444
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
443-
// Ratcheting behaviour, if both `linker` and `compiler` are specified, use `linker`
444-
Some(match (self.first_compiler, self.first_linker) {
445-
(_, Some(span)) => AttributeKind::Used { used_by: UsedBy::Linker, span },
446-
(Some(span), _) => AttributeKind::Used { used_by: UsedBy::Compiler, span },
447-
(None, None) => return None,
445+
// If a specific form of `used` is specified, it takes precedence over generic `#[used]`.
446+
// If both `linker` and `compiler` are specified, use `linker`.
447+
Some(match (self.first_compiler, self.first_linker, self.first_generic) {
448+
(_, Some(span), _) => AttributeKind::Used { used_by: UsedBy::Linker, span },
449+
(Some(span), _, _) => AttributeKind::Used { used_by: UsedBy::Compiler, span },
450+
(_, _, Some(span)) => AttributeKind::Used { used_by: UsedBy::Any, span },
451+
(None, None, None) => return None,
448452
})
449453
}
450454
}

compiler/rustc_codegen_ssa/src/codegen_attrs.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,19 @@ fn process_builtin_attrs(
263263
AttributeKind::Used { used_by, .. } => match used_by {
264264
UsedBy::Compiler => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_COMPILER,
265265
UsedBy::Linker => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER,
266+
UsedBy::Any => {
267+
let used_form = if tcx.sess.target.os == "illumos" {
268+
// illumos' `ld` doesn't support a section header that would represent
269+
// `#[used(linker)]`, see
270+
// https://github.com/rust-lang/rust/issues/146169. For that target,
271+
// downgrade as if `#[used(compiler)]` was requested and hope for the
272+
// best.
273+
CodegenFnAttrFlags::USED_COMPILER
274+
} else {
275+
CodegenFnAttrFlags::USED_LINKER
276+
};
277+
codegen_fn_attrs.flags |= used_form;
278+
}
266279
},
267280
AttributeKind::FfiConst(_) => {
268281
codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST

compiler/rustc_hir/src/attrs/data_structures.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,12 +146,13 @@ impl Deprecation {
146146
}
147147

148148
/// There are three valid forms of the attribute:
149-
/// `#[used]`, which is semantically equivalent to `#[used(linker)]` except that the latter is currently unstable.
149+
/// `#[used]`, which is equivalent to `#[used(linker)]` on targets that support it, but `#[used(compiler)]` if not.
150150
/// `#[used(compiler)]`
151151
/// `#[used(linker)]`
152152
#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
153153
#[derive(HashStable_Generic, PrintAttribute)]
154154
pub enum UsedBy {
155+
Any,
155156
Compiler,
156157
Linker,
157158
}

0 commit comments

Comments
 (0)