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

implement StmtProfiler and Sema::canThrow


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D129531

Files:
  clang/include/clang-c/Index.h
  clang/include/clang/AST/Decl.h
  clang/include/clang/AST/ExprCXX.h
  clang/include/clang/AST/RecursiveASTVisitor.h
  clang/include/clang/Basic/StmtNodes.td
  clang/include/clang/Sema/Initialization.h
  clang/include/clang/Serialization/ASTBitCodes.h
  clang/lib/AST/Expr.cpp
  clang/lib/AST/ExprCXX.cpp
  clang/lib/AST/ExprClassification.cpp
  clang/lib/AST/ExprConstant.cpp
  clang/lib/AST/ItaniumMangle.cpp
  clang/lib/AST/JSONNodeDumper.cpp
  clang/lib/AST/StmtPrinter.cpp
  clang/lib/AST/StmtProfile.cpp
  clang/lib/AST/TextNodeDumper.cpp
  clang/lib/CodeGen/CGExprAgg.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaExceptionSpec.cpp
  clang/lib/Sema/SemaInit.cpp
  clang/lib/Sema/TreeTransform.h
  clang/lib/Serialization/ASTReaderStmt.cpp
  clang/lib/Serialization/ASTWriter.cpp
  clang/lib/Serialization/ASTWriterStmt.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
  clang/test/CXX/class/class.compare/class.spaceship/p1.cpp
  clang/test/CXX/drs/dr2xx.cpp
  clang/test/CXX/temp/temp.decls/temp.variadic/p4.cpp
  clang/test/CodeGen/P0960R3.cpp
  clang/test/SemaCXX/P0960R3.cpp
  clang/test/SemaCXX/cxx2a-explicit-bool.cpp
  clang/tools/libclang/CIndex.cpp
  clang/tools/libclang/CXCursor.cpp

Index: clang/tools/libclang/CXCursor.cpp
===================================================================
--- clang/tools/libclang/CXCursor.cpp
+++ clang/tools/libclang/CXCursor.cpp
@@ -643,6 +643,10 @@
     K = CXCursor_RequiresExpr;
     break;
 
+  case Stmt::CXXParenListInitExprClass:
+    K = CXCursor_CXXParenListInitExpr;
+    break;
+
   case Stmt::MSDependentExistsStmtClass:
     K = CXCursor_UnexposedStmt;
     break;
Index: clang/tools/libclang/CIndex.cpp
===================================================================
--- clang/tools/libclang/CIndex.cpp
+++ clang/tools/libclang/CIndex.cpp
@@ -2139,6 +2139,7 @@
   void VisitLambdaExpr(const LambdaExpr *E);
   void VisitConceptSpecializationExpr(const ConceptSpecializationExpr *E);
   void VisitRequiresExpr(const RequiresExpr *E);
+  void VisitCXXParenListInitExpr(const CXXParenListInitExpr *E);
   void VisitOMPExecutableDirective(const OMPExecutableDirective *D);
   void VisitOMPLoopBasedDirective(const OMPLoopBasedDirective *D);
   void VisitOMPLoopDirective(const OMPLoopDirective *D);
@@ -2999,6 +3000,10 @@
   for (ParmVarDecl *VD : E->getLocalParameters())
     AddDecl(VD);
 }
