# HG changeset patch # User Eldar Insafutdinov # Date 1284412782 -3600 # Node ID af1bebfd96a4eece91aabe1f6d92695bf39aa52d # Parent 4251f96733f430267f438430158b977ec6d9a9f7 dmd 2.038 diff -r 4251f96733f4 -r af1bebfd96a4 commands.linux.txt --- a/commands.linux.txt Sat Sep 11 13:03:39 2010 +0100 +++ b/commands.linux.txt Mon Sep 13 22:19:42 2010 +0100 @@ -78,6 +78,7 @@ dmd/ArrayLengthExp.d dmd/TypeInfoConstDeclaration.d dmd/TypeInfoInvariantDeclaration.d +dmd/TypeInfoWildDeclaration.d dmd/TypeInfoSharedDeclaration.d dmd/TypeInfoStructDeclaration.d dmd/TypeInfoInterfaceDeclaration.d @@ -272,6 +273,7 @@ dmd/Parser.d dmd/PostBlitDeclaration.d dmd/PowExp.d +dmd/PowAssignExp.d dmd/PragmaDeclaration.d dmd/PragmaStatement.d dmd/ProtDeclaration.d diff -r 4251f96733f4 -r af1bebfd96a4 commands.txt --- a/commands.txt Sat Sep 11 13:03:39 2010 +0100 +++ b/commands.txt Mon Sep 13 22:19:42 2010 +0100 @@ -73,6 +73,7 @@ dmd\ArrayLengthExp.d dmd\TypeInfoConstDeclaration.d dmd\TypeInfoInvariantDeclaration.d +dmd\TypeInfoWildDeclaration.d dmd\TypeInfoSharedDeclaration.d dmd\TypeInfoStructDeclaration.d dmd\TypeInfoInterfaceDeclaration.d @@ -267,6 +268,7 @@ dmd\Parser.d dmd\PostBlitDeclaration.d dmd\PowExp.d +dmd\PowAssignExp.d dmd\PragmaDeclaration.d dmd\PragmaStatement.d dmd\ProtDeclaration.d diff -r 4251f96733f4 -r af1bebfd96a4 ddmd.visualdproj --- a/ddmd.visualdproj Sat Sep 11 13:03:39 2010 +0100 +++ b/ddmd.visualdproj Mon Sep 13 22:19:42 2010 +0100 @@ -608,6 +608,8 @@ + + diff -r 4251f96733f4 -r af1bebfd96a4 dmd/AddrExp.d --- a/dmd/AddrExp.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/AddrExp.d Mon Sep 13 22:19:42 2010 +0100 @@ -126,6 +126,11 @@ return this; } + override void checkEscape() + { + e1.checkEscapeRef(); + } + override elem* toElem(IRState* irs) { elem* e; diff -r 4251f96733f4 -r af1bebfd96a4 dmd/AliasDeclaration.d --- a/dmd/AliasDeclaration.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/AliasDeclaration.d Mon Sep 13 22:19:42 2010 +0100 @@ -100,9 +100,10 @@ } this.inSemantic = 1; +version(DMDV1) { // don't really know why this is here if (storage_class & STC.STCconst) error("cannot be const"); - +} storage_class |= sc.stc & STC.STCdeprecated; // Given: @@ -128,11 +129,12 @@ goto L2; // it's a symbolic alias ///version (DMDV2) { + type = type.addStorageClass(storage_class); if (storage_class & (STC.STCref | STCnothrow | STCpure)) { // For 'ref' to be attached to function types, and picked // up by Type.resolve(), it has to go into sc. sc = sc.push(); - sc.stc |= storage_class & (STCref | STCnothrow | STCpure); + sc.stc |= storage_class & (STCref | STCnothrow | STCpure | STCshared); type.resolve(loc, sc, &e, &t, &s); sc = sc.pop(); } diff -r 4251f96733f4 -r af1bebfd96a4 dmd/ArrayLiteralExp.d --- a/dmd/ArrayLiteralExp.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/ArrayLiteralExp.d Mon Sep 13 22:19:42 2010 +0100 @@ -213,10 +213,7 @@ ex = e.interpret(istate); if (ex is EXP_CANT_INTERPRET) - { - delete expsx; - return EXP_CANT_INTERPRET; - } + goto Lerror; /* If any changes, do Copy On Write */ @@ -239,10 +236,7 @@ { expandTuples(expsx); if (expsx.dim != elements.dim) - { - delete expsx; - return EXP_CANT_INTERPRET; - } + goto Lerror; ArrayLiteralExp ae = new ArrayLiteralExp(loc, expsx); ae.type = type; @@ -250,6 +244,12 @@ return ae; } return this; + + Lerror: + if (expsx) + delete expsx; + error("cannot interpret array literal"); + return EXP_CANT_INTERPRET; } override MATCH implicitConvTo(Type t) diff -r 4251f96733f4 -r af1bebfd96a4 dmd/BinExp.d --- a/dmd/BinExp.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/BinExp.d Mon Sep 13 22:19:42 2010 +0100 @@ -552,6 +552,7 @@ case TOK.TOKandass: case TOK.TOKorass: case TOK.TOKxorass: + case TOK.TOKpowass: case TOK.TOKin: case TOK.TOKremove: return true; @@ -803,7 +804,7 @@ } else if (v && v.value && (v.value.op==TOKindex || v.value.op == TOKdotvar)) { - // It is no longer be a TOKvar, eg when a[4] is passed by ref. + // It is no longer a TOKvar, eg when a[4] is passed by ref. e1 = v.value; } } @@ -826,13 +827,13 @@ VarExp ve = cast(VarExp)e1; VarDeclaration v = ve.var.isVarDeclaration(); assert(v); - if (v && v.isDataseg()) + if (v && !v.isCTFE()) { // Can't modify global or static data error("%s cannot be modified at compile time", v.toChars()); return EXP_CANT_INTERPRET; } - if (v && !v.isDataseg()) + if (v && v.isCTFE()) { Expression ev = v.value; if (fp && !ev) @@ -848,7 +849,7 @@ */ if (v.type.toBasetype().ty == Tstruct && e2.op == TOKint64) { - e2 = v.type.defaultInit(Loc(0)); + e2 = v.type.defaultInitLiteral(Loc(0)); } e2 = Cast(v.type, v.type, e2); } @@ -872,7 +873,7 @@ { VarDeclaration v = (cast(VarExp)aggregate).var.isVarDeclaration(); - if (v.isDataseg()) + if (!v.isCTFE()) { // Can't modify global or static data error("%s cannot be modified at compile time", v.toChars()); @@ -949,7 +950,7 @@ SymOffExp soe = cast(SymOffExp)(cast(PtrExp)e1).e1; VarDeclaration v = soe.var.isVarDeclaration(); - if (v.isDataseg()) + if (!v.isCTFE()) { error("%s cannot be modified at compile time", v.toChars()); return EXP_CANT_INTERPRET; @@ -997,7 +998,7 @@ IndexExp ie = cast(IndexExp)e1; VarExp ve = cast(VarExp)ie.e1; VarDeclaration v = ve.var.isVarDeclaration(); - if (!v || v.isDataseg()) + if (!v || !v.isCTFE()) { error("%s cannot be modified at compile time", v ? v.toChars(): "void"); return EXP_CANT_INTERPRET; @@ -1165,7 +1166,7 @@ IndexExp ie = cast(IndexExp)aggregate; VarExp ve = cast(VarExp)(ie.e1); VarDeclaration v = ve.var.isVarDeclaration(); - if (!v || v.isDataseg()) + if (!v || !v.isCTFE()) { error("%s cannot be modified at compile time", v ? v.toChars(): "void"); return EXP_CANT_INTERPRET; @@ -1188,8 +1189,7 @@ if (telem.ty != Tstruct) { return EXP_CANT_INTERPRET; } // Create a default struct literal... - StructDeclaration sym = (cast(TypeStruct)telem).sym; - StructLiteralExp structinit = createDefaultInitStructLiteral(v.loc, sym); + Expression structinit = telem.defaultInitLiteral(v.loc); // ... and use to create a blank array literal size_t dim = cast(size_t)(cast(TypeSArray)t2).dim.toInteger(); @@ -1257,7 +1257,7 @@ SliceExp sexp = cast(SliceExp)e1; VarExp ve = cast(VarExp)(sexp.e1); VarDeclaration v = ve.var.isVarDeclaration(); - if (!v || v.isDataseg()) + if (!v || !v.isCTFE()) { error("%s cannot be modified at compile time", v.toChars()); return EXP_CANT_INTERPRET; diff -r 4251f96733f4 -r af1bebfd96a4 dmd/CallExp.d --- a/dmd/CallExp.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/CallExp.d Mon Sep 13 22:19:42 2010 +0100 @@ -279,7 +279,6 @@ istemp = 0; Lagain: //printf("Lagain: %s\n", toChars()); - //printf("test1 %s\n", toChars()); f = null; if (e1.op == TOK.TOKthis || e1.op == TOK.TOKsuper) { @@ -509,7 +508,7 @@ printf("e1 = %s\n", e1.toChars()); printf("e1.type = %s\n", e1.type.toChars()); } - // Const member function can take const/immutable/mutable this + // Const member function can take const/immutable/mutable/inout this if (!(f.type.isConst())) { // Check for const/immutable compatibility @@ -518,14 +517,14 @@ tthis = tthis.nextOf().toBasetype(); static if (false) { // this checking should have been already done - if (f.type.isInvariant()) + if (f.type.isImmutable()) { - if (tthis.mod != MOD.MODinvariant) + if (tthis.mod != MOD.MODimmutable) error("%s can only be called with an immutable object", e1.toChars()); } else if (f.type.isShared()) { - if (tthis.mod != MOD.MODinvariant && tthis.mod != MOD.MODshared && tthis.mod != (MOD.MODshared | MOD.MODconst)) + if (tthis.mod != MOD.MODimmutable && tthis.mod != MOD.MODshared && tthis.mod != (MOD.MODshared | MOD.MODconst)) error("shared %s can only be called with a shared or immutable object", e1.toChars()); } else @@ -795,12 +794,11 @@ Lcheckargs: assert(tf.ty == TY.Tfunction); - type = tf.next; if (!arguments) arguments = new Expressions(); - functionParameters(loc, sc, tf, arguments); + type = functionParameters(loc, sc, tf, arguments); if (!type) { diff -r 4251f96733f4 -r af1bebfd96a4 dmd/Cast.d --- a/dmd/Cast.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/Cast.d Mon Sep 13 22:19:42 2010 +0100 @@ -61,6 +61,9 @@ } } + if (e1.op == TOK.TOKarrayliteral && typeb == tb) + return e1; + if (e1.isConst() != 1) return EXP_CANT_INTERPRET; diff -r 4251f96733f4 -r af1bebfd96a4 dmd/CastExp.d --- a/dmd/CastExp.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/CastExp.d Mon Sep 13 22:19:42 2010 +0100 @@ -183,6 +183,10 @@ // Cast away pointer to shared goto Lunsafe; + if (t1bn.isWild() && !tobn.isConst() && !tobn.isWild()) + // Cast wild to anything but const | wild + goto Lunsafe; + if (tobn.isTypeBasic() && tobn.size() < t1bn.size()) { // Allow things like casting a long* to an int* ; @@ -425,27 +429,7 @@ to.toCBuffer(buf, null, hgs); else { - switch (mod) - { - case MODundefined: - break; - case MODconst: - buf.writestring(Token.tochars[TOKconst]); - break; - case MODinvariant: - buf.writestring(Token.tochars[TOKimmutable]); - break; - case MODshared: - buf.writestring(Token.tochars[TOKshared]); - break; - case MODshared | MODconst: - buf.writestring(Token.tochars[TOKshared]); - buf.writeByte(' '); - buf.writestring(Token.tochars[TOKconst]); - break; - default: - assert(0); - } + MODtoBuffer(buf, mod); } } buf.writeByte(')'); diff -r 4251f96733f4 -r af1bebfd96a4 dmd/ClassDeclaration.d --- a/dmd/ClassDeclaration.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/ClassDeclaration.d Mon Sep 13 22:19:42 2010 +0100 @@ -258,6 +258,13 @@ Type.typeinfoshared.error("%s", msg); Type.typeinfoshared = this; } + + if (id == Id.TypeInfo_Wild) + { + if (Type.typeinfowild) + Type.typeinfowild.error("%s", msg); + Type.typeinfowild = this; + } } } @@ -699,6 +706,22 @@ structsize = sc.offset; Scope scsave = sc.clone(); sizeok = 0; + + /* Set scope so if there are forward references, we still might be able to + * resolve individual members like enums. + */ + foreach (s; members) + { + /* There are problems doing this in the general case because + * Scope keeps track of things like 'offset' + */ + if (s.isEnumDeclaration() || (s.isAggregateDeclaration() && s.ident)) + { + //printf("setScope %s %s\n", s->kind(), s->toChars()); + s.setScope(sc); + } + } + foreach (Dsymbol s; members) { s.semantic(sc); } diff -r 4251f96733f4 -r af1bebfd96a4 dmd/CommaExp.d --- a/dmd/CommaExp.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/CommaExp.d Mon Sep 13 22:19:42 2010 +0100 @@ -38,6 +38,11 @@ e2.checkEscape(); } + override void checkEscapeRef() + { + e2.checkEscapeRef(); + } + override IntRange getIntRange() { assert(false); diff -r 4251f96733f4 -r af1bebfd96a4 dmd/CondExp.d --- a/dmd/CondExp.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/CondExp.d Mon Sep 13 22:19:42 2010 +0100 @@ -184,6 +184,12 @@ e2.checkEscape(); } + override void checkEscapeRef() + { + e1.checkEscapeRef(); + e2.checkEscapeRef(); + } + override int isLvalue() { return e1.isLvalue() && e2.isLvalue(); diff -r 4251f96733f4 -r af1bebfd96a4 dmd/Declaration.d --- a/dmd/Declaration.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/Declaration.d Mon Sep 13 22:19:42 2010 +0100 @@ -158,7 +158,7 @@ string p = null; if (isConst()) p = "const"; - else if (isInvariant()) + else if (isImmutable()) p = "immutable"; else if (storage_class & STC.STCmanifest) p = "enum"; @@ -311,7 +311,7 @@ bool isConst() { return (storage_class & STC.STCconst) != 0; } - int isInvariant() { return storage_class & STC.STCinvariant; } + int isImmutable() { return storage_class & STC.STCimmutable; } int isAuto() { return storage_class & STC.STCauto; } diff -r 4251f96733f4 -r af1bebfd96a4 dmd/DeclarationExp.d --- a/dmd/DeclarationExp.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/DeclarationExp.d Mon Sep 13 22:19:42 2010 +0100 @@ -148,7 +148,7 @@ e = null; } ///version (DMDV2) { - else if (s == v && (v.isConst() || v.isInvariant()) && v.init) + else if (s == v && (v.isConst() || v.isImmutable()) && v.init) ///} else { /// else if (s == v && v.isConst() && v.init) ///} diff -r 4251f96733f4 -r af1bebfd96a4 dmd/DotVarExp.d --- a/dmd/DotVarExp.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/DotVarExp.d Mon Sep 13 22:19:42 2010 +0100 @@ -187,7 +187,7 @@ if (!t1.isMutable() || (t1.ty == TY.Tpointer && !t1.nextOf().isMutable()) || !var.type.isMutable() || !var.type.isAssignable() || var.storage_class & STC.STCmanifest) { - error("cannot modify const/immutable expression %s", toChars()); + error("cannot modify const/immutable/inout expression %s", toChars()); } } } @@ -242,10 +242,15 @@ { e = se.getField(type, v.offset); if (!e) + { + error("couldn't find field %s in %s", v.toChars(), type.toChars()); e = EXP_CANT_INTERPRET; + } return e; } - } else { + } + else + { error("%s.%s is not yet implemented at compile time", ex.toChars(), var.toChars()); } } diff -r 4251f96733f4 -r af1bebfd96a4 dmd/Expression.d --- a/dmd/Expression.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/Expression.d Mon Sep 13 22:19:42 2010 +0100 @@ -657,6 +657,10 @@ { } + void checkEscapeRef() + { + } + void checkScalar() { if (!type.isscalar()) diff -r 4251f96733f4 -r af1bebfd96a4 dmd/ForeachStatement.d --- a/dmd/ForeachStatement.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/ForeachStatement.d Mon Sep 13 22:19:42 2010 +0100 @@ -115,6 +115,7 @@ Statement s = this; size_t dim = arguments.dim; TypeAArray taa = null; + Dsymbol sapply = null; Type tn = null; Type tnv = null; @@ -255,6 +256,9 @@ sc.noctor++; Lagain: + Identifier idapply = (op == TOK.TOKforeach_reverse) + ? Id.applyReverse : Id.apply; + sapply = null; switch (tab.ty) { case TY.Tarray: @@ -445,6 +449,15 @@ case TY.Tclass: case TY.Tstruct: version (DMDV2) { + /* Prefer using opApply, if it exists + */ + if (dim != 1) // only one argument allowed with ranges + goto Lapply; + + sapply = search_function(cast(AggregateDeclaration)tab.toDsymbol(sc), idapply); + if (sapply) + goto Lapply; + { /* Look for range iteration, i.e. the properties * .empty, .next, .retreat, .head and .rear * foreach (e; aggr) { ... } @@ -454,9 +467,6 @@ * ... * } */ - if (dim != 1) // only one argument allowed with ranges - goto Lapply; - AggregateDeclaration ad = (tab.ty == TY.Tclass) ? cast(AggregateDeclaration)(cast(TypeClass)tab).sym : cast(AggregateDeclaration)(cast(TypeStruct)tab).sym; @@ -531,16 +541,9 @@ case TY.Tdelegate: Lapply: { - FuncDeclaration fdapply; - Parameters args; Expression ec; Expression e; - FuncLiteralDeclaration fld; Parameter a; - Type t; - Expression flde; - Identifier id; - Type tret; if (!checkForArgTypes()) { @@ -548,7 +551,7 @@ return this; } - tret = func.type.nextOf(); + Type tret = func.type.nextOf(); // Need a variable to hold value from any return statements in body. if (!sc.func.vresult && tret && tret != Type.tvoid) @@ -566,10 +569,11 @@ /* Turn body into the function literal: * int delegate(ref T arg) { body } */ - args = new Parameters(); + auto args = new Parameters(); for (size_t i = 0; i < dim; i++) { auto arg = arguments[i]; + Identifier id; arg.type = arg.type.semantic(loc, sc); if (arg.storageClass & STC.STCref) @@ -577,28 +581,25 @@ else { // Make a copy of the ref argument so it isn't // a reference. - VarDeclaration v; - Initializer ie; - id = Lexer.uniqueId("__applyArg", i); - ie = new ExpInitializer(Loc(0), new IdentifierExp(Loc(0), id)); - v = new VarDeclaration(Loc(0), arg.type, arg.ident, ie); + Initializer ie = new ExpInitializer(Loc(0), new IdentifierExp(Loc(0), id)); + auto v = new VarDeclaration(Loc(0), arg.type, arg.ident, ie); s = new DeclarationStatement(Loc(0), v); body_ = new CompoundStatement(loc, s, body_); } a = new Parameter(STC.STCref, arg.type, id, null); args.push(a); } - t = new TypeFunction(args, Type.tint32, 0, LINK.LINKd); - fld = new FuncLiteralDeclaration(loc, Loc(0), t, TOK.TOKdelegate, this); + Type t = new TypeFunction(args, Type.tint32, 0, LINK.LINKd); + FuncLiteralDeclaration fld = new FuncLiteralDeclaration(loc, Loc(0), t, TOK.TOKdelegate, this); fld.fbody = body_; - flde = new FuncExp(loc, fld); + Expression flde = new FuncExp(loc, fld); flde = flde.semantic(sc); fld.tookAddressOf = 0; // Resolve any forward referenced goto's - for (int i = 0; i < gotos.dim; i++) + for (size_t i = 0; i < gotos.dim; i++) { auto cs = cast(CompoundStatement)gotos.data[i]; auto gs = cast(GotoStatement)cs.statements[0]; @@ -631,6 +632,7 @@ /* Call: * _aaApply(aggr, keysize, flde) */ + FuncDeclaration fdapply; if (dim == 2) fdapply = FuncDeclaration.genCfunc(Type.tindex, "_aaApply2"); else @@ -674,7 +676,7 @@ string r = (op == TOK.TOKforeach_reverse) ? "R" : ""; int j = sprintf(fdname.ptr, "_aApply%.*s%.*s%zd".ptr, r, 2, fntab[flag].ptr, dim); assert(j < fdname.sizeof); - fdapply = FuncDeclaration.genCfunc(Type.tindex, fdname[0..j].idup); + FuncDeclaration fdapply = FuncDeclaration.genCfunc(Type.tindex, fdname[0..j].idup); ec = new VarExp(Loc(0), fdapply); auto exps = new Expressions(); @@ -700,10 +702,9 @@ else { assert(tab.ty == TY.Tstruct || tab.ty == TY.Tclass); - Identifier idapply = (op == TOK.TOKforeach_reverse) - ? Id.applyReverse : Id.apply; - Dsymbol sapply = search_function(cast(AggregateDeclaration)tab.toDsymbol(sc), idapply); - Expressions exps = new Expressions(); + auto exps = new Expressions(); + if (!sapply) + sapply = search_function(cast(AggregateDeclaration)tab.toDsymbol(sc), idapply); static if (false) { TemplateDeclaration td; if (sapply && (td = sapply.isTemplateDeclaration()) !is null) diff -r 4251f96733f4 -r af1bebfd96a4 dmd/FuncDeclaration.d --- a/dmd/FuncDeclaration.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/FuncDeclaration.d Mon Sep 13 22:19:42 2010 +0100 @@ -309,37 +309,59 @@ originalType = type; if (!type.deco) { + sc = sc.push(); + sc.stc |= storage_class & STC.STCref; // forward refness to function type + type = type.semantic(loc, sc); + sc = sc.pop(); + /* Apply const, immutable and shared storage class * to the function type */ - type = type.semantic(loc, sc); StorageClass stc = storage_class; - if (type.isInvariant()) + if (type.isImmutable()) stc |= STC.STCimmutable; if (type.isConst()) stc |= STC.STCconst; if (type.isShared() || storage_class & STC.STCsynchronized) stc |= STC.STCshared; + if (type.isWild()) + stc |= STC.STCwild; switch (stc & STC.STC_TYPECTOR) { case STC.STCimmutable: case STC.STCimmutable | STC.STCconst: case STC.STCimmutable | STC.STCconst | STC.STCshared: case STC.STCimmutable | STC.STCshared: + case STC.STCimmutable | STC.STCwild: + case STC.STCimmutable | STC.STCconst | STC.STCwild: + case STC.STCimmutable | STC.STCconst | STC.STCshared | STC.STCwild: + case STC.STCimmutable | STC.STCshared | STC.STCwild: // Don't use toInvariant(), as that will do a merge() type = type.makeInvariant(); goto Lmerge; case STC.STCconst: + case STC.STCconst | STC.STCwild: type = type.makeConst(); goto Lmerge; case STC.STCshared | STC.STCconst: + case STC.STCshared | STC.STCconst | STC.STCwild: type = type.makeSharedConst(); goto Lmerge; case STC.STCshared: type = type.makeShared(); + goto Lmerge; + + case STC.STCwild: + type = type.makeWild(); + goto Lmerge; + + case STC.STCshared | STC.STCwild: + type = type.makeSharedWild(); + goto Lmerge; + Lmerge: if (!(type.ty == Tfunction && !type.nextOf())) /* Can't do merge if return type is not known yet @@ -354,7 +376,7 @@ assert(0); } } - //type.print(); + storage_class &= ~STC.STCref; if (type.ty != TY.Tfunction) { error("%s must be a function", toChars()); @@ -378,7 +400,7 @@ if (isAbstract() && !isVirtual()) error("non-virtual functions cannot be abstract"); - if ((f.isConst() || f.isInvariant()) && !isThis()) + if ((f.isConst() || f.isImmutable()) && !isThis()) error("without 'this' cannot be const/immutable"); if (isAbstract() && isFinal()) @@ -965,7 +987,7 @@ thandle = thandle.nextOf().constOf().pointerTo(); } } - else if (storage_class & STC.STCimmutable || type.isInvariant()) + else if (storage_class & STC.STCimmutable || type.isImmutable()) { if (thandle.ty == TY.Tclass) thandle = thandle.invariantOf(); @@ -1054,7 +1076,7 @@ } } } - +static if(false) { // Propagate storage class from tuple parameters to their element-parameters. if (f.parameters) { @@ -1072,7 +1094,7 @@ } } } - +} /* Declare all the function parameters as variables * and install them in parameters[] */ @@ -2399,10 +2421,10 @@ assert(tb.ty == Tfunction); TypeFunction tf = cast(TypeFunction)tb; Type tret = tf.next.toBasetype(); - if (tf.varargs) + if (tf.varargs && arguments && parameters && arguments.dim != parameters.dim) { cantInterpret = 1; - error("Variadic functions are not yet implemented in CTFE"); + error("C-style variadic functions are not yet implemented in CTFE"); return null; } @@ -2547,7 +2569,7 @@ } } // Don't restore the value of 'this' upon function return - if (needThis() && thisarg.op==TOKvar) { + if (needThis() && thisarg.op == TOKvar && istate) { VarDeclaration thisvar = (cast(VarExp)thisarg).var.isVarDeclaration(); foreach (size_t i, Dsymbol s; istate.vars) { @@ -2562,7 +2584,7 @@ /* Save the values of the local variables used */ - scope Expressions valueSaves = new Expressions(); + scope valueSaves = new Expressions(); if (istate && !isNested()) { //printf("saving local variables...\n"); @@ -3835,6 +3857,35 @@ } } + /********************************************* + * Return the function's parameter list, and whether + * it is variadic or not. + */ + + Parameters getParameters(int *pvarargs) + { + Parameters fparameters; + int fvarargs; + + if (type) + { + assert(type.ty == Tfunction); + auto fdtype = cast(TypeFunction)type; + fparameters = fdtype.parameters; + fvarargs = fdtype.varargs; + } + else // Constructors don't have type's + { + CtorDeclaration fctor = isCtorDeclaration(); + assert(fctor); + fparameters = fctor.arguments; + fvarargs = fctor.varargs; + } + if (pvarargs) + *pvarargs = fvarargs; + return fparameters; + } + override FuncDeclaration isFuncDeclaration() { return this; } } diff -r 4251f96733f4 -r af1bebfd96a4 dmd/Global.d --- a/dmd/Global.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/Global.d Mon Sep 13 22:19:42 2010 +0100 @@ -39,7 +39,7 @@ string[] path; // Array of char*'s which form the import lookup path string[] filePath; // Array of char*'s which form the file import lookup path int structalign = 8; - string version_ = "v2.037"; + string version_ = "v2.038"; Param params; uint errors; // number of errors reported so far diff -r 4251f96733f4 -r af1bebfd96a4 dmd/Id.d --- a/dmd/Id.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/Id.d Mon Sep 13 22:19:42 2010 +0100 @@ -96,6 +96,8 @@ ID( "TypeInfo_Const" ), ID( "TypeInfo_Invariant" ), ID( "TypeInfo_Shared" ), + ID( "TypeInfo_Wild", "TypeInfo_Inout" ), + ID( "elements" ), ID( "_arguments_typeinfo" ), ID( "_arguments" ), @@ -217,7 +219,7 @@ ID( "opImplicitCast" ), ID( "pow", "opPow" ), ID( "pow_r", "opPow_r" ), - //ID( "powass", "opPowAssign" ), + ID( "powass", "opPowAssign" ), ID( "classNew", "new" ), ID( "classDelete", "delete" ), @@ -294,6 +296,9 @@ ID( "isVirtualFunction" ), ID( "isAbstractFunction" ), ID( "isFinalFunction" ), + ID( "isRef" ), + ID( "isOut" ), + ID( "isLazy" ), ID( "hasMember" ), ID( "getMember" ), ID( "getVirtualFunctions" ), diff -r 4251f96733f4 -r af1bebfd96a4 dmd/IdentityExp.d --- a/dmd/IdentityExp.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/IdentityExp.d Mon Sep 13 22:19:42 2010 +0100 @@ -53,12 +53,10 @@ override Expression optimize(int result) { - Expression e; - //printf("IdentityExp.optimize(result = %d) %s\n", result, toChars()); e1 = e1.optimize(WANT.WANTvalue | (result & WANT.WANTinterpret)); e2 = e2.optimize(WANT.WANTvalue | (result & WANT.WANTinterpret)); - e = this; + Expression e = this; if ((this.e1.isConst() && this.e2.isConst()) || (this.e1.op == TOK.TOKnull && this.e2.op == TOK.TOKnull)) { diff -r 4251f96733f4 -r af1bebfd96a4 dmd/IntegerExp.d --- a/dmd/IntegerExp.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/IntegerExp.d Mon Sep 13 22:19:42 2010 +0100 @@ -209,7 +209,8 @@ override bool isBool(bool result) { - return result ? value != 0 : value == 0; + int r = toInteger() != 0; + return cast(bool)(result ? r : !r); } override MATCH implicitConvTo(Type t) diff -r 4251f96733f4 -r af1bebfd96a4 dmd/IsExp.d --- a/dmd/IsExp.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/IsExp.d Mon Sep 13 22:19:42 2010 +0100 @@ -146,13 +146,19 @@ case TOKinvariant: case TOKimmutable: - if (!targ.isInvariant()) + if (!targ.isImmutable()) goto Lno; tded = targ; break; case TOKshared: if (!targ.isShared()) + goto Lno; + tded = targ; + break; + + case TOKwild: + if (!targ.isWild()) goto Lno; tded = targ; break; diff -r 4251f96733f4 -r af1bebfd96a4 dmd/Lexer.d --- a/dmd/Lexer.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/Lexer.d Mon Sep 13 22:19:42 2010 +0100 @@ -498,7 +498,7 @@ Token.tochars[TOK.TOKidentifier] = "identifier"; Token.tochars[TOK.TOKat] = "@"; Token.tochars[TOK.TOKpow] = "^^"; - //Token.tochars[TOK.TOKpowass] = "^^="; + Token.tochars[TOK.TOKpowass] = "^^="; // For debugging Token.tochars[TOKerror] = "error"; @@ -750,16 +750,29 @@ case 'Z': case '_': case_ident: - { ubyte c; - StringValue *sv; - Identifier id; + { + ubyte c; - do - { - c = *++p; - } while (isidchar(c) || (c & 0x80 && isUniAlpha(decodeUTF()))); - sv = stringtable.update((cast(immutable(char)*)t.ptr)[0.. p - t.ptr]); /// - id = cast(Identifier) sv.ptrvalue; + while (1) + { + c = *++p; + if (isidchar(c)) + continue; + else if (c & 0x80) + { + ubyte *s = p; + uint u = decodeUTF(); + if (isUniAlpha(u)) + continue; + error("char 0x%04x not allowed in identifier", u); + p = s; + } + break; + } + + StringValue *sv = stringtable.update((cast(immutable(char)*)t.ptr)[0.. p - t.ptr]); + Identifier id = cast(Identifier) sv.ptrvalue; + if (id is null) { id = new Identifier(sv.lstring.string_, TOK.TOKidentifier); sv.ptrvalue = cast(void*)id; @@ -1266,13 +1279,11 @@ p++; if (*p == '^') { p++; -//static if (false) { -// if (*p == '=') -// { p++; -// t.value = TOKpowass; // ^^= -// } -// else -//} + if (*p == '=') + { p++; + t.value = TOKpowass; // ^^= + } + else t.value = TOKpow; // ^^ } else if (*p == '=') @@ -1370,23 +1381,23 @@ continue; default: - { ubyte c = *p; + { uint c = *p; if (c & 0x80) - { uint u = decodeUTF(); + { c = decodeUTF(); // Check for start of unicode identifier - if (isUniAlpha(u)) + if (isUniAlpha(c)) goto case_ident; - if (u == PS || u == LS) + if (c == PS || c == LS) { loc.linnum++; p++; continue; } } - if (isprint(c)) + if (c < 0x80 && isprint(c)) error("unsupported char '%c'", c); else error("unsupported char 0x%02x", c); @@ -1719,7 +1730,7 @@ if (u == PS || u == LS) loc.linnum++; else - error("non-hex character \\u%x", u); + error("non-hex character \\u%04x", u); } else error("non-hex character '%c'", c); diff -r 4251f96733f4 -r af1bebfd96a4 dmd/MOD.d --- a/dmd/MOD.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/MOD.d Mon Sep 13 22:19:42 2010 +0100 @@ -5,8 +5,9 @@ MODundefined = 0, MODconst = 1, // type is const MODshared = 2, // type is shared - MODinvariant = 4, // type is immutable MODimmutable = 4, // type is immutable + MODwild = 8, // type is wild + MODmutable = 0x10, // type is mutable (only used in wildcard matching) } import dmd.EnumUtils; diff -r 4251f96733f4 -r af1bebfd96a4 dmd/NullExp.d --- a/dmd/NullExp.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/NullExp.d Mon Sep 13 22:19:42 2010 +0100 @@ -21,9 +21,10 @@ { ubyte committed; - this(Loc loc) + this(Loc loc, Type type = null) { super(loc, TOK.TOKnull, NullExp.sizeof); + this.type = type; } override Expression semantic(Scope sc) diff -r 4251f96733f4 -r af1bebfd96a4 dmd/Optimize.d --- a/dmd/Optimize.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/Optimize.d Mon Sep 13 22:19:42 2010 +0100 @@ -24,7 +24,7 @@ if (!v) return e; - if (v.isConst() || v.isInvariant() || v.storage_class & STC.STCmanifest) + if (v.isConst() || v.isImmutable() || v.storage_class & STC.STCmanifest) { if (!v.type) { diff -r 4251f96733f4 -r af1bebfd96a4 dmd/PREC.d --- a/dmd/PREC.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/PREC.d Mon Sep 13 22:19:42 2010 +0100 @@ -25,6 +25,7 @@ PREC_shift, PREC_add, PREC_mul, + PREC_pow, PREC_unary, PREC_primary, } diff -r 4251f96733f4 -r af1bebfd96a4 dmd/Parameter.d --- a/dmd/Parameter.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/Parameter.d Mon Sep 13 22:19:42 2010 +0100 @@ -177,6 +177,9 @@ buf.writestring(", "); auto arg = arguments[i]; + if (arg.storageClass & STCauto) + buf.writestring("auto "); + if (arg.storageClass & STCout) buf.writestring("out "); else if (arg.storageClass & STCref) @@ -187,8 +190,6 @@ buf.writestring("lazy "); else if (arg.storageClass & STCalias) buf.writestring("alias "); - else if (arg.storageClass & STCauto) - buf.writestring("auto "); StorageClass stc = arg.storageClass; if (arg.type && arg.type.mod & MODshared) diff -r 4251f96733f4 -r af1bebfd96a4 dmd/Parser.d --- a/dmd/Parser.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/Parser.d Mon Sep 13 22:19:42 2010 +0100 @@ -79,6 +79,7 @@ import dmd.DivAssignExp; import dmd.AndAssignExp; import dmd.AddAssignExp; +import dmd.PowAssignExp; import dmd.ModuleDeclaration; import dmd.CaseRangeStatement; import dmd.CommaExp; @@ -496,6 +497,12 @@ stc = STC.STCshared; goto Lstc; + case TOKwild: + if (peek(&token).value == TOK.TOKlparen) + goto Ldeclaration; + stc = STCwild; + goto Lstc; + case TOK.TOKfinal: stc = STC.STCfinal; goto Lstc; case TOK.TOKauto: stc = STC.STCauto; goto Lstc; case TOK.TOKscope: stc = STC.STCscope; goto Lstc; @@ -527,6 +534,7 @@ case TOK.TOKinvariant: case TOK.TOKimmutable: case TOK.TOKshared: + case TOKwild: // If followed by a (, it is not a storage class if (peek(&token).value == TOK.TOKlparen) break; @@ -534,6 +542,8 @@ stc = STC.STCconst; else if (token.value == TOK.TOKshared) stc = STC.STCshared; + else if (token.value == TOKwild) + stc = STC.STCwild; else stc = STC.STCimmutable; goto Lstc; @@ -1840,14 +1850,23 @@ goto Ldefault; stc = STC.STCshared; goto L2; + + case TOKwild: + if (peek(&token).value == TOK.TOKlparen) + goto Ldefault; + stc = STCwild; + goto L2; case TOK.TOKin: stc = STC.STCin; goto L2; case TOK.TOKout: stc = STC.STCout; goto L2; +version(D1INOUT) { case TOK.TOKinout: +} case TOK.TOKref: stc = STC.STCref; goto L2; case TOK.TOKlazy: stc = STC.STClazy; goto L2; case TOK.TOKscope: stc = STC.STCscope; goto L2; case TOK.TOKfinal: stc = STC.STCfinal; goto L2; + case TOK.TOKauto: stc = STCauto; goto L2; L2: if (storageClass & stc || (storageClass & STC.STCin && stc & (STC.STCconst | STC.STCscope)) || @@ -2316,6 +2335,17 @@ t = t.makeSharedConst(); return t; } + else if (token.value == TOKwild && peekNext() == TOKshared && peekNext2() != TOKlparen || + token.value == TOKshared && peekNext() == TOKwild && peekNext2() != TOKlparen) + { + nextToken(); + nextToken(); + /* shared wild type + */ + t = parseType(pident, tpl); + t = t.makeSharedWild(); + return t; + } else if (token.value == TOK.TOKconst && peekNext() != TOK.TOKlparen) { nextToken(); @@ -2344,6 +2374,15 @@ t = t.makeShared(); return t; } + else if (token.value == TOKwild && peekNext() != TOKlparen) + { + nextToken(); + /* wild type + */ + t = parseType(pident, tpl); + t = t.makeWild(); + return t; + } else t = parseBasicType(); t = parseDeclarator(t, pident, tpl); @@ -2471,10 +2510,24 @@ check(TOK.TOKrparen); if (t.isConst()) t = t.makeSharedConst(); + else if (t.isWild()) + t = t.makeSharedWild(); else t = t.makeShared(); break; + case TOKwild: + // wild(type) + nextToken(); + check(TOK.TOKlparen); + t = parseType(); + check(TOK.TOKrparen); + if (t.isShared()) + t = t.makeSharedWild(); + else + t = t.makeWild(); + break; + default: error("basic type expected, not %s", token.toChars()); t = Type.tint32; @@ -2742,6 +2795,14 @@ nextToken(); continue; + case TOKwild: + if (tf.isShared()) + tf = tf.makeSharedWild(); + else + tf = tf.makeWild(); + nextToken(); + continue; + case TOK.TOKnothrow: (cast(TypeFunction)tf).isnothrow = 1; nextToken(); @@ -2874,6 +2935,12 @@ if (peek(&token).value == TOK.TOKlparen) break; stc = STC.STCshared; + goto L1; + + case TOKwild: + if (peek(&token).value == TOK.TOKlparen) + break; + stc = STC.STCwild; goto L1; case TOK.TOKstatic: stc = STC.STCstatic; goto L1; @@ -3334,6 +3401,7 @@ version (DMDV2) { case TOK.TOKimmutable: case TOK.TOKshared: + case TOKwild: case TOK.TOKnothrow: case TOK.TOKpure: case TOK.TOKtls: @@ -3526,7 +3594,11 @@ Type at; StorageClass storageClass = STC.STCundefined; - if (token.value == TOK.TOKinout || token.value == TOK.TOKref) + if (token.value == TOKref +//#if D1INOUT +// || token.value == TOKinout +//#endif + ) { storageClass = STC.STCref; nextToken(); } @@ -4374,12 +4446,14 @@ if ((t.value == TOK.TOKconst || t.value == TOK.TOKinvariant || t.value == TOK.TOKimmutable || + t.value == TOKwild || t.value == TOK.TOKshared) && peek(t).value != TOK.TOKlparen) { /* const type * immutable type * shared type + * wild type */ t = peek(t); } @@ -4538,7 +4612,8 @@ case TOK.TOKinvariant: case TOK.TOKimmutable: case TOK.TOKshared: - // const(type) or immutable(type) or shared(type) + case TOKwild: + // const(type) or immutable(type) or shared(type) or wild(type) t = peek(t); if (t.value != TOK.TOKlparen) goto Lfalse; @@ -4703,6 +4778,7 @@ case TOK.TOKinvariant: case TOK.TOKimmutable: case TOK.TOKshared: + case TOKwild: case TOK.TOKpure: case TOK.TOKnothrow: t = peek(t); @@ -4763,18 +4839,22 @@ t = peek(t); break; +version(D1INOUT) { + case TOKinout: +} case TOKin: case TOKout: - case TOKinout: case TOKref: case TOKlazy: case TOKfinal: + case TOKauto: continue; case TOKconst: case TOKinvariant: case TOKimmutable: case TOKshared: + case TOKwild: t = peek(t); if (t.value == TOKlparen) { @@ -5287,6 +5367,7 @@ token.value == TOK.TOKinvariant && peek(&token).value == TOK.TOKrparen || token.value == TOK.TOKimmutable && peek(&token).value == TOK.TOKrparen || token.value == TOK.TOKshared && peek(&token).value == TOK.TOKrparen || + token.value == TOKwild && peek(&token).value == TOKrparen || ///} token.value == TOK.TOKfunction || token.value == TOK.TOKdelegate || @@ -5581,7 +5662,7 @@ nextToken(); check(TOK.TOKlparen); /* Look for cast(), cast(const), cast(immutable), - * cast(shared), cast(shared const) + * cast(shared), cast(shared const), cast(wild), cast(shared wild) */ MOD m; if (token.value == TOK.TOKrparen) @@ -5596,7 +5677,7 @@ } else if ((token.value == TOK.TOKimmutable || token.value == TOK.TOKinvariant) && peekNext() == TOK.TOKrparen) { - m = MOD.MODinvariant; + m = MOD.MODimmutable; goto Lmod2; } else if (token.value == TOK.TOKshared && peekNext() == TOK.TOKrparen) @@ -5604,10 +5685,22 @@ m = MOD.MODshared; goto Lmod2; } + else if (token.value == TOKwild && peekNext() == TOK.TOKrparen) + { + m = MODwild; + goto Lmod2; + } + else if (token.value == TOKwild && peekNext() == TOK.TOKshared && peekNext2() == TOK.TOKrparen || + token.value == TOK.TOKshared && peekNext() == TOKwild && peekNext2() == TOK.TOKrparen) + { + m = MOD.MODshared | MOD.MODwild; + goto Lmod3; + } else if (token.value == TOK.TOKconst && peekNext() == TOK.TOKshared && peekNext2() == TOK.TOKrparen || token.value == TOK.TOKshared && peekNext() == TOK.TOKconst && peekNext2() == TOK.TOKrparen) { m = MOD.MODshared | MOD.MODconst; + Lmod3: nextToken(); Lmod2: nextToken(); @@ -5734,6 +5827,15 @@ break; } assert(e); + + // ^^ is right associative and has higher precedence than the unary operators + while (token.value == TOK.TOKpow) + { + nextToken(); + Expression e2 = parseUnaryExp(); + e = new PowExp(loc, e, e2); + } + return e; } @@ -5862,7 +5964,6 @@ case TOK.TOKmul: nextToken(); e2 = parseUnaryExp(); e = new MulExp(loc,e,e2); continue; case TOK.TOKdiv: nextToken(); e2 = parseUnaryExp(); e = new DivExp(loc,e,e2); continue; case TOK.TOKmod: nextToken(); e2 = parseUnaryExp(); e = new ModExp(loc,e,e2); continue; - case TOK.TOKpow: nextToken(); e2 = parseUnaryExp(); e = new PowExp(loc,e,e2); continue; default: break; @@ -6129,7 +6230,7 @@ case TOK.TOKmulass: nextToken(); e2 = parseAssignExp(); e = new MulAssignExp(loc,e,e2); continue; case TOK.TOKdivass: nextToken(); e2 = parseAssignExp(); e = new DivAssignExp(loc,e,e2); continue; case TOK.TOKmodass: nextToken(); e2 = parseAssignExp(); e = new ModAssignExp(loc,e,e2); continue; -// case TOK.TOKpowass: nextToken(); e2 = parseAssignExp(); e = new PowAssignExp(loc,e,e2); continue; + case TOK.TOKpowass: nextToken(); e2 = parseAssignExp(); e = new PowAssignExp(loc,e,e2); continue; case TOK.TOKandass: nextToken(); e2 = parseAssignExp(); e = new AndAssignExp(loc,e,e2); continue; case TOK.TOKorass: nextToken(); e2 = parseAssignExp(); e = new OrAssignExp(loc,e,e2); continue; case TOK.TOKxorass: nextToken(); e2 = parseAssignExp(); e = new XorAssignExp(loc,e,e2); continue; diff -r 4251f96733f4 -r af1bebfd96a4 dmd/PowAssignExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/PowAssignExp.d Mon Sep 13 22:19:42 2010 +0100 @@ -0,0 +1,77 @@ +module dmd.PowAssignExp; + +import dmd.BinExp; +import dmd.Scope; +import dmd.Loc; +import dmd.Identifier; +import dmd.Expression; +import dmd.TOK; +import dmd.STC; +import dmd.PowExp; +import dmd.AssignExp; +import dmd.Lexer; +import dmd.VarDeclaration; +import dmd.ExpInitializer; +import dmd.DeclarationExp; +import dmd.VarExp; +import dmd.CommaExp; +import dmd.ErrorExp; +import dmd.Id; + +// Only a reduced subset of operations for now. +class PowAssignExp : BinExp +{ + this(Loc loc, Expression e1, Expression e2) + { + super(loc, TOK.TOKpowass, PowAssignExp.sizeof, e1, e2); + } + + override Expression semantic(Scope sc) + { + Expression e; + + if (type) + return this; + + BinExp.semantic(sc); + e2 = resolveProperties(sc, e2); + + e = op_overload(sc); + if (e) + return e; + + e1 = e1.modifiableLvalue(sc, e1); + assert(e1.type && e2.type); + + if ( (e1.type.isintegral() || e1.type.isfloating()) && + (e2.type.isintegral() || e2.type.isfloating())) + { + if (e1.op == TOKvar) + { // Rewrite: e1 = e1 ^^ e2 + e = new PowExp(loc, e1.syntaxCopy(), e2); + e = new AssignExp(loc, e1, e); + } + else + { // Rewrite: ref tmp = e1; tmp = tmp ^^ e2 + Identifier id = Lexer.uniqueId("__powtmp"); + auto v = new VarDeclaration(e1.loc, e1.type, id, new ExpInitializer(loc, e1)); + v.storage_class |= STC.STCref | STC.STCforeach; + Expression de = new DeclarationExp(e1.loc, v); + VarExp ve = new VarExp(e1.loc, v); + e = new PowExp(loc, ve, e2); + e = new AssignExp(loc, new VarExp(e1.loc, v), e); + e = new CommaExp(loc, de, e); + } + e = e.semantic(sc); + return e; + } + error("%s ^^= %s is not supported", e1.type.toChars(), e2.type.toChars() ); + return new ErrorExp(); + } + + // For operator overloading + Identifier opId() + { + return Id.powass; + } +}; \ No newline at end of file diff -r 4251f96733f4 -r af1bebfd96a4 dmd/PowExp.d --- a/dmd/PowExp.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/PowExp.d Mon Sep 13 22:19:42 2010 +0100 @@ -12,6 +12,18 @@ import dmd.DotIdExp; import dmd.CallExp; import dmd.ErrorExp; +import dmd.CommaExp; +import dmd.AndExp; +import dmd.CondExp; +import dmd.IntegerExp; +import dmd.Type; +import dmd.Lexer; +import dmd.VarDeclaration; +import dmd.ExpInitializer; +import dmd.VarExp; +import dmd.DeclarationExp; +import dmd.MulExp; +import dmd.WANT; version(DMDV2) { @@ -22,65 +34,121 @@ super(loc, TOK.TOKpow, PowExp.sizeof, e1, e2); } - Expression semantic(Scope sc) + override Expression semantic(Scope sc) { Expression e; if (type) return this; + //printf("PowExp::semantic() %s\n", toChars()); BinExp.semanticp(sc); e = op_overload(sc); if (e) return e; - static int importMathChecked = 0; - if (!importMathChecked) - { - importMathChecked = 1; - for (int i = 0; i < Module.amodules.dim; i++) - { - auto mi = cast(Module)Module.amodules.data[i]; - //printf("\t[%d] %s\n", i, mi->toChars()); - if (mi.ident == Id.math && - mi.parent.ident == Id.std && - !mi.parent.parent) - goto L1; - } - error("must import std.math to use ^^ operator"); - - L1: ; - } - assert(e1.type && e2.type); if ( (e1.type.isintegral() || e1.type.isfloating()) && (e2.type.isintegral() || e2.type.isfloating())) { - // For built-in numeric types, there are three cases: - // x ^^ 1 ----> x - // x ^^ 0.5 ----> sqrt(x) - // x ^^ y ----> pow(x, y) + // For built-in numeric types, there are several cases. // TODO: backend support, especially for e1 ^^ 2. + bool wantSqrt = false; + e1 = e1.optimize(0); e2 = e2.optimize(0); - if ((e2.op == TOK.TOKfloat64 && e2.toReal() == 1.0) || - (e2.op == TOK.TOKint64 && e2.toInteger() == 1)) + + // Replace 1 ^^ x or 1.0^^x by (x, 1) + if ((e1.op == TOK.TOKint64 && e1.toInteger() == 1) || + (e1.op == TOK.TOKfloat64 && e1.toReal() == 1.0)) + { + typeCombine(sc); + e = new CommaExp(loc, e2, e1); + e = e.semantic(sc); + return e; + } + // Replace -1 ^^ x by (x&1) ? -1 : 1, where x is integral + if (e2.type.isintegral() && e1.op == TOKint64 && cast(long)e1.toInteger() == -1) + { + typeCombine(sc); + Type resultType = type; + e = new AndExp(loc, e2, new IntegerExp(loc, 1, e2.type)); + e = new CondExp(loc, e, new IntegerExp(loc, -1, resultType), new IntegerExp(loc, 1, resultType)); + e = e.semantic(sc); + return e; + } + // All other negative integral powers are illegal + if ((e1.type.isintegral()) && (e2.op == TOK.TOKint64) && cast(long)e2.toInteger() < 0) { - return e1; // Replace x ^^ 1 with x. + error("cannot raise %s to a negative integer power. Did you mean (cast(real)%s)^^%s ?", + e1.type.toBasetype().toChars(), e1.toChars(), e2.toChars()); + return new ErrorExp(); + } + + // Deal with x^^2, x^^3 immediately, since they are of practical importance. + // Don't bother if x is a literal, since it will be constant-folded anyway. + if ( ( (e2.op == TOK.TOKint64 && (e2.toInteger() == 2 || e2.toInteger() == 3)) + || (e2.op == TOK.TOKfloat64 && (e2.toReal() == 2.0 || e2.toReal() == 3.0)) + ) && (e1.op == TOK.TOKint64 || e1.op == TOK.TOKfloat64) + ) + { + typeCombine(sc); + // Replace x^^2 with (tmp = x, tmp*tmp) + // Replace x^^3 with (tmp = x, tmp*tmp*tmp) + Identifier idtmp = Lexer.uniqueId("__tmp"); + VarDeclaration tmp = new VarDeclaration(loc, e1.type.toBasetype(), idtmp, new ExpInitializer(Loc(0), e1)); + VarExp ve = new VarExp(loc, tmp); + Expression ae = new DeclarationExp(loc, tmp); + Expression me = new MulExp(loc, ve, ve); + if ( (e2.op == TOK.TOKint64 && e2.toInteger() == 3) + || (e2.op == TOK.TOKfloat64 && e2.toReal() == 3.0)) + me = new MulExp(loc, me, ve); + e = new CommaExp(loc, ae, me); + e = e.semantic(sc); + return e; } - e = new IdentifierExp(loc, Id.empty); - e = new DotIdExp(loc, e, Id.std); - e = new DotIdExp(loc, e, Id.math); - if (e2.op == TOKfloat64 && e2.toReal() == 0.5) - { // Replace e1 ^^ 0.5 with .std.math.sqrt(x) - e = new CallExp(loc, new DotIdExp(loc, e, Id._sqrt), e1); + static int importMathChecked = 0; + if (!importMathChecked) + { + importMathChecked = 1; + for (int i = 0; i < Module.amodules.dim; i++) + { + auto mi = cast(Module)Module.amodules.data[i]; + //printf("\t[%d] %s\n", i, mi->toChars()); + if (mi.ident == Id.math && + mi.parent.ident == Id.std && + !mi.parent.parent) + goto L1; + } + error("must import std.math to use ^^ operator"); + + L1: ; } - else - { // Replace e1 ^^ e2 with .std.math.pow(e1, e2) - e = new CallExp(loc, new DotIdExp(loc, e, Id._pow), e1, e2); - } - e = e.semantic(sc); + + e = new IdentifierExp(loc, Id.empty); + e = new DotIdExp(loc, e, Id.std); + e = new DotIdExp(loc, e, Id.math); + if (e2.op == TOK.TOKfloat64 && e2.toReal() == 0.5) + { // Replace e1 ^^ 0.5 with .std.math.sqrt(x) + typeCombine(sc); + e = new CallExp(loc, new DotIdExp(loc, e, Id._sqrt), e1); + } + else + { + // Replace e1 ^^ e2 with .std.math.pow(e1, e2) + // We don't combine the types if raising to an integer power (because + // integer powers are treated specially by std.math.pow). + if (!e2.type.isintegral()) + typeCombine(sc); + e = new CallExp(loc, new DotIdExp(loc, e, Id._pow), e1, e2); + } + e = e.semantic(sc); + // Always constant fold integer powers of literals. This will run the interpreter + // on .std.math.pow + if ((e1.op == TOK.TOKfloat64 || e1.op == TOK.TOKint64) && (e2.op == TOK.TOKint64)) + e = e.optimize(WANT.WANTvalue | WANT.WANTinterpret); + return e; } error("%s ^^ %s is not supported", e1.type.toChars(), e2.type.toChars() ); @@ -89,12 +157,12 @@ // For operator overloading - Identifier opId() + override Identifier opId() { return Id.pow; } - Identifier opId_r() + override Identifier opId_r() { return Id.pow_r; } diff -r 4251f96733f4 -r af1bebfd96a4 dmd/PtrExp.d --- a/dmd/PtrExp.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/PtrExp.d Mon Sep 13 22:19:42 2010 +0100 @@ -85,7 +85,12 @@ { return 1; } - + + override void checkEscapeRef() + { + e1.checkEscape(); + } + override Expression toLvalue(Scope sc, Expression e) { static if (false) { diff -r 4251f96733f4 -r af1bebfd96a4 dmd/ReturnStatement.d --- a/dmd/ReturnStatement.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/ReturnStatement.d Mon Sep 13 22:19:42 2010 +0100 @@ -35,6 +35,7 @@ import dmd.VarDeclaration; import dmd.GlobalExpressions; import dmd.BE; +import dmd.Global; import dmd.codegen.Util; @@ -173,14 +174,46 @@ if (fd.returnLabel && tbret.ty != TY.Tvoid) { ; } else if (fd.inferRetType) { - if (fd.type.nextOf()) { - if (!exp.type.equals(fd.type.nextOf())) - error("mismatched function return type inference of %s and %s", exp.type.toChars(), fd.type.nextOf().toChars()); + auto tf = cast(TypeFunction)fd.type; + assert(tf.ty == TY.Tfunction); + Type tfret = tf.nextOf(); + if (tfret) + { + if (!exp.type.equals(tfret)) + error("mismatched function return type inference of %s and %s", exp.type.toChars(), tfret.toChars()); + /* The "refness" is determined by the first return statement, + * not all of them. This means: + * return 3; return x; // ok, x can be a value + * return x; return 3; // error, 3 is not an lvalue + */ } else { - (cast(TypeFunction)fd.type).next = exp.type; - fd.type = fd.type.semantic(loc, sc); + if (tf.isref) + { /* Determine "refness" of function return: + * if it's an lvalue, return by ref, else return by value + */ + if (exp.isLvalue()) + { + /* Return by ref + * (but first ensure it doesn't fail the "check for + * escaping reference" test) + */ + uint errors = global.errors; + global.gag++; + exp.checkEscapeRef(); + global.gag--; + if (errors != global.errors) + { tf.isref = false; // return by value + global.errors = errors; + } + } + else + tf.isref = false; // return by value + } + tf.next = exp.type; + fd.type = tf.semantic(loc, sc); + if (!fd.tintro) { tret = fd.type.nextOf(); @@ -290,19 +323,14 @@ else exp = exp.toLvalue(sc, exp); - if (exp.op == TOK.TOKvar) - { - VarExp ve = cast(VarExp)exp; - VarDeclaration v = ve.var.isVarDeclaration(); - if (v && !v.isDataseg() && !(v.storage_class & (STC.STCref | STC.STCout))) { - error("escaping reference to local variable %s", v.toChars()); - } - } + exp.checkEscapeRef(); } - - //exp.dump(0); - //exp.print(); - exp.checkEscape(); + else + { + //exp.dump(0); + //exp.print(); + exp.checkEscape(); + } } /* BUG: need to issue an error on: diff -r 4251f96733f4 -r af1bebfd96a4 dmd/STC.d --- a/dmd/STC.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/STC.d Mon Sep 13 22:19:42 2010 +0100 @@ -23,7 +23,6 @@ STCctorinit = 0x20000, // can only be set inside constructor STCtemplateparameter = 0x40000, // template parameter STCscope = 0x80000, // template parameter - STCinvariant = 0x100000, STCimmutable = 0x100000, STCref = 0x200000, STCinit = 0x400000, // has explicit initializer @@ -36,7 +35,8 @@ STCshared = 0x20000000, // accessible from multiple threads STCgshared = 0x40000000, // accessible from multiple threads // but not typed as "shared" - STC_TYPECTOR = (STCconst | STCimmutable | STCshared), + STCwild = 0x80000000, // for "wild" type constructor + STC_TYPECTOR = (STCconst | STCimmutable | STCshared | STCwild), } import dmd.EnumUtils; @@ -46,5 +46,6 @@ enum STCsafe = 0x200000000; enum STCtrusted = 0x400000000; enum STCsystem = 0x800000000; +enum STCctfe = 0x1000000000; // can be used in CTFE, even if it is static alias ulong StorageClass; \ No newline at end of file diff -r 4251f96733f4 -r af1bebfd96a4 dmd/Scope.d --- a/dmd/Scope.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/Scope.d Mon Sep 13 22:19:42 2010 +0100 @@ -137,6 +137,7 @@ this.sd = null; this.sw = enclosing.sw; this.tf = enclosing.tf; + this.tinst = enclosing.tinst; this.tinst = enclosing.tinst; this.sbreak = enclosing.sbreak; this.scontinue = enclosing.scontinue; diff -r 4251f96733f4 -r af1bebfd96a4 dmd/SliceExp.d --- a/dmd/SliceExp.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/SliceExp.d Mon Sep 13 22:19:42 2010 +0100 @@ -265,6 +265,11 @@ { e1.checkEscape(); } + + override void checkEscapeRef() + { + e1.checkEscapeRef(); + } version (DMDV2) { override int isLvalue() diff -r 4251f96733f4 -r af1bebfd96a4 dmd/StaticAssert.d --- a/dmd/StaticAssert.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/StaticAssert.d Mon Sep 13 22:19:42 2010 +0100 @@ -68,12 +68,11 @@ else error("(%s) is false", exp.toChars()); - if(sc.tinst) + if (sc.tinst) sc.tinst.printInstantiationTrace(); - if (!global.gag) { + if (!global.gag) fatal(); - } } else if (!e.isBool(true)) { diff -r 4251f96733f4 -r af1bebfd96a4 dmd/StructDeclaration.d --- a/dmd/StructDeclaration.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/StructDeclaration.d Mon Sep 13 22:19:42 2010 +0100 @@ -207,7 +207,22 @@ sc2.protection = PROT.PROTpublic; sc2.explicitProtection = 0; - int members_dim = members.dim; + + /* Set scope so if there are forward references, we still might be able to + * resolve individual members like enums. + */ + foreach (s; members) + { + /* There are problems doing this in the general case because + * Scope keeps track of things like 'offset' + */ + if (s.isEnumDeclaration() || (s.isAggregateDeclaration() && s.ident)) + { + //printf("setScope %s %s\n", s->kind(), s->toChars()); + s.setScope(sc2); + } + } + foreach(Dsymbol s; members) { s.semantic(sc2); @@ -412,6 +427,22 @@ } } + Dsymbol search(Loc loc, Identifier ident, int flags) + { + //printf("%s.StructDeclaration::search('%s')\n", toChars(), ident->toChars()); + + if (scope_) + semantic(scope_); + + if (!members || !symtab) + { + error("is forward referenced when looking for '%s'", ident.toChars()); + return null; + } + + return ScopeDsymbol.search(loc, ident, flags); + } + override void toCBuffer(OutBuffer buf, HdrGenState* hgs) { assert(false); diff -r 4251f96733f4 -r af1bebfd96a4 dmd/StructInitializer.d --- a/dmd/StructInitializer.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/StructInitializer.d Mon Sep 13 22:19:42 2010 +0100 @@ -78,7 +78,6 @@ override Initializer semantic(Scope sc, Type t) { - TypeStruct ts; int errors = 0; //printf("StructInitializer.semantic(t = %s) %s\n", t.toChars(), toChars()); @@ -86,12 +85,14 @@ t = t.toBasetype(); if (t.ty == Tstruct) { - uint i; uint fieldi = 0; - ts = cast(TypeStruct)t; + auto ts = cast(TypeStruct)t; ad = ts.sym; - for (i = 0; i < field.dim; i++) + if (ad.ctor) + error("%s %s has constructors, cannot use { initializers }, use %s( initializers ) instead", + ad.kind(), ad.toChars(), ad.toChars()); + for (size_t i = 0; i < field.dim; i++) { Identifier id = field[i]; Initializer val = value[i]; diff -r 4251f96733f4 -r af1bebfd96a4 dmd/StructLiteralExp.d --- a/dmd/StructLiteralExp.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/StructLiteralExp.d Mon Sep 13 22:19:42 2010 +0100 @@ -157,8 +157,7 @@ } else { - e = v.type.defaultInit(Loc(0)); - e.loc = loc; + e = v.type.defaultInitLiteral(loc); } offset = v.offset + cast(uint)v.type.size(); } @@ -660,7 +659,7 @@ te = te.mutableOf(); else { - assert(t.mod == MODinvariant); + assert(t.mod == MODimmutable); te = te.invariantOf(); } MATCH m2 = e.implicitConvTo(te); diff -r 4251f96733f4 -r af1bebfd96a4 dmd/SwitchStatement.d --- a/dmd/SwitchStatement.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/SwitchStatement.d Mon Sep 13 22:19:42 2010 +0100 @@ -412,7 +412,7 @@ block_appendexp(mystate.switchBlock, econd); block_next(blx,BCswitch,null); - /// + // Corresponding free is in block_free targ_llong* pu = cast(targ_llong*) malloc(targ_llong.sizeof * (numcases + 1)); mystate.switchBlock.Bswitch = pu; /* First pair is the number of cases, and the default block diff -r 4251f96733f4 -r af1bebfd96a4 dmd/SymOffExp.d --- a/dmd/SymOffExp.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/SymOffExp.d Mon Sep 13 22:19:42 2010 +0100 @@ -20,6 +20,7 @@ import dmd.ErrorExp; import dmd.TY; import dmd.TOK; +import dmd.STC; import dmd.backend.Symbol; import dmd.backend.Util; @@ -58,14 +59,14 @@ VarDeclaration v = var.isVarDeclaration(); if (v) { - if (!v.isDataseg()) + if (!v.isDataseg() && !(v.storage_class & (STC.STCref | STC.STCout))) { /* BUG: This should be allowed: * void foo() * { int a; * int* bar() { return &a; } * } */ - error("escaping reference to local variable %s", v.toChars()); + error("escaping reference to local %s", v.toChars()); } } } diff -r 4251f96733f4 -r af1bebfd96a4 dmd/TOK.d --- a/dmd/TOK.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/TOK.d Mon Sep 13 22:19:42 2010 +0100 @@ -127,7 +127,7 @@ TOKshared, TOKat, TOKpow, - //TOKpowass, + TOKpowass, TOKMAX } @@ -251,5 +251,7 @@ } } +alias TOK.TOKinout TOKwild; + import dmd.EnumUtils; mixin(BringToCurrentScope!(TOK)); \ No newline at end of file diff -r 4251f96733f4 -r af1bebfd96a4 dmd/TemplateDeclaration.d --- a/dmd/TemplateDeclaration.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/TemplateDeclaration.d Mon Sep 13 22:19:42 2010 +0100 @@ -797,21 +797,7 @@ } } - if (fd.type) - { - assert(fd.type.ty == Tfunction); - TypeFunction fdtype = cast(TypeFunction)fd.type; - fparameters = fdtype.parameters; - fvarargs = fdtype.varargs; - } - else - { - CtorDeclaration fctor = fd.isCtorDeclaration(); - assert(fctor); - fparameters = fctor.arguments; - fvarargs = fctor.varargs; - } - + fparameters = fd.getParameters(&fvarargs); nfparams = Parameter.dim(fparameters); // number of function parameters nfargs = fargs ? fargs.dim : 0; // number of function arguments @@ -1258,7 +1244,7 @@ */ assert(cast(size_t)cast(void*)td_best.scope_ > 0x10000); ti = new TemplateInstance(loc, td_best, tdargs); - ti.semantic(sc); + ti.semantic(sc, fargs); fd = ti.toAlias().isFuncDeclaration(); if (!fd) goto Lerror; @@ -1390,21 +1376,8 @@ if (fd) { paramscope.parent = fd; - Parameters fparameters; // function parameter list int fvarargs; // function varargs - if (fd.type) - { - assert(fd.type.ty == Tfunction); - TypeFunction fdtype = cast(TypeFunction )fd.type; - fparameters = fdtype.parameters; - fvarargs = fdtype.varargs; - } - else // Constructors don't have type's - { CtorDeclaration fctor = fd.isCtorDeclaration(); - assert(fctor); - fparameters = fctor.arguments; - fvarargs = fctor.varargs; - } + Parameters fparameters = fd.getParameters(&fvarargs); size_t nfparams = Parameter.dim(fparameters); // Num function parameters for (int i = 0; i < nfparams; i++) { diff -r 4251f96733f4 -r af1bebfd96a4 dmd/TemplateInstance.d --- a/dmd/TemplateInstance.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/TemplateInstance.d Mon Sep 13 22:19:42 2010 +0100 @@ -40,6 +40,7 @@ import dmd.TypeFunction; import dmd.TemplateTupleParameter; import dmd.FuncDeclaration; +import dmd.OverloadSet; import dmd.templates.Util; import dmd.backend.glue; @@ -263,6 +264,11 @@ override void semantic(Scope sc) { + semantic(sc, null); + } + + void semantic(Scope sc, Expressions fargs) + { if (global.errors) { if (!global.gag) @@ -364,6 +370,34 @@ if (!match(o1, o2, tempdecl, sc)) { goto L1; + } + } + + /* Template functions may have different instantiations based on + * "auto ref" parameters. + */ + if (fargs) + { + FuncDeclaration fd = ti.toAlias().isFuncDeclaration(); + if (fd) + { + auto fparameters = fd.getParameters(null); + size_t nfparams = Parameter.dim(fparameters); // Num function parameters + for (int i = 0; i < nfparams && i < fargs.dim; i++) + { auto fparam = Parameter.getNth(fparameters, i); + auto farg = fargs[i]; + if (fparam.storageClass & STCauto) // if "auto ref" + { + if (farg.isLvalue()) + { if (!(fparam.storageClass & STC.STCref)) + goto L1; // auto ref's don't match + } + else + { if (fparam.storageClass & STC.STCref) + goto L1; // auto ref's don't match + } + } + } } } @@ -514,6 +548,22 @@ } } } + + /* If function template declaration + */ + if (fargs && aliasdecl) + { + FuncDeclaration fd = aliasdecl.toAlias().isFuncDeclaration(); + if (fd) + { + /* Transmit fargs to type so that TypeFunction::semantic() can + * resolve any "auto ref" storage classes. + */ + auto tf = cast(TypeFunction)fd.type; + if (tf && tf.ty == TY.Tfunction) + tf.fargs = fargs; + } + } // Do semantic() analysis on template instance members version (LOG) { @@ -610,10 +660,9 @@ if (global.errors != errorsave) { error("error instantiating"); - if (tinst && !global.gag) + if (tinst) { tinst.printInstantiationTrace(); - fatal(); } errors = 1; if (global.gag) @@ -832,10 +881,82 @@ return id; } + /************************************** + * Given an error instantiating the TemplateInstance, + * give the nested TemplateInstance instantiations that got + * us here. Those are a list threaded into the nested scopes. + */ void printInstantiationTrace() { if (global.gag) - return; + return; +/+ + const int max_shown = 6; + const string format = "%s: instantiated from here: %s\n"; + + // determine instantiation depth and number of recursive instantiations + int n_instantiations = 1; + int n_totalrecursions = 0; + for (TemplateInstance cur = this; cur; cur = cur.tinst) + { + ++n_instantiations; + // If two instantiations use the same declaration, they are recursive. + // (this works even if they are instantiated from different places in the + // same template). + // In principle, we could also check for multiple-template recursion, but it's + // probably not worthwhile. + if (cur.tinst && cur.tempdecl && cur.tinst.tempdecl + && cur.tempdecl.loc.equals(cur.tinst.tempdecl.loc)) + ++n_totalrecursions; + } + + // show full trace only if it's short or verbose is on + if (n_instantiations <= max_shown || global.params.verbose) + { + for (TemplateInstance cur = this; cur; cur = cur.tinst) + { + fprintf(stdmsg, format, cur.loc.toChars(), cur.toChars()); + } + } + else if (n_instantiations - n_totalrecursions <= max_shown) + { + // By collapsing recursive instantiations into a single line, + // we can stay under the limit. + int recursionDepth=0; + for (TemplateInstance cur = this; cur; cur = cur.tinst) + { + if (cur.tinst && cur.tempdecl && cur.tinst.tempdecl + && cur.tempdecl.loc.equals(cur.tinst.tempdecl.loc)) + { + ++recursionDepth; + } + else + { + if (recursionDepth) + fprintf(stdmsg, "%s: %d recursive instantiations from here: %s\n", cur.loc.toChars(), recursionDepth+2, cur.toChars()); + else + fprintf(stdmsg,format, cur.loc.toChars(), cur.toChars()); + recursionDepth = 0; + } + } + } + else + { + // Even after collapsing the recursions, the depth is too deep. + // Just display the first few and last few instantiations. + size_t i = 0; + for (TemplateInstance cur = this; cur; cur = cur.tinst) + { + if (i == max_shown / 2) + fprintf(stdmsg," ... (%d instantiations, -v to show) ...\n", n_instantiations - max_shown); + + if (i < max_shown / 2 || + i >= n_instantiations - max_shown + max_shown / 2) + fprintf(stdmsg, format, cur.loc.toChars(), cur.toChars()); + ++i; + } + } ++/ } override void toObjFile(int multiobj) // compile to .obj file @@ -1024,9 +1145,32 @@ s = sc.search(loc, id, &scopesym); if (!s) { - error("identifier '%s' is not defined", id.toChars()); + error("template '%s' is not defined", id.toChars()); return null; } + + /* If an OverloadSet, look for a unique member that is a template declaration + */ + OverloadSet os = s.isOverloadSet(); + if (os) + { + s = null; + foreach (s2; os.a) + { + if (s2.isTemplateDeclaration()) + { + if (s) + error("ambiguous template declaration %s and %s", s.toPrettyChars(), s2.toPrettyChars()); + s = s2; + } + } + if (!s) + { + error("template '%s' is not defined", id.toChars()); + return null; + } + } + version (LOG) { printf("It's an instance of '%s' kind '%s'\n", s.toChars(), s.kind()); if (s.parent) diff -r 4251f96733f4 -r af1bebfd96a4 dmd/TraitsExp.d --- a/dmd/TraitsExp.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/TraitsExp.d Mon Sep 13 22:19:42 2010 +0100 @@ -31,6 +31,7 @@ import dmd.TemplateDeclaration; import dmd.TemplateInstance; import dmd.TypeClass; +import dmd.Declaration; import dmd.Util; import dmd.expression.Util; @@ -92,6 +93,7 @@ TemplateInstance.semanticTiargs(loc, sc, args, 1); size_t dim = args ? args.dim : 0; Object o; + Declaration d; FuncDeclaration f; string ISTYPE(string cond) @@ -172,6 +174,20 @@ { mixin(ISDSYMBOL(q{(f = s.isFuncDeclaration()) !is null && f.isFinal()})); } +//version(DMDV2) { + else if (ident == Id.isRef) + { + mixin(ISDSYMBOL(q{(d = s.isDeclaration()) !is null && d.isRef()})); + } + else if (ident == Id.isOut) + { + mixin(ISDSYMBOL(q{(d = s.isDeclaration()) !is null && d.isOut()})); + } + else if (ident == Id.isLazy) + { + mixin(ISDSYMBOL(q{(d = s.isDeclaration()) !is null && d.storage_class & STClazy})); + } +//} else if (ident == Id.hasMember || ident == Id.getMember || ident == Id.getVirtualFunctions) diff -r 4251f96733f4 -r af1bebfd96a4 dmd/Type.d --- a/dmd/Type.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/Type.d Mon Sep 13 22:19:42 2010 +0100 @@ -59,6 +59,8 @@ import dmd.DotIdExp; import dmd.AggregateDeclaration; import dmd.DotTemplateInstanceExp; +import dmd.Token; +import dmd.TypeInfoWildDeclaration; import dmd.expression.Util; @@ -127,6 +129,102 @@ return -1; } +/*************************** + * Return !=0 if modfrom can be implicitly converted to modto + */ +int MODimplicitConv(MOD modfrom, MOD modto) +{ + if (modfrom == modto) + return 1; + + //printf("MODimplicitConv(from = %x, to = %x)\n", modfrom, modto); + static uint X(MOD m, MOD n) + { + return (((m) << 4) | (n)); + } + switch (X(modfrom, modto)) + { + case X(MOD.MODundefined, MOD.MODconst): + case X(MOD.MODimmutable, MOD.MODconst): + case X(MOD.MODwild, MOD.MODconst): + case X(MOD.MODimmutable, MOD.MODconst | MOD.MODshared): + case X(MOD.MODshared, MOD.MODconst | MOD.MODshared): + case X(MOD.MODwild | MOD.MODshared, MOD.MODconst | MOD.MODshared): + return 1; + + default: + return 0; + } +} + +/********************************* + * Mangling for mod. + */ +void MODtoDecoBuffer(OutBuffer buf, MOD mod) +{ + switch (mod) + { + case MOD.MODundefined: + break; + case MOD.MODconst: + buf.writeByte('x'); + break; + case MOD.MODimmutable: + buf.writeByte('y'); + break; + case MOD.MODshared: + buf.writeByte('O'); + break; + case MOD.MODshared | MOD.MODconst: + buf.writestring("Ox"); + break; + case MOD.MODwild: + buf.writestring("Ng"); + break; + case MOD.MODshared | MOD.MODwild: + buf.writestring("ONg"); + break; + default: + assert(0); + } +} + +/********************************* + * Name for mod. + */ +void MODtoBuffer(OutBuffer buf, MOD mod) +{ + switch (mod) + { + case MOD.MODundefined: + break; + + case MOD.MODimmutable: + buf.writestring(Token.tochars[TOK.TOKimmutable]); + break; + + case MOD.MODshared: + buf.writestring(Token.tochars[TOK.TOKshared]); + break; + + case MOD.MODshared | MOD.MODconst: + buf.writestring(Token.tochars[TOK.TOKshared]); + buf.writeByte(' '); + case MOD.MODconst: + buf.writestring(Token.tochars[TOK.TOKconst]); + break; + + case MOD.MODshared | MOD.MODwild: + buf.writestring(Token.tochars[TOK.TOKshared]); + buf.writeByte(' '); + case MOD.MODwild: + buf.writestring(Token.tochars[TOKwild]); + break; + default: + assert(0); + } +} + class Type { TY ty; @@ -143,12 +241,16 @@ * They should not be referenced by anybody but mtype.c. * They can be null if not lazily evaluated yet. * Note that there is no "shared immutable", because that is just immutable + * Naked == no MOD bits */ - Type cto; // MODconst ? mutable version of this type : const version - Type ito; // MODinvariant ? mutable version of this type : invariant version - Type sto; // MODshared ? mutable version of this type : shared mutable version - Type scto; // MODshared|MODconst ? mutable version of this type : shared const version + Type cto; // MODconst ? naked version of this type : const version + Type ito; // MODimmutable ? naked version of this type : immutable version + Type sto; // MODshared ? naked version of this type : shared mutable version + Type scto; // MODshared|MODconst ? naked version of this type : shared const version + Type wto; // MODwild ? naked version of this type : wild version + Type swto; // MODshared|MODwild ? naked version of this type : shared wild version + Type pto; // merged pointer to this type Type rto; // reference to this type @@ -173,6 +275,7 @@ static ClassDeclaration typeinfoconst; static ClassDeclaration typeinfoinvariant; static ClassDeclaration typeinfoshared; + static ClassDeclaration typeinfowild; static Type basic[TY.TMAX]; static ubyte mangleChar[TY.TMAX]; @@ -493,7 +596,7 @@ * forward references. */ if ((cast(TypeClass)t1n).sym == (cast(TypeClass)t2n).sym && - t2n.mod == MOD.MODconst) + MODimplicitConv(t1n.mod, t2n.mod)) goto Lcovariant; // If t1n is forward referenced: @@ -512,6 +615,9 @@ Lcovariant: /* Can convert mutable to const */ + if (!MODimplicitConv(t2.mod, t1.mod)) + goto Lnotcovariant; +static if(false) { if (t1.mod != t2.mod) { if (!(t1.mod & MOD.MODconst) && (t2.mod & MOD.MODconst)) @@ -519,7 +625,7 @@ if (!(t1.mod & MOD.MODshared) && (t2.mod & MOD.MODshared)) goto Lnotcovariant; } - +} /* Can convert pure to impure, and nothrow to throw */ if (!t1.ispure && t2.ispure) @@ -628,6 +734,7 @@ mangleChar[TY.Twchar] = 'u'; mangleChar[TY.Tdchar] = 'w'; + // '@' shouldn't appear anywhere in the deco'd names mangleChar[TY.Tbit] = '@'; mangleChar[TY.Tinstance] = '@'; mangleChar[TY.Terror] = '@'; @@ -736,16 +843,7 @@ { if (flag != mod && flag != 0x100) { - if (mod & MOD.MODshared) - buf.writeByte('O'); - - if (mod & MOD.MODconst) - buf.writeByte('x'); - else if (mod & MOD.MODinvariant) - buf.writeByte('y'); - - // Cannot be both const and invariant - assert((mod & (MOD.MODconst | MOD.MODinvariant)) != (MOD.MODconst | MOD.MODinvariant)); + MODtoDecoBuffer(buf, mod); } buf.writeByte(mangleChar[ty]); } @@ -832,40 +930,35 @@ { if (mod != this.mod) { - string p; - if (this.mod & MOD.MODshared) - buf.writestring("shared("); + { + MODtoBuffer(buf, this.mod & MOD.MODshared); + buf.writeByte('('); + } - switch (this.mod & (MOD.MODconst | MOD.MODinvariant)) - { - case MOD.MODundefined: - toCBuffer2(buf, hgs, this.mod); - break; - case MOD.MODconst: - p = "const("; - goto L1; - case MOD.MODinvariant: - p = "immutable("; - L1: buf.writestring(p); - toCBuffer2(buf, hgs, this.mod); - buf.writeByte(')'); - break; - } - - if (this.mod & MOD.MODshared) - buf.writeByte(')'); + if (this.mod & ~MOD.MODshared) + { + MODtoBuffer(buf, this.mod & ~MOD.MODshared); + buf.writeByte('('); + toCBuffer2(buf, hgs, this.mod); + buf.writeByte(')'); + } + else + toCBuffer2(buf, hgs, this.mod); + if (this.mod & MOD.MODshared) + { + buf.writeByte(')'); + } } } void modToBuffer(OutBuffer buf) { - if (mod & MOD.MODshared) - buf.writestring(" shared"); - if (mod & MOD.MODconst) - buf.writestring(" const"); - if (mod & MOD.MODinvariant) - buf.writestring(" immutable"); + if (mod) + { + buf.writeByte(' '); + MODtoBuffer(buf, mod); + } } version (CPP_MANGLE) { @@ -948,13 +1041,20 @@ bool isConst() { return (mod & MOD.MODconst) != 0; } - int isInvariant() { return mod & MOD.MODinvariant; } + int isImmutable() { return mod & MOD.MODimmutable; } - int isMutable() { return !(mod & (MOD.MODconst | MOD.MODinvariant)); } + int isMutable() { return !(mod & (MOD.MODconst | MOD.MODimmutable | MOD.MODwild)); } int isShared() { return mod & MOD.MODshared; } int isSharedConst() { return mod == (MOD.MODshared | MOD.MODconst); } + + int isWild() { return mod & MOD.MODwild; } + + int isSharedWild() { return mod == (MOD.MODshared | MOD.MODwild); } + + int isNaked() { return mod == 0; } + /******************************** * Convert to 'const'. @@ -982,13 +1082,13 @@ Type invariantOf() { //printf("Type.invariantOf() %p %s\n", this, toChars()); - if (isInvariant()) + if (isImmutable()) { return this; } if (ito) { - assert(ito.isInvariant()); + assert(ito.isImmutable()); return ito; } Type t = makeInvariant(); @@ -1007,51 +1107,29 @@ if (isShared()) t = sto; // shared const => shared else - t = cto; + t = cto; // const => naked assert(!t || t.isMutable()); } - else if (isInvariant()) + else if (isImmutable()) { t = ito; assert(!t || (t.isMutable() && !t.isShared())); } + else if (isWild()) + { + if (isShared()) + t = sto; // shared wild => shared + else + t = wto; // wild => naked + assert(!t || t.isMutable()); + } if (!t) { - uint sz = this.classinfo.init.length; - t = cast(Type)GC.malloc(sz); - memcpy(cast(void*)t, cast(void*)this, sz); - t.mod = mod & MODshared; - t.deco = null; - t.arrayof = null; - t.pto = null; - t.rto = null; - t.cto = null; - t.ito = null; - t.sto = null; - t.scto = null; - t.vtinfo = null; + t = makeMutable(); t = t.merge(); - t.fixTo(this); - - switch (mod) - { - case MODconst: - t.cto = this; - break; - - case MODinvariant: - t.ito = this; - break; - - case MODshared | MODconst: - t.scto = this; - break; - - default: - assert(0); - } } + assert(t.isMutable()); return t; } @@ -1099,6 +1177,13 @@ /******************************** * Make type unshared. + * 0 => 0 + * const => const + * immutable => immutable + * shared => 0 + * shared const => const + * wild => wild + * shared wild => wild */ Type unSharedOf() { @@ -1109,6 +1194,8 @@ { if (isConst()) t = cto; // shared const => const + else if (isWild()) + t = wto; // shared wild => wild else t = sto; assert(!t || !t.isShared()); @@ -1128,37 +1215,68 @@ t.ito = null; t.sto = null; t.scto = null; + t.wto = null; + t.swto = null; t.vtinfo = null; t = t.merge(); t.fixTo(this); - - switch (mod) - { - case MODshared: - t.sto = this; - break; - - case MODshared | MODconst: - t.scto = this; - break; - - default: - assert(0); - } } assert(!t.isShared()); return t; } + + /******************************** + * Convert to 'wild'. + */ + + Type wildOf() + { + //printf("Type::wildOf() %p %s\n", this, toChars()); + if (mod == MOD.MODwild) + { + return this; + } + if (wto) + { + assert(wto.isWild()); + return wto; + } + Type t = makeWild(); + t = t.merge(); + t.fixTo(this); + //printf("\t%p %s\n", t, t->toChars()); + return t; + } + + Type sharedWildOf() + { + //printf("Type::sharedWildOf() %p, %s\n", this, toChars()); + if (mod == (MOD.MODwild)) + { + return this; + } + if (swto) + { + assert(swto.mod == (MOD.MODshared | MOD.MODwild)); + return swto; + } + Type t = makeSharedWild(); + t = t.merge(); + t.fixTo(this); + //printf("\t%p\n", t); + return t; + } + static uint X(MOD m, MOD n) { - return (((m) << 3) | (n)); + return (((m) << 4) | (n)); } /********************************** * For our new type 'this', which is type-constructed from t, - * fill in the cto, ito, sto, scto shortcuts. + * fill in the cto, ito, sto, scto, wto shortcuts. */ void fixTo(Type t) { @@ -1181,7 +1299,7 @@ cto = t; break; - case X(MOD.MODundefined, MOD.MODinvariant): + case X(MOD.MODundefined, MOD.MODimmutable): ito = t; break; @@ -1193,12 +1311,20 @@ scto = t; break; + case X(MOD.MODundefined, MODwild): + wto = t; + break; + + case X(MOD.MODundefined, MODshared | MODwild): + swto = t; + break; + case X(MOD.MODconst, MOD.MODundefined): cto = null; goto L2; - case X(MOD.MODconst, MOD.MODinvariant): + case X(MOD.MODconst, MOD.MODimmutable): ito = t; goto L2; @@ -1208,30 +1334,48 @@ case X(MOD.MODconst, MOD.MODshared | MOD.MODconst): scto = t; + goto L2; + + case X(MOD.MODconst, MOD.MODwild): + wto = t; + goto L2; + + case X(MOD.MODconst, MOD.MODshared | MOD.MODwild): + swto = t; L2: t.cto = this; break; - case X(MOD.MODinvariant, MOD.MODundefined): + case X(MOD.MODimmutable, MOD.MODundefined): ito = null; goto L3; - case X(MOD.MODinvariant, MOD.MODconst): + case X(MOD.MODimmutable, MOD.MODconst): cto = t; goto L3; - case X(MOD.MODinvariant, MOD.MODshared): + case X(MOD.MODimmutable, MOD.MODshared): sto = t; goto L3; - case X(MOD.MODinvariant, MOD.MODshared | MOD.MODconst): + case X(MOD.MODimmutable, MOD.MODshared | MOD.MODconst): scto = t; + goto L3; + + case X(MOD.MODimmutable, MOD.MODwild): + wto = t; + goto L3; + + case X(MOD.MODimmutable, MOD.MODshared | MOD.MODwild): + swto = t; L3: t.ito = this; if (t.cto) t.cto.ito = this; if (t.sto) t.sto.ito = this; if (t.scto) t.scto.ito = this; + if (t.wto) t.wto.ito = this; + if (t.swto) t.swto.ito = this; break; @@ -1243,12 +1387,20 @@ cto = t; goto L4; - case X(MOD.MODshared, MOD.MODinvariant): + case X(MOD.MODshared, MOD.MODimmutable): ito = t; goto L4; case X(MOD.MODshared, MOD.MODshared | MOD.MODconst): scto = t; + goto L4; + + case X(MOD.MODshared, MOD.MODwild): + wto = t; + goto L4; + + case X(MOD.MODshared, MOD.MODshared | MOD.MODwild): + swto = t; L4: t.sto = this; break; @@ -1256,21 +1408,82 @@ case X(MOD.MODshared | MOD.MODconst, MOD.MODundefined): scto = null; - break; + goto L5; case X(MOD.MODshared | MOD.MODconst, MOD.MODconst): cto = t; - break; + goto L5; - case X(MOD.MODshared | MOD.MODconst, MOD.MODinvariant): + case X(MOD.MODshared | MOD.MODconst, MOD.MODimmutable): ito = t; - break; + goto L5; + + case X(MOD.MODshared | MOD.MODconst, MOD.MODwild): + wto = t; + goto L5; case X(MOD.MODshared | MOD.MODconst, MOD.MODshared): sto = t; + goto L5; + + case X(MOD.MODshared | MOD.MODconst, MOD.MODshared | MOD.MODwild): + swto = t; L5: t.scto = this; break; + + case X(MOD.MODwild, MOD.MODundefined): + wto = null; + goto L6; + + case X(MOD.MODwild, MOD.MODconst): + cto = t; + goto L6; + + case X(MOD.MODwild, MOD.MODimmutable): + ito = t; + goto L6; + + case X(MOD.MODwild, MOD.MODshared): + sto = t; + goto L6; + + case X(MOD.MODwild, MOD.MODshared | MOD.MODconst): + scto = t; + goto L6; + + case X(MOD.MODwild, MOD.MODshared | MOD.MODwild): + swto = t; + L6: + t.wto = this; + break; + + + case X(MOD.MODshared | MOD.MODwild, MOD.MODundefined): + swto = null; + goto L7; + + case X(MOD.MODshared | MOD.MODwild, MOD.MODconst): + cto = t; + goto L7; + + case X(MOD.MODshared | MOD.MODwild, MOD.MODimmutable): + ito = t; + goto L7; + + case X(MOD.MODshared | MOD.MODwild, MOD.MODshared): + sto = t; + goto L7; + + case X(MOD.MODshared | MOD.MODwild, MOD.MODshared | MOD.MODconst): + scto = t; + goto L7; + + case X(MOD.MODshared | MOD.MODwild, MOD.MODwild): + wto = t; + L7: + t.swto = this; + break; } check(); @@ -1287,38 +1500,66 @@ { case MOD.MODundefined: if (cto) assert(cto.mod == MOD.MODconst); - if (ito) assert(ito.mod == MOD.MODinvariant); + if (ito) assert(ito.mod == MOD.MODimmutable); if (sto) assert(sto.mod == MOD.MODshared); if (scto) assert(scto.mod == (MOD.MODshared | MOD.MODconst)); + if (wto) assert(wto.mod == MOD.MODwild); + if (swto) assert(swto.mod == (MOD.MODshared | MOD.MODwild)); break; case MOD.MODconst: if (cto) assert(cto.mod == MOD.MODundefined); - if (ito) assert(ito.mod == MOD.MODinvariant); + if (ito) assert(ito.mod == MOD.MODimmutable); if (sto) assert(sto.mod == MOD.MODshared); if (scto) assert(scto.mod == (MOD.MODshared | MOD.MODconst)); + if (wto) assert(wto.mod == MOD.MODwild); + if (swto) assert(swto.mod == (MOD.MODshared | MOD.MODwild)); break; - case MOD.MODinvariant: + case MOD.MODimmutable: if (cto) assert(cto.mod == MOD.MODconst); if (ito) assert(ito.mod == MOD.MODundefined); if (sto) assert(sto.mod == MOD.MODshared); if (scto) assert(scto.mod == (MOD.MODshared | MOD.MODconst)); + if (wto) assert(wto.mod == MOD.MODwild); + if (swto) assert(swto.mod == (MOD.MODshared | MOD.MODwild)); break; case MOD.MODshared: if (cto) assert(cto.mod == MOD.MODconst); - if (ito) assert(ito.mod == MOD.MODinvariant); + if (ito) assert(ito.mod == MOD.MODimmutable); if (sto) assert(sto.mod == MOD.MODundefined); if (scto) assert(scto.mod == (MOD.MODshared | MOD.MODconst)); + if (wto) assert(wto.mod == MOD.MODwild); + if (swto) assert(swto.mod == (MOD.MODshared | MOD.MODwild)); break; case MOD.MODshared | MOD.MODconst: if (cto) assert(cto.mod == MOD.MODconst); - if (ito) assert(ito.mod == MOD.MODinvariant); + if (ito) assert(ito.mod == MOD.MODimmutable); if (sto) assert(sto.mod == MOD.MODshared); if (scto) assert(scto.mod == MOD.MODundefined); + if (wto) assert(wto.mod == MOD.MODwild); + if (swto) assert(swto.mod == (MOD.MODshared | MOD.MODwild)); break; + + case MOD.MODwild: + if (cto) assert(cto.mod == MOD.MODconst); + if (ito) assert(ito.mod == MOD.MODimmutable); + if (sto) assert(sto.mod == MOD.MODshared); + if (scto) assert(scto.mod == (MOD.MODshared | MOD.MODconst)); + if (wto) assert(wto.mod == MOD.MODundefined); + if (swto) assert(swto.mod == (MOD.MODshared | MOD.MODwild)); + break; + + case MOD.MODshared | MOD.MODwild: + if (cto) assert(cto.mod == MOD.MODconst); + if (ito) assert(ito.mod == MOD.MODimmutable); + if (sto) assert(sto.mod == MOD.MODshared); + if (scto) assert(scto.mod == (MOD.MODshared | MOD.MODconst)); + if (wto) assert(wto.mod == MOD.MODwild); + if (swto) assert(swto.mod == MOD.MODundefined); + break; } Type tn = nextOf(); @@ -1331,19 +1572,27 @@ break; case MOD.MODconst: - assert(tn.mod & MOD.MODinvariant || tn.mod & MOD.MODconst); + assert(tn.mod & MOD.MODimmutable || tn.mod & MOD.MODconst); break; - case MOD.MODinvariant: - assert(tn.mod == MOD.MODinvariant); + case MOD.MODimmutable: + assert(tn.mod == MOD.MODimmutable); break; case MOD.MODshared: - assert(tn.mod & MOD.MODinvariant || tn.mod & MOD.MODshared); + assert(tn.mod & MOD.MODimmutable || tn.mod & MOD.MODshared); break; case MOD.MODshared | MOD.MODconst: - assert(tn.mod & MOD.MODinvariant || tn.mod & (MOD.MODshared | MOD.MODconst)); + assert(tn.mod & MOD.MODimmutable || tn.mod & (MOD.MODshared | MOD.MODconst)); + break; + + case MOD.MODwild: + assert(tn.mod); + break; + + case MOD.MODshared | MOD.MODwild: + assert(tn.mod == MOD.MODimmutable || tn.mod == (MOD.MODshared | MOD.MODconst) || tn.mod == (MOD.MODshared | MOD.MODwild)); break; } tn.check(); @@ -1360,23 +1609,31 @@ switch (mod) { case 0: - t = mutableOf(); + t = unSharedOf().mutableOf(); break; case MODconst: - t = constOf(); + t = unSharedOf().constOf(); break; - case MODinvariant: + case MODimmutable: t = invariantOf(); break; case MODshared: - t = sharedOf(); + t = mutableOf().sharedOf(); break; case MODshared | MODconst: t = sharedConstOf(); + break; + + case MODwild: + t = unSharedOf().wildOf(); + break; + + case MODshared | MODwild: + t = sharedWildOf(); break; default: @@ -1396,7 +1653,8 @@ /* Add anything to immutable, and it remains immutable */ - if (!t.isInvariant()) + //printf("addMod(%x) %s\n", mod, toChars()); + if (!t.isImmutable()) { switch (mod) { @@ -1410,13 +1668,15 @@ t = constOf(); break; - case MOD.MODinvariant: + case MOD.MODimmutable: t = invariantOf(); break; case MOD.MODshared: if (isConst()) t = sharedConstOf(); + else if (isWild()) + t = sharedWildOf(); else t = sharedOf(); break; @@ -1424,6 +1684,19 @@ case MOD.MODshared | MOD.MODconst: t = sharedConstOf(); break; + + case MOD.MODwild: + if (isConst()) + {} + else if (isShared()) + t = sharedWildOf(); + else + t = wildOf(); + break; + + case MOD.MODshared | MOD.MODwild: + t = sharedWildOf(); + break; } } return t; @@ -1436,13 +1709,15 @@ MOD mod = MOD.MODundefined; if (stc & STC.STCimmutable) - mod = MOD.MODinvariant; + mod = MOD.MODimmutable; else { if (stc & (STC.STCconst | STC.STCin)) mod = MOD.MODconst; if (stc & STC.STCshared) mod |= MOD.MODshared; + if (stc & STC.STCwild) + mod |= MOD.MODwild; } return addMod(mod); @@ -1514,6 +1789,8 @@ t.ito = null; t.sto = null; t.scto = null; + t.wto = null; + t.swto = null; t.vtinfo = null; //printf("-Type.makeConst() %p, %s\n", t, toChars()); @@ -1527,7 +1804,7 @@ } Type t = clone(); - t.mod = MOD.MODinvariant; + t.mod = MOD.MODimmutable; t.deco = null; t.arrayof = null; @@ -1537,6 +1814,8 @@ t.ito = null; t.sto = null; t.scto = null; + t.wto = null; + t.swto = null; t.vtinfo = null; return t; @@ -1558,6 +1837,8 @@ t.ito = null; t.sto = null; t.scto = null; + t.wto = null; + t.swto = null; t.vtinfo = null; return t; @@ -1579,11 +1860,73 @@ t.ito = null; t.sto = null; t.scto = null; + t.wto = null; + t.swto = null; t.vtinfo = null; return t; } + Type makeWild() + { + if (wto) + return wto; + + Type t = clone(); + t.mod = MOD.MODwild; + t.deco = null; + t.arrayof = null; + t.pto = null; + t.rto = null; + t.cto = null; + t.ito = null; + t.sto = null; + t.scto = null; + t.wto = null; + t.swto = null; + t.vtinfo = null; + return t; + } + + Type makeSharedWild() + { + if (swto) + return swto; + + Type t = clone(); + t.mod = MOD.MODshared | MOD.MODwild; + t.deco = null; + t.arrayof = null; + t.pto = null; + t.rto = null; + t.cto = null; + t.ito = null; + t.sto = null; + t.scto = null; + t.wto = null; + t.swto = null; + t.vtinfo = null; + return t; + } + + Type makeMutable() + { + Type t = clone(); + t.mod = mod & MOD.MODshared; + t.deco = null; + t.arrayof = null; + t.pto = null; + t.rto = null; + t.cto = null; + t.ito = null; + t.sto = null; + t.scto = null; + t.wto = null; + t.swto = null; + t.vtinfo = null; + return t; + } + Dsymbol toDsymbol(Scope sc) { return null; @@ -1627,7 +1970,7 @@ { if (equals(to)) return MATCH.MATCHexact; - if (ty == to.ty && to.mod == MOD.MODconst) + if (ty == to.ty && MODimplicitConv(mod, to.mod)) return MATCH.MATCHconst; return MATCH.MATCHnomatch; } @@ -1883,6 +2226,18 @@ assert(false); } + /*************************************** + * Use when we prefer the default initializer to be a literal, + * rather than a global immutable variable. + */ + Expression defaultInitLiteral(Loc loc = Loc(0)) + { +version(LOGDEFAULTINIT) { + printf("Type::defaultInitLiteral() '%s'\n", toChars()); +} + return defaultInit(loc); + } + ///bool isZeroInit(Loc loc = Loc(0)) // if initializer is 0 bool isZeroInit(Loc loc) // if initializer is 0 { @@ -1995,20 +2350,24 @@ Type at = cast(Type)dedtypes[i]; // 5*5 == 25 cases - static pure int X(int U, int T) { return ((U << 3) | T); } + static pure int X(int U, int T) { return ((U << 4) | T); } switch (X(tparam.mod, mod)) { case X(0, 0): case X(0, MODconst): - case X(0, MODinvariant): + case X(0, MODimmutable): case X(0, MODshared): case X(0, MODconst | MODshared): + case X(0, MODwild): + case X(0, MODwild | MODshared): // foo(U:U) T => T // foo(U:U) const(T) => const(T) // foo(U:U) immutable(T) => immutable(T) // foo(U:U) shared(T) => shared(T) // foo(U:U) const(shared(T)) => const(shared(T)) + // foo(U:U) wild(T) => wild(T) + // foo(U:U) wild(shared(T)) => wild(shared(T)) if (!at) { dedtypes[i] = tt; goto Lexact; @@ -2016,13 +2375,20 @@ break; case X(MODconst, MODconst): - case X(MODinvariant, MODinvariant): + case X(MODimmutable, MODimmutable): case X(MODshared, MODshared): case X(MODconst | MODshared, MODconst | MODshared): + case X(MODwild, MODwild): + case X(MODwild | MODshared, MODwild | MODshared): + case X(MODconst, MODwild): + case X(MODconst, MODwild | MODshared): // foo(U:const(U)) const(T) => T // foo(U:immutable(U)) immutable(T) => T // foo(U:shared(U)) shared(T) => T // foo(U:const(shared(U)) const(shared(T))=> T + // foo(U:wild(U)) wild(T) => T + // foo(U:wild(shared(U)) wild(shared(T)) => T + // foo(U:const(U)) wild(shared(T)) => shared(T) tt = mutableOf().unSharedOf(); if (!at) { @@ -2035,10 +2401,12 @@ case X(MODconst, MODimmutable): case X(MODconst, MODconst | MODshared): case X(MODconst | MODshared, MODimmutable): + case X(MODshared, MODwild | MODshared): // foo(U:const(U)) T => T // foo(U:const(U)) immutable(T) => T // foo(U:const(U)) const(shared(T)) => shared(T) // foo(U:const(shared(U)) immutable(T) => T + // foo(U:shared(U)) wild(shared(T)) => wild(T) tt = mutableOf(); if (!at) { dedtypes[i] = tt; @@ -2067,6 +2435,23 @@ case X(MODshared, MODimmutable): case X(MODconst | MODshared, 0): case X(MODconst | MODshared, MODconst): + case X(MODimmutable, MODwild): + case X(MODshared, MODwild): + case X(MODconst | MODshared, MODwild): + case X(MODwild, 0): + case X(MODwild, MODconst): + case X(MODwild, MODimmutable): + case X(MODwild, MODshared): + case X(MODwild, MODconst | MODshared): + case X(MODwild | MODshared, 0): + case X(MODwild | MODshared, MODconst): + case X(MODwild | MODshared, MODimmutable): + case X(MODwild | MODshared, MODshared): + case X(MODwild | MODshared, MODconst | MODshared): + case X(MODwild | MODshared, MODwild): + case X(MODimmutable, MODwild | MODshared): + case X(MODconst | MODshared, MODwild | MODshared): + case X(MODwild, MODwild | MODshared): // foo(U:immutable(U)) T => nomatch // foo(U:immutable(U)) const(T) => nomatch // foo(U:immutable(U)) shared(T) => nomatch @@ -2077,6 +2462,23 @@ // foo(U:shared(U)) immutable(T) => nomatch // foo(U:const(shared(U)) T => nomatch // foo(U:const(shared(U)) const(T) => nomatch + // foo(U:immutable(U)) wild(T) => nomatch + // foo(U:shared(U)) wild(T) => nomatch + // foo(U:const(shared(U)) wild(T) => nomatch + // foo(U:wild(U)) T => nomatch + // foo(U:wild(U)) const(T) => nomatch + // foo(U:wild(U)) immutable(T) => nomatch + // foo(U:wild(U)) shared(T) => nomatch + // foo(U:wild(U)) const(shared(T)) => nomatch + // foo(U:wild(shared(U)) T => nomatch + // foo(U:wild(shared(U)) const(T) => nomatch + // foo(U:wild(shared(U)) immutable(T) => nomatch + // foo(U:wild(shared(U)) shared(T) => nomatch + // foo(U:wild(shared(U)) const(shared(T)) => nomatch + // foo(U:wild(shared(U)) wild(T) => nomatch + // foo(U:immutable(U)) wild(shared(T)) => nomatch + // foo(U:const(shared(U))) wild(shared(T)) => nomatch + // foo(U:wild(U)) wild(shared(T)) => nomatch //if (!at) goto Lnomatch; break; @@ -2204,8 +2606,11 @@ t.vtinfo = new TypeInfoSharedDeclaration(t); else if (t.isConst()) t.vtinfo = new TypeInfoConstDeclaration(t); - else if (t.isInvariant()) + else if (t.isImmutable()) t.vtinfo = new TypeInfoInvariantDeclaration(t); + else if (t.isWild()) + t.vtinfo = new TypeInfoWildDeclaration(t); + else t.vtinfo = t.getTypeInfoDeclaration(); } else { @@ -2261,6 +2666,24 @@ return null; } + /*************************************** + * Return !=0 if the type or any of its subtypes is wild. + */ + + int hasWild() + { + return mod & MOD.MODwild; + } + + /*************************************** + * Return MOD bits matching argument type (targ) to wild parameter type (this). + */ + + uint wildMatch(Type targ) + { + return 0; + } + Expression toExpression() { assert(false); @@ -2402,14 +2825,16 @@ case MOD.MODundefined: break; case MOD.MODconst: + case MOD.MODwild: t |= mTY.mTYconst; break; - case MOD.MODinvariant: + case MOD.MODimmutable: t |= mTY.mTYimmutable; break; case MOD.MODshared: t |= mTY.mTYshared; break; + case MOD.MODshared | MOD.MODwild: case MOD.MODshared | MOD.MODconst: t |= mTY.mTYshared | mTY.mTYconst; break; diff -r 4251f96733f4 -r af1bebfd96a4 dmd/TypeAArray.d --- a/dmd/TypeAArray.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/TypeAArray.d Mon Sep 13 22:19:42 2010 +0100 @@ -116,7 +116,7 @@ else index = index.semantic(loc,sc); - if (index.nextOf() && !index.nextOf().isInvariant()) + if (index.nextOf() && !index.nextOf().isImmutable()) { index = index.constOf().mutableOf(); static if (false) @@ -330,9 +330,7 @@ version (LOGDEFAULTINIT) { printf("TypeAArray.defaultInit() '%s'\n", toChars()); } - Expression e = new NullExp(loc); - e.type = this; - return e; + return new NullExp(loc, this); } override MATCH deduceType(Scope sc, Type tparam, TemplateParameters parameters, Objects dedtypes) @@ -385,10 +383,10 @@ { TypeAArray ta = cast(TypeAArray)to; - if (!(next.mod == ta.next.mod || ta.next.mod == MODconst)) + if (!MODimplicitConv(next.mod, ta.next.mod)) return MATCHnomatch; // not const-compatible - if (!(index.mod == ta.index.mod || ta.index.mod == MODconst)) + if (!MODimplicitConv(index.mod, ta.index.mod)) return MATCHnomatch; // not const-compatible MATCH m = next.constConv(ta.next); diff -r 4251f96733f4 -r af1bebfd96a4 dmd/TypeClass.d --- a/dmd/TypeClass.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/TypeClass.d Mon Sep 13 22:19:42 2010 +0100 @@ -486,9 +486,7 @@ version (LOGDEFAULTINIT) { printf("TypeClass::defaultInit() '%s'\n", toChars()); } - Expression e = new NullExp(loc); - e.type = this; - return e; + return new NullExp(loc, this); } override bool isZeroInit(Loc loc) diff -r 4251f96733f4 -r af1bebfd96a4 dmd/TypeDArray.d --- a/dmd/TypeDArray.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/TypeDArray.d Mon Sep 13 22:19:42 2010 +0100 @@ -195,7 +195,7 @@ /* Allow conversion to void* */ if (tp.next.ty == Tvoid && - (next.mod == tp.next.mod || tp.next.mod == MODconst)) + MODimplicitConv(next.mod, tp.next.mod)) { return MATCHconvert; } @@ -208,7 +208,7 @@ int offset = 0; TypeDArray ta = cast(TypeDArray)to; - if (!(next.mod == ta.next.mod || ta.next.mod == MODconst)) + if (!MODimplicitConv(next.mod, ta.next.mod)) return MATCHnomatch; // not const-compatible /* Allow conversion to void[] @@ -226,6 +226,7 @@ return m; } +static if(false) { /* Allow conversions of T[][] to const(T)[][] */ if (mod == ta.mod && next.ty == Tarray && ta.next.ty == Tarray) @@ -234,7 +235,7 @@ if (m == MATCHconst) return m; } - +} /* Conversion of array of derived to array of base */ if (ta.next.isBaseOf(next, &offset) && offset == 0) @@ -248,9 +249,7 @@ version (LOGDEFAULTINIT) { printf("TypeDArray.defaultInit() '%s'\n", toChars()); } - Expression e = new NullExp(loc); - e.type = this; - return e; + return new NullExp(loc, this); } override bool builtinTypeInfo() @@ -258,7 +257,7 @@ version (DMDV2) { return !mod && (next.isTypeBasic() !is null && !next.mod || // strings are so common, make them builtin - next.ty == Tchar && next.mod == MODinvariant); + next.ty == Tchar && next.mod == MODimmutable); } else { return next.isTypeBasic() !is null; } diff -r 4251f96733f4 -r af1bebfd96a4 dmd/TypeDelegate.d --- a/dmd/TypeDelegate.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/TypeDelegate.d Mon Sep 13 22:19:42 2010 +0100 @@ -113,10 +113,7 @@ version (LOGDEFAULTINIT) { printf("TypeDelegate.defaultInit() '%s'\n", toChars()); } - Expression e; - e = new NullExp(loc); - e.type = this; - return e; + return new NullExp(loc, this); } override bool isZeroInit(Loc loc) diff -r 4251f96733f4 -r af1bebfd96a4 dmd/TypeEnum.d --- a/dmd/TypeEnum.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/TypeEnum.d Mon Sep 13 22:19:42 2010 +0100 @@ -189,11 +189,20 @@ override MATCH constConv(Type to) { - assert(false); + if (equals(to)) + return MATCHexact; + if (ty == to.ty && sym == (cast(TypeEnum)to).sym && + MODimplicitConv(mod, to.mod)) + return MATCHconst; + return MATCHnomatch; } override Type toBasetype() { + if (sym.scope_) + { + sym.semantic(null); // attempt to resolve forward reference + } if (!sym.memtype) { debug writef("2: "); diff -r 4251f96733f4 -r af1bebfd96a4 dmd/TypeFunction.d --- a/dmd/TypeFunction.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/TypeFunction.d Mon Sep 13 22:19:42 2010 +0100 @@ -34,6 +34,7 @@ import dmd.Util; import dmd.FuncDeclaration; import dmd.Dsymbol; +import dmd.TypeTuple; import dmd.TemplateInstance : isTuple; import dmd.backend.TYPE; @@ -61,6 +62,7 @@ bool isref; // true: returns a reference LINK linkage; // calling convention TRUST trust; // level of trust + Expressions fargs; // function arguments int inuse; @@ -88,6 +90,7 @@ t.isproperty = isproperty; t.isref = isref; t.trust = trust; + t.fargs = fargs; return t; } @@ -136,7 +139,7 @@ return this; } //printf("TypeFunction.semantic() this = %p\n", this); - //printf("TypeFunction.semantic() %s, sc.stc = %x\n", toChars(), sc.stc); + //printf("TypeFunction::semantic() %s, sc->stc = %llx, fargs = %p\n", toChars(), sc->stc, fargs); /* Copy in order to not mess up original. * This can produce redundant copies if inferring return type, @@ -174,6 +177,7 @@ } } + bool wildreturn = false; if (tf.next) { tf.next = tf.next.semantic(loc,sc); @@ -197,8 +201,14 @@ } if (tf.next.isauto() && !(sc.flags & SCOPE.SCOPEctor)) error(loc, "functions cannot return scope %s", tf.next.toChars()); - } + if (tf.next.toBasetype().ty == TY.Tvoid) + tf.isref = false; // rewrite "ref void" as just "void" + if (tf.next.isWild()) + wildreturn = true; + } + bool wildparams = false; + bool wildsubparams = false; if (tf.parameters) { /* Create a scope for evaluating the default arguments for the parameters @@ -210,49 +220,97 @@ size_t dim = Parameter.dim(tf.parameters); for (size_t i = 0; i < dim; i++) - { auto arg = Parameter.getNth(tf.parameters, i); + { auto fparam = Parameter.getNth(tf.parameters, i); tf.inuse++; - arg.type = arg.type.semantic(loc, argsc); + fparam.type = fparam.type.semantic(loc, argsc); if (tf.inuse == 1) tf.inuse--; - arg.type = arg.type.addStorageClass(arg.storageClass); + fparam.type = fparam.type.addStorageClass(fparam.storageClass); - if (arg.storageClass & (STC.STCauto | STC.STCalias | STC.STCstatic)) + if (fparam.storageClass & (STC.STCauto | STC.STCalias | STC.STCstatic)) { - if (!arg.type) + if (!fparam.type) continue; } - Type t = arg.type.toBasetype(); + Type t = fparam.type.toBasetype(); - if (arg.storageClass & (STC.STCout | STC.STCref | STC.STClazy)) + if (fparam.storageClass & (STC.STCout | STC.STCref | STC.STClazy)) { //if (t.ty == TY.Tsarray) //error(loc, "cannot have out or ref parameter of type %s", t.toChars()); - if (arg.storageClass & STC.STCout && arg.type.mod & (STCconst | STCimmutable)) + if (fparam.storageClass & STC.STCout && fparam.type.mod & (STCconst | STCimmutable)) error(loc, "cannot have const or immutabl out parameter of type %s", t.toChars()); } - if (!(arg.storageClass & STC.STClazy) && t.ty == TY.Tvoid) - error(loc, "cannot have parameter of type %s", arg.type.toChars()); + if (!(fparam.storageClass & STC.STClazy) && t.ty == TY.Tvoid) + error(loc, "cannot have parameter of type %s", fparam.type.toChars()); - if (arg.defaultArg) - { - arg.defaultArg = arg.defaultArg.semantic(argsc); - arg.defaultArg = resolveProperties(argsc, arg.defaultArg); - arg.defaultArg = arg.defaultArg.implicitCastTo(argsc, arg.type); - } + if (t.isWild()) + { + wildparams = true; + if (tf.next && !wildreturn) + error(loc, "inout on parameter means inout must be on return type as well (if from D1 code, replace with 'ref')"); + } + else if (!wildsubparams && t.hasWild()) + wildsubparams = true; - /* If arg turns out to be a tuple, the number of parameters may + if (fparam.defaultArg) + { + fparam.defaultArg = fparam.defaultArg.semantic(argsc); + fparam.defaultArg = resolveProperties(argsc, fparam.defaultArg); + fparam.defaultArg = fparam.defaultArg.implicitCastTo(argsc, fparam.type); + } + + /* If fparam turns out to be a tuple, the number of parameters may * change. */ if (t.ty == TY.Ttuple) - { dim = Parameter.dim(tf.parameters); + { + // Propagate storage class from tuple parameters to their element-parameters. + auto tt = cast(TypeTuple)t; + if (tt.arguments) + { + auto tdim = tt.arguments.dim; + foreach (narg; tt.arguments) + { + narg.storageClass = fparam.storageClass; + } + } + + /* Reset number of parameters, and back up one to do this fparam again, + * now that it is the first element of a tuple + */ + dim = Parameter.dim(tf.parameters); i--; + continue; } + + /* Resolve "auto ref" storage class to be either ref or value, + * based on the argument matching the parameter + */ + if (fparam.storageClass & STC.STCauto) + { + if (fargs && i < fargs.dim) + { + auto farg = fargs[i]; + if (farg.isLvalue()) + {} // ref parameter + else + fparam.storageClass &= ~STC.STCref; // value parameter + } + else + error(loc, "auto can only be used for template function parameters"); + } } argsc.pop(); } + + if (wildreturn && !wildparams) + error(loc, "inout on return means inout must be on a parameter as well for %s", toChars()); + if (wildsubparams && wildparams) + error(loc, "inout must be all or none on top level for %s", toChars()); + if (tf.next) tf.deco = tf.merge().deco; @@ -287,14 +345,7 @@ return; } inuse++; -static if (true) { - if (mod & MOD.MODshared) - buf.writeByte('O'); - if (mod & MOD.MODconst) - buf.writeByte('x'); - else if (mod & MOD.MODinvariant) - buf.writeByte('y'); -} + MODtoDecoBuffer(buf, mod); switch (linkage) { case LINK.LINKd: mc = 'F'; break; @@ -320,7 +371,7 @@ buf.writestring("Ne"); break; case TRUST.TRUSTsafe: - buf.writestring("Nd"); + buf.writestring("Nf"); break; default: } @@ -348,12 +399,11 @@ /* Use 'storage class' style for attributes */ - if (mod & MODconst) - buf.writestring("const "); - if (mod & MODinvariant) - buf.writestring("immutable "); - if (mod & MODshared) - buf.writestring("shared "); + if (mod) + { + MODtoBuffer(buf, mod); + buf.writeByte(' '); + } if (ispure) buf.writestring("pure "); @@ -569,16 +619,15 @@ override Type reliesOnTident() { - if (parameters) - { - foreach (arg; parameters) - { - Type t = arg.type.reliesOnTident(); - if (t) - return t; - } - } - return next.reliesOnTident(); + size_t dim = Parameter.dim(parameters); + for (size_t i = 0; i < dim; i++) + { + auto fparam = Parameter.getNth(parameters, i); + Type t = fparam.type.reliesOnTident(); + if (t) + return t; + } + return next ? next.reliesOnTident() : null; } version (CPP_MANGLE) { @@ -631,6 +680,8 @@ { //printf("TypeFunction.callMatch() %s\n", toChars()); MATCH match = MATCH.MATCHexact; // assume exact match + bool exactwildmatch = false; + bool wildmatch = false; if (ethis) { @@ -640,7 +691,7 @@ if (t.mod != mod) { - if (mod == MOD.MODconst) + if (MODimplicitConv(t.mod, mod)) match = MATCH.MATCHconst; else return MATCH.MATCHnomatch; @@ -690,7 +741,7 @@ if (p.storageClass & STCref) { - /* Don't allow static arrays to be passed to mutable refereces + /* Don't allow static arrays to be passed to mutable references * to static arrays if the argument cannot be modified. */ Type targb = arg.type.toBasetype(); @@ -698,15 +749,36 @@ //writef("%s\n", targb.toChars()); //writef("%s\n", tparb.toChars()); if (targb.nextOf() && tparb.ty == Tsarray && - targb.nextOf().mod != tparb.nextOf().mod && - !tparb.nextOf().isConst()) + !MODimplicitConv(targb.nextOf().mod, tparb.nextOf().mod)) goto Nomatch; } if (p.storageClass & STC.STClazy && p.type.ty == TY.Tvoid && arg.type.ty != TY.Tvoid) m = MATCH.MATCHconvert; else + { m = arg.implicitConvTo(p.type); + if (p.type.isWild()) + { + if (m == MATCHnomatch) + { + m = arg.implicitConvTo(p.type.constOf()); + if (m == MATCHnomatch) + m = arg.implicitConvTo(p.type.sharedConstOf()); + if (m != MATCHnomatch) + wildmatch = true; // mod matched to wild + } + else + exactwildmatch = true; // wild matched to wild + + /* If both are allowed, then there could be more than one + * binding of mod to wild, leaving a gaping type hole. + */ + if (wildmatch && exactwildmatch) + m = MATCHnomatch; + } + } + //printf("\tm = %d\n", m); if (m == MATCH.MATCHnomatch) // if no match { diff -r 4251f96733f4 -r af1bebfd96a4 dmd/TypeInfoWildDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeInfoWildDeclaration.d Mon Sep 13 22:19:42 2010 +0100 @@ -0,0 +1,29 @@ +module dmd.TypeInfoWildDeclaration; + +import dmd.TY; +import dmd.Type; +import dmd.TypeInfoDeclaration; + +import dmd.backend.dt_t; +import dmd.backend.Util; +import dmd.backend.TYM; + +class TypeInfoWildDeclaration : TypeInfoDeclaration +{ + this(Type tinfo) + { + super(tinfo, 0); + type = Type.typeinfowild.type; + } + + override void toDt(dt_t **pdt) + { + //printf("TypeInfoWildDeclaration::toDt() %s\n", toChars()); + dtxoff(pdt, Type.typeinfowild.toVtblSymbol(), 0, TYnptr); // vtbl for TypeInfo_Wild + dtdword(pdt, 0); // monitor + Type tm = tinfo.mutableOf(); + tm = tm.merge(); + tm.getTypeInfo(null); + dtxoff(pdt, tm.vtinfo.toSymbol(), 0, TYnptr); + } +}; diff -r 4251f96733f4 -r af1bebfd96a4 dmd/TypeNext.d --- a/dmd/TypeNext.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/TypeNext.d Mon Sep 13 22:19:42 2010 +0100 @@ -53,6 +53,35 @@ return next.reliesOnTident(); } + override int hasWild() + { + return mod == MOD.MODwild || next.hasWild(); + } + + /*************************************** + * Return MOD bits matching argument type (targ) to wild parameter type (this). + */ + + override uint wildMatch(Type targ) + { + uint mod; + + Type tb = targ.nextOf(); + if (!tb) + return 0; + tb = tb.toBasetype(); + if (tb.isMutable()) + mod = MOD.MODmutable; + else if (tb.isConst() || tb.isWild()) + return MOD.MODconst; + else if (tb.isImmutable()) + mod = MOD.MODimmutable; + else + assert(0); + mod |= next.wildMatch(tb); + return mod; + } + override Type nextOf() { return next; @@ -70,7 +99,7 @@ TypeNext t = cast(TypeNext)super.makeConst(); if (ty != TY.Tfunction && ty != TY.Tdelegate && (next.deco || next.ty == TY.Tfunction) && - !next.isInvariant() && !next.isConst()) + !next.isImmutable() && !next.isConst()) { if (next.isShared()) t.next = next.sharedConstOf(); @@ -90,11 +119,11 @@ //printf("TypeNext::makeInvariant() %s\n", toChars()); if (ito) { - assert(ito.isInvariant()); + assert(ito.isImmutable()); return ito; } TypeNext t = cast(TypeNext)Type.makeInvariant(); - if (ty != TY.Tfunction && ty != TY.Tdelegate && (next.deco || next.ty == TY.Tfunction) && !next.isInvariant()) + if (ty != TY.Tfunction && ty != TY.Tdelegate && (next.deco || next.ty == TY.Tfunction) && !next.isImmutable()) { t.next = next.invariantOf(); } @@ -116,9 +145,9 @@ TypeNext t = cast(TypeNext)Type.makeShared(); if (ty != Tfunction && ty != Tdelegate && (next.deco || next.ty == Tfunction) && - !next.isInvariant() && !next.isShared()) + !next.isImmutable() && !next.isShared()) { - if (next.isConst()) + if (next.isConst() || next.isWild()) t.next = next.sharedConstOf(); else t.next = next.sharedOf(); @@ -142,7 +171,7 @@ TypeNext t = cast(TypeNext) Type.makeSharedConst(); if (ty != Tfunction && ty != Tdelegate && (next.deco || next.ty == Tfunction) && - !next.isInvariant() && !next.isSharedConst()) + !next.isImmutable() && !next.isSharedConst()) { t.next = next.sharedConstOf(); } @@ -154,6 +183,73 @@ return t; } + override Type makeWild() + { + //printf("TypeNext::makeWild() %s\n", toChars()); + if (wto) + { + assert(wto.mod == MODwild); + return wto; + } + auto t = cast(TypeNext)Type.makeWild(); + if (ty != TY.Tfunction && ty != TY.Tdelegate && + (next.deco || next.ty == TY.Tfunction) && + !next.isImmutable() && !next.isConst() && !next.isWild()) + { + if (next.isShared()) + t.next = next.sharedWildOf(); + else + t.next = next.wildOf(); + } + if (ty == TY.Taarray) + { + (cast(TypeAArray)t).impl = null; // lazily recompute it + } + //printf("TypeNext::makeWild() returns %p, %s\n", t, t->toChars()); + return t; + } + + Type makeSharedWild() + { + //printf("TypeNext::makeSharedWild() %s\n", toChars()); + if (swto) + { + assert(swto.isSharedWild()); + return swto; + } + auto t = cast(TypeNext)Type.makeSharedWild(); + if (ty != TY.Tfunction && ty != TY.Tdelegate && + (next.deco || next.ty == TY.Tfunction) && + !next.isImmutable() && !next.isSharedConst()) + { + t.next = next.sharedWildOf(); + } + if (ty == Taarray) + { + (cast(TypeAArray)t).impl = null; // lazily recompute it + } + //printf("TypeNext::makeSharedWild() returns %p, %s\n", t, t->toChars()); + return t; + } + + Type makeMutable() + { + //printf("TypeNext::makeMutable() %p, %s\n", this, toChars()); + auto t = cast(TypeNext)Type.makeMutable(); + if (ty != TY.Tfunction && ty != TY.Tdelegate && + (next.deco || next.ty == TY.Tfunction) && + next.isWild()) + { + t.next = next.mutableOf(); + } + if (ty == Taarray) + { + (cast(TypeAArray)t).impl = null; // lazily recompute it + } + //printf("TypeNext::makeMutable() returns %p, %s\n", t, t->toChars()); + return t; + } + override MATCH constConv(Type to) { MATCH m = Type.constConv(to); diff -r 4251f96733f4 -r af1bebfd96a4 dmd/TypePointer.d --- a/dmd/TypePointer.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/TypePointer.d Mon Sep 13 22:19:42 2010 +0100 @@ -108,7 +108,7 @@ TypePointer tp = cast(TypePointer)to; assert(tp.next); - if (!(next.mod == tp.next.mod || tp.next.mod == MOD.MODconst)) + if (!MODimplicitConv(next.mod, tp.next.mod)) return MATCH.MATCHnomatch; // not const-compatible /* Alloc conversion to void[] @@ -145,9 +145,7 @@ version (LOGDEFAULTINIT) { printf("TypePointer::defaultInit() '%s'\n", toChars()); } - Expression e = new NullExp(loc); - e.type = this; - return e; + return new NullExp(loc, this); } override bool isZeroInit(Loc loc) diff -r 4251f96733f4 -r af1bebfd96a4 dmd/TypeQualified.d --- a/dmd/TypeQualified.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/TypeQualified.d Mon Sep 13 22:19:42 2010 +0100 @@ -22,6 +22,7 @@ import dmd.Dsymbol; import dmd.DYNCAST; import dmd.Expression; +import dmd.FuncDeclaration; import dmd.Util; class TypeQualified : Type @@ -100,6 +101,7 @@ void resolveHelper(Loc loc, Scope sc, Dsymbol s, Dsymbol scopesym, Expression* pe, Type* pt, Dsymbol* ps) { VarDeclaration v; + FuncDeclaration fd; EnumMember em; TupleDeclaration td; Expression e; @@ -174,7 +176,7 @@ { id = cast(Identifier)idents.data[i]; //printf("e: '%s', id: '%s', type = %p\n", e.toChars(), id.toChars(), e.type); - if (id == Id.offsetof) + if (id == Id.offsetof || !e.type) { e = new DotIdExp(e.loc, e, id); e = e.semantic(sc); } @@ -195,32 +197,17 @@ v = s.isVarDeclaration(); if (v) { -///static if (false) { -/// // It's not a type, it's an expression -/// Expression *e = v.getConstInitializer(); -/// if (e) -/// { -/// *pe = e.copy(); // make copy so we can change loc -/// (*pe).loc = loc; -/// } -/// else -///} - { -///static if (false) { -/// WithScopeSymbol withsym; -/// if (scopesym && (withsym = scopesym.isWithScopeSymbol()) !is null) -/// { -/// // Same as wthis.ident -/// e = new VarExp(loc, withsym.withstate.wthis); -/// e = new DotIdExp(loc, e, ident); -/// //assert(0); // BUG: should handle this -/// } -/// else -///} - *pe = new VarExp(loc, v); - } + *pe = new VarExp(loc, v); return; } +//#if 0 +// fd = s->isFuncDeclaration(); +// if (fd) +// { +// *pe = new DsymbolExp(loc, fd, 1); +// return; +// } +//#endif em = s.isEnumMember(); if (em) { diff -r 4251f96733f4 -r af1bebfd96a4 dmd/TypeReference.d --- a/dmd/TypeReference.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/TypeReference.d Mon Sep 13 22:19:42 2010 +0100 @@ -10,6 +10,7 @@ import dmd.HdrGenState; import dmd.Expression; import dmd.Identifier; +import dmd.NullExp; import dmd.CppMangleState; import dmd.TY; @@ -56,7 +57,10 @@ override Expression defaultInit(Loc loc) { - assert(false); +version(LOGDEFAULTINIT) { + printf("TypeReference::defaultInit() '%s'\n", toChars()); +} + return new NullExp(loc, this); } override bool isZeroInit(Loc loc) diff -r 4251f96733f4 -r af1bebfd96a4 dmd/TypeSArray.d --- a/dmd/TypeSArray.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/TypeSArray.d Mon Sep 13 22:19:42 2010 +0100 @@ -367,7 +367,7 @@ { TypePointer tp = cast(TypePointer)to; - if (next.mod != tp.next.mod && tp.next.mod != MODconst) + if (!MODimplicitConv(next.mod, tp.next.mod)) return MATCHnomatch; if (tp.next.ty == Tvoid || next.constConv(tp.next) != MATCHnomatch) @@ -381,11 +381,12 @@ int offset = 0; TypeDArray ta = cast(TypeDArray)to; - if (next.mod != ta.next.mod && ta.next.mod != MODconst) + if (!MODimplicitConv(next.mod, ta.next.mod)) return MATCHnomatch; if (next.equals(ta.next) || - next.implicitConvTo(ta.next) >= MATCHconst || +// next.implicitConvTo(ta.next) >= MATCHconst || + next.constConv(ta.next) != MATCHnomatch || (ta.next.isBaseOf(next, &offset) && offset == 0) || ta.next.ty == Tvoid ) diff -r 4251f96733f4 -r af1bebfd96a4 dmd/TypeStruct.d --- a/dmd/TypeStruct.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/TypeStruct.d Mon Sep 13 22:19:42 2010 +0100 @@ -37,6 +37,7 @@ import dmd.VarExp; import dmd.CommaExp; import dmd.ThisExp; +import dmd.StructLiteralExp; import dmd.SymbolDeclaration; import dmd.TypeInfoDeclaration; import dmd.TypeInfoStructDeclaration; @@ -377,18 +378,44 @@ override Expression defaultInit(Loc loc) { - Symbol* s; - Declaration d; - version (LOGDEFAULTINIT) { printf("TypeStruct::defaultInit() '%s'\n", toChars()); } - s = sym.toInitializer(); - d = new SymbolDeclaration(sym.loc, s, sym); + Symbol *s = sym.toInitializer(); + Declaration d = new SymbolDeclaration(sym.loc, s, sym); assert(d); d.type = this; return new VarExp(sym.loc, d); } + + /*************************************** + * Use when we prefer the default initializer to be a literal, + * rather than a global immutable variable. + */ + Expression defaultInitLiteral(Loc loc) + { + version (LOGDEFAULTINIT) { + printf("TypeStruct::defaultInitLiteral() '%s'\n", toChars()); + } + auto structelems = new Expressions(); + structelems.setDim(sym.fields.dim); + for (size_t j = 0; j < structelems.dim; j++) + { + auto vd = cast(VarDeclaration)(sym.fields[j]); + Expression e; + if (vd.init) + e = vd.init.toExpression(); + else + e = vd.type.defaultInitLiteral(); + structelems[j] = e; + } + auto structinit = new StructLiteralExp(loc, cast(StructDeclaration)sym, structelems); + // Why doesn't the StructLiteralExp constructor do this, when + // sym->type != NULL ? + structinit.type = sym.type; + return structinit; + } + override bool isZeroInit(Loc loc) { @@ -403,7 +430,7 @@ for (size_t i = 0; i < sym.fields.dim; i++) { VarDeclaration v = cast(VarDeclaration)sym.fields[i]; - if (v.isConst() || v.isInvariant()) + if (v.isConst() || v.isImmutable()) return false; } return true; @@ -480,6 +507,7 @@ override bool hasPointers() { + // Probably should cache this information in sym rather than recompute StructDeclaration s = sym; sym.size(Loc(0)); // give error for forward references @@ -503,7 +531,7 @@ m = MATCHexact; // exact match if (mod != to.mod) { - if (to.mod == MODconst) + if (MODimplicitConv(mod, to.mod)) m = MATCHconst; else { /* Check all the fields. If they can all be converted, @@ -547,7 +575,8 @@ { if (equals(to)) return MATCHexact; - if (ty == to.ty && sym == (cast(TypeStruct)to).sym && to.mod == MODconst) + if (ty == to.ty && sym == (cast(TypeStruct)to).sym && + MODimplicitConv(mod, to.mod)) return MATCHconst; return MATCHnomatch; } diff -r 4251f96733f4 -r af1bebfd96a4 dmd/TypeTuple.d --- a/dmd/TypeTuple.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/TypeTuple.d Mon Sep 13 22:19:42 2010 +0100 @@ -28,7 +28,7 @@ super(TY.Ttuple); //printf("TypeTuple(this = %p)\n", this); this.arguments = arguments; - //printf("TypeTuple() %s\n", toChars()); + //printf("TypeTuple() %p, %s\n", this, toChars()); debug { if (arguments) { @@ -68,6 +68,7 @@ } } this.arguments = arguments; + //printf("TypeTuple() %p, %s\n", this, toChars()); } override Type syntaxCopy() diff -r 4251f96733f4 -r af1bebfd96a4 dmd/TypeTypedef.d --- a/dmd/TypeTypedef.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/TypeTypedef.d Mon Sep 13 22:19:42 2010 +0100 @@ -213,9 +213,6 @@ override Expression defaultInit(Loc loc) { - Expression e; - Type bt; - version (LOGDEFAULTINIT) { printf("TypeTypedef::defaultInit() '%s'\n", toChars()); } @@ -224,8 +221,8 @@ //sym->init->toExpression()->print(); return sym.init.toExpression(); } - bt = sym.basetype; - e = bt.defaultInit(loc); + Type bt = sym.basetype; + Expression e = bt.defaultInit(loc); e.type = this; while (bt.ty == Tsarray) { @@ -299,6 +296,11 @@ return toBasetype().hasPointers(); } + override int hasWild() + { + return mod & MOD.MODwild || toBasetype().hasWild(); + } + override Type toHeadMutable() { assert(false); diff -r 4251f96733f4 -r af1bebfd96a4 dmd/TypedefDeclaration.d --- a/dmd/TypedefDeclaration.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/TypedefDeclaration.d Mon Sep 13 22:19:42 2010 +0100 @@ -71,6 +71,9 @@ sem = 1; basetype = basetype.semantic(loc, sc); sem = 2; +version(DMDV2) { + type = type.addStorageClass(storage_class); +} type = type.semantic(loc, sc); if (sc.parent.isFuncDeclaration() && init) semantic2(sc); diff -r 4251f96733f4 -r af1bebfd96a4 dmd/TypeidExp.d --- a/dmd/TypeidExp.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/TypeidExp.d Mon Sep 13 22:19:42 2010 +0100 @@ -43,16 +43,19 @@ Expression e; version (LOGSEMANTIC) { - printf("TypeidExp.semantic()\n"); + printf("TypeidExp.semantic() %s\n", toChars()); } Type ta = isType(obj); Expression ea = isExpression(obj); Dsymbol sa = isDsymbol(obj); + //printf("ta %p ea %p sa %p\n", ta, ea, sa); + if (ta) { ta.resolve(loc, sc, &ea, &ta, &sa); } + if (ea) { ea = ea.semantic(sc); @@ -63,7 +66,9 @@ } if (!ta) - { error("no type for typeid(%s)", ea ? ea.toChars() : (sa ? sa.toChars() : "")); + { + //printf("ta %p ea %p sa %p\n", ta, ea, sa); + error("no type for typeid(%s)", ea ? ea.toChars() : (sa ? sa.toChars() : "")); return new ErrorExp(); } diff -r 4251f96733f4 -r af1bebfd96a4 dmd/UshrExp.d --- a/dmd/UshrExp.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/UshrExp.d Mon Sep 13 22:19:42 2010 +0100 @@ -75,6 +75,12 @@ override elem* toElem(IRState* irs) { - return toElemBin(irs, OPER.OPshr); + //return toElemBin(irs, OPER.OPshr); + elem *eleft = e1.toElem(irs); + eleft.Ety = touns(eleft.Ety); + elem *eright = e2.toElem(irs); + elem *e = el_bin(OPER.OPshr, type.totym(), eleft, eright); + el_setLoc(e, loc); + return e; } } \ No newline at end of file diff -r 4251f96733f4 -r af1bebfd96a4 dmd/Util.d --- a/dmd/Util.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/Util.d Mon Sep 13 22:19:42 2010 +0100 @@ -635,6 +635,8 @@ precedence[TOK.TOKnew] = PREC.PREC_unary; precedence[TOK.TOKcast] = PREC.PREC_unary; + precedence[TOK.TOKpow] = PREC.PREC_pow; + precedence[TOK.TOKmul] = PREC.PREC_mul; precedence[TOK.TOKdiv] = PREC.PREC_mul; precedence[TOK.TOKmod] = PREC.PREC_mul; @@ -698,7 +700,7 @@ precedence[TOK.TOKmulass] = PREC.PREC_assign; precedence[TOK.TOKdivass] = PREC.PREC_assign; precedence[TOK.TOKmodass] = PREC.PREC_assign; - //precedence[TOKpowass] = PREC.PREC_assign; + precedence[TOK.TOKpowass] = PREC.PREC_assign; precedence[TOK.TOKshlass] = PREC.PREC_assign; precedence[TOK.TOKshrass] = PREC.PREC_assign; precedence[TOK.TOKushrass] = PREC.PREC_assign; diff -r 4251f96733f4 -r af1bebfd96a4 dmd/VarDeclaration.d --- a/dmd/VarDeclaration.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/VarDeclaration.d Mon Sep 13 22:19:42 2010 +0100 @@ -343,10 +343,12 @@ if (type.isShared()) storage_class |= STC.STCshared; } - else if (type.isInvariant()) + else if (type.isImmutable()) storage_class |= STC.STCimmutable; else if (type.isShared()) storage_class |= STC.STCshared; + else if (type.isWild()) + storage_class |= STC.STCwild; if (isSynchronized()) { @@ -422,6 +424,13 @@ { error("only parameters or foreach declarations can be ref"); } + + if ((storage_class & (STCstatic | STCextern | STCtls | STCgshared | STCmanifest) || + isDataseg()) && + type.hasWild()) + { + error("only fields, parameters or stack based variables can be inout"); + } } if (type.isauto() && !noauto) @@ -438,7 +447,7 @@ } } - if ((isConst() || isInvariant()) && !init && !fd) + if ((isConst() || isImmutable()) && !init && !fd) { // Initialize by constructor only storage_class |= STC.STCctorinit; @@ -652,7 +661,7 @@ } } else if (storage_class & (STC.STCconst | STC.STCimmutable | STC.STCmanifest) || - type.isConst() || type.isInvariant() || + type.isConst() || type.isImmutable() || parent.isAggregateDeclaration()) { /* Because we may need the results of a const declaration in a @@ -795,7 +804,7 @@ { static if (false) { printf("VarDeclaration.isDataseg(%p, '%s')\n", this, toChars()); - printf("%x, %p, %p\n", storage_class & (STC.STCstatic | STC.STCconst), parent.isModule(), parent.isTemplateInstance()); + printf("%llx, isModule: %p, isTemplateInstance: %p\n", storage_class & (STC.STCstatic | STC.STCconst), parent.isModule(), parent.isTemplateInstance()); printf("parent = '%s'\n", parent.toChars()); } if (storage_class & STC.STCmanifest) @@ -830,6 +839,15 @@ } } + /******************************************** + * Can variable be read and written by CTFE? + */ + + int isCTFE() + { + return (storage_class & STCctfe) || !isDataseg(); + } + override bool hasPointers() { //printf("VarDeclaration.hasPointers() %s, ty = %d\n", toChars(), type.ty); @@ -844,7 +862,7 @@ * const int x = 3; * are not stored and hence cannot have their address taken. */ - if ((isConst() || isInvariant()) && (storage_class & STC.STCinit) && (!(storage_class & (STC.STCstatic | STC.STCextern)) || (storage_class & STC.STCfield)) && + if ((isConst() || isImmutable()) && (storage_class & STC.STCinit) && (!(storage_class & (STC.STCstatic | STC.STCextern)) || (storage_class & STC.STCfield)) && (!parent || toParent().isModule() || toParent().isTemplateInstance()) && type.toBasetype().isTypeBasic()) { return false; @@ -992,7 +1010,7 @@ */ Expression getConstInitializer() { - if ((isConst() || isInvariant() || storage_class & STC.STCmanifest) && storage_class & STC.STCinit) + if ((isConst() || isImmutable() || storage_class & STC.STCmanifest) && storage_class & STC.STCinit) { ExpInitializer ei = getExpInitializer(); if (ei) diff -r 4251f96733f4 -r af1bebfd96a4 dmd/VarExp.d --- a/dmd/VarExp.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/VarExp.d Mon Sep 13 22:19:42 2010 +0100 @@ -70,7 +70,7 @@ if (v) { static if (false) { - if ((v.isConst() || v.isInvariant()) && type.toBasetype().ty != TY.Tsarray && v.init) + if ((v.isConst() || v.isImmutable()) && type.toBasetype().ty != TY.Tsarray && v.init) { ExpInitializer ei = v.init.isExpInitializer(); if (ei) @@ -121,12 +121,12 @@ * If it is pure, it cannot access any mutable variables other * than those inside itself */ - if (hasPureParent && v.isDataseg() && !v.isInvariant()) + if (hasPureParent && v.isDataseg() && !v.isImmutable()) { error("pure function '%s' cannot access mutable static data '%s'", sc.func.toChars(), v.toChars()); } - else if (sc.func.isPure() && sc.parent != v.parent && !v.isInvariant() && !(v.storage_class & STC.STCmanifest)) + else if (sc.func.isPure() && sc.parent != v.parent && !v.isImmutable() && !(v.storage_class & STC.STCmanifest)) { error("pure nested function '%s' cannot access mutable data '%s'", sc.func.toChars(), v.toChars()); if (v.isEnumDeclaration()) @@ -142,7 +142,7 @@ } else { if (sc.func && sc.func.isPure() && !sc.intypeof) { - if (v.isDataseg() && !v.isInvariant()) + if (v.isDataseg() && !v.isImmutable()) error("pure function '%s' cannot access mutable static data '%s'", sc.func.toChars(), v.toChars()); } } @@ -207,6 +207,16 @@ } } } + + override void checkEscapeRef() + { + VarDeclaration v = var.isVarDeclaration(); + if (v) + { + if (!v.isDataseg() && !(v.storage_class & (STCref | STCout))) + error("escaping reference to local variable %s", v.toChars()); + } + } version (DMDV2) { diff -r 4251f96733f4 -r af1bebfd96a4 dmd/WhileStatement.d --- a/dmd/WhileStatement.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/WhileStatement.d Mon Sep 13 22:19:42 2010 +0100 @@ -68,7 +68,11 @@ override Expression interpret(InterState istate) { - assert(false); +version(LOG) { + printf("WhileStatement::interpret()\n"); +} + assert(false); // rewritten to ForStatement + return null; } override void toCBuffer(OutBuffer buf, HdrGenState* hgs) diff -r 4251f96733f4 -r af1bebfd96a4 dmd/backend/iasm.d --- a/dmd/backend/iasm.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/backend/iasm.d Mon Sep 13 22:19:42 2010 +0100 @@ -4340,7 +4340,7 @@ } if ((v.isConst() ///version (DMDV2) { - || v.isInvariant() || v.storage_class & STCmanifest + || v.isImmutable() || v.storage_class & STCmanifest ///} ) && !v.type.isfloating() && v.init) { diff -r 4251f96733f4 -r af1bebfd96a4 dmd/codegen/Util.d --- a/dmd/codegen/Util.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/codegen/Util.d Mon Sep 13 22:19:42 2010 +0100 @@ -297,9 +297,15 @@ e = el_una(op,tyret,ep); } else if (ep) - e = el_bin((tf.ispure && tf.isnothrow) ? OPER.OPcallns : OPER.OPcall, tyret, ec, ep); + /* Do not do "no side effect" calls if a hidden parameter is passed, + * as the return value is stored through the hidden parameter, which + * is a side effect. + */ + e = el_bin((tf.ispure && tf.isnothrow && (retmethod != RET.RETstack)) ? + OPcallns : OPcall, tyret, ec, ep); else - e = el_una((tf.ispure && tf.isnothrow) ? OPER.OPucallns : OPER.OPucall, tyret, ec); + e = el_una((tf.ispure && tf.isnothrow && (retmethod != RET.RETstack)) ? + OPucallns : OPucall, tyret, ec); if (retmethod == RET.RETstack) { diff -r 4251f96733f4 -r af1bebfd96a4 dmd/expression/Util.d --- a/dmd/expression/Util.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/expression/Util.d Mon Sep 13 22:19:42 2010 +0100 @@ -594,12 +594,12 @@ * 3. do default promotions on arguments corresponding to ... * 4. add hidden _arguments[] argument * 5. call copy constructor for struct value arguments + * Returns: + * return type from function */ -void functionParameters(Loc loc, Scope sc, TypeFunction tf, Expressions arguments) +Type functionParameters(Loc loc, Scope sc, TypeFunction tf, Expressions arguments) { - uint n; - //printf("functionParameters()\n"); assert(arguments); size_t nargs = arguments ? arguments.dim : 0; @@ -608,8 +608,10 @@ if (nargs > nparams && tf.varargs == 0) error(loc, "expected %zu arguments, not %zu for non-variadic function type %s", nparams, nargs, tf.toChars()); - n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams) + uint n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams) + uint wildmatch = 0; + int done = 0; for (size_t i = 0; i < n; i++) { @@ -634,7 +636,7 @@ goto L2; error(loc, "expected %d function arguments, not %d", nparams, nargs); - return; + return tf.next; } arg = p.defaultArg; arg = arg.copy(); @@ -654,7 +656,7 @@ if (nargs != nparams) { error(loc, "expected %zu function arguments, not %zu", nparams, nargs); - return; + return tf.next; } goto L1; } @@ -680,6 +682,7 @@ Type t = new TypeSArray((cast(TypeArray)tb).next, new IntegerExp(nargs - i)); t = t.semantic(loc, sc); VarDeclaration v = new VarDeclaration(loc, t, id, new VoidInitializer(loc)); + v.storage_class |= STCctfe; v.semantic(sc); v.parent = sc.parent; //sc.insert(v); @@ -729,7 +732,7 @@ if (!arg) { error(loc, "not enough arguments"); - return; + return tf.next; } break; } @@ -748,7 +751,25 @@ //printf("arg.type = %s, p.type = %s\n", arg.type.toChars(), p.type.toChars()); if (arg.op == TOKtype) arg.error("cannot pass type %s as function argument", arg.toChars()); - arg = arg.implicitCastTo(sc, p.type); + if (p.type.isWild() && tf.next.isWild()) + { + Type t = p.type; + MATCH m = arg.implicitConvTo(t); + if (m == MATCH.MATCHnomatch) + { + t = t.constOf(); + m = arg.implicitConvTo(t); + if (m == MATCHnomatch) + { + t = t.sharedConstOf(); + m = arg.implicitConvTo(t); + } + wildmatch |= p.type.wildMatch(arg.type); + } + arg = arg.implicitCastTo(sc, t); + } + else + arg = arg.implicitCastTo(sc, p.type); arg = arg.optimize(WANT.WANTvalue); } } @@ -848,14 +869,9 @@ TypeSArray ts = cast(TypeSArray)tb; Type ta = ts.next.arrayOf(); if (ts.size(arg.loc) == 0) - { - arg = new NullExp(arg.loc); - arg.type = ta; - } + arg = new NullExp(arg.loc, ta); else - { arg = arg.castTo(sc, ta); - } } version (DMDV2) { if (tb.ty == Tstruct) @@ -893,6 +909,24 @@ auto e = createTypeInfoArray(sc, &arguments[nparams], arguments.dim - nparams); arguments.insert(0, e); } + + Type tret = tf.next; + if (wildmatch) + { /* Adjust function return type based on wildmatch + */ + //printf("wildmatch = x%x\n", wildmatch); + assert(tret.isWild()); + if (wildmatch & MOD.MODconst || wildmatch & (wildmatch - 1)) + tret = tret.constOf(); + else if (wildmatch & MOD.MODimmutable) + tret = tret.invariantOf(); + else + { + assert(wildmatch & MOD.MODmutable); + tret = tret.mutableOf(); + } + } + return tret; } /****************************** @@ -1256,7 +1290,7 @@ if (!v) return e; - if (v.isConst() || v.isInvariant() || v.storage_class & STC.STCmanifest) + if (v.isConst() || v.isImmutable() || v.storage_class & STC.STCmanifest) { if (!v.type) { @@ -1403,6 +1437,7 @@ break; } + Dsymbol s; AggregateDeclaration ad; auto arg = arguments[0]; @@ -1449,6 +1484,10 @@ goto Laggr; Laggr: + s = search_function(ad, (op == TOKforeach_reverse) ? Id.applyReverse : Id.apply); + if (s) + goto Lapply; // prefer opApply + if (arguments.dim == 1) { if (!arg.type) @@ -1456,11 +1495,11 @@ /* Look for a head() or rear() overload */ Identifier id = (op == TOK.TOKforeach) ? Id.Fhead : Id.Ftoe; - Dsymbol s = search_function(ad, id); - FuncDeclaration fd = s ? s.isFuncDeclaration() : null; + Dsymbol s1 = search_function(ad, id); + FuncDeclaration fd = s1 ? s1.isFuncDeclaration() : null; if (!fd) { - if (s && s.isTemplateDeclaration()) + if (s1 && s1.isTemplateDeclaration()) break; goto Lapply; } @@ -1474,7 +1513,6 @@ * int opApply(int delegate(ref Type [, ...]) dg); * overload */ - Dsymbol s = search_function(ad, (op == TOK.TOKforeach_reverse) ? Id.applyReverse : Id.apply); if (s) { FuncDeclaration fd = s.isFuncDeclaration(); diff -r 4251f96733f4 -r af1bebfd96a4 dmd/interpret/Util.d --- a/dmd/interpret/Util.d Sat Sep 11 13:03:39 2010 +0100 +++ b/dmd/interpret/Util.d Mon Sep 13 22:19:42 2010 +0100 @@ -140,7 +140,7 @@ if (v) { ///version (DMDV2) { - if ((v.isConst() || v.isInvariant() || v.storage_class & STCmanifest) && v.init && !v.value) + if ((v.isConst() || v.isImmutable() || v.storage_class & STCmanifest) && v.init && !v.value) ///} else { /// if (v.isConst() && v.init) ///} @@ -152,7 +152,7 @@ else { e = v.value; - if (v.isDataseg()) + if (v.isCTFE()) { error(loc, "static variable %s cannot be read at compile time", v.toChars()); e = EXP_CANT_INTERPRET; @@ -232,24 +232,6 @@ /******************************** - * Necessary because defaultInit() for a struct is a VarExp, not a StructLiteralExp. - */ -StructLiteralExp createDefaultInitStructLiteral(Loc loc, StructDeclaration sym) -{ - Expressions structelems = new Expressions(); - structelems.setDim(sym.fields.dim); - for (size_t j = 0; j < structelems.dim; j++) - { - structelems[j] = sym.fields[j].type.defaultInit(Loc(0)); - } - StructLiteralExp structinit = new StructLiteralExp(loc, sym, structelems); - // Why doesn't the StructLiteralExp constructor do this, when - // sym.type != null ? - structinit.type = sym.type; - return structinit; -} - -/******************************** * Add v to the istate list, unless it already exists there. */ void addVarToInterstate(InterState istate, VarDeclaration v)