https://github.com/J-MR-T updated https://github.com/llvm/llvm-project/pull/91891
From 9aab9284fc094d22e12a2ee1217a3bc99e5837b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jim=20M=2E=20R=2E=20Teichgr=C3=A4ber?= <jimmr.teichgrae...@tum.de> Date: Sun, 12 May 2024 13:33:37 +0200 Subject: [PATCH 1/5] [clang] Disallow VLA type compound literals 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 Issue: https://github.com/llvm/llvm-project/issues/89835 --- .../clang/Basic/DiagnosticSemaKinds.td | 2 ++ clang/lib/Sema/SemaExpr.cpp | 19 +++++++++++++------ clang/test/C/C2x/n2900_n3011.c | 8 +++++++- clang/test/C/C2x/n2900_n3011_2.c | 16 ---------------- clang/test/Sema/compound-literal.c | 15 +++++++++++++-- 5 files changed, 35 insertions(+), 25 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index d6863f90edb6e..008d7b2a29cd9 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3371,6 +3371,8 @@ def err_field_with_address_space : Error< "field may not be qualified with an address space">; def err_compound_literal_with_address_space : Error< "compound literal in function scope may not be qualified with an address space">; +def err_compound_literal_with_vla_type : Error< + "compound literal has variable-length array type">; def err_address_space_mismatch_templ_inst : Error< "conflicting address space qualifiers are provided between types %0 and %1">; def err_attr_objc_ownership_redundant : Error< diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index c688cb21f2364..e62e3f3285e5d 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -7274,12 +7274,19 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, // 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)) + // + // But: C99-C23 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. This seems odd, as it allows int a[size] = + // {}; but forbids int a[size] = (int[size]){}; As this is what the + // standard says, this is what's implemented here for C (except for the + // extension that permits constant foldable size arrays) + + auto diagID = LangOpts.CPlusPlus + ? diag::err_variable_object_no_init + : diag::err_compound_literal_with_vla_type; + if (!tryToFixVariablyModifiedVarType(TInfo, literalType, LParenLoc, + diagID)) return ExprError(); } } else if (!literalType->isDependentType() && diff --git a/clang/test/C/C2x/n2900_n3011.c b/clang/test/C/C2x/n2900_n3011.c index 4350aa140691b..f0be8b9e41861 100644 --- a/clang/test/C/C2x/n2900_n3011.c +++ b/clang/test/C/C2x/n2900_n3011.c @@ -27,8 +27,14 @@ void test(void) { compat-warning {{use of an empty initializer is incompatible with C standards before C23}} int vla[i] = {}; // compat-warning {{use of an empty initializer is incompatible with C standards before C23}} \ pedantic-warning {{use of an empty initializer is a C23 extension}} + // 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. int *compound_literal_vla = (int[i]){}; // compat-warning {{use of an empty initializer is incompatible with C standards before C23}} \ - pedantic-warning {{use of an empty initializer is a C23 extension}} + pedantic-warning {{use of an empty initializer is a C23 extension}}\ + compat-error {{compound literal has variable-length array type}} \ + pedantic-error {{compound literal has variable-length array type}}\ + struct T { int i; diff --git a/clang/test/C/C2x/n2900_n3011_2.c b/clang/test/C/C2x/n2900_n3011_2.c index eb15fbf905c86..ab659d636d155 100644 --- a/clang/test/C/C2x/n2900_n3011_2.c +++ b/clang/test/C/C2x/n2900_n3011_2.c @@ -76,22 +76,6 @@ void test_zero_size_vla() { // CHECK-NEXT: call void @llvm.memset.p0.i64(ptr {{.*}} %[[VLA]], i8 0, i64 %[[BYTES_TO_COPY]], i1 false) } -void test_compound_literal_vla() { - int num_elts = 12; - int *compound_literal_vla = (int[num_elts]){}; - // CHECK: define {{.*}} void @test_compound_literal_vla - // CHECK-NEXT: entry: - // CHECK-NEXT: %[[NUM_ELTS_PTR:.+]] = alloca i32 - // CHECK-NEXT: %[[COMP_LIT_VLA:.+]] = alloca ptr - // CHECK-NEXT: %[[COMP_LIT:.+]] = alloca i32 - // CHECK-NEXT: store i32 12, ptr %[[NUM_ELTS_PTR]] - // CHECK-NEXT: %[[NUM_ELTS:.+]] = load i32, ptr %[[NUM_ELTS_PTR]] - // CHECK-NEXT: %[[NUM_ELTS_EXT:.+]] = zext i32 %[[NUM_ELTS]] to i64 - // CHECK-NEXT: %[[BYTES_TO_COPY:.+]] = mul nuw i64 %[[NUM_ELTS_EXT]], 4 - // CHECK-NEXT: call void @llvm.memset.p0.i64(ptr {{.*}} %[[COMP_LIT]], i8 0, i64 %[[BYTES_TO_COPY]], 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, {} } }; diff --git a/clang/test/Sema/compound-literal.c b/clang/test/Sema/compound-literal.c index a64b6f9e5dfa4..b845ff317225e 100644 --- a/clang/test/Sema/compound-literal.c +++ b/clang/test/Sema/compound-literal.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -pedantic %s +// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -pedantic -Wno-comment %s // REQUIRES: LP64 struct foo { int a, b; }; @@ -29,7 +29,7 @@ int main(int argc, char **argv) { struct Incomplete; // expected-note{{forward declaration of 'struct Incomplete'}} struct Incomplete* I1 = &(struct Incomplete){1, 2, 3}; // expected-error {{variable has incomplete type}} void IncompleteFunc(unsigned x) { - struct Incomplete* I2 = (struct foo[x]){1, 2, 3}; // expected-error {{variable-sized object may not be initialized}} + struct Incomplete* I2 = (struct foo[x]){1, 2, 3}; // expected-error {{compound literal has variable-length array type}} (void){1,2,3}; // expected-error {{variable has incomplete type}} (void(void)) { 0 }; // expected-error{{illegal initializer type 'void (void)'}} } @@ -42,3 +42,14 @@ int (^block)(int) = ^(int i) { int *array = (int[]) {i, i + 2, i + 4}; return array[i]; }; + +// 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. +// So check that VLA type compound literals are rejected (see https://github.com/llvm/llvm-project/issues/89835). +void vla(int n) { + int size = 5; + (void)(int[size]){}; // expected-warning {{use of an empty initializer is a C23 extension}} \ + expected-error {{compound literal has variable-length array type}} + (void)(int[size]){1}; // expected-error {{compound literal has variable-length array type}} + (void)(int[size]){1,2,3}; // expected-error {{compound literal has variable-length array type}} + (void)(int[size]){1,2,3,4,5}; // expected-error {{compound literal has variable-length array type}} +} From f9e9f9a50547e4c4274f9ff907207b21873b1f72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jim=20M=2E=20R=2E=20Teichgr=C3=A4ber?= <a@teichgraeber.digital> Date: Mon, 13 May 2024 13:34:26 +0200 Subject: [PATCH 2/5] Update clang/include/clang/Basic/DiagnosticSemaKinds.td Co-authored-by: Aaron Ballman <aa...@aaronballman.com> --- clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 008d7b2a29cd9..25d925da7b748 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3372,7 +3372,7 @@ def err_field_with_address_space : Error< def err_compound_literal_with_address_space : Error< "compound literal in function scope may not be qualified with an address space">; def err_compound_literal_with_vla_type : Error< - "compound literal has variable-length array type">; + "compound literal cannot be of variable-length array type">; def err_address_space_mismatch_templ_inst : Error< "conflicting address space qualifiers are provided between types %0 and %1">; def err_attr_objc_ownership_redundant : Error< From d36e6ce64081099753fa2efad615a2f68616f629 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jim=20M=2E=20R=2E=20Teichgr=C3=A4ber?= <jimmr.teichgrae...@tum.de> Date: Mon, 13 May 2024 13:55:40 +0200 Subject: [PATCH 3/5] update error message in test as well --- clang/test/C/C2x/n2900_n3011.c | 4 ++-- clang/test/Sema/compound-literal.c | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/clang/test/C/C2x/n2900_n3011.c b/clang/test/C/C2x/n2900_n3011.c index f0be8b9e41861..82a3b16c8acda 100644 --- a/clang/test/C/C2x/n2900_n3011.c +++ b/clang/test/C/C2x/n2900_n3011.c @@ -32,8 +32,8 @@ void test(void) { // type. int *compound_literal_vla = (int[i]){}; // compat-warning {{use of an empty initializer is incompatible with C standards before C23}} \ pedantic-warning {{use of an empty initializer is a C23 extension}}\ - compat-error {{compound literal has variable-length array type}} \ - pedantic-error {{compound literal has variable-length array type}}\ + compat-error {{compound literal cannot be of variable-length array type}} \ + pedantic-error {{compound literal cannot be of variable-length array type}}\ struct T { diff --git a/clang/test/Sema/compound-literal.c b/clang/test/Sema/compound-literal.c index b845ff317225e..4de8f64ac3768 100644 --- a/clang/test/Sema/compound-literal.c +++ b/clang/test/Sema/compound-literal.c @@ -29,7 +29,7 @@ int main(int argc, char **argv) { struct Incomplete; // expected-note{{forward declaration of 'struct Incomplete'}} struct Incomplete* I1 = &(struct Incomplete){1, 2, 3}; // expected-error {{variable has incomplete type}} void IncompleteFunc(unsigned x) { - struct Incomplete* I2 = (struct foo[x]){1, 2, 3}; // expected-error {{compound literal has variable-length array type}} + struct Incomplete* I2 = (struct foo[x]){1, 2, 3}; // expected-error {{compound literal cannot be of variable-length array type}} (void){1,2,3}; // expected-error {{variable has incomplete type}} (void(void)) { 0 }; // expected-error{{illegal initializer type 'void (void)'}} } @@ -48,8 +48,8 @@ int (^block)(int) = ^(int i) { void vla(int n) { int size = 5; (void)(int[size]){}; // expected-warning {{use of an empty initializer is a C23 extension}} \ - expected-error {{compound literal has variable-length array type}} - (void)(int[size]){1}; // expected-error {{compound literal has variable-length array type}} - (void)(int[size]){1,2,3}; // expected-error {{compound literal has variable-length array type}} - (void)(int[size]){1,2,3,4,5}; // expected-error {{compound literal has variable-length array type}} + expected-error {{compound literal cannot be of variable-length array type}} + (void)(int[size]){1}; // expected-error {{compound literal cannot be of variable-length array type}} + (void)(int[size]){1,2,3}; // expected-error {{compound literal cannot be of variable-length array type}} + (void)(int[size]){1,2,3,4,5}; // expected-error {{compound literal cannot be of variable-length array type}} } From e61b40aa3e3dcb0f0ce59e40fc8c35047ef49fc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jim=20M=2E=20R=2E=20Teichgr=C3=A4ber?= <jimmr.teichgrae...@tum.de> Date: Mon, 13 May 2024 15:13:07 +0200 Subject: [PATCH 4/5] add to release notes --- clang/docs/ReleaseNotes.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 7c5dcc59c7016..1ffd29da0cba9 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -563,6 +563,9 @@ Bug Fixes in This Version - Clang will no longer emit a duplicate -Wunused-value warning for an expression `(A, B)` which evaluates to glvalue `B` that can be converted to non ODR-use. (#GH45783) +- Clang now correctly disallows VLA type compound literals, e.g. ``(int[size]){}``, + as the C standard mandates. (#GH89835) + Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 5ad0b505c6e394365cdba78638fc5a073ad6f422 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jim=20M=2E=20R=2E=20Teichgr=C3=A4ber?= <jimmr.teichgrae...@tum.de> Date: Mon, 13 May 2024 15:13:26 +0200 Subject: [PATCH 5/5] nicer -verify testing syntax --- clang/test/Sema/compound-literal.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/test/Sema/compound-literal.c b/clang/test/Sema/compound-literal.c index 4de8f64ac3768..3ed53d670d38f 100644 --- a/clang/test/Sema/compound-literal.c +++ b/clang/test/Sema/compound-literal.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -pedantic -Wno-comment %s +// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -pedantic %s // REQUIRES: LP64 struct foo { int a, b; }; @@ -47,8 +47,8 @@ int (^block)(int) = ^(int i) { // So check that VLA type compound literals are rejected (see https://github.com/llvm/llvm-project/issues/89835). void vla(int n) { int size = 5; - (void)(int[size]){}; // expected-warning {{use of an empty initializer is a C23 extension}} \ - expected-error {{compound literal cannot be of variable-length array type}} + (void)(int[size]){}; // expected-warning {{use of an empty initializer is a C23 extension}} + // expected-error@-1 {{compound literal cannot be of variable-length array type}} (void)(int[size]){1}; // expected-error {{compound literal cannot be of variable-length array type}} (void)(int[size]){1,2,3}; // expected-error {{compound literal cannot be of variable-length array type}} (void)(int[size]){1,2,3,4,5}; // expected-error {{compound literal cannot be of variable-length array type}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits