[llvm-branch-commits] [clang] [BoundsSafety][NFC] Thread a late-parsed attribute list through declarators (PR #224559)
Yeoul Na via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Sat Sep 19 10:51:59 PDT 2026
https://github.com/rapidsna updated https://github.com/llvm/llvm-project/pull/224559
>From 9b15b39350c446254445111cf7b8620eca765339 Mon Sep 17 00:00:00 2001
From: Yeoul Na <yeoul_na at apple.com>
Date: Thu, 17 Sep 2026 21:38:11 -0700
Subject: [PATCH] [BoundsSafety][NFC] Thread a late-parsed attribute list
through declarators
A late-parsed type attribute is written in the middle of a declarator, so the
list it lands in has to travel with the declarator pieces until the enclosing
record can supply its argument. Add that storage and plumbing, with nothing
producing or consuming it yet:
- Move CachedTokens and LateParsedAttrList earlier in DeclSpec.h so DeclSpec,
Declarator and DeclaratorChunk can hold one.
- Give DeclSpec, Declarator and DeclaratorChunk a LateParsedAttrList, and let
Declarator::AddTypeInfo carry one onto the chunk it appends.
- Give ParseSpecifierQualifierList and ParseTypeQualifierListOpt an optional
LateParsedAttrList parameter, passed down to ParseDeclarationSpecifiers.
No functional change: the lists stay empty and no caller passes one. The next
commit populates them.
---
clang/include/clang/Parse/Parser.h | 23 +++++---
clang/include/clang/Sema/DeclSpec.h | 87 ++++++++++++++++++-----------
clang/lib/Parse/ParseDecl.cpp | 15 ++++-
3 files changed, 80 insertions(+), 45 deletions(-)
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index ae7c345ba6ce3..6d0affa3c8822 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
@@ -2678,7 +2682,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 e6dc6831d893f..9b1f3b244515d 100644
--- a/clang/include/clang/Sema/DeclSpec.h
+++ b/clang/include/clang/Sema/DeclSpec.h
@@ -213,6 +213,34 @@ 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) {}
+
+ 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;
+ };
+
/// Captures information about "declaration specifiers".
///
/// "Declaration specifiers" encompasses storage-class-specifiers,
@@ -404,6 +432,9 @@ class DeclSpec {
// attributes.
ParsedAttributes Attrs;
+ // late attributes
+ LateParsedAttrList LateParsedAttrs;
+
// Scope specifier for the type spec, if applicable.
CXXScopeSpec TypeScope;
@@ -480,7 +511,9 @@ 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(true, true, true), writtenBS(),
+
+ ObjCQualifiers(nullptr) {}
// storage-class-specifier
SCS getStorageClassSpec() const { return (SCS)StorageClassSpec; }
@@ -880,6 +913,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);
}
@@ -1252,40 +1290,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;
-};
-
/// 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(true, true, true) {};
enum {
Pointer, Reference, Array, Function, BlockPointer, MemberPointer, Paren, Pipe
@@ -1303,6 +1313,7 @@ struct DeclaratorChunk {
}
ParsedAttributesView AttrList;
+ LateParsedAttrList LateAttrList;
struct PointerTypeInfo {
/// The type qualifiers: const/volatile/restrict/unaligned/atomic.
@@ -2015,6 +2026,8 @@ class Declarator {
/// corresponding constructor parameter.
const ParsedAttributesView &DeclarationAttrs;
+ LateParsedAttrList LateParsedAttrs;
+
/// The asm label, if specified.
Expr *AsmLabel;
@@ -2080,8 +2093,8 @@ class Declarator {
Redeclaration(false), Extension(false), ObjCIvar(false),
ObjCWeakProperty(false), InlineStorageUsed(false),
HasInitializer(false), Attrs(DS.getAttributePool().getFactory()),
- DeclarationAttrs(DeclarationAttrs), AsmLabel(nullptr),
- TrailingRequiresClause(nullptr),
+ DeclarationAttrs(DeclarationAttrs), LateParsedAttrs(true, true, true),
+ AsmLabel(nullptr), TrailingRequiresClause(nullptr),
InventedTemplateParameterList(nullptr) {
assert(llvm::all_of(DeclarationAttrs,
[](const ParsedAttr &AL) {
@@ -2403,13 +2416,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
@@ -2739,6 +2755,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 0d205df0c2a48..9dbfc7ec8b393 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2753,12 +2753,20 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
void Parser::ParseSpecifierQualifierList(
DeclSpec &DS, ImplicitTypenameContext AllowImplicitTypename,
- AccessSpecifier AS, DeclSpecContext DSC) {
+ AccessSpecifier AS, DeclSpecContext DSC, LateParsedAttrList *LateAttrs) {
ParsedTemplateInfo TemplateInfo;
+
+ if (LateAttrs)
+ assert(!std::any_of(LateAttrs->begin(), LateAttrs->end(),
+ [&](const LateParsedAttribute *LA) {
+ return isa<LateParsedTypeAttribute>(LA);
+ }) &&
+ "Late type attribute carried over");
+
/// 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.
@@ -6285,7 +6293,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);
More information about the llvm-branch-commits
mailing list