summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2019-09-20 23:08:59 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2019-09-20 23:08:59 +0000
commit2f8985aaa00f95270bce3e1eec546613cbf032e2 (patch)
tree4c16e47cd62da889622ab2867909b28ab7ba4115
parent284e55561b91424f97f4e181de06aa2c71106937 (diff)
downloadclang-2f8985aaa00f95270bce3e1eec546613cbf032e2.tar.gz
Fix assertion failure when constant evaluation of a switch jumps over an
uninitialized variable in an init-statement of a 'for' or 'if'. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@372437 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/AST/ExprConstant.cpp27
-rw-r--r--test/SemaCXX/constant-expression-cxx2a.cpp13
2 files changed, 40 insertions, 0 deletions
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 2d538eda81..39d0943b45 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -4131,6 +4131,21 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
// preceded by our switch label.
BlockScopeRAII Scope(Info);
+ // Step into the init statement in case it brings an (uninitialized)
+ // variable into scope.
+ if (const Stmt *Init = IS->getInit()) {
+ EvalStmtResult ESR = EvaluateStmt(Result, Info, Init, Case);
+ if (ESR != ESR_CaseNotFound) {
+ assert(ESR != ESR_Succeeded);
+ return ESR;
+ }
+ }
+
+ // Condition variable must be initialized if it exists.
+ // FIXME: We can skip evaluating the body if there's a condition
+ // variable, as there can't be any case labels within it.
+ // (The same is true for 'for' statements.)
+
EvalStmtResult ESR = EvaluateStmt(Result, Info, IS->getThen(), Case);
if (ESR != ESR_CaseNotFound || !IS->getElse())
return ESR;
@@ -4147,6 +4162,18 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
case Stmt::ForStmtClass: {
const ForStmt *FS = cast<ForStmt>(S);
+ BlockScopeRAII Scope(Info);
+
+ // Step into the init statement in case it brings an (uninitialized)
+ // variable into scope.
+ if (const Stmt *Init = FS->getInit()) {
+ EvalStmtResult ESR = EvaluateStmt(Result, Info, Init, Case);
+ if (ESR != ESR_CaseNotFound) {
+ assert(ESR != ESR_Succeeded);
+ return ESR;
+ }
+ }
+
EvalStmtResult ESR =
EvaluateLoopBody(Result, Info, FS->getBody(), Case);
if (ESR != ESR_Continue)
diff --git a/test/SemaCXX/constant-expression-cxx2a.cpp b/test/SemaCXX/constant-expression-cxx2a.cpp
index ec4263e3ee..a1ab6e8e12 100644
--- a/test/SemaCXX/constant-expression-cxx2a.cpp
+++ b/test/SemaCXX/constant-expression-cxx2a.cpp
@@ -620,4 +620,17 @@ namespace Uninit {
constexpr int s1 = switch_var(1);
constexpr int s2 = switch_var(2);
static_assert(s1 == 1 && s2 == 2);
+
+ constexpr bool switch_into_init_stmt() {
+ switch (1) {
+ if (int n; false) {
+ for (int m; false;) {
+ case 1:
+ n = m = 1;
+ return n == 1 && m == 1;
+ }
+ }
+ }
+ }
+ static_assert(switch_into_init_stmt());
}