[clang] 41667a8 - Diagnosing the Future Keywords

Aaron Ballman via cfe-commits cfe-commits at lists.llvm.org
Fri Aug 26 06:20:25 PDT 2022


Author: Muhammad Usman Shahid
Date: 2022-08-26T09:20:05-04:00
New Revision: 41667a8b9b624e282e7c08fadf7091223728d1c1

URL: https://github.com/llvm/llvm-project/commit/41667a8b9b624e282e7c08fadf7091223728d1c1
DIFF: https://github.com/llvm/llvm-project/commit/41667a8b9b624e282e7c08fadf7091223728d1c1.diff

LOG: Diagnosing the Future Keywords

The patch diagnoses an identifier as a future keyword if it exists in a
future language mode, such as:

int restrict;

in C modes earlier than C99. We now give a warning to the user that
such an identifier is a future keyword. Handles keywords from C as well
as C++.

Differential Revision: https://reviews.llvm.org/D131683

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/include/clang/Basic/DiagnosticGroups.td
    clang/include/clang/Basic/DiagnosticLexKinds.td
    clang/include/clang/Basic/IdentifierTable.h
    clang/include/clang/Basic/TokenKinds.def
    clang/lib/Basic/IdentifierTable.cpp
    clang/lib/Lex/Preprocessor.cpp
    clang/lib/Parse/ParseDeclCXX.cpp
    clang/test/Lexer/keywords_test.c
    clang/test/Lexer/keywords_test.cpp
    clang/test/Parser/static_assert.c

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index f1be1cd1e44f..75f7f7f293f4 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -106,6 +106,13 @@ Improvements to Clang's diagnostics
   compile-time value and printed out if the assertion fails.
 - Diagnostics about uninitialized ``constexpr`` varaibles have been improved
   to mention the missing constant initializer.
+- Correctly diagnose a future keyword if it exist as a keyword in the higher
+  language version and specifies in which version it will be a keyword. This
+  supports both c and c++ language.
+
+ Non-comprehensive list of changes in this release
+ -------------------------------------------------
+
 
 Non-comprehensive list of changes in this release
 -------------------------------------------------

diff  --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index 4412c93683ed..ba2fef2a8085 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -139,6 +139,7 @@ def MacroRedefined : DiagGroup<"macro-redefined">;
 def BuiltinMacroRedefined : DiagGroup<"builtin-macro-redefined">;
 def BuiltinRequiresHeader : DiagGroup<"builtin-requires-header">;
 def C99Compat : DiagGroup<"c99-compat">;
+def C2xCompat : DiagGroup<"c2x-compat">;
 def CXXCompat: DiagGroup<"c++-compat">;
 def ExternCCompat : DiagGroup<"extern-c-compat">;
 def KeywordCompat : DiagGroup<"keyword-compat">;

diff  --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td
index 6032fbd18d56..fd5398fa0409 100644
--- a/clang/include/clang/Basic/DiagnosticLexKinds.td
+++ b/clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -80,6 +80,10 @@ def warn_cxx11_keyword : Warning<"'%0' is a keyword in C++11">,
   InGroup<CXX11Compat>, DefaultIgnore;
 def warn_cxx20_keyword : Warning<"'%0' is a keyword in C++20">,
   InGroup<CXX20Compat>, DefaultIgnore;
+def warn_c99_keyword : Warning<"'%0' is a keyword in C99">,
+  InGroup<C99Compat>, DefaultIgnore;
+def warn_c2x_keyword : Warning<"'%0' is a keyword in C2x">,
+  InGroup<C2xCompat>, DefaultIgnore;
 
 def ext_unterminated_char_or_string : ExtWarn<
   "missing terminating %select{'|'\"'}0 character">, InGroup<InvalidPPToken>;

diff  --git a/clang/include/clang/Basic/IdentifierTable.h b/clang/include/clang/Basic/IdentifierTable.h
index aaf1297c1a64..1e89aa5f670f 100644
--- a/clang/include/clang/Basic/IdentifierTable.h
+++ b/clang/include/clang/Basic/IdentifierTable.h
@@ -17,6 +17,7 @@
 
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/TokenKinds.h"
+#include "clang/Lex/LexDiagnostic.h"
 #include "llvm/ADT/DenseMapInfo.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringMap.h"
