[C] Diagnose use of C++ keywords in C (#137234)
This adds a new diagnostic group, -Wc++-keyword, which is off by default and grouped under -Wc++-compat. The diagnostic catches use of C++ keywords in C code. This change additionally fixes an issue with -Wreserved-identifier not diagnosing use of reserved identifiers in function parameter lists in a function declaration which is not a definition. Fixes https://github.com/llvm/llvm-project/issues/21898
This commit is contained in:
parent
3d4f979e27
commit
85c810060e
@ -154,6 +154,8 @@ C Language Changes
|
||||
- Added ``-Wimplicit-void-ptr-cast``, grouped under ``-Wc++-compat``, which
|
||||
diagnoses implicit conversion from ``void *`` to another pointer type as
|
||||
being incompatible with C++. (#GH17792)
|
||||
- Added ``-Wc++-keyword``, grouped under ``-Wc++-compat``, which diagnoses when
|
||||
a C++ keyword is used as an identifier in C. (#GH21898)
|
||||
- Added ``-Wc++-hidden-decl``, grouped under ``-Wc++-compat``, which diagnoses
|
||||
use of tag types which are visible in C but not visible in C++ due to scoping
|
||||
rules. e.g.,
|
||||
@ -482,6 +484,8 @@ Improvements to Clang's diagnostics
|
||||
- ``-Winitializer-overrides`` and ``-Wreorder-init-list`` are now grouped under
|
||||
the ``-Wc99-designator`` diagnostic group, as they also are about the
|
||||
behavior of the C99 feature as it was introduced into C++20. Fixes #GH47037
|
||||
- ``-Wreserved-identifier`` now fires on reserved parameter names in a function
|
||||
declaration which is not a definition.
|
||||
|
||||
Improvements to Clang's time-trace
|
||||
----------------------------------
|
||||
|
@ -157,6 +157,7 @@ def C99Compat : DiagGroup<"c99-compat">;
|
||||
def C23Compat : DiagGroup<"c23-compat">;
|
||||
def : DiagGroup<"c2x-compat", [C23Compat]>;
|
||||
|
||||
def CppKeywordInC : DiagGroup<"c++-keyword">;
|
||||
def DuplicateDeclSpecifier : DiagGroup<"duplicate-decl-specifier">;
|
||||
def InitStringTooLongMissingNonString :
|
||||
DiagGroup<"unterminated-string-initialization">;
|
||||
@ -178,9 +179,9 @@ def ImplicitIntToEnumCast : DiagGroup<"implicit-int-enum-cast",
|
||||
[ImplicitEnumEnumCast]>;
|
||||
def TentativeDefnCompat : DiagGroup<"tentative-definition-compat">;
|
||||
def CXXCompat: DiagGroup<"c++-compat", [ImplicitVoidPtrCast, DefaultConstInit,
|
||||
ImplicitIntToEnumCast, HiddenCppDecl,
|
||||
InitStringTooLongForCpp,
|
||||
TentativeDefnCompat,
|
||||
ImplicitIntToEnumCast, CppKeywordInC,
|
||||
HiddenCppDecl, TentativeDefnCompat,
|
||||
InitStringTooLongForCpp,
|
||||
DuplicateDeclSpecifier]>;
|
||||
|
||||
def ExternCCompat : DiagGroup<"extern-c-compat">;
|
||||
|
@ -421,6 +421,9 @@ def warn_pp_macro_is_reserved_attribute_id : Warning<
|
||||
def warn_pp_objc_macro_redef_ignored : Warning<
|
||||
"ignoring redefinition of Objective-C qualifier macro">,
|
||||
InGroup<DiagGroup<"objc-macro-redefinition">>;
|
||||
def warn_pp_identifier_is_cpp_keyword : Warning<
|
||||
"identifier %0 conflicts with a C++ keyword">,
|
||||
InGroup<CppKeywordInC>, DefaultIgnore;
|
||||
|
||||
def pp_invalid_string_literal : Warning<
|
||||
"invalid string literal, ignoring final '\\'">;
|
||||
|
@ -195,7 +195,11 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo {
|
||||
LLVM_PREFERRED_TYPE(bool)
|
||||
unsigned IsFinal : 1;
|
||||
|
||||
// 22 bits left in a 64-bit word.
|
||||
// True if this identifier would be a keyword in C++ mode.
|
||||
LLVM_PREFERRED_TYPE(bool)
|
||||
unsigned IsKeywordInCpp : 1;
|
||||
|
||||
// 21 bits left in a 64-bit word.
|
||||
|
||||
// Managed by the language front-end.
|
||||
void *FETokenInfo = nullptr;
|
||||
@ -212,7 +216,7 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo {
|
||||
IsFromAST(false), ChangedAfterLoad(false), FEChangedAfterLoad(false),
|
||||
RevertedTokenID(false), OutOfDate(false), IsModulesImport(false),
|
||||
IsMangledOpenMPVariantName(false), IsDeprecatedMacro(false),
|
||||
IsRestrictExpansion(false), IsFinal(false) {}
|
||||
IsRestrictExpansion(false), IsFinal(false), IsKeywordInCpp(false) {}
|
||||
|
||||
public:
|
||||
IdentifierInfo(const IdentifierInfo &) = delete;
|
||||
@ -444,6 +448,10 @@ public:
|
||||
}
|
||||
bool isCPlusPlusOperatorKeyword() const { return IsCPPOperatorKeyword; }
|
||||
|
||||
/// Return true if this identifier would be a keyword in C++ mode.
|
||||
bool IsKeywordInCPlusPlus() const { return IsKeywordInCpp; }
|
||||
void setIsKeywordInCPlusPlus(bool Val = true) { IsKeywordInCpp = Val; }
|
||||
|
||||
/// Return true if this token is a keyword in the specified language.
|
||||
bool isKeyword(const LangOptions &LangOpts) const;
|
||||
|
||||
@ -462,6 +470,7 @@ public:
|
||||
/// If this returns false, we know that HandleIdentifier will not affect
|
||||
/// the token.
|
||||
bool isHandleIdentifierCase() const { return NeedsHandleIdentifier; }
|
||||
void setHandleIdentifierCase(bool Val = true) { NeedsHandleIdentifier = Val; }
|
||||
|
||||
/// Return true if the identifier in its current state was loaded
|
||||
/// from an AST file.
|
||||
|
@ -1042,6 +1042,7 @@ ANNOTATION(embed)
|
||||
#undef TYPE_TRAIT_2
|
||||
#undef TYPE_TRAIT_1
|
||||
#undef TYPE_TRAIT
|
||||
#undef MODULES_KEYWORD
|
||||
#undef CXX20_KEYWORD
|
||||
#undef CXX11_KEYWORD
|
||||
#undef KEYWORD
|
||||
|
@ -250,6 +250,32 @@ static KeywordStatus getKeywordStatus(const LangOptions &LangOpts,
|
||||
return CurStatus;
|
||||
}
|
||||
|
||||
static bool IsKeywordInCpp(unsigned Flags) {
|
||||
while (Flags != 0) {
|
||||
unsigned CurFlag = Flags & ~(Flags - 1);
|
||||
Flags = Flags & ~CurFlag;
|
||||
switch (static_cast<TokenKey>(CurFlag)) {
|
||||
case KEYCXX:
|
||||
case KEYCXX11:
|
||||
case KEYCXX20:
|
||||
case BOOLSUPPORT:
|
||||
case WCHARSUPPORT:
|
||||
case CHAR8SUPPORT:
|
||||
return true;
|
||||
default:
|
||||
break; // Go to the next flag, try again.
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void MarkIdentifierAsKeywordInCpp(IdentifierTable &Table,
|
||||
StringRef Name) {
|
||||
IdentifierInfo &II = Table.get(Name, tok::identifier);
|
||||
II.setIsKeywordInCPlusPlus();
|
||||
II.setHandleIdentifierCase();
|
||||
}
|
||||
|
||||
/// AddKeyword - This method is used to associate a token ID with specific
|
||||
/// identifiers because they are language keywords. This causes the lexer to
|
||||
/// automatically map matching identifiers to specialized token codes.
|
||||
@ -258,8 +284,18 @@ static void AddKeyword(StringRef Keyword,
|
||||
const LangOptions &LangOpts, IdentifierTable &Table) {
|
||||
KeywordStatus AddResult = getKeywordStatus(LangOpts, Flags);
|
||||
|
||||
// Don't add this keyword if disabled in this language.
|
||||
if (AddResult == KS_Disabled) return;
|
||||
// Don't add this keyword if disabled in this language and isn't otherwise
|
||||
// special.
|
||||
if (AddResult == KS_Disabled) {
|
||||
// We do not consider any identifiers to be C++ keywords when in
|
||||
// Objective-C because @ effectively introduces a custom grammar where C++
|
||||
// keywords can be used (and similar for selectors). We could enable this
|
||||
// for Objective-C, but it would require more logic to ensure we do not
|
||||
// issue compatibility diagnostics in these cases.
|
||||
if (!LangOpts.ObjC && IsKeywordInCpp(Flags))
|
||||
MarkIdentifierAsKeywordInCpp(Table, Keyword);
|
||||
return;
|
||||
}
|
||||
|
||||
IdentifierInfo &Info =
|
||||
Table.get(Keyword, AddResult == KS_Future ? tok::identifier : TokenCode);
|
||||
@ -304,9 +340,11 @@ void IdentifierTable::AddKeywords(const LangOptions &LangOpts) {
|
||||
#define ALIAS(NAME, TOK, FLAGS) \
|
||||
AddKeyword(StringRef(NAME), tok::kw_ ## TOK, \
|
||||
FLAGS, LangOpts, *this);
|
||||
#define CXX_KEYWORD_OPERATOR(NAME, ALIAS) \
|
||||
if (LangOpts.CXXOperatorNames) \
|
||||
AddCXXOperatorKeyword(StringRef(#NAME), tok::ALIAS, *this);
|
||||
#define CXX_KEYWORD_OPERATOR(NAME, ALIAS) \
|
||||
if (LangOpts.CXXOperatorNames) \
|
||||
AddCXXOperatorKeyword(StringRef(#NAME), tok::ALIAS, *this); \
|
||||
else \
|
||||
MarkIdentifierAsKeywordInCpp(*this, StringRef(#NAME));
|
||||
#define OBJC_AT_KEYWORD(NAME) \
|
||||
if (LangOpts.ObjC) \
|
||||
AddObjCKeyword(StringRef(#NAME), tok::objc_##NAME, *this);
|
||||
|
@ -834,6 +834,11 @@ bool Preprocessor::HandleIdentifier(Token &Identifier) {
|
||||
II.setIsFutureCompatKeyword(false);
|
||||
}
|
||||
|
||||
// If this identifier would be a keyword in C++, diagnose as a compatibility
|
||||
// issue.
|
||||
if (II.IsKeywordInCPlusPlus() && !DisableMacroExpansion)
|
||||
Diag(Identifier, diag::warn_pp_identifier_is_cpp_keyword) << &II;
|
||||
|
||||
// If this is an extension token, diagnose its use.
|
||||
// We avoid diagnosing tokens that originate from macro definitions.
|
||||
// FIXME: This warning is disabled in cases where it shouldn't be,
|
||||
|
@ -59,8 +59,10 @@
|
||||
#include "clang/Sema/SemaWasm.h"
|
||||
#include "clang/Sema/Template.h"
|
||||
#include "llvm/ADT/STLForwardCompat.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/Support/SaveAndRestore.h"
|
||||
#include "llvm/TargetParser/Triple.h"
|
||||
#include <algorithm>
|
||||
@ -10424,6 +10426,15 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
||||
// Finally, we know we have the right number of parameters, install them.
|
||||
NewFD->setParams(Params);
|
||||
|
||||
// If this declarator is a declaration and not a definition, its parameters
|
||||
// will not be pushed onto a scope chain. That means we will not issue any
|
||||
// reserved identifier warnings for the declaration, but we will for the
|
||||
// definition. Handle those here.
|
||||
if (!D.isFunctionDefinition()) {
|
||||
for (const ParmVarDecl *PVD : Params)
|
||||
warnOnReservedIdentifier(PVD);
|
||||
}
|
||||
|
||||
if (D.getDeclSpec().isNoreturnSpecified())
|
||||
NewFD->addAttr(
|
||||
C11NoReturnAttr::Create(Context, D.getDeclSpec().getNoreturnSpecLoc()));
|
||||
|
@ -59,8 +59,14 @@
|
||||
#pragma omp begin assumes ext // expected-warning {{valid begin assumes clauses start with 'ext_', 'absent', 'contains', 'holds', 'no_openmp', 'no_openmp_routines', 'no_openmp_constructs', 'no_parallelism'; token will be ignored}}
|
||||
#pragma omp end assumes
|
||||
|
||||
#pragma omp assumes ext_123(not allowed) // expected-warning {{'ext_123' clause should not be followed by arguments; tokens will be ignored}} expected-note {{the ignored tokens spans until here}}
|
||||
#pragma omp begin assumes ext_123(not allowed) // expected-warning {{'ext_123' clause should not be followed by arguments; tokens will be ignored}} expected-note {{the ignored tokens spans until here}}
|
||||
// FIXME: We should be getting an expected note about where the span of ignored
|
||||
// tokens ends. However, error recovery ends up lexing the 'not' token,
|
||||
// emitting a (silenced) diagnostic about use of a C++ keyword in C, and the
|
||||
// note gets associated with *that* (silenced) diagnostic. This is an existing
|
||||
// issue that also happens with error recovery of reserved identifiers or
|
||||
// extension tokens, but is unfortunate nonetheless.
|
||||
#pragma omp assumes ext_123(not allowed) // expected-warning {{'ext_123' clause should not be followed by arguments; tokens will be ignored}}
|
||||
#pragma omp begin assumes ext_123(not allowed) // expected-warning {{'ext_123' clause should not be followed by arguments; tokens will be ignored}}
|
||||
#pragma omp end assumes
|
||||
|
||||
#pragma omp end assumes // expected-error {{'#pragma omp end assumes' with no matching '#pragma omp begin assumes'}}
|
||||
|
239
clang/test/Sema/c++-keyword-in-c.c
Normal file
239
clang/test/Sema/c++-keyword-in-c.c
Normal file
@ -0,0 +1,239 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify -Wc++-keyword %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify -Wc++-compat %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify=good %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify=cxx -x c++ -std=c++2c %s
|
||||
// good-no-diagnostics
|
||||
|
||||
// 'try', 'this' and 'throw' are not tested as identifiers, but are instead
|
||||
// tested as other constructs (otherwise there would be redefinition errors in
|
||||
// C).
|
||||
int catch; // expected-warning {{identifier 'catch' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected unqualified-id}}
|
||||
int class; // expected-warning {{identifier 'class' conflicts with a C++ keyword}} \
|
||||
cxx-error {{declaration of anonymous class must be a definition}} \
|
||||
cxx-warning {{declaration does not declare anything}}
|
||||
int const_cast; // expected-warning {{identifier 'const_cast' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected unqualified-id}}
|
||||
int delete; // expected-warning {{identifier 'delete' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected unqualified-id}}
|
||||
int dynamic_cast; // expected-warning {{identifier 'dynamic_cast' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected unqualified-id}}
|
||||
int explicit; // expected-warning {{identifier 'explicit' conflicts with a C++ keyword}} \
|
||||
cxx-error {{'explicit' can only appear on non-static member functions}} \
|
||||
cxx-warning {{declaration does not declare anything}}
|
||||
int export; // expected-warning {{identifier 'export' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected unqualified-id}}
|
||||
int friend; // expected-warning {{identifier 'friend' conflicts with a C++ keyword}} \
|
||||
cxx-error {{'friend' used outside of class}} \
|
||||
cxx-warning {{declaration does not declare anything}}
|
||||
int mutable; // expected-warning {{identifier 'mutable' conflicts with a C++ keyword}} \
|
||||
cxx-warning {{declaration does not declare anything}}
|
||||
int namespace; // expected-warning {{identifier 'namespace' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected unqualified-id}}
|
||||
int new; // expected-warning {{identifier 'new' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected unqualified-id}}
|
||||
int operator; // expected-warning {{identifier 'operator' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected a type}}
|
||||
int private; // expected-warning {{identifier 'private' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected unqualified-id}}
|
||||
int protected; // expected-warning {{identifier 'protected' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected unqualified-id}}
|
||||
int public; // expected-warning {{identifier 'public' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected unqualified-id}}
|
||||
int reinterpret_cast; // expected-warning {{identifier 'reinterpret_cast' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected unqualified-id}}
|
||||
int static_cast; // expected-warning {{identifier 'static_cast' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected unqualified-id}}
|
||||
int template; // expected-warning {{identifier 'template' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected unqualified-id}}
|
||||
int typename; // expected-warning {{identifier 'typename' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected a qualified name after 'typename'}}
|
||||
int typeid; // expected-warning {{identifier 'typeid' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected unqualified-id}}
|
||||
int using; // expected-warning {{identifier 'using' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected unqualified-id}}
|
||||
int virtual; // expected-warning {{identifier 'virtual' conflicts with a C++ keyword}} \
|
||||
cxx-error {{'virtual' can only appear on non-static member functions}} \
|
||||
cxx-warning {{declaration does not declare anything}}
|
||||
int wchar_t; // expected-warning {{identifier 'wchar_t' conflicts with a C++ keyword}} \
|
||||
cxx-error {{cannot combine with previous 'int' declaration specifier}} \
|
||||
cxx-warning {{declaration does not declare anything}}
|
||||
int char8_t; // expected-warning {{identifier 'char8_t' conflicts with a C++ keyword}} \
|
||||
cxx-error {{cannot combine with previous 'int' declaration specifier}} \
|
||||
cxx-warning {{declaration does not declare anything}}
|
||||
int char16_t; // expected-warning {{identifier 'char16_t' conflicts with a C++ keyword}} \
|
||||
cxx-error {{cannot combine with previous 'int' declaration specifier}} \
|
||||
cxx-warning {{declaration does not declare anything}}
|
||||
int char32_t; // expected-warning {{identifier 'char32_t' conflicts with a C++ keyword}} \
|
||||
cxx-error {{cannot combine with previous 'int' declaration specifier}} \
|
||||
cxx-warning {{declaration does not declare anything}}
|
||||
int noexcept; // expected-warning {{identifier 'noexcept' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected unqualified-id}}
|
||||
int co_await; // expected-warning {{identifier 'co_await' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected unqualified-id}}
|
||||
int co_return; // expected-warning {{identifier 'co_return' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected unqualified-id}}
|
||||
int co_yield; // expected-warning {{identifier 'co_yield' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected unqualified-id}}
|
||||
int consteval; // expected-warning {{identifier 'consteval' conflicts with a C++ keyword}} \
|
||||
cxx-error {{consteval can only be used in function declarations}}
|
||||
int constinit; // expected-warning {{identifier 'constinit' conflicts with a C++ keyword}} \
|
||||
cxx-error {{constinit can only be used in variable declarations}}
|
||||
int concept; // expected-warning {{identifier 'concept' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected unqualified-id}}
|
||||
int requires; // expected-warning {{identifier 'requires' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected unqualified-id}}
|
||||
|
||||
// Now try the same thing, but as struct members.
|
||||
struct S {
|
||||
int catch; // expected-warning {{identifier 'catch' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected member name or ';' after declaration specifiers}}
|
||||
int class; // expected-warning {{identifier 'class' conflicts with a C++ keyword}} \
|
||||
cxx-error {{declaration of anonymous class must be a definition}} \
|
||||
cxx-warning {{declaration does not declare anything}}
|
||||
int const_cast; // expected-warning {{identifier 'const_cast' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected member name or ';' after declaration specifiers}}
|
||||
int delete; // expected-warning {{identifier 'delete' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected member name or ';' after declaration specifiers}}
|
||||
int dynamic_cast; // expected-warning {{identifier 'dynamic_cast' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected member name or ';' after declaration specifiers}}
|
||||
int explicit; // expected-warning {{identifier 'explicit' conflicts with a C++ keyword}} \
|
||||
cxx-error {{'explicit' can only appear on non-static member functions}} \
|
||||
cxx-warning {{declaration does not declare anything}}
|
||||
int export; // expected-warning {{identifier 'export' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected member name or ';' after declaration specifiers}}
|
||||
int friend; // expected-warning {{identifier 'friend' conflicts with a C++ keyword}} \
|
||||
cxx-error {{'friend' must appear first in a non-function declaration}}
|
||||
int mutable; // expected-warning {{identifier 'mutable' conflicts with a C++ keyword}} \
|
||||
cxx-warning {{declaration does not declare anything}}
|
||||
int namespace; // expected-warning {{identifier 'namespace' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected member name or ';' after declaration specifiers}}
|
||||
int new; // expected-warning {{identifier 'new' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected member name or ';' after declaration specifiers}}
|
||||
int operator; // expected-warning {{identifier 'operator' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected a type}}
|
||||
int private; // expected-warning {{identifier 'private' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected member name or ';' after declaration specifiers}}
|
||||
int protected; // expected-warning {{identifier 'protected' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected member name or ';' after declaration specifiers}}
|
||||
int public; // expected-warning {{identifier 'public' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected member name or ';' after declaration specifiers}}
|
||||
int reinterpret_cast; // expected-warning {{identifier 'reinterpret_cast' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected member name or ';' after declaration specifiers}}
|
||||
int static_cast; // expected-warning {{identifier 'static_cast' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected member name or ';' after declaration specifiers}}
|
||||
int template; // expected-warning {{identifier 'template' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected member name or ';' after declaration specifiers}}
|
||||
int this; // expected-warning {{identifier 'this' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected member name or ';' after declaration specifiers}}
|
||||
int throw; // expected-warning {{identifier 'throw' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected member name or ';' after declaration specifiers}}
|
||||
int try; // expected-warning {{identifier 'try' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected member name or ';' after declaration specifiers}}
|
||||
int typename; // expected-warning {{identifier 'typename' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected a qualified name after 'typename'}}
|
||||
int typeid; // expected-warning {{identifier 'typeid' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected member name or ';' after declaration specifiers}}
|
||||
int using; // expected-warning {{identifier 'using' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected member name or ';' after declaration specifiers}}
|
||||
int virtual; // expected-warning {{identifier 'virtual' conflicts with a C++ keyword}} \
|
||||
cxx-error {{'virtual' can only appear on non-static member functions}} \
|
||||
cxx-warning {{declaration does not declare anything}}
|
||||
int wchar_t; // expected-warning {{identifier 'wchar_t' conflicts with a C++ keyword}} \
|
||||
cxx-error {{cannot combine with previous 'int' declaration specifier}} \
|
||||
cxx-warning {{declaration does not declare anything}}
|
||||
int char8_t; // expected-warning {{identifier 'char8_t' conflicts with a C++ keyword}} \
|
||||
cxx-error {{cannot combine with previous 'int' declaration specifier}} \
|
||||
cxx-warning {{declaration does not declare anything}}
|
||||
int char16_t; // expected-warning {{identifier 'char16_t' conflicts with a C++ keyword}} \
|
||||
cxx-error {{cannot combine with previous 'int' declaration specifier}} \
|
||||
cxx-warning {{declaration does not declare anything}}
|
||||
int char32_t; // expected-warning {{identifier 'char32_t' conflicts with a C++ keyword}} \
|
||||
cxx-error {{cannot combine with previous 'int' declaration specifier}} \
|
||||
cxx-warning {{declaration does not declare anything}}
|
||||
int noexcept; // expected-warning {{identifier 'noexcept' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected member name or ';' after declaration specifiers}}
|
||||
int co_await; // expected-warning {{identifier 'co_await' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected member name or ';' after declaration specifiers}}
|
||||
int co_return; // expected-warning {{identifier 'co_return' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected member name or ';' after declaration specifiers}}
|
||||
int co_yield; // expected-warning {{identifier 'co_yield' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected member name or ';' after declaration specifiers}}
|
||||
int consteval; // expected-warning {{identifier 'consteval' conflicts with a C++ keyword}} \
|
||||
cxx-error {{consteval can only be used in function declarations}}
|
||||
int constinit; // expected-warning {{identifier 'constinit' conflicts with a C++ keyword}} \
|
||||
cxx-error {{constinit can only be used in variable declarations}}
|
||||
int concept; // expected-warning {{identifier 'concept' conflicts with a C++ keyword}} \
|
||||
cxx-error {{concept declarations may only appear in global or namespace scope}}
|
||||
int requires; // expected-warning {{identifier 'requires' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected member name or ';' after declaration specifiers}} \
|
||||
cxx-error {{trailing requires clause can only be used when declaring a function}} \
|
||||
cxx-error {{expected expression}}
|
||||
};
|
||||
|
||||
// Smoke test that we catch a keyword used as an enumerator. If we diagnose
|
||||
// one, we'll diagnose them all.
|
||||
enum E {
|
||||
throw, // expected-warning {{identifier 'throw' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected identifier}}
|
||||
};
|
||||
|
||||
// Smoke test that we catch a keyword used as a tag name.
|
||||
struct try { // expected-warning {{identifier 'try' conflicts with a C++ keyword}} \
|
||||
cxx-error {{declaration of anonymous struct must be a definition}} \
|
||||
cxx-warning {{declaration does not declare anything}}
|
||||
int x;
|
||||
};
|
||||
|
||||
// Smoke test that we catch keyword use in a function name.
|
||||
void this(void); // expected-warning {{identifier 'this' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected unqualified-id}}
|
||||
|
||||
// Smoke test that we catch keyword use in function parameters too.
|
||||
void func(int private); // expected-warning {{identifier 'private' conflicts with a C++ keyword}} \
|
||||
cxx-error {{invalid parameter name: 'private' is a keyword}}
|
||||
|
||||
// These are conditionally a keyword in C++, so they're intentionally not being
|
||||
// diagnosed as a keyword.
|
||||
int module;
|
||||
int import;
|
||||
int override;
|
||||
int final;
|
||||
|
||||
// We do not diagnose use of C++ keywords when used as a macro name because
|
||||
// that does not conflict with C++ (the macros will be replaced before the
|
||||
// keyword is seen by the parser).
|
||||
#define this 12
|
||||
|
||||
// FIXME: These tests are disabled for C++ because it causes a crash.
|
||||
// See GH114815.
|
||||
#ifndef __cplusplus
|
||||
int decltype; // expected-warning {{identifier 'decltype' conflicts with a C++ keyword}}
|
||||
struct T {
|
||||
int decltype; // expected-warning {{identifier 'decltype' conflicts with a C++ keyword}}
|
||||
};
|
||||
#endif // __cplusplus
|
||||
|
||||
// Check alternative operator names.
|
||||
int and; // expected-warning {{identifier 'and' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected unqualified-id}}
|
||||
int and_eq; // expected-warning {{identifier 'and_eq' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected unqualified-id}}
|
||||
int bitand; // expected-warning {{identifier 'bitand' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected unqualified-id}}
|
||||
int bitor; // expected-warning {{identifier 'bitor' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected unqualified-id}}
|
||||
int compl; // expected-warning {{identifier 'compl' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected a class name after '~' to name a destructor}}
|
||||
int not; // expected-warning {{identifier 'not' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected unqualified-id}}
|
||||
int not_eq; // expected-warning {{identifier 'not_eq' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected unqualified-id}}
|
||||
int or; // expected-warning {{identifier 'or' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected unqualified-id}}
|
||||
int or_eq; // expected-warning {{identifier 'or_eq' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected unqualified-id}}
|
||||
int xor; // expected-warning {{identifier 'xor' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected unqualified-id}}
|
||||
int xor_eq; // expected-warning {{identifier 'xor_eq' conflicts with a C++ keyword}} \
|
||||
cxx-error {{expected unqualified-id}}
|
12
clang/test/Sema/c++-keyword-in-objc.m
Normal file
12
clang/test/Sema/c++-keyword-in-objc.m
Normal file
@ -0,0 +1,12 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify -Wc++-keyword %s
|
||||
// expected-no-diagnostics
|
||||
|
||||
// Show that we do not diagnose any C++ keywords in Objective-C.
|
||||
|
||||
@class Foo; // Okay, Objective-C @ keyword, not a regular identifier
|
||||
|
||||
// FIXME: it would be nice to diagnose this, but it is intentionally allowed
|
||||
// due to @ and selectors allowing C++ keywords in ways that are supposed to be
|
||||
// contextually compatible with C++.
|
||||
int class = 12;
|
||||
|
Loading…
x
Reference in New Issue
Block a user