Bug 17541 – Function attribute deduction depends on compile invocation

Status
REOPENED
Severity
normal
Priority
P3
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2017-06-23T10:55:31Z
Last change time
2024-12-13T18:52:42Z
Keywords
industry, pull, wrong-code
Assigned to
No Owner
Creator
johanengelen
See also
https://issues.dlang.org/show_bug.cgi?id=20696
Moved to GitHub: dmd#19265 →

Comments

Comment #0 by johanengelen — 2017-06-23T10:55:31Z
I unfortunately only have a complex testcase for this issue (after long dustmiting sessions and manual reduction), involving three files (one.d, two.d, three.d). When only `one.d` is compiled, function `three.TT!(int).insertabcdefg(int)` is deduced to be `@nogc`. But the deduction happens late, and printing `.mangleof` does not show it. The symbol in the object file does show `@nogc` in the mangling. When `one.d` and `two.d` are compiled simultaneously (with or without `three.d`), the function is no longer deduced to be `@nogc`. (The bug was found in Weka's codebase where everything-at-once compilation is impossible, and where per-package compilation is done. The testcase is heavily simplified.) Details: Only compiling one.d gives: > dmd one.d -c -of=tmp1.o _D5three9__T2TTTiZ2TT13insertabcdefgMFiZv > nm tmp1.o | grep "insertabcdefg" 0000000000000358 S _D5three9__T2TTTiZ2TT13insertabcdefgMFNiiZv Compiling all three at once gives: > dmd one.d two.d three.d -c -of=tmp2.o _D5three9__T2TTTiZ2TT13insertabcdefgMFiZv > nm tmp2.o | grep "insertabcdefg" 0000000000000460 S _D5three9__T2TTTiZ2TT13insertabcdefgMFiZv File one.d ``````````````````````````` module one; import two; import three; struct BB { enum MAX_NUM_FIBERS = 4096; TWOR!1 t; TT!(int) tt; auto foo() { tt.insertabcdefg(1); } } BB bb; ``````````````````````````` File two.d ``````````````````````````` module two; import one; struct ET(bool a) { enum e = BB.MAX_NUM_FIBERS; } alias Event = ET!false; struct TWOR(size_t M) { Event e; void open() { bb.foo(); } } ``````````````````````````` File three.d ``````````````````````````` module three; void aaa() @nogc { } struct TT(T) { void insertabcdefg(T) // @nogc <-- deduction problem { pragma(msg, insertabcdefg.mangleof); aaa(); } } ```````````````````````````
Comment #1 by johanengelen — 2017-06-23T10:57:44Z
(the mangling difference between compiling `one.d` with or without `two.d` leads to linking problems at Weka)
Comment #2 by johanengelen — 2017-06-23T12:43:55Z
In other code I hit the same issue but now with compiler-invocation-dependent deduction of `@safe` or `@trusted` for `__fieldDtor` of a struct.
Comment #3 by johanengelen — 2017-06-23T13:33:47Z
And in other cases, `pure` is deduced depending on compiler invocation, and is actually deduced wrong (function is not pure but is deduced `pure`).
Comment #4 by johanengelen — 2017-07-14T16:47:47Z
This problem is bigger than just templates. I am seeing more and more deduction errors, resulting in linker errors.
Comment #5 by bugzilla — 2017-07-15T02:24:46Z
Comment #6 by github-bugzilla — 2017-10-26T12:14:10Z
Commits pushed to master at https://github.com/dlang/dmd https://github.com/dlang/dmd/commit/df847ccb60a37f4dbc349e8cee4a2ee6081e0c3c fix Issue 17541 - Function attribute deduction depends on compile invocation https://github.com/dlang/dmd/commit/aabeeb0a550a0d4ba066209290c799c5cf812e87 Merge pull request #6995 from WalterBright/fix17541 fix Issue 17541 - Function attribute deduction depends on compile inv…
Comment #7 by johanengelen — 2017-10-26T21:15:21Z
reopening, because it is not fixed for safe/trusted, nor for impure/pure, throw/nothrow.
Comment #8 by github-bugzilla — 2017-12-18T22:55:21Z
Commits pushed to stable at https://github.com/dlang/dmd https://github.com/dlang/dmd/commit/df847ccb60a37f4dbc349e8cee4a2ee6081e0c3c fix Issue 17541 - Function attribute deduction depends on compile invocation https://github.com/dlang/dmd/commit/aabeeb0a550a0d4ba066209290c799c5cf812e87 Merge pull request #6995 from WalterBright/fix17541
Comment #9 by johanengelen — 2017-12-18T23:18:27Z
reopening, because it is not fixed for safe/trusted, nor for impure/pure, throw/nothrow.
Comment #10 by dlang-bot — 2020-03-23T09:08:05Z
@WalterBright created dlang/dmd pull request #10959 "add pure and @safe to correct for issue 17541" mentioning this issue: - add pure and @safe to correct for issue 17541 https://github.com/dlang/dmd/pull/10959
Comment #11 by bugzilla — 2020-03-24T08:27:49Z
I cannot reproduce the problem. The previous fix I pushed was wrong. The pragma(msg, insertabcdefg.mangleof) gives the wrong name mangling, as it happens before the inference is complete. The compiler should give an error for that.
Comment #12 by johanengelen — 2020-03-24T18:57:40Z
(In reply to Walter Bright from comment #11) > I cannot reproduce the problem. The previous fix I pushed was wrong. > > The pragma(msg, insertabcdefg.mangleof) gives the wrong name mangling, as it > happens before the inference is complete. The compiler should give an error > for that. The pragma(msg, insertabcdefg.mangleof) is not the only bug here. The larger pain point is that deduction depends on compiler invocation and hence breaks separate compilation (either for linking symbol resolution, or for code depending on a certain attribute deduction result). Tested with dlang 2.090.1 just now, replacing `@nogc` with `pure`, and following reproduction commands shows the problem: ❯ ~/dlang/dmd20901/osx/bin/dmd one.d -c -of=tmp1.o ❯ nm tmp1.o| grep "insertabc" 00000000000002ac S __D5three__T2TTTiZQg13insertabcdefgMFNaiZv 0000000000000078 S __D5three__T2TTTiZQg13insertabcdefgMFNaiZv.eh ❯ dmd one.d two.d three.d -c -of=tmp2.o ❯ nm tmp2.o | grep "insertabc" 00000000000003b4 S __D5three__T2TTTiZQg13insertabcdefgMFiZv 00000000000000c0 S __D5three__T2TTTiZQg13insertabcdefgMFiZv.eh The symbol names in the binary are different.
Comment #13 by snarwin+bugzilla — 2023-02-17T21:14:00Z
Another example, from Discord: --- test.d module test; void main(){ import test2; MyStruct.RcPtr gl_indcies = MyStruct.RcPtr(MyStruct()); } --- test2.d module test2; struct MyStruct{ alias Ptr = Unique!MyStruct; alias RcPtr = SafeRefCounted!MyStruct; ~this(){} } struct SafeRefCounted(T){ struct RefCountedStore{ struct Impl{ T _payload; } Impl* _store; } RefCountedStore* _refCounted; this(T)(T arg){} ~this(){ destroy(_refCounted._store._payload); } } struct Unique(T){ alias RefT = T*; void opAssign(U)(Unique!U u) if (is(u.RefT:RefT)){} ~this(){ destroy(*_p); } RefT _p; } --- When compiled together, there is no error: --- $ dmd -c test.d test2.d && dmd test.o test2.o $ echo $? 0 --- When compiled separately, linking fails: --- $ dmd -c test.d && dmd -c test2.d && dmd test.o test2.o /usr/bin/ld: test.o: in function `_Dmain': test.d:(.text._Dmain[_Dmain]+0x2f): undefined reference to `_D5test2__T14SafeRefCountedTSQBb8MyStructZQBf6__dtorMFZv' collect2: error: ld returned 1 exit status Error: linker exited with status 1 --- Examining the object files shows that this is due to mismatched attributes: --- $ nm test.o | ddemangle | grep 'SafeRefCounted.*__dtor' U void test2.SafeRefCounted!(test2.MyStruct).SafeRefCounted.__dtor() $ nm test2.o | ddemangle | grep 'SafeRefCounted.*__dtor' 0000000000000000 W pure nothrow @nogc @safe void test2.SafeRefCounted!(test2.MyStruct).SafeRefCounted.__dtor() --- Reproduced with DMD 2.102.0 on 64-bit Linux.
Comment #14 by snarwin+bugzilla — 2023-02-26T00:19:18Z
*** Issue 23723 has been marked as a duplicate of this issue. ***
Comment #15 by dlang-bot — 2023-08-12T18:54:32Z
@ljmf00 created dlang/dmd pull request #15534 "Fix Issue 17541 - @safe/pure/nothrow attribute deduction depends on c…" fixing this issue: - Fix Issue 17541 - @safe/pure/nothrow attribute deduction depends on compile invocation A reboot of #10959 follow-up plus implementation for `nothrow`. Signed-off-by: Luís Ferreira <[email protected]> https://github.com/dlang/dmd/pull/15534
Comment #16 by robert.schadek — 2024-12-13T18:52:42Z
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/dmd/issues/19265 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB