diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-01-18 23:55:52 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-01-18 23:55:52 +0000 |
commit | 8ef7b203332b0c8d65876a1f5e6d1db4e6f40e4b (patch) | |
tree | dee9b186a48a66f3c8be5c56c4e774338408bece /lib/Sema/SemaStmt.cpp | |
parent | d6c7c67313634b317a0d63c32be0511a121bb33d (diff) |
constexpr: converted constant expression handling for enumerator values, case
values and non-type template arguments of integral and enumeration types.
This change causes some legal C++98 code to no longer compile in C++11 mode, by
enforcing the C++11 rule that narrowing integral conversions are not permitted
in the final implicit conversion sequence for the above cases.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@148439 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaStmt.cpp')
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 92 |
1 files changed, 63 insertions, 29 deletions
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 23dc7e9d20..a53e397243 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -266,22 +266,24 @@ Sema::ActOnCaseStmt(SourceLocation CaseLoc, Expr *LHSVal, SourceLocation ColonLoc) { assert((LHSVal != 0) && "missing expression in case statement"); - // C99 6.8.4.2p3: The expression shall be an integer constant. - // However, GCC allows any evaluatable integer expression. - if (!LHSVal->isTypeDependent() && !LHSVal->isValueDependent() && - VerifyIntegerConstantExpression(LHSVal)) + if (getCurFunction()->SwitchStack.empty()) { + Diag(CaseLoc, diag::err_case_not_in_switch); return StmtError(); + } - // GCC extension: The expression shall be an integer constant. + if (!getLangOptions().CPlusPlus0x) { + // C99 6.8.4.2p3: The expression shall be an integer constant. + // However, GCC allows any evaluatable integer expression. + if (!LHSVal->isTypeDependent() && !LHSVal->isValueDependent() && + VerifyIntegerConstantExpression(LHSVal)) + return StmtError(); - if (RHSVal && !RHSVal->isTypeDependent() && !RHSVal->isValueDependent() && - VerifyIntegerConstantExpression(RHSVal)) { - RHSVal = 0; // Recover by just forgetting about it. - } + // GCC extension: The expression shall be an integer constant. - if (getCurFunction()->SwitchStack.empty()) { - Diag(CaseLoc, diag::err_case_not_in_switch); - return StmtError(); + if (RHSVal && !RHSVal->isTypeDependent() && !RHSVal->isValueDependent() && + VerifyIntegerConstantExpression(RHSVal)) { + RHSVal = 0; // Recover by just forgetting about it. + } } CaseStmt *CS = new (Context) CaseStmt(LHSVal, RHSVal, CaseLoc, DotDotDotLoc, @@ -622,8 +624,6 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, } else { CaseStmt *CS = cast<CaseStmt>(SC); - // We already verified that the expression has a i-c-e value (C99 - // 6.8.4.2p3) - get that value now. Expr *Lo = CS->getLHS(); if (Lo->isTypeDependent() || Lo->isValueDependent()) { @@ -631,19 +631,39 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, break; } - llvm::APSInt LoVal = Lo->EvaluateKnownConstInt(Context); + llvm::APSInt LoVal; - // Convert the value to the same width/sign as the condition. + if (getLangOptions().CPlusPlus0x) { + // C++11 [stmt.switch]p2: the constant-expression shall be a converted + // constant expression of the promoted type of the switch condition. + ExprResult ConvLo = + CheckConvertedConstantExpression(Lo, CondType, LoVal, CCEK_CaseValue); + if (ConvLo.isInvalid()) { + CaseListIsErroneous = true; + continue; + } + Lo = ConvLo.take(); + } else { + // We already verified that the expression has a i-c-e value (C99 + // 6.8.4.2p3) - get that value now. + LoVal = Lo->EvaluateKnownConstInt(Context); + + // If the LHS is not the same type as the condition, insert an implicit + // cast. + Lo = DefaultLvalueConversion(Lo).take(); + Lo = ImpCastExprToType(Lo, CondType, CK_IntegralCast).take(); + } + + // Convert the value to the same width/sign as the condition had prior to + // integral promotions. + // + // FIXME: This causes us to reject valid code: + // switch ((char)c) { case 256: case 0: return 0; } + // Here we claim there is a duplicated condition value, but there is not. ConvertIntegerToTypeWarnOnOverflow(LoVal, CondWidth, CondIsSigned, Lo->getLocStart(), diag::warn_case_value_overflow); - // If the LHS is not the same type as the condition, insert an implicit - // cast. - // FIXME: In C++11, the value is a converted constant expression of the - // promoted type of the switch condition. - Lo = DefaultLvalueConversion(Lo).take(); - Lo = ImpCastExprToType(Lo, CondType, CK_IntegralCast).take(); CS->setLHS(Lo); // If this is a case range, remember it in CaseRanges, otherwise CaseVals. @@ -709,19 +729,33 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, llvm::APSInt &LoVal = CaseRanges[i].first; CaseStmt *CR = CaseRanges[i].second; Expr *Hi = CR->getRHS(); - llvm::APSInt HiVal = Hi->EvaluateKnownConstInt(Context); + llvm::APSInt HiVal; + + if (getLangOptions().CPlusPlus0x) { + // C++11 [stmt.switch]p2: the constant-expression shall be a converted + // constant expression of the promoted type of the switch condition. + ExprResult ConvHi = + CheckConvertedConstantExpression(Hi, CondType, HiVal, + CCEK_CaseValue); + if (ConvHi.isInvalid()) { + CaseListIsErroneous = true; + continue; + } + Hi = ConvHi.take(); + } else { + HiVal = Hi->EvaluateKnownConstInt(Context); + + // If the RHS is not the same type as the condition, insert an + // implicit cast. + Hi = DefaultLvalueConversion(Hi).take(); + Hi = ImpCastExprToType(Hi, CondType, CK_IntegralCast).take(); + } // Convert the value to the same width/sign as the condition. ConvertIntegerToTypeWarnOnOverflow(HiVal, CondWidth, CondIsSigned, Hi->getLocStart(), diag::warn_case_value_overflow); - // If the RHS is not the same type as the condition, insert an implicit - // cast. - // FIXME: In C++11, the value is a converted constant expression of the - // promoted type of the switch condition. - Hi = DefaultLvalueConversion(Hi).take(); - Hi = ImpCastExprToType(Hi, CondType, CK_IntegralCast).take(); CR->setRHS(Hi); // If the low value is bigger than the high value, the case is empty. |