about summary refs log tree commit diff
path: root/compiler/rustc_attr_parsing/src
diff options
context:
space:
mode:
authorJonathan Brouwer <jonathantbrouwer@gmail.com>2025-06-25 09:36:26 +0200
committerJonathan Brouwer <jonathantbrouwer@gmail.com>2025-06-27 08:58:26 +0200
commit9e3568407234ba4b8fa772cb4acf8d18b12baa7c (patch)
tree9640b7781f40da7d4392dbca5a9d9cc370a300c0 /compiler/rustc_attr_parsing/src
parente61dd437f33b5a640e67dc3628397689c664c17f (diff)
downloadrust-9e3568407234ba4b8fa772cb4acf8d18b12baa7c.tar.gz
rust-9e3568407234ba4b8fa772cb4acf8d18b12baa7c.zip
Port `#[used]` to new attribute parsing infrastructure
Signed-off-by: Jonathan Brouwer <jonathantbrouwer@gmail.com>
Diffstat (limited to 'compiler/rustc_attr_parsing/src')
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs83
-rw-r--r--compiler/rustc_attr_parsing/src/context.rs2
2 files changed, 84 insertions, 1 deletions
diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
index 5a849e79cc3..7c412d4fa89 100644
--- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
@@ -1,4 +1,4 @@
-use rustc_attr_data_structures::{AttributeKind, OptimizeAttr};
+use rustc_attr_data_structures::{AttributeKind, OptimizeAttr, UsedBy};
 use rustc_feature::{AttributeTemplate, template};
 use rustc_session::parse::feature_err;
 use rustc_span::{Span, Symbol, sym};
@@ -228,3 +228,84 @@ impl<S: Stage> SingleAttributeParser<S> for NoMangleParser {
         Some(AttributeKind::NoMangle(cx.attr_span))
     }
 }
+
+#[derive(Default)]
+pub(crate) struct UsedParser {
+    first_compiler: Option<Span>,
+    first_linker: Option<Span>,
+}
+
+// A custom `AttributeParser` is used rather than a Simple attribute parser because
+// - Specifying two `#[used]` attributes is a warning (but will be an error in the future)
+// - But specifying two conflicting attributes: `#[used(compiler)]` and `#[used(linker)]` is already an error today
+// We can change this to a Simple parser once the warning becomes an error
+impl<S: Stage> AttributeParser<S> for UsedParser {
+    const ATTRIBUTES: AcceptMapping<Self, S> = &[(
+        &[sym::used],
+        template!(Word, List: "compiler|linker"),
+        |group: &mut Self, cx, args| {
+            let used_by = match args {
+                ArgParser::NoArgs => UsedBy::Linker,
+                ArgParser::List(list) => {
+                    let Some(l) = list.single() else {
+                        cx.expected_single_argument(list.span);
+                        return;
+                    };
+
+                    match l.meta_item().and_then(|i| i.path().word_sym()) {
+                        Some(sym::compiler) => {
+                            if !cx.features().used_with_arg() {
+                                feature_err(
+                                    &cx.sess(),
+                                    sym::used_with_arg,
+                                    cx.attr_span,
+                                    "`#[used(compiler)]` is currently unstable",
+                                )
+                                .emit();
+                            }
+                            UsedBy::Compiler
+                        }
+                        Some(sym::linker) => {
+                            if !cx.features().used_with_arg() {
+                                feature_err(
+                                    &cx.sess(),
+                                    sym::used_with_arg,
+                                    cx.attr_span,
+                                    "`#[used(linker)]` is currently unstable",
+                                )
+                                .emit();
+                            }
+                            UsedBy::Linker
+                        }
+                        _ => {
+                            cx.expected_specific_argument(l.span(), vec!["compiler", "linker"]);
+                            return;
+                        }
+                    }
+                }
+                ArgParser::NameValue(_) => return,
+            };
+
+            let target = match used_by {
+                UsedBy::Compiler => &mut group.first_compiler,
+                UsedBy::Linker => &mut group.first_linker,
+            };
+
+            let attr_span = cx.attr_span;
+            if let Some(prev) = *target {
+                cx.warn_unused_duplicate(prev, attr_span);
+            } else {
+                *target = Some(attr_span);
+            }
+        },
+    )];
+
+    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,
+        })
+    }
+}
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index 83e3c75dedb..71bb86ca3d3 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -17,6 +17,7 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
 use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser};
 use crate::attributes::codegen_attrs::{
     ColdParser, ExportNameParser, NakedParser, NoMangleParser, OptimizeParser, TrackCallerParser,
+    UsedParser,
 };
 use crate::attributes::confusables::ConfusablesParser;
 use crate::attributes::deprecation::DeprecationParser;
@@ -103,6 +104,7 @@ attribute_parsers!(
         ConstStabilityParser,
         NakedParser,
         StabilityParser,
+        UsedParser,
         // tidy-alphabetical-end
 
         // tidy-alphabetical-start