diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 75a57c5d18d8..30402411178d 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -138,6 +138,9 @@ Improvements to Clang's diagnostics incorrectly saying no_sanitize only applies to functions and methods. - No longer mention ``reinterpet_cast`` in the invalid constant expression diagnostic note when in C mode. +- Clang will now give a more suitale diagnostic for declaration of block + scope identifiers that have external/internal linkage that has an initializer. + Fixes `Issue 57478: `_. Non-comprehensive list of changes in this release ------------------------------------------------- diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 76e18c9deff4..016affb1b323 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -5901,7 +5901,7 @@ def err_loader_uninitialized_extern_decl : Error<"variable %0 cannot be declared both 'extern' and with the " "'loader_uninitialized' attribute">; def err_block_extern_cant_init : Error< - "'extern' variable cannot have an initializer">; + "declaration of block scope identifier with linkage cannot have an initializer">; def warn_extern_init : Warning<"'extern' variable has an initializer">, InGroup>; def err_variable_object_no_init : Error< diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 2ad6edc121ae..6e94da4a115e 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -12773,8 +12773,11 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { return; } + // C99 6.7.8p5. 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. + // C++14 [dcl.init]p5 is the same restriction for C++. if (VDecl->isLocalVarDecl() && VDecl->hasExternalStorage()) { - // C99 6.7.8p5. C++ has no such restriction, but that is a defect. Diag(VDecl->getLocation(), diag::err_block_extern_cant_init); VDecl->setInvalidDecl(); return; diff --git a/clang/test/Parser/cxx1z-decomposition.cpp b/clang/test/Parser/cxx1z-decomposition.cpp index 7abf1f9cdac5..10ef464bda50 100644 --- a/clang/test/Parser/cxx1z-decomposition.cpp +++ b/clang/test/Parser/cxx1z-decomposition.cpp @@ -69,7 +69,7 @@ namespace BadSpecifiers { // storage-class-specifiers static auto &[a] = n; // expected-warning {{declared 'static' is a C++20 extension}} thread_local auto &[b] = n; // expected-warning {{declared 'thread_local' is a C++20 extension}} - extern auto &[c] = n; // expected-error {{cannot be declared 'extern'}} expected-error {{cannot have an initializer}} + extern auto &[c] = n; // expected-error {{cannot be declared 'extern'}} expected-error {{declaration of block scope identifier with linkage cannot have an initializer}} struct S { mutable auto &[d] = n; // expected-error {{not permitted in this context}} diff --git a/clang/test/Sema/array-init.c b/clang/test/Sema/array-init.c index ae3ce73ccc7a..fcc3c13bc91d 100644 --- a/clang/test/Sema/array-init.c +++ b/clang/test/Sema/array-init.c @@ -48,7 +48,7 @@ void func(void) { struct threeElements *p = 7; // expected-error{{incompatible integer to pointer conversion initializing 'struct threeElements *' with an expression of type 'int'}} - extern int blockScopeExtern[3] = { 1, 3, 5 }; // expected-error{{'extern' variable cannot have an initializer}} + extern int blockScopeExtern[3] = { 1, 3, 5 }; // expected-error{{declaration of block scope identifier with linkage cannot have an initializer}} static long x2[3] = { 1.0, "abc", // expected-error{{incompatible pointer to integer conversion initializing 'long' with an expression of type 'char[4]'}} diff --git a/clang/test/Sema/err-decl-block-extern-no-init.c b/clang/test/Sema/err-decl-block-extern-no-init.c new file mode 100644 index 000000000000..78a8befd0ca7 --- /dev/null +++ b/clang/test/Sema/err-decl-block-extern-no-init.c @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -verify %s +static int x; + +void foo(void) +{ + extern int x = 1; // expected-error {{declaration of block scope identifier with linkage cannot have an initializer}} +} + +int y; + +void bar(void) +{ + extern int y = 1; // expected-error {{declaration of block scope identifier with linkage cannot have an initializer}} + +} diff --git a/clang/test/Sema/private-extern.c b/clang/test/Sema/private-extern.c index 8c7fd18f36fd..7e7fb27416aa 100644 --- a/clang/test/Sema/private-extern.c +++ b/clang/test/Sema/private-extern.c @@ -69,9 +69,9 @@ void f8(void) { struct s0 { int x; }; void f9(void) { - extern int g15 = 0; // expected-error{{'extern' variable cannot have an initializer}} + extern int g15 = 0; // expected-error{{declaration of block scope identifier with linkage cannot have an initializer}} // FIXME: linkage specifier in warning. - __private_extern__ int g16 = 0; // expected-error{{'extern' variable cannot have an initializer}} + __private_extern__ int g16 = 0; // expected-error{{declaration of block scope identifier with linkage cannot have an initializer}} } extern int g17;