[clang] 141df74 - Add missing diagnostic for use of _reserved name in extern "C"

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Wed Oct 6 15:13:47 PDT 2021


Author: Richard Smith
Date: 2021-10-06T15:13:06-07:00
New Revision: 141df744564822b8d8250fe1bcec15cdbd5f213e

URL: https://github.com/llvm/llvm-project/commit/141df744564822b8d8250fe1bcec15cdbd5f213e
DIFF: https://github.com/llvm/llvm-project/commit/141df744564822b8d8250fe1bcec15cdbd5f213e.diff

LOG: Add missing diagnostic for use of _reserved name in extern "C"
declaration.

Names starting with an underscore are reserved at the global scope, so
cannot be used as the name of an extern "C" symbol in any scope because
such usages conflict with a name at global scope.

Added: 
    

Modified: 
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/include/clang/Basic/IdentifierTable.h
    clang/lib/AST/Decl.cpp
    clang/test/SemaCXX/reserved-identifier.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 778ff67ce174..128ad047072e 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -391,6 +391,7 @@ def warn_reserved_extern_symbol: Warning<
   "identifier %0 is reserved because %select{"
   "<ERROR>|" // ReservedIdentifierStatus::NotReserved
   "it starts with '_' at global scope|"
+  "it starts with '_' and has C language linkage|"
   "it starts with '__'|"
   "it starts with '_' followed by a capital letter|"
   "it contains '__'}1">,

diff  --git a/clang/include/clang/Basic/IdentifierTable.h b/clang/include/clang/Basic/IdentifierTable.h
index 803fec8df30c..19c967efcc42 100644
--- a/clang/include/clang/Basic/IdentifierTable.h
+++ b/clang/include/clang/Basic/IdentifierTable.h
@@ -43,6 +43,7 @@ class SourceLocation;
 enum class ReservedIdentifierStatus {
   NotReserved = 0,
   StartsWithUnderscoreAtGlobalScope,
+  StartsWithUnderscoreAndIsExternC,
   StartsWithDoubleUnderscore,
   StartsWithUnderscoreFollowedByCapitalLetter,
   ContainsDoubleUnderscore,
@@ -60,7 +61,8 @@ inline bool isReservedAtGlobalScope(ReservedIdentifierStatus Status) {
 /// example.
 inline bool isReservedInAllContexts(ReservedIdentifierStatus Status) {
   return Status != ReservedIdentifierStatus::NotReserved &&
-         Status != ReservedIdentifierStatus::StartsWithUnderscoreAtGlobalScope;
+         Status != ReservedIdentifierStatus::StartsWithUnderscoreAtGlobalScope &&
+         Status != ReservedIdentifierStatus::StartsWithUnderscoreAndIsExternC;
 }
 
 /// A simple pair of identifier info and location.

diff  --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 57d84f2c3439..acc0839dba75 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -1089,12 +1089,28 @@ NamedDecl::isReserved(const LangOptions &LangOpts) const {
 
   ReservedIdentifierStatus Status = II->isReserved(LangOpts);
   if (isReservedAtGlobalScope(Status) && !isReservedInAllContexts(Status)) {
-    // Check if we're at TU level or not.
+    // This name is only reserved at global scope. Check if this declaration
+    // conflicts with a global scope declaration.
     if (isa<ParmVarDecl>(this) || isTemplateParameter())
       return ReservedIdentifierStatus::NotReserved;
+
+    // C++ [dcl.link]/7:
+    //   Two declarations [conflict] if [...] one declares a function or
+    //   variable with C language linkage, and the other declares [...] a
+    //   variable that belongs to the global scope.
+    //
+    // Therefore names that are reserved at global scope are also reserved as
+    // names of variables and functions with C language linkage.
     const DeclContext *DC = getDeclContext()->getRedeclContext();
-    if (!DC->isTranslationUnit())
-      return ReservedIdentifierStatus::NotReserved;
+    if (DC->isTranslationUnit())
+      return Status;
+    if (auto *VD = dyn_cast<VarDecl>(this))
+      if (VD->isExternC())
+        return ReservedIdentifierStatus::StartsWithUnderscoreAndIsExternC;
+    if (auto *FD = dyn_cast<FunctionDecl>(this))
+      if (FD->isExternC())
+        return ReservedIdentifierStatus::StartsWithUnderscoreAndIsExternC;
+    return ReservedIdentifierStatus::NotReserved;
   }
 
   return Status;

diff  --git a/clang/test/SemaCXX/reserved-identifier.cpp b/clang/test/SemaCXX/reserved-identifier.cpp
index 56fa3873359b..eaa5fe833033 100644
--- a/clang/test/SemaCXX/reserved-identifier.cpp
+++ b/clang/test/SemaCXX/reserved-identifier.cpp
@@ -105,3 +105,10 @@ struct Any {
 #define _Reserved // expected-warning {{macro name is a reserved identifier}}
 #undef _not_reserved
 #undef _Reserved // expected-warning {{macro name is a reserved identifier}}
+
+namespace N {
+  int _namespace_a;
+  extern "C" int _namespace_b; // expected-warning {{identifier '_namespace_b' is reserved because it starts with '_' and has C language linkage}}
+  void _namespace_c();
+  extern "C" void _namespace_d(); // expected-warning {{identifier '_namespace_d' is reserved because it starts with '_' and has C language linkage}}
+}


        


More information about the cfe-commits mailing list