February 16, 2023
https://issues.dlang.org/show_bug.cgi?id=23722

          Issue ID: 23722
           Summary: Lambdas are mangled incorrectly when using multiple
                    compilation units, resulting in incorrect code
           Product: D
           Version: D2
          Hardware: x86_64
                OS: Linux
            Status: NEW
          Severity: normal
          Priority: P1
         Component: dmd
          Assignee: nobody@puremagic.com
          Reporter: zach-dmd@cs.stanford.edu

I have two files, foo.d and bar.d:

bar.d:
```
module bar;

struct A {
    import core.stdc.stdio;
    alias x = () {
        printf("x\n");
    };
    alias y = () {
        printf("y\n");
    };
}

// do_x should call A.x (and print "x")
void do_x() {
    A.x();
}
```

and foo.d:

```
module foo;

import bar;

// do_y should call A.y (and print "y")
void do_y() {
    A.y();
}

extern (C) void main() {
    do_y(); // should print y
    do_x(); // should print x
}
```

This program should print `y` and then `x`. If I compile as one compilation unit then it works fine:

```
$ dmd -betterC foo.d bar.d
$ ./foo
y
x
```

But if I compile with separate compilation units then it has incorrect behavior:

```
$ dmd -betterC -c foo.d
$ dmd -betterC -c bar.d
$ gcc foo.o bar.o -o foo
$ ./foo
x
x
```

This is because in foo.d `A.y` is mangled as `_D3bar1A9__lambda4FNbNiZv`, but and in bar.d `A.x` is mangled as `_D3bar1A9__lambda4FNbNiZv`. They both have the same mangled value but they are different lambdas that do different things. Thus the call to `A.y` ends up being a call to `A.x` once the linker has resolved the symbols. The mangled name seems to use a count of instantiated lambdas for uniqueness, but it should instead to depend on something that is unique across compilation units, such as a counter for the total number of lambdas (this appears to be the approach C++ takes to solve this).

Thanks.

--