Thread overview
is this a bug ? mixin template static function missing!
Aug 10, 2018
learnfirst1
Aug 10, 2018
Simen Kjærås
Aug 10, 2018
learnfirst1
Aug 10, 2018
Simen Kjærås
Aug 10, 2018
learnfirst1
Aug 10, 2018
learnfirst1
August 10, 2018
#!/usr/bin/env rdmd
import core.stdc.stdio;

template G(size_t line = __LINE__, A...){
	int i = 3;
	static extern(C) pragma(crt_constructor) void init2(){
		printf("init: %d\n", line);
	}
}

pragma(crt_constructor) extern(C) void init1(){
      printf("init from global\n");
}

struct A {
	mixin G!();
}

extern(C) void main(){
	mixin G!() g;
	printf("g.i=%d\n", g.i);
	g.init2(); // remove this can build, but g.init2 not get called!
}

-----------------

build error:
Undefined symbols for architecture x86_64: "__D4test4mainUZ1g5init2UNbNiZv", referenced from:



August 10, 2018
On Friday, 10 August 2018 at 08:31:21 UTC, learnfirst1 wrote:
>
> #!/usr/bin/env rdmd
> import core.stdc.stdio;
>
> template G(size_t line = __LINE__, A...){
> 	int i = 3;
> 	static extern(C) pragma(crt_constructor) void init2(){
> 		printf("init: %d\n", line);
> 	}
> }
>
> pragma(crt_constructor) extern(C) void init1(){
>       printf("init from global\n");
> }
>
> struct A {
> 	mixin G!();
> }
>
> extern(C) void main(){
> 	mixin G!() g;
> 	printf("g.i=%d\n", g.i);
> 	g.init2(); // remove this can build, but g.init2 not get called!
> }
>
> -----------------
>
> build error:
> Undefined symbols for architecture x86_64: "__D4test4mainUZ1g5init2UNbNiZv", referenced from:

It is indeed. Reduced example:

template G(){
    extern(C) pragma(crt_constructor) void init(){}
}
void main(){
    mixin G!();
    init();
}

For nested functions, extern(C) is simply ignored[0]. Since pragma(crt_constructor) requires that the symbol it's applied to uses C linkage (and an error message to that effect is shown if you write pragma(crt_constructor) void fun() {} in module scope:
Error: function `fun` must be extern(C) for pragma(crt_constructor)

In addition, if you try to apply pragma(crt_constructor) to a nested function, you get this error message, showing further that nested functions can't be crt_constructors:
Error: unrecognized pragma(crt_constructor)

The correct behavior would be for the compiler to show the latter error message for a mixin'd function as well.

Filed a bug:
https://issues.dlang.org/show_bug.cgi?id=19153

--
  Simen

[0]: from https://dlang.org/spec/attribute.html#linkage:
Note that extern(C) can be provided for all types of declarations, including struct or class, even though there is no corresponding match on the C side. In that case, the attribute is ignored. This behavior applies for nested functions and nested variables as well.
August 10, 2018
On Friday, 10 August 2018 at 10:24:55 UTC, Simen Kjærås wrote:
> On Friday, 10 August 2018 at 08:31:21 UTC, learnfirst1 wrote:
> The correct behavior would be for the compiler to show the latter error message for a mixin'd function as well.
>
> Filed a bug:
> https://issues.dlang.org/show_bug.cgi?id=19153
>
> --
>   Simen
>

I think the static extern(C)  nested function should just work like global extern(C) function.   DMD still report missing symbols.   Or I am wrong about this ?

template G(){
    static extern(C) pragma(crt_constructor) void init(){}
}
void main(){
    mixin G!(); // Line 5
    init();
}
August 10, 2018
On Friday, 10 August 2018 at 10:24:55 UTC, Simen Kjærås wrote:
> On Friday, 10 August 2018 at 08:31:21 UTC, learnfirst1 wrote:
> Filed a bug:
> https://issues.dlang.org/show_bug.cgi?id=19153
>

template G(){
    pragma(crt_constructor) static extern(C) void init(){}
}
void main(){
    mixin G!(); // Line 5
    init();
}

same missing symbols.
August 10, 2018
On Friday, 10 August 2018 at 11:17:10 UTC, learnfirst1 wrote:
> I think the static extern(C)  nested function should just work like global extern(C) function.   DMD still report missing symbols.   Or I am wrong about this ?
>
> template G(){
>     static extern(C) pragma(crt_constructor) void init(){}
> }
> void main(){
>     mixin G!(); // Line 5
>     init();
> }

If you try the same without the mixin template, you'll see that it doesn't work:

void main() {
    static extern(C) pragma(crt_constructor) void init();
    init();
}

Depending on the order of static, extern(C) and pragma(crt_constructor), you can get at least two different error messages, but either way - it doesn't work.

It would be possible to make this work by changing the compiler, but according to spec, it shouldn't.

--
  Simen
August 10, 2018
On Friday, 10 August 2018 at 12:05:52 UTC, Simen Kjærås wrote:
> On Friday, 10 August 2018 at 11:17:10 UTC, learnfirst1 wrote:
> If you try the same without the mixin template, you'll see that it doesn't work:
>


struct Test {
    extern(C) pragma(crt_constructor) static void init(){ // work
        int i = 3;
    }
}

void main(){
    extern(C) pragma(crt_constructor) static void init(){ // not work
        int i = 3;
    }
}

------------------------------

It not work make no sense, since it can work on struct.


I am not be able to search the related spec docs,  only this link:  https://dlang.org/blog/2018/01/04/dmd-2-078-0-has-been-released/

Based on my understand, nested static  extern(C)  function is all about visibility.  It just like put private before it,  there is really no reason to treat them in diff way.