aboutsummaryrefslogtreecommitdiff
path: root/gcc/d/dmd
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gdcproject.org>2024-01-28 12:23:14 +0100
committerIain Buclaw <ibuclaw@gdcproject.org>2024-02-03 12:03:37 +0100
commit51c4eb28c192ecff4463c973a0ff089e04a80b89 (patch)
tree160ac2ef2c9d732681e96577ef0009027092aea6 /gcc/d/dmd
parent854b8555bd49ad97c336b8df7098e725dc196e4f (diff)
downloadgcc-51c4eb28c192ecff4463c973a0ff089e04a80b89.zip
gcc-51c4eb28c192ecff4463c973a0ff089e04a80b89.tar.gz
gcc-51c4eb28c192ecff4463c973a0ff089e04a80b89.tar.bz2
d: Merge dmd. druntime e770945277, phobos 6d6e0b9b9
D front-end changes: - Import latest fixes from dmd v2.107.0-beta.1. - Hex strings can now be cast to integer arrays. - Add support for Interpolated Expression Sequences. D runtime changes: - Import latest fixes from druntime v2.107.0-beta.1. - New core.interpolation module to provide run-time support for D interpolated expression sequence literals. Phobos changes: - Import latest fixes from phobos v2.107.0-beta.1. - `std.range.primitives.isBidirectionalRange', and `std.range.primitives.isRandomAccessRange' now take an optional element type. gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd e770945277. * Make-lang.in (D_FRONTEND_OBJS): Add d/basicmangle.o, d/enumsem.o, d/funcsem.o, d/templatesem.o. * d-builtins.cc (build_frontend_type): Update for new front-end interface. * d-codegen.cc (declaration_type): Likewise. (parameter_type): Likewise. * d-incpath.cc (add_globalpaths): Likewise. (add_filepaths): Likewise. (add_import_paths): Likewise. * d-lang.cc (d_init_options): Likewise. (d_handle_option): Likewise. (d_parse_file): Likewise. * decl.cc (DeclVisitor::finish_vtable): Likewise. (DeclVisitor::visit (FuncDeclaration *)): Likewise. (get_symbol_decl): Likewise. * expr.cc (ExprVisitor::visit (StringExp *)): Likewise. Implement support for 8-byte hexadecimal strings. * typeinfo.cc (create_tinfo_types): Update internal TypeInfo representation. (TypeInfoVisitor::visit (TypeInfoConstDeclaration *)): Update for new front-end interface. (TypeInfoVisitor::visit (TypeInfoInvariantDeclaration *)): Likewise. (TypeInfoVisitor::visit (TypeInfoSharedDeclaration *)): Likewise. (TypeInfoVisitor::visit (TypeInfoWildDeclaration *)): Likewise. (TypeInfoVisitor::visit (TypeInfoClassDeclaration *)): Move data for TypeInfo_Class.nameSig to the end of the object. (create_typeinfo): Update for new front-end interface. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime e770945277. * libdruntime/Makefile.am (DRUNTIME_SOURCES): Add core/interpolation.d. * libdruntime/Makefile.in: Regenerate. * src/MERGE: Merge upstream phobos 6d6e0b9b9.
Diffstat (limited to 'gcc/d/dmd')
-rw-r--r--gcc/d/dmd/MERGE2
-rw-r--r--gcc/d/dmd/README.md4
-rw-r--r--gcc/d/dmd/aggregate.h3
-rw-r--r--gcc/d/dmd/basicmangle.d109
-rw-r--r--gcc/d/dmd/clone.d9
-rw-r--r--gcc/d/dmd/common/outbuffer.d27
-rw-r--r--gcc/d/dmd/cond.d19
-rw-r--r--gcc/d/dmd/constfold.d6
-rw-r--r--gcc/d/dmd/ctfeexpr.d10
-rw-r--r--gcc/d/dmd/dclass.d2
-rw-r--r--gcc/d/dmd/declaration.h7
-rw-r--r--gcc/d/dmd/denum.d85
-rw-r--r--gcc/d/dmd/dinterpret.d68
-rw-r--r--gcc/d/dmd/dmangle.d144
-rw-r--r--gcc/d/dmd/dmodule.d6
-rw-r--r--gcc/d/dmd/doc.d3
-rw-r--r--gcc/d/dmd/dstruct.d2
-rw-r--r--gcc/d/dmd/dsymbolsem.d574
-rw-r--r--gcc/d/dmd/dtemplate.d1540
-rw-r--r--gcc/d/dmd/enum.h2
-rw-r--r--gcc/d/dmd/enumsem.d714
-rw-r--r--gcc/d/dmd/expression.d44
-rw-r--r--gcc/d/dmd/expression.h15
-rw-r--r--gcc/d/dmd/expressionsem.d103
-rw-r--r--gcc/d/dmd/func.d199
-rw-r--r--gcc/d/dmd/funcsem.d219
-rw-r--r--gcc/d/dmd/globals.d12
-rw-r--r--gcc/d/dmd/globals.h12
-rw-r--r--gcc/d/dmd/hdrgen.d84
-rw-r--r--gcc/d/dmd/id.d6
-rw-r--r--gcc/d/dmd/json.d14
-rw-r--r--gcc/d/dmd/lexer.d166
-rw-r--r--gcc/d/dmd/mtype.d56
-rw-r--r--gcc/d/dmd/mtype.h2
-rw-r--r--gcc/d/dmd/parse.d9
-rw-r--r--gcc/d/dmd/parsetimevisitor.d1
-rw-r--r--gcc/d/dmd/res/default_ddoc_theme.ddoc8
-rw-r--r--gcc/d/dmd/root/filename.d67
-rw-r--r--gcc/d/dmd/root/filename.h2
-rw-r--r--gcc/d/dmd/semantic3.d3
-rw-r--r--gcc/d/dmd/statementsem.d3
-rw-r--r--gcc/d/dmd/templatesem.d1497
-rw-r--r--gcc/d/dmd/tokens.d33
-rw-r--r--gcc/d/dmd/tokens.h9
-rw-r--r--gcc/d/dmd/traits.d3
-rw-r--r--gcc/d/dmd/typesem.d26
-rw-r--r--gcc/d/dmd/typinf.d1
-rw-r--r--gcc/d/dmd/visitor.h2
48 files changed, 3358 insertions, 2574 deletions
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index 138b0b6..9217c65 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@
-bce5c1f7b521d22dcf1ea4e2bc3f76d9d28274fa
+e7709452775d374c1e2dfb67566668ada3dec5fc
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/README.md b/gcc/d/dmd/README.md
index f8ac001..23f3333 100644
--- a/gcc/d/dmd/README.md
+++ b/gcc/d/dmd/README.md
@@ -110,6 +110,8 @@ Note that these groups have no strict meaning, the category assignments are a bi
| File | Purpose |
|-------------------------------------------------------------------------------------------|-------------------------------------------------------------------|
| [dsymbolsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dsymbolsem.d) | Do semantic 1 pass (symbol identifiers/types) |
+| [enumsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/enumsem.d) | Enum semantics |
+| [funcsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/funcsem.d) | Function semantics |
| [semantic2.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/semantic2.d) | Do semantic 2 pass (symbol initializers) |
| [semantic3.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/semantic3.d) | Do semantic 3 pass (function bodies) |
| [inline.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/inline.d) | Do inline pass (optimization pass that dmd does in the front-end) |
@@ -117,6 +119,7 @@ Note that these groups have no strict meaning, the category assignments are a bi
| [expressionsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/expressionsem.d) | Do semantic analysis for expressions |
| [statementsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/statementsem.d) | Do semantic analysis for statements |
| [initsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/initsem.d) | Do semantic analysis for initializers |
+| [templatesem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/templatesem.d) | Do semantic analysis for templates |
| [templateparamsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/templateparamsem.d) | Do semantic analysis for template parameters |
| [typesem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/typesem.d) | Do semantic analysis for types |
@@ -230,6 +233,7 @@ Note that these groups have no strict meaning, the category assignments are a bi
|-----------------------------------------------------------------------------------|------------------------------------------------------------------|
| [cppmangle.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/cppmangle.d) | C++ name mangling |
| [cppmanglewin.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/cppmanglewin.d) | C++ name mangling for Windows |
+| [basicmangle.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/basicmangle.d) | D name mangling for basic types |
| [dmangle.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dmangle.d) | D [name mangling](https://dlang.org/spec/abi.html#name_mangling) |
### Linking
diff --git a/gcc/d/dmd/aggregate.h b/gcc/d/dmd/aggregate.h
index 9abdd09..f466ba6 100644
--- a/gcc/d/dmd/aggregate.h
+++ b/gcc/d/dmd/aggregate.h
@@ -234,7 +234,8 @@ struct ClassFlags
hasTypeInfo = 0x20,
isAbstract = 0x40,
isCPPclass = 0x80,
- hasDtor = 0x100
+ hasDtor = 0x100,
+ hasNameSig = 0x200,
};
};
diff --git a/gcc/d/dmd/basicmangle.d b/gcc/d/dmd/basicmangle.d
new file mode 100644
index 0000000..52534fa
--- /dev/null
+++ b/gcc/d/dmd/basicmangle.d
@@ -0,0 +1,109 @@
+/**
+ * Defines the building blocks for creating the mangled names for basic types.
+ *
+ * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/basicmangle.d, _basicmangle.d)
+ * Documentation: https://dlang.org/phobos/dmd_basicmangle.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/basicmangle.d
+ */
+module dmd.basicmangle;
+
+import dmd.astenums;
+import dmd.common.outbuffer : OutBuffer;
+
+/// Type mangling mapping for basic, derived and user defined types
+immutable char[TMAX] mangleChar =
+[
+ Tchar : 'a',
+ Tbool : 'b',
+ Tcomplex80 : 'c',
+ Tfloat64 : 'd',
+ Tfloat80 : 'e',
+ Tfloat32 : 'f',
+ Tint8 : 'g',
+ Tuns8 : 'h',
+ Tint32 : 'i',
+ Timaginary80 : 'j',
+ Tuns32 : 'k',
+ Tint64 : 'l',
+ Tuns64 : 'm',
+ Tnull : 'n',
+ Timaginary32 : 'o',
+ Timaginary64 : 'p',
+ Tcomplex32 : 'q',
+ Tcomplex64 : 'r',
+ Tint16 : 's',
+ Tuns16 : 't',
+ Twchar : 'u',
+ Tvoid : 'v',
+ Tdchar : 'w',
+ // x // const
+ // y // immutable
+ Tint128 : 'z', // zi
+ Tuns128 : 'z', // zk
+
+ Tarray : 'A',
+ Ttuple : 'B',
+ Tclass : 'C',
+ Tdelegate : 'D',
+ Tenum : 'E',
+ Tfunction : 'F', // D function
+ Tsarray : 'G',
+ Taarray : 'H',
+ // I // in
+ // J // out
+ // K // ref
+ // L // lazy
+ // M // has this, or scope
+ // N // Nh:vector Ng:wild Nn:noreturn
+ // O // shared
+ Tpointer : 'P',
+ // Q // Type/symbol/identifier backward reference
+ Treference : 'R',
+ Tstruct : 'S',
+ // T // Ttypedef
+ // U // C function
+ // W // Windows function
+ // X // variadic T t...)
+ // Y // variadic T t,...)
+ // Z // not variadic, end of parameters
+
+ // '@' shouldn't appear anywhere in the deco'd names
+ Tnone : '@',
+ Tident : '@',
+ Tinstance : '@',
+ Terror : '@',
+ Ttypeof : '@',
+ Tslice : '@',
+ Treturn : '@',
+ Tvector : '@',
+ Ttraits : '@',
+ Tmixin : '@',
+ Ttag : '@',
+ Tnoreturn : '@', // becomes 'Nn'
+];
+
+unittest
+{
+ foreach (i, mangle; mangleChar)
+ {
+ if (mangle == char.init)
+ {
+ import core.stdc.stdio;
+ fprintf(stderr, "ty = %u\n", cast(uint)i);
+ assert(0);
+ }
+ }
+}
+
+/***********************
+ * Mangle basic type ty to buf.
+ */
+void tyToDecoBuffer(ref OutBuffer buf, int ty) @safe
+{
+ const c = mangleChar[ty];
+ buf.writeByte(c);
+ if (c == 'z')
+ buf.writeByte(ty == Tint128 ? 'i' : 'k');
+}
diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d
index 6fbf8e2..46470ee 100644
--- a/gcc/d/dmd/clone.d
+++ b/gcc/d/dmd/clone.d
@@ -27,6 +27,7 @@ import dmd.errors;
import dmd.expression;
import dmd.expressionsem;
import dmd.func;
+import dmd.funcsem;
import dmd.globals;
import dmd.id;
import dmd.identifier;
@@ -905,7 +906,7 @@ void buildDtors(AggregateDeclaration ad, Scope* sc)
a.addMember(sc, ad); // temporarily add to symbol table
}
- sdv.dtor.functionSemantic();
+ functionSemantic(sdv.dtor);
stc = mergeFuncAttrs(stc, sdv.dtor);
if (stc & STC.disable)
@@ -1154,7 +1155,7 @@ private DtorDeclaration buildExternDDtor(AggregateDeclaration ad, Scope* sc)
ad.members.push(func);
func.addMember(sc2, ad);
func.dsymbolSemantic(sc2);
- func.functionSemantic(); // to infer attributes
+ functionSemantic(func); // to infer attributes
sc2.pop();
return func;
@@ -1336,7 +1337,7 @@ FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc)
// perform semantic on the member postblit in order to
// be able to aggregate it later on with the rest of the
// postblits
- sdv.postblit.functionSemantic();
+ functionSemantic(sdv.postblit);
stc = mergeFuncAttrs(stc, sdv.postblit);
stc = mergeFuncAttrs(stc, sdv.dtor);
@@ -1401,7 +1402,7 @@ FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc)
*/
if (sdv.dtor)
{
- sdv.dtor.functionSemantic();
+ functionSemantic(sdv.dtor);
// keep a list of fields that need to be destroyed in case
// of a future postblit failure
diff --git a/gcc/d/dmd/common/outbuffer.d b/gcc/d/dmd/common/outbuffer.d
index cff08ec..cb2439f 100644
--- a/gcc/d/dmd/common/outbuffer.d
+++ b/gcc/d/dmd/common/outbuffer.d
@@ -756,6 +756,25 @@ struct OutBuffer
}
/**
+ * Write an array as a string of hexadecimal digits
+ * Params:
+ * data = bytes to write
+ * upperCase = whether to upper case hex digits A-F
+ */
+ void writeHexString(scope const(ubyte)[] data, bool upperCase) pure nothrow @safe
+ {
+ auto slice = this.allocate(2 * data.length);
+ const a = upperCase ? 'A' : 'a';
+ foreach (i, c; data)
+ {
+ char hi = (c >> 4) & 0xF;
+ slice[i * 2] = cast(char)(hi < 10 ? hi + '0' : hi - 10 + a);
+ char lo = c & 0xF;
+ slice[i * 2 + 1] = cast(char)(lo < 10 ? lo + '0' : lo - 10 + a);
+ }
+ }
+
+ /**
Destructively saves the contents of `this` to `filename`. As an
optimization, if the file already has identical contents with the buffer,
no copying is done. This is because on SSD drives reading is often much
@@ -943,3 +962,11 @@ unittest
else
assert(buf[] == "\nabc\n\n");
}
+
+unittest
+{
+ OutBuffer buf;
+ buf.writeHexString([0xAA, 0xBB], false);
+ buf.writeHexString([0xCC], true);
+ assert(buf[] == "aabbCC");
+}
diff --git a/gcc/d/dmd/cond.d b/gcc/d/dmd/cond.d
index 1b32ff7..e194664 100644
--- a/gcc/d/dmd/cond.d
+++ b/gcc/d/dmd/cond.d
@@ -548,8 +548,6 @@ extern (C++) final class DebugCondition : DVCondition
/// Ditto
extern(D) static void addGlobalIdent(const(char)[] ident)
{
- if (!global.debugids)
- global.debugids = new Identifiers();
global.debugids.push(Identifier.idPool(ident));
}
@@ -579,7 +577,7 @@ extern (C++) final class DebugCondition : DVCondition
bool definedInModule = false;
if (ident)
{
- if (findCondition(mod.debugids, ident))
+ if (mod.debugids && findCondition(*mod.debugids, ident))
{
inc = Include.yes;
definedInModule = true;
@@ -830,8 +828,6 @@ extern (C++) final class VersionCondition : DVCondition
/// Ditto
extern(D) static void addPredefinedGlobalIdent(const(char)[] ident)
{
- if (!global.versionids)
- global.versionids = new Identifiers();
global.versionids.push(Identifier.idPool(ident));
}
@@ -861,7 +857,7 @@ extern (C++) final class VersionCondition : DVCondition
bool definedInModule = false;
if (ident)
{
- if (findCondition(mod.versionids, ident))
+ if (mod.versionids && findCondition(*mod.versionids, ident))
{
inc = Include.yes;
definedInModule = true;
@@ -983,15 +979,12 @@ extern (C++) final class StaticIfCondition : Condition
* Returns:
* true if found
*/
-bool findCondition(Identifiers* ids, Identifier ident) @safe nothrow pure
+bool findCondition(ref Identifiers ids, Identifier ident) @safe nothrow pure
{
- if (ids)
+ foreach (id; ids)
{
- foreach (id; *ids)
- {
- if (id == ident)
- return true;
- }
+ if (id == ident)
+ return true;
}
return false;
}
diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d
index cee1f63..41fed9c 100644
--- a/gcc/d/dmd/constfold.d
+++ b/gcc/d/dmd/constfold.d
@@ -711,7 +711,7 @@ UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e
cmp = 1; // if dim1 winds up being 0
foreach (i; 0 .. dim1)
{
- uinteger_t c = es1.getCodeUnit(i);
+ uinteger_t c = es1.getIndex(i);
auto ee2 = es2[i];
if (ee2.isConst() != 1)
{
@@ -1119,7 +1119,7 @@ UnionExp Index(Type type, Expression e1, Expression e2, bool indexIsInBounds)
}
else
{
- emplaceExp!(IntegerExp)(&ue, loc, es1.getCodeUnit(cast(size_t) i), type);
+ emplaceExp!(IntegerExp)(&ue, loc, es1.getIndex(cast(size_t) i), type);
}
}
else if (e1.type.toBasetype().ty == Tsarray && e2.op == EXP.int64)
@@ -1282,7 +1282,7 @@ void sliceAssignArrayLiteralFromString(ArrayLiteralExp existingAE, const StringE
Type elemType = existingAE.type.nextOf();
foreach (j; 0 .. len)
{
- const val = newval.getCodeUnit(j);
+ const val = newval.getIndex(j);
(*existingAE.elements)[j + firstIndex] = new IntegerExp(newval.loc, val, elemType);
}
}
diff --git a/gcc/d/dmd/ctfeexpr.d b/gcc/d/dmd/ctfeexpr.d
index 5fe1e7d..af83aad 100644
--- a/gcc/d/dmd/ctfeexpr.d
+++ b/gcc/d/dmd/ctfeexpr.d
@@ -568,6 +568,9 @@ StringExp createBlockDuplicatedStringLiteral(UnionExp* pue, const ref Loc loc, T
case 4:
(cast(dchar*)s)[elemi] = value;
break;
+ case 8:
+ (cast(ulong*)s)[elemi] = value;
+ break;
default:
assert(0);
}
@@ -1494,7 +1497,7 @@ Expression ctfeIndex(UnionExp* pue, const ref Loc loc, Type type, Expression e1,
error(loc, "string index %llu is out of bounds `[0 .. %llu]`", indx, cast(ulong)es1.len);
return CTFEExp.cantexp;
}
- emplaceExp!IntegerExp(pue, loc, es1.getCodeUnit(cast(size_t) indx), type);
+ emplaceExp!IntegerExp(pue, loc, es1.getIndex(cast(size_t) indx), type);
return pue.exp();
}
@@ -1704,7 +1707,7 @@ Expression changeArrayLiteralLength(UnionExp* pue, const ref Loc loc, TypeArray
void* s = mem.xcalloc(newlen + 1, oldse.sz);
const data = oldse.peekData();
memcpy(s, data.ptr, copylen * oldse.sz);
- const defaultValue = cast(uint)defaultElem.toInteger();
+ const defaultValue = cast(ulong)defaultElem.toInteger();
foreach (size_t elemi; copylen .. newlen)
{
switch (oldse.sz)
@@ -1718,6 +1721,9 @@ Expression changeArrayLiteralLength(UnionExp* pue, const ref Loc loc, TypeArray
case 4:
(cast(dchar*)s)[cast(size_t)(indxlo + elemi)] = cast(dchar)defaultValue;
break;
+ case 8:
+ (cast(ulong*)s)[cast(size_t)(indxlo + elemi)] = cast(ulong)defaultValue;
+ break;
default:
assert(0);
}
diff --git a/gcc/d/dmd/dclass.d b/gcc/d/dmd/dclass.d
index 405e817..7e5e7e4 100644
--- a/gcc/d/dmd/dclass.d
+++ b/gcc/d/dmd/dclass.d
@@ -123,6 +123,7 @@ extern (C++) struct BaseClass
}
}
+// These must match the values in druntime/src/object.d
enum ClassFlags : uint
{
none = 0x0,
@@ -135,6 +136,7 @@ enum ClassFlags : uint
isAbstract = 0x40,
isCPPclass = 0x80,
hasDtor = 0x100,
+ hasNameSig = 0x200,
}
/***********************************************************
diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h
index 0e327be..e4efbbc 100644
--- a/gcc/d/dmd/declaration.h
+++ b/gcc/d/dmd/declaration.h
@@ -30,6 +30,9 @@ class StructDeclaration;
struct IntRange;
struct AttributeViolation;
+bool functionSemantic(FuncDeclaration* fd);
+bool functionSemantic3(FuncDeclaration* fd);
+
//enum STC : ulong from astenums.d:
#define STCundefined 0ULL
@@ -698,14 +701,12 @@ public:
FuncDeclaration *fdensure(FuncDeclaration *fde);
Expressions *fdrequireParams(Expressions *fdrp);
Expressions *fdensureParams(Expressions *fdep);
- bool functionSemantic();
- bool functionSemantic3();
bool equals(const RootObject * const o) const override final;
int findVtblIndex(Dsymbols *vtbl, int dim);
bool overloadInsert(Dsymbol *s) override;
bool inUnittest();
- MATCH leastAsSpecialized(FuncDeclaration *g, Identifiers *names);
+ static MATCH leastAsSpecialized(FuncDeclaration *f, FuncDeclaration *g, Identifiers *names);
LabelDsymbol *searchLabel(Identifier *ident, const Loc &loc);
const char *toPrettyChars(bool QualifyTypes = false) override;
const char *toFullSignature(); // for diagnostics, e.g. 'int foo(int x, int y) pure'
diff --git a/gcc/d/dmd/denum.d b/gcc/d/dmd/denum.d
index 5464ff9..9abdebd 100644
--- a/gcc/d/dmd/denum.d
+++ b/gcc/d/dmd/denum.d
@@ -122,91 +122,6 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol
return isSpecialEnumIdent(ident) && memtype;
}
- Expression getDefaultValue(const ref Loc loc)
- {
- Expression handleErrors(){
- defaultval = ErrorExp.get();
- return defaultval;
- }
- //printf("EnumDeclaration::getDefaultValue() %p %s\n", this, toChars());
- // https://issues.dlang.org/show_bug.cgi?id=23904
- // Return defaultval only if it is not ErrorExp.
- // A speculative context may set defaultval to ErrorExp;
- // subsequent non-speculative contexts need to be able
- // to print the error.
- if (defaultval && !defaultval.isErrorExp())
- return defaultval;
-
- if (isCsymbol())
- return memtype.defaultInit(loc, true);
-
- if (_scope)
- dsymbolSemantic(this, _scope);
- if (errors)
- return handleErrors();
- if (!members)
- {
- if (isSpecial())
- {
- /* Allow these special enums to not need a member list
- */
- return defaultval = memtype.defaultInit(loc);
- }
-
- error(loc, "%s `%s` is opaque and has no default initializer", kind, toPrettyChars);
- return handleErrors();
- }
-
- foreach (const i; 0 .. members.length)
- {
- EnumMember em = (*members)[i].isEnumMember();
- if (em)
- {
- if (em.semanticRun < PASS.semanticdone)
- {
- error(loc, "%s `%s` forward reference of `%s.init`", kind, toPrettyChars, toChars());
- return handleErrors();
- }
-
- defaultval = em.value;
- return defaultval;
- }
- }
- return handleErrors();
- }
-
- Type getMemtype(const ref Loc loc)
- {
- if (_scope)
- {
- /* Enum is forward referenced. We don't need to resolve the whole thing,
- * just the base type
- */
- if (memtype)
- {
- Loc locx = loc.isValid() ? loc : this.loc;
- memtype = memtype.typeSemantic(locx, _scope);
- }
- else
- {
- // Run semantic to get the type from a possible first member value
- dsymbolSemantic(this, _scope);
- }
- }
- if (!memtype)
- {
- if (!isAnonymous() && (members || semanticRun >= PASS.semanticdone))
- memtype = Type.tint32;
- else
- {
- Loc locx = loc.isValid() ? loc : this.loc;
- error(locx, "is forward referenced looking for base type");
- return Type.terror;
- }
- }
- return memtype;
- }
-
override inout(EnumDeclaration) isEnumDeclaration() inout
{
return this;
diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d
index a3b38d9..d8069c6 100644
--- a/gcc/d/dmd/dinterpret.d
+++ b/gcc/d/dmd/dinterpret.d
@@ -33,6 +33,7 @@ import dmd.errors;
import dmd.expression;
import dmd.expressionsem;
import dmd.func;
+import dmd.funcsem;
import dmd.globals;
import dmd.hdrgen;
import dmd.id;
@@ -440,7 +441,7 @@ private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterSta
fdError("circular dependency. Functions cannot be interpreted while being compiled");
return CTFEExp.cantexp;
}
- if (!fd.functionSemantic3())
+ if (!functionSemantic3(fd))
return CTFEExp.cantexp;
if (fd.semanticRun < PASS.semantic3done)
{
@@ -6097,11 +6098,35 @@ public:
result.type = e.to;
return;
}
+
// Disallow array type painting, except for conversions between built-in
// types of identical size.
if ((e.to.ty == Tsarray || e.to.ty == Tarray) && (e1.type.ty == Tsarray || e1.type.ty == Tarray) && !isSafePointerCast(e1.type.nextOf(), e.to.nextOf()))
{
+ auto se = e1.isStringExp();
+ // Allow casting a hex string literal to short[], int[] or long[]
+ if (se && se.hexString && se.postfix == StringExp.NoPostfix)
+ {
+ const sz = cast(size_t) e.to.nextOf().size;
+ if ((se.len % sz) != 0)
+ {
+ error(e.loc, "hex string length %d must be a multiple of %d to cast to `%s`",
+ cast(int) se.len, cast(int) sz, e.to.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+
+ auto str = arrayCastBigEndian((cast(const ubyte[]) se.peekString()), sz);
+ emplaceExp!(StringExp)(pue, e1.loc, str, se.len / sz, cast(ubyte) sz);
+ result = pue.exp();
+ result.type = e.to;
+ return;
+ }
error(e.loc, "array cast from `%s` to `%s` is not supported at compile time", e1.type.toChars(), e.to.toChars());
+ if (se && se.hexString && se.postfix != StringExp.NoPostfix)
+ errorSupplemental(e.loc, "perhaps remove postfix `%s` from hex string",
+ (cast(char) se.postfix ~ "\0").ptr);
+
result = CTFEExp.cantexp;
return;
}
@@ -7719,3 +7744,44 @@ private void removeHookTraceImpl(ref CallExp ce, ref FuncDeclaration fd)
if (global.params.v.verbose)
message("strip %s =>\n %s", oldCE.toChars(), ce.toChars());
}
+
+/**
+ * Cast a `ubyte[]` to an array of larger integers as if we are on a big endian architecture
+ * Params:
+ * data = array with big endian data
+ * size = 1 for ubyte[], 2 for ushort[], 4 for uint[], 8 for ulong[]
+ * Returns: copy of `data`, with bytes shuffled if compiled for `version(LittleEndian)`
+ */
+ubyte[] arrayCastBigEndian(const ubyte[] data, size_t size)
+{
+ ubyte[] impl(T)()
+ {
+ auto result = new T[](data.length / T.sizeof);
+ foreach (i; 0 .. result.length)
+ {
+ result[i] = 0;
+ foreach (j; 0 .. T.sizeof)
+ {
+ result[i] |= T(data[i * T.sizeof + j]) << ((T.sizeof - 1 - j) * 8);
+ }
+ }
+ return cast(ubyte[]) result;
+ }
+ switch (size)
+ {
+ case 1: return data.dup;
+ case 2: return impl!ushort;
+ case 4: return impl!uint;
+ case 8: return impl!ulong;
+ default: assert(0);
+ }
+}
+
+unittest
+{
+ ubyte[] data = [0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22];
+ assert(cast(ulong[]) arrayCastBigEndian(data, 8) == [0xAABBCCDDEEFF1122]);
+ assert(cast(uint[]) arrayCastBigEndian(data, 4) == [0xAABBCCDD, 0xEEFF1122]);
+ assert(cast(ushort[]) arrayCastBigEndian(data, 2) == [0xAABB, 0xCCDD, 0xEEFF, 0x1122]);
+ assert(cast(ubyte[]) arrayCastBigEndian(data, 1) == data);
+}
diff --git a/gcc/d/dmd/dmangle.d b/gcc/d/dmd/dmangle.d
index 15b77ea..5bd1379 100644
--- a/gcc/d/dmd/dmangle.d
+++ b/gcc/d/dmd/dmangle.d
@@ -137,6 +137,7 @@ import core.stdc.string;
import dmd.aggregate;
import dmd.arraytypes;
import dmd.astenums;
+import dmd.basicmangle;
import dmd.dclass;
import dmd.declaration;
import dmd.dinterpret;
@@ -161,89 +162,6 @@ import dmd.target;
import dmd.tokens;
import dmd.visitor;
-private immutable char[TMAX] mangleChar =
-[
- Tchar : 'a',
- Tbool : 'b',
- Tcomplex80 : 'c',
- Tfloat64 : 'd',
- Tfloat80 : 'e',
- Tfloat32 : 'f',
- Tint8 : 'g',
- Tuns8 : 'h',
- Tint32 : 'i',
- Timaginary80 : 'j',
- Tuns32 : 'k',
- Tint64 : 'l',
- Tuns64 : 'm',
- Tnull : 'n',
- Timaginary32 : 'o',
- Timaginary64 : 'p',
- Tcomplex32 : 'q',
- Tcomplex64 : 'r',
- Tint16 : 's',
- Tuns16 : 't',
- Twchar : 'u',
- Tvoid : 'v',
- Tdchar : 'w',
- // x // const
- // y // immutable
- Tint128 : 'z', // zi
- Tuns128 : 'z', // zk
-
- Tarray : 'A',
- Ttuple : 'B',
- Tclass : 'C',
- Tdelegate : 'D',
- Tenum : 'E',
- Tfunction : 'F', // D function
- Tsarray : 'G',
- Taarray : 'H',
- // I // in
- // J // out
- // K // ref
- // L // lazy
- // M // has this, or scope
- // N // Nh:vector Ng:wild Nn:noreturn
- // O // shared
- Tpointer : 'P',
- // Q // Type/symbol/identifier backward reference
- Treference : 'R',
- Tstruct : 'S',
- // T // Ttypedef
- // U // C function
- // W // Windows function
- // X // variadic T t...)
- // Y // variadic T t,...)
- // Z // not variadic, end of parameters
-
- // '@' shouldn't appear anywhere in the deco'd names
- Tnone : '@',
- Tident : '@',
- Tinstance : '@',
- Terror : '@',
- Ttypeof : '@',
- Tslice : '@',
- Treturn : '@',
- Tvector : '@',
- Ttraits : '@',
- Tmixin : '@',
- Ttag : '@',
- Tnoreturn : '@', // becomes 'Nn'
-];
-
-unittest
-{
- foreach (i, mangle; mangleChar)
- {
- if (mangle == char.init)
- {
- fprintf(stderr, "ty = %u\n", cast(uint)i);
- assert(0);
- }
- }
-}
-
/************************************************
* Append the mangling of type `t` to `buf`.
* Params:
@@ -584,6 +502,20 @@ public:
toBuffer(*buf, id.toString(), s);
}
+ void mangleInteger(dinteger_t v)
+ {
+ if (cast(sinteger_t) v < 0)
+ {
+ buf.writeByte('N');
+ buf.print(-v);
+ }
+ else
+ {
+ buf.writeByte('i');
+ buf.print(v);
+ }
+ }
+
////////////////////////////////////////////////////////////////////////////
void mangleDecl(Declaration sthis)
{
@@ -991,17 +923,7 @@ public:
override void visit(IntegerExp e)
{
- const v = e.toInteger();
- if (cast(sinteger_t)v < 0)
- {
- buf.writeByte('N');
- buf.print(-v);
- }
- else
- {
- buf.writeByte('i');
- buf.print(v);
- }
+ mangleInteger(e.toInteger());
}
override void visit(RealExp e)
@@ -1028,6 +950,7 @@ public:
char m;
OutBuffer tmp;
const(char)[] q;
+
/* Write string in UTF-8 format
*/
switch (e.sz)
@@ -1065,7 +988,15 @@ public:
q = tmp[];
break;
}
-
+ case 8:
+ // String of size 8 has to be hexstring cast to long[], mangle as array literal
+ buf.writeByte('A');
+ buf.print(e.len);
+ foreach (i; 0 .. e.len)
+ {
+ mangleInteger(e.getIndex(i));
+ }
+ return;
default:
assert(0);
}
@@ -1073,14 +1004,7 @@ public:
buf.writeByte(m);
buf.print(q.length);
buf.writeByte('_'); // nbytes <= 11
- auto slice = buf.allocate(2 * q.length);
- foreach (i, c; q)
- {
- char hi = (c >> 4) & 0xF;
- slice[i * 2] = cast(char)(hi < 10 ? hi + '0' : hi - 10 + 'a');
- char lo = c & 0xF;
- slice[i * 2 + 1] = cast(char)(lo < 10 ? lo + '0' : lo - 10 + 'a');
- }
+ buf.writeHexString(cast(const(ubyte)[]) q, false);
}
override void visit(ArrayLiteralExp e)
@@ -1168,6 +1092,7 @@ private struct Backref
{
if (t.isFunction_Delegate_PtrToFunction())
{
+ import dmd.typesem : merge2;
t = t.merge2();
}
}
@@ -1213,19 +1138,6 @@ private struct Backref
AssocArray!(Identifier, size_t) idents; /// Identifier => (offset+1) in buf
}
-
-/***********************
- * Mangle basic type ty to buf.
- */
-
-private void tyToDecoBuffer(ref OutBuffer buf, int ty) @safe
-{
- const c = mangleChar[ty];
- buf.writeByte(c);
- if (c == 'z')
- buf.writeByte(ty == Tint128 ? 'i' : 'k');
-}
-
/*********************************
* Mangling for mod.
*/
diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d
index 59d4065..6167e2a 100644
--- a/gcc/d/dmd/dmodule.d
+++ b/gcc/d/dmd/dmodule.d
@@ -490,7 +490,7 @@ extern (C++) final class Module : Package
extern (D) static const(char)[] find(const(char)[] filename)
{
- return global.fileManager.lookForSourceFile(filename, global.path ? (*global.path)[] : null);
+ return global.fileManager.lookForSourceFile(filename, global.path[]);
}
extern (C++) static Module load(const ref Loc loc, Identifiers* packages, Identifier ident)
@@ -644,9 +644,9 @@ extern (C++) final class Module : Package
{
/* Print path
*/
- if (global.path)
+ if (global.path.length)
{
- foreach (i, p; *global.path)
+ foreach (i, p; global.path[])
fprintf(stderr, "import path[%llu] = %s\n", cast(ulong)i, p);
}
else
diff --git a/gcc/d/dmd/doc.d b/gcc/d/dmd/doc.d
index ec3cc91..bcf358c 100644
--- a/gcc/d/dmd/doc.d
+++ b/gcc/d/dmd/doc.d
@@ -5204,6 +5204,7 @@ void highlightCode2(Scope* sc, Dsymbols* a, ref OutBuffer buf, size_t offset)
highlight = "$(D_COMMENT ";
break;
case TOK.string_:
+ case TOK.interpolated:
highlight = "$(D_STRING ";
break;
default:
@@ -5216,7 +5217,7 @@ void highlightCode2(Scope* sc, Dsymbols* a, ref OutBuffer buf, size_t offset)
res.writestring(highlight);
size_t o = res.length;
highlightCode3(sc, res, tok.ptr, lex.p);
- if (tok.value == TOK.comment || tok.value == TOK.string_)
+ if (tok.value == TOK.comment || tok.value == TOK.string_ || tok.value == TOK.interpolated)
/* https://issues.dlang.org/show_bug.cgi?id=7656
* https://issues.dlang.org/show_bug.cgi?id=7715
* https://issues.dlang.org/show_bug.cgi?id=10519
diff --git a/gcc/d/dmd/dstruct.d b/gcc/d/dmd/dstruct.d
index 5683d5f..7546fb6 100644
--- a/gcc/d/dmd/dstruct.d
+++ b/gcc/d/dmd/dstruct.d
@@ -616,7 +616,7 @@ bool _isZeroInit(Expression exp)
foreach (i; 0 .. se.len)
{
- if (se.getCodeUnit(i))
+ if (se.getIndex(i) != 0)
return false;
}
return true;
diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d
index e9cdb94..658beaf 100644
--- a/gcc/d/dmd/dsymbolsem.d
+++ b/gcc/d/dmd/dsymbolsem.d
@@ -38,11 +38,13 @@ import dmd.dstruct;
import dmd.dsymbol;
import dmd.dtemplate;
import dmd.dversion;
+import dmd.enumsem;
import dmd.errors;
import dmd.escape;
import dmd.expression;
import dmd.expressionsem;
import dmd.func;
+import dmd.funcsem;
import dmd.globals;
import dmd.id;
import dmd.identifier;
@@ -440,6 +442,15 @@ private bool checkDeprecatedAliasThis(AliasThis at, const ref Loc loc, Scope* sc
return false;
}
+// Save the scope and defer semantic analysis on the Dsymbol.
+void deferDsymbolSemantic(Scope* sc, Dsymbol s, Scope *scx)
+{
+ s._scope = scx ? scx : sc.copy();
+ s._scope.setNoFree();
+ Module.addDeferredSemantic(s);
+}
+
+
private extern(C++) final class DsymbolSemanticVisitor : Visitor
{
alias visit = Visitor.visit;
@@ -450,14 +461,6 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
this.sc = sc;
}
- // Save the scope and defer semantic analysis on the Dsymbol.
- private void deferDsymbolSemantic(Dsymbol s, Scope *scx)
- {
- s._scope = scx ? scx : sc.copy();
- s._scope.setNoFree();
- Module.addDeferredSemantic(s);
- }
-
override void visit(Dsymbol dsym)
{
.error(dsym.loc, "%s `%s` %p has no semantic routine", dsym.kind, dsym.toPrettyChars, dsym);
@@ -2301,543 +2304,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
override void visit(EnumDeclaration ed)
{
- //printf("EnumDeclaration::semantic(sd = %p, '%s') %s\n", sc.scopesym, sc.scopesym.toChars(), ed.toChars());
- //printf("EnumDeclaration::semantic() %p %s\n", ed, ed.toChars());
- if (ed.semanticRun >= PASS.semanticdone)
- return; // semantic() already completed
- if (ed.semanticRun == PASS.semantic)
- {
- assert(ed.memtype);
- error(ed.loc, "circular reference to enum base type `%s`", ed.memtype.toChars());
- ed.errors = true;
- ed.semanticRun = PASS.semanticdone;
- return;
- }
- Scope* scx = null;
- if (ed._scope)
- {
- sc = ed._scope;
- scx = ed._scope; // save so we don't make redundant copies
- ed._scope = null;
- }
-
- if (!sc)
- return;
-
- ed.parent = sc.parent;
- ed.type = ed.type.typeSemantic(ed.loc, sc);
-
- ed.visibility = sc.visibility;
- if (sc.stc & STC.deprecated_)
- ed.isdeprecated = true;
- ed.userAttribDecl = sc.userAttribDecl;
- ed.cppnamespace = sc.namespace;
-
- ed.semanticRun = PASS.semantic;
- UserAttributeDeclaration.checkGNUABITag(ed, sc.linkage);
- checkMustUseReserved(ed);
-
- if (!ed.members && !ed.memtype) // enum ident;
- {
- ed.semanticRun = PASS.semanticdone;
- return;
- }
-
- if (!ed.symtab)
- ed.symtab = new DsymbolTable();
-
- /* The separate, and distinct, cases are:
- * 1. enum { ... }
- * 2. enum : memtype { ... }
- * 3. enum ident { ... }
- * 4. enum ident : memtype { ... }
- * 5. enum ident : memtype;
- * 6. enum ident;
- */
-
- if (ed.memtype)
- {
- ed.memtype = ed.memtype.typeSemantic(ed.loc, sc);
-
- /* Check to see if memtype is forward referenced
- */
- if (auto te = ed.memtype.isTypeEnum())
- {
- auto sym = te.toDsymbol(sc).isEnumDeclaration();
- // Special enums like __c_[u]long[long] are fine to forward reference
- // see https://issues.dlang.org/show_bug.cgi?id=20599
- if (!sym.isSpecial() && (!sym.memtype || !sym.members || !sym.symtab || sym._scope))
- {
- // memtype is forward referenced, so try again later
- deferDsymbolSemantic(ed, scx);
- //printf("\tdeferring %s\n", toChars());
- ed.semanticRun = PASS.initial;
- return;
- }
- else
- // Ensure that semantic is run to detect. e.g. invalid forward references
- sym.dsymbolSemantic(sc);
- }
- if (ed.memtype.ty == Tvoid)
- {
- .error(ed.loc, "%s `%s` base type must not be `void`", ed.kind, ed.toPrettyChars);
- ed.memtype = Type.terror;
- }
- if (ed.memtype.ty == Terror)
- {
- ed.errors = true;
- // poison all the members
- ed.members.foreachDsymbol( (s) { s.errors = true; } );
- ed.semanticRun = PASS.semanticdone;
- return;
- }
- }
-
- if (!ed.members) // enum ident : memtype;
- {
- ed.semanticRun = PASS.semanticdone;
- return;
- }
-
- if (ed.members.length == 0)
- {
- .error(ed.loc, "%s `%s enum `%s` must have at least one member", ed.kind, ed.toPrettyChars, ed.toChars());
- ed.errors = true;
- ed.semanticRun = PASS.semanticdone;
- return;
- }
-
- if (!(sc.flags & SCOPE.Cfile)) // C enum remains incomplete until members are done
- ed.semanticRun = PASS.semanticdone;
-
- version (none)
- {
- // @@@DEPRECATED_2.110@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint
- // Deprecated in 2.100
- // Make an error in 2.110
- if (sc.stc & STC.scope_)
- deprecation(ed.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site.");
- }
-
- Scope* sce;
- if (ed.isAnonymous())
- sce = sc;
- else
- {
- sce = sc.push(ed);
- sce.parent = ed;
- }
- sce = sce.startCTFE();
- sce.setNoFree(); // needed for getMaxMinValue()
-
- /* Each enum member gets the sce scope
- */
- ed.members.foreachDsymbol( (s)
- {
- EnumMember em = s.isEnumMember();
- if (em)
- em._scope = sce;
- });
-
- /* addMember() is not called when the EnumDeclaration appears as a function statement,
- * so we have to do what addMember() does and install the enum members in the right symbol
- * table
- */
- addEnumMembersToSymtab(ed, sc, sc.getScopesym());
-
- if (sc.flags & SCOPE.Cfile)
- {
- /* C11 6.7.2.2
- */
- Type commonType = ed.memtype;
- if (!commonType)
- commonType = Type.tint32;
- ulong nextValue = 0; // C11 6.7.2.2-3 first member value defaults to 0
-
- // C11 6.7.2.2-2 value must be representable as an int.
- // The sizemask represents all values that int will fit into,
- // from 0..uint.max. We want to cover int.min..uint.max.
- IntRange ir = IntRange.fromType(commonType);
-
- void emSemantic(EnumMember em, ref ulong nextValue)
- {
- static void errorReturn(EnumMember em)
- {
- em.value = ErrorExp.get();
- em.errors = true;
- em.semanticRun = PASS.semanticdone;
- }
-
- em.semanticRun = PASS.semantic;
- em.type = commonType;
- em._linkage = LINK.c;
- em.storage_class |= STC.manifest;
- if (em.value)
- {
- Expression e = em.value;
- assert(e.dyncast() == DYNCAST.expression);
-
- /* To merge the type of e with commonType, add 0 of type commonType
- */
- if (!ed.memtype)
- e = new AddExp(em.loc, e, new IntegerExp(em.loc, 0, commonType));
-
- e = e.expressionSemantic(sc);
- e = resolveProperties(sc, e);
- e = e.integralPromotions(sc);
- e = e.ctfeInterpret();
- if (e.op == EXP.error)
- return errorReturn(em);
- auto ie = e.isIntegerExp();
- if (!ie)
- {
- // C11 6.7.2.2-2
- .error(em.loc, "%s `%s` enum member must be an integral constant expression, not `%s` of type `%s`", em.kind, em.toPrettyChars, e.toChars(), e.type.toChars());
- return errorReturn(em);
- }
- if (ed.memtype && !ir.contains(getIntRange(ie)))
- {
- // C11 6.7.2.2-2
- .error(em.loc, "%s `%s` enum member value `%s` does not fit in `%s`", em.kind, em.toPrettyChars, e.toChars(), commonType.toChars());
- return errorReturn(em);
- }
- nextValue = ie.toInteger();
- if (!ed.memtype)
- commonType = e.type;
- em.value = new IntegerExp(em.loc, nextValue, commonType);
- }
- else
- {
- // C11 6.7.2.2-3 add 1 to value of previous enumeration constant
- bool first = (em == (*em.ed.members)[0]);
- if (!first)
- {
- Expression max = getProperty(commonType, null, em.loc, Id.max, 0);
- if (nextValue == max.toInteger())
- {
- .error(em.loc, "%s `%s` initialization with `%s+1` causes overflow for type `%s`", em.kind, em.toPrettyChars, max.toChars(), commonType.toChars());
- return errorReturn(em);
- }
- nextValue += 1;
- }
- em.value = new IntegerExp(em.loc, nextValue, commonType);
- }
- em.type = commonType;
- em.semanticRun = PASS.semanticdone;
- }
-
- ed.members.foreachDsymbol( (s)
- {
- if (EnumMember em = s.isEnumMember())
- emSemantic(em, nextValue);
- });
-
- if (!ed.memtype)
- {
- // cast all members to commonType
- ed.members.foreachDsymbol( (s)
- {
- if (EnumMember em = s.isEnumMember())
- {
- em.type = commonType;
- em.value = em.value.castTo(sc, commonType);
- }
- });
- }
-
- ed.memtype = commonType;
- ed.semanticRun = PASS.semanticdone;
- return;
- }
-
- ed.members.foreachDsymbol( (s)
- {
- if (EnumMember em = s.isEnumMember())
- em.dsymbolSemantic(em._scope);
- });
- //printf("defaultval = %lld\n", defaultval);
-
- //if (defaultval) printf("defaultval: %s %s\n", defaultval.toChars(), defaultval.type.toChars());
- //printf("members = %s\n", members.toChars());
+ enumSemantic(sc, ed);
}
override void visit(EnumMember em)
{
- //printf("EnumMember::semantic() %s\n", em.toChars());
-
- void errorReturn()
- {
- em.errors = true;
- em.semanticRun = PASS.semanticdone;
- }
-
- if (em.errors || em.semanticRun >= PASS.semanticdone)
- return;
- if (em.semanticRun == PASS.semantic)
- {
- .error(em.loc, "%s `%s` circular reference to `enum` member", em.kind, em.toPrettyChars);
- return errorReturn();
- }
- assert(em.ed);
-
- em.ed.dsymbolSemantic(sc);
- if (em.ed.errors)
- return errorReturn();
- if (em.errors || em.semanticRun >= PASS.semanticdone)
- return;
-
- if (em._scope)
- sc = em._scope;
- if (!sc)
- return;
-
- em.semanticRun = PASS.semantic;
-
- em.visibility = em.ed.isAnonymous() ? em.ed.visibility : Visibility(Visibility.Kind.public_);
- em._linkage = LINK.d;
- em.storage_class |= STC.manifest;
-
- // https://issues.dlang.org/show_bug.cgi?id=9701
- if (em.ed.isAnonymous())
- {
- if (em.userAttribDecl)
- em.userAttribDecl.userAttribDecl = em.ed.userAttribDecl;
- else
- em.userAttribDecl = em.ed.userAttribDecl;
- }
-
- // Eval UDA in this same scope. Issues 19344, 20835, 21122
- if (em.userAttribDecl)
- {
- // Set scope but avoid extra sc.uda attachment inside setScope()
- auto inneruda = em.userAttribDecl.userAttribDecl;
- em.userAttribDecl.setScope(sc);
- em.userAttribDecl.userAttribDecl = inneruda;
- em.userAttribDecl.dsymbolSemantic(sc);
- }
-
- // The first enum member is special
- bool first = (em == (*em.ed.members)[0]);
-
- if (em.origType)
- {
- em.origType = em.origType.typeSemantic(em.loc, sc);
- em.type = em.origType;
- assert(em.value); // "type id;" is not a valid enum member declaration
- }
-
- if (em.value)
- {
- Expression e = em.value;
- assert(e.dyncast() == DYNCAST.expression);
- e = e.expressionSemantic(sc);
- e = resolveProperties(sc, e);
- e = e.ctfeInterpret();
- if (e.op == EXP.error)
- return errorReturn();
- if (first && !em.ed.memtype && !em.ed.isAnonymous())
- {
- em.ed.memtype = e.type;
- if (em.ed.memtype.ty == Terror)
- {
- em.ed.errors = true;
- return errorReturn();
- }
- if (em.ed.memtype.ty != Terror)
- {
- /* https://issues.dlang.org/show_bug.cgi?id=11746
- * All of named enum members should have same type
- * with the first member. If the following members were referenced
- * during the first member semantic, their types should be unified.
- */
- em.ed.members.foreachDsymbol( (s)
- {
- EnumMember enm = s.isEnumMember();
- if (!enm || enm == em || enm.semanticRun < PASS.semanticdone || enm.origType)
- return;
-
- //printf("[%d] em = %s, em.semanticRun = %d\n", i, toChars(), em.semanticRun);
- Expression ev = enm.value;
- ev = ev.implicitCastTo(sc, em.ed.memtype);
- ev = ev.ctfeInterpret();
- ev = ev.castTo(sc, em.ed.type);
- if (ev.op == EXP.error)
- em.ed.errors = true;
- enm.value = ev;
- });
-
- if (em.ed.errors)
- {
- em.ed.memtype = Type.terror;
- return errorReturn();
- }
- }
- }
-
- if (em.ed.memtype && !em.origType)
- {
- e = e.implicitCastTo(sc, em.ed.memtype);
- e = e.ctfeInterpret();
-
- // save origValue for better json output
- em.origValue = e;
-
- if (!em.ed.isAnonymous())
- {
- e = e.castTo(sc, em.ed.type.addMod(e.type.mod)); // https://issues.dlang.org/show_bug.cgi?id=12385
- e = e.ctfeInterpret();
- }
- }
- else if (em.origType)
- {
- e = e.implicitCastTo(sc, em.origType);
- e = e.ctfeInterpret();
- assert(em.ed.isAnonymous());
-
- // save origValue for better json output
- em.origValue = e;
- }
- em.value = e;
- }
- else if (first)
- {
- Type t;
- if (em.ed.memtype)
- t = em.ed.memtype;
- else
- {
- t = Type.tint32;
- if (!em.ed.isAnonymous())
- em.ed.memtype = t;
- }
- const errors = global.startGagging();
- Expression e = new IntegerExp(em.loc, 0, t);
- e = e.ctfeInterpret();
- if (global.endGagging(errors))
- {
- error(em.loc, "cannot generate 0 value of type `%s` for `%s`",
- t.toChars(), em.toChars());
- }
- // save origValue for better json output
- em.origValue = e;
-
- if (!em.ed.isAnonymous())
- {
- e = e.castTo(sc, em.ed.type);
- e = e.ctfeInterpret();
- }
- em.value = e;
- }
- else
- {
- /* Find the previous enum member,
- * and set this to be the previous value + 1
- */
- EnumMember emprev = null;
- em.ed.members.foreachDsymbol( (s)
- {
- if (auto enm = s.isEnumMember())
- {
- if (enm == em)
- return 1; // found
- emprev = enm;
- }
- return 0; // continue
- });
-
- assert(emprev);
- if (emprev.semanticRun < PASS.semanticdone) // if forward reference
- emprev.dsymbolSemantic(emprev._scope); // resolve it
- if (emprev.errors)
- return errorReturn();
-
- auto errors = global.startGagging();
- Expression eprev = emprev.value;
- assert(eprev);
- // .toHeadMutable() due to https://issues.dlang.org/show_bug.cgi?id=18645
- Type tprev = eprev.type.toHeadMutable().equals(em.ed.type.toHeadMutable())
- ? em.ed.memtype
- : eprev.type;
- /*
- https://issues.dlang.org/show_bug.cgi?id=20777
- Previously this used getProperty, which doesn't consider anything user defined,
- this construct does do that and thus fixes the bug.
- */
- Expression emax = DotIdExp.create(em.ed.loc, new TypeExp(em.ed.loc, tprev), Id.max);
- emax = emax.expressionSemantic(sc);
- emax = emax.ctfeInterpret();
-
- // check that (eprev != emax)
- Expression e = new EqualExp(EXP.equal, em.loc, eprev, emax);
- e = e.expressionSemantic(sc);
- e = e.ctfeInterpret();
- if (global.endGagging(errors))
- {
- // display an introductory error before showing what actually failed
- error(em.loc, "cannot check `%s` value for overflow", em.toPrettyChars());
- // rerun to show errors
- Expression e2 = DotIdExp.create(em.ed.loc, new TypeExp(em.ed.loc, tprev), Id.max);
- e2 = e2.expressionSemantic(sc);
- e2 = e2.ctfeInterpret();
- e2 = new EqualExp(EXP.equal, em.loc, eprev, e2);
- e2 = e2.expressionSemantic(sc);
- e2 = e2.ctfeInterpret();
- }
- // now any errors are for generating a value
- if (e.toInteger())
- {
- auto mt = em.ed.memtype;
- if (!mt)
- mt = eprev.type;
- .error(em.loc, "%s `%s` initialization with `%s.%s+1` causes overflow for type `%s`", em.kind, em.toPrettyChars,
- emprev.ed.toChars(), emprev.toChars(), mt.toChars());
- return errorReturn();
- }
- errors = global.startGagging();
- // Now set e to (eprev + 1)
- e = new AddExp(em.loc, eprev, IntegerExp.literal!1);
- e = e.expressionSemantic(sc);
- e = e.castTo(sc, eprev.type);
- e = e.ctfeInterpret();
- if (global.endGagging(errors))
- {
- error(em.loc, "cannot generate value for `%s`", em.toPrettyChars());
- // rerun to show errors
- Expression e2 = new AddExp(em.loc, eprev, IntegerExp.literal!1);
- e2 = e2.expressionSemantic(sc);
- e2 = e2.castTo(sc, eprev.type);
- e2 = e2.ctfeInterpret();
- }
- // save origValue (without cast) for better json output
- if (e.op != EXP.error) // avoid duplicate diagnostics
- {
- assert(emprev.origValue);
- em.origValue = new AddExp(em.loc, emprev.origValue, IntegerExp.literal!1);
- em.origValue = em.origValue.expressionSemantic(sc);
- em.origValue = em.origValue.ctfeInterpret();
- }
-
- if (e.op == EXP.error)
- return errorReturn();
- if (e.type.isfloating())
- {
- // Check that e != eprev (not always true for floats)
- Expression etest = new EqualExp(EXP.equal, em.loc, e, eprev);
- etest = etest.expressionSemantic(sc);
- etest = etest.ctfeInterpret();
- if (etest.toInteger())
- {
- .error(em.loc, "%s `%s` has inexact value due to loss of precision", em.kind, em.toPrettyChars);
- return errorReturn();
- }
- }
- em.value = e;
- }
- if (!em.origType)
- em.type = em.value.type;
-
- assert(em.origValue);
- em.semanticRun = PASS.semanticdone;
+ enumMemberSemantic(sc, em);
}
override void visit(TemplateDeclaration tempdecl)
@@ -3026,7 +2498,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
if (tm.semanticRun == PASS.initial) // forward reference had occurred
{
//printf("forward reference - deferring\n");
- return deferDsymbolSemantic(tm, scx);
+ return deferDsymbolSemantic(sc, tm, scx);
}
tm.inst = tm;
@@ -3740,7 +3212,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
continue;
if (cbd.parent && cbd.parent.isTemplateInstance())
{
- if (!f2.functionSemantic())
+ if (!functionSemantic(f2))
goto Ldone;
}
may_override = true;
@@ -4945,7 +4417,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
sc2.pop();
if (log) printf("\tdeferring %s\n", sd.toChars());
- return deferDsymbolSemantic(sd, scx);
+ return deferDsymbolSemantic(sc, sd, scx);
}
/* Look for special member functions.
@@ -5336,7 +4808,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
{
// Forward referencee of one or more bases, try again later
//printf("\tL%d semantic('%s') failed due to forward references\n", __LINE__, toChars());
- return deferDsymbolSemantic(cldec, scx);
+ return deferDsymbolSemantic(sc, cldec, scx);
}
cldec.baseok = Baseok.done;
@@ -5446,7 +4918,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
if (tc.sym._scope)
Module.addDeferredSemantic(tc.sym);
//printf("\tL%d semantic('%s') failed due to forward references\n", __LINE__, toChars());
- return deferDsymbolSemantic(cldec, scx);
+ return deferDsymbolSemantic(sc, cldec, scx);
}
}
@@ -5563,7 +5035,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
sc2.pop();
//printf("\tdeferring %s\n", toChars());
- return deferDsymbolSemantic(cldec, scx);
+ return deferDsymbolSemantic(sc, cldec, scx);
}
/* Look for special member functions.
@@ -5905,7 +5377,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
if (idec.baseok == Baseok.none)
{
// Forward referencee of one or more bases, try again later
- return deferDsymbolSemantic(idec, scx);
+ return deferDsymbolSemantic(sc, idec, scx);
}
idec.baseok = Baseok.done;
@@ -5942,7 +5414,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
// Forward referencee of one or more bases, try again later
if (tc.sym._scope)
Module.addDeferredSemantic(tc.sym);
- return deferDsymbolSemantic(idec, scx);
+ return deferDsymbolSemantic(sc, idec, scx);
}
}
@@ -6281,7 +5753,7 @@ private extern(C++) class AddMemberVisitor : Visitor
}
else
{
- if (findCondition(m.debugidsNot, ds.ident))
+ if (m.debugidsNot && findCondition(*m.debugidsNot, ds.ident))
{
.error(ds.loc, "%s `%s` defined after use", ds.kind, ds.toPrettyChars);
ds.errors = true;
@@ -6319,7 +5791,7 @@ private extern(C++) class AddMemberVisitor : Visitor
}
else
{
- if (findCondition(m.versionidsNot, vs.ident))
+ if (m.versionidsNot && findCondition(*m.versionidsNot, vs.ident))
{
.error(vs.loc, "%s `%s` defined after use", vs.kind, vs.toPrettyChars);
vs.errors = true;
diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d
index 13cc32f..465ae74 100644
--- a/gcc/d/dmd/dtemplate.d
+++ b/gcc/d/dmd/dtemplate.d
@@ -60,6 +60,7 @@ import dmd.errorsink;
import dmd.expression;
import dmd.expressionsem;
import dmd.func;
+import dmd.funcsem;
import dmd.globals;
import dmd.hdrgen;
import dmd.id;
@@ -76,6 +77,7 @@ import dmd.common.outbuffer;
import dmd.rootobject;
import dmd.semantic2;
import dmd.semantic3;
+import dmd.templatesem;
import dmd.tokens;
import dmd.typesem;
import dmd.visitor;
@@ -373,7 +375,7 @@ Lnomatch:
/************************************
* Match an array of them.
*/
-private bool arrayObjectMatch(ref Objects oa1, ref Objects oa2)
+bool arrayObjectMatch(ref Objects oa1, ref Objects oa2)
{
if (&oa1 == &oa2)
return true;
@@ -586,9 +588,9 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
// threaded list of previous instantiation attempts on stack
TemplatePrevious* previous;
- private Expression lastConstraint; /// the constraint after the last failed evaluation
- private Array!Expression lastConstraintNegs; /// its negative parts
- private Objects* lastConstraintTiargs; /// template instance arguments for `lastConstraint`
+ Expression lastConstraint; /// the constraint after the last failed evaluation
+ Array!Expression lastConstraintNegs; /// its negative parts
+ Objects* lastConstraintTiargs; /// template instance arguments for `lastConstraint`
extern (D) this(const ref Loc loc, Identifier ident, TemplateParameters* parameters, Expression constraint, Dsymbols* decldefs, bool ismixin = false, bool literal = false)
{
@@ -743,59 +745,9 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
override const(char)* toChars() const
{
- return toCharsMaybeConstraints(true);
- }
-
- /****************************
- * Similar to `toChars`, but does not print the template constraints
- */
- const(char)* toCharsNoConstraints() const
- {
- 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;
HdrGenState hgs;
-
- buf.writestring(ident == Id.ctor ? "this" : ident.toString());
- buf.writeByte('(');
- foreach (i, const tp; *parameters)
- {
- if (i)
- buf.writestring(", ");
- toCBuffer(tp, buf, hgs);
- }
- buf.writeByte(')');
-
- if (onemember)
- {
- if (const fd = onemember.isFuncDeclaration())
- {
- if (TypeFunction tf = cast(TypeFunction)fd.type.isTypeFunction())
- {
- // !! Casted away const
- buf.writestring(parametersTypeToChars(tf.parameterList));
- if (tf.mod)
- {
- buf.writeByte(' ');
- buf.MODtoBuffer(tf.mod);
- }
- }
- }
- }
-
- if (includeConstraints &&
- constraint)
- {
- buf.writestring(" if (");
- toCBuffer(constraint, buf, hgs);
- buf.writeByte(')');
- }
-
+ OutBuffer buf;
+ toCharsMaybeConstraints(this, buf, hgs);
return buf.extractChars();
}
@@ -805,132 +757,6 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
}
/****************************
- * Check to see if constraint is satisfied.
- */
- 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
- * void foo(T)(T x) if (is(typeof(foo(x)))) { }
- * static assert(!is(typeof(foo(7))));
- * Recursive attempts are regarded as a constraint failure.
- */
- /* There's a chicken-and-egg problem here. We don't know yet if this template
- * instantiation will be a local one (enclosing is set), and we won't know until
- * after selecting the correct template. Thus, function we're nesting inside
- * is not on the sc scope chain, and this can cause errors in FuncDeclaration.getLevel().
- * Workaround the problem by setting a flag to relax the checking on frame errors.
- */
-
- for (TemplatePrevious* p = previous; p; p = p.prev)
- {
- 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
- * instantiations.
- * the chain of enclosing scopes is broken by paramscope (its enclosing
- * scope is _scope, but paramscope.callsc is the instantiating scope). So
- * it's good enough to check the chain of callsc
- */
- for (Scope* scx = paramscope.callsc; scx; scx = scx.callsc)
- {
- // The first scx might be identical for nested eponymeous templates, e.g.
- // template foo() { void foo()() {...} }
- if (scx == p.sc && scx !is paramscope.callsc)
- return false;
- }
- /* BUG: should also check for ref param differences
- */
- }
-
- TemplatePrevious pr;
- pr.prev = previous;
- pr.sc = paramscope.callsc;
- pr.dedargs = dedargs;
- previous = &pr; // add this to threaded list
-
- Scope* scx = paramscope.push(ti);
- scx.parent = ti;
- scx.tinst = null;
- scx.minst = null;
- // Set SCOPE.constraint before declaring function parameters for the static condition
- // (previously, this was immediately before calling evalStaticCondition), so the
- // semantic pass knows not to issue deprecation warnings for these throw-away decls.
- // https://issues.dlang.org/show_bug.cgi?id=21831
- scx.flags |= SCOPE.constraint;
-
- assert(!ti.symtab);
- if (fd)
- {
- /* Declare all the function parameters as variables and add them to the scope
- * Making parameters is similar to FuncDeclaration.semantic3
- */
- auto tf = fd.type.isTypeFunction();
-
- scx.parent = fd;
-
- Parameters* fparameters = tf.parameterList.parameters;
- const nfparams = tf.parameterList.length;
- foreach (i, fparam; tf.parameterList)
- {
- fparam.storageClass &= (STC.IOR | STC.lazy_ | STC.final_ | STC.TYPECTOR | STC.nodtor);
- fparam.storageClass |= STC.parameter;
- if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nfparams)
- {
- fparam.storageClass |= STC.variadic;
- /* Don't need to set STC.scope_ because this will only
- * be evaluated at compile time
- */
- }
- }
- foreach (fparam; *fparameters)
- {
- if (!fparam.ident)
- continue;
- // don't add it, if it has no name
- auto v = new VarDeclaration(fparam.loc, fparam.type, fparam.ident, null);
- fparam.storageClass |= STC.parameter;
- v.storage_class = fparam.storageClass;
- v.dsymbolSemantic(scx);
- if (!ti.symtab)
- ti.symtab = new DsymbolTable();
- if (!scx.insert(v))
- .error(loc, "%s `%s` parameter `%s.%s` is already defined", kind, toPrettyChars, toChars(), v.toChars());
- else
- v.parent = fd;
- }
- if (isstatic)
- fd.storage_class |= STC.static_;
- fd.declareThis(scx);
- }
-
- lastConstraint = constraint.syntaxCopy();
- lastConstraintTiargs = ti.tiargs;
- lastConstraintNegs.setDim(0);
-
- import dmd.staticcond;
-
- assert(ti.inst is null);
- ti.inst = ti; // temporary instantiation to enable genIdent()
- bool errors;
- const bool result = evalStaticCondition(scx, constraint, lastConstraint, errors, &lastConstraintNegs);
- if (result || errors)
- {
- lastConstraint = null;
- lastConstraintTiargs = null;
- lastConstraintNegs.setDim(0);
- }
- ti.inst = null;
- ti.symtab = null;
- scx = scx.pop();
- previous = pr.prev; // unlink from threaded list
- if (errors)
- return false;
- return result;
- }
-
- /****************************
* Destructively get the error message from the last constraint evaluation
* Params:
* tip = tip to show after printing all overloads
@@ -957,7 +783,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
assert(parameters && lastConstraintTiargs);
if (parameters.length > 0)
{
- formatParamsWithTiargs(*lastConstraintTiargs, buf);
+ formatParamsWithTiargs(*parameters, *lastConstraintTiargs, isVariadic() !is null, buf);
buf.writenl();
}
if (!full)
@@ -990,1300 +816,6 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
return buf.extractChars();
}
- private void formatParamsWithTiargs(ref Objects tiargs, ref OutBuffer buf)
- {
- buf.writestring(" with `");
-
- // write usual arguments line-by-line
- // skips trailing default ones - they are not present in `tiargs`
- const bool variadic = isVariadic() !is null;
- const end = cast(int)parameters.length - (variadic ? 1 : 0);
- uint i;
- for (; i < tiargs.length && i < end; i++)
- {
- if (i > 0)
- {
- buf.writeByte(',');
- buf.writenl();
- buf.writestring(" ");
- }
- write(buf, (*parameters)[i]);
- buf.writestring(" = ");
- write(buf, tiargs[i]);
- }
- // write remaining variadic arguments on the last line
- if (variadic)
- {
- if (i > 0)
- {
- buf.writeByte(',');
- buf.writenl();
- buf.writestring(" ");
- }
- write(buf, (*parameters)[end]);
- buf.writestring(" = ");
- buf.writeByte('(');
- if (cast(int)tiargs.length - end > 0)
- {
- write(buf, tiargs[end]);
- foreach (j; parameters.length .. tiargs.length)
- {
- buf.writestring(", ");
- write(buf, tiargs[j]);
- }
- }
- buf.writeByte(')');
- }
- buf.writeByte('`');
- }
-
- /******************************
- * Create a scope for the parameters of the TemplateInstance
- * `ti` in the parent scope sc from the ScopeDsymbol paramsym.
- *
- * If paramsym is null a new ScopeDsymbol is used in place of
- * paramsym.
- * Params:
- * ti = the TemplateInstance whose parameters to generate the scope for.
- * sc = the parent scope of ti
- * Returns:
- * a scope for the parameters of ti
- */
- Scope* scopeForTemplateParameters(TemplateInstance ti, Scope* sc)
- {
- ScopeDsymbol paramsym = new ScopeDsymbol();
- paramsym.parent = _scope.parent;
- Scope* paramscope = _scope.push(paramsym);
- paramscope.tinst = ti;
- paramscope.minst = sc.minst;
- paramscope.callsc = sc;
- paramscope.stc = 0;
- return paramscope;
- }
-
- /***************************************
- * Given that ti is an instance of this TemplateDeclaration,
- * deduce the types of the parameters to this, and store
- * those deduced types in dedtypes[].
- * Input:
- * flag 1: don't do semantic() because of dummy types
- * 2: don't change types in matchArg()
- * Output:
- * dedtypes deduced arguments
- * Return match level.
- */
- private MATCH matchWithInstance(Scope* sc, TemplateInstance ti, ref Objects dedtypes, ArgumentList argumentList, int flag)
- {
- enum LOGM = 0;
- static if (LOGM)
- {
- printf("\n+TemplateDeclaration.matchWithInstance(this = %s, ti = %s, flag = %d)\n", toChars(), ti.toChars(), flag);
- }
- version (none)
- {
- printf("dedtypes.length = %d, parameters.length = %d\n", dedtypes.length, parameters.length);
- if (ti.tiargs.length)
- printf("ti.tiargs.length = %d, [0] = %p\n", ti.tiargs.length, (*ti.tiargs)[0]);
- }
- MATCH nomatch()
- {
- static if (LOGM)
- {
- printf(" no match\n");
- }
- return MATCH.nomatch;
- }
- MATCH m;
- size_t dedtypes_dim = dedtypes.length;
-
- dedtypes.zero();
-
- if (errors)
- return MATCH.nomatch;
-
- size_t parameters_dim = parameters.length;
- int variadic = isVariadic() !is null;
-
- // If more arguments than parameters, no match
- if (ti.tiargs.length > parameters_dim && !variadic)
- {
- static if (LOGM)
- {
- printf(" no match: more arguments than parameters\n");
- }
- return MATCH.nomatch;
- }
-
- assert(dedtypes_dim == parameters_dim);
- assert(dedtypes_dim >= ti.tiargs.length || variadic);
-
- assert(_scope);
-
- // Set up scope for template parameters
- Scope* paramscope = scopeForTemplateParameters(ti,sc);
-
- // Attempt type deduction
- m = MATCH.exact;
- for (size_t i = 0; i < dedtypes_dim; i++)
- {
- MATCH m2;
- TemplateParameter tp = (*parameters)[i];
- Declaration sparam;
-
- //printf("\targument [%d]\n", i);
- static if (LOGM)
- {
- //printf("\targument [%d] is %s\n", i, oarg ? oarg.toChars() : "null");
- TemplateTypeParameter ttp = tp.isTemplateTypeParameter();
- if (ttp)
- printf("\tparameter[%d] is %s : %s\n", i, tp.ident.toChars(), ttp.specType ? ttp.specType.toChars() : "");
- }
-
- m2 = tp.matchArg(ti.loc, paramscope, ti.tiargs, i, parameters, dedtypes, &sparam);
- //printf("\tm2 = %d\n", m2);
- if (m2 == MATCH.nomatch)
- {
- version (none)
- {
- printf("\tmatchArg() for parameter %i failed\n", i);
- }
- return nomatch();
- }
-
- if (m2 < m)
- m = m2;
-
- if (!flag)
- sparam.dsymbolSemantic(paramscope);
- if (!paramscope.insert(sparam)) // TODO: This check can make more early
- {
- // in TemplateDeclaration.semantic, and
- // then we don't need to make sparam if flags == 0
- return nomatch();
- }
- }
-
- if (!flag)
- {
- /* Any parameter left without a type gets the type of
- * its corresponding arg
- */
- foreach (i, ref dedtype; dedtypes)
- {
- if (!dedtype)
- {
- assert(i < ti.tiargs.length);
- dedtype = cast(Type)(*ti.tiargs)[i];
- }
- }
- }
-
- if (m > MATCH.nomatch && constraint && !flag)
- {
- if (ti.hasNestedArgs(ti.tiargs, this.isstatic)) // TODO: should gag error
- ti.parent = ti.enclosing;
- else
- ti.parent = this.parent;
-
- // Similar to doHeaderInstantiation
- FuncDeclaration fd = onemember ? onemember.isFuncDeclaration() : null;
- if (fd)
- {
- TypeFunction tf = fd.type.isTypeFunction().syntaxCopy();
- if (argumentList.hasNames)
- return nomatch();
- Expressions* fargs = argumentList.arguments;
- // TODO: Expressions* fargs = tf.resolveNamedArgs(argumentList, null);
- // if (!fargs)
- // return nomatch();
-
- fd = new FuncDeclaration(fd.loc, fd.endloc, fd.ident, fd.storage_class, tf);
- fd.parent = ti;
- fd.inferRetType = true;
-
- // Shouldn't run semantic on default arguments and return type.
- foreach (ref param; *tf.parameterList.parameters)
- param.defaultArg = null;
-
- tf.next = null;
- tf.incomplete = true;
-
- // Resolve parameter types and 'auto ref's.
- tf.fargs = fargs;
- uint olderrors = global.startGagging();
- fd.type = tf.typeSemantic(loc, paramscope);
- global.endGagging(olderrors);
- if (fd.type.ty != Tfunction)
- return nomatch();
- fd.originalType = fd.type; // for mangling
- }
-
- // TODO: dedtypes => ti.tiargs ?
- if (!evaluateConstraint(ti, sc, paramscope, &dedtypes, fd))
- return nomatch();
- }
-
- static if (LOGM)
- {
- // Print out the results
- printf("--------------------------\n");
- printf("template %s\n", toChars());
- printf("instance %s\n", ti.toChars());
- if (m > MATCH.nomatch)
- {
- for (size_t i = 0; i < dedtypes_dim; i++)
- {
- TemplateParameter tp = (*parameters)[i];
- RootObject oarg;
- printf(" [%d]", i);
- if (i < ti.tiargs.length)
- oarg = (*ti.tiargs)[i];
- else
- oarg = null;
- tp.print(oarg, (*dedtypes)[i]);
- }
- }
- else
- return nomatch();
- }
- static if (LOGM)
- {
- printf(" match = %d\n", m);
- }
-
- paramscope.pop();
- static if (LOGM)
- {
- printf("-TemplateDeclaration.matchWithInstance(this = %s, ti = %s) = %d\n", toChars(), ti.toChars(), m);
- }
- return m;
- }
-
- /********************************************
- * Determine partial specialization order of 'this' vs td2.
- * Returns:
- * match this is at least as specialized as td2
- * 0 td2 is more specialized than this
- */
- extern (D) MATCH leastAsSpecialized(Scope* sc, TemplateDeclaration td2, ArgumentList argumentList)
- {
- enum LOG_LEASTAS = 0;
- static if (LOG_LEASTAS)
- {
- printf("%s.leastAsSpecialized(%s)\n", toChars(), td2.toChars());
- }
-
- /* This works by taking the template parameters to this template
- * declaration and feeding them to td2 as if it were a template
- * instance.
- * If it works, then this template is at least as specialized
- * as td2.
- */
-
- // Set type arguments to dummy template instance to be types
- // generated from the parameters to this template declaration
- auto tiargs = new Objects();
- tiargs.reserve(parameters.length);
- foreach (tp; *parameters)
- {
- if (tp.dependent)
- break;
- RootObject p = tp.dummyArg();
- if (!p) //TemplateTupleParameter
- break;
-
- tiargs.push(p);
- }
- scope TemplateInstance ti = new TemplateInstance(Loc.initial, ident, tiargs); // create dummy template instance
-
- // Temporary Array to hold deduced types
- Objects dedtypes = Objects(td2.parameters.length);
-
- // Attempt a type deduction
- MATCH m = td2.matchWithInstance(sc, ti, dedtypes, argumentList, 1);
- if (m > MATCH.nomatch)
- {
- /* A non-variadic template is more specialized than a
- * variadic one.
- */
- TemplateTupleParameter tp = isVariadic();
- if (tp && !tp.dependent && !td2.isVariadic())
- goto L1;
-
- static if (LOG_LEASTAS)
- {
- printf(" matches %d, so is least as specialized\n", m);
- }
- return m;
- }
- L1:
- static if (LOG_LEASTAS)
- {
- printf(" doesn't match, so is not as specialized\n");
- }
- return MATCH.nomatch;
- }
-
- /*************************************************
- * Match function arguments against a specific template function.
- *
- * Params:
- * ti = template instance. `ti.tdtypes` will be set to Expression/Type deduced template arguments
- * sc = instantiation scope
- * fd = Partially instantiated function declaration, which is set to an instantiated function declaration
- * tthis = 'this' argument if !NULL
- * argumentList = arguments to function
- *
- * Returns:
- * match pair of initial and inferred template arguments
- */
- extern (D) MATCHpair deduceFunctionTemplateMatch(TemplateInstance ti, Scope* sc, ref FuncDeclaration fd, Type tthis, ArgumentList argumentList)
- {
- version (none)
- {
- printf("\nTemplateDeclaration.deduceFunctionTemplateMatch() %s\n", toChars());
- for (size_t i = 0; i < (fargs ? fargs.length : 0); i++)
- {
- Expression e = (*fargs)[i];
- printf("\tfarg[%d] is %s, type is %s\n", cast(int) i, e.toChars(), e.type.toChars());
- }
- printf("fd = %s\n", fd.toChars());
- printf("fd.type = %s\n", fd.type.toChars());
- if (tthis)
- printf("tthis = %s\n", tthis.toChars());
- }
-
- assert(_scope);
-
- auto dedargs = new Objects(parameters.length);
- dedargs.zero();
-
- Objects* dedtypes = &ti.tdtypes; // for T:T*, the dedargs is the T*, dedtypes is the T
- dedtypes.setDim(parameters.length);
- dedtypes.zero();
-
- if (errors || fd.errors)
- return MATCHpair(MATCH.nomatch, MATCH.nomatch);
-
- // Set up scope for parameters
- Scope* paramscope = scopeForTemplateParameters(ti,sc);
-
- MATCHpair nomatch()
- {
- paramscope.pop();
- //printf("\tnomatch\n");
- return MATCHpair(MATCH.nomatch, MATCH.nomatch);
- }
-
- MATCHpair matcherror()
- {
- // todo: for the future improvement
- paramscope.pop();
- //printf("\terror\n");
- return MATCHpair(MATCH.nomatch, MATCH.nomatch);
- }
- // Mark the parameter scope as deprecated if the templated
- // function is deprecated (since paramscope.enclosing is the
- // calling scope already)
- paramscope.stc |= fd.storage_class & STC.deprecated_;
-
- TemplateTupleParameter tp = isVariadic();
- Tuple declaredTuple = null;
-
- version (none)
- {
- for (size_t i = 0; i < dedargs.length; i++)
- {
- printf("\tdedarg[%d] = ", i);
- RootObject oarg = (*dedargs)[i];
- if (oarg)
- printf("%s", oarg.toChars());
- printf("\n");
- }
- }
-
- size_t ntargs = 0; // array size of tiargs
- size_t inferStart = 0; // index of first parameter to infer
- const Loc instLoc = ti.loc;
- MATCH matchTiargs = MATCH.exact;
-
- if (auto tiargs = ti.tiargs)
- {
- // Set initial template arguments
- ntargs = tiargs.length;
- size_t n = parameters.length;
- if (tp)
- n--;
- if (ntargs > n)
- {
- if (!tp)
- return nomatch();
-
- /* The extra initial template arguments
- * now form the tuple argument.
- */
- auto t = new Tuple(ntargs - n);
- assert(parameters.length);
- (*dedargs)[parameters.length - 1] = t;
-
- for (size_t i = 0; i < t.objects.length; i++)
- {
- t.objects[i] = (*tiargs)[n + i];
- }
- declareParameter(paramscope, tp, t);
- declaredTuple = t;
- }
- else
- n = ntargs;
-
- memcpy(dedargs.tdata(), tiargs.tdata(), n * (*dedargs.tdata()).sizeof);
-
- for (size_t i = 0; i < n; i++)
- {
- assert(i < parameters.length);
- Declaration sparam = null;
- MATCH m = (*parameters)[i].matchArg(instLoc, paramscope, dedargs, i, parameters, *dedtypes, &sparam);
- //printf("\tdeduceType m = %d\n", m);
- if (m == MATCH.nomatch)
- return nomatch();
- if (m < matchTiargs)
- matchTiargs = m;
-
- sparam.dsymbolSemantic(paramscope);
- if (!paramscope.insert(sparam))
- return nomatch();
- }
- if (n < parameters.length && !declaredTuple)
- {
- inferStart = n;
- }
- else
- inferStart = parameters.length;
- //printf("tiargs matchTiargs = %d\n", matchTiargs);
- }
- version (none)
- {
- for (size_t i = 0; i < dedargs.length; i++)
- {
- printf("\tdedarg[%d] = ", i);
- RootObject oarg = (*dedargs)[i];
- if (oarg)
- printf("%s", oarg.toChars());
- printf("\n");
- }
- }
-
- ParameterList fparameters = fd.getParameterList(); // function parameter list
- const nfparams = fparameters.length; // number of function parameters
- if (argumentList.hasNames)
- return matcherror(); // TODO: resolve named args
- Expression[] fargs = argumentList.arguments ? (*argumentList.arguments)[] : null;
-
- /* Check for match of function arguments with variadic template
- * parameter, such as:
- *
- * void foo(T, A...)(T t, A a);
- * void main() { foo(1,2,3); }
- */
- size_t fptupindex = IDX_NOTFOUND;
- if (tp) // if variadic
- {
- // TemplateTupleParameter always makes most lesser matching.
- matchTiargs = MATCH.convert;
-
- if (nfparams == 0 && argumentList.length != 0) // if no function parameters
- {
- if (!declaredTuple)
- {
- auto t = new Tuple();
- //printf("t = %p\n", t);
- (*dedargs)[parameters.length - 1] = t;
- declareParameter(paramscope, tp, t);
- declaredTuple = t;
- }
- }
- else
- {
- /* Figure out which of the function parameters matches
- * the tuple template parameter. Do this by matching
- * type identifiers.
- * Set the index of this function parameter to fptupindex.
- */
- for (fptupindex = 0; fptupindex < nfparams; fptupindex++)
- {
- auto fparam = (*fparameters.parameters)[fptupindex]; // fparameters[fptupindex] ?
- if (fparam.type.ty != Tident)
- continue;
- TypeIdentifier tid = fparam.type.isTypeIdentifier();
- if (!tp.ident.equals(tid.ident) || tid.idents.length)
- continue;
-
- if (fparameters.varargs != VarArg.none) // variadic function doesn't
- return nomatch(); // go with variadic template
-
- goto L1;
- }
- fptupindex = IDX_NOTFOUND;
- L1:
- }
- }
-
- MATCH match = MATCH.exact;
- if (toParent().isModule())
- tthis = null;
- if (tthis)
- {
- bool hasttp = false;
-
- // Match 'tthis' to any TemplateThisParameter's
- foreach (param; *parameters)
- {
- if (auto ttp = param.isTemplateThisParameter())
- {
- hasttp = true;
-
- Type t = new TypeIdentifier(Loc.initial, ttp.ident);
- MATCH m = deduceType(tthis, paramscope, t, *parameters, *dedtypes);
- if (m == MATCH.nomatch)
- return nomatch();
- if (m < match)
- match = m; // pick worst match
- }
- }
-
- // Match attributes of tthis against attributes of fd
- if (fd.type && !fd.isCtorDeclaration() && !(_scope.stc & STC.static_))
- {
- StorageClass stc = _scope.stc | fd.storage_class2;
- // Propagate parent storage class, https://issues.dlang.org/show_bug.cgi?id=5504
- Dsymbol p = parent;
- while (p.isTemplateDeclaration() || p.isTemplateInstance())
- p = p.parent;
- AggregateDeclaration ad = p.isAggregateDeclaration();
- if (ad)
- stc |= ad.storage_class;
-
- ubyte mod = fd.type.mod;
- if (stc & STC.immutable_)
- mod = MODFlags.immutable_;
- else
- {
- if (stc & (STC.shared_ | STC.synchronized_))
- mod |= MODFlags.shared_;
- if (stc & STC.const_)
- mod |= MODFlags.const_;
- if (stc & STC.wild)
- mod |= MODFlags.wild;
- }
-
- ubyte thismod = tthis.mod;
- if (hasttp)
- mod = MODmerge(thismod, mod);
- MATCH m = MODmethodConv(thismod, mod);
- if (m == MATCH.nomatch)
- return nomatch();
- if (m < match)
- match = m;
- }
- }
-
- // Loop through the function parameters
- {
- //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 = fargs.length; // nfargs + supplied defaultArgs
- uint inoutMatch = 0; // for debugging only
- for (size_t parami = 0; parami < nfparams; parami++)
- {
- Parameter fparam = fparameters[parami];
-
- // Apply function parameter storage classes to parameter types
- Type prmtype = fparam.type.addStorageClass(fparam.storageClass);
-
- Expression farg;
-
- /* See function parameters which wound up
- * as part of a template tuple parameter.
- */
- if (fptupindex != IDX_NOTFOUND && parami == fptupindex)
- {
- TypeIdentifier tid = prmtype.isTypeIdentifier();
- assert(tid);
- if (!declaredTuple)
- {
- /* The types of the function arguments
- * now form the tuple argument.
- */
- declaredTuple = new Tuple();
- (*dedargs)[parameters.length - 1] = declaredTuple;
-
- /* Count function parameters with no defaults following a tuple parameter.
- * void foo(U, T...)(int y, T, U, double, int bar = 0) {} // rem == 2 (U, double)
- */
- size_t rem = 0;
- foreach (j; parami + 1 .. nfparams)
- {
- Parameter p = fparameters[j];
- if (p.defaultArg)
- {
- break;
- }
- if (!reliesOnTemplateParameters(p.type, (*parameters)[inferStart .. parameters.length]))
- {
- Type pt = p.type.syntaxCopy().typeSemantic(fd.loc, paramscope);
- if (auto ptt = pt.isTypeTuple())
- rem += ptt.arguments.length;
- else
- rem += 1;
- }
- else
- {
- ++rem;
- }
- }
-
- if (nfargs2 - argi < rem)
- return nomatch();
- declaredTuple.objects.setDim(nfargs2 - argi - rem);
- foreach (i; 0 .. declaredTuple.objects.length)
- {
- farg = fargs[argi + i];
-
- // Check invalid arguments to detect errors early.
- if (farg.op == EXP.error || farg.type.ty == Terror)
- return nomatch();
-
- if (!fparam.isLazy() && farg.type.ty == Tvoid)
- return nomatch();
-
- Type tt;
- MATCH m;
- if (ubyte wm = deduceWildHelper(farg.type, &tt, tid))
- {
- inoutMatch |= wm;
- m = MATCH.constant;
- }
- else
- {
- m = deduceTypeHelper(farg.type, tt, tid);
- }
- if (m == MATCH.nomatch)
- return nomatch();
- if (m < match)
- match = m;
-
- /* Remove top const for dynamic array types and pointer types
- */
- if ((tt.ty == Tarray || tt.ty == Tpointer) && !tt.isMutable() && (!(fparam.storageClass & STC.ref_) || (fparam.storageClass & STC.auto_) && !farg.isLvalue()))
- {
- tt = tt.mutableOf();
- }
- declaredTuple.objects[i] = tt;
- }
- declareParameter(paramscope, tp, declaredTuple);
- }
- else
- {
- // https://issues.dlang.org/show_bug.cgi?id=6810
- // If declared tuple is not a type tuple,
- // it cannot be function parameter types.
- for (size_t i = 0; i < declaredTuple.objects.length; i++)
- {
- if (!isType(declaredTuple.objects[i]))
- return nomatch();
- }
- }
- assert(declaredTuple);
- argi += declaredTuple.objects.length;
- continue;
- }
-
- // If parameter type doesn't depend on inferred template parameters,
- // semantic it to get actual type.
- if (!reliesOnTemplateParameters(prmtype, (*parameters)[inferStart .. parameters.length]))
- {
- // should copy prmtype to avoid affecting semantic result
- prmtype = prmtype.syntaxCopy().typeSemantic(fd.loc, paramscope);
-
- if (TypeTuple tt = prmtype.isTypeTuple())
- {
- 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 < fargs.length)
- {
- prmtype = p.type;
- goto Lvarargs;
- }
- if (argi >= fargs.length)
- {
- if (p.defaultArg)
- continue;
-
- // https://issues.dlang.org/show_bug.cgi?id=19888
- if (fparam.defaultArg)
- break;
-
- return nomatch();
- }
- farg = fargs[argi];
- if (!farg.implicitConvTo(p.type))
- return nomatch();
- }
- continue;
- }
- }
-
- if (argi >= fargs.length) // if not enough arguments
- {
- if (!fparam.defaultArg)
- goto Lvarargs;
-
- /* https://issues.dlang.org/show_bug.cgi?id=2803
- * Before the starting of type deduction from the function
- * default arguments, set the already deduced parameters into paramscope.
- * It's necessary to avoid breaking existing acceptable code. Cases:
- *
- * 1. Already deduced template parameters can appear in fparam.defaultArg:
- * auto foo(A, B)(A a, B b = A.stringof);
- * foo(1);
- * // at fparam == 'B b = A.string', A is equivalent with the deduced type 'int'
- *
- * 2. If prmtype depends on default-specified template parameter, the
- * default type should be preferred.
- * auto foo(N = size_t, R)(R r, N start = 0)
- * foo([1,2,3]);
- * // at fparam `N start = 0`, N should be 'size_t' before
- * // the deduction result from fparam.defaultArg.
- */
- if (argi == fargs.length)
- {
- foreach (ref dedtype; *dedtypes)
- {
- Type at = isType(dedtype);
- if (at && at.ty == Tnone)
- {
- TypeDeduced xt = cast(TypeDeduced)at;
- dedtype = xt.tded; // 'unbox'
- }
- }
- for (size_t i = ntargs; i < dedargs.length; i++)
- {
- TemplateParameter tparam = (*parameters)[i];
-
- RootObject oarg = (*dedargs)[i];
- RootObject oded = (*dedtypes)[i];
- if (oarg)
- continue;
-
- if (oded)
- {
- if (tparam.specialization() || !tparam.isTemplateTypeParameter())
- {
- /* The specialization can work as long as afterwards
- * the oded == oarg
- */
- (*dedargs)[i] = oded;
- MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, *dedtypes, null);
- //printf("m2 = %d\n", m2);
- if (m2 == MATCH.nomatch)
- return nomatch();
- if (m2 < matchTiargs)
- matchTiargs = m2; // pick worst match
- if (!(*dedtypes)[i].equals(oded))
- .error(loc, "%s `%s` specialization not allowed for deduced parameter `%s`", kind, toPrettyChars, kind, toPrettyChars, tparam.ident.toChars());
- }
- else
- {
- if (MATCH.convert < matchTiargs)
- matchTiargs = MATCH.convert;
- }
- (*dedargs)[i] = declareParameter(paramscope, tparam, oded);
- }
- else
- {
- oded = tparam.defaultArg(instLoc, paramscope);
- if (oded)
- (*dedargs)[i] = declareParameter(paramscope, tparam, oded);
- }
- }
- }
- nfargs2 = argi + 1;
-
- /* If prmtype does not depend on any template parameters:
- *
- * auto foo(T)(T v, double x = 0);
- * foo("str");
- * // at fparam == 'double x = 0'
- *
- * or, if all template parameters in the prmtype are already deduced:
- *
- * auto foo(R)(R range, ElementType!R sum = 0);
- * foo([1,2,3]);
- * // at fparam == 'ElementType!R sum = 0'
- *
- * Deducing prmtype from fparam.defaultArg is not necessary.
- */
- if (prmtype.deco || prmtype.syntaxCopy().trySemantic(loc, paramscope))
- {
- ++argi;
- continue;
- }
-
- // Deduce prmtype from the defaultArg.
- farg = fparam.defaultArg.syntaxCopy();
- farg = farg.expressionSemantic(paramscope);
- farg = resolveProperties(paramscope, farg);
- }
- else
- {
- farg = fargs[argi];
- }
- {
- // Check invalid arguments to detect errors early.
- if (farg.op == EXP.error || farg.type.ty == Terror)
- return nomatch();
-
- Type att = null;
- Lretry:
- version (none)
- {
- printf("\tfarg.type = %s\n", farg.type.toChars());
- printf("\tfparam.type = %s\n", prmtype.toChars());
- }
- Type argtype = farg.type;
-
- if (!fparam.isLazy() && argtype.ty == Tvoid && farg.op != EXP.function_)
- return nomatch();
-
- // https://issues.dlang.org/show_bug.cgi?id=12876
- // Optimize argument to allow CT-known length matching
- farg = farg.optimize(WANTvalue, fparam.isReference());
- //printf("farg = %s %s\n", farg.type.toChars(), farg.toChars());
-
- RootObject oarg = farg;
- if ((fparam.storageClass & STC.ref_) && (!(fparam.storageClass & STC.auto_) || farg.isLvalue()))
- {
- /* Allow expressions that have CT-known boundaries and type [] to match with [dim]
- */
- 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())
- {
- argtype = se.type.nextOf().sarrayOf(se.len);
- }
- else if (ArrayLiteralExp ae = farg.isArrayLiteralExp())
- {
- argtype = ae.type.nextOf().sarrayOf(ae.elements.length);
- }
- else if (SliceExp se = farg.isSliceExp())
- {
- if (Type tsa = toStaticArrayType(se))
- argtype = tsa;
- }
- }
-
- oarg = argtype;
- }
- 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
- * by adjusting top-qualifier of the argtype.
- *
- * prmtype argtype ta
- * T <- const(E)[] const(E)[]
- * T <- const(E[]) const(E)[]
- * qualifier(T) <- const(E)[] const(E[])
- * qualifier(T) <- const(E[]) const(E[])
- */
- Type ta = argtype.castMod(prmtype.mod ? argtype.nextOf().mod : 0);
- if (ta != argtype)
- {
- Expression ea = farg.copy();
- ea.type = ta;
- oarg = ea;
- }
- }
-
- 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);
- //printf("\tL%d deduceType m = %d, im = x%x, inoutMatch = x%x\n", __LINE__, m, im, inoutMatch);
- inoutMatch |= im;
-
- /* If no match, see if the argument can be matched by using
- * implicit conversions.
- */
- if (m == MATCH.nomatch && prmtype.deco)
- m = farg.implicitConvTo(prmtype);
-
- if (m == MATCH.nomatch)
- {
- AggregateDeclaration ad = isAggregate(farg.type);
- if (ad && ad.aliasthis && !isRecursiveAliasThis(att, argtype))
- {
- // https://issues.dlang.org/show_bug.cgi?id=12537
- // The isRecursiveAliasThis() call above
-
- /* If a semantic error occurs while doing alias this,
- * eg purity(https://issues.dlang.org/show_bug.cgi?id=7295),
- * just regard it as not a match.
- *
- * We also save/restore sc.func.flags to avoid messing up
- * attribute inference in the evaluation.
- */
- const oldflags = sc.func ? sc.func.flags : 0;
- auto e = resolveAliasThis(sc, farg, true);
- if (sc.func)
- sc.func.flags = oldflags;
- if (e)
- {
- farg = e;
- goto Lretry;
- }
- }
- }
-
- if (m > MATCH.nomatch && (fparam.storageClass & (STC.ref_ | STC.auto_)) == STC.ref_)
- {
- if (!farg.isLvalue())
- {
- if ((farg.op == EXP.string_ || farg.op == EXP.slice) && (prmtype.ty == Tsarray || prmtype.ty == Taarray))
- {
- // Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
- }
- else if (global.params.rvalueRefParam == FeatureState.enabled)
- {
- // Allow implicit conversion to ref
- }
- else
- return nomatch();
- }
- }
- if (m > MATCH.nomatch && (fparam.storageClass & STC.out_))
- {
- if (!farg.isLvalue())
- return nomatch();
- if (!farg.type.isMutable()) // https://issues.dlang.org/show_bug.cgi?id=11916
- return nomatch();
- }
- if (m == MATCH.nomatch && fparam.isLazy() && prmtype.ty == Tvoid && farg.type.ty != Tvoid)
- m = MATCH.convert;
- if (m != MATCH.nomatch)
- {
- if (m < match)
- match = m; // pick worst match
- argi++;
- continue;
- }
- }
-
- Lvarargs:
- /* The following code for variadic arguments closely
- * matches TypeFunction.callMatch()
- */
- if (!(fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams))
- return nomatch();
-
- /* Check for match with function parameter T...
- */
- Type tb = prmtype.toBasetype();
- switch (tb.ty)
- {
- // 6764 fix - TypeAArray may be TypeSArray have not yet run semantic().
- case Tsarray:
- case Taarray:
- {
- // Perhaps we can do better with this, see TypeFunction.callMatch()
- if (TypeSArray tsa = tb.isTypeSArray())
- {
- dinteger_t sz = tsa.dim.toInteger();
- if (sz != fargs.length - argi)
- return nomatch();
- }
- else if (TypeAArray taa = tb.isTypeAArray())
- {
- Expression dim = new IntegerExp(instLoc, fargs.length - argi, Type.tsize_t);
-
- size_t i = templateParameterLookup(taa.index, parameters);
- if (i == IDX_NOTFOUND)
- {
- Expression e;
- Type t;
- Dsymbol s;
- Scope *sco;
-
- uint errors = global.startGagging();
- /* ref: https://issues.dlang.org/show_bug.cgi?id=11118
- * The parameter isn't part of the template
- * ones, let's try to find it in the
- * instantiation scope 'sc' and the one
- * belonging to the template itself. */
- sco = sc;
- taa.index.resolve(instLoc, sco, e, t, s);
- if (!e)
- {
- sco = paramscope;
- taa.index.resolve(instLoc, sco, e, t, s);
- }
- global.endGagging(errors);
-
- if (!e)
- return nomatch();
-
- e = e.ctfeInterpret();
- e = e.implicitCastTo(sco, Type.tsize_t);
- e = e.optimize(WANTvalue);
- if (!dim.equals(e))
- return nomatch();
- }
- else
- {
- // This code matches code in TypeInstance.deduceType()
- TemplateParameter tprm = (*parameters)[i];
- TemplateValueParameter tvp = tprm.isTemplateValueParameter();
- if (!tvp)
- return nomatch();
- Expression e = cast(Expression)(*dedtypes)[i];
- if (e)
- {
- if (!dim.equals(e))
- return nomatch();
- }
- else
- {
- Type vt = tvp.valType.typeSemantic(Loc.initial, sc);
- MATCH m = dim.implicitConvTo(vt);
- if (m == MATCH.nomatch)
- return nomatch();
- (*dedtypes)[i] = dim;
- }
- }
- }
- goto case Tarray;
- }
- case Tarray:
- {
- TypeArray ta = cast(TypeArray)tb;
- Type tret = fparam.isLazyArray();
- for (; argi < fargs.length; argi++)
- {
- Expression arg = fargs[argi];
- assert(arg);
-
- MATCH m;
- /* If lazy array of delegates,
- * convert arg(s) to delegate(s)
- */
- if (tret)
- {
- if (ta.next.equals(arg.type))
- {
- m = MATCH.exact;
- }
- else
- {
- m = arg.implicitConvTo(tret);
- if (m == MATCH.nomatch)
- {
- if (tret.toBasetype().ty == Tvoid)
- m = MATCH.convert;
- }
- }
- }
- else
- {
- uint wm = 0;
- m = deduceType(arg, paramscope, ta.next, *parameters, *dedtypes, &wm, inferStart);
- inoutMatch |= wm;
- }
- if (m == MATCH.nomatch)
- return nomatch();
- if (m < match)
- match = m;
- }
- goto Lmatch;
- }
- case Tclass:
- case Tident:
- goto Lmatch;
-
- default:
- return nomatch();
- }
- assert(0);
- }
- //printf(". argi = %d, nfargs = %d, nfargs2 = %d\n", argi, nfargs, nfargs2);
- if (argi != nfargs2 && fparameters.varargs == VarArg.none)
- return nomatch();
- }
-
- Lmatch:
- foreach (ref dedtype; *dedtypes)
- {
- if (Type at = isType(dedtype))
- {
- if (at.ty == Tnone)
- {
- TypeDeduced xt = cast(TypeDeduced)at;
- at = xt.tded; // 'unbox'
- }
- dedtype = at.merge2();
- }
- }
- for (size_t i = ntargs; i < dedargs.length; i++)
- {
- TemplateParameter tparam = (*parameters)[i];
- //printf("tparam[%d] = %s\n", i, tparam.ident.toChars());
-
- /* For T:T*, the dedargs is the T*, dedtypes is the T
- * But for function templates, we really need them to match
- */
- RootObject oarg = (*dedargs)[i];
- RootObject oded = (*dedtypes)[i];
- //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded);
- //if (oarg) printf("oarg: %s\n", oarg.toChars());
- //if (oded) printf("oded: %s\n", oded.toChars());
- if (oarg)
- continue;
-
- if (oded)
- {
- if (tparam.specialization() || !tparam.isTemplateTypeParameter())
- {
- /* The specialization can work as long as afterwards
- * the oded == oarg
- */
- (*dedargs)[i] = oded;
- MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, *dedtypes, null);
- //printf("m2 = %d\n", m2);
- if (m2 == MATCH.nomatch)
- return nomatch();
- if (m2 < matchTiargs)
- matchTiargs = m2; // pick worst match
- if (!(*dedtypes)[i].equals(oded))
- .error(loc, "%s `%s` specialization not allowed for deduced parameter `%s`", kind, toPrettyChars, tparam.ident.toChars());
- }
- else
- {
- // Discussion: https://issues.dlang.org/show_bug.cgi?id=16484
- if (MATCH.convert < matchTiargs)
- matchTiargs = MATCH.convert;
- }
- }
- else
- {
- oded = tparam.defaultArg(instLoc, paramscope);
- if (!oded)
- {
- // if tuple parameter and
- // tuple parameter was not in function parameter list and
- // we're one or more arguments short (i.e. no tuple argument)
- if (tparam == tp &&
- fptupindex == IDX_NOTFOUND &&
- ntargs <= dedargs.length - 1)
- {
- // make tuple argument an empty tuple
- oded = new Tuple();
- }
- else
- return nomatch();
- }
- if (isError(oded))
- return matcherror();
- ntargs++;
-
- /* At the template parameter T, the picked default template argument
- * X!int should be matched to T in order to deduce dependent
- * template parameter A.
- * auto foo(T : X!A = X!int, A...)() { ... }
- * foo(); // T <-- X!int, A <-- (int)
- */
- if (tparam.specialization())
- {
- (*dedargs)[i] = oded;
- MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, *dedtypes, null);
- //printf("m2 = %d\n", m2);
- if (m2 == MATCH.nomatch)
- return nomatch();
- if (m2 < matchTiargs)
- matchTiargs = m2; // pick worst match
- if (!(*dedtypes)[i].equals(oded))
- .error(loc, "%s `%s` specialization not allowed for deduced parameter `%s`", kind, toPrettyChars, tparam.ident.toChars());
- }
- }
- oded = declareParameter(paramscope, tparam, oded);
- (*dedargs)[i] = oded;
- }
-
- /* https://issues.dlang.org/show_bug.cgi?id=7469
- * As same as the code for 7469 in findBestMatch,
- * expand a Tuple in dedargs to normalize template arguments.
- */
- if (auto d = dedargs.length)
- {
- if (auto va = isTuple((*dedargs)[d - 1]))
- {
- dedargs.setDim(d - 1);
- dedargs.insert(d - 1, &va.objects);
- }
- }
- ti.tiargs = dedargs; // update to the normalized template arguments.
-
- // Partially instantiate function for constraint and fd.leastAsSpecialized()
- {
- assert(paramscope.scopesym);
- Scope* sc2 = _scope;
- sc2 = sc2.push(paramscope.scopesym);
- sc2 = sc2.push(ti);
- sc2.parent = ti;
- sc2.tinst = ti;
- sc2.minst = sc.minst;
- sc2.stc |= fd.storage_class & STC.deprecated_;
-
- fd = doHeaderInstantiation(ti, sc2, fd, tthis, argumentList.arguments);
-
- sc2 = sc2.pop();
- sc2 = sc2.pop();
-
- if (!fd)
- return nomatch();
- }
-
- if (constraint)
- {
- if (!evaluateConstraint(ti, sc, paramscope, dedargs, fd))
- return nomatch();
- }
-
- version (none)
- {
- for (size_t i = 0; i < dedargs.length; i++)
- {
- RootObject o = (*dedargs)[i];
- printf("\tdedargs[%d] = %d, %s\n", i, o.dyncast(), o.toChars());
- }
- }
-
- paramscope.pop();
- //printf("\tmatch %d\n", match);
- return MATCHpair(matchTiargs, match);
- }
-
/**************************************************
* Declare template parameter tp with value o, and install it in the scope sc.
*/
@@ -2770,8 +1302,8 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
* This is because f() is "more specialized."
*/
{
- MATCH c1 = fd.leastAsSpecialized(m.lastf, argumentList.names);
- MATCH c2 = m.lastf.leastAsSpecialized(fd, argumentList.names);
+ MATCH c1 = FuncDeclaration.leastAsSpecialized(fd, m.lastf, argumentList.names);
+ MATCH c2 = FuncDeclaration.leastAsSpecialized(m.lastf, fd, argumentList.names);
//printf("c1 = %d, c2 = %d\n", c1, c2);
if (c1 > c2) return firstIsBetter();
if (c1 < c2) return 0;
@@ -2876,7 +1408,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 = matchWithInstance(sc, td, ti, dedtypes, argumentList, 0);
//printf("matchWithInstance = %d\n", mta);
if (mta == MATCH.nomatch || mta < ta_last) // no match or less match
return 0;
@@ -3036,8 +1568,8 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
if (td_best)
{
// Disambiguate by picking the most specialized TemplateDeclaration
- MATCH c1 = td.leastAsSpecialized(sc, td_best, argumentList);
- MATCH c2 = td_best.leastAsSpecialized(sc, td, argumentList);
+ MATCH c1 = leastAsSpecialized(sc, td, td_best, argumentList);
+ MATCH c2 = leastAsSpecialized(sc, td_best, td, argumentList);
//printf("1: c1 = %d, c2 = %d\n", c1, c2);
if (c1 > c2) goto Ltd;
if (c1 < c2) goto Ltd_best;
@@ -3055,8 +1587,8 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
}
{
// Disambiguate by picking the most specialized FunctionDeclaration
- MATCH c1 = fd.leastAsSpecialized(m.lastf, argumentList.names);
- MATCH c2 = m.lastf.leastAsSpecialized(fd, argumentList.names);
+ MATCH c1 = FuncDeclaration.leastAsSpecialized(fd, m.lastf, argumentList.names);
+ MATCH c2 = FuncDeclaration.leastAsSpecialized(m.lastf, fd, argumentList.names);
//printf("3: c1 = %d, c2 = %d\n", c1, c2);
if (c1 > c2) goto Ltd;
if (c1 < c2) goto Ltd_best;
@@ -3199,7 +1731,7 @@ private size_t templateIdentifierLookup(Identifier id, TemplateParameters* param
return IDX_NOTFOUND;
}
-private size_t templateParameterLookup(Type tparam, TemplateParameters* parameters)
+size_t templateParameterLookup(Type tparam, TemplateParameters* parameters)
{
if (TypeIdentifier tident = tparam.isTypeIdentifier())
{
@@ -3209,7 +1741,7 @@ private size_t templateParameterLookup(Type tparam, TemplateParameters* paramete
return IDX_NOTFOUND;
}
-private ubyte deduceWildHelper(Type t, Type* at, Type tparam)
+ubyte deduceWildHelper(Type t, Type* at, Type tparam)
{
if ((tparam.mod & MODFlags.wild) == 0)
return 0;
@@ -3292,7 +1824,7 @@ private Type rawTypeMerge(Type t1, Type t2)
return null;
}
-private MATCH deduceTypeHelper(Type t, out Type at, Type tparam)
+MATCH deduceTypeHelper(Type t, out Type at, Type tparam)
{
// 9*9 == 81 cases
@@ -5000,7 +3532,7 @@ bool reliesOnTident(Type t, TemplateParameters* tparams, size_t iStart = 0)
* t = Tested type, if null, returns false.
* tparams = Template parameters.
*/
-private bool reliesOnTemplateParameters(Type t, TemplateParameter[] tparams)
+bool reliesOnTemplateParameters(Type t, TemplateParameter[] tparams)
{
bool visitVector(TypeVector t)
{
@@ -6930,7 +5462,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
}
FuncDeclaration fd = sa.isFuncDeclaration();
if (fd)
- fd.functionSemantic();
+ functionSemantic(fd);
}
else if (isParameter(o))
{
@@ -7001,7 +5533,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 (!matchWithInstance(sc, tempdecl, this, tdtypes, argumentList, 2))
{
.error(loc, "%s `%s` incompatible arguments for template instantiation", kind, toPrettyChars);
return false;
@@ -7051,7 +5583,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
dedtypes.zero();
assert(td.semanticRun != PASS.initial);
- MATCH m = td.matchWithInstance(sc, this, dedtypes, argumentList, 0);
+ MATCH m = matchWithInstance(sc, td, this, dedtypes, argumentList, 0);
//printf("matchWithInstance = %d\n", m);
if (m == MATCH.nomatch) // no match at all
return 0;
@@ -7060,8 +5592,8 @@ extern (C++) class TemplateInstance : ScopeDsymbol
// Disambiguate by picking the most specialized TemplateDeclaration
{
- MATCH c1 = td.leastAsSpecialized(sc, td_best, argumentList);
- MATCH c2 = td_best.leastAsSpecialized(sc, td, argumentList);
+ MATCH c1 = leastAsSpecialized(sc, td, td_best, argumentList);
+ MATCH c2 = leastAsSpecialized(sc, td_best, td, argumentList);
//printf("c1 = %d, c2 = %d\n", c1, c2);
if (c1 > c2) goto Ltd;
if (c1 < c2) goto Ltd_best;
@@ -7159,7 +5691,11 @@ extern (C++) class TemplateInstance : ScopeDsymbol
// Only one template, so we can give better error message
const(char)* msg = "does not match template declaration";
const(char)* tip;
- const tmsg = tdecl.toCharsNoConstraints();
+ OutBuffer buf;
+ HdrGenState hgs;
+ hgs.skipConstraints = true;
+ toCharsMaybeConstraints(tdecl, buf, hgs);
+ const tmsg = buf.peekChars();
const cmsg = tdecl.getConstraintEvalError(tip);
if (cmsg)
{
@@ -7327,7 +5863,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
return 1;
}
}
- MATCH m = td.matchWithInstance(sc, this, dedtypes, ArgumentList(), 0);
+ MATCH m = matchWithInstance(sc, td, this, dedtypes, ArgumentList(), 0);
if (m == MATCH.nomatch)
return 0;
}
@@ -8562,15 +7098,21 @@ extern (C++) void printTemplateStats(bool listInstances, ErrorSink eSink)
sortedStats.sort!(TemplateDeclarationStats.compare);
+ OutBuffer buf;
foreach (const ref ss; sortedStats[])
{
+ buf.reset();
+ HdrGenState hgs;
+ hgs.skipConstraints = true;
+ toCharsMaybeConstraints(ss.td, buf, hgs);
+ const tchars = buf.peekChars();
if (listInstances && ss.ts.allInstances)
{
eSink.message(ss.td.loc,
"vtemplate: %u (%u distinct) instantiation(s) of template `%s` found, they are:",
ss.ts.numInstantiations,
ss.ts.uniqueInstantiations,
- ss.td.toCharsNoConstraints());
+ tchars);
foreach (const ti; (*ss.ts.allInstances)[])
{
if (ti.tinst) // if has enclosing instance
@@ -8585,13 +7127,13 @@ extern (C++) void printTemplateStats(bool listInstances, ErrorSink eSink)
"vtemplate: %u (%u distinct) instantiation(s) of template `%s` found",
ss.ts.numInstantiations,
ss.ts.uniqueInstantiations,
- ss.td.toCharsNoConstraints());
+ tchars);
}
}
}
/// Pair of MATCHes
-private struct MATCHpair
+struct MATCHpair
{
MATCH mta; /// match template parameters by initial template arguments
MATCH mfa; /// match template parameters by inferred template arguments
@@ -8605,7 +7147,7 @@ private struct MATCHpair
}
}
-private void write(ref OutBuffer buf, RootObject obj)
+void write(ref OutBuffer buf, RootObject obj)
{
if (obj)
{
diff --git a/gcc/d/dmd/enum.h b/gcc/d/dmd/enum.h
index a4bb588..650bf3e 100644
--- a/gcc/d/dmd/enum.h
+++ b/gcc/d/dmd/enum.h
@@ -52,8 +52,6 @@ public:
bool isDeprecated() const override; // is Dsymbol deprecated?
Visibility visible() override;
bool isSpecial() const;
- Expression *getDefaultValue(const Loc &loc);
- Type *getMemtype(const Loc &loc);
EnumDeclaration *isEnumDeclaration() override { return this; }
diff --git a/gcc/d/dmd/enumsem.d b/gcc/d/dmd/enumsem.d
new file mode 100644
index 0000000..0603960
--- /dev/null
+++ b/gcc/d/dmd/enumsem.d
@@ -0,0 +1,714 @@
+/**
+ * Does the semantic passes on enums.
+ *
+ * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/enumsem.d, _enumsem.d)
+ * Documentation: https://dlang.org/phobos/dmd_enumsem.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/enumsem.d
+ */
+
+module dmd.enumsem;
+
+import core.stdc.stdio;
+import core.stdc.string;
+
+import dmd.aggregate;
+import dmd.aliasthis;
+import dmd.arraytypes;
+import dmd.astcodegen;
+import dmd.astenums;
+import dmd.attrib;
+import dmd.blockexit;
+import dmd.clone;
+import dmd.cond;
+import dmd.compiler;
+import dmd.dcast;
+import dmd.dclass;
+import dmd.declaration;
+import dmd.denum;
+import dmd.dimport;
+import dmd.dinterpret;
+import dmd.dmangle;
+import dmd.dmodule;
+import dmd.dscope;
+import dmd.dstruct;
+import dmd.dsymbol;
+import dmd.dsymbolsem;
+import dmd.dtemplate;
+import dmd.dversion;
+import dmd.errors;
+import dmd.escape;
+import dmd.expression;
+import dmd.expressionsem;
+import dmd.func;
+import dmd.funcsem;
+import dmd.globals;
+import dmd.id;
+import dmd.identifier;
+import dmd.importc;
+import dmd.init;
+import dmd.initsem;
+import dmd.intrange;
+import dmd.hdrgen;
+import dmd.location;
+import dmd.mtype;
+import dmd.mustuse;
+import dmd.nogc;
+import dmd.nspace;
+import dmd.objc;
+import dmd.opover;
+import dmd.optimize;
+import dmd.parse;
+import dmd.root.array;
+import dmd.root.filename;
+import dmd.common.outbuffer;
+import dmd.root.rmem;
+import dmd.rootobject;
+import dmd.root.utf;
+import dmd.semantic2;
+import dmd.semantic3;
+import dmd.sideeffect;
+import dmd.statementsem;
+import dmd.staticassert;
+import dmd.tokens;
+import dmd.utils;
+import dmd.statement;
+import dmd.target;
+import dmd.templateparamsem;
+import dmd.typesem;
+import dmd.visitor;
+
+
+/*********************************
+ * Perform semantic analysis on enum declaration `em`
+ */
+void enumSemantic(Scope* sc, EnumDeclaration ed)
+{
+ //printf("EnumDeclaration::semantic(sd = %p, '%s') %s\n", sc.scopesym, sc.scopesym.toChars(), ed.toChars());
+ //printf("EnumDeclaration::semantic() %p %s\n", ed, ed.toChars());
+ if (ed.semanticRun >= PASS.semanticdone)
+ return; // semantic() already completed
+ if (ed.semanticRun == PASS.semantic)
+ {
+ assert(ed.memtype);
+ error(ed.loc, "circular reference to enum base type `%s`", ed.memtype.toChars());
+ ed.errors = true;
+ ed.semanticRun = PASS.semanticdone;
+ return;
+ }
+ Scope* scx = null;
+ if (ed._scope)
+ {
+ sc = ed._scope;
+ scx = ed._scope; // save so we don't make redundant copies
+ ed._scope = null;
+ }
+
+ if (!sc)
+ return;
+
+ ed.parent = sc.parent;
+ ed.type = ed.type.typeSemantic(ed.loc, sc);
+
+ ed.visibility = sc.visibility;
+ if (sc.stc & STC.deprecated_)
+ ed.isdeprecated = true;
+ ed.userAttribDecl = sc.userAttribDecl;
+ ed.cppnamespace = sc.namespace;
+
+ ed.semanticRun = PASS.semantic;
+ UserAttributeDeclaration.checkGNUABITag(ed, sc.linkage);
+ checkMustUseReserved(ed);
+
+ if (!ed.members && !ed.memtype) // enum ident;
+ {
+ ed.semanticRun = PASS.semanticdone;
+ return;
+ }
+
+ if (!ed.symtab)
+ ed.symtab = new DsymbolTable();
+
+ /* The separate, and distinct, cases are:
+ * 1. enum { ... }
+ * 2. enum : memtype { ... }
+ * 3. enum ident { ... }
+ * 4. enum ident : memtype { ... }
+ * 5. enum ident : memtype;
+ * 6. enum ident;
+ */
+
+ if (ed.memtype)
+ {
+ ed.memtype = ed.memtype.typeSemantic(ed.loc, sc);
+
+ /* Check to see if memtype is forward referenced
+ */
+ if (auto te = ed.memtype.isTypeEnum())
+ {
+ auto sym = te.toDsymbol(sc).isEnumDeclaration();
+ // Special enums like __c_[u]long[long] are fine to forward reference
+ // see https://issues.dlang.org/show_bug.cgi?id=20599
+ if (!sym.isSpecial() && (!sym.memtype || !sym.members || !sym.symtab || sym._scope))
+ {
+ // memtype is forward referenced, so try again later
+ deferDsymbolSemantic(sc, ed, scx);
+ //printf("\tdeferring %s\n", toChars());
+ ed.semanticRun = PASS.initial;
+ return;
+ }
+ else
+ // Ensure that semantic is run to detect. e.g. invalid forward references
+ sym.dsymbolSemantic(sc);
+ }
+ if (ed.memtype.ty == Tvoid)
+ {
+ .error(ed.loc, "%s `%s` base type must not be `void`", ed.kind, ed.toPrettyChars);
+ ed.memtype = Type.terror;
+ }
+ if (ed.memtype.ty == Terror)
+ {
+ ed.errors = true;
+ // poison all the members
+ ed.members.foreachDsymbol( (s) { s.errors = true; } );
+ ed.semanticRun = PASS.semanticdone;
+ return;
+ }
+ }
+
+ if (!ed.members) // enum ident : memtype;
+ {
+ ed.semanticRun = PASS.semanticdone;
+ return;
+ }
+
+ if (ed.members.length == 0)
+ {
+ .error(ed.loc, "%s `%s enum `%s` must have at least one member", ed.kind, ed.toPrettyChars, ed.toChars());
+ ed.errors = true;
+ ed.semanticRun = PASS.semanticdone;
+ return;
+ }
+
+ if (!(sc.flags & SCOPE.Cfile)) // C enum remains incomplete until members are done
+ ed.semanticRun = PASS.semanticdone;
+
+ version (none)
+ {
+ // @@@DEPRECATED_2.110@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint
+ // Deprecated in 2.100
+ // Make an error in 2.110
+ if (sc.stc & STC.scope_)
+ deprecation(ed.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site.");
+ }
+
+ Scope* sce;
+ if (ed.isAnonymous())
+ sce = sc;
+ else
+ {
+ sce = sc.push(ed);
+ sce.parent = ed;
+ }
+ sce = sce.startCTFE();
+ sce.setNoFree(); // needed for getMaxMinValue()
+
+ /* Each enum member gets the sce scope
+ */
+ ed.members.foreachDsymbol( (s)
+ {
+ EnumMember em = s.isEnumMember();
+ if (em)
+ em._scope = sce;
+ });
+
+ /* addMember() is not called when the EnumDeclaration appears as a function statement,
+ * so we have to do what addMember() does and install the enum members in the right symbol
+ * table
+ */
+ addEnumMembersToSymtab(ed, sc, sc.getScopesym());
+
+ if (sc.flags & SCOPE.Cfile)
+ {
+ /* C11 6.7.2.2
+ */
+ Type commonType = ed.memtype;
+ if (!commonType)
+ commonType = Type.tint32;
+ ulong nextValue = 0; // C11 6.7.2.2-3 first member value defaults to 0
+
+ // C11 6.7.2.2-2 value must be representable as an int.
+ // The sizemask represents all values that int will fit into,
+ // from 0..uint.max. We want to cover int.min..uint.max.
+ IntRange ir = IntRange.fromType(commonType);
+
+ void emSemantic(EnumMember em, ref ulong nextValue)
+ {
+ static void errorReturn(EnumMember em)
+ {
+ em.value = ErrorExp.get();
+ em.errors = true;
+ em.semanticRun = PASS.semanticdone;
+ }
+
+ em.semanticRun = PASS.semantic;
+ em.type = commonType;
+ em._linkage = LINK.c;
+ em.storage_class |= STC.manifest;
+ if (em.value)
+ {
+ Expression e = em.value;
+ assert(e.dyncast() == DYNCAST.expression);
+
+ /* To merge the type of e with commonType, add 0 of type commonType
+ */
+ if (!ed.memtype)
+ e = new AddExp(em.loc, e, new IntegerExp(em.loc, 0, commonType));
+
+ e = e.expressionSemantic(sc);
+ e = resolveProperties(sc, e);
+ e = e.integralPromotions(sc);
+ e = e.ctfeInterpret();
+ if (e.op == EXP.error)
+ return errorReturn(em);
+ auto ie = e.isIntegerExp();
+ if (!ie)
+ {
+ // C11 6.7.2.2-2
+ .error(em.loc, "%s `%s` enum member must be an integral constant expression, not `%s` of type `%s`", em.kind, em.toPrettyChars, e.toChars(), e.type.toChars());
+ return errorReturn(em);
+ }
+ if (ed.memtype && !ir.contains(getIntRange(ie)))
+ {
+ // C11 6.7.2.2-2
+ .error(em.loc, "%s `%s` enum member value `%s` does not fit in `%s`", em.kind, em.toPrettyChars, e.toChars(), commonType.toChars());
+ return errorReturn(em);
+ }
+ nextValue = ie.toInteger();
+ if (!ed.memtype)
+ commonType = e.type;
+ em.value = new IntegerExp(em.loc, nextValue, commonType);
+ }
+ else
+ {
+ // C11 6.7.2.2-3 add 1 to value of previous enumeration constant
+ bool first = (em == (*em.ed.members)[0]);
+ if (!first)
+ {
+ Expression max = getProperty(commonType, null, em.loc, Id.max, 0);
+ if (nextValue == max.toInteger())
+ {
+ .error(em.loc, "%s `%s` initialization with `%s+1` causes overflow for type `%s`", em.kind, em.toPrettyChars, max.toChars(), commonType.toChars());
+ return errorReturn(em);
+ }
+ nextValue += 1;
+ }
+ em.value = new IntegerExp(em.loc, nextValue, commonType);
+ }
+ em.type = commonType;
+ em.semanticRun = PASS.semanticdone;
+ }
+
+ ed.members.foreachDsymbol( (s)
+ {
+ if (EnumMember em = s.isEnumMember())
+ emSemantic(em, nextValue);
+ });
+
+ if (!ed.memtype)
+ {
+ // cast all members to commonType
+ ed.members.foreachDsymbol( (s)
+ {
+ if (EnumMember em = s.isEnumMember())
+ {
+ em.type = commonType;
+ em.value = em.value.castTo(sc, commonType);
+ }
+ });
+ }
+
+ ed.memtype = commonType;
+ ed.semanticRun = PASS.semanticdone;
+ return;
+ }
+
+ ed.members.foreachDsymbol( (s)
+ {
+ if (EnumMember em = s.isEnumMember())
+ em.dsymbolSemantic(em._scope);
+ });
+ //printf("ed.defaultval = %lld\n", ed.defaultval);
+
+ //if (ed.defaultval) printf("ed.defaultval: %s %s\n", ed.defaultval.toChars(), ed.defaultval.type.toChars());
+ //printf("members = %s\n", members.toChars());
+}
+
+Expression getDefaultValue(EnumDeclaration ed, const ref Loc loc)
+{
+ Expression handleErrors(){
+ ed.defaultval = ErrorExp.get();
+ return ed.defaultval;
+ }
+ //printf("EnumDeclaration::getDefaultValue() %p %s\n", this, toChars());
+ // https://issues.dlang.org/show_bug.cgi?id=23904
+ // Return ed.defaultval only if it is not ErrorExp.
+ // A speculative context may set ed.defaultval to ErrorExp;
+ // subsequent non-speculative contexts need to be able
+ // to print the error.
+ if (ed.defaultval && !ed.defaultval.isErrorExp())
+ return ed.defaultval;
+
+ if (ed.isCsymbol())
+ return ed.memtype.defaultInit(loc, true);
+
+ if (ed._scope)
+ dsymbolSemantic(ed, ed._scope);
+ if (ed.errors)
+ return handleErrors();
+ if (!ed.members)
+ {
+ if (ed.isSpecial())
+ {
+ /* Allow these special enums to not need a member list
+ */
+ return ed.defaultval = ed.memtype.defaultInit(loc);
+ }
+
+ error(loc, "%s `%s` is opaque and has no default initializer", ed.kind, ed.toPrettyChars);
+ return handleErrors();
+ }
+
+ foreach (const i; 0 .. ed.members.length)
+ {
+ EnumMember em = (*ed.members)[i].isEnumMember();
+ if (em)
+ {
+ if (em.semanticRun < PASS.semanticdone)
+ {
+ error(loc, "%s `%s` forward reference of `%s.init`", ed.kind, ed.toPrettyChars, ed.toChars());
+ return handleErrors();
+ }
+
+ ed.defaultval = em.value;
+ return ed.defaultval;
+ }
+ }
+ return handleErrors();
+}
+
+Type getMemtype(EnumDeclaration ed, const ref Loc loc)
+{
+ if (ed._scope)
+ {
+ /* Enum is forward referenced. We don't need to resolve the whole thing,
+ * just the base type
+ */
+ if (ed.memtype)
+ {
+ Loc locx = loc.isValid() ? loc : ed.loc;
+ ed.memtype = ed.memtype.typeSemantic(locx, ed._scope);
+ }
+ else
+ {
+ // Run semantic to get the type from a possible first member value
+ dsymbolSemantic(ed, ed._scope);
+ }
+ }
+ if (!ed.memtype)
+ {
+ if (!ed.isAnonymous() && (ed.members || ed.semanticRun >= PASS.semanticdone))
+ ed.memtype = Type.tint32;
+ else
+ {
+ Loc locx = loc.isValid() ? loc : ed.loc;
+ error(locx, "is forward referenced looking for base type");
+ return Type.terror;
+ }
+ }
+ return ed.memtype;
+}
+
+/*********************************
+ * Perform semantic analysis on enum member `em`
+ */
+void enumMemberSemantic(Scope* sc, EnumMember em)
+{
+ //printf("EnumMember::semantic() %s\n", em.toChars());
+
+ void errorReturn()
+ {
+ em.errors = true;
+ em.semanticRun = PASS.semanticdone;
+ }
+
+ if (em.errors || em.semanticRun >= PASS.semanticdone)
+ return;
+ if (em.semanticRun == PASS.semantic)
+ {
+ .error(em.loc, "%s `%s` circular reference to `enum` member", em.kind, em.toPrettyChars);
+ return errorReturn();
+ }
+ assert(em.ed);
+
+ em.ed.dsymbolSemantic(sc);
+ if (em.ed.errors)
+ return errorReturn();
+ if (em.errors || em.semanticRun >= PASS.semanticdone)
+ return;
+
+ if (em._scope)
+ sc = em._scope;
+ if (!sc)
+ return;
+
+ em.semanticRun = PASS.semantic;
+
+ em.visibility = em.ed.isAnonymous() ? em.ed.visibility : Visibility(Visibility.Kind.public_);
+ em._linkage = LINK.d;
+ em.storage_class |= STC.manifest;
+
+ // https://issues.dlang.org/show_bug.cgi?id=9701
+ if (em.ed.isAnonymous())
+ {
+ if (em.userAttribDecl)
+ em.userAttribDecl.userAttribDecl = em.ed.userAttribDecl;
+ else
+ em.userAttribDecl = em.ed.userAttribDecl;
+ }
+
+ // Eval UDA in this same scope. Issues 19344, 20835, 21122
+ if (em.userAttribDecl)
+ {
+ // Set scope but avoid extra sc.uda attachment inside setScope()
+ auto inneruda = em.userAttribDecl.userAttribDecl;
+ em.userAttribDecl.setScope(sc);
+ em.userAttribDecl.userAttribDecl = inneruda;
+ em.userAttribDecl.dsymbolSemantic(sc);
+ }
+
+ // The first enum member is special
+ bool first = (em == (*em.ed.members)[0]);
+
+ if (em.origType)
+ {
+ em.origType = em.origType.typeSemantic(em.loc, sc);
+ em.type = em.origType;
+ assert(em.value); // "type id;" is not a valid enum member declaration
+ }
+
+ if (em.value)
+ {
+ Expression e = em.value;
+ assert(e.dyncast() == DYNCAST.expression);
+ e = e.expressionSemantic(sc);
+ e = resolveProperties(sc, e);
+ e = e.ctfeInterpret();
+ if (e.op == EXP.error)
+ return errorReturn();
+ if (first && !em.ed.memtype && !em.ed.isAnonymous())
+ {
+ em.ed.memtype = e.type;
+ if (em.ed.memtype.ty == Terror)
+ {
+ em.ed.errors = true;
+ return errorReturn();
+ }
+ if (em.ed.memtype.ty != Terror)
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=11746
+ * All of named enum members should have same type
+ * with the first member. If the following members were referenced
+ * during the first member semantic, their types should be unified.
+ */
+ em.ed.members.foreachDsymbol( (s)
+ {
+ EnumMember enm = s.isEnumMember();
+ if (!enm || enm == em || enm.semanticRun < PASS.semanticdone || enm.origType)
+ return;
+
+ //printf("[%d] em = %s, em.semanticRun = %d\n", i, toChars(), em.semanticRun);
+ Expression ev = enm.value;
+ ev = ev.implicitCastTo(sc, em.ed.memtype);
+ ev = ev.ctfeInterpret();
+ ev = ev.castTo(sc, em.ed.type);
+ if (ev.op == EXP.error)
+ em.ed.errors = true;
+ enm.value = ev;
+ });
+
+ if (em.ed.errors)
+ {
+ em.ed.memtype = Type.terror;
+ return errorReturn();
+ }
+ }
+ }
+
+ if (em.ed.memtype && !em.origType)
+ {
+ e = e.implicitCastTo(sc, em.ed.memtype);
+ e = e.ctfeInterpret();
+
+ // save origValue for better json output
+ em.origValue = e;
+
+ if (!em.ed.isAnonymous())
+ {
+ e = e.castTo(sc, em.ed.type.addMod(e.type.mod)); // https://issues.dlang.org/show_bug.cgi?id=12385
+ e = e.ctfeInterpret();
+ }
+ }
+ else if (em.origType)
+ {
+ e = e.implicitCastTo(sc, em.origType);
+ e = e.ctfeInterpret();
+ assert(em.ed.isAnonymous());
+
+ // save origValue for better json output
+ em.origValue = e;
+ }
+ em.value = e;
+ }
+ else if (first)
+ {
+ Type t;
+ if (em.ed.memtype)
+ t = em.ed.memtype;
+ else
+ {
+ t = Type.tint32;
+ if (!em.ed.isAnonymous())
+ em.ed.memtype = t;
+ }
+ const errors = global.startGagging();
+ Expression e = new IntegerExp(em.loc, 0, t);
+ e = e.ctfeInterpret();
+ if (global.endGagging(errors))
+ {
+ error(em.loc, "cannot generate 0 value of type `%s` for `%s`",
+ t.toChars(), em.toChars());
+ }
+ // save origValue for better json output
+ em.origValue = e;
+
+ if (!em.ed.isAnonymous())
+ {
+ e = e.castTo(sc, em.ed.type);
+ e = e.ctfeInterpret();
+ }
+ em.value = e;
+ }
+ else
+ {
+ /* Find the previous enum member,
+ * and set this to be the previous value + 1
+ */
+ EnumMember emprev = null;
+ em.ed.members.foreachDsymbol( (s)
+ {
+ if (auto enm = s.isEnumMember())
+ {
+ if (enm == em)
+ return 1; // found
+ emprev = enm;
+ }
+ return 0; // continue
+ });
+
+ assert(emprev);
+ if (emprev.semanticRun < PASS.semanticdone) // if forward reference
+ emprev.dsymbolSemantic(emprev._scope); // resolve it
+ if (emprev.errors)
+ return errorReturn();
+
+ auto errors = global.startGagging();
+ Expression eprev = emprev.value;
+ assert(eprev);
+ // .toHeadMutable() due to https://issues.dlang.org/show_bug.cgi?id=18645
+ Type tprev = eprev.type.toHeadMutable().equals(em.ed.type.toHeadMutable())
+ ? em.ed.memtype
+ : eprev.type;
+ /*
+ https://issues.dlang.org/show_bug.cgi?id=20777
+ Previously this used getProperty, which doesn't consider anything user defined,
+ this construct does do that and thus fixes the bug.
+ */
+ Expression emax = DotIdExp.create(em.ed.loc, new TypeExp(em.ed.loc, tprev), Id.max);
+ emax = emax.expressionSemantic(sc);
+ emax = emax.ctfeInterpret();
+
+ // check that (eprev != emax)
+ Expression e = new EqualExp(EXP.equal, em.loc, eprev, emax);
+ e = e.expressionSemantic(sc);
+ e = e.ctfeInterpret();
+ if (global.endGagging(errors))
+ {
+ // display an introductory error before showing what actually failed
+ error(em.loc, "cannot check `%s` value for overflow", em.toPrettyChars());
+ // rerun to show errors
+ Expression e2 = DotIdExp.create(em.ed.loc, new TypeExp(em.ed.loc, tprev), Id.max);
+ e2 = e2.expressionSemantic(sc);
+ e2 = e2.ctfeInterpret();
+ e2 = new EqualExp(EXP.equal, em.loc, eprev, e2);
+ e2 = e2.expressionSemantic(sc);
+ e2 = e2.ctfeInterpret();
+ }
+ // now any errors are for generating a value
+ if (e.toInteger())
+ {
+ auto mt = em.ed.memtype;
+ if (!mt)
+ mt = eprev.type;
+ .error(em.loc, "%s `%s` initialization with `%s.%s+1` causes overflow for type `%s`", em.kind, em.toPrettyChars,
+ emprev.ed.toChars(), emprev.toChars(), mt.toChars());
+ return errorReturn();
+ }
+ errors = global.startGagging();
+ // Now set e to (eprev + 1)
+ e = new AddExp(em.loc, eprev, IntegerExp.literal!1);
+ e = e.expressionSemantic(sc);
+ e = e.castTo(sc, eprev.type);
+ e = e.ctfeInterpret();
+ if (global.endGagging(errors))
+ {
+ error(em.loc, "cannot generate value for `%s`", em.toPrettyChars());
+ // rerun to show errors
+ Expression e2 = new AddExp(em.loc, eprev, IntegerExp.literal!1);
+ e2 = e2.expressionSemantic(sc);
+ e2 = e2.castTo(sc, eprev.type);
+ e2 = e2.ctfeInterpret();
+ }
+ // save origValue (without cast) for better json output
+ if (e.op != EXP.error) // avoid duplicate diagnostics
+ {
+ assert(emprev.origValue);
+ em.origValue = new AddExp(em.loc, emprev.origValue, IntegerExp.literal!1);
+ em.origValue = em.origValue.expressionSemantic(sc);
+ em.origValue = em.origValue.ctfeInterpret();
+ }
+
+ if (e.op == EXP.error)
+ return errorReturn();
+ if (e.type.isfloating())
+ {
+ // Check that e != eprev (not always true for floats)
+ Expression etest = new EqualExp(EXP.equal, em.loc, e, eprev);
+ etest = etest.expressionSemantic(sc);
+ etest = etest.ctfeInterpret();
+ if (etest.toInteger())
+ {
+ .error(em.loc, "%s `%s` has inexact value due to loss of precision", em.kind, em.toPrettyChars);
+ return errorReturn();
+ }
+ }
+ em.value = e;
+ }
+ if (!em.origType)
+ em.type = em.value.type;
+
+ assert(em.origValue);
+ em.semanticRun = PASS.semanticdone;
+}
diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d
index cbf0118..1603f2b 100644
--- a/gcc/d/dmd/expression.d
+++ b/gcc/d/dmd/expression.d
@@ -721,6 +721,7 @@ extern (C++) abstract class Expression : ASTNode
inout(SuperExp) isSuperExp() { return op == EXP.super_ ? cast(typeof(return))this : null; }
inout(NullExp) isNullExp() { return op == EXP.null_ ? cast(typeof(return))this : null; }
inout(StringExp) isStringExp() { return op == EXP.string_ ? cast(typeof(return))this : null; }
+ inout(InterpExp) isInterpExp() { return op == EXP.interpolated ? cast(typeof(return))this : null; }
inout(TupleExp) isTupleExp() { return op == EXP.tuple ? cast(typeof(return))this : null; }
inout(ArrayLiteralExp) isArrayLiteralExp() { return op == EXP.arrayLiteral ? cast(typeof(return))this : null; }
inout(AssocArrayLiteralExp) isAssocArrayLiteralExp() { return op == EXP.assocArrayLiteral ? cast(typeof(return))this : null; }
@@ -1499,6 +1500,7 @@ extern (C++) final class StringExp : Expression
char* string; // if sz == 1
wchar* wstring; // if sz == 2
dchar* dstring; // if sz == 4
+ ulong* lstring; // if sz == 8
} // (const if ownedByCtfe == OwnedBy.code)
size_t len; // number of code units
ubyte sz = 1; // 1: char, 2: wchar, 4: dchar
@@ -1662,6 +1664,13 @@ extern (C++) final class StringExp : Expression
*/
dchar getCodeUnit(size_t i) const pure
{
+ assert(this.sz <= dchar.sizeof);
+ return cast(dchar) getIndex(i);
+ }
+
+ /// Returns: integer at index `i`
+ dinteger_t getIndex(size_t i) const pure
+ {
assert(i < len);
final switch (sz)
{
@@ -1671,6 +1680,8 @@ extern (C++) final class StringExp : Expression
return wstring[i];
case 4:
return dstring[i];
+ case 8:
+ return lstring[i];
}
}
@@ -1682,6 +1693,11 @@ extern (C++) final class StringExp : Expression
*/
extern (D) void setCodeUnit(size_t i, dchar c)
{
+ return setIndex(i, c);
+ }
+
+ extern (D) void setIndex(size_t i, long c)
+ {
assert(i < len);
final switch (sz)
{
@@ -1692,7 +1708,10 @@ extern (C++) final class StringExp : Expression
wstring[i] = cast(wchar)c;
break;
case 4:
- dstring[i] = c;
+ dstring[i] = cast(dchar) c;
+ break;
+ case 8:
+ lstring[i] = c;
break;
}
}
@@ -1847,6 +1866,28 @@ extern (C++) final class StringExp : Expression
}
}
+extern (C++) final class InterpExp : Expression
+{
+ char postfix = NoPostfix; // 'c', 'w', 'd'
+ OwnedBy ownedByCtfe = OwnedBy.code;
+ InterpolatedSet* interpolatedSet;
+
+ enum char NoPostfix = 0;
+
+ extern (D) this(const ref Loc loc, InterpolatedSet* set, char postfix = NoPostfix) scope
+ {
+ super(loc, EXP.interpolated);
+ this.interpolatedSet = set;
+ this.postfix = postfix;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+
/***********************************************************
* A sequence of expressions
*
@@ -5494,6 +5535,7 @@ private immutable ubyte[EXP.max+1] expSize = [
EXP.preMinusMinus: __traits(classInstanceSize, PreExp),
EXP.identifier: __traits(classInstanceSize, IdentifierExp),
EXP.string_: __traits(classInstanceSize, StringExp),
+ EXP.interpolated: __traits(classInstanceSize, InterpExp),
EXP.this_: __traits(classInstanceSize, ThisExp),
EXP.super_: __traits(classInstanceSize, SuperExp),
EXP.halt: __traits(classInstanceSize, HaltExp),
diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h
index f57f6a4..d53cc3e 100644
--- a/gcc/d/dmd/expression.h
+++ b/gcc/d/dmd/expression.h
@@ -38,6 +38,7 @@ class TemplateDeclaration;
class ClassDeclaration;
class OverloadSet;
class StringExp;
+class InterpExp;
class LoweredAssignExp;
#ifdef IN_GCC
typedef union tree_node Symbol;
@@ -129,6 +130,7 @@ public:
SuperExp* isSuperExp();
NullExp* isNullExp();
StringExp* isStringExp();
+ InterpExp* isInterpExp();
TupleExp* isTupleExp();
ArrayLiteralExp* isArrayLiteralExp();
AssocArrayLiteralExp* isAssocArrayLiteralExp();
@@ -352,7 +354,7 @@ class StringExp final : public Expression
public:
utf8_t postfix; // 'c', 'w', 'd'
OwnedBy ownedByCtfe;
- void *string; // char, wchar, or dchar data
+ void *string; // char, wchar, dchar, or long data
size_t len; // number of chars, wchars, or dchars
unsigned char sz; // 1: char, 2: wchar, 4: dchar
d_bool committed; // if type is committed
@@ -362,6 +364,7 @@ public:
static StringExp *create(const Loc &loc, const void *s, d_size_t len);
bool equals(const RootObject * const o) const override;
char32_t getCodeUnit(d_size_t i) const;
+ dinteger_t getIndex(d_size_t i) const;
StringExp *toStringExp() override;
Optional<bool> toBool() override;
bool isLvalue() override;
@@ -370,6 +373,16 @@ public:
void writeTo(void* dest, bool zero, int tyto = 0) const;
};
+class InterpExp final : public Expression
+{
+public:
+ utf8_t postfix; // 'c', 'w', 'd'
+ OwnedBy ownedByCtfe;
+ void* interpolatedSet;
+
+ void accept(Visitor* v) override { v->visit(this); }
+};
+
// Tuple
class TupleExp final : public Expression
diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d
index d464574..f213303 100644
--- a/gcc/d/dmd/expressionsem.d
+++ b/gcc/d/dmd/expressionsem.d
@@ -42,10 +42,12 @@ import dmd.dsymbolsem;
import dmd.dtemplate;
import dmd.errors;
import dmd.errorsink;
+import dmd.enumsem;
import dmd.escape;
import dmd.expression;
import dmd.file_manager;
import dmd.func;
+import dmd.funcsem;
import dmd.globals;
import dmd.hdrgen;
import dmd.id;
@@ -1579,7 +1581,7 @@ Lagain:
if (auto f = s.isFuncDeclaration())
{
f = f.toAliasFunc();
- if (!f.functionSemantic())
+ if (!functionSemantic(f))
return ErrorExp.get();
if (!hasOverloads && f.checkForwardRef(loc))
@@ -2866,7 +2868,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
// If inferring return type, and semantic3() needs to be run if not already run
if (!tf.next && fd.inferRetType)
{
- fd.functionSemantic();
+ functionSemantic(fd);
}
else if (fd && fd.parent)
{
@@ -4145,6 +4147,84 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
result = e;
}
+ override void visit(InterpExp e)
+ {
+ // the lexer breaks up into an odd/even array of literals and expression code
+ // we need to turn that into:
+ /+
+ tuple(
+ .object.imported!"core.interpolation".InterpolationHeader(),
+ ...
+ .object.imported!"core.interpolation".InterpolationFooter()
+ )
+
+ There the ... loops through them all, making the even ones
+ .object.imported!"core.interpolation".InterpolatedLiteral!str()
+ and making the odd ones
+ .object.imported!"core.interpolation".InterpolatedExpression!str(),
+ the code represented by str
+
+ Empty string literals are skipped as they provide no additional information.
+ +/
+
+ if (e.postfix)
+ error(e.loc, "String postfixes on interpolated expression sequences are not allowed.");
+
+ Expression makeNonTemplateItem(Identifier which) {
+ Expression id = new IdentifierExp(e.loc, Id.empty);
+ id = new DotIdExp(e.loc, id, Id.object);
+ auto moduleNameArgs = new Objects();
+ moduleNameArgs.push(new StringExp(e.loc, "core.interpolation"));
+ id = new DotTemplateInstanceExp(e.loc, id, Id.imported, moduleNameArgs);
+ id = new DotIdExp(e.loc, id, which);
+ id = new CallExp(e.loc, id, new Expressions());
+ return id;
+ }
+
+ Expression makeTemplateItem(Identifier which, string arg) {
+ Expression id = new IdentifierExp(e.loc, Id.empty);
+ id = new DotIdExp(e.loc, id, Id.object);
+ auto moduleNameArgs = new Objects();
+ moduleNameArgs.push(new StringExp(e.loc, "core.interpolation"));
+ id = new DotTemplateInstanceExp(e.loc, id, Id.imported, moduleNameArgs);
+ auto tiargs = new Objects();
+ auto templateStringArg = new StringExp(e.loc, arg);
+ // banning those instead of forwarding them
+ // templateStringArg.postfix = e.postfix; // forward the postfix to these literals
+ tiargs.push(templateStringArg);
+ id = new DotTemplateInstanceExp(e.loc, id, which, tiargs);
+ id = new CallExp(e.loc, id, new Expressions());
+ return id;
+ }
+
+ auto arguments = new Expressions();
+ arguments.push(makeNonTemplateItem(Id.InterpolationHeader));
+
+ foreach (idx, str; e.interpolatedSet.parts)
+ {
+ if (idx % 2 == 0)
+ {
+ if (str.length > 0)
+ arguments.push(makeTemplateItem(Id.InterpolatedLiteral, str));
+ }
+ else
+ {
+ arguments.push(makeTemplateItem(Id.InterpolatedExpression, str));
+ Expressions* mix = new Expressions();
+ mix.push(new StringExp(e.loc, str));
+ // FIXME: i'd rather not use MixinExp but idk how to do it lol
+ arguments.push(new MixinExp(e.loc, mix));
+ }
+ }
+
+ arguments.push(makeNonTemplateItem(Id.InterpolationFooter));
+
+ auto loweredTo = new TupleExp(e.loc, arguments);
+ visit(loweredTo);
+
+ result = loweredTo;
+ }
+
override void visit(StringExp e)
{
static if (LOGSEMANTIC)
@@ -5366,7 +5446,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (fd)
{
//printf("L%d fd = %s\n", __LINE__, f.toChars());
- if (!fd.functionSemantic())
+ if (!functionSemantic(fd))
return setError();
}
@@ -6564,10 +6644,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
.errorSupplemental(exp.loc, "the following error occured while looking for a UFCS match");
}
- .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`",
- exp.f.kind(), exp.f.toPrettyChars(), parametersTypeToChars(tf.parameterList), buf.peekChars());
+ .error(exp.loc, "%s `%s` is not callable using argument types `%s`",
+ exp.f.kind(), exp.f.toChars(), buf.peekChars());
if (failMessage)
errorSupplemental(exp.loc, "%s", failMessage);
+ .errorSupplemental(exp.f.loc, "`%s%s` declared here", exp.f.toPrettyChars(), parametersTypeToChars(tf.parameterList));
exp.f = null;
}
@@ -7549,7 +7630,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
se = se.toUTF8(sc);
auto namez = se.toStringz();
- if (!global.filePath)
+ if (!global.filePath.length)
{
error(e.loc, "need `-J` switch to import text file `%s`", namez.ptr);
return setError();
@@ -7580,12 +7661,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return setError();
}
- auto resolvedNamez = FileName.searchPath(global.filePath, namez, false);
+ auto resolvedNamez = FileName.searchPath(global.filePath[], namez, false);
if (!resolvedNamez)
{
error(e.loc, "file `%s` cannot be found or not in a path specified with `-J`", se.toChars());
errorSupplemental(e.loc, "Path(s) searched (as provided by `-J`):");
- foreach (idx, path; *global.filePath)
+ foreach (idx, path; global.filePath[])
{
const attr = FileName.exists(path);
const(char)* err = attr == 2 ? "" :
@@ -8170,7 +8251,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (FuncDeclaration fd = exp.var.isFuncDeclaration())
{
// for functions, do checks after overload resolution
- if (!fd.functionSemantic())
+ if (!functionSemantic(fd))
return setError();
/* https://issues.dlang.org/show_bug.cgi?id=13843
@@ -8937,7 +9018,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
bool err = false;
if (cd.dtor)
{
- err |= !cd.dtor.functionSemantic();
+ err |= !functionSemantic(cd.dtor);
err |= cd.dtor.checkPurity(exp.loc, sc);
err |= cd.dtor.checkSafety(exp.loc, sc);
err |= cd.dtor.checkNogc(exp.loc, sc);
@@ -14356,7 +14437,7 @@ Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag)
if (auto f = s.isFuncDeclaration())
{
//printf("it's a function\n");
- if (!f.functionSemantic())
+ if (!functionSemantic(f))
return ErrorExp.get();
Expression e;
if (f.needThis())
diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d
index 370da6f..adfecc8 100644
--- a/gcc/d/dmd/func.d
+++ b/gcc/d/dmd/func.d
@@ -39,6 +39,7 @@ import dmd.dtemplate;
import dmd.errors;
import dmd.escape;
import dmd.expression;
+import dmd.funcsem;
import dmd.globals;
import dmd.hdrgen;
import dmd.id;
@@ -467,102 +468,12 @@ extern (C++) class FuncDeclaration : Declaration
}
/****************************************************
- * Resolve forward reference of function signature -
- * parameter types, return type, and attributes.
- * Returns:
- * false if any errors exist in the signature.
- */
- final bool functionSemantic()
- {
- //printf("functionSemantic() %p %s\n", this, toChars());
- if (!_scope)
- return !errors;
-
- this.cppnamespace = _scope.namespace;
-
- if (!originalType) // semantic not yet run
- {
- TemplateInstance spec = isSpeculative();
- uint olderrs = global.errors;
- uint oldgag = global.gag;
- if (global.gag && !spec)
- global.gag = 0;
- dsymbolSemantic(this, _scope);
- global.gag = oldgag;
- if (spec && global.errors != olderrs)
- spec.errors = (global.errors - olderrs != 0);
- if (olderrs != global.errors) // if errors compiling this function
- return false;
- }
-
- // if inferring return type, sematic3 needs to be run
- // - When the function body contains any errors, we cannot assume
- // the inferred return type is valid.
- // So, the body errors should become the function signature error.
- if (inferRetType && type && !type.nextOf())
- return functionSemantic3();
-
- TemplateInstance ti;
- if (isInstantiated() && !isVirtualMethod() &&
- ((ti = parent.isTemplateInstance()) is null || ti.isTemplateMixin() || ti.tempdecl.ident == ident))
- {
- AggregateDeclaration ad = isMemberLocal();
- if (ad && ad.sizeok != Sizeok.done)
- {
- /* Currently dmd cannot resolve forward references per methods,
- * then setting SIZOKfwd is too conservative and would break existing code.
- * So, just stop method attributes inference until ad.dsymbolSemantic() done.
- */
- //ad.sizeok = Sizeok.fwd;
- }
- else
- return functionSemantic3() || !errors;
- }
-
- if (storage_class & STC.inference)
- return functionSemantic3() || !errors;
-
- return !errors;
- }
-
- /****************************************************
- * Resolve forward reference of function body.
- * Returns false if any errors exist in the body.
- */
- final bool functionSemantic3()
- {
- if (semanticRun < PASS.semantic3 && _scope)
- {
- /* Forward reference - we need to run semantic3 on this function.
- * If errors are gagged, and it's not part of a template instance,
- * we need to temporarily ungag errors.
- */
- TemplateInstance spec = isSpeculative();
- uint olderrs = global.errors;
- uint oldgag = global.gag;
- if (global.gag && !spec)
- global.gag = 0;
- semantic3(this, _scope);
- global.gag = oldgag;
-
- // If it is a speculatively-instantiated template, and errors occur,
- // we need to mark the template as having errors.
- if (spec && global.errors != olderrs)
- spec.errors = (global.errors - olderrs != 0);
- if (olderrs != global.errors) // if errors compiling this function
- return false;
- }
-
- return !errors && !this.hasSemantic3Errors();
- }
-
- /****************************************************
* Check that this function type is properly resolved.
* If not, report "forward reference error" and return true.
*/
extern (D) final bool checkForwardRef(const ref Loc loc)
{
- if (!functionSemantic())
+ if (!functionSemantic(this))
return true;
/* No deco means the functionSemantic() call could not resolve
@@ -579,72 +490,6 @@ extern (C++) class FuncDeclaration : Declaration
return false;
}
- // called from semantic3
- /**
- * Creates and returns the hidden parameters for this function declaration.
- *
- * Hidden parameters include the `this` parameter of a class, struct or
- * nested function and the selector parameter for Objective-C methods.
- */
- extern (D) final void declareThis(Scope* sc)
- {
- const bool dualCtx = (toParent2() != toParentLocal());
- if (dualCtx)
- this.hasDualContext = true;
- auto ad = isThis();
- if (!dualCtx && !ad && !isNested())
- {
- vthis = null;
- objc.selectorParameter = null;
- return;
- }
-
- Type addModStc(Type t)
- {
- return t.addMod(type.mod).addStorageClass(storage_class);
- }
-
- if (dualCtx || isNested())
- {
- /* The 'this' for a nested function is the link to the
- * enclosing function's stack frame.
- * Note that nested functions and member functions are disjoint.
- */
- Type tthis = addModStc(dualCtx ?
- Type.tvoidptr.sarrayOf(2).pointerTo() :
- Type.tvoid.pointerTo());
- vthis = new VarDeclaration(loc, tthis, dualCtx ? Id.this2 : Id.capture, null);
- vthis.storage_class |= STC.parameter | STC.nodtor;
- }
- else if (ad)
- {
- Type thandle = addModStc(ad.handleType());
- vthis = new ThisDeclaration(loc, thandle);
- vthis.storage_class |= STC.parameter;
- if (thandle.ty == Tstruct)
- {
- vthis.storage_class |= STC.ref_;
- }
- }
-
- if (auto tf = type.isTypeFunction())
- {
- if (tf.isreturn)
- vthis.storage_class |= STC.return_;
- if (tf.isScopeQual)
- vthis.storage_class |= STC.scope_;
- if (tf.isreturnscope)
- vthis.storage_class |= STC.returnScope;
- }
-
- vthis.dsymbolSemantic(sc);
- if (!sc.insert(vthis))
- assert(0);
- vthis.parent = this;
- if (ad)
- objc.selectorParameter = .objc.createSelectorParameter(this, sc);
- }
-
override final bool equals(const RootObject o) const
{
if (this == o)
@@ -1104,20 +949,24 @@ extern (C++) class FuncDeclaration : Declaration
}
/*************************************
- * Determine partial specialization order of 'this' vs g.
+ * Determine partial specialization order of functions `f` vs `g`.
* This is very similar to TemplateDeclaration::leastAsSpecialized().
+ * Params:
+ * f = first function
+ * g = second function
+ * names = names of parameters
* Returns:
* match 'this' is at least as specialized as g
* 0 g is more specialized than 'this'
*/
- final MATCH leastAsSpecialized(FuncDeclaration g, Identifiers* names)
+ static MATCH leastAsSpecialized(FuncDeclaration f, FuncDeclaration g, Identifiers* names)
{
enum LOG_LEASTAS = 0;
static if (LOG_LEASTAS)
{
import core.stdc.stdio : printf;
- printf("%s.leastAsSpecialized(%s, %s)\n", toChars(), g.toChars(), names ? names.toChars() : "null");
- printf("%s, %s\n", type.toChars(), g.type.toChars());
+ printf("leastAsSpecialized(%s, %s, %s)\n", f.toChars(), g.toChars(), names ? names.toChars() : "null");
+ printf("%s, %s\n", f.type.toChars(), g.type.toChars());
}
/* This works by calling g() with f()'s parameters, and
@@ -1125,15 +974,15 @@ extern (C++) class FuncDeclaration : Declaration
* as g() is.
*/
- TypeFunction tf = type.toTypeFunction();
+ TypeFunction tf = f.type.toTypeFunction();
TypeFunction tg = g.type.toTypeFunction();
/* If both functions have a 'this' pointer, and the mods are not
* the same and g's is not const, then this is less specialized.
*/
- if (needThis() && g.needThis() && tf.mod != tg.mod)
+ if (f.needThis() && g.needThis() && tf.mod != tg.mod)
{
- if (isCtorDeclaration())
+ if (f.isCtorDeclaration())
{
if (!MODimplicitConv(tg.mod, tf.mod))
return MATCH.nomatch;
@@ -3037,7 +2886,7 @@ Expression addInvariant(AggregateDeclaration ad, VarDeclaration vthis)
// Workaround for https://issues.dlang.org/show_bug.cgi?id=13394
// For the correct mangling,
// run attribute inference on inv if needed.
- inv.functionSemantic();
+ functionSemantic(inv);
}
//e = new DsymbolExp(Loc.initial, inv);
@@ -3316,7 +3165,7 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
if (m.count == 1) // exactly one match
{
if (!(flags & FuncResolveFlag.quiet))
- m.lastf.functionSemantic();
+ functionSemantic(m.lastf);
return m.lastf;
}
if ((flags & FuncResolveFlag.overloadOnly) && !tthis && m.lastf.needThis())
@@ -3386,12 +3235,18 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
// all of overloads are templates
if (td)
{
- const(char)* msg = "none of the overloads of %s `%s.%s` are callable using argument types `!(%s)%s`";
if (!od && !td.overnext)
- msg = "%s `%s.%s` is not callable using argument types `!(%s)%s`";
- .error(loc, msg,
+ {
+ .error(loc, "%s `%s` is not callable using argument types `!(%s)%s`",
+ td.kind(), td.ident.toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars());
+ }
+ else
+ {
+ .error(loc, "none of the overloads of %s `%s.%s` are callable using argument types `!(%s)%s`",
td.kind(), td.parent.toPrettyChars(), td.ident.toChars(),
tiargsBuf.peekChars(), fargsBuf.peekChars());
+ }
+
if (!global.gag || global.params.v.showGaggedErrors)
printCandidates(loc, td, sc.isDeprecated());
@@ -3574,7 +3429,11 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration))
if (!print)
return true;
- const tmsg = td.toCharsNoConstraints();
+ OutBuffer buf;
+ HdrGenState hgs;
+ hgs.skipConstraints = true;
+ toCharsMaybeConstraints(td, buf, hgs);
+ const tmsg = buf.peekChars();
const cmsg = td.getConstraintEvalError(constraintsTip);
// add blank space if there are multiple candidates
diff --git a/gcc/d/dmd/funcsem.d b/gcc/d/dmd/funcsem.d
new file mode 100644
index 0000000..8420179
--- /dev/null
+++ b/gcc/d/dmd/funcsem.d
@@ -0,0 +1,219 @@
+/**
+ * Does semantic analysis for functions.
+ *
+ * Specification: $(LINK2 https://dlang.org/spec/function.html, Functions)
+ *
+ * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/funcsem.d, _funcsem.d)
+ * Documentation: https://dlang.org/phobos/dmd_funcsem.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/funcsem.d
+ */
+
+module dmd.funcsem;
+
+import core.stdc.stdio;
+
+import dmd.aggregate;
+import dmd.arraytypes;
+import dmd.astenums;
+import dmd.blockexit;
+import dmd.gluelayer;
+import dmd.dcast;
+import dmd.dclass;
+import dmd.declaration;
+import dmd.delegatize;
+import dmd.dinterpret;
+import dmd.dmodule;
+import dmd.dscope;
+import dmd.dstruct;
+import dmd.dsymbol;
+import dmd.dsymbolsem;
+import dmd.dtemplate;
+import dmd.errors;
+import dmd.escape;
+import dmd.expression;
+import dmd.func;
+import dmd.globals;
+import dmd.hdrgen;
+import dmd.id;
+import dmd.identifier;
+import dmd.init;
+import dmd.location;
+import dmd.mtype;
+import dmd.objc;
+import dmd.root.aav;
+import dmd.common.outbuffer;
+import dmd.rootobject;
+import dmd.root.string;
+import dmd.root.stringtable;
+import dmd.semantic2;
+import dmd.semantic3;
+import dmd.statement_rewrite_walker;
+import dmd.statement;
+import dmd.statementsem;
+import dmd.tokens;
+import dmd.visitor;
+
+/****************************************************
+ * Resolve forward reference of function signature -
+ * parameter types, return type, and attributes.
+ * Params:
+ * fd = function declaration
+ * Returns:
+ * false if any errors exist in the signature.
+ */
+public
+extern (C++)
+bool functionSemantic(FuncDeclaration fd)
+{
+ //printf("functionSemantic() %p %s\n", this, toChars());
+ if (!fd._scope)
+ return !fd.errors;
+
+ fd.cppnamespace = fd._scope.namespace;
+
+ if (!fd.originalType) // semantic not yet run
+ {
+ TemplateInstance spec = fd.isSpeculative();
+ uint olderrs = global.errors;
+ uint oldgag = global.gag;
+ if (global.gag && !spec)
+ global.gag = 0;
+ dsymbolSemantic(fd, fd._scope);
+ global.gag = oldgag;
+ if (spec && global.errors != olderrs)
+ spec.errors = (global.errors - olderrs != 0);
+ if (olderrs != global.errors) // if errors compiling this function
+ return false;
+ }
+
+ // if inferring return type, sematic3 needs to be run
+ // - When the function body contains any errors, we cannot assume
+ // the inferred return type is valid.
+ // So, the body errors should become the function signature error.
+ if (fd.inferRetType && fd.type && !fd.type.nextOf())
+ return fd.functionSemantic3();
+
+ TemplateInstance ti;
+ if (fd.isInstantiated() && !fd.isVirtualMethod() &&
+ ((ti = fd.parent.isTemplateInstance()) is null || ti.isTemplateMixin() || ti.tempdecl.ident == fd.ident))
+ {
+ AggregateDeclaration ad = fd.isMemberLocal();
+ if (ad && ad.sizeok != Sizeok.done)
+ {
+ /* Currently dmd cannot resolve forward references per methods,
+ * then setting SIZOKfwd is too conservative and would break existing code.
+ * So, just stop method attributes inference until ad.dsymbolSemantic() done.
+ */
+ //ad.sizeok = Sizeok.fwd;
+ }
+ else
+ return fd.functionSemantic3() || !fd.errors;
+ }
+
+ if (fd.storage_class & STC.inference)
+ return fd.functionSemantic3() || !fd.errors;
+
+ return !fd.errors;
+}
+
+/****************************************************
+ * Resolve forward reference of function body.
+ * Returns false if any errors exist in the body.
+ */
+public
+extern (C++)
+bool functionSemantic3(FuncDeclaration fd)
+{
+ if (fd.semanticRun < PASS.semantic3 && fd._scope)
+ {
+ /* Forward reference - we need to run semantic3 on this function.
+ * If errors are gagged, and it's not part of a template instance,
+ * we need to temporarily ungag errors.
+ */
+ TemplateInstance spec = fd.isSpeculative();
+ uint olderrs = global.errors;
+ uint oldgag = global.gag;
+ if (global.gag && !spec)
+ global.gag = 0;
+ semantic3(fd, fd._scope);
+ global.gag = oldgag;
+
+ // If it is a speculatively-instantiated template, and errors occur,
+ // we need to mark the template as having errors.
+ if (spec && global.errors != olderrs)
+ spec.errors = (global.errors - olderrs != 0);
+ if (olderrs != global.errors) // if errors compiling this function
+ return false;
+ }
+
+ return !fd.errors && !fd.hasSemantic3Errors();
+}
+
+// called from semantic3
+/**
+ * Creates and returns the hidden parameters for this function declaration.
+ *
+ * Hidden parameters include the `this` parameter of a class, struct or
+ * nested function and the selector parameter for Objective-C methods.
+ */
+extern (D) void declareThis(FuncDeclaration fd, Scope* sc)
+{
+ const bool dualCtx = (fd.toParent2() != fd.toParentLocal());
+ if (dualCtx)
+ fd.hasDualContext = true;
+ auto ad = fd.isThis();
+ if (!dualCtx && !ad && !fd.isNested())
+ {
+ fd.vthis = null;
+ fd.objc.selectorParameter = null;
+ return;
+ }
+
+ Type addModStc(Type t)
+ {
+ return t.addMod(fd.type.mod).addStorageClass(fd.storage_class);
+ }
+
+ if (dualCtx || fd.isNested())
+ {
+ /* The 'this' for a nested function is the link to the
+ * enclosing function's stack frame.
+ * Note that nested functions and member functions are disjoint.
+ */
+ Type tthis = addModStc(dualCtx ?
+ Type.tvoidptr.sarrayOf(2).pointerTo() :
+ Type.tvoid.pointerTo());
+ fd.vthis = new VarDeclaration(fd.loc, tthis, dualCtx ? Id.this2 : Id.capture, null);
+ fd.vthis.storage_class |= STC.parameter | STC.nodtor;
+ }
+ else if (ad)
+ {
+ Type thandle = addModStc(ad.handleType());
+ fd.vthis = new ThisDeclaration(fd.loc, thandle);
+ fd.vthis.storage_class |= STC.parameter;
+ if (thandle.ty == Tstruct)
+ {
+ fd.vthis.storage_class |= STC.ref_;
+ }
+ }
+
+ if (auto tf = fd.type.isTypeFunction())
+ {
+ if (tf.isreturn)
+ fd.vthis.storage_class |= STC.return_;
+ if (tf.isScopeQual)
+ fd.vthis.storage_class |= STC.scope_;
+ if (tf.isreturnscope)
+ fd.vthis.storage_class |= STC.returnScope;
+ }
+
+ fd.vthis.dsymbolSemantic(sc);
+ if (!sc.insert(fd.vthis))
+ assert(0);
+ fd.vthis.parent = fd;
+ if (ad)
+ fd.objc.selectorParameter = .objc.createSelectorParameter(fd, sc);
+}
diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d
index e9e73e8..af7b1fa 100644
--- a/gcc/d/dmd/globals.d
+++ b/gcc/d/dmd/globals.d
@@ -219,8 +219,8 @@ extern (C++) struct Param
const(char)[] argv0; // program name
Array!(const(char)*) modFileAliasStrings; // array of char*'s of -I module filename alias strings
- Array!(const(char)*)* imppath; // array of char*'s of where to look for import modules
- Array!(const(char)*)* fileImppath; // array of char*'s of where to look for file import modules
+ Array!(const(char)*) imppath; // array of char*'s of where to look for import modules
+ Array!(const(char)*) fileImppath; // array of char*'s of where to look for file import modules
const(char)[] objdir; // .obj/.lib file output directory
const(char)[] objname; // .obj file output name
const(char)[] libname; // .lib file output name
@@ -280,8 +280,8 @@ extern (C++) struct Global
string copyright = "Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved";
string written = "written by Walter Bright";
- Array!(const(char)*)* path; /// Array of char*'s which form the import lookup path
- Array!(const(char)*)* filePath; /// Array of char*'s which form the file import lookup path
+ Array!(const(char)*) path; /// Array of char*'s which form the import lookup path
+ Array!(const(char)*) filePath; /// Array of char*'s which form the file import lookup path
private enum string _version = import("VERSION");
char[26] datetime; /// string returned by ctime()
@@ -296,8 +296,8 @@ extern (C++) struct Global
void* console; /// opaque pointer to console for controlling text attributes
- Array!Identifier* versionids; /// command line versions and predefined versions
- Array!Identifier* debugids; /// command line debug versions and predefined versions
+ Array!Identifier versionids; /// command line versions and predefined versions
+ Array!Identifier debugids; /// command line debug versions and predefined versions
bool hasMainFunction; /// Whether a main function has already been compiled in (for -main switch)
uint varSequenceNumber = 1; /// Relative lifetime of `VarDeclaration` within a function, used for `scope` checks
diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h
index 93e7c64..f553ae6 100644
--- a/gcc/d/dmd/globals.h
+++ b/gcc/d/dmd/globals.h
@@ -202,8 +202,8 @@ struct Param
DString argv0; // program name
Array<const char *> modFileAliasStrings; // array of char*'s of -I module filename alias strings
- Array<const char *> *imppath; // array of char*'s of where to look for import modules
- Array<const char *> *fileImppath; // array of char*'s of where to look for file import modules
+ Array<const char *> imppath; // array of char*'s of where to look for import modules
+ Array<const char *> fileImppath; // array of char*'s of where to look for file import modules
DString objdir; // .obj/.lib file output directory
DString objname; // .obj file output name
DString libname; // .lib file output name
@@ -282,8 +282,8 @@ struct Global
const DString copyright;
const DString written;
- Array<const char *> *path; // Array of char*'s which form the import lookup path
- Array<const char *> *filePath; // Array of char*'s which form the file import lookup path
+ Array<const char *> path; // Array of char*'s which form the import lookup path
+ Array<const char *> filePath; // Array of char*'s which form the file import lookup path
char datetime[26]; /// string returned by ctime()
CompileEnv compileEnv;
@@ -297,8 +297,8 @@ struct Global
void* console; // opaque pointer to console for controlling text attributes
- Array<class Identifier*>* versionids; // command line versions and predefined versions
- Array<class Identifier*>* debugids; // command line debug versions and predefined versions
+ Array<class Identifier*> versionids; // command line versions and predefined versions
+ Array<class Identifier*> debugids; // command line debug versions and predefined versions
d_bool hasMainFunction;
unsigned varSequenceNumber;
diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d
index 570c662..030153c 100644
--- a/gcc/d/dmd/hdrgen.d
+++ b/gcc/d/dmd/hdrgen.d
@@ -60,6 +60,7 @@ struct HdrGenState
bool importcHdr; /// true if generating a .di file from an ImportC file
bool doFuncBodies; /// include function bodies in output
bool vcg_ast; /// write out codegen-ast
+ bool skipConstraints; // skip constraints when doing templates
bool fullQual; /// fully qualify types when printing
int tpltMember;
@@ -1957,6 +1958,47 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs)
s.accept(v);
}
+// Note: this function is not actually `const`, because iterating the
+// function parameter list may run dsymbolsemantic on enum types
+public
+void toCharsMaybeConstraints(const TemplateDeclaration td, ref OutBuffer buf, ref HdrGenState hgs)
+{
+ buf.writestring(td.ident == Id.ctor ? "this" : td.ident.toString());
+ buf.writeByte('(');
+ foreach (i, const tp; *td.parameters)
+ {
+ if (i)
+ buf.writestring(", ");
+ toCBuffer(tp, buf, hgs);
+ }
+ buf.writeByte(')');
+
+ if (td.onemember)
+ {
+ if (const fd = td.onemember.isFuncDeclaration())
+ {
+ if (TypeFunction tf = cast(TypeFunction)fd.type.isTypeFunction())
+ {
+ // !! Casted away const
+ buf.writestring(parametersTypeToChars(tf.parameterList));
+ if (tf.mod)
+ {
+ buf.writeByte(' ');
+ buf.MODtoBuffer(tf.mod);
+ }
+ }
+ }
+ }
+
+ if (!hgs.skipConstraints &&
+ td.constraint)
+ {
+ buf.writestring(" if (");
+ toCBuffer(td.constraint, buf, hgs);
+ buf.writeByte(')');
+ }
+}
+
/*****************************************
* Pretty-print a template parameter list to a buffer.
@@ -2234,6 +2276,16 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenSt
void visitString(StringExp e)
{
+ if (e.hexString || e.sz == 8)
+ {
+ buf.writeByte('x');
+ buf.writeByte('"');
+ buf.writeHexString(e.peekData, true);
+ buf.writeByte('"');
+ if (e.postfix)
+ buf.writeByte(e.postfix);
+ return;
+ }
buf.writeByte('"');
const o = buf.length;
foreach (i; 0 .. e.len)
@@ -2247,6 +2299,37 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenSt
buf.writeByte(e.postfix);
}
+ void visitInterpolation(InterpExp e)
+ {
+ buf.writeByte('i');
+ buf.writeByte('"');
+ const o = buf.length;
+
+ foreach (idx, str; e.interpolatedSet.parts)
+ {
+ if (idx % 2 == 0)
+ {
+ foreach(ch; str)
+ writeCharLiteral(buf, ch);
+ }
+ else
+ {
+ buf.writeByte('$');
+ buf.writeByte('(');
+ foreach(ch; str)
+ buf.writeByte(ch);
+ buf.writeByte(')');
+ }
+ }
+
+ if (hgs.ddoc)
+ escapeDdocString(buf, o);
+ buf.writeByte('"');
+ if (e.postfix)
+ buf.writeByte(e.postfix);
+
+ }
+
void visitArrayLiteral(ArrayLiteralExp e)
{
buf.writeByte('[');
@@ -2827,6 +2910,7 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenSt
case EXP.super_: return visitSuper(e.isSuperExp());
case EXP.null_: return visitNull(e.isNullExp());
case EXP.string_: return visitString(e.isStringExp());
+ case EXP.interpolated: return visitInterpolation(e.isInterpExp());
case EXP.arrayLiteral: return visitArrayLiteral(e.isArrayLiteralExp());
case EXP.assocArrayLiteral: return visitAssocArrayLiteral(e.isAssocArrayLiteralExp());
case EXP.structLiteral: return visitStructLiteral(e.isStructLiteralExp());
diff --git a/gcc/d/dmd/id.d b/gcc/d/dmd/id.d
index a66f2af4..5ad324d 100644
--- a/gcc/d/dmd/id.d
+++ b/gcc/d/dmd/id.d
@@ -335,6 +335,12 @@ immutable Msgtable[] msgtable =
{ "_d_arrayassign_l" },
{ "_d_arrayassign_r" },
+ { "imported" },
+ { "InterpolationHeader" },
+ { "InterpolationFooter" },
+ { "InterpolatedLiteral" },
+ { "InterpolatedExpression" },
+
// For pragma's
{ "Pinline", "inline" },
{ "lib" },
diff --git a/gcc/d/dmd/json.d b/gcc/d/dmd/json.d
index 9819c3a..7c65067 100644
--- a/gcc/d/dmd/json.d
+++ b/gcc/d/dmd/json.d
@@ -873,12 +873,9 @@ public:
propertyStart("predefinedVersions");
arrayStart();
- if (global.versionids)
+ foreach (const versionid; global.versionids)
{
- foreach (const versionid; *global.versionids)
- {
- item(versionid.toString());
- }
+ item(versionid.toString());
}
arrayEnd();
@@ -905,12 +902,9 @@ public:
propertyStart("importPaths");
arrayStart();
- if (global.params.imppath)
+ foreach (importPath; global.params.imppath[])
{
- foreach (importPath; *global.params.imppath)
- {
- item(importPath.toDString);
- }
+ item(importPath.toDString);
}
arrayEnd();
diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d
index 5eadd72..937597c 100644
--- a/gcc/d/dmd/lexer.d
+++ b/gcc/d/dmd/lexer.d
@@ -506,6 +506,29 @@ class Lexer
}
else
goto case_ident;
+ case 'i':
+ if (Ccompile)
+ goto case_ident;
+ if (p[1] == '"')
+ {
+ p++; // skip the i
+ escapeStringConstant(t, true);
+ return;
+ }
+ else if (p[1] == '`')
+ {
+ p++; // skip the i
+ wysiwygStringConstant(t, true);
+ return;
+ }
+ else if (p[1] == 'q' && p[2] == '{')
+ {
+ p += 2; // skip the i and q
+ tokenStringConstant(t, true);
+ return;
+ }
+ else
+ goto case_ident;
case '"':
escapeStringConstant(t);
return;
@@ -517,7 +540,7 @@ class Lexer
case 'f':
case 'g':
case 'h':
- case 'i':
+ /*case 'i':*/
case 'j':
case 'k':
case 'l':
@@ -1429,9 +1452,18 @@ class Lexer
Params:
result = pointer to the token that accepts the result
*/
- private void wysiwygStringConstant(Token* result)
+ private void wysiwygStringConstant(Token* result, bool supportInterpolation = false)
{
- result.value = TOK.string_;
+ if (supportInterpolation)
+ {
+ result.value = TOK.interpolated;
+ result.interpolatedSet = null;
+ }
+ else
+ {
+ result.value = TOK.string_;
+ }
+
Loc start = loc();
auto terminator = p[0];
p++;
@@ -1451,6 +1483,14 @@ class Lexer
c = '\n'; // treat EndOfLine as \n character
endOfLine();
break;
+ case '$':
+ if (!supportInterpolation)
+ goto default;
+
+ if (!handleInterpolatedSegment(result, start))
+ goto default;
+
+ continue;
case 0:
case 0x1A:
error("unterminated string constant starting at %s", start.toChars());
@@ -1461,7 +1501,11 @@ class Lexer
default:
if (c == terminator)
{
- result.setString(stringbuffer);
+ if (supportInterpolation)
+ result.appendInterpolatedPart(stringbuffer);
+ else
+ result.setString(stringbuffer);
+
stringPostfix(result);
return;
}
@@ -1736,13 +1780,21 @@ class Lexer
Params:
result = pointer to the token that accepts the result
*/
- private void tokenStringConstant(Token* result)
+ private void tokenStringConstant(Token* result, bool supportInterpolation = false)
{
- result.value = TOK.string_;
+ if (supportInterpolation)
+ {
+ result.value = TOK.interpolated;
+ result.interpolatedSet = null;
+ }
+ else
+ {
+ result.value = TOK.string_;
+ }
uint nest = 1;
const start = loc();
- const pstart = ++p;
+ auto pstart = ++p;
inTokenStringConstant++;
scope(exit) inTokenStringConstant--;
while (1)
@@ -1757,11 +1809,29 @@ class Lexer
case TOK.rightCurly:
if (--nest == 0)
{
- result.setString(pstart, p - 1 - pstart);
+ if (supportInterpolation)
+ result.appendInterpolatedPart(pstart, p - 1 - pstart);
+ else
+ result.setString(pstart, p - 1 - pstart);
+
stringPostfix(result);
return;
}
continue;
+ case TOK.dollar:
+ if (!supportInterpolation)
+ goto default;
+
+ stringbuffer.setsize(0);
+ stringbuffer.write(pstart, p - 1 - pstart);
+ if (!handleInterpolatedSegment(result, start))
+ goto default;
+
+ stringbuffer.setsize(0);
+
+ pstart = p;
+
+ continue;
case TOK.endOfFile:
error("unterminated token string constant starting at %s", start.toChars());
result.setString();
@@ -1772,6 +1842,52 @@ class Lexer
}
}
+ // returns true if it got special treatment as an interpolated segment
+ // otherwise returns false, indicating to treat it as just part of a normal string
+ private bool handleInterpolatedSegment(Token* token, Loc start)
+ {
+ switch(*p)
+ {
+ case '(':
+ // expression, at this level we need to scan until the closing ')'
+
+ // always put the string part in first
+ token.appendInterpolatedPart(stringbuffer);
+ stringbuffer.setsize(0);
+
+ int openParenCount = 1;
+ p++; // skip the first open paren
+ auto pstart = p;
+ while (openParenCount > 0)
+ {
+ // need to scan with the lexer to support embedded strings and other complex cases
+ Token tok;
+ scan(&tok);
+ if (tok.value == TOK.leftParenthesis)
+ openParenCount++;
+ if (tok.value == TOK.rightParenthesis)
+ openParenCount--;
+ if (tok.value == TOK.endOfFile)
+ {
+ // FIXME: make this error better, it spams a lot
+ error("unterminated interpolated string constant starting at %s", start.toChars());
+ return false;
+ }
+ }
+
+ // then put the interpolated string segment
+ token.appendInterpolatedPart(pstart[0 .. p - 1 - pstart]);
+
+ stringbuffer.setsize(0); // make sure this is reset from the last token scan
+ // otherwise something like i"$(func("thing")) stuff" can still include it
+
+ return true;
+ default:
+ // nothing special
+ return false;
+ }
+ }
+
/**
Scan a quoted string while building the processed string value by
handling escape sequences. The result is returned in the given `t` token.
@@ -1783,9 +1899,17 @@ class Lexer
* D https://dlang.org/spec/lex.html#double_quoted_strings
* ImportC C11 6.4.5
*/
- private void escapeStringConstant(Token* t)
+ private void escapeStringConstant(Token* t, bool supportInterpolation = false)
{
- t.value = TOK.string_;
+ if (supportInterpolation)
+ {
+ t.value = TOK.interpolated;
+ t.interpolatedSet = null;
+ }
+ else
+ {
+ t.value = TOK.string_;
+ }
const start = loc();
const tc = *p++; // opening quote
@@ -1813,11 +1937,28 @@ class Lexer
c = escapeSequence(c2);
stringbuffer.writeUTF8(c);
continue;
+ case '$':
+ if (supportInterpolation)
+ {
+ p++; // skip escaped $
+ stringbuffer.writeByte('$');
+ continue;
+ }
+ else
+ goto default;
default:
c = escapeSequence(c2);
break;
}
break;
+ case '$':
+ if (!supportInterpolation)
+ goto default;
+
+ if (!handleInterpolatedSegment(t, start))
+ goto default;
+
+ continue;
case '\n':
endOfLine();
if (Ccompile)
@@ -1835,7 +1976,10 @@ class Lexer
case '"':
if (c != tc)
goto default;
- t.setString(stringbuffer);
+ if (supportInterpolation)
+ t.appendInterpolatedPart(stringbuffer);
+ else
+ t.setString(stringbuffer);
if (!Ccompile)
stringPostfix(t);
return;
diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d
index 3d88a1d..276f209 100644
--- a/gcc/d/dmd/mtype.d
+++ b/gcc/d/dmd/mtype.d
@@ -27,9 +27,11 @@ import dmd.denum;
import dmd.dstruct;
import dmd.dsymbol;
import dmd.dtemplate;
+import dmd.enumsem;
import dmd.errors;
import dmd.expression;
import dmd.func;
+import dmd.funcsem;
import dmd.globals;
import dmd.hdrgen;
import dmd.id;
@@ -516,16 +518,39 @@ extern (C++) abstract class Type : ASTNode
Terror
];
+ static Type merge(Type t)
+ {
+ import dmd.basicmangle : tyToDecoBuffer;
+
+ OutBuffer buf;
+ buf.reserve(3);
+
+ if (t.ty == Tnoreturn)
+ buf.writestring("Nn");
+ else
+ tyToDecoBuffer(buf, t.ty);
+
+ auto sv = t.stringtable.update(buf[]);
+ if (sv.value)
+ return sv.value;
+ else
+ {
+ t.deco = cast(char*)sv.toDchars();
+ sv.value = t;
+ return t;
+ }
+ }
+
for (size_t i = 0; basetab[i] != Terror; i++)
{
Type t = new TypeBasic(basetab[i]);
- t = t.merge();
+ t = merge(t);
basic[basetab[i]] = t;
}
basic[Terror] = new TypeError();
tnoreturn = new TypeNoreturn();
- tnoreturn.deco = tnoreturn.merge().deco;
+ tnoreturn.deco = merge(tnoreturn).deco;
basic[Tnoreturn] = tnoreturn;
tvoid = basic[Tvoid];
@@ -560,7 +585,7 @@ extern (C++) abstract class Type : ASTNode
terror = basic[Terror];
tnoreturn = basic[Tnoreturn];
tnull = new TypeNull();
- tnull.deco = tnull.merge().deco;
+ tnull.deco = merge(tnull).deco;
tvoidptr = tvoid.pointerTo();
tstring = tchar.immutableOf().arrayOf();
@@ -601,29 +626,6 @@ extern (C++) abstract class Type : ASTNode
return cast(uint)size(Loc.initial);
}
- /*************************************
- * This version does a merge even if the deco is already computed.
- * Necessary for types that have a deco, but are not merged.
- */
- final Type merge2()
- {
- //printf("merge2(%s)\n", toChars());
- Type t = this;
- assert(t);
- if (!t.deco)
- return t.merge();
-
- auto sv = stringtable.lookup(t.deco, strlen(t.deco));
- if (sv && sv.value)
- {
- t = sv.value;
- assert(t.deco);
- }
- else
- assert(0);
- return t;
- }
-
/*********************************
* Store this type's modifier name into buf.
*/
@@ -1693,7 +1695,7 @@ extern (C++) abstract class Type : ASTNode
if (callable)
{
auto fd = resolveFuncCall(Loc.initial, null, callable, null, this, ArgumentList(), FuncResolveFlag.quiet);
- if (!fd || fd.errors || !fd.functionSemantic())
+ if (!fd || fd.errors || !functionSemantic(fd))
return Type.terror;
auto t = fd.type.nextOf();
diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h
index c777f35..8b0a1b2 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 *merge2();
void modToBuffer(OutBuffer& buf) const;
char *modToChars() const;
@@ -909,3 +908,4 @@ 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);
+Type *merge2(Type *type);
diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d
index 268622a..0dc54ff 100644
--- a/gcc/d/dmd/parse.d
+++ b/gcc/d/dmd/parse.d
@@ -2015,6 +2015,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
case TOK.wcharLiteral:
case TOK.dcharLiteral:
case TOK.string_:
+ case TOK.interpolated:
case TOK.hexadecimalString:
case TOK.file:
case TOK.fileFullPath:
@@ -5820,6 +5821,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
case TOK.true_:
case TOK.false_:
case TOK.string_:
+ case TOK.interpolated:
case TOK.hexadecimalString:
case TOK.leftParenthesis:
case TOK.cast_:
@@ -7313,6 +7315,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
case TOK.wcharLiteral:
case TOK.dcharLiteral:
case TOK.string_:
+ case TOK.interpolated:
case TOK.hexadecimalString:
case TOK.file:
case TOK.fileFullPath:
@@ -8177,6 +8180,11 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
nextToken();
break;
+ case TOK.interpolated:
+ e = new AST.InterpExp(loc, token.interpolatedSet, token.postfix);
+ nextToken();
+ break;
+
case TOK.string_:
case TOK.hexadecimalString:
const bool hexString = token.value == TOK.hexadecimalString;
@@ -8810,6 +8818,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
case TOK.wcharLiteral:
case TOK.dcharLiteral:
case TOK.string_:
+ case TOK.interpolated:
case TOK.function_:
case TOK.delegate_:
case TOK.typeof_:
diff --git a/gcc/d/dmd/parsetimevisitor.d b/gcc/d/dmd/parsetimevisitor.d
index 3d0a585..422c1c8 100644
--- a/gcc/d/dmd/parsetimevisitor.d
+++ b/gcc/d/dmd/parsetimevisitor.d
@@ -183,6 +183,7 @@ public:
void visit(AST.TypeidExp e) { visit(cast(AST.Expression)e); }
void visit(AST.TraitsExp e) { visit(cast(AST.Expression)e); }
void visit(AST.StringExp e) { visit(cast(AST.Expression)e); }
+ void visit(AST.InterpExp e) { visit(cast(AST.Expression)e); }
void visit(AST.NewExp e) { visit(cast(AST.Expression)e); }
void visit(AST.AssocArrayLiteralExp e) { visit(cast(AST.Expression)e); }
void visit(AST.ArrayLiteralExp e) { visit(cast(AST.Expression)e); }
diff --git a/gcc/d/dmd/res/default_ddoc_theme.ddoc b/gcc/d/dmd/res/default_ddoc_theme.ddoc
index 7ae0db8..20269e1 100644
--- a/gcc/d/dmd/res/default_ddoc_theme.ddoc
+++ b/gcc/d/dmd/res/default_ddoc_theme.ddoc
@@ -70,7 +70,7 @@ D_CODE =
<div class="code_sample">
<div class="dlang">
<ol class="code_lines">
- <li><code class="code">$0</code></li>
+ <li><pre><code class="code">$0</code></pre></li>
</ol>
</div>
</div>
@@ -81,7 +81,7 @@ OTHER_CODE =
<div class="code_sample">
<div class="dlang">
<ol class="code_lines">
- <li><code class="code language-$1">$+</code></li>
+ <li><pre><code class="code language-$1">$+</code></pre></li>
</ol>
</div>
</div>
@@ -517,6 +517,10 @@ DDOC =
white-space: pre-wrap;
}
+ .ddoc .code_lines pre {
+ display: contents;
+ }
+
.ddoc .code_lines li:only-of-type::before {
color: rgba(255, 255, 255, 1);
content: " ";
diff --git a/gcc/d/dmd/root/filename.d b/gcc/d/dmd/root/filename.d
index 5b0bba4..41c2050 100644
--- a/gcc/d/dmd/root/filename.d
+++ b/gcc/d/dmd/root/filename.d
@@ -78,7 +78,7 @@ nothrow:
private const(char)[] str;
///
- extern (D) this(const(char)[] str) pure
+ extern (D) this(const char[] str) pure
{
this.str = str.xarraydup;
}
@@ -96,7 +96,7 @@ nothrow:
}
/// Ditto
- extern (D) static bool equals(const(char)[] name1, const(char)[] name2) pure @nogc
+ extern (D) static bool equals(const char[] name1, const char[] name2) pure @nogc
{
if (name1.length != name2.length)
return false;
@@ -125,7 +125,7 @@ nothrow:
}
/// Ditto
- extern (D) static bool absolute(const(char)[] name) pure @nogc @safe
+ extern (D) static bool absolute(const char[] name) pure @nogc @safe
{
if (!name.length)
return false;
@@ -189,7 +189,7 @@ nothrow:
}
/// Ditto
- extern (D) static const(char)[] ext(const(char)[] str) nothrow pure @safe @nogc
+ extern (D) static const(char)[] ext(const char[] str) nothrow pure @safe @nogc
{
foreach_reverse (idx, char e; str)
{
@@ -249,7 +249,7 @@ nothrow:
}
/// Ditto
- extern (D) static const(char)[] removeExt(const(char)[] str)
+ extern (D) static const(char)[] removeExt(const char[] str)
{
auto e = ext(str);
if (e.length)
@@ -278,7 +278,7 @@ nothrow:
}
/// Ditto
- extern (D) static const(char)[] name(const(char)[] str) pure @nogc @safe
+ extern (D) static const(char)[] name(const char[] str) pure @nogc @safe
{
foreach_reverse (idx, char e; str)
{
@@ -333,7 +333,7 @@ nothrow:
}
/// Ditto
- extern (D) static const(char)[] path(const(char)[] str)
+ extern (D) static const(char)[] path(const char[] str)
{
const n = name(str);
bool hasTrailingSlash;
@@ -358,7 +358,7 @@ nothrow:
/**************************************
* Replace filename portion of path.
*/
- extern (D) static const(char)[] replaceName(const(char)[] path, const(char)[] name)
+ extern (D) static const(char)[] replaceName(const char[] path, const char[] name)
{
if (absolute(name))
return name;
@@ -387,7 +387,7 @@ nothrow:
}
/// Ditto
- extern(D) static const(char)[] combine(const(char)[] path, const(char)[] name)
+ extern(D) static const(char)[] combine(const char[] path, const char[] name)
{
return !path.length ? name : buildPath(path, name);
}
@@ -401,7 +401,7 @@ nothrow:
assert(combine("foo/"[], "bar"[]) == "foo/bar");
}
- static const(char)[] buildPath(const(char)[][] fragments...)
+ static const(char)[] buildPath(const char[][] fragments...)
{
size_t size;
foreach (f; fragments)
@@ -563,7 +563,7 @@ nothrow:
* Returns:
* A newly allocated string (free with `FileName.free`)
*/
- extern(D) static char[] addExt(const(char)[] name, const(char)[] ext) pure
+ extern(D) static char[] addExt(const char[] name, const char[] ext) pure
{
const len = name.length + ext.length + 2;
auto s = cast(char*)mem.xmalloc(len);
@@ -584,7 +584,7 @@ nothrow:
}
/// Ditto
- extern (D) static const(char)[] defaultExt(const(char)[] name, const(char)[] ext)
+ extern (D) static const(char)[] defaultExt(const char[] name, const char[] ext)
{
auto e = FileName.ext(name);
if (e.length) // it already has an extension
@@ -608,7 +608,7 @@ nothrow:
}
/// Ditto
- extern (D) static const(char)[] forceExt(const(char)[] name, const(char)[] ext)
+ extern (D) static const(char)[] forceExt(const char[] name, const char[] ext)
{
if (auto e = FileName.ext(name))
return addExt(name[0 .. $ - e.length - 1], ext);
@@ -630,7 +630,7 @@ nothrow:
}
/// Ditto
- extern (D) static bool equalsExt(const(char)[] name, const(char)[] ext) pure @nogc
+ extern (D) static bool equalsExt(const char[] name, const char[] ext) pure @nogc
{
auto e = FileName.ext(name);
if (!e.length && !ext.length)
@@ -665,12 +665,12 @@ nothrow:
* Returns:
* if found, filename combined with path, otherwise null
*/
- extern (C++) static const(char)* searchPath(Strings* path, const(char)* name, bool cwd)
+ extern (C++) static const(char)* searchPath(const ref Strings path, const char* name, bool cwd)
{
- return searchPath(path, name.toDString, cwd).ptr;
+ return searchPath(path[], name.toDString, cwd).ptr;
}
- extern (D) static const(char)[] searchPath(Strings* path, const(char)[] name, bool cwd)
+ extern (D) static const(char)[] searchPath(const char*[] path, const char[] name, bool cwd)
{
if (absolute(name))
{
@@ -681,24 +681,21 @@ nothrow:
if (exists(name))
return name;
}
- if (path)
+ foreach (p; path)
{
- foreach (p; *path)
+ auto n = combine(p.toDString, name);
+ if (exists(n))
+ return n;
+ //combine might return name
+ if (n.ptr != name.ptr)
{
- auto n = combine(p.toDString, name);
- if (exists(n))
- return n;
- //combine might return name
- if (n.ptr != name.ptr)
- {
- mem.xfree(cast(void*)n.ptr);
- }
+ mem.xfree(cast(void*)n.ptr);
}
}
return null;
}
- extern (D) static const(char)[] searchPath(const(char)* path, const(char)[] name, bool cwd)
+ extern (D) static const(char)[] searchPath(const char* path, const char[] name, bool cwd)
{
if (absolute(name))
{
@@ -738,7 +735,7 @@ nothrow:
* Returns:
* index of the first reserved character in path if found, size_t.max otherwise
*/
- extern (D) static size_t findReservedChar(const(char)[] name) pure @nogc @safe
+ extern (D) static size_t findReservedChar(const char[] name) pure @nogc @safe
{
version (Windows)
{
@@ -787,7 +784,7 @@ nothrow:
* Returns:
* true if path contains '..' reference to parent directory
*/
- extern (D) static bool refersToParentDir(const(char)[] name) pure @nogc @safe
+ extern (D) static bool refersToParentDir(const char[] name) pure @nogc @safe
{
size_t s = 0;
foreach (i; 0 .. name.length)
@@ -845,7 +842,7 @@ nothrow:
}
/// Ditto
- extern (D) static int exists(const(char)[] name)
+ extern (D) static int exists(const char[] name)
{
if (!name.length)
return 0;
@@ -892,7 +889,7 @@ nothrow:
Returns:
`true` if the directory exists or was successfully created
*/
- extern (D) static bool ensurePathExists(const(char)[] path)
+ extern (D) static bool ensurePathExists(const char[] path)
{
//printf("FileName::ensurePathExists(%s)\n", path ? path : "");
if (!path.length)
@@ -967,7 +964,7 @@ nothrow:
}
/// Ditto
- extern (D) static const(char)[] canonicalName(const(char)[] name)
+ extern (D) static const(char)[] canonicalName(const char[] name)
{
version (Posix)
{
@@ -1127,7 +1124,7 @@ version(Windows)
* References:
* https://msdn.microsoft.com/en-us/library/windows/desktop/aa363855(v=vs.85).aspx
*/
- private int _mkdir(const(char)[] path) nothrow
+ private int _mkdir(const char[] path) nothrow
{
const createRet = path.extendedPathThen!(
p => CreateDirectoryW(&p[0], null /*securityAttributes*/));
@@ -1175,7 +1172,7 @@ version(Windows)
* Returns:
* The result of calling F on the UTF16 version of str.
*/
- private auto toWStringzThen(alias F)(const(char)[] str) nothrow
+ private auto toWStringzThen(alias F)(const char[] str) nothrow
{
import dmd.common.smallbuffer : SmallBuffer, toWStringz;
diff --git a/gcc/d/dmd/root/filename.h b/gcc/d/dmd/root/filename.h
index d8834a1..0e52b98 100644
--- a/gcc/d/dmd/root/filename.h
+++ b/gcc/d/dmd/root/filename.h
@@ -38,7 +38,7 @@ public:
bool equalsExt(const char *ext);
- static const char *searchPath(Strings *path, const char *name, bool cwd);
+ static const char *searchPath(Strings& path, const char *name, bool cwd);
static int exists(const char *name);
static bool ensurePathExists(const char *path);
static const char *canonicalName(const char *name);
diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d
index 174d9b4..125a39d 100644
--- a/gcc/d/dmd/semantic3.d
+++ b/gcc/d/dmd/semantic3.d
@@ -41,6 +41,7 @@ import dmd.escape;
import dmd.expression;
import dmd.expressionsem;
import dmd.func;
+import dmd.funcsem;
import dmd.globals;
import dmd.id;
import dmd.identifier;
@@ -384,7 +385,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
}
}
- funcdecl.declareThis(sc2);
+ declareThis(funcdecl, sc2);
// Reverts: https://issues.dlang.org/show_bug.cgi?id=5710
// No compiler supports this, and there was never any spec for it.
diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d
index d4827ae..840035c 100644
--- a/gcc/d/dmd/statementsem.d
+++ b/gcc/d/dmd/statementsem.d
@@ -43,6 +43,7 @@ import dmd.escape;
import dmd.expression;
import dmd.expressionsem;
import dmd.func;
+import dmd.funcsem;
import dmd.globals;
import dmd.gluelayer;
import dmd.hdrgen;
@@ -1284,7 +1285,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
Type tfront;
if (auto fd = sfront.isFuncDeclaration())
{
- if (!fd.functionSemantic())
+ if (!functionSemantic(fd))
return rangeError();
tfront = fd.type;
}
diff --git a/gcc/d/dmd/templatesem.d b/gcc/d/dmd/templatesem.d
new file mode 100644
index 0000000..1942afe
--- /dev/null
+++ b/gcc/d/dmd/templatesem.d
@@ -0,0 +1,1497 @@
+/**
+ * Template semantics.
+ *
+ * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/templatesem.d, _templatesem.d)
+ * Documentation: https://dlang.org/phobos/dmd_templatesem.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/templatesem.d
+ */
+
+module dmd.templatesem;
+
+import core.stdc.stdio;
+import core.stdc.string;
+import dmd.aggregate;
+import dmd.aliasthis;
+import dmd.arraytypes;
+import dmd.astenums;
+import dmd.ast_node;
+import dmd.attrib;
+import dmd.dcast;
+import dmd.dclass;
+import dmd.declaration;
+import dmd.dinterpret;
+import dmd.dmangle;
+import dmd.dmodule;
+import dmd.dscope;
+import dmd.dsymbol;
+import dmd.dsymbolsem;
+import dmd.dtemplate;
+import dmd.errors;
+import dmd.errorsink;
+import dmd.expression;
+import dmd.expressionsem;
+import dmd.func;
+import dmd.funcsem;
+import dmd.globals;
+import dmd.hdrgen;
+import dmd.id;
+import dmd.identifier;
+import dmd.impcnvtab;
+import dmd.init;
+import dmd.initsem;
+import dmd.location;
+import dmd.mtype;
+import dmd.opover;
+import dmd.optimize;
+import dmd.root.array;
+import dmd.common.outbuffer;
+import dmd.rootobject;
+import dmd.semantic2;
+import dmd.semantic3;
+import dmd.tokens;
+import dmd.typesem;
+import dmd.visitor;
+
+/***************************************
+ * Given that ti is an instance of this TemplateDeclaration,
+ * deduce the types of the parameters to this, and store
+ * those deduced types in dedtypes[].
+ * Params:
+ * sc = context
+ * td = template
+ * ti = instance of td
+ * dedtypes = fill in with deduced types
+ * argumentList = arguments to template instance
+ * flag = 1 - don't do semantic() because of dummy types
+ * 2 - don't change types in matchArg()
+ * Returns: match level.
+ */
+public
+MATCH matchWithInstance(Scope* sc, TemplateDeclaration td, TemplateInstance ti, ref Objects dedtypes, ArgumentList argumentList, int flag)
+{
+ enum LOGM = 0;
+ static if (LOGM)
+ {
+ printf("\n+TemplateDeclaration.matchWithInstance(td = %s, ti = %s, flag = %d)\n", td.toChars(), ti.toChars(), flag);
+ }
+ version (none)
+ {
+ printf("dedtypes.length = %d, parameters.length = %d\n", dedtypes.length, parameters.length);
+ if (ti.tiargs.length)
+ printf("ti.tiargs.length = %d, [0] = %p\n", ti.tiargs.length, (*ti.tiargs)[0]);
+ }
+ MATCH nomatch()
+ {
+ static if (LOGM)
+ {
+ printf(" no match\n");
+ }
+ return MATCH.nomatch;
+ }
+ MATCH m;
+ size_t dedtypes_dim = dedtypes.length;
+
+ dedtypes.zero();
+
+ if (td.errors)
+ return MATCH.nomatch;
+
+ size_t parameters_dim = td.parameters.length;
+ int variadic = td.isVariadic() !is null;
+
+ // If more arguments than parameters, no match
+ if (ti.tiargs.length > parameters_dim && !variadic)
+ {
+ static if (LOGM)
+ {
+ printf(" no match: more arguments than parameters\n");
+ }
+ return MATCH.nomatch;
+ }
+
+ assert(dedtypes_dim == parameters_dim);
+ assert(dedtypes_dim >= ti.tiargs.length || variadic);
+
+ assert(td._scope);
+
+ // Set up scope for template parameters
+ Scope* paramscope = createScopeForTemplateParameters(td, ti, sc);
+
+ // Attempt type deduction
+ m = MATCH.exact;
+ for (size_t i = 0; i < dedtypes_dim; i++)
+ {
+ MATCH m2;
+ TemplateParameter tp = (*td.parameters)[i];
+ Declaration sparam;
+
+ //printf("\targument [%d]\n", i);
+ static if (LOGM)
+ {
+ //printf("\targument [%d] is %s\n", i, oarg ? oarg.toChars() : "null");
+ TemplateTypeParameter ttp = tp.isTemplateTypeParameter();
+ if (ttp)
+ printf("\tparameter[%d] is %s : %s\n", i, tp.ident.toChars(), ttp.specType ? ttp.specType.toChars() : "");
+ }
+
+ m2 = tp.matchArg(ti.loc, paramscope, ti.tiargs, i, td.parameters, dedtypes, &sparam);
+ //printf("\tm2 = %d\n", m2);
+ if (m2 == MATCH.nomatch)
+ {
+ version (none)
+ {
+ printf("\tmatchArg() for parameter %i failed\n", i);
+ }
+ return nomatch();
+ }
+
+ if (m2 < m)
+ m = m2;
+
+ if (!flag)
+ sparam.dsymbolSemantic(paramscope);
+ if (!paramscope.insert(sparam)) // TODO: This check can make more early
+ {
+ // in TemplateDeclaration.semantic, and
+ // then we don't need to make sparam if flags == 0
+ return nomatch();
+ }
+ }
+
+ if (!flag)
+ {
+ /* Any parameter left without a type gets the type of
+ * its corresponding arg
+ */
+ foreach (i, ref dedtype; dedtypes)
+ {
+ if (!dedtype)
+ {
+ assert(i < ti.tiargs.length);
+ dedtype = cast(Type)(*ti.tiargs)[i];
+ }
+ }
+ }
+
+ if (m > MATCH.nomatch && td.constraint && !flag)
+ {
+ if (ti.hasNestedArgs(ti.tiargs, td.isstatic)) // TODO: should gag error
+ ti.parent = ti.enclosing;
+ else
+ ti.parent = td.parent;
+
+ // Similar to doHeaderInstantiation
+ FuncDeclaration fd = td.onemember ? td.onemember.isFuncDeclaration() : null;
+ if (fd)
+ {
+ TypeFunction tf = fd.type.isTypeFunction().syntaxCopy();
+ if (argumentList.hasNames)
+ return nomatch();
+ Expressions* fargs = argumentList.arguments;
+ // TODO: Expressions* fargs = tf.resolveNamedArgs(argumentList, null);
+ // if (!fargs)
+ // return nomatch();
+
+ fd = new FuncDeclaration(fd.loc, fd.endloc, fd.ident, fd.storage_class, tf);
+ fd.parent = ti;
+ fd.inferRetType = true;
+
+ // Shouldn't run semantic on default arguments and return type.
+ foreach (ref param; *tf.parameterList.parameters)
+ param.defaultArg = null;
+
+ tf.next = null;
+ tf.incomplete = true;
+
+ // Resolve parameter types and 'auto ref's.
+ tf.fargs = fargs;
+ uint olderrors = global.startGagging();
+ fd.type = tf.typeSemantic(td.loc, paramscope);
+ global.endGagging(olderrors);
+ if (fd.type.ty != Tfunction)
+ return nomatch();
+ fd.originalType = fd.type; // for mangling
+ }
+
+ // TODO: dedtypes => ti.tiargs ?
+ if (!evaluateConstraint(td, ti, sc, paramscope, &dedtypes, fd))
+ return nomatch();
+ }
+
+ static if (LOGM)
+ {
+ // Print out the results
+ printf("--------------------------\n");
+ printf("template %s\n", toChars());
+ printf("instance %s\n", ti.toChars());
+ if (m > MATCH.nomatch)
+ {
+ for (size_t i = 0; i < dedtypes_dim; i++)
+ {
+ TemplateParameter tp = (*parameters)[i];
+ RootObject oarg;
+ printf(" [%d]", i);
+ if (i < ti.tiargs.length)
+ oarg = (*ti.tiargs)[i];
+ else
+ oarg = null;
+ tp.print(oarg, (*dedtypes)[i]);
+ }
+ }
+ else
+ return nomatch();
+ }
+ static if (LOGM)
+ {
+ printf(" match = %d\n", m);
+ }
+
+ paramscope.pop();
+ static if (LOGM)
+ {
+ printf("-TemplateDeclaration.matchWithInstance(td = %s, ti = %s) = %d\n", td.toChars(), ti.toChars(), m);
+ }
+ return m;
+}
+
+/****************************
+ * Check to see if constraint is satisfied.
+ */
+bool evaluateConstraint(TemplateDeclaration td, 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
+ * void foo(T)(T x) if (is(typeof(foo(x)))) { }
+ * static assert(!is(typeof(foo(7))));
+ * Recursive attempts are regarded as a constraint failure.
+ */
+ /* There's a chicken-and-egg problem here. We don't know yet if this template
+ * instantiation will be a local one (enclosing is set), and we won't know until
+ * after selecting the correct template. Thus, function we're nesting inside
+ * is not on the sc scope chain, and this can cause errors in FuncDeclaration.getLevel().
+ * Workaround the problem by setting a flag to relax the checking on frame errors.
+ */
+
+ for (TemplatePrevious* p = td.previous; p; p = p.prev)
+ {
+ 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
+ * instantiations.
+ * the chain of enclosing scopes is broken by paramscope (its enclosing
+ * scope is _scope, but paramscope.callsc is the instantiating scope). So
+ * it's good enough to check the chain of callsc
+ */
+ for (Scope* scx = paramscope.callsc; scx; scx = scx.callsc)
+ {
+ // The first scx might be identical for nested eponymeous templates, e.g.
+ // template foo() { void foo()() {...} }
+ if (scx == p.sc && scx !is paramscope.callsc)
+ return false;
+ }
+ /* BUG: should also check for ref param differences
+ */
+ }
+
+ TemplatePrevious pr;
+ pr.prev = td.previous;
+ pr.sc = paramscope.callsc;
+ pr.dedargs = dedargs;
+ td.previous = &pr; // add this to threaded list
+
+ Scope* scx = paramscope.push(ti);
+ scx.parent = ti;
+ scx.tinst = null;
+ scx.minst = null;
+ // Set SCOPE.constraint before declaring function parameters for the static condition
+ // (previously, this was immediately before calling evalStaticCondition), so the
+ // semantic pass knows not to issue deprecation warnings for these throw-away decls.
+ // https://issues.dlang.org/show_bug.cgi?id=21831
+ scx.flags |= SCOPE.constraint;
+
+ assert(!ti.symtab);
+ if (fd)
+ {
+ /* Declare all the function parameters as variables and add them to the scope
+ * Making parameters is similar to FuncDeclaration.semantic3
+ */
+ auto tf = fd.type.isTypeFunction();
+
+ scx.parent = fd;
+
+ Parameters* fparameters = tf.parameterList.parameters;
+ const nfparams = tf.parameterList.length;
+ foreach (i, fparam; tf.parameterList)
+ {
+ fparam.storageClass &= (STC.IOR | STC.lazy_ | STC.final_ | STC.TYPECTOR | STC.nodtor);
+ fparam.storageClass |= STC.parameter;
+ if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nfparams)
+ {
+ fparam.storageClass |= STC.variadic;
+ /* Don't need to set STC.scope_ because this will only
+ * be evaluated at compile time
+ */
+ }
+ }
+ foreach (fparam; *fparameters)
+ {
+ if (!fparam.ident)
+ continue;
+ // don't add it, if it has no name
+ auto v = new VarDeclaration(fparam.loc, fparam.type, fparam.ident, null);
+ fparam.storageClass |= STC.parameter;
+ v.storage_class = fparam.storageClass;
+ v.dsymbolSemantic(scx);
+ if (!ti.symtab)
+ ti.symtab = new DsymbolTable();
+ if (!scx.insert(v))
+ .error(td.loc, "%s `%s` parameter `%s.%s` is already defined", td.kind, td.toPrettyChars, td.toChars(), v.toChars());
+ else
+ v.parent = fd;
+ }
+ if (td.isstatic)
+ fd.storage_class |= STC.static_;
+ declareThis(fd, scx);
+ }
+
+ td.lastConstraint = td.constraint.syntaxCopy();
+ td.lastConstraintTiargs = ti.tiargs;
+ td.lastConstraintNegs.setDim(0);
+
+ import dmd.staticcond;
+
+ assert(ti.inst is null);
+ ti.inst = ti; // temporary instantiation to enable genIdent()
+ bool errors;
+ const bool result = evalStaticCondition(scx, td.constraint, td.lastConstraint, errors, &td.lastConstraintNegs);
+ if (result || errors)
+ {
+ td.lastConstraint = null;
+ td.lastConstraintTiargs = null;
+ td.lastConstraintNegs.setDim(0);
+ }
+ ti.inst = null;
+ ti.symtab = null;
+ scx = scx.pop();
+ td.previous = pr.prev; // unlink from threaded list
+ if (errors)
+ return false;
+ return result;
+}
+
+/*******************************************
+ * Append to buf a textual representation of template parameters with their arguments.
+ * Params:
+ * parameters = the template parameters
+ * tiargs = the correspondeing template arguments
+ * variadic = if it's a variadic argument list
+ * buf = where the text output goes
+ */
+void formatParamsWithTiargs(ref TemplateParameters parameters, ref Objects tiargs, bool variadic, ref OutBuffer buf)
+{
+ buf.writestring(" with `");
+
+ // write usual arguments line-by-line
+ // skips trailing default ones - they are not present in `tiargs`
+ const end = parameters.length - (variadic ? 1 : 0);
+ size_t i;
+ for (; i < tiargs.length && i < end; i++)
+ {
+ if (i)
+ {
+ buf.writeByte(',');
+ buf.writenl();
+ buf.writestring(" ");
+ }
+ write(buf, parameters[i]);
+ buf.writestring(" = ");
+ write(buf, tiargs[i]);
+ }
+ // write remaining variadic arguments on the last line
+ if (variadic)
+ {
+ if (i)
+ {
+ buf.writeByte(',');
+ buf.writenl();
+ buf.writestring(" ");
+ }
+ write(buf, parameters[end]);
+ buf.writestring(" = ");
+ buf.writeByte('(');
+ if (end < tiargs.length)
+ {
+ write(buf, tiargs[end]);
+ foreach (j; parameters.length .. tiargs.length)
+ {
+ buf.writestring(", ");
+ write(buf, tiargs[j]);
+ }
+ }
+ buf.writeByte(')');
+ }
+ buf.writeByte('`');
+}
+
+/******************************
+ * Create a scope for the parameters of the TemplateInstance
+ * `ti` in the parent scope sc from the ScopeDsymbol paramsym.
+ *
+ * If paramsym is null a new ScopeDsymbol is used in place of
+ * paramsym.
+ * Params:
+ * td = template that ti is an instance of
+ * ti = the TemplateInstance whose parameters to generate the scope for.
+ * sc = the parent scope of ti
+ * Returns:
+ * new scope for the parameters of ti
+ */
+Scope* createScopeForTemplateParameters(TemplateDeclaration td, TemplateInstance ti, Scope* sc)
+{
+ ScopeDsymbol paramsym = new ScopeDsymbol();
+ paramsym.parent = td._scope.parent;
+ Scope* paramscope = td._scope.push(paramsym);
+ paramscope.tinst = ti;
+ paramscope.minst = sc.minst;
+ paramscope.callsc = sc;
+ paramscope.stc = 0;
+ return paramscope;
+}
+
+/********************************************
+ * Determine partial specialization order of `td` vs `td2`.
+ * Params:
+ * sc = context
+ * td = first template
+ * td2 = second template
+ * argumentList = arguments to template
+ * Returns:
+ * MATCH - td is at least as specialized as td2
+ * MATCH.nomatch - td2 is more specialized than td
+ */
+MATCH leastAsSpecialized(Scope* sc, TemplateDeclaration td, TemplateDeclaration td2, ArgumentList argumentList)
+{
+ enum LOG_LEASTAS = 0;
+ static if (LOG_LEASTAS)
+ {
+ printf("%s.leastAsSpecialized(%s)\n", toChars(), td2.toChars());
+ }
+
+ /* This works by taking the template parameters to this template
+ * declaration and feeding them to td2 as if it were a template
+ * instance.
+ * If it works, then this template is at least as specialized
+ * as td2.
+ */
+
+ // Set type arguments to dummy template instance to be types
+ // generated from the parameters to this template declaration
+ auto tiargs = new Objects();
+ tiargs.reserve(td.parameters.length);
+ foreach (tp; *td.parameters)
+ {
+ if (tp.dependent)
+ break;
+ RootObject p = tp.dummyArg();
+ if (!p) //TemplateTupleParameter
+ break;
+
+ tiargs.push(p);
+ }
+ scope TemplateInstance ti = new TemplateInstance(Loc.initial, td.ident, tiargs); // create dummy template instance
+
+ // Temporary Array to hold deduced types
+ Objects dedtypes = Objects(td2.parameters.length);
+
+ // Attempt a type deduction
+ MATCH m = matchWithInstance(sc, td2, ti, dedtypes, argumentList, 1);
+ if (m > MATCH.nomatch)
+ {
+ /* A non-variadic template is more specialized than a
+ * variadic one.
+ */
+ TemplateTupleParameter tp = td.isVariadic();
+ if (tp && !tp.dependent && !td2.isVariadic())
+ goto L1;
+
+ static if (LOG_LEASTAS)
+ {
+ printf(" matches %d, so is least as specialized\n", m);
+ }
+ return m;
+ }
+L1:
+ static if (LOG_LEASTAS)
+ {
+ printf(" doesn't match, so is not as specialized\n");
+ }
+ return MATCH.nomatch;
+}
+
+/*************************************************
+ * Match function arguments against a specific template function.
+ *
+ * Params:
+ * td = template declaration for template instance
+ * ti = template instance. `ti.tdtypes` will be set to Expression/Type deduced template arguments
+ * sc = instantiation scope
+ * fd = Partially instantiated function declaration, which is set to an instantiated function declaration
+ * tthis = 'this' argument if !NULL
+ * argumentList = arguments to function
+ *
+ * Returns:
+ * match pair of initial and inferred template arguments
+ */
+extern (D) MATCHpair deduceFunctionTemplateMatch(TemplateDeclaration td, TemplateInstance ti, Scope* sc, ref FuncDeclaration fd, Type tthis, ArgumentList argumentList)
+{
+ version (none)
+ {
+ printf("\nTemplateDeclaration.deduceFunctionTemplateMatch() %s\n", td.toChars());
+ for (size_t i = 0; i < (fargs ? fargs.length : 0); i++)
+ {
+ Expression e = (*fargs)[i];
+ printf("\tfarg[%d] is %s, type is %s\n", cast(int) i, e.toChars(), e.type.toChars());
+ }
+ printf("fd = %s\n", fd.toChars());
+ printf("fd.type = %s\n", fd.type.toChars());
+ if (tthis)
+ printf("tthis = %s\n", tthis.toChars());
+ }
+
+ assert(td._scope);
+
+ auto dedargs = new Objects(td.parameters.length);
+ dedargs.zero();
+
+ Objects* dedtypes = &ti.tdtypes; // for T:T*, the dedargs is the T*, dedtypes is the T
+ dedtypes.setDim(td.parameters.length);
+ dedtypes.zero();
+
+ if (td.errors || fd.errors)
+ return MATCHpair(MATCH.nomatch, MATCH.nomatch);
+
+ // Set up scope for parameters
+ Scope* paramscope = createScopeForTemplateParameters(td, ti,sc);
+
+ MATCHpair nomatch()
+ {
+ paramscope.pop();
+ //printf("\tnomatch\n");
+ return MATCHpair(MATCH.nomatch, MATCH.nomatch);
+ }
+
+ MATCHpair matcherror()
+ {
+ // todo: for the future improvement
+ paramscope.pop();
+ //printf("\terror\n");
+ return MATCHpair(MATCH.nomatch, MATCH.nomatch);
+ }
+ // Mark the parameter scope as deprecated if the templated
+ // function is deprecated (since paramscope.enclosing is the
+ // calling scope already)
+ paramscope.stc |= fd.storage_class & STC.deprecated_;
+
+ TemplateTupleParameter tp = td.isVariadic();
+ Tuple declaredTuple = null;
+
+ version (none)
+ {
+ for (size_t i = 0; i < dedargs.length; i++)
+ {
+ printf("\tdedarg[%d] = ", i);
+ RootObject oarg = (*dedargs)[i];
+ if (oarg)
+ printf("%s", oarg.toChars());
+ printf("\n");
+ }
+ }
+
+ size_t ntargs = 0; // array size of tiargs
+ size_t inferStart = 0; // index of first parameter to infer
+ const Loc instLoc = ti.loc;
+ MATCH matchTiargs = MATCH.exact;
+
+ if (auto tiargs = ti.tiargs)
+ {
+ // Set initial template arguments
+ ntargs = tiargs.length;
+ size_t n = td.parameters.length;
+ if (tp)
+ n--;
+ if (ntargs > n)
+ {
+ if (!tp)
+ return nomatch();
+
+ /* The extra initial template arguments
+ * now form the tuple argument.
+ */
+ auto t = new Tuple(ntargs - n);
+ assert(td.parameters.length);
+ (*dedargs)[td.parameters.length - 1] = t;
+
+ for (size_t i = 0; i < t.objects.length; i++)
+ {
+ t.objects[i] = (*tiargs)[n + i];
+ }
+ td.declareParameter(paramscope, tp, t);
+ declaredTuple = t;
+ }
+ else
+ n = ntargs;
+
+ memcpy(dedargs.tdata(), tiargs.tdata(), n * (*dedargs.tdata()).sizeof);
+
+ for (size_t i = 0; i < n; i++)
+ {
+ assert(i < td.parameters.length);
+ Declaration sparam = null;
+ MATCH m = (*td.parameters)[i].matchArg(instLoc, paramscope, dedargs, i, td.parameters, *dedtypes, &sparam);
+ //printf("\tdeduceType m = %d\n", m);
+ if (m == MATCH.nomatch)
+ return nomatch();
+ if (m < matchTiargs)
+ matchTiargs = m;
+
+ sparam.dsymbolSemantic(paramscope);
+ if (!paramscope.insert(sparam))
+ return nomatch();
+ }
+ if (n < td.parameters.length && !declaredTuple)
+ {
+ inferStart = n;
+ }
+ else
+ inferStart = td.parameters.length;
+ //printf("tiargs matchTiargs = %d\n", matchTiargs);
+ }
+ version (none)
+ {
+ for (size_t i = 0; i < dedargs.length; i++)
+ {
+ printf("\tdedarg[%d] = ", i);
+ RootObject oarg = (*dedargs)[i];
+ if (oarg)
+ printf("%s", oarg.toChars());
+ printf("\n");
+ }
+ }
+
+ ParameterList fparameters = fd.getParameterList(); // function parameter list
+ const nfparams = fparameters.length; // number of function parameters
+ if (argumentList.hasNames)
+ return matcherror(); // TODO: resolve named args
+ Expression[] fargs = argumentList.arguments ? (*argumentList.arguments)[] : null;
+
+ /* Check for match of function arguments with variadic template
+ * parameter, such as:
+ *
+ * void foo(T, A...)(T t, A a);
+ * void main() { foo(1,2,3); }
+ */
+ size_t fptupindex = IDX_NOTFOUND;
+ if (tp) // if variadic
+ {
+ // TemplateTupleParameter always makes most lesser matching.
+ matchTiargs = MATCH.convert;
+
+ if (nfparams == 0 && argumentList.length != 0) // if no function parameters
+ {
+ if (!declaredTuple)
+ {
+ auto t = new Tuple();
+ //printf("t = %p\n", t);
+ (*dedargs)[td.parameters.length - 1] = t;
+ td.declareParameter(paramscope, tp, t);
+ declaredTuple = t;
+ }
+ }
+ else
+ {
+ /* Figure out which of the function parameters matches
+ * the tuple template parameter. Do this by matching
+ * type identifiers.
+ * Set the index of this function parameter to fptupindex.
+ */
+ for (fptupindex = 0; fptupindex < nfparams; fptupindex++)
+ {
+ auto fparam = (*fparameters.parameters)[fptupindex]; // fparameters[fptupindex] ?
+ if (fparam.type.ty != Tident)
+ continue;
+ TypeIdentifier tid = fparam.type.isTypeIdentifier();
+ if (!tp.ident.equals(tid.ident) || tid.idents.length)
+ continue;
+
+ if (fparameters.varargs != VarArg.none) // variadic function doesn't
+ return nomatch(); // go with variadic template
+
+ goto L1;
+ }
+ fptupindex = IDX_NOTFOUND;
+ L1:
+ }
+ }
+
+ MATCH match = MATCH.exact;
+ if (td.toParent().isModule())
+ tthis = null;
+ if (tthis)
+ {
+ bool hasttp = false;
+
+ // Match 'tthis' to any TemplateThisParameter's
+ foreach (param; *td.parameters)
+ {
+ if (auto ttp = param.isTemplateThisParameter())
+ {
+ hasttp = true;
+
+ Type t = new TypeIdentifier(Loc.initial, ttp.ident);
+ MATCH m = deduceType(tthis, paramscope, t, *td.parameters, *dedtypes);
+ if (m == MATCH.nomatch)
+ return nomatch();
+ if (m < match)
+ match = m; // pick worst match
+ }
+ }
+
+ // Match attributes of tthis against attributes of fd
+ if (fd.type && !fd.isCtorDeclaration() && !(td._scope.stc & STC.static_))
+ {
+ StorageClass stc = td._scope.stc | fd.storage_class2;
+ // Propagate parent storage class, https://issues.dlang.org/show_bug.cgi?id=5504
+ Dsymbol p = td.parent;
+ while (p.isTemplateDeclaration() || p.isTemplateInstance())
+ p = p.parent;
+ AggregateDeclaration ad = p.isAggregateDeclaration();
+ if (ad)
+ stc |= ad.storage_class;
+
+ ubyte mod = fd.type.mod;
+ if (stc & STC.immutable_)
+ mod = MODFlags.immutable_;
+ else
+ {
+ if (stc & (STC.shared_ | STC.synchronized_))
+ mod |= MODFlags.shared_;
+ if (stc & STC.const_)
+ mod |= MODFlags.const_;
+ if (stc & STC.wild)
+ mod |= MODFlags.wild;
+ }
+
+ ubyte thismod = tthis.mod;
+ if (hasttp)
+ mod = MODmerge(thismod, mod);
+ MATCH m = MODmethodConv(thismod, mod);
+ if (m == MATCH.nomatch)
+ return nomatch();
+ if (m < match)
+ match = m;
+ }
+ }
+
+ // Loop through the function parameters
+ {
+ //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 = fargs.length; // nfargs + supplied defaultArgs
+ uint inoutMatch = 0; // for debugging only
+ for (size_t parami = 0; parami < nfparams; parami++)
+ {
+ Parameter fparam = fparameters[parami];
+
+ // Apply function parameter storage classes to parameter types
+ Type prmtype = fparam.type.addStorageClass(fparam.storageClass);
+
+ Expression farg;
+
+ /* See function parameters which wound up
+ * as part of a template tuple parameter.
+ */
+ if (fptupindex != IDX_NOTFOUND && parami == fptupindex)
+ {
+ TypeIdentifier tid = prmtype.isTypeIdentifier();
+ assert(tid);
+ if (!declaredTuple)
+ {
+ /* The types of the function arguments
+ * now form the tuple argument.
+ */
+ declaredTuple = new Tuple();
+ (*dedargs)[td.parameters.length - 1] = declaredTuple;
+
+ /* Count function parameters with no defaults following a tuple parameter.
+ * void foo(U, T...)(int y, T, U, double, int bar = 0) {} // rem == 2 (U, double)
+ */
+ size_t rem = 0;
+ foreach (j; parami + 1 .. nfparams)
+ {
+ Parameter p = fparameters[j];
+ if (p.defaultArg)
+ {
+ break;
+ }
+ if (!reliesOnTemplateParameters(p.type, (*td.parameters)[inferStart .. td.parameters.length]))
+ {
+ Type pt = p.type.syntaxCopy().typeSemantic(fd.loc, paramscope);
+ if (auto ptt = pt.isTypeTuple())
+ rem += ptt.arguments.length;
+ else
+ rem += 1;
+ }
+ else
+ {
+ ++rem;
+ }
+ }
+
+ if (nfargs2 - argi < rem)
+ return nomatch();
+ declaredTuple.objects.setDim(nfargs2 - argi - rem);
+ foreach (i; 0 .. declaredTuple.objects.length)
+ {
+ farg = fargs[argi + i];
+
+ // Check invalid arguments to detect errors early.
+ if (farg.op == EXP.error || farg.type.ty == Terror)
+ return nomatch();
+
+ if (!fparam.isLazy() && farg.type.ty == Tvoid)
+ return nomatch();
+
+ Type tt;
+ MATCH m;
+ if (ubyte wm = deduceWildHelper(farg.type, &tt, tid))
+ {
+ inoutMatch |= wm;
+ m = MATCH.constant;
+ }
+ else
+ {
+ m = deduceTypeHelper(farg.type, tt, tid);
+ }
+ if (m == MATCH.nomatch)
+ return nomatch();
+ if (m < match)
+ match = m;
+
+ /* Remove top const for dynamic array types and pointer types
+ */
+ if ((tt.ty == Tarray || tt.ty == Tpointer) && !tt.isMutable() && (!(fparam.storageClass & STC.ref_) || (fparam.storageClass & STC.auto_) && !farg.isLvalue()))
+ {
+ tt = tt.mutableOf();
+ }
+ declaredTuple.objects[i] = tt;
+ }
+ td.declareParameter(paramscope, tp, declaredTuple);
+ }
+ else
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=6810
+ // If declared tuple is not a type tuple,
+ // it cannot be function parameter types.
+ for (size_t i = 0; i < declaredTuple.objects.length; i++)
+ {
+ if (!isType(declaredTuple.objects[i]))
+ return nomatch();
+ }
+ }
+ assert(declaredTuple);
+ argi += declaredTuple.objects.length;
+ continue;
+ }
+
+ // If parameter type doesn't depend on inferred template parameters,
+ // semantic it to get actual type.
+ if (!reliesOnTemplateParameters(prmtype, (*td.parameters)[inferStart .. td.parameters.length]))
+ {
+ // should copy prmtype to avoid affecting semantic result
+ prmtype = prmtype.syntaxCopy().typeSemantic(fd.loc, paramscope);
+
+ if (TypeTuple tt = prmtype.isTypeTuple())
+ {
+ 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 < fargs.length)
+ {
+ prmtype = p.type;
+ goto Lvarargs;
+ }
+ if (argi >= fargs.length)
+ {
+ if (p.defaultArg)
+ continue;
+
+ // https://issues.dlang.org/show_bug.cgi?id=19888
+ if (fparam.defaultArg)
+ break;
+
+ return nomatch();
+ }
+ farg = fargs[argi];
+ if (!farg.implicitConvTo(p.type))
+ return nomatch();
+ }
+ continue;
+ }
+ }
+
+ if (argi >= fargs.length) // if not enough arguments
+ {
+ if (!fparam.defaultArg)
+ goto Lvarargs;
+
+ /* https://issues.dlang.org/show_bug.cgi?id=2803
+ * Before the starting of type deduction from the function
+ * default arguments, set the already deduced parameters into paramscope.
+ * It's necessary to avoid breaking existing acceptable code. Cases:
+ *
+ * 1. Already deduced template parameters can appear in fparam.defaultArg:
+ * auto foo(A, B)(A a, B b = A.stringof);
+ * foo(1);
+ * // at fparam == 'B b = A.string', A is equivalent with the deduced type 'int'
+ *
+ * 2. If prmtype depends on default-specified template parameter, the
+ * default type should be preferred.
+ * auto foo(N = size_t, R)(R r, N start = 0)
+ * foo([1,2,3]);
+ * // at fparam `N start = 0`, N should be 'size_t' before
+ * // the deduction result from fparam.defaultArg.
+ */
+ if (argi == fargs.length)
+ {
+ foreach (ref dedtype; *dedtypes)
+ {
+ Type at = isType(dedtype);
+ if (at && at.ty == Tnone)
+ {
+ TypeDeduced xt = cast(TypeDeduced)at;
+ dedtype = xt.tded; // 'unbox'
+ }
+ }
+ for (size_t i = ntargs; i < dedargs.length; i++)
+ {
+ TemplateParameter tparam = (*td.parameters)[i];
+
+ RootObject oarg = (*dedargs)[i];
+ RootObject oded = (*dedtypes)[i];
+ if (oarg)
+ continue;
+
+ if (oded)
+ {
+ if (tparam.specialization() || !tparam.isTemplateTypeParameter())
+ {
+ /* The specialization can work as long as afterwards
+ * the oded == oarg
+ */
+ (*dedargs)[i] = oded;
+ MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, td.parameters, *dedtypes, null);
+ //printf("m2 = %d\n", m2);
+ if (m2 == MATCH.nomatch)
+ return nomatch();
+ if (m2 < matchTiargs)
+ matchTiargs = m2; // pick worst match
+ if (!(*dedtypes)[i].equals(oded))
+ .error(td.loc, "%s `%s` specialization not allowed for deduced parameter `%s`",
+ td.kind, td.toPrettyChars, td.kind, td.toPrettyChars, tparam.ident.toChars());
+ }
+ else
+ {
+ if (MATCH.convert < matchTiargs)
+ matchTiargs = MATCH.convert;
+ }
+ (*dedargs)[i] = td.declareParameter(paramscope, tparam, oded);
+ }
+ else
+ {
+ oded = tparam.defaultArg(instLoc, paramscope);
+ if (oded)
+ (*dedargs)[i] = td.declareParameter(paramscope, tparam, oded);
+ }
+ }
+ }
+ nfargs2 = argi + 1;
+
+ /* If prmtype does not depend on any template parameters:
+ *
+ * auto foo(T)(T v, double x = 0);
+ * foo("str");
+ * // at fparam == 'double x = 0'
+ *
+ * or, if all template parameters in the prmtype are already deduced:
+ *
+ * auto foo(R)(R range, ElementType!R sum = 0);
+ * foo([1,2,3]);
+ * // at fparam == 'ElementType!R sum = 0'
+ *
+ * Deducing prmtype from fparam.defaultArg is not necessary.
+ */
+ if (prmtype.deco || prmtype.syntaxCopy().trySemantic(td.loc, paramscope))
+ {
+ ++argi;
+ continue;
+ }
+
+ // Deduce prmtype from the defaultArg.
+ farg = fparam.defaultArg.syntaxCopy();
+ farg = farg.expressionSemantic(paramscope);
+ farg = resolveProperties(paramscope, farg);
+ }
+ else
+ {
+ farg = fargs[argi];
+ }
+ {
+ // Check invalid arguments to detect errors early.
+ if (farg.op == EXP.error || farg.type.ty == Terror)
+ return nomatch();
+
+ Type att = null;
+ Lretry:
+ version (none)
+ {
+ printf("\tfarg.type = %s\n", farg.type.toChars());
+ printf("\tfparam.type = %s\n", prmtype.toChars());
+ }
+ Type argtype = farg.type;
+
+ if (!fparam.isLazy() && argtype.ty == Tvoid && farg.op != EXP.function_)
+ return nomatch();
+
+ // https://issues.dlang.org/show_bug.cgi?id=12876
+ // Optimize argument to allow CT-known length matching
+ farg = farg.optimize(WANTvalue, fparam.isReference());
+ //printf("farg = %s %s\n", farg.type.toChars(), farg.toChars());
+
+ RootObject oarg = farg;
+ if ((fparam.storageClass & STC.ref_) && (!(fparam.storageClass & STC.auto_) || farg.isLvalue()))
+ {
+ /* Allow expressions that have CT-known boundaries and type [] to match with [dim]
+ */
+ 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())
+ {
+ argtype = se.type.nextOf().sarrayOf(se.len);
+ }
+ else if (ArrayLiteralExp ae = farg.isArrayLiteralExp())
+ {
+ argtype = ae.type.nextOf().sarrayOf(ae.elements.length);
+ }
+ else if (SliceExp se = farg.isSliceExp())
+ {
+ if (Type tsa = toStaticArrayType(se))
+ argtype = tsa;
+ }
+ }
+
+ oarg = argtype;
+ }
+ else if ((fparam.storageClass & STC.out_) == 0 &&
+ (argtype.ty == Tarray || argtype.ty == Tpointer) &&
+ templateParameterLookup(prmtype, td.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
+ * by adjusting top-qualifier of the argtype.
+ *
+ * prmtype argtype ta
+ * T <- const(E)[] const(E)[]
+ * T <- const(E[]) const(E)[]
+ * qualifier(T) <- const(E)[] const(E[])
+ * qualifier(T) <- const(E[]) const(E[])
+ */
+ Type ta = argtype.castMod(prmtype.mod ? argtype.nextOf().mod : 0);
+ if (ta != argtype)
+ {
+ Expression ea = farg.copy();
+ ea.type = ta;
+ oarg = ea;
+ }
+ }
+
+ if (fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams && argi + 1 < fargs.length)
+ goto Lvarargs;
+
+ uint im = 0;
+ MATCH m = deduceType(oarg, paramscope, prmtype, *td.parameters, *dedtypes, &im, inferStart);
+ //printf("\tL%d deduceType m = %d, im = x%x, inoutMatch = x%x\n", __LINE__, m, im, inoutMatch);
+ inoutMatch |= im;
+
+ /* If no match, see if the argument can be matched by using
+ * implicit conversions.
+ */
+ if (m == MATCH.nomatch && prmtype.deco)
+ m = farg.implicitConvTo(prmtype);
+
+ if (m == MATCH.nomatch)
+ {
+ AggregateDeclaration ad = isAggregate(farg.type);
+ if (ad && ad.aliasthis && !isRecursiveAliasThis(att, argtype))
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=12537
+ // The isRecursiveAliasThis() call above
+
+ /* If a semantic error occurs while doing alias this,
+ * eg purity(https://issues.dlang.org/show_bug.cgi?id=7295),
+ * just regard it as not a match.
+ *
+ * We also save/restore sc.func.flags to avoid messing up
+ * attribute inference in the evaluation.
+ */
+ const oldflags = sc.func ? sc.func.flags : 0;
+ auto e = resolveAliasThis(sc, farg, true);
+ if (sc.func)
+ sc.func.flags = oldflags;
+ if (e)
+ {
+ farg = e;
+ goto Lretry;
+ }
+ }
+ }
+
+ if (m > MATCH.nomatch && (fparam.storageClass & (STC.ref_ | STC.auto_)) == STC.ref_)
+ {
+ if (!farg.isLvalue())
+ {
+ if ((farg.op == EXP.string_ || farg.op == EXP.slice) && (prmtype.ty == Tsarray || prmtype.ty == Taarray))
+ {
+ // Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
+ }
+ else if (global.params.rvalueRefParam == FeatureState.enabled)
+ {
+ // Allow implicit conversion to ref
+ }
+ else
+ return nomatch();
+ }
+ }
+ if (m > MATCH.nomatch && (fparam.storageClass & STC.out_))
+ {
+ if (!farg.isLvalue())
+ return nomatch();
+ if (!farg.type.isMutable()) // https://issues.dlang.org/show_bug.cgi?id=11916
+ return nomatch();
+ }
+ if (m == MATCH.nomatch && fparam.isLazy() && prmtype.ty == Tvoid && farg.type.ty != Tvoid)
+ m = MATCH.convert;
+ if (m != MATCH.nomatch)
+ {
+ if (m < match)
+ match = m; // pick worst match
+ argi++;
+ continue;
+ }
+ }
+
+ Lvarargs:
+ /* The following code for variadic arguments closely
+ * matches TypeFunction.callMatch()
+ */
+ if (!(fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams))
+ return nomatch();
+
+ /* Check for match with function parameter T...
+ */
+ Type tb = prmtype.toBasetype();
+ switch (tb.ty)
+ {
+ // 6764 fix - TypeAArray may be TypeSArray have not yet run semantic().
+ case Tsarray:
+ case Taarray:
+ {
+ // Perhaps we can do better with this, see TypeFunction.callMatch()
+ if (TypeSArray tsa = tb.isTypeSArray())
+ {
+ dinteger_t sz = tsa.dim.toInteger();
+ if (sz != fargs.length - argi)
+ return nomatch();
+ }
+ else if (TypeAArray taa = tb.isTypeAArray())
+ {
+ Expression dim = new IntegerExp(instLoc, fargs.length - argi, Type.tsize_t);
+
+ size_t i = templateParameterLookup(taa.index, td.parameters);
+ if (i == IDX_NOTFOUND)
+ {
+ Expression e;
+ Type t;
+ Dsymbol s;
+ Scope *sco;
+
+ uint errors = global.startGagging();
+ /* ref: https://issues.dlang.org/show_bug.cgi?id=11118
+ * The parameter isn't part of the template
+ * ones, let's try to find it in the
+ * instantiation scope 'sc' and the one
+ * belonging to the template itself. */
+ sco = sc;
+ taa.index.resolve(instLoc, sco, e, t, s);
+ if (!e)
+ {
+ sco = paramscope;
+ taa.index.resolve(instLoc, sco, e, t, s);
+ }
+ global.endGagging(errors);
+
+ if (!e)
+ return nomatch();
+
+ e = e.ctfeInterpret();
+ e = e.implicitCastTo(sco, Type.tsize_t);
+ e = e.optimize(WANTvalue);
+ if (!dim.equals(e))
+ return nomatch();
+ }
+ else
+ {
+ // This code matches code in TypeInstance.deduceType()
+ TemplateParameter tprm = (*td.parameters)[i];
+ TemplateValueParameter tvp = tprm.isTemplateValueParameter();
+ if (!tvp)
+ return nomatch();
+ Expression e = cast(Expression)(*dedtypes)[i];
+ if (e)
+ {
+ if (!dim.equals(e))
+ return nomatch();
+ }
+ else
+ {
+ Type vt = tvp.valType.typeSemantic(Loc.initial, sc);
+ MATCH m = dim.implicitConvTo(vt);
+ if (m == MATCH.nomatch)
+ return nomatch();
+ (*dedtypes)[i] = dim;
+ }
+ }
+ }
+ goto case Tarray;
+ }
+ case Tarray:
+ {
+ TypeArray ta = cast(TypeArray)tb;
+ Type tret = fparam.isLazyArray();
+ for (; argi < fargs.length; argi++)
+ {
+ Expression arg = fargs[argi];
+ assert(arg);
+
+ MATCH m;
+ /* If lazy array of delegates,
+ * convert arg(s) to delegate(s)
+ */
+ if (tret)
+ {
+ if (ta.next.equals(arg.type))
+ {
+ m = MATCH.exact;
+ }
+ else
+ {
+ m = arg.implicitConvTo(tret);
+ if (m == MATCH.nomatch)
+ {
+ if (tret.toBasetype().ty == Tvoid)
+ m = MATCH.convert;
+ }
+ }
+ }
+ else
+ {
+ uint wm = 0;
+ m = deduceType(arg, paramscope, ta.next, *td.parameters, *dedtypes, &wm, inferStart);
+ inoutMatch |= wm;
+ }
+ if (m == MATCH.nomatch)
+ return nomatch();
+ if (m < match)
+ match = m;
+ }
+ goto Lmatch;
+ }
+ case Tclass:
+ case Tident:
+ goto Lmatch;
+
+ default:
+ return nomatch();
+ }
+ assert(0);
+ }
+ //printf(". argi = %d, nfargs = %d, nfargs2 = %d\n", argi, nfargs, nfargs2);
+ if (argi != nfargs2 && fparameters.varargs == VarArg.none)
+ return nomatch();
+ }
+
+Lmatch:
+ foreach (ref dedtype; *dedtypes)
+ {
+ if (Type at = isType(dedtype))
+ {
+ if (at.ty == Tnone)
+ {
+ TypeDeduced xt = cast(TypeDeduced)at;
+ at = xt.tded; // 'unbox'
+ }
+ dedtype = at.merge2();
+ }
+ }
+ for (size_t i = ntargs; i < dedargs.length; i++)
+ {
+ TemplateParameter tparam = (*td.parameters)[i];
+ //printf("tparam[%d] = %s\n", i, tparam.ident.toChars());
+
+ /* For T:T*, the dedargs is the T*, dedtypes is the T
+ * But for function templates, we really need them to match
+ */
+ RootObject oarg = (*dedargs)[i];
+ RootObject oded = (*dedtypes)[i];
+ //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded);
+ //if (oarg) printf("oarg: %s\n", oarg.toChars());
+ //if (oded) printf("oded: %s\n", oded.toChars());
+ if (oarg)
+ continue;
+
+ if (oded)
+ {
+ if (tparam.specialization() || !tparam.isTemplateTypeParameter())
+ {
+ /* The specialization can work as long as afterwards
+ * the oded == oarg
+ */
+ (*dedargs)[i] = oded;
+ MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, td.parameters, *dedtypes, null);
+ //printf("m2 = %d\n", m2);
+ if (m2 == MATCH.nomatch)
+ return nomatch();
+ if (m2 < matchTiargs)
+ matchTiargs = m2; // pick worst match
+ if (!(*dedtypes)[i].equals(oded))
+ .error(td.loc, "%s `%s` specialization not allowed for deduced parameter `%s`", td.kind, td.toPrettyChars, tparam.ident.toChars());
+ }
+ else
+ {
+ // Discussion: https://issues.dlang.org/show_bug.cgi?id=16484
+ if (MATCH.convert < matchTiargs)
+ matchTiargs = MATCH.convert;
+ }
+ }
+ else
+ {
+ oded = tparam.defaultArg(instLoc, paramscope);
+ if (!oded)
+ {
+ // if tuple parameter and
+ // tuple parameter was not in function parameter list and
+ // we're one or more arguments short (i.e. no tuple argument)
+ if (tparam == tp &&
+ fptupindex == IDX_NOTFOUND &&
+ ntargs <= dedargs.length - 1)
+ {
+ // make tuple argument an empty tuple
+ oded = new Tuple();
+ }
+ else
+ return nomatch();
+ }
+ if (isError(oded))
+ return matcherror();
+ ntargs++;
+
+ /* At the template parameter T, the picked default template argument
+ * X!int should be matched to T in order to deduce dependent
+ * template parameter A.
+ * auto foo(T : X!A = X!int, A...)() { ... }
+ * foo(); // T <-- X!int, A <-- (int)
+ */
+ if (tparam.specialization())
+ {
+ (*dedargs)[i] = oded;
+ MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, td.parameters, *dedtypes, null);
+ //printf("m2 = %d\n", m2);
+ if (m2 == MATCH.nomatch)
+ return nomatch();
+ if (m2 < matchTiargs)
+ matchTiargs = m2; // pick worst match
+ if (!(*dedtypes)[i].equals(oded))
+ .error(td.loc, "%s `%s` specialization not allowed for deduced parameter `%s`", td.kind, td.toPrettyChars, tparam.ident.toChars());
+ }
+ }
+ oded = td.declareParameter(paramscope, tparam, oded);
+ (*dedargs)[i] = oded;
+ }
+
+ /* https://issues.dlang.org/show_bug.cgi?id=7469
+ * As same as the code for 7469 in findBestMatch,
+ * expand a Tuple in dedargs to normalize template arguments.
+ */
+ if (auto d = dedargs.length)
+ {
+ if (auto va = isTuple((*dedargs)[d - 1]))
+ {
+ dedargs.setDim(d - 1);
+ dedargs.insert(d - 1, &va.objects);
+ }
+ }
+ ti.tiargs = dedargs; // update to the normalized template arguments.
+
+ // Partially instantiate function for constraint and fd.leastAsSpecialized()
+ {
+ assert(paramscope.scopesym);
+ Scope* sc2 = td._scope;
+ sc2 = sc2.push(paramscope.scopesym);
+ sc2 = sc2.push(ti);
+ sc2.parent = ti;
+ sc2.tinst = ti;
+ sc2.minst = sc.minst;
+ sc2.stc |= fd.storage_class & STC.deprecated_;
+
+ fd = td.doHeaderInstantiation(ti, sc2, fd, tthis, argumentList.arguments);
+ sc2 = sc2.pop();
+ sc2 = sc2.pop();
+
+ if (!fd)
+ return nomatch();
+ }
+
+ if (td.constraint)
+ {
+ if (!evaluateConstraint(td, ti, sc, paramscope, dedargs, fd))
+ return nomatch();
+ }
+
+ version (none)
+ {
+ for (size_t i = 0; i < dedargs.length; i++)
+ {
+ RootObject o = (*dedargs)[i];
+ printf("\tdedargs[%d] = %d, %s\n", i, o.dyncast(), o.toChars());
+ }
+ }
+
+ paramscope.pop();
+ //printf("\tmatch %d\n", match);
+ return MATCHpair(matchTiargs, match);
+}
diff --git a/gcc/d/dmd/tokens.d b/gcc/d/dmd/tokens.d
index 589bc2b..da4a3ee 100644
--- a/gcc/d/dmd/tokens.d
+++ b/gcc/d/dmd/tokens.d
@@ -124,6 +124,7 @@ enum TOK : ubyte
// Leaf operators
identifier,
string_,
+ interpolated,
hexadecimalString,
this_,
super_,
@@ -380,6 +381,7 @@ enum EXP : ubyte
// Leaf operators
identifier,
string_,
+ interpolated,
this_,
super_,
halt,
@@ -623,6 +625,10 @@ static immutable TOK[TOK.max + 1] Ckeywords =
}
} ();
+struct InterpolatedSet {
+ // all strings in the parts are zero terminated at length+1
+ string[] parts;
+}
/***********************************************************
*/
@@ -645,7 +651,11 @@ extern (C++) struct Token
struct
{
- const(char)* ustring; // UTF8 string
+ union
+ {
+ const(char)* ustring; // UTF8 string
+ InterpolatedSet* interpolatedSet;
+ }
uint len;
ubyte postfix; // 'c', 'w', 'd'
}
@@ -833,6 +843,7 @@ extern (C++) struct Token
// For debugging
TOK.error: "error",
TOK.string_: "string",
+ TOK.interpolated: "interpolated string",
TOK.onScopeExit: "scope(exit)",
TOK.onScopeSuccess: "scope(success)",
TOK.onScopeFailure: "scope(failure)",
@@ -910,6 +921,24 @@ nothrow:
return 0;
}
+ extern(D) void appendInterpolatedPart(const ref OutBuffer buf) {
+ appendInterpolatedPart(cast(const(char)*)buf[].ptr, buf.length);
+ }
+ extern(D) void appendInterpolatedPart(const(char)[] str) {
+ appendInterpolatedPart(str.ptr, str.length);
+ }
+ extern(D) void appendInterpolatedPart(const(char)* ptr, size_t length) {
+ assert(value == TOK.interpolated);
+ if (interpolatedSet is null)
+ interpolatedSet = new InterpolatedSet;
+
+ auto s = cast(char*)mem.xmalloc_noscan(length + 1);
+ memcpy(s, ptr, length);
+ s[length] = 0;
+
+ interpolatedSet.parts ~= cast(string) s[0 .. length];
+ }
+
/****
* Set to contents of ptr[0..length]
* Params:
@@ -918,6 +947,7 @@ nothrow:
*/
void setString(const(char)* ptr, size_t length)
{
+ value = TOK.string_;
auto s = cast(char*)mem.xmalloc_noscan(length + 1);
memcpy(s, ptr, length);
s[length] = 0;
@@ -941,6 +971,7 @@ nothrow:
*/
void setString()
{
+ value = TOK.string_;
ustring = "";
len = 0;
postfix = 0;
diff --git a/gcc/d/dmd/tokens.h b/gcc/d/dmd/tokens.h
index f944663..ef91001 100644
--- a/gcc/d/dmd/tokens.h
+++ b/gcc/d/dmd/tokens.h
@@ -133,6 +133,7 @@ enum class TOK : unsigned char
// Leaf operators
identifier,
string_,
+ interpolated,
hexadecimalString,
this_,
super_,
@@ -390,6 +391,7 @@ enum class EXP : unsigned char
// Leaf operators
identifier,
string_,
+ interpolated,
this_,
super_,
halt,
@@ -461,7 +463,12 @@ struct Token
real_t floatvalue;
struct
- { utf8_t *ustring; // UTF8 string
+ {
+ union
+ {
+ utf8_t *ustring; // UTF8 string
+ void *interpolatedSet;
+ };
unsigned len;
unsigned char postfix; // 'c', 'w', 'd'
};
diff --git a/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d
index c67ee81..be7aa99 100644
--- a/gcc/d/dmd/traits.d
+++ b/gcc/d/dmd/traits.d
@@ -36,6 +36,7 @@ import dmd.errorsink;
import dmd.expression;
import dmd.expressionsem;
import dmd.func;
+import dmd.funcsem;
import dmd.globals;
import dmd.hdrgen;
import dmd.id;
@@ -1306,7 +1307,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
// attribute inference.
if (fd && fd.parent && fd.parent.isTemplateInstance)
{
- fd.functionSemantic3();
+ functionSemantic3(fd);
tf = fd.type.isTypeFunction();
}
diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d
index 714af8a..6721fa6 100644
--- a/gcc/d/dmd/typesem.d
+++ b/gcc/d/dmd/typesem.d
@@ -35,6 +35,7 @@ import dmd.dstruct;
import dmd.dsymbol;
import dmd.dsymbolsem;
import dmd.dtemplate;
+import dmd.enumsem;
import dmd.errors;
import dmd.errorsink;
import dmd.expression;
@@ -2919,6 +2920,29 @@ extern (C++) Type merge(Type type)
return type;
}
+/*************************************
+ * This version does a merge even if the deco is already computed.
+ * Necessary for types that have a deco, but are not merged.
+ */
+extern(C++) Type merge2(Type type)
+{
+ //printf("merge2(%s)\n", toChars());
+ Type t = type;
+ assert(t);
+ if (!t.deco)
+ return t.merge();
+
+ auto sv = Type.stringtable.lookup(t.deco, strlen(t.deco));
+ if (sv && sv.value)
+ {
+ t = sv.value;
+ assert(t.deco);
+ }
+ else
+ assert(0);
+ return t;
+}
+
/***************************************
* Calculate built-in properties which just the type is necessary.
*
@@ -5697,7 +5721,7 @@ Type getComplexLibraryType(const ref Loc loc, Scope* sc, TY ty)
* Returns:
* An enum value of either `Covariant.yes` or a reason it's not covariant.
*/
-extern (C++) Covariant covariant(Type src, Type t, StorageClass* pstc = null, bool cppCovariant = false)
+extern(C++) Covariant covariant(Type src, Type t, StorageClass* pstc = null, bool cppCovariant = false)
{
version (none)
{
diff --git a/gcc/d/dmd/typinf.d b/gcc/d/dmd/typinf.d
index 9e062bd..6ae6df0 100644
--- a/gcc/d/dmd/typinf.d
+++ b/gcc/d/dmd/typinf.d
@@ -65,6 +65,7 @@ extern (C++) bool genTypeInfo(Expression e, const ref Loc loc, Type torig, Scope
fatal();
}
+ import dmd.typesem : merge2;
Type t = torig.merge2(); // do this since not all Type's are merge'd
bool needsCodegen = false;
if (!t.vtinfo)
diff --git a/gcc/d/dmd/visitor.h b/gcc/d/dmd/visitor.h
index 7fa08cb0..6e3d315 100644
--- a/gcc/d/dmd/visitor.h
+++ b/gcc/d/dmd/visitor.h
@@ -195,6 +195,7 @@ class ThisExp;
class SuperExp;
class NullExp;
class StringExp;
+class InterpExp;
class TupleExp;
class ArrayLiteralExp;
class AssocArrayLiteralExp;
@@ -480,6 +481,7 @@ public:
virtual void visit(TypeidExp *e) { visit((Expression *)e); }
virtual void visit(TraitsExp *e) { visit((Expression *)e); }
virtual void visit(StringExp *e) { visit((Expression *)e); }
+ virtual void visit(InterpExp *e) { visit((Expression *)e); }
virtual void visit(NewExp *e) { visit((Expression *)e); }
virtual void visit(AssocArrayLiteralExp *e) { visit((Expression *)e); }
virtual void visit(ArrayLiteralExp *e) { visit((Expression *)e); }