]> granicus.if.org Git - clang/commitdiff
Refactor: split Uninitialized state on APValue into an "Absent" state
authorRichard Smith <richard-llvm@metafoo.co.uk>
Tue, 21 May 2019 23:15:18 +0000 (23:15 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Tue, 21 May 2019 23:15:18 +0000 (23:15 +0000)
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

include/clang/AST/APValue.h
include/clang/Basic/DiagnosticASTKinds.td
lib/AST/APValue.cpp
lib/AST/Decl.cpp
lib/AST/ExprConstant.cpp
lib/CodeGen/CGExprConstant.cpp
lib/CodeGen/CodeGenFunction.cpp
lib/CodeGen/CodeGenModule.cpp
lib/Sema/SemaTemplate.cpp

index 15f8944e4f51c58706d061759978578fd613af6d..02a6394bd5e138245385626b88bd7a64d7d48d42 100644 (file)
@@ -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<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.
@@ -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<const CXXRecordDecl*> Path);
   void MakeAddrLabelDiff() {
-    assert(isUninit() && "Bad state change");
+    assert(isAbsent() && "Bad state change");
     new ((void*)(char*)Data.buffer) AddrLabelDiffData();
     Kind = AddrLabelDiff;
   }
index a9e88d5ecb7ecbf710267016c4bc25fa1f7b086d..f1172a91ea75ea2f9562e4cd17b1e0f1fbbdeccc 100644 (file)
@@ -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">;
index c5db3cd582d050936ce745207595c82ceca39a5e..5d5e67a89027f04a5b006ae97bf1839175ed1072 100644 (file)
@@ -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 << "<out of lifetime>";
+    return;
+  case APValue::Indeterminate:
     Out << "<uninitialized>";
     return;
   case APValue::Int:
@@ -781,21 +790,21 @@ ArrayRef<const CXXRecordDecl*> 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<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);
index bc0a5a4c67e322cfe5994caa7be4af54acfebf97..8b77e01f4e87ac37be70a4ceb5fa78d774b76782 100644 (file)
@@ -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<Expr>(Eval->Value);
   assert(!Init->isValueDependent());
index e654480f09419a4010a7cc236b6dcd84d0c45d66..508456422b6b978f3b675b5d7cf5c949a6ba255a 100644 (file)
@@ -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.
index 70904b192a39ac8314eb189ca92e2946e132775c..caa327c19a4cbe946800135050296f223648fd95 100644 (file)
@@ -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:
index a2d6d59800c1f5ee0b2fc38d9cc2d1dbc587c115..b9573f71a3af9ea6ef36e45cd28c4d22a6a42832 100644 (file)
@@ -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);
index a16e7ce47f93a8ee7e39f4df729f66daf7c560ef..6daea419281379c3f96abd44e0f4e30cfa24b26a 100644 (file)
@@ -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;
   }
 
index 239b4ae7957e821184409ef27d07f705d4f25fcc..2483a28b252f0dceb9017d9f7a9b2d53dd50ae23 100644 (file)
@@ -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);