[llvm-branch-commits] [clang] [Clang] [NFC] Expansion Statements (Part 4: for-range and `ParseScope` refactor) (PR #169683)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Mar 24 08:29:47 PDT 2026
https://github.com/Sirraide updated https://github.com/llvm/llvm-project/pull/169683
>From 8f5fc6a6cca47d38c82ccd04a5b5184d18421775 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Wed, 26 Nov 2025 16:11:59 +0100
Subject: [PATCH] [Clang] [C++26] Expansion Statements (Part 4)
---
clang/include/clang/Parse/Parser.h | 85 +---
clang/include/clang/Sema/Scope.h | 41 +-
clang/include/clang/Sema/Sema.h | 51 +-
clang/lib/Interpreter/IncrementalParser.cpp | 4 +-
clang/lib/Parse/ParseCXXInlineMethods.cpp | 9 +-
clang/lib/Parse/ParseDecl.cpp | 24 +-
clang/lib/Parse/ParseDeclCXX.cpp | 22 +-
clang/lib/Parse/ParseExpr.cpp | 5 +-
clang/lib/Parse/ParseExprCXX.cpp | 22 +-
clang/lib/Parse/ParseHLSL.cpp | 2 +-
clang/lib/Parse/ParseObjc.cpp | 28 +-
clang/lib/Parse/ParseOpenACC.cpp | 2 +-
clang/lib/Parse/ParseOpenMP.cpp | 33 +-
clang/lib/Parse/ParsePragma.cpp | 4 +-
clang/lib/Parse/ParseStmt.cpp | 37 +-
clang/lib/Parse/ParseTemplate.cpp | 10 +-
clang/lib/Parse/Parser.cpp | 55 +--
clang/lib/Sema/Scope.cpp | 33 ++
clang/lib/Sema/Sema.cpp | 32 ++
clang/lib/Sema/SemaDecl.cpp | 2 +-
clang/lib/Sema/SemaStmt.cpp | 487 +++++++++++---------
21 files changed, 538 insertions(+), 450 deletions(-)
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 0cef7658be320..f0bdc3d19e62c 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -211,10 +211,6 @@ class Parser : public CodeCompletionHandler {
const Token &getCurToken() const { return Tok; }
Scope *getCurScope() const { return Actions.getCurScope(); }
- void incrementMSManglingNumber() const {
- return Actions.incrementMSManglingNumber();
- }
-
// Type forwarding. All of these are statically 'void*', but they may all be
// different actual classes based on the actions in place.
typedef OpaquePtr<DeclGroupRef> DeclGroupPtrTy;
@@ -385,78 +381,6 @@ class Parser : public CodeCompletionHandler {
return MightBeCXXScopeToken() && TryAnnotateCXXScopeToken(EnteringContext);
}
- //===--------------------------------------------------------------------===//
- // Scope manipulation
-
- /// ParseScope - Introduces a new scope for parsing. The kind of
- /// scope is determined by ScopeFlags. Objects of this type should
- /// be created on the stack to coincide with the position where the
- /// parser enters the new scope, and this object's constructor will
- /// create that new scope. Similarly, once the object is destroyed
- /// the parser will exit the scope.
- class ParseScope {
- Parser *Self;
- ParseScope(const ParseScope &) = delete;
- void operator=(const ParseScope &) = delete;
-
- public:
- // ParseScope - Construct a new object to manage a scope in the
- // parser Self where the new Scope is created with the flags
- // ScopeFlags, but only when we aren't about to enter a compound statement.
- ParseScope(Parser *Self, unsigned ScopeFlags, bool EnteredScope = true,
- bool BeforeCompoundStmt = false)
- : Self(Self) {
- if (EnteredScope && !BeforeCompoundStmt)
- Self->EnterScope(ScopeFlags);
- else {
- if (BeforeCompoundStmt)
- Self->incrementMSManglingNumber();
-
- this->Self = nullptr;
- }
- }
-
- // Exit - Exit the scope associated with this object now, rather
- // than waiting until the object is destroyed.
- void Exit() {
- if (Self) {
- Self->ExitScope();
- Self = nullptr;
- }
- }
-
- ~ParseScope() { Exit(); }
- };
-
- /// Introduces zero or more scopes for parsing. The scopes will all be exited
- /// when the object is destroyed.
- class MultiParseScope {
- Parser &Self;
- unsigned NumScopes = 0;
-
- MultiParseScope(const MultiParseScope &) = delete;
-
- public:
- MultiParseScope(Parser &Self) : Self(Self) {}
- void Enter(unsigned ScopeFlags) {
- Self.EnterScope(ScopeFlags);
- ++NumScopes;
- }
- void Exit() {
- while (NumScopes) {
- Self.ExitScope();
- --NumScopes;
- }
- }
- ~MultiParseScope() { Exit(); }
- };
-
- /// EnterScope - Start a new scope.
- void EnterScope(unsigned ScopeFlags);
-
- /// ExitScope - Pop a scope off the scope stack.
- void ExitScope();
-
//===--------------------------------------------------------------------===//
// Diagnostic Emission and Error recovery.
@@ -547,11 +471,6 @@ class Parser : public CodeCompletionHandler {
StackExhaustionHandler StackHandler;
- /// ScopeCache - Cache scopes to reduce malloc traffic.
- static constexpr int ScopeCacheSize = 16;
- unsigned NumCachedScopes;
- Scope *ScopeCache[ScopeCacheSize];
-
/// Identifiers used for SEH handling in Borland. These are only
/// allowed in particular circumstances
// __except block
@@ -2538,7 +2457,7 @@ class Parser : public CodeCompletionHandler {
assert(SS.isSet() && "C++ scope was not set!");
CreatedScope = true;
- P.EnterScope(0); // Not a decl scope.
+ P.Actions.EnterScope(0); // Not a decl scope.
if (!P.Actions.ActOnCXXEnterDeclaratorScope(P.getCurScope(), SS))
EnteredScope = true;
@@ -2550,7 +2469,7 @@ class Parser : public CodeCompletionHandler {
P.Actions.ActOnCXXExitDeclaratorScope(P.getCurScope(), SS);
}
if (CreatedScope)
- P.ExitScope();
+ P.Actions.ExitScope();
}
};
diff --git a/clang/include/clang/Sema/Scope.h b/clang/include/clang/Sema/Scope.h
index fb429b73f8627..30ef5e5461a8c 100644
--- a/clang/include/clang/Sema/Scope.h
+++ b/clang/include/clang/Sema/Scope.h
@@ -29,11 +29,11 @@ class raw_ostream;
} // namespace llvm
namespace clang {
-
class Decl;
class DeclContext;
class UsingDirectiveDecl;
class VarDecl;
+class Sema;
/// Scope - A scope is a transient data structure that is used while parsing the
/// program. It assists with resolving identifiers to the appropriate
@@ -685,6 +685,45 @@ class Scope {
void dump() const;
};
+/// ParseScope - Introduces a new scope for parsing. The kind of
+/// scope is determined by ScopeFlags. Objects of this type should
+/// be created on the stack to coincide with the position where the
+/// parser enters the new scope, and this object's constructor will
+/// create that new scope. Similarly, once the object is destroyed
+/// the parser will exit the scope.
+class ParseScope {
+ Sema *S;
+ ParseScope(const ParseScope &) = delete;
+ void operator=(const ParseScope &) = delete;
+
+public:
+ // ParseScope - Construct a new object to manage a scope in the
+ // parser Self where the new Scope is created with the flags
+ // ScopeFlags, but only when we aren't about to enter a compound statement.
+ ParseScope(Sema &S, unsigned ScopeFlags, bool EnteredScope = true,
+ bool BeforeCompoundStmt = false);
+
+ // Exit - Exit the scope associated with this object now, rather
+ // than waiting until the object is destroyed.
+ void Exit();
+
+ ~ParseScope() { Exit(); }
+};
+
+/// Introduces zero or more scopes for parsing. The scopes will all be exited
+/// when the object is destroyed.
+class MultiParseScope {
+ Sema &S;
+ unsigned NumScopes = 0;
+
+ MultiParseScope(const MultiParseScope &) = delete;
+
+public:
+ MultiParseScope(Sema &S) : S(S) {}
+ void Enter(unsigned ScopeFlags);
+ void Exit();
+ ~MultiParseScope() { Exit(); }
+};
} // namespace clang
#endif // LLVM_CLANG_SEMA_SCOPE_H
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 24c81ed9ea590..e745a1d4eafe6 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1213,6 +1213,15 @@ class Sema final : public SemaBase {
/// Scope actions.
void ActOnTranslationUnitScope(Scope *S);
+ /// EnterScope - Start a new scope.
+ void EnterScope(unsigned ScopeFlags);
+
+ /// ExitScope - Pop a scope off the scope stack.
+ void ExitScope();
+
+ /// Delete the scope stack and all cached scopes.
+ void FreeScopes();
+
/// Determine whether \param D is function like (function or function
/// template) for parsing.
bool isDeclaratorFunctionLike(Declarator &D);
@@ -1599,10 +1608,12 @@ class Sema final : public SemaBase {
sema::SemaPPCallbacks *SemaPPCallbackHandler;
/// The parser's current scope.
- ///
- /// The parser maintains this state here.
Scope *CurScope;
+ /// ScopeCache - Cache scopes to reduce malloc traffic.
+ static constexpr unsigned MaxScopeCacheSize = 16;
+ SmallVector<std::unique_ptr<Scope>, MaxScopeCacheSize> ScopeCache;
+
mutable IdentifierInfo *Ident_super;
std::unique_ptr<SemaAMDGPU> AMDGPUPtr;
@@ -4277,7 +4288,7 @@ class Sema final : public SemaBase {
TopLevelStmtDecl *ActOnStartTopLevelStmtDecl(Scope *S);
void ActOnFinishTopLevelStmtDecl(TopLevelStmtDecl *D, Stmt *Statement);
- void ActOnPopScope(SourceLocation Loc, Scope *S);
+ void ActOnPopScope(Scope *S);
/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
/// no declarator (e.g. "struct foo;") is parsed.
@@ -11156,6 +11167,37 @@ class Sema final : public SemaBase {
BuildForRangeKind Kind,
ArrayRef<MaterializeTemporaryExpr *> LifetimeExtendTemps = {});
+ /// Set the type of a for-range declaration whose for-range or expansion
+ /// initialiser is dependent.
+ void ActOnDependentForRangeInitializer(VarDecl *LoopVar,
+ BuildForRangeKind BFRK);
+
+ /// Holds the 'begin' and 'end' variables of a range-based for loop or
+ /// expansion statement; begin-expr and end-expr are also provided; the
+ /// latter are used in some diagnostics.
+ struct ForRangeBeginEndInfo {
+ VarDecl *BeginVar = nullptr;
+ VarDecl *EndVar = nullptr;
+ Expr *BeginExpr = nullptr;
+ Expr *EndExpr = nullptr;
+ bool isValid() const { return BeginVar != nullptr && EndVar != nullptr; }
+ };
+
+ /// Determine begin-expr and end-expr and build variable declarations for
+ /// them as per [stmt.ranged].
+ ForRangeBeginEndInfo BuildCXXForRangeBeginEndVars(
+ Scope *S, VarDecl *RangeVar, SourceLocation ColonLoc,
+ SourceLocation CoawaitLoc,
+ ArrayRef<MaterializeTemporaryExpr *> LifetimeExtendTemps,
+ BuildForRangeKind Kind, bool Constexpr,
+ StmtResult *RebuildResult = nullptr,
+ llvm::function_ref<StmtResult()> RebuildWithDereference = {});
+
+ /// Build the range variable of a range-based for loop or iterating
+ /// expansion statement and return its DeclStmt.
+ StmtResult BuildCXXForRangeRangeVar(Scope *S, Expr *Range, QualType Type,
+ bool Constexpr = false);
+
/// FinishCXXForRangeStmt - Attach the body to a C++0x for-range statement.
/// This is a separate step from ActOnCXXForRangeStmt because analysis of the
/// body cannot be performed until after the type of the range variable is
@@ -11301,6 +11343,9 @@ class Sema final : public SemaBase {
SourceLocation Loc,
unsigned NumParams);
+ void ApplyForRangeOrExpansionStatementLifetimeExtension(
+ VarDecl *RangeVar, ArrayRef<MaterializeTemporaryExpr *> Temporaries);
+
private:
/// Check whether the given statement can have musttail applied to it,
/// issuing a diagnostic and returning false if not.
diff --git a/clang/lib/Interpreter/IncrementalParser.cpp b/clang/lib/Interpreter/IncrementalParser.cpp
index 16a954f3c15e7..4b3c15012eb6b 100644
--- a/clang/lib/Interpreter/IncrementalParser.cpp
+++ b/clang/lib/Interpreter/IncrementalParser.cpp
@@ -65,10 +65,10 @@ IncrementalParser::ParseOrWrapTopLevelDecl() {
P->ConsumeAnyToken();
// FIXME: Clang does not call ExitScope on finalizing the regular TU, we
// might want to do that around HandleEndOfTranslationUnit.
- P->ExitScope();
+ S.ExitScope();
S.CurContext = nullptr;
// Start a new PTU.
- P->EnterScope(Scope::DeclScope);
+ S.EnterScope(Scope::DeclScope);
S.ActOnTranslationUnitScope(P->getCurScope());
}
diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp
index bc18881e89110..cc9ff9e7e5f6f 100644
--- a/clang/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp
@@ -328,7 +328,8 @@ struct Parser::ReenterTemplateScopeRAII {
TemplateParameterDepthRAII CurTemplateDepthTracker;
ReenterTemplateScopeRAII(Parser &P, Decl *MaybeTemplated, bool Enter = true)
- : P(P), Scopes(P), CurTemplateDepthTracker(P.TemplateParameterDepth) {
+ : P(P), Scopes(P.Actions),
+ CurTemplateDepthTracker(P.TemplateParameterDepth) {
if (Enter) {
CurTemplateDepthTracker.addDepth(
P.ReenterTemplateScopes(Scopes, MaybeTemplated));
@@ -510,7 +511,7 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) {
// };
// Setup the CurScope to match the function DeclContext - we have such
// assumption in IsInFnTryBlockHandler().
- ParseScope FnScope(this, Scope::FnScope);
+ ParseScope FnScope(Actions, Scope::FnScope);
Sema::ContextRAII FnContext(Actions, FunctionToPush,
/*NewThisContext=*/false);
Sema::FunctionScopeRAII PopFnContext(Actions);
@@ -597,8 +598,8 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) {
// Parse the method body. Function body parsing code is similar enough
// to be re-used for method bodies as well.
- ParseScope FnScope(this, Scope::FnScope | Scope::DeclScope |
- Scope::CompoundStmtScope);
+ ParseScope FnScope(Actions, Scope::FnScope | Scope::DeclScope |
+ Scope::CompoundStmtScope);
Sema::FPFeaturesStateRAII SaveFPFeatures(Actions);
Actions.ActOnStartOfFunctionDef(getCurScope(), LM.D);
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 9478dfcb4c54c..572204c946bad 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -678,7 +678,7 @@ void Parser::ParseGNUAttributeArgs(
if (normalizeAttrName(AttrName->getName()) == "enable_if" &&
D && D->isFunctionDeclarator()) {
const DeclaratorChunk::FunctionTypeInfo& FTI = D->getFunctionTypeInfo();
- PrototypeScope.emplace(this, Scope::FunctionPrototypeScope |
+ PrototypeScope.emplace(Actions, Scope::FunctionPrototypeScope |
Scope::FunctionDeclarationScope |
Scope::DeclScope);
for (unsigned i = 0; i != FTI.NumParams; ++i)
@@ -2475,7 +2475,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
if (ThisDecl && P.getLangOpts().CPlusPlus) {
Scope *S = nullptr;
if (D.getCXXScopeSpec().isSet()) {
- P.EnterScope(0);
+ P.Actions.EnterScope(0);
S = P.getCurScope();
}
if (ThisDecl && !ThisDecl->isInvalidDecl()) {
@@ -2493,7 +2493,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
if (Entered)
P.Actions.ActOnCXXExitDeclInitializer(S, ThisDecl);
if (S)
- P.ExitScope();
+ P.Actions.ExitScope();
}
ThisDecl = nullptr;
}
@@ -4871,7 +4871,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
if (T.consumeOpen())
return;
- ParseScope StructScope(this, Scope::ClassScope|Scope::DeclScope);
+ ParseScope StructScope(Actions, Scope::ClassScope|Scope::DeclScope);
Actions.ActOnTagStartDefinition(getCurScope(), TagDecl);
// `LateAttrParseExperimentalExtOnly=true` requests that only attributes
@@ -5383,7 +5383,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl,
SkipBodyInfo *SkipBody) {
// Enter the scope of the enum body and start the definition.
- ParseScope EnumScope(this, Scope::DeclScope | Scope::EnumScope);
+ ParseScope EnumScope(Actions, Scope::DeclScope | Scope::EnumScope);
Actions.ActOnTagStartDefinition(getCurScope(), EnumDecl);
BalancedDelimiterTracker T(*this, tok::l_brace);
@@ -5728,8 +5728,8 @@ Parser::DeclGroupPtrTy Parser::ParseTopLevelStmtDecl() {
// Parse a top-level-stmt.
Parser::StmtVector Stmts;
ParsedStmtContext SubStmtCtx = ParsedStmtContext();
- ParseScope FnScope(this, Scope::FnScope | Scope::DeclScope |
- Scope::CompoundStmtScope);
+ ParseScope FnScope(Actions, Scope::FnScope | Scope::DeclScope |
+ Scope::CompoundStmtScope);
TopLevelStmtDecl *TLSD = Actions.ActOnStartTopLevelStmtDecl(getCurScope());
StmtResult R = ParseStatementOrDeclaration(Stmts, SubStmtCtx);
Actions.ActOnFinishTopLevelStmtDecl(TLSD, R.get());
@@ -6874,9 +6874,9 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
// Enter function-declaration scope, limiting any declarators to the
// function prototype scope, including parameter declarators.
ParseScope PrototypeScope(
- this, Scope::FunctionPrototypeScope | Scope::DeclScope |
- (IsFunctionDeclaration ? Scope::FunctionDeclarationScope
- : Scope::NoScope));
+ Actions, Scope::FunctionPrototypeScope | Scope::DeclScope |
+ (IsFunctionDeclaration ? Scope::FunctionDeclarationScope
+ : Scope::NoScope));
// The paren may be part of a C++ direct initializer, eg. "int x(1);".
// In such a case, check if we actually have a function declarator; if it
@@ -7155,7 +7155,7 @@ void Parser::ParseParenDeclarator(Declarator &D) {
// Enter function-declaration scope, limiting any declarators to the
// function prototype scope, including parameter declarators.
- ParseScope PrototypeScope(this,
+ ParseScope PrototypeScope(Actions,
Scope::FunctionPrototypeScope | Scope::DeclScope |
(D.isFunctionDeclaratorAFunctionDeclaration()
? Scope::FunctionDeclarationScope
@@ -8196,7 +8196,7 @@ TypeResult Parser::ParseTypeFromString(StringRef TypeStr, StringRef Context,
ConsumeAnyToken();
// Enter a new scope.
- ParseScope LocalScope(this, 0);
+ ParseScope LocalScope(Actions, 0);
// Parse the type.
TypeResult Result = ParseTypeName(nullptr);
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 274c354d59808..24a38bc0bd65b 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -199,7 +199,7 @@ Parser::DeclGroupPtrTy Parser::ParseNamespace(DeclaratorContext Context,
: diag::ext_inline_namespace);
// Enter a scope for the namespace.
- ParseScope NamespaceScope(this, Scope::DeclScope);
+ ParseScope NamespaceScope(Actions, Scope::DeclScope);
UsingDirectiveDecl *ImplicitUsingDirectiveDecl = nullptr;
Decl *NamespcDecl = Actions.ActOnStartNamespaceDef(
@@ -246,7 +246,7 @@ void Parser::ParseInnerNamespace(const InnerNamespaceInfoList &InnerNSs,
// Handle a nested namespace definition.
// FIXME: Preserve the source information through to the AST rather than
// desugaring it here.
- ParseScope NamespaceScope(this, Scope::DeclScope);
+ ParseScope NamespaceScope(Actions, Scope::DeclScope);
UsingDirectiveDecl *ImplicitUsingDirectiveDecl = nullptr;
Decl *NamespcDecl = Actions.ActOnStartNamespaceDef(
getCurScope(), InnerNSs[index].InlineLoc, InnerNSs[index].NamespaceLoc,
@@ -316,7 +316,7 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, DeclaratorContext Context) {
assert(isTokenStringLiteral() && "Not a string literal!");
ExprResult Lang = ParseUnevaluatedStringLiteralExpression();
- ParseScope LinkageScope(this, Scope::DeclScope);
+ ParseScope LinkageScope(Actions, Scope::DeclScope);
Decl *LinkageSpec =
Lang.isInvalid()
? nullptr
@@ -409,7 +409,7 @@ Decl *Parser::ParseExportDeclaration() {
return nullptr;
}
- ParseScope ExportScope(this, Scope::DeclScope);
+ ParseScope ExportScope(Actions, Scope::DeclScope);
Decl *ExportDecl = Actions.ActOnStartExportDecl(
getCurScope(), ExportLoc,
Tok.is(tok::l_brace) ? Tok.getLocation() : SourceLocation());
@@ -3333,7 +3333,7 @@ void Parser::SkipCXXMemberSpecification(SourceLocation RecordLoc,
// within a template argument).
if (Tok.is(tok::colon)) {
// Enter the scope of the class so that we can correctly parse its bases.
- ParseScope ClassScope(this, Scope::ClassScope | Scope::DeclScope);
+ ParseScope ClassScope(Actions, Scope::ClassScope | Scope::DeclScope);
ParsingClassDefinition ParsingDef(*this, TagDecl, /*NonNestedClass*/ true,
TagType == DeclSpec::TST_interface);
auto OldContext =
@@ -3524,7 +3524,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
}
// Enter a scope for the class.
- ParseScope ClassScope(this, Scope::ClassScope | Scope::DeclScope);
+ ParseScope ClassScope(Actions, Scope::ClassScope | Scope::DeclScope);
// Note that we are parsing a new (potentially-nested) class definition.
ParsingClassDefinition ParsingDef(*this, TagDecl, NonNestedClass,
@@ -3604,8 +3604,8 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
}
if (Tok.is(tok::colon)) {
- ParseScope InheritanceScope(this, getCurScope()->getFlags() |
- Scope::ClassInheritanceScope);
+ ParseScope InheritanceScope(Actions, getCurScope()->getFlags() |
+ Scope::ClassInheritanceScope);
ParseBaseClause(TagDecl);
if (!Tok.is(tok::l_brace)) {
@@ -4118,9 +4118,9 @@ void Parser::ParseTrailingRequiresClause(Declarator &D) {
DeclScopeObj.EnterDeclaratorScope();
ExprResult TrailingRequiresClause;
- ParseScope ParamScope(this, Scope::DeclScope |
- Scope::FunctionDeclarationScope |
- Scope::FunctionPrototypeScope);
+ ParseScope ParamScope(Actions, Scope::DeclScope |
+ Scope::FunctionDeclarationScope |
+ Scope::FunctionPrototypeScope);
Actions.ActOnStartTrailingRequiresClause(getCurScope(), D);
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index cf6fda8c31bc8..e8fad229aafd4 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -3308,8 +3308,9 @@ ExprResult Parser::ParseBlockLiteralExpression() {
// argument decls, decls within the compound expression, etc. This also
// allows determining whether a variable reference inside the block is
// within or outside of the block.
- ParseScope BlockScope(this, Scope::BlockScope | Scope::FnScope |
- Scope::CompoundStmtScope | Scope::DeclScope);
+ ParseScope BlockScope(Actions, Scope::BlockScope | Scope::FnScope |
+ Scope::CompoundStmtScope |
+ Scope::DeclScope);
// Inform sema that we are starting a block.
Actions.ActOnBlockStart(CaretLoc, getCurScope());
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index b3d50daf66b10..83d370d48a3df 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -1219,9 +1219,9 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
Declarator D(DS, ParsedAttributesView::none(), DeclaratorContext::LambdaExpr);
TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
- ParseScope LambdaScope(this, Scope::LambdaScope | Scope::DeclScope |
- Scope::FunctionDeclarationScope |
- Scope::FunctionPrototypeScope);
+ ParseScope LambdaScope(Actions, Scope::LambdaScope | Scope::DeclScope |
+ Scope::FunctionDeclarationScope |
+ Scope::FunctionPrototypeScope);
Actions.PushLambdaScope();
SourceLocation DeclLoc = Tok.getLocation();
@@ -1251,7 +1251,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
D.takeAttributesAppending(Attributes);
}
- MultiParseScope TemplateParamScope(*this);
+ MultiParseScope TemplateParamScope(Actions);
if (Tok.is(tok::less)) {
Diag(Tok, getLangOpts().CPlusPlus20
? diag::warn_cxx17_compat_lambda_template_parameter_list
@@ -1315,9 +1315,9 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
bool HasSpecifiers = false;
SourceLocation MutableLoc;
- ParseScope Prototype(this, Scope::FunctionPrototypeScope |
- Scope::FunctionDeclarationScope |
- Scope::DeclScope);
+ ParseScope Prototype(Actions, Scope::FunctionPrototypeScope |
+ Scope::FunctionDeclarationScope |
+ Scope::DeclScope);
// Parse parameter-declaration-clause.
SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
@@ -1471,7 +1471,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
// it.
unsigned ScopeFlags = Scope::BlockScope | Scope::FnScope | Scope::DeclScope |
Scope::CompoundStmtScope;
- ParseScope BodyScope(this, ScopeFlags);
+ ParseScope BodyScope(Actions, ScopeFlags);
Actions.ActOnStartOfLambdaDefinition(Intro, D, DS);
@@ -3141,8 +3141,8 @@ ExprResult Parser::ParseRequiresExpression() {
BalancedDelimiterTracker Parens(*this, tok::l_paren);
if (Tok.is(tok::l_paren)) {
// requirement parameter list is present.
- ParseScope LocalParametersScope(this, Scope::FunctionPrototypeScope |
- Scope::DeclScope);
+ ParseScope LocalParametersScope(Actions, Scope::FunctionPrototypeScope |
+ Scope::DeclScope);
Parens.consumeOpen();
if (!Tok.is(tok::r_paren)) {
ParsedAttributes FirstArgAttrs(getAttrFactory());
@@ -3171,7 +3171,7 @@ ExprResult Parser::ParseRequiresExpression() {
EnterExpressionEvaluationContext Ctx(
Actions, Sema::ExpressionEvaluationContext::Unevaluated);
- ParseScope BodyScope(this, Scope::DeclScope);
+ ParseScope BodyScope(Actions, Scope::DeclScope);
// Create a separate diagnostic pool for RequiresExprBodyDecl.
// Dependent diagnostics are attached to this Decl and non-depenedent
// diagnostics are surfaced after this parse.
diff --git a/clang/lib/Parse/ParseHLSL.cpp b/clang/lib/Parse/ParseHLSL.cpp
index c727ee3a1f1a6..f1fc21bee25a6 100644
--- a/clang/lib/Parse/ParseHLSL.cpp
+++ b/clang/lib/Parse/ParseHLSL.cpp
@@ -65,7 +65,7 @@ Decl *Parser::ParseHLSLBuffer(SourceLocation &DeclEnd,
MaybeParseHLSLAnnotations(Attrs, nullptr);
- ParseScope BufferScope(this, Scope::DeclScope);
+ ParseScope BufferScope(Actions, Scope::DeclScope);
BalancedDelimiterTracker T(*this, tok::l_brace);
if (T.consumeOpen()) {
Diag(Tok, diag::err_expected) << tok::l_brace;
diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp
index 0b9f113d9edc7..27f5a6a54613f 100644
--- a/clang/lib/Parse/ParseObjc.cpp
+++ b/clang/lib/Parse/ParseObjc.cpp
@@ -1224,8 +1224,9 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
SmallVector<const IdentifierInfo *, 12> KeyIdents;
SmallVector<SourceLocation, 12> KeyLocs;
SmallVector<SemaObjC::ObjCArgInfo, 12> ArgInfos;
- ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope |
- Scope::FunctionDeclarationScope | Scope::DeclScope);
+ ParseScope PrototypeScope(Actions, Scope::FunctionPrototypeScope |
+ Scope::FunctionDeclarationScope |
+ Scope::DeclScope);
AttributePool allParamAttrs(AttrFactory);
while (true) {
@@ -1701,7 +1702,7 @@ void Parser::ParseObjCClassInstanceVariables(ObjCContainerDecl *interfaceDecl,
assert(Tok.is(tok::l_brace) && "expected {");
SmallVector<Decl *, 32> AllIvarDecls;
- ParseScope ClassScope(this, Scope::DeclScope | Scope::ClassScope);
+ ParseScope ClassScope(Actions, Scope::DeclScope | Scope::ClassScope);
BalancedDelimiterTracker T(*this, tok::l_brace);
T.consumeOpen();
@@ -2237,7 +2238,7 @@ Parser::ParseObjCSynchronizedStmt(SourceLocation atLoc) {
Actions.ObjC().ActOnObjCAtSynchronizedOperand(atLoc, operand.get());
// Parse the compound statement within a new scope.
- ParseScope bodyScope(this, Scope::DeclScope | Scope::CompoundStmtScope);
+ ParseScope bodyScope(Actions, Scope::DeclScope | Scope::CompoundStmtScope);
StmtResult body(ParseCompoundStatementBody());
bodyScope.Exit();
@@ -2263,7 +2264,7 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
}
StmtVector CatchStmts;
StmtResult FinallyStmt;
- ParseScope TryScope(this, Scope::DeclScope | Scope::CompoundStmtScope);
+ ParseScope TryScope(Actions, Scope::DeclScope | Scope::CompoundStmtScope);
StmtResult TryBody(ParseCompoundStatementBody());
TryScope.Exit();
if (TryBody.isInvalid())
@@ -2284,9 +2285,9 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
ConsumeToken(); // consume catch
if (Tok.is(tok::l_paren)) {
ConsumeParen();
- ParseScope CatchScope(this, Scope::DeclScope |
- Scope::CompoundStmtScope |
- Scope::AtCatchScope);
+ ParseScope CatchScope(Actions, Scope::DeclScope |
+ Scope::CompoundStmtScope |
+ Scope::AtCatchScope);
if (Tok.isNot(tok::ellipsis)) {
DeclSpec DS(AttrFactory);
ParsedTemplateInfo TemplateInfo;
@@ -2331,7 +2332,7 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
} else {
assert(Tok.isObjCAtKeyword(tok::objc_finally) && "Lookahead confused?");
ConsumeToken(); // consume finally
- ParseScope FinallyScope(this,
+ ParseScope FinallyScope(Actions,
Scope::DeclScope | Scope::CompoundStmtScope);
bool ShouldCapture =
@@ -2378,7 +2379,7 @@ Parser::ParseObjCAutoreleasePoolStmt(SourceLocation atLoc) {
}
// Enter a scope to hold everything within the compound stmt. Compound
// statements can always hold declarations.
- ParseScope BodyScope(this, Scope::DeclScope | Scope::CompoundStmtScope);
+ ParseScope BodyScope(Actions, Scope::DeclScope | Scope::CompoundStmtScope);
StmtResult AutoreleasePoolBody(ParseCompoundStatementBody());
@@ -3295,9 +3296,10 @@ void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) {
assert(Tok.isOneOf(tok::l_brace, tok::kw_try, tok::colon) &&
"Inline objective-c method not starting with '{' or 'try' or ':'");
// Enter a scope for the method or c-function body.
- ParseScope BodyScope(
- this, (parseMethod ? Scope::ObjCMethodScope : Scope::NoScope) |
- Scope::FnScope | Scope::DeclScope | Scope::CompoundStmtScope);
+ ParseScope BodyScope(Actions,
+ (parseMethod ? Scope::ObjCMethodScope : Scope::NoScope) |
+ Scope::FnScope | Scope::DeclScope |
+ Scope::CompoundStmtScope);
Sema::FPFeaturesStateRAII SaveFPFeatures(Actions);
// Tell the actions module that we have entered a method or c-function definition
diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp
index b79a956d51505..78418ee0a8b2e 100644
--- a/clang/lib/Parse/ParseOpenACC.cpp
+++ b/clang/lib/Parse/ParseOpenACC.cpp
@@ -1682,7 +1682,7 @@ StmtResult Parser::ParseOpenACCDirectiveStmt() {
getActions().OpenACC(), DirInfo.DirKind, DirInfo.DirLoc, {},
DirInfo.Clauses);
ParsingOpenACCDirectiveRAII DirScope(*this, /*Value=*/false);
- ParseScope ACCScope(this, getOpenACCScopeFlags(DirInfo.DirKind));
+ ParseScope ACCScope(Actions, getOpenACCScopeFlags(DirInfo.DirKind));
AssocStmt = getActions().OpenACC().ActOnAssociatedStmt(
DirInfo.StartLoc, DirInfo.DirKind, DirInfo.AtomicKind, DirInfo.Clauses,
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index 29397d67b5bcc..070b154fb4e89 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -246,9 +246,9 @@ Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) {
unsigned I = 0, E = ReductionTypes.size();
for (Decl *D : DRD.get()) {
TentativeParsingAction TPA(*this);
- ParseScope OMPDRScope(this, Scope::FnScope | Scope::DeclScope |
- Scope::CompoundStmtScope |
- Scope::OpenMPDirectiveScope);
+ ParseScope OMPDRScope(Actions, Scope::FnScope | Scope::DeclScope |
+ Scope::CompoundStmtScope |
+ Scope::OpenMPDirectiveScope);
// Parse <combiner> expression.
Actions.OpenMP().ActOnOpenMPDeclareReductionCombinerStart(getCurScope(), D);
ExprResult CombinerResult = Actions.ActOnFinishFullExpr(
@@ -282,9 +282,9 @@ Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) {
!T.expectAndConsume(diag::err_expected_lparen_after, "initializer") &&
IsCorrect;
if (Tok.isNot(tok::annot_pragma_openmp_end)) {
- ParseScope OMPDRScope(this, Scope::FnScope | Scope::DeclScope |
- Scope::CompoundStmtScope |
- Scope::OpenMPDirectiveScope);
+ ParseScope OMPDRScope(Actions, Scope::FnScope | Scope::DeclScope |
+ Scope::CompoundStmtScope |
+ Scope::OpenMPDirectiveScope);
// Parse expression.
VarDecl *OmpPrivParm =
Actions.OpenMP().ActOnOpenMPDeclareReductionInitializerStart(
@@ -463,7 +463,7 @@ Parser::ParseOpenMPDeclareMapperDirective(AccessSpecifier AS) {
SourceLocation Loc = Tok.getLocation();
unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope |
Scope::CompoundStmtScope | Scope::OpenMPDirectiveScope;
- ParseScope OMPDirectiveScope(this, ScopeFlags);
+ ParseScope OMPDirectiveScope(Actions, ScopeFlags);
Actions.OpenMP().StartOpenMPDSABlock(OMPD_declare_mapper, DirName,
getCurScope(), Loc);
@@ -611,14 +611,15 @@ namespace {
class FNContextRAII final {
Parser &P;
Sema::CXXThisScopeRAII *ThisScope;
- Parser::MultiParseScope Scopes;
+ MultiParseScope Scopes;
bool HasFunScope = false;
FNContextRAII() = delete;
FNContextRAII(const FNContextRAII &) = delete;
FNContextRAII &operator=(const FNContextRAII &) = delete;
public:
- FNContextRAII(Parser &P, Parser::DeclGroupPtrTy Ptr) : P(P), Scopes(P) {
+ FNContextRAII(Parser &P, Parser::DeclGroupPtrTy Ptr)
+ : P(P), Scopes(P.getActions()) {
Decl *D = *Ptr.get().begin();
NamedDecl *ND = dyn_cast<NamedDecl>(D);
RecordDecl *RD = dyn_cast_or_null<RecordDecl>(D->getDeclContext());
@@ -2350,7 +2351,7 @@ StmtResult Parser::ParseOpenMPExecutableDirective(
ScopeFlags |= Scope::OpenMPLoopDirectiveScope;
if (isOpenMPSimdDirective(DKind))
ScopeFlags |= Scope::OpenMPSimdDirectiveScope;
- ParseScope OMPDirectiveScope(this, ScopeFlags);
+ ParseScope OMPDirectiveScope(Actions, ScopeFlags);
Actions.OpenMP().StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope(),
Loc);
@@ -2477,7 +2478,7 @@ StmtResult Parser::ParseOpenMPInformationalDirective(
DeclarationNameInfo DirName;
unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope |
Scope::CompoundStmtScope | Scope::OpenMPDirectiveScope;
- ParseScope OMPDirectiveScope(this, ScopeFlags);
+ ParseScope OMPDirectiveScope(Actions, ScopeFlags);
Actions.OpenMP().StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope(),
Loc);
@@ -4774,7 +4775,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
// where iterator-specifier is [ iterator-type ] identifier =
// range-specification
HasIterator = true;
- EnterScope(Scope::OpenMPDirectiveScope | Scope::DeclScope);
+ Actions.EnterScope(Scope::OpenMPDirectiveScope | Scope::DeclScope);
ExprResult IteratorRes = ParseOpenMPIteratorsExpr();
Data.DepModOrTailExpr = IteratorRes.get();
// Parse ','
@@ -4887,7 +4888,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
// Handle optional iterator map modifier.
if (Tok.is(tok::identifier) && PP.getSpelling(Tok) == "iterator") {
HasIterator = true;
- EnterScope(Scope::OpenMPDirectiveScope | Scope::DeclScope);
+ Actions.EnterScope(Scope::OpenMPDirectiveScope | Scope::DeclScope);
Data.MapTypeModifiers.push_back(OMPC_MAP_MODIFIER_iterator);
Data.MapTypeModifiersLoc.push_back(Tok.getLocation());
ExprResult IteratorRes = ParseOpenMPIteratorsExpr();
@@ -5004,7 +5005,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
Tail = parseOpenMPAllocateClauseModifiers(*this, Kind, Data);
} else {
HasIterator = true;
- EnterScope(Scope::OpenMPDirectiveScope | Scope::DeclScope);
+ Actions.EnterScope(Scope::OpenMPDirectiveScope | Scope::DeclScope);
Tail = ParseOpenMPIteratorsExpr();
}
Tail = Actions.ActOnFinishFullExpr(Tail.get(), T.getOpenLocation(),
@@ -5169,7 +5170,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
const bool MayHaveTail = (Kind == OMPC_linear || Kind == OMPC_aligned);
while (IsComma || (Tok.isNot(tok::r_paren) && Tok.isNot(tok::colon) &&
Tok.isNot(tok::annot_pragma_openmp_end))) {
- ParseScope OMPListScope(this, Scope::OpenMPDirectiveScope);
+ ParseScope OMPListScope(Actions, Scope::OpenMPDirectiveScope);
ColonProtectionRAIIObject ColonRAII(*this, MayHaveTail);
if (!ParseOpenMPReservedLocator(Kind, Data, getLangOpts())) {
// Parse variable
@@ -5284,7 +5285,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
Data.RLoc = T.getCloseLocation();
// Exit from scope when the iterator is used in depend clause.
if (HasIterator)
- ExitScope();
+ Actions.ExitScope();
return (Kind != OMPC_depend && Kind != OMPC_doacross && Kind != OMPC_map &&
Vars.empty()) ||
(MustHaveTail && !Data.DepModOrTailExpr && StepFound) ||
diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp
index 734d095d74cdf..bb95aa125cca9 100644
--- a/clang/lib/Parse/ParsePragma.cpp
+++ b/clang/lib/Parse/ParsePragma.cpp
@@ -951,8 +951,8 @@ StmtResult Parser::HandlePragmaCaptured()
SourceLocation Loc = Tok.getLocation();
- ParseScope CapturedRegionScope(this, Scope::FnScope | Scope::DeclScope |
- Scope::CompoundStmtScope);
+ ParseScope CapturedRegionScope(Actions, Scope::FnScope | Scope::DeclScope |
+ Scope::CompoundStmtScope);
Actions.ActOnCapturedRegionStart(Loc, getCurScope(), CR_Default,
/*NumParams=*/1);
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 69c0c8e3c38ee..a6e3e055896c2 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -653,8 +653,8 @@ StmtResult Parser::ParseSEHExceptBlock(SourceLocation ExceptLoc) {
if (ExpectAndConsume(tok::l_paren))
return StmtError();
- ParseScope ExpectScope(this, Scope::DeclScope | Scope::ControlScope |
- Scope::SEHExceptScope);
+ ParseScope ExpectScope(Actions, Scope::DeclScope | Scope::ControlScope |
+ Scope::SEHExceptScope);
if (getLangOpts().Borland) {
Ident__exception_info->setIsPoisoned(false);
@@ -700,7 +700,7 @@ StmtResult Parser::ParseSEHFinallyBlock(SourceLocation FinallyLoc) {
if (Tok.isNot(tok::l_brace))
return StmtError(Diag(Tok, diag::err_expected) << tok::l_brace);
- ParseScope FinallyScope(this, 0);
+ ParseScope FinallyScope(Actions, 0);
Actions.ActOnStartSEHFinallyBlock();
StmtResult Block(ParseCompoundStatement());
@@ -1011,7 +1011,7 @@ StmtResult Parser::ParseCompoundStatement(bool isStmtExpr,
// Enter a scope to hold everything within the compound stmt. Compound
// statements can always hold declarations.
- ParseScope CompoundScope(this, ScopeFlags);
+ ParseScope CompoundScope(Actions, ScopeFlags);
// Parse the statements in the body.
StmtResult R;
@@ -1505,7 +1505,7 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
// while, for, and switch statements are local to the if, while, for, or
// switch statement (including the controlled statement).
//
- ParseScope IfScope(this, Scope::DeclScope | Scope::ControlScope, C99orCXX);
+ ParseScope IfScope(Actions, Scope::DeclScope | Scope::ControlScope, C99orCXX);
// Parse the condition.
StmtResult InitStmt;
@@ -1545,7 +1545,7 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
// would have to notify ParseStatement not to create a new scope. It's
// simpler to let it create a new scope.
//
- ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, IsBracedThen);
+ ParseScope InnerScope(Actions, Scope::DeclScope, C99orCXX, IsBracedThen);
MisleadingIndentationChecker MIChecker(*this, MSK_if, IfLoc);
@@ -1596,7 +1596,7 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
// The substatement in a selection-statement (each substatement, in the else
// form of the if statement) implicitly defines a local scope.
//
- ParseScope InnerScope(this, Scope::DeclScope, C99orCXX,
+ ParseScope InnerScope(Actions, Scope::DeclScope, C99orCXX,
Tok.is(tok::l_brace));
MisleadingIndentationChecker MIChecker(*this, MSK_else, ElseLoc);
@@ -1702,7 +1702,7 @@ StmtResult Parser::ParseSwitchStatement(SourceLocation *TrailingElseLoc,
unsigned ScopeFlags = Scope::SwitchScope;
if (C99orCXX)
ScopeFlags |= Scope::DeclScope | Scope::ControlScope;
- ParseScope SwitchScope(this, ScopeFlags);
+ ParseScope SwitchScope(Actions, ScopeFlags);
// Parse the condition.
StmtResult InitStmt;
@@ -1742,7 +1742,8 @@ StmtResult Parser::ParseSwitchStatement(SourceLocation *TrailingElseLoc,
//
getCurScope()->AddFlags(Scope::BreakScope);
getCurScope()->setPrecedingLabel(PrecedingLabel);
- ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace));
+ ParseScope InnerScope(Actions, Scope::DeclScope, C99orCXX,
+ Tok.is(tok::l_brace));
// We have incremented the mangling number for the SwitchScope and the
// InnerScope, which is one too many.
@@ -1791,7 +1792,7 @@ StmtResult Parser::ParseWhileStatement(SourceLocation *TrailingElseLoc,
Scope::DeclScope | Scope::ControlScope;
else
ScopeFlags = Scope::BreakScope | Scope::ContinueScope;
- ParseScope WhileScope(this, ScopeFlags);
+ ParseScope WhileScope(Actions, ScopeFlags);
// Parse the condition.
Sema::ConditionResult Cond;
@@ -1818,7 +1819,8 @@ StmtResult Parser::ParseWhileStatement(SourceLocation *TrailingElseLoc,
// See comments in ParseIfStatement for why we create a scope for the
// condition and a new scope for substatement in C++.
//
- ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace));
+ ParseScope InnerScope(Actions, Scope::DeclScope, C99orCXX,
+ Tok.is(tok::l_brace));
MisleadingIndentationChecker MIChecker(*this, MSK_while, WhileLoc);
@@ -1849,7 +1851,7 @@ StmtResult Parser::ParseDoStatement(LabelDecl *PrecedingLabel) {
else
ScopeFlags = Scope::BreakScope | Scope::ContinueScope;
- ParseScope DoScope(this, ScopeFlags);
+ ParseScope DoScope(Actions, ScopeFlags);
// OpenACC Restricts a do-while-loop inside of certain construct/clause
// combinations, so diagnose that here in OpenACC mode.
@@ -1866,7 +1868,8 @@ StmtResult Parser::ParseDoStatement(LabelDecl *PrecedingLabel) {
// which is entered and exited each time through the loop.
//
bool C99orCXX = getLangOpts().C99 || getLangOpts().CPlusPlus;
- ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace));
+ ParseScope InnerScope(Actions, Scope::DeclScope, C99orCXX,
+ Tok.is(tok::l_brace));
// Read the body statement.
StmtResult Body(ParseStatement());
@@ -2025,7 +2028,7 @@ Parser::ParseForStatement(SourceLocation *TrailingElseLoc,
if (CXXExpansionStmtDecl)
ScopeFlags |= Scope::TemplateParamScope;
- ParseScope ForScope(this, ScopeFlags);
+ ParseScope ForScope(Actions, ScopeFlags);
if (CXXExpansionStmtDecl)
// FIXME: Combine this with the scope flags above once this is actually a
// proper scope flag.
@@ -2370,7 +2373,7 @@ Parser::ParseForStatement(SourceLocation *TrailingElseLoc,
// See comments in ParseIfStatement for why we create a scope for
// for-init-statement/condition and a new scope for substatement in C++.
//
- ParseScope InnerScope(this, Scope::DeclScope, C99orCXXorObjC,
+ ParseScope InnerScope(Actions, Scope::DeclScope, C99orCXXorObjC,
Tok.is(tok::l_brace));
// The body of the for loop has the same local mangling number as the
@@ -2757,8 +2760,8 @@ StmtResult Parser::ParseCXXCatchBlock(bool FnCatch) {
// The name in a catch exception-declaration is local to the handler and
// shall not be redeclared in the outermost block of the handler.
ParseScope CatchScope(
- this, Scope::DeclScope | Scope::ControlScope | Scope::CatchScope |
- (FnCatch ? Scope::FnTryCatchScope : Scope::NoScope));
+ Actions, Scope::DeclScope | Scope::ControlScope | Scope::CatchScope |
+ (FnCatch ? Scope::FnTryCatchScope : Scope::NoScope));
// exception-declaration is equivalent to '...' or a parameter-declaration
// without default arguments.
diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp
index 330a9c6aea0c5..78a4892f3b47e 100644
--- a/clang/lib/Parse/ParseTemplate.cpp
+++ b/clang/lib/Parse/ParseTemplate.cpp
@@ -50,7 +50,7 @@ Parser::DeclGroupPtrTy Parser::ParseTemplateDeclarationOrSpecialization(
assert(Tok.isOneOf(tok::kw_export, tok::kw_template) &&
"Token does not start a template declaration.");
- MultiParseScope TemplateParamScopes(*this);
+ MultiParseScope TemplateParamScopes(Actions);
// Tell the action that names should be checked in the context of
// the declaration to come.
@@ -700,7 +700,7 @@ NamedDecl *Parser::ParseTemplateTemplateParameter(unsigned Depth,
SourceLocation LAngleLoc, RAngleLoc;
ExprResult OptionalRequiresClauseConstraintER;
{
- MultiParseScope TemplateParmScope(*this);
+ MultiParseScope TemplateParmScope(Actions);
if (ParseTemplateParameters(TemplateParmScope, Depth + 1, TemplateParams,
LAngleLoc, RAngleLoc)) {
return nullptr;
@@ -1456,7 +1456,7 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) {
Sema::ContextRAII GlobalSavedContext(
Actions, Actions.Context.getTranslationUnitDecl());
- MultiParseScope Scopes(*this);
+ MultiParseScope Scopes(Actions);
// Get the list of DeclContexts to reenter.
SmallVector<DeclContext*, 4> DeclContextsToReenter;
@@ -1493,8 +1493,8 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) {
// Parse the method body. Function body parsing code is similar enough
// to be re-used for method bodies as well.
- ParseScope FnScope(this, Scope::FnScope | Scope::DeclScope |
- Scope::CompoundStmtScope);
+ ParseScope FnScope(Actions, Scope::FnScope | Scope::DeclScope |
+ Scope::CompoundStmtScope);
// Recreate the containing function DeclContext.
Sema::ContextRAII FunctionSavedContext(Actions, FunD->getLexicalParent());
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 5d18414b1a746..fae4dcc310eb6 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -67,7 +67,6 @@ Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies)
Tok.startToken();
Tok.setKind(tok::eof);
Actions.CurScope = nullptr;
- NumCachedScopes = 0;
CurParsedObjCImpl = nullptr;
// Add #pragma handlers. These are removed and destroyed in the
@@ -419,33 +418,6 @@ bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, SkipUntilFlags Flags) {
//===----------------------------------------------------------------------===//
// Scope manipulation
//===----------------------------------------------------------------------===//
-
-void Parser::EnterScope(unsigned ScopeFlags) {
- if (NumCachedScopes) {
- Scope *N = ScopeCache[--NumCachedScopes];
- N->Init(getCurScope(), ScopeFlags);
- Actions.CurScope = N;
- } else {
- Actions.CurScope = new Scope(getCurScope(), ScopeFlags, Diags);
- }
-}
-
-void Parser::ExitScope() {
- assert(getCurScope() && "Scope imbalance!");
-
- // Inform the actions module that this scope is going away if there are any
- // decls in it.
- Actions.ActOnPopScope(Tok.getLocation(), getCurScope());
-
- Scope *OldScope = getCurScope();
- Actions.CurScope = OldScope->getParent();
-
- if (NumCachedScopes == ScopeCacheSize)
- delete OldScope;
- else
- ScopeCache[NumCachedScopes++] = OldScope;
-}
-
Parser::ParseScopeFlags::ParseScopeFlags(Parser *Self, unsigned ScopeFlags,
bool ManageFlags)
: CurScope(ManageFlags ? Self->getCurScope() : nullptr) {
@@ -466,13 +438,7 @@ Parser::ParseScopeFlags::~ParseScopeFlags() {
//===----------------------------------------------------------------------===//
Parser::~Parser() {
- // If we still have scopes active, delete the scope tree.
- delete getCurScope();
- Actions.CurScope = nullptr;
-
- // Free the scope cache.
- for (unsigned i = 0, e = NumCachedScopes; i != e; ++i)
- delete ScopeCache[i];
+ Actions.FreeScopes();
resetPragmaHandlers();
@@ -486,7 +452,7 @@ Parser::~Parser() {
void Parser::Initialize() {
// Create the translation unit scope. Install it as the current scope.
assert(getCurScope() == nullptr && "A scope is already active?");
- EnterScope(Scope::DeclScope);
+ Actions.EnterScope(Scope::DeclScope);
Actions.ActOnTranslationUnitScope(getCurScope());
// Initialization for Objective-C context sensitive keywords recognition.
@@ -1237,8 +1203,8 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
LateParsedAttrs->empty() && Actions.canDelayFunctionBody(D)) {
MultiTemplateParamsArg TemplateParameterLists(*TemplateInfo.TemplateParams);
- ParseScope BodyScope(this, Scope::FnScope | Scope::DeclScope |
- Scope::CompoundStmtScope);
+ ParseScope BodyScope(Actions, Scope::FnScope | Scope::DeclScope |
+ Scope::CompoundStmtScope);
Scope *ParentScope = getCurScope()->getParent();
D.setFunctionDefinitionKind(FunctionDefinitionKind::Definition);
@@ -1266,8 +1232,8 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
if (CurParsedObjCImpl && !TemplateInfo.TemplateParams &&
(Tok.is(tok::l_brace) || Tok.is(tok::kw_try) || Tok.is(tok::colon)) &&
Actions.CurContext->isTranslationUnit()) {
- ParseScope BodyScope(this, Scope::FnScope | Scope::DeclScope |
- Scope::CompoundStmtScope);
+ ParseScope BodyScope(Actions, Scope::FnScope | Scope::DeclScope |
+ Scope::CompoundStmtScope);
Scope *ParentScope = getCurScope()->getParent();
D.setFunctionDefinitionKind(FunctionDefinitionKind::Definition);
@@ -1285,8 +1251,8 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
}
// Enter a scope for the function body.
- ParseScope BodyScope(this, Scope::FnScope | Scope::DeclScope |
- Scope::CompoundStmtScope);
+ ParseScope BodyScope(Actions, Scope::FnScope | Scope::DeclScope |
+ Scope::CompoundStmtScope);
// Parse function body eagerly if it is either '= delete;' or '= default;' as
// ActOnStartOfFunctionDef needs to know whether the function is deleted.
@@ -1438,8 +1404,9 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) {
// Enter function-declaration scope, limiting any declarators to the
// function prototype scope, including parameter declarators.
- ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope |
- Scope::FunctionDeclarationScope | Scope::DeclScope);
+ ParseScope PrototypeScope(Actions, Scope::FunctionPrototypeScope |
+ Scope::FunctionDeclarationScope |
+ Scope::DeclScope);
// Read all the argument declarations.
while (isDeclarationSpecifier(ImplicitTypenameContext::No)) {
diff --git a/clang/lib/Sema/Scope.cpp b/clang/lib/Sema/Scope.cpp
index 997378f3d8368..44a3a57e7962a 100644
--- a/clang/lib/Sema/Scope.cpp
+++ b/clang/lib/Sema/Scope.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/Scope.h"
+#include "clang/Sema/Sema.h"
#include "clang/AST/Decl.h"
#include "llvm/Support/raw_ostream.h"
@@ -269,3 +270,35 @@ void Scope::dumpImpl(raw_ostream &OS) const {
else
OS << "NRVO is not allowed\n";
}
+
+ParseScope::ParseScope(Sema &S, unsigned ScopeFlags, bool EnteredScope,
+ bool BeforeCompoundStmt)
+ : S(&S) {
+ if (EnteredScope && !BeforeCompoundStmt)
+ S.EnterScope(ScopeFlags);
+ else {
+ if (BeforeCompoundStmt)
+ S.incrementMSManglingNumber();
+
+ this->S = nullptr;
+ }
+}
+
+void ParseScope::Exit() {
+ if (S) {
+ S->ExitScope();
+ S = nullptr;
+ }
+}
+
+void MultiParseScope::Enter(unsigned ScopeFlags) {
+ S.EnterScope(ScopeFlags);
+ ++NumScopes;
+}
+
+void MultiParseScope::Exit() {
+ while (NumScopes) {
+ S.ExitScope();
+ --NumScopes;
+ }
+}
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index fe2d9f9097f18..a0aec04189910 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -621,6 +621,7 @@ Sema::~Sema() {
// Detach from the PP callback handler which outlives Sema since it's owned
// by the preprocessor.
SemaPPCallbackHandler->reset();
+ FreeScopes();
}
void Sema::runWithSufficientStackSpace(SourceLocation Loc,
@@ -2997,3 +2998,34 @@ Attr *Sema::CreateAnnotationAttr(const ParsedAttr &AL) {
return CreateAnnotationAttr(AL, Str, Args);
}
+
+void Sema::EnterScope(unsigned ScopeFlags) {
+ if (!ScopeCache.empty()) {
+ Scope *N = ScopeCache.pop_back_val().release();
+ N->Init(getCurScope(), ScopeFlags);
+ CurScope = N;
+ } else {
+ CurScope = new Scope(getCurScope(), ScopeFlags, Diags);
+ }
+}
+
+void Sema::ExitScope() {
+ assert(getCurScope() && "Scope imbalance!");
+ ActOnPopScope(getCurScope());
+ Scope *OldScope = getCurScope();
+ CurScope = OldScope->getParent();
+ if (ScopeCache.size() == MaxScopeCacheSize)
+ delete OldScope;
+ else
+ ScopeCache.emplace_back(OldScope);
+}
+
+void Sema::FreeScopes() {
+ // Take care not to delete 'CurScope' twice.
+ auto IsCurScope = [&](auto& S) { return S.get() == CurScope; };
+ if (llvm::find_if(ScopeCache, IsCurScope) == ScopeCache.end())
+ delete CurScope;
+
+ ScopeCache.clear();
+ CurScope = nullptr;
+}
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 1d3365cc8d139..d6e91c600845b 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -2270,7 +2270,7 @@ static void CheckPoppedLabel(LabelDecl *L, Sema &S,
<< L);
}
-void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
+void Sema::ActOnPopScope(Scope *S) {
S->applyNRVO();
if (S->decl_empty()) return;
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index b74af55d1bea1..431d5ce39f28d 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -2433,8 +2433,8 @@ void NoteForRangeBeginEndFunction(Sema &SemaRef, Expr *E,
}
/// Build a variable declaration for a for-range statement.
-VarDecl *BuildForRangeVarDecl(Sema &SemaRef, SourceLocation Loc,
- QualType Type, StringRef Name) {
+VarDecl *BuildForRangeVarDecl(Sema &SemaRef, SourceLocation Loc, QualType Type,
+ StringRef Name, bool ForExpansionStmt) {
DeclContext *DC = SemaRef.CurContext;
IdentifierInfo *II = &SemaRef.PP.getIdentifierTable().get(Name);
TypeSourceInfo *TInfo = SemaRef.Context.getTrivialTypeSourceInfo(Type, Loc);
@@ -2444,7 +2444,6 @@ VarDecl *BuildForRangeVarDecl(Sema &SemaRef, SourceLocation Loc,
Decl->setCXXForRangeImplicitVar(true);
return Decl;
}
-
}
static bool ObjCEnumerationCollection(Expr *Collection) {
@@ -2452,6 +2451,25 @@ static bool ObjCEnumerationCollection(Expr *Collection) {
&& Collection->getType()->getAs<ObjCObjectPointerType>() != nullptr;
}
+StmtResult Sema::BuildCXXForRangeRangeVar(Scope *S, Expr *Range, QualType Type,
+ bool Constexpr) {
+
+ // Divide by 2, since the variables are in the inner scope (loop body).
+ const auto DepthStr = std::to_string(S->getDepth() / 2);
+ SourceLocation RangeLoc = Range->getBeginLoc();
+ VarDecl *RangeVar = BuildForRangeVarDecl(
+ *this, RangeLoc, Type, std::string("__range") + DepthStr, Constexpr);
+ if (FinishForRangeVarDecl(*this, RangeVar, Range, RangeLoc,
+ diag::err_for_range_deduction_failure))
+
+ return StmtError();
+
+ // Claim the type doesn't contain auto: we've already done the checking.
+ DeclGroupPtrTy RangeGroup =
+ BuildDeclaratorGroup(MutableArrayRef<Decl *>((Decl **)&RangeVar, 1));
+ return ActOnDeclStmt(RangeGroup, RangeLoc, RangeLoc);
+}
+
StmtResult Sema::ActOnCXXForRangeStmt(
Scope *S, SourceLocation ForLoc, SourceLocation CoawaitLoc, Stmt *InitStmt,
Stmt *First, SourceLocation ColonLoc, Expr *Range, SourceLocation RParenLoc,
@@ -2496,22 +2514,8 @@ StmtResult Sema::ActOnCXXForRangeStmt(
}
// Build auto && __range = range-init
- // Divide by 2, since the variables are in the inner scope (loop body).
- const auto DepthStr = std::to_string(S->getDepth() / 2);
- SourceLocation RangeLoc = Range->getBeginLoc();
- VarDecl *RangeVar = BuildForRangeVarDecl(*this, RangeLoc,
- Context.getAutoRRefDeductType(),
- std::string("__range") + DepthStr);
- if (FinishForRangeVarDecl(*this, RangeVar, Range, RangeLoc,
- diag::err_for_range_deduction_failure)) {
- ActOnInitializerError(LoopVar);
- return StmtError();
- }
-
- // Claim the type doesn't contain auto: we've already done the checking.
- DeclGroupPtrTy RangeGroup =
- BuildDeclaratorGroup(MutableArrayRef<Decl *>((Decl **)&RangeVar, 1));
- StmtResult RangeDecl = ActOnDeclStmt(RangeGroup, RangeLoc, RangeLoc);
+ auto RangeDecl =
+ BuildCXXForRangeRangeVar(S, Range, Context.getAutoRRefDeductType());
if (RangeDecl.isInvalid()) {
ActOnInitializerError(LoopVar);
return StmtError();
@@ -2710,6 +2714,221 @@ static StmtResult RebuildForRangeWithDereference(Sema &SemaRef, Scope *S,
AdjustedRange.get(), RParenLoc, Sema::BFRK_Rebuild);
}
+void Sema::ApplyForRangeOrExpansionStatementLifetimeExtension(
+ VarDecl *RangeVar, ArrayRef<MaterializeTemporaryExpr *> Temporaries) {
+ if (Temporaries.empty())
+ return;
+
+ InitializedEntity Entity = InitializedEntity::InitializeVariable(RangeVar);
+ for (auto *MTE : Temporaries)
+ MTE->setExtendingDecl(RangeVar, Entity.allocateManglingNumber());
+}
+
+Sema::ForRangeBeginEndInfo Sema::BuildCXXForRangeBeginEndVars(
+ Scope *S, VarDecl *RangeVar, SourceLocation ColonLoc,
+ SourceLocation CoawaitLoc,
+ ArrayRef<MaterializeTemporaryExpr *> LifetimeExtendTemps,
+ BuildForRangeKind Kind, bool Constexpr, StmtResult *RebuildResult,
+ llvm::function_ref<StmtResult()> RebuildWithDereference) {
+ QualType RangeVarType = RangeVar->getType();
+ SourceLocation RangeLoc = RangeVar->getLocation();
+ const QualType RangeVarNonRefType = RangeVarType.getNonReferenceType();
+
+ ExprResult BeginRangeRef =
+ BuildDeclRefExpr(RangeVar, RangeVarNonRefType, VK_LValue, ColonLoc);
+ if (BeginRangeRef.isInvalid())
+ return {};
+
+ ExprResult EndRangeRef =
+ BuildDeclRefExpr(RangeVar, RangeVarNonRefType, VK_LValue, ColonLoc);
+ if (EndRangeRef.isInvalid())
+ return {};
+
+ QualType AutoType = Context.getAutoDeductType();
+ Expr *Range = RangeVar->getInit();
+ if (!Range)
+ return {};
+ QualType RangeType = Range->getType();
+
+ if (RequireCompleteType(RangeLoc, RangeType,
+ diag::err_for_range_incomplete_type))
+ return {};
+
+ // Build auto __begin = begin-expr, __end = end-expr.
+ // Divide by 2, since the variables are in the inner scope (loop body).
+ const auto DepthStr = std::to_string(S->getDepth() / 2);
+ VarDecl *BeginVar =
+ BuildForRangeVarDecl(*this, ColonLoc, AutoType,
+ std::string("__begin") + DepthStr, Constexpr);
+ VarDecl *EndVar =
+ BuildForRangeVarDecl(*this, ColonLoc, AutoType,
+ std::string("__end") + DepthStr, Constexpr);
+
+ // Build begin-expr and end-expr and attach to __begin and __end variables.
+ ExprResult BeginExpr, EndExpr;
+ if (const ArrayType *UnqAT = RangeType->getAsArrayTypeUnsafe()) {
+ // - if _RangeT is an array type, begin-expr and end-expr are __range and
+ // __range + __bound, respectively, where __bound is the array bound. If
+ // _RangeT is an array of unknown size or an array of incomplete type,
+ // the program is ill-formed;
+
+ // begin-expr is __range.
+ BeginExpr = BeginRangeRef;
+ if (!CoawaitLoc.isInvalid()) {
+ BeginExpr = ActOnCoawaitExpr(S, ColonLoc, BeginExpr.get());
+ if (BeginExpr.isInvalid())
+ return {};
+ }
+ if (FinishForRangeVarDecl(*this, BeginVar, BeginRangeRef.get(), ColonLoc,
+ diag::err_for_range_iter_deduction_failure)) {
+ NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
+ return {};
+ }
+
+ // Find the array bound.
+ ExprResult BoundExpr;
+ if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(UnqAT))
+ BoundExpr = IntegerLiteral::Create(
+ Context, CAT->getSize(), Context.getPointerDiffType(), RangeLoc);
+ else if (const VariableArrayType *VAT =
+ dyn_cast<VariableArrayType>(UnqAT)) {
+ // For a variably modified type we can't just use the expression within
+ // the array bounds, since we don't want that to be re-evaluated here.
+ // Rather, we need to determine what it was when the array was first
+ // created - so we resort to using sizeof(vla)/sizeof(element).
+ // For e.g.
+ // void f(int b) {
+ // int vla[b];
+ // b = -1; <-- This should not affect the num of iterations below
+ // for (int &c : vla) { .. }
+ // }
+
+ // FIXME: This results in codegen generating IR that recalculates the
+ // run-time number of elements (as opposed to just using the IR Value
+ // that corresponds to the run-time value of each bound that was
+ // generated when the array was created.) If this proves too embarrassing
+ // even for unoptimized IR, consider passing a magic-value/cookie to
+ // codegen that then knows to simply use that initial llvm::Value (that
+ // corresponds to the bound at time of array creation) within
+ // getelementptr. But be prepared to pay the price of increasing a
+ // customized form of coupling between the two components - which could
+ // be hard to maintain as the codebase evolves.
+
+ ExprResult SizeOfVLAExprR = ActOnUnaryExprOrTypeTraitExpr(
+ EndVar->getLocation(), UETT_SizeOf,
+ /*IsType=*/true,
+ CreateParsedType(VAT->desugar(), Context.getTrivialTypeSourceInfo(
+ VAT->desugar(), RangeLoc))
+ .getAsOpaquePtr(),
+ EndVar->getSourceRange());
+ if (SizeOfVLAExprR.isInvalid())
+ return {};
+
+ ExprResult SizeOfEachElementExprR = ActOnUnaryExprOrTypeTraitExpr(
+ EndVar->getLocation(), UETT_SizeOf,
+ /*IsType=*/true,
+ CreateParsedType(VAT->desugar(), Context.getTrivialTypeSourceInfo(
+ VAT->getElementType(), RangeLoc))
+ .getAsOpaquePtr(),
+ EndVar->getSourceRange());
+ if (SizeOfEachElementExprR.isInvalid())
+ return {};
+
+ BoundExpr =
+ ActOnBinOp(S, EndVar->getLocation(), tok::slash, SizeOfVLAExprR.get(),
+ SizeOfEachElementExprR.get());
+ if (BoundExpr.isInvalid())
+ return {};
+
+ } else {
+ // Can't be a DependentSizedArrayType or an IncompleteArrayType since
+ // UnqAT is not incomplete and Range is not type-dependent.
+ llvm_unreachable("Unexpected array type in for-range");
+ }
+
+ // end-expr is __range + __bound.
+ EndExpr =
+ ActOnBinOp(S, ColonLoc, tok::plus, EndRangeRef.get(), BoundExpr.get());
+ if (EndExpr.isInvalid())
+ return {};
+ if (FinishForRangeVarDecl(*this, EndVar, EndExpr.get(), ColonLoc,
+ diag::err_for_range_iter_deduction_failure)) {
+ NoteForRangeBeginEndFunction(*this, EndExpr.get(), BEF_end);
+ return {};
+ }
+ } else {
+ OverloadCandidateSet CandidateSet(RangeLoc,
+ OverloadCandidateSet::CSK_Normal);
+ BeginEndFunction BEFFailure;
+ ForRangeStatus RangeStatus =
+ BuildNonArrayForRange(*this, BeginRangeRef.get(), EndRangeRef.get(),
+ RangeType, BeginVar, EndVar, ColonLoc, CoawaitLoc,
+ &CandidateSet, &BeginExpr, &EndExpr, &BEFFailure);
+
+ if (Kind == BFRK_Build && RangeStatus == FRS_NoViableFunction &&
+ BEFFailure == BEF_begin) {
+ // If the range is being built from an array parameter, emit a
+ // a diagnostic that it is being treated as a pointer.
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Range)) {
+ if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) {
+ QualType ArrayTy = PVD->getOriginalType();
+ QualType PointerTy = PVD->getType();
+ if (PointerTy->isPointerType() && ArrayTy->isArrayType()) {
+ Diag(Range->getBeginLoc(), diag::err_range_on_array_parameter)
+ << RangeLoc << PVD << ArrayTy << PointerTy;
+ Diag(PVD->getLocation(), diag::note_declared_at);
+ return {};
+ }
+ }
+ }
+
+ // If building the range failed, try dereferencing the range expression
+ // unless a diagnostic was issued or the end function is problematic.
+ if (RebuildWithDereference) {
+ assert(RebuildResult);
+ StmtResult SR = RebuildWithDereference();
+ if (SR.isInvalid() || SR.isUsable()) {
+ *RebuildResult = SR;
+ return {};
+ }
+ }
+ }
+
+ // Otherwise, emit diagnostics if we haven't already.
+ if (RangeStatus == FRS_NoViableFunction) {
+ Expr *Range = BEFFailure ? EndRangeRef.get() : BeginRangeRef.get();
+ CandidateSet.NoteCandidates(
+ PartialDiagnosticAt(Range->getBeginLoc(),
+ PDiag(diag::err_for_range_invalid)
+ << RangeLoc << Range->getType()
+ << BEFFailure),
+ *this, OCD_AllCandidates, Range);
+ }
+ // Return an error if no fix was discovered.
+ if (RangeStatus != FRS_Success)
+ return {};
+ }
+
+ assert(!BeginExpr.isInvalid() && !EndExpr.isInvalid() &&
+ "invalid range expression in for loop");
+
+ return {BeginVar, EndVar, BeginExpr.get(), EndExpr.get()};
+}
+
+void Sema::ActOnDependentForRangeInitializer(VarDecl *LoopVar,
+ BuildForRangeKind BFRK) {
+ // Deduce any 'auto's in the loop variable as 'DependentTy'. We'll fill
+ // them in properly when we instantiate the loop.
+ if (!LoopVar->isInvalidDecl() && BFRK != BFRK_Check) {
+ if (auto *DD = dyn_cast<DecompositionDecl>(LoopVar))
+ for (auto *Binding : DD->bindings()) {
+ if (!Binding->isParameterPack())
+ Binding->setType(Context.DependentTy);
+ }
+ LoopVar->setType(SubstAutoTypeDependent(LoopVar->getType()));
+ }
+}
+
StmtResult Sema::BuildCXXForRangeStmt(
SourceLocation ForLoc, SourceLocation CoawaitLoc, Stmt *InitStmt,
SourceLocation ColonLoc, Stmt *RangeDecl, Stmt *Begin, Stmt *End,
@@ -2741,208 +2960,36 @@ StmtResult Sema::BuildCXXForRangeStmt(
if (RangeVarType->isDependentType()) {
// The range is implicitly used as a placeholder when it is dependent.
RangeVar->markUsed(Context);
-
- // Deduce any 'auto's in the loop variable as 'DependentTy'. We'll fill
- // them in properly when we instantiate the loop.
- if (!LoopVar->isInvalidDecl() && Kind != BFRK_Check) {
- if (auto *DD = dyn_cast<DecompositionDecl>(LoopVar))
- for (auto *Binding : DD->bindings()) {
- if (!Binding->isParameterPack())
- Binding->setType(Context.DependentTy);
- }
- LoopVar->setType(SubstAutoTypeDependent(LoopVar->getType()));
- }
+ ActOnDependentForRangeInitializer(LoopVar, Kind);
} else if (!BeginDeclStmt.get()) {
- SourceLocation RangeLoc = RangeVar->getLocation();
-
- const QualType RangeVarNonRefType = RangeVarType.getNonReferenceType();
-
- ExprResult BeginRangeRef = BuildDeclRefExpr(RangeVar, RangeVarNonRefType,
- VK_LValue, ColonLoc);
- if (BeginRangeRef.isInvalid())
- return StmtError();
-
- ExprResult EndRangeRef = BuildDeclRefExpr(RangeVar, RangeVarNonRefType,
- VK_LValue, ColonLoc);
- if (EndRangeRef.isInvalid())
- return StmtError();
+ StmtResult RebuildResult;
+ auto RebuildWithDereference = [&] {
+ return RebuildForRangeWithDereference(
+ *this, S, ForLoc, CoawaitLoc, InitStmt, LoopVarDecl, ColonLoc,
+ RangeVar->getInit(), RangeVar->getLocation(), RParenLoc);
+ };
- QualType AutoType = Context.getAutoDeductType();
- Expr *Range = RangeVar->getInit();
- if (!Range)
- return StmtError();
- QualType RangeType = Range->getType();
+ auto BeginRangeRefTy = RangeVar->getType().getNonReferenceType();
+ auto [BeginVar, EndVar, BeginExpr, EndExpr] = BuildCXXForRangeBeginEndVars(
+ S, RangeVar, ColonLoc, CoawaitLoc, LifetimeExtendTemps, Kind,
+ /*Constexpr=*/false, &RebuildResult, RebuildWithDereference);
- if (RequireCompleteType(RangeLoc, RangeType,
- diag::err_for_range_incomplete_type))
+ if (!RebuildResult.isUnset())
+ return RebuildResult;
+ if (!BeginVar || !EndVar)
return StmtError();
- // Build auto __begin = begin-expr, __end = end-expr.
- // Divide by 2, since the variables are in the inner scope (loop body).
- const auto DepthStr = std::to_string(S->getDepth() / 2);
- VarDecl *BeginVar = BuildForRangeVarDecl(*this, ColonLoc, AutoType,
- std::string("__begin") + DepthStr);
- VarDecl *EndVar = BuildForRangeVarDecl(*this, ColonLoc, AutoType,
- std::string("__end") + DepthStr);
-
- // Build begin-expr and end-expr and attach to __begin and __end variables.
- ExprResult BeginExpr, EndExpr;
- if (const ArrayType *UnqAT = RangeType->getAsArrayTypeUnsafe()) {
- // - if _RangeT is an array type, begin-expr and end-expr are __range and
- // __range + __bound, respectively, where __bound is the array bound. If
- // _RangeT is an array of unknown size or an array of incomplete type,
- // the program is ill-formed;
-
- // begin-expr is __range.
- BeginExpr = BeginRangeRef;
- if (!CoawaitLoc.isInvalid()) {
- BeginExpr = ActOnCoawaitExpr(S, ColonLoc, BeginExpr.get());
- if (BeginExpr.isInvalid())
- return StmtError();
- }
- if (FinishForRangeVarDecl(*this, BeginVar, BeginRangeRef.get(), ColonLoc,
- diag::err_for_range_iter_deduction_failure)) {
- NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
- return StmtError();
- }
-
- // Find the array bound.
- ExprResult BoundExpr;
- if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(UnqAT))
- BoundExpr = IntegerLiteral::Create(
- Context, CAT->getSize(), Context.getPointerDiffType(), RangeLoc);
- else if (const VariableArrayType *VAT =
- dyn_cast<VariableArrayType>(UnqAT)) {
- // For a variably modified type we can't just use the expression within
- // the array bounds, since we don't want that to be re-evaluated here.
- // Rather, we need to determine what it was when the array was first
- // created - so we resort to using sizeof(vla)/sizeof(element).
- // For e.g.
- // void f(int b) {
- // int vla[b];
- // b = -1; <-- This should not affect the num of iterations below
- // for (int &c : vla) { .. }
- // }
-
- // FIXME: This results in codegen generating IR that recalculates the
- // run-time number of elements (as opposed to just using the IR Value
- // that corresponds to the run-time value of each bound that was
- // generated when the array was created.) If this proves too embarrassing
- // even for unoptimized IR, consider passing a magic-value/cookie to
- // codegen that then knows to simply use that initial llvm::Value (that
- // corresponds to the bound at time of array creation) within
- // getelementptr. But be prepared to pay the price of increasing a
- // customized form of coupling between the two components - which could
- // be hard to maintain as the codebase evolves.
-
- ExprResult SizeOfVLAExprR = ActOnUnaryExprOrTypeTraitExpr(
- EndVar->getLocation(), UETT_SizeOf,
- /*IsType=*/true,
- CreateParsedType(VAT->desugar(), Context.getTrivialTypeSourceInfo(
- VAT->desugar(), RangeLoc))
- .getAsOpaquePtr(),
- EndVar->getSourceRange());
- if (SizeOfVLAExprR.isInvalid())
- return StmtError();
-
- ExprResult SizeOfEachElementExprR = ActOnUnaryExprOrTypeTraitExpr(
- EndVar->getLocation(), UETT_SizeOf,
- /*IsType=*/true,
- CreateParsedType(VAT->desugar(),
- Context.getTrivialTypeSourceInfo(
- VAT->getElementType(), RangeLoc))
- .getAsOpaquePtr(),
- EndVar->getSourceRange());
- if (SizeOfEachElementExprR.isInvalid())
- return StmtError();
-
- BoundExpr =
- ActOnBinOp(S, EndVar->getLocation(), tok::slash,
- SizeOfVLAExprR.get(), SizeOfEachElementExprR.get());
- if (BoundExpr.isInvalid())
- return StmtError();
-
- } else {
- // Can't be a DependentSizedArrayType or an IncompleteArrayType since
- // UnqAT is not incomplete and Range is not type-dependent.
- llvm_unreachable("Unexpected array type in for-range");
- }
-
- // end-expr is __range + __bound.
- EndExpr = ActOnBinOp(S, ColonLoc, tok::plus, EndRangeRef.get(),
- BoundExpr.get());
- if (EndExpr.isInvalid())
- return StmtError();
- if (FinishForRangeVarDecl(*this, EndVar, EndExpr.get(), ColonLoc,
- diag::err_for_range_iter_deduction_failure)) {
- NoteForRangeBeginEndFunction(*this, EndExpr.get(), BEF_end);
- return StmtError();
- }
- } else {
- OverloadCandidateSet CandidateSet(RangeLoc,
- OverloadCandidateSet::CSK_Normal);
- BeginEndFunction BEFFailure;
- ForRangeStatus RangeStatus = BuildNonArrayForRange(
- *this, BeginRangeRef.get(), EndRangeRef.get(), RangeType, BeginVar,
- EndVar, ColonLoc, CoawaitLoc, &CandidateSet, &BeginExpr, &EndExpr,
- &BEFFailure);
-
- if (Kind == BFRK_Build && RangeStatus == FRS_NoViableFunction &&
- BEFFailure == BEF_begin) {
- // If the range is being built from an array parameter, emit a
- // a diagnostic that it is being treated as a pointer.
- if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Range)) {
- if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) {
- QualType ArrayTy = PVD->getOriginalType();
- QualType PointerTy = PVD->getType();
- if (PointerTy->isPointerType() && ArrayTy->isArrayType()) {
- Diag(Range->getBeginLoc(), diag::err_range_on_array_parameter)
- << RangeLoc << PVD << ArrayTy << PointerTy;
- Diag(PVD->getLocation(), diag::note_declared_at);
- return StmtError();
- }
- }
- }
-
- // If building the range failed, try dereferencing the range expression
- // unless a diagnostic was issued or the end function is problematic.
- StmtResult SR = RebuildForRangeWithDereference(*this, S, ForLoc,
- CoawaitLoc, InitStmt,
- LoopVarDecl, ColonLoc,
- Range, RangeLoc,
- RParenLoc);
- if (SR.isInvalid() || SR.isUsable())
- return SR;
- }
-
- // Otherwise, emit diagnostics if we haven't already.
- if (RangeStatus == FRS_NoViableFunction) {
- Expr *Range = BEFFailure ? EndRangeRef.get() : BeginRangeRef.get();
- CandidateSet.NoteCandidates(
- PartialDiagnosticAt(Range->getBeginLoc(),
- PDiag(diag::err_for_range_invalid)
- << RangeLoc << Range->getType()
- << BEFFailure),
- *this, OCD_AllCandidates, Range);
- }
- // Return an error if no fix was discovered.
- if (RangeStatus != FRS_Success)
- return StmtError();
- }
-
- assert(!BeginExpr.isInvalid() && !EndExpr.isInvalid() &&
- "invalid range expression in for loop");
-
// C++11 [dcl.spec.auto]p7: BeginType and EndType must be the same.
// C++1z removes this restriction.
+ SourceLocation RangeLoc = RangeVar->getLocation();
QualType BeginType = BeginVar->getType(), EndType = EndVar->getType();
if (!Context.hasSameType(BeginType, EndType)) {
Diag(RangeLoc, getLangOpts().CPlusPlus17
? diag::warn_for_range_begin_end_types_differ
: diag::ext_for_range_begin_end_types_differ)
<< BeginType << EndType;
- NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
- NoteForRangeBeginEndFunction(*this, EndExpr.get(), BEF_end);
+ NoteForRangeBeginEndFunction(*this, BeginExpr, BEF_begin);
+ NoteForRangeBeginEndFunction(*this, EndExpr, BEF_end);
}
BeginDeclStmt =
@@ -2971,10 +3018,10 @@ StmtResult Sema::BuildCXXForRangeStmt(
ActOnFinishFullExpr(NotEqExpr.get(), /*DiscardedValue*/ false);
if (NotEqExpr.isInvalid()) {
Diag(RangeLoc, diag::note_for_range_invalid_iterator)
- << RangeLoc << 0 << BeginRangeRef.get()->getType();
- NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
+ << RangeLoc << 0 << BeginRangeRefTy;
+ NoteForRangeBeginEndFunction(*this, BeginExpr, BEF_begin);
if (!Context.hasSameType(BeginType, EndType))
- NoteForRangeBeginEndFunction(*this, EndExpr.get(), BEF_end);
+ NoteForRangeBeginEndFunction(*this, EndExpr, BEF_end);
return StmtError();
}
@@ -2994,8 +3041,8 @@ StmtResult Sema::BuildCXXForRangeStmt(
IncrExpr = ActOnFinishFullExpr(IncrExpr.get(), /*DiscardedValue*/ false);
if (IncrExpr.isInvalid()) {
Diag(RangeLoc, diag::note_for_range_invalid_iterator)
- << RangeLoc << 2 << BeginRangeRef.get()->getType() ;
- NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
+ << RangeLoc << 2 << BeginRangeRefTy;
+ NoteForRangeBeginEndFunction(*this, BeginExpr, BEF_begin);
return StmtError();
}
@@ -3008,8 +3055,8 @@ StmtResult Sema::BuildCXXForRangeStmt(
ExprResult DerefExpr = ActOnUnaryOp(S, ColonLoc, tok::star, BeginRef.get());
if (DerefExpr.isInvalid()) {
Diag(RangeLoc, diag::note_for_range_invalid_iterator)
- << RangeLoc << 1 << BeginRangeRef.get()->getType();
- NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
+ << RangeLoc << 1 << BeginRangeRefTy;
+ NoteForRangeBeginEndFunction(*this, BeginExpr, BEF_begin);
return StmtError();
}
@@ -3019,7 +3066,7 @@ StmtResult Sema::BuildCXXForRangeStmt(
AddInitializerToDecl(LoopVar, DerefExpr.get(), /*DirectInit=*/false);
if (LoopVar->isInvalidDecl() ||
(LoopVar->getInit() && LoopVar->getInit()->containsErrors()))
- NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
+ NoteForRangeBeginEndFunction(*this, BeginExpr, BEF_begin);
}
}
@@ -3034,11 +3081,9 @@ StmtResult Sema::BuildCXXForRangeStmt(
OpenMP().ActOnOpenMPLoopInitialization(ForLoc, BeginDeclStmt.get());
// P2718R0 - Lifetime extension in range-based for loops.
- if (getLangOpts().CPlusPlus23 && !LifetimeExtendTemps.empty()) {
- InitializedEntity Entity = InitializedEntity::InitializeVariable(RangeVar);
- for (auto *MTE : LifetimeExtendTemps)
- MTE->setExtendingDecl(RangeVar, Entity.allocateManglingNumber());
- }
+ if (getLangOpts().CPlusPlus23)
+ ApplyForRangeOrExpansionStatementLifetimeExtension(RangeVar,
+ LifetimeExtendTemps);
return new (Context) CXXForRangeStmt(
InitStmt, RangeDS, cast_or_null<DeclStmt>(BeginDeclStmt.get()),
More information about the llvm-branch-commits
mailing list