+void EnqueueVisitor::VisitCXXParenListInitExpr(const CXXParenListInitExpr *E) {
+  // FIXME: implement
+  llvm_unreachable("unimplemented");
+}
 void EnqueueVisitor::VisitPseudoObjectExpr(const PseudoObjectExpr *E) {
   // Treat the expression like its syntactic form.
   Visit(E->getSyntacticForm());
@@ -5574,6 +5579,8 @@
     return cxstring::createRef("ConceptSpecializationExpr");
   case CXCursor_RequiresExpr:
     return cxstring::createRef("RequiresExpr");
+  case CXCursor_CXXParenListInitExpr:
+    return cxstring::createRef("CXXParenListInitExpr");
   case CXCursor_UnexposedStmt:
     return cxstring::createRef("UnexposedStmt");
   case CXCursor_DeclStmt:
Index: clang/test/SemaCXX/cxx2a-explicit-bool.cpp
===================================================================
--- clang/test/SemaCXX/cxx2a-explicit-bool.cpp
+++ clang/test/SemaCXX/cxx2a-explicit-bool.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -std=c++17 -fsyntax-only %s -verify -Wno-c++2a-extensions
-// RUN: %clang_cc1 -std=c++2a -fsyntax-only %s -verify
+// RUN: %clang_cc1 -std=c++17 -fsyntax-only %s -verify=expected,pre20 -Wno-c++2a-extensions
+// RUN: %clang_cc1 -std=c++2a -fsyntax-only %s -verify=expected,pro20
 
 template <bool b, auto val> struct enable_ifv {};
 
@@ -20,7 +20,7 @@
 
 template<int a>
 struct A {
-// expected-note@-1+ {{candidate constructor}}
+// pre20-note@-1+ {{candidate constructor}}
   explicit(1 << a)
 // expected-note@-1 {{negative shift count -1}}
 // expected-error@-2 {{explicit specifier argument is not a constant expression}}
@@ -28,8 +28,9 @@
 };
 
 A<-1> a(0);
-// expected-error@-1 {{no matching constructor}}
-// expected-note@-2 {{in instantiation of template class}}
+// pre20-error@-1 {{no matching constructor}}
+// pro20-error@-2 {{excess elements in struct initializer}}
+// expected-note@-3 {{in instantiation of template class}}
 
 template<int a>
 struct B {
Index: clang/test/SemaCXX/P0960R3.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaCXX/P0960R3.cpp
@@ -0,0 +1,88 @@
+// RUN: %clang_cc1 -verify -std=c++20 %s -fsyntax-only
+
+struct A { // expected-note 4{{candidate constructor}}
+  char i;
+  double j;
+};
+
+struct B {
+  A a;
+  int b[20];
+  int &&c; // expected-note {{reference member declared here}}
+};
+
+struct C { // expected-note 2{{candidate constructor}}
+  A a;
+  int b[20];
+};
+
+struct D : public C, public A {
+  int a;
+};
+
+struct E { // expected-note 3{{candidate constructor}}
+  struct F {
+    F(int, int);
+  };
+  int a;
+  F f;
+};
+
+int getint(); // expected-note {{declared here}}
+
+struct F {
+  int a;
+  int b = getint(); // expected-note {{non-constexpr function 'getint' cannot be used in a constant expression}}
+};
+
+union U {
+  int a;
+  char* b;
+};
+
+void foo() {
+  A a(1954, 9, 21);
+  // expected-error@-1 {{excess elements in struct initializer}}
+  A b(2.1);
+  // expected-warning@-1 {{implicit conversion from 'double' to 'char'}}
+  A e(-1.2, 9.8);
+  // expected-warning@-1 {{implicit conversion from 'double' to 'char'}}
+  A s = static_cast<A>(1.1);
+  // expected-warning@-1 {{implicit conversion from 'double' to 'char'}}
+  A h = (A)3.1;
+  // expected-warning@-1 {{implicit conversion from 'double' to 'char'}}
+  A i = A(8.7);
+  // expected-warning@-1 {{implicit conversion from 'double' to 'char'}}
+
+  B n(2022, {7, 8});
+  // expected-error@-1 {{no viable conversion from 'int' to 'A'}}
+  B z(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}}
+
+  C o(A(1), 1, 2, 3, 4);
+  // expected-error@-1 {{excess elements in struct initializer}}
+  D R(1);
+  // expected-error@-1 {{no viable conversion from 'int' to 'C'}}
+  D I(C(1));
+  // expected-error@-1 {{functional-style cast from 'int' to 'C' is not allowed}}
+  D P(C(A(1)), 1);
+  // expected-error@-1 {{no viable conversion from 'int' to 'A'}}
+
+  int arr1[](0, 1, 2, A(1));
+  // expected-error@-1 {{no viable conversion from 'A' to 'int'}}
+  int arr2[2](0, 1, 2);
+  // expected-error@-1 {{excess elements in array initializer}}
+
+  U u1("abcd");
+  // expected-error@-1 {{cannot initialize a member subobject of type 'int' with an lvalue of type 'const char[5]'}}
+  U u2(1, "efgh");
+  // expected-error@-1 {{excess elements in union initializer}}
+
+  E e1(1);
+  // expected-error@-1 {{no matching constructor for initialization of 'E'}}
+
+  constexpr F f1(1);
+  // expected-error@-1 {{constexpr variable 'f1' must be initialized by a constant expression}}
+
+  constexpr F f2(1, 1); // OK: f2.b is initialized by a constant expression.
+}
Index: clang/test/CodeGen/P0960R3.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGen/P0960R3.cpp
@@ -0,0 +1,212 @@
+// RUN: %clang_cc1 -std=c++20 %s -emit-llvm -triple x86_64-unknown-linux-gnu -o - | FileCheck %s
+
+// CHECK-DAG: [[STRUCT_A:%.*]] = type { i8, double }
+struct A {
+  char i;
+  double j;
+};
+
+// CHECK-DAG: [[STRUCT_B:%.*]] = type { [[STRUCT_A]], i32 }
+struct B {
+  A a;
+  int b;
+};
+
+// CHECK-DAG: [[STRUCT_C:%.*]] = type <{ [[STRUCT_B]], [[STRUCT_A]], i32, [4 x i8] }>
+struct C : public B, public A {
+  int c;
+};
+
+// CHECK-DAG: [[STRUCT_D:%.*]] = type { [[STRUCT_A]], [[STRUCT_A]], i8, [[STRUCT_A]] }
+struct D {
+  A a;
+  A b = A{2, 2.0};
+  unsigned : 2;
+  A c;
+};
+
+// CHECK-DAG: [[UNION_U:%.*]] = type { [[STRUCT_A]] }
+union U {
+  unsigned : 1;
+  A a;
+  char b;
+};
+
+// 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: [[B1:@.*b1.*]] = internal constant [[STRUCT_B]] { [[STRUCT_A]] { i8 99, double 0.000000e+00 }, i32 0 }, align 8
+constexpr B b1(A('c'));
+// CHECK-DAG: [[C1:@.*c1.*]] = internal constant { [[STRUCT_A]], i32, [4 x i8], i8, double, i32 } { [[STRUCT_A]] { i8 99, double 0.000000e+00 }, i32 0, [4 x i8] undef, i8 3, double 2.000000e+00, i32 0 }, align
+constexpr C c1(b1, a1);
+// CHECK-DAG: [[U1:@.*u1.*]] = internal constant [[UNION_U]] { [[STRUCT_A]] { i8 1, double 1.000000e+00 } }, align 8
+constexpr U u1(A(1, 1));
+// CHECK-DAG: [[D1:@.*d1.*]] = internal constant { [[STRUCT_A]], [[STRUCT_A]], [8 x i8], [[STRUCT_A]] } { [[STRUCT_A]] { i8 2, double 2.000000e+00 }, [[STRUCT_A]] { i8 2, double 2.000000e+00 }, [8 x i8] undef, [[STRUCT_A]] zeroinitializer }, align 8
+constexpr D d1(A(2, 2));
+// CHECK-DAG: [[ARR1:@.*arr1.*]] = internal constant [3 x i32] [i32 1, i32 2, i32 0], align 4
+constexpr int arr1[3](1, 2);
+
+// CHECK: define dso_local { i8, double } @{{.*foo1.*}}
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_A]], align 8
+// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[RETVAL]], ptr align 8 [[A1]], i64 16, i1 false)
+// CHECK-NEXT: [[TMP_0:%.*]] = load { i8, double }, ptr [[RETVAL]], align 8
+// CHECK-NEXT: ret { i8, double } [[TMP_0]]
+A foo1() {
+  return a1;
+}
+
+// CHECK: define dso_local void @{{.*foo2.*}}(ptr noalias sret([[STRUCT_B]]) align 8 [[AGG_RESULT:%.*]])
+// CHECK-NEXT: entry:
+// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[AGG_RESULT]], ptr align 8 [[B1]], i64 24, i1 false)
+// CHECK-NEXT: ret void
+B foo2() {
+  return b1;
+}
+
+// CHECK: define dso_local void @{{.*foo3.*}}(ptr noalias sret([[STRUCT_C]]) align 8 [[AGG_RESULT:%.*]])
+// CHECK-NEXT: entry:
+// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[AGG_RESULT]], ptr align 8 [[C1]], i64 48, i1 false)
+// CHECK-NEXT: ret void
+C foo3() {
+  return c1;
+}
+
+// CHECK: define dso_local void @{{.*foo4.*}}
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[C2:%.*]] = alloca [[STRUCT_C:%.*]], align 8
+// CHECK-NEXT: [[REF_TMP:%.*]] = alloca [[STRUCT_B:%.*]], align 8
+// CHECK-NEXT: [[REF_TMP_1:%.*]] = alloca [[STRUCT_A:%.*]], align 8
+// CHECK-NEXT: [[A:%.*]] = getelementptr inbounds [[STRUCT_B]], ptr [[REF_TMP]], i32 0, i32 0
+// CHECK-NEXT: [[I:%.*]] = getelementptr inbounds [[STRUCT_A]], ptr [[A]], i32 0, i32 0
+// CHECK-NEXT: store i8 1, ptr [[I]], align 8
+// CHECK-NEXT: [[J:%.*]] = getelementptr inbounds [[STRUCT_A]], ptr [[A]], i32 0, i32 1
+// CHECK-NEXT: store double 1.000000e+00, ptr [[J]], align 8
+// CHECK-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_B]], ptr [[REF_TMP]], i32 0, i32 1
+// CHECK-NEXT: store i32 1, ptr [[B]], align 8
+// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[C2]], ptr align 8 [[REF_TMP]], i64 24, i1 false)
+// CHECK-NEXT: [[TMP_0:%.*]] = getelementptr inbounds i8, ptr [[C2]], i64 24
+// CHECK-NEXT: [[I2:%.*]] = getelementptr inbounds [[STRUCT_A]], ptr [[REF_TMP_1]], i32 0, i32 0
+// CHECK-NEXT: store i8 97, ptr [[I2]], align 8
+// CHECK-NEXT: [[J3:%.*]] = getelementptr inbounds [[STRUCT_A]], ptr [[REF_TMP_1]], i32 0, i32 1
+// CHECK-NEXT: store double 0.000000e+00, ptr [[J3]], align 8
+// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[TMP_0]], ptr align 8 [[REF_TMP_1]], i64 16, i1 false)
+// CHECK-NEXT: [[C:%.*]] = getelementptr inbounds %struct.C, ptr %c2, i32 0, i32 2
+// CHECK-NEXT: store i32 2, ptr %c, align 8
+// CHECK-NEXT: ret void
+void foo4() {
+  C c2(B(A(1, 1), 1), A('a'), 2);
+}
+
+// CHECK: define dso_local { i64, double } @{{.*foo5.*}}
+// CHECK-NEXT: entry:
+// CHECK-NEXT [[RETVAL:%.*]] = alloca [[UNION_U]], align 8
+// CHECK-NEXT call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[RETVAL]], ptr align 8 [[U1]], i64 16, i1 false)
+// CHECK-NEXT [[COERCE_DIVE:%.*]] = getelementptr inbounds [[UNION_U]], ptr %retval, i32 0, i32 0
+// CHECK-NEXT [[TMP_0:%.*]] = load { i64, double }, ptr [[COERCE_DIVE]], align 8
+// CHECK-NEXT ret { i64, double } [[TMP_0]]
+U foo5() {
+  return u1;
+}
+
+
+// CHECK: define dso_local { i64, double } @{{.*foo6.*}}(i8 [[A_COERCE_0:%.*]], double [[A_COERCE_1:%.*]])
+// CHECK-NEXT: entry:
+// CHECK-NEXT:   [[RETVAL:%.*]] = alloca [[UNION_U]], align 8
+// CHECK-NEXT:   [[A:%.*]] = alloca [[STRUCT_A]], align 8
+// CHECK-NEXT:   [[TMP_0:%.*]] = getelementptr inbounds { i8, double }, ptr [[A]], i32 0, i32 0
+// CHECK-NEXT:   store i8 [[A_COERCE_0]], ptr [[TMP_0]], align 8
+// CHECK-NEXT:   [[TMP_1:%.*]] = getelementptr inbounds { i8, double }, ptr [[A]], i32 0, i32 1
+// CHECK-NEXT:   store double [[A_COERCE_1]], ptr [[TMP_1]], align 8
+// CHECK-NEXT:   call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[RETVAL]], ptr align 8 [[A]], i64 16, i1 false)
+// CHECK-NEXT:   [[COERCE_DIVE:%.*]] = getelementptr inbounds [[UNION_U]], ptr [[RETVAL]], i32 0, i32 0
+// CHECK-NEXT:   [[TMP_2:%.*]] = load { i64, double }, ptr [[COERCE_DIVE:%.*]], align 8
+// CHECK-NEXT:   ret { i64, double } [[TMP_2]]
+U foo6(A a) {
+  return U(a);
+}
+
+// CHECK: define dso_local void @{{.*foo7.*}}
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[D:%.*]] = alloca [[STRUCT_D:%.*]], align 8
+// CHECK-NEXT: [[A:%.*]] = getelementptr inbounds [[STRUCT_D]], ptr [[D]], i32 0, i32 0
+// CHECK-NEXT: [[I]] = getelementptr inbounds [[STRUCT_A:%.*]], ptr [[A]], i32 0, i32 0
+// CHECK-NEXT: store i8 1, ptr [[I]], align 8
+// CHECK-NEXT: [[J:%.*]] = getelementptr inbounds [[STRUCT_A]], ptr [[A]], i32 0, i32 1
+// CHECK-NEXT: store double 1.000000e+00, ptr [[J]], align 8
+// CHECK-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_D]], ptr [[D]], i32 0, i32 1
+// CHECK-NEXT: [[I1:%.*]] = getelementptr inbounds [[STRUCT_A]], ptr [[B]], i32 0, i32 0
+// CHECK-NEXT: store i8 11, ptr [[I1]], align 8
+// CHECK-NEXT: [[J2:%.*]] = getelementptr inbounds [[STRUCT_A]], ptr [[B]], i32 0, i32 1
+// CHECK-NEXT: store double 1.100000e+01, ptr [[J2]], align 8
+// CHECK-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_D]], ptr [[D]], i32 0, i32 3
+// CHECK-NEXT: [[I3:%.*]] = getelementptr inbounds [[STRUCT_A]], ptr [[C]], i32 0, i32 0
+// CHECK-NEXT: store i8 111, ptr [[I3]], align 8
+// CHECK-NEXT: [[J4:%.*]] = getelementptr inbounds [[STRUCT_A]], ptr [[C]], i32 0, i32 1
+// CHECK-NEXT: store double 1.110000e+02, ptr [[J4]], align 8
+// CHECK-NEXT: ret void
+void foo7() {
+  D d(A(1, 1), A(11, 11), A(111, 111));
+}
+
+// CHECK: dso_local void @{{.*foo8.*}}(ptr noalias sret([[STRUCT_D]]) align 8 [[AGG_RESULT:%.*]])
+// CHECK-NEXT: entry:
+// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[AGG_RESULT]], ptr align 8 [[D1]], i64 56, i1 false)
+// CHECK-NEXT: ret void
+D foo8() {
+  return d1;
+}
+
+// CHECK: define dso_local void @{{.*foo9.*}}
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[D:%.*]] = alloca [[STRUCT_D:%.*]], align 8
+// CHECK-NEXT: [[A:%.*]] = getelementptr inbounds [[STRUCT_D]], ptr [[D]], i32 0, i32 0
+// CHECK-NEXT: [[I]] = getelementptr inbounds [[STRUCT_A:%.*]], ptr [[A]], i32 0, i32 0
+// CHECK-NEXT: store i8 1, ptr [[I]], align 8
+// CHECK-NEXT: [[J:%.*]] = getelementptr inbounds [[STRUCT_A]], ptr [[A]], i32 0, i32 1
+// CHECK-NEXT: store double 1.000000e+00, ptr [[J]], align 8
+// CHECK-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_D]], ptr [[D]], i32 0, i32 1
+// CHECK-NEXT: [[I1:%.*]] = getelementptr inbounds [[STRUCT_A]], ptr [[B]], i32 0, i32 0
+// CHECK-NEXT: store i8 2, ptr [[I1]], align 8
+// CHECK-NEXT: [[J2:%.*]] = getelementptr inbounds [[STRUCT_A]], ptr [[B]], i32 0, i32 1
+// CHECK-NEXT: store double 2.000000e+00, ptr [[J2]], align 8
+// CHECK-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_D]], ptr [[D]], i32 0, i32 3
+// CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[C]], i8 0, i64 16, i1 false)
+// CHECK-NEXT: ret void
+void foo9() {
+  D d(A(1, 1));
+}
+
+// CHECK: define dso_local noundef ptr @{{.*foo10.*}}()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: ret ptr [[ARR1]]
+const int* foo10() {
+  return arr1;
+}
+
+// CHECK: define dso_local void @{{.*foo11.*}}
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT: [[ARR_2:%.*]] = alloca [3 x i32], align 4
+// CHECK-NEXT: [[ARR_3:%.*]] = alloca [2 x i32], align 4
+// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-NEXT: [[TMP_0:%.*]] = getelementptr inbounds [3 x i32], ptr [[ARR_2]], i64 0, i64 0
+// CHECK-NEXT: [[TMP_1:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-NEXT: store i32 [[TMP_1]], ptr [[TMP_0]], align 4
+// CHECK-NEXT: [[TMP_2:%.*]] = getelementptr inbounds [3 x i32], ptr [[ARR_2]], i64 0, i64 1
+// CHECK-NEXT: [[TMP_3:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-NEXT: store i32 [[TMP_3]], ptr [[TMP_2]], align 4
+// CHECK-NEXT: [[TMP_4:%.*]] = getelementptr inbounds [3 x i32], ptr [[ARR_2]], i64 0, i64 2
+// CHECK-NEXT: store i32 0, ptr [[TMP_4]], align 4
+// CHECK-NEXT: [[TMP_5:%.*]] = getelementptr inbounds [2 x i32], ptr [[ARR_3]], i64 0, i64 0
+// CHECK-NEXT: [[TMP_6:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-NEXT: store i32 [[TMP_6]], ptr [[TMP_5]], align 4
+// CHECK-NEXT: [[TMP_7:%.*]] = getelementptr inbounds [2 x i32], ptr [[ARR_3]], i64 0, i64 1
+// CHECK-NEXT: [[TMP_8:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-NEXT: store i32 [[TMP_8]], ptr [[TMP_7]], align 4
+// CHECK-NEXT: ret void
+void foo11(int a, int b) {
+  int arr2[3](a, b);
+  int arr3[](a, b);
+}
Index: clang/test/CXX/temp/temp.decls/temp.variadic/p4.cpp
===================================================================
--- clang/test/CXX/temp/temp.decls/temp.variadic/p4.cpp
+++ clang/test/CXX/temp/temp.decls/temp.variadic/p4.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fexceptions -fcxx-exceptions -verify %s
-// RUN: %clang_cc1 -std=c++2a -fsyntax-only -fexceptions -fcxx-exceptions -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fexceptions -fcxx-exceptions -verify=expected,pre20 %s
+// RUN: %clang_cc1 -std=c++2a -fsyntax-only -fexceptions -fcxx-exceptions -verify=expected,pro20 %s
 
 template<typename... Types> struct tuple;
 template<int I> struct int_c;
