diff options
author | Iain Buclaw <ibuclaw@gdcproject.org> | 2024-01-18 02:39:20 +0100 |
---|---|---|
committer | Iain Buclaw <ibuclaw@gdcproject.org> | 2024-02-03 00:49:46 +0100 |
commit | f204359931866b917856fc959c70dbf55f28c14d (patch) | |
tree | ba1c671045e384fa49a6381f79abf7c1b84a55ea /gcc/d/dmd | |
parent | 5470a9b176c2b3030ff3891c7e9403db2b0685b8 (diff) | |
download | gcc-f204359931866b917856fc959c70dbf55f28c14d.zip gcc-f204359931866b917856fc959c70dbf55f28c14d.tar.gz gcc-f204359931866b917856fc959c70dbf55f28c14d.tar.bz2 |
d: Merge dmd, druntime bce5c1f7b5, phobos e4d0dd513.
D front-end changes:
- Import latest changes from dmd v2.107.0-beta.1.
- Keywords like `__FILE__' are now always evaluated at the
callsite.
D runtime changes:
- Import latest changes from druntime v2.107.0-beta.1.
- Added `nameSig' field to TypeInfo_Class in object.d.
Phobos changes:
- Import latest changes from phobos v2.107.0-beta.1.
gcc/d/ChangeLog:
* dmd/MERGE: Merge upstream dmd bce5c1f7b5.
* d-attribs.cc (build_attributes): Update for new front-end interface.
* d-lang.cc (d_parse_file): Likewise.
* decl.cc (DeclVisitor::visit (VarDeclaration *)): Likewise.
* expr.cc (build_lambda_tree): New function.
(ExprVisitor::visit (FuncExp *)): Use build_lambda_tree.
(ExprVisitor::visit (SymOffExp *)): Likewise.
(ExprVisitor::visit (VarExp *)): Likewise.
* typeinfo.cc (create_tinfo_types): Add two ulong fields to internal
TypeInfo representation.
(TypeInfoVisitor::visit (TypeInfoClassDeclaration *)): Emit stub data
for TypeInfo_Class.nameSig.
(TypeInfoVisitor::visit (TypeInfoStructDeclaration *)): Update for new
front-end interface.
libphobos/ChangeLog:
* libdruntime/MERGE: Merge upstream druntime bce5c1f7b5.
* src/MERGE: Merge upstream phobos e4d0dd513.
Diffstat (limited to 'gcc/d/dmd')
-rw-r--r-- | gcc/d/dmd/MERGE | 2 | ||||
-rw-r--r-- | gcc/d/dmd/astenums.d | 6 | ||||
-rw-r--r-- | gcc/d/dmd/constfold.d | 1 | ||||
-rw-r--r-- | gcc/d/dmd/declaration.d | 29 | ||||
-rw-r--r-- | gcc/d/dmd/dinterpret.d | 132 | ||||
-rw-r--r-- | gcc/d/dmd/dmodule.d | 18 | ||||
-rw-r--r-- | gcc/d/dmd/doc.d | 1 | ||||
-rw-r--r-- | gcc/d/dmd/dscope.d | 1 | ||||
-rw-r--r-- | gcc/d/dmd/dsymbolsem.d | 6 | ||||
-rw-r--r-- | gcc/d/dmd/dtemplate.d | 964 | ||||
-rw-r--r-- | gcc/d/dmd/dtoh.d | 11 | ||||
-rw-r--r-- | gcc/d/dmd/escape.d | 1 | ||||
-rw-r--r-- | gcc/d/dmd/expression.d | 33 | ||||
-rw-r--r-- | gcc/d/dmd/expressionsem.d | 243 | ||||
-rw-r--r-- | gcc/d/dmd/file_manager.d | 30 | ||||
-rw-r--r-- | gcc/d/dmd/func.d | 33 | ||||
-rw-r--r-- | gcc/d/dmd/globals.d | 4 | ||||
-rw-r--r-- | gcc/d/dmd/globals.h | 2 | ||||
-rw-r--r-- | gcc/d/dmd/mtype.d | 573 | ||||
-rw-r--r-- | gcc/d/dmd/mtype.h | 35 | ||||
-rw-r--r-- | gcc/d/dmd/mustuse.d | 1 | ||||
-rw-r--r-- | gcc/d/dmd/ob.d | 1 | ||||
-rw-r--r-- | gcc/d/dmd/parse.d | 61 | ||||
-rw-r--r-- | gcc/d/dmd/safe.d | 1 | ||||
-rw-r--r-- | gcc/d/dmd/scope.h | 1 | ||||
-rw-r--r-- | gcc/d/dmd/semantic3.d | 6 | ||||
-rw-r--r-- | gcc/d/dmd/sideeffect.d | 1 | ||||
-rw-r--r-- | gcc/d/dmd/statementsem.d | 5 | ||||
-rw-r--r-- | gcc/d/dmd/template.h | 2 | ||||
-rw-r--r-- | gcc/d/dmd/typesem.d | 564 |
30 files changed, 1445 insertions, 1323 deletions
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index 2b4400f..138b0b6 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -d8e3976a58d6aef7c2c9371028a2ca4460b5b2ce +bce5c1f7b521d22dcf1ea4e2bc3f76d9d28274fa The first line of this file holds the git revision number of the last merge done from the dlang/dmd repository. diff --git a/gcc/d/dmd/astenums.d b/gcc/d/dmd/astenums.d index f19edb9..77940b8 100644 --- a/gcc/d/dmd/astenums.d +++ b/gcc/d/dmd/astenums.d @@ -459,3 +459,9 @@ extern (C++) struct structalign_t bool isPack() const { return pack; } void setPack(bool pack) { this.pack = pack; } } + +/// Use to return D arrays from C++ functions +extern (C++) struct DArray(T) +{ + T[] data; +} diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d index 7bd9691..cee1f63 100644 --- a/gcc/d/dmd/constfold.d +++ b/gcc/d/dmd/constfold.d @@ -1038,6 +1038,7 @@ UnionExp Cast(const ref Loc loc, Type type, Type to, Expression e1) else if (tb.ty == Tstruct && e1.op == EXP.int64) { // Struct = 0; + import dmd.typesem : toDsymbol; StructDeclaration sd = tb.toDsymbol(null).isStructDeclaration(); assert(sd); auto elements = new Expressions(); diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d index 5869a22..93ef63f 100644 --- a/gcc/d/dmd/declaration.d +++ b/gcc/d/dmd/declaration.d @@ -1749,6 +1749,35 @@ extern (C++) final class SymbolDeclaration : Declaration /*********************************************************** */ +private Identifier getTypeInfoIdent(Type t) +{ + import dmd.dmangle; + import core.stdc.stdlib; + import dmd.root.rmem; + // _init_10TypeInfo_%s + OutBuffer buf; + buf.reserve(32); + mangleToBuffer(t, buf); + + const slice = buf[]; + + // Allocate buffer on stack, fail over to using malloc() + char[128] namebuf; + const namelen = 19 + size_t.sizeof * 3 + slice.length + 1; + auto name = namelen <= namebuf.length ? namebuf.ptr : cast(char*)Mem.check(malloc(namelen)); + + const length = snprintf(name, namelen, "_D%lluTypeInfo_%.*s6__initZ", + cast(ulong)(9 + slice.length), cast(int)slice.length, slice.ptr); + //printf("%p %s, deco = %s, name = %s\n", this, toChars(), deco, name); + assert(0 < length && length < namelen); // don't overflow the buffer + + auto id = Identifier.idPool(name[0 .. length]); + + if (name != namebuf.ptr) + free(name); + return id; +} + extern (C++) class TypeInfoDeclaration : VarDeclaration { Type tinfo; diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d index eda91d1..a3b38d9 100644 --- a/gcc/d/dmd/dinterpret.d +++ b/gcc/d/dmd/dinterpret.d @@ -1416,6 +1416,7 @@ Expression interpretStatement(UnionExp* pue, Statement s, InterState* istate) foreach (ca; *s.catches) { Type catype = ca.type; + import dmd.typesem : isBaseOf; if (!catype.equals(extype) && !catype.isBaseOf(extype, null)) continue; @@ -6237,6 +6238,11 @@ public: { if (soe.offset == 0 && soe.var.isFuncDeclaration()) return; + if (soe.offset == 0 && soe.var.isVarDeclaration() && soe.var.isImmutable()) + { + result = getVarExp(e.loc, istate, soe.var, CTFEGoal.RValue); + return; + } error(e.loc, "cannot dereference pointer to static variable `%s` at compile time", soe.var.toChars()); result = CTFEExp.cantexp; return; @@ -6359,6 +6365,7 @@ public: { if (auto t = isType(ex.isTypeidExp().obj)) { + import dmd.typesem : toDsymbol; auto sym = t.toDsymbol(null); if (auto ident = (sym ? sym.ident : null)) { @@ -6643,6 +6650,7 @@ Expressions* copyArrayOnWrite(Expressions* exps, Expressions* original) private bool stopPointersEscaping(const ref Loc loc, Expression e) { + import dmd.typesem : hasPointers; if (!e.type.hasPointers()) return true; if (isPointer(e.type)) @@ -6706,7 +6714,7 @@ Statement findGotoTarget(InterState* istate, Identifier ident) Statement target = null; if (ident) { - LabelDsymbol label = istate.fd.searchLabel(ident); + LabelDsymbol label = istate.fd.searchLabel(ident, Loc.initial); assert(label && label.statement); LabelStatement ls = label.statement; target = ls.gotoTarget ? ls.gotoTarget : ls.statement; @@ -7263,6 +7271,33 @@ private Expression interpret_aaApply(UnionExp* pue, InterState* istate, Expressi return eresult; } +/// Returns: equivalent `StringExp` from `ArrayLiteralExp ale` containing only `IntegerExp` elements +StringExp arrayLiteralToString(ArrayLiteralExp ale) +{ + const len = ale.elements ? ale.elements.length : 0; + const size = ale.type.nextOf().size(); + + StringExp impl(T)() + { + T[] result = new T[len]; + foreach (i; 0 .. len) + result[i] = cast(T) (*ale.elements)[i].isIntegerExp().getInteger(); + return new StringExp(ale.loc, result[], len, cast(ubyte) size); + } + + switch (size) + { + case 1: + return impl!char(); + case 2: + return impl!wchar(); + case 4: + return impl!dchar(); + default: + assert(0); + } +} + /* Decoding UTF strings for foreach loops. Duplicates the functionality of * the twelve _aApplyXXn functions in aApply.d in the runtime. */ @@ -7299,8 +7334,10 @@ private Expression foreachApplyUtf(UnionExp* pue, InterState* istate, Expression str = resolveSlice(str, &strTmp); auto se = str.isStringExp(); - auto ale = str.isArrayLiteralExp(); - if (!se && !ale) + if (auto ale = str.isArrayLiteralExp()) + se = arrayLiteralToString(ale); + + if (!se) { error(str.loc, "CTFE internal error: cannot foreach `%s`", str.toChars()); return CTFEExp.cantexp; @@ -7309,7 +7346,7 @@ private Expression foreachApplyUtf(UnionExp* pue, InterState* istate, Expression Expression eresult = null; // ded-store to prevent spurious warning - // Buffers for encoding; also used for decoding array literals + // Buffers for encoding char[4] utf8buf = void; wchar[2] utf16buf = void; @@ -7323,90 +7360,11 @@ private Expression foreachApplyUtf(UnionExp* pue, InterState* istate, Expression dchar rawvalue; // Holds the decoded dchar size_t currentIndex = indx; // The index of the decoded character - if (ale) - { - // If it is an array literal, copy the code points into the buffer - size_t buflen = 1; // #code points in the buffer - size_t n = 1; // #code points in this char - size_t sz = cast(size_t)ale.type.nextOf().size(); + // String literals + size_t saveindx; // used for reverse iteration - switch (sz) - { - case 1: - if (rvs) - { - // find the start of the string - --indx; - buflen = 1; - while (indx > 0 && buflen < 4) - { - Expression r = (*ale.elements)[indx]; - char x = cast(char)r.isIntegerExp().getInteger(); - if ((x & 0xC0) != 0x80) - break; - --indx; - ++buflen; - } - } - else - buflen = (indx + 4 > len) ? len - indx : 4; - for (size_t i = 0; i < buflen; ++i) - { - Expression r = (*ale.elements)[indx + i]; - utf8buf[i] = cast(char)r.isIntegerExp().getInteger(); - } - n = 0; - errmsg = utf_decodeChar(utf8buf[0 .. buflen], n, rawvalue); - break; - - case 2: - if (rvs) - { - // find the start of the string - --indx; - buflen = 1; - Expression r = (*ale.elements)[indx]; - ushort x = cast(ushort)r.isIntegerExp().getInteger(); - if (indx > 0 && x >= 0xDC00 && x <= 0xDFFF) - { - --indx; - ++buflen; - } - } - else - buflen = (indx + 2 > len) ? len - indx : 2; - for (size_t i = 0; i < buflen; ++i) - { - Expression r = (*ale.elements)[indx + i]; - utf16buf[i] = cast(ushort)r.isIntegerExp().getInteger(); - } - n = 0; - errmsg = utf_decodeWchar(utf16buf[0 .. buflen], n, rawvalue); - break; - - case 4: - { - if (rvs) - --indx; - Expression r = (*ale.elements)[indx]; - rawvalue = cast(dchar)r.isIntegerExp().getInteger(); - n = 1; - } - break; - - default: - assert(0); - } - if (!rvs) - indx += n; - } - else + switch (se.sz) { - // String literals - size_t saveindx; // used for reverse iteration - - switch (se.sz) - { case 1: { if (rvs) @@ -7450,8 +7408,8 @@ private Expression foreachApplyUtf(UnionExp* pue, InterState* istate, Expression default: assert(0); - } } + if (errmsg) { error(deleg.loc, "`%.*s`", cast(int)errmsg.length, errmsg.ptr); diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d index 022231c..59d4065 100644 --- a/gcc/d/dmd/dmodule.d +++ b/gcc/d/dmd/dmodule.d @@ -679,23 +679,23 @@ extern (C++) final class Module : Package /* Preprocess the file if it's a .c file */ FileName filename = srcfile; - bool ifile = false; // did we generate a .i file - scope (exit) - { - if (ifile) - File.remove(filename.toChars()); // remove generated file - } + const(ubyte)[] srctext; if (global.preprocess && FileName.equalsExt(srcfile.toString(), c_ext) && FileName.exists(srcfile.toString())) { - filename = global.preprocess(srcfile, loc, ifile, &defines); // run C preprocessor + /* Apply C preprocessor to the .c file, returning the contents + * after preprocessing + */ + srctext = global.preprocess(srcfile, loc, defines).data; } + else + srctext = global.fileManager.getFileContents(filename); + this.src = srctext; - if (auto result = global.fileManager.lookup(filename)) + if (srctext) { - this.src = result; if (global.params.makeDeps.doOutput) global.params.makeDeps.files.push(srcfile.toChars()); return true; diff --git a/gcc/d/dmd/doc.d b/gcc/d/dmd/doc.d index 810642f..ec3cc91 100644 --- a/gcc/d/dmd/doc.d +++ b/gcc/d/dmd/doc.d @@ -1355,6 +1355,7 @@ void toDocBuffer(Dsymbol s, ref OutBuffer buf, Scope* sc) { if (type.ty == Tclass || type.ty == Tstruct || type.ty == Tenum) { + import dmd.typesem : toDsymbol; if (Dsymbol s = type.toDsymbol(null)) // elaborate type prettyPrintDsymbol(s, ad.parent); else diff --git a/gcc/d/dmd/dscope.d b/gcc/d/dmd/dscope.d index 7e9499f..e02ba9a 100644 --- a/gcc/d/dmd/dscope.d +++ b/gcc/d/dmd/dscope.d @@ -97,6 +97,7 @@ extern (C++) struct Scope Dsymbol inunion; /// != null if processing members of a union bool nofree; /// true if shouldn't free it bool inLoop; /// true if inside a loop (where constructor calls aren't allowed) + bool inDefaultArg; /// true if inside a default argument (where __FILE__, etc are evaluated at the call site) int intypeof; /// in typeof(exp) VarDeclaration lastVar; /// Previous symbol used to prevent goto-skips-init ErrorSink eSink; /// sink for error messages diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index 23f0bc5..e9cdb94 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -6553,7 +6553,8 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList TemplateDeclaration tempdecl = tempinst.tempdecl.isTemplateDeclaration(); assert(tempdecl); - TemplateStats.incInstance(tempdecl, tempinst); + if (global.params.v.templates) + TemplateStats.incInstance(tempdecl, tempinst, global.params.v.templatesListInstances); tempdecl.checkDeprecated(tempinst.loc, sc); @@ -6746,7 +6747,8 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList tempinst.parent = tempinst.enclosing ? tempinst.enclosing : tempdecl.parent; //printf("parent = '%s'\n", parent.kind()); - TemplateStats.incUnique(tempdecl, tempinst); + if (global.params.v.templates) + TemplateStats.incUnique(tempdecl, tempinst); TemplateInstance tempdecl_instance_idx = tempdecl.addInstance(tempinst); diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index 1d84ccd..13cc32f 100644 --- a/gcc/d/dmd/dtemplate.d +++ b/gcc/d/dmd/dtemplate.d @@ -56,6 +56,7 @@ import dmd.dscope; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.errors; +import dmd.errorsink; import dmd.expression; import dmd.expressionsem; import dmd.func; @@ -150,7 +151,7 @@ extern (C++) bool isError(const RootObject o) if (const e = isExpression(o)) return (e.op == EXP.error || !e.type || e.type.ty == Terror); if (const v = isTuple(o)) - return arrayObjectIsError(&v.objects); + return arrayObjectIsError(v.objects); const s = isDsymbol(o); assert(s); if (s.errors) @@ -161,9 +162,9 @@ extern (C++) bool isError(const RootObject o) /************************************** * Are any of the Objects an error? */ -bool arrayObjectIsError(const Objects* args) +bool arrayObjectIsError(const ref Objects args) { - foreach (const o; *args) + foreach (const o; args) { if (isError(o)) return true; @@ -187,6 +188,13 @@ inout(Type) getType(inout RootObject o) } +/*********************************** + * If oarg represents a Dsymbol, return that Dsymbol + * Params: + * oarg = argument to check + * Returns: + * Dsymbol if a symbol, null if not + */ Dsymbol getDsymbol(RootObject oarg) { //printf("getDsymbol()\n"); @@ -256,8 +264,11 @@ private Expression getExpression(RootObject o) } /****************************** - * If o1 matches o2, return true. - * Else, return false. + * See if two objects match + * Params: + * o1 = first object + * o2 = second object + * Returns: true if they match */ private bool match(RootObject o1, RootObject o2) { @@ -343,7 +354,7 @@ private bool match(RootObject o1, RootObject o2) printf("\tu1 = %s\n", u1.toChars()); printf("\tu2 = %s\n", u2.toChars()); } - if (!arrayObjectMatch(&u1.objects, &u2.objects)) + if (!arrayObjectMatch(u1.objects, u2.objects)) goto Lnomatch; goto Lmatch; @@ -362,15 +373,15 @@ Lnomatch: /************************************ * Match an array of them. */ -private bool arrayObjectMatch(Objects* oa1, Objects* oa2) +private bool arrayObjectMatch(ref Objects oa1, ref Objects oa2) { - if (oa1 == oa2) + if (&oa1 == &oa2) return true; if (oa1.length != oa2.length) return false; immutable oa1dim = oa1.length; - auto oa1d = (*oa1)[].ptr; - auto oa2d = (*oa2)[].ptr; + auto oa1d = oa1[].ptr; + auto oa2d = oa2[].ptr; foreach (j; 0 .. oa1dim) { RootObject o1 = oa1d[j]; @@ -386,12 +397,12 @@ private bool arrayObjectMatch(Objects* oa1, Objects* oa2) /************************************ * Return hash of Objects. */ -private size_t arrayObjectHash(Objects* oa1) +private size_t arrayObjectHash(ref Objects oa1) { import dmd.root.hash : mixHash; size_t hash = 0; - foreach (o1; *oa1) + foreach (o1; oa1) { /* Must follow the logic of match() */ @@ -407,7 +418,7 @@ private size_t arrayObjectHash(Objects* oa1) hash = mixHash(hash, mixHash(cast(size_t)cast(void*)s1.getIdent(), cast(size_t)cast(void*)s1.parent)); } else if (auto u1 = isTuple(o1)) - hash = mixHash(hash, arrayObjectHash(&u1.objects)); + hash = mixHash(hash, arrayObjectHash(u1.objects)); } return hash; } @@ -672,7 +683,9 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol /********************************** * Overload existing TemplateDeclaration 'this' with the new one 's'. - * Return true if successful; i.e. no conflict. + * Params: + * s = symbol to be inserted + * Return: true if successful; i.e. no conflict. */ override bool overloadInsert(Dsymbol s) { @@ -741,6 +754,8 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol return toCharsMaybeConstraints(false); } + // Note: this function is not actually `const`, because iterating the + // function parameter list may run dsymbolsemantic on enum types const(char)* toCharsMaybeConstraints(bool includeConstraints) const { OutBuffer buf; @@ -758,15 +773,17 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol if (onemember) { - const FuncDeclaration fd = onemember.isFuncDeclaration(); - if (fd && fd.type) + if (const fd = onemember.isFuncDeclaration()) { - TypeFunction tf = cast(TypeFunction)fd.type; - buf.writestring(parametersTypeToChars(tf.parameterList)); - if (tf.mod) + if (TypeFunction tf = cast(TypeFunction)fd.type.isTypeFunction()) { - buf.writeByte(' '); - buf.MODtoBuffer(tf.mod); + // !! Casted away const + buf.writestring(parametersTypeToChars(tf.parameterList)); + if (tf.mod) + { + buf.writeByte(' '); + buf.MODtoBuffer(tf.mod); + } } } } @@ -790,7 +807,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol /**************************** * Check to see if constraint is satisfied. */ - extern (D) bool evaluateConstraint(TemplateInstance ti, Scope* sc, Scope* paramscope, Objects* dedargs, FuncDeclaration fd) + private bool evaluateConstraint(TemplateInstance ti, Scope* sc, Scope* paramscope, Objects* dedargs, FuncDeclaration fd) { /* Detect recursive attempts to instantiate this template declaration, * https://issues.dlang.org/show_bug.cgi?id=4072 @@ -807,7 +824,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol for (TemplatePrevious* p = previous; p; p = p.prev) { - if (!arrayObjectMatch(p.dedargs, dedargs)) + if (!arrayObjectMatch(*p.dedargs, *dedargs)) continue; //printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars()); /* It must be a subscope of p.sc, other scope chains are not recursive @@ -1055,7 +1072,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol * dedtypes deduced arguments * Return match level. */ - extern (D) MATCH matchWithInstance(Scope* sc, TemplateInstance ti, Objects* dedtypes, ArgumentList argumentList, int flag) + private MATCH matchWithInstance(Scope* sc, TemplateInstance ti, ref Objects dedtypes, ArgumentList argumentList, int flag) { enum LOGM = 0; static if (LOGM) @@ -1151,7 +1168,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol /* Any parameter left without a type gets the type of * its corresponding arg */ - foreach (i, ref dedtype; *dedtypes) + foreach (i, ref dedtype; dedtypes) { if (!dedtype) { @@ -1202,7 +1219,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol } // TODO: dedtypes => ti.tiargs ? - if (!evaluateConstraint(ti, sc, paramscope, dedtypes, fd)) + if (!evaluateConstraint(ti, sc, paramscope, &dedtypes, fd)) return nomatch(); } @@ -1283,7 +1300,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol Objects dedtypes = Objects(td2.parameters.length); // Attempt a type deduction - MATCH m = td2.matchWithInstance(sc, ti, &dedtypes, argumentList, 1); + MATCH m = td2.matchWithInstance(sc, ti, dedtypes, argumentList, 1); if (m > MATCH.nomatch) { /* A non-variadic template is more specialized than a @@ -1425,7 +1442,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol { assert(i < parameters.length); Declaration sparam = null; - MATCH m = (*parameters)[i].matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, &sparam); + MATCH m = (*parameters)[i].matchArg(instLoc, paramscope, dedargs, i, parameters, *dedtypes, &sparam); //printf("\tdeduceType m = %d\n", m); if (m == MATCH.nomatch) return nomatch(); @@ -1458,10 +1475,9 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol ParameterList fparameters = fd.getParameterList(); // function parameter list const nfparams = fparameters.length; // number of function parameters - const nfargs = argumentList.length; // number of function arguments if (argumentList.hasNames) return matcherror(); // TODO: resolve named args - Expressions* fargs = argumentList.arguments; // TODO: resolve named args + Expression[] fargs = argumentList.arguments ? (*argumentList.arguments)[] : null; /* Check for match of function arguments with variadic template * parameter, such as: @@ -1475,7 +1491,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol // TemplateTupleParameter always makes most lesser matching. matchTiargs = MATCH.convert; - if (nfparams == 0 && nfargs != 0) // if no function parameters + if (nfparams == 0 && argumentList.length != 0) // if no function parameters { if (!declaredTuple) { @@ -1498,7 +1514,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol auto fparam = (*fparameters.parameters)[fptupindex]; // fparameters[fptupindex] ? if (fparam.type.ty != Tident) continue; - TypeIdentifier tid = cast(TypeIdentifier)fparam.type; + TypeIdentifier tid = fparam.type.isTypeIdentifier(); if (!tp.ident.equals(tid.ident) || tid.idents.length) continue; @@ -1527,7 +1543,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol hasttp = true; Type t = new TypeIdentifier(Loc.initial, ttp.ident); - MATCH m = deduceType(tthis, paramscope, t, parameters, dedtypes); + MATCH m = deduceType(tthis, paramscope, t, *parameters, *dedtypes); if (m == MATCH.nomatch) return nomatch(); if (m < match) @@ -1576,7 +1592,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol //printf("%s\n\tnfargs = %d, nfparams = %d, tuple_dim = %d\n", toChars(), nfargs, nfparams, declaredTuple ? declaredTuple.objects.length : 0); //printf("\ttp = %p, fptupindex = %d, found = %d, declaredTuple = %s\n", tp, fptupindex, fptupindex != IDX_NOTFOUND, declaredTuple ? declaredTuple.toChars() : NULL); size_t argi = 0; - size_t nfargs2 = nfargs; // nfargs + supplied defaultArgs + size_t nfargs2 = fargs.length; // nfargs + supplied defaultArgs uint inoutMatch = 0; // for debugging only for (size_t parami = 0; parami < nfparams; parami++) { @@ -1592,8 +1608,8 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol */ if (fptupindex != IDX_NOTFOUND && parami == fptupindex) { - assert(prmtype.ty == Tident); - TypeIdentifier tid = cast(TypeIdentifier)prmtype; + TypeIdentifier tid = prmtype.isTypeIdentifier(); + assert(tid); if (!declaredTuple) { /* The types of the function arguments @@ -1606,7 +1622,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol * void foo(U, T...)(int y, T, U, double, int bar = 0) {} // rem == 2 (U, double) */ size_t rem = 0; - for (size_t j = parami + 1; j < nfparams; j++) + foreach (j; parami + 1 .. nfparams) { Parameter p = fparameters[j]; if (p.defaultArg) @@ -1616,7 +1632,10 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol if (!reliesOnTemplateParameters(p.type, (*parameters)[inferStart .. parameters.length])) { Type pt = p.type.syntaxCopy().typeSemantic(fd.loc, paramscope); - rem += pt.ty == Ttuple ? (cast(TypeTuple)pt).arguments.length : 1; + if (auto ptt = pt.isTypeTuple()) + rem += ptt.arguments.length; + else + rem += 1; } else { @@ -1627,9 +1646,9 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol if (nfargs2 - argi < rem) return nomatch(); declaredTuple.objects.setDim(nfargs2 - argi - rem); - for (size_t i = 0; i < declaredTuple.objects.length; i++) + foreach (i; 0 .. declaredTuple.objects.length) { - farg = (*fargs)[argi + i]; + farg = fargs[argi + i]; // Check invalid arguments to detect errors early. if (farg.op == EXP.error || farg.type.ty == Terror) @@ -1647,7 +1666,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol } else { - m = deduceTypeHelper(farg.type, &tt, tid); + m = deduceTypeHelper(farg.type, tt, tid); } if (m == MATCH.nomatch) return nomatch(); @@ -1687,20 +1706,19 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol // should copy prmtype to avoid affecting semantic result prmtype = prmtype.syntaxCopy().typeSemantic(fd.loc, paramscope); - if (prmtype.ty == Ttuple) + if (TypeTuple tt = prmtype.isTypeTuple()) { - TypeTuple tt = cast(TypeTuple)prmtype; - size_t tt_dim = tt.arguments.length; + const tt_dim = tt.arguments.length; for (size_t j = 0; j < tt_dim; j++, ++argi) { Parameter p = (*tt.arguments)[j]; if (j == tt_dim - 1 && fparameters.varargs == VarArg.typesafe && - parami + 1 == nfparams && argi < nfargs) + parami + 1 == nfparams && argi < fargs.length) { prmtype = p.type; goto Lvarargs; } - if (argi >= nfargs) + if (argi >= fargs.length) { if (p.defaultArg) continue; @@ -1711,7 +1729,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol return nomatch(); } - farg = (*fargs)[argi]; + farg = fargs[argi]; if (!farg.implicitConvTo(p.type)) return nomatch(); } @@ -1719,7 +1737,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol } } - if (argi >= nfargs) // if not enough arguments + if (argi >= fargs.length) // if not enough arguments { if (!fparam.defaultArg) goto Lvarargs; @@ -1741,7 +1759,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol * // at fparam `N start = 0`, N should be 'size_t' before * // the deduction result from fparam.defaultArg. */ - if (argi == nfargs) + if (argi == fargs.length) { foreach (ref dedtype; *dedtypes) { @@ -1769,7 +1787,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol * the oded == oarg */ (*dedargs)[i] = oded; - MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null); + MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, *dedtypes, null); //printf("m2 = %d\n", m2); if (m2 == MATCH.nomatch) return nomatch(); @@ -1822,7 +1840,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol } else { - farg = (*fargs)[argi]; + farg = fargs[argi]; } { // Check invalid arguments to detect errors early. @@ -1851,8 +1869,15 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol { /* Allow expressions that have CT-known boundaries and type [] to match with [dim] */ - Type taai; - if (argtype.ty == Tarray && (prmtype.ty == Tsarray || prmtype.ty == Taarray && (taai = (cast(TypeAArray)prmtype).index).ty == Tident && (cast(TypeIdentifier)taai).idents.length == 0)) + bool inferIndexType = (argtype.ty == Tarray) && (prmtype.ty == Tsarray || prmtype.ty == Taarray); + if (auto aaType = prmtype.isTypeAArray()) + { + if (auto indexType = aaType.index.isTypeIdentifier()) + { + inferIndexType = indexType.idents.length == 0; + } + } + if (inferIndexType) { if (StringExp se = farg.isStringExp()) { @@ -1871,7 +1896,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol oarg = argtype; } - else if ((fparam.storageClass & STC.out_) == 0 && (argtype.ty == Tarray || argtype.ty == Tpointer) && templateParameterLookup(prmtype, parameters) != IDX_NOTFOUND && (cast(TypeIdentifier)prmtype).idents.length == 0) + else if ((fparam.storageClass & STC.out_) == 0 && (argtype.ty == Tarray || argtype.ty == Tpointer) && templateParameterLookup(prmtype, parameters) != IDX_NOTFOUND && prmtype.isTypeIdentifier().idents.length == 0) { /* The farg passing to the prmtype always make a copy. Therefore, * we can shrink the set of the deduced type arguments for prmtype @@ -1892,11 +1917,11 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol } } - if (fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams && argi + 1 < nfargs) + if (fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams && argi + 1 < fargs.length) goto Lvarargs; uint im = 0; - MATCH m = deduceType(oarg, paramscope, prmtype, parameters, dedtypes, &im, inferStart); + MATCH m = deduceType(oarg, paramscope, prmtype, *parameters, *dedtypes, &im, inferStart); //printf("\tL%d deduceType m = %d, im = x%x, inoutMatch = x%x\n", __LINE__, m, im, inoutMatch); inoutMatch |= im; @@ -1984,17 +2009,15 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol case Taarray: { // Perhaps we can do better with this, see TypeFunction.callMatch() - if (tb.ty == Tsarray) + if (TypeSArray tsa = tb.isTypeSArray()) { - TypeSArray tsa = cast(TypeSArray)tb; dinteger_t sz = tsa.dim.toInteger(); - if (sz != nfargs - argi) + if (sz != fargs.length - argi) return nomatch(); } - else if (tb.ty == Taarray) + else if (TypeAArray taa = tb.isTypeAArray()) { - TypeAArray taa = cast(TypeAArray)tb; - Expression dim = new IntegerExp(instLoc, nfargs - argi, Type.tsize_t); + Expression dim = new IntegerExp(instLoc, fargs.length - argi, Type.tsize_t); size_t i = templateParameterLookup(taa.index, parameters); if (i == IDX_NOTFOUND) @@ -2057,9 +2080,9 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol { TypeArray ta = cast(TypeArray)tb; Type tret = fparam.isLazyArray(); - for (; argi < nfargs; argi++) + for (; argi < fargs.length; argi++) { - Expression arg = (*fargs)[argi]; + Expression arg = fargs[argi]; assert(arg); MATCH m; @@ -2085,7 +2108,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol else { uint wm = 0; - m = deduceType(arg, paramscope, ta.next, parameters, dedtypes, &wm, inferStart); + m = deduceType(arg, paramscope, ta.next, *parameters, *dedtypes, &wm, inferStart); inoutMatch |= wm; } if (m == MATCH.nomatch) @@ -2112,8 +2135,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol Lmatch: foreach (ref dedtype; *dedtypes) { - Type at = isType(dedtype); - if (at) + if (Type at = isType(dedtype)) { if (at.ty == Tnone) { @@ -2147,7 +2169,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol * the oded == oarg */ (*dedargs)[i] = oded; - MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null); + MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, *dedtypes, null); //printf("m2 = %d\n", m2); if (m2 == MATCH.nomatch) return nomatch(); @@ -2194,7 +2216,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol if (tparam.specialization()) { (*dedargs)[i] = oded; - MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null); + MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, *dedtypes, null); //printf("m2 = %d\n", m2); if (m2 == MATCH.nomatch) return nomatch(); @@ -2233,7 +2255,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol sc2.minst = sc.minst; sc2.stc |= fd.storage_class & STC.deprecated_; - fd = doHeaderInstantiation(ti, sc2, fd, tthis, fargs); + fd = doHeaderInstantiation(ti, sc2, fd, tthis, argumentList.arguments); sc2 = sc2.pop(); sc2 = sc2.pop(); @@ -2396,7 +2418,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol } if (hasttp) { - tf = cast(TypeFunction)tf.addSTC(ModToStc(tthis.mod)); + tf = tf.addSTC(ModToStc(tthis.mod)).isTypeFunction(); assert(!tf.deco); } } @@ -2602,10 +2624,10 @@ extern (C++) final class TypeDeduced : Type * tiargs = initial list of template arguments * tthis = if !NULL, the 'this' pointer argument * argumentList= arguments to function - * pMessage = address to store error message, or null + * errorHelper = delegate to send error message to if not null */ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, Objects* tiargs, - Type tthis, ArgumentList argumentList, const(char)** pMessage = null) + Type tthis, ArgumentList argumentList, void delegate(const(char)*) scope errorHelper = null) { version (none) { @@ -2662,7 +2684,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, return 1; } //printf("fd = %s %s, fargs = %s\n", fd.toChars(), fd.type.toChars(), fargs.toChars()); - auto tf = cast(TypeFunction)fd.type; + auto tf = fd.type.isTypeFunction(); int prop = tf.isproperty ? 1 : 2; if (property == 0) @@ -2711,8 +2733,12 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, else if (shared_this && !shared_dtor && tthis_fd !is null) tf.mod = tthis_fd.mod; } - MATCH mfa = tf.callMatch(tthis_fd, argumentList, 0, pMessage, sc); + const(char)* failMessage; + const(char)** pMessage = errorHelper ? &failMessage : null; + MATCH mfa = tf.callMatch(tthis_fd, argumentList, 0, errorHelper, sc); //printf("test1: mfa = %d\n", mfa); + if (failMessage) + errorHelper(failMessage); if (mfa == MATCH.nomatch) return 0; @@ -2850,7 +2876,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, auto ti = new TemplateInstance(loc, td, tiargs); Objects dedtypes = Objects(td.parameters.length); assert(td.semanticRun != PASS.initial); - MATCH mta = td.matchWithInstance(sc, ti, &dedtypes, argumentList, 0); + MATCH mta = td.matchWithInstance(sc, ti, dedtypes, argumentList, 0); //printf("matchWithInstance = %d\n", mta); if (mta == MATCH.nomatch || mta < ta_last) // no match or less match return 0; @@ -2869,7 +2895,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, // Check for recursive instantiation of tdx. for (TemplatePrevious* p = tdx.previous; p; p = p.prev) { - if (arrayObjectMatch(p.dedargs, &dedtypesX)) + if (arrayObjectMatch(*p.dedargs, dedtypesX)) { //printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars()); /* It must be a subscope of p.sc, other scope chains are not recursive @@ -2918,7 +2944,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, Type tthis_fd = fd.needThis() && !fd.isCtorDeclaration() ? tthis : null; - auto tf = cast(TypeFunction)fd.type; + auto tf = fd.type.isTypeFunction(); MATCH mfa = tf.callMatch(tthis_fd, argumentList, 0, null, sc); if (mfa < m.last) return 0; @@ -2979,7 +3005,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, if (isCtorCall) { // Constructor call requires additional check. - auto tf = cast(TypeFunction)fd.type; + auto tf = fd.type.isTypeFunction(); assert(tf.next); if (MODimplicitConv(tf.mod, tthis_fd.mod) || tf.isWild() && tf.isShared() == tthis_fd.isShared() || @@ -3175,9 +3201,8 @@ private size_t templateIdentifierLookup(Identifier id, TemplateParameters* param private size_t templateParameterLookup(Type tparam, TemplateParameters* parameters) { - if (tparam.ty == Tident) + if (TypeIdentifier tident = tparam.isTypeIdentifier()) { - TypeIdentifier tident = cast(TypeIdentifier)tparam; //printf("\ttident = '%s'\n", tident.toChars()); return templateIdentifierLookup(tident.ident, parameters); } @@ -3267,7 +3292,7 @@ private Type rawTypeMerge(Type t1, Type t2) return null; } -private MATCH deduceTypeHelper(Type t, Type* at, Type tparam) +private MATCH deduceTypeHelper(Type t, out Type at, Type tparam) { // 9*9 == 81 cases @@ -3297,7 +3322,7 @@ private MATCH deduceTypeHelper(Type t, Type* at, Type tparam) // foo(U) shared(inout(const(T))) => shared(inout(const(T))) // foo(U) immutable(T) => immutable(T) { - *at = t; + at = t; return MATCH.exact; } case X(MODFlags.const_, MODFlags.const_): @@ -3317,7 +3342,7 @@ private MATCH deduceTypeHelper(Type t, Type* at, Type tparam) // foo(shared(inout(const(U)))) shared(inout(const(T))) => T // foo(immutable(U)) immutable(T) => T { - *at = t.mutableOf().unSharedOf(); + at = t.mutableOf().unSharedOf(); return MATCH.exact; } case X(MODFlags.const_, MODFlags.shared_ | MODFlags.const_): @@ -3327,7 +3352,7 @@ private MATCH deduceTypeHelper(Type t, Type* at, Type tparam) // foo(inout(U)) shared(inout(T)) => shared(T) // foo(inout(const(U))) shared(inout(const(T))) => shared(T) { - *at = t.mutableOf(); + at = t.mutableOf(); return MATCH.exact; } case X(MODFlags.const_, 0): @@ -3345,13 +3370,13 @@ private MATCH deduceTypeHelper(Type t, Type* at, Type tparam) // foo(const(U)) immutable(T) => T // foo(shared(const(U))) immutable(T) => T { - *at = t.mutableOf(); + at = t.mutableOf(); return MATCH.constant; } case X(MODFlags.const_, MODFlags.shared_): // foo(const(U)) shared(T) => shared(T) { - *at = t; + at = t; return MATCH.constant; } case X(MODFlags.shared_, MODFlags.shared_ | MODFlags.const_): @@ -3361,13 +3386,13 @@ private MATCH deduceTypeHelper(Type t, Type* at, Type tparam) // foo(shared(U)) shared(inout(T)) => inout(T) // foo(shared(U)) shared(inout(const(T))) => inout(const(T)) { - *at = t.unSharedOf(); + at = t.unSharedOf(); return MATCH.exact; } case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_): // foo(shared(const(U))) shared(T) => T { - *at = t.unSharedOf(); + at = t.unSharedOf(); return MATCH.constant; } case X(MODFlags.wildconst, MODFlags.immutable_): @@ -3379,13 +3404,13 @@ private MATCH deduceTypeHelper(Type t, Type* at, Type tparam) // foo(shared(inout(const(U)))) immutable(T) => T // foo(shared(inout(const(U)))) shared(inout(T)) => T { - *at = t.unSharedOf().mutableOf(); + at = t.unSharedOf().mutableOf(); return MATCH.constant; } case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_ | MODFlags.wild): // foo(shared(const(U))) shared(inout(T)) => T { - *at = t.unSharedOf().mutableOf(); + at = t.unSharedOf().mutableOf(); return MATCH.constant; } case X(MODFlags.wild, 0): @@ -3499,30 +3524,16 @@ __gshared Expression emptyArrayElement = null; * Output: * dedtypes = [ int ] // Array of Expression/Type's */ -MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, uint* wm = null, size_t inferStart = 0, bool ignoreAliasThis = false) +MATCH deduceType(RootObject o, Scope* sc, Type tparam, ref TemplateParameters parameters, ref Objects dedtypes, uint* wm = null, size_t inferStart = 0, bool ignoreAliasThis = false) { extern (C++) final class DeduceType : Visitor { alias visit = Visitor.visit; public: - Scope* sc; - Type tparam; - TemplateParameters* parameters; - Objects* dedtypes; - uint* wm; - size_t inferStart; - bool ignoreAliasThis; MATCH result; - extern (D) this(Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, uint* wm, size_t inferStart, bool ignoreAliasThis) @safe + extern (D) this() @safe { - this.sc = sc; - this.tparam = tparam; - this.parameters = parameters; - this.dedtypes = dedtypes; - this.wm = wm; - this.inferStart = inferStart; - this.ignoreAliasThis = ignoreAliasThis; result = MATCH.nomatch; } @@ -3537,7 +3548,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param if (tparam.ty == Tident) { // Determine which parameter tparam is - size_t i = templateParameterLookup(tparam, parameters); + size_t i = templateParameterLookup(tparam, ¶meters); if (i == IDX_NOTFOUND) { if (!sc) @@ -3548,7 +3559,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param Loc loc; if (parameters.length) { - TemplateParameter tp = (*parameters)[0]; + TemplateParameter tp = parameters[0]; loc = tp.loc; } @@ -3561,9 +3572,9 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param return; } - TemplateParameter tp = (*parameters)[i]; + TemplateParameter tp = parameters[i]; - TypeIdentifier tident = cast(TypeIdentifier)tparam; + TypeIdentifier tident = tparam.isTypeIdentifier(); if (tident.idents.length > 0) { //printf("matching %s to %s\n", tparam.toChars(), t.toChars()); @@ -3601,21 +3612,21 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param Type tt = s.getType(); if (!tt) goto Lnomatch; - Type at = cast(Type)(*dedtypes)[i]; + Type at = cast(Type)dedtypes[i]; if (at && at.ty == Tnone) at = (cast(TypeDeduced)at).tded; if (!at || tt.equals(at)) { - (*dedtypes)[i] = tt; + dedtypes[i] = tt; goto Lexact; } } if (tp.isTemplateAliasParameter()) { - Dsymbol s2 = cast(Dsymbol)(*dedtypes)[i]; + Dsymbol s2 = cast(Dsymbol)dedtypes[i]; if (!s2 || s == s2) { - (*dedtypes)[i] = s; + dedtypes[i] = s; goto Lexact; } } @@ -3637,7 +3648,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param +/ if (auto ta = tp.isTemplateAliasParameter()) { - (*dedtypes)[i] = t; + dedtypes[i] = t; goto Lexact; } // (23578) - ensure previous behaviour for non-alias template params @@ -3646,14 +3657,14 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param goto Lnomatch; } - Type at = cast(Type)(*dedtypes)[i]; + Type at = cast(Type)dedtypes[i]; Type tt; if (ubyte wx = wm ? deduceWildHelper(t, &tt, tparam) : 0) { // type vs (none) if (!at) { - (*dedtypes)[i] = tt; + dedtypes[i] = tt; *wm |= wx; result = MATCH.constant; return; @@ -3662,11 +3673,11 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // type vs expressions if (at.ty == Tnone) { - TypeDeduced xt = cast(TypeDeduced)at; + auto xt = cast(TypeDeduced)at; result = xt.matchAll(tt); if (result > MATCH.nomatch) { - (*dedtypes)[i] = tt; + dedtypes[i] = tt; if (result > MATCH.constant) result = MATCH.constant; // limit level for inout matches } @@ -3676,29 +3687,29 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // type vs type if (tt.equals(at)) { - (*dedtypes)[i] = tt; // Prefer current type match + dedtypes[i] = tt; // Prefer current type match goto Lconst; } if (tt.implicitConvTo(at.constOf())) { - (*dedtypes)[i] = at.constOf().mutableOf(); + dedtypes[i] = at.constOf().mutableOf(); *wm |= MODFlags.const_; goto Lconst; } if (at.implicitConvTo(tt.constOf())) { - (*dedtypes)[i] = tt.constOf().mutableOf(); + dedtypes[i] = tt.constOf().mutableOf(); *wm |= MODFlags.const_; goto Lconst; } goto Lnomatch; } - else if (MATCH m = deduceTypeHelper(t, &tt, tparam)) + else if (MATCH m = deduceTypeHelper(t, tt, tparam)) { // type vs (none) if (!at) { - (*dedtypes)[i] = tt; + dedtypes[i] = tt; result = m; return; } @@ -3706,11 +3717,11 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // type vs expressions if (at.ty == Tnone) { - TypeDeduced xt = cast(TypeDeduced)at; + auto xt = cast(TypeDeduced)at; result = xt.matchAll(tt); if (result > MATCH.nomatch) { - (*dedtypes)[i] = tt; + dedtypes[i] = tt; } return; } @@ -3740,7 +3751,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param Loc loc; if (parameters.length) { - TemplateParameter tp = (*parameters)[0]; + TemplateParameter tp = parameters[0]; loc = tp.loc; } @@ -3757,9 +3768,8 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param MATCH m = t.implicitConvTo(tparam); if (m == MATCH.nomatch && !ignoreAliasThis) { - if (t.ty == Tclass) + if (auto tc = t.isTypeClass()) { - TypeClass tc = cast(TypeClass)t; if (tc.sym.aliasthis && !(tc.att & AliasThisRec.tracingDT)) { if (auto ato = t.aliasthisOf()) @@ -3770,9 +3780,8 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param } } } - else if (t.ty == Tstruct) + else if (auto ts = t.isTypeStruct()) { - TypeStruct ts = cast(TypeStruct)t; if (ts.sym.aliasthis && !(ts.att & AliasThisRec.tracingDT)) { if (auto ato = t.aliasthisOf()) @@ -3822,9 +3831,8 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param override void visit(TypeVector t) { - if (tparam.ty == Tvector) + if (auto tp = tparam.isTypeVector()) { - TypeVector tp = cast(TypeVector)tparam; result = deduceType(t.basetype, sc, tp.basetype, parameters, dedtypes, wm); return; } @@ -3851,25 +3859,23 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param TemplateParameter tp = null; Expression edim = null; size_t i; - if (tparam.ty == Tsarray) + if (auto tsa = tparam.isTypeSArray()) { - TypeSArray tsa = cast(TypeSArray)tparam; if (tsa.dim.isVarExp() && tsa.dim.isVarExp().var.storage_class & STC.templateparameter) { Identifier id = tsa.dim.isVarExp().var.ident; - i = templateIdentifierLookup(id, parameters); + i = templateIdentifierLookup(id, ¶meters); assert(i != IDX_NOTFOUND); - tp = (*parameters)[i]; + tp = parameters[i]; } else edim = tsa.dim; } - else if (tparam.ty == Taarray) + else if (auto taa = tparam.isTypeAArray()) { - TypeAArray taa = cast(TypeAArray)tparam; - i = templateParameterLookup(taa.index, parameters); + i = templateParameterLookup(taa.index, ¶meters); if (i != IDX_NOTFOUND) - tp = (*parameters)[i]; + tp = parameters[i]; else { Loc loc; @@ -3878,7 +3884,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // so we use that for the resolution (better error message). if (inferStart < parameters.length) { - TemplateParameter loctp = (*parameters)[inferStart]; + TemplateParameter loctp = parameters[inferStart]; loc = loctp.loc; } @@ -3889,7 +3895,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param edim = s ? getValue(s) : getValue(e); } } - if (tp && tp.matchArg(sc, t.dim, i, parameters, dedtypes, null) || edim && edim.toInteger() == t.dim.toInteger()) + if (tp && tp.matchArg(sc, t.dim, i, ¶meters, dedtypes, null) || edim && edim.toInteger() == t.dim.toInteger()) { result = deduceType(t.next, sc, tparam.nextOf(), parameters, dedtypes, wm); return; @@ -3903,7 +3909,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // Extra check that index type must match if (tparam && tparam.ty == Taarray) { - TypeAArray tp = cast(TypeAArray)tparam; + TypeAArray tp = tparam.isTypeAArray(); if (!deduceType(t.index, sc, tp.index, parameters, dedtypes)) { result = MATCH.nomatch; @@ -3936,7 +3942,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // https://issues.dlang.org/show_bug.cgi?id=15243 // Resolve parameter type if it's not related with template parameters - if (!reliesOnTemplateParameters(fparam.type, (*parameters)[inferStart .. parameters.length])) + if (!reliesOnTemplateParameters(fparam.type, parameters[inferStart .. parameters.length])) { auto tx = fparam.type.typeSemantic(Loc.initial, sc); if (tx.ty == Terror) @@ -3948,7 +3954,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param } } - size_t nfargs = t.parameterList.length; + const size_t nfargs = t.parameterList.length; size_t nfparams = tp.parameterList.length; /* See if tuple match @@ -3963,7 +3969,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param assert(fparam.type); if (fparam.type.ty != Tident) goto L1; - TypeIdentifier tid = cast(TypeIdentifier)fparam.type; + TypeIdentifier tid = fparam.type.isTypeIdentifier(); if (tid.idents.length) goto L1; @@ -3974,7 +3980,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param { if (tupi == parameters.length) goto L1; - TemplateParameter tx = (*parameters)[tupi]; + TemplateParameter tx = parameters[tupi]; TemplateTupleParameter tup = tx.isTemplateTupleParameter(); if (tup && tup.ident.equals(tid.ident)) break; @@ -3987,7 +3993,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param /* See if existing tuple, and whether it matches or not */ - RootObject o = (*dedtypes)[tupi]; + RootObject o = dedtypes[tupi]; if (o) { // Existing deduced argument must be a tuple, and must match @@ -4016,7 +4022,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param Parameter arg = t.parameterList[nfparams - 1 + i]; tup.objects[i] = arg.type; } - (*dedtypes)[tupi] = tup; + dedtypes[tupi] = tup; } nfparams--; // don't consider the last parameter for type deduction goto L2; @@ -4053,7 +4059,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // Extra check if (tparam && tparam.ty == Tident) { - TypeIdentifier tp = cast(TypeIdentifier)tparam; + TypeIdentifier tp = tparam.isTypeIdentifier(); for (size_t i = 0; i < t.idents.length; i++) { RootObject id1 = t.idents[i]; @@ -4076,7 +4082,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param TemplateDeclaration tempdecl = t.tempinst.tempdecl.isTemplateDeclaration(); assert(tempdecl); - TypeInstance tp = cast(TypeInstance)tparam; + TypeInstance tp = tparam.isTypeInstance(); //printf("tempinst.tempdecl = %p\n", tempdecl); //printf("tp.tempinst.tempdecl = %p\n", tp.tempinst.tempdecl); @@ -4087,7 +4093,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param /* Handle case of: * template Foo(T : sa!(T), alias sa) */ - size_t i = templateIdentifierLookup(tp.tempinst.name, parameters); + size_t i = templateIdentifierLookup(tp.tempinst.name, ¶meters); if (i == IDX_NOTFOUND) { /* Didn't find it as a parameter identifier. Try looking @@ -4132,15 +4138,15 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param goto Lnomatch; } - TemplateParameter tpx = (*parameters)[i]; - if (!tpx.matchArg(sc, tempdecl, i, parameters, dedtypes, null)) + TemplateParameter tpx = parameters[i]; + if (!tpx.matchArg(sc, tempdecl, i, ¶meters, dedtypes, null)) goto Lnomatch; } else if (tempdecl != tp.tempinst.tempdecl) goto Lnomatch; L2: - if (!resolveTemplateInstantiation(t.tempinst.tiargs, &t.tempinst.tdtypes, tempdecl, tp, dedtypes)) + if (!resolveTemplateInstantiation(sc, ¶meters, t.tempinst.tiargs, &t.tempinst.tdtypes, tempdecl, tp, &dedtypes)) goto Lnomatch; } visit(cast(Type)t); @@ -4151,198 +4157,6 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param result = MATCH.nomatch; } - /******************** - * Match template `parameters` to the target template instance. - * Example: - * struct Temp(U, int Z) {} - * void foo(T)(Temp!(T, 3)); - * foo(Temp!(int, 3)()); - * Input: - * this.parameters = template params of foo -> [T] - * tiargs = <Temp!(int, 3)>.tiargs -> [int, 3] - * tdtypes = <Temp!(int, 3)>.tdtypes -> [int, 3] - * tempdecl = <struct Temp!(T, int Z)> -> [T, Z] - * tp = <Temp!(T, 3)> - * Output: - * dedtypes = deduced params of `foo(Temp!(int, 3)())` -> [int] - */ - private bool resolveTemplateInstantiation(Objects* tiargs, Objects* tdtypes, TemplateDeclaration tempdecl, TypeInstance tp, Objects* dedtypes) - { - for (size_t i = 0; 1; i++) - { - //printf("\ttest: tempinst.tiargs[%zu]\n", i); - RootObject o1 = null; - if (i < tiargs.length) - o1 = (*tiargs)[i]; - else if (i < tdtypes.length && i < tp.tempinst.tiargs.length) - { - // Pick up default arg - o1 = (*tdtypes)[i]; - } - else if (i >= tp.tempinst.tiargs.length) - break; - //printf("\ttest: o1 = %s\n", o1.toChars()); - if (i >= tp.tempinst.tiargs.length) - { - size_t dim = tempdecl.parameters.length - (tempdecl.isVariadic() ? 1 : 0); - while (i < dim && ((*tempdecl.parameters)[i].dependent || (*tempdecl.parameters)[i].hasDefaultArg())) - { - i++; - } - if (i >= dim) - break; // match if all remained parameters are dependent - return false; - } - - RootObject o2 = (*tp.tempinst.tiargs)[i]; - Type t2 = isType(o2); - //printf("\ttest: o2 = %s\n", o2.toChars()); - size_t j = (t2 && t2.ty == Tident && i == tp.tempinst.tiargs.length - 1) - ? templateParameterLookup(t2, parameters) : IDX_NOTFOUND; - if (j != IDX_NOTFOUND && j == parameters.length - 1 && - (*parameters)[j].isTemplateTupleParameter()) - { - /* Given: - * struct A(B...) {} - * alias A!(int, float) X; - * static if (is(X Y == A!(Z), Z...)) {} - * deduce that Z is a tuple(int, float) - */ - - /* Create tuple from remaining args - */ - size_t vtdim = (tempdecl.isVariadic() ? tiargs.length : tdtypes.length) - i; - auto vt = new Tuple(vtdim); - for (size_t k = 0; k < vtdim; k++) - { - RootObject o; - if (k < tiargs.length) - o = (*tiargs)[i + k]; - else // Pick up default arg - o = (*tdtypes)[i + k]; - vt.objects[k] = o; - } - - Tuple v = cast(Tuple)(*dedtypes)[j]; - if (v) - { - if (!match(v, vt)) - return false; - } - else - (*dedtypes)[j] = vt; - break; - } - else if (!o1) - break; - - Type t1 = isType(o1); - Dsymbol s1 = isDsymbol(o1); - Dsymbol s2 = isDsymbol(o2); - Expression e1 = s1 ? getValue(s1) : getValue(isExpression(o1)); - Expression e2 = isExpression(o2); - version (none) - { - Tuple v1 = isTuple(o1); - Tuple v2 = isTuple(o2); - if (t1) - printf("t1 = %s\n", t1.toChars()); - if (t2) - printf("t2 = %s\n", t2.toChars()); - if (e1) - printf("e1 = %s\n", e1.toChars()); - if (e2) - printf("e2 = %s\n", e2.toChars()); - if (s1) - printf("s1 = %s\n", s1.toChars()); - if (s2) - printf("s2 = %s\n", s2.toChars()); - if (v1) - printf("v1 = %s\n", v1.toChars()); - if (v2) - printf("v2 = %s\n", v2.toChars()); - } - - if (t1 && t2) - { - if (!deduceType(t1, sc, t2, parameters, dedtypes)) - return false; - } - else if (e1 && e2) - { - Le: - e1 = e1.ctfeInterpret(); - - /* If it is one of the template parameters for this template, - * we should not attempt to interpret it. It already has a value. - */ - if (e2.op == EXP.variable && (e2.isVarExp().var.storage_class & STC.templateparameter)) - { - /* - * (T:Number!(e2), int e2) - */ - j = templateIdentifierLookup(e2.isVarExp().var.ident, parameters); - if (j != IDX_NOTFOUND) - goto L1; - // The template parameter was not from this template - // (it may be from a parent template, for example) - } - - e2 = e2.expressionSemantic(sc); // https://issues.dlang.org/show_bug.cgi?id=13417 - e2 = e2.ctfeInterpret(); - - //printf("e1 = %s, type = %s %d\n", e1.toChars(), e1.type.toChars(), e1.type.ty); - //printf("e2 = %s, type = %s %d\n", e2.toChars(), e2.type.toChars(), e2.type.ty); - if (!e1.equals(e2)) - { - if (!e2.implicitConvTo(e1.type)) - return false; - - e2 = e2.implicitCastTo(sc, e1.type); - e2 = e2.ctfeInterpret(); - if (!e1.equals(e2)) - return false; - } - } - else if (e1 && t2 && t2.ty == Tident) - { - j = templateParameterLookup(t2, parameters); - L1: - if (j == IDX_NOTFOUND) - { - t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2); - if (e2) - goto Le; - return false; - } - if (!(*parameters)[j].matchArg(sc, e1, j, parameters, dedtypes, null)) - return false; - } - else if (s1 && s2) - { - Ls: - if (!s1.equals(s2)) - return false; - } - else if (s1 && t2 && t2.ty == Tident) - { - j = templateParameterLookup(t2, parameters); - if (j == IDX_NOTFOUND) - { - t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2); - if (s2) - goto Ls; - return false; - } - if (!(*parameters)[j].matchArg(sc, s1, j, parameters, dedtypes, null)) - return false; - } - else - return false; - } - return true; - } - override void visit(TypeStruct t) { /* If this struct is a template struct, and we're matching @@ -4368,7 +4182,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param /* Match things like: * S!(T).foo */ - TypeInstance tpi = cast(TypeInstance)tparam; + TypeInstance tpi = tparam.isTypeInstance(); if (tpi.idents.length) { RootObject id = tpi.idents[tpi.idents.length - 1]; @@ -4391,7 +4205,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // Extra check if (tparam && tparam.ty == Tstruct) { - TypeStruct tp = cast(TypeStruct)tparam; + TypeStruct tp = tparam.isTypeStruct(); //printf("\t%d\n", cast(MATCH) t.implicitConvTo(tp)); if (wm && t.deduceWild(tparam, false)) @@ -4410,7 +4224,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // Extra check if (tparam && tparam.ty == Tenum) { - TypeEnum tp = cast(TypeEnum)tparam; + TypeEnum tp = tparam.isTypeEnum(); if (t.sym == tp.sym) visit(cast(Type)t); else @@ -4428,59 +4242,6 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param visit(cast(Type)t); } - /* Helper for TypeClass.deduceType(). - * Classes can match with implicit conversion to a base class or interface. - * This is complicated, because there may be more than one base class which - * matches. In such cases, one or more parameters remain ambiguous. - * For example, - * - * interface I(X, Y) {} - * class C : I(uint, double), I(char, double) {} - * C x; - * foo(T, U)( I!(T, U) x) - * - * deduces that U is double, but T remains ambiguous (could be char or uint). - * - * Given a baseclass b, and initial deduced types 'dedtypes', this function - * tries to match tparam with b, and also tries all base interfaces of b. - * If a match occurs, numBaseClassMatches is incremented, and the new deduced - * types are ANDed with the current 'best' estimate for dedtypes. - */ - static void deduceBaseClassParameters(ref BaseClass b, Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, Objects* best, ref int numBaseClassMatches) - { - TemplateInstance parti = b.sym ? b.sym.parent.isTemplateInstance() : null; - if (parti) - { - // Make a temporary copy of dedtypes so we don't destroy it - auto tmpdedtypes = new Objects(dedtypes.length); - memcpy(tmpdedtypes.tdata(), dedtypes.tdata(), dedtypes.length * (void*).sizeof); - - auto t = new TypeInstance(Loc.initial, parti); - MATCH m = deduceType(t, sc, tparam, parameters, tmpdedtypes); - if (m > MATCH.nomatch) - { - // If this is the first ever match, it becomes our best estimate - if (numBaseClassMatches == 0) - memcpy(best.tdata(), tmpdedtypes.tdata(), tmpdedtypes.length * (void*).sizeof); - else - for (size_t k = 0; k < tmpdedtypes.length; ++k) - { - // If we've found more than one possible type for a parameter, - // mark it as unknown. - if ((*tmpdedtypes)[k] != (*best)[k]) - (*best)[k] = (*dedtypes)[k]; - } - ++numBaseClassMatches; - } - } - - // Now recursively test the inherited interfaces - foreach (ref bi; b.baseInterfaces) - { - deduceBaseClassParameters(bi, sc, tparam, parameters, dedtypes, best, numBaseClassMatches); - } - } - override void visit(TypeClass t) { //printf("TypeClass.deduceType(this = %s)\n", t.toChars()); @@ -4509,7 +4270,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param /* Match things like: * S!(T).foo */ - TypeInstance tpi = cast(TypeInstance)tparam; + TypeInstance tpi = tparam.isTypeInstance(); if (tpi.idents.length) { RootObject id = tpi.idents[tpi.idents.length - 1]; @@ -4547,12 +4308,12 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param while (s && s.baseclasses.length > 0) { // Test the base class - deduceBaseClassParameters(*(*s.baseclasses)[0], sc, tparam, parameters, dedtypes, best, numBaseClassMatches); + deduceBaseClassParameters(*(*s.baseclasses)[0], sc, tparam, parameters, dedtypes, *best, numBaseClassMatches); // Test the interfaces inherited by the base class foreach (b; s.interfaces) { - deduceBaseClassParameters(*b, sc, tparam, parameters, dedtypes, best, numBaseClassMatches); + deduceBaseClassParameters(*b, sc, tparam, parameters, dedtypes, *best, numBaseClassMatches); } s = (*s.baseclasses)[0].sym; } @@ -4572,7 +4333,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // Extra check if (tparam && tparam.ty == Tclass) { - TypeClass tp = cast(TypeClass)tparam; + TypeClass tp = tparam.isTypeClass(); //printf("\t%d\n", cast(MATCH) t.implicitConvTo(tp)); if (wm && t.deduceWild(tparam, false)) @@ -4589,8 +4350,8 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param override void visit(Expression e) { //printf("Expression.deduceType(e = %s)\n", e.toChars()); - size_t i = templateParameterLookup(tparam, parameters); - if (i == IDX_NOTFOUND || (cast(TypeIdentifier)tparam).idents.length > 0) + size_t i = templateParameterLookup(tparam, ¶meters); + if (i == IDX_NOTFOUND || tparam.isTypeIdentifier().idents.length > 0) { if (e == emptyArrayElement && tparam.ty == Tarray) { @@ -4602,13 +4363,13 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param return; } - TemplateTypeParameter tp = (*parameters)[i].isTemplateTypeParameter(); + TemplateTypeParameter tp = parameters[i].isTemplateTypeParameter(); if (!tp) return; // nomatch if (e == emptyArrayElement) { - if ((*dedtypes)[i]) + if (dedtypes[i]) { result = MATCH.exact; return; @@ -4630,14 +4391,14 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param tb.ty == Tstruct && tb.hasPointers(); } - Type at = cast(Type)(*dedtypes)[i]; + Type at = cast(Type)dedtypes[i]; Type tt; if (ubyte wx = deduceWildHelper(e.type, &tt, tparam)) { *wm |= wx; result = MATCH.constant; } - else if (MATCH m = deduceTypeHelper(e.type, &tt, tparam)) + else if (MATCH m = deduceTypeHelper(e.type, tt, tparam)) { result = m; } @@ -4658,7 +4419,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // expression vs (none) if (!at) { - (*dedtypes)[i] = new TypeDeduced(tt, e, tparam); + dedtypes[i] = new TypeDeduced(tt, e, tparam); return; } @@ -4716,7 +4477,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param if (xt) xt.update(tt, e, tparam); else - (*dedtypes)[i] = tt; + dedtypes[i] = tt; result = match1; return; } @@ -4736,7 +4497,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param if (xt) xt.update(t, e, tparam); else - (*dedtypes)[i] = t; + dedtypes[i] = t; pt = tt.addMod(tparam.mod); if (*wm) @@ -4870,7 +4631,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // Parameter types inference from 'tof' assert(e.td._scope); - TypeFunction tf = cast(TypeFunction)e.fd.type; + TypeFunction tf = e.fd.type.isTypeFunction(); //printf("\ttof = %s\n", tof.toChars()); //printf("\ttf = %s\n", tf.toChars()); const dim = tf.parameterList.length; @@ -4895,7 +4656,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param if (!pto) break; Type t = pto.type.syntaxCopy(); // https://issues.dlang.org/show_bug.cgi?id=11774 - if (reliesOnTemplateParameters(t, (*parameters)[inferStart .. parameters.length])) + if (reliesOnTemplateParameters(t, parameters[inferStart .. parameters.length])) return; t = t.typeSemantic(e.loc, sc); if (t.ty == Terror) @@ -4929,7 +4690,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // Allow conversion from implicit function pointer to delegate if (e.tok == TOK.reserved && t.ty == Tpointer && tparam.ty == Tdelegate) { - TypeFunction tf = cast(TypeFunction)t.nextOf(); + TypeFunction tf = t.nextOf().isTypeFunction(); t = (new TypeDelegate(tf)).merge(); } //printf("tparam = %s <= e.type = %s, t = %s\n", tparam.toChars(), e.type.toChars(), t.toChars()); @@ -4959,7 +4720,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param } } - scope DeduceType v = new DeduceType(sc, tparam, parameters, dedtypes, wm, inferStart, ignoreAliasThis); + scope DeduceType v = new DeduceType(); if (Type t = isType(o)) t.accept(v); else if (Expression e = isExpression(o)) @@ -4972,6 +4733,254 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param return v.result; } + +/* Helper for TypeClass.deduceType(). + * Classes can match with implicit conversion to a base class or interface. + * This is complicated, because there may be more than one base class which + * matches. In such cases, one or more parameters remain ambiguous. + * For example, + * + * interface I(X, Y) {} + * class C : I(uint, double), I(char, double) {} + * C x; + * foo(T, U)( I!(T, U) x) + * + * deduces that U is double, but T remains ambiguous (could be char or uint). + * + * Given a baseclass b, and initial deduced types 'dedtypes', this function + * tries to match tparam with b, and also tries all base interfaces of b. + * If a match occurs, numBaseClassMatches is incremented, and the new deduced + * types are ANDed with the current 'best' estimate for dedtypes. + */ +private void deduceBaseClassParameters(ref BaseClass b, Scope* sc, Type tparam, ref TemplateParameters parameters, ref Objects dedtypes, ref Objects best, ref int numBaseClassMatches) +{ + TemplateInstance parti = b.sym ? b.sym.parent.isTemplateInstance() : null; + if (parti) + { + // Make a temporary copy of dedtypes so we don't destroy it + auto tmpdedtypes = new Objects(dedtypes.length); + memcpy(tmpdedtypes.tdata(), dedtypes.tdata(), dedtypes.length * (void*).sizeof); + + auto t = new TypeInstance(Loc.initial, parti); + MATCH m = deduceType(t, sc, tparam, parameters, *tmpdedtypes); + if (m > MATCH.nomatch) + { + // If this is the first ever match, it becomes our best estimate + if (numBaseClassMatches == 0) + memcpy(best.tdata(), tmpdedtypes.tdata(), tmpdedtypes.length * (void*).sizeof); + else + for (size_t k = 0; k < tmpdedtypes.length; ++k) + { + // If we've found more than one possible type for a parameter, + // mark it as unknown. + if ((*tmpdedtypes)[k] != best[k]) + best[k] = dedtypes[k]; + } + ++numBaseClassMatches; + } + } + + // Now recursively test the inherited interfaces + foreach (ref bi; b.baseInterfaces) + { + deduceBaseClassParameters(bi, sc, tparam, parameters, dedtypes, best, numBaseClassMatches); + } +} + +/******************** + * Match template `parameters` to the target template instance. + * Example: + * struct Temp(U, int Z) {} + * void foo(T)(Temp!(T, 3)); + * foo(Temp!(int, 3)()); + * Input: + * sc = context + * parameters = template params of foo -> [T] + * tiargs = <Temp!(int, 3)>.tiargs -> [int, 3] + * tdtypes = <Temp!(int, 3)>.tdtypes -> [int, 3] + * tempdecl = <struct Temp!(T, int Z)> -> [T, Z] + * tp = <Temp!(T, 3)> + * Output: + * dedtypes = deduced params of `foo(Temp!(int, 3)())` -> [int] + */ +private bool resolveTemplateInstantiation(Scope* sc, TemplateParameters* parameters, Objects* tiargs, Objects* tdtypes, TemplateDeclaration tempdecl, TypeInstance tp, Objects* dedtypes) +{ + for (size_t i = 0; 1; i++) + { + //printf("\ttest: tempinst.tiargs[%zu]\n", i); + RootObject o1 = null; + if (i < tiargs.length) + o1 = (*tiargs)[i]; + else if (i < tdtypes.length && i < tp.tempinst.tiargs.length) + { + // Pick up default arg + o1 = (*tdtypes)[i]; + } + else if (i >= tp.tempinst.tiargs.length) + break; + //printf("\ttest: o1 = %s\n", o1.toChars()); + if (i >= tp.tempinst.tiargs.length) + { + size_t dim = tempdecl.parameters.length - (tempdecl.isVariadic() ? 1 : 0); + while (i < dim && ((*tempdecl.parameters)[i].dependent || (*tempdecl.parameters)[i].hasDefaultArg())) + { + i++; + } + if (i >= dim) + break; // match if all remained parameters are dependent + return false; + } + + RootObject o2 = (*tp.tempinst.tiargs)[i]; + Type t2 = isType(o2); + //printf("\ttest: o2 = %s\n", o2.toChars()); + size_t j = (t2 && t2.ty == Tident && i == tp.tempinst.tiargs.length - 1) + ? templateParameterLookup(t2, parameters) : IDX_NOTFOUND; + if (j != IDX_NOTFOUND && j == parameters.length - 1 && + (*parameters)[j].isTemplateTupleParameter()) + { + /* Given: + * struct A(B...) {} + * alias A!(int, float) X; + * static if (is(X Y == A!(Z), Z...)) {} + * deduce that Z is a tuple(int, float) + */ + + /* Create tuple from remaining args + */ + size_t vtdim = (tempdecl.isVariadic() ? tiargs.length : tdtypes.length) - i; + auto vt = new Tuple(vtdim); + for (size_t k = 0; k < vtdim; k++) + { + RootObject o; + if (k < tiargs.length) + o = (*tiargs)[i + k]; + else // Pick up default arg + o = (*tdtypes)[i + k]; + vt.objects[k] = o; + } + + Tuple v = cast(Tuple)(*dedtypes)[j]; + if (v) + { + if (!match(v, vt)) + return false; + } + else + (*dedtypes)[j] = vt; + break; + } + else if (!o1) + break; + + Type t1 = isType(o1); + Dsymbol s1 = isDsymbol(o1); + Dsymbol s2 = isDsymbol(o2); + Expression e1 = s1 ? getValue(s1) : getValue(isExpression(o1)); + Expression e2 = isExpression(o2); + version (none) + { + Tuple v1 = isTuple(o1); + Tuple v2 = isTuple(o2); + if (t1) + printf("t1 = %s\n", t1.toChars()); + if (t2) + printf("t2 = %s\n", t2.toChars()); + if (e1) + printf("e1 = %s\n", e1.toChars()); + if (e2) + printf("e2 = %s\n", e2.toChars()); + if (s1) + printf("s1 = %s\n", s1.toChars()); + if (s2) + printf("s2 = %s\n", s2.toChars()); + if (v1) + printf("v1 = %s\n", v1.toChars()); + if (v2) + printf("v2 = %s\n", v2.toChars()); + } + + if (t1 && t2) + { + if (!deduceType(t1, sc, t2, *parameters, *dedtypes)) + return false; + } + else if (e1 && e2) + { + Le: + e1 = e1.ctfeInterpret(); + + /* If it is one of the template parameters for this template, + * we should not attempt to interpret it. It already has a value. + */ + if (e2.op == EXP.variable && (e2.isVarExp().var.storage_class & STC.templateparameter)) + { + /* + * (T:Number!(e2), int e2) + */ + j = templateIdentifierLookup(e2.isVarExp().var.ident, parameters); + if (j != IDX_NOTFOUND) + goto L1; + // The template parameter was not from this template + // (it may be from a parent template, for example) + } + + e2 = e2.expressionSemantic(sc); // https://issues.dlang.org/show_bug.cgi?id=13417 + e2 = e2.ctfeInterpret(); + + //printf("e1 = %s, type = %s %d\n", e1.toChars(), e1.type.toChars(), e1.type.ty); + //printf("e2 = %s, type = %s %d\n", e2.toChars(), e2.type.toChars(), e2.type.ty); + if (!e1.equals(e2)) + { + if (!e2.implicitConvTo(e1.type)) + return false; + + e2 = e2.implicitCastTo(sc, e1.type); + e2 = e2.ctfeInterpret(); + if (!e1.equals(e2)) + return false; + } + } + else if (e1 && t2 && t2.ty == Tident) + { + j = templateParameterLookup(t2, parameters); + L1: + if (j == IDX_NOTFOUND) + { + t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2); + if (e2) + goto Le; + return false; + } + if (!(*parameters)[j].matchArg(sc, e1, j, parameters, *dedtypes, null)) + return false; + } + else if (s1 && s2) + { + Ls: + if (!s1.equals(s2)) + return false; + } + else if (s1 && t2 && t2.ty == Tident) + { + j = templateParameterLookup(t2, parameters); + if (j == IDX_NOTFOUND) + { + t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2); + if (s2) + goto Ls; + return false; + } + if (!(*parameters)[j].matchArg(sc, s1, j, parameters, *dedtypes, null)) + return false; + } + else + return false; + } + return true; +} + + /*********************************************************** * Check whether the type t representation relies on one or more the template parameters. * Params: @@ -5625,7 +5634,11 @@ extern (C++) final class TemplateValueParameter : TemplateParameter if (e) { e = e.syntaxCopy(); - if ((e = e.expressionSemantic(sc)) is null) + Scope* sc2 = sc.push(); + sc2.inDefaultArg = true; + e = e.expressionSemantic(sc2); + sc2.pop(); + if (e is null) return null; if (auto te = e.isTemplateExp()) { @@ -6176,7 +6189,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol } //printf("parent = %s, ti.parent = %s\n", parent.toPrettyChars(), ti.parent.toPrettyChars()); - if (!arrayObjectMatch(&tdtypes, &ti.tdtypes)) + if (!arrayObjectMatch(tdtypes, ti.tdtypes)) goto Lnotequals; /* Template functions may have different instantiations based on @@ -6221,7 +6234,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol if (!hash) { hash = cast(size_t)cast(void*)enclosing; - hash += arrayObjectHash(&tdtypes); + hash += arrayObjectHash(tdtypes); hash += hash == 0; } return hash; @@ -6691,6 +6704,12 @@ extern (C++) class TemplateInstance : ScopeDsymbol if (!tiargs) return true; bool err = false; + + // The arguments are not treated as part of a default argument, + // because they are evaluated at compile time. + sc = sc.push(); + sc.inDefaultArg = false; + for (size_t j = 0; j < tiargs.length; j++) { RootObject o = (*tiargs)[j]; @@ -6716,10 +6735,9 @@ extern (C++) class TemplateInstance : ScopeDsymbol } Ltype: - if (ta.ty == Ttuple) + if (TypeTuple tt = ta.isTypeTuple()) { // Expand tuple - TypeTuple tt = cast(TypeTuple)ta; size_t dim = tt.arguments.length; tiargs.remove(j); if (dim) @@ -6923,6 +6941,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol } //printf("1: (*tiargs)[%d] = %p\n", j, (*tiargs)[j]); } + sc.pop(); version (none) { printf("-TemplateInstance.semanticTiargs()\n"); @@ -6982,7 +7001,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol assert(tempdecl._scope); // Deduce tdtypes tdtypes.setDim(tempdecl.parameters.length); - if (!tempdecl.matchWithInstance(sc, this, &tdtypes, argumentList, 2)) + if (!tempdecl.matchWithInstance(sc, this, tdtypes, argumentList, 2)) { .error(loc, "%s `%s` incompatible arguments for template instantiation", kind, toPrettyChars); return false; @@ -7032,7 +7051,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol dedtypes.zero(); assert(td.semanticRun != PASS.initial); - MATCH m = td.matchWithInstance(sc, this, &dedtypes, argumentList, 0); + MATCH m = td.matchWithInstance(sc, this, dedtypes, argumentList, 0); //printf("matchWithInstance = %d\n", m); if (m == MATCH.nomatch) // no match at all return 0; @@ -7158,7 +7177,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol // print additional information, e.g. `foo` is not a type foreach (i, param; *tdecl.parameters) { - MATCH match = param.matchArg(loc, sc, tiargs, i, tdecl.parameters, &dedtypes, null); + MATCH match = param.matchArg(loc, sc, tiargs, i, tdecl.parameters, dedtypes, null); auto arg = (*tiargs)[i]; auto sym = arg.isDsymbol; auto exp = arg.isExpression; @@ -7262,7 +7281,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol * to instantiate the template. */ //printf("tp = %p, td.parameters.length = %d, tiargs.length = %d\n", tp, td.parameters.length, tiargs.length); - auto tf = cast(TypeFunction)fd.type; + auto tf = fd.type.isTypeFunction(); if (tf.parameterList.length) { auto tp = td.isVariadic(); @@ -7308,7 +7327,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol return 1; } } - MATCH m = td.matchWithInstance(sc, this, &dedtypes, ArgumentList(), 0); + MATCH m = td.matchWithInstance(sc, this, dedtypes, ArgumentList(), 0); if (m == MATCH.nomatch) return 0; } @@ -7992,7 +8011,7 @@ struct TemplateInstanceBox * dedtypes[] deduced arguments to template instance * *psparam set to symbol declared and initialized to dedtypes[i] */ -MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, size_t i, TemplateParameters* parameters, Objects* dedtypes, Declaration* psparam) +MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, size_t i, TemplateParameters* parameters, ref Objects dedtypes, Declaration* psparam) { MATCH matchArgNoMatch() { @@ -8015,7 +8034,7 @@ MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, si { assert(i < dedtypes.length); // It might have already been deduced - oarg = (*dedtypes)[i]; + oarg = dedtypes[i]; if (!oarg) return matchArgNoMatch(); } @@ -8031,7 +8050,7 @@ MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, si assert(i + 1 == dedtypes.length); // must be the last one Tuple ovar; - if (Tuple u = isTuple((*dedtypes)[i])) + if (Tuple u = isTuple(dedtypes[i])) { // It has already been deduced ovar = u; @@ -8059,7 +8078,7 @@ MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, si return matchArgParameter(); } -MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, TemplateParameters* parameters, Objects* dedtypes, Declaration* psparam) +MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, TemplateParameters* parameters, ref Objects dedtypes, Declaration* psparam) { MATCH matchArgNoMatch() { @@ -8087,7 +8106,7 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ return matchArgNoMatch(); //printf("\tcalling deduceType(): ta is %s, specType is %s\n", ta.toChars(), ttp.specType.toChars()); - MATCH m2 = deduceType(ta, sc, ttp.specType, parameters, dedtypes); + MATCH m2 = deduceType(ta, sc, ttp.specType, *parameters, dedtypes); if (m2 == MATCH.nomatch) { //printf("\tfailed deduceType\n"); @@ -8096,9 +8115,9 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ if (m2 < m) m = m2; - if ((*dedtypes)[i]) + if (dedtypes[i]) { - Type t = cast(Type)(*dedtypes)[i]; + Type t = cast(Type)dedtypes[i]; if (ttp.dependent && !t.equals(ta)) // https://issues.dlang.org/show_bug.cgi?id=14357 return matchArgNoMatch(); @@ -8113,10 +8132,10 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ } else { - if ((*dedtypes)[i]) + if (dedtypes[i]) { // Must match already deduced type - Type t = cast(Type)(*dedtypes)[i]; + Type t = cast(Type)dedtypes[i]; if (!t.equals(ta)) { @@ -8130,7 +8149,7 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ m = MATCH.convert; } } - (*dedtypes)[i] = ta; + dedtypes[i] = ta; if (psparam) *psparam = new AliasDeclaration(ttp.loc, ttp.ident, ta); @@ -8235,15 +8254,15 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ } else { - if ((*dedtypes)[i]) + if (dedtypes[i]) { // Must match already deduced value - Expression e = cast(Expression)(*dedtypes)[i]; + Expression e = cast(Expression)dedtypes[i]; if (!ei || !ei.equals(e)) return matchArgNoMatch(); } } - (*dedtypes)[i] = ei; + dedtypes[i] = ei; if (psparam) { @@ -8354,7 +8373,7 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ return matchArgNoMatch(); Type t = new TypeInstance(Loc.initial, ti); - MATCH m2 = deduceType(t, sc, talias, parameters, dedtypes); + MATCH m2 = deduceType(t, sc, talias, *parameters, dedtypes); if (m2 == MATCH.nomatch) return matchArgNoMatch(); } @@ -8375,14 +8394,14 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ } } } - else if ((*dedtypes)[i]) + else if (dedtypes[i]) { // Must match already deduced symbol - RootObject si = (*dedtypes)[i]; + RootObject si = dedtypes[i]; if (!sa || si != sa) return matchArgNoMatch(); } - (*dedtypes)[i] = sa; + dedtypes[i] = sa; if (psparam) { @@ -8415,15 +8434,15 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ Tuple ovar = isTuple(oarg); if (!ovar) return MATCH.nomatch; - if ((*dedtypes)[i]) + if (dedtypes[i]) { - Tuple tup = isTuple((*dedtypes)[i]); + Tuple tup = isTuple(dedtypes[i]); if (!tup) return MATCH.nomatch; if (!match(tup, ovar)) return MATCH.nomatch; } - (*dedtypes)[i] = ovar; + dedtypes[i] = ovar; if (psparam) *psparam = new TupleDeclaration(ttp.loc, ttp.ident, &ovar.objects); @@ -8457,21 +8476,24 @@ struct TemplateStats /******************************* * Add this instance + * Params: + * td = template declaration + * ti = instance of td + * listInstances = keep track of instances of templates */ static void incInstance(const TemplateDeclaration td, - const TemplateInstance ti) + const TemplateInstance ti, + bool listInstances) { void log(ref TemplateStats ts) { if (ts.allInstances is null) ts.allInstances = new TemplateInstances(); - if (global.params.v.templatesListInstances) + if (listInstances) ts.allInstances.push(cast() ti); } - // message(ti.loc, "incInstance %p %p", td, ti); - if (!global.params.v.templates) - return; + // message(ti.loc, "incInstance %p %p", td, ti); if (!td) return; assert(ti); @@ -8494,8 +8516,6 @@ struct TemplateStats const TemplateInstance ti) { // message(ti.loc, "incUnique %p %p", td, ti); - if (!global.params.v.templates) - return; if (!td) return; assert(ti); @@ -8506,7 +8526,13 @@ struct TemplateStats } } -extern (C++) void printTemplateStats() +/******************************** + * Print informational statistics on template instantiations. + * Params: + * listInstances = list instances of templates + * eSink = where the print is sent + */ +extern (C++) void printTemplateStats(bool listInstances, ErrorSink eSink) { static struct TemplateDeclarationStats { @@ -8523,11 +8549,12 @@ extern (C++) void printTemplateStats() } } - if (!global.params.v.templates) - return; + const stats_length = TemplateStats.stats.length; + if (!stats_length) + return; // nothing to report Array!(TemplateDeclarationStats) sortedStats; - sortedStats.reserve(TemplateStats.stats.length); + sortedStats.reserve(stats_length); foreach (td_, ref ts; TemplateStats.stats) { sortedStats.push(TemplateDeclarationStats(cast(TemplateDeclaration) td_, ts)); @@ -8537,10 +8564,9 @@ extern (C++) void printTemplateStats() foreach (const ref ss; sortedStats[]) { - if (global.params.v.templatesListInstances && - ss.ts.allInstances) + if (listInstances && ss.ts.allInstances) { - message(ss.td.loc, + eSink.message(ss.td.loc, "vtemplate: %u (%u distinct) instantiation(s) of template `%s` found, they are:", ss.ts.numInstantiations, ss.ts.uniqueInstantiations, @@ -8548,14 +8574,14 @@ extern (C++) void printTemplateStats() foreach (const ti; (*ss.ts.allInstances)[]) { if (ti.tinst) // if has enclosing instance - message(ti.loc, "vtemplate: implicit instance `%s`", ti.toChars()); + eSink.message(ti.loc, "vtemplate: implicit instance `%s`", ti.toChars()); else - message(ti.loc, "vtemplate: explicit instance `%s`", ti.toChars()); + eSink.message(ti.loc, "vtemplate: explicit instance `%s`", ti.toChars()); } } else { - message(ss.td.loc, + eSink.message(ss.td.loc, "vtemplate: %u (%u distinct) instantiation(s) of template `%s` found", ss.ts.numInstantiations, ss.ts.uniqueInstantiations, diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d index 30991c9..2bfa96c 100644 --- a/gcc/d/dmd/dtoh.d +++ b/gcc/d/dmd/dtoh.d @@ -779,6 +779,17 @@ public: } } + if (tf && tf.next) + { + // Ensure return type is declared before a function that returns that is declared. + if (auto sty = tf.next.isTypeStruct()) + ensureDeclared(sty.sym); + //else if (auto cty = tf.next.isTypeClass()) + // includeSymbol(cty.sym); // classes are returned by pointer only need to forward declare + //else if (auto ety = tf.next.isTypeEnum()) + // ensureDeclared(ety.sym); + } + writeProtection(fd.visibility.kind); if (tf && tf.linkage == LINK.c) diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d index 433907a..3e17ff4 100644 --- a/gcc/d/dmd/escape.d +++ b/gcc/d/dmd/escape.d @@ -34,6 +34,7 @@ import dmd.mtype; import dmd.printast; import dmd.rootobject; import dmd.tokens; +import dmd.typesem : hasPointers, parameterStorageClass; import dmd.visitor; import dmd.arraytypes; diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index 41eeff9..cbf0118 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -190,39 +190,6 @@ extern (C++) void expandTuples(Expressions* exps, Identifiers* names = null) } /**************************************** - * Expand alias this tuples. - */ -TupleDeclaration isAliasThisTuple(Expression e) -{ - if (!e.type) - return null; - - Type t = e.type.toBasetype(); - while (true) - { - if (Dsymbol s = t.toDsymbol(null)) - { - if (auto ad = s.isAggregateDeclaration()) - { - s = ad.aliasthis ? ad.aliasthis.sym : null; - if (s && s.isVarDeclaration()) - { - TupleDeclaration td = s.isVarDeclaration().toAlias().isTupleDeclaration(); - if (td && td.isexp) - return td; - } - if (Type att = t.aliasthisOf()) - { - t = att; - continue; - } - } - } - return null; - } -} - -/**************************************** * If `s` is a function template, i.e. the only member of a template * and that member is a function, return that template. * Params: diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index 9ce6f4d..d464574 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -384,7 +384,6 @@ private Expression reorderSettingAAElem(BinExp exp, Scope* sc) return Expression.combine(e0, be); } - private Expression checkOpAssignTypes(BinExp binExp, Scope* sc) { auto e1 = binExp.e1; @@ -563,6 +562,39 @@ private Expression extractOpDollarSideEffect(Scope* sc, UnaExp ue) return e0; } +/**************************************** + * Expand alias this tuples. + */ +TupleDeclaration isAliasThisTuple(Expression e) +{ + if (!e.type) + return null; + + Type t = e.type.toBasetype(); + while (true) + { + if (Dsymbol s = t.toDsymbol(null)) + { + if (auto ad = s.isAggregateDeclaration()) + { + s = ad.aliasthis ? ad.aliasthis.sym : null; + if (s && s.isVarDeclaration()) + { + TupleDeclaration td = s.isVarDeclaration().toAlias().isTupleDeclaration(); + if (td && td.isexp) + return td; + } + if (Type att = t.aliasthisOf()) + { + t = att; + continue; + } + } + } + return null; + } +} + /************************************** * Runs semantic on ae.arguments. Declares temporary variables * if '$' was used. @@ -5115,7 +5147,16 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor tb = tb.isTypeDArray().next.toBasetype(); } - if (global.params.betterC || !sc.needsCodegen()) + if (!global.params.useGC && sc.needsCodegen()) + { + version(IN_GCC) + error(exp.loc, "expression `%s` allocates with the GC and cannot be used with switch `-fno-rtti`", exp.toChars()); + else + error(exp.loc, "expression `%s` allocates with the GC and cannot be used with switch `-betterC`", exp.toChars()); + return setError(); + } + + if (!sc.needsCodegen()) goto LskipNewArrayLowering; /* Class types may inherit base classes that have errors. @@ -6432,8 +6473,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } - const(char)* failMessage; - if (!tf.callMatch(null, exp.argumentList, 0, &failMessage, sc)) + void errorHelper(const(char)* failMessage) scope { OutBuffer buf; buf.writeByte('('); @@ -6447,8 +6487,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor p, exp.e1.toChars(), parametersTypeToChars(tf.parameterList), buf.peekChars()); if (failMessage) errorSupplemental(exp.loc, "%s", failMessage); - return setError(); } + + if (tf.callMatch(null, exp.argumentList, 0, &errorHelper, sc) == MATCH.nomatch) + return setError(); + // Purity and safety check should run after testing arguments matching if (exp.f) { @@ -6505,8 +6548,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { exp.f = exp.f.toAliasFunc(); TypeFunction tf = cast(TypeFunction)exp.f.type; - const(char)* failMessage; - if (!tf.callMatch(null, exp.argumentList, 0, &failMessage, sc)) + + void errorHelper2(const(char)* failMessage) scope { OutBuffer buf; buf.writeByte('('); @@ -6527,6 +6570,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor errorSupplemental(exp.loc, "%s", failMessage); exp.f = null; } + + if (tf.callMatch(null, exp.argumentList, 0, &errorHelper2, sc) == MATCH.nomatch) + exp.f = null; } if (!exp.f || exp.f.errors) return setError(); @@ -7041,7 +7087,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor sc2.tinst = null; sc2.minst = null; sc2.flags |= SCOPE.fullinst; - Type t = e.targ.trySemantic(e.loc, sc2); + Type t = dmd.typesem.trySemantic(e.targ, e.loc, sc2); sc2.pop(); if (!t) // errors, so condition is false return no(); @@ -7271,7 +7317,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor Objects dedtypes = Objects(e.parameters.length); dedtypes.zero(); - MATCH m = deduceType(e.targ, sc, e.tspec, e.parameters, &dedtypes, null, 0, e.tok == TOK.equal); + MATCH m = deduceType(e.targ, sc, e.tspec, *e.parameters, dedtypes, null, 0, e.tok == TOK.equal); if (m == MATCH.nomatch || (m != MATCH.exact && e.tok == TOK.equal)) { @@ -7292,7 +7338,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor TemplateParameter tp = (*e.parameters)[i]; Declaration s = null; - m = tp.matchArg(e.loc, sc, &tiargs, i, e.parameters, &dedtypes, &s); + m = tp.matchArg(e.loc, sc, &tiargs, i, e.parameters, dedtypes, &s); if (m == MATCH.nomatch) return no(); s.dsymbolSemantic(sc); @@ -7437,7 +7483,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = (cast(BinExp)e).reorderSettingAAElem(sc); } - private Expression compileIt(MixinExp exp) + private Expression compileIt(MixinExp exp, Scope *sc) { OutBuffer buf; if (expressionsToString(buf, sc, exp.exps)) @@ -7478,7 +7524,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor printf("MixinExp::semantic('%s')\n", exp.toChars()); } - auto e = compileIt(exp); + // The expression is not treated as part of a default argument, + // because it is evaluated at compile time. + Scope* sc2 = sc.push(); + sc2.inDefaultArg = false; + + auto e = compileIt(exp, sc2); + sc2.pop(); if (!e) return setError(); result = e.expressionSemantic(sc); @@ -7575,7 +7627,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { auto fileName = FileName(resolvedNamez); - if (auto fmResult = global.fileManager.lookup(fileName)) + if (auto fmResult = global.fileManager.getFileContents(fileName)) { se = new StringExp(e.loc, fmResult); } @@ -7721,7 +7773,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // if the assert condition is a mixin expression, try to compile it if (auto ce = exp.e1.isMixinExp()) { - if (auto e1 = compileIt(ce)) + if (auto e1 = compileIt(ce, sc)) exp.e1 = e1; } @@ -13924,45 +13976,34 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { //printf("FileInitExp::semantic()\n"); e.type = Type.tstring; - result = e; + result = e.resolveLoc(e.loc, sc); } override void visit(LineInitExp e) { e.type = Type.tint32; - result = e; + result = e.resolveLoc(e.loc, sc); } override void visit(ModuleInitExp e) { //printf("ModuleInitExp::semantic()\n"); e.type = Type.tstring; - result = e; + result = e.resolveLoc(e.loc, sc); } override void visit(FuncInitExp e) { //printf("FuncInitExp::semantic()\n"); e.type = Type.tstring; - if (sc.func) - { - result = e.resolveLoc(Loc.initial, sc); - return; - } - result = e; + result = e.resolveLoc(e.loc, sc); } override void visit(PrettyFuncInitExp e) { //printf("PrettyFuncInitExp::semantic()\n"); e.type = Type.tstring; - if (sc.func) - { - result = e.resolveLoc(Loc.initial, sc); - return; - } - - result = e; + result = e.resolveLoc(e.loc, sc); } } @@ -15047,10 +15088,21 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false) */ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc) { + // Don't replace the special keywords, while we are inside a default + // argument. They are replaced later when copied to the call site. + if (sc.inDefaultArg) + return exp; + exp.loc = loc; Expression visit(Expression exp) { + if (auto binExp = exp.isBinExp()) + { + binExp.e1 = binExp.e1.resolveLoc(loc, sc); + binExp.e2 = binExp.e2.resolveLoc(loc, sc); + return binExp; + } if (auto unaExp = exp.isUnaExp()) { unaExp.e1 = unaExp.e1.resolveLoc(loc, sc); @@ -15059,10 +15111,121 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc) return exp; } + Expression visitCond(CondExp exp) + { + exp.e1 = exp.e1.resolveLoc(loc, sc); + exp.e2 = exp.e2.resolveLoc(loc, sc); + exp.econd = exp.econd.resolveLoc(loc, sc); + return exp; + } + Expression visitCat(CatExp exp) { exp.e1 = exp.e1.resolveLoc(loc, sc); exp.e2 = exp.e2.resolveLoc(loc, sc); + if (exp.lowering) + exp.lowering = exp.lowering.resolveLoc(loc, sc); + return exp; + } + + Expression visitStructLiteral(StructLiteralExp exp) + { + foreach (ref element; *exp.elements) + { + if (element) + element = element.resolveLoc(loc, sc); + } + + return exp; + } + + Expression visitNew(NewExp exp) + { + if (exp.thisexp) + exp.thisexp = exp.thisexp.resolveLoc(loc, sc); + if (exp.argprefix) + exp.argprefix = exp.argprefix.resolveLoc(loc, sc); + if (exp.lowering) + exp.lowering = exp.lowering.resolveLoc(loc, sc); + + foreach (ref element; *exp.arguments) + { + if (element) + element = element.resolveLoc(loc, sc); + } + + return exp; + } + + Expression visitCall(CallExp exp) + { + foreach (ref element; *exp.arguments) + { + if (element) + element = element.resolveLoc(loc, sc); + } + + return exp; + } + + Expression visitArray(ArrayExp exp) + { + exp.e1 = exp.e1.resolveLoc(loc, sc); + + foreach (ref element; *exp.arguments) + { + if (element) + element = element.resolveLoc(loc, sc); + } + + return exp; + } + + Expression visitSlice(SliceExp exp) + { + exp.e1 = exp.e1.resolveLoc(loc, sc); + exp.lwr = exp.lwr.resolveLoc(loc, sc); + exp.upr = exp.upr.resolveLoc(loc, sc); + + return exp; + } + + Expression visitInterval(IntervalExp exp) + { + exp.lwr = exp.lwr.resolveLoc(loc, sc); + exp.upr = exp.upr.resolveLoc(loc, sc); + + return exp; + } + + Expression visitArrayLiteral(ArrayLiteralExp exp) + { + if (exp.basis) + exp.basis = exp.basis.resolveLoc(loc, sc); + + foreach (ref element; *exp.elements) + { + if (element) + element = element.resolveLoc(loc, sc); + } + + return exp; + } + + Expression visitAssocArrayLiteral(AssocArrayLiteralExp exp) + { + foreach (ref element; *exp.keys) + { + if (element) + element = element.resolveLoc(loc, sc); + } + + foreach (ref element; *exp.values) + { + if (element) + element = element.resolveLoc(loc, sc); + } + return exp; } @@ -15079,20 +15242,20 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc) return e.expressionSemantic(sc); } - Expression visitLineInit(LineInitExp _) + Expression visitLineInit(LineInitExp exp) { Expression e = new IntegerExp(loc, loc.linnum, Type.tint32); return e.expressionSemantic(sc); } - Expression visitModuleInit(ModuleInitExp _) + Expression visitModuleInit(ModuleInitExp exp) { const auto s = (sc.callsc ? sc.callsc : sc)._module.toPrettyChars().toDString(); Expression e = new StringExp(loc, s); return e.expressionSemantic(sc); } - Expression visitFuncInit(FuncInitExp _) + Expression visitFuncInit(FuncInitExp exp) { const(char)* s; if (sc.callsc && sc.callsc.func) @@ -15105,7 +15268,7 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc) return e.expressionSemantic(sc); } - Expression visitPrettyFunc(PrettyFuncInitExp _) + Expression visitPrettyFunc(PrettyFuncInitExp exp) { FuncDeclaration fd = (sc.callsc && sc.callsc.func) ? sc.callsc.func @@ -15133,7 +15296,16 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc) switch(exp.op) { default: return visit(exp); + case EXP.structLiteral: return visitStructLiteral(exp.isStructLiteralExp()); + case EXP.new_: return visitNew(exp.isNewExp()); case EXP.concatenate: return visitCat(exp.isCatExp()); + case EXP.call: return visitCall(exp.isCallExp()); + case EXP.question: return visitCond(exp.isCondExp()); + case EXP.array: return visitArray(exp.isArrayExp()); + case EXP.slice: return visitSlice(exp.isSliceExp()); + case EXP.interval: return visitInterval(exp.isIntervalExp()); + case EXP.arrayLiteral: return visitArrayLiteral(exp.isArrayLiteralExp()); + case EXP.assocArrayLiteral: return visitAssocArrayLiteral(exp.isAssocArrayLiteralExp()); case EXP.file: case EXP.fileFullPath: return visitFileInit(exp.isFileInitExp()); case EXP.line: return visitLineInit(exp.isLineInitExp); @@ -16193,7 +16365,10 @@ Expression getVarExp(EnumMember em, const ref Loc loc, Scope* sc) em.checkDisabled(loc, sc); if (em.depdecl && !em.depdecl._scope) + { em.depdecl._scope = sc; + em.depdecl._scope.setNoFree(); + } em.checkDeprecated(loc, sc); if (em.errors) diff --git a/gcc/d/dmd/file_manager.d b/gcc/d/dmd/file_manager.d index eaef8d5..c696a5c 100644 --- a/gcc/d/dmd/file_manager.d +++ b/gcc/d/dmd/file_manager.d @@ -72,7 +72,7 @@ private struct PathStack final class FileManager { - private StringTable!(const(ubyte)[]) files; + private StringTable!(const(ubyte)[]) files; // contents of files indexed by file name private StringTable!(bool) packageStatus; // check if the package path of the given path exists. The input path is @@ -247,35 +247,37 @@ nothrow: } /** - * Looks up the given filename from the internal file buffer table. - * If the file does not already exist within the table, it will be read from the filesystem. - * If it has been read before, - * - * Returns: the loaded source file if it was found in memory, - * otherwise `null` + * Retrieve the cached contents of the file given by `filename`. + * If the file has not been read before, read it and add the contents + * to the file cache. + * Params: + * filename = the name of the file + * Returns: + * the contents of the file, or `null` if it could not be read or was empty */ - const(ubyte)[] lookup(FileName filename) + const(ubyte)[] getFileContents(FileName filename) { const name = filename.toString; - if (auto val = files.lookup(name)) - return val.value; + if (auto val = files.lookup(name)) // if `name` is cached + return val.value; // return its contents - if (name == "__stdin.d") + if (name == "__stdin.d") // special name for reading from stdin { - auto buffer = readFromStdin().extractSlice(); + const ubyte[] buffer = readFromStdin().extractSlice(); if (this.files.insert(name, buffer) is null) + // this.files already contains the name assert(0, "stdin: Insert after lookup failure should never return `null`"); return buffer; } - if (FileName.exists(name) != 1) + if (FileName.exists(name) != 1) // if not an ordinary file return null; auto readResult = File.read(name); if (!readResult.success) return null; - auto fb = readResult.extractSlice(); + const ubyte[] fb = readResult.extractSlice(); if (files.insert(name, fb) is null) assert(0, "Insert after lookup failure should never return `null`"); diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d index 242b4dc..370da6f 100644 --- a/gcc/d/dmd/func.d +++ b/gcc/d/dmd/func.d @@ -1195,7 +1195,7 @@ extern (C++) class FuncDeclaration : Declaration * * Returns: the `LabelDsymbol` for `ident` */ - final LabelDsymbol searchLabel(Identifier ident, const ref Loc loc = Loc.initial) + final LabelDsymbol searchLabel(Identifier ident, const ref Loc loc) { Dsymbol s; if (!labtab) @@ -1471,6 +1471,9 @@ extern (C++) class FuncDeclaration : Declaration final PURE isPure() { //printf("FuncDeclaration::isPure() '%s'\n", toChars()); + + import dmd.typesem : purityLevel; + TypeFunction tf = type.toTypeFunction(); if (purityInprocess) setImpure(); @@ -1782,6 +1785,7 @@ extern (C++) class FuncDeclaration : Declaration case Tstruct: /* Drill down and check the struct's fields */ + import dmd.typesem : toDsymbol; auto sym = t.toDsymbol(null).isStructDeclaration(); const tName = t.toChars.toDString; const entry = parentTypes.insert(tName, t); @@ -1863,6 +1867,7 @@ extern (C++) class FuncDeclaration : Declaration case Tstruct: /* Drill down and check the struct's fields */ + import dmd.typesem : toDsymbol; auto sym = tp.toDsymbol(null).isStructDeclaration(); foreach (v; sym.fields) { @@ -2727,6 +2732,7 @@ extern (C++) class FuncDeclaration : Declaration { Type t1 = fdv.type.nextOf().toBasetype(); Type t2 = this.type.nextOf().toBasetype(); + import dmd.typesem : isBaseOf; if (t1.isBaseOf(t2, null)) { /* Making temporary reference variable is necessary @@ -3294,7 +3300,7 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, printf("\tfnames: %s\n", fnames ? fnames.toChars() : "null"); } - if (tiargs && arrayObjectIsError(tiargs)) + if (tiargs && arrayObjectIsError(*tiargs)) return null; if (fargs !is null) foreach (arg; *fargs) @@ -3441,17 +3447,20 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, return null; } - const(char)* failMessage; - functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &failMessage); - if (failMessage) + bool calledHelper; + void errorHelper(const(char)* failMessage) scope { .error(loc, "%s `%s%s%s` is not callable using argument types `%s`", fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList), tf.modToChars(), fargsBuf.peekChars()); errorSupplemental(loc, failMessage); - return null; + calledHelper = true; } + functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &errorHelper); + if (calledHelper) + return null; + if (fd.isCtorDeclaration()) .error(loc, "%s%s `%s` cannot construct a %sobject", funcBuf.peekChars(), fd.kind(), fd.toPrettyChars(), thisBuf.peekChars()); @@ -3505,10 +3514,13 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, } } } - const(char)* failMessage; - functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &failMessage); - if (failMessage) + + void errorHelper2(const(char)* failMessage) scope + { errorSupplemental(loc, failMessage); + } + + functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &errorHelper2); } return null; } @@ -3624,6 +3636,7 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration)) */ Type getIndirection(Type t) { + import dmd.typesem : hasPointers; t = t.baseElemOf(); if (t.ty == Tarray || t.ty == Tpointer) return t.nextOf().toBasetype(); @@ -3670,6 +3683,7 @@ private bool traverseIndirections(Type ta, Type tb) static bool traverse(Type ta, Type tb, ref scope AssocArray!(const(char)*, bool) table, bool reversePass) { + import dmd.typesem : hasPointers; //printf("traverse(%s, %s)\n", ta.toChars(), tb.toChars()); ta = ta.baseElemOf(); tb = tb.baseElemOf(); @@ -3706,6 +3720,7 @@ private bool traverseIndirections(Type ta, Type tb) else *found = true; + import dmd.typesem : toDsymbol; AggregateDeclaration sym = tb.toDsymbol(null).isAggregateDeclaration(); foreach (v; sym.fields) { diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d index b60a3f8..e9e73e8 100644 --- a/gcc/d/dmd/globals.d +++ b/gcc/d/dmd/globals.d @@ -15,7 +15,9 @@ import core.stdc.stdio; import core.stdc.stdint; import core.stdc.string; +import dmd.astenums; import dmd.root.array; +import dmd.root.file; import dmd.root.filename; import dmd.common.outbuffer; import dmd.errorsink; @@ -308,7 +310,7 @@ extern (C++) struct Global ErrorSink errorSink; /// where the error messages go ErrorSink errorSinkNull; /// where the error messages are ignored - extern (C++) FileName function(FileName, ref const Loc, out bool, OutBuffer*) preprocess; + extern (C++) DArray!ubyte function(FileName, ref const Loc, ref OutBuffer) preprocess; nothrow: diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h index c71d2f0..93e7c64 100644 --- a/gcc/d/dmd/globals.h +++ b/gcc/d/dmd/globals.h @@ -307,7 +307,7 @@ struct Global ErrorSink* errorSink; // where the error messages go ErrorSink* errorSinkNull; // where the error messages disappear - FileName (*preprocess)(FileName, const Loc&, bool&, OutBuffer&); + DArray<unsigned char> (*preprocess)(FileName, const Loc&, OutBuffer&); /* Start gagging. Return the current number of gagged errors */ diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d index 4c741cd..3d88a1d 100644 --- a/gcc/d/dmd/mtype.d +++ b/gcc/d/dmd/mtype.d @@ -21,16 +21,11 @@ import dmd.aggregate; import dmd.arraytypes; import dmd.astenums; import dmd.ast_node; -import dmd.gluelayer; import dmd.dclass; -import dmd.dcast; import dmd.declaration; import dmd.denum; -import dmd.dmangle; -import dmd.dscope; import dmd.dstruct; import dmd.dsymbol; -import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; import dmd.expression; @@ -39,9 +34,7 @@ import dmd.globals; import dmd.hdrgen; import dmd.id; import dmd.identifier; -import dmd.init; import dmd.location; -import dmd.opover; import dmd.root.ctfloat; import dmd.common.outbuffer; import dmd.root.rmem; @@ -256,57 +249,6 @@ bool isSomeChar(TY ty) pure nothrow @nogc @safe return ty == Tchar || ty == Twchar || ty == Tdchar; } -/************************************ - * Determine mutability of indirections in (ref) t. - * - * Returns: When the type has any mutable indirections, returns 0. - * When all indirections are immutable, returns 2. - * Otherwise, when the type has const/inout indirections, returns 1. - * - * Params: - * isref = if true, check `ref t`; otherwise, check just `t` - * t = the type that is being checked - */ -int mutabilityOfType(bool isref, Type t) -{ - if (isref) - { - if (t.mod & MODFlags.immutable_) - return 2; - if (t.mod & (MODFlags.const_ | MODFlags.wild)) - return 1; - return 0; - } - - t = t.baseElemOf(); - - if (!t.hasPointers() || t.mod & MODFlags.immutable_) - return 2; - - /* Accept immutable(T)[] and immutable(T)* as being strongly pure - */ - if (t.ty == Tarray || t.ty == Tpointer) - { - Type tn = t.nextOf().toBasetype(); - if (tn.mod & MODFlags.immutable_) - return 2; - if (tn.mod & (MODFlags.const_ | MODFlags.wild)) - return 1; - } - - /* The rest of this is too strict; fix later. - * For example, the only pointer members of a struct may be immutable, - * which would maintain strong purity. - * (Just like for dynamic arrays and pointers above.) - */ - if (t.mod & (MODFlags.const_ | MODFlags.wild)) - return 1; - - /* Should catch delegates and function pointers, and fold in their purity - */ - return 0; -} - /**************** * dotExp() bit flags */ @@ -363,7 +305,7 @@ extern (C++) abstract class Type : ASTNode TypeInfoDeclaration vtinfo; // TypeInfo object for this Type - type* ctype; // for back end + void* ctype; // for back end extern (C++) __gshared Type tvoid; extern (C++) __gshared Type tint8; @@ -659,31 +601,6 @@ extern (C++) abstract class Type : ASTNode return cast(uint)size(Loc.initial); } - final Type trySemantic(const ref Loc loc, Scope* sc) - { - //printf("+trySemantic(%s) %d\n", toChars(), global.errors); - - // Needed to display any deprecations that were gagged - auto tcopy = this.syntaxCopy(); - - const errors = global.startGagging(); - Type t = typeSemantic(this, loc, sc); - if (global.endGagging(errors) || t.ty == Terror) // if any errors happened - { - t = null; - } - else - { - // If `typeSemantic` succeeded, there may have been deprecations that - // were gagged due the `startGagging` above. Run again to display - // those deprecations. https://issues.dlang.org/show_bug.cgi?id=19107 - if (global.gaggedWarnings > 0) - typeSemantic(tcopy, loc, sc); - } - //printf("-trySemantic(%s) %d\n", toChars(), global.errors); - return t; - } - /************************************* * This version does a merge even if the deco is already computed. * Necessary for types that have a deco, but are not merged. @@ -1907,11 +1824,6 @@ extern (C++) abstract class Type : ASTNode return t; } - Dsymbol toDsymbol(Scope* sc) - { - return null; - } - /******************************* * If this is a shell around another type, * get that other type. @@ -1925,11 +1837,6 @@ extern (C++) abstract class Type : ASTNode return ((te = isTypeEnum()) !is null) ? te.toBasetype2() : this; } - bool isBaseOf(Type t, int* poffset) - { - return 0; // assume not - } - /******************************** * Determine if 'this' can be implicitly converted * to type 'to'. @@ -2155,32 +2062,6 @@ extern (C++) abstract class Type : ASTNode return false; // assume not } - final Identifier getTypeInfoIdent() - { - // _init_10TypeInfo_%s - OutBuffer buf; - buf.reserve(32); - mangleToBuffer(this, buf); - - const slice = buf[]; - - // Allocate buffer on stack, fail over to using malloc() - char[128] namebuf; - const namelen = 19 + size_t.sizeof * 3 + slice.length + 1; - auto name = namelen <= namebuf.length ? namebuf.ptr : cast(char*)Mem.check(malloc(namelen)); - - const length = snprintf(name, namelen, "_D%lluTypeInfo_%.*s6__initZ", - cast(ulong)(9 + slice.length), cast(int)slice.length, slice.ptr); - //printf("%p %s, deco = %s, name = %s\n", this, toChars(), deco, name); - assert(0 < length && length < namelen); // don't overflow the buffer - - auto id = Identifier.idPool(name[0 .. length]); - - if (name != namebuf.ptr) - free(name); - return id; - } - /*************************************** * Return !=0 if the type or any of its subtypes is wild. */ @@ -2189,16 +2070,6 @@ extern (C++) abstract class Type : ASTNode return mod & MODFlags.wild; } - /*************************************** - * Return !=0 if type has pointers that need to - * be scanned by the GC during a collection cycle. - */ - bool hasPointers() - { - //printf("Type::hasPointers() %s, %d\n", toChars(), ty); - return false; - } - /************************************* * Detect if type has pointer fields that are initialized to void. * Local stack variables with such void fields can remain uninitialized, @@ -2340,76 +2211,6 @@ extern (C++) abstract class Type : ASTNode return false; } - /************************************* - * https://issues.dlang.org/show_bug.cgi?id=14488 - * Check if the inner most base type is complex or imaginary. - * Should only give alerts when set to emit transitional messages. - * Params: - * loc = The source location. - * sc = scope of the type - */ - extern (D) final bool checkComplexTransition(const ref Loc loc, Scope* sc) - { - if (sc.isDeprecated()) - return false; - // Don't complain if we're inside a template constraint - // https://issues.dlang.org/show_bug.cgi?id=21831 - if (sc.flags & SCOPE.constraint) - return false; - - Type t = baseElemOf(); - while (t.ty == Tpointer || t.ty == Tarray) - t = t.nextOf().baseElemOf(); - - // Basetype is an opaque enum, nothing to check. - if (t.ty == Tenum && !(cast(TypeEnum)t).sym.memtype) - return false; - - if (t.isimaginary() || t.iscomplex()) - { - if (sc.flags & SCOPE.Cfile) - return true; // complex/imaginary not deprecated in C code - Type rt; - switch (t.ty) - { - case Tcomplex32: - case Timaginary32: - rt = Type.tfloat32; - break; - - case Tcomplex64: - case Timaginary64: - rt = Type.tfloat64; - break; - - case Tcomplex80: - case Timaginary80: - rt = Type.tfloat80; - break; - - default: - assert(0); - } - // @@@DEPRECATED_2.117@@@ - // Deprecated in 2.097 - Can be made an error from 2.117. - // The deprecation period is longer than usual as `cfloat`, - // `cdouble`, and `creal` were quite widely used. - if (t.iscomplex()) - { - deprecation(loc, "use of complex type `%s` is deprecated, use `std.complex.Complex!(%s)` instead", - toChars(), rt.toChars()); - return true; - } - else - { - deprecation(loc, "use of imaginary type `%s` is deprecated, use `%s` instead", - toChars(), rt.toChars()); - return true; - } - } - return false; - } - // For eliminating dynamic_cast TypeBasic isTypeBasic() { @@ -3531,24 +3332,6 @@ extern (C++) final class TypeSArray : TypeArray return ae; } - override bool hasPointers() - { - /* Don't want to do this, because: - * struct S { T* array[0]; } - * may be a variable length struct. - */ - //if (dim.toInteger() == 0) - // return false; - - if (next.ty == Tvoid) - { - // Arrays of void contain arbitrary data, which may include pointers - return true; - } - else - return next.hasPointers(); - } - override bool hasSystemFields() { return next.hasSystemFields(); @@ -3673,11 +3456,6 @@ extern (C++) final class TypeDArray : TypeArray return Type.implicitConvTo(to); } - override bool hasPointers() - { - return true; - } - override void accept(Visitor v) { v.visit(this); @@ -3734,11 +3512,6 @@ extern (C++) final class TypeAArray : TypeArray return true; } - override bool hasPointers() - { - return true; - } - override MATCH implicitConvTo(Type to) { //printf("TypeAArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars()); @@ -3877,11 +3650,6 @@ extern (C++) final class TypePointer : TypeNext return true; } - override bool hasPointers() - { - return true; - } - override void accept(Visitor v) { v.visit(this); @@ -4059,39 +3827,6 @@ extern (C++) final class TypeFunction : TypeNext } /******************************************** - * Set 'purity' field of 'this'. - * Do this lazily, as the parameter types might be forward referenced. - */ - void purityLevel() - { - TypeFunction tf = this; - if (tf.purity != PURE.fwdref) - return; - - purity = PURE.const_; // assume strong until something weakens it - - /* Evaluate what kind of purity based on the modifiers for the parameters - */ - foreach (i, fparam; tf.parameterList) - { - Type t = fparam.type; - if (!t) - continue; - - if (fparam.storageClass & (STC.lazy_ | STC.out_)) - { - purity = PURE.weak; - break; - } - const pref = (fparam.storageClass & STC.ref_) != 0; - if (mutabilityOfType(pref, t) == 0) - purity = PURE.weak; - } - - tf.purity = purity; - } - - /******************************************** * Return true if there are lazy parameters. */ bool hasLazyParameters() @@ -4115,122 +3850,6 @@ extern (C++) final class TypeFunction : TypeNext return linkage == LINK.d && parameterList.varargs == VarArg.variadic; } - /************************************ - * Take the specified storage class for p, - * and use the function signature to infer whether - * STC.scope_ and STC.return_ should be OR'd in. - * (This will not affect the name mangling.) - * Params: - * tthis = type of `this` parameter, null if none - * p = parameter to this function - * outerVars = context variables p could escape into, if any - * indirect = is this for an indirect or virtual function call? - * Returns: - * storage class with STC.scope_ or STC.return_ OR'd in - */ - StorageClass parameterStorageClass(Type tthis, Parameter p, VarDeclarations* outerVars = null, - bool indirect = false) - { - //printf("parameterStorageClass(p: %s)\n", p.toChars()); - auto stc = p.storageClass; - - // When the preview switch is enable, `in` parameters are `scope` - if (stc & STC.constscoperef) - return stc | STC.scope_; - - if (stc & (STC.scope_ | STC.return_ | STC.lazy_) || purity == PURE.impure) - return stc; - - /* If haven't inferred the return type yet, can't infer storage classes - */ - if (!nextOf() || !isnothrow()) - return stc; - - purityLevel(); - - static bool mayHavePointers(Type t) - { - if (auto ts = t.isTypeStruct()) - { - auto sym = ts.sym; - if (sym.members && !sym.determineFields() && sym.type != Type.terror) - // struct is forward referenced, so "may have" pointers - return true; - } - return t.hasPointers(); - } - - // See if p can escape via any of the other parameters - if (purity == PURE.weak) - { - /* - * Indirect calls may escape p through a nested context - * See: - * https://issues.dlang.org/show_bug.cgi?id=24212 - * https://issues.dlang.org/show_bug.cgi?id=24213 - */ - if (indirect) - return stc; - - // Check escaping through parameters - foreach (i, fparam; parameterList) - { - Type t = fparam.type; - if (!t) - continue; - t = t.baseElemOf(); // punch thru static arrays - if (t.isMutable() && t.hasPointers()) - { - if (fparam.isReference() && fparam != p) - return stc; - - if (t.ty == Tdelegate) - return stc; // could escape thru delegate - - if (t.ty == Tclass) - return stc; - - /* if t is a pointer to mutable pointer - */ - if (auto tn = t.nextOf()) - { - if (tn.isMutable() && mayHavePointers(tn)) - return stc; // escape through pointers - } - } - } - - // Check escaping through `this` - if (tthis && tthis.isMutable()) - { - foreach (VarDeclaration v; isAggregate(tthis).fields) - { - if (v.hasPointers()) - return stc; - } - } - - // Check escaping through nested context - if (outerVars && this.isMutable()) - { - foreach (VarDeclaration v; *outerVars) - { - if (v.hasPointers()) - return stc; - } - } - } - - // Check escaping through return value - Type tret = nextOf().toBasetype(); - if (isref || tret.hasPointers()) - { - return stc | STC.scope_ | STC.return_ | STC.returnScope; - } - else - return stc | STC.scope_; - } - override Type addStorageClass(StorageClass stc) { //printf("addStorageClass(%llx) %d\n", stc, (stc & STC.scope_) != 0); @@ -4631,11 +4250,6 @@ extern (C++) final class TypeDelegate : TypeNext return true; } - override bool hasPointers() - { - return true; - } - override void accept(Visitor v) { v.visit(this); @@ -4676,20 +4290,6 @@ extern (C++) final class TypeTraits : Type return tt; } - override Dsymbol toDsymbol(Scope* sc) - { - Type t; - Expression e; - Dsymbol s; - resolve(this, loc, sc, e, t, s); - if (t && t.ty != Terror) - s = t.toDsymbol(sc); - else if (e) - s = getDsymbol(e); - - return s; - } - override void accept(Visitor v) { v.visit(this); @@ -4729,20 +4329,6 @@ extern (C++) final class TypeMixin : Type return new TypeMixin(loc, Expression.arraySyntaxCopy(exps)); } - override Dsymbol toDsymbol(Scope* sc) - { - Type t; - Expression e; - Dsymbol s; - resolve(this, loc, sc, e, t, s); - if (t) - s = t.toDsymbol(sc); - else if (e) - s = getDsymbol(e); - - return s; - } - override void accept(Visitor v) { v.visit(this); @@ -4867,28 +4453,6 @@ extern (C++) final class TypeIdentifier : TypeQualified return t; } - /***************************************** - * See if type resolves to a symbol, if so, - * return that symbol. - */ - override Dsymbol toDsymbol(Scope* sc) - { - //printf("TypeIdentifier::toDsymbol('%s')\n", toChars()); - if (!sc) - return null; - - Type t; - Expression e; - Dsymbol s; - resolve(this, loc, sc, e, t, s); - if (t && t.ty != Tident) - s = t.toDsymbol(sc); - if (e) - s = getDsymbol(e); - - return s; - } - override void accept(Visitor v) { v.visit(this); @@ -4922,18 +4486,6 @@ extern (C++) final class TypeInstance : TypeQualified return t; } - override Dsymbol toDsymbol(Scope* sc) - { - Type t; - Expression e; - Dsymbol s; - //printf("TypeInstance::semantic(%s)\n", toChars()); - resolve(this, loc, sc, e, t, s); - if (t && t.ty != Tinstance) - s = t.toDsymbol(sc); - return s; - } - override void accept(Visitor v) { v.visit(this); @@ -4967,16 +4519,6 @@ extern (C++) final class TypeTypeof : TypeQualified return t; } - override Dsymbol toDsymbol(Scope* sc) - { - //printf("TypeTypeof::toDsymbol('%s')\n", toChars()); - Expression e; - Type t; - Dsymbol s; - resolve(this, loc, sc, e, t, s); - return s; - } - override uinteger_t size(const ref Loc loc) { if (exp.type) @@ -5013,15 +4555,6 @@ extern (C++) final class TypeReturn : TypeQualified return t; } - override Dsymbol toDsymbol(Scope* sc) - { - Expression e; - Type t; - Dsymbol s; - resolve(this, loc, sc, e, t, s); - return s; - } - override void accept(Visitor v) { v.visit(this); @@ -5068,11 +4601,6 @@ extern (C++) final class TypeStruct : Type return this; } - override Dsymbol toDsymbol(Scope* sc) - { - return sym; - } - override structalign_t alignment() { if (sym.alignment.isUnknown()) @@ -5214,15 +4742,6 @@ extern (C++) final class TypeStruct : Type return false; } - override bool hasPointers() - { - if (sym.members && !sym.determineFields() && sym.type != Type.terror) - error(sym.loc, "no size because of forward references"); - - sym.determineTypeProperties(); - return sym.hasPointerField; - } - override bool hasVoidInitPointers() { sym.size(Loc.initial); // give error for forward references @@ -5393,9 +4912,9 @@ extern (C++) final class TypeEnum : Type return sym.getMemtype(loc).size(loc); } - Type memType(const ref Loc loc = Loc.initial) + Type memType() { - return sym.getMemtype(loc); + return sym.getMemtype(Loc.initial); } override uint alignsize() @@ -5406,11 +4925,6 @@ extern (C++) final class TypeEnum : Type return t.alignsize(); } - override Dsymbol toDsymbol(Scope* sc) - { - return sym; - } - override bool isintegral() { return memType().isintegral(); @@ -5511,11 +5025,6 @@ extern (C++) final class TypeEnum : Type return sym.getDefaultValue(loc).toBool().hasValue(false); } - override bool hasPointers() - { - return memType().hasPointers(); - } - override bool hasVoidInitPointers() { return memType().hasVoidInitPointers(); @@ -5571,44 +5080,14 @@ extern (C++) final class TypeClass : Type return this; } - override Dsymbol toDsymbol(Scope* sc) - { - return sym; - } - override inout(ClassDeclaration) isClassHandle() inout { return sym; } - override bool isBaseOf(Type t, int* poffset) - { - if (t && t.ty == Tclass) - { - ClassDeclaration cd = (cast(TypeClass)t).sym; - if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete()) - cd.dsymbolSemantic(null); - if (sym.semanticRun < PASS.semanticdone && !sym.isBaseInfoComplete()) - sym.dsymbolSemantic(null); - - if (sym.isBaseOf(cd, poffset)) - return true; - } - return false; - } - extern (D) MATCH implicitConvToWithoutAliasThis(Type to) { - // Run semantic before checking whether class is convertible ClassDeclaration cdto = to.isClassHandle(); - if (cdto) - { - //printf("TypeClass::implicitConvTo(to = '%s') %s, isbase = %d %d\n", to.toChars(), toChars(), cdto.isBaseInfoComplete(), sym.isBaseInfoComplete()); - if (cdto.semanticRun < PASS.semanticdone && !cdto.isBaseInfoComplete()) - cdto.dsymbolSemantic(null); - if (sym.semanticRun < PASS.semanticdone && !sym.isBaseInfoComplete()) - sym.dsymbolSemantic(null); - } MATCH m = constConv(to); if (m > MATCH.nomatch) return m; @@ -5706,11 +5185,6 @@ extern (C++) final class TypeClass : Type return true; } - override bool hasPointers() - { - return true; - } - override void accept(Visitor v) { v.visit(this); @@ -5952,14 +5426,6 @@ extern (C++) final class TypeNull : Type return MATCH.nomatch; } - override bool hasPointers() - { - /* Although null isn't dereferencable, treat it as a pointer type for - * attribute inference, generic code, etc. - */ - return true; - } - override bool isBoolean() { return true; @@ -6633,39 +6099,6 @@ bool isIndexableNonAggregate(Type t) t.ty == Ttuple || t.ty == Tvector); } -/*************************************************** - * Determine if type t is copyable. - * Params: - * t = type to check - * Returns: - * true if we can copy it - */ -bool isCopyable(Type t) -{ - //printf("isCopyable() %s\n", t.toChars()); - if (auto ts = t.isTypeStruct()) - { - if (ts.sym.postblit && - ts.sym.postblit.storage_class & STC.disable) - return false; - if (ts.sym.hasCopyCtor) - { - // check if there is a matching overload of the copy constructor and whether it is disabled or not - // `assert(ctor)` fails on Win32 and Win_32_64. See: https://auto-tester.puremagic.com/pull-history.ghtml?projectid=1&repoid=1&pullid=10575 - Dsymbol ctor = search_function(ts.sym, Id.ctor); - assert(ctor); - scope el = new IdentifierExp(Loc.initial, Id.p); // dummy lvalue - el.type = cast() ts; - Expressions* args = new Expressions(); - args.push(el); - FuncDeclaration f = resolveFuncCall(Loc.initial, null, ctor, null, cast()ts, ArgumentList(args), FuncResolveFlag.quiet); - if (!f || f.storage_class & STC.disable) - return false; - } - } - return true; -} - /*************************************** * Computes how a parameter may be returned. * Shrinking the representation is necessary because StorageClass is so wide diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h index 97a7ae3..c777f35 100644 --- a/gcc/d/dmd/mtype.h +++ b/gcc/d/dmd/mtype.h @@ -233,7 +233,6 @@ public: uinteger_t size(); virtual uinteger_t size(const Loc &loc); virtual unsigned alignsize(); - Type *trySemantic(const Loc &loc, Scope *sc); Type *merge2(); void modToBuffer(OutBuffer& buf) const; char *modToChars() const; @@ -287,9 +286,7 @@ public: virtual Type *makeSharedWild(); virtual Type *makeSharedWildConst(); virtual Type *makeMutable(); - virtual Dsymbol *toDsymbol(Scope *sc); Type *toBasetype(); - virtual bool isBaseOf(Type *t, int *poffset); virtual MATCH implicitConvTo(Type *to); virtual MATCH constConv(Type *to); virtual unsigned char deduceWild(Type *t, bool isRef); @@ -302,9 +299,7 @@ public: virtual structalign_t alignment(); virtual Expression *defaultInitLiteral(const Loc &loc); virtual bool isZeroInit(const Loc &loc = Loc()); // if initializer is 0 - Identifier *getTypeInfoIdent(); virtual int hasWild() const; - virtual bool hasPointers(); virtual bool hasVoidInitPointers(); virtual bool hasSystemFields(); virtual bool hasInvariant(); @@ -451,7 +446,6 @@ public: MATCH constConv(Type *to) override; MATCH implicitConvTo(Type *to) override; Expression *defaultInitLiteral(const Loc &loc) override; - bool hasPointers() override; bool hasSystemFields() override; bool hasVoidInitPointers() override; bool hasInvariant() override; @@ -474,7 +468,6 @@ public: bool isZeroInit(const Loc &loc) override; bool isBoolean() override; MATCH implicitConvTo(Type *to) override; - bool hasPointers() override; void accept(Visitor *v) override { v->visit(this); } }; @@ -491,7 +484,6 @@ public: uinteger_t size(const Loc &loc) override; bool isZeroInit(const Loc &loc) override; bool isBoolean() override; - bool hasPointers() override; MATCH implicitConvTo(Type *to) override; MATCH constConv(Type *to) override; @@ -509,7 +501,6 @@ public: MATCH constConv(Type *to) override; bool isscalar() override; bool isZeroInit(const Loc &loc) override; - bool hasPointers() override; void accept(Visitor *v) override { v->visit(this); } }; @@ -605,10 +596,8 @@ public: static TypeFunction *create(Parameters *parameters, Type *treturn, VarArg varargs, LINK linkage, StorageClass stc = 0); const char *kind() override; TypeFunction *syntaxCopy() override; - void purityLevel(); bool hasLazyParameters(); bool isDstyleVariadic() const; - StorageClass parameterStorageClass(Type* tthis, Parameter *p, VarDeclarations* outerVars = nullptr, bool indirect = false); Type *addStorageClass(StorageClass stc) override; Type *substWildTo(unsigned mod) override; @@ -659,7 +648,6 @@ public: MATCH implicitConvTo(Type *to) override; bool isZeroInit(const Loc &loc) override; bool isBoolean() override; - bool hasPointers() override; void accept(Visitor *v) override { v->visit(this); } }; @@ -675,7 +663,6 @@ class TypeTraits final : public Type const char *kind() override; TypeTraits *syntaxCopy() override; uinteger_t size(const Loc &loc) override; - Dsymbol *toDsymbol(Scope *sc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -687,7 +674,6 @@ class TypeMixin final : public Type const char *kind() override; TypeMixin *syntaxCopy() override; - Dsymbol *toDsymbol(Scope *sc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -713,7 +699,6 @@ public: static TypeIdentifier *create(const Loc &loc, Identifier *ident); const char *kind() override; TypeIdentifier *syntaxCopy() override; - Dsymbol *toDsymbol(Scope *sc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -726,7 +711,6 @@ public: const char *kind() override; TypeInstance *syntaxCopy() override; - Dsymbol *toDsymbol(Scope *sc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -738,7 +722,6 @@ public: const char *kind() override; TypeTypeof *syntaxCopy() override; - Dsymbol *toDsymbol(Scope *sc) override; uinteger_t size(const Loc &loc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -748,7 +731,6 @@ class TypeReturn final : public TypeQualified public: const char *kind() override; TypeReturn *syntaxCopy() override; - Dsymbol *toDsymbol(Scope *sc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -776,7 +758,6 @@ public: uinteger_t size(const Loc &loc) override; unsigned alignsize() override; TypeStruct *syntaxCopy() override; - Dsymbol *toDsymbol(Scope *sc) override; structalign_t alignment() override; Expression *defaultInitLiteral(const Loc &loc) override; bool isZeroInit(const Loc &loc) override; @@ -785,7 +766,6 @@ public: bool needsDestruction() override; bool needsCopyOrPostblit() override; bool needsNested() override; - bool hasPointers() override; bool hasVoidInitPointers() override; bool hasSystemFields() override; bool hasInvariant() override; @@ -806,8 +786,7 @@ public: TypeEnum *syntaxCopy() override; uinteger_t size(const Loc &loc) override; unsigned alignsize() override; - Type *memType(const Loc &loc = Loc()); - Dsymbol *toDsymbol(Scope *sc) override; + Type *memType(const Loc &loc); bool isintegral() override; bool isfloating() override; bool isreal() override; @@ -824,7 +803,6 @@ public: MATCH implicitConvTo(Type *to) override; MATCH constConv(Type *to) override; bool isZeroInit(const Loc &loc) override; - bool hasPointers() override; bool hasVoidInitPointers() override; bool hasSystemFields() override; bool hasInvariant() override; @@ -843,9 +821,7 @@ public: const char *kind() override; uinteger_t size(const Loc &loc) override; TypeClass *syntaxCopy() override; - Dsymbol *toDsymbol(Scope *sc) override; ClassDeclaration *isClassHandle() override; - bool isBaseOf(Type *t, int *poffset) override; MATCH implicitConvTo(Type *to) override; MATCH constConv(Type *to) override; unsigned char deduceWild(Type *t, bool isRef) override; @@ -853,7 +829,6 @@ public: bool isZeroInit(const Loc &loc) override; bool isscope() override; bool isBoolean() override; - bool hasPointers() override; void accept(Visitor *v) override { v->visit(this); } }; @@ -894,7 +869,6 @@ public: TypeNull *syntaxCopy() override; MATCH implicitConvTo(Type *to) override; - bool hasPointers() override; bool isBoolean() override; uinteger_t size(const Loc &loc) override; @@ -925,6 +899,13 @@ public: /**************************************************************/ + // If the type is a class or struct, returns the symbol for it, else null. AggregateDeclaration *isAggregate(Type *t); +bool hasPointers(Type *t); +// return the symbol to which type t resolves +Dsymbol *toDsymbol(Type *t, Scope *sc); Covariant covariant(Type *, Type *, StorageClass * = NULL, bool = false); +bool isBaseOf(Type *tthis, Type *t, int *poffset); +Type *trySemantic(Type *type, const Loc &loc, Scope *sc); +void purityLevel(TypeFunction *type); diff --git a/gcc/d/dmd/mustuse.d b/gcc/d/dmd/mustuse.d index b5601a2..c2fa5fb 100644 --- a/gcc/d/dmd/mustuse.d +++ b/gcc/d/dmd/mustuse.d @@ -31,6 +31,7 @@ import dmd.location; bool checkMustUse(Expression e, Scope* sc) { import dmd.id : Id; + import dmd.typesem : toDsymbol; assert(e.type); if (auto sym = e.type.toDsymbol(sc)) diff --git a/gcc/d/dmd/ob.d b/gcc/d/dmd/ob.d index 785912e..0a59815 100644 --- a/gcc/d/dmd/ob.d +++ b/gcc/d/dmd/ob.d @@ -2566,6 +2566,7 @@ void checkObErrors(ref ObState obstate) //printf("%s: ", obstate.vars[i].toChars()); pvs.print(obstate.vars[]); if (pvs.state == PtrState.Owner) { + import dmd.typesem : hasPointers; auto v = obstate.vars[i]; if (v.type.hasPointers()) .error(v.loc, "%s `%s` is not disposed of before return", v.kind, v.toPrettyChars); diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index a012e0c..268622a 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -1675,7 +1675,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (token.value == TOK.assign) // = CondExpression { nextToken(); - tp_defaultvalue = parseDefaultInitExp(); + tp_defaultvalue = parseAssignExp(); } tp = new AST.TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue); } @@ -2969,7 +2969,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (token.value == TOK.assign) // = defaultArg { nextToken(); - ae = parseDefaultInitExp(); + ae = parseAssignExp(); } auto param = new AST.Parameter(loc, storageClass | STC.parameter, at, ai, ae, null); if (udas) @@ -6949,33 +6949,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } } - /***************************************** - * Parses default argument initializer expression that is an assign expression, - * with special handling for __FILE__, __FILE_DIR__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__. - */ - private AST.Expression parseDefaultInitExp() - { - AST.Expression e = null; - const tv = peekNext(); - if (tv == TOK.comma || tv == TOK.rightParenthesis) - { - switch (token.value) - { - case TOK.file: e = new AST.FileInitExp(token.loc, EXP.file); break; - case TOK.fileFullPath: e = new AST.FileInitExp(token.loc, EXP.fileFullPath); break; - case TOK.line: e = new AST.LineInitExp(token.loc); break; - case TOK.moduleString: e = new AST.ModuleInitExp(token.loc); break; - case TOK.functionString: e = new AST.FuncInitExp(token.loc); break; - case TOK.prettyFunction: e = new AST.PrettyFuncInitExp(token.loc); break; - default: goto LExp; - } - nextToken(); - return e; - } - LExp: - return parseAssignExp(); - } - /******************** * Parse inline assembler block. * Enters with token on the `asm`. @@ -8152,33 +8125,23 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer break; case TOK.file: - { - const(char)* s = loc.filename ? loc.filename : mod.ident.toChars(); - e = new AST.StringExp(loc, s.toDString()); - nextToken(); - break; - } + e = new AST.FileInitExp(loc, EXP.file); + nextToken(); + break; case TOK.fileFullPath: - { - assert(loc.isValid(), "__FILE_FULL_PATH__ does not work with an invalid location"); - const s = FileName.toAbsolute(loc.filename); - e = new AST.StringExp(loc, s.toDString()); - nextToken(); - break; - } + e = new AST.FileInitExp(loc, EXP.fileFullPath); + nextToken(); + break; case TOK.line: - e = new AST.IntegerExp(loc, loc.linnum, AST.Type.tint32); + e = new AST.LineInitExp(loc); nextToken(); break; case TOK.moduleString: - { - const(char)* s = md ? md.toChars() : mod.toChars(); - e = new AST.StringExp(loc, s.toDString()); - nextToken(); - break; - } + e = new AST.ModuleInitExp(loc); + nextToken(); + break; case TOK.functionString: e = new AST.FuncInitExp(loc); nextToken(); diff --git a/gcc/d/dmd/safe.d b/gcc/d/dmd/safe.d index af81bff..8b57f7f 100644 --- a/gcc/d/dmd/safe.d +++ b/gcc/d/dmd/safe.d @@ -26,6 +26,7 @@ import dmd.identifier; import dmd.mtype; import dmd.target; import dmd.tokens; +import dmd.typesem : hasPointers; import dmd.func : setUnsafe, setUnsafePreview; /************************************************************* diff --git a/gcc/d/dmd/scope.h b/gcc/d/dmd/scope.h index 1535fd0..4b157cc 100644 --- a/gcc/d/dmd/scope.h +++ b/gcc/d/dmd/scope.h @@ -87,6 +87,7 @@ struct Scope Dsymbol *inunion; // !=null if processing members of a union d_bool nofree; // true if shouldn't free it d_bool inLoop; // true if inside a loop (where constructor calls aren't allowed) + d_bool inDefaultArg; // true if inside a default argument (where __FILE__, etc are evaluated at the call site) int intypeof; // in typeof(exp) VarDeclaration *lastVar; // Previous symbol used to prevent goto-skips-init ErrorSink *eSink; // sink for error messages diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d index 520e05f..174d9b4 100644 --- a/gcc/d/dmd/semantic3.d +++ b/gcc/d/dmd/semantic3.d @@ -231,8 +231,7 @@ private extern(C++) final class Semantic3Visitor : Visitor if (sc.flags & SCOPE.Cfile && funcdecl.isCMain() && f.next.ty == Tint32) return true; - return f.next.ty == Tvoid && - (funcdecl.isMain() || global.params.betterC && funcdecl.isCMain()); + return f.next.ty == Tvoid && (funcdecl.isMain() || funcdecl.isCMain()); } VarDeclaration _arguments = null; @@ -346,6 +345,7 @@ private extern(C++) final class Semantic3Visitor : Visitor sc2.tf = null; sc2.os = null; sc2.inLoop = false; + sc2.inDefaultArg = false; sc2.userAttribDecl = null; if (sc2.intypeof == 1) sc2.intypeof = 2; @@ -570,7 +570,7 @@ private extern(C++) final class Semantic3Visitor : Visitor if ((needEnsure && global.params.useOut == CHECKENABLE.on) || fpostinv) { - funcdecl.returnLabel = funcdecl.searchLabel(Id.returnLabel); + funcdecl.returnLabel = funcdecl.searchLabel(Id.returnLabel, Loc.initial); } // scope of out contract (need for vresult.semantic) diff --git a/gcc/d/dmd/sideeffect.d b/gcc/d/dmd/sideeffect.d index 59398a7..8038770 100644 --- a/gcc/d/dmd/sideeffect.d +++ b/gcc/d/dmd/sideeffect.d @@ -24,6 +24,7 @@ import dmd.init; import dmd.mtype; import dmd.postordervisitor; import dmd.tokens; +import dmd.typesem; import dmd.visitor; /************************************************** diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d index 229cf17..d4827ae 100644 --- a/gcc/d/dmd/statementsem.d +++ b/gcc/d/dmd/statementsem.d @@ -3753,7 +3753,10 @@ public bool throwSemantic(const ref Loc loc, ref Expression exp, Scope* sc) { if (!global.params.useExceptions) { - loc.error("cannot use `throw` statements with %s", global.params.betterC ? "-betterC".ptr : "-nothrow".ptr); + version (IN_GCC) + loc.error("cannot use `throw` statements with `-fno-exceptions`"); + else + loc.error("cannot use `throw` statements with %s", global.params.betterC ? "-betterC".ptr : "-nothrow".ptr); return false; } diff --git a/gcc/d/dmd/template.h b/gcc/d/dmd/template.h index 09c4912..153eb4e 100644 --- a/gcc/d/dmd/template.h +++ b/gcc/d/dmd/template.h @@ -324,4 +324,4 @@ Tuple *isTuple(RootObject *o); Parameter *isParameter(RootObject *o); TemplateParameter *isTemplateParameter(RootObject *o); bool isError(const RootObject *const o); -void printTemplateStats(); +void printTemplateStats(bool listInstances, ErrorSink* eSink); diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index 51b4ef8..714af8a 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -430,6 +430,123 @@ private Dsymbol searchX(Dsymbol dsym, const ref Loc loc, Scope* sc, RootObject i return sm; } +/*************************************************** + * Determine if type t is copyable. + * Params: + * t = type to check + * Returns: + * true if we can copy it + */ +bool isCopyable(Type t) +{ + //printf("isCopyable() %s\n", t.toChars()); + if (auto ts = t.isTypeStruct()) + { + if (ts.sym.postblit && + ts.sym.postblit.storage_class & STC.disable) + return false; + if (ts.sym.hasCopyCtor) + { + // check if there is a matching overload of the copy constructor and whether it is disabled or not + // `assert(ctor)` fails on Win32 and Win_32_64. See: https://auto-tester.puremagic.com/pull-history.ghtml?projectid=1&repoid=1&pullid=10575 + Dsymbol ctor = search_function(ts.sym, Id.ctor); + assert(ctor); + scope el = new IdentifierExp(Loc.initial, Id.p); // dummy lvalue + el.type = cast() ts; + Expressions* args = new Expressions(); + args.push(el); + FuncDeclaration f = resolveFuncCall(Loc.initial, null, ctor, null, cast()ts, ArgumentList(args), FuncResolveFlag.quiet); + if (!f || f.storage_class & STC.disable) + return false; + } + } + return true; +} + +/************************************ + * Determine mutability of indirections in (ref) t. + * + * Returns: When the type has any mutable indirections, returns 0. + * When all indirections are immutable, returns 2. + * Otherwise, when the type has const/inout indirections, returns 1. + * + * Params: + * isref = if true, check `ref t`; otherwise, check just `t` + * t = the type that is being checked + */ +int mutabilityOfType(bool isref, Type t) +{ + if (isref) + { + if (t.mod & MODFlags.immutable_) + return 2; + if (t.mod & (MODFlags.const_ | MODFlags.wild)) + return 1; + return 0; + } + + t = t.baseElemOf(); + + if (!t.hasPointers() || t.mod & MODFlags.immutable_) + return 2; + + /* Accept immutable(T)[] and immutable(T)* as being strongly pure + */ + if (t.ty == Tarray || t.ty == Tpointer) + { + Type tn = t.nextOf().toBasetype(); + if (tn.mod & MODFlags.immutable_) + return 2; + if (tn.mod & (MODFlags.const_ | MODFlags.wild)) + return 1; + } + + /* The rest of this is too strict; fix later. + * For example, the only pointer members of a struct may be immutable, + * which would maintain strong purity. + * (Just like for dynamic arrays and pointers above.) + */ + if (t.mod & (MODFlags.const_ | MODFlags.wild)) + return 1; + + /* Should catch delegates and function pointers, and fold in their purity + */ + return 0; +} + +/******************************************** + * Set 'purity' field of 'typeFunction'. + * Do this lazily, as the parameter types might be forward referenced. + */ +extern(C++) void purityLevel(TypeFunction typeFunction) +{ + TypeFunction tf = typeFunction; + if (tf.purity != PURE.fwdref) + return; + + typeFunction.purity = PURE.const_; // assume strong until something weakens it + + /* Evaluate what kind of purity based on the modifiers for the parameters + */ + foreach (i, fparam; tf.parameterList) + { + Type t = fparam.type; + if (!t) + continue; + + if (fparam.storageClass & (STC.lazy_ | STC.out_)) + { + typeFunction.purity = PURE.weak; + break; + } + const pref = (fparam.storageClass & STC.ref_) != 0; + if (mutabilityOfType(pref, t) == 0) + typeFunction.purity = PURE.weak; + } + + tf.purity = typeFunction.purity; +} + /****************************************** * We've mistakenly parsed `t` as a type. * Redo `t` as an Expression only if there are no type modifiers. @@ -486,6 +603,77 @@ Expression typeToExpression(Type t) } } +/************************************* + * https://issues.dlang.org/show_bug.cgi?id=14488 + * Check if the inner most base type is complex or imaginary. + * Should only give alerts when set to emit transitional messages. + * Params: + * type = type to check + * loc = The source location. + * sc = scope of the type + */ +extern (D) bool checkComplexTransition(Type type, const ref Loc loc, Scope* sc) +{ + if (sc.isDeprecated()) + return false; + // Don't complain if we're inside a template constraint + // https://issues.dlang.org/show_bug.cgi?id=21831 + if (sc.flags & SCOPE.constraint) + return false; + + Type t = type.baseElemOf(); + while (t.ty == Tpointer || t.ty == Tarray) + t = t.nextOf().baseElemOf(); + + // Basetype is an opaque enum, nothing to check. + if (t.ty == Tenum && !(cast(TypeEnum)t).sym.memtype) + return false; + + if (t.isimaginary() || t.iscomplex()) + { + if (sc.flags & SCOPE.Cfile) + return true; // complex/imaginary not deprecated in C code + Type rt; + switch (t.ty) + { + case Tcomplex32: + case Timaginary32: + rt = Type.tfloat32; + break; + + case Tcomplex64: + case Timaginary64: + rt = Type.tfloat64; + break; + + case Tcomplex80: + case Timaginary80: + rt = Type.tfloat80; + break; + + default: + assert(0); + } + // @@@DEPRECATED_2.117@@@ + // Deprecated in 2.097 - Can be made an error from 2.117. + // The deprecation period is longer than usual as `cfloat`, + // `cdouble`, and `creal` were quite widely used. + if (t.iscomplex()) + { + deprecation(loc, "use of complex type `%s` is deprecated, use `std.complex.Complex!(%s)` instead", + type.toChars(), rt.toChars()); + return true; + } + else + { + deprecation(loc, "use of imaginary type `%s` is deprecated, use `%s` instead", + type.toChars(), rt.toChars()); + return true; + } + } + return false; +} + /******************************** * 'args' are being matched to function type 'tf' * Determine match level. @@ -494,12 +682,12 @@ Expression typeToExpression(Type t) * tthis = type of `this` pointer, null if not member function * argumentList = arguments to function call * flag = 1: performing a partial ordering match - * pMessage = address to store error message, or null + * errorHelper = delegate to call for error messages * sc = context * Returns: * MATCHxxxx */ -extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentList, int flag = 0, const(char)** pMessage = null, Scope* sc = null) +extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentList, int flag = 0, void delegate(const(char)*) scope errorHelper = null, Scope* sc = null) { //printf("TypeFunction::callMatch() %s\n", tf.toChars()); MATCH match = MATCH.exact; // assume exact match @@ -542,7 +730,7 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis { // suppress early exit if an error message is wanted, // so we can check any matching args are valid - if (!pMessage) + if (!errorHelper) return MATCH.nomatch; } // too many args; no match @@ -552,18 +740,25 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis // https://issues.dlang.org/show_bug.cgi?id=22997 if (parameterList.varargs == VarArg.none && nparams > argumentList.length && !parameterList.hasDefaultArgs) { - OutBuffer buf; - buf.printf("too few arguments, expected %d, got %d", cast(int)nparams, cast(int)argumentList.length); - if (pMessage) - *pMessage = buf.extractChars(); + if (errorHelper) + { + OutBuffer buf; + buf.printf("too few arguments, expected %d, got %d", cast(int)nparams, cast(int)argumentList.length); + errorHelper(buf.peekChars()); + } return MATCH.nomatch; } + const(char)* failMessage; + const(char)** pMessage = errorHelper ? &failMessage : null; auto resolvedArgs = tf.resolveNamedArgs(argumentList, pMessage); Expression[] args; if (!resolvedArgs) { - if (!pMessage || *pMessage) + if (failMessage) + { + errorHelper(failMessage); return MATCH.nomatch; + } // if no message was provided, it was because of overflow which will be diagnosed below match = MATCH.nomatch; @@ -642,6 +837,8 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis if (auto vmatch = matchTypeSafeVarArgs(tf, p, trailingArgs, pMessage)) return vmatch < match ? vmatch : match; // Error message was already generated in `matchTypeSafeVarArgs` + if (failMessage) + errorHelper(failMessage); return MATCH.nomatch; } if (pMessage && u >= args.length) @@ -651,16 +848,18 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis else if (pMessage && !*pMessage) *pMessage = tf.getParamError(args[u], p); + if (errorHelper) + errorHelper(*pMessage); return MATCH.nomatch; } if (m < match) match = m; // pick worst match } - if (pMessage && !parameterList.varargs && args.length > nparams) + if (errorHelper && !parameterList.varargs && args.length > nparams) { // all parameters had a match, but there are surplus args - *pMessage = tf.getMatchError("expected %d argument(s), not %d", nparams, args.length); + errorHelper(tf.getMatchError("expected %d argument(s), not %d", nparams, args.length)); return MATCH.nomatch; } //printf("match = %d\n", match); @@ -687,7 +886,7 @@ private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct, Expression e = new DotIdExp(arg.loc, ve, Id.ctor); e = new CallExp(arg.loc, e, arg); //printf("e = %s\n", e.toChars()); - if (.trySemantic(e, sc)) + if (dmd.expressionsem.trySemantic(e, sc)) return true; if (pMessage) @@ -1017,6 +1216,70 @@ private extern(D) MATCH matchTypeSafeVarArgs(TypeFunction tf, Parameter p, } } +/*************************************** + * Return !=0 if type has pointers that need to + * be scanned by the GC during a collection cycle. + */ +extern(C++) bool hasPointers(Type t) +{ + bool visitType(Type _) { return false; } + bool visitDArray(TypeDArray _) { return true; } + bool visitAArray(TypeAArray _) { return true; } + bool visitPointer(TypePointer _) { return true; } + bool visitDelegate(TypeDelegate _) { return true; } + bool visitClass(TypeClass _) { return true; } + bool visitEnum(TypeEnum t) { return t.memType().hasPointers(); } + + /* Although null isn't dereferencable, treat it as a pointer type for + * attribute inference, generic code, etc. + */ + bool visitNull(TypeNull _) { return true; } + + bool visitSArray(TypeSArray t) + { + /* Don't want to do this, because: + * struct S { T* array[0]; } + * may be a variable length struct. + */ + //if (dim.toInteger() == 0) + // return false; + + if (t.next.ty == Tvoid) + { + // Arrays of void contain arbitrary data, which may include pointers + return true; + } + else + return t.next.hasPointers(); + } + + bool visitStruct(TypeStruct t) + { + StructDeclaration sym = t.sym; + + if (sym.members && !sym.determineFields() && sym.type != Type.terror) + error(sym.loc, "no size because of forward references"); + + sym.determineTypeProperties(); + return sym.hasPointerField; + } + + + switch(t.ty) + { + default: return visitType(t); + case Tsarray: return visitSArray(t.isTypeSArray()); + case Tarray: return visitDArray(t.isTypeDArray()); + case Taarray: return visitAArray(t.isTypeAArray()); + case Tpointer: return visitPointer(t.isTypePointer()); + case Tdelegate: return visitDelegate(t.isTypeDelegate()); + case Tstruct: return visitStruct(t.isTypeStruct()); + case Tenum: return visitEnum(t.isTypeEnum()); + case Tclass: return visitClass(t.isTypeClass()); + case Tnull: return visitNull(t.isTypeNull()); + } +} + /****************************************** * Perform semantic analysis on a type. * Params: @@ -1661,9 +1924,12 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) else { e = inferType(e, fparam.type); + Scope* sc2 = sc.push(); + sc2.inDefaultArg = true; Initializer iz = new ExpInitializer(e.loc, e); - iz = iz.initializerSemantic(sc, fparam.type, INITnointerpret); + iz = iz.initializerSemantic(sc2, fparam.type, INITnointerpret); e = iz.initializerToExpression(); + sc2.pop(); } if (e.op == EXP.function_) // https://issues.dlang.org/show_bug.cgi?id=4820 { @@ -2553,6 +2819,31 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) } } +extern(C++) Type trySemantic(Type type, const ref Loc loc, Scope* sc) +{ + //printf("+trySemantic(%s) %d\n", toChars(), global.errors); + + // Needed to display any deprecations that were gagged + auto tcopy = type.syntaxCopy(); + + const errors = global.startGagging(); + Type t = typeSemantic(type, loc, sc); + if (global.endGagging(errors) || t.ty == Terror) // if any errors happened + { + t = null; + } + else + { + // If `typeSemantic` succeeded, there may have been deprecations that + // were gagged due the `startGagging` above. Run again to display + // those deprecations. https://issues.dlang.org/show_bug.cgi?id=19107 + if (global.gaggedWarnings > 0) + typeSemantic(tcopy, loc, sc); + } + //printf("-trySemantic(%s) %d\n", toChars(), global.errors); + return t; +} + /************************************ * If an identical type to `type` is in `type.stringtable`, return * the latter one. Otherwise, add it to `type.stringtable`. @@ -5216,6 +5507,117 @@ extern (C++) Expression defaultInit(Type mt, const ref Loc loc, const bool isCfi } } +/* +If `type` resolves to a dsymbol, then that +dsymbol is returned. + +Params: + type = the type that is checked + sc = the scope where the type is used + +Returns: + The dsymbol to which the type resolve or `null` + if the type does resolve to any symbol (for example, + in the case of basic types). +*/ +extern(C++) Dsymbol toDsymbol(Type type, Scope* sc) +{ + Dsymbol visitType(Type _) { return null; } + Dsymbol visitStruct(TypeStruct type) { return type.sym; } + Dsymbol visitEnum(TypeEnum type) { return type.sym; } + Dsymbol visitClass(TypeClass type) { return type.sym; } + + Dsymbol visitTraits(TypeTraits type) + { + Type t; + Expression e; + Dsymbol s; + resolve(type, type.loc, sc, e, t, s); + if (t && t.ty != Terror) + s = t.toDsymbol(sc); + else if (e) + s = getDsymbol(e); + + return s; + } + + Dsymbol visitMixin(TypeMixin type) + { + Type t; + Expression e; + Dsymbol s; + resolve(type, type.loc, sc, e, t, s); + if (t) + s = t.toDsymbol(sc); + else if (e) + s = getDsymbol(e); + + return s; + } + + Dsymbol visitIdentifier(TypeIdentifier type) + { + //printf("TypeIdentifier::toDsymbol('%s')\n", toChars()); + if (!sc) + return null; + + Type t; + Expression e; + Dsymbol s; + resolve(type, type.loc, sc, e, t, s); + if (t && t.ty != Tident) + s = t.toDsymbol(sc); + if (e) + s = getDsymbol(e); + + return s; + } + + Dsymbol visitInstance(TypeInstance type) + { + Type t; + Expression e; + Dsymbol s; + //printf("TypeInstance::semantic(%s)\n", toChars()); + resolve(type, type.loc, sc, e, t, s); + if (t && t.ty != Tinstance) + s = t.toDsymbol(sc); + return s; + } + + Dsymbol visitTypeof(TypeTypeof type) + { + //printf("TypeTypeof::toDsymbol('%s')\n", toChars()); + Expression e; + Type t; + Dsymbol s; + resolve(type, type.loc, sc, e, t, s); + return s; + } + + Dsymbol visitReturn(TypeReturn type) + { + Expression e; + Type t; + Dsymbol s; + resolve(type, type.loc, sc, e, t, s); + return s; + } + + switch(type.ty) + { + default: return visitType(type); + case Ttraits: return visitTraits(type.isTypeTraits()); + case Tmixin: return visitMixin(type.isTypeMixin()); + case Tident: return visitIdentifier(type.isTypeIdentifier()); + case Tinstance: return visitInstance(type.isTypeInstance()); + case Ttypeof: return visitTypeof(type.isTypeTypeof()); + case Treturn: return visitReturn(type.isTypeReturn()); + case Tstruct: return visitStruct(type.isTypeStruct()); + case Tenum: return visitEnum(type.isTypeEnum()); + case Tclass: return visitClass(type.isTypeClass()); + } +} /********************************************** * Extract complex type from core.stdc.config @@ -5541,6 +5943,144 @@ Lnotcovariant: return Covariant.no; } +/************************************ + * Take the specified storage class for p, + * and use the function signature to infer whether + * STC.scope_ and STC.return_ should be OR'd in. + * (This will not affect the name mangling.) + * Params: + * tf = TypeFunction to use to get the signature from + * tthis = type of `this` parameter, null if none + * p = parameter to this function + * outerVars = context variables p could escape into, if any + * indirect = is this for an indirect or virtual function call? + * Returns: + * storage class with STC.scope_ or STC.return_ OR'd in + */ +StorageClass parameterStorageClass(TypeFunction tf, Type tthis, Parameter p, VarDeclarations* outerVars = null, + bool indirect = false) +{ + //printf("parameterStorageClass(p: %s)\n", p.toChars()); + auto stc = p.storageClass; + + // When the preview switch is enable, `in` parameters are `scope` + if (stc & STC.constscoperef) + return stc | STC.scope_; + + if (stc & (STC.scope_ | STC.return_ | STC.lazy_) || tf.purity == PURE.impure) + return stc; + + /* If haven't inferred the return type yet, can't infer storage classes + */ + if (!tf.nextOf() || !tf.isnothrow()) + return stc; + + tf.purityLevel(); + + static bool mayHavePointers(Type t) + { + if (auto ts = t.isTypeStruct()) + { + auto sym = ts.sym; + if (sym.members && !sym.determineFields() && sym.type != Type.terror) + // struct is forward referenced, so "may have" pointers + return true; + } + return t.hasPointers(); + } + + // See if p can escape via any of the other parameters + if (tf.purity == PURE.weak) + { + /* + * Indirect calls may escape p through a nested context + * See: + * https://issues.dlang.org/show_bug.cgi?id=24212 + * https://issues.dlang.org/show_bug.cgi?id=24213 + */ + if (indirect) + return stc; + + // Check escaping through parameters + foreach (i, fparam; tf.parameterList) + { + Type t = fparam.type; + if (!t) + continue; + t = t.baseElemOf(); // punch thru static arrays + if (t.isMutable() && t.hasPointers()) + { + if (fparam.isReference() && fparam != p) + return stc; + + if (t.ty == Tdelegate) + return stc; // could escape thru delegate + + if (t.ty == Tclass) + return stc; + + /* if t is a pointer to mutable pointer + */ + if (auto tn = t.nextOf()) + { + if (tn.isMutable() && mayHavePointers(tn)) + return stc; // escape through pointers + } + } + } + + // Check escaping through `this` + if (tthis && tthis.isMutable()) + { + foreach (VarDeclaration v; isAggregate(tthis).fields) + { + if (v.hasPointers()) + return stc; + } + } + + // Check escaping through nested context + if (outerVars && tf.isMutable()) + { + foreach (VarDeclaration v; *outerVars) + { + if (v.hasPointers()) + return stc; + } + } + } + + // Check escaping through return value + Type tret = tf.nextOf().toBasetype(); + if (tf.isref || tret.hasPointers()) + { + return stc | STC.scope_ | STC.return_ | STC.returnScope; + } + else + return stc | STC.scope_; +} + +extern(C++) bool isBaseOf(Type tthis, Type t, int* poffset) +{ + auto tc = tthis.isTypeClass(); + if (!tc) + return false; + + if (!t || t.ty != Tclass) + return false; + + ClassDeclaration cd = t.isTypeClass().sym; + if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete()) + cd.dsymbolSemantic(null); + if (tc.sym.semanticRun < PASS.semanticdone && !tc.sym.isBaseInfoComplete()) + tc.sym.dsymbolSemantic(null); + + if (tc.sym.isBaseOf(cd, poffset)) + return true; + + return false; +} + /******************************* Private *****************************************/ private: |