Bootstrapped and regression tested on x86_64.
c: error for function with external and internal linkage [PR111708] Declaring a function with both external and internal linkage in the same TU is translation-time UB. Add an error for this case as already done for objects. PR c/111708 gcc/c/Changelog: * c-decl.cc (grokdeclarator): Add error. gcc/testsuite/Changelog: * gcc.dg/pr111708-1.c: New test. * gcc.dg/pr111708-2.c: New test. diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index 5822faf01b4..52490a784d0 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -8032,6 +8032,28 @@ grokdeclarator (const struct c_declarator *declarator, TREE_THIS_VOLATILE (decl) = 1; } } + + /* C99 6.2.2p7: It is invalid (compile-time undefined + behavior) to create an 'extern' declaration for a + function if there is a global declaration that is + 'static' and the global declaration is not visible. + (If the static declaration _is_ currently visible, + the 'extern' declaration is taken to refer to that decl.) */ + if (!initialized + && storage_class != csc_static + && storage_class != csc_auto + && current_scope != file_scope) + { + tree global_decl = identifier_global_value (declarator->u.id.id); + tree visible_decl = lookup_name (declarator->u.id.id); + + if (global_decl + && global_decl != visible_decl + && VAR_OR_FUNCTION_DECL_P (global_decl) + && !TREE_PUBLIC (global_decl)) + error_at (loc, "function previously declared %<static%> " + "redeclared %<extern%>"); + } } else { diff --git a/gcc/testsuite/gcc.dg/pr111708-1.c b/gcc/testsuite/gcc.dg/pr111708-1.c new file mode 100644 index 00000000000..4af7f53d75f --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr111708-1.c @@ -0,0 +1,42 @@ +/* { dg-do compile } */ +/* { dg-options "" } */ + +extern int a(void); // external linkage (6.2.2p4) +static int a(void); /* { dg-error "static declaration of 'a' follows non-static declaration" } */ + +static int b(void); // internal linkage (6.2.2p3) +extern int b(void); // internal linkage (6.2.2p4) + +static int h0(void); + +void s(void) +{ + extern int h0(void); // internal linkage (6.2.2p4), + extern int h0(void); // internal linkage (6.2.2p4), redeclaration, ok + extern int h2(void); // external linkage (6.2.2p4) + extern int h2(void); // external linkage (6.2.2p4), redeclaration, ok. +} + + +extern int i(void); // external linkage (6.2.2p4) +static int j(void); // internal linkage (6.2.2p3) + +void bar(void) +{ + extern int i(void); // external linkage (6.2.2p4), ok +} + +void foo(void) +{ + extern int j(void); // internal linkage (6.2.2p4), ok, internal +} + +void x(void) +{ + int i(void); // no linkage (6.2.2p6) + int j; // no linkage (6.2.2p6) + { + extern int j(void); /* { dg-error "function previously declared 'static' redeclared 'extern'" } */ + } +} + diff --git a/gcc/testsuite/gcc.dg/pr111708-2.c b/gcc/testsuite/gcc.dg/pr111708-2.c new file mode 100644 index 00000000000..065c0525c2e --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr111708-2.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "" } */ +/* { dg-require-effective-target trampolines } */ + +static void pp(void) +{ + int pp; + { + auto void pp(void); + void pp(void) { } + } +} + +static void q2(void); + +static void qq(void) +{ + auto void q2(void); + void q2(void) { } +} +