Author: Yeoul Na Date: 2026-11-03T10:46:22-08:00 New Revision: a23f991b4e3c856d89cc7424a1efa908562a1376
URL: https://github.com/llvm/llvm-project/commit/a23f991b4e3c856d89cc7424a1efa908562a1376 DIFF: https://github.com/llvm/llvm-project/commit/a23f991b4e3c856d89cc7424a1efa908562a1376.diff LOG: [BoundsSafety][NFC] Add late-parsed type attribute lists to declarators (#224559) This is groundwork for late-parsing type attributes in every type position where an ordinary type attribute can appear, following the direction set in https://github.com/llvm/llvm-project/pull/223267, which allows a CountAttributedType's count to be filled in later. Ordinary type attributes are kept on the DeclSpec, on each DeclaratorChunk and on the Declarator. Give late-parsed type attributes the same three homes, with nothing producing or consuming them yet. No functional change: no caller passes a list yet, so the lists stay empty. The next commit populates them. Assisted-by: Opus 5.5 <sub>Stack created with <a href="https://github.com/github/gh-stack">GitHub Stacks CLI</a> • <a href="https://gh.io/stacks-feedback">Give Feedback 💬</a></sub> Added: Modified: clang/include/clang/Parse/Parser.h clang/include/clang/Sema/DeclSpec.h clang/lib/Parse/ParseDecl.cpp Removed: ################################################################################ diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index b19f0ed880ddfe..e4fa25ebc427f6 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1953,10 +1953,12 @@ class Parser : public CodeCompletionHandler { DeclSpec &DS, AccessSpecifier AS, DeclSpecContext DSContext, LateParsedAttrList *LateAttrs = nullptr); - void ParseSpecifierQualifierList( - DeclSpec &DS, AccessSpecifier AS = AS_none, - DeclSpecContext DSC = DeclSpecContext::DSC_normal) { - ParseSpecifierQualifierList(DS, getImplicitTypenameContext(DSC), AS, DSC); + void + ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS = AS_none, + DeclSpecContext DSC = DeclSpecContext::DSC_normal, + LateParsedAttrList *LateAttrs = nullptr) { + ParseSpecifierQualifierList(DS, getImplicitTypenameContext(DSC), AS, DSC, + LateAttrs); } /// ParseSpecifierQualifierList @@ -1967,10 +1969,12 @@ class Parser : public CodeCompletionHandler { /// [GNU] attributes specifier-qualifier-list[opt] /// \endverbatim /// - void ParseSpecifierQualifierList( - DeclSpec &DS, ImplicitTypenameContext AllowImplicitTypename, - AccessSpecifier AS = AS_none, - DeclSpecContext DSC = DeclSpecContext::DSC_normal); + void + ParseSpecifierQualifierList(DeclSpec &DS, + ImplicitTypenameContext AllowImplicitTypename, + AccessSpecifier AS = AS_none, + DeclSpecContext DSC = DeclSpecContext::DSC_normal, + LateParsedAttrList *LateAttrs = nullptr); /// ParseEnumSpecifier /// \verbatim @@ -2677,7 +2681,8 @@ class Parser : public CodeCompletionHandler { void ParseTypeQualifierListOpt( DeclSpec &DS, unsigned AttrReqs = AR_AllAttributesParsed, bool AtomicOrPtrauthAllowed = true, bool IdentifierRequired = false, - llvm::function_ref<void()> CodeCompletionHandler = {}); + llvm::function_ref<void()> CodeCompletionHandler = {}, + LateParsedAttrList *LateAttrs = nullptr); /// ParseDirectDeclarator /// \verbatim diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index 7b58bfcf53d98a..a1fd6c8ef6adc8 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -214,6 +214,64 @@ namespace clang { unsigned location_size() const { return Builder.getBuffer().second; } }; + /// 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, + bool LateAttrParseTypeAttrOnly = false) + : ParseSoon(PSoon), + LateAttrParseExperimentalExtOnly(LateAttrParseExperimentalExtOnly), + LateAttrParseTypeAttrOnly(LateAttrParseTypeAttrOnly) {} + + /// A list for the late-parsed type attributes of a declaration specifier, + /// declarator or declarator chunk. + static LateParsedAttrList forTypeAttrs() { + return LateParsedAttrList(/*PSoon=*/true, + /*LateAttrParseExperimentalExtOnly=*/true, + /*LateAttrParseTypeAttrOnly=*/true); + } + + bool parseSoon() const { return ParseSoon; } + /// returns true iff the attribute to be parsed should only be late parsed + /// if it is annotated with `LateAttrParseExperimentalExt` + bool lateAttrParseExperimentalExtOnly() const { + return LateAttrParseExperimentalExtOnly; + } + + bool lateAttrParseTypeAttrOnly() const { return LateAttrParseTypeAttrOnly; } + + private: + bool ParseSoon; // Are we planning to parse these shortly after creation? + bool LateAttrParseExperimentalExtOnly; + bool LateAttrParseTypeAttrOnly; + }; + + /// The part of a late-parsed type attribute that Sema reads and fills in + /// during type construction. The parser owns the attribute and its cached + /// tokens and embeds this, so Sema never needs to see the parser's type. + struct LateParsedTypeAttrInfo { + ParsedAttr::Kind Kind; + SourceLocation NameLoc; + + /// The type built for this attribute during type construction, still + /// missing the argument that hasn't been parsed yet. Filled in by + /// `Sema::ProcessLateParsedTypeAttr` and completed once the enclosing scope + /// makes the argument parseable. Null if type construction rejected the + /// attribute. + /// + /// Store pointer to the base class so the parser stays agnostic about which + /// bounds attribute this is; Sema dispatches on the concrete kind when + /// completing. + BoundsAttributedType *TypeToComplete = nullptr; + + LateParsedTypeAttrInfo(ParsedAttr::Kind Kind, SourceLocation NameLoc) + : Kind(Kind), NameLoc(NameLoc) {} + }; + /// Captures information about "declaration specifiers". /// /// "Declaration specifiers" encompasses storage-class-specifiers, @@ -408,6 +466,9 @@ class DeclSpec { // attributes. ParsedAttributes Attrs; + // late attributes + LateParsedAttrList LateParsedAttrs; + // Scope specifier for the type spec, if applicable. CXXScopeSpec TypeScope; @@ -484,7 +545,8 @@ class DeclSpec { FS_virtual_specified(false), FS_noreturn_specified(false), FriendSpecifiedFirst(false), ConstexprSpecifier(static_cast<unsigned>( ConstexprSpecKind::Unspecified)), - Attrs(attrFactory), writtenBS(), ObjCQualifiers(nullptr) {} + Attrs(attrFactory), LateParsedAttrs(LateParsedAttrList::forTypeAttrs()), + writtenBS(), ObjCQualifiers(nullptr) {} // storage-class-specifier SCS getStorageClassSpec() const { return (SCS)StorageClassSpec; } @@ -884,6 +946,11 @@ class DeclSpec { ParsedAttributes &getAttributes() { return Attrs; } const ParsedAttributes &getAttributes() const { return Attrs; } + LateParsedAttrList &getLateAttributes() { return LateParsedAttrs; } + const LateParsedAttrList &getLateAttributes() const { + return LateParsedAttrs; + } + void takeAttributesAppendingingFrom(ParsedAttributes &attrs) { Attrs.takeAllAppendingFrom(attrs); } @@ -1256,61 +1323,12 @@ class UnqualifiedId { SourceLocation getEndLoc() const LLVM_READONLY { return EndLocation; } }; -/// 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, - bool LateAttrParseTypeAttrOnly = false) - : ParseSoon(PSoon), - LateAttrParseExperimentalExtOnly(LateAttrParseExperimentalExtOnly), - LateAttrParseTypeAttrOnly(LateAttrParseTypeAttrOnly) {} - - bool parseSoon() const { return ParseSoon; } - /// returns true iff the attribute to be parsed should only be late parsed - /// if it is annotated with `LateAttrParseExperimentalExt` - bool lateAttrParseExperimentalExtOnly() const { - return LateAttrParseExperimentalExtOnly; - } - - bool lateAttrParseTypeAttrOnly() const { return LateAttrParseTypeAttrOnly; } - -private: - bool ParseSoon; // Are we planning to parse these shortly after creation? - bool LateAttrParseExperimentalExtOnly; - bool LateAttrParseTypeAttrOnly; -}; - -/// The part of a late-parsed type attribute that Sema reads and fills in during -/// type construction. The parser owns the attribute and its cached tokens and -/// embeds this, so Sema never needs to see the parser's type. -struct LateParsedTypeAttrInfo { - ParsedAttr::Kind Kind; - SourceLocation NameLoc; - - /// The type built for this attribute during type construction, still missing - /// the argument that hasn't been parsed yet. Filled in by - /// `Sema::ProcessLateParsedTypeAttr` and completed once the enclosing scope - /// makes the argument parseable. Null if type construction rejected the - /// attribute. - /// - /// Held as the base class so the parser stays agnostic about which bounds - /// attribute this is; Sema dispatches on the concrete kind when completing. - BoundsAttributedType *TypeToComplete = nullptr; - - LateParsedTypeAttrInfo(ParsedAttr::Kind Kind, SourceLocation NameLoc) - : Kind(Kind), NameLoc(NameLoc) {} -}; - /// One instance of this struct is used for each type in a /// declarator that is parsed. /// /// This is intended to be a small value object. struct DeclaratorChunk { - DeclaratorChunk() {}; + DeclaratorChunk() : LateAttrList(LateParsedAttrList::forTypeAttrs()) {} enum { Pointer, Reference, Array, Function, BlockPointer, MemberPointer, Paren, Pipe @@ -1328,6 +1346,7 @@ struct DeclaratorChunk { } ParsedAttributesView AttrList; + LateParsedAttrList LateAttrList; struct PointerTypeInfo { /// The type qualifiers: const/volatile/restrict/unaligned/atomic. @@ -2040,6 +2059,8 @@ class Declarator { /// corresponding constructor parameter. const ParsedAttributesView &DeclarationAttrs; + LateParsedAttrList LateParsedAttrs; + /// The asm label, if specified. Expr *AsmLabel; @@ -2105,7 +2126,8 @@ class Declarator { Redeclaration(false), Extension(false), ObjCIvar(false), ObjCWeakProperty(false), InlineStorageUsed(false), HasInitializer(false), Attrs(DS.getAttributePool().getFactory()), - DeclarationAttrs(DeclarationAttrs), AsmLabel(nullptr), + DeclarationAttrs(DeclarationAttrs), + LateParsedAttrs(LateParsedAttrList::forTypeAttrs()), AsmLabel(nullptr), TrailingRequiresClause(nullptr), InventedTemplateParameterList(nullptr) { assert(llvm::all_of(DeclarationAttrs, @@ -2194,6 +2216,7 @@ class Declarator { DeclTypeInfo[i].destroy(); DeclTypeInfo.clear(); Attrs.clear(); + LateParsedAttrs.clear(); AsmLabel = nullptr; InlineStorageUsed = false; HasInitializer = false; @@ -2428,13 +2451,16 @@ class Declarator { /// This function takes attrs by R-Value reference because it takes ownership /// of those attributes from the parameter. void AddTypeInfo(const DeclaratorChunk &TI, ParsedAttributes &&attrs, - SourceLocation EndLoc) { + SourceLocation EndLoc, + const LateParsedAttrList &LateAttrs = {}) { DeclTypeInfo.push_back(TI); DeclTypeInfo.back().getAttrs().prepend(attrs.begin(), attrs.end()); getAttributePool().takeAllFrom(attrs.getPool()); if (!EndLoc.isInvalid()) SetRangeEnd(EndLoc); + + DeclTypeInfo.back().LateAttrList.append(LateAttrs); } /// AddTypeInfo - Add a chunk to this declarator. Also extend the range to @@ -2764,6 +2790,11 @@ class Declarator { return DeclarationAttrs; } + LateParsedAttrList &getLateAttributes() { return LateParsedAttrs; } + const LateParsedAttrList &getLateAttributes() const { + return LateParsedAttrs; + } + /// hasAttributes - do we contain any attributes? bool hasAttributes() const { if (!getAttributes().empty() || !getDeclarationAttributes().empty() || diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index e452c312702491..03252922458d04 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2768,12 +2768,17 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( void Parser::ParseSpecifierQualifierList( DeclSpec &DS, ImplicitTypenameContext AllowImplicitTypename, - AccessSpecifier AS, DeclSpecContext DSC) { + AccessSpecifier AS, DeclSpecContext DSC, LateParsedAttrList *LateAttrs) { ParsedTemplateInfo TemplateInfo; + + assert((!LateAttrs || + llvm::none_of(*LateAttrs, llvm::IsaPred<LateParsedTypeAttribute>)) && + "caller's late-attribute list must not hold type attributes yet"); + /// specifier-qualifier-list is a subset of declaration-specifiers. Just /// parse declaration-specifiers and complain about extra stuff. /// TODO: diagnose attribute-specifiers and alignment-specifiers. - ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC, nullptr, + ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC, LateAttrs, AllowImplicitTypename); // Validate declspec for type-name. @@ -6326,7 +6331,8 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide, void Parser::ParseTypeQualifierListOpt( DeclSpec &DS, unsigned AttrReqs, bool AtomicOrPtrauthAllowed, - bool IdentifierRequired, llvm::function_ref<void()> CodeCompletionHandler) { + bool IdentifierRequired, llvm::function_ref<void()> CodeCompletionHandler, + LateParsedAttrList *LateAttrs) { if ((AttrReqs & AR_CXX11AttributesParsed) && isAllowedCXX11AttributeSpecifier()) { ParsedAttributes Attrs(AttrFactory); @@ -6494,7 +6500,7 @@ void Parser::ParseTypeQualifierListOpt( // recovery is graceful. if (AttrReqs & AR_GNUAttributesParsed || AttrReqs & AR_GNUAttributesParsedAndRejected) { - ParseGNUAttributes(DS.getAttributes()); + ParseGNUAttributes(DS.getAttributes(), LateAttrs); continue; // do *not* consume the next token! } // otherwise, FALL THROUGH! _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
