ayzhao updated this revision to Diff 513808.
ayzhao added a comment.

fix comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D148274/new/

https://reviews.llvm.org/D148274

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Initialization.h
  clang/lib/Sema/SemaAccess.cpp
  clang/lib/Sema/SemaInit.cpp
  clang/test/CodeGen/paren-list-agg-init.cpp
  clang/test/SemaCXX/paren-list-agg-init.cpp

Index: clang/test/SemaCXX/paren-list-agg-init.cpp
===================================================================
--- clang/test/SemaCXX/paren-list-agg-init.cpp
+++ clang/test/SemaCXX/paren-list-agg-init.cpp
@@ -9,7 +9,7 @@
 struct B {
   A a;
   int b[20];
-  int &&c; // expected-note {{reference member declared here}}
+  int &&c;
 };
 
 struct C { // expected-note 5{{candidate constructor}}
@@ -21,9 +21,9 @@
   int a;
 };
 
-struct E { // expected-note 3{{candidate constructor}}
-  struct F {
-    F(int, int);
+struct E {
+  struct F { // expected-note 2{{candidate constructor}}
+    F(int, int); // expected-note {{candidate constructor}}
   };
   int a;
   F f;
@@ -56,6 +56,12 @@
   int b[]; // expected-note {{initialized flexible array member 'b' is here}}
 };
 
+enum K { K0, K1, K2 };
+
+struct L {
+  K k : 1;
+};
+
 union U {
   int a;
   char* b;
@@ -96,9 +102,8 @@
   B b1(2022, {7, 8});
   // expected-error@-1 {{no viable conversion from 'int' to 'A'}}
   B b2(A(1), {}, 1);
-  // expected-error@-1 {{reference member 'c' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
-  // beforecxx20-warning@-2 {{aggregate initialization of type 'A' from a parenthesized list of values is a C++20 extension}}
-  // beforecxx20-warning@-3 {{aggregate initialization of type 'B' from a parenthesized list of values is a C++20 extension}}
+  // beforecxx20-warning@-1 {{aggregate initialization of type 'A' from a parenthesized list of values is a C++20 extension}}
+  // beforecxx20-warning@-2 {{aggregate initialization of type 'B' from a parenthesized list of values is a C++20 extension}}
 
   C c(A(1), 1, 2, 3, 4);
   // expected-error@-1 {{array initializer must be an initializer list}}
@@ -130,7 +135,7 @@
   // expected-error@-1 {{excess elements in union initializer}}
 
   E e1(1);
-  // expected-error@-1 {{no matching constructor for initialization of 'E'}}
+  // expected-error@-1 {{no matching constructor for initialization of 'F'}}
 
   constexpr F f1(1);
   // expected-error@-1 {{constexpr variable 'f1' must be initialized by a constant expression}}
@@ -148,6 +153,10 @@
   A a7 = Construct<A>('i', 2.2);
   // beforecxx20-note@-1 {{in instantiation of function template specialization 'Construct<A, char, double>' requested here}}
 
+  L l(K::K2);
+  // expected-warning@-1 {{implicit truncation}}
+  // beforecxx20-warning@-2 {{aggregate initialization of type 'L' from a parenthesized list of values is a C++20 extension}}
+
   int arr4[](1, 2);
   // beforecxx20-warning@-1 {{aggregate initialization of type 'int[2]' from a parenthesized list of values is a C++20 extension}}
 
@@ -200,3 +209,21 @@
   // expected-error@-1 {{call to implicitly-deleted copy constructor of 'V'}}
 }
 }
+
+namespace gh61567 {
+  struct K {
+    struct L {
+     private:
+      L(int);
+      // expected-note@-1 {{declared private here}}
+    };
+    int i;
+    L l;
+  };
+
+  void foo() {
+    K k(1, 1);
+    // expected-error@-1 {{field of type 'L' has private constructor}}
+    // beforecxx20-warning@-2 {{aggregate initialization of type 'K' from a parenthesized list of values is a C++20 extension}}
+  }
+}
Index: clang/test/CodeGen/paren-list-agg-init.cpp
===================================================================
--- clang/test/CodeGen/paren-list-agg-init.cpp
+++ clang/test/CodeGen/paren-list-agg-init.cpp
@@ -90,6 +90,14 @@
   };
 }
 
