about summary refs log tree commit diff
path: root/compiler/rustc_attr_parsing/src/interface.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_attr_parsing/src/interface.rs')
-rw-r--r--compiler/rustc_attr_parsing/src/interface.rs73
1 files changed, 51 insertions, 22 deletions
diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs
index 22bbea766f2..f652d39a708 100644
--- a/compiler/rustc_attr_parsing/src/interface.rs
+++ b/compiler/rustc_attr_parsing/src/interface.rs
@@ -1,3 +1,5 @@
+use std::borrow::Cow;
+
 use rustc_ast as ast;
 use rustc_ast::NodeId;
 use rustc_errors::DiagCtxtHandle;
@@ -49,27 +51,44 @@ impl<'sess> AttributeParser<'sess, Early> {
         target_node_id: NodeId,
         features: Option<&'sess Features>,
     ) -> Option<Attribute> {
-        let mut p = Self {
-            features,
-            tools: Vec::new(),
-            parse_only: Some(sym),
+        let mut parsed = Self::parse_limited_all(
             sess,
-            stage: Early { emit_errors: ShouldEmit::Nothing },
-        };
-        let mut parsed = p.parse_attribute_list(
             attrs,
+            Some(sym),
+            Target::Crate, // Does not matter, we're not going to emit errors anyways
             target_span,
             target_node_id,
-            Target::Crate, // Does not matter, we're not going to emit errors anyways
+            features,
+            ShouldEmit::Nothing,
+        );
+        assert!(parsed.len() <= 1);
+        parsed.pop()
+    }
+
+    pub fn parse_limited_all(
+        sess: &'sess Session,
+        attrs: &[ast::Attribute],
+        parse_only: Option<Symbol>,
+        target: Target,
+        target_span: Span,
+        target_node_id: NodeId,
+        features: Option<&'sess Features>,
+        emit_errors: ShouldEmit,
+    ) -> Vec<Attribute> {
+        let mut p =
+            Self { features, tools: Vec::new(), parse_only, sess, stage: Early { emit_errors } };
+        p.parse_attribute_list(
+            attrs,
+            target_span,
+            target_node_id,
+            target,
             OmitDoc::Skip,
             std::convert::identity,
             |_lint| {
-                panic!("can't emit lints here for now (nothing uses this atm)");
+                // FIXME: Can't emit lints here for now
+                // This branch can be hit when an attribute produces a warning during early parsing (such as attributes on macro calls)
             },
-        );
-        assert!(parsed.len() <= 1);
-
-        parsed.pop()
+        )
     }
 
     pub fn parse_single<T>(
@@ -79,9 +98,9 @@ impl<'sess> AttributeParser<'sess, Early> {
         target_node_id: NodeId,
         features: Option<&'sess Features>,
         emit_errors: ShouldEmit,
-        parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser<'_>) -> T,
+        parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser<'_>) -> Option<T>,
         template: &AttributeTemplate,
-    ) -> T {
+    ) -> Option<T> {
         let mut parser = Self {
             features,
             tools: Vec::new(),
@@ -92,7 +111,9 @@ impl<'sess> AttributeParser<'sess, Early> {
         let ast::AttrKind::Normal(normal_attr) = &attr.kind else {
             panic!("parse_single called on a doc attr")
         };
-        let meta_parser = MetaItemParser::from_attr(normal_attr, parser.dcx());
+        let parts =
+            normal_attr.item.path.segments.iter().map(|seg| seg.ident.name).collect::<Vec<_>>();
+        let meta_parser = MetaItemParser::from_attr(normal_attr, &parts, &sess.psess, emit_errors)?;
         let path = meta_parser.path();
         let args = meta_parser.args();
         let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext {
@@ -199,14 +220,22 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
                 //     }))
                 // }
                 ast::AttrKind::Normal(n) => {
-                    attr_paths.push(PathParser::Ast(&n.item.path));
+                    attr_paths.push(PathParser(Cow::Borrowed(&n.item.path)));
 
-                    let parser = MetaItemParser::from_attr(n, self.dcx());
-                    let path = parser.path();
-                    let args = parser.args();
-                    let path_parts = path.segments().map(|i| i.name).collect::<Vec<_>>();
+                    let parts =
+                        n.item.path.segments.iter().map(|seg| seg.ident.name).collect::<Vec<_>>();
 
-                    if let Some(accepts) = S::parsers().accepters.get(path_parts.as_slice()) {
+                    if let Some(accepts) = S::parsers().accepters.get(parts.as_slice()) {
+                        let Some(parser) = MetaItemParser::from_attr(
+                            n,
+                            &parts,
+                            &self.sess.psess,
+                            self.stage.should_emit(),
+                        ) else {
+                            continue;
+                        };
+                        let path = parser.path();
+                        let args = parser.args();
                         for accept in accepts {
                             let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext {
                                 shared: SharedContext {