Skip to content

Commit 44d103f

Browse files
committed
Implementation base of N3006 Underspecified object declarations
1 parent 540fd42 commit 44d103f

File tree

6 files changed

+73
-2
lines changed

6 files changed

+73
-2
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ ABI Changes in This Version
104104
ifuncs. Its purpose was to preserve backwards compatibility when the ".ifunc"
105105
suffix got removed from the name mangling. The alias interacts badly with
106106
GlobalOpt (see the issue #96197).
107-
107+
108108
- Fixed Microsoft name mangling for auto non-type template arguments of pointer
109109
type for MSVC 1920+. This change resolves incompatibilities with code compiled
110110
by MSVC 1920+ but will introduce incompatibilities with code compiled by
@@ -337,6 +337,9 @@ C23 Feature Support
337337
- Properly promote bit-fields of bit-precise integer types to the field's type
338338
rather than to ``int``. #GH87641
339339

340+
- Clang now diagnoses `N3006 Underspecified object declarations
341+
<https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3006.htm>`_.
342+
340343
Non-comprehensive list of changes in this release
341344
-------------------------------------------------
342345

clang/include/clang/Basic/DiagnosticSemaKinds.td

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

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

clang/lib/Sema/SemaExpr.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7117,6 +7117,33 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
71177117
diagID))
71187118
return ExprError();
71197119
}
7120+
} else if (LangOpts.C23 &&
7121+
(literalType->isRecordType() || literalType->isEnumeralType())) {
7122+
// C23 6.2.1p7: Structure, union, and enumeration tags have scope that
7123+
// begins just after the appearance of the tag in a type specifier that
7124+
// declares the tag.
7125+
// [...]
7126+
// An ordinary identifier that has an underspecified definition has scope
7127+
// that starts when the definition is completed; if the same ordinary
7128+
// identifier declares another entity with a scope that encloses the current
7129+
// block, that declaration is hidden as soon as the inner declarator is
7130+
// completed*.)
7131+
// [...]
7132+
// *) That means, that the outer declaration is not visible for the
7133+
// initializer.
7134+
auto Range = SourceRange(LParenLoc, RParenLoc);
7135+
const auto *Tag = literalType->castAs<TagType>();
7136+
const auto &TagRange = Tag->getDecl()->getSourceRange();
7137+
7138+
// We should diagnose underspecified declaration, unless the identifier has
7139+
// been diagnosed as being a redefinition, since the tag is made anonymous.
7140+
if (Range.fullyContains(TagRange) && Tag->getDecl()->getIdentifier()) {
7141+
Diag(TagRange.getBegin(),
7142+
diag::err_c23_underspecified_object_declaration)
7143+
<< (unsigned)Tag->getDecl()->getTagKind()
7144+
<< Tag->getDecl()->getName() << TagRange;
7145+
return ExprError();
7146+
}
71207147
} else if (!literalType->isDependentType() &&
71217148
RequireCompleteType(LParenLoc, literalType,
71227149
diag::err_typecheck_decl_incomplete_type,

clang/test/C/C2x/n3006.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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 underspecified_struct = (struct S2 { int x, y; }){ 1, 2 }; // expected-error {{'struct S2' is defined as an underspecified object initializer}}
13+
auto underspecified_struct_redef = (struct S1 { char x, y; }){ 'A', 'B'}; // expected-error {{redefinition of 'S1'}}
14+
auto underspecified_empty_struct = (struct S3 { }){ }; // expected-error {{'struct S3' is defined as an underspecified object initializer}}
15+
16+
auto normal_union_int = (union U1){ .a = 12 };
17+
auto normal_union_double = (union U1){ .b = 2.4 };
18+
auto underspecified_union = (union U2 { int a; double b; }){ .a = 34 }; // expected-error {{'union U2' is defined as an underspecified object initializer}}
19+
auto underspecified_union_redef = (union U1 { char a; double b; }){ .a = 'A' }; // expected-error {{redefinition of 'U1'}}
20+
auto underspecified_empty_union = (union U3 { }){ }; // expected-error {{'union U3' is defined as an underspecified object initializer}}
21+
22+
auto normal_enum_foo = (enum E1){ FOO };
23+
auto normal_enum_bar = (enum E1){ BAR };
24+
auto underspecified_enum = (enum E2 { BAZ, QUX }){ BAZ }; // expected-error {{'enum E2' is defined as an underspecified object initializer}}
25+
auto underspecified_enum_redef = (enum E1 { ONE, TWO }){ ONE }; // expected-error {{redefinition of 'E1'}}
26+
auto underspecified_empty_enum = (enum E3 { }){ }; // expected-error {{'enum E3' is defined as an underspecified object initializer}} \
27+
expected-error {{use of empty enum}}
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
@@ -1175,7 +1175,7 @@ <h2 id="c2x">C23 implementation status</h2>
11751175
<tr>
11761176
<td>Underspecified object definitions</td>
11771177
<td><a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3006.htm">N3006</a></td>
1178-
<td class="none" align="center">No</td>
1178+
<td class="unreleased" align="center">Clang 19</td>
11791179
</tr>
11801180
<tr>
11811181
<td>Type inference for object declarations</td>

0 commit comments

Comments
 (0)