Bug 15712 – extern(C) attribute inside extern(C) unittest is incorrectly ignored

Status
RESOLVED
Resolution
FIXED
Severity
normal
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2016-02-21T10:17:23Z
Last change time
2022-11-05T01:10:00Z
Keywords
pull
Assigned to
No Owner
Creator
John Colvin
See also
https://issues.dlang.org/show_bug.cgi?id=6132

Comments

Comment #0 by john.loughran.colvin — 2016-02-21T10:17:23Z
% cat test.d extern(C): unittest { extern(C) static void foo(){}; pragma(msg, typeof(foo)); pragma(msg, typeof(&foo)); } % dmd test.d void() void function() Seems that somehow the two extern(C)s cancel out.
Comment #1 by razvan.nitu1305 — 2022-11-03T09:43:46Z
If you meant that `extern(C)` is missing from the output of the pragma, then I cannot reproduce this. I get: pure nothrow @nogc @safe extern (C) void() extern (C) void function() pure nothrow @nogc @safe Closing as WORKSFORME.
Comment #2 by john.loughran.colvin — 2022-11-03T12:23:14Z
I don't think it's fixed, see output below: $ dmd --version DMD64 D Compiler v2.100.2 Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved written by Walter Bright $ cat test.d unittest { extern(C) static void foo(){} pragma(msg, typeof(foo)); pragma(msg, typeof(&foo)); } extern(C): unittest { static void bar(){} pragma(msg, typeof(bar)); pragma(msg, typeof(&bar)); } unittest { extern(C) static void baz(){} pragma(msg, typeof(baz)); pragma(msg, typeof(&baz)); } $ dmd -unittest -o- test.d pure nothrow @nogc @safe extern (C) void() extern (C) void function() pure nothrow @nogc @safe pure nothrow @nogc @safe void() void function() pure nothrow @nogc @safe pure nothrow @nogc @safe void() void function() pure nothrow @nogc @safe
Comment #3 by razvan.nitu1305 — 2022-11-03T13:38:20Z
Why do you expect that extern(C) should apply deeply for nested functions? As far as I know it only applies to the first level of declarations. That was the case for attributes also before nested functions got their attributes inferred. Also, why would you want it to have extern(C) linkage? Technically it's callable from inside the unittest/function (which is actually D code, even if the function is callable from C), which means it technically cannot be called from C code (except if you escape it somehow, but I assume those cases to be rare). Either way, I think that this bug is not valid. Do you have a compelling use case for this?
Comment #4 by john.loughran.colvin — 2022-11-04T08:39:51Z
Why would I want an extern(C) static function as a local? One simple use-case would be to pass to a C function to use as a callback. But that is not the point of this bug report. The point of the bug report is that typeof(foo) is extern(C) but typeof(baz) is not.
Comment #5 by razvan.nitu1305 — 2022-11-04T11:39:42Z
(In reply to John Colvin from comment #4) > Why would I want an extern(C) static function as a local? One simple > use-case would be to pass to a C function to use as a callback. > > But that is not the point of this bug report. The point of the bug report is > that typeof(foo) is extern(C) but typeof(baz) is not. What I meant was: why would you want static/non-static nested functions to inherit the upper level linkage attribute? I would argue that in most situations nested functions are not made to be escaped (as callbacks) but if that situation arises the programmer can manually add extern(C).
Comment #6 by dkorpel — 2022-11-04T12:38:25Z
(In reply to RazvanN from comment #5) > but if that situation arises the programmer can manually add extern(C). But extern(C) *is* manually added. This is the buggy part: ``` extern(C): unittest { extern(C) void baz() {} pragma(msg, "typeof(baz): ", typeof(baz)); } ``` `baz` is not `extern(C)` like this, but either *removing* `extern(C):` or changing the unittest to a regular function will make `baz` `extern(C)`.
Comment #7 by razvan.nitu1305 — 2022-11-04T12:44:43Z
(In reply to Dennis from comment #6) > (In reply to RazvanN from comment #5) > > but if that situation arises the programmer can manually add extern(C). > > But extern(C) *is* manually added. This is the buggy part: > ``` > extern(C): > unittest > { > extern(C) void baz() {} > pragma(msg, "typeof(baz): ", typeof(baz)); > } > ``` > > `baz` is not `extern(C)` like this, but either *removing* `extern(C):` or > changing the unittest to a regular function will make `baz` `extern(C)`. Aaah, ok, sorry, I don't know what happened. When I tested last time it seemed the extern(C) was there in the above example and I misunderstood the bug report as being about extern(C) not propagating for nested functions. I might have miscompiled the example. Sorry for the noise. Yes, this is definitely a bug.
Comment #8 by dkorpel — 2022-11-04T20:31:06Z
It turns out the parser doesn't generate an AttributeDeclaration for extern(linkage) when it thinks it's redundant, but it's not aware that during semantic analysis, unittests are set to extern(D).
Comment #9 by dlang-bot — 2022-11-04T20:32:54Z
@dkorpel created dlang/dmd pull request #14619 "Fix 15712 - extern(C) attribute inside extern(C) unittest is incorrectly ignored" fixing this issue: - Fix 15712 - extern(C) attribute inside extern(C) unittest is incorrectly ignored https://github.com/dlang/dmd/pull/14619
Comment #10 by dlang-bot — 2022-11-05T01:10:00Z
dlang/dmd pull request #14619 "Fix 15712 - extern(C) attribute inside extern(C) unittest is incorrectly ignored" was merged into master: - fc432644adae61fab2c54af7d17a73872c0b5f8e by Dennis Korpel: Fix 15712 - extern(C) attribute inside extern(C) unittest is incorrectly ignored https://github.com/dlang/dmd/pull/14619