aboutsummaryrefslogtreecommitdiff
path: root/lib/AST/ExprConstant.cpp
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2011-12-09 22:58:01 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2011-12-09 22:58:01 +0000
commitf48fdb0937e67f691393f9ffdf75653e5128ea13 (patch)
tree33b0dc89859845c093891fc0609366e429ebc3d9 /lib/AST/ExprConstant.cpp
parent0373fcc3e5b205cc26656c70d7dff737b0e08345 (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.cpp663
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