digitalmars.D.bugs - [Issue 14541] New: "duplicate COMDAT" linker error with the template
- via Digitalmars-d-bugs (113/113) May 03 2015 https://issues.dlang.org/show_bug.cgi?id=14541
https://issues.dlang.org/show_bug.cgi?id=14541 Issue ID: 14541 Summary: "duplicate COMDAT" linker error with the template forward reference in Tuple.opAssign Product: D Version: D2 Hardware: x86_64 OS: Windows Status: NEW Keywords: link-failure, rejects-valid Severity: normal Priority: P1 Component: DMD Assignee: nobody puremagic.com Reporter: k.hara.pg gmail.com Command line and error message: $ dmd -m64 test test.obj : fatal error LNK1179: invalid or corrupt file: duplicate COMDAT '_D6traits14__T5TupleTiTiZ5Tuple44__T8opAssignTS6traits14__T5TupleTiTiZ5TupleZ8opAssignMFNaNbNiNfS6traits14__T5TupleTiTiZ5TupleZv' --- errorlevel 1179 Source files with explanation comments: ==== test.d import traits; void main() { Tuple!(int, int) result; alias T = typeof(result); static assert(hasElaborateAssign!T); // hasElablrateAssign!(Tuple(int, int)): // 1. instantiates Tuple!(int, int).opAssign!(Tuple!(int, int)) [auto ref = Rvalue] // 2. instantiates swap!(Tuple!(int, int)) // 3. instantiates hasElablrateAssign!(Tuple!(int, int)) // --> forward reference error // --> swap!(Tuple!(int, int)) fails to instantiate // --> Tuple!(int, int).opAssign!(Tuple!(int, int)) [auto ref = rvalue] fails to instantiate // 4. instantiates Tuple!(int, int).opAssign!(Tuple!(int, int)) [auto ref = Lvalue] // --> succeeds // hasElablrateAssign!(Tuple(int, int)) succeeds to instantiate (result is 'true') // Instantiates Tuple!(int, int).opAssign!(Tuple!(int, int)) [auto ref = Rvalue], but // it's already done in gagged context, so this is made an error reproduction instantiation. // --> 1st error reproduction instantiation // But, the forward reference of hasElablrateAssign!(Tuple(int, int)) is alredy resolved, so // the instantiation will succeeds. result = Tuple!(int, int)(0, 0); // Instantiates Tuple!(int, int).opAssign!(Tuple!(int, int)) [auto ref = Rvalue], but // it's already done in gagged context, so this is made an error reproduction instantiation. // --> 2nd error reproduction instantiation // But, the forward reference of hasElablrateAssign!(Tuple(int, int)) is alredy resolved, so // the instantiation will succeeds. result = Tuple!(int, int)(0, 0); // The two error reproduction instantiations generate the function: // Tuple!(int, int).opAssign!(Tuple!(int, int)) [auto ref = Rvalue] // twice, then it will cause duplicate COMDAT error in Win64 platform. } ==== traits.d template hasElaborateAssign(S) { static if (is(S == struct)) { extern __gshared S lvalue; enum hasElaborateAssign = is(typeof(S.init.opAssign(S.init))) || is(typeof(S.init.opAssign(lvalue))); } else { enum bool hasElaborateAssign = false; } } void swap(T)(ref T lhs, ref T rhs) trusted pure nothrow nogc { static if (hasElaborateAssign!T) { } else { } } template Tuple(Types...) { struct Tuple { Types field; alias field this; this(Types values) { field[] = values[]; } void opAssign(R)(auto ref R rhs) { static if (is(R : Tuple!Types) && !__traits(isRef, rhs)) { // Use swap-and-destroy to optimize rvalue assignment swap!(Tuple!Types)(this, rhs); } else { // Do not swap; opAssign should be called on the fields. field[] = rhs.field[]; } } } } --
May 03 2015