@@ -668,6 +669,12 @@ class IdentifierTable {
   /// Populate the identifier table with info about the language keywords
   /// for the language specified by \p LangOpts.
   void AddKeywords(const LangOptions &LangOpts);
+
+  /// Returns the correct diagnostic to issue for a future-compat diagnostic
+  /// warning. Note, this function assumes the identifier passed has already
+  /// been determined to be a future compatible keyword.
+  diag::kind getFutureCompatDiagKind(const IdentifierInfo &II,
+                                     const LangOptions &LangOpts);
 };
 
 /// A family of Objective-C methods.

diff  --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index 7f421add92aa..729442a79f05 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -28,6 +28,9 @@
 #ifndef CXX20_KEYWORD
 #define CXX20_KEYWORD(X,Y) KEYWORD(X,KEYCXX20|(Y))
 #endif
+#ifndef C99_KEYWORD
+#define C99_KEYWORD(X,Y) KEYWORD(X,KEYC99|(Y))
+#endif
 #ifndef COROUTINES_KEYWORD
 #define COROUTINES_KEYWORD(X) CXX20_KEYWORD(X,KEYCOROUTINES)
 #endif
@@ -250,6 +253,7 @@ PUNCTUATOR(caretcaret,            "^^")
 //              always be treated as a keyword
 //   KEYC99   - This is a keyword introduced to C in C99
 //   KEYC11   - This is a keyword introduced to C in C11
+//   KEYC2X   - This is a keyword introduced to C in C2x
 //   KEYCXX   - This is a C++ keyword, or a C++-specific keyword in the
 //              implementation namespace
 //   KEYNOCXX - This is a keyword in every non-C++ dialect.
@@ -291,13 +295,11 @@ KEYWORD(float                       , KEYALL)
 KEYWORD(for                         , KEYALL)
 KEYWORD(goto                        , KEYALL)
 KEYWORD(if                          , KEYALL)
-KEYWORD(inline                      , KEYC99|KEYCXX|KEYGNU)
 KEYWORD(int                         , KEYALL)
 KEYWORD(_ExtInt                     , KEYALL)
 KEYWORD(_BitInt                     , KEYALL)
 KEYWORD(long                        , KEYALL)
 KEYWORD(register                    , KEYALL)
-KEYWORD(restrict                    , KEYC99)
 KEYWORD(return                      , KEYALL)
 KEYWORD(short                       , KEYALL)
 KEYWORD(signed                      , KEYALL)
@@ -328,7 +330,7 @@ KEYWORD(__objc_no                   , KEYALL)
 
 // C++ 2.11p1: Keywords.
 KEYWORD(asm                         , KEYCXX|KEYGNU)
-KEYWORD(bool                        , BOOLSUPPORT)
+KEYWORD(bool                        , KEYCXX|KEYOPENCLC|KEYOPENCLCXX|KEYC2X)
 KEYWORD(catch                       , KEYCXX)
 KEYWORD(class                       , KEYCXX)
 KEYWORD(const_cast                  , KEYCXX)
@@ -336,7 +338,7 @@ KEYWORD(delete                      , KEYCXX)
 KEYWORD(dynamic_cast                , KEYCXX)
 KEYWORD(explicit                    , KEYCXX)
 KEYWORD(export                      , KEYCXX)
-KEYWORD(false                       , BOOLSUPPORT)
+KEYWORD(false                       , KEYCXX|KEYOPENCLC|KEYOPENCLCXX|KEYC2X)
 KEYWORD(friend                      , KEYCXX)
 KEYWORD(mutable                     , KEYCXX)
 KEYWORD(namespace                   , KEYCXX)
@@ -350,7 +352,7 @@ KEYWORD(static_cast                 , KEYCXX)
 KEYWORD(template                    , KEYCXX)
 KEYWORD(this                        , KEYCXX)
 KEYWORD(throw                       , KEYCXX)
-KEYWORD(true                        , BOOLSUPPORT)
+KEYWORD(true                        , KEYCXX|KEYOPENCLC|KEYOPENCLCXX|KEYC2X)
 KEYWORD(try                         , KEYCXX)
 KEYWORD(typename                    , KEYCXX)
 KEYWORD(typeid                      , KEYCXX)