@@ -99,12 +99,12 @@
   HasMixins(int i);
 };
 
-struct A { }; // expected-note{{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'int' to 'const A' for 1st argument}} \
-// expected-note{{candidate constructor (the implicit move constructor) not viable: no known conversion from 'int' to 'A' for 1st argument}} \
-// expected-note{{candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided}}
-struct B { }; // expected-note{{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'int' to 'const B' for 1st argument}} \
-// expected-note{{candidate constructor (the implicit move constructor) not viable: no known conversion from 'int' to 'B' for 1st argument}} \
-// expected-note{{candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided}}
+struct A { }; // pre20-note{{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'int' to 'const A' for 1st argument}} \
+// pre20-note{{candidate constructor (the implicit move constructor) not viable: no known conversion from 'int' to 'A' for 1st argument}} \
+// pre20-note{{candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided}}
+struct B { }; // pre20-note{{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'int' to 'const B' for 1st argument}} \
+// pre20-note{{candidate constructor (the implicit move constructor) not viable: no known conversion from 'int' to 'B' for 1st argument}} \
+// pre20-note{{candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided}}
 struct C { };
 struct D { };
 
@@ -126,8 +126,10 @@
 
 template<typename ...Mixins>
 HasMixins<Mixins...>::HasMixins(int i): Mixins(i)... { }
