diff --git a/compiler/src/dmd/arrayop.d b/compiler/src/dmd/arrayop.d index d0ec5ebcdbe9..66570e315f87 100644 --- a/compiler/src/dmd/arrayop.d +++ b/compiler/src/dmd/arrayop.d @@ -231,7 +231,7 @@ private Expressions* buildArrayOp(Scope* sc, Expression e, Objects* tiargs) // RPN, prefix unary ops with u OutBuffer buf; buf.writestring("u"); - buf.writestring(EXPtoString(e.op)); + buf.writestring(expressionTypeToString(e.op)); e.e1.accept(this); tiargs.push(new StringExp(Loc.initial, buf.extractSlice()).expressionSemantic(sc)); } @@ -249,7 +249,7 @@ private Expressions* buildArrayOp(Scope* sc, Expression e, Objects* tiargs) // RPN e.e1.accept(this); e.e2.accept(this); - tiargs.push(new StringExp(Loc.initial, EXPtoString(e.op)).expressionSemantic(sc)); + tiargs.push(new StringExp(Loc.initial, expressionTypeToString(e.op)).expressionSemantic(sc)); } } } diff --git a/compiler/src/dmd/astcodegen.d b/compiler/src/dmd/astcodegen.d index fd8387adb224..0ce1401b2397 100644 --- a/compiler/src/dmd/astcodegen.d +++ b/compiler/src/dmd/astcodegen.d @@ -90,7 +90,7 @@ struct ASTCodegen alias Dsymbols = dmd.dsymbol.Dsymbols; alias Visibility = dmd.dsymbol.Visibility; - alias stcToBuffer = dmd.hdrgen.stcToBuffer; + alias stcToBuffer = dmd.hdrgen.storageClassToBuffer; alias linkageToChars = dmd.hdrgen.linkageToChars; alias visibilityToChars = dmd.hdrgen.visibilityToChars; diff --git a/compiler/src/dmd/astenums.d b/compiler/src/dmd/astenums.d index 1e30b9f8fc25..58f17987671f 100644 --- a/compiler/src/dmd/astenums.d +++ b/compiler/src/dmd/astenums.d @@ -141,6 +141,15 @@ enum STC : ulong // transfer changes to declaration.h STC.TYPECTOR | STC.final_ | STC.tls | STC.gshared | STC.ref_ | STC.return_ | STC.property | STC.nothrow_ | STC.pure_ | STC.safe | STC.trusted | STC.system), /// for a FuncDeclaration + // These storage classes when used as attributes should emitted differently as part of .di header generator + lhsHeaderAttributes = STC.static_ | STC.extern_ | STC.final_ | STC.abstract_ | STC.override_ | + STC.synchronized_ | STC.deprecated_ | STC.disable, + // For module (de)constructors limit lhs + lhsHeaderMCtorAttributes = STC.extern_ | STC.final_ | STC.abstract_ | STC.override_ | + STC.synchronized_ | STC.deprecated_ | STC.disable, + // For module (de)constructors limit rhs + rhsHeaderMCtorAttributes = STC.visibleStorageClasses & ~(STC.lhsHeaderMCtorAttributes | STC.shared_ | STC.static_), + } alias StorageClass = ulong; diff --git a/compiler/src/dmd/ctfeexpr.d b/compiler/src/dmd/ctfeexpr.d index d2fcf5f79608..9a8eaa8b2126 100644 --- a/compiler/src/dmd/ctfeexpr.d +++ b/compiler/src/dmd/ctfeexpr.d @@ -62,7 +62,7 @@ extern (D) struct UnionExp extern (D) Expression copy() { Expression e = exp(); - //if (e.size > sizeof(u)) printf("%s\n", EXPtoString(e.op).ptr); + //if (e.size > sizeof(u)) printf("%s\n", expressionTypeToString(e.op).ptr); assert(e.size <= u.sizeof); switch (e.op) { @@ -1325,8 +1325,8 @@ bool ctfeEqual(const ref Loc loc, EXP op, Expression e1, Expression e2) bool ctfeIdentity(const ref Loc loc, EXP op, Expression e1, Expression e2) { //printf("ctfeIdentity %s %s\n", e1.toChars(), e2.toChars()); - //printf("ctfeIdentity op = '%s', e1 = %s %s, e2 = %s %s\n", EXPtoString(op).ptr, - // EXPtoString(e1.op).ptr, e1.toChars(), EXPtoString(e2.op).ptr, e1.toChars()); + //printf("ctfeIdentity op = '%s', e1 = %s %s, e2 = %s %s\n", expressionTypeToString(op).ptr, + // expressionTypeToString(e1.op).ptr, e1.toChars(), expressionTypeToString(e2.op).ptr, e1.toChars()); bool cmp; if (e1.op == EXP.null_) { diff --git a/compiler/src/dmd/dcast.d b/compiler/src/dmd/dcast.d index 78781f4ced7c..042d1a0b90ee 100644 --- a/compiler/src/dmd/dcast.d +++ b/compiler/src/dmd/dcast.d @@ -3590,13 +3590,13 @@ LmodCompare: return null; } - //printf("test %s\n", EXPtoString(op).ptr); + //printf("test %s\n", expressionTypeToString(op).ptr); e1 = e1.optimize(WANTvalue); if (isCommutative(op) && e1.isConst()) { /* Swap operands to minimize number of functions generated */ - //printf("swap %s\n", EXPtoString(op).ptr); + //printf("swap %s\n", expressionTypeToString(op).ptr); Expression tmp = e1; e1 = e2; e2 = tmp; @@ -3777,7 +3777,7 @@ void fix16997(Scope* sc, UnaExp ue) case Twchar: case Tdchar: deprecation(ue.loc, "integral promotion not done for `%s`, remove '-revert=intpromote' switch or `%scast(int)(%s)`", - ue.toChars(), EXPtoString(ue.op).ptr, ue.e1.toChars()); + ue.toChars(), expressionTypeToString(ue.op).ptr, ue.e1.toChars()); break; default: diff --git a/compiler/src/dmd/dinterpret.d b/compiler/src/dmd/dinterpret.d index 5493fc188812..e0070b7479b9 100644 --- a/compiler/src/dmd/dinterpret.d +++ b/compiler/src/dmd/dinterpret.d @@ -1696,7 +1696,7 @@ public: { debug (LOG) { - printf("%s Expression::interpret() '%s' %s\n", e.loc.toChars(), EXPtoString(e.op).ptr, e.toChars()); + printf("%s Expression::interpret() '%s' %s\n", e.loc.toChars(), expressionTypeToString(e.op).ptr, e.toChars()); printf("type = %s\n", e.type.toChars()); showCtfeExpr(e); } @@ -3266,7 +3266,7 @@ public: return; default: - printf("be = '%s' %s at [%s]\n", EXPtoString(e.op).ptr, e.toChars(), e.loc.toChars()); + printf("be = '%s' %s at [%s]\n", expressionTypeToString(e.op).ptr, e.toChars(), e.loc.toChars()); assert(0); } } @@ -4778,7 +4778,7 @@ public: if (auto ce = ea.isCastExp()) ea = ce.e1; - // printf("2 ea = %s, %s %s\n", ea.type.toChars(), EXPtoString(ea.op).ptr, ea.toChars()); + // printf("2 ea = %s, %s %s\n", ea.type.toChars(), expressionTypeToString(ea.op).ptr, ea.toChars()); if (ea.op == EXP.variable || ea.op == EXP.symbolOffset) result = getVarExp(e.loc, istate, (cast(SymbolExp)ea).var, CTFEGoal.RValue); else if (auto ae = ea.isAddrExp()) @@ -7130,7 +7130,7 @@ private Expression copyRegionExp(Expression e) return e; default: - printf("e: %s, %s\n", EXPtoString(e.op).ptr, e.toChars()); + printf("e: %s, %s\n", expressionTypeToString(e.op).ptr, e.toChars()); assert(0); } diff --git a/compiler/src/dmd/doc.d b/compiler/src/dmd/doc.d index a8b43da625b3..715b1102e4da 100644 --- a/compiler/src/dmd/doc.d +++ b/compiler/src/dmd/doc.d @@ -243,7 +243,7 @@ final class ParamSection : Section } else if (fparam && fparam.type && fparam.ident) { - toCBuffer(fparam.type, buf, fparam.ident, hgs); + hgs.toCBuffer(fparam.type, buf, fparam.ident); } else { @@ -1227,7 +1227,7 @@ 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); + hgs.toCBuffer(s, *buf); } void prefix(Dsymbol s) @@ -1277,7 +1277,7 @@ void toDocBuffer(Dsymbol s, ref OutBuffer buf, Scope* sc) HdrGenState hgs; hgs.ddoc = true; emitVisibility(*buf, i); - toCBuffer(i, *buf, hgs); + hgs.toCBuffer(i, *buf); } override void visit(Declaration d) @@ -1296,10 +1296,10 @@ 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); + hgs.functionSignatureToBuffer(cast(TypeFunction)origType, *buf, d.ident, td); } else - toCBuffer(origType, *buf, d.ident, hgs); + hgs.toCBuffer(origType, *buf, d.ident); } else buf.writestring(d.ident.toString()); @@ -1312,7 +1312,7 @@ void toDocBuffer(Dsymbol s, ref OutBuffer buf, Scope* sc) { if (i) buf.writestring(", "); - toCBuffer((*td.origParameters)[i], *buf, hgs); + hgs.toCBuffer((*td.origParameters)[i], *buf); } } buf.writeByte(')'); @@ -1326,7 +1326,7 @@ void toDocBuffer(Dsymbol s, ref OutBuffer buf, Scope* sc) buf.writestring("$(DDOC_CONSTRAINT "); } - toCBuffer(td.constraint, *buf, hgs); + hgs.toCBuffer(td.constraint, *buf); if (noFuncDecl) { @@ -1487,7 +1487,7 @@ void toDocBuffer(Dsymbol s, ref OutBuffer buf, Scope* sc) else { HdrGenState hgs; - toCBuffer(bc.type, *buf, null, hgs); + hgs.toCBuffer(bc.type, *buf, null); } } buf.writestring(";\n"); @@ -1502,7 +1502,7 @@ void toDocBuffer(Dsymbol s, ref OutBuffer buf, Scope* sc) { buf.writestring(": $(DDOC_ENUM_BASETYPE "); HdrGenState hgs; - toCBuffer(ed.memtype, *buf, null, hgs); + hgs.toCBuffer(ed.memtype, *buf, null); buf.writestring(")"); } buf.writestring(";\n"); @@ -5078,7 +5078,7 @@ void highlightCode(Scope* sc, Dsymbols* a, ref OutBuffer buf, size_t offset) size_t lastOffset = parametersBuf.length; - toCBuffer(tp, parametersBuf, hgs); + hgs.toCBuffer(tp, parametersBuf); paramLens[parami] = parametersBuf.length - lastOffset; } diff --git a/compiler/src/dmd/dsymbolsem.d b/compiler/src/dmd/dsymbolsem.d index 4a21b1473423..84995523781a 100644 --- a/compiler/src/dmd/dsymbolsem.d +++ b/compiler/src/dmd/dsymbolsem.d @@ -896,7 +896,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor else { OutBuffer buf; - stcToBuffer(buf, stc); + storageClassToBuffer(buf, stc); .error(dsym.loc, "%s `%s` cannot be `%s`", dsym.kind, dsym.toPrettyChars, buf.peekChars()); } dsym.storage_class &= ~stc; // strip off @@ -913,7 +913,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (stc) { OutBuffer buf; - stcToBuffer(buf, stc); + storageClassToBuffer(buf, stc); .error(dsym.loc, "%s `%s` cannot be `scope` and `%s`", dsym.kind, dsym.toPrettyChars, buf.peekChars()); } else if (dsym.isMember()) @@ -1671,7 +1671,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor ob.writeByte(' '); if (imp.isstatic) { - stcToBuffer(*ob, STC.static_); + storageClassToBuffer(*ob, STC.static_); ob.writeByte(' '); } ob.writestring(": "); diff --git a/compiler/src/dmd/dtemplate.d b/compiler/src/dmd/dtemplate.d index 33ec6b1849f6..09899dfbfb67 100644 --- a/compiler/src/dmd/dtemplate.d +++ b/compiler/src/dmd/dtemplate.d @@ -314,8 +314,8 @@ private bool match(RootObject o1, RootObject o2) static if (log) { - printf("\te1 = %s '%s' %s\n", e1.type ? e1.type.toChars() : "null", EXPtoString(e1.op).ptr, e1.toChars()); - printf("\te2 = %s '%s' %s\n", e2.type ? e2.type.toChars() : "null", EXPtoString(e2.op).ptr, e2.toChars()); + printf("\te1 = %s '%s' %s\n", e1.type ? e1.type.toChars() : "null", expressionTypeToString(e1.op).ptr, e1.toChars()); + printf("\te2 = %s '%s' %s\n", e2.type ? e2.type.toChars() : "null", expressionTypeToString(e2.op).ptr, e2.toChars()); } // two expressions can be equal although they do not have the same @@ -747,7 +747,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol { HdrGenState hgs; OutBuffer buf; - toCharsMaybeConstraints(this, buf, hgs); + hgs.toCharsMaybeConstraints(this, buf); return buf.extractChars(); } @@ -758,7 +758,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol { HdrGenState hgs = { skipConstraints: true }; OutBuffer buf; - toCharsMaybeConstraints(this, buf, hgs); + hgs.toCharsMaybeConstraints(this, buf); return buf.extractChars(); } @@ -4581,7 +4581,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol else if (ea) { Lexpr: - //printf("+[%d] ea = %s %s\n", j, EXPtoString(ea.op).ptr, ea.toChars()); + //printf("+[%d] ea = %s %s\n", j, expressionTypeToString(ea.op).ptr, ea.toChars()); if (flags & 1) // only used by __traits { ea = ea.expressionSemantic(sc); @@ -4626,7 +4626,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol ea = ErrorExp.get(); } } - //printf("-[%d] ea = %s %s\n", j, EXPtoString(ea.op).ptr, ea.toChars()); + //printf("-[%d] ea = %s %s\n", j, expressionTypeToString(ea.op).ptr, ea.toChars()); if (TupleExp te = ea.isTupleExp()) { // Expand tuple @@ -4979,7 +4979,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol OutBuffer buf; HdrGenState hgs; hgs.skipConstraints = true; - toCharsMaybeConstraints(tdecl, buf, hgs); + hgs.toCharsMaybeConstraints(tdecl, buf); const tmsg = buf.peekChars(); const cmsg = tdecl.getConstraintEvalError(tip); if (cmsg) @@ -6388,7 +6388,7 @@ void printTemplateStats(bool listInstances, ErrorSink eSink) buf.reset(); HdrGenState hgs; hgs.skipConstraints = true; - toCharsMaybeConstraints(ss.td, buf, hgs); + hgs.toCharsMaybeConstraints(ss.td, buf); const tchars = buf.peekChars(); if (listInstances && ss.ts.allInstances) { diff --git a/compiler/src/dmd/dtoh.d b/compiler/src/dmd/dtoh.d index 883091be9e30..fd81c5ce8782 100644 --- a/compiler/src/dmd/dtoh.d +++ b/compiler/src/dmd/dtoh.d @@ -2544,7 +2544,7 @@ public: case identity: return "=="; case notIdentity: return "!="; default: - return EXPtoString(op); + return expressionTypeToString(op); } } diff --git a/compiler/src/dmd/e2ir.d b/compiler/src/dmd/e2ir.d index e073d6bd82dc..c3b53aaf212f 100644 --- a/compiler/src/dmd/e2ir.d +++ b/compiler/src/dmd/e2ir.d @@ -562,7 +562,7 @@ elem* toElem(Expression e, ref IRState irs) { elem* visit(Expression e) { - printf("[%s] %s: %s\n", e.loc.toChars(), EXPtoString(e.op).ptr, e.toChars()); + printf("[%s] %s: %s\n", e.loc.toChars(), expressionTypeToString(e.op).ptr, e.toChars()); assert(0); } diff --git a/compiler/src/dmd/expression.d b/compiler/src/dmd/expression.d index a26f3ab83b99..3cfd33969003 100644 --- a/compiler/src/dmd/expression.d +++ b/compiler/src/dmd/expression.d @@ -472,7 +472,7 @@ extern (C++) abstract class Expression : ASTNode dinteger_t toInteger() { - //printf("Expression %s\n", EXPtoString(op).ptr); + //printf("Expression %s\n", expressionTypeToString(op).ptr); if (!type.isTypeError()) error(loc, "integer constant expression expected instead of `%s`", toChars()); return 0; @@ -480,7 +480,7 @@ extern (C++) abstract class Expression : ASTNode uinteger_t toUInteger() { - //printf("Expression %s\n", EXPtoString(op).ptr); + //printf("Expression %s\n", expressionTypeToString(op).ptr); return cast(uinteger_t)toInteger(); } @@ -601,7 +601,7 @@ extern (C++) abstract class Expression : ASTNode const char* msg = type.isAggregate() ? "operator `%s` is not defined for `%s` of type `%s`" : "illegal operator `%s` for `%s` of type `%s`"; - error(loc, msg, EXPtoString(op).ptr, toChars(), type.toChars()); + error(loc, msg, expressionTypeToString(op).ptr, toChars(), type.toChars()); return true; } return checkValue(); @@ -635,7 +635,7 @@ extern (C++) abstract class Expression : ASTNode error(loc, "read-modify-write operations are not allowed for `shared` variables"); errorSupplemental(loc, "Use `core.atomic.atomicOp!\"%s\"(%s, %s)` instead", - EXPtoString(rmwOp).ptr, toChars(), ex ? ex.toChars() : "1"); + expressionTypeToString(rmwOp).ptr, toChars(), ex ? ex.toChars() : "1"); return true; } @@ -3036,11 +3036,11 @@ extern (C++) abstract class UnaExp : Expression if (e1.op == EXP.type) { - error(loc, "incompatible type for `%s(%s)`: cannot use `%s` with types", EXPtoString(op).ptr, e1.toChars(), EXPtoString(op).ptr); + error(loc, "incompatible type for `%s(%s)`: cannot use `%s` with types", expressionTypeToString(op).ptr, e1.toChars(), expressionTypeToString(op).ptr); } else { - error(loc, "incompatible type for `%s(%s)`: `%s`", EXPtoString(op).ptr, e1.toChars(), e1.type.toChars()); + error(loc, "incompatible type for `%s(%s)`: `%s`", expressionTypeToString(op).ptr, e1.toChars(), e1.type.toChars()); } return ErrorExp.get(); } @@ -3103,11 +3103,11 @@ extern (C++) abstract class BinExp : Expression return e2; // CondExp uses 'a ? b : c' but we're comparing 'b : c' - const(char)* thisOp = (op == EXP.question) ? ":" : EXPtoString(op).ptr; + const(char)* thisOp = (op == EXP.question) ? ":" : expressionTypeToString(op).ptr; if (e1.op == EXP.type || e2.op == EXP.type) { error(loc, "incompatible types for `(%s) %s (%s)`: cannot use `%s` with types", - e1.toChars(), thisOp, e2.toChars(), EXPtoString(op).ptr); + e1.toChars(), thisOp, e2.toChars(), expressionTypeToString(op).ptr); } else if (e1.type.equals(e2.type)) { diff --git a/compiler/src/dmd/expressionsem.d b/compiler/src/dmd/expressionsem.d index 481806d392bd..e44be9670440 100644 --- a/compiler/src/dmd/expressionsem.d +++ b/compiler/src/dmd/expressionsem.d @@ -408,7 +408,7 @@ private Expression checkOpAssignTypes(BinExp binExp, Scope* sc) { if ((type.isintegral() && t2.isfloating())) { - warning(loc, "`%s %s %s` is performing truncating conversion", type.toChars(), EXPtoString(op).ptr, t2.toChars()); + warning(loc, "`%s %s %s` is performing truncating conversion", type.toChars(), expressionTypeToString(op).ptr, t2.toChars()); } } @@ -417,7 +417,7 @@ private Expression checkOpAssignTypes(BinExp binExp, Scope* sc) { // Any multiplication by an imaginary or complex number yields a complex result. // r *= c, i*=c, r*=i, i*=i are all forbidden operations. - const(char)* opstr = EXPtoString(op).ptr; + const(char)* opstr = expressionTypeToString(op).ptr; if (t1.isreal() && t2.iscomplex()) { error(loc, "`%s %s %s` is undefined. Did you mean `%s %s %s.re`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars()); @@ -442,7 +442,7 @@ private Expression checkOpAssignTypes(BinExp binExp, Scope* sc) // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations. if ((t1.isreal() && (t2.isimaginary() || t2.iscomplex())) || (t1.isimaginary() && (t2.isreal() || t2.iscomplex()))) { - error(loc, "`%s %s %s` is undefined (result is complex)", t1.toChars(), EXPtoString(op).ptr, t2.toChars()); + error(loc, "`%s %s %s` is undefined (result is complex)", t1.toChars(), expressionTypeToString(op).ptr, t2.toChars()); return ErrorExp.get(); } if (type.isreal() || type.isimaginary()) @@ -1263,7 +1263,7 @@ int expandAliasThisTuples(Expressions* exps, size_t starti = 0) printf("expansion ->\n"); foreach (e; exps) { - printf("\texps[%d] e = %s %s\n", i, EXPtoString(e.op), e.toChars()); + printf("\texps[%d] e = %s %s\n", i, expressionTypeToString(e.op), e.toChars()); } } return cast(int)u; @@ -2253,7 +2253,7 @@ private bool checkPostblit(Type t, ref Loc loc, Scope* sc) */ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = null, BinExp saveAtts = null) { - //printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", EXPtoString(e1.op).ptr, e1.toChars(), e2 ? e2.toChars() : null); + //printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", expressionTypeToString(e1.op).ptr, e1.toChars(), e2 ? e2.toChars() : null); Loc loc = e1.loc; OverloadSet os; @@ -7628,7 +7628,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (p.token.value != TOK.endOfFile) { error(e.loc, "unexpected token `%s` after %s expression", - p.token.toChars(), EXPtoString(e.op).ptr); + p.token.toChars(), expressionTypeToString(e.op).ptr); errorSupplemental(e.loc, "while parsing string mixin expression `%s`", str.ptr); return null; @@ -7961,7 +7961,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } // template args - Expression comp = new StringExp(loc, isEqualsCallExpression ? "==" : EXPtoString(exp.e1.op)); + Expression comp = new StringExp(loc, isEqualsCallExpression ? "==" : expressionTypeToString(exp.e1.op)); comp = comp.expressionSemantic(sc); (*es)[0] = comp; (*tiargs)[0] = (*es)[1].type; @@ -13458,7 +13458,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } else if (t1.ty == Taarray || t2.ty == Taarray) { - error(exp.loc, "`%s` is not defined for associative arrays", EXPtoString(exp.op).ptr); + error(exp.loc, "`%s` is not defined for associative arrays", expressionTypeToString(exp.op).ptr); return setError(); } else if (!target.isVectorOpSupported(t1, exp.op, t2)) @@ -15451,8 +15451,9 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc) if (fd) { const funcStr = fd.Dsymbol.toPrettyChars(); + HdrGenState hds; OutBuffer buf; - functionToBufferWithIdent(fd.type.isTypeFunction(), buf, funcStr, fd.isStatic); + hds.functionSignatureToBufferAsPostfix(fd.type.isTypeFunction(), buf, funcStr.toDString(), fd.isStatic); s = buf.extractChars(); } else diff --git a/compiler/src/dmd/frontend.d b/compiler/src/dmd/frontend.d index a181a6628916..ce865063d24a 100644 --- a/compiler/src/dmd/frontend.d +++ b/compiler/src/dmd/frontend.d @@ -449,12 +449,12 @@ Returns: string prettyPrint(Module m) { import dmd.common.outbuffer: OutBuffer; - import dmd.hdrgen : HdrGenState, moduleToBuffer2; + import dmd.hdrgen : HdrGenState; auto buf = OutBuffer(); buf.doindent = 1; HdrGenState hgs = { fullDump: 1 }; - moduleToBuffer2(m, buf, hgs); + hgs.moduleToBuffer2(m, buf); import std.string : replace, fromStringz; import std.exception : assumeUnique; diff --git a/compiler/src/dmd/func.d b/compiler/src/dmd/func.d index 54ff82670aeb..6e2fb60d582c 100644 --- a/compiler/src/dmd/func.d +++ b/compiler/src/dmd/func.d @@ -620,8 +620,9 @@ extern (C++) class FuncDeclaration : Declaration /** for diagnostics, e.g. 'int foo(int x, int y) pure' */ final const(char)* toFullSignature() { + HdrGenState hds; OutBuffer buf; - functionToBufferWithIdent(type.toTypeFunction(), buf, toChars(), isStatic); + hds.functionSignatureToBufferAsPostfix(type.toTypeFunction(), buf, toChars().toDString(), isStatic); return buf.extractChars(); } diff --git a/compiler/src/dmd/funcsem.d b/compiler/src/dmd/funcsem.d index fdbadb9a8df5..06a8cd4c6449 100644 --- a/compiler/src/dmd/funcsem.d +++ b/compiler/src/dmd/funcsem.d @@ -932,8 +932,8 @@ void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl) OutBuffer buf; auto fd = s.isFuncDeclaration(); - functionToBufferFull(cast(TypeFunction)(funcdecl.type), buf, - new Identifier(funcdecl.toPrettyChars()), hgs, null); + hgs.functionSignatureToBuffer(cast(TypeFunction)(funcdecl.type), buf, + new Identifier(funcdecl.toPrettyChars()), null); const(char)* funcdeclToChars = buf.peekChars(); if (fd) @@ -955,8 +955,8 @@ void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl) } else { - functionToBufferFull(cast(TypeFunction)(fd.type), buf1, - new Identifier(fd.toPrettyChars()), hgs, null); + hgs.functionSignatureToBuffer(cast(TypeFunction)(fd.type), buf1, + new Identifier(fd.toPrettyChars()), null); error(funcdecl.loc, "function `%s` does not override any function, did you mean to override `%s`?", funcdeclToChars, buf1.peekChars()); @@ -1807,7 +1807,7 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration)) HdrGenState hgs; hgs.skipConstraints = true; hgs.showOneMember = !recurse; - toCharsMaybeConstraints(td, buf, hgs); + hgs.toCharsMaybeConstraints(td, buf); const tmsg = buf.peekChars(); const cmsg = child ? null : td.getConstraintEvalError(constraintsTip); diff --git a/compiler/src/dmd/hdrgen.d b/compiler/src/dmd/hdrgen.d index 1e72cf709c66..e1407191bce3 100644 --- a/compiler/src/dmd/hdrgen.d +++ b/compiler/src/dmd/hdrgen.d @@ -53,4451 +53,5104 @@ import dmd.tokens; import dmd.typesem; import dmd.visitor; -struct HdrGenState -{ - bool hdrgen; /// true if generating header file - bool ddoc; /// true if generating Ddoc file - bool fullDump; /// true if generating a full AST dump file - bool importcHdr; /// true if generating a .di file from an ImportC file - bool doFuncBodies; /// include function bodies in output - bool vcg_ast; /// write out codegen-ast - bool skipConstraints; // skip constraints when doing templates - bool showOneMember = true; +/** + Print the visibility of a symbol to a buffer. - bool fullQual; /// fully qualify types when printing - int tpltMember; - int autoMember; - int forStmtInit; - int insideFuncBody; - int insideAggregate; + Params: + buf = the buffer. + vis = the visibility. +*/ +void visibilityToBuffer(ref OutBuffer buf, Visibility vis) +{ + buf.writestring(visibilityToString(vis.kind)); - bool declstring; // set while declaring alias for string,wstring or dstring - EnumDeclaration inEnumDecl; + if (vis.kind == Visibility.Kind.package_ && vis.pkg) + { + buf.writeByte('('); + buf.writestring(vis.pkg.toPrettyChars(true)); + buf.writeByte(')'); + } } -enum TEST_EMIT_ALL = 0; +/** + Map a visibility to its kind as a string. -/**************************************** - * Generate a header (.di) file for Module m. - * Params: - * m = Module to generate header for - * doFuncBodies = generate function definitions rather than just declarations - * buf = buffer to write the data to - */ -void genhdrfile(Module m, bool doFuncBodies, ref OutBuffer buf) + Params: + kind = the visibility kind to map. + + Returns: A string representing the visibility kind. +*/ +string visibilityToString(Visibility.Kind kind) pure nothrow @nogc @safe { - buf.doindent = 1; - buf.printf("// D import file generated from '%s'", m.srcfile.toChars()); - buf.writenl(); - HdrGenState hgs; - hgs.hdrgen = true; - hgs.importcHdr = (m.filetype == FileType.c); - hgs.doFuncBodies = doFuncBodies; - toCBuffer(m, buf, hgs); + return TableOfVisibilityStrings[kind]; } -/*************************************** - * Turn a Statement into a string suitable for printf. - * Leaks memory. - * Params: - * s = Statement to convert - * Returns: - * 0-terminated string +/** + Map a visibility to its kind as a zero terminated string. + + Params: + kind = the visibility kind to map. + + Returns: A zero terminated string that represents a visibility kind. */ -public const(char)* toChars(const Statement s) +const(char)* visibilityToChars(Visibility.Kind kind) pure nothrow @nogc @trusted { - HdrGenState hgs; - OutBuffer buf; - toCBuffer(s, buf, hgs); - buf.writeByte(0); - return buf.extractSlice().ptr; + // Null terminated because we return a literal + return TableOfVisibilityStrings[kind].ptr; } -public const(char)* toChars(const Expression e) -{ - HdrGenState hgs; - OutBuffer buf; - toCBuffer(e, buf, hgs); - return buf.extractChars(); -} +/** + Map a linkage as a string. + + Params: + linkage = the linkage to map. -public const(char)* toChars(const Initializer i) + Returns: A string representing the linkage type. +*/ +string linkageToString(LINK linkage) pure nothrow @nogc @safe { - OutBuffer buf; - HdrGenState hgs; - toCBuffer(i, buf, hgs); - return buf.extractChars(); + return TableOfLinkageStrings[linkage]; } -public const(char)* toChars(const Type t) -{ - OutBuffer buf; - buf.reserve(16); - HdrGenState hgs; - hgs.fullQual = (t.ty == Tclass && !t.mod); +/** + Map a linkage as a zero terminated string. - toCBuffer(t, buf, null, hgs); - return buf.extractChars(); -} + Params: + linkage = the linkage to map. -public const(char)[] toString(const Initializer i) + Returns: A zero terminated string representing the linkage type. + */ +const(char)* linkageToChars(LINK linkage) pure nothrow @nogc @trusted { - OutBuffer buf; - HdrGenState hgs; - toCBuffer(i, buf, hgs); - return buf.extractSlice(); + return TableOfLinkageStrings[linkage].ptr; } /** - * Dumps the full contents of module `m` to `buf`. - * Params: - * buf = buffer to write to. - * vcg_ast = write out codegen ast - * m = module to visit all members of. - */ -void moduleToBuffer(ref OutBuffer buf, bool vcg_ast, Module m) +Convert an expression type to string. + +Params: + op = The expression type. + +Returns: The string representation of an expression type. +*/ +string expressionTypeToString(EXP op) { - HdrGenState hgs; - hgs.fullDump = true; - hgs.vcg_ast = vcg_ast; - toCBuffer(m, buf, hgs); + return TableOfExpressionTypeStrings[op]; } -void moduleToBuffer2(Module m, ref OutBuffer buf, ref HdrGenState hgs) +/** +Find the first active storage class, remove it and return its string representation. + +Params: + stc = A set of storage classes to look in and mutate. + +Returns: The string representation of the first storage class or null if none are active. +*/ +string storageClassToString(ref StorageClass stc) @safe { - if (m.md) + if (stc > 0) { - if (m.userAttribDecl) - { - buf.writestring("@("); - argsToBuffer(m.userAttribDecl.atts, buf, hgs); - buf.writeByte(')'); - buf.writenl(); - } - if (m.md.isdeprecated) + foreach (immutable ref entry; TableOfStorageClassStrings) { - if (m.md.msg) + const StorageClass tbl = entry.stc; + assert(tbl & STC.visibleStorageClasses); + + if (stc & tbl) { - buf.writestring("deprecated("); - m.md.msg.expressionToBuffer(buf, hgs); - buf.writestring(") "); + stc &= ~tbl; + return entry.id; } - else - buf.writestring("deprecated "); } - buf.writestring("module "); - buf.writestring(m.md.toChars()); - buf.writeByte(';'); - buf.writenl(); } - foreach (s; *m.members) - { - s.dsymbolToBuffer(buf, hgs); - } + return null; } -private void statementToBuffer(Statement s, ref OutBuffer buf, ref HdrGenState hgs) +/** +Write storage classes to a buffer. + +Takes into account scope and return ordering. + +Params: + buf = The buffer to write into. + stc = The storage classes. + +Returns: +*/ +bool storageClassToBuffer(ref OutBuffer buf, StorageClass stc) @safe { - void visitDefaultCase(Statement s) - { - printf("Statement::toCBuffer() %d\n", s.stmt); - assert(0, "unrecognized statement in statementToBuffer()"); - } + //printf("stc: %llx\n", stc); + bool result = false; - void visitError(ErrorStatement s) + if (stc & STC.scopeinferred) { - buf.writestring("__error__"); - buf.writenl(); + stc &= ~(STC.scope_ | STC.scopeinferred); } - - void visitExp(ExpStatement s) + if (stc & STC.returninferred) { - if (s.exp && s.exp.op == EXP.declaration && - (cast(DeclarationExp)s.exp).declaration) - { - // bypass visit(DeclarationExp) - (cast(DeclarationExp)s.exp).declaration.dsymbolToBuffer(buf, hgs); - return; - } - if (s.exp) - s.exp.expressionToBuffer(buf, hgs); - buf.writeByte(';'); - if (!hgs.forStmtInit) - buf.writenl(); + stc &= ~(STC.return_ | STC.returninferred); } - void visitDtorExp(DtorExpStatement s) - { - visitExp(s); - } + // Put scope ref return into a standard order + string rrs; + const isout = (stc & STC.out_) != 0; + //printf("bsr = %d %llx\n", buildScopeRef(stc), stc); - void visitMixin(MixinStatement s) + final switch (buildScopeRef(stc)) { - buf.writestring("mixin("); - argsToBuffer(s.exps, buf, hgs, null); - buf.writestring(");"); - if (!hgs.forStmtInit) - buf.writenl(); + case ScopeRef.None, ScopeRef.Scope, ScopeRef.Ref, ScopeRef.Return: + break; + + case ScopeRef.ReturnScope: + rrs = "return scope"; + goto L1; + case ScopeRef.ReturnRef: + rrs = isout ? "return out" : "return ref"; + goto L1; + case ScopeRef.RefScope: + rrs = isout ? "out scope" : "ref scope"; + goto L1; + case ScopeRef.ReturnRef_Scope: + rrs = isout ? "return out scope" : "return ref scope"; + goto L1; + case ScopeRef.Ref_ReturnScope: + rrs = isout ? "out return scope" : "ref return scope"; + + L1: + stc &= ~(STC.out_ | STC.scope_ | STC.ref_ | STC.return_); + + buf.writestring(rrs); + result = true; + break; } - void visitCompound(CompoundStatement s) + string storageClassText; + while ((storageClassText = storageClassToString(stc)) !is null) { - foreach (sx; *s.statements) - { - if (sx) - sx.statementToBuffer(buf, hgs); - } - } + if (result) + buf.writeByte(' '); - void visitCompoundAsm(CompoundAsmStatement s) - { - visitCompound(s); + buf.writestring(storageClassText); + result = true; } - void visitCompoundDeclaration(CompoundDeclarationStatement s) - { - bool anywritten = false; - foreach (sx; *s.statements) - { - auto ds = sx ? sx.isExpStatement() : null; - if (ds && ds.exp.isDeclarationExp()) - { - auto d = ds.exp.isDeclarationExp().declaration; - if (auto v = d.isVarDeclaration()) - { - visitVarDecl(v, anywritten, buf, hgs); - } - else - d.dsymbolToBuffer(buf, hgs); - anywritten = true; - } - } - buf.writeByte(';'); - if (!hgs.forStmtInit) - buf.writenl(); - } + return result; +} - void visitUnrolledLoop(UnrolledLoopStatement s) - { - buf.writestring("/*unrolled*/ {"); - buf.writenl(); - buf.level++; - foreach (sx; *s.statements) - { - if (sx) - sx.statementToBuffer(buf, hgs); - } - buf.level--; - buf.writeByte('}'); - buf.writenl(); - } +/** +Formats `value` as a literal of type `type` into `buf`. + + Params: + type = literal type (e.g. Tfloat) + value = value to print + buf = target buffer + allowHex = whether hex floating point literals may be used + for greater accuracy +*/ +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". + // (ie, 8 chars more than mantissa). Plus one for trailing \0. + // Plus one for rounding. + const(size_t) BUFFER_LEN = value.sizeof * 3 + 8 + 1 + 1; + char[BUFFER_LEN] buffer = void; - void visitScope(ScopeStatement s) - { - buf.writeByte('{'); - buf.writenl(); - buf.level++; - if (s.statement) - s.statement.statementToBuffer(buf, hgs); - buf.level--; - buf.writeByte('}'); - buf.writenl(); - } + CTFloat.sprint(buffer.ptr, BUFFER_LEN, 'g', value); + assert(strlen(buffer.ptr) < BUFFER_LEN); - void visitWhile(WhileStatement s) + if (allowHex) { - buf.writestring("while ("); - if (auto p = s.param) - { - // Print condition assignment - StorageClass stc = p.storageClass; - if (!p.type && !stc) - stc = STC.auto_; - if (stcToBuffer(buf, stc)) - buf.writeByte(' '); - if (p.type) - typeToBuffer(p.type, p.ident, buf, hgs); - else - buf.writestring(p.ident.toString()); - buf.writestring(" = "); - } - s.condition.expressionToBuffer(buf, hgs); - buf.writeByte(')'); - buf.writenl(); - if (s._body) - s._body.statementToBuffer(buf, hgs); + bool isOutOfRange; + real_t r = CTFloat.parse(buffer.ptr, isOutOfRange); + //assert(!isOutOfRange); // test/compilable/test22725.c asserts here + if (r != value) // if exact duplication + CTFloat.sprint(buffer.ptr, BUFFER_LEN, 'a', value); } - void visitDo(DoStatement s) - { - buf.writestring("do"); - buf.writenl(); - if (s._body) - s._body.statementToBuffer(buf, hgs); - buf.writestring("while ("); - s.condition.expressionToBuffer(buf, hgs); - buf.writestring(");"); - buf.writenl(); - } + buf.writestring(buffer.ptr); + if (buffer.ptr[strlen(buffer.ptr) - 1] == '.') + buf.remove(buf.length() - 1, 1); - void visitFor(ForStatement s) + if (type) { - buf.writestring("for ("); - if (s._init) - { - hgs.forStmtInit++; - s._init.statementToBuffer(buf, hgs); - hgs.forStmtInit--; - } - else - buf.writeByte(';'); - if (s.condition) - { - buf.writeByte(' '); - s.condition.expressionToBuffer(buf, hgs); - } - buf.writeByte(';'); - if (s.increment) - { - buf.writeByte(' '); - s.increment.expressionToBuffer(buf, hgs); - } - buf.writeByte(')'); - buf.writenl(); - buf.writeByte('{'); - buf.writenl(); - buf.level++; - if (s._body) - s._body.statementToBuffer(buf, hgs); - buf.level--; - buf.writeByte('}'); - buf.writenl(); - } + Type t = type.toBasetype(); - void foreachWithoutBody(ForeachStatement s) - { - buf.writestring(Token.toString(s.op)); - buf.writestring(" ("); - foreach (i, p; *s.parameters) + switch (t.ty) { - if (i) - buf.writestring(", "); - if (stcToBuffer(buf, p.storageClass)) - buf.writeByte(' '); - if (p.type) - typeToBuffer(p.type, p.ident, buf, hgs); - else - buf.writestring(p.ident.toString()); + case Tfloat32, Timaginary32, Tcomplex32: + buf.writeByte('F'); + break; + case Tfloat80, Timaginary80, Tcomplex80: + buf.writeByte('L'); + break; + default: + break; } - buf.writestring("; "); - s.aggr.expressionToBuffer(buf, hgs); - buf.writeByte(')'); - buf.writenl(); - } - void visitForeach(ForeachStatement s) - { - foreachWithoutBody(s); - buf.writeByte('{'); - buf.writenl(); - buf.level++; - if (s._body) - s._body.statementToBuffer(buf, hgs); - buf.level--; - buf.writeByte('}'); - buf.writenl(); + if (t.isimaginary()) + buf.writeByte('i'); } +} - void foreachRangeWithoutBody(ForeachRangeStatement s) - { - buf.writestring(Token.toString(s.op)); - buf.writestring(" ("); - if (s.prm.type) - typeToBuffer(s.prm.type, s.prm.ident, buf, hgs); - else - buf.writestring(s.prm.ident.toString()); - buf.writestring("; "); - s.lwr.expressionToBuffer(buf, hgs); - buf.writestring(" .. "); - s.upr.expressionToBuffer(buf, hgs); - buf.writeByte(')'); - buf.writenl(); - } +/** + Turn an AST node into a string suitable for printf. + Leaks memory. + + Params: + node = AST node to convert + Returns: 0-terminated string +*/ +const(char)* toChars(const Statement node) +{ + HdrGenState hgs; + OutBuffer buf; - void visitForeachRange(ForeachRangeStatement s) - { - foreachRangeWithoutBody(s); - buf.writeByte('{'); - buf.writenl(); - buf.level++; - if (s._body) - s._body.statementToBuffer(buf, hgs); - buf.level--; - buf.writeByte('}'); - buf.writenl(); - } + hgs.toCBuffer(node, buf); - void visitStaticForeach(StaticForeachStatement s) - { - buf.writestring("static "); - if (s.sfe.aggrfe) - { - visitForeach(s.sfe.aggrfe); - } - else - { - assert(s.sfe.rangefe); - visitForeachRange(s.sfe.rangefe); - } - } + return buf.extractChars(); +} - void visitForwarding(ForwardingStatement s) - { - s.statement.statementToBuffer(buf, hgs); - } +/// Ditto +const(char)* toChars(const Expression node) +{ + HdrGenState hgs; + OutBuffer buf; - void visitIf(IfStatement s) - { - buf.writestring("if ("); - if (Parameter p = s.prm) - { - StorageClass stc = p.storageClass; - if (!p.type && !stc) - stc = STC.auto_; - if (stcToBuffer(buf, stc)) - buf.writeByte(' '); - if (p.type) - typeToBuffer(p.type, p.ident, buf, hgs); - else - buf.writestring(p.ident.toString()); - buf.writestring(" = "); - } - s.condition.expressionToBuffer(buf, hgs); - buf.writeByte(')'); - buf.writenl(); - if (s.ifbody.isScopeStatement()) + hgs.toCBuffer(node, buf); + + return buf.extractChars(); +} + +/// Ditto +const(char)* toChars(const Initializer node) +{ + HdrGenState hgs; + OutBuffer buf; + + hgs.toCBuffer(node, buf); + + return buf.extractChars(); +} + +/// Ditto +const(char)* toChars(const Type node) +{ + + HdrGenState hgs; + hgs.fullQual = (node.ty == Tclass && !node.mod); + + OutBuffer buf; + hgs.toCBuffer(node, buf, null); + + return buf.extractChars(); +} + +/** + Turn an AST node into a string suitable. + Leaks memory. + + Params: + node = AST node to convert + Returns: A string. +*/ +const(char)[] toString(const Initializer node) +{ + OutBuffer buf; + HdrGenState hgs; + hgs.toCBuffer(node, buf); + return buf.extractSlice(); +} + +/** + Write a template instance, template arguments out to buffer. + + Params: + ti = The template instance which contains template arguments. + buf = The buffer to write into. + qualifyTypes = Should type names be fully qualified? +*/ +void toCBufferInstance(const TemplateInstance ti, ref OutBuffer buf, bool qualifyTypes = false) +{ + HdrGenState hgs; + hgs.fullQual = qualifyTypes; + + buf.writestring(ti.name.toChars()); + hgs.tiargsToBuffer(cast() ti, buf); +} + +/** + Dumps the full contents of module `m` to `buf`. + Params: + buf = buffer to write to. + vcg_ast = write out codegen ast + m = module to visit all members of. +*/ +void moduleToBuffer(ref OutBuffer buf, bool vcg_ast, Module m) +{ + HdrGenState hgs; + hgs.fullDump = true; + hgs.vcg_ast = vcg_ast; + hgs.toCBuffer(m, buf); +} + +/** + Genearate the contents of a D header file. + + Params: + m = The module to generate for. + doFuncBodies = Will it include function bodies? + buf = The output buffer. +*/ +void genhdrfile(Module m, bool doFuncBodies, ref OutBuffer buf) +{ + buf.doindent = 1; + buf.printf("// D import file generated from '%s'", m.srcfile.toChars()); + buf.writenl(); + HdrGenState hgs; + hgs.hdrgen = true; + hgs.importcHdr = (m.filetype == FileType.c); + hgs.doFuncBodies = doFuncBodies; + hgs.toCBuffer(m, buf); +} + +/** + Pretty print function parameters. + + Params: + pl = parameter list to print + + Returns: Null-terminated string representing parameters. + */ +const(char)* parametersTypeToChars(ParameterList pl) +{ + OutBuffer buf; + HdrGenState hgs; + hgs.parametersToBuffer(pl, buf); + return buf.extractChars(); +} + +/** + Write out argument types to buffer. + + Params: + buf = The buffer to write into. + arguments = the expressions to acquire the types of from. +*/ +void argExpTypesToCBuffer(ref OutBuffer buf, Expressions* arguments) +{ + if (!arguments || !arguments.length) + return; + + HdrGenState hgs; + + foreach (i, arg; *arguments) + { + if (i) + buf.writestring(", "); + hgs.typeToBuffer(arg.type, null, buf); + } +} + +/** + Write out an array of objects to buffer. + + Params: + buf = The buffer to write into. + objects = the objects to write. +*/ +void arrayObjectsToBuffer(ref OutBuffer buf, Objects* objects) +{ + if (!objects || !objects.length) + return; + + HdrGenState hgs; + + foreach (i, o; *objects) + { + if (i) + buf.writestring(", "); + + hgs.objectToBuffer(o, buf); + } +} + +/** + Pretty print function parameter. + + Params: + parameter = parameter to print. + tf = TypeFunction which holds parameter. + fullQual = whether to fully qualify types. + + Returns: Null-terminated string representing parameters. +*/ +const(char)* parameterToChars(Parameter parameter, TypeFunction tf, bool fullQual) +{ + OutBuffer buf; + HdrGenState hgs; + hgs.fullQual = fullQual; + + hgs.parameterToBuffer(parameter, buf); + + if (tf.parameterList.varargs == VarArg.typesafe + && parameter == tf.parameterList[tf.parameterList.parameters.length - 1]) + { + buf.writestring("..."); + } + + return buf.extractChars(); +} + +struct HdrGenState +{ + bool hdrgen; /// true if generating header file + bool ddoc; /// true if generating Ddoc file + bool fullDump; /// true if generating a full AST dump file + bool importcHdr; /// true if generating a .di file from an ImportC file + bool doFuncBodies; /// include function bodies in output + bool vcg_ast; /// write out codegen-ast + bool skipConstraints; // skip constraints when doing templates + bool showOneMember = true; + + bool fullQual; /// fully qualify types when printing + int tpltMember; + int autoMember; + int forStmtInit; + int insideFuncBody; + int insideAggregate; + + bool declstring; // set while declaring alias for string,wstring or dstring + EnumDeclaration inEnumDecl; + + /** + Emit a function signature a buffer, using correct identifier, attributes and template arguments. + + Params: + tf = A function that has semantic information attached to it. + buf = The buffer to write into. + ident = The function's identifier. + td = The template declaration. + */ + void functionSignatureToBuffer(TypeFunction tf, ref OutBuffer buf, + const Identifier ident, TemplateDeclaration td) + { + if (tf.inuse) { - s.ifbody.statementToBuffer(buf, hgs); + tf.inuse = 2; // flag error to caller + return; } - else + + tf.inuse++; + scope (exit) + tf.inuse--; + { - buf.level++; - s.ifbody.statementToBuffer(buf, hgs); - buf.level--; + // emit prefix attributes/linkage + + if (tf.linkage > LINK.d && this.ddoc != 1 && !this.hdrgen) + { + linkageToBuffer(buf, tf.linkage); + buf.writeByte(' '); + } + + void prefixWriteAttribute(string str) + { + if (str == "ref") + { + if (ident == Id.ctor) + return; + } + else if (str != "@property") + return; + + buf.writestring(str); + buf.writeByte(' '); + } + + tf.attributesApply(&prefixWriteAttribute); } - if (s.elsebody) + { - buf.writestring("else"); - if (!s.elsebody.isIfStatement()) + // emit the return type + + if (ident && ident.toHChars2() != ident.toChars()) { - buf.writenl(); + // Don't print return type for ctor, dtor, unittest, etc } - else + else if (tf.next) { - buf.writeByte(' '); + typeToBuffer(tf.next, null, buf); + if (ident) + buf.writeByte(' '); } - if (s.elsebody.isScopeStatement() || s.elsebody.isIfStatement()) + else if (this.ddoc) { - s.elsebody.statementToBuffer(buf, hgs); + buf.writestring("auto "); } - else + } + + if (ident) + buf.writestring(ident.toHChars2()); + + { + // emit the parameters + + // template parameters + if (td) { - buf.level++; - s.elsebody.statementToBuffer(buf, hgs); - buf.level--; + buf.writeByte('('); + foreach (i, p; *td.origParameters) + { + if (i) + buf.writestring(", "); + + toCBuffer(p, buf); + } + buf.writeByte(')'); } + + if (ident !is Id.postblit) + parametersToBuffer(tf.parameterList, buf); } - } - void visitConditional(ConditionalStatement s) - { - s.condition.conditionToBuffer(buf, hgs); - buf.writenl(); - buf.writeByte('{'); - buf.writenl(); - buf.level++; - if (s.ifbody) - s.ifbody.statementToBuffer(buf, hgs); - buf.level--; - buf.writeByte('}'); - buf.writenl(); - if (s.elsebody) { - buf.writestring("else"); - buf.writenl(); - buf.writeByte('{'); - buf.level++; - buf.writenl(); - s.elsebody.statementToBuffer(buf, hgs); - buf.level--; - buf.writeByte('}'); + // Postfix storage classes & attributes + + if (tf.mod) + { + buf.writeByte(' '); + MODtoBuffer(buf, tf.mod); + } + + void postfixWriteAttribute(string str) + { + if (str != "ref" && str != "@property") + { + buf.writeByte(' '); + buf.writestring(str); + } + } + + tf.attributesApply(&postfixWriteAttribute); } - buf.writenl(); } - void visitPragma(PragmaStatement s) + /** + Emit a function signature a buffer, using correct identifier, attributes with knowledge of if it is static. + + Params: + tf = A function that has semantic information attached to it. + buf = The buffer to write into. + ident = The function's identifier. + isStatic = Is the function static? + */ + void functionSignatureToBufferAsPostfix(TypeFunction t, ref OutBuffer buf, + const char[] ident, bool isStatic) { - buf.writestring("pragma ("); - buf.writestring(s.ident.toString()); - if (s.args && s.args.length) + if (t.inuse) { - buf.writestring(", "); - argsToBuffer(s.args, buf, hgs); + t.inuse = 2; // flag error to caller + return; } - buf.writeByte(')'); - if (s._body) + + t.inuse++; + scope (exit) + t.inuse--; + + if (t.linkage > LINK.d && this.ddoc != 1 && !this.hdrgen) { - buf.writenl(); - buf.writeByte('{'); - buf.writenl(); - buf.level++; - s._body.statementToBuffer(buf, hgs); - buf.level--; - buf.writeByte('}'); - buf.writenl(); + linkageToBuffer(buf, t.linkage); + buf.writeByte(' '); } - else + + if (t.linkage == LINK.objc && isStatic) + buf.write("static "); + { - buf.writeByte(';'); - buf.writenl(); + // emit the return type + + if (t.next) + { + typeToBuffer(t.next, null, buf); + if (ident) + buf.writeByte(' '); + } + else if (this.ddoc) + buf.writestring("auto "); } - } - void visitStaticAssert(StaticAssertStatement s) - { - s.sa.dsymbolToBuffer(buf, hgs); - } + if (ident) + buf.writestring(ident); + + parametersToBuffer(t.parameterList, buf); - void visitSwitch(SwitchStatement s) - { - buf.writestring(s.isFinal ? "final switch (" : "switch ("); - if (auto p = s.param) - { - // Print condition assignment - StorageClass stc = p.storageClass; - if (!p.type && !stc) - stc = STC.auto_; - if (stcToBuffer(buf, stc)) - buf.writeByte(' '); - if (p.type) - typeToBuffer(p.type, p.ident, buf, hgs); - else - buf.writestring(p.ident.toString()); - buf.writestring(" = "); - } - s.condition.expressionToBuffer(buf, hgs); - buf.writeByte(')'); - buf.writenl(); - if (s._body) { - if (!s._body.isScopeStatement()) + // Use postfix style for attributes + if (t.mod) { - buf.writeByte('{'); - buf.writenl(); - buf.level++; - s._body.statementToBuffer(buf, hgs); - buf.level--; - buf.writeByte('}'); - buf.writenl(); + buf.writeByte(' '); + MODtoBuffer(buf, t.mod); } - else + + void dg(string str) { - s._body.statementToBuffer(buf, hgs); + buf.writeByte(' '); + buf.writestring(str); } + + t.attributesApply(&dg); } } - void visitCase(CaseStatement s) + void toCBuffer(const TemplateParameter tp, ref OutBuffer buf) { - buf.writestring("case "); - s.exp.expressionToBuffer(buf, hgs); - buf.writeByte(':'); - buf.writenl(); - s.statement.statementToBuffer(buf, hgs); + scope v = new TemplateParameterPrettyPrintVisitor; + v.buf = &buf; + v.hgs = &this; + + (cast() tp).accept(v); } - void visitCaseRange(CaseRangeStatement s) + void toCBuffer(const Type t, ref OutBuffer buf, const Identifier ident) { - buf.writestring("case "); - s.first.expressionToBuffer(buf, hgs); - buf.writestring(": .. case "); - s.last.expressionToBuffer(buf, hgs); - buf.writeByte(':'); - buf.writenl(); - s.statement.statementToBuffer(buf, hgs); + typeToBuffer(cast() t, ident, buf); } - void visitDefault(DefaultStatement s) + void toCBuffer(const Expression e, ref OutBuffer buf) { - buf.writestring("default:"); - buf.writenl(); - s.statement.statementToBuffer(buf, hgs); + expressionPrettyPrint(cast() e, buf); } - void visitGotoDefault(GotoDefaultStatement s) + void toCBuffer(Dsymbol s, ref OutBuffer buf) { - buf.writestring("goto default;"); - buf.writenl(); + scope v = new DsymbolPrettyPrintVisitor(); + v.hgs = &this; + v.buf = &buf; + + /+if (s.getModule !is null) + v.doTrace = s.getModule.ident.toString == "builder_utf8" + || s.getModule.ident.toString == "testhdrgen";+/ + s.accept(v); } - void visitGotoCase(GotoCaseStatement s) + // Note: this function is not actually `const`, because iterating the + // function parameter list may run dsymbolsemantic on enum types + void toCharsMaybeConstraints(const TemplateDeclaration td, ref OutBuffer buf) { - buf.writestring("goto case"); - if (s.exp) - { - buf.writeByte(' '); - s.exp.expressionToBuffer(buf, hgs); - } - buf.writeByte(';'); - buf.writenl(); - } - - void visitSwitchError(SwitchErrorStatement s) - { - buf.writestring("SwitchErrorStatement::toCBuffer()"); - buf.writenl(); - } - - void visitReturn(ReturnStatement s) - { - buf.writestring("return "); - if (s.exp) - s.exp.expressionToBuffer(buf, hgs); - buf.writeByte(';'); - buf.writenl(); - } + buf.writestring(td.ident == Id.ctor ? "this" : td.ident.toString()); + buf.writeByte('('); - void visitBreak(BreakStatement s) - { - buf.writestring("break"); - if (s.ident) + foreach (i, const tp; *td.parameters) { - buf.writeByte(' '); - buf.writestring(s.ident.toString()); + if (i) + buf.writestring(", "); + toCBuffer(tp, buf); } - buf.writeByte(';'); - buf.writenl(); - } + buf.writeByte(')'); - void visitContinue(ContinueStatement s) - { - buf.writestring("continue"); - if (s.ident) + if (this.showOneMember && td.onemember) { - buf.writeByte(' '); - buf.writestring(s.ident.toString()); + if (const fd = td.onemember.isFuncDeclaration()) + { + if (TypeFunction tf = cast(TypeFunction) fd.type.isTypeFunction()) + { + // !! Casted away const + buf.writestring(parametersTypeToChars(tf.parameterList)); + + if (tf.mod) + { + buf.writeByte(' '); + buf.MODtoBuffer(tf.mod); + } + } + } } - buf.writeByte(';'); - buf.writenl(); - } - void visitSynchronized(SynchronizedStatement s) - { - buf.writestring("synchronized"); - if (s.exp) + if (!this.skipConstraints && td.constraint) { - buf.writeByte('('); - s.exp.expressionToBuffer(buf, hgs); + buf.writestring(" if ("); + toCBuffer(td.constraint, buf); buf.writeByte(')'); } - if (s._body) - { - buf.writeByte(' '); - s._body.statementToBuffer(buf, hgs); - } } - void visitWith(WithStatement s) - { - buf.writestring("with ("); - s.exp.expressionToBuffer(buf, hgs); - buf.writestring(")"); - buf.writenl(); - if (s._body) - s._body.statementToBuffer(buf, hgs); - } + /** + Dumps the full contents of module `m` to `buf`. - void visitTryCatch(TryCatchStatement s) + Params: + buf = buffer to write to. + m = module to visit all members of. + */ + void moduleToBuffer2(Module m, ref OutBuffer buf) { - buf.writestring("try"); - buf.writenl(); - if (s._body) + if (m.md) { - if (s._body.isScopeStatement()) - { - s._body.statementToBuffer(buf, hgs); - } - else + if (m.userAttribDecl) { - buf.level++; - s._body.statementToBuffer(buf, hgs); - buf.level--; + buf.writestring("@("); + argsToBuffer(m.userAttribDecl.atts, buf); + buf.writeByte(')'); + buf.writenl(); } - } - foreach (c; *s.catches) - { - buf.writestring("catch"); - if (c.type) + if (m.md.isdeprecated) { - buf.writeByte('('); - typeToBuffer(c.type, c.ident, buf, hgs); - buf.writeByte(')'); + if (m.md.msg) + { + buf.writestring("deprecated("); + expressionPrettyPrint(m.md.msg, buf); + buf.writestring(") "); + } + else + buf.writestring("deprecated "); } - buf.writenl(); - buf.writeByte('{'); - buf.writenl(); - buf.level++; - if (c.handler) - c.handler.statementToBuffer(buf, hgs); - buf.level--; - buf.writeByte('}'); + buf.writestring("module "); + buf.writestring(m.md.toChars()); + buf.writeByte(';'); buf.writenl(); } - } - void visitTryFinally(TryFinallyStatement s) - { - buf.writestring("try"); - buf.writenl(); - buf.writeByte('{'); - buf.writenl(); - buf.level++; - s._body.statementToBuffer(buf, hgs); - buf.level--; - buf.writeByte('}'); - buf.writenl(); - buf.writestring("finally"); - buf.writenl(); - if (s.finalbody.isScopeStatement()) - { - s.finalbody.statementToBuffer(buf, hgs); - } - else + foreach (s; *m.members) { - buf.level++; - s.finalbody.statementToBuffer(buf, hgs); - buf.level--; + toCBuffer(s, buf); } } - void visitScopeGuard(ScopeGuardStatement s) +private: + + int childCountOfModule; + + // not used outside this module + void toCBuffer(const Initializer iz, ref OutBuffer buf) { - buf.writestring(Token.toString(s.tok)); - buf.writeByte(' '); - if (s.statement) - s.statement.statementToBuffer(buf, hgs); + initializerToBuffer(cast() iz, buf); } - void visitThrow(ThrowStatement s) + // not used outside this module + void toCBuffer(const Statement s, ref OutBuffer buf) { - buf.writestring("throw "); - s.exp.expressionToBuffer(buf, hgs); - buf.writeByte(';'); - buf.writenl(); + statementToBuffer(cast() s, buf); } - void visitDebug(DebugStatement s) + void typeToBuffer(Type t, const Identifier ident, ref OutBuffer buf, ubyte modMask = 0) { - if (s.statement) + if (auto tf = t.isTypeFunction()) { - s.statement.statementToBuffer(buf, hgs); + functionSignatureToBuffer(tf, buf, ident, null); + return; } - } - void visitGoto(GotoStatement s) - { - buf.writestring("goto "); - buf.writestring(s.ident.toString()); - buf.writeByte(';'); - buf.writenl(); - } + visitWithMask(t, modMask, buf); - void visitLabel(LabelStatement s) - { - buf.writestring(s.ident.toString()); - buf.writeByte(':'); - buf.writenl(); - if (s.statement) - s.statement.statementToBuffer(buf, hgs); + if (ident) + { + buf.writeByte(' '); + buf.writestring(ident.toString()); + } } - void visitAsm(AsmStatement s) + void visitWithMask(Type t, ubyte modMask, ref OutBuffer buf) { - buf.writestring("asm { "); - Token* t = s.tokens; - buf.level++; - while (t) - { - buf.writestring(t.toString()); - if (t.next && - t.value != TOK.min && - t.value != TOK.comma && t.next.value != TOK.comma && - t.value != TOK.leftBracket && t.next.value != TOK.leftBracket && - t.next.value != TOK.rightBracket && - t.value != TOK.leftParenthesis && t.next.value != TOK.leftParenthesis && - t.next.value != TOK.rightParenthesis && - t.value != TOK.dot && t.next.value != TOK.dot) + // Tuples and functions don't use the type constructor syntax + if (modMask == t.mod || t.ty == Tfunction || t.ty == Ttuple) + { + typeToBufferx(t, buf); + } + else + { + ubyte m = t.mod & ~(t.mod & modMask); + if (m & MODFlags.shared_) { - buf.writeByte(' '); + MODtoBuffer(buf, MODFlags.shared_); + buf.writeByte('('); + } + if (m & MODFlags.wild) + { + MODtoBuffer(buf, MODFlags.wild); + buf.writeByte('('); + } + if (m & (MODFlags.const_ | MODFlags.immutable_)) + { + MODtoBuffer(buf, m & (MODFlags.const_ | MODFlags.immutable_)); + buf.writeByte('('); } - t = t.next; - } - buf.level--; - buf.writestring("; }"); - buf.writenl(); - } - void visitInlineAsm(InlineAsmStatement s) - { - visitAsm(s); - } + typeToBufferx(t, buf); - void visitGccAsm(GccAsmStatement s) - { - visitAsm(s); + if (m & (MODFlags.const_ | MODFlags.immutable_)) + buf.writeByte(')'); + if (m & MODFlags.wild) + buf.writeByte(')'); + if (m & MODFlags.shared_) + buf.writeByte(')'); + } } - void visitImport(ImportStatement s) + void parametersToBuffer(ParameterList pl, ref OutBuffer buf) { - foreach (imp; *s.imports) + buf.writeByte('('); + + foreach (i; 0 .. pl.length) { - imp.dsymbolToBuffer(buf, hgs); + if (i) + buf.writestring(", "); + + parameterToBuffer(pl[i], buf); } - } - mixin VisitStatement!void visit; - visit.VisitStatement(s); -} + final switch (pl.varargs) + { + case VarArg.none, VarArg.KRvariadic: + break; -private void dsymbolToBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) -{ - toCBuffer(s, buf, hgs); -} + case VarArg.variadic: + if (pl.length) + buf.writestring(", "); -void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) -{ - void visitDsymbol(Dsymbol s) - { - buf.writestring(s.toChars()); - } + if (storageClassToBuffer(buf, pl.stc)) + buf.writeByte(' '); - void visitStaticAssert(StaticAssert s) - { - buf.writestring(s.kind()); - buf.writeByte('('); - s.exp.expressionToBuffer(buf, hgs); - if (s.msgs) - { - foreach (m; (*s.msgs)[]) - { - buf.writestring(", "); - m.expressionToBuffer(buf, hgs); - } + goto case VarArg.typesafe; + + case VarArg.typesafe: + buf.writestring("..."); + break; } - buf.writestring(");"); - buf.writenl(); - } - void visitDebugSymbol(DebugSymbol s) - { - buf.writestring("debug = "); - if (s.ident) - buf.writestring(s.ident.toString()); - else - buf.print(s.level); - buf.writeByte(';'); - buf.writenl(); + buf.writeByte(')'); } - void visitVersionSymbol(VersionSymbol s) + void parameterToBuffer(Parameter p, ref OutBuffer buf) { - buf.writestring("version = "); - if (s.ident) - buf.writestring(s.ident.toString()); - else - buf.print(s.level); - buf.writeByte(';'); - buf.writenl(); - } + if (p.userAttribDecl) + { + buf.writeByte('@'); - void visitEnumMember(EnumMember em) - { - if (em.type) - typeToBuffer(em.type, em.ident, buf, hgs); - else - buf.writestring(em.ident.toString()); - if (em.value) + bool isAnonymous = p.userAttribDecl.atts.length > 0 + && !(*p.userAttribDecl.atts)[0].isCallExp(); + if (isAnonymous) + buf.writeByte('('); + + argsToBuffer(p.userAttribDecl.atts, buf); + + if (isAnonymous) + buf.writeByte(')'); + buf.writeByte(' '); + } + + if (p.storageClass & STC.auto_) + buf.writestring("auto "); + + StorageClass stc = p.storageClass; + if (p.storageClass & STC.in_) { - buf.writestring(" = "); - em.value.expressionToBuffer(buf, hgs); + buf.writestring("in "); + if ((p.storageClass & (STC.constscoperef | STC.ref_)) == (STC.constscoperef | STC.ref_)) + stc &= ~STC.ref_; } - } + else if (p.storageClass & STC.lazy_) + buf.writestring("lazy "); + else if (p.storageClass & STC.alias_) + buf.writestring("alias "); - void visitImport(Import imp) - { - if (hgs.hdrgen && imp.id == Id.object) - return; // object is imported by default - if (imp.isstatic) - buf.writestring("static "); - buf.writestring("import "); - if (imp.aliasId) + if (p.type && p.type.mod & MODFlags.shared_) + stc &= ~STC.shared_; + + if (storageClassToBuffer(buf, + stc & ( + STC.const_ | STC.immutable_ | STC.wild | STC.shared_ | STC.return_ + | STC.returninferred | STC.scope_ | STC.scopeinferred | STC.out_ + | STC.ref_ | STC.returnScope))) + buf.writeByte(' '); + + const(char)[] s; + if (p.storageClass & STC.alias_) { - buf.printf("%s = ", imp.aliasId.toChars()); + if (p.ident) + buf.writestring(p.ident.toString()); } - foreach (const pid; imp.packages) + else if (p.type.isTypeIdentifier() && (s = p.type.isTypeIdentifier() + .ident.toString()).length > 3 && s[0 .. 3] == "__T") { - buf.write(pid.toString()); - buf.writeByte('.'); + // print parameter name, instead of undetermined type parameter + buf.writestring(p.ident.toString()); } - buf.writestring(imp.id.toString()); - if (imp.names.length) + else { - buf.writestring(" : "); - foreach (const i, const name; imp.names) - { - if (i) - buf.writestring(", "); - const _alias = imp.aliases[i]; - if (_alias) - buf.printf("%s = %s", _alias.toChars(), name.toChars()); - else - buf.writestring(name.toChars()); - } + typeToBuffer(p.type, p.ident, buf, (stc & STC.in_) ? MODFlags.const_ : 0); } - buf.writeByte(';'); - buf.writenl(); - } - void visitAliasThis(AliasThis d) - { - buf.writestring("alias "); - buf.writestring(d.ident.toString()); - buf.writestring(" this;\n"); + if (p.defaultArg) + { + buf.writestring(" = "); + expToBuffer(p.defaultArg, PREC.assign, buf); + } } - void visitAttribDeclaration(AttribDeclaration d) + /* + Write expression out to buf, but wrap it + in ( ) if its precedence is less than pr. + */ + void expToBuffer(Expression e, PREC pr, ref OutBuffer buf) { - bool hasSTC; - if (auto stcd = d.isStorageClassDeclaration) + debug { - hasSTC = stcToBuffer(buf, stcd.stc); + if (precedence[e.op] == PREC.zero) + printf("precedence not defined for token '%s'\n", expressionTypeToString(e.op).ptr); } - if (!d.decl) + if (e.op == 0xFF) { - buf.writeByte(';'); - buf.writenl(); + buf.writestring(""); return; } - if (d.decl.length == 0 || (hgs.hdrgen && d.decl.length == 1 && (*d.decl)[0].isUnitTestDeclaration())) - { - // hack for https://issues.dlang.org/show_bug.cgi?id=8081 - if (hasSTC) buf.writeByte(' '); - buf.writestring("{}"); - } - else if (d.decl.length == 1) + + assert(precedence[e.op] != PREC.zero); + assert(pr != PREC.zero); + + // Despite precedence, we don't allow a= PREC.or && pr <= PREC.and && precedence[e.op] == PREC.rel)) { - if (hasSTC) buf.writeByte(' '); - toCBuffer((*d.decl)[0], buf, hgs); - return; + buf.writeByte('('); + expressionPrettyPrint(e, buf); + buf.writeByte(')'); } else { - buf.writenl(); - buf.writeByte('{'); - buf.writenl(); - buf.level++; - foreach (de; *d.decl) - toCBuffer(de, buf, hgs); - buf.level--; - buf.writeByte('}'); + expressionPrettyPrint(e, buf); } - buf.writenl(); } - void visitStorageClassDeclaration(StorageClassDeclaration d) - { - visitAttribDeclaration(d); - } + /** + Write out argument list to buf. - void visitDeprecatedDeclaration(DeprecatedDeclaration d) + Params: + expressions = argument list + buf = buffer to write to + hgs = context + 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 + */ + void argsToBuffer(Expressions* expressions, ref OutBuffer buf, + Expression basis = null, Identifiers* names = null) { - buf.writestring("deprecated("); - d.msg.expressionToBuffer(buf, hgs); - buf.writestring(") "); - visitAttribDeclaration(d); - } + if (!expressions || !expressions.length) + return; - void visitLinkDeclaration(LinkDeclaration d) - { - buf.writestring("extern ("); - buf.writestring(linkageToString(d.linkage)); - buf.writestring(") "); - visitAttribDeclaration(d); - } + version (all) + { + foreach (i, el; *expressions) + { + if (i) + buf.writestring(", "); - void visitCPPMangleDeclaration(CPPMangleDeclaration d) - { - string s; - final switch (d.cppmangle) + if (names && i < names.length && (*names)[i]) + { + buf.writestring((*names)[i].toString()); + buf.writestring(": "); + } + + if (!el) + el = basis; + + if (el) + expToBuffer(el, PREC.assign, buf); + } + } + else { - case CPPMANGLE.asClass: - s = "class"; - break; - case CPPMANGLE.asStruct: - s = "struct"; - break; - case CPPMANGLE.def: - break; + // Sparse style formatting, for debug use only + // [0..length: basis, 1: e1, 5: e5] + + if (basis) + { + buf.writestring("0.."); + buf.print(expressions.length); + buf.writestring(": "); + expToBuffer(basis, PREC.assign, buf); + } + + foreach (i, el; *expressions) + { + if (el) + { + if (basis) + { + buf.writestring(", "); + buf.print(i); + buf.writestring(": "); + } + else if (i) + buf.writestring(", "); + expToBuffer(el, PREC.assign, buf); + } + } } - buf.writestring("extern (C++, "); - buf.writestring(s); - buf.writestring(") "); - visitAttribDeclaration(d); } - void visitVisibilityDeclaration(VisibilityDeclaration d) - { - visibilityToBuffer(buf, d.visibility); - AttribDeclaration ad = cast(AttribDeclaration)d; - if (ad.decl.length <= 1) - buf.writeByte(' '); - if (ad.decl.length == 1 && (*ad.decl)[0].isVisibilityDeclaration) - visitAttribDeclaration((*ad.decl)[0].isVisibilityDeclaration); - else - visitAttribDeclaration(d); - } + /** + Print an expression to buffer. - void visitAlignDeclaration(AlignDeclaration d) + Params: + e = The expression. + buf = the output buffer. + */ + void expressionPrettyPrint(Expression e, ref OutBuffer buf) { - if (d.exps) + void visitInteger(IntegerExp e) { - foreach (i, exp; (*d.exps)[]) + const ulong v = e.toInteger(); + if (e.type) { - if (i) - buf.writeByte(' '); - buf.writestring("align ("); - toCBuffer(exp, buf, hgs); - buf.writeByte(')'); - } - if (d.decl && d.decl.length < 2) - buf.writeByte(' '); + Type t = e.type; + L1: + switch (t.ty) + { + case Tenum: + TypeEnum te = cast(TypeEnum) t; + auto sym = te.sym; + if (sym && sym.members && (!this.inEnumDecl || this.inEnumDecl != sym)) + { + foreach (em; *sym.members) + { + if ((cast(EnumMember) em).value.toInteger == v) + { + const id = em.ident.toString(); + buf.printf("%s.%.*s", sym.toChars(), cast(int) id.length, id.ptr); + return; + } + } + } + + buf.printf("cast(%s)", te.sym.toChars()); + t = te.sym.memtype; + goto L1; + case Tchar, Twchar, Tdchar: + { + const o = buf.length; + writeSingleCharLiteral(buf, cast(dchar) v); + + if (this.ddoc) + escapeDdocString(buf, o); + break; + } + case Tint8: + buf.writestring("cast(byte)"); + goto L2; + case Tint16: + buf.writestring("cast(short)"); + goto L2; + case Tint32: + L2: + buf.printf("%d", cast(int) v); + break; + case Tuns8: + buf.writestring("cast(ubyte)"); + goto case Tuns32; + case Tuns16: + buf.writestring("cast(ushort)"); + goto case Tuns32; + case Tuns32: + buf.printf("%uu", cast(uint) v); + break; + case Tint64: + if (v == long.min) + { + // https://issues.dlang.org/show_bug.cgi?id=23173 + // This is a special case because - is not part of the + // integer literal and 9223372036854775808L overflows a long + buf.writestring("cast(long)-9223372036854775808"); + } + else + { + buf.printf("%lldL", v); + } + break; + case Tuns64: + buf.printf("%lluLU", v); + break; + case Tbool: + buf.writestring(v ? "true" : "false"); + break; + case Tpointer: + buf.writestring("cast("); + + // Should re-examine need for new hgs + // We do a copy of our state, so that input context and childCountOfModule applies from here on out. + HdrGenState hgs2 = this; + hgs2.fullQual = (t.ty == Tclass && !t.mod); + hgs2.toCBuffer(t, buf, null); + + buf.writestring(")cast(size_t)"); + goto case Tuns64; + + case Tvoid: + buf.writestring("cast(void)0"); + break; + + default: + /* This can happen if errors, such as + * the type is painted on like in fromConstInitializer(). + * Just ignore + */ + break; + } + } + else if (v & 0x8000000000000000L) + buf.printf("0x%llx", v); + else + buf.print(v); } - else - buf.writestring("align "); - visitAttribDeclaration(d.isAttribDeclaration()); - } + void floatToBuffer(Type type, real_t value) + { + .floatToBuffer(type, value, buf, this.hdrgen); + } - void visitAnonDeclaration(AnonDeclaration d) - { - buf.writestring(d.isunion ? "union" : "struct"); - buf.writenl(); - buf.writestring("{"); - buf.writenl(); - buf.level++; - if (d.decl) + void visitReal(RealExp e) { - foreach (de; *d.decl) - toCBuffer(de, buf, hgs); + floatToBuffer(e.type, e.value); } - buf.level--; - buf.writestring("}"); - buf.writenl(); - } - void visitPragmaDeclaration(PragmaDeclaration d) - { - buf.writestring("pragma ("); - buf.writestring(d.ident.toString()); - if (d.args && d.args.length) + void visitComplex(ComplexExp e) { - buf.writestring(", "); - argsToBuffer(d.args, buf, hgs); + /* Print as: + * (re+imi) + */ + buf.writeByte('('); + floatToBuffer(e.type, creall(e.value)); + buf.writeByte('+'); + floatToBuffer(e.type, cimagl(e.value)); + buf.writestring("i)"); } - buf.writeByte(')'); + void visitIdentifier(IdentifierExp e) + { + if (this.hdrgen || this.ddoc) + buf.writestring(e.ident.toHChars2()); + else + buf.writestring(e.ident.toString()); + } - // https://issues.dlang.org/show_bug.cgi?id=14690 - // Unconditionally perform a full output dump - // for `pragma(inline)` declarations. - const saved = hgs.doFuncBodies; - if (d.ident == Id.Pinline) - hgs.doFuncBodies = true; + void visitString(StringExp e) + { + if (e.hexString || e.sz == 8) + { + buf.writeByte('x'); + buf.writeByte('"'); - visitAttribDeclaration(d); - hgs.doFuncBodies = saved; - } + foreach (i; 0 .. e.len) + buf.printf("%0*llX", e.sz, e.getIndex(i)); - void visitConditionalDeclaration(ConditionalDeclaration d) - { - d.condition.conditionToBuffer(buf, hgs); - if (d.decl || d.elsedecl) - { - buf.writenl(); - buf.writeByte('{'); - buf.writenl(); - buf.level++; - if (d.decl) + buf.writeByte('"'); + + if (e.postfix) + buf.writeByte(e.postfix); + return; + } + buf.writeByte('"'); + const o = buf.length; + + foreach (i; 0 .. e.len) { - foreach (de; *d.decl) - toCBuffer(de, buf, hgs); + writeCharLiteral(buf, e.getCodeUnit(i)); } - buf.level--; - buf.writeByte('}'); - if (d.elsedecl) + + if (this.ddoc) + escapeDdocString(buf, o); + + buf.writeByte('"'); + + if (e.postfix) + buf.writeByte(e.postfix); + } + + void visitInterpolation(InterpExp e) + { + buf.writeByte('i'); + buf.writeByte('"'); + const o = buf.length; + + foreach (idx, str; e.interpolatedSet.parts) { - buf.writenl(); - buf.writestring("else"); - buf.writenl(); - buf.writeByte('{'); - buf.writenl(); - buf.level++; - foreach (de; *d.elsedecl) - toCBuffer(de, buf, hgs); - buf.level--; - buf.writeByte('}'); + if (idx % 2 == 0) + { + foreach (ch; str) + writeCharLiteral(buf, ch); + } + else + { + buf.writeByte('$'); + buf.writeByte('('); + + foreach (ch; str) + buf.writeByte(ch); + + buf.writeByte(')'); + } } + + if (this.ddoc) + escapeDdocString(buf, o); + + buf.writeByte('"'); + + if (e.postfix) + buf.writeByte(e.postfix); + } - else - buf.writeByte(':'); - buf.writenl(); - } - void visitStaticForeachDeclaration(StaticForeachDeclaration s) - { - void foreachWithoutBody(ForeachStatement s) + void visitArrayLiteral(ArrayLiteralExp e) { - buf.writestring(Token.toString(s.op)); - buf.writestring(" ("); - foreach (i, p; *s.parameters) + buf.writeByte('['); + argsToBuffer(e.elements, buf, e.basis); + buf.writeByte(']'); + } + + void visitAssocArrayLiteral(AssocArrayLiteralExp e) + { + buf.writeByte('['); + foreach (i, key; *e.keys) { if (i) buf.writestring(", "); - if (stcToBuffer(buf, p.storageClass)) - buf.writeByte(' '); - if (p.type) - typeToBuffer(p.type, p.ident, buf, hgs); - else - buf.writestring(p.ident.toString()); + expToBuffer(key, PREC.assign, buf); + buf.writeByte(':'); + auto value = (*e.values)[i]; + expToBuffer(value, PREC.assign, buf); } - buf.writestring("; "); - s.aggr.expressionToBuffer(buf, hgs); - buf.writeByte(')'); - buf.writenl(); + buf.writeByte(']'); } - void foreachRangeWithoutBody(ForeachRangeStatement s) + void visitStructLiteral(StructLiteralExp e) { - /* s.op ( prm ; lwr .. upr ) - */ - buf.writestring(Token.toString(s.op)); - buf.writestring(" ("); - if (s.prm.type) - typeToBuffer(s.prm.type, s.prm.ident, buf, hgs); + buf.writestring(e.sd.toChars()); + buf.writeByte('('); + // CTFE can generate struct literals that contain an AddrExp pointing + // to themselves, need to avoid infinite recursion: + // struct S { this(int){ this.s = &this; } S* s; } + // const foo = new S(0); + if (e.stageflags & stageToCBuffer) + buf.writestring(""); else - buf.writestring(s.prm.ident.toString()); - buf.writestring("; "); - s.lwr.expressionToBuffer(buf, hgs); - buf.writestring(" .. "); - s.upr.expressionToBuffer(buf, hgs); + { + const old = e.stageflags; + e.stageflags |= stageToCBuffer; + argsToBuffer(e.elements, buf); + e.stageflags = old; + } buf.writeByte(')'); - buf.writenl(); } - buf.writestring("static "); - if (s.sfe.aggrfe) + void visitCompoundLiteral(CompoundLiteralExp e) { - foreachWithoutBody(s.sfe.aggrfe); + buf.writeByte('('); + typeToBuffer(e.type, null, buf); + buf.writeByte(')'); + initializerToBuffer(e.initializer, buf); } - else + + void visitScope(ScopeExp e) { - assert(s.sfe.rangefe); - foreachRangeWithoutBody(s.sfe.rangefe); + if (e.sds.isTemplateInstance()) + { + toCBuffer(e.sds, buf); + } + else if (this.ddoc) + { + // fixes bug 6491 + if (auto m = e.sds.isModule()) + buf.writestring(m.md.toChars()); + else + buf.writestring(e.sds.toChars()); + } + else + { + buf.writestring(e.sds.kind()); + buf.writeByte(' '); + buf.writestring(e.sds.toChars()); + } } - buf.writeByte('{'); - buf.writenl(); - buf.level++; - visitAttribDeclaration(s); - buf.level--; - buf.writeByte('}'); - buf.writenl(); - } + void visitNew(NewExp e) + { + if (e.thisexp) + { + expToBuffer(e.thisexp, PREC.primary, buf); + buf.writeByte('.'); + } + buf.writestring("new "); + typeToBuffer(e.newtype, null, buf); + if (e.arguments && e.arguments.length) + { + buf.writeByte('('); + argsToBuffer(e.arguments, buf, null, e.names); + buf.writeByte(')'); + } + } - void visitMixinDeclaration(MixinDeclaration d) - { - buf.writestring("mixin("); - argsToBuffer(d.exps, buf, hgs, null); - buf.writestring(");"); - buf.writenl(); - } + void visitNewAnonClass(NewAnonClassExp e) + { + if (e.thisexp) + { + expToBuffer(e.thisexp, PREC.primary, buf); + buf.writeByte('.'); + } + buf.writestring("new"); + buf.writestring(" class "); + if (e.arguments && e.arguments.length) + { + buf.writeByte('('); + argsToBuffer(e.arguments, buf); + buf.writeByte(')'); + } + if (e.cd) + toCBuffer(e.cd, buf); + } - void visitUserAttributeDeclaration(UserAttributeDeclaration d) - { - buf.writestring("@("); - argsToBuffer(d.atts, buf, hgs); - buf.writeByte(')'); - visitAttribDeclaration(d); - } + void visitSymOff(SymOffExp e) + { + if (e.offset) + buf.printf("(& %s%+lld)", e.var.toChars(), e.offset); + else if (e.var.isTypeInfoDeclaration()) + buf.writestring(e.var.toChars()); + else + buf.printf("& %s", e.var.toChars()); + } - void visitTemplateConstraint(Expression constraint) - { - if (!constraint) - return; - buf.writestring(" if ("); - constraint.expressionToBuffer(buf, hgs); - buf.writeByte(')'); - } + void visitTuple(TupleExp e) + { + if (e.e0) + { + buf.writeByte('('); + expressionPrettyPrint(e.e0, buf); + buf.writestring(", AliasSeq!("); + argsToBuffer(e.exps, buf); + buf.writestring("))"); + } + else + { + buf.writestring("AliasSeq!("); + argsToBuffer(e.exps, buf); + buf.writeByte(')'); + } + } - /// Returns: whether `do` is needed to write the function body - bool contractsToBuffer(FuncDeclaration f) - { - bool requireDo = false; - // in{} - if (f.frequires) + void visitDeclaration(DeclarationExp e) { - foreach (frequire; *f.frequires) + /* Normal dmd execution won't reach here - regular variable declarations + * are handled in visit(ExpStatement), so here would be used only when + * we'll directly call Expression.toChars() for debugging. + */ + if (e.declaration) { - buf.writestring("in"); - if (auto es = frequire.isExpStatement()) + if (auto var = e.declaration.isVarDeclaration()) { - assert(es.exp && es.exp.op == EXP.assert_); - buf.writestring(" ("); - (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs); + // For debugging use: + // - Avoid printing newline. + // - Intentionally use the format (Type var;) + // which isn't correct as regular D code. + buf.writeByte('('); + + visitVarDecl(var, false, buf); + + buf.writeByte(';'); buf.writeByte(')'); - buf.writenl(); - requireDo = false; } else - { - buf.writenl(); - frequire.statementToBuffer(buf, hgs); - requireDo = true; - } + toCBuffer(e.declaration, buf); } } - // out{} - if (f.fensures) + + void visitTraits(TraitsExp e) { - foreach (fensure; *f.fensures) + buf.writestring("__traits("); + if (e.ident) + buf.writestring(e.ident.toString()); + if (e.args) { - buf.writestring("out"); - if (auto es = fensure.ensure.isExpStatement()) - { - assert(es.exp && es.exp.op == EXP.assert_); - buf.writestring(" ("); - if (fensure.id) - { - buf.writestring(fensure.id.toString()); - } - buf.writestring("; "); - (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs); - buf.writeByte(')'); - buf.writenl(); - requireDo = false; - } - else + foreach (arg; *e.args) { - if (fensure.id) - { - buf.writeByte('('); - buf.writestring(fensure.id.toString()); - buf.writeByte(')'); - } - buf.writenl(); - fensure.ensure.statementToBuffer(buf, hgs); - requireDo = true; + buf.writestring(", "); + objectToBuffer(arg, buf); } } + buf.writeByte(')'); } - return requireDo; - } - void bodyToBuffer(FuncDeclaration f) - { - if (!f.fbody || (hgs.hdrgen && hgs.doFuncBodies == false && !hgs.autoMember && !hgs.tpltMember && !hgs.insideFuncBody)) + void visitIs(IsExp e) { - if (!f.fbody && (f.fensures || f.frequires)) + buf.writestring("is("); + typeToBuffer(e.targ, e.id, buf); + if (e.tok2 != TOK.reserved) { - buf.writenl(); - contractsToBuffer(f); + buf.writeByte(' '); + buf.writestring(Token.toString(e.tok)); + buf.writeByte(' '); + buf.writestring(Token.toString(e.tok2)); } - buf.writeByte(';'); - buf.writenl(); - return; + else if (e.tspec) + { + if (e.tok == TOK.colon) + buf.writestring(" : "); + else + buf.writestring(" == "); + typeToBuffer(e.tspec, null, buf); + } + if (e.parameters && e.parameters.length) + { + buf.writestring(", "); + visitTemplateParameters(e.parameters, buf); + } + buf.writeByte(')'); } - // there is no way to know if a function is nested - // or not after parsing. We need scope information - // for that, which is avaible during semantic - // analysis. To overcome that, a simple mechanism - // is implemented: everytime we print a function - // body (templated or not) we increment a counter. - // We decredement the counter when we stop - // printing the function body. - ++hgs.insideFuncBody; - scope(exit) { --hgs.insideFuncBody; } - - const savetlpt = hgs.tpltMember; - const saveauto = hgs.autoMember; - hgs.tpltMember = 0; - hgs.autoMember = 0; - buf.writenl(); - bool requireDo = contractsToBuffer(f); - - if (requireDo) + void visitUna(UnaExp e) { - buf.writestring("do"); - buf.writenl(); + buf.writestring(expressionTypeToString(e.op)); + expToBuffer(e.e1, precedence[e.op], buf); } - buf.writeByte('{'); - buf.writenl(); - buf.level++; - f.fbody.statementToBuffer(buf, hgs); - buf.level--; - buf.writeByte('}'); - buf.writenl(); - hgs.tpltMember = savetlpt; - hgs.autoMember = saveauto; - } - void visitBaseClasses(ClassDeclaration d) - { - if (!d || !d.baseclasses.length) - return; - if (!d.isAnonymous()) - buf.writestring(" : "); - foreach (i, b; *d.baseclasses) + void visitLoweredAssignExp(LoweredAssignExp e) { - if (i) - buf.writestring(", "); - typeToBuffer(b.type, null, buf, hgs); + if (this.vcg_ast) + { + expressionPrettyPrint(e.lowering, buf); + return; + } + + buf.writestring(expressionTypeToString((cast(BinExp) e).op)); } - } - bool visitEponymousMember(TemplateDeclaration d) - { - if (!d.members || d.members.length != 1) - return false; - Dsymbol onemember = (*d.members)[0]; - if (onemember.ident != d.ident) - return false; - if (FuncDeclaration fd = onemember.isFuncDeclaration()) + void visitBin(BinExp e) { - assert(fd.type); - if (stcToBuffer(buf, fd.storage_class)) - buf.writeByte(' '); - functionToBufferFull(cast(TypeFunction)fd.type, buf, d.ident, hgs, d); - visitTemplateConstraint(d.constraint); - hgs.tpltMember++; - bodyToBuffer(fd); - hgs.tpltMember--; - return true; + expToBuffer(e.e1, precedence[e.op], buf); + buf.writeByte(' '); + buf.writestring(expressionTypeToString(e.op)); + buf.writeByte(' '); + expToBuffer(e.e2, cast(PREC)(precedence[e.op] + 1), buf); } - if (AggregateDeclaration ad = onemember.isAggregateDeclaration()) + + void visitComma(CommaExp e) { - buf.writestring(ad.kind()); - buf.writeByte(' '); - buf.writestring(ad.ident.toString()); - buf.writeByte('('); - visitTemplateParameters(hgs.ddoc ? d.origParameters : d.parameters, buf, hgs); - buf.writeByte(')'); - visitTemplateConstraint(d.constraint); - visitBaseClasses(ad.isClassDeclaration()); - hgs.tpltMember++; - if (ad.members) + // CommaExp is generated by the compiler so it shouldn't + // appear in error messages or header files. + // For now, this treats the case where the compiler + // generates CommaExp for temporaries by calling + // the `sideeffect.copyToTemp` function. + auto ve = e.e2.isVarExp(); + + // not a CommaExp introduced for temporaries, go on + // the old path + if (!ve || !(ve.var.storage_class & STC.temp)) { - buf.writenl(); - buf.writeByte('{'); - buf.writenl(); - buf.level++; - foreach (s; *ad.members) - toCBuffer(s, buf, hgs); - buf.level--; - buf.writeByte('}'); + visitBin(cast(BinExp) e); + return; } - else - buf.writeByte(';'); - buf.writenl(); - hgs.tpltMember--; - return true; - } - if (VarDeclaration vd = onemember.isVarDeclaration()) - { - if (d.constraint) - return false; - if (stcToBuffer(buf, vd.storage_class)) - buf.writeByte(' '); - if (vd.type) - typeToBuffer(vd.type, vd.ident, buf, hgs); - else - buf.writestring(vd.ident.toString()); - buf.writeByte('('); - visitTemplateParameters(hgs.ddoc ? d.origParameters : d.parameters, buf, hgs); - buf.writeByte(')'); - if (vd._init) + + // CommaExp that contain temporaries inserted via + // `copyToTemp` are usually of the form + // ((T __temp = exp), __tmp). + // Asserts are here to easily spot + // missing cases where CommaExp + // are used for other constructs + auto vd = ve.var.isVarDeclaration(); + assert(vd && vd._init); + + if (auto ei = vd._init.isExpInitializer()) { - 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); - else - vd._init.initializerToBuffer(buf, hgs); + Expression commaExtract; + auto exp = ei.exp; + if (auto ce = exp.isConstructExp()) + commaExtract = ce.e2; + else if (auto se = exp.isStructLiteralExp()) + commaExtract = se; + + if (commaExtract) + { + expToBuffer(commaExtract, precedence[exp.op], buf); + return; + } } - buf.writeByte(';'); - buf.writenl(); - return true; - } - return false; - } - void visitTemplateDeclaration(TemplateDeclaration d) - { - version (none) - { - // Should handle template functions for doc generation - if (onemember && onemember.isFuncDeclaration()) - buf.writestring("foo "); - } - if ((hgs.hdrgen || hgs.fullDump) && visitEponymousMember(d)) + // not one of the known cases, go on the old path + visitBin(cast(BinExp) e); return; - if (hgs.ddoc) - buf.writestring(d.kind()); - else - buf.writestring("template"); - buf.writeByte(' '); - buf.writestring(d.ident.toString()); - buf.writeByte('('); - visitTemplateParameters(hgs.ddoc ? d.origParameters : d.parameters, buf, hgs); - buf.writeByte(')'); - visitTemplateConstraint(d.constraint); - if (hgs.hdrgen || hgs.fullDump) - { - hgs.tpltMember++; - buf.writenl(); - buf.writeByte('{'); - buf.writenl(); - buf.level++; - foreach (s; *d.members) - toCBuffer(s, buf, hgs); - buf.level--; - buf.writeByte('}'); - buf.writenl(); - hgs.tpltMember--; } - } - - void visitTemplateInstance(TemplateInstance ti) - { - buf.writestring(ti.name.toChars()); - tiargsToBuffer(ti, buf, hgs); - if (hgs.fullDump) + void visitAssert(AssertExp e) { - buf.writenl(); - dumpTemplateInstance(ti, buf, hgs); + buf.writestring("assert("); + expToBuffer(e.e1, PREC.assign, buf); + if (e.msg) + { + buf.writestring(", "); + expToBuffer(e.msg, PREC.assign, buf); + } + buf.writeByte(')'); } - } - void visitTemplateMixin(TemplateMixin tm) - { - buf.writestring("mixin "); - typeToBuffer(tm.tqual, null, buf, hgs); - tiargsToBuffer(tm, buf, hgs); - if (tm.ident && memcmp(tm.ident.toString().ptr, cast(const(char)*) "__mixin", 7) != 0) + void visitDotId(DotIdExp e) { - buf.writeByte(' '); - buf.writestring(tm.ident.toString()); + expToBuffer(e.e1, PREC.primary, buf); + if (e.arrow) + buf.writestring("->"); + else + buf.writeByte('.'); + buf.writestring(e.ident.toString()); } - buf.writeByte(';'); - buf.writenl(); - if (hgs.fullDump) - dumpTemplateInstance(tm, buf, hgs); - } - void visitEnumDeclaration(EnumDeclaration d) - { - auto oldInEnumDecl = hgs.inEnumDecl; - scope(exit) hgs.inEnumDecl = oldInEnumDecl; - hgs.inEnumDecl = d; - buf.writestring("enum "); - if (d.ident) + void visitDotTemplate(DotTemplateExp e) { - buf.writestring(d.ident.toString()); + expToBuffer(e.e1, PREC.primary, buf); + buf.writeByte('.'); + buf.writestring(e.td.toChars()); } - if (d.memtype) + + void visitDotVar(DotVarExp e) { - buf.writestring(" : "); - typeToBuffer(d.memtype, null, buf, hgs); + expToBuffer(e.e1, PREC.primary, buf); + buf.writeByte('.'); + buf.writestring(e.var.toChars()); } - if (!d.members) + + void visitDotTemplateInstance(DotTemplateInstanceExp e) { - buf.writeByte(';'); - buf.writenl(); - return; + expToBuffer(e.e1, PREC.primary, buf); + buf.writeByte('.'); + toCBuffer(e.ti, buf); } - buf.writenl(); - buf.writeByte('{'); - buf.writenl(); - buf.level++; - foreach (em; *d.members) + + void visitDelegate(DelegateExp e) { - if (!em) - continue; - toCBuffer(em, buf, hgs); - buf.writeByte(','); - buf.writenl(); + buf.writeByte('&'); + if (!e.func.isNested() || e.func.needThis()) + { + expToBuffer(e.e1, PREC.primary, buf); + buf.writeByte('.'); + } + buf.writestring(e.func.toChars()); } - buf.level--; - buf.writeByte('}'); - buf.writenl(); - - if (!hgs.importcHdr || !d.ident) - return; - /* C enums get their members inserted into the symbol table of the enum declaration. - * This is accomplished in addEnumMembersToSymtab(). - * But when generating D code from ImportC code, D rulez are followed. - * Accomplish this by generating an alias declaration for each member - */ - foreach (em; *d.members) + void visitDotType(DotTypeExp e) { - if (!em) - continue; - buf.writestring("alias "); - buf.writestring(em.ident.toString); - buf.writestring(" = "); - buf.writestring(d.ident.toString); + expToBuffer(e.e1, PREC.primary, buf); buf.writeByte('.'); - buf.writestring(em.ident.toString); - buf.writeByte(';'); - buf.writenl(); + buf.writestring(e.sym.toChars()); } - } - - void visitNspace(Nspace d) - { - buf.writestring("extern (C++, "); - buf.writestring(d.ident.toString()); - buf.writeByte(')'); - buf.writenl(); - buf.writeByte('{'); - buf.writenl(); - buf.level++; - foreach (s; *d.members) - toCBuffer(s, buf, hgs); - buf.level--; - buf.writeByte('}'); - buf.writenl(); - } - void visitStructDeclaration(StructDeclaration d) - { - //printf("visitStructDeclaration() %s\n", d.ident.toChars()); - buf.writestring(d.kind()); - buf.writeByte(' '); - if (!d.isAnonymous()) - buf.writestring(d.toChars()); - if (!d.members) + void visitCall(CallExp e) { - buf.writeByte(';'); - buf.writenl(); - return; + if (e.e1.op == EXP.type) + { + /* Avoid parens around type to prevent forbidden cast syntax: + * (sometype)(arg1) + * This is ok since types in constructor calls + * can never depend on parens anyway + */ + expressionPrettyPrint(e.e1, buf); + } + else + expToBuffer(e.e1, precedence[e.op], buf); + buf.writeByte('('); + argsToBuffer(e.arguments, buf, null, e.names); + buf.writeByte(')'); } - buf.writenl(); - buf.writeByte('{'); - buf.writenl(); - buf.level++; - hgs.insideAggregate++; - foreach (s; *d.members) - toCBuffer(s, buf, hgs); - hgs.insideAggregate--; - buf.level--; - buf.writeByte('}'); - buf.writenl(); - } - void visitClassDeclaration(ClassDeclaration d) - { - if (!d.isAnonymous()) + void visitPtr(PtrExp e) { - buf.writestring(d.kind()); - buf.writeByte(' '); - buf.writestring(d.ident.toString()); + buf.writeByte('*'); + expToBuffer(e.e1, precedence[e.op], buf); } - visitBaseClasses(d); - if (d.members) + + void visitDelete(DeleteExp e) { - buf.writenl(); - buf.writeByte('{'); - buf.writenl(); - buf.level++; - hgs.insideAggregate++; - foreach (s; *d.members) - toCBuffer(s, buf, hgs); - hgs.insideAggregate--; - buf.level--; - buf.writeByte('}'); + buf.writestring("delete "); + expToBuffer(e.e1, precedence[e.op], buf); } - else - buf.writeByte(';'); - buf.writenl(); - } - void visitAliasDeclaration(AliasDeclaration d) - { - if (d.storage_class & STC.local) - return; - if (d.adFlags & d.hidden) - return; - buf.writestring("alias "); - if (d.aliassym) + void visitCast(CastExp e) { - buf.writestring(d.ident.toString()); - buf.writestring(" = "); - if (stcToBuffer(buf, d.storage_class)) - buf.writeByte(' '); - /* - https://issues.dlang.org/show_bug.cgi?id=23223 - https://issues.dlang.org/show_bug.cgi?id=23222 - This special case (initially just for modules) avoids some segfaults - and nicer -vcg-ast output. - */ - if (d.aliassym.isModule()) - { - buf.writestring(d.aliassym.ident.toString()); - } + buf.writestring("cast("); + + if (e.to) + typeToBuffer(e.to, null, buf); else { - toCBuffer(d.aliassym, buf, hgs); + MODtoBuffer(buf, e.mod); } + + buf.writeByte(')'); + expToBuffer(e.e1, precedence[e.op], buf); } - else if (d.type.ty == Tfunction) - { - if (stcToBuffer(buf, d.storage_class)) - buf.writeByte(' '); - typeToBuffer(d.type, d.ident, buf, hgs); - } - else if (d.ident) + + void visitVector(VectorExp e) { - 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)) - buf.writeByte(' '); - typeToBuffer(d.type, null, buf, hgs); - hgs.declstring = false; + buf.writestring("cast("); + typeToBuffer(e.to, null, buf); + buf.writeByte(')'); + expToBuffer(e.e1, precedence[e.op], buf); } - buf.writeByte(';'); - buf.writenl(); - } - - void visitAliasAssign(AliasAssign d) - { - buf.writestring(d.ident.toString()); - buf.writestring(" = "); - if (d.aliassym) - toCBuffer(d.aliassym, buf, hgs); - else // d.type - typeToBuffer(d.type, null, buf, hgs); - buf.writeByte(';'); - buf.writenl(); - } - - void visitVarDeclaration(VarDeclaration d) - { - if (d.storage_class & STC.local) - return; - visitVarDecl(d, false, buf, hgs); - buf.writeByte(';'); - buf.writenl(); - } - - void visitFuncDeclaration(FuncDeclaration f) - { - //printf("FuncDeclaration::toCBuffer() '%s'\n", f.toChars()); - if (stcToBuffer(buf, f.storage_class)) - buf.writeByte(' '); - auto tf = f.type.isTypeFunction(); - typeToBuffer(tf, f.ident, buf, hgs); - if (hgs.hdrgen) + void visitSlice(SliceExp e) { - // if the return type is missing (e.g. ref functions or auto) - // https://issues.dlang.org/show_bug.cgi?id=20090 - // constructors are an exception: they don't have an explicit return - // type but we still don't output the body. - if ((!f.isCtorDeclaration() && !tf.next) || f.storage_class & STC.auto_) - { - hgs.autoMember++; - bodyToBuffer(f); - hgs.autoMember--; - } - else if (hgs.tpltMember == 0 && hgs.doFuncBodies == false && !hgs.insideFuncBody) + expToBuffer(e.e1, precedence[e.op], buf); + buf.writeByte('['); + if (e.upr || e.lwr) { - if (!f.fbody) - { - // this can happen on interfaces / abstract functions, see `allowsContractWithoutBody` - if (f.fensures || f.frequires) - buf.writenl(); - contractsToBuffer(f); - } - buf.writeByte(';'); - buf.writenl(); + if (e.lwr) + sizeToBuffer(e.lwr, buf); + else + buf.writeByte('0'); + buf.writestring(".."); + if (e.upr) + sizeToBuffer(e.upr, buf); + else + buf.writeByte('$'); } - else - bodyToBuffer(f); + buf.writeByte(']'); } - else - bodyToBuffer(f); - } - void visitFuncLiteralDeclaration(FuncLiteralDeclaration f) - { - if (f.type.ty == Terror) - { - buf.writestring("__error"); - return; - } - if (f.tok != TOK.reserved) + void visitInterval(IntervalExp e) { - buf.writestring(f.kind()); - buf.writeByte(' '); + expToBuffer(e.lwr, PREC.assign, buf); + buf.writestring(".."); + expToBuffer(e.upr, PREC.assign, buf); } - TypeFunction tf = cast(TypeFunction)f.type; - if (!f.inferRetType && tf.next) - typeToBuffer(tf.next, null, buf, hgs); - parametersToBuffer(tf.parameterList, buf, hgs); - - // https://issues.dlang.org/show_bug.cgi?id=20074 - void printAttribute(string str) + void visitDelegateFuncptr(DelegateFuncptrExp e) { - buf.writeByte(' '); - buf.writestring(str); + expToBuffer(e.e1, PREC.primary, buf); + buf.writestring(".funcptr"); } - tf.attributesApply(&printAttribute); - - CompoundStatement cs = f.fbody.isCompoundStatement(); - Statement s1; - if (f.semanticRun >= PASS.semantic3done && cs) + void visitArray(ArrayExp e) { - s1 = (*cs.statements)[cs.statements.length - 1]; + expToBuffer(e.e1, PREC.primary, buf); + buf.writeByte('['); + argsToBuffer(e.arguments, buf); + buf.writeByte(']'); } - else - s1 = !cs ? f.fbody : null; - ReturnStatement rs = s1 ? s1.endsWithReturnStatement() : null; - if (rs && rs.exp) + + void visitDot(DotExp e) { - buf.writestring(" => "); - rs.exp.expressionToBuffer(buf, hgs); + expToBuffer(e.e1, PREC.primary, buf); + buf.writeByte('.'); + expToBuffer(e.e2, PREC.primary, buf); } - else + + void visitIndex(IndexExp e) { - hgs.tpltMember++; - bodyToBuffer(f); - hgs.tpltMember--; + expToBuffer(e.e1, PREC.primary, buf); + buf.writeByte('['); + sizeToBuffer(e.e2, buf); + buf.writeByte(']'); } - } - - void visitPostBlitDeclaration(PostBlitDeclaration d) - { - if (stcToBuffer(buf, d.storage_class)) - buf.writeByte(' '); - buf.writestring("this(this)"); - bodyToBuffer(d); - } - - void visitDtorDeclaration(DtorDeclaration d) - { - if (stcToBuffer(buf, d.storage_class)) - buf.writeByte(' '); - buf.writestring("~this()"); - bodyToBuffer(d); - } - void visitStaticCtorDeclaration(StaticCtorDeclaration d) - { - if (stcToBuffer(buf, d.storage_class & ~STC.static_)) - buf.writeByte(' '); - if (d.isSharedStaticCtorDeclaration()) - buf.writestring("shared "); - buf.writestring("static this()"); - if (hgs.hdrgen && !hgs.tpltMember) + void visitPost(PostExp e) { - buf.writeByte(';'); - buf.writenl(); + expToBuffer(e.e1, precedence[e.op], buf); + buf.writestring(expressionTypeToString(e.op)); } - else - bodyToBuffer(d); - } - void visitStaticDtorDeclaration(StaticDtorDeclaration d) - { - if (stcToBuffer(buf, d.storage_class & ~STC.static_)) - buf.writeByte(' '); - if (d.isSharedStaticDtorDeclaration()) - buf.writestring("shared "); - buf.writestring("static ~this()"); - if (hgs.hdrgen && !hgs.tpltMember) + void visitPre(PreExp e) { - buf.writeByte(';'); - buf.writenl(); + buf.writestring(expressionTypeToString(e.op)); + expToBuffer(e.e1, precedence[e.op], buf); } - else - bodyToBuffer(d); - } - void visitInvariantDeclaration(InvariantDeclaration d) - { - if (hgs.hdrgen) - return; - if (stcToBuffer(buf, d.storage_class)) - buf.writeByte(' '); - buf.writestring("invariant"); - if(auto es = d.fbody.isExpStatement()) + void visitRemove(RemoveExp e) { - assert(es.exp && es.exp.op == EXP.assert_); - buf.writestring(" ("); - (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs); - buf.writestring(");"); - buf.writenl(); + expToBuffer(e.e1, PREC.primary, buf); + buf.writestring(".remove("); + expToBuffer(e.e2, PREC.assign, buf); + buf.writeByte(')'); } - else + + void visitCond(CondExp e) { - bodyToBuffer(d); + expToBuffer(e.econd, PREC.oror, buf); + buf.writestring(" ? "); + expToBuffer(e.e1, PREC.expr, buf); + buf.writestring(" : "); + expToBuffer(e.e2, PREC.cond, buf); } - } - void visitUnitTestDeclaration(UnitTestDeclaration d) - { - if (hgs.hdrgen) - return; - if (stcToBuffer(buf, d.storage_class)) - buf.writeByte(' '); - buf.writestring("unittest"); - bodyToBuffer(d); - } - - void visitBitFieldDeclaration(BitFieldDeclaration d) - { - if (stcToBuffer(buf, d.storage_class)) - buf.writeByte(' '); - Identifier id = d.isAnonymous() ? null : d.ident; - typeToBuffer(d.type, id, buf, hgs); - buf.writestring(" : "); - d.width.expressionToBuffer(buf, hgs); - buf.writeByte(';'); - buf.writenl(); - } - - void visitNewDeclaration(NewDeclaration d) - { - if (stcToBuffer(buf, d.storage_class & ~STC.static_)) - buf.writeByte(' '); - buf.writestring("new();"); - } - - void visitModule(Module m) - { - moduleToBuffer2(m, buf, hgs); - } - - extern (C++) - final class DsymbolPrettyPrintVisitor : Visitor - { - alias visit = Visitor.visit; + switch (e.op) + { + default: + if (auto be = e.isBinExp()) + return visitBin(be); + else if (auto ue = e.isUnaExp()) + return visitUna(ue); + else if (auto de = e.isDefaultInitExp()) + { + buf.writestring(expressionTypeToString(e.isDefaultInitExp().op)); + return; + } + else + { + buf.writestring(expressionTypeToString(e.op)); + return; + } - public: - override: - void visit(Dsymbol s) { visitDsymbol(s); } - void visit(StaticAssert s) { visitStaticAssert(s); } - void visit(DebugSymbol s) { visitDebugSymbol(s); } - void visit(VersionSymbol s) { visitVersionSymbol(s); } - void visit(EnumMember em) { visitEnumMember(em); } - void visit(Import imp) { visitImport(imp); } - void visit(AliasThis d) { visitAliasThis(d); } - void visit(AttribDeclaration d) { visitAttribDeclaration(d); } - void visit(StorageClassDeclaration d) { visitStorageClassDeclaration(d); } - void visit(DeprecatedDeclaration d) { visitDeprecatedDeclaration(d); } - void visit(LinkDeclaration d) { visitLinkDeclaration(d); } - void visit(CPPMangleDeclaration d) { visitCPPMangleDeclaration(d); } - void visit(VisibilityDeclaration d) { visitVisibilityDeclaration(d); } - void visit(AlignDeclaration d) { visitAlignDeclaration(d); } - void visit(AnonDeclaration d) { visitAnonDeclaration(d); } - void visit(PragmaDeclaration d) { visitPragmaDeclaration(d); } - void visit(ConditionalDeclaration d) { visitConditionalDeclaration(d); } - void visit(StaticForeachDeclaration s) { visitStaticForeachDeclaration(s); } - void visit(MixinDeclaration d) { visitMixinDeclaration(d); } - void visit(UserAttributeDeclaration d) { visitUserAttributeDeclaration(d); } - void visit(TemplateDeclaration d) { visitTemplateDeclaration(d); } - void visit(TemplateInstance ti) { visitTemplateInstance(ti); } - void visit(TemplateMixin tm) { visitTemplateMixin(tm); } - void visit(EnumDeclaration d) { visitEnumDeclaration(d); } - void visit(Nspace d) { visitNspace(d); } - void visit(StructDeclaration d) { visitStructDeclaration(d); } - void visit(ClassDeclaration d) { visitClassDeclaration(d); } - void visit(AliasDeclaration d) { visitAliasDeclaration(d); } - void visit(AliasAssign d) { visitAliasAssign(d); } - void visit(VarDeclaration d) { visitVarDeclaration(d); } - void visit(FuncDeclaration f) { visitFuncDeclaration(f); } - void visit(FuncLiteralDeclaration f) { visitFuncLiteralDeclaration(f); } - void visit(PostBlitDeclaration d) { visitPostBlitDeclaration(d); } - void visit(DtorDeclaration d) { visitDtorDeclaration(d); } - void visit(StaticCtorDeclaration d) { visitStaticCtorDeclaration(d); } - void visit(StaticDtorDeclaration d) { visitStaticDtorDeclaration(d); } - void visit(InvariantDeclaration d) { visitInvariantDeclaration(d); } - void visit(UnitTestDeclaration d) { visitUnitTestDeclaration(d); } - void visit(BitFieldDeclaration d) { visitBitFieldDeclaration(d); } - void visit(NewDeclaration d) { visitNewDeclaration(d); } - void visit(Module m) { visitModule(m); } - } + case EXP.error: + buf.writestring("__error"); + return; + case EXP.this_: + buf.writestring("this"); + return; + case EXP.super_: + buf.writestring("super"); + return; + case EXP.null_: + buf.writestring("null"); + return; + case EXP.void_: + buf.writestring("void"); + return; + case EXP.halt: + buf.writestring("halt"); + return; - scope v = new DsymbolPrettyPrintVisitor(); - s.accept(v); -} + case EXP.function_: + toCBuffer(e.isFuncExp().fd, buf); + return; + case EXP.classReference: + buf.writestring(e.isClassReferenceExp().value.toChars()); + return; + case EXP.arrayLength: + expToBuffer(e.isArrayLengthExp().e1, PREC.primary, buf); + buf.writestring(".length"); + return; + case EXP.vectorArray: + expToBuffer(e.isVectorArrayExp().e1, PREC.primary, buf); + buf.writestring(".array"); + return; + case EXP.throw_: + buf.writestring("throw "); + expToBuffer(e.isThrowExp().e1, PREC.unary, buf); + return; + case EXP.import_: + buf.writestring("import("); + expToBuffer(e.isImportExp().e1, PREC.assign, buf); + buf.writeByte(')'); + return; + case EXP.mixin_: + buf.writestring("mixin("); + argsToBuffer(e.isMixinExp().exps, buf, null); + buf.writeByte(')'); + return; + case EXP.typeid_: + buf.writestring("typeid("); + objectToBuffer(e.isTypeidExp().obj, buf); + buf.writeByte(')'); + return; + case EXP.overloadSet: + buf.writestring(e.isOverExp().vars.ident.toString()); + return; + case EXP.variable: + buf.writestring(e.isVarExp().var.toChars()); + return; + case EXP.template_: + buf.writestring(e.isTemplateExp().td.toChars()); + return; + case EXP.type: + typeToBuffer(e.isTypeExp().type, null, buf); + return; + case EXP.dSymbol: + buf.writestring(e.isDsymbolExp().s.toChars()); + return; + case EXP.delegatePointer: + expToBuffer(e.isDelegatePtrExp().e1, PREC.primary, buf); + buf.writestring(".ptr"); + return; -// Note: this function is not actually `const`, because iterating the -// function parameter list may run dsymbolsemantic on enum types -public -void toCharsMaybeConstraints(const TemplateDeclaration td, ref OutBuffer buf, ref HdrGenState hgs) -{ - buf.writestring(td.ident == Id.ctor ? "this" : td.ident.toString()); - buf.writeByte('('); - foreach (i, const tp; *td.parameters) - { - if (i) - buf.writestring(", "); - toCBuffer(tp, buf, hgs); - } - buf.writeByte(')'); + case EXP.int64: + return visitInteger(e.isIntegerExp()); + case EXP.float64: + return visitReal(e.isRealExp()); + case EXP.complex80: + return visitComplex(e.isComplexExp()); + case EXP.identifier: + return visitIdentifier(e.isIdentifierExp()); + case EXP.string_: + return visitString(e.isStringExp()); + case EXP.interpolated: + return visitInterpolation(e.isInterpExp()); + case EXP.arrayLiteral: + return visitArrayLiteral(e.isArrayLiteralExp()); + case EXP.assocArrayLiteral: + return visitAssocArrayLiteral(e.isAssocArrayLiteralExp()); + case EXP.structLiteral: + return visitStructLiteral(e.isStructLiteralExp()); + case EXP.compoundLiteral: + return visitCompoundLiteral(e.isCompoundLiteralExp()); + case EXP.scope_: + return visitScope(e.isScopeExp()); + case EXP.new_: + return visitNew(e.isNewExp()); + case EXP.newAnonymousClass: + return visitNewAnonClass(e.isNewAnonClassExp()); + case EXP.symbolOffset: + return visitSymOff(e.isSymOffExp()); + case EXP.tuple: + return visitTuple(e.isTupleExp()); + case EXP.declaration: + return visitDeclaration(e.isDeclarationExp()); + case EXP.traits: + return visitTraits(e.isTraitsExp()); + case EXP.is_: + return visitIs(e.isExp()); + case EXP.comma: + return visitComma(e.isCommaExp()); + case EXP.assert_: + return visitAssert(e.isAssertExp()); + case EXP.dotIdentifier: + return visitDotId(e.isDotIdExp()); + case EXP.dotTemplateDeclaration: + return visitDotTemplate(e.isDotTemplateExp()); + case EXP.dotVariable: + return visitDotVar(e.isDotVarExp()); + case EXP.dotTemplateInstance: + return visitDotTemplateInstance(e.isDotTemplateInstanceExp()); + case EXP.delegate_: + return visitDelegate(e.isDelegateExp()); + case EXP.dotType: + return visitDotType(e.isDotTypeExp()); + case EXP.call: + return visitCall(e.isCallExp()); + case EXP.star: + return visitPtr(e.isPtrExp()); + case EXP.delete_: + return visitDelete(e.isDeleteExp()); + case EXP.cast_: + return visitCast(e.isCastExp()); + case EXP.vector: + return visitVector(e.isVectorExp()); + case EXP.slice: + return visitSlice(e.isSliceExp()); + case EXP.interval: + return visitInterval(e.isIntervalExp()); + case EXP.delegateFunctionPointer: + return visitDelegateFuncptr(e.isDelegateFuncptrExp()); + case EXP.array: + return visitArray(e.isArrayExp()); + case EXP.dot: + return visitDot(e.isDotExp()); + case EXP.index: + return visitIndex(e.isIndexExp()); + case EXP.minusMinus, EXP.plusPlus: + return visitPost(e.isPostExp()); + case EXP.preMinusMinus, EXP.prePlusPlus: + return visitPre(e.isPreExp()); + case EXP.remove: + return visitRemove(e.isRemoveExp()); + case EXP.question: + return visitCond(e.isCondExp()); + + case EXP.loweredAssignExp: + return visitLoweredAssignExp(e.isLoweredAssignExp()); + } + } + + void initializerToBuffer(Initializer inx, ref OutBuffer buf) + { + void visitError(ErrorInitializer iz) + { + buf.writestring("__error__"); + } + + void visitVoid(VoidInitializer iz) + { + buf.writestring("void"); + } + + void visitDefault(DefaultInitializer iz) + { + buf.writestring("{ }"); + } + + void visitStruct(StructInitializer si) + { + //printf("StructInitializer::toCBuffer()\n"); + buf.writeByte('{'); + foreach (i, const id; si.field) + { + if (i) + buf.writestring(", "); + if (id) + { + buf.writestring(id.toString()); + buf.writeByte(':'); + } + if (auto iz = si.value[i]) + initializerToBuffer(iz, buf); + } + buf.writeByte('}'); + } - if (hgs.showOneMember && td.onemember) - { - if (const fd = td.onemember.isFuncDeclaration()) + void visitArray(ArrayInitializer ai) { - if (TypeFunction tf = cast(TypeFunction)fd.type.isTypeFunction()) + buf.writeByte('['); + foreach (i, ex; ai.index) { - // !! Casted away const - buf.writestring(parametersTypeToChars(tf.parameterList)); - if (tf.mod) + if (i) + buf.writestring(", "); + if (ex) { - buf.writeByte(' '); - buf.MODtoBuffer(tf.mod); + expressionPrettyPrint(ex, buf); + buf.writeByte(':'); } + if (auto iz = ai.value[i]) + initializerToBuffer(iz, buf); } + buf.writeByte(']'); } - } - - if (!hgs.skipConstraints && - td.constraint) - { - buf.writestring(" if ("); - toCBuffer(td.constraint, buf, hgs); - buf.writeByte(')'); - } -} - - -/***************************************** - * Pretty-print a template parameter list to a buffer. - */ -private void visitTemplateParameters(TemplateParameters* parameters, ref OutBuffer buf, ref HdrGenState hgs) -{ - if (!parameters) - return; - foreach (i, p; *parameters) - { - if (i) - buf.writestring(", "); - toCBuffer(p, 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); - } - - const commentIt = hgs.importcHdr && isSpecialCName(v.ident); - if (commentIt) - buf.writestring("/+"); - 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) + void visitExp(ExpInitializer ei) { - buf.writestring("typeof("); - vinit(v); - buf.writestring(") "); - buf.writestring(v.ident.toString()); + expressionPrettyPrint(ei.exp, buf); } - else - buf.writestring(v.ident.toString()); - } - if (v._init && !isextern) - { - buf.writestring(" = "); - vinit(v); - } - if (commentIt) - buf.writestring("+/"); -} - -/************************************* - * The names __DATE__, __TIME__,__EOF__, __VENDOR__, __TIMESTAMP__, __VERSION__ - * are special to the D lexer and cannot be used as D source variable names. - * Params: - * id = name to check - * Returns: - * true if special C name - */ -private bool isSpecialCName(Identifier id) -{ - auto s = id.toString(); - if (s.length >= 7 && s[0] == '_' && s[1] == '_' && - (id == Id.DATE || - id == Id.TIME || - id == Id.EOFX || - id == Id.VENDOR || - id == Id.TIMESTAMP || - id == Id.VERSIONX)) - return true; - return false; -} - -/********************************************* - * Print expression to buffer. - */ -private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenState hgs) -{ - void visit(Expression e) - { - buf.writestring(EXPtoString(e.op)); - } - void visitInteger(IntegerExp e) - { - const ulong v = e.toInteger(); - if (e.type) + void visitC(CInitializer ci) { - Type t = e.type; - L1: - switch (t.ty) + buf.writeByte('{'); + foreach (i, ref DesigInit di; ci.initializerList) { - case Tenum: + if (i) + buf.writestring(", "); + if (di.designatorList) { - TypeEnum te = cast(TypeEnum)t; - auto sym = te.sym; - if (sym && sym.members && (!hgs.inEnumDecl || hgs.inEnumDecl != sym)) + foreach (ref Designator d; (*di.designatorList)[]) { - foreach (em; *sym.members) + if (d.exp) { - if ((cast(EnumMember)em).value.toInteger == v) - { - const id = em.ident.toString(); - buf.printf("%s.%.*s", sym.toChars(), cast(int)id.length, id.ptr); - return ; - } + buf.writeByte('['); + toCBuffer(d.exp, buf); + buf.writeByte(']'); + } + else + { + buf.writeByte('.'); + buf.writestring(d.ident.toString()); } } - - buf.printf("cast(%s)", te.sym.toChars()); - t = te.sym.memtype; - goto L1; - } - case Tchar: - case Twchar: - case Tdchar: - { - const o = buf.length; - writeSingleCharLiteral(buf, cast(dchar) v); - if (hgs.ddoc) - escapeDdocString(buf, o); - break; + buf.writeByte('='); } - case Tint8: - buf.writestring("cast(byte)"); - goto L2; - case Tint16: - buf.writestring("cast(short)"); - goto L2; - case Tint32: - L2: - buf.printf("%d", cast(int)v); - break; - case Tuns8: - buf.writestring("cast(ubyte)"); - goto case Tuns32; - case Tuns16: - buf.writestring("cast(ushort)"); - goto case Tuns32; - case Tuns32: - buf.printf("%uu", cast(uint)v); - break; - case Tint64: - if (v == long.min) - { - // https://issues.dlang.org/show_bug.cgi?id=23173 - // This is a special case because - is not part of the - // integer literal and 9223372036854775808L overflows a long - buf.writestring("cast(long)-9223372036854775808"); - } - else - { - buf.printf("%lldL", v); - } - break; - case Tuns64: - buf.printf("%lluLU", v); - break; - case Tbool: - buf.writestring(v ? "true" : "false"); - break; - case Tpointer: - buf.writestring("cast("); - - HdrGenState hgs2; // should re-examine need for new hgs - hgs2.fullQual = (t.ty == Tclass && !t.mod); - toCBuffer(t, buf, null, hgs2); - - buf.writestring(")cast(size_t)"); - goto case Tuns64; - - case Tvoid: - buf.writestring("cast(void)0"); - break; - - default: - /* This can happen if errors, such as - * the type is painted on like in fromConstInitializer(). - * Just ignore - */ - break; + initializerToBuffer(di.initializer, buf); } + buf.writeByte('}'); } - else if (v & 0x8000000000000000L) - buf.printf("0x%llx", v); - else - buf.print(v); - } - void visitError(ErrorExp e) - { - buf.writestring("__error"); - } - - void visitVoidInit(VoidInitExp e) - { - buf.writestring("void"); + mixin VisitInitializer!void visit; + visit.VisitInitializer(inx); } - void floatToBuffer(Type type, real_t value) + void sizeToBuffer(Expression e, ref OutBuffer buf) { - .floatToBuffer(type, value, buf, hgs.hdrgen); - } + if (e.type == Type.tsize_t) + { + Expression ex = (e.op == EXP.cast_ ? (cast(CastExp) e).e1 : e); + ex = ex.optimize(WANTvalue); - void visitReal(RealExp e) - { - floatToBuffer(e.type, e.value); - } + const ulong uval = ex.op == EXP.int64 ? ex.toInteger() : cast(ulong)-1; + if (cast(long) uval >= 0) + { + if (uval <= 0xFFFFU) + { + buf.print(uval); + return; + } - void visitComplex(ComplexExp e) - { - /* Print as: - * (re+imi) - */ - buf.writeByte('('); - floatToBuffer(e.type, creall(e.value)); - buf.writeByte('+'); - floatToBuffer(e.type, cimagl(e.value)); - buf.writestring("i)"); - } + if (uval <= 0x7FFF_FFFF_FFFF_FFFFUL) + { + buf.writestring("cast(size_t)"); + buf.print(uval); + return; + } + } + } - void visitIdentifier(IdentifierExp e) - { - if (hgs.hdrgen || hgs.ddoc) - buf.writestring(e.ident.toHChars2()); - else - buf.writestring(e.ident.toString()); + expToBuffer(e, PREC.assign, buf); } - void visitDsymbol(DsymbolExp e) + /** + This makes a 'pretty' version of the template arguments. + It's analogous to genIdent() which makes a mangled version. + */ + void objectToBuffer(RootObject oarg, ref OutBuffer buf) { - buf.writestring(e.s.toChars()); - } + //printf("objectToBuffer()\n"); + /* The logic of this should match what genIdent() does. The _dynamic_cast() + * function relies on all the pretty strings to be unique for different classes + * See https://issues.dlang.org/show_bug.cgi?id=7375 + * Perhaps it would be better to demangle what genIdent() does. + */ - void visitThis(ThisExp e) - { - buf.writestring("this"); - } + if (auto t = isType(oarg)) + { + //printf("\tt: %s ty = %d\n", t.toChars(), t.ty); + typeToBuffer(t, null, buf); + } + else if (auto e = isExpression(oarg)) + { + if (e.op == EXP.variable) + e = e.optimize(WANTvalue); // added to fix https://issues.dlang.org/show_bug.cgi?id=7375 - void visitSuper(SuperExp e) - { - buf.writestring("super"); - } + expToBuffer(e, PREC.assign, buf); + } + else if (Dsymbol s = isDsymbol(oarg)) + { + if (s.ident) + buf.writestring(s.ident.toString()); + else + buf.writestring(s.toChars()); + } + else if (auto v = isTuple(oarg)) + { + auto args = &v.objects; - void visitNull(NullExp e) - { - buf.writestring("null"); - } + foreach (i, arg; *args) + { + if (i) + buf.writestring(", "); - void visitString(StringExp e) - { - if (e.hexString || e.sz == 8) + objectToBuffer(arg, buf); + } + } + else if (auto p = isParameter(oarg)) { - buf.writeByte('x'); - buf.writeByte('"'); - foreach (i; 0 .. e.len) - buf.printf("%0*llX", e.sz, e.getIndex(i)); - buf.writeByte('"'); - if (e.postfix) - buf.writeByte(e.postfix); - return; + parameterToBuffer(p, buf); } - buf.writeByte('"'); - const o = buf.length; - foreach (i; 0 .. e.len) + else if (!oarg) { - writeCharLiteral(buf, e.getCodeUnit(i)); + buf.writestring("NULL"); } - if (hgs.ddoc) - escapeDdocString(buf, o); - buf.writeByte('"'); - if (e.postfix) - buf.writeByte(e.postfix); - } - - void visitInterpolation(InterpExp e) - { - buf.writeByte('i'); - buf.writeByte('"'); - const o = buf.length; - - foreach (idx, str; e.interpolatedSet.parts) + else { - if (idx % 2 == 0) - { - foreach(ch; str) - writeCharLiteral(buf, ch); - } - else + debug { - buf.writeByte('$'); - buf.writeByte('('); - foreach(ch; str) - buf.writeByte(ch); - buf.writeByte(')'); + printf("bad Object = %p\n", oarg); } + assert(0); } - - if (hgs.ddoc) - escapeDdocString(buf, o); - buf.writeByte('"'); - if (e.postfix) - buf.writeByte(e.postfix); - } - void visitArrayLiteral(ArrayLiteralExp e) + /** + Pretty-print a template parameter list to a buffer. + */ + void visitTemplateParameters(TemplateParameters* parameters, ref OutBuffer buf) { - buf.writeByte('['); - argsToBuffer(e.elements, buf, hgs, e.basis); - buf.writeByte(']'); - } + if (!parameters) + return; - void visitAssocArrayLiteral(AssocArrayLiteralExp e) - { - buf.writeByte('['); - foreach (i, key; *e.keys) + foreach (i, p; *parameters) { if (i) buf.writestring(", "); - expToBuffer(key, PREC.assign, buf, hgs); - buf.writeByte(':'); - auto value = (*e.values)[i]; - expToBuffer(value, PREC.assign, buf, hgs); - } - buf.writeByte(']'); - } - void visitStructLiteral(StructLiteralExp e) - { - buf.writestring(e.sd.toChars()); - buf.writeByte('('); - // CTFE can generate struct literals that contain an AddrExp pointing - // to themselves, need to avoid infinite recursion: - // struct S { this(int){ this.s = &this; } S* s; } - // const foo = new S(0); - if (e.stageflags & stageToCBuffer) - buf.writestring(""); - else - { - const old = e.stageflags; - e.stageflags |= stageToCBuffer; - argsToBuffer(e.elements, buf, hgs); - e.stageflags = old; + toCBuffer(p, buf); } - buf.writeByte(')'); - } - - void visitCompoundLiteral(CompoundLiteralExp e) - { - buf.writeByte('('); - typeToBuffer(e.type, null, buf, hgs); - buf.writeByte(')'); - e.initializer.initializerToBuffer(buf, hgs); } - void visitType(TypeExp e) + /** + Pretty-print a VarDeclaration to buf. + */ + void visitVarDecl(VarDeclaration v, bool anywritten, ref OutBuffer buf) { - typeToBuffer(e.type, null, buf, hgs); - } + const bool isextern = this.hdrgen && !this.insideFuncBody && !this.tpltMember + && !this.insideAggregate && !(v.storage_class & STC.manifest); - void visitScope(ScopeExp e) - { - if (e.sds.isTemplateInstance()) + void vinit(VarDeclaration v) { - e.sds.dsymbolToBuffer(buf, hgs); + auto ie = v._init.isExpInitializer(); + if (ie && (ie.exp.op == EXP.construct || ie.exp.op == EXP.blit)) + expressionPrettyPrint((cast(AssignExp) ie.exp).e2, buf); + else + initializerToBuffer(v._init, buf); } - else if (hgs.ddoc) + + const commentIt = this.importcHdr && isSpecialCName(v.ident); + if (commentIt) + buf.writestring("/+"); + + if (anywritten) { - // fixes bug 6491 - if (auto m = e.sds.isModule()) - buf.writestring(m.md.toChars()); - else - buf.writestring(e.sds.toChars()); + buf.writestring(", "); + buf.writestring(v.ident.toString()); } else { - buf.writestring(e.sds.kind()); - buf.writeByte(' '); - buf.writestring(e.sds.toChars()); - } - } + const bool useTypeof = isextern && v._init && !v.type; + auto stc = v.storage_class; - void visitTemplate(TemplateExp e) - { - buf.writestring(e.td.toChars()); - } + if (isextern) + stc |= STC.extern_; - void visitNew(NewExp e) - { - if (e.thisexp) - { - expToBuffer(e.thisexp, PREC.primary, buf, hgs); - buf.writeByte('.'); + if (useTypeof) + stc &= ~STC.auto_; + + if (storageClassToBuffer(buf, stc)) + buf.writeByte(' '); + + if (v.type) + typeToBuffer(v.type, v.ident, buf); + else if (useTypeof) + { + buf.writestring("typeof("); + vinit(v); + buf.writestring(") "); + buf.writestring(v.ident.toString()); + } + else + buf.writestring(v.ident.toString()); } - buf.writestring("new "); - typeToBuffer(e.newtype, null, buf, hgs); - if (e.arguments && e.arguments.length) + + if (v._init && !isextern) { - buf.writeByte('('); - argsToBuffer(e.arguments, buf, hgs, null, e.names); - buf.writeByte(')'); + buf.writestring(" = "); + vinit(v); } + if (commentIt) + buf.writestring("+/"); } - void visitNewAnonClass(NewAnonClassExp e) + void typeToBufferx(Type t, ref OutBuffer buf) { - if (e.thisexp) + void visitVector(TypeVector t) { - expToBuffer(e.thisexp, PREC.primary, buf, hgs); - buf.writeByte('.'); + //printf("TypeVector::toCBuffer2(t.mod = %d)\n", t.mod); + buf.writestring("__vector("); + visitWithMask(t.basetype, t.mod, buf); + buf.writestring(")"); } - buf.writestring("new"); - buf.writestring(" class "); - if (e.arguments && e.arguments.length) + + void visitSArray(TypeSArray t) { - buf.writeByte('('); - argsToBuffer(e.arguments, buf, hgs); - buf.writeByte(')'); + visitWithMask(t.next, t.mod, buf); + buf.writeByte('['); + sizeToBuffer(t.dim, buf); + buf.writeByte(']'); } - if (e.cd) - e.cd.dsymbolToBuffer(buf, hgs); - } - - void visitSymOff(SymOffExp e) - { - if (e.offset) - buf.printf("(& %s%+lld)", e.var.toChars(), e.offset); - else if (e.var.isTypeInfoDeclaration()) - buf.writestring(e.var.toChars()); - else - buf.printf("& %s", e.var.toChars()); - } - - void visitVar(VarExp e) - { - buf.writestring(e.var.toChars()); - } - - void visitOver(OverExp e) - { - buf.writestring(e.vars.ident.toString()); - } - void visitTuple(TupleExp e) - { - if (e.e0) + void visitDArray(TypeDArray t) { - buf.writeByte('('); - e.e0.expressionPrettyPrint(buf, hgs); - buf.writestring(", AliasSeq!("); - argsToBuffer(e.exps, buf, hgs); - buf.writestring("))"); + Type ut = t.castMod(0); + if (this.declstring) + goto L1; + if (ut.equals(Type.tstring)) + buf.writestring("string"); + else if (ut.equals(Type.twstring)) + buf.writestring("wstring"); + else if (ut.equals(Type.tdstring)) + buf.writestring("dstring"); + else + { + L1: + visitWithMask(t.next, t.mod, buf); + buf.writestring("[]"); + } } - else + + void visitAArray(TypeAArray t) { - buf.writestring("AliasSeq!("); - argsToBuffer(e.exps, buf, hgs); - buf.writeByte(')'); + visitWithMask(t.next, t.mod, buf); + buf.writeByte('['); + visitWithMask(t.index, 0, buf); + buf.writeByte(']'); } - } - - void visitFunc(FuncExp e) - { - e.fd.dsymbolToBuffer(buf, hgs); - //buf.writestring(e.fd.toChars()); - } - void visitDeclaration(DeclarationExp e) - { - /* Normal dmd execution won't reach here - regular variable declarations - * are handled in visit(ExpStatement), so here would be used only when - * we'll directly call Expression.toChars() for debugging. - */ - if (e.declaration) + void visitPointer(TypePointer t) { - if (auto var = e.declaration.isVarDeclaration()) + //printf("TypePointer::toCBuffer2() next = %d\n", t.next.ty); + if (t.next.ty == Tfunction) + functionSignatureToBufferAsPostfix(cast(TypeFunction) t.next, + buf, "function", false); + else { - // For debugging use: - // - Avoid printing newline. - // - Intentionally use the format (Type var;) - // which isn't correct as regular D code. - buf.writeByte('('); - - visitVarDecl(var, false, buf, hgs); - - buf.writeByte(';'); - buf.writeByte(')'); + visitWithMask(t.next, t.mod, buf); + buf.writeByte('*'); } - else e.declaration.dsymbolToBuffer(buf, hgs); } - } - void visitTypeid(TypeidExp e) - { - buf.writestring("typeid("); - objectToBuffer(e.obj, buf, hgs); - buf.writeByte(')'); - } + void visitReference(TypeReference t) + { + visitWithMask(t.next, t.mod, buf); + buf.writeByte('&'); + } - void visitTraits(TraitsExp e) - { - buf.writestring("__traits("); - if (e.ident) - buf.writestring(e.ident.toString()); - if (e.args) + void visitTypeQualifiedHelper(TypeQualified t) { - foreach (arg; *e.args) + foreach (id; t.idents) { - buf.writestring(", "); - objectToBuffer(arg, buf, hgs); + switch (id.dyncast()) with (DYNCAST) + { + case dsymbol: + buf.writeByte('.'); + TemplateInstance ti = cast(TemplateInstance) id; + toCBuffer(ti, buf); + break; + case expression: + buf.writeByte('['); + expressionPrettyPrint(cast(Expression) id, buf); + buf.writeByte(']'); + break; + case type: + buf.writeByte('['); + typeToBufferx(cast(Type) id, buf); + buf.writeByte(']'); + break; + default: + buf.writeByte('.'); + buf.writestring(id.toString()); + } } } - buf.writeByte(')'); - } - - void visitHalt(HaltExp e) - { - buf.writestring("halt"); - } - void visitIs(IsExp e) - { - buf.writestring("is("); - typeToBuffer(e.targ, e.id, buf, hgs); - if (e.tok2 != TOK.reserved) + void visitIdentifier(TypeIdentifier t) { - buf.writeByte(' '); - buf.writestring(Token.toString(e.tok)); - buf.writeByte(' '); - buf.writestring(Token.toString(e.tok2)); + //printf("visitTypeIdentifier() %s\n", t.ident.toChars()); + buf.writestring(t.ident.toString()); + visitTypeQualifiedHelper(t); } - else if (e.tspec) + + void visitInstance(TypeInstance t) { - if (e.tok == TOK.colon) - buf.writestring(" : "); - else - buf.writestring(" == "); - typeToBuffer(e.tspec, null, buf, hgs); + toCBuffer(t.tempinst, buf); + visitTypeQualifiedHelper(t); } - if (e.parameters && e.parameters.length) + + void visitTypeof(TypeTypeof t) { - buf.writestring(", "); - visitTemplateParameters(e.parameters, buf, hgs); + buf.writestring("typeof("); + expressionPrettyPrint(t.exp, buf); + buf.writeByte(')'); + visitTypeQualifiedHelper(t); } - buf.writeByte(')'); - } - void visitUna(UnaExp e) - { - buf.writestring(EXPtoString(e.op)); - expToBuffer(e.e1, precedence[e.op], buf, hgs); - } - - void visitLoweredAssignExp(LoweredAssignExp e) - { - if (hgs.vcg_ast) + void visitEnum(TypeEnum t) { - expressionToBuffer(e.lowering, buf, hgs); - return; + //printf("visitEnum: %s\n", t.sym.toChars()); + buf.writestring(this.fullQual ? t.sym.toPrettyChars() : t.sym.toChars()); } - visit(cast(BinExp)e); - } - void visitBin(BinExp e) - { - expToBuffer(e.e1, precedence[e.op], buf, hgs); - buf.writeByte(' '); - buf.writestring(EXPtoString(e.op)); - buf.writeByte(' '); - expToBuffer(e.e2, cast(PREC)(precedence[e.op] + 1), buf, hgs); - } + void visitStruct(TypeStruct t) + { + //printf("visitTypeStruct() %s\n", t.sym.toChars()); - void visitComma(CommaExp e) - { - // CommaExp is generated by the compiler so it shouldn't - // appear in error messages or header files. - // For now, this treats the case where the compiler - // generates CommaExp for temporaries by calling - // the `sideeffect.copyToTemp` function. - auto ve = e.e2.isVarExp(); - - // not a CommaExp introduced for temporaries, go on - // the old path - if (!ve || !(ve.var.storage_class & STC.temp)) - { - visitBin(cast(BinExp)e); - return; + // https://issues.dlang.org/show_bug.cgi?id=13776 + // Don't use ti.toAlias() to avoid forward reference error + // while printing messages. + TemplateInstance ti = t.sym.parent ? t.sym.parent.isTemplateInstance() : null; + if (ti && ti.aliasdecl == t.sym) + buf.writestring(this.fullQual ? ti.toPrettyChars() : ti.toChars()); + else + buf.writestring(this.fullQual ? t.sym.toPrettyChars() : t.sym.toChars()); } - // CommaExp that contain temporaries inserted via - // `copyToTemp` are usually of the form - // ((T __temp = exp), __tmp). - // Asserts are here to easily spot - // missing cases where CommaExp - // are used for other constructs - auto vd = ve.var.isVarDeclaration(); - assert(vd && vd._init); - - if (auto ei = vd._init.isExpInitializer()) + void visitClass(TypeClass t) { - Expression commaExtract; - auto exp = ei.exp; - if (auto ce = exp.isConstructExp()) - commaExtract = ce.e2; - else if (auto se = exp.isStructLiteralExp()) - commaExtract = se; + // https://issues.dlang.org/show_bug.cgi?id=13776 + // Don't use ti.toAlias() to avoid forward reference error + // while printing messages. + TemplateInstance ti = t.sym.parent ? t.sym.parent.isTemplateInstance() : null; + if (ti && ti.aliasdecl == t.sym) + buf.writestring(this.fullQual ? ti.toPrettyChars() : ti.toChars()); + else + buf.writestring(this.fullQual ? t.sym.toPrettyChars() : t.sym.toChars()); + } - if (commaExtract) + void visitTag(TypeTag t) + { + if (t.mod & MODFlags.const_) + buf.writestring("const "); + if (this.importcHdr && t.id) { - expToBuffer(commaExtract, precedence[exp.op], buf, hgs); + buf.writestring(t.id.toString()); return; } + buf.writestring(Token.toString(t.tok)); + buf.writeByte(' '); + if (t.id) + buf.writestring(t.id.toString()); + if (t.tok == TOK.enum_ && t.base && t.base.ty != TY.Tint32) + { + buf.writestring(" : "); + visitWithMask(t.base, t.mod, buf); + } } - // not one of the known cases, go on the old path - visitBin(cast(BinExp)e); - return; - } - - void visitMixin(MixinExp e) - { - buf.writestring("mixin("); - argsToBuffer(e.exps, buf, hgs, null); - buf.writeByte(')'); - } - - void visitImport(ImportExp e) - { - buf.writestring("import("); - expToBuffer(e.e1, PREC.assign, buf, hgs); - buf.writeByte(')'); - } - - void visitAssert(AssertExp e) - { - buf.writestring("assert("); - expToBuffer(e.e1, PREC.assign, buf, hgs); - if (e.msg) + void visitSlice(TypeSlice t) { - buf.writestring(", "); - expToBuffer(e.msg, PREC.assign, buf, hgs); + visitWithMask(t.next, t.mod, buf); + buf.writeByte('['); + sizeToBuffer(t.lwr, buf); + buf.writestring(" .. "); + sizeToBuffer(t.upr, buf); + buf.writeByte(']'); } - buf.writeByte(')'); - } - void visitThrow(ThrowExp e) - { - buf.writestring("throw "); - expToBuffer(e.e1, PREC.unary, buf, hgs); - } + switch (t.ty) + { + default: + if (t.isTypeBasic()) + buf.writestring((cast(TypeBasic) t).dstring); + else + { + printf("t = %p, ty = %d\n", t, t.ty); + assert(0); + } + return; - void visitDotId(DotIdExp e) - { - expToBuffer(e.e1, PREC.primary, buf, hgs); - if (e.arrow) - buf.writestring("->"); - else - buf.writeByte('.'); - buf.writestring(e.ident.toString()); - } + case Tnoreturn: + buf.writestring("noreturn"); + return; + case Tnull: + buf.writestring("typeof(null)"); + return; + case Terror: + buf.writestring("_error_"); + return; - void visitDotTemplate(DotTemplateExp e) - { - expToBuffer(e.e1, PREC.primary, buf, hgs); - buf.writeByte('.'); - buf.writestring(e.td.toChars()); - } + case Ttuple: + parametersToBuffer(ParameterList((cast(TypeTuple) t).arguments, VarArg.none), buf); + return; + case Tdelegate: + functionSignatureToBufferAsPostfix(cast(TypeFunction)(cast(TypeDelegate) t) + .next, buf, "delegate", false); + return; + case Tfunction: + functionSignatureToBufferAsPostfix(cast(TypeFunction) t, buf, null, false); + return; + case Tmixin: + buf.writestring("mixin("); + argsToBuffer((cast(TypeMixin) t).exps, buf, null); + buf.writeByte(')'); + return; + case Treturn: + buf.writestring("typeof(return)"); + visitTypeQualifiedHelper(cast(TypeReturn) t); + return; + case Ttraits: + expressionPrettyPrint((cast(TypeTraits) t).exp, buf); + return; - void visitDotVar(DotVarExp e) - { - expToBuffer(e.e1, PREC.primary, buf, hgs); - buf.writeByte('.'); - buf.writestring(e.var.toChars()); - } + case Tvector: + return visitVector(cast(TypeVector) t); + case Tsarray: + return visitSArray(cast(TypeSArray) t); + case Tarray: + return visitDArray(cast(TypeDArray) t); + case Taarray: + return visitAArray(cast(TypeAArray) t); + case Tpointer: + return visitPointer(cast(TypePointer) t); + case Treference: + return visitReference(cast(TypeReference) t); + + case Tident: + return visitIdentifier(cast(TypeIdentifier) t); + case Tinstance: + return visitInstance(cast(TypeInstance) t); + case Ttypeof: + return visitTypeof(cast(TypeTypeof) t); + case Tenum: + return visitEnum(cast(TypeEnum) t); + case Tstruct: + return visitStruct(cast(TypeStruct) t); + case Tclass: + return visitClass(cast(TypeClass) t); + + case Tslice: + return visitSlice(cast(TypeSlice) t); + + case Ttag: + return visitTag(cast(TypeTag) t); + } + } + + void moduleToBuffer(Module m, ref OutBuffer buf) + { + if (m.md) + { + if (m.userAttribDecl) + { + buf.writestring("@("); + argsToBuffer(m.userAttribDecl.atts, buf); + buf.writeByte(')'); + buf.writenl(); + } + if (m.md.isdeprecated) + { + if (m.md.msg) + { + buf.writestring("deprecated("); + expressionPrettyPrint(m.md.msg, buf); + buf.writestring(") "); + } + else + buf.writestring("deprecated "); + } + buf.writestring("module "); + buf.writestring(m.md.toChars()); + buf.writeByte(';'); + buf.writenl(); + } - void visitDotTemplateInstance(DotTemplateInstanceExp e) - { - expToBuffer(e.e1, PREC.primary, buf, hgs); - buf.writeByte('.'); - e.ti.dsymbolToBuffer(buf, hgs); + foreach (s; *m.members) + { + toCBuffer(s, buf); + } } - void visitDelegate(DelegateExp e) + void dumpTemplateInstance(TemplateInstance ti, ref OutBuffer buf) { - buf.writeByte('&'); - if (!e.func.isNested() || e.func.needThis()) + buf.writeByte('{'); + buf.writenl(); + buf.level++; + + if (ti.aliasdecl) { - expToBuffer(e.e1, PREC.primary, buf, hgs); - buf.writeByte('.'); + this.toCBuffer(ti.aliasdecl, buf); + buf.writenl(); + } + else if (ti.members) + { + foreach (m; *ti.members) + this.toCBuffer(m, buf); } - buf.writestring(e.func.toChars()); - } - void visitDotType(DotTypeExp e) - { - expToBuffer(e.e1, PREC.primary, buf, hgs); - buf.writeByte('.'); - buf.writestring(e.sym.toChars()); + buf.level--; + buf.writeByte('}'); + buf.writenl(); } - void visitCall(CallExp e) + void tiargsToBuffer(TemplateInstance ti, ref OutBuffer buf) { - if (e.e1.op == EXP.type) + buf.writeByte('!'); + + if (ti.nest) { - /* Avoid parens around type to prevent forbidden cast syntax: - * (sometype)(arg1) - * This is ok since types in constructor calls - * can never depend on parens anyway - */ - e.e1.expressionPrettyPrint(buf, hgs); + buf.writestring("(...)"); + return; } - else - expToBuffer(e.e1, precedence[e.op], buf, hgs); - buf.writeByte('('); - argsToBuffer(e.arguments, buf, hgs, null, e.names); - buf.writeByte(')'); - } + else if (!ti.tiargs) + { + buf.writestring("()"); + return; + } + else if (ti.tiargs.length == 1) + { + RootObject oarg = (*ti.tiargs)[0]; - void visitPtr(PtrExp e) - { - buf.writeByte('*'); - expToBuffer(e.e1, precedence[e.op], buf, hgs); - } + if (Type t = isType(oarg)) + { + if (t.equals(Type.tstring) || t.equals(Type.twstring) + || t.equals(Type.tdstring) || t.mod == 0 && (t.isTypeBasic() + || t.ty == Tident && (cast(TypeIdentifier) t).idents.length == 0)) + { + HdrGenState hgs2 = this; // re-examine need for new hgs + hgs2.fullQual = (t.ty == Tclass && !t.mod); + hgs2.toCBuffer(t, buf, null); + return; + } + } + else if (Expression e = isExpression(oarg)) + { + if (e.op == EXP.int64 || e.op == EXP.float64 || e.op == EXP.null_ + || e.op == EXP.string_ || e.op == EXP.this_) + { + toCBuffer(e, buf); + return; + } + } + } - void visitDelete(DeleteExp e) - { - buf.writestring("delete "); - expToBuffer(e.e1, precedence[e.op], buf, hgs); - } + buf.writeByte('('); + ti.nestUp(); - void visitCast(CastExp e) - { - buf.writestring("cast("); - if (e.to) - typeToBuffer(e.to, null, buf, hgs); - else + foreach (i, arg; *ti.tiargs) { - MODtoBuffer(buf, e.mod); + if (i) + buf.writestring(", "); + + objectToBuffer(arg, buf); } - buf.writeByte(')'); - expToBuffer(e.e1, precedence[e.op], buf, hgs); - } - void visitVector(VectorExp e) - { - buf.writestring("cast("); - typeToBuffer(e.to, null, buf, hgs); + ti.nestDown(); buf.writeByte(')'); - expToBuffer(e.e1, precedence[e.op], buf, hgs); } - void visitVectorArray(VectorArrayExp e) + void statementToBuffer(Statement s, ref OutBuffer buf) { - expToBuffer(e.e1, PREC.primary, buf, hgs); - buf.writestring(".array"); - } + void visitDefaultCase(Statement s) + { + printf("Statement::toCBuffer() %d\n", s.stmt); + assert(0, "unrecognized statement in statementToBuffer()"); + } - void visitSlice(SliceExp e) - { - expToBuffer(e.e1, precedence[e.op], buf, hgs); - buf.writeByte('['); - if (e.upr || e.lwr) + void visitError(ErrorStatement s) { - if (e.lwr) - sizeToBuffer(e.lwr, buf, hgs); - else - buf.writeByte('0'); - buf.writestring(".."); - if (e.upr) - sizeToBuffer(e.upr, buf, hgs); - else - buf.writeByte('$'); + buf.writestring("__error__"); + buf.writenl(); } - buf.writeByte(']'); - } - void visitArrayLength(ArrayLengthExp e) - { - expToBuffer(e.e1, PREC.primary, buf, hgs); - buf.writestring(".length"); - } + void visitExp(ExpStatement s) + { + if (s.exp && s.exp.op == EXP.declaration && (cast(DeclarationExp) s.exp).declaration) + { + // bypass visit(DeclarationExp) + toCBuffer((cast(DeclarationExp) s.exp).declaration, buf); + return; + } - void visitInterval(IntervalExp e) - { - expToBuffer(e.lwr, PREC.assign, buf, hgs); - buf.writestring(".."); - expToBuffer(e.upr, PREC.assign, buf, hgs); - } + if (s.exp) + expressionPrettyPrint(s.exp, buf); - void visitDelegatePtr(DelegatePtrExp e) - { - expToBuffer(e.e1, PREC.primary, buf, hgs); - buf.writestring(".ptr"); - } + buf.writeByte(';'); - void visitDelegateFuncptr(DelegateFuncptrExp e) - { - expToBuffer(e.e1, PREC.primary, buf, hgs); - buf.writestring(".funcptr"); - } + if (!this.forStmtInit) + buf.writenl(); + } - void visitArray(ArrayExp e) - { - expToBuffer(e.e1, PREC.primary, buf, hgs); - buf.writeByte('['); - argsToBuffer(e.arguments, buf, hgs); - buf.writeByte(']'); - } + void visitDtorExp(DtorExpStatement s) + { + visitExp(s); + } - void visitDot(DotExp e) - { - expToBuffer(e.e1, PREC.primary, buf, hgs); - buf.writeByte('.'); - expToBuffer(e.e2, PREC.primary, buf, hgs); - } + void visitMixin(MixinStatement s) + { + buf.writestring("mixin("); + argsToBuffer(s.exps, buf, null); + buf.writestring(");"); - void visitIndex(IndexExp e) - { - expToBuffer(e.e1, PREC.primary, buf, hgs); - buf.writeByte('['); - sizeToBuffer(e.e2, buf, hgs); - buf.writeByte(']'); - } + if (!this.forStmtInit) + buf.writenl(); + } - void visitPost(PostExp e) - { - expToBuffer(e.e1, precedence[e.op], buf, hgs); - buf.writestring(EXPtoString(e.op)); - } + void visitCompound(CompoundStatement s) + { + foreach (sx; *s.statements) + { + if (sx) + statementToBuffer(sx, buf); + } + } - void visitPre(PreExp e) - { - buf.writestring(EXPtoString(e.op)); - expToBuffer(e.e1, precedence[e.op], buf, hgs); - } + void visitCompoundAsm(CompoundAsmStatement s) + { + visitCompound(s); + } - void visitRemove(RemoveExp e) - { - expToBuffer(e.e1, PREC.primary, buf, hgs); - buf.writestring(".remove("); - expToBuffer(e.e2, PREC.assign, buf, hgs); - buf.writeByte(')'); + void visitCompoundDeclaration(CompoundDeclarationStatement s) + { + bool anywritten = false; + + foreach (sx; *s.statements) + { + auto ds = sx ? sx.isExpStatement() : null; + if (ds && ds.exp.isDeclarationExp()) + { + auto d = ds.exp.isDeclarationExp().declaration; + + if (auto v = d.isVarDeclaration()) + { + visitVarDecl(v, anywritten, buf); + } + else + toCBuffer(d, buf); + + anywritten = true; + } + } + + buf.writeByte(';'); + if (!this.forStmtInit) + buf.writenl(); + } + + void visitUnrolledLoop(UnrolledLoopStatement s) + { + buf.writestring("/*unrolled*/ {"); + buf.writenl(); + buf.level++; + + foreach (sx; *s.statements) + { + if (sx) + statementToBuffer(sx, buf); + } + + buf.level--; + buf.writeByte('}'); + buf.writenl(); + } + + void visitScope(ScopeStatement s) + { + buf.writeByte('{'); + buf.writenl(); + buf.level++; + + if (s.statement) + statementToBuffer(s.statement, buf); + + buf.level--; + buf.writeByte('}'); + buf.writenl(); + } + + void visitWhile(WhileStatement s) + { + buf.writestring("while ("); + + if (auto p = s.param) + { + // Print condition assignment + StorageClass stc = p.storageClass; + + if (!p.type && !stc) + stc = STC.auto_; + + if (storageClassToBuffer(buf, stc)) + buf.writeByte(' '); + + if (p.type) + typeToBuffer(p.type, p.ident, buf); + else + buf.writestring(p.ident.toString()); + + buf.writestring(" = "); + } + + expressionPrettyPrint(s.condition, buf); + buf.writeByte(')'); + buf.writenl(); + + if (s._body) + statementToBuffer(s._body, buf); + } + + void visitDo(DoStatement s) + { + buf.writestring("do"); + buf.writenl(); + + if (s._body) + statementToBuffer(s._body, buf); + + buf.writestring("while ("); + expressionPrettyPrint(s.condition, buf); + buf.writestring(");"); + buf.writenl(); + } + + void visitFor(ForStatement s) + { + buf.writestring("for ("); + + if (s._init) + { + this.forStmtInit++; + statementToBuffer(s._init, buf); + this.forStmtInit--; + } + else + buf.writeByte(';'); + + if (s.condition) + { + buf.writeByte(' '); + expressionPrettyPrint(s.condition, buf); + } + + buf.writeByte(';'); + + if (s.increment) + { + buf.writeByte(' '); + expressionPrettyPrint(s.increment, buf); + } + + buf.writeByte(')'); + buf.writenl(); + buf.writeByte('{'); + buf.writenl(); + buf.level++; + + if (s._body) + statementToBuffer(s._body, buf); + + buf.level--; + buf.writeByte('}'); + buf.writenl(); + } + + void foreachWithoutBody(ForeachStatement s) + { + buf.writestring(Token.toString(s.op)); + buf.writestring(" ("); + + foreach (i, p; *s.parameters) + { + if (i) + buf.writestring(", "); + + if (storageClassToBuffer(buf, p.storageClass)) + buf.writeByte(' '); + + if (p.type) + typeToBuffer(p.type, p.ident, buf); + else + buf.writestring(p.ident.toString()); + } + + buf.writestring("; "); + expressionPrettyPrint(s.aggr, buf); + buf.writeByte(')'); + buf.writenl(); + } + + void visitForeach(ForeachStatement s) + { + foreachWithoutBody(s); + buf.writeByte('{'); + buf.writenl(); + buf.level++; + + if (s._body) + statementToBuffer(s._body, buf); + + buf.level--; + buf.writeByte('}'); + buf.writenl(); + } + + void foreachRangeWithoutBody(ForeachRangeStatement s) + { + buf.writestring(Token.toString(s.op)); + buf.writestring(" ("); + + if (s.prm.type) + typeToBuffer(s.prm.type, s.prm.ident, buf); + else + buf.writestring(s.prm.ident.toString()); + + buf.writestring("; "); + expressionPrettyPrint(s.lwr, buf); + buf.writestring(" .. "); + expressionPrettyPrint(s.upr, buf); + buf.writeByte(')'); + buf.writenl(); + } + + void visitForeachRange(ForeachRangeStatement s) + { + foreachRangeWithoutBody(s); + buf.writeByte('{'); + buf.writenl(); + buf.level++; + + if (s._body) + statementToBuffer(s._body, buf); + + buf.level--; + buf.writeByte('}'); + buf.writenl(); + } + + void visitStaticForeach(StaticForeachStatement s) + { + buf.writestring("static "); + + if (s.sfe.aggrfe) + { + visitForeach(s.sfe.aggrfe); + } + else + { + assert(s.sfe.rangefe); + visitForeachRange(s.sfe.rangefe); + } + } + + void visitForwarding(ForwardingStatement s) + { + statementToBuffer(s.statement, buf); + } + + void visitIf(IfStatement s) + { + buf.writestring("if ("); + + if (Parameter p = s.prm) + { + StorageClass stc = p.storageClass; + + if (!p.type && !stc) + stc = STC.auto_; + + if (storageClassToBuffer(buf, stc)) + buf.writeByte(' '); + + if (p.type) + typeToBuffer(p.type, p.ident, buf); + else + buf.writestring(p.ident.toString()); + + buf.writestring(" = "); + } + + expressionPrettyPrint(s.condition, buf); + buf.writeByte(')'); + buf.writenl(); + + if (s.ifbody.isScopeStatement()) + { + statementToBuffer(s.ifbody, buf); + } + else + { + buf.level++; + statementToBuffer(s.ifbody, buf); + buf.level--; + } + + if (s.elsebody) + { + buf.writestring("else"); + + if (!s.elsebody.isIfStatement()) + { + buf.writenl(); + } + else + { + buf.writeByte(' '); + } + + if (s.elsebody.isScopeStatement() || s.elsebody.isIfStatement()) + { + statementToBuffer(s.elsebody, buf); + } + else + { + buf.level++; + statementToBuffer(s.elsebody, buf); + buf.level--; + } + } + } + + void visitConditional(ConditionalStatement s) + { + conditionToBuffer(s.condition, buf); + + buf.writenl(); + buf.writeByte('{'); + buf.writenl(); + buf.level++; + + if (s.ifbody) + statementToBuffer(s.ifbody, buf); + + buf.level--; + buf.writeByte('}'); + buf.writenl(); + + if (s.elsebody) + { + buf.writestring("else"); + buf.writenl(); + buf.writeByte('{'); + buf.level++; + buf.writenl(); + statementToBuffer(s.elsebody, buf); + buf.level--; + buf.writeByte('}'); + } + + buf.writenl(); + } + + void visitPragma(PragmaStatement s) + { + buf.writestring("pragma ("); + buf.writestring(s.ident.toString()); + + if (s.args && s.args.length) + { + buf.writestring(", "); + argsToBuffer(s.args, buf); + } + + buf.writeByte(')'); + + if (s._body) + { + buf.writenl(); + buf.writeByte('{'); + buf.writenl(); + buf.level++; + statementToBuffer(s._body, buf); + buf.level--; + buf.writeByte('}'); + buf.writenl(); + } + else + { + buf.writeByte(';'); + buf.writenl(); + } + } + + void visitStaticAssert(StaticAssertStatement s) + { + toCBuffer(s.sa, buf); + } + + void visitSwitch(SwitchStatement s) + { + buf.writestring(s.isFinal ? "final switch (" : "switch ("); + + if (auto p = s.param) + { + // Print condition assignment + StorageClass stc = p.storageClass; + + if (!p.type && !stc) + stc = STC.auto_; + + if (storageClassToBuffer(buf, stc)) + buf.writeByte(' '); + + if (p.type) + typeToBuffer(p.type, p.ident, buf); + else + buf.writestring(p.ident.toString()); + + buf.writestring(" = "); + } + + expressionPrettyPrint(s.condition, buf); + buf.writeByte(')'); + buf.writenl(); + + if (s._body) + { + if (!s._body.isScopeStatement()) + { + buf.writeByte('{'); + buf.writenl(); + buf.level++; + statementToBuffer(s._body, buf); + buf.level--; + buf.writeByte('}'); + buf.writenl(); + } + else + { + statementToBuffer(s._body, buf); + } + } + } + + void visitCase(CaseStatement s) + { + buf.writestring("case "); + expressionPrettyPrint(s.exp, buf); + buf.writeByte(':'); + buf.writenl(); + statementToBuffer(s.statement, buf); + } + + void visitCaseRange(CaseRangeStatement s) + { + buf.writestring("case "); + expressionPrettyPrint(s.first, buf); + buf.writestring(": .. case "); + expressionPrettyPrint(s.last, buf); + buf.writeByte(':'); + buf.writenl(); + statementToBuffer(s.statement, buf); + } + + void visitDefault(DefaultStatement s) + { + buf.writestring("default:"); + buf.writenl(); + statementToBuffer(s.statement, buf); + } + + void visitGotoDefault(GotoDefaultStatement s) + { + buf.writestring("goto default;"); + buf.writenl(); + } + + void visitGotoCase(GotoCaseStatement s) + { + buf.writestring("goto case"); + + if (s.exp) + { + buf.writeByte(' '); + expressionPrettyPrint(s.exp, buf); + } + + buf.writeByte(';'); + buf.writenl(); + } + + void visitSwitchError(SwitchErrorStatement s) + { + buf.writestring("SwitchErrorStatement::toCBuffer()"); + buf.writenl(); + } + + void visitReturn(ReturnStatement s) + { + buf.writestring("return "); + + if (s.exp) + expressionPrettyPrint(s.exp, buf); + + buf.writeByte(';'); + buf.writenl(); + } + + void visitBreak(BreakStatement s) + { + buf.writestring("break"); + + if (s.ident) + { + buf.writeByte(' '); + buf.writestring(s.ident.toString()); + } + + buf.writeByte(';'); + buf.writenl(); + } + + void visitContinue(ContinueStatement s) + { + buf.writestring("continue"); + + if (s.ident) + { + buf.writeByte(' '); + buf.writestring(s.ident.toString()); + } + + buf.writeByte(';'); + buf.writenl(); + } + + void visitSynchronized(SynchronizedStatement s) + { + buf.writestring("synchronized"); + + if (s.exp) + { + buf.writeByte('('); + expressionPrettyPrint(s.exp, buf); + buf.writeByte(')'); + } + + if (s._body) + { + buf.writeByte(' '); + statementToBuffer(s._body, buf); + } + } + + void visitWith(WithStatement s) + { + buf.writestring("with ("); + expressionPrettyPrint(s.exp, buf); + buf.writestring(")"); + buf.writenl(); + + if (s._body) + statementToBuffer(s._body, buf); + } + + void visitTryCatch(TryCatchStatement s) + { + buf.writestring("try"); + buf.writenl(); + + if (s._body) + { + if (s._body.isScopeStatement()) + { + statementToBuffer(s._body, buf); + } + else + { + buf.level++; + statementToBuffer(s._body, buf); + buf.level--; + } + } + + foreach (c; *s.catches) + { + buf.writestring("catch"); + + if (c.type) + { + buf.writeByte('('); + typeToBuffer(c.type, c.ident, buf); + buf.writeByte(')'); + } + + buf.writenl(); + buf.writeByte('{'); + buf.writenl(); + buf.level++; + + if (c.handler) + statementToBuffer(c.handler, buf); + + buf.level--; + buf.writeByte('}'); + buf.writenl(); + } + } + + void visitTryFinally(TryFinallyStatement s) + { + buf.writestring("try"); + buf.writenl(); + buf.writeByte('{'); + buf.writenl(); + buf.level++; + statementToBuffer(s._body, buf); + buf.level--; + buf.writeByte('}'); + buf.writenl(); + buf.writestring("finally"); + buf.writenl(); + + if (s.finalbody.isScopeStatement()) + { + statementToBuffer(s.finalbody, buf); + } + else + { + buf.level++; + statementToBuffer(s.finalbody, buf); + buf.level--; + } + } + + void visitScopeGuard(ScopeGuardStatement s) + { + buf.writestring(Token.toString(s.tok)); + buf.writeByte(' '); + + if (s.statement) + statementToBuffer(s.statement, buf); + } + + void visitThrow(ThrowStatement s) + { + buf.writestring("throw "); + expressionPrettyPrint(s.exp, buf); + buf.writeByte(';'); + buf.writenl(); + } + + void visitDebug(DebugStatement s) + { + if (s.statement) + { + statementToBuffer(s.statement, buf); + } + } + + void visitGoto(GotoStatement s) + { + buf.writestring("goto "); + buf.writestring(s.ident.toString()); + buf.writeByte(';'); + buf.writenl(); + } + + void visitLabel(LabelStatement s) + { + buf.writestring(s.ident.toString()); + buf.writeByte(':'); + buf.writenl(); + + if (s.statement) + statementToBuffer(s.statement, buf); + } + + void visitAsm(AsmStatement s) + { + buf.writestring("asm { "); + Token* t = s.tokens; + buf.level++; + + while (t) + { + buf.writestring(t.toString()); + + if (t.next && t.value != TOK.min && t.value != TOK.comma + && t.next.value != TOK.comma && t.value != TOK.leftBracket + && t.next.value != TOK.leftBracket && t.next.value != TOK.rightBracket + && t.value != TOK.leftParenthesis && t.next.value != TOK.leftParenthesis + && t.next.value != TOK.rightParenthesis + && t.value != TOK.dot && t.next.value != TOK.dot) + { + buf.writeByte(' '); + } + + t = t.next; + } + + buf.level--; + buf.writestring("; }"); + buf.writenl(); + } + + void visitInlineAsm(InlineAsmStatement s) + { + visitAsm(s); + } + + void visitGccAsm(GccAsmStatement s) + { + visitAsm(s); + } + + void visitImport(ImportStatement s) + { + foreach (imp; *s.imports) + { + toCBuffer(imp, buf); + } + } + + mixin VisitStatement!void visit; + visit.VisitStatement(s); + } + + void conditionToBuffer(Condition c, ref OutBuffer buf) + { + scope v = new ConditionPrettyPrintVisitor; + v.buf = &buf; + v.hgs = &this; + + c.accept(v); + } + + // Gives stronger control over identifier and parameters to emit. + void writeTypeFunctionAttributes(TypeFunction tf, ref OutBuffer buf, ulong lhsStorageClasses, + ulong rhsStorageClasses, scope void delegate(TypeFunction) writeFuncDel) + { + { + // Prefix storage classes, used for semantic 3 + + if (storageClassToBuffer(buf, lhsStorageClasses)) + buf.writeByte(' '); + } + + writeFuncDel(tf); + + { + // postfix attributes and storage classes + + void postfixWriteAttribute(string str) + { + buf.writeByte(' '); + buf.writestring(str); + } + + // Used for when semantic < 3 + const stcOffset = buf.length; + const wroteSTCPostfix = storageClassToBuffer(buf, rhsStorageClasses); + + if (wroteSTCPostfix) + { + buf.insert(stcOffset, " "); + } + else if (tf !is null) + { + if (tf.mod) + { + buf.writeByte(' '); + MODtoBuffer(buf, tf.mod); + } + + tf.attributesApply(&postfixWriteAttribute); + } + } } - void visitCond(CondExp e) - { - expToBuffer(e.econd, PREC.oror, buf, hgs); - buf.writestring(" ? "); - expToBuffer(e.e1, PREC.expr, buf, hgs); - buf.writestring(" : "); - expToBuffer(e.e2, PREC.cond, buf, hgs); - } + extern (C++) final class DsymbolPrettyPrintVisitor : Visitor + { + alias visit = Visitor.visit; + + HdrGenState* hgs; + OutBuffer* buf; + bool doTrace; + + extern (D) void trace(string func = __PRETTY_FUNCTION__) + { + if (!doTrace) + return; + + enum ToSlice = "extern (C++) void dmd.hdrgen.HdrGenState.DsymbolPrettyPrintVisitor."; + + printf("%*s %s\n", hgs.childCountOfModule * 2, "".ptr, func[ToSlice.length .. $].ptr); + } + + public: + void visitBaseClasses(ClassDeclaration d) + { + if (!d || !d.baseclasses.length) + return; + + size_t i; + foreach (b; *d.baseclasses) + { + if (b.sym !is ClassDeclaration.object) + { + if (i) + buf.writestring(", "); + else if (!d.isAnonymous()) + buf.writestring(" : "); + + i++; + hgs.typeToBuffer(b.type, null, *buf); + } + } + } + + bool visitEponymousMember(TemplateDeclaration d) + { + if (!d.members || d.members.length != 1) + return false; + + Dsymbol onemember = (*d.members)[0]; + if (onemember.ident != d.ident) + return false; + + if (FuncDeclaration fd = onemember.isFuncDeclaration()) + { + assert(fd.type); + if (storageClassToBuffer(*buf, fd.storage_class)) + buf.writeByte(' '); + + hgs.functionSignatureToBuffer(cast(TypeFunction) fd.type, *buf, d.ident, d); + visitTemplateConstraint(d.constraint); + + hgs.tpltMember++; + bodyToBuffer(fd); + hgs.tpltMember--; + + return true; + } + else if (AggregateDeclaration ad = onemember.isAggregateDeclaration()) + { + buf.writestring(ad.kind()); + buf.writeByte(' '); + buf.writestring(ad.ident.toString()); + buf.writeByte('('); + hgs.visitTemplateParameters(hgs.ddoc ? d.origParameters : d.parameters, *buf); + buf.writeByte(')'); + visitTemplateConstraint(d.constraint); + visitBaseClasses(ad.isClassDeclaration()); + hgs.tpltMember++; + + if (ad.members) + { + buf.writenl(); + buf.writeByte('{'); + buf.writenl(); + buf.level++; + + foreach (s; *ad.members) + hgs.toCBuffer(s, *buf); + + buf.level--; + buf.writeByte('}'); + } + else + buf.writeByte(';'); + + buf.writenl(); + hgs.tpltMember--; + return true; + } + else if (VarDeclaration vd = onemember.isVarDeclaration()) + { + if (d.constraint) + return false; + else if (storageClassToBuffer(*buf, vd.storage_class)) + buf.writeByte(' '); + + if (vd.type) + hgs.typeToBuffer(vd.type, vd.ident, *buf); + else + buf.writestring(vd.ident.toString()); + + buf.writeByte('('); + hgs.visitTemplateParameters(hgs.ddoc ? d.origParameters : d.parameters, *buf); + buf.writeByte(')'); + + if (vd._init) + { + buf.writestring(" = "); + ExpInitializer ie = vd._init.isExpInitializer(); + + if (ie && (ie.exp.op == EXP.construct || ie.exp.op == EXP.blit)) + hgs.expressionPrettyPrint((cast(AssignExp) ie.exp).e2, *buf); + else + hgs.initializerToBuffer(vd._init, *buf); + } + + buf.writeByte(';'); + buf.writenl(); + return true; + } + + return false; + } + + void bodyToBuffer(FuncDeclaration f) + { + if (!f.fbody || (hgs.hdrgen && hgs.doFuncBodies == false + && !hgs.autoMember && !hgs.tpltMember && !hgs.insideFuncBody)) + { + if (!f.fbody && (f.fensures || f.frequires)) + { + buf.writenl(); + contractsToBuffer(f); + } + + buf.writeByte(';'); + buf.writenl(); + return; + } + + // there is no way to know if a function is nested + // or not after parsing. We need scope information + // for that, which is avaible during semantic + // analysis. To overcome that, a simple mechanism + // is implemented: everytime we print a function + // body (templated or not) we increment a counter. + // We decredement the counter when we stop + // printing the function body. + ++hgs.insideFuncBody; + scope (exit) + { + --hgs.insideFuncBody; + } + + const savetlpt = hgs.tpltMember; + const saveauto = hgs.autoMember; + hgs.tpltMember = 0; + hgs.autoMember = 0; + buf.writenl(); + bool requireDo = contractsToBuffer(f); + + if (requireDo) + { + buf.writestring("do"); + buf.writenl(); + } + + buf.writeByte('{'); + buf.writenl(); + buf.level++; + hgs.statementToBuffer(f.fbody, *buf); + buf.level--; + buf.writeByte('}'); + buf.writenl(); + + hgs.tpltMember = savetlpt; + hgs.autoMember = saveauto; + } + + void visitTemplateConstraint(Expression constraint) + { + if (!constraint) + return; + + buf.writestring(" if ("); + hgs.expressionPrettyPrint(constraint, *buf); + buf.writeByte(')'); + } + + /// Returns: whether `do` is needed to write the function body + bool contractsToBuffer(FuncDeclaration f) + { + bool requireDo = false; // in{} + + if (f.frequires) + { + foreach (frequire; *f.frequires) + { + buf.writestring("in"); + if (auto es = frequire.isExpStatement()) + { + assert(es.exp && es.exp.op == EXP.assert_); + buf.writestring(" ("); + hgs.expressionPrettyPrint((cast(AssertExp) es.exp).e1, *buf); + buf.writeByte(')'); + buf.writenl(); + requireDo = false; + } + else + { + buf.writenl(); + hgs.statementToBuffer(frequire, *buf); + requireDo = true; + } + } + } + + // out{} + if (f.fensures) + { + foreach (fensure; *f.fensures) + { + buf.writestring("out"); + + if (auto es = fensure.ensure.isExpStatement()) + { + assert(es.exp && es.exp.op == EXP.assert_); + buf.writestring(" ("); + + if (fensure.id) + { + buf.writestring(fensure.id.toString()); + } + + buf.writestring("; "); + hgs.expressionPrettyPrint((cast(AssertExp) es.exp).e1, *buf); + buf.writeByte(')'); + buf.writenl(); + requireDo = false; + } + else + { + if (fensure.id) + { + buf.writeByte('('); + buf.writestring(fensure.id.toString()); + buf.writeByte(')'); + } + + buf.writenl(); + hgs.statementToBuffer(fensure.ensure, *buf); + requireDo = true; + } + } + } + + return requireDo; + } + + void visitAttribDeclaration(AttribDeclaration d) + { + bool hasSTC; + if (auto stcd = d.isStorageClassDeclaration) + { + hasSTC = storageClassToBuffer(*buf, stcd.stc); + } + + if (!d.decl) + { + buf.writeByte(';'); + buf.writenl(); + return; + } + + if (d.decl.length == 0 || (hgs.hdrgen && d.decl.length == 1 + && (*d.decl)[0].isUnitTestDeclaration())) + { + // hack for https://issues.dlang.org/show_bug.cgi?id=8081 + if (hasSTC) + buf.writeByte(' '); + buf.writestring("{}"); + } + else if (d.decl.length == 1) + { + if (hasSTC) + buf.writeByte(' '); + hgs.toCBuffer((*d.decl)[0], *buf); + return; + } + else + { + buf.writenl(); + buf.writeByte('{'); + buf.writenl(); + buf.level++; + + foreach (de; *d.decl) + hgs.toCBuffer(de, *buf); + + buf.level--; + buf.writeByte('}'); + } + + buf.writenl(); + } - void visitDefaultInit(DefaultInitExp e) - { - buf.writestring(EXPtoString(e.op)); - } + override: - void visitClassReference(ClassReferenceExp e) - { - buf.writestring(e.value.toChars()); - } + void visit(Dsymbol s) + { + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; - switch (e.op) - { - default: - if (auto be = e.isBinExp()) - return visitBin(be); - else if (auto ue = e.isUnaExp()) - return visitUna(ue); - else if (auto de = e.isDefaultInitExp()) - return visitDefaultInit(e.isDefaultInitExp()); - return visit(e); - - case EXP.int64: return visitInteger(e.isIntegerExp()); - case EXP.error: return visitError(e.isErrorExp()); - case EXP.void_: return visitVoidInit(e.isVoidInitExp()); - case EXP.float64: return visitReal(e.isRealExp()); - case EXP.complex80: return visitComplex(e.isComplexExp()); - case EXP.identifier: return visitIdentifier(e.isIdentifierExp()); - case EXP.dSymbol: return visitDsymbol(e.isDsymbolExp()); - case EXP.this_: return visitThis(e.isThisExp()); - case EXP.super_: return visitSuper(e.isSuperExp()); - case EXP.null_: return visitNull(e.isNullExp()); - case EXP.string_: return visitString(e.isStringExp()); - case EXP.interpolated: return visitInterpolation(e.isInterpExp()); - case EXP.arrayLiteral: return visitArrayLiteral(e.isArrayLiteralExp()); - case EXP.assocArrayLiteral: return visitAssocArrayLiteral(e.isAssocArrayLiteralExp()); - case EXP.structLiteral: return visitStructLiteral(e.isStructLiteralExp()); - case EXP.compoundLiteral: return visitCompoundLiteral(e.isCompoundLiteralExp()); - case EXP.type: return visitType(e.isTypeExp()); - case EXP.scope_: return visitScope(e.isScopeExp()); - case EXP.template_: return visitTemplate(e.isTemplateExp()); - case EXP.new_: return visitNew(e.isNewExp()); - case EXP.newAnonymousClass: return visitNewAnonClass(e.isNewAnonClassExp()); - case EXP.symbolOffset: return visitSymOff(e.isSymOffExp()); - case EXP.variable: return visitVar(e.isVarExp()); - case EXP.overloadSet: return visitOver(e.isOverExp()); - case EXP.tuple: return visitTuple(e.isTupleExp()); - case EXP.function_: return visitFunc(e.isFuncExp()); - case EXP.declaration: return visitDeclaration(e.isDeclarationExp()); - case EXP.typeid_: return visitTypeid(e.isTypeidExp()); - case EXP.traits: return visitTraits(e.isTraitsExp()); - case EXP.halt: return visitHalt(e.isHaltExp()); - case EXP.is_: return visitIs(e.isExp()); - case EXP.comma: return visitComma(e.isCommaExp()); - case EXP.mixin_: return visitMixin(e.isMixinExp()); - case EXP.import_: return visitImport(e.isImportExp()); - case EXP.assert_: return visitAssert(e.isAssertExp()); - case EXP.throw_: return visitThrow(e.isThrowExp()); - case EXP.dotIdentifier: return visitDotId(e.isDotIdExp()); - case EXP.dotTemplateDeclaration: return visitDotTemplate(e.isDotTemplateExp()); - case EXP.dotVariable: return visitDotVar(e.isDotVarExp()); - case EXP.dotTemplateInstance: return visitDotTemplateInstance(e.isDotTemplateInstanceExp()); - case EXP.delegate_: return visitDelegate(e.isDelegateExp()); - case EXP.dotType: return visitDotType(e.isDotTypeExp()); - case EXP.call: return visitCall(e.isCallExp()); - case EXP.star: return visitPtr(e.isPtrExp()); - case EXP.delete_: return visitDelete(e.isDeleteExp()); - case EXP.cast_: return visitCast(e.isCastExp()); - case EXP.vector: return visitVector(e.isVectorExp()); - case EXP.vectorArray: return visitVectorArray(e.isVectorArrayExp()); - case EXP.slice: return visitSlice(e.isSliceExp()); - case EXP.arrayLength: return visitArrayLength(e.isArrayLengthExp()); - case EXP.interval: return visitInterval(e.isIntervalExp()); - case EXP.delegatePointer: return visitDelegatePtr(e.isDelegatePtrExp()); - case EXP.delegateFunctionPointer: return visitDelegateFuncptr(e.isDelegateFuncptrExp()); - case EXP.array: return visitArray(e.isArrayExp()); - case EXP.dot: return visitDot(e.isDotExp()); - case EXP.index: return visitIndex(e.isIndexExp()); - case EXP.minusMinus: - case EXP.plusPlus: return visitPost(e.isPostExp()); - case EXP.preMinusMinus: - case EXP.prePlusPlus: return visitPre(e.isPreExp()); - case EXP.remove: return visitRemove(e.isRemoveExp()); - case EXP.question: return visitCond(e.isCondExp()); - case EXP.classReference: return visitClassReference(e.isClassReferenceExp()); - case EXP.loweredAssignExp: return visitLoweredAssignExp(e.isLoweredAssignExp()); - } -} + buf.writestring(s.toChars()); + } -/** - * Formats `value` as a literal of type `type` into `buf`. - * - * Params: - * type = literal type (e.g. Tfloat) - * value = value to print - * buf = target buffer - * allowHex = whether hex floating point literals may be used - * for greater accuracy - */ -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". - (ie, 8 chars more than mantissa). Plus one for trailing \0. - Plus one for rounding. */ - const(size_t) BUFFER_LEN = value.sizeof * 3 + 8 + 1 + 1; - char[BUFFER_LEN] buffer = void; - CTFloat.sprint(buffer.ptr, BUFFER_LEN, 'g', value); - assert(strlen(buffer.ptr) < BUFFER_LEN); - if (allowHex) - { - bool isOutOfRange; - real_t r = CTFloat.parse(buffer.ptr, isOutOfRange); - //assert(!isOutOfRange); // test/compilable/test22725.c asserts here - if (r != value) // if exact duplication - CTFloat.sprint(buffer.ptr, BUFFER_LEN, 'a', value); - } - buf.writestring(buffer.ptr); - if (buffer.ptr[strlen(buffer.ptr) - 1] == '.') - buf.remove(buf.length() - 1, 1); + void visit(StaticAssert s) + { + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; - if (type) - { - Type t = type.toBasetype(); - switch (t.ty) + buf.writestring(s.kind()); + buf.writeByte('('); + hgs.expressionPrettyPrint(s.exp, *buf); + + if (s.msgs) + { + foreach (m; (*s.msgs)[]) + { + buf.writestring(", "); + hgs.expressionPrettyPrint(m, *buf); + } + } + + buf.writestring(");"); + buf.writenl(); + } + + void visit(DebugSymbol s) { - case Tfloat32: - case Timaginary32: - case Tcomplex32: - buf.writeByte('F'); - break; - case Tfloat80: - case Timaginary80: - case Tcomplex80: - buf.writeByte('L'); - break; - default: - break; + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; + + buf.writestring("debug = "); + if (s.ident) + buf.writestring(s.ident.toString()); + else + buf.print(s.level); + buf.writeByte(';'); + buf.writenl(); } - if (t.isimaginary()) - buf.writeByte('i'); - } -} -void toCBuffer(const TemplateParameter tp, ref OutBuffer buf, ref HdrGenState hgs) -{ - scope v = new TemplateParameterPrettyPrintVisitor(&buf, &hgs); - (cast() tp).accept(v); -} + void visit(VersionSymbol s) + { + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; -private extern (C++) final class TemplateParameterPrettyPrintVisitor : Visitor -{ - alias visit = Visitor.visit; -public: - OutBuffer* buf; - HdrGenState* hgs; + buf.writestring("version = "); + if (s.ident) + buf.writestring(s.ident.toString()); + else + buf.print(s.level); + buf.writeByte(';'); + buf.writenl(); + } - extern (D) this(OutBuffer* buf, HdrGenState* hgs) scope @safe - { - this.buf = buf; - this.hgs = hgs; - } + void visit(EnumMember em) + { + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; - override void visit(TemplateTypeParameter tp) - { - buf.writestring(tp.ident.toString()); - if (tp.specType) + assert(em.ident !is null, "ICE: Enum member identifier is null"); + buf.writestring(em.ident.toString()); + + if (em.value) + { + buf.writestring(" = "); + hgs.expressionPrettyPrint(em.value, *buf); + } + } + + void visit(Import imp) { - buf.writestring(" : "); - typeToBuffer(tp.specType, null, *buf, *hgs); + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; + + if (hgs.hdrgen && imp.id == Id.object) + return; // object is imported by default + else if (imp.isstatic) + buf.writestring("static "); + + buf.writestring("import "); + + if (imp.aliasId) + { + buf.printf("%s = ", imp.aliasId.toChars()); + } + + foreach (const pid; imp.packages) + { + buf.write(pid.toString()); + buf.writeByte('.'); + } + + buf.writestring(imp.id.toString()); + + if (imp.names.length) + { + buf.writestring(" : "); + + foreach (const i, const name; imp.names) + { + if (i) + buf.writestring(", "); + + const _alias = imp.aliases[i]; + + if (_alias) + buf.printf("%s = %s", _alias.toChars(), name.toChars()); + else + buf.writestring(name.toChars()); + } + } + + buf.writeByte(';'); + buf.writenl(); } - if (tp.defaultType) + + void visit(AliasThis d) { - buf.writestring(" = "); - typeToBuffer(tp.defaultType, null, *buf, *hgs); + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; + + buf.writestring("alias "); + buf.writestring(d.ident.toString()); + buf.writestring(" this;\n"); } - } - override void visit(TemplateThisParameter tp) - { - buf.writestring("this "); - visit(cast(TemplateTypeParameter)tp); - } + void visit(AttribDeclaration d) + { + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; - override void visit(TemplateAliasParameter tp) - { - buf.writestring("alias "); - if (tp.specType) - typeToBuffer(tp.specType, tp.ident, *buf, *hgs); - else - buf.writestring(tp.ident.toString()); - if (tp.specAlias) + visitAttribDeclaration(d); + } + + void visit(StorageClassDeclaration d) { - buf.writestring(" : "); - objectToBuffer(tp.specAlias, *buf, *hgs); + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; + + visitAttribDeclaration(d); } - if (tp.defaultAlias) + + void visit(DeprecatedDeclaration d) { - buf.writestring(" = "); - objectToBuffer(tp.defaultAlias, *buf, *hgs); + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; + + buf.writestring("deprecated("); + hgs.expressionPrettyPrint(d.msg, *buf); + buf.writestring(") "); + + visitAttribDeclaration(d); } - } - override void visit(TemplateValueParameter tp) - { - typeToBuffer(tp.valType, tp.ident, *buf, *hgs); - if (tp.specValue) + void visit(LinkDeclaration d) { - buf.writestring(" : "); - tp.specValue.expressionToBuffer(*buf, *hgs); + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; + + buf.writestring("extern ("); + buf.writestring(linkageToString(d.linkage)); + buf.writestring(") "); + visitAttribDeclaration(d); } - if (tp.defaultValue) + + void visit(CPPMangleDeclaration d) { - buf.writestring(" = "); - tp.defaultValue.expressionToBuffer(*buf, *hgs); + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; + + string s; + final switch (d.cppmangle) + { + case CPPMANGLE.asClass: + s = "class"; + break; + case CPPMANGLE.asStruct: + s = "struct"; + break; + case CPPMANGLE.def: + break; + } + + buf.writestring("extern (C++, "); + buf.writestring(s); + buf.writestring(") "); + + visitAttribDeclaration(d); } - } - override void visit(TemplateTupleParameter tp) - { - buf.writestring(tp.ident.toString()); - buf.writestring("..."); - } -} + void visit(VisibilityDeclaration d) + { + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; -private void conditionToBuffer(Condition c, ref OutBuffer buf, ref HdrGenState hgs) -{ - scope v = new ConditionPrettyPrintVisitor(&buf, &hgs); - c.accept(v); -} + visibilityToBuffer(*buf, d.visibility); + AttribDeclaration ad = cast(AttribDeclaration) d; -private extern (C++) final class ConditionPrettyPrintVisitor : Visitor -{ - alias visit = Visitor.visit; -public: - OutBuffer* buf; - HdrGenState* hgs; + if (ad.decl.length <= 1) + buf.writeByte(' '); + + if (ad.decl.length == 1 && (*ad.decl)[0].isVisibilityDeclaration) + visitAttribDeclaration((*ad.decl)[0].isVisibilityDeclaration); + else + visitAttribDeclaration(d); + } + + void visit(AlignDeclaration d) + { + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; + + if (d.exps) + { + foreach (i, exp; (*d.exps)[]) + { + if (i) + buf.writeByte(' '); + + buf.writestring("align ("); + hgs.toCBuffer(exp, *buf); + buf.writeByte(')'); + } + + if (d.decl && d.decl.length < 2) + buf.writeByte(' '); + } + else + buf.writestring("align "); + + visitAttribDeclaration(d.isAttribDeclaration()); + } + + void visit(AnonDeclaration d) + { + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; + + buf.writestring(d.isunion ? "union" : "struct"); + buf.writenl(); + buf.writestring("{"); + buf.writenl(); + buf.level++; + + if (d.decl) + { + foreach (de; *d.decl) + hgs.toCBuffer(de, *buf); + } + + buf.level--; + buf.writestring("}"); + buf.writenl(); + } + + void visit(PragmaDeclaration d) + { + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; + + buf.writestring("pragma ("); + buf.writestring(d.ident.toString()); + + if (d.args && d.args.length) + { + buf.writestring(", "); + hgs.argsToBuffer(d.args, *buf); + } + + buf.writeByte(')'); + + // https://issues.dlang.org/show_bug.cgi?id=14690 + // Unconditionally perform a full output dump + // for `pragma(inline)` declarations. + const saved = hgs.doFuncBodies; + if (d.ident == Id.Pinline) + hgs.doFuncBodies = true; + + visitAttribDeclaration(d); + hgs.doFuncBodies = saved; + } + + void visit(ConditionalDeclaration d) + { + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; + + hgs.conditionToBuffer(d.condition, *buf); + + if (d.decl || d.elsedecl) + { + buf.writenl(); + buf.writeByte('{'); + buf.writenl(); + buf.level++; + + if (d.decl) + { + foreach (de; *d.decl) + hgs.toCBuffer(de, *buf); + } + + buf.level--; + buf.writeByte('}'); + + if (d.elsedecl) + { + buf.writenl(); + buf.writestring("else"); + buf.writenl(); + buf.writeByte('{'); + buf.writenl(); + buf.level++; + + foreach (de; *d.elsedecl) + hgs.toCBuffer(de, *buf); + + buf.level--; + buf.writeByte('}'); + } + } + else + buf.writeByte(':'); + + buf.writenl(); + } + + void visit(StaticForeachDeclaration s) + { + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; + + void foreachWithoutBody(ForeachStatement s) + { + buf.writestring(Token.toString(s.op)); + buf.writestring(" ("); + + foreach (i, p; *s.parameters) + { + if (i) + buf.writestring(", "); + + if (storageClassToBuffer(*buf, p.storageClass)) + buf.writeByte(' '); + + if (p.type) + hgs.typeToBuffer(p.type, p.ident, *buf); + else + buf.writestring(p.ident.toString()); + } + + buf.writestring("; "); + hgs.expressionPrettyPrint(s.aggr, *buf); + buf.writeByte(')'); + buf.writenl(); + } - extern (D) this(OutBuffer* buf, HdrGenState* hgs) scope @safe - { - this.buf = buf; - this.hgs = hgs; - } + void foreachRangeWithoutBody(ForeachRangeStatement s) + { + // s.op ( prm ; lwr .. upr ) + buf.writestring(Token.toString(s.op)); + buf.writestring(" ("); - override void visit(DebugCondition c) - { - buf.writestring("debug ("); - if (c.ident) - buf.writestring(c.ident.toString()); - else - buf.print(c.level); - buf.writeByte(')'); - } + if (s.prm.type) + hgs.typeToBuffer(s.prm.type, s.prm.ident, *buf); + else + buf.writestring(s.prm.ident.toString()); - override void visit(VersionCondition c) - { - buf.writestring("version ("); - if (c.ident) - buf.writestring(c.ident.toString()); - else - buf.print(c.level); - buf.writeByte(')'); - } + buf.writestring("; "); + hgs.expressionPrettyPrint(s.lwr, *buf); + buf.writestring(" .. "); + hgs.expressionPrettyPrint(s.upr, *buf); + buf.writeByte(')'); + buf.writenl(); + } - override void visit(StaticIfCondition c) - { - buf.writestring("static if ("); - c.exp.expressionToBuffer(*buf, *hgs); - buf.writeByte(')'); - } -} + buf.writestring("static "); -void toCBuffer(const Statement s, ref OutBuffer buf, ref HdrGenState hgs) -{ - (cast()s).statementToBuffer(buf, hgs); -} + if (s.sfe.aggrfe) + { + foreachWithoutBody(s.sfe.aggrfe); + } + else + { + assert(s.sfe.rangefe); + foreachRangeWithoutBody(s.sfe.rangefe); + } -void toCBuffer(const Type t, ref OutBuffer buf, const Identifier ident, ref HdrGenState hgs) -{ - typeToBuffer(cast() t, ident, buf, hgs); -} + buf.writeByte('{'); + buf.writenl(); + buf.level++; + visitAttribDeclaration(s); + buf.level--; + buf.writeByte('}'); + buf.writenl(); + } -// used from TemplateInstance::toChars() and TemplateMixin::toChars() -void toCBufferInstance(const TemplateInstance ti, ref OutBuffer buf, bool qualifyTypes = false) -{ - HdrGenState hgs; - hgs.fullQual = qualifyTypes; + void visit(MixinDeclaration d) + { + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; - buf.writestring(ti.name.toChars()); - tiargsToBuffer(cast() ti, buf, hgs); -} + buf.writestring("mixin("); + hgs.argsToBuffer(d.exps, *buf, null); + buf.writestring(");"); + buf.writenl(); + } -void toCBuffer(const Initializer iz, ref OutBuffer buf, ref HdrGenState hgs) -{ - initializerToBuffer(cast() iz, buf, hgs); -} + void visit(UserAttributeDeclaration d) + { + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; -bool stcToBuffer(ref OutBuffer buf, StorageClass stc) @safe -{ - //printf("stc: %llx\n", stc); - bool result = false; + buf.writestring("@("); + hgs.argsToBuffer(d.atts, *buf); + buf.writeByte(')'); + visitAttribDeclaration(d); + } - if (stc & STC.scopeinferred) - { - //buf.writestring("scope-inferred "); - stc &= ~(STC.scope_ | STC.scopeinferred); - } - if (stc & STC.returninferred) - { - //buf.writestring((stc & STC.returnScope) ? "return-scope-inferred " : "return-ref-inferred "); - stc &= ~(STC.return_ | STC.returninferred); - } + void visit(TemplateDeclaration d) + { + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; - /* Put scope ref return into a standard order - */ - string rrs; - const isout = (stc & STC.out_) != 0; - //printf("bsr = %d %llx\n", buildScopeRef(stc), stc); - final switch (buildScopeRef(stc)) - { - case ScopeRef.None: - case ScopeRef.Scope: - case ScopeRef.Ref: - case ScopeRef.Return: - break; + version (none) + { + // Should handle template functions for doc generation + if (onemember && onemember.isFuncDeclaration()) + buf.writestring("foo "); + } - case ScopeRef.ReturnScope: rrs = "return scope"; goto L1; - case ScopeRef.ReturnRef: rrs = isout ? "return out" : "return ref"; goto L1; - case ScopeRef.RefScope: rrs = isout ? "out scope" : "ref scope"; goto L1; - case ScopeRef.ReturnRef_Scope: rrs = isout ? "return out scope" : "return ref scope"; goto L1; - case ScopeRef.Ref_ReturnScope: rrs = isout ? "out return scope" : "ref return scope"; goto L1; - L1: - buf.writestring(rrs); - result = true; - stc &= ~(STC.out_ | STC.scope_ | STC.ref_ | STC.return_); - break; - } + if ((hgs.hdrgen || hgs.fullDump) && visitEponymousMember(d)) + return; + else if (hgs.ddoc) + buf.writestring(d.kind()); + else + buf.writestring("template"); - while (stc) - { - const s = stcToString(stc); - if (!s.length) - break; - if (result) buf.writeByte(' '); - result = true; - buf.writestring(s); - } + buf.writestring(d.ident.toString()); + buf.writeByte('('); + hgs.visitTemplateParameters(hgs.ddoc ? d.origParameters : d.parameters, *buf); + buf.writeByte(')'); + visitTemplateConstraint(d.constraint); - return result; -} + if (hgs.hdrgen || hgs.fullDump) + { + hgs.tpltMember++; + buf.writenl(); + buf.writeByte('{'); + buf.writenl(); + buf.level++; -/************************************************* - * Pick off one of the storage classes from stc, - * and return a string representation of it. - * stc is reduced by the one picked. - */ -string stcToString(ref StorageClass stc) @safe -{ - static struct SCstring - { - StorageClass stc; - string id; - } + foreach (s; *d.members) + hgs.toCBuffer(s, *buf); - // Note: The identifier needs to be `\0` terminated - // as some code assumes it (e.g. when printing error messages) - static immutable SCstring[] table = - [ - SCstring(STC.auto_, Token.toString(TOK.auto_)), - SCstring(STC.scope_, Token.toString(TOK.scope_)), - SCstring(STC.static_, Token.toString(TOK.static_)), - SCstring(STC.extern_, Token.toString(TOK.extern_)), - SCstring(STC.const_, Token.toString(TOK.const_)), - SCstring(STC.final_, Token.toString(TOK.final_)), - SCstring(STC.abstract_, Token.toString(TOK.abstract_)), - SCstring(STC.synchronized_, Token.toString(TOK.synchronized_)), - SCstring(STC.deprecated_, Token.toString(TOK.deprecated_)), - SCstring(STC.override_, Token.toString(TOK.override_)), - SCstring(STC.lazy_, Token.toString(TOK.lazy_)), - SCstring(STC.alias_, Token.toString(TOK.alias_)), - SCstring(STC.out_, Token.toString(TOK.out_)), - SCstring(STC.in_, Token.toString(TOK.in_)), - SCstring(STC.manifest, Token.toString(TOK.enum_)), - SCstring(STC.immutable_, Token.toString(TOK.immutable_)), - SCstring(STC.shared_, Token.toString(TOK.shared_)), - SCstring(STC.nothrow_, Token.toString(TOK.nothrow_)), - SCstring(STC.wild, Token.toString(TOK.inout_)), - SCstring(STC.pure_, Token.toString(TOK.pure_)), - SCstring(STC.ref_, Token.toString(TOK.ref_)), - SCstring(STC.return_, Token.toString(TOK.return_)), - SCstring(STC.gshared, Token.toString(TOK.gshared)), - SCstring(STC.nogc, "@nogc"), - SCstring(STC.live, "@live"), - SCstring(STC.property, "@property"), - SCstring(STC.safe, "@safe"), - SCstring(STC.trusted, "@trusted"), - SCstring(STC.system, "@system"), - SCstring(STC.disable, "@disable"), - SCstring(STC.future, "@__future"), - SCstring(STC.local, "__local"), - ]; - foreach (ref entry; table) - { - const StorageClass tbl = entry.stc; - assert(tbl & STC.visibleStorageClasses); - if (stc & tbl) - { - stc &= ~tbl; - return entry.id; + buf.level--; + buf.writeByte('}'); + buf.writenl(); + hgs.tpltMember--; + } } - } - //printf("stc = %llx\n", stc); - return null; -} -private void linkageToBuffer(ref OutBuffer buf, LINK linkage) @safe -{ - const s = linkageToString(linkage); - if (s.length) - { - buf.writestring("extern ("); - buf.writestring(s); - buf.writeByte(')'); - } -} + void visit(TemplateInstance ti) + { + trace; -const(char)* linkageToChars(LINK linkage) -{ - /// Works because we return a literal - return linkageToString(linkage).ptr; -} + if (hgs.childCountOfModule > 1 || !hgs.hdrgen) + { + buf.writestring(ti.name.toChars()); + hgs.tiargsToBuffer(ti, *buf); -string linkageToString(LINK linkage) pure nothrow @safe -{ - with (LINK) - { - immutable string[7] a = [ - default_ : null, - d : "D", - c : "C", - cpp : "C++", - windows : "Windows", - objc : "Objective-C", - system : "System" ]; - return a[linkage]; - } -} + if (hgs.fullDump) + { + buf.writenl(); + hgs.dumpTemplateInstance(ti, *buf); + } + } + } -void visibilityToBuffer(ref OutBuffer buf, Visibility vis) -{ - buf.writestring(visibilityToString(vis.kind)); - if (vis.kind == Visibility.Kind.package_ && vis.pkg) - { - buf.writeByte('('); - buf.writestring(vis.pkg.toPrettyChars(true)); - buf.writeByte(')'); - } -} + void visit(TemplateMixin tm) + { + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; -/** - * Returns: - * a human readable representation of `kind` - */ -const(char)* visibilityToChars(Visibility.Kind kind) -{ - // Null terminated because we return a literal - return visibilityToString(kind).ptr; -} + if ((cast(TypeIdentifier) tm.tqual).ident is Id.CMain && !hgs.vcg_ast) + return; -/// Ditto -extern (D) string visibilityToString(Visibility.Kind kind) nothrow pure @safe -{ - with (Visibility.Kind) - { - immutable string[7] a = [ - none : "none", - private_ : "private", - package_ : "package", - protected_ : "protected", - public_ : "public", - export_ : "export" ]; - return a[kind]; - } -} + buf.writestring("mixin "); + hgs.typeToBuffer(tm.tqual, null, *buf); + hgs.tiargsToBuffer(tm, *buf); -// Print the full function signature with correct ident, attributes and template args -void functionToBufferFull(TypeFunction tf, ref OutBuffer buf, const Identifier ident, ref HdrGenState hgs, TemplateDeclaration td) -{ - //printf("TypeFunction::toCBuffer() this = %p\n", this); - visitFuncIdentWithPrefix(tf, ident, td, buf, hgs); -} + if (tm.ident && memcmp(tm.ident.toString().ptr, cast(const(char)*) "__mixin", 7) != 0) + { + buf.writeByte(' '); + buf.writestring(tm.ident.toString()); + } -// ident is inserted before the argument list and will be "function" or "delegate" for a type -void functionToBufferWithIdent(TypeFunction tf, ref OutBuffer buf, const(char)* ident, bool isStatic) -{ - HdrGenState hgs; - visitFuncIdentWithPostfix(tf, ident.toDString(), buf, hgs, isStatic); -} + buf.writeByte(';'); + buf.writenl(); -void toCBuffer(const Expression e, ref OutBuffer buf, ref HdrGenState hgs) -{ - expressionPrettyPrint(cast()e, buf, hgs); -} + if (hgs.fullDump) + hgs.dumpTemplateInstance(tm, *buf); + } -/************************************************** - * Write out argument types to buf. - */ -void argExpTypesToCBuffer(ref OutBuffer buf, Expressions* arguments) -{ - if (!arguments || !arguments.length) - return; - HdrGenState hgs; - foreach (i, arg; *arguments) - { - if (i) - buf.writestring(", "); - typeToBuffer(arg.type, null, buf, hgs); - } -} + void visit(EnumDeclaration d) + { + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; -void arrayObjectsToBuffer(ref OutBuffer buf, Objects* objects) -{ - if (!objects || !objects.length) - return; - HdrGenState hgs; - foreach (i, o; *objects) - { - if (i) - buf.writestring(", "); - objectToBuffer(o, buf, hgs); - } -} + auto oldInEnumDecl = hgs.inEnumDecl; + scope (exit) + hgs.inEnumDecl = oldInEnumDecl; -/************************************************************* - * Pretty print function parameters. - * Params: - * pl = parameter list to print - * Returns: Null-terminated string representing parameters. - */ -const(char)* parametersTypeToChars(ParameterList pl) -{ - OutBuffer buf; - HdrGenState hgs; - parametersToBuffer(pl, buf, hgs); - return buf.extractChars(); -} + hgs.inEnumDecl = d; + buf.writestring("enum"); -/************************************************************* - * Pretty print function parameter. - * Params: - * parameter = parameter to print. - * tf = TypeFunction which holds parameter. - * fullQual = whether to fully qualify types. - * Returns: Null-terminated string representing parameters. - */ -const(char)* parameterToChars(Parameter parameter, TypeFunction tf, bool fullQual) -{ - OutBuffer buf; - HdrGenState hgs; - hgs.fullQual = fullQual; + if (d.ident) + { + buf.writestring(" "); + buf.writestring(d.ident.toString()); + } - parameterToBuffer(parameter, buf, hgs); + if (d.memtype) + { + buf.writestring(" : "); + hgs.typeToBuffer(d.memtype, null, *buf); + } - if (tf.parameterList.varargs == VarArg.typesafe && parameter == tf.parameterList[tf.parameterList.parameters.length - 1]) - { - buf.writestring("..."); - } - return buf.extractChars(); -} + if (!d.members) + { + buf.writeByte(';'); + buf.writenl(); + return; + } + buf.writenl(); + buf.writeByte('{'); + buf.writenl(); + buf.level++; -/************************************************* - * Write ParameterList to buffer. - * Params: - * pl = parameter list to serialize - * buf = buffer to write it to - * hgs = context - */ + foreach (em; *d.members) + { + if (!em) + continue; -private void parametersToBuffer(ParameterList pl, ref OutBuffer buf, ref HdrGenState hgs) -{ - buf.writeByte('('); - foreach (i; 0 .. pl.length) - { - if (i) - buf.writestring(", "); - pl[i].parameterToBuffer(buf, hgs); - } - final switch (pl.varargs) - { - case VarArg.none: - case VarArg.KRvariadic: - break; + hgs.toCBuffer(em, *buf); + buf.writeByte(','); + buf.writenl(); + } - case VarArg.variadic: - if (pl.length) - buf.writestring(", "); + buf.level--; + buf.writeByte('}'); + buf.writenl(); - if (stcToBuffer(buf, pl.stc)) - buf.writeByte(' '); - goto case VarArg.typesafe; + if (!hgs.importcHdr || !d.ident) + return; - case VarArg.typesafe: - buf.writestring("..."); - break; - } - buf.writeByte(')'); -} + /* C enums get their members inserted into the symbol table of the enum declaration. + * This is accomplished in addEnumMembersToSymtab(). + * But when generating D code from ImportC code, D rulez are followed. + * Accomplish this by generating an alias declaration for each member + */ + foreach (em; *d.members) + { + if (!em) + continue; + + buf.writestring("alias "); + buf.writestring(em.ident.toString); + buf.writestring(" = "); + buf.writestring(d.ident.toString); + buf.writeByte('.'); + buf.writestring(em.ident.toString); + buf.writeByte(';'); + buf.writenl(); + } + } + void visit(Nspace d) + { + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; -/*********************************************************** - * Write parameter `p` to buffer `buf`. - * Params: - * p = parameter to serialize - * buf = buffer to write it to - * hgs = context - */ -private void parameterToBuffer(Parameter p, ref OutBuffer buf, ref HdrGenState hgs) -{ - if (p.userAttribDecl) - { - buf.writeByte('@'); + buf.writestring("extern (C++, "); + buf.writestring(d.ident.toString()); + buf.writeByte(')'); + buf.writenl(); + buf.writeByte('{'); + buf.writenl(); + buf.level++; - bool isAnonymous = p.userAttribDecl.atts.length > 0 && !(*p.userAttribDecl.atts)[0].isCallExp(); - if (isAnonymous) - buf.writeByte('('); + foreach (s; *d.members) + hgs.toCBuffer(s, *buf); - argsToBuffer(p.userAttribDecl.atts, buf, hgs); + buf.level--; + buf.writeByte('}'); + buf.writenl(); + } - if (isAnonymous) - buf.writeByte(')'); - buf.writeByte(' '); - } - if (p.storageClass & STC.auto_) - buf.writestring("auto "); + void visit(StructDeclaration d) + { + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; - StorageClass stc = p.storageClass; - if (p.storageClass & STC.in_) - { - buf.writestring("in "); - if ((p.storageClass & (STC.constscoperef | STC.ref_)) == (STC.constscoperef | STC.ref_)) - stc &= ~STC.ref_; - } - else if (p.storageClass & STC.lazy_) - buf.writestring("lazy "); - else if (p.storageClass & STC.alias_) - buf.writestring("alias "); + //printf("visitStructDeclaration() %s\n", d.ident.toChars()); + buf.writestring(d.kind()); + buf.writeByte(' '); - if (p.type && p.type.mod & MODFlags.shared_) - stc &= ~STC.shared_; + if (!d.isAnonymous()) + buf.writestring(d.toChars()); - if (stcToBuffer(buf, stc & (STC.const_ | STC.immutable_ | STC.wild | STC.shared_ | - STC.return_ | STC.returninferred | STC.scope_ | STC.scopeinferred | STC.out_ | STC.ref_ | STC.returnScope))) - buf.writeByte(' '); + if (!d.members) + { + buf.writeByte(';'); + buf.writenl(); + return; + } - const(char)[] s; - if (p.storageClass & STC.alias_) - { - if (p.ident) - buf.writestring(p.ident.toString()); - } - else if (p.type.isTypeIdentifier() && - (s = p.type.isTypeIdentifier().ident.toString()).length > 3 && - s[0..3] == "__T") - { - // print parameter name, instead of undetermined type parameter - buf.writestring(p.ident.toString()); - } - else - { - typeToBuffer(p.type, p.ident, buf, hgs, (stc & STC.in_) ? MODFlags.const_ : 0); - } + buf.writenl(); + buf.writeByte('{'); + buf.writenl(); + buf.level++; + hgs.insideAggregate++; - if (p.defaultArg) - { - buf.writestring(" = "); - p.defaultArg.expToBuffer(PREC.assign, buf, hgs); - } -} + foreach (s; *d.members) + hgs.toCBuffer(s, *buf); + hgs.insideAggregate--; + buf.level--; + buf.writeByte('}'); + buf.writenl(); + } -/************************************************** - * Write out argument list to buf. - * Params: - * expressions = argument list - * buf = buffer to write to - * hgs = context - * 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, ref OutBuffer buf, ref HdrGenState hgs, Expression basis = null, Identifiers* names = null) -{ - if (!expressions || !expressions.length) - return; - version (all) - { - foreach (i, el; *expressions) + void visit(ClassDeclaration d) { - if (i) - buf.writestring(", "); + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; - if (names && i < names.length && (*names)[i]) + if (!d.isAnonymous()) { - buf.writestring((*names)[i].toString()); - buf.writestring(": "); + buf.writestring(d.kind()); + buf.writeByte(' '); + buf.writestring(d.ident.toString()); } - if (!el) - el = basis; - if (el) - expToBuffer(el, PREC.assign, buf, hgs); - } - } - else - { - // Sparse style formatting, for debug use only - // [0..length: basis, 1: e1, 5: e5] - if (basis) - { - buf.writestring("0.."); - buf.print(expressions.length); - buf.writestring(": "); - expToBuffer(basis, PREC.assign, buf, hgs); + + visitBaseClasses(d); + + if (d.members) + { + buf.writenl(); + buf.writeByte('{'); + buf.writenl(); + buf.level++; + hgs.insideAggregate++; + + foreach (s; *d.members) + hgs.toCBuffer(s, *buf); + + hgs.insideAggregate--; + buf.level--; + buf.writeByte('}'); + } + else + buf.writeByte(';'); + + buf.writenl(); } - foreach (i, el; *expressions) + + void visit(AliasDeclaration d) { - if (el) + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; + + if (d.storage_class & STC.local) + return; + else if (d.adFlags & d.hidden) + return; + + buf.writestring("alias "); + + if (d.aliassym) { - if (basis) + buf.writestring(d.ident.toString()); + buf.writestring(" = "); + + if (storageClassToBuffer(*buf, d.storage_class)) + buf.writeByte(' '); + + if (d.aliassym.ident !is null) { - buf.writestring(", "); - buf.print(i); - buf.writestring(": "); + /* + https://issues.dlang.org/show_bug.cgi?id=23223 + https://issues.dlang.org/show_bug.cgi?id=23222 + This special case (initially just for modules) avoids some segfaults + and nicer -vcg-ast output. + */ + buf.writestring(d.aliassym.ident.toString()); } - else if (i) - buf.writestring(", "); - expToBuffer(el, PREC.assign, buf, hgs); - } - } - } -} + else + { + hgs.toCBuffer(d.aliassym, *buf); -private void sizeToBuffer(Expression e, ref OutBuffer buf, ref HdrGenState hgs) -{ - if (e.type == Type.tsize_t) - { - Expression ex = (e.op == EXP.cast_ ? (cast(CastExp)e).e1 : e); - ex = ex.optimize(WANTvalue); - const ulong uval = ex.op == EXP.int64 ? ex.toInteger() : cast(ulong)-1; - if (cast(long)uval >= 0) - { - if (uval <= 0xFFFFU) + char lastChar = (*buf)[][$ - 1]; + if (lastChar == ';' || lastChar == '\n') + return; + } + } + else if (d.type.ty == Tfunction) { - buf.print(uval); - return; + if (storageClassToBuffer(*buf, d.storage_class)) + buf.writeByte(' '); + + hgs.typeToBuffer(d.type, d.ident, *buf); } - if (uval <= 0x7FFF_FFFF_FFFF_FFFFUL) + else if (d.ident) { - buf.writestring("cast(size_t)"); - buf.print(uval); - return; + hgs.declstring = (d.ident == Id.string || d.ident == Id.wstring + || d.ident == Id.dstring); + buf.writestring(d.ident.toString()); + buf.writestring(" = "); + + if (storageClassToBuffer(*buf, d.storage_class)) + buf.writeByte(' '); + + hgs.typeToBuffer(d.type, null, *buf); + hgs.declstring = false; } - } - } - expToBuffer(e, PREC.assign, buf, hgs); -} -private void expressionToBuffer(Expression e, ref OutBuffer buf, ref HdrGenState hgs) -{ - expressionPrettyPrint(e, buf, hgs); -} + buf.writeByte(';'); + buf.writenl(); + } -/************************************************** - * Write expression out to buf, but wrap it - * in ( ) if its precedence is less than pr. - */ -private void expToBuffer(Expression e, PREC pr, ref OutBuffer buf, ref HdrGenState hgs) -{ - debug - { - if (precedence[e.op] == PREC.zero) - printf("precedence not defined for token '%s'\n", EXPtoString(e.op).ptr); - } - if (e.op == 0xFF) - { - buf.writestring(""); - return; - } - assert(precedence[e.op] != PREC.zero); - assert(pr != PREC.zero); - /* Despite precedence, we don't allow a= PREC.or && pr <= PREC.and && precedence[e.op] == PREC.rel)) - { - buf.writeByte('('); - e.expressionToBuffer(buf, hgs); - buf.writeByte(')'); - } - else - { - e.expressionToBuffer(buf, hgs); - } -} + void visit(AliasAssign d) + { + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; + buf.writestring(d.ident.toString()); + buf.writestring(" = "); -/************************************************** - * An entry point to pretty-print type. - */ -private void typeToBuffer(Type t, const Identifier ident, ref OutBuffer buf, ref HdrGenState hgs, - ubyte modMask = 0) -{ - if (auto tf = t.isTypeFunction()) - { - visitFuncIdentWithPrefix(tf, ident, null, buf, hgs); - return; - } - visitWithMask(t, modMask, buf, hgs); - if (ident) - { - buf.writeByte(' '); - buf.writestring(ident.toString()); - } -} + if (d.aliassym) + hgs.toCBuffer(d.aliassym, *buf); + else // d.type + hgs.typeToBuffer(d.type, null, *buf); -private void visitWithMask(Type t, ubyte modMask, ref OutBuffer buf, ref HdrGenState hgs) -{ - // Tuples and functions don't use the type constructor syntax - if (modMask == t.mod || t.ty == Tfunction || t.ty == Ttuple) - { - typeToBufferx(t, buf, hgs); - } - else - { - ubyte m = t.mod & ~(t.mod & modMask); - if (m & MODFlags.shared_) - { - MODtoBuffer(buf, MODFlags.shared_); - buf.writeByte('('); + buf.writeByte(';'); + buf.writenl(); } - if (m & MODFlags.wild) + + void visit(VarDeclaration d) { - MODtoBuffer(buf, MODFlags.wild); - buf.writeByte('('); + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; + + if (d.storage_class & STC.local) + return; + + hgs.visitVarDecl(d, false, *buf); + buf.writeByte(';'); + buf.writenl(); } - if (m & (MODFlags.const_ | MODFlags.immutable_)) + + void visit(FuncDeclaration f) { - MODtoBuffer(buf, m & (MODFlags.const_ | MODFlags.immutable_)); - buf.writeByte('('); - } - typeToBufferx(t, buf, hgs); - if (m & (MODFlags.const_ | MODFlags.immutable_)) - buf.writeByte(')'); - if (m & MODFlags.wild) - buf.writeByte(')'); - if (m & MODFlags.shared_) - buf.writeByte(')'); - } -} + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; + //printf("FuncDeclaration::toCBuffer() '%s'\n", f.toChars()); + if (storageClassToBuffer(*buf, f.storage_class & STC.lhsHeaderAttributes)) + { + buf.writeByte(' '); + } -private void dumpTemplateInstance(TemplateInstance ti, ref OutBuffer buf, ref HdrGenState hgs) -{ - buf.writeByte('{'); - buf.writenl(); - buf.level++; + auto tf = f.type.isTypeFunction(); + hgs.typeToBuffer(tf, f.ident, *buf); - if (ti.aliasdecl) - { - ti.aliasdecl.dsymbolToBuffer(buf, hgs); - buf.writenl(); - } - else if (ti.members) - { - foreach(m;*ti.members) - m.dsymbolToBuffer(buf, hgs); - } + if (hgs.hdrgen) + { + // if the return type is missing (e.g. ref functions or auto) + // https://issues.dlang.org/show_bug.cgi?id=20090 + // constructors are an exception: they don't have an explicit return + // type but we still don't output the body. + if ((!f.isCtorDeclaration() && !tf.next) || f.storage_class & STC.auto_) + { + hgs.autoMember++; + bodyToBuffer(f); + hgs.autoMember--; + } + else if (hgs.tpltMember == 0 && hgs.doFuncBodies == false && !hgs.insideFuncBody) + { + if (!f.fbody) + { + // this can happen on interfaces / abstract functions, see `allowsContractWithoutBody` + if (f.fensures || f.frequires) + buf.writenl(); - buf.level--; - buf.writeByte('}'); - buf.writenl(); + contractsToBuffer(f); + } -} + buf.writeByte(';'); + buf.writenl(); + } + else + bodyToBuffer(f); + } + else + bodyToBuffer(f); + } -private void tiargsToBuffer(TemplateInstance ti, ref OutBuffer buf, ref HdrGenState hgs) -{ - buf.writeByte('!'); - if (ti.nest) - { - buf.writestring("(...)"); - return; - } - if (!ti.tiargs) - { - buf.writestring("()"); - return; - } - if (ti.tiargs.length == 1) - { - RootObject oarg = (*ti.tiargs)[0]; - if (Type t = isType(oarg)) + void visit(FuncLiteralDeclaration f) { - if (t.equals(Type.tstring) || t.equals(Type.twstring) || t.equals(Type.tdstring) || t.mod == 0 && (t.isTypeBasic() || t.ty == Tident && (cast(TypeIdentifier)t).idents.length == 0)) + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; + + if (f.type.ty == Terror) { - HdrGenState hgs2; // re-examine need for new hgs - hgs2.fullQual = (t.ty == Tclass && !t.mod); - toCBuffer(t, buf, null, hgs2); + buf.writestring("__error"); return; } - } - else if (Expression e = isExpression(oarg)) - { - if (e.op == EXP.int64 || e.op == EXP.float64 || e.op == EXP.null_ || e.op == EXP.string_ || e.op == EXP.this_) + else if (f.tok != TOK.reserved) { - toCBuffer(e, buf, hgs); - return; + buf.writestring(f.kind()); + buf.writeByte(' '); } - } - } - buf.writeByte('('); - ti.nestUp(); - foreach (i, arg; *ti.tiargs) - { - if (i) - buf.writestring(", "); - objectToBuffer(arg, buf, hgs); - } - ti.nestDown(); - buf.writeByte(')'); -} - -/**************************************** - * This makes a 'pretty' version of the template arguments. - * It's analogous to genIdent() which makes a mangled version. - */ -private void objectToBuffer(RootObject oarg, ref OutBuffer buf, ref HdrGenState hgs) -{ - //printf("objectToBuffer()\n"); - /* The logic of this should match what genIdent() does. The _dynamic_cast() - * function relies on all the pretty strings to be unique for different classes - * See https://issues.dlang.org/show_bug.cgi?id=7375 - * Perhaps it would be better to demangle what genIdent() does. - */ - if (auto t = isType(oarg)) - { - //printf("\tt: %s ty = %d\n", t.toChars(), t.ty); - typeToBuffer(t, null, buf, hgs); - } - else if (auto e = isExpression(oarg)) - { - if (e.op == EXP.variable) - e = e.optimize(WANTvalue); // added to fix https://issues.dlang.org/show_bug.cgi?id=7375 - expToBuffer(e, PREC.assign, buf, hgs); - } - else if (Dsymbol s = isDsymbol(oarg)) - { - if (s.ident) - buf.writestring(s.ident.toString()); - else - buf.writestring(s.toChars()); - } - else if (auto v = isTuple(oarg)) - { - auto args = &v.objects; - foreach (i, arg; *args) - { - if (i) - buf.writestring(", "); - objectToBuffer(arg, buf, hgs); - } - } - else if (auto p = isParameter(oarg)) - { - parameterToBuffer(p, buf, hgs); - } - else if (!oarg) - { - buf.writestring("NULL"); - } - else - { - debug - { - printf("bad Object = %p\n", oarg); - } - assert(0); - } -} - - -private void visitFuncIdentWithPostfix(TypeFunction t, const char[] ident, ref OutBuffer buf, ref HdrGenState hgs, bool isStatic) -{ - if (t.inuse) - { - t.inuse = 2; // flag error to caller - return; - } - t.inuse++; - if (t.linkage > LINK.d && hgs.ddoc != 1 && !hgs.hdrgen) - { - linkageToBuffer(buf, t.linkage); - buf.writeByte(' '); - } - if (t.linkage == LINK.objc && isStatic) - buf.write("static "); - if (t.next) - { - typeToBuffer(t.next, null, buf, hgs); - if (ident) - buf.writeByte(' '); - } - else if (hgs.ddoc) - buf.writestring("auto "); - if (ident) - buf.writestring(ident); - parametersToBuffer(t.parameterList, buf, hgs); - /* Use postfix style for attributes - */ - if (t.mod) - { - buf.writeByte(' '); - MODtoBuffer(buf, t.mod); - } + TypeFunction tf = cast(TypeFunction) f.type; - void dg(string str) - { - buf.writeByte(' '); - buf.writestring(str); - } - t.attributesApply(&dg); + if (!f.inferRetType && tf.next) + hgs.typeToBuffer(tf.next, null, *buf); - t.inuse--; -} + hgs.parametersToBuffer(tf.parameterList, *buf); -private void visitFuncIdentWithPrefix(TypeFunction t, const Identifier ident, TemplateDeclaration td, - ref OutBuffer buf, ref HdrGenState hgs) -{ - if (t.inuse) - { - t.inuse = 2; // flag error to caller - return; - } - t.inuse++; + // https://issues.dlang.org/show_bug.cgi?id=20074 + void printAttribute(string str) + { + buf.writeByte(' '); + buf.writestring(str); + } - /* Use 'storage class' (prefix) style for attributes - */ - if (t.mod) - { - MODtoBuffer(buf, t.mod); - buf.writeByte(' '); - } + tf.attributesApply(&printAttribute); - void ignoreReturn(string str) - { - if (str != "return") - { - // don't write 'ref' for ctors - if ((ident == Id.ctor) && str == "ref") - return; - buf.writestring(str); - buf.writeByte(' '); - } - } - t.attributesApply(&ignoreReturn); + CompoundStatement cs = f.fbody.isCompoundStatement(); + Statement s1; - if (t.linkage > LINK.d && hgs.ddoc != 1 && !hgs.hdrgen) - { - linkageToBuffer(buf, t.linkage); - buf.writeByte(' '); - } - if (ident && ident.toHChars2() != ident.toChars()) - { - // Don't print return type for ctor, dtor, unittest, etc - } - else if (t.next) - { - typeToBuffer(t.next, null, buf, hgs); - if (ident) - buf.writeByte(' '); - } - else if (hgs.ddoc) - buf.writestring("auto "); - if (ident) - buf.writestring(ident.toHChars2()); - if (td) - { - buf.writeByte('('); - foreach (i, p; *td.origParameters) - { - if (i) - buf.writestring(", "); - toCBuffer(p, buf, hgs); + if (f.semanticRun >= PASS.semantic3done && cs) + { + s1 = (*cs.statements)[cs.statements.length - 1]; + } + else + s1 = !cs ? f.fbody : null; + + ReturnStatement rs = s1 ? s1.endsWithReturnStatement() : null; + + if (rs && rs.exp) + { + buf.writestring(" => "); + hgs.expressionPrettyPrint(rs.exp, *buf); + } + else + { + hgs.tpltMember++; + bodyToBuffer(f); + hgs.tpltMember--; + } } - buf.writeByte(')'); - } - parametersToBuffer(t.parameterList, buf, hgs); - if (t.isreturn) - { - buf.writestring(" return"); - } - t.inuse--; -} + void visit(PostBlitDeclaration d) + { + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; -private void initializerToBuffer(Initializer inx, ref OutBuffer buf, ref HdrGenState hgs) -{ - void visitError(ErrorInitializer iz) - { - buf.writestring("__error__"); - } + if (d.type !is null) + { + auto tf = d.type.isTypeFunction(); - void visitVoid(VoidInitializer iz) - { - buf.writestring("void"); - } + if (storageClassToBuffer(*buf, d.storage_class & STC.lhsHeaderAttributes)) + buf.writeByte(' '); - void visitDefault(DefaultInitializer iz) - { - buf.writestring("{ }"); - } + hgs.typeToBuffer(tf, d.ident, *buf); + bodyToBuffer(d); + } + } - void visitStruct(StructInitializer si) - { - //printf("StructInitializer::toCBuffer()\n"); - buf.writeByte('{'); - foreach (i, const id; si.field) + void visit(DtorDeclaration d) { - if (i) - buf.writestring(", "); - if (id) + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; + + if (d.type !is null) { - buf.writestring(id.toString()); - buf.writeByte(':'); + auto tf = d.type.isTypeFunction(); + + if (storageClassToBuffer(*buf, d.storage_class & STC.lhsHeaderAttributes)) + buf.writeByte(' '); + + hgs.typeToBuffer(tf, d.ident, *buf); + bodyToBuffer(d); } - if (auto iz = si.value[i]) - initializerToBuffer(iz, buf, hgs); } - buf.writeByte('}'); - } - void visitArray(ArrayInitializer ai) - { - buf.writeByte('['); - foreach (i, ex; ai.index) + void visit(StaticCtorDeclaration d) { - if (i) - buf.writestring(", "); - if (ex) + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; + + hgs.writeTypeFunctionAttributes(d.type !is null ? d.type.isTypeFunction() : null, + *buf, d.storage_class & STC.lhsHeaderMCtorAttributes, + d.storage_class & STC.rhsHeaderMCtorAttributes, (TypeFunction tf) { + if (d.isSharedStaticCtorDeclaration()) + buf.writestring("shared "); + + buf.writestring("static this()"); + }); + + if (hgs.hdrgen && !hgs.tpltMember) { - ex.expressionToBuffer(buf, hgs); - buf.writeByte(':'); + buf.writeByte(';'); + buf.writenl(); } - if (auto iz = ai.value[i]) - initializerToBuffer(iz, buf, hgs); + else + bodyToBuffer(d); } - buf.writeByte(']'); - } - - void visitExp(ExpInitializer ei) - { - ei.exp.expressionToBuffer(buf, hgs); - } - void visitC(CInitializer ci) - { - buf.writeByte('{'); - foreach (i, ref DesigInit di; ci.initializerList) + void visit(StaticDtorDeclaration d) { - if (i) - buf.writestring(", "); - if (di.designatorList) + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; + + hgs.writeTypeFunctionAttributes(d.type !is null ? d.type.isTypeFunction() : null, + *buf, d.storage_class & STC.lhsHeaderMCtorAttributes, + d.storage_class & STC.rhsHeaderMCtorAttributes, (TypeFunction tf) { + if (d.isSharedStaticDtorDeclaration()) + buf.writestring("shared "); + + buf.writestring("static ~this()"); + }); + + if (hgs.hdrgen && !hgs.tpltMember) { - foreach (ref Designator d; (*di.designatorList)[]) - { - if (d.exp) - { - buf.writeByte('['); - toCBuffer(d.exp, buf, hgs); - buf.writeByte(']'); - } - else - { - buf.writeByte('.'); - buf.writestring(d.ident.toString()); - } - } - buf.writeByte('='); + buf.writeByte(';'); + buf.writenl(); } - initializerToBuffer(di.initializer, buf, hgs); + else + bodyToBuffer(d); } - buf.writeByte('}'); - } - mixin VisitInitializer!void visit; - visit.VisitInitializer(inx); -} + void visit(InvariantDeclaration d) + { + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; + if (hgs.hdrgen) + return; + else if (storageClassToBuffer(*buf, d.storage_class)) + buf.writeByte(' '); -private void typeToBufferx(Type t, ref OutBuffer buf, ref HdrGenState hgs) -{ - void visitType(Type t) - { - printf("t = %p, ty = %d\n", t, t.ty); - assert(0); - } + // FIXME: no attributes would be emitted here for semantic 3 - void visitError(TypeError t) - { - buf.writestring("_error_"); - } + buf.writestring("invariant"); - void visitBasic(TypeBasic t) - { - //printf("TypeBasic::toCBuffer2(t.mod = %d)\n", t.mod); - buf.writestring(t.dstring); - } + if (auto es = d.fbody.isExpStatement()) + { + assert(es.exp && es.exp.op == EXP.assert_); + buf.writestring(" ("); + hgs.expressionPrettyPrint((cast(AssertExp) es.exp).e1, *buf); + buf.writestring(");"); + buf.writenl(); + } + else + { + bodyToBuffer(d); + } + } - void visitTraits(TypeTraits t) - { - //printf("TypeBasic::toCBuffer2(t.mod = %d)\n", t.mod); - t.exp.expressionToBuffer(buf, hgs); - } + void visit(UnitTestDeclaration d) + { + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; - void visitVector(TypeVector t) - { - //printf("TypeVector::toCBuffer2(t.mod = %d)\n", t.mod); - buf.writestring("__vector("); - visitWithMask(t.basetype, t.mod, buf, hgs); - buf.writestring(")"); - } + if (hgs.hdrgen) + return; + else if (storageClassToBuffer(*buf, d.storage_class)) + buf.writeByte(' '); - void visitSArray(TypeSArray t) - { - visitWithMask(t.next, t.mod, buf, hgs); - buf.writeByte('['); - sizeToBuffer(t.dim, buf, hgs); - buf.writeByte(']'); - } + // FIXME: no attributes would be emitted here for semantic 3 - void visitDArray(TypeDArray t) - { - Type ut = t.castMod(0); - if (hgs.declstring) - goto L1; - if (ut.equals(Type.tstring)) - buf.writestring("string"); - else if (ut.equals(Type.twstring)) - buf.writestring("wstring"); - else if (ut.equals(Type.tdstring)) - buf.writestring("dstring"); - else - { - L1: - visitWithMask(t.next, t.mod, buf, hgs); - buf.writestring("[]"); + buf.writestring("unittest"); + bodyToBuffer(d); } - } - void visitAArray(TypeAArray t) - { - visitWithMask(t.next, t.mod, buf, hgs); - buf.writeByte('['); - visitWithMask(t.index, 0, buf, hgs); - buf.writeByte(']'); - } + void visit(BitFieldDeclaration d) + { + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; - void visitPointer(TypePointer t) - { - //printf("TypePointer::toCBuffer2() next = %d\n", t.next.ty); - if (t.next.ty == Tfunction) - visitFuncIdentWithPostfix(cast(TypeFunction)t.next, "function", buf, hgs, false); - else + if (storageClassToBuffer(*buf, d.storage_class)) + buf.writeByte(' '); + + Identifier id = d.isAnonymous() ? null : d.ident; + hgs.typeToBuffer(d.type, id, *buf); + buf.writestring(" : "); + hgs.expressionPrettyPrint(d.width, *buf); + buf.writeByte(';'); + buf.writenl(); + } + + void visit(NewDeclaration d) { - visitWithMask(t.next, t.mod, buf, hgs); - buf.writeByte('*'); + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; + + if (storageClassToBuffer(*buf, d.storage_class & ~STC.static_)) + buf.writeByte(' '); + + buf.writestring("new();"); } - } - void visitReference(TypeReference t) - { - visitWithMask(t.next, t.mod, buf, hgs); - buf.writeByte('&'); - } + void visit(Module m) + { + hgs.childCountOfModule++; + scope (exit) + hgs.childCountOfModule--; + trace; - void visitFunction(TypeFunction t) - { - //printf("TypeFunction::toCBuffer2() t = %p, ref = %d\n", t, t.isref); - visitFuncIdentWithPostfix(t, null, buf, hgs, false); + hgs.moduleToBuffer(m, *buf); + } } - void visitDelegate(TypeDelegate t) + extern (C++) final class TemplateParameterPrettyPrintVisitor : Visitor { - visitFuncIdentWithPostfix(cast(TypeFunction)t.next, "delegate", buf, hgs, false); - } + alias visit = Visitor.visit; + OutBuffer* buf; + HdrGenState* hgs; - void visitTypeQualifiedHelper(TypeQualified t) - { - foreach (id; t.idents) + override void visit(TemplateTypeParameter tp) { - switch (id.dyncast()) with (DYNCAST) + buf.writestring(tp.ident.toString()); + + if (tp.specType) { - case dsymbol: - buf.writeByte('.'); - TemplateInstance ti = cast(TemplateInstance)id; - ti.dsymbolToBuffer(buf, hgs); - break; - case expression: - buf.writeByte('['); - (cast(Expression)id).expressionToBuffer(buf, hgs); - buf.writeByte(']'); - break; - case type: - buf.writeByte('['); - typeToBufferx(cast(Type)id, buf, hgs); - buf.writeByte(']'); - break; - default: - buf.writeByte('.'); - buf.writestring(id.toString()); + buf.writestring(" : "); + hgs.typeToBuffer(tp.specType, null, *buf); + } + + if (tp.defaultType) + { + buf.writestring(" = "); + hgs.typeToBuffer(tp.defaultType, null, *buf); } } - } - void visitIdentifier(TypeIdentifier t) - { - //printf("visitTypeIdentifier() %s\n", t.ident.toChars()); - buf.writestring(t.ident.toString()); - visitTypeQualifiedHelper(t); - } + override void visit(TemplateThisParameter tp) + { + buf.writestring("this "); + visit(cast(TemplateTypeParameter) tp); + } - void visitInstance(TypeInstance t) - { - t.tempinst.dsymbolToBuffer(buf, hgs); - visitTypeQualifiedHelper(t); - } + override void visit(TemplateAliasParameter tp) + { + buf.writestring("alias "); - void visitTypeof(TypeTypeof t) - { - buf.writestring("typeof("); - t.exp.expressionToBuffer(buf, hgs); - buf.writeByte(')'); - visitTypeQualifiedHelper(t); - } + if (tp.specType) + hgs.typeToBuffer(tp.specType, tp.ident, *buf); + else + buf.writestring(tp.ident.toString()); - void visitReturn(TypeReturn t) - { - buf.writestring("typeof(return)"); - visitTypeQualifiedHelper(t); - } + if (tp.specAlias) + { + buf.writestring(" : "); + hgs.objectToBuffer(tp.specAlias, *buf); + } - void visitEnum(TypeEnum t) - { - //printf("visitEnum: %s\n", t.sym.toChars()); - buf.writestring(hgs.fullQual ? t.sym.toPrettyChars() : t.sym.toChars()); - } + if (tp.defaultAlias) + { + buf.writestring(" = "); + hgs.objectToBuffer(tp.defaultAlias, *buf); + } + } - void visitStruct(TypeStruct t) - { - //printf("visitTypeStruct() %s\n", t.sym.toChars()); - - // https://issues.dlang.org/show_bug.cgi?id=13776 - // Don't use ti.toAlias() to avoid forward reference error - // while printing messages. - TemplateInstance ti = t.sym.parent ? t.sym.parent.isTemplateInstance() : null; - if (ti && ti.aliasdecl == t.sym) - buf.writestring(hgs.fullQual ? ti.toPrettyChars() : ti.toChars()); - else - buf.writestring(hgs.fullQual ? t.sym.toPrettyChars() : t.sym.toChars()); - } + override void visit(TemplateValueParameter tp) + { + hgs.typeToBuffer(tp.valType, tp.ident, *buf); - void visitClass(TypeClass t) - { - // https://issues.dlang.org/show_bug.cgi?id=13776 - // Don't use ti.toAlias() to avoid forward reference error - // while printing messages. - TemplateInstance ti = t.sym.parent ? t.sym.parent.isTemplateInstance() : null; - if (ti && ti.aliasdecl == t.sym) - buf.writestring(hgs.fullQual ? ti.toPrettyChars() : ti.toChars()); - else - buf.writestring(hgs.fullQual ? t.sym.toPrettyChars() : t.sym.toChars()); - } + if (tp.specValue) + { + buf.writestring(" : "); + hgs.expressionPrettyPrint(tp.specValue, *buf); + } - void visitTag(TypeTag t) - { - if (t.mod & MODFlags.const_) - buf.writestring("const "); - if (hgs.importcHdr && t.id) - { - buf.writestring(t.id.toString()); - return; + if (tp.defaultValue) + { + buf.writestring(" = "); + hgs.expressionPrettyPrint(tp.defaultValue, *buf); + } } - buf.writestring(Token.toString(t.tok)); - buf.writeByte(' '); - if (t.id) - buf.writestring(t.id.toString()); - if (t.tok == TOK.enum_ && t.base && t.base.ty != TY.Tint32) + + override void visit(TemplateTupleParameter tp) { - buf.writestring(" : "); - visitWithMask(t.base, t.mod, buf, hgs); + buf.writestring(tp.ident.toString()); + buf.writestring("..."); } } - void visitTuple(TypeTuple t) + extern (C++) final class ConditionPrettyPrintVisitor : Visitor { - parametersToBuffer(ParameterList(t.arguments, VarArg.none), buf, hgs); - } + alias visit = Visitor.visit; + OutBuffer* buf; + HdrGenState* hgs; - void visitSlice(TypeSlice t) - { - visitWithMask(t.next, t.mod, buf, hgs); - buf.writeByte('['); - sizeToBuffer(t.lwr, buf, hgs); - buf.writestring(" .. "); - sizeToBuffer(t.upr, buf, hgs); - buf.writeByte(']'); - } + override void visit(DebugCondition c) + { + buf.writestring("debug ("); - void visitNull(TypeNull t) - { - buf.writestring("typeof(null)"); - } + if (c.ident) + buf.writestring(c.ident.toString()); + else + buf.print(c.level); - void visitMixin(TypeMixin t) - { - buf.writestring("mixin("); - argsToBuffer(t.exps, buf, hgs, null); - buf.writeByte(')'); - } + buf.writeByte(')'); + } - void visitNoreturn(TypeNoreturn t) - { - buf.writestring("noreturn"); - } + override void visit(VersionCondition c) + { + buf.writestring("version ("); + if (c.ident) + buf.writestring(c.ident.toString()); + else + buf.print(c.level); - switch (t.ty) - { - default: return t.isTypeBasic() ? - visitBasic(cast(TypeBasic)t) : - visitType(t); - - case Terror: return visitError(cast(TypeError)t); - case Ttraits: return visitTraits(cast(TypeTraits)t); - case Tvector: return visitVector(cast(TypeVector)t); - case Tsarray: return visitSArray(cast(TypeSArray)t); - case Tarray: return visitDArray(cast(TypeDArray)t); - case Taarray: return visitAArray(cast(TypeAArray)t); - case Tpointer: return visitPointer(cast(TypePointer)t); - case Treference: return visitReference(cast(TypeReference)t); - case Tfunction: return visitFunction(cast(TypeFunction)t); - case Tdelegate: return visitDelegate(cast(TypeDelegate)t); - case Tident: return visitIdentifier(cast(TypeIdentifier)t); - case Tinstance: return visitInstance(cast(TypeInstance)t); - case Ttypeof: return visitTypeof(cast(TypeTypeof)t); - case Treturn: return visitReturn(cast(TypeReturn)t); - case Tenum: return visitEnum(cast(TypeEnum)t); - case Tstruct: return visitStruct(cast(TypeStruct)t); - case Tclass: return visitClass(cast(TypeClass)t); - case Ttuple: return visitTuple (cast(TypeTuple)t); - case Tslice: return visitSlice(cast(TypeSlice)t); - case Tnull: return visitNull(cast(TypeNull)t); - case Tmixin: return visitMixin(cast(TypeMixin)t); - case Tnoreturn: return visitNoreturn(cast(TypeNoreturn)t); - case Ttag: return visitTag(cast(TypeTag)t); + buf.writeByte(')'); + } + + override void visit(StaticIfCondition c) + { + buf.writestring("static if ("); + hgs.expressionPrettyPrint(c.exp, *buf); + buf.writeByte(')'); + } } } -/**************************************** - * Convert EXP to char*. - */ +private: + +// dfmt off +static immutable string[7] TableOfVisibilityStrings = [ + Visibility.Kind.none: "none", + Visibility.Kind.private_: "private", + Visibility.Kind.package_: "package", + Visibility.Kind.protected_: "protected", + Visibility.Kind.public_: "public", + Visibility.Kind.export_: "export" +]; + +static immutable string[7] TableOfLinkageStrings = [ + LINK.default_: null, + LINK.d: "D", + LINK.c: "C", + LINK.cpp: "C++", + LINK.windows: "Windows", + LINK.objc: "Objective-C", + LINK.system: "System" +]; + +static immutable string[EXP.max + 1] TableOfExpressionTypeStrings = [ + EXP.type: "type", + EXP.error: "error", + EXP.objcClassReference: "class", + + EXP.mixin_: "mixin", + EXP.import_: "import", + EXP.dotVariable: "dotvar", + EXP.scope_: "scope", + EXP.identifier: "identifier", + EXP.this_: "this", + EXP.super_: "super", + EXP.int64: "long", + EXP.float64: "double", + EXP.complex80: "creal", + EXP.null_: "null", + EXP.string_: "string", + EXP.arrayLiteral: "arrayliteral", + EXP.assocArrayLiteral: "assocarrayliteral", + EXP.classReference: "classreference", + EXP.file: "__FILE__", + EXP.fileFullPath: "__FILE_FULL_PATH__", + EXP.line: "__LINE__", + EXP.moduleString: "__MODULE__", + EXP.functionString: "__FUNCTION__", + EXP.prettyFunction: "__PRETTY_FUNCTION__", + EXP.typeid_: "typeid", + EXP.is_: "is", + EXP.assert_: "assert", + EXP.halt: "halt", + EXP.template_: "template", + EXP.dSymbol: "symbol", + EXP.function_: "function", + EXP.variable: "var", + EXP.symbolOffset: "symoff", + EXP.structLiteral: "structLiteral", + EXP.compoundLiteral: "compoundliteral", + EXP.arrayLength: "arraylength", + EXP.delegatePointer: "delegateptr", + EXP.delegateFunctionPointer: "delegatefuncptr", + EXP.remove: "remove", + EXP.tuple: "sequence", + EXP.traits: "__traits", + EXP.overloadSet: "__overloadset", + EXP.void_: "void", + EXP.vectorArray: "vectorarray", + EXP._Generic: "_Generic", + + // post + EXP.dotTemplateInstance: "dotti", + EXP.dotIdentifier: "dotid", + EXP.dotTemplateDeclaration: "dottd", + EXP.dot: ".", + EXP.dotType: "dottype", + EXP.plusPlus: "++", + EXP.minusMinus: "--", + EXP.prePlusPlus: "++", + EXP.preMinusMinus: "--", + EXP.call: "call", + EXP.slice: "..", + EXP.array: "[]", + EXP.index: "[i]", + EXP.delegate_: "delegate", + EXP.address: "&", + EXP.star: "*", + EXP.negate: "-", + EXP.uadd: "+", + EXP.not: "!", + EXP.tilde: "~", + EXP.delete_: "delete", + EXP.new_: "new", + EXP.newAnonymousClass: "newanonclass", + EXP.cast_: "cast", + + EXP.vector: "__vector", + EXP.pow: "^^", + EXP.mul: "*", + EXP.div: "/", + EXP.mod: "%", + EXP.add: "+", + EXP.min: "-", + EXP.concatenate: "~", + + EXP.leftShift: "<<", + EXP.rightShift: ">>", + EXP.unsignedRightShift: ">>>", + + EXP.lessThan: "<", + EXP.lessOrEqual: "<=", + EXP.greaterThan: ">", + EXP.greaterOrEqual: ">=", + EXP.in_: "in", + EXP.equal: "==", + EXP.notEqual: "!=", + EXP.identity: "is", + EXP.notIdentity: "!is", + + EXP.and: "&", + EXP.xor: "^", + EXP.or: "|", + EXP.andAnd: "&&", + EXP.orOr: "||", + + EXP.question: "?", + EXP.assign: "=", + EXP.construct: "=", + EXP.blit: "=", + EXP.addAssign: "+=", + EXP.minAssign: "-=", + EXP.concatenateAssign: "~=", + EXP.concatenateElemAssign: "~=", + EXP.concatenateDcharAssign: "~=", + EXP.mulAssign: "*=", + EXP.divAssign: "/=", + EXP.modAssign: "%=", + EXP.powAssign: "^^=", + EXP.leftShiftAssign: "<<=", + EXP.rightShiftAssign: ">>=", + EXP.unsignedRightShiftAssign: ">>>=", + EXP.andAssign: "&=", + EXP.orAssign: "|=", + EXP.xorAssign: "^=", + + EXP.comma: ",", + EXP.declaration: "declaration", + EXP.interval: "interval", + EXP.loweredAssignExp: "=" +]; + +struct StorageClassStringMap +{ + StorageClass stc; + string id; +} -string EXPtoString(EXP op) +static immutable StorageClassStringMap[] TableOfStorageClassStrings = [ + StorageClassStringMap(STC.auto_, Token.toString(TOK.auto_)), + StorageClassStringMap(STC.scope_, Token.toString(TOK.scope_)), + StorageClassStringMap(STC.static_, Token.toString(TOK.static_)), + StorageClassStringMap(STC.extern_, Token.toString(TOK.extern_)), + StorageClassStringMap(STC.const_, Token.toString(TOK.const_)), + StorageClassStringMap(STC.final_, Token.toString(TOK.final_)), + StorageClassStringMap(STC.abstract_, Token.toString(TOK.abstract_)), + StorageClassStringMap(STC.synchronized_, Token.toString(TOK.synchronized_)), + StorageClassStringMap(STC.deprecated_, Token.toString(TOK.deprecated_)), + StorageClassStringMap(STC.override_, Token.toString(TOK.override_)), + StorageClassStringMap(STC.lazy_, Token.toString(TOK.lazy_)), + StorageClassStringMap(STC.alias_, Token.toString(TOK.alias_)), + StorageClassStringMap(STC.out_, Token.toString(TOK.out_)), + StorageClassStringMap(STC.in_, Token.toString(TOK.in_)), + StorageClassStringMap(STC.manifest, Token.toString(TOK.enum_)), + StorageClassStringMap(STC.immutable_, Token.toString(TOK.immutable_)), + StorageClassStringMap(STC.shared_, Token.toString(TOK.shared_)), + StorageClassStringMap(STC.nothrow_, Token.toString(TOK.nothrow_)), + StorageClassStringMap(STC.wild, Token.toString(TOK.inout_)), + StorageClassStringMap(STC.pure_, Token.toString(TOK.pure_)), + StorageClassStringMap(STC.ref_, Token.toString(TOK.ref_)), + StorageClassStringMap(STC.return_, Token.toString(TOK.return_)), + StorageClassStringMap(STC.gshared, Token.toString(TOK.gshared)), + StorageClassStringMap(STC.nogc, "@nogc"), + StorageClassStringMap(STC.live, "@live"), + StorageClassStringMap(STC.property, "@property"), + StorageClassStringMap(STC.safe, "@safe"), + StorageClassStringMap(STC.trusted, "@trusted"), + StorageClassStringMap(STC.system, "@system"), + StorageClassStringMap(STC.disable, "@disable"), + StorageClassStringMap(STC.future, "@__future"), + StorageClassStringMap(STC.local, "__local"), +]; +// dfmt on + +void linkageToBuffer(ref OutBuffer buf, LINK linkage) @safe nothrow pure { - static immutable char*[EXP.max + 1] strings = - [ - EXP.type : "type", - EXP.error : "error", - EXP.objcClassReference : "class", - - EXP.mixin_ : "mixin", - - EXP.import_ : "import", - EXP.dotVariable : "dotvar", - EXP.scope_ : "scope", - EXP.identifier : "identifier", - EXP.this_ : "this", - EXP.super_ : "super", - EXP.int64 : "long", - EXP.float64 : "double", - EXP.complex80 : "creal", - EXP.null_ : "null", - EXP.string_ : "string", - EXP.arrayLiteral : "arrayliteral", - EXP.assocArrayLiteral : "assocarrayliteral", - EXP.classReference : "classreference", - EXP.file : "__FILE__", - EXP.fileFullPath : "__FILE_FULL_PATH__", - EXP.line : "__LINE__", - EXP.moduleString : "__MODULE__", - EXP.functionString : "__FUNCTION__", - EXP.prettyFunction : "__PRETTY_FUNCTION__", - EXP.typeid_ : "typeid", - EXP.is_ : "is", - EXP.assert_ : "assert", - EXP.halt : "halt", - EXP.template_ : "template", - EXP.dSymbol : "symbol", - EXP.function_ : "function", - EXP.variable : "var", - EXP.symbolOffset : "symoff", - EXP.structLiteral : "structLiteral", - EXP.compoundLiteral : "compoundliteral", - EXP.arrayLength : "arraylength", - EXP.delegatePointer : "delegateptr", - EXP.delegateFunctionPointer : "delegatefuncptr", - EXP.remove : "remove", - EXP.tuple : "sequence", - EXP.traits : "__traits", - EXP.overloadSet : "__overloadset", - EXP.void_ : "void", - EXP.vectorArray : "vectorarray", - EXP._Generic : "_Generic", - - // post - EXP.dotTemplateInstance : "dotti", - EXP.dotIdentifier : "dotid", - EXP.dotTemplateDeclaration : "dottd", - EXP.dot : ".", - EXP.dotType : "dottype", - EXP.plusPlus : "++", - EXP.minusMinus : "--", - EXP.prePlusPlus : "++", - EXP.preMinusMinus : "--", - EXP.call : "call", - EXP.slice : "..", - EXP.array : "[]", - EXP.index : "[i]", - - EXP.delegate_ : "delegate", - EXP.address : "&", - EXP.star : "*", - EXP.negate : "-", - EXP.uadd : "+", - EXP.not : "!", - EXP.tilde : "~", - EXP.delete_ : "delete", - EXP.new_ : "new", - EXP.newAnonymousClass : "newanonclass", - EXP.cast_ : "cast", - - EXP.vector : "__vector", - EXP.pow : "^^", - - EXP.mul : "*", - EXP.div : "/", - EXP.mod : "%", - - EXP.add : "+", - EXP.min : "-", - EXP.concatenate : "~", - - EXP.leftShift : "<<", - EXP.rightShift : ">>", - EXP.unsignedRightShift : ">>>", - - EXP.lessThan : "<", - EXP.lessOrEqual : "<=", - EXP.greaterThan : ">", - EXP.greaterOrEqual : ">=", - EXP.in_ : "in", - - EXP.equal : "==", - EXP.notEqual : "!=", - EXP.identity : "is", - EXP.notIdentity : "!is", - - EXP.and : "&", - EXP.xor : "^", - EXP.or : "|", - - EXP.andAnd : "&&", - EXP.orOr : "||", - - EXP.question : "?", - - EXP.assign : "=", - EXP.construct : "=", - EXP.blit : "=", - EXP.addAssign : "+=", - EXP.minAssign : "-=", - EXP.concatenateAssign : "~=", - EXP.concatenateElemAssign : "~=", - EXP.concatenateDcharAssign : "~=", - EXP.mulAssign : "*=", - EXP.divAssign : "/=", - EXP.modAssign : "%=", - EXP.powAssign : "^^=", - EXP.leftShiftAssign : "<<=", - EXP.rightShiftAssign : ">>=", - EXP.unsignedRightShiftAssign : ">>>=", - EXP.andAssign : "&=", - EXP.orAssign : "|=", - EXP.xorAssign : "^=", - - EXP.comma : ",", - EXP.declaration : "declaration", - - EXP.interval : "interval", - EXP.loweredAssignExp : "=" - ]; - const p = strings[op]; - if (!p) + const s = linkageToString(linkage); + if (s.length) { - printf("error: EXP %d has no string\n", op); - return "XXXXX"; - //assert(0); + buf.writestring("extern ("); + buf.writestring(s); + buf.writeByte(')'); } - assert(p); - return p[0 .. strlen(p)]; +} + +/** + The names __DATE__, __TIME__,__EOF__, __VENDOR__, __TIMESTAMP__, __VERSION__ + are special to the D lexer and cannot be used as D source variable names. + + Params: + id = name to check + + Returns: + true if special C name +*/ +bool isSpecialCName(Identifier id) +{ + auto s = id.toString(); + return s.length >= 7 && s[0] == '_' && s[1] == '_' && (id == Id.DATE + || id == Id.TIME || id == Id.EOFX || id == Id.VENDOR + || id == Id.TIMESTAMP || id == Id.VERSIONX); } diff --git a/compiler/src/dmd/identifier.d b/compiler/src/dmd/identifier.d index 6fd0d3ad5ec6..7f433ea35ffd 100644 --- a/compiler/src/dmd/identifier.d +++ b/compiler/src/dmd/identifier.d @@ -110,6 +110,8 @@ nothrow: p = "this"; else if (this == Id.dtor) p = "~this"; + else if (this == Id.postblit) + p = "this(this)"; else if (this == Id.unitTest) p = "unittest"; else if (this == Id.dollar) diff --git a/compiler/src/dmd/inline.d b/compiler/src/dmd/inline.d index a95ded38f2bb..b1b8913f22ba 100644 --- a/compiler/src/dmd/inline.d +++ b/compiler/src/dmd/inline.d @@ -441,7 +441,7 @@ public: override void visit(Expression e) { - //printf("Expression.doInlineAs!%s(%s): %s\n", Result.stringof.ptr, EXPtoString(e.op).ptr, e.toChars()); + //printf("Expression.doInlineAs!%s(%s): %s\n", Result.stringof.ptr, expressionTypeToString(e.op).ptr, e.toChars()); result = e.copy(); } diff --git a/compiler/src/dmd/json.d b/compiler/src/dmd/json.d index f20b3d4b38a3..076066cb58b4 100644 --- a/compiler/src/dmd/json.d +++ b/compiler/src/dmd/json.d @@ -337,7 +337,7 @@ public: arrayStart(); while (stc) { - auto p = stcToString(stc); + auto p = storageClassToString(stc); assert(p.length); item(p); } @@ -430,8 +430,9 @@ public: else property("kind", s.kind.toDString); } - // TODO: How about package(names)? - property("protection", visibilityToString(s.visible().kind)); + + writePropertyVisibility("protection", s.visible()); + if (EnumMember em = s.isEnumMember()) { if (em.origValue) @@ -518,7 +519,7 @@ public: property("comment", s.comment.toDString); property("line", "char", s.loc); if (s.visible().kind != Visibility.Kind.public_) - property("protection", visibilityToString(s.visible().kind)); + writePropertyVisibility("protection", s.visible()); if (s.aliasId) property("alias", s.aliasId.toString()); bool hasRenamed = false; @@ -970,6 +971,18 @@ public: arrayEnd(); objectEnd(); } + +private: + extern(D) void writePropertyVisibility(string name, Visibility visibility) + { + propertyStart(name); + + stringStart(); + visibilityToBuffer(*this.buf, visibility); + stringEnd(); + + comma(); + } } /*********************************** diff --git a/compiler/src/dmd/lambdacomp.d b/compiler/src/dmd/lambdacomp.d index a1db8d525485..041a9ce2541c 100644 --- a/compiler/src/dmd/lambdacomp.d +++ b/compiler/src/dmd/lambdacomp.d @@ -339,7 +339,7 @@ public: return; buf.writeByte('('); - buf.writestring(EXPtoString(exp.op)); + buf.writestring(expressionTypeToString(exp.op)); exp.e1.accept(this); if (buf.length != 0) buf.writestring(")_"); @@ -372,7 +372,7 @@ public: return; buf.writeByte('('); - buf.writestring(EXPtoString(exp.op).ptr); + buf.writestring(expressionTypeToString(exp.op).ptr); exp.e1.accept(this); if (buf.length == 0) diff --git a/compiler/src/dmd/main.d b/compiler/src/dmd/main.d index a5e53ee18bd6..bf5a8dd066a3 100644 --- a/compiler/src/dmd/main.d +++ b/compiler/src/dmd/main.d @@ -488,29 +488,8 @@ private int tryMain(size_t argc, const(char)** argv, ref Param params) if (global.errors) fatal(); - if (params.dihdr.doOutput) - { - /* Generate 'header' import files. - * Since 'header' import files must be independent of command - * line switches and what else is imported, they are generated - * before any semantic analysis. - */ - OutBuffer buf; - foreach (m; modules) - { - if (m.filetype == FileType.dhdr) - continue; - if (params.v.verbose) - message("import %s", m.toChars()); - - buf.reset(); // reuse the buffer - genhdrfile(m, params.dihdr.fullOutput, buf); - if (!writeFile(m.loc, m.hdrfile.toString(), buf[])) - fatal(); - } - } if (global.errors) - removeHdrFilesAndFail(params, modules); + fatal(); // load all unconditional imports for better symbol resolving foreach (m; modules) @@ -520,7 +499,7 @@ private int tryMain(size_t argc, const(char)** argv, ref Param params) m.importAll(null); } if (global.errors) - removeHdrFilesAndFail(params, modules); + fatal(); backend_init(params, driverParams, target); @@ -553,7 +532,7 @@ private int tryMain(size_t argc, const(char)** argv, ref Param params) } Module.runDeferredSemantic2(); if (global.errors) - removeHdrFilesAndFail(params, modules); + fatal(); // Do pass 3 semantic analysis foreach (m; modules) @@ -578,7 +557,7 @@ private int tryMain(size_t argc, const(char)** argv, ref Param params) } Module.runDeferredSemantic3(); if (global.errors) - removeHdrFilesAndFail(params, modules); + fatal(); // Scan for functions to inline foreach (m; modules) @@ -599,7 +578,31 @@ private int tryMain(size_t argc, const(char)** argv, ref Param params) // Do not attempt to generate output files if errors or warnings occurred if (global.errors || global.warnings) - removeHdrFilesAndFail(params, modules); + { + fatal(); + } + else if (params.dihdr.doOutput) + { + // Generate 'header' files. + // This was previously done prior to semantic analysis. + // Thanks to inferring of attributes (even on non-templated symbols), + // the emitted files were not actually representative of the symbols compiled. + // It would therefore have failed to link as of 2024. + + OutBuffer buf; + foreach (m; modules) + { + if (m.filetype == FileType.dhdr) + continue; + if (params.v.verbose) + message("import %s", m.toChars()); + + buf.reset(); // reuse the buffer + genhdrfile(m, params.dihdr.fullOutput, buf); + if (!writeFile(m.loc, m.hdrfile.toString(), buf[])) + fatal(); + } + } // inlineScan incrementally run semantic3 of each expanded functions. // So deps file generation should be moved after the inlining stage. diff --git a/compiler/src/dmd/mtype.d b/compiler/src/dmd/mtype.d index a91a0a4ef630..f739d593ded3 100644 --- a/compiler/src/dmd/mtype.d +++ b/compiler/src/dmd/mtype.d @@ -480,7 +480,7 @@ extern (C++) abstract class Type : ASTNode HdrGenState hgs; hgs.fullQual = QualifyTypes; - toCBuffer(this, buf, null, hgs); + hgs.toCBuffer(this, buf, null); return buf.extractChars(); } diff --git a/compiler/src/dmd/ob.d b/compiler/src/dmd/ob.d index 756caf870bcb..3b1f5cd45f42 100644 --- a/compiler/src/dmd/ob.d +++ b/compiler/src/dmd/ob.d @@ -1368,7 +1368,7 @@ void genKill(ref ObState obstate, ObNode* ob) override void visit(Expression e) { - //printf("[%s] %s: %s\n", e.loc.toChars(), EXPtoString(e.op).ptr, e.toChars()); + //printf("[%s] %s: %s\n", e.loc.toChars(), expressionTypeToString(e.op).ptr, e.toChars()); //assert(0); } diff --git a/compiler/src/dmd/opover.d b/compiler/src/dmd/opover.d index 0d32d7d9713d..a2d45594fc01 100644 --- a/compiler/src/dmd/opover.d +++ b/compiler/src/dmd/opover.d @@ -200,7 +200,7 @@ Objects* opToArg(Scope* sc, EXP op) default: break; } - Expression e = new StringExp(Loc.initial, EXPtoString(op)); + Expression e = new StringExp(Loc.initial, expressionTypeToString(op)); e = e.expressionSemantic(sc); auto tiargs = new Objects(); tiargs.push(e); @@ -409,7 +409,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) { // @@@DEPRECATED_2.110@@@. // Deprecated in 2.088, made an error in 2.100 - error(e.loc, "`%s` is obsolete. Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr); + error(e.loc, "`%s` is obsolete. Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), expressionTypeToString(e.op).ptr); return ErrorExp.get(); } } @@ -419,7 +419,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) /* Rewrite op(e1) as: * op(e1.aliasthis) */ - //printf("att una %s e1 = %s\n", EXPtoString(op).ptr, this.e1.type.toChars()); + //printf("att una %s e1 = %s\n", expressionTypeToString(op).ptr, this.e1.type.toChars()); if (auto e1 = resolveAliasThis(sc, e.e1, true)) { e.e1 = e1; @@ -682,9 +682,9 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) // @@@DEPRECATED_2.110@@@. // Deprecated in 2.088, made an error in 2.100 if (id == Id.postinc || id == Id.postdec) - error(e.loc, "`%s` is obsolete. Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr); + error(e.loc, "`%s` is obsolete. Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), expressionTypeToString(e.op).ptr); else - error(e.loc, "`%s` is obsolete. Use `opBinary(string op)(...) if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr); + error(e.loc, "`%s` is obsolete. Use `opBinary(string op)(...) if (op == \"%s\")` instead.", id.toChars(), expressionTypeToString(e.op).ptr); return ErrorExp.get(); } } @@ -700,7 +700,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) { // @@@DEPRECATED_2.110@@@. // Deprecated in 2.088, made an error in 2.100 - error(e.loc, "`%s` is obsolete. Use `opBinaryRight(string op)(...) if (op == \"%s\")` instead.", id_r.toChars(), EXPtoString(e.op).ptr); + error(e.loc, "`%s` is obsolete. Use `opBinaryRight(string op)(...) if (op == \"%s\")` instead.", id_r.toChars(), expressionTypeToString(e.op).ptr); return ErrorExp.get(); } } @@ -923,8 +923,8 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) t2.ty == Tclass && e.e1.op == EXP.null_) { error(e.loc, "use `%s` instead of `%s` when comparing with `null`", - EXPtoString(e.op == EXP.equal ? EXP.identity : EXP.notIdentity).ptr, - EXPtoString(e.op).ptr); + expressionTypeToString(e.op == EXP.equal ? EXP.identity : EXP.notIdentity).ptr, + expressionTypeToString(e.op).ptr); return ErrorExp.get(); } if (t1.ty == Tclass && t2.ty == Tnull || @@ -1233,7 +1233,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) { // @@@DEPRECATED_2.110@@@. // Deprecated in 2.088, made an error in 2.100 - scope char[] op = EXPtoString(e.op).dup; + scope char[] op = expressionTypeToString(e.op).dup; op[$-1] = '\0'; // remove trailing `=` error(e.loc, "`%s` is obsolete. Use `opOpAssign(string op)(...) if (op == \"%s\")` instead.", id.toChars(), op.ptr); return ErrorExp.get(); diff --git a/compiler/src/dmd/printast.d b/compiler/src/dmd/printast.d index 02dc65390b03..5476732ded97 100644 --- a/compiler/src/dmd/printast.d +++ b/compiler/src/dmd/printast.d @@ -47,7 +47,7 @@ extern (C++) final class PrintASTVisitor : Visitor override void visit(Expression e) { printIndent(indent); - auto s = EXPtoString(e.op); + auto s = expressionTypeToString(e.op); printf("%.*s %s\n", cast(int)s.length, s.ptr, e.type ? e.type.toChars() : ""); } @@ -71,7 +71,7 @@ extern (C++) final class PrintASTVisitor : Visitor override void visit(StructLiteralExp e) { printIndent(indent); - auto s = EXPtoString(e.op); + auto s = expressionTypeToString(e.op); printf("%.*s %s, %s\n", cast(int)s.length, s.ptr, e.type ? e.type.toChars() : "", e.toChars()); } @@ -126,7 +126,7 @@ extern (C++) final class PrintASTVisitor : Visitor override void visit(CastExp e) { printIndent(indent); - auto s = EXPtoString(e.op); + auto s = expressionTypeToString(e.op); printf("%.*s %s\n", cast(int)s.length, s.ptr, e.type ? e.type.toChars() : ""); printIndent(indent + 2); printf(".to: %s\n", e.to.toChars()); diff --git a/compiler/src/dmd/semantic3.d b/compiler/src/dmd/semantic3.d index 963fa9238a08..79d1685efb34 100644 --- a/compiler/src/dmd/semantic3.d +++ b/compiler/src/dmd/semantic3.d @@ -1464,7 +1464,7 @@ private extern(C++) final class Semantic3Visitor : Visitor { // storage_class is apparently not set for dtor & ctor OutBuffer ob; - stcToBuffer(ob, + storageClassToBuffer(ob, (ngErr ? STC.nogc : 0) | (puErr ? STC.pure_ : 0) | (saErr ? STC.system : 0) diff --git a/compiler/src/dmd/target.d b/compiler/src/dmd/target.d index 104cf580ea75..e4c9600b62c6 100644 --- a/compiler/src/dmd/target.d +++ b/compiler/src/dmd/target.d @@ -724,7 +724,7 @@ extern (C++) struct Target */ extern (C++) bool isVectorOpSupported(Type type, EXP op, Type t2 = null) { - import dmd.hdrgen : EXPtoString; + import dmd.hdrgen : expressionTypeToString; auto tvec = type.isTypeVector(); if (tvec is null) @@ -919,7 +919,7 @@ extern (C++) struct Target default: // import std.stdio : stderr, writeln; // stderr.writeln(op); - assert(0, "unhandled op " ~ EXPtoString(cast(EXP)op)); + assert(0, "unhandled op " ~ expressionTypeToString(cast(EXP)op)); } return supported; } diff --git a/compiler/src/dmd/traits.d b/compiler/src/dmd/traits.d index 5ec38449123c..13155f75b7a2 100644 --- a/compiler/src/dmd/traits.d +++ b/compiler/src/dmd/traits.d @@ -789,9 +789,9 @@ Expression semanticTraits(TraitsExp e, Scope* sc) if (s.semanticRun == PASS.initial) s.dsymbolSemantic(null); - auto protName = visibilityToString(s.visible().kind); // TODO: How about package(names) - assert(protName); - auto se = new StringExp(e.loc, protName); + OutBuffer protNameBuffer; + visibilityToBuffer(protNameBuffer, s.visible); + auto se = new StringExp(e.loc, protNameBuffer.extractSlice()); return se.expressionSemantic(sc); } if (e.ident == Id.parent) @@ -1281,7 +1281,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) Expression x = isExpression(o); Type t = isType(o); if (x) - printf("e = %s %s\n", EXPtoString(x.op).ptr, x.toChars()); + printf("e = %s %s\n", expressionTypeToString(x.op).ptr, x.toChars()); if (t) printf("t = %d %s\n", t.ty, t.toChars()); } diff --git a/compiler/src/dmd/typesem.d b/compiler/src/dmd/typesem.d index 31ebc4c809c6..7575e425a8ab 100644 --- a/compiler/src/dmd/typesem.d +++ b/compiler/src/dmd/typesem.d @@ -2046,8 +2046,8 @@ 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; storageClassToBuffer(buf1, stc1 | ((stc1 & STC.ref_) ? (fparam.storageClass & STC.auto_) : 0)); + OutBuffer buf2; storageClassToBuffer(buf2, stc2); .error(loc, "incompatible parameter storage classes `%s` and `%s`", buf1.peekChars(), buf2.peekChars()); @@ -6999,7 +6999,7 @@ private: */ Expression typeToExpressionHelper(TypeQualified t, Expression e, size_t i = 0) { - //printf("toExpressionHelper(e = %s %s)\n", EXPtoString(e.op).ptr, e.toChars()); + //printf("toExpressionHelper(e = %s %s)\n", expressionTypeToString(e.op).ptr, e.toChars()); foreach (id; t.idents[i .. t.idents.length]) { //printf("\t[%d] e: '%s', id: '%s'\n", i, e.toChars(), id.toChars()); diff --git a/compiler/test/compilable/bug6963.d b/compiler/test/compilable/bug6963.d index 33d595cfedbc..af3ad7ea14fb 100644 --- a/compiler/test/compilable/bug6963.d +++ b/compiler/test/compilable/bug6963.d @@ -4,8 +4,8 @@ /* TEST_OUTPUT: --- -output foo: 1e: pure nothrow @nogc @safe void(int x) -output foo: 3e: pure nothrow @nogc @safe void(int x) +output foo: 1e: void(int x) pure nothrow @nogc @safe +output foo: 3e: void(int x) pure nothrow @nogc @safe --- */ diff --git a/compiler/test/compilable/ctod.i b/compiler/test/compilable/ctod.i index b836dcaf8db5..a9a1b1ad1332 100644 --- a/compiler/test/compilable/ctod.i +++ b/compiler/test/compilable/ctod.i @@ -10,7 +10,7 @@ TEST_OUTPUT: extern (C) { uint equ(double x, double y); - enum SQLINTERVAL + enum SQLINTERVAL : int { SQL_IS_YEAR = 1, SQL_IS_MONTH = 2, @@ -27,9 +27,9 @@ extern (C) int x = void; } alias T = S; - enum + enum : int { - A, + A = 0, } /+enum int __DATE__ = 1+/; /+enum int __TIME__ = 1+/; diff --git a/compiler/test/compilable/extra-files/ddoc10.html b/compiler/test/compilable/extra-files/ddoc10.html index fe0044d28e8c..7d619a97d97e 100644 --- a/compiler/test/compilable/extra-files/ddoc10.html +++ b/compiler/test/compilable/extra-files/ddoc10.html @@ -1088,7 +1088,7 @@

