https://github.com/to268 updated https://github.com/llvm/llvm-project/pull/79845
>From 6b4ac6b0dc8bafa19521d47856d7dee341439fbc Mon Sep 17 00:00:00 2001 From: Guillot Tony <tony.guil...@protonmail.com> Date: Thu, 30 Jan 2025 01:12:13 +0100 Subject: [PATCH] N3006 base --- clang/docs/ReleaseNotes.rst | 2 + .../clang/Basic/DiagnosticSemaKinds.td | 2 + clang/lib/Sema/SemaExpr.cpp | 34 +++++++++- clang/test/C/C23/n3006.c | 66 +++++++++++++++++++ clang/test/Parser/c23-underspecified-decls.c | 12 ++++ clang/www/c_status.html | 2 +- 6 files changed, 114 insertions(+), 4 deletions(-) create mode 100644 clang/test/C/C23/n3006.c create mode 100644 clang/test/Parser/c23-underspecified-decls.c diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 2b56ce974289d5e..4deeb53276ca526 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -87,6 +87,8 @@ C2y Feature Support C23 Feature Support ^^^^^^^^^^^^^^^^^^^ +- Clang now supports `N3006 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3006.htm>`_ Underspecified object declarations. + Non-comprehensive list of changes in this release ------------------------------------------------- diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 2ac3879a4caabca..b8ed7f6f946f8c8 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -7924,6 +7924,8 @@ def err_attribute_arm_mve_polymorphism : Error< "'__clang_arm_mve_strict_polymorphism' attribute can only be applied to an MVE/NEON vector type">; def err_attribute_webassembly_funcref : Error< "'__funcref' attribute can only be applied to a function pointer type">; +def err_c23_underspecified_object_declaration: Error< + "'%select{struct|<ERROR>|union|<ERROR>|enum}0 %1' is defined as an underspecified object initializer">; def warn_setter_getter_impl_required : Warning< "property %0 requires method %1 to be defined - " diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index ba4aaa94b90ffd5..98924971b44f84a 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -7101,10 +7101,38 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, diagID)) return ExprError(); } + } else if (LangOpts.C23 && + (literalType->isRecordType() || literalType->isEnumeralType())) { + // C23 6.2.1p7: Structure, union, and enumeration tags have scope that + // begins just after the appearance of the tag in a type specifier that + // declares the tag. + // [...] + // An ordinary identifier that has an underspecified definition has scope + // that starts when the definition is completed; if the same ordinary + // identifier declares another entity with a scope that encloses the current + // block, that declaration is hidden as soon as the inner declarator is + // completed*.) + // [...] + // *) That means, that the outer declaration is not visible for the + // initializer. + auto Range = SourceRange(LParenLoc, RParenLoc); + const auto *Tag = literalType->castAs<TagType>(); + const auto &TagRange = Tag->getDecl()->getSourceRange(); + + // We should diagnose underspecified declaration, unless the identifier has + // been diagnosed as being a redefinition, since the tag is made anonymous. + if (Range.fullyContains(TagRange) && Tag->getDecl()->getIdentifier()) { + Diag(TagRange.getBegin(), diag::err_c23_underspecified_object_declaration) + << (unsigned)Tag->getDecl()->getTagKind() << Tag->getDecl()->getName() + << TagRange; + return ExprError(); + } } else if (!literalType->isDependentType() && - RequireCompleteType(LParenLoc, literalType, - diag::err_typecheck_decl_incomplete_type, - SourceRange(LParenLoc, LiteralExpr->getSourceRange().getEnd()))) + RequireCompleteType( + LParenLoc, literalType, + diag::err_typecheck_decl_incomplete_type, + SourceRange(LParenLoc, + LiteralExpr->getSourceRange().getEnd()))) return ExprError(); InitializedEntity Entity diff --git a/clang/test/C/C23/n3006.c b/clang/test/C/C23/n3006.c new file mode 100644 index 000000000000000..882b910e96214a7 --- /dev/null +++ b/clang/test/C/C23/n3006.c @@ -0,0 +1,66 @@ +// RUN: %clang_cc1 -std=c2x -verify %s + +/* WG14 N3006: Full + * Underspecified object declarations + */ + +struct S1 { int x, y; }; // expected-note {{previous definition is here}} +union U1 { int a; double b; }; // expected-note {{previous definition is here}} +enum E1 { FOO, BAR }; // expected-note {{previous definition is here}} + +auto normal_struct = (struct S1){ 1, 2 }; +auto normal_struct2 = (struct S1) { .x = 1, .y = 2 }; +auto underspecified_struct = (struct S2 { int x, y; }){ 1, 2 }; // expected-error {{'struct S2' is defined as an underspecified object initializer}} +auto underspecified_struct_redef = (struct S1 { char x, y; }){ 'A', 'B'}; // expected-error {{redefinition of 'S1'}} +auto underspecified_empty_struct = (struct S3 { }){ }; // expected-error {{'struct S3' is defined as an underspecified object initializer}} + +auto normal_union_int = (union U1){ .a = 12 }; +auto normal_union_double = (union U1){ .b = 2.4 }; +auto underspecified_union = (union U2 { int a; double b; }){ .a = 34 }; // expected-error {{'union U2' is defined as an underspecified object initializer}} +auto underspecified_union_redef = (union U1 { char a; double b; }){ .a = 'A' }; // expected-error {{redefinition of 'U1'}} +auto underspecified_empty_union = (union U3 { }){ }; // expected-error {{'union U3' is defined as an underspecified object initializer}} + +auto normal_enum_foo = (enum E1){ FOO }; +auto normal_enum_bar = (enum E1){ BAR }; +auto underspecified_enum = (enum E2 { BAZ, QUX }){ BAZ }; // expected-error {{'enum E2' is defined as an underspecified object initializer}} +auto underspecified_enum_redef = (enum E1 { ONE, TWO }){ ONE }; // expected-error {{redefinition of 'E1'}} +auto underspecified_empty_enum = (enum E3 { }){ }; // expected-error {{'enum E3' is defined as an underspecified object initializer}} \ + expected-error {{use of empty enum}} +void constexpr_test() { + constexpr auto ce_struct = (struct S1){ 1, 2 }; + constexpr auto ce_union = (union U1){ .a = 12 }; + constexpr auto ce_enum = (enum E1){ FOO }; +} + +void trivial_test() { + constexpr int i = i; // expected-error {{constexpr variable 'i' must be initialized by a constant expression}} \ + expected-note {{read of object outside its lifetime is not allowed in a constant expression}} + auto j = j; // expected-error {{variable 'j' declared with deduced type 'auto' cannot appear in its own initializer}} +} + +void double_definition_test() { + const struct S { int x; } s; // expected-note {{previous definition is here}} + constexpr struct S s = {0}; // expected-error {{redefinition of 's'}} +} + +void declaring_an_underspecified_defied_object_test() { + struct S { int x, y; }; + constexpr int i = (struct T { int a, b; }){0, 1}.a; // expected-error {{'struct T' is defined as an underspecified object initializer}} \ + FIXME: `constexpr variable 'i' must be initialized by a constant expression` shoud appear + + struct T t = { 1, 2 }; // TODO: Should this be diagnosed as an invalid declaration? +} + +void constexpr_complience_test() { + int x = (struct Foo { int x; }){ 0 }.x; // expected-error {{'struct Foo' is defined as an underspecified object initializer}} + constexpr int y = (struct Bar { int x; }){ 0 }.x; // expected-error {{'struct Bar' is defined as an underspecified object initializer}} +} + +void special_test() { + constexpr typeof(struct s *) x = 0; // FIXME: declares `s` which is not an ordinary identifier + constexpr struct S { int a, b; } y = { 0 }; // FIXME: declares `S`, `a`, and `b`, none of which are ordinary identifiers + constexpr int a = 0, b = 0; + auto c = (struct T { int x, y; }){0, 0}; // expected-error {{'struct T' is defined as an underspecified object initializer}} + constexpr int (*fp)(struct X { int x; } val) = 0; // expected-warning {{declaration of 'struct X' will not be visible outside of this function}} \ + FIXME: declares `X` and `x` which are not ordinary identifiers +} diff --git a/clang/test/Parser/c23-underspecified-decls.c b/clang/test/Parser/c23-underspecified-decls.c new file mode 100644 index 000000000000000..5a7e935cda54448 --- /dev/null +++ b/clang/test/Parser/c23-underspecified-decls.c @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -fsyntax-only -verify=expected,c23 -std=c23 %s +// RUN: %clang_cc1 -fsyntax-only -verify=expected,c17 -std=c17 %s + +auto underspecified_struct = (struct S1 { int x, y; }){ 1, 2 }; // c23-error {{'struct S1' is defined as an underspecified object initializer}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} \ + c17-error {{illegal storage class on file-scoped variable}} +auto underspecified_union = (union U1 { int a; double b; }){ .a = 34 }; // c23-error {{'union U1' is defined as an underspecified object initializer}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} \ + c17-error {{illegal storage class on file-scoped variable}} +auto underspecified_enum = (enum E1 { FOO, BAR }){ BAR }; // c23-error {{'enum E1' is defined as an underspecified object initializer}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} \ + c17-error {{illegal storage class on file-scoped variable}} diff --git a/clang/www/c_status.html b/clang/www/c_status.html index ca2ca5398bb8739..ce6b4f8ef173c87 100644 --- a/clang/www/c_status.html +++ b/clang/www/c_status.html @@ -797,7 +797,7 @@ <h2 id="c2x">C23 implementation status</h2> <tr> <td>Underspecified object definitions</td> <td><a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3006.htm">N3006</a></td> - <td class="none" align="center">No</td> + <td class="unreleased" align="center">Clang 21</td> </tr> <tr> <td>Type inference for object declarations</td> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits