diff --git a/src/dmd/doc.d b/src/dmd/doc.d index dbf58e2a1ab0..97d5c438a455 100644 --- a/src/dmd/doc.d +++ b/src/dmd/doc.d @@ -4482,7 +4482,7 @@ private void highlightCode2(Scope* sc, Dsymbols* a, OutBuffer* buf, size_t offse { uint errorsave = global.startGagging(); scope diagnosticReporter = new StderrDiagnosticReporter(global.params.useDeprecated); - scope Lexer lex = new Lexer(null, cast(char*)buf.data, 0, buf.offset - 1, 0, 1, diagnosticReporter); + scope Lexer lex = new Lexer(null, cast(char*)buf.data, 0, buf.offset - 1, 0, 1); OutBuffer res; const(char)* lastp = cast(char*)buf.data; //printf("highlightCode2('%.*s')\n", cast(int)(buf.offset - 1), buf.data); @@ -4490,7 +4490,7 @@ private void highlightCode2(Scope* sc, Dsymbols* a, OutBuffer* buf, size_t offse while (1) { Token tok; - lex.scan(&tok); + lex.scan(&tok).printDiagnostics(diagnosticReporter); highlightCode3(sc, &res, lastp, tok.ptr); const(char)* highlight = null; switch (tok.value) diff --git a/src/dmd/dsymbol.d b/src/dmd/dsymbol.d index afc5cf3d9ab6..5685a869c517 100644 --- a/src/dmd/dsymbol.d +++ b/src/dmd/dsymbol.d @@ -349,7 +349,7 @@ extern (C++) class Dsymbol : ASTNode final bool checkDeprecated(const ref Loc loc, Scope* sc) { - if (global.params.useDeprecated != Diagnostic.off && isDeprecated()) + if (global.params.useDeprecated != DiagnosticReporting.off && isDeprecated()) { // Don't complain if we're inside a deprecated symbol's scope if (sc.isDeprecated()) diff --git a/src/dmd/errors.d b/src/dmd/errors.d index 064115e64d3f..de748b827061 100644 --- a/src/dmd/errors.d +++ b/src/dmd/errors.d @@ -21,6 +21,453 @@ import dmd.root.outbuffer; import dmd.root.rmem; import dmd.console; +auto toStringzThen(alias func)(const(char)[] str) +{ + import core.stdc.stdlib: malloc, free; + + if (str.length == 0) + return func("".ptr); + + char[1024] staticBuffer; + const newLength = str.length + 1; + char[] buffer; + + if (str.length >= buffer.length) + buffer = (cast(char*) malloc(newLength * char.sizeof))[0 .. newLength]; + else + buffer = staticBuffer[0 .. newLength]; + + scope (exit) + { + if (&buffer[0] != &staticBuffer[0]) + free(&buffer[0]); + } + + buffer[0 .. $ - 1] = str; + buffer[$ - 1] = '\0'; + + return func(&buffer[0]); +} + +struct Diagnosed(T) +{ + T value; + DiagnosticSet diagnosticSet; +} + +T unwrap(alias func, T)(Diagnosed!T diagnosed) +{ + func(diagnosed.diagnosticSet); + return diagnosed.value; +} + +Diagnosed!T diagnosed(T)(T value, DiagnosticSet diagnosticSet) +{ + return Diagnosed!(T)(value, diagnosticSet); +} + +auto map(alias func, T)(Diagnosed!T diagnosed) +{ + return .diagnosed(func(diagnosed.value), diagnosed.diagnosticSet); +} + +auto chainedMap(alias func, T)(Diagnosed!T diagnosed) +{ + auto diagnosedResult = func(diagnosed.value); + auto originalSet = diagnosed.diagnosticSet; + auto resultSet = diagnosedResult.diagnosticSet; + + return .diagnosed(diagnosedResult.value, originalSet ~ resultSet); +} + +/// Diagnostic severity. +enum Severity +{ + /// An error occurred. + error, + + /// A warning occurred. + warning, + + /// A deprecation occurred. + deprecation, +} + +struct DiagnosticSet +{ + private Diagnostic[] _diagnostics; + + void add(Diagnostic diagnostic) pure nothrow @safe + { + _diagnostics ~= diagnostic; + } + + DiagnosticSet opBinary(string op)(DiagnosticSet set) pure nothrow @safe + if (op == "~") + { + DiagnosticSet newSet; + newSet ~= this; + newSet ~= set; + + return newSet; + } + + DiagnosticSet opOpAssign(string op)(Diagnostic diagnostic) pure nothrow @safe + if (op == "~") + { + _diagnostics ~= diagnostic; + return this; + } + + DiagnosticSet opOpAssign(string op)(DiagnosticSet set) pure nothrow @safe + if (op == "~") + { + _diagnostics ~= set._diagnostics; + return this; + } + + void addSupplemental(const Diagnostic diagnostic) pure nothrow @safe + { + _diagnostics[$ - 1].addSupplementalDiagnostic(diagnostic); + } + + const(Diagnostic) front() const pure nothrow @nogc @safe + { + return _diagnostics[0]; + } + + void popFront() pure nothrow @nogc @safe + { + _diagnostics = _diagnostics[1 .. $]; + } + + bool empty() const pure nothrow @nogc @safe + { + return _diagnostics.length == 0; + } + + size_t length() const pure nothrow @nogc @safe + { + return _diagnostics.length; + } + + const(Diagnostic) opIndex(size_t index) const pure nothrow @nogc @safe + { + return _diagnostics[index]; + } +} + +/// A single diagnostic message. +abstract class Diagnostic +{ + /// The location of where the diagnostic occurred. + const Loc loc; + + /// The severity of the diagnostic. + const Severity severity; + + /// The message. + abstract string message() const nothrow; + + private const(Diagnostic)[] _supplementalDiagnostics; + + this(const ref Loc loc, const Severity severity) pure nothrow @nogc @safe + { + this.loc = loc; + this.severity = severity; + } + + final const(Diagnostic[]) supplementalDiagnostics() const pure nothrow @nogc @safe + { + return _supplementalDiagnostics; + } + + private final void addSupplementalDiagnostic(const Diagnostic diagnostic) pure nothrow @safe + in + { + assert(diagnostic.severity == severity); + } + body + { + _supplementalDiagnostics ~= diagnostic; + } +} + +class FormattedDiagnostic(Args...) : Diagnostic +{ + private const string formatString; + private const Args args; + + this(const ref Loc loc, const Severity severity, const string formatString, + const Args args) pure nothrow @nogc @safe + { + super(loc, severity); + this.formatString = formatString; + this.args = args; + } + + override string message() const nothrow + { + OutBuffer buffer; + formatString.toStringzThen!(str => buffer.printf(str, args)); + + return cast(string) buffer.extractSlice(); + } +} + +void printDiagnostics(DiagnosticSet set, DiagnosticReporter reporter) +{ + alias DiagnosticFunction = void delegate( + ref const(Loc) loc, const(char)* format, ...); + + static void printMessage(const Diagnostic diagnostic, + DiagnosticFunction diagnosticFunc) + { + const message = diagnostic.message; + + diagnosticFunc(diagnostic.loc, "%.*s", + cast(int) message.length, message.ptr); + } + + static void printSupplementalMessages(const Diagnostic[] diagnostics, + DiagnosticFunction diagnosticFunc) + { + foreach (diagnostic; diagnostics) + printMessage(diagnostic, diagnosticFunc); + } + + foreach (diagnostic; set) + { + const message = diagnostic.message; + + final switch (diagnostic.severity) + { + case Severity.deprecation: + printMessage(diagnostic, &reporter.deprecation); + printSupplementalMessages(diagnostic.supplementalDiagnostics, + &reporter.deprecationSupplemental); + break; + + case Severity.error: + printMessage(diagnostic, &reporter.error); + printSupplementalMessages(diagnostic.supplementalDiagnostics, + &reporter.errorSupplemental); + break; + + case Severity.warning: + printMessage(diagnostic, &reporter.warning); + printSupplementalMessages(diagnostic.supplementalDiagnostics, + &reporter.warningSupplemental); + break; + } + } +} + +/// Interface for diagnostic reporting. +abstract class DiagnosticReporter +{ + /// Returns: the number of errors that occurred during lexing or parsing. + abstract int errorCount(); + + /// Returns: the number of warnings that occurred during lexing or parsing. + abstract int warningCount(); + + /// Returns: the number of deprecations that occurred during lexing or parsing. + abstract int deprecationCount(); + + /** + Reports an error message. + + Params: + loc = Location of error + format = format string for error + ... = format string arguments + */ + final void error(const ref Loc loc, const(char)* format, ...) + { + va_list args; + va_start(args, format); + error(loc, format, args); + va_end(args); + } + + /// ditto + abstract void error(const ref Loc loc, const(char)* format, va_list args); + + /** + Reports additional details about an error message. + + Params: + loc = Location of error + format = format string for supplemental message + ... = format string arguments + */ + final void errorSupplemental(const ref Loc loc, const(char)* format, ...) + { + va_list args; + va_start(args, format); + errorSupplemental(loc, format, args); + va_end(args); + } + + /// ditto + abstract void errorSupplemental(const ref Loc loc, const(char)* format, va_list); + + /** + Reports a warning message. + + Params: + loc = Location of warning + format = format string for warning + ... = format string arguments + */ + final void warning(const ref Loc loc, const(char)* format, ...) + { + va_list args; + va_start(args, format); + warning(loc, format, args); + va_end(args); + } + + /// ditto + abstract void warning(const ref Loc loc, const(char)* format, va_list args); + + /** + Reports additional details about a warning message. + + Params: + loc = Location of warning + format = format string for supplemental message + ... = format string arguments + */ + final void warningSupplemental(const ref Loc loc, const(char)* format, ...) + { + va_list args; + va_start(args, format); + warningSupplemental(loc, format, args); + va_end(args); + } + + /// ditto + abstract void warningSupplemental(const ref Loc loc, const(char)* format, va_list); + + /** + Reports a deprecation message. + + Params: + loc = Location of the deprecation + format = format string for the deprecation + ... = format string arguments + */ + final void deprecation(const ref Loc loc, const(char)* format, ...) + { + va_list args; + va_start(args, format); + deprecation(loc, format, args); + va_end(args); + } + + /// ditto + abstract void deprecation(const ref Loc loc, const(char)* format, va_list args); + + /** + Reports additional details about a deprecation message. + + Params: + loc = Location of deprecation + format = format string for supplemental message + ... = format string arguments + */ + final void deprecationSupplemental(const ref Loc loc, const(char)* format, ...) + { + va_list args; + va_start(args, format); + deprecationSupplemental(loc, format, args); + va_end(args); + } + + /// ditto + abstract void deprecationSupplemental(const ref Loc loc, const(char)* format, va_list); +} + +/** +Diagnostic reporter which prints the diagnostic messages to stderr. + +This is usually the default diagnostic reporter. +*/ +final class StderrDiagnosticReporter : DiagnosticReporter +{ + private const DiagnosticReporting useDeprecated; + + private int errorCount_; + private int warningCount_; + private int deprecationCount_; + + /** + Initializes this object. + + Params: + useDeprecated = indicates how deprecation diagnostics should be + handled + */ + this(DiagnosticReporting useDeprecated) + { + this.useDeprecated = useDeprecated; + } + + override int errorCount() + { + return errorCount_; + } + + override int warningCount() + { + return warningCount_; + } + + override int deprecationCount() + { + return deprecationCount_; + } + + override void error(const ref Loc loc, const(char)* format, va_list args) + { + verror(loc, format, args); + errorCount_++; + } + + override void errorSupplemental(const ref Loc loc, const(char)* format, va_list args) + { + verrorSupplemental(loc, format, args); + } + + override void warning(const ref Loc loc, const(char)* format, va_list args) + { + vwarning(loc, format, args); + warningCount_++; + } + + override void warningSupplemental(const ref Loc loc, const(char)* format, va_list args) + { + vwarningSupplemental(loc, format, args); + } + + override void deprecation(const ref Loc loc, const(char)* format, va_list args) + { + vdeprecation(loc, format, args); + + if (useDeprecated == DiagnosticReporting.error) + errorCount_++; + else + deprecationCount_++; + } + + override void deprecationSupplemental(const ref Loc loc, const(char)* format, va_list args) + { + vdeprecationSupplemental(loc, format, args); + } +} + /** * Color highlighting to classify messages */ @@ -322,12 +769,12 @@ extern (C++) void verrorSupplemental(const ref Loc loc, const(char)* format, va_ */ extern (C++) void vwarning(const ref Loc loc, const(char)* format, va_list ap) { - if (global.params.warnings != Diagnostic.off) + if (global.params.warnings != DiagnosticReporting.off) { if (!global.gag) { verrorPrint(loc, Classification.warning, "Warning: ", format, ap); - if (global.params.warnings == Diagnostic.error) + if (global.params.warnings == DiagnosticReporting.error) global.warnings++; } else @@ -346,7 +793,7 @@ extern (C++) void vwarning(const ref Loc loc, const(char)* format, va_list ap) */ extern (C++) void vwarningSupplemental(const ref Loc loc, const(char)* format, va_list ap) { - if (global.params.warnings != Diagnostic.off && !global.gag) + if (global.params.warnings != DiagnosticReporting.off && !global.gag) verrorPrint(loc, Classification.warning, " ", format, ap); } @@ -362,9 +809,9 @@ extern (C++) void vwarningSupplemental(const ref Loc loc, const(char)* format, v extern (C++) void vdeprecation(const ref Loc loc, const(char)* format, va_list ap, const(char)* p1 = null, const(char)* p2 = null) { __gshared const(char)* header = "Deprecation: "; - if (global.params.useDeprecated == Diagnostic.error) + if (global.params.useDeprecated == DiagnosticReporting.error) verror(loc, format, ap, p1, p2, header); - else if (global.params.useDeprecated == Diagnostic.inform) + else if (global.params.useDeprecated == DiagnosticReporting.inform) { if (!global.gag) { @@ -408,9 +855,9 @@ extern (C++) void vmessage(const ref Loc loc, const(char)* format, va_list ap) */ extern (C++) void vdeprecationSupplemental(const ref Loc loc, const(char)* format, va_list ap) { - if (global.params.useDeprecated == Diagnostic.error) + if (global.params.useDeprecated == DiagnosticReporting.error) verrorSupplemental(loc, format, ap); - else if (global.params.useDeprecated == Diagnostic.inform && !global.gag) + else if (global.params.useDeprecated == DiagnosticReporting.inform && !global.gag) verrorPrint(loc, Classification.deprecation, " ", format, ap); } @@ -519,7 +966,7 @@ private void colorHighlightCode(OutBuffer* buf) auto gaggedErrorsSave = global.startGagging(); scope diagnosticReporter = new StderrDiagnosticReporter(global.params.useDeprecated); - scope Lexer lex = new Lexer(null, cast(char*)buf.data, 0, buf.offset - 1, 0, 1, diagnosticReporter); + scope Lexer lex = new Lexer(null, cast(char*)buf.data, 0, buf.offset - 1, 0, 1); OutBuffer res; const(char)* lastp = cast(char*)buf.data; //printf("colorHighlightCode('%.*s')\n", cast(int)(buf.offset - 1), buf.data); @@ -529,7 +976,8 @@ private void colorHighlightCode(OutBuffer* buf) while (1) { Token tok; - lex.scan(&tok); + lex.scan(&tok) + .printDiagnostics(diagnosticReporter); res.writestring(lastp[0 .. tok.ptr - lastp]); HIGHLIGHT highlight; switch (tok.value) diff --git a/src/dmd/expressionsem.d b/src/dmd/expressionsem.d index a4933bd82824..dbecc6e07c64 100644 --- a/src/dmd/expressionsem.d +++ b/src/dmd/expressionsem.d @@ -8530,7 +8530,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } - if (0 && global.params.warnings != Diagnostic.off && !global.gag && exp.op == TOK.assign && + if (0 && global.params.warnings != DiagnosticReporting.off && !global.gag && exp.op == TOK.assign && e2x.op != TOK.slice && e2x.op != TOK.assign && e2x.op != TOK.arrayLiteral && e2x.op != TOK.string_ && !(e2x.op == TOK.add || e2x.op == TOK.min || @@ -8594,7 +8594,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } else { - if (0 && global.params.warnings != Diagnostic.off && !global.gag && exp.op == TOK.assign && + if (0 && global.params.warnings != DiagnosticReporting.off && !global.gag && exp.op == TOK.assign && t1.ty == Tarray && t2.ty == Tsarray && e2x.op != TOK.slice && t2.implicitConvTo(t1)) diff --git a/src/dmd/frontend.d b/src/dmd/frontend.d index fcdb55393d33..53d39d1bfb3f 100644 --- a/src/dmd/frontend.d +++ b/src/dmd/frontend.d @@ -15,7 +15,7 @@ module dmd.frontend; import dmd.dmodule : Module; -import dmd.lexer : DiagnosticReporter; +import dmd.errors : DiagnosticReporter; import std.range.primitives : isInputRange, ElementType; import std.traits : isNarrowString; @@ -367,7 +367,7 @@ string prettyPrint(Module m) private DiagnosticReporter defaultDiagnosticReporter() { import dmd.globals : global; - import dmd.lexer : StderrDiagnosticReporter; + import dmd.errors : StderrDiagnosticReporter; return new StderrDiagnosticReporter(global.params.useDeprecated); } diff --git a/src/dmd/globals.d b/src/dmd/globals.d index f2853bbd5756..c6a720b13484 100644 --- a/src/dmd/globals.d +++ b/src/dmd/globals.d @@ -34,7 +34,7 @@ enum TARGET : bool DragonFlyBSD = xversion!`DragonFlyBSD`, } -enum Diagnostic : ubyte +enum DiagnosticReporting : ubyte { error, // generate an error inform, // generate a warning @@ -132,7 +132,7 @@ struct Param bool isSolaris; // generate code for Solaris bool hasObjectiveC; // target supports Objective-C bool mscoff = false; // for Win32: write MsCoff object files instead of OMF - Diagnostic useDeprecated = Diagnostic.inform; // how use of deprecated features are handled + DiagnosticReporting useDeprecated = DiagnosticReporting.inform; // how use of deprecated features are handled bool stackstomp; // add stack stomping code bool useUnitTests; // generate unittest code bool useInline = false; // inline expand functions @@ -140,7 +140,7 @@ struct Param bool noDIP25; // revert to pre-DIP25 behavior bool release; // build release version bool preservePaths; // true means don't strip path from source file - Diagnostic warnings = Diagnostic.off; // how compiler warnings are handled + DiagnosticReporting warnings = DiagnosticReporting.off; // how compiler warnings are handled bool pic; // generate position-independent-code for shared libs bool color; // use ANSI colors in console output bool cov; // generate code coverage data @@ -492,9 +492,8 @@ nothrow: this.filename = filename; } - extern (C++) const(char)* toChars() const + extern (C++) void toChars(ref OutBuffer buf) const { - OutBuffer buf; if (filename) { buf.writestring(filename); @@ -510,6 +509,12 @@ nothrow: } buf.writeByte(')'); } + } + + extern (C++) const(char)* toChars() const + { + OutBuffer buf; + toChars(buf); return buf.extractString(); } diff --git a/src/dmd/iasmgcc.d b/src/dmd/iasmgcc.d index 42d54213a52b..f4e7a162a379 100644 --- a/src/dmd/iasmgcc.d +++ b/src/dmd/iasmgcc.d @@ -20,11 +20,11 @@ import core.stdc.string; import dmd.arraytypes; import dmd.astcodegen; import dmd.dscope; +import dmd.errors; import dmd.expression; import dmd.expressionsem; import dmd.identifier; import dmd.globals; -import dmd.lexer; import dmd.parse; import dmd.tokens; import dmd.statement; diff --git a/src/dmd/lexer.d b/src/dmd/lexer.d index 2ad44e72223c..37938abadb30 100644 --- a/src/dmd/lexer.d +++ b/src/dmd/lexer.d @@ -150,16 +150,18 @@ unittest */ string text = "int"; // We rely on the implicit null-terminator scope diagnosticReporter = new StderrDiagnosticReporter(global.params.useDeprecated); - scope Lexer lex1 = new Lexer(null, text.ptr, 0, text.length, 0, 0, diagnosticReporter); + scope Lexer lex1 = new Lexer(null, text.ptr, 0, text.length, 0, 0); + + alias printDiagnostics = set => set.printDiagnostics(diagnosticReporter); TOK tok; - tok = lex1.nextToken(); + tok = lex1.nextToken().unwrap!printDiagnostics; //printf("tok == %s, %d, %d\n", Token::toChars(tok), tok, TOK.int32); assert(tok == TOK.int32); - tok = lex1.nextToken(); + tok = lex1.nextToken().unwrap!printDiagnostics; assert(tok == TOK.endOfFile); - tok = lex1.nextToken(); + tok = lex1.nextToken().unwrap!printDiagnostics; assert(tok == TOK.endOfFile); - tok = lex1.nextToken(); + tok = lex1.nextToken().unwrap!printDiagnostics; assert(tok == TOK.endOfFile); } @@ -186,224 +188,21 @@ unittest foreach (testcase; testcases) { scope diagnosticReporter = new StderrDiagnosticReporter(global.params.useDeprecated); - scope Lexer lex2 = new Lexer(null, testcase.ptr, 0, testcase.length-1, 0, 0, diagnosticReporter); - TOK tok = lex2.nextToken(); + scope Lexer lex2 = new Lexer(null, testcase.ptr, 0, testcase.length-1, 0, 0); + + alias printDiagnostics = set => set.printDiagnostics(diagnosticReporter); + TOK tok = lex2.nextToken().unwrap!printDiagnostics; size_t iterations = 1; while ((tok != TOK.endOfFile) && (iterations++ < testcase.length)) { - tok = lex2.nextToken(); + tok = lex2.nextToken().unwrap!printDiagnostics; } assert(tok == TOK.endOfFile); - tok = lex2.nextToken(); + tok = lex2.nextToken().unwrap!printDiagnostics; assert(tok == TOK.endOfFile); } } -/// Interface for diagnostic reporting. -abstract class DiagnosticReporter -{ - /// Returns: the number of errors that occurred during lexing or parsing. - abstract int errorCount(); - - /// Returns: the number of warnings that occurred during lexing or parsing. - abstract int warningCount(); - - /// Returns: the number of deprecations that occurred during lexing or parsing. - abstract int deprecationCount(); - - /** - Reports an error message. - - Params: - loc = Location of error - format = format string for error - ... = format string arguments - */ - final void error(const ref Loc loc, const(char)* format, ...) - { - va_list args; - va_start(args, format); - error(loc, format, args); - va_end(args); - } - - /// ditto - abstract void error(const ref Loc loc, const(char)* format, va_list args); - - /** - Reports additional details about an error message. - - Params: - loc = Location of error - format = format string for supplemental message - ... = format string arguments - */ - final void errorSupplemental(const ref Loc loc, const(char)* format, ...) - { - va_list args; - va_start(args, format); - errorSupplemental(loc, format, args); - va_end(args); - } - - /// ditto - abstract void errorSupplemental(const ref Loc loc, const(char)* format, va_list); - - /** - Reports a warning message. - - Params: - loc = Location of warning - format = format string for warning - ... = format string arguments - */ - final void warning(const ref Loc loc, const(char)* format, ...) - { - va_list args; - va_start(args, format); - warning(loc, format, args); - va_end(args); - } - - /// ditto - abstract void warning(const ref Loc loc, const(char)* format, va_list args); - - /** - Reports additional details about a warning message. - - Params: - loc = Location of warning - format = format string for supplemental message - ... = format string arguments - */ - final void warningSupplemental(const ref Loc loc, const(char)* format, ...) - { - va_list args; - va_start(args, format); - warningSupplemental(loc, format, args); - va_end(args); - } - - /// ditto - abstract void warningSupplemental(const ref Loc loc, const(char)* format, va_list); - - /** - Reports a deprecation message. - - Params: - loc = Location of the deprecation - format = format string for the deprecation - ... = format string arguments - */ - final void deprecation(const ref Loc loc, const(char)* format, ...) - { - va_list args; - va_start(args, format); - deprecation(loc, format, args); - va_end(args); - } - - /// ditto - abstract void deprecation(const ref Loc loc, const(char)* format, va_list args); - - /** - Reports additional details about a deprecation message. - - Params: - loc = Location of deprecation - format = format string for supplemental message - ... = format string arguments - */ - final void deprecationSupplemental(const ref Loc loc, const(char)* format, ...) - { - va_list args; - va_start(args, format); - deprecationSupplemental(loc, format, args); - va_end(args); - } - - /// ditto - abstract void deprecationSupplemental(const ref Loc loc, const(char)* format, va_list); -} - -/** -Diagnostic reporter which prints the diagnostic messages to stderr. - -This is usually the default diagnostic reporter. -*/ -final class StderrDiagnosticReporter : DiagnosticReporter -{ - private const Diagnostic useDeprecated; - - private int errorCount_; - private int warningCount_; - private int deprecationCount_; - - /** - Initializes this object. - - Params: - useDeprecated = indicates how deprecation diagnostics should be - handled - */ - this(Diagnostic useDeprecated) - { - this.useDeprecated = useDeprecated; - } - - override int errorCount() - { - return errorCount_; - } - - override int warningCount() - { - return warningCount_; - } - - override int deprecationCount() - { - return deprecationCount_; - } - - override void error(const ref Loc loc, const(char)* format, va_list args) - { - verror(loc, format, args); - errorCount_++; - } - - override void errorSupplemental(const ref Loc loc, const(char)* format, va_list args) - { - verrorSupplemental(loc, format, args); - } - - override void warning(const ref Loc loc, const(char)* format, va_list args) - { - vwarning(loc, format, args); - warningCount_++; - } - - override void warningSupplemental(const ref Loc loc, const(char)* format, va_list args) - { - vwarningSupplemental(loc, format, args); - } - - override void deprecation(const ref Loc loc, const(char)* format, va_list args) - { - vdeprecation(loc, format, args); - - if (useDeprecated == Diagnostic.error) - errorCount_++; - else - deprecationCount_++; - } - - override void deprecationSupplemental(const ref Loc loc, const(char)* format, va_list args) - { - vdeprecationSupplemental(loc, format, args); - } -} - /*********************************************************** */ class Lexer @@ -416,6 +215,8 @@ class Lexer const(char)* p; // current character Token token; + // should be made private when the parser has its own DiagnosticSet + protected DiagnosticSet diagnosticSet; private { @@ -428,7 +229,6 @@ class Lexer bool commentToken; // comments are TOK.comment's int lastDocLine; // last line of previous doc comment - DiagnosticReporter diagnosticReporter; Token* tokenFreelist; } @@ -443,18 +243,10 @@ class Lexer * endoffset = the last offset to read into base[] * doDocComment = handle documentation comments * commentToken = comments become TOK.comment's - * diagnosticReporter = the diagnostic reporter to use */ this(const(char)* filename, const(char)* base, size_t begoffset, - size_t endoffset, bool doDocComment, bool commentToken, - DiagnosticReporter diagnosticReporter) - in - { - assert(diagnosticReporter !is null); - } - body + size_t endoffset, bool doDocComment, bool commentToken) { - this.diagnosticReporter = diagnosticReporter; scanloc = Loc(filename, 1, 1); //printf("Lexer::Lexer(%p,%d)\n",base,length); //printf("lexer.filename = %s\n", filename); @@ -495,7 +287,11 @@ class Lexer /// Returns: `true` if any errors occurred during lexing or parsing. final bool errors() { - return diagnosticReporter.errorCount > 0; + foreach (diagnostic; diagnosticSet) + if (diagnostic.severity == Severity.error) + return true; + + return false; } /// Returns: a newly allocated `Token`. @@ -518,8 +314,9 @@ class Lexer tokenFreelist = token; } - final TOK nextToken() + final Diagnosed!TOK nextToken() { + DiagnosticSet set; prevloc = token.loc; if (token.next) { @@ -528,35 +325,40 @@ class Lexer releaseToken(t); } else - { - scan(&token); - } + set = scan(&token); + //printf(token.toChars()); - return token.value; + return diagnosed(token.value, set); } /*********************** * Look ahead at next token's value. */ - final TOK peekNext() + final Diagnosed!TOK peekNext() { - return peek(&token).value; + return peek(&token).map!(v => v.value); } /*********************** * Look 2 tokens ahead at value. */ - final TOK peekNext2() + final Diagnosed!TOK peekNext2() { - Token* t = peek(&token); - return peek(t).value; + return peek(&token) + .chainedMap!(t => peek(t)) + .map!(t => t.value); } /**************************** * Turn next token in buffer into a token. + * + * Returns: a set of diagnostic that occurred when scanning the token */ - final void scan(Token* t) + final DiagnosticSet scan(Token* t) { + scope (exit) + diagnosticSet = DiagnosticSet(); + const lastLine = scanloc.linnum; Loc startLoc; t.blockComment = null; @@ -573,7 +375,7 @@ class Lexer case 0x1A: t.value = TOK.endOfFile; // end of file // Intentionally not advancing `p`, such that subsequent calls keep returning TOK.endOfFile. - return; + return diagnosticSet; case ' ': case '\t': case '\v': @@ -595,7 +397,7 @@ class Lexer ++p; t.unsvalue = 0; t.value = TOK.int32Literal; - return; + return diagnosticSet; } goto Lnumber; @@ -605,11 +407,11 @@ class Lexer t.unsvalue = *p - '0'; ++p; t.value = TOK.int32Literal; - return; + return diagnosticSet; } Lnumber: t.value = number(t); - return; + return diagnosticSet; case '\'': if (issinglechar(p[1]) && p[2] == '\'') @@ -620,7 +422,7 @@ class Lexer } else t.value = charConstant(t); - return; + return diagnosticSet; case 'r': if (p[1] != '"') goto case_ident; @@ -628,32 +430,32 @@ class Lexer goto case '`'; case '`': wysiwygStringConstant(t); - return; + return diagnosticSet; case 'x': if (p[1] != '"') goto case_ident; p++; t.value = hexStringConstant(t); deprecation("Built-in hex string literals are deprecated, use `std.conv.hexString` instead."); - return; + return diagnosticSet; case 'q': if (p[1] == '"') { p++; delimitedStringConstant(t); - return; + return diagnosticSet; } else if (p[1] == '{') { p++; tokenStringConstant(t); - return; + return diagnosticSet; } else goto case_ident; case '"': escapeStringConstant(t); - return; + return diagnosticSet; case 'a': case 'b': case 'c': @@ -782,7 +584,7 @@ class Lexer } } //printf("t.value = %d\n",t.value); - return; + return diagnosticSet; } case '/': p++; @@ -791,7 +593,7 @@ class Lexer case '=': p++; t.value = TOK.divAssign; - return; + return diagnosticSet; case '*': p++; startLoc = loc(); @@ -819,7 +621,7 @@ class Lexer p = end; t.loc = loc(); t.value = TOK.endOfFile; - return; + return diagnosticSet; default: if (c & 0x80) { @@ -840,7 +642,7 @@ class Lexer { t.loc = startLoc; t.value = TOK.comment; - return; + return diagnosticSet; } else if (doDocComment && t.ptr[2] == '*' && p - 4 != t.ptr) { @@ -869,7 +671,7 @@ class Lexer p = end; t.loc = startLoc; t.value = TOK.comment; - return; + return diagnosticSet; } if (doDocComment && t.ptr[2] == '/') { @@ -879,7 +681,7 @@ class Lexer p = end; t.loc = loc(); t.value = TOK.endOfFile; - return; + return diagnosticSet; default: if (c & 0x80) { @@ -897,7 +699,7 @@ class Lexer endOfLine(); t.loc = startLoc; t.value = TOK.comment; - return; + return diagnosticSet; } if (doDocComment && t.ptr[2] == '/') { @@ -950,7 +752,7 @@ class Lexer p = end; t.loc = loc(); t.value = TOK.endOfFile; - return; + return diagnosticSet; default: if (c & 0x80) { @@ -967,7 +769,7 @@ class Lexer { t.loc = startLoc; t.value = TOK.comment; - return; + return diagnosticSet; } if (doDocComment && t.ptr[2] == '+' && p - 4 != t.ptr) { @@ -981,7 +783,7 @@ class Lexer break; } t.value = TOK.div; - return; + return diagnosticSet; case '.': p++; if (isdigit(*p)) @@ -1007,7 +809,7 @@ class Lexer } else t.value = TOK.dot; - return; + return diagnosticSet; case '&': p++; if (*p == '=') @@ -1022,7 +824,7 @@ class Lexer } else t.value = TOK.and; - return; + return diagnosticSet; case '|': p++; if (*p == '=') @@ -1037,7 +839,7 @@ class Lexer } else t.value = TOK.or; - return; + return diagnosticSet; case '-': p++; if (*p == '=') @@ -1052,7 +854,7 @@ class Lexer } else t.value = TOK.min; - return; + return diagnosticSet; case '+': p++; if (*p == '=') @@ -1067,7 +869,7 @@ class Lexer } else t.value = TOK.add; - return; + return diagnosticSet; case '<': p++; if (*p == '=') @@ -1088,7 +890,7 @@ class Lexer } else t.value = TOK.lessThan; // < - return; + return diagnosticSet; case '>': p++; if (*p == '=') @@ -1120,7 +922,7 @@ class Lexer } else t.value = TOK.greaterThan; // > - return; + return diagnosticSet; case '!': p++; if (*p == '=') @@ -1130,7 +932,7 @@ class Lexer } else t.value = TOK.not; // ! - return; + return diagnosticSet; case '=': p++; if (*p == '=') @@ -1145,7 +947,7 @@ class Lexer } else t.value = TOK.assign; // = - return; + return diagnosticSet; case '~': p++; if (*p == '=') @@ -1155,7 +957,7 @@ class Lexer } else t.value = TOK.tilde; // ~ - return; + return diagnosticSet; case '^': p++; if (*p == '^') @@ -1176,55 +978,55 @@ class Lexer } else t.value = TOK.xor; // ^ - return; + return diagnosticSet; case '(': p++; t.value = TOK.leftParentheses; - return; + return diagnosticSet; case ')': p++; t.value = TOK.rightParentheses; - return; + return diagnosticSet; case '[': p++; t.value = TOK.leftBracket; - return; + return diagnosticSet; case ']': p++; t.value = TOK.rightBracket; - return; + return diagnosticSet; case '{': p++; t.value = TOK.leftCurly; - return; + return diagnosticSet; case '}': p++; t.value = TOK.rightCurly; - return; + return diagnosticSet; case '?': p++; t.value = TOK.question; - return; + return diagnosticSet; case ',': p++; t.value = TOK.comma; - return; + return diagnosticSet; case ';': p++; t.value = TOK.semicolon; - return; + return diagnosticSet; case ':': p++; t.value = TOK.colon; - return; + return diagnosticSet; case '$': p++; t.value = TOK.dollar; - return; + return diagnosticSet; case '@': p++; t.value = TOK.at; - return; + return diagnosticSet; case '*': p++; if (*p == '=') @@ -1234,7 +1036,7 @@ class Lexer } else t.value = TOK.mul; - return; + return diagnosticSet; case '%': p++; if (*p == '=') @@ -1244,12 +1046,12 @@ class Lexer } else t.value = TOK.mod; - return; + return diagnosticSet; case '#': { p++; Token n; - scan(&n); + diagnosticSet ~= scan(&n); if (n.value == TOK.identifier) { if (n.ident == Id.line) @@ -1268,7 +1070,7 @@ class Lexer error("C preprocessor directive `#if` is not supported, use `version` or `static if`"); } t.value = TOK.pound; - return; + return diagnosticSet; } default: { @@ -1295,34 +1097,39 @@ class Lexer } } } + + return diagnosticSet; } - final Token* peek(Token* ct) + final Diagnosed!(Token*) peek(Token* ct) { Token* t; + DiagnosticSet set; if (ct.next) t = ct.next; else { t = allocateToken(); - scan(t); + set = scan(t); ct.next = t; } - return t; + return diagnosed(t, set); } /********************************* * tk is on the opening (. * Look ahead and return token that is past the closing ). */ - final Token* peekPastParen(Token* tk) + final Diagnosed!(Token*) peekPastParen(Token* tk) { //printf("peekPastParen()\n"); int parens = 1; int curlynest = 0; + DiagnosticSet set; + while (1) { - tk = peek(tk); + tk = peek(tk).unwrap!(s => set ~= s); //tk.print(); switch (tk.value) { @@ -1333,7 +1140,7 @@ class Lexer --parens; if (parens) continue; - tk = peek(tk); + tk = peek(tk).unwrap!(s => set ~= s); break; case TOK.leftCurly: curlynest++; @@ -1351,7 +1158,7 @@ class Lexer default: continue; } - return tk; + return diagnosed(tk, set); } } @@ -1360,7 +1167,8 @@ class Lexer */ private uint escapeSequence() { - return Lexer.escapeSequence(token.loc, diagnosticReporter, p); + return Lexer.escapeSequence(token.loc, p) + .unwrap!(set => diagnosticSet ~= set); } /** @@ -1373,13 +1181,15 @@ class Lexer Returns: the escaped sequence as a single character */ - private static dchar escapeSequence(const ref Loc loc, DiagnosticReporter handler, ref const(char)* sequence) - in - { - assert(handler !is null); - } - body + private static Diagnosed!dchar escapeSequence(const ref Loc loc, ref const(char)* sequence) { + DiagnosticSet diagnosticSet; + + void error(Args...)(const ref Loc loc, string format, Args args) + { + diagnosticSet ~= new FormattedDiagnostic!(Args)(loc, Severity.error, format, args); + } + const(char)* p = sequence; // cache sequence reference on stack scope(exit) sequence = p; @@ -1444,20 +1254,20 @@ class Lexer break; if (!ishex(cast(char)c)) { - handler.error(loc, "escape hex sequence has %d hex digits instead of %d", n, ndigits); + error(loc, "escape hex sequence has %d hex digits instead of %d", n, ndigits); break; } } if (ndigits != 2 && !utf_isValidDchar(v)) { - handler.error(loc, "invalid UTF character \\U%08x", v); + error(loc, "invalid UTF character \\U%08x", v); v = '?'; // recover with valid UTF character } c = v; } else { - handler.error(loc, "undefined escape hex sequence \\%c%c", sequence[0], c); + error(loc, "undefined escape hex sequence \\%c%c", sequence[0], c); p++; } break; @@ -1471,7 +1281,7 @@ class Lexer c = HtmlNamedEntity(idstart, p - idstart); if (c == ~0) { - handler.error(loc, "unnamed character entity &%.*s;", cast(int)(p - idstart), idstart); + error(loc, "unnamed character entity &%.*s;", cast(int)(p - idstart), idstart); c = '?'; } p++; @@ -1479,7 +1289,7 @@ class Lexer default: if (isalpha(*p) || (p != idstart && isdigit(*p))) continue; - handler.error(loc, "unterminated named entity &%.*s;", cast(int)(p - idstart + 1), idstart); + error(loc, "unterminated named entity &%.*s;", cast(int)(p - idstart + 1), idstart); c = '?'; break; } @@ -1504,16 +1314,16 @@ class Lexer while (++n < 3 && isoctal(cast(char)c)); c = v; if (c > 0xFF) - handler.error(loc, "escape octal sequence \\%03o is larger than \\377", c); + error(loc, "escape octal sequence \\%03o is larger than \\377", c); } else { - handler.error(loc, "undefined escape sequence \\%c", c); + error(loc, "undefined escape sequence \\%c", c); p++; } break; } - return c; + return diagnosed(cast(dchar) c, diagnosticSet); } /** @@ -1742,7 +1552,7 @@ class Lexer // Start of identifier; must be a heredoc Token tok; p--; - scan(&tok); // read in heredoc identifier + diagnosticSet ~= scan(&tok); // read in heredoc identifier if (tok.value != TOK.identifier) { error("identifier expected for heredoc, not %s", tok.toChars()); @@ -1790,7 +1600,7 @@ class Lexer Token tok; auto psave = p; p--; - scan(&tok); // read in possible heredoc identifier + diagnosticSet ~= scan(&tok); // read in possible heredoc identifier //printf("endid = '%s'\n", tok.ident.toChars()); if (tok.value == TOK.identifier && tok.ident.equals(hereid)) { @@ -1836,7 +1646,7 @@ class Lexer while (1) { Token tok; - scan(&tok); + diagnosticSet ~= scan(&tok); switch (tok.value) { case TOK.leftCurly: @@ -2484,68 +2294,50 @@ class Lexer return scanloc; } - final void error(const(char)* format, ...) + void error(Args...)(string format, Args args) pure nothrow @safe { - va_list args; - va_start(args, format); - diagnosticReporter.error(token.loc, format, args); - va_end(args); + error(token.loc, format, args); } - final void error(const ref Loc loc, const(char)* format, ...) + void error(Args...)(const ref Loc loc, string format, Args args) pure nothrow @safe { - va_list args; - va_start(args, format); - diagnosticReporter.error(loc, format, args); - va_end(args); + diagnosticSet ~= new FormattedDiagnostic!(Args)(loc, Severity.error, format, args); } - final void errorSupplemental(const ref Loc loc, const(char)* format, ...) + void errorSupplemental(Args...)(const ref Loc loc, string format, Args args) pure nothrow @safe { - va_list args; - va_start(args, format); - diagnosticReporter.errorSupplemental(loc, format, args); - va_end(args); + diagnosticSet.addSupplemental( + new FormattedDiagnostic!(Args)(loc, Severity.error, format, args) + ); } - final void warning(const ref Loc loc, const(char)* format, ...) + void warning(Args...)(const ref Loc loc, string format, Args args) pure nothrow @safe { - va_list args; - va_start(args, format); - diagnosticReporter.warning(loc, format, args); - va_end(args); + diagnosticSet ~= new FormattedDiagnostic!(Args)(loc, Severity.warning, format, args); } - final void warningSupplemental(const ref Loc loc, const(char)* format, ...) + void warningSupplemental(Args...)(const ref Loc loc, string format, Args args) pure nothrow @safe { - va_list args; - va_start(args, format); - diagnosticReporter.warningSupplemental(loc, format, args); - va_end(args); + diagnosticSet.addSupplemental( + new FormattedDiagnostic!(Args)(loc, Severity.warning, format, args) + ); } - final void deprecation(const(char)* format, ...) + void deprecation(Args...)(string format, Args args) pure nothrow @safe { - va_list args; - va_start(args, format); - diagnosticReporter.deprecation(token.loc, format, args); - va_end(args); + deprecation(token.loc, format, args); } - final void deprecation(const ref Loc loc, const(char)* format, ...) + void deprecation(Args...)(const ref Loc loc, string format, Args args) pure nothrow @safe { - va_list args; - va_start(args, format); - diagnosticReporter.deprecation(loc, format, args); - va_end(args); + diagnosticSet ~= new FormattedDiagnostic!(Args)(loc, Severity.deprecation, format, args); } - final void deprecationSupplemental(const ref Loc loc, const(char)* format, ...) + void deprecationSupplemental(Args...)(const ref Loc loc, string format, Args args) pure nothrow @safe { - va_list args; - va_start(args, format); - diagnosticReporter.deprecationSupplemental(loc, format, args); - va_end(args); + diagnosticSet.addSupplemental( + new FormattedDiagnostic!(Args)(loc, Severity.deprecation, format, args) + ); } /********************************************* @@ -2559,7 +2351,7 @@ class Lexer const(char)* filespec = null; const loc = this.loc(); Token tok; - scan(&tok); + diagnosticSet ~= scan(&tok); if (tok.value == TOK.int32Literal || tok.value == TOK.int64Literal) { const lin = cast(int)(tok.unsvalue - 1); @@ -2869,23 +2661,12 @@ private: unittest { - static final class AssertDiagnosticReporter : DiagnosticReporter - { - override int errorCount() { assert(0); } - override int warningCount() { assert(0); } - override int deprecationCount() { assert(0); } - override void error(const ref Loc, const(char)*, va_list) { assert(0); } - override void errorSupplemental(const ref Loc, const(char)*, va_list) { assert(0); } - override void warning(const ref Loc, const(char)*, va_list) { assert(0); } - override void warningSupplemental(const ref Loc, const(char)*, va_list) { assert(0); } - override void deprecation(const ref Loc, const(char)*, va_list) { assert(0); } - override void deprecationSupplemental(const ref Loc, const(char)*, va_list) { assert(0); } - } static void test(T)(string sequence, T expected) { - scope assertOnError = new AssertDiagnosticReporter(); auto p = cast(const(char)*)sequence.ptr; - assert(expected == Lexer.escapeSequence(Loc.initial, assertOnError, p)); + auto diagnosed = Lexer.escapeSequence(Loc.initial, p); + assert(expected == diagnosed.value); + assert(diagnosed.diagnosticSet.empty); assert(p == sequence.ptr + sequence.length); } @@ -2924,36 +2705,13 @@ unittest } unittest { - static final class ExpectDiagnosticReporter : DiagnosticReporter - { - string expected; - bool gotError; - this(string expected) { this.expected = expected; } - - override int errorCount() { assert(0); } - override int warningCount() { assert(0); } - override int deprecationCount() { assert(0); } - - override void error(const ref Loc loc, const(char)* format, va_list args) - { - gotError = true; - char[100] buffer; - auto actual = buffer[0 .. vsprintf(buffer.ptr, format, args)]; - assert(expected == actual); - } - - override void errorSupplemental(const ref Loc, const(char)*, va_list) { assert(0); } - override void warning(const ref Loc, const(char)*, va_list) { assert(0); } - override void warningSupplemental(const ref Loc, const(char)*, va_list) { assert(0); } - override void deprecation(const ref Loc, const(char)*, va_list) { assert(0); } - override void deprecationSupplemental(const ref Loc, const(char)*, va_list) { assert(0); } - } static void test(string sequence, string expectedError, dchar expectedReturnValue, uint expectedScanLength) { - scope handler = new ExpectDiagnosticReporter(expectedError); auto p = cast(const(char)*)sequence.ptr; - auto actualReturnValue = Lexer.escapeSequence(Loc.initial, handler, p); - assert(handler.gotError); + auto diagnosed = Lexer.escapeSequence(Loc.initial, p); + auto actualReturnValue = diagnosed.value; + assert(diagnosed.diagnosticSet.length); + assert(diagnosed.diagnosticSet.front.message == expectedError); assert(expectedReturnValue == actualReturnValue); auto actualScanLength = p - sequence.ptr; diff --git a/src/dmd/mars.d b/src/dmd/mars.d index 3de3ba1f478c..3fa37daeb9ea 100644 --- a/src/dmd/mars.d +++ b/src/dmd/mars.d @@ -1573,11 +1573,11 @@ bool parseCommandLine(const ref Strings arguments, const size_t argc, ref Param if (arg == "-allinst") // https://dlang.org/dmd.html#switch-allinst params.allInst = true; else if (arg == "-de") // https://dlang.org/dmd.html#switch-de - params.useDeprecated = Diagnostic.error; + params.useDeprecated = DiagnosticReporting.error; else if (arg == "-d") // https://dlang.org/dmd.html#switch-d - params.useDeprecated = Diagnostic.off; + params.useDeprecated = DiagnosticReporting.off; else if (arg == "-dw") // https://dlang.org/dmd.html#switch-dw - params.useDeprecated = Diagnostic.inform; + params.useDeprecated = DiagnosticReporting.inform; else if (arg == "-c") // https://dlang.org/dmd.html#switch-c params.link = false; else if (startsWith(p + 1, "checkaction")) // https://dlang.org/dmd.html#switch-checkaction @@ -2009,9 +2009,9 @@ bool parseCommandLine(const ref Strings arguments, const size_t argc, ref Param params.useDIP25 = false; } else if (arg == "-w") // https://dlang.org/dmd.html#switch-w - params.warnings = Diagnostic.error; + params.warnings = DiagnosticReporting.error; else if (arg == "-wi") // https://dlang.org/dmd.html#switch-wi - params.warnings = Diagnostic.inform; + params.warnings = DiagnosticReporting.inform; else if (arg == "-O") // https://dlang.org/dmd.html#switch-O params.optimize = true; else if (p[1] == 'o') diff --git a/src/dmd/parse.d b/src/dmd/parse.d index c0a7c3d0178e..ea6fe4d4add8 100644 --- a/src/dmd/parse.d +++ b/src/dmd/parse.d @@ -278,6 +278,7 @@ final class Parser(AST) : Lexer Loc endloc; // set to location of last right curly int inBrackets; // inside [] of array index or slice Loc lookingForElse; // location of lonely if looking for an else + DiagnosticReporter diagnosticReporter; } /********************* @@ -288,9 +289,10 @@ final class Parser(AST) : Lexer extern (D) this(const ref Loc loc, AST.Module _module, const(char)[] input, bool doDocComment, DiagnosticReporter diagnosticReporter) { - super(_module ? _module.srcfile.toChars() : null, input.ptr, 0, input.length, doDocComment, false, diagnosticReporter); + super(_module ? _module.srcfile.toChars() : null, input.ptr, 0, input.length, doDocComment, false); //printf("Parser::Parser()\n"); + this.diagnosticReporter = diagnosticReporter; scanloc = loc; if (!writeMixin(input, scanloc) && loc.filename) @@ -310,16 +312,60 @@ final class Parser(AST) : Lexer extern (D) this(AST.Module _module, const(char)[] input, bool doDocComment, DiagnosticReporter diagnosticReporter) { - super(_module ? _module.srcfile.toChars() : null, input.ptr, 0, input.length, doDocComment, false, diagnosticReporter); + super(_module ? _module.srcfile.toChars() : null, input.ptr, 0, input.length, doDocComment, false); //printf("Parser::Parser()\n"); + this.diagnosticReporter = diagnosticReporter; mod = _module; linkage = LINK.d; //nextToken(); // start up the scanner } + private void printDiagnostics(ref DiagnosticSet set) + { + scope (exit) + set = DiagnosticSet(); + + .printDiagnostics(set, diagnosticReporter); + } + + private auto forwardDiagnosedFunction(T)(lazy T value) + { + auto diagnosed = value; + printDiagnostics(diagnosed.diagnosticSet); + return diagnosed.value; + } + + TOK nextToken() + { + return forwardDiagnosedFunction(super.nextToken); + } + + TOK peekNext() + { + return forwardDiagnosedFunction(super.peekNext); + } + + TOK peekNext2() + { + return forwardDiagnosedFunction(super.peekNext2); + } + + Token* peek(Token* ct) + { + return forwardDiagnosedFunction(super.peek(ct)); + } + + Token* peekPastParen(Token* tk) + { + return forwardDiagnosedFunction(super.peekPastParen(tk)); + } + AST.Dsymbols* parseModule() { + scope (exit) + printDiagnostics(diagnosticSet); + const comment = token.blockComment; bool isdeprecated = false; AST.Expression msg = null; @@ -462,6 +508,9 @@ final class Parser(AST) : Lexer AST.Dsymbols* parseDeclDefs(int once, AST.Dsymbol* pLastDecl = null, PrefixAttributes!AST* pAttrs = null) { + scope (exit) + printDiagnostics(diagnosticSet); + AST.Dsymbol lastDecl = null; // used to link unittest to its previous declaration if (!pLastDecl) pLastDecl = &lastDecl; @@ -5345,6 +5394,9 @@ final class Parser(AST) : Lexer */ AST.Statement parseStatement(int flags, const(char)** endPtr = null, Loc* pEndloc = null) { + scope (exit) + printDiagnostics(diagnosticSet); + AST.Statement s; AST.Condition cond; AST.Statement ifbody; @@ -6678,6 +6730,9 @@ final class Parser(AST) : Lexer void check(TOK value) { + scope (exit) + printDiagnostics(diagnosticSet); + check(token.loc, value); } @@ -7532,6 +7587,9 @@ final class Parser(AST) : Lexer AST.Expression parseExpression() { + scope (exit) + printDiagnostics(diagnosticSet); + auto loc = token.loc; //printf("Parser::parseExpression() loc = %d\n", loc.linnum); @@ -7550,6 +7608,9 @@ final class Parser(AST) : Lexer AST.Expression parsePrimaryExp() { + scope (exit) + printDiagnostics(diagnosticSet); + AST.Expression e; AST.Type t; Identifier id; @@ -8756,6 +8817,9 @@ final class Parser(AST) : Lexer AST.Expression parseAssignExp() { + scope (exit) + printDiagnostics(diagnosticSet); + AST.Expression e; e = parseCondExp(); if (e is null) diff --git a/src/dmd/semantic3.d b/src/dmd/semantic3.d index dedfd6c858a2..0bc6b1870d5e 100644 --- a/src/dmd/semantic3.d +++ b/src/dmd/semantic3.d @@ -1384,7 +1384,7 @@ private extern(C++) final class Semantic3Visitor : Visitor // don't do it for unused deprecated types // or error ypes - if (!ad.getRTInfo && Type.rtinfo && (!ad.isDeprecated() || global.params.useDeprecated != Diagnostic.error) && (ad.type && ad.type.ty != Terror)) + if (!ad.getRTInfo && Type.rtinfo && (!ad.isDeprecated() || global.params.useDeprecated != DiagnosticReporting.error) && (ad.type && ad.type.ty != Terror)) { // Evaluate: RTinfo!type auto tiargs = new Objects(); diff --git a/src/dmd/sideeffect.d b/src/dmd/sideeffect.d index 98108ca223c4..f9e321512e9b 100644 --- a/src/dmd/sideeffect.d +++ b/src/dmd/sideeffect.d @@ -251,7 +251,7 @@ bool discardValue(Expression e) } case TOK.call: /* Issue 3882: */ - if (global.params.warnings != Diagnostic.off && !global.gag) + if (global.params.warnings != DiagnosticReporting.off && !global.gag) { CallExp ce = cast(CallExp)e; if (e.type.ty == Tvoid) diff --git a/test/unit/lexer/diagnostic_reporter.d b/test/unit/lexer/diagnostic_reporter.d index 0a9a91db8e94..df1b46cbc50b 100644 --- a/test/unit/lexer/diagnostic_reporter.d +++ b/test/unit/lexer/diagnostic_reporter.d @@ -2,8 +2,8 @@ module lexer.diagnostic_reporter; import core.stdc.stdarg; +import dmd.errors : DiagnosticReporter; import dmd.globals : Loc; -import dmd.lexer : DiagnosticReporter; import support : afterEach, NoopDiagnosticReporter; @@ -72,11 +72,13 @@ unittest private void lexUntilEndOfFile(string code, DiagnosticReporter reporter) { + import dmd.errors : printDiagnostics, unwrap; import dmd.lexer : Lexer; import dmd.tokens : TOK; - scope lexer = new Lexer("test", code.ptr, 0, code.length, 0, 0, reporter); - lexer.nextToken; + alias printDiags = set => set.printDiagnostics(reporter); + scope lexer = new Lexer("test", code.ptr, 0, code.length, 0, 0); + lexer.nextToken.unwrap!printDiags; - while (lexer.nextToken != TOK.endOfFile) {} + while (lexer.nextToken.unwrap!printDiags != TOK.endOfFile) {} } diff --git a/test/unit/support.d b/test/unit/support.d index 857495563f7a..f99fc1c39c5d 100644 --- a/test/unit/support.d +++ b/test/unit/support.d @@ -1,6 +1,6 @@ module support; -import dmd.lexer : DiagnosticReporter; +import dmd.errors : DiagnosticReporter; /// UDA used to indicate a function should be run before each test. enum beforeEach;