[clang] 0617413 - [C2x] Implement support for revised spelling of keywords

Aaron Ballman via cfe-commits cfe-commits at lists.llvm.org
Sat Feb 25 06:30:20 PST 2023


Author: Aaron Ballman
Date: 2023-02-25T09:30:10-05:00
New Revision: 06174134e418251982d43eff9385674b7644007f

URL: https://github.com/llvm/llvm-project/commit/06174134e418251982d43eff9385674b7644007f
DIFF: https://github.com/llvm/llvm-project/commit/06174134e418251982d43eff9385674b7644007f.diff

LOG: [C2x] Implement support for revised spelling of keywords

This implements WG14 N2934
(https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2934.pdf), which
adds keywords for alignas, alignof, bool, static_assert, and
thread_local in C, as aliases for _Alignas, _Alignof, _Bool,
_Static_assert, and _Thread_local. We already supported the keywords in
C2x mode, but this completes support by adding pre-C2x compat warnings
and updates the stdalign.h header in freestanding mode.

Added: 
    clang/test/C/C2x/n2934.c

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/include/clang/Basic/DiagnosticParseKinds.td
    clang/lib/Headers/stdalign.h
    clang/lib/Parse/ParseDecl.cpp
    clang/lib/Parse/ParseDeclCXX.cpp
    clang/lib/Parse/ParseExpr.cpp
    clang/www/c_status.html

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 0397ba0b305eb..b4c64c4e60515 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -97,6 +97,10 @@ C2x Feature Support
 - Removed the ``ATOMIC_VAR_INIT`` macro in C2x and later standards modes, which
   implements `WG14 N2886 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2886.htm>`_
 
+- Implemented `WG14 N2934 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2934.pdf>`_
+  which introduces the ``bool``, ``static_assert``, ``alignas``, ``alignof``,
+  and ``thread_local`` keywords in C2x.
+
 Non-comprehensive list of changes in this release
 -------------------------------------------------
 - Clang now saves the address of ABI-indirect function parameters on the stack,

diff  --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index e3849c6658d16..243c69a551650 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -162,6 +162,9 @@ def ext_c99_feature : Extension<
   "'%0' is a C99 extension">, InGroup<C99>;
 def ext_c11_feature : Extension<
   "'%0' is a C11 extension">, InGroup<C11>;
+def warn_c2x_compat_keyword : Warning<
+ "'%0' is incompatible with C standards before C2x">,
+ InGroup<CPre2xCompat>, DefaultIgnore;
 
 def err_c11_noreturn_misplaced : Error<
   "'_Noreturn' keyword must precede function declarator">;
@@ -371,9 +374,6 @@ def warn_cxx11_compat_decltype_auto_type_specifier : Warning<
 def ext_auto_type : Extension<
   "'__auto_type' is a GNU extension">,
   InGroup<GNUAutoType>;
-def warn_c2x_compat_typeof_type_specifier : Warning<
-  "'%select{typeof|typeof_unqual}0' is incompatible with C standards before "
-  "C2x">, InGroup<CPre2xCompat>, DefaultIgnore;
 def ext_for_range : ExtWarn<
   "range-based for loop is a C++11 extension">, InGroup<CXX11>;
 def warn_cxx98_compat_for_range : Warning<
@@ -704,9 +704,6 @@ def warn_cxx98_compat_nullptr : Warning<
   "'nullptr' is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore;
 def ext_c_nullptr : Extension<
   "'nullptr' is a C2x extension">, InGroup<C2x>;
-def warn_c17_compat_nullptr : Warning<
-  "'nullptr' is incompatible with C standards before C2x">,
-  InGroup<CPre2xCompat>, DefaultIgnore;
 
 def warn_wrong_clang_attr_namespace : Warning<
   "'__clang__' is a predefined macro name, not an attribute scope specifier; "
@@ -1574,9 +1571,6 @@ def warn_ext_int_deprecated : Warning<
 def ext_bit_int : Extension<
   "'_BitInt' in %select{C17 and earlier|C++}0 is a Clang extension">,
   InGroup<DiagGroup<"bit-int-extension">>;