-// expected-error@-1 {{no matching constructor for initialization of 'A'}}
-// expected-error@-2 {{no matching constructor for initialization of 'B'}}
+// pre20-error@-1 {{no matching constructor for initialization of 'A'}}
+// pre20-error@-2 {{no matching constructor for initialization of 'B'}}
+// pro20-error@-3 {{excess elements in struct initializer}}
+// pro20-error@-4 {{excess elements in struct initializer}}
 
 void test_has_mixins() {
   HasMixins<A, B> ab;
Index: clang/test/CXX/drs/dr2xx.cpp
===================================================================
--- clang/test/CXX/drs/dr2xx.cpp
+++ clang/test/CXX/drs/dr2xx.cpp
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++17 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++20 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++98 %s -verify=expected,pre20 -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++11 %s -verify=expected,pre20 -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++14 %s -verify=expected,pre20 -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++17 %s -verify=expected,pre20 -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++20 %s -verify=expected,pro20 -fexceptions -fcxx-exceptions -pedantic-errors
 
 // PR13819 -- __SIZE_TYPE__ is incompatible.
 typedef __SIZE_TYPE__ size_t; // expected-error 0-1 {{extension}}
@@ -157,7 +157,8 @@
     void test3(A::S as) { using A::f; f(as); } // ok
     void test4(A::S as) { using B::f; f(as); } // ok
     void test5(A::S as) { int f; f(as); } // expected-error {{called object type 'int'}}
-    void test6(A::S as) { struct f {}; (void) f(as); } // expected-error {{no matching conversion}} expected-note +{{}}
+    void test6(A::S as) { struct f {}; (void) f(as); } // pre20-error {{no matching conversion}} pre20-note +{{}}
+    // pro20-error@-1 {{functional-style cast from 'A::S' to 'f' is not allowed}}
   };
 
   namespace D {
Index: clang/test/CXX/class/class.compare/class.spaceship/p1.cpp
===================================================================
--- clang/test/CXX/class/class.compare/class.spaceship/p1.cpp
+++ clang/test/CXX/class/class.compare/class.spaceship/p1.cpp
@@ -1,7 +1,7 @@
 // RUN: %clang_cc1 -std=c++2a -verify %s -fcxx-exceptions
 
 namespace std {
-  struct strong_ordering { // expected-note 6{{candidate}}
+  struct strong_ordering {
     int n;
     constexpr operator int() const { return n; }
     static const strong_ordering less, equal, greater;
@@ -103,7 +103,7 @@
       Cmp<G1>() <=> Cmp<G1>(), // expected-note-re {{in defaulted three-way comparison operator for '{{.*}}Cmp<{{.*}}G1>' first required here}}j
       // expected-error@#cmp {{value of type 'void' is not contextually convertible to 'bool'}}
       Cmp<G2>() <=> Cmp<G2>(), // expected-note-re {{in defaulted three-way comparison operator for '{{.*}}Cmp<{{.*}}G2>' first required here}}j
-      // expected-error@#cmp {{no matching conversion for static_cast from 'void' to 'std::strong_ordering'}}
+      // expected-error@#cmp {{static_cast from 'void' to 'std::strong_ordering' is not allowed}}
       Cmp<H>() <=> Cmp<H>(), // expected-note-re {{in defaulted three-way comparison operator for '{{.*}}Cmp<{{.*}}H>' first required here}}j
       0
     );
@@ -134,7 +134,7 @@
       CmpArray<G1>() <=> CmpArray<G1>(), // expected-note-re {{in defaulted three-way comparison operator for '{{.*}}CmpArray<{{.*}}G1>' first required here}}j
       // expected-error@#cmparray {{value of type 'void' is not contextually convertible to 'bool'}}
       CmpArray<G2>() <=> CmpArray<G2>(), // expected-note-re {{in defaulted three-way comparison operator for '{{.*}}CmpArray<{{.*}}G2>' first required here}}j
-      // expected-error@#cmparray {{no matching conversion for static_cast from 'void' to 'std::strong_ordering'}}
+      // expected-error@#cmparray {{static_cast from 'void' to 'std::strong_ordering' is not allowed}}
       CmpArray<H>() <=> CmpArray<H>(), // expected-note-re {{in defaulted three-way comparison operator for '{{.*}}CmpArray<{{.*}}H>' first required here}}j
       0
     );
Index: clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1897,6 +1897,7 @@
     case Stmt::ConceptSpecializationExprClass:
     case Stmt::CXXRewrittenBinaryOperatorClass:
     case Stmt::RequiresExprClass:
+    case Expr::CXXParenListInitExprClass:
       // Fall through.
 
     // Cases we intentionally don't evaluate, since they don't need
Index: clang/lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- clang/lib/Serialization/ASTWriterStmt.cpp
+++ clang/lib/Serialization/ASTWriterStmt.cpp
@@ -2078,6 +2078,16 @@
   Code = serialization::EXPR_CXX_FOLD;
 }
 
+void ASTStmtWriter::VisitCXXParenListInitExpr(CXXParenListInitExpr *E) {
+  VisitExpr(E);
+  Record.AddSourceLocation(E->getExprLoc());
+  ArrayRef<Expr *> InitExprs = E->getInitExprs();
+  Record.push_back(InitExprs.size());
+  for (Expr *InitExpr : E->getInitExprs())
+    Record.AddStmt(InitExpr);
+  Code = serialization::EXPR_CXX_PAREN_LIST_INIT;
+}
+
 void ASTStmtWriter::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
   VisitExpr(E);
   Record.AddStmt(E->getSourceExpr());
Index: clang/lib/Serialization/ASTWriter.cpp
===================================================================
--- clang/lib/Serialization/ASTWriter.cpp
+++ clang/lib/Serialization/ASTWriter.cpp
@@ -733,6 +733,7 @@
   RECORD(EXPR_USER_DEFINED_LITERAL);
   RECORD(EXPR_CXX_STD_INITIALIZER_LIST);
   RECORD(EXPR_CXX_BOOL_LITERAL);
+  RECORD(EXPR_CXX_PAREN_LIST_INIT);
   RECORD(EXPR_CXX_NULL_PTR_LITERAL);
   RECORD(EXPR_CXX_TYPEID_EXPR);
   RECORD(EXPR_CXX_TYPEID_TYPE);
Index: clang/lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- clang/lib/Serialization/ASTReaderStmt.cpp
+++ clang/lib/Serialization/ASTReaderStmt.cpp
@@ -2168,6 +2168,14 @@
   E->Opcode = (BinaryOperatorKind)Record.readInt();
 }
 
+void ASTStmtReader::VisitCXXParenListInitExpr(CXXParenListInitExpr *E) {
+  VisitExpr(E);
+  E->Loc = readSourceLocation();
+  E->NumExprs = Record.readInt();
+  for (unsigned I = 0; I < E->NumExprs; I++)
+    E->getTrailingObjects<Expr *>()[I] = Record.readSubExpr();
+}
+
 void ASTStmtReader::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
   VisitExpr(E);
   E->SourceExpr = Record.readSubExpr();
@@ -3947,6 +3955,10 @@
       S = new (Context) CXXFoldExpr(Empty);
       break;
 
+    case EXPR_CXX_PAREN_LIST_INIT:
+      S = new (Context) CXXParenListInitExpr(Empty);
+      break;
+
     case EXPR_OPAQUE_VALUE:
       S = new (Context) OpaqueValueExpr(Empty);
       break;
Index: clang/lib/Sema/TreeTransform.h
===================================================================
--- clang/lib/Sema/TreeTransform.h
+++ clang/lib/Sema/TreeTransform.h
@@ -13919,6 +13919,13 @@
   return Result;
 }
 
+template <typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformCXXParenListInitExpr(CXXParenListInitExpr *E) {
+  // FIXME: unimplemented
+  llvm_unreachable("unimplemented");
+}
+
 template<typename Derived>
 ExprResult
 TreeTransform<Derived>::TransformCXXStdInitializerListExpr(
Index: clang/lib/Sema/SemaInit.cpp
===================================================================
--- clang/lib/Sema/SemaInit.cpp
+++ clang/lib/Sema/SemaInit.cpp
@@ -3519,11 +3519,13 @@
   case SK_StdInitializerListConstructorCall:
   case SK_OCLSamplerInit:
   case SK_OCLZeroOpaqueType:
+  case SK_ParenthesizedListInit:
     break;
 
   case SK_ConversionSequence:
   case SK_ConversionSequenceNoNarrowing:
     delete ICS;
+    break;
   }
 }
 
@@ -3578,6 +3580,7 @@
   case FK_PlaceholderType:
   case FK_ExplicitConstructor:
   case FK_AddressOfUnaddressableFunction:
+  case FK_ParenthesizedListInitFailed:
     return false;
 
   case FK_ReferenceInitOverloadFailed:
