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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits