@@ -1544,6 +1544,9 @@ FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc)
1544
1544
return xpostblit;
1545
1545
}
1546
1546
1547
+ /* ===================================== Copy Constructor ========================== */
1548
+ static if (1 ) {
1549
+
1547
1550
/**
1548
1551
* Generates a copy constructor declaration with the specified storage
1549
1552
* class for the parameter and the function.
@@ -1552,18 +1555,19 @@ FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc)
1552
1555
* sd = the `struct` that contains the copy constructor
1553
1556
* paramStc = the storage class of the copy constructor parameter
1554
1557
* funcStc = the storage class for the copy constructor declaration
1558
+ * copyCtor = true for copy constructor, false for move constructor
1555
1559
*
1556
1560
* Returns:
1557
1561
* The copy constructor declaration for struct `sd`.
1558
1562
*/
1559
- private CtorDeclaration generateCopyCtorDeclaration (StructDeclaration sd, const StorageClass paramStc, const StorageClass funcStc)
1563
+ private CtorDeclaration generateCopyCtorDeclaration (StructDeclaration sd, const StorageClass paramStc, const StorageClass funcStc, bool copyCtor )
1560
1564
{
1561
1565
auto fparams = new Parameters();
1562
1566
auto structType = sd.type;
1563
1567
fparams.push(new Parameter (Loc.initial, paramStc | STC .ref_ | STC .return_ | STC .scope_, structType, Id.p, null , null ));
1564
1568
ParameterList pList = ParameterList(fparams);
1565
1569
auto tf = new TypeFunction(pList, structType, LINK .d, STC .ref_);
1566
- auto ccd = new CtorDeclaration(sd.loc, Loc.initial, STC .ref_, tf, true );
1570
+ auto ccd = new CtorDeclaration(sd.loc, Loc.initial, STC .ref_, tf, copyCtor, ! copyCtor );
1567
1571
ccd.storage_class |= funcStc;
1568
1572
ccd.storage_class |= STC .inference;
1569
1573
ccd.isGenerated = true ;
@@ -1726,7 +1730,7 @@ bool buildCopyCtor(StructDeclaration sd, Scope* sc)
1726
1730
// printf("generating copy constructor for %s\n", sd.toChars());
1727
1731
const MOD paramMod = MODFlags.wild;
1728
1732
const MOD funcMod = MODFlags.wild;
1729
- auto ccd = generateCopyCtorDeclaration(sd, ModToStc(paramMod), ModToStc(funcMod));
1733
+ auto ccd = generateCopyCtorDeclaration(sd, ModToStc(paramMod), ModToStc(funcMod), true );
1730
1734
auto copyCtorBody = generateCopyCtorBody(sd);
1731
1735
ccd.fbody = copyCtorBody;
1732
1736
sd.members.push(ccd);
@@ -1747,3 +1751,209 @@ bool buildCopyCtor(StructDeclaration sd, Scope* sc)
1747
1751
}
1748
1752
return true ;
1749
1753
}
1754
+
1755
+ }
1756
+
1757
+ /* ===================================== Move Constructor ========================== */
1758
+ static if (1 ) {
1759
+
1760
+ /**
1761
+ * Generates a move constructor declaration with the specified storage
1762
+ * class for the parameter and the function.
1763
+ *
1764
+ * Params:
1765
+ * sd = the `struct` that contains the move constructor
1766
+ * paramStc = the storage class of the move constructor parameter
1767
+ * funcStc = the storage class for the move constructor declaration
1768
+ *
1769
+ * Returns:
1770
+ * The move constructor declaration for struct `sd`.
1771
+ */
1772
+ private CtorDeclaration generateMoveCtorDeclaration (StructDeclaration sd, const StorageClass paramStc, const StorageClass funcStc)
1773
+ {
1774
+ /* Although the move constructor is declared as `=this(S s) { ... }`,
1775
+ * it is implemented as `=this(ref S s) { ... }`
1776
+ */
1777
+ return generateCopyCtorDeclaration (sd, paramStc, funcStc, false );
1778
+ }
1779
+
1780
+ /**
1781
+ * Generates a trivial move constructor body that simply does memberwise
1782
+ * initialization:
1783
+ *
1784
+ * this.field1 = rhs.field1;
1785
+ * this.field2 = rhs.field2;
1786
+ * ...
1787
+ *
1788
+ * Params:
1789
+ * sd = the `struct` declaration that contains the copy constructor
1790
+ *
1791
+ * Returns:
1792
+ * A `CompoundStatement` containing the body of the copy constructor.
1793
+ */
1794
+ private Statement generateMoveCtorBody (StructDeclaration sd)
1795
+ {
1796
+ Loc loc;
1797
+ Expression e;
1798
+ foreach (v; sd.fields)
1799
+ {
1800
+ auto ec = new AssignExp(loc,
1801
+ new DotVarExp (loc, new ThisExp(loc), v),
1802
+ new DotVarExp (loc, new IdentifierExp(loc, Id.p), v));
1803
+ e = Expression.combine(e, ec);
1804
+ // printf("e.toChars = %s\n", e.toChars());
1805
+ }
1806
+ Statement s1 = new ExpStatement(loc, e);
1807
+ return new CompoundStatement(loc, s1);
1808
+ }
1809
+
1810
+ /**
1811
+ * Determine if a move constructor is needed for struct sd,
1812
+ * if the following conditions are met:
1813
+ *
1814
+ * 1. sd does not define a move constructor
1815
+ * 2. at least one field of sd defines a move constructor
1816
+ *
1817
+ * Params:
1818
+ * sd = the `struct` for which the move constructor is generated
1819
+ * hasMoveCtor = set to true if a move constructor is already present
1820
+ *
1821
+ * Returns:
1822
+ * `true` if one needs to be generated
1823
+ * `false` otherwise
1824
+ */
1825
+ bool needMoveCtor (StructDeclaration sd, out bool hasMoveCtor)
1826
+ {
1827
+ if (global.errors)
1828
+ return false ;
1829
+
1830
+ auto ctor = sd.search(sd.loc, Id.moveCtor);
1831
+ if (ctor)
1832
+ {
1833
+ if (ctor.isOverloadSet())
1834
+ return false ;
1835
+ if (auto td = ctor.isTemplateDeclaration())
1836
+ ctor = td.funcroot;
1837
+ }
1838
+
1839
+ CtorDeclaration moveCtor;
1840
+ CtorDeclaration rvalueCtor;
1841
+
1842
+ if (! ctor)
1843
+ goto LcheckFields;
1844
+
1845
+ overloadApply(ctor, (Dsymbol s)
1846
+ {
1847
+ if (s.isTemplateDeclaration())
1848
+ return 0 ;
1849
+ auto ctorDecl = s.isCtorDeclaration();
1850
+ assert (ctorDecl);
1851
+ if (ctorDecl.isMoveCtor)
1852
+ {
1853
+ if (! moveCtor)
1854
+ moveCtor = ctorDecl;
1855
+ return 0 ;
1856
+ }
1857
+
1858
+ if (isRvalueConstructor(sd, ctorDecl))
1859
+ rvalueCtor = ctorDecl;
1860
+ return 0 ;
1861
+ });
1862
+
1863
+ if (moveCtor)
1864
+ {
1865
+ if (rvalueCtor)
1866
+ {
1867
+ .error(sd.loc, " `struct %s` may not define both a rvalue constructor and a move constructor" , sd.toChars());
1868
+ errorSupplemental(rvalueCtor.loc," rvalue constructor defined here" );
1869
+ errorSupplemental(moveCtor.loc, " move constructor defined here" );
1870
+ }
1871
+ hasMoveCtor = true ;
1872
+ return false ;
1873
+ }
1874
+
1875
+ LcheckFields:
1876
+ VarDeclaration fieldWithMoveCtor;
1877
+ // see if any struct members define a copy constructor
1878
+ foreach (v; sd.fields)
1879
+ {
1880
+ if (v.storage_class & STC .ref_)
1881
+ continue ;
1882
+ if (v.overlapped)
1883
+ continue ;
1884
+
1885
+ auto ts = v.type.baseElemOf().isTypeStruct();
1886
+ if (! ts)
1887
+ continue ;
1888
+ if (ts.sym.hasMoveCtor)
1889
+ {
1890
+ fieldWithMoveCtor = v;
1891
+ break ;
1892
+ }
1893
+ }
1894
+
1895
+ if (fieldWithMoveCtor && rvalueCtor)
1896
+ {
1897
+ .error(sd.loc, " `struct %s` may not define a rvalue constructor and have fields with move constructors" , sd.toChars());
1898
+ errorSupplemental(rvalueCtor.loc," rvalue constructor defined here" );
1899
+ errorSupplemental(fieldWithMoveCtor.loc, " field with move constructor defined here" );
1900
+ return false ;
1901
+ }
1902
+ else if (! fieldWithMoveCtor)
1903
+ return false ;
1904
+ return true ;
1905
+ }
1906
+
1907
+ /**
1908
+ * Generates a move constructor if needMoveCtor() returns true.
1909
+ * The generated move constructor will be of the form:
1910
+ * this(ref return scope inout(S) rhs) inout
1911
+ * {
1912
+ * this.field1 = rhs.field1;
1913
+ * this.field2 = rhs.field2;
1914
+ * ...
1915
+ * }
1916
+ *
1917
+ * Params:
1918
+ * sd = the `struct` for which the copy constructor is generated
1919
+ * sc = the scope where the copy constructor is generated
1920
+ *
1921
+ * Returns:
1922
+ * `true` if `struct` sd defines a copy constructor (explicitly or generated),
1923
+ * `false` otherwise.
1924
+ * References:
1925
+ * https://dlang.org/spec/struct.html#struct-copy-constructor
1926
+ */
1927
+ bool buildMoveCtor (StructDeclaration sd, Scope* sc)
1928
+ {
1929
+ // printf("buildMoveCtor() %s\n", sd.toChars());
1930
+ bool hasMoveCtor;
1931
+ if (! needMoveCtor(sd, hasMoveCtor))
1932
+ return hasMoveCtor;
1933
+
1934
+ // printf("generating move constructor for %s\n", sd.toChars());
1935
+ const MOD paramMod = MODFlags.wild;
1936
+ const MOD funcMod = MODFlags.wild;
1937
+ auto ccd = generateMoveCtorDeclaration(sd, ModToStc(paramMod), ModToStc(funcMod));
1938
+ auto moveCtorBody = generateMoveCtorBody(sd);
1939
+ ccd.fbody = moveCtorBody;
1940
+ sd.members.push(ccd);
1941
+ ccd.addMember(sc, sd);
1942
+ const errors = global.startGagging();
1943
+ Scope* sc2 = sc.push();
1944
+ sc2.stc = 0 ;
1945
+ sc2.linkage = LINK .d;
1946
+ ccd.dsymbolSemantic(sc2);
1947
+ ccd.semantic2(sc2);
1948
+ ccd.semantic3(sc2);
1949
+ // printf("ccd semantic: %s\n", ccd.type.toChars());
1950
+ sc2.pop();
1951
+ if (global.endGagging(errors) || sd.isUnionDeclaration())
1952
+ {
1953
+ ccd.storage_class |= STC .disable;
1954
+ ccd.fbody = null ;
1955
+ }
1956
+ return true ;
1957
+ }
1958
+
1959
+ }
0 commit comments