[clang] 5d8aaad - [C2x] Implement support for empty brace initialization (WG14 N2900 and WG14 N3011)
Aaron Ballman via cfe-commits
cfe-commits at lists.llvm.org
Mon Apr 3 12:23:01 PDT 2023
Author: Aaron Ballman
Date: 2023-04-03T15:22:52-04:00
New Revision: 5d8aaad4452f60ba8902e921d9bed606713a8f26
URL: https://github.com/llvm/llvm-project/commit/5d8aaad4452f60ba8902e921d9bed606713a8f26
DIFF: https://github.com/llvm/llvm-project/commit/5d8aaad4452f60ba8902e921d9bed606713a8f26.diff
LOG: [C2x] Implement support for empty brace initialization (WG14 N2900 and WG14 N3011)
This implements support for allowing {} to consistently zero initialize
objects. We already supported most of this work as a GNU extension, but
the C2x feature goes beyond what the GNU extension allowed.
The changes in this patch are:
* Removed the -Wgnu-empty-initializer warning group. The extension is
now a C2x extension warning instead. Note that use of
`-Wno-gnu-empty-initializer seems` to be quite low in the wild
(https://sourcegraph.com/search?q=context%3Aglobal+-file%3A.*test.*+%22-Wno-gnu-empty-initializer%22&patternType=standard&sm=1&groupBy=repo
which currently only gives 8 hits total), so this is not expected to
be an overly disruptive change. But I'm adding the clang vendors
review group just in case this expectation is wrong.
* Reworded the diagnostic wording to be about a C2x extension, added a
pre-C2x compat warning.
* Allow {} to zero initialize a VLA
This functionality is exposed as an extension in all older C modes
(same as the GNU extension was), but does *not* allow the extension for
VLA initialization in C++ due to concern about handling non-trivially
constructible types.
Differential Revision: https://reviews.llvm.org/D147349
Added:
clang/test/C/C2x/n2900_n3011.c
clang/test/C/C2x/n2900_n3011_2.c
Modified:
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/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
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index cd9aae998a503..53a0541ed290a 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -121,6 +121,18 @@ C2x Feature Support
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,
diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td
index f574b0f0171b7..bac77299671c5 100644
--- a/clang/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td
@@ -130,6 +130,12 @@ def warn_cxx20_compat_consteval : Warning<
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 {
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index 0d2829d64501f..31f64f4eceb7c 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -256,7 +256,6 @@ def EmptyBody : DiagGroup<"empty-body">;
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 @@ def GNU : DiagGroup<"gnu", [GNUAlignofExpression, GNUAnonymousStruct,
GNUBinaryLiteral, GNUCaseRange,
GNUComplexInteger, GNUCompoundLiteralInitializer,
GNUConditionalOmittedOperand, GNUDesignator,
- GNUEmptyInitializer, GNUEmptyStruct,
+ GNUEmptyStruct,
VLAExtension, GNUFlexibleArrayInitializer,
GNUFlexibleArrayUnionMember, GNUFoldingConstant,
GNUImaginaryConstant, GNUIncludeNext,
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 929ba9e3287ef..d8ad04728b32d 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -182,8 +182,6 @@ def ext_gnu_statement_expr_macro : Extension<
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<
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index 33d2295fa98ee..7a2d65084887a 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -1658,11 +1658,19 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr(
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.
+ assert(InitExprs.size() == 0 &&
+ "you can only use an empty initializer with VLAs");
+ CGF.EmitNullInitialization(Dest.getAddress(), ExprToVisit->getType());
+ return;
}
assert(ExprToVisit->getType()->isRecordType() &&
diff --git a/clang/lib/Parse/ParseInit.cpp b/clang/lib/Parse/ParseInit.cpp
index af0c3b47958d2..e9eb56b6583a3 100644
--- a/clang/lib/Parse/ParseInit.cpp
+++ b/clang/lib/Parse/ParseInit.cpp
@@ -429,7 +429,7 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator(
/// initializer: [C99 6.7.8]
/// '{' initializer-list '}'
/// '{' initializer-list ',' '}'
-/// [GNU] '{' '}'
+/// [C2x] '{' '}'
///
/// initializer-list:
/// designation[opt] initializer ...[opt]
@@ -447,9 +447,12 @@ ExprResult Parser::ParseBraceInitializer() {
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());
}
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 40c2a993b8ffe..47b548e9a9fc6 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -7491,10 +7491,23 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
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,
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 569024551d559..1775dad77d345 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -1565,20 +1565,23 @@ void InitListChecker::CheckScalarType(const InitializedEntity &Entity,
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 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
// 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;
diff --git a/clang/test/C/C2x/n2900_n3011.c b/clang/test/C/C2x/n2900_n3011.c
new file mode 100644
index 0000000000000..b0de79e9a516f
--- /dev/null
+++ b/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}}
+}
+
diff --git a/clang/test/C/C2x/n2900_n3011_2.c b/clang/test/C/C2x/n2900_n3011_2.c
new file mode 100644
index 0000000000000..eb15fbf905c86
--- /dev/null
+++ b/clang/test/C/C2x/n2900_n3011_2.c
@@ -0,0 +1,122 @@
+// 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 num_elts = 12;
+ int vla[num_elts] = {};
+ // CHECK: define {{.*}} void @test_vla
+ // CHECK-NEXT: entry:
+ // CHECK-NEXT: %[[NUM_ELTS_PTR:.+]] = alloca i32
+ // CHECK: %[[VLA_EXPR:.+]] = alloca i64
+ // 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: %[[VLA:.+]] = alloca i32, i64 %[[NUM_ELTS_EXT]]
+ // CHECK-NEXT: store i64 %[[NUM_ELTS_EXT]], ptr %[[VLA_EXPR]]
+ // CHECK-NEXT: %[[BYTES_TO_COPY:.+]] = mul nuw i64 %[[NUM_ELTS_EXT]], 4
+ // CHECK-NEXT: call void @llvm.memset.p0.i64(ptr {{.*}} %[[VLA]], i8 0, i64 %[[BYTES_TO_COPY]], i1 false)
+}
+
+void test_zero_size_vla() {
+ int num_elts = 0;
+ int vla[num_elts] = {};
+ // CHECK: define {{.*}} void @test_zero_size_vla
+ // CHECK-NEXT: entry:
+ // CHECK-NEXT: %[[NUM_ELTS_PTR:.+]] = alloca i32
+ // CHECK: %[[VLA_EXPR:.+]] = alloca i64
+ // CHECK-NEXT: store i32 0, 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: %[[VLA:.+]] = alloca i32, i64 %[[NUM_ELTS_EXT]]
+ // CHECK-NEXT: store i64 %[[NUM_ELTS_EXT]], ptr %[[VLA_EXPR]]
+ // CHECK-NEXT: %[[BYTES_TO_COPY:.+]] = mul nuw i64 %[[NUM_ELTS_EXT]], 4
+ // 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, {} } };
+ 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)
+}
+
+void test_vla_of_nested_structs(int num_elts) {
+ struct T t3[num_elts] = {};
+ // CHECK: define {{.*}} void @test_vla_of_nested_structs(i32 noundef %[[NUM_ELTS_PARAM:.+]])
+ // CHECK-NEXT: entry:
+ // CHECK-NEXT: %[[NUM_ELTS_PTR:.+]] = alloca i32
+ // CHECK: %[[VLA_EXPR:.+]] = alloca i64
+ // CHECK-NEXT: store i32 %[[NUM_ELTS_PARAM]], ptr %[[NUM_ELTS_PTR]]
+ // CHECK-NEXT: %[[NUM_ELTS_LOCAL:.+]] = load i32, ptr %[[NUM_ELTS_PTR]]
+ // CHECK-NEXT: %[[NUM_ELTS_EXT:.+]] = zext i32 %[[NUM_ELTS_LOCAL]] to i64
+ // CHECK: %[[VLA:.+]] = alloca %struct.T, i64 %[[NUM_ELTS_EXT]]
+ // CHECK-NEXT: store i64 %[[NUM_ELTS_EXT]], ptr %[[VLA_EXPR]]
+ // CHECK-NEXT: %[[COPY_BYTES:.+]] = mul nuw i64 %[[NUM_ELTS_EXT]], 12
+ // CHECK-NEXT: call void @llvm.memset.p0.i64(ptr {{.*}} %[[VLA]], i8 0, i64 %[[COPY_BYTES]], i1 false)
+}
diff --git a/clang/test/Sema/array-init.c b/clang/test/Sema/array-init.c
index fcc3c13bc91da..0e23a7d3d3755 100644
--- a/clang/test/Sema/array-init.c
+++ b/clang/test/Sema/array-init.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=gnu99 -fsyntax-only -pedantic -verify %s
+// RUN: %clang_cc1 -std=gnu99 -fsyntax-only -pedantic -verify=expected,pedantic %s
// RUN: %clang_cc1 -std=gnu99 -fsyntax-only -Wgnu -Wc11-extensions -verify %s
// REQUIRES: LP64
@@ -64,7 +64,7 @@ void test(void) {
{ 2, 4, 6 },
{ 3, 5, 7 },
{ 4, 6, 8 },
- { }, // expected-warning{{use of GNU empty initializer extension}} expected-warning{{excess elements in array initializer}}
+ { }, // pedantic-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 @@ void charArrays(void) {
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}} pedantic-warning{{use of an empty initializer is a C2x extension}}
}
void variableArrayInit(void) {
@@ -197,7 +197,7 @@ const char r7[] = "zxcv";
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}} pedantic-warning{{use of an empty initializer is a C2x extension}}
// Some struct tests
void autoStructTest(void) {
@@ -221,8 +221,7 @@ int t8[sizeof t7 == (3*sizeof(int)) ? 1 : -1];
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 = {}; //pedantic-warning{{use of an empty initializer is a C2x extension}}
int u2 = {{3}}; //expected-warning{{too many braces around scalar initializer}}
// PR2362
diff --git a/clang/test/Sema/complex-init-list.c b/clang/test/Sema/complex-init-list.c
index b8f87f57f0793..ac220d8e07c9b 100644
--- a/clang/test/Sema/complex-init-list.c
+++ b/clang/test/Sema/complex-init-list.c
@@ -38,8 +38,7 @@ _Complex float valid5 = {1.0f, 1.0fi}; // expected-warning {{imaginary constants
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
diff --git a/clang/test/Sema/compound-literal.c b/clang/test/Sema/compound-literal.c
index 8ed4fd3976d4a..46fa41e55c72c 100644
--- a/clang/test/Sema/compound-literal.c
+++ b/clang/test/Sema/compound-literal.c
@@ -14,7 +14,7 @@ static int *p2 = (int []){2,x}; // expected-error {{initializer element is not a
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};
diff --git a/clang/test/Sema/flexible-array-init.c b/clang/test/Sema/flexible-array-init.c
index d3620154c5f0c..57c7344dd33e1 100644
--- a/clang/test/Sema/flexible-array-init.c
+++ b/clang/test/Sema/flexible-array-init.c
@@ -10,7 +10,7 @@ void test(void) {
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 bar { struct foo z; }; // expected-warning {{'z' may not be nested in a s
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}}
diff --git a/clang/test/Sema/gnu-flags.c b/clang/test/Sema/gnu-flags.c
index 8389cb6055bc4..941d7084869de 100644
--- a/clang/test/Sema/gnu-flags.c
+++ b/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 @@ _Complex short int complexint;
static const char* omittedoperand = (const char*)0 ?: "Null";
-#if ALL || EMPTYINIT
-// expected-warning at +3 {{use of GNU empty initializer extension}}
-#endif
-
-struct { int x; } emptyinit = {};
-
-
#if ALL || LABELVALUE
// expected-warning at +6 {{use of GNU address-of-label extension}}
// expected-warning at +7 {{use of GNU indirect-goto extension}}
diff --git a/clang/test/Sema/sizeless-1.c b/clang/test/Sema/sizeless-1.c
index 64af214d206b9..8ef30a12f1128 100644
--- a/clang/test/Sema/sizeless-1.c
+++ b/clang/test/Sema/sizeless-1.c
@@ -83,8 +83,8 @@ void func(int sel) {
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'}}
diff --git a/clang/test/Sema/vla.c b/clang/test/Sema/vla.c
index c6d61aac4515f..efdc11b85be99 100644
--- a/clang/test/Sema/vla.c
+++ b/clang/test/Sema/vla.c
@@ -113,14 +113,14 @@ void test_fold_to_constant_array(void) {
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}}
diff --git a/clang/test/SemaObjC/property.m b/clang/test/SemaObjC/property.m
index b03aea37f92c6..64123f261df59 100644
--- a/clang/test/SemaObjC/property.m
+++ b/clang/test/SemaObjC/property.m
@@ -78,5 +78,5 @@ @interface Test7
@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] = {};
}
diff --git a/clang/test/SemaOpenCL/intel-subgroup-avc-ext-types.cl b/clang/test/SemaOpenCL/intel-subgroup-avc-ext-types.cl
index 48ed4c0594d65..adddead3eb412 100644
--- a/clang/test/SemaOpenCL/intel-subgroup-avc-ext-types.cl
+++ b/clang/test/SemaOpenCL/intel-subgroup-avc-ext-types.cl
@@ -28,37 +28,34 @@ void foo(char c, float f, void* v, struct st ss) {
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 at -14 {{initializing '__private intel_sub_group_avc_mce_payload_t' with an expression of incompatible type 'int'}}
-// expected-error at -14 {{initializing '__private intel_sub_group_avc_ime_payload_t' with an expression of incompatible type 'int'}}
-// expected-error at -14 {{initializing '__private intel_sub_group_avc_ref_payload_t' with an expression of incompatible type '__private float'}}
-// expected-error at -14 {{initializing '__private intel_sub_group_avc_sic_payload_t' with an expression of incompatible type '__private struct st'}}
-// expected-error at -14 {{initializing '__private intel_sub_group_avc_mce_result_t' with an expression of incompatible type 'int'}}
-// expected-error at -14 {{initializing '__private intel_sub_group_avc_ime_result_t' with an expression of incompatible type 'int'}}
-// expected-error at -14 {{initializing '__private intel_sub_group_avc_ref_result_t' with an expression of incompatible type '__private float'}}
-// expected-error at -14 {{initializing '__private intel_sub_group_avc_sic_result_t' with an expression of incompatible type '__private struct st'}}
-// expected-error at -14 {{initializing '__private intel_sub_group_avc_ime_result_single_reference_streamout_t' with an expression of incompatible type '__private void *__private'}}
-// expected-warning at -14 {{excess elements in struct initializer}}
-// expected-error at -14 {{scalar initializer cannot be empty}}
-// expected-error at -14 {{initializing '__private intel_sub_group_avc_ime_single_reference_streamin_t' with an expression of incompatible type '__private char'}}
-// expected-error at -14 {{initializing '__private intel_sub_group_avc_ime_dual_reference_streamin_t' with an expression of incompatible type 'int'}}
+// expected-error at -13 {{initializing '__private intel_sub_group_avc_mce_payload_t' with an expression of incompatible type 'int'}}
+// expected-error at -13 {{initializing '__private intel_sub_group_avc_ime_payload_t' with an expression of incompatible type 'int'}}
+// expected-error at -13 {{initializing '__private intel_sub_group_avc_ref_payload_t' with an expression of incompatible type '__private float'}}
+// expected-error at -13 {{initializing '__private intel_sub_group_avc_sic_payload_t' with an expression of incompatible type '__private struct st'}}
+// expected-error at -13 {{initializing '__private intel_sub_group_avc_mce_result_t' with an expression of incompatible type 'int'}}
+// expected-error at -13 {{initializing '__private intel_sub_group_avc_ime_result_t' with an expression of incompatible type 'int'}}
+// expected-error at -13 {{initializing '__private intel_sub_group_avc_ref_result_t' with an expression of incompatible type '__private float'}}
+// expected-error at -13 {{initializing '__private intel_sub_group_avc_sic_result_t' with an expression of incompatible type '__private struct st'}}
+// expected-error at -13 {{initializing '__private intel_sub_group_avc_ime_result_single_reference_streamout_t' with an expression of incompatible type '__private void *__private'}}
+// expected-warning at -13 {{excess elements in struct initializer}}
+// expected-error at -13 {{initializing '__private intel_sub_group_avc_ime_single_reference_streamin_t' with an expression of incompatible type '__private char'}}
+// expected-error at -13 {{initializing '__private intel_sub_group_avc_ime_dual_reference_streamin_t' with an expression of incompatible type 'int'}}
#else
-// expected-error at -28 {{use of undeclared identifier 'intel_sub_group_avc_mce_payload_t'}}
-// expected-error at -28 {{use of undeclared identifier 'intel_sub_group_avc_ime_payload_t'}}
-// expected-error at -28 {{use of undeclared identifier 'intel_sub_group_avc_ref_payload_t'}}
-// expected-error at -28 {{use of undeclared identifier 'intel_sub_group_avc_sic_payload_t'}}
-// expected-error at -28 {{use of undeclared identifier 'intel_sub_group_avc_mce_result_t'}}
-// expected-error at -28 {{use of undeclared identifier 'intel_sub_group_avc_ime_result_t'}}
-// expected-error at -28 {{use of undeclared identifier 'intel_sub_group_avc_ref_result_t'}}
-// expected-error at -28 {{use of undeclared identifier 'intel_sub_group_avc_sic_result_t'}}
-// expected-error at -28 {{use of undeclared identifier 'intel_sub_group_avc_ime_result_single_reference_streamout_t'}}
-// expected-error at -28 {{use of undeclared identifier 'intel_sub_group_avc_ime_result_dual_reference_streamout_t'}}
-// expected-error at -28 {{use of undeclared identifier 'intel_sub_group_avc_ime_dual_reference_streamin_t'}}
-// expected-error at -28 {{use of undeclared identifier 'intel_sub_group_avc_ime_single_reference_streamin_t'}}
-// expected-error at -28 {{use of undeclared identifier 'intel_sub_group_avc_ime_dual_reference_streamin_t'}}
+// expected-error at -26 {{use of undeclared identifier 'intel_sub_group_avc_mce_payload_t'}}
+// expected-error at -26 {{use of undeclared identifier 'intel_sub_group_avc_ime_payload_t'}}
+// expected-error at -26 {{use of undeclared identifier 'intel_sub_group_avc_ref_payload_t'}}
+// expected-error at -26 {{use of undeclared identifier 'intel_sub_group_avc_sic_payload_t'}}
+// expected-error at -26 {{use of undeclared identifier 'intel_sub_group_avc_mce_result_t'}}
+// expected-error at -26 {{use of undeclared identifier 'intel_sub_group_avc_ime_result_t'}}
+// expected-error at -26 {{use of undeclared identifier 'intel_sub_group_avc_ref_result_t'}}
+// expected-error at -26 {{use of undeclared identifier 'intel_sub_group_avc_sic_result_t'}}
+// expected-error at -26 {{use of undeclared identifier 'intel_sub_group_avc_ime_result_single_reference_streamout_t'}}
+// expected-error at -26 {{use of undeclared identifier 'intel_sub_group_avc_ime_result_dual_reference_streamout_t'}}
+// expected-error at -26 {{use of undeclared identifier 'intel_sub_group_avc_ime_single_reference_streamin_t'}}
+// expected-error at -26 {{use of undeclared identifier 'intel_sub_group_avc_ime_dual_reference_streamin_t'}}
#endif
}
diff --git a/clang/www/c_status.html b/clang/www/c_status.html
index 764c7c58c7a51..a431508e6e16a 100644
--- a/clang/www/c_status.html
+++ b/clang/www/c_status.html
@@ -1083,11 +1083,11 @@ <h2 id="c2x">C2x implementation status</h2>
</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>
More information about the cfe-commits
mailing list