summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp')
-rw-r--r--contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp828
1 files changed, 563 insertions, 265 deletions
diff --git a/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp b/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp
index fa652ba..df944e8 100644
--- a/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp
+++ b/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp
@@ -157,13 +157,13 @@ namespace {
/// True if the subobject was named in a manner not supported by C++11. Such
/// lvalues can still be folded, but they are not core constant expressions
/// and we cannot perform lvalue-to-rvalue conversions on them.
- bool Invalid : 1;
+ unsigned Invalid : 1;
/// Is this a pointer one past the end of an object?
- bool IsOnePastTheEnd : 1;
+ unsigned IsOnePastTheEnd : 1;
/// Indicator of whether the most-derived object is an array element.
- bool MostDerivedIsArrayElement : 1;
+ unsigned MostDerivedIsArrayElement : 1;
/// The length of the path to the most-derived object of which this is a
/// subobject.
@@ -477,6 +477,9 @@ namespace {
/// fold (not just why it's not strictly a constant expression)?
bool HasFoldFailureDiagnostic;
+ /// \brief Whether or not we're currently speculatively evaluating.
+ bool IsSpeculativelyEvaluating;
+
enum EvaluationMode {
/// Evaluate as a constant expression. Stop if we find that the expression
/// is not a constant expression.
@@ -541,7 +544,8 @@ namespace {
BottomFrame(*this, SourceLocation(), nullptr, nullptr, nullptr),
EvaluatingDecl((const ValueDecl *)nullptr),
EvaluatingDeclValue(nullptr), HasActiveDiagnostic(false),
- HasFoldFailureDiagnostic(false), EvalMode(Mode) {}
+ HasFoldFailureDiagnostic(false), IsSpeculativelyEvaluating(false),
+ EvalMode(Mode) {}
void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value) {
EvaluatingDecl = Base;
@@ -557,12 +561,12 @@ namespace {
return false;
if (NextCallIndex == 0) {
// NextCallIndex has wrapped around.
- Diag(Loc, diag::note_constexpr_call_limit_exceeded);
+ FFDiag(Loc, diag::note_constexpr_call_limit_exceeded);
return false;
}
if (CallStackDepth <= getLangOpts().ConstexprCallDepth)
return true;
- Diag(Loc, diag::note_constexpr_depth_limit_exceeded)
+ FFDiag(Loc, diag::note_constexpr_depth_limit_exceeded)
<< getLangOpts().ConstexprCallDepth;
return false;
}
@@ -579,7 +583,7 @@ namespace {
bool nextStep(const Stmt *S) {
if (!StepsLeft) {
- Diag(S->getLocStart(), diag::note_constexpr_step_limit_exceeded);
+ FFDiag(S->getLocStart(), diag::note_constexpr_step_limit_exceeded);
return false;
}
--StepsLeft;
@@ -597,11 +601,10 @@ namespace {
/// Add notes containing a call stack to the current point of evaluation.
void addCallStack(unsigned Limit);
- public:
- /// Diagnose that the evaluation cannot be folded.
- OptionalDiagnostic Diag(SourceLocation Loc, diag::kind DiagId
- = diag::note_invalid_subexpr_in_const_expr,
- unsigned ExtraNotes = 0, bool IsCCEDiag = false) {
+ private:
+ OptionalDiagnostic Diag(SourceLocation Loc, diag::kind DiagId,
+ unsigned ExtraNotes, bool IsCCEDiag) {
+
if (EvalStatus.Diag) {
// If we have a prior diagnostic, it will be noting that the expression
// isn't a constant expression. This diagnostic is more important,
@@ -646,12 +649,20 @@ namespace {
HasActiveDiagnostic = false;
return OptionalDiagnostic();
}
-
- OptionalDiagnostic Diag(const Expr *E, diag::kind DiagId
+ public:
+ // Diagnose that the evaluation could not be folded (FF => FoldFailure)
+ OptionalDiagnostic
+ FFDiag(SourceLocation Loc,
+ diag::kind DiagId = diag::note_invalid_subexpr_in_const_expr,
+ unsigned ExtraNotes = 0) {
+ return Diag(Loc, DiagId, ExtraNotes, false);
+ }
+
+ OptionalDiagnostic FFDiag(const Expr *E, diag::kind DiagId
= diag::note_invalid_subexpr_in_const_expr,
- unsigned ExtraNotes = 0, bool IsCCEDiag = false) {
+ unsigned ExtraNotes = 0) {
if (EvalStatus.Diag)
- return Diag(E->getExprLoc(), DiagId, ExtraNotes, IsCCEDiag);
+ return Diag(E->getExprLoc(), DiagId, ExtraNotes, /*IsCCEDiag*/false);
HasActiveDiagnostic = false;
return OptionalDiagnostic();
}
@@ -661,8 +672,7 @@ namespace {
///
/// FIXME: Stop evaluating if we're in EM_ConstantExpression or
/// EM_PotentialConstantExpression mode and we produce one of these.
- template<typename LocArg>
- OptionalDiagnostic CCEDiag(LocArg Loc, diag::kind DiagId
+ OptionalDiagnostic CCEDiag(SourceLocation Loc, diag::kind DiagId
= diag::note_invalid_subexpr_in_const_expr,
unsigned ExtraNotes = 0) {
// Don't override a previous diagnostic. Don't bother collecting
@@ -673,7 +683,11 @@ namespace {
}
return Diag(Loc, DiagId, ExtraNotes, true);
}
-
+ OptionalDiagnostic CCEDiag(const Expr *E, diag::kind DiagId
+ = diag::note_invalid_subexpr_in_const_expr,
+ unsigned ExtraNotes = 0) {
+ return CCEDiag(E->getExprLoc(), DiagId, ExtraNotes);
+ }
/// Add a note to a prior diagnostic.
OptionalDiagnostic Note(SourceLocation Loc, diag::kind DiagId) {
if (!HasActiveDiagnostic)
@@ -763,6 +777,29 @@ namespace {
llvm_unreachable("Missed EvalMode case");
}
+ /// Notes that we failed to evaluate an expression that other expressions
+ /// directly depend on, and determine if we should keep evaluating. This
+ /// should only be called if we actually intend to keep evaluating.
+ ///
+ /// Call noteSideEffect() instead if we may be able to ignore the value that
+ /// we failed to evaluate, e.g. if we failed to evaluate Foo() in:
+ ///
+ /// (Foo(), 1) // use noteSideEffect
+ /// (Foo() || true) // use noteSideEffect
+ /// Foo() + 1 // use noteFailure
+ LLVM_ATTRIBUTE_UNUSED_RESULT bool noteFailure() {
+ // Failure when evaluating some expression often means there is some
+ // subexpression whose evaluation was skipped. Therefore, (because we
+ // don't track whether we skipped an expression when unwinding after an
+ // evaluation failure) every evaluation failure that bubbles up from a
+ // subexpression implies that a side-effect has potentially happened. We
+ // skip setting the HasSideEffects flag to true until we decide to
+ // continue evaluating after that point, which happens here.
+ bool KeepGoing = keepEvaluatingAfterFailure();
+ EvalStatus.HasSideEffects |= KeepGoing;
+ return KeepGoing;
+ }
+
bool allowInvalidBaseExpr() const {
return EvalMode == EM_DesignatorFold;
}
@@ -811,24 +848,52 @@ namespace {
~FoldOffsetRAII() { Info.EvalMode = OldMode; }
};
- /// RAII object used to suppress diagnostics and side-effects from a
- /// speculative evaluation.
+ /// RAII object used to optionally suppress diagnostics and side-effects from
+ /// a speculative evaluation.
class SpeculativeEvaluationRAII {
- EvalInfo &Info;
+ /// Pair of EvalInfo, and a bit that stores whether or not we were
+ /// speculatively evaluating when we created this RAII.
+ llvm::PointerIntPair<EvalInfo *, 1, bool> InfoAndOldSpecEval;
Expr::EvalStatus Old;
+ void moveFromAndCancel(SpeculativeEvaluationRAII &&Other) {
+ InfoAndOldSpecEval = Other.InfoAndOldSpecEval;
+ Old = Other.Old;
+ Other.InfoAndOldSpecEval.setPointer(nullptr);
+ }
+
+ void maybeRestoreState() {
+ EvalInfo *Info = InfoAndOldSpecEval.getPointer();
+ if (!Info)
+ return;
+
+ Info->EvalStatus = Old;
+ Info->IsSpeculativelyEvaluating = InfoAndOldSpecEval.getInt();
+ }
+
public:
- SpeculativeEvaluationRAII(EvalInfo &Info,
- SmallVectorImpl<PartialDiagnosticAt> *NewDiag = nullptr)
- : Info(Info), Old(Info.EvalStatus) {
+ SpeculativeEvaluationRAII() = default;
+
+ SpeculativeEvaluationRAII(
+ EvalInfo &Info, SmallVectorImpl<PartialDiagnosticAt> *NewDiag = nullptr)
+ : InfoAndOldSpecEval(&Info, Info.IsSpeculativelyEvaluating),
+ Old(Info.EvalStatus) {
Info.EvalStatus.Diag = NewDiag;
- // If we're speculatively evaluating, we may have skipped over some
- // evaluations and missed out a side effect.
- Info.EvalStatus.HasSideEffects = true;
+ Info.IsSpeculativelyEvaluating = true;
}
- ~SpeculativeEvaluationRAII() {
- Info.EvalStatus = Old;
+
+ SpeculativeEvaluationRAII(const SpeculativeEvaluationRAII &Other) = delete;
+ SpeculativeEvaluationRAII(SpeculativeEvaluationRAII &&Other) {
+ moveFromAndCancel(std::move(Other));
}
+
+ SpeculativeEvaluationRAII &operator=(SpeculativeEvaluationRAII &&Other) {
+ maybeRestoreState();
+ moveFromAndCancel(std::move(Other));
+ return *this;
+ }
+
+ ~SpeculativeEvaluationRAII() { maybeRestoreState(); }
};
/// RAII object wrapping a full-expression or block scope, and handling
@@ -941,6 +1006,16 @@ void EvalInfo::addCallStack(unsigned Limit) {
continue;
}
+ // Use a different note for an inheriting constructor, because from the
+ // user's perspective it's not really a function at all.
+ if (auto *CD = dyn_cast_or_null<CXXConstructorDecl>(Frame->Callee)) {
+ if (CD->isInheritingConstructor()) {
+ addDiag(Frame->CallLoc, diag::note_constexpr_inherited_ctor_call_here)
+ << CD->getParent();
+ continue;
+ }
+ }
+
SmallVector<char, 128> Buffer;
llvm::raw_svector_ostream Out(Buffer);
describeCall(Frame, Out);
@@ -992,7 +1067,7 @@ namespace {
struct LValue {
APValue::LValueBase Base;
CharUnits Offset;
- bool InvalidBase : 1;
+ unsigned InvalidBase : 1;
unsigned CallIndex : 31;
SubobjectDesignator Designator;
@@ -1335,12 +1410,12 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
if (!IsGlobalLValue(Base)) {
if (Info.getLangOpts().CPlusPlus11) {
const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>();
- Info.Diag(Loc, diag::note_constexpr_non_global, 1)
+ Info.FFDiag(Loc, diag::note_constexpr_non_global, 1)
<< IsReferenceType << !Designator.Entries.empty()
<< !!VD << VD;
NoteLValueLocation(Info, Base);
} else {
- Info.Diag(Loc);
+ Info.FFDiag(Loc);
}
// Don't allow references to temporaries to escape.
return false;
@@ -1390,7 +1465,7 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
// Does this refer one past the end of some object?
if (!Designator.Invalid && Designator.isOnePastTheEnd()) {
const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>();
- Info.Diag(Loc, diag::note_constexpr_past_end, 1)
+ Info.FFDiag(Loc, diag::note_constexpr_past_end, 1)
<< !Designator.Entries.empty() << !!VD << VD;
NoteLValueLocation(Info, Base);
}
@@ -1414,10 +1489,10 @@ static bool CheckLiteralType(EvalInfo &Info, const Expr *E,
// Prvalue constant expressions must be of literal types.
if (Info.getLangOpts().CPlusPlus11)
- Info.Diag(E, diag::note_constexpr_nonliteral)
+ Info.FFDiag(E, diag::note_constexpr_nonliteral)
<< E->getType();
else
- Info.Diag(E, diag::note_invalid_subexpr_in_const_expr);
+ Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr);
return false;
}
@@ -1427,7 +1502,7 @@ static bool CheckLiteralType(EvalInfo &Info, const Expr *E,
static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc,
QualType Type, const APValue &Value) {
if (Value.isUninit()) {
- Info.Diag(DiagLoc, diag::note_constexpr_uninitialized)
+ Info.FFDiag(DiagLoc, diag::note_constexpr_uninitialized)
<< true << Type;
return false;
}
@@ -1637,7 +1712,7 @@ static bool truncateBitfieldValue(EvalInfo &Info, const Expr *E,
// FIXME: In this case, we should provide the diagnostic for casting
// a pointer to an integer.
assert(Value.isLValue() && "integral value neither int nor lvalue?");
- Info.Diag(E);
+ Info.FFDiag(E);
return false;
}
@@ -1679,7 +1754,7 @@ static bool EvalAndBitcastToAPInt(EvalInfo &Info, const Expr *E,
} else {
// Don't try to handle vectors of anything other than int or float
// (not sure if it's possible to hit this case).
- Info.Diag(E, diag::note_invalid_subexpr_in_const_expr);
+ Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr);
return false;
}
unsigned BaseEltSize = EltAsInt.getBitWidth();
@@ -1692,7 +1767,7 @@ static bool EvalAndBitcastToAPInt(EvalInfo &Info, const Expr *E,
}
// Give up if the input isn't an int, float, or vector. For example, we
// reject "(v4i16)(intptr_t)&a".
- Info.Diag(E, diag::note_invalid_subexpr_in_const_expr);
+ Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr);
return false;
}
@@ -1728,7 +1803,7 @@ static bool handleIntIntBinOp(EvalInfo &Info, const Expr *E, const APSInt &LHS,
APSInt &Result) {
switch (Opcode) {
default:
- Info.Diag(E);
+ Info.FFDiag(E);
return false;
case BO_Mul:
return CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() * 2,
@@ -1745,7 +1820,7 @@ static bool handleIntIntBinOp(EvalInfo &Info, const Expr *E, const APSInt &LHS,
case BO_Div:
case BO_Rem:
if (RHS == 0) {
- Info.Diag(E, diag::note_expr_divide_by_zero);
+ Info.FFDiag(E, diag::note_expr_divide_by_zero);
return false;
}
Result = (Opcode == BO_Rem ? LHS % RHS : LHS / RHS);
@@ -1826,7 +1901,7 @@ static bool handleFloatFloatBinOp(EvalInfo &Info, const Expr *E,
const APFloat &RHS) {
switch (Opcode) {
default:
- Info.Diag(E);
+ Info.FFDiag(E);
return false;
case BO_Mul:
LHS.multiply(RHS, APFloat::rmNearestTiesToEven);
@@ -1968,10 +2043,15 @@ static bool HandleSizeof(EvalInfo &Info, SourceLocation Loc,
return true;
}
+ if (Type->isDependentType()) {
+ Info.FFDiag(Loc);
+ return false;
+ }
+
if (!Type->isConstantSizeType()) {
// sizeof(vla) is not a constantexpr: C99 6.5.3.4p2.
// FIXME: Better diagnostic.
- Info.Diag(Loc);
+ Info.FFDiag(Loc);
return false;
}
@@ -2035,7 +2115,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
if (Info.checkingPotentialConstantExpression())
return false;
if (!Frame || !Frame->Arguments) {
- Info.Diag(E, diag::note_invalid_subexpr_in_const_expr);
+ Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr);
return false;
}
Result = &Frame->Arguments[PVD->getFunctionScopeIndex()];
@@ -2055,7 +2135,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
// If we're checking a potential constant expression, the variable could be
// initialized later.
if (!Info.checkingPotentialConstantExpression())
- Info.Diag(E, diag::note_invalid_subexpr_in_const_expr);
+ Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr);
return false;
}
@@ -2069,7 +2149,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
// 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()) {
- Info.Diag(E, diag::note_invalid_subexpr_in_const_expr);
+ Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr);
return false;
}
@@ -2077,7 +2157,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
// this in the cases where it matters for conformance.
SmallVector<PartialDiagnosticAt, 8> Notes;
if (!VD->evaluateValue(Notes)) {
- Info.Diag(E, diag::note_constexpr_var_init_non_constant,
+ Info.FFDiag(E, diag::note_constexpr_var_init_non_constant,
Notes.size() + 1) << VD;
Info.Note(VD->getLocation(), diag::note_declared_at);
Info.addNotes(Notes);
@@ -2218,7 +2298,7 @@ static bool diagnoseUnreadableFields(EvalInfo &Info, const Expr *E,
// FIXME: Add core issue number for the union case.
if (Field->isMutable() &&
(RD->isUnion() || isReadByLvalueToRvalueConversion(Field->getType()))) {
- Info.Diag(E, diag::note_constexpr_ltor_mutable, 1) << Field;
+ Info.FFDiag(E, diag::note_constexpr_ltor_mutable, 1) << Field;
Info.Note(Field->getLocation(), diag::note_declared_at);
return true;
}
@@ -2272,10 +2352,10 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
return handler.failed();
if (Sub.isOnePastTheEnd()) {
if (Info.getLangOpts().CPlusPlus11)
- Info.Diag(E, diag::note_constexpr_access_past_end)
+ Info.FFDiag(E, diag::note_constexpr_access_past_end)
<< handler.AccessKind;
else
- Info.Diag(E);
+ Info.FFDiag(E);
return handler.failed();
}
@@ -2287,7 +2367,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
for (unsigned I = 0, N = Sub.Entries.size(); /**/; ++I) {
if (O->isUninit()) {
if (!Info.checkingPotentialConstantExpression())
- Info.Diag(E, diag::note_constexpr_access_uninit) << handler.AccessKind;
+ Info.FFDiag(E, diag::note_constexpr_access_uninit) << handler.AccessKind;
return handler.failed();
}
@@ -2322,10 +2402,10 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
// Note, it should not be possible to form a pointer with a valid
// designator which points more than one past the end of the array.
if (Info.getLangOpts().CPlusPlus11)
- Info.Diag(E, diag::note_constexpr_access_past_end)
+ Info.FFDiag(E, diag::note_constexpr_access_past_end)
<< handler.AccessKind;
else
- Info.Diag(E);
+ Info.FFDiag(E);
return handler.failed();
}
@@ -2355,10 +2435,10 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
uint64_t Index = Sub.Entries[I].ArrayIndex;
if (Index > 1) {
if (Info.getLangOpts().CPlusPlus11)
- Info.Diag(E, diag::note_constexpr_access_past_end)
+ Info.FFDiag(E, diag::note_constexpr_access_past_end)
<< handler.AccessKind;
else
- Info.Diag(E);
+ Info.FFDiag(E);
return handler.failed();
}
@@ -2378,7 +2458,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
}
} else if (const FieldDecl *Field = getAsField(Sub.Entries[I])) {
if (Field->isMutable() && handler.AccessKind == AK_Read) {
- Info.Diag(E, diag::note_constexpr_ltor_mutable, 1)
+ Info.FFDiag(E, diag::note_constexpr_ltor_mutable, 1)
<< Field;
Info.Note(Field->getLocation(), diag::note_declared_at);
return handler.failed();
@@ -2390,7 +2470,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
const FieldDecl *UnionField = O->getUnionField();
if (!UnionField ||
UnionField->getCanonicalDecl() != Field->getCanonicalDecl()) {
- Info.Diag(E, diag::note_constexpr_access_inactive_union_member)
+ Info.FFDiag(E, diag::note_constexpr_access_inactive_union_member)
<< handler.AccessKind << Field << !UnionField << UnionField;
return handler.failed();
}
@@ -2406,11 +2486,11 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
if (ObjType.isVolatileQualified()) {
if (Info.getLangOpts().CPlusPlus) {
// FIXME: Include a description of the path to the volatile subobject.
- Info.Diag(E, diag::note_constexpr_access_volatile_obj, 1)
+ Info.FFDiag(E, diag::note_constexpr_access_volatile_obj, 1)
<< handler.AccessKind << 2 << Field;
Info.Note(Field->getLocation(), diag::note_declared_at);
} else {
- Info.Diag(E, diag::note_invalid_subexpr_in_const_expr);
+ Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr);
}
return handler.failed();
}
@@ -2482,7 +2562,7 @@ struct ModifySubobjectHandler {
bool checkConst(QualType QT) {
// Assigning to a const object has undefined behavior.
if (QT.isConstQualified()) {
- Info.Diag(E, diag::note_constexpr_modify_const_type) << QT;
+ Info.FFDiag(E, diag::note_constexpr_modify_const_type) << QT;
return false;
}
return true;
@@ -2501,7 +2581,7 @@ struct ModifySubobjectHandler {
return false;
if (!NewVal.isInt()) {
// Maybe trying to write a cast pointer value into a complex?
- Info.Diag(E);
+ Info.FFDiag(E);
return false;
}
Value = NewVal.getInt();
@@ -2592,7 +2672,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
AccessKinds AK, const LValue &LVal,
QualType LValType) {
if (!LVal.Base) {
- Info.Diag(E, diag::note_constexpr_access_null) << AK;
+ Info.FFDiag(E, diag::note_constexpr_access_null) << AK;
return CompleteObject();
}
@@ -2600,7 +2680,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
if (LVal.CallIndex) {
Frame = Info.getCallFrame(LVal.CallIndex);
if (!Frame) {
- Info.Diag(E, diag::note_constexpr_lifetime_ended, 1)
+ Info.FFDiag(E, diag::note_constexpr_lifetime_ended, 1)
<< AK << LVal.Base.is<const ValueDecl*>();
NoteLValueLocation(Info, LVal.Base);
return CompleteObject();
@@ -2613,10 +2693,10 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
// semantics.
if (LValType.isVolatileQualified()) {
if (Info.getLangOpts().CPlusPlus)
- Info.Diag(E, diag::note_constexpr_access_volatile_type)
+ Info.FFDiag(E, diag::note_constexpr_access_volatile_type)
<< AK << LValType;
else
- Info.Diag(E);
+ Info.FFDiag(E);
return CompleteObject();
}
@@ -2638,18 +2718,18 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
VD = VDef;
}
if (!VD || VD->isInvalidDecl()) {
- Info.Diag(E);
+ Info.FFDiag(E);
return CompleteObject();
}
// Accesses of volatile-qualified objects are not allowed.
if (BaseType.isVolatileQualified()) {
if (Info.getLangOpts().CPlusPlus) {
- Info.Diag(E, diag::note_constexpr_access_volatile_obj, 1)
+ Info.FFDiag(E, diag::note_constexpr_access_volatile_obj, 1)
<< AK << 1 << VD;
Info.Note(VD->getLocation(), diag::note_declared_at);
} else {
- Info.Diag(E);
+ Info.FFDiag(E);
}
return CompleteObject();
}
@@ -2664,17 +2744,20 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
// evaluation.
} else if (AK != AK_Read) {
// All the remaining cases only permit reading.
- Info.Diag(E, diag::note_constexpr_modify_global);
+ Info.FFDiag(E, diag::note_constexpr_modify_global);
return CompleteObject();
} else if (VD->isConstexpr()) {
// OK, we can read this variable.
} else if (BaseType->isIntegralOrEnumerationType()) {
- if (!BaseType.isConstQualified()) {
+ // In OpenCL if a variable is in constant address space it is a const value.
+ if (!(BaseType.isConstQualified() ||
+ (Info.getLangOpts().OpenCL &&
+ BaseType.getAddressSpace() == LangAS::opencl_constant))) {
if (Info.getLangOpts().CPlusPlus) {
- Info.Diag(E, diag::note_constexpr_ltor_non_const_int, 1) << VD;
+ Info.FFDiag(E, diag::note_constexpr_ltor_non_const_int, 1) << VD;
Info.Note(VD->getLocation(), diag::note_declared_at);
} else {
- Info.Diag(E);
+ Info.FFDiag(E);
}
return CompleteObject();
}
@@ -2690,11 +2773,15 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
}
} else {
// FIXME: Allow folding of values of any literal type in all languages.
- if (Info.getLangOpts().CPlusPlus11) {
- Info.Diag(E, diag::note_constexpr_ltor_non_constexpr, 1) << VD;
+ if (Info.checkingPotentialConstantExpression() &&
+ VD->getType().isConstQualified() && !VD->hasDefinition(Info.Ctx)) {
+ // The definition of this variable could be constexpr. We can't
+ // access it right now, but may be able to in future.
+ } else if (Info.getLangOpts().CPlusPlus11) {
+ Info.FFDiag(E, diag::note_constexpr_ltor_non_constexpr, 1) << VD;
Info.Note(VD->getLocation(), diag::note_declared_at);
} else {
- Info.Diag(E);
+ Info.FFDiag(E);
}
return CompleteObject();
}
@@ -2730,7 +2817,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
if (!(BaseType.isConstQualified() &&
BaseType->isIntegralOrEnumerationType()) &&
!(VD && VD->getCanonicalDecl() == ED->getCanonicalDecl())) {
- Info.Diag(E, diag::note_constexpr_access_static_temporary, 1) << AK;
+ Info.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK;
Info.Note(MTE->getExprLoc(), diag::note_constexpr_temporary_here);
return CompleteObject();
}
@@ -2738,7 +2825,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
BaseVal = Info.Ctx.getMaterializedTemporaryValue(MTE, false);
assert(BaseVal && "got reference to unevaluated temporary");
} else {
- Info.Diag(E);
+ Info.FFDiag(E);
return CompleteObject();
}
} else {
@@ -2749,11 +2836,11 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
// Volatile temporary objects cannot be accessed in constant expressions.
if (BaseType.isVolatileQualified()) {
if (Info.getLangOpts().CPlusPlus) {
- Info.Diag(E, diag::note_constexpr_access_volatile_obj, 1)
+ Info.FFDiag(E, diag::note_constexpr_access_volatile_obj, 1)
<< AK << 0;
Info.Note(Base->getExprLoc(), diag::note_constexpr_temporary_here);
} else {
- Info.Diag(E);
+ Info.FFDiag(E);
}
return CompleteObject();
}
@@ -2769,12 +2856,13 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
}
// In C++1y, we can't safely access any mutable state when we might be
- // evaluating after an unmodeled side effect or an evaluation failure.
+ // evaluating after an unmodeled side effect.
//
// FIXME: Not all local state is mutable. Allow local constant subobjects
// to be read here (but take care with 'mutable' fields).
- if (Frame && Info.getLangOpts().CPlusPlus14 &&
- (Info.EvalStatus.HasSideEffects || Info.keepEvaluatingAfterFailure()))
+ if ((Frame && Info.getLangOpts().CPlusPlus14 &&
+ Info.EvalStatus.HasSideEffects) ||
+ (AK != AK_Read && Info.IsSpeculativelyEvaluating))
return CompleteObject();
return CompleteObject(BaseVal, BaseType);
@@ -2806,7 +2894,7 @@ static bool handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv,
// an ICE in C, so this only matters for fold.
assert(!Info.getLangOpts().CPlusPlus && "lvalue compound literal in c++?");
if (Type.isVolatileQualified()) {
- Info.Diag(Conv);
+ Info.FFDiag(Conv);
return false;
}
APValue Lit;
@@ -2835,7 +2923,7 @@ static bool handleAssignment(EvalInfo &Info, const Expr *E, const LValue &LVal,
return false;
if (!Info.getLangOpts().CPlusPlus14) {
- Info.Diag(E);
+ Info.FFDiag(E);
return false;
}
@@ -2863,7 +2951,7 @@ struct CompoundAssignSubobjectHandler {
bool checkConst(QualType QT) {
// Assigning to a const object has undefined behavior.
if (QT.isConstQualified()) {
- Info.Diag(E, diag::note_constexpr_modify_const_type) << QT;
+ Info.FFDiag(E, diag::note_constexpr_modify_const_type) << QT;
return false;
}
return true;
@@ -2879,13 +2967,13 @@ struct CompoundAssignSubobjectHandler {
case APValue::ComplexInt:
case APValue::ComplexFloat:
// FIXME: Implement complex compound assignment.
- Info.Diag(E);
+ Info.FFDiag(E);
return false;
case APValue::LValue:
return foundPointer(Subobj, SubobjType);
default:
// FIXME: can this happen?
- Info.Diag(E);
+ Info.FFDiag(E);
return false;
}
}
@@ -2896,7 +2984,7 @@ struct CompoundAssignSubobjectHandler {
if (!SubobjType->isIntegerType() || !RHS.isInt()) {
// We don't support compound assignment on integer-cast-to-pointer
// values.
- Info.Diag(E);
+ Info.FFDiag(E);
return false;
}
@@ -2924,7 +3012,7 @@ struct CompoundAssignSubobjectHandler {
if (PointeeType.isNull() || !RHS.isInt() ||
(Opcode != BO_Add && Opcode != BO_Sub)) {
- Info.Diag(E);
+ Info.FFDiag(E);
return false;
}
@@ -2956,7 +3044,7 @@ static bool handleCompoundAssignment(
return false;
if (!Info.getLangOpts().CPlusPlus14) {
- Info.Diag(E);
+ Info.FFDiag(E);
return false;
}
@@ -2978,7 +3066,7 @@ struct IncDecSubobjectHandler {
bool checkConst(QualType QT) {
// Assigning to a const object has undefined behavior.
if (QT.isConstQualified()) {
- Info.Diag(E, diag::note_constexpr_modify_const_type) << QT;
+ Info.FFDiag(E, diag::note_constexpr_modify_const_type) << QT;
return false;
}
return true;
@@ -3010,7 +3098,7 @@ struct IncDecSubobjectHandler {
return foundPointer(Subobj, SubobjType);
default:
// FIXME: can this happen?
- Info.Diag(E);
+ Info.FFDiag(E);
return false;
}
}
@@ -3021,7 +3109,7 @@ struct IncDecSubobjectHandler {
if (!SubobjType->isIntegerType()) {
// We don't support increment / decrement on integer-cast-to-pointer
// values.
- Info.Diag(E);
+ Info.FFDiag(E);
return false;
}
@@ -3080,7 +3168,7 @@ struct IncDecSubobjectHandler {
if (const PointerType *PT = SubobjType->getAs<PointerType>())
PointeeType = PT->getPointeeType();
else {
- Info.Diag(E);
+ Info.FFDiag(E);
return false;
}
@@ -3105,7 +3193,7 @@ static bool handleIncDec(EvalInfo &Info, const Expr *E, const LValue &LVal,
return false;
if (!Info.getLangOpts().CPlusPlus14) {
- Info.Diag(E);
+ Info.FFDiag(E);
return false;
}
@@ -3127,7 +3215,7 @@ static bool EvaluateObjectArgument(EvalInfo &Info, const Expr *Object,
if (Object->getType()->isLiteralType(Info.Ctx))
return EvaluateTemporary(Object, This, Info);
- Info.Diag(Object, diag::note_constexpr_nonliteral) << Object->getType();
+ Info.FFDiag(Object, diag::note_constexpr_nonliteral) << Object->getType();
return false;
}
@@ -3155,7 +3243,7 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
// member value, the behavior is undefined.
if (!MemPtr.getDecl()) {
// FIXME: Specific diagnostic.
- Info.Diag(RHS);
+ Info.FFDiag(RHS);
return nullptr;
}
@@ -3165,7 +3253,7 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
// derived-to-base path for the member pointer.
if (LV.Designator.MostDerivedPathLength + MemPtr.Path.size() >
LV.Designator.Entries.size()) {
- Info.Diag(RHS);
+ Info.FFDiag(RHS);
return nullptr;
}
unsigned PathLengthToMember =
@@ -3175,7 +3263,7 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
LV.Designator.Entries[PathLengthToMember + I]);
const CXXRecordDecl *MPDecl = MemPtr.Path[I];
if (LVDecl->getCanonicalDecl() != MPDecl->getCanonicalDecl()) {
- Info.Diag(RHS);
+ Info.FFDiag(RHS);
return nullptr;
}
}
@@ -3231,7 +3319,7 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
assert(BO->getOpcode() == BO_PtrMemD || BO->getOpcode() == BO_PtrMemI);
if (!EvaluateObjectArgument(Info, BO->getLHS(), LV)) {
- if (Info.keepEvaluatingAfterFailure()) {
+ if (Info.noteFailure()) {
MemberPtr MemPtr;
EvaluateMemberPointer(BO->getRHS(), MemPtr, Info);
}
@@ -3309,7 +3397,7 @@ static bool EvaluateDecl(EvalInfo &Info, const Decl *D) {
const Expr *InitE = VD->getInit();
if (!InitE) {
- Info.Diag(D->getLocStart(), diag::note_constexpr_uninitialized)
+ Info.FFDiag(D->getLocStart(), diag::note_constexpr_uninitialized)
<< false << VD->getType();
Val = APValue();
return false;
@@ -3338,6 +3426,7 @@ static bool EvaluateCond(EvalInfo &Info, const VarDecl *CondDecl,
return EvaluateAsBooleanCondition(Cond, Result, Info);
}
+namespace {
/// \brief A location where the result (returned value) of evaluating a
/// statement should be stored.
struct StmtResult {
@@ -3346,6 +3435,7 @@ struct StmtResult {
/// The location containing the result, if any (used to support RVO).
const LValue *Slot;
};
+}
static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
const Stmt *S,
@@ -3379,6 +3469,11 @@ static EvalStmtResult EvaluateSwitch(StmtResult &Result, EvalInfo &Info,
APSInt Value;
{
FullExpressionRAII Scope(Info);
+ if (const Stmt *Init = SS->getInit()) {
+ EvalStmtResult ESR = EvaluateStmt(Result, Info, Init);
+ if (ESR != ESR_Succeeded)
+ return ESR;
+ }
if (SS->getConditionVariable() &&
!EvaluateDecl(Info, SS->getConditionVariable()))
return ESR_Failed;
@@ -3421,7 +3516,7 @@ static EvalStmtResult EvaluateSwitch(StmtResult &Result, EvalInfo &Info,
case ESR_CaseNotFound:
// This can only happen if the switch case is nested within a statement
// expression. We have no intention of supporting that.
- Info.Diag(Found->getLocStart(), diag::note_constexpr_stmt_expr_unsupported);
+ Info.FFDiag(Found->getLocStart(), diag::note_constexpr_stmt_expr_unsupported);
return ESR_Failed;
}
llvm_unreachable("Invalid EvalStmtResult!");
@@ -3512,7 +3607,7 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
return ESR_Succeeded;
}
- Info.Diag(S->getLocStart());
+ Info.FFDiag(S->getLocStart());
return ESR_Failed;
case Stmt::NullStmtClass:
@@ -3525,7 +3620,7 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
// FIXME: This isn't quite right; if we're performing aggregate
// initialization, each braced subexpression is its own full-expression.
FullExpressionRAII Scope(Info);
- if (!EvaluateDecl(Info, DclIt) && !Info.keepEvaluatingAfterFailure())
+ if (!EvaluateDecl(Info, DclIt) && !Info.noteFailure())
return ESR_Failed;
}
return ESR_Succeeded;
@@ -3561,6 +3656,11 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
// Evaluate the condition, as either a var decl or as an expression.
BlockScopeRAII Scope(Info);
+ if (const Stmt *Init = IS->getInit()) {
+ EvalStmtResult ESR = EvaluateStmt(Result, Info, Init);
+ if (ESR != ESR_Succeeded)
+ return ESR;
+ }
bool Cond;
if (!EvaluateCond(Info, IS->getConditionVariable(), IS->getCond(), Cond))
return ESR_Failed;
@@ -3647,7 +3747,10 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
return ESR;
// Create the __begin and __end iterators.
- ESR = EvaluateStmt(Result, Info, FS->getBeginEndStmt());
+ ESR = EvaluateStmt(Result, Info, FS->getBeginStmt());
+ if (ESR != ESR_Succeeded)
+ return ESR;
+ ESR = EvaluateStmt(Result, Info, FS->getEndStmt());
if (ESR != ESR_Succeeded)
return ESR;
@@ -3736,7 +3839,8 @@ static bool CheckTrivialDefaultConstructor(EvalInfo &Info, SourceLocation Loc,
/// expression.
static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc,
const FunctionDecl *Declaration,
- const FunctionDecl *Definition) {
+ const FunctionDecl *Definition,
+ const Stmt *Body) {
// Potential constant expressions can contain calls to declared, but not yet
// defined, constexpr functions.
if (Info.checkingPotentialConstantExpression() && !Definition &&
@@ -3749,19 +3853,34 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc,
return false;
// Can we evaluate this function call?
- if (Definition && Definition->isConstexpr() && !Definition->isInvalidDecl())
+ if (Definition && Definition->isConstexpr() &&
+ !Definition->isInvalidDecl() && Body)
return true;
if (Info.getLangOpts().CPlusPlus11) {
const FunctionDecl *DiagDecl = Definition ? Definition : Declaration;
- // FIXME: If DiagDecl is an implicitly-declared special member function, we
- // should be much more explicit about why it's not constexpr.
- Info.Diag(CallLoc, diag::note_constexpr_invalid_function, 1)
- << DiagDecl->isConstexpr() << isa<CXXConstructorDecl>(DiagDecl)
- << DiagDecl;
+
+ // If this function is not constexpr because it is an inherited
+ // non-constexpr constructor, diagnose that directly.
+ auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl);
+ if (CD && CD->isInheritingConstructor()) {
+ auto *Inherited = CD->getInheritedConstructor().getConstructor();
+ if (!Inherited->isConstexpr())
+ DiagDecl = CD = Inherited;
+ }
+
+ // FIXME: If DiagDecl is an implicitly-declared special member function
+ // or an inheriting constructor, we should be much more explicit about why
+ // it's not constexpr.
+ if (CD && CD->isInheritingConstructor())
+ Info.FFDiag(CallLoc, diag::note_constexpr_invalid_inhctor, 1)
+ << CD->getInheritedConstructor().getConstructor()->getParent();
+ else
+ Info.FFDiag(CallLoc, diag::note_constexpr_invalid_function, 1)
+ << DiagDecl->isConstexpr() << (bool)CD << DiagDecl;
Info.Note(DiagDecl->getLocation(), diag::note_declared_at);
} else {
- Info.Diag(CallLoc, diag::note_invalid_subexpr_in_const_expr);
+ Info.FFDiag(CallLoc, diag::note_invalid_subexpr_in_const_expr);
}
return false;
}
@@ -3795,7 +3914,7 @@ static bool EvaluateArgs(ArrayRef<const Expr*> Args, ArgVector &ArgValues,
if (!Evaluate(ArgValues[I - Args.begin()], Info, *I)) {
// If we're checking for a potential constant expression, evaluate all
// initializers even if some of them fail.
- if (!Info.keepEvaluatingAfterFailure())
+ if (!Info.noteFailure())
return false;
Success = false;
}
@@ -3848,37 +3967,34 @@ static bool HandleFunctionCall(SourceLocation CallLoc,
if (ESR == ESR_Succeeded) {
if (Callee->getReturnType()->isVoidType())
return true;
- Info.Diag(Callee->getLocEnd(), diag::note_constexpr_no_return);
+ Info.FFDiag(Callee->getLocEnd(), diag::note_constexpr_no_return);
}
return ESR == ESR_Returned;
}
/// Evaluate a constructor call.
-static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
- ArrayRef<const Expr*> Args,
+static bool HandleConstructorCall(const Expr *E, const LValue &This,
+ APValue *ArgValues,
const CXXConstructorDecl *Definition,
EvalInfo &Info, APValue &Result) {
- ArgVector ArgValues(Args.size());
- if (!EvaluateArgs(Args, ArgValues, Info))
- return false;
-
+ SourceLocation CallLoc = E->getExprLoc();
if (!Info.CheckCallLimit(CallLoc))
return false;
const CXXRecordDecl *RD = Definition->getParent();
if (RD->getNumVBases()) {
- Info.Diag(CallLoc, diag::note_constexpr_virtual_base) << RD;
+ Info.FFDiag(CallLoc, diag::note_constexpr_virtual_base) << RD;
return false;
}
- CallStackFrame Frame(Info, CallLoc, Definition, &This, ArgValues.data());
+ CallStackFrame Frame(Info, CallLoc, Definition, &This, ArgValues);
// FIXME: Creating an APValue just to hold a nonexistent return value is
// wasteful.
APValue RetVal;
StmtResult Ret = {RetVal, nullptr};
- // If it's a delegating constructor, just delegate.
+ // If it's a delegating constructor, delegate.
if (Definition->isDelegatingConstructor()) {
CXXConstructorDecl::init_const_iterator I = Definition->init_begin();
{
@@ -3902,8 +4018,9 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
(Definition->isTrivial() && hasFields(Definition->getParent())))) {
LValue RHS;
RHS.setFrom(Info.Ctx, ArgValues[0]);
- return handleLValueToRValueConversion(Info, Args[0], Args[0]->getType(),
- RHS, Result);
+ return handleLValueToRValueConversion(
+ Info, E, Definition->getParamDecl(0)->getType().getNonReferenceType(),
+ RHS, Result);
}
// Reserve space for the struct members.
@@ -3987,7 +4104,7 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
*Value, FD))) {
// If we're checking for a potential constant expression, evaluate all
// initializers even if some of them fail.
- if (!Info.keepEvaluatingAfterFailure())
+ if (!Info.noteFailure())
return false;
Success = false;
}
@@ -3997,6 +4114,18 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
EvaluateStmt(Ret, Info, Definition->getBody()) != ESR_Failed;
}
+static bool HandleConstructorCall(const Expr *E, const LValue &This,
+ ArrayRef<const Expr*> Args,
+ const CXXConstructorDecl *Definition,
+ EvalInfo &Info, APValue &Result) {
+ ArgVector ArgValues(Args.size());
+ if (!EvaluateArgs(Args, ArgValues, Info))
+ return false;
+
+ return HandleConstructorCall(E, This, ArgValues.data(), Definition,
+ Info, Result);
+}
+
//===----------------------------------------------------------------------===//
// Generic Evaluation
//===----------------------------------------------------------------------===//
@@ -4022,14 +4151,16 @@ private:
assert(Info.checkingPotentialConstantExpression());
// Speculatively evaluate both arms.
+ SmallVector<PartialDiagnosticAt, 8> Diag;
{
- SmallVector<PartialDiagnosticAt, 8> Diag;
SpeculativeEvaluationRAII Speculate(Info, &Diag);
-
StmtVisitorTy::Visit(E->getFalseExpr());
if (Diag.empty())
return;
+ }
+ {
+ SpeculativeEvaluationRAII Speculate(Info, &Diag);
Diag.clear();
StmtVisitorTy::Visit(E->getTrueExpr());
if (Diag.empty())
@@ -4044,7 +4175,7 @@ private:
bool HandleConditionalOperator(const ConditionalOperator *E) {
bool BoolResult;
if (!EvaluateAsBooleanCondition(E->getCond(), BoolResult, Info)) {
- if (Info.checkingPotentialConstantExpression())
+ if (Info.checkingPotentialConstantExpression() && Info.noteFailure())
CheckPotentialConstantConditional(E);
return false;
}
@@ -4072,7 +4203,7 @@ public:
/// 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, D);
+ Info.FFDiag(E, D);
return false;
}
bool Error(const Expr *E) {
@@ -4275,7 +4406,7 @@ public:
const FunctionDecl *Definition = nullptr;
Stmt *Body = FD->getBody(Definition);
- if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition) ||
+ if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition, Body) ||
!HandleFunctionCall(E->getExprLoc(), Definition, This, Args, Body, Info,
Result, ResultSlot))
return false;
@@ -4397,7 +4528,7 @@ public:
if (BI + 1 == BE) {
const Expr *FinalExpr = dyn_cast<Expr>(*BI);
if (!FinalExpr) {
- Info.Diag((*BI)->getLocStart(),
+ Info.FFDiag((*BI)->getLocStart(),
diag::note_constexpr_stmt_expr_unsupported);
return false;
}
@@ -4412,7 +4543,7 @@ public:
// 'break', or 'continue', it would be nice to propagate that to
// the outer statement evaluation rather than bailing out.
if (ESR != ESR_Failed)
- Info.Diag((*BI)->getLocStart(),
+ Info.FFDiag((*BI)->getLocStart(),
diag::note_constexpr_stmt_expr_unsupported);
return false;
}
@@ -4425,6 +4556,15 @@ public:
void VisitIgnoredValue(const Expr *E) {
EvaluateIgnoredValue(Info, E);
}
+
+ /// Potentially visit a MemberExpr's base expression.
+ void VisitIgnoredBaseExpression(const Expr *E) {
+ // While MSVC doesn't evaluate the base expression, it does diagnose the
+ // presence of side-effecting behavior.
+ if (Info.getLangOpts().MSVCCompat && !E->HasSideEffects(Info.Ctx))
+ return;
+ VisitIgnoredValue(E);
+ }
};
}
@@ -4651,7 +4791,7 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
return false;
if (V->isUninit()) {
if (!Info.checkingPotentialConstantExpression())
- Info.Diag(E, diag::note_constexpr_use_uninit_reference);
+ Info.FFDiag(E, diag::note_constexpr_use_uninit_reference);
return false;
}
return Success(*V, E);
@@ -4735,7 +4875,7 @@ bool LValueExprEvaluator::VisitCXXTypeidExpr(const CXXTypeidExpr *E) {
if (!E->isPotentiallyEvaluated())
return Success(E);
- Info.Diag(E, diag::note_constexpr_typeid_polymorphic)
+ Info.FFDiag(E, diag::note_constexpr_typeid_polymorphic)
<< E->getExprOperand()->getType()
<< E->getExprOperand()->getSourceRange();
return false;
@@ -4748,14 +4888,14 @@ bool LValueExprEvaluator::VisitCXXUuidofExpr(const CXXUuidofExpr *E) {
bool LValueExprEvaluator::VisitMemberExpr(const MemberExpr *E) {
// Handle static data members.
if (const VarDecl *VD = dyn_cast<VarDecl>(E->getMemberDecl())) {
- VisitIgnoredValue(E->getBase());
+ VisitIgnoredBaseExpression(E->getBase());
return VisitVarDecl(E, VD);
}
// Handle static member functions.
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(E->getMemberDecl())) {
if (MD->isStatic()) {
- VisitIgnoredValue(E->getBase());
+ VisitIgnoredBaseExpression(E->getBase());
return Success(MD);
}
}
@@ -4823,7 +4963,7 @@ bool LValueExprEvaluator::VisitCompoundAssignOperator(
// The overall lvalue result is the result of evaluating the LHS.
if (!this->Visit(CAO->getLHS())) {
- if (Info.keepEvaluatingAfterFailure())
+ if (Info.noteFailure())
Evaluate(RHS, this->Info, CAO->getRHS());
return false;
}
@@ -4844,7 +4984,7 @@ bool LValueExprEvaluator::VisitBinAssign(const BinaryOperator *E) {
APValue NewVal;
if (!this->Visit(E->getLHS())) {
- if (Info.keepEvaluatingAfterFailure())
+ if (Info.noteFailure())
Evaluate(NewVal, this->Info, E->getRHS());
return false;
}
@@ -4903,9 +5043,9 @@ public:
return false;
if (!Info.CurrentCall->This) {
if (Info.getLangOpts().CPlusPlus11)
- Info.Diag(E, diag::note_constexpr_this) << E->isImplicit();
+ Info.FFDiag(E, diag::note_constexpr_this) << E->isImplicit();
else
- Info.Diag(E);
+ Info.FFDiag(E);
return false;
}
Result = *Info.CurrentCall->This;
@@ -4932,7 +5072,7 @@ bool PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
std::swap(PExp, IExp);
bool EvalPtrOK = EvaluatePointer(PExp, Result, Info);
- if (!EvalPtrOK && !Info.keepEvaluatingAfterFailure())
+ if (!EvalPtrOK && !Info.noteFailure())
return false;
llvm::APSInt Offset;
@@ -5135,7 +5275,7 @@ bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) {
}
// The offset must also have the correct alignment.
- if (OffsetResult.Offset.RoundUpToAlignment(Align) != OffsetResult.Offset) {
+ if (OffsetResult.Offset.alignTo(Align) != OffsetResult.Offset) {
Result.Designator.setInvalid();
APSInt Offset(64, false);
Offset = OffsetResult.Offset.getQuantity();
@@ -5265,14 +5405,21 @@ namespace {
Result = V;
return true;
}
- bool ZeroInitialization(const Expr *E);
+ bool ZeroInitialization(const Expr *E) {
+ return ZeroInitialization(E, E->getType());
+ }
+ bool ZeroInitialization(const Expr *E, QualType T);
bool VisitCallExpr(const CallExpr *E) {
return handleCallExpr(E, Result, &This);
}
bool VisitCastExpr(const CastExpr *E);
bool VisitInitListExpr(const InitListExpr *E);
- bool VisitCXXConstructExpr(const CXXConstructExpr *E);
+ bool VisitCXXConstructExpr(const CXXConstructExpr *E) {
+ return VisitCXXConstructExpr(E, E->getType());
+ }
+ bool VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E);
+ bool VisitCXXConstructExpr(const CXXConstructExpr *E, QualType T);
bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E);
};
}
@@ -5327,8 +5474,8 @@ static bool HandleClassZeroInitialization(EvalInfo &Info, const Expr *E,
return true;
}
-bool RecordExprEvaluator::ZeroInitialization(const Expr *E) {
- const RecordDecl *RD = E->getType()->castAs<RecordType>()->getDecl();
+bool RecordExprEvaluator::ZeroInitialization(const Expr *E, QualType T) {
+ const RecordDecl *RD = T->castAs<RecordType>()->getDecl();
if (RD->isInvalidDecl()) return false;
if (RD->isUnion()) {
// C++11 [dcl.init]p5: If T is a (possibly cv-qualified) union type, the
@@ -5348,7 +5495,7 @@ bool RecordExprEvaluator::ZeroInitialization(const Expr *E) {
}
if (isa<CXXRecordDecl>(RD) && cast<CXXRecordDecl>(RD)->getNumVBases()) {
- Info.Diag(E, diag::note_constexpr_virtual_base) << RD;
+ Info.FFDiag(E, diag::note_constexpr_virtual_base) << RD;
return false;
}
@@ -5417,12 +5564,34 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
return EvaluateInPlace(Result.getUnionValue(), Info, Subobject, InitExpr);
}
- assert((!isa<CXXRecordDecl>(RD) || !cast<CXXRecordDecl>(RD)->getNumBases()) &&
- "initializer list for class with base classes");
- Result = APValue(APValue::UninitStruct(), 0,
- std::distance(RD->field_begin(), RD->field_end()));
+ auto *CXXRD = dyn_cast<CXXRecordDecl>(RD);
+ if (Result.isUninit())
+ Result = APValue(APValue::UninitStruct(), CXXRD ? CXXRD->getNumBases() : 0,
+ std::distance(RD->field_begin(), RD->field_end()));
unsigned ElementNo = 0;
bool Success = true;
+
+ // Initialize base classes.
+ if (CXXRD) {
+ for (const auto &Base : CXXRD->bases()) {
+ assert(ElementNo < E->getNumInits() && "missing init for base class");
+ const Expr *Init = E->getInit(ElementNo);
+
+ LValue Subobject = This;
+ if (!HandleLValueBase(Info, Init, Subobject, CXXRD, &Base))
+ return false;
+
+ APValue &FieldVal = Result.getStructBase(ElementNo);
+ if (!EvaluateInPlace(FieldVal, Info, Subobject, Init)) {
+ if (!Info.noteFailure())
+ return false;
+ Success = false;
+ }
+ ++ElementNo;
+ }
+ }
+
+ // Initialize members.
for (const auto *Field : RD->fields()) {
// Anonymous bit-fields are not considered members of the class for
// purposes of aggregate initialization.
@@ -5452,7 +5621,7 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
if (!EvaluateInPlace(FieldVal, Info, Subobject, Init) ||
(Field->isBitField() && !truncateBitfieldValue(Info, Init,
FieldVal, Field))) {
- if (!Info.keepEvaluatingAfterFailure())
+ if (!Info.noteFailure())
return false;
Success = false;
}
@@ -5461,7 +5630,10 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
return Success;
}
-bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
+bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
+ QualType T) {
+ // Note that E's type is not necessarily the type of our class here; we might
+ // be initializing an array element instead.
const CXXConstructorDecl *FD = E->getConstructor();
if (FD->isInvalidDecl() || FD->getParent()->isInvalidDecl()) return false;
@@ -5479,13 +5651,13 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
// lifetimes of all the base subobjects (there can be no data member
// subobjects in this case) per [basic.life]p1.
// Either way, ZeroInitialization is appropriate.
- return ZeroInitialization(E);
+ return ZeroInitialization(E, T);
}
const FunctionDecl *Definition = nullptr;
- FD->getBody(Definition);
+ auto Body = FD->getBody(Definition);
- if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition))
+ if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition, Body))
return false;
// Avoid materializing a temporary for an elidable copy/move constructor.
@@ -5494,11 +5666,33 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
= dyn_cast<MaterializeTemporaryExpr>(E->getArg(0)))
return Visit(ME->GetTemporaryExpr());
- if (ZeroInit && !ZeroInitialization(E))
+ if (ZeroInit && !ZeroInitialization(E, T))
return false;
auto Args = llvm::makeArrayRef(E->getArgs(), E->getNumArgs());
- return HandleConstructorCall(E->getExprLoc(), This, Args,
+ return HandleConstructorCall(E, This, Args,
+ cast<CXXConstructorDecl>(Definition), Info,
+ Result);
+}
+
+bool RecordExprEvaluator::VisitCXXInheritedCtorInitExpr(
+ const CXXInheritedCtorInitExpr *E) {
+ if (!Info.CurrentCall) {
+ assert(Info.checkingPotentialConstantExpression());
+ return false;
+ }
+
+ const CXXConstructorDecl *FD = E->getConstructor();
+ if (FD->isInvalidDecl() || FD->getParent()->isInvalidDecl())
+ return false;
+
+ const FunctionDecl *Definition = nullptr;
+ auto Body = FD->getBody(Definition);
+
+ if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition, Body))
+ return false;
+
+ return HandleConstructorCall(E, This, Info.CurrentCall->Arguments,
cast<CXXConstructorDecl>(Definition), Info,
Result);
}
@@ -5902,7 +6096,7 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
Info, Subobject, Init) ||
!HandleLValueArrayAdjustment(Info, Init, Subobject,
CAT->getElementType(), 1)) {
- if (!Info.keepEvaluatingAfterFailure())
+ if (!Info.noteFailure())
return false;
Success = false;
}
@@ -5958,34 +6152,8 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
if (!Type->isRecordType())
return Error(E);
- const CXXConstructorDecl *FD = E->getConstructor();
-
- bool ZeroInit = E->requiresZeroInitialization();
- if (CheckTrivialDefaultConstructor(Info, E->getExprLoc(), FD, ZeroInit)) {
- if (HadZeroInit)
- return true;
-
- // See RecordExprEvaluator::VisitCXXConstructExpr for explanation.
- ImplicitValueInitExpr VIE(Type);
- return EvaluateInPlace(*Value, Info, Subobject, &VIE);
- }
-
- const FunctionDecl *Definition = nullptr;
- FD->getBody(Definition);
-
- if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition))
- return false;
-
- if (ZeroInit && !HadZeroInit) {
- ImplicitValueInitExpr VIE(Type);
- if (!EvaluateInPlace(*Value, Info, Subobject, &VIE))
- return false;
- }
-
- auto Args = llvm::makeArrayRef(E->getArgs(), E->getNumArgs());
- return HandleConstructorCall(E->getExprLoc(), Subobject, Args,
- cast<CXXConstructorDecl>(Definition),
- Info, *Value);
+ return RecordExprEvaluator(Info, Subobject, *Value)
+ .VisitCXXConstructExpr(E, Type);
}
//===----------------------------------------------------------------------===//
@@ -6076,7 +6244,7 @@ public:
}
bool VisitMemberExpr(const MemberExpr *E) {
if (CheckReferencedDecl(E, E->getMemberDecl())) {
- VisitIgnoredValue(E->getBase());
+ VisitIgnoredBaseExpression(E->getBase());
return true;
}
@@ -6149,7 +6317,7 @@ static bool EvaluateInteger(const Expr *E, APSInt &Result, EvalInfo &Info) {
if (!Val.isInt()) {
// FIXME: It would be better to produce the diagnostic for casting
// a pointer to an integer.
- Info.Diag(E, diag::note_invalid_subexpr_in_const_expr);
+ Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr);
return false;
}
Result = Val.getInt();
@@ -6185,7 +6353,8 @@ bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) {
/// EvaluateBuiltinClassifyType - Evaluate __builtin_classify_type the same way
/// as GCC.
-static int EvaluateBuiltinClassifyType(const CallExpr *E) {
+static int EvaluateBuiltinClassifyType(const CallExpr *E,
+ const LangOptions &LangOpts) {
// The following enum mimics the values returned by GCC.
// FIXME: Does GCC differ between lvalue and rvalue references here?
enum gcc_type_class {
@@ -6205,37 +6374,123 @@ static int EvaluateBuiltinClassifyType(const CallExpr *E) {
if (E->getNumArgs() == 0)
return no_type_class;
- QualType ArgTy = E->getArg(0)->getType();
- if (ArgTy->isVoidType())
- return void_type_class;
- else if (ArgTy->isEnumeralType())
- return enumeral_type_class;
- else if (ArgTy->isBooleanType())
- return boolean_type_class;
- else if (ArgTy->isCharType())
- return string_type_class; // gcc doesn't appear to use char_type_class
- else if (ArgTy->isIntegerType())
- return integer_type_class;
- else if (ArgTy->isPointerType())
+ QualType CanTy = E->getArg(0)->getType().getCanonicalType();
+ const BuiltinType *BT = dyn_cast<BuiltinType>(CanTy);
+
+ switch (CanTy->getTypeClass()) {
+#define TYPE(ID, BASE)
+#define DEPENDENT_TYPE(ID, BASE) case Type::ID:
+#define NON_CANONICAL_TYPE(ID, BASE) case Type::ID:
+#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(ID, BASE) case Type::ID:
+#include "clang/AST/TypeNodes.def"
+ llvm_unreachable("CallExpr::isBuiltinClassifyType(): unimplemented type");
+
+ case Type::Builtin:
+ switch (BT->getKind()) {
+#define BUILTIN_TYPE(ID, SINGLETON_ID)
+#define SIGNED_TYPE(ID, SINGLETON_ID) case BuiltinType::ID: return integer_type_class;
+#define FLOATING_TYPE(ID, SINGLETON_ID) case BuiltinType::ID: return real_type_class;
+#define PLACEHOLDER_TYPE(ID, SINGLETON_ID) case BuiltinType::ID: break;
+#include "clang/AST/BuiltinTypes.def"
+ case BuiltinType::Void:
+ return void_type_class;
+
+ case BuiltinType::Bool:
+ return boolean_type_class;
+
+ case BuiltinType::Char_U: // gcc doesn't appear to use char_type_class
+ case BuiltinType::UChar:
+ case BuiltinType::UShort:
+ case BuiltinType::UInt:
+ case BuiltinType::ULong:
+ case BuiltinType::ULongLong:
+ case BuiltinType::UInt128:
+ return integer_type_class;
+
+ case BuiltinType::NullPtr:
+ return pointer_type_class;
+
+ case BuiltinType::WChar_U:
+ case BuiltinType::Char16:
+ case BuiltinType::Char32:
+ case BuiltinType::ObjCId:
+ case BuiltinType::ObjCClass:
+ case BuiltinType::ObjCSel:
+#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
+ case BuiltinType::Id:
+#include "clang/Basic/OpenCLImageTypes.def"
+ case BuiltinType::OCLSampler:
+ case BuiltinType::OCLEvent:
+ case BuiltinType::OCLClkEvent:
+ case BuiltinType::OCLQueue:
+ case BuiltinType::OCLNDRange:
+ case BuiltinType::OCLReserveID:
+ case BuiltinType::Dependent:
+ llvm_unreachable("CallExpr::isBuiltinClassifyType(): unimplemented type");
+ };
+
+ case Type::Enum:
+ return LangOpts.CPlusPlus ? enumeral_type_class : integer_type_class;
+ break;
+
+ case Type::Pointer:
return pointer_type_class;
- else if (ArgTy->isReferenceType())
- return reference_type_class;
- else if (ArgTy->isRealType())
- return real_type_class;
- else if (ArgTy->isComplexType())
+ break;
+
+ case Type::MemberPointer:
+ if (CanTy->isMemberDataPointerType())
+ return offset_type_class;
+ else {
+ // We expect member pointers to be either data or function pointers,
+ // nothing else.
+ assert(CanTy->isMemberFunctionPointerType());
+ return method_type_class;
+ }
+
+ case Type::Complex:
return complex_type_class;
- else if (ArgTy->isFunctionType())
- return function_type_class;
- else if (ArgTy->isStructureOrClassType())
- return record_type_class;
- else if (ArgTy->isUnionType())
- return union_type_class;
- else if (ArgTy->isArrayType())
- return array_type_class;
- else if (ArgTy->isUnionType())
- return union_type_class;
- else // FIXME: offset_type_class, method_type_class, & lang_type_class?
+
+ case Type::FunctionNoProto:
+ case Type::FunctionProto:
+ return LangOpts.CPlusPlus ? function_type_class : pointer_type_class;
+
+ case Type::Record:
+ if (const RecordType *RT = CanTy->getAs<RecordType>()) {
+ switch (RT->getDecl()->getTagKind()) {
+ case TagTypeKind::TTK_Struct:
+ case TagTypeKind::TTK_Class:
+ case TagTypeKind::TTK_Interface:
+ return record_type_class;
+
+ case TagTypeKind::TTK_Enum:
+ return LangOpts.CPlusPlus ? enumeral_type_class : integer_type_class;
+
+ case TagTypeKind::TTK_Union:
+ return union_type_class;
+ }
+ }
llvm_unreachable("CallExpr::isBuiltinClassifyType(): unimplemented type");
+
+ case Type::ConstantArray:
+ case Type::VariableArray:
+ case Type::IncompleteArray:
+ return LangOpts.CPlusPlus ? array_type_class : pointer_type_class;
+
+ case Type::BlockPointer:
+ case Type::LValueReference:
+ case Type::RValueReference:
+ case Type::Vector:
+ case Type::ExtVector:
+ case Type::Auto:
+ case Type::ObjCObject:
+ case Type::ObjCInterface:
+ case Type::ObjCObjectPointer:
+ case Type::Pipe:
+ case Type::Atomic:
+ llvm_unreachable("CallExpr::isBuiltinClassifyType(): unimplemented type");
+ }
+
+ llvm_unreachable("CallExpr::isBuiltinClassifyType(): unimplemented type");
}
/// EvaluateBuiltinConstantPForLValue - Determine the result of
@@ -6346,25 +6601,32 @@ static const Expr *ignorePointerCastsAndParens(const Expr *E) {
///
/// Please note: this function is specialized for how __builtin_object_size
/// views "objects".
+///
+/// If this encounters an invalid RecordDecl, it will always return true.
static bool isDesignatorAtObjectEnd(const ASTContext &Ctx, const LValue &LVal) {
assert(!LVal.Designator.Invalid);
- auto IsLastFieldDecl = [&Ctx](const FieldDecl *FD) {
- if (FD->getParent()->isUnion())
+ auto IsLastOrInvalidFieldDecl = [&Ctx](const FieldDecl *FD, bool &Invalid) {
+ const RecordDecl *Parent = FD->getParent();
+ Invalid = Parent->isInvalidDecl();
+ if (Invalid || Parent->isUnion())
return true;
- const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(FD->getParent());
+ const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(Parent);
return FD->getFieldIndex() + 1 == Layout.getFieldCount();
};
auto &Base = LVal.getLValueBase();
if (auto *ME = dyn_cast_or_null<MemberExpr>(Base.dyn_cast<const Expr *>())) {
if (auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
- if (!IsLastFieldDecl(FD))
- return false;
+ bool Invalid;
+ if (!IsLastOrInvalidFieldDecl(FD, Invalid))
+ return Invalid;
} else if (auto *IFD = dyn_cast<IndirectFieldDecl>(ME->getMemberDecl())) {
- for (auto *FD : IFD->chain())
- if (!IsLastFieldDecl(cast<FieldDecl>(FD)))
- return false;
+ for (auto *FD : IFD->chain()) {
+ bool Invalid;
+ if (!IsLastOrInvalidFieldDecl(cast<FieldDecl>(FD), Invalid))
+ return Invalid;
+ }
}
}
@@ -6387,8 +6649,9 @@ static bool isDesignatorAtObjectEnd(const ASTContext &Ctx, const LValue &LVal) {
return false;
BaseType = CT->getElementType();
} else if (auto *FD = getAsField(LVal.Designator.Entries[I])) {
- if (!IsLastFieldDecl(FD))
- return false;
+ bool Invalid;
+ if (!IsLastOrInvalidFieldDecl(FD, Invalid))
+ return Invalid;
BaseType = FD->getType();
} else {
assert(getAsBaseClass(LVal.Designator.Entries[I]) != nullptr &&
@@ -6607,7 +6870,7 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
}
case Builtin::BI__builtin_classify_type:
- return Success(EvaluateBuiltinClassifyType(E), E);
+ return Success(EvaluateBuiltinClassifyType(E, Info.getLangOpts()), E);
// FIXME: BI__builtin_clrsb
// FIXME: BI__builtin_clrsbl
@@ -6899,23 +7162,14 @@ class DataRecursiveIntBinOpEvaluator {
Job() = default;
Job(Job &&J)
: E(J.E), LHSResult(J.LHSResult), Kind(J.Kind),
- StoredInfo(J.StoredInfo), OldEvalStatus(J.OldEvalStatus) {
- J.StoredInfo = nullptr;
- }
+ SpecEvalRAII(std::move(J.SpecEvalRAII)) {}
void startSpeculativeEval(EvalInfo &Info) {
- OldEvalStatus = Info.EvalStatus;
- Info.EvalStatus.Diag = nullptr;
- StoredInfo = &Info;
- }
- ~Job() {
- if (StoredInfo) {
- StoredInfo->EvalStatus = OldEvalStatus;
- }
+ SpecEvalRAII = SpeculativeEvaluationRAII(Info);
}
+
private:
- EvalInfo *StoredInfo = nullptr; // non-null if status changed.
- Expr::EvalStatus OldEvalStatus;
+ SpeculativeEvaluationRAII SpecEvalRAII;
};
SmallVector<Job, 16> Queue;
@@ -6935,7 +7189,9 @@ public:
static bool shouldEnqueue(const BinaryOperator *E) {
return E->getOpcode() == BO_Comma ||
E->isLogicalOp() ||
- (E->getLHS()->getType()->isIntegralOrEnumerationType() &&
+ (E->isRValue() &&
+ E->getType()->isIntegralOrEnumerationType() &&
+ E->getLHS()->getType()->isIntegralOrEnumerationType() &&
E->getRHS()->getType()->isIntegralOrEnumerationType());
}
@@ -7017,7 +7273,7 @@ bool DataRecursiveIntBinOpEvaluator::
LHSResult.Failed = true;
// Since we weren't able to evaluate the left hand side, it
- // must have had side effects.
+ // might have had side effects.
if (!Info.noteSideEffect())
return false;
@@ -7033,7 +7289,7 @@ bool DataRecursiveIntBinOpEvaluator::
assert(E->getLHS()->getType()->isIntegralOrEnumerationType() &&
E->getRHS()->getType()->isIntegralOrEnumerationType());
- if (LHSResult.Failed && !Info.keepEvaluatingAfterFailure())
+ if (LHSResult.Failed && !Info.noteFailure())
return false; // Ignore RHS;
return true;
@@ -7185,10 +7441,34 @@ void DataRecursiveIntBinOpEvaluator::process(EvalResult &Result) {
llvm_unreachable("Invalid Job::Kind!");
}
+namespace {
+/// Used when we determine that we should fail, but can keep evaluating prior to
+/// noting that we had a failure.
+class DelayedNoteFailureRAII {
+ EvalInfo &Info;
+ bool NoteFailure;
+
+public:
+ DelayedNoteFailureRAII(EvalInfo &Info, bool NoteFailure = true)
+ : Info(Info), NoteFailure(NoteFailure) {}
+ ~DelayedNoteFailureRAII() {
+ if (NoteFailure) {
+ bool ContinueAfterFailure = Info.noteFailure();
+ (void)ContinueAfterFailure;
+ assert(ContinueAfterFailure &&
+ "Shouldn't have kept evaluating on failure.");
+ }
+ }
+};
+}
+
bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
+ // We don't call noteFailure immediately because the assignment happens after
+ // we evaluate LHS and RHS.
if (!Info.keepEvaluatingAfterFailure() && E->isAssignmentOp())
return Error(E);
+ DelayedNoteFailureRAII MaybeNoteFailureLater(Info, E->isAssignmentOp());
if (DataRecursiveIntBinOpEvaluator::shouldEnqueue(E))
return DataRecursiveIntBinOpEvaluator(*this, Result).Traverse(E);
@@ -7211,7 +7491,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
} else {
LHSOK = EvaluateComplex(E->getLHS(), LHS, Info);
}
- if (!LHSOK && !Info.keepEvaluatingAfterFailure())
+ if (!LHSOK && !Info.noteFailure())
return false;
if (E->getRHS()->getType()->isRealFloatingType()) {
@@ -7259,7 +7539,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
APFloat RHS(0.0), LHS(0.0);
bool LHSOK = EvaluateFloat(E->getRHS(), RHS, Info);
- if (!LHSOK && !Info.keepEvaluatingAfterFailure())
+ if (!LHSOK && !Info.noteFailure())
return false;
if (!EvaluateFloat(E->getLHS(), LHS, Info) || !LHSOK)
@@ -7293,7 +7573,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
LValue LHSValue, RHSValue;
bool LHSOK = EvaluatePointer(E->getLHS(), LHSValue, Info);
- if (!LHSOK && !Info.keepEvaluatingAfterFailure())
+ if (!LHSOK && !Info.noteFailure())
return false;
if (!EvaluatePointer(E->getRHS(), RHSValue, Info) || !LHSOK)
@@ -7387,7 +7667,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
// C, array of zero length). Pointer subtraction in such cases has
// undefined behavior, so is not constant.
if (ElementSize.isZero()) {
- Info.Diag(E, diag::note_constexpr_pointer_subtraction_zero_size)
+ Info.FFDiag(E, diag::note_constexpr_pointer_subtraction_zero_size)
<< ElementType;
return false;
}
@@ -7510,7 +7790,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
MemberPtr LHSValue, RHSValue;
bool LHSOK = EvaluateMemberPointer(E->getLHS(), LHSValue, Info);
- if (!LHSOK && Info.keepEvaluatingAfterFailure())
+ if (!LHSOK && !Info.noteFailure())
return false;
if (!EvaluateMemberPointer(E->getRHS(), RHSValue, Info) || !LHSOK)
@@ -8082,7 +8362,7 @@ bool FloatExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
APFloat RHS(0.0);
bool LHSOK = EvaluateFloat(E->getLHS(), Result, Info);
- if (!LHSOK && !Info.keepEvaluatingAfterFailure())
+ if (!LHSOK && !Info.noteFailure())
return false;
return EvaluateFloat(E->getRHS(), RHS, Info) && LHSOK &&
handleFloatFloatBinOp(Info, E, Result, E->getOpcode(), RHS);
@@ -8359,7 +8639,7 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
} else {
LHSOK = Visit(E->getLHS());
}
- if (!LHSOK && !Info.keepEvaluatingAfterFailure())
+ if (!LHSOK && !Info.noteFailure())
return false;
ComplexValue RHS;
@@ -8513,12 +8793,14 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
APFloat MaxCD = maxnum(abs(C), abs(D));
if (MaxCD.isFinite()) {
DenomLogB = ilogb(MaxCD);
- C = scalbn(C, -DenomLogB);
- D = scalbn(D, -DenomLogB);
+ C = scalbn(C, -DenomLogB, APFloat::rmNearestTiesToEven);
+ D = scalbn(D, -DenomLogB, APFloat::rmNearestTiesToEven);
}
APFloat Denom = C * C + D * D;
- ResR = scalbn((A * C + B * D) / Denom, -DenomLogB);
- ResI = scalbn((B * C - A * D) / Denom, -DenomLogB);
+ ResR = scalbn((A * C + B * D) / Denom, -DenomLogB,
+ APFloat::rmNearestTiesToEven);
+ ResI = scalbn((B * C - A * D) / Denom, -DenomLogB,
+ APFloat::rmNearestTiesToEven);
if (ResR.isNaN() && ResI.isNaN()) {
if (Denom.isPosZero() && (!A.isNaN() || !B.isNaN())) {
ResR = APFloat::getInf(ResR.getSemantics(), C.isNegative()) * A;
@@ -8758,10 +9040,10 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) {
if (!EvaluateAtomic(E, Result, Info))
return false;
} else if (Info.getLangOpts().CPlusPlus11) {
- Info.Diag(E, diag::note_constexpr_nonliteral) << E->getType();
+ Info.FFDiag(E, diag::note_constexpr_nonliteral) << E->getType();
return false;
} else {
- Info.Diag(E, diag::note_invalid_subexpr_in_const_expr);
+ Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr);
return false;
}
@@ -8885,6 +9167,20 @@ bool Expr::EvaluateAsInt(APSInt &Result, const ASTContext &Ctx,
return true;
}
+bool Expr::EvaluateAsFloat(APFloat &Result, const ASTContext &Ctx,
+ SideEffectsKind AllowSideEffects) const {
+ if (!getType()->isRealFloatingType())
+ return false;
+
+ EvalResult ExprResult;
+ if (!EvaluateAsRValue(ExprResult, Ctx) || !ExprResult.Val.isFloat() ||
+ hasUnacceptableSideEffect(ExprResult, AllowSideEffects))
+ return false;
+
+ Result = ExprResult.Val.getFloat();
+ return true;
+}
+
bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const {
EvalInfo Info(Ctx, Result, EvalInfo::EM_ConstantFold);
@@ -9070,6 +9366,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
case Expr::TypoExprClass:
case Expr::DependentScopeDeclRefExprClass:
case Expr::CXXConstructExprClass:
+ case Expr::CXXInheritedCtorInitExprClass:
case Expr::CXXStdInitializerListExprClass:
case Expr::CXXBindTemporaryExprClass:
case Expr::ExprWithCleanupsClass:
@@ -9089,6 +9386,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
case Expr::ObjCPropertyRefExprClass:
case Expr::ObjCSubscriptRefExprClass:
case Expr::ObjCIsaExprClass:
+ case Expr::ObjCAvailabilityCheckExprClass:
case Expr::ShuffleVectorExprClass:
case Expr::ConvertVectorExprClass:
case Expr::BlockExprClass:
@@ -9533,17 +9831,17 @@ bool Expr::isPotentialConstantExpr(const FunctionDecl *FD,
ArrayRef<const Expr*> Args;
- SourceLocation Loc = FD->getLocation();
-
APValue Scratch;
if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) {
// Evaluate the call as a constant initializer, to allow the construction
// of objects of non-literal types.
Info.setEvaluatingDecl(This.getLValueBase(), Scratch);
- HandleConstructorCall(Loc, This, Args, CD, Info, Scratch);
- } else
+ HandleConstructorCall(&VIE, This, Args, CD, Info, Scratch);
+ } else {
+ SourceLocation Loc = FD->getLocation();
HandleFunctionCall(Loc, FD, (MD && MD->isInstance()) ? &This : nullptr,
Args, FD->getBody(), Info, Scratch, nullptr);
+ }
return Diags.empty();
}
OpenPOWER on IntegriCloud