Skip to content

Commit 141df74

Browse files
committed
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.
1 parent 7063b76 commit 141df74

File tree

4 files changed

+30
-4
lines changed

4 files changed

+30
-4
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,7 @@ def warn_reserved_extern_symbol: Warning<
391391
"identifier %0 is reserved because %select{"
392392
"<ERROR>|" // ReservedIdentifierStatus::NotReserved
393393
"it starts with '_' at global scope|"
394+
"it starts with '_' and has C language linkage|"
394395
"it starts with '__'|"
395396
"it starts with '_' followed by a capital letter|"
396397
"it contains '__'}1">,

clang/include/clang/Basic/IdentifierTable.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class SourceLocation;
4343
enum class ReservedIdentifierStatus {
4444
NotReserved = 0,
4545
StartsWithUnderscoreAtGlobalScope,
46+
StartsWithUnderscoreAndIsExternC,
4647
StartsWithDoubleUnderscore,
4748
StartsWithUnderscoreFollowedByCapitalLetter,
4849
ContainsDoubleUnderscore,
@@ -60,7 +61,8 @@ inline bool isReservedAtGlobalScope(ReservedIdentifierStatus Status) {
6061
/// example.
6162
inline bool isReservedInAllContexts(ReservedIdentifierStatus Status) {
6263
return Status != ReservedIdentifierStatus::NotReserved &&
63-
Status != ReservedIdentifierStatus::StartsWithUnderscoreAtGlobalScope;
64+
Status != ReservedIdentifierStatus::StartsWithUnderscoreAtGlobalScope &&
65+
Status != ReservedIdentifierStatus::StartsWithUnderscoreAndIsExternC;
6466
}
6567

6668
/// A simple pair of identifier info and location.

clang/lib/AST/Decl.cpp

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1089,12 +1089,28 @@ NamedDecl::isReserved(const LangOptions &LangOpts) const {
10891089

10901090
ReservedIdentifierStatus Status = II->isReserved(LangOpts);
10911091
if (isReservedAtGlobalScope(Status) && !isReservedInAllContexts(Status)) {
1092-
// Check if we're at TU level or not.
1092+
// This name is only reserved at global scope. Check if this declaration
1093+
// conflicts with a global scope declaration.
10931094
if (isa<ParmVarDecl>(this) || isTemplateParameter())
10941095
return ReservedIdentifierStatus::NotReserved;
1096+
1097+
// C++ [dcl.link]/7:
1098+
// Two declarations [conflict] if [...] one declares a function or
1099+
// variable with C language linkage, and the other declares [...] a
1100+
// variable that belongs to the global scope.
1101+
//
1102+
// Therefore names that are reserved at global scope are also reserved as
1103+
// names of variables and functions with C language linkage.
10951104
const DeclContext *DC = getDeclContext()->getRedeclContext();
1096-
if (!DC->isTranslationUnit())
1097-
return ReservedIdentifierStatus::NotReserved;
1105+
if (DC->isTranslationUnit())
1106+
return Status;
1107+
if (auto *VD = dyn_cast<VarDecl>(this))
1108+
if (VD->isExternC())
1109+
return ReservedIdentifierStatus::StartsWithUnderscoreAndIsExternC;
1110+
if (auto *FD = dyn_cast<FunctionDecl>(this))
1111+
if (FD->isExternC())
1112+
return ReservedIdentifierStatus::StartsWithUnderscoreAndIsExternC;
1113+
return ReservedIdentifierStatus::NotReserved;
10981114
}
10991115

11001116
return Status;

clang/test/SemaCXX/reserved-identifier.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,10 @@ struct Any {
105105
#define _Reserved // expected-warning {{macro name is a reserved identifier}}
106106
#undef _not_reserved
107107
#undef _Reserved // expected-warning {{macro name is a reserved identifier}}
108+
109+
namespace N {
110+
int _namespace_a;
111+
extern "C" int _namespace_b; // expected-warning {{identifier '_namespace_b' is reserved because it starts with '_' and has C language linkage}}
112+
void _namespace_c();
113+
extern "C" void _namespace_d(); // expected-warning {{identifier '_namespace_d' is reserved because it starts with '_' and has C language linkage}}
114+
}

0 commit comments

Comments
 (0)