# HG changeset patch # User korDen # Date 1283010161 -14400 # Node ID ef02e2e203c2973f9fc12fe9d6a043b7e6f3f5e6 # Parent 2e2a5c3f943a94c067208bfbb8216cbc9a775fe9 Updating to dmd2.033 diff -r 2e2a5c3f943a -r ef02e2e203c2 commands.txt --- a/commands.txt Sat Aug 28 16:19:48 2010 +0200 +++ b/commands.txt Sat Aug 28 19:42:41 2010 +0400 @@ -14,10 +14,10 @@ -version=SEH -version=OMFOBJ -version=SNAN_DEFAULT_INIT --ofbin\dmd.exe +-ofC:\dmd2.033\windows\bin\dmd.exe bridge.obj ddmd.def -dmd.lib +C:\dmd2.033\src\dmd\dmd.lib main.d dbg\CallStackInfo.d dbg\Debug.d @@ -333,6 +333,7 @@ dmd\TypeTypeof.d dmd\TypedefDeclaration.d dmd\TypeInfoTupleDeclaration +dmd\TypeInfoFunctionDeclaration dmd\UnionDeclaration.d dmd\UnitTestDeclaration.d dmd\Utf.d diff -r 2e2a5c3f943a -r ef02e2e203c2 dbg/CallStackInfo.d --- a/dbg/CallStackInfo.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dbg/CallStackInfo.d Sat Aug 28 19:42:41 2010 +0400 @@ -193,7 +193,7 @@ alias LONG function(EXCEPTION_POINTERS*) PTOP_LEVEL_EXCEPTION_FILTER; extern (Windows) PTOP_LEVEL_EXCEPTION_FILTER SetUnhandledExceptionFilter(PTOP_LEVEL_EXCEPTION_FILTER); -void append(T)(T[] array, ref size_t index, T value) +void append(T)(ref T[] array, ref size_t index, T value) { size_t capacity = array.length; assert(capacity >= index); @@ -201,8 +201,10 @@ if (capacity < 8) { capacity = 8; } else { - array.length = capacity * 2; + capacity *= 2; } + + array.length = capacity; } array[index++] = value; diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/AddAssignExp.d --- a/dmd/AddAssignExp.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/AddAssignExp.d Sat Aug 28 19:42:41 2010 +0400 @@ -126,6 +126,7 @@ typeCombine(sc); e1.checkArithmetic(); e2.checkArithmetic(); + checkComplexAddAssign(); if (type.isreal() || type.isimaginary()) { diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/ArrayInitializer.d --- a/dmd/ArrayInitializer.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/ArrayInitializer.d Sat Aug 28 19:42:41 2010 +0400 @@ -158,6 +158,7 @@ /******************************** * If possible, convert array initializer to array literal. + * Otherwise return null. */ override Expression toExpression() { @@ -238,9 +239,7 @@ } Lno: - delete elements; - error(loc, "array initializers as expressions are not allowed"); - return new ErrorExp(); + return null; } Initializer toAssocArrayInitializer() diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/BinExp.d --- a/dmd/BinExp.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/BinExp.d Sat Aug 28 19:42:41 2010 +0400 @@ -1328,6 +1328,46 @@ { return e1.canThrow() || e2.canThrow(); } + + // generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary + void checkComplexMulAssign() + { + // Any multiplication by an imaginary or complex number yields a complex result. + // r *= c, i*=c, r*=i, i*=i are all forbidden operations. + string opstr = Token.toChars(op); + if ( e1.type.isreal() && e2.type.iscomplex()) + { + error("%s %s %s is undefined. Did you mean %s %s %s.re ?", + e1.type.toChars(), opstr, e2.type.toChars(), + e1.type.toChars(), opstr, e2.type.toChars()); + } + else if (e1.type.isimaginary() && e2.type.iscomplex()) + { + error("%s %s %s is undefined. Did you mean %s %s %s.im ?", + e1.type.toChars(), opstr, e2.type.toChars(), + e1.type.toChars(), opstr, e2.type.toChars()); + } + else if ((e1.type.isreal() || e1.type.isimaginary()) && e2.type.isimaginary()) + { + error("%s %s %s is an undefined operation", e1.type.toChars(), + opstr, e2.type.toChars()); + } + } + + // generate an error if this is a nonsensical += or -=, eg real += imaginary + void checkComplexAddAssign() + { + // Addition or subtraction of a real and an imaginary is a complex result. + // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations. + if ( (e1.type.isreal() && (e2.type.isimaginary() || e2.type.iscomplex())) || + (e1.type.isimaginary() && (e2.type.isreal() || e2.type.iscomplex())) + ) + { + error("%s %s %s is undefined (result is complex)", + e1.type.toChars(), Token.toChars(op), e2.type.toChars()); + } + } + /*********************************** * Construct the array operation expression. @@ -1335,6 +1375,13 @@ Expression arrayOp(Scope sc) { //printf("BinExp.arrayOp() %s\n", toChars()); + + if (type.toBasetype().nextOf().toBasetype().ty == Tvoid) + { + error("Cannot perform array operations on void[] arrays"); + return new ErrorExp(); + } + Expressions arguments = new Expressions(); /* The expression to generate an array operation for is mangled diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/CallExp.d --- a/dmd/CallExp.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/CallExp.d Sat Aug 28 19:42:41 2010 +0400 @@ -93,9 +93,11 @@ super(loc, TOK.TOKcall, CallExp.sizeof, e); Expressions arguments = new Expressions(); - arguments.setDim(1); - arguments.data[0] = cast(void*)earg1; - + if (earg1) + { + arguments.setDim(1); + arguments.data[0] = cast(void*)earg1; + } this.arguments = arguments; } @@ -734,7 +736,7 @@ accessCheck(loc, sc, null, f); ve.var = f; - // ve.hasOverloads = 0; + // ve.hasOverloads = false; ve.type = f.type; t1 = f.type; } diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/CastExp.d --- a/dmd/CastExp.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/CastExp.d Sat Aug 28 19:42:41 2010 +0400 @@ -3,6 +3,7 @@ import dmd.Expression; import dmd.TY; import dmd.TypeStruct; +import dmd.ErrorExp; import dmd.TypeExp; import dmd.DotIdExp; import dmd.CallExp; @@ -84,50 +85,63 @@ super.semantic(sc); if (e1.type) // if not a tuple { - e1 = resolveProperties(sc, e1); + e1 = resolveProperties(sc, e1); + + if (!to) + { + /* Handle cast(const) and cast(immutable), etc. + */ + to = e1.type.castMod(mod); + } + else + to = to.semantic(loc, sc); + + if (!to.equals(e1.type)) + { + e = op_overload(sc); + if (e) + { + return e.implicitCastTo(sc, to); + } + } - if (!to) - { - /* Handle cast(const) and cast(immutable), etc. - */ - to = e1.type.castMod(mod); - } - else - to = to.semantic(loc, sc); + Type t1b = e1.type.toBasetype(); + Type tob = to.toBasetype(); + if (tob.ty == TY.Tstruct && + !tob.equals(t1b) && + (cast(TypeStruct)tob).sym.search(Loc(0), Id.call, 0) + ) + { + /* Look to replace: + * cast(S)t + * with: + * S(t) + */ - if (!to.equals(e1.type)) - { - e = op_overload(sc); - if (e) + // Rewrite as to.call(e1) + e = new TypeExp(loc, to); + e = new DotIdExp(loc, e, Id.call); + e = new CallExp(loc, e, e1); + e = e.semantic(sc); + return e; + } + + // Struct casts are possible only when the sizes match + if (tob.ty == Tstruct || t1b.ty == Tstruct) { - return e.implicitCastTo(sc, to); + size_t fromsize = cast(size_t)t1b.size(loc); + size_t tosize = cast(size_t)tob.size(loc); + if (fromsize != tosize) + { + error("cannot cast from %s to %s", e1.type.toChars(), to.toChars()); + return new ErrorExp(); + } } } - - Type t1b = e1.type.toBasetype(); - Type tob = to.toBasetype(); - if (tob.ty == TY.Tstruct && - !tob.equals(t1b) && - (cast(TypeStruct)tob).sym.search(Loc(0), Id.call, 0) - ) - { - /* Look to replace: - * cast(S)t - * with: - * S(t) - */ - - // Rewrite as to.call(e1) - e = new TypeExp(loc, to); - e = new DotIdExp(loc, e, Id.call); - e = new CallExp(loc, e, e1); - e = e.semantic(sc); - return e; - } - } else if (!to) - { error("cannot cast tuple"); - to = Type.terror; + { + error("cannot cast tuple"); + to = Type.terror; } if (global.params.safe && !sc.module_.safe && !sc.intypeof) @@ -212,9 +226,14 @@ break; default: } - ir.imin &= type.sizemask(); - ir.imax &= type.sizemask(); - //printf("CastExp: imin = x%llx, imax = x%llx\n", ir.imin, ir.imax); + + if (type.isintegral()) + { + ir.imin &= type.sizemask(); + ir.imax &= type.sizemask(); + } + + //printf("CastExp: imin = x%llx, imax = x%llx\n", ir.imin, ir.imax); return ir; } diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/ClassDeclaration.d --- a/dmd/ClassDeclaration.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/ClassDeclaration.d Sat Aug 28 19:42:41 2010 +0400 @@ -1,1904 +1,1936 @@ -module dmd.ClassDeclaration; - -import dmd.AggregateDeclaration; -import dmd.InterfaceDeclaration; -import dmd.ThisDeclaration; -import dmd.CompoundStatement; -import dmd.DeleteDeclaration; -import dmd.NewDeclaration; -import dmd.CtorDeclaration; -import dmd.TypeIdentifier; -import dmd.STC; -import dmd.Argument; -import dmd.TypeTuple; -import dmd.TY; -import dmd.LINK; -import dmd.DsymbolTable; -import dmd.FuncDeclaration; -import dmd.Array; -import dmd.TypeClass; -import dmd.Module; -import dmd.Id; -import dmd.Type; -import dmd.OverloadSet; -import dmd.ArrayTypes; -import dmd.BaseClass; -import dmd.ClassInfoDeclaration; -import dmd.Loc; -import dmd.Identifier; -import dmd.Dsymbol; -import dmd.Scope; -import dmd.TypeFunction; -import dmd.OutBuffer; -import dmd.HdrGenState; -import dmd.VarDeclaration; -import dmd.Initializer; -import dmd.ExpInitializer; -import dmd.TypeSArray; -import dmd.ScopeDsymbol; -import dmd.PROT; -import dmd.Util; -import dmd.Global; - -import dmd.expression.Util; - -import dmd.backend.Symbol; -import dmd.backend.dt_t; -import dmd.backend.TYPE; -import dmd.backend.FL; -import dmd.backend.SFL; -import dmd.backend.mTY; -import dmd.backend.SC; -import dmd.backend.mTYman; -import dmd.backend.Util; -import dmd.backend.TYM; -import dmd.backend.Classsym; -import dmd.backend.glue; -import dmd.backend.RTLSYM; -import dmd.backend.LIST; - -import dmd.codegen.Util; - -import std.string; - -version (DMDV2) { - enum CLASSINFO_SIZE = (0x3C+16+4); // value of ClassInfo.size -} else { - enum CLASSINFO_SIZE = (0x3C+12+4); // value of ClassInfo.size -} - -enum OFFSET_RUNTIME = 0x76543210; - -struct Param -{ - int isf(void*, FuncDeclaration fd2) - { - //printf("param = %p, fd = %p %s\n", param, fd, fd.toChars()); - return fd is fd2; - } - - FuncDeclaration fd; -} - -class ClassDeclaration : AggregateDeclaration -{ - static __gshared ClassDeclaration object; - static __gshared ClassDeclaration classinfo; - - ClassDeclaration baseClass; // null only if this is Object - FuncDeclaration staticCtor; - FuncDeclaration staticDtor; - Array vtbl; // Array of FuncDeclaration's making up the vtbl[] - Array vtblFinal; // More FuncDeclaration's that aren't in vtbl[] - - BaseClasses baseclasses; // Array of BaseClass's; first is super, - // rest are Interface's - - int interfaces_dim; - BaseClass* interfaces; // interfaces[interfaces_dim] for this class - // (does not include baseClass) - - BaseClasses vtblInterfaces; // array of base interfaces that have - // their own vtbl[] - - ClassInfoDeclaration vclassinfo; // the ClassInfo object for this ClassDeclaration - bool com; // true if this is a COM class (meaning - // it derives from IUnknown) - bool isauto; // true if this is an auto class - bool isabstract; // true if abstract class - - int inuse; // to prevent recursive attempts - - this(Loc loc, Identifier id, BaseClasses baseclasses) - { - super(loc, id); - - vtbl = new Array(); - vtblFinal = new Array(); - - enum msg = "only object.d can define this reserved class name"; - - if (baseclasses) { - this.baseclasses = baseclasses; - } else { - this.baseclasses = new BaseClasses(); - } - - //printf("ClassDeclaration(%s), dim = %d\n", id.toChars(), this.baseclasses.dim); - - // For forward references - type = new TypeClass(this); - - if (id) - { - // Look for special class names - - if (id is Id.__sizeof || id is Id.alignof_ || id is Id.mangleof_) - error("illegal class name"); - - // BUG: What if this is the wrong TypeInfo, i.e. it is nested? - if (id.toChars()[0] == 'T') - { - if (id is Id.TypeInfo) - { - if (Type.typeinfo) - Type.typeinfo.error("%s", msg); - Type.typeinfo = this; - } - - if (id is Id.TypeInfo_Class) - { - if (Type.typeinfoclass) - Type.typeinfoclass.error("%s", msg); - Type.typeinfoclass = this; - } - - if (id is Id.TypeInfo_Interface) - { - if (Type.typeinfointerface) - Type.typeinfointerface.error("%s", msg); - Type.typeinfointerface = this; - } - - if (id is Id.TypeInfo_Struct) - { - if (Type.typeinfostruct) - Type.typeinfostruct.error("%s", msg); - Type.typeinfostruct = this; - } - - if (id is Id.TypeInfo_Typedef) - { - if (Type.typeinfotypedef) - Type.typeinfotypedef.error("%s", msg); - Type.typeinfotypedef = this; - } - - if (id is Id.TypeInfo_Pointer) - { - if (Type.typeinfopointer) - Type.typeinfopointer.error("%s", msg); - Type.typeinfopointer = this; - } - - if (id is Id.TypeInfo_Array) - { - if (Type.typeinfoarray) - Type.typeinfoarray.error("%s", msg); - Type.typeinfoarray = this; - } - - if (id is Id.TypeInfo_StaticArray) - { //if (Type.typeinfostaticarray) - //Type.typeinfostaticarray.error("%s", msg); - Type.typeinfostaticarray = this; - } - - if (id is Id.TypeInfo_AssociativeArray) - { - if (Type.typeinfoassociativearray) - Type.typeinfoassociativearray.error("%s", msg); - Type.typeinfoassociativearray = this; - } - - if (id is Id.TypeInfo_Enum) - { - if (Type.typeinfoenum) - Type.typeinfoenum.error("%s", msg); - Type.typeinfoenum = this; - } - - if (id is Id.TypeInfo_Function) - { - if (Type.typeinfofunction) - Type.typeinfofunction.error("%s", msg); - Type.typeinfofunction = this; - } - - if (id is Id.TypeInfo_Delegate) - { - if (Type.typeinfodelegate) - Type.typeinfodelegate.error("%s", msg); - Type.typeinfodelegate = this; - } - - if (id is Id.TypeInfo_Tuple) - { - if (Type.typeinfotypelist) - Type.typeinfotypelist.error("%s", msg); - Type.typeinfotypelist = this; - } - - version (DMDV2) { - if (id is Id.TypeInfo_Const) - { - if (Type.typeinfoconst) - Type.typeinfoconst.error("%s", msg); - Type.typeinfoconst = this; - } - - if (id is Id.TypeInfo_Invariant) - { - if (Type.typeinfoinvariant) - Type.typeinfoinvariant.error("%s", msg); - Type.typeinfoinvariant = this; - } - - if (id is Id.TypeInfo_Shared) - { - if (Type.typeinfoshared) - Type.typeinfoshared.error("%s", msg); - Type.typeinfoshared = this; - } - } - } - - if (id is Id.Object_) - { - if (object) - object.error("%s", msg); - object = this; - } - - if (id is Id.ClassInfo) - { - if (classinfo) - classinfo.error("%s", msg); - classinfo = this; - } - - if (id is Id.ModuleInfo) - { - if (Module.moduleinfo) - Module.moduleinfo.error("%s", msg); - Module.moduleinfo = this; - } - } - - com = 0; - isauto = false; - isabstract = false; - inuse = 0; - } - - override Dsymbol syntaxCopy(Dsymbol s) - { - ClassDeclaration cd; - - //printf("ClassDeclaration.syntaxCopy('%s')\n", toChars()); - if (s) - cd = cast(ClassDeclaration)s; - else - cd = new ClassDeclaration(loc, ident, null); - - cd.storage_class |= storage_class; - - cd.baseclasses.setDim(this.baseclasses.dim); - for (int i = 0; i < cd.baseclasses.dim; i++) - { - BaseClass b = cast(BaseClass)this.baseclasses.data[i]; - BaseClass b2 = new BaseClass(b.type.syntaxCopy(), b.protection); - cd.baseclasses.data[i] = cast(void*)b2; - } - - ScopeDsymbol.syntaxCopy(cd); - return cd; - } - - override void semantic(Scope sc) - { - int i; - uint offset; - - //printf("ClassDeclaration.semantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this); - //printf("\tparent = %p, '%s'\n", sc.parent, sc.parent ? sc.parent.toChars() : ""); - //printf("sc.stc = %x\n", sc.stc); - - //{ static int n; if (++n == 20) *(char*)0=0; } - - if (!ident) // if anonymous class - { - string id = "__anonclass"; - ident = Identifier.generateId(id); - } - - if (!sc) - sc = scope_; - - if (!parent && sc.parent && !sc.parent.isModule()) - parent = sc.parent; - - type = type.semantic(loc, sc); - handle = type; - - if (!members) // if forward reference - { - //printf("\tclass '%s' is forward referenced\n", toChars()); - return; - } - if (symtab) - { if (!scope_) - { //printf("\tsemantic for '%s' is already completed\n", toChars()); - return; // semantic() already completed - } - } - else - symtab = new DsymbolTable(); - - Scope scx = null; - if (scope_) - { sc = scope_; - scx = scope_; // save so we don't make redundant copies - scope_ = null; - } -version (IN_GCC) { - methods.setDim(0); -} - - if (sc.stc & STC.STCdeprecated) - { - isdeprecated = 1; - } - - if (sc.linkage == LINK.LINKcpp) - error("cannot create C++ classes"); - - // Expand any tuples in baseclasses[] - for (i = 0; i < baseclasses.dim; ) - { - BaseClass b = cast(BaseClass)baseclasses.data[i]; - //printf("test1 %s %s\n", toChars(), b.type.toChars()); - b.type = b.type.semantic(loc, sc); - //printf("test2\n"); - Type tb = b.type.toBasetype(); - - if (tb.ty == TY.Ttuple) - { - TypeTuple tup = cast(TypeTuple)tb; - enum PROT protection = b.protection; - baseclasses.remove(i); - size_t dim = Argument.dim(tup.arguments); - for (size_t j = 0; j < dim; j++) - { - Argument arg = Argument.getNth(tup.arguments, j); - b = new BaseClass(arg.type, protection); - baseclasses.insert(i + j, cast(void*)b); - } - } - else - i++; - } - - // See if there's a base class as first in baseclasses[] - if (baseclasses.dim) - { - TypeClass tc; - BaseClass b; - Type tb; - - b = cast(BaseClass)baseclasses.data[0]; - //b.type = b.type.semantic(loc, sc); - tb = b.type.toBasetype(); - if (tb.ty != TY.Tclass) - { error("base type must be class or interface, not %s", b.type.toChars()); - baseclasses.remove(0); - } - else - { - tc = cast(TypeClass)(tb); - - if (tc.sym.isDeprecated()) - { - if (!isDeprecated()) - { - // Deriving from deprecated class makes this one deprecated too - isdeprecated = 1; - - tc.checkDeprecated(loc, sc); - } - } - - if (tc.sym.isInterfaceDeclaration()) { - ; - } else { - for (ClassDeclaration cdb = tc.sym; cdb; cdb = cdb.baseClass) - { - if (cdb == this) - { - error("circular inheritance"); - baseclasses.remove(0); - goto L7; - } - } - if (!tc.sym.symtab || tc.sym.sizeok == 0) - { // Try to resolve forward reference - if (sc.mustsemantic && tc.sym.scope_) - tc.sym.semantic(null); - } - if (!tc.sym.symtab || tc.sym.scope_ || tc.sym.sizeok == 0) - { - //printf("%s: forward reference of base class %s\n", toChars(), tc.sym.toChars()); - //error("forward reference of base class %s", baseClass.toChars()); - // Forward reference of base class, try again later - //printf("\ttry later, forward reference of base class %s\n", tc.sym.toChars()); - scope_ = scx ? scx : new Scope(sc); - scope_.setNoFree(); - if (tc.sym.scope_) - tc.sym.scope_.module_.addDeferredSemantic(tc.sym); - scope_.module_.addDeferredSemantic(this); - return; - } - else - { baseClass = tc.sym; - b.base = baseClass; - } - L7: ; - } - } - } - - // Treat the remaining entries in baseclasses as interfaces - // Check for errors, handle forward references - for (i = (baseClass ? 1 : 0); i < baseclasses.dim; ) - { TypeClass tc; - BaseClass b; - Type tb; - - b = cast(BaseClass)baseclasses.data[i]; - b.type = b.type.semantic(loc, sc); - tb = b.type.toBasetype(); - if (tb.ty == TY.Tclass) - tc = cast(TypeClass)tb; - else - tc = null; - if (!tc || !tc.sym.isInterfaceDeclaration()) - { - error("base type must be interface, not %s", b.type.toChars()); - baseclasses.remove(i); - continue; - } - else - { - if (tc.sym.isDeprecated()) - { - if (!isDeprecated()) - { - // Deriving from deprecated class makes this one deprecated too - isdeprecated = 1; - - tc.checkDeprecated(loc, sc); - } - } - - // Check for duplicate interfaces - for (size_t j = (baseClass ? 1 : 0); j < i; j++) - { - BaseClass b2 = cast(BaseClass)baseclasses.data[j]; - if (b2.base == tc.sym) - error("inherits from duplicate interface %s", b2.base.toChars()); - } - - if (!tc.sym.symtab) - { // Try to resolve forward reference - if (sc.mustsemantic && tc.sym.scope_) - tc.sym.semantic(null); - } - - b.base = tc.sym; - if (!b.base.symtab || b.base.scope_) - { - //error("forward reference of base class %s", baseClass.toChars()); - // Forward reference of base, try again later - //printf("\ttry later, forward reference of base %s\n", baseClass.toChars()); - scope_ = scx ? scx : new Scope(sc); - scope_.setNoFree(); - if (tc.sym.scope_) - tc.sym.scope_.module_.addDeferredSemantic(tc.sym); - scope_.module_.addDeferredSemantic(this); - return; - } - } - i++; - } - - - // If no base class, and this is not an Object, use Object as base class - if (!baseClass && ident !is Id.Object_) - { - // BUG: what if Object is redefined in an inner scope? - Type tbase = new TypeIdentifier(Loc(0), Id.Object_); - BaseClass b; - TypeClass tc; - Type bt; - - if (!object) - { - error("missing or corrupt object.d"); - fatal(); - } - bt = tbase.semantic(loc, sc).toBasetype(); - b = new BaseClass(bt, PROT.PROTpublic); - baseclasses.shift(cast(void*)b); - assert(b.type.ty == TY.Tclass); - tc = cast(TypeClass)(b.type); - baseClass = tc.sym; - assert(!baseClass.isInterfaceDeclaration()); - b.base = baseClass; - } - - interfaces_dim = baseclasses.dim; - interfaces = cast(BaseClass*)baseclasses.data; - - if (baseClass) - { - if (baseClass.storage_class & STC.STCfinal) - error("cannot inherit from final class %s", baseClass.toChars()); - - interfaces_dim--; - interfaces++; - - // Copy vtbl[] from base class - vtbl.setDim(baseClass.vtbl.dim); - memcpy(vtbl.data, baseClass.vtbl.data, (void*).sizeof * vtbl.dim); - - // Inherit properties from base class - com = baseClass.isCOMclass(); - isauto = baseClass.isauto; - vthis = baseClass.vthis; - storage_class |= baseClass.storage_class & STC.STC_TYPECTOR; - } - else - { - // No base class, so this is the root of the class hierarchy - vtbl.setDim(0); - vtbl.push(cast(void*)this); // leave room for classinfo as first member - } - - protection = sc.protection; - storage_class |= sc.stc; - - if (sizeok == 0) - { - interfaceSemantic(sc); - - for (i = 0; i < members.dim; i++) - { - Dsymbol s = cast(Dsymbol)members.data[i]; - s.addMember(sc, this, true); - } - - /* If this is a nested class, add the hidden 'this' - * member which is a pointer to the enclosing scope. - */ - if (vthis) // if inheriting from nested class - { // Use the base class's 'this' member - isnested = true; - if (storage_class & STC.STCstatic) - error("static class cannot inherit from nested class %s", baseClass.toChars()); - if (toParent2() != baseClass.toParent2()) - { - if (toParent2()) - { - error("is nested within %s, but super class %s is nested within %s", - toParent2().toChars(), - baseClass.toChars(), - baseClass.toParent2().toChars()); - } - else - { - error("is not nested, but super class %s is nested within %s", - baseClass.toChars(), - baseClass.toParent2().toChars()); - } - isnested = false; - } - } - else if (!(storage_class & STC.STCstatic)) - { - Dsymbol s = toParent2(); - if (s) - { - AggregateDeclaration ad = s.isClassDeclaration(); - FuncDeclaration fd = s.isFuncDeclaration(); - - if (ad || fd) - { isnested = true; - Type t; - if (ad) - t = ad.handle; - else if (fd) - { - AggregateDeclaration ad2 = fd.isMember2(); - if (ad2) - t = ad2.handle; - else - { - t = Type.tvoidptr; - } - } - else - assert(0); - if (t.ty == TY.Tstruct) // ref to struct - t = Type.tvoidptr; - assert(!vthis); - vthis = new ThisDeclaration(loc, t); - members.push(cast(void*)vthis); - } - } - } - } - - if (storage_class & (STC.STCauto | STC.STCscope)) - isauto = true; - if (storage_class & STC.STCabstract) - isabstract = true; - if (storage_class & STC.STCimmutable) - type = type.invariantOf(); - else if (storage_class & STC.STCconst) - type = type.constOf(); - else if (storage_class & STC.STCshared) - type = type.sharedOf(); - - sc = sc.push(this); - sc.stc &= ~(STC.STCfinal | STC.STCauto | STC.STCscope | STC.STCstatic | - STC.STCabstract | STC.STCdeprecated | STC.STC_TYPECTOR | STC.STCtls | STC.STCgshared); - sc.stc |= storage_class & STC.STC_TYPECTOR; - sc.parent = this; - sc.inunion = 0; - - if (isCOMclass()) - { -version (_WIN32) { - sc.linkage = LINK.LINKwindows; -} else { - /* This enables us to use COM objects under Linux and - * work with things like XPCOM - */ - sc.linkage = LINK.LINKc; -} - } - sc.protection = PROT.PROTpublic; - sc.explicitProtection = 0; - sc.structalign = 8; - structalign = sc.structalign; - if (baseClass) - { sc.offset = baseClass.structsize; - alignsize = baseClass.alignsize; - // if (isnested) - // sc.offset += PTRSIZE; // room for uplevel context pointer - } - else - { sc.offset = PTRSIZE * 2; // allow room for __vptr and __monitor - alignsize = PTRSIZE; - } - structsize = sc.offset; - Scope scsave = sc; /// a copy must be created? - int members_dim = members.dim; - sizeok = 0; - for (i = 0; i < members_dim; i++) - { - Dsymbol s = cast(Dsymbol)members.data[i]; - s.semantic(sc); - } - - if (sizeok == 2) - { // semantic() failed because of forward references. - // Unwind what we did, and defer it for later - fields.setDim(0); - structsize = 0; - alignsize = 0; - structalign = 0; - - sc = sc.pop(); - - scope_ = scx ? scx : new Scope(sc); - scope_.setNoFree(); - scope_.module_.addDeferredSemantic(this); - - //printf("\tsemantic('%s') failed due to forward references\n", toChars()); - return; - } - - //printf("\tsemantic('%s') successful\n", toChars()); - - structsize = sc.offset; - //members.print(); - - /* Look for special member functions. - * They must be in this class, not in a base class. - */ - ctor = cast(CtorDeclaration)search(Loc(0), Id.ctor, 0); - if (ctor && (ctor.toParent() != this || !ctor.isCtorDeclaration())) - ctor = null; - - // dtor = (DtorDeclaration *)search(Id.dtor, 0); - // if (dtor && dtor.toParent() != this) - // dtor = null; - - // inv = (InvariantDeclaration *)search(Id.classInvariant, 0); - // if (inv && inv.toParent() != this) - // inv = null; - - // Can be in base class - aggNew = cast(NewDeclaration)search(Loc(0), Id.classNew, 0); - aggDelete = cast(DeleteDeclaration)search(Loc(0), Id.classDelete, 0); - - // If this class has no constructor, but base class does, create - // a constructor: - // this() { } - if (!ctor && baseClass && baseClass.ctor) - { - //printf("Creating default this(){} for class %s\n", toChars()); - CtorDeclaration ctor = new CtorDeclaration(loc, Loc(0), null, 0); - ctor.fbody = new CompoundStatement(Loc(0), new Statements()); - members.push(cast(void*)ctor); - ctor.addMember(sc, this, true); - sc = scsave; // why? What about sc.nofree? /// - sc.offset = structsize; - ctor.semantic(sc); - this.ctor = ctor; - defaultCtor = ctor; - } - -static if (false) { - if (baseClass) - { if (!aggDelete) - aggDelete = baseClass.aggDelete; - if (!aggNew) - aggNew = baseClass.aggNew; - } -} - - // Allocate instance of each new interface - for (i = 0; i < vtblInterfaces.dim; i++) - { - BaseClass b = cast(BaseClass)vtblInterfaces.data[i]; - uint thissize = PTRSIZE; - - alignmember(structalign, thissize, &sc.offset); - assert(b.offset == 0); - b.offset = sc.offset; - - // Take care of single inheritance offsets - while (b.baseInterfaces.length) - { - b = b.baseInterfaces[0]; - b.offset = sc.offset; - } - - sc.offset += thissize; - if (alignsize < thissize) - alignsize = thissize; - } - structsize = sc.offset; - sizeok = 1; - Module.dprogress++; - - dtor = buildDtor(sc); - - sc.pop(); - -static if (false) { // Do not call until toObjfile() because of forward references - // Fill in base class vtbl[]s - for (i = 0; i < vtblInterfaces.dim; i++) - { - BaseClass b = cast(BaseClass)vtblInterfaces.data[i]; - - //b.fillVtbl(this, &b.vtbl, 1); - } -} - //printf("-ClassDeclaration.semantic(%s), type = %p\n", toChars(), type); - } - - override void toCBuffer(OutBuffer buf, HdrGenState* hgs) - { - assert(false); - } - - /********************************************* - * Determine if 'this' is a base class of cd. - * This is used to detect circular inheritance only. - */ - int isBaseOf2(ClassDeclaration cd) - { - if (!cd) - return 0; - //printf("ClassDeclaration::isBaseOf2(this = '%s', cd = '%s')\n", toChars(), cd.toChars()); - for (int i = 0; i < cd.baseclasses.dim; i++) - { - BaseClass b = cast(BaseClass)cd.baseclasses.data[i]; - - if (b.base is this || isBaseOf2(b.base)) - return 1; - } - return 0; - } - - /******************************************* - * Determine if 'this' is a base class of cd. - */ -/// #define OFFSET_RUNTIME 0x76543210 - bool isBaseOf(ClassDeclaration cd, int* poffset) - { - if (!cd) - return 0; - //printf("ClassDeclaration::isBaseOf2(this = '%s', cd = '%s')\n", toChars(), cd.toChars()); - for (int i = 0; i < cd.baseclasses.dim; i++) - { - BaseClass b = cast(BaseClass)cd.baseclasses.data[i]; - - if (b.base == this || isBaseOf2(b.base)) - return 1; - } - - return 0; - } - - override Dsymbol search(Loc, Identifier ident, int flags) - { - Dsymbol s; - //printf("%s.ClassDeclaration.search('%s')\n", toChars(), ident.toChars()); - - if (scope_) - { - Scope sc = scope_; - sc.mustsemantic++; - semantic(sc); - sc.mustsemantic--; - } - - if (!members || !symtab || scope_) - { - error("is forward referenced when looking for '%s'", ident.toChars()); - //*(char*)0=0; - return null; - } - - s = ScopeDsymbol.search(loc, ident, flags); - if (!s) - { - // Search bases classes in depth-first, left to right order - - int i; - - for (i = 0; i < baseclasses.dim; i++) - { - BaseClass b = cast(BaseClass)baseclasses.data[i]; - - if (b.base) - { - if (!b.base.symtab) - error("base %s is forward referenced", b.base.ident.toChars()); - else - { - s = b.base.search(loc, ident, flags); - if (s is this) // happens if s is nested in this and derives from this - s = null; - else if (s) - break; - } - } - } - } - return s; - } - -version (DMDV2) { - bool isFuncHidden(FuncDeclaration fd) - { - //printf("ClassDeclaration::isFuncHidden(class = %s, fd = %s)\n", toChars(), fd.toChars()); - Dsymbol s = search(Loc(0), fd.ident, 4|2); - if (!s) - { - //printf("not found\n"); - /* Because, due to a hack, if there are multiple definitions - * of fd.ident, null is returned. - */ - return false; - } - - Param p; p.fd = fd; - - s = s.toAlias(); - OverloadSet os = s.isOverloadSet(); - if (os) - { - for (int i = 0; i < os.a.dim; i++) - { - Dsymbol s2 = cast(Dsymbol)os.a.data[i]; - FuncDeclaration f2 = s2.isFuncDeclaration(); - if (f2 && overloadApply(f2, &p.isf, &p)) - return false; - } - return true; - } - else - { - FuncDeclaration fdstart = s.isFuncDeclaration(); - //printf("%s fdstart = %p\n", s.kind(), fdstart); - return !overloadApply(fdstart, &p.isf, &p); - } - } -} - FuncDeclaration findFunc(Identifier ident, TypeFunction tf) - { - //printf("ClassDeclaration.findFunc(%s, %s) %s\n", ident.toChars(), tf.toChars(), toChars()); - - ClassDeclaration cd = this; - Array vtbl = cd.vtbl; - while (true) - { - for (size_t i = 0; i < vtbl.dim; i++) - { - FuncDeclaration fd = (cast(Dsymbol)vtbl.data[i]).isFuncDeclaration(); - if (!fd) - continue; // the first entry might be a ClassInfo - - //printf("\t[%d] = %s\n", i, fd.toChars()); - if (ident == fd.ident && - //tf.equals(fd.type) - fd.type.covariant(tf) == 1 - ) - { //printf("\t\tfound\n"); - return fd; - } - //else printf("\t\t%d\n", fd.type.covariant(tf)); - } - if (!cd) - break; - - vtbl = cd.vtblFinal; - cd = cd.baseClass; - } - - return null; - } - - void interfaceSemantic(Scope sc) - { - InterfaceDeclaration id = isInterfaceDeclaration(); - - vtblInterfaces = new BaseClasses(); - vtblInterfaces.reserve(interfaces_dim); - - for (size_t i = 0; i < interfaces_dim; i++) - { - BaseClass b = interfaces[i]; - - // If this is an interface, and it derives from a COM interface, - // then this is a COM interface too. - if (b.base.isCOMinterface()) - com = 1; - - if (b.base.isCPPinterface() && id) - id.cpp = 1; - - vtblInterfaces.push(cast(void*)b); - b.copyBaseInterfaces(vtblInterfaces); - } - } - - bool isCOMclass() - { - return com; - } - - bool isCOMinterface() - { - return false; - } - -version (DMDV2) { - bool isCPPinterface() - { - return false; - } -} - bool isAbstract() - { - if (isabstract) - return true; - - for (int i = 1; i < vtbl.dim; i++) - { - FuncDeclaration fd = (cast(Dsymbol)vtbl.data[i]).isFuncDeclaration(); - - //printf("\tvtbl[%d] = %p\n", i, fd); - if (!fd || fd.isAbstract()) - { - isabstract = true; - return true; - } - } - - return false; - } - - int vtblOffset() - { - assert(false); - } - - override string kind() - { - return "class"; - } - - override string mangle() - { - Dsymbol parentsave = parent; - - //printf("ClassDeclaration.mangle() %s.%s\n", parent.toChars(), toChars()); - - /* These are reserved to the compiler, so keep simple - * names for them. - */ - if (ident is Id.Exception) - { - if (parent.ident is Id.object) - parent = null; - } - else if (ident is Id.TypeInfo || - // ident is Id.Exception || - ident is Id.TypeInfo_Struct || - ident is Id.TypeInfo_Class || - ident is Id.TypeInfo_Typedef || - ident is Id.TypeInfo_Tuple || - this is object || - this is classinfo || - this is Module.moduleinfo || - ident.toChars().startsWith("TypeInfo_") - ) - { - parent = null; - } - - string id = Dsymbol.mangle(); - parent = parentsave; - return id; - } - - override void toDocBuffer(OutBuffer buf) - { - assert(false); - } - - override PROT getAccess(Dsymbol smember) // determine access to smember - { - PROT access_ret = PROT.PROTnone; - - version (LOG) { - printf("+ClassDeclaration::getAccess(this = '%s', smember = '%s')\n", - toChars(), smember.toChars()); - } - if (smember.toParent() is this) - { - access_ret = smember.prot(); - } - else - { - PROT access; - int i; - - if (smember.isDeclaration().isStatic()) - { - access_ret = smember.prot(); - } - - for (i = 0; i < baseclasses.dim; i++) - { - BaseClass b = cast(BaseClass)baseclasses.data[i]; - - access = b.base.getAccess(smember); - switch (access) - { - case PROT.PROTnone: - break; - - case PROT.PROTprivate: - access = PROT.PROTnone; // private members of base class not accessible - break; - - case PROT.PROTpackage: - case PROT.PROTprotected: - case PROT.PROTpublic: - case PROT.PROTexport: - // If access is to be tightened - if (b.protection < access) - access = b.protection; - - // Pick path with loosest access - if (access > access_ret) - access_ret = access; - break; - - default: - assert(0); - } - } - } - - version (LOG) { - printf("-ClassDeclaration::getAccess(this = '%s', smember = '%s') = %d\n", - toChars(), smember.toChars(), access_ret); - } - - return access_ret; - } - - override void addLocalClass(ClassDeclarations aclasses) - { - aclasses.push(cast(void*)this); - } - - // Back end - override void toObjFile(int multiobj) // compile to .obj file - { - uint i; - uint offset; - Symbol* sinit; - enum_SC scclass; - - //printf("ClassDeclaration.toObjFile('%s')\n", toChars()); - - if (!members) - return; - - if (multiobj) - { - obj_append(this); - return; - } - - if (global.params.symdebug) - toDebug(); - - assert(!scope_); // semantic() should have been run to completion - - scclass = SCglobal; - if (inTemplateInstance()) - scclass = SCcomdat; - - // Put out the members - for (i = 0; i < members.dim; i++) - { - Dsymbol member; - - member = cast(Dsymbol)members.data[i]; - member.toObjFile(0); - } - -static if (false) { - // Build destructor by aggregating dtors[] - Symbol* sdtor; - switch (dtors.dim) - { - case 0: - // No destructors for this class - sdtor = null; - break; - - case 1: - // One destructor, just use it directly - sdtor = (cast(DtorDeclaration)dtors.data[0]).toSymbol(); - break; - - default: - { - /* Build a destructor that calls all the - * other destructors in dtors[]. - */ - - elem* edtor = null; - - // Declare 'this' pointer for our new destructor - Symbol* sthis = symbol_calloc("this"); - sthis.Stype = type_fake(TYnptr); - sthis.Stype.Tcount++; - sthis.Sclass = SCfastpar; - sthis.Spreg = AX; - sthis.Sfl = FLauto; - - // Call each of the destructors in dtors[] - // in reverse order - for (i = 0; i < dtors.dim; i++) - { - DtorDeclaration d = cast(DtorDeclaration)dtors.data[i]; - Symbol* s = d.toSymbol(); - elem* e = el_bin(OPcall, TYvoid, el_var(s), el_var(sthis)); - edtor = el_combine(e, edtor); - } - - // Create type for the function - .type* t = type_alloc(TYjfunc); - t.Tflags |= TFprototype | TFfixed; - t.Tmangle = mTYman_d; - t.Tnext = tsvoid; - tsvoid.Tcount++; - - // Create the function, sdtor, and write it out - localgot = null; - sdtor = toSymbolX("__dtor", SCglobal, t, "FZv"); - block* b = block_calloc(); - b.BC = BCret; - b.Belem = edtor; - sdtor.Sfunc.Fstartblock = b; - cstate.CSpsymtab = &sdtor.Sfunc.Flocsym; - symbol_add(sthis); - writefunc(sdtor); - } - } -} - - // Generate C symbols - toSymbol(); - toVtblSymbol(); - sinit = toInitializer(); - - ////////////////////////////////////////////// - - // Generate static initializer - sinit.Sclass = scclass; - sinit.Sfl = FLdata; - version (ELFOBJ) { // Burton - sinit.Sseg = Segment.CDATA; - } - version (MACHOBJ) { - sinit.Sseg = Segment.DATA; - } - toDt(&sinit.Sdt); - outdata(sinit); - - ////////////////////////////////////////////// - - // Put out the TypeInfo - type.getTypeInfo(null); - type.vtinfo.toObjFile(multiobj); - - ////////////////////////////////////////////// - - // Put out the ClassInfo - csym.Sclass = scclass; - csym.Sfl = FLdata; - - /* The layout is: - { - void **vptr; - monitor_t monitor; - byte[] initializer; // static initialization data - char[] name; // class name - void *[] vtbl; - Interface[] interfaces; - ClassInfo *base; // base class - void *destructor; - void *invariant; // class invariant - uint flags; - void *deallocator; - OffsetTypeInfo[] offTi; - void *defaultConstructor; - const(MemberInfo[]) function(string) xgetMembers; // module getMembers() function - TypeInfo typeinfo; - } - */ - dt_t* dt = null; - offset = CLASSINFO_SIZE; // must be ClassInfo.size - if (classinfo) - { - if (classinfo.structsize != CLASSINFO_SIZE) - error("D compiler and phobos' object.d are mismatched"); - } - - if (classinfo) - dtxoff(&dt, classinfo.toVtblSymbol(), 0, TYnptr); // vtbl for ClassInfo - else - dtdword(&dt, 0); // BUG: should be an assert() - - dtdword(&dt, 0); // monitor - - // initializer[] - assert(structsize >= 8); - dtdword(&dt, structsize); // size - dtxoff(&dt, sinit, 0, TYnptr); // initializer - - // name[] - string name = ident.toChars(); - size_t namelen = name.length; - if (!(namelen > 9 && name[0..9] == "TypeInfo_")) - { - name = toPrettyChars(); - namelen = name.length; - } - dtdword(&dt, namelen); - dtabytes(&dt, TYnptr, 0, namelen + 1, toStringz(name)); - - // vtbl[] - dtdword(&dt, vtbl.dim); - dtxoff(&dt, vtblsym, 0, TYnptr); - - // interfaces[] - dtdword(&dt, vtblInterfaces.dim); - if (vtblInterfaces.dim) - dtxoff(&dt, csym, offset, TYnptr); // (*) - else - dtdword(&dt, 0); - - // base - if (baseClass) - dtxoff(&dt, baseClass.toSymbol(), 0, TYnptr); - else - dtdword(&dt, 0); - - // destructor - if (dtor) - dtxoff(&dt, dtor.toSymbol(), 0, TYnptr); - else - dtdword(&dt, 0); - - // invariant - if (inv) - dtxoff(&dt, inv.toSymbol(), 0, TYnptr); - else - dtdword(&dt, 0); - - // flags - int flags = 4 | isCOMclass(); - version (DMDV2) { - flags |= 16; - } - flags |= 32; - - if (ctor) - flags |= 8; - for (ClassDeclaration cd = this; cd; cd = cd.baseClass) - { - if (cd.members) - { - for (size_t j = 0; j < cd.members.dim; j++) - { - Dsymbol sm = cast(Dsymbol)cd.members.data[j]; - //printf("sm = %s %s\n", sm.kind(), sm.toChars()); - if (sm.hasPointers()) - goto L2; - } - } - } - flags |= 2; // no pointers - L2: - dtdword(&dt, flags); - - - // deallocator - if (aggDelete) - dtxoff(&dt, aggDelete.toSymbol(), 0, TYnptr); - else - dtdword(&dt, 0); - - // offTi[] - dtdword(&dt, 0); - dtdword(&dt, 0); // null for now, fix later - - // defaultConstructor - if (defaultCtor) - dtxoff(&dt, defaultCtor.toSymbol(), 0, TYnptr); - else - dtdword(&dt, 0); - - version (DMDV2) { - FuncDeclaration sgetmembers = findGetMembers(); - if (sgetmembers) - dtxoff(&dt, sgetmembers.toSymbol(), 0, TYnptr); - else - dtdword(&dt, 0); // module getMembers() function - } - - dtxoff(&dt, type.vtinfo.toSymbol(), 0, TYnptr); // typeinfo - //dtdword(&dt, 0); - - ////////////////////////////////////////////// - - // Put out vtblInterfaces.data[]. Must immediately follow csym, because - // of the fixup (*) - - offset += vtblInterfaces.dim * (4 * PTRSIZE); - for (i = 0; i < vtblInterfaces.dim; i++) - { - BaseClass b = cast(BaseClass)vtblInterfaces.data[i]; - ClassDeclaration id = b.base; - - /* The layout is: - * { - * ClassInfo *interface; - * void *[] vtbl; - * unsigned offset; - * } - */ - - // Fill in vtbl[] - b.fillVtbl(this, b.vtbl, 1); - - dtxoff(&dt, id.toSymbol(), 0, TYnptr); // ClassInfo - - // vtbl[] - dtdword(&dt, id.vtbl.dim); - dtxoff(&dt, csym, offset, TYnptr); - - dtdword(&dt, b.offset); // this offset - - offset += id.vtbl.dim * PTRSIZE; - } - - // Put out the vtblInterfaces.data[].vtbl[] - // This must be mirrored with ClassDeclaration.baseVtblOffset() - //printf("putting out %d interface vtbl[]s for '%s'\n", vtblInterfaces.dim, toChars()); - for (i = 0; i < vtblInterfaces.dim; i++) - { - BaseClass b = cast(BaseClass)vtblInterfaces.data[i]; - ClassDeclaration id = b.base; - int j; - - //printf(" interface[%d] is '%s'\n", i, id.toChars()); - j = 0; - if (id.vtblOffset()) - { - // First entry is ClassInfo reference - //dtxoff(&dt, id.toSymbol(), 0, TYnptr); - - // First entry is struct Interface reference - dtxoff(&dt, csym, CLASSINFO_SIZE + i * (4 * PTRSIZE), TYnptr); - j = 1; - } - - assert(id.vtbl.dim == b.vtbl.dim); - for (; j < id.vtbl.dim; j++) - { - FuncDeclaration fd; - - assert(j < b.vtbl.dim); - static if (false) { - Object o = cast(Object)b.vtbl.data[j]; - if (o) - { - printf("o = %p\n", o); - assert(o.dyncast() == DYNCAST_DSYMBOL); - Dsymbol s = cast(Dsymbol)o; - printf("s.kind() = '%s'\n", s.kind()); - } - } - fd = cast(FuncDeclaration)b.vtbl.data[j]; - if (fd) - dtxoff(&dt, fd.toThunkSymbol(b.offset), 0, TYnptr); - else - dtdword(&dt, 0); - } - } - - static if (true) { - // Put out the overriding interface vtbl[]s. - // This must be mirrored with ClassDeclaration.baseVtblOffset() - //printf("putting out overriding interface vtbl[]s for '%s' at offset x%x\n", toChars(), offset); - ClassDeclaration cd; - scope Array bvtbl = new Array(); - - for (cd = this.baseClass; cd; cd = cd.baseClass) - { - for (int k = 0; k < cd.vtblInterfaces.dim; k++) - { - BaseClass bs = cast(BaseClass)cd.vtblInterfaces.data[k]; - - if (bs.fillVtbl(this, bvtbl, 0)) - { - //printf("\toverriding vtbl[] for %s\n", bs.base.toChars()); - ClassDeclaration id = bs.base; - int j; - - j = 0; - if (id.vtblOffset()) - { - // First entry is ClassInfo reference - //dtxoff(&dt, id.toSymbol(), 0, TYnptr); - - // First entry is struct Interface reference - dtxoff(&dt, cd.toSymbol(), CLASSINFO_SIZE + k * (4 * PTRSIZE), TYnptr); - j = 1; - } - - for (; j < id.vtbl.dim; j++) - { - assert(j < bvtbl.dim); - FuncDeclaration fd = cast(FuncDeclaration)bvtbl.data[j]; - if (fd) - dtxoff(&dt, fd.toThunkSymbol(bs.offset), 0, TYnptr); - else - dtdword(&dt, 0); - } - } - } - } - } - - version (INTERFACE_VIRTUAL) { - // Put out the overriding interface vtbl[]s. - // This must be mirrored with ClassDeclaration.baseVtblOffset() - //printf("putting out overriding interface vtbl[]s for '%s' at offset x%x\n", toChars(), offset); - for (i = 0; i < vtblInterfaces.dim; i++) - { - BaseClass b = cast(BaseClass)vtblInterfaces.data[i]; - ClassDeclaration cd; - - for (cd = this.baseClass; cd; cd = cd.baseClass) - { - for (int k = 0; k < cd.vtblInterfaces.dim; k++) - { - BaseClass bs = cast(BaseClass)cd.vtblInterfaces.data[k]; - - if (b.base == bs.base) - { - //printf("\toverriding vtbl[] for %s\n", b.base.toChars()); - ClassDeclaration id = b.base; - int j; - - j = 0; - if (id.vtblOffset()) - { - // First entry is ClassInfo reference - //dtxoff(&dt, id.toSymbol(), 0, TYnptr); - - // First entry is struct Interface reference - dtxoff(&dt, cd.toSymbol(), CLASSINFO_SIZE + k * (4 * PTRSIZE), TYnptr); - j = 1; - } - - for (; j < id.vtbl.dim; j++) - { - assert(j < b.vtbl.dim); - FuncDeclaration fd = cast(FuncDeclaration)b.vtbl.data[j]; - if (fd) - dtxoff(&dt, fd.toThunkSymbol(bs.offset), 0, TYnptr); - else - dtdword(&dt, 0); - } - } - } - } - } - } - - - csym.Sdt = dt; - version (ELFOBJ_OR_MACHOBJ) { // Burton - // ClassInfo cannot be const data, because we use the monitor on it - csym.Sseg = Segment.DATA; - } - outdata(csym); - if (isExport()) - obj_export(csym,0); - - ////////////////////////////////////////////// - - // Put out the vtbl[] - //printf("putting out %s.vtbl[]\n", toChars()); - dt = null; - if (0) - i = 0; - else - { - dtxoff(&dt, csym, 0, TYnptr); // first entry is ClassInfo reference - i = 1; - } - for (; i < vtbl.dim; i++) - { - FuncDeclaration fd = (cast(Dsymbol)vtbl.data[i]).isFuncDeclaration(); - - //printf("\tvtbl[%d] = %p\n", i, fd); - if (fd && (fd.fbody || !isAbstract())) - { - Symbol* s = fd.toSymbol(); - - version (DMDV2) { - if (isFuncHidden(fd)) - { - /* fd is hidden from the view of this class. - * If fd overlaps with any function in the vtbl[], then - * issue 'hidden' error. - */ - for (int j = 1; j < vtbl.dim; j++) - { - if (j == i) - continue; - FuncDeclaration fd2 = (cast(Dsymbol)vtbl.data[j]).isFuncDeclaration(); - if (!fd2.ident.equals(fd.ident)) - continue; - if (fd.leastAsSpecialized(fd2) || fd2.leastAsSpecialized(fd)) - { - if (global.params.warnings) - { - TypeFunction tf = cast(TypeFunction)fd.type; - if (tf.ty == Tfunction) - warning("%s%s is hidden by %s\n", fd.toPrettyChars(), Argument.argsTypesToChars(tf.parameters, tf.varargs), toChars()); - else - warning("%s is hidden by %s\n", fd.toPrettyChars(), toChars()); - } - s = rtlsym[RTLSYM_DHIDDENFUNC]; - break; - } - } - } - } - dtxoff(&dt, s, 0, TYnptr); - } - else - dtdword(&dt, 0); - } - - vtblsym.Sdt = dt; - vtblsym.Sclass = scclass; - vtblsym.Sfl = FLdata; - version (ELFOBJ) { - vtblsym.Sseg = Segment.CDATA; - } - version (MACHOBJ) { - vtblsym.Sseg = Segment.DATA; - } - outdata(vtblsym); - if (isExport()) - obj_export(vtblsym,0); - } - - void toDebug() - { - assert(false); - } - - /****************************************** - * Get offset of base class's vtbl[] initializer from start of csym. - * Returns ~0 if not this csym. - */ - uint baseVtblOffset(BaseClass bc) - { - uint csymoffset; - int i; - - //printf("ClassDeclaration.baseVtblOffset('%s', bc = %p)\n", toChars(), bc); - csymoffset = CLASSINFO_SIZE; - csymoffset += vtblInterfaces.dim * (4 * PTRSIZE); - - for (i = 0; i < vtblInterfaces.dim; i++) - { - BaseClass b = cast(BaseClass)vtblInterfaces.data[i]; - - if (b == bc) - return csymoffset; - csymoffset += b.base.vtbl.dim * PTRSIZE; - } - - static if (true) { - // Put out the overriding interface vtbl[]s. - // This must be mirrored with ClassDeclaration.baseVtblOffset() - //printf("putting out overriding interface vtbl[]s for '%s' at offset x%x\n", toChars(), offset); - ClassDeclaration cd; - Array bvtbl; - - for (cd = this.baseClass; cd; cd = cd.baseClass) - { - for (int k = 0; k < cd.vtblInterfaces.dim; k++) - { - BaseClass bs = cast(BaseClass)cd.vtblInterfaces.data[k]; - - if (bs.fillVtbl(this, null, 0)) - { - if (bc == bs) - { - //printf("\tcsymoffset = x%x\n", csymoffset); - return csymoffset; - } - csymoffset += bs.base.vtbl.dim * PTRSIZE; - } - } - } - } - version (INTERFACE_VIRTUAL) { - for (i = 0; i < vtblInterfaces.dim; i++) - { - BaseClass b = cast(BaseClass)vtblInterfaces.data[i]; - ClassDeclaration cd; - - for (cd = this.baseClass; cd; cd = cd.baseClass) - { - //printf("\tbase class %s\n", cd.toChars()); - for (int k = 0; k < cd.vtblInterfaces.dim; k++) - { - BaseClass bs = cast(BaseClass)cd.vtblInterfaces.data[k]; - - if (bc == bs) - { - //printf("\tcsymoffset = x%x\n", csymoffset); - return csymoffset; - } - if (b.base == bs.base) - csymoffset += bs.base.vtbl.dim * PTRSIZE; - } - } - } - } - - return ~0; - } - - static private __gshared Classsym* scc; - - /************************************* - * Create the "ClassInfo" symbol - */ - override Symbol* toSymbol() - { - if (!csym) - { - Symbol* s; - - if (!scc) - scc = fake_classsym(Id.ClassInfo); - - s = toSymbolX("__Class", SC.SCextern, scc.Stype, "Z"); - s.Sfl = FL.FLextern; - s.Sflags |= SFL.SFLnodebug; - csym = s; - slist_add(s); - } - - return csym; - } - - /************************************* - * This is accessible via the ClassData, but since it is frequently - * needed directly (like for rtti comparisons), make it directly accessible. - */ - Symbol* toVtblSymbol() - { - if (!vtblsym) - { - if (!csym) - toSymbol(); - - TYPE* t = type_alloc(TYM.TYnptr | mTY.mTYconst); - t.Tnext = tsvoid; - t.Tnext.Tcount++; - t.Tmangle = mTYman.mTYman_d; - - Symbol* s = toSymbolX("__vtbl", SC.SCextern, t, "Z"); - s.Sflags |= SFL.SFLnodebug; - s.Sfl = FL.FLextern; - vtblsym = s; - slist_add(s); - } - return vtblsym; - } - - // Generate the data for the static initializer. - void toDt(dt_t **pdt) - { - //printf("ClassDeclaration.toDt(this = '%s')\n", toChars()); - - // Put in first two members, the vtbl[] and the monitor - dtxoff(pdt, toVtblSymbol(), 0, TYnptr); - dtdword(pdt, 0); // monitor - - // Put in the rest - toDt2(pdt, this); - - //printf("-ClassDeclaration.toDt(this = '%s')\n", toChars()); - } - - void toDt2(dt_t** pdt, ClassDeclaration cd) - { - uint offset; - uint i; - dt_t* dt; - uint csymoffset; - - version (LOG) { - printf("ClassDeclaration.toDt2(this = '%s', cd = '%s')\n", toChars(), cd.toChars()); - } - if (baseClass) - { - baseClass.toDt2(pdt, cd); - offset = baseClass.structsize; - } - else - { - offset = 8; - } - - // Note equivalence of this loop to struct's - for (i = 0; i < fields.dim; i++) - { - VarDeclaration v = cast(VarDeclaration)fields.data[i]; - Initializer init; - - //printf("\t\tv = '%s' v.offset = %2d, offset = %2d\n", v.toChars(), v.offset, offset); - dt = null; - init = v.init; - if (init) - { - //printf("\t\t%s has initializer %s\n", v.toChars(), init.toChars()); - ExpInitializer ei = init.isExpInitializer(); - Type tb = v.type.toBasetype(); - if (ei && tb.ty == Tsarray) - (cast(TypeSArray)tb).toDtElem(&dt, ei.exp); - else - dt = init.toDt(); - } - else if (v.offset >= offset) - { //printf("\t\tdefault initializer\n"); - v.type.toDt(&dt); - } - if (dt) - { - if (v.offset < offset) - error("duplicated union initialization for %s", v.toChars()); - else - { - if (offset < v.offset) - dtnzeros(pdt, v.offset - offset); - dtcat(pdt, dt); - offset = v.offset + cast(uint)v.type.size(); - } - } - } - - // Interface vptr initializations - toSymbol(); // define csym - - for (i = 0; i < vtblInterfaces.dim; i++) - { - BaseClass b = cast(BaseClass)vtblInterfaces.data[i]; - -/// version (1 || INTERFACE_VIRTUAL) { - for (ClassDeclaration cd2 = cd; 1; cd2 = cd2.baseClass) - { - assert(cd2); - csymoffset = cd2.baseVtblOffset(b); - if (csymoffset != ~0) - { - if (offset < b.offset) - dtnzeros(pdt, b.offset - offset); - dtxoff(pdt, cd2.toSymbol(), csymoffset, TYnptr); - break; - } - } -/// } else { -/// csymoffset = baseVtblOffset(b); -/// assert(csymoffset != ~0); -/// dtxoff(pdt, csym, csymoffset, TYnptr); -/// } - offset = b.offset + 4; - } - - if (offset < structsize) - dtnzeros(pdt, structsize - offset); - } - - Symbol* vtblsym; - - ///ClassDeclaration isClassDeclaration() { return cast(ClassDeclaration)this; } /// huh? - override ClassDeclaration isClassDeclaration() { return this; } -} +module dmd.ClassDeclaration; + +import dmd.AggregateDeclaration; +import dmd.InterfaceDeclaration; +import dmd.ThisDeclaration; +import dmd.CompoundStatement; +import dmd.DeleteDeclaration; +import dmd.NewDeclaration; +import dmd.CtorDeclaration; +import dmd.TypeIdentifier; +import dmd.STC; +import dmd.Argument; +import dmd.TypeTuple; +import dmd.TY; +import dmd.LINK; +import dmd.DsymbolTable; +import dmd.FuncDeclaration; +import dmd.Array; +import dmd.TypeClass; +import dmd.Module; +import dmd.Id; +import dmd.Type; +import dmd.OverloadSet; +import dmd.ArrayTypes; +import dmd.BaseClass; +import dmd.ClassInfoDeclaration; +import dmd.Loc; +import dmd.Identifier; +import dmd.Dsymbol; +import dmd.Scope; +import dmd.TypeFunction; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.VarDeclaration; +import dmd.Initializer; +import dmd.ExpInitializer; +import dmd.TypeSArray; +import dmd.ScopeDsymbol; +import dmd.PROT; +import dmd.Util; +import dmd.Global; + +import dmd.expression.Util; + +import dmd.backend.Symbol; +import dmd.backend.dt_t; +import dmd.backend.TYPE; +import dmd.backend.FL; +import dmd.backend.SFL; +import dmd.backend.mTY; +import dmd.backend.SC; +import dmd.backend.mTYman; +import dmd.backend.Util; +import dmd.backend.TYM; +import dmd.backend.Classsym; +import dmd.backend.glue; +import dmd.backend.RTLSYM; +import dmd.backend.LIST; + +import dmd.codegen.Util; + +import std.string; + +version (DMDV2) { + enum CLASSINFO_SIZE = (0x3C+16+4); // value of ClassInfo.size +} else { + enum CLASSINFO_SIZE = (0x3C+12+4); // value of ClassInfo.size +} + +enum OFFSET_RUNTIME = 0x76543210; + +struct Param +{ + int isf(void*, FuncDeclaration fd2) + { + //printf("param = %p, fd = %p %s\n", param, fd, fd.toChars()); + return fd is fd2; + } + + FuncDeclaration fd; +} + +class ClassDeclaration : AggregateDeclaration +{ + static __gshared ClassDeclaration object; + static __gshared ClassDeclaration classinfo; + + ClassDeclaration baseClass; // null only if this is Object + FuncDeclaration staticCtor; + FuncDeclaration staticDtor; + Array vtbl; // Array of FuncDeclaration's making up the vtbl[] + Array vtblFinal; // More FuncDeclaration's that aren't in vtbl[] + + BaseClasses baseclasses; // Array of BaseClass's; first is super, + // rest are Interface's + + int interfaces_dim; + BaseClass* interfaces; // interfaces[interfaces_dim] for this class + // (does not include baseClass) + + BaseClasses vtblInterfaces; // array of base interfaces that have + // their own vtbl[] + + ClassInfoDeclaration vclassinfo; // the ClassInfo object for this ClassDeclaration + bool com; // true if this is a COM class (meaning + // it derives from IUnknown) + bool isauto; // true if this is an auto class + bool isabstract; // true if abstract class + + int inuse; // to prevent recursive attempts + + this(Loc loc, Identifier id, BaseClasses baseclasses) + { + super(loc, id); + + vtbl = new Array(); + vtblFinal = new Array(); + + enum msg = "only object.d can define this reserved class name"; + + if (baseclasses) { + this.baseclasses = baseclasses; + } else { + this.baseclasses = new BaseClasses(); + } + + //printf("ClassDeclaration(%s), dim = %d\n", id.toChars(), this.baseclasses.dim); + + // For forward references + type = new TypeClass(this); + + if (id) + { + // Look for special class names + + if (id is Id.__sizeof || id is Id.alignof_ || id is Id.mangleof_) + error("illegal class name"); + + // BUG: What if this is the wrong TypeInfo, i.e. it is nested? + if (id.toChars()[0] == 'T') + { + if (id is Id.TypeInfo) + { + if (Type.typeinfo) + Type.typeinfo.error("%s", msg); + Type.typeinfo = this; + } + + if (id is Id.TypeInfo_Class) + { + if (Type.typeinfoclass) + Type.typeinfoclass.error("%s", msg); + Type.typeinfoclass = this; + } + + if (id is Id.TypeInfo_Interface) + { + if (Type.typeinfointerface) + Type.typeinfointerface.error("%s", msg); + Type.typeinfointerface = this; + } + + if (id is Id.TypeInfo_Struct) + { + if (Type.typeinfostruct) + Type.typeinfostruct.error("%s", msg); + Type.typeinfostruct = this; + } + + if (id is Id.TypeInfo_Typedef) + { + if (Type.typeinfotypedef) + Type.typeinfotypedef.error("%s", msg); + Type.typeinfotypedef = this; + } + + if (id is Id.TypeInfo_Pointer) + { + if (Type.typeinfopointer) + Type.typeinfopointer.error("%s", msg); + Type.typeinfopointer = this; + } + + if (id is Id.TypeInfo_Array) + { + if (Type.typeinfoarray) + Type.typeinfoarray.error("%s", msg); + Type.typeinfoarray = this; + } + + if (id is Id.TypeInfo_StaticArray) + { //if (Type.typeinfostaticarray) + //Type.typeinfostaticarray.error("%s", msg); + Type.typeinfostaticarray = this; + } + + if (id is Id.TypeInfo_AssociativeArray) + { + if (Type.typeinfoassociativearray) + Type.typeinfoassociativearray.error("%s", msg); + Type.typeinfoassociativearray = this; + } + + if (id is Id.TypeInfo_Enum) + { + if (Type.typeinfoenum) + Type.typeinfoenum.error("%s", msg); + Type.typeinfoenum = this; + } + + if (id is Id.TypeInfo_Function) + { + if (Type.typeinfofunction) + Type.typeinfofunction.error("%s", msg); + Type.typeinfofunction = this; + } + + if (id is Id.TypeInfo_Delegate) + { + if (Type.typeinfodelegate) + Type.typeinfodelegate.error("%s", msg); + Type.typeinfodelegate = this; + } + + if (id is Id.TypeInfo_Tuple) + { + if (Type.typeinfotypelist) + Type.typeinfotypelist.error("%s", msg); + Type.typeinfotypelist = this; + } + + version (DMDV2) { + if (id is Id.TypeInfo_Const) + { + if (Type.typeinfoconst) + Type.typeinfoconst.error("%s", msg); + Type.typeinfoconst = this; + } + + if (id is Id.TypeInfo_Invariant) + { + if (Type.typeinfoinvariant) + Type.typeinfoinvariant.error("%s", msg); + Type.typeinfoinvariant = this; + } + + if (id is Id.TypeInfo_Shared) + { + if (Type.typeinfoshared) + Type.typeinfoshared.error("%s", msg); + Type.typeinfoshared = this; + } + } + } + + if (id is Id.Object_) + { + if (object) + object.error("%s", msg); + object = this; + } + + if (id is Id.ClassInfo) + { + if (classinfo) + classinfo.error("%s", msg); + classinfo = this; + } + + if (id is Id.ModuleInfo) + { + if (Module.moduleinfo) + Module.moduleinfo.error("%s", msg); + Module.moduleinfo = this; + } + } + + com = 0; + isauto = false; + isabstract = false; + inuse = 0; + } + + override Dsymbol syntaxCopy(Dsymbol s) + { + ClassDeclaration cd; + + //printf("ClassDeclaration.syntaxCopy('%s')\n", toChars()); + if (s) + cd = cast(ClassDeclaration)s; + else + cd = new ClassDeclaration(loc, ident, null); + + cd.storage_class |= storage_class; + + cd.baseclasses.setDim(this.baseclasses.dim); + for (int i = 0; i < cd.baseclasses.dim; i++) + { + BaseClass b = cast(BaseClass)this.baseclasses.data[i]; + BaseClass b2 = new BaseClass(b.type.syntaxCopy(), b.protection); + cd.baseclasses.data[i] = cast(void*)b2; + } + + ScopeDsymbol.syntaxCopy(cd); + return cd; + } + + override void semantic(Scope sc) + { + int i; + uint offset; + + //printf("ClassDeclaration.semantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this); + //printf("\tparent = %p, '%s'\n", sc.parent, sc.parent ? sc.parent.toChars() : ""); + //printf("sc.stc = %x\n", sc.stc); + + //{ static int n; if (++n == 20) *(char*)0=0; } + + if (!ident) // if anonymous class + { + string id = "__anonclass"; + ident = Identifier.generateId(id); + } + + if (!sc) + sc = scope_; + + if (!parent && sc.parent && !sc.parent.isModule()) + parent = sc.parent; + + type = type.semantic(loc, sc); + handle = type; + + if (!members) // if forward reference + { + //printf("\tclass '%s' is forward referenced\n", toChars()); + return; + } + if (symtab) + { if (!scope_) + { //printf("\tsemantic for '%s' is already completed\n", toChars()); + return; // semantic() already completed + } + } + else + symtab = new DsymbolTable(); + + Scope scx = null; + if (scope_) + { sc = scope_; + scx = scope_; // save so we don't make redundant copies + scope_ = null; + } +version (IN_GCC) { + methods.setDim(0); +} + + if (sc.stc & STC.STCdeprecated) + { + isdeprecated = 1; + } + + if (sc.linkage == LINK.LINKcpp) + error("cannot create C++ classes"); + + // Expand any tuples in baseclasses[] + for (i = 0; i < baseclasses.dim; ) + { + BaseClass b = cast(BaseClass)baseclasses.data[i]; + //printf("test1 %s %s\n", toChars(), b.type.toChars()); + b.type = b.type.semantic(loc, sc); + //printf("test2\n"); + Type tb = b.type.toBasetype(); + + if (tb.ty == TY.Ttuple) + { + TypeTuple tup = cast(TypeTuple)tb; + enum PROT protection = b.protection; + baseclasses.remove(i); + size_t dim = Argument.dim(tup.arguments); + for (size_t j = 0; j < dim; j++) + { + Argument arg = Argument.getNth(tup.arguments, j); + b = new BaseClass(arg.type, protection); + baseclasses.insert(i + j, cast(void*)b); + } + } + else + i++; + } + + // See if there's a base class as first in baseclasses[] + if (baseclasses.dim) + { + TypeClass tc; + BaseClass b; + Type tb; + + b = cast(BaseClass)baseclasses.data[0]; + //b.type = b.type.semantic(loc, sc); + tb = b.type.toBasetype(); + if (tb.ty != TY.Tclass) + { error("base type must be class or interface, not %s", b.type.toChars()); + baseclasses.remove(0); + } + else + { + tc = cast(TypeClass)(tb); + + if (tc.sym.isDeprecated()) + { + if (!isDeprecated()) + { + // Deriving from deprecated class makes this one deprecated too + isdeprecated = 1; + + tc.checkDeprecated(loc, sc); + } + } + + if (tc.sym.isInterfaceDeclaration()) { + ; + } else { + for (ClassDeclaration cdb = tc.sym; cdb; cdb = cdb.baseClass) + { + if (cdb == this) + { + error("circular inheritance"); + baseclasses.remove(0); + goto L7; + } + } + if (!tc.sym.symtab || tc.sym.sizeok == 0) + { // Try to resolve forward reference + if (sc.mustsemantic && tc.sym.scope_) + tc.sym.semantic(null); + } + if (!tc.sym.symtab || tc.sym.scope_ || tc.sym.sizeok == 0) + { + //printf("%s: forward reference of base class %s\n", toChars(), tc.sym.toChars()); + //error("forward reference of base class %s", baseClass.toChars()); + // Forward reference of base class, try again later + //printf("\ttry later, forward reference of base class %s\n", tc.sym.toChars()); + scope_ = scx ? scx : new Scope(sc); + scope_.setNoFree(); + if (tc.sym.scope_) + tc.sym.scope_.module_.addDeferredSemantic(tc.sym); + scope_.module_.addDeferredSemantic(this); + return; + } + else + { baseClass = tc.sym; + b.base = baseClass; + } + L7: ; + } + } + } + + // Treat the remaining entries in baseclasses as interfaces + // Check for errors, handle forward references + for (i = (baseClass ? 1 : 0); i < baseclasses.dim; ) + { TypeClass tc; + BaseClass b; + Type tb; + + b = cast(BaseClass)baseclasses.data[i]; + b.type = b.type.semantic(loc, sc); + tb = b.type.toBasetype(); + if (tb.ty == TY.Tclass) + tc = cast(TypeClass)tb; + else + tc = null; + if (!tc || !tc.sym.isInterfaceDeclaration()) + { + error("base type must be interface, not %s", b.type.toChars()); + baseclasses.remove(i); + continue; + } + else + { + if (tc.sym.isDeprecated()) + { + if (!isDeprecated()) + { + // Deriving from deprecated class makes this one deprecated too + isdeprecated = 1; + + tc.checkDeprecated(loc, sc); + } + } + + // Check for duplicate interfaces + for (size_t j = (baseClass ? 1 : 0); j < i; j++) + { + BaseClass b2 = cast(BaseClass)baseclasses.data[j]; + if (b2.base == tc.sym) + error("inherits from duplicate interface %s", b2.base.toChars()); + } + + if (!tc.sym.symtab) + { // Try to resolve forward reference + if (sc.mustsemantic && tc.sym.scope_) + tc.sym.semantic(null); + } + + b.base = tc.sym; + if (!b.base.symtab || b.base.scope_) + { + //error("forward reference of base class %s", baseClass.toChars()); + // Forward reference of base, try again later + //printf("\ttry later, forward reference of base %s\n", baseClass.toChars()); + scope_ = scx ? scx : new Scope(sc); + scope_.setNoFree(); + if (tc.sym.scope_) + tc.sym.scope_.module_.addDeferredSemantic(tc.sym); + scope_.module_.addDeferredSemantic(this); + return; + } + } + i++; + } + + + // If no base class, and this is not an Object, use Object as base class + if (!baseClass && ident !is Id.Object_) + { + // BUG: what if Object is redefined in an inner scope? + Type tbase = new TypeIdentifier(Loc(0), Id.Object_); + BaseClass b; + TypeClass tc; + Type bt; + + if (!object) + { + error("missing or corrupt object.d"); + fatal(); + } + bt = tbase.semantic(loc, sc).toBasetype(); + b = new BaseClass(bt, PROT.PROTpublic); + baseclasses.shift(cast(void*)b); + assert(b.type.ty == TY.Tclass); + tc = cast(TypeClass)(b.type); + baseClass = tc.sym; + assert(!baseClass.isInterfaceDeclaration()); + b.base = baseClass; + } + + interfaces_dim = baseclasses.dim; + interfaces = cast(BaseClass*)baseclasses.data; + + if (baseClass) + { + if (baseClass.storage_class & STC.STCfinal) + error("cannot inherit from final class %s", baseClass.toChars()); + + interfaces_dim--; + interfaces++; + + // Copy vtbl[] from base class + vtbl.setDim(baseClass.vtbl.dim); + memcpy(vtbl.data, baseClass.vtbl.data, (void*).sizeof * vtbl.dim); + + // Inherit properties from base class + com = baseClass.isCOMclass(); + isauto = baseClass.isauto; + vthis = baseClass.vthis; + storage_class |= baseClass.storage_class & STC.STC_TYPECTOR; + } + else + { + // No base class, so this is the root of the class hierarchy + vtbl.setDim(0); + vtbl.push(cast(void*)this); // leave room for classinfo as first member + } + + protection = sc.protection; + storage_class |= sc.stc; + + if (sizeok == 0) + { + interfaceSemantic(sc); + + for (i = 0; i < members.dim; i++) + { + Dsymbol s = cast(Dsymbol)members.data[i]; + s.addMember(sc, this, true); + } + + /* If this is a nested class, add the hidden 'this' + * member which is a pointer to the enclosing scope. + */ + if (vthis) // if inheriting from nested class + { // Use the base class's 'this' member + isnested = true; + if (storage_class & STC.STCstatic) + error("static class cannot inherit from nested class %s", baseClass.toChars()); + if (toParent2() != baseClass.toParent2()) + { + if (toParent2()) + { + error("is nested within %s, but super class %s is nested within %s", + toParent2().toChars(), + baseClass.toChars(), + baseClass.toParent2().toChars()); + } + else + { + error("is not nested, but super class %s is nested within %s", + baseClass.toChars(), + baseClass.toParent2().toChars()); + } + isnested = false; + } + } + else if (!(storage_class & STC.STCstatic)) + { + Dsymbol s = toParent2(); + if (s) + { + AggregateDeclaration ad = s.isClassDeclaration(); + FuncDeclaration fd = s.isFuncDeclaration(); + + if (ad || fd) + { isnested = true; + Type t; + if (ad) + t = ad.handle; + else if (fd) + { + AggregateDeclaration ad2 = fd.isMember2(); + if (ad2) + t = ad2.handle; + else + { + t = Type.tvoidptr; + } + } + else + assert(0); + if (t.ty == TY.Tstruct) // ref to struct + t = Type.tvoidptr; + assert(!vthis); + vthis = new ThisDeclaration(loc, t); + members.push(cast(void*)vthis); + } + } + } + } + + if (storage_class & (STC.STCauto | STC.STCscope)) + isauto = true; + if (storage_class & STC.STCabstract) + isabstract = true; + if (storage_class & STC.STCimmutable) + type = type.invariantOf(); + else if (storage_class & STC.STCconst) + type = type.constOf(); + else if (storage_class & STC.STCshared) + type = type.sharedOf(); + + sc = sc.push(this); + sc.stc &= ~(STC.STCfinal | STC.STCauto | STC.STCscope | STC.STCstatic | + STC.STCabstract | STC.STCdeprecated | STC.STC_TYPECTOR | STC.STCtls | STC.STCgshared); + sc.stc |= storage_class & STC.STC_TYPECTOR; + sc.parent = this; + sc.inunion = 0; + + if (isCOMclass()) + { +version (_WIN32) { + sc.linkage = LINK.LINKwindows; +} else { + /* This enables us to use COM objects under Linux and + * work with things like XPCOM + */ + sc.linkage = LINK.LINKc; +} + } + sc.protection = PROT.PROTpublic; + sc.explicitProtection = 0; + sc.structalign = 8; + structalign = sc.structalign; + if (baseClass) + { sc.offset = baseClass.structsize; + alignsize = baseClass.alignsize; + // if (isnested) + // sc.offset += PTRSIZE; // room for uplevel context pointer + } + else + { sc.offset = PTRSIZE * 2; // allow room for __vptr and __monitor + alignsize = PTRSIZE; + } + structsize = sc.offset; + Scope scsave = sc; /// a copy must be created? + int members_dim = members.dim; + sizeok = 0; + for (i = 0; i < members_dim; i++) + { + Dsymbol s = cast(Dsymbol)members.data[i]; + s.semantic(sc); + } + + if (sizeok == 2) + { // semantic() failed because of forward references. + // Unwind what we did, and defer it for later + fields.setDim(0); + structsize = 0; + alignsize = 0; + structalign = 0; + + sc = sc.pop(); + + scope_ = scx ? scx : new Scope(sc); + scope_.setNoFree(); + scope_.module_.addDeferredSemantic(this); + + //printf("\tsemantic('%s') failed due to forward references\n", toChars()); + return; + } + + //printf("\tsemantic('%s') successful\n", toChars()); + + structsize = sc.offset; + //members.print(); + + /* Look for special member functions. + * They must be in this class, not in a base class. + */ + ctor = cast(CtorDeclaration)search(Loc(0), Id.ctor, 0); + if (ctor && (ctor.toParent() != this || !ctor.isCtorDeclaration())) + ctor = null; + + // dtor = (DtorDeclaration *)search(Id.dtor, 0); + // if (dtor && dtor.toParent() != this) + // dtor = null; + + // inv = (InvariantDeclaration *)search(Id.classInvariant, 0); + // if (inv && inv.toParent() != this) + // inv = null; + + // Can be in base class + aggNew = cast(NewDeclaration)search(Loc(0), Id.classNew, 0); + aggDelete = cast(DeleteDeclaration)search(Loc(0), Id.classDelete, 0); + + // If this class has no constructor, but base class does, create + // a constructor: + // this() { } + if (!ctor && baseClass && baseClass.ctor) + { + //printf("Creating default this(){} for class %s\n", toChars()); + CtorDeclaration ctor = new CtorDeclaration(loc, Loc(0), null, 0); + ctor.fbody = new CompoundStatement(Loc(0), new Statements()); + members.push(cast(void*)ctor); + ctor.addMember(sc, this, true); + sc = scsave; // why? What about sc.nofree? /// + sc.offset = structsize; + ctor.semantic(sc); + this.ctor = ctor; + defaultCtor = ctor; + } + +static if (false) { + if (baseClass) + { if (!aggDelete) + aggDelete = baseClass.aggDelete; + if (!aggNew) + aggNew = baseClass.aggNew; + } +} + + // Allocate instance of each new interface + for (i = 0; i < vtblInterfaces.dim; i++) + { + BaseClass b = cast(BaseClass)vtblInterfaces.data[i]; + uint thissize = PTRSIZE; + + alignmember(structalign, thissize, &sc.offset); + assert(b.offset == 0); + b.offset = sc.offset; + + // Take care of single inheritance offsets + while (b.baseInterfaces.length) + { + b = b.baseInterfaces[0]; + b.offset = sc.offset; + } + + sc.offset += thissize; + if (alignsize < thissize) + alignsize = thissize; + } + structsize = sc.offset; + sizeok = 1; + Module.dprogress++; + + dtor = buildDtor(sc); + + sc.pop(); + +static if (false) { // Do not call until toObjfile() because of forward references + // Fill in base class vtbl[]s + for (i = 0; i < vtblInterfaces.dim; i++) + { + BaseClass b = cast(BaseClass)vtblInterfaces.data[i]; + + //b.fillVtbl(this, &b.vtbl, 1); + } +} + //printf("-ClassDeclaration.semantic(%s), type = %p\n", toChars(), type); + } + + override void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + if (!isAnonymous()) + { + buf.printf("%s ", kind()); + buf.writestring(toChars()); + if (baseclasses.dim) + buf.writestring(" : "); + } + for (int i = 0; i < baseclasses.dim; i++) + { + BaseClass b = cast(BaseClass)baseclasses.data[i]; + + if (i) + buf.writeByte(','); + //buf.writestring(b.base.ident.toChars()); + b.type.toCBuffer(buf, null, hgs); + } + if (members) + { + buf.writenl(); + buf.writeByte('{'); + buf.writenl(); + for (int i = 0; i < members.dim; i++) + { + Dsymbol s = cast(Dsymbol)members.data[i]; + + buf.writestring(" "); + s.toCBuffer(buf, hgs); + } + buf.writestring("}"); + } + else + buf.writeByte(';'); + buf.writenl(); + } + + /********************************************* + * Determine if 'this' is a base class of cd. + * This is used to detect circular inheritance only. + */ + int isBaseOf2(ClassDeclaration cd) + { + if (!cd) + return 0; + //printf("ClassDeclaration::isBaseOf2(this = '%s', cd = '%s')\n", toChars(), cd.toChars()); + for (int i = 0; i < cd.baseclasses.dim; i++) + { + BaseClass b = cast(BaseClass)cd.baseclasses.data[i]; + + if (b.base is this || isBaseOf2(b.base)) + return 1; + } + return 0; + } + + /******************************************* + * Determine if 'this' is a base class of cd. + */ +/// #define OFFSET_RUNTIME 0x76543210 + bool isBaseOf(ClassDeclaration cd, int* poffset) + { + if (!cd) + return 0; + //printf("ClassDeclaration::isBaseOf2(this = '%s', cd = '%s')\n", toChars(), cd.toChars()); + for (int i = 0; i < cd.baseclasses.dim; i++) + { + BaseClass b = cast(BaseClass)cd.baseclasses.data[i]; + + if (b.base == this || isBaseOf2(b.base)) + return 1; + } + + return 0; + } + + override Dsymbol search(Loc, Identifier ident, int flags) + { + Dsymbol s; + //printf("%s.ClassDeclaration.search('%s')\n", toChars(), ident.toChars()); + + if (scope_) + { + Scope sc = scope_; + sc.mustsemantic++; + semantic(sc); + sc.mustsemantic--; + } + + if (!members || !symtab || scope_) + { + error("is forward referenced when looking for '%s'", ident.toChars()); + //*(char*)0=0; + return null; + } + + s = ScopeDsymbol.search(loc, ident, flags); + if (!s) + { + // Search bases classes in depth-first, left to right order + + int i; + + for (i = 0; i < baseclasses.dim; i++) + { + BaseClass b = cast(BaseClass)baseclasses.data[i]; + + if (b.base) + { + if (!b.base.symtab) + error("base %s is forward referenced", b.base.ident.toChars()); + else + { + s = b.base.search(loc, ident, flags); + if (s is this) // happens if s is nested in this and derives from this + s = null; + else if (s) + break; + } + } + } + } + return s; + } + +version (DMDV2) { + bool isFuncHidden(FuncDeclaration fd) + { + //printf("ClassDeclaration::isFuncHidden(class = %s, fd = %s)\n", toChars(), fd.toChars()); + Dsymbol s = search(Loc(0), fd.ident, 4|2); + if (!s) + { + //printf("not found\n"); + /* Because, due to a hack, if there are multiple definitions + * of fd.ident, null is returned. + */ + return false; + } + + Param p; p.fd = fd; + + s = s.toAlias(); + OverloadSet os = s.isOverloadSet(); + if (os) + { + for (int i = 0; i < os.a.dim; i++) + { + Dsymbol s2 = cast(Dsymbol)os.a.data[i]; + FuncDeclaration f2 = s2.isFuncDeclaration(); + if (f2 && overloadApply(f2, &p.isf, &p)) + return false; + } + return true; + } + else + { + FuncDeclaration fdstart = s.isFuncDeclaration(); + //printf("%s fdstart = %p\n", s.kind(), fdstart); + return !overloadApply(fdstart, &p.isf, &p); + } + } +} + FuncDeclaration findFunc(Identifier ident, TypeFunction tf) + { + //printf("ClassDeclaration.findFunc(%s, %s) %s\n", ident.toChars(), tf.toChars(), toChars()); + + ClassDeclaration cd = this; + Array vtbl = cd.vtbl; + while (true) + { + for (size_t i = 0; i < vtbl.dim; i++) + { + FuncDeclaration fd = (cast(Dsymbol)vtbl.data[i]).isFuncDeclaration(); + if (!fd) + continue; // the first entry might be a ClassInfo + + //printf("\t[%d] = %s\n", i, fd.toChars()); + if (ident == fd.ident && + //tf.equals(fd.type) + fd.type.covariant(tf) == 1 + ) + { //printf("\t\tfound\n"); + return fd; + } + //else printf("\t\t%d\n", fd.type.covariant(tf)); + } + if (!cd) + break; + + vtbl = cd.vtblFinal; + cd = cd.baseClass; + } + + return null; + } + + void interfaceSemantic(Scope sc) + { + InterfaceDeclaration id = isInterfaceDeclaration(); + + vtblInterfaces = new BaseClasses(); + vtblInterfaces.reserve(interfaces_dim); + + for (size_t i = 0; i < interfaces_dim; i++) + { + BaseClass b = interfaces[i]; + + // If this is an interface, and it derives from a COM interface, + // then this is a COM interface too. + if (b.base.isCOMinterface()) + com = 1; + + if (b.base.isCPPinterface() && id) + id.cpp = 1; + + vtblInterfaces.push(cast(void*)b); + b.copyBaseInterfaces(vtblInterfaces); + } + } + + bool isCOMclass() + { + return com; + } + + bool isCOMinterface() + { + return false; + } + +version (DMDV2) { + bool isCPPinterface() + { + return false; + } +} + bool isAbstract() + { + if (isabstract) + return true; + + for (int i = 1; i < vtbl.dim; i++) + { + FuncDeclaration fd = (cast(Dsymbol)vtbl.data[i]).isFuncDeclaration(); + + //printf("\tvtbl[%d] = %p\n", i, fd); + if (!fd || fd.isAbstract()) + { + isabstract = true; + return true; + } + } + + return false; + } + + int vtblOffset() + { + assert(false); + } + + override string kind() + { + return "class"; + } + + override string mangle() + { + Dsymbol parentsave = parent; + + //printf("ClassDeclaration.mangle() %s.%s\n", parent.toChars(), toChars()); + + /* These are reserved to the compiler, so keep simple + * names for them. + */ + if (ident is Id.Exception) + { + if (parent.ident is Id.object) + parent = null; + } + else if (ident is Id.TypeInfo || + // ident is Id.Exception || + ident is Id.TypeInfo_Struct || + ident is Id.TypeInfo_Class || + ident is Id.TypeInfo_Typedef || + ident is Id.TypeInfo_Tuple || + this is object || + this is classinfo || + this is Module.moduleinfo || + ident.toChars().startsWith("TypeInfo_") + ) + { + parent = null; + } + + string id = Dsymbol.mangle(); + parent = parentsave; + return id; + } + + override void toDocBuffer(OutBuffer buf) + { + assert(false); + } + + override PROT getAccess(Dsymbol smember) // determine access to smember + { + PROT access_ret = PROT.PROTnone; + + version (LOG) { + printf("+ClassDeclaration::getAccess(this = '%s', smember = '%s')\n", + toChars(), smember.toChars()); + } + if (smember.toParent() is this) + { + access_ret = smember.prot(); + } + else + { + PROT access; + int i; + + if (smember.isDeclaration().isStatic()) + { + access_ret = smember.prot(); + } + + for (i = 0; i < baseclasses.dim; i++) + { + BaseClass b = cast(BaseClass)baseclasses.data[i]; + + access = b.base.getAccess(smember); + switch (access) + { + case PROT.PROTnone: + break; + + case PROT.PROTprivate: + access = PROT.PROTnone; // private members of base class not accessible + break; + + case PROT.PROTpackage: + case PROT.PROTprotected: + case PROT.PROTpublic: + case PROT.PROTexport: + // If access is to be tightened + if (b.protection < access) + access = b.protection; + + // Pick path with loosest access + if (access > access_ret) + access_ret = access; + break; + + default: + assert(0); + } + } + } + + version (LOG) { + printf("-ClassDeclaration::getAccess(this = '%s', smember = '%s') = %d\n", + toChars(), smember.toChars(), access_ret); + } + + return access_ret; + } + + override void addLocalClass(ClassDeclarations aclasses) + { + aclasses.push(cast(void*)this); + } + + // Back end + override void toObjFile(int multiobj) // compile to .obj file + { + uint i; + uint offset; + Symbol* sinit; + enum_SC scclass; + + //printf("ClassDeclaration.toObjFile('%s')\n", toChars()); + + if (!members) + return; + + if (multiobj) + { + obj_append(this); + return; + } + + if (global.params.symdebug) + toDebug(); + + assert(!scope_); // semantic() should have been run to completion + + scclass = SCglobal; + if (inTemplateInstance()) + scclass = SCcomdat; + + // Put out the members + for (i = 0; i < members.dim; i++) + { + Dsymbol member; + + member = cast(Dsymbol)members.data[i]; + member.toObjFile(0); + } + +static if (false) { + // Build destructor by aggregating dtors[] + Symbol* sdtor; + switch (dtors.dim) + { + case 0: + // No destructors for this class + sdtor = null; + break; + + case 1: + // One destructor, just use it directly + sdtor = (cast(DtorDeclaration)dtors.data[0]).toSymbol(); + break; + + default: + { + /* Build a destructor that calls all the + * other destructors in dtors[]. + */ + + elem* edtor = null; + + // Declare 'this' pointer for our new destructor + Symbol* sthis = symbol_calloc("this"); + sthis.Stype = type_fake(TYnptr); + sthis.Stype.Tcount++; + sthis.Sclass = SCfastpar; + sthis.Spreg = AX; + sthis.Sfl = FLauto; + + // Call each of the destructors in dtors[] + // in reverse order + for (i = 0; i < dtors.dim; i++) + { + DtorDeclaration d = cast(DtorDeclaration)dtors.data[i]; + Symbol* s = d.toSymbol(); + elem* e = el_bin(OPcall, TYvoid, el_var(s), el_var(sthis)); + edtor = el_combine(e, edtor); + } + + // Create type for the function + .type* t = type_alloc(TYjfunc); + t.Tflags |= TFprototype | TFfixed; + t.Tmangle = mTYman_d; + t.Tnext = tsvoid; + tsvoid.Tcount++; + + // Create the function, sdtor, and write it out + localgot = null; + sdtor = toSymbolX("__dtor", SCglobal, t, "FZv"); + block* b = block_calloc(); + b.BC = BCret; + b.Belem = edtor; + sdtor.Sfunc.Fstartblock = b; + cstate.CSpsymtab = &sdtor.Sfunc.Flocsym; + symbol_add(sthis); + writefunc(sdtor); + } + } +} + + // Generate C symbols + toSymbol(); + toVtblSymbol(); + sinit = toInitializer(); + + ////////////////////////////////////////////// + + // Generate static initializer + sinit.Sclass = scclass; + sinit.Sfl = FLdata; + version (ELFOBJ) { // Burton + sinit.Sseg = Segment.CDATA; + } + version (MACHOBJ) { + sinit.Sseg = Segment.DATA; + } + toDt(&sinit.Sdt); + outdata(sinit); + + ////////////////////////////////////////////// + + // Put out the TypeInfo + type.getTypeInfo(null); + type.vtinfo.toObjFile(multiobj); + + ////////////////////////////////////////////// + + // Put out the ClassInfo + csym.Sclass = scclass; + csym.Sfl = FLdata; + + /* The layout is: + { + void **vptr; + monitor_t monitor; + byte[] initializer; // static initialization data + char[] name; // class name + void *[] vtbl; + Interface[] interfaces; + ClassInfo *base; // base class + void *destructor; + void *invariant; // class invariant + uint flags; + void *deallocator; + OffsetTypeInfo[] offTi; + void *defaultConstructor; + const(MemberInfo[]) function(string) xgetMembers; // module getMembers() function + TypeInfo typeinfo; + } + */ + dt_t* dt = null; + offset = CLASSINFO_SIZE; // must be ClassInfo.size + if (classinfo) + { + if (classinfo.structsize != CLASSINFO_SIZE) + error("D compiler and phobos' object.d are mismatched"); + } + + if (classinfo) + dtxoff(&dt, classinfo.toVtblSymbol(), 0, TYnptr); // vtbl for ClassInfo + else + dtdword(&dt, 0); // BUG: should be an assert() + + dtdword(&dt, 0); // monitor + + // initializer[] + assert(structsize >= 8); + dtdword(&dt, structsize); // size + dtxoff(&dt, sinit, 0, TYnptr); // initializer + + // name[] + string name = ident.toChars(); + size_t namelen = name.length; + if (!(namelen > 9 && name[0..9] == "TypeInfo_")) + { + name = toPrettyChars(); + namelen = name.length; + } + dtdword(&dt, namelen); + dtabytes(&dt, TYnptr, 0, namelen + 1, toStringz(name)); + + // vtbl[] + dtdword(&dt, vtbl.dim); + dtxoff(&dt, vtblsym, 0, TYnptr); + + // interfaces[] + dtdword(&dt, vtblInterfaces.dim); + if (vtblInterfaces.dim) + dtxoff(&dt, csym, offset, TYnptr); // (*) + else + dtdword(&dt, 0); + + // base + if (baseClass) + dtxoff(&dt, baseClass.toSymbol(), 0, TYnptr); + else + dtdword(&dt, 0); + + // destructor + if (dtor) + dtxoff(&dt, dtor.toSymbol(), 0, TYnptr); + else + dtdword(&dt, 0); + + // invariant + if (inv) + dtxoff(&dt, inv.toSymbol(), 0, TYnptr); + else + dtdword(&dt, 0); + + // flags + int flags = 4 | isCOMclass(); + version (DMDV2) { + flags |= 16; + } + flags |= 32; + + if (ctor) + flags |= 8; + for (ClassDeclaration cd = this; cd; cd = cd.baseClass) + { + if (cd.members) + { + for (size_t j = 0; j < cd.members.dim; j++) + { + Dsymbol sm = cast(Dsymbol)cd.members.data[j]; + //printf("sm = %s %s\n", sm.kind(), sm.toChars()); + if (sm.hasPointers()) + goto L2; + } + } + } + flags |= 2; // no pointers + L2: + dtdword(&dt, flags); + + + // deallocator + if (aggDelete) + dtxoff(&dt, aggDelete.toSymbol(), 0, TYnptr); + else + dtdword(&dt, 0); + + // offTi[] + dtdword(&dt, 0); + dtdword(&dt, 0); // null for now, fix later + + // defaultConstructor + if (defaultCtor) + dtxoff(&dt, defaultCtor.toSymbol(), 0, TYnptr); + else + dtdword(&dt, 0); + + version (DMDV2) { + FuncDeclaration sgetmembers = findGetMembers(); + if (sgetmembers) + dtxoff(&dt, sgetmembers.toSymbol(), 0, TYnptr); + else + dtdword(&dt, 0); // module getMembers() function + } + + dtxoff(&dt, type.vtinfo.toSymbol(), 0, TYnptr); // typeinfo + //dtdword(&dt, 0); + + ////////////////////////////////////////////// + + // Put out vtblInterfaces.data[]. Must immediately follow csym, because + // of the fixup (*) + + offset += vtblInterfaces.dim * (4 * PTRSIZE); + for (i = 0; i < vtblInterfaces.dim; i++) + { + BaseClass b = cast(BaseClass)vtblInterfaces.data[i]; + ClassDeclaration id = b.base; + + /* The layout is: + * { + * ClassInfo *interface; + * void *[] vtbl; + * unsigned offset; + * } + */ + + // Fill in vtbl[] + b.fillVtbl(this, b.vtbl, 1); + + dtxoff(&dt, id.toSymbol(), 0, TYnptr); // ClassInfo + + // vtbl[] + dtdword(&dt, id.vtbl.dim); + dtxoff(&dt, csym, offset, TYnptr); + + dtdword(&dt, b.offset); // this offset + + offset += id.vtbl.dim * PTRSIZE; + } + + // Put out the vtblInterfaces.data[].vtbl[] + // This must be mirrored with ClassDeclaration.baseVtblOffset() + //printf("putting out %d interface vtbl[]s for '%s'\n", vtblInterfaces.dim, toChars()); + for (i = 0; i < vtblInterfaces.dim; i++) + { + BaseClass b = cast(BaseClass)vtblInterfaces.data[i]; + ClassDeclaration id = b.base; + int j; + + //printf(" interface[%d] is '%s'\n", i, id.toChars()); + j = 0; + if (id.vtblOffset()) + { + // First entry is ClassInfo reference + //dtxoff(&dt, id.toSymbol(), 0, TYnptr); + + // First entry is struct Interface reference + dtxoff(&dt, csym, CLASSINFO_SIZE + i * (4 * PTRSIZE), TYnptr); + j = 1; + } + + assert(id.vtbl.dim == b.vtbl.dim); + for (; j < id.vtbl.dim; j++) + { + FuncDeclaration fd; + + assert(j < b.vtbl.dim); + static if (false) { + Object o = cast(Object)b.vtbl.data[j]; + if (o) + { + printf("o = %p\n", o); + assert(o.dyncast() == DYNCAST_DSYMBOL); + Dsymbol s = cast(Dsymbol)o; + printf("s.kind() = '%s'\n", s.kind()); + } + } + fd = cast(FuncDeclaration)b.vtbl.data[j]; + if (fd) + dtxoff(&dt, fd.toThunkSymbol(b.offset), 0, TYnptr); + else + dtdword(&dt, 0); + } + } + + static if (true) { + // Put out the overriding interface vtbl[]s. + // This must be mirrored with ClassDeclaration.baseVtblOffset() + //printf("putting out overriding interface vtbl[]s for '%s' at offset x%x\n", toChars(), offset); + ClassDeclaration cd; + scope Array bvtbl = new Array(); + + for (cd = this.baseClass; cd; cd = cd.baseClass) + { + for (int k = 0; k < cd.vtblInterfaces.dim; k++) + { + BaseClass bs = cast(BaseClass)cd.vtblInterfaces.data[k]; + + if (bs.fillVtbl(this, bvtbl, 0)) + { + //printf("\toverriding vtbl[] for %s\n", bs.base.toChars()); + ClassDeclaration id = bs.base; + int j; + + j = 0; + if (id.vtblOffset()) + { + // First entry is ClassInfo reference + //dtxoff(&dt, id.toSymbol(), 0, TYnptr); + + // First entry is struct Interface reference + dtxoff(&dt, cd.toSymbol(), CLASSINFO_SIZE + k * (4 * PTRSIZE), TYnptr); + j = 1; + } + + for (; j < id.vtbl.dim; j++) + { + assert(j < bvtbl.dim); + FuncDeclaration fd = cast(FuncDeclaration)bvtbl.data[j]; + if (fd) + dtxoff(&dt, fd.toThunkSymbol(bs.offset), 0, TYnptr); + else + dtdword(&dt, 0); + } + } + } + } + } + + version (INTERFACE_VIRTUAL) { + // Put out the overriding interface vtbl[]s. + // This must be mirrored with ClassDeclaration.baseVtblOffset() + //printf("putting out overriding interface vtbl[]s for '%s' at offset x%x\n", toChars(), offset); + for (i = 0; i < vtblInterfaces.dim; i++) + { + BaseClass b = cast(BaseClass)vtblInterfaces.data[i]; + ClassDeclaration cd; + + for (cd = this.baseClass; cd; cd = cd.baseClass) + { + for (int k = 0; k < cd.vtblInterfaces.dim; k++) + { + BaseClass bs = cast(BaseClass)cd.vtblInterfaces.data[k]; + + if (b.base == bs.base) + { + //printf("\toverriding vtbl[] for %s\n", b.base.toChars()); + ClassDeclaration id = b.base; + int j; + + j = 0; + if (id.vtblOffset()) + { + // First entry is ClassInfo reference + //dtxoff(&dt, id.toSymbol(), 0, TYnptr); + + // First entry is struct Interface reference + dtxoff(&dt, cd.toSymbol(), CLASSINFO_SIZE + k * (4 * PTRSIZE), TYnptr); + j = 1; + } + + for (; j < id.vtbl.dim; j++) + { + assert(j < b.vtbl.dim); + FuncDeclaration fd = cast(FuncDeclaration)b.vtbl.data[j]; + if (fd) + dtxoff(&dt, fd.toThunkSymbol(bs.offset), 0, TYnptr); + else + dtdword(&dt, 0); + } + } + } + } + } + } + + + csym.Sdt = dt; + version (ELFOBJ_OR_MACHOBJ) { // Burton + // ClassInfo cannot be const data, because we use the monitor on it + csym.Sseg = Segment.DATA; + } + outdata(csym); + if (isExport()) + obj_export(csym,0); + + ////////////////////////////////////////////// + + // Put out the vtbl[] + //printf("putting out %s.vtbl[]\n", toChars()); + dt = null; + if (0) + i = 0; + else + { + dtxoff(&dt, csym, 0, TYnptr); // first entry is ClassInfo reference + i = 1; + } + for (; i < vtbl.dim; i++) + { + FuncDeclaration fd = (cast(Dsymbol)vtbl.data[i]).isFuncDeclaration(); + + //printf("\tvtbl[%d] = %p\n", i, fd); + if (fd && (fd.fbody || !isAbstract())) + { + Symbol* s = fd.toSymbol(); + + version (DMDV2) { + if (isFuncHidden(fd)) + { + /* fd is hidden from the view of this class. + * If fd overlaps with any function in the vtbl[], then + * issue 'hidden' error. + */ + for (int j = 1; j < vtbl.dim; j++) + { + if (j == i) + continue; + FuncDeclaration fd2 = (cast(Dsymbol)vtbl.data[j]).isFuncDeclaration(); + if (!fd2.ident.equals(fd.ident)) + continue; + if (fd.leastAsSpecialized(fd2) || fd2.leastAsSpecialized(fd)) + { + if (global.params.warnings) + { + TypeFunction tf = cast(TypeFunction)fd.type; + if (tf.ty == Tfunction) + warning("%s%s is hidden by %s\n", fd.toPrettyChars(), Argument.argsTypesToChars(tf.parameters, tf.varargs), toChars()); + else + warning("%s is hidden by %s\n", fd.toPrettyChars(), toChars()); + } + s = rtlsym[RTLSYM_DHIDDENFUNC]; + break; + } + } + } + } + dtxoff(&dt, s, 0, TYnptr); + } + else + dtdword(&dt, 0); + } + + vtblsym.Sdt = dt; + vtblsym.Sclass = scclass; + vtblsym.Sfl = FLdata; + version (ELFOBJ) { + vtblsym.Sseg = Segment.CDATA; + } + version (MACHOBJ) { + vtblsym.Sseg = Segment.DATA; + } + outdata(vtblsym); + if (isExport()) + obj_export(vtblsym,0); + } + + void toDebug() + { + assert(false); + } + + /****************************************** + * Get offset of base class's vtbl[] initializer from start of csym. + * Returns ~0 if not this csym. + */ + uint baseVtblOffset(BaseClass bc) + { + uint csymoffset; + int i; + + //printf("ClassDeclaration.baseVtblOffset('%s', bc = %p)\n", toChars(), bc); + csymoffset = CLASSINFO_SIZE; + csymoffset += vtblInterfaces.dim * (4 * PTRSIZE); + + for (i = 0; i < vtblInterfaces.dim; i++) + { + BaseClass b = cast(BaseClass)vtblInterfaces.data[i]; + + if (b == bc) + return csymoffset; + csymoffset += b.base.vtbl.dim * PTRSIZE; + } + + static if (true) { + // Put out the overriding interface vtbl[]s. + // This must be mirrored with ClassDeclaration.baseVtblOffset() + //printf("putting out overriding interface vtbl[]s for '%s' at offset x%x\n", toChars(), offset); + ClassDeclaration cd; + Array bvtbl; + + for (cd = this.baseClass; cd; cd = cd.baseClass) + { + for (int k = 0; k < cd.vtblInterfaces.dim; k++) + { + BaseClass bs = cast(BaseClass)cd.vtblInterfaces.data[k]; + + if (bs.fillVtbl(this, null, 0)) + { + if (bc == bs) + { + //printf("\tcsymoffset = x%x\n", csymoffset); + return csymoffset; + } + csymoffset += bs.base.vtbl.dim * PTRSIZE; + } + } + } + } + version (INTERFACE_VIRTUAL) { + for (i = 0; i < vtblInterfaces.dim; i++) + { + BaseClass b = cast(BaseClass)vtblInterfaces.data[i]; + ClassDeclaration cd; + + for (cd = this.baseClass; cd; cd = cd.baseClass) + { + //printf("\tbase class %s\n", cd.toChars()); + for (int k = 0; k < cd.vtblInterfaces.dim; k++) + { + BaseClass bs = cast(BaseClass)cd.vtblInterfaces.data[k]; + + if (bc == bs) + { + //printf("\tcsymoffset = x%x\n", csymoffset); + return csymoffset; + } + if (b.base == bs.base) + csymoffset += bs.base.vtbl.dim * PTRSIZE; + } + } + } + } + + return ~0; + } + + static private __gshared Classsym* scc; + + /************************************* + * Create the "ClassInfo" symbol + */ + override Symbol* toSymbol() + { + if (!csym) + { + Symbol* s; + + if (!scc) + scc = fake_classsym(Id.ClassInfo); + + s = toSymbolX("__Class", SC.SCextern, scc.Stype, "Z"); + s.Sfl = FL.FLextern; + s.Sflags |= SFL.SFLnodebug; + csym = s; + slist_add(s); + } + + return csym; + } + + /************************************* + * This is accessible via the ClassData, but since it is frequently + * needed directly (like for rtti comparisons), make it directly accessible. + */ + Symbol* toVtblSymbol() + { + if (!vtblsym) + { + if (!csym) + toSymbol(); + + TYPE* t = type_alloc(TYM.TYnptr | mTY.mTYconst); + t.Tnext = tsvoid; + t.Tnext.Tcount++; + t.Tmangle = mTYman.mTYman_d; + + Symbol* s = toSymbolX("__vtbl", SC.SCextern, t, "Z"); + s.Sflags |= SFL.SFLnodebug; + s.Sfl = FL.FLextern; + vtblsym = s; + slist_add(s); + } + return vtblsym; + } + + // Generate the data for the static initializer. + void toDt(dt_t **pdt) + { + //printf("ClassDeclaration.toDt(this = '%s')\n", toChars()); + + // Put in first two members, the vtbl[] and the monitor + dtxoff(pdt, toVtblSymbol(), 0, TYnptr); + dtdword(pdt, 0); // monitor + + // Put in the rest + toDt2(pdt, this); + + //printf("-ClassDeclaration.toDt(this = '%s')\n", toChars()); + } + + void toDt2(dt_t** pdt, ClassDeclaration cd) + { + uint offset; + uint i; + dt_t* dt; + uint csymoffset; + + version (LOG) { + printf("ClassDeclaration.toDt2(this = '%s', cd = '%s')\n", toChars(), cd.toChars()); + } + if (baseClass) + { + baseClass.toDt2(pdt, cd); + offset = baseClass.structsize; + } + else + { + offset = 8; + } + + // Note equivalence of this loop to struct's + for (i = 0; i < fields.dim; i++) + { + VarDeclaration v = cast(VarDeclaration)fields.data[i]; + Initializer init; + + //printf("\t\tv = '%s' v.offset = %2d, offset = %2d\n", v.toChars(), v.offset, offset); + dt = null; + init = v.init; + if (init) + { + //printf("\t\t%s has initializer %s\n", v.toChars(), init.toChars()); + ExpInitializer ei = init.isExpInitializer(); + Type tb = v.type.toBasetype(); + if (ei && tb.ty == Tsarray) + (cast(TypeSArray)tb).toDtElem(&dt, ei.exp); + else + dt = init.toDt(); + } + else if (v.offset >= offset) + { //printf("\t\tdefault initializer\n"); + v.type.toDt(&dt); + } + if (dt) + { + if (v.offset < offset) + error("duplicated union initialization for %s", v.toChars()); + else + { + if (offset < v.offset) + dtnzeros(pdt, v.offset - offset); + dtcat(pdt, dt); + offset = v.offset + cast(uint)v.type.size(); + } + } + } + + // Interface vptr initializations + toSymbol(); // define csym + + for (i = 0; i < vtblInterfaces.dim; i++) + { + BaseClass b = cast(BaseClass)vtblInterfaces.data[i]; + +/// version (1 || INTERFACE_VIRTUAL) { + for (ClassDeclaration cd2 = cd; 1; cd2 = cd2.baseClass) + { + assert(cd2); + csymoffset = cd2.baseVtblOffset(b); + if (csymoffset != ~0) + { + if (offset < b.offset) + dtnzeros(pdt, b.offset - offset); + dtxoff(pdt, cd2.toSymbol(), csymoffset, TYnptr); + break; + } + } +/// } else { +/// csymoffset = baseVtblOffset(b); +/// assert(csymoffset != ~0); +/// dtxoff(pdt, csym, csymoffset, TYnptr); +/// } + offset = b.offset + 4; + } + + if (offset < structsize) + dtnzeros(pdt, structsize - offset); + } + + Symbol* vtblsym; + + ///ClassDeclaration isClassDeclaration() { return cast(ClassDeclaration)this; } /// huh? + override ClassDeclaration isClassDeclaration() { return this; } +} diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/DelegateExp.d --- a/dmd/DelegateExp.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/DelegateExp.d Sat Aug 28 19:42:41 2010 +0400 @@ -28,9 +28,9 @@ class DelegateExp : UnaExp { FuncDeclaration func; - int hasOverloads; + bool hasOverloads; - this(Loc loc, Expression e, FuncDeclaration f, int hasOverloads = 0) + this(Loc loc, Expression e, FuncDeclaration f, bool hasOverloads = false) { super(loc, TOK.TOKdelegate, DelegateExp.sizeof, e); this.func = f; diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/DivAssignExp.d --- a/dmd/DivAssignExp.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/DivAssignExp.d Sat Aug 28 19:42:41 2010 +0400 @@ -54,6 +54,7 @@ typeCombine(sc); e1.checkArithmetic(); e2.checkArithmetic(); + checkComplexMulAssign(); if (e2.type.isimaginary()) { Type t1; diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/DotVarExp.d --- a/dmd/DotVarExp.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/DotVarExp.d Sat Aug 28 19:42:41 2010 +0400 @@ -41,9 +41,9 @@ { Declaration var; - int hasOverloads; + bool hasOverloads; - this(Loc loc, Expression e, Declaration var, int hasOverloads = 0) + this(Loc loc, Expression e, Declaration var, bool hasOverloads = false) { super(loc, TOK.TOKdotvar, DotVarExp.sizeof, e); //printf("DotVarExp()\n"); diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/Dsymbol.d --- a/dmd/Dsymbol.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/Dsymbol.d Sat Aug 28 19:42:41 2010 +0400 @@ -843,7 +843,7 @@ id = cast(char*) GC.malloc(2 + nlen + size_t.sizeof * 3 + prefix.length + suffix.length + 1); else id = cast(char*) alloca(2 + nlen + size_t.sizeof * 3 + prefix.length + suffix.length + 1); - sprintf(id, "_D%.*s%lu%.*s%.*s", n, prefix.length, prefix, suffix); + sprintf(id, "_D%.*s%zu%.*s%.*s", n, prefix.length, prefix, suffix); static if (false) { if (global.params.isWindows && (type_mangle(t) == mTYman.mTYman_c || type_mangle(t) == mTYman.mTYman_std)) diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/DsymbolExp.d --- a/dmd/DsymbolExp.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/DsymbolExp.d Sat Aug 28 19:42:41 2010 +0400 @@ -36,9 +36,9 @@ class DsymbolExp : Expression { Dsymbol s; - int hasOverloads; + bool hasOverloads; - this(Loc loc, Dsymbol s, int hasOverloads = 0) + this(Loc loc, Dsymbol s, bool hasOverloads = false) { super(loc, TOK.TOKdsymbol, DsymbolExp.sizeof); this.s = s; diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/ErrorExp.d --- a/dmd/ErrorExp.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/ErrorExp.d Sat Aug 28 19:42:41 2010 +0400 @@ -3,6 +3,7 @@ import dmd.OutBuffer; import dmd.IntegerExp; import dmd.Loc; +import dmd.TOK; import dmd.HdrGenState; import dmd.Type; @@ -15,6 +16,7 @@ this() { super(Loc(0), 0, Type.terror); + op = TOKerror; } override void toCBuffer(OutBuffer buf, HdrGenState* hgs) diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/ExpInitializer.d --- a/dmd/ExpInitializer.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/ExpInitializer.d Sat Aug 28 19:42:41 2010 +0400 @@ -1,6 +1,7 @@ module dmd.ExpInitializer; import dmd.Initializer; +import dmd.DelegateExp; import dmd.Loc; import dmd.Scope; import dmd.Type; @@ -83,6 +84,15 @@ if (se.hasOverloads && !se.var.isFuncDeclaration().isUnique()) exp.error("cannot infer type from overloaded function symbol %s", exp.toChars()); } + + // Give error for overloaded function addresses + if (exp.op == TOKdelegate) + { + DelegateExp se = cast(DelegateExp)exp; + if (se.func.isFuncDeclaration() && !se.func.isFuncDeclaration().isUnique()) + exp.error("cannot infer type from overloaded function symbol %s", exp.toChars()); + } + Type t = exp.type; if (!t) diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/Expression.d --- a/dmd/Expression.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/Expression.d Sat Aug 28 19:42:41 2010 +0400 @@ -530,7 +530,11 @@ { IntRange ir; ir.imin = 0; - ir.imax = type.sizemask(); + if (type.isintegral()) + ir.imax = type.sizemask(); + else + ir.imax = 0xFFFFFFFFFFFFFFFFUL; // assume the worst + return ir; } @@ -741,8 +745,9 @@ Expression deref() { //printf("Expression::deref()\n"); - if (type.ty == TY.Treference) - { + // type could be null if forward referencing an 'auto' variable + if (type && type.ty == Treference) + { Expression e = new PtrExp(loc, this); e.type = (cast(TypeReference)type).next; return e; @@ -863,7 +868,11 @@ { if (flag == 0) { - if (op == TOKimport) + if (op == TOKerror) + { + // Error should have already been printed + } + else if (op == TOKimport) error("%s has no effect", toChars()); else error("%s has no effect in expression (%s)", diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/ForeachStatement.d --- a/dmd/ForeachStatement.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/ForeachStatement.d Sat Aug 28 19:42:41 2010 +0400 @@ -659,7 +659,7 @@ case TY.Tdchar: flag += 2; break; } string r = (op == TOK.TOKforeach_reverse) ? "R" : ""; - int j = sprintf(fdname.ptr, "_aApply%.*s%.*s%ld".ptr, r, 2, fntab[flag].ptr, dim); + 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); diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/FuncDeclaration.d --- a/dmd/FuncDeclaration.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/FuncDeclaration.d Sat Aug 28 19:42:41 2010 +0400 @@ -4,6 +4,9 @@ import dmd.DotIdExp; import dmd.AddrExp; import dmd.TryFinallyStatement; +import dmd.TryCatchStatement; +import dmd.Catch; +import dmd.DeclarationStatement; import dmd.StaticDtorDeclaration; import dmd.GlobalExpressions; import dmd.PeelStatement; @@ -80,7 +83,6 @@ import dmd.Util; import dmd.BaseClass; import dmd.Module; -import dmd.ILS; import dmd.InlineCostState; import dmd.expression.Util; @@ -126,6 +128,10 @@ Statement frequire; Statement fensure; Statement fbody; + + FuncDeclarations foverrides; // functions this function overrides + FuncDeclaration fdrequire; // function that does the in contract + FuncDeclaration fdensure; // function that does the out contract Identifier outId; // identifier for out statement VarDeclaration vresult; // variable corresponding to outId @@ -142,10 +148,10 @@ DsymbolTable labtab; // statement label symbol table Declaration overnext; // next in overload list Loc endloc; // location of closing curly bracket - int vtblIndex = -1; // for member functions, index into vtbl[] + int vtblIndex; // for member functions, index into vtbl[] int naked; // !=0 if naked int inlineAsm; // !=0 if has inline assembler - ILS inlineStatus = ILS.ILSuninitialized; + ILS inlineStatus; int inlineNest; // !=0 if nested inline int cantInterpret; // !=0 if cannot interpret function int semanticRun; // 1 semantic() run @@ -196,17 +202,52 @@ this.type = type; this.loc = loc; this.endloc = endloc; - + fthrows = null; + frequire = null; + fdrequire = null; + fdensure = null; + outId = null; + vresult = null; + returnLabel = null; + fensure = null; + fbody = null; + localsymtab = null; + vthis = null; + v_arguments = null; +version (IN_GCC) { + v_argptr = null; +} + parameters = null; + labtab = null; + overnext = null; + vtblIndex = -1; + hasReturnExp = 0; + naked = 0; + inlineStatus = ILS.ILSuninitialized; + inlineNest = 0; + inlineAsm = 0; + cantInterpret = 0; + semanticRun = 0; +version (DMDV1) { + nestedFrameRef = 0; +} + fes = null; + introducing = 0; + tintro = null; /* The type given for "infer the return type" is a TypeFunction with * null for the return type. */ inferRetType = (type && type.nextOf() is null); - + hasReturnExp = 0; + nrvo_can = 1; + nrvo_var = null; + shidden = null; +version (DMDV2) { + builtin = BUILTINunknown; + tookAddressOf = 0; +} + foverrides = new FuncDeclarations(); closureVars = new Dsymbols(); - -version (DMDV2) { - builtin = BUILTIN.BUILTINunknown; -} } override Dsymbol syntaxCopy(Dsymbol s) @@ -551,6 +592,10 @@ } cd.vtbl.data[vi] = cast(void*)this; vtblIndex = vi; + + /* Remember which functions this overrides + */ + foverrides.push(cast(void*)fdv); /* This works by whenever this function is called, * it actually returns tintro, which gets dynamically @@ -597,9 +642,13 @@ default: { FuncDeclaration fdv = cast(FuncDeclaration)b.base.vtbl.data[vi]; Type ti = null; + + /* Remember which functions this overrides + */ + foverrides.push(cast(void*)fdv); if (fdv.tintro) - ti = fdv.tintro; + ti = fdv.tintro; else if (!type.equals(fdv.type)) { /* Only need to have a tintro if the vptr @@ -727,6 +776,61 @@ } } } + + if (isVirtual()) + { + /* Rewrite contracts as nested functions, then call them. + * Doing it as nested functions means that overriding functions + * can call them. + */ + if (frequire) + { + /* in { ... } + * becomes: + * void __require() { ... } + * __require(); + */ + Loc loc = frequire.loc; + TypeFunction tf = new TypeFunction(null, Type.tvoid, 0, LINKd); + FuncDeclaration fd = new FuncDeclaration(loc, loc, Id.require, STCundefined, tf); + fd.fbody = frequire; + Statement s1 = new DeclarationStatement(loc, fd); + Expression e = new CallExp(loc, new VarExp(loc, fd, 0), cast(Expressions)null); + Statement s2 = new ExpStatement(loc, e); + frequire = new CompoundStatement(loc, s1, s2); + fdrequire = fd; + } + + if (fensure) + { /* out (result) { ... } + * becomes: + * tret __ensure(ref tret result) { ... } + * __ensure(result); + */ + if (!outId && f.nextOf().toBasetype().ty != Tvoid) + outId = Id.result; // provide a default + + Loc loc = fensure.loc; + Arguments arguments = new Arguments(); + Argument a = null; + if (outId) + { + a = new Argument(STCref, f.nextOf(), outId, null); + arguments.push(cast(void*)a); + } + TypeFunction tf = new TypeFunction(arguments, Type.tvoid, 0, LINKd); + FuncDeclaration fd = new FuncDeclaration(loc, loc, Id.ensure, STCundefined, tf); + fd.fbody = fensure; + Statement s1 = new DeclarationStatement(loc, fd); + Expression eresult = null; + if (outId) + eresult = new IdentifierExp(loc, outId); + Expression e = new CallExp(loc, new VarExp(loc, fd, 0), eresult); + Statement s2 = new ExpStatement(loc, e); + fensure = new CompoundStatement(loc, s1, s2); + fdensure = fd; + } + } Ldone: /* Save scope for possible later use (if we need the @@ -790,6 +894,9 @@ error("can only throw classes, not %s", t.toChars()); } } + + frequire = mergeFrequire(frequire); + fensure = mergeFensure(fensure); if (fbody || frequire) { @@ -1328,27 +1435,29 @@ if (argptr) { // Initialize _argptr to point past non-variadic arg version (IN_GCC) { - // Handled in FuncDeclaration.toObjFile - v_argptr = argptr; - v_argptr.init = new VoidInitializer(loc); + // Handled in FuncDeclaration.toObjFile + v_argptr = argptr; + v_argptr.init = new VoidInitializer(loc); } else { - Expression e1; - Expression e; - Type t = argptr.type; - VarDeclaration p; - uint offset; - - e1 = new VarExp(Loc(0), argptr); - if (parameters && parameters.dim) - p = cast(VarDeclaration)parameters.data[parameters.dim - 1]; - else - p = v_arguments; // last parameter is _arguments[] - offset = cast(uint)p.type.size(); /// - offset = (offset + 3) & ~3; // assume stack aligns on 4 - e = new SymOffExp(Loc(0), p, offset); - e = new AssignExp(Loc(0), e1, e); - e.type = t; - a.push(cast(void*)new ExpStatement(Loc(0), e)); + Type t = argptr.type; + VarDeclaration p; + uint offset; + + Expression e1 = new VarExp(Loc(0), argptr); + if (parameters && parameters.dim) + p = cast(VarDeclaration)parameters.data[parameters.dim - 1]; + else + p = v_arguments; // last parameter is _arguments[] + if (p.storage_class & STClazy) + // If the last parameter is lazy, it's the size of a delegate + offset = PTRSIZE * 2; + else + offset = cast(size_t)p.type.size(); + offset = (offset + 3) & ~3; // assume stack aligns on 4 + Expression e = new SymOffExp(Loc(0), p, offset); + e = new AssignExp(Loc(0), e1, e); + e.type = t; + a.push(cast(void*)new ExpStatement(Loc(0), e)); } } @@ -2767,6 +2876,99 @@ return true; } + /**************************************************** + * Merge into this function the 'in' contracts of all it overrides. + * 'in's are OR'd together, i.e. only one of them needs to pass. + */ + + Statement mergeFrequire(Statement sf) + { + /* Implementing this is done by having the overriding function call + * nested functions (the fdrequire functions) nested inside the overridden + * function. This requires that the stack layout of the calling function's + * parameters and 'this' pointer be in the same place (as the nested + * function refers to them). + * This is easy for the parameters, as they are all on the stack in the same + * place by definition, since it's an overriding function. The problem is + * getting the 'this' pointer in the same place, since it is a local variable. + * We did some hacks in the code generator to make this happen: + * 1. always generate exception handler frame, or at least leave space for it + * in the frame (Windows 32 SEH only) + * 2. always generate an EBP style frame + * 3. since 'this' is passed in a register that is subsequently copied into + * a stack local, allocate that local immediately following the exception + * handler block, so it is always at the same offset from EBP. + */ + for (int i = 0; i < foverrides.dim; i++) + { + FuncDeclaration fdv = cast(FuncDeclaration)foverrides.data[i]; + sf = fdv.mergeFrequire(sf); + if (fdv.frequire) + { + //printf("fdv.frequire: %s\n", fdv.frequire.toChars()); + /* Make the call: + * try { __require(); } + * catch { frequire; } + */ + Expression eresult = null; + Expression e = new CallExp(loc, new VarExp(loc, fdv.fdrequire, 0), eresult); + Statement s2 = new ExpStatement(loc, e); + + if (sf) + { + Catch c = new Catch(loc, null, null, sf); + Array catches = new Array(); + catches.push(cast(void*)c); + sf = new TryCatchStatement(loc, s2, catches); + } + else + sf = s2; + } + } + return sf; + } + + /**************************************************** + * Merge into this function the 'out' contracts of all it overrides. + * 'out's are AND'd together, i.e. all of them need to pass. + */ + + Statement mergeFensure(Statement sf) + { + /* Same comments as for mergeFrequire(), except that we take care + * of generating a consistent reference to the 'result' local by + * explicitly passing 'result' to the nested function as a reference + * argument. + * This won't work for the 'this' parameter as it would require changing + * the semantic code for the nested function so that it looks on the parameter + * list for the 'this' pointer, something that would need an unknown amount + * of tweaking of various parts of the compiler that I'd rather leave alone. + */ + for (int i = 0; i < foverrides.dim; i++) + { + FuncDeclaration fdv = cast(FuncDeclaration)foverrides.data[i]; + sf = fdv.mergeFensure(sf); + if (fdv.fensure) + { + //printf("fdv.fensure: %s\n", fdv.fensure.toChars()); + // Make the call: __ensure(result) + Expression eresult = null; + if (outId) + eresult = new IdentifierExp(loc, outId); + Expression e = new CallExp(loc, new VarExp(loc, fdv.fdensure, 0), eresult); + Statement s2 = new ExpStatement(loc, e); + + if (sf) + { + sf = new CompoundStatement(fensure.loc, s2, sf); + } + else + sf = s2; + } + } + return sf; + } + static FuncDeclaration genCfunc(Type treturn, string name) { return genCfunc(treturn, Lexer.idPool(name)); @@ -2991,6 +3193,16 @@ s = func.toSymbol(); f = s.Sfunc; + +version (TARGET_WINDOS) { + /* This is done so that the 'this' pointer on the stack is the same + * distance away from the function parameters, so that an overriding + * function can call the nested fdensure or fdrequire of its overridden function + * and the stack offsets are the same. + */ + if (isVirtual() && (fensure || frequire)) + f.Fflags3 |= F3.Ffakeeh; +} version (TARGET_OSX) { s.Sclass = SC.SCcomdat; diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/Global.d --- a/dmd/Global.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/Global.d Sat Aug 28 19:42:41 2010 +0400 @@ -37,7 +37,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.032"; + string version_ = "v2.033"; Param params; uint errors; // number of errors reported so far diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/Id.d --- a/dmd/Id.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/Id.d Sat Aug 28 19:42:41 2010 +0400 @@ -17,6 +17,8 @@ static Identifier _postblit; static Identifier classInvariant; static Identifier unitTest; + static Identifier require; + static Identifier ensure; static Identifier init_; static Identifier size; static Identifier __sizeof; @@ -242,6 +244,8 @@ _postblit = Lexer.idPool("__postblit"); classInvariant = Lexer.idPool("__invariant"); unitTest = Lexer.idPool("__unitTest"); + require = Lexer.idPool("__require"); + ensure = Lexer.idPool("__ensure"); init_ = Lexer.idPool("init"); size = Lexer.idPool("size"); __sizeof = Lexer.idPool("sizeof"); diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/IdentityExp.d --- a/dmd/IdentityExp.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/IdentityExp.d Sat Aug 28 19:42:41 2010 +0400 @@ -10,6 +10,7 @@ import dmd.Type; import dmd.WANT; import dmd.TY; +import dmd.GlobalExpressions; import dmd.expression.Identity; import dmd.backend.elem; @@ -61,6 +62,8 @@ if ((this.e1.isConst() && this.e2.isConst()) || (this.e1.op == TOK.TOKnull && this.e2.op == TOK.TOKnull)) { e = Identity(op, type, this.e1, this.e2); + if (e is EXP_CANT_INTERPRET) + e = this; } return e; diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/IndexExp.d --- a/dmd/IndexExp.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/IndexExp.d Sat Aug 28 19:42:41 2010 +0400 @@ -43,6 +43,9 @@ import dmd.backend.TYM; import core.stdc.string; +import core.stdc.stdio; + +extern (C) extern void exit(int); class IndexExp : BinExp { @@ -147,6 +150,9 @@ TupleExp te; TypeTuple tup; + printf("e1.op: %d\n", e1.op); + exit(-1); + if (e1.op == TOKtuple) { te = cast(TupleExp)e1; diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/IntegerExp.d --- a/dmd/IntegerExp.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/IntegerExp.d Sat Aug 28 19:42:41 2010 +0400 @@ -22,6 +22,7 @@ import dmd.backend.Util; import core.stdc.ctype : isprint; +import std.stdio; class IntegerExp : Expression { @@ -166,11 +167,16 @@ * the type is painted on like in fromConstInitializer(). */ if (!global.errors) - { + { + printf("ty = %d, %d\n", type.ty, t.ty); + if (type.ty == Tenum) { + printf("test1\n"); + } ///type.print(); assert(0); } break; + } break; } diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/Lexer.d --- a/dmd/Lexer.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/Lexer.d Sat Aug 28 19:42:41 2010 +0400 @@ -498,6 +498,7 @@ Token.tochars[TOK.TOKat] = "@"; // For debugging + Token.tochars[TOKerror] = "error"; Token.tochars[TOK.TOKdotexp] = "dotexp"; Token.tochars[TOK.TOKdotti] = "dotti"; Token.tochars[TOK.TOKdotvar] = "dotvar"; diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/MinAssignExp.d --- a/dmd/MinAssignExp.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/MinAssignExp.d Sat Aug 28 19:42:41 2010 +0400 @@ -54,6 +54,7 @@ { e1 = e1.checkArithmetic(); e2 = e2.checkArithmetic(); + checkComplexAddAssign(); type = e1.type; typeCombine(sc); if (type.isreal() || type.isimaginary()) diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/ModAssignExp.d --- a/dmd/ModAssignExp.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/ModAssignExp.d Sat Aug 28 19:42:41 2010 +0400 @@ -24,7 +24,9 @@ override Expression semantic(Scope sc) { - return commonSemanticAssign(sc); + BinExp.semantic(sc); + checkComplexMulAssign(); + return commonSemanticAssign(sc); } override Expression interpret(InterState istate) diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/Module.d --- a/dmd/Module.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/Module.d Sat Aug 28 19:42:41 2010 +0400 @@ -1164,8 +1164,11 @@ Dsymbol s; if (insearch) s = null; - else if (searchCacheIdent is ident && searchCacheFlags == flags) + else if (searchCacheIdent == ident && searchCacheFlags == flags && searchCacheSymbol) + { s = searchCacheSymbol; + //printf("%s Module.search('%s', flags = %d) insearch = %d searchCacheSymbol = %s\n", toChars(), ident.toChars(), flags, insearch, searchCacheSymbol ? searchCacheSymbol.toChars() : "null"); + } else { insearch = 1; diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/MulAssignExp.d --- a/dmd/MulAssignExp.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/MulAssignExp.d Sat Aug 28 19:42:41 2010 +0400 @@ -50,6 +50,7 @@ typeCombine(sc); e1.checkArithmetic(); e2.checkArithmetic(); + checkComplexMulAssign(); if (e2.type.isfloating()) { Type t1; diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/RealExp.d --- a/dmd/RealExp.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/RealExp.d Sat Aug 28 19:42:41 2010 +0400 @@ -21,6 +21,8 @@ import dmd.Complex; +import std.stdio; + class RealExp : Expression { real value; @@ -158,7 +160,7 @@ print(); ///type.print(); ///type.toBasetype().print(); - writef("ty = %d, tym = %x\n", type.ty, ty); + printf("ty = %d, tym = %lx\n", type.ty, ty); assert(0); } return el_const(ty, &c); diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/ReturnStatement.d --- a/dmd/ReturnStatement.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/ReturnStatement.d Sat Aug 28 19:42:41 2010 +0400 @@ -330,16 +330,22 @@ return gs; } - if (exp && tbret.ty == TY.Tvoid && !fd.isMain()) + if (exp && tbret.ty == Tvoid && !implicit0) { /* Replace: * return exp; * with: * exp; return; + * or, if main(): + * exp; return 0; */ Statement s = new ExpStatement(loc, exp); + //s = s.semantic(sc); loc = Loc(0); - exp = null; + if (fd.isMain()) + exp = new IntegerExp(0); + else + exp = null; return new CompoundStatement(loc, s, this); } diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/SymOffExp.d --- a/dmd/SymOffExp.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/SymOffExp.d Sat Aug 28 19:42:41 2010 +0400 @@ -28,7 +28,7 @@ { uint offset; - this(Loc loc, Declaration var, uint offset, int hasOverloads = 0) + this(Loc loc, Declaration var, uint offset, bool hasOverloads = false) { super(loc, TOK.TOKsymoff, SymOffExp.sizeof, var, hasOverloads); @@ -136,7 +136,7 @@ static if (false) { printf("SymOffExp::castTo(this=%s, type=%s, t=%s)\n", toChars(), type.toChars(), t.toChars()); } - if (type == t && hasOverloads == 0) + if (type == t && !hasOverloads) return this; Expression e; @@ -199,7 +199,7 @@ { e = copy(); e.type = t; - (cast(SymOffExp)e).hasOverloads = 0; + (cast(SymOffExp)e).hasOverloads = false; } return e; } diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/SymbolExp.d --- a/dmd/SymbolExp.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/SymbolExp.d Sat Aug 28 19:42:41 2010 +0400 @@ -23,9 +23,9 @@ { Declaration var; - int hasOverloads; + bool hasOverloads; - this(Loc loc, TOK op, int size, Declaration var, int hasOverloads) + this(Loc loc, TOK op, int size, Declaration var, bool hasOverloads) { super(loc, op, size); assert(var); diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/TOK.d --- a/dmd/TOK.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/TOK.d Sat Aug 28 19:42:41 2010 +0400 @@ -74,6 +74,7 @@ TOKidentifier, TOKstring, TOKthis, TOKsuper, TOKhalt, TOKtuple, + TOKerror, // Basic types TOKvoid, @@ -202,6 +203,7 @@ TOKidentifier, TOKstring, TOKthis, TOKsuper, TOKhalt, TOKtuple, + TOKerror, // Basic types TOKvoid, diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/Type.d --- a/dmd/Type.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/Type.d Sat Aug 28 19:42:41 2010 +0400 @@ -906,7 +906,7 @@ * a = b; * ? */ - int isAssignable() + bool isAssignable() { return true; } diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/TypeAArray.d --- a/dmd/TypeAArray.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/TypeAArray.d Sat Aug 28 19:42:41 2010 +0400 @@ -124,6 +124,7 @@ case Tfunction: case Tvoid: case Tnone: + case Ttuple: error(loc, "can't have associative array key of %s", index.toBasetype().toChars()); break; default: diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/TypeClass.d --- a/dmd/TypeClass.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/TypeClass.d Sat Aug 28 19:42:41 2010 +0400 @@ -398,7 +398,7 @@ e = e.semantic(sc); return e; } - else if (d.needThis() && (hasThis(sc) || !d.isFuncDeclaration())) + else if (d.needThis() && (hasThis(sc) || !(sc.intypeof || d.isFuncDeclaration()))) { if (sc.func) { diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/TypeEnum.d --- a/dmd/TypeEnum.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/TypeEnum.d Sat Aug 28 19:42:41 2010 +0400 @@ -129,18 +129,42 @@ override bool isintegral() { - return true; + return sym.memtype.isintegral(); } override bool isfloating() { - return false; + return sym.memtype.isfloating(); + } + + bool isreal() + { + return sym.memtype.isreal(); + } + + bool isimaginary() + { + return sym.memtype.isimaginary(); + } + + bool iscomplex() + { + return sym.memtype.iscomplex(); + } + + bool checkBoolean() + { + return sym.memtype.checkBoolean(); + } + + bool isAssignable() + { + return sym.memtype.isAssignable(); } override bool isscalar() { - return true; - //return sym.memtype.isscalar(); + return sym.memtype.isscalar(); } override bool isunsigned() diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/TypeFunction.d --- a/dmd/TypeFunction.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/TypeFunction.d Sat Aug 28 19:42:41 2010 +0400 @@ -10,6 +10,7 @@ import dmd.Global; import dmd.STC; import dmd.MOD; +import dmd.PROT; import dmd.Type; import dmd.Loc; import dmd.Scope; @@ -158,13 +159,20 @@ } if (tf.parameters) - { size_t dim = Argument.dim(tf.parameters); + { + /* Create a scope for evaluating the default arguments for the parameters + */ + Scope argsc = sc.push(); + argsc.stc = STCundefined; // don't inherit storage class + argsc.protection = PROT.PROTpublic; + + size_t dim = Argument.dim(tf.parameters); for (size_t i = 0; i < dim; i++) { Argument arg = Argument.getNth(tf.parameters, i); tf.inuse++; - arg.type = arg.type.semantic(loc,sc); + arg.type = arg.type.semantic(loc, argsc); if (tf.inuse == 1) tf.inuse--; arg.type = arg.type.addStorageClass(arg.storageClass); @@ -189,9 +197,9 @@ if (arg.defaultArg) { - arg.defaultArg = arg.defaultArg.semantic(sc); - arg.defaultArg = resolveProperties(sc, arg.defaultArg); - arg.defaultArg = arg.defaultArg.implicitCastTo(sc, arg.type); + arg.defaultArg = arg.defaultArg.semantic(argsc); + arg.defaultArg = resolveProperties(argsc, arg.defaultArg); + arg.defaultArg = arg.defaultArg.implicitCastTo(argsc, arg.type); } /* If arg turns out to be a tuple, the number of parameters may @@ -202,6 +210,7 @@ i--; } } + argsc.pop(); } if (tf.next) tf.deco = tf.merge().deco; @@ -307,10 +316,10 @@ switch (linkage) { case LINKd: p = null; break; - case LINKc: p = "C "; break; - case LINKwindows: p = "Windows "; break; - case LINKpascal: p = "Pascal "; break; - case LINKcpp: p = "C++ "; break; + case LINKc: p = " C"; break; + case LINKwindows: p = " Windows"; break; + case LINKpascal: p = " Pascal"; break; + case LINKcpp: p = " C++"; break; default: assert(0); } diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/TypeInfoArrayDeclaration.d --- a/dmd/TypeInfoArrayDeclaration.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/TypeInfoArrayDeclaration.d Sat Aug 28 19:42:41 2010 +0400 @@ -15,6 +15,7 @@ this(Type tinfo) { super(tinfo, 0); + type = Type.typeinfoarray.type; } override void toDt(dt_t** pdt) diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/TypeInfoAssociativeArrayDeclaration.d --- a/dmd/TypeInfoAssociativeArrayDeclaration.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/TypeInfoAssociativeArrayDeclaration.d Sat Aug 28 19:42:41 2010 +0400 @@ -13,6 +13,7 @@ this(Type tinfo) { super(tinfo, 0); + type = Type.typeinfoassociativearray.type; } override void toDt(dt_t** pdt) diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/TypeInfoClassDeclaration.d --- a/dmd/TypeInfoClassDeclaration.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/TypeInfoClassDeclaration.d Sat Aug 28 19:42:41 2010 +0400 @@ -16,6 +16,7 @@ this(Type tinfo) { super(tinfo, 0); + type = Type.typeinfostruct.type; } override void toDt(dt_t** pdt) diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/TypeInfoConstDeclaration.d --- a/dmd/TypeInfoConstDeclaration.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/TypeInfoConstDeclaration.d Sat Aug 28 19:42:41 2010 +0400 @@ -12,6 +12,7 @@ this(Type tinfo) { super(tinfo, 0); + type = Type.typeinfoconst.type; } override void toDt(dt_t** pdt) diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/TypeInfoDelegateDeclaration.d --- a/dmd/TypeInfoDelegateDeclaration.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/TypeInfoDelegateDeclaration.d Sat Aug 28 19:42:41 2010 +0400 @@ -14,6 +14,7 @@ this(Type tinfo) { super(tinfo, 0); + type = Type.typeinfodelegate.type; } override void toDt(dt_t** pdt) diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/TypeInfoEnumDeclaration.d --- a/dmd/TypeInfoEnumDeclaration.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/TypeInfoEnumDeclaration.d Sat Aug 28 19:42:41 2010 +0400 @@ -17,6 +17,7 @@ this(Type tinfo) { super(tinfo, 0); + type = Type.typeinfoenum.type; } override void toDt(dt_t** pdt) diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/TypeInfoFunctionDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeInfoFunctionDeclaration.d Sat Aug 28 19:42:41 2010 +0400 @@ -0,0 +1,20 @@ +module dmd.TypeInfoFunctionDeclaration; + +import dmd.Type; +import dmd.TypeInfoDeclaration; +import dmd.backend.dt_t; + +class TypeInfoFunctionDeclaration : TypeInfoDeclaration +{ + this(Type tinfo) + { + super(tinfo, 0); + type = Type.typeinfofunction.type; + } + + void toDt(dt_t** pdt) + { + assert(false); + } +} + diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/TypeInfoInterfaceDeclaration.d --- a/dmd/TypeInfoInterfaceDeclaration.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/TypeInfoInterfaceDeclaration.d Sat Aug 28 19:42:41 2010 +0400 @@ -16,6 +16,7 @@ this(Type tinfo) { super(tinfo, 0); + type = Type.typeinfointerface.type; } override void toDt(dt_t** pdt) diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/TypeInfoInvariantDeclaration.d --- a/dmd/TypeInfoInvariantDeclaration.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/TypeInfoInvariantDeclaration.d Sat Aug 28 19:42:41 2010 +0400 @@ -11,6 +11,7 @@ this(Type tinfo) { super(tinfo, 0); + type = Type.typeinfoinvariant.type; } override void toDt(dt_t** pdt) diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/TypeInfoPointerDeclaration.d --- a/dmd/TypeInfoPointerDeclaration.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/TypeInfoPointerDeclaration.d Sat Aug 28 19:42:41 2010 +0400 @@ -13,6 +13,7 @@ this(Type tinfo) { super(tinfo, 0); + type = Type.typeinfopointer.type; } override void toDt(dt_t** pdt) diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/TypeInfoSharedDeclaration.d --- a/dmd/TypeInfoSharedDeclaration.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/TypeInfoSharedDeclaration.d Sat Aug 28 19:42:41 2010 +0400 @@ -8,8 +8,8 @@ { this(Type tinfo) { - assert(false); super(tinfo, 0); + type = Type.typeinfoshared.type; } override void toDt(dt_t** pdt) diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/TypeInfoStaticArrayDeclaration.d --- a/dmd/TypeInfoStaticArrayDeclaration.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/TypeInfoStaticArrayDeclaration.d Sat Aug 28 19:42:41 2010 +0400 @@ -14,6 +14,7 @@ this(Type tinfo) { super(tinfo, 0); + type = Type.typeinfostaticarray.type; } override void toDt(dt_t** pdt) diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/TypeInfoStructDeclaration.d --- a/dmd/TypeInfoStructDeclaration.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/TypeInfoStructDeclaration.d Sat Aug 28 19:42:41 2010 +0400 @@ -28,6 +28,7 @@ this(Type tinfo) { super(tinfo, 0); + type = Type.typeinfostruct.type; } override void toDt(dt_t** pdt) diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/TypeInfoTupleDeclaration.d --- a/dmd/TypeInfoTupleDeclaration.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/TypeInfoTupleDeclaration.d Sat Aug 28 19:42:41 2010 +0400 @@ -18,6 +18,7 @@ this(Type tinfo) { super(tinfo, 0); + type = Type.typeinfotypelist.type; } override void toDt(dt_t **pdt) diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/TypeInfoTypedefDeclaration.d --- a/dmd/TypeInfoTypedefDeclaration.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/TypeInfoTypedefDeclaration.d Sat Aug 28 19:42:41 2010 +0400 @@ -17,6 +17,7 @@ this(Type tinfo) { super(tinfo, 0); + type = Type.typeinfotypedef.type; } override void toDt(dt_t** pdt) diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/TypeQualified.d --- a/dmd/TypeQualified.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/TypeQualified.d Sat Aug 28 19:42:41 2010 +0400 @@ -2,6 +2,7 @@ import dmd.Type; import dmd.Import; +import dmd.DsymbolExp; import dmd.TypeExp; import dmd.DotIdExp; import dmd.VarDeclaration; @@ -139,6 +140,19 @@ goto Lerror; goto L3; } + else if (v && id == Id.stringof_) + { + e = new DsymbolExp(loc, s, 0); + do + { + id = cast(Identifier)idents.data[i]; + e = new DotIdExp(loc, e, id); + } while (++i < idents.dim); + e = e.semantic(sc); + *pe = e; + return; + } + t = s.getType(); if (!t && s.isDeclaration()) t = s.isDeclaration().type; @@ -242,20 +256,29 @@ { if (t.reliesOnTident()) { - Scope scx; - - for (scx = sc; 1; scx = scx.enclosing) + if (s.scope_) + t = t.semantic(loc, s.scope_); + else { - if (!scx) - { - error(loc, "forward reference to '%s'", t.toChars()); - return; + /* Attempt to find correct scope in which to evaluate t. + * Not sure if this is right or not, or if we should just + * give forward reference error if s.scope is not set. + */ + for (Scope scx = sc; 1; scx = scx.enclosing) + { + if (!scx) + { + error(loc, "forward reference to '%s'", t.toChars()); + return; + } + if (scx.scopesym == scopesym) + { + t = t.semantic(loc, scx); + break; + } } - if (scx.scopesym == scopesym) - break; } - t = t.semantic(loc, scx); - //((TypeIdentifier *)t).resolve(loc, scx, pe, &t, ps); + } } if (t.ty == TY.Ttuple) diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/TypeStruct.d --- a/dmd/TypeStruct.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/TypeStruct.d Sat Aug 28 19:42:41 2010 +0400 @@ -428,7 +428,7 @@ return sym.zeroInit; } - override int isAssignable() + override bool isAssignable() { /* If any of the fields are const or invariant, * then one cannot assign this struct. diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/TypeTypedef.d --- a/dmd/TypeTypedef.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/TypeTypedef.d Sat Aug 28 19:42:41 2010 +0400 @@ -163,7 +163,7 @@ return sym.basetype.checkBoolean(); } - override int isAssignable() + override bool isAssignable() { return sym.basetype.isAssignable(); } diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/VarDeclaration.d --- a/dmd/VarDeclaration.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/VarDeclaration.d Sat Aug 28 19:42:41 2010 +0400 @@ -51,6 +51,7 @@ import dmd.OutBuffer; import dmd.HdrGenState; import dmd.PROT; +import dmd.expression.Util; import dmd.backend.Symbol; import dmd.backend.TYM; @@ -559,10 +560,20 @@ } } if (!ei.exp.implicitConvTo(type)) - { Type ti = ei.exp.type.toBasetype(); - // Don't cast away invariant or mutability in initializer - if (!(ti.ty == TY.Tstruct && t.toDsymbol(sc) == ti.toDsymbol(sc))) - ei.exp = new CastExp(loc, ei.exp, type); + { + /* Look for opCall + * See bugzilla 2702 for more discussion + */ + Type ti = ei.exp.type.toBasetype(); + // Don't cast away invariant or mutability in initializer + if (search_function(sd, Id.call) && + /* Initializing with the same type is done differently + */ + !(ti.ty == Tstruct && t.toDsymbol(sc) == ti.toDsymbol(sc))) + { // Rewrite as e1.call(arguments) + Expression eCall = new DotIdExp(loc, e1, Id.call); + ei.exp = new CallExp(loc, eCall, ei.exp); + } } } ei.exp = new AssignExp(loc, e1, ei.exp); diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/VarExp.d --- a/dmd/VarExp.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/VarExp.d Sat Aug 28 19:42:41 2010 +0400 @@ -26,7 +26,7 @@ class VarExp : SymbolExp { - this(Loc loc, Declaration var, int hasOverloads = 0) + this(Loc loc, Declaration var, bool hasOverloads = false) { super(loc, TOK.TOKvar, VarExp.sizeof, var, hasOverloads); diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/backend/F.d --- a/dmd/backend/F.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/backend/F.d Sat Aug 28 19:42:41 2010 +0400 @@ -57,4 +57,5 @@ Fnested = 0x1000, // D nested function with 'this' Fmember = 0x2000, // D member function with 'this' Fnotailrecursion = 0x4000, // no tail recursion optimizations + Ffakeeh = 0x8000, // allocate space for NT EH context sym anyway } \ No newline at end of file diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/codegen/Util.d --- a/dmd/codegen/Util.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/codegen/Util.d Sat Aug 28 19:42:41 2010 +0400 @@ -1,6 +1,7 @@ module dmd.codegen.Util; import dmd.Loc; +import dmd.Id; import dmd.IRState; import dmd.Type; import dmd.Array; @@ -351,7 +352,12 @@ Dsymbol fdparent = fd.toParent2(); //printf("getEthis(thisfd = '%s', fd = '%s', fdparent = '%s')\n", thisfd.toChars(), fd.toChars(), fdparent.toChars()); - if (fdparent == thisfd) + if (fdparent == thisfd || + /* These two are compiler generated functions for the in and out contracts, + * and are called from an overriding function, not just the one they're + * nested inside, so this hack is so they'll pass + */ + fd.ident == Id.require || fd.ident == Id.ensure) { /* Going down one nesting level, i.e. we're calling * a nested function from its enclosing function. @@ -405,6 +411,8 @@ ethis.Eoper = OPER.OPframeptr; } } + + //if (fdparent != thisfd) ethis = el_bin(OPadd, TYnptr, ethis, el_long(TYint, 0x18)); } else { diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/expression/Equal.d --- a/dmd/expression/Equal.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/expression/Equal.d Sat Aug 28 19:42:41 2010 +0400 @@ -3,6 +3,7 @@ import dmd.Expression; import dmd.Type; import dmd.TOK; +import dmd.TY; import dmd.Loc; import dmd.StringExp; import dmd.GlobalExpressions; @@ -194,7 +195,7 @@ { cmp = (e1.toComplex() == e2.toComplex()); } - else if (e1.type.isintegral()) + else if (e1.type.isintegral() || e1.type.ty == Tpointer) { cmp = (e1.toInteger() == e2.toInteger()); } diff -r 2e2a5c3f943a -r ef02e2e203c2 dmd/expression/Util.d --- a/dmd/expression/Util.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/expression/Util.d Sat Aug 28 19:42:41 2010 +0400 @@ -745,21 +745,28 @@ } } version (DMDV2) { - if (tb.ty == TY.Tstruct) + if (tb.ty == Tstruct) { arg = callCpCtor(loc, sc, arg); } +} - // Give error for overloaded function addresses - if (arg.op == TOK.TOKsymoff) - { - SymOffExp se = cast(SymOffExp)arg; - if (se.hasOverloads && !se.var.isFuncDeclaration().isUnique()) - arg.error("function %s is overloaded", arg.toChars()); - } + // Give error for overloaded function addresses + if (arg.op == TOKsymoff) + { + SymOffExp se = cast(SymOffExp)arg; +version (DMDV2) { + bool aux = (se.hasOverloads != 0); +} else { + bool aux = true; } - arg.rvalue(); - } + if (aux && !se.var.isFuncDeclaration().isUnique()) + arg.error("function %s is overloaded", arg.toChars()); + } + + arg.rvalue(); + } + arg = arg.optimize(WANT.WANTvalue); arguments.data[i] = cast(void*) arg; if (done) diff -r 2e2a5c3f943a -r ef02e2e203c2 rt/memory.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/memory.d Sat Aug 28 19:42:41 2010 +0400 @@ -0,0 +1,3 @@ +module rt.memory; + +extern(D) void initStaticDataGC(); \ No newline at end of file