Declaration

- const pure nothrow this(long ticks); + this(long ticks) const pure nothrow;

@@ -1113,7 +1113,7 @@

Declaration

- const pure nothrow void foo(long ticks); + void foo(long ticks) const pure nothrow;

diff --git a/compiler/test/compilable/extra-files/ddoc10869.html b/compiler/test/compilable/extra-files/ddoc10869.html index 1d7365d242a8..a8d0c86fab63 100644 --- a/compiler/test/compilable/extra-files/ddoc10869.html +++ b/compiler/test/compilable/extra-files/ddoc10869.html @@ -552,7 +552,7 @@

Declaration

- const void c1Foo(); + void c1Foo() const;

@@ -577,7 +577,7 @@

Declaration

- immutable void i1Foo(); + void i1Foo() immutable;

@@ -602,7 +602,7 @@

Declaration

- immutable void c2Foo(); + void c2Foo() immutable;

@@ -627,7 +627,7 @@

Declaration

- immutable void i2Foo(); + void i2Foo() immutable;

diff --git a/compiler/test/compilable/extra-files/ddoc14.html b/compiler/test/compilable/extra-files/ddoc14.html index 1d18931920d6..da9d095912f8 100644 --- a/compiler/test/compilable/extra-files/ddoc14.html +++ b/compiler/test/compilable/extra-files/ddoc14.html @@ -623,7 +623,7 @@