@@ -3813,6 +3816,13 @@
   Steps.push_back(S);
 }
 
+void InitializationSequence::AddParenthesizedListInitStep(QualType T) {
+  Step S;
+  S.Kind = SK_ParenthesizedListInit;
+  S.Type = T;
+  Steps.push_back(S);
+}
+
 void InitializationSequence::RewrapReferenceInitList(QualType T,
                                                      InitListExpr *Syntactic) {
   assert(Syntactic->getNumInits() == 1 &&
@@ -5250,6 +5260,139 @@
   }
 }
 
+static void TryOrBuildParenListInitialization(
+    Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind,
+    ArrayRef<Expr *> Args, InitializationSequence &Sequence, bool VerifyOnly,
+    ExprResult *Result = nullptr) {
+  unsigned Index = 0;
+  SmallVector<Expr *, 4> InitExprs;
+  QualType ResultType;
+
+  auto InitHelper = [&](auto Range) -> bool {
+    for (InitializedEntity SubEntity : Range) {
+      if (Index == 1 && Entity.getType()->isUnionType())
+        // Unions should only have one initializer expression.
+        return true;
+
+      if (SubEntity.getKind() == InitializedEntity::EK_Member &&
+          cast<FieldDecl>(SubEntity.getDecl())->isUnnamedBitfield())
+        continue;
+
+      if (Index == Args.size()) {
+        if (SubEntity.getKind() == InitializedEntity::EK_Member) {
+          // C++ [dcl.init]p17.6.2.2
+          //   The remaining elements are initialized with their default member
+          //   initializers, if any, and otherwise are value-initialized.
+          const auto *FD = cast<FieldDecl>(SubEntity.getDecl());
+          if (Expr *ICE = FD->getInClassInitializer()) {
+            InitExprs.push_back(ICE);
+            continue;
+          };
+        }
+        InitializationKind SubKind = InitializationKind::CreateValue(
+            Kind.getLocation(), Kind.getLocation(), Kind.getLocation());
+        InitializationSequence Seq(S, SubEntity, SubKind, None);
+        TryValueInitialization(S, SubEntity, SubKind, Seq);
+        if (Seq.Failed()) {
+          if (!VerifyOnly)
+            Seq.Diagnose(S, SubEntity, SubKind, None);
+          return false;
+        }
+        if (!VerifyOnly) {
+          ExprResult ER = Seq.Perform(S, SubEntity, SubKind, None);
+          InitExprs.push_back(ER.get());
+        }
+        continue;
+      }
+
+      Expr *E = Args[Index++];
+      InitializationKind SubKind = InitializationKind::CreateForInit(
+          E->getExprLoc(), /*isDirectInit*/ false, E);
+      InitializationSequence Seq(S, SubEntity, SubKind, E);
+
+      if (Seq.Failed()) {
+        if (!VerifyOnly)
+          Seq.Diagnose(S, SubEntity, SubKind, E);
+        else
+          Sequence.SetFailed(
+              InitializationSequence::FK_ParenthesizedListInitFailed);
+
+        return false;
+      }
+      if (!VerifyOnly) {
+        ExprResult ER = Seq.Perform(S, SubEntity, SubKind, E);
+        InitExprs.push_back(ER.get());
+      }
+    }
+    return true;
+  };
+
+  if (const ArrayType *AT =
+          S.getASTContext().getAsArrayType(Entity.getType())) {
+
+    SmallVector<InitializedEntity, 4> ElementEntities;
+    uint64_t ArrayLength;
+    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 (!InitHelper(ElementEntities))
+        return;
+
+      ResultType = S.Context.getConstantArrayType(
+          AT->getElementType(), llvm::APInt(32, ArrayLength), nullptr,
+          ArrayType::Normal, 0);
+    }
+  } else if (auto *RT = Entity.getType()->getAs<RecordType>()) {
+    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 (!InitHelper(BaseRange))
+      return;
+
+    if (!InitHelper(FieldRange))
+      return;
+
+    ResultType = Entity.getType();
+  }
+
+  if (Index != Args.size()) {
+    if (!VerifyOnly) {
+      QualType T = Entity.getType();
+      int InitKind = T->isArrayType() ? 0 : T->isUnionType() ? 3 : 4;
+      S.Diag(Kind.getLocation(), diag::err_excess_initializers)
+          << InitKind << Args[Index]->getSourceRange();
+    } else {
+      Sequence.SetFailed(
+          InitializationSequence::FK_ParenthesizedListInitFailed);
+    }
+    return;
+  }
+
+  if (VerifyOnly) {
+    Sequence.setSequenceKind(InitializationSequence::NormalSequence);
+    Sequence.AddParenthesizedListInitStep(Entity.getType());
+  } else if (Result) {
+    *Result = CXXParenListInitExpr::Create(S.getASTContext(), InitExprs,
+                                           ResultType, Kind.getLocation());
+  }
+
+  return;
+}
+
 /// Attempt a user-defined conversion between two types (C++ [dcl.init]),
 /// which enumerates all conversion functions and performs overload resolution
 /// to select the best.
@@ -5905,7 +6048,10 @@
       TryListInitialization(S, Entity, Kind, cast<InitListExpr>(Initializer),
                             *this, TreatUnavailableAsInvalid);
       AddParenthesizedArrayInitStep(DestType);
-    } else if (DestAT->getElementType()->isCharType())
+    } else if (S.getLangOpts().CPlusPlus20 && !TopLevelOfInitList)
+      TryOrBuildParenListInitialization(S, Entity, Kind, Args, *this,
+                                        /*VerifyOnly=*/true);
+    else if (DestAT->getElementType()->isCharType())
       SetFailed(FK_ArrayNeedsInitListOrStringLiteral);
     else if (IsWideCharCompatible(DestAT->getElementType(), Context))
       SetFailed(FK_ArrayNeedsInitListOrWideStringLiteral);
@@ -5952,18 +6098,52 @@
     if (Kind.getKind() == InitializationKind::IK_Direct ||
         (Kind.getKind() == InitializationKind::IK_Copy &&
          (Context.hasSameUnqualifiedType(SourceType, DestType) ||
-          S.IsDerivedFrom(Initializer->getBeginLoc(), SourceType, DestType))))
-      TryConstructorInitialization(S, Entity, Kind, Args,
-                                   DestType, DestType, *this);
-    //     - Otherwise (i.e., for the remaining copy-initialization cases),
-    //       user-defined conversion sequences that can convert from the source
-    //       type to the destination type or (when a conversion function is
-    //       used) to a derived class thereof are enumerated as described in
-    //       13.3.1.4, and the best one is chosen through overload resolution
-    //       (13.3).
-    else
+          S.IsDerivedFrom(Initializer->getBeginLoc(), SourceType, DestType)))) {
+      TryConstructorInitialization(S, Entity, Kind, Args, DestType, DestType,
+                                   *this);
+
+      // We fall back to the "no matching constructor "path iff the
+      // failed candidate set has function other than the three default
+      // constructors. For example, conversion function.
+      if (const CXXRecordDecl *RD =
+              dyn_cast<CXXRecordDecl>(DestType->getAs<RecordType>()->getDecl());
+          S.getLangOpts().CPlusPlus20 && RD && RD->isAggregate() &&
+          Failure == FK_ConstructorOverloadFailed &&
+          getFailedCandidateSet().size() == 3) {
+        // const ValueDecl *VD = Entity.getDecl();
+        // if (const VarDecl *VarD = dyn_cast_or_null<VarDecl>(VD);
+        //     VarD && VarD->hasInit() && !VarD->getInit()->containsErrors())
+        // C++20 [dcl.init] 17.6.2.2:
+        //   - Otherwise, if no constructor is viable, the destination type is
+        //   an
+        //      aggregate class, and the initializer is a parenthesized
+        //      expression-list, the object is initialized as follows. Let e1,
+        //      ..., en be the elements of the aggregate . Let x1, ..., xk be
+        //      the elements of the expression-list. If k is greater than n,
+        //      the program is ill-formed. The element ei is copy-initialized
+        //      with xi for 1 <= i <= k. The remaining elements are
+        //      initialized with their default member initializers, if any,
+        //      and otherwise are value-initialized. For each 1 <= i < j <= n,
+        //      every value computation and side effect associated with the
+        //      initialization of ei is sequenced before those associated with
+        //      the initialization of ej. Note: By contrast with
+        //      direct-list-initialization, narrowing conversions (9.4.4) are
+        //      permitted, designators are not permitted, a temporary object
+        //      bound to a reference does not have its lifetime extended
+        //      (6.7.7), and there is no brace elision.
+        TryOrBuildParenListInitialization(S, Entity, Kind, Args, *this,
+                                          /*VerifyOnly=*/true);
+      }
+    } else {
+      //     - Otherwise (i.e., for the remaining copy-initialization cases),
+      //       user-defined conversion sequences that can convert from the
+      //       source type to the destination type or (when a conversion
+      //       function is used) to a derived class thereof are enumerated as
+      //       described in 13.3.1.4, and the best one is chosen through
+      //       overload resolution (13.3).
       TryUserDefinedConversion(S, DestType, Kind, Initializer, *this,
                                TopLevelOfInitList);
+    }
     return;
   }
 
