Skip to content

Commit e637cbe

Browse files
committed
Refactor: split Uninitialized state on APValue into an "Absent" state
representing no such object, and an "Indeterminate" state representing an uninitialized object. The latter is not yet used, but soon will be. llvm-svn: 361328
1 parent a49496f commit e637cbe

File tree

9 files changed

+83
-61
lines changed

9 files changed

+83
-61
lines changed

clang/include/clang/AST/APValue.h

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,10 @@ class APValue {
7878
typedef llvm::APFloat APFloat;
7979
public:
8080
enum ValueKind {
81-
Uninitialized,
81+
/// There is no such object (it's outside its lifetime).
82+
None,
83+
/// This object has an indeterminate value (C++ [basic.indet]).
84+
Indeterminate,
8285
Int,
8386
Float,
8487
FixedPoint,
@@ -231,58 +234,59 @@ class APValue {
231234
DataType Data;
232235

233236
public:
234-
APValue() : Kind(Uninitialized) {}
235-
explicit APValue(APSInt I) : Kind(Uninitialized) {
237+
APValue() : Kind(None) {}
238+
explicit APValue(APSInt I) : Kind(None) {
236239
MakeInt(); setInt(std::move(I));
237240
}
238-
explicit APValue(APFloat F) : Kind(Uninitialized) {
241+
explicit APValue(APFloat F) : Kind(None) {
239242
MakeFloat(); setFloat(std::move(F));
240243
}
241-
explicit APValue(APFixedPoint FX) : Kind(Uninitialized) {
244+
explicit APValue(APFixedPoint FX) : Kind(None) {
242245
MakeFixedPoint(std::move(FX));
243246
}
244-
explicit APValue(const APValue *E, unsigned N) : Kind(Uninitialized) {
247+
explicit APValue(const APValue *E, unsigned N) : Kind(None) {
245248
MakeVector(); setVector(E, N);
246249
}
247-
APValue(APSInt R, APSInt I) : Kind(Uninitialized) {
250+
APValue(APSInt R, APSInt I) : Kind(None) {
248251
MakeComplexInt(); setComplexInt(std::move(R), std::move(I));
249252
}
250-
APValue(APFloat R, APFloat I) : Kind(Uninitialized) {
253+
APValue(APFloat R, APFloat I) : Kind(None) {
251254
MakeComplexFloat(); setComplexFloat(std::move(R), std::move(I));
252255
}
253256
APValue(const APValue &RHS);
254-
APValue(APValue &&RHS) : Kind(Uninitialized) { swap(RHS); }
257+
APValue(APValue &&RHS) : Kind(None) { swap(RHS); }
255258
APValue(LValueBase B, const CharUnits &O, NoLValuePath N,
256259
bool IsNullPtr = false)
257-
: Kind(Uninitialized) {
260+
: Kind(None) {
258261
MakeLValue(); setLValue(B, O, N, IsNullPtr);
259262
}
260263
APValue(LValueBase B, const CharUnits &O, ArrayRef<LValuePathEntry> Path,
261264
bool OnePastTheEnd, bool IsNullPtr = false)
262-
: Kind(Uninitialized) {
265+
: Kind(None) {
263266
MakeLValue(); setLValue(B, O, Path, OnePastTheEnd, IsNullPtr);
264267
}
265-
APValue(UninitArray, unsigned InitElts, unsigned Size) : Kind(Uninitialized) {
268+
APValue(UninitArray, unsigned InitElts, unsigned Size) : Kind(None) {
266269
MakeArray(InitElts, Size);
267270
}
268-
APValue(UninitStruct, unsigned B, unsigned M) : Kind(Uninitialized) {
271+
APValue(UninitStruct, unsigned B, unsigned M) : Kind(None) {
269272
MakeStruct(B, M);
270273
}
271274
explicit APValue(const FieldDecl *D, const APValue &V = APValue())
272-
: Kind(Uninitialized) {
275+
: Kind(None) {
273276
MakeUnion(); setUnion(D, V);
274277
}
275278
APValue(const ValueDecl *Member, bool IsDerivedMember,
276-
ArrayRef<const CXXRecordDecl*> Path) : Kind(Uninitialized) {
279+
ArrayRef<const CXXRecordDecl*> Path) : Kind(None) {
277280
MakeMemberPointer(Member, IsDerivedMember, Path);
278281
}
279282
APValue(const AddrLabelExpr* LHSExpr, const AddrLabelExpr* RHSExpr)
280-
: Kind(Uninitialized) {
283+
: Kind(None) {
281284
MakeAddrLabelDiff(); setAddrLabelDiff(LHSExpr, RHSExpr);
282285
}
283286

284287
~APValue() {
285-
MakeUninit();
288+
if (Kind != None && Kind != Indeterminate)
289+
DestroyDataAndMakeUninit();
286290
}
287291

288292
/// Returns whether the object performed allocations.
@@ -296,7 +300,11 @@ class APValue {
296300
void swap(APValue &RHS);
297301

298302
ValueKind getKind() const { return Kind; }
299-
bool isUninit() const { return Kind == Uninitialized; }
303+
304+
bool isAbsent() const { return Kind == None; }
305+
bool isIndeterminate() const { return Kind == Indeterminate; }
306+
bool hasValue() const { return Kind != None && Kind != Indeterminate; }
307+
300308
bool isInt() const { return Kind == Int; }
301309
bool isFloat() const { return Kind == Float; }
302310
bool isFixedPoint() const { return Kind == FixedPoint; }
@@ -536,56 +544,52 @@ class APValue {
536544

537545
private:
538546
void DestroyDataAndMakeUninit();
539-
void MakeUninit() {
540-
if (Kind != Uninitialized)
541-
DestroyDataAndMakeUninit();
542-
}
543547
void MakeInt() {
544-
assert(isUninit() && "Bad state change");
548+
assert(isAbsent() && "Bad state change");
545549
new ((void*)Data.buffer) APSInt(1);
546550
Kind = Int;
547551
}
548552
void MakeFloat() {
549-
assert(isUninit() && "Bad state change");
553+
assert(isAbsent() && "Bad state change");
550554
new ((void*)(char*)Data.buffer) APFloat(0.0);
551555
Kind = Float;
552556
}
553557
void MakeFixedPoint(APFixedPoint &&FX) {
554-
assert(isUninit() && "Bad state change");
558+
assert(isAbsent() && "Bad state change");
555559
new ((void *)(char *)Data.buffer) APFixedPoint(std::move(FX));
556560
Kind = FixedPoint;
557561
}
558562
void MakeVector() {
559-
assert(isUninit() && "Bad state change");
563+
assert(isAbsent() && "Bad state change");
560564
new ((void*)(char*)Data.buffer) Vec();
561565
Kind = Vector;
562566
}
563567
void MakeComplexInt() {
564-
assert(isUninit() && "Bad state change");
568+
assert(isAbsent() && "Bad state change");
565569
new ((void*)(char*)Data.buffer) ComplexAPSInt();
566570
Kind = ComplexInt;
567571
}
568572
void MakeComplexFloat() {
569-
assert(isUninit() && "Bad state change");
573+
assert(isAbsent() && "Bad state change");
570574
new ((void*)(char*)Data.buffer) ComplexAPFloat();
571575
Kind = ComplexFloat;
572576
}
573577
void MakeLValue();
574578
void MakeArray(unsigned InitElts, unsigned Size);
575579
void MakeStruct(unsigned B, unsigned M) {
576-
assert(isUninit() && "Bad state change");
580+
assert(isAbsent() && "Bad state change");
577581
new ((void*)(char*)Data.buffer) StructData(B, M);
578582
Kind = Struct;
579583
}
580584
void MakeUnion() {
581-
assert(isUninit() && "Bad state change");
585+
assert(isAbsent() && "Bad state change");
582586
new ((void*)(char*)Data.buffer) UnionData();
583587
Kind = Union;
584588
}
585589
void MakeMemberPointer(const ValueDecl *Member, bool IsDerivedMember,
586590
ArrayRef<const CXXRecordDecl*> Path);
587591
void MakeAddrLabelDiff() {
588-
assert(isUninit() && "Bad state change");
592+
assert(isAbsent() && "Bad state change");
589593
new ((void*)(char*)Data.buffer) AddrLabelDiffData();
590594
Kind = AddrLabelDiff;
591595
}

clang/include/clang/Basic/DiagnosticASTKinds.td

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,8 @@ def note_constexpr_lifetime_ended : Note<
115115
def note_constexpr_access_uninit : Note<
116116
"%select{read of|assignment to|increment of|decrement of|member call on|"
117117
"dynamic_cast of|typeid applied to}0 "
118-
"object outside its lifetime is not allowed in a constant expression">;
118+
"%select{object outside its lifetime|uninitialized object}1 "
119+
"is not allowed in a constant expression">;
119120
def note_constexpr_use_uninit_reference : Note<
120121
"use of reference outside its lifetime "
121122
"is not allowed in a constant expression">;

clang/lib/AST/APValue.cpp

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -219,9 +219,11 @@ APValue::UnionData::~UnionData () {
219219
delete Value;
220220
}
221221

222-
APValue::APValue(const APValue &RHS) : Kind(Uninitialized) {
222+
APValue::APValue(const APValue &RHS) : Kind(None) {
223223
switch (RHS.getKind()) {
224-
case Uninitialized:
224+
case None:
225+
case Indeterminate:
226+
Kind = RHS.getKind();
225227
break;
226228
case Int:
227229
MakeInt();
@@ -313,12 +315,13 @@ void APValue::DestroyDataAndMakeUninit() {
313315
((MemberPointerData*)(char*)Data.buffer)->~MemberPointerData();
314316
else if (Kind == AddrLabelDiff)
315317
((AddrLabelDiffData*)(char*)Data.buffer)->~AddrLabelDiffData();
316-
Kind = Uninitialized;
318+
Kind = None;
317319
}
318320

319321
bool APValue::needsCleanup() const {
320322
switch (getKind()) {
321-
case Uninitialized:
323+
case None:
324+
case Indeterminate:
322325
case AddrLabelDiff:
323326
return false;
324327
case Struct:
@@ -376,8 +379,11 @@ static double GetApproxValue(const llvm::APFloat &F) {
376379

377380
void APValue::dump(raw_ostream &OS) const {
378381
switch (getKind()) {
379-
case Uninitialized:
380-
OS << "Uninitialized";
382+
case None:
383+
OS << "None";
384+
return;
385+
case Indeterminate:
386+
OS << "Indeterminate";
381387
return;
382388
case Int:
383389
OS << "Int: " << getInt();
@@ -452,7 +458,10 @@ void APValue::dump(raw_ostream &OS) const {
452458

453459
void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{
454460
switch (getKind()) {
455-
case APValue::Uninitialized:
461+
case APValue::None:
462+
Out << "<out of lifetime>";
463+
return;
464+
case APValue::Indeterminate:
456465
Out << "<uninitialized>";
457466
return;
458467
case APValue::Int:
@@ -781,21 +790,21 @@ ArrayRef<const CXXRecordDecl*> APValue::getMemberPointerPath() const {
781790
}
782791

783792
void APValue::MakeLValue() {
784-
assert(isUninit() && "Bad state change");
793+
assert(isAbsent() && "Bad state change");
785794
static_assert(sizeof(LV) <= DataSize, "LV too big");
786795
new ((void*)(char*)Data.buffer) LV();
787796
Kind = LValue;
788797
}
789798

790799
void APValue::MakeArray(unsigned InitElts, unsigned Size) {
791-
assert(isUninit() && "Bad state change");
800+
assert(isAbsent() && "Bad state change");
792801
new ((void*)(char*)Data.buffer) Arr(InitElts, Size);
793802
Kind = Array;
794803
}
795804

796805
void APValue::MakeMemberPointer(const ValueDecl *Member, bool IsDerivedMember,
797806
ArrayRef<const CXXRecordDecl*> Path) {
798-
assert(isUninit() && "Bad state change");
807+
assert(isAbsent() && "Bad state change");
799808
MemberPointerData *MPD = new ((void*)(char*)Data.buffer) MemberPointerData;
800809
Kind = MemberPointer;
801810
MPD->MemberAndIsDerivedMember.setPointer(Member);

clang/lib/AST/Decl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2302,7 +2302,7 @@ APValue *VarDecl::evaluateValue(
23022302
// first time it is evaluated. FIXME: The notes won't always be emitted the
23032303
// first time we try evaluation, so might not be produced at all.
23042304
if (Eval->WasEvaluated)
2305-
return Eval->Evaluated.isUninit() ? nullptr : &Eval->Evaluated;
2305+
return Eval->Evaluated.isAbsent() ? nullptr : &Eval->Evaluated;
23062306

23072307
const auto *Init = cast<Expr>(Eval->Value);
23082308
assert(!Init->isValueDependent());

clang/lib/AST/ExprConstant.cpp

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1291,7 +1291,7 @@ APValue &CallStackFrame::createTemporary(const void *Key,
12911291
bool IsLifetimeExtended) {
12921292
unsigned Version = Info.CurrentCall->getTempVersion();
12931293
APValue &Result = Temporaries[MapKeyTy(Key, Version)];
1294-
assert(Result.isUninit() && "temporary created multiple times");
1294+
assert(Result.isAbsent() && "temporary created multiple times");
12951295
Info.CleanupStack.push_back(Cleanup(&Result, IsLifetimeExtended));
12961296
return Result;
12971297
}
@@ -2025,7 +2025,7 @@ static bool
20252025
CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, QualType Type,
20262026
const APValue &Value,
20272027
Expr::ConstExprUsage Usage = Expr::EvaluateForCodeGen) {
2028-
if (Value.isUninit()) {
2028+
if (!Value.hasValue()) {
20292029
Info.FFDiag(DiagLoc, diag::note_constexpr_uninitialized)
20302030
<< true << Type;
20312031
return false;
@@ -2108,7 +2108,8 @@ static bool EvalPointerValueAsBool(const APValue &Value, bool &Result) {
21082108

21092109
static bool HandleConversionToBool(const APValue &Val, bool &Result) {
21102110
switch (Val.getKind()) {
2111-
case APValue::Uninitialized:
2111+
case APValue::None:
2112+
case APValue::Indeterminate:
21122113
return false;
21132114
case APValue::Int:
21142115
Result = Val.getInt().getBoolValue();
@@ -2971,10 +2972,10 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
29712972

29722973
// Walk the designator's path to find the subobject.
29732974
for (unsigned I = 0, N = Sub.Entries.size(); /**/; ++I) {
2974-
if (O->isUninit()) {
2975+
if (!O->hasValue()) {
29752976
if (!Info.checkingPotentialConstantExpression())
29762977
Info.FFDiag(E, diag::note_constexpr_access_uninit)
2977-
<< handler.AccessKind;
2978+
<< handler.AccessKind << O->isIndeterminate();
29782979
return handler.failed();
29792980
}
29802981

@@ -5040,7 +5041,7 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
50405041
}
50415042

50425043
// Reserve space for the struct members.
5043-
if (!RD->isUnion() && Result.isUninit())
5044+
if (!RD->isUnion() && !Result.hasValue())
50445045
Result = APValue(APValue::UninitStruct(), RD->getNumBases(),
50455046
std::distance(RD->field_begin(), RD->field_end()));
50465047

@@ -5097,7 +5098,7 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
50975098
// subobject other than the first.
50985099
// FIXME: In this case, the values of the other subobjects are
50995100
// specified, since zero-initialization sets all padding bits to zero.
5100-
if (Value->isUninit() ||
5101+
if (!Value->hasValue() ||
51015102
(Value->isUnion() && Value->getUnionField() != FD)) {
51025103
if (CD->isUnion())
51035104
*Value = APValue(FD);
@@ -5953,7 +5954,9 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
59535954
APValue *V;
59545955
if (!evaluateVarDeclInit(Info, E, VD, Frame, V, nullptr))
59555956
return false;
5956-
if (V->isUninit()) {
5957+
if (!V->hasValue()) {
5958+
// FIXME: Is it possible for V to be indeterminate here? If so, we should
5959+
// adjust the diagnostic to say that.
59575960
if (!Info.checkingPotentialConstantExpression())
59585961
Info.FFDiag(E, diag::note_constexpr_use_uninit_reference);
59595962
return false;
@@ -7217,7 +7220,7 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
72177220
return EvaluateInPlace(Result.getUnionValue(), Info, Subobject, InitExpr);
72187221
}
72197222

7220-
if (Result.isUninit())
7223+
if (!Result.hasValue())
72217224
Result = APValue(APValue::UninitStruct(), CXXRD ? CXXRD->getNumBases() : 0,
72227225
std::distance(RD->field_begin(), RD->field_end()));
72237226
unsigned ElementNo = 0;
@@ -7294,7 +7297,7 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
72947297
bool ZeroInit = E->requiresZeroInitialization();
72957298
if (CheckTrivialDefaultConstructor(Info, E->getExprLoc(), FD, ZeroInit)) {
72967299
// If we've already performed zero-initialization, we're already done.
7297-
if (!Result.isUninit())
7300+
if (Result.hasValue())
72987301
return true;
72997302

73007303
// We can get here in two different ways:
@@ -7794,7 +7797,7 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
77947797

77957798
// If the array was previously zero-initialized, preserve the
77967799
// zero-initialized values.
7797-
if (!Filler.isUninit()) {
7800+
if (Filler.hasValue()) {
77987801
for (unsigned I = 0, E = Result.getArrayInitializedElts(); I != E; ++I)
77997802
Result.getArrayInitializedElt(I) = Filler;
78007803
if (Result.hasArrayFiller())
@@ -7863,7 +7866,7 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
78637866
const LValue &Subobject,
78647867
APValue *Value,
78657868
QualType Type) {
7866-
bool HadZeroInit = !Value->isUninit();
7869+
bool HadZeroInit = Value->hasValue();
78677870

78687871
if (const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(Type)) {
78697872
unsigned N = CAT->getSize().getZExtValue();
@@ -8427,7 +8430,7 @@ static bool EvaluateBuiltinConstantP(EvalInfo &Info, const Expr *Arg) {
84278430
return EvaluateBuiltinConstantPForLValue(V);
84288431

84298432
// Otherwise, any constant value is good enough.
8430-
return V.getKind() != APValue::Uninitialized;
8433+
return V.hasValue();
84318434
}
84328435

84338436
// Anything else isn't considered to be sufficiently constant.

clang/lib/CodeGen/CGExprConstant.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1860,8 +1860,10 @@ ConstantLValueEmitter::VisitMaterializeTemporaryExpr(
18601860
llvm::Constant *ConstantEmitter::tryEmitPrivate(const APValue &Value,
18611861
QualType DestType) {
18621862
switch (Value.getKind()) {
1863-
case APValue::Uninitialized:
1864-
llvm_unreachable("Constant expressions should be initialized.");
1863+
case APValue::None:
1864+
case APValue::Indeterminate:
1865+
// Out-of-lifetime and indeterminate values can be modeled as 'undef'.
1866+
return llvm::UndefValue::get(CGM.getTypes().ConvertType(DestType));
18651867
case APValue::LValue:
18661868
return ConstantLValueEmitter(*this, Value, DestType).tryEmit();
18671869
case APValue::Int:

0 commit comments

Comments
 (0)