Jump to page: 1 24  
Page
Thread overview
[Issue 20012] extern(C) functions inside template mixins are not mangled as C functions
[Issue 20012] export inside mixin doesn't seem to work
Jul 23, 2019
Walter Bright
Jul 23, 2019
Manu
Jul 24, 2019
Walter Bright
Jul 24, 2019
Manu
Jul 24, 2019
Manu
Jul 24, 2019
Walter Bright
Jul 24, 2019
Manu
Jul 24, 2019
Walter Bright
Jul 24, 2019
Manu
Jul 24, 2019
Walter Bright
Jul 24, 2019
Adam D. Ruppe
Jul 24, 2019
Manu
Jul 24, 2019
Walter Bright
Jul 24, 2019
Manu
Jul 24, 2019
Ketmar Dark
Jul 24, 2019
ponce
Jul 24, 2019
anonymous4
Jul 24, 2019
anonymous4
Jul 24, 2019
Manu
Jul 24, 2019
Dennis
Jul 24, 2019
Dennis
Jul 24, 2019
Dennis
Jul 25, 2019
anonymous4
Jul 25, 2019
Dennis
Jul 26, 2019
anonymous4
Jul 26, 2019
Manu
Jul 27, 2019
Ethan Watson
Jul 28, 2019
Dlang Bot
Jul 29, 2019
Walter Bright
Jul 29, 2019
Walter Bright
Sep 30, 2019
Dlang Bot
Jan 14, 2020
Dlang Bot
July 23, 2019
https://issues.dlang.org/show_bug.cgi?id=20012

Walter Bright <bugzilla@digitalmars.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |bugzilla@digitalmars.com

--- Comment #1 from Walter Bright <bugzilla@digitalmars.com> ---
It is exported, just as:

  __D4test8__mixin43fooUZv

instead of:

  _foo

You can see what's exported by running obj2asm on the .obj file, don't need to use GetProcAddress. For example:

---
  export extern(C) void fun() {}
  mixin template M() {
    export extern(C) void bar() {}
  }
  mixin M!();

---
  dmd -c test.d
  obj2asm test.obj
---
    _TEXT       segment dword use32 public 'CODE'       ;size is 0
    _TEXT       ends
    _DATA       segment para use32 public 'DATA'        ;size is 0
    _DATA       ends
    CONST       segment para use32 public 'CONST'       ;size is 13
    CONST       ends
    _BSS        segment para use32 public 'BSS' ;size is 0
    _BSS        ends
    FLAT        group
    extrn       _fun
    ;expdef expflag=x00, export '_fun', internal '', ordinal=x0
    extrn       __D4test8__mixin43barUZv
    ;expdef expflag=x00, export '__D4test8__mixin43barUZv', internal '',
ordinal=x0
    FMB segment dword use32 public 'DATA'       ;size is 0
    FMB ends
    FM  segment dword use32 public 'DATA'       ;size is 4
    FM  ends
    FME segment dword use32 public 'DATA'       ;size is 0
    FME ends

            public      __D4test12__ModuleInfoZ
    _fun        COMDAT flags=x0 attr=x0 align=x0
    __D4test8__mixin43barUZv    COMDAT flags=x0 attr=x10 align=x0

    _TEXT       segment
            assume      CS:_TEXT
    _TEXT       ends
    _DATA       segment
    _DATA       ends
    CONST       segment
    __D4test12__ModuleInfoZ:
            db  004h,010h,000h,000h,000h,000h,000h,000h ;........
            db  074h,065h,073h,074h,000h        ;test.
    CONST       ends
    _BSS        segment
    _BSS        ends
    FMB segment
    FMB ends
    FM  segment
            dd  offset FLAT:__D4test12__ModuleInfoZ
    FM  ends
    FME segment
    FME ends
    _fun        comdat
            assume      CS:_fun
                    ret
    _fun        ends
    __D4test8__mixin43barUZv    comdat
            assume      CS:__D4test8__mixin43barUZv
                    ret
    __D4test8__mixin43barUZv    ends
            end
---

--
July 23, 2019
https://issues.dlang.org/show_bug.cgi?id=20012

--- Comment #2 from Manu <turkeyman@gmail.com> ---
Right. We'll, that's obviously broken :)

