From: Martin Uecker Date: Sat, 14 Oct 2023 07:09:07 +0000 (+0200) Subject: c: error for function with external and internal linkage [PR111708] X-Git-Tag: basepoints/gcc-15~5450 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1f186f64b8602d74769af4a6250255e51227f744;p=thirdparty%2Fgcc.git 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 5822faf01b48..0de384783041 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -8032,6 +8032,27 @@ 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 + && TREE_PUBLIC (decl) + && 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 % " + "redeclared %"); + } } else { diff --git a/gcc/testsuite/gcc.dg/pr111708-1.c b/gcc/testsuite/gcc.dg/pr111708-1.c new file mode 100644 index 000000000000..4af7f53d75f0 --- /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 000000000000..065c0525c2eb --- /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) { } +} +