diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 0a608707d545..46330a400fa2 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -1274,7 +1274,7 @@ public: CanQualType getCanonicalParamType(QualType T) const; /// \brief Determine whether the given types are equivalent. - bool hasSameType(QualType T1, QualType T2) { + bool hasSameType(QualType T1, QualType T2) const { return getCanonicalType(T1) == getCanonicalType(T2); } @@ -1294,7 +1294,7 @@ public: /// \brief Determine whether the given types are equivalent after /// cvr-qualifiers have been removed. - bool hasSameUnqualifiedType(QualType T1, QualType T2) { + bool hasSameUnqualifiedType(QualType T1, QualType T2) const { return getCanonicalType(T1).getTypePtr() == getCanonicalType(T2).getTypePtr(); } diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index e0f5e6015797..ad686187c496 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 26ea2256d45f..d59d79ec69be 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -148,10 +148,13 @@ static bool IsGlobalLValue(const Expr* E) { if (const CompoundLiteralExpr *CLE = dyn_cast(E)) return CLE->isFileScope(); + if (isa(E)) + return false; + 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 +186,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, @@ -263,6 +270,8 @@ static APFloat HandleIntToFloatCast(QualType DestType, QualType SrcType, /// Try to evaluate the initializer for a variable declaration. static APValue *EvaluateVarDeclInit(EvalInfo &Info, const VarDecl *VD) { + // FIXME: If this is a parameter to an active constexpr function call, perform + // substitution now. if (isa(VD)) return 0; @@ -278,10 +287,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()); @@ -289,11 +299,92 @@ static APValue *EvaluateVarDeclInit(EvalInfo &Info, const VarDecl *VD) { return VD->getEvaluatedValue(); } -bool IsConstNonVolatile(QualType T) { +static bool IsConstNonVolatile(QualType T) { Qualifiers Quals = T.getQualifiers(); return Quals.hasConst() && !Quals.hasVolatile(); } +bool HandleLValueToRValueConversion(EvalInfo &Info, QualType Type, + const LValue &LVal, APValue &RVal) { + const Expr *Base = LVal.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 (!LVal.Offset.isZero()) + return false; + + const Decl *D = 0; + + if (const DeclRefExpr *DRE = dyn_cast(Base)) { + // If the lvalue has been cast to some other type, don't try to read it. + // FIXME: Could simulate a bitcast here. + if (!Info.Ctx.hasSameUnqualifiedType(Type, DRE->getType())) + return false; + D = DRE->getDecl(); + } + + // FIXME: Static data members accessed via a MemberExpr are represented as + // that MemberExpr. We should use the Decl directly instead. + if (const MemberExpr *ME = dyn_cast(Base)) { + if (!Info.Ctx.hasSameUnqualifiedType(Type, ME->getType())) + return false; + D = ME->getMemberDecl(); + assert(!isa(D) && "shouldn't see fields here"); + } + + if (D) { + // In C++98, const, non-volatile integers initialized with ICEs are ICEs. + // In C++11, constexpr, non-volatile variables initialized with constant + // expressions are constant expressions too. + // In C, such things can also be folded, although they are not ICEs. + // + // FIXME: Allow folding any const variable of literal type initialized with + // a constant expression. For now, we only allow variables with integral and + // floating types to be folded. + const VarDecl *VD = dyn_cast(D); + if (!VD || !IsConstNonVolatile(VD->getType()) || + (!Type->isIntegralOrEnumerationType() && !Type->isRealFloatingType())) + return false; + + APValue *V = EvaluateVarDeclInit(Info, VD); + if (!V || V->isUninit()) + return false; + + if (!VD->getAnyInitializer()->isLValue()) { + RVal = *V; + return true; + } + + // The declaration was initialized by an lvalue, with no lvalue-to-rvalue + // conversion. This happens when the declaration and the lvalue should be + // considered synonymous, for instance when initializing an array of char + // from a string literal. Continue as if the initializer lvalue was the + // value we were originally given. + Base = V->getLValueBase(); + if (!V->getLValueOffset().isZero()) + 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(RVal, Info, CLE->getInitializer()); + } + + return false; +} + namespace { class HasSideEffect : public ConstStmtVisitor { @@ -454,7 +545,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 +553,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 +568,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 +587,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 +621,23 @@ 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). +// +// LValue evaluation produces values comprising a base expression of one of the +// following types: +// * DeclRefExpr +// * MemberExpr for a static member +// * CompoundLiteralExpr in C +// * StringLiteral +// * PredefinedExpr +// * ObjCEncodeExpr +// * AddrLabelExpr +// * BlockExpr +// * CallExpr for a MakeStringConstant builtin +// plus an offset in bytes. //===----------------------------------------------------------------------===// namespace { class LValueExprEvaluator @@ -530,6 +663,8 @@ public: return false; } + bool VisitVarDecl(const Expr *E, const VarDecl *VD); + bool VisitDeclRefExpr(const DeclRefExpr *E); bool VisitPredefinedExpr(const PredefinedExpr *E) { return Success(E); } bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E); @@ -542,13 +677,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,39 +692,52 @@ 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) { + assert((E->isGLValue() || E->getType()->isFunctionType() || + E->getType()->isVoidType() || isa(E)) && + "can't evaluate expression as an lvalue"); return LValueExprEvaluator(Info, Result).Visit(E); } bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) { - if (isa(E->getDecl())) { + if (isa(E->getDecl())) return Success(E); - } else if (const VarDecl* VD = dyn_cast(E->getDecl())) { - if (!VD->getType()->isReferenceType()) - return Success(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! + if (const VarDecl* VD = dyn_cast(E->getDecl())) + return VisitVarDecl(E, VD); + return Error(E); +} - // Check for recursive initializers of references. - if (PrevDecl == VD) - return Error(E); - PrevDecl = VD; - if (const Expr *Init = VD->getAnyInitializer()) - return Visit(Init); - } - } +bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) { + if (!VD->getType()->isReferenceType()) + return Success(E); - return ExprEvaluatorBaseTy::VisitDeclRefExpr(E); + APValue *V = EvaluateVarDeclInit(Info, VD); + if (V && !V->isUninit()) + return Success(*V, 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); } bool LValueExprEvaluator::VisitMemberExpr(const MemberExpr *E) { + // Handle static data members. + if (const VarDecl *VD = dyn_cast(E->getMemberDecl())) { + VisitIgnoredValue(E->getBase()); + return VisitVarDecl(E, VD); + } + QualType Ty; if (E->isArrow()) { if (!EvaluatePointer(E->getBase(), Result, Info)) @@ -617,6 +765,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 +836,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 +892,6 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { default: break; - case CK_NoOp: case CK_BitCast: case CK_CPointerToObjCPointerCast: case CK_BlockPointerToObjCPointerCast: @@ -810,7 +961,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 +1003,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 +1014,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 +1076,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 +1163,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 +1250,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 +1305,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 +1347,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 +1549,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 +1562,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 +1731,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 +1794,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 +1806,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 +1976,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); } @@ -1842,8 +1985,9 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { if (!E->getSubExpr()->getType()->isIntegralOrEnumerationType()) return false; - // Get the operand value into 'Result'. - if (!Visit(E->getSubExpr())) + // Get the operand value. + APValue Val; + if (!Evaluate(Val, Info, E->getSubExpr())) return false; switch (E->getOpcode()) { @@ -1854,16 +1998,16 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { case UO_Extension: // FIXME: Should extension allow i-c-e extension expressions in its scope? // If so, we could clear the diagnostic ID. - return true; + return Success(Val, E); case UO_Plus: - // The result is always just the subexpr. - return true; + // The result is just the value. + return Success(Val, E); case UO_Minus: - if (!Result.isInt()) return false; - return Success(-Result.getInt(), E); + if (!Val.isInt()) return false; + return Success(-Val.getInt(), E); case UO_Not: - if (!Result.isInt()) return false; - return Success(~Result.getInt(), E); + if (!Val.isInt()) return false; + return Success(~Val.getInt(), E); } } @@ -1918,7 +2062,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 +2071,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 +2194,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 +2283,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 +2372,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 +2440,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 +2513,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 +2757,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; @@ -2667,36 +2791,50 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) { return true; } + /// 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); + } + + // FIXME: We don't allow expressions to fold to pointers or references to + // locals. Code which calls Evaluate() isn't ready for that yet. + return !Result.Val.isLValue() || IsGlobalLValue(Result.Val.getLValueBase()); } 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 { EvalInfo Info(Ctx, Result); LValue LV; - if (EvaluateLValue(this, LV, Info) && - !Result.HasSideEffects && + if (EvaluateLValue(this, LV, Info) && !Result.HasSideEffects && IsGlobalLValue(LV.Base)) { LV.moveInto(Result.Val); return true; @@ -3193,11 +3331,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/CodeGenCXX/static-data-member.cpp b/clang/test/CodeGenCXX/static-data-member.cpp index b19067af61df..4eeda3d42867 100644 --- a/clang/test/CodeGenCXX/static-data-member.cpp +++ b/clang/test/CodeGenCXX/static-data-member.cpp @@ -64,3 +64,17 @@ namespace test3 { // CHECK-NEXT: br label // CHECK: ret void } + +// Test that we can fold member lookup expressions which resolve to static data +// members. +namespace test4 { + struct A { + static const int n = 76; + }; + + int f(A *a) { + // CHECK: define i32 @_ZN5test41fEPNS_1AE + // CHECK: ret i32 76 + return a->n; + } +} diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp index 89955701e62d..fdab28389372 100644 --- a/clang/test/SemaCXX/constant-expression-cxx11.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp @@ -26,3 +26,17 @@ namespace CaseStatements { } } } + +extern int &Recurse1; +int &Recurse2 = Recurse1, &Recurse1 = Recurse2; +constexpr int &Recurse3 = Recurse2; // expected-error {{must be initialized by a constant expression}} + +namespace MemberEnum { + struct WithMemberEnum { + enum E { A = 42 }; + } wme; + // FIXME: b's initializer is not treated as a constant expression yet, but we + // can at least fold it. + constexpr bool b = wme.A == 42; + int n[b]; +}