Skip to content

Commit cf6bd6f

Browse files
committed
Fix members of an extern template class from being in every TU [GH #252]
1 parent be10744 commit cf6bd6f

37 files changed

Lines changed: 152 additions & 53 deletions

‎src/c_gen_be.c‎

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10851,12 +10851,19 @@ if this routine has a body (dump nothing if it has no body).
1085110851
a_boolean is_marked_weak = FALSE;
1085210852
a_boolean thread_local_init_case = FALSE;
1085310853
a_boolean for_inlining_only;
10854+
a_boolean inline_only_defn = FALSE;
10855+
a_boolean need_gnu_inline_attr = FALSE;
1085410856

1085510857
if (c99_mode && rout->definition_for_inlining_only &&
10856-
!gcc_version_is(< 50000)) {
10858+
!gcc_version_is(< 50000)
10859+
#if GNU_EXTENSIONS_ALLOWED
10860+
&& !rout->gnu_c89_inline
10861+
#endif /* GNU_EXTENSIONS_ALLOWED */
10862+
) {
1085710863
/* This is a C99 "inline definition", so we must suppress the "extern"
1085810864
keyword to avoid turning it into an external definition. (gcc did
10859-
not support C99 inline semantics until version 5.1.0.) */
10865+
not support C99 inline semantics until version 5.1.0. A routine with
10866+
the gnu_inline attribute follows the GNU C89 rules instead.) */
1086010867
for_inlining_only = TRUE;
1086110868
} else {
1086210869
for_inlining_only = FALSE;
@@ -10881,8 +10888,23 @@ if this routine has a body (dump nothing if it has no body).
1088110888
provided only for the purpose of inlining -- "extern inline".
1088210889
Put out the definition in that case. */
1088310890
has_defn = TRUE;
10891+
inline_only_defn = TRUE;
1088410892
if (!for_inlining_only) {
1088510893
storage_class = (a_storage_class)sc_extern;
10894+
/* "extern inline" is a definition only for inlining under the GNU
10895+
C89 rules, but an external definition under the C99 rules (the
10896+
gcc default since 5.1), so request the former with the gnu_inline
10897+
attribute. */
10898+
need_gnu_inline_attr = TRUE;
10899+
#if GCC_IS_GENERATED_CODE_TARGET
10900+
if (gcc_is_generated_code_target &&
10901+
gnu_target_version_number < 40200) {
10902+
need_gnu_inline_attr = FALSE;
10903+
} /* if */
10904+
#endif /* GCC_IS_GENERATED_CODE_TARGET */
10905+
#if GNU_EXTENSIONS_ALLOWED
10906+
if (rout->gnu_c89_inline) need_gnu_inline_attr = FALSE;
10907+
#endif /* GNU_EXTENSIONS_ALLOWED */
1088610908
} /* if */
1088710909
} /* if */
1088810910
} /* if */
@@ -11143,15 +11165,18 @@ if this routine has a body (dump nothing if it has no body).
1114311165
#endif /* MICROSOFT_EXTENSIONS_ALLOWED */
1114411166
if (gcc_or_clang_is_generated_code_target && rout->is_inline) {
1114511167
/* gcc will be used to compile this generated code, so we know how to
11146-
indicate an inline function. */
11147-
/* gcc ignores __inline__ on functions with ellipses, so don't
11148-
mark such functions as inline. Recent versions of gcc issue an
11149-
error for a function marked both inline and weak, so don't mark a
11150-
weak function as inline, either. */
11151-
if (!f_skip_typerefs(rout->type)->variant.routine.extra_info->
11152-
has_ellipsis &&
11168+
indicate an inline function. gcc ignores __inline__ on functions
11169+
with ellipses, so don't mark such functions as inline. Also,
11170+
recent versions of gcc issue an error for a function marked both
11171+
inline and weak, so don't mark a weak function as inline either */
11172+
if ((!f_skip_typerefs(rout->type)->variant.routine.extra_info->
11173+
has_ellipsis ||
11174+
inline_only_defn) &&
1115311175
!is_marked_weak) {
1115411176
write_tok_str("__inline__ ");
11177+
if (need_gnu_inline_attr) {
11178+
write_tok_str("__attribute__((__gnu_inline__)) ");
11179+
} /* if */
1115511180
} /* if */
1115611181
} /* if */
1115711182
#if GNU_EXTENSIONS_ALLOWED && !LOWER_IFUNC
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
[GH #252]
2+
C-generating back end: inline-only definitions emitted as external ones
3+
4+
When an inline function definition was to be used only for inlining (for
5+
example, a member of a class template specialization that is the subject of
6+
an explicit instantiation declaration), the C-generating back end emitted it
7+
as an "extern __inline__" definition for GCC and Clang. That form is a
8+
definition only for inlining under the GNU C89 rules, but an external
9+
definition under the C99 rules that GCC uses by default since version 5.
10+
Every object file that used such a function then contained an external
11+
definition of it, and linking two such object files failed. For example,
12+
with --c++17:
13+
14+
// a.h
15+
template <class T> struct A {
16+
int f() { return 1; }
17+
};
18+
extern template struct A<int>;
19+
20+
// a.cpp
21+
#include "a.h"
22+
int g1() { return A<int>().f(); }
23+
24+
// b.cpp
25+
#include "a.h"
26+
int g2() { return A<int>().f(); } // Linking with a.cpp previously failed.
27+
28+
The same problem affected GNU C89 "extern inline" functions, functions with
29+
the gnu_inline attribute in C99 and later C modes (which lost the "extern"
30+
keyword), and such definitions of functions with an ellipsis (which were not
31+
marked inline). This is now fixed: The C-generating back end now adds the
32+
__gnu_inline__ attribute to "extern __inline__" definitions, keeps "extern"
33+
for functions with the gnu_inline attribute, and marks a definition only for
34+
inlining as inline even when the function has an ellipsis.

‎tests/expectations/edg_x86_64/imported.log‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4211,7 +4211,6 @@ gnu/c/torture/pr68661-1a.sft.c:s:-DTEST_NUMBER=1:SKIPPED:
42114211
gnu/c/torture/pr68661-1b.sft.c:s:-DTEST_NUMBER=1:SKIPPED:
42124212
gnu/c/torture/pr69242.sft.c:fp:-DTEST_NUMBER=1 -w:FAIL:
42134213
gnu/c/torture/pr69886.sft.c:s:-DTEST_NUMBER=1 -w:SKIPPED:
4214-
gnu/c/torture/pr70123.sft.c:rp:-DTEST_NUMBER=1:BADC(COMPILE):
42154214
gnu/c/torture/pr70457.sft.c:fp:-DTEST_NUMBER=1:FAIL:
42164215
gnu/c/torture/pr70985.sft.c:fp:-DTEST_NUMBER=1:FAIL:
42174216
gnu/c/torture/pr71594.sft.c:s:-DTEST_NUMBER=1:SKIPPED:

‎tests/tests/imported/gnu/c/torture/.pr70123.rto/default.1.1.txt‎

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,3 @@ eccp -DTEST_NUMBER=1 --gnu_version=999999 -e 200 --no_wrap --no_wrap_diagnostics
5959
__attribute__ ((noinline, noclone)) int
6060
^
6161

62-
eccp: diagnostics generated from compilation of Test_name.int.c:
63-
Test_name.c: In function 'baz':
64-
Test_name.c:15:8: error: invalid use of '__builtin_va_arg_pack ()'
65-
eccp: end of diagnostics from compilation of Test_name.int.c
66-
eccp: gcc compilation of Test_name.int.c returned an exit status of 1
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
./a.out
Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1 @@
11
eccp -DTEST_NUMBER=1 --gnu_version=999999 -e 200 --no_wrap --no_wrap_diagnostics --gcc Test_name.c
2-
eccp: diagnostics generated from compilation of Test_name.int.c:
3-
Test_name.c: In function 'baz':
4-
Test_name.c:15:8: error: invalid use of '__builtin_va_arg_pack ()'
5-
eccp: end of diagnostics from compilation of Test_name.int.c
6-
eccp: gcc compilation of Test_name.int.c returned an exit status of 1
Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1 @@
11
eccp -DTEST_NUMBER=1 --gnu_version=999999 -e 200 --no_wrap --no_wrap_diagnostics --gcc Test_name.c
2-
eccp: diagnostics generated from compilation of Test_name.int.c:
3-
Test_name.c: In function 'baz':
4-
Test_name.c:15:8: error: invalid use of '__builtin_va_arg_pack ()'
5-
eccp: end of diagnostics from compilation of Test_name.int.c
6-
eccp: gcc compilation of Test_name.int.c returned an exit status of 1

‎tests/tests/imported/gnu/cpp/ext/.va-arg-pack-1.rto/default.1.1.txt‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
eccp -DTEST_NUMBER=1 --gnu_version=999999 -tused -e 200 --no_wrap --no_wrap_diagnostics Test_name.c
22
eccp: diagnostics generated from compilation of Test_name.int.c:
3-
./ext/va-arg-pack-1.C: In function '_Z3bariz':
4-
./ext/va-arg-pack-1.C:127:108: error: invalid use of '__builtin_va_arg_pack ()'
5-
./ext/va-arg-pack-1.C:128:114: error: invalid use of '__builtin_va_arg_pack ()'
63
In function '_Z3bariz',
74
inlined from 'main' at ./ext/va-arg-pack-1.C:134:103:
85
./ext/va-arg-pack-1.C:127:108: error: invalid use of '__builtin_va_arg_pack ()'

‎tests/tests/imported/gnu/cpp/ext/.va-arg-pack-1.rto/edg_x86_32.1.1.txt‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
eccp -DTEST_NUMBER=1 --gnu_version=999999 -tused -e 200 --no_wrap --no_wrap_diagnostics Test_name.c
22
eccp: diagnostics generated from compilation of Test_name.int.c:
3-
./ext/va-arg-pack-1.C: In function '_Z3bariz':
4-
./ext/va-arg-pack-1.C:127:93: error: invalid use of '__builtin_va_arg_pack ()'
5-
./ext/va-arg-pack-1.C:128:99: error: invalid use of '__builtin_va_arg_pack ()'
63
In function '_Z3bariz',
74
inlined from 'main' at ./ext/va-arg-pack-1.C:134:88:
85
./ext/va-arg-pack-1.C:127:93: error: invalid use of '__builtin_va_arg_pack ()'

‎tests/tests/imported/gnu/cpp/ext/.va-arg-pack-1.rto/edg_x86_32_cp.1.1.txt‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
eccp -DTEST_NUMBER=1 --gnu_version=999999 -tused -e 200 --no_wrap --no_wrap_diagnostics Test_name.c
22
eccp: diagnostics generated from compilation of Test_name.int.c:
3-
./ext/va-arg-pack-1.C: In function '_Z3bariz':
4-
./ext/va-arg-pack-1.C:127:92: error: invalid use of '__builtin_va_arg_pack ()'
5-
./ext/va-arg-pack-1.C:128:98: error: invalid use of '__builtin_va_arg_pack ()'
63
In function '_Z3bariz',
74
inlined from 'main' at ./ext/va-arg-pack-1.C:134:88:
85
./ext/va-arg-pack-1.C:127:92: error: invalid use of '__builtin_va_arg_pack ()'

0 commit comments

Comments
 (0)