--
July 24, 2019
https://issues.dlang.org/show_bug.cgi?id=20012

--- Comment #3 from Walter Bright <bugzilla@digitalmars.com> ---
Is it? Note the same behavior happens with:

  struct S { extern (C) void foo() { } }

i.e. foo() gets mangled. There are two aspects of C mangling - one is the ABI, the other is the ABI. Using C mangling in a scope means there can be only one, so D just uses it to set the ABI.

But there's another way you can do it:

  mixin template M()
  {
    export extern(C) pragma(mangle, "fun") void fun() {}
  }
  mixin M!();

which will work.

--
July 24, 2019
https://issues.dlang.org/show_bug.cgi?id=20012

--- Comment #4 from Manu <turkeyman@gmail.com> ---
Why are you comparing it to a struct with methods?

mixin is not a structured object with methods, and there's no reason to think those methods should receive a context object and be mangled accordingly. mixin inserts material into the lexical scope, which in this case is the global scope. It's the closest thing we have to a macro.

I understand the workaround, but this is broken. It's caught a couple of people
now.
It's embarrassing when people see something that doesn't work with no
reasonable explanation; we have a lot of that, and there's only so many
occurrences people can handle before their confidence is lost.
Easy low-hanging fruit like this is worth fixing, and we can spend our
confidence erosion budget on the real issues.

--
July 24, 2019
https://issues.dlang.org/show_bug.cgi?id=20012

--- Comment #5 from Manu <turkeyman@gmail.com> ---
> Using C mangling in a scope means there can be only one...

Yes, and that's the entire point. That is how C is. Nobody would ever expect otherwise.

--
July 24, 2019
https://issues.dlang.org/show_bug.cgi?id=20012

--- Comment #6 from Walter Bright <bugzilla@digitalmars.com> ---
You can also use:

enum M = "export extern(C) void fun() {}";
mixin(M);

--
July 24, 2019
https://issues.dlang.org/show_bug.cgi?id=20012

--- Comment #7 from Manu <turkeyman@gmail.com> ---
It's just one declaration among a bunch of other stuff that is inserted into the global scope, and it's the only declaration that doesn't 'work'. It shouldn't be separated from all its associated declarations, and it's super weird that that's required.

Mixin templates into the global scope appear in every single reflection-driven application I've ever written. One part of that generated code is the entrypoint function which registers the modules contents with the module loader.

Seriously, just fix this. It's a bug.

--
July 24, 2019
https://issues.dlang.org/show_bug.cgi?id=20012

--- Comment #8 from Walter Bright <bugzilla@digitalmars.com> ---
Template mixins are meant to be included multiple times. That's why the scope is part of the mangled name.

--
July 24, 2019
https://issues.dlang.org/show_bug.cgi?id=20012

--- Comment #9 from Manu <turkeyman@gmail.com> ---
A template mixin with an extern(C) function in it is obviously meant to be
included at the global scope, why on earth would there be an extern(C) function
in a template mixin otherwise? Especially an `extern` one.
Nobody would be surprised by a link error complaining about multiple
definitions of an extern(C) function; in fact, they'd be annoyed if it didn't.

The pattern of a reflection template mixin placed at top-level is unbelievably
common, and this code is common-sense for anyone trying to emit
reflection-based data from a DLL.
Lots of people don't use DLL's, so maybe it hasn't come up, but I use DLL's a
lot.

Seriously, the only conceivable useful thing you could do with an extern(C) function in a template mixin doesn't work. This is a bug.

extern(C) means extern(C). There's no reason to re-interpret what extern(C)
means in this one weird case. extern(C) specifies mangling and ABI, not
mangling, or ABI, or maybe both.

--
July 24, 2019
https://issues.dlang.org/show_bug.cgi?id=20012

--- Comment #10 from Walter Bright <bugzilla@digitalmars.com> ---
(In reply to Manu from comment #9)
> A template mixin with an extern(C) function in it is obviously meant to be
> included at the global scope, why on earth would there be an extern(C)
> function in a template mixin otherwise?

Because there are uses for functions that follow the C ABI. Note that Microsoft C++ also distinguishes between C mangling and C ABI.

Template mixins were designed so that boilerplate code can be inserted into many places.

--
« First   ‹ Prev
1 2 3 4