Skip to content

Commit 16328b4

Browse files
committed
N3006 base
1 parent 30e276d commit 16328b4

File tree

6 files changed

+114
-5
lines changed

6 files changed

+114
-5
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,7 @@ C23 Feature Support
423423
- Clang now officially supports `N3030 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3030.htm>`_ Enhancements to Enumerations. Clang already supported it as an extension, so there were no changes to compiler behavior.
424424
- Fixed the value of ``BOOL_WIDTH`` in ``<limits.h>`` to return ``1``
425425
explicitly, as mandated by the standard. Fixes #GH117348
426+
- Clang now supports `N3006 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3006.htm>`_ Underspecified object declarations.
426427

427428
Non-comprehensive list of changes in this release
428429
-------------------------------------------------
@@ -717,7 +718,7 @@ Improvements to Clang's diagnostics
717718

718719
- Clang now diagnoses dangling references for C++20's parenthesized aggregate initialization (#101957).
719720

720-
- Fixed a bug where Clang would not emit ``-Wunused-private-field`` warnings when an unrelated class
721+
- Fixed a bug where Clang would not emit ``-Wunused-private-field`` warnings when an unrelated class
721722
defined a defaulted comparison operator (#GH116270).
722723

723724
.. code-block:: c++

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7901,6 +7901,8 @@ def err_attribute_arm_mve_polymorphism : Error<
79017901
"'__clang_arm_mve_strict_polymorphism' attribute can only be applied to an MVE/NEON vector type">;
79027902
def err_attribute_webassembly_funcref : Error<
79037903
"'__funcref' attribute can only be applied to a function pointer type">;
7904+
def err_c23_underspecified_object_declaration: Error<
7905+
"'%select{struct|<ERROR>|union|<ERROR>|enum}0 %1' is defined as an underspecified object initializer">;
79047906

79057907
def warn_setter_getter_impl_required : Warning<
79067908
"property %0 requires method %1 to be defined - "

clang/lib/Sema/SemaExpr.cpp

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7087,10 +7087,38 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
70877087
diagID))
70887088
return ExprError();
70897089
}
7090+
} else if (LangOpts.C23 &&
7091+
(literalType->isRecordType() || literalType->isEnumeralType())) {
7092+
// C23 6.2.1p7: Structure, union, and enumeration tags have scope that
7093+
// begins just after the appearance of the tag in a type specifier that
7094+
// declares the tag.
7095+
// [...]
7096+
// An ordinary identifier that has an underspecified definition has scope
7097+
// that starts when the definition is completed; if the same ordinary
7098+
// identifier declares another entity with a scope that encloses the current
7099+
// block, that declaration is hidden as soon as the inner declarator is
7100+
// completed*.)
7101+
// [...]
7102+
// *) That means, that the outer declaration is not visible for the
7103+
// initializer.
7104+
auto Range = SourceRange(LParenLoc, RParenLoc);
7105+
const auto *Tag = literalType->castAs<TagType>();
7106+
const auto &TagRange = Tag->getDecl()->getSourceRange();
7107+
7108+
// We should diagnose underspecified declaration, unless the identifier has
7109+
// been diagnosed as being a redefinition, since the tag is made anonymous.
7110+
if (Range.fullyContains(TagRange) && Tag->getDecl()->getIdentifier()) {
7111+
Diag(TagRange.getBegin(), diag::err_c23_underspecified_object_declaration)
7112+
<< (unsigned)Tag->getDecl()->getTagKind() << Tag->getDecl()->getName()
7113+
<< TagRange;
7114+
return ExprError();
7115+
}
70907116
} else if (!literalType->isDependentType() &&
7091-
RequireCompleteType(LParenLoc, literalType,
7092-
diag::err_typecheck_decl_incomplete_type,
7093-
SourceRange(LParenLoc, LiteralExpr->getSourceRange().getEnd())))
7117+
RequireCompleteType(
7118+
LParenLoc, literalType,
7119+
diag::err_typecheck_decl_incomplete_type,
7120+
SourceRange(LParenLoc,
7121+
LiteralExpr->getSourceRange().getEnd())))
70947122
return ExprError();
70957123

70967124
InitializedEntity Entity