+namespace gh61567 {
+  // CHECK-DAG: [[STRUCT_H:%.*H.*]] = type { i32, ptr }
+  struct H {
+    int a;
+    int&& r;
+  };
+}
+
 // CHECK-DAG: [[A1:@.*a1.*]] = internal constant [[STRUCT_A]] { i8 3, double 2.000000e+00 }, align 8
 constexpr A a1(3.1, 2.0);
 // CHECK-DAG: [[A2:@.*a2.*]] = internal constant [[STRUCT_A]] { i8 99, double 0.000000e+00 }, align 8
@@ -421,3 +429,50 @@
     make2<0>();
   }
 }
+
+namespace gh61567 {
+  int foo20();
+
+  // CHECK: define {{.*}} void @{{.*foo21.*}} {
+  // CHECK-NEXT: entry
+  // CHECK-NEXT: [[AGG_TMP_ENSURED:%.*]] = alloca [[STRUCT_H]], align 8
+  // CHECK-NEXT: [[REF_TMP:%.*]] = alloca i32, align 4
+  // CHECK-NEXT: [[A:%.*a.*]] = getelementptr inbounds [[STRUCT_H]], ptr [[AGG_TMP_ENSURED]], i32 0, i32 0
+  // CHECK-NEXT: store i32 0, ptr [[A]], align 8
+  // CHECK-NEXT: [[R:%.*r.*]] = getelementptr inbounds [[STRUCT_H]], ptr [[AGG_TMP_ENSURED]], i32 0, i32 1
+  // CHECK-NEXT: store i32 1, ptr [[REF_TMP]], align 4
+  // CHECK-NEXT: store ptr [[REF_TMP]], ptr [[R]], align 8
+  // CHECK-NEXT: ret void
+  void foo21() {
+    H(0, 1);
+  }
+
+  // CHECK: define {{.*}} void @{{.*foo22.*}} {
+  // CHECK-NEXT: entry
+  // CHECK-NEXT: [[AGG_TMP_ENSURED:%.*]] = alloca [[STRUCT_H]], align 8
+  // CHECK-NEXT: [[REF_TMP:%.*]] = alloca i32, align 4
+  // CHECK-NEXT: [[A:%.*a.*]] = getelementptr inbounds [[STRUCT_H]], ptr [[AGG_TMP_ENSURED]], i32 0, i32 0
+  // CHECK-NEXT: store i32 0, ptr [[A]], align 8
+  // CHECK-NEXT: [[R:%.*r.*]] = getelementptr inbounds [[STRUCT_H]], ptr [[AGG_TMP_ENSURED]], i32 0, i32 1
+  // CHECK-NEXT: [[CALL:%.*call*]] = call noundef i32 @{{.*foo20.*}}
+  // CHECK-NEXT: store i32 [[CALL]], ptr [[REF_TMP]], align 4
+  // CHECK-NEXT: store ptr [[REF_TMP]], ptr [[R]], align 8
+  // CHECK-NEXT: ret void
+  void foo22() {
+    H(0, foo20());
+  }
+
+  // CHECK: define {{.*}} void @{{.*foo23.*}}(i32 noundef [[I:%.*i.*]])
+  // CHECK-NEXT: entry
+  // CHECK-NEXT: [[I_ADDR:%.*i.*]] = alloca i32, align 4
+  // CHECK-NEXT: [[AGG_TMP_ENSURED:%.*]] = alloca [[STRUCT_H]], align 8
+  // CHECK-NEXT: store i32 [[I]], ptr [[I_ADDR]], align 4
+  // CHECK-NEXT: [[A:%.*a.*]] = getelementptr inbounds [[STRUCT_H]], ptr [[AGG_TMP_ENSURED]], i32 0, i32 0
+  // CHECK-NEXT: store i32 0, ptr [[A]], align 8
+  // CHECK-NEXT: [[R:%.*r.*]] = getelementptr inbounds [[STRUCT_H]], ptr [[AGG_TMP_ENSURED]], i32 0, i32 1
+  // CHECK-NEXT: store ptr [[I_ADDR]], ptr [[R]], align 8
+  // CHECK-NEXT: ret void
+  void foo23(int i) {
+    H(0, static_cast<int&&>(i));
+  }
+}
Index: clang/lib/Sema/SemaInit.cpp
===================================================================
--- clang/lib/Sema/SemaInit.cpp
+++ clang/lib/Sema/SemaInit.cpp
@@ -1186,6 +1186,7 @@
   case InitializedEntity::EK_LambdaToBlockConversionBlockElement:
   case InitializedEntity::EK_Binding:
   case InitializedEntity::EK_StmtExprResult:
