diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 1e0321de3f4b6..2c2e249282246 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -1401,7 +1401,7 @@ def C23 : DiagGroup<"c23-extensions", [VariadicMacroArgumentsOmitted]>; def : DiagGroup<"c2x-extensions", [C23]>; // A warning group for warnings about using C2y features as extensions. -def C2y : DiagGroup<"c2y-extensions", [StaticInInline]>; +def C2y : DiagGroup<"c2y-extensions", [StaticInInline, StaticLocalInInline]>; // Previously supported warning group which is no longer pertinent as binary // literals are a C++14 and C23 extension now instead of a GNU extension. diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 3e864475f22a1..4b35c811793dd 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6339,9 +6339,13 @@ def warn_c2y_compat_internal_in_extern_inline : Warning< "using static %select{function|variable}0 %1 in an inline function with " "external linkage is incompatible with standards before C2y">, InGroup, DefaultIgnore; -def warn_static_local_in_extern_inline : Warning< - "non-constant static local variable in inline function may be different " - "in different files">, InGroup; +def ext_static_local_in_extern_inline : ExtWarn< + "non-constant static local variable in an inline function with " + "external linkage is a C2y extension">, InGroup; +def warn_c2y_compat_static_local_in_extern_inline : Warning< + "non-constant static local variable in an inline function with " + "external linkage is incompatible with standards before C2y">, + InGroup, DefaultIgnore; def note_convert_inline_to_static : Note< "use 'static' to give inline function %0 internal linkage">; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 086dd8ba1c670..ebb82a129d0ca 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -8111,6 +8111,11 @@ NamedDecl *Sema::ActOnVariableDeclarator( // An inline definition of a function with external linkage shall // not contain a definition of a modifiable object with static or // thread storage duration... + // + // WG14 N3622 which removed the constraint entirely in C2y. It is left + // enabled in earlier language modes because this is a constraint in those + // language modes. But in C2y mode, we still want to issue the "incompatible + // with previous standards" diagnostic, too. // We only apply this when the function is required to be defined // elsewhere, i.e. when the function is not 'extern inline'. Note // that a local variable with thread storage duration still has to @@ -8120,8 +8125,13 @@ NamedDecl *Sema::ActOnVariableDeclarator( !NewVD->getType().isConstQualified()) { FunctionDecl *CurFD = getCurFunctionDecl(); if (CurFD && isFunctionDefinitionDiscarded(*this, CurFD)) { - Diag(D.getDeclSpec().getStorageClassSpecLoc(), - diag::warn_static_local_in_extern_inline); + unsigned DiagID; + if (getLangOpts().C2y) + DiagID = diag::warn_c2y_compat_static_local_in_extern_inline; + else + DiagID = diag::ext_static_local_in_extern_inline; + + Diag(D.getDeclSpec().getStorageClassSpecLoc(), DiagID); MaybeSuggestAddingStaticToDecl(CurFD); } } diff --git a/clang/test/C/C2y/n3622_1.c b/clang/test/C/C2y/n3622_1.c new file mode 100644 index 0000000000000..49351a52d026a --- /dev/null +++ b/clang/test/C/C2y/n3622_1.c @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -verify=good -pedantic -Wall -std=c2y %s +// RUN: %clang_cc1 -verify=compat,expected -pedantic -Wall -Wpre-c2y-compat -std=c2y %s +// RUN: %clang_cc1 -verify=ped,expected -pedantic -Wall -std=c23 %s +// RUN: %clang_cc1 -verify=ped,expected -pedantic -Wall -std=c17 %s +// good-no-diagnostics + +/* WG14 N3622: Clang 22 + * Allow static local variables in extern inline functions + * + * This verifies that a constraint from previous standards is no longer + * triggered in C2y mode. The constraint is regarding static local + * variables in inline functions with external linkage. + */ + +inline void func1(void) { // expected-note {{use 'static' to give inline function 'func1' internal linkage}} + static int x = 0; /* ped-warning {{non-constant static local variable in an inline function with external linkage is a C2y extension}} + compat-warning {{non-constant static local variable in an inline function with external linkage is incompatible with standards before C2y}} + */ + (void)x; +} + +inline void func2(void) { + static const int x = 0; + (void)x; +} diff --git a/clang/test/Sema/inline.c b/clang/test/Sema/inline.c index 6361db8496c2d..ea65b2cb82997 100644 --- a/clang/test/Sema/inline.c +++ b/clang/test/Sema/inline.c @@ -73,9 +73,9 @@ inline int useStaticAgain (void) { // expected-note 2 {{use 'static' to give inl #pragma clang diagnostic pop -inline void defineStaticVar(void) { // expected-note {{use 'static' to give inline function 'defineStaticVar' internal linkage}} +inline void defineStaticVar(void) { // ok (no -pedantic) static const int x = 0; // ok - static int y = 0; // expected-warning {{non-constant static local variable in inline function may be different in different files}} + static int y = 0; // ok (no -pedantic) } extern inline void defineStaticVarInExtern(void) {