@@ -1729,10 +1729,12 @@ void semanticTypeInfoMembers(StructDeclaration sd)
1729
1729
* verify that such an allocation is allowed under the current compilation
1730
1730
* settings.
1731
1731
*
1732
- * Whenever an error is emitted, every nested function that actually closes
1733
- * over a variable is listed in a supplemental diagnostic, together with the
1734
- * location of the captured variable’s declaration. (This extra walk is
1735
- * skipped when the compiler is gagged.)
1732
+ * Emits errors if:
1733
+ * - A captured variable has a destructor, which is prohibited.
1734
+ * - Closure allocation violates `@nogc` or `-betterC`.
1735
+ *
1736
+ * Additionally, provides supplemental diagnostics listing nested functions
1737
+ * that close over variables, unless the compiler is gagged.
1736
1738
*
1737
1739
* See_Also:
1738
1740
* $(UL
@@ -1747,6 +1749,33 @@ extern (D) bool checkClosure(FuncDeclaration fd)
1747
1749
if (! fd.needsClosure())
1748
1750
return false ;
1749
1751
1752
+ // Preventing closure construction due to variables with destructor
1753
+ foreach (v; fd.closureVars)
1754
+ {
1755
+ if (! v.type)
1756
+ continue ;
1757
+
1758
+ if (auto ts = v.type.isTypeStruct())
1759
+ {
1760
+ if (ts.sym && ts.sym.dtor)
1761
+ {
1762
+ .error(v.loc, " variable `%s` has scoped destruction, cannot build closure" , v.toPrettyChars());
1763
+ fd.errors = true ;
1764
+ return true ;
1765
+ }
1766
+ }
1767
+ else if (auto tc = v.type.isTypeClass())
1768
+ {
1769
+ if (tc.sym && tc.sym.dtor && (v.storage_class & STC .scope_))
1770
+ {
1771
+ .error(v.loc, " scoped class variable `%s` has destructor, cannot build closure" , v.toPrettyChars());
1772
+ fd.errors = true ;
1773
+ return true ;
1774
+ }
1775
+ }
1776
+ }
1777
+
1778
+ // Checking compilation restrictions
1750
1779
if (fd.setGC(fd.loc, " allocating a closure for `%s()`" , fd))
1751
1780
{
1752
1781
.error(fd.loc, " %s `%s` is `@nogc` yet allocates closure for `%s()` with the GC" , fd.kind, fd.toPrettyChars(), fd.toChars());
@@ -1765,7 +1794,8 @@ extern (D) bool checkClosure(FuncDeclaration fd)
1765
1794
return false ;
1766
1795
}
1767
1796
1768
- FuncDeclarations a;
1797
+ // Additional diagnostics: who captures variables
1798
+ FuncDeclarations reported;
1769
1799
foreach (v; fd.closureVars)
1770
1800
{
1771
1801
foreach (f; v.nestedrefs)
@@ -1778,18 +1808,25 @@ extern (D) bool checkClosure(FuncDeclaration fd)
1778
1808
auto fx = s.isFuncDeclaration();
1779
1809
if (! fx)
1780
1810
continue ;
1811
+
1781
1812
if (fx.isThis() ||
1782
1813
fx.tookAddressOf ||
1783
1814
checkEscapingSiblings(fx, fd))
1784
1815
{
1785
- foreach (f2; a)
1816
+ bool alreadyReported = false ;
1817
+ foreach (r; reported)
1786
1818
{
1787
- if (f2 == f)
1788
- break LcheckAncestorsOfANestedRef;
1819
+ if (r == f)
1820
+ {
1821
+ alreadyReported = true ;
1822
+ break ;
1823
+ }
1789
1824
}
1790
- a.push(f);
1791
- .errorSupplemental(f.loc, " %s `%s` closes over variable `%s`" ,
1792
- f.kind, f.toErrMsg(), v.toChars());
1825
+ if (alreadyReported)
1826
+ break LcheckAncestorsOfANestedRef;
1827
+
1828
+ reported.push(f);
1829
+ .errorSupplemental(f.loc, " %s `%s` closes over variable `%s`" , f.kind, f.toErrMsg(), v.toChars());
1793
1830
if (v.ident != Id.This)
1794
1831
.errorSupplemental(v.loc, " `%s` declared here" , v.toChars());
1795
1832
0 commit comments