diff --git a/src/c_gen_be.c b/src/c_gen_be.c index 644f356700..86cd0fc9ff 100644 --- a/src/c_gen_be.c +++ b/src/c_gen_be.c @@ -10851,12 +10851,19 @@ if this routine has a body (dump nothing if it has no body). a_boolean is_marked_weak = FALSE; a_boolean thread_local_init_case = FALSE; a_boolean for_inlining_only; + a_boolean inline_only_defn = FALSE; + a_boolean need_gnu_inline_attr = FALSE; if (c99_mode && rout->definition_for_inlining_only && - !gcc_version_is(< 50000)) { + !gcc_version_is(< 50000) +#if GNU_EXTENSIONS_ALLOWED + && !rout->gnu_c89_inline +#endif /* GNU_EXTENSIONS_ALLOWED */ + ) { /* This is a C99 "inline definition", so we must suppress the "extern" keyword to avoid turning it into an external definition. (gcc did - not support C99 inline semantics until version 5.1.0.) */ + not support C99 inline semantics until version 5.1.0. A routine with + the gnu_inline attribute follows the GNU C89 rules instead.) */ for_inlining_only = TRUE; } else { for_inlining_only = FALSE; @@ -10881,8 +10888,29 @@ if this routine has a body (dump nothing if it has no body). provided only for the purpose of inlining -- "extern inline". Put out the definition in that case. */ has_defn = TRUE; + inline_only_defn = TRUE; if (!for_inlining_only) { storage_class = (a_storage_class)sc_extern; + /* "extern inline" is a definition only for inlining under the GNU + C89 rules, but an external definition under the C99 rules (used + by gcc in C99 modes since 4.3, and by default since 5.1), so + request the former with the gnu_inline attribute. As in + form_routine_attributes, omit it for gcc before 4.2, which does + not recognize it but always follows the GNU C89 rules. */ + need_gnu_inline_attr = TRUE; +#if GCC_IS_GENERATED_CODE_TARGET + if (gcc_is_generated_code_target && + gnu_target_version_number < 40200) { + need_gnu_inline_attr = FALSE; + } /* if */ +#endif /* GCC_IS_GENERATED_CODE_TARGET */ +#if GNU_EXTENSIONS_ALLOWED + if (rout->gnu_c89_inline) { + /* form_routine_attributes already puts out the gnu_inline + attribute for this routine. */ + need_gnu_inline_attr = FALSE; + } /* if */ +#endif /* GNU_EXTENSIONS_ALLOWED */ } /* if */ } /* if */ } /* if */ @@ -11145,13 +11173,17 @@ if this routine has a body (dump nothing if it has no body). /* gcc will be used to compile this generated code, so we know how to indicate an inline function. */ /* gcc ignores __inline__ on functions with ellipses, so don't - mark such functions as inline. Recent versions of gcc issue an - error for a function marked both inline and weak, so don't mark a - weak function as inline, either. */ - if (!f_skip_typerefs(rout->type)->variant.routine.extra_info-> - has_ellipsis && + mark such functions as inline, except for a definition only for + inlining, which would otherwise be an external definition. Recent + versions of gcc issue an error for a function marked both inline and + weak, so don't mark a weak function as inline, either. */ + if ((!rout_type_supp(f_skip_typerefs(rout->type))->has_ellipsis || + inline_only_defn) && !is_marked_weak) { write_tok_str("__inline__ "); + if (need_gnu_inline_attr) { + write_tok_str("__attribute__((__gnu_inline__)) "); + } /* if */ } /* if */ } /* if */ #if GNU_EXTENSIONS_ALLOWED && !LOWER_IFUNC diff --git a/src/pending_changes/gh-252-extern-inline-definitions.txt b/src/pending_changes/gh-252-extern-inline-definitions.txt new file mode 100644 index 0000000000..b639983f37 --- /dev/null +++ b/src/pending_changes/gh-252-extern-inline-definitions.txt @@ -0,0 +1,38 @@ +[GH #252] +C-generating back end: inline-only definitions emitted as external ones + +When an inline function definition was to be used only for inlining (for +example, a member of a class template specialization that is the subject of +an explicit instantiation declaration), the C-generating back end emitted it +as an "extern __inline__" definition for GCC and Clang. That form is a +definition only for inlining under the GNU C89 rules, but an external +definition under the C99 rules that GCC uses by default since version 5. +Every object file that used such a function then contained an external +definition of it, and linking two such object files failed. For example, +with --c++17: + + // a.h + template struct A { + int f() { return 1; } + }; + extern template struct A; + + // a.cpp + #include "a.h" + int g1() { return A().f(); } + + // b.cpp + #include "a.h" + int g2() { return A().f(); } // Linking with a.cpp previously failed. + + // c.cpp + #include "a.h" + template struct A; + +The same problem affected GNU C89 "extern inline" functions, functions with +the gnu_inline attribute in C99 and later C modes (which lost the "extern" +keyword), and such definitions of functions with an ellipsis (which were not +marked inline). This is now fixed: The C-generating back end now adds the +__gnu_inline__ attribute to "extern __inline__" definitions, keeps "extern" +for functions with the gnu_inline attribute, and marks a definition only for +inlining as inline even when the function has an ellipsis. diff --git a/tests/expectations/edg_x86_64/imported.log b/tests/expectations/edg_x86_64/imported.log index ada16fd747..322752f038 100644 --- a/tests/expectations/edg_x86_64/imported.log +++ b/tests/expectations/edg_x86_64/imported.log @@ -4211,7 +4211,6 @@ gnu/c/torture/pr68661-1a.sft.c:s:-DTEST_NUMBER=1:SKIPPED: gnu/c/torture/pr68661-1b.sft.c:s:-DTEST_NUMBER=1:SKIPPED: gnu/c/torture/pr69242.sft.c:fp:-DTEST_NUMBER=1 -w:FAIL: gnu/c/torture/pr69886.sft.c:s:-DTEST_NUMBER=1 -w:SKIPPED: -gnu/c/torture/pr70123.sft.c:rp:-DTEST_NUMBER=1:BADC(COMPILE): gnu/c/torture/pr70457.sft.c:fp:-DTEST_NUMBER=1:FAIL: gnu/c/torture/pr70985.sft.c:fp:-DTEST_NUMBER=1:FAIL: gnu/c/torture/pr71594.sft.c:s:-DTEST_NUMBER=1:SKIPPED: diff --git a/tests/tests/imported/gnu/c/torture/.pr70123.rto/default.1.1.txt b/tests/tests/imported/gnu/c/torture/.pr70123.rto/default.1.1.txt index 6122b6ca2b..6b1a64e524 100644 --- a/tests/tests/imported/gnu/c/torture/.pr70123.rto/default.1.1.txt +++ b/tests/tests/imported/gnu/c/torture/.pr70123.rto/default.1.1.txt @@ -59,8 +59,3 @@ eccp -DTEST_NUMBER=1 --gnu_version=999999 -e 200 --no_wrap --no_wrap_diagnostics __attribute__ ((noinline, noclone)) int ^ -eccp: diagnostics generated from compilation of Test_name.int.c: -Test_name.c: In function 'baz': -Test_name.c:15:8: error: invalid use of '__builtin_va_arg_pack ()' -eccp: end of diagnostics from compilation of Test_name.int.c -eccp: gcc compilation of Test_name.int.c returned an exit status of 1 diff --git a/tests/tests/imported/gnu/c/torture/.pr70123.rto/default.1.2.txt b/tests/tests/imported/gnu/c/torture/.pr70123.rto/default.1.2.txt new file mode 100644 index 0000000000..ff2642c6d5 --- /dev/null +++ b/tests/tests/imported/gnu/c/torture/.pr70123.rto/default.1.2.txt @@ -0,0 +1 @@ +./a.out diff --git a/tests/tests/imported/gnu/c/torture/.pr70123.rto/edg_x86_32_cp.1.1.txt b/tests/tests/imported/gnu/c/torture/.pr70123.rto/edg_x86_32_cp.1.1.txt index 745f05b3b6..531b329c84 100644 --- a/tests/tests/imported/gnu/c/torture/.pr70123.rto/edg_x86_32_cp.1.1.txt +++ b/tests/tests/imported/gnu/c/torture/.pr70123.rto/edg_x86_32_cp.1.1.txt @@ -1,6 +1 @@ eccp -DTEST_NUMBER=1 --gnu_version=999999 -e 200 --no_wrap --no_wrap_diagnostics --gcc Test_name.c -eccp: diagnostics generated from compilation of Test_name.int.c: -Test_name.c: In function 'baz': -Test_name.c:15:8: error: invalid use of '__builtin_va_arg_pack ()' -eccp: end of diagnostics from compilation of Test_name.int.c -eccp: gcc compilation of Test_name.int.c returned an exit status of 1 diff --git a/tests/tests/imported/gnu/c/torture/.pr70123.rto/edg_x86_64_cp.1.1.txt b/tests/tests/imported/gnu/c/torture/.pr70123.rto/edg_x86_64_cp.1.1.txt index 745f05b3b6..531b329c84 100644 --- a/tests/tests/imported/gnu/c/torture/.pr70123.rto/edg_x86_64_cp.1.1.txt +++ b/tests/tests/imported/gnu/c/torture/.pr70123.rto/edg_x86_64_cp.1.1.txt @@ -1,6 +1 @@ eccp -DTEST_NUMBER=1 --gnu_version=999999 -e 200 --no_wrap --no_wrap_diagnostics --gcc Test_name.c -eccp: diagnostics generated from compilation of Test_name.int.c: -Test_name.c: In function 'baz': -Test_name.c:15:8: error: invalid use of '__builtin_va_arg_pack ()' -eccp: end of diagnostics from compilation of Test_name.int.c -eccp: gcc compilation of Test_name.int.c returned an exit status of 1 diff --git a/tests/tests/imported/gnu/cpp/ext/.va-arg-pack-1.rto/default.1.1.txt b/tests/tests/imported/gnu/cpp/ext/.va-arg-pack-1.rto/default.1.1.txt index c6cecbacaa..7319dec802 100644 --- a/tests/tests/imported/gnu/cpp/ext/.va-arg-pack-1.rto/default.1.1.txt +++ b/tests/tests/imported/gnu/cpp/ext/.va-arg-pack-1.rto/default.1.1.txt @@ -1,8 +1,5 @@ eccp -DTEST_NUMBER=1 --gnu_version=999999 -tused -e 200 --no_wrap --no_wrap_diagnostics Test_name.c eccp: diagnostics generated from compilation of Test_name.int.c: -./ext/va-arg-pack-1.C: In function '_Z3bariz': -./ext/va-arg-pack-1.C:127:108: error: invalid use of '__builtin_va_arg_pack ()' -./ext/va-arg-pack-1.C:128:114: error: invalid use of '__builtin_va_arg_pack ()' In function '_Z3bariz', inlined from 'main' at ./ext/va-arg-pack-1.C:134:103: ./ext/va-arg-pack-1.C:127:108: error: invalid use of '__builtin_va_arg_pack ()' diff --git a/tests/tests/imported/gnu/cpp/ext/.va-arg-pack-1.rto/edg_x86_32.1.1.txt b/tests/tests/imported/gnu/cpp/ext/.va-arg-pack-1.rto/edg_x86_32.1.1.txt index 0d28c7d687..a006454d35 100644 --- a/tests/tests/imported/gnu/cpp/ext/.va-arg-pack-1.rto/edg_x86_32.1.1.txt +++ b/tests/tests/imported/gnu/cpp/ext/.va-arg-pack-1.rto/edg_x86_32.1.1.txt @@ -1,8 +1,5 @@ eccp -DTEST_NUMBER=1 --gnu_version=999999 -tused -e 200 --no_wrap --no_wrap_diagnostics Test_name.c eccp: diagnostics generated from compilation of Test_name.int.c: -./ext/va-arg-pack-1.C: In function '_Z3bariz': -./ext/va-arg-pack-1.C:127:93: error: invalid use of '__builtin_va_arg_pack ()' -./ext/va-arg-pack-1.C:128:99: error: invalid use of '__builtin_va_arg_pack ()' In function '_Z3bariz', inlined from 'main' at ./ext/va-arg-pack-1.C:134:88: ./ext/va-arg-pack-1.C:127:93: error: invalid use of '__builtin_va_arg_pack ()' diff --git a/tests/tests/imported/gnu/cpp/ext/.va-arg-pack-1.rto/edg_x86_32_cp.1.1.txt b/tests/tests/imported/gnu/cpp/ext/.va-arg-pack-1.rto/edg_x86_32_cp.1.1.txt index cacadf2663..4803c8057f 100644 --- a/tests/tests/imported/gnu/cpp/ext/.va-arg-pack-1.rto/edg_x86_32_cp.1.1.txt +++ b/tests/tests/imported/gnu/cpp/ext/.va-arg-pack-1.rto/edg_x86_32_cp.1.1.txt @@ -1,8 +1,5 @@ eccp -DTEST_NUMBER=1 --gnu_version=999999 -tused -e 200 --no_wrap --no_wrap_diagnostics Test_name.c eccp: diagnostics generated from compilation of Test_name.int.c: -./ext/va-arg-pack-1.C: In function '_Z3bariz': -./ext/va-arg-pack-1.C:127:92: error: invalid use of '__builtin_va_arg_pack ()' -./ext/va-arg-pack-1.C:128:98: error: invalid use of '__builtin_va_arg_pack ()' In function '_Z3bariz', inlined from 'main' at ./ext/va-arg-pack-1.C:134:88: ./ext/va-arg-pack-1.C:127:92: error: invalid use of '__builtin_va_arg_pack ()' diff --git a/tests/tests/imported/gnu/cpp/ext/.va-arg-pack-1.rto/edg_x86_64_cp.1.1.txt b/tests/tests/imported/gnu/cpp/ext/.va-arg-pack-1.rto/edg_x86_64_cp.1.1.txt index f4bcf016bc..25e22e7512 100644 --- a/tests/tests/imported/gnu/cpp/ext/.va-arg-pack-1.rto/edg_x86_64_cp.1.1.txt +++ b/tests/tests/imported/gnu/cpp/ext/.va-arg-pack-1.rto/edg_x86_64_cp.1.1.txt @@ -1,8 +1,5 @@ eccp -DTEST_NUMBER=1 --gnu_version=999999 -tused -e 200 --no_wrap --no_wrap_diagnostics Test_name.c eccp: diagnostics generated from compilation of Test_name.int.c: -./ext/va-arg-pack-1.C: In function '_Z3bariz': -./ext/va-arg-pack-1.C:127:107: error: invalid use of '__builtin_va_arg_pack ()' -./ext/va-arg-pack-1.C:128:113: error: invalid use of '__builtin_va_arg_pack ()' In function '_Z3bariz', inlined from 'main' at ./ext/va-arg-pack-1.C:134:103: ./ext/va-arg-pack-1.C:127:107: error: invalid use of '__builtin_va_arg_pack ()' diff --git a/tests/tests/imported/gnu/cpp/ext/.va-arg-pack-len-1.rto/default.1.1.txt b/tests/tests/imported/gnu/cpp/ext/.va-arg-pack-len-1.rto/default.1.1.txt index 0185978c0f..a23e9136b3 100644 --- a/tests/tests/imported/gnu/cpp/ext/.va-arg-pack-len-1.rto/default.1.1.txt +++ b/tests/tests/imported/gnu/cpp/ext/.va-arg-pack-len-1.rto/default.1.1.txt @@ -1,9 +1,5 @@ eccp -DTEST_NUMBER=1 --gnu_version=999999 -tused -e 200 --no_wrap --no_wrap_diagnostics Test_name.c eccp: diagnostics generated from compilation of Test_name.int.c: -./ext/va-arg-pack-len-1.C: In function '_Z6myopenPKciz': -./ext/va-arg-pack-len-1.C:81:6: error: invalid use of '__builtin_va_arg_pack_len ()' -./ext/va-arg-pack-len-1.C:94:6: error: invalid use of '__builtin_va_arg_pack_len ()' -./ext/va-arg-pack-len-1.C:97:113: error: invalid use of '__builtin_va_arg_pack ()' In function '_Z6myopenPKciz', inlined from 'main' at ./ext/va-arg-pack-len-1.C:106:5: ./ext/va-arg-pack-len-1.C:97:113: error: invalid use of '__builtin_va_arg_pack ()' diff --git a/tests/tests/imported/gnu/cpp/ext/.va-arg-pack-len-1.rto/edg_x86_32.1.1.txt b/tests/tests/imported/gnu/cpp/ext/.va-arg-pack-len-1.rto/edg_x86_32.1.1.txt index 44837a133e..a2db210ce2 100644 --- a/tests/tests/imported/gnu/cpp/ext/.va-arg-pack-len-1.rto/edg_x86_32.1.1.txt +++ b/tests/tests/imported/gnu/cpp/ext/.va-arg-pack-len-1.rto/edg_x86_32.1.1.txt @@ -1,9 +1,5 @@ eccp -DTEST_NUMBER=1 --gnu_version=999999 -tused -e 200 --no_wrap --no_wrap_diagnostics Test_name.c eccp: diagnostics generated from compilation of Test_name.int.c: -./ext/va-arg-pack-len-1.C: In function '_Z6myopenPKciz': -./ext/va-arg-pack-len-1.C:81:6: error: invalid use of '__builtin_va_arg_pack_len ()' -./ext/va-arg-pack-len-1.C:94:6: error: invalid use of '__builtin_va_arg_pack_len ()' -./ext/va-arg-pack-len-1.C:97:98: error: invalid use of '__builtin_va_arg_pack ()' In function '_Z6myopenPKciz', inlined from 'main' at ./ext/va-arg-pack-len-1.C:106:5: ./ext/va-arg-pack-len-1.C:97:98: error: invalid use of '__builtin_va_arg_pack ()' diff --git a/tests/tests/imported/gnu/cpp/ext/.va-arg-pack-len-1.rto/edg_x86_32_cp.1.1.txt b/tests/tests/imported/gnu/cpp/ext/.va-arg-pack-len-1.rto/edg_x86_32_cp.1.1.txt index 2041861774..6eb429c218 100644 --- a/tests/tests/imported/gnu/cpp/ext/.va-arg-pack-len-1.rto/edg_x86_32_cp.1.1.txt +++ b/tests/tests/imported/gnu/cpp/ext/.va-arg-pack-len-1.rto/edg_x86_32_cp.1.1.txt @@ -1,9 +1,5 @@ eccp -DTEST_NUMBER=1 --gnu_version=999999 -tused -e 200 --no_wrap --no_wrap_diagnostics Test_name.c eccp: diagnostics generated from compilation of Test_name.int.c: -./ext/va-arg-pack-len-1.C: In function '_Z6myopenPKciz': -./ext/va-arg-pack-len-1.C:81:6: error: invalid use of '__builtin_va_arg_pack_len ()' -./ext/va-arg-pack-len-1.C:94:6: error: invalid use of '__builtin_va_arg_pack_len ()' -./ext/va-arg-pack-len-1.C:97:96: error: invalid use of '__builtin_va_arg_pack ()' In function '_Z6myopenPKciz', inlined from 'main' at ./ext/va-arg-pack-len-1.C:106:5: ./ext/va-arg-pack-len-1.C:97:96: error: invalid use of '__builtin_va_arg_pack ()' diff --git a/tests/tests/imported/gnu/cpp/ext/.va-arg-pack-len-1.rto/edg_x86_64_cp.1.1.txt b/tests/tests/imported/gnu/cpp/ext/.va-arg-pack-len-1.rto/edg_x86_64_cp.1.1.txt index dd35fd4688..ac46c2dd13 100644 --- a/tests/tests/imported/gnu/cpp/ext/.va-arg-pack-len-1.rto/edg_x86_64_cp.1.1.txt +++ b/tests/tests/imported/gnu/cpp/ext/.va-arg-pack-len-1.rto/edg_x86_64_cp.1.1.txt @@ -1,9 +1,5 @@ eccp -DTEST_NUMBER=1 --gnu_version=999999 -tused -e 200 --no_wrap --no_wrap_diagnostics Test_name.c eccp: diagnostics generated from compilation of Test_name.int.c: -./ext/va-arg-pack-len-1.C: In function '_Z6myopenPKciz': -./ext/va-arg-pack-len-1.C:81:6: error: invalid use of '__builtin_va_arg_pack_len ()' -./ext/va-arg-pack-len-1.C:94:6: error: invalid use of '__builtin_va_arg_pack_len ()' -./ext/va-arg-pack-len-1.C:97:111: error: invalid use of '__builtin_va_arg_pack ()' In function '_Z6myopenPKciz', inlined from 'main' at ./ext/va-arg-pack-len-1.C:106:5: ./ext/va-arg-pack-len-1.C:97:111: error: invalid use of '__builtin_va_arg_pack ()' diff --git a/tests/tests/regressions/gh-252-c/.test.rto/default.1.1.txt b/tests/tests/regressions/gh-252-c/.test.rto/default.1.1.txt new file mode 100644 index 0000000000..dd835ceabf --- /dev/null +++ b/tests/tests/regressions/gh-252-c/.test.rto/default.1.1.txt @@ -0,0 +1,4 @@ +eccp -DTEST_NUMBER=1 --c11 Test_name.c use.c def.c +Test_name.c: +use.c: +def.c: diff --git a/tests/tests/regressions/gh-252-c/.test.rto/default.1.2.txt b/tests/tests/regressions/gh-252-c/.test.rto/default.1.2.txt new file mode 100644 index 0000000000..ff2642c6d5 --- /dev/null +++ b/tests/tests/regressions/gh-252-c/.test.rto/default.1.2.txt @@ -0,0 +1 @@ +./a.out diff --git a/tests/tests/regressions/gh-252-c/.test.rto/default.2.1.txt b/tests/tests/regressions/gh-252-c/.test.rto/default.2.1.txt new file mode 100644 index 0000000000..1d10c3be1d --- /dev/null +++ b/tests/tests/regressions/gh-252-c/.test.rto/default.2.1.txt @@ -0,0 +1,4 @@ +eccp -DTEST_NUMBER=2 --c11 --gnu=150100 Test_name.c use.c def.c +Test_name.c: +use.c: +def.c: diff --git a/tests/tests/regressions/gh-252-c/.test.rto/default.2.2.txt b/tests/tests/regressions/gh-252-c/.test.rto/default.2.2.txt new file mode 100644 index 0000000000..ff2642c6d5 --- /dev/null +++ b/tests/tests/regressions/gh-252-c/.test.rto/default.2.2.txt @@ -0,0 +1 @@ +./a.out diff --git a/tests/tests/regressions/gh-252-c/.test.rto/default.3.1.txt b/tests/tests/regressions/gh-252-c/.test.rto/default.3.1.txt new file mode 100644 index 0000000000..d63b3e6e68 --- /dev/null +++ b/tests/tests/regressions/gh-252-c/.test.rto/default.3.1.txt @@ -0,0 +1,4 @@ +eccp -DTEST_NUMBER=3 --c --gnu=40200 Test_name.c use.c def.c +Test_name.c: +use.c: +def.c: diff --git a/tests/tests/regressions/gh-252-c/.test.rto/default.3.2.txt b/tests/tests/regressions/gh-252-c/.test.rto/default.3.2.txt new file mode 100644 index 0000000000..ff2642c6d5 --- /dev/null +++ b/tests/tests/regressions/gh-252-c/.test.rto/default.3.2.txt @@ -0,0 +1 @@ +./a.out diff --git a/tests/tests/regressions/gh-252-c/def.c b/tests/tests/regressions/gh-252-c/def.c new file mode 100644 index 0000000000..b4d07d382e --- /dev/null +++ b/tests/tests/regressions/gh-252-c/def.c @@ -0,0 +1,3 @@ +int h(void) { return 1; } +int v(int n, ...) { return n; } +int k(void) { return 1; } diff --git a/tests/tests/regressions/gh-252-c/inl.h b/tests/tests/regressions/gh-252-c/inl.h new file mode 100644 index 0000000000..a4885b4258 --- /dev/null +++ b/tests/tests/regressions/gh-252-c/inl.h @@ -0,0 +1,13 @@ +/* Definitions only for inlining. */ +#if __GNUC_GNU_INLINE__ +#define INLINE_ONLY extern inline +#else +#define INLINE_ONLY inline +#endif +INLINE_ONLY int h(void) { return 1; } +INLINE_ONLY int v(int n, ...) { return n; } +#ifdef __GNUC__ +extern inline __attribute__((gnu_inline)) int k(void) { return 1; } +#else +INLINE_ONLY int k(void) { return 1; } +#endif diff --git a/tests/tests/regressions/gh-252-c/test.mft.c b/tests/tests/regressions/gh-252-c/test.mft.c new file mode 100644 index 0000000000..fa2df78bf2 --- /dev/null +++ b/tests/tests/regressions/gh-252-c/test.mft.c @@ -0,0 +1,11 @@ +//type:rp +//options:--c11:--c11 --gnu=150100:--c --gnu=40200 +//source_files:inl.h use.c def.c +/* h, v, and k are used here and in use.c, but only def.c may define them. + Each object used to contain an external definition of v, of h (with the + GNU C89 inline rules), or of k (with the C99 inline rules). */ +#include "inl.h" +int use(void); +int main(void) { + return (h() == 1 && v(1, 2) == 1 && k() == 1 && use() == 3) ? 0 : 1; +} diff --git a/tests/tests/regressions/gh-252-c/use.c b/tests/tests/regressions/gh-252-c/use.c new file mode 100644 index 0000000000..821a2cd8fd --- /dev/null +++ b/tests/tests/regressions/gh-252-c/use.c @@ -0,0 +1,2 @@ +#include "inl.h" +int use(void) { return h() + v(1, 3) + k(); } diff --git a/tests/tests/regressions/gh-252/.test.rto/default.1.1.txt b/tests/tests/regressions/gh-252/.test.rto/default.1.1.txt new file mode 100644 index 0000000000..9fddda4ac1 --- /dev/null +++ b/tests/tests/regressions/gh-252/.test.rto/default.1.1.txt @@ -0,0 +1,7 @@ +./check_defs -DTEST_NUMBER=1 --c++17 Test_name.c use.C inst.C +Test_name.c: +use.C: +inst.C: +Test_name.o: +use.o: +inst.o: _ZN1AIiE1fEv _ZN1AIiE1gEiz diff --git a/tests/tests/regressions/gh-252/.test.rto/default.1.2.txt b/tests/tests/regressions/gh-252/.test.rto/default.1.2.txt new file mode 100644 index 0000000000..ff2642c6d5 --- /dev/null +++ b/tests/tests/regressions/gh-252/.test.rto/default.1.2.txt @@ -0,0 +1 @@ +./a.out diff --git a/tests/tests/regressions/gh-252/.test.rto/default.2.1.txt b/tests/tests/regressions/gh-252/.test.rto/default.2.1.txt new file mode 100644 index 0000000000..1371461338 --- /dev/null +++ b/tests/tests/regressions/gh-252/.test.rto/default.2.1.txt @@ -0,0 +1,7 @@ +./check_defs -DTEST_NUMBER=2 --c++17 --g++ Test_name.c use.C inst.C +Test_name.c: +use.C: +inst.C: +Test_name.o: +use.o: +inst.o: _ZN1AIiE1fEv _ZN1AIiE1gEiz diff --git a/tests/tests/regressions/gh-252/.test.rto/default.2.2.txt b/tests/tests/regressions/gh-252/.test.rto/default.2.2.txt new file mode 100644 index 0000000000..ff2642c6d5 --- /dev/null +++ b/tests/tests/regressions/gh-252/.test.rto/default.2.2.txt @@ -0,0 +1 @@ +./a.out diff --git a/tests/tests/regressions/gh-252/.test.rto/default.3.1.txt b/tests/tests/regressions/gh-252/.test.rto/default.3.1.txt new file mode 100644 index 0000000000..38e27fcbb3 --- /dev/null +++ b/tests/tests/regressions/gh-252/.test.rto/default.3.1.txt @@ -0,0 +1,7 @@ +./check_defs -DTEST_NUMBER=3 --c++17 --g++ -tused Test_name.c use.C inst.C +Test_name.c: +use.C: +inst.C: +Test_name.o: +use.o: +inst.o: _ZN1AIiE1fEv _ZN1AIiE1gEiz diff --git a/tests/tests/regressions/gh-252/.test.rto/default.3.2.txt b/tests/tests/regressions/gh-252/.test.rto/default.3.2.txt new file mode 100644 index 0000000000..ff2642c6d5 --- /dev/null +++ b/tests/tests/regressions/gh-252/.test.rto/default.3.2.txt @@ -0,0 +1 @@ +./a.out diff --git a/tests/tests/regressions/gh-252/.test.rto/default.4.1.txt b/tests/tests/regressions/gh-252/.test.rto/default.4.1.txt new file mode 100644 index 0000000000..3f77797318 --- /dev/null +++ b/tests/tests/regressions/gh-252/.test.rto/default.4.1.txt @@ -0,0 +1,7 @@ +./check_defs -DTEST_NUMBER=4 --c++17 --clang Test_name.c use.C inst.C +Test_name.c: +use.C: +inst.C: +Test_name.o: +use.o: +inst.o: _ZN1AIiE1fEv _ZN1AIiE1gEiz diff --git a/tests/tests/regressions/gh-252/.test.rto/default.4.2.txt b/tests/tests/regressions/gh-252/.test.rto/default.4.2.txt new file mode 100644 index 0000000000..ff2642c6d5 --- /dev/null +++ b/tests/tests/regressions/gh-252/.test.rto/default.4.2.txt @@ -0,0 +1 @@ +./a.out diff --git a/tests/tests/regressions/gh-252/a.h b/tests/tests/regressions/gh-252/a.h new file mode 100644 index 0000000000..297a0271c8 --- /dev/null +++ b/tests/tests/regressions/gh-252/a.h @@ -0,0 +1,5 @@ +template struct A { + int f() { return 1; } + int g(int n, ...) { return n; } +}; +extern template struct A; diff --git a/tests/tests/regressions/gh-252/check_defs b/tests/tests/regressions/gh-252/check_defs new file mode 100755 index 0000000000..529e7bcbe9 --- /dev/null +++ b/tests/tests/regressions/gh-252/check_defs @@ -0,0 +1,31 @@ +#!/bin/bash +# Compile each source file to an object file, check that only inst.o (the +# explicit instantiation) defines A::f and A::g, and then link the +# object files. +opts= +objs= +for arg in "$@"; do + case $arg in + *.c | *.C) objs="$objs ${arg%.*}.o" ;; + *) opts="$opts $arg" ;; + esac +done +eccp -c "$@" || exit $? +status=0 +for obj in $objs; do + defs=`nm -g --defined-only $obj | grep -o '_ZN1AIiE1[fg]E[a-z]*' | sort` + defs=`echo $defs` + echo $obj: $defs + expected= + if [ $obj = inst.o ]; then + expected="_ZN1AIiE1fEv _ZN1AIiE1gEiz" + fi + if [ "$defs" != "$expected" ]; then + echo "FAIL: Expected '$expected'." + status=1 + fi +done +if [ $status -ne 0 ]; then + exit $status +fi +exec eccp $opts $objs diff --git a/tests/tests/regressions/gh-252/inst.C b/tests/tests/regressions/gh-252/inst.C new file mode 100644 index 0000000000..fb8d2dec70 --- /dev/null +++ b/tests/tests/regressions/gh-252/inst.C @@ -0,0 +1,2 @@ +#include "a.h" +template struct A; diff --git a/tests/tests/regressions/gh-252/test.mft.cpp b/tests/tests/regressions/gh-252/test.mft.cpp new file mode 100644 index 0000000000..66e8cc51f5 --- /dev/null +++ b/tests/tests/regressions/gh-252/test.mft.cpp @@ -0,0 +1,11 @@ +//type:rp +//options:--c++17:--c++17 --g++:--c++17 --g++ -tused:--c++17 --clang +//source_files:a.h use.C inst.C +//script:./check_defs +// The members of A are used here and in use.C, but only inst.C may +// define them; each object used to contain an external definition. +#include "a.h" +int use(); +int main() { + return (A().f() == 1 && A().g(1, 2) == 1 && use() == 2) ? 0 : 1; +} diff --git a/tests/tests/regressions/gh-252/use.C b/tests/tests/regressions/gh-252/use.C new file mode 100644 index 0000000000..feeb2a7ab7 --- /dev/null +++ b/tests/tests/regressions/gh-252/use.C @@ -0,0 +1,2 @@ +#include "a.h" +int use() { return A().f() + A().g(1, 3); }