clang/test/C/C23/n3006.c

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// RUN: %clang_cc1 -std=c2x -verify %s
2+
3+
/* WG14 N3006: Full
4+
* Underspecified object declarations
5+
*/
6+
7+
struct S1 { int x, y; }; // expected-note {{previous definition is here}}
8+
union U1 { int a; double b; }; // expected-note {{previous definition is here}}
9+
enum E1 { FOO, BAR }; // expected-note {{previous definition is here}}
10+
11+
auto normal_struct = (struct S1){ 1, 2 };
12+
auto normal_struct2 = (struct S1) { .x = 1, .y = 2 };
13+
auto underspecified_struct = (struct S2 { int x, y; }){ 1, 2 }; // expected-error {{'struct S2' is defined as an underspecified object initializer}}
14+
auto underspecified_struct_redef = (struct S1 { char x, y; }){ 'A', 'B'}; // expected-error {{redefinition of 'S1'}}
15+
auto underspecified_empty_struct = (struct S3 { }){ }; // expected-error {{'struct S3' is defined as an underspecified object initializer}}
16+
17+
auto normal_union_int = (union U1){ .a = 12 };
18+
auto normal_union_double = (union U1){ .b = 2.4 };
19+
auto underspecified_union = (union U2 { int a; double b; }){ .a = 34 }; // expected-error {{'union U2' is defined as an underspecified object initializer}}
20+
auto underspecified_union_redef = (union U1 { char a; double b; }){ .a = 'A' }; // expected-error {{redefinition of 'U1'}}
21+
auto underspecified_empty_union = (union U3 { }){ }; // expected-error {{'union U3' is defined as an underspecified object initializer}}
22+
23+
auto normal_enum_foo = (enum E1){ FOO };
24+
auto normal_enum_bar = (enum E1){ BAR };
25+
auto underspecified_enum = (enum E2 { BAZ, QUX }){ BAZ }; // expected-error {{'enum E2' is defined as an underspecified object initializer}}
26+
auto underspecified_enum_redef = (enum E1 { ONE, TWO }){ ONE }; // expected-error {{redefinition of 'E1'}}
27+
auto underspecified_empty_enum = (enum E3 { }){ }; // expected-error {{'enum E3' is defined as an underspecified object initializer}} \
28+
expected-error {{use of empty enum}}
29+
void constexpr_test() {
30+
constexpr auto ce_struct = (struct S1){ 1, 2 };
31+
constexpr auto ce_union = (union U1){ .a = 12 };
32+
constexpr auto ce_enum = (enum E1){ FOO };
33+
}
34+
35+
void trivial_test() {
36+
constexpr int i = i; // expected-error {{constexpr variable 'i' must be initialized by a constant expression}} \
37+
expected-note {{read of object outside its lifetime is not allowed in a constant expression}}
38+
auto j = j; // expected-error {{variable 'j' declared with deduced type 'auto' cannot appear in its own initializer}}
39+
}
40+
41+
void double_definition_test() {
42+
const struct S { int x; } s; // expected-note {{previous definition is here}}
43+
constexpr struct S s = {0}; // expected-error {{redefinition of 's'}}
44+
}
45+
46+
void declaring_an_underspecified_defied_object_test() {
47+
struct S { int x, y; };
48+
constexpr int i = (struct T { int a, b; }){0, 1}.a; // expected-error {{'struct T' is defined as an underspecified object initializer}} \
49+
FIXME: `constexpr variable 'i' must be initialized by a constant expression` shoud appear
50+
51+
struct T t = { 1, 2 }; // TODO: Should this be diagnosed as an invalid declaration?
52+
}
53+
54+
void constexpr_complience_test() {
55+
int x = (struct Foo { int x; }){ 0 }.x; // expected-error {{'struct Foo' is defined as an underspecified object initializer}}
56+
constexpr int y = (struct Bar { int x; }){ 0 }.x; // expected-error {{'struct Bar' is defined as an underspecified object initializer}}
57+
}
58+
59+
void special_test() {
60+
constexpr typeof(struct s *) x = 0; // FIXME: declares `s` which is not an ordinary identifier
61+
constexpr struct S { int a, b; } y = { 0 }; // FIXME: declares `S`, `a`, and `b`, none of which are ordinary identifiers
62+
constexpr int a = 0, b = 0;
63+
auto c = (struct T { int x, y; }){0, 0}; // expected-error {{'struct T' is defined as an underspecified object initializer}}
64+
constexpr int (*fp)(struct X { int x; } val) = 0; // expected-warning {{declaration of 'struct X' will not be visible outside of this function}} \
65+
FIXME: declares `X` and `x` which are not ordinary identifiers
66+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %clang_cc1 -fsyntax-only -verify=expected,c23 -std=c23 %s
2+
// RUN: %clang_cc1 -fsyntax-only -verify=expected,c17 -std=c17 %s
3+
4+
auto underspecified_struct = (struct S1 { int x, y; }){ 1, 2 }; // c23-error {{'struct S1' is defined as an underspecified object initializer}} \
5+
c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} \
6+
c17-error {{illegal storage class on file-scoped variable}}
7+
auto underspecified_union = (union U1 { int a; double b; }){ .a = 34 }; // c23-error {{'union U1' is defined as an underspecified object initializer}} \
8+
c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} \
9+
c17-error {{illegal storage class on file-scoped variable}}
10+
auto underspecified_enum = (enum E1 { FOO, BAR }){ BAR }; // c23-error {{'enum E1' is defined as an underspecified object initializer}} \
11+
c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} \
12+
c17-error {{illegal storage class on file-scoped variable}}

clang/www/c_status.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -797,7 +797,7 @@ <h2 id="c2x">C23 implementation status</h2>
797797
<tr>
798798
<td>Underspecified object definitions</td>
799799
<td><a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3006.htm">N3006</a></td>
800-
<td class="none" align="center">No</td>
800+
<td class="unreleased" align="center">Clang 20</td>
801801
</tr>
802802
<tr>
803803
<td>Type inference for object declarations</td>

0 commit comments

Comments
 (0)