Declaration

- pure nothrow V mPrefix(lazy P p); + V mPrefix(lazy P p) pure nothrow;

@@ -655,7 +655,7 @@

Declaration

- pure nothrow V mSuffix(lazy P p); + V mSuffix(lazy P p) pure nothrow;

@@ -687,7 +687,7 @@

Declaration

- pure nothrow V mSuffixTemplate(T)(lazy P p, T[] t...); + V mSuffixTemplate(T)(lazy P p, T[] t...) pure nothrow;

@@ -719,7 +719,7 @@

Declaration

- pure nothrow V mScoped(lazy P p); + V mScoped(lazy P p) pure nothrow;

@@ -751,7 +751,7 @@

Declaration

- pure nothrow auto mAutoPrefix(ref P p); + auto mAutoPrefix(ref P p) pure nothrow;

@@ -783,7 +783,7 @@

Declaration

- pure nothrow auto mAutoTemplateSuffix(alias T)(ref T t); + auto mAutoTemplateSuffix(alias T)(ref T t) pure nothrow;

@@ -815,7 +815,7 @@

Declaration

- pure nothrow V mColon(lazy P p); + V mColon(lazy P p) pure nothrow;

@@ -946,7 +946,7 @@

Declaration

- pure nothrow V mPrefix(lazy P p); + V mPrefix(lazy P p) pure nothrow;

