diff --git a/compiler/src/dmd/dsymbol.d b/compiler/src/dmd/dsymbol.d index 7467112ad04c..70e14b0279e9 100644 --- a/compiler/src/dmd/dsymbol.d +++ b/compiler/src/dmd/dsymbol.d @@ -33,6 +33,7 @@ import dmd.dscope; import dmd.dstruct; import dmd.dtemplate; import dmd.errors; +import dmd.errorsink; import dmd.expression; import dmd.func; import dmd.globals; @@ -122,6 +123,28 @@ struct Ungag } } +/** + * Temporarily changes the error sink for a scope. + * When the object goes out of scope, the original error sink is restored. + */ +struct ErrorSinkSwitch +{ + ErrorSink oldSink; + Scope* sc; + + extern (D) this(Scope* sc, ErrorSink newSink) nothrow @safe + { + this.sc = sc; + this.oldSink = sc.eSink; + sc.eSink = newSink; + } + + extern (C++) ~this() nothrow + { + sc.eSink = oldSink; + } +} + struct Visibility { /// @@ -683,6 +706,13 @@ extern (C++) class Dsymbol : ASTNode return parent.isSpeculative(); } + /** + * Returns an Ungag object that temporarily disables error gagging + * when not in a speculative context. + * + * This is the old implementation that uses global.gag. + * It will be deprecated in favor of ungagSpeculativeWithErrorSink. + */ final Ungag ungagSpeculative() const { const oldgag = global.gag; @@ -691,6 +721,19 @@ extern (C++) class Dsymbol : ASTNode return Ungag(oldgag); } + /** + * Returns an ErrorSinkSwitch object that temporarily changes the error sink + * to allow errors to be reported when not in a speculative context. + * + * This is the new implementation that uses ErrorSink instead of global.gag. + */ + final ErrorSinkSwitch ungagSpeculativeWithErrorSink(Scope* sc) const + { + if (sc.eSink == global.errorSinkNull && !isSpeculative() && !toParent2().isFuncDeclaration()) + return ErrorSinkSwitch(sc, global.errorSink); + return ErrorSinkSwitch(sc, sc.eSink); + } + // kludge for template.isSymbol() override final DYNCAST dyncast() const { diff --git a/compiler/src/dmd/dsymbolsem.d b/compiler/src/dmd/dsymbolsem.d index e93232f5b192..4654f5cbc133 100644 --- a/compiler/src/dmd/dsymbolsem.d +++ b/compiler/src/dmd/dsymbolsem.d @@ -2919,8 +2919,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } } - // Ungag errors when not speculative - Ungag ungag = sd.ungagSpeculative(); + // Ungag errors when not speculative using ErrorSink + auto errorSinkSwitch = sd.ungagSpeculativeWithErrorSink(sc); if (sd.semanticRun == PASS.initial) { @@ -3422,8 +3422,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor tc.sym = cldec; } - // Ungag errors when not speculative - Ungag ungag = cldec.ungagSpeculative(); + // Ungag errors when not speculative using ErrorSink + auto errorSinkSwitch = cldec.ungagSpeculativeWithErrorSink(sc); if (cldec.semanticRun == PASS.initial) { @@ -4799,9 +4799,11 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList { printf("Recursive template expansion\n"); } - auto ungag = Ungag(global.gag); - if (!tempinst.gagged) - global.gag = 0; + // Use ErrorSinkSwitch instead of Ungag + auto errorSinkSwitch = sc && sc.eSink == global.errorSinkNull ? + ErrorSinkSwitch(sc, global.errorSink) : + ErrorSinkSwitch(sc, sc.eSink); + .error(tempinst.loc, "%s `%s` recursive template expansion", tempinst.kind, tempinst.toPrettyChars); if (tempinst.gagged) tempinst.semanticRun = PASS.initial; @@ -5560,14 +5562,12 @@ void aliasSemantic(AliasDeclaration ds, Scope* sc) const errors = global.errors; Type oldtype = ds.type; - // Ungag errors when not instantiated DeclDefs scope alias - auto ungag = Ungag(global.gag); - //printf("%s parent = %s, gag = %d, instantiated = %d\n", ds.toChars(), ds.parent.toChars(), global.gag, ds.isInstantiated() !is null); - if (ds.parent && global.gag && !ds.isInstantiated() && !ds.toParent2().isFuncDeclaration() && (sc.minst || sc.tinst)) - { - //printf("%s type = %s\n", ds.toPrettyChars(), ds.type.toChars()); - global.gag = 0; - } + // Ungag errors when not instantiated DeclDefs scope alias using ErrorSink + auto errorSinkSwitch = sc && sc.eSink == global.errorSinkNull && + ds.parent && !ds.isInstantiated() && !ds.toParent2().isFuncDeclaration() && + (sc.minst || sc.tinst) ? + ErrorSinkSwitch(sc, global.errorSink) : + ErrorSinkSwitch(sc, sc.eSink); // https://issues.dlang.org/show_bug.cgi?id=18480 // Detect `alias sym = sym;` to prevent creating loops in overload overnext lists. diff --git a/compiler/src/dmd/dtemplate.d b/compiler/src/dmd/dtemplate.d index fe398d6696d2..fa1a18996f44 100644 --- a/compiler/src/dmd/dtemplate.d +++ b/compiler/src/dmd/dtemplate.d @@ -4324,8 +4324,8 @@ extern (C++) class TemplateInstance : ScopeDsymbol { if (td._scope) { - // Try to fix forward reference. Ungag errors while doing so. - Ungag ungag = td.ungagSpeculative(); + // Try to fix forward reference. Ungag errors while doing so using ErrorSink. + auto errorSinkSwitch = td.ungagSpeculativeWithErrorSink(td._scope); td.dsymbolSemantic(td._scope); } if (td.semanticRun == PASS.initial) diff --git a/compiler/src/dmd/templatesem.d b/compiler/src/dmd/templatesem.d index a2ef8459742d..78c94f455e5b 100644 --- a/compiler/src/dmd/templatesem.d +++ b/compiler/src/dmd/templatesem.d @@ -1933,7 +1933,8 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, if (!fd.isCtorDeclaration && fd.semanticRun < PASS.semanticdone) { - fd.ungagSpeculative(); + // Use ErrorSinkSwitch instead of Ungag + auto errorSinkSwitch = fd.ungagSpeculativeWithErrorSink(sc); fd.dsymbolSemantic(null); } if (fd.semanticRun < PASS.semanticdone) @@ -2105,8 +2106,8 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, if (td.semanticRun == PASS.initial && td._scope) { - // Try to fix forward reference. Ungag errors while doing so. - td.ungagSpeculative(); + // Try to fix forward reference. Ungag errors while doing so using ErrorSink. + auto errorSinkSwitch = td.ungagSpeculativeWithErrorSink(td._scope); td.dsymbolSemantic(td._scope); } if (td.semanticRun == PASS.initial)