[c++20] P1331R2: Allow transient use of uninitialized objects in
constant evaluation.

llvm-svn: 372237
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index a4c2473..2d538ed 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -1192,9 +1192,14 @@
   return Result;
 }
 
+static bool isRead(AccessKinds AK) {
+  return AK == AK_Read || AK == AK_ReadObjectRepresentation;
+}
+
 static bool isModification(AccessKinds AK) {
   switch (AK) {
   case AK_Read:
+  case AK_ReadObjectRepresentation:
   case AK_MemberCall:
   case AK_DynamicCast:
   case AK_TypeId:
@@ -1209,7 +1214,7 @@
 
 /// Is this an access per the C++ definition?
 static bool isFormalAccess(AccessKinds AK) {
-  return AK == AK_Read || isModification(AK);
+  return isRead(AK) || isModification(AK);
 }
 
 namespace {
@@ -1858,14 +1863,16 @@
   return false;
 }
 
-/// Check that this core constant expression value is a valid value for a
-/// constant expression. If not, report an appropriate diagnostic. Does not
-/// check that the expression is of literal type.
+enum class CheckEvaluationResultKind {
+  ConstantExpression,
+  FullyInitialized,
+};
+
 static bool
-CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, QualType Type,
-                        const APValue &Value,
-                        Expr::ConstExprUsage Usage = Expr::EvaluateForCodeGen,
-                        SourceLocation SubobjectLoc = SourceLocation()) {
+CheckEvaluationResult(CheckEvaluationResultKind CERK, EvalInfo &Info,
+                      SourceLocation DiagLoc, QualType Type,
+                      const APValue &Value, Expr::ConstExprUsage Usage,
+                      SourceLocation SubobjectLoc = SourceLocation()) {
   if (!Value.hasValue()) {
     Info.FFDiag(DiagLoc, diag::note_constexpr_uninitialized)
       << true << Type;
@@ -1885,30 +1892,29 @@
   if (Value.isArray()) {
     QualType EltTy = Type->castAsArrayTypeUnsafe()->getElementType();
     for (unsigned I = 0, N = Value.getArrayInitializedElts(); I != N; ++I) {
-      if (!CheckConstantExpression(Info, DiagLoc, EltTy,
-                                   Value.getArrayInitializedElt(I), Usage,
-                                   SubobjectLoc))
+      if (!CheckEvaluationResult(CERK, Info, DiagLoc, EltTy,
+                                 Value.getArrayInitializedElt(I), Usage,
+                                 SubobjectLoc))
         return false;
     }
     if (!Value.hasArrayFiller())
       return true;
-    return CheckConstantExpression(Info, DiagLoc, EltTy, Value.getArrayFiller(),
-                                   Usage, SubobjectLoc);
+    return CheckEvaluationResult(CERK, Info, DiagLoc, EltTy,
+                                 Value.getArrayFiller(), Usage, SubobjectLoc);
   }
   if (Value.isUnion() && Value.getUnionField()) {
-    return CheckConstantExpression(Info, DiagLoc,
-                                   Value.getUnionField()->getType(),
-                                   Value.getUnionValue(), Usage,
-                                   Value.getUnionField()->getLocation());
+    return CheckEvaluationResult(
+        CERK, Info, DiagLoc, Value.getUnionField()->getType(),
+        Value.getUnionValue(), Usage, Value.getUnionField()->getLocation());
   }
   if (Value.isStruct()) {
     RecordDecl *RD = Type->castAs<RecordType>()->getDecl();
     if (const CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD)) {
       unsigned BaseIndex = 0;
       for (const CXXBaseSpecifier &BS : CD->bases()) {
-        if (!CheckConstantExpression(Info, DiagLoc, BS.getType(),
-                                     Value.getStructBase(BaseIndex), Usage,
-                                     BS.getBeginLoc()))
+        if (!CheckEvaluationResult(CERK, Info, DiagLoc, BS.getType(),
+                                   Value.getStructBase(BaseIndex), Usage,
+                                   BS.getBeginLoc()))
           return false;
         ++BaseIndex;
       }
@@ -1917,26 +1923,48 @@
       if (I->isUnnamedBitfield())
         continue;
 
-      if (!CheckConstantExpression(Info, DiagLoc, I->getType(),
-                                   Value.getStructField(I->getFieldIndex()),
-                                   Usage, I->getLocation()))
+      if (!CheckEvaluationResult(CERK, Info, DiagLoc, I->getType(),
+                                 Value.getStructField(I->getFieldIndex()),
+                                 Usage, I->getLocation()))
         return false;
     }
   }
 
-  if (Value.isLValue()) {
+  if (Value.isLValue() &&
+      CERK == CheckEvaluationResultKind::ConstantExpression) {
     LValue LVal;
     LVal.setFrom(Info.Ctx, Value);
     return CheckLValueConstantExpression(Info, DiagLoc, Type, LVal, Usage);
   }
 
-  if (Value.isMemberPointer())
+  if (Value.isMemberPointer() &&
+      CERK == CheckEvaluationResultKind::ConstantExpression)
     return CheckMemberPointerConstantExpression(Info, DiagLoc, Type, Value, Usage);
 
   // Everything else is fine.
   return true;
 }
 
+/// Check that this core constant expression value is a valid value for a
+/// constant expression. If not, report an appropriate diagnostic. Does not
+/// check that the expression is of literal type.
+static bool
+CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, QualType Type,
+                        const APValue &Value,
+                        Expr::ConstExprUsage Usage = Expr::EvaluateForCodeGen) {
+  return CheckEvaluationResult(CheckEvaluationResultKind::ConstantExpression,
+                               Info, DiagLoc, Type, Value, Usage);
+}
+
+/// Check that this evaluated value is fully-initialized and can be loaded by
+/// an lvalue-to-rvalue conversion.
+static bool CheckFullyInitialized(EvalInfo &Info, SourceLocation DiagLoc,
+                                  QualType Type, const APValue &Value) {
+  return CheckEvaluationResult(CheckEvaluationResultKind::FullyInitialized,
+                               Info, DiagLoc, Type, Value,
+                               Expr::EvaluateForCodeGen);
+}
+
 static bool EvalPointerValueAsBool(const APValue &Value, bool &Result) {
   // A null base expression indicates a null pointer.  These are always
   // evaluatable, and they are false unless the offset is zero.
@@ -2821,7 +2849,9 @@
   // Walk the designator's path to find the subobject.
   for (unsigned I = 0, N = Sub.Entries.size(); /**/; ++I) {
     // Reading an indeterminate value is undefined, but assigning over one is OK.
-    if (O->isAbsent() || (O->isIndeterminate() && handler.AccessKind != AK_Assign)) {
+    if (O->isAbsent() ||
+        (O->isIndeterminate() && handler.AccessKind != AK_Assign &&
+         handler.AccessKind != AK_ReadObjectRepresentation)) {
       if (!Info.checkingPotentialConstantExpression())
         Info.FFDiag(E, diag::note_constexpr_access_uninit)
             << handler.AccessKind << O->isIndeterminate();
@@ -2876,7 +2906,7 @@
       // things we need to check: if there are any mutable subobjects, we
       // cannot perform this read. (This only happens when performing a trivial
       // copy or assignment.)
-      if (ObjType->isRecordType() && handler.AccessKind == AK_Read &&
+      if (ObjType->isRecordType() && isRead(handler.AccessKind) &&
           !Obj.mayReadMutableMembers(Info) &&
           diagnoseUnreadableFields(Info, E, ObjType))
         return handler.failed();
@@ -2916,7 +2946,7 @@
 
       if (O->getArrayInitializedElts() > Index)
         O = &O->getArrayInitializedElt(Index);
-      else if (handler.AccessKind != AK_Read) {
+      else if (!isRead(handler.AccessKind)) {
         expandArray(*O, Index);
         O = &O->getArrayInitializedElt(Index);
       } else
@@ -2946,7 +2976,7 @@
                                    : O->getComplexFloatReal(), ObjType);
       }
     } else if (const FieldDecl *Field = getAsField(Sub.Entries[I])) {
-      if (Field->isMutable() && handler.AccessKind == AK_Read &&
+      if (Field->isMutable() && isRead(handler.AccessKind) &&
           !Obj.mayReadMutableMembers(Info)) {
         Info.FFDiag(E, diag::note_constexpr_ltor_mutable, 1)
           << Field;
@@ -2986,15 +3016,17 @@
 namespace {
 struct ExtractSubobjectHandler {
   EvalInfo &Info;
+  const Expr *E;
   APValue &Result;
-
-  static const AccessKinds AccessKind = AK_Read;
+  const AccessKinds AccessKind;
 
   typedef bool result_type;
   bool failed() { return false; }
   bool found(APValue &Subobj, QualType SubobjType) {
     Result = Subobj;
-    return true;
+    if (AccessKind == AK_ReadObjectRepresentation)
+      return true;
+    return CheckFullyInitialized(Info, E->getExprLoc(), SubobjType, Result);
   }
   bool found(APSInt &Value, QualType SubobjType) {
     Result = APValue(Value);
@@ -3007,14 +3039,13 @@
 };
 } // end anonymous namespace
 
-const AccessKinds ExtractSubobjectHandler::AccessKind;
-
 /// Extract the designated sub-object of an rvalue.
 static bool extractSubobject(EvalInfo &Info, const Expr *E,
                              const CompleteObject &Obj,
-                             const SubobjectDesignator &Sub,
-                             APValue &Result) {
-  ExtractSubobjectHandler Handler = { Info, Result };
+                             const SubobjectDesignator &Sub, APValue &Result,
+                             AccessKinds AK = AK_Read) {
+  assert(AK == AK_Read || AK == AK_ReadObjectRepresentation);
+  ExtractSubobjectHandler Handler = {Info, E, Result, AK};
   return findSubobject(Info, E, Obj, Sub, Handler);
 }
 
@@ -3340,15 +3371,22 @@
 ///               case of a non-class type).
 /// \param LVal - The glvalue on which we are attempting to perform this action.
 /// \param RVal - The produced value will be placed here.
-static bool handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv,
-                                           QualType Type,
-                                           const LValue &LVal, APValue &RVal) {
+/// \param WantObjectRepresentation - If true, we're looking for the object
+///               representation rather than the value, and in particular,
+///               there is no requirement that the result be fully initialized.
+static bool
+handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, QualType Type,
+                               const LValue &LVal, APValue &RVal,
+                               bool WantObjectRepresentation = false) {
   if (LVal.Designator.Invalid)
     return false;
 
   // Check for special cases where there is no existing APValue to look at.
   const Expr *Base = LVal.Base.dyn_cast<const Expr*>();
 
+  AccessKinds AK =
+      WantObjectRepresentation ? AK_ReadObjectRepresentation : AK_Read;
+
   if (Base && !LVal.getLValueCallIndex() && !Type.isVolatileQualified()) {
     if (const CompoundLiteralExpr *CLE = dyn_cast<CompoundLiteralExpr>(Base)) {
       // In C99, a CompoundLiteralExpr is an lvalue, and we defer evaluating the
@@ -3362,7 +3400,7 @@
       if (!Evaluate(Lit, Info, CLE->getInitializer()))
         return false;
       CompleteObject LitObj(LVal.Base, &Lit, Base->getType());
-      return extractSubobject(Info, Conv, LitObj, LVal.Designator, RVal);
+      return extractSubobject(Info, Conv, LitObj, LVal.Designator, RVal, AK);
     } else if (isa<StringLiteral>(Base) || isa<PredefinedExpr>(Base)) {
       // Special-case character extraction so we don't have to construct an
       // APValue for the whole string.
@@ -3377,7 +3415,7 @@
       }
       if (LVal.Designator.isOnePastTheEnd()) {
         if (Info.getLangOpts().CPlusPlus11)
-          Info.FFDiag(Conv, diag::note_constexpr_access_past_end) << AK_Read;
+          Info.FFDiag(Conv, diag::note_constexpr_access_past_end) << AK;
         else
           Info.FFDiag(Conv);
         return false;
@@ -3388,8 +3426,8 @@
     }
   }
 
-  CompleteObject Obj = findCompleteObject(Info, Conv, AK_Read, LVal, Type);
-  return Obj && extractSubobject(Info, Conv, Obj, LVal.Designator, RVal);
+  CompleteObject Obj = findCompleteObject(Info, Conv, AK, LVal, Type);
+  return Obj && extractSubobject(Info, Conv, Obj, LVal.Designator, RVal, AK);
 }
 
 /// Perform an assignment of Val to LVal. Takes ownership of Val.
@@ -3843,6 +3881,40 @@
   return CastToDerivedClass(Info, E, Result, TargetType, NewEntriesSize);
 }
 
+/// Get the value to use for a default-initialized object of type T.
+static APValue getDefaultInitValue(QualType T) {
+  if (auto *RD = T->getAsCXXRecordDecl()) {
+    if (RD->isUnion())
+      return APValue((const FieldDecl*)nullptr);
+
+    APValue Struct(APValue::UninitStruct(), RD->getNumBases(),
+                   std::distance(RD->field_begin(), RD->field_end()));
+
+    unsigned Index = 0;
+    for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+           End = RD->bases_end(); I != End; ++I, ++Index)
+      Struct.getStructBase(Index) = getDefaultInitValue(I->getType());
+
+    for (const auto *I : RD->fields()) {
+      if (I->isUnnamedBitfield())
+        continue;
+      Struct.getStructField(I->getFieldIndex()) =
+          getDefaultInitValue(I->getType());
+    }
+    return Struct;
+  }
+
+  if (auto *AT =
+          dyn_cast_or_null<ConstantArrayType>(T->getAsArrayTypeUnsafe())) {
+    APValue Array(APValue::UninitArray(), 0, AT->getSize().getZExtValue());
+    if (Array.hasArrayFiller())
+      Array.getArrayFiller() = getDefaultInitValue(AT->getElementType());
+    return Array;
+  }
+
+  return APValue::IndeterminateValue();
+}
+
 namespace {
 enum EvalStmtResult {
   /// Evaluation failed.
@@ -3870,10 +3942,8 @@
 
   const Expr *InitE = VD->getInit();
   if (!InitE) {
-    Info.FFDiag(VD->getBeginLoc(), diag::note_constexpr_uninitialized)
-        << false << VD->getType();
-    Val = APValue();
-    return false;
+    Val = getDefaultInitValue(VD->getType());
+    return true;
   }
 
   if (InitE->isValueDependent())
@@ -4089,9 +4159,23 @@
       break;
     }
 
-    case Stmt::DeclStmtClass:
-      // FIXME: If the variable has initialization that can't be jumped over,
-      // bail out of any immediately-surrounding compound-statement too.
+    case Stmt::DeclStmtClass: {
+      // Start the lifetime of any uninitialized variables we encounter. They
+      // might be used by the selected branch of the switch.
+      const DeclStmt *DS = cast<DeclStmt>(S);
+      for (const auto *D : DS->decls()) {
+        if (const auto *VD = dyn_cast<VarDecl>(D)) {
+          if (VD->hasLocalStorage() && !VD->getInit())
+            if (!EvaluateVarDecl(Info, VD))
+              return ESR_Failed;
+          // FIXME: If the variable has initialization that can't be jumped
+          // over, bail out of any immediately-surrounding compound-statement
+          // too. There can't be any case labels here.
+        }
+      }
+      return ESR_CaseNotFound;
+    }
+
     default:
       return ESR_CaseNotFound;
     }
@@ -4116,12 +4200,10 @@
 
   case Stmt::DeclStmtClass: {
     const DeclStmt *DS = cast<DeclStmt>(S);
-    for (const auto *DclIt : DS->decls()) {
+    for (const auto *D : DS->decls()) {
       // Each declaration initialization is its own full-expression.
-      // 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.noteFailure())
+      if (!EvaluateDecl(Info, D) && !Info.noteFailure())
         return ESR_Failed;
     }
     return ESR_Succeeded;
@@ -4743,39 +4825,6 @@
 
   static const AccessKinds AccessKind = AK_Assign;
 
-  APValue getDefaultInitValue(QualType SubobjType) {
-    if (auto *RD = SubobjType->getAsCXXRecordDecl()) {
-      if (RD->isUnion())
-        return APValue((const FieldDecl*)nullptr);
-
-      APValue Struct(APValue::UninitStruct(), RD->getNumBases(),
-                     std::distance(RD->field_begin(), RD->field_end()));
-
-      unsigned Index = 0;
-      for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
-             End = RD->bases_end(); I != End; ++I, ++Index)
-        Struct.getStructBase(Index) = getDefaultInitValue(I->getType());
-
-      for (const auto *I : RD->fields()) {
-        if (I->isUnnamedBitfield())
-          continue;
-        Struct.getStructField(I->getFieldIndex()) =
-            getDefaultInitValue(I->getType());
-      }
-      return Struct;
-    }
-
-    if (auto *AT = dyn_cast_or_null<ConstantArrayType>(
-            SubobjType->getAsArrayTypeUnsafe())) {
-      APValue Array(APValue::UninitArray(), 0, AT->getSize().getZExtValue());
-      if (Array.hasArrayFiller())
-        Array.getArrayFiller() = getDefaultInitValue(AT->getElementType());
-      return Array;
-    }
-
-    return APValue::IndeterminateValue();
-  }
-
   typedef bool result_type;
   bool failed() { return false; }
   bool found(APValue &Subobj, QualType SubobjType) {
@@ -4981,8 +5030,8 @@
     LValue RHS;
     RHS.setFrom(Info.Ctx, ArgValues[0]);
     APValue RHSValue;
-    if (!handleLValueToRValueConversion(Info, Args[0], Args[0]->getType(),
-                                        RHS, RHSValue))
+    if (!handleLValueToRValueConversion(Info, Args[0], Args[0]->getType(), RHS,
+                                        RHSValue, MD->getParent()->isUnion()))
       return false;
     if (Info.getLangOpts().CPlusPlus2a && MD->isTrivial() &&
         !HandleUnionActiveMemberChange(Info, Args[0], *This))
@@ -5066,7 +5115,7 @@
     RHS.setFrom(Info.Ctx, ArgValues[0]);
     return handleLValueToRValueConversion(
         Info, E, Definition->getParamDecl(0)->getType().getNonReferenceType(),
-        RHS, Result);
+        RHS, Result, Definition->getParent()->isUnion());
   }
 
   // Reserve space for the struct members.
@@ -5085,6 +5134,25 @@
 #ifndef NDEBUG
   CXXRecordDecl::base_class_const_iterator BaseIt = RD->bases_begin();
 #endif
+  CXXRecordDecl::field_iterator FieldIt = RD->field_begin();
+  auto SkipToField = [&](FieldDecl *FD, bool Indirect) {
+    // We might be initializing the same field again if this is an indirect
+    // field initialization.
+    if (FieldIt == RD->field_end() ||
+        FieldIt->getFieldIndex() > FD->getFieldIndex()) {
+      assert(Indirect && "fields out of order?");
+      return;
+    }
+
+    // Default-initialize any fields with no explicit initializer.
+    for (; !declaresSameEntity(*FieldIt, FD); ++FieldIt) {
+      assert(FieldIt != RD->field_end() && "missing field?");
+      if (!FieldIt->isUnnamedBitfield())
+        Result.getStructField(FieldIt->getFieldIndex()) =
+            getDefaultInitValue(FieldIt->getType());
+    }
+    ++FieldIt;
+  };
   for (const auto *I : Definition->inits()) {
     LValue Subobject = This;
     LValue SubobjectParent = This;
@@ -5113,6 +5181,7 @@
         Result = APValue(FD);
         Value = &Result.getUnionValue();
       } else {
+        SkipToField(FD, false);
         Value = &Result.getStructField(FD->getFieldIndex());
       }
     } else if (IndirectFieldDecl *IFD = I->getIndirectMember()) {
@@ -5132,8 +5201,10 @@
           if (CD->isUnion())
             *Value = APValue(FD);
           else
-            *Value = APValue(APValue::UninitStruct(), CD->getNumBases(),
-                             std::distance(CD->field_begin(), CD->field_end()));
+            // FIXME: This immediately starts the lifetime of all members of an
+            // anonymous struct. It would be preferable to strictly start member
+            // lifetime in initialization order.
+            *Value = getDefaultInitValue(Info.Ctx.getRecordType(CD));
         }
         // Store Subobject as its parent before updating it for the last element
         // in the chain.
@@ -5143,8 +5214,11 @@
           return false;
         if (CD->isUnion())
           Value = &Value->getUnionValue();
-        else
+        else {
+          if (C == IndirectFieldChain.front() && !RD->isUnion())
+            SkipToField(FD, true);
           Value = &Value->getStructField(FD->getFieldIndex());
+        }
       }
     } else {
       llvm_unreachable("unknown base initializer kind");
@@ -5173,6 +5247,15 @@
       EvalObj.finishedConstructingBases();
   }
 
+  // Default-initialize any remaining fields.
+  if (!RD->isUnion()) {
+    for (; FieldIt != RD->field_end(); ++FieldIt) {
+      if (!FieldIt->isUnnamedBitfield())
+        Result.getStructField(FieldIt->getFieldIndex()) =
+            getDefaultInitValue(FieldIt->getType());
+    }
+  }
+
   return Success &&
          EvaluateStmt(Ret, Info, Definition->getBody()) != ESR_Failed;
 }
@@ -5658,9 +5741,9 @@
   LValue SourceLValue;
   APValue SourceRValue;
   SourceLValue.setFrom(Info.Ctx, SourceValue);
-  if (!handleLValueToRValueConversion(Info, BCE,
-                                      BCE->getSubExpr()->getType().withConst(),
-                                      SourceLValue, SourceRValue))
+  if (!handleLValueToRValueConversion(
+          Info, BCE, BCE->getSubExpr()->getType().withConst(), SourceLValue,
+          SourceRValue, /*WantObjectRepresentation=*/true))
     return false;
 
   // Read out SourceValue into a char buffer.
@@ -7455,6 +7538,8 @@
 
     while (true) {
       APValue Val;
+      // FIXME: Set WantObjectRepresentation to true if we're copying a
+      // char-like type?
       if (!handleLValueToRValueConversion(Info, E, T, Src, Val) ||
           !handleAssignment(Info, E, Dest, T, Val))
         return false;
@@ -7830,15 +7915,11 @@
     if (Result.hasValue())
       return true;
 
-    // We can get here in two different ways:
-    //  1) We're performing value-initialization, and should zero-initialize
-    //     the object, or
-    //  2) We're performing default-initialization of an object with a trivial
-    //     constexpr default constructor, in which case we should start the
-    //     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, T);
+    if (ZeroInit)
+      return ZeroInitialization(E, T);
+
+    Result = getDefaultInitValue(T);
+    return true;
   }
 
   const FunctionDecl *Definition = nullptr;