@@ -978,7 +978,7 @@

Declaration

- pure nothrow V mSuffix(lazy P p); + V mSuffix(lazy P p) pure nothrow;

@@ -1010,7 +1010,7 @@

Declaration

- pure nothrow V mSuffixTemplate(T)(lazy P p, T[] t...); + V mSuffixTemplate(T)(lazy P p, T[] t...) pure nothrow;

@@ -1042,7 +1042,7 @@

Declaration

- pure nothrow V mScoped(lazy P p); + V mScoped(lazy P p) pure nothrow;

@@ -1074,7 +1074,7 @@

Declaration

- pure nothrow auto mAutoPrefix(ref P p); + auto mAutoPrefix(ref P p) pure nothrow;

@@ -1106,7 +1106,7 @@

Declaration

- pure nothrow auto mAutoTemplateSuffix(alias T)(ref T t); + auto mAutoTemplateSuffix(alias T)(ref T t) pure nothrow;

@@ -1138,7 +1138,7 @@

Declaration

- pure nothrow V mColon(lazy P p); + V mColon(lazy P p) pure nothrow;

@@ -1239,7 +1239,7 @@

Declaration

- pure nothrow V mPrefix(lazy P p); + V mPrefix(lazy P p) pure nothrow;

@@ -1271,7 +1271,7 @@

