[clang] [clang][C23] N3006 Underspecified object declarations (PR #79845)

Guillot Tony via cfe-commits cfe-commits at lists.llvm.org
Mon Mar 18 01:32:34 PDT 2024


https://github.com/to268 updated https://github.com/llvm/llvm-project/pull/79845

>From f463907db6a68422c2f28d08593ab21e42c6a497 Mon Sep 17 00:00:00 2001
From: Guillot Tony <tony.guillot at protonmail.com>
Date: Mon, 29 Jan 2024 15:14:32 +0100
Subject: [PATCH 1/3] Implementation base of N3006 Underspecified object
 declarations

---
 clang/docs/ReleaseNotes.rst                   |  3 +++
 .../clang/Basic/DiagnosticSemaKinds.td        |  2 ++
 clang/lib/Sema/SemaExpr.cpp                   | 27 +++++++++++++++++++
 clang/test/C/C2x/n3006.c                      | 27 +++++++++++++++++++
 clang/test/Parser/c2x-underspecified-decls.c  | 12 +++++++++
 clang/www/c_status.html                       |  2 +-
 6 files changed, 72 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/C/C2x/n3006.c
 create mode 100644 clang/test/Parser/c2x-underspecified-decls.c

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 125d51c42d507f..3b4a9291b6f7f0 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -163,6 +163,9 @@ C23 Feature Support
 - Clang now supports `N3018 The constexpr specifier for object definitions`
   <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3018.htm>`_.
 
+- Clang now diagnoses `N3006 Underspecified object declarations
+  <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3006.htm>`_.
+
 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 8e97902564af08..b336b5f63367c1 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -7685,6 +7685,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 8725b09f8546cf..6395690e0edeb9 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -7813,6 +7813,33 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
                                            diag::err_variable_object_no_init))
         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,
diff --git a/clang/test/C/C2x/n3006.c b/clang/test/C/C2x/n3006.c
new file mode 100644
index 00000000000000..15efc0ccd6d323
--- /dev/null
+++ b/clang/test/C/C2x/n3006.c
@@ -0,0 +1,27 @@
+// 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 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}}
diff --git a/clang/test/Parser/c2x-underspecified-decls.c b/clang/test/Parser/c2x-underspecified-decls.c
new file mode 100644
index 00000000000000..5a7e935cda5444
--- /dev/null
+++ b/clang/test/Parser/c2x-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 9e4600b3e66acb..6abd1199147234 100644
--- a/clang/www/c_status.html
+++ b/clang/www/c_status.html
@@ -1191,7 +1191,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 19</td>
     </tr>
     <tr>
       <td>Type inference for object declarations</td>

>From de90e3ddfe38e2a5b6ae5d5938d9c9fc3ae21228 Mon Sep 17 00:00:00 2001
From: Guillot Tony <tony.guillot at protonmail.com>
Date: Mon, 29 Jan 2024 16:11:02 +0100
Subject: [PATCH 2/3] Fidex formatting

---
 clang/lib/Sema/SemaExpr.cpp | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 6395690e0edeb9..7ec2c0a5fd78d0 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -7834,16 +7834,17 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
     // 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;
+      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

>From 76ee2339d7eb5dde94bfbb3c6bf20cb28229447b Mon Sep 17 00:00:00 2001
From: Guillot Tony <tony.guillot at protonmail.com>
Date: Mon, 18 Mar 2024 08:00:47 +0100
Subject: [PATCH 3/3] Revert "Fidex formatting"

This reverts commit de90e3ddfe38e2a5b6ae5d5938d9c9fc3ae21228.
---
 clang/lib/Sema/SemaExpr.cpp | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 7ec2c0a5fd78d0..bb6004d6fc3cb2 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -7840,11 +7840,9 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
       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



More information about the cfe-commits mailing list