diff options
author | Muhammad Usman Shahid <codesbyusman@gmail.com> | 2022-08-26 09:17:14 -0400 |
---|---|---|
committer | Aaron Ballman <aaron@aaronballman.com> | 2022-08-26 09:20:05 -0400 |
commit | 41667a8b9b624e282e7c08fadf7091223728d1c1 (patch) | |
tree | fd845d5f127d655f70888e733fe832ad70e77534 /clang/lib | |
parent | 5af06ba7dc26f614989a9a9e16e69f6ecc811519 (diff) | |
download | llvm-41667a8b9b624e282e7c08fadf7091223728d1c1.zip llvm-41667a8b9b624e282e7c08fadf7091223728d1c1.tar.gz llvm-41667a8b9b624e282e7c08fadf7091223728d1c1.tar.bz2 |
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
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Basic/IdentifierTable.cpp | 89 | ||||
-rw-r--r-- | clang/lib/Lex/Preprocessor.cpp | 25 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDeclCXX.cpp | 9 |
3 files changed, 64 insertions, 59 deletions
diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp index 06f0850..5d413a8 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 8c4859d..6af415a 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 4510ff8..d0bf897 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); } |