about summary refs log tree commit diff
path: root/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-10-04 13:37:12 +0000
committerbors <bors@rust-lang.org>2025-10-04 13:37:12 +0000
commit1bd98acf0e54f1ea678c4fabb8e1b10851eb8465 (patch)
treee1e0adfca6dd8050387b45ffb09c0985cf2a32a8 /compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
parent99b9a8850349e56247acb6ce19910c7f96db8439 (diff)
parent1ebbb3c2fd78de38d0730cf9d874295f0d5dc2f1 (diff)
downloadrust-auto.tar.gz
rust-auto.zip
Auto merge of #147330 - matthiaskrgr:rollup-h4jyzmv, r=matthiaskrgr auto
Rollup of 11 pull requests

Successful merges:

 - rust-lang/rust#142670 (Document fully-qualified syntax in `as`' keyword doc)
 - rust-lang/rust#145685 (add CloneFromCell and Cell::get_cloned)
 - rust-lang/rust#146330 (Bump unicode_data and printables to version 17.0.0)
 - rust-lang/rust#146451 (Fix atan2 inaccuracy in documentation)
 - rust-lang/rust#146479 (add mem::conjure_zst)
 - rust-lang/rust#147117 (interpret `#[used]` as `#[used(compiler)]` on illumos)
 - rust-lang/rust#147190 (std: `sys::net` cleanups)
 - rust-lang/rust#147251 (Do not assert that a change in global cache only happens when concurrent)
 - rust-lang/rust#147280 (Return to needs-llvm-components being info-only)
 - rust-lang/rust#147288 (compiletest: Make `DirectiveLine` responsible for name/value splitting)
 - rust-lang/rust#147315 (bless autodiff batching test)

r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs')
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs36
1 files changed, 28 insertions, 8 deletions
diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
index 262b8213977..7978bf28214 100644
--- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
@@ -370,6 +370,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for NoMangleParser {
 pub(crate) struct UsedParser {
     first_compiler: Option<Span>,
     first_linker: Option<Span>,
+    first_default: Option<Span>,
 }
 
 // A custom `AttributeParser` is used rather than a Simple attribute parser because
@@ -382,7 +383,7 @@ impl<S: Stage> AttributeParser<S> for UsedParser {
         template!(Word, List: &["compiler", "linker"]),
         |group: &mut Self, cx, args| {
             let used_by = match args {
-                ArgParser::NoArgs => UsedBy::Linker,
+                ArgParser::NoArgs => UsedBy::Default,
                 ArgParser::List(list) => {
                     let Some(l) = list.single() else {
                         cx.expected_single_argument(list.span);
@@ -423,12 +424,29 @@ impl<S: Stage> AttributeParser<S> for UsedParser {
                 ArgParser::NameValue(_) => return,
             };
 
+            let attr_span = cx.attr_span;
+
+            // `#[used]` is interpreted as `#[used(linker)]` (though depending on target OS the
+            // circumstances are more complicated). While we're checking `used_by`, also report
+            // these cross-`UsedBy` duplicates to warn.
             let target = match used_by {
                 UsedBy::Compiler => &mut group.first_compiler,
-                UsedBy::Linker => &mut group.first_linker,
+                UsedBy::Linker => {
+                    if let Some(prev) = group.first_default {
+                        cx.warn_unused_duplicate(prev, attr_span);
+                        return;
+                    }
+                    &mut group.first_linker
+                }
+                UsedBy::Default => {
+                    if let Some(prev) = group.first_linker {
+                        cx.warn_unused_duplicate(prev, attr_span);
+                        return;
+                    }
+                    &mut group.first_default
+                }
             };
 
-            let attr_span = cx.attr_span;
             if let Some(prev) = *target {
                 cx.warn_unused_duplicate(prev, attr_span);
             } else {
@@ -440,11 +458,13 @@ impl<S: Stage> AttributeParser<S> for UsedParser {
         AllowedTargets::AllowList(&[Allow(Target::Static), Warn(Target::MacroCall)]);
 
     fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
-        // Ratcheting behaviour, if both `linker` and `compiler` are specified, use `linker`
-        Some(match (self.first_compiler, self.first_linker) {
-            (_, Some(span)) => AttributeKind::Used { used_by: UsedBy::Linker, span },
-            (Some(span), _) => AttributeKind::Used { used_by: UsedBy::Compiler, span },
-            (None, None) => return None,
+        // If a specific form of `used` is specified, it takes precedence over generic `#[used]`.
+        // If both `linker` and `compiler` are specified, use `linker`.
+        Some(match (self.first_compiler, self.first_linker, self.first_default) {
+            (_, Some(span), _) => AttributeKind::Used { used_by: UsedBy::Linker, span },
+            (Some(span), _, _) => AttributeKind::Used { used_by: UsedBy::Compiler, span },
+            (_, _, Some(span)) => AttributeKind::Used { used_by: UsedBy::Default, span },
+            (None, None, None) => return None,
         })
     }
 }