diff options
author | Iain Buclaw <ibuclaw@gdcproject.org> | 2023-10-15 12:05:10 +0200 |
---|---|---|
committer | Iain Buclaw <ibuclaw@gdcproject.org> | 2023-10-15 12:12:49 +0200 |
commit | ac908237bd551fb55f2f82736cb37038e9b91459 (patch) | |
tree | 1d9efb93ef9af63ec88bf85130e16116249bb192 /gcc/d/dmd | |
parent | 648d30716d0cdb5dec96b2da9ed23328bad7cb9f (diff) | |
download | gcc-ac908237bd551fb55f2f82736cb37038e9b91459.zip gcc-ac908237bd551fb55f2f82736cb37038e9b91459.tar.gz gcc-ac908237bd551fb55f2f82736cb37038e9b91459.tar.bz2 |
d: Merge upstream dmd, druntime f9efc98fd7, phobos a3f22129d.
D front-end changes:
- Import dmd v2.105.2.
- A function with enum storage class is now deprecated.
- Global variables can now be initialized with Associative
Arrays.
- Improvements for the C++ header generation of static variables
used in a default argument context.
D runtime changes:
- Import druntime v2.105.2.
- The `core.memory.GC' functions `GC.enable', `GC.disable',
`GC.collect', and `GC.minimize' `have been marked `@safe'.
Phobos changes:
- Import phobos v2.105.2.
gcc/d/ChangeLog:
* dmd/MERGE: Merge upstream dmd f9efc98fd7.
* dmd/VERSION: Bump version to v2.105.2.
* d-builtins.cc (build_frontend_type): Update for new front-end
interface.
* d-diagnostic.cc (verrorReport): Don't emit tips when error gagging
is turned on.
* d-lang.cc (d_handle_option): Remove obsolete parameter.
(d_post_options): Likewise.
(d_read_ddoc_files): New function.
(d_generate_ddoc_file): New function.
(d_parse_file): Update for new front-end interface.
* expr.cc (ExprVisitor::visit (AssocArrayLiteralExp *)): Check for new
front-end lowering of static associative arrays.
libphobos/ChangeLog:
* libdruntime/MERGE: Merge upstream druntime f9efc98fd7.
* libdruntime/Makefile.am (DRUNTIME_DSOURCES): Add
core/internal/newaa.d.
* libdruntime/Makefile.in: Regenerate.
* src/MERGE: Merge upstream phobos a3f22129d.
* testsuite/libphobos.hash/test_hash.d: Update test.
* testsuite/libphobos.phobos/phobos.exp: Add compiler flags
-Wno-deprecated.
* testsuite/libphobos.phobos_shared/phobos_shared.exp: Likewise.
gcc/testsuite/ChangeLog:
* lib/gdc-utils.exp (gdc-convert-args): Handle new compiler options.
Diffstat (limited to 'gcc/d/dmd')
64 files changed, 1361 insertions, 1003 deletions
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index dc26778..d5dfe0d 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -4574d1728d1f7e52ff40e6733b8c39889d128349 +f9efc98fd7954741333f72c6a50af273f3863a1a The first line of this file holds the git revision number of the last merge done from the dlang/dmd repository. diff --git a/gcc/d/dmd/VERSION b/gcc/d/dmd/VERSION index 8012337..fd05dcf 100644 --- a/gcc/d/dmd/VERSION +++ b/gcc/d/dmd/VERSION @@ -1 +1 @@ -v2.105.0 +v2.105.2 diff --git a/gcc/d/dmd/attrib.d b/gcc/d/dmd/attrib.d index baabe93..5a91bc7 100644 --- a/gcc/d/dmd/attrib.d +++ b/gcc/d/dmd/attrib.d @@ -679,7 +679,7 @@ extern (C++) final class VisibilityDeclaration : AttribDeclaration { assert(visibility.kind > Visibility.Kind.undefined); OutBuffer buf; - visibilityToBuffer(&buf, visibility); + visibilityToBuffer(buf, visibility); return buf.extractChars(); } diff --git a/gcc/d/dmd/blockexit.d b/gcc/d/dmd/blockexit.d index bdc81f2..a0da77a 100644 --- a/gcc/d/dmd/blockexit.d +++ b/gcc/d/dmd/blockexit.d @@ -18,6 +18,7 @@ import dmd.astenums; import dmd.canthrow; import dmd.dclass; import dmd.declaration; +import dmd.errorsink; import dmd.expression; import dmd.func; import dmd.globals; @@ -56,11 +57,11 @@ enum BE : int * Params: * s = statement to check for block exit status * func = function that statement s is in - * mustNotThrow = generate an error if it throws + * eSink = generate an error if it throws * Returns: * BE.xxxx */ -int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) +int blockExit(Statement s, FuncDeclaration func, ErrorSink eSink) { int result = BE.none; @@ -97,7 +98,7 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) if (s.exp.type && s.exp.type.toBasetype().isTypeNoreturn()) result = BE.halt; - result |= canThrow(s.exp, func, mustNotThrow); + result |= canThrow(s.exp, func, eSink !is null); } } @@ -143,23 +144,23 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) // Deprecated in 2.100 // Make an error in 2.110 if (sl && sl.isCaseStatement()) - s.deprecation("switch case fallthrough - use 'goto %s;' if intended", gototype); + global.errorSink.deprecation(s.loc, "switch case fallthrough - use 'goto %s;' if intended", gototype); else - s.error("switch case fallthrough - use 'goto %s;' if intended", gototype); + global.errorSink.error(s.loc, "switch case fallthrough - use 'goto %s;' if intended", gototype); } } } if (!(result & BE.fallthru) && !s.comeFrom()) { - if (blockExit(s, func, mustNotThrow) != BE.halt && s.hasCode() && + if (blockExit(s, func, eSink) != BE.halt && s.hasCode() && s.loc != Loc.initial) // don't emit warning for generated code - s.warning("statement is not reachable"); + global.errorSink.warning(s.loc, "statement is not reachable"); } else { result &= ~BE.fallthru; - result |= blockExit(s, func, mustNotThrow); + result |= blockExit(s, func, eSink); } slast = s; } @@ -173,7 +174,7 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) { if (s) { - int r = blockExit(s, func, mustNotThrow); + int r = blockExit(s, func, eSink); result |= r & ~(BE.break_ | BE.continue_ | BE.fallthru); if ((r & (BE.fallthru | BE.continue_ | BE.break_)) == 0) result &= ~BE.fallthru; @@ -184,7 +185,7 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) void visitScope(ScopeStatement s) { //printf("ScopeStatement::blockExit(%p)\n", s.statement); - result = blockExit(s.statement, func, mustNotThrow); + result = blockExit(s.statement, func, eSink); } void visitWhile(WhileStatement s) @@ -197,7 +198,7 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) { if (s._body) { - result = blockExit(s._body, func, mustNotThrow); + result = blockExit(s._body, func, eSink); if (result == BE.break_) { result = BE.fallthru; @@ -210,7 +211,7 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) result = BE.fallthru; if (result & BE.fallthru) { - result |= canThrow(s.condition, func, mustNotThrow); + result |= canThrow(s.condition, func, eSink !is null); if (!(result & BE.break_) && s.condition.toBool().hasValue(true)) result &= ~BE.fallthru; @@ -223,13 +224,13 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) result = BE.fallthru; if (s._init) { - result = blockExit(s._init, func, mustNotThrow); + result = blockExit(s._init, func, eSink); if (!(result & BE.fallthru)) return; } if (s.condition) { - result |= canThrow(s.condition, func, mustNotThrow); + result |= canThrow(s.condition, func, eSink !is null); const opt = s.condition.toBool(); if (opt.hasValue(true)) @@ -241,22 +242,22 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) result &= ~BE.fallthru; // the body must do the exiting if (s._body) { - int r = blockExit(s._body, func, mustNotThrow); + int r = blockExit(s._body, func, eSink); if (r & (BE.break_ | BE.goto_)) result |= BE.fallthru; result |= r & ~(BE.fallthru | BE.break_ | BE.continue_); } if (s.increment) - result |= canThrow(s.increment, func, mustNotThrow); + result |= canThrow(s.increment, func, eSink !is null); } void visitForeach(ForeachStatement s) { result = BE.fallthru; - result |= canThrow(s.aggr, func, mustNotThrow); + result |= canThrow(s.aggr, func, eSink !is null); if (s._body) - result |= blockExit(s._body, func, mustNotThrow) & ~(BE.break_ | BE.continue_); + result |= blockExit(s._body, func, eSink) & ~(BE.break_ | BE.continue_); } void visitForeachRange(ForeachRangeStatement s) @@ -269,30 +270,30 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) { //printf("IfStatement::blockExit(%p)\n", s); result = BE.none; - result |= canThrow(s.condition, func, mustNotThrow); + result |= canThrow(s.condition, func, eSink !is null); const opt = s.condition.toBool(); if (opt.hasValue(true)) { - result |= blockExit(s.ifbody, func, mustNotThrow); + result |= blockExit(s.ifbody, func, eSink); } else if (opt.hasValue(false)) { - result |= blockExit(s.elsebody, func, mustNotThrow); + result |= blockExit(s.elsebody, func, eSink); } else { - result |= blockExit(s.ifbody, func, mustNotThrow); - result |= blockExit(s.elsebody, func, mustNotThrow); + result |= blockExit(s.ifbody, func, eSink); + result |= blockExit(s.elsebody, func, eSink); } //printf("IfStatement::blockExit(%p) = x%x\n", s, result); } void visitConditional(ConditionalStatement s) { - result = blockExit(s.ifbody, func, mustNotThrow); + result = blockExit(s.ifbody, func, eSink); if (s.elsebody) - result |= blockExit(s.elsebody, func, mustNotThrow); + result |= blockExit(s.elsebody, func, eSink); } void visitPragma(PragmaStatement s) @@ -308,11 +309,11 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) void visitSwitch(SwitchStatement s) { result = BE.none; - result |= canThrow(s.condition, func, mustNotThrow); + result |= canThrow(s.condition, func, eSink !is null); if (s._body) { - result |= blockExit(s._body, func, mustNotThrow); + result |= blockExit(s._body, func, eSink); if (result & BE.break_) { result |= BE.fallthru; @@ -325,12 +326,12 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) void visitCase(CaseStatement s) { - result = blockExit(s.statement, func, mustNotThrow); + result = blockExit(s.statement, func, eSink); } void visitDefault(DefaultStatement s) { - result = blockExit(s.statement, func, mustNotThrow); + result = blockExit(s.statement, func, eSink); } void visitGotoDefault(GotoDefaultStatement s) @@ -353,7 +354,7 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) { result = BE.return_; if (s.exp) - result |= canThrow(s.exp, func, mustNotThrow); + result |= canThrow(s.exp, func, eSink !is null); } void visitBreak(BreakStatement s) @@ -369,20 +370,20 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) void visitSynchronized(SynchronizedStatement s) { - result = blockExit(s._body, func, mustNotThrow); + result = blockExit(s._body, func, eSink); } void visitWith(WithStatement s) { result = BE.none; - result |= canThrow(s.exp, func, mustNotThrow); - result |= blockExit(s._body, func, mustNotThrow); + result |= canThrow(s.exp, func, eSink !is null); + result |= blockExit(s._body, func, eSink); } void visitTryCatch(TryCatchStatement s) { assert(s._body); - result = blockExit(s._body, func, false); + result = blockExit(s._body, func, null); int catchresult = 0; foreach (c; *s.catches) @@ -390,7 +391,7 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) if (c.type == Type.terror) continue; - int cresult = blockExit(c.handler, func, mustNotThrow); + int cresult = blockExit(c.handler, func, eSink); /* If we're catching Object, then there is no throwing */ @@ -411,10 +412,10 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) } catchresult |= cresult; } - if (mustNotThrow && (result & BE.throw_)) + if (eSink && (result & BE.throw_)) { // now explain why this is nothrow - blockExit(s._body, func, mustNotThrow); + blockExit(s._body, func, eSink); } result |= catchresult; } @@ -423,12 +424,12 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) { result = BE.fallthru; if (s._body) - result = blockExit(s._body, func, false); + result = blockExit(s._body, func, null); // check finally body as well, it may throw (bug #4082) int finalresult = BE.fallthru; if (s.finalbody) - finalresult = blockExit(s.finalbody, func, false); + finalresult = blockExit(s.finalbody, func, null); // If either body or finalbody halts if (result == BE.halt) @@ -436,13 +437,13 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) if (finalresult == BE.halt) result = BE.none; - if (mustNotThrow) + if (eSink) { // now explain why this is nothrow if (s._body && (result & BE.throw_)) - blockExit(s._body, func, mustNotThrow); + blockExit(s._body, func, eSink); if (s.finalbody && (finalresult & BE.throw_)) - blockExit(s.finalbody, func, mustNotThrow); + blockExit(s.finalbody, func, eSink); } version (none) @@ -452,7 +453,7 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) // destructor call, exit of synchronized statement, etc. if (result == BE.halt && finalresult != BE.halt && s.finalbody && s.finalbody.hasCode()) { - s.finalbody.warning("statement is not reachable"); + eSink.warning(s.finalbody.loc, "statement is not reachable"); } } @@ -472,12 +473,12 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) if (s.internalThrow) { // https://issues.dlang.org/show_bug.cgi?id=8675 - // Allow throwing 'Throwable' object even if mustNotThrow. + // Allow throwing 'Throwable' object even if eSink. result = BE.fallthru; return; } - result = checkThrow(s.loc, s.exp, mustNotThrow, func); + result = checkThrow(s.loc, s.exp, func, eSink); } void visitGoto(GotoStatement s) @@ -489,7 +490,7 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) void visitLabel(LabelStatement s) { //printf("LabelStatement::blockExit(%p)\n", s); - result = blockExit(s.statement, func, mustNotThrow); + result = blockExit(s.statement, func, eSink); if (s.breaks) result |= BE.fallthru; } @@ -502,8 +503,8 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) { if(func) func.setThrow(s.loc, "`asm` statement is assumed to throw - mark it with `nothrow` if it does not"); - if (mustNotThrow) - s.error("`asm` statement is assumed to throw - mark it with `nothrow` if it does not"); // TODO + if (eSink) + eSink.error(s.loc, "`asm` statement is assumed to throw - mark it with `nothrow` if it does not"); // TODO else result |= BE.throw_; } @@ -528,15 +529,13 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) + Params: + loc = location of the `throw` + exp = expression yielding the throwable - + mustNotThrow = inside of a `nothrow` scope? + + eSink = if !null then inside of a `nothrow` scope + func = function containing the `throw` + + Returns: `BE.[err]throw` depending on the type of `exp` +/ -BE checkThrow(ref const Loc loc, Expression exp, const bool mustNotThrow, FuncDeclaration func) +BE checkThrow(ref const Loc loc, Expression exp, FuncDeclaration func, ErrorSink eSink) { - import dmd.errors : error; - Type t = exp.type.toBasetype(); ClassDeclaration cd = t.isClassHandle(); assert(cd); @@ -545,8 +544,8 @@ BE checkThrow(ref const Loc loc, Expression exp, const bool mustNotThrow, FuncDe { return BE.errthrow; } - if (mustNotThrow) - loc.error("`%s` is thrown but not caught", exp.type.toChars()); + if (eSink) + eSink.error(loc, "`%s` is thrown but not caught", exp.type.toChars()); else if (func) func.setThrow(loc, "`%s` is thrown but not caught", exp.type); diff --git a/gcc/d/dmd/canthrow.d b/gcc/d/dmd/canthrow.d index ba13eb0..4cead30 100644 --- a/gcc/d/dmd/canthrow.d +++ b/gcc/d/dmd/canthrow.d @@ -202,7 +202,7 @@ extern (C++) /* CT */ BE canThrow(Expression e, FuncDeclaration func, bool mustN override void visit(ThrowExp te) { - const res = checkThrow(te.loc, te.e1, mustNotThrow, func); + const res = checkThrow(te.loc, te.e1, func, mustNotThrow ? global.errorSink : null); assert((res & ~(CT.exception | CT.error)) == 0); result |= res; } diff --git a/gcc/d/dmd/chkformat.d b/gcc/d/dmd/chkformat.d index feaa3c7..8cfad59 100644 --- a/gcc/d/dmd/chkformat.d +++ b/gcc/d/dmd/chkformat.d @@ -15,7 +15,7 @@ import core.stdc.ctype : isdigit; import dmd.astenums; import dmd.cond; -import dmd.errors; +import dmd.errorsink; import dmd.expression; import dmd.globals; import dmd.identifier; @@ -53,6 +53,7 @@ import dmd.target; * format = format string * args = arguments to match with format string * isVa_list = if a "v" function (format check only) + * eSink = where the error messages go * * Returns: * `true` if errors occurred @@ -60,7 +61,8 @@ import dmd.target; * C99 7.19.6.1 * https://www.cplusplus.com/reference/cstdio/printf/ */ -bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expression[] args, bool isVa_list) +public +bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expression[] args, bool isVa_list, ErrorSink eSink) { //printf("checkPrintFormat('%.*s')\n", cast(int)format.length, format.ptr); size_t n; // index in args @@ -87,7 +89,7 @@ bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expre { // format check only if (fmt == Format.error) - deprecation(loc, "format specifier `\"%.*s\"` is invalid", cast(int)slice.length, slice.ptr); + eSink.deprecation(loc, "format specifier `\"%.*s\"` is invalid", cast(int)slice.length, slice.ptr); continue; } @@ -96,7 +98,7 @@ bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expre if (n == args.length) { if (args.length < (n + 1)) - deprecation(loc, "more format specifiers than %d arguments", cast(int)n); + eSink.deprecation(loc, "more format specifiers than %d arguments", cast(int)n); else skip = true; return null; @@ -106,7 +108,7 @@ bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expre void errorMsg(const char* prefix, Expression arg, const char* texpect, Type tactual) { - deprecation(arg.loc, "%sargument `%s` for format specification `\"%.*s\"` must be `%s`, not `%s`", + eSink.deprecation(arg.loc, "%sargument `%s` for format specification `\"%.*s\"` must be `%s`, not `%s`", prefix ? prefix : "", arg.toChars(), cast(int)slice.length, slice.ptr, texpect, tactual.toChars()); } @@ -178,7 +180,7 @@ bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expre else errorMsg(null, e, (c_longsize == 4 ? "int" : "long"), t); if (t.isintegral() && t.size() != c_longsize) - errorSupplemental(e.loc, "C `long` is %d bytes on your system", c_longsize); + eSink.errorSupplemental(e.loc, "C `long` is %d bytes on your system", c_longsize); } break; @@ -226,7 +228,7 @@ bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expre break; case Format.n: // pointer to int - if (!(t.ty == Tpointer && tnext.ty == Tint32)) + if (!(t.ty == Tpointer && tnext.ty == Tint32 && tnext.isMutable())) errorMsg(null, e, "int*", t); break; @@ -286,7 +288,7 @@ bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expre break; case Format.error: - deprecation(loc, "format specifier `\"%.*s\"` is invalid", cast(int)slice.length, slice.ptr); + eSink.deprecation(loc, "format specifier `\"%.*s\"` is invalid", cast(int)slice.length, slice.ptr); break; case Format.GNU_m: @@ -327,6 +329,7 @@ bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expre * format = format string * args = arguments to match with format string * isVa_list = if a "v" function (format check only) + * eSink = where the error messages go * * Returns: * `true` if errors occurred @@ -334,7 +337,8 @@ bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expre * C99 7.19.6.2 * https://www.cplusplus.com/reference/cstdio/scanf/ */ -bool checkScanfFormat(ref const Loc loc, scope const char[] format, scope Expression[] args, bool isVa_list) +public +bool checkScanfFormat(ref const Loc loc, scope const char[] format, scope Expression[] args, bool isVa_list, ErrorSink eSink) { size_t n = 0; for (size_t i = 0; i < format.length;) @@ -357,7 +361,7 @@ bool checkScanfFormat(ref const Loc loc, scope const char[] format, scope Expres { // format check only if (fmt == Format.error) - deprecation(loc, "format specifier `\"%.*s\"` is invalid", cast(int)slice.length, slice.ptr); + eSink.deprecation(loc, "format specifier `\"%.*s\"` is invalid", cast(int)slice.length, slice.ptr); continue; } @@ -366,7 +370,7 @@ bool checkScanfFormat(ref const Loc loc, scope const char[] format, scope Expres if (n == args.length) { if (!asterisk) - deprecation(loc, "more format specifiers than %d arguments", cast(int)n); + eSink.deprecation(loc, "more format specifiers than %d arguments", cast(int)n); return null; } return args[n++]; @@ -374,7 +378,7 @@ bool checkScanfFormat(ref const Loc loc, scope const char[] format, scope Expres void errorMsg(const char* prefix, Expression arg, const char* texpect, Type tactual) { - deprecation(arg.loc, "%sargument `%s` for format specification `\"%.*s\"` must be `%s`, not `%s`", + eSink.deprecation(arg.loc, "%sargument `%s` for format specification `\"%.*s\"` must be `%s`, not `%s`", prefix ? prefix : "", arg.toChars(), cast(int)slice.length, slice.ptr, texpect, tactual.toChars()); } @@ -512,7 +516,7 @@ bool checkScanfFormat(ref const Loc loc, scope const char[] format, scope Expres break; case Format.error: - deprecation(loc, "format specifier `\"%.*s\"` is invalid", cast(int)slice.length, slice.ptr); + eSink.deprecation(loc, "format specifier `\"%.*s\"` is invalid", cast(int)slice.length, slice.ptr); break; case Format.GNU_m: @@ -523,6 +527,8 @@ bool checkScanfFormat(ref const Loc loc, scope const char[] format, scope Expres return false; } +/*****************************************************************************************************/ + private: /************************************** diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d index 4cff1ec..181268e 100644 --- a/gcc/d/dmd/clone.d +++ b/gcc/d/dmd/clone.d @@ -297,7 +297,7 @@ FuncDeclaration buildOpAssign(StructDeclaration sd, Scope* sc) } auto fparams = new Parameters(); - fparams.push(new Parameter(STC.nodtor, sd.type, Id.p, null, null)); + fparams.push(new Parameter(loc, STC.nodtor, sd.type, Id.p, null, null)); auto tf = new TypeFunction(ParameterList(fparams), sd.handleType(), LINK.d, stc | STC.ref_); auto fop = new FuncDeclaration(declLoc, Loc.initial, Id.assign, stc, tf); fop.storage_class |= STC.inference; @@ -546,10 +546,11 @@ FuncDeclaration buildXopEquals(StructDeclaration sd, Scope* sc) TypeFunction tfeqptr; { Scope scx; + scx.eSink = sc.eSink; /* const bool opEquals(ref const S s); */ auto parameters = new Parameters(); - parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, null, null, null)); + parameters.push(new Parameter(Loc.initial, STC.ref_ | STC.const_, sd.type, null, null, null)); tfeqptr = new TypeFunction(ParameterList(parameters), Type.tbool, LINK.d); tfeqptr.mod = MODFlags.const_; tfeqptr = cast(TypeFunction)tfeqptr.typeSemantic(Loc.initial, &scx); @@ -577,7 +578,7 @@ FuncDeclaration buildXopEquals(StructDeclaration sd, Scope* sc) Loc declLoc; // loc is unnecessary so __xopEquals is never called directly Loc loc; // loc is unnecessary so errors are gagged auto parameters = new Parameters(); - parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.p, null, null)); + parameters.push(new Parameter(loc, STC.ref_ | STC.const_, sd.type, Id.p, null, null)); auto tf = new TypeFunction(ParameterList(parameters), Type.tbool, LINK.d, STC.const_); tf = tf.addSTC(STC.const_).toTypeFunction(); Identifier id = Id.xopEquals; @@ -620,10 +621,11 @@ FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc) TypeFunction tfcmpptr; { Scope scx; + scx.eSink = sc.eSink; /* const int opCmp(ref const S s); */ auto parameters = new Parameters(); - parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, null, null, null)); + parameters.push(new Parameter(Loc.initial, STC.ref_ | STC.const_, sd.type, null, null, null)); tfcmpptr = new TypeFunction(ParameterList(parameters), Type.tint32, LINK.d); tfcmpptr.mod = MODFlags.const_; tfcmpptr = cast(TypeFunction)tfcmpptr.typeSemantic(Loc.initial, &scx); @@ -701,7 +703,7 @@ FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc) Loc declLoc; // loc is unnecessary so __xopCmp is never called directly Loc loc; // loc is unnecessary so errors are gagged auto parameters = new Parameters(); - parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.p, null, null)); + parameters.push(new Parameter(loc, STC.ref_ | STC.const_, sd.type, Id.p, null, null)); auto tf = new TypeFunction(ParameterList(parameters), Type.tint32, LINK.d, STC.const_); tf = tf.addSTC(STC.const_).toTypeFunction(); Identifier id = Id.xopCmp; @@ -820,7 +822,7 @@ FuncDeclaration buildXtoHash(StructDeclaration sd, Scope* sc) Loc declLoc; // loc is unnecessary so __xtoHash is never called directly Loc loc; // internal code should have no loc to prevent coverage auto parameters = new Parameters(); - parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.p, null, null)); + parameters.push(new Parameter(loc, STC.ref_ | STC.const_, sd.type, Id.p, null, null)); auto tf = new TypeFunction(ParameterList(parameters), Type.thash_t, LINK.d, STC.nothrow_ | STC.trusted); Identifier id = Id.xtoHash; auto fop = new FuncDeclaration(declLoc, Loc.initial, id, STC.static_, tf); @@ -1074,7 +1076,7 @@ private DtorDeclaration buildWindowsCppDtor(AggregateDeclaration ad, DtorDeclara // // TODO: if (del) delete (char*)this; // return (void*) this; // } - Parameter delparam = new Parameter(STC.undefined_, Type.tuns32, Identifier.idPool("del"), new IntegerExp(dtor.loc, 0, Type.tuns32), null); + Parameter delparam = new Parameter(Loc.initial, STC.undefined_, Type.tuns32, Identifier.idPool("del"), new IntegerExp(dtor.loc, 0, Type.tuns32), null); Parameters* params = new Parameters; params.push(delparam); const stc = dtor.storage_class & ~STC.scope_; // because we add the `return this;` later @@ -1126,7 +1128,7 @@ private DtorDeclaration buildExternDDtor(AggregateDeclaration ad, Scope* sc) return null; // Generate shim only when ABI incompatible on target platform - if (ad.classKind != ClassKind.cpp || !target.cpp.wrapDtorInExternD) + if (dtor._linkage != LINK.cpp || !target.cpp.wrapDtorInExternD) return dtor; // generate member function that adjusts calling convention @@ -1514,7 +1516,7 @@ private CtorDeclaration generateCopyCtorDeclaration(StructDeclaration sd, const { auto fparams = new Parameters(); auto structType = sd.type; - fparams.push(new Parameter(paramStc | STC.ref_ | STC.return_ | STC.scope_, structType, Id.p, null, null)); + fparams.push(new Parameter(Loc.initial, paramStc | STC.ref_ | STC.return_ | STC.scope_, structType, Id.p, null, null)); ParameterList pList = ParameterList(fparams); auto tf = new TypeFunction(pList, structType, LINK.d, STC.ref_); auto ccd = new CtorDeclaration(sd.loc, Loc.initial, STC.ref_, tf, true); diff --git a/gcc/d/dmd/cond.d b/gcc/d/dmd/cond.d index 360acf5..76cef77 100644 --- a/gcc/d/dmd/cond.d +++ b/gcc/d/dmd/cond.d @@ -322,7 +322,7 @@ extern (C++) final class StaticForeach : RootObject foreach (params; pparams) { auto p = aggrfe ? (*aggrfe.parameters)[i] : rangefe.prm; - params.push(new Parameter(p.storageClass, p.type, p.ident, null, null)); + params.push(new Parameter(aloc, p.storageClass, p.type, p.ident, null, null)); } } Expression[2] res; diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d index 03383d1..b05d81d 100644 --- a/gcc/d/dmd/cparse.d +++ b/gcc/d/dmd/cparse.d @@ -626,7 +626,7 @@ final class CParser(AST) : Parser!AST default: // ImportC extensions: parse as a D asm block. - s = parseAsm(); + s = parseAsm(compileEnv.masm); break; } break; @@ -3114,12 +3114,13 @@ final class CParser(AST) : Parser!AST } Identifier id; + const paramLoc = token.loc; auto t = cparseDeclarator(DTR.xparameter, tspec, id, specifier); if (token.value == TOK.__attribute__) cparseGnuAttributes(specifier); if (specifier.mod & MOD.xconst) t = toConst(t); - auto param = new AST.Parameter(specifiersToSTC(LVL.parameter, specifier), + auto param = new AST.Parameter(paramLoc, specifiersToSTC(LVL.parameter, specifier), t, id, null, null); parameters.push(param); if (token.value == TOK.rightParenthesis || token.value == TOK.endOfFile) @@ -3297,8 +3298,10 @@ final class CParser(AST) : Parser!AST nextToken(); else { - error("extended-decl-modifier expected"); - break; + error("extended-decl-modifier expected after `__declspec(`, saw `%s` instead", token.toChars()); + nextToken(); + if (token.value != TOK.rightParenthesis) + break; } } } diff --git a/gcc/d/dmd/cppmangle.d b/gcc/d/dmd/cppmangle.d index 5d74ec4..0c32fad 100644 --- a/gcc/d/dmd/cppmangle.d +++ b/gcc/d/dmd/cppmangle.d @@ -23,7 +23,6 @@ module dmd.cppmangle; -import core.stdc.string; import core.stdc.stdio; import dmd.arraytypes; @@ -46,7 +45,6 @@ import dmd.common.outbuffer; import dmd.root.rootobject; import dmd.root.string; import dmd.target; -import dmd.tokens; import dmd.typesem; import dmd.visitor; diff --git a/gcc/d/dmd/ctfeexpr.d b/gcc/d/dmd/ctfeexpr.d index d355538..c0a2ca6 100644 --- a/gcc/d/dmd/ctfeexpr.d +++ b/gcc/d/dmd/ctfeexpr.d @@ -12,7 +12,6 @@ module dmd.ctfeexpr; import core.stdc.stdio; -import core.stdc.stdlib; import core.stdc.string; import dmd.arraytypes; import dmd.astenums; @@ -306,9 +305,10 @@ UnionExp copyLiteral(Expression e) } if (auto aae = e.isAssocArrayLiteralExp()) { - emplaceExp!(AssocArrayLiteralExp)(&ue, e.loc, copyLiteralArray(aae.keys), copyLiteralArray(aae.values)); + emplaceExp!(AssocArrayLiteralExp)(&ue, aae.loc, copyLiteralArray(aae.keys), copyLiteralArray(aae.values)); AssocArrayLiteralExp r = ue.exp().isAssocArrayLiteralExp(); - r.type = e.type; + r.type = aae.type; + r.lowering = aae.lowering; r.ownedByCtfe = OwnedBy.ctfe; return ue; } diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d index b2aa643..d7cb2b1 100644 --- a/gcc/d/dmd/dcast.d +++ b/gcc/d/dmd/dcast.d @@ -23,7 +23,6 @@ import dmd.declaration; import dmd.dscope; import dmd.dstruct; import dmd.dsymbol; -import dmd.errors; import dmd.escape; import dmd.expression; import dmd.expressionsem; @@ -32,7 +31,6 @@ import dmd.globals; import dmd.hdrgen; import dmd.location; import dmd.impcnvtab; -import dmd.id; import dmd.importc; import dmd.init; import dmd.intrange; @@ -44,7 +42,6 @@ import dmd.root.rmem; import dmd.root.utf; import dmd.tokens; import dmd.typesem; -import dmd.visitor; enum LOG = false; @@ -73,7 +70,7 @@ Expression implicitCastTo(Expression e, Scope* sc, Type t) { // no need for an extra cast when matching is exact - if (match == MATCH.convert && e.type.isTypeNoreturn()) + if (match == MATCH.convert && e.type.isTypeNoreturn() && e.op != EXP.type) { return specialNoreturnCast(e, t); } @@ -174,7 +171,7 @@ Expression implicitCastTo(Expression e, Scope* sc, Type t) { //printf("FuncExp::implicitCastTo type = %p %s, t = %s\n", e.type, e.type ? e.type.toChars() : NULL, t.toChars()); FuncExp fe; - if (e.matchType(t, sc, &fe) > MATCH.nomatch) + if (e.matchType(t, sc, &fe, global.errorSink) > MATCH.nomatch) { return fe; } @@ -1075,7 +1072,7 @@ MATCH implicitConvTo(Expression e, Type t) MATCH visitFunc(FuncExp e) { //printf("FuncExp::implicitConvTo type = %p %s, t = %s\n", e.type, e.type ? e.type.toChars() : NULL, t.toChars()); - MATCH m = e.matchType(t, null, null, 1); + MATCH m = e.matchType(t, null, null, global.errorSinkNull); if (m > MATCH.nomatch) { return m; @@ -1537,7 +1534,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) { return e; } - if (e.type.isTypeNoreturn()) + if (e.type.isTypeNoreturn() && e.op != EXP.type) { return specialNoreturnCast(e, t); } @@ -2489,7 +2486,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) { //printf("FuncExp::castTo type = %s, t = %s\n", e.type.toChars(), t.toChars()); FuncExp fe; - if (e.matchType(t, sc, &fe, 1) > MATCH.nomatch) + if (e.matchType(t, sc, &fe, global.errorSinkNull) > MATCH.nomatch) { return fe; } diff --git a/gcc/d/dmd/dclass.d b/gcc/d/dmd/dclass.d index 20cb82e..b446e77 100644 --- a/gcc/d/dmd/dclass.d +++ b/gcc/d/dmd/dclass.d @@ -19,14 +19,12 @@ import core.stdc.string; import dmd.aggregate; import dmd.arraytypes; import dmd.astenums; -import dmd.attrib; import dmd.gluelayer; import dmd.declaration; import dmd.dscope; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.func; -import dmd.globals; import dmd.id; import dmd.identifier; import dmd.location; @@ -879,6 +877,10 @@ extern (C++) class ClassDeclaration : AggregateDeclaration return 0; } + // opaque class is not abstract if it is not declared abstract + if (!members) + return no(); + for (size_t i = 0; i < members.length; i++) { auto s = (*members)[i]; diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d index 8a91a80..b21678c 100644 --- a/gcc/d/dmd/declaration.d +++ b/gcc/d/dmd/declaration.d @@ -16,7 +16,6 @@ import core.stdc.stdio; import dmd.aggregate; import dmd.arraytypes; import dmd.astenums; -import dmd.attrib; import dmd.ctorflow; import dmd.dclass; import dmd.delegatize; @@ -647,11 +646,11 @@ extern (C++) final class TupleDeclaration : Declaration { buf.printf("_%s_%d", ident.toChars(), i); auto id = Identifier.idPool(buf.extractSlice()); - auto arg = new Parameter(STC.in_, t, id, null); + auto arg = new Parameter(Loc.initial, STC.in_, t, id, null); } else { - auto arg = new Parameter(0, t, null, null, null); + auto arg = new Parameter(Loc.initial, 0, t, null, null, null); } (*args)[i] = arg; if (!t.deco) @@ -1602,6 +1601,8 @@ extern (C++) class VarDeclaration : Declaration { inuse++; _init = _init.initializerSemantic(_scope, type, INITinterpret); + import dmd.semantic2 : lowerStaticAAs; + lowerStaticAAs(this, _scope); _scope = null; inuse--; } diff --git a/gcc/d/dmd/delegatize.d b/gcc/d/dmd/delegatize.d index 559f103..490ef56 100644 --- a/gcc/d/dmd/delegatize.d +++ b/gcc/d/dmd/delegatize.d @@ -21,7 +21,6 @@ import dmd.dsymbol; import dmd.expression; import dmd.expressionsem; import dmd.func; -import dmd.globals; import dmd.init; import dmd.initsem; import dmd.location; diff --git a/gcc/d/dmd/denum.d b/gcc/d/dmd/denum.d index 87b40b8..955a17d 100644 --- a/gcc/d/dmd/denum.d +++ b/gcc/d/dmd/denum.d @@ -24,13 +24,11 @@ import dmd.dscope; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.expression; -import dmd.globals; import dmd.id; import dmd.identifier; import dmd.init; import dmd.location; import dmd.mtype; -import dmd.tokens; import dmd.typesem; import dmd.visitor; diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d index 5948351..7cdafda 100644 --- a/gcc/d/dmd/dinterpret.d +++ b/gcc/d/dmd/dinterpret.d @@ -40,7 +40,6 @@ import dmd.init; import dmd.initsem; import dmd.location; import dmd.mtype; -import dmd.printast; import dmd.root.rmem; import dmd.root.array; import dmd.root.ctfloat; @@ -635,8 +634,6 @@ private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterSta { if (ctfeGlobals.callDepth > CTFE_RECURSION_LIMIT) { - // This is a compiler error. It must not be suppressed. - global.gag = 0; fd.error("CTFE recursion limit exceeded"); e = CTFEExp.cantexp; break; @@ -790,7 +787,7 @@ Expression interpretStatement(UnionExp* pue, Statement s, InterState* istate) istate.start = null; } - s.error("statement `%s` cannot be interpreted at compile time", s.toChars()); + error(s.loc, "statement `%s` cannot be interpreted at compile time", s.toChars()); result = CTFEExp.cantexp; } @@ -976,7 +973,7 @@ Expression interpretStatement(UnionExp* pue, Statement s, InterState* istate) { // To support this, we need to copy all the closure vars // into the delegate literal. - s.error("closures are not yet supported in CTFE"); + error(s.loc, "closures are not yet supported in CTFE"); result = CTFEExp.cantexp; return; } @@ -1259,7 +1256,7 @@ Expression interpretStatement(UnionExp* pue, Statement s, InterState* istate) if (!scase) { if (s.hasNoDefault) - s.error("no `default` or `case` for `%s` in `switch` statement", econdition.toChars()); + error(s.loc, "no `default` or `case` for `%s` in `switch` statement", econdition.toChars()); scase = s.sdefault; } @@ -1599,7 +1596,7 @@ Expression interpretStatement(UnionExp* pue, Statement s, InterState* istate) return; istate.start = null; } - s.error("`asm` statements cannot be interpreted at compile time"); + error(s.loc, "`asm` statements cannot be interpreted at compile time"); result = CTFEExp.cantexp; } @@ -6105,7 +6102,8 @@ public: result = interpret(&ue, e.msg, istate); if (exceptionOrCant(result)) return; - if (StringExp se = result.isStringExp()) + result = scrubReturnValue(e.loc, result); + if (StringExp se = result.toStringExp()) e.error("%s", se.toStringz().ptr); else e.error("%s", result.toChars()); diff --git a/gcc/d/dmd/dmacro.d b/gcc/d/dmd/dmacro.d index 6fc23e9..6e6c4b1 100644 --- a/gcc/d/dmd/dmacro.d +++ b/gcc/d/dmd/dmacro.d @@ -13,11 +13,12 @@ module dmd.dmacro; import core.stdc.ctype; import core.stdc.string; -import dmd.doc; import dmd.common.outbuffer; import dmd.root.rmem; -extern (C++) struct MacroTable +@trusted: + +struct MacroTable { /********************************** * Define name=text macro. @@ -26,7 +27,7 @@ extern (C++) struct MacroTable * name = name of macro * text = text of macro */ - extern (D) void define(const(char)[] name, const(char)[] text) nothrow pure @safe + void define(const(char)[] name, const(char)[] text) nothrow pure @safe { //printf("MacroTable::define('%.*s' = '%.*s')\n", cast(int)name.length, name.ptr, text.length, text.ptr); if (auto table = name in mactab) @@ -37,13 +38,16 @@ extern (C++) struct MacroTable mactab[name] = new Macro(name, text); } + alias fp_t = bool function(const(char)* p) @nogc nothrow pure; + /***************************************************** * Look for macros in buf and expand them in place. * Only look at the text in buf from start to pend. * * Returns: `true` on success, `false` when the recursion limit was reached */ - extern (D) bool expand(ref OutBuffer buf, size_t start, ref size_t pend, const(char)[] arg, int recursionLimit) nothrow pure + bool expand(ref OutBuffer buf, size_t start, ref size_t pend, const(char)[] arg, int recursionLimit, + fp_t isIdStart, fp_t isIdTail) nothrow pure { version (none) { @@ -101,7 +105,7 @@ extern (C++) struct MacroTable end += marg.length - 2; // Scan replaced text for further expansion size_t mend = u + marg.length; - const success = expand(buf, u, mend, null, recursionLimit); + const success = expand(buf, u, mend, null, recursionLimit, isIdStart, isIdTail); if (!success) return false; end += mend - (u + marg.length); @@ -119,7 +123,7 @@ extern (C++) struct MacroTable end += -2 + 2 + marg.length + 2; // Scan replaced text for further expansion size_t mend = u + 2 + marg.length; - const success = expand(buf, u + 2, mend, null, recursionLimit); + const success = expand(buf, u + 2, mend, null, recursionLimit, isIdStart, isIdTail); if (!success) return false; end += mend - (u + 2 + marg.length); @@ -149,7 +153,7 @@ extern (C++) struct MacroTable /* Scan forward to find end of macro name and * beginning of macro argument (marg). */ - for (v = u + 2; v < end; v += utfStride(p + v)) + for (v = u + 2; v < end; v += utfStride(p[v])) { if (!isIdTail(p + v)) { @@ -228,7 +232,7 @@ extern (C++) struct MacroTable // Scan replaced text for further expansion m.inuse++; size_t mend = v + 1 + 2 + m.text.length + 2; - const success = expand(buf, v + 1, mend, marg, recursionLimit); + const success = expand(buf, v + 1, mend, marg, recursionLimit, isIdStart, isIdTail); if (!success) return false; end += mend - (v + 1 + 2 + m.text.length + 2); @@ -260,7 +264,7 @@ extern (C++) struct MacroTable private: - extern (D) Macro* search(const(char)[] name) @nogc nothrow pure @safe + Macro* search(const(char)[] name) @nogc nothrow pure @safe { //printf("Macro::search(%.*s)\n", cast(int)name.length, name.ptr); if (auto table = name in mactab) @@ -299,7 +303,7 @@ struct Macro * copy allocated with mem.xmalloc() */ -char[] memdup(const(char)[] p) nothrow pure @trusted +char[] memdup(const(char)[] p) nothrow pure { size_t len = p.length; return (cast(char*)memcpy(mem.xmalloc(len), p.ptr, len))[0 .. len]; @@ -424,3 +428,35 @@ Largstart: //printf("extractArg%d('%.*s') = '%.*s'\n", n, cast(int)end, p, cast(int)marg.length, marg.ptr); return v; } + +/***************************************** + * Get number of UTF-8 code units in code point that starts with `c` + * Params: + * c = starting code unit + * Returns: number of UTF-8 code units (i.e. bytes), else 1 on invalid UTF start + */ +@safe +int utfStride(char c) @nogc nothrow pure +{ + return + c < 0x80 ? 1 : + c < 0xC0 ? 1 : // invalid UTF start + c < 0xE0 ? 2 : + c < 0xF0 ? 3 : + c < 0xF8 ? 4 : + c < 0xFC ? 5 : + c < 0xFE ? 6 : + 1; // invalid UTF start +} + +unittest +{ + assert(utfStride(0) == 1); + assert(utfStride(0x80) == 1); + assert(utfStride(0xC0) == 2); + assert(utfStride(0xE0) == 3); + assert(utfStride(0xF0) == 4); + assert(utfStride(0xF8) == 5); + assert(utfStride(0xFC) == 6); + assert(utfStride(0xFE) == 1); +} diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d index 4a2e15c..eb68b31 100644 --- a/gcc/d/dmd/dmodule.d +++ b/gcc/d/dmd/dmodule.d @@ -780,7 +780,9 @@ extern (C++) final class Module : Package { filetype = FileType.c; + global.compileEnv.masm = target.os == Target.OS.Windows && !target.omfobj; // Microsoft inline assembler format scope p = new CParser!AST(this, buf, cast(bool) docfile, global.errorSink, target.c, &defines, &global.compileEnv); + global.compileEnv.masm = false; p.nextToken(); checkCompiledImport(); members = p.parseModule(); @@ -1253,7 +1255,7 @@ extern (C++) final class Module : Package // Back end int doppelganger; // sub-module Symbol* cov; // private uint[] __coverage; - uint* covb; // bit array of valid code line numbers + uint[] covb; // bit array of valid code line numbers Symbol* sictor; // module order independent constructor Symbol* sctor; // module constructor Symbol* sdtor; // module destructor diff --git a/gcc/d/dmd/doc.d b/gcc/d/dmd/doc.d index 887fd6c..5488d5a 100644 --- a/gcc/d/dmd/doc.d +++ b/gcc/d/dmd/doc.d @@ -52,9 +52,11 @@ import dmd.root.rmem; import dmd.root.string; import dmd.root.utf; import dmd.tokens; -import dmd.utils; import dmd.visitor; +private: + +public struct Escape { const(char)[][char.max] strings; @@ -94,7 +96,7 @@ struct Escape /*********************************************************** */ -private class Section +class Section { const(char)[] name; const(char)[] body_; @@ -105,7 +107,7 @@ private class Section assert(0); } - void write(Loc loc, DocComment* dc, Scope* sc, Dsymbols* a, OutBuffer* buf) + void write(Loc loc, DocComment* dc, Scope* sc, Dsymbols* a, ref OutBuffer buf) { assert(a.length); if (name.length) @@ -151,16 +153,16 @@ private class Section size_t o = buf.length; buf.write(body_); escapeStrayParenthesis(loc, buf, o, true, sc.eSink); - highlightText(sc, a, loc, *buf, o); + highlightText(sc, a, loc, buf, o); buf.writestring(")"); } } /*********************************************************** */ -private final class ParamSection : Section +final class ParamSection : Section { - override void write(Loc loc, DocComment* dc, Scope* sc, Dsymbols* a, OutBuffer* buf) + override void write(Loc loc, DocComment* dc, Scope* sc, Dsymbols* a, ref OutBuffer buf) { assert(a.length); Dsymbol s = (*a)[0]; // test @@ -241,7 +243,7 @@ private final class ParamSection : Section } else if (fparam && fparam.type && fparam.ident) { - .toCBuffer(fparam.type, buf, fparam.ident, &hgs); + toCBuffer(fparam.type, buf, fparam.ident, hgs); } else { @@ -257,7 +259,7 @@ private final class ParamSection : Section buf.write(namestart[0 .. namelen]); } escapeStrayParenthesis(loc, buf, o, true, sc.eSink); - highlightCode(sc, a, *buf, o); + highlightCode(sc, a, buf, o); } buf.writestring(")"); buf.writestring("$(DDOC_PARAM_DESC "); @@ -265,7 +267,7 @@ private final class ParamSection : Section size_t o = buf.length; buf.write(textstart[0 .. textlen]); escapeStrayParenthesis(loc, buf, o, true, sc.eSink); - highlightText(sc, a, loc, *buf, o); + highlightText(sc, a, loc, buf, o); } buf.writestring(")"); } @@ -317,19 +319,19 @@ private final class ParamSection : Section /*********************************************************** */ -private final class MacroSection : Section +final class MacroSection : Section { - override void write(Loc loc, DocComment* dc, Scope* sc, Dsymbols* a, OutBuffer* buf) + override void write(Loc loc, DocComment* dc, Scope* sc, Dsymbols* a, ref OutBuffer buf) { //printf("MacroSection::write()\n"); DocComment.parseMacros(dc.escapetable, *dc.pmacrotable, body_); } } -private alias Sections = Array!(Section); +alias Sections = Array!(Section); // Workaround for missing Parameter instance for variadic params. (it's unnecessary to instantiate one). -private bool isCVariadicParameter(Dsymbols* a, const(char)[] p) @safe +bool isCVariadicParameter(Dsymbols* a, const(char)[] p) @safe { foreach (member; *a) { @@ -340,7 +342,7 @@ private bool isCVariadicParameter(Dsymbols* a, const(char)[] p) @safe return false; } -private Dsymbol getEponymousMember(TemplateDeclaration td) @safe +Dsymbol getEponymousMember(TemplateDeclaration td) @safe { if (!td.onemember) return null; @@ -355,7 +357,7 @@ private Dsymbol getEponymousMember(TemplateDeclaration td) @safe return null; } -private TemplateDeclaration getEponymousParent(Dsymbol s) @safe +TemplateDeclaration getEponymousParent(Dsymbol s) @safe { if (!s.parent) return null; @@ -363,40 +365,46 @@ private TemplateDeclaration getEponymousParent(Dsymbol s) @safe return (td && getEponymousMember(td)) ? td : null; } -private immutable ddoc_default = import("default_ddoc_theme." ~ ddoc_ext); -private immutable ddoc_decl_s = "$(DDOC_DECL "; -private immutable ddoc_decl_e = ")\n"; -private immutable ddoc_decl_dd_s = "$(DDOC_DECL_DD "; -private immutable ddoc_decl_dd_e = ")\n"; +immutable ddoc_default = import("default_ddoc_theme." ~ ddoc_ext); +immutable ddoc_decl_s = "$(DDOC_DECL "; +immutable ddoc_decl_e = ")\n"; +immutable ddoc_decl_dd_s = "$(DDOC_DECL_DD "; +immutable ddoc_decl_dd_e = ")\n"; /**************************************************** + * Generate Ddoc file for Module m. + * Params: + * m = Module + * ddoctext_ptr = combined text of .ddoc files for macro definitions + * ddoctext_length = extant of ddoctext_ptr + * datetime = charz returned by ctime() + * eSink = send error messages to eSink + * outbuf = append the Ddoc text to this */ -extern(C++) void gendocfile(Module m, ErrorSink eSink) +public +extern(C++) void gendocfile(Module m, const char* ddoctext_ptr, size_t ddoctext_length, const char* datetime, ErrorSink eSink, ref OutBuffer outbuf) { - __gshared OutBuffer mbuf; - __gshared int mbuf_done; - OutBuffer buf; - //printf("Module::gendocfile()\n"); - if (!mbuf_done) // if not already read the ddoc files - { - mbuf_done = 1; - // Use our internal default - mbuf.writestring(ddoc_default); - // Override with DDOCFILE specified in the sc.ini file - char* p = getenv("DDOCFILE"); - if (p) - global.params.ddoc.files.shift(p); - // Override with the ddoc macro files from the command line - for (size_t i = 0; i < global.params.ddoc.files.length; i++) - { - auto buffer = readFile(m.loc, global.params.ddoc.files[i]); - // BUG: convert file contents to UTF-8 before use - const data = buffer.data; - //printf("file: '%.*s'\n", cast(int)data.length, data.ptr); - mbuf.write(data); - } - } - DocComment.parseMacros(m.escapetable, m.macrotable, mbuf[]); + gendocfile(m, ddoctext_ptr[0 .. ddoctext_length], datetime, eSink, outbuf); +} + +/**************************************************** + * Generate Ddoc text for Module `m` and append it to `outbuf`. + * Params: + * m = Module + * ddoctext = combined text of .ddoc files for macro definitions + * datetime = charz returned by ctime() + * eSink = send error messages to eSink + * outbuf = append the Ddoc text to this + */ +public +void gendocfile(Module m, const char[] ddoctext, const char* datetime, ErrorSink eSink, ref OutBuffer outbuf) +{ + // Load internal default macros first + DocComment.parseMacros(m.escapetable, m.macrotable, ddoc_default[]); + + // Ddoc files override default macros + DocComment.parseMacros(m.escapetable, m.macrotable, ddoctext); + Scope* sc = Scope.createGlobal(m, eSink); // create root scope DocComment* dc = DocComment.parse(m, m.comment); dc.pmacrotable = &m.macrotable; @@ -409,14 +417,9 @@ extern(C++) void gendocfile(Module m, ErrorSink eSink) m.macrotable.define("TITLE", p); } // Set time macros - { - time_t t; - time(&t); - char* p = ctime(&t); - p = mem.xstrdup(p); - m.macrotable.define("DATETIME", p.toDString()); - m.macrotable.define("YEAR", p[20 .. 20 + 4]); - } + m.macrotable.define("DATETIME", datetime[0 .. 26]); + m.macrotable.define("YEAR", datetime[20 .. 20 + 4]); + const srcfilename = m.srcfile.toString(); m.macrotable.define("SRCFILENAME", srcfilename); const docfilename = m.docfile.toString(); @@ -426,6 +429,8 @@ extern(C++) void gendocfile(Module m, ErrorSink eSink) dc.copyright.nooutput = 1; m.macrotable.define("COPYRIGHT", dc.copyright.body_); } + + OutBuffer buf; if (m.filetype == FileType.ddoc) { const ploc = m.md ? &m.md.loc : &m.loc; @@ -433,14 +438,14 @@ extern(C++) void gendocfile(Module m, ErrorSink eSink) if (!loc.filename) loc.filename = srcfilename.ptr; - size_t commentlen = strlen(cast(char*)m.comment); + size_t commentlen = m.comment ? strlen(cast(char*)m.comment) : 0; Dsymbols a; // https://issues.dlang.org/show_bug.cgi?id=9764 // Don't push m in a, to prevent emphasize ddoc file name. if (dc.macros) { commentlen = dc.macros.name.ptr - m.comment; - dc.macros.write(loc, dc, sc, &a, &buf); + dc.macros.write(loc, dc, sc, &a, buf); } buf.write(m.comment[0 .. commentlen]); highlightText(sc, &a, loc, buf, 0); @@ -449,73 +454,47 @@ extern(C++) void gendocfile(Module m, ErrorSink eSink) { Dsymbols a; a.push(m); - dc.writeSections(sc, &a, &buf); + dc.writeSections(sc, &a, buf); emitMemberComments(m, buf, sc); } //printf("BODY= '%.*s'\n", cast(int)buf.length, buf.data); m.macrotable.define("BODY", buf[]); + OutBuffer buf2; buf2.writestring("$(DDOC)"); size_t end = buf2.length; - const success = m.macrotable.expand(buf2, 0, end, null, global.recursionLimit); + // Expand buf in place with macro expansions + const success = m.macrotable.expand(buf2, 0, end, null, global.recursionLimit, &isIdStart, &isIdTail); if (!success) eSink.error(Loc.initial, "DDoc macro expansion limit exceeded; more than %d expansions.", global.recursionLimit); - version (all) + /* Remove all the escape sequences from buf, + * and make CR-LF the newline. + */ + const slice = buf2[]; + outbuf.reserve(slice.length); + auto p = slice.ptr; + for (size_t j = 0; j < slice.length; j++) { - /* Remove all the escape sequences from buf2, - * and make CR-LF the newline. - */ + char c = p[j]; + if (c == 0xFF && j + 1 < slice.length) { - const slice = buf2[]; - buf.setsize(0); - buf.reserve(slice.length); - auto p = slice.ptr; - for (size_t j = 0; j < slice.length; j++) - { - char c = p[j]; - if (c == 0xFF && j + 1 < slice.length) - { - j++; - continue; - } - if (c == '\n') - buf.writeByte('\r'); - else if (c == '\r') - { - buf.writestring("\r\n"); - if (j + 1 < slice.length && p[j + 1] == '\n') - { - j++; - } - continue; - } - buf.writeByte(c); - } + j++; + continue; } - writeFile(m.loc, m.docfile.toString(), buf[]); - } - else - { - /* Remove all the escape sequences from buf2 - */ + if (c == '\n') + outbuf.writeByte('\r'); + else if (c == '\r') { - size_t i = 0; - char* p = buf2.data; - for (size_t j = 0; j < buf2.length; j++) + outbuf.writestring("\r\n"); + if (j + 1 < slice.length && p[j + 1] == '\n') { - if (p[j] == 0xFF && j + 1 < buf2.length) - { - j++; - continue; - } - p[i] = p[j]; - i++; + j++; } - buf2.setsize(i); + continue; } - writeFile(m.loc, m.docfile.toString(), buf2[]); + outbuf.writeByte(c); } } @@ -526,11 +505,12 @@ extern(C++) void gendocfile(Module m, ErrorSink eSink) * to preserve text literally. This also means macros in the * text won't be expanded. */ -void escapeDdocString(OutBuffer* buf, size_t start) +public +void escapeDdocString(ref OutBuffer buf, size_t start) { for (size_t u = start; u < buf.length; u++) { - char c = (*buf)[u]; + char c = buf[u]; switch (c) { case '$': @@ -568,14 +548,14 @@ void escapeDdocString(OutBuffer* buf, size_t start) * directly preceeded by a backslash with $(LPAREN) or $(RPAREN) instead of * counting them as stray parentheses */ -private void escapeStrayParenthesis(Loc loc, OutBuffer* buf, size_t start, bool respectBackslashEscapes, ErrorSink eSink) +private void escapeStrayParenthesis(Loc loc, ref OutBuffer buf, size_t start, bool respectBackslashEscapes, ErrorSink eSink) { uint par_open = 0; char inCode = 0; bool atLineStart = true; for (size_t u = start; u < buf.length; u++) { - char c = (*buf)[u]; + char c = buf[u]; switch (c) { case '(': @@ -619,7 +599,7 @@ private void escapeStrayParenthesis(Loc loc, OutBuffer* buf, size_t start, bool // Issue 15465: don't try to escape unbalanced parens inside code // blocks. int numdash = 1; - for (++u; u < buf.length && (*buf)[u] == c; ++u) + for (++u; u < buf.length && buf[u] == c; ++u) ++numdash; --u; if (c == '`' || (atLineStart && numdash >= 3)) @@ -635,14 +615,14 @@ private void escapeStrayParenthesis(Loc loc, OutBuffer* buf, size_t start, bool // replace backslash-escaped parens with their macros if (!inCode && respectBackslashEscapes && u+1 < buf.length) { - if ((*buf)[u+1] == '(' || (*buf)[u+1] == ')') + if (buf[u+1] == '(' || buf[u+1] == ')') { - const paren = (*buf)[u+1] == '(' ? "$(LPAREN)" : "$(RPAREN)"; + const paren = buf[u+1] == '(' ? "$(LPAREN)" : "$(RPAREN)"; buf.remove(u, 2); //remove the \) buf.insert(u, paren); //insert this instead u += 8; //skip over newly inserted macro } - else if ((*buf)[u+1] == '\\') + else if (buf[u+1] == '\\') ++u; } break; @@ -657,7 +637,7 @@ private void escapeStrayParenthesis(Loc loc, OutBuffer* buf, size_t start, bool for (size_t u = buf.length; u > start;) { u--; - char c = (*buf)[u]; + char c = buf[u]; switch (c) { case ')': @@ -683,14 +663,14 @@ private void escapeStrayParenthesis(Loc loc, OutBuffer* buf, size_t start, bool // Basically, this is to skip over things like private{} blocks in a struct or // class definition that don't add any components to the qualified name. -private Scope* skipNonQualScopes(Scope* sc) @safe +Scope* skipNonQualScopes(Scope* sc) @safe { while (sc && !sc.scopesym) sc = sc.enclosing; return sc; } -private bool emitAnchorName(ref OutBuffer buf, Dsymbol s, Scope* sc, bool includeParent) +bool emitAnchorName(ref OutBuffer buf, Dsymbol s, Scope* sc, bool includeParent) { if (!s || s.isPackage() || s.isModule()) return false; @@ -721,7 +701,7 @@ private bool emitAnchorName(ref OutBuffer buf, Dsymbol s, Scope* sc, bool includ return true; } -private void emitAnchor(ref OutBuffer buf, Dsymbol s, Scope* sc, bool forHeader = false) +void emitAnchor(ref OutBuffer buf, Dsymbol s, Scope* sc, bool forHeader = false) { Identifier ident; { @@ -846,7 +826,7 @@ private void emitAnchor(ref OutBuffer buf, Dsymbol s, Scope* sc, bool forHeader /******************************* emitComment **********************************/ /** Get leading indentation from 'src' which represents lines of code. */ -private size_t getCodeIndent(const(char)* src) +size_t getCodeIndent(const(char)* src) { while (src && (*src == '\r' || *src == '\n')) ++src; // skip until we find the first non-empty line @@ -860,7 +840,7 @@ private size_t getCodeIndent(const(char)* src) } /** Recursively expand template mixin member docs into the scope. */ -private void expandTemplateMixinComments(TemplateMixin tm, ref OutBuffer buf, Scope* sc) +void expandTemplateMixinComments(TemplateMixin tm, ref OutBuffer buf, Scope* sc) { if (!tm.semanticRun) tm.dsymbolSemantic(sc); @@ -879,7 +859,7 @@ private void expandTemplateMixinComments(TemplateMixin tm, ref OutBuffer buf, Sc } } -private void emitMemberComments(ScopeDsymbol sds, ref OutBuffer buf, Scope* sc) +void emitMemberComments(ScopeDsymbol sds, ref OutBuffer buf, Scope* sc) { if (!sds.members) return; @@ -920,14 +900,14 @@ private void emitMemberComments(ScopeDsymbol sds, ref OutBuffer buf, Scope* sc) buf.writestring(")"); } -private void emitVisibility(ref OutBuffer buf, Import i) +void emitVisibility(ref OutBuffer buf, Import i) { // imports are private by default, which is different from other declarations // so they should explicitly show their visibility emitVisibility(buf, i.visibility); } -private void emitVisibility(ref OutBuffer buf, Declaration d) +void emitVisibility(ref OutBuffer buf, Declaration d) { auto vis = d.visibility; if (vis.kind != Visibility.Kind.undefined && vis.kind != Visibility.Kind.public_) @@ -936,13 +916,13 @@ private void emitVisibility(ref OutBuffer buf, Declaration d) } } -private void emitVisibility(ref OutBuffer buf, Visibility vis) +void emitVisibility(ref OutBuffer buf, Visibility vis) { - visibilityToBuffer(&buf, vis); + visibilityToBuffer(buf, vis); buf.writeByte(' '); } -private void emitComment(Dsymbol s, ref OutBuffer buf, Scope* sc) +void emitComment(Dsymbol s, ref OutBuffer buf, Scope* sc) { extern (C++) final class EmitComment : Visitor { @@ -1037,7 +1017,7 @@ private void emitComment(Dsymbol s, ref OutBuffer buf, Scope* sc) // Put the ddoc comment as the document 'description' buf.writestring(ddoc_decl_dd_s); { - dc.writeSections(sc, &dc.a, buf); + dc.writeSections(sc, &dc.a, *buf); if (ScopeDsymbol sds = dc.a[0].isScopeDsymbol()) emitMemberComments(sds, *buf, sc); } @@ -1226,7 +1206,7 @@ private void emitComment(Dsymbol s, ref OutBuffer buf, Scope* sc) s.accept(v); } -private void toDocBuffer(Dsymbol s, ref OutBuffer buf, Scope* sc) +void toDocBuffer(Dsymbol s, ref OutBuffer buf, Scope* sc) { extern (C++) final class ToDocBuffer : Visitor { @@ -1246,7 +1226,7 @@ private void toDocBuffer(Dsymbol s, ref OutBuffer buf, Scope* sc) //printf("Dsymbol::toDocbuffer() %s\n", s.toChars()); HdrGenState hgs; hgs.ddoc = true; - .toCBuffer(s, buf, &hgs); + toCBuffer(s, *buf, hgs); } void prefix(Dsymbol s) @@ -1296,7 +1276,7 @@ private void toDocBuffer(Dsymbol s, ref OutBuffer buf, Scope* sc) HdrGenState hgs; hgs.ddoc = true; emitVisibility(*buf, i); - .toCBuffer(i, buf, &hgs); + toCBuffer(i, *buf, hgs); } override void visit(Declaration d) @@ -1315,10 +1295,10 @@ private void toDocBuffer(Dsymbol s, ref OutBuffer buf, Scope* sc) Type origType = d.originalType ? d.originalType : d.type; if (origType.ty == Tfunction) { - functionToBufferFull(cast(TypeFunction)origType, buf, d.ident, &hgs, td); + functionToBufferFull(cast(TypeFunction)origType, *buf, d.ident, &hgs, td); } else - .toCBuffer(origType, buf, d.ident, &hgs); + toCBuffer(origType, *buf, d.ident, hgs); } else buf.writestring(d.ident.toString()); @@ -1331,7 +1311,7 @@ private void toDocBuffer(Dsymbol s, ref OutBuffer buf, Scope* sc) { if (i) buf.writestring(", "); - toCBuffer((*td.origParameters)[i], buf, &hgs); + toCBuffer((*td.origParameters)[i], *buf, hgs); } } buf.writeByte(')'); @@ -1345,7 +1325,7 @@ private void toDocBuffer(Dsymbol s, ref OutBuffer buf, Scope* sc) buf.writestring("$(DDOC_CONSTRAINT "); } - .toCBuffer(td.constraint, buf, &hgs); + toCBuffer(td.constraint, *buf, hgs); if (noFuncDecl) { @@ -1505,7 +1485,7 @@ private void toDocBuffer(Dsymbol s, ref OutBuffer buf, Scope* sc) else { HdrGenState hgs; - .toCBuffer(bc.type, buf, null, &hgs); + toCBuffer(bc.type, *buf, null, hgs); } } buf.writestring(";\n"); @@ -1520,7 +1500,7 @@ private void toDocBuffer(Dsymbol s, ref OutBuffer buf, Scope* sc) { buf.writestring(": $(DDOC_ENUM_BASETYPE "); HdrGenState hgs; - .toCBuffer(ed.memtype, buf, null, &hgs); + toCBuffer(ed.memtype, *buf, null, hgs); buf.writestring(")"); } buf.writestring(";\n"); @@ -1540,6 +1520,7 @@ private void toDocBuffer(Dsymbol s, ref OutBuffer buf, Scope* sc) /*********************************************************** */ +public struct DocComment { Sections sections; // Section*[] @@ -1872,7 +1853,7 @@ struct DocComment } } - void writeSections(Scope* sc, Dsymbols* a, OutBuffer* buf) + void writeSections(Scope* sc, Dsymbols* a, ref OutBuffer buf) { assert(a.length); //printf("DocComment::writeSections()\n"); @@ -1897,7 +1878,7 @@ struct DocComment size_t o = buf.length; buf.write(sec.body_); escapeStrayParenthesis(loc, buf, o, true, sc.eSink); - highlightText(sc, a, loc, *buf, o); + highlightText(sc, a, loc, buf, o); buf.writestring(")"); } else @@ -1928,7 +1909,7 @@ struct DocComment buf.writestring("----\n"); buf.writestring(codedoc); buf.writestring("----\n"); - highlightText(sc, a, loc, *buf, o); + highlightText(sc, a, loc, buf, o); } buf.writestring(")"); } @@ -1948,7 +1929,7 @@ struct DocComment /***************************************** * Return true if comment consists entirely of "ditto". */ -private bool isDitto(const(char)* comment) +bool isDitto(const(char)* comment) { if (comment) { @@ -1962,13 +1943,13 @@ private bool isDitto(const(char)* comment) /********************************************** * Skip white space. */ -private const(char)* skipwhitespace(const(char)* p) +const(char)* skipwhitespace(const(char)* p) { return skipwhitespace(p.toDString).ptr; } /// Ditto -private const(char)[] skipwhitespace(const(char)[] p) @safe +const(char)[] skipwhitespace(const(char)[] p) @safe { foreach (idx, char c; p) { @@ -1993,7 +1974,7 @@ private const(char)[] skipwhitespace(const(char)[] p) @safe * chars = the characters to skip; order is unimportant * Returns: the index after skipping characters. */ -private size_t skipChars(ref OutBuffer buf, size_t i, string chars) @safe +size_t skipChars(ref OutBuffer buf, size_t i, string chars) @safe { Outer: foreach (j, c; buf[][i..$]) @@ -2028,7 +2009,7 @@ unittest { * r = the string to replace `c` with * Returns: `s` with `c` replaced with `r` */ -private inout(char)[] replaceChar(inout(char)[] s, char c, string r) pure @safe +inout(char)[] replaceChar(inout(char)[] s, char c, string r) pure @safe { int count = 0; foreach (char sc; s) @@ -2070,7 +2051,7 @@ unittest * s = the string to lowercase * Returns: the lowercase version of the string or the original if already lowercase */ -private string toLowercase(string s) pure @safe +string toLowercase(string s) pure @safe { string lower; foreach (size_t i; 0..s.length) @@ -2112,7 +2093,7 @@ unittest * to = the index within `buf` to stop counting at, exclusive * Returns: the indent */ -private int getMarkdownIndent(ref OutBuffer buf, size_t from, size_t to) @safe +int getMarkdownIndent(ref OutBuffer buf, size_t from, size_t to) @safe { const slice = buf[]; if (to > slice.length) @@ -2158,7 +2139,7 @@ size_t skiptoident(ref OutBuffer buf, size_t i) @safe /************************************************ * Scan forward past end of identifier. */ -private size_t skippastident(ref OutBuffer buf, size_t i) @safe +size_t skippastident(ref OutBuffer buf, size_t i) @safe { const slice = buf[]; while (i < slice.length) @@ -2188,7 +2169,7 @@ private size_t skippastident(ref OutBuffer buf, size_t i) @safe * Scan forward past end of an identifier that might * contain dots (e.g. `abc.def`) */ -private size_t skipPastIdentWithDots(ref OutBuffer buf, size_t i) @safe +size_t skipPastIdentWithDots(ref OutBuffer buf, size_t i) @safe { const slice = buf[]; bool lastCharWasDot; @@ -2250,7 +2231,7 @@ private size_t skipPastIdentWithDots(ref OutBuffer buf, size_t i) @safe * i if not a URL * index just past it if it is a URL */ -private size_t skippastURL(ref OutBuffer buf, size_t i) +size_t skippastURL(ref OutBuffer buf, size_t i) { const slice = buf[][i .. $]; size_t j; @@ -2295,7 +2276,7 @@ Lno: * i = an index within `buf`. If `i` is after `iAt` then it gets * reduced by the length of the removed macro. */ -private void removeBlankLineMacro(ref OutBuffer buf, ref size_t iAt, ref size_t i) +void removeBlankLineMacro(ref OutBuffer buf, ref size_t iAt, ref size_t i) { if (!iAt) return; @@ -2320,7 +2301,7 @@ private void removeBlankLineMacro(ref OutBuffer buf, ref size_t iAt, ref size_t * loc = the current location within the file * Returns: whether a thematic break was replaced */ -private bool replaceMarkdownThematicBreak(ref OutBuffer buf, ref size_t i, size_t iLineStart, const ref Loc loc) +bool replaceMarkdownThematicBreak(ref OutBuffer buf, ref size_t i, size_t iLineStart, const ref Loc loc) { const slice = buf[]; @@ -2356,7 +2337,7 @@ private bool replaceMarkdownThematicBreak(ref OutBuffer buf, ref size_t i, size_ * the detected heading level from 1 to 6, or * 0 if not at an ATX heading */ -private int detectAtxHeadingLevel(ref OutBuffer buf, const size_t i) @safe +int detectAtxHeadingLevel(ref OutBuffer buf, const size_t i) @safe { const iHeadingStart = i; const iAfterHashes = skipChars(buf, i, "#"); @@ -2380,7 +2361,7 @@ private int detectAtxHeadingLevel(ref OutBuffer buf, const size_t i) @safe * buf = an OutBuffer containing the DDoc * i = the index within `buf` to start looking for a suffix at */ -private void removeAnyAtxHeadingSuffix(ref OutBuffer buf, size_t i) +void removeAnyAtxHeadingSuffix(ref OutBuffer buf, size_t i) { size_t j = i; size_t iSuffixStart = 0; @@ -2425,7 +2406,7 @@ private void removeAnyAtxHeadingSuffix(ref OutBuffer buf, size_t i) * headingLevel = the level (1-6) of heading to end. Is set to `0` when this * function ends. */ -private void endMarkdownHeading(ref OutBuffer buf, size_t iStart, ref size_t iEnd, const ref Loc loc, ref int headingLevel) +void endMarkdownHeading(ref OutBuffer buf, size_t iStart, ref size_t iEnd, const ref Loc loc, ref int headingLevel) { char[5] heading = "$(H0 "; heading[3] = cast(char) ('0' + headingLevel); @@ -2446,7 +2427,7 @@ private void endMarkdownHeading(ref OutBuffer buf, size_t iStart, ref size_t iEn * quoteLevel = the current quote level. Is set to `0` when this function ends. * Returns: the amount that `i` was moved */ -private size_t endAllMarkdownQuotes(ref OutBuffer buf, size_t i, ref int quoteLevel) +size_t endAllMarkdownQuotes(ref OutBuffer buf, size_t i, ref int quoteLevel) { const length = quoteLevel; for (; quoteLevel > 0; --quoteLevel) @@ -2468,7 +2449,7 @@ private size_t endAllMarkdownQuotes(ref OutBuffer buf, size_t i, ref int quoteLe * `0` when this function ends. * Returns: the amount that `i` was moved */ -private size_t endAllListsAndQuotes(ref OutBuffer buf, ref size_t i, ref MarkdownList[] nestedLists, ref int quoteLevel, out int quoteMacroLevel) +size_t endAllListsAndQuotes(ref OutBuffer buf, ref size_t i, ref MarkdownList[] nestedLists, ref int quoteLevel, out int quoteMacroLevel) { quoteMacroLevel = 0; const i0 = i; @@ -2487,7 +2468,7 @@ private size_t endAllListsAndQuotes(ref OutBuffer buf, ref size_t i, ref Markdow * downToLevel = the length within `inlineDelimiters`` to reduce emphasis to * Returns: the number of characters added to the buffer by the replacements */ -private size_t replaceMarkdownEmphasis(ref OutBuffer buf, const ref Loc loc, ref MarkdownDelimiter[] inlineDelimiters, int downToLevel = 0) +size_t replaceMarkdownEmphasis(ref OutBuffer buf, const ref Loc loc, ref MarkdownDelimiter[] inlineDelimiters, int downToLevel = 0) { size_t replaceEmphasisPair(ref MarkdownDelimiter start, ref MarkdownDelimiter end) { @@ -2566,7 +2547,7 @@ private size_t replaceMarkdownEmphasis(ref OutBuffer buf, const ref Loc loc, ref /**************************************************** */ -private bool isIdentifier(Dsymbols* a, const(char)[] s) @safe +bool isIdentifier(Dsymbols* a, const(char)[] s) @safe { foreach (member; *a) { @@ -2608,7 +2589,7 @@ private bool isIdentifier(Dsymbols* a, const(char)[] s) @safe /**************************************************** */ -private bool isKeyword(const(char)[] str) @safe +bool isKeyword(const(char)[] str) @safe { immutable string[3] table = ["true", "false", "null"]; foreach (s; table) @@ -2621,7 +2602,7 @@ private bool isKeyword(const(char)[] str) @safe /**************************************************** */ -private TypeFunction isTypeFunction(Dsymbol s) @safe +TypeFunction isTypeFunction(Dsymbol s) @safe { FuncDeclaration f = s.isFuncDeclaration(); /* f.type may be NULL for template members. @@ -2637,7 +2618,7 @@ private TypeFunction isTypeFunction(Dsymbol s) @safe /**************************************************** */ -private Parameter isFunctionParameter(Dsymbol s, const(char)[] str) @safe +Parameter isFunctionParameter(Dsymbol s, const(char)[] str) @safe { TypeFunction tf = isTypeFunction(s); if (tf && tf.parameterList.parameters) @@ -2655,7 +2636,7 @@ private Parameter isFunctionParameter(Dsymbol s, const(char)[] str) @safe /**************************************************** */ -private Parameter isFunctionParameter(Dsymbols* a, const(char)[] p) @safe +Parameter isFunctionParameter(Dsymbols* a, const(char)[] p) @safe { foreach (Dsymbol sym; *a) { @@ -2670,7 +2651,7 @@ private Parameter isFunctionParameter(Dsymbols* a, const(char)[] p) @safe /**************************************************** */ -private Parameter isEponymousFunctionParameter(Dsymbols *a, const(char)[] p) @safe +Parameter isEponymousFunctionParameter(Dsymbols *a, const(char)[] p) @safe { foreach (Dsymbol dsym; *a) { @@ -2718,7 +2699,7 @@ private Parameter isEponymousFunctionParameter(Dsymbols *a, const(char)[] p) @sa /**************************************************** */ -private TemplateParameter isTemplateParameter(Dsymbols* a, const(char)* p, size_t len) +TemplateParameter isTemplateParameter(Dsymbols* a, const(char)* p, size_t len) { for (size_t i = 0; i < a.length; i++) { @@ -2744,7 +2725,7 @@ private TemplateParameter isTemplateParameter(Dsymbols* a, const(char)* p, size_ * Return true if str is a reserved symbol name * that starts with a double underscore. */ -private bool isReservedName(const(char)[] str) @safe +bool isReservedName(const(char)[] str) @safe { immutable string[] table = [ @@ -2791,7 +2772,7 @@ private bool isReservedName(const(char)[] str) @safe /**************************************************** * A delimiter for Markdown inline content like emphasis and links. */ -private struct MarkdownDelimiter +struct MarkdownDelimiter { size_t iStart; /// the index where this delimiter starts int count; /// the length of this delimeter's start sequence @@ -2811,7 +2792,7 @@ private struct MarkdownDelimiter /**************************************************** * Info about a Markdown list. */ -private struct MarkdownList +struct MarkdownList { string orderedStart; /// an optional start number--if present then the list starts at this number size_t iStart; /// the index where the list item starts @@ -3028,7 +3009,7 @@ private struct MarkdownList /**************************************************** * A Markdown link. */ -private struct MarkdownLink +struct MarkdownLink { string href; /// the link destination string title; /// an optional title for the link @@ -3607,7 +3588,7 @@ private struct MarkdownLink /************************************************** * A set of Markdown link references. */ -private struct MarkdownLinkReferences +struct MarkdownLinkReferences { MarkdownLink[string] references; // link references keyed by normalized label MarkdownLink[string] symbols; // link symbols keyed by name @@ -3872,7 +3853,7 @@ private struct MarkdownLinkReferences } } -private enum TableColumnAlignment +enum TableColumnAlignment { none, left, @@ -3893,7 +3874,7 @@ private enum TableColumnAlignment * columnAlignments = alignments to populate for each column * Returns: the index of the end of the parsed delimiter, or `0` if not found */ -private size_t parseTableDelimiterRow(ref OutBuffer buf, const size_t iStart, bool inQuote, ref TableColumnAlignment[] columnAlignments) @safe +size_t parseTableDelimiterRow(ref OutBuffer buf, const size_t iStart, bool inQuote, ref TableColumnAlignment[] columnAlignments) @safe { size_t i = skipChars(buf, iStart, inQuote ? ">| \t" : "| \t"); while (i < buf.length && buf[i] != '\r' && buf[i] != '\n') @@ -3945,7 +3926,7 @@ private size_t parseTableDelimiterRow(ref OutBuffer buf, const size_t iStart, bo * columnAlignments = the parsed alignments for each column * Returns: the number of characters added by starting the table, or `0` if unchanged */ -private size_t startTable(ref OutBuffer buf, size_t iStart, size_t iEnd, const ref Loc loc, bool inQuote, ref MarkdownDelimiter[] inlineDelimiters, out TableColumnAlignment[] columnAlignments) +size_t startTable(ref OutBuffer buf, size_t iStart, size_t iEnd, const ref Loc loc, bool inQuote, ref MarkdownDelimiter[] inlineDelimiters, out TableColumnAlignment[] columnAlignments) { const iDelimiterRowEnd = parseTableDelimiterRow(buf, iEnd + 1, inQuote, columnAlignments); if (iDelimiterRowEnd) @@ -3981,7 +3962,7 @@ private size_t startTable(ref OutBuffer buf, size_t iStart, size_t iEnd, const r * delta = the number of characters added by replacing the row, or `0` if unchanged * Returns: `true` if a table row was found and replaced */ -private bool replaceTableRow(ref OutBuffer buf, size_t iStart, size_t iEnd, const ref Loc loc, ref MarkdownDelimiter[] inlineDelimiters, TableColumnAlignment[] columnAlignments, bool headerRow, out size_t delta) +bool replaceTableRow(ref OutBuffer buf, size_t iStart, size_t iEnd, const ref Loc loc, ref MarkdownDelimiter[] inlineDelimiters, TableColumnAlignment[] columnAlignments, bool headerRow, out size_t delta) { delta = 0; @@ -4108,7 +4089,7 @@ private bool replaceTableRow(ref OutBuffer buf, size_t iStart, size_t iEnd, cons * columnAlignments = alignments for each column; upon return is set to length `0` * Returns: the number of characters added by ending the table, or `0` if unchanged */ -private size_t endTable(ref OutBuffer buf, size_t i, ref TableColumnAlignment[] columnAlignments) +size_t endTable(ref OutBuffer buf, size_t i, ref TableColumnAlignment[] columnAlignments) { if (!columnAlignments.length) return 0; @@ -4130,7 +4111,7 @@ private size_t endTable(ref OutBuffer buf, size_t i, ref TableColumnAlignment[] * columnAlignments = alignments for each column; upon return is set to length `0` * Returns: the number of characters added by replacing the row, or `0` if unchanged */ -private size_t endRowAndTable(ref OutBuffer buf, size_t iStart, size_t iEnd, const ref Loc loc, ref MarkdownDelimiter[] inlineDelimiters, ref TableColumnAlignment[] columnAlignments) +size_t endRowAndTable(ref OutBuffer buf, size_t iStart, size_t iEnd, const ref Loc loc, ref MarkdownDelimiter[] inlineDelimiters, ref TableColumnAlignment[] columnAlignments) { size_t delta; replaceTableRow(buf, iStart, iEnd, loc, inlineDelimiters, columnAlignments, false, delta); @@ -4148,7 +4129,7 @@ private size_t endRowAndTable(ref OutBuffer buf, size_t iStart, size_t iEnd, con * buf = an OutBuffer containing the DDoc * offset = the index within buf to start highlighting */ -private void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t offset) +void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t offset) { const incrementLoc = loc.linnum == 0 ? 1 : 0; loc.linnum = loc.linnum + incrementLoc; @@ -4417,7 +4398,7 @@ private void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, s codebuf.write(buf[iCodeStart + count .. i]); // escape the contents, but do not perform highlighting except for DDOC_PSYMBOL highlightCode(sc, a, codebuf, 0); - escapeStrayParenthesis(loc, &codebuf, 0, false, sc.eSink); + escapeStrayParenthesis(loc, codebuf, 0, false, sc.eSink); buf.remove(iCodeStart, i - iCodeStart + count); // also trimming off the current ` immutable pre = "$(DDOC_BACKQUOTED "; i = buf.insert(iCodeStart, pre); @@ -4626,7 +4607,7 @@ private void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, s highlightCode2(sc, a, codebuf, 0); else codebuf.remove(codebuf.length-1, 1); // remove the trailing 0 byte - escapeStrayParenthesis(loc, &codebuf, 0, false, sc.eSink); + escapeStrayParenthesis(loc, codebuf, 0, false, sc.eSink); buf.remove(iCodeStart, i - iCodeStart); i = buf.insert(iCodeStart, codebuf[]); i = buf.insert(i, ")\n"); @@ -5002,7 +4983,7 @@ private void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, s /************************************************** * Highlight code for DDOC section. */ -private void highlightCode(Scope* sc, Dsymbol s, ref OutBuffer buf, size_t offset) +void highlightCode(Scope* sc, Dsymbol s, ref OutBuffer buf, size_t offset) { auto imp = s.isImport(); if (imp && imp.aliases.length > 0) @@ -5037,7 +5018,7 @@ private void highlightCode(Scope* sc, Dsymbol s, ref OutBuffer buf, size_t offse /**************************************************** */ -private void highlightCode(Scope* sc, Dsymbols* a, ref OutBuffer buf, size_t offset) +void highlightCode(Scope* sc, Dsymbols* a, ref OutBuffer buf, size_t offset) { //printf("highlightCode(a = '%s')\n", a.toChars()); bool resolvedTemplateParameters = false; @@ -5119,7 +5100,7 @@ private void highlightCode(Scope* sc, Dsymbols* a, ref OutBuffer buf, size_t off size_t lastOffset = parametersBuf.length; - .toCBuffer(tp, ¶metersBuf, &hgs); + toCBuffer(tp, parametersBuf, hgs); paramLens[parami] = parametersBuf.length - lastOffset; } @@ -5163,7 +5144,7 @@ private void highlightCode(Scope* sc, Dsymbols* a, ref OutBuffer buf, size_t off /**************************************** */ -private void highlightCode3(Scope* sc, ref OutBuffer buf, const(char)* p, const(char)* pend) +void highlightCode3(Scope* sc, ref OutBuffer buf, const(char)* p, const(char)* pend) { for (; p < pend; p++) { @@ -5178,7 +5159,7 @@ private void highlightCode3(Scope* sc, ref OutBuffer buf, const(char)* p, const( /************************************************** * Highlight code for CODE section. */ -private void highlightCode2(Scope* sc, Dsymbols* a, ref OutBuffer buf, size_t offset) +void highlightCode2(Scope* sc, Dsymbols* a, ref OutBuffer buf, size_t offset) { scope eSinkNull = new ErrorSinkNull(); @@ -5236,7 +5217,7 @@ private void highlightCode2(Scope* sc, Dsymbols* a, ref OutBuffer buf, size_t of * https://issues.dlang.org/show_bug.cgi?id=7715 * https://issues.dlang.org/show_bug.cgi?id=10519 */ - escapeDdocString(&res, o); + escapeDdocString(res, o); res.writeByte(')'); } else @@ -5252,7 +5233,7 @@ private void highlightCode2(Scope* sc, Dsymbols* a, ref OutBuffer buf, size_t of /**************************************** * Determine if p points to the start of a "..." parameter identifier. */ -private bool isCVariadicArg(const(char)[] p) @nogc nothrow pure @safe +bool isCVariadicArg(const(char)[] p) @nogc nothrow pure @safe { return p.length >= 3 && p[0 .. 3] == "..."; } @@ -5260,6 +5241,7 @@ private bool isCVariadicArg(const(char)[] p) @nogc nothrow pure @safe /**************************************** * Determine if p points to the start of an identifier. */ +@trusted bool isIdStart(const(char)* p) @nogc nothrow pure { dchar c = *p; @@ -5279,6 +5261,7 @@ bool isIdStart(const(char)* p) @nogc nothrow pure /**************************************** * Determine if p points to the rest of an identifier. */ +@trusted bool isIdTail(const(char)* p) @nogc nothrow pure { dchar c = *p; @@ -5298,7 +5281,7 @@ bool isIdTail(const(char)* p) @nogc nothrow pure /**************************************** * Determine if p points to the indentation space. */ -private bool isIndentWS(const(char)* p) @nogc nothrow pure @safe +bool isIndentWS(const(char)* p) @nogc nothrow pure @safe { return (*p == ' ') || (*p == '\t'); } @@ -5316,7 +5299,7 @@ int utfStride(const(char)* p) @nogc nothrow pure return cast(int)i; } -private inout(char)* stripLeadingNewlines(inout(char)* s) @nogc nothrow pure +inout(char)* stripLeadingNewlines(inout(char)* s) @nogc nothrow pure { while (s && *s == '\n' || *s == '\r') s++; diff --git a/gcc/d/dmd/doc.h b/gcc/d/dmd/doc.h index 669e308..562427f 100644 --- a/gcc/d/dmd/doc.h +++ b/gcc/d/dmd/doc.h @@ -13,4 +13,5 @@ class Module; class ErrorSink; -void gendocfile(Module *m, ErrorSink *eSink); +void gendocfile(Module *m, const char *ddoctext_ptr, size_t ddoctext_length, + const char *datetime, ErrorSink *eSink, OutBuffer &outbuf); diff --git a/gcc/d/dmd/dscope.d b/gcc/d/dmd/dscope.d index c2c0628..981e093 100644 --- a/gcc/d/dmd/dscope.d +++ b/gcc/d/dmd/dscope.d @@ -169,6 +169,7 @@ extern (C++) struct Scope sc.scopesym = new ScopeDsymbol(); sc.scopesym.symtab = new DsymbolTable(); sc.eSink = eSink; + assert(eSink); // Add top level package as member of this global scope Dsymbol m = _module; while (m.parent) diff --git a/gcc/d/dmd/dstruct.d b/gcc/d/dmd/dstruct.d index 49b9841..a131a8a 100644 --- a/gcc/d/dmd/dstruct.d +++ b/gcc/d/dmd/dstruct.d @@ -105,6 +105,7 @@ extern (C++) void semanticTypeInfo(Scope* sc, Type t) if (!sc) // inline may request TypeInfo. { Scope scx; + scx.eSink = global.errorSink; scx._module = sd.getModule(); getTypeInfoType(sd.loc, t, &scx); sd.requestTypeInfo = true; diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d index 0fa4dbc..c9a2c92 100644 --- a/gcc/d/dmd/dsymbol.d +++ b/gcc/d/dmd/dsymbol.d @@ -1801,6 +1801,7 @@ public: if (!tfgetmembers) { Scope sc; + sc.eSink = global.errorSink; auto parameters = new Parameters(); Parameters* p = new Parameter(STC.in_, Type.tchar.constOf().arrayOf(), null, null); parameters.push(p); diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index 378d3e6..ebdd3a8 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -83,7 +83,7 @@ else version = MARS; enum LOG = false; -private uint setMangleOverride(Dsymbol s, const(char)[] sym) +package uint setMangleOverride(Dsymbol s, const(char)[] sym) { if (s.isFuncDeclaration() || s.isVarDeclaration()) { @@ -766,7 +766,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor else { OutBuffer buf; - stcToBuffer(&buf, stc); + stcToBuffer(buf, stc); dsym.error("cannot be `%s`", buf.peekChars()); } dsym.storage_class &= ~stc; // strip off @@ -783,7 +783,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (stc) { OutBuffer buf; - stcToBuffer(&buf, stc); + stcToBuffer(buf, stc); dsym.error("cannot be `scope` and `%s`", buf.peekChars()); } else if (dsym.isMember()) @@ -1121,11 +1121,9 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (ne.member && !(ne.member.storage_class & STC.scope_)) { import dmd.escape : setUnsafeDIP1000; - const inSafeFunc = sc.func && sc.func.isSafeBypassingInference(); + const inSafeFunc = sc.func && sc.func.isSafeBypassingInference(); // isSafeBypassingInference may call setUnsafe(). if (sc.setUnsafeDIP1000(false, dsym.loc, "`scope` allocation of `%s` requires that constructor be annotated with `scope`", dsym)) errorSupplemental(ne.member.loc, "is the location of the constructor"); - else if (global.params.obsolete && inSafeFunc) - warningSupplemental(ne.member.loc, "is the location of the constructor"); } ne.onstack = 1; dsym.onstack = true; @@ -1512,11 +1510,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor ob.writestring(") : "); // use visibility instead of sc.visibility because it couldn't be // resolved yet, see the comment above - visibilityToBuffer(ob, imp.visibility); + visibilityToBuffer(*ob, imp.visibility); ob.writeByte(' '); if (imp.isstatic) { - stcToBuffer(ob, STC.static_); + stcToBuffer(*ob, STC.static_); ob.writeByte(' '); } ob.writestring(": "); @@ -2528,9 +2526,14 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (!em.ed.isAnonymous()) em.ed.memtype = t; } + const errors = global.startGagging(); Expression e = new IntegerExp(em.loc, 0, t); e = e.ctfeInterpret(); - + if (global.endGagging(errors)) + { + error(em.loc, "cannot generate 0 value of type `%s` for `%s`", + t.toChars(), em.toChars()); + } // save origValue for better json output em.origValue = e; @@ -2564,7 +2567,9 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (emprev.errors) return errorReturn(); + auto errors = global.startGagging(); Expression eprev = emprev.value; + assert(eprev); // .toHeadMutable() due to https://issues.dlang.org/show_bug.cgi?id=18645 Type tprev = eprev.type.toHeadMutable().equals(em.ed.type.toHeadMutable()) ? em.ed.memtype @@ -2578,12 +2583,23 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor emax = emax.expressionSemantic(sc); emax = emax.ctfeInterpret(); - // Set value to (eprev + 1). - // But first check that (eprev != emax) - assert(eprev); + // check that (eprev != emax) Expression e = new EqualExp(EXP.equal, em.loc, eprev, emax); e = e.expressionSemantic(sc); e = e.ctfeInterpret(); + if (global.endGagging(errors)) + { + // display an introductory error before showing what actually failed + error(em.loc, "cannot check `%s` value for overflow", em.toPrettyChars()); + // rerun to show errors + Expression e2 = DotIdExp.create(em.ed.loc, new TypeExp(em.ed.loc, tprev), Id.max); + e2 = e2.expressionSemantic(sc); + e2 = e2.ctfeInterpret(); + e2 = new EqualExp(EXP.equal, em.loc, eprev, e2); + e2 = e2.expressionSemantic(sc); + e2 = e2.ctfeInterpret(); + } + // now any errors are for generating a value if (e.toInteger()) { auto mt = em.ed.memtype; @@ -2593,13 +2609,21 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor emprev.ed.toChars(), emprev.toChars(), mt.toChars()); return errorReturn(); } - + errors = global.startGagging(); // Now set e to (eprev + 1) e = new AddExp(em.loc, eprev, IntegerExp.literal!1); e = e.expressionSemantic(sc); e = e.castTo(sc, eprev.type); e = e.ctfeInterpret(); - + if (global.endGagging(errors)) + { + error(em.loc, "cannot generate value for `%s`", em.toPrettyChars()); + // rerun to show errors + Expression e2 = new AddExp(em.loc, eprev, IntegerExp.literal!1); + e2 = e2.expressionSemantic(sc); + e2 = e2.castTo(sc, eprev.type); + e2 = e2.ctfeInterpret(); + } // save origValue (without cast) for better json output if (e.op != EXP.error) // avoid duplicate diagnostics { @@ -3351,7 +3375,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (!tf.isNaked() && !(funcdecl.isThis() || funcdecl.isNested())) { OutBuffer buf; - MODtoBuffer(&buf, tf.mod); + MODtoBuffer(buf, tf.mod); funcdecl.error("without `this` cannot be `%s`", buf.peekChars()); tf.mod = 0; // remove qualifiers } @@ -3889,7 +3913,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor OutBuffer buf; auto fd = s.isFuncDeclaration(); - functionToBufferFull(cast(TypeFunction)(funcdecl.type), &buf, + functionToBufferFull(cast(TypeFunction)(funcdecl.type), buf, new Identifier(funcdecl.toPrettyChars()), &hgs, null); const(char)* funcdeclToChars = buf.peekChars(); @@ -3912,7 +3936,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } else { - functionToBufferFull(cast(TypeFunction)(fd.type), &buf1, + functionToBufferFull(cast(TypeFunction)(fd.type), buf1, new Identifier(fd.toPrettyChars()), &hgs, null); error(funcdecl.loc, "function `%s` does not override any function, did you mean to override `%s`?", diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index e492c7e..67ca2ef 100644 --- a/gcc/d/dmd/dtemplate.d +++ b/gcc/d/dmd/dtemplate.d @@ -750,7 +750,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol { if (i) buf.writestring(", "); - .toCBuffer(tp, &buf, &hgs); + toCBuffer(tp, buf, hgs); } buf.writeByte(')'); @@ -768,7 +768,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol constraint) { buf.writestring(" if ("); - .toCBuffer(constraint, &buf, &hgs); + toCBuffer(constraint, buf, hgs); buf.writeByte(')'); } @@ -865,7 +865,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol if (!fparam.ident) continue; // don't add it, if it has no name - auto v = new VarDeclaration(loc, fparam.type, fparam.ident, null); + auto v = new VarDeclaration(fparam.loc, fparam.type, fparam.ident, null); fparam.storageClass |= STC.parameter; v.storage_class = fparam.storageClass; v.dsymbolSemantic(scx); @@ -6024,14 +6024,14 @@ extern (C++) class TemplateInstance : ScopeDsymbol override const(char)* toChars() const { OutBuffer buf; - toCBufferInstance(this, &buf); + toCBufferInstance(this, buf); return buf.extractChars(); } override final const(char)* toPrettyCharsHelper() { OutBuffer buf; - toCBufferInstance(this, &buf, true); + toCBufferInstance(this, buf, true); return buf.extractChars(); } @@ -6058,11 +6058,9 @@ extern (C++) class TemplateInstance : ScopeDsymbol { case Classification.error: return &errorSupplemental; - case Classification.warning: - return &warningSupplemental; case Classification.deprecation: return &deprecationSupplemental; - case Classification.gagged, Classification.tip: + case Classification.gagged, Classification.tip, Classification.warning: assert(0); } }(); @@ -7056,10 +7054,10 @@ extern (C++) class TemplateInstance : ScopeDsymbol if (td_ambig) { - .error(loc, "%s `%s.%s` matches more than one template declaration:\n%s: `%s`\nand\n%s: `%s`", - td_best.kind(), td_best.parent.toPrettyChars(), td_best.ident.toChars(), - td_best.loc.toChars(), td_best.toChars(), - td_ambig.loc.toChars(), td_ambig.toChars()); + .error(loc, "%s `%s.%s` matches more than one template declaration:", + td_best.kind(), td_best.parent.toPrettyChars(), td_best.ident.toChars()); + .errorSupplemental(td_best.loc, "`%s`\nand:", td_best.toChars()); + .errorSupplemental(td_ambig.loc, "`%s`", td_ambig.toChars()); return false; } if (td_best) @@ -7825,7 +7823,7 @@ extern (C++) final class TemplateMixin : TemplateInstance override const(char)* toChars() const { OutBuffer buf; - toCBufferInstance(this, &buf); + toCBufferInstance(this, buf); return buf.extractChars(); } diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d index 6a7442a..d5f658a 100644 --- a/gcc/d/dmd/dtoh.d +++ b/gcc/d/dmd/dtoh.d @@ -199,7 +199,8 @@ struct _d_dynamicArray final else { const(char)[] name = FileName.combine(global.params.cxxhdr.dir, global.params.cxxhdr.name); - writeFile(Loc.initial, name, buf[]); + if (!writeFile(Loc.initial, name, buf[])) + return fatal(); } } @@ -2327,7 +2328,12 @@ public: { //printf("%s %d\n", p.defaultArg.toChars, p.defaultArg.op); buf.writestring(" = "); + // Always emit the FDN of a symbol for the default argument, + // to avoid generating an ambiguous assignment. + auto save = adparent; + adparent = null; printExpressionFor(p.type, p.defaultArg); + adparent = save; } } @@ -2636,7 +2642,7 @@ public: import dmd.hdrgen; // Hex floating point literals were introduced in C++ 17 const allowHex = global.params.cplusplus >= CppStdRevision.cpp17; - floatToBuffer(e.type, e.value, buf, allowHex); + floatToBuffer(e.type, e.value, *buf, allowHex); } } diff --git a/gcc/d/dmd/errors.h b/gcc/d/dmd/errors.h index c6b5975..759ad27 100644 --- a/gcc/d/dmd/errors.h +++ b/gcc/d/dmd/errors.h @@ -14,6 +14,7 @@ struct Loc; +// Constants used to discriminate kinds of error messages. enum class ErrorKind { warning = 0, @@ -43,7 +44,7 @@ D_ATTRIBUTE_FORMAT(1, 2) void message(const char *format, ...); D_ATTRIBUTE_FORMAT(2, 3) void message(const Loc& loc, const char *format, ...); D_ATTRIBUTE_FORMAT(1, 2) void tip(const char *format, ...); -D_ATTRIBUTE_FORMAT(2, 0) void verrorReport(const Loc& loc, const char *format, va_list ap, const char *p1 = NULL, const char *p2 = NULL); +D_ATTRIBUTE_FORMAT(2, 0) void verrorReport(const Loc& loc, const char *format, va_list ap, ErrorKind kind, const char *p1 = NULL, const char *p2 = NULL); D_ATTRIBUTE_FORMAT(2, 0) void verrorReportSupplemental(const Loc& loc, const char* format, va_list ap, ErrorKind kind); #if defined(__GNUC__) || defined(__clang__) diff --git a/gcc/d/dmd/errorsink.d b/gcc/d/dmd/errorsink.d index e14829e..ce23517 100644 --- a/gcc/d/dmd/errorsink.d +++ b/gcc/d/dmd/errorsink.d @@ -62,6 +62,7 @@ class ErrorSinkNull : ErrorSink /***************************************** * Simplest implementation, just sends messages to stderr. + * See also: ErrorSinkCompiler. */ class ErrorSinkStderr : ErrorSink { diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d index f817a4e..8562e2e 100644 --- a/gcc/d/dmd/escape.d +++ b/gcc/d/dmd/escape.d @@ -37,6 +37,8 @@ import dmd.tokens; import dmd.visitor; import dmd.arraytypes; +private: + /// Groups global state for escape checking together package(dmd) struct EscapeState { @@ -69,6 +71,7 @@ package(dmd) struct EscapeState * Returns: * `true` if error */ +public bool checkMutableArguments(Scope* sc, FuncDeclaration fd, TypeFunction tf, Expression ethis, Expressions* arguments, bool gag) { @@ -179,7 +182,7 @@ bool checkMutableArguments(Scope* sc, FuncDeclaration fd, TypeFunction tf, const(char)* msg = eb.isMutable && eb2.isMutable ? "more than one mutable reference %s `%s` in arguments to `%s()`" : "mutable and const references %s `%s` in arguments to `%s()`"; - error((*arguments)[i].loc, msg, + sc.eSink.error((*arguments)[i].loc, msg, referenceVerb, v.toChars(), fd ? fd.toPrettyChars() : "indirectly"); @@ -226,6 +229,7 @@ bool checkMutableArguments(Scope* sc, FuncDeclaration fd, TypeFunction tf, * Returns: * `true` if any elements escaped */ +public bool checkArrayLiteralEscape(Scope *sc, ArrayLiteralExp ae, bool gag) { bool errors; @@ -249,6 +253,7 @@ bool checkArrayLiteralEscape(Scope *sc, ArrayLiteralExp ae, bool gag) * Returns: * `true` if any elements escaped */ +public bool checkAssocArrayLiteralEscape(Scope *sc, AssocArrayLiteralExp ae, bool gag) { bool errors; @@ -274,6 +279,7 @@ bool checkAssocArrayLiteralEscape(Scope *sc, AssocArrayLiteralExp ae, bool gag) * v = parameter that was not inferred * recursionLimit = recursion limit for printing the reason */ +private void printScopeFailure(E)(E printFunc, VarDeclaration v, int recursionLimit) { recursionLimit--; @@ -316,12 +322,13 @@ void printScopeFailure(E)(E printFunc, VarDeclaration v, int recursionLimit) * Returns: * `true` if pointers to the stack can escape via assignment */ +public bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Identifier parId, VarDeclaration vPar, STC parStc, Expression arg, bool assertmsg, bool gag) { enum log = false; - if (log) printf("checkParamArgumentEscape(arg: %s par: %s)\n", + if (log) printf("checkParamArgumentEscape(arg: %s par: %s parSTC: %llx)\n", arg ? arg.toChars() : "null", - parId ? parId.toChars() : "null"); + parId ? parId.toChars() : "null", parStc); //printf("type = %s, %d\n", arg.type.toChars(), arg.type.hasPointers()); if (!arg.type.hasPointers()) @@ -334,7 +341,7 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Identifier parId, if (parStc & STC.scope_) { // These errors only apply to non-scope parameters - // When the paraneter is `scope`, only `checkScopeVarAddr` on `er.byref` is needed + // When the parameter is `scope`, only `checkScopeVarAddr` on `er.byref` is needed er.byfunc.setDim(0); er.byvalue.setDim(0); er.byexp.setDim(0); @@ -467,6 +474,7 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Identifier parId, * Returns: * `true` if assignment to `firstArg` would cause an error */ +public bool checkParamArgumentReturn(Scope* sc, Expression firstArg, Expression arg, Parameter param, bool gag) { enum log = false; @@ -502,6 +510,7 @@ bool checkParamArgumentReturn(Scope* sc, Expression firstArg, Expression arg, Pa * Returns: * `true` if construction would cause an escaping reference error */ +public bool checkConstructorEscape(Scope* sc, CallExp ce, bool gag) { enum log = false; @@ -543,6 +552,7 @@ bool checkConstructorEscape(Scope* sc, CallExp ce, bool gag) } /// How a `return` parameter escapes its pointer value +public enum ReturnParamDest { returnVal, /// through return statement: `return x` @@ -564,6 +574,7 @@ enum ReturnParamDest * tthis = type of `this` parameter, or `null` if none * Returns: What a `return` parameter should transfer the lifetime of the argument to */ +public ReturnParamDest returnParamDest(TypeFunction tf, Type tthis) { assert(tf); @@ -596,6 +607,7 @@ ReturnParamDest returnParamDest(TypeFunction tf, Type tthis) * Returns: * `true` if pointers to the stack can escape via assignment */ +public bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) { enum log = false; @@ -912,7 +924,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) !(va && va.storage_class & STC.temp)) { if (!gag) - deprecation(ee.loc, "slice of static array temporary returned by `%s` assigned to longer lived variable `%s`", + sc.eSink.deprecation(ee.loc, "slice of static array temporary returned by `%s` assigned to longer lived variable `%s`", ee.toChars(), e1.toChars()); //result = true; continue; @@ -959,6 +971,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) * Returns: * `true` if pointers to the stack can escape */ +public bool checkThrowEscape(Scope* sc, Expression e, bool gag) { //printf("[%s] checkThrowEscape, e = %s\n", e.loc.toChars(), e.toChars()); @@ -1002,6 +1015,7 @@ bool checkThrowEscape(Scope* sc, Expression e, bool gag) * Returns: * `true` if pointers to the stack can escape */ +public bool checkNewEscape(Scope* sc, Expression e, bool gag) { import dmd.globals: FeatureState; @@ -1124,7 +1138,7 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag) { if (log) printf("byexp %s\n", ee.toChars()); if (!gag) - error(ee.loc, "storing reference to stack allocated value returned by `%s` into allocated memory causes it to escape", + sc.eSink.error(ee.loc, "storing reference to stack allocated value returned by `%s` into allocated memory causes it to escape", ee.toChars()); result = true; } @@ -1144,6 +1158,7 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag) * Returns: * `true` if pointers to the stack can escape */ +public bool checkReturnEscape(Scope* sc, Expression e, bool gag) { //printf("[%s] checkReturnEscape, e: %s\n", e.loc.toChars(), e.toChars()); @@ -1161,6 +1176,7 @@ bool checkReturnEscape(Scope* sc, Expression e, bool gag) * Returns: * `true` if references to the stack can escape */ +public bool checkReturnEscapeRef(Scope* sc, Expression e, bool gag) { version (none) @@ -1266,7 +1282,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) else if (v.isTypesafeVariadicArray && p == sc.func) { if (!gag) - error(e.loc, "returning `%s` escapes a reference to variadic parameter `%s`", e.toChars(), v.toChars()); + sc.eSink.error(e.loc, "returning `%s` escapes a reference to variadic parameter `%s`", e.toChars(), v.toChars()); result = false; } else @@ -1420,7 +1436,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) else { if (!gag) - error(ee.loc, "escaping reference to stack allocated value returned by `%s`", ee.toChars()); + sc.eSink.error(ee.loc, "escaping reference to stack allocated value returned by `%s`", ee.toChars()); result = true; } } @@ -1434,6 +1450,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) * va = variable to infer scope for * Returns: `true` if succesful or already `scope` */ +private bool inferScope(VarDeclaration va) { if (!va) @@ -1526,6 +1543,7 @@ private bool inferReturn(FuncDeclaration fd, VarDeclaration v, bool returnScope) * live = if @live semantics apply, i.e. expressions `p`, `*p`, `**p`, etc., all return `p`. * retRefTransition = if `e` is returned through a `return ref scope` function call */ +public void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool retRefTransition = false) { //printf("[%s] escapeByValue, e: %s\n", e.loc.toChars(), e.toChars()); @@ -1924,6 +1942,7 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re * live = if @live semantics apply, i.e. expressions `p`, `*p`, `**p`, etc., all return `p`. * retRefTransition = if `e` is returned through a `return ref scope` function call */ +private void escapeByRef(Expression e, EscapeByResults* er, bool live = false, bool retRefTransition = false) { //printf("[%s] escapeByRef, e: %s, retRefTransition: %d\n", e.loc.toChars(), e.toChars(), retRefTransition); @@ -2158,6 +2177,7 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false, bool retR /************************************ * Aggregate the data collected by the escapeBy??() functions. */ +public struct EscapeByResults { VarDeclarations byref; // array into which variables being returned by ref are inserted @@ -2295,6 +2315,7 @@ private void doNotInferScope(VarDeclaration v, RootObject o) * f = final function type. `funcdecl.type` started as the 'premature type' before attribute * inference, then its inferred attributes are copied over to final type `f` */ +public void finishScopeParamInference(FuncDeclaration funcdecl, ref TypeFunction f) { @@ -2427,6 +2448,7 @@ private void eliminateMaybeScopes(VarDeclaration[] array) * Returns: * true if it's a pointer (or reference) to mutable data */ +private bool isReferenceToMutable(Type t) { t = t.baseElemOf(); @@ -2486,6 +2508,7 @@ bool isReferenceToMutable(Type t) * Returns: * true if it's a pointer (or reference) to mutable data */ +private bool isReferenceToMutable(Parameter p, Type t) { if (p.isReference()) @@ -2561,6 +2584,7 @@ private void addMaybe(VarDeclaration va, VarDeclaration v) } // `setUnsafePreview` partially evaluated for dip1000 +public bool setUnsafeDIP1000(Scope* sc, bool gag, Loc loc, const(char)* msg, RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null) { diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index 07cc8d4..99f6587 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -40,6 +40,7 @@ import dmd.dsymbol; import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; +import dmd.errorsink; import dmd.escape; import dmd.expressionsem; import dmd.func; @@ -813,7 +814,7 @@ extern (C++) abstract class Expression : ASTNode { OutBuffer buf; HdrGenState hgs; - toCBuffer(this, &buf, &hgs); + toCBuffer(this, buf, hgs); return buf.extractChars(); } @@ -1186,7 +1187,7 @@ extern (C++) abstract class Expression : ASTNode return checkValue(); } - extern (D) final bool checkArithmetic() + extern (D) final bool checkArithmetic(EXP op) { if (op == EXP.error) return true; @@ -1194,7 +1195,11 @@ extern (C++) abstract class Expression : ASTNode return true; if (!type.isintegral() && !type.isfloating()) { - error("`%s` is not of arithmetic type, it is a `%s`", toChars(), type.toChars()); + // unary aggregate ops error here + const char* msg = type.isAggregate() ? + "operator `%s` is not defined for `%s` of type `%s`" : + "illegal operator `%s` for `%s` of type `%s`"; + error(msg, EXPtoString(op).ptr, toChars(), type.toChars()); return true; } return checkValue(); @@ -3250,6 +3255,8 @@ extern (C++) final class AssocArrayLiteralExp : Expression Expressions* keys; Expressions* values; + /// Lower to core.internal.newaa for static initializaton + Expression lowering; extern (D) this(const ref Loc loc, Expressions* keys, Expressions* values) @safe { @@ -4036,13 +4043,11 @@ extern (C++) final class FuncExp : Expression return new FuncExp(loc, fd); } - extern (D) MATCH matchType(Type to, Scope* sc, FuncExp* presult, int flag = 0) + extern (D) MATCH matchType(Type to, Scope* sc, FuncExp* presult, ErrorSink eSink) { - - static MATCH cannotInfer(Expression e, Type to, int flag) + MATCH cannotInfer() { - if (!flag) - e.error("cannot infer parameter types from `%s`", to.toChars()); + eSink.error(loc, "cannot infer parameter types from `%s`", to.toChars()); return MATCH.nomatch; } @@ -4055,8 +4060,7 @@ extern (C++) final class FuncExp : Expression { if (tok == TOK.function_) { - if (!flag) - error("cannot match function literal to delegate type `%s`", to.toChars()); + eSink.error(loc, "cannot match function literal to delegate type `%s`", to.toChars()); return MATCH.nomatch; } tof = cast(TypeFunction)to.nextOf(); @@ -4065,8 +4069,7 @@ extern (C++) final class FuncExp : Expression { if (tok == TOK.delegate_) { - if (!flag) - error("cannot match delegate literal to function pointer type `%s`", to.toChars()); + eSink.error(loc, "cannot match delegate literal to function pointer type `%s`", to.toChars()); return MATCH.nomatch; } } @@ -4075,7 +4078,7 @@ extern (C++) final class FuncExp : Expression { if (!tof) { - return cannotInfer(this, to, flag); + return cannotInfer(); } // Parameter types inference from 'tof' @@ -4086,7 +4089,7 @@ extern (C++) final class FuncExp : Expression const dim = tf.parameterList.length; if (tof.parameterList.length != dim || tof.parameterList.varargs != tf.parameterList.varargs) - return cannotInfer(this, to, flag); + return cannotInfer(); auto tiargs = new Objects(); tiargs.reserve(td.parameters.length); @@ -4106,7 +4109,7 @@ extern (C++) final class FuncExp : Expression Parameter pto = tof.parameterList[u]; Type t = pto.type; if (t.ty == Terror) - return cannotInfer(this, to, flag); + return cannotInfer(); tf.parameterList[u].storageClass = tof.parameterList[u].storageClass; tiargs.push(t); } @@ -4124,9 +4127,9 @@ extern (C++) final class FuncExp : Expression if (ex.op == EXP.error) return MATCH.nomatch; if (auto ef = ex.isFuncExp()) - return ef.matchType(to, sc, presult, flag); + return ef.matchType(to, sc, presult, eSink); else - return cannotInfer(this, to, flag); + return cannotInfer(); } if (!tof || !tof.next) @@ -4198,10 +4201,10 @@ extern (C++) final class FuncExp : Expression (*presult).fd.modifyReturns(sc, tof.next); } } - else if (!flag) + else if (!cast(ErrorSinkNull)eSink) { auto ts = toAutoQualChars(tx, to); - error("cannot implicitly convert expression `%s` of type `%s` to `%s`", + eSink.error(loc, "cannot implicitly convert expression `%s` of type `%s` to `%s`", toChars(), ts[0], ts[1]); } return m; @@ -4674,8 +4677,8 @@ extern (C++) abstract class BinExp : Expression extern (D) final bool checkArithmeticBin() { - bool r1 = e1.checkArithmetic(); - bool r2 = e2.checkArithmetic(); + bool r1 = e1.checkArithmetic(this.op); + bool r2 = e2.checkArithmetic(this.op); return (r1 || r2); } @@ -7217,7 +7220,7 @@ extern (C++) final class PrettyFuncInitExp : DefaultInitExp { const funcStr = fd.Dsymbol.toPrettyChars(); OutBuffer buf; - functionToBufferWithIdent(fd.type.isTypeFunction(), &buf, funcStr, fd.isStatic); + functionToBufferWithIdent(fd.type.isTypeFunction(), buf, funcStr, fd.isStatic); s = buf.extractChars(); } else diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h index 1f04c6c..2189757 100644 --- a/gcc/d/dmd/expression.h +++ b/gcc/d/dmd/expression.h @@ -94,7 +94,7 @@ public: const char *toChars() const override; void error(const char *format, ...) const; - void warning(const char *format, ...) const; + void warning(unsigned flag, const char *format, ...) const; void deprecation(const char *format, ...) const; virtual dinteger_t toInteger(); @@ -446,6 +446,7 @@ public: OwnedBy ownedByCtfe; Expressions *keys; Expressions *values; + Expression* lowering; bool equals(const RootObject * const o) const override; AssocArrayLiteralExp *syntaxCopy() override; diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index 69999cb..30382bb 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -1197,6 +1197,11 @@ private bool haveSameThis(FuncDeclaration outerFunc, FuncDeclaration calledFunc) if (thisAd == requiredAd) return true; + // if outerfunc is the member of a nested aggregate, then let + // getRightThis take care of this. + if (thisAd.isNested()) + return true; + // outerfunc is the member of a base class that contains calledFunc, // then we consider that they have the same this. auto cd = requiredAd.isClassDeclaration(); @@ -1206,11 +1211,6 @@ private bool haveSameThis(FuncDeclaration outerFunc, FuncDeclaration calledFunc) if (cd.isBaseOf2(thisAd.isClassDeclaration())) return true; - // if outerfunc is the member of a nested aggregate, then let - // getRightThis take care of this. - if (thisAd.isNested()) - return true; - return false; } @@ -2319,6 +2319,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc, } err |= arg.checkValue(); err |= arg.checkSharedAccess(sc); + err |= checkParamArgumentEscape(sc, fd, Id.dotdotdot, null, cast(STC) tf.parameterList.stc, arg, false, false); arg = arg.optimize(WANTvalue); } (*arguments)[i] = arg; @@ -2331,14 +2332,14 @@ private bool functionParameters(const ref Loc loc, Scope* sc, { if (auto se = (*arguments)[nparams - 1 - isVa_list].isStringExp()) { - checkPrintfFormat(se.loc, se.peekString(), (*arguments)[nparams .. nargs], isVa_list); + checkPrintfFormat(se.loc, se.peekString(), (*arguments)[nparams .. nargs], isVa_list, sc.eSink); } } else if (fd && fd.scanf) { if (auto se = (*arguments)[nparams - 1 - isVa_list].isStringExp()) { - checkScanfFormat(se.loc, se.peekString(), (*arguments)[nparams .. nargs], isVa_list); + checkScanfFormat(se.loc, se.peekString(), (*arguments)[nparams .. nargs], isVa_list, sc.eSink); } } else @@ -2528,7 +2529,8 @@ private bool functionParameters(const ref Loc loc, Scope* sc, auto args = new Parameters(arguments.length - nparams); for (size_t i = 0; i < arguments.length - nparams; i++) { - auto arg = new Parameter(STC.in_, (*arguments)[nparams + i].type, null, null, null); + Expression earg = (*arguments)[nparams + i]; + auto arg = new Parameter(earg.loc, STC.in_, earg.type, null, null, null); (*args)[i] = arg; } auto tup = new TypeTuple(args); @@ -3889,10 +3891,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor foreach (v; c.fields) { if (v.inuse || v._scope is null || v._init is null || - v._init.isVoidInitializer()) + v._init.isVoidInitializer() || v.semanticRun >= PASS.semantic2done) continue; v.inuse++; v._init = v._init.initializerSemantic(v._scope, v.type, INITinterpret); + import dmd.semantic2 : lowerStaticAAs; + lowerStaticAAs(v, sc); v.inuse--; } } @@ -4312,7 +4316,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (exp.fd.treq) // defer type determination { FuncExp fe; - if (exp.matchType(exp.fd.treq, sc, &fe) > MATCH.nomatch) + if (exp.matchType(exp.fd.treq, sc, &fe, sc.eSink) > MATCH.nomatch) e = fe; else e = ErrorExp.get(); @@ -5275,10 +5279,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { OutBuffer buf; buf.writeByte('('); - argExpTypesToCBuffer(&buf, exp.arguments); + argExpTypesToCBuffer(buf, exp.arguments); buf.writeByte(')'); if (tthis) - tthis.modToBuffer(&buf); + tthis.modToBuffer(buf); //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco); .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`", @@ -5348,7 +5352,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { OutBuffer buf; buf.writeByte('('); - argExpTypesToCBuffer(&buf, exp.arguments); + argExpTypesToCBuffer(buf, exp.arguments); buf.writeByte(')'); //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco); @@ -5947,7 +5951,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor for (size_t i = 0; i < cd.baseclasses.length; i++) { BaseClass* b = (*cd.baseclasses)[i]; - args.push(new Parameter(STC.in_, b.type, null, null, null)); + args.push(new Parameter(Loc.initial, STC.in_, b.type, null, null, null)); } tded = new TypeTuple(args); } @@ -5993,7 +5997,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor */ if (e.tok2 == TOK.parameters && arg.defaultArg && arg.defaultArg.op == EXP.error) return setError(); - args.push(new Parameter(arg.storageClass, arg.type, (e.tok2 == TOK.parameters) ? arg.ident : null, (e.tok2 == TOK.parameters) ? arg.defaultArg : null, arg.userAttribDecl)); + args.push(new Parameter(arg.loc, arg.storageClass, arg.type, (e.tok2 == TOK.parameters) ? arg.ident : null, (e.tok2 == TOK.parameters) ? arg.defaultArg : null, arg.userAttribDecl)); } tded = new TypeTuple(args); break; @@ -7278,7 +7282,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor else if (!exp.e1.type.deco) { // try to resolve the type - exp.e1.type = exp.e1.type.typeSemantic(exp.e1.loc, null); + exp.e1.type = exp.e1.type.typeSemantic(exp.e1.loc, sc); if (!exp.e1.type.deco) // still couldn't resolve it { if (auto ve = exp.e1.isVarExp()) @@ -7527,7 +7531,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } if (exp.e1.checkNoBool()) return setError(); - if (exp.e1.checkArithmetic() || + if (exp.e1.checkArithmetic(exp.op) || exp.e1.checkSharedAccess(sc)) return setError(); @@ -7557,7 +7561,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } if (exp.e1.checkNoBool()) return setError(); - if (exp.e1.checkArithmetic()) + if (exp.e1.checkArithmetic(exp.op)) return setError(); if (exp.e1.checkSharedAccess(sc)) return setError(); @@ -10024,19 +10028,22 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } - if (0 && global.params.warnings != DiagnosticReporting.off && !global.gag && exp.op == EXP.assign && - e2x.op != EXP.slice && e2x.op != EXP.assign && - e2x.op != EXP.arrayLiteral && e2x.op != EXP.string_ && - !(e2x.op == EXP.add || e2x.op == EXP.min || - e2x.op == EXP.mul || e2x.op == EXP.div || - e2x.op == EXP.mod || e2x.op == EXP.xor || - e2x.op == EXP.and || e2x.op == EXP.or || - e2x.op == EXP.pow || - e2x.op == EXP.tilde || e2x.op == EXP.negate)) + version (none) { - const(char)* e1str = exp.e1.toChars(); - const(char)* e2str = e2x.toChars(); - exp.warning("explicit element-wise assignment `%s = (%s)[]` is better than `%s = %s`", e1str, e2str, e1str, e2str); + if (global.params.warnings != DiagnosticReporting.off && !global.gag && exp.op == EXP.assign && + e2x.op != EXP.slice && e2x.op != EXP.assign && + e2x.op != EXP.arrayLiteral && e2x.op != EXP.string_ && + !(e2x.op == EXP.add || e2x.op == EXP.min || + e2x.op == EXP.mul || e2x.op == EXP.div || + e2x.op == EXP.mod || e2x.op == EXP.xor || + e2x.op == EXP.and || e2x.op == EXP.or || + e2x.op == EXP.pow || + e2x.op == EXP.tilde || e2x.op == EXP.negate)) + { + const(char)* e1str = exp.e1.toChars(); + const(char)* e2str = e2x.toChars(); + exp.warning("explicit element-wise assignment `%s = (%s)[]` is better than `%s = %s`", e1str, e2str, e1str, e2str); + } } Type t2n = t2.nextOf(); @@ -10085,17 +10092,20 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } else { - if (0 && global.params.warnings != DiagnosticReporting.off && !global.gag && exp.op == EXP.assign && - t1.ty == Tarray && t2.ty == Tsarray && - e2x.op != EXP.slice && - t2.implicitConvTo(t1)) + version (none) { - // Disallow ar[] = sa (Converted to ar[] = sa[]) - // Disallow da = sa (Converted to da = sa[]) - const(char)* e1str = exp.e1.toChars(); - const(char)* e2str = e2x.toChars(); - const(char)* atypestr = exp.e1.op == EXP.slice ? "element-wise" : "slice"; - exp.warning("explicit %s assignment `%s = (%s)[]` is better than `%s = %s`", atypestr, e1str, e2str, e1str, e2str); + if (global.params.warnings != DiagnosticReporting.off && !global.gag && exp.op == EXP.assign && + t1.ty == Tarray && t2.ty == Tsarray && + e2x.op != EXP.slice && + t2.implicitConvTo(t1)) + { + // Disallow ar[] = sa (Converted to ar[] = sa[]) + // Disallow da = sa (Converted to da = sa[]) + const(char)* e1str = exp.e1.toChars(); + const(char)* e2str = e2x.toChars(); + const(char)* atypestr = exp.e1.op == EXP.slice ? "element-wise" : "slice"; + exp.warning("explicit %s assignment `%s = (%s)[]` is better than `%s = %s`", atypestr, e1str, e2str, e1str, e2str); + } } if (exp.op == EXP.blit) e2x = e2x.castTo(sc, exp.e1.type); @@ -10785,11 +10795,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor bool err = false; if (tb1.ty == Tdelegate || tb1.isPtrToFunction()) { - err |= exp.e1.checkArithmetic() || exp.e1.checkSharedAccess(sc); + err |= exp.e1.checkArithmetic(exp.op) || exp.e1.checkSharedAccess(sc); } if (tb2.ty == Tdelegate || tb2.isPtrToFunction()) { - err |= exp.e2.checkArithmetic() || exp.e2.checkSharedAccess(sc); + err |= exp.e2.checkArithmetic(exp.op) || exp.e2.checkSharedAccess(sc); } if (err) return setError(); @@ -10891,11 +10901,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor bool err = false; if (t1.ty == Tdelegate || t1.isPtrToFunction()) { - err |= exp.e1.checkArithmetic() || exp.e1.checkSharedAccess(sc); + err |= exp.e1.checkArithmetic(exp.op) || exp.e1.checkSharedAccess(sc); } if (t2.ty == Tdelegate || t2.isPtrToFunction()) { - err |= exp.e2.checkArithmetic() || exp.e2.checkSharedAccess(sc); + err |= exp.e2.checkArithmetic(exp.op) || exp.e2.checkSharedAccess(sc); } if (err) return setError(); @@ -11032,7 +11042,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor (exp.e2.isStringExp() && (exp.e1.isIntegerExp() || exp.e1.isStringExp()))) return exp; - Identifier hook = global.params.tracegc ? Id._d_arraycatnTXTrace : Id._d_arraycatnTX; + bool useTraceGCHook = global.params.tracegc && sc.needsCodegen(); + + Identifier hook = useTraceGCHook ? Id._d_arraycatnTXTrace : Id._d_arraycatnTX; if (!verifyHookExist(exp.loc, *sc, hook, "concatenating arrays")) { setError(); @@ -11061,7 +11073,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } auto arguments = new Expressions(); - if (global.params.tracegc) + if (useTraceGCHook) { auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars(); @@ -11088,7 +11100,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor /* `_d_arraycatnTX` canot be used with `-betterC`, but `CatExp`s may be * used with `-betterC`, but only during CTFE. */ - if (!global.params.useGC || !sc.needsCodegen()) + if (!global.params.useGC) return; if (auto ce = exp.isCatExp()) @@ -12087,8 +12099,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } - if (sc.needsCodegen() && - (t1.ty == Tarray || t1.ty == Tsarray) && + if ((t1.ty == Tarray || t1.ty == Tsarray) && (t2.ty == Tarray || t2.ty == Tsarray)) { if (!verifyHookExist(exp.loc, *sc, Id.__cmp, "comparing arrays")) diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d index 73f1ba7..bf7ad7e 100644 --- a/gcc/d/dmd/func.d +++ b/gcc/d/dmd/func.d @@ -173,7 +173,7 @@ public: Identifier id = Identifier.generateId("__o"); Statement handler = new PeelStatement(sexception); - if (sexception.blockExit(fd, false) & BE.fallthru) + if (sexception.blockExit(fd, null) & BE.fallthru) { auto ts = new ThrowStatement(Loc.initial, new IdentifierExp(Loc.initial, id)); ts.internalThrow = true; @@ -1311,7 +1311,7 @@ extern (C++) class FuncDeclaration : Declaration final const(char)* toFullSignature() { OutBuffer buf; - functionToBufferWithIdent(type.toTypeFunction(), &buf, toChars(), isStatic); + functionToBufferWithIdent(type.toTypeFunction(), buf, toChars(), isStatic); return buf.extractChars(); } @@ -2279,8 +2279,11 @@ extern (C++) class FuncDeclaration : Declaration break LcheckAncestorsOfANestedRef; } a.push(f); - .errorSupplemental(f.loc, "`%s` closes over variable `%s` at %s", - f.toPrettyChars(), v.toChars(), v.loc.toChars()); + .errorSupplemental(f.loc, "%s `%s` closes over variable `%s`", + f.kind, f.toPrettyChars(), v.toChars()); + if (v.ident != Id.This) + .errorSupplemental(v.loc, "`%s` declared here", v.toChars()); + break LcheckAncestorsOfANestedRef; } } @@ -2657,7 +2660,7 @@ extern (C++) class FuncDeclaration : Declaration auto fparams = new Parameters(); if (canBuildResultVar()) { - Parameter p = new Parameter(STC.ref_ | STC.const_, f.nextOf(), Id.result, null, null); + Parameter p = new Parameter(loc, STC.ref_ | STC.const_, f.nextOf(), Id.result, null, null); fparams.push(p); } auto fo = cast(TypeFunction)(originalType ? originalType : f); @@ -3340,14 +3343,14 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, s = fd = td.funcroot; OutBuffer tiargsBuf; - arrayObjectsToBuffer(&tiargsBuf, tiargs); + arrayObjectsToBuffer(tiargsBuf, tiargs); OutBuffer fargsBuf; fargsBuf.writeByte('('); - argExpTypesToCBuffer(&fargsBuf, fargs); + argExpTypesToCBuffer(fargsBuf, fargs); fargsBuf.writeByte(')'); if (tthis) - tthis.modToBuffer(&fargsBuf); + tthis.modToBuffer(fargsBuf); // The call is ambiguous if (m.lastf && m.nextf) @@ -4623,7 +4626,7 @@ bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, const(char) { if (!gag) { - if (!sc.isDeprecated() && global.params.obsolete) + version (none) // disable obsolete warning warning(loc, msg, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : ""); } } diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d index af711a0..840074e 100644 --- a/gcc/d/dmd/globals.d +++ b/gcc/d/dmd/globals.d @@ -101,6 +101,23 @@ extern(C++) struct Output OutBuffer* buffer; // if this output is buffered, this is the buffer int bufferLines; // number of lines written to the buffer } + +/// Command line state related to printing usage about other switches +extern(C++) struct Help +{ + bool manual; // open browser on compiler manual + bool usage; // print usage and exit + // print help of switch: + bool mcpu; // -mcpu + bool transition; // -transition + bool check; // -check + bool checkAction; // -checkaction + bool revert; // -revert + bool preview; // -preview + bool externStd; // -extern-std + bool hc; // -HC +} + /// Put command line switches in here extern (C++) struct Param { @@ -124,7 +141,6 @@ extern (C++) struct Param bool release; // build release version bool preservePaths; // true means don't strip path from source file DiagnosticReporting warnings = DiagnosticReporting.off; // how compiler warnings are handled - bool obsolete; // enable warnings about use of obsolete messages bool color; // use ANSI colors in console output bool cov; // generate code coverage data ubyte covPercent; // 0..100 code coverage percentage required @@ -143,16 +159,7 @@ extern (C++) struct Param bool showGaggedErrors; // print gagged errors anyway bool printErrorContext; // print errors with the error context (the error line in the source file) - bool manual; // open browser on compiler manual - bool usage; // print usage and exit - bool mcpuUsage; // print help on -mcpu switch - bool transitionUsage; // print help on -transition switch - bool checkUsage; // print help on -check switch - bool checkActionUsage; // print help on -checkaction switch - bool revertUsage; // print help on -revert switch - bool previewUsage; // print help on -preview switch - bool externStdUsage; // print help on -extern-std switch - bool hcUsage; // print help on -HC switch + Help help; bool logo; // print compiler logo // Options for `-preview=/-revert=` @@ -258,6 +265,7 @@ extern (C++) struct Global Array!(const(char)*)* filePath; /// Array of char*'s which form the file import lookup path private enum string _version = import("VERSION"); + char[26] datetime; /// string returned by ctime() CompileEnv compileEnv; Param params; /// command line parameters @@ -281,6 +289,7 @@ extern (C++) struct Global enum recursionLimit = 500; /// number of recursive template expansions before abort ErrorSink errorSink; /// where the error messages go + ErrorSink errorSinkNull; /// where the error messages are ignored extern (C++) FileName function(FileName, ref const Loc, out bool, OutBuffer*) preprocess; @@ -337,6 +346,7 @@ extern (C++) struct Global extern (C++) void _init() { errorSink = new ErrorSinkCompiler; + errorSinkNull = new ErrorSinkNull; this.fileManager = new FileManager(); version (MARS) @@ -369,6 +379,7 @@ extern (C++) struct Global core.stdc.time.time(&ct); const p = ctime(&ct); assert(p); + datetime[] = p[0 .. 26]; __gshared char[11 + 1] date = 0; // put in BSS segment __gshared char[8 + 1] time = 0; diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h index 0ef9eed..e24042a 100644 --- a/gcc/d/dmd/globals.h +++ b/gcc/d/dmd/globals.h @@ -96,6 +96,22 @@ struct Output int bufferLines; // number of lines written to the buffer }; +/// Command line state related to printing uasage about other switches +struct Help +{ + d_bool manual; // open browser on compiler manual + d_bool usage; // print usage and exit + // print help of switch: + d_bool mcpu; // -mcpu + d_bool transition; // -transition + d_bool check; // -check + d_bool checkAction; // -checkaction + d_bool revert; // -revert + d_bool preview; // -preview + d_bool externStd; // -extern-std + d_bool hc; // -HC +}; + // Put command line switches in here struct Param { @@ -119,7 +135,6 @@ struct Param d_bool release; // build release version d_bool preservePaths; // true means don't strip path from source file Diagnostic warnings; - d_bool obsolete; // warn about use of obsolete features d_bool color; // use ANSI colors in console output d_bool cov; // generate code coverage data unsigned char covPercent; // 0..100 code coverage percentage required @@ -136,16 +151,7 @@ struct Param CppStdRevision cplusplus; // version of C++ name mangling to support d_bool showGaggedErrors; // print gagged errors anyway d_bool printErrorContext; // print errors with the error context (the error line in the source file) - d_bool manual; // open browser on compiler manual - d_bool usage; // print usage and exit - d_bool mcpuUsage; // print help on -mcpu switch - d_bool transitionUsage; // print help on -transition switch - d_bool checkUsage; // print help on -check switch - d_bool checkActionUsage; // print help on -checkaction switch - d_bool revertUsage; // print help on -revert switch - d_bool previewUsage; // print help on -preview switch - d_bool externStdUsage; // print help on -extern-std switch - d_bool hcUsage; // print help on -HC switch + Help help; d_bool logo; // print logo; // Options for `-preview=/-revert=` @@ -265,7 +271,6 @@ struct CompileEnv bool previewIn; bool ddocOutput; bool shortenedMethods; - bool obsolete; }; struct Global @@ -277,6 +282,7 @@ struct Global Array<const char *> *path; // Array of char*'s which form the import lookup path Array<const char *> *filePath; // Array of char*'s which form the file import lookup path + char datetime[26]; /// string returned by ctime() CompileEnv compileEnv; Param params; @@ -296,6 +302,7 @@ struct Global FileManager* fileManager; ErrorSink* errorSink; // where the error messages go + ErrorSink* errorSinkNull; // where the error messages disappear FileName (*preprocess)(FileName, const Loc&, bool&, OutBuffer&); @@ -358,8 +365,8 @@ struct Loc { private: unsigned _linnum; - unsigned short _charnum; - unsigned short fileIndex; + unsigned _charnum; + unsigned fileIndex; public: static void set(bool showColumns, MessageStyle messageStyle); diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d index 33cbc19..b4c8e8b 100644 --- a/gcc/d/dmd/hdrgen.d +++ b/gcc/d/dmd/hdrgen.d @@ -51,7 +51,6 @@ import dmd.statement; import dmd.staticassert; import dmd.target; import dmd.tokens; -import dmd.utils; import dmd.visitor; struct HdrGenState @@ -73,16 +72,20 @@ struct HdrGenState enum TEST_EMIT_ALL = 0; -extern (C++) void genhdrfile(Module m) +/**************************************** + * Generate a header (.di) file for Module m. + * Params: + * m = Module to generate header for + * buf = buffer to write the data to + */ +extern (C++) void genhdrfile(Module m, ref OutBuffer buf) { - OutBuffer buf; buf.doindent = 1; buf.printf("// D import file generated from '%s'", m.srcfile.toChars()); buf.writenl(); HdrGenState hgs; hgs.hdrgen = true; - toCBuffer(m, &buf, &hgs); - writeFile(m.loc, m.hdrfile.toString(), buf[]); + toCBuffer(m, buf, hgs); } /** @@ -91,14 +94,14 @@ extern (C++) void genhdrfile(Module m) * buf = buffer to write to. * m = module to visit all members of. */ -extern (C++) void moduleToBuffer(OutBuffer* buf, Module m) +extern (C++) void moduleToBuffer(ref OutBuffer buf, Module m) { HdrGenState hgs; hgs.fullDump = true; - toCBuffer(m, buf, &hgs); + toCBuffer(m, buf, hgs); } -void moduleToBuffer2(Module m, OutBuffer* buf, HdrGenState* hgs) +void moduleToBuffer2(Module m, ref OutBuffer buf, HdrGenState* hgs) { if (m.md) { @@ -132,7 +135,7 @@ void moduleToBuffer2(Module m, OutBuffer* buf, HdrGenState* hgs) } } -private void statementToBuffer(Statement s, OutBuffer* buf, HdrGenState* hgs) +private void statementToBuffer(Statement s, ref OutBuffer buf, HdrGenState* hgs) { void visitDefaultCase(Statement s) { @@ -201,8 +204,7 @@ private void statementToBuffer(Statement s, OutBuffer* buf, HdrGenState* hgs) auto d = ds.exp.isDeclarationExp().declaration; if (auto v = d.isVarDeclaration()) { - scope ppv = new DsymbolPrettyPrintVisitor(buf, hgs); - ppv.visitVarDecl(v, anywritten); + visitVarDecl(v, anywritten, buf, *hgs); } else d.dsymbolToBuffer(buf, hgs); @@ -792,9 +794,9 @@ private void statementToBuffer(Statement s, OutBuffer* buf, HdrGenState* hgs) visit.VisitStatement(s); } -private void dsymbolToBuffer(Dsymbol s, OutBuffer* buf, HdrGenState* hgs) +private void dsymbolToBuffer(Dsymbol s, ref OutBuffer buf, HdrGenState* hgs) { - scope v = new DsymbolPrettyPrintVisitor(buf, hgs); + scope v = new DsymbolPrettyPrintVisitor(&buf, hgs); s.accept(v); } @@ -822,13 +824,13 @@ public: { buf.writestring(s.kind()); buf.writeByte('('); - s.exp.expressionToBuffer(buf, hgs); + s.exp.expressionToBuffer(*buf, hgs); if (s.msgs) { foreach (m; (*s.msgs)[]) { buf.writestring(", "); - m.expressionToBuffer(buf, hgs); + m.expressionToBuffer(*buf, hgs); } } buf.writestring(");"); @@ -860,13 +862,13 @@ public: override void visit(EnumMember em) { if (em.type) - typeToBuffer(em.type, em.ident, buf, hgs); + typeToBuffer(em.type, em.ident, *buf, hgs); else buf.writestring(em.ident.toString()); if (em.value) { buf.writestring(" = "); - em.value.expressionToBuffer(buf, hgs); + em.value.expressionToBuffer(*buf, hgs); } } @@ -916,7 +918,7 @@ public: bool hasSTC; if (auto stcd = d.isStorageClassDeclaration) { - hasSTC = stcToBuffer(buf, stcd.stc); + hasSTC = stcToBuffer(*buf, stcd.stc); } if (!d.decl) @@ -959,7 +961,7 @@ public: override void visit(DeprecatedDeclaration d) { buf.writestring("deprecated("); - d.msg.expressionToBuffer(buf, hgs); + d.msg.expressionToBuffer(*buf, hgs); buf.writestring(") "); visit(cast(AttribDeclaration)d); } @@ -994,7 +996,7 @@ public: override void visit(VisibilityDeclaration d) { - visibilityToBuffer(buf, d.visibility); + visibilityToBuffer(*buf, d.visibility); AttribDeclaration ad = cast(AttribDeclaration)d; if (ad.decl.length <= 1) buf.writeByte(' '); @@ -1047,7 +1049,7 @@ public: if (d.args && d.args.length) { buf.writestring(", "); - argsToBuffer(d.args, buf, hgs); + argsToBuffer(d.args, *buf, hgs); } buf.writeByte(')'); @@ -1065,7 +1067,7 @@ public: override void visit(ConditionalDeclaration d) { - d.condition.conditionToBuffer(buf, hgs); + d.condition.conditionToBuffer(*buf, hgs); if (d.decl || d.elsedecl) { buf.writenl(); @@ -1108,15 +1110,15 @@ public: { if (i) buf.writestring(", "); - if (stcToBuffer(buf, p.storageClass)) + if (stcToBuffer(*buf, p.storageClass)) buf.writeByte(' '); if (p.type) - typeToBuffer(p.type, p.ident, buf, hgs); + typeToBuffer(p.type, p.ident, *buf, hgs); else buf.writestring(p.ident.toString()); } buf.writestring("; "); - s.aggr.expressionToBuffer(buf, hgs); + s.aggr.expressionToBuffer(*buf, hgs); buf.writeByte(')'); buf.writenl(); } @@ -1128,13 +1130,13 @@ public: buf.writestring(Token.toString(s.op)); buf.writestring(" ("); if (s.prm.type) - typeToBuffer(s.prm.type, s.prm.ident, buf, hgs); + typeToBuffer(s.prm.type, s.prm.ident, *buf, hgs); else buf.writestring(s.prm.ident.toString()); buf.writestring("; "); - s.lwr.expressionToBuffer(buf, hgs); + s.lwr.expressionToBuffer(*buf, hgs); buf.writestring(" .. "); - s.upr.expressionToBuffer(buf, hgs); + s.upr.expressionToBuffer(*buf, hgs); buf.writeByte(')'); buf.writenl(); } @@ -1162,7 +1164,7 @@ public: override void visit(MixinDeclaration d) { buf.writestring("mixin("); - argsToBuffer(d.exps, buf, hgs, null); + argsToBuffer(d.exps, *buf, hgs, null); buf.writestring(");"); buf.writenl(); } @@ -1170,7 +1172,7 @@ public: override void visit(UserAttributeDeclaration d) { buf.writestring("@("); - argsToBuffer(d.atts, buf, hgs); + argsToBuffer(d.atts, *buf, hgs); buf.writeByte(')'); visit(cast(AttribDeclaration)d); } @@ -1221,9 +1223,9 @@ public: if (FuncDeclaration fd = onemember.isFuncDeclaration()) { assert(fd.type); - if (stcToBuffer(buf, fd.storage_class)) + if (stcToBuffer(*buf, fd.storage_class)) buf.writeByte(' '); - functionToBufferFull(cast(TypeFunction)fd.type, buf, d.ident, hgs, d); + functionToBufferFull(cast(TypeFunction)fd.type, *buf, d.ident, hgs, d); visitTemplateConstraint(d.constraint); hgs.tpltMember++; bodyToBuffer(fd); @@ -1262,10 +1264,10 @@ public: { if (d.constraint) return false; - if (stcToBuffer(buf, vd.storage_class)) + if (stcToBuffer(*buf, vd.storage_class)) buf.writeByte(' '); if (vd.type) - typeToBuffer(vd.type, vd.ident, buf, hgs); + typeToBuffer(vd.type, vd.ident, *buf, hgs); else buf.writestring(vd.ident.toString()); buf.writeByte('('); @@ -1276,9 +1278,9 @@ public: buf.writestring(" = "); ExpInitializer ie = vd._init.isExpInitializer(); if (ie && (ie.exp.op == EXP.construct || ie.exp.op == EXP.blit)) - (cast(AssignExp)ie.exp).e2.expressionToBuffer(buf, hgs); + (cast(AssignExp)ie.exp).e2.expressionToBuffer(*buf, hgs); else - vd._init.initializerToBuffer(buf, hgs); + vd._init.initializerToBuffer(*buf, hgs); } buf.writeByte(';'); buf.writenl(); @@ -1295,7 +1297,7 @@ public: { if (i) buf.writestring(", "); - p.templateParameterToBuffer(buf, hgs); + p.templateParameterToBuffer(*buf, hgs); } } @@ -1304,27 +1306,27 @@ public: if (!constraint) return; buf.writestring(" if ("); - constraint.expressionToBuffer(buf, hgs); + constraint.expressionToBuffer(*buf, hgs); buf.writeByte(')'); } override void visit(TemplateInstance ti) { buf.writestring(ti.name.toChars()); - tiargsToBuffer(ti, buf, hgs); + tiargsToBuffer(ti, *buf, hgs); if (hgs.fullDump) { buf.writenl(); - dumpTemplateInstance(ti, buf, hgs); + dumpTemplateInstance(ti, *buf, hgs); } } override void visit(TemplateMixin tm) { buf.writestring("mixin "); - typeToBuffer(tm.tqual, null, buf, hgs); - tiargsToBuffer(tm, buf, hgs); + typeToBuffer(tm.tqual, null, *buf, hgs); + tiargsToBuffer(tm, *buf, hgs); if (tm.ident && memcmp(tm.ident.toChars(), cast(const(char)*)"__mixin", 7) != 0) { buf.writeByte(' '); @@ -1333,7 +1335,7 @@ public: buf.writeByte(';'); buf.writenl(); if (hgs.fullDump) - dumpTemplateInstance(tm, buf, hgs); + dumpTemplateInstance(tm, *buf, hgs); } override void visit(EnumDeclaration d) @@ -1349,7 +1351,7 @@ public: if (d.memtype) { buf.writestring(" : "); - typeToBuffer(d.memtype, null, buf, hgs); + typeToBuffer(d.memtype, null, *buf, hgs); } if (!d.members) { @@ -1452,7 +1454,7 @@ public: { if (i) buf.writestring(", "); - typeToBuffer(b.type, null, buf, hgs); + typeToBuffer(b.type, null, *buf, hgs); } } @@ -1465,7 +1467,7 @@ public: { buf.writestring(d.ident.toString()); buf.writestring(" = "); - if (stcToBuffer(buf, d.storage_class)) + if (stcToBuffer(*buf, d.storage_class)) buf.writeByte(' '); /* https://issues.dlang.org/show_bug.cgi?id=23223 @@ -1484,18 +1486,18 @@ public: } else if (d.type.ty == Tfunction) { - if (stcToBuffer(buf, d.storage_class)) + if (stcToBuffer(*buf, d.storage_class)) buf.writeByte(' '); - typeToBuffer(d.type, d.ident, buf, hgs); + typeToBuffer(d.type, d.ident, *buf, hgs); } else if (d.ident) { hgs.declstring = (d.ident == Id.string || d.ident == Id.wstring || d.ident == Id.dstring); buf.writestring(d.ident.toString()); buf.writestring(" = "); - if (stcToBuffer(buf, d.storage_class)) + if (stcToBuffer(*buf, d.storage_class)) buf.writeByte(' '); - typeToBuffer(d.type, null, buf, hgs); + typeToBuffer(d.type, null, *buf, hgs); hgs.declstring = false; } buf.writeByte(';'); @@ -1509,7 +1511,7 @@ public: if (d.aliassym) d.aliassym.accept(this); else // d.type - typeToBuffer(d.type, null, buf, hgs); + typeToBuffer(d.type, null, *buf, hgs); buf.writeByte(';'); buf.writenl(); } @@ -1518,69 +1520,18 @@ public: { if (d.storage_class & STC.local) return; - visitVarDecl(d, false); + visitVarDecl(d, false, *buf, *hgs); buf.writeByte(';'); buf.writenl(); } - void visitVarDecl(VarDeclaration v, bool anywritten) - { - const bool isextern = hgs.hdrgen && - !hgs.insideFuncBody && - !hgs.tpltMember && - !hgs.insideAggregate && - !(v.storage_class & STC.manifest); - - void vinit(VarDeclaration v) - { - auto ie = v._init.isExpInitializer(); - if (ie && (ie.exp.op == EXP.construct || ie.exp.op == EXP.blit)) - (cast(AssignExp)ie.exp).e2.expressionToBuffer(buf, hgs); - else - v._init.initializerToBuffer(buf, hgs); - } - - if (anywritten) - { - buf.writestring(", "); - buf.writestring(v.ident.toString()); - } - else - { - const bool useTypeof = isextern && v._init && !v.type; - auto stc = v.storage_class; - if (isextern) - stc |= STC.extern_; - if (useTypeof) - stc &= ~STC.auto_; - if (stcToBuffer(buf, stc)) - buf.writeByte(' '); - if (v.type) - typeToBuffer(v.type, v.ident, buf, hgs); - else if (useTypeof) - { - buf.writestring("typeof("); - vinit(v); - buf.writestring(") "); - buf.writestring(v.ident.toString()); - } - else - buf.writestring(v.ident.toString()); - } - if (v._init && !isextern) - { - buf.writestring(" = "); - vinit(v); - } - } - override void visit(FuncDeclaration f) { //printf("FuncDeclaration::toCBuffer() '%s'\n", f.toChars()); - if (stcToBuffer(buf, f.storage_class)) + if (stcToBuffer(*buf, f.storage_class)) buf.writeByte(' '); auto tf = cast(TypeFunction)f.type; - typeToBuffer(tf, f.ident, buf, hgs); + typeToBuffer(tf, f.ident, *buf, hgs); if (hgs.hdrgen) { @@ -1627,7 +1578,7 @@ public: { assert(es.exp && es.exp.op == EXP.assert_); buf.writestring(" ("); - (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs); + (cast(AssertExp)es.exp).e1.expressionToBuffer(*buf, hgs); buf.writeByte(')'); buf.writenl(); requireDo = false; @@ -1635,7 +1586,7 @@ public: else { buf.writenl(); - frequire.statementToBuffer(buf, hgs); + frequire.statementToBuffer(*buf, hgs); requireDo = true; } } @@ -1655,7 +1606,7 @@ public: buf.writestring(fensure.id.toString()); } buf.writestring("; "); - (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs); + (cast(AssertExp)es.exp).e1.expressionToBuffer(*buf, hgs); buf.writeByte(')'); buf.writenl(); requireDo = false; @@ -1669,7 +1620,7 @@ public: buf.writeByte(')'); } buf.writenl(); - fensure.ensure.statementToBuffer(buf, hgs); + fensure.ensure.statementToBuffer(*buf, hgs); requireDo = true; } } @@ -1717,7 +1668,7 @@ public: buf.writeByte('{'); buf.writenl(); buf.level++; - f.fbody.statementToBuffer(buf, hgs); + f.fbody.statementToBuffer(*buf, hgs); buf.level--; buf.writeByte('}'); buf.writenl(); @@ -1740,8 +1691,8 @@ public: TypeFunction tf = cast(TypeFunction)f.type; if (!f.inferRetType && tf.next) - typeToBuffer(tf.next, null, buf, hgs); - parametersToBuffer(tf.parameterList, buf, hgs); + typeToBuffer(tf.next, null, *buf, hgs); + parametersToBuffer(tf.parameterList, *buf, hgs); // https://issues.dlang.org/show_bug.cgi?id=20074 void printAttribute(string str) @@ -1764,7 +1715,7 @@ public: if (rs && rs.exp) { buf.writestring(" => "); - rs.exp.expressionToBuffer(buf, hgs); + rs.exp.expressionToBuffer(*buf, hgs); } else { @@ -1776,7 +1727,7 @@ public: override void visit(PostBlitDeclaration d) { - if (stcToBuffer(buf, d.storage_class)) + if (stcToBuffer(*buf, d.storage_class)) buf.writeByte(' '); buf.writestring("this(this)"); bodyToBuffer(d); @@ -1784,7 +1735,7 @@ public: override void visit(DtorDeclaration d) { - if (stcToBuffer(buf, d.storage_class)) + if (stcToBuffer(*buf, d.storage_class)) buf.writeByte(' '); buf.writestring("~this()"); bodyToBuffer(d); @@ -1792,7 +1743,7 @@ public: override void visit(StaticCtorDeclaration d) { - if (stcToBuffer(buf, d.storage_class & ~STC.static_)) + if (stcToBuffer(*buf, d.storage_class & ~STC.static_)) buf.writeByte(' '); if (d.isSharedStaticCtorDeclaration()) buf.writestring("shared "); @@ -1808,7 +1759,7 @@ public: override void visit(StaticDtorDeclaration d) { - if (stcToBuffer(buf, d.storage_class & ~STC.static_)) + if (stcToBuffer(*buf, d.storage_class & ~STC.static_)) buf.writeByte(' '); if (d.isSharedStaticDtorDeclaration()) buf.writestring("shared "); @@ -1826,14 +1777,14 @@ public: { if (hgs.hdrgen) return; - if (stcToBuffer(buf, d.storage_class)) + if (stcToBuffer(*buf, d.storage_class)) buf.writeByte(' '); buf.writestring("invariant"); if(auto es = d.fbody.isExpStatement()) { assert(es.exp && es.exp.op == EXP.assert_); buf.writestring(" ("); - (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs); + (cast(AssertExp)es.exp).e1.expressionToBuffer(*buf, hgs); buf.writestring(");"); buf.writenl(); } @@ -1847,7 +1798,7 @@ public: { if (hgs.hdrgen) return; - if (stcToBuffer(buf, d.storage_class)) + if (stcToBuffer(*buf, d.storage_class)) buf.writeByte(' '); buf.writestring("unittest"); bodyToBuffer(d); @@ -1855,33 +1806,88 @@ public: override void visit(BitFieldDeclaration d) { - if (stcToBuffer(buf, d.storage_class)) + if (stcToBuffer(*buf, d.storage_class)) buf.writeByte(' '); Identifier id = d.isAnonymous() ? null : d.ident; - typeToBuffer(d.type, id, buf, hgs); + typeToBuffer(d.type, id, *buf, hgs); buf.writestring(" : "); - d.width.expressionToBuffer(buf, hgs); + d.width.expressionToBuffer(*buf, hgs); buf.writeByte(';'); buf.writenl(); } override void visit(NewDeclaration d) { - if (stcToBuffer(buf, d.storage_class & ~STC.static_)) + if (stcToBuffer(*buf, d.storage_class & ~STC.static_)) buf.writeByte(' '); buf.writestring("new();"); } override void visit(Module m) { - moduleToBuffer2(m, buf, hgs); + moduleToBuffer2(m, *buf, hgs); + } +} + +/******************************************* + * Pretty-print a VarDeclaration to buf. + */ +private void visitVarDecl(VarDeclaration v, bool anywritten, ref OutBuffer buf, ref HdrGenState hgs) +{ + const bool isextern = hgs.hdrgen && + !hgs.insideFuncBody && + !hgs.tpltMember && + !hgs.insideAggregate && + !(v.storage_class & STC.manifest); + + void vinit(VarDeclaration v) + { + auto ie = v._init.isExpInitializer(); + if (ie && (ie.exp.op == EXP.construct || ie.exp.op == EXP.blit)) + (cast(AssignExp)ie.exp).e2.expressionToBuffer(buf, &hgs); + else + v._init.initializerToBuffer(buf, &hgs); + } + + if (anywritten) + { + buf.writestring(", "); + buf.writestring(v.ident.toString()); + } + else + { + const bool useTypeof = isextern && v._init && !v.type; + auto stc = v.storage_class; + if (isextern) + stc |= STC.extern_; + if (useTypeof) + stc &= ~STC.auto_; + if (stcToBuffer(buf, stc)) + buf.writeByte(' '); + if (v.type) + typeToBuffer(v.type, v.ident, buf, &hgs); + else if (useTypeof) + { + buf.writestring("typeof("); + vinit(v); + buf.writestring(") "); + buf.writestring(v.ident.toString()); + } + else + buf.writestring(v.ident.toString()); + } + if (v._init && !isextern) + { + buf.writestring(" = "); + vinit(v); } } + /********************************************* * Print expression to buffer. */ -private void expressionPrettyPrint(Expression e, OutBuffer* buf, HdrGenState* hgs) +private void expressionPrettyPrint(Expression e, ref OutBuffer buf, HdrGenState* hgs) { void visit(Expression e) { @@ -1922,7 +1928,7 @@ private void expressionPrettyPrint(Expression e, OutBuffer* buf, HdrGenState* hg case Tdchar: { const o = buf.length; - writeSingleCharLiteral(*buf, cast(dchar) v); + writeSingleCharLiteral(buf, cast(dchar) v); if (hgs.ddoc) escapeDdocString(buf, o); break; @@ -2064,7 +2070,7 @@ private void expressionPrettyPrint(Expression e, OutBuffer* buf, HdrGenState* hg const o = buf.length; foreach (i; 0 .. e.len) { - writeCharLiteral(*buf, e.getCodeUnit(i)); + writeCharLiteral(buf, e.getCodeUnit(i)); } if (hgs.ddoc) escapeDdocString(buf, o); @@ -2251,8 +2257,7 @@ private void expressionPrettyPrint(Expression e, OutBuffer* buf, HdrGenState* hg // which isn't correct as regular D code. buf.writeByte('('); - scope v = new DsymbolPrettyPrintVisitor(buf, hgs); - v.visitVarDecl(var, false); + visitVarDecl(var, false, buf, *hgs); buf.writeByte(';'); buf.writeByte(')'); @@ -2308,7 +2313,7 @@ private void expressionPrettyPrint(Expression e, OutBuffer* buf, HdrGenState* hg if (e.parameters && e.parameters.length) { buf.writestring(", "); - scope v = new DsymbolPrettyPrintVisitor(buf, hgs); + scope v = new DsymbolPrettyPrintVisitor(&buf, hgs); v.visitTemplateParameters(e.parameters); } buf.writeByte(')'); @@ -2717,7 +2722,7 @@ private void expressionPrettyPrint(Expression e, OutBuffer* buf, HdrGenState* hg * allowHex = whether hex floating point literals may be used * for greater accuracy */ -void floatToBuffer(Type type, const real_t value, OutBuffer* buf, const bool allowHex) +void floatToBuffer(Type type, const real_t value, ref OutBuffer buf, const bool allowHex) { /** sizeof(value)*3 is because each byte of mantissa is max of 256 (3 characters). The string will be "-M.MMMMe-4932". @@ -2762,9 +2767,9 @@ void floatToBuffer(Type type, const real_t value, OutBuffer* buf, const bool all } } -private void templateParameterToBuffer(TemplateParameter tp, OutBuffer* buf, HdrGenState* hgs) +private void templateParameterToBuffer(TemplateParameter tp, ref OutBuffer buf, HdrGenState* hgs) { - scope v = new TemplateParameterPrettyPrintVisitor(buf, hgs); + scope v = new TemplateParameterPrettyPrintVisitor(&buf, hgs); tp.accept(v); } @@ -2787,12 +2792,12 @@ public: if (tp.specType) { buf.writestring(" : "); - typeToBuffer(tp.specType, null, buf, hgs); + typeToBuffer(tp.specType, null, *buf, hgs); } if (tp.defaultType) { buf.writestring(" = "); - typeToBuffer(tp.defaultType, null, buf, hgs); + typeToBuffer(tp.defaultType, null, *buf, hgs); } } @@ -2806,33 +2811,33 @@ public: { buf.writestring("alias "); if (tp.specType) - typeToBuffer(tp.specType, tp.ident, buf, hgs); + typeToBuffer(tp.specType, tp.ident, *buf, hgs); else buf.writestring(tp.ident.toString()); if (tp.specAlias) { buf.writestring(" : "); - objectToBuffer(tp.specAlias, buf, hgs); + objectToBuffer(tp.specAlias, *buf, hgs); } if (tp.defaultAlias) { buf.writestring(" = "); - objectToBuffer(tp.defaultAlias, buf, hgs); + objectToBuffer(tp.defaultAlias, *buf, hgs); } } override void visit(TemplateValueParameter tp) { - typeToBuffer(tp.valType, tp.ident, buf, hgs); + typeToBuffer(tp.valType, tp.ident, *buf, hgs); if (tp.specValue) { buf.writestring(" : "); - tp.specValue.expressionToBuffer(buf, hgs); + tp.specValue.expressionToBuffer(*buf, hgs); } if (tp.defaultValue) { buf.writestring(" = "); - tp.defaultValue.expressionToBuffer(buf, hgs); + tp.defaultValue.expressionToBuffer(*buf, hgs); } } @@ -2843,9 +2848,9 @@ public: } } -private void conditionToBuffer(Condition c, OutBuffer* buf, HdrGenState* hgs) +private void conditionToBuffer(Condition c, ref OutBuffer buf, HdrGenState* hgs) { - scope v = new ConditionPrettyPrintVisitor(buf, hgs); + scope v = new ConditionPrettyPrintVisitor(&buf, hgs); c.accept(v); } @@ -2885,42 +2890,42 @@ public: override void visit(StaticIfCondition c) { buf.writestring("static if ("); - c.exp.expressionToBuffer(buf, hgs); + c.exp.expressionToBuffer(*buf, hgs); buf.writeByte(')'); } } -void toCBuffer(const Statement s, OutBuffer* buf, HdrGenState* hgs) +void toCBuffer(const Statement s, ref OutBuffer buf, ref HdrGenState hgs) { - (cast()s).statementToBuffer(buf, hgs); + (cast()s).statementToBuffer(buf, &hgs); } -void toCBuffer(const Type t, OutBuffer* buf, const Identifier ident, HdrGenState* hgs) +void toCBuffer(const Type t, ref OutBuffer buf, const Identifier ident, ref HdrGenState hgs) { - typeToBuffer(cast() t, ident, buf, hgs); + typeToBuffer(cast() t, ident, buf, &hgs); } -void toCBuffer(Dsymbol s, OutBuffer* buf, HdrGenState* hgs) +void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) { - scope v = new DsymbolPrettyPrintVisitor(buf, hgs); + scope v = new DsymbolPrettyPrintVisitor(&buf, &hgs); s.accept(v); } // used from TemplateInstance::toChars() and TemplateMixin::toChars() -void toCBufferInstance(const TemplateInstance ti, OutBuffer* buf, bool qualifyTypes = false) +void toCBufferInstance(const TemplateInstance ti, ref OutBuffer buf, bool qualifyTypes = false) { HdrGenState hgs; hgs.fullQual = qualifyTypes; - scope v = new DsymbolPrettyPrintVisitor(buf, &hgs); + scope v = new DsymbolPrettyPrintVisitor(&buf, &hgs); v.visit(cast() ti); } -void toCBuffer(const Initializer iz, OutBuffer* buf, HdrGenState* hgs) +void toCBuffer(const Initializer iz, ref OutBuffer buf, ref HdrGenState hgs) { - initializerToBuffer(cast() iz, buf, hgs); + initializerToBuffer(cast() iz, buf, &hgs); } -bool stcToBuffer(OutBuffer* buf, StorageClass stc) @safe +bool stcToBuffer(ref OutBuffer buf, StorageClass stc) @safe { //printf("stc: %llx\n", stc); bool result = false; @@ -3039,7 +3044,7 @@ string stcToString(ref StorageClass stc) @safe return null; } -private void linkageToBuffer(OutBuffer* buf, LINK linkage) @safe +private void linkageToBuffer(ref OutBuffer buf, LINK linkage) @safe { const s = linkageToString(linkage); if (s.length) @@ -3077,7 +3082,7 @@ string linkageToString(LINK linkage) pure nothrow @safe } } -void visibilityToBuffer(OutBuffer* buf, Visibility vis) +void visibilityToBuffer(ref OutBuffer buf, Visibility vis) { buf.writestring(visibilityToString(vis.kind)); if (vis.kind == Visibility.Kind.package_ && vis.pkg) @@ -3121,28 +3126,28 @@ extern (D) string visibilityToString(Visibility.Kind kind) nothrow pure @safe } // Print the full function signature with correct ident, attributes and template args -void functionToBufferFull(TypeFunction tf, OutBuffer* buf, const Identifier ident, HdrGenState* hgs, TemplateDeclaration td) +void functionToBufferFull(TypeFunction tf, ref OutBuffer buf, const Identifier ident, HdrGenState* hgs, TemplateDeclaration td) { //printf("TypeFunction::toCBuffer() this = %p\n", this); visitFuncIdentWithPrefix(tf, ident, td, buf, hgs); } // ident is inserted before the argument list and will be "function" or "delegate" for a type -void functionToBufferWithIdent(TypeFunction tf, OutBuffer* buf, const(char)* ident, bool isStatic) +void functionToBufferWithIdent(TypeFunction tf, ref OutBuffer buf, const(char)* ident, bool isStatic) { HdrGenState hgs; visitFuncIdentWithPostfix(tf, ident.toDString(), buf, &hgs, isStatic); } -void toCBuffer(const Expression e, OutBuffer* buf, HdrGenState* hgs) +void toCBuffer(const Expression e, ref OutBuffer buf, ref HdrGenState hgs) { - expressionPrettyPrint(cast()e, buf, hgs); + expressionPrettyPrint(cast()e, buf, &hgs); } /************************************************** * Write out argument types to buf. */ -void argExpTypesToCBuffer(OutBuffer* buf, Expressions* arguments) +void argExpTypesToCBuffer(ref OutBuffer buf, Expressions* arguments) { if (!arguments || !arguments.length) return; @@ -3155,13 +3160,13 @@ void argExpTypesToCBuffer(OutBuffer* buf, Expressions* arguments) } } -void toCBuffer(const TemplateParameter tp, OutBuffer* buf, HdrGenState* hgs) +void toCBuffer(const TemplateParameter tp, ref OutBuffer buf, ref HdrGenState hgs) { - scope v = new TemplateParameterPrettyPrintVisitor(buf, hgs); + scope v = new TemplateParameterPrettyPrintVisitor(&buf, &hgs); (cast() tp).accept(v); } -void arrayObjectsToBuffer(OutBuffer* buf, Objects* objects) +void arrayObjectsToBuffer(ref OutBuffer buf, Objects* objects) { if (!objects || !objects.length) return; @@ -3184,7 +3189,7 @@ extern (C++) const(char)* parametersTypeToChars(ParameterList pl) { OutBuffer buf; HdrGenState hgs; - parametersToBuffer(pl, &buf, &hgs); + parametersToBuffer(pl, buf, &hgs); return buf.extractChars(); } @@ -3202,7 +3207,7 @@ const(char)* parameterToChars(Parameter parameter, TypeFunction tf, bool fullQua HdrGenState hgs; hgs.fullQual = fullQual; - parameterToBuffer(parameter, &buf, &hgs); + parameterToBuffer(parameter, buf, &hgs); if (tf.parameterList.varargs == VarArg.typesafe && parameter == tf.parameterList[tf.parameterList.parameters.length - 1]) { @@ -3220,7 +3225,7 @@ const(char)* parameterToChars(Parameter parameter, TypeFunction tf, bool fullQua * hgs = context */ -private void parametersToBuffer(ParameterList pl, OutBuffer* buf, HdrGenState* hgs) +private void parametersToBuffer(ParameterList pl, ref OutBuffer buf, HdrGenState* hgs) { buf.writeByte('('); foreach (i; 0 .. pl.length) @@ -3258,7 +3263,7 @@ private void parametersToBuffer(ParameterList pl, OutBuffer* buf, HdrGenState* h * buf = buffer to write it to * hgs = context */ -private void parameterToBuffer(Parameter p, OutBuffer* buf, HdrGenState* hgs) +private void parameterToBuffer(Parameter p, ref OutBuffer buf, HdrGenState* hgs) { if (p.userAttribDecl) { @@ -3330,7 +3335,7 @@ private void parameterToBuffer(Parameter p, OutBuffer* buf, HdrGenState* hgs) * basis = replace `null`s in argument list with this expression (for sparse array literals) * names = if non-null, use these as the names for the arguments */ -private void argsToBuffer(Expressions* expressions, OutBuffer* buf, HdrGenState* hgs, Expression basis = null, Identifiers* names = null) +private void argsToBuffer(Expressions* expressions, ref OutBuffer buf, HdrGenState* hgs, Expression basis = null, Identifiers* names = null) { if (!expressions || !expressions.length) return; @@ -3381,7 +3386,7 @@ private void argsToBuffer(Expressions* expressions, OutBuffer* buf, HdrGenState* } } -private void sizeToBuffer(Expression e, OutBuffer* buf, HdrGenState* hgs) +private void sizeToBuffer(Expression e, ref OutBuffer buf, HdrGenState* hgs) { if (e.type == Type.tsize_t) { @@ -3409,7 +3414,7 @@ private void sizeToBuffer(Expression e, OutBuffer* buf, HdrGenState* hgs) expToBuffer(e, PREC.assign, buf, hgs); } -private void expressionToBuffer(Expression e, OutBuffer* buf, HdrGenState* hgs) +private void expressionToBuffer(Expression e, ref OutBuffer buf, HdrGenState* hgs) { expressionPrettyPrint(e, buf, hgs); } @@ -3418,7 +3423,7 @@ private void expressionToBuffer(Expression e, OutBuffer* buf, HdrGenState* hgs) * Write expression out to buf, but wrap it * in ( ) if its precedence is less than pr. */ -private void expToBuffer(Expression e, PREC pr, OutBuffer* buf, HdrGenState* hgs) +private void expToBuffer(Expression e, PREC pr, ref OutBuffer buf, HdrGenState* hgs) { debug { @@ -3452,7 +3457,7 @@ private void expToBuffer(Expression e, PREC pr, OutBuffer* buf, HdrGenState* hgs /************************************************** * An entry point to pretty-print type. */ -private void typeToBuffer(Type t, const Identifier ident, OutBuffer* buf, HdrGenState* hgs, +private void typeToBuffer(Type t, const Identifier ident, ref OutBuffer buf, HdrGenState* hgs, ubyte modMask = 0) { if (auto tf = t.isTypeFunction()) @@ -3468,7 +3473,7 @@ private void typeToBuffer(Type t, const Identifier ident, OutBuffer* buf, HdrGen } } -private void visitWithMask(Type t, ubyte modMask, OutBuffer* buf, HdrGenState* hgs) +private void visitWithMask(Type t, ubyte modMask, ref OutBuffer buf, HdrGenState* hgs) { // Tuples and functions don't use the type constructor syntax if (modMask == t.mod || t.ty == Tfunction || t.ty == Ttuple) @@ -3504,7 +3509,7 @@ private void visitWithMask(Type t, ubyte modMask, OutBuffer* buf, HdrGenState* h } -private void dumpTemplateInstance(TemplateInstance ti, OutBuffer* buf, HdrGenState* hgs) +private void dumpTemplateInstance(TemplateInstance ti, ref OutBuffer buf, HdrGenState* hgs) { buf.writeByte('{'); buf.writenl(); @@ -3527,7 +3532,7 @@ private void dumpTemplateInstance(TemplateInstance ti, OutBuffer* buf, HdrGenSta } -private void tiargsToBuffer(TemplateInstance ti, OutBuffer* buf, HdrGenState* hgs) +private void tiargsToBuffer(TemplateInstance ti, ref OutBuffer buf, HdrGenState* hgs) { buf.writeByte('!'); if (ti.nest) @@ -3576,7 +3581,7 @@ private void tiargsToBuffer(TemplateInstance ti, OutBuffer* buf, HdrGenState* hg * This makes a 'pretty' version of the template arguments. * It's analogous to genIdent() which makes a mangled version. */ -private void objectToBuffer(RootObject oarg, OutBuffer* buf, HdrGenState* hgs) +private void objectToBuffer(RootObject oarg, ref OutBuffer buf, HdrGenState* hgs) { //printf("objectToBuffer()\n"); /* The logic of this should match what genIdent() does. The _dynamic_cast() @@ -3629,7 +3634,7 @@ private void objectToBuffer(RootObject oarg, OutBuffer* buf, HdrGenState* hgs) } -private void visitFuncIdentWithPostfix(TypeFunction t, const char[] ident, OutBuffer* buf, HdrGenState* hgs, bool isStatic) +private void visitFuncIdentWithPostfix(TypeFunction t, const char[] ident, ref OutBuffer buf, HdrGenState* hgs, bool isStatic) { if (t.inuse) { @@ -3674,7 +3679,7 @@ private void visitFuncIdentWithPostfix(TypeFunction t, const char[] ident, OutBu } private void visitFuncIdentWithPrefix(TypeFunction t, const Identifier ident, TemplateDeclaration td, - OutBuffer* buf, HdrGenState* hgs) + ref OutBuffer buf, HdrGenState* hgs) { if (t.inuse) { @@ -3743,7 +3748,7 @@ private void visitFuncIdentWithPrefix(TypeFunction t, const Identifier ident, Te } -private void initializerToBuffer(Initializer inx, OutBuffer* buf, HdrGenState* hgs) +private void initializerToBuffer(Initializer inx, ref OutBuffer buf, HdrGenState* hgs) { void visitError(ErrorInitializer iz) { @@ -3811,7 +3816,7 @@ private void initializerToBuffer(Initializer inx, OutBuffer* buf, HdrGenState* h if (d.exp) { buf.writeByte('['); - toCBuffer(d.exp, buf, hgs); + toCBuffer(d.exp, buf, *hgs); buf.writeByte(']'); } else @@ -3832,7 +3837,7 @@ private void initializerToBuffer(Initializer inx, OutBuffer* buf, HdrGenState* h } -private void typeToBufferx(Type t, OutBuffer* buf, HdrGenState* hgs) +private void typeToBufferx(Type t, ref OutBuffer buf, HdrGenState* hgs) { void visitType(Type t) { @@ -4020,7 +4025,7 @@ private void typeToBufferx(Type t, OutBuffer* buf, HdrGenState* hgs) buf.writeByte(' '); if (t.id) buf.writestring(t.id.toChars()); - if (t.tok == TOK.enum_ && t.base.ty != TY.Tint32) + if (t.tok == TOK.enum_ && t.base && t.base.ty != TY.Tint32) { buf.writestring(" : "); visitWithMask(t.base, t.mod, buf, hgs); diff --git a/gcc/d/dmd/hdrgen.h b/gcc/d/dmd/hdrgen.h index 43fea34..e43a355 100644 --- a/gcc/d/dmd/hdrgen.h +++ b/gcc/d/dmd/hdrgen.h @@ -15,7 +15,7 @@ class Module; -void genhdrfile(Module *m); +void genhdrfile(Module *m, OutBuffer &buf); void genCppHdrFiles(Modules &ms); -void moduleToBuffer(OutBuffer *buf, Module *m); +void moduleToBuffer(OutBuffer& buf, Module *m); const char *parametersTypeToChars(ParameterList pl); diff --git a/gcc/d/dmd/iasmgcc.d b/gcc/d/dmd/iasmgcc.d index 1d4dea4..5494fec 100644 --- a/gcc/d/dmd/iasmgcc.d +++ b/gcc/d/dmd/iasmgcc.d @@ -330,7 +330,7 @@ extern (C++) public Statement gccAsmSemantic(GccAsmStatement s, Scope *sc) s.insn = semanticString(sc, s.insn, "asm instruction template"); if (s.labels && s.outputargs) - s.error("extended asm statements with labels cannot have output constraints"); + error(s.loc, "extended asm statements with labels cannot have output constraints"); // Analyse all input and output operands. if (s.args) diff --git a/gcc/d/dmd/id.d b/gcc/d/dmd/id.d index 43b2e5f..62fb51f 100644 --- a/gcc/d/dmd/id.d +++ b/gcc/d/dmd/id.d @@ -114,6 +114,7 @@ immutable Msgtable[] msgtable = { "returnLabel", "__returnLabel" }, { "line" }, { "empty", "" }, + { "dotdotdot", "..." }, // use for error messages { "p" }, { "__vptr" }, { "__monitor" }, @@ -305,6 +306,7 @@ immutable Msgtable[] msgtable = { "aaKeys", "_aaKeys" }, { "aaValues", "_aaValues" }, { "aaRehash", "_aaRehash" }, + { "_aaAsStruct" }, { "monitorenter", "_d_monitorenter" }, { "monitorexit", "_d_monitorexit" }, { "criticalenter", "_d_criticalenter2" }, diff --git a/gcc/d/dmd/init.d b/gcc/d/dmd/init.d index e7cf905..4501185 100644 --- a/gcc/d/dmd/init.d +++ b/gcc/d/dmd/init.d @@ -61,7 +61,7 @@ extern (C++) class Initializer : ASTNode { OutBuffer buf; HdrGenState hgs; - .toCBuffer(this, &buf, &hgs); + toCBuffer(this, buf, hgs); return buf.extractChars(); } diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d index c60b431..45f09af8 100644 --- a/gcc/d/dmd/initsem.d +++ b/gcc/d/dmd/initsem.d @@ -53,31 +53,38 @@ import dmd.typesem; */ Expression toAssocArrayLiteral(ArrayInitializer ai) { - Expression e; - //printf("ArrayInitializer::toAssocArrayInitializer()\n"); + //printf("ArrayInitializer::toAssocArrayInitializer(%s)\n", ai.toChars()); //static int i; if (++i == 2) assert(0); const dim = ai.value.length; + if (!dim) + { + error(ai.loc, "invalid associative array initializer `%s`, use `null` instead", + ai.toChars()); + return ErrorExp.get(); + } + auto no(const char* format, Initializer i) + { + error(i.loc, format, i.toChars()); + return ErrorExp.get(); + } + Expression e; auto keys = new Expressions(dim); auto values = new Expressions(dim); for (size_t i = 0; i < dim; i++) { - e = ai.index[i]; - if (!e) - goto Lno; - (*keys)[i] = e; Initializer iz = ai.value[i]; - if (!iz) - goto Lno; + assert(iz); e = iz.initializerToExpression(); if (!e) - goto Lno; + return no("invalid value `%s` in initializer", iz); (*values)[i] = e; + e = ai.index[i]; + if (!e) + return no("missing key for value `%s` in initializer", iz); + (*keys)[i] = e; } e = new AssocArrayLiteralExp(ai.loc, keys, values); return e; -Lno: - error(ai.loc, "not an associative array initializer"); - return ErrorExp.get(); } /****************************************** diff --git a/gcc/d/dmd/json.d b/gcc/d/dmd/json.d index 9689986..c803bf8 100644 --- a/gcc/d/dmd/json.d +++ b/gcc/d/dmd/json.d @@ -810,17 +810,14 @@ public: Params: modules = array of the "root modules" */ - private void generateModules(Modules* modules) + private void generateModules(ref Modules modules) { arrayStart(); - if (modules) + foreach (m; modules) { - foreach (m; *modules) - { - if (global.params.verbose) - message("json gen %s", m.toChars()); - m.accept(this); - } + if (global.params.verbose) + message("json gen %s", m.toChars()); + m.accept(this); } arrayEnd(); } @@ -981,9 +978,15 @@ public: } } -extern (C++) void json_generate(OutBuffer* buf, Modules* modules) +/*********************************** + * Generate json for the modules. + * Params: + * modules = array of Modules + * buf = write json output to buf + */ +extern (C++) void json_generate(ref Modules modules, ref OutBuffer buf) { - scope ToJsonVisitor json = new ToJsonVisitor(buf); + scope ToJsonVisitor json = new ToJsonVisitor(&buf); // write trailing newline scope(exit) buf.writeByte('\n'); diff --git a/gcc/d/dmd/json.h b/gcc/d/dmd/json.h index 7a23897..09fdecd 100644 --- a/gcc/d/dmd/json.h +++ b/gcc/d/dmd/json.h @@ -15,5 +15,5 @@ struct OutBuffer; -void json_generate(OutBuffer *, Modules *); +void json_generate(Modules &, OutBuffer &); JsonFieldFlags tryParseJsonField(const char *fieldName); diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d index c28fe5c..28ffbf8 100644 --- a/gcc/d/dmd/lexer.d +++ b/gcc/d/dmd/lexer.d @@ -51,7 +51,7 @@ struct CompileEnv bool previewIn; /// `in` means `[ref] scope const`, accepts rvalues bool ddocOutput; /// collect embedded documentation comments bool shortenedMethods = true; /// allow => in normal function declarations - bool obsolete; /// warn on use of legacy code + bool masm; /// use MASM inline asm syntax } /*********************************************************** @@ -484,6 +484,12 @@ class Lexer goto default; wysiwygStringConstant(t); return; + case 'x': + if (p[1] != '"') + goto case_ident; + p++; + t.value = hexStringConstant(t); + return; case 'q': if (Ccompile) goto case_ident; @@ -526,7 +532,7 @@ class Lexer //case 'u': case 'v': case 'w': - case 'x': + /*case 'x':*/ case 'y': case 'z': case 'A': @@ -1476,6 +1482,84 @@ class Lexer } } + /************************************** + * Lex hex strings: + * x"0A ae 34FE BD" + */ + final TOK hexStringConstant(Token* t) + { + Loc start = loc(); + uint n = 0; + uint v = ~0; // dead assignment, needed to suppress warning + p++; + stringbuffer.setsize(0); + while (1) + { + dchar c = *p++; + switch (c) + { + case ' ': + case '\t': + case '\v': + case '\f': + continue; // skip white space + case '\r': + if (*p == '\n') + continue; // ignore '\r' if followed by '\n' + // Treat isolated '\r' as if it were a '\n' + goto case '\n'; + case '\n': + endOfLine(); + continue; + case 0: + case 0x1A: + error("unterminated string constant starting at %s", start.toChars()); + t.setString(); + // decrement `p`, because it needs to point to the next token (the 0 or 0x1A character is the TOK.endOfFile token). + p--; + return TOK.hexadecimalString; + case '"': + if (n & 1) + { + error("odd number (%d) of hex characters in hex string", n); + stringbuffer.writeByte(v); + } + t.setString(stringbuffer); + stringPostfix(t); + return TOK.hexadecimalString; + default: + if (c >= '0' && c <= '9') + c -= '0'; + else if (c >= 'a' && c <= 'f') + c -= 'a' - 10; + else if (c >= 'A' && c <= 'F') + c -= 'A' - 10; + else if (c & 0x80) + { + p--; + const u = decodeUTF(); + p++; + if (u == PS || u == LS) + endOfLine(); + else + error("non-hex character \\u%04x in hex string", u); + } + else + error("non-hex character '%c' in hex string", c); + if (n & 1) + { + v = (v << 4) | c; + stringbuffer.writeByte(v); + } + else + v = c; + n++; + break; + } + } + assert(0); // see bug 15731 + } + /** Lex a delimited string. Some examples of delimited strings are: --- diff --git a/gcc/d/dmd/location.d b/gcc/d/dmd/location.d index 0f3b9a7..ef2bd0a 100644 --- a/gcc/d/dmd/location.d +++ b/gcc/d/dmd/location.d @@ -38,8 +38,8 @@ debug info etc. struct Loc { private uint _linnum; - private ushort _charnum; - private ushort fileIndex; // index into filenames[], starting from 1 (0 means no filename) + private uint _charnum; + private uint fileIndex; // index into filenames[], starting from 1 (0 means no filename) version (LocOffset) uint fileOffset; /// utf8 code unit index relative to start of file, starting from 0 @@ -67,7 +67,7 @@ nothrow: extern (D) this(const(char)* filename, uint linnum, uint charnum) @safe { this._linnum = linnum; - this._charnum = cast(ushort) charnum; + this._charnum = charnum; this.filename = filename; } @@ -80,7 +80,7 @@ nothrow: /// ditto extern (C++) uint charnum(uint num) @nogc @safe { - return _charnum = cast(ushort) num; + return _charnum = num; } /// line number, starting from 1 @@ -114,8 +114,16 @@ nothrow: { //printf("setting %s\n", name); filenames.push(name); - fileIndex = cast(ushort)filenames.length; - assert(fileIndex); // no overflow + fileIndex = cast(uint)filenames.length; + if (!fileIndex) + { + import dmd.globals : global; + import dmd.errors : error, fatal; + + global.gag = 0; // ensure error message gets printed + error(Loc.initial, "internal compiler error: file name index overflow!"); + fatal(); + } } else fileIndex = 0; diff --git a/gcc/d/dmd/module.h b/gcc/d/dmd/module.h index 8b48110..ce51266 100644 --- a/gcc/d/dmd/module.h +++ b/gcc/d/dmd/module.h @@ -142,7 +142,7 @@ public: int doppelganger; // sub-module Symbol *cov; // private uint[] __coverage; - unsigned *covb; // bit array of valid code line numbers + DArray<unsigned> covb; // bit array of valid code line numbers Symbol *sictor; // module order independent constructor Symbol *sctor; // module constructor diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d index 9d83db1..63e20ed 100644 --- a/gcc/d/dmd/mtype.d +++ b/gcc/d/dmd/mtype.d @@ -157,7 +157,7 @@ MOD MODmerge(MOD mod1, MOD mod2) pure nothrow @nogc @safe /********************************* * Store modifier name into buf. */ -void MODtoBuffer(OutBuffer* buf, MOD mod) nothrow @safe +void MODtoBuffer(ref OutBuffer buf, MOD mod) nothrow @safe { buf.writestring(MODtoString(mod)); } @@ -787,7 +787,7 @@ extern (C++) abstract class Type : ASTNode HdrGenState hgs; hgs.fullQual = (ty == Tclass && !mod); - .toCBuffer(this, &buf, null, &hgs); + toCBuffer(this, buf, null, hgs); return buf.extractChars(); } @@ -799,7 +799,7 @@ extern (C++) abstract class Type : ASTNode HdrGenState hgs; hgs.fullQual = QualifyTypes; - .toCBuffer(this, &buf, null, &hgs); + toCBuffer(this, buf, null, hgs); return buf.extractChars(); } @@ -973,7 +973,7 @@ extern (C++) abstract class Type : ASTNode /********************************* * Store this type's modifier name into buf. */ - final void modToBuffer(OutBuffer* buf) nothrow const + final void modToBuffer(ref OutBuffer buf) nothrow const { if (mod) { @@ -989,7 +989,7 @@ extern (C++) abstract class Type : ASTNode { OutBuffer buf; buf.reserve(16); - modToBuffer(&buf); + modToBuffer(buf); return buf.extractChars(); } @@ -4563,7 +4563,7 @@ extern (C++) final class TypeFunction : TypeNext continue; if (params == parameterList.parameters) params = parameterList.parameters.copy(); - (*params)[i] = new Parameter(p.storageClass, t, null, null, null); + (*params)[i] = new Parameter(p.loc, p.storageClass, t, null, null, null); } if (next == tret && params == parameterList.parameters) return this; @@ -6218,7 +6218,7 @@ extern (C++) final class TypeTuple : Type Expression e = (*exps)[i]; if (e.type.ty == Ttuple) e.error("cannot form sequence of sequences"); - auto arg = new Parameter(STC.undefined_, e.type, null, null, null); + auto arg = new Parameter(e.loc, STC.undefined_, e.type, null, null, null); (*arguments)[i] = arg; } } @@ -6244,15 +6244,15 @@ extern (C++) final class TypeTuple : Type { super(Ttuple); arguments = new Parameters(); - arguments.push(new Parameter(0, t1, null, null, null)); + arguments.push(new Parameter(Loc.initial, 0, t1, null, null, null)); } extern (D) this(Type t1, Type t2) { super(Ttuple); arguments = new Parameters(); - arguments.push(new Parameter(0, t1, null, null, null)); - arguments.push(new Parameter(0, t2, null, null, null)); + arguments.push(new Parameter(Loc.initial, 0, t1, null, null, null)); + arguments.push(new Parameter(Loc.initial, 0, t2, null, null, null)); } static TypeTuple create() @safe @@ -6661,14 +6661,16 @@ extern (C++) final class Parameter : ASTNode { import dmd.attrib : UserAttributeDeclaration; + Loc loc; StorageClass storageClass; Type type; Identifier ident; Expression defaultArg; UserAttributeDeclaration userAttribDecl; // user defined attributes - extern (D) this(StorageClass storageClass, Type type, Identifier ident, Expression defaultArg, UserAttributeDeclaration userAttribDecl) @safe + extern (D) this(const ref Loc loc, StorageClass storageClass, Type type, Identifier ident, Expression defaultArg, UserAttributeDeclaration userAttribDecl) @safe { + this.loc = loc; this.type = type; this.ident = ident; this.storageClass = storageClass; @@ -6676,14 +6678,14 @@ extern (C++) final class Parameter : ASTNode this.userAttribDecl = userAttribDecl; } - static Parameter create(StorageClass storageClass, Type type, Identifier ident, Expression defaultArg, UserAttributeDeclaration userAttribDecl) @safe + static Parameter create(const ref Loc loc, StorageClass storageClass, Type type, Identifier ident, Expression defaultArg, UserAttributeDeclaration userAttribDecl) @safe { - return new Parameter(storageClass, type, ident, defaultArg, userAttribDecl); + return new Parameter(loc, storageClass, type, ident, defaultArg, userAttribDecl); } Parameter syntaxCopy() { - return new Parameter(storageClass, type ? type.syntaxCopy() : null, ident, defaultArg ? defaultArg.syntaxCopy() : null, userAttribDecl ? userAttribDecl.syntaxCopy(null) : null); + return new Parameter(loc, storageClass, type ? type.syntaxCopy() : null, ident, defaultArg ? defaultArg.syntaxCopy() : null, userAttribDecl ? userAttribDecl.syntaxCopy(null) : null); } /**************************************************** @@ -7688,3 +7690,28 @@ pure string visitTYCase(string handler) @safe } assert(0); } + + +/** + * Returns: + * `TypeIdentifier` corresponding to `object.Throwable` + */ +TypeIdentifier getThrowable() +{ + auto tid = new TypeIdentifier(Loc.initial, Id.empty); + tid.addIdent(Id.object); + tid.addIdent(Id.Throwable); + return tid; +} + +/** + * Returns: + * TypeIdentifier corresponding to `object.Exception` + */ +TypeIdentifier getException() +{ + auto tid = new TypeIdentifier(Loc.initial, Id.empty); + tid.addIdent(Id.object); + tid.addIdent(Id.Exception); + return tid; +} diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h index 457b91f..aeeee8c 100644 --- a/gcc/d/dmd/mtype.h +++ b/gcc/d/dmd/mtype.h @@ -237,7 +237,7 @@ public: virtual unsigned alignsize(); Type *trySemantic(const Loc &loc, Scope *sc); Type *merge2(); - void modToBuffer(OutBuffer *buf) const; + void modToBuffer(OutBuffer& buf) const; char *modToChars() const; virtual bool isintegral(); @@ -563,13 +563,14 @@ enum class PURE : unsigned char class Parameter final : public ASTNode { public: + Loc loc; StorageClass storageClass; Type *type; Identifier *ident; Expression *defaultArg; UserAttributeDeclaration *userAttribDecl; // user defined attributes - static Parameter *create(StorageClass storageClass, Type *type, Identifier *ident, + static Parameter *create(const Loc &loc, StorageClass storageClass, Type *type, Identifier *ident, Expression *defaultArg, UserAttributeDeclaration *userAttribDecl); Parameter *syntaxCopy(); Type *isLazyArray(); diff --git a/gcc/d/dmd/opover.d b/gcc/d/dmd/opover.d index 457e8b6..f9de1ee 100644 --- a/gcc/d/dmd/opover.d +++ b/gcc/d/dmd/opover.d @@ -1767,10 +1767,10 @@ private FuncDeclaration findBestOpApplyMatch(Expression ethis, FuncDeclaration f if (fd_ambig) { - .error(ethis.loc, "`%s.%s` matches more than one declaration:\n`%s`: `%s`\nand:\n`%s`: `%s`", - ethis.toChars(), fstart.ident.toChars(), - fd_best.loc.toChars(), fd_best.type.toChars(), - fd_ambig.loc.toChars(), fd_ambig.type.toChars()); + .error(ethis.loc, "`%s.%s` matches more than one declaration:", + ethis.toChars(), fstart.ident.toChars()); + .errorSupplemental(fd_best.loc, "`%s`\nand:", fd_best.type.toChars()); + .errorSupplemental(fd_ambig.loc, "`%s`", fd_ambig.type.toChars()); return null; } diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d index f98e7c7..3756382 100644 --- a/gcc/d/dmd/optimize.d +++ b/gcc/d/dmd/optimize.d @@ -1280,19 +1280,25 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) //printf("CatExp::optimize(%d) %s\n", result, e.toChars()); if (binOptimize(e, result)) return; - if (auto ce1 = e.e1.isCatExp()) - { - // https://issues.dlang.org/show_bug.cgi?id=12798 - // optimize ((expr ~ str1) ~ str2) - scope CatExp cex = new CatExp(e.loc, ce1.e2, e.e2); - cex.type = e.type; - Expression ex = Expression_optimize(cex, result, false); - if (ex != cex) + + if (e.type == Type.tstring) + if (auto ce1 = e.e1.isCatExp()) { - e.e1 = ce1.e1; - e.e2 = ex; + // https://issues.dlang.org/show_bug.cgi?id=12798 + // optimize ((expr ~ str1) ~ str2) + // https://issues.dlang.org/show_bug.cgi?id=24078 + // This optimization is only valid if `expr` is a string. + // Otherwise it leads to: + // `["c"] ~ "a" ~ "b"` becoming `["c"] ~ "ab"` + scope CatExp cex = new CatExp(e.loc, ce1.e2, e.e2); + cex.type = e.type; + Expression ex = Expression_optimize(cex, result, false); + if (ex != cex) + { + e.e1 = ce1.e1; + e.e2 = ex; + } } - } // optimize "str"[] -> "str" if (auto se1 = e.e1.isSliceExp()) { diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index 13bba4f..2a96415 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -1204,7 +1204,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (orig & added) { OutBuffer buf; - AST.stcToBuffer(&buf, added); + AST.stcToBuffer(buf, added); error("redundant attribute `%s`", buf.peekChars()); return orig | added; } @@ -2007,6 +2007,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer case TOK.wcharLiteral: case TOK.dcharLiteral: case TOK.string_: + case TOK.hexadecimalString: case TOK.file: case TOK.fileFullPath: case TOK.line: @@ -2545,7 +2546,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer else if (StorageClass modStc = stc & STC.TYPECTOR) { OutBuffer buf; - AST.stcToBuffer(&buf, modStc); + AST.stcToBuffer(buf, modStc); error(loc, "static constructor cannot be `%s`", buf.peekChars()); } stc &= ~(STC.static_ | STC.TYPECTOR); @@ -2580,7 +2581,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer else if (StorageClass modStc = stc & STC.TYPECTOR) { OutBuffer buf; - AST.stcToBuffer(&buf, modStc); + AST.stcToBuffer(buf, modStc); error(loc, "static destructor cannot be `%s`", buf.peekChars()); } stc &= ~(STC.static_ | STC.TYPECTOR); @@ -2619,7 +2620,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer else if (StorageClass modStc = stc & STC.TYPECTOR) { OutBuffer buf; - AST.stcToBuffer(&buf, modStc); + AST.stcToBuffer(buf, modStc); error(loc, "shared static constructor cannot be `%s`", buf.peekChars()); } stc &= ~(STC.static_ | STC.TYPECTOR); @@ -2653,7 +2654,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer else if (StorageClass modStc = stc & STC.TYPECTOR) { OutBuffer buf; - AST.stcToBuffer(&buf, modStc); + AST.stcToBuffer(buf, modStc); error(loc, "shared static destructor cannot be `%s`", buf.peekChars()); } stc &= ~(STC.static_ | STC.TYPECTOR); @@ -2837,7 +2838,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (varargsStc & ~VarArgsStc) { OutBuffer buf; - AST.stcToBuffer(&buf, varargsStc & ~VarArgsStc); + AST.stcToBuffer(buf, varargsStc & ~VarArgsStc); error("variadic parameter cannot have attributes `%s`", buf.peekChars()); varargsStc &= VarArgsStc; } @@ -2935,11 +2936,12 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer //error("scope cannot be ref or out"); const tv = peekNext(); + Loc loc; if (tpl && token.value == TOK.identifier && (tv == TOK.comma || tv == TOK.rightParenthesis || tv == TOK.dotDotDot)) { Identifier id = Identifier.generateId("__T"); - const loc = token.loc; + loc = token.loc; at = new AST.TypeIdentifier(loc, id); if (!*tpl) *tpl = new AST.TemplateParameters(); @@ -2951,7 +2953,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } else { - at = parseType(&ai); + at = parseType(&ai, null, &loc); } ae = null; if (token.value == TOK.assign) // = defaultArg @@ -2959,7 +2961,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer nextToken(); ae = parseDefaultInitExp(); } - auto param = new AST.Parameter(storageClass | STC.parameter, at, ai, ae, null); + auto param = new AST.Parameter(loc, storageClass | STC.parameter, at, ai, ae, null); if (udas) { auto a = new AST.Dsymbols(); @@ -3083,7 +3085,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer else { OutBuffer buf; - AST.stcToBuffer(&buf, _stc); + AST.stcToBuffer(buf, _stc); error(attributeErrorMessage, buf.peekChars()); } nextToken(); @@ -3284,8 +3286,14 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (token.value != TOK.rightCurly) { /* { */ - error(token.loc, "`}` expected following members in `%s` declaration at %s", - Token.toChars(tok), loc.toChars()); + error(token.loc, "`}` expected following members in `%s` declaration", + Token.toChars(tok)); + if (id) + eSink.errorSupplemental(loc, "%s `%s` starts here", + Token.toChars(tok), id.toChars()); + else + eSink.errorSupplemental(loc, "%s starts here", + Token.toChars(tok)); } nextToken(); } @@ -3481,8 +3489,9 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer * Params: * pident = set to Identifier if there is one, null if not * ptpl = if !null, then set to TemplateParameterList + * pdeclLoc = if !null, then set to location of the declarator */ - AST.Type parseType(Identifier* pident = null, AST.TemplateParameters** ptpl = null) + AST.Type parseType(Identifier* pident = null, AST.TemplateParameters** ptpl = null, Loc* pdeclLoc = null) { /* Take care of the storage class prefixes that * serve as type attributes: @@ -3539,6 +3548,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer AST.Type t; t = parseBasicType(); + if (pdeclLoc) + *pdeclLoc = token.loc; int alt = 0; t = parseDeclarator(t, alt, pident, ptpl); checkCstyleTypeSyntax(typeLoc, t, alt, pident ? *pident : null); @@ -4575,8 +4586,10 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } else if (t.ty == Tfunction) { + /* @@@DEPRECATED_2.115@@@ + * change to error, deprecated in 2.105.1 */ if (storage_class & STC.manifest) - error("function cannot have enum storage class"); + deprecation("function cannot have enum storage class"); AST.Expression constraint = null; //printf("%s funcdecl t = %s, storage_class = x%lx\n", loc.toChars(), t.toChars(), storage_class); @@ -4953,7 +4966,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (remStc) { OutBuffer buf; - AST.stcToBuffer(&buf, remStc); + AST.stcToBuffer(buf, remStc); // @@@DEPRECATED_2.103@@@ // Deprecated in 2020-07, can be made an error in 2.103 eSink.deprecation(token.loc, "storage class `%s` has no effect in type aliases", buf.peekChars()); @@ -5108,7 +5121,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (save == TOK.function_) { OutBuffer buf; - AST.stcToBuffer(&buf, modStc); + AST.stcToBuffer(buf, modStc); error("function literal cannot be `%s`", buf.peekChars()); } else @@ -5126,7 +5139,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer parameterList.parameters = new AST.Parameters(); Identifier id = Identifier.generateId("__T"); AST.Type t = new AST.TypeIdentifier(loc, id); - parameterList.parameters.push(new AST.Parameter(STC.parameter, t, token.ident, null, null)); + parameterList.parameters.push(new AST.Parameter(loc, STC.parameter, t, token.ident, null, null)); tpl = new AST.TemplateParameters(); AST.TemplateParameter tp = new AST.TemplateTypeParameter(loc, id, null, null); @@ -5443,6 +5456,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer { Identifier ai = null; AST.Type at; + Loc aloc; StorageClass storageClass = 0; StorageClass stc = 0; @@ -5524,6 +5538,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer lastai = token.ident; ai = token.ident; at = null; // infer argument type + aloc = token.loc; nextToken(); goto Larg; } @@ -5532,7 +5547,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (!ai) noIdentifierForDeclarator(at); Larg: - auto p = new AST.Parameter(storageClass, at, ai, null, null); + auto p = new AST.Parameter(aloc, storageClass, at, ai, null, null); parameters.push(p); if (token.value == TOK.comma) { @@ -5684,16 +5699,18 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer { Identifier ai = token.ident; AST.Type at = null; // infer parameter type + const aloc = token.loc; nextToken(); check(TOK.assign); - param = new AST.Parameter(storageClass, at, ai, null, null); + param = new AST.Parameter(aloc, storageClass, at, ai, null, null); } else if (isDeclaration(&token, NeedDeclaratorId.must, TOK.assign, null)) { Identifier ai; + const aloc = token.loc; AST.Type at = parseType(&ai); check(TOK.assign); - param = new AST.Parameter(storageClass, at, ai, null, null); + param = new AST.Parameter(aloc, storageClass, at, ai, null, null); } else if (storageClass != 0) error("found `%s` while expecting `=` or identifier", n.toChars()); @@ -5789,6 +5806,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer case TOK.true_: case TOK.false_: case TOK.string_: + case TOK.hexadecimalString: case TOK.leftParenthesis: case TOK.cast_: case TOK.mul: @@ -5816,7 +5834,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer AST.Expression exp = parseExpression(); /* https://issues.dlang.org/show_bug.cgi?id=15103 * Improve declaration / initialization syntax error message - * Error: found 'foo' when expecting ';' following statement + * Error: found 'foo' when expecting ';' following expression * becomes Error: found `(` when expecting `;` or `=`, did you mean `Foo foo = 42`? */ if (token.value == TOK.identifier && exp.op == EXP.identifier) @@ -5841,11 +5859,14 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer * otherwise we fall back on the old path (advancing the token). */ if (token.value != TOK.semicolon && peek(&token).value == TOK.semicolon) - error("found `%s` when expecting `;` following statement", token.toChars()); + error("found `%s` when expecting `;` following expression", token.toChars()); else { if (token.value != TOK.semicolon) - error("found `%s` when expecting `;` following statement `%s` on line %s", token.toChars(), exp.toChars(), exp.loc.toChars()); + { + error("found `%s` when expecting `;` following expression", token.toChars()); + eSink.errorSupplemental(exp.loc, "expression: `%s`", exp.toChars()); + } nextToken(); } } @@ -6580,7 +6601,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } case TOK.asm_: - s = parseAsm(); + s = parseAsm(false); break; case TOK.import_: @@ -6951,10 +6972,12 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer * AsmInstruction ; * AsmInstruction ; AsmInstruction * + * Params: + * endOfLine = true if EOL means end of asm statement * Returns: * inline assembler block as a Statement */ - AST.Statement parseAsm() + AST.Statement parseAsm(bool endOfLine) { // Parse the asm block into a sequence of AsmStatements, // each AsmStatement is one instruction. @@ -6977,6 +7000,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer size_t nestlevel = 0; while (1) { + if (endOfLine) + nextDefineLine(); switch (token.value) { case TOK.identifier: @@ -7011,6 +7036,10 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } break; + case TOK.endOfLine: + nextDefineLine(); + goto case; + case TOK.semicolon: if (nestlevel != 0) error("mismatched number of curly brackets"); @@ -7018,7 +7047,9 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (toklist || label) { // Create AsmStatement from list of tokens we've saved - AST.Statement s = new AST.AsmStatement(token.loc, toklist); + AST.AsmStatement as = new AST.AsmStatement(token.loc, toklist); + as.caseSensitive = !endOfLine; + AST.Statement s = as; toklist = null; ptoklist = &toklist; if (label) @@ -7062,6 +7093,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer break; } nextToken(); + if (token.value == TOK.endOfLine) + nextToken(); auto s = new AST.CompoundAsmStatement(loc, statements, stc); return s; } @@ -7291,6 +7324,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer case TOK.wcharLiteral: case TOK.dcharLiteral: case TOK.string_: + case TOK.hexadecimalString: case TOK.file: case TOK.fileFullPath: case TOK.line: @@ -7562,7 +7596,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } continue; - // Valid tokens that follow a declaration + // Valid tokens that follow the start of a declaration case TOK.rightParenthesis: case TOK.rightBracket: case TOK.assign: @@ -7581,6 +7615,23 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } return false; + // To recognize the shortened function declaration syntax + case TOK.goesTo: + /* + 1. https://issues.dlang.org/show_bug.cgi?id=24088 + + 2. We need to make sure the would-be + declarator has an identifier otherwise function literals + are handled incorrectly. Some special treatment is required + here, it turns out that a lot of code in the compiler relies + on this mess (in the parser), i.e. having isDeclarator be more + precise the parsing of other things go kaboom, so we do it in a + separate case. + */ + if (*haveId) + goto case TOK.do_; + goto default; + case TOK.identifier: if (t.ident == Id._body) { @@ -8148,6 +8199,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer break; case TOK.string_: + case TOK.hexadecimalString: { // cat adjacent strings auto s = token.ustring; @@ -8157,7 +8209,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer { const prev = token; nextToken(); - if (token.value == TOK.string_) + if (token.value == TOK.string_ || token.value == TOK.hexadecimalString) { if (token.postfix) { @@ -9549,7 +9601,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer void usageOfBodyKeyword() { - if (compileEnv.obsolete) + version (none) // disable obsolete warning { eSink.warning(token.loc, "usage of identifer `body` as a keyword is obsolete. Use `do` instead."); } diff --git a/gcc/d/dmd/printast.d b/gcc/d/dmd/printast.d index e43ffad..e1deb2c 100644 --- a/gcc/d/dmd/printast.d +++ b/gcc/d/dmd/printast.d @@ -64,7 +64,7 @@ extern (C++) final class PrintASTVisitor : Visitor import dmd.hdrgen : floatToBuffer; import dmd.common.outbuffer : OutBuffer; OutBuffer buf; - floatToBuffer(e.type, e.value, &buf, false); + floatToBuffer(e.type, e.value, buf, false); printf("Real %s %s\n", buf.peekChars(), e.type ? e.type.toChars() : ""); } diff --git a/gcc/d/dmd/safe.d b/gcc/d/dmd/safe.d index c3fa90d..bd531c0 100644 --- a/gcc/d/dmd/safe.d +++ b/gcc/d/dmd/safe.d @@ -51,7 +51,7 @@ bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg) DotVarExp dve = cast(DotVarExp)e; if (VarDeclaration v = dve.var.isVarDeclaration()) { - if (sc.intypeof || !sc.func || !sc.func.isSafeBypassingInference()) + if (!sc.func) return false; auto ad = v.isMember2(); if (!ad) @@ -65,6 +65,11 @@ bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg) return true; } + // This branch shouldn't be here, but unfortunately calling `ad.determineSize` + // breaks code with circular reference errors. Specifically, test23589.d fails + if (ad.sizeok != Sizeok.done && !sc.func.isSafeBypassingInference()) + return false; + // needed to set v.overlapped and v.overlapUnsafe if (ad.sizeok != Sizeok.done) ad.determineSize(ad.loc); @@ -74,9 +79,23 @@ bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg) { if (v.overlapped) { - if (sc.setUnsafe(!printmsg, e.loc, + if (sc.func.isSafeBypassingInference() && sc.setUnsafe(!printmsg, e.loc, "field `%s.%s` cannot access pointers in `@safe` code that overlap other fields", ad, v)) + { return true; + } + else + { + import dmd.globals : FeatureState; + // @@@DEPRECATED_2.116@@@ + // https://issues.dlang.org/show_bug.cgi?id=20655 + // Inferring `@system` because of union access breaks code, + // so make it a deprecation safety violation as of 2.106 + // To turn into an error, remove `isSafeBypassingInference` check in the + // above if statement and remove the else branch + sc.setUnsafePreview(FeatureState.default_, !printmsg, e.loc, + "field `%s.%s` cannot access pointers in `@safe` code that overlap other fields", ad, v); + } } } diff --git a/gcc/d/dmd/semantic2.d b/gcc/d/dmd/semantic2.d index 53c8714..e2d2e04 100644 --- a/gcc/d/dmd/semantic2.d +++ b/gcc/d/dmd/semantic2.d @@ -275,6 +275,7 @@ private extern(C++) final class Semantic2Visitor : Visitor // https://issues.dlang.org/show_bug.cgi?id=20417 // Don't run CTFE for the temporary variables inside typeof or __traits(compiles) vd._init = vd._init.initializerSemantic(sc, vd.type, sc.intypeof == 1 || sc.flags & SCOPE.compile ? INITnointerpret : INITinterpret); + lowerStaticAAs(vd, sc); vd.inuse--; } if (vd._init && vd.storage_class & STC.manifest) @@ -819,3 +820,55 @@ private void doGNUABITagSemantic(ref Expression e, ref Expression* lastTag) } ale.elements.sort!predicate; } + +/** + * Try lower a variable's static Associative Array to a newaa struct. + * Params: + * vd = Variable to lower + * sc = Scope + */ +void lowerStaticAAs(VarDeclaration vd, Scope* sc) +{ + if (vd.storage_class & STC.manifest) + return; + if (auto ei = vd._init.isExpInitializer()) + { + scope v = new StaticAAVisitor(sc); + v.vd = vd; + ei.exp.accept(v); + } +} + +/// Visit Associative Array literals and lower them to structs for static initialization +private extern(C++) final class StaticAAVisitor : SemanticTimeTransitiveVisitor +{ + alias visit = SemanticTimeTransitiveVisitor.visit; + Scope* sc; + VarDeclaration vd; + + this(Scope* sc) scope @safe + { + this.sc = sc; + } + + override void visit(AssocArrayLiteralExp aaExp) + { + if (!verifyHookExist(aaExp.loc, *sc, Id._aaAsStruct, "initializing static associative arrays", Id.object)) + return; + + Expression hookFunc = new IdentifierExp(aaExp.loc, Id.empty); + hookFunc = new DotIdExp(aaExp.loc, hookFunc, Id.object); + hookFunc = new DotIdExp(aaExp.loc, hookFunc, Id._aaAsStruct); + auto arguments = new Expressions(); + arguments.push(aaExp.syntaxCopy()); + Expression loweredExp = new CallExp(aaExp.loc, hookFunc, arguments); + + sc = sc.startCTFE(); + loweredExp = loweredExp.expressionSemantic(sc); + loweredExp = resolveProperties(sc, loweredExp); + sc = sc.endCTFE(); + loweredExp = loweredExp.ctfeInterpret(); + + aaExp.lowering = loweredExp; + } +} diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d index bff89f8..04f57a4 100644 --- a/gcc/d/dmd/semantic3.d +++ b/gcc/d/dmd/semantic3.d @@ -471,7 +471,7 @@ private extern(C++) final class Semantic3Visitor : Visitor stc |= STC.temp; } Type vtype = fparam.type; - auto v = new VarDeclaration(funcdecl.loc, vtype, id, null); + auto v = new VarDeclaration(fparam.loc, vtype, id, null); //printf("declaring parameter %s of type %s\n", v.toChars(), v.type.toChars()); stc |= STC.parameter; if (f.parameterList.varargs == VarArg.typesafe && i + 1 == nparams) @@ -749,7 +749,7 @@ private extern(C++) final class Semantic3Visitor : Visitor funcdecl.buildEnsureRequire(); // Check for errors related to 'nothrow'. - const blockexit = funcdecl.fbody.blockExit(funcdecl, f.isnothrow); + const blockexit = funcdecl.fbody.blockExit(funcdecl, f.isnothrow ? global.errorSink : null); if (f.isnothrow && blockexit & BE.throw_) error(funcdecl.loc, "%s `%s` may throw but is marked as `nothrow`", funcdecl.kind(), funcdecl.toPrettyChars()); @@ -993,7 +993,7 @@ private extern(C++) final class Semantic3Visitor : Visitor freq = freq.statementSemantic(sc2); // @@@DEPRECATED_2.111@@@ - pass `isnothrow` instead of `false` to print a more detailed error msg` - const blockExit = freq.blockExit(funcdecl, false); + const blockExit = freq.blockExit(funcdecl, null); if (blockExit & BE.throw_) { if (isnothrow) @@ -1040,7 +1040,7 @@ private extern(C++) final class Semantic3Visitor : Visitor fens = fens.statementSemantic(sc2); // @@@DEPRECATED_2.111@@@ - pass `isnothrow` instead of `false` to print a more detailed error msg` - const blockExit = fens.blockExit(funcdecl, false); + const blockExit = fens.blockExit(funcdecl, null); if (blockExit & BE.throw_) { if (isnothrow) @@ -1177,7 +1177,7 @@ private extern(C++) final class Semantic3Visitor : Visitor s = s.statementSemantic(sc2); - const blockexit = s.blockExit(funcdecl, isnothrow); + const blockexit = s.blockExit(funcdecl, isnothrow ? global.errorSink : null); if (blockexit & BE.throw_) { funcdecl.hasNoEH = false; @@ -1187,7 +1187,7 @@ private extern(C++) final class Semantic3Visitor : Visitor f.isnothrow = false; } - if (sbody.blockExit(funcdecl, f.isnothrow) == BE.fallthru) + if (sbody.blockExit(funcdecl, f.isnothrow ? global.errorSink : null) == BE.fallthru) sbody = new CompoundStatement(Loc.initial, sbody, s); else sbody = new TryFinallyStatement(Loc.initial, sbody, s); @@ -1453,7 +1453,7 @@ private extern(C++) final class Semantic3Visitor : Visitor { // storage_class is apparently not set for dtor & ctor OutBuffer ob; - stcToBuffer(&ob, + stcToBuffer(ob, (ngErr ? STC.nogc : 0) | (puErr ? STC.pure_ : 0) | (saErr ? STC.system : 0) diff --git a/gcc/d/dmd/statement.d b/gcc/d/dmd/statement.d index 607dd51..58550fe 100644 --- a/gcc/d/dmd/statement.d +++ b/gcc/d/dmd/statement.d @@ -16,20 +16,14 @@ module dmd.statement; import core.stdc.stdarg; import core.stdc.stdio; -import dmd.aggregate; import dmd.arraytypes; import dmd.astenums; import dmd.ast_node; +import dmd.errors; import dmd.gluelayer; import dmd.cond; -import dmd.dclass; import dmd.declaration; -import dmd.denum; -import dmd.dimport; -import dmd.dscope; import dmd.dsymbol; -import dmd.dtemplate; -import dmd.errors; import dmd.expression; import dmd.func; import dmd.globals; @@ -37,40 +31,14 @@ import dmd.hdrgen; import dmd.id; import dmd.identifier; import dmd.location; -import dmd.dinterpret; import dmd.mtype; import dmd.common.outbuffer; import dmd.root.rootobject; import dmd.sapply; -import dmd.sideeffect; import dmd.staticassert; import dmd.tokens; import dmd.visitor; -/** - * Returns: - * `TypeIdentifier` corresponding to `object.Throwable` - */ -TypeIdentifier getThrowable() -{ - auto tid = new TypeIdentifier(Loc.initial, Id.empty); - tid.addIdent(Id.object); - tid.addIdent(Id.Throwable); - return tid; -} - -/** - * Returns: - * TypeIdentifier corresponding to `object.Exception` - */ -TypeIdentifier getException() -{ - auto tid = new TypeIdentifier(Loc.initial, Id.empty); - tid.addIdent(Id.object); - tid.addIdent(Id.Exception); - return tid; -} - /*********************************************************** * Specification: https://dlang.org/spec/statement.html */ @@ -118,64 +86,11 @@ extern (C++) abstract class Statement : ASTNode { HdrGenState hgs; OutBuffer buf; - .toCBuffer(this, &buf, &hgs); + toCBuffer(this, buf, hgs); buf.writeByte(0); return buf.extractSlice().ptr; } - static if (__VERSION__ < 2092) - { - final void error(const(char)* format, ...) - { - va_list ap; - va_start(ap, format); - .verrorReport(loc, format, ap, ErrorKind.error); - va_end(ap); - } - - final void warning(const(char)* format, ...) - { - va_list ap; - va_start(ap, format); - .verrorReport(loc, format, ap, ErrorKind.warning); - va_end(ap); - } - - final void deprecation(const(char)* format, ...) - { - va_list ap; - va_start(ap, format); - .verrorReport(loc, format, ap, ErrorKind.deprecation); - va_end(ap); - } - } - else - { - pragma(printf) final void error(const(char)* format, ...) - { - va_list ap; - va_start(ap, format); - .verrorReport(loc, format, ap, ErrorKind.error); - va_end(ap); - } - - pragma(printf) final void warning(const(char)* format, ...) - { - va_list ap; - va_start(ap, format); - .verrorReport(loc, format, ap, ErrorKind.warning); - va_end(ap); - } - - pragma(printf) final void deprecation(const(char)* format, ...) - { - va_list ap; - va_start(ap, format); - .verrorReport(loc, format, ap, ErrorKind.deprecation); - va_end(ap); - } - } - Statement getRelatedLabeled() { return this; @@ -1252,9 +1167,10 @@ extern (C++) final class SwitchStatement : Statement if (v.isDataseg() || (v.storage_class & (STC.manifest | STC.temp) && vd.ident != Id.withSym) || v._init.isVoidInitializer()) continue; if (vd.ident == Id.withSym) - error("`switch` skips declaration of `with` temporary at %s", v.loc.toChars()); + error(loc, "`switch` skips declaration of `with` temporary"); else - error("`switch` skips declaration of variable `%s` at %s", v.toPrettyChars(), v.loc.toChars()); + error(loc, "`switch` skips declaration of variable `%s`", v.toPrettyChars()); + errorSupplemental(v.loc, "declared here"); return true; } return false; @@ -1813,22 +1729,22 @@ extern (C++) final class GotoStatement : Statement else { if (label.statement.os) - error("cannot `goto` in to `%s` block", Token.toChars(label.statement.os.tok)); + error(loc, "cannot `goto` in to `%s` block", Token.toChars(label.statement.os.tok)); else - error("cannot `goto` out of `%s` block", Token.toChars(os.tok)); + error(loc, "cannot `goto` out of `%s` block", Token.toChars(os.tok)); return true; } } if (label.statement.tf != tf) { - error("cannot `goto` in or out of `finally` block"); + error(loc, "cannot `goto` in or out of `finally` block"); return true; } if (label.statement.inCtfeBlock && !inCtfeBlock) { - error("cannot `goto` into `if (__ctfe)` block"); + error(loc, "cannot `goto` into `if (__ctfe)` block"); return true; } @@ -1837,7 +1753,7 @@ extern (C++) final class GotoStatement : Statement { if (!stb) { - error("cannot `goto` into `try` block"); + error(loc, "cannot `goto` into `try` block"); return true; } if (auto stf = stb.isTryFinallyStatement()) @@ -1863,17 +1779,15 @@ extern (C++) final class GotoStatement : Statement { // Lifetime ends at end of expression, so no issue with skipping the statement } - else if (vd.ident == Id.withSym) - { - error("`goto` skips declaration of `with` temporary at %s", vd.loc.toChars()); - return true; - } else { - error("`goto` skips declaration of variable `%s` at %s", vd.toPrettyChars(), vd.loc.toChars()); + if (vd.ident == Id.withSym) + error(loc, "`goto` skips declaration of `with` temporary"); + else + error(loc, "`goto` skips declaration of variable `%s`", vd.toPrettyChars()); + errorSupplemental(vd.loc, "declared here"); return true; } - return false; } @@ -1959,6 +1873,7 @@ extern (C++) final class LabelDsymbol : Dsymbol extern (C++) class AsmStatement : Statement { Token* tokens; + bool caseSensitive; // for register names extern (D) this(const ref Loc loc, Token* tokens) @safe { diff --git a/gcc/d/dmd/statement.h b/gcc/d/dmd/statement.h index eb4849d..dd8b9f2 100644 --- a/gcc/d/dmd/statement.h +++ b/gcc/d/dmd/statement.h @@ -116,7 +116,7 @@ public: const char *toChars() const override final; void error(const char *format, ...); - void warning(const char *format, ...); + void warning(unsigned flag, const char *format, ...); void deprecation(const char *format, ...); virtual Statement *getRelatedLabeled() { return this; } virtual bool hasBreak() const; @@ -712,6 +712,7 @@ class AsmStatement : public Statement { public: Token *tokens; + bool caseSensitive; // for register names AsmStatement *syntaxCopy() override; void accept(Visitor *v) override { v->visit(this); } diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d index 178cef5..304cb86 100644 --- a/gcc/d/dmd/statementsem.d +++ b/gcc/d/dmd/statementsem.d @@ -38,6 +38,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; @@ -349,7 +350,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) Identifier id = Identifier.generateId("__o"); Statement handler = new PeelStatement(sexception); - if (sexception.blockExit(sc.func, false) & BE.fallthru) + if (sexception.blockExit(sc.func, null) & BE.fallthru) { auto ts = new ThrowStatement(Loc.initial, new IdentifierExp(Loc.initial, id)); ts.internalThrow = true; @@ -704,7 +705,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) { if (!p.type) { - fs.error("cannot infer type for `foreach` variable `%s`, perhaps set it explicitly", p.ident.toChars()); + error(fs.loc, "cannot infer type for `foreach` variable `%s`, perhaps set it explicitly", p.ident.toChars()); p.type = Type.terror; result = true; } @@ -753,7 +754,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) { assert(oaggr.type); - fs.error("invalid `%s` aggregate `%s` of type `%s`", + error(fs.loc, "invalid `%s` aggregate `%s` of type `%s`", Token.toChars(fs.op), oaggr.toChars(), oaggr.type.toPrettyChars()); if (auto ad = isAggregate(fs.aggr.type)) @@ -815,11 +816,11 @@ Statement statementSemanticVisit(Statement s, Scope* sc) if (foundMismatch && dim != foreachParamCount) { const(char)* plural = foreachParamCount > 1 ? "s" : ""; - fs.error("cannot infer argument types, expected %llu argument%s, not %llu", + error(fs.loc, "cannot infer argument types, expected %llu argument%s, not %llu", cast(ulong) foreachParamCount, plural, cast(ulong) dim); } else - fs.error("cannot uniquely infer `foreach` argument types"); + error(fs.loc, "cannot uniquely infer `foreach` argument types"); return setError(); } @@ -845,11 +846,11 @@ Statement statementSemanticVisit(Statement s, Scope* sc) { if (p.storageClass & STC.manifest) { - fs.error("cannot declare `enum` loop variables for non-unrolled foreach"); + error(fs.loc, "cannot declare `enum` loop variables for non-unrolled foreach"); } if (p.storageClass & STC.alias_) { - fs.error("cannot declare `alias` loop variables for non-unrolled foreach"); + error(fs.loc, "cannot declare `alias` loop variables for non-unrolled foreach"); } } @@ -861,7 +862,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) void rangeError() { - fs.error("cannot infer argument types"); + error(fs.loc, "cannot infer argument types"); return retError(); } @@ -959,7 +960,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) if (dim < 1 || dim > 2) { - fs.error("only one or two arguments for array `foreach`"); + error(fs.loc, "only one or two arguments for array `foreach`"); return retError(); } @@ -978,7 +979,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) Type tindex = (*fs.parameters)[0].type; if (!tindex.isintegral()) { - fs.error("foreach: key cannot be of non-integral type `%s`", tindex.toChars()); + error(fs.loc, "foreach: key cannot be of non-integral type `%s`", tindex.toChars()); return retError(); } /* What cases to deprecate implicit conversions for: @@ -990,7 +991,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) (tn.ty != tv.ty && tn.ty.isSomeChar && tv.ty.isSomeChar)) && !Type.tsize_t.implicitConvTo(tindex)) { - fs.deprecation("foreach: loop index implicitly converted from `size_t` to `%s`", + deprecation(fs.loc, "foreach: loop index implicitly converted from `size_t` to `%s`", tindex.toChars()); } } @@ -1007,7 +1008,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) { if (p.storageClass & STC.ref_) { - fs.error("`foreach`: value of UTF conversion cannot be `ref`"); + error(fs.loc, "`foreach`: value of UTF conversion cannot be `ref`"); return retError(); } if (dim == 2) @@ -1015,7 +1016,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) p = (*fs.parameters)[0]; if (p.storageClass & STC.ref_) { - fs.error("`foreach`: key cannot be `ref`"); + error(fs.loc, "`foreach`: key cannot be `ref`"); return retError(); } } @@ -1036,7 +1037,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) { if (fs.key.type.constConv(p.type) == MATCH.nomatch) { - fs.error("key type mismatch, `%s` to `ref %s`", + error(fs.loc, "key type mismatch, `%s` to `ref %s`", fs.key.type.toChars(), p.type.toChars()); return retError(); } @@ -1048,7 +1049,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) dimrange.imax = SignExtendedNumber(dimrange.imax.value-1); if (!IntRange.fromType(fs.key.type).contains(dimrange)) { - fs.error("index type `%s` cannot cover index range 0..%llu", + error(fs.loc, "index type `%s` cannot cover index range 0..%llu", p.type.toChars(), ta.dim.toInteger()); return retError(); } @@ -1071,7 +1072,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) Type t = tab.nextOf(); if (t.constConv(p.type) == MATCH.nomatch) { - fs.error("argument type mismatch, `%s` to `ref %s`", + error(fs.loc, "argument type mismatch, `%s` to `ref %s`", t.toChars(), p.type.toChars()); return retError(); } @@ -1197,13 +1198,13 @@ Statement statementSemanticVisit(Statement s, Scope* sc) } case Taarray: if (fs.op == TOK.foreach_reverse_) - fs.warning("cannot use `foreach_reverse` with an associative array"); + warning(fs.loc, "cannot use `foreach_reverse` with an associative array"); if (checkForArgTypes(fs)) return retError(); if (dim < 1 || dim > 2) { - fs.error("only one or two arguments for associative array `foreach`"); + error(fs.loc, "only one or two arguments for associative array `foreach`"); return retError(); } return retStmt(apply()); @@ -1308,7 +1309,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) } if (tfront.ty == Tvoid) { - fs.error("`%s.front` is `void` and has no value", oaggr.toChars()); + error(fs.loc, "`%s.front` is `void` and has no value", oaggr.toChars()); return retError(); } @@ -1348,7 +1349,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) if (exps.length != dim) { const(char)* plural = exps.length > 1 ? "s" : ""; - fs.error("cannot infer argument types, expected %llu argument%s, not %llu", + error(fs.loc, "cannot infer argument types, expected %llu argument%s, not %llu", cast(ulong) exps.length, plural, cast(ulong) dim); return retError(); } @@ -1371,7 +1372,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) p.type = p.type.addStorageClass(sc).typeSemantic(loc, sc2); if (!exp.implicitConvTo(p.type)) { - fs.error("cannot implicilty convert range element of type `%s` to variable `%s` of type `%s`", + error(fs.loc, "cannot implicilty convert range element of type `%s` to variable `%s` of type `%s`", exp.type.toChars(), p.toChars(), p.type.toChars()); return retError(); } @@ -1399,12 +1400,12 @@ Statement statementSemanticVisit(Statement s, Scope* sc) } case Tdelegate: if (fs.op == TOK.foreach_reverse_) - fs.deprecation("cannot use `foreach_reverse` with a delegate"); + deprecation(fs.loc, "cannot use `foreach_reverse` with a delegate"); return retStmt(apply()); case Terror: return retError(); default: - fs.error("`foreach`: `%s` is not an aggregate type", fs.aggr.type.toChars()); + error(fs.loc, "`foreach`: `%s` is not an aggregate type", fs.aggr.type.toChars()); return retError(); } } @@ -1421,7 +1422,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) fs.lwr = fs.lwr.optimize(WANTvalue); if (!fs.lwr.type) { - fs.error("invalid range lower bound `%s`", fs.lwr.toChars()); + error(fs.loc, "invalid range lower bound `%s`", fs.lwr.toChars()); return setError(); } @@ -1430,7 +1431,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) fs.upr = fs.upr.optimize(WANTvalue); if (!fs.upr.type) { - fs.error("invalid range upper bound `%s`", fs.upr.toChars()); + error(fs.loc, "invalid range upper bound `%s`", fs.upr.toChars()); return setError(); } @@ -1584,7 +1585,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) { if (fs.key.type.constConv(fs.prm.type) == MATCH.nomatch) { - fs.error("argument type mismatch, `%s` to `ref %s`", fs.key.type.toChars(), fs.prm.type.toChars()); + error(fs.loc, "argument type mismatch, `%s` to `ref %s`", fs.key.type.toChars(), fs.prm.type.toChars()); return setError(); } } @@ -1762,14 +1763,14 @@ Statement statementSemanticVisit(Statement s, Scope* sc) { /* Should this be allowed? */ - ps.error("`pragma(lib)` not allowed as statement"); + error(ps.loc, "`pragma(lib)` not allowed as statement"); return setError(); } else { if (!ps.args || ps.args.length != 1) { - ps.error("`string` expected for library name"); + error(ps.loc, "`string` expected for library name"); return setError(); } else @@ -1789,7 +1790,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) { /* Should this be allowed? */ - ps.error("`pragma(linkerDirective)` not allowed as statement"); + error(ps.loc, "`pragma(linkerDirective)` not allowed as statement"); return setError(); } else if (ps.ident == Id.startaddress) @@ -1805,13 +1806,32 @@ Statement statementSemanticVisit(Statement s, Scope* sc) } else { - ps.error("`pragma(inline)` is not inside a function"); + error(ps.loc, "`pragma(inline)` is not inside a function"); return setError(); } } + else if (ps.ident == Id.mangle) + { + auto es = ps._body ? ps._body.isExpStatement() : null; + auto de = es ? es.exp.isDeclarationExp() : null; + if (!de) + { + error(ps.loc, "`pragma(mangle)` must be attached to a declaration"); + return setError(); + } + const se = ps.args && (*ps.args).length == 1 ? semanticString(sc, (*ps.args)[0], "pragma mangle argument") : null; + if (!se) + { + error(ps.loc, "`pragma(mangle)` takes a single argument that must be a string literal"); + return setError(); + } + const cnt = setMangleOverride(de.declaration, cast(const(char)[])se.peekData()); + if (cnt != 1) + assert(0); + } else if (!global.params.ignoreUnsupportedPragmas) { - ps.error("unrecognized `pragma(%s)`", ps.ident.toChars()); + error(ps.loc, "unrecognized `pragma(%s)`", ps.ident.toChars()); return setError(); } @@ -1819,7 +1839,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) { if (ps.ident == Id.msg || ps.ident == Id.startaddress) { - ps.error("`pragma(%s)` is missing a terminating `;`", ps.ident.toChars()); + error(ps.loc, "`pragma(%s)` is missing a terminating `;`", ps.ident.toChars()); return setError(); } ps._body = ps._body.statementSemantic(sc); @@ -1885,7 +1905,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) if (!ss.condition.isErrorExp()) { - ss.error("`%s` must be of integral or string type, it is a `%s`", + error(ss.loc, "`%s` must be of integral or string type, it is a `%s`", ss.condition.toChars(), ss.condition.type.toChars()); conditionError = true; break; @@ -1924,7 +1944,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) { if (!gcs.exp) { - gcs.error("no `case` statement following `goto case;`"); + error(gcs.loc, "no `case` statement following `goto case;`"); sc.pop(); return setError(); } @@ -1942,7 +1962,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) } } } - gcs.error("`case %s` not found", gcs.exp.toChars()); + error(gcs.loc, "`case %s` not found", gcs.exp.toChars()); sc.pop(); return setError(); } @@ -1975,7 +1995,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) continue Lmembers; } if (missingMembers == 0) - ss.error("missing cases for `enum` members in `final switch`:"); + error(ss.loc, "missing cases for `enum` members in `final switch`:"); if (missingMembers < maxShown) errorSupplemental(ss.loc, "`%s`", em.toChars()); @@ -2000,7 +2020,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) ss.hasNoDefault = 1; if (!ss.isFinal && (!ss._body || !ss._body.isErrorStatement()) && !(sc.flags & SCOPE.Cfile)) - ss.error("`switch` statement without a `default`; use `final switch` or add `default: assert(0);` or add `default: break;`"); + error(ss.loc, "`switch` statement without a `default`; use `final switch` or add `default: assert(0);` or add `default: break;`"); // Generate runtime error if the default is hit auto a = new Statements(); @@ -2051,7 +2071,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) a.reserve(2); sc.sw.sdefault = new DefaultStatement(ss.loc, s); a.push(ss._body); - if (ss._body.blockExit(sc.func, false) & BE.fallthru) + if (ss._body.blockExit(sc.func, null) & BE.fallthru) a.push(new BreakStatement(Loc.initial, null)); a.push(sc.sw.sdefault); cs = new CompoundStatement(ss.loc, a); @@ -2193,12 +2213,12 @@ Statement statementSemanticVisit(Statement s, Scope* sc) */ if (!v.isConst() && !v.isImmutable()) { - cs.error("`case` variables have to be `const` or `immutable`"); + error(cs.loc, "`case` variables have to be `const` or `immutable`"); } if (sw.isFinal) { - cs.error("`case` variables not allowed in `final switch` statements"); + error(cs.loc, "`case` variables not allowed in `final switch` statements"); errors = true; } @@ -2213,7 +2233,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) if (!scx.search(cs.exp.loc, v.ident, null)) { - cs.error("`case` variable `%s` declared at %s cannot be declared in `switch` body", + error(cs.loc, "`case` variable `%s` declared at %s cannot be declared in `switch` body", v.toChars(), v.loc.toChars()); errors = true; } @@ -2229,7 +2249,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) cs.exp = se; else if (!cs.exp.isIntegerExp() && !cs.exp.isErrorExp()) { - cs.error("`case` expression must be a compile-time `string` or an integral constant, not `%s`", cs.exp.toChars()); + error(cs.loc, "`case` expression must be a compile-time `string` or an integral constant, not `%s`", cs.exp.toChars()); errors = true; } @@ -2242,7 +2262,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) if (cs2.exp.equals(cs.exp)) { // https://issues.dlang.org/show_bug.cgi?id=15909 - cs.error("duplicate `case %s` in `switch` statement", initialExp.toChars()); + error(cs.loc, "duplicate `case %s` in `switch` statement", initialExp.toChars()); errors = true; break; } @@ -2265,18 +2285,18 @@ Statement statementSemanticVisit(Statement s, Scope* sc) if (sc.sw.tf != sc.tf) { - cs.error("`switch` and `case` are in different `finally` blocks"); + error(cs.loc, "`switch` and `case` are in different `finally` blocks"); errors = true; } if (sc.sw.tryBody != sc.tryBody) { - cs.error("case cannot be in different `try` block level from `switch`"); + error(cs.loc, "case cannot be in different `try` block level from `switch`"); errors = true; } } else { - cs.error("`case` not in `switch` statement"); + error(cs.loc, "`case` not in `switch` statement"); errors = true; } @@ -2299,7 +2319,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) SwitchStatement sw = sc.sw; if (sw is null) { - crs.error("case range not in `switch` statement"); + error(crs.loc, "case range not in `switch` statement"); return setError(); } @@ -2307,7 +2327,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) bool errors = false; if (sw.isFinal) { - crs.error("case ranges not allowed in `final switch`"); + error(crs.loc, "case ranges not allowed in `final switch`"); errors = true; } @@ -2336,14 +2356,14 @@ Statement statementSemanticVisit(Statement s, Scope* sc) uinteger_t lval = crs.last.toInteger(); if ((crs.first.type.isunsigned() && fval > lval) || (!crs.first.type.isunsigned() && cast(sinteger_t)fval > cast(sinteger_t)lval)) { - crs.error("first `case %s` is greater than last `case %s`", crs.first.toChars(), crs.last.toChars()); + error(crs.loc, "first `case %s` is greater than last `case %s`", crs.first.toChars(), crs.last.toChars()); errors = true; lval = fval; } if (lval - fval > 256) { - crs.error("had %llu cases which is more than 257 cases in case range", 1 + lval - fval); + error(crs.loc, "had %llu cases which is more than 257 cases in case range", 1 + lval - fval); errors = true; lval = fval + 256; } @@ -2385,30 +2405,30 @@ Statement statementSemanticVisit(Statement s, Scope* sc) { if (sc.sw.sdefault) { - ds.error("`switch` statement already has a default"); + error(ds.loc, "`switch` statement already has a default"); errors = true; } sc.sw.sdefault = ds; if (sc.sw.tf != sc.tf) { - ds.error("`switch` and `default` are in different `finally` blocks"); + error(ds.loc, "`switch` and `default` are in different `finally` blocks"); errors = true; } if (sc.sw.tryBody != sc.tryBody) { - ds.error("default cannot be in different `try` block level from `switch`"); + error(ds.loc, "default cannot be in different `try` block level from `switch`"); errors = true; } if (sc.sw.isFinal) { - ds.error("`default` statement not allowed in `final switch` statement"); + error(ds.loc, "`default` statement not allowed in `final switch` statement"); errors = true; } } else { - ds.error("`default` not in `switch` statement"); + error(ds.loc, "`default` not in `switch` statement"); errors = true; } @@ -2429,12 +2449,12 @@ Statement statementSemanticVisit(Statement s, Scope* sc) gds.sw = sc.sw; if (!gds.sw) { - gds.error("`goto default` not in `switch` statement"); + error(gds.loc, "`goto default` not in `switch` statement"); return setError(); } if (gds.sw.isFinal) { - gds.error("`goto default` not allowed in `final switch` statement"); + error(gds.loc, "`goto default` not allowed in `final switch` statement"); return setError(); } result = gds; @@ -2447,7 +2467,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) if (!sc.sw) { - gcs.error("`goto case` not in `switch` statement"); + error(gcs.loc, "`goto case` not in `switch` statement"); return setError(); } @@ -2512,7 +2532,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) bool errors = false; if (sc.flags & SCOPE.contract) { - rs.error("`return` statements cannot be in contracts"); + error(rs.loc, "`return` statements cannot be in contracts"); errors = true; } if (sc.os) @@ -2521,18 +2541,18 @@ Statement statementSemanticVisit(Statement s, Scope* sc) // Deprecated in 2.100, transform into an error in 2.112 if (sc.os.tok == TOK.onScopeFailure) { - rs.deprecation("`return` statements cannot be in `scope(failure)` bodies."); + deprecation(rs.loc, "`return` statements cannot be in `scope(failure)` bodies."); deprecationSupplemental(rs.loc, "Use try-catch blocks for this purpose"); } else { - rs.error("`return` statements cannot be in `%s` bodies", Token.toChars(sc.os.tok)); + error(rs.loc, "`return` statements cannot be in `%s` bodies", Token.toChars(sc.os.tok)); errors = true; } } if (sc.tf) { - rs.error("`return` statements cannot be in `finally` bodies"); + error(rs.loc, "`return` statements cannot be in `finally` bodies"); errors = true; } @@ -2540,7 +2560,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) { if (rs.exp) { - rs.error("cannot return expression from constructor"); + error(rs.loc, "cannot return expression from constructor"); errors = true; } @@ -2595,7 +2615,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) { if (!convToVoid) { - rs.error("cannot return non-void from `void` function"); + error(rs.loc, "cannot return non-void from `void` function"); errors = true; rs.exp = new CastExp(rs.loc, rs.exp, Type.tvoid); rs.exp = rs.exp.expressionSemantic(sc); @@ -2655,7 +2675,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) } else if (!rs.exp.isErrorExp()) { - rs.error("expected return type of `%s`, not `%s`:", + error(rs.loc, "expected return type of `%s`, not `%s`:", tret.toChars(), rs.exp.type.toChars()); errorSupplemental((fd.returns) ? (*fd.returns)[0].loc : fd.loc, @@ -2697,7 +2717,12 @@ Statement statementSemanticVisit(Statement s, Scope* sc) { /* May return by ref */ - if (checkReturnEscapeRef(sc, rs.exp, true)) + Scope* sc2 = sc.push(); + sc2.eSink = global.errorSinkNull; + bool err = checkReturnEscapeRef(sc2, rs.exp, true); + sc2.pop(); + + if (err) turnOffRef(() { checkReturnEscapeRef(sc, rs.exp, false); }); else if (!rs.exp.type.constConv(tf.next)) turnOffRef( @@ -2736,7 +2761,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) { if (tf.next.ty != Terror) { - rs.error("mismatched function return type inference of `void` and `%s`", tf.next.toChars()); + error(rs.loc, "mismatched function return type inference of `void` and `%s`", tf.next.toChars()); } errors = true; tf.next = Type.terror; @@ -2755,15 +2780,15 @@ Statement statementSemanticVisit(Statement s, Scope* sc) if (tbret.ty != Terror) { if (e0) - rs.error("expected return type of `%s`, not `%s`", tret.toChars(), resType.toChars()); + error(rs.loc, "expected return type of `%s`, not `%s`", tret.toChars(), resType.toChars()); else if (tbret.isTypeNoreturn()) { - rs.error("cannot return from `noreturn` function"); + error(rs.loc, "cannot return from `noreturn` function"); .errorSupplemental(rs.loc, "Consider adding an endless loop, `assert(0)`, or another `noreturn` expression"); } else - rs.error("`return` expression expected"); + error(rs.loc, "`return` expression expected"); } errors = true; } @@ -2777,7 +2802,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) // If any branches have called a ctor, but this branch hasn't, it's an error if (sc.ctorflow.callSuper & CSX.any_ctor && !(sc.ctorflow.callSuper & (CSX.this_ctor | CSX.super_ctor))) { - rs.error("`return` without calling constructor"); + error(rs.loc, "`return` without calling constructor"); errors = true; } @@ -2790,7 +2815,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) bool mustInit = (v.storage_class & STC.nodefaultctor || v.type.needsNested()); if (mustInit && !(sc.ctorflow.fieldinit[i].csx & CSX.this_ctor)) { - rs.error("an earlier `return` statement skips field `%s` initialization", v.toChars()); + error(rs.loc, "an earlier `return` statement skips field `%s` initialization", v.toChars()); errors = true; } } @@ -2904,9 +2929,9 @@ Statement statementSemanticVisit(Statement s, Scope* sc) { Statement s = ls.statement; if (!s || !s.hasBreak()) - bs.error("label `%s` has no `break`", bs.ident.toChars()); + error(bs.loc, "label `%s` has no `break`", bs.ident.toChars()); else if (ls.tf != sc.tf) - bs.error("cannot break out of `finally` block"); + error(bs.loc, "cannot break out of `finally` block"); else { ls.breaks = true; @@ -2916,14 +2941,14 @@ Statement statementSemanticVisit(Statement s, Scope* sc) return setError(); } } - bs.error("enclosing label `%s` for `break` not found", bs.ident.toChars()); + error(bs.loc, "enclosing label `%s` for `break` not found", bs.ident.toChars()); return setError(); } else if (!sc.sbreak) { if (sc.os && sc.os.tok != TOK.onScopeFailure) { - bs.error("`break` is not allowed inside `%s` bodies", Token.toChars(sc.os.tok)); + error(bs.loc, "`break` is not allowed inside `%s` bodies", Token.toChars(sc.os.tok)); } else if (sc.fes) { @@ -2932,12 +2957,12 @@ Statement statementSemanticVisit(Statement s, Scope* sc) return; } else - bs.error("`break` is not inside a loop or `switch`"); + error(bs.loc, "`break` is not inside a loop or `switch`"); return setError(); } else if (sc.sbreak.isForwardingStatement()) { - bs.error("must use labeled `break` within `static foreach`"); + error(bs.loc, "must use labeled `break` within `static foreach`"); } result = bs; } @@ -2992,9 +3017,9 @@ Statement statementSemanticVisit(Statement s, Scope* sc) { Statement s = ls.statement; if (!s || !s.hasContinue()) - cs.error("label `%s` has no `continue`", cs.ident.toChars()); + error(cs.loc, "label `%s` has no `continue`", cs.ident.toChars()); else if (ls.tf != sc.tf) - cs.error("cannot continue out of `finally` block"); + error(cs.loc, "cannot continue out of `finally` block"); else { result = cs; @@ -3003,14 +3028,14 @@ Statement statementSemanticVisit(Statement s, Scope* sc) return setError(); } } - cs.error("enclosing label `%s` for `continue` not found", cs.ident.toChars()); + error(cs.loc, "enclosing label `%s` for `continue` not found", cs.ident.toChars()); return setError(); } else if (!sc.scontinue) { if (sc.os && sc.os.tok != TOK.onScopeFailure) { - cs.error("`continue` is not allowed inside `%s` bodies", Token.toChars(sc.os.tok)); + error(cs.loc, "`continue` is not allowed inside `%s` bodies", Token.toChars(sc.os.tok)); } else if (sc.fes) { @@ -3019,12 +3044,12 @@ Statement statementSemanticVisit(Statement s, Scope* sc) return; } else - cs.error("`continue` is not inside a loop"); + error(cs.loc, "`continue` is not inside a loop"); return setError(); } else if (sc.scontinue.isForwardingStatement()) { - cs.error("must use labeled `continue` within `static foreach`"); + error(cs.loc, "must use labeled `continue` within `static foreach`"); } result = cs; } @@ -3050,7 +3075,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) ClassDeclaration cd = ss.exp.type.isClassHandle(); if (!cd) { - ss.error("can only `synchronize` on class objects, not `%s`", ss.exp.type.toChars()); + error(ss.loc, "can only `synchronize` on class objects, not `%s`", ss.exp.type.toChars()); return setError(); } else if (cd.isInterfaceDeclaration()) @@ -3060,7 +3085,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) */ if (!ClassDeclaration.object) { - ss.error("missing or corrupt object.d"); + error(ss.loc, "missing or corrupt object.d"); fatal(); } @@ -3085,7 +3110,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) cs.push(new ExpStatement(ss.loc, tmp)); auto args = new Parameters(); - args.push(new Parameter(0, ClassDeclaration.object.type, null, null, null)); + args.push(new Parameter(Loc.initial, 0, ClassDeclaration.object.type, null, null, null)); FuncDeclaration fdenter = FuncDeclaration.genCfunc(args, Type.tvoid, Id.monitorenter); Expression e = new CallExp(ss.loc, fdenter, new VarExp(ss.loc, tmp)); @@ -3127,7 +3152,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) cs.push(new ExpStatement(ss.loc, v)); auto enterArgs = new Parameters(); - enterArgs.push(new Parameter(0, t.pointerTo(), null, null, null)); + enterArgs.push(new Parameter(Loc.initial, 0, t.pointerTo(), null, null, null)); FuncDeclaration fdenter = FuncDeclaration.genCfunc(enterArgs, Type.tvoid, Id.criticalenter, STC.nothrow_); Expression e = new AddrExp(ss.loc, tmpExp); @@ -3137,7 +3162,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) cs.push(new ExpStatement(ss.loc, e)); auto exitArgs = new Parameters(); - exitArgs.push(new Parameter(0, t, null, null, null)); + exitArgs.push(new Parameter(Loc.initial, 0, t, null, null, null)); FuncDeclaration fdexit = FuncDeclaration.genCfunc(exitArgs, Type.tvoid, Id.criticalexit, STC.nothrow_); e = new CallExp(ss.loc, fdexit, tmpExp); @@ -3177,7 +3202,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) Dsymbol s = (cast(TypeExp)ws.exp).type.toDsymbol(sc); if (!s || !s.isScopeDsymbol()) { - ws.error("`with` type `%s` has no members", ws.exp.toChars()); + error(ws.loc, "`with` type `%s` has no members", ws.exp.toChars()); return setError(); } sym = new WithScopeSymbol(ws); @@ -3252,7 +3277,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) } else { - ws.error("`with` expression types must be enums or aggregates or pointers to them, not `%s`", olde.type.toChars()); + error(ws.loc, "`with` expression types must be enums or aggregates or pointers to them, not `%s`", olde.type.toChars()); return setError(); } } @@ -3281,13 +3306,13 @@ Statement statementSemanticVisit(Statement s, Scope* sc) if (!global.params.useExceptions) { - tcs.error("cannot use try-catch statements with -betterC"); + error(tcs.loc, "cannot use try-catch statements with %s", global.params.betterC ? "-betterC".ptr : "-nothrow".ptr); return setError(); } if (!ClassDeclaration.throwable) { - tcs.error("cannot use try-catch statements because `object.Throwable` was not declared"); + error(tcs.loc, "cannot use try-catch statements because `object.Throwable` was not declared"); return setError(); } @@ -3320,7 +3345,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) const sj = cj.loc.toChars(); if (c.type.toBasetype().implicitConvTo(cj.type.toBasetype())) { - tcs.error("`catch` at %s hides `catch` at %s", sj, si); + error(tcs.loc, "`catch` at %s hides `catch` at %s", sj, si); catchErrors = true; } } @@ -3331,7 +3356,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) sc.func.hasCatches = true; if (flags == (FLAGcpp | FLAGd)) { - tcs.error("cannot mix catching D and C++ exceptions in the same try-catch"); + error(tcs.loc, "cannot mix catching D and C++ exceptions in the same try-catch"); catchErrors = true; } } @@ -3353,7 +3378,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) /* If the try body never throws, we can eliminate any catches * of recoverable exceptions. */ - if (!(tcs._body.blockExit(sc.func, false) & BE.throw_) && ClassDeclaration.exception) + if (!(tcs._body.blockExit(sc.func, null) & BE.throw_) && ClassDeclaration.exception) { foreach_reverse (i; 0 .. tcs.catches.length) { @@ -3403,7 +3428,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) return; } - auto blockexit = tfs._body.blockExit(sc.func, false); + auto blockexit = tfs._body.blockExit(sc.func, null); // if not worrying about exceptions if (!(global.params.useExceptions && ClassDeclaration.throwable)) @@ -3429,7 +3454,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) // https://issues.dlang.org/show_bug.cgi?id=23159 if (!global.params.useExceptions) { - oss.error("`%s` cannot be used with -betterC", Token.toChars(oss.tok)); + error(oss.loc, "`%s` cannot be used with -betterC", Token.toChars(oss.tok)); return setError(); } @@ -3439,12 +3464,12 @@ Statement statementSemanticVisit(Statement s, Scope* sc) if (sc.os && sc.os.tok != TOK.onScopeFailure) { // If enclosing is scope(success) or scope(exit), this will be placed in finally block. - oss.error("cannot put `%s` statement inside `%s`", Token.toChars(oss.tok), Token.toChars(sc.os.tok)); + error(oss.loc, "cannot put `%s` statement inside `%s`", Token.toChars(oss.tok), Token.toChars(sc.os.tok)); return setError(); } if (sc.tf) { - oss.error("cannot put `%s` statement inside `finally` block", Token.toChars(oss.tok)); + error(oss.loc, "cannot put `%s` statement inside `finally` block", Token.toChars(oss.tok)); return setError(); } } @@ -3556,12 +3581,12 @@ Statement statementSemanticVisit(Statement s, Scope* sc) if (ls.loc == ls2.loc) { ls2.duplicated = true; - ls.error("label `%s` is duplicated", ls2.toChars()); + error(ls.loc, "label `%s` is duplicated", ls2.toChars()); .errorSupplemental(ls2.loc, "labels cannot be used in a static foreach with more than 1 iteration"); } else { - ls.error("label `%s` is already defined", ls2.toChars()); + error(ls.loc, "label `%s` is already defined", ls2.toChars()); .errorSupplemental(ls2.loc, "first definition is here"); } return setError(); @@ -3620,14 +3645,14 @@ Statement statementSemanticVisit(Statement s, Scope* sc) assert(sc.func); if (!(cas.stc & STC.pure_) && sc.func.setImpure(cas.loc, "`asm` statement is assumed to be impure - mark it with `pure` if it is not")) - cas.error("`asm` statement is assumed to be impure - mark it with `pure` if it is not"); + error(cas.loc, "`asm` statement is assumed to be impure - mark it with `pure` if it is not"); if (!(cas.stc & STC.nogc) && sc.func.setGC(cas.loc, "`asm` statement in %s `%s` is assumed to use the GC - mark it with `@nogc` if it does not")) - cas.error("`asm` statement is assumed to use the GC - mark it with `@nogc` if it does not"); + error(cas.loc, "`asm` statement is assumed to use the GC - mark it with `@nogc` if it does not"); // @@@DEPRECATED_2.114@@@ // change deprecation() to error(), add `else` and remove `| STC.safe` // to turn deprecation into an error when deprecation cycle is over if (cas.stc & STC.safe) - cas.deprecation("`asm` statement cannot be marked `@safe`, use `@system` or `@trusted` instead"); + deprecation(cas.loc, "`asm` statement cannot be marked `@safe`, use `@system` or `@trusted` instead"); if (!(cas.stc & (STC.trusted | STC.safe))) { sc.setUnsafe(false, cas.loc, "`asm` statement is assumed to be `@system` - mark it with `@trusted` if it is not"); @@ -3696,7 +3721,7 @@ public bool throwSemantic(const ref Loc loc, ref Expression exp, Scope* sc) { if (!global.params.useExceptions) { - loc.error("cannot use `throw` statements with -betterC"); + loc.error("cannot use `throw` statements with %s", global.params.betterC ? "-betterC".ptr : "-nothrow".ptr); return false; } @@ -3767,7 +3792,7 @@ private extern(D) Expression applyOpApply(ForeachStatement fs, Expression flde, return null; if (ec.type != Type.tint32) { - fs.error("`opApply()` function for `%s` must return an `int`", tab.toChars()); + error(fs.loc, "`opApply()` function for `%s` must return an `int`", tab.toChars()); return null; } return ec; @@ -3792,7 +3817,7 @@ private extern(D) Expression applyDelegate(ForeachStatement fs, Expression flde, return null; if (ec.type != Type.tint32) { - fs.error("`opApply()` function for `%s` must return an `int`", tab.toChars()); + error(fs.loc, "`opApply()` function for `%s` must return an `int`", tab.toChars()); return null; } return ec; @@ -3841,13 +3866,13 @@ private extern(D) Expression applyArray(ForeachStatement fs, Expression flde, FuncDeclaration fdapply; TypeDelegate dgty; auto params = new Parameters(); - params.push(new Parameter(STC.in_, tn.arrayOf(), null, null, null)); + params.push(new Parameter(Loc.initial, STC.in_, tn.arrayOf(), null, null, null)); auto dgparams = new Parameters(); - dgparams.push(new Parameter(0, Type.tvoidptr, null, null, null)); + dgparams.push(new Parameter(Loc.initial, 0, Type.tvoidptr, null, null, null)); if (dim == 2) - dgparams.push(new Parameter(0, Type.tvoidptr, null, null, null)); + dgparams.push(new Parameter(Loc.initial, 0, Type.tvoidptr, null, null, null)); dgty = new TypeDelegate(new TypeFunction(ParameterList(dgparams), Type.tint32, LINK.d)); - params.push(new Parameter(0, dgty, null, null, null)); + params.push(new Parameter(Loc.initial, 0, dgty, null, null, null)); fdapply = FuncDeclaration.genCfunc(params, Type.tint32, fdname.ptr); if (tab.isTypeSArray()) @@ -3879,7 +3904,7 @@ private extern(D) Expression applyAssocArray(ForeachStatement fs, Expression fld Type ti = (isRef ? taa.index.addMod(MODFlags.const_) : taa.index); if (isRef ? !ti.constConv(ta) : !ti.implicitConvTo(ta)) { - fs.error("`foreach`: index must be type `%s`, not `%s`", + error(fs.loc, "`foreach`: index must be type `%s`, not `%s`", ti.toChars(), ta.toChars()); return null; } @@ -3890,7 +3915,7 @@ private extern(D) Expression applyAssocArray(ForeachStatement fs, Expression fld Type taav = taa.nextOf(); if (isRef ? !taav.constConv(ta) : !taav.implicitConvTo(ta)) { - fs.error("`foreach`: value must be type `%s`, not `%s`", + error(fs.loc, "`foreach`: value must be type `%s`, not `%s`", taav.toChars(), ta.toChars()); return null; } @@ -3908,14 +3933,14 @@ private extern(D) Expression applyAssocArray(ForeachStatement fs, Expression fld if (!fdapply[i]) { auto params = new Parameters(); - params.push(new Parameter(0, Type.tvoid.pointerTo(), null, null, null)); - params.push(new Parameter(STC.const_, Type.tsize_t, null, null, null)); + params.push(new Parameter(Loc.initial, 0, Type.tvoid.pointerTo(), null, null, null)); + params.push(new Parameter(Loc.initial, STC.const_, Type.tsize_t, null, null, null)); auto dgparams = new Parameters(); - dgparams.push(new Parameter(0, Type.tvoidptr, null, null, null)); + dgparams.push(new Parameter(Loc.initial, 0, Type.tvoidptr, null, null, null)); if (dim == 2) - dgparams.push(new Parameter(0, Type.tvoidptr, null, null, null)); + dgparams.push(new Parameter(Loc.initial, 0, Type.tvoidptr, null, null, null)); fldeTy[i] = new TypeDelegate(new TypeFunction(ParameterList(dgparams), Type.tint32, LINK.d)); - params.push(new Parameter(0, fldeTy[i], null, null, null)); + params.push(new Parameter(Loc.initial, 0, fldeTy[i], null, null, null)); fdapply[i] = FuncDeclaration.genCfunc(params, Type.tint32, i ? Id._aaApply2 : Id._aaApply); } @@ -4000,7 +4025,7 @@ private FuncExp foreachBodyToFunction(Scope* sc, ForeachStatement fs, TypeFuncti { if (!(prm.storageClass & STC.ref_)) { - fs.error("`foreach`: cannot make `%s` `ref`", p.ident.toChars()); + error(fs.loc, "`foreach`: cannot make `%s` `ref`", p.ident.toChars()); return null; } goto LcopyArg; @@ -4026,7 +4051,7 @@ private FuncExp foreachBodyToFunction(Scope* sc, ForeachStatement fs, TypeFuncti Statement s = new ExpStatement(fs.loc, v); fs._body = new CompoundStatement(fs.loc, s, fs._body); } - params.push(new Parameter(stc, p.type, id, null, null)); + params.push(new Parameter(fs.loc, stc, p.type, id, null, null)); } // https://issues.dlang.org/show_bug.cgi?id=13840 // Throwable nested function inside nothrow function is acceptable. @@ -4328,7 +4353,7 @@ public auto makeTupleForeach(Scope* sc, bool isStatic, bool isDecl, ForeachState const bool skipCheck = isStatic && needExpansion; if (!skipCheck && (dim < 1 || dim > 2)) { - fs.error("only one (value) or two (key,value) arguments allowed for sequence `foreach`"); + error(fs.loc, "only one (value) or two (key,value) arguments allowed for sequence `foreach`"); return returnEarly(); } @@ -4390,7 +4415,7 @@ public auto makeTupleForeach(Scope* sc, bool isStatic, bool isDecl, ForeachState // Declare key if (p.isReference() || p.isLazy()) { - fs.error("no storage class for key `%s`", p.ident.toChars()); + error(fs.loc, "no storage class for key `%s`", p.ident.toChars()); return returnEarly(); } @@ -4405,7 +4430,7 @@ public auto makeTupleForeach(Scope* sc, bool isStatic, bool isDecl, ForeachState if (!p.type.isintegral()) { - fs.error("foreach: key cannot be of non-integral type `%s`", + error(fs.loc, "foreach: key cannot be of non-integral type `%s`", p.type.toChars()); return returnEarly(); } @@ -4416,7 +4441,7 @@ public auto makeTupleForeach(Scope* sc, bool isStatic, bool isDecl, ForeachState dimrange.imax = SignExtendedNumber(dimrange.imax.value-1); if (!IntRange.fromType(p.type).contains(dimrange)) { - fs.error("index type `%s` cannot cover index range 0..%llu", + error(fs.loc, "index type `%s` cannot cover index range 0..%llu", p.type.toChars(), cast(ulong)length); return returnEarly(); } @@ -4450,7 +4475,7 @@ public auto makeTupleForeach(Scope* sc, bool isStatic, bool isDecl, ForeachState if (storageClass & (STC.out_ | STC.lazy_) || storageClass & STC.ref_ && !te) { - fs.error("no storage class for value `%s`", ident.toChars()); + error(fs.loc, "no storage class for value `%s`", ident.toChars()); return false; } Declaration var; @@ -4478,7 +4503,7 @@ public auto makeTupleForeach(Scope* sc, bool isStatic, bool isDecl, ForeachState } else if (storageClass & STC.alias_) { - fs.error("`foreach` loop variable cannot be both `enum` and `alias`"); + error(fs.loc, "`foreach` loop variable cannot be both `enum` and `alias`"); return false; } @@ -4487,12 +4512,12 @@ public auto makeTupleForeach(Scope* sc, bool isStatic, bool isDecl, ForeachState var = new AliasDeclaration(loc, ident, ds); if (storageClass & STC.ref_) { - fs.error("symbol `%s` cannot be `ref`", ds.toChars()); + error(fs.loc, "symbol `%s` cannot be `ref`", ds.toChars()); return false; } if (paramtype) { - fs.error("cannot specify element type for symbol `%s`", ds.toChars()); + error(fs.loc, "cannot specify element type for symbol `%s`", ds.toChars()); return false; } } @@ -4501,7 +4526,7 @@ public auto makeTupleForeach(Scope* sc, bool isStatic, bool isDecl, ForeachState var = new AliasDeclaration(loc, ident, e.type); if (paramtype) { - fs.error("cannot specify element type for type `%s`", e.type.toChars()); + error(fs.loc, "cannot specify element type for type `%s`", e.type.toChars()); return false; } } @@ -4522,17 +4547,17 @@ public auto makeTupleForeach(Scope* sc, bool isStatic, bool isDecl, ForeachState { if (!isStatic) { - fs.error("constant value `%s` cannot be `ref`", ie.toChars()); + error(fs.loc, "constant value `%s` cannot be `ref`", ie.toChars()); } else { if (!needExpansion) { - fs.error("constant value `%s` cannot be `ref`", ie.toChars()); + error(fs.loc, "constant value `%s` cannot be `ref`", ie.toChars()); } else { - fs.error("constant value `%s` cannot be `ref`", ident.toChars()); + error(fs.loc, "constant value `%s` cannot be `ref`", ident.toChars()); } } return false; @@ -4548,7 +4573,7 @@ public auto makeTupleForeach(Scope* sc, bool isStatic, bool isDecl, ForeachState var = new AliasDeclaration(loc, ident, t); if (paramtype) { - fs.error("cannot specify element type for symbol `%s`", fs.toChars()); + error(fs.loc, "cannot specify element type for symbol `%s`", fs.toChars()); return false; } } diff --git a/gcc/d/dmd/tokens.d b/gcc/d/dmd/tokens.d index 950c830..c76d549 100644 --- a/gcc/d/dmd/tokens.d +++ b/gcc/d/dmd/tokens.d @@ -124,6 +124,7 @@ enum TOK : ubyte // Leaf operators identifier, string_, + hexadecimalString, this_, super_, error, @@ -855,6 +856,7 @@ extern (C++) struct Token TOK.wcharLiteral: "wcharv", TOK.dcharLiteral: "dcharv", TOK.wchar_tLiteral: "wchar_tv", + TOK.hexadecimalString: "xstring", TOK.endOfLine: "\\n", TOK.whitespace: "whitespace", @@ -898,7 +900,7 @@ extern (C++) struct Token nothrow: - int isKeyword() const @safe + int isKeyword() pure const @safe @nogc { foreach (kw; keywords) { @@ -1014,6 +1016,24 @@ nothrow: p = buf.extractChars(); } break; + case TOK.hexadecimalString: + { + OutBuffer buf; + buf.writeByte('x'); + buf.writeByte('"'); + foreach (size_t i; 0 .. len) + { + if (i) + buf.writeByte(' '); + buf.printf("%02x", ustring[i]); + } + buf.writeByte('"'); + if (postfix) + buf.writeByte(postfix); + buf.writeByte(0); + p = buf.extractData(); + break; + } case TOK.identifier: case TOK.enum_: case TOK.struct_: diff --git a/gcc/d/dmd/tokens.h b/gcc/d/dmd/tokens.h index 6c1b979..b1f633f 100644 --- a/gcc/d/dmd/tokens.h +++ b/gcc/d/dmd/tokens.h @@ -133,6 +133,7 @@ enum class TOK : unsigned char // Leaf operators identifier, string_, + hexadecimalString, this_, super_, error, diff --git a/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d index 0d9c95f..2bde9f2 100644 --- a/gcc/d/dmd/traits.d +++ b/gcc/d/dmd/traits.d @@ -1920,7 +1920,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) StringExp se = ex ? ex.ctfeInterpret().toStringExp() : null; if (!ex || !se || se.len == 0) { - e.error("string expected as argument of __traits `%s` instead of `%s`", e.ident.toChars(), ex.toChars()); + e.error("string expected as argument of __traits `%s` instead of `%s`", e.ident.toChars(), (*e.args)[0].toChars()); return ErrorExp.get(); } se = se.toUTF8(sc); diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index a80aa80..1422689 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -1170,8 +1170,8 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) StorageClass stc2 = narg.storageClass & (STC.ref_ | STC.out_ | STC.lazy_); if (stc1 && stc2 && stc1 != stc2) { - OutBuffer buf1; stcToBuffer(&buf1, stc1 | ((stc1 & STC.ref_) ? (fparam.storageClass & STC.auto_) : 0)); - OutBuffer buf2; stcToBuffer(&buf2, stc2); + OutBuffer buf1; stcToBuffer(buf1, stc1 | ((stc1 & STC.ref_) ? (fparam.storageClass & STC.auto_) : 0)); + OutBuffer buf2; stcToBuffer(buf2, stc2); .error(loc, "incompatible parameter storage classes `%s` and `%s`", buf1.peekChars(), buf2.peekChars()); @@ -1179,7 +1179,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) stc = stc1 | (stc & ~(STC.ref_ | STC.out_ | STC.lazy_)); } (*newparams)[j] = new Parameter( - stc, narg.type, narg.ident, narg.defaultArg, narg.userAttribDecl); + loc, stc, narg.type, narg.ident, narg.defaultArg, narg.userAttribDecl); } fparam.type = new TypeTuple(newparams); fparam.type = fparam.type.typeSemantic(loc, argsc); @@ -2089,6 +2089,7 @@ Expression getProperty(Type t, Scope* scope_, const ref Loc loc, Identifier iden { e = new StringExp(loc, mt.deco.toDString()); Scope sc; + sc.eSink = global.errorSink; e = e.expressionSemantic(&sc); } } @@ -2097,6 +2098,7 @@ Expression getProperty(Type t, Scope* scope_, const ref Loc loc, Identifier iden const s = mt.toChars(); e = new StringExp(loc, s.toDString()); Scope sc; + sc.eSink = global.errorSink; e = e.expressionSemantic(&sc); } else if (flag && mt != Type.terror) @@ -2127,7 +2129,9 @@ Expression getProperty(Type t, Scope* scope_, const ref Loc loc, Identifier iden error(loc, "no property `%s` for `%s` of type `%s`", ident.toChars(), src.toChars(), mt.toPrettyChars(true)); else error(loc, "no property `%s` for type `%s`", ident.toChars(), mt.toPrettyChars(true)); + if (auto dsym = mt.toDsymbol(scope_)) + { if (auto sym = dsym.isAggregateDeclaration()) { if (auto fd = search_function(sym, Id.opDispatch)) @@ -2135,6 +2139,9 @@ Expression getProperty(Type t, Scope* scope_, const ref Loc loc, Identifier iden else if (!sym.members) errorSupplemental(sym.loc, "`%s %s` is opaque and has no members.", sym.kind, mt.toPrettyChars(true)); } + errorSupplemental(dsym.loc, "%s `%s` defined here", + dsym.kind, dsym.toChars()); + } } } e = ErrorExp.get(); @@ -3482,7 +3489,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag if (fd_aaLen is null) { auto fparams = new Parameters(); - fparams.push(new Parameter(STC.const_ | STC.scope_, mt, null, null, null)); + fparams.push(new Parameter(Loc.initial, STC.const_ | STC.scope_, mt, null, null, null)); fd_aaLen = FuncDeclaration.genCfunc(fparams, Type.tsize_t, Id.aaLen); TypeFunction tf = fd_aaLen.type.toTypeFunction(); tf.purity = PURE.const_; @@ -3938,6 +3945,8 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag e.error("no property `%s` for type `%s`", ident.toChars(), mt.toChars()); + errorSupplemental(mt.sym.loc, "%s `%s` defined here", + mt.sym.kind, mt.toChars()); return ErrorExp.get(); } return res; @@ -4791,7 +4800,7 @@ Type stripDefaultArgs(Type t) { Type t = stripDefaultArgs(p.type); return (t != p.type || p.defaultArg || p.ident || p.userAttribDecl) - ? new Parameter(p.storageClass, t, null, null, null) + ? new Parameter(p.loc, p.storageClass, t, null, null, null) : null; } diff --git a/gcc/d/dmd/utils.d b/gcc/d/dmd/utils.d index dfb4cb5..bb389b6 100644 --- a/gcc/d/dmd/utils.d +++ b/gcc/d/dmd/utils.d @@ -53,12 +53,6 @@ const(char)* toWinPath(const(char)* src) * loc = The line number information from where the call originates * filename = Path to file */ -Buffer readFile(Loc loc, const(char)* filename) -{ - return readFile(loc, filename.toDString()); -} - -/// Ditto Buffer readFile(Loc loc, const(char)[] filename) { auto result = File.read(filename); @@ -78,15 +72,19 @@ Buffer readFile(Loc loc, const(char)[] filename) * loc = The line number information from where the call originates * filename = Path to file * data = Full content of the file to be written + * Returns: + * false on error */ -extern (D) void writeFile(Loc loc, const(char)[] filename, const void[] data) +extern (D) bool writeFile(Loc loc, const(char)[] filename, const void[] data) { - ensurePathToNameExists(Loc.initial, filename); + if (!ensurePathToNameExists(Loc.initial, filename)) + return false; if (!File.update(filename, data)) { error(loc, "error writing file '%.*s'", cast(int) filename.length, filename.ptr); - fatal(); + return false; } + return true; } @@ -97,8 +95,10 @@ extern (D) void writeFile(Loc loc, const(char)[] filename, const void[] data) * Params: * loc = The line number information from where the call originates * name = a path to check (the name is stripped) + * Returns: + * false on error */ -void ensurePathToNameExists(Loc loc, const(char)[] name) +bool ensurePathToNameExists(Loc loc, const(char)[] name) { const char[] pt = FileName.path(name); if (pt.length) @@ -106,10 +106,12 @@ void ensurePathToNameExists(Loc loc, const(char)[] name) if (!FileName.ensurePathExists(pt)) { error(loc, "cannot create directory %*.s", cast(int) pt.length, pt.ptr); - fatal(); + FileName.free(pt.ptr); + return false; } } FileName.free(pt.ptr); + return true; } |