Declaration

- pure nothrow V mSuffix(lazy P p); + V mSuffix(lazy P p) pure nothrow;

@@ -1303,7 +1303,7 @@

Declaration

- pure nothrow V mSuffixTemplate(T)(lazy P p, T[] t...); + V mSuffixTemplate(T)(lazy P p, T[] t...) pure nothrow;

@@ -1335,7 +1335,7 @@

Declaration

- pure nothrow V mScoped(lazy P p); + V mScoped(lazy P p) pure nothrow;

@@ -1367,7 +1367,7 @@

Declaration

- pure nothrow auto mAutoPrefix(ref P p); + auto mAutoPrefix(ref P p) pure nothrow;

@@ -1399,7 +1399,7 @@

Declaration

- pure nothrow auto mAutoTemplateSuffix(alias T)(ref T t); + auto mAutoTemplateSuffix(alias T)(ref T t) pure nothrow;

@@ -1431,7 +1431,7 @@

Declaration

- pure nothrow V mColon(lazy P p); + V mColon(lazy P p) pure nothrow;

diff --git a/compiler/test/compilable/extra-files/header1.di b/compiler/test/compilable/extra-files/header1.di index 11186409ddf4..60bfc5045aab 100644 --- a/compiler/test/compilable/extra-files/header1.di +++ b/compiler/test/compilable/extra-files/header1.di @@ -517,8 +517,8 @@ struct SafeS @safe { ref SafeS foo() return; - scope SafeS foo2() return; - ref scope SafeS foo3() return; + SafeS foo2() return scope; + ref SafeS foo3() return scope; int* p; } } diff --git a/compiler/test/compilable/extra-files/header18365.d b/compiler/test/compilable/extra-files/header18365.d index a0fb8333d1b3..fbb53c42d790 100644 --- a/compiler/test/compilable/extra-files/header18365.d +++ b/compiler/test/compilable/extra-files/header18365.d @@ -2,5 +2,5 @@ module foo.bar.ba; nothrow pure @nogc @safe package(foo) { void foo(); - nothrow pure @nogc @safe package(foo.bar) void foo2(); + package(foo.bar) void foo2() nothrow pure @nogc @safe; } diff --git a/compiler/test/compilable/extra-files/header2.di b/compiler/test/compilable/extra-files/header2.di index 7a2cff9de317..94a511615f95 100644 --- a/compiler/test/compilable/extra-files/header2.di +++ b/compiler/test/compilable/extra-files/header2.di @@ -3,16 +3,19 @@ class C { } -void foo(const C c, const(char)[] s, const int* q, const(int*) p); +void foo(const(C) c, const(char)[] s, const(int*) q, const(int*) p); void bar(in void* p); void f(void function() f2); class C2; -void foo2(const C2 c); +void foo2(const(C2) c); struct Foo3 { int k; - @nogc @live @trusted @disable ~this(); + @disable ~this() @nogc @live @trusted; this(this); + alias __xdtor = __dtor; + alias __xpostblit = __postblit; + @disable ref Foo3 opAssign(Foo3 p) @nogc @trusted; } class C3 { @@ -24,9 +27,6 @@ T foo3(T)() struct S4A(T) { T x; - @safe ~this() - { - } } struct S4B(T) if (1) { @@ -76,7 +76,7 @@ template templateVariableBar(T) if (is(T == int)) { enum int templateVariableBar = T.stringof.length; } -extern typeof(3 / 2.0) flit; +extern double flit; void foo11217()(const int[] arr) { } @@ -105,7 +105,7 @@ void test13275(); align (1) struct S9766 { align {} - align (true ? 2 : 3) + align (2) { int var1; align int var2; @@ -119,14 +119,14 @@ align (2) struct S12200_2 { align (1) {} } -pure nothrow @trusted inout(T)[] overlap(T)(inout(T)[] r1, inout(T)[] r2) +inout(T)[] overlap(T)(inout(T)[] r1, inout(T)[] r2) pure nothrow @trusted { alias U = inout(T); - static nothrow U* max(U* a, U* b) + static U* max(U* a, U* b) nothrow { return a > b ? a : b; } - static nothrow U* min(U* a, U* b) + static U* min(U* a, U* b) nothrow { return a < b ? a : b; } @@ -170,7 +170,7 @@ extern const typeof(new class LeClass, LeInterface ) levar; class CC { - @safe void fun()() + void fun()() @safe { () pure @trusted { @@ -180,4 +180,4 @@ class CC } private struct Export { -} \ No newline at end of file +} diff --git a/compiler/test/compilable/extra-files/header2i.di b/compiler/test/compilable/extra-files/header2i.di index 9c57de106e77..e2c491d4c9db 100644 --- a/compiler/test/compilable/extra-files/header2i.di +++ b/compiler/test/compilable/extra-files/header2i.di @@ -3,7 +3,7 @@ class C { } -void foo(const C c, const(char)[] s, const int* q, const(int*) p) +void foo(const(C) c, const(char)[] s, const(int*) q, const(int*) p) { } void bar(in void* p) @@ -11,18 +11,21 @@ void bar(in void* p) } void f(void function() f2); class C2; -void foo2(const C2 c); +void foo2(const(C2) c); struct Foo3 { int k; - @nogc @live @trusted @disable ~this() + @disable ~this() @nogc @live @trusted { - k = 1; + this.k = 1; } this(this) { - k = 2; + this.k = 2; } + alias __xdtor = __dtor; + alias __xpostblit = __postblit; + @disable ref Foo3 opAssign(Foo3 p) @nogc @trusted; } class C3 { @@ -37,9 +40,6 @@ T foo3(T)() struct S4A(T) { T x; - @safe ~this() - { - } } struct S4B(T) if (1) { @@ -89,7 +89,7 @@ template templateVariableBar(T) if (is(T == int)) { enum int templateVariableBar = T.stringof.length; } -extern typeof(3 / 2.0) flit; +extern double flit; void foo11217()(const int[] arr) { } @@ -207,7 +207,7 @@ void test13275() align (1) struct S9766 { align {} - align (true ? 2 : 3) + align (2) { int var1; align int var2; @@ -221,14 +221,14 @@ align (2) struct S12200_2 { align (1) {} } -pure nothrow @trusted inout(T)[] overlap(T)(inout(T)[] r1, inout(T)[] r2) +inout(T)[] overlap(T)(inout(T)[] r1, inout(T)[] r2) pure nothrow @trusted { alias U = inout(T); - static nothrow U* max(U* a, U* b) + static U* max(U* a, U* b) nothrow { return a > b ? a : b; } - static nothrow U* min(U* a, U* b) + static U* min(U* a, U* b) nothrow { return a < b ? a : b; } @@ -278,7 +278,7 @@ extern const typeof(new class LeClass, LeInterface ) levar; class CC { - @safe void fun()() + void fun()() @safe { () pure @trusted { diff --git a/compiler/test/compilable/extra-files/json.json b/compiler/test/compilable/extra-files/json.json index 1ff4b7ee4eb1..706a25c981a4 100644 --- a/compiler/test/compilable/extra-files/json.json +++ b/compiler/test/compilable/extra-files/json.json @@ -67,6 +67,7 @@ "kind": "shared static constructor", "line": 15, "name": "_sharedStaticCtor_L15_C5", + "protection": "", "storageClass": [ "static" ] @@ -78,6 +79,7 @@ "kind": "static constructor", "line": 16, "name": "_staticCtor_L16_C5", + "protection": "", "storageClass": [ "static" ] @@ -89,6 +91,7 @@ "kind": "shared static destructor", "line": 17, "name": "_sharedStaticDtor_L17_C5", + "protection": "", "storageClass": [ "static" ] @@ -100,6 +103,7 @@ "kind": "static destructor", "line": 18, "name": "_staticDtor_L18_C5", + "protection": "", "storageClass": [ "static" ] @@ -215,6 +219,7 @@ "kind": "variable", "line": 21, "name": "t", + "protection": "", "type": "T" } ], @@ -247,7 +252,8 @@ "init": "T", "kind": "variable", "line": 22, - "name": "t" + "name": "t", + "protection": "" } ], "name": "Bar", @@ -279,7 +285,8 @@ "kind": "function", "line": 23, "name": "t", - "type": "const T[0]()" + "protection": "", + "type": "T[0]() const" } ], "name": "Baz", @@ -515,6 +522,7 @@ "kind": "function", "line": 57, "name": "method1", + "protection": "", "type": "void()" }, { @@ -522,6 +530,7 @@ "kind": "function", "line": 61, "name": "method2", + "protection": "", "type": "void()" }, { @@ -529,6 +538,7 @@ "kind": "function", "line": 68, "name": "method4", + "protection": "", "type": "void()" } ], @@ -554,7 +564,7 @@ "kind": "function", "line": 74, "name": "bar", - "originalType": "@trusted myInt(ref uint blah, Bar2 foo = new Bar3(7))", + "originalType": "myInt(ref uint blah, Bar2 foo = new Bar3(7)) @trusted", "parameters": [ { "deco": "VALUE_REMOVED_FOR_TEST", @@ -647,6 +657,7 @@ "type": "T" } ], + "protection": "", "type": "(T t)" } ], @@ -874,6 +885,7 @@ "kind": "alias", "line": 141, "name": "Seq", + "protection": "", "type": "T" } ], diff --git a/compiler/test/compilable/extra-files/vcg-ast.d.cg b/compiler/test/compilable/extra-files/vcg-ast.d.cg index 640cba43ed67..246f1c361cbf 100644 --- a/compiler/test/compilable/extra-files/vcg-ast.d.cg +++ b/compiler/test/compilable/extra-files/vcg-ast.d.cg @@ -26,7 +26,7 @@ void foo() int a1 = 1; int a2 = 1; } -class C : Object +class C { invariant { @@ -49,7 +49,7 @@ class C : Object out (; true) out (r; true) { - pure nothrow @nogc @safe void __require() + void __require() pure nothrow @nogc @safe { { { @@ -65,7 +65,7 @@ class C : Object goto __returnLabel; __returnLabel: this.__invariant(); - pure nothrow @nogc @safe void __ensure(ref const(int) __result) + void __ensure(ref const(int) __result) pure nothrow @nogc @safe { { } @@ -131,14 +131,14 @@ RTInfo!(C) enum immutable(void)* RTInfo = null; } -NoPointersBitmapPayload!1$?:32=u|64=LU$ +NoPointersBitmapPayload!1LU { - enum $?:32=uint|64=ulong$[1] NoPointersBitmapPayload = [0$?:32=u|64=LU$]; + enum ulong[1] NoPointersBitmapPayload = [0LU]; } values!(__c_wchar_t) { - pure nothrow @safe __c_wchar_t[] values() + __c_wchar_t[] values() pure nothrow @safe { __c_wchar_t[] values = [cast(__c_wchar_t)'\uffff']; return values; diff --git a/compiler/test/compilable/header18364.d b/compiler/test/compilable/header18364.d index 080a0960a149..a0fc6005bac8 100644 --- a/compiler/test/compilable/header18364.d +++ b/compiler/test/compilable/header18364.d @@ -10,8 +10,8 @@ TEST_OUTPUT: module foo.bar.ba; nothrow pure @nogc @safe package(foo) { - void foo(); - nothrow pure @nogc @safe package(foo.bar) void foo2(); + void foo() pure nothrow @nogc @safe; + nothrow pure @nogc @safe package(foo.bar) void foo2() pure nothrow @nogc @safe; } --- */ diff --git a/compiler/test/compilable/header18365.d b/compiler/test/compilable/header18365.d index 7e51fb26cc77..5138c1070469 100644 --- a/compiler/test/compilable/header18365.d +++ b/compiler/test/compilable/header18365.d @@ -13,9 +13,9 @@ struct FullCaseEntry ubyte n; ubyte size; ubyte entry_len; - auto const pure nothrow @nogc @property @trusted value() return + @property const(dchar)[] value() const pure nothrow @nogc return @trusted { - return seq[0..entry_len]; + return this.seq[0..cast(ulong)this.entry_len]; } } --- diff --git a/compiler/test/compilable/jsonc.i b/compiler/test/compilable/jsonc.i index 013761af1b36..b79d74263c2d 100644 --- a/compiler/test/compilable/jsonc.i +++ b/compiler/test/compilable/jsonc.i @@ -12,13 +12,14 @@ TEST_OUTPUT: "baseDeco": "i", "char": 9, "kind": "enum", - "line": 43, + "line": 44, "members": [ { "char": 17, "kind": "enum member", - "line": 43, - "name": "a" + "line": 44, + "name": "a", + "protection": "" } ], "name": "E", @@ -28,7 +29,7 @@ TEST_OUTPUT: "char": 22, "deco": "VALUE_REMOVED_FOR_TEST", "kind": "alias", - "line": 43, + "line": 44, "name": "E", "originalType": "enum E", "protection": "public" diff --git a/compiler/test/compilable/shared.d b/compiler/test/compilable/shared.d index 647910ecf161..0802769ec944 100644 --- a/compiler/test/compilable/shared.d +++ b/compiler/test/compilable/shared.d @@ -1,8 +1,8 @@ /* REQUIRED_ARGS: -preview=nosharedaccess TEST_OUTPUT: --- -pure nothrow @nogc ref @safe shared(C1)(return ref shared(C1) c) -pure nothrow @nogc ref @safe shared(int)(return ref shared(C3) c) +ref shared(C1)(return ref shared(C1) c) pure nothrow @nogc @safe +ref shared(int)(return ref shared(C3) c) pure nothrow @nogc @safe --- */ ref shared(int) f(return shared ref int y) diff --git a/compiler/test/compilable/test16495.d b/compiler/test/compilable/test16495.d index 70f11be49b89..dc1984e05f6e 100644 --- a/compiler/test/compilable/test16495.d +++ b/compiler/test/compilable/test16495.d @@ -92,7 +92,7 @@ void names() // Function types + function attributes static assert(__traits(fullyQualifiedName, typeof(func)) == "ref const(" ~ xx ~ "[string])(ref " ~ xx ~ ", lazy scope string)"); static assert(__traits(fullyQualifiedName, typeof(retfunc)) == "ref const(" ~ xx ~ "[string])(return ref " ~ xx ~ ")"); - static assert(__traits(fullyQualifiedName, typeof(inoutFunc)) == "inout "~xx~"(inout("~xx~"))"); + static assert(__traits(fullyQualifiedName, typeof(inoutFunc)) == ""~xx~"(inout("~xx~")) inout"); static assert(__traits(fullyQualifiedName, typeof(deleg)) == "const(" ~ xx ~ " delegate(double, string) nothrow @safe)"); static assert(__traits(fullyQualifiedName, typeof(inoutDeleg)) == "inout(int) delegate(inout(int)) inout"); static assert(__traits(fullyQualifiedName, typeof(funcPtr)) == "" ~ xx ~ " function(out double, string)"); diff --git a/compiler/test/compilable/testInference.d b/compiler/test/compilable/testInference.d index bddbaf429465..22d957fccec8 100644 --- a/compiler/test/compilable/testInference.d +++ b/compiler/test/compilable/testInference.d @@ -277,7 +277,7 @@ extern(C) void testC8504() {} void test8504() { - static assert(typeof(foo8504!()).stringof == "pure nothrow @nogc @safe void()"); + static assert(typeof(foo8504!()).stringof == "void() pure nothrow @nogc @safe"); static assert(typeof(foo8504!()).mangleof == "FNaNbNiNfZv"); static assert(demangle(foo8504!().mangleof) == "pure nothrow @nogc @safe void testInference.foo8504!().foo8504()"); @@ -350,14 +350,14 @@ struct S5933 double foo()(double a) { return a * a; } } // outside function -static assert(typeof(foo5933!()).stringof == "pure nothrow @nogc @safe int(int a)"); -static assert(typeof(S5933.init.foo!()).stringof == "pure nothrow @nogc @safe double(double a)"); +static assert(typeof(foo5933!()).stringof == "int(int a) pure nothrow @nogc @safe"); +static assert(typeof(S5933.init.foo!()).stringof == "double(double a) pure nothrow @nogc @safe"); void test5933() { // inside function - static assert(typeof(foo5933!()).stringof == "pure nothrow @nogc @safe int(int a)"); - static assert(typeof(S5933.init.foo!()).stringof == "pure nothrow @nogc @safe double(double a)"); + static assert(typeof(foo5933!()).stringof == "int(int a) pure nothrow @nogc @safe"); + static assert(typeof(S5933.init.foo!()).stringof == "double(double a) pure nothrow @nogc @safe"); } /***************************************************/ @@ -655,7 +655,7 @@ void foo10296()() void bar()() { a[1] = 2; } bar(); - static assert(typeof(bar!()).stringof == "pure nothrow @nogc @safe void()"); // nothrow @safe void() + static assert(typeof(bar!()).stringof == "void() pure nothrow @nogc @safe"); // nothrow @safe void() } pure void test10296() { diff --git a/compiler/test/compilable/testfwdref.d b/compiler/test/compilable/testfwdref.d index d5ad5fa3894e..e02bd03bc11a 100644 --- a/compiler/test/compilable/testfwdref.d +++ b/compiler/test/compilable/testfwdref.d @@ -362,8 +362,8 @@ class E14390b(T) : D14390b!int { void m() { auto c = new C14390b(); } } /* TEST_OUTPUT: --- -pure nothrow @nogc @safe void() -pure nothrow @nogc @safe void() +void() pure nothrow @nogc @safe +void() pure nothrow @nogc @safe --- */ diff --git a/compiler/test/compilable/testheader17125.d b/compiler/test/compilable/testheader17125.d index 7549f617aa0e..df3b4aa5a123 100644 --- a/compiler/test/compilable/testheader17125.d +++ b/compiler/test/compilable/testheader17125.d @@ -9,9 +9,9 @@ TEST_OUTPUT: === ${RESULTS_DIR}/compilable/testheader17125.di // D import file generated from 'compilable/extra-files/header17125.d' void func1(real value = 103500.0L); -void func2(real value = 520199.0F); -void func3(real value = 970000.0); -void func4(real value = 102450.0F); +void func2(real value = 520199.0L); +void func3(real value = 970000.0L); +void func4(real value = 102450.0L); void func5(real value = 412502.0L); --- */ diff --git a/compiler/test/compilable/testheader3.d b/compiler/test/compilable/testheader3.d index be38d7c76eec..ee363805f2ce 100644 --- a/compiler/test/compilable/testheader3.d +++ b/compiler/test/compilable/testheader3.d @@ -8,9 +8,11 @@ TEST_OUTPUT: --- === ${RESULTS_DIR}/compilable/testheader3.di // D import file generated from 'compilable/extra-files/header3.d' -auto elseifchain() +void elseifchain() pure nothrow @nogc @safe { - bool a, b, c; + bool a = false; + bool b = false; + bool c = false; if (a) { } diff --git a/compiler/test/compilable/testheaderudamodule.d b/compiler/test/compilable/testheaderudamodule.d index b6b0ed1a278e..40f655015567 100644 --- a/compiler/test/compilable/testheaderudamodule.d +++ b/compiler/test/compilable/testheaderudamodule.d @@ -14,7 +14,7 @@ struct UDA int a; } void main(); -void foo(@(1) int bar, @UDA(2) string bebe); +void foo(@(1) int bar, @(UDA(2)) string bebe); --- */ @@ -28,4 +28,4 @@ struct UDA void main() {} -void foo(@(1) int bar, @UDA(2) string bebe) {} +void foo(@(1) int bar, @(UDA(2)) string bebe) {} diff --git a/compiler/test/dshell/extra-files/dwarf/excepted_results/delegates.txt b/compiler/test/dshell/extra-files/dwarf/excepted_results/delegates.txt index b69af8fa23ba..9ba00554d9cf 100644 --- a/compiler/test/dshell/extra-files/dwarf/excepted_results/delegates.txt +++ b/compiler/test/dshell/extra-files/dwarf/excepted_results/delegates.txt @@ -4,6 +4,6 @@ DW_AT_name : dg_gc_sys DW_AT_name : void delegate() pure nothrow @system DW_AT_name : dg_lazy DW_AT_name : void delegate(lazy void f) pure nothrow @nogc @safe -DW_AT_name : pure nothrow @nogc @safe void(lazy void f) +DW_AT_name : void(lazy void f) pure nothrow @nogc @safe DW_AT_name : ptr DW_AT_name : funcptr diff --git a/compiler/test/fail_compilation/covariant_override.d b/compiler/test/fail_compilation/covariant_override.d index 7738770775d4..c16f9fdd4866 100644 --- a/compiler/test/fail_compilation/covariant_override.d +++ b/compiler/test/fail_compilation/covariant_override.d @@ -3,8 +3,8 @@ https://issues.dlang.org/show_bug.cgi?id=21538 TEST_OUTPUT: --- -fail_compilation/covariant_override.d(23): Error: function `@safe void covariant_override.CI.f(void delegate() @safe dg)` does not override any function, did you mean to override `@safe void covariant_override.I.f(void delegate() @system dg)`? -fail_compilation/covariant_override.d(34): Error: function `@safe void covariant_override.CA.f(void delegate() @safe dg)` does not override any function, did you mean to override `@safe void covariant_override.A.f(void delegate() @system dg)`? +fail_compilation/covariant_override.d(23): Error: function `void covariant_override.CI.f(void delegate() @safe dg) @safe` does not override any function, did you mean to override `void covariant_override.I.f(void delegate() @system dg) @safe`? +fail_compilation/covariant_override.d(34): Error: function `void covariant_override.CA.f(void delegate() @safe dg) @safe` does not override any function, did you mean to override `void covariant_override.A.f(void delegate() @system dg) @safe`? fail_compilation/covariant_override.d(20): Error: class `covariant_override.CI` interface function `void f(void delegate() @system dg) @safe` is not implemented --- ++/ diff --git a/compiler/test/fail_compilation/fail22202.d b/compiler/test/fail_compilation/fail22202.d index 9fb5165a711f..ddf7b0fae20d 100644 --- a/compiler/test/fail_compilation/fail22202.d +++ b/compiler/test/fail_compilation/fail22202.d @@ -4,7 +4,7 @@ TEST_OUTPUT: --- fail_compilation/fail22202.d(22): Error: function `fun` is not callable using argument types `(SystemCopy)` -fail_compilation/fail22202.d(22): `inout ref inout(SystemCopy)(ref inout(SystemCopy) other)` copy constructor cannot be called from a `pure @safe nogc` context +fail_compilation/fail22202.d(22): `ref inout(SystemCopy)(ref inout(SystemCopy) other) inout` copy constructor cannot be called from a `pure @safe nogc` context fail_compilation/fail22202.d(17): `fail22202.fun(SystemCopy __param_0)` declared here --- */ diff --git a/compiler/test/fail_compilation/fail262.d b/compiler/test/fail_compilation/fail262.d index 7c92c7c18261..7ec09c9ca157 100644 --- a/compiler/test/fail_compilation/fail262.d +++ b/compiler/test/fail_compilation/fail262.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail262.d(23): Error: function `const void fail262.B.f()` does not override any function, did you mean to override `shared const void fail262.A.f()`? +fail_compilation/fail262.d(23): Error: function `void fail262.B.f() const` does not override any function, did you mean to override `void fail262.A.f() shared const`? --- */ diff --git a/compiler/test/fail_compilation/fail8631.d b/compiler/test/fail_compilation/fail8631.d index 4f5b0763d481..6c643957f2c8 100644 --- a/compiler/test/fail_compilation/fail8631.d +++ b/compiler/test/fail_compilation/fail8631.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail8631.d(14): Error: function `shared const int fail8631.D.foo()` does not override any function, did you mean to override `immutable int fail8631.B.foo()`? +fail_compilation/fail8631.d(14): Error: function `int fail8631.D.foo() shared const` does not override any function, did you mean to override `int fail8631.B.foo() immutable`? --- */ diff --git a/compiler/test/fail_compilation/retref2.d b/compiler/test/fail_compilation/retref2.d index aaa5b41e306c..d502ee07e9f8 100644 --- a/compiler/test/fail_compilation/retref2.d +++ b/compiler/test/fail_compilation/retref2.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/retref2.d(18): Error: function `ref int retref2.D.foo(return ref int)` does not override any function, did you mean to override `ref int retref2.C.foo(ref int)`? -fail_compilation/retref2.d(19): Error: function `ref scope int retref2.D.bar() return` does not override any function, did you mean to override `ref int retref2.C.bar()`? +fail_compilation/retref2.d(19): Error: function `ref int retref2.D.bar() return scope` does not override any function, did you mean to override `ref int retref2.C.bar()`? --- */ diff --git a/compiler/test/fail_compilation/test17284.d b/compiler/test/fail_compilation/test17284.d index b7fd9796d8be..bb9a83009f9d 100644 --- a/compiler/test/fail_compilation/test17284.d +++ b/compiler/test/fail_compilation/test17284.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/test17284.d(17): Error: field `U.c` cannot access pointers in `@safe` code that overlap other fields -pure nothrow @safe void(U t) +void(U t) pure nothrow @safe --- REQUIRED_ARGS: -preview=bitfields */ diff --git a/compiler/test/fail_compilation/test20626.d b/compiler/test/fail_compilation/test20626.d index bd0bed8a85a7..a23a74347f8f 100644 --- a/compiler/test/fail_compilation/test20626.d +++ b/compiler/test/fail_compilation/test20626.d @@ -4,7 +4,7 @@ TEST_OUTPUT: ---- fail_compilation/test20626.d(2): Error: expression `__unittest_L1_C1` has no type _error_ -const void() +void() const ---- https://issues.dlang.org/show_bug.cgi?id=20626 diff --git a/compiler/test/runnable/functype.d b/compiler/test/runnable/functype.d index cdeb4182a1fa..2fba5128c42d 100644 --- a/compiler/test/runnable/functype.d +++ b/compiler/test/runnable/functype.d @@ -6,16 +6,16 @@ void testfp() { static int func1(int n = 1) { return n; } static int func2(int n ) { return n; } - static assert(typeof(func1).stringof == "pure nothrow @nogc @safe int(int n = 1)"); - static assert(typeof(func2).stringof == "pure nothrow @nogc @safe int(int n)"); + static assert(typeof(func1).stringof == "int(int n = 1) pure nothrow @nogc @safe"); + static assert(typeof(func2).stringof == "int(int n) pure nothrow @nogc @safe"); static assert( is(typeof(func1()))); // OK static assert(!is(typeof(func2()))); // NG alias typeof(func1) Func1; alias typeof(func2) Func2; static assert(is(Func1 == Func2)); - static assert(Func1.stringof == "pure nothrow @nogc @safe int(int n = 1)"); - static assert(Func2.stringof == "pure nothrow @nogc @safe int(int n)"); + static assert(Func1.stringof == "int(int n = 1) pure nothrow @nogc @safe"); + static assert(Func2.stringof == "int(int n) pure nothrow @nogc @safe"); auto fp1 = &func1; auto fp2 = &func2; @@ -54,16 +54,16 @@ void testdg() { int nest1(int n = 1) { return n; } int nest2(int n ) { return n; } - static assert(typeof(nest1).stringof == "pure nothrow @nogc @safe int(int n = 1)"); - static assert(typeof(nest2).stringof == "pure nothrow @nogc @safe int(int n)"); + static assert(typeof(nest1).stringof == "int(int n = 1) pure nothrow @nogc @safe"); + static assert(typeof(nest2).stringof == "int(int n) pure nothrow @nogc @safe"); static assert( is(typeof(nest1()))); // OK static assert(!is(typeof(nest2()))); // NG alias typeof(nest1) Nest1; alias typeof(nest2) Nest2; static assert(is(Nest1 == Nest2)); - static assert(Nest1.stringof == "pure nothrow @nogc @safe int(int n = 1)"); - static assert(Nest2.stringof == "pure nothrow @nogc @safe int(int n)"); + static assert(Nest1.stringof == "int(int n = 1) pure nothrow @nogc @safe"); + static assert(Nest2.stringof == "int(int n) pure nothrow @nogc @safe"); auto dg1 = &nest1; auto dg2 = &nest2; @@ -127,8 +127,8 @@ template StringOf(T) void testti() { int[] test(int[] a = []) { return a; } - static assert(typeof(test).stringof == "pure nothrow @nogc @safe int[](int[] a = [])"); - static assert(StringOf!(typeof(test)) == "pure nothrow @nogc @safe int[](int[])"); + static assert(typeof(test).stringof == "int[](int[] a = []) pure nothrow @nogc @safe"); + static assert(StringOf!(typeof(test)) == "int[](int[]) pure nothrow @nogc @safe"); float function(float x = 0F) fp = x => x; static assert(typeof(fp).stringof == "float function(float x = " ~ (0F).stringof ~ ")"); @@ -306,7 +306,7 @@ void test14656() //unaryFun!()(41); static void fun(int n) pure nothrow @safe @nogc {} alias F = typeof(fun); - assert(Identity!F.stringof == "pure nothrow @nogc @safe void(int)"); + assert(Identity!F.stringof == "void(int) pure nothrow @nogc @safe"); } void test14656_ref() @@ -316,7 +316,7 @@ void test14656_ref() unaryFun!()(41); static void fun(int n) pure nothrow @safe @nogc {} alias F = typeof(fun); - assert(Identity!F.stringof == "pure nothrow @nogc @safe void(int)"); + assert(Identity!F.stringof == "void(int) pure nothrow @nogc @safe"); } /***************************************************/ diff --git a/compiler/test/runnable/nulltype.d b/compiler/test/runnable/nulltype.d index 87d794005051..69c657e20bd4 100644 --- a/compiler/test/runnable/nulltype.d +++ b/compiler/test/runnable/nulltype.d @@ -1,9 +1,9 @@ /* TEST_OUTPUT: --- -pure nothrow @safe Object(bool b) -pure nothrow @safe int*(bool b) -pure nothrow @safe int[](bool b) +Object(bool b) pure nothrow @safe +int*(bool b) pure nothrow @safe +int[](bool b) pure nothrow @safe --- RUN_OUTPUT: diff --git a/compiler/test/runnable/template9.d b/compiler/test/runnable/template9.d index 7a55b2dbfee0..568555a0db52 100644 --- a/compiler/test/runnable/template9.d +++ b/compiler/test/runnable/template9.d @@ -29,14 +29,14 @@ immutable(K5886) 8 ; K5886 9 ; const(K5886) 10 ; immutable(K5886) -> U = int, N:$?:64=ulong = 3LU|32=uint = 3u$ +> U = int, N:ulong = 3LU K=string, V=int K=char, V=string -T = SA, E = int, dim = $?:64=5LU|32=5u$ +T = SA, E = int, dim = 5LU T = DA, E = int T = AA, K = string, V = int -pure nothrow @nogc @safe void(int t) -pure nothrow @nogc @safe void(int t) +void(int t) pure nothrow @nogc @safe +void(int t) pure nothrow @nogc @safe T = byte T = char ---