@@ -371,18 +373,23 @@ CXX_KEYWORD_OPERATOR(or_eq   , pipeequal)
 CXX_KEYWORD_OPERATOR(xor     , caret)
 CXX_KEYWORD_OPERATOR(xor_eq  , caretequal)
 
+// C99 Keywords.
+C99_KEYWORD(restrict                    , 0)
+C99_KEYWORD(inline                      , KEYCXX|KEYGNU)
+
+
 // C++11 keywords
-CXX11_KEYWORD(alignas               , 0)
+CXX11_KEYWORD(alignas               , KEYC2X)
 // alignof and _Alignof return the required ABI alignment
-CXX11_UNARY_EXPR_OR_TYPE_TRAIT(alignof, AlignOf, 0)
+CXX11_UNARY_EXPR_OR_TYPE_TRAIT(alignof, AlignOf, KEYC2X)
 CXX11_KEYWORD(char16_t              , KEYNOMS18)
 CXX11_KEYWORD(char32_t              , KEYNOMS18)
 CXX11_KEYWORD(constexpr             , 0)
 CXX11_KEYWORD(decltype              , 0)
 CXX11_KEYWORD(noexcept              , 0)
 CXX11_KEYWORD(nullptr               , 0)
-CXX11_KEYWORD(static_assert         , KEYMSCOMPAT)
-CXX11_KEYWORD(thread_local          , 0)
+CXX11_KEYWORD(static_assert         , KEYMSCOMPAT|KEYC2X)
+CXX11_KEYWORD(thread_local          , KEYC2X)
 
 // C++20 / coroutines TS keywords
 COROUTINES_KEYWORD(co_await)
@@ -444,7 +451,7 @@ KEYWORD(__PRETTY_FUNCTION__         , KEYALL)
 KEYWORD(__auto_type                 , KEYALL)
 
 // GNU Extensions (outside impl-reserved namespace)
-KEYWORD(typeof                      , KEYGNU)
+KEYWORD(typeof                      , KEYGNU|KEYC2X)
 
 // MS Extensions
 KEYWORD(__FUNCDNAME__               , KEYMS)
@@ -935,3 +942,4 @@ ANNOTATION(header_unit)
 #undef KEYWORD
 #undef PUNCTUATOR
 #undef TOK
+#undef C99_KEYWORD

