Skip to content

Commit e91ea1b

Browse files
authored
[Clang] Disallow VLA type compound literals (llvm#91891)
C99-C23 6.5.2.5 says: The type name shall specify an object type or an array of unknown size, but not a variable length array type. Fixes llvm#89835.
1 parent 83e61d0 commit e91ea1b

File tree

6 files changed

+37
-24
lines changed

6 files changed

+37
-24
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,9 @@ Bug Fixes in This Version
570570
- Clang will no longer emit a duplicate -Wunused-value warning for an expression
571571
`(A, B)` which evaluates to glvalue `B` that can be converted to non ODR-use. (#GH45783)
572572

573+
- Clang now correctly disallows VLA type compound literals, e.g. ``(int[size]){}``,
574+
as the C standard mandates. (#GH89835)
575+
573576
Bug Fixes to Compiler Builtins
574577
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
575578

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3371,6 +3371,8 @@ def err_field_with_address_space : Error<
33713371
"field may not be qualified with an address space">;
33723372
def err_compound_literal_with_address_space : Error<
33733373
"compound literal in function scope may not be qualified with an address space">;
3374+
def err_compound_literal_with_vla_type : Error<
3375+
"compound literal cannot be of variable-length array type">;
33743376
def err_address_space_mismatch_templ_inst : Error<
33753377
"conflicting address space qualifiers are provided between types %0 and %1">;
33763378
def err_attr_objc_ownership_redundant : Error<

clang/lib/Sema/SemaExpr.cpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7130,12 +7130,19 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
71307130
// init a VLA in C++ in all cases (such as with non-trivial constructors).
71317131
// FIXME: should we allow this construct in C++ when it makes sense to do
71327132
// so?
7133-
std::optional<unsigned> NumInits;
7134-
if (const auto *ILE = dyn_cast<InitListExpr>(LiteralExpr))
7135-
NumInits = ILE->getNumInits();
7136-
if ((LangOpts.CPlusPlus || NumInits.value_or(0)) &&
7137-
!tryToFixVariablyModifiedVarType(TInfo, literalType, LParenLoc,
7138-
diag::err_variable_object_no_init))
7133+
//
7134+
// But: C99-C23 6.5.2.5 Compound literals constraint 1: The type name
7135+
// shall specify an object type or an array of unknown size, but not a
7136+
// variable length array type. This seems odd, as it allows int a[size] =
7137+
// {}; but forbids int a[size] = (int[size]){}; As this is what the
7138+
// standard says, this is what's implemented here for C (except for the
7139+
// extension that permits constant foldable size arrays)
7140+
7141+
auto diagID = LangOpts.CPlusPlus
7142+
? diag::err_variable_object_no_init
7143+
: diag::err_compound_literal_with_vla_type;
7144+
if (!tryToFixVariablyModifiedVarType(TInfo, literalType, LParenLoc,
7145+
diagID))
71397146
return ExprError();
71407147
}
71417148
} else if (!literalType->isDependentType() &&

clang/test/C/C2x/n2900_n3011.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,14 @@ void test(void) {
2727
compat-warning {{use of an empty initializer is incompatible with C standards before C23}}
2828
int vla[i] = {}; // compat-warning {{use of an empty initializer is incompatible with C standards before C23}} \
2929
pedantic-warning {{use of an empty initializer is a C23 extension}}
30+
// C99 6.5.2.5 Compound literals constraint 1: The type name shall specify an
31+
// object type or an array of unknown size, but not a variable length array
32+
// type.
3033
int *compound_literal_vla = (int[i]){}; // compat-warning {{use of an empty initializer is incompatible with C standards before C23}} \
31-
pedantic-warning {{use of an empty initializer is a C23 extension}}
34+
pedantic-warning {{use of an empty initializer is a C23 extension}}\
35+
compat-error {{compound literal cannot be of variable-length array type}} \
36+
pedantic-error {{compound literal cannot be of variable-length array type}}\
37+
3238

3339
struct T {
3440
int i;

clang/test/C/C2x/n2900_n3011_2.c

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -76,22 +76,6 @@ void test_zero_size_vla() {
7676
// CHECK-NEXT: call void @llvm.memset.p0.i64(ptr {{.*}} %[[VLA]], i8 0, i64 %[[BYTES_TO_COPY]], i1 false)
7777
}
7878

79-
void test_compound_literal_vla() {
80-
int num_elts = 12;
81-
int *compound_literal_vla = (int[num_elts]){};
82-
// CHECK: define {{.*}} void @test_compound_literal_vla
83-
// CHECK-NEXT: entry:
84-
// CHECK-NEXT: %[[NUM_ELTS_PTR:.+]] = alloca i32
85-
// CHECK-NEXT: %[[COMP_LIT_VLA:.+]] = alloca ptr
86-
// CHECK-NEXT: %[[COMP_LIT:.+]] = alloca i32
87-
// CHECK-NEXT: store i32 12, ptr %[[NUM_ELTS_PTR]]
88-
// CHECK-NEXT: %[[NUM_ELTS:.+]] = load i32, ptr %[[NUM_ELTS_PTR]]
89-
// CHECK-NEXT: %[[NUM_ELTS_EXT:.+]] = zext i32 %[[NUM_ELTS]] to i64
90-
// CHECK-NEXT: %[[BYTES_TO_COPY:.+]] = mul nuw i64 %[[NUM_ELTS_EXT]], 4
91-
// CHECK-NEXT: call void @llvm.memset.p0.i64(ptr {{.*}} %[[COMP_LIT]], i8 0, i64 %[[BYTES_TO_COPY]], i1 false)
92-
// CHECK-NEXT: store ptr %[[COMP_LIT]], ptr %[[COMP_LIT_VLA]]
93-
}
94-
9579
void test_nested_structs() {
9680
struct T t1 = { 1, {} };
9781
struct T t2 = { 1, { 2, {} } };

clang/test/Sema/compound-literal.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ int main(int argc, char **argv) {
2929
struct Incomplete; // expected-note{{forward declaration of 'struct Incomplete'}}
3030
struct Incomplete* I1 = &(struct Incomplete){1, 2, 3}; // expected-error {{variable has incomplete type}}
3131
void IncompleteFunc(unsigned x) {
32-
struct Incomplete* I2 = (struct foo[x]){1, 2, 3}; // expected-error {{variable-sized object may not be initialized}}
32+
struct Incomplete* I2 = (struct foo[x]){1, 2, 3}; // expected-error {{compound literal cannot be of variable-length array type}}
3333
(void){1,2,3}; // expected-error {{variable has incomplete type}}
3434
(void(void)) { 0 }; // expected-error{{illegal initializer type 'void (void)'}}
3535
}
@@ -42,3 +42,14 @@ int (^block)(int) = ^(int i) {
4242
int *array = (int[]) {i, i + 2, i + 4};
4343
return array[i];
4444
};
45+
46+
// C99 6.5.2.5 Compound literals constraint 1: The type name shall specify an object type or an array of unknown size, but not a variable length array type.
47+
// So check that VLA type compound literals are rejected (see https://github.com/llvm/llvm-project/issues/89835).
48+
void vla(int n) {
49+
int size = 5;
50+
(void)(int[size]){}; // expected-warning {{use of an empty initializer is a C23 extension}}
51+
// expected-error@-1 {{compound literal cannot be of variable-length array type}}
52+
(void)(int[size]){1}; // expected-error {{compound literal cannot be of variable-length array type}}
53+
(void)(int[size]){1,2,3}; // expected-error {{compound literal cannot be of variable-length array type}}
54+
(void)(int[size]){1,2,3,4,5}; // expected-error {{compound literal cannot be of variable-length array type}}
55+
}

0 commit comments

Comments
 (0)