@@ -8223,6 +8403,7 @@
   case SK_ConstructorInitializationFromList:
   case SK_StdInitializerListConstructorCall:
   case SK_ZeroInitialization:
+  case SK_ParenthesizedListInit:
     break;
   }
 
@@ -8912,6 +9093,14 @@
                                     CurInit.get()->getValueKind());
       break;
     }
+    case SK_ParenthesizedListInit: {
+      CurInit = false;
+      TryOrBuildParenListInitialization(S, Entity, Kind, Args, *this,
+                                        /*VerifyOnly=*/false, &CurInit);
+      if (CurInit.get() && ResultType)
+        *ResultType = CurInit.get()->getType();
+      break;
+    }
     }
   }
 
@@ -9514,6 +9703,10 @@
            diag::note_explicit_ctor_deduction_guide_here) << false;
     break;
   }
+
+  case FK_ParenthesizedListInitFailed:
+    TryOrBuildParenListInitialization(S, Entity, Kind, Args, *this,
+                                      /*VerifyOnly=*/false);
   }
 
   PrintInitLocationNote(S, Entity);
@@ -9680,6 +9873,10 @@
     case FK_ExplicitConstructor:
       OS << "list copy initialization chose explicit constructor";
       break;
+
+    case FK_ParenthesizedListInitFailed:
+      OS << "parenthesized list initialization failed";
+      break;
     }
     OS << '\n';
     return;
@@ -9851,6 +10048,9 @@
     case SK_OCLZeroOpaqueType:
       OS << "OpenCL opaque type from zero";
       break;
+    case SK_ParenthesizedListInit:
+      OS << "initialization from a parenthesized list of values";
+      break;
     }
 
     OS << " [" << S->Type << ']';
Index: clang/lib/Sema/SemaExceptionSpec.cpp
===================================================================
--- clang/lib/Sema/SemaExceptionSpec.cpp
+++ clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1289,6 +1289,7 @@
   case Expr::StmtExprClass:
   case Expr::ConvertVectorExprClass:
   case Expr::VAArgExprClass:
+  case Expr::CXXParenListInitExprClass:
     return canSubStmtsThrow(*this, S);
 
   case Expr::CompoundLiteralExprClass:
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -12974,6 +12974,7 @@
 
   // Perform the initialization.
   ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init);
+  bool IsParenListInit = false;
   if (!VDecl->isInvalidDecl()) {
     InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl);
     InitializationKind Kind = InitializationKind::CreateForInit(
@@ -13016,6 +13017,8 @@
     }
 
     Init = Result.getAs<Expr>();
+    IsParenListInit = InitSeq.step_begin()->Kind ==
+                      InitializationSequence::SK_ParenthesizedListInit;
   }
 
   // Check for self-references within variable initializers.
@@ -13264,7 +13267,8 @@
   // class type.
   if (CXXDirectInit) {
     assert(DirectInit && "Call-style initializer must be direct init.");
-    VDecl->setInitStyle(VarDecl::CallInit);
+    VDecl->setInitStyle(IsParenListInit ? VarDecl::ParenListInit
+                                        : VarDecl::CallInit);
   } else if (DirectInit) {
     // This must be list-initialization. No other way is direct-initialization.
     VDecl->setInitStyle(VarDecl::ListInit);
Index: clang/lib/CodeGen/CGExprAgg.cpp
===================================================================
--- clang/lib/CodeGen/CGExprAgg.cpp
+++ clang/lib/CodeGen/CGExprAgg.cpp
@@ -205,6 +205,7 @@
   }
 
   void VisitVAArgExpr(VAArgExpr *E);
+  void VisitCXXParenListInitExpr(CXXParenListInitExpr *E);
 
   void EmitInitializationToLValue(Expr *E, LValue Address);
   void EmitNullInitializationToLValue(LValue Address);
@@ -1591,6 +1592,48 @@
   }
 }
 
+void AggExprEmitter::VisitCXXParenListInitExpr(CXXParenListInitExpr *E) {
+  ArrayRef<Expr *> InitExprs = E->getInitExprs();
+  AggValueSlot Dest = EnsureSlot(E->getType());
+
+  if (const ArrayType *AT = dyn_cast<ArrayType>(E->getType())) {
+    for (auto Pair : llvm::enumerate(InitExprs)) {
+      // Initialization for every element of the array.
+      Address V = Builder.CreateConstArrayGEP(Dest.getAddress(), Pair.index());
+      LValue LV = CGF.MakeAddrLValue(V, AT->getElementType());
+      EmitInitializationToLValue(Pair.value(), LV);
+    }
+  } else if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(
+                 E->getType()->castAs<RecordType>()->getDecl())) {
+
+    unsigned Index = 0;
+    LValue DestLV = CGF.MakeAddrLValue(Dest.getAddress(), E->getType());
+
+    // Initialize the base classes first.
+    for (auto &Base : RD->bases()) {
+      if (Index < InitExprs.size()) {
+        const CXXRecordDecl *BaseRD = Base.getType()->getAsCXXRecordDecl();
+        Address V = CGF.GetAddressOfDirectBaseInCompleteClass(
+            Dest.getAddress(), RD, BaseRD,
+            /*isBaseVirtual*/ false);
+        AggValueSlot AggSlot = AggValueSlot::forAddr(
+            V, Qualifiers(), AggValueSlot::IsDestructed,
+            AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsNotAliased,
+            CGF.getOverlapForBaseInit(RD, BaseRD, Base.isVirtual()));
+        CGF.EmitAggExpr(InitExprs[Index++], AggSlot);
+      }
+    }
+
+    // Then initialize the fields.
+    for (const FieldDecl *F : RD->fields()) {
+      if (!F->isUnnamedBitfield() && Index < InitExprs.size()) {
+        LValue LV = CGF.EmitLValueForFieldInitialization(DestLV, F);
+        EmitInitializationToLValue(InitExprs[Index++], LV);
+      }
+    }
+  }
+}
+
 void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
 #if 0
   // FIXME: Assess perf here?  Figure out what cases are worth optimizing here
Index: clang/lib/AST/TextNodeDumper.cpp
===================================================================
--- clang/lib/AST/TextNodeDumper.cpp
+++ clang/lib/AST/TextNodeDumper.cpp
@@ -1798,6 +1798,8 @@
     case VarDecl::ListInit:
       OS << " listinit";
       break;
+    case VarDecl::ParenListInit:
+      OS << " parenlistinit";
     }
   }
   if (D->needsDestruction(D->getASTContext()))
Index: clang/lib/AST/StmtProfile.cpp
===================================================================
--- clang/lib/AST/StmtProfile.cpp
+++ clang/lib/AST/StmtProfile.cpp
@@ -2181,6 +2181,10 @@
   ID.AddInteger(S->getOperator());
 }
 
+void StmtProfiler::VisitCXXParenListInitExpr(const CXXParenListInitExpr *S) {
+  VisitExpr(S);
+}
+
 void StmtProfiler::VisitCoroutineBodyStmt(const CoroutineBodyStmt *S) {
   VisitStmt(S);
 }
Index: clang/lib/AST/StmtPrinter.cpp
===================================================================
--- clang/lib/AST/StmtPrinter.cpp
+++ clang/lib/AST/StmtPrinter.cpp
@@ -2460,6 +2460,18 @@
   OS << ")";
 }
 
+void StmtPrinter::VisitCXXParenListInitExpr(CXXParenListInitExpr *Node) {
+  OS << "(";
+  unsigned i = 0;
+  for (Expr *E : Node->getInitExprs()) {
+    if (i)
+      OS << ", ";
+    PrintExpr(E);
+    i++;
+  }
+  OS << ")";
+}
+
 void StmtPrinter::VisitConceptSpecializationExpr(ConceptSpecializationExpr *E) {
   NestedNameSpecifierLoc NNS = E->getNestedNameSpecifierLoc();
   if (NNS)
Index: clang/lib/AST/JSONNodeDumper.cpp
===================================================================
--- clang/lib/AST/JSONNodeDumper.cpp
+++ clang/lib/AST/JSONNodeDumper.cpp
@@ -843,6 +843,9 @@
     case VarDecl::CInit: JOS.attribute("init", "c");  break;
     case VarDecl::CallInit: JOS.attribute("init", "call"); break;
     case VarDecl::ListInit: JOS.attribute("init", "list"); break;
+    case VarDecl::ParenListInit:
+      JOS.attribute("init", "paren-list");
+      break;
     }
   }
   attributeOnlyIfTrue("isParameterPack", VD->isParameterPack());
Index: clang/lib/AST/ItaniumMangle.cpp
===================================================================
--- clang/lib/AST/ItaniumMangle.cpp
+++ clang/lib/AST/ItaniumMangle.cpp
@@ -5132,6 +5132,9 @@
     Out << "E";
     break;
   }
+  case Expr::CXXParenListInitExprClass:
+    // FIXME: unimplemented
+    llvm_unreachable("unimplemented");
   }
 
   if (AsTemplateArg && !IsPrimaryExpr)
Index: clang/lib/AST/ExprConstant.cpp
===================================================================
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -9811,6 +9811,9 @@
     bool VisitCXXConstructExpr(const CXXConstructExpr *E, QualType T);
     bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E);
     bool VisitBinCmp(const BinaryOperator *E);
+    bool VisitCXXParenListInitExpr(const CXXParenListInitExpr *E);
+    bool VisitCXXParenListOrInitListExpr(const Expr *E,
+                                         ArrayRef<Expr *> InitExprs);
   };
 }
 
@@ -9929,7 +9932,11 @@
 bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
   if (E->isTransparent())
     return Visit(E->getInit(0));
+  return VisitCXXParenListOrInitListExpr(E, E->inits());
+}
 
+bool RecordExprEvaluator::VisitCXXParenListOrInitListExpr(
+    const Expr *E, ArrayRef<Expr *> InitExprs) {
   const RecordDecl *RD = E->getType()->castAs<RecordType>()->getDecl();
   if (RD->isInvalidDecl()) return false;
   const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
@@ -9941,7 +9948,24 @@
       CXXRD && CXXRD->getNumBases());
 
   if (RD->isUnion()) {
-    const FieldDecl *Field = E->getInitializedFieldInUnion();
+    const FieldDecl *Field;
+    if (isa<InitListExpr>(E)) {
+      Field = cast<InitListExpr>(E)->getInitializedFieldInUnion();
+    } else if (isa<CXXParenListInitExpr>(E)) {
+      assert(InitExprs.size() == 1 &&
+             "Number of expressions in C++ paren list is not 1");
+
+      for (const FieldDecl *FD : RD->fields()) {
+        if (!FD->isUnnamedBitfield()) {
+          Field = FD;
+          break;
+        }
+      }
+    } else {
+      llvm_unreachable(
+          "Expression is neither an init list nor a C++ paren list");
+    }
+
     Result = APValue(Field);
     if (!Field)
       return true;
@@ -9952,7 +9976,7 @@
     //        Is this difference ever observable for initializer lists which
     //        we don't build?
     ImplicitValueInitExpr VIE(Field->getType());
-    const Expr *InitExpr = E->getNumInits() ? E->getInit(0) : &VIE;
+    const Expr *InitExpr = InitExprs.size() ? InitExprs[0] : &VIE;
 
     LValue Subobject = This;
     if (!HandleLValueMember(Info, InitExpr, Subobject, Field, &Layout))
@@ -9981,8 +10005,8 @@
   // Initialize base classes.
   if (CXXRD && CXXRD->getNumBases()) {
     for (const auto &Base : CXXRD->bases()) {
-      assert(ElementNo < E->getNumInits() && "missing init for base class");
-      const Expr *Init = E->getInit(ElementNo);
+      assert(ElementNo < InitExprs.size() && "missing init for base class");
+      const Expr *Init = InitExprs[ElementNo];
 
       LValue Subobject = This;
       if (!HandleLValueBase(Info, Init, Subobject, CXXRD, &Base))
@@ -10009,18 +10033,18 @@
 
     LValue Subobject = This;
 
-    bool HaveInit = ElementNo < E->getNumInits();
+    bool HaveInit = ElementNo < InitExprs.size();
 
     // FIXME: Diagnostics here should point to the end of the initializer
     // list, not the start.
-    if (!HandleLValueMember(Info, HaveInit ? E->getInit(ElementNo) : E,
+    if (!HandleLValueMember(Info, HaveInit ? InitExprs[ElementNo] : E,
                             Subobject, Field, &Layout))
       return false;
 
     // Perform an implicit value-initialization for members beyond the end of
     // the initializer list.
     ImplicitValueInitExpr VIE(HaveInit ? Info.Ctx.IntTy : Field->getType());
-    const Expr *Init = HaveInit ? E->getInit(ElementNo++) : &VIE;
+    const Expr *Init = HaveInit ? InitExprs[ElementNo++] : &VIE;
 
     if (Field->getType()->isIncompleteArrayType()) {
       if (auto *CAT = Info.Ctx.getAsConstantArrayType(Init->getType())) {
@@ -10654,6 +10678,7 @@
       expandStringLiteral(Info, E, Result, AllocType);
       return true;
     }
+    bool VisitCXXParenListInitExpr(const CXXParenListInitExpr *E);
   };
 } // end anonymous namespace
 
@@ -10899,6 +10924,26 @@
              .VisitCXXConstructExpr(E, Type);
 }
 
+bool ArrayExprEvaluator::VisitCXXParenListInitExpr(
+    const CXXParenListInitExpr *E) {
+  const auto *CAT = dyn_cast<ConstantArrayType>(E->getType());
+  assert(CAT && "Expression result is not a constant array type");
+
+  const ArrayRef<Expr *> InitExprs = E->getInitExprs();
+  unsigned NumElts = InitExprs.size();
+  Result = APValue(APValue::UninitArray(), NumElts, NumElts);
+
+  LValue Subobject = This;
+  Subobject.addArray(Info, E, CAT);
+
+  for (unsigned Index = 0; Index < NumElts; Index++)
+    if (!EvaluateInPlace(Result.getArrayInitializedElt(Index), Info, Subobject,
+                         InitExprs[Index]))
+      return false;
+
+  return true;
+}
+
 //===----------------------------------------------------------------------===//
 // Integer Evaluation
 //
@@ -13120,6 +13165,11 @@
   });
 }
 
+bool RecordExprEvaluator::VisitCXXParenListInitExpr(
+    const CXXParenListInitExpr *E) {
+  return VisitCXXParenListOrInitListExpr(E, E->getInitExprs());
+}
+
 bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
   // We don't support assignment in C. C++ assignments don't get here because
   // assignment is an lvalue in C++.
@@ -15532,6 +15582,7 @@
   case Expr::DependentCoawaitExprClass:
   case Expr::CoyieldExprClass:
   case Expr::SYCLUniqueStableNameExprClass:
+  case Expr::CXXParenListInitExprClass:
     return ICEDiag(IK_NotICE, E->getBeginLoc());
 
   case Expr::InitListExprClass: {
Index: clang/lib/AST/ExprClassification.cpp
===================================================================
--- clang/lib/AST/ExprClassification.cpp
+++ clang/lib/AST/ExprClassification.cpp
@@ -442,6 +442,11 @@
   case Expr::SYCLUniqueStableNameExprClass:
     return Cl::CL_PRValue;
     break;
+
+  case Expr::CXXParenListInitExprClass:
+    if (isa<ArrayType>(E->getType()))
+      return Cl::CL_ArrayTemporary;
+    return Cl::CL_ClassTemporary;
   }
 
   llvm_unreachable("unhandled expression kind in classification");
Index: clang/lib/AST/ExprCXX.cpp
===================================================================
--- clang/lib/AST/ExprCXX.cpp
+++ clang/lib/AST/ExprCXX.cpp
@@ -1746,3 +1746,11 @@
                            alignof(CUDAKernelCallExpr));
   return new (Mem) CUDAKernelCallExpr(NumArgs, HasFPFeatures, Empty);
 }
