diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2019-09-20 23:08:59 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2019-09-20 23:08:59 +0000 |
commit | 397a686762e229c32857efc4e66b4e6cf72bee93 (patch) | |
tree | becd3557256b8d0ec95389720e3d806ec550443e | |
parent | 48b40834dc59ec1d02f59b1c36360b12c58b3c7b (diff) | |
download | bcm5719-llvm-397a686762e229c32857efc4e66b4e6cf72bee93.tar.gz bcm5719-llvm-397a686762e229c32857efc4e66b4e6cf72bee93.zip |
Fix assertion failure when constant evaluation of a switch jumps over an
uninitialized variable in an init-statement of a 'for' or 'if'.
llvm-svn: 372437
-rw-r--r-- | clang/lib/AST/ExprConstant.cpp | 27 | ||||
-rw-r--r-- | clang/test/SemaCXX/constant-expression-cxx2a.cpp | 13 |
2 files changed, 40 insertions, 0 deletions
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 2d538eda812..39d0943b45e 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/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/clang/test/SemaCXX/constant-expression-cxx2a.cpp b/clang/test/SemaCXX/constant-expression-cxx2a.cpp index ec4263e3ee4..a1ab6e8e126 100644 --- a/clang/test/SemaCXX/constant-expression-cxx2a.cpp +++ b/clang/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()); } |