Index: clang/include/clang/AST/Decl.h =================================================================== --- clang/include/clang/AST/Decl.h +++ clang/include/clang/AST/Decl.h @@ -356,6 +356,10 @@ /// a C++ class. bool isCXXInstanceMember() const; + /// Determine if the declaration obeys the reserved identifier rules of the + /// given Language + bool isReserved(const LangOptions &) const; + /// Determine what kind of linkage this entity has. /// /// This is not the linkage as defined by the standard or the codegen notion Index: clang/include/clang/Basic/DiagnosticGroups.td =================================================================== --- clang/include/clang/Basic/DiagnosticGroups.td +++ clang/include/clang/Basic/DiagnosticGroups.td @@ -689,6 +689,7 @@ [UnneededMemberFunction]>; def UnusedLabel : DiagGroup<"unused-label">; def UnusedLambdaCapture : DiagGroup<"unused-lambda-capture">; +def ReservedIdentifier : DiagGroup<"reserved-identifier">; def UnusedParameter : DiagGroup<"unused-parameter">; def UnusedResult : DiagGroup<"unused-result">; def PotentiallyEvaluatedExpression : DiagGroup<"potentially-evaluated-expression">; Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -372,6 +372,10 @@ "%select{used|required to be captured for this use}1">, InGroup, DefaultIgnore; +def warn_reserved_identifier: Warning< + "'%0' is a reserved identifier">, + InGroup, DefaultIgnore; + def warn_parameter_size: Warning< "%0 is a large (%1 bytes) pass-by-value argument; " "pass it by reference instead ?">, InGroup; Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -2463,6 +2463,8 @@ SourceLocation Less, SourceLocation Greater); + void warnOnReservedIdentifier(NamedDecl *D); + Decl *ActOnDeclarator(Scope *S, Declarator &D); NamedDecl *HandleDeclarator(Scope *S, Declarator &D, Index: clang/lib/AST/Decl.cpp =================================================================== --- clang/lib/AST/Decl.cpp +++ clang/lib/AST/Decl.cpp @@ -1078,6 +1078,31 @@ return L == getCachedLinkage(); } +bool NamedDecl::isReserved(const LangOptions &LangOpts) const { + StringRef Name = getName(); + if (Name.size() <= 1) + return false; + + if (Name[0] == '_') { + if (VarDecl const *VD = dyn_cast(this)) { + if (VD->hasExternalStorage()) + return true; + } else if (FunctionDecl const *FD = dyn_cast(this)) { + if (FD->getStorageClass() == SC_Extern || + FD->getStorageClass() == SC_PrivateExtern || + FD->getStorageClass() == SC_None) + return true; + } + if (Name[1] == '_' || ('A' <= Name[1] && Name[1] <= 'Z')) + return true; + } + + if (LangOpts.CPlusPlus && Name.contains("__")) + return true; + + return false; +} + ObjCStringFormatFamily NamedDecl::getObjCFStringFormattingFamily() const { StringRef name = getName(); if (name.empty()) return SFF_None; Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -5542,6 +5542,12 @@ return false; } +void Sema::warnOnReservedIdentifier(NamedDecl *D) { + if (!Context.getSourceManager().isInSystemHeader(D->getLocation()) && + D->isReserved(getLangOpts())) + Diag(D->getLocation(), diag::warn_reserved_identifier) << D->getName(); +} + Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) { D.setFunctionDefinitionKind(FunctionDefinitionKind::Declaration); Decl *Dcl = HandleDeclarator(S, D, MultiTemplateParamsArg()); @@ -5887,6 +5893,7 @@ if (isInOpenMPDeclareTargetContext()) checkDeclIsAllowedInOpenMPTarget(nullptr, New); + warnOnReservedIdentifier(New); return New; } @@ -13622,6 +13629,8 @@ if (getLangOpts().OpenCL) deduceOpenCLAddressSpace(New); + warnOnReservedIdentifier(New); + return New; } @@ -16276,6 +16285,7 @@ } else if (SkipBody && SkipBody->ShouldSkip) { return SkipBody->Previous; } else { + warnOnReservedIdentifier(New); return New; } } @@ -17088,6 +17098,8 @@ i != end; ++i) { FieldDecl *FD = cast(*i); + warnOnReservedIdentifier(FD); + // Get the type for the field. const Type *FDTy = FD->getType().getTypePtr(); Index: clang/lib/Sema/SemaDeclCXX.cpp =================================================================== --- clang/lib/Sema/SemaDeclCXX.cpp +++ clang/lib/Sema/SemaDeclCXX.cpp @@ -10985,6 +10985,9 @@ // for the namespace has the declarations that showed up in that particular // namespace definition. PushDeclContext(NamespcScope, Namespc); + + warnOnReservedIdentifier(Namespc); + return Namespc; } @@ -12659,6 +12662,9 @@ PushOnScopeChains(NewND, S); ActOnDocumentableDecl(NewND); + + warnOnReservedIdentifier(NewND); + return NewND; } Index: clang/test/Sema/reserved-identifier.c =================================================================== --- /dev/null +++ clang/test/Sema/reserved-identifier.c @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -Wreserved-identifier %s + +int foo__bar() { return 0; } // no-warning +static int _bar() { return 0; } // no-warning +static int _Bar() { return 0; } // expected-warning {{'_Bar' is a reserved identifier}} +int _foo() { return 0; } // expected-warning {{'_foo' is a reserved identifier}} + +void foo(unsigned int _Reserved) { // expected-warning {{'_Reserved' is a reserved identifier}} + unsigned int __1 = // expected-warning {{'__1' is a reserved identifier}} + _Reserved; // no-warning +} + +struct __babar { // expected-warning {{'__babar' is a reserved identifier}} +}; + +typedef struct { + int _Field; // expected-warning {{'_Field' is a reserved identifier}} +} _Typedef; // expected-warning {{'_Typedef' is a reserved identifier}} + +int foobar() { + return foo__bar(); // no-warning +} Index: clang/test/Sema/reserved-identifier.cpp =================================================================== --- /dev/null +++ clang/test/Sema/reserved-identifier.cpp @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -Wreserved-identifier %s + +int foo__bar() { return 0; } // expected-warning {{'foo__bar' is a reserved identifier}} +static int _bar() { return 0; } // no-warning +static int _Bar() { return 0; } // expected-warning {{'_Bar' is a reserved identifier}} +int _barbouille() { return 0; } // expected-warning {{'_barbouille' is a reserved identifier}} + +void foo(unsigned int _Reserved) { // expected-warning {{'_Reserved' is a reserved identifier}} + unsigned int __1 = // expected-warning {{'__1' is a reserved identifier}} + _Reserved; // no-warning +} + +namespace _Barbidur { // expected-warning {{'_Barbidur' is a reserved identifier}} + +struct __barbidou { // expected-warning {{'__barbidou' is a reserved identifier}} +}; + +} // namespace _Barbidur + +class __barbapapa { // expected-warning {{'__barbapapa' is a reserved identifier}} + void _barbabelle() {} // expected-warning {{'_barbabelle' is a reserved identifier}} + int _Barbalala; // expected-warning {{'_Barbalala' is a reserved identifier}} +}; + +using _Barbamama = __barbapapa; // expected-warning {{'_Barbamama' is a reserved identifier}} + +int foobar() { + return foo__bar(); // no-warning +}