From cbb407268e06bce2dda06edf0b94093e5a2c8ae1 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Mon, 24 Oct 2011 21:07:08 +0000 Subject: [PATCH] Constant expression evaluation: evaluate lvalues as lvalues, and rvalues as rvalues, as C++11 constant evaluation semantics require. DeclRefs referring to references can now use the normal initialization-caching codepath, which incidentally fixes a crash in cyclic initialization of references. llvm-svn: 142844 --- clang/include/clang/AST/Expr.h | 3 +- clang/lib/AST/ExprConstant.cpp | 398 ++++++++++++++++++------------- clang/test/SemaCXX/i-c-e-cxx.cpp | 3 + 3 files changed, 242 insertions(+), 162 deletions(-) diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index e7b1a0593ffe..028dfa2c6719 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -465,7 +465,8 @@ public: /// Evaluate - Return true if this is a constant which we can fold using /// 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. + /// in Result. If this expression is a glvalue, an lvalue-to-rvalue conversion + /// will be applied. bool Evaluate(EvalResult &Result, const ASTContext &Ctx) const; /// EvaluateAsBooleanCondition - Return true if this is a constant diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index e681e915442c..98fe07f1b68c 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -151,7 +151,7 @@ static bool IsGlobalLValue(const Expr* E) { return true; } -static bool EvalPointerValueAsBool(LValue& Value, bool& Result) { +static bool EvalPointerValueAsBool(const LValue &Value, bool &Result) { const Expr* Base = Value.Base; // A null base expression indicates a null pointer. These are always @@ -183,40 +183,44 @@ static bool EvalPointerValueAsBool(LValue& Value, bool& Result) { return true; } -static bool HandleConversionToBool(const Expr* E, bool& Result, - EvalInfo &Info) { - if (E->getType()->isIntegralOrEnumerationType()) { - APSInt IntResult; - if (!EvaluateInteger(E, IntResult, Info)) - return false; - Result = IntResult != 0; +static bool HandleConversionToBool(const APValue &Val, bool &Result) { + switch (Val.getKind()) { + case APValue::Uninitialized: + return false; + case APValue::Int: + Result = Val.getInt().getBoolValue(); return true; - } else if (E->getType()->isRealFloatingType()) { - APFloat FloatResult(0.0); - if (!EvaluateFloat(E, FloatResult, Info)) - return false; - Result = !FloatResult.isZero(); + case APValue::Float: + Result = !Val.getFloat().isZero(); return true; - } else if (E->getType()->hasPointerRepresentation()) { - LValue PointerResult; - if (!EvaluatePointer(E, PointerResult, Info)) - return false; - return EvalPointerValueAsBool(PointerResult, Result); - } else if (E->getType()->isAnyComplexType()) { - ComplexValue ComplexResult; - if (!EvaluateComplex(E, ComplexResult, Info)) - return false; - if (ComplexResult.isComplexFloat()) { - Result = !ComplexResult.getComplexFloatReal().isZero() || - !ComplexResult.getComplexFloatImag().isZero(); - } else { - Result = ComplexResult.getComplexIntReal().getBoolValue() || - ComplexResult.getComplexIntImag().getBoolValue(); + case APValue::ComplexInt: + Result = Val.getComplexIntReal().getBoolValue() || + Val.getComplexIntImag().getBoolValue(); + return true; + case APValue::ComplexFloat: + Result = !Val.getComplexFloatReal().isZero() || + !Val.getComplexFloatImag().isZero(); + return true; + case APValue::LValue: + { + LValue PointerResult; + PointerResult.setFrom(Val); + return EvalPointerValueAsBool(PointerResult, Result); } - return true; + case APValue::Vector: + return false; } - return false; + llvm_unreachable("unknown APValue kind"); +} + +static bool EvaluateAsBooleanCondition(const Expr *E, bool &Result, + EvalInfo &Info) { + assert(E->isRValue() && "missing lvalue-to-rvalue conv in bool condition"); + APValue Val; + if (!Evaluate(Val, Info, E)) + return false; + return HandleConversionToBool(Val, Result); } static APSInt HandleFloatToIntCast(QualType DestType, QualType SrcType, @@ -278,10 +282,11 @@ static APValue *EvaluateVarDeclInit(EvalInfo &Info, const VarDecl *VD) { VD->setEvaluatingValue(); - // FIXME: If the initializer isn't a constant expression, propagate up any - // diagnostic explaining why not. Expr::EvalResult EResult; - if (Init->Evaluate(EResult, Info.Ctx) && !EResult.HasSideEffects) + EvalInfo InitInfo(Info.Ctx, EResult); + // FIXME: The caller will need to know whether the value was a constant + // expression. If not, we should propagate up a diagnostic. + if (Evaluate(EResult.Val, InitInfo, Init)) VD->setEvaluatedValue(EResult.Val); else VD->setEvaluatedValue(APValue()); @@ -294,6 +299,52 @@ bool IsConstNonVolatile(QualType T) { return Quals.hasConst() && !Quals.hasVolatile(); } +bool HandleLValueToRValueConversion(EvalInfo &Info, QualType Type, + const LValue &LValue, APValue &RValue) { + const Expr *Base = LValue.Base; + + // FIXME: Indirection through a null pointer deserves a diagnostic. + if (!Base) + return false; + + // FIXME: Support accessing subobjects of objects of literal types. A simple + // byte offset is insufficient for C++11 semantics: we need to know how the + // reference was formed (which union member was named, for instance). + // FIXME: Support subobjects of StringLiteral and PredefinedExpr. + if (!LValue.Offset.isZero()) + return false; + + if (const DeclRefExpr *DRE = dyn_cast(Base)) { + // In C++, const, non-volatile integers initialized with ICEs are ICEs. + // In C, they can also be folded, although they are not ICEs. + // In C++0x, constexpr variables are constant expressions too. + // We allow folding any const variable of literal type initialized with + // a constant expression. + const VarDecl *VD = dyn_cast(DRE->getDecl()); + if (VD && IsConstNonVolatile(VD->getType()) && Type->isLiteralType()) { + APValue *V = EvaluateVarDeclInit(Info, VD); + if (V && !V->isUninit()) { + RValue = *V; + return true; + } + } + return false; + } + + // FIXME: C++11: Support MaterializeTemporaryExpr in LValueExprEvaluator and + // here. + + // In C99, a CompoundLiteralExpr is an lvalue, and we defer evaluating the + // initializer until now for such expressions. Such an expression can't be + // an ICE in C, so this only matters for fold. + if (const CompoundLiteralExpr *CLE = dyn_cast(Base)) { + assert(!Info.getLangOpts().CPlusPlus && "lvalue compound literal in c++?"); + return Evaluate(RValue, Info, CLE->getInitializer()); + } + + return false; +} + namespace { class HasSideEffect : public ConstStmtVisitor { @@ -454,7 +505,7 @@ public: return DerivedError(E); bool cond; - if (!HandleConversionToBool(E->getCond(), cond, Info)) + if (!EvaluateAsBooleanCondition(E->getCond(), cond, Info)) return DerivedError(E); return StmtVisitorTy::Visit(cond ? E->getTrueExpr() : E->getFalseExpr()); @@ -462,10 +513,10 @@ public: RetTy VisitConditionalOperator(const ConditionalOperator *E) { bool BoolResult; - if (!HandleConversionToBool(E->getCond(), BoolResult, Info)) + if (!EvaluateAsBooleanCondition(E->getCond(), BoolResult, Info)) return DerivedError(E); - Expr* EvalExpr = BoolResult ? E->getTrueExpr() : E->getFalseExpr(); + Expr *EvalExpr = BoolResult ? E->getTrueExpr() : E->getFalseExpr(); return StmtVisitorTy::Visit(EvalExpr); } @@ -477,6 +528,9 @@ public: return DerivedSuccess(*value, E); } + RetTy VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) { + return StmtVisitorTy::Visit(E->getInitializer()); + } RetTy VisitInitListExpr(const InitListExpr *E) { if (Info.getLangOpts().CPlusPlus0x) { if (E->getNumInits() == 0) @@ -493,6 +547,28 @@ public: return DerivedValueInitialization(E); } + RetTy VisitCastExpr(const CastExpr *E) { + switch (E->getCastKind()) { + default: + break; + + case CK_NoOp: + return StmtVisitorTy::Visit(E->getSubExpr()); + + case CK_LValueToRValue: { + LValue LVal; + if (EvaluateLValue(E->getSubExpr(), LVal, Info)) { + APValue RVal; + if (HandleLValueToRValueConversion(Info, E->getType(), LVal, RVal)) + return DerivedSuccess(RVal, E); + } + break; + } + } + + return DerivedError(E); + } + /// Visit a value which is evaluated, but whose value is ignored. void VisitIgnoredValue(const Expr *E) { APValue Scratch; @@ -505,6 +581,10 @@ public: //===----------------------------------------------------------------------===// // LValue Evaluation +// +// This is used for evaluating lvalues (in C and C++), xvalues (in C++11), +// function designators (in C), decl references to void objects (in C), and +// temporaries (if building with -Wno-address-of-temporary). //===----------------------------------------------------------------------===// namespace { class LValueExprEvaluator @@ -542,13 +622,13 @@ public: bool VisitCastExpr(const CastExpr *E) { switch (E->getCastKind()) { default: - return false; + return ExprEvaluatorBaseTy::VisitCastExpr(E); - case CK_NoOp: case CK_LValueBitCast: return Visit(E->getSubExpr()); - // FIXME: Support CK_DerivedToBase and friends. + // FIXME: Support CK_DerivedToBase and CK_UncheckedDerivedToBase. + // Reuse PointerExprEvaluator::VisitCastExpr for these. } } @@ -557,6 +637,11 @@ public: }; } // end anonymous namespace +/// Evaluate an expression as an lvalue. This can be legitimately called on +/// expressions which are not glvalues, in a few cases: +/// * function designators in C, +/// * "extern void" objects, +/// * temporaries, if building with -Wno-address-of-temporary. static bool EvaluateLValue(const Expr* E, LValue& Result, EvalInfo &Info) { return LValueExprEvaluator(Info, Result).Visit(E); } @@ -570,22 +655,24 @@ bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) { // Reference parameters can refer to anything even if they have an // "initializer" in the form of a default argument. if (!isa(VD)) { - // FIXME: Check whether VD might be overridden! - - // Check for recursive initializers of references. - if (PrevDecl == VD) - return Error(E); - PrevDecl = VD; - if (const Expr *Init = VD->getAnyInitializer()) - return Visit(Init); + APValue *V = EvaluateVarDeclInit(Info, VD); + if (V && !V->isUninit()) { + assert(V->isLValue() && "reference init not glvalue"); + Result.Base = V->getLValueBase(); + Result.Offset = V->getLValueOffset(); + return true; + } } } - return ExprEvaluatorBaseTy::VisitDeclRefExpr(E); + return Error(E); } bool LValueExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) { + assert(!Info.getLangOpts().CPlusPlus && "lvalue compound literal in c++?"); + // Defer visiting the literal until the lvalue-to-rvalue conversion. We can + // only see this when folding in C, so there's no standard to follow here. return Success(E); } @@ -617,6 +704,10 @@ bool LValueExprEvaluator::VisitMemberExpr(const MemberExpr *E) { } bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { + // FIXME: Deal with vectors as array subscript bases. + if (E->getBase()->getType()->isVectorType()) + return false; + if (!EvaluatePointer(E->getBase(), Result, Info)) return false; @@ -684,7 +775,7 @@ public: } // end anonymous namespace static bool EvaluatePointer(const Expr* E, LValue& Result, EvalInfo &Info) { - assert(E->getType()->hasPointerRepresentation()); + assert(E->isRValue() && E->getType()->hasPointerRepresentation()); return PointerExprEvaluator(Info, Result).Visit(E); } @@ -740,7 +831,6 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { default: break; - case CK_NoOp: case CK_BitCast: case CK_CPointerToObjCPointerCast: case CK_BlockPointerToObjCPointerCast: @@ -810,7 +900,7 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { return EvaluateLValue(SubExpr, Result, Info); } - return false; + return ExprEvaluatorBaseTy::VisitCastExpr(E); } bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) { @@ -852,7 +942,6 @@ namespace { bool VisitUnaryReal(const UnaryOperator *E) { return Visit(E->getSubExpr()); } bool VisitCastExpr(const CastExpr* E); - bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E); bool VisitInitListExpr(const InitListExpr *E); bool VisitUnaryImag(const UnaryOperator *E); // FIXME: Missing: unary -, unary ~, binary add/sub/mul/div, @@ -864,8 +953,7 @@ namespace { } // end anonymous namespace static bool EvaluateVector(const Expr* E, APValue& Result, EvalInfo &Info) { - if (!E->getType()->isVectorType()) - return false; + assert(E->isRValue() && E->getType()->isVectorType() &&"not a vector rvalue"); return VectorExprEvaluator(Info, Result).Visit(E); } @@ -927,19 +1015,11 @@ bool VectorExprEvaluator::VisitCastExpr(const CastExpr* E) { } return Success(Elts, E); } - case CK_LValueToRValue: - case CK_NoOp: - return Visit(SE); default: - return Error(E); + return ExprEvaluatorBaseTy::VisitCastExpr(E); } } -bool -VectorExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) { - return Visit(E->getInitializer()); -} - bool VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) { const VectorType *VT = E->getType()->castAs(); @@ -1022,6 +1102,10 @@ bool VectorExprEvaluator::VisitUnaryImag(const UnaryOperator *E) { //===----------------------------------------------------------------------===// // Integer Evaluation +// +// As a GNU extension, we support casting pointers to sufficiently-wide integer +// types and back in constant folding. Integer values are thus represented +// either as an integer-valued APValue, or as an lvalue-valued APValue. //===----------------------------------------------------------------------===// namespace { @@ -1105,8 +1189,7 @@ public: } bool VisitMemberExpr(const MemberExpr *E) { if (CheckReferencedDecl(E, E->getMemberDecl())) { - // Conservatively assume a MemberExpr will have side-effects - Info.EvalStatus.HasSideEffects = true; + VisitIgnoredValue(E->getBase()); return true; } @@ -1161,14 +1244,20 @@ private: }; } // end anonymous namespace +/// EvaluateIntegerOrLValue - Evaluate an rvalue integral-typed expression, and +/// produce either the integer value or a pointer. +/// +/// GCC has a heinous extension which folds casts between pointer types and +/// pointer-sized integral types. We support this by allowing the evaluation of +/// an integer rvalue to produce a pointer (represented as an lvalue) instead. +/// Some simple arithmetic on such values is supported (they are treated much +/// like char*). static bool EvaluateIntegerOrLValue(const Expr* E, APValue &Result, EvalInfo &Info) { - assert(E->getType()->isIntegralOrEnumerationType()); + assert(E->isRValue() && E->getType()->isIntegralOrEnumerationType()); return IntExprEvaluator(Info, Result).Visit(E); } static bool EvaluateInteger(const Expr* E, APSInt &Result, EvalInfo &Info) { - assert(E->getType()->isIntegralOrEnumerationType()); - APValue Val; if (!EvaluateIntegerOrLValue(E, Val, Info) || !Val.isInt()) return false; @@ -1197,18 +1286,6 @@ bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) { return Success(Val, E); } } - - // In C++, const, non-volatile integers initialized with ICEs are ICEs. - // In C, they can also be folded, although they are not ICEs. - if (IsConstNonVolatile(E->getType())) { - if (const VarDecl *VD = dyn_cast(D)) { - APValue *V = EvaluateVarDeclInit(Info, VD); - if (V && V->isInt()) - return Success(V->getInt(), E); - } - } - - // Otherwise, random variable references are not constants. return false; } @@ -1411,6 +1488,9 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { } bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { + if (E->isAssignmentOp()) + return Error(E->getOperatorLoc(), diag::note_invalid_subexpr_in_ice, E); + if (E->getOpcode() == BO_Comma) { VisitIgnoredValue(E->getLHS()); return Visit(E->getRHS()); @@ -1421,20 +1501,20 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { // necessarily integral bool lhsResult, rhsResult; - if (HandleConversionToBool(E->getLHS(), lhsResult, Info)) { + if (EvaluateAsBooleanCondition(E->getLHS(), lhsResult, Info)) { // We were able to evaluate the LHS, see if we can get away with not // evaluating the RHS: 0 && X -> 0, 1 || X -> 1 if (lhsResult == (E->getOpcode() == BO_LOr)) return Success(lhsResult, E); - if (HandleConversionToBool(E->getRHS(), rhsResult, Info)) { + if (EvaluateAsBooleanCondition(E->getRHS(), rhsResult, Info)) { if (E->getOpcode() == BO_LOr) return Success(lhsResult || rhsResult, E); else return Success(lhsResult && rhsResult, E); } } else { - if (HandleConversionToBool(E->getRHS(), rhsResult, Info)) { + if (EvaluateAsBooleanCondition(E->getRHS(), rhsResult, Info)) { // We can't evaluate the LHS; however, sometimes the result // is determined by the RHS: X && 0 -> 0, X || 1 -> 1. if (rhsResult == (E->getOpcode() == BO_LOr) || @@ -1590,58 +1670,60 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { } // The LHS of a constant expr is always evaluated and needed. - if (!Visit(E->getLHS())) + APValue LHSVal; + if (!EvaluateIntegerOrLValue(E->getLHS(), LHSVal, Info)) return false; // error in subexpression. - APValue RHSVal; - if (!EvaluateIntegerOrLValue(E->getRHS(), RHSVal, Info)) + if (!Visit(E->getRHS())) return false; + APValue &RHSVal = Result; // Handle cases like (unsigned long)&a + 4. - if (E->isAdditiveOp() && Result.isLValue() && RHSVal.isInt()) { - CharUnits Offset = Result.getLValueOffset(); + if (E->isAdditiveOp() && LHSVal.isLValue() && RHSVal.isInt()) { + CharUnits Offset = LHSVal.getLValueOffset(); CharUnits AdditionalOffset = CharUnits::fromQuantity( RHSVal.getInt().getZExtValue()); if (E->getOpcode() == BO_Add) Offset += AdditionalOffset; else Offset -= AdditionalOffset; - Result = APValue(Result.getLValueBase(), Offset); + Result = APValue(LHSVal.getLValueBase(), Offset); return true; } // Handle cases like 4 + (unsigned long)&a if (E->getOpcode() == BO_Add && - RHSVal.isLValue() && Result.isInt()) { + RHSVal.isLValue() && LHSVal.isInt()) { CharUnits Offset = RHSVal.getLValueOffset(); - Offset += CharUnits::fromQuantity(Result.getInt().getZExtValue()); + Offset += CharUnits::fromQuantity(LHSVal.getInt().getZExtValue()); Result = APValue(RHSVal.getLValueBase(), Offset); return true; } // All the following cases expect both operands to be an integer - if (!Result.isInt() || !RHSVal.isInt()) + if (!LHSVal.isInt() || !RHSVal.isInt()) return false; - APSInt& RHS = RHSVal.getInt(); + APSInt &LHS = LHSVal.getInt(); + APSInt &RHS = RHSVal.getInt(); switch (E->getOpcode()) { default: return Error(E->getOperatorLoc(), diag::note_invalid_subexpr_in_ice, E); - case BO_Mul: return Success(Result.getInt() * RHS, E); - case BO_Add: return Success(Result.getInt() + RHS, E); - case BO_Sub: return Success(Result.getInt() - RHS, E); - case BO_And: return Success(Result.getInt() & RHS, E); - case BO_Xor: return Success(Result.getInt() ^ RHS, E); - case BO_Or: return Success(Result.getInt() | RHS, E); + case BO_Mul: return Success(LHS * RHS, E); + case BO_Add: return Success(LHS + RHS, E); + case BO_Sub: return Success(LHS - RHS, E); + case BO_And: return Success(LHS & RHS, E); + case BO_Xor: return Success(LHS ^ RHS, E); + case BO_Or: return Success(LHS | RHS, E); case BO_Div: if (RHS == 0) return Error(E->getOperatorLoc(), diag::note_expr_divide_by_zero, E); - return Success(Result.getInt() / RHS, E); + return Success(LHS / RHS, E); case BO_Rem: if (RHS == 0) return Error(E->getOperatorLoc(), diag::note_expr_divide_by_zero, E); - return Success(Result.getInt() % RHS, E); + return Success(LHS % RHS, E); case BO_Shl: { // During constant-folding, a negative shift is an opposite shift. if (RHS.isSigned() && RHS.isNegative()) { @@ -1651,8 +1733,8 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { shift_left: unsigned SA - = (unsigned) RHS.getLimitedValue(Result.getInt().getBitWidth()-1); - return Success(Result.getInt() << SA, E); + = (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1); + return Success(LHS << SA, E); } case BO_Shr: { // During constant-folding, a negative shift is an opposite shift. @@ -1663,16 +1745,16 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { shift_right: unsigned SA = - (unsigned) RHS.getLimitedValue(Result.getInt().getBitWidth()-1); - return Success(Result.getInt() >> SA, E); + (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1); + return Success(LHS >> SA, E); } - case BO_LT: return Success(Result.getInt() < RHS, E); - case BO_GT: return Success(Result.getInt() > RHS, E); - case BO_LE: return Success(Result.getInt() <= RHS, E); - case BO_GE: return Success(Result.getInt() >= RHS, E); - case BO_EQ: return Success(Result.getInt() == RHS, E); - case BO_NE: return Success(Result.getInt() != RHS, E); + case BO_LT: return Success(LHS < RHS, E); + case BO_GT: return Success(LHS > RHS, E); + case BO_LE: return Success(LHS <= RHS, E); + case BO_GE: return Success(LHS >= RHS, E); + case BO_EQ: return Success(LHS == RHS, E); + case BO_NE: return Success(LHS != RHS, E); } } @@ -1833,7 +1915,7 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { if (E->getOpcode() == UO_LNot) { // LNot's operand isn't necessarily an integer, so we handle it specially. bool bres; - if (!HandleConversionToBool(E->getSubExpr(), bres, Info)) + if (!EvaluateAsBooleanCondition(E->getSubExpr(), bres, Info)) return false; return Success(!bres, E); } @@ -1918,7 +2000,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_LValueToRValue: case CK_NoOp: - return Visit(E->getSubExpr()); + return ExprEvaluatorBaseTy::VisitCastExpr(E); case CK_MemberPointerToBoolean: case CK_PointerToBoolean: @@ -1927,7 +2009,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_FloatingComplexToBoolean: case CK_IntegralComplexToBoolean: { bool BoolResult; - if (!HandleConversionToBool(SubExpr, BoolResult, Info)) + if (!EvaluateAsBooleanCondition(SubExpr, BoolResult, Info)) return false; return Success(BoolResult, E); } @@ -2050,15 +2132,13 @@ public: bool VisitUnaryReal(const UnaryOperator *E); bool VisitUnaryImag(const UnaryOperator *E); - bool VisitDeclRefExpr(const DeclRefExpr *E); - // FIXME: Missing: array subscript of vector, member of vector, // ImplicitValueInitExpr }; } // end anonymous namespace static bool EvaluateFloat(const Expr* E, APFloat& Result, EvalInfo &Info) { - assert(E->getType()->isRealFloatingType()); + assert(E->isRValue() && E->getType()->isRealFloatingType()); return FloatExprEvaluator(Info, Result).Visit(E); } @@ -2141,21 +2221,6 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { } } -bool FloatExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) { - if (ExprEvaluatorBaseTy::VisitDeclRefExpr(E)) - return true; - - const VarDecl *VD = dyn_cast(E->getDecl()); - if (VD && IsConstNonVolatile(VD->getType())) { - APValue *V = EvaluateVarDeclInit(Info, VD); - if (V && V->isFloat()) { - Result = V->getFloat(); - return true; - } - } - return false; -} - bool FloatExprEvaluator::VisitUnaryReal(const UnaryOperator *E) { if (E->getSubExpr()->getType()->isAnyComplexType()) { ComplexValue CV; @@ -2245,11 +2310,7 @@ bool FloatExprEvaluator::VisitCastExpr(const CastExpr *E) { switch (E->getCastKind()) { default: - return false; - - case CK_LValueToRValue: - case CK_NoOp: - return Visit(SubExpr); + return ExprEvaluatorBaseTy::VisitCastExpr(E); case CK_IntegralToFloating: { APSInt IntResult; @@ -2317,7 +2378,7 @@ public: static bool EvaluateComplex(const Expr *E, ComplexValue &Result, EvalInfo &Info) { - assert(E->getType()->isAnyComplexType()); + assert(E->isRValue() && E->getType()->isAnyComplexType()); return ComplexExprEvaluator(Info, Result).Visit(E); } @@ -2390,7 +2451,7 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_LValueToRValue: case CK_NoOp: - return Visit(E->getSubExpr()); + return ExprEvaluatorBaseTy::VisitCastExpr(E); case CK_Dependent: case CK_GetObjCProperty: @@ -2634,27 +2695,28 @@ bool ComplexExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { //===----------------------------------------------------------------------===// static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) { - if (E->getType()->isVectorType()) { + // In C, function designators are not lvalues, but we evaluate them as if they + // are. + if (E->isGLValue() || E->getType()->isFunctionType()) { + LValue LV; + if (!EvaluateLValue(E, LV, Info)) + return false; + LV.moveInto(Result); + } else if (E->getType()->isVectorType()) { if (!EvaluateVector(E, Result, Info)) return false; } else if (E->getType()->isIntegralOrEnumerationType()) { if (!IntExprEvaluator(Info, Result).Visit(E)) return false; - if (Result.isLValue() && - !IsGlobalLValue(Result.getLValueBase())) - return false; } else if (E->getType()->hasPointerRepresentation()) { LValue LV; if (!EvaluatePointer(E, LV, Info)) return false; - if (!IsGlobalLValue(LV.Base)) - return false; LV.moveInto(Result); } else if (E->getType()->isRealFloatingType()) { llvm::APFloat F(0.0); if (!EvaluateFloat(E, F, Info)) return false; - Result = APValue(F); } else if (E->getType()->isAnyComplexType()) { ComplexValue C; @@ -2670,25 +2732,43 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) { /// Evaluate - Return true if this is a constant which we can fold using /// 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. +/// in Result. If this expression is a glvalue, an lvalue-to-rvalue conversion +/// will be applied to the result. bool Expr::Evaluate(EvalResult &Result, const ASTContext &Ctx) const { EvalInfo Info(Ctx, Result); - return ::Evaluate(Result.Val, Info, this); + + if (!::Evaluate(Result.Val, Info, this)) + return false; + + if (isGLValue()) { + LValue LV; + LV.setFrom(Result.Val); + return HandleLValueToRValueConversion(Info, getType(), LV, Result.Val); + } else if (Result.Val.isLValue()) { + // FIXME: We don't allow expressions to fold to references to locals. Code + // which calls Evaluate() isn't ready for that yet. For instance, we don't + // have any checking that the initializer of a pointer in C is an address + // constant. + if (!IsGlobalLValue(Result.Val.getLValueBase())) + return false; + } + + return true; } bool Expr::EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx) const { - EvalStatus Scratch; - EvalInfo Info(Ctx, Scratch); - - return HandleConversionToBool(this, Result, Info); + EvalResult Scratch; + return Evaluate(Scratch, Ctx) && HandleConversionToBool(Scratch.Val, Result); } bool Expr::EvaluateAsInt(APSInt &Result, const ASTContext &Ctx) const { - EvalStatus Scratch; - EvalInfo Info(Ctx, Scratch); - - return EvaluateInteger(this, Result, Info) && !Scratch.HasSideEffects; + EvalResult ExprResult; + if (!Evaluate(ExprResult, Ctx) || ExprResult.HasSideEffects || + !ExprResult.Val.isInt()) + return false; + Result = ExprResult.Val.getInt(); + return true; } bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const { @@ -3184,11 +3264,7 @@ bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx, if (Loc) *Loc = d.Loc; return false; } - EvalResult EvalResult; - if (!Evaluate(EvalResult, Ctx)) + if (!EvaluateAsInt(Result, Ctx)) llvm_unreachable("ICE cannot be evaluated!"); - assert(!EvalResult.HasSideEffects && "ICE with side effects!"); - assert(EvalResult.Val.isInt() && "ICE that isn't integer!"); - Result = EvalResult.Val.getInt(); return true; } diff --git a/clang/test/SemaCXX/i-c-e-cxx.cpp b/clang/test/SemaCXX/i-c-e-cxx.cpp index ba60054f2e00..271ac987afed 100644 --- a/clang/test/SemaCXX/i-c-e-cxx.cpp +++ b/clang/test/SemaCXX/i-c-e-cxx.cpp @@ -66,3 +66,6 @@ const int nonconst = 1.0; int arr[nonconst]; // expected-warning {{folded to constant array as an extension}} const int castfloat = static_cast(1.0); int arr2[castfloat]; // ok + +extern const int &Recurse1; +const int &Recurse2 = Recurse1, &Recurse1 = Recurse2;