[clang] [BoundsSafety][NFC] Introduce LateParsedTypeAttribute for late-parsed type attributes (PR #192799)
Yeoul Na via cfe-commits
cfe-commits at lists.llvm.org
Sat Apr 18 10:18:09 PDT 2026
https://github.com/rapidsna created https://github.com/llvm/llvm-project/pull/192799
Preparatory refactoring for llvm/llvm-project#179612. The new late parsing approach needs a distinct data structure to carry type-attribute-specific information through the late parsing pipeline, separate from declaration-level late-parsed attributes.
- Add LateParsedTypeAttribute subtyping LateParsedAttribute
- Add LPA_Kind enum and LLVM-style RTTI to distinguish declaration vs type late-parsed attributes
- Add ParseLexedTypeAttribute and LateTypeAttrParserCallback to Parser
- Extract the shared token setup, parsing, and cleanup logic from ParseLexedCAttribute and ParseLexedTypeAttribute into a common ParseLexedCAttributeTokens helper.
>From 844fc9b65126aa307d679e76a876368a15d65cb9 Mon Sep 17 00:00:00 2001
From: Yeoul Na <yeoul_na at apple.com>
Date: Tue, 14 Apr 2026 12:26:18 -0700
Subject: [PATCH 1/3] [BoundsSafety][NFC] Move LateParsedAttribute outside
Parser class; move LateParsedAttrList to DeclSpec.h
Preparatory refactoring for llvm/llvm-project#179612, which introduces
late parsing of bounds-safety attributes as type attributes. The new
approach needs LateParsedAttribute accessible from DeclSpec.h (to store
late attr pointers in DeclaratorChunk, Declarator, and DeclSpec), which
cannot depend on Parser.h.
- Move LateParsedDeclaration and LateParsedAttribute to namespace level in Parser.h
- Move LateParsedAttrList to DeclSpec.h with a forward declaration of LateParsedAttribute
Other LateParsedDeclaration subclasses (LateParsedClass, LateParsedPragma,
LateParsedMemberInitializer, etc.) remain inside Parser as they are only
created and consumed within Parser and don't need to cross the Parser/Sema
boundary.
---
clang/include/clang/Parse/Parser.h | 107 +++++++++-------------
clang/include/clang/Sema/DeclSpec.h | 21 +++++
clang/lib/Parse/ParseCXXInlineMethods.cpp | 14 +--
3 files changed, 72 insertions(+), 70 deletions(-)
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index c077671cb2407..412fe5f13d844 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -164,6 +164,48 @@ enum class CXX11AttributeKind {
InvalidAttributeSpecifier
};
+/// [class.mem]p1: "... the class is regarded as complete within
+/// - function bodies
+/// - default arguments
+/// - exception-specifications (TODO: C++0x)
+/// - and brace-or-equal-initializers for non-static data members
+/// (including such things in nested classes)."
+/// LateParsedDeclarations build the tree of those elements so they can
+/// be parsed after parsing the top-level class.
+class LateParsedDeclaration {
+public:
+ virtual ~LateParsedDeclaration();
+
+ virtual void ParseLexedMethodDeclarations();
+ virtual void ParseLexedMemberInitializers();
+ virtual void ParseLexedMethodDefs();
+ virtual void ParseLexedAttributes();
+ virtual void ParseLexedPragmas();
+};
+
+/// Contains the lexed tokens of an attribute with arguments that
+/// may reference member variables and so need to be parsed at the
+/// end of the class declaration after parsing all other member
+/// member declarations.
+/// FIXME: Perhaps we should change the name of LateParsedDeclaration to
+/// LateParsedTokens.
+struct LateParsedAttribute : public LateParsedDeclaration {
+ Parser *Self;
+ CachedTokens Toks;
+ IdentifierInfo &AttrName;
+ IdentifierInfo *MacroII = nullptr;
+ SourceLocation AttrNameLoc;
+ SmallVector<Decl *, 2> Decls;
+
+ explicit LateParsedAttribute(Parser *P, IdentifierInfo &Name,
+ SourceLocation Loc)
+ : Self(P), AttrName(Name), AttrNameLoc(Loc) {}
+
+ void ParseLexedAttributes() override;
+
+ void addDecl(Decl *D) { Decls.push_back(D); }
+};
+
/// Parser - This implements a parser for the C family of languages. After
/// parsing units of the grammar, productions are invoked to handle whatever has
/// been read.
@@ -950,7 +992,6 @@ class Parser : public CodeCompletionHandler {
void SkipFunctionBody();
struct ParsedTemplateInfo;
- class LateParsedAttrList;
/// ParseFunctionDefinition - We parsed and verified that the specified
/// Declarator is well formed. If this is a K&R-style function, read the
@@ -1118,26 +1159,9 @@ class Parser : public CodeCompletionHandler {
///@{
private:
- struct ParsingClass;
+ friend struct LateParsedAttribute;
- /// [class.mem]p1: "... the class is regarded as complete within
- /// - function bodies
- /// - default arguments
- /// - exception-specifications (TODO: C++0x)
- /// - and brace-or-equal-initializers for non-static data members
- /// (including such things in nested classes)."
- /// LateParsedDeclarations build the tree of those elements so they can
- /// be parsed after parsing the top-level class.
- class LateParsedDeclaration {
- public:
- virtual ~LateParsedDeclaration();
-
- virtual void ParseLexedMethodDeclarations();
- virtual void ParseLexedMemberInitializers();
- virtual void ParseLexedMethodDefs();
- virtual void ParseLexedAttributes();
- virtual void ParseLexedPragmas();
- };
+ struct ParsingClass;
/// Inner node of the LateParsedDeclaration tree that parses
/// all its members recursively.
@@ -1161,29 +1185,6 @@ class Parser : public CodeCompletionHandler {
ParsingClass *Class;
};
- /// Contains the lexed tokens of an attribute with arguments that
- /// may reference member variables and so need to be parsed at the
- /// end of the class declaration after parsing all other member
- /// member declarations.
- /// FIXME: Perhaps we should change the name of LateParsedDeclaration to
- /// LateParsedTokens.
- struct LateParsedAttribute : public LateParsedDeclaration {
- Parser *Self;
- CachedTokens Toks;
- IdentifierInfo &AttrName;
- IdentifierInfo *MacroII = nullptr;
- SourceLocation AttrNameLoc;
- SmallVector<Decl *, 2> Decls;
-
- explicit LateParsedAttribute(Parser *P, IdentifierInfo &Name,
- SourceLocation Loc)
- : Self(P), AttrName(Name), AttrNameLoc(Loc) {}
-
- void ParseLexedAttributes() override;
-
- void addDecl(Decl *D) { Decls.push_back(D); }
- };
-
/// Contains the lexed tokens of a pragma with arguments that
/// may reference member variables and so need to be parsed at the
/// end of the class declaration after parsing all other member
@@ -1204,26 +1205,6 @@ class Parser : public CodeCompletionHandler {
void ParseLexedPragmas() override;
};
- // A list of late-parsed attributes. Used by ParseGNUAttributes.
- class LateParsedAttrList : public SmallVector<LateParsedAttribute *, 2> {
- public:
- LateParsedAttrList(bool PSoon = false,
- bool LateAttrParseExperimentalExtOnly = false)
- : ParseSoon(PSoon),
- LateAttrParseExperimentalExtOnly(LateAttrParseExperimentalExtOnly) {}
-
- bool parseSoon() { return ParseSoon; }
- /// returns true iff the attribute to be parsed should only be late parsed
- /// if it is annotated with `LateAttrParseExperimentalExt`
- bool lateAttrParseExperimentalExtOnly() {
- return LateAttrParseExperimentalExtOnly;
- }
-
- private:
- bool ParseSoon; // Are we planning to parse these shortly after creation?
- bool LateAttrParseExperimentalExtOnly;
- };
-
/// Contains the lexed tokens of a member function definition
/// which needs to be parsed at the end of the class declaration
/// after parsing all other member declarations.
diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h
index 6e5421c7072c7..aff63ec56ddb2 100644
--- a/clang/include/clang/Sema/DeclSpec.h
+++ b/clang/include/clang/Sema/DeclSpec.h
@@ -50,6 +50,7 @@ namespace clang {
class Declarator;
class OverflowBehaviorType;
struct TemplateIdAnnotation;
+ struct LateParsedAttribute;
/// Represents a C++ nested-name-specifier or a global scope specifier.
///
@@ -1249,6 +1250,26 @@ class UnqualifiedId {
/// A set of tokens that has been cached for later parsing.
typedef SmallVector<Token, 4> CachedTokens;
+// A list of late-parsed attributes. Used by ParseGNUAttributes.
+class LateParsedAttrList : public SmallVector<LateParsedAttribute *, 2> {
+public:
+ LateParsedAttrList(bool PSoon = false,
+ bool LateAttrParseExperimentalExtOnly = false)
+ : ParseSoon(PSoon),
+ LateAttrParseExperimentalExtOnly(LateAttrParseExperimentalExtOnly) {}
+
+ bool parseSoon() { return ParseSoon; }
+ /// returns true iff the attribute to be parsed should only be late parsed
+ /// if it is annotated with `LateAttrParseExperimentalExt`
+ bool lateAttrParseExperimentalExtOnly() {
+ return LateAttrParseExperimentalExtOnly;
+ }
+
+private:
+ bool ParseSoon; // Are we planning to parse these shortly after creation?
+ bool LateAttrParseExperimentalExtOnly;
+};
+
/// One instance of this struct is used for each type in a
/// declarator that is parsed.
///
diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp
index bc18881e89110..bea7d9e55a77d 100644
--- a/clang/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp
@@ -268,12 +268,12 @@ void Parser::ParseCXXNonStaticMemberInitializer(Decl *VarD) {
Toks.push_back(Eof);
}
-Parser::LateParsedDeclaration::~LateParsedDeclaration() {}
-void Parser::LateParsedDeclaration::ParseLexedMethodDeclarations() {}
-void Parser::LateParsedDeclaration::ParseLexedMemberInitializers() {}
-void Parser::LateParsedDeclaration::ParseLexedMethodDefs() {}
-void Parser::LateParsedDeclaration::ParseLexedAttributes() {}
-void Parser::LateParsedDeclaration::ParseLexedPragmas() {}
+LateParsedDeclaration::~LateParsedDeclaration() {}
+void LateParsedDeclaration::ParseLexedMethodDeclarations() {}
+void LateParsedDeclaration::ParseLexedMemberInitializers() {}
+void LateParsedDeclaration::ParseLexedMethodDefs() {}
+void LateParsedDeclaration::ParseLexedAttributes() {}
+void LateParsedDeclaration::ParseLexedPragmas() {}
Parser::LateParsedClass::LateParsedClass(Parser *P, ParsingClass *C)
: Self(P), Class(C) {}
@@ -314,7 +314,7 @@ void Parser::LateParsedMemberInitializer::ParseLexedMemberInitializers() {
Self->ParseLexedMemberInitializer(*this);
}
-void Parser::LateParsedAttribute::ParseLexedAttributes() {
+void LateParsedAttribute::ParseLexedAttributes() {
Self->ParseLexedAttribute(*this, true, false);
}
>From 95fc3d9d11c1890bd6ca1615d1df6d139e8d4522 Mon Sep 17 00:00:00 2001
From: Yeoul Na <yeoul_na at apple.com>
Date: Tue, 14 Apr 2026 12:32:59 -0700
Subject: [PATCH 2/3] [BoundsSafety][NFC] Introduce LateParsedTypeAttribute for
late-parsed type attributes
Preparatory refactoring for llvm/llvm-project#179612. The new late
parsing approach needs a distinct data structure to carry
type-attribute-specific information through the late parsing pipeline,
separate from declaration-level late-parsed attributes.
- Add LateParsedTypeAttribute subtyping LateParsedAttribute
- Add LPA_Kind enum and LLVM-style RTTI to distinguish declaration vs type late-parsed attributes
- Add ParseLexedTypeAttribute and LateTypeAttrParserCallback to Parser
---
clang/include/clang/Parse/Parser.h | 58 +++++++++++++++++++-
clang/include/clang/Sema/DeclSpec.h | 10 +++-
clang/lib/Parse/ParseCXXInlineMethods.cpp | 2 +
clang/lib/Parse/ParseDecl.cpp | 66 +++++++++++++++++++++++
4 files changed, 132 insertions(+), 4 deletions(-)
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 412fe5f13d844..8e5cadaa229c5 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -190,6 +190,12 @@ class LateParsedDeclaration {
/// FIXME: Perhaps we should change the name of LateParsedDeclaration to
/// LateParsedTokens.
struct LateParsedAttribute : public LateParsedDeclaration {
+
+ enum LPA_Kind {
+ LPA_Declaration,
+ LPA_Type,
+ };
+
Parser *Self;
CachedTokens Toks;
IdentifierInfo &AttrName;
@@ -197,13 +203,51 @@ struct LateParsedAttribute : public LateParsedDeclaration {
SourceLocation AttrNameLoc;
SmallVector<Decl *, 2> Decls;
+private:
+ LPA_Kind Kind;
+
+public:
explicit LateParsedAttribute(Parser *P, IdentifierInfo &Name,
- SourceLocation Loc)
- : Self(P), AttrName(Name), AttrNameLoc(Loc) {}
+ SourceLocation Loc,
+ LPA_Kind Kind = LPA_Declaration)
+ : Self(P), AttrName(Name), AttrNameLoc(Loc), Kind(Kind) {}
void ParseLexedAttributes() override;
void addDecl(Decl *D) { Decls.push_back(D); }
+
+ LPA_Kind getKind() const { return Kind; }
+
+ // LLVM-style RTTI support
+ static bool classof(const LateParsedAttribute *LA) {
+ // LateParsedAttribute matches both Declaration and Type kinds
+ return LA->getKind() == LPA_Declaration || LA->getKind() == LPA_Type;
+ }
+};
+
+/// Contains the lexed tokens of an attribute with arguments that
+/// may reference member variables and so need to be parsed at the
+/// end of the class declaration after parsing all other member
+/// member declarations.
+/// FIXME: Perhaps we should change the name of LateParsedDeclaration to
+/// LateParsedTokens.
+struct LateParsedTypeAttribute : public LateParsedAttribute {
+
+ explicit LateParsedTypeAttribute(Parser *P, IdentifierInfo &Name,
+ SourceLocation Loc)
+ : LateParsedAttribute(P, Name, Loc, LPA_Type) {}
+
+ void ParseLexedAttributes() override;
+
+ /// Parse this late-parsed type attribute and store results in OutAttrs.
+ /// This method can be called from Sema during type transformation to
+ /// parse the cached tokens and produce the final attribute.
+ void ParseInto(ParsedAttributes &OutAttrs);
+
+ // LLVM-style RTTI support
+ static bool classof(const LateParsedAttribute *LA) {
+ return LA->getKind() == LPA_Type;
+ }
};
/// Parser - This implements a parser for the C family of languages. After
@@ -1160,6 +1204,7 @@ class Parser : public CodeCompletionHandler {
private:
friend struct LateParsedAttribute;
+ friend struct LateParsedTypeAttribute;
struct ParsingClass;
@@ -1481,6 +1526,15 @@ class Parser : public CodeCompletionHandler {
void ParseLexedCAttribute(LateParsedAttribute &LA, bool EnterScope,
ParsedAttributes *OutAttrs = nullptr);
+ void ParseLexedTypeAttribute(LateParsedTypeAttribute &LA, bool EnterScope,
+ ParsedAttributes &OutAttrs);
+
+ /// Helper function to move LateParsedTypeAttribute pointers from one list
+ /// to another. Filters type attributes from \p From and appends them to \p
+ /// To.
+ static void TakeTypeAttrsAppendingFrom(LateParsedAttrList &To,
+ LateParsedAttrList &From);
+
void ParseLexedPragmas(ParsingClass &Class);
void ParseLexedPragma(LateParsedPragma &LP);
diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h
index aff63ec56ddb2..5e09b8bdac84a 100644
--- a/clang/include/clang/Sema/DeclSpec.h
+++ b/clang/include/clang/Sema/DeclSpec.h
@@ -51,6 +51,7 @@ namespace clang {
class OverflowBehaviorType;
struct TemplateIdAnnotation;
struct LateParsedAttribute;
+ struct LateParsedTypeAttribute;
/// Represents a C++ nested-name-specifier or a global scope specifier.
///
@@ -1254,9 +1255,11 @@ typedef SmallVector<Token, 4> CachedTokens;
class LateParsedAttrList : public SmallVector<LateParsedAttribute *, 2> {
public:
LateParsedAttrList(bool PSoon = false,
- bool LateAttrParseExperimentalExtOnly = false)
+ bool LateAttrParseExperimentalExtOnly = false,
+ bool LateAttrParseTypeAttrOnly = false)
: ParseSoon(PSoon),
- LateAttrParseExperimentalExtOnly(LateAttrParseExperimentalExtOnly) {}
+ LateAttrParseExperimentalExtOnly(LateAttrParseExperimentalExtOnly),
+ LateAttrParseTypeAttrOnly(LateAttrParseTypeAttrOnly) {}
bool parseSoon() { return ParseSoon; }
/// returns true iff the attribute to be parsed should only be late parsed
@@ -1265,9 +1268,12 @@ class LateParsedAttrList : public SmallVector<LateParsedAttribute *, 2> {
return LateAttrParseExperimentalExtOnly;
}
+ bool lateAttrParseTypeAttrOnly() { return LateAttrParseTypeAttrOnly; }
+
private:
bool ParseSoon; // Are we planning to parse these shortly after creation?
bool LateAttrParseExperimentalExtOnly;
+ bool LateAttrParseTypeAttrOnly;
};
/// One instance of this struct is used for each type in a
diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp
index bea7d9e55a77d..c9b1c1eb50921 100644
--- a/clang/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp
@@ -318,6 +318,8 @@ void LateParsedAttribute::ParseLexedAttributes() {
Self->ParseLexedAttribute(*this, true, false);
}
+void LateParsedTypeAttribute::ParseLexedAttributes() {}
+
void Parser::LateParsedPragma::ParseLexedPragmas() {
Self->ParseLexedPragma(*this);
}
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index e2ac86bc5e064..d10c4d11b535d 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -4885,6 +4885,72 @@ void Parser::ParseLexedCAttribute(LateParsedAttribute &LA, bool EnterScope,
}
}
+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::ParseStructUnionBody(SourceLocation RecordLoc,
DeclSpec::TST TagType, RecordDecl *TagDecl) {
PrettyDeclStackTraceEntry CrashInfo(Actions.Context, TagDecl, RecordLoc,
>From e28735a4a8d2f0721d0890c6527e581c50f9a4de Mon Sep 17 00:00:00 2001
From: Yeoul Na <yeoul_na at apple.com>
Date: Sat, 18 Apr 2026 10:15:24 -0700
Subject: [PATCH 3/3] [BoundsSafety][NFC] Extract ParseLexedCAttributeTokens
helper; polish LateParsedTypeAttribute comment
Extract the shared token setup, parsing, and cleanup logic from
ParseLexedCAttribute and ParseLexedTypeAttribute into a common
ParseLexedCAttributeTokens helper. The two callers now differ only
in what they do with the resulting ParsedAttributes (apply to decls
vs return for type construction).
Also update the LateParsedTypeAttribute doc comment to describe its
actual purpose rather than carrying the copy-pasted LateParsedAttribute
comment.
---
clang/include/clang/Parse/Parser.h | 16 +++++---
clang/lib/Parse/ParseDecl.cpp | 65 ++++++------------------------
2 files changed, 23 insertions(+), 58 deletions(-)
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 8e5cadaa229c5..5df0013ee2d4c 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -225,12 +225,11 @@ struct LateParsedAttribute : public LateParsedDeclaration {
}
};
-/// Contains the lexed tokens of an attribute with arguments that
-/// may reference member variables and so need to be parsed at the
-/// end of the class declaration after parsing all other member
-/// member declarations.
-/// FIXME: Perhaps we should change the name of LateParsedDeclaration to
-/// LateParsedTokens.
+/// A late-parsed attribute that will be applied as a type attribute.
+/// Unlike LateParsedAttribute (which applies to declarations via
+/// ActOnFinishDelayedAttribute), this stores cached tokens that are
+/// parsed during type construction when the placeholder LateParsedAttrType
+/// is replaced with a concrete type (e.g., CountAttributedType).
struct LateParsedTypeAttribute : public LateParsedAttribute {
explicit LateParsedTypeAttribute(Parser *P, IdentifierInfo &Name,
@@ -1529,6 +1528,11 @@ class Parser : public CodeCompletionHandler {
void ParseLexedTypeAttribute(LateParsedTypeAttribute &LA, bool EnterScope,
ParsedAttributes &OutAttrs);
+ /// Parse cached tokens for a late-parsed attribute and return the parsed
+ /// attributes. Shared implementation used by both ParseLexedCAttribute and
+ /// ParseLexedTypeAttribute.
+ ParsedAttributes ParseLexedCAttributeTokens(LateParsedAttribute &LA);
+
/// Helper function to move LateParsedTypeAttribute pointers from one list
/// to another. Filters type attributes from \p From and appends them to \p
/// To.
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index d10c4d11b535d..1cbd36c1bf7b6 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -4836,8 +4836,7 @@ void Parser::ParseLexedCAttributeList(LateParsedAttrList &LAs, bool EnterScope,
LAs.clear();
}
-void Parser::ParseLexedCAttribute(LateParsedAttribute &LA, bool EnterScope,
- ParsedAttributes *OutAttrs) {
+ParsedAttributes Parser::ParseLexedCAttributeTokens(LateParsedAttribute &LA) {
// Create a fake EOF so that attribute parsing won't go off the end of the
// attribute.
Token AttrEnd;
@@ -4856,9 +4855,6 @@ void Parser::ParseLexedCAttribute(LateParsedAttribute &LA, bool EnterScope,
// as when we entered this function.
ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
- // TODO: Use `EnterScope`
- (void)EnterScope;
-
ParsedAttributes Attrs(AttrFactory);
assert(LA.Decls.size() <= 1 &&
@@ -4868,9 +4864,6 @@ void Parser::ParseLexedCAttribute(LateParsedAttribute &LA, bool EnterScope,
ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, nullptr, nullptr,
SourceLocation(), ParsedAttr::Form::GNU(), nullptr);
- for (auto *D : LA.Decls)
- Actions.ActOnFinishDelayedAttribute(getCurScope(), D, Attrs);
-
// 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))
@@ -4880,56 +4873,24 @@ void Parser::ParseLexedCAttribute(LateParsedAttribute &LA, bool EnterScope,
if (Tok.is(tok::eof) && Tok.getEofData() == AttrEnd.getEofData())
ConsumeAnyToken();
- if (OutAttrs) {
+ return Attrs;
+}
+
+void Parser::ParseLexedCAttribute(LateParsedAttribute &LA, bool EnterScope,
+ ParsedAttributes *OutAttrs) {
+ ParsedAttributes Attrs = ParseLexedCAttributeTokens(LA);
+
+ for (auto *D : LA.Decls)
+ Actions.ActOnFinishDelayedAttribute(getCurScope(), D, Attrs);
+
+ if (OutAttrs)
OutAttrs->takeAllAppendingFrom(Attrs);
- }
}
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();
-
+ ParsedAttributes Attrs = ParseLexedCAttributeTokens(LA);
OutAttrs.takeAllAppendingFrom(Attrs);
}
More information about the cfe-commits
mailing list