From: Richard Smith Date: Tue, 21 May 2019 23:15:18 +0000 (+0000) Subject: Refactor: split Uninitialized state on APValue into an "Absent" state X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=695aab4c2beb2412fc3531e9f55b22267ecf9af3;p=clang 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@361328 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/APValue.h b/include/clang/AST/APValue.h index 15f8944e4f..02a6394bd5 100644 --- a/include/clang/AST/APValue.h +++ b/include/clang/AST/APValue.h @@ -78,7 +78,10 @@ class APValue { 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, @@ -231,58 +234,59 @@ private: 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 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 Path) : Kind(Uninitialized) { + ArrayRef 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. @@ -296,7 +300,11 @@ public: 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; } @@ -536,56 +544,52 @@ public: 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 Path); void MakeAddrLabelDiff() { - assert(isUninit() && "Bad state change"); + assert(isAbsent() && "Bad state change"); new ((void*)(char*)Data.buffer) AddrLabelDiffData(); Kind = AddrLabelDiff; } diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td index a9e88d5ecb..f1172a91ea 100644 --- a/include/clang/Basic/DiagnosticASTKinds.td +++ b/include/clang/Basic/DiagnosticASTKinds.td @@ -115,7 +115,8 @@ def note_constexpr_lifetime_ended : Note< 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">; diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp index c5db3cd582..5d5e67a890 100644 --- a/lib/AST/APValue.cpp +++ b/lib/AST/APValue.cpp @@ -219,9 +219,11 @@ APValue::UnionData::~UnionData () { 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(); @@ -313,12 +315,13 @@ void APValue::DestroyDataAndMakeUninit() { ((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: @@ -376,8 +379,11 @@ static double GetApproxValue(const llvm::APFloat &F) { 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(); @@ -452,7 +458,10 @@ void APValue::dump(raw_ostream &OS) const { void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{ switch (getKind()) { - case APValue::Uninitialized: + case APValue::None: + Out << ""; + return; + case APValue::Indeterminate: Out << ""; return; case APValue::Int: @@ -781,21 +790,21 @@ ArrayRef APValue::getMemberPointerPath() const { } 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 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); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index bc0a5a4c67..8b77e01f4e 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -2302,7 +2302,7 @@ APValue *VarDecl::evaluateValue( // 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(Eval->Value); assert(!Init->isValueDependent()); diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index e654480f09..508456422b 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -1291,7 +1291,7 @@ APValue &CallStackFrame::createTemporary(const void *Key, 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; } @@ -2025,7 +2025,7 @@ static bool 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; @@ -2108,7 +2108,8 @@ static bool EvalPointerValueAsBool(const APValue &Value, bool &Result) { 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(); @@ -2971,10 +2972,10 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, // 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(); } @@ -5040,7 +5041,7 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This, } // 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())); @@ -5097,7 +5098,7 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This, // 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); @@ -5953,7 +5954,9 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) { 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; @@ -7217,7 +7220,7 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { 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; @@ -7294,7 +7297,7 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E, 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: @@ -7794,7 +7797,7 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) { // 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()) @@ -7863,7 +7866,7 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E, 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(); @@ -8427,7 +8430,7 @@ static bool EvaluateBuiltinConstantP(EvalInfo &Info, const Expr *Arg) { 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. diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 70904b192a..caa327c19a 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -1860,8 +1860,10 @@ ConstantLValueEmitter::VisitMaterializeTemporaryExpr( 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: diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index a2d6d59800..b9573f71a3 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -1990,7 +1990,7 @@ Address CodeGenFunction::EmitMSVAListRef(const Expr *E) { 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); diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index a16e7ce47f..6daea41928 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -4886,7 +4886,7 @@ ConstantAddress CodeGenModule::GetAddrOfGlobalTemporary( // 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; } diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 239b4ae795..2483a28b25 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -6390,10 +6390,13 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // 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);