-def warn_c17_compat_bit_int : Warning<
-  "'_BitInt' is incompatible with C standards before C2x">,
-  InGroup<CPre2xCompat>, DefaultIgnore;
 } // end of Parse Issue category.
 
 let CategoryName = "Modules Issue" in {

diff  --git a/clang/lib/Headers/stdalign.h b/clang/lib/Headers/stdalign.h
index 6ad25db4539a1..8ae6e658dd0a2 100644
--- a/clang/lib/Headers/stdalign.h
+++ b/clang/lib/Headers/stdalign.h
@@ -10,6 +10,10 @@
 #ifndef __STDALIGN_H
 #define __STDALIGN_H
 
+/* FIXME: This is using the placeholder dates Clang produces for these macros
+   in C2x mode; switch to the correct values once they've been published. */
+#if defined(__cplusplus) ||                                                    \
+    (defined(__STDC_VERSION__) && __STDC_VERSION__ < 202000L)
 #ifndef __cplusplus
 #define alignas _Alignas
 #define alignof _Alignof
@@ -17,5 +21,6 @@
 
 #define __alignas_is_defined 1
 #define __alignof_is_defined 1
+#endif /* __STDC_VERSION__ */
 
 #endif /* __STDALIGN_H */

diff  --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index d654cdff847be..3106571728692 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -3934,6 +3934,8 @@ void Parser::ParseDeclarationSpecifiers(
       isStorageClass = true;
       break;
     case tok::kw_thread_local:
+      if (getLangOpts().C2x)
+        Diag(Tok, diag::warn_c2x_compat_keyword) << Tok.getName();
       isInvalid = DS.SetStorageClassSpecThread(DeclSpec::TSCS_thread_local, Loc,
                                                PrevSpec, DiagID);
       isStorageClass = true;
@@ -4169,6 +4171,9 @@ void Parser::ParseDeclarationSpecifiers(
                                      DiagID, Policy);
       break;
     case tok::kw_bool:
+      if (getLangOpts().C2x)
+        Diag(Tok, diag::warn_c2x_compat_keyword) << Tok.getName();
+      [[fallthrough]];
     case tok::kw__Bool:
       if (Tok.is(tok::kw__Bool) && !getLangOpts().C99)
         Diag(Tok, diag::ext_c99_feature) << Tok.getName();
@@ -7657,8 +7662,7 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
   bool IsUnqual = Tok.is(tok::kw_typeof_unqual);
   const IdentifierInfo *II = Tok.getIdentifierInfo();
   if (getLangOpts().C2x && !II->getName().startswith("__"))
-    Diag(Tok.getLocation(), diag::warn_c2x_compat_typeof_type_specifier)
-        << IsUnqual;
+    Diag(Tok.getLocation(), diag::warn_c2x_compat_keyword) << Tok.getName();
 
   Token OpTok = Tok;
   SourceLocation StartLoc = ConsumeToken();
@@ -7858,7 +7862,7 @@ void Parser::DiagnoseBitIntUse(const Token &Tok) {
     // In C2x mode, diagnose that the use is not compatible with pre-C2x modes.
     // Otherwise, diagnose that the use is a Clang extension.
     if (getLangOpts().C2x)
-      Diag(Loc, diag::warn_c17_compat_bit_int);
+      Diag(Loc, diag::warn_c2x_compat_keyword) << Tok.getName();
     else
       Diag(Loc, diag::ext_bit_int) << getLangOpts().CPlusPlus;
   }

diff  --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index c7d8eb0af99d4..c2403f0d6f439 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -965,7 +965,9 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd) {
     Diag(Tok, diag::ext_c11_feature) << Tok.getName();
   if (Tok.is(tok::kw_static_assert)) {
     if (!getLangOpts().CPlusPlus) {
-      if (!getLangOpts().C2x)
+      if (getLangOpts().C2x)
+        Diag(Tok, diag::warn_c2x_compat_keyword) << Tok.getName();
+      else
         Diag(Tok, diag::ext_ms_static_assert) << FixItHint::CreateReplacement(
             Tok.getLocation(), "_Static_assert");
     } else
@@ -4457,7 +4459,10 @@ void Parser::ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs,
                                                   CachedTokens &OpenMPTokens,
                                                   SourceLocation *EndLoc) {
   if (Tok.is(tok::kw_alignas)) {
-    Diag(Tok.getLocation(), diag::warn_cxx98_compat_alignas);
+    if (getLangOpts().C2x)
+      Diag(Tok, diag::warn_c2x_compat_keyword) << Tok.getName();
+    else
+      Diag(Tok.getLocation(), diag::warn_cxx98_compat_alignas);
     ParseAlignmentSpecifier(Attrs, EndLoc);
     return;
   }

diff  --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index 66d937ac5742d..e2ada6ad9f82b 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -1007,8 +1007,8 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
     if (getLangOpts().CPlusPlus)
       Diag(Tok, diag::warn_cxx98_compat_nullptr);
     else
-      Diag(Tok, getLangOpts().C2x ? diag::warn_c17_compat_nullptr
-                                  : diag::ext_c_nullptr);
+      Diag(Tok, getLangOpts().C2x ? diag::warn_c2x_compat_keyword
+                                  : diag::ext_c_nullptr) << Tok.getName();
 
     Res = Actions.ActOnCXXNullPtrLiteral(ConsumeToken());
     break;
@@ -2484,8 +2484,11 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() {
                                                 RParenLoc);
   }
 
-  if (OpTok.isOneOf(tok::kw_alignof, tok::kw__Alignof))
+  if (getLangOpts().CPlusPlus &&
+      OpTok.isOneOf(tok::kw_alignof, tok::kw__Alignof))
     Diag(OpTok, diag::warn_cxx98_compat_alignof);
+  else if (getLangOpts().C2x && OpTok.is(tok::kw_alignof))
+    Diag(OpTok, diag::warn_c2x_compat_keyword) << OpTok.getName();
 
   EnterExpressionEvaluationContext Unevaluated(
       Actions, Sema::ExpressionEvaluationContext::Unevaluated,

diff  --git a/clang/test/C/C2x/n2934.c b/clang/test/C/C2x/n2934.c
new file mode 100644
index 0000000000000..d36e0b76344a3
--- /dev/null
+++ b/clang/test/C/C2x/n2934.c
@@ -0,0 +1,57 @@
+// RUN: %clang_cc1 -ffreestanding -verify=c2x -std=c2x -Wpre-c2x-compat %s
+// RUN: %clang_cc1 -ffreestanding -verify=c17 -std=c17 %s
+
+/* WG14 N2934: yes
+ * Revise spelling of keywords v7
+ */
+
+thread_local struct alignas(int) S { // c2x-warning {{'alignas' is incompatible with C standards before C2x}} \
+                                        c2x-warning {{'thread_local' is incompatible with C standards before C2x}} \
+                                        c17-error {{unknown type name 'thread_local'}} \
+                                        c17-error {{expected identifier or '('}} \
+                                        c17-error {{expected ')'}} \
+                                        c17-note {{to match this '('}}
+  bool b; // c2x-warning {{'bool' is incompatible with C standards before C2x}}
+} s; // c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}}
+
+static_assert(alignof(struct S) == alignof(int), ""); // c2x-warning {{'static_assert' is incompatible with C standards before C2x}} \
+                                                         c2x-warning 2 {{'alignof' is incompatible with C standards before C2x}} \
+                                                         c17-error 2 {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} \
+                                                         c17-error {{expected ')'}} \
+                                                         c17-warning {{declaration of 'struct S' will not be visible outside of this function}} \
+                                                         c17-note {{to match this '('}}
+
+#include <stdalign.h>
+
+// C17 and earlier must have __alignas_is_defined and __alignof_is_defined,
+// but C2x and later must not.
+#if __STDC_VERSION__ <= 201710L
+  #if __alignas_is_defined != 1
+    #error "alignas should be defined"
+  #endif
+  #if __alignof_is_defined != 1
+    #error "alignof should be defined"
+  #endif
+#else
+  #ifdef __alignas_is_defined
+    #error "alignas should not be defined"
+  #endif
+  #ifdef __alignof_is_defined
+    #error "alignof should not be defined"
+  #endif
+#endif
+
+#include <stdbool.h>
+
+// C17 and earlier must have bool defined as a macro, but C2x and later should
+// not (at least in Clang's implementation; it's permissible for bool to be a
+// macro in general, as it could expand to _Bool).
+#if __STDC_VERSION__ <= 201710L
+  #ifndef bool
+    #error "bool should be defined"
+  #endif
+#else
+  #ifdef bool
+    #error "bool should not be defined"
+  #endif
+#endif

diff  --git a/clang/www/c_status.html b/clang/www/c_status.html
index f8cd9f1fd2fcc..7665d24a381dc 100644
--- a/clang/www/c_status.html
+++ b/clang/www/c_status.html
@@ -1105,7 +1105,7 @@ <h2 id="c2x">C2x implementation status</h2>
     <tr>
       <td>Revise spelling of keywords v7</td>
       <td><a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2934.pdf">N2934</a></td>
-      <td class="none" align="center">No</td>
+      <td class="unreleased" align="center">Clang 17</td>
     </tr>
     <tr>
       <td>Make false and true first-class language features v8</td>


        


More information about the cfe-commits mailing list