typedef llvm::APFloat APFloat;
public:
enum ValueKind {
- Uninitialized,
+ /// There is no such object (it's outside its lifetime).
+ None,
+ /// This object has an indeterminate value (C++ [basic.indet]).
+ Indeterminate,
Int,
Float,
FixedPoint,
DataType Data;
public:
- APValue() : Kind(Uninitialized) {}
- explicit APValue(APSInt I) : Kind(Uninitialized) {
+ APValue() : Kind(None) {}
+ explicit APValue(APSInt I) : Kind(None) {
MakeInt(); setInt(std::move(I));
}
- explicit APValue(APFloat F) : Kind(Uninitialized) {
+ explicit APValue(APFloat F) : Kind(None) {
MakeFloat(); setFloat(std::move(F));
}
- explicit APValue(APFixedPoint FX) : Kind(Uninitialized) {
+ explicit APValue(APFixedPoint FX) : Kind(None) {
MakeFixedPoint(std::move(FX));
}
- explicit APValue(const APValue *E, unsigned N) : Kind(Uninitialized) {
+ explicit APValue(const APValue *E, unsigned N) : Kind(None) {
MakeVector(); setVector(E, N);
}
- APValue(APSInt R, APSInt I) : Kind(Uninitialized) {
+ APValue(APSInt R, APSInt I) : Kind(None) {
MakeComplexInt(); setComplexInt(std::move(R), std::move(I));
}
- APValue(APFloat R, APFloat I) : Kind(Uninitialized) {
+ APValue(APFloat R, APFloat I) : Kind(None) {
MakeComplexFloat(); setComplexFloat(std::move(R), std::move(I));
}
APValue(const APValue &RHS);
- APValue(APValue &&RHS) : Kind(Uninitialized) { swap(RHS); }
+ APValue(APValue &&RHS) : Kind(None) { swap(RHS); }
APValue(LValueBase B, const CharUnits &O, NoLValuePath N,
bool IsNullPtr = false)
- : Kind(Uninitialized) {
+ : Kind(None) {
MakeLValue(); setLValue(B, O, N, IsNullPtr);
}
APValue(LValueBase B, const CharUnits &O, ArrayRef<LValuePathEntry> Path,
bool OnePastTheEnd, bool IsNullPtr = false)
- : Kind(Uninitialized) {
+ : Kind(None) {
MakeLValue(); setLValue(B, O, Path, OnePastTheEnd, IsNullPtr);
}
- APValue(UninitArray, unsigned InitElts, unsigned Size) : Kind(Uninitialized) {
+ APValue(UninitArray, unsigned InitElts, unsigned Size) : Kind(None) {
MakeArray(InitElts, Size);
}
- APValue(UninitStruct, unsigned B, unsigned M) : Kind(Uninitialized) {
+ APValue(UninitStruct, unsigned B, unsigned M) : Kind(None) {
MakeStruct(B, M);
}
explicit APValue(const FieldDecl *D, const APValue &V = APValue())
- : Kind(Uninitialized) {
+ : Kind(None) {
MakeUnion(); setUnion(D, V);
}
APValue(const ValueDecl *Member, bool IsDerivedMember,
- ArrayRef<const CXXRecordDecl*> Path) : Kind(Uninitialized) {
+ ArrayRef<const CXXRecordDecl*> Path) : Kind(None) {
MakeMemberPointer(Member, IsDerivedMember, Path);
}
APValue(const AddrLabelExpr* LHSExpr, const AddrLabelExpr* RHSExpr)
- : Kind(Uninitialized) {
+ : Kind(None) {
MakeAddrLabelDiff(); setAddrLabelDiff(LHSExpr, RHSExpr);
}
~APValue() {
- MakeUninit();
+ if (Kind != None && Kind != Indeterminate)
+ DestroyDataAndMakeUninit();
}
/// Returns whether the object performed allocations.
void swap(APValue &RHS);
ValueKind getKind() const { return Kind; }
- bool isUninit() const { return Kind == Uninitialized; }
+
+ bool isAbsent() const { return Kind == None; }
+ bool isIndeterminate() const { return Kind == Indeterminate; }
+ bool hasValue() const { return Kind != None && Kind != Indeterminate; }
+
bool isInt() const { return Kind == Int; }
bool isFloat() const { return Kind == Float; }
bool isFixedPoint() const { return Kind == FixedPoint; }
private:
void DestroyDataAndMakeUninit();
- void MakeUninit() {
- if (Kind != Uninitialized)
- DestroyDataAndMakeUninit();
- }
void MakeInt() {
- assert(isUninit() && "Bad state change");
+ assert(isAbsent() && "Bad state change");
new ((void*)Data.buffer) APSInt(1);
Kind = Int;
}
void MakeFloat() {
- assert(isUninit() && "Bad state change");
+ assert(isAbsent() && "Bad state change");
new ((void*)(char*)Data.buffer) APFloat(0.0);
Kind = Float;
}
void MakeFixedPoint(APFixedPoint &&FX) {
- assert(isUninit() && "Bad state change");
+ assert(isAbsent() && "Bad state change");
new ((void *)(char *)Data.buffer) APFixedPoint(std::move(FX));
Kind = FixedPoint;
}
void MakeVector() {
- assert(isUninit() && "Bad state change");
+ assert(isAbsent() && "Bad state change");
new ((void*)(char*)Data.buffer) Vec();
Kind = Vector;
}
void MakeComplexInt() {
- assert(isUninit() && "Bad state change");
+ assert(isAbsent() && "Bad state change");
new ((void*)(char*)Data.buffer) ComplexAPSInt();
Kind = ComplexInt;
}
void MakeComplexFloat() {
- assert(isUninit() && "Bad state change");
+ assert(isAbsent() && "Bad state change");
new ((void*)(char*)Data.buffer) ComplexAPFloat();
Kind = ComplexFloat;
}
void MakeLValue();
void MakeArray(unsigned InitElts, unsigned Size);
void MakeStruct(unsigned B, unsigned M) {
- assert(isUninit() && "Bad state change");
+ assert(isAbsent() && "Bad state change");
new ((void*)(char*)Data.buffer) StructData(B, M);
Kind = Struct;
}
void MakeUnion() {
- assert(isUninit() && "Bad state change");
+ assert(isAbsent() && "Bad state change");
new ((void*)(char*)Data.buffer) UnionData();
Kind = Union;
}
void MakeMemberPointer(const ValueDecl *Member, bool IsDerivedMember,
ArrayRef<const CXXRecordDecl*> Path);
void MakeAddrLabelDiff() {
- assert(isUninit() && "Bad state change");
+ assert(isAbsent() && "Bad state change");
new ((void*)(char*)Data.buffer) AddrLabelDiffData();
Kind = AddrLabelDiff;
}
def note_constexpr_access_uninit : Note<
"%select{read of|assignment to|increment of|decrement of|member call on|"
"dynamic_cast of|typeid applied to}0 "
- "object outside its lifetime is not allowed in a constant expression">;
+ "%select{object outside its lifetime|uninitialized object}1 "
+ "is not allowed in a constant expression">;
def note_constexpr_use_uninit_reference : Note<
"use of reference outside its lifetime "
"is not allowed in a constant expression">;
delete Value;
}
-APValue::APValue(const APValue &RHS) : Kind(Uninitialized) {
+APValue::APValue(const APValue &RHS) : Kind(None) {
switch (RHS.getKind()) {
- case Uninitialized:
+ case None:
+ case Indeterminate:
+ Kind = RHS.getKind();
break;
case Int:
MakeInt();
((MemberPointerData*)(char*)Data.buffer)->~MemberPointerData();
else if (Kind == AddrLabelDiff)
((AddrLabelDiffData*)(char*)Data.buffer)->~AddrLabelDiffData();
- Kind = Uninitialized;
+ Kind = None;
}
bool APValue::needsCleanup() const {
switch (getKind()) {
- case Uninitialized:
+ case None:
+ case Indeterminate:
case AddrLabelDiff:
return false;
case Struct:
void APValue::dump(raw_ostream &OS) const {
switch (getKind()) {
- case Uninitialized:
- OS << "Uninitialized";
+ case None:
+ OS << "None";
+ return;
+ case Indeterminate:
+ OS << "Indeterminate";
return;
case Int:
OS << "Int: " << getInt();
void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{
switch (getKind()) {
- case APValue::Uninitialized:
+ case APValue::None:
+ Out << "<out of lifetime>";
+ return;
+ case APValue::Indeterminate:
Out << "<uninitialized>";
return;
case APValue::Int:
}
void APValue::MakeLValue() {
- assert(isUninit() && "Bad state change");
+ assert(isAbsent() && "Bad state change");
static_assert(sizeof(LV) <= DataSize, "LV too big");
new ((void*)(char*)Data.buffer) LV();
Kind = LValue;
}
void APValue::MakeArray(unsigned InitElts, unsigned Size) {
- assert(isUninit() && "Bad state change");
+ assert(isAbsent() && "Bad state change");
new ((void*)(char*)Data.buffer) Arr(InitElts, Size);
Kind = Array;
}
void APValue::MakeMemberPointer(const ValueDecl *Member, bool IsDerivedMember,
ArrayRef<const CXXRecordDecl*> Path) {
- assert(isUninit() && "Bad state change");
+ assert(isAbsent() && "Bad state change");
MemberPointerData *MPD = new ((void*)(char*)Data.buffer) MemberPointerData;
Kind = MemberPointer;
MPD->MemberAndIsDerivedMember.setPointer(Member);
// first time it is evaluated. FIXME: The notes won't always be emitted the
// first time we try evaluation, so might not be produced at all.
if (Eval->WasEvaluated)
- return Eval->Evaluated.isUninit() ? nullptr : &Eval->Evaluated;
+ return Eval->Evaluated.isAbsent() ? nullptr : &Eval->Evaluated;
const auto *Init = cast<Expr>(Eval->Value);
assert(!Init->isValueDependent());
bool IsLifetimeExtended) {
unsigned Version = Info.CurrentCall->getTempVersion();
APValue &Result = Temporaries[MapKeyTy(Key, Version)];
- assert(Result.isUninit() && "temporary created multiple times");
+ assert(Result.isAbsent() && "temporary created multiple times");
Info.CleanupStack.push_back(Cleanup(&Result, IsLifetimeExtended));
return Result;
}
CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, QualType Type,
const APValue &Value,
Expr::ConstExprUsage Usage = Expr::EvaluateForCodeGen) {
- if (Value.isUninit()) {
+ if (!Value.hasValue()) {
Info.FFDiag(DiagLoc, diag::note_constexpr_uninitialized)
<< true << Type;
return false;
static bool HandleConversionToBool(const APValue &Val, bool &Result) {
switch (Val.getKind()) {
- case APValue::Uninitialized:
+ case APValue::None:
+ case APValue::Indeterminate:
return false;
case APValue::Int:
Result = Val.getInt().getBoolValue();
// Walk the designator's path to find the subobject.
for (unsigned I = 0, N = Sub.Entries.size(); /**/; ++I) {
- if (O->isUninit()) {
+ if (!O->hasValue()) {
if (!Info.checkingPotentialConstantExpression())
Info.FFDiag(E, diag::note_constexpr_access_uninit)
- << handler.AccessKind;
+ << handler.AccessKind << O->isIndeterminate();
return handler.failed();
}
}
// Reserve space for the struct members.
- if (!RD->isUnion() && Result.isUninit())
+ if (!RD->isUnion() && !Result.hasValue())
Result = APValue(APValue::UninitStruct(), RD->getNumBases(),
std::distance(RD->field_begin(), RD->field_end()));
// subobject other than the first.
// FIXME: In this case, the values of the other subobjects are
// specified, since zero-initialization sets all padding bits to zero.
- if (Value->isUninit() ||
+ if (!Value->hasValue() ||
(Value->isUnion() && Value->getUnionField() != FD)) {
if (CD->isUnion())
*Value = APValue(FD);
APValue *V;
if (!evaluateVarDeclInit(Info, E, VD, Frame, V, nullptr))
return false;
- if (V->isUninit()) {
+ if (!V->hasValue()) {
+ // FIXME: Is it possible for V to be indeterminate here? If so, we should
+ // adjust the diagnostic to say that.
if (!Info.checkingPotentialConstantExpression())
Info.FFDiag(E, diag::note_constexpr_use_uninit_reference);
return false;
return EvaluateInPlace(Result.getUnionValue(), Info, Subobject, InitExpr);
}
- if (Result.isUninit())
+ if (!Result.hasValue())
Result = APValue(APValue::UninitStruct(), CXXRD ? CXXRD->getNumBases() : 0,
std::distance(RD->field_begin(), RD->field_end()));
unsigned ElementNo = 0;
bool ZeroInit = E->requiresZeroInitialization();
if (CheckTrivialDefaultConstructor(Info, E->getExprLoc(), FD, ZeroInit)) {
// If we've already performed zero-initialization, we're already done.
- if (!Result.isUninit())
+ if (Result.hasValue())
return true;
// We can get here in two different ways:
// If the array was previously zero-initialized, preserve the
// zero-initialized values.
- if (!Filler.isUninit()) {
+ if (Filler.hasValue()) {
for (unsigned I = 0, E = Result.getArrayInitializedElts(); I != E; ++I)
Result.getArrayInitializedElt(I) = Filler;
if (Result.hasArrayFiller())
const LValue &Subobject,
APValue *Value,
QualType Type) {
- bool HadZeroInit = !Value->isUninit();
+ bool HadZeroInit = Value->hasValue();
if (const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(Type)) {
unsigned N = CAT->getSize().getZExtValue();
return EvaluateBuiltinConstantPForLValue(V);
// Otherwise, any constant value is good enough.
- return V.getKind() != APValue::Uninitialized;
+ return V.hasValue();
}
// Anything else isn't considered to be sufficiently constant.
llvm::Constant *ConstantEmitter::tryEmitPrivate(const APValue &Value,
QualType DestType) {
switch (Value.getKind()) {
- case APValue::Uninitialized:
- llvm_unreachable("Constant expressions should be initialized.");
+ case APValue::None:
+ case APValue::Indeterminate:
+ // Out-of-lifetime and indeterminate values can be modeled as 'undef'.
+ return llvm::UndefValue::get(CGM.getTypes().ConvertType(DestType));
case APValue::LValue:
return ConstantLValueEmitter(*this, Value, DestType).tryEmit();
case APValue::Int:
void CodeGenFunction::EmitDeclRefExprDbgValue(const DeclRefExpr *E,
const APValue &Init) {
- assert(!Init.isUninit() && "Invalid DeclRefExpr initializer!");
+ assert(Init.hasValue() && "Invalid DeclRefExpr initializer!");
if (CGDebugInfo *Dbg = getDebugInfo())
if (CGM.getCodeGenOpts().getDebugInfo() >= codegenoptions::LimitedDebugInfo)
Dbg->EmitGlobalVariable(E->getDecl(), Init);
// evaluating the initializer if the surrounding constant expression
// modifies the temporary.
Value = getContext().getMaterializedTemporaryValue(E, false);
- if (Value && Value->isUninit())
+ if (Value && Value->isAbsent())
Value = nullptr;
}
// Convert the APValue to a TemplateArgument.
switch (Value.getKind()) {
- case APValue::Uninitialized:
+ case APValue::None:
assert(ParamType->isNullPtrType());
Converted = TemplateArgument(CanonParamType, /*isNullPtr*/true);
break;
+ case APValue::Indeterminate:
+ llvm_unreachable("result of constant evaluation should be initialized");
+ break;
case APValue::Int:
assert(ParamType->isIntegralOrEnumerationType());
Converted = TemplateArgument(Context, Value.getInt(), CanonParamType);