================
@@ -4809,12 +4838,107 @@ void 
Parser::ParseLexedCAttributeList(LateParsedAttrList &LAs, bool EnterScope,
   assert(LAs.parseSoon() &&
          "Attribute list should be marked for immediate parsing.");
   for (auto *LA : LAs) {
+    assert(!isa<LateParsedTypeAttribute>(LA));
     ParseLexedCAttribute(*LA, EnterScope, OutAttrs);
     delete LA;
   }
   LAs.clear();
 }
 
+void Parser::ParseLexedTypeAttribute(LateParsedTypeAttribute &LA,
+                                     bool EnterScope,
+                                     ParsedAttributes &OutAttrs) {
+  // Create a fake EOF so that attribute parsing won't go off the end of the
+  // attribute.
+  Token AttrEnd;
+  AttrEnd.startToken();
+  AttrEnd.setKind(tok::eof);
+  AttrEnd.setLocation(Tok.getLocation());
+  AttrEnd.setEofData(LA.Toks.data());
+  LA.Toks.push_back(AttrEnd);
+
+  // Append the current token at the end of the new token stream so that it
+  // doesn't get lost.
+  LA.Toks.push_back(Tok);
+  PP.EnterTokenStream(LA.Toks, /*DisableMacroExpansion=*/true,
+                      /*IsReinject=*/true);
+  // Drop the current token and bring the first cached one. It's the same token
+  // as when we entered this function.
+  ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
+
+  // Note: EnterScope parameter is not used here. Type attributes are parsed
+  // in the context where ActOnFields is called, which already has the proper
+  // scope established. The actual semantic analysis happens during the
+  // RebuildTypeWithLateParsedAttr transformation, not during token parsing.
+  (void)EnterScope;
+
+  ParsedAttributes Attrs(AttrFactory);
+
+  assert(LA.Decls.size() <= 1 &&
+         "late field attribute expects to have at most one declaration.");
+
+  // Dispatch based on the attribute and parse it
+  ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, nullptr, nullptr,
+                        SourceLocation(), ParsedAttr::Form::GNU(), nullptr);
+
+  // Due to a parsing error, we either went over the cached tokens or
+  // there are still cached tokens left, so we skip the leftover tokens.
+  while (Tok.isNot(tok::eof))
+    ConsumeAnyToken();
+
+  // Consume the fake EOF token if it's there
+  if (Tok.is(tok::eof) && Tok.getEofData() == AttrEnd.getEofData())
+    ConsumeAnyToken();
+
+  OutAttrs.takeAllAppendingFrom(Attrs);
+}
+
+void LateParsedTypeAttribute::ParseInto(ParsedAttributes &OutAttrs) {
+  // Delegate to the Parser that created this attribute
+  Self->ParseLexedTypeAttribute(*this, /*EnterScope=*/true, OutAttrs);
+}
+
+void Parser::TakeTypeAttrsAppendingFrom(LateParsedAttrList &To,
+                                        LateParsedAttrList &From) {
+  auto it =
+      std::remove_if(From.begin(), From.end(), [&](LateParsedAttribute *LA) {
+        if (auto *LTA = dyn_cast<LateParsedTypeAttribute>(LA)) {
+          To.push_back(LTA);
+          return true;
+        }
+        return false;
+      });
+  From.erase(it, From.end());
+}
+
+void Parser::ParseLateParsedTypeAttributeCallback(LateParsedTypeAttribute *LTA,
+                                                  ParsedAttributes *Attrs) {
+  // Parse the cached attribute tokens
+  LTA->ParseInto(*Attrs);
+  // LateParsedTypeAttribute is no longer needed so delete it. Ideally,
+  // LateParsedAttrType would own this object, but LateParsedTypeAttribute
+  // is intentionally forward declared to avoid making the AST depend on
+  // Sema/Parser components.
+  delete LTA;
+}
+
+SourceLocation Parser::GetLateParsedAttributeLocationCallback(
+    const LateParsedTypeAttribute *LTA) {
+  return LTA ? LTA->AttrNameLoc : SourceLocation();
----------------
zmodem wrote:

Do we need the null check, or could the caller do that?

https://github.com/llvm/llvm-project/pull/179612
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to