diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2011-12-09 22:58:01 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2011-12-09 22:58:01 +0000 |
commit | f48fdb0937e67f691393f9ffdf75653e5128ea13 (patch) | |
tree | 33b0dc89859845c093891fc0609366e429ebc3d9 /lib/AST/ExprConstant.cpp | |
parent | 0373fcc3e5b205cc26656c70d7dff737b0e08345 (diff) |
C++11 constant expressions: Don't use CheckICE in C++11; instead, determine
whether an expression is a (core) constant expression as a side-effect of
evaluation. This takes us from accepting far too few expressions as ICEs to
accepting slightly too many -- fixes for the remaining cases are coming next.
The diagnostics produced when an expression is found to be non-constant are
currently quite poor (with generic wording but reasonable source locations),
and will be improved in subsequent commits.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@146289 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/AST/ExprConstant.cpp')
-rw-r--r-- | lib/AST/ExprConstant.cpp | 663 |
1 files changed, 379 insertions, 284 deletions
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index c095f2166d..5162c625d1 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -298,6 +298,27 @@ namespace { bool atCallLimit() const { return CallStackDepth > getLangOpts().ConstexprCallDepth; } + + /// Diagnose that the evaluation does not produce a C++11 core constant + /// expression. + void CCEDiag(const Expr *E, SourceLocation Loc, diag::kind Diag) { + // Don't override a previous diagnostic. + if (EvalStatus.Diag == 0) { + EvalStatus.DiagLoc = Loc; + EvalStatus.Diag = Diag; + EvalStatus.DiagExpr = E; + } + } + + /// Diagnose that the evaluation cannot be folded. + void Diag(const Expr *E, SourceLocation Loc, diag::kind Diag) { + // If we have a prior diagnostic, it will be noting that the expression + // isn't a constant expression. This diagnostic is more important. + // FIXME: We might want to show both diagnostics to the user. + EvalStatus.DiagLoc = Loc; + EvalStatus.Diag = Diag; + EvalStatus.DiagExpr = E; + } }; CallStackFrame::CallStackFrame(EvalInfo &Info, const LValue *This, @@ -543,9 +564,12 @@ static bool IsGlobalLValue(APValue::LValueBase B) { /// Check that this reference or pointer core constant expression is a valid /// value for a constant expression. Type T should be either LValue or CCValue. template<typename T> -static bool CheckLValueConstantExpression(const T &LVal, APValue &Value) { - if (!IsGlobalLValue(LVal.getLValueBase())) +static bool CheckLValueConstantExpression(EvalInfo &Info, const Expr *E, + const T &LVal, APValue &Value) { + if (!IsGlobalLValue(LVal.getLValueBase())) { + Info.Diag(E, E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); return false; + } const SubobjectDesignator &Designator = LVal.getLValueDesignator(); // A constant expression must refer to an object or be a null pointer. @@ -564,12 +588,14 @@ static bool CheckLValueConstantExpression(const T &LVal, APValue &Value) { /// Check that this core constant expression value is a valid value for a /// constant expression, and if it is, produce the corresponding constant value. -static bool CheckConstantExpression(const CCValue &CCValue, APValue &Value) { +/// If not, report an appropriate diagnostic. +static bool CheckConstantExpression(EvalInfo &Info, const Expr *E, + const CCValue &CCValue, APValue &Value) { if (!CCValue.isLValue()) { Value = CCValue; return true; } - return CheckLValueConstantExpression(CCValue, Value); + return CheckLValueConstantExpression(Info, E, CCValue, Value); } const ValueDecl *GetLValueBaseDecl(const LValue &LVal) { @@ -840,13 +866,16 @@ static bool HandleLValueArrayAdjustment(EvalInfo &Info, LValue &LVal, } /// Try to evaluate the initializer for a variable declaration. -static bool EvaluateVarDeclInit(EvalInfo &Info, const VarDecl *VD, +static bool EvaluateVarDeclInit(EvalInfo &Info, const Expr *E, + const VarDecl *VD, CallStackFrame *Frame, CCValue &Result) { // If this is a parameter to an active constexpr function call, perform // argument substitution. if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(VD)) { - if (!Frame || !Frame->Arguments) + if (!Frame || !Frame->Arguments) { + Info.Diag(E, E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); return false; + } Result = Frame->Arguments[PVD->getFunctionScopeIndex()]; return true; } @@ -860,20 +889,26 @@ static bool EvaluateVarDeclInit(EvalInfo &Info, const VarDecl *VD, // Never evaluate the initializer of a weak variable. We can't be sure that // this is the definition which will be used. - if (VD->isWeak()) + if (VD->isWeak()) { + Info.Diag(E, E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); return false; + } const Expr *Init = VD->getAnyInitializer(); - if (!Init || Init->isValueDependent()) + if (!Init || Init->isValueDependent()) { + Info.Diag(E, E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); return false; + } if (APValue *V = VD->getEvaluatedValue()) { Result = CCValue(*V, CCValue::GlobalValue()); return !Result.isUninit(); } - if (VD->isEvaluatingValue()) + if (VD->isEvaluatingValue()) { + Info.Diag(E, E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); return false; + } VD->setEvaluatingValue(); @@ -894,6 +929,7 @@ static bool EvaluateVarDeclInit(EvalInfo &Info, const VarDecl *VD, // or a failed evaluation of the initializer should be reattempted each time // it is used. VD->setEvaluatedValue(APValue()); + Info.Diag(E, E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); return false; } @@ -923,10 +959,13 @@ static unsigned getBaseIndex(const CXXRecordDecl *Derived, } /// Extract the designated sub-object of an rvalue. -static bool ExtractSubobject(EvalInfo &Info, CCValue &Obj, QualType ObjType, +static bool ExtractSubobject(EvalInfo &Info, const Expr *E, + CCValue &Obj, QualType ObjType, const SubobjectDesignator &Sub, QualType SubType) { - if (Sub.Invalid || Sub.OnePastTheEnd) + if (Sub.Invalid || Sub.OnePastTheEnd) { + Info.Diag(E, E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); return false; + } if (Sub.Entries.empty()) return true; @@ -937,11 +976,12 @@ static bool ExtractSubobject(EvalInfo &Info, CCValue &Obj, QualType ObjType, if (ObjType->isArrayType()) { // Next subobject is an array element. const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(ObjType); - if (!CAT) - return false; + assert(CAT && "vla in literal type?"); uint64_t Index = Sub.Entries[I].ArrayIndex; - if (CAT->getSize().ule(Index)) + if (CAT->getSize().ule(Index)) { + Info.Diag(E, E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); return false; + } if (O->getArrayInitializedElts() > Index) O = &O->getArrayInitializedElt(Index); else @@ -953,8 +993,11 @@ static bool ExtractSubobject(EvalInfo &Info, CCValue &Obj, QualType ObjType, if (RD->isUnion()) { const FieldDecl *UnionField = O->getUnionField(); if (!UnionField || - UnionField->getCanonicalDecl() != Field->getCanonicalDecl()) + UnionField->getCanonicalDecl() != Field->getCanonicalDecl()) { + Info.Diag(E, E->getExprLoc(), + diag::note_invalid_subexpr_in_const_expr); return false; + } O = &O->getUnionValue(); } else O = &O->getStructField(Field->getFieldIndex()); @@ -967,8 +1010,10 @@ static bool ExtractSubobject(EvalInfo &Info, CCValue &Obj, QualType ObjType, ObjType = Info.Ctx.getRecordType(Base); } - if (O->isUninit()) + if (O->isUninit()) { + Info.Diag(E, E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); return false; + } } Obj = CCValue(*O, CCValue::GlobalValue()); @@ -980,17 +1025,23 @@ static bool ExtractSubobject(EvalInfo &Info, CCValue &Obj, QualType ObjType, /// for looking up the glvalue referred to by an entity of reference type. /// /// \param Info - Information about the ongoing evaluation. +/// \param Conv - The expression for which we are performing the conversion. +/// Used for diagnostics. /// \param Type - The type we expect this conversion to produce. /// \param LVal - The glvalue on which we are attempting to perform this action. /// \param RVal - The produced value will be placed here. -static bool HandleLValueToRValueConversion(EvalInfo &Info, QualType Type, +static bool HandleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, + QualType Type, const LValue &LVal, CCValue &RVal) { const Expr *Base = LVal.Base.dyn_cast<const Expr*>(); CallStackFrame *Frame = LVal.Frame; - // FIXME: Indirection through a null pointer deserves a diagnostic. - if (!LVal.Base) + if (!LVal.Base) { + // FIXME: Indirection through a null pointer deserves a specific diagnostic. + Info.Diag(Conv, Conv->getExprLoc(), + diag::note_invalid_subexpr_in_const_expr); return false; + } if (const ValueDecl *D = LVal.Base.dyn_cast<const ValueDecl*>()) { // In C++98, const, non-volatile integers initialized with ICEs are ICEs. @@ -1005,22 +1056,32 @@ static bool HandleLValueToRValueConversion(EvalInfo &Info, QualType Type, // objects in constant expressions), but lvalue-to-rvalue conversions on // them are not permitted. const VarDecl *VD = dyn_cast<VarDecl>(D); - if (!VD || VD->isInvalidDecl()) + if (!VD || VD->isInvalidDecl()) { + Info.Diag(Conv, Conv->getExprLoc(), + diag::note_invalid_subexpr_in_const_expr); return false; + } + QualType VT = VD->getType(); if (!isa<ParmVarDecl>(VD)) { - if (!IsConstNonVolatile(VT)) + if (!IsConstNonVolatile(VT)) { + Info.Diag(Conv, Conv->getExprLoc(), + diag::note_invalid_subexpr_in_const_expr); return false; + } // FIXME: Allow folding of values of any literal type in all languages. if (!VT->isIntegralOrEnumerationType() && !VT->isRealFloatingType() && - !VD->isConstexpr()) + !VD->isConstexpr()) { + Info.Diag(Conv, Conv->getExprLoc(), + diag::note_invalid_subexpr_in_const_expr); return false; + } } - if (!EvaluateVarDeclInit(Info, VD, Frame, RVal)) + if (!EvaluateVarDeclInit(Info, Conv, VD, Frame, RVal)) return false; if (isa<ParmVarDecl>(VD) || !VD->getAnyInitializer()->isLValue()) - return ExtractSubobject(Info, RVal, VT, LVal.Designator, Type); + return ExtractSubobject(Info, Conv, RVal, VT, LVal.Designator, Type); // The declaration was initialized by an lvalue, with no lvalue-to-rvalue // conversion. This happens when the declaration and the lvalue should be @@ -1036,13 +1097,19 @@ static bool HandleLValueToRValueConversion(EvalInfo &Info, QualType Type, // FIXME: Support PredefinedExpr, ObjCEncodeExpr, MakeStringConstant if (const StringLiteral *S = dyn_cast<StringLiteral>(Base)) { const SubobjectDesignator &Designator = LVal.Designator; - if (Designator.Invalid || Designator.Entries.size() != 1) + if (Designator.Invalid || Designator.Entries.size() != 1) { + Info.Diag(Conv, Conv->getExprLoc(), + diag::note_invalid_subexpr_in_const_expr); return false; + } assert(Type->isIntegerType() && "string element not integer type"); uint64_t Index = Designator.Entries[0].ArrayIndex; - if (Index > S->getLength()) + if (Index > S->getLength()) { + Info.Diag(Conv, Conv->getExprLoc(), + diag::note_invalid_subexpr_in_const_expr); return false; + } APSInt Value(S->getCharByteWidth() * Info.Ctx.getCharWidth(), Type->isUnsignedIntegerType()); if (Index < S->getLength()) @@ -1063,10 +1130,14 @@ static bool HandleLValueToRValueConversion(EvalInfo &Info, QualType Type, assert(!Info.getLangOpts().CPlusPlus && "lvalue compound literal in c++?"); if (!Evaluate(RVal, Info, CLE->getInitializer())) return false; - } else + } else { + Info.Diag(Conv, Conv->getExprLoc(), + diag::note_invalid_subexpr_in_const_expr); return false; + } - return ExtractSubobject(Info, RVal, Base->getType(), LVal.Designator, Type); + return ExtractSubobject(Info, Conv, RVal, Base->getType(), LVal.Designator, + Type); } /// Build an lvalue for the object argument of a member function call. @@ -1270,11 +1341,15 @@ static bool EvaluateArgs(ArrayRef<const Expr*> Args, ArgVector &ArgValues, } /// Evaluate a function call. -static bool HandleFunctionCall(const LValue *This, ArrayRef<const Expr*> Args, - const Stmt *Body, EvalInfo &Info, - CCValue &Result) { - if (Info.atCallLimit()) +static bool HandleFunctionCall(const Expr *CallExpr, const LValue *This, + ArrayRef<const Expr*> Args, const Stmt *Body, + EvalInfo &Info, CCValue &Result) { + if (Info.atCallLimit()) { + // FIXME: Add a specific proper diagnostic for this. + Info.Diag(CallExpr, CallExpr->getExprLoc(), + diag::note_invalid_subexpr_in_const_expr); return false; + } ArgVector ArgValues(Args.size()); if (!EvaluateArgs(Args, ArgValues, Info)) @@ -1285,13 +1360,17 @@ static bool HandleFunctionCall(const LValue *This, ArrayRef<const Expr*> Args, } /// Evaluate a constructor call. -static bool HandleConstructorCall(const LValue &This, +static bool HandleConstructorCall(const Expr *CallExpr, const LValue &This, ArrayRef<const Expr*> Args, const CXXConstructorDecl *Definition, EvalInfo &Info, APValue &Result) { - if (Info.atCallLimit()) + if (Info.atCallLimit()) { + // FIXME: Add a specific diagnostic for this. + Info.Diag(CallExpr, CallExpr->getExprLoc(), + diag::note_invalid_subexpr_in_const_expr); return false; + } ArgVector ArgValues(Args.size()); if (!EvaluateArgs(Args, ArgValues, Info)) @@ -1349,6 +1428,8 @@ static bool HandleConstructorCall(const LValue &This, return false; } else { // FIXME: handle indirect field initializers + Info.Diag((*I)->getInit(), (*I)->getInit()->getExprLoc(), + diag::note_invalid_subexpr_in_const_expr); return false; } } @@ -1466,16 +1547,14 @@ public: //===----------------------------------------------------------------------===// namespace { -template <class Derived, typename RetTy=void> +// FIXME: RetTy is always bool. Remove it. +template <class Derived, typename RetTy=bool> class ExprEvaluatorBase : public ConstStmtVisitor<Derived, RetTy> { private: RetTy DerivedSuccess(const CCValue &V, const Expr *E) { return static_cast<Derived*>(this)->Success(V, E); } - RetTy DerivedError(const Expr *E) { - return static_cast<Derived*>(this)->Error(E); - } RetTy DerivedValueInitialization(const Expr *E) { return static_cast<Derived*>(this)->ValueInitialization(E); } @@ -1485,7 +1564,21 @@ protected: typedef ConstStmtVisitor<Derived, RetTy> StmtVisitorTy; typedef ExprEvaluatorBase ExprEvaluatorBaseTy; - RetTy ValueInitialization(const Expr *E) { return DerivedError(E); } + void CCEDiag(const Expr *E, diag::kind D) { + Info.CCEDiag(E, E->getExprLoc(), D); + } + + /// Report an evaluation error. This should only be called when an error is + /// first discovered. When propagating an error, just return false. + bool Error(const Expr *E, diag::kind D) { + Info.Diag(E, E->getExprLoc(), D); + return false; + } + bool Error(const Expr *E) { + return Error(E, diag::note_invalid_subexpr_in_const_expr); + } + + RetTy ValueInitialization(const Expr *E) { return Error(E); } public: ExprEvaluatorBase(EvalInfo &Info) : Info(Info) {} @@ -1494,7 +1587,7 @@ public: llvm_unreachable("Expression evaluator should not be called on stmts"); } RetTy VisitExpr(const Expr *E) { - return DerivedError(E); + return Error(E); } RetTy VisitParenExpr(const ParenExpr *E) @@ -1515,7 +1608,7 @@ public: RetTy VisitBinaryOperator(const BinaryOperator *E) { switch (E->getOpcode()) { default: - return DerivedError(E); + return Error(E); case BO_Comma: VisitIgnoredValue(E->getLHS()); @@ -1527,7 +1620,7 @@ public: if (!HandleMemberPointerAccess(Info, E, Obj)) return false; CCValue Result; - if (!HandleLValueToRValueConversion(Info, E->getType(), Obj, Result)) + if (!HandleLValueToRValueConversion(Info, E, E->getType(), Obj, Result)) return false; return DerivedSuccess(Result, E); } @@ -1537,11 +1630,11 @@ public: RetTy VisitBinaryConditionalOperator(const BinaryConditionalOperator *E) { OpaqueValueEvaluation opaque(Info, E->getOpaqueValue(), E->getCommon()); if (opaque.hasError()) - return DerivedError(E); + return false; bool cond; if (!EvaluateAsBooleanCondition(E->getCond(), cond, Info)) - return DerivedError(E); + return false; return StmtVisitorTy::Visit(cond ? E->getTrueExpr() : E->getFalseExpr()); } @@ -1549,7 +1642,7 @@ public: RetTy VisitConditionalOperator(const ConditionalOperator *E) { bool BoolResult; if (!EvaluateAsBooleanCondition(E->getCond(), BoolResult, Info)) - return DerivedError(E); + return false; Expr *EvalExpr = BoolResult ? E->getTrueExpr() : E->getFalseExpr(); return StmtVisitorTy::Visit(EvalExpr); @@ -1560,10 +1653,10 @@ public: if (!Value) { const Expr *Source = E->getSourceExpr(); if (!Source) - return DerivedError(E); + return Error(E); if (Source == E) { // sanity checking. assert(0 && "OpaqueValueExpr recursively refers to itself"); - return DerivedError(E); + return Error(E); } return StmtVisitorTy::Visit(Source); } @@ -1580,39 +1673,46 @@ public: // Extract function decl and 'this' pointer from the callee. if (CalleeType->isSpecificBuiltinType(BuiltinType::BoundMember)) { + const ValueDecl *Member = 0; if (const MemberExpr *ME = dyn_cast<MemberExpr>(Callee)) { // Explicit bound member calls, such as x.f() or p->g(); if (!EvaluateObjectArgument(Info, ME->getBase(), ThisVal)) - return DerivedError(ME->getBase()); + return false; + Member = ME->getMemberDecl(); This = &ThisVal; - FD = dyn_cast<FunctionDecl>(ME->getMemberDecl()); - if (!FD) - return DerivedError(ME); } else if (const BinaryOperator *BE = dyn_cast<BinaryOperator>(Callee)) { // Indirect bound member calls ('.*' or '->*'). - const ValueDecl *Member = HandleMemberPointerAccess(Info, BE, ThisVal, - false); + Member = HandleMemberPointerAccess(Info, BE, ThisVal, false); + if (!Member) return false; This = &ThisVal; - FD = dyn_cast_or_null<FunctionDecl>(Member); - if (!FD) - return DerivedError(Callee); } else - return DerivedError(Callee); + return Error(Callee); + + FD = dyn_cast<FunctionDecl>(Member); + if (!FD) + return Error(Callee); } else if (CalleeType->isFunctionPointerType()) { CCValue Call; - if (!Evaluate(Call, Info, Callee) || !Call.isLValue() || - !Call.getLValueOffset().isZero()) - return DerivedError(Callee); + if (!Evaluate(Call, Info, Callee)) + return false; + if (!Call.isLValue() || !Call.getLValueOffset().isZero()) + return Error(Callee); FD = dyn_cast_or_null<FunctionDecl>( Call.getLValueBase().dyn_cast<const ValueDecl*>()); if (!FD) - return DerivedError(Callee); + return Error(Callee); // Overloaded operator calls to member functions are represented as normal // calls with '*this' as the first argument. const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD); if (MD && !MD->isStatic()) { + // FIXME: When selecting an implicit conversion for an overloaded + // operator delete, we sometimes try to evaluate calls to conversion + // operators without a 'this' parameter! + if (Args.empty()) + return Error(E); + if (!EvaluateObjectArgument(Info, Args[0], ThisVal)) return false; This = &ThisVal; @@ -1621,21 +1721,23 @@ public: // Don't call function pointers which have been cast to some other type. if (!Info.Ctx.hasSameType(CalleeType->getPointeeType(), FD->getType())) - return DerivedError(E); + return Error(E); } else - return DerivedError(E); + return Error(E); const FunctionDecl *Definition; Stmt *Body = FD->getBody(Definition); CCValue CCResult; APValue Result; - if (Body && Definition->isConstexpr() && !Definition->isInvalidDecl() && - HandleFunctionCall(This, Args, Body, Info, CCResult) && - CheckConstantExpression(CCResult, Result)) - return DerivedSuccess(CCValue(Result, CCValue::GlobalValue()), E); + if (!Body || !Definition->isConstexpr() || Definition->isInvalidDecl()) + return Error(E); + + if (!HandleFunctionCall(E, This, Args, Body, Info, CCResult) || + !CheckConstantExpression(Info, E, CCResult, Result)) + return false; - return DerivedError(E); + return DerivedSuccess(CCValue(Result, CCValue::GlobalValue()), E); } RetTy VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) { @@ -1648,7 +1750,7 @@ public: if (E->getNumInits() == 1) return StmtVisitorTy::Visit(E->getInit(0)); } - return DerivedError(E); + return Error(E); } RetTy VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) { return DerivedValueInitialization(E); @@ -1671,7 +1773,7 @@ public: QualType BaseTy = E->getBase()->getType(); const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl()); - if (!FD) return false; + if (!FD) return Error(E); assert(!FD->getType()->isReferenceType() && "prvalue reference?"); assert(BaseTy->getAs<RecordType>()->getDecl()->getCanonicalDecl() == FD->getParent()->getCanonicalDecl() && "record / field mismatch"); @@ -1679,7 +1781,7 @@ public: SubobjectDesignator Designator; Designator.addDecl(FD); - return ExtractSubobject(Info, Val, BaseTy, Designator, E->getType()) && + return ExtractSubobject(Info, E, Val, BaseTy, Designator, E->getType()) && DerivedSuccess(Val, E); } @@ -1693,16 +1795,16 @@ public: case CK_LValueToRValue: { LValue LVal; - if (EvaluateLValue(E->getSubExpr(), LVal, Info)) { - CCValue RVal; - if (HandleLValueToRValueConversion(Info, E->getType(), LVal, RVal)) - return DerivedSuccess(RVal, E); - } - break; + if (!EvaluateLValue(E->getSubExpr(), LVal, Info)) + return false; + CCValue RVal; + if (!HandleLValueToRValueConversion(Info, E, E->getType(), LVal, RVal)) + return false; + return DerivedSuccess(RVal, E); } } - return DerivedError(E); + return Error(E); } /// Visit a value which is evaluated, but whose value is ignored. @@ -1740,9 +1842,6 @@ public: Result.setFrom(V); return true; } - bool Error(const Expr *E) { - return false; - } bool CheckValidLValue() { // C++11 [basic.lval]p1: An lvalue designates a function or an object. Hence @@ -1768,7 +1867,7 @@ public: const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl()); // FIXME: Handle IndirectFieldDecls - if (!FD) return false; + if (!FD) return this->Error(E); assert(BaseTy->getAs<RecordType>()->getDecl()->getCanonicalDecl() == FD->getParent()->getCanonicalDecl() && "record / field mismatch"); (void)BaseTy; @@ -1777,7 +1876,7 @@ public: if (FD->getType()->isReferenceType()) { CCValue RefValue; - if (!HandleLValueToRValueConversion(this->Info, FD->getType(), Result, + if (!HandleLValueToRValueConversion(this->Info, E, FD->getType(), Result, RefValue)) return false; return Success(RefValue, E); @@ -1927,10 +2026,9 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) { } CCValue V; - if (EvaluateVarDeclInit(Info, VD, Info.CurrentCall, V)) - return Success(V, E); - - return Error(E); + if (!EvaluateVarDeclInit(Info, E, VD, Info.CurrentCall, V)) + return false; + return Success(V, E); } bool LValueExprEvaluator::VisitMaterializeTemporaryExpr( @@ -1949,7 +2047,7 @@ bool LValueExprEvaluator::VisitMaterializeTemporaryExpr( // FIXME: The AST should contain an lvalue-to-rvalue node for such cases. if (!Visit(E->GetTemporaryExpr())) return false; - if (!HandleLValueToRValueConversion(Info, E->getType(), Result, + if (!HandleLValueToRValueConversion(Info, E, E->getType(), Result, Info.CurrentCall->Temporaries[E])) return false; Result.set(E, Info.CurrentCall); @@ -1986,7 +2084,7 @@ 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; + return Error(E); if (!EvaluatePointer(E->getBase(), Result, Info)) return false; @@ -2029,9 +2127,6 @@ public: Result.setFrom(V); return true; } - bool Error(const Stmt *S) { - return false; - } bool ValueInitialization(const Expr *E) { return Success((Expr*)0); } @@ -2047,11 +2142,11 @@ public: bool VisitBlockExpr(const BlockExpr *E) { if (!E->getBlockDecl()->hasCaptures()) return Success(E); - return false; + return Error(E); } bool VisitCXXThisExpr(const CXXThisExpr *E) { if (!Info.CurrentCall->This) - return false; + return Error(E); Result = *Info.CurrentCall->This; return true; } @@ -2213,9 +2308,6 @@ public: Result.setFrom(V); return true; } - bool Error(const Stmt *S) { - return false; - } bool ValueInitialization(const Expr *E) { return Success((const ValueDecl*)0); } @@ -2253,11 +2345,11 @@ bool MemberPointerExprEvaluator::VisitCastExpr(const CastExpr *E) { assert(!(*PathI)->isVirtual() && "memptr cast through vbase"); const CXXRecordDecl *Derived = (*PathI)->getType()->getAsCXXRecordDecl(); if (!Result.castToDerived(Derived)) - return false; + return Error(E); } const Type *FinalTy = E->getType()->castAs<MemberPointerType>()->getClass(); if (!Result.castToDerived(FinalTy->getAsCXXRecordDecl())) - return false; + return Error(E); return true; } @@ -2269,7 +2361,7 @@ bool MemberPointerExprEvaluator::VisitCastExpr(const CastExpr *E) { assert(!(*PathI)->isVirtual() && "memptr cast through vbase"); const CXXRecordDecl *Base = (*PathI)->getType()->getAsCXXRecordDecl(); if (!Result.castToBase(Base)) - return false; + return Error(E); } return true; } @@ -2296,9 +2388,8 @@ namespace { : ExprEvaluatorBaseTy(info), This(This), Result(Result) {} bool Success(const CCValue &V, const Expr *E) { - return CheckConstantExpression(V, Result); + return CheckConstantExpression(Info, E, V, Result); } - bool Error(const Expr *E) { return false; } bool VisitCastExpr(const CastExpr *E); bool VisitInitListExpr(const InitListExpr *E); @@ -2317,9 +2408,10 @@ bool RecordExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_DerivedToBase: case CK_UncheckedDerivedToBase: { CCValue DerivedObject; - if (!Evaluate(DerivedObject, Info, E->getSubExpr()) || - !DerivedObject.isStruct()) + if (!Evaluate(DerivedObject, Info, E->getSubExpr())) return false; + if (!DerivedObject.isStruct()) + return Error(E->getSubExpr()); // Derived-to-base rvalue conversion: just slice off the derived part. APValue *Value = &DerivedObject; @@ -2392,7 +2484,7 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) { FD->getBody(Definition); if (!Definition || !Definition->isConstexpr() || Definition->isInvalidDecl()) - return false; + return Error(E); // FIXME: Elide the copy/move construction wherever we can. if (E->isElidable()) @@ -2401,8 +2493,9 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) { return Visit(ME->GetTemporaryExpr()); llvm::ArrayRef<const Expr*> Args(E->getArgs(), E->getNumArgs()); - return HandleConstructorCall(This, Args, cast<CXXConstructorDecl>(Definition), - Info, Result); + return HandleConstructorCall(E, This, Args, + cast<CXXConstructorDecl>(Definition), Info, + Result); } static bool EvaluateRecord(const Expr *E, const LValue &This, @@ -2486,7 +2579,6 @@ namespace { Result = V; return true; } - bool Error(const Expr *E) { return false; } bool ValueInitialization(const Expr *E); bool VisitUnaryReal(const UnaryOperator *E) @@ -2520,12 +2612,12 @@ bool VectorExprEvaluator::VisitCastExpr(const CastExpr* E) { if (SETy->isIntegerType()) { APSInt IntResult; if (!EvaluateInteger(SE, IntResult, Info)) - return Error(E); + return false; Val = APValue(IntResult); } else if (SETy->isRealFloatingType()) { APFloat F(0.0); if (!EvaluateFloat(SE, F, Info)) - return Error(E); + return false; Val = APValue(F); } else { return Error(E); @@ -2563,12 +2655,12 @@ VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) { if (EltTy->isIntegerType()) { llvm::APSInt sInt(32); if (!EvaluateInteger(E->getInit(0), sInt, Info)) - return Error(E); + return false; InitValue = APValue(sInt); } else { llvm::APFloat f(0.0); if (!EvaluateFloat(E->getInit(0), f, Info)) - return Error(E); + return false; InitValue = APValue(f); } for (unsigned i = 0; i < NumElements; i++) { @@ -2580,7 +2672,7 @@ VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) { llvm::APSInt sInt(32); if (i < NumInits) { if (!EvaluateInteger(E->getInit(i), sInt, Info)) - return Error(E); + return false; } else { sInt = Info.Ctx.MakeIntValue(0, EltTy); } @@ -2589,7 +2681,7 @@ VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) { llvm::APFloat f(0.0); if (i < NumInits) { if (!EvaluateFloat(E->getInit(i), f, Info)) - return Error(E); + return false; } else { f = APFloat::getZero(Info.Ctx.getFloatTypeSemantics(EltTy)); } @@ -2639,13 +2731,12 @@ namespace { Result = V; return true; } - bool Error(const Expr *E) { return false; } bool ValueInitialization(const Expr *E) { const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(E->getType()); if (!CAT) - return false; + return Error(E); Result = APValue(APValue::UninitArray(), 0, CAT->getSize().getZExtValue()); @@ -2674,7 +2765,7 @@ static bool EvaluateArray(const Expr *E, const LValue &This, bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) { const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(E->getType()); if (!CAT) - return false; + return Error(E); Result = APValue(APValue::UninitArray(), E->getNumInits(), CAT->getSize().getZExtValue()); @@ -2703,7 +2794,7 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) { bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) { const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(E->getType()); if (!CAT) - return false; + return Error(E); Result = APValue(APValue::UninitArray(), 0, CAT->getSize().getZExtValue()); if (!Result.hasArrayFiller()) @@ -2714,7 +2805,7 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) { FD->getBody(Definition); if (!Definition || !Definition->isConstexpr() || Definition->isInvalidDecl()) - return false; + return Error(E); // FIXME: The Subobject here isn't necessarily right. This rarely matters, // but sometimes does: @@ -2723,7 +2814,7 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) { LValue Subobject = This; Subobject.Designator.addIndex(0); llvm::ArrayRef<const Expr*> Args(E->getArgs(), E->getNumArgs()); - return HandleConstructorCall(Subobject, Args, + return HandleConstructorCall(E, Subobject, Args, cast<CXXConstructorDecl>(Definition), Info, Result.getArrayFiller()); } @@ -2777,17 +2868,6 @@ public: return Success(Size.getQuantity(), E); } - - bool Error(SourceLocation L, diag::kind D, const Expr *E) { - // Take the first error. - if (Info.EvalStatus.Diag == 0) { - Info.EvalStatus.DiagLoc = L; - Info.EvalStatus.Diag = D; - Info.EvalStatus.DiagExpr = E; - } - return false; - } - bool Success(const CCValue &V, const Expr *E) { if (V.isLValue()) { Result = V; @@ -2795,9 +2875,6 @@ public: } return Success(V.getInt(), E); } - bool Error(const Expr *E) { - return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E); - } bool ValueInitialization(const Expr *E) { return Success(0, E); } @@ -2884,20 +2961,29 @@ private: /// 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, CCValue &Result, +static bool EvaluateIntegerOrLValue(const Expr *E, CCValue &Result, EvalInfo &Info) { assert(E->isRValue() && E->getType()->isIntegralOrEnumerationType()); return IntExprEvaluator(Info, Result).Visit(E); } -static bool EvaluateInteger(const Expr* E, APSInt &Result, EvalInfo &Info) { +static bool EvaluateInteger(const Expr *E, APSInt &Result, EvalInfo &Info) { CCValue Val; - if (!EvaluateIntegerOrLValue(E, Val, Info) || !Val.isInt()) + if (!EvaluateIntegerOrLValue(E, Val, Info)) + return false; + if (!Val.isInt()) { + // FIXME: It would be better to produce the diagnostic for casting + // a pointer to an integer. + Info.Diag(E, E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); return false; + } Result = Val.getInt(); return true; } +/// Check whether the given declaration can be directly converted to an integral +/// rvalue. If not, no diagnostic is produced; there are other things we can +/// try. bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) { // Enums are integer constant exprs. if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D)) { @@ -3007,7 +3093,7 @@ bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(const CallExpr *E) { T->isFunctionType() || T->isVariablyModifiedType() || T->isDependentType()) - return false; + return Error(E); CharUnits Size = Info.Ctx.getTypeSizeInChars(T); CharUnits Offset = Base.getLValueOffset(); @@ -3036,7 +3122,7 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { return Success(0, E); } - return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E); + return Error(E); } case Builtin::BI__builtin_classify_type: @@ -3114,7 +3200,7 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { return Success(Str.size(), E); } - return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E); + return Error(E); case Builtin::BI__atomic_is_lock_free: { APSInt SizeVal; @@ -3138,7 +3224,7 @@ bool IntExprEvaluator::Visi |