================
@@ -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