+
+CXXParenListInitExpr *CXXParenListInitExpr::Create(ASTContext &C,
+                                                   ArrayRef<Expr *> Args,
+                                                   QualType T,
+                                                   SourceLocation Loc) {
+  void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(Args.size()));
+  return new (Mem) CXXParenListInitExpr(Args, T, Loc);
+}
Index: clang/lib/AST/Expr.cpp
===================================================================
--- clang/lib/AST/Expr.cpp
+++ clang/lib/AST/Expr.cpp
@@ -3635,6 +3635,7 @@
   case ShuffleVectorExprClass:
   case ConvertVectorExprClass:
   case AsTypeExprClass:
+  case CXXParenListInitExprClass:
     // These have a side-effect if any subexpression does.
     break;
 
Index: clang/include/clang/Serialization/ASTBitCodes.h
===================================================================
--- clang/include/clang/Serialization/ASTBitCodes.h
+++ clang/include/clang/Serialization/ASTBitCodes.h
@@ -1852,6 +1852,9 @@
   /// A CXXBoolLiteralExpr record.
   EXPR_CXX_BOOL_LITERAL,
 
+  /// A CXXParenListInitExpr record.
+  EXPR_CXX_PAREN_LIST_INIT,
+
   EXPR_CXX_NULL_PTR_LITERAL, // CXXNullPtrLiteralExpr
   EXPR_CXX_TYPEID_EXPR,      // CXXTypeidExpr (of expr).
   EXPR_CXX_TYPEID_TYPE,      // CXXTypeidExpr (of type).
Index: clang/include/clang/Sema/Initialization.h
===================================================================
--- clang/include/clang/Sema/Initialization.h
+++ clang/include/clang/Sema/Initialization.h
@@ -923,7 +923,11 @@
     SK_OCLSamplerInit,
 
     /// Initialize an opaque OpenCL type (event_t, queue_t, etc.) with zero
-    SK_OCLZeroOpaqueType
+    SK_OCLZeroOpaqueType,
+
+    /// Initialize an aggreagate with parenthesized list of values.
+    /// This is a C++20 feature.
+    SK_ParenthesizedListInit
   };
 
   /// A single step in the initialization sequence.
@@ -1099,6 +1103,10 @@
 
     /// List-copy-initialization chose an explicit constructor.
     FK_ExplicitConstructor,
+
+    /// Parenthesized list initialization failed at some point.
+    /// This is a C++20 feature.
+    FK_ParenthesizedListInitFailed,
   };
 
 private:
@@ -1357,6 +1365,8 @@
   /// from a zero constant.
   void AddOCLZeroOpaqueTypeStep(QualType T);
 
+  void AddParenthesizedListInitStep(QualType T);
+
   /// Add steps to unwrap a initializer list for a reference around a
   /// single element and rewrap it at the end.
   void RewrapReferenceInitList(QualType T, InitListExpr *Syntactic);
Index: clang/include/clang/Basic/StmtNodes.td
===================================================================
--- clang/include/clang/Basic/StmtNodes.td
+++ clang/include/clang/Basic/StmtNodes.td
@@ -160,6 +160,7 @@
 def MaterializeTemporaryExpr : StmtNode<Expr>;
 def LambdaExpr : StmtNode<Expr>;
 def CXXFoldExpr : StmtNode<Expr>;
+def CXXParenListInitExpr: StmtNode<Expr>;
 
 // C++ Coroutines TS expressions
 def CoroutineSuspendExpr : StmtNode<Expr, 1>;
Index: clang/include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- clang/include/clang/AST/RecursiveASTVisitor.h
+++ clang/include/clang/AST/RecursiveASTVisitor.h
@@ -2850,6 +2850,7 @@
 DEF_TRAVERSE_STMT(FunctionParmPackExpr, {})
 DEF_TRAVERSE_STMT(CXXFoldExpr, {})
 DEF_TRAVERSE_STMT(AtomicExpr, {})
+DEF_TRAVERSE_STMT(CXXParenListInitExpr, {})
 
 DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, {
   if (S->getLifetimeExtendedTemporaryDecl()) {
Index: clang/include/clang/AST/ExprCXX.h
===================================================================
--- clang/include/clang/AST/ExprCXX.h
+++ clang/include/clang/AST/ExprCXX.h
@@ -4685,6 +4685,95 @@
   }
 };
 
+/// Represents a list-initialization with parenthesis.
+///
+/// As per P0960R3, this is a C++20 feature that allows aggregate to
+/// be initialized with a parenthesized list of values:
+/// ```
+/// struct A {
+///   int a;
+///   double b;
+/// };
+///
+/// void foo() {
+///   A a1(0);        // legal in C++20
+///   A a2(1.5, 1.0); // legal in C++20
+/// }
+/// ```
+/// It has some sort of similiarity to braced
+/// list-initialization, with some differences such as
+/// it allows narrowing conversion whilst braced
+/// list-initialization doesn't.
+/// ```
+/// struct A {
+///   char a;
+/// };
+/// void foo() {
+///   A a(1.5); // legal in C++20
+///   A b{1.5}; // illegal !
+/// }
+/// ```
+class CXXParenListInitExpr final
+    : public Expr,
+      private llvm::TrailingObjects<CXXParenListInitExpr, Expr *> {
+  friend class TrailingObjects;
+  friend class ASTStmtReader;
+  friend class ASTStmtWriter;
+
+  unsigned NumExprs;
+  SourceLocation Loc;
+
+  CXXParenListInitExpr(ArrayRef<Expr *> Args, QualType T, SourceLocation Loc)
+      : Expr(CXXParenListInitExprClass, T,
+             T->isLValueReferenceType()   ? VK_LValue
+             : T->isRValueReferenceType() ? VK_XValue
+                                          : VK_PRValue,
+             OK_Ordinary),
+        NumExprs(Args.size()), Loc(Loc) {
+    std::copy(Args.begin(), Args.end(), getTrailingObjects<Expr *>());
+  }
+
+  size_t numTrailingObjects(OverloadToken<Expr *>) const { return NumExprs; }
+
+public:
+  static CXXParenListInitExpr *Create(ASTContext &C, ArrayRef<Expr *> Args,
+                                      QualType T, SourceLocation Loc);
+
+  explicit CXXParenListInitExpr(EmptyShell Empty)
+      : Expr(CXXParenListInitExprClass, Empty) {}
+
+  ArrayRef<Expr *> getInitExprs() {
+    return {getTrailingObjects<Expr *>(), NumExprs};
+  }
+
+  const ArrayRef<Expr *> getInitExprs() const {
+    return {getTrailingObjects<Expr *>(), NumExprs};
+  }
+
+  SourceLocation getBeginLoc() const LLVM_READONLY { return Loc; }
+
+  SourceLocation getEndLoc() const LLVM_READONLY { return Loc; }
+
+  SourceRange getSourceRange() const LLVM_READONLY {
+    return SourceRange(getBeginLoc(), getEndLoc());
+  }
+
+  child_range children() {
+    Stmt **Begin = reinterpret_cast<Stmt **>(getTrailingObjects<Expr *>());
+    return child_range(Begin, Begin + NumExprs);
+  }
+
+  const_child_range children() const {
+    Stmt *const *Begin =
+        reinterpret_cast<Stmt *const *>(getTrailingObjects<Expr *>());
+    return const_child_range(Begin, Begin + NumExprs);
+  }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == CXXParenListInitExprClass;
+  }
+};
+
 /// Represents an expression that might suspend coroutine execution;
 /// either a co_await or co_yield expression.
 ///
Index: clang/include/clang/AST/Decl.h
===================================================================
--- clang/include/clang/AST/Decl.h
+++ clang/include/clang/AST/Decl.h
@@ -887,7 +887,10 @@
     CallInit,
 
     /// Direct list-initialization (C++11)
-    ListInit
+    ListInit,
+
+    /// Parenthesized list-initialization (C++20)
+    ParenListInit
   };
 
   /// Kinds of thread-local storage.
Index: clang/include/clang-c/Index.h
===================================================================
--- clang/include/clang-c/Index.h
+++ clang/include/clang-c/Index.h
@@ -1531,7 +1531,14 @@
    */
   CXCursor_RequiresExpr = 154,
 
-  CXCursor_LastExpr = CXCursor_RequiresExpr,
+  /**
+   * Expression that references a C++20 parenthesized list aggregate
+   * initializer.
+   *
+   */
+  CXCursor_CXXParenListInitExpr = 155,
+
+  CXCursor_LastExpr = CXCursor_CXXParenListInitExpr,
 
   /* Statements */
   CXCursor_FirstStmt = 200,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to