Skip to content

Commit f463907

Browse files
committed
Implementation base of N3006 Underspecified object declarations
1 parent 65ae09e commit f463907

File tree

6 files changed

+72
-1
lines changed

6 files changed

+72
-1
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,9 @@ C23 Feature Support
163163
- Clang now supports `N3018 The constexpr specifier for object definitions`
164164
<https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3018.htm>`_.
165165

166+
- Clang now diagnoses `N3006 Underspecified object declarations
167+
<https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3006.htm>`_.
168+
166169
Non-comprehensive list of changes in this release
167170
-------------------------------------------------
168171

clang/include/clang/Basic/DiagnosticSemaKinds.td

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

76897691
def warn_setter_getter_impl_required : Warning<
76907692
"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
@@ -7813,6 +7813,33 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
78137813
diag::err_variable_object_no_init))
78147814
return ExprError();
78157815
}
7816+
} else if (LangOpts.C23 &&
7817+
(literalType->isRecordType() || literalType->isEnumeralType())) {
7818+
// C23 6.2.1p7: Structure, union, and enumeration tags have scope that
7819+
// begins just after the appearance of the tag in a type specifier that
7820+
// declares the tag.
7821+
// [...]
7822+
// An ordinary identifier that has an underspecified definition has scope
7823+
// that starts when the definition is completed; if the same ordinary
7824+
// identifier declares another entity with a scope that encloses the current
7825+
// block, that declaration is hidden as soon as the inner declarator is
7826+
// completed*.)
7827+
// [...]
7828+
// *) That means, that the outer declaration is not visible for the
7829+
// initializer.
7830+
auto Range = SourceRange(LParenLoc, RParenLoc);
7831+
const auto *Tag = literalType->castAs<TagType>();
7832+
const auto &TagRange = Tag->getDecl()->getSourceRange();
7833+
7834+
// We should diagnose underspecified declaration, unless the identifier has
7835+
// been diagnosed as being a redefinition, since the tag is made anonymous.
7836+
if (Range.fullyContains(TagRange) && Tag->getDecl()->getIdentifier()) {
7837+
Diag(TagRange.getBegin(),
7838+
diag::err_c23_underspecified_object_declaration)
7839+
<< (unsigned)Tag->getDecl()->getTagKind()
7840+
<< Tag->getDecl()->getName() << TagRange;
7841+
return ExprError();
7842+
}
78167843
} else if (!literalType->isDependentType() &&
78177844
RequireCompleteType(LParenLoc, literalType,
78187845
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
@@ -1191,7 +1191,7 @@ <h2 id="c2x">C23 implementation status</h2>
11911191
<tr>
11921192
<td>Underspecified object definitions</td>
11931193
<td><a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3006.htm">N3006</a></td>
1194-
<td class="none" align="center">No</td>
1194+
<td class="unreleased" align="center">Clang 19</td>
11951195
</tr>
11961196
<tr>
11971197
<td>Type inference for object declarations</td>

0 commit comments

Comments
 (0)