+  case InitializedEntity::EK_ParenAggInitMember:
     llvm_unreachable("unexpected braced scalar init");
   }
 
@@ -3359,6 +3360,7 @@
 
   case EK_Variable:
   case EK_Member:
+  case EK_ParenAggInitMember:
   case EK_Binding:
   case EK_TemplateParameter:
     return Variable.VariableOrMember->getDeclName();
@@ -3390,6 +3392,7 @@
   switch (getKind()) {
   case EK_Variable:
   case EK_Member:
+  case EK_ParenAggInitMember:
   case EK_Binding:
   case EK_TemplateParameter:
     return Variable.VariableOrMember;
@@ -3431,6 +3434,7 @@
   case EK_Parameter_CF_Audited:
   case EK_TemplateParameter:
   case EK_Member:
+  case EK_ParenAggInitMember:
   case EK_Binding:
   case EK_New:
   case EK_Temporary:
@@ -3465,7 +3469,10 @@
   case EK_Result: OS << "Result"; break;
   case EK_StmtExprResult: OS << "StmtExprResult"; break;
   case EK_Exception: OS << "Exception"; break;
-  case EK_Member: OS << "Member"; break;
+  case EK_Member:
+  case EK_ParenAggInitMember:
+    OS << "Member";
+    break;
   case EK_Binding: OS << "Binding"; break;
   case EK_New: OS << "New"; break;
   case EK_Temporary: OS << "Temporary"; break;
@@ -5303,176 +5310,201 @@
     Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind,
     ArrayRef<Expr *> Args, InitializationSequence &Sequence, bool VerifyOnly,
     ExprResult *Result = nullptr) {
-  unsigned ArgIndexToProcess = 0;
+  unsigned EntityIndexToProcess = 0;
   SmallVector<Expr *, 4> InitExprs;
   QualType ResultType;
   Expr *ArrayFiller = nullptr;
   FieldDecl *InitializedFieldInUnion = nullptr;
 
-  // Process entities (i.e. array members, base classes, or class fields) by
-  // adding an initialization expression to InitExprs for each entity to
-  // initialize.
-  auto ProcessEntities = [&](auto Range) -> bool {
-    bool IsUnionType = Entity.getType()->isUnionType();
-    for (InitializedEntity SubEntity : Range) {
-      // Unions should only have one initializer expression.
-      // If there are more initializers than it will be caught when we check
-      // whether Index equals Args.size().
-      if (ArgIndexToProcess == 1 && IsUnionType)
-        return true;
-
-      bool IsMember = SubEntity.getKind() == InitializedEntity::EK_Member;
-
-      // Unnamed bitfields should not be initialized at all, either with an arg
-      // or by default.
-      if (IsMember && cast<FieldDecl>(SubEntity.getDecl())->isUnnamedBitfield())
-        continue;
-
-      if (ArgIndexToProcess < Args.size()) {
-        // There are still expressions in Args that haven't been processed.
-        // Let's match them to the current entity to initialize.
-        Expr *E = Args[ArgIndexToProcess++];
-
-        // Incomplete array types indicate flexible array members. Do not allow
-        // paren list initializations of structs with these members, as GCC
-        // doesn't either.
-        if (IsMember) {
-          auto *FD = cast<FieldDecl>(SubEntity.getDecl());
-          if (FD->getType()->isIncompleteArrayType()) {
-            if (!VerifyOnly) {
-              S.Diag(E->getBeginLoc(), diag::err_flexible_array_init)
-                  << SourceRange(E->getBeginLoc(), E->getEndLoc());
-              S.Diag(FD->getLocation(), diag::note_flexible_array_member) << FD;
-            }
-            Sequence.SetFailed(
-                InitializationSequence::FK_ParenthesizedListInitFailed);
-            return false;
-          }
-        }
-
-        InitializationKind SubKind = InitializationKind::CreateForInit(
-            E->getExprLoc(), /*isDirectInit=*/false, E);
-        InitializationSequence SubSeq(S, SubEntity, SubKind, E);
-
-        if (SubSeq.Failed()) {
-          if (!VerifyOnly)
-            SubSeq.Diagnose(S, SubEntity, SubKind, E);
-          else
-            Sequence.SetFailed(
-                InitializationSequence::FK_ParenthesizedListInitFailed);
+  auto HandleInitializedEntity = [&](const InitializedEntity &SubEntity,
+                                     const InitializationKind &SubKind,
+                                     Expr *Arg, Expr **InitExpr = nullptr) {
+    auto CreateInitializationSequence = [&]() {
+      if (Arg)
+        return InitializationSequence(S, SubEntity, SubKind, Arg);
+      return InitializationSequence(S, SubEntity, SubKind, std::nullopt);
+    };
+    InitializationSequence IS = CreateInitializationSequence();
 
-          return false;
-        }
-        if (!VerifyOnly) {
-          ExprResult ER = SubSeq.Perform(S, SubEntity, SubKind, E);
-          InitExprs.push_back(ER.get());
-          if (IsMember && IsUnionType)
-            InitializedFieldInUnion = cast<FieldDecl>(SubEntity.getDecl());
-        }
+    if (IS.Failed()) {
+      if (!VerifyOnly) {
+        if (Arg)
+          IS.Diagnose(S, SubEntity, SubKind, Arg);
+        else
+          IS.Diagnose(S, SubEntity, SubKind, std::nullopt);
       } else {
-        // We've processed all of the args, but there are still entities that
-        // have to be initialized.
-        if (IsMember) {
-          // C++ [dcl.init]p17.6.2.2
-          //   The remaining elements are initialized with their default member
-          //   initializers, if any
-          auto *FD = cast<FieldDecl>(SubEntity.getDecl());
-          if (Expr *ICE = FD->getInClassInitializer(); ICE && !VerifyOnly) {
-            ExprResult DIE = S.BuildCXXDefaultInitExpr(FD->getLocation(), FD);
-            if (DIE.isInvalid())
-              return false;
-            S.checkInitializerLifetime(SubEntity, DIE.get());
-            InitExprs.push_back(DIE.get());
-            continue;
-          };
-        }
-        // Remaining class elements without default member initializers and
-        // array elements are value initialized:
-        //
-        // C++ [dcl.init]p17.6.2.2
-        //   The remaining elements...otherwise are value initialzed
-        //
-        // C++ [dcl.init]p17.5
-        //   if the destination type is an array, the object is initialized as
-        // . follows. Let x1, . . . , xk be the elements of the expression-list
-        //   ...Let n denote the array size...the ith array element is...value-
-        //   initialized for each k < i <= n.
-        InitializationKind SubKind = InitializationKind::CreateValue(
-            Kind.getLocation(), Kind.getLocation(), Kind.getLocation(), true);
-        InitializationSequence SubSeq(S, SubEntity, SubKind, std::nullopt);
-        if (SubSeq.Failed()) {
-          if (!VerifyOnly)
-            SubSeq.Diagnose(S, SubEntity, SubKind, std::nullopt);
-          return false;
-        }
-        if (!VerifyOnly) {
-          ExprResult ER = SubSeq.Perform(S, SubEntity, SubKind, std::nullopt);
-          if (SubEntity.getKind() == InitializedEntity::EK_ArrayElement) {
-            ArrayFiller = ER.get();
-            return true;
-          }
-          InitExprs.push_back(ER.get());
-        }
+        Sequence.SetFailed(
+            InitializationSequence::FK_ParenthesizedListInitFailed);
       }
+
+      return false;
+    }
+    if (!VerifyOnly) {
+      auto CreateExprResult = [&]() {
+        if (Arg)
+          return IS.Perform(S, SubEntity, SubKind, Arg);
+        return IS.Perform(S, SubEntity, SubKind, std::nullopt);
+      };
+      ExprResult ER = CreateExprResult();
+      if (InitExpr)
+        *InitExpr = ER.get();
+      else
+        InitExprs.push_back(ER.get());
     }
     return true;
   };
 
   if (const ArrayType *AT =
           S.getASTContext().getAsArrayType(Entity.getType())) {
-
     SmallVector<InitializedEntity, 4> ElementEntities;
     uint64_t ArrayLength;
-    // C++ [dcl.init]p17.5
+    // C++ [dcl.init]p16.5
     //   if the destination type is an array, the object is initialized as
     //   follows. Let x1, . . . , xk be the elements of the expression-list. If
-    //   the destination type is an array of unknown bound, it is define as
+    //   the destination type is an array of unknown bound, it is defined as
     //   having k elements.
     if (const ConstantArrayType *CAT =
             S.getASTContext().getAsConstantArrayType(Entity.getType()))
       ArrayLength = CAT->getSize().getZExtValue();
     else
       ArrayLength = Args.size();
-
-    if (ArrayLength >= Args.size()) {
-      for (uint64_t I = 0; I < ArrayLength; ++I)
-        ElementEntities.push_back(
-            InitializedEntity::InitializeElement(S.getASTContext(), I, Entity));
-
-      if (!ProcessEntities(ElementEntities))
+    EntityIndexToProcess = ArrayLength;
+
+    //   ...the ith array element is copy-initialized with xi for each
+    //   1 <= i <= k
+    for (Expr *E : Args) {
+      InitializedEntity SubEntity = InitializedEntity::InitializeElement(
+          S.getASTContext(), EntityIndexToProcess, Entity);
+      InitializationKind SubKind = InitializationKind::CreateForInit(
+          E->getExprLoc(), /*isDirectInit=*/false, E);
+      if (!HandleInitializedEntity(SubEntity, SubKind, E))
+        return;
+    }
+    //   ...and value-initialized for each k < i <= n;
+    if (ArrayLength > Args.size()) {
+      InitializedEntity SubEntity = InitializedEntity::InitializeElement(
+          S.getASTContext(), Args.size(), Entity);
+      InitializationKind SubKind = InitializationKind::CreateValue(
+          Kind.getLocation(), Kind.getLocation(), Kind.getLocation(), true);
+      if (!HandleInitializedEntity(SubEntity, SubKind, nullptr, &ArrayFiller))
         return;
-
-      ResultType = S.Context.getConstantArrayType(
-          AT->getElementType(), llvm::APInt(/*numBits=*/32, ArrayLength),
-          nullptr, ArrayType::Normal, 0);
     }
+
+    ResultType = S.Context.getConstantArrayType(
+        AT->getElementType(), llvm::APInt(/*numBits=*/32, ArrayLength), nullptr,
+        ArrayType::Normal, 0);
   } else if (auto *RT = Entity.getType()->getAs<RecordType>()) {
+    bool IsUnion = RT->isUnionType();
     const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
 
-    auto BaseRange = map_range(RD->bases(), [&S](auto &base) {
-      return InitializedEntity::InitializeBase(S.getASTContext(), &base, false);
-    });
-    auto FieldRange = map_range(RD->fields(), [](auto *field) {
-      return InitializedEntity::InitializeMember(field);
-    });
+    if (!IsUnion) {
+      for (const CXXBaseSpecifier &Base : RD->bases()) {
+        InitializedEntity SubEntity =
+            InitializedEntity::InitializeBase(S.getASTContext(), &Base, false);
+        if (EntityIndexToProcess < Args.size()) {
+          // C++ [dcl.init]p16.6.2.2.
+          //   ...the object is initialized is follows. Let e1, ..., en be the
+          //   elements of the aggregate([dcl.init.aggr]). Let x1, ..., xk be
+          //   the elements of the expression-list...The element ei is
+          //   copy-initialized with xi for 1 <= i <= k.
+          Expr *E = Args[EntityIndexToProcess];
+          InitializationKind SubKind = InitializationKind::CreateForInit(
+              E->getExprLoc(), /*isDirectInit=*/false, E);
+          if (!HandleInitializedEntity(SubEntity, SubKind, E))
+            return;
+        } else {
+          // We've processed all of the args, but there are still base classes
+          // that have to be initialized.
+          // C++ [dcl.init]p17.6.2.2
+          //   The remaining elements...otherwise are value initialzed
+          InitializationKind SubKind = InitializationKind::CreateValue(
+              Kind.getLocation(), Kind.getLocation(), Kind.getLocation(), true);
+          if (!HandleInitializedEntity(SubEntity, SubKind, nullptr))
+            return;
+        }
+        EntityIndexToProcess++;
+      }
+    }
 
-    if (!ProcessEntities(BaseRange))
-      return;
+    for (FieldDecl *FD : RD->fields()) {
+      // Unnamed bitfields should not be initialized at all, either with an arg
+      // or by default.
+      if (FD->isUnnamedBitfield())
+        continue;
 
-    if (!ProcessEntities(FieldRange))
-      return;
+      if (EntityIndexToProcess < Args.size()) {
+        //   ...The element ei is copy-initialized with xi for 1 <= i <= k.
+        Expr *E = Args[EntityIndexToProcess];
+
+        // Incomplete array types indicate flexible array members. Do not allow
+        // paren list initializations of structs with these members, as GCC
+        // doesn't either.
+        if (FD->getType()->isIncompleteArrayType()) {
+          if (!VerifyOnly) {
+            S.Diag(E->getBeginLoc(), diag::err_flexible_array_init)
+                << SourceRange(E->getBeginLoc(), E->getEndLoc());
+            S.Diag(FD->getLocation(), diag::note_flexible_array_member) << FD;
+          }
+          Sequence.SetFailed(
+              InitializationSequence::FK_ParenthesizedListInitFailed);
+          return;
+        }
+
+        InitializationKind SubKind = InitializationKind::CreateForInit(
+            E->getExprLoc(), /*isDirectInit=*/false, E);
+        InitializedEntity SubEntity =
+            InitializedEntity::InitializeMemberFromParenAggInit(FD);
+        if (!HandleInitializedEntity(SubEntity, SubKind, E))
+          return;
 
+        // Unions should have only one initializer expression, so we bail out
+        // after processing the first field. If there are more initializers then
+        // it will be caught when we later check whether EntityIndexToProcess is
+        // less than Args.size();
+        if (IsUnion) {
+          InitializedFieldInUnion = FD;
+          EntityIndexToProcess = 1;
+          break;
+        }
+      } else {
+        // We've processed all of the args, but there are still members that
+        // have to be initialized.
+        if (Expr *ICE = FD->getInClassInitializer(); ICE && !VerifyOnly) {
+          // C++ [dcl.init]p16.6.2.2
+          //   The remaining elements are initialized with their default member
+          //   initializers, if any
+          InitializedEntity SubEntity =
+              InitializedEntity::InitializeMemberFromDefaultMemberInitializer(
+                  FD);
+          ExprResult DIE = S.BuildCXXDefaultInitExpr(FD->getLocation(), FD);
+          if (DIE.isInvalid())
+            return;
+          S.checkInitializerLifetime(SubEntity, DIE.get());
+          InitExprs.push_back(DIE.get());
+        } else {
+          // C++ [dcl.init]p17.6.2.2
+          //   The remaining elements...otherwise are value initialzed
+          InitializedEntity SubEntity =
+              InitializedEntity::InitializeMember(FD, &Entity);
+          InitializationKind SubKind = InitializationKind::CreateValue(
+              Kind.getLocation(), Kind.getLocation(), Kind.getLocation(), true);
+          if (!HandleInitializedEntity(SubEntity, SubKind, nullptr))
+            return;
+        }
+      }
+      EntityIndexToProcess++;
+    }
     ResultType = Entity.getType();
   }
 
   // Not all of the args have been processed, so there must've been more args
   // than were required to initialize the element.
-  if (ArgIndexToProcess < Args.size()) {
+  if (EntityIndexToProcess < Args.size()) {
     Sequence.SetFailed(InitializationSequence::FK_ParenthesizedListInitFailed);
     if (!VerifyOnly) {
       QualType T = Entity.getType();
       int InitKind = T->isArrayType() ? 0 : T->isUnionType() ? 3 : 4;
-      SourceRange ExcessInitSR(Args[ArgIndexToProcess]->getBeginLoc(),
+      SourceRange ExcessInitSR(Args[EntityIndexToProcess]->getBeginLoc(),
                                Args.back()->getEndLoc());
       S.Diag(Kind.getLocation(), diag::err_excess_initializers)
           << InitKind << ExcessInitSR;
@@ -6438,6 +6470,7 @@
     return Sema::AA_Converting;
 
   case InitializedEntity::EK_Member:
+  case InitializedEntity::EK_ParenAggInitMember:
   case InitializedEntity::EK_Binding:
   case InitializedEntity::EK_ArrayElement:
   case InitializedEntity::EK_VectorElement:
@@ -6458,6 +6491,7 @@
   switch (Entity.getKind()) {
   case InitializedEntity::EK_ArrayElement:
   case InitializedEntity::EK_Member:
+  case InitializedEntity::EK_ParenAggInitMember:
   case InitializedEntity::EK_Result:
   case InitializedEntity::EK_StmtExprResult:
   case InitializedEntity::EK_New:
@@ -6502,6 +6536,7 @@
       return false;
 
     case InitializedEntity::EK_Member:
+    case InitializedEntity::EK_ParenAggInitMember:
     case InitializedEntity::EK_Binding:
     case InitializedEntity::EK_Variable:
     case InitializedEntity::EK_Parameter:
@@ -6538,6 +6573,7 @@
 
   case InitializedEntity::EK_ArrayElement:
   case InitializedEntity::EK_Member:
+  case InitializedEntity::EK_ParenAggInitMember:
   case InitializedEntity::EK_Parameter:
   case InitializedEntity::EK_Parameter_CF_Audited:
   case InitializedEntity::EK_TemplateParameter:
@@ -7106,7 +7142,15 @@
   case InitializedEntity::EK_Exception:
     // FIXME: Can we diagnose lifetime problems with exceptions?
     return {nullptr, LK_FullExpression};
+
+  case InitializedEntity::EK_ParenAggInitMember:
+    //   -- A temporary object bound to a reference element of an aggregate of
+    //      class type initialized from a parenthesized expression-list
+    //      [dcl.init, 9.3] persists until the completion of the full-expression
+    //      containing the expression-list.
+    return {nullptr, LK_FullExpression};
   }
+
   llvm_unreachable("unknown entity kind");
 }
 
@@ -9222,7 +9266,9 @@
     S.checkInitializerLifetime(Entity, Init);
 
   // Diagnose non-fatal problems with the completed initialization.
-  if (Entity.getKind() == InitializedEntity::EK_Member &&
+  if (InitializedEntity::EntityKind EK = Entity.getKind();
+      (EK == InitializedEntity::EK_Member ||
+       EK == InitializedEntity::EK_ParenAggInitMember) &&
       cast<FieldDecl>(Entity.getDecl())->isBitField())
     S.CheckBitFieldInitialization(Kind.getLocation(),
                                   cast<FieldDecl>(Entity.getDecl()),
@@ -9676,47 +9722,47 @@
       case OR_No_Viable_Function:
         if (Kind.getKind() == InitializationKind::IK_Default &&
             (Entity.getKind() == InitializedEntity::EK_Base ||
-             Entity.getKind() == InitializedEntity::EK_Member) &&
+             Entity.getKind() == InitializedEntity::EK_Member ||
+             Entity.getKind() == InitializedEntity::EK_ParenAggInitMember) &&
             isa<CXXConstructorDecl>(S.CurContext)) {
-          // This is implicit default initialization of a member or
-          // base within a constructor. If no viable function was
-          // found, notify the user that they need to explicitly
-          // initialize this base/member.
-          CXXConstructorDecl *Constructor
-            = cast<CXXConstructorDecl>(S.CurContext);
-          const CXXRecordDecl *InheritedFrom = nullptr;
-          if (auto Inherited = Constructor->getInheritedConstructor())
-            InheritedFrom = Inherited.getShadowDecl()->getNominatedBaseClass();
-          if (Entity.getKind() == InitializedEntity::EK_Base) {
-            S.Diag(Kind.getLocation(), diag::err_missing_default_ctor)
-              << (InheritedFrom ? 2 : Constructor->isImplicit() ? 1 : 0)
+        // This is implicit default initialization of a member or
+        // base within a constructor. If no viable function was
+        // found, notify the user that they need to explicitly
+        // initialize this base/member.
+        CXXConstructorDecl *Constructor =
+            cast<CXXConstructorDecl>(S.CurContext);
+        const CXXRecordDecl *InheritedFrom = nullptr;
+        if (auto Inherited = Constructor->getInheritedConstructor())
+          InheritedFrom = Inherited.getShadowDecl()->getNominatedBaseClass();
+        if (Entity.getKind() == InitializedEntity::EK_Base) {
+          S.Diag(Kind.getLocation(), diag::err_missing_default_ctor)
+              << (InheritedFrom               ? 2
+                  : Constructor->isImplicit() ? 1
+                                              : 0)
               << S.Context.getTypeDeclType(Constructor->getParent())
-              << /*base=*/0
-              << Entity.getType()
-              << InheritedFrom;
-
-            RecordDecl *BaseDecl
-              = Entity.getBaseSpecifier()->getType()->castAs<RecordType>()
-                                                                  ->getDecl();
-            S.Diag(BaseDecl->getLocation(), diag::note_previous_decl)
+              << /*base=*/0 << Entity.getType() << InheritedFrom;
+
+          RecordDecl *BaseDecl = Entity.getBaseSpecifier()
+                                     ->getType()
+                                     ->castAs<RecordType>()
+                                     ->getDecl();
+          S.Diag(BaseDecl->getLocation(), diag::note_previous_decl)
               << S.Context.getTagDeclType(BaseDecl);
-          } else {
-            S.Diag(Kind.getLocation(), diag::err_missing_default_ctor)
-              << (InheritedFrom ? 2 : Constructor->isImplicit() ? 1 : 0)
+        } else {
+          S.Diag(Kind.getLocation(), diag::err_missing_default_ctor)
+              << (InheritedFrom               ? 2
+                  : Constructor->isImplicit() ? 1
+                                              : 0)
               << S.Context.getTypeDeclType(Constructor->getParent())
-              << /*member=*/1
-              << Entity.getName()
-              << InheritedFrom;
-            S.Diag(Entity.getDecl()->getLocation(),
-                   diag::note_member_declared_at);
-
-            if (const RecordType *Record
-                                 = Entity.getType()->getAs<RecordType>())
-              S.Diag(Record->getDecl()->getLocation(),
-                     diag::note_previous_decl)
+              << /*member=*/1 << Entity.getName() << InheritedFrom;
+          S.Diag(Entity.getDecl()->getLocation(),
+                 diag::note_member_declared_at);
+
+          if (const RecordType *Record = Entity.getType()->getAs<RecordType>())
+            S.Diag(Record->getDecl()->getLocation(), diag::note_previous_decl)
                 << S.Context.getTagDeclType(Record->getDecl());
-          }
-          break;
+        }
+        break;
         }
 
         FailedCandidateSet.NoteCandidates(
Index: clang/lib/Sema/SemaAccess.cpp
===================================================================
--- clang/lib/Sema/SemaAccess.cpp
+++ clang/lib/Sema/SemaAccess.cpp
@@ -1651,7 +1651,8 @@
        << Entity.getBaseSpecifier()->getType() << getSpecialMember(Constructor);
     break;
 
-  case InitializedEntity::EK_Member: {
+  case InitializedEntity::EK_Member:
+  case InitializedEntity::EK_ParenAggInitMember: {
     const FieldDecl *Field = cast<FieldDecl>(Entity.getDecl());
     PD = PDiag(diag::err_access_field_ctor);
     PD << Field->getType() << getSpecialMember(Constructor);
Index: clang/include/clang/Sema/Initialization.h
===================================================================
--- clang/include/clang/Sema/Initialization.h
+++ clang/include/clang/Sema/Initialization.h
@@ -123,6 +123,10 @@
     /// decomposition declaration.
     EK_Binding,
 
+    /// The entity being initialized is a non-static data member subobject of an
+    /// object initialized via parenthesized aggregate initialization.
+    EK_ParenAggInitMember,
+
     // Note: err_init_conversion_failed in DiagnosticSemaKinds.td uses this
     // enum as an index for its first %select.  When modifying this list,
     // that diagnostic text needs to be updated as well.
@@ -227,8 +231,10 @@
 
   /// Create the initialization entity for a member subobject.
   InitializedEntity(FieldDecl *Member, const InitializedEntity *Parent,
-                    bool Implicit, bool DefaultMemberInit)
-      : Kind(EK_Member), Parent(Parent), Type(Member->getType()),
+                    bool Implicit, bool DefaultMemberInit,
+                    bool IsParenAggInit = false)
+      : Kind(IsParenAggInit ? EK_ParenAggInitMember : EK_Member),
+        Parent(Parent), Type(Member->getType()),
         Variable{Member, Implicit, DefaultMemberInit} {}
 
   /// Create the initialization entity for an array element.
@@ -388,6 +394,14 @@
     return InitializedEntity(Member->getAnonField(), Parent, Implicit, false);
   }
 
+  /// Create the initialization entity for a member subobject initialized via
+  /// parenthesized aggregate init.
+  static InitializedEntity InitializeMemberFromParenAggInit(FieldDecl *Member) {
+    return InitializedEntity(Member, /*Parent=*/nullptr, /*Implicit=*/false,
+                             /*DefaultMemberInit=*/false,
+                             /*IsParenAggInit=*/true);
+  }
+
   /// Create the initialization entity for a default member initializer.
   static InitializedEntity
   InitializeMemberFromDefaultMemberInitializer(FieldDecl *Member) {
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2126,7 +2126,8 @@
   "exception object|a member subobject|an array element|a new value|a value|a "
   "base class|a constructor delegation|a vector element|a block element|a "
   "block element|a complex element|a lambda capture|a compound literal "
-  "initializer|a related result|a parameter of CF audited function}0 "
+  "initializer|a related result|a parameter of CF audited function|a "
+  "structured binding|a member subobject}0 "
   "%diff{of type $ with an %select{rvalue|lvalue}2 of type $|"
   "with an %select{rvalue|lvalue}2 of incompatible type}1,3"
   "%select{|: different classes%diff{ ($ vs $)|}5,6"
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to