Skip to content

Commit f459a97

Browse files
committed
[C2y] Allow static local variables in inline functions with external linkage (N3622)
This allows static local variables to be declared in inline functions with external linkage, a constraint that was removed in WG14 N3622. Such declarations are now allowed in C2y mode, and accepted as an extension in earlier language models. The code changes carried out were heavily inspired by commit 8e60adc, which implemented making use of static variables or functions within extern inline functions as part of the same paper.
1 parent 4ecb3c7 commit f459a97

File tree

5 files changed

+54
-8
lines changed

5 files changed

+54
-8
lines changed

clang/include/clang/Basic/DiagnosticGroups.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1401,7 +1401,7 @@ def C23 : DiagGroup<"c23-extensions", [VariadicMacroArgumentsOmitted]>;
14011401
def : DiagGroup<"c2x-extensions", [C23]>;
14021402

14031403
// A warning group for warnings about using C2y features as extensions.
1404-
def C2y : DiagGroup<"c2y-extensions", [StaticInInline]>;
1404+
def C2y : DiagGroup<"c2y-extensions", [StaticInInline, StaticLocalInInline]>;
14051405

14061406
// Previously supported warning group which is no longer pertinent as binary
14071407
// literals are a C++14 and C23 extension now instead of a GNU extension.

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6339,9 +6339,18 @@ def warn_c2y_compat_internal_in_extern_inline : Warning<
63396339
"using static %select{function|variable}0 %1 in an inline function with "
63406340
"external linkage is incompatible with standards before C2y">,
63416341
InGroup<CPre2yCompat>, DefaultIgnore;
6342-
def warn_static_local_in_extern_inline : Warning<
6343-
"non-constant static local variable in inline function may be different "
6344-
"in different files">, InGroup<StaticLocalInInline>;
6342+
def ext_static_local_in_extern_inline
6343+
: ExtWarn<"non-constant static local variable in an inline function with "
6344+
"external linkage is a C2y extension">,
6345+
InGroup<StaticLocalInInline>;
6346+
def ext_static_local_in_extern_inline_quiet
6347+
: Extension<ext_static_local_in_extern_inline.Summary>,
6348+
InGroup<StaticLocalInInline>;
6349+
def warn_c2y_compat_static_local_in_extern_inline
6350+
: Warning<"non-constant static local variable in an inline function with "
6351+
"external linkage is incompatible with standards before C2y">,
6352+
InGroup<CPre2yCompat>,
6353+
DefaultIgnore;
63456354
def note_convert_inline_to_static : Note<
63466355
"use 'static' to give inline function %0 internal linkage">;
63476356

clang/lib/Sema/SemaDecl.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8111,6 +8111,11 @@ NamedDecl *Sema::ActOnVariableDeclarator(
81118111
// An inline definition of a function with external linkage shall
81128112
// not contain a definition of a modifiable object with static or
81138113
// thread storage duration...
8114+
//
8115+
// WG14 N3622 which removed the constraint entirely in C2y. It is left
8116+
// enabled in earlier language modes because this is a constraint in those
8117+
// language modes. But in C2y mode, we still want to issue the "incompatible
8118+
// with previous standards" diagnostic, too.
81148119
// We only apply this when the function is required to be defined
81158120
// elsewhere, i.e. when the function is not 'extern inline'. Note
81168121
// that a local variable with thread storage duration still has to
@@ -8120,8 +8125,15 @@ NamedDecl *Sema::ActOnVariableDeclarator(
81208125
!NewVD->getType().isConstQualified()) {
81218126
FunctionDecl *CurFD = getCurFunctionDecl();
81228127
if (CurFD && isFunctionDefinitionDiscarded(*this, CurFD)) {
8123-
Diag(D.getDeclSpec().getStorageClassSpecLoc(),
8124-
diag::warn_static_local_in_extern_inline);
8128+
unsigned DiagID;
8129+
if (getLangOpts().C2y)
8130+
DiagID = diag::warn_c2y_compat_static_local_in_extern_inline;
8131+
else if (getSourceManager().isInMainFile(D.getBeginLoc()))
8132+
DiagID = diag::ext_static_local_in_extern_inline_quiet;
8133+
else
8134+
DiagID = diag::ext_static_local_in_extern_inline;
8135+
8136+
Diag(D.getDeclSpec().getStorageClassSpecLoc(), DiagID);
81258137
MaybeSuggestAddingStaticToDecl(CurFD);
81268138
}
81278139
}

clang/test/C/C2y/n3622_1.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// RUN: %clang_cc1 -verify=good -pedantic -Wall -std=c2y %s
2+
// RUN: %clang_cc1 -verify=compat,expected -pedantic -Wall -Wpre-c2y-compat -std=c2y %s
3+
// RUN: %clang_cc1 -verify=ped,expected -pedantic -Wall -std=c23 %s
4+
// RUN: %clang_cc1 -verify=ped,expected -pedantic -Wall -std=c17 %s
5+
// good-no-diagnostics
6+
7+
/* WG14 N3622: Clang 22
8+
* Allow static local variables in extern inline functions
9+
*
10+
* This verifies that a constraint from previous standards is no longer
11+
* triggered in C2y mode. The constraint is regarding static local
12+
* variables in inline functions with external linkage.
13+
*/
14+
15+
inline void func1(void) { // expected-note {{use 'static' to give inline function 'func1' internal linkage}}
16+
static int x = 0; /* ped-warning {{non-constant static local variable in an inline function with external linkage is a C2y extension}}
17+
compat-warning {{non-constant static local variable in an inline function with external linkage is incompatible with standards before C2y}}
18+
*/
19+
(void)x;
20+
}
21+
22+
inline void func2(void) {
23+
static const int x = 0;
24+
(void)x;
25+
}

clang/test/Sema/inline.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,9 @@ inline int useStaticAgain (void) { // expected-note 2 {{use 'static' to give inl
7373

7474
#pragma clang diagnostic pop
7575

76-
inline void defineStaticVar(void) { // expected-note {{use 'static' to give inline function 'defineStaticVar' internal linkage}}
76+
inline void defineStaticVar(void) { // ok (no -pedantic)
7777
static const int x = 0; // ok
78-
static int y = 0; // expected-warning {{non-constant static local variable in inline function may be different in different files}}
78+
static int y = 0; // ok (no -pedantic)
7979
}
8080

8181
extern inline void defineStaticVarInExtern(void) {

0 commit comments

Comments
 (0)