aaron.ballman updated this revision to Diff 510213. aaron.ballman added a comment.
Fixed some test failures found by precommit CI. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D147349/new/ https://reviews.llvm.org/D147349 Files: clang/docs/ReleaseNotes.rst clang/include/clang/Basic/DiagnosticCommonKinds.td clang/include/clang/Basic/DiagnosticGroups.td clang/include/clang/Basic/DiagnosticParseKinds.td clang/lib/CodeGen/CGExprAgg.cpp clang/lib/Parse/ParseInit.cpp clang/lib/Sema/SemaExpr.cpp clang/lib/Sema/SemaInit.cpp clang/test/C/C2x/n2900_n3011.c clang/test/C/C2x/n2900_n3011_2.c clang/test/Sema/array-init.c clang/test/Sema/complex-init-list.c clang/test/Sema/compound-literal.c clang/test/Sema/flexible-array-init.c clang/test/Sema/gnu-flags.c clang/test/Sema/sizeless-1.c clang/test/Sema/vla.c clang/test/SemaObjC/property.m clang/test/SemaOpenCL/intel-subgroup-avc-ext-types.cl clang/www/c_status.html
Index: clang/www/c_status.html =================================================================== --- clang/www/c_status.html +++ clang/www/c_status.html @@ -1083,11 +1083,11 @@ </tr> <tr> <!-- Feb 2022 --> <td><a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2900.htm">N2900</a></td> - <td class="unknown" align="center">Unknown</td> + <td class="unreleased" align="center">Clang 17</td> </tr> <tr> <!-- Jul 2022 --> <td><a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3011.htm">N3011</a></td> - <td class="unknown" align="center">Unknown</td> + <td class="unreleased" align="center">Clang 17</td> </tr> <tr id="typeof"> <td rowspan="3">Not-so-magic: typeof</td> Index: clang/test/SemaOpenCL/intel-subgroup-avc-ext-types.cl =================================================================== --- clang/test/SemaOpenCL/intel-subgroup-avc-ext-types.cl +++ clang/test/SemaOpenCL/intel-subgroup-avc-ext-types.cl @@ -28,37 +28,34 @@ intel_sub_group_avc_sic_result_t result_sic = ss; intel_sub_group_avc_ime_result_single_reference_streamout_t sstreamout = v; intel_sub_group_avc_ime_result_dual_reference_streamout_t dstreamin_list = {0x0, 0x1}; - intel_sub_group_avc_ime_dual_reference_streamin_t dstreamin_list2 = {}; intel_sub_group_avc_ime_single_reference_streamin_t dstreamin_list3 = {c}; intel_sub_group_avc_ime_dual_reference_streamin_t dstreamin_list4 = {1}; #ifdef EXT -// expected-error@-14 {{initializing '__private intel_sub_group_avc_mce_payload_t' with an expression of incompatible type 'int'}} -// expected-error@-14 {{initializing '__private intel_sub_group_avc_ime_payload_t' with an expression of incompatible type 'int'}} -// expected-error@-14 {{initializing '__private intel_sub_group_avc_ref_payload_t' with an expression of incompatible type '__private float'}} -// expected-error@-14 {{initializing '__private intel_sub_group_avc_sic_payload_t' with an expression of incompatible type '__private struct st'}} -// expected-error@-14 {{initializing '__private intel_sub_group_avc_mce_result_t' with an expression of incompatible type 'int'}} -// expected-error@-14 {{initializing '__private intel_sub_group_avc_ime_result_t' with an expression of incompatible type 'int'}} -// expected-error@-14 {{initializing '__private intel_sub_group_avc_ref_result_t' with an expression of incompatible type '__private float'}} -// expected-error@-14 {{initializing '__private intel_sub_group_avc_sic_result_t' with an expression of incompatible type '__private struct st'}} -// expected-error@-14 {{initializing '__private intel_sub_group_avc_ime_result_single_reference_streamout_t' with an expression of incompatible type '__private void *__private'}} -// expected-warning@-14 {{excess elements in struct initializer}} -// expected-error@-14 {{scalar initializer cannot be empty}} -// expected-error@-14 {{initializing '__private intel_sub_group_avc_ime_single_reference_streamin_t' with an expression of incompatible type '__private char'}} -// expected-error@-14 {{initializing '__private intel_sub_group_avc_ime_dual_reference_streamin_t' with an expression of incompatible type 'int'}} +// expected-error@-13 {{initializing '__private intel_sub_group_avc_mce_payload_t' with an expression of incompatible type 'int'}} +// expected-error@-13 {{initializing '__private intel_sub_group_avc_ime_payload_t' with an expression of incompatible type 'int'}} +// expected-error@-13 {{initializing '__private intel_sub_group_avc_ref_payload_t' with an expression of incompatible type '__private float'}} +// expected-error@-13 {{initializing '__private intel_sub_group_avc_sic_payload_t' with an expression of incompatible type '__private struct st'}} +// expected-error@-13 {{initializing '__private intel_sub_group_avc_mce_result_t' with an expression of incompatible type 'int'}} +// expected-error@-13 {{initializing '__private intel_sub_group_avc_ime_result_t' with an expression of incompatible type 'int'}} +// expected-error@-13 {{initializing '__private intel_sub_group_avc_ref_result_t' with an expression of incompatible type '__private float'}} +// expected-error@-13 {{initializing '__private intel_sub_group_avc_sic_result_t' with an expression of incompatible type '__private struct st'}} +// expected-error@-13 {{initializing '__private intel_sub_group_avc_ime_result_single_reference_streamout_t' with an expression of incompatible type '__private void *__private'}} +// expected-warning@-13 {{excess elements in struct initializer}} +// expected-error@-13 {{initializing '__private intel_sub_group_avc_ime_single_reference_streamin_t' with an expression of incompatible type '__private char'}} +// expected-error@-13 {{initializing '__private intel_sub_group_avc_ime_dual_reference_streamin_t' with an expression of incompatible type 'int'}} #else -// expected-error@-28 {{use of undeclared identifier 'intel_sub_group_avc_mce_payload_t'}} -// expected-error@-28 {{use of undeclared identifier 'intel_sub_group_avc_ime_payload_t'}} -// expected-error@-28 {{use of undeclared identifier 'intel_sub_group_avc_ref_payload_t'}} -// expected-error@-28 {{use of undeclared identifier 'intel_sub_group_avc_sic_payload_t'}} -// expected-error@-28 {{use of undeclared identifier 'intel_sub_group_avc_mce_result_t'}} -// expected-error@-28 {{use of undeclared identifier 'intel_sub_group_avc_ime_result_t'}} -// expected-error@-28 {{use of undeclared identifier 'intel_sub_group_avc_ref_result_t'}} -// expected-error@-28 {{use of undeclared identifier 'intel_sub_group_avc_sic_result_t'}} -// expected-error@-28 {{use of undeclared identifier 'intel_sub_group_avc_ime_result_single_reference_streamout_t'}} -// expected-error@-28 {{use of undeclared identifier 'intel_sub_group_avc_ime_result_dual_reference_streamout_t'}} -// expected-error@-28 {{use of undeclared identifier 'intel_sub_group_avc_ime_dual_reference_streamin_t'}} -// expected-error@-28 {{use of undeclared identifier 'intel_sub_group_avc_ime_single_reference_streamin_t'}} -// expected-error@-28 {{use of undeclared identifier 'intel_sub_group_avc_ime_dual_reference_streamin_t'}} +// expected-error@-26 {{use of undeclared identifier 'intel_sub_group_avc_mce_payload_t'}} +// expected-error@-26 {{use of undeclared identifier 'intel_sub_group_avc_ime_payload_t'}} +// expected-error@-26 {{use of undeclared identifier 'intel_sub_group_avc_ref_payload_t'}} +// expected-error@-26 {{use of undeclared identifier 'intel_sub_group_avc_sic_payload_t'}} +// expected-error@-26 {{use of undeclared identifier 'intel_sub_group_avc_mce_result_t'}} +// expected-error@-26 {{use of undeclared identifier 'intel_sub_group_avc_ime_result_t'}} +// expected-error@-26 {{use of undeclared identifier 'intel_sub_group_avc_ref_result_t'}} +// expected-error@-26 {{use of undeclared identifier 'intel_sub_group_avc_sic_result_t'}} +// expected-error@-26 {{use of undeclared identifier 'intel_sub_group_avc_ime_result_single_reference_streamout_t'}} +// expected-error@-26 {{use of undeclared identifier 'intel_sub_group_avc_ime_result_dual_reference_streamout_t'}} +// expected-error@-26 {{use of undeclared identifier 'intel_sub_group_avc_ime_single_reference_streamin_t'}} +// expected-error@-26 {{use of undeclared identifier 'intel_sub_group_avc_ime_dual_reference_streamin_t'}} #endif } Index: clang/test/SemaObjC/property.m =================================================================== --- clang/test/SemaObjC/property.m +++ clang/test/SemaObjC/property.m @@ -78,5 +78,5 @@ @property unsigned length; @end void test7(Test7 *t) { - char data[t.length] = {}; // expected-error {{variable-sized object may not be initialized}} + char data[t.length] = {}; } Index: clang/test/Sema/vla.c =================================================================== --- clang/test/Sema/vla.c +++ clang/test/Sema/vla.c @@ -113,14 +113,14 @@ jump_over_a2:; goto jump_over_a3; - char a3[ksize] = {}; // expected-warning {{variable length array folded to constant array as an extension}} expected-warning{{use of GNU empty initializer}} + char a3[ksize] = {}; // expected-warning {{variable length array folded to constant array as an extension}} expected-warning{{use of an empty initializer is a C2x extension}} jump_over_a3:; goto jump_over_a4; // expected-error{{cannot jump from this goto statement to its label}} char a4[ksize][2]; // expected-note{{variable length array}} jump_over_a4:; - char a5[ksize][2] = {}; // expected-warning {{variable length array folded to constant array as an extension}} expected-warning{{use of GNU empty initializer}} + char a5[ksize][2] = {}; // expected-warning {{variable length array folded to constant array as an extension}} expected-warning{{use of an empty initializer is a C2x extension}} int a6[ksize] = {1,2,3,4}; // expected-warning{{variable length array folded to constant array as an extension}} Index: clang/test/Sema/sizeless-1.c =================================================================== --- clang/test/Sema/sizeless-1.c +++ clang/test/Sema/sizeless-1.c @@ -83,8 +83,8 @@ svint8_t init_int8 = local_int8; svint8_t bad_init_int8 = for; // expected-error {{expected expression}} - int empty_brace_init_int = {}; // expected-error {{scalar initializer cannot be empty}} - svint8_t empty_brace_init_int8 = {}; // expected-error {{initializer for sizeless type 'svint8_t' (aka '__SVInt8_t') cannot be empty}} + int empty_brace_init_int = {}; + svint8_t empty_brace_init_int8 = {}; svint8_t brace_init_int8 = {local_int8}; svint8_t bad_brace_init_int8_1 = {local_int8, 0}; // expected-warning {{excess elements in initializer for indivisible sizeless type 'svint8_t'}} svint8_t bad_brace_init_int8_2 = {0}; // expected-error {{incompatible type 'int'}} Index: clang/test/Sema/gnu-flags.c =================================================================== --- clang/test/Sema/gnu-flags.c +++ clang/test/Sema/gnu-flags.c @@ -2,13 +2,13 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -DALL -Wgnu // RUN: %clang_cc1 -fsyntax-only -verify %s -DALL -Wno-gnu \ // RUN: -Wgnu-alignof-expression -Wgnu-case-range -Wgnu-complex-integer -Wgnu-conditional-omitted-operand \ -// RUN: -Wgnu-empty-initializer -Wgnu-label-as-value -Wgnu-statement-expression \ +// RUN: -Wgnu-label-as-value -Wgnu-statement-expression \ // RUN: -Wgnu-compound-literal-initializer -Wgnu-flexible-array-initializer \ // RUN: -Wgnu-redeclared-enum -Wgnu-folding-constant -Wgnu-empty-struct \ // RUN: -Wgnu-union-cast -Wgnu-variable-sized-type-not-at-end // RUN: %clang_cc1 -fsyntax-only -verify %s -DNONE -Wgnu \ // RUN: -Wno-gnu-alignof-expression -Wno-gnu-case-range -Wno-gnu-complex-integer -Wno-gnu-conditional-omitted-operand \ -// RUN: -Wno-gnu-empty-initializer -Wno-gnu-label-as-value -Wno-gnu-statement-expression \ +// RUN: -Wno-gnu-label-as-value -Wno-gnu-statement-expression \ // RUN: -Wno-gnu-compound-literal-initializer -Wno-gnu-flexible-array-initializer \ // RUN: -Wno-gnu-redeclared-enum -Wno-gnu-folding-constant -Wno-gnu-empty-struct \ // RUN: -Wno-gnu-union-cast -Wno-gnu-variable-sized-type-not-at-end @@ -17,7 +17,6 @@ // %clang_cc1 -fsyntax-only -verify %s -DCASERANGE -Wno-gnu -Wgnu-case-range // %clang_cc1 -fsyntax-only -verify %s -DCOMPLEXINT -Wno-gnu -Wgnu-complex-integer // %clang_cc1 -fsyntax-only -verify %s -DOMITTEDOPERAND -Wno-gnu -Wgnu-conditional-omitted-operand -// %clang_cc1 -fsyntax-only -verify %s -DEMPTYINIT -Wno-gnu -Wgnu-empty-initializer // %clang_cc1 -fsyntax-only -verify %s -DLABELVALUE -Wno-gnu -Wgnu-label-as-value // %clang_cc1 -fsyntax-only -verify %s -DSTATEMENTEXP -Wno-gnu -Wgnu-statement-expression // %clang_cc1 -fsyntax-only -verify %s -DSTATEMENTEXPMACRO -Wno-gnu -Wgnu-statement-expression-from-macro-expansion @@ -67,13 +66,6 @@ static const char* omittedoperand = (const char*)0 ?: "Null"; -#if ALL || EMPTYINIT -// expected-warning@+3 {{use of GNU empty initializer extension}} -#endif - -struct { int x; } emptyinit = {}; - - #if ALL || LABELVALUE // expected-warning@+6 {{use of GNU address-of-label extension}} // expected-warning@+7 {{use of GNU indirect-goto extension}} Index: clang/test/Sema/flexible-array-init.c =================================================================== --- clang/test/Sema/flexible-array-init.c +++ clang/test/Sema/flexible-array-init.c @@ -10,7 +10,7 @@ struct one x3 = {5, {1, 2, 3}}; // expected-error{{initialization of flexible array member is not allowed}} struct one x3a = { 5 }; struct one x3b = { .a = 5 }; - struct one x3c = { 5, {} }; // expected-warning{{use of GNU empty initializer extension}} \ + struct one x3c = { 5, {} }; // expected-warning{{use of an empty initializer is a C2x extension}} \ // expected-warning{{flexible array initialization is a GNU extension}} \ // expected-warning{{zero size arrays are an extension}} } @@ -24,13 +24,13 @@ struct foo a = { 1, { 2, 3, 4 } }; // expected-warning{{flexible array initialization is a GNU extension}} struct bar b = { { 1, { 2, 3, 4 } } }; // expected-error{{initialization of flexible array member is not allowed}} struct bar c = { { 1, { } } }; // // expected-warning{{flexible array initialization is a GNU extension}} \ - // expected-warning{{use of GNU empty initializer extension}} \ + // expected-warning{{use of an empty initializer is a C2x extension}} \ // expected-warning{{zero size arrays are an extension}} struct foo d[1] = { { 1, { 2, 3, 4 } } }; // expected-warning{{'struct foo' may not be used as an array element due to flexible array member}} \ // expected-error{{initialization of flexible array member is not allowed}} struct foo desig_foo = { .y = {2, 3, 4} }; // expected-warning{{flexible array initialization is a GNU extension}} -struct bar desig_bar = { .z.y = { } }; // expected-warning{{use of GNU empty initializer extension}} \ +struct bar desig_bar = { .z.y = { } }; // expected-warning{{use of an empty initializer is a C2x extension}} \ // expected-warning{{zero size arrays are an extension}} \ // expected-warning{{flexible array initialization is a GNU extension}} struct bar desig_bar2 = { .z.y = { 2, 3, 4} }; // expected-error{{initialization of flexible array member is not allowed}} Index: clang/test/Sema/compound-literal.c =================================================================== --- clang/test/Sema/compound-literal.c +++ clang/test/Sema/compound-literal.c @@ -14,7 +14,7 @@ static long *p3 = (long []){2,"x"}; // expected-error {{incompatible pointer to integer conversion initializing 'long' with an expression of type 'char[2]'}} typedef struct { } cache_t; // expected-warning{{empty struct is a GNU extension}} -static cache_t clo_I1_cache = ((cache_t) { } ); // expected-warning{{use of GNU empty initializer extension}} +static cache_t clo_I1_cache = ((cache_t) { } ); // expected-warning{{use of an empty initializer is a C2x extension}} typedef struct Test {int a;int b;} Test; static Test* ll = &(Test) {0,0}; Index: clang/test/Sema/complex-init-list.c =================================================================== --- clang/test/Sema/complex-init-list.c +++ clang/test/Sema/complex-init-list.c @@ -38,8 +38,7 @@ struct teststruct invalid1 = { 1, 2 }; // expected-warning {{excess elements}} _Complex float invalid2 = { 1, 2, 3 }; // expected-warning {{specifying real and imaginary components is an extension}} \ // expected-warning {{excess elements in scalar initializer}} -_Complex float invalid3 = {}; // expected-error {{scalar initializer cannot be empty}} \ - // expected-warning {{GNU empty initializer}} +_Complex float invalid3 = {}; // expected-warning {{use of an empty initializer is a C2x extension}} // Check incomplete array sizing Index: clang/test/Sema/array-init.c =================================================================== --- clang/test/Sema/array-init.c +++ clang/test/Sema/array-init.c @@ -64,7 +64,7 @@ { 2, 4, 6 }, { 3, 5, 7 }, { 4, 6, 8 }, - { }, // expected-warning{{use of GNU empty initializer extension}} expected-warning{{excess elements in array initializer}} + { }, // expected-warning{{use of an empty initializer is a C2x extension}} expected-warning{{excess elements in array initializer}} }; int y4[4][3] = { { 1, 3, 5, 2 }, // expected-warning{{excess elements in array initializer}} @@ -175,7 +175,7 @@ char c3[5] = { "Hello" }; char c4[4] = { "Hello" }; //expected-warning{{initializer-string for char array is too long}} - int i3[] = {}; //expected-warning{{zero size arrays are an extension}} expected-warning{{use of GNU empty initializer extension}} + int i3[] = {}; //expected-warning{{zero size arrays are an extension}} expected-warning{{use of an empty initializer is a C2x extension}} } void variableArrayInit(void) { @@ -197,7 +197,7 @@ char r8[5] = "5char"; char r9[5] = "6chars"; //expected-warning{{initializer-string for char array is too long}} unsigned char r10[] = __extension__ (_Generic(0, int: (__extension__ "foo" ))); -int r11[0] = {}; //expected-warning{{zero size arrays are an extension}} expected-warning{{use of GNU empty initializer extension}} +int r11[0] = {}; //expected-warning{{zero size arrays are an extension}} expected-warning{{use of an empty initializer is a C2x extension}} // Some struct tests void autoStructTest(void) { @@ -221,8 +221,7 @@ struct bittest{int : 31, a, :21, :12, b;}; struct bittest bittestvar = {1, 2, 3, 4}; //expected-warning{{excess elements in struct initializer}} -// Not completely sure what should happen here... -int u1 = {}; //expected-warning{{use of GNU empty initializer extension}} expected-error{{scalar initializer cannot be empty}} +int u1 = {}; //expected-warning{{use of an empty initializer is a C2x extension}} int u2 = {{3}}; //expected-warning{{too many braces around scalar initializer}} // PR2362 Index: clang/test/C/C2x/n2900_n3011_2.c =================================================================== --- /dev/null +++ clang/test/C/C2x/n2900_n3011_2.c @@ -0,0 +1,108 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -std=c2x -verify -emit-llvm %s -o - | FileCheck %s +// expected-no-diagnostics + +struct S { int x, y; }; +struct T { + int i; + struct S s; +}; + +// CHECK: @[[CONST_T1:.+]] = private unnamed_addr constant %struct.T { i32 1, %struct.S zeroinitializer } +// CHECK: @[[CONST_T2:.+]] = private unnamed_addr constant %struct.T { i32 1, %struct.S { i32 2, i32 0 } } + +void test_struct() { + struct S s = {}; + // CHECK: define {{.*}} void @test_struct + // CHECK-NEXT: entry: + // CHECK-NEXT: %[[S:.+]] = alloca %struct.S + // CHECK-NEXT: call void @llvm.memset.p0.i64({{.*}}%[[S]], i8 0, i64 8, i1 false) +} + +void test_var() { + int i = {}; + // CHECK: define {{.*}} void @test_var + // CHECK-NEXT: entry: + // CHECK-NEXT: %[[I:.+]] = alloca i32 + // CHECK-NEXT: store i32 0, ptr %[[I]] +} + +void test_simple_compound_literal() { + int j = (int){}; + // CHECK: define {{.*}} void @test_simple_compound_literal + // CHECK-NEXT: entry: + // CHECK-NEXT: %[[J:.+]] = alloca i32 + // CHECK-NEXT: %[[COMPOUND:.+]] = alloca i32 + // CHECK-NEXT: store i32 0, ptr %[[COMPOUND]] + // CHECK-NEXT: %[[MEM:.+]] = load i32, ptr %[[COMPOUND]] + // CHECK-NEXT: store i32 %[[MEM]], ptr %[[J]] +} + +void test_zero_size_array() { + int unknown_size[] = {}; + // CHECK: define {{.*}} void @test_zero_size_array + // CHECK-NEXT: entry: + // CHECK-NEXT: %[[UNKNOWN:.+]] = alloca [0 x i32] +} + +void test_vla() { + int i = 12; + int vla[i] = {}; + // CHECK: define {{.*}} void @test_vla + // CHECK-NEXT: entry: + // CHECK-NEXT: %[[I:.+]] = alloca i32 + // CHECK: %[[VLA_EXPR:.+]] = alloca i64 + // CHECK-NEXT: store i32 12, ptr %[[I]] + // CHECK-NEXT: %[[MEM0:.+]] = load i32, ptr %[[I]] + // CHECK-NEXT: %[[MEM1:.+]] = zext i32 %[[MEM0]] to i64 + // CHECK: %[[VLA:.+]] = alloca i32, i64 %[[MEM1]] + // CHECK-NEXT: store i64 %[[MEM1]], ptr %[[VLA_EXPR]] + // CHECK-NEXT: %[[MEM3:.+]] = mul nuw i64 %[[MEM1]], 4 + // CHECK-NEXT: call void @llvm.memset.p0.i64(ptr {{.*}} %[[VLA]], i8 0, i64 %[[MEM3]], i1 false) +} + +void test_zero_size_vla() { + int i = 0; + int vla[i] = {}; + // CHECK: define {{.*}} void @test_zero_size_vla + // CHECK-NEXT: entry: + // CHECK-NEXT: %[[I:.+]] = alloca i32 + // CHECK: %[[VLA_EXPR:.+]] = alloca i64 + // CHECK-NEXT: store i32 0, ptr %[[I]] + // CHECK-NEXT: %[[MEM0:.+]] = load i32, ptr %[[I]] + // CHECK-NEXT: %[[MEM1:.+]] = zext i32 %[[MEM0]] to i64 + // CHECK: %[[VLA:.+]] = alloca i32, i64 %[[MEM1]] + // CHECK-NEXT: store i64 %[[MEM1]], ptr %[[VLA_EXPR]] + // CHECK-NEXT: %[[MEM3:.+]] = mul nuw i64 %[[MEM1]], 4 + // CHECK-NEXT: call void @llvm.memset.p0.i64(ptr {{.*}} %[[VLA]], i8 0, i64 %[[MEM3]], i1 false) +} + +void test_compound_literal_vla() { + int i = 12; + int *compound_literal_vla = (int[i]){}; + // CHECK: define {{.*}} void @test_compound_literal_vla + // CHECK-NEXT: entry: + // CHECK-NEXT: %[[I:.+]] = alloca i32 + // CHECK-NEXT: %[[COMP_LIT_VLA:.+]] = alloca ptr + // CHECK-NEXT: %[[COMP_LIT:.+]] = alloca i32 + // CHECK-NEXT: store i32 12, ptr %[[I]] + // CHECK-NEXT: %[[MEM0:.+]] = load i32, ptr %[[I]] + // CHECK-NEXT: %[[MEM1:.+]] = zext i32 %[[MEM0]] to i64 + // CHECK-NEXT: %[[MEM2:.+]] = mul nuw i64 %[[MEM1]], 4 + // CHECK-NEXT: call void @llvm.memset.p0.i64(ptr {{.*}} %[[COMP_LIT]], i8 0, i64 %[[MEM2]], i1 false) + // CHECK-NEXT: store ptr %[[COMP_LIT]], ptr %[[COMP_LIT_VLA]] +} + +void test_nested_structs() { + struct T t1 = { 1, {} }; + struct T t2 = { 1, { 2, {} } }; + struct T t3 = { (int){}, {} }; + // CHECK: define {{.*}} void @test_nested_structs + // CHECK-NEXT: entry: + // CHECK-NEXT: %[[T1:.+]] = alloca %struct.T + // CHECK-NEXT: %[[T2:.+]] = alloca %struct.T + // CHECK-NEXT: %[[T3:.+]] = alloca %struct.T + // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr {{.*}} %[[T1]], ptr {{.*}} @[[CONST_T1]], i64 12, i1 false) + // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr {{.*}} %[[T2]], ptr {{.*}} @[[CONST_T2]], i64 12, i1 false) + // CHECK-NEXT: call void @llvm.memset.p0.i64(ptr {{.*}} %[[T3]], i8 0, i64 12, i1 false) +} + Index: clang/test/C/C2x/n2900_n3011.c =================================================================== --- /dev/null +++ clang/test/C/C2x/n2900_n3011.c @@ -0,0 +1,53 @@ +// RUN: %clang_cc1 -std=c2x -fsyntax-only -Wpre-c2x-compat -verify=compat %s +// RUN: %clang_cc1 -std=c17 -fsyntax-only -pedantic -Wno-comment -verify=pedantic %s + +/* WG14 N2900: yes + * Consistent, Warningless, and Intuitive Initialization with {} + */ + +/* WG14 N3011: yes + * Consistent, Warningless, and Intuitive Initialization with {} + */ +void test(void) { + struct S { int x, y; } s = {}; // compat-warning {{use of an empty initializer is incompatible with C standards before C2x}} \ + pedantic-warning {{use of an empty initializer is a C2x extension}} + int i = {}; // compat-warning {{use of an empty initializer is incompatible with C standards before C2x}} \ + pedantic-warning {{use of an empty initializer is a C2x extension}} + int j = (int){}; // compat-warning {{use of an empty initializer is incompatible with C standards before C2x}} \ + pedantic-warning {{use of an empty initializer is a C2x extension}} + int unknown_size[] = {}; // pedantic-warning {{zero size arrays are an extension}} \ + pedantic-warning {{use of an empty initializer is a C2x extension}} \ + compat-warning {{use of an empty initializer is incompatible with C standards before C2x}} + int vla[i] = {}; // compat-warning {{use of an empty initializer is incompatible with C standards before C2x}} \ + pedantic-warning {{use of an empty initializer is a C2x extension}} + int *compound_literal_vla = (int[i]){}; // compat-warning {{use of an empty initializer is incompatible with C standards before C2x}} \ + pedantic-warning {{use of an empty initializer is a C2x extension}} + + struct T { + int i; + struct S s; + } t1 = { 1, {} }; // compat-warning {{use of an empty initializer is incompatible with C standards before C2x}} \ + pedantic-warning {{use of an empty initializer is a C2x extension}} + + struct T t2 = { + 1, { + 2, {} // compat-warning {{use of an empty initializer is incompatible with C standards before C2x}} \ + pedantic-warning {{use of an empty initializer is a C2x extension}} + } + }; + + struct T t3 = { + (int){}, // compat-warning {{use of an empty initializer is incompatible with C standards before C2x}} \ + pedantic-warning {{use of an empty initializer is a C2x extension}} + {} // compat-warning {{use of an empty initializer is incompatible with C standards before C2x}} \ + pedantic-warning {{use of an empty initializer is a C2x extension}} + }; + + // Ensure that zero initialization does what you'd expect in a constant expr. + // FIXME: the "not an ICE" warning is incorrect for C2x, but we don't yet + // implement WG14 N3038. + _Static_assert((int){} == 0, "what?"); // compat-warning {{use of an empty initializer is incompatible with C standards before C2x}} \ + pedantic-warning {{use of an empty initializer is a C2x extension}} \ + pedantic-warning {{expression is not an integer constant expression; folding it to a constant is a GNU extension}} +} + Index: clang/lib/Sema/SemaInit.cpp =================================================================== --- clang/lib/Sema/SemaInit.cpp +++ clang/lib/Sema/SemaInit.cpp @@ -1565,20 +1565,23 @@ unsigned &StructuredIndex) { if (Index >= IList->getNumInits()) { if (!VerifyOnly) { - if (DeclType->isSizelessBuiltinType()) - SemaRef.Diag(IList->getBeginLoc(), - SemaRef.getLangOpts().CPlusPlus11 - ? diag::warn_cxx98_compat_empty_sizeless_initializer - : diag::err_empty_sizeless_initializer) - << DeclType << IList->getSourceRange(); - else - SemaRef.Diag(IList->getBeginLoc(), - SemaRef.getLangOpts().CPlusPlus11 - ? diag::warn_cxx98_compat_empty_scalar_initializer - : diag::err_empty_scalar_initializer) - << IList->getSourceRange(); + if (SemaRef.getLangOpts().CPlusPlus) { + if (DeclType->isSizelessBuiltinType()) + SemaRef.Diag(IList->getBeginLoc(), + SemaRef.getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_empty_sizeless_initializer + : diag::err_empty_sizeless_initializer) + << DeclType << IList->getSourceRange(); + else + SemaRef.Diag(IList->getBeginLoc(), + SemaRef.getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_empty_scalar_initializer + : diag::err_empty_scalar_initializer) + << IList->getSourceRange(); + } } - hadError = !SemaRef.getLangOpts().CPlusPlus11; + hadError = + SemaRef.getLangOpts().CPlusPlus && !SemaRef.getLangOpts().CPlusPlus11; ++Index; ++StructuredIndex; return; @@ -1908,11 +1911,24 @@ // Check for VLAs; in standard C it would be possible to check this // earlier, but I don't know where clang accepts VLAs (gcc accepts // them in all sorts of strange places). - if (!VerifyOnly) - SemaRef.Diag(VAT->getSizeExpr()->getBeginLoc(), - diag::err_variable_object_no_init) - << VAT->getSizeExpr()->getSourceRange(); - hadError = true; + bool HasErr = IList->getNumInits() != 0 || SemaRef.getLangOpts().CPlusPlus; + if (!VerifyOnly) { + // C2x 6.7.9p4: An entity of variable length array type shall not be + // initialized except by an empty initializer. + // + // The C extension warnings are issued from ParseBraceInitializer() and + // do not need to be issued here. However, we continue to issue an error + // in the case there are initializers or we are compiling C++. We allow + // use of VLAs in C++, but it's not clear we want to allow {} to zero + // init a VLA in C++ in all cases (such as with non-trivial constructors). + // FIXME: should we allow this construct in C++ when it makes sense to do + // so? + if (HasErr) + SemaRef.Diag(VAT->getSizeExpr()->getBeginLoc(), + diag::err_variable_object_no_init) + << VAT->getSizeExpr()->getSourceRange(); + } + hadError = HasErr; ++Index; ++StructuredIndex; return; Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -7491,10 +7491,23 @@ SourceRange(LParenLoc, LiteralExpr->getSourceRange().getEnd()))) return ExprError(); if (literalType->isVariableArrayType()) { - if (!tryToFixVariablyModifiedVarType(TInfo, literalType, LParenLoc, - diag::err_variable_object_no_init)) { + // C2x 6.7.9p4: An entity of variable length array type shall not be + // initialized except by an empty initializer. + // + // The C extension warnings are issued from ParseBraceInitializer() and + // do not need to be issued here. However, we continue to issue an error + // in the case there are initializers or we are compiling C++. We allow + // use of VLAs in C++, but it's not clear we want to allow {} to zero + // init a VLA in C++ in all cases (such as with non-trivial constructors). + // FIXME: should we allow this construct in C++ when it makes sense to do + // so? + std::optional<unsigned> NumInits; + if (const auto *ILE = dyn_cast<InitListExpr>(LiteralExpr)) + NumInits = ILE->getNumInits(); + if ((LangOpts.CPlusPlus || NumInits.value_or(0)) && + !tryToFixVariablyModifiedVarType(TInfo, literalType, LParenLoc, + diag::err_variable_object_no_init)) return ExprError(); - } } } else if (!literalType->isDependentType() && RequireCompleteType(LParenLoc, literalType, Index: clang/lib/Parse/ParseInit.cpp =================================================================== --- clang/lib/Parse/ParseInit.cpp +++ clang/lib/Parse/ParseInit.cpp @@ -429,7 +429,7 @@ /// initializer: [C99 6.7.8] /// '{' initializer-list '}' /// '{' initializer-list ',' '}' -/// [GNU] '{' '}' +/// [C2x] '{' '}' /// /// initializer-list: /// designation[opt] initializer ...[opt] @@ -447,9 +447,12 @@ ExprVector InitExprs; if (Tok.is(tok::r_brace)) { - // Empty initializers are a C++ feature and a GNU extension to C. - if (!getLangOpts().CPlusPlus) - Diag(LBraceLoc, diag::ext_gnu_empty_initializer); + // Empty initializers are a C++ feature and a GNU extension to C before C2x. + if (!getLangOpts().CPlusPlus) { + Diag(LBraceLoc, getLangOpts().C2x + ? diag::warn_c2x_compat_empty_initializer + : diag::ext_c_empty_initializer); + } // Match the '}'. return Actions.ActOnInitList(LBraceLoc, std::nullopt, ConsumeBrace()); } Index: clang/lib/CodeGen/CGExprAgg.cpp =================================================================== --- clang/lib/CodeGen/CGExprAgg.cpp +++ clang/lib/CodeGen/CGExprAgg.cpp @@ -1658,11 +1658,17 @@ LValue DestLV = CGF.MakeAddrLValue(Dest.getAddress(), ExprToVisit->getType()); // Handle initialization of an array. - if (ExprToVisit->getType()->isArrayType()) { + if (ExprToVisit->getType()->isConstantArrayType()) { auto AType = cast<llvm::ArrayType>(Dest.getAddress().getElementType()); EmitArrayInit(Dest.getAddress(), AType, ExprToVisit->getType(), ExprToVisit, InitExprs, ArrayFiller); return; + } else if (ExprToVisit->getType()->isVariableArrayType()) { + // A variable array type that has an initializer can only do empty + // initialization. And because this feature is not exposed as an extension + // in C++, we can safely memset the array memory to zero. + CGF.EmitNullInitialization(Dest.getAddress(), ExprToVisit->getType()); + return; } assert(ExprToVisit->getType()->isRecordType() && Index: clang/include/clang/Basic/DiagnosticParseKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticParseKinds.td +++ clang/include/clang/Basic/DiagnosticParseKinds.td @@ -182,8 +182,6 @@ InGroup<GNUStatementExpressionFromMacroExpansion>; def ext_gnu_conditional_expr : Extension< "use of GNU ?: conditional expression extension, omitting middle operand">, InGroup<GNUConditionalOmittedOperand>; -def ext_gnu_empty_initializer : Extension< - "use of GNU empty initializer extension">, InGroup<GNUEmptyInitializer>; def ext_gnu_array_range : Extension<"use of GNU array range extension">, InGroup<GNUDesignator>; def ext_gnu_missing_equal_designator : ExtWarn< Index: clang/include/clang/Basic/DiagnosticGroups.td =================================================================== --- clang/include/clang/Basic/DiagnosticGroups.td +++ clang/include/clang/Basic/DiagnosticGroups.td @@ -256,7 +256,6 @@ def Exceptions : DiagGroup<"exceptions">; def DeclarationAfterStatement : DiagGroup<"declaration-after-statement">; -def GNUEmptyInitializer : DiagGroup<"gnu-empty-initializer">; def GNUEmptyStruct : DiagGroup<"gnu-empty-struct">; def ExtraTokens : DiagGroup<"extra-tokens">; def CXX98CompatExtraSemi : DiagGroup<"c++98-compat-extra-semi">; @@ -1135,7 +1134,7 @@ GNUBinaryLiteral, GNUCaseRange, GNUComplexInteger, GNUCompoundLiteralInitializer, GNUConditionalOmittedOperand, GNUDesignator, - GNUEmptyInitializer, GNUEmptyStruct, + GNUEmptyStruct, VLAExtension, GNUFlexibleArrayInitializer, GNUFlexibleArrayUnionMember, GNUFoldingConstant, GNUImaginaryConstant, GNUIncludeNext, Index: clang/include/clang/Basic/DiagnosticCommonKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticCommonKinds.td +++ clang/include/clang/Basic/DiagnosticCommonKinds.td @@ -130,6 +130,12 @@ def warn_missing_type_specifier : Warning< "type specifier missing, defaults to 'int'">, InGroup<ImplicitInt>, DefaultIgnore; + +def ext_c_empty_initializer : Extension< + "use of an empty initializer is a C2x extension">, InGroup<C2x>; +def warn_c2x_compat_empty_initializer : Warning< + "use of an empty initializer is incompatible with C standards before C2x">, + InGroup<CPre2xCompat>, DefaultIgnore; } let CategoryName = "Nullability Issue" in { Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -121,6 +121,18 @@ which introduces the ``bool``, ``static_assert``, ``alignas``, ``alignof``, and ``thread_local`` keywords in C2x. +- Implemented `WG14 N2900 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2900.htm>`_ + and `WG14 N3011 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3011.htm>`_ + which allows for empty braced initialization in C. + + .. code-block:: c + + struct S { int x, y } s = {}; // Initializes s.x and s.y to 0 + + As part of this change, the ``-Wgnu-empty-initializer`` warning group was + removed, as this is no longer a GNU extension but a C2x extension. You can + use ``-Wno-c2x-extensions`` to silence the extension warning instead. + Non-comprehensive list of changes in this release ------------------------------------------------- - Clang now saves the address of ABI-indirect function parameters on the stack,
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits