[clang] [BoundsSafety] unify ParseLexedAttribute (PR #186033)
Mohammed Ashraf via cfe-commits
cfe-commits at lists.llvm.org
Wed Mar 11 21:07:21 PDT 2026
https://github.com/Holo-xy created https://github.com/llvm/llvm-project/pull/186033
Resolves #93263
>From d8bec4125f1893f3c14d4d3e0449760a4e1d423f Mon Sep 17 00:00:00 2001
From: Mohammed Ashraf <mohammedashraf4599 at gmail.com>
Date: Thu, 12 Mar 2026 03:27:11 +0000
Subject: [PATCH] [BoundsSafety] merge ParseLexedAttribute and
ParseLexedCAttribute functions
---
clang/include/clang/Parse/Parser.h | 17 ++----
clang/lib/Parse/ParseCXXInlineMethods.cpp | 69 +++++++++++++++--------
clang/lib/Parse/ParseDecl.cpp | 64 +--------------------
3 files changed, 51 insertions(+), 99 deletions(-)
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 5ae02e2b4e8ad..2efc901ff49ad 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -1337,7 +1337,8 @@ class Parser : public CodeCompletionHandler {
/// Parse all attributes in LAs, and attach them to Decl D.
void ParseLexedAttributeList(LateParsedAttrList &LAs, Decl *D,
- bool EnterScope, bool OnDefinition);
+ bool EnterScope, bool OnDefinition,
+ ParsedAttributes *OutAttrs = nullptr);
/// Finish parsing an attribute for which parsing was delayed.
/// This will be called at the end of parsing a class declaration
@@ -1345,7 +1346,8 @@ class Parser : public CodeCompletionHandler {
/// create an attribute with the arguments filled in. We add this
/// to the Attribute list for the decl.
void ParseLexedAttribute(LateParsedAttribute &LA, bool EnterScope,
- bool OnDefinition);
+ bool OnDefinition,
+ ParsedAttributes *OutAttrs = nullptr);
/// ParseLexedMethodDeclarations - We finished parsing the member
/// specification of a top (non-nested) C++ class. Now go over the
@@ -1478,17 +1480,6 @@ class Parser : public CodeCompletionHandler {
const char *&PrevSpec, unsigned &DiagID,
bool &isInvalid);
- void ParseLexedCAttributeList(LateParsedAttrList &LA, bool EnterScope,
- ParsedAttributes *OutAttrs = nullptr);
-
- /// Finish parsing an attribute for which parsing was delayed.
- /// This will be called at the end of parsing a class declaration
- /// for each LateParsedAttribute. We consume the saved tokens and
- /// create an attribute with the arguments filled in. We add this
- /// to the Attribute list for the decl.
- void ParseLexedCAttribute(LateParsedAttribute &LA, bool EnterScope,
- ParsedAttributes *OutAttrs = nullptr);
-
void ParseLexedPragmas(ParsingClass &Class);
void ParseLexedPragma(LateParsedPragma &LP);
diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp
index bc18881e89110..aefcfce55508c 100644
--- a/clang/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp
@@ -717,20 +717,22 @@ void Parser::ParseLexedAttributes(ParsingClass &Class) {
}
void Parser::ParseLexedAttributeList(LateParsedAttrList &LAs, Decl *D,
- bool EnterScope, bool OnDefinition) {
+ bool EnterScope, bool OnDefinition,
+ ParsedAttributes *OutAttrs) {
assert(LAs.parseSoon() &&
"Attribute list should be marked for immediate parsing.");
for (unsigned i = 0, ni = LAs.size(); i < ni; ++i) {
if (D)
LAs[i]->addDecl(D);
- ParseLexedAttribute(*LAs[i], EnterScope, OnDefinition);
+ ParseLexedAttribute(*LAs[i], EnterScope, OnDefinition, OutAttrs);
delete LAs[i];
}
LAs.clear();
}
-void Parser::ParseLexedAttribute(LateParsedAttribute &LA,
- bool EnterScope, bool OnDefinition) {
+void Parser::ParseLexedAttribute(LateParsedAttribute &LA, bool EnterScope,
+ bool OnDefinition,
+ ParsedAttributes *OutAttrs) {
// Create a fake EOF so that attribute parsing won't go off the end of the
// attribute.
Token AttrEnd;
@@ -751,24 +753,45 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA,
if (LA.Decls.size() > 0) {
Decl *D = LA.Decls[0];
- NamedDecl *ND = dyn_cast<NamedDecl>(D);
- RecordDecl *RD = dyn_cast_or_null<RecordDecl>(D->getDeclContext());
- // Allow 'this' within late-parsed attributes.
- Sema::CXXThisScopeRAII ThisScope(Actions, RD, Qualifiers(),
- ND && ND->isCXXInstanceMember());
+ if (getLangOpts().CPlusPlus) {
+ NamedDecl *ND = dyn_cast<NamedDecl>(D);
+ RecordDecl *RD = dyn_cast_or_null<RecordDecl>(D->getDeclContext());
- if (LA.Decls.size() == 1) {
- // If the Decl is templatized, add template parameters to scope.
- ReenterTemplateScopeRAII InDeclScope(*this, D, EnterScope);
+ // Allow 'this' within late-parsed attributes.
+ Sema::CXXThisScopeRAII ThisScope(Actions, RD, Qualifiers(),
+ ND && ND->isCXXInstanceMember());
- // If the Decl is on a function, add function parameters to the scope.
+ if (LA.Decls.size() == 1) {
+ // If the Decl is templatized, add template parameters to scope.
+ ReenterTemplateScopeRAII InDeclScope(*this, D, EnterScope);
+
+ // If the Decl is on a function, add function parameters to the scope.
+ bool HasFunScope = EnterScope && D->isFunctionOrFunctionTemplate();
+ if (HasFunScope) {
+ InDeclScope.Scopes.Enter(Scope::FnScope | Scope::DeclScope |
+ Scope::CompoundStmtScope);
+ Actions.ActOnReenterFunctionContext(Actions.CurScope, D);
+ }
+
+ ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, nullptr,
+ nullptr, SourceLocation(),
+ ParsedAttr::Form::GNU(), nullptr);
+
+ if (HasFunScope)
+ Actions.ActOnExitFunctionContext();
+ } else {
+ // If there are multiple decls, then the decl cannot be within the
+ // function scope.
+ ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, nullptr,
+ nullptr, SourceLocation(),
+ ParsedAttr::Form::GNU(), nullptr);
+ }
+ } else {
bool HasFunScope = EnterScope && D->isFunctionOrFunctionTemplate();
- if (HasFunScope) {
- InDeclScope.Scopes.Enter(Scope::FnScope | Scope::DeclScope |
- Scope::CompoundStmtScope);
+ ParseScope FnScope(this, Scope::FnScope | Scope::DeclScope, HasFunScope);
+ if (HasFunScope)
Actions.ActOnReenterFunctionContext(Actions.CurScope, D);
- }
ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, nullptr,
nullptr, SourceLocation(), ParsedAttr::Form::GNU(),
@@ -776,13 +799,10 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA,
if (HasFunScope)
Actions.ActOnExitFunctionContext();
- } else {
- // If there are multiple decls, then the decl cannot be within the
- // function scope.
- ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, nullptr,
- nullptr, SourceLocation(), ParsedAttr::Form::GNU(),
- nullptr);
}
+ } else if (OutAttrs) {
+ ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, nullptr, nullptr,
+ SourceLocation(), ParsedAttr::Form::GNU(), nullptr);
} else {
Diag(Tok, diag::warn_attribute_no_decl) << LA.AttrName.getName();
}
@@ -802,6 +822,9 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA,
if (Tok.is(tok::eof) && Tok.getEofData() == AttrEnd.getEofData())
ConsumeAnyToken();
+
+ if (OutAttrs)
+ OutAttrs->takeAllAppendingFrom(Attrs);
}
void Parser::ParseLexedPragmas(ParsingClass &Class) {
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 72935f427b7f8..46c261aa04e3d 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -4802,68 +4802,6 @@ void Parser::ParseStructDeclaration(
}
}
-// TODO: All callers of this function should be moved to
-// `Parser::ParseLexedAttributeList`.
-void Parser::ParseLexedCAttributeList(LateParsedAttrList &LAs, bool EnterScope,
- ParsedAttributes *OutAttrs) {
- assert(LAs.parseSoon() &&
- "Attribute list should be marked for immediate parsing.");
- for (auto *LA : LAs) {
- ParseLexedCAttribute(*LA, EnterScope, OutAttrs);
- delete LA;
- }
- LAs.clear();
-}
-
-void Parser::ParseLexedCAttribute(LateParsedAttribute &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);
-
- // TODO: Use `EnterScope`
- (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);
-
- 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))
- ConsumeAnyToken();
-
- // Consume the fake EOF token if it's there
- if (Tok.is(tok::eof) && Tok.getEofData() == AttrEnd.getEofData())
- ConsumeAnyToken();
-
- if (OutAttrs) {
- OutAttrs->takeAllAppendingFrom(Attrs);
- }
-}
-
void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
DeclSpec::TST TagType, RecordDecl *TagDecl) {
PrettyDeclStackTraceEntry CrashInfo(Actions.Context, TagDecl, RecordLoc,
@@ -4990,7 +4928,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
MaybeParseGNUAttributes(attrs, &LateFieldAttrs);
// Late parse field attributes if necessary.
- ParseLexedCAttributeList(LateFieldAttrs, /*EnterScope=*/false);
+ ParseLexedAttributeList(LateFieldAttrs, nullptr, false, false);
SmallVector<Decl *, 32> FieldDecls(TagDecl->fields());
More information about the cfe-commits
mailing list