www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 14541] New: "duplicate COMDAT" linker error with the template

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