AntonBikineev updated this revision to Diff 63056.
AntonBikineev added a comment.
@rsmith,
I've added some tests for c++1z init statement. Please let me know if there is
anything else I should add or change.
http://reviews.llvm.org/D21834
Files:
include/clang/AST/Stmt.h
include/clang/Sema/Sema.h
lib/AST/ASTImporter.cpp
lib/AST/ExprConstant.cpp
lib/AST/Stmt.cpp
lib/Analysis/BodyFarm.cpp
lib/Analysis/CFG.cpp
lib/CodeGen/CGStmt.cpp
lib/Sema/JumpDiagnostics.cpp
lib/Sema/SemaStmt.cpp
lib/Sema/TreeTransform.h
lib/Serialization/ASTReaderStmt.cpp
lib/Serialization/ASTWriterStmt.cpp
test/CodeGenCXX/cxx1z-init-statement.cpp
test/PCH/cxx1z-init-statement.cpp
test/PCH/cxx1z-init-statement.h
test/Parser/cxx1z-init-statement.cpp
test/SemaCXX/cxx1z-init-statement-warn-unused.cpp
test/SemaCXX/cxx1z-init-statement.cpp
Index: test/SemaCXX/cxx1z-init-statement.cpp
===================================================================
--- test/SemaCXX/cxx1z-init-statement.cpp
+++ test/SemaCXX/cxx1z-init-statement.cpp
@@ -0,0 +1,91 @@
+// RUN: %clang_cc1 -std=c++1z -verify %s
+
+void testIf() {
+ int x = 0;
+ if (x; x) ++x;
+ if (int t = 0; t) ++t; else --t;
+
+ if (int x, y = 0; y) // expected-note 2 {{previous definition is here}}
+ int x = 0; // expected-error {{redefinition of 'x'}}
+ else
+ int x = 0; // expected-error {{redefinition of 'x'}}
+
+ if (x; int a = 0) ++a;
+ if (x, +x; int a = 0) // expected-note 2 {{previous definition is here}} expected-warning {{unused}}
+ int a = 0; // expected-error {{redefinition of 'a'}}
+ else
+ int a = 0; // expected-error {{redefinition of 'a'}}
+
+ if (int b = 0; b)
+ ;
+ b = 2; // expected-error {{use of undeclared identifier}}
+}
+
+void testSwitch() {
+ int x = 0;
+ switch (x; x) {
+ case 1:
+ ++x;
+ }
+
+ switch (int x, y = 0; y) {
+ case 1:
+ ++x;
+ default:
+ ++y;
+ }
+
+ switch (int x, y = 0; y) { // expected-note 2 {{previous definition is here}}
+ case 0:
+ int x = 0; // expected-error {{redefinition of 'x'}}
+ case 1:
+ int y = 0; // expected-error {{redefinition of 'y'}}
+ };
+
+ switch (x; int a = 0) {
+ case 0:
+ ++a;
+ }
+
+ switch (x, +x; int a = 0) { // expected-note {{previous definition is here}} expected-warning {{unused}}
+ case 0:
+ int a = 0; // expected-error {{redefinition of 'a'}} // expected-note {{previous definition is here}}
+ case 1:
+ int a = 0; // expected-error {{redefinition of 'a'}}
+ }
+
+ switch (int b = 0; b) {
+ case 0:
+ break;
+ }
+ b = 2; // expected-error {{use of undeclared identifier}}
+}
+
+constexpr bool constexpr_if_init(int n) {
+ if (int a = n; ++a > 0)
+ return true;
+ else
+ return false;
+}
+
+constexpr int constexpr_switch_init(int n) {
+ switch (int p = n + 2; p) {
+ case 0:
+ return 0;
+ case 1:
+ return 1;
+ default:
+ return -1;
+ }
+}
+
+void test_constexpr_init_stmt() {
+ constexpr bool a = constexpr_if_init(-2);
+ static_assert(!a, "");
+ static_assert(constexpr_if_init(1), "");
+
+ constexpr int b = constexpr_switch_init(-1);
+ static_assert(b == 1, "");
+ static_assert(constexpr_switch_init(-2) == 0, "");
+ static_assert(constexpr_switch_init(-5) == -1, "");
+}
Index: test/SemaCXX/cxx1z-init-statement-warn-unused.cpp
===================================================================
--- test/SemaCXX/cxx1z-init-statement-warn-unused.cpp
+++ test/SemaCXX/cxx1z-init-statement-warn-unused.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -std=c++1z -verify -Wuninitialized %s
+
+void testIf() {
+ if (bool b; b) // expected-warning {{uninitialized}} expected-note {{to silence}}
+ ;
+ if (int a, b = 2; a) // expected-warning {{uninitialized}} expected-note {{to silence}}
+ ;
+}
+
+void testSwitch() {
+ switch (bool b; b) { // expected-warning {{uninitialized}} expected-warning {{boolean value}} expected-note {{to silence}}
+ case 0:
+ break;
+ }
+ switch (int a, b = 7; a) { // expected-warning {{uninitialized}} expected-note {{to silence}}
+ case 0:
+ break;
+ }
+}
Index: test/Parser/cxx1z-init-statement.cpp
===================================================================
--- test/Parser/cxx1z-init-statement.cpp
+++ test/Parser/cxx1z-init-statement.cpp
@@ -4,17 +4,17 @@
typedef int T;
int f() {
// init-statement declarations
- if (T n = 0; n != 0) {} // expected-error {{not yet supported}}
- if (T f(); f()) {} // expected-error {{not yet supported}}
- if (T(f()); f()) {} // expected-error {{not yet supported}}
- if (T(f()), g, h; f()) {} // expected-error {{not yet supported}}
- if (T f(); f()) {} // expected-error {{not yet supported}}
- if (T f(), g, h; f()) {} // expected-error {{not yet supported}}
+ if (T n = 0; n != 0) {}
+ if (T f(); f()) {}
+ if (T(f()); f()) {}
+ if (T(f()), g, h; f()) {}
+ if (T f(); f()) {}
+ if (T f(), g, h; f()) {}
// init-statement expressions
- if (T{f()}; f()) {} // expected-error {{not yet supported}}
- if (T{f()}, g, h; f()) {} // expected-error {{not yet supported}} expected-warning 2{{unused}}
- if (T(f()), g, h + 1; f()) {} // expected-error {{not yet supported}} expected-warning 2{{unused}}
+ if (T{f()}; f()) {}
+ if (T{f()}, g, h; f()) {} // expected-warning 2{{unused}}
+ if (T(f()), g, h + 1; f()) {} // expected-warning 2{{unused}}
// condition declarations
if (T(n){g}) {}
@@ -32,10 +32,10 @@
//if (T(n)(g)) {} // expected-err-FIXME {{not a function}}
// Likewise for 'switch'
- switch (int n; n) {} // expected-error {{not yet supported}}
- switch (g; int g = 5) {} // expected-error {{not yet supported}}
+ switch (int n; n) {}
+ switch (g; int g = 5) {}
- if (int a, b; int c = a) { // expected-error {{not yet supported}} expected-note 6{{previous}}
+ if (int a, b; int c = a) { // expected-note 6{{previous}}
int a; // expected-error {{redefinition}}
int b; // expected-error {{redefinition}}
int c; // expected-error {{redefinition}}
@@ -44,4 +44,6 @@
int b; // expected-error {{redefinition}}
int c; // expected-error {{redefinition}}
}
+
+ return 0;
}
Index: test/PCH/cxx1z-init-statement.h
===================================================================
--- test/PCH/cxx1z-init-statement.h
+++ test/PCH/cxx1z-init-statement.h
@@ -0,0 +1,59 @@
+// Header for PCH test cxx1z-init-statement.cpp
+
+void f0(int x) {
+ // NullStmt
+ ;
+ // IfStmt
+ if (int a = x; a) {
+ } else if (+a; x + 1) {
+ }
+
+ switch (int a = x; x) {
+ case 0:
+ a = 17;
+ break;
+
+ case 1:
+ break;
+
+ default:
+ switch (x >> 1; x) {
+ case 7:
+ // fall through
+ case 9:
+ break;
+ }
+ a += 2;
+ break;
+ }
+
+ while (x > 20) {
+ if (x > 30; x < 30) {
+ --x;
+ continue;
+ } else if (int b = x; b < 5)
+ break;
+ else
+ goto done;
+ }
+
+ done:
+ x = x + 2;
+
+ int z = x, *y, j = 5;
+}
+
+int f1(int x) {
+ switch (int b = x; b) {
+ case 17:
+ return 12;
+
+ default:
+ break;
+ }
+
+ // variable-length array
+ int array[x * 17 + 3];
+
+ return x*2;
+}
Index: test/PCH/cxx1z-init-statement.cpp
===================================================================
--- test/PCH/cxx1z-init-statement.cpp
+++ test/PCH/cxx1z-init-statement.cpp
@@ -0,0 +1,9 @@
+// Test this without pch.
+// RUN: %clang_cc1 -std=c++1z -include %S/cxx1z-init-statement.h -fsyntax-only -emit-llvm -o - %s
+
+// Test with pch.
+// RUN: %clang_cc1 -std=c++1z -emit-pch -o %t %S/cxx1z-init-statement.h
+// RUN: %clang_cc1 -std=c++1z -include-pch %t -fsyntax-only -emit-llvm -o - %s
+
+void g0(void) { f0(5); }
+int g1(int x) { return f1(x); }
Index: test/CodeGenCXX/cxx1z-init-statement.cpp
===================================================================
--- test/CodeGenCXX/cxx1z-init-statement.cpp
+++ test/CodeGenCXX/cxx1z-init-statement.cpp
@@ -0,0 +1,70 @@
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-macosx10.7.0 -emit-llvm -o - %s -w | FileCheck %s
+
+typedef int T;
+void f() {
+ // CHECK: %1 = alloca i32, align 4
+ // CHECK-NEXT: store i32 5, i32* %1, align 4
+ // CHECK-NEXT: %2 = load i32, i32* %1, align 4
+ // CHECK-NEXT %3 = icmp slt i32 %2, 8
+ if (int a = 5; a < 8)
+ ;
+}
+
+void f1() {
+ // CHECK: %1 = alloca i32, align 4
+ // CHECK-NEXT: %2 = alloca i32, align 4
+ // CHECK-NEXT: %3 = alloca i32, align 4
+ // CHECK-NEXT: store i32 5, i32* %2, align 4
+ // CHECK-NEXT: store i32 7, i32* %3, align 4
+ if (int a, b = 5; int c = 7)
+ ;
+}
+
+int f2() {
+ // CHECK: %1 = alloca i32, align 4
+ // CHECK-NEXT: %2 = call i32 @_Z2f2v()
+ // CHECK-NEXT: store i32 7, i32* %1, align 4
+ // CHECK-NEXT: %3 = load i32, i32* %1, align 4
+ // CHECK-NEXT: %4 = icmp ne i32 %3, 0
+ if (T{f2()}; int c = 7)
+ ;
+ return 2;
+}
+
+void g() {
+ // CHECK: %1 = alloca i32, align 4
+ // CHECK-NEXT: store i32 5, i32* %1, align 4
+ // CHECK-NEXT: %2 = load i32, i32* %1, align 4
+ // CHECK-NEXT: switch i32 %2, label %4 [
+ switch (int a = 5; a) {
+ case 0:
+ break;
+ }
+}
+
+void g1() {
+ // CHECK: %1 = alloca i32, align 4
+ // CHECK-NEXT: %2 = alloca i32, align 4
+ // CHECK-NEXT: %3 = alloca i32, align 4
+ // CHECK-NEXT: store i32 5, i32* %2, align 4
+ // CHECK-NEXT: store i32 7, i32* %3, align 4
+ // CHECK-NEXT: %4 = load i32, i32* %3, align 4
+ // CHECK-NEXT: switch i32 %4, label %6 [
+ switch (int a, b = 5; int c = 7) {
+ case 0:
+ break;
+ }
+}
+
+int g2() {
+ // CHECK: %1 = alloca i32, align 4
+ // CHECK-NEXT: %2 = call i32 @_Z2f2v()
+ // CHECK-NEXT: store i32 7, i32* %1, align 4
+ // CHECK-NEXT: %3 = load i32, i32* %1, align 4
+ // CHECK-NEXT: switch i32 %3, label %5 [
+ switch (T{f2()}; int c = 7) {
+ case 0:
+ break;
+ }
+ return 2;
+}
Index: lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- lib/Serialization/ASTWriterStmt.cpp
+++ lib/Serialization/ASTWriterStmt.cpp
@@ -129,6 +129,7 @@
void ASTStmtWriter::VisitIfStmt(IfStmt *S) {
VisitStmt(S);
Record.push_back(S->isConstexpr());
+ Record.AddStmt(S->getInit());
Record.AddDeclRef(S->getConditionVariable());
Record.AddStmt(S->getCond());
Record.AddStmt(S->getThen());
@@ -140,6 +141,7 @@
void ASTStmtWriter::VisitSwitchStmt(SwitchStmt *S) {
VisitStmt(S);
+ Record.AddStmt(S->getInit());
Record.AddDeclRef(S->getConditionVariable());
Record.AddStmt(S->getCond());
Record.AddStmt(S->getBody());
Index: lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- lib/Serialization/ASTReaderStmt.cpp
+++ lib/Serialization/ASTReaderStmt.cpp
@@ -185,6 +185,7 @@
void ASTStmtReader::VisitIfStmt(IfStmt *S) {
VisitStmt(S);
S->setConstexpr(Record[Idx++]);
+ S->setInit(Reader.ReadSubStmt());
S->setConditionVariable(Reader.getContext(),
ReadDeclAs<VarDecl>(Record, Idx));
S->setCond(Reader.ReadSubExpr());
@@ -196,6 +197,7 @@
void ASTStmtReader::VisitSwitchStmt(SwitchStmt *S) {
VisitStmt(S);
+ S->setInit(Reader.ReadSubStmt());
S->setConditionVariable(Reader.getContext(),
ReadDeclAs<VarDecl>(Record, Idx));
S->setCond(Reader.ReadSubExpr());
Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h
+++ lib/Sema/TreeTransform.h
@@ -1174,9 +1174,9 @@
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
StmtResult RebuildIfStmt(SourceLocation IfLoc, bool IsConstexpr,
- Sema::ConditionResult Cond, Stmt *Then,
+ Sema::ConditionResult Cond, Stmt *Init, Stmt *Then,
SourceLocation ElseLoc, Stmt *Else) {
- return getSema().ActOnIfStmt(IfLoc, IsConstexpr, nullptr, Cond, Then,
+ return getSema().ActOnIfStmt(IfLoc, IsConstexpr, Init, Cond, Then,
ElseLoc, Else);
}
@@ -1185,8 +1185,9 @@
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
StmtResult RebuildSwitchStmtStart(SourceLocation SwitchLoc,
+ Stmt *Init,
Sema::ConditionResult Cond) {
- return getSema().ActOnStartOfSwitchStmt(SwitchLoc, nullptr, Cond);
+ return getSema().ActOnStartOfSwitchStmt(SwitchLoc, Init, Cond);
}
/// \brief Attach the body to the switch statement.
@@ -6236,6 +6237,11 @@
template<typename Derived>
StmtResult
TreeTransform<Derived>::TransformIfStmt(IfStmt *S) {
+ // Transform the initialization statement
+ StmtResult Init = getDerived().TransformStmt(S->getInit());
+ if (Init.isInvalid())
+ return StmtError();
+
// Transform the condition
Sema::ConditionResult Cond = getDerived().TransformCondition(
S->getIfLoc(), S->getConditionVariable(), S->getCond(),
@@ -6268,6 +6274,7 @@
}
if (!getDerived().AlwaysRebuild() &&
+ Init.get() == S->getInit() &&
Cond.get() == std::make_pair(S->getConditionVariable(), S->getCond()) &&
Then.get() == S->getThen() &&
Else.get() == S->getElse())
@@ -6274,12 +6281,17 @@
return S;
return getDerived().RebuildIfStmt(S->getIfLoc(), S->isConstexpr(), Cond,
- Then.get(), S->getElseLoc(), Else.get());
+ Init.get(), Then.get(), S->getElseLoc(), Else.get());
}
template<typename Derived>
StmtResult
TreeTransform<Derived>::TransformSwitchStmt(SwitchStmt *S) {
+ // Transform the initialization statement
+ StmtResult Init = getDerived().TransformStmt(S->getInit());
+ if (Init.isInvalid())
+ return StmtError();
+
// Transform the condition.
Sema::ConditionResult Cond = getDerived().TransformCondition(
S->getSwitchLoc(), S->getConditionVariable(), S->getCond(),
@@ -6289,7 +6301,8 @@
// Rebuild the switch statement.
StmtResult Switch
- = getDerived().RebuildSwitchStmtStart(S->getSwitchLoc(), Cond);
+ = getDerived().RebuildSwitchStmtStart(S->getSwitchLoc(),
+ S->getInit(), Cond);
if (Switch.isInvalid())
return StmtError();
Index: lib/Sema/SemaStmt.cpp
===================================================================
--- lib/Sema/SemaStmt.cpp
+++ lib/Sema/SemaStmt.cpp
@@ -508,9 +508,6 @@
ConditionResult Cond,
Stmt *thenStmt, SourceLocation ElseLoc,
Stmt *elseStmt) {
- if (InitStmt)
- Diag(InitStmt->getLocStart(), diag::err_init_stmt_not_supported);
-
if (Cond.isInvalid())
Cond = ConditionResult(
*this, nullptr,
@@ -528,10 +525,10 @@
DiagnoseEmptyStmtBody(CondExpr->getLocEnd(), thenStmt,
diag::warn_empty_if_body);
- return BuildIfStmt(IfLoc, IsConstexpr, Cond, thenStmt, ElseLoc, elseStmt);
+ return BuildIfStmt(IfLoc, IsConstexpr, InitStmt, Cond, thenStmt, ElseLoc, elseStmt);
}
-StmtResult Sema::BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr,
+StmtResult Sema::BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr, Stmt *InitStmt,
ConditionResult Cond, Stmt *thenStmt,
SourceLocation ElseLoc, Stmt *elseStmt) {
if (Cond.isInvalid())
@@ -543,7 +540,7 @@
DiagnoseUnusedExprResult(thenStmt);
DiagnoseUnusedExprResult(elseStmt);
- return new (Context) IfStmt(Context, IfLoc, IsConstexpr, Cond.get().first,
+ return new (Context) IfStmt(Context, IfLoc, IsConstexpr, InitStmt, Cond.get().first,
Cond.get().second, thenStmt, ElseLoc, elseStmt);
}
@@ -668,13 +665,10 @@
if (Cond.isInvalid())
return StmtError();
- if (InitStmt)
- Diag(InitStmt->getLocStart(), diag::err_init_stmt_not_supported);
-
getCurFunction()->setHasBranchIntoScope();
SwitchStmt *SS =
- new (Context) SwitchStmt(Context, Cond.get().first, Cond.get().second);
+ new (Context) SwitchStmt(Context, InitStmt, Cond.get().first, Cond.get().second);
getCurFunction()->SwitchStack.push_back(SS);
return SS;
}
Index: lib/Sema/JumpDiagnostics.cpp
===================================================================
--- lib/Sema/JumpDiagnostics.cpp
+++ lib/Sema/JumpDiagnostics.cpp
@@ -279,7 +279,7 @@
unsigned &ParentScope = ((isa<Expr>(S) && !isa<StmtExpr>(S))
? origParentScope : independentParentScope);
- bool SkipFirstSubStmt = false;
+ unsigned StmtsToSkip = 0u;
// If we found a label, remember that it is in ParentScope scope.
switch (S->getStmtClass()) {
@@ -304,11 +304,15 @@
break;
case Stmt::SwitchStmtClass:
- // Evaluate the condition variable before entering the scope of the switch
- // statement.
+ // Evaluate the C++17 init stmt and condition variable
+ // before entering the scope of the switch statement.
+ if (Stmt *Init = cast<SwitchStmt>(S)->getInit()) {
+ BuildScopeInformation(Init, ParentScope);
+ ++StmtsToSkip;
+ }
if (VarDecl *Var = cast<SwitchStmt>(S)->getConditionVariable()) {
BuildScopeInformation(Var, ParentScope);
- SkipFirstSubStmt = true;
+ ++StmtsToSkip;
}
// Fall through
@@ -537,13 +541,13 @@
}
for (Stmt *SubStmt : S->children()) {
- if (SkipFirstSubStmt) {
- SkipFirstSubStmt = false;
+ if (!SubStmt)
+ continue;
+ if (StmtsToSkip) {
+ --StmtsToSkip;
continue;
}
- if (!SubStmt) continue;
-
// Cases, labels, and defaults aren't "scope parents". It's also
// important to handle these iteratively instead of recursively in
// order to avoid blowing out the stack.
Index: lib/CodeGen/CGStmt.cpp
===================================================================
--- lib/CodeGen/CGStmt.cpp
+++ lib/CodeGen/CGStmt.cpp
@@ -561,6 +561,9 @@
// unequal to 0. The condition must be a scalar type.
LexicalScope ConditionScope(*this, S.getCond()->getSourceRange());
+ if (S.getInit())
+ EmitStmt(S.getInit());
+
if (S.getConditionVariable())
EmitAutoVarDecl(*S.getConditionVariable());
@@ -1465,6 +1468,9 @@
incrementProfileCounter(Case);
RunCleanupsScope ExecutedScope(*this);
+ if (S.getInit())
+ EmitStmt(S.getInit());
+
// Emit the condition variable if needed inside the entire cleanup scope
// used by this special case for constant folded switches.
if (S.getConditionVariable())
@@ -1492,6 +1498,10 @@
JumpDest SwitchExit = getJumpDestInCurrentScope("sw.epilog");
RunCleanupsScope ConditionScope(*this);
+
+ if (S.getInit())
+ EmitStmt(S.getInit());
+
if (S.getConditionVariable())
EmitAutoVarDecl(*S.getConditionVariable());
llvm::Value *CondV = EmitScalarExpr(S.getCond());
Index: lib/Analysis/CFG.cpp
===================================================================
--- lib/Analysis/CFG.cpp
+++ lib/Analysis/CFG.cpp
@@ -2168,6 +2168,13 @@
// won't be restored when traversing AST.
SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos);
+ // Create local scope for C++17 if-init stmt if exists
+ if (Stmt *Init = I->getInit()) {
+ LocalScope::const_iterator BeginScopePos = ScopePos;
+ addLocalScopeForStmt(Init);
+ addAutomaticObjDtors(ScopePos, BeginScopePos, I);
+ }
+
// Create local scope for possible condition variable.
// Store scope position. Add implicit destructor.
if (VarDecl *VD = I->getConditionVariable()) {
@@ -2268,7 +2275,7 @@
// blocks will be pointed to be "Block".
CFGBlock *LastBlock = addStmt(I->getCond());
- // Finally, if the IfStmt contains a condition variable, add it and its
+ // If the IfStmt contains a condition variable, add it and its
// initializer to the CFG.
if (const DeclStmt* DS = I->getConditionVariableDeclStmt()) {
autoCreateBlock();
@@ -2275,6 +2282,12 @@
LastBlock = addStmt(const_cast<DeclStmt *>(DS));
}
+ // Finally, if the IfStmt contains a C++17 init-stmt, add it to the CFG
+ if (Stmt* Init = I->getInit()) {
+ autoCreateBlock();
+ LastBlock = addStmt(Init);
+ }
+
return LastBlock;
}
@@ -3059,6 +3072,13 @@
// won't be restored when traversing AST.
SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos);
+ // Create local scope for C++17 switch-init stmt if exists
+ if (Stmt *Init = Terminator->getInit()) {
+ LocalScope::const_iterator BeginScopePos = ScopePos;
+ addLocalScopeForStmt(Init);
+ addAutomaticObjDtors(ScopePos, BeginScopePos, Terminator);
+ }
+
// Create local scope for possible condition variable.
// Store scope position. Add implicit destructor.
if (VarDecl *VD = Terminator->getConditionVariable()) {
@@ -3138,7 +3158,7 @@
Block = SwitchTerminatedBlock;
CFGBlock *LastBlock = addStmt(Terminator->getCond());
- // Finally, if the SwitchStmt contains a condition variable, add both the
+ // If the SwitchStmt contains a condition variable, add both the
// SwitchStmt and the condition variable initialization to the CFG.
if (VarDecl *VD = Terminator->getConditionVariable()) {
if (Expr *Init = VD->getInit()) {
@@ -3148,6 +3168,12 @@
}
}
+ // Finally, if the SwitchStmt contains a C++17 init-stmt, add it to the CFG
+ if (Stmt* Init = Terminator->getInit()) {
+ autoCreateBlock();
+ LastBlock = addStmt(Init);
+ }
+
return LastBlock;
}
Index: lib/Analysis/BodyFarm.cpp
===================================================================
--- lib/Analysis/BodyFarm.cpp
+++ lib/Analysis/BodyFarm.cpp
@@ -239,7 +239,7 @@
SourceLocation());
// (5) Create the 'if' statement.
- IfStmt *If = new (C) IfStmt(C, SourceLocation(), false, nullptr, UO, CS);
+ IfStmt *If = new (C) IfStmt(C, SourceLocation(), false, nullptr, nullptr, UO, CS);
return If;
}
@@ -343,7 +343,7 @@
/// Construct the If.
Stmt *If =
- new (C) IfStmt(C, SourceLocation(), false, nullptr, Comparison, Body,
+ new (C) IfStmt(C, SourceLocation(), false, nullptr, nullptr, Comparison, Body,
SourceLocation(), Else);
return If;
Index: lib/AST/Stmt.cpp
===================================================================
--- lib/AST/Stmt.cpp
+++ lib/AST/Stmt.cpp
@@ -764,11 +764,12 @@
}
IfStmt::IfStmt(const ASTContext &C, SourceLocation IL, bool IsConstexpr,
- VarDecl *var, Expr *cond, Stmt *then, SourceLocation EL,
+ Stmt *init, VarDecl *var, Expr *cond, Stmt *then, SourceLocation EL,
Stmt *elsev)
: Stmt(IfStmtClass), IfLoc(IL), ElseLoc(EL) {
setConstexpr(IsConstexpr);
setConditionVariable(C, var);
+ SubExprs[INIT] = init;
SubExprs[COND] = cond;
SubExprs[THEN] = then;
SubExprs[ELSE] = elsev;
@@ -824,9 +825,10 @@
VarRange.getEnd());
}
-SwitchStmt::SwitchStmt(const ASTContext &C, VarDecl *Var, Expr *cond)
+SwitchStmt::SwitchStmt(const ASTContext &C, Stmt* init, VarDecl *Var, Expr *cond)
: Stmt(SwitchStmtClass), FirstCase(nullptr, false) {
setConditionVariable(C, Var);
+ SubExprs[INIT] = init;
SubExprs[COND] = cond;
SubExprs[BODY] = nullptr;
}
Index: lib/AST/ExprConstant.cpp
===================================================================
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -3475,6 +3475,11 @@
APSInt Value;
{
FullExpressionRAII Scope(Info);
+ if (const Stmt* Init = SS->getInit()) {
+ EvalStmtResult ESR = EvaluateStmt(Result, Info, Init);
+ if (ESR != ESR_Succeeded)
+ return ESR;
+ }
if (SS->getConditionVariable() &&
!EvaluateDecl(Info, SS->getConditionVariable()))
return ESR_Failed;
@@ -3657,6 +3662,11 @@
// Evaluate the condition, as either a var decl or as an expression.
BlockScopeRAII Scope(Info);
+ if (const Stmt* Init = IS->getInit()) {
+ EvalStmtResult ESR = EvaluateStmt(Result, Info, Init);
+ if (ESR != ESR_Succeeded)
+ return ESR;
+ }
bool Cond;
if (!EvaluateCond(Info, IS->getConditionVariable(), IS->getCond(), Cond))
return ESR_Failed;
Index: lib/AST/ASTImporter.cpp
===================================================================
--- lib/AST/ASTImporter.cpp
+++ lib/AST/ASTImporter.cpp
@@ -4963,6 +4963,9 @@
Stmt *ASTNodeImporter::VisitIfStmt(IfStmt *S) {
SourceLocation ToIfLoc = Importer.Import(S->getIfLoc());
+ Stmt *ToInit = Importer.Import(S->getInit());
+ if (!ToInit && S->getInit())
+ return nullptr;
VarDecl *ToConditionVariable = nullptr;
if (VarDecl *FromConditionVariable = S->getConditionVariable()) {
ToConditionVariable =
@@ -4982,6 +4985,7 @@
return nullptr;
return new (Importer.getToContext()) IfStmt(Importer.getToContext(),
ToIfLoc, S->isConstexpr(),
+ ToInit,
ToConditionVariable,
ToCondition, ToThenStmt,
ToElseLoc, ToElseStmt);
@@ -4988,6 +4992,9 @@
}
Stmt *ASTNodeImporter::VisitSwitchStmt(SwitchStmt *S) {
+ Stmt *ToInit = Importer.Import(S->getInit());
+ if (!ToInit && S->getInit())
+ return nullptr;
VarDecl *ToConditionVariable = nullptr;
if (VarDecl *FromConditionVariable = S->getConditionVariable()) {
ToConditionVariable =
@@ -4999,8 +5006,8 @@
if (!ToCondition && S->getCond())
return nullptr;
SwitchStmt *ToStmt = new (Importer.getToContext()) SwitchStmt(
- Importer.getToContext(), ToConditionVariable,
- ToCondition);
+ Importer.getToContext(), ToInit,
+ ToConditionVariable, ToCondition);
Stmt *ToBody = Importer.Import(S->getBody());
if (!ToBody && S->getBody())
return nullptr;
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -3401,6 +3401,7 @@
ConditionResult Cond, Stmt *ThenVal,
SourceLocation ElseLoc, Stmt *ElseVal);
StmtResult BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr,
+ Stmt *InitStmt,
ConditionResult Cond, Stmt *ThenVal,
SourceLocation ElseLoc, Stmt *ElseVal);
StmtResult ActOnStartOfSwitchStmt(SourceLocation SwitchLoc,
Index: include/clang/AST/Stmt.h
===================================================================
--- include/clang/AST/Stmt.h
+++ include/clang/AST/Stmt.h
@@ -879,7 +879,7 @@
/// IfStmt - This represents an if/then/else.
///
class IfStmt : public Stmt {
- enum { VAR, COND, THEN, ELSE, END_EXPR };
+ enum { INIT, VAR, COND, THEN, ELSE, END_EXPR };
Stmt* SubExprs[END_EXPR];
SourceLocation IfLoc;
@@ -887,7 +887,7 @@
public:
IfStmt(const ASTContext &C, SourceLocation IL,
- bool IsConstexpr, VarDecl *var, Expr *cond,
+ bool IsConstexpr, Stmt* init, VarDecl *var, Expr *cond,
Stmt *then, SourceLocation EL = SourceLocation(),
Stmt *elsev = nullptr);
@@ -911,6 +911,9 @@
return reinterpret_cast<DeclStmt*>(SubExprs[VAR]);
}
+ Stmt *getInit() { return SubExprs[INIT]; }
+ const Stmt *getInit() const { return SubExprs[INIT]; }
+ void setInit(Stmt *S) { SubExprs[INIT] = S; }
const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);}
void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt *>(E); }
const Stmt *getThen() const { return SubExprs[THEN]; }
@@ -953,7 +956,7 @@
///
class SwitchStmt : public Stmt {
SourceLocation SwitchLoc;
- enum { VAR, COND, BODY, END_EXPR };
+ enum { INIT, VAR, COND, BODY, END_EXPR };
Stmt* SubExprs[END_EXPR];
// This points to a linked list of case and default statements and, if the
// SwitchStmt is a switch on an enum value, records whether all the enum
@@ -962,7 +965,7 @@
llvm::PointerIntPair<SwitchCase *, 1, bool> FirstCase;
public:
- SwitchStmt(const ASTContext &C, VarDecl *Var, Expr *cond);
+ SwitchStmt(const ASTContext &C, Stmt *Init, VarDecl *Var, Expr *cond);
/// \brief Build a empty switch statement.
explicit SwitchStmt(EmptyShell Empty) : Stmt(SwitchStmtClass, Empty) { }
@@ -985,6 +988,9 @@
return reinterpret_cast<DeclStmt*>(SubExprs[VAR]);
}
+ Stmt *getInit() { return SubExprs[INIT]; }
+ const Stmt *getInit() const { return SubExprs[INIT]; }
+ void setInit(Stmt *S) { SubExprs[INIT] = S; }
const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);}
const Stmt *getBody() const { return SubExprs[BODY]; }
const SwitchCase *getSwitchCaseList() const { return FirstCase.getPointer(); }
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits