Skip to content

Commit 7222867

Browse files
authored
Set lambda linkage to LinkOnceODR (was Internal) (#5045)
This reverts #4415. The mangling of lambdas has been fixed (and is now stable and cannot clash with other modules anymore), so there is no longer a need for internal linkage. This allows merging of identical lambdas again (multiple instantiations). This also fixes an instantiation bug, where the lambda's emission is sometimes culled because the frontend knows it is already instantiated in another module, but because of internal linkage it cannot resolve the symbol during linking (thus resulting in a missing symbol during linking).
1 parent df9c533 commit 7222867

3 files changed

Lines changed: 17 additions & 20 deletions

File tree

gen/tollvm.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -229,18 +229,15 @@ LLGlobalValue::LinkageTypes DtoLinkageOnly(Dsymbol *sym) {
229229
return LLGlobalValue::InternalLinkage;
230230

231231
/* Function (incl. delegate) literals are emitted into each referencing
232-
* compilation unit, so use internal linkage for all lambdas and all global
232+
* compilation unit, so use linkonce_odr for all lambdas and all global
233233
* variables they define.
234-
* This makes sure these symbols don't accidentally collide when linking
235-
* object files compiled by different compiler invocations (lambda mangles
236-
* aren't stable - see https://issues.dlang.org/show_bug.cgi?id=23722).
237234
*/
238235
auto potentialLambda = sym;
239236
if (auto vd = sym->isVarDeclaration())
240237
if (vd->isDataseg())
241238
potentialLambda = vd->toParent2();
242239
if (potentialLambda->isFuncLiteralDeclaration())
243-
return LLGlobalValue::InternalLinkage;
240+
return LLGlobalValue::LinkOnceODRLinkage;
244241

245242
if (sym->isInstantiated())
246243
return templateLinkage;

tests/codegen/lambdas_gh3648.d

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Tests that lambdas and contained globals are emitted with internal linkage.
1+
// Tests that lambdas and contained globals are emitted as linkonce_odr.
22

33
// RUN: %ldc -output-ll -of=%t.ll %s && FileCheck %s < %t.ll
44

@@ -25,22 +25,22 @@ void foo()
2525
}(123);
2626
}
2727

28-
// the global variables should be defined as internal:
29-
// CHECK: _D14lambdas_gh364815__lambda_L5_C12FZ10global_bari{{.*}} = internal thread_local global
30-
// CHECK: _D14lambdas_gh364816__lambda_L10_C20FZ18global_bar_inlinedOi{{.*}} = internal global
31-
// CHECK: _D14lambdas_gh36483fooFZ__T15__lambda_L21_C5TiZQuFiZ12lambda_templi{{.*}} = internal global
28+
// the global variables should be defined as linkonce_odr:
29+
// CHECK: _D14lambdas_gh364815__lambda_L5_C12FZ10global_bari{{.*}} = linkonce_odr {{(hidden )?}}thread_local global
30+
// CHECK: _D14lambdas_gh364816__lambda_L10_C20FZ18global_bar_inlinedOi{{.*}} = linkonce_odr {{(hidden )?}}global
31+
// CHECK: _D14lambdas_gh36483fooFZ__T15__lambda_L21_C5TiZQuFiZ12lambda_templi{{.*}} = linkonce_odr {{(hidden )?}}global
3232

3333
// foo() should only call two lambdas:
3434
// CHECK: define {{.*}}_D14lambdas_gh36483fooFZv
3535
// CHECK-NEXT: call {{.*}}__lambda_L5_C12
3636
// CHECK-NEXT: call {{.*}}__T15__lambda_L21_C5
3737
// CHECK-NEXT: ret void
3838

39-
// bar() should be defined as internal:
40-
// CHECK: define internal {{.*}}__lambda_L5_C12
39+
// bar() should be defined as linkonce_odr:
40+
// CHECK: define linkonce_odr {{.*}}__lambda_L5_C12
4141

4242
// bar_inlined() should NOT have made it to the .ll:
4343
// CHECK-NOT: define {{.*}}__lambda_L10_C20
4444

45-
// the template lambda instance should be defined as internal:
46-
// CHECK: define internal {{.*}}__T15__lambda_L21_C5
45+
// the template lambda instance should be defined as linkonce_odr:
46+
// CHECK: define linkonce_odr {{.*}}__T15__lambda_L21_C5

tests/codegen/lambdas_gh3648b.d

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Tests that *imported* lambdas and contained globals are emitted with internal linkage.
1+
// Tests that *imported* lambdas and contained globals are emitted as linkonce_odr.
22

33
// RUN: %ldc -output-ll -of=%t.ll %s -I%S && FileCheck %s < %t.ll
44

@@ -10,17 +10,17 @@ void foo()
1010
bar_inlined();
1111
}
1212

13-
// the global variables should be defined as internal:
14-
// CHECK: _D14lambdas_gh364815__lambda_L5_C12FZ10global_bari{{.*}} = internal thread_local global
15-
// CHECK: _D14lambdas_gh364816__lambda_L10_C20FZ18global_bar_inlinedOi{{.*}} = internal global
13+
// the global variables should be defined as linkonce_odr:
14+
// CHECK: _D14lambdas_gh364815__lambda_L5_C12FZ10global_bari{{.*}} = linkonce_odr {{(hidden )?}}thread_local global
15+
// CHECK: _D14lambdas_gh364816__lambda_L10_C20FZ18global_bar_inlinedOi{{.*}} = linkonce_odr {{(hidden )?}}global
1616

1717
// foo() should only call one lambda:
1818
// CHECK: define {{.*}}_D15lambdas_gh3648b3fooFZv
1919
// CHECK-NEXT: call {{.*}}__lambda_L5_C12
2020
// CHECK-NEXT: ret void
2121

22-
// bar() should be defined as internal:
23-
// CHECK: define internal {{.*}}__lambda_L5_C12
22+
// bar() should be defined as linkonce_odr:
23+
// CHECK: define linkonce_odr {{.*}}__lambda_L5_C12
2424

2525
// bar_inlined() should NOT have made it to the .ll:
2626
// CHECK-NOT: define {{.*}}__lambda_L10_C20

0 commit comments

Comments
 (0)