diff options
-rw-r--r-- | clang/include/clang/AST/Expr.h | 5 | ||||
-rw-r--r-- | clang/lib/AST/ExprConstant.cpp | 42 | ||||
-rw-r--r-- | clang/lib/Sema/SemaStmt.cpp | 7 | ||||
-rw-r--r-- | clang/test/Sema/switch.c | 10 |
4 files changed, 41 insertions, 23 deletions
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 77d6d5f86dd..321dca53365 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -141,8 +141,9 @@ public: /// any crazy technique (that has nothing to do with language standards) that /// we want to. If this function returns true, it returns the folded constant /// in Result. - bool Evaluate(APValue& Result, ASTContext &Ctx) const; - + // FIXME: We should come up with a better API for the isEvaluated case. + bool Evaluate(APValue& Result, ASTContext &Ctx, bool *isEvaluated = 0) const; + /// isEvaluatable - Call Evaluate to see if this expression can be constant /// folded, but discard the result. bool isEvaluatable(ASTContext &Ctx) const; diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 35cec0f3442..5c5adb6a45e 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -537,6 +537,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { // These need to be handled specially because the operands aren't // necessarily integral bool bres; + bool isEvaluated = true; if (HandleConversionToBool(E->getLHS(), bres, Info)) { // We were able to evaluate the LHS, see if we can get away with not @@ -548,16 +549,18 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { // We can't evaluate. return false; } + + // We did not evaluate the LHS + isEvaluated = false; } - // FIXME: If we evaluate the RHS, we need to check if the LHS has - // any side effects. - if (bres == (E->getOpcode() == BinaryOperator::LOr) || !bres == (E->getOpcode() == BinaryOperator::LAnd)) { Result.zextOrTrunc(getIntTypeSizeInBits(E->getType())); Result.setIsUnsigned(E->getType()->isUnsignedIntegerType()); Result = bres; + Info.isEvaluated = isEvaluated; + return true; } @@ -1153,30 +1156,31 @@ APValue ComplexFloatExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) /// any crazy technique (that has nothing to do with language standards) that /// we want to. If this function returns true, it returns the folded constant /// in Result. -bool Expr::Evaluate(APValue &Result, ASTContext &Ctx) const { +bool Expr::Evaluate(APValue &Result, ASTContext &Ctx, bool *isEvaluated) const { EvalInfo Info(Ctx); if (getType()->isIntegerType()) { llvm::APSInt sInt(32); - if (EvaluateInteger(this, sInt, Info)) { - Result = APValue(sInt); - return true; - } + if (!EvaluateInteger(this, sInt, Info)) + return false; + + Result = APValue(sInt); } else if (getType()->isPointerType()) { - if (EvaluatePointer(this, Result, Info)) { - return true; - } + if (!EvaluatePointer(this, Result, Info)) + return false; } else if (getType()->isRealFloatingType()) { llvm::APFloat f(0.0); - if (EvaluateFloat(this, f, Info)) { - Result = APValue(f); - return true; - } + if (!EvaluateFloat(this, f, Info)) + return false; + + Result = APValue(f); } else if (getType()->isComplexType()) { - if (EvaluateComplexFloat(this, Result, Info)) - return true; + if (!EvaluateComplexFloat(this, Result, Info)) + return false; } - - return false; + + if (isEvaluated) + *isEvaluated = Info.isEvaluated; + return true; } /// isEvaluatable - Call Evaluate to see if this expression can be constant diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 6839310e0ec..15d955cb7b4 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -131,8 +131,10 @@ Sema::ActOnCaseStmt(SourceLocation CaseLoc, ExprTy *lhsval, // However, GCC allows any evaluatable integer expression. // FIXME: Should we warn if this is evaluatable but not an I-C-E? APValue Result; + bool isEvaluated; - if (!LHSVal->Evaluate(Result, Context) || !Result.isInt()) { + if (!LHSVal->Evaluate(Result, Context, &isEvaluated) || !Result.isInt() || + !isEvaluated) { // FIXME: Evaluate doesn't return the SourceLocation that it failed to // evaluate. ExpLoc = LHSVal->getExprLoc(); @@ -142,7 +144,8 @@ Sema::ActOnCaseStmt(SourceLocation CaseLoc, ExprTy *lhsval, } // GCC extension: The expression shall be an integer constant. - if (RHSVal && !RHSVal->Evaluate(Result, Context) || !Result.isInt()) { + if (RHSVal && !RHSVal->Evaluate(Result, Context, &isEvaluated) || + !Result.isInt() || !isEvaluated) { ExpLoc = RHSVal->getExprLoc(); Diag(ExpLoc, diag::err_case_label_not_integer_constant_expr) << RHSVal->getSourceRange(); diff --git a/clang/test/Sema/switch.c b/clang/test/Sema/switch.c index fd8e0464be6..63e5fe33b7d 100644 --- a/clang/test/Sema/switch.c +++ b/clang/test/Sema/switch.c @@ -48,5 +48,15 @@ void test4() case 0 && g() ... 1 || g(): break; } + + switch (1) { + case g() && 0: // expected-error {{case label does not reduce to an integer constant}} + break; + } + + switch (1) { + case 0 ... g() || 1: // expected-error {{case label does not reduce to an integer constant}} + break; + } } |