mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-01 01:31:26 +00:00
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
This commit is contained in:
parent
5af06ba7dc
commit
41667a8b9b
@ -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
|
||||
-------------------------------------------------
|
||||
|
@ -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">;
|
||||
|
@ -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>;
|
||||
|
@ -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 @@ public:
|
||||
/// 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.
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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}}
|
||||
|
Loading…
Reference in New Issue
Block a user