diff  --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp
index 06f0850430f2..5d413a8da6d3 100644
--- a/clang/lib/Basic/IdentifierTable.cpp
+++ b/clang/lib/Basic/IdentifierTable.cpp
@@ -88,26 +88,25 @@ namespace {
     KEYCXX11      = 0x4,
     KEYGNU        = 0x8,
     KEYMS         = 0x10,
-    BOOLSUPPORT   = 0x20,
-    KEYALTIVEC    = 0x40,
-    KEYNOCXX      = 0x80,
-    KEYBORLAND    = 0x100,
-    KEYOPENCLC    = 0x200,
-    KEYC11        = 0x400,
-    KEYNOMS18     = 0x800,
-    KEYNOOPENCL   = 0x1000,
-    WCHARSUPPORT  = 0x2000,
-    HALFSUPPORT   = 0x4000,
-    CHAR8SUPPORT  = 0x8000,
-    KEYOBJC       = 0x10000,
-    KEYZVECTOR    = 0x20000,
-    KEYCOROUTINES = 0x40000,
-    KEYMODULES    = 0x80000,
-    KEYCXX20      = 0x100000,
-    KEYOPENCLCXX  = 0x200000,
-    KEYMSCOMPAT   = 0x400000,
-    KEYSYCL       = 0x800000,
-    KEYCUDA       = 0x1000000,
+    KEYALTIVEC    = 0x20,
+    KEYNOCXX      = 0x40,
+    KEYBORLAND    = 0x80,
+    KEYOPENCLC    = 0x100,
+    KEYC2X        = 0x200,
+    KEYNOMS18     = 0x400,
+    KEYNOOPENCL   = 0x800,
+    WCHARSUPPORT  = 0x1000,
+    HALFSUPPORT   = 0x2000,
+    CHAR8SUPPORT  = 0x4000,
+    KEYOBJC       = 0x8000,
+    KEYZVECTOR    = 0x10000,
+    KEYCOROUTINES = 0x20000,
+    KEYMODULES    = 0x40000,
+    KEYCXX20      = 0x80000,
+    KEYOPENCLCXX  = 0x100000,
+    KEYMSCOMPAT   = 0x200000,
+    KEYSYCL       = 0x400000,
+    KEYCUDA       = 0x800000,
     KEYMAX        = KEYCUDA, // The maximum key
     KEYALLCXX = KEYCXX | KEYCXX11 | KEYCXX20,
     KEYALL = (KEYMAX | (KEYMAX-1)) & ~KEYNOMS18 &
@@ -140,15 +139,13 @@ static KeywordStatus getKeywordStatusHelper(const LangOptions &LangOpts,
 
   switch (Flag) {
   case KEYC99:
-    // FIXME: This should have KS_Future logic here, but that can only happen if
-    // getFutureCompatDiagKind ALSO gets updated. This is safe, since C mode is
-    // ALWAYS implied.
-    return LangOpts.C99 ? KS_Enabled : KS_Unknown;
-  case KEYC11:
-    // FIXME: This should have KS_Future logic here, but that can only happen if
-    // getFutureCompatDiagKind ALSO gets updated. This is safe, since C mode is
-    // ALWAYS implied.
-    return LangOpts.C11 ? KS_Enabled : KS_Unknown;
+    if (LangOpts.C99)
+      return KS_Enabled;
+    return !LangOpts.CPlusPlus ? KS_Future : KS_Unknown;
+  case KEYC2X:
+    if (LangOpts.C2x)
+      return KS_Enabled;
+    return !LangOpts.CPlusPlus ? KS_Future : KS_Unknown;
   case KEYCXX:
     return LangOpts.CPlusPlus ? KS_Enabled : KS_Unknown;
   case KEYCXX11:
@@ -163,8 +160,6 @@ static KeywordStatus getKeywordStatusHelper(const LangOptions &LangOpts,
     return LangOpts.GNUKeywords ? KS_Extension : KS_Unknown;
   case KEYMS:
     return LangOpts.MicrosoftExt ? KS_Extension : KS_Unknown;
-  case BOOLSUPPORT:
-    return LangOpts.Bool ? KS_Enabled : KS_Unknown;
   case KEYALTIVEC:
     return LangOpts.AltiVec ? KS_Enabled : KS_Unknown;
   case KEYBORLAND:
@@ -845,3 +840,35 @@ StringRef clang::getNullabilitySpelling(NullabilityKind kind,
   }
   llvm_unreachable("Unknown nullability kind.");
 }
+
+diag::kind
+IdentifierTable::getFutureCompatDiagKind(const IdentifierInfo &II,
+                                         const LangOptions &LangOpts) {
+  assert(II.isFutureCompatKeyword() && "diagnostic should not be needed");
+
+  unsigned Flags = llvm::StringSwitch<unsigned>(II.getName())
+#define KEYWORD(NAME, FLAGS) .Case(#NAME, FLAGS)
+#include "clang/Basic/TokenKinds.def"
+#undef KEYWORD
+      ;
+
+  if (LangOpts.CPlusPlus) {
+    if ((Flags & KEYCXX11) == KEYCXX11)
+      return diag::warn_cxx11_keyword;
+
+    // char8_t is not modeled as a CXX20_KEYWORD because it's not
+    // unconditionally enabled in C++20 mode. (It can be disabled
+    // by -fno-char8_t.)
+    if (((Flags & KEYCXX20) == KEYCXX20) ||
+        ((Flags & CHAR8SUPPORT) == CHAR8SUPPORT))
+      return diag::warn_cxx20_keyword;
+  } else {
+    if ((Flags & KEYC99) == KEYC99)
+      return diag::warn_c99_keyword;
+    if ((Flags & KEYC2X) == KEYC2X)
+      return diag::warn_c2x_keyword;
+  }
+
+  llvm_unreachable(
+      "Keyword not known to come from a newer Standard or proposed Standard");
+}

diff  --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp
index 8c4859de045a..6af415a96b7c 100644
--- a/clang/lib/Lex/Preprocessor.cpp
+++ b/clang/lib/Lex/Preprocessor.cpp
@@ -773,29 +773,6 @@ void Preprocessor::HandlePoisonedIdentifier(Token & Identifier) {
     Diag(Identifier,it->second) << Identifier.getIdentifierInfo();
 }
 
-/// Returns a diagnostic message kind for reporting a future keyword as
-/// appropriate for the identifier and specified language.
-static diag::kind getFutureCompatDiagKind(const IdentifierInfo &II,
-                                          const LangOptions &LangOpts) {
-  assert(II.isFutureCompatKeyword() && "diagnostic should not be needed");
-
-  if (LangOpts.CPlusPlus)
-    return llvm::StringSwitch<diag::kind>(II.getName())
-#define CXX11_KEYWORD(NAME, FLAGS)                                             \
-        .Case(#NAME, diag::warn_cxx11_keyword)
-#define CXX20_KEYWORD(NAME, FLAGS)                                             \
-        .Case(#NAME, diag::warn_cxx20_keyword)
-#include "clang/Basic/TokenKinds.def"
-        // char8_t is not modeled as a CXX20_KEYWORD because it's not
-        // unconditionally enabled in C++20 mode. (It can be disabled
-        // by -fno-char8_t.)
-        .Case("char8_t", diag::warn_cxx20_keyword)
-        ;
-
-  llvm_unreachable(
-      "Keyword not known to come from a newer Standard or proposed Standard");
-}
-
 void Preprocessor::updateOutOfDateIdentifier(IdentifierInfo &II) const {
   assert(II.isOutOfDate() && "not out of date");
   getExternalSource()->updateOutOfDateIdentifier(II);
@@ -867,7 +844,7 @@ bool Preprocessor::HandleIdentifier(Token &Identifier) {
   // FIXME: This warning is disabled in cases where it shouldn't be, like
   //   "#define constexpr constexpr", "int constexpr;"
   if (II.isFutureCompatKeyword() && !DisableMacroExpansion) {
-    Diag(Identifier, getFutureCompatDiagKind(II, getLangOpts()))
+    Diag(Identifier, getIdentifierTable().getFutureCompatDiagKind(II, getLangOpts()))
         << II.getName();
     // Don't diagnose this keyword again in this translation unit.
     II.setIsFutureCompatKeyword(false);

diff  --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 4510ff8470fa..d0bf89799c25 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -935,10 +935,11 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd) {
   if (Tok.is(tok::kw__Static_assert) && !getLangOpts().C11)
     Diag(Tok, diag::ext_c11_feature) << Tok.getName();
   if (Tok.is(tok::kw_static_assert)) {
-    if (!getLangOpts().CPlusPlus)
-      Diag(Tok, diag::ext_ms_static_assert)
-          << FixItHint::CreateReplacement(Tok.getLocation(), "_Static_assert");
-    else
+    if (!getLangOpts().CPlusPlus) {
+      if (!getLangOpts().C2x)
+        Diag(Tok, diag::ext_ms_static_assert) << FixItHint::CreateReplacement(
+            Tok.getLocation(), "_Static_assert");
+    } else
       Diag(Tok, diag::warn_cxx98_compat_static_assert);
   }
 

diff  --git a/clang/test/Lexer/keywords_test.c b/clang/test/Lexer/keywords_test.c
index 16778143f0ba..a207839a8f98 100644
--- a/clang/test/Lexer/keywords_test.c
+++ b/clang/test/Lexer/keywords_test.c
@@ -14,6 +14,40 @@
 // RUN: %clang_cc1 -std=c99 -fms-extensions -fno-declspec -E %s -o - \
 // RUN:     | FileCheck --check-prefix=CHECK-MS-KEYWORDS-WITHOUT-DECLSPEC %s
 
+// RUN: %clang_cc1 -std=c99 -DC99 -fsyntax-only %s
+// RUN: %clang_cc1 -std=c2x -DC99 -DC2x -fsyntax-only %s
+
+// RUN: %clang_cc1 -fsyntax-only -std=c89 -DFutureKeyword -Wc2x-compat -Wc99-compat -verify=c89 %s
+
+#define IS_KEYWORD(NAME) _Static_assert(!__is_identifier(NAME), #NAME)
+#define NOT_KEYWORD(NAME) _Static_assert(__is_identifier(NAME), #NAME)
+
+#if defined(C99)
+#define C99_KEYWORD(NAME)  IS_KEYWORD(NAME)
+#else
+#define C99_KEYWORD(NAME)  NOT_KEYWORD(NAME)
+#endif
+
+#if defined(C2x)
+#define C2x_KEYWORD(NAME)  IS_KEYWORD(NAME)
+#else
+#define C2x_KEYWORD(NAME)  NOT_KEYWORD(NAME)
+#endif
+
+// C99 Keywords.
+C99_KEYWORD(restrict);
+C99_KEYWORD(inline);
+
+// C2x Keywords.
+C2x_KEYWORD(bool);
+C2x_KEYWORD(true);
+C2x_KEYWORD(false);
+C2x_KEYWORD(static_assert);
+C2x_KEYWORD(typeof);
+C2x_KEYWORD(thread_local);
+C2x_KEYWORD(alignas);
+C2x_KEYWORD(alignof);
+
 void f() {
 // CHECK-NONE: int asm
 // CHECK-GNU-KEYWORDS: asm ("ret" : :)
@@ -52,3 +86,18 @@ void no_static_assert();
 #else
 void has_static_assert();
 #endif
+
+#ifdef FutureKeyword
+
+  int restrict; // c89-warning {{'restrict' is a keyword in C99}}
+  int inline;  // c89-warning {{'inline' is a keyword in C99}}
+
+  int bool; // c89-warning {{'bool' is a keyword in C2x}}
+  char true; // c89-warning {{'true' is a keyword in C2x}}
+  char false; // c89-warning {{'false' is a keyword in C2x}}
+  float alignof; // c89-warning {{'alignof' is a keyword in C2x}}
+  int typeof; // c89-warning {{'typeof' is a keyword in C2x}}
+  int alignas; // c89-warning {{'alignas' is a keyword in C2x}}
+  int static_assert; // c89-warning {{'static_assert' is a keyword in C2x}}
+
+#endif

diff  --git a/clang/test/Lexer/keywords_test.cpp b/clang/test/Lexer/keywords_test.cpp
index 0fb9a6a086d3..62a2aef8ff66 100644
--- a/clang/test/Lexer/keywords_test.cpp
+++ b/clang/test/Lexer/keywords_test.cpp
@@ -15,6 +15,8 @@
 // RUN: %clang -std=c++03 -target i686-windows-msvc -DMS -fno-declspec -fsyntax-only %s
 // RUN: %clang -std=c++03 -target x86_64-scei-ps4 -fno-declspec -fsyntax-only %s
 
+// RUN: %clang_cc1 -std=c++98 -DFutureKeyword -fsyntax-only -Wc++11-compat -Wc++20-compat -verify=cxx98 %s
+
 #define IS_KEYWORD(NAME) _Static_assert(!__is_identifier(NAME), #NAME)
 #define NOT_KEYWORD(NAME) _Static_assert(__is_identifier(NAME), #NAME)
 #define IS_TYPE(NAME) void is_##NAME##_type() { int f(NAME); }
@@ -50,17 +52,24 @@ CXX11_KEYWORD(char32_t);
 CXX11_TYPE(char32_t);
 CXX11_KEYWORD(constexpr);
 CXX11_KEYWORD(noexcept);
+
 #ifndef MS
 CXX11_KEYWORD(static_assert);
 #else
 // MS compiler recognizes static_assert in all modes. So should we.
 IS_KEYWORD(static_assert);
 #endif
+
 CXX11_KEYWORD(thread_local);
 
 // Concepts keywords
 CXX20_KEYWORD(concept);
 CXX20_KEYWORD(requires);
+CXX20_KEYWORD(consteval);
+CXX20_KEYWORD(constinit);
+CXX20_KEYWORD(co_await);
+CXX20_KEYWORD(co_return);
+CXX20_KEYWORD(co_yield);
 
 // __declspec extension
 DECLSPEC_KEYWORD(__declspec);
@@ -70,3 +79,26 @@ IS_KEYWORD(__char16_t);
 IS_TYPE(__char16_t);
 IS_KEYWORD(__char32_t);
 IS_TYPE(__char32_t);
+
+#ifdef FutureKeyword
+
+int nullptr; // cxx98-warning {{'nullptr' is a keyword in C++11}}
+int decltype;  // cxx98-warning {{'decltype' is a keyword in C++11}}
+int alignof;  // cxx98-warning {{'alignof' is a keyword in C++11}}
+int alignas;  // cxx98-warning {{'alignas' is a keyword in C++11}}
+int char16_t;  // cxx98-warning {{'char16_t' is a keyword in C++11}}
+int char32_t;  // cxx98-warning {{'char32_t' is a keyword in C++11}}
+int constexpr;  // cxx98-warning {{'constexpr' is a keyword in C++11}}
+int noexcept;  // cxx98-warning {{'noexcept' is a keyword in C++11}}
+int static_assert; // cxx98-warning {{'static_assert' is a keyword in C++11}}
+char thread_local; // cxx98-warning {{'thread_local' is a keyword in C++11}}
+
+int co_await; // cxx98-warning {{'co_await' is a keyword in C++20}}
+char co_return; // cxx98-warning {{'co_return' is a keyword in C++20}}
+char co_yield; // cxx98-warning {{'co_yield' is a keyword in C++20}}
+int constinit; // cxx98-warning {{'constinit' is a keyword in C++20}}
+int consteval; // cxx98-warning {{'consteval' is a keyword in C++20}}
+int requires; // cxx98-warning {{'requires' is a keyword in C++20}}
+int concept; // cxx98-warning {{'concept' is a keyword in C++20}}
+
+#endif

diff  --git a/clang/test/Parser/static_assert.c b/clang/test/Parser/static_assert.c
index c57e3b0e0680..08b2c37f8afe 100644
--- a/clang/test/Parser/static_assert.c
+++ b/clang/test/Parser/static_assert.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c2x -DTEST_SPELLING -verify=c2x %s
-// RUN: %clang_cc1 -fsyntax-only -std=c2x -DTEST_SPELLING -fms-compatibility -verify=c2x-ms %s
+// RUN: %clang_cc1 -fsyntax-only -std=c17 -DTEST_SPELLING -Wc2x-compat -verify=c17 %s
+// RUN: %clang_cc1 -fsyntax-only -std=c17 -DTEST_SPELLING -fms-compatibility -verify=c17-ms %s
 // RUN: %clang_cc1 -fsyntax-only -std=c2x -Wpre-c2x-compat -verify=c2x-compat %s
 // RUN: %clang_cc1 -fsyntax-only -std=c99 -verify=c99 %s
 // RUN: %clang_cc1 -fsyntax-only -std=c99 -pedantic -verify=c99-pedantic %s
@@ -15,11 +15,13 @@
 // Only test the C++ spelling in C mode in some of the tests, to reduce the
 // amount of diagnostics to have to check. This spelling is allowed in MS-
 // compatibility mode in C, but otherwise produces errors.
-static_assert(1, ""); // c2x-error {{expected parameter declarator}} \
-                      // c2x-error {{expected ')'}} \
-                      // c2x-note {{to match this '('}} \
-                      // c2x-error {{a type specifier is required for all declarations}} \
-                      // c2x-ms-warning {{use of 'static_assert' without inclusion of <assert.h> is a Microsoft extension}}
+static_assert(1, ""); // c17-warning {{'static_assert' is a keyword in C2x}} \
+                      // c17-error {{expected parameter declarator}} \
+                      // c17-error {{expected ')'}} \
+                      // c17-note {{to match this '('}} \
+                      // c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} \
+                      // c17-ms-warning {{use of 'static_assert' without inclusion of <assert.h> is a Microsoft extension}}
+
 #endif
 
 // We support _Static_assert as an extension in older C modes and in all C++
@@ -42,4 +44,6 @@ _Static_assert(1); // c99-pedantic-warning {{'_Static_assert' with no message is
                    // cxx17-compat-warning {{'static_assert' with no message is incompatible with C++ standards before C++17}} \
                    // c99-pedantic-warning {{'_Static_assert' is a C11 extension}} \
                    // cxx17-pedantic-warning {{'_Static_assert' is a C11 extension}} \
-                   // cxx98-pedantic-warning {{'_Static_assert' is a C11 extension}}
+                   // cxx98-pedantic-warning {{'_Static_assert' is a C11 extension}} \
+                   // c17-warning {{'_Static_assert' with no message is a C2x extension}} \
+                   // c17-ms-warning {{'_Static_assert' with no message is a C2x extension}}


        


More information about the cfe-commits mailing list