diff --git a/compiler/src/build.d b/compiler/src/build.d index dcb6b80e5f80..63a38205ce1e 100755 --- a/compiler/src/build.d +++ b/compiler/src/build.d @@ -1576,7 +1576,7 @@ auto sourceFiles() statement.h staticassert.h target.h template.h tokens.h version.h visitor.h "), lexer: fileArray(env["D"], " - console.d entity.d errors.d file_manager.d globals.d id.d identifier.d lexer.d location.d tokens.d + console.d entity.d errors.d errorsink.d file_manager.d globals.d id.d identifier.d lexer.d location.d tokens.d ") ~ fileArray(env["ROOT"], " array.d bitarray.d ctfloat.d file.d filename.d hash.d port.d region.d rmem.d rootobject.d stringtable.d utf.d diff --git a/compiler/src/dmd/README.md b/compiler/src/dmd/README.md index 43eb187c735b..cecd008e608b 100644 --- a/compiler/src/dmd/README.md +++ b/compiler/src/dmd/README.md @@ -38,7 +38,8 @@ Note that these groups have no strict meaning, the category assignments are a bi | [dinifile.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dinifile.d) | Parse settings from .ini file (`sc.ini` / `dmd.conf`) | | [vsoptions.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/vsoptions.d) | Detect the Microsoft Visual Studio toolchain for linking | | [frontend.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/frontend.d) | An interface for using DMD as a library | -| [errors.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/errors.d) | Error reporting functionality | +| [errors.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/errors.d) | Error reporting implementation | +| [errorsink.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/errorsink.d) | Error reporting interface | | [target.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/target.d) | Manage target-specific parameters for cross-compiling (for LDC/GDC) | | [compiler.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/compiler.d) | Describe a back-end compiler and implements compiler-specific actions | diff --git a/compiler/src/dmd/cparse.d b/compiler/src/dmd/cparse.d index 57ca35503090..a18f810372df 100644 --- a/compiler/src/dmd/cparse.d +++ b/compiler/src/dmd/cparse.d @@ -16,6 +16,7 @@ module dmd.cparse; import core.stdc.stdio; import core.stdc.string; import dmd.astenums; +import dmd.errorsink; import dmd.globals; import dmd.id; import dmd.identifier; @@ -69,9 +70,10 @@ final class CParser(AST) : Parser!AST OutBuffer* defines; extern (D) this(TARGET)(AST.Module _module, const(char)[] input, bool doDocComment, + ErrorSink errorSink, const ref TARGET target, OutBuffer* defines) scope { - super(_module, input, doDocComment); + super(_module, input, doDocComment, errorSink); //printf("CParser.this()\n"); mod = _module; @@ -273,7 +275,7 @@ final class CParser(AST) : Parser!AST auto exp = cparseExpression(); if (token.value == TOK.identifier && exp.op == EXP.identifier) { - error("found `%s` when expecting `;` or `=`, did you mean `%s %s = %s`?", peek(&token).toChars(), exp.toChars(), token.toChars(), peek(peek(&token)).toChars()); + error(token.loc, "found `%s` when expecting `;` or `=`, did you mean `%s %s = %s`?", peek(&token).toChars(), exp.toChars(), token.toChars(), peek(peek(&token)).toChars()); nextToken(); } else @@ -754,7 +756,7 @@ final class CParser(AST) : Parser!AST if (token.postfix) { if (token.postfix != postfix) - error("mismatched string literal postfixes `'%c'` and `'%c'`", postfix, token.postfix); + error(token.loc, "mismatched string literal postfixes `'%c'` and `'%c'`", postfix, token.postfix); postfix = token.postfix; } @@ -1948,7 +1950,7 @@ final class CParser(AST) : Parser!AST case TOK.identifier: if (s) { - error("missing comma or semicolon after declaration of `%s`, found `%s` instead", s.toChars(), token.toChars()); + error(token.loc, "missing comma or semicolon after declaration of `%s`, found `%s` instead", s.toChars(), token.toChars()); goto Lend; } goto default; @@ -2014,7 +2016,7 @@ final class CParser(AST) : Parser!AST importBuiltins = true; // will need __va_list_tag auto plLength = pl.length; if (symbols.length != plLength) - error("%d identifiers does not match %d declarations", cast(int)plLength, cast(int)symbols.length); + error(token.loc, "%d identifiers does not match %d declarations", cast(int)plLength, cast(int)symbols.length); /* Transfer the types and storage classes from symbols[] to pl[] */ @@ -5154,9 +5156,9 @@ final class CParser(AST) : Parser!AST if (n.value == TOK.identifier && n.ident == Id.show) { if (packalign.isDefault()) - warning(startloc, "current pack attribute is default"); + eSink.warning(startloc, "current pack attribute is default"); else - warning(startloc, "current pack attribute is %d", packalign.get()); + eSink.warning(startloc, "current pack attribute is %d", packalign.get()); scan(&n); return closingParen(); } diff --git a/compiler/src/dmd/dmodule.d b/compiler/src/dmd/dmodule.d index bb518fa081d3..a5f7cd321da5 100644 --- a/compiler/src/dmd/dmodule.d +++ b/compiler/src/dmd/dmodule.d @@ -29,6 +29,7 @@ import dmd.dscope; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.errors; +import dmd.errorsink; import dmd.expression; import dmd.expressionsem; import dmd.file_manager; @@ -766,7 +767,7 @@ extern (C++) final class Module : Package { filetype = FileType.c; - scope p = new CParser!AST(this, buf, cast(bool) docfile, target.c, &defines); + scope p = new CParser!AST(this, buf, cast(bool) docfile, global.errorSink, target.c, &defines); p.nextToken(); checkCompiledImport(); members = p.parseModule(); @@ -775,7 +776,7 @@ extern (C++) final class Module : Package } else { - scope p = new Parser!AST(this, buf, cast(bool) docfile); + scope p = new Parser!AST(this, buf, cast(bool) docfile, global.errorSink); p.nextToken(); p.parseModuleDeclaration(); md = p.md; @@ -1382,7 +1383,7 @@ extern (C++) struct ModuleDeclaration * for inclusion in ModuleInfo * Params: * mod = the Module - * aclasses = array to fill in + * aclasses = array to fill in * Returns: array of local classes */ extern (C++) void getLocalClasses(Module mod, ref ClassDeclarations aclasses) diff --git a/compiler/src/dmd/doc.d b/compiler/src/dmd/doc.d index 155406f99195..88e8996ae3aa 100644 --- a/compiler/src/dmd/doc.d +++ b/compiler/src/dmd/doc.d @@ -5183,6 +5183,7 @@ private void highlightCode2(Scope* sc, Dsymbols* a, ref OutBuffer buf, size_t of uint errorsave = global.startGagging(); scope Lexer lex = new Lexer(null, cast(char*)buf[].ptr, 0, buf.length - 1, 0, 1, + global.errorSink, global.vendor, global.versionNumber()); OutBuffer res; const(char)* lastp = cast(char*)buf[].ptr; diff --git a/compiler/src/dmd/dsymbolsem.d b/compiler/src/dmd/dsymbolsem.d index eb60cc670044..cc09fb072296 100644 --- a/compiler/src/dmd/dsymbolsem.d +++ b/compiler/src/dmd/dsymbolsem.d @@ -1917,7 +1917,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor const len = buf.length; buf.writeByte(0); const str = buf.extractSlice()[0 .. len]; - scope p = new Parser!ASTCodegen(cd.loc, sc._module, str, false); + scope p = new Parser!ASTCodegen(cd.loc, sc._module, str, false, global.errorSink); p.nextToken(); auto d = p.parseDeclDefs(0); diff --git a/compiler/src/dmd/dtemplate.d b/compiler/src/dmd/dtemplate.d index df76d28a0b22..ad3a6d4dd54f 100644 --- a/compiler/src/dmd/dtemplate.d +++ b/compiler/src/dmd/dtemplate.d @@ -7561,7 +7561,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol //printf("\t staticIfDg on '%s %s' in '%s'\n", s.kind(), s.toChars(), this.toChars()); if (!s.isStaticIfDeclaration()) { - //s.dsymbolSemantic(sc2); + //s.dsymbolSemantic(sc2); done = true; return; } diff --git a/compiler/src/dmd/errors.d b/compiler/src/dmd/errors.d index b9a533565d8d..05b884c280e2 100644 --- a/compiler/src/dmd/errors.d +++ b/compiler/src/dmd/errors.d @@ -15,6 +15,7 @@ import core.stdc.stdarg; import core.stdc.stdio; import core.stdc.stdlib; import core.stdc.string; +import dmd.errorsink; import dmd.globals; import dmd.location; import dmd.common.outbuffer; @@ -24,6 +25,57 @@ import dmd.console; nothrow: +/*************************** + * Error message sink for D compiler. + */ +class ErrorSinkCompiler : ErrorSink +{ + nothrow: + extern (C++): + override: + + void error(const ref Loc loc, const(char)* format, ...) + { + va_list ap; + va_start(ap, format); + verror(loc, format, ap); + va_end(ap); + } + + void errorSupplemental(const ref Loc loc, const(char)* format, ...) + { + va_list ap; + va_start(ap, format); + verrorSupplemental(loc, format, ap); + va_end(ap); + } + + void warning(const ref Loc loc, const(char)* format, ...) + { + va_list ap; + va_start(ap, format); + vwarning(loc, format, ap); + va_end(ap); + } + + void deprecation(const ref Loc loc, const(char)* format, ...) + { + va_list ap; + va_start(ap, format); + vdeprecation(loc, format, ap); + va_end(ap); + } + + void deprecationSupplemental(const ref Loc loc, const(char)* format, ...) + { + va_list ap; + va_start(ap, format); + vdeprecationSupplemental(loc, format, ap); + va_end(ap); + } +} + + /** * Color highlighting to classify messages */ @@ -768,7 +820,7 @@ private void colorHighlightCode(ref OutBuffer buf) ++nested; auto gaggedErrorsSave = global.startGagging(); - scope Lexer lex = new Lexer(null, cast(char*)buf[].ptr, 0, buf.length - 1, 0, 1, global.vendor, global.versionNumber()); + scope Lexer lex = new Lexer(null, cast(char*)buf[].ptr, 0, buf.length - 1, 0, 1, global.errorSink, global.vendor, global.versionNumber()); OutBuffer res; const(char)* lastp = cast(char*)buf[].ptr; //printf("colorHighlightCode('%.*s')\n", cast(int)(buf.length - 1), buf[].ptr); diff --git a/compiler/src/dmd/errorsink.d b/compiler/src/dmd/errorsink.d new file mode 100644 index 000000000000..b519db7e9bc0 --- /dev/null +++ b/compiler/src/dmd/errorsink.d @@ -0,0 +1,121 @@ +/** + * Provides an abstraction for what to do with error messages. + * + * Copyright: Copyright (C) 2023 by The D Language Foundation, All Rights Reserved + * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) + * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) + * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/errorsink.d, _errorsink.d) + * Documentation: https://dlang.org/phobos/dmd_errorsink.html + * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/errorsink.d + */ + +module dmd.errorsink; + +import dmd.location; + +/*************************************** + * Where error/warning/deprecation messages go. + */ +abstract class ErrorSink +{ + nothrow: + extern (C++): + + void error(const ref Loc loc, const(char)* format, ...); + + void errorSupplemental(const ref Loc loc, const(char)* format, ...); + + void warning(const ref Loc loc, const(char)* format, ...); + + void deprecation(const ref Loc loc, const(char)* format, ...); + + void deprecationSupplemental(const ref Loc loc, const(char)* format, ...); +} + +/***************************************** + * Just ignores the messages. + */ +class ErrorSinkNull : ErrorSink +{ + nothrow: + extern (C++): + override: + + void error(const ref Loc loc, const(char)* format, ...) { } + + void errorSupplemental(const ref Loc loc, const(char)* format, ...) { } + + void warning(const ref Loc loc, const(char)* format, ...) { } + + void deprecation(const ref Loc loc, const(char)* format, ...) { } + + void deprecationSupplemental(const ref Loc loc, const(char)* format, ...) { } +} + +/***************************************** + * Simplest implementation, just sends messages to stderr. + */ +class ErrorSinkStderr : ErrorSink +{ + import core.stdc.stdio; + import core.stdc.stdarg; + + nothrow: + extern (C++): + override: + + void error(const ref Loc loc, const(char)* format, ...) + { + fputs("Error: ", stderr); + const p = loc.toChars(); + if (*p) + { + fprintf(stderr, "%s: ", p); + //mem.xfree(cast(void*)p); // loc should provide the free() + } + + va_list ap; + va_start(ap, format); + vfprintf(stderr, format, ap); + fputc('\n', stderr); + va_end(ap); + } + + void errorSupplemental(const ref Loc loc, const(char)* format, ...) { } + + void warning(const ref Loc loc, const(char)* format, ...) + { + fputs("Warning: ", stderr); + const p = loc.toChars(); + if (*p) + { + fprintf(stderr, "%s: ", p); + //mem.xfree(cast(void*)p); // loc should provide the free() + } + + va_list ap; + va_start(ap, format); + vfprintf(stderr, format, ap); + fputc('\n', stderr); + va_end(ap); + } + + void deprecation(const ref Loc loc, const(char)* format, ...) + { + fputs("Deprecation: ", stderr); + const p = loc.toChars(); + if (*p) + { + fprintf(stderr, "%s: ", p); + //mem.xfree(cast(void*)p); // loc should provide the free() + } + + va_list ap; + va_start(ap, format); + vfprintf(stderr, format, ap); + fputc('\n', stderr); + va_end(ap); + } + + void deprecationSupplemental(const ref Loc loc, const(char)* format, ...) { } +} diff --git a/compiler/src/dmd/expressionsem.d b/compiler/src/dmd/expressionsem.d index 14ba676b8a1c..c805b06173a5 100644 --- a/compiler/src/dmd/expressionsem.d +++ b/compiler/src/dmd/expressionsem.d @@ -6101,7 +6101,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor uint errors = global.errors; const len = buf.length; const str = buf.extractChars()[0 .. len]; - scope p = new Parser!ASTCodegen(exp.loc, sc._module, str, false); + scope p = new Parser!ASTCodegen(exp.loc, sc._module, str, false, global.errorSink); p.nextToken(); //printf("p.loc.linnum = %d\n", p.loc.linnum); diff --git a/compiler/src/dmd/frontend.h b/compiler/src/dmd/frontend.h index 80caadb00914..99522b6b29ed 100644 --- a/compiler/src/dmd/frontend.h +++ b/compiler/src/dmd/frontend.h @@ -307,6 +307,7 @@ class ArrayInitializer; class ExpInitializer; class CInitializer; class FileManager; +class ErrorSink; class ErrorStatement; class ExpStatement; class ConditionalStatement; @@ -3382,6 +3383,7 @@ struct Global final FileManager* fileManager; enum : int32_t { recursionLimit = 500 }; + ErrorSink* errorSink; FileName(*preprocess)(FileName , const Loc& , bool& , OutBuffer* ); uint32_t startGagging(); bool endGagging(uint32_t oldGagged); @@ -3408,10 +3410,11 @@ struct Global final hasMainFunction(), varSequenceNumber(1u), fileManager(), + errorSink(), preprocess() { } - Global(_d_dynamicArray< const char > inifilename, _d_dynamicArray< const char > copyright = { 73, "Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved" }, _d_dynamicArray< const char > written = { 24, "written by Walter Bright" }, Array* path = nullptr, Array* filePath = nullptr, _d_dynamicArray< const char > vendor = {}, Param params = Param(), uint32_t errors = 0u, uint32_t warnings = 0u, uint32_t gag = 0u, uint32_t gaggedErrors = 0u, uint32_t gaggedWarnings = 0u, void* console = nullptr, Array* versionids = nullptr, Array* debugids = nullptr, bool hasMainFunction = false, uint32_t varSequenceNumber = 1u, FileManager* fileManager = nullptr, FileName(*preprocess)(FileName , const Loc& , bool& , OutBuffer* ) = nullptr) : + Global(_d_dynamicArray< const char > inifilename, _d_dynamicArray< const char > copyright = { 73, "Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved" }, _d_dynamicArray< const char > written = { 24, "written by Walter Bright" }, Array* path = nullptr, Array* filePath = nullptr, _d_dynamicArray< const char > vendor = {}, Param params = Param(), uint32_t errors = 0u, uint32_t warnings = 0u, uint32_t gag = 0u, uint32_t gaggedErrors = 0u, uint32_t gaggedWarnings = 0u, void* console = nullptr, Array* versionids = nullptr, Array* debugids = nullptr, bool hasMainFunction = false, uint32_t varSequenceNumber = 1u, FileManager* fileManager = nullptr, ErrorSink* errorSink = nullptr, FileName(*preprocess)(FileName , const Loc& , bool& , OutBuffer* ) = nullptr) : inifilename(inifilename), copyright(copyright), written(written), @@ -3430,6 +3433,7 @@ struct Global final hasMainFunction(hasMainFunction), varSequenceNumber(varSequenceNumber), fileManager(fileManager), + errorSink(errorSink), preprocess(preprocess) {} }; diff --git a/compiler/src/dmd/globals.d b/compiler/src/dmd/globals.d index 407c68423c55..1919d9ae0ce1 100644 --- a/compiler/src/dmd/globals.d +++ b/compiler/src/dmd/globals.d @@ -15,6 +15,8 @@ import core.stdc.stdint; import dmd.root.array; import dmd.root.filename; import dmd.common.outbuffer; +import dmd.errorsink; +import dmd.errors; import dmd.file_manager; import dmd.identifier; import dmd.location; @@ -292,6 +294,8 @@ extern (C++) struct Global enum recursionLimit = 500; /// number of recursive template expansions before abort + ErrorSink errorSink; /// where the error messages go + extern (C++) FileName function(FileName, ref const Loc, out bool, OutBuffer*) preprocess; nothrow: @@ -346,6 +350,8 @@ extern (C++) struct Global extern (C++) void _init() { + global.errorSink = new ErrorSinkCompiler; + this.fileManager = new FileManager(); version (MARS) { diff --git a/compiler/src/dmd/globals.h b/compiler/src/dmd/globals.h index dc637f86c3ec..ec8fc32ed0f5 100644 --- a/compiler/src/dmd/globals.h +++ b/compiler/src/dmd/globals.h @@ -19,6 +19,7 @@ // Can't include arraytypes.h here, need to declare these directly. template struct Array; +class ErrorSink; class FileManager; struct Loc; @@ -278,6 +279,7 @@ struct Global unsigned varSequenceNumber; FileManager* fileManager; + ErrorSink* errorSink; // where the error messages go FileName (*preprocess)(FileName, const Loc&, bool&, OutBuffer&); diff --git a/compiler/src/dmd/iasmgcc.d b/compiler/src/dmd/iasmgcc.d index baf6b14b97d8..f8c88ab536e9 100644 --- a/compiler/src/dmd/iasmgcc.d +++ b/compiler/src/dmd/iasmgcc.d @@ -17,6 +17,7 @@ import dmd.arraytypes; import dmd.astcodegen; import dmd.dscope; import dmd.errors; +import dmd.errorsink; import dmd.expression; import dmd.expressionsem; import dmd.identifier; @@ -72,7 +73,7 @@ int parseExtAsmOperands(Parser)(Parser p, GccAsmStatement s) } else { - p.error(s.loc, "expected identifier after `[`"); + p.eSink.error(s.loc, "expected identifier after `[`"); goto Lerror; } // Look for closing `]` @@ -116,7 +117,7 @@ int parseExtAsmOperands(Parser)(Parser p, GccAsmStatement s) break; default: - p.error("expected constant string constraint for operand, not `%s`", + p.eSink.error(p.token.loc, "expected constant string constraint for operand, not `%s`", p.token.toChars()); goto Lerror; } @@ -167,7 +168,7 @@ Expressions *parseExtAsmClobbers(Parser)(Parser p) break; default: - p.error("expected constant string constraint for clobber name, not `%s`", + p.eSink.error(p.token.loc, "expected constant string constraint for clobber name, not `%s`", p.token.toChars()); goto Lerror; } @@ -214,7 +215,7 @@ Identifiers *parseExtAsmGotoLabels(Parser)(Parser p) break; default: - p.error("expected identifier for goto label name, not `%s`", + p.eSink.error(p.token.loc, "expected identifier for goto label name, not `%s`", p.token.toChars()); goto Lerror; } @@ -301,7 +302,7 @@ Ldone: extern (C++) public Statement gccAsmSemantic(GccAsmStatement s, Scope *sc) { //printf("GccAsmStatement.semantic()\n"); - scope p = new Parser!ASTCodegen(sc._module, ";", false); + scope p = new Parser!ASTCodegen(sc._module, ";", false, global.errorSink); // Make a safe copy of the token list before parsing. Token *toklist = null; @@ -384,6 +385,9 @@ unittest { import dmd.mtype : TypeBasic; + if (!global.errorSink) + global.errorSink = new ErrorSinkCompiler; + uint errors = global.startGagging(); scope(exit) global.endGagging(errors); @@ -406,7 +410,7 @@ unittest { const errors = global.errors; scope gas = new GccAsmStatement(Loc.initial, tokens); - scope p = new Parser!ASTCodegen(null, ";", false); + scope p = new Parser!ASTCodegen(null, ";", false, global.errorSink); p.token = *tokens; p.parseGccAsm(gas); return global.errors - errors; @@ -416,7 +420,7 @@ unittest static void parseAsm(string input, bool expectError) { // Generate tokens from input test. - scope p = new Parser!ASTCodegen(null, input, false); + scope p = new Parser!ASTCodegen(null, input, false, global.errorSink); p.nextToken(); Token* toklist = null; diff --git a/compiler/src/dmd/lexer.d b/compiler/src/dmd/lexer.d index 81830d7307b0..4dc4a39929ad 100644 --- a/compiler/src/dmd/lexer.d +++ b/compiler/src/dmd/lexer.d @@ -23,6 +23,7 @@ import core.stdc.time; import dmd.entity; import dmd.errors; +import dmd.errorsink; import dmd.globals; import dmd.id; import dmd.identifier; @@ -69,6 +70,8 @@ class Lexer ubyte long_doublesize; /// size of C long double, 8 or D real.sizeof ubyte wchar_tsize; /// size of C wchar_t, 2 or 4 + ErrorSink eSink; /// send error messages through this interface + private { const(char)* base; // pointer to start of buffer @@ -103,11 +106,13 @@ class Lexer * endoffset = the last offset to read into base[] * doDocComment = handle documentation comments * commentToken = comments become TOK.comment's + * errorSink = where error messages go, must not be null * vendor = name of the vendor * versionNumber = version of the caller */ this(const(char)* filename, const(char)* base, size_t begoffset, size_t endoffset, bool doDocComment, bool commentToken, + ErrorSink errorSink, const(char)[] vendor = "DLF", uint versionNumber = 1) pure scope { scanloc = Loc(filename, 1, 1); @@ -123,6 +128,8 @@ class Lexer this.tokenizeNewlines = false; this.inTokenStringConstant = 0; this.lastDocLine = 0; + this.eSink = errorSink; + assert(errorSink); this.versionNumber = versionNumber; this.vendor = vendor; //initKeywords(); @@ -163,16 +170,18 @@ class Lexer * Alternative entry point for DMDLIB, adds `whitespaceToken` */ this(const(char)* filename, const(char)* base, size_t begoffset, size_t endoffset, - bool doDocComment, bool commentToken, bool whitespaceToken) + bool doDocComment, bool commentToken, bool whitespaceToken, + ErrorSink errorSink + ) { - this(filename, base, begoffset, endoffset, doDocComment, commentToken); + this(filename, base, begoffset, endoffset, doDocComment, commentToken, errorSink); this.whitespaceToken = whitespaceToken; } /****************** * Used for unittests for a mock Lexer */ - this() scope { } + this(ErrorSink errorSink) scope { assert(errorSink); this.eSink = errorSink; } /************************************** * Reset lexer to lex #define's @@ -1616,7 +1625,7 @@ class Lexer else if (isspace(delimright)) error("delimited string must end in `\"`"); else - error("delimited string must end in `%c\"`", delimright); + error(token.loc, "delimited string must end in `%c\"`", delimright); result.setString(stringbuffer); stringPostfix(result); } @@ -1909,10 +1918,10 @@ class Lexer if (idx < n && !msg) msg = utf_decodeChar(str, idx, d2); if (msg) - error(loc, "%s", msg); + error(loc, "%.*s", cast(int)msg.length, msg.ptr); else if (idx < n) error(loc, "max number of chars in 16 bit character literal is 2, had %d", - (n + 1) >> 1); + cast(int)((n + 1) >> 1)); else if (d1 > 0x1_0000) error(loc, "%d does not fit in 16 bits", d1); else if (d2 > 0x1_0000) @@ -1927,10 +1936,10 @@ class Lexer size_t idx; auto msg = utf_decodeChar(str, idx, d); if (msg) - error(loc, "%s", msg); + error(loc, "%.*s", cast(int)msg.length, msg.ptr); else if (idx < n) error(loc, "max number of chars in 32 bit character literal is 1, had %d", - (n + 3) >> 2); + cast(int)((n + 3) >> 2)); u = d; break; @@ -2137,7 +2146,7 @@ class Lexer Ldone: if (errorDigit) { - error("%s digit expected, not `%c`", base == 2 ? "binary".ptr : + error(token.loc, "%s digit expected, not `%c`", base == 2 ? "binary".ptr : base == 8 ? "octal".ptr : "decimal".ptr, errorDigit); err = true; @@ -2149,7 +2158,7 @@ class Lexer } if ((base == 2 && !anyBinaryDigitsNoSingleUS) || (base == 16 && !anyHexDigitsNoSingleUS)) - error("`%.*s` isn't a valid integer literal, use `%.*s0` instead", cast(int)(p - start), start, 2, start); + error(token.loc, "`%.*s` isn't a valid integer literal, use `%.*s0` instead", cast(int)(p - start), start, 2, start); t.unsvalue = n; @@ -2202,7 +2211,7 @@ class Lexer // can't translate invalid octal value, just show a generic message error("octal literals larger than 7 are no longer supported"); else - error("octal literals `0%llo%.*s` are no longer supported, use `std.conv.octal!\"%llo%.*s\"` instead", + error(token.loc, "octal literals `0%llo%.*s` are no longer supported, use `std.conv.octal!\"%llo%.*s\"` instead", n, cast(int)(p - psuffix), psuffix, n, cast(int)(p - psuffix), psuffix); } TOK result; @@ -2619,7 +2628,7 @@ class Lexer TOK.float80Literal: "`real` for the current target".ptr][result]; error(scanloc, "number `%s%s` is not representable as a %s", sbufptr, suffix, type); const char* extra = result == TOK.float64Literal ? "`real` literals can be written using the `L` suffix. " : ""; - errorSupplemental(scanloc, "%shttps://dlang.org/spec/lex.html#floatliteral", extra); + eSink.errorSupplemental(scanloc, "%shttps://dlang.org/spec/lex.html#floatliteral", extra); } debug { @@ -2647,28 +2656,24 @@ class Lexer return scanloc; } - final void error(const(char)* format, ...) + void error(T...)(const(char)* format, T args) + { + eSink.error(token.loc, format, args); + } + + void error(T...)(const ref Loc loc, const(char)* format, T args) { - va_list args; - va_start(args, format); - .verror(token.loc, format, args); - va_end(args); + eSink.error(loc, format, args); } - final void error(const ref Loc loc, const(char)* format, ...) + final void deprecation(const(char)* format) { - va_list args; - va_start(args, format); - .verror(loc, format, args); - va_end(args); + eSink.deprecation(token.loc, format); } - final void deprecation(const(char)* format, ...) + final void deprecationSupplemental(const(char)* format) { - va_list args; - va_start(args, format); - .vdeprecation(token.loc, format, args); - va_end(args); + eSink.deprecationSupplemental(token.loc, format); } /*************************************** @@ -2692,7 +2697,7 @@ class Lexer else { const locx = loc(); - warning(locx, "C preprocessor directive `#%s` is not supported", n.ident.toChars()); + eSink.warning(locx, "C preprocessor directive `#%s` is not supported", n.ident.toChars()); } } else if (n.value == TOK.if_) @@ -2853,7 +2858,7 @@ class Lexer auto result = decodeUTFpure(msg); if (msg) - error("%.*s", cast(int)msg.length, msg.ptr); + error(token.loc, "%.*s", cast(int)msg.length, msg.ptr); return result; } @@ -3217,6 +3222,7 @@ private bool c_isalnum(const int c) pure @nogc @safe unittest { + fprintf(stderr, "Lexer.unittest %d\n", __LINE__); import dmd.console; nothrow bool assertDiagnosticHandler(const ref Loc loc, Color headerColor, const(char)* header, const(char)* format, va_list ap, const(char)* p1, const(char)* p2) @@ -3225,11 +3231,14 @@ unittest } diagnosticHandler = &assertDiagnosticHandler; + if (!global.errorSink) + global.errorSink = new ErrorSinkCompiler; + static void test(T)(string sequence, T expected, bool Ccompile = false) { auto p = cast(const(char)*)sequence.ptr; dchar c2; - Lexer lexer = new Lexer(); + Lexer lexer = new Lexer(global.errorSink); assert(expected == lexer.escapeSequence(Loc.initial, p, Ccompile, c2)); assert(p == sequence.ptr + sequence.length); } @@ -3272,6 +3281,7 @@ unittest unittest { + fprintf(stderr, "Lexer.unittest %d\n", __LINE__); import dmd.console; string expected; bool gotError; @@ -3290,13 +3300,16 @@ unittest diagnosticHandler = &expectDiagnosticHandler; + if (!global.errorSink) + global.errorSink = new ErrorSinkCompiler; + void test(string sequence, string expectedError, dchar expectedReturnValue, uint expectedScanLength, bool Ccompile = false) { uint errors = global.errors; gotError = false; expected = expectedError; auto p = cast(const(char)*)sequence.ptr; - Lexer lexer = new Lexer(); + Lexer lexer = new Lexer(global.errorSink); dchar c2; auto actualReturnValue = lexer.escapeSequence(Loc.initial, p, Ccompile, c2); assert(gotError); @@ -3344,11 +3357,13 @@ unittest unittest { - //printf("lexer.unittest\n"); + fprintf(stderr, "Lexer.unittest %d\n", __LINE__); /* Not much here, just trying things out. */ string text = "int"; // We rely on the implicit null-terminator - scope Lexer lex1 = new Lexer(null, text.ptr, 0, text.length, 0, 0); + if (!global.errorSink) + global.errorSink = new ErrorSinkCompiler; + scope Lexer lex1 = new Lexer(null, text.ptr, 0, text.length, false, false, global.errorSink); TOK tok; tok = lex1.nextToken(); //printf("tok == %s, %d, %d\n", Token::toChars(tok), tok, TOK.int32); @@ -3363,6 +3378,10 @@ unittest unittest { + fprintf(stderr, "Lexer.unittest %d\n", __LINE__); + if (!global.errorSink) + global.errorSink = new ErrorSinkCompiler; + // We don't want to see Lexer error output during these tests. uint errors = global.startGagging(); scope(exit) global.endGagging(errors); @@ -3383,7 +3402,7 @@ unittest foreach (testcase; testcases) { - scope Lexer lex2 = new Lexer(null, testcase.ptr, 0, testcase.length-1, 0, 0); + scope Lexer lex2 = new Lexer(null, testcase.ptr, 0, testcase.length-1, false, false, global.errorSink); TOK tok = lex2.nextToken(); size_t iterations = 1; while ((tok != TOK.endOfFile) && (iterations++ < testcase.length)) diff --git a/compiler/src/dmd/parse.d b/compiler/src/dmd/parse.d index ec219af6cb42..36a76f50da20 100644 --- a/compiler/src/dmd/parse.d +++ b/compiler/src/dmd/parse.d @@ -16,6 +16,7 @@ module dmd.parse; import core.stdc.stdio; import core.stdc.string; import dmd.astenums; +import dmd.errorsink; import dmd.globals; import dmd.id; import dmd.identifier; @@ -51,9 +52,11 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer * Input: * loc location in source file of mixin */ - extern (D) this(const ref Loc loc, AST.Module _module, const(char)[] input, bool doDocComment) scope + extern (D) this(const ref Loc loc, AST.Module _module, const(char)[] input, bool doDocComment, + ErrorSink errorSink) scope { super(_module ? _module.srcfile.toChars() : null, input.ptr, 0, input.length, doDocComment, false, + errorSink, global.vendor, global.versionNumber()); //printf("Parser::Parser()\n"); @@ -75,9 +78,10 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer //nextToken(); // start up the scanner } - extern (D) this(AST.Module _module, const(char)[] input, bool doDocComment) scope + extern (D) this(AST.Module _module, const(char)[] input, bool doDocComment, ErrorSink errorSink) scope { super(_module ? _module.srcfile.toChars() : null, input.ptr, 0, input.length, doDocComment, false, + errorSink, global.vendor, global.versionNumber()); //printf("Parser::Parser()\n"); @@ -168,13 +172,13 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (token.value == TOK.rightCurly) { - error(token.loc, "unmatched closing brace"); + error("unmatched closing brace"); return errorReturn(); } if (token.value != TOK.endOfFile) { - error(token.loc, "unrecognized declaration"); + error("unrecognized declaration"); return errorReturn(); } return decldefs; @@ -287,7 +291,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer check(TOK.rightParenthesis); if (msg) { - error("conflicting storage class `deprecated(%s)` and `deprecated(%s)`", msg.toChars(), e.toChars()); + error(token.loc, "conflicting storage class `deprecated(%s)` and `deprecated(%s)`", msg.toChars(), e.toChars()); } msg = e; return true; @@ -800,7 +804,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer { if (pAttrs.link != res.link) { - error("conflicting linkage `extern (%s)` and `extern (%s)`", AST.linkageToChars(pAttrs.link), AST.linkageToChars(res.link)); + error(token.loc, "conflicting linkage `extern (%s)` and `extern (%s)`", AST.linkageToChars(pAttrs.link), AST.linkageToChars(res.link)); } else if (res.idents || res.identExps || res.cppmangle != CPPMANGLE.def) { @@ -888,7 +892,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (pAttrs.visibility.kind != AST.Visibility.Kind.undefined) { if (pAttrs.visibility.kind != prot) - error("conflicting visibility attribute `%s` and `%s`", AST.visibilityToChars(pAttrs.visibility.kind), AST.visibilityToChars(prot)); + error(token.loc, "conflicting visibility attribute `%s` and `%s`", AST.visibilityToChars(pAttrs.visibility.kind), AST.visibilityToChars(prot)); else error("redundant visibility attribute `%s`", AST.visibilityToChars(prot)); } @@ -1241,7 +1245,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer { // Windows `printf` does not support `%1$s` const(char*) stc_str = (orig & STC.scope_) ? "scope".ptr : "ref".ptr; - error("attribute `in` cannot be added after `%s`: remove `%s`", + error(token.loc, "attribute `in` cannot be added after `%s`: remove `%s`", stc_str, stc_str); } else @@ -2174,7 +2178,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer nextToken(); if (token.value != TOK.identifier) { - error("`%s` expected as dot-separated identifiers, got `%s`", entity, token.toChars()); + error(token.loc, "`%s` expected as dot-separated identifiers, got `%s`", entity, token.toChars()); return qualified; } @@ -3237,7 +3241,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (token.value != TOK.rightCurly) { /* { */ - error("`}` expected following members in `%s` declaration at %s", + error(token.loc, "`}` expected following members in `%s` declaration at %s", Token.toChars(tok), loc.toChars()); } nextToken(); @@ -3250,7 +3254,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } else { - error("{ } expected following `%s` declaration", Token.toChars(tok)); + error(token.loc, "{ } expected following `%s` declaration", Token.toChars(tok)); } AST.AggregateDeclaration a; @@ -3637,7 +3641,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer loc = token.loc; nextToken(); if (token.value != TOK.leftParenthesis) - error("found `%s` when expecting `%s` following `mixin`", token.toChars(), Token.toChars(TOK.leftParenthesis)); + error(token.loc, "found `%s` when expecting `%s` following `mixin`", token.toChars(), Token.toChars(TOK.leftParenthesis)); auto exps = parseArguments(); t = new AST.TypeMixin(loc, exps); break; @@ -3701,7 +3705,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer default: error("basic type expected, not `%s`", token.toChars()); if (token.value == TOK.else_) - errorSupplemental(token.loc, "There's no `static else`, use `else` instead."); + eSink.errorSupplemental(token.loc, "There's no `static else`, use `else` instead."); t = AST.Type.terror; break; } @@ -4449,7 +4453,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (!tfirst) tfirst = t; else if (t != tfirst) - error("multiple declarations must have the same type, not `%s` and `%s`", tfirst.toChars(), t.toChars()); + error(token.loc, "multiple declarations must have the same type, not `%s` and `%s`", tfirst.toChars(), t.toChars()); if (token.value == TOK.colon && !ident && t.ty != Tfunction) { @@ -4486,7 +4490,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (_init) { if (isThis) - error("cannot use syntax `alias this = %s`, use `alias %s this` instead", _init.toChars(), _init.toChars()); + error(token.loc, "cannot use syntax `alias this = %s`, use `alias %s this` instead", _init.toChars(), _init.toChars()); else error("alias cannot have initializer"); } @@ -4664,12 +4668,12 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer default: if (loc.linnum != token.loc.linnum) { - error("semicolon needed to end declaration of `%s`, instead of `%s`", s.toChars(), token.toChars()); - errorSupplemental(loc, "`%s` declared here", s.toChars()); + error(token.loc, "semicolon needed to end declaration of `%s`, instead of `%s`", s.toChars(), token.toChars()); + eSink.errorSupplemental(loc, "`%s` declared here", s.toChars()); } else { - error("semicolon needed to end declaration of `%s` instead of `%s`", s.toChars(), token.toChars()); + error(token.loc, "semicolon needed to end declaration of `%s` instead of `%s`", s.toChars(), token.toChars()); } break; } @@ -4687,7 +4691,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer // A common mistake is to use a reserved keyword as an identifier, e.g. `in` or `out` if (token.isKeyword) { - errorSupplemental(token.loc, "`%s` is a keyword, perhaps append `_` to make it an identifier", token.toChars()); + eSink.errorSupplemental(token.loc, "`%s` is a keyword, perhaps append `_` to make it an identifier", token.toChars()); nextToken(); } } @@ -4907,7 +4911,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer AST.stcToBuffer(&buf, remStc); // @@@DEPRECATED_2.103@@@ // Deprecated in 2020-07, can be made an error in 2.103 - deprecation("storage class `%s` has no effect in type aliases", buf.peekChars()); + eSink.deprecation(token.loc, "storage class `%s` has no effect in type aliases", buf.peekChars()); } } @@ -5099,7 +5103,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (token.value == TOK.leftCurly) { deprecation("using `(args) => { ... }` to create a delegate that returns a delegate is error-prone."); - deprecationSupplemental(token.loc, "Use `(args) { ... }` for a multi-statement function literal or use `(args) => () { }` if you intended for the lambda to return a delegate."); + deprecationSupplemental("Use `(args) { ... }` for a multi-statement function literal or use `(args) => () { }` if you intended for the lambda to return a delegate."); } const returnloc = token.loc; AST.Expression ae = parseAssignExp(); @@ -5324,7 +5328,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer { if (token.value != TOK.else_ && token.value != TOK.catch_ && token.value != TOK.finally_ && lookingForElse.linnum != 0) { - warning(elseloc, "else is dangling, add { } after condition at %s", lookingForElse.toChars()); + eSink.warning(elseloc, "else is dangling, add { } after condition at %s", lookingForElse.toChars()); } } @@ -5367,7 +5371,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer nextToken(); } if (format) - error(format.ptr, start.ptr, param ? "declaration".ptr : condition.toChars()); + error(token.loc, format.ptr, start.ptr, param ? "declaration".ptr : condition.toChars()); } /***************************************** @@ -5502,7 +5506,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer nextToken(); if (lastai && parameters.length >= 2) { - errorSupplemental(loc, "perhaps the `;` goes before `%s`", lastai.toChars()); + eSink.errorSupplemental(loc, "perhaps the `;` goes before `%s`", lastai.toChars()); } return null; } @@ -5775,7 +5779,7 @@ LagainStc: */ if (token.value == TOK.identifier && exp.op == EXP.identifier) { - error("found `%s` when expecting `;` or `=`, did you mean `%s %s = %s`?", peek(&token).toChars(), exp.toChars(), token.toChars(), peek(peek(&token)).toChars()); + error(token.loc, "found `%s` when expecting `;` or `=`, did you mean `%s %s = %s`?", peek(&token).toChars(), exp.toChars(), token.toChars(), peek(peek(&token)).toChars()); nextToken(); } else @@ -6478,7 +6482,7 @@ LagainStc: if (token.value != TOK.leftParenthesis) { deprecation("`catch` statement without an exception specification is deprecated"); - deprecationSupplemental(token.loc, "use `catch(Throwable)` for old behavior"); + deprecationSupplemental("use `catch(Throwable)` for old behavior"); t = null; id = null; } @@ -7037,7 +7041,7 @@ LagainStc: void check(TOK value, const(char)* string) { if (token.value != value) - error("found `%s` when expecting `%s` following %s", token.toChars(), Token.toChars(value), string); + error(token.loc, "found `%s` when expecting `%s` following %s", token.toChars(), Token.toChars(value), string); nextToken(); } @@ -8103,12 +8107,12 @@ LagainStc: if (token.postfix) { if (token.postfix != postfix) - error("mismatched string literal postfixes `'%c'` and `'%c'`", postfix, token.postfix); + error(token.loc, "mismatched string literal postfixes `'%c'` and `'%c'`", postfix, token.postfix); postfix = token.postfix; } error("implicit string concatenation is error-prone and disallowed in D"); - errorSupplemental(token.loc, "Use the explicit syntax instead " ~ + eSink.errorSupplemental(token.loc, "Use the explicit syntax instead " ~ "(concatenating literals is `@nogc`): %s ~ %s", prev.toChars(), token.toChars()); @@ -8239,7 +8243,7 @@ LagainStc: check(TOK.dot); if (token.value != TOK.identifier) { - error("found `%s` when expecting identifier following `%s`.", token.toChars(), t.toChars()); + error(token.loc, "found `%s` when expecting identifier following `%s`.", token.toChars(), t.toChars()); goto Lerr; } e = new AST.DotIdExp(loc, new AST.TypeExp(loc, t), token.ident); @@ -8384,7 +8388,7 @@ LagainStc: // https://dlang.org/spec/expression.html#mixin_expressions nextToken(); if (token.value != TOK.leftParenthesis) - error("found `%s` when expecting `%s` following `mixin`", token.toChars(), Token.toChars(TOK.leftParenthesis)); + error(token.loc, "found `%s` when expecting `%s` following `mixin`", token.toChars(), Token.toChars(TOK.leftParenthesis)); auto exps = parseArguments(); e = new AST.MixinExp(loc, exps); break; diff --git a/compiler/src/dmd/statementsem.d b/compiler/src/dmd/statementsem.d index ebf7bd1484f3..c80f08d4f211 100644 --- a/compiler/src/dmd/statementsem.d +++ b/compiler/src/dmd/statementsem.d @@ -39,6 +39,7 @@ import dmd.dsymbol; import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; +import dmd.errorsink; import dmd.escape; import dmd.expression; import dmd.expressionsem; @@ -4732,7 +4733,7 @@ private Statements* flatten(Statement statement, Scope* sc) const len = buf.length; buf.writeByte(0); const str = buf.extractSlice()[0 .. len]; - scope p = new Parser!ASTCodegen(cs.loc, sc._module, str, false); + scope p = new Parser!ASTCodegen(cs.loc, sc._module, str, false, global.errorSink); p.nextToken(); auto a = new Statements(); diff --git a/compiler/src/dmd/typesem.d b/compiler/src/dmd/typesem.d index ac60596506ba..84561ac467aa 100644 --- a/compiler/src/dmd/typesem.d +++ b/compiler/src/dmd/typesem.d @@ -35,6 +35,7 @@ import dmd.dsymbol; import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; +import dmd.errorsink; import dmd.expression; import dmd.expressionsem; import dmd.func; @@ -4917,7 +4918,7 @@ RootObject compileTypeMixin(TypeMixin tm, Loc loc, Scope* sc) const len = buf.length; buf.writeByte(0); const str = buf.extractSlice()[0 .. len]; - scope p = new Parser!ASTCodegen(loc, sc._module, str, false); + scope p = new Parser!ASTCodegen(loc, sc._module, str, false, global.errorSink); p.nextToken(); //printf("p.loc.linnum = %d\n", p.loc.linnum); diff --git a/compiler/test/unit/frontend.d b/compiler/test/unit/frontend.d index fd3556d63270..59275132709f 100644 --- a/compiler/test/unit/frontend.d +++ b/compiler/test/unit/frontend.d @@ -56,7 +56,7 @@ unittest initDMD(); defaultImportPaths.each!addImport; - auto t = parseModule!AST("test.d", q{ + auto t = parseModule!AST("frontendcustomASTfamily.d", q{ interface Foo {} }); @@ -174,7 +174,7 @@ unittest initDMD(); defaultImportPaths.each!addImport; - auto t = parseModule("test.d", q{ + auto t = parseModule("frontendcontractchecking.d", q{ int foo(int a) in(a == 3) out(result; result == 0) @@ -219,7 +219,7 @@ unittest initDMD(null, null, ["Foo"]); defaultImportPaths.each!addImport; - auto t = parseModule("test.d", q{ + auto t = parseModule("frontendversionidentifiers.d", q{ version (Foo) enum a = 1; else @@ -263,7 +263,7 @@ unittest initDMD(&diagnosticHandler); defaultImportPaths.each!addImport; - parseModule("test.d", q{ + parseModule("frontendcustomdiagnostichandling.d", q{ void foo(){ auto temp == 7.8; foreach(i; 0..5){ @@ -287,7 +287,7 @@ unittest defaultImportPaths.each!addImport; addStringImport(__FILE_FULL_PATH__.dirName.buildPath("support", "data")); - auto t = parseModule("test.d", q{ + auto t = parseModule("frontendaddStringImport.d", q{ enum a = import("foo.txt"); }); @@ -310,7 +310,7 @@ unittest initDMD(); defaultImportPaths.each!addImport; - auto t = parseModule("test.d", q{ + auto t = parseModule("frontendfloatingpoint.d", q{ static assert((2.0i).re == 0); }); @@ -333,7 +333,7 @@ unittest initDMD(); defaultImportPaths.each!addImport; - auto t = parseModule("test.d", q{ + auto t = parseModule("frontendinlineassembly.d", q{ void foo() { asm @@ -380,7 +380,7 @@ unittest initDMD(&diagnosticHandler); defaultImportPaths.each!addImport; - auto t = parseModule("test.dd", q{Ddoc}); + auto t = parseModule("frontendddoc.dd", q{Ddoc}); assert(!t.diagnostics.hasErrors); assert(!t.diagnostics.hasWarnings); diff --git a/compiler/test/unit/lexer/diagnostic_reporter.d b/compiler/test/unit/lexer/diagnostic_reporter.d index 314c7a80f347..030ce6c6ecad 100644 --- a/compiler/test/unit/lexer/diagnostic_reporter.d +++ b/compiler/test/unit/lexer/diagnostic_reporter.d @@ -6,6 +6,7 @@ import core.stdc.stdarg; import dmd.globals : global, DiagnosticReporting; import dmd.location; +import dmd.errors; import support : afterEach, NoopDiagnosticReporter; @@ -61,7 +62,9 @@ private void lexUntilEndOfFile(string code) import dmd.lexer : Lexer; import dmd.tokens : TOK; - scope lexer = new Lexer("test", code.ptr, 0, code.length, 0, 0); + if (!global.errorSink) + global.errorSink = new ErrorSinkCompiler; + scope lexer = new Lexer("test", code.ptr, 0, code.length, 0, 0, global.errorSink); lexer.nextToken; while (lexer.nextToken != TOK.endOfFile) {} diff --git a/compiler/test/unit/lexer/lexer_dmdlib.d b/compiler/test/unit/lexer/lexer_dmdlib.d index 589abce0e453..561fd1d19880 100644 --- a/compiler/test/unit/lexer/lexer_dmdlib.d +++ b/compiler/test/unit/lexer/lexer_dmdlib.d @@ -2,6 +2,7 @@ module lexer.lexer_dmdlib; import dmd.lexer : Lexer; import dmd.tokens : TOK; +import dmd.errorsink; unittest { @@ -16,7 +17,7 @@ unittest TOK.rightCurly, ]; - Lexer lexer = new Lexer(null, code.ptr, 0, code.length, false, false, false); + Lexer lexer = new Lexer(null, code.ptr, 0, code.length, false, false, false, new ErrorSinkStderr); TOK[] result; while (lexer.nextToken != TOK.endOfFile) @@ -39,7 +40,7 @@ unittest TOK.comment, ]; - Lexer lexer = new Lexer(null, code.ptr, 0, code.length, false, true, false); + Lexer lexer = new Lexer(null, code.ptr, 0, code.length, false, true, false, new ErrorSinkStderr); TOK[] result; while (lexer.nextToken != TOK.endOfFile) @@ -65,7 +66,7 @@ unittest TOK.comment, ]; - Lexer lexer = new Lexer(null, code.ptr, 0, code.length, false, true, true); + Lexer lexer = new Lexer(null, code.ptr, 0, code.length, false, true, true, new ErrorSinkStderr); TOK[] result; while (lexer.nextToken != TOK.endOfFile) @@ -92,7 +93,7 @@ unittest TOK.whitespace, ]; - Lexer lexer = new Lexer(null, code.ptr, 0, code.length, false, true, true); + Lexer lexer = new Lexer(null, code.ptr, 0, code.length, false, true, true, new ErrorSinkStderr); TOK[] result; while (lexer.nextToken != TOK.endOfFile) @@ -136,7 +137,7 @@ unittest TOK.whitespace, ]; - Lexer lexer = new Lexer(null, code.ptr, 0, code.length, false, true, true); + Lexer lexer = new Lexer(null, code.ptr, 0, code.length, false, true, true, new ErrorSinkStderr); TOK[] result; while (lexer.nextToken != TOK.endOfFile) @@ -171,7 +172,7 @@ unittest TOK.whitespace, ]; - Lexer lexer = new Lexer(null, code.ptr, 0, code.length, false, true, true); + Lexer lexer = new Lexer(null, code.ptr, 0, code.length, false, true, true, new ErrorSinkStderr); TOK[] result; while (lexer.nextToken != TOK.endOfFile) @@ -193,7 +194,7 @@ unittest TOK.rightCurly, ]; - Lexer lexer = new Lexer(null, code.ptr, 0, code.length, false, false); + Lexer lexer = new Lexer(null, code.ptr, 0, code.length, false, false, new ErrorSinkStderr); lexer.nextToken; TOK[] result; @@ -214,7 +215,7 @@ unittest TOK.comment, ]; - Lexer lexer = new Lexer(null, code.ptr, 0, code.length, false, true); + Lexer lexer = new Lexer(null, code.ptr, 0, code.length, false, true, new ErrorSinkStderr); lexer.nextToken; TOK[] result; @@ -240,7 +241,7 @@ unittest TOK.reserved, ]; - Lexer lexer = new Lexer(null, code.ptr, 0, code.length, false, false); + Lexer lexer = new Lexer(null, code.ptr, 0, code.length, false, false, new ErrorSinkStderr); TOK[] result; @@ -265,6 +266,7 @@ unittest import dmd.location; import dmd.common.outbuffer; import dmd.console : Color; + import dmd.errors; const(char)[][2][] diagnosticMessages; nothrow bool diagnosticHandler(const ref Loc loc, Color headerColor, const(char)* header, @@ -288,7 +290,7 @@ unittest foreach (codeNum, code; codes) { auto fileName = text("file", codeNum, '\0'); - Lexer lexer = new Lexer(fileName.ptr, code.ptr, 0, code.length, false, false); + Lexer lexer = new Lexer(fileName.ptr, code.ptr, 0, code.length, false, false, new ErrorSinkCompiler); // Generate the errors foreach(unused; lexer){} } diff --git a/compiler/test/unit/lexer/location_offset.d b/compiler/test/unit/lexer/location_offset.d index 9ba3c51752b0..c52de839dbee 100644 --- a/compiler/test/unit/lexer/location_offset.d +++ b/compiler/test/unit/lexer/location_offset.d @@ -2,6 +2,7 @@ module lexer.location_offset; import dmd.lexer : Lexer; import dmd.tokens : TOK; +import dmd.errorsink; import support : afterEach; @@ -16,7 +17,7 @@ unittest { enum code = "token"; - scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0); + scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0, new ErrorSinkStderr); lexer.nextToken; @@ -28,7 +29,7 @@ unittest { enum code = "ignored_token token"; - scope lexer = new Lexer("test.d", code.ptr, 13, code.length - 14, 0, 0); + scope lexer = new Lexer("test.d", code.ptr, 13, code.length - 14, 0, 0, new ErrorSinkStderr); lexer.nextToken; @@ -40,7 +41,7 @@ unittest { enum code = "token1 token2 3"; - scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0); + scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0, new ErrorSinkStderr); lexer.nextToken; lexer.nextToken; @@ -54,7 +55,7 @@ unittest { enum code = "token"; - scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0); + scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0, new ErrorSinkStderr); lexer.nextToken; lexer.nextToken; @@ -67,7 +68,7 @@ unittest { enum code = "/* comment */"; - scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, true); + scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, true, new ErrorSinkStderr); lexer.nextToken; @@ -80,7 +81,7 @@ unittest { enum code = "// comment"; - scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, true); + scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, true, new ErrorSinkStderr); lexer.nextToken; @@ -93,7 +94,7 @@ unittest { enum code = "/+ comment +/"; - scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, true); + scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, true, new ErrorSinkStderr); lexer.nextToken; @@ -106,7 +107,7 @@ unittest { enum code = "/* comment */ token"; - scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0); + scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0, new ErrorSinkStderr); lexer.nextToken; @@ -118,7 +119,7 @@ unittest { enum code = "// comment\ntoken"; - scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0); + scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0, new ErrorSinkStderr); lexer.nextToken; @@ -130,7 +131,7 @@ unittest { enum code = "/+ comment +/ token"; - scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0); + scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0, new ErrorSinkStderr); lexer.nextToken; @@ -142,7 +143,7 @@ unittest { enum code = "line\ntoken"; - scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0); + scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0, new ErrorSinkStderr); lexer.nextToken; lexer.nextToken; @@ -155,7 +156,7 @@ unittest { enum code = "line\r\ntoken"; - scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0); + scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0, new ErrorSinkStderr); lexer.nextToken; lexer.nextToken; @@ -168,7 +169,7 @@ unittest { enum code = "line\rtoken"; - scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0); + scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0, new ErrorSinkStderr); lexer.nextToken; lexer.nextToken; @@ -181,7 +182,7 @@ unittest { enum code = "'🍺'"; - scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0); + scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0, new ErrorSinkStderr); lexer.nextToken; @@ -193,7 +194,7 @@ unittest { enum code = `"🍺🍺"`; - scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0); + scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0, new ErrorSinkStderr); lexer.nextToken; @@ -205,7 +206,7 @@ unittest { enum code = "'🍺' token"; - scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0); + scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0, new ErrorSinkStderr); lexer.nextToken; lexer.nextToken; @@ -218,7 +219,7 @@ unittest { enum code = `"🍺🍺" token`; - scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0); + scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0, new ErrorSinkStderr); lexer.nextToken; lexer.nextToken; @@ -557,7 +558,7 @@ static foreach (tok; __traits(allMembers, TOK)) { const newCode = "first_token " ~ tests[tok].code; - scope lexer = new Lexer("test.d", newCode.ptr, 0, newCode.length, 0, 0); + scope lexer = new Lexer("test.d", newCode.ptr, 0, newCode.length, 0, 0, new ErrorSinkStderr); lexer.nextToken; lexer.nextToken;