Skip to content

Commit 1d51bb8

Browse files
committed
[Clang] Reword diagnostic for scope identifier with linkage
If the declaration of an identifier has block scope, and the identifier has external or internal linkage, the declaration shall have no initializer for the identifier. Clang now gives a more suitable diagnosis for this case. Fixes llvm#57478 Signed-off-by: Jun Zhang <[email protected]> Differential Revision: https://reviews.llvm.org/D133088
1 parent e4f4542 commit 1d51bb8

File tree

7 files changed

+27
-6
lines changed

7 files changed

+27
-6
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@ Improvements to Clang's diagnostics
138138
incorrectly saying no_sanitize only applies to functions and methods.
139139
- No longer mention ``reinterpet_cast`` in the invalid constant expression
140140
diagnostic note when in C mode.
141+
- Clang will now give a more suitale diagnostic for declaration of block
142+
scope identifiers that have external/internal linkage that has an initializer.
143+
Fixes `Issue 57478: <https://github.com/llvm/llvm-project/issues/57478>`_.
141144

142145
Non-comprehensive list of changes in this release
143146
-------------------------------------------------

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5901,7 +5901,7 @@ def err_loader_uninitialized_extern_decl
59015901
: Error<"variable %0 cannot be declared both 'extern' and with the "
59025902
"'loader_uninitialized' attribute">;
59035903
def err_block_extern_cant_init : Error<
5904-
"'extern' variable cannot have an initializer">;
5904+
"declaration of block scope identifier with linkage cannot have an initializer">;
59055905
def warn_extern_init : Warning<"'extern' variable has an initializer">,
59065906
InGroup<DiagGroup<"extern-initializer">>;
59075907
def err_variable_object_no_init : Error<

clang/lib/Sema/SemaDecl.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12773,8 +12773,11 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
1277312773
return;
1277412774
}
1277512775

12776+
// C99 6.7.8p5. If the declaration of an identifier has block scope, and
12777+
// the identifier has external or internal linkage, the declaration shall
12778+
// have no initializer for the identifier.
12779+
// C++14 [dcl.init]p5 is the same restriction for C++.
1277612780
if (VDecl->isLocalVarDecl() && VDecl->hasExternalStorage()) {
12777-
// C99 6.7.8p5. C++ has no such restriction, but that is a defect.
1277812781
Diag(VDecl->getLocation(), diag::err_block_extern_cant_init);
1277912782
VDecl->setInvalidDecl();
1278012783
return;

clang/test/Parser/cxx1z-decomposition.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ namespace BadSpecifiers {
6969
// storage-class-specifiers
7070
static auto &[a] = n; // expected-warning {{declared 'static' is a C++20 extension}}
7171
thread_local auto &[b] = n; // expected-warning {{declared 'thread_local' is a C++20 extension}}
72-
extern auto &[c] = n; // expected-error {{cannot be declared 'extern'}} expected-error {{cannot have an initializer}}
72+
extern auto &[c] = n; // expected-error {{cannot be declared 'extern'}} expected-error {{declaration of block scope identifier with linkage cannot have an initializer}}
7373
struct S {
7474
mutable auto &[d] = n; // expected-error {{not permitted in this context}}
7575

clang/test/Sema/array-init.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ void func(void) {
4848

4949
struct threeElements *p = 7; // expected-error{{incompatible integer to pointer conversion initializing 'struct threeElements *' with an expression of type 'int'}}
5050

51-
extern int blockScopeExtern[3] = { 1, 3, 5 }; // expected-error{{'extern' variable cannot have an initializer}}
51+
extern int blockScopeExtern[3] = { 1, 3, 5 }; // expected-error{{declaration of block scope identifier with linkage cannot have an initializer}}
5252

5353
static long x2[3] = { 1.0,
5454
"abc", // expected-error{{incompatible pointer to integer conversion initializing 'long' with an expression of type 'char[4]'}}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -verify %s
2+
static int x;
3+
4+
void foo(void)
5+
{
6+
extern int x = 1; // expected-error {{declaration of block scope identifier with linkage cannot have an initializer}}
7+
}
8+
9+
int y;
10+
11+
void bar(void)
12+
{
13+
extern int y = 1; // expected-error {{declaration of block scope identifier with linkage cannot have an initializer}}
14+
15+
}

clang/test/Sema/private-extern.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,9 @@ void f8(void) {
6969
struct s0 { int x; };
7070

7171
void f9(void) {
72-
extern int g15 = 0; // expected-error{{'extern' variable cannot have an initializer}}
72+
extern int g15 = 0; // expected-error{{declaration of block scope identifier with linkage cannot have an initializer}}
7373
// FIXME: linkage specifier in warning.
74-
__private_extern__ int g16 = 0; // expected-error{{'extern' variable cannot have an initializer}}
74+
__private_extern__ int g16 = 0; // expected-error{{declaration of block scope identifier with linkage cannot have an initializer}}
7575
}
7676

7777
extern int g17;

0 commit comments

Comments
 (0)