Skip to content

Commit 773d310

Browse files
mborlanddaveedvdv-nvidia
authored andcommitted
Prioritize "weak" over "always_inline" in C-generating back end. [GH edgcpp#175]
1 parent 4b6c10b commit 773d310

11 files changed

Lines changed: 76 additions & 7 deletions

File tree

‎src/Changes‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,33 @@ For example, with --g++:
2626

2727
This is now fixed: When GCC is the back end compiler, such calls are now not
2828
inlined into a routine that has the always_inline attribute.
29+
10/7/26 [GH #175]
30+
C-generating back end: always_inline routines defined in several objects
31+
32+
When a routine placed in a COMDAT group also had the GNU "always_inline"
33+
attribute, the C-generating back end suppressed the __weak__ attribute that
34+
it otherwise uses to approximate the COMDAT group (see the entry for
35+
EDGcpfe/21186 of 5/2/19). As a result, every object file that defined the
36+
routine contained a conflicting external definition of it, and linking two
37+
such object files failed. For example, with --g++:
38+
39+
// twice.h
40+
[[gnu::always_inline]] inline int twice(int x) { return x + x; }
41+
42+
// test.cpp
43+
#include "twice.h"
44+
using fn = int (*)(int);
45+
fn other();
46+
int main() { return (&twice == other() && twice(1) == 2) ? 0 : 1; }
47+
48+
// other.cpp
49+
#include "twice.h"
50+
using fn = int (*)(int);
51+
fn other() { return &twice; } // Linking with test.cpp previously failed.
52+
53+
This is now fixed: When generating code targeting GCC, the C-generating back
54+
end now preserves the __weak__ attribute and suppresses the __always_inline__
55+
attribute instead.
2956

3057

3158
10/5/26 [GH #195]

‎src/c_gen_be.c‎

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11086,20 +11086,26 @@ if this routine has a body (dump nothing if it has no body).
1108611086
(a_storage_class)sc_unspecified,
1108711087
"dump_routine_decl: rout without defn in comdat");
1108811088
if (gcc_or_clang_is_generated_code_target
11089-
#if GNU_EXTENSIONS_ALLOWED
11090-
&& !rout->always_inline /* gcc gives an error on weak functions with
11091-
the always_inline attribute (because they
11092-
can change at link time). */
11093-
#if !LOWER_IFUNC
11089+
#if GNU_EXTENSIONS_ALLOWED && !LOWER_IFUNC
1109411090
&& !rout->is_ifunc /* gcc doesn't allow ifunc to be weak, so
1109511091
suppress the weak attribute (though this
1109611092
may result in multiple-definition errors
1109711093
in some cases). */
11098-
#endif /* !LOWER_IFUNC */
11099-
#endif /* GNU_EXTENSIONS_ALLOWED */
11094+
#endif /* GNU_EXTENSIONS_ALLOWED && !LOWER_IFUNC */
1110011095
) {
1110111096
/* GCC does not support COMDAT, but it does support weak, which
1110211097
provides a sufficient approximation. */
11098+
#if GNU_EXTENSIONS_ALLOWED
11099+
if (rout->always_inline && gcc_is_generated_code_target) {
11100+
/* gcc gives an error on calls to a weak function with the
11101+
always_inline attribute (because the definition could be
11102+
replaced at link time). Without the weak attribute each
11103+
translation unit that defines the routine contains a conflicting
11104+
external definition of it, so suppress the always_inline
11105+
attribute instead (Clang accepts both). */
11106+
rout->always_inline = FALSE;
11107+
} /* if */
11108+
#endif /* GNU_EXTENSIONS_ALLOWED */
1110311109
write_tok_str(" __attribute__((__weak__))");
1110411110
is_marked_weak = TRUE;
1110511111
} /* if */
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
eccp -DTEST_NUMBER=1 --c++17 --g++ Test_name.c other.C
2+
Test_name.c:
3+
other.C:
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
./a.out
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
eccp -DTEST_NUMBER=2 --c++17 --g++ -tused Test_name.c other.C
2+
Test_name.c:
3+
other.C:
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
./a.out
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
eccp -DTEST_NUMBER=3 --c++17 --clang Test_name.c other.C
2+
Test_name.c:
3+
other.C:
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
./a.out
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#include "twice.h"
2+
using fn = int (*)(int);
3+
using move_fn = int &&(*)(int &);
4+
fn other() { return &twice; }
5+
move_fn other_move() { return &move_it<int>; }
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//type:rp
2+
//options:--c++17 --g++:--c++17 --g++ -tused:--c++17 --clang
3+
//source_files:twice.h other.C
4+
#include "twice.h"
5+
using fn = int (*)(int);
6+
using move_fn = int &&(*)(int &);
7+
fn other();
8+
move_fn other_move();
9+
int main() {
10+
int i = 1;
11+
return (&twice == other() && twice(1) == 2 &&
12+
&move_it<int> == other_move() && move_it(i) == 1) ? 0 : 1;
13+
}

0 commit comments

Comments
 (0)