-
-
Notifications
You must be signed in to change notification settings - Fork 609
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4814 from 9rnsr/fix14541
Issue 14541 - "duplicate COMDAT" linker error with the template forward reference in Tuple.opAssign
- Loading branch information
Showing
3 changed files
with
119 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| module imports.link14541traits; | ||
|
|
||
| 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[]; | ||
| } | ||
| } | ||
| } | ||
| } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| import imports.link14541traits; | ||
|
|
||
| void main() | ||
| { | ||
| Tuple!(int, int) result; | ||
|
|
||
| alias T = typeof(result); | ||
| static assert(hasElaborateAssign!T); | ||
| // hasElaborateAssign!(Tuple(int, int)): | ||
| // 1. instantiates Tuple!(int, int).opAssign!(Tuple!(int, int)) [auto ref = Rvalue] | ||
| // 2. instantiates swap!(Tuple!(int, int)) | ||
| // 3. instantiates hasElaborateAssign!(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 | ||
| // hasElaborateAssign!(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. | ||
| // But, the forward reference of hasElaborateAssign!(Tuple(int, int)) is already resolved, so | ||
| // the instantiation will succeeds. | ||
| result = Tuple!(int, int)(0, 0); // --> 1st error reproduction instantiation | ||
| result = Tuple!(int, int)(0, 0); // --> 2nd error reproduction instantiation | ||
|
|
||
| // 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. | ||
| } | ||
|
|
||
| /+ | ||
| The point is, if instantiated contexts are different, two instantiations may cause different result. | ||
| - The 1st Tuple.opAssign instantiation is invoked from hasElaborateAssign template with gagging. | ||
| So it has failed, because of the circular reference of hasElaborateAssign template.. | ||
| - The 2nd Tuple.opAssign instantiation is invoked from main() without gagging. | ||
| It does not have circular reference, so the instantiation should succeed. | ||
| Therefore, the gagged failure should be overridden by the ungagged success. | ||
| +/ |