From cb341586e310bfd595dbb9dc0a377bbcfea53d46 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sat, 19 Oct 2013 23:21:53 +0200 Subject: [PATCH] First merge of 2.064 beta. This corresponds to DMD commit a913ce4bc59a94a022a27e390fc841f4aededffb. Doesn't build Phobos yet. --- CMakeLists.txt | 4 +- dmd2/access.c | 76 +- dmd2/aggregate.h | 98 +- dmd2/aliasthis.h | 3 +- dmd2/apply.c | 38 +- dmd2/argtypes.c | 50 +- dmd2/arrayop.c | 242 +-- dmd2/arraytypes.h | 60 +- dmd2/attrib.c | 175 ++- dmd2/attrib.h | 78 +- dmd2/builtin.c | 4 +- dmd2/canthrow.c | 41 +- dmd2/cast.c | 126 +- dmd2/class.c | 475 +++--- dmd2/clone.c | 293 +++- dmd2/cond.c | 72 +- dmd2/cond.h | 32 +- dmd2/constfold.c | 80 +- dmd2/cppmangle.c | 31 +- dmd2/ctfe.h | 25 +- dmd2/ctfeexpr.c | 269 +++- dmd2/declaration.c | 296 ++-- dmd2/declaration.h | 395 ++--- dmd2/doc.c | 328 +++-- dmd2/dsymbol.c | 272 ++-- dmd2/dsymbol.h | 167 ++- dmd2/entity.c | 4 +- dmd2/enum.c | 636 +++++--- dmd2/enum.h | 55 +- dmd2/expression.c | 2695 ++++++++++++++++++++++------------ dmd2/expression.h | 492 ++++--- dmd2/func.c | 1214 ++++++++------- dmd2/identifier.c | 4 +- dmd2/identifier.h | 14 +- dmd2/idgen.c | 8 +- dmd2/import.c | 89 +- dmd2/import.h | 32 +- dmd2/init.c | 404 +++-- dmd2/init.h | 43 +- dmd2/inline.c | 87 +- dmd2/interpret.c | 2086 +++++++++++++++++--------- dmd2/intrange.h | 4 +- dmd2/json.c | 26 +- dmd2/lexer.c | 372 ++--- dmd2/lexer.h | 43 +- dmd2/macro.c | 36 +- dmd2/macro.h | 12 +- dmd2/mangle.c | 72 +- dmd2/mars.c | 279 +++- dmd2/mars.h | 59 +- dmd2/module.c | 367 +++-- dmd2/module.h | 57 +- dmd2/mtype.c | 1108 +++++++------- dmd2/mtype.h | 166 ++- dmd2/opover.c | 225 +-- dmd2/optimize.c | 237 +-- dmd2/parse.c | 632 ++++---- dmd2/parse.h | 81 +- dmd2/root/aav.c | 84 +- dmd2/root/array.c | 222 --- dmd2/root/longdouble.c | 6 +- dmd2/root/longdouble.h | 61 +- dmd2/root/port.c | 666 +++++---- dmd2/root/port.h | 35 +- dmd2/root/rmem.c | 61 +- dmd2/root/root.c | 92 +- dmd2/root/root.h | 272 +++- dmd2/scope.c | 169 ++- dmd2/scope.h | 65 +- dmd2/statement.c | 866 ++++++----- dmd2/statement.h | 242 ++- dmd2/staticassert.c | 20 +- dmd2/staticassert.h | 7 +- dmd2/struct.c | 233 ++- dmd2/target.h | 3 +- dmd2/template.c | 3170 +++++++++++++++++++++++++--------------- dmd2/template.h | 204 +-- dmd2/traits.c | 198 ++- dmd2/version.c | 18 + dmd2/version.h | 6 +- driver/main.cpp | 93 +- gen/aa.h | 2 +- gen/abi-x86-64.cpp | 7 +- gen/abi.h | 4 +- gen/arrays.h | 8 +- gen/asm-x86.h | 6 +- gen/cl_helpers.h | 4 +- gen/classes.cpp | 10 +- gen/classes.h | 11 +- gen/complex.h | 2 +- gen/declarations.cpp | 6 +- gen/dibuilder.cpp | 2 +- gen/dibuilder.h | 12 +- gen/dvalue.h | 8 +- gen/functions.cpp | 154 +- gen/functions.h | 8 +- gen/irstate.h | 14 +- gen/llvmhelpers.cpp | 17 +- gen/module.cpp | 10 +- gen/naked.cpp | 8 +- gen/pragma.h | 4 +- gen/rttibuilder.h | 12 +- gen/runtime.cpp | 4 +- gen/statements.cpp | 8 +- gen/structs.cpp | 27 +- gen/structs.h | 8 +- gen/target.cpp | 25 +- gen/tocall.cpp | 4 +- gen/toir.cpp | 6 +- gen/tollvm.cpp | 2 +- gen/typeinf.h | 2 +- gen/typinf.cpp | 21 +- gen/utils.h | 16 +- ir/iraggr.cpp | 62 - ir/iraggr.h | 5 +- ir/irclass.cpp | 16 +- ir/irdsymbol.h | 4 +- ir/irforw.h | 20 +- ir/irfunction.h | 2 +- ir/irfuncty.h | 2 +- ir/irmodule.h | 2 +- ir/irtype.h | 2 +- ir/irtypeaggr.h | 4 +- ir/irtypeclass.cpp | 24 +- ir/irtypeclass.h | 5 +- ir/irtypestruct.h | 4 +- ir/irvar.h | 2 +- runtime/CMakeLists.txt | 4 - runtime/druntime | 2 +- runtime/phobos | 2 +- 130 files changed, 13566 insertions(+), 9190 deletions(-) delete mode 100644 dmd2/root/array.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 847d9b5c..9bcb3993 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,8 +33,8 @@ include(GetLinuxDistribution) set(LDC_VERSION "0.12.0") # May be overridden by git hash tag set(DMDFE_MAJOR_VERSION 2) set(DMDFE_MINOR_VERSION 0) -set(DMDFE_PATCH_VERSION 63) -set(DMDFE_FIX_LEVEL 2) # Comment out if not used +set(DMDFE_PATCH_VERSION 64) +#set(DMDFE_FIX_LEVEL 2) # Comment out if not used set(DMD_VERSION ${DMDFE_MAJOR_VERSION}.${DMDFE_MINOR_VERSION}${DMDFE_PATCH_VERSION}) if(DEFINED DMDFE_FIX_LEVEL) diff --git a/dmd2/access.c b/dmd2/access.c index 1d2e5a1c..968d3549 100644 --- a/dmd2/access.c +++ b/dmd2/access.c @@ -38,14 +38,14 @@ int hasPackageAccess(Scope *sc, Dsymbol *s); * Return PROT access for Dsymbol smember in this declaration. */ -enum PROT AggregateDeclaration::getAccess(Dsymbol *smember) +PROT AggregateDeclaration::getAccess(Dsymbol *smember) { return PROTpublic; } -enum PROT StructDeclaration::getAccess(Dsymbol *smember) +PROT StructDeclaration::getAccess(Dsymbol *smember) { - enum PROT access_ret = PROTnone; + PROT access_ret = PROTnone; #if LOG printf("+StructDeclaration::getAccess(this = '%s', smember = '%s')\n", @@ -62,9 +62,9 @@ enum PROT StructDeclaration::getAccess(Dsymbol *smember) return access_ret; } -enum PROT ClassDeclaration::getAccess(Dsymbol *smember) +PROT ClassDeclaration::getAccess(Dsymbol *smember) { - enum PROT access_ret = PROTnone; + PROT access_ret = PROTnone; #if LOG printf("+ClassDeclaration::getAccess(this = '%s', smember = '%s')\n", @@ -84,7 +84,7 @@ enum PROT ClassDeclaration::getAccess(Dsymbol *smember) for (size_t i = 0; i < baseclasses->dim; i++) { BaseClass *b = (*baseclasses)[i]; - enum PROT access = b->base->getAccess(smember); + PROT access = b->base->getAccess(smember); switch (access) { case PROTnone: @@ -152,7 +152,7 @@ static int accessCheckX( { for (size_t i = 0; i < cdthis->baseclasses->dim; i++) { BaseClass *b = (*cdthis->baseclasses)[i]; - enum PROT access = b->base->getAccess(smember); + PROT access = b->base->getAccess(smember); if (access >= PROTprotected || accessCheckX(smember, sfunc, b->base, cdscope) ) @@ -192,7 +192,7 @@ void AggregateDeclaration::accessCheck(Loc loc, Scope *sc, Dsymbol *smember) FuncDeclaration *f = sc->func; AggregateDeclaration *cdscope = sc->getStructClassScope(); - enum PROT access; + PROT access; #if LOG printf("AggregateDeclaration::accessCheck() for %s.%s in function %s() in scope %s\n", @@ -214,7 +214,7 @@ void AggregateDeclaration::accessCheck(Loc loc, Scope *sc, Dsymbol *smember) //assert(smember->parent->isBaseOf(this, NULL)); if (smemberparent == this) - { enum PROT access2 = smember->prot(); + { PROT access2 = smember->prot(); result = access2 >= PROTpublic || hasPrivateAccess(f) || @@ -290,25 +290,60 @@ int hasPackageAccess(Scope *sc, Dsymbol *s) printf("hasPackageAccess(s = '%s', sc = '%p')\n", s->toChars(), sc); #endif + Package *pkg = NULL; for (; s; s = s->parent) { - if (s->isPackage() && !s->isModule()) + if (Module *m = s->isModule()) + { + DsymbolTable *dst = Package::resolve(m->md ? m->md->packages : NULL, NULL, NULL); + assert(dst); + Dsymbol *s2 = dst->lookup(m->ident); + assert(s2); + Package *p = s2->isPackage(); + if (p && p->isPkgMod == PKGmodule) + { + assert(p->mod == m); + pkg = p; + break; + } + } + else if ((pkg = s->isPackage()) != NULL) break; } #if LOG - if (s) - printf("\tthis is in package '%s'\n", s->toChars()); + if (pkg) + printf("\tthis is in package '%s'\n", pkg->toChars()); #endif - if (s && s == sc->module->parent) + if (pkg) { + if (pkg == sc->module->parent) + { #if LOG - printf("\ts is in same package as sc\n"); + printf("\ts is in same package as sc\n"); #endif - return 1; + return 1; + } + if (pkg->isPkgMod == PKGmodule && pkg->mod == sc->module) + { +#if LOG + printf("\ts is in same package.d module as sc\n"); +#endif + return 1; + } + s = sc->module->parent; + for (; s; s = s->parent) + { + if (s == pkg) + { +#if LOG + printf("\ts is in ancestor package of sc\n"); +#endif + return 1; + } + } } - #if LOG printf("\tno package access\n"); #endif @@ -375,6 +410,9 @@ int AggregateDeclaration::hasPrivateAccess(Dsymbol *smember) void accessCheck(Loc loc, Scope *sc, Expression *e, Declaration *d) { + if (sc->flags & SCOPEnoaccesscheck) + return; + #if LOG if (e) { printf("accessCheck(%s . %s)\n", e->toChars(), d->toChars()); @@ -395,7 +433,8 @@ void accessCheck(Loc loc, Scope *sc, Expression *e, Declaration *d) } } else if (e->type->ty == Tclass) - { // Do access check + { + // Do access check ClassDeclaration *cd = (ClassDeclaration *)(((TypeClass *)e->type)->sym); if (e->op == TOKsuper) { @@ -406,7 +445,8 @@ void accessCheck(Loc loc, Scope *sc, Expression *e, Declaration *d) cd->accessCheck(loc, sc, d); } else if (e->type->ty == Tstruct) - { // Do access check + { + // Do access check StructDeclaration *cd = (StructDeclaration *)(((TypeStruct *)e->type)->sym); cd->accessCheck(loc, sc, d); } diff --git a/dmd2/aggregate.h b/dmd2/aggregate.h index a324a0c8..d8225de2 100644 --- a/dmd2/aggregate.h +++ b/dmd2/aggregate.h @@ -20,19 +20,19 @@ #include "dsymbol.h" #include "declaration.h" -struct Identifier; -struct Type; -struct TypeFunction; -struct Expression; -struct FuncDeclaration; -struct CtorDeclaration; -struct DtorDeclaration; -struct InvariantDeclaration; -struct NewDeclaration; -struct DeleteDeclaration; -struct InterfaceDeclaration; -struct TypeInfoClassDeclaration; -struct VarDeclaration; +class Identifier; +class Type; +class TypeFunction; +class Expression; +class FuncDeclaration; +class CtorDeclaration; +class DtorDeclaration; +class InvariantDeclaration; +class NewDeclaration; +class DeleteDeclaration; +class InterfaceDeclaration; +class TypeInfoClassDeclaration; +class VarDeclaration; struct dt_t; enum Sizeok @@ -42,17 +42,18 @@ enum Sizeok SIZEOKfwd, // error in computing size of aggregate }; -struct AggregateDeclaration : ScopeDsymbol +class AggregateDeclaration : public ScopeDsymbol { +public: Type *type; StorageClass storage_class; - enum PROT protection; + PROT protection; Type *handle; // 'this' type unsigned structsize; // size of struct unsigned alignsize; // size of struct for alignment purposes int hasUnions; // set if aggregate has overlapping fields VarDeclarations fields; // VarDeclaration fields - enum Sizeok sizeok; // set when structsize contains valid data + Sizeok sizeok; // set when structsize contains valid data Dsymbol *deferred; // any deferred semantic2() or semantic3() symbol bool isdeprecated; // !=0 if deprecated @@ -103,7 +104,8 @@ struct AggregateDeclaration : ScopeDsymbol FuncDeclaration *buildInv(Scope *sc); bool isNested(); void makeNested(); - int isExport(); + bool isExport(); + void searchCtor(); void emitComment(Scope *sc); void toJson(JsonOut *json); @@ -120,7 +122,7 @@ struct AggregateDeclaration : ScopeDsymbol int hasPrivateAccess(Dsymbol *smember); // does smember have private access to members of this class? void accessCheck(Loc loc, Scope *sc, Dsymbol *smember); - enum PROT prot(); + PROT prot(); #if IN_DMD // Back end @@ -137,8 +139,18 @@ struct AggregateDeclaration : ScopeDsymbol #endif }; -struct StructDeclaration : AggregateDeclaration +struct StructFlags { + typedef unsigned Type; + enum Enum + { + hasPointers = 0x1, // NB: should use noPointers as in ClassFlags + }; +}; + +class StructDeclaration : public AggregateDeclaration +{ +public: int zeroInit; // !=0 if initialize with 0 fill #if DMDV2 int hasIdentityAssign; // !=0 if has identity opAssign @@ -148,7 +160,9 @@ struct StructDeclaration : AggregateDeclaration FuncDeclaration *postblit; // aggregate postblit FuncDeclaration *xeq; // TypeInfo_Struct.xopEquals + FuncDeclaration *xcmp; // TypeInfo_Struct.xopCmp static FuncDeclaration *xerreq; // object.xopEquals + static FuncDeclaration *xerrcmp; // object.xopCmp structalign_t alignment; // alignment applied outside of the struct #endif @@ -177,6 +191,7 @@ struct StructDeclaration : AggregateDeclaration FuncDeclaration *buildCpCtor(Scope *sc); FuncDeclaration *buildOpEquals(Scope *sc); FuncDeclaration *buildXopEquals(Scope *sc); + FuncDeclaration *buildXopCmp(Scope *sc); #endif void toDocBuffer(OutBuffer *buf, Scope *sc); @@ -195,8 +210,9 @@ struct StructDeclaration : AggregateDeclaration #endif }; -struct UnionDeclaration : StructDeclaration +class UnionDeclaration : public StructDeclaration { +public: UnionDeclaration(Loc loc, Identifier *id); Dsymbol *syntaxCopy(Dsymbol *s); const char *kind(); @@ -207,10 +223,10 @@ struct UnionDeclaration : StructDeclaration struct BaseClass { Type *type; // (before semantic processing) - enum PROT protection; // protection for the base interface + PROT protection; // protection for the base interface ClassDeclaration *base; - int offset; // 'this' pointer offset + unsigned offset; // 'this' pointer offset FuncDeclarations vtbl; // for interfaces: Array of FuncDeclaration's // making up the vtbl[] @@ -219,7 +235,7 @@ struct BaseClass // are a copy of the InterfaceDeclaration::interfaces BaseClass(); - BaseClass(Type *type, enum PROT protection); + BaseClass(Type *type, PROT protection); int fillVtbl(ClassDeclaration *cd, FuncDeclarations *vtbl, int newinstance); void copyBaseInterfaces(BaseClasses *); @@ -233,10 +249,26 @@ struct BaseClass #define CLASSINFO_SIZE_64 (0x98) // value of ClassInfo.size #endif -struct ClassDeclaration : AggregateDeclaration +struct ClassFlags { + typedef unsigned Type; + enum Enum + { + isCOMclass = 0x1, + noPointers = 0x2, + hasOffTi = 0x4, + hasCtor = 0x8, + hasGetMembers = 0x10, + hasTypeInfo = 0x20, + isAbstract = 0x40, + isCPPclass = 0x80, + }; +}; + +class ClassDeclaration : public AggregateDeclaration +{ +public: static ClassDeclaration *object; - static ClassDeclaration *classinfo; static ClassDeclaration *throwable; static ClassDeclaration *exception; static ClassDeclaration *errorException; @@ -264,14 +296,17 @@ struct ClassDeclaration : AggregateDeclaration TypeInfoClassDeclaration *vclassinfo; // the ClassInfo object for this ClassDeclaration int com; // !=0 if this is a COM class (meaning // it derives from IUnknown) +#if DMDV2 + int cpp; // !=0 if this is a C++ interface +#endif int isscope; // !=0 if this is an auto class int isabstract; // !=0 if abstract class int inuse; // to prevent recursive attempts - enum Semantic doAncestorsSemantic; // Before searching symbol, whole ancestors should finish + Semantic doAncestorsSemantic; // Before searching symbol, whole ancestors should finish // calling semantic() at least once, due to fill symtab // and do addMember(). [== Semantic(Start,In,Done)] - ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses); + ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses, bool inObject = false); Dsymbol *syntaxCopy(Dsymbol *s); void semantic(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -291,9 +326,10 @@ struct ClassDeclaration : AggregateDeclaration int isCOMclass(); virtual int isCOMinterface(); #if DMDV2 + int isCPPclass(); virtual int isCPPinterface(); #endif - int isAbstract(); + bool isAbstract(); virtual int vtblOffset(); const char *kind(); const char *mangle(bool isv = false); @@ -323,11 +359,9 @@ struct ClassDeclaration : AggregateDeclaration #endif }; -struct InterfaceDeclaration : ClassDeclaration +class InterfaceDeclaration : public ClassDeclaration { -#if DMDV2 - int cpp; // !=0 if this is a C++ interface -#endif +public: InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses); Dsymbol *syntaxCopy(Dsymbol *s); void semantic(Scope *sc); diff --git a/dmd2/aliasthis.h b/dmd2/aliasthis.h index c804cdb5..5f4cd685 100644 --- a/dmd2/aliasthis.h +++ b/dmd2/aliasthis.h @@ -22,8 +22,9 @@ #if DMDV2 -struct AliasThis : Dsymbol +class AliasThis : public Dsymbol { +public: // alias Identifier this; Identifier *ident; diff --git a/dmd2/apply.c b/dmd2/apply.c index 320b24a8..afd45456 100644 --- a/dmd2/apply.c +++ b/dmd2/apply.c @@ -26,9 +26,7 @@ * Creating an iterator for this would be much more complex. */ -typedef int (*fp_t)(Expression *, void *); - -int Expression::apply(fp_t fp, void *param) +int Expression::apply(apply_fp_t fp, void *param) { return (*fp)(this, param); } @@ -38,7 +36,7 @@ int Expression::apply(fp_t fp, void *param) */ #define condApply(t, fp, param) (t ? t->apply(fp, param) : 0) -int NewExp::apply(int (*fp)(Expression *, void *), void *param) +int NewExp::apply(apply_fp_t fp, void *param) { //printf("NewExp::apply(): %s\n", toChars()); @@ -48,7 +46,7 @@ int NewExp::apply(int (*fp)(Expression *, void *), void *param) (*fp)(this, param); } -int NewAnonClassExp::apply(int (*fp)(Expression *, void *), void *param) +int NewAnonClassExp::apply(apply_fp_t fp, void *param) { //printf("NewAnonClassExp::apply(): %s\n", toChars()); @@ -58,47 +56,47 @@ int NewAnonClassExp::apply(int (*fp)(Expression *, void *), void *param) (*fp)(this, param); } -int UnaExp::apply(fp_t fp, void *param) +int UnaExp::apply(apply_fp_t fp, void *param) { return e1->apply(fp, param) || (*fp)(this, param); } -int BinExp::apply(fp_t fp, void *param) +int BinExp::apply(apply_fp_t fp, void *param) { return e1->apply(fp, param) || e2->apply(fp, param) || (*fp)(this, param); } -int AssertExp::apply(fp_t fp, void *param) +int AssertExp::apply(apply_fp_t fp, void *param) { - //printf("CallExp::apply(fp_t fp, void *param): %s\n", toChars()); + //printf("CallExp::apply(apply_fp_t fp, void *param): %s\n", toChars()); return e1->apply(fp, param) || condApply(msg, fp, param) || (*fp)(this, param); } -int CallExp::apply(fp_t fp, void *param) +int CallExp::apply(apply_fp_t fp, void *param) { - //printf("CallExp::apply(fp_t fp, void *param): %s\n", toChars()); + //printf("CallExp::apply(apply_fp_t fp, void *param): %s\n", toChars()); return e1->apply(fp, param) || condApply(arguments, fp, param) || (*fp)(this, param); } -int ArrayExp::apply(fp_t fp, void *param) +int ArrayExp::apply(apply_fp_t fp, void *param) { - //printf("ArrayExp::apply(fp_t fp, void *param): %s\n", toChars()); + //printf("ArrayExp::apply(apply_fp_t fp, void *param): %s\n", toChars()); return e1->apply(fp, param) || condApply(arguments, fp, param) || (*fp)(this, param); } -int SliceExp::apply(fp_t fp, void *param) +int SliceExp::apply(apply_fp_t fp, void *param) { return e1->apply(fp, param) || condApply(lwr, fp, param) || @@ -107,14 +105,14 @@ int SliceExp::apply(fp_t fp, void *param) } -int ArrayLiteralExp::apply(fp_t fp, void *param) +int ArrayLiteralExp::apply(apply_fp_t fp, void *param) { return condApply(elements, fp, param) || (*fp)(this, param); } -int AssocArrayLiteralExp::apply(fp_t fp, void *param) +int AssocArrayLiteralExp::apply(apply_fp_t fp, void *param) { return condApply(keys, fp, param) || condApply(values, fp, param) || @@ -122,19 +120,19 @@ int AssocArrayLiteralExp::apply(fp_t fp, void *param) } -int StructLiteralExp::apply(fp_t fp, void *param) +int StructLiteralExp::apply(apply_fp_t fp, void *param) { if(stageflags & stageApply) return 0; int old = stageflags; stageflags |= stageApply; int ret = condApply(elements, fp, param) || (*fp)(this, param); - stageflags = old; + stageflags = old; return ret; } -int TupleExp::apply(fp_t fp, void *param) +int TupleExp::apply(apply_fp_t fp, void *param) { return (e0 ? (*fp)(e0, param) : 0) || condApply(exps, fp, param) || @@ -142,7 +140,7 @@ int TupleExp::apply(fp_t fp, void *param) } -int CondExp::apply(fp_t fp, void *param) +int CondExp::apply(apply_fp_t fp, void *param) { return econd->apply(fp, param) || e1->apply(fp, param) || diff --git a/dmd2/argtypes.c b/dmd2/argtypes.c index 0030cc2f..989caf20 100644 --- a/dmd2/argtypes.c +++ b/dmd2/argtypes.c @@ -154,14 +154,6 @@ TypeTuple *TypeSArray::toArgTypes() #endif } -TypeTuple *TypeDArray::toArgTypes() -{ - /* Should be done as if it were: - * struct S { size_t length; void* ptr; } - */ - return new TypeTuple(Type::tsize_t, Type::tvoidptr); -} - TypeTuple *TypeAArray::toArgTypes() { return new TypeTuple(Type::tvoidptr); @@ -172,14 +164,6 @@ TypeTuple *TypePointer::toArgTypes() return new TypeTuple(Type::tvoidptr); } -TypeTuple *TypeDelegate::toArgTypes() -{ - /* Should be done as if it were: - * struct S { void* ptr; void* funcptr; } - */ - return new TypeTuple(Type::tvoidptr, Type::tvoidptr); -} - /************************************* * Convert a floating point type into the equivalent integral type. */ @@ -273,6 +257,38 @@ Type *argtypemerge(Type *t1, Type *t2, unsigned offset2) return t; } +TypeTuple *TypeDArray::toArgTypes() +{ + /* Should be done as if it were: + * struct S { size_t length; void* ptr; } + */ + if (global.params.is64bit && !global.params.isLP64) + { + // For AMD64 ILP32 ABI, D arrays fit into a single integer register. + unsigned offset = Type::tsize_t->size(Loc()); + Type *t = argtypemerge(Type::tsize_t, Type::tvoidptr, offset); + if (t) + return new TypeTuple(t); + } + return new TypeTuple(Type::tsize_t, Type::tvoidptr); +} + +TypeTuple *TypeDelegate::toArgTypes() +{ + /* Should be done as if it were: + * struct S { size_t length; void* ptr; } + */ + if (global.params.is64bit && !global.params.isLP64) + { + // For AMD64 ILP32 ABI, delegates fit into a single integer register. + unsigned offset = Type::tsize_t->size(Loc()); + Type *t = argtypemerge(Type::tsize_t, Type::tvoidptr, offset); + if (t) + return new TypeTuple(t); + } + return new TypeTuple(Type::tvoidptr, Type::tvoidptr); +} + TypeTuple *TypeStruct::toArgTypes() { //printf("TypeStruct::toArgTypes() %s\n", toChars()); @@ -309,8 +325,6 @@ TypeTuple *TypeStruct::toArgTypes() if (global.params.is64bit && sym->fields.dim) { #if 1 - unsigned sz1 = 0; - unsigned sz2 = 0; t1 = NULL; for (size_t i = 0; i < sym->fields.dim; i++) { VarDeclaration *f = sym->fields[i]; diff --git a/dmd2/arrayop.c b/dmd2/arrayop.c index 3f9f9a48..61ddf7b7 100644 --- a/dmd2/arrayop.c +++ b/dmd2/arrayop.c @@ -250,18 +250,18 @@ int isDruntimeArrayOp(Identifier *ident) ArrayOp *buildArrayOp(Identifier *ident, BinExp *exp, Scope *sc, Loc loc) { - ArrayOp *op = new ArrayOp; -#if IN_LLVM // LDC: Build parameters. Parameters *fparams = new Parameters(); Expression *loopbody = exp->buildArrayLoop(fparams); + + ArrayOp *op = new ArrayOp; if (isDruntimeArrayOp(ident)) +#if IN_LLVM { +#endif op->cFunc = FuncDeclaration::genCfunc(fparams, exp->type, ident); +#if IN_LLVM op->cFunc->isArrayOp = 2; } -#else - if (isDruntimeArrayOp(ident)) - op->cFunc = FuncDeclaration::genCfunc(exp->type, ident); #endif else op->cFunc = NULL; @@ -271,10 +271,6 @@ ArrayOp *buildArrayOp(Identifier *ident, BinExp *exp, Scope *sc, Loc loc) * loopbody; * return p; */ -#if !IN_LLVM - Parameters *fparams = new Parameters(); - Expression *loopbody = exp->buildArrayLoop(fparams); -#endif Parameter *p = (*fparams)[0 /*fparams->dim - 1*/]; #if DMDV1 // for (size_t i = 0; i < p.length; i++) @@ -298,9 +294,12 @@ ArrayOp *buildArrayOp(Identifier *ident, BinExp *exp, Scope *sc, Loc loc) //printf("s2: %s\n", s2->toChars()); Statement *fbody = new CompoundStatement(Loc(), s1, s2); + // Built-in array ops should be @trusted, pure and nothrow + StorageClass stc = STCtrusted | STCpure | STCnothrow; + /* Construct the function */ - TypeFunction *ftype = new TypeFunction(fparams, exp->type, 0, LINKc); + TypeFunction *ftype = new TypeFunction(fparams, exp->type, 0, LINKc, stc); //printf("ftype: %s\n", ftype->toChars()); FuncDeclaration *fd = new FuncDeclaration(Loc(), Loc(), ident, STCundefined, ftype); fd->fbody = fbody; @@ -336,6 +335,13 @@ bool isArrayOpValid(Expression *e) { if (e->op == TOKslice) return true; + if (e->op == TOKarrayliteral) + { + Type *t = e->type->toBasetype(); + while (t->ty == Tarray || t->ty == Tsarray) + t = t->nextOf()->toBasetype(); + return (t->ty != Tvoid); + } Type *tb = e->type->toBasetype(); if ( (tb->ty == Tarray) || (tb->ty == Tsarray) ) @@ -482,6 +488,12 @@ void CastExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) Expression::buildArrayIdent(buf, arguments); } +void ArrayLiteralExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) +{ + buf->writestring("Slice"); + arguments->shift(this); +} + void SliceExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) { buf->writestring("Slice"); @@ -497,30 +509,30 @@ void AssignExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) buf->writestring("Assign"); } -#define X(Str) \ -void Str##AssignExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) \ -{ \ - /* Evaluate assign expressions right to left \ - */ \ - e2->buildArrayIdent(buf, arguments); \ - e1->buildArrayIdent(buf, arguments); \ - buf->writestring(#Str); \ - buf->writestring("ass"); \ -} - -X(Add) -X(Min) -X(Mul) -X(Div) -X(Mod) -X(Xor) -X(And) -X(Or) +void BinAssignExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) +{ + /* Evaluate assign expressions right to left + */ + e2->buildArrayIdent(buf, arguments); + e1->buildArrayIdent(buf, arguments); + const char *s; + switch(op) + { + case TOKaddass: s = "Addass"; break; + case TOKminass: s = "Subass"; break; + case TOKmulass: s = "Mulass"; break; + case TOKdivass: s = "Divass"; break; + case TOKmodass: s = "Modass"; break; + case TOKxorass: s = "Xorass"; break; + case TOKandass: s = "Andass"; break; + case TOKorass: s = "Orass"; break; #if DMDV2 -X(Pow) + case TOKpowass: s = "Powass"; break; #endif - -#undef X + default: assert(0); + } + buf->writestring(s); +} void NegExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) { @@ -534,29 +546,35 @@ void ComExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) buf->writestring("Com"); } -#define X(Str) \ -void Str##Exp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) \ -{ \ - /* Evaluate assign expressions left to right \ - */ \ - e1->buildArrayIdent(buf, arguments); \ - e2->buildArrayIdent(buf, arguments); \ - buf->writestring(#Str); \ -} - -X(Add) -X(Min) -X(Mul) -X(Div) -X(Mod) -X(Xor) -X(And) -X(Or) +void BinExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) +{ + /* Evaluate assign expressions left to right + */ + const char *s = NULL; + switch(op) + { + case TOKadd: s = "Add"; break; + case TOKmin: s = "Sub"; break; + case TOKmul: s = "Mul"; break; + case TOKdiv: s = "Div"; break; + case TOKmod: s = "Mod"; break; + case TOKxor: s = "Xor"; break; + case TOKand: s = "And"; break; + case TOKor: s = "Or"; break; #if DMDV2 -X(Pow) + case TOKpow: s = "Pow"; break; #endif - -#undef X + default: break; + } + if (s) + { + e1->buildArrayIdent(buf, arguments); + e2->buildArrayIdent(buf, arguments); + buf->writestring(s); + } + else + Expression::buildArrayIdent(buf, arguments); +} /****************************************** * Construct the inner loop for the array operation function, @@ -583,6 +601,19 @@ Expression *CastExp::buildArrayLoop(Parameters *fparams) return Expression::buildArrayLoop(fparams); } +Expression *ArrayLiteralExp::buildArrayLoop(Parameters *fparams) +{ + Identifier *id = Identifier::generateId("p", fparams->dim); + Parameter *param = new Parameter(STCconst, type, id, NULL); + fparams->shift(param); + Expression *e = new IdentifierExp(Loc(), id); + Expressions *arguments = new Expressions(); + Expression *index = new IdentifierExp(Loc(), Id::p); + arguments->push(index); + e = new ArrayExp(Loc(), e, arguments); + return e; +} + Expression *SliceExp::buildArrayLoop(Parameters *fparams) { Identifier *id = Identifier::generateId("p", fparams->dim); @@ -616,32 +647,33 @@ Expression *AssignExp::buildArrayLoop(Parameters *fparams) return e; } -#define X(Str) \ -Expression *Str##AssignExp::buildArrayLoop(Parameters *fparams) \ -{ \ - /* Evaluate assign expressions right to left \ - */ \ - Expression *ex2 = e2->buildArrayLoop(fparams); \ - Expression *ex1 = e1->buildArrayLoop(fparams); \ - Parameter *param = (*fparams)[0]; \ - param->storageClass = 0; \ - Expression *e = new Str##AssignExp(loc, ex1, ex2); \ - return e; \ -} - -X(Add) -X(Min) -X(Mul) -X(Div) -X(Mod) -X(Xor) -X(And) -X(Or) +Expression *BinAssignExp::buildArrayLoop(Parameters *fparams) +{ + /* Evaluate assign expressions right to left + */ + Expression *ex2 = e2->buildArrayLoop(fparams); + Expression *ex1 = e1->buildArrayLoop(fparams); + Parameter *param = (*fparams)[0]; + param->storageClass = 0; + Expression *e; + switch(op) + { + case TOKaddass: return new AddAssignExp(loc, ex1, ex2); + case TOKminass: return new MinAssignExp(loc, ex1, ex2); + case TOKmulass: return new MulAssignExp(loc, ex1, ex2); + case TOKdivass: return new DivAssignExp(loc, ex1, ex2); + case TOKmodass: return new ModAssignExp(loc, ex1, ex2); + case TOKxorass: return new XorAssignExp(loc, ex1, ex2); + case TOKandass: return new AndAssignExp(loc, ex1, ex2); + case TOKorass: return new OrAssignExp(loc, ex1, ex2); #if DMDV2 -X(Pow) + case TOKpowass: return new PowAssignExp(loc, ex1, ex2); #endif - -#undef X + default: + assert(0); + return NULL; + } +} Expression *NegExp::buildArrayLoop(Parameters *fparams) { @@ -657,31 +689,34 @@ Expression *ComExp::buildArrayLoop(Parameters *fparams) return e; } -#define X(Str) \ -Expression *Str##Exp::buildArrayLoop(Parameters *fparams) \ -{ \ - /* Evaluate assign expressions left to right \ - */ \ - Expression *ex1 = e1->buildArrayLoop(fparams); \ - Expression *ex2 = e2->buildArrayLoop(fparams); \ - Expression *e = new Str##Exp(Loc(), ex1, ex2); \ - return e; \ -} - -X(Add) -X(Min) -X(Mul) -X(Div) -X(Mod) -X(Xor) -X(And) -X(Or) +Expression *BinExp::buildArrayLoop(Parameters *fparams) +{ + switch(op) + { + case TOKadd: + case TOKmin: + case TOKmul: + case TOKdiv: + case TOKmod: + case TOKxor: + case TOKand: + case TOKor: #if DMDV2 -X(Pow) + case TOKpow: #endif - -#undef X - + { + /* Evaluate assign expressions left to right + */ + BinExp *e = (BinExp *)copy(); + e->e1 = e->e1->buildArrayLoop(fparams); + e->e2 = e->e2->buildArrayLoop(fparams); + e->type = NULL; + return e; + } + default: + return Expression::buildArrayLoop(fparams); + } +} /*********************************************** * Test if operand is a valid array op operand. @@ -692,6 +727,13 @@ int Expression::isArrayOperand() //printf("Expression::isArrayOperand() %s\n", toChars()); if (op == TOKslice) return 1; + if (op == TOKarrayliteral) + { + Type *t = type->toBasetype(); + while (t->ty == Tarray || t->ty == Tsarray) + t = t->nextOf()->toBasetype(); + return (t->ty != Tvoid); + } if (type->toBasetype()->ty == Tarray) { switch (op) diff --git a/dmd2/arraytypes.h b/dmd2/arraytypes.h index 9e54239a..48efab11 100644 --- a/dmd2/arraytypes.h +++ b/dmd2/arraytypes.h @@ -18,63 +18,63 @@ #include "root.h" -typedef ArrayBase TemplateParameters; +typedef Array TemplateParameters; -typedef ArrayBase Expressions; +typedef Array Expressions; -typedef ArrayBase Statements; +typedef Array Statements; -typedef ArrayBase BaseClasses; +typedef Array BaseClasses; -typedef ArrayBase ClassDeclarations; +typedef Array ClassDeclarations; -typedef ArrayBase Dsymbols; +typedef Array Dsymbols; -typedef ArrayBase Objects; +typedef Array Objects; -typedef ArrayBase FuncDeclarations; +typedef Array FuncDeclarations; -typedef ArrayBase Parameters; +typedef Array Parameters; -typedef ArrayBase Identifiers; +typedef Array Identifiers; -typedef ArrayBase Initializers; +typedef Array Initializers; -typedef ArrayBase VarDeclarations; +typedef Array VarDeclarations; -typedef ArrayBase Types; +typedef Array Types; -typedef ArrayBase ScopeDsymbols; +typedef Array ScopeDsymbols; -typedef ArrayBase Catches; +typedef Array Catches; -typedef ArrayBase StaticDtorDeclarations; +typedef Array StaticDtorDeclarations; -typedef ArrayBase SharedStaticDtorDeclarations; +typedef Array SharedStaticDtorDeclarations; -typedef ArrayBase AliasDeclarations; +typedef Array AliasDeclarations; -typedef ArrayBase Modules; +typedef Array Modules; -typedef ArrayBase Files; +typedef Array Files; -typedef ArrayBase CaseStatements; +typedef Array CaseStatements; -typedef ArrayBase CompoundStatements; +typedef Array CompoundStatements; -typedef ArrayBase GotoCaseStatements; +typedef Array GotoCaseStatements; -typedef ArrayBase ReturnStatements; +typedef Array ReturnStatements; -typedef ArrayBase TemplateInstances; +typedef Array TemplateInstances; -//typedef ArrayBase Strings; +//typedef Array Strings; -typedef ArrayBase Voids; +typedef Array Voids; -typedef ArrayBase Blocks; +typedef Array Blocks; -typedef ArrayBase Symbols; +typedef Array Symbols; -typedef ArrayBase Dts; +typedef Array Dts; #endif diff --git a/dmd2/attrib.c b/dmd2/attrib.c index 3b1135f1..8c5409f8 100644 --- a/dmd2/attrib.c +++ b/dmd2/attrib.c @@ -28,6 +28,7 @@ #include "parse.h" #include "template.h" #include "hdrgen.h" +#include "utf.h" #if IN_LLVM #include "../gen/pragma.h" #endif @@ -81,7 +82,7 @@ int AttribDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) } void AttribDeclaration::setScopeNewSc(Scope *sc, - StorageClass stc, enum LINK linkage, enum PROT protection, int explicitProtection, + StorageClass stc, LINK linkage, PROT protection, int explicitProtection, structalign_t structalign) { if (decl) @@ -116,7 +117,7 @@ void AttribDeclaration::setScopeNewSc(Scope *sc, } void AttribDeclaration::semanticNewSc(Scope *sc, - StorageClass stc, enum LINK linkage, enum PROT protection, int explicitProtection, + StorageClass stc, LINK linkage, PROT protection, int explicitProtection, structalign_t structalign) { if (decl) @@ -206,7 +207,7 @@ void AttribDeclaration::inlineScan() } } -void AttribDeclaration::addComment(unsigned char *comment) +void AttribDeclaration::addComment(utf8_t *comment) { //printf("AttribDeclaration::addComment %s\n", comment); if (comment) @@ -261,7 +262,7 @@ void AttribDeclaration::setFieldOffset(AggregateDeclaration *ad, unsigned *poffs } } -int AttribDeclaration::hasPointers() +bool AttribDeclaration::hasPointers() { Dsymbols *d = include(NULL, NULL); @@ -271,10 +272,10 @@ int AttribDeclaration::hasPointers() { Dsymbol *s = (*d)[i]; if (s->hasPointers()) - return 1; + return true; } } - return 0; + return false; } bool AttribDeclaration::hasStaticCtorOrDtor() @@ -298,7 +299,7 @@ const char *AttribDeclaration::kind() return "attribute"; } -int AttribDeclaration::oneMember(Dsymbol **ps, Identifier *ident) +bool AttribDeclaration::oneMember(Dsymbol **ps, Identifier *ident) { Dsymbols *d = include(NULL, NULL); @@ -384,10 +385,10 @@ Dsymbol *StorageClassDeclaration::syntaxCopy(Dsymbol *s) return scd; } -int StorageClassDeclaration::oneMember(Dsymbol **ps, Identifier *ident) +bool StorageClassDeclaration::oneMember(Dsymbol **ps, Identifier *ident) { - int t = Dsymbol::oneMembers(decl, ps, ident); + bool t = Dsymbol::oneMembers(decl, ps, ident); if (t && *ps) { /* This is to deal with the following case: @@ -476,8 +477,8 @@ const char *StorageClassDeclaration::stcToChars(char tmp[], StorageClass& stc) struct SCstring { StorageClass stc; - enum TOK tok; - Identifier *id; + TOK tok; + const char *id; }; static SCstring table[] = @@ -505,11 +506,11 @@ const char *StorageClassDeclaration::stcToChars(char tmp[], StorageClass& stc) { STCref, TOKref }, { STCtls }, { STCgshared, TOKgshared }, - { STCproperty, TOKat, Id::property }, - { STCsafe, TOKat, Id::safe }, - { STCtrusted, TOKat, Id::trusted }, - { STCsystem, TOKat, Id::system }, - { STCdisable, TOKat, Id::disable }, + { STCproperty, TOKat, "property" }, + { STCsafe, TOKat, "safe" }, + { STCtrusted, TOKat, "trusted" }, + { STCsystem, TOKat, "system" }, + { STCdisable, TOKat, "disable" }, #endif }; @@ -523,12 +524,12 @@ const char *StorageClassDeclaration::stcToChars(char tmp[], StorageClass& stc) if (tbl == STCtls) // TOKtls was removed return "__thread"; - enum TOK tok = table[i].tok; + TOK tok = table[i].tok; #if DMDV2 if (tok == TOKat) { tmp[0] = '@'; - strcpy(tmp + 1, table[i].id->toChars()); + strcpy(tmp + 1, table[i].id); return tmp; } else @@ -599,7 +600,7 @@ void DeprecatedDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) /********************************* LinkDeclaration ****************************/ -LinkDeclaration::LinkDeclaration(enum LINK p, Dsymbols *decl) +LinkDeclaration::LinkDeclaration(LINK p, Dsymbols *decl) : AttribDeclaration(decl) { //printf("LinkDeclaration(linkage = %d, decl = %p)\n", p, decl); @@ -637,7 +638,7 @@ void LinkDeclaration::semantic3(Scope *sc) { //printf("LinkDeclaration::semantic3(linkage = %d, decl = %p)\n", linkage, decl); if (decl) - { enum LINK linkage_save = sc->linkage; + { LINK linkage_save = sc->linkage; sc->linkage = linkage; for (size_t i = 0; i < decl->dim; i++) @@ -685,7 +686,7 @@ char *LinkDeclaration::toChars() /********************************* ProtDeclaration ****************************/ -ProtDeclaration::ProtDeclaration(enum PROT p, Dsymbols *decl) +ProtDeclaration::ProtDeclaration(PROT p, Dsymbols *decl) : AttribDeclaration(decl) { protection = p; @@ -740,7 +741,7 @@ void ProtDeclaration::semantic(Scope *sc) } } -void ProtDeclaration::protectionToCBuffer(OutBuffer *buf, enum PROT protection) +void ProtDeclaration::protectionToCBuffer(OutBuffer *buf, PROT protection) { const char *p; @@ -805,7 +806,7 @@ void AlignDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) /********************************* AnonDeclaration ****************************/ -AnonDeclaration::AnonDeclaration(Loc loc, int isunion, Dsymbols *decl) +AnonDeclaration::AnonDeclaration(Loc loc, bool isunion, Dsymbols *decl) : AttribDeclaration(decl) { this->loc = loc; @@ -1012,10 +1013,13 @@ void PragmaDeclaration::semantic(Scope *sc) { Expression *e = (*args)[i]; - e = e->ctfeSemantic(sc); + sc = sc->startCTFE(); + e = e->semantic(sc); e = resolveProperties(sc, e); - if (e->op != TOKerror && e->op != TOKtype) - e = e->ctfeInterpret(); + sc = sc->endCTFE(); + + // pragma(msg) is allowed to contain types as well as expressions + e = ctfeInterpretForPragmaMsg(e); if (e->op == TOKerror) { errorSupplemental(loc, "while evaluating pragma(msg, %s)", (*args)[i]->toChars()); return; @@ -1040,8 +1044,11 @@ void PragmaDeclaration::semantic(Scope *sc) { Expression *e = (*args)[0]; - e = e->ctfeSemantic(sc); + sc = sc->startCTFE(); + e = e->semantic(sc); e = resolveProperties(sc, e); + sc = sc->endCTFE(); + e = e->ctfeInterpret(); (*args)[0] = e; if (e->op == TOKerror) @@ -1049,12 +1056,25 @@ void PragmaDeclaration::semantic(Scope *sc) StringExp *se = e->toString(); if (!se) error("string expected for library name, not '%s'", e->toChars()); - else if (global.params.verbose) + else { char *name = (char *)mem.malloc(se->len + 1); memcpy(name, se->string, se->len); name[se->len] = 0; - printf("library %s\n", name); + if (global.params.verbose) + fprintf(global.stdmsg, "library %s\n", name); + if (global.params.moduleDeps && !global.params.moduleDepsFile) + { + OutBuffer *ob = global.params.moduleDeps; + Module* imod = sc->instantiatingModule ? sc->instantiatingModule : sc->module; + ob->writestring("depsLib "); + ob->writestring(imod->toPrettyChars()); + ob->writestring(" ("); + escapePath(ob, imod->srcfile->toChars()); + ob->writestring(") : "); + ob->writestring((char *) name); + ob->writenl(); + } mem.free(name); } } @@ -1068,8 +1088,12 @@ void PragmaDeclaration::semantic(Scope *sc) else { Expression *e = (*args)[0]; - e = e->ctfeSemantic(sc); + + sc = sc->startCTFE(); + e = e->semantic(sc); e = resolveProperties(sc, e); + sc = sc->endCTFE(); + e = e->ctfeInterpret(); (*args)[0] = e; Dsymbol *sa = getDsymbol(e); @@ -1107,6 +1131,47 @@ void PragmaDeclaration::semantic(Scope *sc) if (se->sz != 1) error("mangled name characters can only be of type char"); + +#if 1 + /* Note: D language specification should not have any assumption about backend + * implementation. Ideally pragma(mangle) can accept a string of any content. + * + * Therefore, this validation is compiler implementation specific. + */ + for (size_t i = 0; i < se->len; ) + { + utf8_t *p = (utf8_t *)se->string; + dchar_t c = p[i]; + if (c < 0x80) + { + if (c >= 'A' && c <= 'Z' || + c >= 'a' && c <= 'z' || + c >= '0' && c <= '9' || + c != 0 && strchr("$%().:?@[]_", c)) + { + ++i; + continue; + } + else + { + error("char 0x%02x not allowed in mangled name", c); + break; + } + } + + if (const char* msg = utf_decodeChar((utf8_t *)se->string, se->len, &i, &c)) + { + error("%s", msg); + break; + } + + if (!isUniAlpha(c)) + { + error("char 0x%04x not allowed in mangled name", c); + break; + } + } +#endif } } #if IN_LLVM @@ -1121,27 +1186,28 @@ void PragmaDeclaration::semantic(Scope *sc) { /* Print unrecognized pragmas */ - printf("pragma %s", ident->toChars()); + fprintf(global.stdmsg, "pragma %s", ident->toChars()); if (args) { for (size_t i = 0; i < args->dim; i++) { Expression *e = (*args)[i]; - #if IN_LLVM // ignore errors in ignored pragmas. global.gag++; unsigned errors_save = global.errors; #endif - e = e->ctfeSemantic(sc); + sc = sc->startCTFE(); + e = e->semantic(sc); e = resolveProperties(sc, e); + sc = sc->endCTFE(); + e = e->ctfeInterpret(); if (i == 0) - printf(" ("); + fprintf(global.stdmsg, " ("); else - printf(","); - printf("%s", e->toChars()); - + fprintf(global.stdmsg, ","); + fprintf(global.stdmsg, "%s", e->toChars()); #if IN_LLVM // restore error state. global.gag--; @@ -1149,9 +1215,9 @@ void PragmaDeclaration::semantic(Scope *sc) #endif } if (args->dim) - printf(")"); + fprintf(global.stdmsg, ")"); } - printf("\n"); + fprintf(global.stdmsg, "\n"); } } else @@ -1198,10 +1264,10 @@ Lnodecl: } } -int PragmaDeclaration::oneMember(Dsymbol **ps, Identifier *ident) +bool PragmaDeclaration::oneMember(Dsymbol **ps, Identifier *ident) { *ps = NULL; - return TRUE; + return true; } const char *PragmaDeclaration::kind() @@ -1244,7 +1310,7 @@ Dsymbol *ConditionalDeclaration::syntaxCopy(Dsymbol *s) } -int ConditionalDeclaration::oneMember(Dsymbol **ps, Identifier *ident) +bool ConditionalDeclaration::oneMember(Dsymbol **ps, Identifier *ident) { //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition->inc); if (condition->inc) @@ -1252,8 +1318,13 @@ int ConditionalDeclaration::oneMember(Dsymbol **ps, Identifier *ident) Dsymbols *d = condition->include(NULL, NULL) ? decl : elsedecl; return Dsymbol::oneMembers(d, ps, ident); } - *ps = NULL; - return TRUE; + else + { + bool res = (Dsymbol::oneMembers( decl, ps, ident) && *ps == NULL && + Dsymbol::oneMembers(elsedecl, ps, ident) && *ps == NULL); + *ps = NULL; + return res; + } } void ConditionalDeclaration::emitComment(Scope *sc) @@ -1317,7 +1388,7 @@ void ConditionalDeclaration::importAll(Scope *sc) } } -void ConditionalDeclaration::addComment(unsigned char *comment) +void ConditionalDeclaration::addComment(utf8_t *comment) { /* Because addComment is called by the parser, if we called * include() it would define a version before it was used. @@ -1529,6 +1600,9 @@ Dsymbol *CompileDeclaration::syntaxCopy(Dsymbol *s) int CompileDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) { //printf("CompileDeclaration::addMember(sc = %p, sd = %p, memnum = %d)\n", sc, sd, memnum); + if (compiled) + return 1; + this->sd = sd; if (memnum == 0) { /* No members yet, so parse the mixin now @@ -1543,8 +1617,10 @@ int CompileDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) void CompileDeclaration::compileIt(Scope *sc) { //printf("CompileDeclaration::compileIt(loc = %d) %s\n", loc.linnum, exp->toChars()); - exp = exp->ctfeSemantic(sc); + sc = sc->startCTFE(); + exp = exp->semantic(sc); exp = resolveProperties(sc, exp); + sc = sc->endCTFE(); exp = exp->ctfeInterpret(); StringExp *se = exp->toString(); if (!se) @@ -1553,12 +1629,15 @@ void CompileDeclaration::compileIt(Scope *sc) else { se = se->toUTF8(sc); - Parser p(sc->module, (unsigned char *)se->string, se->len, 0); - p.loc = loc; + Parser p(sc->module, (utf8_t *)se->string, se->len, 0); + p.scanloc = loc; p.nextToken(); + unsigned errors = global.errors; decl = p.parseDeclDefs(0); if (p.token.value != TOKeof) exp->error("incomplete mixin declaration (%s)", se->toChars()); + if (global.errors != errors) + decl = NULL; } } diff --git a/dmd2/attrib.h b/dmd2/attrib.h index 760d3ed0..d4d64700 100644 --- a/dmd2/attrib.h +++ b/dmd2/attrib.h @@ -17,18 +17,19 @@ #include "dsymbol.h" -struct Expression; -struct Statement; -struct LabelDsymbol; -struct Initializer; -struct Module; -struct Condition; +class Expression; +class Statement; +class LabelDsymbol; +class Initializer; +class Module; +class Condition; struct HdrGenState; /**************************************************************/ -struct AttribDeclaration : Dsymbol +class AttribDeclaration : public Dsymbol { +public: Dsymbols *decl; // array of Dsymbol's AttribDeclaration(Dsymbols *decl); @@ -36,21 +37,21 @@ struct AttribDeclaration : Dsymbol int apply(Dsymbol_apply_ft_t fp, void *param); int addMember(Scope *sc, ScopeDsymbol *s, int memnum); void setScopeNewSc(Scope *sc, - StorageClass newstc, enum LINK linkage, enum PROT protection, int explictProtection, + StorageClass newstc, LINK linkage, PROT protection, int explictProtection, structalign_t structalign); void semanticNewSc(Scope *sc, - StorageClass newstc, enum LINK linkage, enum PROT protection, int explictProtection, + StorageClass newstc, LINK linkage, PROT protection, int explictProtection, structalign_t structalign); void semantic(Scope *sc); void semantic2(Scope *sc); void semantic3(Scope *sc); void inlineScan(); - void addComment(unsigned char *comment); + void addComment(utf8_t *comment); void emitComment(Scope *sc); const char *kind(); - int oneMember(Dsymbol **ps, Identifier *ident); + bool oneMember(Dsymbol **ps, Identifier *ident); void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); - int hasPointers(); + bool hasPointers(); bool hasStaticCtorOrDtor(); void checkCtorConstInit(); void addLocalClass(ClassDeclarations *); @@ -67,23 +68,25 @@ struct AttribDeclaration : Dsymbol #endif }; -struct StorageClassDeclaration : AttribDeclaration +class StorageClassDeclaration : public AttribDeclaration { +public: StorageClass stc; StorageClassDeclaration(StorageClass stc, Dsymbols *decl); Dsymbol *syntaxCopy(Dsymbol *s); void setScope(Scope *sc); void semantic(Scope *sc); - int oneMember(Dsymbol **ps, Identifier *ident); + bool oneMember(Dsymbol **ps, Identifier *ident); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); static const char *stcToChars(char tmp[], StorageClass& stc); static void stcToCBuffer(OutBuffer *buf, StorageClass stc); }; -struct DeprecatedDeclaration : StorageClassDeclaration +class DeprecatedDeclaration : public StorageClassDeclaration { +public: Expression *msg; DeprecatedDeclaration(Expression *msg, Dsymbols *decl); @@ -92,11 +95,12 @@ struct DeprecatedDeclaration : StorageClassDeclaration void toCBuffer(OutBuffer *buf, HdrGenState *hgs); }; -struct LinkDeclaration : AttribDeclaration +class LinkDeclaration : public AttribDeclaration { - enum LINK linkage; +public: + LINK linkage; - LinkDeclaration(enum LINK p, Dsymbols *decl); + LinkDeclaration(LINK p, Dsymbols *decl); Dsymbol *syntaxCopy(Dsymbol *s); void setScope(Scope *sc); void semantic(Scope *sc); @@ -105,22 +109,24 @@ struct LinkDeclaration : AttribDeclaration char *toChars(); }; -struct ProtDeclaration : AttribDeclaration +class ProtDeclaration : public AttribDeclaration { - enum PROT protection; +public: + PROT protection; - ProtDeclaration(enum PROT p, Dsymbols *decl); + ProtDeclaration(PROT p, Dsymbols *decl); Dsymbol *syntaxCopy(Dsymbol *s); void importAll(Scope *sc); void setScope(Scope *sc); void semantic(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - static void protectionToCBuffer(OutBuffer *buf, enum PROT protection); + static void protectionToCBuffer(OutBuffer *buf, PROT protection); }; -struct AlignDeclaration : AttribDeclaration +class AlignDeclaration : public AttribDeclaration { +public: unsigned salign; AlignDeclaration(unsigned sa, Dsymbols *decl); @@ -130,13 +136,14 @@ struct AlignDeclaration : AttribDeclaration void toCBuffer(OutBuffer *buf, HdrGenState *hgs); }; -struct AnonDeclaration : AttribDeclaration +class AnonDeclaration : public AttribDeclaration { +public: bool isunion; structalign_t alignment; int sem; // 1 if successful semantic() - AnonDeclaration(Loc loc, int isunion, Dsymbols *decl); + AnonDeclaration(Loc loc, bool isunion, Dsymbols *decl); Dsymbol *syntaxCopy(Dsymbol *s); void semantic(Scope *sc); void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); @@ -144,15 +151,16 @@ struct AnonDeclaration : AttribDeclaration const char *kind(); }; -struct PragmaDeclaration : AttribDeclaration +class PragmaDeclaration : public AttribDeclaration { +public: Expressions *args; // array of Expression's PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Dsymbols *decl); Dsymbol *syntaxCopy(Dsymbol *s); void semantic(Scope *sc); void setScope(Scope *sc); - int oneMember(Dsymbol **ps, Identifier *ident); + bool oneMember(Dsymbol **ps, Identifier *ident); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); const char *kind(); @@ -165,25 +173,27 @@ struct PragmaDeclaration : AttribDeclaration #endif }; -struct ConditionalDeclaration : AttribDeclaration +class ConditionalDeclaration : public AttribDeclaration { +public: Condition *condition; Dsymbols *elsedecl; // array of Dsymbol's for else block ConditionalDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl); Dsymbol *syntaxCopy(Dsymbol *s); - int oneMember(Dsymbol **ps, Identifier *ident); + bool oneMember(Dsymbol **ps, Identifier *ident); void emitComment(Scope *sc); Dsymbols *include(Scope *sc, ScopeDsymbol *s); - void addComment(unsigned char *comment); + void addComment(utf8_t *comment); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void toJson(JsonOut *json); void importAll(Scope *sc); void setScope(Scope *sc); }; -struct StaticIfDeclaration : ConditionalDeclaration +class StaticIfDeclaration : public ConditionalDeclaration { +public: ScopeDsymbol *sd; int addisdone; @@ -199,8 +209,9 @@ struct StaticIfDeclaration : ConditionalDeclaration // Mixin declarations -struct CompileDeclaration : AttribDeclaration +class CompileDeclaration : public AttribDeclaration { +public: Expression *exp; ScopeDsymbol *sd; @@ -219,8 +230,9 @@ struct CompileDeclaration : AttribDeclaration * User defined attributes look like: * [ args, ... ] */ -struct UserAttributeDeclaration : AttribDeclaration +class UserAttributeDeclaration : public AttribDeclaration { +public: Expressions *atts; UserAttributeDeclaration(Expressions *atts, Dsymbols *decl); diff --git a/dmd2/builtin.c b/dmd2/builtin.c index ae3542c3..7783d875 100644 --- a/dmd2/builtin.c +++ b/dmd2/builtin.c @@ -30,7 +30,7 @@ * Determine if function is a builtin one that we can * evaluate at compile time. */ -enum BUILTIN FuncDeclaration::isBuiltin() +BUILTIN FuncDeclaration::isBuiltin() { static const char FeZe [] = "FNaNbNfeZe"; // @safe pure nothrow real function(real) static const char FeZe2[] = "FNaNbNeeZe"; // @trusted pure nothrow real function(real) @@ -154,7 +154,7 @@ uinteger_t eval_bswap(Expression *arg0) * Return result; NULL if cannot evaluate it. */ -Expression *eval_builtin(Loc loc, enum BUILTIN builtin, Expressions *arguments) +Expression *eval_builtin(Loc loc, BUILTIN builtin, Expressions *arguments) { assert(arguments && arguments->dim); Expression *arg0 = (*arguments)[0]; diff --git a/dmd2/canthrow.c b/dmd2/canthrow.c index 27992b08..8381716b 100644 --- a/dmd2/canthrow.c +++ b/dmd2/canthrow.c @@ -56,14 +56,15 @@ int lambdaCanThrow(Expression *e, void *param) switch (e->op) { case TOKdeclaration: - { DeclarationExp *de = (DeclarationExp *)e; + { + DeclarationExp *de = (DeclarationExp *)e; pct->can = Dsymbol_canThrow(de->declaration, pct->mustnot); break; } case TOKcall: - { CallExp *ce = (CallExp *)e; - + { + CallExp *ce = (CallExp *)e; if (global.errors && !ce->e1->type) break; // error recovery @@ -79,14 +80,15 @@ int lambdaCanThrow(Expression *e, void *param) else { if (pct->mustnot) - e->error("%s is not nothrow", ce->e1->toChars()); + e->error("'%s' is not nothrow", ce->f ? ce->f->toPrettyChars() : ce->e1->toChars()); pct->can = TRUE; } break; } case TOKnew: - { NewExp *ne = (NewExp *)e; + { + NewExp *ne = (NewExp *)e; if (ne->member) { // See if constructor call can throw @@ -102,6 +104,33 @@ int lambdaCanThrow(Expression *e, void *param) break; } + case TOKassign: + case TOKconstruct: + { + /* Element-wise assignment could invoke postblits. + */ + AssignExp *ae = (AssignExp *)e; + if (ae->e1->op != TOKslice) + break; + + Type *tv = ae->e1->type->toBasetype()->nextOf()->baseElemOf(); + if (tv->ty != Tstruct) + break; + StructDeclaration *sd = ((TypeStruct *)tv)->sym; + if (!sd->postblit || sd->postblit->type->ty != Tfunction) + break; + + if (((TypeFunction *)sd->postblit->type)->isnothrow) + ; + else + { + if (pct->mustnot) + e->error("'%s' is not nothrow", sd->postblit->toPrettyChars()); + pct->can = TRUE; + } + break; + } + case TOKnewanonclass: assert(0); // should have been lowered by semantic() break; @@ -175,7 +204,7 @@ int Dsymbol_canThrow(Dsymbol *s, bool mustNotThrow) else if ((td = s->isTupleDeclaration()) != NULL) { for (size_t i = 0; i < td->objects->dim; i++) - { Object *o = (*td->objects)[i]; + { RootObject *o = (*td->objects)[i]; if (o->dyncast() == DYNCAST_EXPRESSION) { Expression *eo = (Expression *)o; if (eo->op == TOKdsymbol) diff --git a/dmd2/cast.c b/dmd2/cast.c index 30a92648..1747dee9 100644 --- a/dmd2/cast.c +++ b/dmd2/cast.c @@ -163,7 +163,7 @@ MATCH Expression::implicitConvTo(Type *t) type = Type::terror; } Expression *e = optimize(WANTvalue | WANTflags); - if (e->type == t) + if (e->type->equals(t)) return MATCHexact; if (e != this) { //printf("\toptimized to %s of type %s\n", e->toChars(), e->type->toChars()); @@ -351,8 +351,8 @@ MATCH IntegerExp::implicitConvTo(Type *t) } else { - f = (float)(long long)value; - if (f != (long long)value) + f = (float)(sinteger_t)value; + if (f != (sinteger_t)value) goto Lno; } goto Lyes; @@ -369,8 +369,8 @@ MATCH IntegerExp::implicitConvTo(Type *t) } else { - f = (double)(long long)value; - if (f != (long long)value) + f = (double)(sinteger_t)value; + if (f != (sinteger_t)value) goto Lno; } goto Lyes; @@ -387,8 +387,8 @@ MATCH IntegerExp::implicitConvTo(Type *t) } else { - f = ldouble((long long)value); - if (f != (long long)value) + f = ldouble((sinteger_t)value); + if (f != (sinteger_t)value) goto Lno; } goto Lyes; @@ -418,6 +418,11 @@ Lno: return MATCHnomatch; } +MATCH ErrorExp::implicitConvTo(Type *t) +{ + return MATCHnomatch; +} + MATCH NullExp::implicitConvTo(Type *t) { #if 0 @@ -431,7 +436,7 @@ MATCH NullExp::implicitConvTo(Type *t) * and mutable to immutable. It works because, after all, a null * doesn't actually point to anything. */ - if (t->invariantOf()->equals(type->invariantOf())) + if (t->immutableOf()->equals(type->immutableOf())) return MATCHconst; return Expression::implicitConvTo(t); @@ -655,7 +660,7 @@ MATCH CallExp::implicitConvTo(Type *t) * convert to immutable */ if (f && f->isolateReturn()) - return type->invariantOf()->implicitConvTo(t); + return type->immutableOf()->implicitConvTo(t); /* The result of arr.dup and arr.idup can be unique essentially. * So deal with this case specially. @@ -680,7 +685,7 @@ MATCH CallExp::implicitConvTo(Type *t) return MATCHnomatch; } } - m = type->invariantOf()->implicitConvTo(t); + m = type->immutableOf()->implicitConvTo(t); return m; } @@ -1021,8 +1026,7 @@ Type *SliceExp::toStaticArrayType() if (lwr->isConst() && upr->isConst()) { size_t len = upr->toUInteger() - lwr->toUInteger(); - return new TypeSArray(type->toBasetype()->nextOf(), - new IntegerExp(Loc(), len, Type::tindex)); + return TypeSArray::makeType(loc, type->toBasetype()->nextOf(), len); } } return NULL; @@ -1049,6 +1053,7 @@ MATCH SliceExp::implicitConvTo(Type *t) /************************************** * Do an explicit cast. + * Assume that the 'this' expression does not have any indirections. */ Expression *Expression::castTo(Scope *sc, Type *t) @@ -1058,21 +1063,21 @@ Expression *Expression::castTo(Scope *sc, Type *t) printf("Expression::castTo(this=%s, type=%s, t=%s)\n", toChars(), type->toChars(), t->toChars()); #endif - if (type == t) + if (type->equals(t)) return this; if (op == TOKvar) { VarDeclaration *v = ((VarExp *)this)->var->isVarDeclaration(); if (v && v->storage_class & STCmanifest) { - Expression *e = optimize(WANTvalue | WANTinterpret); + Expression *e = ctfeInterpret(); return e->castTo(sc, t); } } Expression *e = this; Type *tb = t->toBasetype(); Type *typeb = type->toBasetype(); - if (tb != typeb) + if (!tb->equals(typeb)) { // Do (type *) cast of (type [dim]) if (tb->ty == Tpointer && @@ -1140,7 +1145,7 @@ Expression *Expression::castTo(Scope *sc, Type *t) e = e->semantic(sc); return e; } - else if (typeb->implicitConvTo(tb) == MATCHconst && t == type->constOf()) + else if (typeb->implicitConvTo(tb) == MATCHconst && t->equals(type->constOf())) { Expression *e = copy(); e->type = t; @@ -1167,8 +1172,9 @@ Expression *ErrorExp::castTo(Scope *sc, Type *t) Expression *RealExp::castTo(Scope *sc, Type *t) -{ Expression *e = this; - if (type != t) +{ + Expression *e = this; + if (!type->equals(t)) { if ((type->isreal() && t->isreal()) || (type->isimaginary() && t->isimaginary()) @@ -1184,8 +1190,9 @@ Expression *RealExp::castTo(Scope *sc, Type *t) Expression *ComplexExp::castTo(Scope *sc, Type *t) -{ Expression *e = this; - if (type != t) +{ + Expression *e = this; + if (!type->equals(t)) { if (type->iscomplex() && t->iscomplex()) { e = copy(); @@ -1200,8 +1207,8 @@ Expression *ComplexExp::castTo(Scope *sc, Type *t) Expression *NullExp::castTo(Scope *sc, Type *t) { - //printf("NullExp::castTo(t = %p)\n", t); - if (type == t) + //printf("NullExp::castTo(t = %s) %s\n", t->toChars(), toChars()); + if (type->equals(t)) { committed = 1; return this; @@ -1212,7 +1219,7 @@ Expression *NullExp::castTo(Scope *sc, Type *t) Type *tb = t->toBasetype(); #if 0 e->type = type->toBasetype(); - if (tb != e->type) + if (!tb->equals(e->type)) { // NULL implicitly converts to any pointer type or dynamic array if (e->type->ty == Tpointer && e->type->nextOf()->ty == Tvoid && @@ -1243,6 +1250,10 @@ Expression *NullExp::castTo(Scope *sc, Type *t) return e->Expression::castTo(sc, t); } #endif + if (tb->ty == Tsarray || tb->ty == Tstruct) + { + error("cannot cast null to %s", t->toChars()); + } e->type = t; return e; } @@ -1278,7 +1289,7 @@ Expression *StringExp::castTo(Scope *sc, Type *t) copied = 1; } - if (type == t) + if (type->equals(t)) { return se; } @@ -1289,7 +1300,7 @@ Expression *StringExp::castTo(Scope *sc, Type *t) return Expression::castTo(sc, t); Type *typeb = type->toBasetype(); - if (typeb == tb) + if (typeb->equals(tb)) { if (!copied) { se = (StringExp *)copy(); @@ -1308,6 +1319,16 @@ Expression *StringExp::castTo(Scope *sc, Type *t) se->len = (len * sz) / se->sz; se->committed = 1; se->type = t; + + /* Assure space for terminating 0 + */ + if ((se->len + 1) * se->sz > (len + 1) * sz) + { + void *s = (void *)mem.malloc((se->len + 1) * se->sz); + memcpy(s, se->string, se->len * se->sz); + memset((char *)s + se->len * se->sz, 0, se->sz); + se->string = s; + } return se; } @@ -1357,7 +1378,7 @@ Expression *StringExp::castTo(Scope *sc, Type *t) case X(Tchar, Twchar): for (size_t u = 0; u < len;) { unsigned c; - const char *p = utf_decodeChar((unsigned char *)se->string, len, &u, &c); + const char *p = utf_decodeChar((utf8_t *)se->string, len, &u, &c); if (p) error("%s", p); else @@ -1370,7 +1391,7 @@ Expression *StringExp::castTo(Scope *sc, Type *t) case X(Tchar, Tdchar): for (size_t u = 0; u < len;) { unsigned c; - const char *p = utf_decodeChar((unsigned char *)se->string, len, &u, &c); + const char *p = utf_decodeChar((utf8_t *)se->string, len, &u, &c); if (p) error("%s", p); buffer.write4(c); @@ -1469,7 +1490,7 @@ L2: // Copy when changing the string literal size_t newsz = se->sz; size_t d = (dim2 < se->len) ? dim2 : se->len; - void *s = (unsigned char *)mem.malloc((dim2 + 1) * newsz); + void *s = (void *)mem.malloc((dim2 + 1) * newsz); memcpy(s, se->string, d * newsz); // Extend with 0, add terminating 0 memset((char *)s + d * newsz, 0, (dim2 + 1 - d) * newsz); @@ -1498,7 +1519,7 @@ Expression *AddrExp::castTo(Scope *sc, Type *t) tb = t->toBasetype(); type = type->toBasetype(); - if (tb != type) + if (!tb->equals(type)) { // Look for pointers to functions where the functions are overloaded. @@ -1559,6 +1580,9 @@ Expression *AddrExp::castTo(Scope *sc, Type *t) Expression *TupleExp::castTo(Scope *sc, Type *t) { + if (type->equals(t)) + return this; + TupleExp *e = (TupleExp *)copy(); e->e0 = e0 ? e0->copy() : NULL; e->exps = (Expressions *)exps->copy(); @@ -1674,12 +1698,12 @@ Expression *SymOffExp::castTo(Scope *sc, Type *t) printf("SymOffExp::castTo(this=%s, type=%s, t=%s)\n", toChars(), type->toChars(), t->toChars()); #endif - if (type == t && hasOverloads == 0) + if (type == t && !hasOverloads) return this; Expression *e; Type *tb = t->toBasetype(); Type *typeb = type->toBasetype(); - if (tb != typeb) + if (!tb->equals(typeb)) { // Look for pointers to functions where the functions are overloaded. FuncDeclaration *f; @@ -1732,7 +1756,7 @@ Expression *SymOffExp::castTo(Scope *sc, Type *t) else { e = copy(); e->type = t; - ((SymOffExp *)e)->hasOverloads = 0; + ((SymOffExp *)e)->hasOverloads = false; } return e; } @@ -1743,12 +1767,12 @@ Expression *DelegateExp::castTo(Scope *sc, Type *t) printf("DelegateExp::castTo(this=%s, type=%s, t=%s)\n", toChars(), type->toChars(), t->toChars()); #endif - static char msg[] = "cannot form delegate due to covariant return type"; + static const char msg[] = "cannot form delegate due to covariant return type"; Expression *e = this; Type *tb = t->toBasetype(); Type *typeb = type->toBasetype(); - if (tb != typeb || hasOverloads) + if (!tb->equals(typeb) || hasOverloads) { // Look for delegates to functions where the functions are overloaded. FuncDeclaration *f; @@ -1810,7 +1834,7 @@ Expression *CondExp::castTo(Scope *sc, Type *t) { Expression *e = this; - if (type != t) + if (!type->equals(t)) { if (1 || e1->op == TOKstring || e2->op == TOKstring) { e = new CondExp(loc, econd, e1->castTo(sc, t), e2->castTo(sc, t)); @@ -1852,6 +1876,14 @@ Expression *SliceExp::castTo(Scope *sc, Type *t) e = copy(); e->type = t; } + else if (typeb->ty == Tarray && tb->ty == Tarray && + typeb->nextOf()->constConv(tb->nextOf()) == MATCHconst) + { + // immutable(T)[] to const(T)[] + // T [] to const(T)[] + e = copy(); + e->type = t; + } else { e = Expression::castTo(sc, t); @@ -2200,13 +2232,13 @@ Lagain: if (t1b->ty == ty1) // if no promotions { - if (t1 == t2) + if (t1->equals(t2)) { t = t1; goto Lret; } - if (t1b == t2b) + if (t1b->equals(t2b)) { t = t1b; goto Lret; @@ -2228,8 +2260,14 @@ Lagain: t1 = t1b; t2 = t2b; - if (t1 == t2) + if (t1->ty == Ttuple || t2->ty == Ttuple) + goto Lincompatible; + + if (t1->equals(t2)) { + // merging can not result in new enum type + if (t->ty == Tenum) + t = t1b; } else if ((t1->ty == Tpointer && t2->ty == Tpointer) || (t1->ty == Tdelegate && t2->ty == Tdelegate)) @@ -2238,12 +2276,8 @@ Lagain: Type *t1n = t1->nextOf(); Type *t2n = t2->nextOf(); - if (t1n == t2n) + if (t1n->equals(t2n)) ; -#if IN_LLVM - else if (t1n->equals(t2n)) - ; -#endif else if (t1n->ty == Tvoid) // pointers to void are always compatible t = t2; else if (t2n->ty == Tvoid) @@ -2800,8 +2834,8 @@ Expression *Expression::integralPromotions(Scope *sc) int arrayTypeCompatible(Loc loc, Type *t1, Type *t2) { - t1 = t1->toBasetype(); - t2 = t2->toBasetype(); + t1 = t1->toBasetype()->merge2(); + t2 = t2->toBasetype()->merge2(); if ((t1->ty == Tarray || t1->ty == Tsarray || t1->ty == Tpointer) && (t2->ty == Tarray || t2->ty == Tsarray || t2->ty == Tpointer)) @@ -2864,7 +2898,7 @@ IntRange Expression::getIntRange() IntRange IntegerExp::getIntRange() { - return IntRange(value).cast(type) DUMP; + return IntRange(SignExtendedNumber(value)).cast(type) DUMP; } IntRange CastExp::getIntRange() diff --git a/dmd2/class.c b/dmd2/class.c index db93aa58..4f8c33b4 100644 --- a/dmd2/class.c +++ b/dmd2/class.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars +// Copyright (c) 1999-2013 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -32,16 +32,15 @@ /********************************* ClassDeclaration ****************************/ -ClassDeclaration *ClassDeclaration::classinfo; ClassDeclaration *ClassDeclaration::object; ClassDeclaration *ClassDeclaration::throwable; ClassDeclaration *ClassDeclaration::exception; ClassDeclaration *ClassDeclaration::errorException; -ClassDeclaration::ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses) +ClassDeclaration::ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses, bool inObject) : AggregateDeclaration(loc, id) { - static char msg[] = "only object.d can define this reserved class name"; + static const char msg[] = "only object.d can define this reserved class name"; if (baseclasses) // Actually, this is a transfer @@ -79,147 +78,140 @@ ClassDeclaration::ClassDeclaration(Loc loc, Identifier *id, BaseClasses *basecla if (id->toChars()[0] == 'T') { if (id == Id::TypeInfo) - { if (Type::typeinfo) - Type::typeinfo->error("%s", msg); - Type::typeinfo = this; + { if (!inObject) + error("%s", msg); + Type::dtypeinfo = this; } if (id == Id::TypeInfo_Class) - { if (Type::typeinfoclass) - Type::typeinfoclass->error("%s", msg); + { if (!inObject) + error("%s", msg); Type::typeinfoclass = this; } if (id == Id::TypeInfo_Interface) - { if (Type::typeinfointerface) - Type::typeinfointerface->error("%s", msg); + { if (!inObject) + error("%s", msg); Type::typeinfointerface = this; } if (id == Id::TypeInfo_Struct) - { if (Type::typeinfostruct) - Type::typeinfostruct->error("%s", msg); + { if (!inObject) + error("%s", msg); Type::typeinfostruct = this; } if (id == Id::TypeInfo_Typedef) - { if (Type::typeinfotypedef) - Type::typeinfotypedef->error("%s", msg); + { if (!inObject) + error("%s", msg); Type::typeinfotypedef = this; } if (id == Id::TypeInfo_Pointer) - { if (Type::typeinfopointer) - Type::typeinfopointer->error("%s", msg); + { if (!inObject) + error("%s", msg); Type::typeinfopointer = this; } if (id == Id::TypeInfo_Array) - { if (Type::typeinfoarray) - Type::typeinfoarray->error("%s", msg); + { if (!inObject) + error("%s", msg); Type::typeinfoarray = this; } if (id == Id::TypeInfo_StaticArray) - { //if (Type::typeinfostaticarray) + { //if (!inObject) //Type::typeinfostaticarray->error("%s", msg); Type::typeinfostaticarray = this; } if (id == Id::TypeInfo_AssociativeArray) - { if (Type::typeinfoassociativearray) - Type::typeinfoassociativearray->error("%s", msg); + { if (!inObject) + error("%s", msg); Type::typeinfoassociativearray = this; } if (id == Id::TypeInfo_Enum) - { if (Type::typeinfoenum) - Type::typeinfoenum->error("%s", msg); + { if (!inObject) + error("%s", msg); Type::typeinfoenum = this; } if (id == Id::TypeInfo_Function) - { if (Type::typeinfofunction) - Type::typeinfofunction->error("%s", msg); + { if (!inObject) + error("%s", msg); Type::typeinfofunction = this; } if (id == Id::TypeInfo_Delegate) - { if (Type::typeinfodelegate) - Type::typeinfodelegate->error("%s", msg); + { if (!inObject) + error("%s", msg); Type::typeinfodelegate = this; } if (id == Id::TypeInfo_Tuple) - { if (Type::typeinfotypelist) - Type::typeinfotypelist->error("%s", msg); + { if (!inObject) + error("%s", msg); Type::typeinfotypelist = this; } #if DMDV2 if (id == Id::TypeInfo_Const) - { if (Type::typeinfoconst) - Type::typeinfoconst->error("%s", msg); + { if (!inObject) + error("%s", msg); Type::typeinfoconst = this; } if (id == Id::TypeInfo_Invariant) - { if (Type::typeinfoinvariant) - Type::typeinfoinvariant->error("%s", msg); + { if (!inObject) + error("%s", msg); Type::typeinfoinvariant = this; } if (id == Id::TypeInfo_Shared) - { if (Type::typeinfoshared) - Type::typeinfoshared->error("%s", msg); + { if (!inObject) + error("%s", msg); Type::typeinfoshared = this; } if (id == Id::TypeInfo_Wild) - { if (Type::typeinfowild) - Type::typeinfowild->error("%s", msg); + { if (!inObject) + error("%s", msg); Type::typeinfowild = this; } if (id == Id::TypeInfo_Vector) - { if (Type::typeinfovector) - Type::typeinfovector->error("%s", msg); + { if (!inObject) + error("%s", msg); Type::typeinfovector = this; } #endif } if (id == Id::Object) - { if (object) - object->error("%s", msg); + { if (!inObject) + error("%s", msg); object = this; } if (id == Id::Throwable) - { if (throwable) - throwable->error("%s", msg); + { if (!inObject) + error("%s", msg); throwable = this; } if (id == Id::Exception) - { if (exception) - exception->error("%s", msg); + { if (!inObject) + error("%s", msg); exception = this; } if (id == Id::Error) - { if (errorException) - errorException->error("%s", msg); + { if (!inObject) + error("%s", msg); errorException = this; } - //if (id == Id::ClassInfo) - if (id == Id::TypeInfo_Class) - { if (classinfo) - classinfo->error("%s", msg); - classinfo = this; - } - #if !MODULEINFO_IS_STRUCT #ifdef DMDV2 if (id == Id::ModuleInfo && !Module::moduleinfo) @@ -227,7 +219,7 @@ ClassDeclaration::ClassDeclaration(Loc loc, Identifier *id, BaseClasses *basecla #else if (id == Id::ModuleInfo) { if (Module::moduleinfo) - Module::moduleinfo->error("%s", msg); + error("%s", msg); Module::moduleinfo = this; } #endif @@ -235,6 +227,7 @@ ClassDeclaration::ClassDeclaration(Loc loc, Identifier *id, BaseClasses *basecla } com = 0; + cpp = 0; isscope = 0; isabstract = 0; inuse = 0; @@ -302,7 +295,8 @@ void ClassDeclaration::semantic(Scope *sc) Scope *scx = NULL; if (scope) - { sc = scope; + { + sc = scope; scx = scope; // save so we don't make redundant copies scope = NULL; } @@ -316,17 +310,21 @@ void ClassDeclaration::semantic(Scope *sc) userAttributes = sc->userAttributes; if (sc->linkage == LINKcpp) - error("cannot create C++ classes"); + cpp = 1; // Expand any tuples in baseclasses[] for (size_t i = 0; i < baseclasses->dim; ) - { BaseClass *b = (*baseclasses)[i]; - b->type = b->type->semantic(loc, sc); - Type *tb = b->type->toBasetype(); + { + // Ungag errors when not speculative + Ungag ungag = ungagSpeculative(); + BaseClass *b = (*baseclasses)[i]; + b->type = b->type->semantic(loc, sc); + + Type *tb = b->type->toBasetype(); if (tb->ty == Ttuple) { TypeTuple *tup = (TypeTuple *)tb; - enum PROT protection = b->protection; + PROT protection = b->protection; baseclasses->remove(i); size_t dim = Parameter::dim(tup->arguments); for (size_t j = 0; j < dim; j++) @@ -341,21 +339,23 @@ void ClassDeclaration::semantic(Scope *sc) // See if there's a base class as first in baseclasses[] if (baseclasses->dim) - { TypeClass *tc; - BaseClass *b; - Type *tb; + { + // Ungag errors when not speculative + Ungag ungag = ungagSpeculative(); - b = (*baseclasses)[0]; + BaseClass *b = (*baseclasses)[0]; //b->type = b->type->semantic(loc, sc); - tb = b->type->toBasetype(); + + Type *tb = b->type->toBasetype(); if (tb->ty != Tclass) - { if (b->type != Type::terror) + { + if (b->type != Type::terror) error("base type must be class or interface, not %s", b->type->toChars()); baseclasses->remove(0); } else { - tc = (TypeClass *)(tb); + TypeClass *tc = (TypeClass *)(tb); if (tc->sym->isDeprecated()) { @@ -411,19 +411,18 @@ void ClassDeclaration::semantic(Scope *sc) // Treat the remaining entries in baseclasses as interfaces // Check for errors, handle forward references for (size_t i = (baseClass ? 1 : 0); i < baseclasses->dim; ) - { TypeClass *tc; - BaseClass *b; - Type *tb; + { + // Ungag errors when not speculative + Ungag ungag = ungagSpeculative(); - b = (*baseclasses)[i]; + BaseClass *b = (*baseclasses)[i]; b->type = b->type->semantic(loc, sc); - tb = b->type->toBasetype(); - if (tb->ty == Tclass) - tc = (TypeClass *)tb; - else - tc = NULL; + + Type *tb = b->type->toBasetype(); + TypeClass *tc = (tb->ty == Tclass) ? (TypeClass *)tb : NULL; if (!tc || !tc->sym->isInterfaceDeclaration()) - { if (b->type != Type::terror) + { + if (b->type != Type::terror) error("base type must be interface, not %s", b->type->toChars()); baseclasses->remove(i); continue; @@ -475,63 +474,65 @@ void ClassDeclaration::semantic(Scope *sc) doAncestorsSemantic = SemanticDone; - // If no base class, and this is not an Object, use Object as base class - if (!baseClass && ident != Id::Object) - { - if (!object) - { - error("missing or corrupt object.d"); - fatal(); - } - - Type *t = object->type; - t = t->semantic(loc, sc)->toBasetype(); - assert(t->ty == Tclass); - TypeClass *tc = (TypeClass *)t; - - BaseClass *b = new BaseClass(tc, PROTpublic); - baseclasses->shift(b); - - baseClass = tc->sym; - assert(!baseClass->isInterfaceDeclaration()); - b->base = baseClass; - } - - interfaces_dim = baseclasses->dim; - interfaces = baseclasses->tdata(); - - - if (baseClass) - { - if (baseClass->storage_class & 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.tdata(), baseClass->vtbl.tdata(), sizeof(void *) * vtbl.dim); - - // Inherit properties from base class - com = baseClass->isCOMclass(); - isscope = baseClass->isscope; - vthis = baseClass->vthis; - enclosing = baseClass->enclosing; - storage_class |= baseClass->storage_class & STC_TYPECTOR; - } - else - { - // No base class, so this is the root of the class hierarchy - vtbl.setDim(0); - vtbl.push(this); // leave room for classinfo as first member - } - - protection = sc->protection; - storage_class |= sc->stc; - if (sizeok == SIZEOKnone) { + // If no base class, and this is not an Object, use Object as base class + if (!baseClass && ident != Id::Object && !cpp) + { + if (!object) + { + error("missing or corrupt object.d"); + fatal(); + } + + Type *t = object->type; + t = t->semantic(loc, sc)->toBasetype(); + assert(t->ty == Tclass); + TypeClass *tc = (TypeClass *)t; + + BaseClass *b = new BaseClass(tc, PROTpublic); + baseclasses->shift(b); + + baseClass = tc->sym; + assert(!baseClass->isInterfaceDeclaration()); + b->base = baseClass; + } + + interfaces_dim = baseclasses->dim; + interfaces = baseclasses->tdata(); + + if (baseClass) + { + if (baseClass->storage_class & 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.tdata(), baseClass->vtbl.tdata(), sizeof(void *) * vtbl.dim); + + // Inherit properties from base class + com = baseClass->isCOMclass(); + if (baseClass->isCPPclass()) + cpp = 1; + isscope = baseClass->isscope; + vthis = baseClass->vthis; + enclosing = baseClass->enclosing; + storage_class |= baseClass->storage_class & STC_TYPECTOR; + } + else + { + // No base class, so this is the root of the class hierarchy + vtbl.setDim(0); + if (vtblOffset()) + vtbl.push(this); // leave room for classinfo as first member + } + + protection = sc->protection; + storage_class |= sc->stc; + interfaceSemantic(sc); for (size_t i = 0; i < members->dim; i++) @@ -544,7 +545,8 @@ void ClassDeclaration::semantic(Scope *sc) * member which is a pointer to the enclosing scope. */ if (vthis) // if inheriting from nested class - { // Use the base class's 'this' member + { + // Use the base class's 'this' member if (storage_class & STCstatic) error("static class cannot inherit from nested class %s", baseClass->toChars()); if (toParent2() != baseClass->toParent2() && @@ -570,14 +572,14 @@ void ClassDeclaration::semantic(Scope *sc) } else makeNested(); - } - if (storage_class & STCauto) - error("storage class 'auto' is invalid when declaring a class, did you mean to use 'scope'?"); - if (storage_class & STCscope) - isscope = 1; - if (storage_class & STCabstract) - isabstract = 1; + if (storage_class & STCauto) + error("storage class 'auto' is invalid when declaring a class, did you mean to use 'scope'?"); + if (storage_class & STCscope) + isscope = 1; + if (storage_class & STCabstract) + isabstract = 1; + } sc = sc->push(this); //sc->stc &= ~(STCfinal | STCauto | STCscope | STCstatic | STCabstract | STCdeprecated | STC_TYPECTOR | STCtls | STCgshared); @@ -585,7 +587,6 @@ void ClassDeclaration::semantic(Scope *sc) sc->stc &= STCsafe | STCtrusted | STCsystem; sc->parent = this; sc->inunion = 0; - if (isCOMclass()) { if (global.params.isWindows) @@ -600,13 +601,19 @@ void ClassDeclaration::semantic(Scope *sc) sc->explicitProtection = 0; sc->structalign = STRUCTALIGN_DEFAULT; if (baseClass) - { sc->offset = baseClass->structsize; + { + sc->offset = baseClass->structsize; alignsize = baseClass->alignsize; + sc->offset = (sc->offset + alignsize - 1) & ~(alignsize - 1); // if (enclosing) // sc->offset += Target::ptrsize; // room for uplevel context pointer } else - { sc->offset = Target::ptrsize * 2; // allow room for __vptr and __monitor + { + if (cpp) + sc->offset = Target::ptrsize; // allow room for __vptr + else + sc->offset = Target::ptrsize * 2; // allow room for __vptr and __monitor alignsize = Target::ptrsize; } sc->userAttributes = NULL; @@ -619,50 +626,45 @@ void ClassDeclaration::semantic(Scope *sc) * resolve individual members like enums. */ for (size_t i = 0; i < members_dim; i++) - { Dsymbol *s = (*members)[i]; - /* There are problems doing this in the general case because - * Scope keeps track of things like 'offset' - */ - if (s->isEnumDeclaration() || - (s->isAggregateDeclaration() && s->ident) || - s->isTemplateMixin() || - s->isAttribDeclaration() || - s->isAliasDeclaration()) - { - //printf("[%d] setScope %s %s, sc = %p\n", i, s->kind(), s->toChars(), sc); - s->setScope(sc); - } + { + Dsymbol *s = (*members)[i]; + //printf("[%d] setScope %s %s, sc = %p\n", i, s->kind(), s->toChars(), sc); + s->setScope(sc); } for (size_t i = 0; i < members_dim; i++) - { Dsymbol *s = (*members)[i]; + { + Dsymbol *s = (*members)[i]; + + // Ungag errors when not speculative + Ungag ungag = ungagSpeculative(); s->semantic(sc); } // Set the offsets of the fields and determine the size of the class unsigned offset = structsize; - bool isunion = isUnionDeclaration() != NULL; for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (*members)[i]; + { + Dsymbol *s = (*members)[i]; s->setFieldOffset(this, &offset, false); } sc->offset = structsize; if (global.errors != errors) - { // The type is no good. + { + // The type is no good. type = Type::terror; } if (sizeok == SIZEOKfwd) // failed due to forward references - { // semantic() failed due to forward references + { + // semantic() failed due to forward references // Unwind what we did, and defer it for later - for (size_t i = 0; i < fields.dim; i++) - { Dsymbol *s = fields[i]; - VarDeclaration *vd = s->isVarDeclaration(); - if (vd) - vd->offset = 0; + { + if (VarDeclaration *v = fields[i]) + v->offset = 0; } fields.setDim(0); structsize = 0; @@ -688,11 +690,7 @@ void ClassDeclaration::semantic(Scope *sc) /* Look for special member functions. * They must be in this class, not in a base class. */ - ctor = search(Loc(), Id::ctor, 0); -#if DMDV1 - if (ctor && (ctor->toParent() != this || !ctor->isCtorDeclaration())) - ctor = NULL; -#else + searchCtor(); if (ctor && (ctor->toParent() != this || !(ctor->isCtorDeclaration() || ctor->isTemplateDeclaration()))) ctor = NULL; // search() looks through ancestor classes if (!ctor && noDefaultCtor) @@ -705,11 +703,6 @@ void ClassDeclaration::semantic(Scope *sc) ::error(v->loc, "field %s must be initialized in constructor", v->toChars()); } } -#endif - -// dtor = (DtorDeclaration *)search(Id::dtor, 0); -// if (dtor && dtor->toParent() != this) -// dtor = NULL; inv = buildInv(sc); @@ -722,10 +715,14 @@ void ClassDeclaration::semantic(Scope *sc) // this() { } if (!ctor && baseClass && baseClass->ctor) { - if (resolveFuncCall(loc, sc, baseClass->ctor, NULL, NULL, NULL, 1)) + if (FuncDeclaration *fd = resolveFuncCall(loc, sc, baseClass->ctor, NULL, NULL, NULL, 1)) { //printf("Creating default this(){} for class %s\n", toChars()); - Type *tf = new TypeFunction(NULL, NULL, 0, LINKd, 0); + TypeFunction *btf = (TypeFunction *)fd->type; + TypeFunction *tf = new TypeFunction(NULL, NULL, 0, LINKd, fd->storage_class); + tf->purity = btf->purity; + tf->isnothrow = btf->isnothrow; + tf->trust = btf->trust; CtorDeclaration *ctor = new CtorDeclaration(loc, Loc(), 0, tf); ctor->fbody = new CompoundStatement(Loc(), new Statements()); members->push(ctor); @@ -787,7 +784,7 @@ void ClassDeclaration::semantic(Scope *sc) if (FuncDeclaration *f = hasIdentityOpAssign(sc)) { if (!(f->storage_class & STCdisable)) - error("identity assignment operator overload is illegal"); + error(f->loc, "identity assignment operator overload is illegal"); } sc->pop(); @@ -808,14 +805,12 @@ void ClassDeclaration::semantic(Scope *sc) deferred->semantic3(sc); } -#if 0 if (type->ty == Tclass && ((TypeClass *)type)->sym != this) { - printf("this = %p %s\n", this, this->toChars()); - printf("type = %d sym = %p\n", type->ty, ((TypeClass *)type)->sym); + error("failed semantic analysis"); + this->errors = true; + type = Type::terror; } -#endif - assert(type->ty != Tclass || ((TypeClass *)type)->sym == this); } void ClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) @@ -899,10 +894,10 @@ int ClassDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset) { /* cd->baseClass might not be set if cd is forward referenced. */ - if (!cd->baseClass && cd->baseclasses->dim && !cd->isInterfaceDeclaration()) + if (!cd->baseClass && cd->scope && !cd->isInterfaceDeclaration()) { cd->semantic(NULL); - if (!cd->baseClass) + if (!cd->baseClass && cd->scope) cd->error("base class is forward referenced by %s", toChars()); } @@ -941,14 +936,7 @@ Dsymbol *ClassDeclaration::search(Loc loc, Identifier *ident, int flags) { // must semantic on base class/interfaces doAncestorsSemantic = SemanticIn; - - // If speculatively gagged, ungag now. - unsigned oldgag = global.gag; - if (global.isSpeculativeGagging()) - global.gag = 0; semantic(scope); - global.gag = oldgag; - if (doAncestorsSemantic != SemanticDone) doAncestorsSemantic = SemanticStart; } @@ -995,6 +983,8 @@ ClassDeclaration *ClassDeclaration::searchBase(Loc loc, Identifier *ident) { BaseClass *b = (*baseclasses)[i]; ClassDeclaration *cdb = b->type->isClassHandle(); + if (!cdb) // Bugzilla 10616 + return NULL; if (cdb->ident->equals(ident)) return cdb; cdb = cdb->searchBase(loc, ident); @@ -1010,10 +1000,13 @@ ClassDeclaration *ClassDeclaration::searchBase(Loc loc, Identifier *ident) */ #if DMDV2 -int isf(void *param, FuncDeclaration *fd) +int isf(void *param, Dsymbol *s) { + FuncDeclaration *fd = s->isFuncDeclaration(); + if (!fd) + return 0; //printf("param = %p, fd = %p %s\n", param, fd, fd->toChars()); - return param == fd; + return (RootObject *)param == fd; } int ClassDeclaration::isFuncHidden(FuncDeclaration *fd) @@ -1021,7 +1014,8 @@ int ClassDeclaration::isFuncHidden(FuncDeclaration *fd) //printf("ClassDeclaration::isFuncHidden(class = %s, fd = %s)\n", toChars(), fd->toChars()); Dsymbol *s = search(Loc(), fd->ident, 4|2); if (!s) - { //printf("not found\n"); + { + //printf("not found\n"); /* Because, due to a hack, if there are multiple definitions * of fd->ident, NULL is returned. */ @@ -1032,9 +1026,10 @@ int ClassDeclaration::isFuncHidden(FuncDeclaration *fd) if (os) { for (size_t i = 0; i < os->a.dim; i++) - { Dsymbol *s2 = os->a[i]; + { + Dsymbol *s2 = os->a[i]; FuncDeclaration *f2 = s2->isFuncDeclaration(); - if (f2 && overloadApply(f2, &isf, fd)) + if (f2 && overloadApply(f2, (void *)fd, &isf)) return 0; } return 1; @@ -1043,7 +1038,7 @@ int ClassDeclaration::isFuncHidden(FuncDeclaration *fd) { FuncDeclaration *fdstart = s->isFuncDeclaration(); //printf("%s fdstart = %p\n", s->kind(), fdstart); - if (overloadApply(fdstart, &isf, fd)) + if (overloadApply(fdstart, (void *)fd, &isf)) return 0; return !fd->parent->isTemplateMixin(); @@ -1152,9 +1147,13 @@ void ClassDeclaration::interfaceSemantic(Scope *sc) if (b->base->isCOMinterface()) com = 1; +#if 1 if (b->base->isCPPinterface() && id) id->cpp = 1; - +#else + if (b->base->isCPPinterface()) + cpp = 1; +#endif vtblInterfaces->push(b); b->copyBaseInterfaces(vtblInterfaces); } @@ -1174,6 +1173,11 @@ int ClassDeclaration::isCOMinterface() } #if DMDV2 +int ClassDeclaration::isCPPclass() +{ + return cpp; +} + int ClassDeclaration::isCPPinterface() { return 0; @@ -1184,10 +1188,10 @@ int ClassDeclaration::isCPPinterface() /**************************************** */ -int ClassDeclaration::isAbstract() +bool ClassDeclaration::isAbstract() { if (isabstract) - return TRUE; + return true; for (size_t i = 1; i < vtbl.dim; i++) { FuncDeclaration *fd = vtbl[i]->isFuncDeclaration(); @@ -1196,10 +1200,10 @@ int ClassDeclaration::isAbstract() if (!fd || fd->isAbstract()) { isabstract |= 1; - return TRUE; + return true; } } - return FALSE; + return false; } @@ -1208,11 +1212,14 @@ int ClassDeclaration::isAbstract() * For class objects, yes, this is where the classinfo ptr goes. * For COM interfaces, no. * For non-COM interfaces, yes, this is where the Interface ptr goes. + * Returns: + * 0 vtbl[0] is first virtual function pointer + * 1 vtbl[0] is classinfo/interfaceinfo pointer */ int ClassDeclaration::vtblOffset() { - return 1; + return cpp ? 0 : 1; } /**************************************** @@ -1236,8 +1243,6 @@ void ClassDeclaration::addLocalClass(ClassDeclarations *aclasses) InterfaceDeclaration::InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses) : ClassDeclaration(loc, id, baseclasses) { - com = 0; - cpp = 0; if (id == Id::IUnknown) // IUnknown is the root of all COM interfaces { com = 1; cpp = 1; // IUnknown is also a C++ interface @@ -1284,7 +1289,8 @@ void InterfaceDeclaration::semantic(Scope *sc) Scope *scx = NULL; if (scope) - { sc = scope; + { + sc = scope; scx = scope; // save so we don't make redundant copies scope = NULL; } @@ -1299,13 +1305,17 @@ void InterfaceDeclaration::semantic(Scope *sc) // Expand any tuples in baseclasses[] for (size_t i = 0; i < baseclasses->dim; ) - { BaseClass *b = (*baseclasses)[i]; - b->type = b->type->semantic(loc, sc); - Type *tb = b->type->toBasetype(); + { + // Ungag errors when not speculative + Ungag ungag = ungagSpeculative(); + BaseClass *b = (*baseclasses)[i]; + b->type = b->type->semantic(loc, sc); + + Type *tb = b->type->toBasetype(); if (tb->ty == Ttuple) { TypeTuple *tup = (TypeTuple *)tb; - enum PROT protection = b->protection; + PROT protection = b->protection; baseclasses->remove(i); size_t dim = Parameter::dim(tup->arguments); for (size_t j = 0; j < dim; j++) @@ -1323,19 +1333,18 @@ void InterfaceDeclaration::semantic(Scope *sc) // Check for errors, handle forward references for (size_t i = 0; i < baseclasses->dim; ) - { TypeClass *tc; - BaseClass *b; - Type *tb; + { + // Ungag errors when not speculative + Ungag ungag = ungagSpeculative(); - b = (*baseclasses)[i]; + BaseClass *b = (*baseclasses)[i]; b->type = b->type->semantic(loc, sc); - tb = b->type->toBasetype(); - if (tb->ty == Tclass) - tc = (TypeClass *)tb; - else - tc = NULL; + + Type *tb = b->type->toBasetype(); + TypeClass *tc = (tb->ty == Tclass) ? (TypeClass *)tb : NULL; if (!tc || !tc->sym->isInterfaceDeclaration()) - { if (b->type != Type::terror) + { + if (b->type != Type::terror) error("base type must be interface, not %s", b->type->toChars()); baseclasses->remove(i); continue; @@ -1432,9 +1441,9 @@ void InterfaceDeclaration::semantic(Scope *sc) sc = sc->push(this); sc->stc &= STCsafe | STCtrusted | STCsystem; sc->parent = this; - if (isCOMinterface()) + if (com) sc->linkage = LINKwindows; - else if (isCPPinterface()) + else if (cpp) sc->linkage = LINKcpp; sc->structalign = STRUCTALIGN_DEFAULT; sc->protection = PROTpublic; @@ -1463,6 +1472,9 @@ void InterfaceDeclaration::semantic(Scope *sc) for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (*members)[i]; + + // Ungag errors when not speculative + Ungag ungag = ungagSpeculative(); s->semantic(sc); } @@ -1476,14 +1488,12 @@ void InterfaceDeclaration::semantic(Scope *sc) sc->pop(); //printf("-InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type); -#if 0 if (type->ty == Tclass && ((TypeClass *)type)->sym != this) { - printf("this = %p %s\n", this, this->toChars()); - printf("type = %d sym = %p\n", type->ty, ((TypeClass *)type)->sym); + error("failed semantic analysis"); + this->errors = true; + type = Type::terror; } -#endif - assert(type->ty != Tclass || ((TypeClass *)type)->sym == this); } @@ -1618,7 +1628,7 @@ BaseClass::BaseClass() memset(this, 0, sizeof(BaseClass)); } -BaseClass::BaseClass(Type *type, enum PROT protection) +BaseClass::BaseClass(Type *type, PROT protection) { //printf("BaseClass(this = %p, '%s')\n", this, type->toChars()); this->type = type; @@ -1643,7 +1653,6 @@ BaseClass::BaseClass(Type *type, enum PROT protection) int BaseClass::fillVtbl(ClassDeclaration *cd, FuncDeclarations *vtbl, int newinstance) { - ClassDeclaration *id = base; int result = 0; //printf("BaseClass::fillVtbl(this='%s', cd='%s')\n", base->toChars(), cd->toChars()); diff --git a/dmd2/clone.c b/dmd2/clone.c index 03ea82c2..daf7ff26 100644 --- a/dmd2/clone.c +++ b/dmd2/clone.c @@ -135,13 +135,10 @@ int StructDeclaration::needOpAssign() assert(v && v->isField()); if (v->storage_class & STCref) continue; - Type *tv = v->type->toBasetype(); - while (tv->ty == Tsarray) - { TypeSArray *ta = (TypeSArray *)tv; - tv = tv->nextOf()->toBasetype(); - } + Type *tv = v->type->baseElemOf(); if (tv->ty == Tstruct) - { TypeStruct *ts = (TypeStruct *)tv; + { + TypeStruct *ts = (TypeStruct *)tv; StructDeclaration *sd = ts->sym; if (sd->needOpAssign()) goto Lneed; @@ -164,7 +161,7 @@ Lneed: * Note that s will be constructed onto the stack, and probably * copy-constructed in caller site. * - * If S has copy copy construction and/or destructor, + * If S has copy copy construction and/or destructor, * the body will make bit-wise object swap: * S __tmp = this; // bit copy * this = s; // bit copy @@ -192,19 +189,46 @@ FuncDeclaration *StructDeclaration::buildOpAssign(Scope *sc) return NULL; //printf("StructDeclaration::buildOpAssign() %s\n", toChars()); - StorageClass stc = STCundefined; + StorageClass stc = STCsafe | STCnothrow | STCpure; Loc declLoc = this->loc; Loc loc = Loc(); // internal code should have no loc to prevent coverage + if (dtor || postblit) + { + if (dtor) + stc = mergeFuncAttrs(stc, dtor->storage_class); + } + else + { + for (size_t i = 0; i < fields.dim; i++) + { + Dsymbol *s = fields[i]; + VarDeclaration *v = s->isVarDeclaration(); + assert(v && v->isField()); + if (v->storage_class & STCref) + continue; + Type *tv = v->type->baseElemOf(); + if (tv->ty == Tstruct) + { + TypeStruct *ts = (TypeStruct *)tv; + StructDeclaration *sd = ts->sym; + if (FuncDeclaration *f = sd->hasIdentityOpAssign(sc)) + stc = mergeFuncAttrs(stc, f->storage_class); + } + } + } + Parameters *fparams = new Parameters; fparams->push(new Parameter(STCnodtor, type, Id::p, NULL)); - Type *ftype = new TypeFunction(fparams, handle, FALSE, LINKd); - ((TypeFunction *)ftype)->isref = 1; + Type *tf = new TypeFunction(fparams, handle, 0, LINKd, stc | STCref); - FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), Id::assign, stc, ftype); + FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), Id::assign, stc, tf); Expression *e = NULL; - if (dtor || postblit) + if (stc & STCdisable) + { + } + else if (dtor || postblit) { /* Do swap this and rhs * tmp = this; this = s; tmp.dtor(); @@ -258,15 +282,18 @@ FuncDeclaration *StructDeclaration::buildOpAssign(Scope *sc) e = Expression::combine(e, ec); } } - Statement *s1 = new ExpStatement(loc, e); + if (e) + { + Statement *s1 = new ExpStatement(loc, e); - /* Add: - * return this; - */ - e = new ThisExp(loc); - Statement *s2 = new ReturnStatement(loc, e); + /* Add: + * return this; + */ + e = new ThisExp(loc); + Statement *s2 = new ReturnStatement(loc, e); - fop->fbody = new CompoundStatement(loc, s1, s2); + fop->fbody = new CompoundStatement(loc, s1, s2); + } Dsymbol *s = fop; #if 1 // workaround until fixing issue 1528 @@ -347,12 +374,10 @@ int StructDeclaration::needOpEquals() goto Lneed; if (tv->ty == Tclass) goto Lneed; - while (tv->ty == Tsarray) - { TypeSArray *ta = (TypeSArray *)tv; - tv = tv->nextOf()->toBasetype(); - } + tv = tv->baseElemOf(); if (tv->ty == Tstruct) - { TypeStruct *ts = (TypeStruct *)tv; + { + TypeStruct *ts = (TypeStruct *)tv; StructDeclaration *sd = ts->sym; if (sd->needOpEquals()) goto Lneed; @@ -384,7 +409,7 @@ FuncDeclaration *AggregateDeclaration::hasIdentityOpEquals(Scope *sc) Type *tthis; if (i == 0) tthis = type; if (i == 1) tthis = type->constOf(); - if (i == 2) tthis = type->invariantOf(); + if (i == 2) tthis = type->immutableOf(); if (i == 3) tthis = type->sharedOf(); if (i == 4) tthis = type->sharedConstOf(); if (i == 5) break; @@ -449,9 +474,48 @@ FuncDeclaration *StructDeclaration::buildOpEquals(Scope *sc) FuncDeclaration *StructDeclaration::buildXopEquals(Scope *sc) { if (!needOpEquals()) - return NULL; + return NULL; // bitwise comparison would work //printf("StructDeclaration::buildXopEquals() %s\n", toChars()); + if (Dsymbol *eq = search_function(this, Id::eq)) + { + if (FuncDeclaration *fd = eq->isFuncDeclaration()) + { + TypeFunction *tfeqptr; + { + Scope sc; + + /* const bool opEquals(ref const S s); + */ + Parameters *parameters = new Parameters; + parameters->push(new Parameter(STCref | STCconst, type, NULL, NULL)); + tfeqptr = new TypeFunction(parameters, Type::tbool, 0, LINKd); + tfeqptr->mod = MODconst; + tfeqptr = (TypeFunction *)tfeqptr->semantic(Loc(), &sc); + } + fd = fd->overloadExactMatch(tfeqptr); + if (fd) + return fd; + } + } + + if (!xerreq) + { + Identifier *id = Lexer::idPool("_xopEquals"); + Expression *e = new IdentifierExp(loc, Id::empty); + e = new DotIdExp(loc, e, Id::object); + e = new DotIdExp(loc, e, id); + e = e->semantic(sc); + Dsymbol *s = getDsymbol(e); + if (!s) + { + ::error(Loc(), "ICE: %s not found in object module. You must update druntime", id->toChars()); + fatal(); + } + assert(s); + xerreq = s->isFuncDeclaration(); + } + Loc declLoc = Loc(); // loc is unnecessary so __xopEquals is never called directly Loc loc = Loc(); // loc is unnecessary so errors are gagged @@ -470,42 +534,143 @@ FuncDeclaration *StructDeclaration::buildXopEquals(Scope *sc) fop->fbody = new ReturnStatement(loc, e); - size_t index = members->dim; - members->push(fop); - - unsigned errors = global.startGagging(); // Do not report errors, even if the - unsigned oldspec = global.speculativeGag; // template opAssign fbody makes it. - global.speculativeGag = global.gag; + unsigned errors = global.startGagging(); // Do not report errors Scope *sc2 = sc->push(); sc2->stc = 0; sc2->linkage = LINKd; - sc2->speculative = true; fop->semantic(sc2); fop->semantic2(sc2); - fop->semantic3(sc2); sc2->pop(); - global.speculativeGag = oldspec; if (global.endGagging(errors)) // if errors happened - { - members->remove(index); - - if (!xerreq) - { - Expression *e = new IdentifierExp(loc, Id::empty); - e = new DotIdExp(loc, e, Id::object); - e = new DotIdExp(loc, e, Lexer::idPool("_xopEquals")); - e = e->semantic(sc); - Dsymbol *s = getDsymbol(e); - FuncDeclaration *fd = s->isFuncDeclaration(); - - xerreq = fd; - } fop = xerreq; + + return fop; +} + +/****************************************** + * Build __xopCmp for TypeInfo_Struct + * static bool __xopCmp(ref const S p, ref const S q) + * { + * return p.opCmp(q); + * } + * + * This is called by TypeInfo.compare(p1, p2). If the struct does not support + * const objects comparison, it will throw "not implemented" Error in runtime. + */ + +FuncDeclaration *StructDeclaration::buildXopCmp(Scope *sc) +{ + //printf("StructDeclaration::buildXopCmp() %s\n", toChars()); + if (Dsymbol *cmp = search_function(this, Id::cmp)) + { + if (FuncDeclaration *fd = cmp->isFuncDeclaration()) + { + TypeFunction *tfcmpptr; + { + Scope sc; + + /* const int opCmp(ref const S s); + */ + Parameters *parameters = new Parameters; + parameters->push(new Parameter(STCref | STCconst, type, NULL, NULL)); + tfcmpptr = new TypeFunction(parameters, Type::tint32, 0, LINKd); + tfcmpptr->mod = MODconst; + tfcmpptr = (TypeFunction *)tfcmpptr->semantic(Loc(), &sc); + } + fd = fd->overloadExactMatch(tfcmpptr); + if (fd) + return fd; + } } else - fop->addMember(sc, this, 1); + { +#if 0 // FIXME: doesn't work for recursive alias this + /* Check opCmp member exists. + * Consider 'alias this', but except opDispatch. + */ + Expression *e = new DsymbolExp(loc, this); + e = new DotIdExp(loc, e, Id::cmp); + Scope *sc2 = sc->push(); + e = e->trySemantic(sc2); + sc2->pop(); + if (e) + { + Dsymbol *s = NULL; + switch (e->op) + { + case TOKoverloadset: s = ((OverExp *)e)->vars; break; + case TOKimport: s = ((ScopeExp *)e)->sds; break; + case TOKvar: s = ((VarExp *)e)->var; break; + default: break; + } + if (!s || s->ident != Id::cmp) + e = NULL; // there's no valid member 'opCmp' + } + if (!e) + return NULL; // bitwise comparison would work + /* Essentially, a struct which does not define opCmp is not comparable. + * At this time, typeid(S).compare might be correct that throwing "not implement" Error. + * But implementing it would break existing code, such as: + * + * struct S { int value; } // no opCmp + * int[S] aa; // Currently AA key uses bitwise comparison + * // (It's default behavior of TypeInfo_Strust.compare). + * + * Not sure we should fix this inconsistency, so just keep current behavior. + */ +#else + return NULL; +#endif + } + + if (!xerrcmp) + { + Identifier *id = Lexer::idPool("_xopCmp"); + Expression *e = new IdentifierExp(loc, Id::empty); + e = new DotIdExp(loc, e, Id::object); + e = new DotIdExp(loc, e, id); + e = e->semantic(sc); + Dsymbol *s = getDsymbol(e); + if (!s) + { + ::error(Loc(), "ICE: %s not found in object module. You must update druntime", id->toChars()); + fatal(); + } + assert(s); + xerrcmp = s->isFuncDeclaration(); + } + + Loc declLoc = Loc(); // loc is unnecessary so __xopCmp is never called directly + Loc loc = Loc(); // loc is unnecessary so errors are gagged + + Parameters *parameters = new Parameters; + parameters->push(new Parameter(STCref | STCconst, type, Id::p, NULL)); + parameters->push(new Parameter(STCref | STCconst, type, Id::q, NULL)); + TypeFunction *tf = new TypeFunction(parameters, Type::tint32, 0, LINKd); + tf = (TypeFunction *)tf->semantic(loc, sc); + + Identifier *id = Lexer::idPool("__xopCmp"); + FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), id, STCstatic, tf); + + Expression *e1 = new IdentifierExp(loc, Id::p); + Expression *e2 = new IdentifierExp(loc, Id::q); + Expression *e = new CallExp(loc, new DotIdExp(loc, e1, Id::cmp), e2); + + fop->fbody = new ReturnStatement(loc, e); + + unsigned errors = global.startGagging(); // Do not report errors + Scope *sc2 = sc->push(); + sc2->stc = 0; + sc2->linkage = LINKd; + + fop->semantic(sc2); + fop->semantic2(sc2); + + sc2->pop(); + if (global.endGagging(errors)) // if errors happened + fop = xerrcmp; return fop; } @@ -542,14 +707,14 @@ FuncDeclaration *StructDeclaration::buildCpCtor(Scope *sc) stc = mergeFuncAttrs(stc, postblit->storage_class); if (stc & STCsafe) // change to @trusted for unsafe casts - stc = stc & ~STCsafe | STCtrusted; + stc = (stc & ~STCsafe) | STCtrusted; Parameters *fparams = new Parameters; fparams->push(new Parameter(STCref, type->constOf(), Id::p, NULL)); - Type *ftype = new TypeFunction(fparams, Type::tvoid, 0, LINKd, stc); - ftype->mod = MODconst; + Type *tf = new TypeFunction(fparams, Type::tvoid, 0, LINKd, stc); + tf->mod = MODconst; - FuncDeclaration *fcp = new FuncDeclaration(declLoc, Loc(), Id::cpctor, stc, ftype); + FuncDeclaration *fcp = new FuncDeclaration(declLoc, Loc(), Id::cpctor, stc, tf); if (!(stc & STCdisable)) { @@ -612,12 +777,14 @@ FuncDeclaration *StructDeclaration::buildPostBlit(Scope *sc) Type *tv = v->type->toBasetype(); dinteger_t dim = 1; while (tv->ty == Tsarray) - { TypeSArray *ta = (TypeSArray *)tv; - dim *= ((TypeSArray *)tv)->dim->toInteger(); - tv = tv->nextOf()->toBasetype(); + { + TypeSArray *tsa = (TypeSArray *)tv; + dim *= tsa->dim->toInteger(); + tv = tsa->next->toBasetype(); } if (tv->ty == Tstruct) - { TypeStruct *ts = (TypeStruct *)tv; + { + TypeStruct *ts = (TypeStruct *)tv; StructDeclaration *sd = ts->sym; if (sd->postblit && dim) { @@ -726,12 +893,14 @@ FuncDeclaration *AggregateDeclaration::buildDtor(Scope *sc) Type *tv = v->type->toBasetype(); dinteger_t dim = 1; while (tv->ty == Tsarray) - { TypeSArray *ta = (TypeSArray *)tv; - dim *= ((TypeSArray *)tv)->dim->toInteger(); - tv = tv->nextOf()->toBasetype(); + { + TypeSArray *tsa = (TypeSArray *)tv; + dim *= tsa->dim->toInteger(); + tv = tsa->next->toBasetype(); } if (tv->ty == Tstruct) - { TypeStruct *ts = (TypeStruct *)tv; + { + TypeStruct *ts = (TypeStruct *)tv; StructDeclaration *sd = ts->sym; if (sd->dtor && dim) { diff --git a/dmd2/cond.c b/dmd2/cond.c index 87666ed2..183b59a9 100644 --- a/dmd2/cond.c +++ b/dmd2/cond.c @@ -84,16 +84,41 @@ DebugCondition::DebugCondition(Module *mod, unsigned level, Identifier *ident) { } +// Helper for printing dependency information +void printDepsConditional(Scope *sc, DVCondition* condition, const char* depType) +{ + if (!global.params.moduleDeps || global.params.moduleDepsFile) + return; + OutBuffer *ob = global.params.moduleDeps; + Module* imod = sc ? (sc->instantiatingModule ? sc->instantiatingModule : sc->module) : condition->mod; + if (!imod) + return; + ob->writestring(depType); + ob->writestring(imod->toPrettyChars()); + ob->writestring(" ("); + escapePath(ob, imod->srcfile->toChars()); + ob->writestring(") : "); + if (condition->ident) + ob->printf("%s\n", condition->ident->toChars()); + else + ob->printf("%d\n", condition->level); +} + + int DebugCondition::include(Scope *sc, ScopeDsymbol *s) { //printf("DebugCondition::include() level = %d, debuglevel = %d\n", level, global.params.debuglevel); if (inc == 0) { inc = 2; + bool definedInModule = false; if (ident) { if (findCondition(mod->debugids, ident)) + { inc = 1; + definedInModule = true; + } else if (findCondition(global.params.debugids, ident)) inc = 1; else @@ -104,6 +129,8 @@ int DebugCondition::include(Scope *sc, ScopeDsymbol *s) } else if (level <= global.params.debuglevel || level <= mod->debuglevel) inc = 1; + if (!definedInModule) + printDepsConditional(sc, this, "depsDebug "); } return (inc == 1); } @@ -123,7 +150,7 @@ void VersionCondition::setGlobalLevel(unsigned level) global.params.versionlevel = level; } -void VersionCondition::checkPredefined(Loc loc, const char *ident) +bool VersionCondition::isPredefined(const char *ident) { static const char* reserved[] = { @@ -217,16 +244,12 @@ void VersionCondition::checkPredefined(Loc loc, const char *ident) for (unsigned i = 0; i < sizeof(reserved) / sizeof(reserved[0]); i++) { if (strcmp(ident, reserved[i]) == 0) - goto Lerror; + return true; } if (ident[0] == 'D' && ident[1] == '_') - goto Lerror; - - return; - - Lerror: - error(loc, "version identifier '%s' is reserved and cannot be set", ident); + return true; + return false; } void VersionCondition::addGlobalIdent(const char *ident) @@ -255,10 +278,14 @@ int VersionCondition::include(Scope *sc, ScopeDsymbol *s) if (inc == 0) { inc = 2; + bool definedInModule=false; if (ident) { if (findCondition(mod->versionids, ident)) + { inc = 1; + definedInModule = true; + } else if (findCondition(global.params.versionids, ident)) inc = 1; else @@ -270,6 +297,8 @@ int VersionCondition::include(Scope *sc, ScopeDsymbol *s) } else if (level <= global.params.versionlevel || level <= mod->versionlevel) inc = 1; + if (!definedInModule && (!ident || (!isPredefined(ident->toChars()) && ident != Lexer::idPool(Token::toChars(TOKunittest)) && ident != Lexer::idPool(Token::toChars(TOKassert))))) + printDepsConditional(sc, this, "depsVersion "); } return (inc == 1); } @@ -312,9 +341,7 @@ int StaticIfCondition::include(Scope *sc, ScopeDsymbol *s) { error(loc, (nest > 1000) ? "unresolvable circular static if expression" : "error evaluating static if expression"); - if (!global.gag) - inc = 2; // so we don't see the error message again - return 0; + goto Lerror; } if (!sc) @@ -328,21 +355,25 @@ int StaticIfCondition::include(Scope *sc, ScopeDsymbol *s) sc = sc->push(sc->scopesym); sc->sd = s; // s gets any addMember() sc->flags |= SCOPEstaticif; - Expression *e = exp->ctfeSemantic(sc); + + sc = sc->startCTFE(); + Expression *e = exp->semantic(sc); e = resolveProperties(sc, e); + sc = sc->endCTFE(); + sc->pop(); + --nest; + if (!e->type->checkBoolean()) { if (e->type->toBasetype() != Type::terror) exp->error("expression %s of type %s does not have a boolean value", exp->toChars(), e->type->toChars()); - inc = 0; - return 0; + goto Lerror; } e = e->ctfeInterpret(); - --nest; if (e->op == TOKerror) - { exp = e; - inc = 0; + { + goto Lerror; } else if (e->isBool(TRUE)) inc = 1; @@ -351,10 +382,15 @@ int StaticIfCondition::include(Scope *sc, ScopeDsymbol *s) else { e->error("expression %s is not constant or does not evaluate to a bool", e->toChars()); - inc = 2; + goto Lerror; } } return (inc == 1); + +Lerror: + if (!global.gag) + inc = 2; // so we don't see the error message again + return 0; } void StaticIfCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) diff --git a/dmd2/cond.h b/dmd2/cond.h index 9b297569..9394f72e 100644 --- a/dmd2/cond.h +++ b/dmd2/cond.h @@ -11,21 +11,22 @@ #ifndef DMD_DEBCOND_H #define DMD_DEBCOND_H -struct Expression; -struct Identifier; +class Expression; +class Identifier; struct OutBuffer; -struct Module; +class Module; struct Scope; -struct ScopeDsymbol; -struct DebugCondition; +class ScopeDsymbol; +class DebugCondition; #include "lexer.h" // dmdhg enum TOK; struct HdrGenState; int findCondition(Strings *ids, Identifier *ident); -struct Condition +class Condition { +public: Loc loc; int inc; // 0: not computed yet // 1: include @@ -39,8 +40,9 @@ struct Condition virtual DebugCondition *isDebugCondition() { return NULL; } }; -struct DVCondition : Condition +class DVCondition : public Condition { +public: unsigned level; Identifier *ident; Module *mod; @@ -50,8 +52,9 @@ struct DVCondition : Condition Condition *syntaxCopy(); }; -struct DebugCondition : DVCondition +class DebugCondition : public DVCondition { +public: static void setGlobalLevel(unsigned level); static void addGlobalIdent(const char *ident); @@ -62,10 +65,16 @@ struct DebugCondition : DVCondition DebugCondition *isDebugCondition() { return this; } }; -struct VersionCondition : DVCondition +class VersionCondition : public DVCondition { +public: static void setGlobalLevel(unsigned level); - static void checkPredefined(Loc loc, const char *ident); + static bool isPredefined(const char *ident); + static void checkPredefined(Loc loc, const char *ident) + { + if (isPredefined(ident)) + error(loc, "version identifier '%s' is reserved and cannot be set", ident); + } static void addGlobalIdent(const char *ident); static void addPredefinedGlobalIdent(const char *ident); @@ -75,8 +84,9 @@ struct VersionCondition : DVCondition void toCBuffer(OutBuffer *buf, HdrGenState *hgs); }; -struct StaticIfCondition : Condition +class StaticIfCondition : public Condition { +public: Expression *exp; int nest; // limit circular dependencies diff --git a/dmd2/constfold.c b/dmd2/constfold.c index 06f9b302..596f4891 100644 --- a/dmd2/constfold.c +++ b/dmd2/constfold.c @@ -326,11 +326,7 @@ Expression *Mul(Type *type, Expression *e1, Expression *e2) if (type->isfloating()) { complex_t c; -#ifdef IN_GCC - real_t r; -#else d_float80 r; -#endif if (e1->type->isreal()) { @@ -397,11 +393,7 @@ Expression *Div(Type *type, Expression *e1, Expression *e2) if (type->isfloating()) { complex_t c; -#ifdef IN_GCC - real_t r; -#else d_float80 r; -#endif //e1->type->print(); //e2->type->print(); @@ -486,8 +478,6 @@ Expression *Mod(Type *type, Expression *e1, Expression *e2) #ifdef __DMC__ c = Port::fmodl(e1->toReal(), r2) + Port::fmodl(e1->toImaginary(), r2) * I; -#elif defined(IN_GCC) - c = complex_t(e1->toReal() % r2, e1->toImaginary() % r2); #else c = complex_t(Port::fmodl(e1->toReal(), r2), Port::fmodl(e1->toImaginary(), r2)); #endif @@ -497,8 +487,6 @@ Expression *Mod(Type *type, Expression *e1, Expression *e2) #ifdef __DMC__ c = Port::fmodl(e1->toReal(), i2) + Port::fmodl(e1->toImaginary(), i2) * I; -#elif defined(IN_GCC) - c = complex_t(e1->toReal() % i2, e1->toImaginary() % i2); #else c = complex_t(Port::fmodl(e1->toReal(), i2), Port::fmodl(e1->toImaginary(), i2)); #endif @@ -582,8 +570,8 @@ Expression *Pow(Type *type, Expression *e1, Expression *e2) } else { - r = new RealExp(loc, e1->toReal(), Type::tfloat64); - v = new RealExp(loc, ldouble(1.0), Type::tfloat64); + r = new IntegerExp(loc, e1->toInteger(), e1->type); + v = new IntegerExp(loc, 1, e1->type); } while (n != 0) @@ -607,7 +595,7 @@ Expression *Pow(Type *type, Expression *e1, Expression *e2) // x ^^ y for x < 0 and y not an integer is not defined if (e1->toReal() < 0.0) { - e = new RealExp(loc, ldouble(Port::nan), type); + e = new RealExp(loc, Port::ldbl_nan, type); } else if (e2->toReal() == 0.5) { @@ -757,7 +745,7 @@ Expression *Xor(Type *type, Expression *e1, Expression *e2) /* Also returns EXP_CANT_INTERPRET if cannot be computed. */ -Expression *Equal(enum TOK op, Type *type, Expression *e1, Expression *e2) +Expression *Equal(TOK op, Type *type, Expression *e1, Expression *e2) { Expression *e; Loc loc = e1->loc; int cmp; @@ -955,7 +943,7 @@ Expression *Equal(enum TOK op, Type *type, Expression *e1, Expression *e2) return e; } -Expression *Identity(enum TOK op, Type *type, Expression *e1, Expression *e2) +Expression *Identity(TOK op, Type *type, Expression *e1, Expression *e2) { Loc loc = e1->loc; int cmp; @@ -1002,7 +990,7 @@ Expression *Identity(enum TOK op, Type *type, Expression *e1, Expression *e2) } -Expression *Cmp(enum TOK op, Type *type, Expression *e1, Expression *e2) +Expression *Cmp(TOK op, Type *type, Expression *e1, Expression *e2) { Expression *e; Loc loc = e1->loc; dinteger_t n; @@ -1226,7 +1214,7 @@ Expression *Cast(Type *type, Type *to, Expression *e1) } if (e1->op == TOKarrayliteral && typeb == tb) - return e1; + return expType(to, e1); if (e1->isConst() != 1) return EXP_CANT_INTERPRET; @@ -1333,6 +1321,8 @@ Expression *ArrayLength(Type *type, Expression *e1) e = new IntegerExp(loc, dim, type); } + else if (e1->type->toBasetype()->ty == Tsarray) + e = ((TypeSArray *)e1->type->toBasetype())->dim; else e = EXP_CANT_INTERPRET; return e; @@ -1456,12 +1446,12 @@ Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr) StringExp *es; s = mem.malloc((len + 1) * sz); - memcpy((unsigned char *)s, (unsigned char *)es1->string + ilwr * sz, len * sz); - memset((unsigned char *)s + len * sz, 0, sz); + memcpy((utf8_t *)s, (utf8_t *)es1->string + ilwr * sz, len * sz); + memset((utf8_t *)s + len * sz, 0, sz); es = new StringExp(loc, s, len, es1->postfix); es->sz = sz; - es->committed = 1; + es->committed = es1->committed; es->type = type; e = es; } @@ -1499,7 +1489,7 @@ void sliceAssignArrayLiteralFromString(ArrayLiteralExp *existingAE, StringExp *n { size_t newlen = newval->len; size_t sz = newval->sz; - unsigned char *s = (unsigned char *)newval->string; + utf8_t *s = (utf8_t *)newval->string; Type *elemType = existingAE->type->nextOf(); for (size_t j = 0; j < newlen; j++) { @@ -1523,7 +1513,7 @@ void sliceAssignArrayLiteralFromString(ArrayLiteralExp *existingAE, StringExp *n */ void sliceAssignStringFromArrayLiteral(StringExp *existingSE, ArrayLiteralExp *newae, size_t firstIndex) { - unsigned char *s = (unsigned char *)existingSE->string; + utf8_t *s = (utf8_t *)existingSE->string; for (size_t j = 0; j < newae->elements->dim; j++) { unsigned value = (unsigned)((*newae->elements)[j]->toInteger()); @@ -1544,7 +1534,7 @@ void sliceAssignStringFromArrayLiteral(StringExp *existingSE, ArrayLiteralExp *n */ void sliceAssignStringFromString(StringExp *existingSE, StringExp *newstr, size_t firstIndex) { - unsigned char *s = (unsigned char *)existingSE->string; + utf8_t *s = (utf8_t *)existingSE->string; size_t sz = existingSE->sz; assert(sz == newstr->sz); memcpy(s + firstIndex * sz, newstr->string, sz * newstr->len); @@ -1555,8 +1545,8 @@ void sliceAssignStringFromString(StringExp *existingSE, StringExp *newstr, size_ */ int sliceCmpStringWithString(StringExp *se1, StringExp *se2, size_t lo1, size_t lo2, size_t len) { - unsigned char *s1 = (unsigned char *)se1->string; - unsigned char *s2 = (unsigned char *)se2->string; + utf8_t *s1 = (utf8_t *)se1->string; + utf8_t *s2 = (utf8_t *)se2->string; size_t sz = se1->sz; assert(sz == se2->sz); @@ -1568,11 +1558,9 @@ int sliceCmpStringWithString(StringExp *se1, StringExp *se2, size_t lo1, size_t */ int sliceCmpStringWithArray(StringExp *se1, ArrayLiteralExp *ae2, size_t lo1, size_t lo2, size_t len) { - unsigned char *s = (unsigned char *)se1->string; + utf8_t *s = (utf8_t *)se1->string; size_t sz = se1->sz; - int c = 0; - for (size_t j = 0; j < len; j++) { unsigned value = (unsigned)((*ae2->elements)[j + lo2]->toInteger()); @@ -1636,13 +1624,13 @@ Expression *Cat(Type *type, Expression *e1, Expression *e2) (unsigned char *)&v + (sizeof(dinteger_t) - sz), sz); #endif #else - memcpy((unsigned char *)s, &v, sz); + memcpy((utf8_t *)s, &v, sz); #endif else utf_encode(sz, s, v); // Add terminating 0 - memset((unsigned char *)s + len * sz, 0, sz); + memset((utf8_t *)s + len * sz, 0, sz); es = new StringExp(loc, s, len); es->sz = sz; @@ -1696,10 +1684,10 @@ Expression *Cat(Type *type, Expression *e1, Expression *e2) } s = mem.malloc((len + 1) * sz); memcpy(s, es1->string, es1->len * sz); - memcpy((unsigned char *)s + es1->len * sz, es2->string, es2->len * sz); + memcpy((utf8_t *)s + es1->len * sz, es2->string, es2->len * sz); // Add terminating 0 - memset((unsigned char *)s + len * sz, 0, sz); + memset((utf8_t *)s + len * sz, 0, sz); es = new StringExp(loc, s, len); es->sz = sz; @@ -1769,13 +1757,13 @@ Expression *Cat(Type *type, Expression *e1, Expression *e2) (unsigned char *)&v + (sizeof(dinteger_t) - sz), sz); #endif #else - memcpy((unsigned char *)s + (sz * es1->len), &v, sz); + memcpy((utf8_t *)s + (sz * es1->len), &v, sz); #endif else - utf_encode(sz, (unsigned char *)s + (sz * es1->len), v); + utf_encode(sz, (utf8_t *)s + (sz * es1->len), v); // Add terminating 0 - memset((unsigned char *)s + len * sz, 0, sz); + memset((utf8_t *)s + len * sz, 0, sz); es = new StringExp(loc, s, len); es->sz = sz; @@ -1802,12 +1790,12 @@ Expression *Cat(Type *type, Expression *e1, Expression *e2) (unsigned char *)&v + (sizeof(dinteger_t) - sz), sz); #endif #else - memcpy((unsigned char *)s, &v, sz); + memcpy((utf8_t *)s, &v, sz); #endif - memcpy((unsigned char *)s + sz, es2->string, es2->len * sz); + memcpy((utf8_t *)s + sz, es2->string, es2->len * sz); // Add terminating 0 - memset((unsigned char *)s + len * sz, 0, sz); + memset((utf8_t *)s + len * sz, 0, sz); es = new StringExp(loc, s, len); es->sz = sz; @@ -1828,8 +1816,7 @@ Expression *Cat(Type *type, Expression *e1, Expression *e2) if (type->toBasetype()->ty == Tsarray) { - e->type = new TypeSArray(t1->nextOf(), new IntegerExp(loc, es1->elements->dim, Type::tindex)); - e->type = e->type->semantic(loc, NULL); + e->type = TypeSArray::makeType(loc, t1->nextOf(), es1->elements->dim); } else e->type = type; @@ -1853,8 +1840,7 @@ Expression *Cat(Type *type, Expression *e1, Expression *e2) if (type->toBasetype()->ty == Tsarray) { - e->type = new TypeSArray(t1->nextOf(), new IntegerExp(loc, es->elements->dim, Type::tindex)); - e->type = e->type->semantic(loc, NULL); + e->type = TypeSArray::makeType(loc, t1->nextOf(), es->elements->dim); } else e->type = type; @@ -1876,8 +1862,7 @@ Expression *Cat(Type *type, Expression *e1, Expression *e2) if (type->toBasetype()->ty == Tsarray) { - e->type = new TypeSArray(e2->type, new IntegerExp(loc, es1->elements->dim, Type::tindex)); - e->type = e->type->semantic(loc, NULL); + e->type = TypeSArray::makeType(loc, e2->type, es1->elements->dim); } else e->type = type; @@ -1893,8 +1878,7 @@ Expression *Cat(Type *type, Expression *e1, Expression *e2) if (type->toBasetype()->ty == Tsarray) { - e->type = new TypeSArray(e1->type, new IntegerExp(loc, es2->elements->dim, Type::tindex)); - e->type = e->type->semantic(loc, NULL); + e->type = TypeSArray::makeType(loc, e1->type, es2->elements->dim); } else e->type = type; diff --git a/dmd2/cppmangle.c b/dmd2/cppmangle.c index 686d61bd..42eef23e 100644 --- a/dmd2/cppmangle.c +++ b/dmd2/cppmangle.c @@ -129,16 +129,24 @@ void cpp_mangle_name(OutBuffer *buf, CppMangleState *cms, Dsymbol *s) buf->writeByte('N'); FuncDeclaration *fd = s->isFuncDeclaration(); - if (!fd) + VarDeclaration *vd = s->isVarDeclaration(); + if (fd && fd->type->isConst()) { - s->error("C++ static variables not supported"); - } - else if (fd->type->isConst()) buf->writeByte('K'); - - prefix_name(buf, cms, p); - source_name(buf, s); - + } + if (vd && !(vd->storage_class & (STCextern | STCgshared))) + { + s->error("C++ static non- __gshared non-extern variables not supported"); + } + if (vd || fd) + { + prefix_name(buf, cms, p); + source_name(buf, s); + } + else + { + assert(0); + } buf->writeByte('E'); } else @@ -337,7 +345,7 @@ void TypeFunction::toCppMangle(OutBuffer *buf, CppMangleState *cms) TypeFunctions for non-static member functions, and non-static member functions of different classes. */ - if (!cms->substitute(buf, this)) + if (!cms->exist(this)) { buf->writeByte('F'); if (linkage == LINKc) @@ -345,7 +353,10 @@ void TypeFunction::toCppMangle(OutBuffer *buf, CppMangleState *cms) next->toCppMangle(buf, cms); Parameter::argsCppMangle(buf, cms, parameters, varargs); buf->writeByte('E'); + cms->store(this); } + else + cms->substitute(buf, this); } @@ -417,7 +428,7 @@ static int argsCppMangleDg(void *ctx, size_t n, Parameter *arg) { ArgsCppMangleCtx *p = (ArgsCppMangleCtx *)ctx; - Type *t = arg->type; + Type *t = arg->type->merge2(); if (arg->storageClass & (STCout | STCref)) t = t->referenceTo(); else if (arg->storageClass & STClazy) diff --git a/dmd2/ctfe.h b/dmd2/ctfe.h index 7dc157c3..975778a3 100644 --- a/dmd2/ctfe.h +++ b/dmd2/ctfe.h @@ -30,18 +30,13 @@ struct CtfeStatus static int numAssignments; // total number of assignments executed }; - -/** Expression subclasses which only exist in CTFE */ - -#define TOKclassreference ((TOK)(TOKMAX+1)) -#define TOKthrownexception ((TOK)(TOKMAX+2)) - /** A reference to a class, or an interface. We need this when we point to a base class (we must record what the type is). */ -struct ClassReferenceExp : Expression +class ClassReferenceExp : public Expression { +public: StructLiteralExp *value; ClassReferenceExp(Loc loc, StructLiteralExp *lit, Type *type); Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); @@ -73,8 +68,9 @@ int findFieldIndexByName(StructDeclaration *sd, VarDeclaration *v); /** An uninitialized value */ -struct VoidInitExp : Expression +class VoidInitExp : public Expression { +public: VarDeclaration *var; VoidInitExp(VarDeclaration *var, Type *type); @@ -86,8 +82,9 @@ struct VoidInitExp : Expression /** Fake class which holds the thrown exception. Used for implementing exception handling. */ -struct ThrownExceptionExp : Expression +class ThrownExceptionExp : public Expression { +public: ClassReferenceExp *thrown; // the thing being tossed ThrownExceptionExp(Loc loc, ClassReferenceExp *victim); Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); @@ -186,11 +183,11 @@ Expression *pointerDifference(Loc loc, Type *type, Expression *e1, Expression *e /// Return 1 if true, 0 if false /// -1 if comparison is illegal because they point to non-comparable memory blocks -int comparePointers(Loc loc, enum TOK op, Type *type, Expression *agg1, dinteger_t ofs1, Expression *agg2, dinteger_t ofs2); +int comparePointers(Loc loc, TOK op, Type *type, Expression *agg1, dinteger_t ofs1, Expression *agg2, dinteger_t ofs2); // Return eptr op e2, where eptr is a pointer, e2 is an integer, // and op is TOKadd or TOKmin -Expression *pointerArithmetic(Loc loc, enum TOK op, Type *type, +Expression *pointerArithmetic(Loc loc, TOK op, Type *type, Expression *eptr, Expression *e2); // True if conversion from type 'from' to 'to' involves a reinterpret_cast @@ -235,13 +232,13 @@ void intBinary(TOK op, IntegerExp *dest, Type *type, IntegerExp *e1, IntegerExp bool isCtfeComparable(Expression *e); /// Evaluate ==, !=. Resolves slices before comparing. Returns 0 or 1 -int ctfeEqual(Loc loc, enum TOK op, Expression *e1, Expression *e2); +int ctfeEqual(Loc loc, TOK op, Expression *e1, Expression *e2); /// Evaluate is, !is. Resolves slices before comparing. Returns 0 or 1 -int ctfeIdentity(Loc loc, enum TOK op, Expression *e1, Expression *e2); +int ctfeIdentity(Loc loc, TOK op, Expression *e1, Expression *e2); /// Evaluate >,<=, etc. Resolves slices before comparing. Returns 0 or 1 -int ctfeCmp(Loc loc, enum TOK op, Expression *e1, Expression *e2); +int ctfeCmp(Loc loc, TOK op, Expression *e1, Expression *e2); /// Returns e1 ~ e2. Resolves slices before concatenation. Expression *ctfeCat(Type *type, Expression *e1, Expression *e2); diff --git a/dmd2/ctfeexpr.c b/dmd2/ctfeexpr.c index 3ca582d6..d0819e36 100644 --- a/dmd2/ctfeexpr.c +++ b/dmd2/ctfeexpr.c @@ -156,8 +156,10 @@ char *ThrownExceptionExp::toChars() // Generate an error message when this exception is not caught void ThrownExceptionExp::generateUncaughtError() { - thrown->error("Uncaught CTFE exception %s(%s)", thrown->type->toChars(), - thrown->value->elements->tdata()[0]->toChars()); + Expression *e = (*thrown->value->elements)[0]; + StringExp* se = e->toString(); + thrown->error("Uncaught CTFE exception %s(%s)", thrown->type->toChars(), se ? se->toChars() : e->toChars()); + /* Also give the line where the throw statement was. We won't have it * in the case where the ThrowStatement is generated internally * (eg, in ScopeStatement) @@ -170,6 +172,8 @@ void ThrownExceptionExp::generateUncaughtError() // True if 'e' is EXP_CANT_INTERPRET, or an exception bool exceptionOrCantInterpret(Expression *e) { + assert(EXP_CANT_INTERPRET && "EXP_CANT_INTERPRET must be distinct from " + "null, Expression::init not called?"); if (e == EXP_CANT_INTERPRET) return true; if (!e || e == EXP_GOTO_INTERPRET || e == EXP_VOID_INTERPRET || e == EXP_BREAK_INTERPRET || e == EXP_CONTINUE_INTERPRET) @@ -225,7 +229,7 @@ Expressions *copyLiteralArray(Expressions *oldelems) Expressions *newelems = new Expressions(); newelems->setDim(oldelems->dim); for (size_t i = 0; i < oldelems->dim; i++) - newelems->tdata()[i] = copyLiteral(oldelems->tdata()[i]); + (*newelems)[i] = copyLiteral((*oldelems)[i]); return newelems; } @@ -236,8 +240,7 @@ Expression *copyLiteral(Expression *e) if (e->op == TOKstring) // syntaxCopy doesn't make a copy for StringExp! { StringExp *se = (StringExp *)e; - unsigned char *s; - s = (unsigned char *)mem.calloc(se->len + 1, se->sz); + utf8_t *s = (utf8_t *)mem.calloc(se->len + 1, se->sz); memcpy(s, se->string, se->len * se->sz); StringExp *se2 = new StringExp(se->loc, s, se->len); se2->committed = se->committed; @@ -277,7 +280,7 @@ Expression *copyLiteral(Expression *e) newelems->setDim(oldelems->dim); for (size_t i = 0; i < newelems->dim; i++) { - Expression *m = oldelems->tdata()[i]; + Expression *m = (*oldelems)[i]; // We need the struct definition to detect block assignment AggregateDeclaration *sd = se->sd; Dsymbol *s = sd->fields[i]; @@ -297,7 +300,7 @@ Expression *copyLiteral(Expression *e) } else if (v->type->ty != Tarray && v->type->ty!=Taarray) // NOTE: do not copy array references m = copyLiteral(m); - newelems->tdata()[i] = m; + (*newelems)[i] = m; } #if DMDV2 StructLiteralExp *r = new StructLiteralExp(e->loc, se->sd, newelems, se->stype); @@ -328,12 +331,12 @@ Expression *copyLiteral(Expression *e) else if (e->op == TOKindex) r = new IndexExp(e->loc, ((IndexExp *)e)->e1, ((IndexExp *)e)->e2); else if (e->op == TOKdotvar) - r = new DotVarExp(e->loc, ((DotVarExp *)e)->e1, - ((DotVarExp *)e)->var #if DMDV2 - , ((DotVarExp *)e)->hasOverloads + r = new DotVarExp(e->loc, ((DotVarExp *)e)->e1, + ((DotVarExp *)e)->var, ((DotVarExp *)e)->hasOverloads); +#else + r = new DotVarExp(e->loc, ((DotVarExp *)e)->e1, ((DotVarExp *)e)->var); #endif - ); else assert(0); r->type = e->type; @@ -348,6 +351,8 @@ Expression *copyLiteral(Expression *e) } else if (e->op == TOKclassreference) return new ClassReferenceExp(e->loc, ((ClassReferenceExp *)e)->value, e->type); + else if (e->op == TOKerror) + return e; else { e->error("Internal Compiler Error: CTFE literal %s", e->toChars()); @@ -364,8 +369,13 @@ Expression *copyLiteral(Expression *e) */ Expression *paintTypeOntoLiteral(Type *type, Expression *lit) { - if (lit->type == type) + if (lit->type->equals(type)) return lit; + + // If it is a cast to inout, retain the original type. + if (type->hasWild()) + return lit; + Expression *e; if (lit->op == TOKslice) { @@ -455,6 +465,13 @@ ArrayLiteralExp *createBlockDuplicatedArrayLiteral(Loc loc, Type *type, { Expressions *elements = new Expressions(); elements->setDim(dim); + if (type->ty == Tsarray && type->nextOf()->ty == Tsarray && + elem->type->ty != Tsarray) + { + // If it is a multidimensional array literal, do it recursively + elem = createBlockDuplicatedArrayLiteral(loc, type->nextOf(), elem, + ((TypeSArray *)type->nextOf())->dim->toInteger()); + } bool mustCopy = needToCopyLiteral(elem); for (size_t i = 0; i < dim; i++) { if (mustCopy) @@ -474,8 +491,7 @@ ArrayLiteralExp *createBlockDuplicatedArrayLiteral(Loc loc, Type *type, StringExp *createBlockDuplicatedStringLiteral(Loc loc, Type *type, unsigned value, size_t dim, int sz) { - unsigned char *s; - s = (unsigned char *)mem.calloc(dim + 1, sz); + utf8_t *s = (utf8_t *)mem.calloc(dim + 1, sz); for (size_t elemi = 0; elemi < dim; ++elemi) { switch (sz) @@ -526,7 +542,7 @@ TypeAArray *toBuiltinAAType(Type *t) assert(sym->ident == Id::AssociativeArray); TemplateInstance *tinst = sym->parent->isTemplateInstance(); assert(tinst); - return new TypeAArray((Type *)(tinst->tiargs->tdata()[1]), (Type *)(tinst->tiargs->tdata()[0])); + return new TypeAArray((Type *)(*tinst->tiargs)[1], (Type *)(*tinst->tiargs)[0]); #else assert(0); return NULL; @@ -539,8 +555,8 @@ TypeAArray *toBuiltinAAType(Type *t) bool isTypeInfo_Class(Type *type) { return type->ty == Tclass && - (( Type::typeinfo == ((TypeClass*)type)->sym) - || Type::typeinfo->isBaseOf(((TypeClass*)type)->sym, NULL)); + (( Type::dtypeinfo == ((TypeClass*)type)->sym) + || Type::dtypeinfo->isBaseOf(((TypeClass*)type)->sym, NULL)); } /************** Pointer operations ************************************/ @@ -564,20 +580,36 @@ int isTrueBool(Expression *e) * destPointee may be void. */ bool isSafePointerCast(Type *srcPointee, Type *destPointee) -{ // It's OK if both are the same (modulo const) +{ + // It's safe to cast S** to D** if it's OK to cast S* to D* + while (srcPointee->ty == Tpointer && destPointee->ty == Tpointer) + { + srcPointee = srcPointee->nextOf(); + destPointee = destPointee->nextOf(); + } + #if DMDV2 - if (srcPointee->castMod(0) == destPointee->castMod(0)) - return true; -#else + // It's OK if both are the same (modulo const) + srcPointee = srcPointee->castMod(0); + destPointee = destPointee->castMod(0); +#endif if (srcPointee == destPointee) return true; -#endif + + // It's OK if function pointers differ only in safe/pure/nothrow + if (srcPointee->ty == Tfunction && destPointee->ty == Tfunction) + return srcPointee->covariant(destPointee) == 1; + // it's OK to cast to void* if (destPointee->ty == Tvoid) return true; - // It's OK if they are the same size integers, eg int* and uint* - return srcPointee->isintegral() && destPointee->isintegral() - && srcPointee->size() == destPointee->size(); + + // It's OK if they are the same size (static array of) integers, eg: + // int* --> uint* + // int[5][] --> uint[5][] + return srcPointee->baseElemOf()->isintegral() && + destPointee->baseElemOf()->isintegral() && + srcPointee->size() == destPointee->size(); } Expression *getAggregateFromPointer(Expression *e, dinteger_t *ofs) @@ -599,7 +631,7 @@ Expression *getAggregateFromPointer(Expression *e, dinteger_t *ofs) i = ((ClassReferenceExp *)ex)->getFieldIndex(e->type, v->offset); else i = se->getFieldIndex(e->type, v->offset); - e = se->elements->tdata()[i]; + e = (*se->elements)[i]; } if (e->op == TOKindex) { @@ -669,7 +701,7 @@ Expression *pointerDifference(Loc loc, Type *type, Expression *e1, Expression *e // Return eptr op e2, where eptr is a pointer, e2 is an integer, // and op is TOKadd or TOKmin -Expression *pointerArithmetic(Loc loc, enum TOK op, Type *type, +Expression *pointerArithmetic(Loc loc, TOK op, Type *type, Expression *eptr, Expression *e2) { if (eptr->type->nextOf()->ty == Tvoid) @@ -749,14 +781,12 @@ Expression *pointerArithmetic(Loc loc, enum TOK op, Type *type, // Return 1 if true, 0 if false // -1 if comparison is illegal because they point to non-comparable memory blocks -int comparePointers(Loc loc, enum TOK op, Type *type, Expression *agg1, dinteger_t ofs1, +int comparePointers(Loc loc, TOK op, Type *type, Expression *agg1, dinteger_t ofs1, Expression *agg2, dinteger_t ofs2) { if ( pointToSameMemoryBlock(agg1, agg2) ) { - dinteger_t cm = ofs1 - ofs2; dinteger_t n; - dinteger_t zero = 0; switch(op) { case TOKlt: n = (ofs1 < ofs2); break; @@ -790,6 +820,8 @@ int comparePointers(Loc loc, enum TOK op, Type *type, Expression *agg1, dinteger case TOKnotequal: cmp = (null1 == null2); break; + default: + assert(0); } } else @@ -844,7 +876,7 @@ Expression *paintFloatInt(Expression *fromVal, Type *to) if (to->isintegral()) { u.f = fromVal->toReal(); - return new IntegerExp(fromVal->loc, ldouble(u.x), to); + return new IntegerExp(fromVal->loc, (dinteger_t)ldouble(u.x), to); } else { @@ -887,6 +919,9 @@ void intUnary(TOK op, IntegerExp *e) case TOKtilde: e->value = ~e->value; break; + default: + assert(0); + break; } } @@ -1089,6 +1124,8 @@ bool isCtfeComparable(Expression *e) if (x->isConst() != 1 && x->op != TOKnull && x->op != TOKstring && + x->op != TOKfunction && + x->op != TOKdelegate && x->op != TOKarrayliteral && x->op != TOKstructliteral && x->op != TOKclassreference) @@ -1244,16 +1281,16 @@ int ctfeCmpArrays(Loc loc, Expression *e1, Expression *e2, uinteger_t len) { lo1 = ((SliceExp *)x)->lwr->toInteger(); x = ((SliceExp*)x)->e1; } - StringExp *se1 = (x->op == TOKstring) ? (StringExp *)x : 0; - ArrayLiteralExp *ae1 = (x->op == TOKarrayliteral) ? (ArrayLiteralExp *)x : 0; + StringExp *se1 = (x->op == TOKstring) ? (StringExp *)x : NULL; + ArrayLiteralExp *ae1 = (x->op == TOKarrayliteral) ? (ArrayLiteralExp *)x : NULL; x = e2; if (x->op == TOKslice) { lo2 = ((SliceExp *)x)->lwr->toInteger(); x = ((SliceExp*)x)->e1; } - StringExp *se2 = (x->op == TOKstring) ? (StringExp *)x : 0; - ArrayLiteralExp *ae2 = (x->op == TOKarrayliteral) ? (ArrayLiteralExp *)x : 0; + StringExp *se2 = (x->op == TOKstring) ? (StringExp *)x : NULL; + ArrayLiteralExp *ae2 = (x->op == TOKarrayliteral) ? (ArrayLiteralExp *)x : NULL; // Now both must be either TOKarrayliteral or TOKstring if (se1 && se2) @@ -1286,6 +1323,21 @@ int ctfeCmpArrays(Loc loc, Expression *e1, Expression *e2, uinteger_t len) return 0; } +/* Given a delegate expression e, return .funcptr. + * If e is NullExp, return NULL. + */ +FuncDeclaration *funcptrOf(Expression *e) +{ + assert(e->type->ty == Tdelegate); + + if (e->op == TOKdelegate) + return ((DelegateExp *)e)->func; + if (e->op == TOKfunction) + return ((FuncExp *)e)->fd; + assert(e->op == TOKnull); + return NULL; +} + bool isArray(Expression *e) { return e->op == TOKarrayliteral || e->op == TOKstring || @@ -1303,13 +1355,16 @@ int ctfeRawCmp(Loc loc, Expression *e1, Expression *e2) return 0; return 1; } + + // null == null, regardless of type + if (e1->op == TOKnull && e2->op == TOKnull) return 0; if (e1->type->ty == Tpointer && e2->type->ty == Tpointer) - { // Can only be an equality test. - if (e1->op == TOKnull && e2->op == TOKnull) - return 0; + { + // Can only be an equality test. + dinteger_t ofs1, ofs2; Expression *agg1 = getAggregateFromPointer(e1, &ofs1); Expression *agg2 = getAggregateFromPointer(e2, &ofs2); @@ -1320,6 +1375,35 @@ int ctfeRawCmp(Loc loc, Expression *e1, Expression *e2) } return 1; } + if (e1->type->ty == Tdelegate && e2->type->ty == Tdelegate) + { + // If .funcptr isn't the same, they are not equal + + if (funcptrOf(e1) != funcptrOf(e2)) + return 1; + + // If both are delegate literals, assume they have the + // same closure pointer. TODO: We don't support closures yet! + if (e1->op == TOKfunction && e2->op == TOKfunction) + return 0; + assert(e1->op == TOKdelegate && e2->op == TOKdelegate); + + // Same .funcptr. Do they have the same .ptr? + Expression * ptr1 = ((DelegateExp *)e1)->e1; + Expression * ptr2 = ((DelegateExp *)e2)->e1; + + dinteger_t ofs1, ofs2; + Expression *agg1 = getAggregateFromPointer(ptr1, &ofs1); + Expression *agg2 = getAggregateFromPointer(ptr2, &ofs2); + // If they are TOKvar, it means they are FuncDeclarations + if ((agg1 == agg2 && ofs1 == ofs2) || + (agg1->op == TOKvar && agg2->op == TOKvar && + ((VarExp *)agg1)->var == ((VarExp *)agg2)->var)) + { + return 0; + } + return 1; + } if (isArray(e1) && isArray(e2)) { uinteger_t len1 = resolveArrayLength(e1); @@ -1409,7 +1493,7 @@ int ctfeRawCmp(Loc loc, Expression *e1, Expression *e2) /// Evaluate ==, !=. Resolves slices before comparing. Returns 0 or 1 -int ctfeEqual(Loc loc, enum TOK op, Expression *e1, Expression *e2) +int ctfeEqual(Loc loc, TOK op, Expression *e1, Expression *e2) { int cmp = !ctfeRawCmp(loc, e1, e2); if (op == TOKnotequal) @@ -1419,7 +1503,7 @@ int ctfeEqual(Loc loc, enum TOK op, Expression *e1, Expression *e2) /// Evaluate is, !is. Resolves slices before comparing. Returns 0 or 1 -int ctfeIdentity(Loc loc, enum TOK op, Expression *e1, Expression *e2) +int ctfeIdentity(Loc loc, TOK op, Expression *e1, Expression *e2) { int cmp; if (e1->op == TOKnull) @@ -1456,7 +1540,7 @@ int ctfeIdentity(Loc loc, enum TOK op, Expression *e1, Expression *e2) /// Evaluate >,<=, etc. Resolves slices before comparing. Returns 0 or 1 -int ctfeCmp(Loc loc, enum TOK op, Expression *e1, Expression *e2) +int ctfeCmp(Loc loc, TOK op, Expression *e1, Expression *e2) { int n; Type *t1 = e1->type->toBasetype(); @@ -1522,7 +1606,8 @@ Expression *ctfeCat(Type *type, Expression *e1, Expression *e2) void *s = mem.malloc((len + 1) * sz); memcpy((char *)s + sz * es2->elements->dim, es1->string, es1->len * sz); for (size_t i = 0; i < es2->elements->dim; i++) - { Expression *es2e = es2->elements->tdata()[i]; + { + Expression *es2e = (*es2->elements)[i]; if (es2e->op != TOKint64) return EXP_CANT_INTERPRET; dinteger_t v = es2e->toInteger(); @@ -1534,12 +1619,12 @@ Expression *ctfeCat(Type *type, Expression *e1, Expression *e2) (unsigned char *)&v + (sizeof(dinteger_t) - sz), sz); #endif #else - memcpy((unsigned char *)s + i * sz, &v, sz); + memcpy((utf8_t *)s + i * sz, &v, sz); #endif } // Add terminating 0 - memset((unsigned char *)s + len * sz, 0, sz); + memset((utf8_t *)s + len * sz, 0, sz); StringExp *es = new StringExp(loc, s, len); es->sz = sz; @@ -1561,7 +1646,8 @@ Expression *ctfeCat(Type *type, Expression *e1, Expression *e2) void *s = mem.malloc((len + 1) * sz); memcpy(s, es1->string, es1->len * sz); for (size_t i = 0; i < es2->elements->dim; i++) - { Expression *es2e = es2->elements->tdata()[i]; + { + Expression *es2e = (*es2->elements)[i]; if (es2e->op != TOKint64) return EXP_CANT_INTERPRET; dinteger_t v = es2e->toInteger(); @@ -1573,12 +1659,12 @@ Expression *ctfeCat(Type *type, Expression *e1, Expression *e2) (unsigned char *) &v + (sizeof(dinteger_t) - sz), sz); #endif #else - memcpy((unsigned char *)s + (es1->len + i) * sz, &v, sz); + memcpy((utf8_t *)s + (es1->len + i) * sz, &v, sz); #endif } // Add terminating 0 - memset((unsigned char *)s + len * sz, 0, sz); + memset((utf8_t *)s + len * sz, 0, sz); StringExp *es = new StringExp(loc, s, len); es->sz = sz; @@ -1587,6 +1673,32 @@ Expression *ctfeCat(Type *type, Expression *e1, Expression *e2) e = es; return e; } + else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral && + t1->nextOf()->equals(t2->nextOf())) + { + // [ e1 ] ~ [ e2 ] ---> [ e1, e2 ] + ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; + ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; + + es1 = new ArrayLiteralExp(es1->loc, copyLiteralArray(es1->elements)); + es1->elements->insert(es1->elements->dim, copyLiteralArray(es2->elements)); + e = es1; + e->type = type; + return e; + } + else if (e1->op == TOKarrayliteral && e2->op == TOKnull && + t1->nextOf()->equals(t2->nextOf())) + { + // [ e1 ] ~ null ----> [ e1 ].dup + return paintTypeOntoLiteral(type, copyLiteral(e1)); + } + else if (e1->op == TOKnull && e2->op == TOKarrayliteral && + t1->nextOf()->equals(t2->nextOf())) + { + // null ~ [ e2 ] ----> [ e2 ].dup + return paintTypeOntoLiteral(type, copyLiteral(e2)); + } + return Cat(type, e1, e2); } @@ -1600,11 +1712,11 @@ Expression *findKeyInAA(Loc loc, AssocArrayLiteralExp *ae, Expression *e2) for (size_t i = ae->keys->dim; i;) { i--; - Expression *ekey = ae->keys->tdata()[i]; + Expression *ekey = (*ae->keys)[i]; int eq = ctfeEqual(loc, TOKequal, ekey, e2); if (eq) { - return ae->values->tdata()[i]; + return (*ae->values)[i]; } } return NULL; @@ -1634,7 +1746,7 @@ Expression *ctfeIndex(Loc loc, Type *type, Expression *e1, uinteger_t indx) error(loc, "array index %llu is out of bounds %s[0 .. %llu]", indx, e1->toChars(), (ulonglong)ale->elements->dim); return EXP_CANT_INTERPRET; } - Expression *e = ale->elements->tdata()[indx]; + Expression *e = (*ale->elements)[indx]; return paintTypeOntoLiteral(type, e); } @@ -1654,7 +1766,12 @@ Expression *ctfeCast(Loc loc, Type *type, Type *to, Expression *e) // Allow TypeInfo type painting if (isTypeInfo_Class(e->type) && e->type->implicitConvTo(to)) return paintTypeOntoLiteral(to, e); - +#if DMDV2 + // Allow casting away const for struct literals + if (e->op == TOKstructliteral && + e->type->toBasetype()->castMod(0) == to->toBasetype()->castMod(0)) + return paintTypeOntoLiteral(to, e); +#endif Expression *r = Cast(type, to, e); if (r == EXP_CANT_INTERPRET) error(loc, "cannot cast %s to %s at compile time", e->toChars(), to->toChars()); @@ -1711,8 +1828,8 @@ void assignInPlace(Expression *dest, Expression *src) for (size_t i= 0; i < oldelems->dim; ++i) { - Expression *e = newelems->tdata()[i]; - Expression *o = oldelems->tdata()[i]; + Expression *e = (*newelems)[i]; + Expression *o = (*oldelems)[i]; if (e->op == TOKstructliteral) { assert(o->op == e->op); @@ -1724,7 +1841,7 @@ void assignInPlace(Expression *dest, Expression *src) } else { - oldelems->tdata()[i] = newelems->tdata()[i]; + (*oldelems)[i] = (*newelems)[i]; } } } @@ -1734,10 +1851,10 @@ void recursiveBlockAssign(ArrayLiteralExp *ae, Expression *val, bool wantRef) assert( ae->type->ty == Tsarray || ae->type->ty == Tarray); #if DMDV2 Type *desttype = ((TypeArray *)ae->type)->next->castMod(0); - bool directblk = (val->type->toBasetype()->castMod(0)) == desttype; + bool directblk = (val->type->toBasetype()->castMod(0))->equals(desttype); #else Type *desttype = ((TypeArray *)ae->type)->next; - bool directblk = (val->type->toBasetype()) == desttype; + bool directblk = (val->type->toBasetype())->equals(desttype); #endif bool cow = !(val->op == TOKstructliteral || val->op == TOKarrayliteral @@ -1745,16 +1862,16 @@ void recursiveBlockAssign(ArrayLiteralExp *ae, Expression *val, bool wantRef) for (size_t k = 0; k < ae->elements->dim; k++) { - if (!directblk && ae->elements->tdata()[k]->op == TOKarrayliteral) + if (!directblk && (*ae->elements)[k]->op == TOKarrayliteral) { - recursiveBlockAssign((ArrayLiteralExp *)ae->elements->tdata()[k], val, wantRef); + recursiveBlockAssign((ArrayLiteralExp *)(*ae->elements)[k], val, wantRef); } else { if (wantRef || cow) - ae->elements->tdata()[k] = val; + (*ae->elements)[k] = val; else - assignInPlace(ae->elements->tdata()[k], val); + assignInPlace((*ae->elements)[k], val); } } } @@ -1770,7 +1887,7 @@ Expressions *changeOneElement(Expressions *oldelems, size_t indexToChange, Expre if (j == indexToChange) (*expsx)[j] = newelem; else - (*expsx)[j] = oldelems->tdata()[j]; + (*expsx)[j] = (*oldelems)[j]; } return expsx; } @@ -1801,10 +1918,11 @@ Expression *assignAssocArrayElement(Loc loc, AssocArrayLiteralExp *aae, int updated = 0; for (size_t j = valuesx->dim; j; ) { j--; - Expression *ekey = aae->keys->tdata()[j]; + Expression *ekey = (*aae->keys)[j]; int eq = ctfeEqual(loc, TOKequal, ekey, index); if (eq) - { valuesx->tdata()[j] = newval; + { + (*valuesx)[j] = newval; updated = 1; } } @@ -1838,7 +1956,7 @@ Expression *changeArrayLiteralLength(Loc loc, TypeArray *arrayType, if (oldval->op == TOKstring) { StringExp *oldse = (StringExp *)oldval; - unsigned char *s = (unsigned char *)mem.calloc(newlen + 1, oldse->sz); + utf8_t *s = (utf8_t *)mem.calloc(newlen + 1, oldse->sz); memcpy(s, oldse->string, copylen * oldse->sz); unsigned defaultValue = (unsigned)(defaultElem->toInteger()); for (size_t elemi = copylen; elemi < newlen; ++elemi) @@ -1890,11 +2008,12 @@ Expression *changeArrayLiteralLength(Loc loc, TypeArray *arrayType, bool isCtfeValueValid(Expression *newval) { - if ( #if DMDV2 - newval->type->ty == Tnull || + bool isnull = newval->type->ty == Tnull; +#else + bool isnull = false; #endif - isPointer(newval->type) ) + if (isnull || isPointer(newval->type)) { if (newval->op == TOKaddress || newval->op == TOKnull || newval->op == TOKstring) @@ -1946,8 +2065,19 @@ bool isCtfeValueValid(Expression *newval) if (ie->e2->op == TOKvar) return true; } - if (newval->op == TOKfunction) return true; // function/delegate literal - if (newval->op == TOKdelegate) return true; + + if (newval->op == TOKfunction) + return true; // function literal or delegate literal + + if (newval->op == TOKdelegate) + { + Expression *dge = ((DelegateExp *)newval)->e1; + if (dge->op == TOKvar && ((VarExp *)dge)->var->isFuncDeclaration()) + return true; // &nestedfunc + + if (dge->op == TOKstructliteral || dge->op == TOKclassreference) + return true; // &struct.func or &clasinst.func + } if (newval->op == TOKsymoff) // function pointer { if (((SymOffExp *)newval)->var->isFuncDeclaration()) @@ -1955,6 +2085,7 @@ bool isCtfeValueValid(Expression *newval) if (((SymOffExp *)newval)->var->isDataseg()) return true; // pointer to static variable } + if (newval->op == TOKint64 || newval->op == TOKfloat64 || newval->op == TOKchar || newval->op == TOKcomplex80) return true; diff --git a/dmd2/declaration.c b/dmd2/declaration.c index a266be82..9b3fa956 100644 --- a/dmd2/declaration.c +++ b/dmd2/declaration.c @@ -102,27 +102,27 @@ unsigned Declaration::size(Loc loc) return type->size(); } -int Declaration::isDelete() +bool Declaration::isDelete() { - return FALSE; + return false; } -int Declaration::isDataseg() +bool Declaration::isDataseg() { - return FALSE; + return false; } -int Declaration::isThreadlocal() +bool Declaration::isThreadlocal() { - return FALSE; + return false; } -int Declaration::isCodeseg() +bool Declaration::isCodeseg() { - return FALSE; + return false; } -enum PROT Declaration::prot() +PROT Declaration::prot() { return protection; } @@ -148,7 +148,7 @@ int Declaration::checkModify(Loc loc, Scope *sc, Type *t, Expression *e1, int fl { const char *s = isParameter() && parent->ident != Id::ensure ? "parameter" : "result"; if (!flag) error(loc, "cannot modify %s '%s' in contract", s, toChars()); - return 0; + return 2; // do not report type related errors } } } @@ -184,7 +184,7 @@ TupleDeclaration::TupleDeclaration(Loc loc, Identifier *id, Objects *objects) this->loc = loc; this->type = NULL; this->objects = objects; - this->isexp = 0; + this->isexp = false; this->tupletype = NULL; } @@ -212,7 +212,7 @@ Type *TupleDeclaration::getType() /* It's only a type tuple if all the Object's are types */ for (size_t i = 0; i < objects->dim; i++) - { Object *o = (*objects)[i]; + { RootObject *o = (*objects)[i]; if (o->dyncast() != DYNCAST_TYPE) { @@ -253,11 +253,11 @@ Type *TupleDeclaration::getType() return tupletype; } -int TupleDeclaration::needThis() +bool TupleDeclaration::needThis() { //printf("TupleDeclaration::needThis(%s)\n", toChars()); for (size_t i = 0; i < objects->dim; i++) - { Object *o = (*objects)[i]; + { RootObject *o = (*objects)[i]; if (o->dyncast() == DYNCAST_EXPRESSION) { Expression *e = (Expression *)o; if (e->op == TOKdsymbol) @@ -265,12 +265,12 @@ int TupleDeclaration::needThis() Declaration *d = ve->s->isDeclaration(); if (d && d->needThis()) { - return 1; + return true; } } } } - return 0; + return false; } #if IN_LLVM @@ -279,7 +279,7 @@ void TupleDeclaration::semantic3(Scope *sc) { //printf("TupleDeclaration::semantic3((%s)\n", toChars()); for (size_t i = 0; i < objects->dim; i++) - { Object *o = (Object *)objects->data[i]; + { RootObject *o = (RootObject *)objects->data[i]; if (o->dyncast() == DYNCAST_EXPRESSION) { Expression *e = (Expression *)o; if (e->op == TOKdsymbol) @@ -445,7 +445,7 @@ AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Type *type) this->htype = NULL; this->haliassym = NULL; this->overnext = NULL; - this->inSemantic = 0; + this->inSemantic = false; assert(type); } @@ -461,7 +461,7 @@ AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Dsymbol *s) this->htype = NULL; this->haliassym = NULL; this->overnext = NULL; - this->inSemantic = 0; + this->inSemantic = false; assert(s); } @@ -506,7 +506,7 @@ void AliasDeclaration::semantic(Scope *sc) aliassym->semantic(sc); return; } - this->inSemantic = 1; + this->inSemantic = true; #if DMDV1 // don't really know why this is here if (storage_class & STCconst) @@ -587,7 +587,7 @@ void AliasDeclaration::semantic(Scope *sc) } if (overnext) ScopeDsymbol::multiplyDefined(Loc(), overnext, this); - this->inSemantic = 0; + this->inSemantic = false; if (global.gag && errors != global.errors) type = savedtype; @@ -641,16 +641,16 @@ void AliasDeclaration::semantic(Scope *sc) type = savedtype; overnext = savedovernext; aliassym = NULL; - inSemantic = 0; + inSemantic = false; return; } } //printf("setting aliassym %s to %s %s\n", toChars(), s->kind(), s->toChars()); aliassym = s; - this->inSemantic = 0; + this->inSemantic = false; } -int AliasDeclaration::overloadInsert(Dsymbol *s) +bool AliasDeclaration::overloadInsert(Dsymbol *s) { /* Don't know yet what the aliased symbol is, so assume it can * be overloaded and check later for correctness. @@ -673,10 +673,10 @@ int AliasDeclaration::overloadInsert(Dsymbol *s) { if (s == this) { - return TRUE; + return true; } overnext = s; - return TRUE; + return true; } else { @@ -702,7 +702,13 @@ Dsymbol *AliasDeclaration::toAlias() assert(this != aliassym); //static int count; if (++count == 10) *(char*)0=0; if (inSemantic) - { error("recursive alias declaration"); + { + error("recursive alias declaration"); + + // Avoid breaking "recursive alias" state during errors gagged + if (global.isSpeculativeGagging()) + return this; + aliassym = new AliasDeclaration(loc, ident, Type::terror); type = Type::terror; } @@ -858,6 +864,9 @@ void VarDeclaration::semantic(Scope *sc) // return; // sem = SemanticIn; + if (sem >= SemanticDone) + return; + Scope *scx = NULL; if (scope) { sc = scope; @@ -885,8 +894,8 @@ void VarDeclaration::semantic(Scope *sc) // Infering the type requires running semantic, // so mark the scope as ctfe if required - if (storage_class & (STCmanifest | STCstatic)) - sc->needctfe++; + bool needctfe = (storage_class & (STCmanifest | STCstatic)); + if (needctfe) sc = sc->startCTFE(); //printf("inferring type for %s with init %s\n", toChars(), init->toChars()); ArrayInitializer *ai = init->isArrayInitializer(); @@ -907,10 +916,11 @@ void VarDeclaration::semantic(Scope *sc) type = type->nextOf()->arrayOf(); } else + { type = init->inferType(sc); + } - if (storage_class & (STCmanifest | STCstatic)) - sc->needctfe--; + if (needctfe) sc = sc->endCTFE(); // type = type->semantic(loc, sc); inuse--; @@ -986,9 +996,7 @@ void VarDeclaration::semantic(Scope *sc) FuncDeclaration *fd = parent->isFuncDeclaration(); Type *tb = type->toBasetype(); - Type *tbn = tb; - while (tbn->ty == Tsarray) - tbn = tbn->nextOf()->toBasetype(); + Type *tbn = tb->baseElemOf(); if (tb->ty == Tvoid && !(storage_class & STClazy)) { if (inferred) @@ -1128,7 +1136,8 @@ Lnomatch: } for (size_t i = 0; i < nelems; i++) - { Parameter *arg = Parameter::getNth(tt->arguments, i); + { + Parameter *arg = Parameter::getNth(tt->arguments, i); OutBuffer buf; buf.printf("_%s_field_%llu", ident->toChars(), (ulonglong)i); @@ -1136,20 +1145,24 @@ Lnomatch: const char *name = (const char *)buf.extractData(); Identifier *id = Lexer::idPool(name); - Expression *einit = ie; - if (ie && ie->op == TOKtuple) + Initializer *ti; + if (ie) { - TupleExp *te = (TupleExp *)ie; - einit = (*te->exps)[i]; - if (i == 0) - einit = Expression::combine(te->e0, einit); - } - Initializer *ti = init; - if (einit) - { ti = new ExpInitializer(einit->loc, einit); + Expression *einit = ie; + if (ie->op == TOKtuple) + { + TupleExp *te = (TupleExp *)ie; + einit = (*te->exps)[i]; + if (i == 0) + einit = Expression::combine(te->e0, einit); + } + ti = new ExpInitializer(einit->loc, einit); } + else + ti = init ? init->syntaxCopy() : NULL; VarDeclaration *v = new VarDeclaration(loc, arg->type, id, ti); + v->storage_class |= storage_class; if (arg->storageClass & STCparameter) v->storage_class |= arg->storageClass; //printf("declaring field %s of type %s\n", v->toChars(), v->type->toChars()); @@ -1169,7 +1182,7 @@ Lnomatch: } TupleDeclaration *v2 = new TupleDeclaration(loc, ident, exps); v2->parent = this->parent; - v2->isexp = 1; + v2->isexp = true; aliassym = v2; return; } @@ -1227,8 +1240,17 @@ Lnomatch: { const char *p = loc.toChars(); const char *s = (storage_class & STCimmutable) ? "immutable" : "const"; - fprintf(stderr, "%s: %s.%s is %s field\n", p ? p : "", ad->toPrettyChars(), toChars(), s); + fprintf(global.stdmsg, "%s: %s.%s is %s field\n", p ? p : "", ad->toPrettyChars(), toChars(), s); } + storage_class |= STCfield; +#if DMDV2 + if (tbn->ty == Tstruct && ((TypeStruct *)tbn)->sym->noDefaultCtor || + tbn->ty == Tclass && ((TypeClass *)tbn)->sym->noDefaultCtor) + { + if (!isThisDeclaration()) + aad->noDefaultCtor = TRUE; + } +#endif #else if (storage_class & (STCconst | STCimmutable) && init) { @@ -1239,15 +1261,18 @@ Lnomatch: storage_class |= STCstatic; } else -#endif { storage_class |= STCfield; #if DMDV2 - if (tbn->ty == Tstruct && ((TypeStruct *)tbn)->sym->noDefaultCtor || - tbn->ty == Tclass && ((TypeClass *)tbn)->sym->noDefaultCtor) - aad->noDefaultCtor = TRUE; + if ((tbn->ty == Tstruct && ((TypeStruct *)tbn)->sym->noDefaultCtor) || + (tbn->ty == Tclass && ((TypeClass *)tbn)->sym->noDefaultCtor)) + { + if (!isThisDeclaration()) + aad->noDefaultCtor = TRUE; + } #endif } +#endif } InterfaceDeclaration *id = parent->isInterfaceDeclaration(); @@ -1300,25 +1325,35 @@ Lnomatch: { if (func->fes) func = func->fes->func; - if (!((TypeFunction *)func->type)->iswild) + bool isWild = false; + for (FuncDeclaration *fd = func; fd; fd = fd->toParent2()->isFuncDeclaration()) + { + if (((TypeFunction *)fd->type)->iswild) + { + isWild = true; + break; + } + } + if (!isWild) { error("inout variables can only be declared inside inout functions"); } } } - if (!(storage_class & (STCctfe | STCref)) && tbn->ty == Tstruct && + if (!(storage_class & (STCctfe | STCref | STCresult)) && tbn->ty == Tstruct && ((TypeStruct *)tbn)->sym->noDefaultCtor) { if (!init) - { if (isField()) + { + if (isField()) /* For fields, we'll check the constructor later to make sure it is initialized */ storage_class |= STCnodefaultctor; else if (storage_class & STCparameter) ; else - error("initializer required for type %s", type->toChars()); + error("default construction is disabled for type %s", type->toChars()); } } #endif @@ -1347,7 +1382,7 @@ Lnomatch: else if (storage_class & STCmanifest) error("manifest constants must have initializers"); - enum TOK op = TOKconstruct; + TOK op = TOKconstruct; if (!init && !sc->inunion && !(storage_class & (STCstatic | STCgshared | STCextern)) && fd && (!(storage_class & (STCfield | STCin | STCforeach | STCparameter | STCresult)) || (storage_class & STCout)) && @@ -1423,7 +1458,6 @@ Lnomatch: init = new ExpInitializer(e->loc, e); } - StructInitializer *si = init->isStructInitializer(); ExpInitializer *ei = init->isExpInitializer(); if (ei && isScope()) @@ -1492,7 +1526,7 @@ Lnomatch: if (t->ty != Tsarray) break; dim *= ((TypeSArray *)t)->dim->toInteger(); - e1->type = new TypeSArray(t->nextOf(), new IntegerExp(Loc(), dim, Type::tindex)); + e1->type = TypeSArray::makeType(Loc(), t->nextOf(), dim); } } e1 = new SliceExp(loc, e1, NULL, NULL); @@ -1641,20 +1675,21 @@ Lnomatch: * Ignore failure. */ - if (!global.errors && !inferred) + if (!inferred) { unsigned errors = global.errors; inuse++; #if DMDV2 if (ei) { - Expression *exp; - exp = ei->exp->syntaxCopy(); - if (isDataseg() || (storage_class & STCmanifest)) - exp = exp->ctfeSemantic(sc); - else - exp = exp->semantic(sc); + Expression *exp = ei->exp->syntaxCopy(); + + bool needctfe = isDataseg() || (storage_class & STCmanifest); + if (needctfe) sc = sc->startCTFE(); + exp = exp->semantic(sc); exp = resolveProperties(sc, exp); + if (needctfe) sc = sc->endCTFE(); + Type *tb = type->toBasetype(); Type *ti = exp->type->toBasetype(); @@ -1670,30 +1705,17 @@ Lnomatch: * because the postblit doesn't get run on the initialization of w. */ if (ti->ty == Tstruct) - { StructDeclaration *sd = ((TypeStruct *)ti)->sym; + { + StructDeclaration *sd = ((TypeStruct *)ti)->sym; /* Look to see if initializer involves a copy constructor * (which implies a postblit) */ if (sd->cpctor && // there is a copy constructor - tb->equals(ti)) // rvalue is the same struct + tb->toDsymbol(NULL) == sd) // exp is the same struct { // The only allowable initializer is a (non-copy) constructor - if (exp->op == TOKcall) - { - CallExp *ce = (CallExp *)exp; - if (ce->e1->op == TOKdotvar) - { - DotVarExp *dve = (DotVarExp *)ce->e1; - if (dve->var->isCtorDeclaration()) - goto LNoCopyConstruction; - } - } - global.gag--; - error("of type struct %s uses this(this), which is not allowed in static initialization", tb->toChars()); - global.gag++; - - LNoCopyConstruction: - ; + if (exp->isLvalue()) + error("of type struct %s uses this(this), which is not allowed in static initialization", tb->toChars()); } } ei->exp = exp; @@ -1722,7 +1744,10 @@ Ldtor: edtor = callScopeDtor(sc); if (edtor) { - edtor = edtor->semantic(sc); + if (sc->func && storage_class & (STCstatic | STCgshared)) + edtor = edtor->semantic(sc->module->scope); + else + edtor = edtor->semantic(sc); #if 0 // currently disabled because of std.stdio.stdin, stdout and stderr if (isDataseg() && !(storage_class & STCextern)) @@ -1838,7 +1863,7 @@ void VarDeclaration::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, TupleDeclaration *v2 = aliassym->isTupleDeclaration(); assert(v2); for (size_t i = 0; i < v2->objects->dim; i++) - { Object *o = (*v2->objects)[i]; + { RootObject *o = (*v2->objects)[i]; assert(o->dyncast() == DYNCAST_EXPRESSION); Expression *e = (Expression *)o; assert(e->op == TOKdsymbol); @@ -1871,11 +1896,7 @@ void VarDeclaration::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, } if (t->ty == Tstruct || t->ty == Tsarray) { - Type *tv = t; - while (tv->ty == Tsarray) - { - tv = tv->nextOf()->toBasetype(); - } + Type *tv = t->baseElemOf(); if (tv->ty == Tstruct) { TypeStruct *ts = (TypeStruct *)tv; @@ -1985,23 +2006,23 @@ AggregateDeclaration *VarDeclaration::isThis() return ad; } -int VarDeclaration::needThis() +bool VarDeclaration::needThis() { //printf("VarDeclaration::needThis(%s, x%x)\n", toChars(), storage_class); return isField(); } -int VarDeclaration::isExport() +bool VarDeclaration::isExport() { return protection == PROTexport; } -int VarDeclaration::isImportedSymbol() +bool VarDeclaration::isImportedSymbol() { if (protection == PROTexport && !init && (storage_class & STCstatic || parent->isModule())) - return TRUE; - return FALSE; + return true; + return false; } void VarDeclaration::checkCtorConstInit() @@ -2066,7 +2087,7 @@ void VarDeclaration::checkNestedReference(Scope *sc, Loc loc) * See: compilable/testInference.d */ if (type->isMutable() || // mutable variable - !type->implicitConvTo(type->invariantOf()) || // has any mutable indirections + !type->implicitConvTo(type->immutableOf()) || // has any mutable indirections !fdv->isPureBypassingInference()) // does not belong to pure function { fld->setImpure(); // Bugzilla 9415 @@ -2138,7 +2159,7 @@ Expression *VarDeclaration::getConstInitializer(bool needFullType) if (scope) { inuse++; - init->semantic(scope, type, INITinterpret); + init = init->semantic(scope, type, INITinterpret); scope = NULL; inuse--; } @@ -2149,10 +2170,10 @@ Expression *VarDeclaration::getConstInitializer(bool needFullType) } /************************************* - * Return !=0 if we can take the address of this variable. + * Return true if we can take the address of this variable. */ -int VarDeclaration::canTakeAddressOf() +bool VarDeclaration::canTakeAddressOf() { #if 0 /* Global variables and struct/class fields of the form: @@ -2166,13 +2187,13 @@ int VarDeclaration::canTakeAddressOf() type->toBasetype()->isTypeBasic() ) { - return 0; + return false; } #else if (storage_class & STCmanifest) - return 0; + return false; #endif - return 1; + return true; } @@ -2181,7 +2202,7 @@ int VarDeclaration::canTakeAddressOf() * Includes extern variables. */ -int VarDeclaration::isDataseg() +bool VarDeclaration::isDataseg() { #if 0 printf("VarDeclaration::isDataseg(%p, '%s')\n", this, toChars()); @@ -2189,12 +2210,12 @@ int VarDeclaration::isDataseg() printf("parent = '%s'\n", parent->toChars()); #endif if (storage_class & STCmanifest) - return 0; + return false; Dsymbol *parent = this->toParent(); if (!parent && !(storage_class & STCstatic)) { error("forward referenced"); type = Type::terror; - return 0; + return false; } return canTakeAddressOf() && (storage_class & (STCstatic | STCextern | STCtls | STCgshared) || @@ -2206,7 +2227,7 @@ int VarDeclaration::isDataseg() * Does symbol go into thread local storage? */ -int VarDeclaration::isThreadlocal() +bool VarDeclaration::isThreadlocal() { //printf("VarDeclaration::isThreadlocal(%p, '%s')\n", this, toChars()); #if 0 //|| TARGET_OSX @@ -2219,7 +2240,7 @@ int VarDeclaration::isThreadlocal() /* Data defaults to being thread-local. It is not thread-local * if it is immutable, const or shared. */ - int i = isDataseg() && + bool i = isDataseg() && !(storage_class & (STCimmutable | STCconst | STCshared | STCgshared)); //printf("\treturn %d\n", i); return i; @@ -2230,29 +2251,29 @@ int VarDeclaration::isThreadlocal() * Can variable be read and written by CTFE? */ -int VarDeclaration::isCTFE() +bool VarDeclaration::isCTFE() { return (storage_class & STCctfe) != 0; // || !isDataseg(); } -int VarDeclaration::hasPointers() +bool VarDeclaration::hasPointers() { //printf("VarDeclaration::hasPointers() %s, ty = %d\n", toChars(), type->ty); return (!isDataseg() && type->hasPointers()); } /****************************************** - * Return TRUE if variable needs to call the destructor. + * Return true if variable needs to call the destructor. */ -int VarDeclaration::needsAutoDtor() +bool VarDeclaration::needsAutoDtor() { //printf("VarDeclaration::needsAutoDtor() %s\n", toChars()); if (noscope || !edtor) - return FALSE; + return false; - return TRUE; + return true; } @@ -2273,19 +2294,14 @@ Expression *VarDeclaration::callScopeDtor(Scope *sc) } // Destructors for structs and arrays of structs - bool array = false; - Type *tv = type->toBasetype(); - while (tv->ty == Tsarray) - { TypeSArray *ta = (TypeSArray *)tv; - array = true; - tv = tv->nextOf()->toBasetype(); - } + Type *tv = type->baseElemOf(); if (tv->ty == Tstruct) - { TypeStruct *ts = (TypeStruct *)tv; + { + TypeStruct *ts = (TypeStruct *)tv; StructDeclaration *sd = ts->sym; if (sd->dtor) { - if (array) + if (type->toBasetype()->ty == Tsarray) { // Typeinfo.destroy(cast(void*)&v); Expression *ea = new SymOffExp(loc, this, 0, 0); @@ -2350,7 +2366,7 @@ void ObjectNotFound(Identifier *id) fatal(); } -/********************************* ClassInfoDeclaration ****************************/ +/******************************** SymbolDeclaration ********************************/ SymbolDeclaration::SymbolDeclaration(Loc loc, StructDeclaration *dsym) : Declaration(dsym->ident) @@ -2363,7 +2379,7 @@ SymbolDeclaration::SymbolDeclaration(Loc loc, StructDeclaration *dsym) /********************************* ClassInfoDeclaration ****************************/ ClassInfoDeclaration::ClassInfoDeclaration(ClassDeclaration *cd) - : VarDeclaration(Loc(), ClassDeclaration::classinfo->type, cd->ident, NULL) + : VarDeclaration(Loc(), Type::typeinfoclass->type, cd->ident, NULL) { this->cd = cd; storage_class = STCstatic | STCgshared; @@ -2379,29 +2395,10 @@ void ClassInfoDeclaration::semantic(Scope *sc) { } -/********************************* ModuleInfoDeclaration ****************************/ - -ModuleInfoDeclaration::ModuleInfoDeclaration(Module *mod) - : VarDeclaration(Loc(), Module::moduleinfo->type, mod->ident, NULL) -{ - this->mod = mod; - storage_class = STCstatic | STCgshared; -} - -Dsymbol *ModuleInfoDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(0); // should never be produced by syntax - return NULL; -} - -void ModuleInfoDeclaration::semantic(Scope *sc) -{ -} - /********************************* TypeInfoDeclaration ****************************/ TypeInfoDeclaration::TypeInfoDeclaration(Type *tinfo, int internal) - : VarDeclaration(Loc(), Type::typeinfo->type, tinfo->getTypeInfoIdent(internal), NULL) + : VarDeclaration(Loc(), Type::dtypeinfo->type, tinfo->getTypeInfoIdent(internal), NULL) { this->tinfo = tinfo; storage_class = STCstatic | STCgshared; @@ -2424,6 +2421,17 @@ void TypeInfoDeclaration::semantic(Scope *sc) #endif } +char *TypeInfoDeclaration::toChars() +{ + //printf("TypeInfoDeclaration::toChars() tinfo = %s\n", tinfo->toChars()); + OutBuffer buf; + buf.writestring("typeid("); + buf.writestring(tinfo->toChars()); + buf.writeByte(')'); + buf.writeByte(0); + return buf.extractData(); +} + /***************************** TypeInfoConstDeclaration **********************/ #if DMDV2 diff --git a/dmd2/declaration.h b/dmd2/declaration.h index ee57cdfd..53f6a44c 100644 --- a/dmd2/declaration.h +++ b/dmd2/declaration.h @@ -30,24 +30,22 @@ #include "lexer.h" #include "mtype.h" -struct Expression; -struct Statement; -struct LabelDsymbol; -#if IN_LLVM -struct LabelStatement; -#endif -struct Initializer; -struct Module; +class Expression; +class Statement; +class LabelDsymbol; +class Initializer; +class Module; struct InlineScanState; -struct ForeachStatement; -struct FuncDeclaration; -struct ExpInitializer; -struct StructDeclaration; -struct TupleType; +class ForeachStatement; +class FuncDeclaration; +class ExpInitializer; +class StructDeclaration; struct InterState; struct IRState; +struct CompiledCtfeFunction; #if IN_LLVM -struct AnonDeclaration; +class AnonDeclaration; +class LabelStatement; #endif enum PROT; @@ -104,11 +102,11 @@ enum PURE; #define STCtemp 0x10000000000LL // temporary variable introduced by inlining // and used only in backend process, so it's rvalue -#define STCStorageClass (STCauto | STCscope | STCstatic | STCextern | STCconst | STCfinal | \ - STCabstract | STCsynchronized | STCdeprecated | STCoverride | STClazy | STCalias | \ - STCout | STCin | \ - STCmanifest | STCimmutable | STCshared | STCnothrow | STCpure | STCref | STCtls | \ - STCgshared | STCproperty | STCsafe | STCtrusted | STCsystem | STCdisable) +const StorageClass STCStorageClass = (STCauto | STCscope | STCstatic | STCextern | STCconst | STCfinal | + STCabstract | STCsynchronized | STCdeprecated | STCoverride | STClazy | STCalias | + STCout | STCin | + STCmanifest | STCimmutable | STCshared | STCnothrow | STCpure | STCref | STCtls | + STCgshared | STCproperty | STCsafe | STCtrusted | STCsystem | STCdisable); struct Match { @@ -119,11 +117,8 @@ struct Match FuncDeclaration *anyf; // pick a func, any func, to use for error recovery }; -void overloadResolveX(Match *m, FuncDeclaration *f, - Type *tthis, Expressions *arguments); -int overloadApply(FuncDeclaration *fstart, - int (*fp)(void *, FuncDeclaration *), - void *param); +void functionResolve(Match *m, Dsymbol *fd, Loc loc, Scope *sc, Objects *tiargs, Type *tthis, Expressions *fargs); +int overloadApply(Dsymbol *fstart, void *param, int (*fp)(void *, Dsymbol *)); void ObjectNotFound(Identifier *id); @@ -137,16 +132,17 @@ enum Semantic /**************************************************************/ -struct Declaration : Dsymbol +class Declaration : public Dsymbol { +public: Type *type; Type *originalType; // before semantic analysis StorageClass storage_class; - enum PROT protection; - enum LINK linkage; + PROT protection; + LINK linkage; int inuse; // used to detect cycles const char *mangleOverride; // overridden symbol with pragma(mangle, "...") - enum Semantic sem; + Semantic sem; Declaration(Identifier *id); void semantic(Scope *sc); @@ -163,10 +159,10 @@ struct Declaration : Dsymbol const char *mangle(bool isv = false); bool isStatic() { return (storage_class & STCstatic) != 0; } - virtual int isDelete(); - virtual int isDataseg(); - virtual int isThreadlocal(); - virtual int isCodeseg(); + virtual bool isDelete(); + virtual bool isDataseg(); + virtual bool isThreadlocal(); + virtual bool isCodeseg(); bool isCtorinit() { return (storage_class & STCctorinit) != 0; } bool isFinal() { return (storage_class & STCfinal) != 0; } bool isAbstract() { return (storage_class & STCabstract) != 0; } @@ -186,17 +182,18 @@ struct Declaration : Dsymbol bool isOut() { return (storage_class & STCout) != 0; } bool isRef() { return (storage_class & STCref) != 0; } - enum PROT prot(); + PROT prot(); Declaration *isDeclaration() { return this; } }; /**************************************************************/ -struct TupleDeclaration : Declaration +class TupleDeclaration : public Declaration { +public: Objects *objects; - int isexp; // 1: expression tuple + bool isexp; // true: expression tuple TypeTuple *tupletype; // !=NULL if this is a type tuple @@ -204,7 +201,7 @@ struct TupleDeclaration : Declaration Dsymbol *syntaxCopy(Dsymbol *); const char *kind(); Type *getType(); - int needThis(); + bool needThis(); TupleDeclaration *isTupleDeclaration() { return this; } @@ -217,8 +214,9 @@ struct TupleDeclaration : Declaration /**************************************************************/ -struct TypedefDeclaration : Declaration +class TypedefDeclaration : public Declaration { +public: Type *basetype; Initializer *init; @@ -257,18 +255,19 @@ struct TypedefDeclaration : Declaration /**************************************************************/ -struct AliasDeclaration : Declaration +class AliasDeclaration : public Declaration { +public: Dsymbol *aliassym; Dsymbol *overnext; // next in overload list Dsymbol *import; // !=NULL if unresolved internal alias for selective import - int inSemantic; + bool inSemantic; AliasDeclaration(Loc loc, Identifier *ident, Type *type); AliasDeclaration(Loc loc, Identifier *ident, Dsymbol *s); Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); - int overloadInsert(Dsymbol *s); + bool overloadInsert(Dsymbol *s); const char *kind(); Type *getType(); Dsymbol *toAlias(); @@ -283,8 +282,9 @@ struct AliasDeclaration : Declaration /**************************************************************/ -struct VarDeclaration : Declaration +class VarDeclaration : public Declaration { +public: Initializer *init; unsigned offset; bool noscope; // no auto semantics @@ -329,16 +329,16 @@ struct VarDeclaration : Declaration Type *htype; Initializer *hinit; AggregateDeclaration *isThis(); - int needThis(); - int isExport(); - int isImportedSymbol(); - int isDataseg(); - int isThreadlocal(); - int isCTFE(); - int hasPointers(); + bool needThis(); + bool isExport(); + bool isImportedSymbol(); + bool isDataseg(); + bool isThreadlocal(); + bool isCTFE(); + bool hasPointers(); #if DMDV2 - int canTakeAddressOf(); - int needsAutoDtor(); + bool canTakeAddressOf(); + bool needsAutoDtor(); #endif Expression *callScopeDtor(Scope *sc); ExpInitializer *getExpInitializer(); @@ -347,8 +347,8 @@ struct VarDeclaration : Declaration void checkNestedReference(Scope *sc, Loc loc); Dsymbol *toAlias(); #if IN_DMD - void toObjFile(int multiobj); // compile to .obj file Symbol *toSymbol(); + void toObjFile(int multiobj); // compile to .obj file int cvMember(unsigned char *p); #endif const char *mangle(bool isv = false); @@ -381,8 +381,9 @@ struct VarDeclaration : Declaration // This is a shell around a back end symbol -struct SymbolDeclaration : Declaration +class SymbolDeclaration : public Declaration { +public: StructDeclaration *dsym; SymbolDeclaration(Loc loc, StructDeclaration *dsym); @@ -395,8 +396,9 @@ struct SymbolDeclaration : Declaration SymbolDeclaration *isSymbolDeclaration() { return (SymbolDeclaration *)this; } }; -struct ClassInfoDeclaration : VarDeclaration +class ClassInfoDeclaration : public VarDeclaration { +public: ClassDeclaration *cd; ClassInfoDeclaration(ClassDeclaration *cd); @@ -413,40 +415,25 @@ struct ClassInfoDeclaration : VarDeclaration ClassInfoDeclaration* isClassInfoDeclaration() { return this; } }; -struct ModuleInfoDeclaration : VarDeclaration -{ - Module *mod; - - ModuleInfoDeclaration(Module *mod); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - - void emitComment(Scope *sc); - void toJson(JsonOut *json); - -#if IN_DMD - Symbol *toSymbol(); -#endif -}; - -struct TypeInfoDeclaration : VarDeclaration +class TypeInfoDeclaration : public VarDeclaration { +public: Type *tinfo; TypeInfoDeclaration(Type *tinfo, int internal); Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); + char *toChars(); void emitComment(Scope *sc); void toJson(JsonOut *json); #if IN_DMD - void toObjFile(int multiobj); // compile to .obj file Symbol *toSymbol(); + void toObjFile(int multiobj); // compile to .obj file virtual void toDt(dt_t **pdt); #endif - - virtual TypeInfoDeclaration* isTypeInfoDeclaration() { return this; } + TypeInfoDeclaration *isTypeInfoDeclaration() { return this; } #if IN_LLVM /// Codegen traversal @@ -455,8 +442,9 @@ struct TypeInfoDeclaration : VarDeclaration #endif }; -struct TypeInfoStructDeclaration : TypeInfoDeclaration +class TypeInfoStructDeclaration : public TypeInfoDeclaration { +public: TypeInfoStructDeclaration(Type *tinfo); #if IN_DMD @@ -468,8 +456,9 @@ struct TypeInfoStructDeclaration : TypeInfoDeclaration #endif }; -struct TypeInfoClassDeclaration : TypeInfoDeclaration +class TypeInfoClassDeclaration : public TypeInfoDeclaration { +public: TypeInfoClassDeclaration(Type *tinfo); #if IN_DMD @@ -487,8 +476,9 @@ struct TypeInfoClassDeclaration : TypeInfoDeclaration #endif }; -struct TypeInfoInterfaceDeclaration : TypeInfoDeclaration +class TypeInfoInterfaceDeclaration : public TypeInfoDeclaration { +public: TypeInfoInterfaceDeclaration(Type *tinfo); #if IN_DMD @@ -500,8 +490,9 @@ struct TypeInfoInterfaceDeclaration : TypeInfoDeclaration #endif }; -struct TypeInfoTypedefDeclaration : TypeInfoDeclaration +class TypeInfoTypedefDeclaration : public TypeInfoDeclaration { +public: TypeInfoTypedefDeclaration(Type *tinfo); #if IN_DMD @@ -513,8 +504,9 @@ struct TypeInfoTypedefDeclaration : TypeInfoDeclaration #endif }; -struct TypeInfoPointerDeclaration : TypeInfoDeclaration +class TypeInfoPointerDeclaration : public TypeInfoDeclaration { +public: TypeInfoPointerDeclaration(Type *tinfo); #if IN_DMD @@ -526,8 +518,9 @@ struct TypeInfoPointerDeclaration : TypeInfoDeclaration #endif }; -struct TypeInfoArrayDeclaration : TypeInfoDeclaration +class TypeInfoArrayDeclaration : public TypeInfoDeclaration { +public: TypeInfoArrayDeclaration(Type *tinfo); #if IN_DMD @@ -539,8 +532,9 @@ struct TypeInfoArrayDeclaration : TypeInfoDeclaration #endif }; -struct TypeInfoStaticArrayDeclaration : TypeInfoDeclaration +class TypeInfoStaticArrayDeclaration : public TypeInfoDeclaration { +public: TypeInfoStaticArrayDeclaration(Type *tinfo); #if IN_DMD @@ -552,8 +546,9 @@ struct TypeInfoStaticArrayDeclaration : TypeInfoDeclaration #endif }; -struct TypeInfoAssociativeArrayDeclaration : TypeInfoDeclaration +class TypeInfoAssociativeArrayDeclaration : public TypeInfoDeclaration { +public: TypeInfoAssociativeArrayDeclaration(Type *tinfo); #if IN_DMD @@ -565,8 +560,9 @@ struct TypeInfoAssociativeArrayDeclaration : TypeInfoDeclaration #endif }; -struct TypeInfoEnumDeclaration : TypeInfoDeclaration +class TypeInfoEnumDeclaration : public TypeInfoDeclaration { +public: TypeInfoEnumDeclaration(Type *tinfo); #if IN_DMD @@ -578,8 +574,9 @@ struct TypeInfoEnumDeclaration : TypeInfoDeclaration #endif }; -struct TypeInfoFunctionDeclaration : TypeInfoDeclaration +class TypeInfoFunctionDeclaration : public TypeInfoDeclaration { +public: TypeInfoFunctionDeclaration(Type *tinfo); #if IN_DMD @@ -591,8 +588,9 @@ struct TypeInfoFunctionDeclaration : TypeInfoDeclaration #endif }; -struct TypeInfoDelegateDeclaration : TypeInfoDeclaration +class TypeInfoDelegateDeclaration : public TypeInfoDeclaration { +public: TypeInfoDelegateDeclaration(Type *tinfo); #if IN_DMD @@ -604,8 +602,9 @@ struct TypeInfoDelegateDeclaration : TypeInfoDeclaration #endif }; -struct TypeInfoTupleDeclaration : TypeInfoDeclaration +class TypeInfoTupleDeclaration : public TypeInfoDeclaration { +public: TypeInfoTupleDeclaration(Type *tinfo); #if IN_DMD @@ -618,8 +617,9 @@ struct TypeInfoTupleDeclaration : TypeInfoDeclaration }; #if DMDV2 -struct TypeInfoConstDeclaration : TypeInfoDeclaration +class TypeInfoConstDeclaration : public TypeInfoDeclaration { +public: TypeInfoConstDeclaration(Type *tinfo); #if IN_DMD @@ -631,8 +631,9 @@ struct TypeInfoConstDeclaration : TypeInfoDeclaration #endif }; -struct TypeInfoInvariantDeclaration : TypeInfoDeclaration +class TypeInfoInvariantDeclaration : public TypeInfoDeclaration { +public: TypeInfoInvariantDeclaration(Type *tinfo); #if IN_DMD @@ -644,8 +645,9 @@ struct TypeInfoInvariantDeclaration : TypeInfoDeclaration #endif }; -struct TypeInfoSharedDeclaration : TypeInfoDeclaration +class TypeInfoSharedDeclaration : public TypeInfoDeclaration { +public: TypeInfoSharedDeclaration(Type *tinfo); #if IN_DMD @@ -657,8 +659,9 @@ struct TypeInfoSharedDeclaration : TypeInfoDeclaration #endif }; -struct TypeInfoWildDeclaration : TypeInfoDeclaration +class TypeInfoWildDeclaration : public TypeInfoDeclaration { +public: TypeInfoWildDeclaration(Type *tinfo); #if IN_DMD @@ -670,8 +673,9 @@ struct TypeInfoWildDeclaration : TypeInfoDeclaration #endif }; -struct TypeInfoVectorDeclaration : TypeInfoDeclaration +class TypeInfoVectorDeclaration : public TypeInfoDeclaration { +public: TypeInfoVectorDeclaration(Type *tinfo); #if IN_DMD @@ -686,8 +690,9 @@ struct TypeInfoVectorDeclaration : TypeInfoDeclaration /**************************************************************/ -struct ThisDeclaration : VarDeclaration +class ThisDeclaration : public VarDeclaration { +public: ThisDeclaration(Loc loc, Type *t); Dsymbol *syntaxCopy(Dsymbol *); ThisDeclaration *isThisDeclaration() { return this; } @@ -726,14 +731,15 @@ enum BUILTIN #endif }; -Expression *eval_builtin(Loc loc, enum BUILTIN builtin, Expressions *arguments); +Expression *eval_builtin(Loc loc, BUILTIN builtin, Expressions *arguments); #else enum BUILTIN { }; #endif -struct FuncDeclaration : Declaration +class FuncDeclaration : public Declaration { +public: Types *fthrows; // Array of Type's of exceptions (not used) Statement *frequire; Statement *fensure; @@ -766,28 +772,30 @@ struct FuncDeclaration : Declaration VarDeclaration *v_argsave; // save area for args passed in registers for variadic functions VarDeclarations *parameters; // Array of VarDeclaration's for parameters DsymbolTable *labtab; // statement label symbol table - Declaration *overnext; // next in overload list + Dsymbol *overnext; // next in overload list + FuncDeclaration *overnext0; // next in overload list (only used during IFTI) Loc endloc; // location of closing curly bracket int vtblIndex; // for member functions, index into vtbl[] - bool naked; // !=0 if naked + bool naked; // true if naked ILS inlineStatusStmt; ILS inlineStatusExp; + + CompiledCtfeFunction *ctfeCode; // Compiled code for interpreter int inlineNest; // !=0 if nested inline #if IN_LLVM char isArrayOp; // 1 if compiler-generated array op, 2 if druntime-provided #else - bool isArrayOp; // !=0 if array operation + bool isArrayOp; // true if array operation #endif FuncDeclaration *dArrayOp; // D version of array op for ctfe - enum PASS semanticRun; int semantic3Errors; // !=0 if errors in semantic3 // this function's frame ptr ForeachStatement *fes; // if foreach body, this is the foreach - bool introducing; // !=0 if 'introducing' function + bool introducing; // true if 'introducing' function Type *tintro; // if !=NULL, then this is the type // of the 'introducing' function // this one is overriding - int inferRetType; // !=0 if return type is to be inferred + bool inferRetType; // true if return type is to be inferred StorageClass storage_class2; // storage class for template onemember's // Things that should really go into Scope @@ -797,7 +805,7 @@ struct FuncDeclaration : Declaration // 8 if there's inline asm // Support for NRVO (named return value optimization) - bool nrvo_can; // !=0 means we can do it + bool nrvo_can; // true means we can do it VarDeclaration *nrvo_var; // variable to replace with shidden #if IN_DMD Symbol *shidden; // hidden pointer passed to function @@ -806,7 +814,7 @@ struct FuncDeclaration : Declaration ReturnStatements *returns; #if DMDV2 - enum BUILTIN builtin; // set if this is a known, builtin + BUILTIN builtin; // set if this is a known, builtin // function we can evaluate at compile // time @@ -839,16 +847,16 @@ struct FuncDeclaration : Declaration bool functionSemantic3(); // called from semantic3 VarDeclaration *declareThis(Scope *sc, AggregateDeclaration *ad); - int equals(Object *o); + bool equals(RootObject *o); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void bodyToCBuffer(OutBuffer *buf, HdrGenState *hgs); void toJson(JsonOut *json); int overrides(FuncDeclaration *fd); int findVtblIndex(Dsymbols *vtbl, int dim); - int overloadInsert(Dsymbol *s); + bool overloadInsert(Dsymbol *s); FuncDeclaration *overloadExactMatch(Type *t); - FuncDeclaration *overloadResolve(Loc loc, Type *tthis, Expressions *arguments, int flags = 0); + TemplateDeclaration *findTemplateDeclRoot(); MATCH leastAsSpecialized(FuncDeclaration *g); LabelDsymbol *searchLabel(Identifier *ident); AggregateDeclaration *isThis(); @@ -857,35 +865,36 @@ struct FuncDeclaration : Declaration void appendExp(Expression *e); void appendState(Statement *s); const char *mangle(bool isv = false); + const char *mangleExact(bool isv = false); const char *toPrettyChars(); const char *toFullSignature(); // for diagnostics, e.g. 'int foo(int x, int y) pure' - int isMain(); - int isWinMain(); - int isDllMain(); - enum BUILTIN isBuiltin(); - int isExport(); - int isImportedSymbol(); - int isAbstract(); - int isCodeseg(); - int isOverloadable(); - int hasOverloads(); - enum PURE isPure(); - enum PURE isPureBypassingInference(); + bool isMain(); + bool isWinMain(); + bool isDllMain(); + BUILTIN isBuiltin(); + bool isExport(); + bool isImportedSymbol(); + bool isCodeseg(); + bool isOverloadable(); + bool hasOverloads(); + PURE isPure(); + PURE isPureBypassingInference(); bool setImpure(); - int isSafe(); + bool isSafe(); bool isSafeBypassingInference(); - int isTrusted(); + bool isTrusted(); bool setUnsafe(); bool isolateReturn(); bool parametersIntersect(Type *t); - virtual int isNested(); - int needThis(); - int isVirtualMethod(); - virtual int isVirtual(); - virtual int isFinal(); - virtual int addPreInvariant(); - virtual int addPostInvariant(); + virtual bool isNested(); + bool needThis(); + bool isVirtualMethod(); + virtual bool isVirtual(); + virtual bool isFinalFunc(); + virtual bool addPreInvariant(); + virtual bool addPostInvariant(); Expression *interpret(InterState *istate, Expressions *arguments, Expression *thisexp = NULL); + void ctfeCompile(); void inlineScan(); int canInline(int hasthis, int hdrscan, int statementsToo); Expression *expandInline(InlineScanState *iss, Expression *ethis, Expressions *arguments, Statement **ps); @@ -893,11 +902,11 @@ struct FuncDeclaration : Declaration void toDocBuffer(OutBuffer *buf, Scope *sc); FuncDeclaration *isUnique(); void checkNestedReference(Scope *sc, Loc loc); - int needsClosure(); - int hasNestedFrameRefs(); + bool needsClosure(); + bool hasNestedFrameRefs(); void buildResultVar(); Statement *mergeFrequire(Statement *, Expressions *params = 0); - Statement *mergeFensure(Statement *, Expressions *params = 0); + Statement *mergeFensure(Statement *, Identifier *oid, Expressions *params = 0); Parameters *getParameters(int *pvarargs); // LDC: give argument types to runtime functions @@ -959,34 +968,36 @@ FuncDeclaration *resolveFuncCall(Loc loc, Scope *sc, Dsymbol *s, int flags = 0); #endif -struct FuncAliasDeclaration : FuncDeclaration +class FuncAliasDeclaration : public FuncDeclaration { +public: FuncDeclaration *funcalias; - int hasOverloads; + bool hasOverloads; - FuncAliasDeclaration(FuncDeclaration *funcalias, int hasOverloads = 1); + FuncAliasDeclaration(FuncDeclaration *funcalias, bool hasOverloads = true); FuncAliasDeclaration *isFuncAliasDeclaration() { return this; } const char *kind(); #if IN_DMD Symbol *toSymbol(); #endif - const char *mangle(bool isv = false) { return toAliasFunc()->mangle(isv); } + const char *mangle(bool isv = false); FuncDeclaration *toAliasFunc(); }; -struct FuncLiteralDeclaration : FuncDeclaration +class FuncLiteralDeclaration : public FuncDeclaration { - enum TOK tok; // TOKfunction or TOKdelegate +public: + TOK tok; // TOKfunction or TOKdelegate Type *treq; // target of return type inference - FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type, enum TOK tok, - ForeachStatement *fes); + FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type, TOK tok, + ForeachStatement *fes, Identifier *id = NULL); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Dsymbol *syntaxCopy(Dsymbol *); - int isNested(); - int isVirtual(); + bool isNested(); + bool isVirtual(); FuncLiteralDeclaration *isFuncLiteralDeclaration() { return this; } const char *kind(); @@ -1002,40 +1013,43 @@ struct FuncLiteralDeclaration : FuncDeclaration #endif }; -struct CtorDeclaration : FuncDeclaration +class CtorDeclaration : public FuncDeclaration { +public: CtorDeclaration(Loc loc, Loc endloc, StorageClass stc, Type *type); Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); const char *kind(); char *toChars(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); + bool isVirtual(); + bool addPreInvariant(); + bool addPostInvariant(); CtorDeclaration *isCtorDeclaration() { return this; } }; #if DMDV2 -struct PostBlitDeclaration : FuncDeclaration +class PostBlitDeclaration : public FuncDeclaration { +public: PostBlitDeclaration(Loc loc, Loc endloc, StorageClass stc, Identifier *id); Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void toJson(JsonOut *json); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - int overloadInsert(Dsymbol *s); + bool isVirtual(); + bool addPreInvariant(); + bool addPostInvariant(); + bool overloadInsert(Dsymbol *s); void emitComment(Scope *sc); PostBlitDeclaration *isPostBlitDeclaration() { return this; } }; #endif -struct DtorDeclaration : FuncDeclaration +class DtorDeclaration : public FuncDeclaration { +public: DtorDeclaration(Loc loc, Loc endloc); DtorDeclaration(Loc loc, Loc endloc, StorageClass stc, Identifier *id); Dsymbol *syntaxCopy(Dsymbol *); @@ -1043,25 +1057,26 @@ struct DtorDeclaration : FuncDeclaration void toCBuffer(OutBuffer *buf, HdrGenState *hgs); const char *kind(); char *toChars(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - int overloadInsert(Dsymbol *s); + bool isVirtual(); + bool addPreInvariant(); + bool addPostInvariant(); + bool overloadInsert(Dsymbol *s); void emitComment(Scope *sc); DtorDeclaration *isDtorDeclaration() { return this; } }; -struct StaticCtorDeclaration : FuncDeclaration +class StaticCtorDeclaration : public FuncDeclaration { +public: StaticCtorDeclaration(Loc loc, Loc endloc); StaticCtorDeclaration(Loc loc, Loc endloc, const char *name); Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); AggregateDeclaration *isThis(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); + bool isVirtual(); + bool addPreInvariant(); + bool addPostInvariant(); bool hasStaticCtorOrDtor(); void emitComment(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -1070,8 +1085,9 @@ struct StaticCtorDeclaration : FuncDeclaration }; #if DMDV2 -struct SharedStaticCtorDeclaration : StaticCtorDeclaration +class SharedStaticCtorDeclaration : public StaticCtorDeclaration { +public: SharedStaticCtorDeclaration(Loc loc, Loc endloc); Dsymbol *syntaxCopy(Dsymbol *); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -1080,18 +1096,20 @@ struct SharedStaticCtorDeclaration : StaticCtorDeclaration }; #endif -struct StaticDtorDeclaration : FuncDeclaration -{ VarDeclaration *vgate; // 'gate' variable +class StaticDtorDeclaration : public FuncDeclaration +{ +public: + VarDeclaration *vgate; // 'gate' variable - StaticDtorDeclaration(Loc loc, Loc endloc); - StaticDtorDeclaration(Loc loc, Loc endloc, const char *name); + StaticDtorDeclaration(Loc loc, Loc endloc, StorageClass stc); + StaticDtorDeclaration(Loc loc, Loc endloc, const char *name, StorageClass stc); Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); AggregateDeclaration *isThis(); - int isVirtual(); + bool isVirtual(); bool hasStaticCtorOrDtor(); - int addPreInvariant(); - int addPostInvariant(); + bool addPreInvariant(); + bool addPostInvariant(); void emitComment(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -1099,9 +1117,10 @@ struct StaticDtorDeclaration : FuncDeclaration }; #if DMDV2 -struct SharedStaticDtorDeclaration : StaticDtorDeclaration +class SharedStaticDtorDeclaration : public StaticDtorDeclaration { - SharedStaticDtorDeclaration(Loc loc, Loc endloc); +public: + SharedStaticDtorDeclaration(Loc loc, Loc endloc, StorageClass stc); Dsymbol *syntaxCopy(Dsymbol *); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -1109,38 +1128,42 @@ struct SharedStaticDtorDeclaration : StaticDtorDeclaration }; #endif -struct InvariantDeclaration : FuncDeclaration +class InvariantDeclaration : public FuncDeclaration { +public: InvariantDeclaration(Loc loc, Loc endloc, StorageClass stc, Identifier *id = NULL); Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); + bool isVirtual(); + bool addPreInvariant(); + bool addPostInvariant(); void emitComment(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); InvariantDeclaration *isInvariantDeclaration() { return this; } }; -struct UnitTestDeclaration : FuncDeclaration +class UnitTestDeclaration : public FuncDeclaration { +public: char *codedoc; /** For documented unittest. */ UnitTestDeclaration(Loc loc, Loc endloc, char *codedoc); Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); AggregateDeclaration *isThis(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); + bool isVirtual(); + bool addPreInvariant(); + bool addPostInvariant(); void emitComment(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); UnitTestDeclaration *isUnitTestDeclaration() { return this; } }; -struct NewDeclaration : FuncDeclaration -{ Parameters *arguments; +class NewDeclaration : public FuncDeclaration +{ +public: + Parameters *arguments; int varargs; NewDeclaration(Loc loc, Loc endloc, Parameters *arguments, int varargs); @@ -1148,26 +1171,28 @@ struct NewDeclaration : FuncDeclaration void semantic(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); const char *kind(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); + bool isVirtual(); + bool addPreInvariant(); + bool addPostInvariant(); NewDeclaration *isNewDeclaration() { return this; } }; -struct DeleteDeclaration : FuncDeclaration -{ Parameters *arguments; +class DeleteDeclaration : public FuncDeclaration +{ +public: + Parameters *arguments; DeleteDeclaration(Loc loc, Loc endloc, Parameters *arguments); Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); const char *kind(); - int isDelete(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); + bool isDelete(); + bool isVirtual(); + bool addPreInvariant(); + bool addPostInvariant(); DeleteDeclaration *isDeleteDeclaration() { return this; } }; diff --git a/dmd2/doc.c b/dmd2/doc.c index edaac798..8af895d8 100644 --- a/dmd2/doc.c +++ b/dmd2/doc.c @@ -44,12 +44,13 @@ struct Escape const char *escapeChar(unsigned c); }; -struct Section +class Section { - unsigned char *name; +public: + utf8_t *name; size_t namelen; - unsigned char *body; + utf8_t *body; size_t bodylen; int nooutput; @@ -57,17 +58,19 @@ struct Section virtual void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf); }; -struct ParamSection : Section +class ParamSection : public Section { +public: void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf); }; -struct MacroSection : Section +class MacroSection : public Section { +public: void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf); }; -typedef ArrayBase
Sections; +typedef Array
Sections; struct DocComment { @@ -83,31 +86,33 @@ struct DocComment summary(NULL), copyright(NULL), macros(NULL), pmacrotable(NULL), pescapetable(NULL) { } - static DocComment *parse(Scope *sc, Dsymbol *s, unsigned char *comment); - static void parseMacros(Escape **pescapetable, Macro **pmacrotable, unsigned char *m, size_t mlen); - static void parseEscapes(Escape **pescapetable, unsigned char *textstart, size_t textlen); + static DocComment *parse(Scope *sc, Dsymbol *s, utf8_t *comment); + static void parseMacros(Escape **pescapetable, Macro **pmacrotable, utf8_t *m, size_t mlen); + static void parseEscapes(Escape **pescapetable, utf8_t *textstart, size_t textlen); - void parseSections(unsigned char *comment); + void parseSections(utf8_t *comment); void writeSections(Scope *sc, Dsymbol *s, OutBuffer *buf); }; int cmp(const char *stringz, void *s, size_t slen); int icmp(const char *stringz, void *s, size_t slen); -int isDitto(unsigned char *comment); -unsigned char *skipwhitespace(unsigned char *p); +int isDitto(utf8_t *comment); +utf8_t *skipwhitespace(utf8_t *p); size_t skiptoident(OutBuffer *buf, size_t i); size_t skippastident(OutBuffer *buf, size_t i); size_t skippastURL(OutBuffer *buf, size_t i); void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, size_t offset); void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, size_t offset, bool anchor = true); void highlightCode2(Scope *sc, Dsymbol *s, OutBuffer *buf, size_t offset); -Parameter *isFunctionParameter(Dsymbol *s, unsigned char *p, size_t len); +TypeFunction *isTypeFunction(Dsymbol *s); +Parameter *isFunctionParameter(Dsymbol *s, utf8_t *p, size_t len); +TemplateParameter *isTemplateParameter(Dsymbol *s, utf8_t *p, size_t len); -int isIdStart(unsigned char *p); -int isIdTail(unsigned char *p); -int isIndentWS(unsigned char *p); -int utfStride(unsigned char *p); +int isIdStart(utf8_t *p); +int isIdTail(utf8_t *p); +int isIndentWS(utf8_t *p); +int utfStride(utf8_t *p); static const char ddoc_default[] = "\ DDOC = \n\ @@ -185,6 +190,7 @@ DDOC_CLASS_MEMBERS = $(DDOC_MEMBERS $0)\n\ DDOC_STRUCT_MEMBERS = $(DDOC_MEMBERS $0)\n\ DDOC_ENUM_MEMBERS = $(DDOC_MEMBERS $0)\n\ DDOC_TEMPLATE_MEMBERS = $(DDOC_MEMBERS $0)\n\ +DDOC_ENUM_BASETYPE = $0\n\ DDOC_PARAMS = $(B Params:)$(BR)\n$(TABLE $0)$(BR)\n\ DDOC_PARAM_ROW = $(TR $0)\n\ DDOC_PARAM_ID = $(TD $0)\n\ @@ -224,7 +230,7 @@ void Module::gendocfile() { mbuf_done = 1; // Use our internal default - mbuf.write(ddoc_default, sizeof(ddoc_default) - 1); + mbuf.write(ddoc_default, strlen(ddoc_default)); // Override with DDOCFILE specified in the sc.ini file char *p = getenv("DDOCFILE"); @@ -256,7 +262,7 @@ void Module::gendocfile() // Set the title to be the name of the module { const char *p = toPrettyChars(); - Macro::define(¯otable, (unsigned char *)"TITLE", 5, (unsigned char *)p, strlen(p)); + Macro::define(¯otable, (utf8_t *)"TITLE", 5, (utf8_t *)p, strlen(p)); } // Set time macros @@ -264,20 +270,20 @@ void Module::gendocfile() time(&t); char *p = ctime(&t); p = mem.strdup(p); - Macro::define(¯otable, (unsigned char *)"DATETIME", 8, (unsigned char *)p, strlen(p)); - Macro::define(¯otable, (unsigned char *)"YEAR", 4, (unsigned char *)p + 20, 4); + Macro::define(¯otable, (utf8_t *)"DATETIME", 8, (utf8_t *)p, strlen(p)); + Macro::define(¯otable, (utf8_t *)"YEAR", 4, (utf8_t *)p + 20, 4); } char *srcfilename = srcfile->toChars(); - Macro::define(¯otable, (unsigned char *)"SRCFILENAME", 11, (unsigned char *)srcfilename, strlen(srcfilename)); + Macro::define(¯otable, (utf8_t *)"SRCFILENAME", 11, (utf8_t *)srcfilename, strlen(srcfilename)); char *docfilename = docfile->toChars(); - Macro::define(¯otable, (unsigned char *)"DOCFILENAME", 11, (unsigned char *)docfilename, strlen(docfilename)); + Macro::define(¯otable, (utf8_t *)"DOCFILENAME", 11, (utf8_t *)docfilename, strlen(docfilename)); if (dc->copyright) { dc->copyright->nooutput = 1; - Macro::define(¯otable, (unsigned char *)"COPYRIGHT", 9, dc->copyright->body, dc->copyright->bodylen); + Macro::define(¯otable, (utf8_t *)"COPYRIGHT", 9, dc->copyright->body, dc->copyright->bodylen); } buf.printf("$(DDOC_COMMENT Generated by Ddoc from %s)\n", srcfile->toChars()); @@ -299,7 +305,7 @@ void Module::gendocfile() } //printf("BODY= '%.*s'\n", buf.offset, buf.data); - Macro::define(¯otable, (unsigned char *)"BODY", 4, buf.data, buf.offset); + Macro::define(¯otable, (utf8_t *)"BODY", 4, buf.data, buf.offset); OutBuffer buf2; buf2.writestring("$(DDOC)\n"); @@ -313,10 +319,10 @@ void Module::gendocfile() { buf.setsize(0); buf.reserve(buf2.offset); - unsigned char *p = buf2.data; + utf8_t *p = buf2.data; for (size_t j = 0; j < buf2.offset; j++) { - unsigned char c = p[j]; + utf8_t c = p[j]; if (c == 0xFF && j + 1 < buf2.offset) { j++; @@ -347,7 +353,7 @@ void Module::gendocfile() /* Remove all the escape sequences from buf2 */ { size_t i = 0; - unsigned char *p = buf2.data; + utf8_t *p = buf2.data; for (size_t j = 0; j < buf2.offset; j++) { if (p[j] == 0xFF && j + 1 < buf2.offset) @@ -380,7 +386,7 @@ void escapeDdocString(OutBuffer *buf, size_t start) { for (size_t u = start; u < buf->offset; u++) { - unsigned char c = buf->data[u]; + utf8_t c = buf->data[u]; switch(c) { case '$': @@ -410,13 +416,20 @@ void escapeDdocString(OutBuffer *buf, size_t start) * Fix by replacing unmatched ( with $(LPAREN) and unmatched ) with $(RPAREN). */ -void escapeStrayParenthesis(OutBuffer *buf, size_t start, Loc loc) +void escapeStrayParenthesis(OutBuffer *buf, size_t start, Dsymbol *s) { unsigned par_open = 0; + Loc loc = s->loc; + + if (Module *m = s->isModule()) + { + if (m->md) + loc = m->md->loc; + } for (size_t u = start; u < buf->offset; u++) { - unsigned char c = buf->data[u]; + utf8_t c = buf->data[u]; switch(c) { case '(': @@ -451,7 +464,7 @@ void escapeStrayParenthesis(OutBuffer *buf, size_t start, Loc loc) { par_open = 0; for (size_t u = buf->offset; u > start;) { u--; - unsigned char c = buf->data[u]; + utf8_t c = buf->data[u]; switch(c) { case ')': @@ -501,6 +514,7 @@ static bool emitAnchorName(OutBuffer *buf, Dsymbol *s) * We don't want the template parameter list and constraints. */ buf->writestring(s->Dsymbol::toChars()); } + return true; } @@ -532,13 +546,13 @@ void emitUnittestComment(Scope *sc, Dsymbol *s, size_t ofs) { OutBuffer *buf = sc->docbuf; - for (UnitTestDeclaration *utd = s->unittest; utd; utd = utd->unittest) + for (UnitTestDeclaration *utd = s->ddocUnittest; utd; utd = utd->ddocUnittest) { if (utd->protection == PROTprivate || !utd->comment || !utd->fbody) continue; // Strip whitespaces to avoid showing empty summary - unsigned char *c = utd->comment; + utf8_t *c = utd->comment; while (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r') ++c; OutBuffer codebuf; @@ -593,7 +607,7 @@ void Dsymbol::emitDitto(Scope *sc) sc->lastoffset += b.offset; Dsymbol *s = this; - if (!s->unittest && parent) + if (!s->ddocUnittest && parent) s = parent->isTemplateDeclaration(); if (s) emitUnittestComment(sc, s, strlen(ddoc_decl_dd_e)); @@ -658,7 +672,6 @@ void DtorDeclaration::emitComment(Scope *sc) { } void StaticCtorDeclaration::emitComment(Scope *sc) { } void StaticDtorDeclaration::emitComment(Scope *sc) { } void ClassInfoDeclaration::emitComment(Scope *sc) { } -void ModuleInfoDeclaration::emitComment(Scope *sc) { } void TypeInfoDeclaration::emitComment(Scope *sc) { } @@ -733,7 +746,7 @@ void TemplateDeclaration::emitComment(Scope *sc) if (prot() == PROTprivate) return; - unsigned char *com = comment; + utf8_t *com = comment; int hasmembers = 1; Dsymbol *ss = this; @@ -883,14 +896,17 @@ void prefix(OutBuffer *buf, Dsymbol *s) else if (d->isAbstract()) buf->writestring("abstract "); - if (d->isConst()) - buf->writestring("const "); -#if DMDV2 - if (d->isImmutable()) - buf->writestring("immutable "); -#endif - if (d->isSynchronized()) - buf->writestring("synchronized "); + if (!d->isFuncDeclaration()) // toCBufferWithAttributes handles this + { + if (d->isConst()) + buf->writestring("const "); + #if DMDV2 + if (d->isImmutable()) + buf->writestring("immutable "); + #endif + if (d->isSynchronized()) + buf->writestring("synchronized "); + } } } @@ -919,6 +935,16 @@ void declarationToDocBuffer(Declaration *decl, OutBuffer *buf, TemplateDeclarati else buf->writestring(decl->ident->toChars()); + // emit constraints if declaration is a templated declaration + if (td && td->constraint) + { + HdrGenState hgs; + hgs.ddoc = 1; + buf->writestring(" if ("); + td->constraint->toCBuffer(buf, &hgs); + buf->writeByte(')'); + } + if (decl->isDeprecated()) buf->writestring(")"); @@ -1122,7 +1148,7 @@ void ClassDeclaration::toDocBuffer(OutBuffer *buf, Scope *sc) } else { - if (isAbstract()) + if (!isInterfaceDeclaration() && isAbstract()) buf->writestring("abstract "); buf->printf("%s %s", kind(), toChars()); } @@ -1162,6 +1188,13 @@ void EnumDeclaration::toDocBuffer(OutBuffer *buf, Scope *sc) if (ident) { buf->printf("%s %s", kind(), toChars()); + if (memtype) + { + buf->writestring(": $(DDOC_ENUM_BASETYPE "); + HdrGenState *hgs = NULL; + memtype->toCBuffer(buf, NULL, hgs); + buf->writestring(")"); + } buf->writestring(";\n"); } } @@ -1177,7 +1210,7 @@ void EnumMember::toDocBuffer(OutBuffer *buf, Scope *sc) /********************************* DocComment *********************************/ -DocComment *DocComment::parse(Scope *sc, Dsymbol *s, unsigned char *comment) +DocComment *DocComment::parse(Scope *sc, Dsymbol *s, utf8_t *comment) { //printf("parse(%s): '%s'\n", s->toChars(), comment); if (sc->lastdc && isDitto(comment)) @@ -1214,21 +1247,21 @@ DocComment *DocComment::parse(Scope *sc, Dsymbol *s, unsigned char *comment) * then (*pcomment)[0 .. idlen] is the identifier. */ -void DocComment::parseSections(unsigned char *comment) -{ unsigned char *p; - unsigned char *pstart; - unsigned char *pend; - unsigned char *idstart; +void DocComment::parseSections(utf8_t *comment) +{ utf8_t *p; + utf8_t *pstart; + utf8_t *pend; + utf8_t *idstart; size_t idlen; - unsigned char *name = NULL; + utf8_t *name = NULL; size_t namelen = 0; //printf("parseSections('%s')\n", comment); p = comment; while (*p) { - unsigned char *pstart0 = p; + utf8_t *pstart0 = p; p = skipwhitespace(p); pstart = p; pend = p; @@ -1263,7 +1296,7 @@ void DocComment::parseSections(unsigned char *comment) if (!inCode && isIdStart(p)) { - unsigned char *q = p + utfStride(p); + utf8_t *q = p + utfStride(p); while (isIdTail(q)) q += utfStride(q); if (*q == ':') // identifier: ends it @@ -1337,7 +1370,7 @@ void DocComment::parseSections(unsigned char *comment) void DocComment::writeSections(Scope *sc, Dsymbol *s, OutBuffer *buf) { //printf("DocComment::writeSections()\n"); - if (sections.dim || s->unittest) + if (sections.dim || s->ddocUnittest) { buf->writestring("$(DDOC_SECTIONS \n"); for (size_t i = 0; i < sections.dim; i++) @@ -1353,12 +1386,12 @@ void DocComment::writeSections(Scope *sc, Dsymbol *s, OutBuffer *buf) buf->writestring("$(DDOC_SUMMARY "); size_t o = buf->offset; buf->write(sec->body, sec->bodylen); - escapeStrayParenthesis(buf, o, s->loc); + escapeStrayParenthesis(buf, o, s); highlightText(sc, s, buf, o); buf->writestring(")\n"); } } - if (s->unittest) + if (s->ddocUnittest) emitUnittestComment(sc, s, 0); buf->writestring(")\n"); } @@ -1395,10 +1428,10 @@ void Section::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) buf->writestring("$(DDOC_SECTION_H "); size_t o = buf->offset; for (size_t u = 0; u < namelen; u++) - { unsigned char c = name[u]; + { utf8_t c = name[u]; buf->writeByte((c == '_') ? ' ' : c); } - escapeStrayParenthesis(buf, o, s->loc); + escapeStrayParenthesis(buf, o, s); buf->writestring(":)\n"); } else @@ -1408,7 +1441,7 @@ void Section::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) L1: size_t o = buf->offset; buf->write(body, bodylen); - escapeStrayParenthesis(buf, o, s->loc); + escapeStrayParenthesis(buf, o, s); highlightText(sc, s, buf, o); buf->writestring(")\n"); } @@ -1418,20 +1451,20 @@ void Section::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) void ParamSection::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) { - unsigned char *p = body; + utf8_t *p = body; size_t len = bodylen; - unsigned char *pend = p + len; + utf8_t *pend = p + len; - unsigned char *tempstart; + utf8_t *tempstart; size_t templen; - unsigned char *namestart; + utf8_t *namestart; size_t namelen = 0; // !=0 if line continuation - unsigned char *textstart; + utf8_t *textstart; size_t textlen; - size_t o; + size_t o, paramcount = 0; Parameter *arg; buf->writestring("$(DDOC_PARAMS \n"); @@ -1481,23 +1514,37 @@ void ParamSection::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) L1: //printf("param '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart); + ++paramcount; HdrGenState hgs; buf->writestring("$(DDOC_PARAM_ROW "); buf->writestring("$(DDOC_PARAM_ID "); o = buf->offset; arg = isFunctionParameter(s, namestart, namelen); if (arg && arg->type && arg->ident) + { arg->type->toCBuffer(buf, arg->ident, &hgs); + } else + { + if (isTemplateParameter(s, namestart, namelen)) + { + // 10236: Don't count template parameters for params check + --paramcount; + } + else if (!arg) + { + warning(s->loc, "Ddoc: function declaration has no parameter '%.*s'", namelen, namestart); + } buf->write(namestart, namelen); - escapeStrayParenthesis(buf, o, s->loc); + } + escapeStrayParenthesis(buf, o, s); highlightCode(sc, s, buf, o, false); buf->writestring(")\n"); buf->writestring("$(DDOC_PARAM_DESC "); o = buf->offset; buf->write(textstart, textlen); - escapeStrayParenthesis(buf, o, s->loc); + escapeStrayParenthesis(buf, o, s); highlightText(sc, s, buf, o); buf->writestring(")"); buf->writestring(")\n"); @@ -1530,6 +1577,16 @@ void ParamSection::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) if (namelen) goto L1; // write out last one buf->writestring(")\n"); + + TypeFunction *tf = isTypeFunction(s); + if (tf) + { + size_t pcount = tf->parameters ? tf->parameters->dim : 0; + if (pcount != paramcount) + { + warning(s->loc, "Ddoc: parameter count mismatch"); + } + } } /*************************************************** @@ -1549,19 +1606,19 @@ void MacroSection::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) * name2 = value2 */ -void DocComment::parseMacros(Escape **pescapetable, Macro **pmacrotable, unsigned char *m, size_t mlen) +void DocComment::parseMacros(Escape **pescapetable, Macro **pmacrotable, utf8_t *m, size_t mlen) { - unsigned char *p = m; + utf8_t *p = m; size_t len = mlen; - unsigned char *pend = p + len; + utf8_t *pend = p + len; - unsigned char *tempstart; + utf8_t *tempstart; size_t templen; - unsigned char *namestart; + utf8_t *namestart; size_t namelen = 0; // !=0 if line continuation - unsigned char *textstart; + utf8_t *textstart; size_t textlen; while (p < pend) @@ -1674,7 +1731,7 @@ Ldone: * by whitespace and/or commas. */ -void DocComment::parseEscapes(Escape **pescapetable, unsigned char *textstart, size_t textlen) +void DocComment::parseEscapes(Escape **pescapetable, utf8_t *textstart, size_t textlen) { Escape *escapetable = *pescapetable; if (!escapetable) @@ -1683,8 +1740,8 @@ void DocComment::parseEscapes(Escape **pescapetable, unsigned char *textstart, s *pescapetable = escapetable; } //printf("parseEscapes('%.*s') pescapetable = %p\n", textlen, textstart, pescapetable); - unsigned char *p = textstart; - unsigned char *pend = p + textlen; + utf8_t *p = textstart; + utf8_t *pend = p + textlen; while (1) { @@ -1698,9 +1755,9 @@ void DocComment::parseEscapes(Escape **pescapetable, unsigned char *textstart, s } if (p[0] != '/' || p[2] != '/') return; - unsigned char c = p[1]; + utf8_t c = p[1]; p += 3; - unsigned char *start = p; + utf8_t *start = p; while (1) { if (p >= pend) @@ -1746,11 +1803,11 @@ int icmp(const char *stringz, void *s, size_t slen) * Return !=0 if comment consists entirely of "ditto". */ -int isDitto(unsigned char *comment) +int isDitto(utf8_t *comment) { if (comment) { - unsigned char *p = skipwhitespace(comment); + utf8_t *p = skipwhitespace(comment); if (Port::memicmp((char *)p, "ditto", 5) == 0 && *skipwhitespace(p + 5) == 0) return 1; @@ -1762,7 +1819,7 @@ int isDitto(unsigned char *comment) * Skip white space. */ -unsigned char *skipwhitespace(unsigned char *p) +utf8_t *skipwhitespace(utf8_t *p) { for (; 1; p++) { switch (*p) @@ -1791,7 +1848,7 @@ size_t skiptoident(OutBuffer *buf, size_t i) { dchar_t c; size_t oi = i; - if (utf_decodeChar((unsigned char *)buf->data, buf->offset, &i, &c)) + if (utf_decodeChar((utf8_t *)buf->data, buf->offset, &i, &c)) /* Ignore UTF errors, but still consume input */ break; @@ -1818,7 +1875,7 @@ size_t skippastident(OutBuffer *buf, size_t i) { dchar_t c; size_t oi = i; - if (utf_decodeChar((unsigned char *)buf->data, buf->offset, &i, &c)) + if (utf_decodeChar((utf8_t *)buf->data, buf->offset, &i, &c)) /* Ignore UTF errors, but still consume input */ break; @@ -1846,7 +1903,7 @@ size_t skippastident(OutBuffer *buf, size_t i) size_t skippastURL(OutBuffer *buf, size_t i) { size_t length = buf->offset - i; - unsigned char *p = &buf->data[i]; + utf8_t *p = &buf->data[i]; size_t j; unsigned sawdot = 0; @@ -1862,7 +1919,7 @@ size_t skippastURL(OutBuffer *buf, size_t i) goto Lno; for (; j < length; j++) - { unsigned char c = p[j]; + { utf8_t c = p[j]; if (isalnum(c)) continue; if (c == '-' || c == '_' || c == '?' || @@ -1888,7 +1945,7 @@ Lno: /**************************************************** */ -int isKeyword(unsigned char *p, size_t len) +int isKeyword(utf8_t *p, size_t len) { static const char *table[] = { "true", "false", "null" }; @@ -1903,10 +1960,17 @@ int isKeyword(unsigned char *p, size_t len) /**************************************************** */ -Parameter *isFunctionParameter(Dsymbol *s, unsigned char *p, size_t len) +TypeFunction *isTypeFunction(Dsymbol *s) { FuncDeclaration *f = s->isFuncDeclaration(); + /* Check whether s refers to an eponymous function template. + */ + if (f == NULL && s->isTemplateDeclaration() && s->isTemplateDeclaration()->onemember) + { + f = s->isTemplateDeclaration()->onemember->isFuncDeclaration(); + } + /* f->type may be NULL for template members. */ if (f && f->type) @@ -1919,15 +1983,45 @@ Parameter *isFunctionParameter(Dsymbol *s, unsigned char *p, size_t len) else tf = (TypeFunction *)f->type; - if (tf->parameters) - { - for (size_t k = 0; k < tf->parameters->dim; k++) - { Parameter *arg = (*tf->parameters)[k]; + return tf; + } + return NULL; +} - if (arg->ident && cmp(arg->ident->toChars(), p, len) == 0) - { - return arg; - } +/**************************************************** + */ + +Parameter *isFunctionParameter(Dsymbol *s, utf8_t *p, size_t len) +{ + TypeFunction *tf = isTypeFunction(s); + if (tf && tf->parameters) + { + for (size_t k = 0; k < tf->parameters->dim; k++) + { + Parameter *arg = (*tf->parameters)[k]; + if (arg->ident && cmp(arg->ident->toChars(), p, len) == 0) + { + return arg; + } + } + } + return NULL; +} + +/**************************************************** + */ + +TemplateParameter *isTemplateParameter(Dsymbol *s, utf8_t *p, size_t len) +{ + TemplateDeclaration *td = s->isTemplateDeclaration(); + if (td && td->origParameters) + { + for (size_t k = 0; k < td->origParameters->dim; k++) + { + TemplateParameter *arg = (*td->origParameters)[k]; + if (arg->ident && cmp(arg->ident->toChars(), p, len) == 0) + { + return arg; } } } @@ -1943,7 +2037,7 @@ void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, size_t offset) //printf("highlightText()\n"); const char *sid = s->ident->toChars(); FuncDeclaration *f = s->isFuncDeclaration(); - unsigned char *p; + utf8_t *p; const char *se; int leadingBlank = 1; @@ -1955,7 +2049,7 @@ void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, size_t offset) size_t iLineStart = offset; for (size_t i = offset; i < buf->offset; i++) - { unsigned char c = buf->data[i]; + { utf8_t c = buf->data[i]; Lcont: switch (c) @@ -1970,7 +2064,7 @@ void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, size_t offset) { static char blankline[] = "$(DDOC_BLANKLINE)\n"; - i = buf->insert(i, blankline, sizeof(blankline) - 1); + i = buf->insert(i, blankline, strlen(blankline)); } leadingBlank = 1; iLineStart = i + 1; @@ -2126,13 +2220,13 @@ void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, size_t offset) // Remove leading indentations from all lines bool lineStart = true; - unsigned char *endp = codebuf.data + codebuf.offset; - for (unsigned char *p = codebuf.data; p < endp; ) + utf8_t *endp = codebuf.data + codebuf.offset; + for (utf8_t *p = codebuf.data; p < endp; ) { if (lineStart) { size_t j = codeIndent; - unsigned char *q = p; + utf8_t *q = p; while (j-- > 0 && q < endp && isIndentWS(q)) ++q; codebuf.remove(p - codebuf.data, q - p); @@ -2158,7 +2252,7 @@ void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, size_t offset) inCode = 1; codeIndent = istart - iLineStart; // save indent count - i = buf->insert(i, pre, sizeof(pre) - 1); + i = buf->insert(i, pre, strlen(pre)); iCodeStart = i; i--; // place i on > leadingBlank = true; @@ -2237,7 +2331,7 @@ void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, size_t offset, bool an //printf("highlightCode(s = '%s', kind = %s)\n", sid, s->kind()); for (size_t i = offset; i < buf->offset; i++) - { unsigned char c = buf->data[i]; + { utf8_t c = buf->data[i]; const char *se; se = sc->module->escapetable->escapeChar(c); @@ -2276,7 +2370,7 @@ void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, size_t offset, bool an /**************************************** */ -void highlightCode3(Scope *sc, OutBuffer *buf, unsigned char *p, unsigned char *pend) +void highlightCode3(Scope *sc, OutBuffer *buf, utf8_t *p, utf8_t *pend) { for (; p < pend; p++) { const char *s = sc->module->escapetable->escapeChar(*p); @@ -2294,13 +2388,13 @@ void highlightCode3(Scope *sc, OutBuffer *buf, unsigned char *p, unsigned char * void highlightCode2(Scope *sc, Dsymbol *s, OutBuffer *buf, size_t offset) { - char *sid = s->ident->toChars(); + const char *sid = s->ident->toChars(); FuncDeclaration *f = s->isFuncDeclaration(); unsigned errorsave = global.errors; Lexer lex(NULL, buf->data, 0, buf->offset - 1, 0, 1); Token tok; OutBuffer res; - unsigned char *lastp = buf->data; + utf8_t *lastp = buf->data; const char *highlight; if (s->isModule() && ((Module *)s)->isDocFile) @@ -2348,10 +2442,16 @@ void highlightCode2(Scope *sc, Dsymbol *s, OutBuffer *buf, size_t offset) break; } if (highlight) + { res.writestring(highlight); - highlightCode3(sc, &res, tok.ptr, lex.p); - if (highlight) + size_t o = res.offset; + highlightCode3(sc, &res, tok.ptr, lex.p); + if (tok.value == TOKcomment || tok.value == TOKstring) + escapeDdocString(&res, o); // Bugzilla 7656, 7715, and 10519 res.writeByte(')'); + } + else + highlightCode3(sc, &res, tok.ptr, lex.p); if (tok.value == TOKeof) break; lastp = lex.p; @@ -2396,7 +2496,7 @@ const char *Escape::escapeChar(unsigned c) * Determine if p points to the start of an identifier. */ -int isIdStart(unsigned char *p) +int isIdStart(utf8_t *p) { unsigned c = *p; if (isalpha(c) || c == '_') @@ -2415,7 +2515,7 @@ int isIdStart(unsigned char *p) * Determine if p points to the rest of an identifier. */ -int isIdTail(unsigned char *p) +int isIdTail(utf8_t *p) { unsigned c = *p; if (isalnum(c) || c == '_') @@ -2434,7 +2534,7 @@ int isIdTail(unsigned char *p) * Determine if p points to the indentation space. */ -int isIndentWS(unsigned char *p) +int isIndentWS(utf8_t *p) { return (*p == ' ') || (*p == '\t'); } @@ -2443,7 +2543,7 @@ int isIndentWS(unsigned char *p) * Return number of bytes in UTF character. */ -int utfStride(unsigned char *p) +int utfStride(utf8_t *p) { unsigned c = *p; if (c < 0x80) diff --git a/dmd2/dsymbol.c b/dmd2/dsymbol.c index 20da3e69..d401d3e9 100644 --- a/dmd2/dsymbol.c +++ b/dmd2/dsymbol.c @@ -53,10 +53,11 @@ Dsymbol::Dsymbol() this->loc = Loc(); this->comment = NULL; this->scope = NULL; + this->semanticRun = PASSinit; this->errors = false; this->depmsg = NULL; this->userAttributes = NULL; - this->unittest = NULL; + this->ddocUnittest = NULL; #if IN_LLVM this->llvmInternal = LLVMnone; #endif @@ -74,25 +75,25 @@ Dsymbol::Dsymbol(Identifier *ident) this->loc = Loc(); this->comment = NULL; this->scope = NULL; + this->semanticRun = PASSinit; this->errors = false; this->depmsg = NULL; this->userAttributes = NULL; - this->unittest = NULL; + this->ddocUnittest = NULL; #if IN_LLVM this->llvmInternal = LLVMnone; #endif } -int Dsymbol::equals(Object *o) -{ Dsymbol *s; - +bool Dsymbol::equals(RootObject *o) +{ if (this == o) - return TRUE; - s = (Dsymbol *)(o); + return true; + Dsymbol *s = (Dsymbol *)(o); // Overload sets don't have an ident if (s && ident && s->ident && ident->equals(s->ident)) - return TRUE; - return FALSE; + return true; + return false; } /************************************** @@ -112,23 +113,23 @@ Dsymbol *Dsymbol::syntaxCopy(Dsymbol *s) /************************************** * Determine if this symbol is only one. * Returns: - * FALSE, *ps = NULL: There are 2 or more symbols - * TRUE, *ps = NULL: There are zero symbols - * TRUE, *ps = symbol: The one and only one symbol + * false, *ps = NULL: There are 2 or more symbols + * true, *ps = NULL: There are zero symbols + * true, *ps = symbol: The one and only one symbol */ -int Dsymbol::oneMember(Dsymbol **ps, Identifier *ident) +bool Dsymbol::oneMember(Dsymbol **ps, Identifier *ident) { //printf("Dsymbol::oneMember()\n"); *ps = this; - return TRUE; + return true; } /***************************************** * Same as Dsymbol::oneMember(), but look at an array of Dsymbols. */ -int Dsymbol::oneMembers(Dsymbols *members, Dsymbol **ps, Identifier *ident) +bool Dsymbol::oneMembers(Dsymbols *members, Dsymbol **ps, Identifier *ident) { //printf("Dsymbol::oneMembers() %d\n", members ? members->dim : 0); Dsymbol *s = NULL; @@ -138,46 +139,61 @@ int Dsymbol::oneMembers(Dsymbols *members, Dsymbol **ps, Identifier *ident) for (size_t i = 0; i < members->dim; i++) { Dsymbol *sx = (*members)[i]; - int x = sx->oneMember(ps, ident); + bool x = sx->oneMember(ps, ident); //printf("\t[%d] kind %s = %d, s = %p\n", i, sx->kind(), x, *ps); if (!x) { //printf("\tfalse 1\n"); assert(*ps == NULL); - return FALSE; + return false; } if (*ps) { - if (ident) - { - if (!(*ps)->ident || !(*ps)->ident->equals(ident)) - continue; - } + assert(ident); + if (!(*ps)->ident || !(*ps)->ident->equals(ident)) + continue; if (!s) s = *ps; else if (s->isOverloadable() && (*ps)->isOverloadable()) - ; // keep head of overload set + { + // keep head of overload set + FuncDeclaration *f1 = s->isFuncDeclaration(); + FuncDeclaration *f2 = (*ps)->isFuncDeclaration(); + if (f1 && f2) + { + assert(!f1->isFuncAliasDeclaration()); + assert(!f2->isFuncAliasDeclaration()); + for (; f1 != f2; f1 = f1->overnext0) + { + if (f1->overnext0 == NULL) + { + f1->overnext0 = f2; + break; + } + } + } + } else // more than one symbol { *ps = NULL; //printf("\tfalse 2\n"); - return FALSE; + return false; } } } } *ps = s; // s is the one symbol, NULL if none //printf("\ttrue\n"); - return TRUE; + return true; } /***************************************** * Is Dsymbol a variable that contains pointers? */ -int Dsymbol::hasPointers() +bool Dsymbol::hasPointers() { //printf("Dsymbol::hasPointers() %s\n", toChars()); - return 0; + return false; } bool Dsymbol::hasStaticCtorOrDtor() @@ -190,6 +206,11 @@ void Dsymbol::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool i { } +Identifier *Dsymbol::getIdent() +{ + return ident; +} + char *Dsymbol::toChars() { return ident ? ident->toChars() : (char *)"__anonymous"; @@ -315,9 +336,9 @@ TemplateInstance *Dsymbol::isSpeculative() return NULL; } -int Dsymbol::isAnonymous() +bool Dsymbol::isAnonymous() { - return ident ? 0 : 1; + return ident == NULL; } /************************************* @@ -343,10 +364,6 @@ void Dsymbol::importAll(Scope *sc) * Does semantic analysis on the public face of declarations. */ -void Dsymbol::semantic0(Scope *sc) -{ -} - void Dsymbol::semantic(Scope *sc) { error("%p has no semantic routine", this); @@ -414,8 +431,7 @@ void *symbol_search_fp(void *arg, const char *seed) assert(id); Dsymbol *s = (Dsymbol *)arg; - Module::clearCache(); - return s->search(Loc(), id, 4|2); + return (void *)s->search(Loc(), id, 4|2); } Dsymbol *Dsymbol::search_correct(Identifier *ident) @@ -423,7 +439,7 @@ Dsymbol *Dsymbol::search_correct(Identifier *ident) if (global.gag) return NULL; // don't do it for speculative compiles; too time consuming - return (Dsymbol *)speller(ident->toChars(), &symbol_search_fp, this, idchars); + return (Dsymbol *)speller(ident->toChars(), &symbol_search_fp, (void *)this, idchars); } /*************************************** @@ -433,7 +449,7 @@ Dsymbol *Dsymbol::search_correct(Identifier *ident) * symbol found, NULL if not */ -Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, Object *id) +Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, RootObject *id) { //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars()); Dsymbol *s = toAlias(); @@ -483,10 +499,10 @@ Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, Object *id) return sm; } -int Dsymbol::overloadInsert(Dsymbol *s) +bool Dsymbol::overloadInsert(Dsymbol *s) { //printf("Dsymbol::overloadInsert('%s')\n", s->toChars()); - return FALSE; + return false; } void Dsymbol::toCBuffer(OutBuffer *buf, HdrGenState *hgs) @@ -500,9 +516,9 @@ unsigned Dsymbol::size(Loc loc) return 0; } -int Dsymbol::isforwardRef() +bool Dsymbol::isforwardRef() { - return FALSE; + return false; } AggregateDeclaration *Dsymbol::isThis() @@ -537,14 +553,14 @@ void Dsymbol::defineRef(Dsymbol *s) assert(0); } -int Dsymbol::isExport() +bool Dsymbol::isExport() { - return FALSE; + return false; } -int Dsymbol::isImportedSymbol() +bool Dsymbol::isImportedSymbol() { - return FALSE; + return false; } bool Dsymbol::isDeprecated() @@ -553,14 +569,14 @@ bool Dsymbol::isDeprecated() } #if DMDV2 -int Dsymbol::isOverloadable() +bool Dsymbol::isOverloadable() { - return 0; + return false; } -int Dsymbol::hasOverloads() +bool Dsymbol::hasOverloads() { - return 0; + return false; } #endif @@ -582,9 +598,9 @@ Type *Dsymbol::getType() return NULL; } -int Dsymbol::needThis() +bool Dsymbol::needThis() { - return FALSE; + return false; } int Dsymbol::apply(Dsymbol_apply_ft_t fp, void *param) @@ -756,7 +772,7 @@ Module *Dsymbol::getAccessModule() /************************************* */ -enum PROT Dsymbol::prot() +PROT Dsymbol::prot() { return PROTpublic; } @@ -790,7 +806,7 @@ Dsymbols *Dsymbol::arraySyntaxCopy(Dsymbols *a) * Ignore NULL comments. */ -void Dsymbol::addComment(unsigned char *comment) +void Dsymbol::addComment(utf8_t *comment) { //if (comment) //printf("adding comment '%s' to symbol %p '%s'\n", comment, this, toChars()); @@ -858,35 +874,44 @@ Dsymbol *ScopeDsymbol::syntaxCopy(Dsymbol *s) return sd; } +/***************************************** + * This function is #1 on the list of functions that eat cpu time. + * Be very, very careful about slowing it down. + */ + Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags) { //printf("%s->ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident->toChars(), flags); //if (strcmp(ident->toChars(),"c") == 0) *(char*)0=0; // Look in symbols declared in this module - Dsymbol *s = symtab ? symtab->lookup(ident) : NULL; - //printf("\ts = %p, imports = %p, %d\n", s, imports, imports ? imports->dim : 0); - if (s) + Dsymbol *s1 = symtab ? symtab->lookup(ident) : NULL; + //printf("\ts1 = %p, imports = %p, %d\n", s1, imports, imports ? imports->dim : 0); + if (s1) { - //printf("\ts = '%s.%s'\n",toChars(),s->toChars()); + //printf("\ts = '%s.%s'\n",toChars(),s1->toChars()); + return s1; } - else if (imports) + else if (!imports) + return NULL; + else { + Dsymbol *s = NULL; OverloadSet *a = NULL; // Look in imported modules for (size_t i = 0; i < imports->dim; i++) - { Dsymbol *ss = (*imports)[i]; - Dsymbol *s2; - + { // If private import, don't search it if (flags & 1 && prots[i] == PROTprivate) continue; + Dsymbol *ss = (*imports)[i]; + //printf("\tscanning import '%s', prots = %d, isModule = %p, isImport = %p\n", ss->toChars(), prots[i], ss->isModule(), ss->isImport()); /* Don't find private members if ss is a module */ - s2 = ss->search(loc, ident, ss->isModule() ? 1 : 0); + Dsymbol *s2 = ss->search(loc, ident, ss->isModule() ? 1 : 0); if (!s) s = s2; else if (s2 && s != s2) @@ -931,7 +956,10 @@ Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags) */ if (s2->isOverloadable() && (a || s->isOverloadable())) { if (!a) + { a = new OverloadSet(s->ident); + a->parent = this; + } /* Don't add to a[] if s2 is alias of previous sym */ for (size_t j = 0; j < a->a.dim; j++) @@ -968,33 +996,17 @@ Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags) if (s) { - if (!(flags & 2)) - { Declaration *d = s->isDeclaration(); - if (d && d->protection == PROTprivate && - !d->parent->isTemplateMixin()) - error(loc, "%s is private", d->toPrettyChars()); - - AggregateDeclaration *ad = s->isAggregateDeclaration(); - if (ad && ad->protection == PROTprivate && - !ad->parent->isTemplateMixin()) - error(loc, "%s is private", ad->toPrettyChars()); - - EnumDeclaration *ed = s->isEnumDeclaration(); - if (ed && ed->protection == PROTprivate && - !ed->parent->isTemplateMixin()) - error(loc, "%s is private", ed->toPrettyChars()); - - TemplateDeclaration *td = s->isTemplateDeclaration(); - if (td && td->protection == PROTprivate && - !td->parent->isTemplateMixin()) - error(loc, "%s is private", td->toPrettyChars()); + if (!(flags & 2) && s->prot() == PROTprivate && !s->parent->isTemplateMixin()) + { + if (!s->isImport()) + error(loc, "%s %s is private", s->kind(), s->toPrettyChars()); } } + return s; } - return s; } -void ScopeDsymbol::importScope(Dsymbol *s, enum PROT protection) +void ScopeDsymbol::importScope(Dsymbol *s, PROT protection) { //printf("%s->ScopeDsymbol::importScope(%s, %d)\n", toChars(), s->toChars(), protection); @@ -1021,7 +1033,7 @@ void ScopeDsymbol::importScope(Dsymbol *s, enum PROT protection) } } -int ScopeDsymbol::isforwardRef() +bool ScopeDsymbol::isforwardRef() { return (members == NULL); } @@ -1251,7 +1263,24 @@ WithScopeSymbol::WithScopeSymbol(WithStatement *withstate) Dsymbol *WithScopeSymbol::search(Loc loc, Identifier *ident, int flags) { // Acts as proxy to the with class declaration - return withstate->exp->type->toDsymbol(NULL)->search(loc, ident, 0); + Dsymbol *s = NULL; + Expression *eold = NULL; + for (Expression *e = withstate->exp; e != eold; e = resolveAliasThis(scope, e)) + { + Type *t = e->type->toBasetype(); + if (t->ty == Taarray) + s = ((TypeAArray *)t)->getImpl(); + else + s = t->toDsymbol(NULL); + if (s) + { + s = s->search(loc, ident, 0); + if (s) + return s; + } + eold = e; + } + return NULL; } /****************************** ArrayScopeSymbol ******************************/ @@ -1398,29 +1427,6 @@ Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags) return NULL; s = s->toAlias(); - if (ce->hasSideEffect()) - { - /* Even if opDollar is needed, 'ce' should be evaluate only once. So - * Rewrite: - * ce.opIndex( ... use of $ ... ) - * ce.opSlice( ... use of $ ... ) - * as: - * (ref __dop = ce, __dop).opIndex( ... __dop.opDollar ...) - * (ref __dop = ce, __dop).opSlice( ... __dop.opDollar ...) - */ - Identifier *id = Lexer::uniqueId("__dop"); - ExpInitializer *ei = new ExpInitializer(loc, ce); - VarDeclaration *v = new VarDeclaration(loc, NULL, id, ei); - v->storage_class |= STCctfe | STCforeach | STCref; - DeclarationExp *de = new DeclarationExp(loc, v); - VarExp *ve = new VarExp(loc, v); - v->semantic(sc); - de->type = ce->type; - ve->type = ce->type; - ((UnaExp *)exp)->e1 = new CommaExp(loc, de, ve); - ce = ve; - } - Expression *e = NULL; // Check for multi-dimensional opDollar(dim) template. if (TemplateDeclaration *td = s->isTemplateDeclaration()) @@ -1492,90 +1498,42 @@ Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags) DsymbolTable::DsymbolTable() { -#if STRINGTABLE - tab = new StringTable; - tab->init(); -#else tab = NULL; -#endif -} - -DsymbolTable::~DsymbolTable() -{ -#if STRINGTABLE - delete tab; -#endif } Dsymbol *DsymbolTable::lookup(Identifier *ident) { -#if STRINGTABLE -#ifdef DEBUG - assert(ident); - assert(tab); -#endif - //printf("DsymbolTable::lookup(%s)\n", (char*)ident->string); - StringValue *sv = tab->lookup((char*)ident->string, ident->len); - return (Dsymbol *)(sv ? sv->ptrvalue : NULL); -#else //printf("DsymbolTable::lookup(%s)\n", (char*)ident->string); return (Dsymbol *)_aaGetRvalue(tab, ident); -#endif } Dsymbol *DsymbolTable::insert(Dsymbol *s) { //printf("DsymbolTable::insert(this = %p, '%s')\n", this, s->ident->toChars()); Identifier *ident = s->ident; -#if STRINGTABLE -#ifdef DEBUG - assert(ident); - assert(tab); -#endif - StringValue *sv = tab->insert(ident->toChars(), ident->len); - if (!sv) - return NULL; // already in table - sv->ptrvalue = s; - return s; -#else Dsymbol **ps = (Dsymbol **)_aaGet(&tab, ident); if (*ps) return NULL; // already in table *ps = s; return s; -#endif } Dsymbol *DsymbolTable::insert(Identifier *ident, Dsymbol *s) { //printf("DsymbolTable::insert()\n"); -#if STRINGTABLE - StringValue *sv = tab->insert(ident->toChars(), ident->len); - if (!sv) - return NULL; // already in table - sv->ptrvalue = s; - return s; -#else Dsymbol **ps = (Dsymbol **)_aaGet(&tab, ident); if (*ps) return NULL; // already in table *ps = s; return s; -#endif } Dsymbol *DsymbolTable::update(Dsymbol *s) { Identifier *ident = s->ident; -#if STRINGTABLE - StringValue *sv = tab->update(ident->toChars(), ident->len); - sv->ptrvalue = s; - return s; -#else Dsymbol **ps = (Dsymbol **)_aaGet(&tab, ident); *ps = s; return s; -#endif } diff --git a/dmd2/dsymbol.h b/dmd2/dsymbol.h index 9e32403c..f2b188e6 100644 --- a/dmd2/dsymbol.h +++ b/dmd2/dsymbol.h @@ -29,66 +29,65 @@ #include "../ir/irdsymbol.h" #endif -struct Identifier; +class Identifier; struct Scope; -struct DsymbolTable; -struct Declaration; -struct ThisDeclaration; -struct TupleDeclaration; -struct TypedefDeclaration; -struct AliasDeclaration; -struct AggregateDeclaration; -struct EnumDeclaration; -struct ClassDeclaration; -struct InterfaceDeclaration; -struct StructDeclaration; -struct UnionDeclaration; -struct FuncDeclaration; -struct FuncAliasDeclaration; -struct FuncLiteralDeclaration; -struct CtorDeclaration; -struct PostBlitDeclaration; -struct DtorDeclaration; -struct StaticCtorDeclaration; -struct StaticDtorDeclaration; -struct SharedStaticCtorDeclaration; -struct SharedStaticDtorDeclaration; -struct InvariantDeclaration; -struct UnitTestDeclaration; -struct NewDeclaration; -struct VarDeclaration; -struct AttribDeclaration; +class DsymbolTable; +class Declaration; +class ThisDeclaration; +class TypeInfoDeclaration; +class TupleDeclaration; +class TypedefDeclaration; +class AliasDeclaration; +class AggregateDeclaration; +class EnumDeclaration; +class ClassDeclaration; +class InterfaceDeclaration; +class StructDeclaration; +class UnionDeclaration; +class FuncDeclaration; +class FuncAliasDeclaration; +class FuncLiteralDeclaration; +class CtorDeclaration; +class PostBlitDeclaration; +class DtorDeclaration; +class StaticCtorDeclaration; +class StaticDtorDeclaration; +class SharedStaticCtorDeclaration; +class SharedStaticDtorDeclaration; +class InvariantDeclaration; +class UnitTestDeclaration; +class NewDeclaration; +class VarDeclaration; +class AttribDeclaration; #if IN_DMD struct Symbol; #endif -struct Package; -struct Module; -struct Import; -struct Type; -struct TypeTuple; -struct WithStatement; -struct LabelDsymbol; -struct ScopeDsymbol; -struct TemplateDeclaration; -struct TemplateInstance; -struct TemplateMixin; -struct EnumMember; -struct ScopeDsymbol; -struct WithScopeSymbol; -struct ArrayScopeSymbol; -struct SymbolDeclaration; -struct Expression; -struct DeleteDeclaration; +class Package; +class Module; +class Import; +class Type; +class TypeTuple; +class WithStatement; +class LabelDsymbol; +class ScopeDsymbol; +class TemplateDeclaration; +class TemplateInstance; +class TemplateMixin; +class EnumMember; +class WithScopeSymbol; +class ArrayScopeSymbol; +class SymbolDeclaration; +class Expression; +class DeleteDeclaration; struct HdrGenState; -struct OverloadSet; +class OverloadSet; struct AA; struct JsonOut; #if IN_LLVM -struct TypeInfoDeclaration; -struct ClassInfoDeclaration; +class TypeInfoDeclaration; +class ClassInfoDeclaration; #endif #ifdef IN_GCC -union tree_node; typedef union tree_node TYPE; #else struct TYPE; @@ -127,37 +126,42 @@ enum PASS PASSinit, // initial state PASSsemantic, // semantic() started PASSsemanticdone, // semantic() done - PASSsemantic2, // semantic2() run + PASSsemantic2, // semantic2() started + PASSsemantic2done, // semantic2() done PASSsemantic3, // semantic3() started PASSsemantic3done, // semantic3() done + PASSinline, // inline started + PASSinlinedone, // inline done PASSobj, // toObjFile() run }; typedef int (*Dsymbol_apply_ft_t)(Dsymbol *, void *); -struct Dsymbol : Object +class Dsymbol : public RootObject { +public: Identifier *ident; Dsymbol *parent; #if IN_DMD Symbol *csym; // symbol for code generator Symbol *isym; // import version of csym #endif - unsigned char *comment; // documentation comment for this Dsymbol + utf8_t *comment; // documentation comment for this Dsymbol Loc loc; // where defined Scope *scope; // !=NULL means context to use for semantic() bool errors; // this symbol failed to pass semantic() + PASS semanticRun; char *depmsg; // customized deprecation message Expressions *userAttributes; // user defined attributes from UserAttributeDeclaration - UnitTestDeclaration *unittest; // !=NULL means there's a unittest associated with this symbol + UnitTestDeclaration *ddocUnittest; // !=NULL means there's a ddoc unittest associated with this symbol (only use this with ddoc) Dsymbol(); Dsymbol(Identifier *); char *toChars(); Loc& getLoc(); char *locToChars(); - int equals(Object *o); - int isAnonymous(); + bool equals(RootObject *o); + bool isAnonymous(); void error(Loc loc, const char *format, ...); void error(const char *format, ...); void deprecation(Loc loc, const char *format, ...); @@ -170,11 +174,13 @@ struct Dsymbol : Object Dsymbol *toParent2(); TemplateInstance *inTemplateInstance(); TemplateInstance *isSpeculative(); + Ungag ungagSpeculative(); int dyncast() { return DYNCAST_DSYMBOL; } // kludge for template.isSymbol() static Dsymbols *arraySyntaxCopy(Dsymbols *a); + virtual Identifier *getIdent(); virtual const char *toPrettyChars(); virtual const char *kind(); virtual Dsymbol *toAlias(); // resolve real symbol @@ -182,50 +188,49 @@ struct Dsymbol : Object virtual int addMember(Scope *sc, ScopeDsymbol *s, int memnum); virtual void setScope(Scope *sc); virtual void importAll(Scope *sc); - virtual void semantic0(Scope *sc); virtual void semantic(Scope *sc); virtual void semantic2(Scope *sc); virtual void semantic3(Scope *sc); virtual void inlineScan(); virtual Dsymbol *search(Loc loc, Identifier *ident, int flags); Dsymbol *search_correct(Identifier *id); - Dsymbol *searchX(Loc loc, Scope *sc, Object *id); - virtual int overloadInsert(Dsymbol *s); + Dsymbol *searchX(Loc loc, Scope *sc, RootObject *id); + virtual bool overloadInsert(Dsymbol *s); virtual void toHBuffer(OutBuffer *buf, HdrGenState *hgs); virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs); virtual void toDocBuffer(OutBuffer *buf, Scope *sc); virtual void toJson(JsonOut *json); virtual void jsonProperties(JsonOut *json); virtual unsigned size(Loc loc); - virtual int isforwardRef(); + virtual bool isforwardRef(); virtual void defineRef(Dsymbol *s); virtual AggregateDeclaration *isThis(); // is a 'this' required to access the member AggregateDeclaration *isAggregateMember(); // are we a member of an aggregate? AggregateDeclaration *isAggregateMember2(); // are we a member of an aggregate? ClassDeclaration *isClassMember(); // are we a member of a class? - virtual int isExport(); // is Dsymbol exported? - virtual int isImportedSymbol(); // is Dsymbol imported? + virtual bool isExport(); // is Dsymbol exported? + virtual bool isImportedSymbol(); // is Dsymbol imported? virtual bool isDeprecated(); // is Dsymbol deprecated? #if DMDV2 - virtual int isOverloadable(); - virtual int hasOverloads(); + virtual bool isOverloadable(); + virtual bool hasOverloads(); #endif virtual LabelDsymbol *isLabel(); // is this a LabelDsymbol? virtual AggregateDeclaration *isMember(); // is this symbol a member of an AggregateDeclaration? virtual Type *getType(); // is this a type? virtual const char *mangle(bool isv = false); - virtual int needThis(); // need a 'this' pointer? - virtual enum PROT prot(); + virtual bool needThis(); // need a 'this' pointer? + virtual PROT prot(); virtual Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees - virtual int oneMember(Dsymbol **ps, Identifier *ident); - static int oneMembers(Dsymbols *members, Dsymbol **ps, Identifier *ident = NULL); + virtual bool oneMember(Dsymbol **ps, Identifier *ident); + static bool oneMembers(Dsymbols *members, Dsymbol **ps, Identifier *ident); virtual void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); - virtual int hasPointers(); + virtual bool hasPointers(); virtual bool hasStaticCtorOrDtor(); virtual void addLocalClass(ClassDeclarations *) { } virtual void checkCtorConstInit() { } - virtual void addComment(unsigned char *comment); + virtual void addComment(utf8_t *comment); virtual void emitComment(Scope *sc); void emitDitto(Scope *sc); @@ -251,6 +256,7 @@ struct Dsymbol : Object virtual TemplateMixin *isTemplateMixin() { return NULL; } virtual Declaration *isDeclaration() { return NULL; } virtual ThisDeclaration *isThisDeclaration() { return NULL; } + virtual TypeInfoDeclaration *isTypeInfoDeclaration() { return NULL; } virtual TupleDeclaration *isTupleDeclaration() { return NULL; } virtual TypedefDeclaration *isTypedefDeclaration() { return NULL; } virtual AliasDeclaration *isAliasDeclaration() { return NULL; } @@ -283,7 +289,6 @@ struct Dsymbol : Object virtual AttribDeclaration *isAttribDeclaration() { return NULL; } virtual OverloadSet *isOverloadSet() { return NULL; } #if IN_LLVM - virtual TypeInfoDeclaration* isTypeInfoDeclaration() { return NULL; } virtual ClassInfoDeclaration* isClassInfoDeclaration() { return NULL; } /// Codegen traversal @@ -298,8 +303,9 @@ struct Dsymbol : Object // Dsymbol that generates a scope -struct ScopeDsymbol : Dsymbol +class ScopeDsymbol : public Dsymbol { +public: Dsymbols *members; // all Dsymbol's in this scope DsymbolTable *symtab; // members[] sorted into table @@ -310,8 +316,8 @@ struct ScopeDsymbol : Dsymbol ScopeDsymbol(Identifier *id); Dsymbol *syntaxCopy(Dsymbol *s); Dsymbol *search(Loc loc, Identifier *ident, int flags); - void importScope(Dsymbol *s, enum PROT protection); - int isforwardRef(); + void importScope(Dsymbol *s, PROT protection); + bool isforwardRef(); void defineRef(Dsymbol *s); static void multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2); Dsymbol *nameCollision(Dsymbol *s); @@ -333,8 +339,9 @@ struct ScopeDsymbol : Dsymbol // With statement scope -struct WithScopeSymbol : ScopeDsymbol +class WithScopeSymbol : public ScopeDsymbol { +public: WithStatement *withstate; WithScopeSymbol(WithStatement *withstate); @@ -345,8 +352,9 @@ struct WithScopeSymbol : ScopeDsymbol // Array Index/Slice scope -struct ArrayScopeSymbol : ScopeDsymbol +class ArrayScopeSymbol : public ScopeDsymbol { +public: Expression *exp; // IndexExp or SliceExp TypeTuple *type; // for tuple[length] TupleDeclaration *td; // for tuples of objects @@ -363,8 +371,9 @@ struct ArrayScopeSymbol : ScopeDsymbol // Overload Sets #if DMDV2 -struct OverloadSet : Dsymbol +class OverloadSet : public Dsymbol { +public: Dsymbols a; // array of Dsymbols OverloadSet(Identifier *ident); @@ -376,12 +385,12 @@ struct OverloadSet : Dsymbol // Table of Dsymbol's -struct DsymbolTable : Object +class DsymbolTable : public RootObject { +public: AA *tab; DsymbolTable(); - ~DsymbolTable(); // Look up Identifier. Return Dsymbol if found, NULL if not. Dsymbol *lookup(Identifier *ident); diff --git a/dmd2/entity.c b/dmd2/entity.c index 53d25391..2333a95f 100644 --- a/dmd2/entity.c +++ b/dmd2/entity.c @@ -11,6 +11,8 @@ #include #include +#include "port.h" + /********************************************* * Convert from named entity to its encoding. * For reference: @@ -2372,7 +2374,7 @@ static NameId* namesTable[] = { namesS, namesT, namesU, namesV, namesW, namesX, namesY, namesZ, NULL }; -int HtmlNamedEntity(unsigned char *p, size_t length) +int HtmlNamedEntity(utf8_t *p, size_t length) { int tableIndex = tolower(*p) - 'a'; if (tableIndex >= 0 && tableIndex < 26) diff --git a/dmd2/enum.c b/dmd2/enum.c index 9b665c71..15f31852 100644 --- a/dmd2/enum.c +++ b/dmd2/enum.c @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2011 by Digital Mars +// Copyright (c) 1999-2013 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -25,6 +25,7 @@ EnumDeclaration::EnumDeclaration(Loc loc, Identifier *id, Type *memtype) : ScopeDsymbol(id) { + //printf("EnumDeclaration() %s\n", toChars()); this->loc = loc; type = new TypeEnum(this); this->memtype = memtype; @@ -35,12 +36,9 @@ EnumDeclaration::EnumDeclaration(Loc loc, Identifier *id, Type *memtype) sinit = NULL; #endif isdeprecated = false; - isdone = 0; -#if IN_DMD - objFileDone = 0; -#endif protection = PROTundefined; parent = NULL; + added = false; } Dsymbol *EnumDeclaration::syntaxCopy(Dsymbol *s) @@ -70,80 +68,60 @@ Dsymbol *EnumDeclaration::syntaxCopy(Dsymbol *s) void EnumDeclaration::setScope(Scope *sc) { - if (isdone) + if (semanticRun > PASSinit) return; ScopeDsymbol::setScope(sc); } int EnumDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) { - if (!isAnonymous()) - return ScopeDsymbol::addMember(sc, sd, memnum); +#if 0 + printf("EnumDeclaration::addMember() %s\n", toChars()); + for (size_t i = 0; i < members->dim; i++) + { + EnumMember *em = (*members)[i]->isEnumMember(); + printf(" member %s\n", em->toChars()); + } +#endif /* Anonymous enum members get added to enclosing scope. */ - for (size_t i = 0; i < members->dim; i++) + ScopeDsymbol *scopesym = isAnonymous() ? sd : this; + + if (!isAnonymous()) { - EnumMember *em = (*members)[i]->isEnumMember(); - em->ed = this; - //printf("add %s\n", em->toChars()); - em->addMember(sc, sd, 1); + ScopeDsymbol::addMember(sc, sd, memnum); + + if (!symtab) + symtab = new DsymbolTable(); } + + if (members) + { + for (size_t i = 0; i < members->dim; i++) + { + EnumMember *em = (*members)[i]->isEnumMember(); + em->ed = this; + //printf("add %s to scope %s\n", em->toChars(), scopesym->toChars()); + em->addMember(sc, scopesym, 1); + } + } + added = true; return 1; } -void EnumDeclaration::semantic0(Scope *sc) -{ - /* This function is a hack to get around a significant problem. - * The members of anonymous enums, like: - * enum { A, B, C } - * don't get installed into the symbol table until after they are - * semantically analyzed, yet they're supposed to go into the enclosing - * scope's table. Hence, when forward referenced, they come out as - * 'undefined'. The real fix is to add them in at addSymbol() time. - * But to get code to compile, we'll just do this quick hack at the moment - * to compile it if it doesn't depend on anything else. - */ - - if (isdone || !scope) - return; - - parent = scope->parent; - protection = scope->protection; - - if (!isAnonymous() || memtype) - return; - for (size_t i = 0; i < members->dim; i++) - { - EnumMember *em = (*members)[i]->isEnumMember(); - if (em && (em->type || em->value)) - return; - } - - // Can do it - semantic(sc); -} void EnumDeclaration::semantic(Scope *sc) { - Type *t; - Scope *sce; - //printf("EnumDeclaration::semantic(sd = %p, '%s') %s\n", sc->scopesym, sc->scopesym->toChars(), toChars()); - //printf("EnumDeclaration::semantic() %s\n", toChars()); + //printf("EnumDeclaration::semantic() %p %s\n", this, toChars()); if (!members && !memtype) // enum ident; return; - if (!memtype && !isAnonymous()) - { // Set memtype if we can to reduce fwd reference errors - memtype = Type::tint32; // case 1) enum ident { ... } - } + if (semanticRun > PASSinit) + return; // semantic() already completed - if (symtab) // if already done - { if (isdone || !scope) - return; // semantic() already completed - } - else + if (!symtab) symtab = new DsymbolTable(); Scope *scx = NULL; @@ -167,8 +145,12 @@ void EnumDeclaration::semantic(Scope *sc) * 2. enum : memtype { ... } * 3. enum ident { ... } * 4. enum ident : memtype { ... } + * 5. enum ident : memtype; + * 6. enum ident; */ + type = type->semantic(loc, sc); + if (memtype) { memtype = memtype->semantic(loc, sc); @@ -192,207 +174,238 @@ void EnumDeclaration::semantic(Scope *sc) error("base type must not be void"); memtype = Type::terror; } -#if 0 // Decided to abandon this restriction for D 2.0 - if (!memtype->isintegral()) - { error("base type must be of integral type, not %s", memtype->toChars()); - memtype = Type::tint32; + if (memtype->ty == Terror) + { + errors = true; + if (members) + { + for (size_t i = 0; i < members->dim; i++) + { + Dsymbol *s = (*members)[i]; + s->errors = true; // poison all the members + } + } + semanticRun = PASSsemanticdone; + return; } -#endif } - isdone = 1; + semanticRun = PASSsemanticdone; if (!members) // enum ident : memtype; return; + if (members->dim == 0) + { + error("enum %s must have at least one member", toChars()); + errors = true; + return; + } + Module::dprogress++; - type = type->semantic(loc, sc); + Scope *sce; if (isAnonymous()) sce = sc; else { sce = sc->push(this); sce->parent = this; } - if (members->dim == 0) - error("enum %s must have at least one member", toChars()); + sce = sce->startCTFE(); + sce->setNoFree(); // needed for getMaxMinValue() - ScopeDsymbol *scopesym; - if (isAnonymous()) - { - /* Anonymous enum members get added to enclosing scope. - */ - for (Scope *sct = sce; sct; sct = sct->enclosing) - { - if (sct->scopesym) - { - scopesym = sct->scopesym; - if (!sct->scopesym->symtab) - sct->scopesym->symtab = new DsymbolTable(); - break; - } - } - } - else - scopesym = this; - - int first = 1; - Expression *elast = NULL; + /* Each enum member gets the sce scope + */ for (size_t i = 0; i < members->dim; i++) { EnumMember *em = (*members)[i]->isEnumMember(); - Expression *e; - Expression *emax = NULL; + if (em) + em->scope = sce; + } - if (!em) - /* The e->semantic(sce) can insert other symbols, such as - * template instances and function literals. - */ - continue; - - //printf(" Enum member '%s'\n",em->toChars()); - if (em->type) - em->type = em->type->semantic(em->loc, sce); - e = em->value; - if (e) - { - assert(e->dyncast() == DYNCAST_EXPRESSION); - e = e->ctfeSemantic(sce); - e = e->ctfeInterpret(); - if (memtype) - { - e = e->implicitCastTo(sce, memtype); - e = e->ctfeInterpret(); - if (!isAnonymous()) - e = e->castTo(sce, type); - t = memtype; - } - else if (em->type) - { - e = e->implicitCastTo(sce, em->type); - e = e->ctfeInterpret(); - assert(isAnonymous()); - t = e->type; - } - else - t = e->type; - } - else if (first) - { - if (memtype) - t = memtype; - else if (em->type) - t = em->type; - else - t = Type::tint32; - e = new IntegerExp(em->loc, 0, Type::tint32); - e = e->implicitCastTo(sce, t); - e = e->ctfeInterpret(); - if (!isAnonymous()) - e = e->castTo(sce, type); - } - else if (memtype && memtype == Type::terror) - { - e = new ErrorExp(); - minval = e; - maxval = e; - defaultval = e; - } - else - { - // Lazily evaluate enum.max - if (!emax) - { - emax = t->getProperty(Loc(), Id::max, 0); - emax = emax->ctfeSemantic(sce); - emax = emax->ctfeInterpret(); - } - - // Set value to (elast + 1). - // But first check that (elast != t.max) - assert(elast); - e = new EqualExp(TOKequal, em->loc, elast, emax); - e = e->ctfeSemantic(sce); - e = e->ctfeInterpret(); - if (e->toInteger()) - error("overflow of enum value %s", elast->toChars()); - - // Now set e to (elast + 1) - e = new AddExp(em->loc, elast, new IntegerExp(em->loc, 1, Type::tint32)); - e = e->ctfeSemantic(sce); - e = e->castTo(sce, elast->type); - e = e->ctfeInterpret(); - - if (t->isfloating()) - { - // Check that e != elast (not always true for floats) - Expression *etest = new EqualExp(TOKequal, em->loc, e, elast); - etest = etest->ctfeSemantic(sce); - etest = etest->ctfeInterpret(); - if (etest->toInteger()) - error("enum member %s has inexact value, due to loss of precision", em->toChars()); - } - } - elast = e; - em->value = e; - - // Add to symbol table only after evaluating 'value' - if (isAnonymous() && !sc->func) - { - // already inserted to enclosing scope in addMember - assert(em->ed); - } - else - { - em->ed = this; - em->addMember(sc, scopesym, 1); - } - - /* Compute .min, .max and .default values. - * If enum doesn't have a name, we can never identify the enum type, - * so there is no purpose for a .min, .max or .default + if (!added) + { + /* addMember() is not called when the EnumDeclaration appears as a function statement, + * so we have to do what addMember() does and install the enum members in the right symbol + * table */ - if (!isAnonymous() && memtype != Type::terror) + ScopeDsymbol *scopesym = NULL; + if (isAnonymous()) { - if (first) - { defaultval = e; - minval = e; - maxval = e; - } - else - { Expression *ec; - - /* In order to work successfully with UDTs, - * build expressions to do the comparisons, - * and let the semantic analyzer and constant - * folder give us the result. - */ - - // Compute if(e < minval) - ec = new CmpExp(TOKlt, em->loc, e, minval); - ec = ec->ctfeSemantic(sce); - ec = ec->ctfeInterpret(); - if (ec->toInteger()) - minval = e; - - ec = new CmpExp(TOKgt, em->loc, e, maxval); - ec = ec->ctfeSemantic(sce); - ec = ec->ctfeInterpret(); - if (ec->toInteger()) - maxval = e; + /* Anonymous enum members get added to enclosing scope. + */ + for (Scope *sct = sce; 1; sct = sct->enclosing) + { + assert(sct); + if (sct->scopesym) + { + scopesym = sct->scopesym; + if (!sct->scopesym->symtab) + sct->scopesym->symtab = new DsymbolTable(); + break; + } } } - first = 0; + else + // Otherwise enum members are in the EnumDeclaration's symbol table + scopesym = this; + + for (size_t i = 0; i < members->dim; i++) + { + EnumMember *em = (*members)[i]->isEnumMember(); + if (em) + { + em->ed = this; + em->addMember(sc, scopesym, 1); + } + } + } + + for (size_t i = 0; i < members->dim; i++) + { + EnumMember *em = (*members)[i]->isEnumMember(); + if (em) + em->semantic(em->scope); } //printf("defaultval = %lld\n", defaultval); //if (defaultval) printf("defaultval: %s %s\n", defaultval->toChars(), defaultval->type->toChars()); - if (sc != sce) - sce->pop(); //members->print(); } -int EnumDeclaration::oneMember(Dsymbol **ps, Identifier *ident) +/****************************** + * Get the value of the .max/.min property as an Expression + * Input: + * id Id::max or Id::min + */ + +Expression *EnumDeclaration::getMaxMinValue(Loc loc, Identifier *id) +{ + //printf("EnumDeclaration::getMaxValue()\n"); + bool first = true; + + Expression **pval = (id == Id::max) ? &maxval : &minval; + + if (*pval) + return *pval; + + if (scope) + semantic(scope); + if (errors) + goto Lerrors; + if (semanticRun == PASSinit || !members) + { + error("is forward referenced looking for .%s", id->toChars()); + goto Lerrors; + } + if (!(memtype && memtype->isintegral())) + { + error(loc, "has no .%s property because base type %s is not an integral type", + id->toChars(), + memtype ? memtype->toChars() : ""); + goto Lerrors; + } + + for (size_t i = 0; i < members->dim; i++) + { + EnumMember *em = (*members)[i]->isEnumMember(); + if (!em) + continue; + if (em->errors) + goto Lerrors; + + Expression *e = em->value; + if (first) + { + *pval = e; + first = false; + } + else + { + /* In order to work successfully with UDTs, + * build expressions to do the comparisons, + * and let the semantic analyzer and constant + * folder give us the result. + */ + + /* Compute: + * if (e > maxval) + * maxval = e; + */ + Expression *ec = new CmpExp(id == Id::max ? TOKgt : TOKlt, em->loc, e, *pval); + ec = ec->semantic(em->scope); + ec = ec->ctfeInterpret(); + if (ec->toInteger()) + *pval = e; + } + } + return *pval; + +Lerrors: + *pval = new ErrorExp(); + return *pval; +} + +Expression *EnumDeclaration::getDefaultValue(Loc loc) +{ + //printf("EnumDeclaration::getDefaultValue() %p %s\n", this, toChars()); + if (defaultval) + return defaultval; + + if (scope) + semantic(scope); + if (errors) + goto Lerrors; + if (semanticRun == PASSinit || !members) + { + error(loc, "forward reference of %s.init", toChars()); + goto Lerrors; + } + + for (size_t i = 0; i < members->dim; i++) + { + EnumMember *em = (*members)[i]->isEnumMember(); + if (!em) + continue; + defaultval = em->value; + return defaultval; + } + +Lerrors: + defaultval = new ErrorExp(); + return defaultval; +} + +Type *EnumDeclaration::getMemtype(Loc loc) +{ + if (loc.linnum == 0) + loc = this->loc; + if (scope) + { /* Enum is forward referenced. We don't need to resolve the whole thing, + * just the base type + */ + if (memtype) + memtype = memtype->semantic(loc, scope); + else + { + if (!isAnonymous()) + memtype = Type::tint32; + } + } + if (!memtype) + { + if (!isAnonymous()) + memtype = Type::tint32; + else + { + error(loc, "is forward referenced looking for base type"); + return Type::terror; + } + } + return memtype; +} + +bool EnumDeclaration::oneMember(Dsymbol **ps, Identifier *ident) { if (isAnonymous()) return Dsymbol::oneMembers(members, ps, ident); @@ -450,6 +463,11 @@ bool EnumDeclaration::isDeprecated() return isdeprecated; } +PROT EnumDeclaration::prot() +{ + return protection; +} + Dsymbol *EnumDeclaration::search(Loc loc, Identifier *ident, int flags) { //printf("%s.EnumDeclaration::search('%s')\n", toChars(), ident->toChars()); @@ -521,24 +539,170 @@ const char *EnumMember::kind() void EnumMember::semantic(Scope *sc) { + //printf("EnumMember::semantic() %s\n", toChars()); + if (errors || semanticRun >= PASSsemanticdone) + return; + if (semanticRun == PASSsemantic) + { + error("circular reference to enum member"); + Lerrors: + errors = true; + semanticRun = PASSsemanticdone; + return; + } assert(ed); - if (this->vd) return; ed->semantic(sc); - assert(value); - vd = new VarDeclaration(loc, type, ident, new ExpInitializer(loc, value->copy())); + if (ed->errors) + goto Lerrors; - vd->storage_class = STCmanifest; - vd->semantic(sc); + if (errors || semanticRun >= PASSsemanticdone) + return; - vd->protection = ed->isAnonymous() ? ed->protection : PROTpublic; - vd->parent = ed->isAnonymous() ? ed->parent : ed; - vd->userAttributes = ed->isAnonymous() ? ed->userAttributes : NULL; + semanticRun = PASSsemantic; + if (scope) + sc = scope; + + // The first enum member is special + bool first = (this == (*ed->members)[0]); + + if (type) + { + type = type->semantic(loc, sc); + assert(value); // "type id;" is not a valid enum member declaration + } + + if (value) + { + Expression *e = value; + assert(e->dyncast() == DYNCAST_EXPRESSION); + e = e->semantic(sc); + e = resolveProperties(sc, e); + e = e->ctfeInterpret(); + if (first && !ed->memtype && !ed->isAnonymous()) + { + ed->memtype = e->type; + if (ed->memtype->ty == Terror) + { + ed->errors = true; + goto Lerrors; + } + } + + if (ed->memtype && !type) + { + e = e->implicitCastTo(sc, ed->memtype); + e = e->ctfeInterpret(); + if (!ed->isAnonymous()) + e = e->castTo(sc, ed->type); + } + else if (type) + { + e = e->implicitCastTo(sc, type); + e = e->ctfeInterpret(); + assert(ed->isAnonymous()); + } + value = e; + } + else if (first) + { + Type *t; + if (ed->memtype) + t = ed->memtype; + else + { + t = Type::tint32; + if (!ed->isAnonymous()) + ed->memtype = t; + } + Expression *e = new IntegerExp(loc, 0, Type::tint32); + e = e->implicitCastTo(sc, t); + e = e->ctfeInterpret(); + if (!ed->isAnonymous()) + e = e->castTo(sc, ed->type); + value = e; + } + else + { + /* Find the previous enum member, + * and set this to be the previous value + 1 + */ + EnumMember *emprev = NULL; + for (size_t i = 0; i < ed->members->dim; i++) + { + EnumMember *em = (*ed->members)[i]->isEnumMember(); + if (em) + { + if (em == this) + break; + emprev = em; + } + } + assert(emprev); + if (emprev->semanticRun < PASSsemanticdone) // if forward reference + emprev->semantic(emprev->scope); // resolve it + if (emprev->errors) + goto Lerrors; + + Expression *eprev = emprev->value; + Type *tprev = eprev->type->equals(ed->type) ? ed->memtype : eprev->type; + + Expression *emax = tprev->getProperty(Loc(), Id::max, 0); + emax = emax->semantic(sc); + emax = emax->ctfeInterpret(); + + // Set value to (eprev + 1). + // But first check that (eprev != emax) + assert(eprev); + Expression *e = new EqualExp(TOKequal, loc, eprev, emax); + e = e->semantic(sc); + e = e->ctfeInterpret(); + if (e->toInteger()) + { + error("initialization with (%s.%s + 1) causes overflow for type '%s'", emprev->ed->toChars(), emprev->toChars(), ed->type->toBasetype()->toChars()); + goto Lerrors; + } + + // Now set e to (eprev + 1) + e = new AddExp(loc, eprev, new IntegerExp(loc, 1, Type::tint32)); + e = e->semantic(sc); + e = e->castTo(sc, eprev->type); + e = e->ctfeInterpret(); + + if (e->type->isfloating()) + { + // Check that e != eprev (not always true for floats) + Expression *etest = new EqualExp(TOKequal, loc, e, eprev); + etest = etest->semantic(sc); + etest = etest->ctfeInterpret(); + if (etest->toInteger()) + { + error("has inexact value, due to loss of precision"); + goto Lerrors; + } + } + value = e; + } + + semanticRun = PASSsemanticdone; } Expression *EnumMember::getVarExp(Loc loc, Scope *sc) { semantic(sc); - assert(vd); + if (errors) + return new ErrorExp(); + if (!vd) + { + assert(value); + vd = new VarDeclaration(loc, type, ident, new ExpInitializer(loc, value->copy())); + + vd->storage_class = STCmanifest; + vd->semantic(sc); + + vd->protection = ed->isAnonymous() ? ed->protection : PROTpublic; + vd->parent = ed->isAnonymous() ? ed->parent : ed; + vd->userAttributes = ed->isAnonymous() ? ed->userAttributes : NULL; + } Expression *e = new VarExp(loc, vd); return e->semantic(sc); } diff --git a/dmd2/enum.h b/dmd2/enum.h index 8efabeaa..b6a94cb9 100644 --- a/dmd2/enum.h +++ b/dmd2/enum.h @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2008 by Digital Mars +// Copyright (c) 1999-2013 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -18,39 +18,42 @@ #include "root.h" #include "dsymbol.h" -struct Identifier; -struct Type; -struct Expression; +class Identifier; +class Type; +class Expression; struct HdrGenState; -struct VarDeclaration; +class VarDeclaration; -struct EnumDeclaration : ScopeDsymbol -{ /* enum ident : memtype { ... } +class EnumDeclaration : public ScopeDsymbol +{ +public: + /* The separate, and distinct, cases are: + * 1. enum { ... } + * 2. enum : memtype { ... } + * 3. enum id { ... } + * 4. enum id : memtype { ... } + * 5. enum id : memtype; + * 6. enum id; */ Type *type; // the TypeEnum Type *memtype; // type of the members - enum PROT protection; + PROT protection; -#if DMDV1 - dinteger_t maxval; - dinteger_t minval; - dinteger_t defaultval; // default initializer -#else +private: Expression *maxval; Expression *minval; Expression *defaultval; // default initializer -#endif + +public: bool isdeprecated; - int isdone; // 0: not done - // 1: semantic() successfully completed + bool added; EnumDeclaration(Loc loc, Identifier *id, Type *memtype); Dsymbol *syntaxCopy(Dsymbol *s); int addMember(Scope *sc, ScopeDsymbol *sd, int memnum); void setScope(Scope *sc); - void semantic0(Scope *sc); void semantic(Scope *sc); - int oneMember(Dsymbol **ps, Identifier *ident = NULL); + bool oneMember(Dsymbol **ps, Identifier *ident); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Type *getType(); const char *kind(); @@ -58,6 +61,10 @@ struct EnumDeclaration : ScopeDsymbol Dsymbol *search(Loc, Identifier *ident, int flags); #endif bool isDeprecated(); // is Dsymbol deprecated? + PROT prot(); + Expression *getMaxMinValue(Loc loc, Identifier *id); + Expression *getDefaultValue(Loc loc); + Type *getMemtype(Loc loc); void emitComment(Scope *sc); void toJson(JsonOut *json); @@ -66,7 +73,6 @@ struct EnumDeclaration : ScopeDsymbol EnumDeclaration *isEnumDeclaration() { return this; } #if IN_DMD - bool objFileDone; // if toObjFile was already called void toObjFile(int multiobj); // compile to .obj file void toDebug(); int cvMember(unsigned char *p); @@ -81,11 +87,18 @@ struct EnumDeclaration : ScopeDsymbol }; -struct EnumMember : Dsymbol +class EnumMember : public Dsymbol { - EnumDeclaration *ed; +public: + /* Can take the following forms: + * 1. id + * 2. id = value + * 3. type id = value + */ Expression *value; Type *type; + + EnumDeclaration *ed; VarDeclaration *vd; EnumMember(Loc loc, Identifier *id, Expression *value, Type *type); diff --git a/dmd2/expression.c b/dmd2/expression.c index d6fed00e..c11e7424 100644 --- a/dmd2/expression.c +++ b/dmd2/expression.c @@ -20,10 +20,6 @@ #endif #endif -#if _WIN32 && __DMC__ -extern "C" const char * __cdecl __locale_decpoint; -#endif - #include "rmem.h" #include "port.h" #include "root.h" @@ -47,6 +43,7 @@ extern "C" const char * __cdecl __locale_decpoint; #include "hdrgen.h" #include "parse.h" #include "doc.h" +#include "aav.h" #if IN_DMD Expression *createTypeInfoArray(Scope *sc, Expression *args[], size_t dim); @@ -277,118 +274,250 @@ Expression *checkRightThis(Scope *sc, Expression *e) * Pull out any properties. */ -Expression *resolvePropertiesX(Scope *sc, Expression *e) +Expression *resolvePropertiesX(Scope *sc, Expression *e1, Expression *e2 = NULL) { - TemplateDeclaration *td; + //printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", Token::toChars(e1->op), e1->toChars(), e2 ? e2->toChars() : NULL); + Loc loc = e1->loc; + + OverloadSet *os; + Dsymbol *s; Objects *tiargs; Type *tthis; - if (e->op == TOKdotti) + if (e1->op == TOKdotexp) { - DotTemplateInstanceExp* dti = (DotTemplateInstanceExp *)e; - td = dti->getTempdecl(sc); - dti->ti->semanticTiargs(sc); + DotExp *de = (DotExp *)e1; + if (de->e2->op == TOKoverloadset) + { + tiargs = NULL; + tthis = de->e1->type; + os = ((OverExp *)de->e2)->vars; + goto Los; + } + } + else if (e1->op == TOKoverloadset) + { + tiargs = NULL; + tthis = NULL; + os = ((OverExp *)e1)->vars; + Los: + assert(os); + FuncDeclaration *fd = NULL; + if (e2) + { + e2 = e2->semantic(sc); + if (e2->op == TOKerror) + return new ErrorExp(); + e2 = resolveProperties(sc, e2); + + Expressions a; + a.push(e2); + + for (size_t i = 0; i < os->a.dim; i++) + { + Dsymbol *s = os->a[i]; + FuncDeclaration *f = resolveFuncCall(loc, sc, s, tiargs, tthis, &a, 1); + if (f) + { + fd = f; + assert(fd->type->ty == Tfunction); + TypeFunction *tf = (TypeFunction *)fd->type; + if (!tf->isproperty && global.params.enforcePropertySyntax) + goto Leprop; + } + } + if (fd) + { + Expression *e = new CallExp(loc, e1, e2); + return e->semantic(sc); + } + } + { + for (size_t i = 0; i < os->a.dim; i++) + { + Dsymbol *s = os->a[i]; + FuncDeclaration *f = resolveFuncCall(loc, sc, s, tiargs, tthis, NULL, 1); + if (f) + { + fd = f; + assert(fd->type->ty == Tfunction); + TypeFunction *tf = (TypeFunction *)fd->type; + if (!tf->isref && e2) + goto Leproplvalue; + if (!tf->isproperty && global.params.enforcePropertySyntax) + goto Leprop; + } + } + if (fd) + { + Expression *e = new CallExp(loc, e1); + if (e2) + e = new AssignExp(loc, e, e2); + return e->semantic(sc); + } + } + if (e2) + goto Leprop; + } + else if (e1->op == TOKdotti) + { + DotTemplateInstanceExp* dti = (DotTemplateInstanceExp *)e1; + if (!dti->findTempDecl(sc)) + goto Leprop; + if (!dti->ti->semanticTiargs(sc)) + goto Leprop; tiargs = dti->ti->tiargs; tthis = dti->e1->type; - goto L1; + if ((os = dti->ti->tempdecl->isOverloadSet()) != NULL) + goto Los; + if ((s = dti->ti->tempdecl) != NULL) + goto Lfd; } - else if (e->op == TOKdottd) + else if (e1->op == TOKdottd) { - DotTemplateExp *dte = (DotTemplateExp *)e; - td = dte->td; + DotTemplateExp *dte = (DotTemplateExp *)e1; + s = dte->td; tiargs = NULL; tthis = dte->e1->type; - goto L1; + goto Lfd; } - else if (e->op == TOKimport) + else if (e1->op == TOKimport) { - Dsymbol *s = ((ScopeExp *)e)->sds; - td = s->isTemplateDeclaration(); - if (td) + s = ((ScopeExp *)e1)->sds; + if (s->isTemplateDeclaration()) { tiargs = NULL; tthis = NULL; - goto L1; + goto Lfd; } TemplateInstance *ti = s->isTemplateInstance(); - if (ti && !ti->semanticRun) + if (ti && !ti->semanticRun && ti->tempdecl) { //assert(ti->needsTypeInference(sc)); - td = ti->tempdecl; - ti->semanticTiargs(sc); + if (!ti->semanticTiargs(sc)) + { + ti->inst = ti; + ti->inst->errors = true; + goto Leprop; + } tiargs = ti->tiargs; tthis = NULL; - goto L1; + if ((os = ti->tempdecl->isOverloadSet()) != NULL) + goto Los; + if ((s = ti->tempdecl) != NULL) + goto Lfd; } } - else if (e->op == TOKtemplate) + else if (e1->op == TOKtemplate) { - td = ((TemplateExp *)e)->td; + s = ((TemplateExp *)e1)->td; tiargs = NULL; tthis = NULL; - L1: - assert(td); - unsigned errors = global.startGagging(); - FuncDeclaration *fd = resolveFuncCall(e->loc, sc, td, tiargs, tthis, NULL, 1); - if (global.endGagging(errors)) - fd = NULL; // eat "is not a function template" error - if (fd && fd->type) - { assert(fd->type->ty == Tfunction); + goto Lfd; + } + else if (e1->op == TOKdotvar && e1->type->toBasetype()->ty == Tfunction) + { + DotVarExp *dve = (DotVarExp *)e1; + s = dve->var->isFuncDeclaration(); + tiargs = NULL; + tthis = dve->e1->type; + goto Lfd; + } + else if (e1->op == TOKvar && e1->type->toBasetype()->ty == Tfunction) + { + s = ((VarExp *)e1)->var->isFuncDeclaration(); + tiargs = NULL; + tthis = NULL; + Lfd: + assert(s); + FuncDeclaration *fd; + if (e2) + { + e2 = e2->semantic(sc); + if (e2->op == TOKerror) + return new ErrorExp(); + e2 = resolveProperties(sc, e2); + + Expressions a; + a.push(e2); + + fd = resolveFuncCall(loc, sc, s, tiargs, tthis, &a, 1); + if (fd && fd->type) + { + assert(fd->type->ty == Tfunction); + TypeFunction *tf = (TypeFunction *)fd->type; + if (!tf->isproperty && global.params.enforcePropertySyntax) + goto Leprop; + Expression *e = new CallExp(loc, e1, e2); + return e->semantic(sc); + } + } + { + fd = resolveFuncCall(loc, sc, s, tiargs, tthis, NULL, 1); + if (fd && fd->type) + { + assert(fd->type->ty == Tfunction); + TypeFunction *tf = (TypeFunction *)fd->type; + if (!tf->isref && e2) + goto Leproplvalue; + if (!tf->isproperty && global.params.enforcePropertySyntax) + goto Leprop; + Expression *e = new CallExp(loc, e1); + if (e2) + e = new AssignExp(loc, e, e2); + return e->semantic(sc); + } + } + if (FuncDeclaration *fd = s->isFuncDeclaration()) + { // Keep better diagnostic message for invalid property usage of functions + assert(fd->type->ty == Tfunction); TypeFunction *tf = (TypeFunction *)fd->type; if (!tf->isproperty && global.params.enforcePropertySyntax) - { error(e->loc, "not a property %s", e->toChars()); - return new ErrorExp(); - } - e = new CallExp(e->loc, e); - e = e->semantic(sc); + error(loc, "not a property %s", e1->toChars()); + Expression *e = new CallExp(loc, e1, e2); + return e->semantic(sc); } - goto return_expr; + if (e2) + goto Leprop; } + if (e2) + return NULL; - if (e->type && - e->op != TOKtype) // function type is not a property + if (e1->type && + e1->op != TOKtype) // function type is not a property { - Type *t = e->type->toBasetype(); - - if (t->ty == Tfunction || e->op == TOKoverloadset) - { - if (t->ty == Tfunction && !((TypeFunction *)t)->isproperty && - global.params.enforcePropertySyntax) - { - error(e->loc, "not a property %s", e->toChars()); - return new ErrorExp(); - } - e = new CallExp(e->loc, e); - e = e->semantic(sc); - } - - /* Look for e being a lazy parameter; rewrite as delegate call + /* Look for e1 being a lazy parameter; rewrite as delegate call */ - else if (e->op == TOKvar) + if (e1->op == TOKvar) { - VarExp *ve = (VarExp *)e; + VarExp *ve = (VarExp *)e1; if (ve->var->storage_class & STClazy) { - e = new CallExp(e->loc, e); - e = e->semantic(sc); + Expression *e = new CallExp(loc, e1); + return e->semantic(sc); } } - - else if (e->op == TOKdotexp) + else if (e1->op == TOKdotexp) { - e->error("expression has no value"); + e1->error("expression has no value"); return new ErrorExp(); } - } -return_expr: - if (!e->type) + if (!e1->type) { - error(e->loc, "cannot resolve type for %s", e->toChars()); - e->type = new TypeError(); + error(loc, "cannot resolve type for %s", e1->toChars()); + e1 = new ErrorExp(); } - return e; + return e1; + +Leprop: + error(loc, "not a property %s", e1->toChars()); + return new ErrorExp(); + +Leproplvalue: + error(loc, "%s is not an lvalue", e1->toChars()); + return new ErrorExp(); } Expression *resolveProperties(Scope *sc, Expression *e) @@ -436,6 +565,109 @@ void checkPropertyCall(Expression *e, Expression *emsg) } } +/****************************** + * If e1 is a property function (template), resolve it. + */ + +Expression *resolvePropertiesOnly(Scope *sc, Expression *e1) +{ + OverloadSet *os; + FuncDeclaration *fd; + TemplateDeclaration *td; + + if (e1->op == TOKdotexp) + { + DotExp *de = (DotExp *)e1; + if (de->e2->op == TOKoverloadset) + { + os = ((OverExp *)de->e2)->vars; + goto Los; + } + } + else if (e1->op == TOKoverloadset) + { + os = ((OverExp *)e1)->vars; + Los: + assert(os); + for (size_t i = 0; i < os->a.dim; i++) + { + Dsymbol *s = os->a[i]; + fd = s->isFuncDeclaration(); + td = s->isTemplateDeclaration(); + if (fd) + { + if (((TypeFunction *)fd->type)->isproperty) + return resolveProperties(sc, e1); + } + else if (td && td->onemember && + (fd = td->onemember->isFuncDeclaration()) != NULL) + { + if (((TypeFunction *)fd->type)->isproperty || + (fd->storage_class2 & STCproperty) || + (td->scope->stc & STCproperty)) + { + return resolveProperties(sc, e1); + } + } + } + } + else if (e1->op == TOKdotti) + { + DotTemplateInstanceExp* dti = (DotTemplateInstanceExp *)e1; + if (dti->ti->tempdecl && (td = dti->ti->tempdecl->isTemplateDeclaration()) != NULL) + goto Ltd; + } + else if (e1->op == TOKdottd) + { + td = ((DotTemplateExp *)e1)->td; + goto Ltd; + } + else if (e1->op == TOKimport) + { + Dsymbol *s = ((ScopeExp *)e1)->sds; + td = s->isTemplateDeclaration(); + if (td) + goto Ltd; + TemplateInstance *ti = s->isTemplateInstance(); + if (ti && !ti->semanticRun && ti->tempdecl) + { + if ((td = ti->tempdecl->isTemplateDeclaration()) != NULL) + goto Ltd; + } + } + else if (e1->op == TOKtemplate) + { + td = ((TemplateExp *)e1)->td; + Ltd: + assert(td); + if (td->onemember && + (fd = td->onemember->isFuncDeclaration()) != NULL) + { + if (((TypeFunction *)fd->type)->isproperty || + (fd->storage_class2 & STCproperty) || + (td->scope->stc & STCproperty)) + { + return resolveProperties(sc, e1); + } + } + } + else if (e1->op == TOKdotvar && e1->type->ty == Tfunction) + { + DotVarExp *dve = (DotVarExp *)e1; + fd = dve->var->isFuncDeclaration(); + goto Lfd; + } + else if (e1->op == TOKvar && e1->type->ty == Tfunction) + { + fd = ((VarExp *)e1)->var->isFuncDeclaration(); + Lfd: + assert(fd); + if (((TypeFunction *)fd->type)->isproperty) + return resolveProperties(sc, e1); + } + return e1; +} + /****************************** * Find symbol in accordance with the UFCS name look up rule @@ -474,26 +706,24 @@ Expression *searchUFCS(Scope *sc, UnaExp *ue, Identifier *ident) FuncDeclaration *f = s->isFuncDeclaration(); if (f) - { TemplateDeclaration *tempdecl = getFuncTemplateDecl(f); - if (tempdecl) + { + TemplateDeclaration *td = getFuncTemplateDecl(f); + if (td) { - if (tempdecl->overroot) - tempdecl = tempdecl->overroot; - s = tempdecl; + if (td->overroot) + td = td->overroot; + s = td; } } if (ue->op == TOKdotti) { + TemplateInstance *ti = new TemplateInstance(loc, s->ident); + if (!ti->updateTemplateDeclaration(sc, s)) + return new ErrorExp(); DotTemplateInstanceExp *dti = (DotTemplateInstanceExp *)ue; - TemplateDeclaration *td = s->toAlias()->isTemplateDeclaration(); - if (!td) - { s->error(loc, "is not a template"); - return new ErrorExp(); - } - if (!dti->ti->semanticTiargs(sc)) - return new ErrorExp(); - return new ScopeExp(loc, new TemplateInstance(loc, td, dti->ti->tiargs)); + ti->tiargs = dti->ti->tiargs; + return new ScopeExp(loc, ti); } else { @@ -501,6 +731,17 @@ Expression *searchUFCS(Scope *sc, UnaExp *ue, Identifier *ident) } } +/****************************** + * check e is exp.opDispatch!(tiargs) or not + * It's used to switch to UFCS the semantic analysis path + */ + +bool isDotOpDispatch(Expression *e) +{ + return e->op == TOKdotti && + ((DotTemplateInstanceExp *)e)->ti->name == Id::opDispatch; +} + /****************************** * Pull out callable entity with UFCS. */ @@ -518,7 +759,8 @@ Expression *resolveUFCS(Scope *sc, CallExp *ce) Expression *ex = die->semanticX(sc); if (ex != die) - { ce->e1 = ex; + { + ce->e1 = ex; return NULL; } eleft = die->e1; @@ -531,7 +773,6 @@ Expression *resolveUFCS(Scope *sc, CallExp *ce) * It is necessary in: e.init() */ } -#if 1 else if (t->ty == Taarray) { if (ident == Id::remove) @@ -540,11 +781,13 @@ Expression *resolveUFCS(Scope *sc, CallExp *ce) * aa.remove(arg) into delete aa[arg] */ if (!ce->arguments || ce->arguments->dim != 1) - { ce->error("expected key as argument to aa.remove()"); + { + ce->error("expected key as argument to aa.remove()"); return new ErrorExp(); } if (!eleft->type->isMutable()) - { ce->error("cannot remove key from %s associative array %s", + { + ce->error("cannot remove key from %s associative array %s", MODtoChars(t->mod), eleft->toChars()); return new ErrorExp(); } @@ -565,7 +808,8 @@ Expression *resolveUFCS(Scope *sc, CallExp *ce) return NULL; } else - { TypeAArray *taa = (TypeAArray *)t; + { + TypeAArray *taa = (TypeAArray *)t; assert(taa->ty == Taarray); StructDeclaration *sd = taa->getImpl(); Dsymbol *s = sd->search(Loc(), ident, 2); @@ -573,12 +817,22 @@ Expression *resolveUFCS(Scope *sc, CallExp *ce) return NULL; } } -#endif else { if (Expression *ey = die->semanticY(sc, 1)) - { ce->e1 = ey; - return NULL; + { + ce->e1 = ey; + if (isDotOpDispatch(ey)) + { + unsigned errors = global.startGagging(); + e = ce->semantic(sc); + if (global.endGagging(errors)) + {} /* fall down to UFCS */ + else + return e; + } + else + return NULL; } } e = searchUFCS(sc, die, ident); @@ -587,7 +841,8 @@ Expression *resolveUFCS(Scope *sc, CallExp *ce) { DotTemplateInstanceExp *dti = (DotTemplateInstanceExp *)ce->e1; if (Expression *ey = dti->semanticY(sc, 1)) - { ce->e1 = ey; + { + ce->e1 = ey; return NULL; } eleft = dti->e1; @@ -774,26 +1029,28 @@ void expandTuples(Expressions *exps) TupleDeclaration *isAliasThisTuple(Expression *e) { - if (e->type) + if (!e->type) + return NULL; + + Type *t = e->type->toBasetype(); +Lagain: + if (Dsymbol *s = t->toDsymbol(NULL)) { - Type *t = e->type->toBasetype(); - AggregateDeclaration *ad; - if (t->ty == Tstruct) + AggregateDeclaration *ad = s->isAggregateDeclaration(); + if (ad) { - ad = ((TypeStruct *)t)->sym; - goto L1; - } - else if (t->ty == Tclass) - { - ad = ((TypeClass *)t)->sym; - L1: - Dsymbol *s = ad->aliasthis; + s = ad->aliasthis; if (s && s->isVarDeclaration()) { TupleDeclaration *td = s->isVarDeclaration()->toAlias()->isTupleDeclaration(); if (td && td->isexp) return td; } + if (Type *att = t->aliasthisOf()) + { + t = att; + goto Lagain; + } } } return NULL; @@ -889,39 +1146,18 @@ Expressions *arrayExpressionToCommonType(Scope *sc, Expressions *exps, Type **pt Expression *e = (*exps)[i]; e = resolveProperties(sc, e); if (!e->type) - { e->error("%s has no value", e->toChars()); + { + e->error("%s has no value", e->toChars()); e = new ErrorExp(); } if (Expression *ex = e->isTemp()) e = ex; - if (e->isLvalue()) - { - e = callCpCtor(e->loc, sc, e, 1); - } - else - { - Type *tb = e->type->toBasetype(); - if (tb->ty == Tsarray) - { - e = callCpCtor(e->loc, sc, e, 1); - } - else if (tb->ty == Tstruct) - { - if (e->op == TOKcall && !e->isLvalue()) - { - valueNoDtor(e); - } - else - { /* Not transferring it, so call the copy constructor - */ - e = callCpCtor(e->loc, sc, e, 1); - } - } - } + e = e->isLvalue() ? callCpCtor(sc, e) : valueNoDtor(e); if (t0) - { if (t0 != e->type) + { + if (t0 != e->type) { /* This applies ?: to merge the types. It's backwards; * ?: should call this function to merge types. @@ -939,7 +1175,8 @@ Expressions *arrayExpressionToCommonType(Scope *sc, Expressions *exps, Type **pt } } else - { j0 = i; + { + j0 = i; e0 = e; t0 = e->type; } @@ -972,16 +1209,19 @@ TemplateDeclaration *getFuncTemplateDecl(Dsymbol *s) { FuncDeclaration *f = s->isFuncDeclaration(); if (f && f->parent) - { TemplateInstance *ti = f->parent->isTemplateInstance(); - + { + TemplateInstance *ti = f->parent->isTemplateInstance(); + TemplateDeclaration *td; if (ti && !ti->isTemplateMixin() && (ti->name == f->ident || ti->toAlias()->ident == f->ident) && - ti->tempdecl && ti->tempdecl->onemember) + ti->tempdecl && + (td = ti->tempdecl->isTemplateDeclaration()) != NULL && + td->onemember) { - return ti->tempdecl; + return td; } } return NULL; @@ -1016,7 +1256,7 @@ void preFunctionParameters(Loc loc, Scope *sc, Expressions *exps) * the destructor on it. */ -void valueNoDtor(Expression *e) +Expression *valueNoDtor(Expression *e) { if (e->op == TOKcall) { @@ -1029,21 +1269,29 @@ void valueNoDtor(Expression *e) */ CallExp *ce = (CallExp *)e; if (ce->e1->op == TOKdotvar) - { DotVarExp *dve = (DotVarExp *)ce->e1; + { + DotVarExp *dve = (DotVarExp *)ce->e1; if (dve->var->isCtorDeclaration()) - { // It's a constructor call + { + // It's a constructor call if (dve->e1->op == TOKcomma) - { CommaExp *comma = (CommaExp *)dve->e1; + { + CommaExp *comma = (CommaExp *)dve->e1; if (comma->e2->op == TOKvar) - { VarExp *ve = (VarExp *)comma->e2; + { + VarExp *ve = (VarExp *)comma->e2; VarDeclaration *ctmp = ve->var->isVarDeclaration(); if (ctmp) + { ctmp->noscope = 1; + assert(!ce->isLvalue()); + } } } } } } + return e; } /******************************************** @@ -1052,9 +1300,7 @@ void valueNoDtor(Expression *e) #if DMDV2 bool checkDefCtor(Loc loc, Type *t) { - t = t->toBasetype(); - while (t->ty == Tsarray) - t = t->nextOf()->toBasetype(); + t = t->baseElemOf(); if (t->ty == Tstruct) { StructDeclaration *sd = ((TypeStruct *)t)->sym; @@ -1072,11 +1318,9 @@ bool checkDefCtor(Loc loc, Type *t) * Determine if t is an array of structs that need a postblit. */ #if DMDV2 -bool checkPostblit(Loc loc, Type *t) +bool Expression::checkPostblit(Scope *sc, Type *t) { - t = t->toBasetype(); - while (t->ty == Tsarray) - t = t->nextOf()->toBasetype(); + t = t->baseElemOf(); if (t->ty == Tstruct) { StructDeclaration *sd = ((TypeStruct *)t)->sym; @@ -1084,6 +1328,11 @@ bool checkPostblit(Loc loc, Type *t) { if (sd->postblit->storage_class & STCdisable) sd->error(loc, "is not copyable because it is annotated with @disable"); + else + { + checkPurity(sc, sd->postblit); + checkSafety(sc, sd->postblit); + } return true; } } @@ -1093,30 +1342,17 @@ bool checkPostblit(Loc loc, Type *t) /********************************************* * Call copy constructor for struct value argument. + * Input: + * sc just used to specify the scope of created temporary variable */ #if DMDV2 -Expression *callCpCtor(Loc loc, Scope *sc, Expression *e, int noscope) +Expression *callCpCtor(Scope *sc, Expression *e) { - if (e->op == TOKarrayliteral) - { - ArrayLiteralExp *ae = (ArrayLiteralExp *)e; - for (size_t i = 0; i < ae->elements->dim; i++) - { - ae->elements->tdata()[i] = - callCpCtor(loc, sc, ae->elements->tdata()[i], noscope); - } - e = ae->semantic(sc); - return e; - } - - Type *tb = e->type->toBasetype(); - Type *tv = tb; - while (tv->ty == Tsarray) - tv = tv->nextOf()->toBasetype(); + Type *tv = e->type->baseElemOf(); if (tv->ty == Tstruct) { StructDeclaration *sd = ((TypeStruct *)tv)->sym; - if (sd->cpctor && e->isLvalue()) + if (sd->cpctor) { /* Create a variable tmp, and replace the argument e with: * (tmp = e),tmp @@ -1125,12 +1361,15 @@ Expression *callCpCtor(Loc loc, Scope *sc, Expression *e, int noscope) * directly onto the stack. */ Identifier *idtmp = Lexer::uniqueId("__cpcttmp"); - VarDeclaration *tmp = new VarDeclaration(loc, tb, idtmp, new ExpInitializer(Loc(), e)); + VarDeclaration *tmp = new VarDeclaration(e->loc, e->type, idtmp, new ExpInitializer(e->loc, e)); tmp->storage_class |= STCctfe; - tmp->noscope = noscope; - Expression *ae = new DeclarationExp(loc, tmp); - e = new CommaExp(loc, ae, new VarExp(loc, tmp)); - e = e->semantic(sc); + tmp->noscope = 1; + tmp->semantic(sc); + Expression *de = new DeclarationExp(e->loc, tmp); + Expression *ve = new VarExp(e->loc, tmp); + de->type = Type::tvoid; + ve->type = e->type; + e = Expression::combine(de, ve); } } return e; @@ -1212,7 +1451,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, if (!arg) { - if (!p->defaultArg || !fd) + if (!p->defaultArg) { if (tf->varargs == 2 && i + 1 == nparams) goto L2; @@ -1228,14 +1467,6 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, arguments->push(arg); nargs++; } - else - { - Type *pt = p->type; - if (tf->varargs == 2 && i + 1 == nparams && pt->nextOf()) - pt = pt->nextOf(); - arg = arg->inferType(pt); - (*arguments)[i] = arg; - } if (tf->varargs == 2 && i + 1 == nparams) { @@ -1259,22 +1490,11 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, case Tsarray: case Tarray: { // Create a static array variable v of type arg->type -#ifdef IN_GCC - /* GCC 4.0 does not like zero length arrays used like - this; pass a null array value instead. Could also - just make a one-element array. */ - if (nargs - i == 0) - { - arg = new NullExp(loc); - break; - } -#endif Identifier *id = Lexer::uniqueId("__arrayArg"); Type *t = new TypeSArray(((TypeArray *)tb)->next, new IntegerExp(nargs - i)); t = t->semantic(loc, sc); - bool isSafe = fd ? fd->isSafe() : tf->trust == TRUSTsafe; VarDeclaration *v = new VarDeclaration(loc, t, id, - (isSafe && sc->func) ? NULL : new VoidInitializer(loc)); + (sc->func && sc->func->isSafe()) ? NULL : new VoidInitializer(loc)); v->storage_class |= STCctfe; v->semantic(sc); v->parent = sc->parent; @@ -1284,10 +1504,14 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, c->type = v->type; for (size_t u = i; u < nargs; u++) - { Expression *a = (*arguments)[u]; + { + Expression *a = (*arguments)[u]; TypeArray *ta = (TypeArray *)tb; + a = a->inferType(ta->next); + (*arguments)[u] = a; if (tret && !ta->next->equals(a->type)) - { if (tret->toBasetype()->ty == Tvoid || + { + if (tret->toBasetype()->ty == Tvoid || a->implicitConvTo(tret)) { a = a->toDelegate(sc, tret); @@ -1347,7 +1571,8 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, break; } if (wildmatch) - { /* Calculate wild matching modifier + { + /* Calculate wild matching modifier */ if (wildmatch & MODconst || wildmatch & (wildmatch - 1)) wildmatch = MODconst; @@ -1356,9 +1581,52 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, else if (wildmatch & MODwild) wildmatch = MODwild; else - { assert(wildmatch & MODmutable); + { + assert(wildmatch & MODmutable); wildmatch = MODmutable; } + + if ((wildmatch == MODmutable || wildmatch == MODimmutable) && + tf->next->hasWild() && + (tf->isref || !tf->next->implicitConvTo(tf->next->immutableOf()))) + { + if (fd) + { + /* If the called function may return the reference to + * outer inout data, it should be rejected. + * + * void foo(ref inout(int) x) { + * ref inout(int) bar(inout(int)) { return x; } + * struct S { ref inout(int) bar() inout { return x; } } + * bar(int.init) = 1; // bad! + * S().bar() = 1; // bad! + * } + */ + FuncDeclaration *f; + if (AggregateDeclaration *ad = fd->isThis()) + { + f = ad->toParent2()->isFuncDeclaration(); + goto Linoutnest; + } + else if (fd->isNested()) + { + f = fd->toParent2()->isFuncDeclaration(); + Linoutnest: + for (; f; f = f->toParent2()->isFuncDeclaration()) + { + if (((TypeFunction *)f->type)->iswild) + goto Linouterr; + } + } + } + else if (tf->isWild()) + { + Linouterr: + const char *s = wildmatch == MODmutable ? "mutable" : MODtoChars(wildmatch); + error(loc, "modify inout to %s is not allowed inside inout function", s); + return Type::terror; + } + } } assert(nargs >= nparams); @@ -1378,7 +1646,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, arg = arg->implicitCastTo(sc, p->type->substWildTo(wildmatch)); arg = arg->optimize(WANTvalue, p->storageClass & STCref); } - else if (p->type != arg->type) + else if (!p->type->equals(arg->type)) { //printf("arg->type = %s, p->type = %s\n", arg->type->toChars(), p->type->toChars()); if (arg->op == TOKtype) @@ -1412,30 +1680,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, { if (Expression *e = arg->isTemp()) arg = e; - Type *tb = arg->type->toBasetype(); - if (tb->ty == Tsarray) - { - // call copy constructor of each element - arg = callCpCtor(loc, sc, arg, 1); - } -#if DMDV2 - else if (tb->ty == Tstruct) - { - if (arg->op == TOKcall && !arg->isLvalue()) - { - /* The struct value returned from the function is transferred - * to the function, so the callee should not call the destructor - * on it. - */ - valueNoDtor(arg); - } - else - { /* Not transferring it, so call the copy constructor - */ - arg = callCpCtor(loc, sc, arg, 1); - } - } -#endif + arg = arg->isLvalue() ? callCpCtor(sc, arg) : valueNoDtor(arg); } //printf("arg: %s\n", arg->toChars()); @@ -1506,25 +1751,29 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, // Do not allow types that need destructors if (arg->type->needsDestruction()) - { arg->error("cannot pass types that need destruction as variadic arguments"); + { + arg->error("cannot pass types that need destruction as variadic arguments"); arg = new ErrorExp(); } +#if 0 + arg = arg->isLvalue() ? callCpCtor(sc, arg) : valueNoDtor(arg); +#else // Convert static arrays to dynamic arrays // BUG: I don't think this is right for D2 Type *tb = arg->type->toBasetype(); if (tb->ty == Tsarray) - { TypeSArray *ts = (TypeSArray *)tb; + { + TypeSArray *ts = (TypeSArray *)tb; Type *ta = ts->next->arrayOf(); if (ts->size(arg->loc) == 0) arg = new NullExp(arg->loc, ta); else arg = arg->castTo(sc, ta); } -#if DMDV2 if (tb->ty == Tstruct) { - arg = callCpCtor(loc, sc, arg, 1); + arg = callCpCtor(sc, arg); } #endif @@ -1594,7 +1843,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, * in ( ) if its precedence is less than pr. */ -void expToCBuffer(OutBuffer *buf, HdrGenState *hgs, Expression *e, enum PREC pr) +void expToCBuffer(OutBuffer *buf, HdrGenState *hgs, Expression *e, PREC pr) { #if !IN_LLVM #ifdef DEBUG @@ -1620,6 +1869,33 @@ void expToCBuffer(OutBuffer *buf, HdrGenState *hgs, Expression *e, enum PREC pr) e->toCBuffer(buf, hgs); } +void sizeToCBuffer(OutBuffer *buf, HdrGenState *hgs, Expression *e) +{ + if (e->type == Type::tsize_t) + { + Expression *ex = (e->op == TOKcast ? ((CastExp *)e)->e1 : e); + ex = ex->optimize(WANTvalue); + + dinteger_t uval = ex->op == TOKint64 ? ex->toInteger() : (dinteger_t)-1; + if ((sinteger_t)uval >= 0) + { + dinteger_t sizemax; + if (Target::ptrsize == 4) + sizemax = 0xFFFFFFFFUL; + else if (Target::ptrsize == 8) + sizemax = 0xFFFFFFFFFFFFFFFFULL; + else + assert(0); + if (uval <= sizemax && uval <= 0x7FFFFFFFFFFFFFFFULL) + { + buf->printf("%llu", uval); + return; + } + } + } + expToCBuffer(buf, hgs, e, PREC_assign); +} + /************************************************** * Write out argument list to buf. */ @@ -1645,12 +1921,12 @@ void argsToCBuffer(OutBuffer *buf, Expressions *expressions, HdrGenState *hgs) void argExpTypesToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs) { - if (arguments) - { OutBuffer argbuf; - + if (arguments && arguments->dim) + { + OutBuffer argbuf; for (size_t i = 0; i < arguments->dim; i++) - { Expression *e = (*arguments)[i]; - + { + Expression *e = (*arguments)[i]; if (i) buf->writestring(", "); argbuf.reset(); @@ -1662,7 +1938,7 @@ void argExpTypesToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *h /******************************** Expression **************************/ -Expression::Expression(Loc loc, enum TOK op, int size) +Expression::Expression(Loc loc, TOK op, int size) { //printf("Expression::Expression(op = %d) this = %p\n", op, this); this->loc = loc; @@ -1716,7 +1992,7 @@ Expression *Expression::copy() } e = (Expression *)mem.malloc(size); //printf("Expression::copy(op = %d) e = %p\n", op, e); - return (Expression *)memcpy(e, this, size); + return (Expression *)memcpy((void*)e, (void*)this, size); } /************************** @@ -1754,29 +2030,6 @@ Expression *Expression::trySemantic(Scope *sc) return e; } -/********************************** - * Shortcut to run semantic with purity and - * safety checking disabled for the immediate - * expressions - */ - -Expression *Expression::ctfeSemantic(Scope *sc) -{ - if (sc) - { - assert(sc->needctfe >= 0); - sc->needctfe++; - Expression *e = semantic(sc); - sc->needctfe--; - assert(sc->needctfe >= 0); - return e; - } - else - { - return semantic(sc); - } -} - void Expression::print() { fprintf(stderr, "%s\n", toChars()); @@ -1887,11 +2140,7 @@ real_t Expression::toImaginary() complex_t Expression::toComplex() { error("Floating point constant expression expected instead of %s", toChars()); -#ifdef IN_GCC - return complex_t(real_t(0)); // %% nicer -#else - return 0.0; -#endif + return (complex_t)0.0; } StringExp *Expression::toString() @@ -1959,7 +2208,9 @@ Expression *Expression::modifiableLvalue(Scope *sc, Expression *e) if (type->isMutable()) { if (!type->isAssignable()) - error("cannot modify struct %s %s with immutable members", toChars(), type->toChars()); + { error("cannot modify struct %s %s with immutable members", toChars(), type->toChars()); + goto Lerror; + } } else { @@ -1978,9 +2229,13 @@ Expression *Expression::modifiableLvalue(Scope *sc, Expression *e) { error("cannot modify %s expression %s", MODtoChars(type->mod), toChars()); } + goto Lerror; } } return toLvalue(sc, e); + +Lerror: + return new ErrorExp(); } @@ -2074,13 +2329,13 @@ void Expression::checkPurity(Scope *sc, FuncDeclaration *f) } // Find the closest pure parent of the called function - if (getFuncTemplateDecl(f) && + if (getFuncTemplateDecl(f) && !f->isNested() && f->parent->isTemplateInstance()->enclosing == NULL) { // The closest pure parent of instantiated non-nested template function is // always itself. - if (!f->isPure() && outerfunc->setImpure()) + if (!f->isPure() && outerfunc->setImpure() && !(sc->flags & SCOPEctfe)) error("pure function '%s' cannot call impure function '%s'", - outerfunc->toChars(), f->toChars()); + outerfunc->toPrettyChars(), f->toPrettyChars()); return; } FuncDeclaration *calledparent = f; @@ -2118,7 +2373,7 @@ void Expression::checkPurity(Scope *sc, FuncDeclaration *f) // OR, they must have the same pure parent. if (/*outerfunc->isPure() &&*/ // comment out because we deduce purity now !f->isPure() && calledparent != outerfunc && - !sc->needctfe) + !(sc->flags & SCOPEctfe)) { if (outerfunc->setImpure()) error("pure function '%s' cannot call impure function '%s'", @@ -2135,10 +2390,9 @@ void Expression::checkPurity(Scope *sc, FuncDeclaration *f) /******************************************* * Accessing variable v. * Check for purity and safety violations. - * If ethis is not NULL, then ethis is the 'this' pointer as in ethis.v */ -void Expression::checkPurity(Scope *sc, VarDeclaration *v, Expression *ethis) +void Expression::checkPurity(Scope *sc, VarDeclaration *v) { /* Look for purity and safety violations when accessing variable v * from current function. @@ -2149,7 +2403,7 @@ void Expression::checkPurity(Scope *sc, VarDeclaration *v, Expression *ethis) v->ident != Id::ctfe && // magic variable never violates pure and safe !v->isImmutable() && // always safe and pure to access immutables... !(v->isConst() && !v->isRef() && (v->isDataseg() || v->isParameter()) && - v->type->implicitConvTo(v->type->invariantOf())) && + v->type->implicitConvTo(v->type->immutableOf())) && // or const global/parameter values which have no mutable indirections !(v->storage_class & STCmanifest) // ...or manifest constants ) @@ -2166,7 +2420,8 @@ void Expression::checkPurity(Scope *sc, VarDeclaration *v, Expression *ethis) FuncDeclaration *ff = s->isFuncDeclaration(); if (!ff) break; - if (ff->setImpure() && !msg) + // Accessing implicit generated __gate is pure. + if (ff->setImpure() && !msg && strcmp(v->ident->toChars(), "__gate")) { error("pure function '%s' cannot access mutable static data '%s'", sc->func->toPrettyChars(), v->toChars()); msg = TRUE; // only need the innermost message @@ -2175,6 +2430,26 @@ void Expression::checkPurity(Scope *sc, VarDeclaration *v, Expression *ethis) } else { + /* Bugzilla 10981: Special case for the contracts of pure virtual function. + * Rewrite: + * tret foo(int i) pure + * in { assert(i); } out { assert(i); } body { ... } + * + * as: + * tret foo(int i) pure { + * void __require() pure { assert(i); } // allow accessing to i + * void __ensure() pure { assert(i); } // allow accessing to i + * __require(); + * ... + * __ensure(); + * } + */ + if ((sc->func->ident == Id::require || sc->func->ident == Id::ensure) && + v->isParameter() && sc->func->parent == v->parent) + { + return; + } + /* Given: * void f() * { int fx; @@ -2219,7 +2494,7 @@ void Expression::checkPurity(Scope *sc, VarDeclaration *v, Expression *ethis) void Expression::checkSafety(Scope *sc, FuncDeclaration *f) { if (sc->func && !sc->intypeof && - !(sc->needctfe) && + !(sc->flags & SCOPEctfe) && !f->isSafe() && !f->isTrusted()) { if (sc->func->setUnsafe()) @@ -2388,20 +2663,25 @@ Expression *Expression::isTemp() { //printf("isTemp() %s\n", toChars()); if (op == TOKcomma) - { CommaExp *ec = (CommaExp *)this; + { + CommaExp *ec = (CommaExp *)this; if (ec->e1->op == TOKdeclaration && ec->e2->op == TOKvar) - { DeclarationExp *de = (DeclarationExp *)ec->e1; + { + DeclarationExp *de = (DeclarationExp *)ec->e1; VarExp *ve = (VarExp *)ec->e2; - if (ve->var == de->declaration && ve->var->storage_class & STCctfe) - { VarDeclaration *v = ve->var->isVarDeclaration(); + if (de->declaration == ve->var && ve->var->storage_class & STCctfe) + { + VarDeclaration *v = ve->var->isVarDeclaration(); if (v && v->init) { ExpInitializer *ei = v->init->isExpInitializer(); if (ei) - { Expression *e = ei->exp; + { + Expression *e = ei->exp; if (e->op == TOKconstruct) - { ConstructExp *ce = (ConstructExp *)e; + { + ConstructExp *ce = (ConstructExp *)e; if (ce->e1->op == TOKvar && ((VarExp *)ce->e1)->var == ve->var) e = ce->e2; } @@ -2449,15 +2729,20 @@ IntegerExp::IntegerExp(dinteger_t value) this->value = value; } -int IntegerExp::equals(Object *o) -{ IntegerExp *ne; - - if (this == o || - (((Expression *)o)->op == TOKint64 && - ((ne = (IntegerExp *)o), type->toHeadMutable()->equals(ne->type->toHeadMutable())) && - value == ne->value)) - return 1; - return 0; +bool IntegerExp::equals(RootObject *o) +{ + if (this == o) + return true; + if (((Expression *)o)->op == TOKint64) + { + IntegerExp *ne = (IntegerExp *)o; + if (type->toHeadMutable()->equals(ne->type->toHeadMutable()) && + value == ne->value) + { + return true; + } + } + return false; } char *IntegerExp::toChars() @@ -2544,7 +2829,7 @@ real_t IntegerExp::toImaginary() complex_t IntegerExp::toComplex() { - return toReal(); + return (complex_t)toReal(); } int IntegerExp::isBool(int result) @@ -2758,11 +3043,8 @@ char *RealExp::toChars() Plus one for rounding. */ char buffer[sizeof(value) * 3 + 8 + 1 + 1]; -#ifdef IN_GCC - value.format(buffer, sizeof(buffer)); -#else ld_sprint(buffer, 'g', value); -#endif + if (type->isimaginary()) strcat(buffer, "i"); @@ -2772,20 +3054,12 @@ char *RealExp::toChars() dinteger_t RealExp::toInteger() { -#ifdef IN_GCC - return (sinteger_t) toReal().toInt(); -#else return (sinteger_t) toReal(); -#endif } uinteger_t RealExp::toUInteger() { -#ifdef IN_GCC - return (uinteger_t) toReal().toInt(); -#else return (uinteger_t) toReal(); -#endif } real_t RealExp::toReal() @@ -2816,23 +3090,23 @@ complex_t RealExp::toComplex() int RealEquals(real_t x1, real_t x2) { return (Port::isNan(x1) && Port::isNan(x2)) || - /* In some cases, the REALPAD bytes get garbage in them, - * so be sure and ignore them. - */ - memcmp(&x1, &x2, Target::realsize - Target::realpad) == 0; + Port::fequal(x1, x2); } -int RealExp::equals(Object *o) -{ RealExp *ne; - - if (this == o || - (((Expression *)o)->op == TOKfloat64 && - ((ne = (RealExp *)o), type->toHeadMutable()->equals(ne->type->toHeadMutable())) && - RealEquals(value, ne->value) - ) - ) - return 1; - return 0; +bool RealExp::equals(RootObject *o) +{ + if (this == o) + return true; + if (((Expression *)o)->op == TOKfloat64) + { + RealExp *ne = (RealExp *)o; + if (type->toHeadMutable()->equals(ne->type->toHeadMutable()) && + RealEquals(value, ne->value)) + { + return true; + } + } + return false; } Expression *RealExp::semantic(Scope *sc) @@ -2846,12 +3120,8 @@ Expression *RealExp::semantic(Scope *sc) int RealExp::isBool(int result) { -#ifdef IN_GCC - return result ? (! value.isZero()) : (value.isZero()); -#else return result ? (value != 0) : (value == 0); -#endif } void floatToBuffer(OutBuffer *buf, Type *type, real_t value) @@ -2867,37 +3137,11 @@ void floatToBuffer(OutBuffer *buf, Type *type, real_t value) char buffer[32]; ld_sprint(buffer, 'g', value); assert(strlen(buffer) < sizeof(buffer) / sizeof(buffer[0])); -#if _WIN32 && __DMC__ - const char *save = __locale_decpoint; - __locale_decpoint = "."; - real_t r = strtold(buffer, NULL); - __locale_decpoint = save; -#else - real_t r = Port::strtold(buffer, NULL); -#endif -#if IN_LLVM - if (r == value) // if exact duplication - buf->writestring(buffer); - else - { -#ifdef __HAIKU__ // broken printf workaround - char buffer2[25]; - char *ptr = (char *)&value; - for(int i = 0; i < sizeof(value); i++) - snprintf(buffer2, sizeof(char), "%x", ptr[i]); - buf->writestring(buffer2); -#else - buf->printf("%La", value); // ensure exact duplication -#endif - } -#else // if IN_DMD + real_t r = Port::strtold(buffer, NULL); if (r != value) // if exact duplication ld_sprint(buffer, 'a', value); buf->writestring(buffer); -#endif - - if (type) { @@ -2944,6 +3188,8 @@ void realToMangleBuffer(OutBuffer *buf, real_t value) if (Port::isNan(value)) buf->writestring("NAN"); // no -NAN bugs + else if (Port::isInfinity(value)) + buf->writestring(value < 0 ? "NINF" : "INF"); else { char buffer[36]; @@ -2997,13 +3243,9 @@ char *ComplexExp::toChars() char buf1[sizeof(value) * 3 + 8 + 1]; char buf2[sizeof(value) * 3 + 8 + 1]; -#ifdef IN_GCC - creall(value).format(buf1, sizeof(buf1)); - cimagl(value).format(buf2, sizeof(buf2)); -#else + ld_sprint(buf1, 'g', creall(value)); ld_sprint(buf2, 'g', cimagl(value)); -#endif sprintf(buffer, "(%s+%si)", buf1, buf2); assert(strlen(buffer) < sizeof(buffer) / sizeof(buffer[0])); return mem.strdup(buffer); @@ -3011,20 +3253,12 @@ char *ComplexExp::toChars() dinteger_t ComplexExp::toInteger() { -#ifdef IN_GCC - return (sinteger_t) toReal().toInt(); -#else return (sinteger_t) toReal(); -#endif } uinteger_t ComplexExp::toUInteger() { -#ifdef IN_GCC - return (uinteger_t) toReal().toInt(); -#else return (uinteger_t) toReal(); -#endif } real_t ComplexExp::toReal() @@ -3042,18 +3276,21 @@ complex_t ComplexExp::toComplex() return value; } -int ComplexExp::equals(Object *o) -{ ComplexExp *ne; - - if (this == o || - (((Expression *)o)->op == TOKcomplex80 && - ((ne = (ComplexExp *)o), type->toHeadMutable()->equals(ne->type->toHeadMutable())) && - RealEquals(creall(value), creall(ne->value)) && - RealEquals(cimagl(value), cimagl(ne->value)) - ) - ) - return 1; - return 0; +bool ComplexExp::equals(RootObject *o) +{ + if (this == o) + return true; + if (((Expression *)o)->op == TOKcomplex80) + { + ComplexExp *ne = (ComplexExp *)o; + if (type->toHeadMutable()->equals(ne->type->toHeadMutable()) && + RealEquals(creall(value), creall(ne->value)) && + RealEquals(cimagl(value), cimagl(ne->value))) + { + return true; + } + } + return false; } Expression *ComplexExp::semantic(Scope *sc) @@ -3078,19 +3315,11 @@ void ComplexExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) /* Print as: * (re+imi) */ -#ifdef IN_GCC - char buf1[sizeof(value) * 3 + 8 + 1]; - char buf2[sizeof(value) * 3 + 8 + 1]; - creall(value).format(buf1, sizeof(buf1)); - cimagl(value).format(buf2, sizeof(buf2)); - buf->printf("(%s+%si)", buf1, buf2); -#else buf->writeByte('('); floatToBuffer(buf, type, creall(value)); buf->writeByte('+'); floatToBuffer(buf, type, cimagl(value)); buf->writestring("i)"); -#endif } void ComplexExp::toMangleBuffer(OutBuffer *buf) @@ -3176,12 +3405,13 @@ Expression *IdentifierExp::semantic(Scope *sc) */ FuncDeclaration *f = s->isFuncDeclaration(); if (f) - { TemplateDeclaration *tempdecl = getFuncTemplateDecl(f); - if (tempdecl) + { + TemplateDeclaration *td = getFuncTemplateDecl(f); + if (td) { - if (tempdecl->overroot) // if not start of overloaded list of TemplateDeclaration's - tempdecl = tempdecl->overroot; // then get the start - e = new TemplateExp(loc, tempdecl, f); + if (td->overroot) // if not start of overloaded list of TemplateDeclaration's + td = td->overroot; // then get the start + e = new TemplateExp(loc, td, f); e = e->semantic(sc); return e; } @@ -3261,7 +3491,7 @@ DollarExp::DollarExp(Loc loc) /******************************** DsymbolExp **************************/ -DsymbolExp::DsymbolExp(Loc loc, Dsymbol *s, int hasOverloads) +DsymbolExp::DsymbolExp(Loc loc, Dsymbol *s, bool hasOverloads) : Expression(loc, TOKdsymbol, sizeof(DsymbolExp)) { this->s = s; @@ -3319,13 +3549,6 @@ Lagain: em = s->isEnumMember(); if (em) { - e = em->value; - if (!e) - { - em->errors = true; - error("forward reference of %s %s", s->kind(), s->toChars()); - return new ErrorExp(); - } return em->getVarExp(loc, sc); } v = s->isVarDeclaration(); @@ -3347,7 +3570,7 @@ Lagain: if (v->scope) { v->inuse++; - v->init->semantic(v->scope, v->type, INITinterpret); + v->init = v->init->semantic(v->scope, v->type, INITinterpret); v->scope = NULL; v->inuse--; } @@ -3380,11 +3603,6 @@ Lagain: if (!f->functionSemantic()) return new ErrorExp(); - if (f->isUnitTestDeclaration()) - { - error("cannot call unittest function %s", toChars()); - return new ErrorExp(); - } if (!f->type->deco) { error("forward reference to %s", toChars()); @@ -3699,15 +3917,15 @@ NullExp::NullExp(Loc loc, Type *type) this->type = type; } -int NullExp::equals(Object *o) +bool NullExp::equals(RootObject *o) { if (o && o->dyncast() == DYNCAST_EXPRESSION) - { Expression *e = (Expression *)o; - + { + Expression *e = (Expression *)o; if (e->op == TOKnull) - return TRUE; + return true; } - return FALSE; + return false; } Expression *NullExp::semantic(Scope *sc) @@ -3771,7 +3989,7 @@ StringExp::StringExp(Loc loc, void *string, size_t len) this->ownedByCtfe = false; } -StringExp::StringExp(Loc loc, void *string, size_t len, unsigned char postfix) +StringExp::StringExp(Loc loc, void *string, size_t len, utf8_t postfix) : Expression(loc, TOKstring, sizeof(StringExp)) { this->string = string; @@ -3790,18 +4008,18 @@ Expression *StringExp::syntaxCopy() } #endif -int StringExp::equals(Object *o) +bool StringExp::equals(RootObject *o) { //printf("StringExp::equals('%s') %s\n", o->toChars(), toChars()); if (o && o->dyncast() == DYNCAST_EXPRESSION) - { Expression *e = (Expression *)o; - + { + Expression *e = (Expression *)o; if (e->op == TOKstring) { return compare(o) == 0; } } - return FALSE; + return false; } Expression *StringExp::semantic(Scope *sc) @@ -3821,7 +4039,7 @@ Expression *StringExp::semantic(Scope *sc) case 'd': for (u = 0; u < len;) { - p = utf_decodeChar((unsigned char *)string, len, &u, &c); + p = utf_decodeChar((utf8_t *)string, len, &u, &c); if (p) { error("%s", p); return new ErrorExp(); @@ -3836,14 +4054,14 @@ Expression *StringExp::semantic(Scope *sc) len = newlen; sz = 4; //type = new TypeSArray(Type::tdchar, new IntegerExp(loc, len, Type::tindex)); - type = new TypeDArray(Type::tdchar->invariantOf()); + type = new TypeDArray(Type::tdchar->immutableOf()); committed = 1; break; case 'w': for (u = 0; u < len;) { - p = utf_decodeChar((unsigned char *)string, len, &u, &c); + p = utf_decodeChar((utf8_t *)string, len, &u, &c); if (p) { error("%s", p); return new ErrorExp(); @@ -3860,7 +4078,7 @@ Expression *StringExp::semantic(Scope *sc) len = newlen; sz = 2; //type = new TypeSArray(Type::twchar, new IntegerExp(loc, len, Type::tindex)); - type = new TypeDArray(Type::twchar->invariantOf()); + type = new TypeDArray(Type::twchar->immutableOf()); committed = 1; break; @@ -3868,11 +4086,11 @@ Expression *StringExp::semantic(Scope *sc) committed = 1; default: //type = new TypeSArray(Type::tchar, new IntegerExp(loc, len, Type::tindex)); - type = new TypeDArray(Type::tchar->invariantOf()); + type = new TypeDArray(Type::tchar->immutableOf()); break; } type = type->semantic(loc, sc); - //type = type->invariantOf(); + //type = type->immutableOf(); //printf("type = %s\n", type->toChars()); } return this; @@ -3893,7 +4111,7 @@ size_t StringExp::length() case 1: for (size_t u = 0; u < len;) { - p = utf_decodeChar((unsigned char *)string, len, &u, &c); + p = utf_decodeChar((utf8_t *)string, len, &u, &c); if (p) { error("%s", p); return 0; @@ -3950,7 +4168,7 @@ StringExp *StringExp::toUTF8(Scope *sc) return this; } -int StringExp::compare(Object *obj) +int StringExp::compare(RootObject *obj) { //printf("StringExp::compare()\n"); // Used to sort case statement expressions so we can do an efficient lookup @@ -4039,7 +4257,7 @@ unsigned StringExp::charAt(size_t i) switch (sz) { case 1: - value = ((unsigned char *)string)[i]; + value = ((utf8_t *)string)[i]; break; case 2: @@ -4098,7 +4316,7 @@ void StringExp::toMangleBuffer(OutBuffer *buf) const char *p; unsigned c; size_t u; - unsigned char *q; + utf8_t *q; size_t qlen; /* Write string in UTF-8 format @@ -4106,7 +4324,7 @@ void StringExp::toMangleBuffer(OutBuffer *buf) switch (sz) { case 1: m = 'a'; - q = (unsigned char *)string; + q = (utf8_t *)string; qlen = len; break; case 2: @@ -4142,12 +4360,12 @@ void StringExp::toMangleBuffer(OutBuffer *buf) buf->writeByte(m); buf->printf("%d_", (int)qlen); // nbytes <= 11 - for (unsigned char *p = buf->data + buf->offset, *pend = p + 2 * qlen; + for (utf8_t *p = buf->data + buf->offset, *pend = p + 2 * qlen; p < pend; p += 2, ++q) { - unsigned char hi = *q >> 4 & 0xF; + utf8_t hi = *q >> 4 & 0xF; p[0] = (hi < 10 ? hi + '0' : hi - 10 + 'a'); - unsigned char lo = *q & 0xF; + utf8_t lo = *q & 0xF; p[1] = (lo < 10 ? lo + '0' : lo - 10 + 'a'); } buf->offset += 2 * qlen; @@ -4172,6 +4390,29 @@ ArrayLiteralExp::ArrayLiteralExp(Loc loc, Expression *e) this->ownedByCtfe = false; } +bool ArrayLiteralExp::equals(RootObject *o) +{ + if (this == o) + return true; + if (o && o->dyncast() == DYNCAST_EXPRESSION && + ((Expression *)o)->op == TOKarrayliteral) + { + ArrayLiteralExp *ae = (ArrayLiteralExp *)o; + if (elements->dim != ae->elements->dim) + return false; + for (size_t i = 0; i < elements->dim; i++) + { + Expression *e1 = (*elements)[i]; + Expression *e2 = (*ae->elements)[i]; + if (e1 != e2 && + (!e1 || !e2 || !e1->equals(e2))) + return false; + } + return true; + } + return false; +} + Expression *ArrayLiteralExp::syntaxCopy() { return new ArrayLiteralExp(loc, arraySyntaxCopy(elements)); @@ -4221,23 +4462,31 @@ StringExp *ArrayLiteralExp::toString() if (telem == Tchar || telem == Twchar || telem == Tdchar || (telem == Tvoid && (!elements || elements->dim == 0))) { + unsigned char sz = 1; + if (telem == Twchar) sz = 2; + else if (telem == Tdchar) sz = 4; + OutBuffer buf; if (elements) + { for (int i = 0; i < elements->dim; ++i) { Expression *ch = (*elements)[i]; if (ch->op != TOKint64) return NULL; - buf.writeUTF8(ch->toInteger()); + if (sz == 1) buf.writebyte(ch->toInteger()); + else if (sz == 2) buf.writeword(ch->toInteger()); + else buf.write4(ch->toInteger()); } - buf.writebyte(0); + } + char prefix; + if (sz == 1) { prefix = 'c'; buf.writebyte(0); } + else if (sz == 2) { prefix = 'w'; buf.writeword(0); } + else { prefix = 'd'; buf.write4(0); } - char prefix = 'c'; - if (telem == Twchar) prefix = 'w'; - else if (telem == Tdchar) prefix = 'd'; - - const size_t len = buf.offset - 1; + const size_t len = buf.offset / sz - 1; StringExp *se = new StringExp(loc, buf.extractData(), len, prefix); + se->sz = sz; se->type = type; return se; } @@ -4380,26 +4629,29 @@ StructLiteralExp::StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions * //printf("StructLiteralExp::StructLiteralExp(%s)\n", toChars()); } -int StructLiteralExp::equals(Object *o) +bool StructLiteralExp::equals(RootObject *o) { if (this == o) - return 1; + return true; if (o && o->dyncast() == DYNCAST_EXPRESSION && ((Expression *)o)->op == TOKstructliteral) { StructLiteralExp *se = (StructLiteralExp *)o; if (sd != se->sd) - return 0; + return false; if (elements->dim != se->elements->dim) - return 0; + return false; for (size_t i = 0; i < elements->dim; i++) { - if (!(*elements)[i]->equals((*se->elements)[i])) - return 0; + Expression *e1 = (*elements)[i]; + Expression *e2 = (*se->elements)[i]; + if (e1 != e2 && + (!e1 || !e2 || !e1->equals(e2))) + return false; } - return 1; + return true; } - return 0; + return false; } Expression *StructLiteralExp::syntaxCopy() @@ -4410,8 +4662,7 @@ Expression *StructLiteralExp::syntaxCopy() } Expression *StructLiteralExp::semantic(Scope *sc) -{ Expression *e; - +{ #if LOGSEMANTIC printf("StructLiteralExp::semantic('%s')\n", toChars()); #endif @@ -4427,13 +4678,18 @@ Expression *StructLiteralExp::semantic(Scope *sc) expandTuples(elements); size_t offset = 0; for (size_t i = 0; i < elements->dim; i++) - { e = (*elements)[i]; + { + Expression *e = (*elements)[i]; if (!e) continue; e = resolveProperties(sc, e); if (i >= nfields) { + if (i == sd->fields.dim - 1 && sd->isNested() && e->op == TOKnull) + { // CTFE sometimes creates null as hidden pointer; we'll allow this. + continue; + } #if 0 for (size_t i = 0; i < sd->fields.dim; i++) printf("[%d] = %s\n", i, sd->fields[i]->toChars()); @@ -4441,11 +4697,10 @@ Expression *StructLiteralExp::semantic(Scope *sc) error("more initializers than fields (%d) of %s", nfields, sd->toChars()); return new ErrorExp(); } - Dsymbol *s = sd->fields[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v); + VarDeclaration *v = sd->fields[i]; if (v->offset < offset) - { error("overlapping initialization for %s", v->toChars()); + { + error("overlapping initialization for %s", v->toChars()); return new ErrorExp(); } offset = v->offset + v->type->size(); @@ -4455,7 +4710,8 @@ Expression *StructLiteralExp::semantic(Scope *sc) telem = telem->addMod(stype->mod); Type *origType = telem; while (!e->implicitConvTo(telem) && telem->toBasetype()->ty == Tsarray) - { /* Static array initialization, as in: + { + /* Static array initialization, as in: * T[3][5] = e; */ telem = telem->toBasetype()->nextOf(); @@ -4468,19 +4724,20 @@ Expression *StructLiteralExp::semantic(Scope *sc) if (e->op == TOKerror) return e; - (*elements)[i] = callCpCtor(e->loc, sc, e, 1); + (*elements)[i] = e->isLvalue() ? callCpCtor(sc, e) : valueNoDtor(e); } /* Fill out remainder of elements[] with default initializers for fields[] */ for (size_t i = elements->dim; i < nfields; i++) - { Dsymbol *s = sd->fields[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v); + { + Expression *e; + VarDeclaration *v = sd->fields[i]; assert(!v->isThisDeclaration()); if (v->offset < offset) - { e = NULL; + { + e = NULL; sd->hasUnions = 1; } else @@ -4494,7 +4751,7 @@ Expression *StructLiteralExp::semantic(Scope *sc) } else { - if (v->storage_class & STCnodefaultctor) + if ((v->storage_class & STCnodefaultctor) && !ctorinit) { error("field %s.%s must be initialized because it has no default constructor", sd->type->toChars(), v->toChars()); @@ -4506,6 +4763,15 @@ Expression *StructLiteralExp::semantic(Scope *sc) } offset = v->offset + v->type->size(); } + if (e && e->op == TOKerror) + { + /* An error in the initializer needs to be recorded as an error + * in the enclosing function or template, since the initializer + * will be part of the stuct declaration. + */ + global.increaseErrorCount(); + return e; + } elements->push(e); } @@ -4623,19 +4889,21 @@ void StructLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring(sd->toChars()); buf->writeByte('('); -#if IN_LLVM // Backport of DMD pull request 2183. - if (stageflags & 32) - buf->writestring("..."); + + // CTFE can generate struct literals that contain an AddrExp pointing + // to themselves, need to avoid infinite recursion: + // struct S { this(int){ this.s = &this; } S* s; } + // const foo = new S(0); + if (stageflags & stageToCBuffer) + buf->writestring(""); else { int old = stageflags; - stageflags |= 32; -#endif - argsToCBuffer(buf, elements, hgs); -#if IN_LLVM + stageflags |= stageToCBuffer; + argsToCBuffer(buf, elements, hgs); stageflags = old; } -#endif + buf->writeByte(')'); } @@ -4746,31 +5014,50 @@ Expression *ScopeExp::syntaxCopy() Expression *ScopeExp::semantic(Scope *sc) { - TemplateInstance *ti; - ScopeDsymbol *sds2; - #if LOGSEMANTIC printf("+ScopeExp::semantic('%s')\n", toChars()); #endif + //if (type == Type::tvoid) + // return this; + Lagain: - ti = sds->isTemplateInstance(); - if (ti && !ti->errors) + TemplateInstance *ti = sds->isTemplateInstance(); + if (ti) { - unsigned olderrs = global.errors; + if (!ti->findTemplateDeclaration(sc) || + !ti->semanticTiargs(sc)) + { + ti->inst = ti; + ti->inst->errors = true; + return new ErrorExp(); + } if (ti->needsTypeInference(sc)) { - TemplateDeclaration *td = ti->tempdecl; - Dsymbol *p = td->toParent2(); - FuncDeclaration *fdthis = hasThis(sc); - AggregateDeclaration *ad = p ? p->isAggregateDeclaration() : NULL; - if (fdthis && ad && isAggregate(fdthis->vthis->type) == ad && - (td->scope->stc & STCstatic) == 0) + if (TemplateDeclaration *td = ti->tempdecl->isTemplateDeclaration()) { - Expression *e = new DotTemplateInstanceExp(loc, new ThisExp(loc), ti->name, ti->tiargs); - return e->semantic(sc); + Dsymbol *p = td->toParent2(); + FuncDeclaration *fdthis = hasThis(sc); + AggregateDeclaration *ad = p ? p->isAggregateDeclaration() : NULL; + if (fdthis && ad && isAggregate(fdthis->vthis->type) == ad && + (td->scope->stc & STCstatic) == 0) + { + Expression *e = new DotTemplateInstanceExp(loc, new ThisExp(loc), ti->name, ti->tiargs); + return e->semantic(sc); + } + } + else if (OverloadSet *os = ti->tempdecl->isOverloadSet()) + { + FuncDeclaration *fdthis = hasThis(sc); + AggregateDeclaration *ad = os->parent->isAggregateDeclaration(); + if (fdthis && ad && isAggregate(fdthis->vthis->type) == ad) + { + Expression *e = new DotTemplateInstanceExp(loc, new ThisExp(loc), ti->name, ti->tiargs); + return e->semantic(sc); + } } return this; } + unsigned olderrs = global.errors; if (!ti->semanticRun) ti->semantic(sc); if (ti->inst) @@ -4778,9 +5065,10 @@ Lagain: if (ti->inst->errors) return new ErrorExp(); Dsymbol *s = ti->inst->toAlias(); - sds2 = s->isScopeDsymbol(); + ScopeDsymbol *sds2 = s->isScopeDsymbol(); if (!sds2) - { Expression *e; + { + Expression *e; //printf("s = %s, '%s'\n", s->kind(), s->toChars()); if (ti->withsym) @@ -4981,7 +5269,7 @@ Lagain: goto Lerr; } - if (cd->noDefaultCtor && !nargs) + if (cd->noDefaultCtor && !nargs && !cd->defaultCtor) { error("default construction is disabled for type %s", cd->type->toChars()); goto Lerr; } @@ -5060,6 +5348,10 @@ Lagain: if (f) { checkDeprecated(sc, f); +#if DMDV2 + checkPurity(sc, f); + checkSafety(sc, f); +#endif member = f->isCtorDeclaration(); assert(member); @@ -5155,6 +5447,10 @@ Lagain: if (f) { checkDeprecated(sc, f); +#if DMDV2 + checkPurity(sc, f); + checkSafety(sc, f); +#endif member = f->isCtorDeclaration(); assert(member); @@ -5200,9 +5496,7 @@ Lagain: } else if (tb->ty == Tarray && nargs) { - Type *tn = tb->nextOf()->toBasetype(); - while (tn->ty == Tsarray) - tn = tn->nextOf()->toBasetype(); + Type *tn = tb->nextOf()->baseElemOf(); Dsymbol *s = tn->toDsymbol(sc); AggregateDeclaration *ad = s ? s->isAggregateDeclaration() : NULL; if (ad && ad->noDefaultCtor) @@ -5306,10 +5600,11 @@ Expression *NewAnonClassExp::semantic(Scope *sc) #endif Expression *d = new DeclarationExp(loc, cd); - int needctfe = sc->needctfe; - sc->needctfe = 0; + sc = sc->startCTFE(); // just create new scope + sc->flags &= ~SCOPEctfe; // temporary stop CTFE d = d->semantic(sc); - sc->needctfe = needctfe; + sc->flags |= SCOPEctfe; + sc = sc->endCTFE(); Expression *n = new NewExp(loc, thisexp, newargs, cd->type, arguments); @@ -5348,7 +5643,7 @@ void NewAnonClassExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) /********************** SymbolExp **************************************/ #if DMDV2 -SymbolExp::SymbolExp(Loc loc, enum TOK op, int size, Declaration *var, int hasOverloads) +SymbolExp::SymbolExp(Loc loc, TOK op, int size, Declaration *var, bool hasOverloads) : Expression(loc, op, size) { assert(var); @@ -5359,7 +5654,7 @@ SymbolExp::SymbolExp(Loc loc, enum TOK op, int size, Declaration *var, int hasOv /********************** SymOffExp **************************************/ -SymOffExp::SymOffExp(Loc loc, Declaration *var, unsigned offset, int hasOverloads) +SymOffExp::SymOffExp(Loc loc, Declaration *var, unsigned offset, bool hasOverloads) : SymbolExp(loc, TOKsymoff, sizeof(SymOffExp), var, hasOverloads) { this->offset = offset; @@ -5411,13 +5706,15 @@ void SymOffExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { if (offset) buf->printf("(& %s+%u)", var->toChars(), offset); + else if (var->isTypeInfoDeclaration()) + buf->printf("%s", var->toChars()); else buf->printf("& %s", var->toChars()); } /******************************** VarExp **************************/ -VarExp::VarExp(Loc loc, Declaration *var, int hasOverloads) +VarExp::VarExp(Loc loc, Declaration *var, bool hasOverloads) : SymbolExp(loc, TOKvar, sizeof(VarExp), var, hasOverloads) { //printf("VarExp(this = %p, '%s', loc = %s)\n", this, var->toChars(), loc.toChars()); @@ -5425,15 +5722,20 @@ VarExp::VarExp(Loc loc, Declaration *var, int hasOverloads) this->type = var->type; } -int VarExp::equals(Object *o) -{ VarExp *ne; - - if (this == o || - (((Expression *)o)->op == TOKvar && - ((ne = (VarExp *)o), type->toHeadMutable()->equals(ne->type->toHeadMutable())) && - var == ne->var)) - return 1; - return 0; +bool VarExp::equals(RootObject *o) +{ + if (this == o) + return true; + if (((Expression *)o)->op == TOKvar) + { + VarExp *ne = (VarExp *)o; + if (type->toHeadMutable()->equals(ne->type->toHeadMutable()) && + var == ne->var) + { + return true; + } + } + return false; } Expression *VarExp::semantic(Scope *sc) @@ -5463,9 +5765,10 @@ Expression *VarExp::semantic(Scope *sc) VarDeclaration *v = var->isVarDeclaration(); if (v) { + hasOverloads = 0; v->checkNestedReference(sc, loc); #if DMDV2 - checkPurity(sc, v, NULL); + checkPurity(sc, v); #endif } FuncDeclaration *f = var->isFuncDeclaration(); @@ -5576,6 +5879,12 @@ Expression *OverExp::toLvalue(Scope *sc, Expression *e) { return this; } + +void OverExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(vars->ident->toChars()); +} + #endif @@ -5605,7 +5914,7 @@ TupleExp::TupleExp(Loc loc, TupleDeclaration *tup) this->exps->reserve(tup->objects->dim); for (size_t i = 0; i < tup->objects->dim; i++) - { Object *o = (*tup->objects)[i]; + { RootObject *o = (*tup->objects)[i]; if (Dsymbol *s = getDsymbol(o)) { /* If tuple element represents a symbol, translate to DsymbolExp @@ -5632,27 +5941,27 @@ TupleExp::TupleExp(Loc loc, TupleDeclaration *tup) } } -int TupleExp::equals(Object *o) +bool TupleExp::equals(RootObject *o) { if (this == o) - return 1; + return true; if (((Expression *)o)->op == TOKtuple) { TupleExp *te = (TupleExp *)o; if (exps->dim != te->exps->dim) - return 0; + return false; if (e0 && !e0->equals(te->e0) || !e0 && te->e0) - return 0; + return false; for (size_t i = 0; i < exps->dim; i++) - { Expression *e1 = (*exps)[i]; + { + Expression *e1 = (*exps)[i]; Expression *e2 = (*te->exps)[i]; - if (!e1->equals(e2)) - return 0; + return false; } - return 1; + return true; } - return 0; + return false; } Expression *TupleExp::syntaxCopy() @@ -5727,10 +6036,57 @@ FuncExp::FuncExp(Loc loc, FuncLiteralDeclaration *fd, TemplateDeclaration *td) tok = fd->tok; // save original kind of function/delegate/(infer) } +void FuncExp::genIdent(Scope *sc) +{ + if (fd->ident == Id::empty) + { + const char *s; + if (fd->fes) s = "__foreachbody"; + else if (fd->tok == TOKreserved) s = "__lambda"; + else if (fd->tok == TOKdelegate) s = "__dgliteral"; + else s = "__funcliteral"; + + DsymbolTable *symtab; + if (FuncDeclaration *func = sc->parent->isFuncDeclaration()) + { + symtab = func->localsymtab; + if (symtab) + { + // Inside template constraint, symtab is not set yet. + goto L1; + } + } + else + { + symtab = sc->parent->isScopeDsymbol()->symtab; + L1: + assert(symtab); + int num = _aaLen(symtab->tab) + 1; + Identifier *id = Lexer::uniqueId(s, num); + fd->ident = id; + if (td) td->ident = id; + symtab->insert(td ? (Dsymbol *)td : (Dsymbol *)fd); + } + } +} + Expression *FuncExp::syntaxCopy() { - TemplateDeclaration *td2 = td ? (TemplateDeclaration *)td->syntaxCopy(NULL) : NULL; - return new FuncExp(loc, (FuncLiteralDeclaration *)fd->syntaxCopy(NULL), td2); + TemplateDeclaration *td2; + FuncLiteralDeclaration *fd2; + if (td) + { + td2 = (TemplateDeclaration *)td->syntaxCopy(NULL); + assert(td2->members->dim == 1); + fd2 = (*td2->members)[0]->isFuncLiteralDeclaration(); + assert(fd2); + } + else + { + td2 = NULL; + fd2 = (FuncLiteralDeclaration *)fd->syntaxCopy(NULL); + } + return new FuncExp(loc, fd2, td2); } Expression *FuncExp::semantic(Scope *sc) @@ -5741,8 +6097,8 @@ Expression *FuncExp::semantic(Scope *sc) #endif Expression *e = this; - int needctfe = sc->needctfe; - sc->needctfe = 0; + sc = sc->startCTFE(); // just create new scope + sc->flags &= ~SCOPEctfe; // temporary stop CTFE if (!type || type == Type::tvoid) { @@ -5754,6 +6110,8 @@ Expression *FuncExp::semantic(Scope *sc) //if (fd->treq) // fd->treq = fd->treq->semantic(loc, sc); + genIdent(sc); + // Set target of return type inference if (fd->treq && !fd->type->nextOf()) { TypeFunction *tfv = NULL; @@ -5796,8 +6154,12 @@ Expression *FuncExp::semantic(Scope *sc) } // need to infer return type - if ((olderrors != global.errors) && fd->type && fd->type->ty == Tfunction && !fd->type->nextOf()) - ((TypeFunction *)fd->type)->next = Type::terror; + if (olderrors != global.errors) + { + if (fd->type && fd->type->ty == Tfunction && !fd->type->nextOf()) + ((TypeFunction *)fd->type)->next = Type::terror; + return new ErrorExp(); + } // Type is a "delegate to" or "pointer to" the function literal if ((fd->isNested() && fd->tok == TOKdelegate) || @@ -5831,7 +6193,8 @@ Expression *FuncExp::semantic(Scope *sc) fd->tookAddressOf++; } Ldone: - sc->needctfe = needctfe; + sc->flags |= SCOPEctfe; + sc = sc->endCTFE(); return e; } @@ -5846,6 +6209,8 @@ Expression *FuncExp::semantic(Scope *sc, Expressions *arguments) return checkarg; } + genIdent(sc); + assert(td->parameters && td->parameters->dim); td->semantic(sc); @@ -5960,7 +6325,7 @@ Expression *DeclarationExp::semantic(Scope *sc) return new ErrorExp(); } else if (sc->func) - { VarDeclaration *v = s->isVarDeclaration(); + { if ( (s->isFuncDeclaration() || s->isTypedefDeclaration() || s->isAggregateDeclaration() || s->isEnumDeclaration() || s->isInterfaceDeclaration()) && @@ -6024,7 +6389,7 @@ void DeclarationExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) * typeid(int) */ -TypeidExp::TypeidExp(Loc loc, Object *o) +TypeidExp::TypeidExp(Loc loc, RootObject *o) : Expression(loc, TOKtypeid, sizeof(TypeidExp)) { this->obj = o; @@ -6051,7 +6416,7 @@ Expression *TypeidExp::semantic(Scope *sc) if (ta) { - ta->resolve(loc, sc, &ea, &ta, &sa); + ta->resolve(loc, sc, &ea, &ta, &sa, true); } if (ea) @@ -6130,7 +6495,7 @@ void TraitsExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) for (size_t i = 0; i < args->dim; i++) { buf->writestring(", ");; - Object *oarg = (*args)[i]; + RootObject *oarg = (*args)[i]; ObjectToCBuffer(buf, hgs, oarg); } } @@ -6162,8 +6527,8 @@ void HaltExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) /************************************************************/ -IsExp::IsExp(Loc loc, Type *targ, Identifier *id, enum TOK tok, - Type *tspec, enum TOK tok2, TemplateParameters *parameters) +IsExp::IsExp(Loc loc, Type *targ, Identifier *id, TOK tok, + Type *tspec, TOK tok2, TemplateParameters *parameters) : Expression(loc, TOKis, sizeof(IsExp)) { this->targ = targ; @@ -6263,8 +6628,6 @@ Expression *IsExp::semantic(Scope *sc) tded = targ; break; - case TOKinvariant: - deprecation("use of 'invariant' rather than 'immutable' is deprecated"); case TOKimmutable: if (!targ->isImmutable()) goto Lno; @@ -6445,7 +6808,7 @@ Expression *IsExp::semantic(Scope *sc) { TemplateParameter *tp = (*parameters)[i]; Declaration *s = NULL; - m = tp->matchArg(sc, &tiargs, i, parameters, &dedtypes, &s); + m = tp->matchArg(loc, sc, &tiargs, i, parameters, &dedtypes, &s); if (m == MATCHnomatch) goto Lno; s->semantic(sc); @@ -6526,7 +6889,7 @@ void IsExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) /************************************************************/ -UnaExp::UnaExp(Loc loc, enum TOK op, int size, Expression *e1) +UnaExp::UnaExp(Loc loc, TOK op, int size, Expression *e1) : Expression(loc, op, size) { this->e1 = e1; @@ -6566,7 +6929,7 @@ void UnaExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) /************************************************************/ -BinExp::BinExp(Loc loc, enum TOK op, int size, Expression *e1, Expression *e2) +BinExp::BinExp(Loc loc, TOK op, int size, Expression *e1, Expression *e2) : Expression(loc, op, size) { this->e1 = e1; @@ -6730,7 +7093,7 @@ void BinExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writeByte(' '); buf->writestring(Token::toChars(op)); buf->writeByte(' '); - expToCBuffer(buf, hgs, e2, (enum PREC)(precedence[op] + 1)); + expToCBuffer(buf, hgs, e2, (PREC)(precedence[op] + 1)); } int BinExp::isunsigned() @@ -6920,8 +7283,10 @@ Expression *CompileExp::semantic(Scope *sc) #if LOGSEMANTIC printf("CompileExp::semantic('%s')\n", toChars()); #endif - e1 = e1->ctfeSemantic(sc); + sc = sc->startCTFE(); + e1 = e1->semantic(sc); e1 = resolveProperties(sc, e1); + sc = sc->endCTFE(); if (e1->op == TOKerror) return e1; if (!e1->type->isString()) @@ -6936,8 +7301,8 @@ Expression *CompileExp::semantic(Scope *sc) return new ErrorExp(); } se = se->toUTF8(sc); - Parser p(sc->module, (unsigned char *)se->string, se->len, 0); - p.loc = loc; + Parser p(sc->module, (utf8_t *)se->string, se->len, 0); + p.scanloc = loc; p.nextToken(); //printf("p.loc.linnum = %d\n", p.loc.linnum); unsigned errors = global.errors; @@ -6973,8 +7338,10 @@ Expression *FileExp::semantic(Scope *sc) #if LOGSEMANTIC printf("FileExp::semantic('%s')\n", toChars()); #endif - e1 = e1->ctfeSemantic(sc); + sc = sc->startCTFE(); + e1 = e1->semantic(sc); e1 = resolveProperties(sc, e1); + sc = sc->endCTFE(); e1 = e1->ctfeInterpret(); if (e1->op != TOKstring) { error("file name argument must be a string, not (%s)", e1->toChars()); @@ -7001,7 +7368,23 @@ Expression *FileExp::semantic(Scope *sc) } if (global.params.verbose) - printf("file %s\t(%s)\n", (char *)se->string, name); + fprintf(global.stdmsg, "file %s\t(%s)\n", (char *)se->string, name); + if (global.params.moduleDeps != NULL && global.params.moduleDepsFile == NULL) + { + OutBuffer *ob = global.params.moduleDeps; + Module* imod = sc->instantiatingModule ? sc->instantiatingModule : sc->module; + + ob->writestring("depsFile "); + ob->writestring(imod->toPrettyChars()); + ob->writestring(" ("); + escapePath(ob, imod->srcfile->toChars()); + ob->writestring(") : "); + ob->writestring((char *) se->string); + ob->writestring(" ("); + escapePath(ob, name); + ob->writestring(")"); + ob->writenl(); + } { File f(name); if (f.read()) @@ -7103,6 +7486,15 @@ Expression *DotIdExp::semantic(Scope *sc) //printf("e1->op = %d, '%s'\n", e1->op, Token::toChars(e1->op)); #endif Expression *e = semanticY(sc, 1); + if (e && isDotOpDispatch(e)) + { + unsigned errors = global.startGagging(); + e = resolvePropertiesX(sc, e); + if (global.endGagging(errors)) + e = NULL; /* fall down to UFCS */ + else + return e; + } if (!e) // if failed to find the property { /* If ident is not a valid property, rewrite: @@ -7130,15 +7522,26 @@ Expression *DotIdExp::semanticX(Scope *sc) Dsymbol *ds; switch (e1->op) { - case TOKimport: ds = ((ScopeExp *)e1)->sds; goto L1; - case TOKvar: ds = ((VarExp *)e1)->var; goto L1; - case TOKdotvar: ds = ((DotVarExp *)e1)->var; goto L1; - default: break; - L1: + case TOKimport: + ds = ((ScopeExp *)e1)->sds; + goto L1; + case TOKvar: + ds = ((VarExp *)e1)->var; + goto L1; + case TOKdotvar: + ds = ((DotVarExp *)e1)->var; + goto L1; + case TOKoverloadset: + ds = ((OverExp *)e1)->vars; + L1: + { const char* s = ds->mangle(); e = new StringExp(loc, (void*)s, strlen(s), 'c'); e = e->semantic(sc); return e; + } + default: + break; } } @@ -7208,26 +7611,15 @@ Expression *DotIdExp::semanticY(Scope *sc, int flag) { if (AggregateDeclaration *ad = sc->getStructClassScope()) { - if (ClassDeclaration *cd = ad->isClassDeclaration()) + if (e1->op == TOKthis) { - if (e1->op == TOKthis) - { - DotIdExp *die = typeDotIdExp(loc, cd->type, ident); - return die->semanticY(sc, flag); - } - else if (cd->baseClass && e1->op == TOKsuper) - { - DotIdExp *die = typeDotIdExp(loc, cd->baseClass->type, ident); - return die->semanticY(sc, flag); - } + e1 = new TypeExp(e1->loc, ad->type); } - else if (StructDeclaration *sd = ad->isStructDeclaration()) + else { - if (e1->op == TOKthis) - { - DotIdExp *die = typeDotIdExp(loc, sd->type, ident); - return die->semanticY(sc, flag); - } + ClassDeclaration *cd = ad->isClassDeclaration(); + if (cd && cd->baseClass) + e1 = new TypeExp(e1->loc, cd->baseClass->type); } } } @@ -7360,7 +7752,7 @@ Expression *DotIdExp::semanticY(Scope *sc, int flag) ScopeDsymbol *sds = s->isScopeDsymbol(); if (sds) { - //printf("it's a ScopeDsymbol\n"); + //printf("it's a ScopeDsymbol %s\n", ident->toChars()); e = new ScopeExp(loc, sds); e = e->semantic(sc); if (eleft) @@ -7422,7 +7814,7 @@ Expression *DotIdExp::semanticY(Scope *sc, int flag) } else { - if (e1->op == TOKtemplate) + if (e1->op == TOKtype || e1->op == TOKtemplate) flag = 0; e = e1->type->dotExp(sc, e1, ident, flag); if (!flag || e) @@ -7460,7 +7852,7 @@ void DotTemplateExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) /************************************************************/ -DotVarExp::DotVarExp(Loc loc, Expression *e, Declaration *v, int hasOverloads) +DotVarExp::DotVarExp(Loc loc, Expression *e, Declaration *v, bool hasOverloads) : UnaExp(loc, TOKdotvar, sizeof(DotVarExp), e) { //printf("DotVarExp()\n"); @@ -7502,7 +7894,7 @@ Expression *DotVarExp::semantic(Scope *sc) exps->reserve(tup->objects->dim); for (size_t i = 0; i < tup->objects->dim; i++) - { Object *o = (*tup->objects)[i]; + { RootObject *o = (*tup->objects)[i]; Expression *e; if (o->dyncast() == DYNCAST_EXPRESSION) { @@ -7564,13 +7956,10 @@ Expression *DotVarExp::semantic(Scope *sc) Dsymbol *vparent = var->toParent(); AggregateDeclaration *ad = vparent ? vparent->isAggregateDeclaration() : NULL; e1 = getRightThis(loc, sc, ad, e1, var); - if (!sc->noaccesscheck) - accessCheck(loc, sc, e1, var); + accessCheck(loc, sc, e1, var); VarDeclaration *v = var->isVarDeclaration(); -#if PULL93 - if (v && (v->isDataseg() || (v->storage_class & STCmanifest))) -#endif + if (!PULL93 || v && (v->isDataseg() || (v->storage_class & STCmanifest))) { Expression *e = expandVar(WANTvalue, v); if (e) @@ -7642,7 +8031,41 @@ int modifyFieldVar(Loc loc, Scope *sc, VarDeclaration *var, Expression *e1) { var->ctorinit = 1; //printf("setting ctorinit\n"); - return TRUE; + int result = TRUE; + if (var->isField() && sc->fieldinit && !sc->intypeof) + { + assert(e1); + bool mustInit = (var->storage_class & STCnodefaultctor || + var->type->needsNested()); + + size_t dim = sc->fieldinit_dim; + AggregateDeclaration *ad = fd->isAggregateMember2(); + assert(ad); + size_t i; + for (i = 0; i < dim; i++) // same as findFieldIndexByName in ctfeexp.c ? + { + if (ad->fields[i] == var) + break; + } + assert(i < dim); + unsigned fi = sc->fieldinit[i]; + if (fi & CSXthis_ctor) + { + if (var->type->isMutable() && e1->type->isMutable()) + result = FALSE; + else + ::error(loc, "multiple field %s initialization", var->toChars()); + } + else if (sc->noctor || fi & CSXlabel) + { + if (!mustInit && var->type->isMutable() && e1->type->isMutable()) + result = FALSE; + else + ::error(loc, "field %s initializing not allowed in loops or after labels", var->toChars()); + } + sc->fieldinit[i] |= CSXthis_ctor; + } + return result; } else { @@ -7707,26 +8130,30 @@ Expression *DotTemplateInstanceExp::syntaxCopy() return de; } -TemplateDeclaration *DotTemplateInstanceExp::getTempdecl(Scope *sc) +bool DotTemplateInstanceExp::findTempDecl(Scope *sc) { #if LOGSEMANTIC - printf("DotTemplateInstanceExp::getTempdecl('%s')\n", toChars()); + printf("DotTemplateInstanceExp::findTempDecl('%s')\n", toChars()); #endif - if (!ti->tempdecl) + if (ti->tempdecl) + return true; + + Expression *e = new DotIdExp(loc, e1, ti->name); + e = e->semantic(sc); + if (e->op == TOKdotexp) + e = ((DotExp *)e)->e2; + + Dsymbol *s = NULL; + switch (e->op) { - Expression *e = new DotIdExp(loc, e1, ti->name); - e = e->semantic(sc); - if (e->op == TOKdottd) - { - DotTemplateExp *dte = (DotTemplateExp *)e; - ti->tempdecl = dte->td; - } - else if (e->op == TOKimport) - { ScopeExp *se = (ScopeExp *)e; - ti->tempdecl = se->sds->isTemplateDeclaration(); - } + case TOKoverloadset: s = ((OverExp *)e)->vars; break; + case TOKdottd: s = ((DotTemplateExp *)e)->td; break; + case TOKimport: s = ((ScopeExp *)e)->sds; break; + case TOKdotvar: s = ((DotVarExp *)e)->var; break; + case TOKvar: s = ((VarExp *)e)->var; break; + default: return false; } - return ti->tempdecl; + return ti->updateTemplateDeclaration(sc, s); } Expression *DotTemplateInstanceExp::semantic(Scope *sc) @@ -7768,6 +8195,13 @@ Expression *DotTemplateInstanceExp::semanticY(Scope *sc, int flag) return NULL; } e = die->semanticY(sc, flag); + if (flag && e && isDotOpDispatch(e)) + { + /* opDispatch!tiargs would be a function template that needs IFTI, + * so it's not a template + */ + e = NULL; /* fall down to UFCS */ + } if (flag && !e) return NULL; } @@ -7776,14 +8210,47 @@ Expression *DotTemplateInstanceExp::semanticY(Scope *sc, int flag) L1: if (e->op == TOKerror) return e; + if (e->op == TOKdotvar) + { + DotVarExp *dve = (DotVarExp *)e; + FuncDeclaration *f = dve->var->isFuncDeclaration(); + if (f) + { + TemplateDeclaration *td = f->findTemplateDeclRoot(); + if (td) + { + e = new DotTemplateExp(dve->loc, dve->e1, td); + e = e->semantic(sc); + } + } + } + else if (e->op == TOKvar) + { + VarExp *ve = (VarExp *)e; + FuncDeclaration *f = ve->var->isFuncDeclaration(); + if (f) + { + TemplateDeclaration *td = f->findTemplateDeclRoot(); + if (td) + { + e = new ScopeExp(ve->loc, td); + e = e->semantic(sc); + } + } + } if (e->op == TOKdottd) { if (ti->errors) return new ErrorExp(); DotTemplateExp *dte = (DotTemplateExp *)e; - TemplateDeclaration *td = dte->td; Expression *eleft = dte->e1; - ti->tempdecl = td; + ti->tempdecl = dte->td; + if (!ti->semanticTiargs(sc)) + { + ti->inst = ti; + ti->inst->errors = true; + return new ErrorExp(); + } if (ti->needsTypeInference(sc)) { e1 = eleft; // save result of semantic() @@ -7845,9 +8312,39 @@ L1: } else if (e->op == TOKdotexp) { DotExp *de = (DotExp *)e; + Expression *eleft = de->e1; if (de->e2->op == TOKoverloadset) { + if (!findTempDecl(sc) || + !ti->semanticTiargs(sc)) + { + ti->inst = ti; + ti->inst->errors = true; + return new ErrorExp(); + } + if (ti->needsTypeInference(sc)) + { + e1 = eleft; + return this; + } + else + ti->semantic(sc); + if (!ti->inst) // if template failed to expand + return new ErrorExp(); + Dsymbol *s = ti->inst->toAlias(); + Declaration *v = s->isDeclaration(); + if (v) + { + if (v->type && !v->type->deco) + v->type = v->type->semantic(v->loc, sc); + e = new DotVarExp(loc, eleft, v); + e = e->semantic(sc); + return e; + } + e = new ScopeExp(loc, ti); + e = new DotExp(loc, eleft, e); + e = e->semantic(sc); return e; } @@ -7870,6 +8367,14 @@ L1: goto Lerr; goto L1; } + else if (e->op == TOKoverloadset) + { + OverExp *oe = (OverExp *)e; + ti->tempdecl = oe->vars; + e = new ScopeExp(loc, ti); + e = e->semantic(sc); + return e; + } Lerr: error("%s isn't a template", e->toChars()); return new ErrorExp(); @@ -7884,7 +8389,7 @@ void DotTemplateInstanceExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) /************************************************************/ -DelegateExp::DelegateExp(Loc loc, Expression *e, FuncDeclaration *f, int hasOverloads) +DelegateExp::DelegateExp(Loc loc, Expression *e, FuncDeclaration *f, bool hasOverloads) : UnaExp(loc, TOKdelegate, sizeof(DelegateExp), e) { this->func = f; @@ -8004,7 +8509,6 @@ Expression *CallExp::semantic(Scope *sc) Type *t1; int istemp; Objects *tiargs = NULL; // initial list of template arguments - TemplateInstance *tierror = NULL; Expression *ethis = NULL; Type *tthis = NULL; @@ -8023,10 +8527,10 @@ Expression *CallExp::semantic(Scope *sc) #endif if (e1->op == TOKcomma) - { /* Rewrite (a,b)(args) as (a,(b(args))) + { + /* Rewrite (a,b)(args) as (a,(b(args))) */ CommaExp *ce = (CommaExp *)e1; - e1 = ce->e2; e1->type = ce->type; ce->e2 = this; @@ -8035,15 +8539,15 @@ Expression *CallExp::semantic(Scope *sc) } if (e1->op == TOKdelegate) - { DelegateExp *de = (DelegateExp *)e1; - + { + DelegateExp *de = (DelegateExp *)e1; e1 = new DotVarExp(de->loc, de->e1, de->func); return semantic(sc); } if (e1->op == TOKfunction) - { FuncExp *fe = (FuncExp *)e1; - + { + FuncExp *fe = (FuncExp *)e1; arguments = arrayExpressionSemantic(arguments, sc); preFunctionParameters(loc, sc, arguments); e1 = fe->semantic(sc, arguments); @@ -8066,22 +8570,29 @@ Expression *CallExp::semantic(Scope *sc) /* Attempt to instantiate ti. If that works, go with it. * If not, go with partial explicit specialization. */ - unsigned olderrors = global.errors; - ti->semanticTiargs(sc); - if (olderrors != global.errors) + if (!ti->findTemplateDeclaration(sc) || + !ti->semanticTiargs(sc)) + { + ti->inst = ti; + ti->inst->errors = true; return new ErrorExp(); - if (ti->needsTypeInference(sc)) + } + if (ti->needsTypeInference(sc, 1)) { /* Go with partial explicit specialization */ tiargs = ti->tiargs; - tierror = ti; // for error reporting assert(ti->tempdecl); - e1 = new TemplateExp(loc, ti->tempdecl); + if (TemplateDeclaration *td = ti->tempdecl->isTemplateDeclaration()) + e1 = new TemplateExp(loc, td); + else + e1 = new OverExp(loc, ti->tempdecl->isOverloadSet()); } else { ti->semantic(sc); + if (ti->errors) + e1 = new ErrorExp(); } } } @@ -8098,18 +8609,23 @@ Ldotti: /* Attempt to instantiate ti. If that works, go with it. * If not, go with partial explicit specialization. */ - ti->semanticTiargs(sc); - if (!ti->tempdecl) + if (!se->findTempDecl(sc) || + !ti->semanticTiargs(sc)) { - se->getTempdecl(sc); + ti->inst = ti; + ti->inst->errors = true; + return new ErrorExp(); } - if (ti->tempdecl && ti->needsTypeInference(sc)) + if (ti->needsTypeInference(sc, 1)) { /* Go with partial explicit specialization */ tiargs = ti->tiargs; - tierror = ti; // for error reporting - e1 = new DotIdExp(loc, se->e1, ti->name); + assert(ti->tempdecl); + if (TemplateDeclaration *td = ti->tempdecl->isTemplateDeclaration()) + e1 = new DotTemplateExp(loc, se->e1, td); + else + e1 = new DotExp(loc, se->e1, new OverExp(loc, ti->tempdecl->isOverloadSet())); } else { @@ -8258,14 +8774,20 @@ Lagain: av = new CommaExp(loc, av, new VarExp(loc, tmp)); Expression *e; - CtorDeclaration *cf = ad->ctor->isCtorDeclaration(); - if (cf) + if (CtorDeclaration *cf = ad->ctor->isCtorDeclaration()) + { e = new DotVarExp(loc, av, cf, 1); - else - { TemplateDeclaration *td = ad->ctor->isTemplateDeclaration(); - assert(td); + } + else if (TemplateDeclaration *td = ad->ctor->isTemplateDeclaration()) + { e = new DotTemplateExp(loc, av, td); } + else if (OverloadSet *os = ad->ctor->isOverloadSet()) + { + e = new DotExp(loc, av, new OverExp(loc, os)); + } + else + assert(0); e = new CallExp(loc, e, arguments); e = e->semantic(sc); return e; @@ -8325,7 +8847,7 @@ Lagain: if (tiargs && tiargs->dim) { for (size_t k = 0; k < tiargs->dim; k++) - { Object *o = (*tiargs)[k]; + { RootObject *o = (*tiargs)[k]; if (isError(o)) return new ErrorExp(); } @@ -8355,6 +8877,7 @@ Lagain: { dve = (DotVarExp *)(e1); s = dve->var; + tiargs = NULL; } else { dte = (DotTemplateExp *)(e1); @@ -8539,6 +9062,8 @@ Lagain: Dsymbol *s = NULL; for (size_t i = 0; i < eo->vars->a.dim; i++) { s = eo->vars->a[i]; + if (tiargs && s->isFuncDeclaration()) + continue; FuncDeclaration *f2 = resolveFuncCall(loc, sc, s, tiargs, tthis, arguments, 1); if (f2) { if (f) @@ -8571,6 +9096,7 @@ Lagain: { TypeFunction *tf; const char *p; + f = NULL; if (e1->op == TOKfunction) { // function literal that direct called is always inferred. @@ -8578,11 +9104,10 @@ Lagain: f = ((FuncExp *)e1)->fd; tf = (TypeFunction *)f->type; p = "function literal"; - - f->checkNestedReference(sc, loc); } else if (t1->ty == Tdelegate) - { TypeDelegate *td = (TypeDelegate *)t1; + { + TypeDelegate *td = (TypeDelegate *)t1; assert(td->next->ty == Tfunction); tf = (TypeFunction *)(td->next); p = "delegate"; @@ -8597,10 +9122,7 @@ Lagain: TemplateExp *te = (TemplateExp *)e1; f = resolveFuncCall(loc, sc, te->td, tiargs, NULL, arguments); if (!f) - { if (tierror) - tierror->error("errors instantiating template"); // give better error message return new ErrorExp(); - } if (f->needThis()) { if (hasThis(sc)) @@ -8622,21 +9144,11 @@ Lagain: goto Lagain; } else - { error("function expected before (), not %s of type %s", e1->toChars(), e1->type->toChars()); + { + error("function expected before (), not %s of type %s", e1->toChars(), e1->type->toChars()); return new ErrorExp(); } - if (sc->func && !tf->purity && !(sc->flags & SCOPEdebug) && !sc->needctfe) - { - if (sc->func->setImpure()) - error("pure function '%s' cannot call impure %s '%s'", sc->func->toPrettyChars(), p, e1->toChars()); - } - if (sc->func && tf->trust <= TRUSTsystem && !sc->needctfe) - { - if (sc->func->setUnsafe()) - error("safe function '%s' cannot call system %s '%s'", sc->func->toPrettyChars(), p, e1->toChars()); - } - if (!tf->callMatch(NULL, arguments)) { OutBuffer buf; @@ -8662,6 +9174,29 @@ Lagain: return new ErrorExp(); } + // Purity and safety check should run after testing arguments matching + if (f) + { +#if DMDV2 + checkPurity(sc, f); + checkSafety(sc, f); +#endif + f->checkNestedReference(sc, loc); + } + else if (sc->func && !(sc->flags & SCOPEctfe)) + { + if (!tf->purity && !(sc->flags & SCOPEdebug) && sc->func->setImpure()) + { + error("pure function '%s' cannot call impure %s '%s'", sc->func->toPrettyChars(), p, e1->toChars()); + return new ErrorExp(); + } + if (tf->trust <= TRUSTsystem && sc->func->setUnsafe()) + { + error("safe function '%s' cannot call system %s '%s'", sc->func->toPrettyChars(), p, e1->toChars()); + return new ErrorExp(); + } + } + if (t1->ty == Tpointer) { Expression *e = new PtrExp(loc, e1); @@ -8677,6 +9212,7 @@ Lagain: f = ve->var->isFuncDeclaration(); assert(f); + tiargs = NULL; if (ve->hasOverloads) f = resolveFuncCall(loc, sc, f, tiargs, NULL, arguments, 2); @@ -8772,6 +9308,13 @@ Lagain: } } + // Handle the case of a direct lambda call + if (f && f->isFuncLiteralDeclaration() && + sc->func && !sc->intypeof) + { + f->tookAddressOf = 0; + } + return this; } @@ -8812,16 +9355,14 @@ Expression *CallExp::addDtorHook(Scope *sc) return this; } - Type *tv = type->toBasetype(); - while (tv->ty == Tsarray) - { TypeSArray *ta = (TypeSArray *)tv; - tv = tv->nextOf()->toBasetype(); - } + Type *tv = type->baseElemOf(); if (tv->ty == Tstruct) - { TypeStruct *ts = (TypeStruct *)tv; + { + TypeStruct *ts = (TypeStruct *)tv; StructDeclaration *sd = ts->sym; if (sd->dtor) - { /* Type needs destruction, so declare a tmp + { + /* Type needs destruction, so declare a tmp * which the back end will recognize and call dtor on */ Identifier *idtmp = Lexer::uniqueId("__tmpfordtor"); @@ -8833,7 +9374,6 @@ Expression *CallExp::addDtorHook(Scope *sc) return e; } } -Lnone: return this; } @@ -8869,7 +9409,6 @@ Expression *AddrExp::semantic(Scope *sc) if (!type) { UnaExp::semantic(sc); - Expression *olde1 = e1; if (e1->type == Type::terror) return new ErrorExp(); int wasCond = e1->op == TOKquestion; @@ -9460,6 +9999,10 @@ Expression *CastExp::semantic(Scope *sc) if (e1->type->ty == Terror) return new ErrorExp(); + // cast(void) is used to mark e1 as unused, so it is safe + if (to->ty == Tvoid) + goto Lsafe; + if (!to->equals(e1->type)) { Expression *e = op_overload(sc); @@ -9501,15 +10044,19 @@ Expression *CastExp::semantic(Scope *sc) if (tob->ty == Tstruct || t1b->ty == Tstruct || (tob->ty == Tsarray && t1b->ty == Tsarray)) { - size_t fromsize = t1b->size(loc); - size_t tosize = tob->size(loc); - if (fromsize != tosize) + if (t1b->ty == Tnull || tob->ty == Tnull || t1b->size(loc) != tob->size(loc)) { error("cannot cast from %s to %s", e1->type->toChars(), to->toChars()); return new ErrorExp(); } } + if ((t1b->ty == Tarray || t1b->ty == Tsarray) && tob->ty == Tclass) + { + error("cannot cast from %s to %s", e1->type->toChars(), to->toChars()); + return new ErrorExp(); + } + // Look for casting to a vector type if (tob->ty == Tvector && t1b->ty != Tvector) { @@ -9524,6 +10071,12 @@ Expression *CastExp::semantic(Scope *sc) if (tob->ty == Tpointer && t1b->ty == Tdelegate) deprecation("casting from %s to %s is deprecated", e1->type->toChars(), to->toChars()); + + if (t1b->ty == Tvoid && tob->ty != Tvoid && e1->op != TOKfunction) + { + error("cannot cast %s of type %s to %s", e1->toChars(), e1->type->toChars(), to->toChars()); + return new ErrorExp(); + } } else if (!to) { error("cannot cast tuple"); @@ -9582,7 +10135,10 @@ Expression *CastExp::semantic(Scope *sc) { Type* tobn = tob->nextOf()->toBasetype(); Type* t1bn = t1b->nextOf()->toBasetype(); - if (!tobn->hasPointers() && + // If the struct is opaque we don't know about the struct members and the cast becomes unsafe + bool sfwrd = tobn->ty == Tstruct && !((StructDeclaration *)((TypeStruct *)tobn)->sym)->members || + t1bn->ty == Tstruct && !((StructDeclaration *)((TypeStruct *)t1bn)->sym)->members; + if (!sfwrd && !tobn->hasPointers() && tobn->ty != Tfunction && t1bn->ty != Tfunction && tobn->size() <= t1bn->size() && MODimplicitConv(t1bn->mod, tobn->mod)) @@ -9597,6 +10153,16 @@ Expression *CastExp::semantic(Scope *sc) } Lsafe: +#if DMDV2 + /* Instantiate AA implementations during semantic analysis. + */ + Type *tfrom = e1->type->toBasetype(); + Type *t = to->toBasetype(); + if (tfrom->ty == Taarray) + ((TypeAArray *)tfrom)->getImpl(); + if (t->ty == Taarray) + ((TypeAArray *)t)->getImpl(); +#endif Expression *e = e1->castTo(sc, to); return e; } @@ -9756,6 +10322,8 @@ Lagain: { error("need upper and lower bound to slice pointer"); return new ErrorExp(); } + if (sc->func && !sc->intypeof && sc->func->setUnsafe()) + error("pointer slicing not allowed in safe functions"); } else if (t->ty == Tarray) { @@ -9776,15 +10344,17 @@ Lagain: if (search_function(ad, Id::slice)) { // Rewrite as e1.slice(lwr, upr) - SliceExp *se = resolveOpDollar(sc, this); + Expression *e0 = resolveOpDollar(sc, this); Expressions *a = new Expressions(); - assert(!se->lwr || se->upr); - if (se->lwr) - { a->push(se->lwr); - a->push(se->upr); + assert(!lwr || upr); + if (lwr) + { + a->push(lwr); + a->push(upr); } - e = new DotIdExp(loc, se->e1, Id::slice); + e = new DotIdExp(loc, e1, Id::slice); e = new CallExp(loc, e, a); + e = combine(e0, e); e = e->semantic(sc); return e; } @@ -9823,22 +10393,20 @@ Lagain: if (lwr) { - if (t->ty == Ttuple) - lwr = lwr->ctfeSemantic(sc2); - else - lwr = lwr->semantic(sc2); + if (t->ty == Ttuple) sc2 = sc2->startCTFE(); + lwr = lwr->semantic(sc2); lwr = resolveProperties(sc2, lwr); + if (t->ty == Ttuple) sc2 = sc2->endCTFE(); lwr = lwr->implicitCastTo(sc2, Type::tsize_t); if (lwr->type == Type::terror) goto Lerr; } if (upr) { - if (t->ty == Ttuple) - upr = upr->ctfeSemantic(sc2); - else - upr = upr->semantic(sc2); + if (t->ty == Ttuple) sc2 = sc2->startCTFE(); + upr = upr->semantic(sc2); upr = resolveProperties(sc2, upr); + if (t->ty == Ttuple) sc2 = sc2->endCTFE(); upr = upr->implicitCastTo(sc2, Type::tsize_t); if (upr->type == Type::terror) goto Lerr; @@ -9978,14 +10546,14 @@ void SliceExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) if (upr || lwr) { if (lwr) - expToCBuffer(buf, hgs, lwr, PREC_assign); + sizeToCBuffer(buf, hgs, lwr); else buf->writeByte('0'); buf->writestring(".."); if (upr) - expToCBuffer(buf, hgs, upr, PREC_assign); + sizeToCBuffer(buf, hgs, upr); else - buf->writestring("length"); // BUG: should be array.length + buf->writestring("$"); } buf->writeByte(']'); } @@ -10012,7 +10580,7 @@ Expression *ArrayLengthExp::semantic(Scope *sc) return this; } -Expression *opAssignToOp(Loc loc, enum TOK op, Expression *e1, Expression *e2) +Expression *opAssignToOp(Loc loc, TOK op, Expression *e1, Expression *e2) { Expression *e; switch (op) @@ -10261,6 +10829,7 @@ IndexExp::IndexExp(Loc loc, Expression *e1, Expression *e2) //printf("IndexExp::IndexExp('%s')\n", toChars()); lengthVar = NULL; modifiable = 0; // assume it is an rvalue + skipboundscheck = 0; } Expression *IndexExp::syntaxCopy() @@ -10311,11 +10880,10 @@ Expression *IndexExp::semantic(Scope *sc) sc = sc->push(sym); } - if (t1->ty == Ttuple) - e2 = e2->ctfeSemantic(sc); - else - e2 = e2->semantic(sc); + if (t1->ty == Ttuple) sc = sc->startCTFE(); + e2 = e2->semantic(sc); e2 = resolveProperties(sc, e2); + if (t1->ty == Ttuple) sc = sc->endCTFE(); if (e2->type == Type::terror) goto Lerr; if (e2->type->ty == Ttuple && ((TupleExp *)e2)->exps->dim == 1) // bug 4444 fix @@ -10328,10 +10896,12 @@ Expression *IndexExp::semantic(Scope *sc) { case Tpointer: e2 = e2->implicitCastTo(sc, Type::tsize_t); + if (e2->type == Type::terror) + goto Lerr; e2 = e2->optimize(WANTvalue); if (e2->op == TOKint64 && e2->toInteger() == 0) ; - else if (sc->func->setUnsafe()) + else if (sc->func && sc->func->setUnsafe()) { error("safe function '%s' cannot index pointer '%s'", sc->func->toPrettyChars(), e1->toChars()); @@ -10342,12 +10912,16 @@ Expression *IndexExp::semantic(Scope *sc) case Tarray: e2 = e2->implicitCastTo(sc, Type::tsize_t); + if (e2->type == Type::terror) + goto Lerr; e->type = ((TypeNext *)t1)->next; break; case Tsarray: { e2 = e2->implicitCastTo(sc, Type::tsize_t); + if (e2->type == Type::terror) + goto Lerr; TypeSArray *tsa = (TypeSArray *)t1; e->type = t1->nextOf(); break; @@ -10369,6 +10943,8 @@ Expression *IndexExp::semantic(Scope *sc) case Ttuple: { e2 = e2->implicitCastTo(sc, Type::tsize_t); + if (e2->type == Type::terror) + goto Lerr; e2 = e2->ctfeInterpret(); uinteger_t index = e2->toUInteger(); size_t length; @@ -10415,6 +10991,21 @@ Expression *IndexExp::semantic(Scope *sc) case Terror: goto Lerr; } + + if (t1->ty == Tsarray || t1->ty == Tarray) + { + Expression *el = new ArrayLengthExp(loc, e1); + el = el->semantic(sc); + el = el->optimize(WANTvalue); + if (el->op == TOKint64) + { + e2 = e2->optimize(WANTvalue); + dinteger_t length = el->toInteger(); + if (length) + skipboundscheck = IntRange(SignExtendedNumber(0), SignExtendedNumber(length)).contains(e2->getIntRange()); + } + } + return e; Lerr: @@ -10465,14 +11056,14 @@ void IndexExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { expToCBuffer(buf, hgs, e1, PREC_primary); buf->writeByte('['); - expToCBuffer(buf, hgs, e2, PREC_assign); + sizeToCBuffer(buf, hgs, e2); buf->writeByte(']'); } /************************* PostExp ***********************************/ -PostExp::PostExp(enum TOK op, Loc loc, Expression *e) +PostExp::PostExp(TOK op, Loc loc, Expression *e) : BinExp(loc, op, sizeof(PostExp), e, new IntegerExp(loc, 1, Type::tint32)) { @@ -10566,7 +11157,7 @@ void PostExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) /************************* PreExp ***********************************/ -PreExp::PreExp(enum TOK op, Loc loc, Expression *e) +PreExp::PreExp(TOK op, Loc loc, Expression *e) : UnaExp(loc, op, sizeof(PreExp), e) { } @@ -10633,11 +11224,11 @@ Expression *AssignExp::semantic(Scope *sc) { ArrayExp *ae = (ArrayExp *)e1; AggregateDeclaration *ad = NULL; - Identifier *id = Id::index; ae->e1 = ae->e1->semantic(sc); ae->e1 = resolveProperties(sc, ae->e1); - Expression *e1 = ae->e1; + Expression *ae1old = ae->e1; + Type *t1 = ae->e1->type->toBasetype(); if (t1->ty == Tstruct) { @@ -10652,12 +11243,13 @@ Expression *AssignExp::semantic(Scope *sc) if (search_function(ad, Id::indexass)) { // Deal with $ - ae = resolveOpDollar(sc, ae); + Expression *e0 = resolveOpDollar(sc, ae); Expressions *a = (Expressions *)ae->arguments->copy(); a->insert(0, e2); - Expression *e = new DotIdExp(loc, e1, Id::indexass); + Expression *e = new DotIdExp(loc, ae->e1, Id::indexass); e = new CallExp(loc, e, a); + e = combine(e0, e); e = e->semantic(sc); return e; } @@ -10668,8 +11260,8 @@ Expression *AssignExp::semantic(Scope *sc) { if (!att1 && t1->checkAliasThisRec()) att1 = t1; - e1 = resolveAliasThis(sc, e1); - t1 = e1->type->toBasetype(); + ae->e1 = resolveAliasThis(sc, ae->e1); + t1 = ae->e1->type->toBasetype(); if (t1->ty == Tstruct) { ad = ((TypeStruct *)t1)->sym; @@ -10681,6 +11273,8 @@ Expression *AssignExp::semantic(Scope *sc) goto L1; } } + + ae->e1 = ae1old; // restore } /* Look for operator overloading of a[i..j]=value. * Do it before semantic() otherwise the a[i..j] will have been @@ -10690,11 +11284,11 @@ Expression *AssignExp::semantic(Scope *sc) { SliceExp *ae = (SliceExp *)e1; AggregateDeclaration *ad = NULL; - Identifier *id = Id::index; ae->e1 = ae->e1->semantic(sc); ae->e1 = resolveProperties(sc, ae->e1); - Expression *e1 = ae->e1; + Expression *ae1old = ae->e1; + Type *t1 = ae->e1->type->toBasetype(); if (t1->ty == Tstruct) { @@ -10708,16 +11302,18 @@ Expression *AssignExp::semantic(Scope *sc) // Rewrite (a[i..j] = value) to (a.opSliceAssign(value, i, j)) if (search_function(ad, Id::sliceass)) { - ae = resolveOpDollar(sc, ae); + Expression *e0 = resolveOpDollar(sc, ae); Expressions *a = new Expressions(); a->push(e2); assert(!ae->lwr || ae->upr); if (ae->lwr) - { a->push(ae->lwr); + { + a->push(ae->lwr); a->push(ae->upr); } - Expression *e = new DotIdExp(loc, e1, Id::sliceass); + Expression *e = new DotIdExp(loc, ae->e1, Id::sliceass); e = new CallExp(loc, e, a); + e = combine(e0, e); e = e->semantic(sc); return e; } @@ -10728,8 +11324,8 @@ Expression *AssignExp::semantic(Scope *sc) { if (!att1 && t1->checkAliasThisRec()) att1 = t1; - e1 = resolveAliasThis(sc, e1); - t1 = e1->type->toBasetype(); + ae->e1 = resolveAliasThis(sc, ae->e1); + t1 = ae->e1->type->toBasetype(); if (t1->ty == Tstruct) { ad = ((TypeStruct *)t1)->sym; @@ -10741,6 +11337,8 @@ Expression *AssignExp::semantic(Scope *sc) goto L2; } } + + ae->e1 = ae1old; // restore } /* With UFCS, e.f = value @@ -10761,11 +11359,21 @@ Expression *AssignExp::semantic(Scope *sc) { DotIdExp *die = (DotIdExp *)e1; Expression *e = die->semanticY(sc, 1); + if (e && isDotOpDispatch(e)) + { + unsigned errors = global.startGagging(); + e = resolvePropertiesX(sc, e, e2); + if (global.endGagging(errors)) + e = NULL; /* fall down to UFCS */ + else + return e; + } if (!e) return resolveUFCSProperties(sc, e1, e2); e1 = e; } - e1 = e1->semantic(sc); + else + e1 = e1->semantic(sc); if (e1->op == TOKerror) return new ErrorExp(); @@ -10775,113 +11383,8 @@ Expression *AssignExp::semantic(Scope *sc) * or: * f() = value */ - TemplateDeclaration *td; - Objects *tiargs; - FuncDeclaration *fd; - Type *tthis; - if (e1->op == TOKdotti) - { - DotTemplateInstanceExp* dti = (DotTemplateInstanceExp *)e1; - td = dti->getTempdecl(sc); - dti->ti->semanticTiargs(sc); - tiargs = dti->ti->tiargs; - tthis = dti->e1->type; - goto L3; - } - else if (e1->op == TOKdottd) - { - DotTemplateExp *dte = (DotTemplateExp *)e1; - td = dte->td; - tiargs = NULL; - tthis = dte->e1->type; - goto L3; - } - else if (e1->op == TOKtemplate) - { - td = ((TemplateExp *)e1)->td; - tiargs = NULL; - tthis = NULL; - L3: - { - e2 = e2->semantic(sc); - if (e2->op == TOKerror) - return new ErrorExp(); - e2 = resolveProperties(sc, e2); - - assert(td); - Expressions a; - a.push(e2); - - fd = resolveFuncCall(loc, sc, td, tiargs, tthis, &a, 1); - if (fd && fd->type) - goto Lsetter; - - fd = resolveFuncCall(loc, sc, td, tiargs, tthis, NULL, 1); - if (fd && fd->type) - goto Lgetter; - } - goto Leprop; - } - else if (e1->op == TOKdotvar && e1->type->toBasetype()->ty == Tfunction) - { - DotVarExp *dve = (DotVarExp *)e1; - fd = dve->var->isFuncDeclaration(); - tthis = dve->e1->type; - goto L4; - } - else if (e1->op == TOKvar && e1->type->toBasetype()->ty == Tfunction) - { - fd = ((VarExp *)e1)->var->isFuncDeclaration(); - tthis = NULL; - L4: - { - e2 = e2->semantic(sc); - if (e2->op == TOKerror) - return new ErrorExp(); - e2 = resolveProperties(sc, e2); - - assert(fd); - FuncDeclaration *f = fd; - Expressions a; - a.push(e2); - - fd = resolveFuncCall(loc, sc, f, NULL, tthis, &a, 1); - if (fd && fd->type) - goto Lsetter; - - fd = resolveFuncCall(loc, sc, f, NULL, tthis, NULL, 1); - if (fd && fd->type) - goto Lgetter; - - goto Leprop; - } - - Expression *e; - TypeFunction *tf; - - Lsetter: - assert(fd->type->ty == Tfunction); - tf = (TypeFunction *)fd->type; - if (!tf->isproperty && global.params.enforcePropertySyntax) - goto Leprop; - e = new CallExp(loc, e1, e2); - return e->semantic(sc); - - Lgetter: - assert(fd->type->ty == Tfunction); - tf = (TypeFunction *)fd->type; - if (!tf->isref) - goto Leprop; - if (!tf->isproperty && global.params.enforcePropertySyntax) - goto Leprop; - e = new CallExp(loc, e1); - e = new AssignExp(loc, e, e2); - return e->semantic(sc); - - Leprop: - ::error(e1->loc, "not a property %s", e1->toChars()); - return new ErrorExp(); - } + if (Expression *e = resolvePropertiesX(sc, e1, e2)) + return e; e1 = checkRightThis(sc, e1); @@ -10901,29 +11404,36 @@ Expression *AssignExp::semantic(Scope *sc) */ Ltupleassign: if (e1->op == TOKtuple && e2->op == TOKtuple) - { TupleExp *tup1 = (TupleExp *)e1; + { + TupleExp *tup1 = (TupleExp *)e1; TupleExp *tup2 = (TupleExp *)e2; size_t dim = tup1->exps->dim; + Expression *e = NULL; if (dim != tup2->exps->dim) { error("mismatched tuple lengths, %d and %d", (int)dim, (int)tup2->exps->dim); return new ErrorExp(); } + if (dim == 0) + { + e = new IntegerExp(loc, 0, Type::tint32); + e = new CastExp(loc, e, Type::tvoid); // avoid "has no effect" error + e = combine(combine(tup1->e0, tup2->e0), e); + } else { Expressions *exps = new Expressions; exps->setDim(dim); - - Expression *e0 = combine(tup1->e0, tup2->e0); for (size_t i = 0; i < dim; i++) - { Expression *ex1 = (*tup1->exps)[i]; + { + Expression *ex1 = (*tup1->exps)[i]; Expression *ex2 = (*tup2->exps)[i]; - (*exps)[i] = new AssignExp(loc, ex1, ex2); + (*exps)[i] = new AssignExp(loc, ex1, ex2); } - Expression *e = new TupleExp(loc, e0, exps); - e = e->semantic(sc); - return e; + e = new TupleExp(loc, combine(tup1->e0, tup2->e0), exps); } + assert(e); + return e->semantic(sc); } if (e1->op == TOKtuple) @@ -10972,10 +11482,17 @@ Ltupleassign: } } + if (op == TOKassign && e1->checkModifiable(sc) == 2) + { + //printf("[%s] change to init - %s\n", loc.toChars(), toChars()); + op = TOKconstruct; + } + // Determine if this is an initialization of a reference int refinit = 0; if (op == TOKconstruct && e1->op == TOKvar) - { VarExp *ve = (VarExp *)e1; + { + VarExp *ve = (VarExp *)e1; VarDeclaration *v = ve->var->isVarDeclaration(); if (v->storage_class & (STCout | STCref)) refinit = 1; @@ -10989,88 +11506,232 @@ Ltupleassign: StructDeclaration *sd = ((TypeStruct *)t1)->sym; if (op == TOKassign) { - Expression *e = op_overload(sc); - if (e && e1->op == TOKindex && + if (e1->op == TOKindex && ((IndexExp *)e1)->e1->type->toBasetype()->ty == Taarray) { - // Deal with AAs (Bugzilla 2451) - // Rewrite as: - // e1 = (typeof(aa.value) tmp = void, tmp = e2, tmp); - Type * aaValueType = ((TypeAArray *)((IndexExp*)e1)->e1->type->toBasetype())->next; - Identifier *id = Lexer::uniqueId("__aatmp"); - VarDeclaration *v = new VarDeclaration(loc, aaValueType, - id, new VoidInitializer(Loc())); - v->storage_class |= STCctfe; - v->semantic(sc); - v->parent = sc->parent; + /* + * Rewrite: + * aa[key] = e2; + * as: + * ref __aatmp = aa; + * ref __aakey = key; + * ref __aaval = e2; + * (__aakey in __aatmp + * ? __aatmp[__aakey].opAssign(__aaval) + * : ConstructExp(__aatmp[__aakey], __aaval)); + */ + IndexExp *ie = (IndexExp *)e1; + Type *t2 = e2->type->toBasetype(); + Expression *e0 = NULL; - Expression *de = new DeclarationExp(loc, v); - VarExp *ve = new VarExp(loc, v); + Expression *ea = ie->e1; + Expression *ek = ie->e2; + Expression *ev = e2; + if (ea->hasSideEffect()) + { + VarDeclaration *v = new VarDeclaration(loc, ie->e1->type, + Lexer::uniqueId("__aatmp"), new ExpInitializer(loc, ie->e1)); + v->storage_class |= STCctfe; + v->semantic(sc); + e0 = combine(e0, new DeclarationExp(loc, v)); + ea = new VarExp(loc, v); + } + if (ek->hasSideEffect()) + { + VarDeclaration *v = new VarDeclaration(loc, ie->e2->type, + Lexer::uniqueId("__aakey"), new ExpInitializer(loc, ie->e2)); + v->storage_class |= STCctfe; + v->semantic(sc); + e0 = combine(e0, new DeclarationExp(loc, v)); + ek = new VarExp(loc, v); + } + if (ev->hasSideEffect()) + { + VarDeclaration *v = new VarDeclaration(loc, e2->type, + Lexer::uniqueId("__aaval"), new ExpInitializer(loc, e2)); + v->storage_class |= STCctfe; + v->semantic(sc); + e0 = combine(e0, new DeclarationExp(loc, v)); + ev = new VarExp(loc, v); + } + if (e0) + e0 = e0->semantic(sc); - AssignExp *ae = new AssignExp(loc, ve, e2); - e = ae->op_overload(sc); - e2 = new CommaExp(loc, new CommaExp(loc, de, e), ve); - e2 = e2->semantic(sc); + AssignExp *ae = (AssignExp *)copy(); + ae->e1 = new IndexExp(loc, ea, ek); + ae->e1 = ae->e1->semantic(sc); + ae->e1 = ae->e1->optimize(WANTvalue); + ae->e2 = ev; + //Expression *e = new CallExp(loc, new DotIdExp(loc, ex, Id::assign), ev); + Expression *e = ae->op_overload(sc); + if (!e) + goto Lx; - e1 = e1->optimize(WANTvalue); - e1 = e1->modifiableLvalue(sc, e1); - e2 = e2->implicitCastTo(sc, e1->type); - type = e1->type; - assert(type); - e = this; + Expression *ey = NULL; + if (t2->ty == Tstruct && sd == t2->toDsymbol(sc)) + { + ey = ev; + goto Lctor; + } + else if (!ev->implicitConvTo(ie->type) && sd->ctor) + { + // Look for implicit constructor call + // Rewrite as S().ctor(e2) + ey = new StructLiteralExp(loc, sd, NULL); + ey = new DotIdExp(loc, ey, Id::ctor); + ey = new CallExp(loc, ey, ev); + ey = ey->trySemantic(sc); + if (ey) + { + Lctor: + Expression *ex; + ex = new IndexExp(loc, ea, ek); + ex = ex->semantic(sc); + ex = ex->optimize(WANTvalue); + ex = ex->modifiableLvalue(sc, ex); // allocate new slot + ey = new ConstructExp(loc, ex, ey); + + e = new CastExp(e->loc, e, Type::tvoid); + ey = new CastExp(ey->loc, ey, Type::tvoid); + } + } + if (ey) + e = new CondExp(loc, new InExp(loc, ek, ea), e, ey); + + e = combine(e0, e); + e = e->semantic(sc); + return e; } + + Expression *e = op_overload(sc); if (e) { /* See if we need to set ctorinit, i.e. track * assignments to fields. An assignment to a field counts even * if done through an opAssign overload. */ - e1->checkModifiable(sc); return e; } } else if (op == TOKconstruct && !refinit) - { Type *t2 = e2->type->toBasetype(); - if (t2->ty == Tstruct && - sd == ((TypeStruct *)t2)->sym && - sd->cpctor) - { /* We have a copy constructor for this - */ - if (e2->op == TOKquestion) - { /* Write as: - * a ? e1 = b : e1 = c; - */ - CondExp *econd = (CondExp *)e2; - AssignExp *ea1 = new AssignExp(econd->e1->loc, e1, econd->e1); - ea1->op = op; - AssignExp *ea2 = new AssignExp(econd->e1->loc, e1, econd->e2); - ea2->op = op; - Expression *e = new CondExp(loc, econd->econd, ea1, ea2); - return e->semantic(sc); - } - else if (e2->isLvalue()) - { /* Write as: - * e1.cpctor(e2); - */ - if (!e2->type->implicitConvTo(e1->type)) - error("conversion error from %s to %s", e2->type->toChars(), e1->type->toChars()); - - Expression *e = new DotVarExp(loc, e1, sd->cpctor, 0); - e = new CallExp(loc, e, e2); - return e->semantic(sc); - } - else if (e2->op == TOKcall) + { + Type *t2 = e2->type->toBasetype(); + if (t2->ty == Tstruct && sd == ((TypeStruct *)t2)->sym) + { + if (sd->ctor && // there are constructors + e2->op == TOKcall && + e2->type->implicitConvTo(t1)) { - /* The struct value returned from the function is transferred - * so should not call the destructor on it. + /* Look for form of constructor call which is: + * *__ctmp.ctor(arguments...) */ - valueNoDtor(e2); + CallExp *ce = (CallExp *)e2; + if (ce->e1->op == TOKdotvar) + { + DotVarExp *dve = (DotVarExp *)ce->e1; + if (dve->var->isCtorDeclaration()) + { + /* It's a constructor call, currently constructing + * a temporary __ctmp. + */ + /* Before calling the constructor, initialize + * variable with a bit copy of the default + * initializer + */ + + if (sd->zeroInit == 1) + { + e2 = new IntegerExp(loc, 0, Type::tint32); + } + else if (sd->isNested()) + { + e2 = t1->defaultInitLiteral(loc); + this->op = TOKblit; + } + else + { + e2 = t1->defaultInit(loc); + this->op = TOKblit; + } + type = e1->type; + + /* Replace __ctmp being constructed with e1. + * We need to copy constructor call expression, + * because it may be used in other place. + */ + DotVarExp *dvx = (DotVarExp *)dve->copy(); + dvx->e1 = e1; + CallExp *cx = (CallExp *)ce->copy(); + cx->e1 = dvx; + + Expression *e = new CommaExp(loc, this, cx); + e = e->semantic(sc); + return e; + } + } + } + if (sd->cpctor) + { + /* We have a copy constructor for this + */ + if (e2->op == TOKquestion) + { + /* Write as: + * a ? e1 = b : e1 = c; + */ + CondExp *econd = (CondExp *)e2; + AssignExp *ea1 = new AssignExp(econd->e1->loc, e1, econd->e1); + ea1->op = op; + AssignExp *ea2 = new AssignExp(econd->e1->loc, e1, econd->e2); + ea2->op = op; + Expression *e = new CondExp(loc, econd->econd, ea1, ea2); + return e->semantic(sc); + } + + if (e2->isLvalue()) + { + /* Write as: + * e1.cpctor(e2); + */ + if (!e2->type->implicitConvTo(e1->type)) + error("conversion error from %s to %s", e2->type->toChars(), e1->type->toChars()); + + Expression *e = new DotVarExp(loc, e1, sd->cpctor, 0); + e = new CallExp(loc, e, e2); + return e->semantic(sc); + } + else + { + /* The struct value returned from the function is transferred + * so should not call the destructor on it. + */ + e2 = valueNoDtor(e2); + } + } + } + else + { + if (!e2->implicitConvTo(t1)) + { + // Look for implicit constructor call + if (sd->ctor) + { + // Look for constructor first + // Rewrite as e1.ctor(arguments) + Expression *e; + e = new DotIdExp(loc, e1, Id::ctor); + e = new CallExp(loc, e, e2); + e = e->semantic(sc); + return e; + } } } } + Lx: ; } else if (t1->ty == Tclass) - { // Disallow assignment operator overloads for same type + { + // Disallow assignment operator overloads for same type if (op == TOKassign && !e2->implicitConvTo(e1->type)) { Expression *e = op_overload(sc); @@ -11101,7 +11762,8 @@ Ltupleassign: e2 = e2->semantic(sc); } else if (global.params.warnings && !global.gag && op == TOKassign && - e2->op != TOKarrayliteral && e2->op != TOKstring) + e2->op != TOKarrayliteral && e2->op != TOKstring && + !e2->implicitConvTo(t1)) { // Disallow sa = da (Converted to sa[] = da[]) // Disallow sa = e (Converted to sa[] = e) const char* e1str = e1->toChars(); @@ -11134,13 +11796,17 @@ Ltupleassign: ArrayLengthExp *ale = (ArrayLengthExp *)e1; ale->e1 = ale->e1->modifiableLvalue(sc, e1); + if (ale->e1->op == TOKerror) + return ale->e1; + checkDefCtor(ale->loc, ale->e1->type->toBasetype()->nextOf()); } else if (e1->op == TOKslice) { Type *tn = e1->type->nextOf(); - if (op == TOKassign && e1->checkModifiable(sc) == 1 && !tn->isMutable()) - { error("slice %s is not mutable", e1->toChars()); + if (op == TOKassign && !tn->isMutable()) + { + error("slice %s is not mutable", e1->toChars()); return new ErrorExp(); } } @@ -11171,6 +11837,8 @@ Ltupleassign: { // memset ismemset = 1; // make it easy for back end to tell what this is e2 = e2->implicitCastTo(sc, t1->nextOf()); + if (op != TOKblit && e2->isLvalue()) + e2->checkPostblit(sc, t1->nextOf()); } else if (t1->ty == Tsarray) { @@ -11198,7 +11866,8 @@ Ltupleassign: tx2 = ((SliceExp *)e2)->e1->type->toBasetype(); uinteger_t dim1, dim2; if (e2->op == TOKarrayliteral) - { dim2 = ((ArrayLiteralExp *)e2)->elements->dim; + { + dim2 = ((ArrayLiteralExp *)e2)->elements->dim; goto Lsa; } if (tx2->ty == Tsarray) @@ -11220,7 +11889,7 @@ Ltupleassign: e2->op == TOKcast && ((UnaExp *)e2)->e1->isLvalue() || e2->op != TOKslice && e2->isLvalue())) { - checkPostblit(e2->loc, t2->nextOf()); + e2->checkPostblit(sc, t2->nextOf()); } if (global.params.warnings && !global.gag && op == TOKassign && e2->op != TOKslice && e2->op != TOKassign && @@ -11254,9 +11923,9 @@ Ltupleassign: // Disallow da = sa (Converted to da = sa[]) const char* e1str = e1->toChars(); const char* e2str = e2->toChars(); + const char* atypestr = e1->op == TOKslice ? "element-wise" : "slice"; warning("explicit %s assignment %s = (%s)[] is better than %s = %s", - e1->op == TOKslice ? "element-wise" : "slice", - e1str, e2str, e1str, e2str); + atypestr, e1str, e2str, e1str, e2str); } e2 = e2->implicitCastTo(sc, e1->type); } @@ -11292,7 +11961,7 @@ Ltupleassign: type = e1->type; assert(type); - return reorderSettingAAElem(sc); + return op == TOKassign ? reorderSettingAAElem(sc) : this; } Expression *AssignExp::checkToBoolean(Scope *sc) @@ -11374,7 +12043,7 @@ Expression *CatAssignExp::semantic(Scope *sc) ) ) { // Append array - checkPostblit(e1->loc, tb1next); + e1->checkPostblit(sc, tb1next); e2 = e2->castTo(sc, e1->type); type = e1->type; } @@ -11382,8 +12051,9 @@ Expression *CatAssignExp::semantic(Scope *sc) e2->implicitConvTo(tb1next) ) { // Append element - checkPostblit(e2->loc, tb2); + e2->checkPostblit(sc, tb2); e2 = e2->castTo(sc, tb1next); + e2 = e2->isLvalue() ? callCpCtor(sc, e2) : valueNoDtor(e2); type = e1->type; } else if (tb1->ty == Tarray && @@ -11569,6 +12239,19 @@ Expression *AddExp::semantic(Scope *sc) Type *tb1 = e1->type->toBasetype(); Type *tb2 = e2->type->toBasetype(); + if (tb1->ty == Tdelegate || + tb1->ty == Tpointer && tb1->nextOf()->ty == Tfunction) + { + e = e1->checkArithmetic(); + } + if (tb2->ty == Tdelegate || + tb2->ty == Tpointer && tb2->nextOf()->ty == Tfunction) + { + e = e2->checkArithmetic(); + } + if (e) + return e; + if ((tb1->ty == Tarray || tb1->ty == Tsarray) && (tb2->ty == Tarray || tb2->ty == Tsarray) && tb1->nextOf()->equals(tb2->nextOf()) @@ -11578,8 +12261,10 @@ Expression *AddExp::semantic(Scope *sc) e = this; } else if (tb1->ty == Tpointer && e2->type->isintegral() || - tb2->ty == Tpointer && e1->type->isintegral()) + tb2->ty == Tpointer && e1->type->isintegral()) + { e = scaleFactor(sc); + } else if (tb1->ty == Tpointer && tb2->ty == Tpointer) { return incompatibleTypes(); @@ -11645,9 +12330,23 @@ Expression *MinExp::semantic(Scope *sc) if (e) return e; - e = this; Type *t1 = e1->type->toBasetype(); Type *t2 = e2->type->toBasetype(); + + if (t1->ty == Tdelegate || + t1->ty == Tpointer && t1->nextOf()->ty == Tfunction) + { + e = e1->checkArithmetic(); + } + if (t2->ty == Tdelegate || + t2->ty == Tpointer && t2->nextOf()->ty == Tfunction) + { + e = e2->checkArithmetic(); + } + if (e) + return e; + + e = this; if (t1->ty == Tpointer) { if (t2->ty == Tpointer) @@ -11772,7 +12471,7 @@ Expression *CatExp::semantic(Scope *sc) e2->implicitConvTo(tb1next) >= MATCHconvert && tb2->ty != Tvoid) { - checkPostblit(e2->loc, tb2); + e2->checkPostblit(sc, tb2); e2 = e2->implicitCastTo(sc, tb1next); type = tb1next->arrayOf(); if (tb2->ty == Tarray || tb2->ty == Tsarray) @@ -11786,7 +12485,7 @@ Expression *CatExp::semantic(Scope *sc) e1->implicitConvTo(tb2next) >= MATCHconvert && tb1->ty != Tvoid) { - checkPostblit(e1->loc, tb1); + e1->checkPostblit(sc, tb1); e1 = e1->implicitCastTo(sc, tb2next); type = tb2next->arrayOf(); if (tb1->ty == Tarray || tb1->ty == Tsarray) @@ -11828,7 +12527,7 @@ Expression *CatExp::semantic(Scope *sc) } if (tb->nextOf()) { - checkPostblit(loc, tb->nextOf()); + checkPostblit(sc, tb->nextOf()); } #if 0 e1->type->print(); @@ -12079,95 +12778,91 @@ Expression *PowExp::semantic(Scope *sc) } } - if ( (e1->type->isintegral() || e1->type->isfloating()) && - (e2->type->isintegral() || e2->type->isfloating())) + if ( !(e1->type->isintegral() || e1->type->isfloating()) || + !(e2->type->isintegral() || e2->type->isfloating())) { - // For built-in numeric types, there are several cases. - // TODO: backend support, especially for e1 ^^ 2. + return incompatibleTypes(); + } - bool wantSqrt = false; + // For built-in numeric types, there are several cases. + // TODO: backend support, especially for e1 ^^ 2. - // First, attempt to fold the expression. - e = optimize(WANTvalue); - if (e->op != TOKpow) - { - e = e->semantic(sc); - return e; - } + bool wantSqrt = false; - // Determine if we're raising to an integer power. - sinteger_t intpow = 0; - if (e2->op == TOKint64 && ((sinteger_t)e2->toInteger() == 2 || (sinteger_t)e2->toInteger() == 3)) - intpow = e2->toInteger(); - else if (e2->op == TOKfloat64 && (e2->toReal() == (sinteger_t)(e2->toReal()))) - intpow = (sinteger_t)(e2->toReal()); - - // Deal with x^^2, x^^3 immediately, since they are of practical importance. - if (intpow == 2 || intpow == 3) - { - // Replace x^^2 with (tmp = x, tmp*tmp) - // Replace x^^3 with (tmp = x, tmp*tmp*tmp) - Identifier *idtmp = Lexer::uniqueId("__powtmp"); - VarDeclaration *tmp = new VarDeclaration(loc, e1->type->toBasetype(), idtmp, new ExpInitializer(Loc(), e1)); - tmp->storage_class = STCctfe; - Expression *ve = new VarExp(loc, tmp); - Expression *ae = new DeclarationExp(loc, tmp); - /* Note that we're reusing ve. This should be ok. - */ - Expression *me = new MulExp(loc, ve, ve); - if (intpow == 3) - me = new MulExp(loc, me, ve); - e = new CommaExp(loc, ae, me); - e = e->semantic(sc); - return e; - } - - static int importMathChecked = 0; - static bool importMath = false; - if (!importMathChecked) - { - importMathChecked = 1; - for (size_t i = 0; i < Module::amodules.dim; i++) - { Module *mi = Module::amodules[i]; - //printf("\t[%d] %s\n", i, mi->toChars()); - if (mi->ident == Id::math && - mi->parent->ident == Id::std && - !mi->parent->parent) - { - importMath = true; - goto L1; - } - } - error("must import std.math to use ^^ operator"); - return new ErrorExp(); - - L1: ; - } - else - { - if (!importMath) - { - error("must import std.math to use ^^ operator"); - return new ErrorExp(); - } - } - - e = new IdentifierExp(loc, Id::empty); - e = new DotIdExp(loc, e, Id::std); - e = new DotIdExp(loc, e, Id::math); - if (e2->op == TOKfloat64 && e2->toReal() == 0.5) - { // Replace e1 ^^ 0.5 with .std.math.sqrt(x) - e = new CallExp(loc, new DotIdExp(loc, e, Id::_sqrt), e1); - } - else - { - // Replace e1 ^^ e2 with .std.math.pow(e1, e2) - e = new CallExp(loc, new DotIdExp(loc, e, Id::_pow), e1, e2); - } + // First, attempt to fold the expression. + e = optimize(WANTvalue); + if (e->op != TOKpow) + { e = e->semantic(sc); return e; } - return incompatibleTypes(); + + // Determine if we're raising to an integer power. + sinteger_t intpow = 0; + if (e2->op == TOKint64 && ((sinteger_t)e2->toInteger() == 2 || (sinteger_t)e2->toInteger() == 3)) + intpow = e2->toInteger(); + else if (e2->op == TOKfloat64 && (e2->toReal() == (sinteger_t)(e2->toReal()))) + intpow = (sinteger_t)(e2->toReal()); + + // Deal with x^^2, x^^3 immediately, since they are of practical importance. + if (intpow == 2 || intpow == 3) + { + // Replace x^^2 with (tmp = x, tmp*tmp) + // Replace x^^3 with (tmp = x, tmp*tmp*tmp) + Identifier *idtmp = Lexer::uniqueId("__powtmp"); + VarDeclaration *tmp = new VarDeclaration(loc, e1->type->toBasetype(), idtmp, new ExpInitializer(Loc(), e1)); + tmp->storage_class = STCctfe; + Expression *ve = new VarExp(loc, tmp); + Expression *ae = new DeclarationExp(loc, tmp); + /* Note that we're reusing ve. This should be ok. + */ + Expression *me = new MulExp(loc, ve, ve); + if (intpow == 3) + me = new MulExp(loc, me, ve); + e = new CommaExp(loc, ae, me); + e = e->semantic(sc); + return e; + } + + static int importMathChecked = 0; + static bool importMath = false; + if (!importMathChecked) + { + importMathChecked = 1; + for (size_t i = 0; i < Module::amodules.dim; i++) + { Module *mi = Module::amodules[i]; + //printf("\t[%d] %s\n", i, mi->toChars()); + if (mi->ident == Id::math && + mi->parent->ident == Id::std && + !mi->parent->parent) + { + importMath = true; + break; + } + } + } + if (!importMath) + { // Leave handling of PowExp to the backend, or throw + // an error gracefully if no backend support exists. + typeCombine(sc); + e = this; + return e; + } + + e = new IdentifierExp(loc, Id::empty); + e = new DotIdExp(loc, e, Id::std); + e = new DotIdExp(loc, e, Id::math); + if (e2->op == TOKfloat64 && e2->toReal() == 0.5) + { // Replace e1 ^^ 0.5 with .std.math.sqrt(x) + e = new CallExp(loc, new DotIdExp(loc, e, Id::_sqrt), e1); + } + else + { + // Replace e1 ^^ e2 with .std.math.pow(e1, e2) + e = new CallExp(loc, new DotIdExp(loc, e, Id::_pow), e1, e2); + } + e = e->semantic(sc); + return e; } /************************************************************/ @@ -12567,7 +13262,7 @@ void RemoveExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) /************************************************************/ -CmpExp::CmpExp(enum TOK op, Loc loc, Expression *e1, Expression *e2) +CmpExp::CmpExp(TOK op, Loc loc, Expression *e1, Expression *e2) : BinExp(loc, op, sizeof(CmpExp), e1, e2) { } @@ -12616,9 +13311,6 @@ Expression *CmpExp::semantic(Scope *sc) return new ErrorExp(); } - Expression *eb1 = e1; - Expression *eb2 = e2; - e = typeCombine(sc); if (e->op == TOKerror) return e; @@ -12653,6 +13345,11 @@ Expression *CmpExp::semantic(Scope *sc) error("compare not defined for complex operands"); e = new ErrorExp(); } + else if (t1->ty == Taarray || t2->ty == Taarray) + { + error("%s is not defined for associative arrays", Token::toChars(op)); + e = new ErrorExp(); + } else if (t1->ty == Tvector) return incompatibleTypes(); else @@ -12672,7 +13369,7 @@ int CmpExp::isBit() /************************************************************/ -EqualExp::EqualExp(enum TOK op, Loc loc, Expression *e1, Expression *e2) +EqualExp::EqualExp(TOK op, Loc loc, Expression *e1, Expression *e2) : BinExp(loc, op, sizeof(EqualExp), e1, e2) { assert(op == TOKequal || op == TOKnotequal); @@ -12714,16 +13411,20 @@ Expression *EqualExp::semantic(Scope *sc) BinExp::semanticp(sc); + if (e1->op == TOKtype || e2->op == TOKtype) + return incompatibleTypes(); + /* Before checking for operator overloading, check to see if we're * comparing the addresses of two statics. If so, we can just see * if they are the same symbol. */ if (e1->op == TOKaddress && e2->op == TOKaddress) - { AddrExp *ae1 = (AddrExp *)e1; + { + AddrExp *ae1 = (AddrExp *)e1; AddrExp *ae2 = (AddrExp *)e2; - if (ae1->e1->op == TOKvar && ae2->e1->op == TOKvar) - { VarExp *ve1 = (VarExp *)ae1->e1; + { + VarExp *ve1 = (VarExp *)ae1->e1; VarExp *ve2 = (VarExp *)ae2->e1; if (ve1->var == ve2->var /*|| ve1->var->toSymbol() == ve2->var->toSymbol()*/) @@ -12812,6 +13513,7 @@ Expression *EqualExp::semantic(Scope *sc) } } + // check tuple equality before typeCombine if (e1->op == TOKtuple && e2->op == TOKtuple) { TupleExp *tup1 = (TupleExp *)e1; @@ -12880,7 +13582,7 @@ int EqualExp::isBit() /************************************************************/ -IdentityExp::IdentityExp(enum TOK op, Loc loc, Expression *e1, Expression *e2) +IdentityExp::IdentityExp(TOK op, Loc loc, Expression *e1, Expression *e2) : BinExp(loc, op, sizeof(IdentityExp), e1, e2) { } @@ -12931,11 +13633,7 @@ Expression *CondExp::syntaxCopy() Expression *CondExp::semantic(Scope *sc) -{ Type *t1; - Type *t2; - unsigned cs0; - unsigned cs1; - +{ #if LOGSEMANTIC printf("CondExp::semantic('%s')\n", toChars()); #endif @@ -12947,19 +13645,32 @@ Expression *CondExp::semantic(Scope *sc) econd = econd->checkToPointer(); econd = econd->checkToBoolean(sc); - cs0 = sc->callSuper; + unsigned cs0 = sc->callSuper; + unsigned *fi0 = fi0 = sc->saveFieldInit(); e1 = e1->semantic(sc); e1 = resolveProperties(sc, e1); - cs1 = sc->callSuper; + + unsigned cs1 = sc->callSuper; + unsigned *fi1 = sc->fieldinit; sc->callSuper = cs0; + sc->fieldinit = fi0; e2 = e2->semantic(sc); e2 = resolveProperties(sc, e2); + sc->mergeCallSuper(loc, cs1); + sc->mergeFieldInit(loc, fi1); + + if (econd->type == Type::terror) + return econd; + if (e1->type == Type::terror) + return e1; + if (e2->type == Type::terror) + return e2; // If either operand is void, the result is void - t1 = e1->type; - t2 = e2->type; + Type *t1 = e1->type; + Type *t2 = e2->type; if (t1->ty == Tvoid || t2->ty == Tvoid) type = Type::tvoid; else if (t1 == t2) @@ -12989,6 +13700,7 @@ Expression *CondExp::semantic(Scope *sc) e2 = e2->castTo(sc, type); } } + type = type->merge2(); #if 0 printf("res: %s\n", type->toChars()); printf("e1 : %s\n", e1->type->toChars()); @@ -13092,7 +13804,7 @@ Expression* GEPExp::toLvalue(Scope* sc, Expression* e) /****************************************************************/ -DefaultInitExp::DefaultInitExp(Loc loc, enum TOK subop, int size) +DefaultInitExp::DefaultInitExp(Loc loc, TOK subop, int size) : Expression(loc, TOKdefault, size) { this->subop = subop; @@ -13248,15 +13960,42 @@ Expression *PrettyFuncInitExp::resolveLoc(Loc loc, Scope *sc) return e; } +Expression *extractOpDollarSideEffect(Scope *sc, UnaExp *ue) +{ + Expression *e0 = NULL; + if (ue->e1->hasSideEffect()) + { + /* Even if opDollar is needed, 'ue->e1' should be evaluate only once. So + * Rewrite: + * ue->e1.opIndex( ... use of $ ... ) + * ue->e1.opSlice( ... use of $ ... ) + * as: + * (ref __dop = ue->e1, __dop).opIndex( ... __dop.opDollar ...) + * (ref __dop = ue->e1, __dop).opSlice( ... __dop.opDollar ...) + */ + Identifier *id = Lexer::uniqueId("__dop"); + ExpInitializer *ei = new ExpInitializer(ue->loc, ue->e1); + VarDeclaration *v = new VarDeclaration(ue->loc, ue->e1->type, id, ei); + v->storage_class |= STCctfe | STCforeach | STCref; + e0 = new DeclarationExp(ue->loc, v); + e0 = e0->semantic(sc); + ue->e1 = new VarExp(ue->loc, v); + ue->e1 = ue->e1->semantic(sc); + } + return e0; +} + /************************************** * Runs semantic on ae->arguments. Declares temporary variables * if '$' was used. */ -ArrayExp *resolveOpDollar(Scope *sc, ArrayExp *ae) +Expression *resolveOpDollar(Scope *sc, ArrayExp *ae) { assert(!ae->lengthVar); + Expression *e0 = extractOpDollarSideEffect(sc, ae); + for (size_t i = 0; i < ae->arguments->dim; i++) { // Create scope for '$' variable for this dimension @@ -13272,8 +14011,9 @@ ArrayExp *resolveOpDollar(Scope *sc, ArrayExp *ae) e = resolveProperties(sc, e); if (!e->type) ae->error("%s has no value", e->toChars()); - if (ae->lengthVar) - { // If $ was used, declare it now + if (ae->lengthVar && sc->func) + { + // If $ was used, declare it now Expression *de = new DeclarationExp(ae->loc, ae->lengthVar); e = new CommaExp(Loc(), de, e); e = e->semantic(sc); @@ -13281,7 +14021,8 @@ ArrayExp *resolveOpDollar(Scope *sc, ArrayExp *ae) (*ae->arguments)[i] = e; sc = sc->pop(); } - return ae; + + return e0; } /************************************** @@ -13289,12 +14030,14 @@ ArrayExp *resolveOpDollar(Scope *sc, ArrayExp *ae) * if '$' was used. */ -SliceExp *resolveOpDollar(Scope *sc, SliceExp *se) +Expression *resolveOpDollar(Scope *sc, SliceExp *se) { assert(!se->lengthVar); assert(!se->lwr || se->upr); - if (!se->lwr) return se; + if (!se->lwr) return NULL; + + Expression *e0 = extractOpDollarSideEffect(sc, se); // create scope for '$' ArrayScopeSymbol *sym = new ArrayScopeSymbol(sc, se); @@ -13309,17 +14052,19 @@ SliceExp *resolveOpDollar(Scope *sc, SliceExp *se) e = resolveProperties(sc, e); if (!e->type) se->error("%s has no value", e->toChars()); - i == 0 ? se->lwr : se->upr = e; + (i == 0 ? se->lwr : se->upr) = e; } - if (se->lengthVar) - { // If $ was used, declare it now + if (se->lengthVar && sc->func) + { + // If $ was used, declare it now Expression *de = new DeclarationExp(se->loc, se->lengthVar); se->lwr = new CommaExp(Loc(), de, se->lwr); se->lwr = se->lwr->semantic(sc); } sc = sc->pop(); - return se; + + return e0; } Expression *BinExp::reorderSettingAAElem(Scope *sc) @@ -13372,7 +14117,7 @@ Expression *BinExp::reorderSettingAAElem(Scope *sc) { Identifier *id = Lexer::uniqueId("__aaval"); VarDeclaration *vd = new VarDeclaration(loc, this->e2->type, id, new ExpInitializer(this->e2->loc, this->e2)); - vd->storage_class |= STCref | STCforeach; + vd->storage_class |= STCref | STCforeach | (this->e2->isLvalue() ? 0 : STCtemp); Expression *de = new DeclarationExp(this->e2->loc, vd); ec = ec ? new CommaExp(loc, ec, de) : de; diff --git a/dmd2/expression.h b/dmd2/expression.h index 2e4489d0..f5c98f04 100644 --- a/dmd2/expression.h +++ b/dmd2/expression.h @@ -17,32 +17,32 @@ #include "arraytypes.h" #include "intrange.h" -struct Type; -struct TypeVector; +class Type; +class TypeVector; struct Scope; -struct TupleDeclaration; -struct VarDeclaration; -struct FuncDeclaration; -struct FuncLiteralDeclaration; -struct Declaration; -struct CtorDeclaration; -struct NewDeclaration; -struct Dsymbol; -struct Import; -struct Module; -struct ScopeDsymbol; +class TupleDeclaration; +class VarDeclaration; +class FuncDeclaration; +class FuncLiteralDeclaration; +class Declaration; +class CtorDeclaration; +class NewDeclaration; +class Dsymbol; +class Import; +class Module; +class ScopeDsymbol; struct InlineCostState; struct InlineDoState; struct InlineScanState; -struct Expression; -struct Declaration; -struct AggregateDeclaration; -struct StructDeclaration; -struct TemplateInstance; -struct TemplateDeclaration; -struct ClassDeclaration; +class Expression; +class Declaration; +class AggregateDeclaration; +class StructDeclaration; +class TemplateInstance; +class TemplateDeclaration; +class ClassDeclaration; struct HdrGenState; -struct BinExp; +class BinExp; struct InterState; #if IN_DMD struct Symbol; // back end symbol @@ -50,9 +50,14 @@ struct Symbol; // back end symbol struct OverloadSet; struct Initializer; struct StringExp; +class OverloadSet; +class Initializer; +class StringExp; +class ArrayExp; +class SliceExp; #if IN_LLVM -struct AssignExp; -struct SymbolDeclaration; +class AssignExp; +class SymbolDeclaration; #endif enum TOK; @@ -64,7 +69,7 @@ struct dt_t; #endif #ifdef IN_GCC -union tree_node; typedef union tree_node elem; +typedef union tree_node elem; #elif IN_LLVM class DValue; typedef class DValue elem; #else @@ -78,6 +83,7 @@ namespace llvm { class ConstantInt; class GlobalVariable; class StructType; + class Value; } #endif @@ -86,6 +92,7 @@ void initPrecedence(); typedef int (*apply_fp_t)(Expression *, void *); Expression *resolveProperties(Scope *sc, Expression *e); +Expression *resolvePropertiesOnly(Scope *sc, Expression *e1); void accessCheck(Loc loc, Scope *sc, Expression *e, Declaration *d); Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg, Dsymbol *d); Dsymbol *search_function(ScopeDsymbol *ad, Identifier *funcid); @@ -98,17 +105,21 @@ FuncDeclaration *hasThis(Scope *sc); Expression *fromConstInitializer(int result, Expression *e); int arrayExpressionCanThrow(Expressions *exps, bool mustNotThrow); TemplateDeclaration *getFuncTemplateDecl(Dsymbol *s); -void valueNoDtor(Expression *e); +Expression *valueNoDtor(Expression *e); int modifyFieldVar(Loc loc, Scope *sc, VarDeclaration *var, Expression *e1); #if DMDV2 Expression *resolveAliasThis(Scope *sc, Expression *e); -Expression *callCpCtor(Loc loc, Scope *sc, Expression *e, int noscope); -bool checkPostblit(Loc loc, Type *t); +Expression *callCpCtor(Scope *sc, Expression *e); #endif -struct ArrayExp *resolveOpDollar(Scope *sc, struct ArrayExp *ae); -struct SliceExp *resolveOpDollar(Scope *sc, struct SliceExp *se); +Expression *resolveOpDollar(Scope *sc, ArrayExp *ae); +Expression *resolveOpDollar(Scope *sc, SliceExp *se); Expressions *arrayExpressionSemantic(Expressions *exps, Scope *sc); +/* Run CTFE on the expression, but allow the expression to be a TypeExp + * or a tuple containing a TypeExp. (This is required by pragma(msg)). + */ +Expression *ctfeInterpretForPragmaMsg(Expression *e); + /* Interpreter: what form of return value expression is required? */ enum CtfeGoal @@ -121,27 +132,25 @@ enum CtfeGoal #define WANTflags 1 #define WANTvalue 2 -// A compile-time result is required. Give an error if not possible -#define WANTinterpret 4 // Same as WANTvalue, but also expand variables as far as possible #define WANTexpand 8 -struct Expression : Object +class Expression : public RootObject { +public: Loc loc; // file location - enum TOK op; // handy to minimize use of dynamic_cast + TOK op; // handy to minimize use of dynamic_cast Type *type; // !=NULL means that semantic() has been run unsigned char size; // # of bytes in Expression so we can copy() it unsigned char parens; // if this is a parenthesized expression - Expression(Loc loc, enum TOK op, int size); + Expression(Loc loc, TOK op, int size); static void init(); Expression *copy(); virtual Expression *syntaxCopy(); virtual int apply(apply_fp_t fp, void *param); virtual Expression *semantic(Scope *sc); Expression *trySemantic(Scope *sc); - Expression *ctfeSemantic(Scope *sc); int dyncast() { return DYNCAST_EXPRESSION; } // kludge for template.isExpression() @@ -181,8 +190,9 @@ struct Expression : Object Expression *checkArithmetic(); void checkDeprecated(Scope *sc, Dsymbol *s); void checkPurity(Scope *sc, FuncDeclaration *f); - void checkPurity(Scope *sc, VarDeclaration *v, Expression *e1); + void checkPurity(Scope *sc, VarDeclaration *v); void checkSafety(Scope *sc, FuncDeclaration *f); + bool checkPostblit(Scope *sc, Type *t); virtual int checkModifiable(Scope *sc, int flag = 0); virtual Expression *checkToBoolean(Scope *sc); virtual Expression *addDtorHook(Scope *sc); @@ -241,13 +251,14 @@ struct Expression : Object #endif }; -struct IntegerExp : Expression +class IntegerExp : public Expression { +public: dinteger_t value; IntegerExp(Loc loc, dinteger_t value, Type *type); IntegerExp(dinteger_t value); - int equals(Object *o); + bool equals(RootObject *o); Expression *semantic(Scope *sc); Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); char *toChars(); @@ -271,22 +282,25 @@ struct IntegerExp : Expression #endif }; -struct ErrorExp : IntegerExp +class ErrorExp : public IntegerExp { +public: ErrorExp(); Expression *implicitCastTo(Scope *sc, Type *t); + MATCH implicitConvTo(Type *t); Expression *castTo(Scope *sc, Type *t); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Expression *toLvalue(Scope *sc, Expression *e); }; -struct RealExp : Expression +class RealExp : public Expression { +public: real_t value; RealExp(Loc loc, real_t value, Type *type); - int equals(Object *o); + bool equals(RootObject *o); Expression *semantic(Scope *sc); Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); char *toChars(); @@ -308,12 +322,13 @@ struct RealExp : Expression #endif }; -struct ComplexExp : Expression +class ComplexExp : public Expression { +public: complex_t value; ComplexExp(Loc loc, complex_t value, Type *type); - int equals(Object *o); + bool equals(RootObject *o); Expression *semantic(Scope *sc); Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); char *toChars(); @@ -335,8 +350,9 @@ struct ComplexExp : Expression #endif }; -struct IdentifierExp : Expression +class IdentifierExp : public Expression { +public: Identifier *ident; Declaration *var; @@ -349,17 +365,19 @@ struct IdentifierExp : Expression Expression *toLvalue(Scope *sc, Expression *e); }; -struct DollarExp : IdentifierExp +class DollarExp : public IdentifierExp { +public: DollarExp(Loc loc); }; -struct DsymbolExp : Expression +class DsymbolExp : public Expression { +public: Dsymbol *s; - int hasOverloads; + bool hasOverloads; - DsymbolExp(Loc loc, Dsymbol *s, int hasOverloads = 0); + DsymbolExp(Loc loc, Dsymbol *s, bool hasOverloads = false); Expression *semantic(Scope *sc); char *toChars(); void dump(int indent); @@ -368,8 +386,9 @@ struct DsymbolExp : Expression Expression *toLvalue(Scope *sc, Expression *e); }; -struct ThisExp : Expression +class ThisExp : public Expression { +public: Declaration *var; ThisExp(Loc loc); @@ -388,8 +407,9 @@ struct ThisExp : Expression elem *toElem(IRState *irs); }; -struct SuperExp : ThisExp +class SuperExp : public ThisExp { +public: SuperExp(Loc loc); Expression *semantic(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -398,12 +418,13 @@ struct SuperExp : ThisExp //Expression *inlineScan(InlineScanState *iss); }; -struct NullExp : Expression +class NullExp : public Expression { +public: unsigned char committed; // !=0 if type is committed NullExp(Loc loc, Type *t = NULL); - int equals(Object *o); + bool equals(RootObject *o); Expression *semantic(Scope *sc); int isBool(int result); int isConst(); @@ -421,20 +442,21 @@ struct NullExp : Expression #endif }; -struct StringExp : Expression +class StringExp : public Expression { +public: void *string; // char, wchar, or dchar data size_t len; // number of chars, wchars, or dchars unsigned char sz; // 1: char, 2: wchar, 4: dchar unsigned char committed; // !=0 if type is committed - unsigned char postfix; // 'c', 'w', 'd' + utf8_t postfix; // 'c', 'w', 'd' bool ownedByCtfe; // true = created in CTFE StringExp(Loc loc, char *s); StringExp(Loc loc, void *s, size_t len); - StringExp(Loc loc, void *s, size_t len, unsigned char postfix); + StringExp(Loc loc, void *s, size_t len, utf8_t postfix); //Expression *syntaxCopy(); - int equals(Object *o); + bool equals(RootObject *o); Expression *semantic(Scope *sc); Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); size_t length(); @@ -443,7 +465,7 @@ struct StringExp : Expression Expression *implicitCastTo(Scope *sc, Type *t); MATCH implicitConvTo(Type *t); Expression *castTo(Scope *sc, Type *t); - int compare(Object *obj); + int compare(RootObject *obj); int isBool(int result); int isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); @@ -461,8 +483,9 @@ struct StringExp : Expression // Tuple -struct TupleExp : Expression +class TupleExp : public Expression { +public: Expression *e0; // side-effect part /* Tuple-field access may need to take out its side effect part. * For example: @@ -478,7 +501,7 @@ struct TupleExp : Expression TupleExp(Loc loc, TupleDeclaration *tup); Expression *syntaxCopy(); int apply(apply_fp_t fp, void *param); - int equals(Object *o); + bool equals(RootObject *o); Expression *semantic(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void checkEscape(); @@ -491,8 +514,9 @@ struct TupleExp : Expression Expression *inlineScan(InlineScanState *iss); }; -struct ArrayLiteralExp : Expression +class ArrayLiteralExp : public Expression { +public: Expressions *elements; bool ownedByCtfe; // true = created in CTFE @@ -501,6 +525,7 @@ struct ArrayLiteralExp : Expression Expression *syntaxCopy(); int apply(apply_fp_t fp, void *param); + bool equals(RootObject *o); Expression *semantic(Scope *sc); int isBool(int result); elem *toElem(IRState *irs); @@ -518,12 +543,16 @@ struct ArrayLiteralExp : Expression dt_t **toDt(dt_t **pdt); #endif + void buildArrayIdent(OutBuffer *buf, Expressions *arguments); + Expression *buildArrayLoop(Parameters *fparams); + Expression *doInline(InlineDoState *ids); Expression *inlineScan(InlineScanState *iss); }; -struct AssocArrayLiteralExp : Expression +class AssocArrayLiteralExp : public Expression { +public: Expressions *keys; Expressions *values; bool ownedByCtfe; // true = created in CTFE @@ -557,9 +586,12 @@ struct AssocArrayLiteralExp : Expression #define stageApply 0x8 //inlineScan is running #define stageInlineScan 0x10 +// toCBuffer is running +#define stageToCBuffer 0x20 -struct StructLiteralExp : Expression +class StructLiteralExp : public Expression { +public: StructDeclaration *sd; // which aggregate this is for Expressions *elements; // parallels sd->fields[] with // NULL entries for fields to skip @@ -586,7 +618,7 @@ struct StructLiteralExp : Expression // (with infinite recursion) of this expression. StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions *elements, Type *stype = NULL); - int equals(Object *o); + bool equals(RootObject *o); Expression *syntaxCopy(); int apply(apply_fp_t fp, void *param); Expression *semantic(Scope *sc); @@ -625,11 +657,12 @@ struct StructLiteralExp : Expression Expression *inlineScan(InlineScanState *iss); }; -struct DotIdExp; +class DotIdExp; DotIdExp *typeDotIdExp(Loc loc, Type *type, Identifier *ident); -struct TypeExp : Expression +class TypeExp : public Expression { +public: TypeExp(Loc loc, Type *type); Expression *syntaxCopy(); Expression *semantic(Scope *sc); @@ -639,8 +672,9 @@ struct TypeExp : Expression elem *toElem(IRState *irs); }; -struct ScopeExp : Expression +class ScopeExp : public Expression { +public: ScopeDsymbol *sds; ScopeExp(Loc loc, ScopeDsymbol *sds); @@ -650,8 +684,9 @@ struct ScopeExp : Expression void toCBuffer(OutBuffer *buf, HdrGenState *hgs); }; -struct TemplateExp : Expression +class TemplateExp : public Expression { +public: TemplateDeclaration *td; FuncDeclaration *fd; @@ -662,8 +697,9 @@ struct TemplateExp : Expression Expression *toLvalue(Scope *sc, Expression *e); }; -struct NewExp : Expression +class NewExp : public Expression { +public: /* thisexp.new(newargs) newtype(arguments) */ Expression *thisexp; // if !NULL, 'this' for class being allocated @@ -691,8 +727,9 @@ struct NewExp : Expression //Expression *inlineScan(InlineScanState *iss); }; -struct NewAnonClassExp : Expression +class NewAnonClassExp : public Expression { +public: /* thisexp.new(newargs) class baseclasses { } (arguments) */ Expression *thisexp; // if !NULL, 'this' for class being allocated @@ -709,12 +746,13 @@ struct NewAnonClassExp : Expression }; #if DMDV2 -struct SymbolExp : Expression +class SymbolExp : public Expression { +public: Declaration *var; - int hasOverloads; + bool hasOverloads; - SymbolExp(Loc loc, enum TOK op, int size, Declaration *var, int hasOverloads); + SymbolExp(Loc loc, TOK op, int size, Declaration *var, bool hasOverloads); elem *toElem(IRState *irs); }; @@ -722,11 +760,12 @@ struct SymbolExp : Expression // Offset from symbol -struct SymOffExp : SymbolExp +class SymOffExp : public SymbolExp { +public: unsigned offset; - SymOffExp(Loc loc, Declaration *var, unsigned offset, int hasOverloads = 0); + SymOffExp(Loc loc, Declaration *var, unsigned offset, bool hasOverloads = false); Expression *semantic(Scope *sc); Expression *optimize(int result, bool keepLvalue = false); Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); @@ -748,10 +787,11 @@ struct SymOffExp : SymbolExp // Variable -struct VarExp : SymbolExp +class VarExp : public SymbolExp { - VarExp(Loc loc, Declaration *var, int hasOverloads = 0); - int equals(Object *o); +public: + VarExp(Loc loc, Declaration *var, bool hasOverloads = false); + bool equals(RootObject *o); Expression *semantic(Scope *sc); Expression *optimize(int result, bool keepLvalue = false); Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); @@ -780,25 +820,29 @@ struct VarExp : SymbolExp #if DMDV2 // Overload Set -struct OverExp : Expression +class OverExp : public Expression { +public: OverloadSet *vars; OverExp(Loc loc, OverloadSet *s); int isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); }; #endif // Function/Delegate literal -struct FuncExp : Expression +class FuncExp : public Expression { +public: FuncLiteralDeclaration *fd; TemplateDeclaration *td; - enum TOK tok; + TOK tok; FuncExp(Loc loc, FuncLiteralDeclaration *fd, TemplateDeclaration *td = NULL); + void genIdent(Scope *sc); Expression *syntaxCopy(); Expression *semantic(Scope *sc); Expression *semantic(Scope *sc, Expressions *arguments); @@ -823,8 +867,9 @@ struct FuncExp : Expression // Declaration of a symbol -struct DeclarationExp : Expression +class DeclarationExp : public Expression { +public: Dsymbol *declaration; DeclarationExp(Loc loc, Dsymbol *declaration); @@ -839,19 +884,21 @@ struct DeclarationExp : Expression Expression *inlineScan(InlineScanState *iss); }; -struct TypeidExp : Expression +class TypeidExp : public Expression { - Object *obj; +public: + RootObject *obj; - TypeidExp(Loc loc, Object *obj); + TypeidExp(Loc loc, RootObject *obj); Expression *syntaxCopy(); Expression *semantic(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); }; #if DMDV2 -struct TraitsExp : Expression +class TraitsExp : public Expression { +public: Identifier *ident; Objects *args; @@ -862,8 +909,9 @@ struct TraitsExp : Expression }; #endif -struct HaltExp : Expression +class HaltExp : public Expression { +public: HaltExp(Loc loc); Expression *semantic(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -871,20 +919,21 @@ struct HaltExp : Expression elem *toElem(IRState *irs); }; -struct IsExp : Expression +class IsExp : public Expression { +public: /* is(targ id tok tspec) * is(targ id == tok2) */ Type *targ; Identifier *id; // can be NULL - enum TOK tok; // ':' or '==' + TOK tok; // ':' or '==' Type *tspec; // can be NULL - enum TOK tok2; // 'struct', 'union', 'typedef', etc. + TOK tok2; // 'struct', 'union', 'typedef', etc. TemplateParameters *parameters; - IsExp(Loc loc, Type *targ, Identifier *id, enum TOK tok, Type *tspec, - enum TOK tok2, TemplateParameters *parameters); + IsExp(Loc loc, Type *targ, Identifier *id, TOK tok, Type *tspec, + TOK tok2, TemplateParameters *parameters); Expression *syntaxCopy(); Expression *semantic(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -892,12 +941,13 @@ struct IsExp : Expression /****************************************************************/ -struct UnaExp : Expression +class UnaExp : public Expression { +public: Expression *e1; Type *att1; // Save alias this type to detect recursion - UnaExp(Loc loc, enum TOK op, int size, Expression *e1); + UnaExp(Loc loc, TOK op, int size, Expression *e1); Expression *syntaxCopy(); int apply(apply_fp_t fp, void *param); Expression *semantic(Scope *sc); @@ -913,15 +963,19 @@ struct UnaExp : Expression virtual Expression *op_overload(Scope *sc); }; -struct BinExp : Expression +typedef Expression *(*fp_t)(Type *, Expression *, Expression *); +typedef int (*fp2_t)(Loc loc, TOK, Expression *, Expression *); + +class BinExp : public Expression { +public: Expression *e1; Expression *e2; Type *att1; // Save alias this type to detect recursion Type *att2; // Save alias this type to detect recursion - BinExp(Loc loc, enum TOK op, int size, Expression *e1, Expression *e2); + BinExp(Loc loc, TOK op, int size, Expression *e1, Expression *e2); Expression *syntaxCopy(); int apply(apply_fp_t fp, void *param); Expression *semantic(Scope *sc); @@ -936,12 +990,9 @@ struct BinExp : Expression void dump(int indent); Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - Expression *interpretCommon(InterState *istate, CtfeGoal goal, - Expression *(*fp)(Type *, Expression *, Expression *)); - Expression *interpretCompareCommon(InterState *istate, CtfeGoal goal, - int (*fp)(Loc, TOK, Expression *, Expression *)); - Expression *interpretAssignCommon(InterState *istate, CtfeGoal goal, - Expression *(*fp)(Type *, Expression *, Expression *), int post = 0); + Expression *interpretCommon(InterState *istate, CtfeGoal goal, fp_t fp); + Expression *interpretCompareCommon(InterState *istate, CtfeGoal goal, fp2_t fp); + Expression *interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_t fp, int post = 0); Expression *interpretFourPointerRelation(InterState *istate, CtfeGoal goal); virtual Expression *arrayOp(Scope *sc); @@ -952,14 +1003,18 @@ struct BinExp : Expression Expression *compare_overload(Scope *sc, Identifier *id); Expression *reorderSettingAAElem(Scope *sc); + void buildArrayIdent(OutBuffer *buf, Expressions *arguments); + Expression *buildArrayLoop(Parameters *fparams); + #if IN_DMD elem *toElemBin(IRState *irs, int op); #endif }; -struct BinAssignExp : BinExp +class BinAssignExp : public BinExp { - BinAssignExp(Loc loc, enum TOK op, int size, Expression *e1, Expression *e2) +public: + BinAssignExp(Loc loc, TOK op, int size, Expression *e1, Expression *e2) : BinExp(loc, op, size, e1, e2) { } @@ -971,6 +1026,9 @@ struct BinAssignExp : BinExp Expression *op_overload(Scope *sc); + void buildArrayIdent(OutBuffer *buf, Expressions *arguments); + Expression *buildArrayLoop(Parameters *fparams); + int isLvalue(); Expression *toLvalue(Scope *sc, Expression *ex); Expression *modifiableLvalue(Scope *sc, Expression *e); @@ -978,22 +1036,25 @@ struct BinAssignExp : BinExp /****************************************************************/ -struct CompileExp : UnaExp +class CompileExp : public UnaExp { +public: CompileExp(Loc loc, Expression *e); Expression *semantic(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); }; -struct FileExp : UnaExp +class FileExp : public UnaExp { +public: FileExp(Loc loc, Expression *e); Expression *semantic(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); }; -struct AssertExp : UnaExp +class AssertExp : public UnaExp { +public: Expression *msg; AssertExp(Loc loc, Expression *e, Expression *msg = NULL); @@ -1009,8 +1070,9 @@ struct AssertExp : UnaExp elem *toElem(IRState *irs); }; -struct DotIdExp : UnaExp +class DotIdExp : public UnaExp { +public: Identifier *ident; DotIdExp(Loc loc, Expression *e, Identifier *ident); @@ -1021,20 +1083,22 @@ struct DotIdExp : UnaExp void dump(int i); }; -struct DotTemplateExp : UnaExp +class DotTemplateExp : public UnaExp { +public: TemplateDeclaration *td; DotTemplateExp(Loc loc, Expression *e, TemplateDeclaration *td); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); }; -struct DotVarExp : UnaExp +class DotVarExp : public UnaExp { +public: Declaration *var; - int hasOverloads; + bool hasOverloads; - DotVarExp(Loc loc, Expression *e, Declaration *var, int hasOverloads = 0); + DotVarExp(Loc loc, Expression *e, Declaration *var, bool hasOverloads = false); Expression *semantic(Scope *sc); int checkModifiable(Scope *sc, int flag); int isLvalue(); @@ -1051,25 +1115,27 @@ struct DotVarExp : UnaExp #endif }; -struct DotTemplateInstanceExp : UnaExp +class DotTemplateInstanceExp : public UnaExp { +public: TemplateInstance *ti; DotTemplateInstanceExp(Loc loc, Expression *e, Identifier *name, Objects *tiargs); Expression *syntaxCopy(); - TemplateDeclaration *getTempdecl(Scope *sc); + bool findTempDecl(Scope *sc); Expression *semantic(Scope *sc); Expression *semanticY(Scope *sc, int flag); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void dump(int indent); }; -struct DelegateExp : UnaExp +class DelegateExp : public UnaExp { +public: FuncDeclaration *func; - int hasOverloads; + bool hasOverloads; - DelegateExp(Loc loc, Expression *e, FuncDeclaration *func, int hasOverloads = 0); + DelegateExp(Loc loc, Expression *e, FuncDeclaration *func, bool hasOverloads = false); Expression *semantic(Scope *sc); Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); MATCH implicitConvTo(Type *t); @@ -1081,8 +1147,9 @@ struct DelegateExp : UnaExp elem *toElem(IRState *irs); }; -struct DotTypeExp : UnaExp +class DotTypeExp : public UnaExp { +public: Dsymbol *sym; // symbol that represents a type DotTypeExp(Loc loc, Expression *e, Dsymbol *sym); @@ -1091,8 +1158,9 @@ struct DotTypeExp : UnaExp elem *toElem(IRState *irs); }; -struct CallExp : UnaExp +class CallExp : public UnaExp { +public: Expressions *arguments; // function arguments FuncDeclaration *f; // symbol to call @@ -1123,8 +1191,9 @@ struct CallExp : UnaExp #endif }; -struct AddrExp : UnaExp +class AddrExp : public UnaExp { +public: AddrExp(Loc loc, Expression *e); Expression *semantic(Scope *sc); void checkEscape(); @@ -1140,8 +1209,9 @@ struct AddrExp : UnaExp #endif }; -struct PtrExp : UnaExp +class PtrExp : public UnaExp { +public: PtrExp(Loc loc, Expression *e); PtrExp(Loc loc, Expression *e, Type *t); Expression *semantic(Scope *sc); @@ -1163,8 +1233,9 @@ struct PtrExp : UnaExp #endif }; -struct NegExp : UnaExp +class NegExp : public UnaExp { +public: NegExp(Loc loc, Expression *e); Expression *semantic(Scope *sc); Expression *optimize(int result, bool keepLvalue = false); @@ -1178,8 +1249,9 @@ struct NegExp : UnaExp elem *toElem(IRState *irs); }; -struct UAddExp : UnaExp +class UAddExp : public UnaExp { +public: UAddExp(Loc loc, Expression *e); Expression *semantic(Scope *sc); @@ -1187,8 +1259,9 @@ struct UAddExp : UnaExp Identifier *opId(); }; -struct ComExp : UnaExp +class ComExp : public UnaExp { +public: ComExp(Loc loc, Expression *e); Expression *semantic(Scope *sc); Expression *optimize(int result, bool keepLvalue = false); @@ -1202,8 +1275,9 @@ struct ComExp : UnaExp elem *toElem(IRState *irs); }; -struct NotExp : UnaExp +class NotExp : public UnaExp { +public: NotExp(Loc loc, Expression *e); Expression *semantic(Scope *sc); Expression *optimize(int result, bool keepLvalue = false); @@ -1211,8 +1285,9 @@ struct NotExp : UnaExp elem *toElem(IRState *irs); }; -struct BoolExp : UnaExp +class BoolExp : public UnaExp { +public: BoolExp(Loc loc, Expression *e, Type *type); Expression *semantic(Scope *sc); Expression *optimize(int result, bool keepLvalue = false); @@ -1220,8 +1295,9 @@ struct BoolExp : UnaExp elem *toElem(IRState *irs); }; -struct DeleteExp : UnaExp +class DeleteExp : public UnaExp { +public: DeleteExp(Loc loc, Expression *e); Expression *semantic(Scope *sc); Expression *checkToBoolean(Scope *sc); @@ -1229,8 +1305,9 @@ struct DeleteExp : UnaExp elem *toElem(IRState *irs); }; -struct CastExp : UnaExp +class CastExp : public UnaExp { +public: // Possible to cast to one type while painting to another type Type *to; // type to cast to unsigned mod; // MODxxxxx @@ -1260,8 +1337,9 @@ struct CastExp : UnaExp #endif }; -struct VectorExp : UnaExp +class VectorExp : public UnaExp { +public: TypeVector *to; // the target vector type before semantic() unsigned dim; // number of elements in the vector @@ -1275,8 +1353,9 @@ struct VectorExp : UnaExp #endif }; -struct SliceExp : UnaExp +class SliceExp : public UnaExp { +public: Expression *upr; // NULL if implicit 0 Expression *lwr; // NULL if implicit [length - 1] VarDeclaration *lengthVar; @@ -1307,8 +1386,9 @@ struct SliceExp : UnaExp Expression *inlineScan(InlineScanState *iss); }; -struct ArrayLengthExp : UnaExp +class ArrayLengthExp : public UnaExp { +public: ArrayLengthExp(Loc loc, Expression *e1); Expression *semantic(Scope *sc); Expression *optimize(int result, bool keepLvalue = false); @@ -1321,8 +1401,9 @@ struct ArrayLengthExp : UnaExp // e1[a0,a1,a2,a3,...] -struct ArrayExp : UnaExp +class ArrayExp : public UnaExp { +public: Expressions *arguments; // Array of Expression's size_t currentDimension; // for opDollar VarDeclaration *lengthVar; @@ -1345,15 +1426,17 @@ struct ArrayExp : UnaExp /****************************************************************/ -struct DotExp : BinExp +class DotExp : public BinExp { +public: DotExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); }; -struct CommaExp : BinExp +class CommaExp : public BinExp { +public: CommaExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); void checkEscape(); @@ -1376,10 +1459,12 @@ struct CommaExp : BinExp #endif }; -struct IndexExp : BinExp +class IndexExp : public BinExp { +public: VarDeclaration *lengthVar; int modifiable; + bool skipboundscheck; IndexExp(Loc loc, Expression *e1, Expression *e2); Expression *syntaxCopy(); @@ -1402,9 +1487,10 @@ struct IndexExp : BinExp /* For both i++ and i-- */ -struct PostExp : BinExp +class PostExp : public BinExp { - PostExp(enum TOK op, Loc loc, Expression *e); +public: + PostExp(TOK op, Loc loc, Expression *e); Expression *semantic(Scope *sc); Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -1414,15 +1500,18 @@ struct PostExp : BinExp /* For both ++i and --i */ -struct PreExp : UnaExp +class PreExp : public UnaExp { - PreExp(enum TOK op, Loc loc, Expression *e); +public: + PreExp(TOK op, Loc loc, Expression *e); Expression *semantic(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); }; -struct AssignExp : BinExp -{ int ismemset; // !=0 if setting the contents of an array +class AssignExp : public BinExp +{ +public: + int ismemset; // !=0 if setting the contents of an array AssignExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); @@ -1438,18 +1527,18 @@ struct AssignExp : BinExp #endif }; -struct ConstructExp : AssignExp +class ConstructExp : public AssignExp { +public: ConstructExp(Loc loc, Expression *e1, Expression *e2); }; #define ASSIGNEXP(op) \ -struct op##AssignExp : BinAssignExp \ +class op##AssignExp : public BinAssignExp \ { \ +public: \ op##AssignExp(Loc loc, Expression *e1, Expression *e2); \ S(Expression *semantic(Scope *sc);) \ - X(void buildArrayIdent(OutBuffer *buf, Expressions *arguments);) \ - X(Expression *buildArrayLoop(Parameters *fparams);) \ \ Identifier *opId(); /* For operator overloading */ \ \ @@ -1492,13 +1581,12 @@ ASSIGNEXP(Cat) #undef X #undef ASSIGNEXP -struct AddExp : BinExp +class AddExp : public BinExp { +public: AddExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result, bool keepLvalue = false); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); IntRange getIntRange(); // For operator overloading @@ -1513,13 +1601,12 @@ struct AddExp : BinExp #endif }; -struct MinExp : BinExp +class MinExp : public BinExp { +public: MinExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result, bool keepLvalue = false); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); IntRange getIntRange(); // For operator overloading @@ -1533,8 +1620,9 @@ struct MinExp : BinExp #endif }; -struct CatExp : BinExp +class CatExp : public BinExp { +public: CatExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result, bool keepLvalue = false); @@ -1547,13 +1635,12 @@ struct CatExp : BinExp elem *toElem(IRState *irs); }; -struct MulExp : BinExp +class MulExp : public BinExp { +public: MulExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result, bool keepLvalue = false); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); IntRange getIntRange(); // For operator overloading @@ -1564,13 +1651,12 @@ struct MulExp : BinExp elem *toElem(IRState *irs); }; -struct DivExp : BinExp +class DivExp : public BinExp { +public: DivExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result, bool keepLvalue = false); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); IntRange getIntRange(); // For operator overloading @@ -1580,13 +1666,12 @@ struct DivExp : BinExp elem *toElem(IRState *irs); }; -struct ModExp : BinExp +class ModExp : public BinExp { +public: ModExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result, bool keepLvalue = false); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); IntRange getIntRange(); // For operator overloading @@ -1597,13 +1682,12 @@ struct ModExp : BinExp }; #if DMDV2 -struct PowExp : BinExp +class PowExp : public BinExp { +public: PowExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result, bool keepLvalue = false); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); // For operator overloading Identifier *opId(); @@ -1613,8 +1697,9 @@ struct PowExp : BinExp }; #endif -struct ShlExp : BinExp +class ShlExp : public BinExp { +public: ShlExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result, bool keepLvalue = false); @@ -1627,8 +1712,9 @@ struct ShlExp : BinExp elem *toElem(IRState *irs); }; -struct ShrExp : BinExp +class ShrExp : public BinExp { +public: ShrExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result, bool keepLvalue = false); @@ -1641,8 +1727,9 @@ struct ShrExp : BinExp elem *toElem(IRState *irs); }; -struct UshrExp : BinExp +class UshrExp : public BinExp { +public: UshrExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result, bool keepLvalue = false); @@ -1655,13 +1742,12 @@ struct UshrExp : BinExp elem *toElem(IRState *irs); }; -struct AndExp : BinExp +class AndExp : public BinExp { +public: AndExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result, bool keepLvalue = false); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); IntRange getIntRange(); // For operator overloading @@ -1672,13 +1758,12 @@ struct AndExp : BinExp elem *toElem(IRState *irs); }; -struct OrExp : BinExp +class OrExp : public BinExp { +public: OrExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result, bool keepLvalue = false); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); MATCH implicitConvTo(Type *t); IntRange getIntRange(); @@ -1690,13 +1775,12 @@ struct OrExp : BinExp elem *toElem(IRState *irs); }; -struct XorExp : BinExp +class XorExp : public BinExp { +public: XorExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result, bool keepLvalue = false); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); MATCH implicitConvTo(Type *t); IntRange getIntRange(); @@ -1708,8 +1792,9 @@ struct XorExp : BinExp elem *toElem(IRState *irs); }; -struct OrOrExp : BinExp +class OrOrExp : public BinExp { +public: OrOrExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *checkToBoolean(Scope *sc); @@ -1719,8 +1804,9 @@ struct OrOrExp : BinExp elem *toElem(IRState *irs); }; -struct AndAndExp : BinExp +class AndAndExp : public BinExp { +public: AndAndExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *checkToBoolean(Scope *sc); @@ -1730,9 +1816,10 @@ struct AndAndExp : BinExp elem *toElem(IRState *irs); }; -struct CmpExp : BinExp +class CmpExp : public BinExp { - CmpExp(enum TOK op, Loc loc, Expression *e1, Expression *e2); +public: + CmpExp(TOK op, Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result, bool keepLvalue = false); int isBit(); @@ -1745,8 +1832,9 @@ struct CmpExp : BinExp elem *toElem(IRState *irs); }; -struct InExp : BinExp +class InExp : public BinExp { +public: InExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); @@ -1759,8 +1847,9 @@ struct InExp : BinExp elem *toElem(IRState *irs); }; -struct RemoveExp : BinExp +class RemoveExp : public BinExp { +public: RemoveExp(Loc loc, Expression *e1, Expression *e2); Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -1769,9 +1858,10 @@ struct RemoveExp : BinExp // == and != -struct EqualExp : BinExp +class EqualExp : public BinExp { - EqualExp(enum TOK op, Loc loc, Expression *e1, Expression *e2); +public: + EqualExp(TOK op, Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result, bool keepLvalue = false); int isBit(); @@ -1786,9 +1876,10 @@ struct EqualExp : BinExp // is and !is -struct IdentityExp : BinExp +class IdentityExp : public BinExp { - IdentityExp(enum TOK op, Loc loc, Expression *e1, Expression *e2); +public: + IdentityExp(TOK op, Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); int isBit(); Expression *optimize(int result, bool keepLvalue = false); @@ -1797,8 +1888,9 @@ struct IdentityExp : BinExp /****************************************************************/ -struct CondExp : BinExp +class CondExp : public BinExp { +public: Expression *econd; CondExp(Loc loc, Expression *econd, Expression *e1, Expression *e2); @@ -1828,44 +1920,50 @@ struct CondExp : BinExp #if DMDV2 /****************************************************************/ -struct DefaultInitExp : Expression +class DefaultInitExp : public Expression { - enum TOK subop; // which of the derived classes this is +public: + TOK subop; // which of the derived classes this is - DefaultInitExp(Loc loc, enum TOK subop, int size); + DefaultInitExp(Loc loc, TOK subop, int size); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); }; -struct FileInitExp : DefaultInitExp +class FileInitExp : public DefaultInitExp { +public: FileInitExp(Loc loc); Expression *semantic(Scope *sc); Expression *resolveLoc(Loc loc, Scope *sc); }; -struct LineInitExp : DefaultInitExp +class LineInitExp : public DefaultInitExp { +public: LineInitExp(Loc loc); Expression *semantic(Scope *sc); Expression *resolveLoc(Loc loc, Scope *sc); }; -struct ModuleInitExp : DefaultInitExp +class ModuleInitExp : public DefaultInitExp { +public: ModuleInitExp(Loc loc); Expression *semantic(Scope *sc); Expression *resolveLoc(Loc loc, Scope *sc); }; -struct FuncInitExp : DefaultInitExp +class FuncInitExp : public DefaultInitExp { +public: FuncInitExp(Loc loc); Expression *semantic(Scope *sc); Expression *resolveLoc(Loc loc, Scope *sc); }; -struct PrettyFuncInitExp : DefaultInitExp +class PrettyFuncInitExp : public DefaultInitExp { +public: PrettyFuncInitExp(Loc loc); Expression *semantic(Scope *sc); Expression *resolveLoc(Loc loc, Scope *sc); @@ -1928,9 +2026,9 @@ Expression *Xor(Type *type, Expression *e1, Expression *e2); Expression *Index(Type *type, Expression *e1, Expression *e2); Expression *Cat(Type *type, Expression *e1, Expression *e2); -Expression *Equal(enum TOK op, Type *type, Expression *e1, Expression *e2); -Expression *Cmp(enum TOK op, Type *type, Expression *e1, Expression *e2); -Expression *Identity(enum TOK op, Type *type, Expression *e1, Expression *e2); +Expression *Equal(TOK op, Type *type, Expression *e1, Expression *e2); +Expression *Cmp(TOK op, Type *type, Expression *e1, Expression *e2); +Expression *Identity(TOK op, Type *type, Expression *e1, Expression *e2); Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr); diff --git a/dmd2/func.c b/dmd2/func.c index db81f48e..bd96ea88 100644 --- a/dmd2/func.c +++ b/dmd2/func.c @@ -1,5 +1,5 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars +// Copyright (c) 1999-2013 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -25,8 +25,10 @@ #include "template.h" #include "hdrgen.h" #include "target.h" +#include "parse.h" void functionToCBuffer2(TypeFunction *t, OutBuffer *buf, HdrGenState *hgs, int mod, const char *kind); +void genCmain(Scope *sc); /********************************* FuncDeclaration ****************************/ @@ -64,15 +66,16 @@ FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, StorageCla parameters = NULL; labtab = NULL; overnext = NULL; + overnext0 = NULL; vtblIndex = -1; hasReturnExp = 0; naked = 0; inlineStatusExp = ILSuninitialized; inlineStatusStmt = ILSuninitialized; inlineNest = 0; + ctfeCode = NULL; isArrayOp = 0; dArrayOp = NULL; - semanticRun = PASSinit; semantic3Errors = 0; #if DMDV1 nestedFrameRef = 0; @@ -163,7 +166,6 @@ void FuncDeclaration::semantic(Scope *sc) StructDeclaration *sd; ClassDeclaration *cd; InterfaceDeclaration *id; - Dsymbol *pd; bool doesoverride; #if 0 @@ -184,25 +186,17 @@ void FuncDeclaration::semantic(Scope *sc) return; } + if (semanticRun >= PASSsemanticdone) + return; + assert(semanticRun <= PASSsemantic); + semanticRun = PASSsemantic; + parent = sc->parent; Dsymbol *parent = toParent(); - if (semanticRun >= PASSsemanticdone) - { - if (!parent->isClassDeclaration()) - { - return; - } - // need to re-run semantic() in order to set the class's vtbl[] - } - else - { - assert(semanticRun <= PASSsemantic); - semanticRun = PASSsemantic; - } - if (scope) - { sc = scope; + { + sc = scope; scope = NULL; } @@ -386,9 +380,14 @@ void FuncDeclaration::semantic(Scope *sc) } if (isOverride() && !isVirtual()) - error("cannot override a non-virtual function"); + { + if ((prot() == PROTprivate || prot() == PROTpackage) && isMember()) + error("%s method is not virtual and cannot override", Pprotectionnames[prot()]); + else + error("cannot override a non-virtual function"); + } - if (isAbstract() && isFinal()) + if (isAbstract() && isFinalFunc()) error("cannot be both final and abstract"); #if 0 if (isAbstract() && fbody) @@ -463,10 +462,8 @@ void FuncDeclaration::semantic(Scope *sc) cd = parent->isClassDeclaration(); if (cd) - { size_t vi; - CtorDeclaration *ctor; - DtorDeclaration *dtor; - + { + size_t vi; if (isCtorDeclaration()) { // ctor = (CtorDeclaration *)this; @@ -475,34 +472,6 @@ void FuncDeclaration::semantic(Scope *sc) goto Ldone; } -#if 0 - dtor = isDtorDeclaration(); - if (dtor) - { - if (cd->dtor) - error("multiple destructors for class %s", cd->toChars()); - cd->dtor = dtor; - } - - if (isInvariantDeclaration()) - { - cd->invs.push(this); - } - - if (isNewDeclaration()) - { - if (!cd->aggNew) - cd->aggNew = (NewDeclaration *)(this); - } - - if (isDelete()) - { - if (cd->aggDelete) - error("multiple delete's for class %s", cd->toChars()); - cd->aggDelete = (DeleteDeclaration *)(this); - } -#endif - if (storage_class & STCabstract) cd->isabstract = 1; @@ -516,19 +485,33 @@ void FuncDeclaration::semantic(Scope *sc) if (type->nextOf() == Type::terror) goto Ldone; - if (cd->baseClass) + bool may_override = false; + for (size_t i = 0; i < cd->baseclasses->dim; i++) { - Dsymbol *cbd = cd->baseClass; - if (cbd->parent && cbd->parent->isTemplateInstance()) + BaseClass *b = (*cd->baseclasses)[i]; + ClassDeclaration *cbd = b->type->toBasetype()->isClassHandle(); + if (!cbd) + continue; + for (size_t j = 0; j < cbd->vtbl.dim; j++) { - for (size_t i = 0; i < cd->baseClass->vtbl.dim; i++) + FuncDeclaration *f = cbd->vtbl[j]->isFuncDeclaration(); + if (!f || f->ident != ident) + continue; + if (cbd->parent && cbd->parent->isTemplateInstance()) { - FuncDeclaration *f = cd->baseClass->vtbl[i]->isFuncDeclaration(); - if (f && f->ident == ident && !f->functionSemantic()) + if (!f->functionSemantic()) goto Ldone; } + may_override = true; } } + if (may_override && type->nextOf() == NULL) + { + /* If same name function exists in base class but 'this' is auto return, + * cannot find index of base class's vtbl[] to override. + */ + error("return type inference is not supported if may override base class function"); + } /* Find index of existing function in base class's vtbl[] to override * (the index will be the same as in cd's current vtbl[]) @@ -539,7 +522,7 @@ void FuncDeclaration::semantic(Scope *sc) doesoverride = FALSE; switch (vi) { - case -1: + case (size_t)-1: Lintro: /* Didn't find one, so * This is an 'introducing' function which gets a new @@ -555,13 +538,13 @@ void FuncDeclaration::semantic(Scope *sc) if (f) { f = f->overloadExactMatch(type); - if (f && f->isFinal() && f->prot() != PROTprivate) + if (f && f->isFinalFunc() && f->prot() != PROTprivate) error("cannot override final function %s", f->toPrettyChars()); } } } - if (isFinal()) + if (isFinalFunc()) { // Don't check here, as it may override an interface function //if (isOverride()) @@ -579,7 +562,7 @@ void FuncDeclaration::semantic(Scope *sc) } break; - case -2: // can't determine because of fwd refs + case (size_t)-2: // can't determine because of fwd refs cd->sizeok = SIZEOKfwd; // can't finish due to forward reference Module::dprogress = dprogress_save; return; @@ -589,6 +572,12 @@ void FuncDeclaration::semantic(Scope *sc) FuncDeclaration *fdc = cd->vtbl[vi]->isFuncDeclaration(); // This function is covariant with fdv + if (fdc == this) + { + doesoverride = TRUE; + break; + } + if (fdc->toParent() == parent) { //printf("vi = %d,\tthis = %p %s %s @ [%s]\n\tfdc = %p %s %s @ [%s]\n\tfdv = %p %s %s @ [%s]\n", @@ -602,7 +591,7 @@ void FuncDeclaration::semantic(Scope *sc) } // This function overrides fdv - if (fdv->isFinal()) + if (fdv->isFinalFunc()) error("cannot override final function %s", fdv->toPrettyChars()); doesoverride = TRUE; @@ -668,10 +657,10 @@ void FuncDeclaration::semantic(Scope *sc) vi = findVtblIndex((Dsymbols *)&b->base->vtbl, b->base->vtbl.dim); switch (vi) { - case -1: + case (size_t)-1: break; - case -2: + case (size_t)-2: cd->sizeok = SIZEOKfwd; // can't finish due to forward reference Module::dprogress = dprogress_save; return; @@ -735,7 +724,7 @@ void FuncDeclaration::semantic(Scope *sc) } } - if (!doesoverride && isOverride()) + if (!doesoverride && isOverride() && type->nextOf()) { Dsymbol *s = NULL; for (size_t i = 0; i < cd->baseclasses->dim; i++) @@ -767,7 +756,7 @@ void FuncDeclaration::semantic(Scope *sc) if (f) { f = f->overloadExactMatch(type); - if (f && f->isFinal() && f->prot() != PROTprivate) + if (f && f->isFinalFunc() && f->prot() != PROTprivate) error("cannot override final function %s.%s", b->base->toChars(), f->toPrettyChars()); } } @@ -777,6 +766,10 @@ void FuncDeclaration::semantic(Scope *sc) else if (isOverride() && !parent->isTemplateInstance()) error("override only applies to class member functions"); + // Reflect this->type to f because it could be changed by findVtblIndex + assert(type->ty == Tfunction); + f = (TypeFunction *)type; + /* Do not allow template instances to add virtual functions * to a class. */ @@ -859,7 +852,7 @@ void FuncDeclaration::semantic(Scope *sc) */ fdrequireParams = new Expressions(); Parameters *params = outToRef(((TypeFunction*)type)->parameters); - Type *tf = new TypeFunction(params, Type::tvoid, 0, LINKd); + TypeFunction *tf = new TypeFunction(params, Type::tvoid, 0, LINKd); #else /* in { ... } * becomes: @@ -869,6 +862,9 @@ void FuncDeclaration::semantic(Scope *sc) TypeFunction *tf = new TypeFunction(NULL, Type::tvoid, 0, LINKd); #endif Loc loc = frequire->loc; + tf->isnothrow = f->isnothrow; + tf->purity = f->purity; + tf->trust = f->trust; FuncDeclaration *fd = new FuncDeclaration(loc, loc, Id::require, STCundefined, tf); fd->fbody = frequire; @@ -904,7 +900,7 @@ void FuncDeclaration::semantic(Scope *sc) #else /* out (result) { ... } * becomes: - * tret __ensure(ref tret result) { ... } + * void __ensure(ref tret result) { ... } * __ensure(result); */ Parameters *arguments = new Parameters(); @@ -916,6 +912,9 @@ void FuncDeclaration::semantic(Scope *sc) arguments->insert(0, a); } TypeFunction *tf = new TypeFunction(arguments, Type::tvoid, 0, LINKd); + tf->isnothrow = f->isnothrow; + tf->purity = f->purity; + tf->trust = f->trust; FuncDeclaration *fd = new FuncDeclaration(loc, loc, Id::ensure, STCundefined, tf); fd->fbody = fensure; @@ -976,10 +975,13 @@ Ldone: { printedMain = true; const char *name = FileName::searchPath(global.path, mod->srcfile->toChars(), 1); - printf("%-10s%-10s\t%s\n", "entry", type, name); + printf("entry %-10s\t%s\n", type, name); } } + if (fbody && isMain() && sc->module->isRoot()) + genCmain(sc); + return; } @@ -1061,7 +1063,7 @@ void FuncDeclaration::semantic3(Scope *sc) } frequire = mergeFrequire(frequire); - fensure = mergeFensure(fensure); + fensure = mergeFensure(fensure, outId); if (fbody || frequire || fensure) { @@ -1101,6 +1103,8 @@ void FuncDeclaration::semantic3(Scope *sc) sc2->speculative = sc->speculative || isSpeculative() != NULL; sc2->userAttributes = NULL; if (sc2->intypeof == 1) sc2->intypeof = 2; + sc2->fieldinit = NULL; + sc2->fieldinit_dim = 0; // Declare 'this' AggregateDeclaration *ad = isThis(); @@ -1150,7 +1154,7 @@ void FuncDeclaration::semantic3(Scope *sc) v_arguments->parent = this; //t = Type::typeinfo->type->constOf()->arrayOf(); - t = Type::typeinfo->type->arrayOf(); + t = Type::dtypeinfo->type->arrayOf(); _arguments = new VarDeclaration(Loc(), t, Id::_arguments, NULL); _arguments->semantic(sc2); sc2->insert(_arguments); @@ -1278,7 +1282,7 @@ void FuncDeclaration::semantic3(Scope *sc) assert(arg->ident); TupleDeclaration *v = new TupleDeclaration(loc, arg->ident, exps); //printf("declaring tuple %s\n", v->toChars()); - v->isexp = 1; + v->isexp = true; if (!sc2->insert(v)) error("parameter %s.%s is already defined", toChars(), v->toChars()); localsymtab->insert(v); @@ -1402,10 +1406,13 @@ void FuncDeclaration::semantic3(Scope *sc) */ if (ad && isCtorDeclaration()) { + sc2->fieldinit = new unsigned[ad->fields.dim]; + sc2->fieldinit_dim = ad->fields.dim; for (size_t i = 0; i < ad->fields.dim; i++) - { VarDeclaration *v = ad->fields[i]; - + { + VarDeclaration *v = ad->fields[i]; v->ctorinit = 0; + sc2->fieldinit[i] = 0; } } @@ -1417,26 +1424,31 @@ void FuncDeclaration::semantic3(Scope *sc) fbody = new CompoundStatement(Loc(), new Statements()); if (inferRetType) - { // If no return type inferred yet, then infer a void + { + // If no return type inferred yet, then infer a void if (!type->nextOf()) { f->next = Type::tvoid; //type = type->semantic(loc, sc); // Removed with 6902 } - else if (returns && f->next->ty != Tvoid) - { - for (size_t i = 0; i < returns->dim; i++) - { Expression *exp = (*returns)[i]->exp; - if (!f->next->invariantOf()->equals(exp->type->invariantOf())) - { exp = exp->castTo(sc2, f->next); - exp = exp->optimize(WANTvalue); - (*returns)[i]->exp = exp; - } - //printf("[%d] %s %s\n", i, exp->type->toChars(), exp->toChars()); - } - } - assert(type == f); } + if (returns && f->next->ty != Tvoid) + { + for (size_t i = 0; i < returns->dim; i++) + { + Expression *exp = (*returns)[i]->exp; + if (!nrvo_can && !f->isref && exp->isLvalue()) + exp = callCpCtor(sc2, exp); + if (!tintro && !f->next->immutableOf()->equals(exp->type->immutableOf())) + { + exp = exp->castTo(sc2, f->next); + exp = exp->optimize(WANTvalue); + } + //printf("[%d] %s %s\n", i, exp->type->toChars(), exp->toChars()); + (*returns)[i]->exp = exp; + } + } + assert(type == f); if (isStaticCtorDeclaration()) { /* It's a static constructor. Ensure that all @@ -1459,14 +1471,16 @@ void FuncDeclaration::semantic3(Scope *sc) } } - if (isCtorDeclaration() && ad) + if (fbody->isErrorStatement()) + ; + else if (isCtorDeclaration() && ad) { #if DMDV2 // Check for errors related to 'nothrow'. int nothrowErrors = global.errors; int blockexit = fbody->blockExit(f->isnothrow); if (f->isnothrow && (global.errors != nothrowErrors) ) - error("'%s' is nothrow yet may throw", toChars()); + ::error(loc, "%s '%s' is nothrow yet may throw", kind(), toPrettyChars()); if (flags & FUNCFLAGnothrowInprocess) f->isnothrow = !(blockexit & BEthrow); #endif @@ -1495,8 +1509,20 @@ void FuncDeclaration::semantic3(Scope *sc) else if (v->type->needsNested()) error("field %s must be initialized in constructor, because it is nested struct", v->toChars()); } + else + { + bool mustInit = (v->storage_class & STCnodefaultctor || + v->type->needsNested()); + if (mustInit && !(sc2->fieldinit[i] & CSXthis_ctor)) + { + error("field %s must be initialized but skipped", v->toChars()); + } + } } } + delete[] sc2->fieldinit; + sc2->fieldinit = NULL; + sc2->fieldinit_dim = 0; if (cd && !(sc2->callSuper & CSXany_ctor) && @@ -1554,10 +1580,10 @@ void FuncDeclaration::semantic3(Scope *sc) int nothrowErrors = global.errors; int blockexit = fbody->blockExit(f->isnothrow); if (f->isnothrow && (global.errors != nothrowErrors) ) - error("'%s' is nothrow yet may throw", toChars()); + ::error(loc, "%s '%s' is nothrow yet may throw", kind(), toPrettyChars()); if (flags & FUNCFLAGnothrowInprocess) { - if (type == f) f = f->copy(); + if (type == f) f = (TypeFunction *)f->copy(); f->isnothrow = !(blockexit & BEthrow); } @@ -1638,6 +1664,12 @@ void FuncDeclaration::semantic3(Scope *sc) // BUG: need to treat parameters as const // BUG: need to disallow returns and throws + if (inferRetType && fdensure && ((TypeFunction *)fdensure->type)->parameters) + { + // Return type was unknown in the first semantic pass + Parameter *p = (*((TypeFunction *)fdensure->type)->parameters)[0]; + p->type = ((TypeFunction *)type)->nextOf(); + } fens = fens->semantic(sc2); sc2 = sc2->pop(); @@ -1846,7 +1878,7 @@ void FuncDeclaration::semantic3(Scope *sc) bool isnothrow = f->isnothrow & !(flags & FUNCFLAGnothrowInprocess); int blockexit = s->blockExit(isnothrow); if (f->isnothrow && (global.errors != nothrowErrors) ) - error("'%s' is nothrow yet may throw", toChars()); + ::error(loc, "%s '%s' is nothrow yet may throw", kind(), toPrettyChars()); if (flags & FUNCFLAGnothrowInprocess && blockexit & BEthrow) f->isnothrow = FALSE; if (fbody->blockExit(f->isnothrow) == BEfallthru) @@ -1908,14 +1940,14 @@ void FuncDeclaration::semantic3(Scope *sc) if (flags & FUNCFLAGpurityInprocess) { flags &= ~FUNCFLAGpurityInprocess; - if (type == f) f = f->copy(); + if (type == f) f = (TypeFunction *)f->copy(); f->purity = PUREfwdref; } if (flags & FUNCFLAGsafetyInprocess) { flags &= ~FUNCFLAGsafetyInprocess; - if (type == f) f = f->copy(); + if (type == f) f = (TypeFunction *)f->copy(); f->trust = TRUSTsafe; } @@ -1955,7 +1987,10 @@ void FuncDeclaration::semantic3(Scope *sc) bool FuncDeclaration::functionSemantic() { - if (scope && !originalType) // semantic not yet run + if (!scope) + return true; + + if (!originalType) // semantic not yet run { TemplateInstance *spec = isSpeculative(); unsigned olderrs = global.errors; @@ -1971,14 +2006,26 @@ bool FuncDeclaration::functionSemantic() } // if inferring return type, sematic3 needs to be run - TemplateInstance *ti; - AggregateDeclaration *ad; - if (scope && - (inferRetType && type && !type->nextOf() || - (ti = parent->isTemplateInstance()) != NULL && !ti->isTemplateMixin() && ti->name == ident || - (ad = isThis()) != NULL && ad->parent && ad->parent->isTemplateInstance() && !isVirtualMethod())) - { + if (inferRetType && type && !type->nextOf()) return functionSemantic3(); + + TemplateInstance *ti = parent->isTemplateInstance(); + if (ti && !ti->isTemplateMixin() && ti->name == ident) + return functionSemantic3(); + + AggregateDeclaration *ad = isThis(); + if (ad && ad->parent && ad->parent->isTemplateInstance() && !isVirtualMethod()) + { + if (ad->sizeok != SIZEOKdone) + { + /* Currently dmd cannot resolve forward references per methods, + * then setting SIZOKfwd is too conservative and would break existing code. + * So, just stop method attributes inference until ad->semantic() done. + */ + //ad->sizeok = SIZEOKfwd; + } + else + return functionSemantic3(); } return true; @@ -2081,24 +2128,38 @@ VarDeclaration *FuncDeclaration::declareThis(Scope *sc, AggregateDeclaration *ad return NULL; } -int FuncDeclaration::equals(Object *o) +bool FuncDeclaration::equals(RootObject *o) { if (this == o) - return TRUE; + return true; Dsymbol *s = isDsymbol(o); if (s) { - FuncDeclaration *fd1 = this->toAliasFunc(); + FuncDeclaration *fd1 = this; FuncDeclaration *fd2 = s->isFuncDeclaration(); - if (fd2) + if (!fd2) + return false; + + FuncAliasDeclaration *fa1 = fd1->isFuncAliasDeclaration(); + FuncAliasDeclaration *fa2 = fd2->isFuncAliasDeclaration(); + if (fa1 && fa2) { - fd2 = fd2->toAliasFunc(); - return fd1->toParent()->equals(fd2->toParent()) && - fd1->ident->equals(fd2->ident) && fd1->type->equals(fd2->type); + return fa1->toAliasFunc()->equals(fa2->toAliasFunc()) && + fa1->hasOverloads == fa2->hasOverloads; } + + if (fa1 && (fd1 = fa1->toAliasFunc())->isUnique() && !fa1->hasOverloads) + fa1 = NULL; + if (fa2 && (fd2 = fa2->toAliasFunc())->isUnique() && !fa2->hasOverloads) + fa2 = NULL; + if ((fa1 != NULL) != (fa2 != NULL)) + return false; + + return fd1->toParent()->equals(fd2->toParent()) && + fd1->ident->equals(fd2->ident) && fd1->type->equals(fd2->type); } - return FALSE; + return false; } void FuncDeclaration::bodyToCBuffer(OutBuffer *buf, HdrGenState *hgs) @@ -2296,7 +2357,11 @@ Statement *FuncDeclaration::mergeFrequire(Statement *sf, Expressions *params) * 'out's are AND'd together, i.e. all of them need to pass. */ -Statement *FuncDeclaration::mergeFensure(Statement *sf, Expressions *params) +#if IN_LLVM +Statement *FuncDeclaration::mergeFensure(Statement *sf, Identifier *oid, Expressions *params) +#else +Statement *FuncDeclaration::mergeFensure(Statement *sf, Identifier *oid) +#endif { if (!params) params = fdensureParams; @@ -2326,7 +2391,7 @@ Statement *FuncDeclaration::mergeFensure(Statement *sf, Expressions *params) sc->pop(); } - sf = fdv->mergeFensure(sf, params); + sf = fdv->mergeFensure(sf, oid, params); if (fdv->fdensure) { //printf("fdv->fensure: %s\n", fdv->fensure->toChars()); @@ -2337,8 +2402,9 @@ Statement *FuncDeclaration::mergeFensure(Statement *sf, Expressions *params) #if IN_LLVM eresult = (*params)[0]; #else - eresult = new IdentifierExp(loc, outId); + eresult = new IdentifierExp(loc, oid); #endif + Type *t1 = fdv->type->nextOf()->toBasetype(); #if IN_LLVM // We actually check for matching types in CommaExp::toElem, @@ -2346,12 +2412,11 @@ Statement *FuncDeclaration::mergeFensure(Statement *sf, Expressions *params) t1 = t1->constOf(); #endif Type *t2 = this->type->nextOf()->toBasetype(); - int offset; - if (t1->isBaseOf(t2, &offset) && offset != 0) + if (t1->isBaseOf(t2, NULL)) { /* Making temporary reference variable is necessary - * to match offset difference in covariant return. - * See bugzilla 5204. + * in covariant return. + * See bugzilla 5204 and 10479. */ ExpInitializer *ei = new ExpInitializer(Loc(), eresult); VarDeclaration *v = new VarDeclaration(Loc(), t1, Lexer::uniqueId("__covres"), ei); @@ -2371,7 +2436,7 @@ Statement *FuncDeclaration::mergeFensure(Statement *sf, Expressions *params) if (sf) { - sf = new CompoundStatement(fensure->loc, s2, sf); + sf = new CompoundStatement(sf->loc, s2, sf); } else sf = s2; @@ -2476,19 +2541,16 @@ int FuncDeclaration::findVtblIndex(Dsymbols *vtbl, int dim) type = type->addStorageClass(mismatchstc); bestvi = mismatchvi; } - else - error("of type %s overrides but is not covariant with %s of type %s", - type->toChars(), mismatch->toPrettyChars(), mismatch->type->toChars()); } return bestvi; } /**************************************************** * Overload this FuncDeclaration with the new one f. - * Return !=0 if successful; i.e. no conflict. + * Return true if successful; i.e. no conflict. */ -int FuncDeclaration::overloadInsert(Dsymbol *s) +bool FuncDeclaration::overloadInsert(Dsymbol *s) { //printf("FuncDeclaration::overloadInsert(s = %s) this = %s\n", s->toChars(), toChars()); AliasDeclaration *ad = s->isAliasDeclaration(); @@ -2499,15 +2561,23 @@ int FuncDeclaration::overloadInsert(Dsymbol *s) if (!ad->aliassym && ad->type->ty != Tident && ad->type->ty != Tinstance) { //printf("\tad = '%s'\n", ad->type->toChars()); - return FALSE; + return false; } overnext = ad; //printf("\ttrue: no conflict\n"); + return true; + } + TemplateDeclaration *td = s->isTemplateDeclaration(); + if (td) + { + if (overnext) + return overnext->overloadInsert(td); + overnext = td; return TRUE; } FuncDeclaration *fd = s->isFuncDeclaration(); if (!fd) - return FALSE; + return false; #if 0 /* Disable this check because: @@ -2530,80 +2600,78 @@ int FuncDeclaration::overloadInsert(Dsymbol *s) #endif if (overnext) - return overnext->overloadInsert(fd); + { + td = overnext->isTemplateDeclaration(); + if (td) + fd->overloadInsert(td); + else + return overnext->overloadInsert(fd); + } overnext = fd; //printf("\ttrue: no conflict\n"); - return TRUE; + return true; } -/******************************************** - * Find function in overload list that exactly matches t. - */ - /*************************************************** - * Visit each overloaded function in turn, and call - * (*fp)(param, f) on it. - * Exit when no more, or (*fp)(param, f) returns 1. + * Visit each overloaded function/template in turn, and call + * (*fp)(param, s) on it. + * Exit when no more, or (*fp)(param, f) returns nonzero. * Returns: - * 0 continue - * 1 done + * ==0 continue + * !=0 done */ -int overloadApply(FuncDeclaration *fstart, - int (*fp)(void *, FuncDeclaration *), - void *param) +int overloadApply(Dsymbol *fstart, void *param, int (*fp)(void *, Dsymbol *)) { - FuncDeclaration *f; - Declaration *d; - Declaration *next; - + Dsymbol *d; + Dsymbol *next; for (d = fstart; d; d = next) - { FuncAliasDeclaration *fa = d->isFuncAliasDeclaration(); - - if (fa) + { + if (FuncAliasDeclaration *fa = d->isFuncAliasDeclaration()) { if (fa->hasOverloads) { - if (overloadApply(fa->funcalias, fp, param)) - return 1; + if (int r = overloadApply(fa->funcalias, param, fp)) + return r; } else { - f = fa->toAliasFunc(); - if (!f) - { d->error("is aliased to a function"); + FuncDeclaration *fd = fa->toAliasFunc(); + if (!fd) + { + d->error("is aliased to a function"); break; } - if ((*fp)(param, f)) - return 1; + if (int r = (*fp)(param, fd)) + return r; } next = fa->overnext; } + else if (AliasDeclaration *ad = d->isAliasDeclaration()) + { + next = ad->toAlias(); + if (next == ad) + break; + if (next == fstart) + break; + } + else if (TemplateDeclaration *td = d->isTemplateDeclaration()) + { + if (int r = (*fp)(param, td)) + return r; + next = td->overnext; + } else { - AliasDeclaration *a = d->isAliasDeclaration(); - - if (a) + FuncDeclaration *fd = d->isFuncDeclaration(); + if (!fd) { - Dsymbol *s = a->toAlias(); - next = s->isDeclaration(); - if (next == a) - break; - if (next == fstart) - break; - } - else - { - f = d->isFuncDeclaration(); - if (!f) - { d->error("is aliased to a function"); - break; // BUG: should print error message? - } - if ((*fp)(param, f)) - return 1; - - next = f->overnext; + d->error("is aliased to a function"); + break; // BUG: should print error message? } + if (int r = (*fp)(param, fd)) + return r; + next = fd->overnext; } } return 0; @@ -2614,23 +2682,31 @@ int overloadApply(FuncDeclaration *fstart, * otherwise return NULL. */ -static int fpunique(void *param, FuncDeclaration *f) -{ FuncDeclaration **pf = (FuncDeclaration **)param; - - if (*pf) - { *pf = NULL; - return 1; // ambiguous, done - } - else - { *pf = f; - return 0; - } -} - FuncDeclaration *FuncDeclaration::isUnique() -{ FuncDeclaration *result = NULL; +{ + struct ParamUnique + { + static int fp(void *param, Dsymbol *s) + { + FuncDeclaration *f = s->isFuncDeclaration(); + if (!f) + return 0; + FuncDeclaration **pf = (FuncDeclaration **)param; - overloadApply(this, &fpunique, &result); + if (*pf) + { + *pf = NULL; + return 1; // ambiguous, done + } + else + { + *pf = f; + return 0; + } + } + }; + FuncDeclaration *result = NULL; + overloadApply(this, &result, &ParamUnique::fp); return result; } @@ -2638,183 +2714,52 @@ FuncDeclaration *FuncDeclaration::isUnique() * Find function in overload list that exactly matches t. */ -struct Param1 +FuncDeclaration *FuncDeclaration::overloadExactMatch(Type *t) { + struct ParamExact + { Type *t; // type to match FuncDeclaration *f; // return value -}; -int fp1(void *param, FuncDeclaration *f) -{ Param1 *p = (Param1 *)param; - Type *t = p->t; + static int fp(void *param, Dsymbol *s) + { + FuncDeclaration *f = s->isFuncDeclaration(); + if (!f) + return 0; + ParamExact *p = (ParamExact *)param; + Type *t = p->t; - if (t->equals(f->type)) - { p->f = f; - return 1; - } - -#if DMDV2 - /* Allow covariant matches, as long as the return type - * is just a const conversion. - * This allows things like pure functions to match with an impure function type. - */ - if (t->ty == Tfunction) - { TypeFunction *tf = (TypeFunction *)f->type; - if (tf->covariant(t) == 1 && - tf->nextOf()->implicitConvTo(t->nextOf()) >= MATCHconst) + if (t->equals(f->type)) { p->f = f; return 1; } - } -#endif - return 0; -} -FuncDeclaration *FuncDeclaration::overloadExactMatch(Type *t) -{ - Param1 p; +#if DMDV2 + /* Allow covariant matches, as long as the return type + * is just a const conversion. + * This allows things like pure functions to match with an impure function type. + */ + if (t->ty == Tfunction) + { TypeFunction *tf = (TypeFunction *)f->type; + if (tf->covariant(t) == 1 && + tf->nextOf()->implicitConvTo(t->nextOf()) >= MATCHconst) + { + p->f = f; + return 1; + } + } +#endif + return 0; + } + }; + ParamExact p; p.t = t; p.f = NULL; - overloadApply(this, &fp1, &p); + overloadApply(this, &p, &ParamExact::fp); return p.f; } - -/******************************************** - * Decide which function matches the arguments best. - * flags 1: do not issue error message on no match, just return NULL - * 2: do not issue error on ambiguous matches and need explicit this - */ - -struct Param2 -{ - Match *m; -#if DMDV2 - Type *tthis; - int property; // 0: unintialized - // 1: seen @property - // 2: not @property -#endif - Expressions *arguments; -}; - -int fp2(void *param, FuncDeclaration *f) -{ - Param2 *p = (Param2 *)param; - Match *m = p->m; - Expressions *arguments = p->arguments; - - if (f != m->lastf) // skip duplicates - { - m->anyf = f; - TypeFunction *tf = (TypeFunction *)f->type; - - int property = (tf->isproperty) ? 1 : 2; - if (p->property == 0) - p->property = property; - else if (p->property != property) - error(f->loc, "cannot overload both property and non-property functions"); - - /* For constructors, qualifier check will be opposite direction. - * Qualified constructor always makes qualified object, then will be checked - * that it is implicitly convertible to tthis. - */ - Type *tthis = f->needThis() ? p->tthis : NULL; - if (tthis && f->isCtorDeclaration()) - { - //printf("%s tf->mod = x%x tthis->mod = x%x %d\n", tf->toChars(), - // tf->mod, tthis->mod, f->isolateReturn()); - if (MODimplicitConv(tf->mod, tthis->mod) || - tf->isWild() && tf->isShared() == tthis->isShared() || - f->isolateReturn()/* && tf->isShared() == tthis->isShared()*/) - { // Uniquely constructed object can ignore shared qualifier. - // TODO: Is this appropriate? - tthis = NULL; - } - else - return 0; // MATCHnomatch - } - MATCH match = tf->callMatch(tthis, arguments); - //printf("test1: match = %d\n", match); - if (match != MATCHnomatch) - { - if (match > m->last) - goto LfIsBetter; - - if (match < m->last) - goto LlastIsBetter; - - /* See if one of the matches overrides the other. - */ - if (m->lastf->overrides(f)) - goto LlastIsBetter; - else if (f->overrides(m->lastf)) - goto LfIsBetter; - -#if DMDV2 - /* Try to disambiguate using template-style partial ordering rules. - * In essence, if f() and g() are ambiguous, if f() can call g(), - * but g() cannot call f(), then pick f(). - * This is because f() is "more specialized." - */ - { - MATCH c1 = f->leastAsSpecialized(m->lastf); - MATCH c2 = m->lastf->leastAsSpecialized(f); - //printf("c1 = %d, c2 = %d\n", c1, c2); - if (c1 > c2) - goto LfIsBetter; - if (c1 < c2) - goto LlastIsBetter; - } - - /* If the two functions are the same function, like: - * int foo(int); - * int foo(int x) { ... } - * then pick the one with the body. - */ - if (tf->equals(m->lastf->type) && - f->storage_class == m->lastf->storage_class && - f->parent == m->lastf->parent && - f->protection == m->lastf->protection && - f->linkage == m->lastf->linkage) - { - if (f->fbody && !m->lastf->fbody) - goto LfIsBetter; - else if (!f->fbody && m->lastf->fbody) - goto LlastIsBetter; - } -#endif - Lambiguous: - m->nextf = f; - m->count++; - return 0; - - LfIsBetter: - m->last = match; - m->lastf = f; - m->count = 1; - return 0; - - LlastIsBetter: - return 0; - } - } - return 0; -} - - -void overloadResolveX(Match *m, FuncDeclaration *fstart, - Type *tthis, Expressions *arguments) -{ - Param2 p; - p.m = m; - p.tthis = tthis; - p.property = 0; - p.arguments = arguments; - overloadApply(fstart, &fp2, &p); -} - static void MODMatchToBuffer(OutBuffer *buf, unsigned char lhsMod, unsigned char rhsMod) { bool bothMutable = ((lhsMod & rhsMod) == 0); @@ -2838,89 +2783,20 @@ static void MODMatchToBuffer(OutBuffer *buf, unsigned char lhsMod, unsigned char buf->writestring("mutable "); } -FuncDeclaration *FuncDeclaration::overloadResolve(Loc loc, Type *tthis, Expressions *arguments, int flags) +/******************************************** + * find function template root in overload list + */ + +TemplateDeclaration *FuncDeclaration::findTemplateDeclRoot() { -#if 0 - printf("FuncDeclaration::overloadResolve('%s')\n", toChars()); - if (arguments) + FuncDeclaration *f = this; + while (f && f->overnext) { - for (size_t i = 0; i < arguments->dim; i++) - { - Expression *arg = (*arguments)[i]; - assert(arg->type); - printf("\t%s: ", arg->toChars()); - arg->type->print(); - } - } -#endif - - Match m; - memset(&m, 0, sizeof(m)); - m.last = MATCHnomatch; - overloadResolveX(&m, this, tthis, arguments); - - if (m.count == 1) // exactly one match - { - if (!(flags & 1)) - m.lastf->functionSemantic(); - return m.lastf; - } - - if (m.last != MATCHnomatch && (flags & 2) && !tthis && m.lastf->needThis()) - { - return m.lastf; - } - - /* Failed to find a best match. - * Do nothing or print error. - */ - if (m.last == MATCHnomatch && (flags & 1)) - { // if do not print error messages - } - else - { - OutBuffer buf; - - buf.writeByte('('); - if (arguments && arguments->dim) - { - HdrGenState hgs; - argExpTypesToCBuffer(&buf, arguments, &hgs); - } - buf.writeByte(')'); - if (tthis) - tthis->modToBuffer(&buf); - - if (m.last == MATCHnomatch) - { - TypeFunction *tf = (TypeFunction *)type; - if (tthis && !MODimplicitConv(tthis->mod, tf->mod)) // modifier mismatch - { - OutBuffer thisBuf, funcBuf; - MODMatchToBuffer(&thisBuf, tthis->mod, tf->mod); - MODMatchToBuffer(&funcBuf, tf->mod, tthis->mod); - ::error(loc, "%smethod %s is not callable using a %sobject", - funcBuf.toChars(), this->toPrettyChars(), thisBuf.toChars()); - } - else - { - //printf("tf = %s, args = %s\n", tf->deco, (*arguments)[0]->type->deco); - error(loc, "%s%s is not callable using argument types %s", - Parameter::argsTypesToChars(tf->parameters, tf->varargs), - tf->modToChars(), - buf.toChars()); - } - } - else - { - TypeFunction *t1 = (TypeFunction *)m.lastf->type; - TypeFunction *t2 = (TypeFunction *)m.nextf->type; - - error(loc, "called with argument types:\n\t(%s)\nmatches both:\n\t%s(%d): %s%s\nand:\n\t%s(%d): %s%s", - buf.toChars(), - m.lastf->loc.filename, m.lastf->loc.linnum, m.lastf->toPrettyChars(), Parameter::argsTypesToChars(t1->parameters, t1->varargs), - m.nextf->loc.filename, m.nextf->loc.linnum, m.nextf->toPrettyChars(), Parameter::argsTypesToChars(t2->parameters, t2->varargs)); - } + //printf("f->overnext = %p %s\n", f->overnext, f->overnext->toChars()); + TemplateDeclaration *td = f->overnext->isTemplateDeclaration(); + if (td) + return td; + f = f->overnext->isFuncDeclaration(); } return NULL; } @@ -2933,7 +2809,6 @@ FuncDeclaration *FuncDeclaration::overloadResolve(Loc loc, Type *tthis, Expressi * 0 g is more specialized than 'this' */ -#if DMDV2 MATCH FuncDeclaration::leastAsSpecialized(FuncDeclaration *g) { #define LOG_LEASTAS 0 @@ -3029,28 +2904,159 @@ MATCH FuncDeclaration::leastAsSpecialized(FuncDeclaration *g) FuncDeclaration *resolveFuncCall(Loc loc, Scope *sc, Dsymbol *s, Objects *tiargs, Type *tthis, - Expressions *arguments, + Expressions *fargs, int flags) { if (!s) return NULL; // no match - if (tiargs && arrayObjectIsError(tiargs) || - arguments && arrayObjectIsError((Objects *)arguments)) + +#if 0 + printf("resolveFuncCall('%s')\n", toChars()); + if (fargs) + { + for (size_t i = 0; i < fargs->dim; i++) + { + Expression *arg = (*fargs)[i]; + assert(arg->type); + printf("\t%s: ", arg->toChars()); + arg->type->print(); + } + } +#endif + + if (tiargs && arrayObjectIsError(tiargs) || + fargs && arrayObjectIsError((Objects *)fargs)) { return NULL; } - FuncDeclaration *f = s->isFuncDeclaration(); - if (f) - f = f->overloadResolve(loc, tthis, arguments, flags); - else - { TemplateDeclaration *td = s->isTemplateDeclaration(); - assert(td); - if (!sc) sc = td->scope; - f = td->deduceFunctionTemplate(loc, sc, tiargs, tthis, arguments, flags); + + Match m; + memset(&m, 0, sizeof(m)); + m.last = MATCHnomatch; + + functionResolve(&m, s, loc, sc, tiargs, tthis, fargs); + + if (m.count == 1) // exactly one match + { + assert(m.lastf); + if (!(flags & 1)) + m.lastf->functionSemantic(); + return m.lastf; } - return f; + if (m.last != MATCHnomatch && (flags & 2) && !tthis && m.lastf->needThis()) + { + return m.lastf; + } + +Lerror: + /* Failed to find a best match. + * Do nothing or print error. + */ + if (m.last == MATCHnomatch && (flags & 1)) + { // if do not print error messages + return NULL; // no match + } + + HdrGenState hgs; + + FuncDeclaration *fd = s->isFuncDeclaration(); + TemplateDeclaration *td = s->isTemplateDeclaration(); + if (td && td->funcroot) + s = fd = td->funcroot; + + OutBuffer tiargsBuf; + size_t dim = tiargs ? tiargs->dim : 0; + for (size_t i = 0; i < dim; i++) + { + if (i) + tiargsBuf.writestring(", "); + RootObject *oarg = (*tiargs)[i]; + ObjectToCBuffer(&tiargsBuf, &hgs, oarg); + } + + OutBuffer fargsBuf; + fargsBuf.writeByte('('); + argExpTypesToCBuffer(&fargsBuf, fargs, &hgs); + fargsBuf.writeByte(')'); + if (tthis) + tthis->modToBuffer(&fargsBuf); + + assert(!m.lastf || m.nextf); + if (!m.lastf && !(flags & 1)) // no match + { + if (td) + { + if (!fd) // all of overloads are template + { + ::error(loc, "%s %s.%s does not match any function template declaration. Candidates are:", + td->kind(), td->parent->toPrettyChars(), td->ident->toChars()); + + // Display candidate template functions + int numToDisplay = 5; // sensible number to display + for (TemplateDeclaration *tdx = td; tdx; tdx = tdx->overnext) + { + ::errorSupplemental(tdx->loc, "%s", tdx->toPrettyChars()); + if (!global.params.verbose && --numToDisplay == 0) + { + // Too many overloads to sensibly display. + // Just show count of remaining overloads. + int remaining = 0; + for (; tdx; tdx = tdx->overnext) + ++remaining; + if (remaining > 0) + ::errorSupplemental(loc, "... (%d more, -v to show) ...", remaining); + break; + } + } + } + td->error(loc, "cannot deduce template function from argument types !(%s)%s", + tiargsBuf.toChars(), fargsBuf.toChars()); + } + else + { + assert(fd); + TypeFunction *tf = (TypeFunction *)fd->type; + if (tthis && !MODimplicitConv(tthis->mod, tf->mod)) // modifier mismatch + { + OutBuffer thisBuf, funcBuf; + MODMatchToBuffer(&thisBuf, tthis->mod, tf->mod); + MODMatchToBuffer(&funcBuf, tf->mod, tthis->mod); + ::error(loc, "%smethod %s is not callable using a %sobject", + funcBuf.toChars(), fd->toPrettyChars(), thisBuf.toChars()); + } + else + { + //printf("tf = %s, args = %s\n", tf->deco, (*fargs)[0]->type->deco); + fd->error(loc, "%s%s is not callable using argument types %s", + Parameter::argsTypesToChars(tf->parameters, tf->varargs), + tf->modToChars(), + fargsBuf.toChars()); + } + } + } + else if (m.nextf) + { + /* CAUTION: m.lastf and m.nextf might be incompletely instantiated functions + * (created by doHeaderInstantiation), so call toPrettyChars will segfault. + */ + assert(m.lastf); + TypeFunction *t1 = (TypeFunction *)m.lastf->type; + TypeFunction *t2 = (TypeFunction *)m.nextf->type; + TemplateInstance *lastti = m.lastf->parent->isTemplateInstance(); + TemplateInstance *nextti = m.nextf->parent->isTemplateInstance(); + Dsymbol *lasts = lastti ? (Dsymbol *)lastti->tempdecl : (Dsymbol *)m.lastf; + Dsymbol *nexts = nextti ? (Dsymbol *)nextti->tempdecl : (Dsymbol *)m.nextf; + const char *lastprms = lastti ? "" : Parameter::argsTypesToChars(t1->parameters, t1->varargs); + const char *nextprms = nextti ? "" : Parameter::argsTypesToChars(t2->parameters, t2->varargs); + ::error(loc, "%s.%s called with argument types %s matches both:\n" + "\t%s(%d): %s%s\nand:\n\t%s(%d): %s%s", + s->parent->toPrettyChars(), s->ident->toChars(), + fargsBuf.toChars(), + lasts->loc.filename, lasts->loc.linnum, lasts->toChars(), lastprms, + nexts->loc.filename, nexts->loc.linnum, nexts->toChars(), nextprms); + } + return NULL; } -#endif /******************************** * Labels are in a separate scope, one per function. @@ -3138,7 +3144,8 @@ int FuncDeclaration::getLevel(Loc loc, Scope *sc, FuncDeclaration *fd) //printf("\ts = %s, '%s'\n", s->kind(), s->toChars()); FuncDeclaration *thisfd = s->isFuncDeclaration(); if (thisfd) - { if (!thisfd->isNested() && !thisfd->vthis && !sc->intypeof) + { + if (!thisfd->isNested() && !thisfd->vthis && !sc->intypeof) goto Lerr; } else @@ -3172,7 +3179,11 @@ int FuncDeclaration::getLevel(Loc loc, Scope *sc, FuncDeclaration *fd) Lerr: // Don't give error if in template constraint if (!((sc->flags & SCOPEstaticif) && parent->isTemplateDeclaration())) - error(loc, "cannot access frame of function %s", fd->toPrettyChars()); + { + // better diagnostics for static functions + ::error(loc, "%s%s %s cannot access frame of function %s", + isStatic() ? "static " : "", kind(), toPrettyChars(), fd->toPrettyChars()); + } return 1; } @@ -3220,17 +3231,17 @@ const char *FuncDeclaration::toFullSignature() return buf.extractData(); } -int FuncDeclaration::isMain() +bool FuncDeclaration::isMain() { return ident == Id::main && linkage != LINKc && !isMember() && !isNested(); } -int FuncDeclaration::isWinMain() +bool FuncDeclaration::isWinMain() { //printf("FuncDeclaration::isWinMain() %s\n", toChars()); #if 0 - int x = ident == Id::WinMain && + bool x = ident == Id::WinMain && linkage != LINKc && !isMember(); printf("%s\n", x ? "yes" : "no"); return x; @@ -3240,18 +3251,18 @@ int FuncDeclaration::isWinMain() #endif } -int FuncDeclaration::isDllMain() +bool FuncDeclaration::isDllMain() { return ident == Id::DllMain && linkage != LINKc && !isMember(); } -int FuncDeclaration::isExport() +bool FuncDeclaration::isExport() { return protection == PROTexport; } -int FuncDeclaration::isImportedSymbol() +bool FuncDeclaration::isImportedSymbol() { //printf("isImportedSymbol()\n"); //printf("protection = %d\n", protection); @@ -3260,7 +3271,7 @@ int FuncDeclaration::isImportedSymbol() // Determine if function goes into virtual function pointer table -int FuncDeclaration::isVirtual() +bool FuncDeclaration::isVirtual() { if (toAliasFunc() != this) return toAliasFunc()->isVirtual(); @@ -3273,40 +3284,40 @@ int FuncDeclaration::isVirtual() isMember() && !(isStatic() || protection == PROTprivate || protection == PROTpackage) && p->isClassDeclaration() && - !(p->isInterfaceDeclaration() && isFinal())); + !(p->isInterfaceDeclaration() && isFinalFunc())); #endif return isMember() && !(isStatic() || protection == PROTprivate || protection == PROTpackage) && p->isClassDeclaration() && - !(p->isInterfaceDeclaration() && isFinal()); + !(p->isInterfaceDeclaration() && isFinalFunc()); } // Determine if a function is pedantically virtual -int FuncDeclaration::isVirtualMethod() +bool FuncDeclaration::isVirtualMethod() { if (toAliasFunc() != this) return toAliasFunc()->isVirtualMethod(); //printf("FuncDeclaration::isVirtualMethod() %s\n", toChars()); if (!isVirtual()) - return 0; + return false; // If it's a final method, and does not override anything, then it is not virtual - if (isFinal() && foverrides.dim == 0) + if (isFinalFunc() && foverrides.dim == 0) { - return 0; + return false; } - return 1; + return true; } -int FuncDeclaration::isFinal() +bool FuncDeclaration::isFinalFunc() { if (toAliasFunc() != this) - return toAliasFunc()->isFinal(); + return toAliasFunc()->isFinalFunc(); ClassDeclaration *cd; #if 0 - printf("FuncDeclaration::isFinal(%s), %x\n", toChars(), Declaration::isFinal()); + printf("FuncDeclaration::isFinalFunc(%s), %x\n", toChars(), Declaration::isFinal()); printf("%p %d %d %d\n", isMember(), isStatic(), Declaration::isFinal(), ((cd = toParent()->isClassDeclaration()) != NULL && cd->storage_class & STCfinal)); printf("result is %d\n", isMember() && @@ -3325,27 +3336,22 @@ int FuncDeclaration::isFinal() ((cd = toParent()->isClassDeclaration()) != NULL && cd->storage_class & STCfinal)); } -int FuncDeclaration::isAbstract() +bool FuncDeclaration::isCodeseg() { - return storage_class & STCabstract; + return true; // functions are always in the code segment } -int FuncDeclaration::isCodeseg() +bool FuncDeclaration::isOverloadable() { - return TRUE; // functions are always in the code segment + return true; // functions can be overloaded } -int FuncDeclaration::isOverloadable() -{ - return 1; // functions can be overloaded -} - -int FuncDeclaration::hasOverloads() +bool FuncDeclaration::hasOverloads() { return overnext != NULL; } -enum PURE FuncDeclaration::isPure() +PURE FuncDeclaration::isPure() { //printf("FuncDeclaration::isPure() '%s'\n", toChars()); assert(type->ty == Tfunction); @@ -3354,7 +3360,7 @@ enum PURE FuncDeclaration::isPure() setImpure(); if (tf->purity == PUREfwdref) tf->purityLevel(); - enum PURE purity = tf->purity; + PURE purity = tf->purity; if (purity > PUREweak && isNested()) purity = PUREweak; if (purity > PUREweak && needThis()) @@ -3372,7 +3378,7 @@ enum PURE FuncDeclaration::isPure() return purity; } -enum PURE FuncDeclaration::isPureBypassingInference() +PURE FuncDeclaration::isPureBypassingInference() { if (flags & FUNCFLAGpurityInprocess) return PUREfwdref; @@ -3396,7 +3402,7 @@ bool FuncDeclaration::setImpure() return FALSE; } -int FuncDeclaration::isSafe() +bool FuncDeclaration::isSafe() { assert(type->ty == Tfunction); if (flags & FUNCFLAGsafetyInprocess) @@ -3412,7 +3418,7 @@ bool FuncDeclaration::isSafeBypassingInference() return isSafe(); } -int FuncDeclaration::isTrusted() +bool FuncDeclaration::isTrusted() { assert(type->ty == Tfunction); if (flags & FUNCFLAGsafetyInprocess) @@ -3443,12 +3449,7 @@ bool FuncDeclaration::setUnsafe() Type *getIndirection(Type *t) { - t = t->toBasetype(); - - if (t->ty == Tsarray) - { while (t->ty == Tsarray) - t = t->nextOf()->toBasetype(); - } + t = t->baseElemOf(); if (t->ty == Tarray || t->ty == Tpointer) return t->nextOf()->toBasetype(); if (t->ty == Taarray || t->ty == Tclass) @@ -3471,7 +3472,7 @@ int traverseIndirections(Type *ta, Type *tb, void *p = NULL, bool a2b = true) //printf("\ttraverse(1) %s appears in %s\n", ta->toChars(), tb->toChars()); if (ta->constConv(tb)) return 1; - else if (ta->invariantOf()->equals(tb->invariantOf())) + else if (ta->immutableOf()->equals(tb->immutableOf())) return 0; else if (tb->ty == Tvoid && MODimplicitConv(ta->mod, tb->mod)) return 1; @@ -3481,7 +3482,7 @@ int traverseIndirections(Type *ta, Type *tb, void *p = NULL, bool a2b = true) //printf("\ttraverse(2) %s appears in %s\n", tb->toChars(), ta->toChars()); if (tb->constConv(ta)) return 1; - else if (tb->invariantOf()->equals(ta->invariantOf())) + else if (tb->immutableOf()->equals(ta->immutableOf())) return 0; else if (ta->ty == Tvoid && MODimplicitConv(tb->mod, ta->mod)) return 1; @@ -3499,10 +3500,7 @@ int traverseIndirections(Type *ta, Type *tb, void *p = NULL, bool a2b = true) if (tbb != tb) return traverseIndirections(ta, tbb, ctxt, a2b); - if (tb->ty == Tsarray) - { while (tb->toBasetype()->ty == Tsarray) - tb = tb->toBasetype()->nextOf(); - } + tb = tb->baseElemOf(); if (tb->ty == Tclass || tb->ty == Tstruct) { for (Ctxt *c = ctxt; c; c = c->prev) @@ -3606,7 +3604,7 @@ bool FuncDeclaration::parametersIntersect(Type *t) // Determine if function needs // a static frame pointer to its lexically enclosing function -int FuncDeclaration::isNested() +bool FuncDeclaration::isNested() { FuncDeclaration *f = toAliasFunc(); //printf("\ttoParent2() = '%s'\n", f->toParent2()->toChars()); @@ -3615,16 +3613,17 @@ int FuncDeclaration::isNested() (f->toParent2()->isFuncDeclaration() != NULL); } -int FuncDeclaration::needThis() +bool FuncDeclaration::needThis() { //printf("FuncDeclaration::needThis() '%s'\n", toChars()); return toAliasFunc()->isThis() != NULL; } -int FuncDeclaration::addPreInvariant() +bool FuncDeclaration::addPreInvariant() { AggregateDeclaration *ad = isThis(); - return (ad && + ClassDeclaration *cd = ad ? ad->isClassDeclaration() : NULL; + return (ad && !(cd && cd->isCPPclass()) && //ad->isClassDeclaration() && global.params.useInvariants && (protection == PROTprotected || protection == PROTpublic || protection == PROTexport) && @@ -3632,10 +3631,11 @@ int FuncDeclaration::addPreInvariant() ident != Id::cpctor); } -int FuncDeclaration::addPostInvariant() +bool FuncDeclaration::addPostInvariant() { AggregateDeclaration *ad = isThis(); - return (ad && + ClassDeclaration *cd = ad ? ad->isClassDeclaration() : NULL; + return (ad && !(cd && cd->isCPPclass()) && ad->inv && //ad->isClassDeclaration() && global.params.useInvariants && @@ -3648,10 +3648,6 @@ int FuncDeclaration::addPostInvariant() * Generate a FuncDeclaration for a runtime library function. */ -// -// LDC: Adjusted to give argument info to the runtime function decl. -// - FuncDeclaration *FuncDeclaration::genCfunc(Parameters *args, Type *treturn, const char *name) { return genCfunc(args, treturn, Lexer::idPool(name)); @@ -3679,11 +3675,7 @@ FuncDeclaration *FuncDeclaration::genCfunc(Parameters *args, Type *treturn, Iden } else { -#if IN_LLVM tf = new TypeFunction(args, treturn, 0, LINKc); -#else - tf = new TypeFunction(NULL, treturn, 0, LINKc); -#endif fd = new FuncDeclaration(Loc(), Loc(), id, STCstatic, tf); fd->protection = PROTpublic; fd->linkage = LINKc; @@ -3815,7 +3807,7 @@ bool checkEscapingSiblings(FuncDeclaration *f, FuncDeclaration *outerFunc) */ #if DMDV2 -int FuncDeclaration::needsClosure() +bool FuncDeclaration::needsClosure() { /* Need a closure for all the closureVars[] if any of the * closureVars[] are accessed by a @@ -3903,11 +3895,11 @@ int FuncDeclaration::needsClosure() } } - return 0; + return false; Lyes: //printf("\tneeds closure\n"); - return 1; + return true; } #endif @@ -3916,14 +3908,14 @@ Lyes: * nested within it. */ -int FuncDeclaration::hasNestedFrameRefs() +bool FuncDeclaration::hasNestedFrameRefs() { #if DMDV2 if (closureVars.dim) #else if (nestedFrameRef) #endif - return 1; + return true; /* If a virtual method has contracts, assume its variables are referenced * by those contracts, even if they aren't. Because they might be referenced @@ -3933,7 +3925,7 @@ int FuncDeclaration::hasNestedFrameRefs() * context had better match, or Bugzilla 7337 will bite. */ if ((fdrequire || fdensure) && isVirtualMethod()) - return 1; + return true; if (foverrides.dim && isVirtualMethod()) { @@ -3941,11 +3933,11 @@ int FuncDeclaration::hasNestedFrameRefs() { FuncDeclaration *fdv = foverrides[i]; if (fdv->hasNestedFrameRefs()) - return 1; + return true; } } - return 0; + return false; } /********************************************* @@ -3954,8 +3946,8 @@ int FuncDeclaration::hasNestedFrameRefs() */ Parameters *FuncDeclaration::getParameters(int *pvarargs) -{ Parameters *fparameters; - int fvarargs; +{ Parameters *fparameters = NULL; + int fvarargs = 0; if (type) { @@ -3974,7 +3966,7 @@ Parameters *FuncDeclaration::getParameters(int *pvarargs) // Used as a way to import a set of functions from another scope into this one. -FuncAliasDeclaration::FuncAliasDeclaration(FuncDeclaration *funcalias, int hasOverloads) +FuncAliasDeclaration::FuncAliasDeclaration(FuncDeclaration *funcalias, bool hasOverloads) : FuncDeclaration(funcalias->loc, funcalias->endloc, funcalias->ident, funcalias->storage_class, funcalias->type) { @@ -3990,7 +3982,7 @@ FuncAliasDeclaration::FuncAliasDeclaration(FuncDeclaration *funcalias, int hasOv else { // for internal use assert(!funcalias->isFuncAliasDeclaration()); - this->hasOverloads = 0; + this->hasOverloads = false; } userAttributes = funcalias->userAttributes; } @@ -4009,20 +4001,10 @@ FuncDeclaration *FuncAliasDeclaration::toAliasFunc() /****************************** FuncLiteralDeclaration ************************/ FuncLiteralDeclaration::FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type, - enum TOK tok, ForeachStatement *fes) + TOK tok, ForeachStatement *fes, Identifier *id) : FuncDeclaration(loc, endloc, NULL, STCundefined, type) { - const char *id; - - if (fes) - id = "__foreachbody"; - else if (tok == TOKreserved) - id = "__lambda"; - else if (tok == TOKdelegate) - id = "__dgliteral"; - else - id = "__funcliteral"; - this->ident = Lexer::uniqueId(id); + this->ident = id ? id : Id::empty; this->tok = tok; this->fes = fes; this->treq = NULL; @@ -4041,23 +4023,21 @@ Dsymbol *FuncLiteralDeclaration::syntaxCopy(Dsymbol *s) if (s) f = (FuncLiteralDeclaration *)s; else - { f = new FuncLiteralDeclaration(loc, endloc, type->syntaxCopy(), tok, fes); - f->ident = ident; // keep old identifier - f->treq = treq; // don't need to copy - } + f = new FuncLiteralDeclaration(loc, endloc, type->syntaxCopy(), tok, fes, ident); + f->treq = treq; // don't need to copy FuncDeclaration::syntaxCopy(f); return f; } -int FuncLiteralDeclaration::isNested() +bool FuncLiteralDeclaration::isNested() { //printf("FuncLiteralDeclaration::isNested() '%s'\n", toChars()); return (tok != TOKfunction); } -int FuncLiteralDeclaration::isVirtual() +bool FuncLiteralDeclaration::isVirtual() { - return FALSE; + return false; } const char *FuncLiteralDeclaration::kind() @@ -4076,16 +4056,24 @@ void FuncLiteralDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) TypeFunction *tf = (TypeFunction *)type; // Don't print tf->mod, tf->trust, and tf->linkage - if (tf->next) + if (!inferRetType && tf->next) tf->next->toCBuffer2(buf, hgs, 0); Parameter::argsToCBuffer(buf, hgs, tf->parameters, tf->varargs); - ReturnStatement *ret = !fbody->isCompoundStatement() ? - fbody->isReturnStatement() : NULL; - if (ret && ret->exp) + CompoundStatement *cs = fbody->isCompoundStatement(); + Statement *s1; + if (semanticRun >= PASSsemantic3done) + { + assert(cs); + s1 = (*cs->statements)[cs->statements->dim - 1]; + } + else + s1 = !cs ? fbody : NULL; + ReturnStatement *rs = s1 ? s1->isReturnStatement() : NULL; + if (rs && rs->exp) { buf->writestring(" => "); - ret->exp->toCBuffer(buf, hgs); + rs->exp->toCBuffer(buf, hgs); } else { @@ -4173,17 +4161,17 @@ char *CtorDeclaration::toChars() return (char *)"this"; } -int CtorDeclaration::isVirtual() +bool CtorDeclaration::isVirtual() { - return FALSE; + return false; } -int CtorDeclaration::addPreInvariant() +bool CtorDeclaration::addPreInvariant() { - return FALSE; + return false; } -int CtorDeclaration::addPostInvariant() +bool CtorDeclaration::addPostInvariant() { return (isThis() && vthis && global.params.useInvariants); } @@ -4236,24 +4224,24 @@ void PostBlitDeclaration::semantic(Scope *sc) sc->pop(); } -int PostBlitDeclaration::overloadInsert(Dsymbol *s) +bool PostBlitDeclaration::overloadInsert(Dsymbol *s) { - return FALSE; // cannot overload postblits + return false; // cannot overload postblits } -int PostBlitDeclaration::addPreInvariant() +bool PostBlitDeclaration::addPreInvariant() { - return FALSE; + return false; } -int PostBlitDeclaration::addPostInvariant() +bool PostBlitDeclaration::addPostInvariant() { return (isThis() && vthis && global.params.useInvariants); } -int PostBlitDeclaration::isVirtual() +bool PostBlitDeclaration::isVirtual() { - return FALSE; + return false; } void PostBlitDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) @@ -4314,19 +4302,19 @@ void DtorDeclaration::semantic(Scope *sc) sc->pop(); } -int DtorDeclaration::overloadInsert(Dsymbol *s) +bool DtorDeclaration::overloadInsert(Dsymbol *s) { - return FALSE; // cannot overload destructors + return false; // cannot overload destructors } -int DtorDeclaration::addPreInvariant() +bool DtorDeclaration::addPreInvariant() { return (isThis() && vthis && global.params.useInvariants); } -int DtorDeclaration::addPostInvariant() +bool DtorDeclaration::addPostInvariant() { - return FALSE; + return false; } const char *DtorDeclaration::kind() @@ -4339,10 +4327,10 @@ char *DtorDeclaration::toChars() return (char *)"~this"; } -int DtorDeclaration::isVirtual() +bool DtorDeclaration::isVirtual() { - // FALSE so that dtor's don't get put into the vtbl[] - return FALSE; + // false so that dtor's don't get put into the vtbl[] + return false; } void DtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) @@ -4430,9 +4418,9 @@ AggregateDeclaration *StaticCtorDeclaration::isThis() return NULL; } -int StaticCtorDeclaration::isVirtual() +bool StaticCtorDeclaration::isVirtual() { - return FALSE; + return false; } bool StaticCtorDeclaration::hasStaticCtorOrDtor() @@ -4440,14 +4428,14 @@ bool StaticCtorDeclaration::hasStaticCtorOrDtor() return TRUE; } -int StaticCtorDeclaration::addPreInvariant() +bool StaticCtorDeclaration::addPreInvariant() { - return FALSE; + return false; } -int StaticCtorDeclaration::addPostInvariant() +bool StaticCtorDeclaration::addPostInvariant() { - return FALSE; + return false; } void StaticCtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) @@ -4484,16 +4472,16 @@ void SharedStaticCtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) /********************************* StaticDtorDeclaration ****************************/ -StaticDtorDeclaration::StaticDtorDeclaration(Loc loc, Loc endloc) +StaticDtorDeclaration::StaticDtorDeclaration(Loc loc, Loc endloc, StorageClass stc) : FuncDeclaration(loc, endloc, - Identifier::generateId("_staticDtor"), STCstatic, NULL) + Identifier::generateId("_staticDtor"), STCstatic | stc, NULL) { vgate = NULL; } -StaticDtorDeclaration::StaticDtorDeclaration(Loc loc, Loc endloc, const char *name) +StaticDtorDeclaration::StaticDtorDeclaration(Loc loc, Loc endloc, const char *name, StorageClass stc) : FuncDeclaration(loc, endloc, - Identifier::generateId(name), STCstatic, NULL) + Identifier::generateId(name), STCstatic | stc, NULL) { vgate = NULL; } @@ -4501,7 +4489,7 @@ StaticDtorDeclaration::StaticDtorDeclaration(Loc loc, Loc endloc, const char *na Dsymbol *StaticDtorDeclaration::syntaxCopy(Dsymbol *s) { assert(!s); - StaticDtorDeclaration *sdd = new StaticDtorDeclaration(loc, endloc); + StaticDtorDeclaration *sdd = new StaticDtorDeclaration(loc, endloc, storage_class); return FuncDeclaration::syntaxCopy(sdd); } @@ -4513,10 +4501,8 @@ void StaticDtorDeclaration::semantic(Scope *sc) scope = NULL; } - ClassDeclaration *cd = sc->scopesym->isClassDeclaration(); - if (!type) - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); + type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd, storage_class); /* If the static ctor appears within a template instantiation, * it could get called multiple times by the module constructors @@ -4565,9 +4551,9 @@ AggregateDeclaration *StaticDtorDeclaration::isThis() return NULL; } -int StaticDtorDeclaration::isVirtual() +bool StaticDtorDeclaration::isVirtual() { - return FALSE; + return false; } bool StaticDtorDeclaration::hasStaticCtorOrDtor() @@ -4575,14 +4561,14 @@ bool StaticDtorDeclaration::hasStaticCtorOrDtor() return TRUE; } -int StaticDtorDeclaration::addPreInvariant() +bool StaticDtorDeclaration::addPreInvariant() { - return FALSE; + return false; } -int StaticDtorDeclaration::addPostInvariant() +bool StaticDtorDeclaration::addPostInvariant() { - return FALSE; + return false; } void StaticDtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) @@ -4595,15 +4581,15 @@ void StaticDtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) /********************************* SharedStaticDtorDeclaration ****************************/ -SharedStaticDtorDeclaration::SharedStaticDtorDeclaration(Loc loc, Loc endloc) - : StaticDtorDeclaration(loc, endloc, "_sharedStaticDtor") +SharedStaticDtorDeclaration::SharedStaticDtorDeclaration(Loc loc, Loc endloc, StorageClass stc) + : StaticDtorDeclaration(loc, endloc, "_sharedStaticDtor", stc) { } Dsymbol *SharedStaticDtorDeclaration::syntaxCopy(Dsymbol *s) { assert(!s); - SharedStaticDtorDeclaration *sdd = new SharedStaticDtorDeclaration(loc, endloc); + SharedStaticDtorDeclaration *sdd = new SharedStaticDtorDeclaration(loc, endloc, storage_class); return FuncDeclaration::syntaxCopy(sdd); } @@ -4669,19 +4655,19 @@ void InvariantDeclaration::semantic(Scope *sc) sc->pop(); } -int InvariantDeclaration::isVirtual() +bool InvariantDeclaration::isVirtual() { - return FALSE; + return false; } -int InvariantDeclaration::addPreInvariant() +bool InvariantDeclaration::addPreInvariant() { - return FALSE; + return false; } -int InvariantDeclaration::addPostInvariant() +bool InvariantDeclaration::addPostInvariant() { - return FALSE; + return false; } void InvariantDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) @@ -4740,8 +4726,6 @@ void UnitTestDeclaration::semantic(Scope *sc) if (!type) type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); Scope *sc2 = sc->push(); - // It makes no sense for unit tests to be pure or nothrow. - sc2->stc &= ~(STCnothrow | STCpure); sc2->linkage = LINKd; FuncDeclaration::semantic(sc2); sc2->pop(); @@ -4768,19 +4752,19 @@ AggregateDeclaration *UnitTestDeclaration::isThis() return NULL; } -int UnitTestDeclaration::isVirtual() +bool UnitTestDeclaration::isVirtual() { - return FALSE; + return false; } -int UnitTestDeclaration::addPreInvariant() +bool UnitTestDeclaration::addPreInvariant() { - return FALSE; + return false; } -int UnitTestDeclaration::addPostInvariant() +bool UnitTestDeclaration::addPostInvariant() { - return FALSE; + return false; } void UnitTestDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) @@ -4858,19 +4842,19 @@ const char *NewDeclaration::kind() return "allocator"; } -int NewDeclaration::isVirtual() +bool NewDeclaration::isVirtual() { - return FALSE; + return false; } -int NewDeclaration::addPreInvariant() +bool NewDeclaration::addPreInvariant() { - return FALSE; + return false; } -int NewDeclaration::addPostInvariant() +bool NewDeclaration::addPostInvariant() { - return FALSE; + return false; } void NewDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) @@ -4946,24 +4930,24 @@ const char *DeleteDeclaration::kind() return "deallocator"; } -int DeleteDeclaration::isDelete() +bool DeleteDeclaration::isDelete() { - return TRUE; + return true; } -int DeleteDeclaration::isVirtual() +bool DeleteDeclaration::isVirtual() { - return FALSE; + return false; } -int DeleteDeclaration::addPreInvariant() +bool DeleteDeclaration::addPreInvariant() { - return FALSE; + return false; } -int DeleteDeclaration::addPostInvariant() +bool DeleteDeclaration::addPostInvariant() { - return FALSE; + return false; } void DeleteDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) diff --git a/dmd2/identifier.c b/dmd2/identifier.c index e17ab7e7..9146fc3a 100644 --- a/dmd2/identifier.c +++ b/dmd2/identifier.c @@ -30,12 +30,12 @@ hash_t Identifier::hashCode() return String::calcHash(string); } -int Identifier::equals(Object *o) +bool Identifier::equals(RootObject *o) { return this == o || memcmp(string,o->toChars(),len+1) == 0; } -int Identifier::compare(Object *o) +int Identifier::compare(RootObject *o) { return memcmp(string, o->toChars(), len + 1); } diff --git a/dmd2/identifier.h b/dmd2/identifier.h index e6cda8ec..878df0b6 100644 --- a/dmd2/identifier.h +++ b/dmd2/identifier.h @@ -17,23 +17,17 @@ #include "root.h" -#if IN_LLVM -namespace llvm -{ - class Value; -} -#endif - -struct Identifier : Object +class Identifier : public RootObject { +public: int value; const char *string; size_t len; Identifier(const char *string, int value); - int equals(Object *o); + bool equals(RootObject *o); hash_t hashCode(); - int compare(Object *o); + int compare(RootObject *o); void print(); char *toChars(); const char *toHChars2(); diff --git a/dmd2/idgen.c b/dmd2/idgen.c index e22b69f4..01cc2795 100644 --- a/dmd2/idgen.c +++ b/dmd2/idgen.c @@ -266,7 +266,7 @@ Msgtable msgtable[] = { "lib" }, { "msg" }, { "startaddress" }, - { "mangle" }, + { "mangle" }, #if IN_LLVM // LDC-specific pragmas. @@ -324,6 +324,7 @@ Msgtable msgtable[] = { "WinMain" }, { "DllMain" }, { "tls_get_addr", "___tls_get_addr" }, + { "entrypoint", "__entrypoint" }, // varargs implementation { "va_argsave_t", "__va_argsave_t" }, @@ -385,6 +386,9 @@ Msgtable msgtable[] = { "compiles" }, { "parameters" }, { "getAttributes" }, + { "getUnitTests" }, + { "isOverrideFunction" }, + { "getVirtualIndex" } }; @@ -406,7 +410,7 @@ int main() #endif fprintf(fp, "#ifndef DMD_ID_H\n"); fprintf(fp, "#define DMD_ID_H 1\n"); - fprintf(fp, "struct Identifier;\n"); + fprintf(fp, "class Identifier;\n"); fprintf(fp, "struct Id\n"); fprintf(fp, "{\n"); diff --git a/dmd2/import.c b/dmd2/import.c index 9e211718..3063442a 100644 --- a/dmd2/import.c +++ b/dmd2/import.c @@ -30,6 +30,18 @@ Import::Import(Loc loc, Identifiers *packages, Identifier *id, Identifier *alias : Dsymbol(NULL) { assert(id); +#if 0 + printf("Import::Import("); + if (packages && packages->dim) + { + for (size_t i = 0; i < packages->dim; i++) + { + Identifier *id = (*packages)[i]; + printf("%s.", id->toChars()); + } + } + printf("%s)\n", id->toChars()); +#endif this->loc = loc; this->packages = packages; this->id = id; @@ -68,7 +80,7 @@ const char *Import::kind() return isstatic ? (char *)"static import" : (char *)"import"; } -enum PROT Import::prot() +PROT Import::prot() { return protection; } @@ -89,10 +101,11 @@ Dsymbol *Import::syntaxCopy(Dsymbol *s) void Import::load(Scope *sc) { - //printf("Import::load('%s')\n", toChars()); + //printf("Import::load('%s') %p\n", toPrettyChars(), this); // See if existing module DsymbolTable *dst = Package::resolve(packages, NULL, &pkg); +#if 0 if (pkg && pkg->isModule()) { ::error(loc, "can only import from a module, not from a member of module %s. Did you mean `import %s : %s`?", @@ -100,6 +113,7 @@ void Import::load(Scope *sc) mod = pkg->isModule(); // Error recovery - treat as import of that module return; } +#endif Dsymbol *s = dst->lookup(id); if (s) { @@ -107,7 +121,31 @@ void Import::load(Scope *sc) mod = (Module *)s; else { - if (pkg) + if (s->isAliasDeclaration()) + { + ::error(loc, "%s %s conflicts with %s", s->kind(), s->toPrettyChars(), id->toChars()); + } + else if (Package *p = s->isPackage()) + { + if (p->isPkgMod == PKGunknown) + { + mod = Module::load(loc, packages, id); + if (!mod) + p->isPkgMod = PKGpackage; + else + assert(p->isPkgMod == PKGmodule); + } + else if (p->isPkgMod == PKGmodule) + { + mod = p->mod; + } + if (p->isPkgMod != PKGmodule) + { + ::error(loc, "can only import from a module, not from package %s.%s", + p->toPrettyChars(), id->toChars()); + } + } + else if (pkg) { ::error(loc, "can only import from a module, not from package %s.%s", pkg->toPrettyChars(), id->toChars()); @@ -128,36 +166,16 @@ void Import::load(Scope *sc) { dst->insert(id, mod); // id may be different from mod->ident, // if so then insert alias - if (!mod->importedFrom) - mod->importedFrom = sc ? sc->module->importedFrom : Module::rootModule; } } + if (mod && !mod->importedFrom) + mod->importedFrom = sc ? sc->module->importedFrom : Module::rootModule; if (!pkg) pkg = mod; //printf("-Import::load('%s'), pkg = %p\n", toChars(), pkg); } -void escapePath(OutBuffer *buf, const char *fname) -{ - while (1) - { - switch (*fname) - { - case 0: - return; - case '(': - case ')': - case '\\': - buf->writebyte('\\'); - default: - buf->writebyte(*fname); - break; - } - fname++; - } -} - void Import::importAll(Scope *sc) { if (!mod) @@ -178,7 +196,7 @@ void Import::importAll(Scope *sc) void Import::semantic(Scope *sc) { - //printf("Import::semantic('%s')\n", toChars()); + //printf("Import::semantic('%s')\n", toPrettyChars()); if (scope) { sc = scope; @@ -260,7 +278,10 @@ void Import::semantic(Scope *sc) if (global.params.moduleDeps != NULL && // object self-imports itself, so skip that (Bugzilla 7547) - !(id == Id::object && sc->module->ident == Id::object)) + !(id == Id::object && sc->module->ident == Id::object) && + // don't list pseudo modules __entrypoint.d, __main.d (Bugzilla 11117, 11164) + sc->module->ident != Id::entrypoint && + strcmp(sc->module->ident->string, "__main") != 0) { /* The grammar of the file is: * ImportDeclaration @@ -276,10 +297,12 @@ void Import::semantic(Scope *sc) */ OutBuffer *ob = global.params.moduleDeps; - - ob->writestring(sc->module->toPrettyChars()); + Module* imod = sc->instantiatingModule ? sc->instantiatingModule : sc->module; + if (!global.params.moduleDepsFile) + ob->writestring("depsImport "); + ob->writestring(imod->toPrettyChars()); ob->writestring(" ("); - escapePath(ob, sc->module->srcfile->toChars()); + escapePath(ob, imod->srcfile->toChars()); ob->writestring(") : "); // use protection instead of sc->protection because it couldn't be @@ -403,7 +426,7 @@ Dsymbol *Import::search(Loc loc, Identifier *ident, int flags) return pkg->search(loc, ident, flags); } -int Import::overloadInsert(Dsymbol *s) +bool Import::overloadInsert(Dsymbol *s) { /* Allow multiple imports with the same package base, but disallow * alias collisions (Bugzilla 5412). @@ -411,9 +434,9 @@ int Import::overloadInsert(Dsymbol *s) assert(ident && ident == s->ident); Import *imp; if (!aliasId && (imp = s->isImport()) != NULL && !imp->aliasId) - return TRUE; + return true; else - return FALSE; + return false; } void Import::toCBuffer(OutBuffer *buf, HdrGenState *hgs) diff --git a/dmd2/import.h b/dmd2/import.h index 5549a82b..dd17239a 100644 --- a/dmd2/import.h +++ b/dmd2/import.h @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars +// Copyright (c) 1999-2013 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -18,37 +18,41 @@ #include "dsymbol.h" -struct Identifier; +class Identifier; struct Scope; struct OutBuffer; -struct Module; -struct Package; -struct AliasDeclaration; +class Module; +class Package; +class AliasDeclaration; struct HdrGenState; -struct Import : Dsymbol +class Import : public Dsymbol { +public: + /* static import aliasId = pkg1.pkg2.id : alias1 = name1, alias2 = name2; + */ + Identifiers *packages; // array of Identifier's representing packages Identifier *id; // module Identifier Identifier *aliasId; int isstatic; // !=0 if static import - enum PROT protection; + PROT protection; // Pairs of alias=name to bind into current namespace Identifiers names; Identifiers aliases; - AliasDeclarations aliasdecls; // AliasDeclarations for names/aliases - - Module *mod; - Package *pkg; // leftmost package/module - Import(Loc loc, Identifiers *packages, Identifier *id, Identifier *aliasId, int isstatic); void addAlias(Identifier *name, Identifier *alias); + AliasDeclarations aliasdecls; // corresponding AliasDeclarations for alias=name pairs + + Module *mod; + Package *pkg; // leftmost package/module + const char *kind(); - enum PROT prot(); + PROT prot(); Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees void load(Scope *sc); void importAll(Scope *sc); @@ -57,7 +61,7 @@ struct Import : Dsymbol Dsymbol *toAlias(); int addMember(Scope *sc, ScopeDsymbol *s, int memnum); Dsymbol *search(Loc loc, Identifier *ident, int flags); - int overloadInsert(Dsymbol *s); + bool overloadInsert(Dsymbol *s); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void toJson(JsonOut *json); diff --git a/dmd2/init.c b/dmd2/init.c index 0bbe76aa..b25e4da3 100644 --- a/dmd2/init.c +++ b/dmd2/init.c @@ -68,10 +68,10 @@ char *Initializer::toChars() { HdrGenState hgs; - memset(&hgs, 0, sizeof(hgs)); - OutBuffer *buf = new OutBuffer(); - toCBuffer(buf, &hgs); - return buf->toChars(); + OutBuffer buf; + toCBuffer(&buf, &hgs); + buf.writebyte(0); + return buf.extractData(); } /********************************** ErrorInitializer ***************************/ @@ -132,8 +132,7 @@ Initializer *VoidInitializer::semantic(Scope *sc, Type *t, NeedInterpret needInt Expression *VoidInitializer::toExpression(Type *t) { - error(loc, "void initializer has no value"); - return new ErrorExp(); + return NULL; } @@ -148,10 +147,6 @@ void VoidInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs) StructInitializer::StructInitializer(Loc loc) : Initializer(loc) { - ad = NULL; -#if IN_LLVM - ltype = NULL; -#endif } Initializer *StructInitializer::syntaxCopy() @@ -181,101 +176,30 @@ void StructInitializer::addInit(Identifier *field, Initializer *value) Initializer *StructInitializer::semantic(Scope *sc, Type *t, NeedInterpret needInterpret) { - int errors = 0; - //printf("StructInitializer::semantic(t = %s) %s\n", t->toChars(), toChars()); - vars.setDim(field.dim); t = t->toBasetype(); if (t->ty == Tsarray && t->nextOf()->toBasetype()->ty == Tstruct) t = t->nextOf()->toBasetype(); if (t->ty == Tstruct) { - size_t fieldi = 0; - - TypeStruct *ts = (TypeStruct *)t; - ad = ts->sym; - if (ad->ctor) + StructDeclaration *sd = ((TypeStruct *)t)->sym; + if (sd->ctor) + { error(loc, "%s %s has constructors, cannot use { initializers }, use %s( initializers ) instead", - ad->kind(), ad->toChars(), ad->toChars()); - StructDeclaration *sd = ad->isStructDeclaration(); - assert(sd); - sd->size(loc); - if (sd->sizeok != SIZEOKdone) - { - error(loc, "struct %s is forward referenced", sd->toChars()); - errors = 1; - goto Lerror; + sd->kind(), sd->toChars(), sd->toChars()); + return new ErrorInitializer(); } - size_t nfields = sd->fields.dim - sd->isNested(); - for (size_t i = 0; i < field.dim; i++) - { - Identifier *id = field[i]; - Initializer *val = value[i]; - Dsymbol *s; - VarDeclaration *v; - if (id == NULL) - { - if (fieldi >= nfields) - { error(loc, "too many initializers for %s", ad->toChars()); - errors = 1; - field.remove(i); - i--; - continue; - } - else - { - s = ad->fields[fieldi]; - } - } - else - { - //s = ad->symtab->lookup(id); - s = ad->search(loc, id, 0); - if (!s) - { - s = ad->search_correct(id); - if (s) - error(loc, "'%s' is not a member of '%s', did you mean '%s %s'?", - id->toChars(), t->toChars(), s->kind(), s->toChars()); - else - error(loc, "'%s' is not a member of '%s'", id->toChars(), t->toChars()); - errors = 1; - continue; - } - s = s->toAlias(); + Expression *e = fill(sc, t, needInterpret); + if (e->op == TOKerror) + return new ErrorInitializer(); - // Find out which field index it is - for (fieldi = 0; 1; fieldi++) - { - if (fieldi >= nfields) - { - error(loc, "%s.%s is not a per-instance initializable field", - t->toChars(), s->toChars()); - errors = 1; - break; - } - if (s == ad->fields[fieldi]) - break; - } - } - if (s && (v = s->isVarDeclaration()) != NULL) - { - val = val->semantic(sc, v->type->addMod(t->mod), needInterpret); - value[i] = val; - vars[i] = v; - if (val->isErrorInitializer()) - errors = 1; - } - else - { error(loc, "%s is not a field of %s", id ? id->toChars() : s->toChars(), ad->toChars()); - errors = 1; - } - fieldi++; - } + ExpInitializer *ie = new ExpInitializer(loc, e); + return ie->semantic(sc, t, needInterpret); } else if (t->ty == Tdelegate && value.dim == 0) - { /* Rewrite as empty delegate literal { } + { + /* Rewrite as empty delegate literal { } */ Parameters *arguments = new Parameters; Type *tf = new TypeFunction(arguments, NULL, 0, LINKd); @@ -286,17 +210,9 @@ Initializer *StructInitializer::semantic(Scope *sc, Type *t, NeedInterpret needI ExpInitializer *ie = new ExpInitializer(loc, e); return ie->semantic(sc, t, needInterpret); } - else - { - error(loc, "a struct is not a valid initializer for a %s", t->toChars()); - errors = 1; - } -Lerror: - if (errors) - { - return new ErrorInitializer(); - } - return this; + + error(loc, "a struct is not a valid initializer for a %s", t->toChars()); + return new ErrorInitializer(); } /*************************************** @@ -305,34 +221,42 @@ Lerror: * same thing. */ Expression *StructInitializer::toExpression(Type *t) -{ Expression *e; - size_t offset; +{ + // cannot convert to an expression without target 'ad' + return NULL; +} - //printf("StructInitializer::toExpression() %s\n", toChars()); - if (!ad) // if fwd referenced - return NULL; - StructDeclaration *sd = ad->isStructDeclaration(); - if (!sd) - return NULL; +Expression *StructInitializer::fill(Scope *sc, Type *t, NeedInterpret needInterpret) +{ + //printf("StructInitializer::fill(sc = %p, '%s')\n", sc, toChars()); + assert(t->ty == Tstruct); + StructDeclaration *sd = ((TypeStruct *)t)->sym; + sd->size(loc); + if (sd->sizeok != SIZEOKdone) + return new ErrorExp(); + size_t nfields = sd->fields.dim - sd->isNested(); Expressions *elements = new Expressions(); - size_t nfields = ad->fields.dim - sd->isNested(); elements->setDim(nfields); for (size_t i = 0; i < elements->dim; i++) - { (*elements)[i] = NULL; - } - size_t fieldi = 0; - for (size_t i = 0; i < value.dim; i++) + + // Run semantic for explicitly given initializers + bool errors = false; + for (size_t fieldi = 0, i = 0; i < field.dim; i++) { - Identifier *id = field[i]; - if (id) + if (Identifier *id = field[i]) { - Dsymbol * s = ad->search(loc, id, 0); + Dsymbol *s = sd->search(loc, id, 0); if (!s) { - error(loc, "'%s' is not a member of '%s'", id->toChars(), sd->toChars()); - goto Lerror; + s = sd->search_correct(id); + if (s) + error(loc, "'%s' is not a member of '%s', did you mean '%s %s'?", + id->toChars(), sd->toChars(), s->kind(), s->toChars()); + else + error(loc, "'%s' is not a member of '%s'", id->toChars(), sd->toChars()); + return new ErrorExp(); } s = s->toAlias(); @@ -341,126 +265,155 @@ Expression *StructInitializer::toExpression(Type *t) { if (fieldi >= nfields) { - s->error("is not a per-instance initializable field"); - goto Lerror; + error(loc, "%s.%s is not a per-instance initializable field", + sd->toChars(), s->toChars()); + return new ErrorExp(); } - if (s == ad->fields[fieldi]) + if (s == sd->fields[fieldi]) break; } } else if (fieldi >= nfields) - { error(loc, "too many initializers for '%s'", ad->toChars()); - goto Lerror; + { + error(loc, "too many initializers for %s", sd->toChars()); + return new ErrorExp(); } - Initializer *iz = value[i]; - if (!iz) - goto Lno; - Expression *ex = iz->toExpression(); - if (!ex) - goto Lno; + + VarDeclaration *vd = sd->fields[fieldi]; if ((*elements)[fieldi]) - { error(loc, "duplicate initializer for field '%s'", - ad->fields[fieldi]->toChars()); - goto Lerror; + { + error(loc, "duplicate initializer for field '%s'", vd->toChars()); + errors = true; + continue; } + for (size_t j = 0; j < nfields; j++) + { + VarDeclaration *v2 = sd->fields[j]; + bool overlap = (vd->offset < v2->offset + v2->type->size() && + v2->offset < vd->offset + vd->type->size()); + if (overlap && (*elements)[j]) + { + error(loc, "overlapping initialization for field %s and %s", + v2->toChars(), vd->toChars()); + errors = true; + continue; + } + } + + assert(sc); + Initializer *iz = value[i]; + iz = iz->semantic(sc, vd->type->addMod(t->mod), needInterpret); + Expression *ex = iz->toExpression(); + if (ex->op == TOKerror) + { + errors = true; + continue; + } + value[i] = iz; (*elements)[fieldi] = ex; ++fieldi; } - // Now, fill in any missing elements with default initializers. - // We also need to validate any anonymous unions - offset = 0; - for (size_t i = 0; i < elements->dim; ) - { - VarDeclaration * vd = ad->fields[i]->isVarDeclaration(); + if (errors) + return new ErrorExp(); - //printf("test2 [%d] : %s %d %d\n", i, vd->toChars(), (int)offset, (int)vd->offset); - if (vd->offset < offset) + // Fill in missing any elements with default initializers + for (size_t i = 0; i < elements->dim; i++) + { + if ((*elements)[i]) + continue; + VarDeclaration *vd = sd->fields[i]; + VarDeclaration *vx = vd; + if (vd->init && vd->init->isVoidInitializer()) + vx = NULL; + // Find overlapped fields with the hole [vd->offset .. vd->offset->size()]. + size_t fieldi = i; + for (size_t j = 0; j < nfields; j++) { - // Only the first field of a union can have an initializer - if ((*elements)[i]) - goto Lno; + if (i == j) + continue; + VarDeclaration *v2 = sd->fields[j]; + if (v2->init && v2->init->isVoidInitializer()) + continue; + + bool overlap = (vd->offset < v2->offset + v2->type->size() && + v2->offset < vd->offset + vd->type->size()); + if (!overlap) + continue; + + if ((*elements)[j]) + { + vx = NULL; + break; + } + + #if 1 + /* Prefer first found non-void-initialized field + * union U { int a; int b = 2; } + * U u; // Error: overlapping initialization for field a and b + */ + if (!vx) + vx = v2, fieldi = j; + else if (v2->init) + { + error(loc, "overlapping initialization for field %s and %s", + v2->toChars(), vd->toChars()); + } + #else // fix Bugzilla 1432 + /* Prefer explicitly initialized field + * union U { int a; int b = 2; } + * U u; // OK (u.b == 2) + */ + if (!vx || !vx->init && v2->init) + vx = v2, fieldi = j; + else if (vx->init && v2->init) + { + error(loc, "overlapping default initialization for field %s and %s", + v2->toChars(), vd->toChars()); + } + else + assert(vx->init || !vx->init && !v2->init); + #endif } - else + if (vx) { - if (!(*elements)[i]) - { // Default initialize - if (vd->init) + if (vx->init) + { + assert(!vx->init->isVoidInitializer()); + if (vx->scope) { - if (vd->scope) - { // Do deferred semantic analysis - Initializer *i2 = vd->init->syntaxCopy(); - i2 = i2->semantic(vd->scope, vd->type, INITinterpret); - (*elements)[i] = i2->toExpression(); - if (!global.gag) - { vd->scope = NULL; - vd->init = i2; // save result - } + // Do deferred semantic analysis + Initializer *i2 = vx->init->syntaxCopy(); + i2 = i2->semantic(vx->scope, vx->type, INITinterpret); + (*elements)[fieldi] = i2->toExpression(); + if (!global.gag) + { + vx->scope = NULL; + vx->init = i2; // save result } - else - (*elements)[i] = vd->init->toExpression(); } else - (*elements)[i] = vd->type->defaultInit(); + (*elements)[fieldi] = vx->init->toExpression(); } + else + (*elements)[fieldi] = vx->type->defaultInit(); } - offset = vd->offset + vd->type->size(); - i++; -#if 0 - int unionSize = ad->numFieldsInUnion(i); - if (unionSize == 1) - { // Not a union -- default initialize if missing - if (!(*elements)[i]) - (*elements)[i] = vd->type->defaultInit(); - } - else - { // anonymous union -- check for errors - int found = -1; // index of the first field with an initializer - for (size_t j = i; j < i + unionSize; ++j) - { - if (!(*elements)[j]) - continue; - if (found >= 0) - { - VarDeclaration * v1 = ((Dsymbol *)ad->fields.data[found])->isVarDeclaration(); - VarDeclaration * v = ((Dsymbol *)ad->fields.data[j])->isVarDeclaration(); - error(loc, "%s cannot have initializers for fields %s and %s in same union", - ad->toChars(), - v1->toChars(), v->toChars()); - goto Lerror; - } - found = j; - } - if (found == -1) - { - error(loc, "no initializer for union that contains field %s", - vd->toChars()); - goto Lerror; - } - } - i += unionSize; -#endif } for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (*elements)[i]; + { + Expression *e = (*elements)[i]; if (e && e->op == TOKerror) return e; } - e = new StructLiteralExp(loc, sd, elements); - e->type = sd->type; + Expression *e = new StructLiteralExp(loc, sd, elements, t); + if (sc) + e = e->semantic(sc); + else + e->type = sd->type; // from glue layer return e; - -Lno: - delete elements; - return NULL; - -Lerror: - delete elements; - return new ErrorExp(); } - void StructInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { //printf("StructInitializer::toCBuffer()\n"); @@ -561,7 +514,10 @@ Initializer *ArrayInitializer::semantic(Scope *sc, Type *t, NeedInterpret needIn { Expression *idx = index[i]; if (idx) - { idx = idx->ctfeSemantic(sc); + { + sc = sc->startCTFE(); + idx = idx->semantic(sc); + sc = sc->endCTFE(); idx = idx->ctfeInterpret(); index[i] = idx; length = idx->toInteger(); @@ -945,11 +901,10 @@ bool arrayHasNonConstPointers(Expressions *elems) Initializer *ExpInitializer::semantic(Scope *sc, Type *t, NeedInterpret needInterpret) { //printf("ExpInitializer::semantic(%s), type = %s\n", exp->toChars(), t->toChars()); - if (needInterpret) - exp = exp->ctfeSemantic(sc); - else - exp = exp->semantic(sc); + if (needInterpret) sc = sc->startCTFE(); + exp = exp->semantic(sc); exp = resolveProperties(sc, exp); + if (needInterpret) sc = sc->endCTFE(); if (exp->op == TOKerror) return this; @@ -1066,17 +1021,17 @@ Type *ExpInitializer::inferType(Scope *sc) // Give error for overloaded function addresses if (exp->op == TOKsymoff) - { SymOffExp *se = (SymOffExp *)exp; + { + SymOffExp *se = (SymOffExp *)exp; if (se->hasOverloads && !se->var->isFuncDeclaration()->isUnique()) { exp->error("cannot infer type from overloaded function symbol %s", exp->toChars()); return Type::terror; } } - - // Give error for overloaded function addresses if (exp->op == TOKdelegate) - { DelegateExp *se = (DelegateExp *)exp; + { + DelegateExp *se = (DelegateExp *)exp; if (se->hasOverloads && se->func->isFuncDeclaration() && !se->func->isFuncDeclaration()->isUnique()) @@ -1085,6 +1040,15 @@ Type *ExpInitializer::inferType(Scope *sc) return Type::terror; } } + if (exp->op == TOKaddress) + { + AddrExp *ae = (AddrExp *)exp; + if (ae->e1->op == TOKoverloadset) + { + exp->error("cannot infer type from overloaded function symbol %s", exp->toChars()); + return Type::terror; + } + } Type *t = exp->type; if (!t) diff --git a/dmd2/init.h b/dmd2/init.h index ba3b5683..de545ff4 100644 --- a/dmd2/init.h +++ b/dmd2/init.h @@ -16,17 +16,17 @@ #include "mars.h" #include "arraytypes.h" -struct Identifier; -struct Expression; +class Identifier; +class Expression; struct Scope; -struct Type; +class Type; struct dt_t; -struct AggregateDeclaration; -struct ErrorInitializer; -struct VoidInitializer; -struct StructInitializer; -struct ArrayInitializer; -struct ExpInitializer; +class AggregateDeclaration; +class ErrorInitializer; +class VoidInitializer; +class StructInitializer; +class ArrayInitializer; +class ExpInitializer; struct HdrGenState; #if IN_LLVM @@ -37,8 +37,9 @@ namespace llvm { enum NeedInterpret { INITnointerpret, INITinterpret }; -struct Initializer : Object +class Initializer : public RootObject { +public: Loc loc; Initializer(Loc loc); @@ -63,8 +64,9 @@ struct Initializer : Object virtual ExpInitializer *isExpInitializer() { return NULL; } }; -struct VoidInitializer : Initializer +class VoidInitializer : public Initializer { +public: Type *type; // type that this will initialize to VoidInitializer(Loc loc); @@ -80,8 +82,9 @@ struct VoidInitializer : Initializer virtual VoidInitializer *isVoidInitializer() { return this; } }; -struct ErrorInitializer : Initializer +class ErrorInitializer : public Initializer { +public: ErrorInitializer(); Initializer *syntaxCopy(); Initializer *semantic(Scope *sc, Type *t, NeedInterpret needInterpret); @@ -91,19 +94,18 @@ struct ErrorInitializer : Initializer virtual ErrorInitializer *isErrorInitializer() { return this; } }; -struct StructInitializer : Initializer +class StructInitializer : public Initializer { +public: Identifiers field; // of Identifier *'s Initializers value; // parallel array of Initializer *'s - VarDeclarations vars; // parallel array of VarDeclaration *'s - AggregateDeclaration *ad; // which aggregate this is for - StructInitializer(Loc loc); Initializer *syntaxCopy(); void addInit(Identifier *field, Initializer *value); Initializer *semantic(Scope *sc, Type *t, NeedInterpret needInterpret); Expression *toExpression(Type *t = NULL); + Expression *fill(Scope *sc, Type *t, NeedInterpret needInterpret); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); #if IN_DMD @@ -111,13 +113,11 @@ struct StructInitializer : Initializer #endif StructInitializer *isStructInitializer() { return this; } -#if IN_LLVM - llvm::StructType *ltype; -#endif }; -struct ArrayInitializer : Initializer +class ArrayInitializer : public Initializer { +public: Expressions index; // indices Initializers value; // of Initializer *'s size_t dim; // length of array being initialized @@ -141,8 +141,9 @@ struct ArrayInitializer : Initializer ArrayInitializer *isArrayInitializer() { return this; } }; -struct ExpInitializer : Initializer +class ExpInitializer : public Initializer { +public: Expression *exp; int expandTuples; diff --git a/dmd2/inline.c b/dmd2/inline.c index 8f982203..07f07c58 100644 --- a/dmd2/inline.c +++ b/dmd2/inline.c @@ -293,7 +293,7 @@ int DeclarationExp::inlineCost3(InlineCostState *ics) return COST_MAX; // finish DeclarationExp::doInline #else for (size_t i = 0; i < td->objects->dim; i++) - { Object *o = (*td->objects)[i]; + { RootObject *o = (*td->objects)[i]; if (o->dyncast() != DYNCAST_EXPRESSION) return COST_MAX; Expression *eo = (Expression *)o; @@ -665,11 +665,69 @@ Expression *VarExp::doInline(InlineDoState *ids) } } if (ids->fd && var == ids->fd->vthis) - { VarExp *ve = new VarExp(loc, ids->vthis); + { + VarExp *ve = new VarExp(loc, ids->vthis); ve->type = type; return ve; } + /* Inlining context pointer access for nested referenced variables. + * For example: + * auto fun() { + * int i = 40; + * auto foo() { + * int g = 2; + * struct Result { + * auto bar() { return i + g; } + * } + * return Result(); + * } + * return foo(); + * } + * auto t = fun(); + * 'i' and 'g' are nested referenced variables in Result.bar(), so: + * auto x = t.bar(); + * should be inlined to: + * auto x = *(t.vthis.vthis + i->voffset) + *(t.vthis + g->voffset) + */ + VarDeclaration *v = var->isVarDeclaration(); + if (v && v->nestedrefs.dim && ids->vthis) + { + Dsymbol *s = ids->fd; + FuncDeclaration *fdv = v->toParent()->isFuncDeclaration(); + assert(fdv); + Expression *ve = new VarExp(loc, ids->vthis); + ve->type = ids->vthis->type; + while (s != fdv) + { + FuncDeclaration *f = s->isFuncDeclaration(); + if (AggregateDeclaration *ad = s->isThis()) + { + assert(ad->vthis); + ve = new DotVarExp(loc, ve, ad->vthis); + ve->type = ad->vthis->type; + s = ad->toParent2(); + } + else if (f && f->isNested()) + { + assert(f->vthis); + if (f->hasNestedFrameRefs()) + { + ve = new DotVarExp(loc, ve, f->vthis); + ve->type = f->vthis->type; + } + s = f->toParent2(); + } + else + assert(0); + assert(s); + } + ve = new DotVarExp(loc, ve, v); + ve->type = v->type; + //printf("\t==> ve = %s, type = %s\n", ve->toChars(), ve->type->toChars()); + return ve; + } + return this; } @@ -724,7 +782,7 @@ Expression *DeclarationExp::doInline(InlineDoState *ids) VarDeclaration *vto; vto = new VarDeclaration(vd->loc, vd->type, vd->ident, vd->init); - *vto = *vd; + memcpy((void*)vto, (void*)vd, sizeof(VarDeclaration)); vto->parent = ids->parent; #if IN_DMD vto->csym = NULL; @@ -820,7 +878,7 @@ Expression *IndexExp::doInline(InlineDoState *ids) VarDeclaration *vto; vto = new VarDeclaration(vd->loc, vd->type, vd->ident, vd->init); - *vto = *vd; + memcpy((void*)vto, (void*)vd, sizeof(VarDeclaration)); vto->parent = ids->parent; #if IN_DMD vto->csym = NULL; @@ -859,7 +917,7 @@ Expression *SliceExp::doInline(InlineDoState *ids) VarDeclaration *vto; vto = new VarDeclaration(vd->loc, vd->type, vd->ident, vd->init); - *vto = *vd; + memcpy((void*)vto, (void*)vd, sizeof(VarDeclaration)); vto->parent = ids->parent; #if IN_DMD vto->csym = NULL; @@ -1133,12 +1191,7 @@ Statement *ReturnStatement::inlineScan(InlineScanState *iss) { //printf("ReturnStatement::inlineScan()\n"); if (exp) - { exp = exp->inlineScan(iss); - - FuncDeclaration *func = iss->fd; - TypeFunction *tf = (TypeFunction *)(func->type); - } return this; } @@ -1230,6 +1283,7 @@ Expression *Expression::inlineScan(InlineScanState *iss) void scanVar(Dsymbol *s, InlineScanState *iss) { + //printf("scanVar(%s %s)\n", s->kind(), s->toPrettyChars()); VarDeclaration *vd = s->isVarDeclaration(); if (vd) { @@ -1281,6 +1335,10 @@ void scanVar(Dsymbol *s, InlineScanState *iss) } } } + else + { + s->inlineScan(); + } } Expression *DeclarationExp::inlineScan(InlineScanState *iss) @@ -1438,7 +1496,7 @@ void FuncDeclaration::inlineScan() InlineScanState iss; #if LOG - printf("FuncDeclaration::inlineScan('%s')\n", toChars()); + printf("FuncDeclaration::inlineScan('%s')\n", toPrettyChars()); #endif memset(&iss, 0, sizeof(iss)); iss.fd = this; @@ -1458,7 +1516,7 @@ int FuncDeclaration::canInline(int hasthis, int hdrscan, int statementsToo) #define CANINLINE_LOG 0 #if CANINLINE_LOG - printf("FuncDeclaration::canInline(hasthis = %d, statementsToo = %d, '%s')\n", hasthis, statementsToo, toChars()); + printf("FuncDeclaration::canInline(hasthis = %d, statementsToo = %d, '%s')\n", hasthis, statementsToo, toPrettyChars()); #endif if (needThis() && !hasthis) @@ -1535,10 +1593,8 @@ int FuncDeclaration::canInline(int hasthis, int hdrscan, int statementsToo) #endif isSynchronized() || isImportedSymbol() || -//#if !IN_LLVM hasNestedFrameRefs() || // no nested references to this frame -//#endif // !IN_LLVM - (isVirtual() && !isFinal()) + (isVirtual() && !isFinalFunc()) )) { goto Lno; @@ -1749,6 +1805,7 @@ Expression *FuncDeclaration::expandInline(InlineScanState *iss, Expression *ethi //eb->print(); //eb->dump(0); } + //printf("%s->expandInline = { %s }\n", toChars(), e->toChars()); /* There's a problem if what the function returns is used subsequently as an * lvalue, as in a struct return that is then used as a 'this'. diff --git a/dmd2/interpret.c b/dmd2/interpret.c index 3876b033..35b5d876 100644 --- a/dmd2/interpret.c +++ b/dmd2/interpret.c @@ -33,6 +33,7 @@ #define LOG 0 #define LOGASSIGN 0 +#define LOGCOMPILE 0 #define SHOWPERFORMANCE 0 // Maximum allowable recursive function calls in CTFE @@ -53,13 +54,13 @@ private: the stack might not be empty when CTFE begins. Ctfe Stack addresses are just 0-based integers, but we save - them as 'void *' because ArrayBase can only do pointers. + them as 'void *' because Array can only do pointers. */ Expressions values; // values on the stack VarDeclarations vars; // corresponding variables - ArrayBase savedId; // id of the previous state of that var + Array savedId; // id of the previous state of that var - ArrayBase frames; // all previous frame pointers + Array frames; // all previous frame pointers Expressions savedThis; // all previous values of localThis /* Global constants get saved here after evaluation, so we never @@ -263,6 +264,418 @@ Expression *evaluateIfBuiltin(InterState *istate, Loc loc, FuncDeclaration *fd, Expressions *arguments, Expression *pthis); Expression *scrubReturnValue(Loc loc, Expression *e); + + +/************************************* + * CTFE-object code for a single function + * + * Currently only counts the number of local variables in the function + */ +struct CompiledCtfeFunction +{ + FuncDeclaration *func; // Function being compiled, NULL if global scope + int numVars; // Number of variables declared in this function + Loc callingloc; + + CompiledCtfeFunction(FuncDeclaration *f) + { + func = f; + numVars = 0; + } + + void onDeclaration(VarDeclaration *v) + { + //printf("%s CTFE declare %s\n", v->loc.toChars(), v->toChars()); + ++numVars; + } + static int walkAllVars(Expression *e, void *_this); + void onExpression(Expression *e) + { + e->apply(&walkAllVars, this); + } +}; + +int CompiledCtfeFunction::walkAllVars(Expression *e, void *_this) +{ + CompiledCtfeFunction *ccf = (CompiledCtfeFunction *)_this; + if (e->op == TOKerror) + { + // Currently there's a front-end bug: silent errors + // can occur inside delegate literals inside is(typeof()). + // Suppress the check in this case. + if (global.gag && ccf->func) + return 1; + + printf("CTFE: ErrorExp in %s\n", ccf->func ? ccf->func->loc.toChars() : ccf->callingloc.toChars()); + assert(0); + } + if (e->op == TOKdeclaration) + { + DeclarationExp *decl = (DeclarationExp *)e; + VarDeclaration *v = decl->declaration->isVarDeclaration(); + if (!v) + return 0; + TupleDeclaration *td = v->toAlias()->isTupleDeclaration(); + if (td) + { + if (!td->objects) + return 0; + for(size_t i= 0; i < td->objects->dim; ++i) + { + RootObject *o = td->objects->tdata()[i]; + Expression *ex = isExpression(o); + DsymbolExp *s = (ex && ex->op == TOKdsymbol) ? (DsymbolExp *)ex : NULL; + assert(s); + VarDeclaration *v2 = s->s->isVarDeclaration(); + assert(v2); + if (!v2->isDataseg() || v2->isCTFE()) + ccf->onDeclaration(v2); + } + } + else if (!(v->isDataseg() || v->storage_class & STCmanifest) || v->isCTFE()) + ccf->onDeclaration(v); + Dsymbol *s = v->toAlias(); + if (s == v && !v->isStatic() && v->init) + { + ExpInitializer *ie = v->init->isExpInitializer(); + if (ie) + ccf->onExpression(ie->exp); + } + } + else if (e->op == TOKindex && ((IndexExp *)e)->lengthVar) + ccf->onDeclaration( ((IndexExp *)e)->lengthVar); + else if (e->op == TOKslice && ((SliceExp *)e)->lengthVar) + ccf->onDeclaration( ((SliceExp *)e)->lengthVar); + return 0; +} + +void Statement::ctfeCompile(CompiledCtfeFunction *ccf) +{ +#if LOGCOMPILE + printf("%s Statement::ctfeCompile %s\n", loc.toChars(), toChars()); +#endif + assert(0); +} + +void ExpStatement::ctfeCompile(CompiledCtfeFunction *ccf) +{ +#if LOGCOMPILE + printf("%s ExpStatement::ctfeCompile\n", loc.toChars()); +#endif + if (exp) + ccf->onExpression(exp); +} + +void CompoundStatement::ctfeCompile(CompiledCtfeFunction *ccf) +{ +#if LOGCOMPILE + printf("%s CompoundStatement::ctfeCompile\n", loc.toChars()); +#endif + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (*statements)[i]; + if (s) + s->ctfeCompile(ccf); + } +} + +void UnrolledLoopStatement::ctfeCompile(CompiledCtfeFunction *ccf) +{ +#if LOGCOMPILE + printf("%s UnrolledLoopStatement::ctfeCompile\n", loc.toChars()); +#endif + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (*statements)[i]; + if (s) + s->ctfeCompile(ccf); + } +} + +void IfStatement::ctfeCompile(CompiledCtfeFunction *ccf) +{ +#if LOGCOMPILE + printf("%s IfStatement::ctfeCompile\n", loc.toChars()); +#endif + + ccf->onExpression(condition); + if (ifbody) + ifbody->ctfeCompile(ccf); + if (elsebody) + elsebody->ctfeCompile(ccf); +} + +void ScopeStatement::ctfeCompile(CompiledCtfeFunction *ccf) +{ +#if LOGCOMPILE + printf("%s ScopeStatement::ctfeCompile\n", loc.toChars()); +#endif + if (statement) + statement->ctfeCompile(ccf); +} + +void OnScopeStatement::ctfeCompile(CompiledCtfeFunction *ccf) +{ +#if LOGCOMPILE + printf("%s OnScopeStatement::ctfeCompile\n", loc.toChars()); +#endif + // rewritten to try/catch/finally + assert(0); +} + +void DoStatement::ctfeCompile(CompiledCtfeFunction *ccf) +{ +#if LOGCOMPILE + printf("%s DoStatement::ctfeCompile\n", loc.toChars()); +#endif + ccf->onExpression(condition); + if (body) + body->ctfeCompile(ccf); +} + +void WhileStatement::ctfeCompile(CompiledCtfeFunction *ccf) +{ +#if LOGCOMPILE + printf("%s WhileStatement::ctfeCompile\n", loc.toChars()); +#endif + // rewritten to ForStatement + assert(0); +} + +void ForStatement::ctfeCompile(CompiledCtfeFunction *ccf) +{ +#if LOGCOMPILE + printf("%s ForStatement::ctfeCompile\n", loc.toChars()); +#endif + + if (init) + init->ctfeCompile(ccf); + if (condition) + ccf->onExpression(condition); + if (increment) + ccf->onExpression(increment); + if (body) + body->ctfeCompile(ccf); +} + +void ForeachStatement::ctfeCompile(CompiledCtfeFunction *ccf) +{ +#if LOGCOMPILE + printf("%s ForeachStatement::ctfeCompile\n", loc.toChars()); +#endif + // rewritten for ForStatement + assert(0); +} + + +void SwitchStatement::ctfeCompile(CompiledCtfeFunction *ccf) +{ +#if LOGCOMPILE + printf("%s SwitchStatement::ctfeCompile\n", loc.toChars()); +#endif + ccf->onExpression(condition); + // Note that the body contains the the Case and Default + // statements, so we only need to compile the expressions + for (size_t i = 0; i < cases->dim; i++) + { + ccf->onExpression((*cases)[i]->exp); + } + if (body) + body->ctfeCompile(ccf); +} + +void CaseStatement::ctfeCompile(CompiledCtfeFunction *ccf) +{ +#if LOGCOMPILE + printf("%s CaseStatement::ctfeCompile\n", loc.toChars()); +#endif + if (statement) + statement->ctfeCompile(ccf); +} + +void DefaultStatement::ctfeCompile(CompiledCtfeFunction *ccf) +{ +#if LOGCOMPILE + printf("%s DefaultStatement::ctfeCompile\n", loc.toChars()); +#endif + if (statement) + statement->ctfeCompile(ccf); +} + +void GotoDefaultStatement::ctfeCompile(CompiledCtfeFunction *ccf) +{ +#if LOGCOMPILE + printf("%s GotoDefaultStatement::ctfeCompile\n", loc.toChars()); +#endif +} + +void GotoCaseStatement::ctfeCompile(CompiledCtfeFunction *ccf) +{ +#if LOGCOMPILE + printf("%s GotoCaseStatement::ctfeCompile\n", loc.toChars()); +#endif +} + +void SwitchErrorStatement::ctfeCompile(CompiledCtfeFunction *ccf) +{ +#if LOGCOMPILE + printf("%s SwitchErrorStatement::ctfeCompile\n", loc.toChars()); +#endif +} + +void ReturnStatement::ctfeCompile(CompiledCtfeFunction *ccf) +{ +#if LOGCOMPILE + printf("%s ReturnStatement::ctfeCompile\n", loc.toChars()); +#endif + if (exp) + ccf->onExpression(exp); +} + +void BreakStatement::ctfeCompile(CompiledCtfeFunction *ccf) +{ +#if LOGCOMPILE + printf("%s BreakStatement::ctfeCompile\n", loc.toChars()); +#endif +} + +void ContinueStatement::ctfeCompile(CompiledCtfeFunction *ccf) +{ +#if LOGCOMPILE + printf("%s ContinueStatement::ctfeCompile\n", loc.toChars()); +#endif +} + +void WithStatement::ctfeCompile(CompiledCtfeFunction *ccf) +{ +#if LOGCOMPILE + printf("%s WithStatement::ctfeCompile\n", loc.toChars()); +#endif + // If it is with(Enum) {...}, just execute the body. + if (exp->op == TOKimport || exp->op == TOKtype) + {} + else + { + ccf->onDeclaration(wthis); + ccf->onExpression(exp); + } + if (body) + body->ctfeCompile(ccf); +} + +void TryCatchStatement::ctfeCompile(CompiledCtfeFunction *ccf) +{ +#if LOGCOMPILE + printf("%s TryCatchStatement::ctfeCompile\n", loc.toChars()); +#endif + if (body) + body->ctfeCompile(ccf); + for (size_t i = 0; i < catches->dim; i++) + { +#if DMDV1 + Catch *ca = (Catch *)catches->data[i]; +#else + Catch *ca = catches->tdata()[i]; +#endif + if (ca->var) + ccf->onDeclaration(ca->var); + if (ca->handler) + ca->handler->ctfeCompile(ccf); + } +} + +void TryFinallyStatement::ctfeCompile(CompiledCtfeFunction *ccf) +{ +#if LOGCOMPILE + printf("%s TryFinallyStatement::ctfeCompile\n", loc.toChars()); +#endif + if (body) + body->ctfeCompile(ccf); + if (finalbody) + finalbody->ctfeCompile(ccf); +} + +void ThrowStatement::ctfeCompile(CompiledCtfeFunction *ccf) +{ +#if LOGCOMPILE + printf("%s ThrowStatement::ctfeCompile\n", loc.toChars()); +#endif + ccf->onExpression(exp); +} + +void GotoStatement::ctfeCompile(CompiledCtfeFunction *ccf) +{ +#if LOGCOMPILE + printf("%s GotoStatement::ctfeCompile\n", loc.toChars()); +#endif +} + +void LabelStatement::ctfeCompile(CompiledCtfeFunction *ccf) +{ +#if LOGCOMPILE + printf("%s LabelStatement::ctfeCompile\n", loc.toChars()); +#endif + if (statement) + statement->ctfeCompile(ccf); +} + +#if DMDV2 +void ImportStatement::ctfeCompile(CompiledCtfeFunction *ccf) +{ +#if LOGCOMPILE + printf("%s ImportStatement::ctfeCompile\n", loc.toChars()); +#endif + // Contains no variables or executable code +} + +void ForeachRangeStatement::ctfeCompile(CompiledCtfeFunction *ccf) +{ +#if LOGCOMPILE + printf("%s ForeachRangeStatement::ctfeCompile\n", loc.toChars()); +#endif + // rewritten for ForStatement + assert(0); +} + +#endif + +void AsmStatement::ctfeCompile(CompiledCtfeFunction *ccf) +{ +#if LOGCOMPILE + printf("%s AsmStatement::ctfeCompile\n", loc.toChars()); +#endif + // we can't compile asm statements +} + +/************************************* + * Compile this function for CTFE. + * At present, this merely allocates variables. + */ +void FuncDeclaration::ctfeCompile() +{ +#if LOGCOMPILE + printf("\n%s FuncDeclaration::ctfeCompile %s\n", loc.toChars(), toChars()); +#endif + assert(!ctfeCode); + assert(!semantic3Errors); + assert(semanticRun == PASSsemantic3done); + + ctfeCode = new CompiledCtfeFunction(this); + if (parameters) + { + Type *tb = type->toBasetype(); + assert(tb->ty == Tfunction); + TypeFunction *tf = (TypeFunction *)tb; + for (size_t i = 0; i < parameters->dim; i++) + { + Parameter *arg = Parameter::getNth(tf->parameters, i); + VarDeclaration *v = (*parameters)[i]; + ctfeCode->onDeclaration(v); + } + } + if (vresult) + ctfeCode->onDeclaration(vresult); + fbody->ctfeCompile(ctfeCode); +} + /************************************* * * Entry point for CTFE. @@ -270,9 +683,75 @@ Expression *scrubReturnValue(Loc loc, Expression *e); */ Expression *Expression::ctfeInterpret() { - return optimize(WANTvalue | WANTinterpret); + if (type == Type::terror) + return this; + + // This code is outside a function, but still needs to be compiled + // (there are compiler-generated temporary variables such as __dollar). + // However, this will only be run once and can then be discarded. + CompiledCtfeFunction ctfeCodeGlobal(NULL); + ctfeCodeGlobal.callingloc = loc; + ctfeCodeGlobal.onExpression(this); + + Expression *e = interpret(NULL); + if (e != EXP_CANT_INTERPRET) + e = scrubReturnValue(loc, e); + if (e == EXP_CANT_INTERPRET) + e = new ErrorExp(); + return e; } +/* Run CTFE on the expression, but allow the expression to be a TypeExp + * or a tuple containing a TypeExp. (This is required by pragma(msg)). + */ +Expression *ctfeInterpretForPragmaMsg(Expression *e) +{ + if (e->op == TOKerror || e->op == TOKtype) + return e; + + // It's also OK for it to be a function declaration (happens only with + // __traits(getOverloads)) + if (e->op == TOKvar && ((VarExp *)e)->var->isFuncDeclaration()) + { + return e; + } + + if (e->op != TOKtuple) + return e->ctfeInterpret(); + + // Tuples need to be treated seperately, since they are + // allowed to contain a TypeExp in this case. + + TupleExp *tup = (TupleExp *)e; + Expressions *expsx = NULL; + for (size_t i = 0; i < tup->exps->dim; ++i) + { + Expression *g = (*tup->exps)[i]; + Expression *h = g; + h = ctfeInterpretForPragmaMsg(g); + if (h != g) + { + if (!expsx) + { + expsx = new Expressions(); + expsx->setDim(tup->exps->dim); + for (size_t j = 0; j < tup->exps->dim; j++) + (*expsx)[j] = (*tup->exps)[j]; + } + (*expsx)[i] = h; + } + } + if (expsx) + { + TupleExp *te = new TupleExp(e->loc, expsx); + expandTuples(te->exps); + te->type = new TypeTuple(te->exps); + return te; + } + return e; +} + + /************************************* * Attempt to interpret a function given the arguments. * Input: @@ -299,10 +778,13 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument if (semanticRun < PASSsemantic3done) return EXP_CANT_INTERPRET; + // CTFE-compile the function + if (!ctfeCode) + ctfeCompile(); + Type *tb = type->toBasetype(); assert(tb->ty == Tfunction); TypeFunction *tf = (TypeFunction *)tb; - Type *tret = tf->next->toBasetype(); if (tf->varargs && arguments && ((parameters && arguments->dim != parameters->dim) || (!parameters && arguments->dim))) { @@ -514,12 +996,6 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument return EXP_CANT_INTERPRET; } - // If we're about to leave CTFE, make sure we don't crash the - // compiler by returning a CTFE-internal expression. - if (!istate && !evaluatingArgs) - { - e = scrubReturnValue(loc, e); - } return e; } @@ -702,8 +1178,11 @@ bool stopPointersEscaping(Loc loc, Expression *e) return true; if ( isPointer(e->type) ) { - if (e->op == TOKvar && ((VarExp *)e)->var->isVarDeclaration() && - ctfeStack.isInCurrentFrame( ((VarExp *)e)->var->isVarDeclaration() ) ) + Expression *x = e; + if (e->op == TOKaddress) + x = ((AddrExp *)e)->e1; + if (x->op == TOKvar && ((VarExp *)x)->var->isVarDeclaration() && + ctfeStack.isInCurrentFrame( ((VarExp *)x)->var->isVarDeclaration() ) ) { error(loc, "returning a pointer to a local stack variable"); return false; } @@ -734,7 +1213,7 @@ bool stopPointersEscapingFromArray(Loc loc, Expressions *elems) { for (size_t i = 0; i < elems->dim; i++) { - Expression *m = elems->tdata()[i]; + Expression *m = (*elems)[i]; if (!m) continue; if (m) @@ -810,21 +1289,56 @@ Expression *scrubReturnValue(Loc loc, Expression *e) return e; } +// Return true if every element is either void, +// or is an array literal or struct literal of void elements. +bool isEntirelyVoid(Expressions *elems) +{ + for (size_t i = 0; i < elems->dim; i++) + { + Expression *m = (*elems)[i]; + // It can be NULL for performance reasons, + // see StructLiteralExp::interpret(). + if (!m) + continue; + + if (!(m->op == TOKvoid) && + !(m->op == TOKarrayliteral && isEntirelyVoid(((ArrayLiteralExp *)m)->elements)) && + !(m->op == TOKstructliteral && isEntirelyVoid(((StructLiteralExp *)m)->elements))) + { + return false; + } + } + return true; +} + // Scrub all members of an array. Return false if error bool scrubArray(Loc loc, Expressions *elems, bool structlit) { for (size_t i = 0; i < elems->dim; i++) { - Expression *m = elems->tdata()[i]; + Expression *m = (*elems)[i]; + // It can be NULL for performance reasons, + // see StructLiteralExp::interpret(). if (!m) continue; - if (m && m->op == TOKvoid && structlit) - m = NULL; - if (m) + + // A struct .init may contain void members. + // Static array members are a weird special case (bug 10994). + if (structlit && + ((m->op == TOKvoid) || + (m->op == TOKarrayliteral && m->type->ty == Tsarray && isEntirelyVoid(((ArrayLiteralExp *)m)->elements)) || + (m->op == TOKstructliteral && isEntirelyVoid(((StructLiteralExp *)m)->elements))) + ) + { + m = NULL; + } + else + { m = scrubReturnValue(loc, m); - if (m == EXP_CANT_INTERPRET) - return false; - elems->tdata()[i] = m; + if (m == EXP_CANT_INTERPRET) + return false; + } + (*elems)[i] = m; } return true; } @@ -869,21 +1383,19 @@ Expression *ReturnStatement::interpret(InterState *istate) { e = exp->interpret(istate, ctfeNeedLvalue); if (exceptionOrCantInterpret(e)) return e; - // Disallow returning pointers to stack-allocated variables (bug 7876) - if (e->op == TOKvar && ((VarExp *)e)->var->isVarDeclaration() && - ctfeStack.isInCurrentFrame( ((VarExp *)e)->var->isVarDeclaration() ) ) - { error("returning a pointer to a local stack variable"); - return EXP_CANT_INTERPRET; - } } else { e = exp->interpret(istate); if (exceptionOrCantInterpret(e)) return e; - if (!stopPointersEscaping(loc, e)) - return EXP_CANT_INTERPRET; } + + // Disallow returning pointers to stack-allocated variables (bug 7876) + + if (!stopPointersEscaping(loc, e)) + return EXP_CANT_INTERPRET; + if (needToCopyLiteral(e)) e = copyLiteral(e); #if LOGASSIGN @@ -900,13 +1412,19 @@ Expression *BreakStatement::interpret(InterState *istate) #endif START() if (ident) - { LabelDsymbol *label = istate->fd->searchLabel(ident); + { + LabelDsymbol *label = istate->fd->searchLabel(ident); assert(label && label->statement); - Statement *s = label->statement; - if (s->isLabelStatement()) - s = s->isLabelStatement()->statement; - if (s->isScopeStatement()) - s = s->isScopeStatement()->statement; + LabelStatement *ls = label->statement; + Statement *s; + if (ls->gotoTarget) + s = ls->gotoTarget; + else + { + s = ls->statement; + if (s->isScopeStatement()) + s = s->isScopeStatement()->statement; + } istate->gotoTarget = s; return EXP_BREAK_INTERPRET; } @@ -924,13 +1442,19 @@ Expression *ContinueStatement::interpret(InterState *istate) #endif START() if (ident) - { LabelDsymbol *label = istate->fd->searchLabel(ident); + { + LabelDsymbol *label = istate->fd->searchLabel(ident); assert(label && label->statement); - Statement *s = label->statement; - if (s->isLabelStatement()) - s = s->isLabelStatement()->statement; - if (s->isScopeStatement()) - s = s->isScopeStatement()->statement; + LabelStatement *ls = label->statement; + Statement *s; + if (ls->gotoTarget) + s = ls->gotoTarget; + else + { + s = ls->statement; + if (s->isScopeStatement()) + s = s->isScopeStatement()->statement; + } istate->gotoTarget = s; return EXP_CONTINUE_INTERPRET; } @@ -978,7 +1502,6 @@ Expression *DoStatement::interpret(InterState *istate) if (istate->gotoTarget && istate->gotoTarget != this) break; // continue at a higher level - Lcontinue: istate->gotoTarget = NULL; e = condition->interpret(istate); if (exceptionOrCantInterpret(e)) @@ -1240,7 +1763,7 @@ Expression *TryCatchStatement::interpret(InterState *istate) #if DMDV1 Catch *ca = (Catch *)catches->data[i]; #else - Catch *ca = catches->tdata()[i]; + Catch *ca = (*catches)[i]; #endif Type *catype = ca->type; @@ -1270,20 +1793,20 @@ ThrownExceptionExp *chainExceptions(ThrownExceptionExp *oldest, ThrownExceptionE #if DMDV2 // Little sanity check to make sure it's really a Throwable ClassReferenceExp *boss = oldest->thrown; - assert(boss->value->elements->tdata()[4]->type->ty == Tclass); + assert((*boss->value->elements)[4]->type->ty == Tclass); ClassReferenceExp *collateral = newest->thrown; if (isAnErrorException(collateral->originalClass()) && !isAnErrorException(boss->originalClass())) { // The new exception bypass the existing chain - assert(collateral->value->elements->tdata()[5]->type->ty == Tclass); - collateral->value->elements->tdata()[5] = boss; + assert((*collateral->value->elements)[5]->type->ty == Tclass); + (*collateral->value->elements)[5] = boss; return newest; } - while (boss->value->elements->tdata()[4]->op == TOKclassreference) + while ((*boss->value->elements)[4]->op == TOKclassreference) { - boss = (ClassReferenceExp *)(boss->value->elements->tdata()[4]); + boss = (ClassReferenceExp *)(*boss->value->elements)[4]; } - boss->value->elements->tdata()[4] = collateral; + (*boss->value->elements)[4] = collateral; return oldest; #else // for D1, the newest exception just clobbers the older one @@ -1487,7 +2010,6 @@ Expression *SymOffExp::interpret(InterState *istate, CtfeGoal goal) } // Check for taking an address of a shared variable. // If the shared variable is an array, the offset might not be zero. - VarDeclaration *vd = var->isVarDeclaration(); Type *fromType = NULL; if (var->type->ty == Tarray || var->type->ty == Tsarray) { @@ -1496,12 +2018,6 @@ Expression *SymOffExp::interpret(InterState *istate, CtfeGoal goal) if ( var->isDataseg() && ( (offset == 0 && isSafePointerCast(var->type, pointee)) || (fromType && isSafePointerCast(fromType, pointee)) - ) && !(vd && vd->init && -#if DMDV2 - (var->isConst() || var->isImmutable()) -#else - var>isConst() -#endif )) { return this; @@ -1535,7 +2051,6 @@ Expression *SymOffExp::interpret(InterState *istate, CtfeGoal goal) return EXP_CANT_INTERPRET; } - TypeArray *tar = (TypeArray *)val->type; dinteger_t sz = pointee->size(); dinteger_t indx = offset/sz; assert(sz * indx == offset); @@ -1558,9 +2073,12 @@ Expression *SymOffExp::interpret(InterState *istate, CtfeGoal goal) } else if ( offset == 0 && isSafePointerCast(var->type, pointee) ) { + // Create a CTFE pointer &var VarExp *ve = new VarExp(loc, var); - ve->type = type; - return ve; + ve->type = var->type; + AddrExp *re = new AddrExp(loc, ve); + re->type = type; + return re; } error("Cannot convert &%s to %s at compile time", var->type->toChars(), type->toChars()); @@ -1572,6 +2090,13 @@ Expression *AddrExp::interpret(InterState *istate, CtfeGoal goal) #if LOG printf("%s AddrExp::interpret() %s\n", loc.toChars(), toChars()); #endif + if (e1->op == TOKvar && ((VarExp *)e1)->var->isDataseg()) + { // Normally this is already done by optimize() + // Do it here in case optimize(0) wasn't run before CTFE + SymOffExp *se = new SymOffExp(loc, ((VarExp *)e1)->var, 0); + se->type = type; + return se; + } // For reference types, we need to return an lvalue ref. TY tb = e1->type->toBasetype()->ty; bool needRef = (tb == Tarray || tb == Taarray || tb == Tclass); @@ -1589,7 +2114,27 @@ Expression *DelegateExp::interpret(InterState *istate, CtfeGoal goal) #if LOG printf("%s DelegateExp::interpret() %s\n", loc.toChars(), toChars()); #endif - return this; + // TODO: Really we should create a CTFE-only delegate expression + // of a pointer and a funcptr. + + // If it is &nestedfunc, just return it + // TODO: We should save the context pointer + if (e1->op == TOKvar && ((VarExp *)e1)->var->isFuncDeclaration()) + return this; + + // If it has already been CTFE'd, just return it + if (e1->op == TOKstructliteral || e1->op == TOKclassreference) + return this; + + // Else change it into &structliteral.func or &classref.func + Expression *e = e1->interpret(istate, ctfeNeedLvalue); + + if (exceptionOrCantInterpret(e)) + return e; + + e = new DelegateExp(loc, e, func); + e->type = type; + return e; } @@ -1652,12 +2197,29 @@ Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal */ if (v->ident == Id::ctfe) return new IntegerExp(loc, 1, Type::tbool); + + if (!v->originalType && v->scope) // semantic() not yet run + { + v->semantic (v->scope); + if (v->type->ty == Terror) + return EXP_CANT_INTERPRET; + } + if ((v->isConst() || v->isImmutable() || v->storage_class & STCmanifest) && v->init && !v->hasValue() && !v->isCTFE()) #else if (v->isConst() && v->init && !v->isCTFE()) #endif - { e = v->init->toExpression(v->type); + { + if(v->scope) + v->init = v->init->semantic(v->scope, v->type, INITinterpret); // might not be run on aggregate members + e = v->init->toExpression(v->type); + if (v->inuse) + { + error(loc, "circular initialization of %s", v->toChars()); + return EXP_CANT_INTERPRET; + } + if (e && (e->op == TOKconstruct || e->op == TOKblit)) { AssignExp *ae = (AssignExp *)e; e = ae->e2; @@ -1675,14 +2237,19 @@ Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal if (e && !e->type) e->type = v->type; if (e) + { + v->inuse++; e = e->interpret(istate, ctfeNeedAnyValue); + v->inuse--; + } if (e == EXP_CANT_INTERPRET && !global.gag && !CtfeStatus::stackTraceCallsToSuppress) errorSupplemental(loc, "while evaluating %s.init", v->toChars()); } if (e && e != EXP_CANT_INTERPRET && e->op != TOKthrownexception) { e = copyLiteral(e); - ctfeStack.saveGlobalConstant(v, e); + if (v->isDataseg() || (v->storage_class & STCmanifest )) + ctfeStack.saveGlobalConstant(v, e); } } else if (v->isCTFE() && !v->hasValue()) @@ -1755,6 +2322,8 @@ Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal else if (s) { // Struct static initializers, for example e = s->dsym->type->defaultInitLiteral(loc); + if (e->op == TOKerror) + error(loc, "CTFE failed because of previous errors in %s.init", s->toChars()); e = e->semantic(NULL); if (e->op == TOKerror) e = EXP_CANT_INTERPRET; @@ -1815,7 +2384,7 @@ Expression *DeclarationExp::interpret(InterState *istate, CtfeGoal goal) return NULL; for(size_t i= 0; i < td->objects->dim; ++i) { - Object * o = td->objects->tdata()[i]; + RootObject * o = (*td->objects)[i]; Expression *ex = isExpression(o); DsymbolExp *s = (ex && ex->op == TOKdsymbol) ? (DsymbolExp *)ex : NULL; VarDeclaration *v2 = s ? s->s->isVarDeclaration() : NULL; @@ -1876,9 +2445,15 @@ Expression *DeclarationExp::interpret(InterState *istate, CtfeGoal goal) declaration->isTupleDeclaration()) { // Check for static struct declarations, which aren't executable AttribDeclaration *ad = declaration->isAttribDeclaration(); - if (ad && ad->decl && ad->decl->dim == 1 - && ad->decl->tdata()[0]->isAggregateDeclaration()) - return NULL; // static struct declaration. Nothing to do. + if (ad && ad->decl && ad->decl->dim == 1) + { + Dsymbol *s = (*ad->decl)[0]; + if (s->isAggregateDeclaration() || + s->isTemplateDeclaration()) + { + return NULL; // static (template) struct declaration. Nothing to do. + } + } // These can be made to work, too lazy now error("Declaration %s is not yet implemented in CTFE", toChars()); @@ -1913,9 +2488,7 @@ Expression *TupleExp::interpret(InterState *istate, CtfeGoal goal) ex = e->interpret(istate); if (exceptionOrCantInterpret(ex)) - { delete expsx; return ex; - } // A tuple of assignments can contain void (Bug 5676). if (goal == ctfeNeedNothing) @@ -1968,9 +2541,7 @@ Expression *ArrayLiteralExp::interpret(InterState *istate, CtfeGoal goal) if (e->op == TOKindex) // segfault bug 6250 assert( ((IndexExp*)e)->e1 != this); ex = e->interpret(istate); - if (ex == EXP_CANT_INTERPRET) - goto Lerror; - if (ex->op == TOKthrownexception) + if (exceptionOrCantInterpret(ex)) return ex; /* If any changes, do Copy On Write @@ -1994,7 +2565,10 @@ Expression *ArrayLiteralExp::interpret(InterState *istate, CtfeGoal goal) { expandTuples(expsx); if (expsx->dim != elements->dim) - goto Lerror; + { + error("Internal Compiler Error: Invalid array literal"); + return EXP_CANT_INTERPRET; + } ArrayLiteralExp *ae = new ArrayLiteralExp(loc, expsx); ae->type = type; return copyLiteral(ae); @@ -2006,12 +2580,6 @@ Expression *ArrayLiteralExp::interpret(InterState *istate, CtfeGoal goal) } #endif return copyLiteral(this); - -Lerror: - if (expsx) - delete expsx; - error("cannot interpret array literal"); - return EXP_CANT_INTERPRET; } Expression *AssocArrayLiteralExp::interpret(InterState *istate, CtfeGoal goal) @@ -2024,30 +2592,26 @@ Expression *AssocArrayLiteralExp::interpret(InterState *istate, CtfeGoal goal) if (ownedByCtfe) // We've already interpreted all the elements return copyLiteral(this); for (size_t i = 0; i < keys->dim; i++) - { Expression *ekey = keys->tdata()[i]; - Expression *evalue = values->tdata()[i]; + { + Expression *ekey = (*keys)[i]; + Expression *evalue = (*values)[i]; Expression *ex; ex = ekey->interpret(istate); - if (ex == EXP_CANT_INTERPRET) - goto Lerr; - if (ex->op == TOKthrownexception) + if (exceptionOrCantInterpret(ex)) return ex; - /* If any changes, do Copy On Write */ if (ex != ekey) { if (keysx == keys) keysx = (Expressions *)keys->copy(); - keysx->tdata()[i] = ex; + (*keysx)[i] = ex; } ex = evalue->interpret(istate); - if (ex == EXP_CANT_INTERPRET) - goto Lerr; - if (ex->op == TOKthrownexception) + if (exceptionOrCantInterpret(ex)) return ex; /* If any changes, do Copy On Write @@ -2056,7 +2620,7 @@ Expression *AssocArrayLiteralExp::interpret(InterState *istate, CtfeGoal goal) { if (valuesx == values) valuesx = (Expressions *)values->copy(); - valuesx->tdata()[i] = ex; + (*valuesx)[i] = ex; } } if (keysx != keys) @@ -2064,14 +2628,19 @@ Expression *AssocArrayLiteralExp::interpret(InterState *istate, CtfeGoal goal) if (valuesx != values) expandTuples(valuesx); if (keysx->dim != valuesx->dim) - goto Lerr; + { + error("Internal Compiler Error: invalid AA"); + return EXP_CANT_INTERPRET; + } /* Remove duplicate keys */ for (size_t i = 1; i < keysx->dim; i++) - { Expression *ekey = keysx->tdata()[i - 1]; + { + Expression *ekey = (*keysx)[i - 1]; for (size_t j = i; j < keysx->dim; j++) - { Expression *ekey2 = keysx->tdata()[j]; + { + Expression *ekey2 = (*keysx)[j]; int eq = ctfeEqual(loc, TOKequal, ekey, ekey2); if (eq) // if a match { @@ -2097,13 +2666,6 @@ Expression *AssocArrayLiteralExp::interpret(InterState *istate, CtfeGoal goal) return ae; } return this; - -Lerr: - if (keysx != keys) - delete keysx; - if (valuesx != values) - delete values; - return EXP_CANT_INTERPRET; } Expression *StructLiteralExp::interpret(InterState *istate, CtfeGoal goal) @@ -2112,50 +2674,70 @@ Expression *StructLiteralExp::interpret(InterState *istate, CtfeGoal goal) #if LOG printf("%s StructLiteralExp::interpret() %s\n", loc.toChars(), toChars()); #endif - /* We don't know how to deal with overlapping fields - */ - if (sd->hasUnions) - { error("Unions with overlapping fields are not yet supported in CTFE"); - return EXP_CANT_INTERPRET; - } if (ownedByCtfe) return copyLiteral(this); - if (elements) - { - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (*elements)[i]; - if (!e) - continue; + size_t elemdim = elements ? elements->dim : 0; - Expression *ex = e->interpret(istate); - if (exceptionOrCantInterpret(ex)) - { delete expsx; - return ex; - } - - /* If any changes, do Copy On Write + for (size_t i = 0; i < sd->fields.dim; i++) + { Expression *e = NULL; + Expression *ex = NULL; + if (i >= elemdim) + { + /* If a nested struct has no initialized hidden pointer, + * set it to null to match the runtime behaviour. */ - if (ex != e) - { - if (!expsx) - { expsx = new Expressions(); - ++CtfeStatus::numArrayAllocs; - expsx->setDim(elements->dim); - for (size_t j = 0; j < elements->dim; j++) - { - (*expsx)[j] = (*elements)[j]; - } - } - (*expsx)[i] = ex; + if (i == sd->fields.dim - 1 && sd->isNested()) + { // Context field has not been filled + ex = new NullExp(loc); + ex->type = sd->fields[i]->type; } } + else + { + e = (*elements)[i]; + if (!e) + { + /* Ideally, we'd convert NULL members into void expressions. + * The problem is that the VoidExp will be removed when we + * leave CTFE, causing another memory allocation if we use this + * same struct literal again. + * + * ex = sd->fields[i]->type->voidInitLiteral(sd->fields[i]); + */ + ex = NULL; + } + else + { + ex = e->interpret(istate); + if (exceptionOrCantInterpret(ex)) + return ex; + } + } + + /* If any changes, do Copy On Write + */ + if (ex != e) + { + if (!expsx) + { expsx = new Expressions(); + ++CtfeStatus::numArrayAllocs; + expsx->setDim(sd->fields.dim); + for (size_t j = 0; j < elements->dim; j++) + { + (*expsx)[j] = (*elements)[j]; + } + } + (*expsx)[i] = ex; + } } + if (elements && expsx) { expandTuples(expsx); - if (expsx->dim != elements->dim) - { delete expsx; + if (expsx->dim != sd->fields.dim) + { + error("Internal Compiler Error: invalid struct literal"); return EXP_CANT_INTERPRET; } StructLiteralExp *se = new StructLiteralExp(loc, sd, expsx); @@ -2250,10 +2832,19 @@ Expression *NewExp::interpret(InterState *istate, CtfeGoal goal) Dsymbol *s = c->fields[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v); - Expression *m = v->init ? v->init->toExpression() : v->type->defaultInitLiteral(loc); + Expression *m; + if (v->init) + { + if (v->init->isVoidInitializer()) + m = v->type->voidInitLiteral(v); + else + m = v->getConstInitializer(true); + } + else + m = v->type->defaultInitLiteral(loc); if (exceptionOrCantInterpret(m)) return m; - elems->tdata()[fieldsSoFar+i] = copyLiteral(m); + (*elems)[fieldsSoFar+i] = copyLiteral(m); } } // Hack: we store a ClassDeclaration instead of a StructDeclaration. @@ -2290,6 +2881,11 @@ Expression *UnaExp::interpret(InterState *istate, CtfeGoal goal) #if LOG printf("%s UnaExp::interpret() %s\n", loc.toChars(), toChars()); #endif + if (op == TOKdottype) + { + error("Internal Compiler Error: CTFE DotType: %s", toChars()); + return EXP_CANT_INTERPRET; + } e1 = this->e1->interpret(istate); if (exceptionOrCantInterpret(e1)) return e1; @@ -2299,12 +2895,12 @@ Expression *UnaExp::interpret(InterState *istate, CtfeGoal goal) case TOKtilde: e = Com(type, e1); break; case TOKnot: e = Not(type, e1); break; case TOKtobool: e = Bool(type, e1); break; + case TOKvector: e = this; break; // do nothing default: assert(0); } return e; } -typedef Expression *(*fp_t)(Type *, Expression *, Expression *); Expression *BinExp::interpretCommon(InterState *istate, CtfeGoal goal, fp_t fp) { Expression *e; @@ -2353,39 +2949,49 @@ Expression *BinExp::interpretCommon(InterState *istate, CtfeGoal goal, fp_t fp) if (exceptionOrCantInterpret(e1)) return e1; if (e1->isConst() != 1) - goto Lcant; + { + error("Internal Compiler Error: non-constant value %s", this->e1->toChars()); + return EXP_CANT_INTERPRET; + } e2 = this->e2->interpret(istate); if (exceptionOrCantInterpret(e2)) return e2; if (e2->isConst() != 1) - goto Lcant; + { + error("Internal Compiler Error: non-constant value %s", this->e2->toChars()); + return EXP_CANT_INTERPRET; + } + if (op == TOKshr || op == TOKshl || op == TOKushr) + { + sinteger_t i2 = e2->toInteger(); + d_uns64 sz = e1->type->size() * 8; + if (i2 < 0 || i2 >= sz) + { error("shift by %lld is outside the range 0..%llu", i2, (ulonglong)sz - 1); + return EXP_CANT_INTERPRET; + } + } e = (*fp)(type, e1, e2); if (e == EXP_CANT_INTERPRET) error("%s cannot be interpreted at compile time", toChars()); return e; - -Lcant: - return EXP_CANT_INTERPRET; } -typedef int (*fp2_t)(Loc loc, enum TOK, Expression *, Expression *); - Expression *BinExp::interpretCompareCommon(InterState *istate, CtfeGoal goal, fp2_t fp) { Expression *e1; Expression *e2; #if LOG - printf("%s BinExp::interpretCommon2() %s\n", loc.toChars(), toChars()); + printf("%s BinExp::interpretCompareCommon() %s\n", loc.toChars(), toChars()); #endif if (this->e1->type->ty == Tpointer && this->e2->type->ty == Tpointer) { - e1 = this->e1->interpret(istate, ctfeNeedLvalue); + e1 = this->e1->interpret(istate); if (exceptionOrCantInterpret(e1)) return e1; - e2 = this->e2->interpret(istate, ctfeNeedLvalue); + e2 = this->e2->interpret(istate); if (exceptionOrCantInterpret(e2)) return e2; dinteger_t ofs1, ofs2; @@ -2494,6 +3100,14 @@ VarDeclaration * findParentVar(Expression *e) return v; } +Expression *interpretAssignToSlice(InterState *istate, CtfeGoal goal, Loc loc, + SliceExp *sexp, Expression *newval, bool wantRef, bool isBlockAssignment, + BinExp *originalExpression); + +bool interpretAssignToIndex(InterState *istate, Loc loc, + IndexExp *ie, Expression *newval, bool wantRef, + BinExp *originalExp); + Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_t fp, int post) { #if LOG @@ -2529,9 +3143,9 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ { desttype = ((TypeArray *)desttype)->next; #if DMDV2 - if (srctype == desttype->castMod(0)) + if (srctype->equals(desttype->castMod(0))) #else - if (srctype == desttype) + if (srctype->equals(desttype)) #endif { isBlockAssignment = true; @@ -2551,7 +3165,7 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ bool wantRef = false; bool wantLvalueRef = false; - if (!fp && this->e1->type->toBasetype() == this->e2->type->toBasetype() && + if (!fp && this->e1->type->toBasetype()->equals(this->e2->type->toBasetype()) && (e1->type->toBasetype()->ty == Tarray || isAssocArray(e1->type) || e1->type->toBasetype()->ty == Tclass) // e = *x is never a reference, because *x is always a value @@ -2636,7 +3250,7 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ if (exceptionOrCantInterpret(e1)) return e1; if (!(e1->op == TOKvar || e1->op == TOKdotvar || e1->op == TOKindex - || e1->op == TOKslice)) + || e1->op == TOKslice || e1->op == TOKstructliteral)) { error("cannot dereference invalid pointer %s", this->e1->toChars()); @@ -2645,7 +3259,7 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ } if (!(e1->op == TOKarraylength || e1->op == TOKvar || e1->op == TOKdotvar - || e1->op == TOKindex || e1->op == TOKslice)) + || e1->op == TOKindex || e1->op == TOKslice || e1->op == TOKstructliteral)) { error("CTFE internal error: unsupported assignment %s", toChars()); return EXP_CANT_INTERPRET; @@ -2957,18 +3571,17 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ // collapsed into a single assignment. if (!wantRef && e1->op == TOKdotvar) { - // Strip of all of the leading dotvars, unless we started with a call - // or a ref parameter + // Strip of all of the leading dotvars, unless it is a CTFE dotvar + // pointer or reference // (in which case, we already have the lvalue). - if (this->e1->op != TOKcall && !(this->e1->op==TOKvar - && ((VarExp*)this->e1)->var->storage_class & (STCref | STCout))) - e1 = e1->interpret(istate, isPointer(type)? ctfeNeedLvalueRef : ctfeNeedLvalue); - if (exceptionOrCantInterpret(e1)) - return e1; - if (e1->op == TOKstructliteral && newval->op == TOKstructliteral) + DotVarExp *dve = (DotVarExp *)e1; + bool isCtfePointer = (dve->e1->op == TOKstructliteral) + && ((StructLiteralExp *)(dve->e1))->ownedByCtfe; + if (!isCtfePointer) { - assignInPlace(e1, newval); - return returnValue; + e1 = e1->interpret(istate, isPointer(type) ? ctfeNeedLvalueRef : ctfeNeedLvalue); + if (exceptionOrCantInterpret(e1)) + return e1; } } #if LOGASSIGN @@ -3018,6 +3631,15 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ } } } + else if (e1->op == TOKstructliteral && newval->op == TOKstructliteral) + { + /* Assignment to complete struct of the form: + * e1 = newval + * (e1 was a ref parameter, or was created via TOKstar dereferencing). + */ + assignInPlace(e1, newval); + return returnValue; + } else if (e1->op == TOKdotvar) { /* Assignment to member variable of the form: @@ -3062,500 +3684,31 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ for(int i = unionStart; i < unionStart + unionSize; ++i) { if (i == fieldi) continue; - Expression **el = &se->elements->tdata()[i]; + Expression **el = &(*se->elements)[i]; if ((*el)->op != TOKvoid) *el = (*el)->type->voidInitLiteral(member); } } if (newval->op == TOKstructliteral) - assignInPlace(se->elements->tdata()[fieldi], newval); + assignInPlace((*se->elements)[fieldi], newval); else - se->elements->tdata()[fieldi] = newval; + (*se->elements)[fieldi] = newval; return returnValue; } else if (e1->op == TOKindex) { - /* Assignment to array element of the form: - * aggregate[i] = newval - * aggregate is not AA (AAs were dealt with already). - */ - IndexExp *ie = (IndexExp *)e1; - assert(ie->e1->type->toBasetype()->ty != Taarray); - uinteger_t destarraylen = 0; - - // Set the $ variable, and find the array literal to modify - if (ie->e1->type->toBasetype()->ty != Tpointer) - { - Expression *oldval = ie->e1->interpret(istate); - if (oldval->op == TOKnull) - { - error("cannot index null array %s", ie->e1->toChars()); - return EXP_CANT_INTERPRET; - } - if (oldval->op != TOKarrayliteral && oldval->op != TOKstring - && oldval->op != TOKslice) - { - error("cannot determine length of %s at compile time", - ie->e1->toChars()); - return EXP_CANT_INTERPRET; - } - destarraylen = resolveArrayLength(oldval); - if (ie->lengthVar) - { - IntegerExp *dollarExp = new IntegerExp(loc, destarraylen, Type::tsize_t); - ctfeStack.push(ie->lengthVar); - ie->lengthVar->setValue(dollarExp); - } - } - Expression *index = ie->e2->interpret(istate); - if (ie->lengthVar) - ctfeStack.pop(ie->lengthVar); // $ is defined only inside [] - if (exceptionOrCantInterpret(index)) - return index; - - assert (index->op != TOKslice); // only happens with AA assignment - - ArrayLiteralExp *existingAE = NULL; - StringExp *existingSE = NULL; - - Expression *aggregate = resolveReferences(ie->e1); - - // Set the index to modify, and check that it is in range - dinteger_t indexToModify = index->toInteger(); - if (ie->e1->type->toBasetype()->ty == Tpointer) - { - dinteger_t ofs; - aggregate = aggregate->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(aggregate)) - return aggregate; - if (aggregate->op == TOKnull) - { - error("cannot index through null pointer %s", ie->e1->toChars()); - return EXP_CANT_INTERPRET; - } - if (aggregate->op == TOKint64) - { - error("cannot index through invalid pointer %s of value %s", - ie->e1->toChars(), aggregate->toChars()); - return EXP_CANT_INTERPRET; - } - aggregate = getAggregateFromPointer(aggregate, &ofs); - indexToModify += ofs; - if (aggregate->op != TOKslice && aggregate->op != TOKstring && - aggregate->op != TOKarrayliteral && aggregate->op != TOKassocarrayliteral) - { - if (aggregate->op == TOKsymoff) - { - error("mutable variable %s cannot be modified at compile time, even through a pointer", ((SymOffExp *)aggregate)->var->toChars()); - return EXP_CANT_INTERPRET; - } - if (indexToModify != 0) - { - error("pointer index [%lld] lies outside memory block [0..1]", indexToModify); - return EXP_CANT_INTERPRET; - } - // It is equivalent to *aggregate = newval. - // Aggregate could be varexp, a dotvar, ... - // TODO: we could support this - error("indexed assignment of non-array pointers is not yet supported at compile time; use *%s = %s instead", - ie->e1->toChars(), e2->toChars()); - return EXP_CANT_INTERPRET; - } - destarraylen = resolveArrayLength(aggregate); - } - if (indexToModify >= destarraylen) - { - error("array index %lld is out of bounds [0..%lld]", indexToModify, - destarraylen); + if ( !interpretAssignToIndex(istate, loc, (IndexExp *)e1, newval, + wantRef, this)) return EXP_CANT_INTERPRET; - } - - /* The only possible indexable LValue aggregates are array literals, and - * slices of array literals. - */ - if (aggregate->op == TOKindex || aggregate->op == TOKdotvar || - aggregate->op == TOKslice || aggregate->op == TOKcall || - aggregate->op == TOKstar) - { - Expression *origagg = aggregate; - aggregate = aggregate->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(aggregate)) - return aggregate; - // The array could be an index of an AA. Resolve it if so. - if (aggregate->op == TOKindex && - ((IndexExp *)aggregate)->e1->op == TOKassocarrayliteral) - { - IndexExp *ix = (IndexExp *)aggregate; - aggregate = findKeyInAA(loc, (AssocArrayLiteralExp *)ix->e1, ix->e2); - if (!aggregate) - { - error("key %s not found in associative array %s", - ix->e2->toChars(), ix->e1->toChars()); - return EXP_CANT_INTERPRET; - } - if (exceptionOrCantInterpret(aggregate)) - return aggregate; - } - } - if (aggregate->op == TOKvar) - { - VarExp *ve = (VarExp *)aggregate; - VarDeclaration *v = ve->var->isVarDeclaration(); - aggregate = v->getValue(); - if (aggregate->op == TOKnull) - { - // This would be a runtime segfault - error("cannot index null array %s", v->toChars()); - return EXP_CANT_INTERPRET; - } - } - if (aggregate->op == TOKslice) - { - SliceExp *sexp = (SliceExp *)aggregate; - aggregate = sexp->e1; - Expression *lwr = sexp->lwr->interpret(istate); - indexToModify += lwr->toInteger(); - } - if (aggregate->op == TOKarrayliteral) - existingAE = (ArrayLiteralExp *)aggregate; - else if (aggregate->op == TOKstring) - existingSE = (StringExp *)aggregate; - else - { - error("CTFE internal compiler error %s", aggregate->toChars()); - return EXP_CANT_INTERPRET; - } - if (!wantRef && newval->op == TOKslice) - { - newval = resolveSlice(newval); - if (newval == EXP_CANT_INTERPRET) - { - error("Compiler error: CTFE index assign %s", toChars()); - assert(0); - } - } - if (wantRef && newval->op == TOKindex - && ((IndexExp *)newval)->e1 == aggregate) - { // It's a circular reference, resolve it now - newval = newval->interpret(istate); - } - - if (existingAE) - { - if (newval->op == TOKstructliteral) - assignInPlace((Expression *)(existingAE->elements->tdata()[indexToModify]), newval); - else - existingAE->elements->tdata()[indexToModify] = newval; - return returnValue; - } - if (existingSE) - { - unsigned char *s = (unsigned char *)existingSE->string; - if (!existingSE->ownedByCtfe) - { - error("cannot modify read-only string literal %s", ie->e1->toChars()); - return EXP_CANT_INTERPRET; - } - unsigned value = newval->toInteger(); - switch (existingSE->sz) - { - case 1: s[indexToModify] = value; break; - case 2: ((unsigned short *)s)[indexToModify] = value; break; - case 4: ((unsigned *)s)[indexToModify] = value; break; - default: - assert(0); - break; - } - return returnValue; - } - else - { - error("Index assignment %s is not yet supported in CTFE ", toChars()); - return EXP_CANT_INTERPRET; - } return returnValue; } else if (e1->op == TOKslice) { - // ------------------------------ - // aggregate[] = newval - // aggregate[low..upp] = newval - // ------------------------------ - SliceExp * sexp = (SliceExp *)e1; - // Set the $ variable - Expression *oldval = sexp->e1; - bool assignmentToSlicedPointer = false; - if (isPointer(oldval->type)) - { // Slicing a pointer - oldval = oldval->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(oldval)) - return oldval; - dinteger_t ofs; - oldval = getAggregateFromPointer(oldval, &ofs); - assignmentToSlicedPointer = true; - } else - oldval = oldval->interpret(istate); - - if (oldval->op != TOKarrayliteral && oldval->op != TOKstring - && oldval->op != TOKslice && oldval->op != TOKnull) - { - if (oldval->op == TOKsymoff) - { - error("pointer %s cannot be sliced at compile time (it points to a static variable)", sexp->e1->toChars()); - return EXP_CANT_INTERPRET; - } - if (assignmentToSlicedPointer) - { - error("pointer %s cannot be sliced at compile time (it does not point to an array)", - sexp->e1->toChars()); - } - else - error("CTFE ICE: cannot resolve array length"); - return EXP_CANT_INTERPRET; - } - uinteger_t dollar = resolveArrayLength(oldval); - if (sexp->lengthVar) - { - Expression *arraylen = new IntegerExp(loc, dollar, Type::tsize_t); - ctfeStack.push(sexp->lengthVar); - sexp->lengthVar->setValue(arraylen); - } - - Expression *upper = NULL; - Expression *lower = NULL; - if (sexp->upr) - upper = sexp->upr->interpret(istate); - if (exceptionOrCantInterpret(upper)) - { - if (sexp->lengthVar) - ctfeStack.pop(sexp->lengthVar); // $ is defined only in [L..U] - return upper; - } - if (sexp->lwr) - lower = sexp->lwr->interpret(istate); - if (sexp->lengthVar) - ctfeStack.pop(sexp->lengthVar); // $ is defined only in [L..U] - if (exceptionOrCantInterpret(lower)) - return lower; - - size_t dim = dollar; - size_t upperbound = upper ? upper->toInteger() : dim; - int lowerbound = lower ? lower->toInteger() : 0; - - if (!assignmentToSlicedPointer && (((int)lowerbound < 0) || (upperbound > dim))) - { - error("Array bounds [0..%d] exceeded in slice [%d..%d]", - dim, lowerbound, upperbound); - return EXP_CANT_INTERPRET; - } - if (upperbound == lowerbound) - return newval; - - Expression *aggregate = resolveReferences(((SliceExp *)e1)->e1); - dinteger_t firstIndex = lowerbound; - - ArrayLiteralExp *existingAE = NULL; - StringExp *existingSE = NULL; - - /* The only possible slicable LValue aggregates are array literals, - * and slices of array literals. - */ - - if (aggregate->op == TOKindex || aggregate->op == TOKdotvar || - aggregate->op == TOKslice || - aggregate->op == TOKstar || aggregate->op == TOKcall) - { - aggregate = aggregate->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(aggregate)) - return aggregate; - // The array could be an index of an AA. Resolve it if so. - if (aggregate->op == TOKindex && - ((IndexExp *)aggregate)->e1->op == TOKassocarrayliteral) - { - IndexExp *ix = (IndexExp *)aggregate; - aggregate = findKeyInAA(loc, (AssocArrayLiteralExp *)ix->e1, ix->e2); - if (!aggregate) - { - error("key %s not found in associative array %s", - ix->e2->toChars(), ix->e1->toChars()); - return EXP_CANT_INTERPRET; - } - if (exceptionOrCantInterpret(aggregate)) - return aggregate; - } - } - if (aggregate->op == TOKvar) - { - VarExp *ve = (VarExp *)(aggregate); - VarDeclaration *v = ve->var->isVarDeclaration(); - aggregate = v->getValue(); - } - if (aggregate->op == TOKslice) - { // Slice of a slice --> change the bounds - SliceExp *sexpold = (SliceExp *)aggregate; - sinteger_t hi = upperbound + sexpold->lwr->toInteger(); - firstIndex = lowerbound + sexpold->lwr->toInteger(); - if (hi > sexpold->upr->toInteger()) - { - error("slice [%d..%d] exceeds array bounds [0..%lld]", - lowerbound, upperbound, - sexpold->upr->toInteger() - sexpold->lwr->toInteger()); - return EXP_CANT_INTERPRET; - } - aggregate = sexpold->e1; - } - if ( isPointer(aggregate->type) ) - { // Slicing a pointer --> change the bounds - aggregate = sexp->e1->interpret(istate, ctfeNeedLvalue); - dinteger_t ofs; - aggregate = getAggregateFromPointer(aggregate, &ofs); - if (aggregate->op == TOKnull) - { - error("cannot slice null pointer %s", sexp->e1->toChars()); - return EXP_CANT_INTERPRET; - } - sinteger_t hi = upperbound + ofs; - firstIndex = lowerbound + ofs; - if (firstIndex < 0 || hi > dim) - { - error("slice [lld..%lld] exceeds memory block bounds [0..%lld]", - firstIndex, hi, dim); - return EXP_CANT_INTERPRET; - } - } - if (aggregate->op == TOKarrayliteral) - existingAE = (ArrayLiteralExp *)aggregate; - else if (aggregate->op == TOKstring) - existingSE = (StringExp *)aggregate; - if (existingSE && !existingSE->ownedByCtfe) - { error("cannot modify read-only string literal %s", sexp->e1->toChars()); - return EXP_CANT_INTERPRET; - } - - if (!wantRef && newval->op == TOKslice) - { - newval = resolveSlice(newval); - if (newval == EXP_CANT_INTERPRET) - { - error("Compiler error: CTFE slice %s", toChars()); - assert(0); - } - } - if (wantRef && newval->op == TOKindex - && ((IndexExp *)newval)->e1 == aggregate) - { // It's a circular reference, resolve it now - newval = newval->interpret(istate); - } - - // For slice assignment, we check that the lengths match. - size_t srclen = 0; - if (newval->op == TOKarrayliteral) - srclen = ((ArrayLiteralExp *)newval)->elements->dim; - else if (newval->op == TOKstring) - srclen = ((StringExp *)newval)->len; - if (!isBlockAssignment && srclen != (upperbound - lowerbound)) - { - error("Array length mismatch assigning [0..%d] to [%d..%d]", srclen, lowerbound, upperbound); - return EXP_CANT_INTERPRET; - } - - if (!isBlockAssignment && newval->op == TOKarrayliteral && existingAE) - { - Expressions *oldelems = existingAE->elements; - Expressions *newelems = ((ArrayLiteralExp *)newval)->elements; - for (size_t j = 0; j < newelems->dim; j++) - { - oldelems->tdata()[j + firstIndex] = newelems->tdata()[j]; - } - return newval; - } - else if (newval->op == TOKstring && existingSE) - { - sliceAssignStringFromString((StringExp *)existingSE, (StringExp *)newval, firstIndex); - return newval; - } - else if (newval->op == TOKstring && existingAE - && existingAE->type->isString()) - { /* Mixed slice: it was initialized as an array literal of chars. - * Now a slice of it is being set with a string. - */ - sliceAssignArrayLiteralFromString(existingAE, (StringExp *)newval, firstIndex); - return newval; - } - else if (newval->op == TOKarrayliteral && existingSE) - { /* Mixed slice: it was initialized as a string literal. - * Now a slice of it is being set with an array literal. - */ - sliceAssignStringFromArrayLiteral(existingSE, (ArrayLiteralExp *)newval, firstIndex); - return newval; - } - else if (existingSE) - { // String literal block slice assign - unsigned value = newval->toInteger(); - unsigned char *s = (unsigned char *)existingSE->string; - for (size_t j = 0; j < upperbound-lowerbound; j++) - { - switch (existingSE->sz) - { - case 1: s[j+firstIndex] = value; break; - case 2: ((unsigned short *)s)[j+firstIndex] = value; break; - case 4: ((unsigned *)s)[j+firstIndex] = value; break; - default: - assert(0); - break; - } - } - if (goal == ctfeNeedNothing) - return NULL; // avoid creating an unused literal - SliceExp *retslice = new SliceExp(loc, existingSE, - new IntegerExp(loc, firstIndex, Type::tsize_t), - new IntegerExp(loc, firstIndex + upperbound-lowerbound, Type::tsize_t)); - retslice->type = this->type; - return retslice->interpret(istate); - } - else if (existingAE) - { - /* Block assignment, initialization of static arrays - * x[] = e - * x may be a multidimensional static array. (Note that this - * only happens with array literals, never with strings). - */ - Expressions * w = existingAE->elements; - assert( existingAE->type->ty == Tsarray || - existingAE->type->ty == Tarray); -#if DMDV2 - Type *desttype = ((TypeArray *)existingAE->type)->next->castMod(0); - bool directblk = (e2->type->toBasetype()->castMod(0)) == desttype; -#else - Type *desttype = ((TypeArray *)existingAE->type)->next; - bool directblk = (e2->type->toBasetype()) == desttype; -#endif - bool cow = !(newval->op == TOKstructliteral || newval->op == TOKarrayliteral - || newval->op == TOKstring); - for (size_t j = 0; j < upperbound-lowerbound; j++) - { - if (!directblk) - // Multidimensional array block assign - recursiveBlockAssign((ArrayLiteralExp *)w->tdata()[j+firstIndex], newval, wantRef); - else - { - if (wantRef || cow) - existingAE->elements->tdata()[j+firstIndex] = newval; - else - assignInPlace(existingAE->elements->tdata()[j+firstIndex], newval); - } - } - if (goal == ctfeNeedNothing) - return NULL; // avoid creating an unused literal - SliceExp *retslice = new SliceExp(loc, existingAE, - new IntegerExp(loc, firstIndex, Type::tsize_t), - new IntegerExp(loc, firstIndex + upperbound-lowerbound, Type::tsize_t)); - retslice->type = this->type; - return retslice->interpret(istate); - } - else - error("Slice operation %s cannot be evaluated at compile time", toChars()); + // Note that slice assignments don't support things like ++, so + // we don't need to remember 'returnValue'. + return interpretAssignToSlice(istate, goal, loc, (SliceExp *)e1, + newval, wantRef, isBlockAssignment, this); } else { @@ -3564,6 +3717,521 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ return returnValue; } +/************* + * Deal with assignments of the form + * aggregate[ie] = newval + * where aggregate and newval have already been interpreted + * + * Return true if OK, false if error occured + */ +bool interpretAssignToIndex(InterState *istate, Loc loc, + IndexExp *ie, Expression *newval, bool wantRef, + BinExp *originalExp) +{ + /* Assignment to array element of the form: + * aggregate[i] = newval + * aggregate is not AA (AAs were dealt with already). + */ + assert(ie->e1->type->toBasetype()->ty != Taarray); + uinteger_t destarraylen = 0; + + // Set the $ variable, and find the array literal to modify + if (ie->e1->type->toBasetype()->ty != Tpointer) + { + Expression *oldval = ie->e1->interpret(istate); + if (oldval->op == TOKnull) + { + originalExp->error("cannot index null array %s", ie->e1->toChars()); + return false; + } + if (oldval->op != TOKarrayliteral && oldval->op != TOKstring + && oldval->op != TOKslice) + { + originalExp->error("cannot determine length of %s at compile time", + ie->e1->toChars()); + return false; + } + destarraylen = resolveArrayLength(oldval); + if (ie->lengthVar) + { + IntegerExp *dollarExp = new IntegerExp(loc, destarraylen, Type::tsize_t); + ctfeStack.push(ie->lengthVar); + ie->lengthVar->setValue(dollarExp); + } + } + Expression *index = ie->e2->interpret(istate); + if (ie->lengthVar) + ctfeStack.pop(ie->lengthVar); // $ is defined only inside [] + if (exceptionOrCantInterpret(index)) + return false; + + assert (index->op != TOKslice); // only happens with AA assignment + + ArrayLiteralExp *existingAE = NULL; + StringExp *existingSE = NULL; + + Expression *aggregate = resolveReferences(ie->e1); + + // Set the index to modify, and check that it is in range + dinteger_t indexToModify = index->toInteger(); + if (ie->e1->type->toBasetype()->ty == Tpointer) + { + dinteger_t ofs; + aggregate = aggregate->interpret(istate, ctfeNeedLvalue); + if (exceptionOrCantInterpret(aggregate)) + return false; + if (aggregate->op == TOKnull) + { + originalExp->error("cannot index through null pointer %s", ie->e1->toChars()); + return false; + } + if (aggregate->op == TOKint64) + { + originalExp->error("cannot index through invalid pointer %s of value %s", + ie->e1->toChars(), aggregate->toChars()); + return false; + } + aggregate = getAggregateFromPointer(aggregate, &ofs); + indexToModify += ofs; + if (aggregate->op != TOKslice && aggregate->op != TOKstring && + aggregate->op != TOKarrayliteral && aggregate->op != TOKassocarrayliteral) + { + if (aggregate->op == TOKsymoff) + { + originalExp->error("mutable variable %s cannot be modified at compile time, even through a pointer", ((SymOffExp *)aggregate)->var->toChars()); + return false; + } + if (indexToModify != 0) + { + originalExp->error("pointer index [%lld] lies outside memory block [0..1]", indexToModify); + return false; + } + // It is equivalent to *aggregate = newval. + // Aggregate could be varexp, a dotvar, ... + // TODO: we could support this + originalExp->error("indexed assignment of non-array pointers is not yet supported at compile time; use *%s = %s instead", + ie->e1->toChars(), originalExp->e2->toChars()); + return false; + } + destarraylen = resolveArrayLength(aggregate); + } + if (indexToModify >= destarraylen) + { + originalExp->error("array index %lld is out of bounds [0..%lld]", indexToModify, + destarraylen); + return false; + } + + /* The only possible indexable LValue aggregates are array literals, and + * slices of array literals. + */ + if (aggregate->op == TOKindex || aggregate->op == TOKdotvar || + aggregate->op == TOKslice || aggregate->op == TOKcall || + aggregate->op == TOKstar) + { + aggregate = aggregate->interpret(istate, ctfeNeedLvalue); + if (exceptionOrCantInterpret(aggregate)) + return false; + // The array could be an index of an AA. Resolve it if so. + if (aggregate->op == TOKindex && + ((IndexExp *)aggregate)->e1->op == TOKassocarrayliteral) + { + IndexExp *ix = (IndexExp *)aggregate; + aggregate = findKeyInAA(loc, (AssocArrayLiteralExp *)ix->e1, ix->e2); + if (!aggregate) + { + originalExp->error("key %s not found in associative array %s", + ix->e2->toChars(), ix->e1->toChars()); + return false; + } + if (exceptionOrCantInterpret(aggregate)) + return false; + } + } + if (aggregate->op == TOKvar) + { + VarExp *ve = (VarExp *)aggregate; + VarDeclaration *v = ve->var->isVarDeclaration(); + aggregate = v->getValue(); + if (aggregate->op == TOKnull) + { + // This would be a runtime segfault + originalExp->error("cannot index null array %s", v->toChars()); + return false; + } + } + if (aggregate->op == TOKslice) + { + SliceExp *sexp = (SliceExp *)aggregate; + aggregate = sexp->e1; + Expression *lwr = sexp->lwr->interpret(istate); + indexToModify += lwr->toInteger(); + } + if (aggregate->op == TOKarrayliteral) + existingAE = (ArrayLiteralExp *)aggregate; + else if (aggregate->op == TOKstring) + existingSE = (StringExp *)aggregate; + else + { + originalExp->error("CTFE internal compiler error %s", aggregate->toChars()); + return false; + } + if (!wantRef && newval->op == TOKslice) + { + newval = resolveSlice(newval); + if (newval == EXP_CANT_INTERPRET) + { + originalExp->error("Compiler error: CTFE index assign %s", originalExp->toChars()); + assert(0); + } + } + if (wantRef && newval->op == TOKindex + && ((IndexExp *)newval)->e1 == aggregate) + { // It's a circular reference, resolve it now + newval = newval->interpret(istate); + } + + if (existingAE) + { + if (newval->op == TOKstructliteral) + assignInPlace((*existingAE->elements)[indexToModify], newval); + else + (*existingAE->elements)[indexToModify] = newval; + return true; + } + if (existingSE) + { + utf8_t *s = (utf8_t *)existingSE->string; + if (!existingSE->ownedByCtfe) + { + originalExp->error("cannot modify read-only string literal %s", ie->e1->toChars()); + return false; + } + unsigned value = newval->toInteger(); + switch (existingSE->sz) + { + case 1: s[indexToModify] = value; break; + case 2: ((unsigned short *)s)[indexToModify] = value; break; + case 4: ((unsigned *)s)[indexToModify] = value; break; + default: + assert(0); + break; + } + return true; + } + else + { + originalExp->error("Index assignment %s is not yet supported in CTFE ", originalExp->toChars()); + return false; + } + return true; +} + +/************* + * Deal with assignments of the form + * dest[] = newval + * dest[low..upp] = newval + * where newval has already been interpreted + * + * This could be a slice assignment or a block assignment, and + * dest could be either an array literal, or a string. + * + * Returns EXP_CANT_INTERPRET on failure. If there are no errors, + * it returns aggregate[low..upp], except that as an optimisation, + * if goal == ctfeNeedNothing, it will return NULL + */ + +Expression *interpretAssignToSlice(InterState *istate, CtfeGoal goal, Loc loc, + SliceExp *sexp, Expression *newval, bool wantRef, bool isBlockAssignment, + BinExp *originalExp) +{ + Expression *e2 = originalExp->e2; + + // ------------------------------ + // aggregate[] = newval + // aggregate[low..upp] = newval + // ------------------------------ + // Set the $ variable + Expression *oldval = sexp->e1; + bool assignmentToSlicedPointer = false; + if (isPointer(oldval->type)) + { // Slicing a pointer + oldval = oldval->interpret(istate, ctfeNeedLvalue); + if (exceptionOrCantInterpret(oldval)) + return oldval; + dinteger_t ofs; + oldval = getAggregateFromPointer(oldval, &ofs); + assignmentToSlicedPointer = true; + } + else + oldval = oldval->interpret(istate); + + if (oldval->op != TOKarrayliteral && oldval->op != TOKstring + && oldval->op != TOKslice && oldval->op != TOKnull) + { + if (oldval->op == TOKsymoff) + { + originalExp->error("pointer %s cannot be sliced at compile time (it points to a static variable)", sexp->e1->toChars()); + return EXP_CANT_INTERPRET; + } + if (assignmentToSlicedPointer) + { + originalExp->error("pointer %s cannot be sliced at compile time (it does not point to an array)", + sexp->e1->toChars()); + } + else + originalExp->error("CTFE ICE: cannot resolve array length"); + return EXP_CANT_INTERPRET; + } + uinteger_t dollar = resolveArrayLength(oldval); + if (sexp->lengthVar) + { + Expression *arraylen = new IntegerExp(loc, dollar, Type::tsize_t); + ctfeStack.push(sexp->lengthVar); + sexp->lengthVar->setValue(arraylen); + } + + Expression *upper = NULL; + Expression *lower = NULL; + if (sexp->upr) + upper = sexp->upr->interpret(istate); + if (exceptionOrCantInterpret(upper)) + { + if (sexp->lengthVar) + ctfeStack.pop(sexp->lengthVar); // $ is defined only in [L..U] + return upper; + } + if (sexp->lwr) + lower = sexp->lwr->interpret(istate); + if (sexp->lengthVar) + ctfeStack.pop(sexp->lengthVar); // $ is defined only in [L..U] + if (exceptionOrCantInterpret(lower)) + return lower; + + size_t dim = dollar; + size_t upperbound = upper ? upper->toInteger() : dim; + int lowerbound = lower ? lower->toInteger() : 0; + + if (!assignmentToSlicedPointer && (((int)lowerbound < 0) || (upperbound > dim))) + { + originalExp->error("Array bounds [0..%d] exceeded in slice [%d..%d]", + dim, lowerbound, upperbound); + return EXP_CANT_INTERPRET; + } + if (upperbound == lowerbound) + return newval; + + Expression *aggregate = resolveReferences(sexp->e1); + sinteger_t firstIndex = lowerbound; + + ArrayLiteralExp *existingAE = NULL; + StringExp *existingSE = NULL; + + /* The only possible slicable LValue aggregates are array literals, + * and slices of array literals. + */ + + if (aggregate->op == TOKindex || aggregate->op == TOKdotvar || + aggregate->op == TOKslice || + aggregate->op == TOKstar || aggregate->op == TOKcall) + { + aggregate = aggregate->interpret(istate, ctfeNeedLvalue); + if (exceptionOrCantInterpret(aggregate)) + return aggregate; + // The array could be an index of an AA. Resolve it if so. + if (aggregate->op == TOKindex && + ((IndexExp *)aggregate)->e1->op == TOKassocarrayliteral) + { + IndexExp *ix = (IndexExp *)aggregate; + aggregate = findKeyInAA(loc, (AssocArrayLiteralExp *)ix->e1, ix->e2); + if (!aggregate) + { + originalExp->error("key %s not found in associative array %s", + ix->e2->toChars(), ix->e1->toChars()); + return EXP_CANT_INTERPRET; + } + if (exceptionOrCantInterpret(aggregate)) + return aggregate; + } + } + if (aggregate->op == TOKvar) + { + VarExp *ve = (VarExp *)(aggregate); + VarDeclaration *v = ve->var->isVarDeclaration(); + aggregate = v->getValue(); + } + if (aggregate->op == TOKslice) + { // Slice of a slice --> change the bounds + SliceExp *sexpold = (SliceExp *)aggregate; + sinteger_t hi = upperbound + sexpold->lwr->toInteger(); + firstIndex = lowerbound + sexpold->lwr->toInteger(); + if (hi > sexpold->upr->toInteger()) + { + originalExp->error("slice [%d..%d] exceeds array bounds [0..%lld]", + lowerbound, upperbound, + sexpold->upr->toInteger() - sexpold->lwr->toInteger()); + return EXP_CANT_INTERPRET; + } + aggregate = sexpold->e1; + } + if ( isPointer(aggregate->type) ) + { // Slicing a pointer --> change the bounds + aggregate = sexp->e1->interpret(istate, ctfeNeedLvalue); + dinteger_t ofs; + aggregate = getAggregateFromPointer(aggregate, &ofs); + if (aggregate->op == TOKnull) + { + originalExp->error("cannot slice null pointer %s", sexp->e1->toChars()); + return EXP_CANT_INTERPRET; + } + sinteger_t hi = upperbound + ofs; + firstIndex = lowerbound + ofs; + if (firstIndex < 0 || hi > dim) + { + originalExp->error("slice [lld..%lld] exceeds memory block bounds [0..%lld]", + firstIndex, hi, dim); + return EXP_CANT_INTERPRET; + } + } + if (aggregate->op == TOKarrayliteral) + existingAE = (ArrayLiteralExp *)aggregate; + else if (aggregate->op == TOKstring) + existingSE = (StringExp *)aggregate; + if (existingSE && !existingSE->ownedByCtfe) + { originalExp->error("cannot modify read-only string literal %s", sexp->e1->toChars()); + return EXP_CANT_INTERPRET; + } + + if (!wantRef && newval->op == TOKslice) + { + Expression *orignewval = newval; + newval = resolveSlice(newval); + if (newval == EXP_CANT_INTERPRET) + { + originalExp->error("Compiler error: CTFE slice %s", orignewval->toChars()); + assert(0); + } + } + if (wantRef && newval->op == TOKindex + && ((IndexExp *)newval)->e1 == aggregate) + { // It's a circular reference, resolve it now + newval = newval->interpret(istate); + } + + // For slice assignment, we check that the lengths match. + size_t srclen = 0; + if (newval->op == TOKarrayliteral) + srclen = ((ArrayLiteralExp *)newval)->elements->dim; + else if (newval->op == TOKstring) + srclen = ((StringExp *)newval)->len; + if (!isBlockAssignment && srclen != (upperbound - lowerbound)) + { + originalExp->error("Array length mismatch assigning [0..%d] to [%d..%d]", srclen, lowerbound, upperbound); + return EXP_CANT_INTERPRET; + } + + if (!isBlockAssignment && newval->op == TOKarrayliteral && existingAE) + { + Expressions *oldelems = existingAE->elements; + Expressions *newelems = ((ArrayLiteralExp *)newval)->elements; + Type *elemtype = existingAE->type->nextOf(); + for (size_t j = 0; j < newelems->dim; j++) + { + (*oldelems)[j + firstIndex] = paintTypeOntoLiteral(elemtype, (*newelems)[j]); + } + return newval; + } + else if (newval->op == TOKstring && existingSE) + { + sliceAssignStringFromString((StringExp *)existingSE, (StringExp *)newval, firstIndex); + return newval; + } + else if (newval->op == TOKstring && existingAE + && existingAE->type->isString()) + { /* Mixed slice: it was initialized as an array literal of chars. + * Now a slice of it is being set with a string. + */ + sliceAssignArrayLiteralFromString(existingAE, (StringExp *)newval, firstIndex); + return newval; + } + else if (newval->op == TOKarrayliteral && existingSE) + { /* Mixed slice: it was initialized as a string literal. + * Now a slice of it is being set with an array literal. + */ + sliceAssignStringFromArrayLiteral(existingSE, (ArrayLiteralExp *)newval, firstIndex); + return newval; + } + else if (existingSE) + { // String literal block slice assign + unsigned value = newval->toInteger(); + utf8_t *s = (utf8_t *)existingSE->string; + for (size_t j = 0; j < upperbound-lowerbound; j++) + { + switch (existingSE->sz) + { + case 1: s[j+firstIndex] = value; break; + case 2: ((unsigned short *)s)[j+firstIndex] = value; break; + case 4: ((unsigned *)s)[j+firstIndex] = value; break; + default: + assert(0); + break; + } + } + if (goal == ctfeNeedNothing) + return NULL; // avoid creating an unused literal + SliceExp *retslice = new SliceExp(loc, existingSE, + new IntegerExp(loc, firstIndex, Type::tsize_t), + new IntegerExp(loc, firstIndex + upperbound-lowerbound, Type::tsize_t)); + retslice->type = originalExp->type; + return retslice->interpret(istate); + } + else if (existingAE) + { + /* Block assignment, initialization of static arrays + * x[] = e + * x may be a multidimensional static array. (Note that this + * only happens with array literals, never with strings). + */ + Expressions * w = existingAE->elements; + assert( existingAE->type->ty == Tsarray || + existingAE->type->ty == Tarray); +#if DMDV2 + Type *desttype = ((TypeArray *)existingAE->type)->next->castMod(0); + bool directblk = (e2->type->toBasetype()->castMod(0))->equals(desttype); +#else + Type *desttype = ((TypeArray *)existingAE->type)->next; + bool directblk = (e2->type->toBasetype())->equals(desttype); +#endif + bool cow = !(newval->op == TOKstructliteral || newval->op == TOKarrayliteral + || newval->op == TOKstring); + for (size_t j = 0; j < upperbound-lowerbound; j++) + { + if (!directblk) + // Multidimensional array block assign + recursiveBlockAssign((ArrayLiteralExp *)(*w)[j+firstIndex], newval, wantRef); + else + { + if (wantRef || cow) + (*existingAE->elements)[j+firstIndex] = newval; + else + assignInPlace((*existingAE->elements)[j+firstIndex], newval); + } + } + if (goal == ctfeNeedNothing) + return NULL; // avoid creating an unused literal + SliceExp *retslice = new SliceExp(loc, existingAE, + new IntegerExp(loc, firstIndex, Type::tsize_t), + new IntegerExp(loc, firstIndex + upperbound-lowerbound, Type::tsize_t)); + retslice->type = originalExp->type; + return retslice->interpret(istate); + } + else + { + originalExp->error("Slice operation %s = %s cannot be evaluated at compile time", sexp->toChars(), newval->toChars()); + return EXP_CANT_INTERPRET; + } +} + Expression *AssignExp::interpret(InterState *istate, CtfeGoal goal) { return interpretAssignCommon(istate, goal, NULL); @@ -4047,10 +4715,21 @@ Expression *CallExp::interpret(InterState *istate, CtfeGoal goal) VarDeclaration *vthis = ((VarExp*)thisval)->var->isVarDeclaration(); assert(vthis); thisval = getVarExp(loc, istate, vthis, ctfeNeedLvalue); + if (exceptionOrCantInterpret(thisval)) + return thisval; // If it is a reference, resolve it if (thisval->op != TOKnull && thisval->op != TOKclassreference) thisval = pthis->interpret(istate); } + else if (pthis->op == TOKsymoff) + { + VarDeclaration *vthis = ((SymOffExp*)thisval)->var->isVarDeclaration(); + assert(vthis); + thisval = getVarExp(loc, istate, vthis, ctfeNeedLvalue); + if (exceptionOrCantInterpret(thisval)) + return thisval; + } + // Get the function from the vtable of the original class ClassDeclaration *cd; if (thisval && thisval->op == TOKnull) @@ -4197,7 +4876,7 @@ Expression *CondExp::interpret(InterState *istate, CtfeGoal goal) Expression *e; if ( isPointer(econd->type) ) { - e = econd->interpret(istate, ctfeNeedLvalue); + e = econd->interpret(istate); if (exceptionOrCantInterpret(e)) return e; if (e->op != TOKnull) @@ -4276,12 +4955,21 @@ Expression *IndexExp::interpret(InterState *istate, CtfeGoal goal) { dinteger_t len = ArrayLength(Type::tsize_t, agg)->toInteger(); //Type *pointee = ((TypePointer *)agg->type)->next; - if ((indx + ofs) < 0 || (indx+ofs) > len) + if ((sinteger_t)(indx + ofs) < 0 || (indx+ofs) > len) { error("pointer index [%lld] exceeds allocated memory block [0..%lld]", indx+ofs, len); return EXP_CANT_INTERPRET; } + if (goal == ctfeNeedLvalueRef) + { + // if we need a reference, IndexExp shouldn't be interpreting + // the expression to a value, it should stay as a reference + Expression *e = new IndexExp(loc, agg, + ofs ? new IntegerExp(loc,indx + ofs, e2->type) : e2); + e->type = type; + return e; + } return ctfeIndex(loc, type, agg, indx+ofs); } else @@ -4297,6 +4985,10 @@ Expression *IndexExp::interpret(InterState *istate, CtfeGoal goal) indx+ofs); return EXP_CANT_INTERPRET; } + if (goal == ctfeNeedLvalueRef) + { + return paintTypeOntoLiteral(type, agg); + } return agg->interpret(istate); } } @@ -4309,7 +5001,7 @@ Expression *IndexExp::interpret(InterState *istate, CtfeGoal goal) if (e1->op == TOKnull) { - if (goal == ctfeNeedLvalue && e1->type->ty == Taarray) + if (goal == ctfeNeedLvalue && e1->type->ty == Taarray && modifiable) return paintTypeOntoLiteral(type, e1); error("cannot index null array %s", this->e1->toChars()); return EXP_CANT_INTERPRET; @@ -4708,7 +5400,7 @@ Expression *CastExp::interpret(InterState *istate, CtfeGoal goal) e->type = type; return e; } - if (e1->op == TOKindex && ((IndexExp *)e1)->e1->type != e1->type) + if (e1->op == TOKindex && !((IndexExp *)e1)->e1->type->equals(e1->type)) { // type painting operation IndexExp *ie = (IndexExp *)e1; e = new IndexExp(e1->loc, ie->e1, ie->e2); @@ -4722,7 +5414,7 @@ Expression *CastExp::interpret(InterState *istate, CtfeGoal goal) { ArrayLiteralExp *ale = (ArrayLiteralExp *)ie->e1; uinteger_t indx = ie->e2->toInteger(); if (indx < ale->elements->dim) - xx = ale->elements->tdata()[indx]; + xx = (*ale->elements)[indx]; } if (xx && xx->op == TOKindex) origType = ((IndexExp *)xx)->e1->type->nextOf(); @@ -4742,7 +5434,7 @@ Expression *CastExp::interpret(InterState *istate, CtfeGoal goal) } if (e1->op == TOKaddress) { - Type *origType = ((AddrExp *)e1)->type; + Type *origType = ((AddrExp *)e1)->e1->type; if (isSafePointerCast(origType, pointee)) { e = new AddrExp(loc, ((AddrExp *)e1)->e1); @@ -4763,7 +5455,7 @@ Expression *CastExp::interpret(InterState *istate, CtfeGoal goal) if (e1->op == TOKvar) e = new VarExp(loc, ((VarExp *)e1)->var); else - e = new SymOffExp(loc, ((SymOffExp *)e1)->var, 0); + e = new SymOffExp(loc, ((SymOffExp *)e1)->var, ((SymOffExp *)e1)->offset); e->type = to; return e; } @@ -4847,17 +5539,14 @@ Expression *AssertExp::interpret(InterState *istate, CtfeGoal goal) } else error("%s failed", toChars()); - goto Lcant; + return EXP_CANT_INTERPRET; } else { error("%s is not a compile-time boolean expression", e1->toChars()); - goto Lcant; + return EXP_CANT_INTERPRET; } return e1; - -Lcant: - return EXP_CANT_INTERPRET; } Expression *PtrExp::interpret(InterState *istate, CtfeGoal goal) @@ -4952,7 +5641,7 @@ Expression *PtrExp::interpret(InterState *istate, CtfeGoal goal) error("dereference of invalid pointer '%s'", e->toChars()); return EXP_CANT_INTERPRET; } - if (goal != ctfeNeedLvalue) + if (goal != ctfeNeedLvalue && goal != ctfeNeedLvalueRef) { if (e->op == TOKindex && e->type->ty == Tpointer) { @@ -5011,8 +5700,26 @@ Expression *PtrExp::interpret(InterState *istate, CtfeGoal goal) if (e->op == TOKaddress) { e = ((AddrExp*)e)->e1; - if (e->op == TOKdotvar || e->op == TOKindex) + // We're changing *&e to e. + // We needed the AddrExp to deal with type painting expressions + // we couldn't otherwise express. Now that the type painting is + // undone, we must simplify them. This applies to references + // (which will be a DotVarExp or IndexExp) and to local structs + // (which will be a VarExp). + + // We sometimes use DotVarExp and IndexExp to represent pointers, + // so in that case, they shouldn't be simplified. + + bool isCtfePtr = (e->op == TOKdotvar || e->op == TOKindex) + && isPointer(e->type); + + // We also must not simplify if it is already a struct Literal + // or array literal, because it has already been interpreted. + if ( !isCtfePtr && e->op != TOKstructliteral && + e->op != TOKassocarrayliteral && e->op != TOKarrayliteral) + { e = e->interpret(istate, goal); + } } else if (e->op == TOKvar) { @@ -5028,7 +5735,7 @@ Expression *PtrExp::interpret(InterState *istate, CtfeGoal goal) error("dereference of null pointer '%s'", e1->toChars()); return EXP_CANT_INTERPRET; } - e->type = type; + e = paintTypeOntoLiteral(type, e); } #if LOG @@ -5061,14 +5768,27 @@ Expression *DotVarExp::interpret(InterState *istate, CtfeGoal goal) ex = ((AddrExp *)ex)->e1; VarDeclaration *v = var->isVarDeclaration(); if (!v) + { error("CTFE internal error: %s", toChars()); + return EXP_CANT_INTERPRET; + } if (ex->op == TOKnull && ex->type->toBasetype()->ty == Tclass) { error("class '%s' is null and cannot be dereferenced", e1->toChars()); return EXP_CANT_INTERPRET; } + if (ex->op == TOKnull) + { error("dereference of null pointer '%s'", e1->toChars()); + return EXP_CANT_INTERPRET; + } if (ex->op == TOKstructliteral || ex->op == TOKclassreference) { StructLiteralExp *se = ex->op == TOKclassreference ? ((ClassReferenceExp *)ex)->value : (StructLiteralExp *)ex; + /* We don't know how to deal with overlapping fields + */ + if (se->sd->hasUnions) + { error("Unions with overlapping fields are not yet supported in CTFE"); + return EXP_CANT_INTERPRET; + } // We can't use getField, because it makes a copy int i = -1; if (ex->op == TOKclassreference) @@ -5080,7 +5800,7 @@ Expression *DotVarExp::interpret(InterState *istate, CtfeGoal goal) error("couldn't find field %s of type %s in %s", v->toChars(), type->toChars(), se->toChars()); return EXP_CANT_INTERPRET; } - e = se->elements->tdata()[i]; + e = (*se->elements)[i]; if (goal == ctfeNeedLvalue || goal == ctfeNeedLvalueRef) { // If it is an lvalue literal, return it... @@ -5095,7 +5815,7 @@ Expression *DotVarExp::interpret(InterState *istate, CtfeGoal goal) * CastExp. */ if (goal == ctfeNeedLvalue && e->op == TOKindex && - e->type == type && + e->type->equals(type) && isPointer(type) ) return e; // ...Otherwise, just return the (simplified) dotvar expression @@ -5105,8 +5825,8 @@ Expression *DotVarExp::interpret(InterState *istate, CtfeGoal goal) } if (!e) { - error("couldn't find field %s in %s", v->toChars(), type->toChars()); - e = EXP_CANT_INTERPRET; + error("Internal Compiler Error: Null field %s", v->toChars()); + return EXP_CANT_INTERPRET; } // If it is an rvalue literal, return it... if (e->op == TOKstructliteral || e->op == TOKarrayliteral || @@ -5115,8 +5835,7 @@ Expression *DotVarExp::interpret(InterState *istate, CtfeGoal goal) if (e->op == TOKvoid) { VoidInitExp *ve = (VoidInitExp *)e; - error("cannot read uninitialized variable %s in ctfe", toChars()); - ve->var->error("was uninitialized and used before set"); + error("cannot read uninitialized variable %s in CTFE", ve->var->toChars()); return EXP_CANT_INTERPRET; } if ( isPointer(type) ) @@ -5162,13 +5881,15 @@ Expression *RemoveExp::interpret(InterState *istate, CtfeGoal goal) Expressions *valuesx = aae->values; size_t removed = 0; for (size_t j = 0; j < valuesx->dim; ++j) - { Expression *ekey = keysx->tdata()[j]; + { + Expression *ekey = (*keysx)[j]; int eq = ctfeEqual(loc, TOKequal, ekey, index); if (eq) ++removed; else if (removed != 0) - { keysx->tdata()[j - removed] = ekey; - valuesx->tdata()[j - removed] = valuesx->tdata()[j]; + { + (*keysx)[j - removed] = ekey; + (*valuesx)[j - removed] = (*valuesx)[j]; } } valuesx->dim = valuesx->dim - removed; @@ -5255,11 +5976,7 @@ Expression *interpret_aaApply(InterState *istate, Expression *aa, Expression *de assert(fd && fd->fbody); assert(fd->parameters); int numParams = fd->parameters->dim; - assert(numParams == 1 || numParams==2); - - Type *valueType = fd->parameters->tdata()[numParams-1]->type; - Type *keyType = numParams == 2 ? fd->parameters->tdata()[0]->type - : Type::tsize_t; + assert(numParams == 1 || numParams == 2); Parameter *valueArg = Parameter::getNth(((TypeFunction *)fd->type)->parameters, numParams - 1); bool wantRefValue = 0 != (valueArg->storageClass & (STCout | STCref)); @@ -5274,8 +5991,8 @@ Expression *interpret_aaApply(InterState *istate, Expression *aa, Expression *de for (size_t i = 0; i < ae->keys->dim; ++i) { - Expression *ekey = ae->keys->tdata()[i]; - Expression *evalue = ae->values->tdata()[i]; + Expression *ekey = (*ae->keys)[i]; + Expression *evalue = (*ae->values)[i]; if (wantRefValue) { Type *t = evalue->type; evalue = new IndexExp(deleg->loc, ae, ekey); @@ -5326,8 +6043,8 @@ Expression *foreachApplyUtf(InterState *istate, Expression *str, Expression *del assert(fd->parameters); int numParams = fd->parameters->dim; assert(numParams == 1 || numParams==2); - Type *charType = fd->parameters->tdata()[numParams-1]->type; - Type *indexType = numParams == 2 ? fd->parameters->tdata()[0]->type + Type *charType = (*fd->parameters)[numParams-1]->type; + Type *indexType = numParams == 2 ? (*fd->parameters)[0]->type : Type::tsize_t; uinteger_t len = resolveArrayLength(str); if (len == 0) @@ -5352,7 +6069,7 @@ Expression *foreachApplyUtf(InterState *istate, Expression *str, Expression *del Expression *eresult; // Buffers for encoding; also used for decoding array literals - unsigned char utf8buf[4]; + utf8_t utf8buf[4]; unsigned short utf16buf[2]; size_t start = rvs ? len : 0; @@ -5379,9 +6096,10 @@ Expression *foreachApplyUtf(InterState *istate, Expression *str, Expression *del --indx; buflen = 1; while (indx > 0 && buflen < 4) - { Expression * r = ale->elements->tdata()[indx]; + { + Expression * r = (*ale->elements)[indx]; assert(r->op == TOKint64); - unsigned char x = (unsigned char)(((IntegerExp *)r)->value); + utf8_t x = (utf8_t)(((IntegerExp *)r)->value); if ( (x & 0xC0) != 0x80) break; ++buflen; @@ -5391,9 +6109,9 @@ Expression *foreachApplyUtf(InterState *istate, Expression *str, Expression *del buflen = (indx + 4 > len) ? len - indx : 4; for (int i = 0; i < buflen; ++i) { - Expression * r = ale->elements->tdata()[indx + i]; + Expression * r = (*ale->elements)[indx + i]; assert(r->op == TOKint64); - utf8buf[i] = (unsigned char)(((IntegerExp *)r)->value); + utf8buf[i] = (utf8_t)(((IntegerExp *)r)->value); } n = 0; errmsg = utf_decodeChar(&utf8buf[0], buflen, &n, &rawvalue); @@ -5403,7 +6121,7 @@ Expression *foreachApplyUtf(InterState *istate, Expression *str, Expression *del { // find the start of the string --indx; buflen = 1; - Expression * r = ale->elements->tdata()[indx]; + Expression * r = (*ale->elements)[indx]; assert(r->op == TOKint64); unsigned short x = (unsigned short)(((IntegerExp *)r)->value); if (indx > 0 && x >= 0xDC00 && x <= 0xDFFF) @@ -5416,7 +6134,7 @@ Expression *foreachApplyUtf(InterState *istate, Expression *str, Expression *del buflen = (indx + 2 > len) ? len - indx : 2; for (int i=0; i < buflen; ++i) { - Expression * r = ale->elements->tdata()[indx + i]; + Expression * r = (*ale->elements)[indx + i]; assert(r->op == TOKint64); utf16buf[i] = (unsigned short)(((IntegerExp *)r)->value); } @@ -5428,7 +6146,7 @@ Expression *foreachApplyUtf(InterState *istate, Expression *str, Expression *del if (rvs) --indx; - Expression * r = ale->elements->tdata()[indx]; + Expression * r = (*ale->elements)[indx]; assert(r->op == TOKint64); rawvalue = ((IntegerExp *)r)->value; n = 1; @@ -5449,13 +6167,13 @@ Expression *foreachApplyUtf(InterState *istate, Expression *str, Expression *del case 1: if (rvs) { // find the start of the string - unsigned char *s = (unsigned char *)se->string; + utf8_t *s = (utf8_t *)se->string; --indx; while (indx > 0 && ((s[indx]&0xC0)==0x80)) --indx; saveindx = indx; } - errmsg = utf_decodeChar((unsigned char *)se->string, se->len, &indx, &rawvalue); + errmsg = utf_decodeChar((utf8_t *)se->string, se->len, &indx, &rawvalue); if (rvs) indx = saveindx; break; @@ -5571,7 +6289,7 @@ Expression *evaluateIfBuiltin(InterState *istate, Loc loc, } if (!pthis) { - enum BUILTIN b = fd->isBuiltin(); + BUILTIN b = fd->isBuiltin(); if (b) { Expressions args; args.setDim(nargs); @@ -5630,10 +6348,10 @@ Expression *evaluateIfBuiltin(InterState *istate, Loc loc, assert(arguments->dim <= se->elements->dim); for (int i = 0; i < arguments->dim; ++i) { - Expression *e = (*arguments)[i]->interpret(istate); + e = (*arguments)[i]->interpret(istate); if (exceptionOrCantInterpret(e)) return e; - se->elements->tdata()[i] = e; + (*se->elements)[i] = e; } return EXP_VOID_INTERPRET; } diff --git a/dmd2/intrange.h b/dmd2/intrange.h index 747e4ae7..359e99bc 100644 --- a/dmd2/intrange.h +++ b/dmd2/intrange.h @@ -13,8 +13,8 @@ #define DMD_SXNUM_H #include "mars.h" // for uinteger_t -struct Type; -struct Expression; +class Type; +class Expression; /** This class represents a "sign-extended number", i.e. a 65-bit number, which can diff --git a/dmd2/json.c b/dmd2/json.c index 373215d3..342e9f39 100644 --- a/dmd2/json.c +++ b/dmd2/json.c @@ -68,9 +68,9 @@ struct JsonOut void property(const char *name, Type* type); void property(const char *name, const char *deconame, Type* type); void property(const char *name, Parameters* parameters); - void property(const char *name, enum TRUST trust); - void property(const char *name, enum PURE purity); - void property(const char *name, enum LINK linkage); + void property(const char *name, TRUST trust); + void property(const char *name, PURE purity); + void property(const char *name, LINK linkage); }; @@ -82,7 +82,7 @@ void json_generate(OutBuffer *buf, Modules *modules) for (size_t i = 0; i < modules->dim; i++) { Module *m = (*modules)[i]; if (global.params.verbose) - printf("json gen %s\n", m->toChars()); + fprintf(global.stdmsg, "json gen %s\n", m->toChars()); m->toJson(&json); } json.arrayEnd(); @@ -128,7 +128,7 @@ void JsonOut::stringPart(const char *s) { for (; *s; s++) { - unsigned char c = (unsigned char) *s; + utf8_t c = (utf8_t) *s; switch (c) { case '\n': @@ -307,7 +307,7 @@ void JsonOut::propertyBool(const char *name, bool b) } -void JsonOut::property(const char *name, enum TRUST trust) +void JsonOut::property(const char *name, TRUST trust) { switch (trust) { @@ -329,7 +329,7 @@ void JsonOut::property(const char *name, enum TRUST trust) } } -void JsonOut::property(const char *name, enum PURE purity) +void JsonOut::property(const char *name, PURE purity) { switch (purity) { @@ -354,7 +354,7 @@ void JsonOut::property(const char *name, enum PURE purity) } } -void JsonOut::property(const char *name, enum LINK linkage) +void JsonOut::property(const char *name, LINK linkage) { switch (linkage) { @@ -395,7 +395,7 @@ void JsonOut::propertyStorageClass(const char *name, StorageClass stc) { char tmp[20]; const char *p = StorageClassDeclaration::stcToChars(tmp, stc); assert(p); - assert(strlen(p) < sizeof(tmp)); + assert(strlen(p) < sizeof(tmp) / sizeof(tmp[0])); if (p[0] == '@') { indent(); @@ -544,7 +544,7 @@ void TypeQualified::toJson(JsonOut *json) // ident.ident.ident.etc json->arrayStart(); for (size_t i = 0; i < idents.dim; i++) - { Object *ident = idents[i]; + { RootObject *ident = idents[i]; json->item(ident->toChars()); } @@ -806,7 +806,6 @@ void ConditionalDeclaration::toJson(JsonOut *json) void ClassInfoDeclaration::toJson(JsonOut *json) { } -void ModuleInfoDeclaration::toJson(JsonOut *json) { } void TypeInfoDeclaration::toJson(JsonOut *json) { } #if DMDV2 void PostBlitDeclaration::toJson(JsonOut *json) { } @@ -971,9 +970,10 @@ void TemplateDeclaration::toJson(JsonOut *json) if (s->isTemplateThisParameter()) json->property("kind", "this"); else -#endif json->property("kind", "type"); - +#else + json->property("kind", "type"); +#endif json->property("type", "deco", type->specType); json->property("default", "defaultDeco", type->defaultType); diff --git a/dmd2/lexer.c b/dmd2/lexer.c index b244c5d5..d8b3989b 100644 --- a/dmd2/lexer.c +++ b/dmd2/lexer.c @@ -36,12 +36,7 @@ #include "id.h" #include "module.h" -#if _WIN32 && __DMC__ -// from \dm\src\include\setlocal.h -extern "C" const char * __cdecl __locale_decpoint; -#endif - -extern int HtmlNamedEntity(unsigned char *p, size_t length); +extern int HtmlNamedEntity(utf8_t *p, size_t length); #define LS 0x2028 // UTF line separator #define PS 0x2029 // UTF paragraph separator @@ -58,9 +53,9 @@ const int CMoctal = 0x1; const int CMhex = 0x2; const int CMidchar = 0x4; -inline unsigned char isoctal (unsigned char c) { return cmtable[c] & CMoctal; } -inline unsigned char ishex (unsigned char c) { return cmtable[c] & CMhex; } -inline unsigned char isidchar(unsigned char c) { return cmtable[c] & CMidchar; } +inline bool isoctal (utf8_t c) { return cmtable[c] & CMoctal; } +inline bool ishex (utf8_t c) { return cmtable[c] & CMhex; } +inline bool isidchar(utf8_t c) { return cmtable[c] & CMidchar; } static void cmtable_init() { @@ -108,22 +103,14 @@ const char *Token::toChars() switch (value) { case TOKint32v: -#if defined(IN_GCC) || defined(IN_LLVM) - sprintf(buffer,"%d",(d_int32)int64value); -#else sprintf(buffer,"%d",int32value); -#endif break; case TOKuns32v: case TOKcharv: case TOKwcharv: case TOKdcharv: -#if defined(IN_GCC) || defined(IN_LLVM) - sprintf(buffer,"%uU",(d_uns32)uns64value); -#else sprintf(buffer,"%uU",uns32value); -#endif break; case TOKint64v: @@ -134,20 +121,6 @@ const char *Token::toChars() sprintf(buffer,"%lluUL",(ulonglong)uns64value); break; -#ifdef IN_GCC - case TOKfloat32v: - case TOKfloat64v: - case TOKfloat80v: - float80value.format(buffer, sizeof(buffer)); - break; - case TOKimaginary32v: - case TOKimaginary64v: - case TOKimaginary80v: - float80value.format(buffer, sizeof(buffer)); - // %% buffer - strcat(buffer, "i"); - break; -#else case TOKfloat32v: ld_sprint(buffer, 'g', float80value); strcat(buffer, "f"); @@ -176,7 +149,6 @@ const char *Token::toChars() ld_sprint(buffer, 'g', float80value); strcat(buffer, "Li"); break; -#endif case TOKstring: { OutBuffer buf; @@ -185,7 +157,7 @@ const char *Token::toChars() for (size_t i = 0; i < len; ) { unsigned c; - utf_decodeChar((unsigned char *)ustring, len, &i, &c); + utf_decodeChar((utf8_t *)ustring, len, &i, &c); switch (c) { case 0: @@ -230,7 +202,7 @@ const char *Token::toChars() return p; } -const char *Token::toChars(enum TOK value) +const char *Token::toChars(TOK value) { const char *p; static char buffer[3 + 3 * sizeof(value) + 1]; @@ -249,10 +221,10 @@ StringTable Lexer::stringtable; OutBuffer Lexer::stringbuffer; Lexer::Lexer(Module *mod, - unsigned char *base, size_t begoffset, size_t endoffset, + utf8_t *base, size_t begoffset, size_t endoffset, int doDocComment, int commentToken) - : loc(mod, 1) { + scanloc = Loc(mod, 1); //printf("Lexer::Lexer(%p,%d)\n",base,length); //printf("lexer.mod = %p, %p\n", mod, this->loc.mod); memset(&token,0,sizeof(token)); @@ -272,7 +244,7 @@ Lexer::Lexer(Module *mod, { p += 2; while (1) - { unsigned char c = *p; + { utf8_t c = *p; switch (c) { case '\n': @@ -300,7 +272,7 @@ Lexer::Lexer(Module *mod, } break; } - loc.linnum = 2; + scanloc.linnum = 2; } } @@ -309,7 +281,7 @@ void Lexer::error(const char *format, ...) { va_list ap; va_start(ap, format); - ::verror(tokenLoc(), format, ap); + ::verror(token.loc, format, ap); va_end(ap); } @@ -325,16 +297,15 @@ void Lexer::deprecation(const char *format, ...) { va_list ap; va_start(ap, format); - ::vdeprecation(tokenLoc(), format, ap); + ::vdeprecation(token.loc, format, ap); va_end(ap); } TOK Lexer::nextToken() -{ Token *t; - +{ if (token.next) { - t = token.next; + Token *t = token.next; memcpy(&token,t,sizeof(Token)); t->next = freelist; freelist = t; @@ -348,8 +319,8 @@ TOK Lexer::nextToken() } Token *Lexer::peek(Token *ct) -{ Token *t; - +{ + Token *t; if (ct->next) t = ct->next; else @@ -454,7 +425,7 @@ int Lexer::isValidIdentifier(char *p) while (p[idx]) { dchar_t dc; - const char *q = utf_decodeChar((unsigned char *)p, len, &idx, &dc); + const char *q = utf_decodeChar((utf8_t *)p, len, &idx, &dc); if (q) goto Linvalid; @@ -473,7 +444,7 @@ Linvalid: void Lexer::scan(Token *t) { - unsigned lastLine = loc.linnum; + unsigned lastLine = scanloc.linnum; unsigned linnum; t->blockComment = NULL; @@ -482,6 +453,7 @@ void Lexer::scan(Token *t) { t->ptr = p; //printf("p = %p, *p = '%c'\n",p,*p); + t->loc = scanloc; switch (*p) { case 0: @@ -499,12 +471,12 @@ void Lexer::scan(Token *t) case '\r': p++; if (*p != '\n') // if CR stands by itself - loc.linnum++; + scanloc.linnum++; continue; // skip white space case '\n': p++; - loc.linnum++; + scanloc.linnum++; continue; // skip white space case '0': case '1': case '2': case '3': case '4': @@ -556,7 +528,7 @@ void Lexer::scan(Token *t) #if ! TEXTUAL_ASSEMBLY_OUT case '\\': // escaped string literal { unsigned c; - unsigned char *pstart = p; + utf8_t *pstart = p; stringbuffer.reset(); do @@ -579,7 +551,7 @@ void Lexer::scan(Token *t) } while (*p == '\\'); t->len = stringbuffer.offset; stringbuffer.writeByte(0); - t->ustring = (unsigned char *)mem.malloc(stringbuffer.offset); + t->ustring = (utf8_t *)mem.malloc(stringbuffer.offset); memcpy(t->ustring, stringbuffer.data, stringbuffer.offset); t->postfix = 0; t->value = TOKstring; @@ -608,7 +580,7 @@ void Lexer::scan(Token *t) case 'Z': case '_': case_ident: - { unsigned char c; + { utf8_t c; while (1) { @@ -616,7 +588,7 @@ void Lexer::scan(Token *t) if (isidchar(c)) continue; else if (c & 0x80) - { unsigned char *s = p; + { utf8_t *s = p; unsigned u = decodeUTF(); if (isUniAlpha(u)) continue; @@ -630,23 +602,24 @@ void Lexer::scan(Token *t) Identifier *id = (Identifier *) sv->ptrvalue; if (!id) { id = new Identifier(sv->toDchars(),TOKidentifier); - sv->ptrvalue = id; + sv->ptrvalue = (char *)id; } t->ident = id; - t->value = (enum TOK) id->value; + t->value = (TOK) id->value; anyToken = 1; if (*t->ptr == '_') // if special identifier token { + static bool initdone = false; static char date[11+1]; static char time[8+1]; static char timestamp[24+1]; - if (!date[0]) // lazy evaluation - { time_t t; - char *p; - + if (!initdone) // lazy evaluation + { + initdone = true; + time_t t; ::time(&t); - p = ctime(&t); + char *p = ctime(&t); assert(p); sprintf(date, "%.6s %.4s", p + 4, p + 20); sprintf(time, "%.8s", p + 11); @@ -656,34 +629,34 @@ void Lexer::scan(Token *t) #if DMDV1 if (mod && id == Id::FILE) { - t->ustring = (unsigned char *)(loc.filename ? loc.filename : mod->ident->toChars()); + t->ustring = (utf8_t *)(loc.filename ? loc.filename : mod->ident->toChars()); goto Lstr; } else if (mod && id == Id::LINE) { t->value = TOKint64v; - t->uns64value = loc.linnum; + t->uns64value = scanloc.linnum; } else #endif if (id == Id::DATE) { - t->ustring = (unsigned char *)date; + t->ustring = (utf8_t *)date; goto Lstr; } else if (id == Id::TIME) { - t->ustring = (unsigned char *)time; + t->ustring = (utf8_t *)time; goto Lstr; } else if (id == Id::VENDOR) { - t->ustring = (unsigned char *)global.compiler.vendor; + t->ustring = (utf8_t *)global.compiler.vendor; goto Lstr; } else if (id == Id::TIMESTAMP) { - t->ustring = (unsigned char *)timestamp; + t->ustring = (utf8_t *)timestamp; Lstr: t->value = TOKstring; t->postfix = 0; @@ -697,7 +670,7 @@ void Lexer::scan(Token *t) for (const char *p = global.version + 1; 1; p++) { char c = *p; - if (isdigit((unsigned char)c)) + if (isdigit((utf8_t)c)) minor = minor * 10 + c - '0'; else if (c == '.') { @@ -738,31 +711,32 @@ void Lexer::scan(Token *t) case '*': p++; - linnum = loc.linnum; + linnum = scanloc.linnum; while (1) { while (1) - { unsigned char c = *p; + { utf8_t c = *p; switch (c) { case '/': break; case '\n': - loc.linnum++; + scanloc.linnum++; p++; continue; case '\r': p++; if (*p != '\n') - loc.linnum++; + scanloc.linnum++; continue; case 0: case 0x1A: error("unterminated /* */ comment"); p = end; + t->loc = scanloc; t->value = TOKeof; return; @@ -770,7 +744,7 @@ void Lexer::scan(Token *t) if (c & 0x80) { unsigned u = decodeUTF(); if (u == PS || u == LS) - loc.linnum++; + scanloc.linnum++; } p++; continue; @@ -783,6 +757,8 @@ void Lexer::scan(Token *t) } if (commentToken) { + t->loc.filename = scanloc.filename; + t->loc.linnum = linnum; t->value = TOKcomment; return; } @@ -793,9 +769,9 @@ void Lexer::scan(Token *t) continue; case '/': // do // style comments - linnum = loc.linnum; + linnum = scanloc.linnum; while (1) - { unsigned char c = *++p; + { utf8_t c = *++p; switch (c) { case '\n': @@ -811,12 +787,15 @@ void Lexer::scan(Token *t) if (commentToken) { p = end; + t->loc.filename = scanloc.filename; + t->loc.linnum = linnum; t->value = TOKcomment; return; } if (doDocComment && t->ptr[2] == '/') getDocComment(t, lastLine == linnum); p = end; + t->loc = scanloc; t->value = TOKeof; return; @@ -834,7 +813,9 @@ void Lexer::scan(Token *t) if (commentToken) { p++; - loc.linnum++; + scanloc.linnum++; + t->loc.filename = scanloc.filename; + t->loc.linnum = linnum; t->value = TOKcomment; return; } @@ -842,17 +823,17 @@ void Lexer::scan(Token *t) getDocComment(t, lastLine == linnum); p++; - loc.linnum++; + scanloc.linnum++; continue; case '+': { int nest; - linnum = loc.linnum; + linnum = scanloc.linnum; p++; nest = 1; while (1) - { unsigned char c = *p; + { utf8_t c = *p; switch (c) { case '/': @@ -877,11 +858,11 @@ void Lexer::scan(Token *t) case '\r': p++; if (*p != '\n') - loc.linnum++; + scanloc.linnum++; continue; case '\n': - loc.linnum++; + scanloc.linnum++; p++; continue; @@ -889,6 +870,7 @@ void Lexer::scan(Token *t) case 0x1A: error("unterminated /+ +/ comment"); p = end; + t->loc = scanloc; t->value = TOKeof; return; @@ -896,7 +878,7 @@ void Lexer::scan(Token *t) if (c & 0x80) { unsigned u = decodeUTF(); if (u == PS || u == LS) - loc.linnum++; + scanloc.linnum++; } p++; continue; @@ -905,6 +887,8 @@ void Lexer::scan(Token *t) } if (commentToken) { + t->loc.filename = scanloc.filename; + t->loc.linnum = linnum; t->value = TOKcomment; return; } @@ -1066,12 +1050,7 @@ void Lexer::scan(Token *t) p++; if (*p == '=') { p++; - if (*p == '=' && global.params.Dversion == 1) - { p++; - t->value = TOKnotidentity; // !== - } - else - t->value = TOKnotequal; // != + t->value = TOKnotequal; // != } else if (*p == '<') { p++; @@ -1108,12 +1087,7 @@ void Lexer::scan(Token *t) p++; if (*p == '=') { p++; - if (*p == '=' && global.params.Dversion == 1) - { p++; - t->value = TOKidentity; // === - } - else - t->value = TOKequal; // == + t->value = TOKequal; // == } #if DMDV2 else if (*p == '>') @@ -1221,7 +1195,7 @@ void Lexer::scan(Token *t) if (c == PS || c == LS) { - loc.linnum++; + scanloc.linnum++; p++; continue; } @@ -1312,7 +1286,7 @@ unsigned Lexer::escapeSequence() break; case '&': // named character entity - for (unsigned char *idstart = ++p; 1; p++) + for (utf8_t *idstart = ++p; 1; p++) { switch (*p) { @@ -1367,8 +1341,9 @@ unsigned Lexer::escapeSequence() */ TOK Lexer::wysiwygStringConstant(Token *t, int tc) -{ unsigned c; - Loc start = loc; +{ + unsigned c; + Loc start = scanloc; p++; stringbuffer.reset(); @@ -1378,20 +1353,20 @@ TOK Lexer::wysiwygStringConstant(Token *t, int tc) switch (c) { case '\n': - loc.linnum++; + scanloc.linnum++; break; case '\r': if (*p == '\n') continue; // ignore c = '\n'; // treat EndOfLine as \n character - loc.linnum++; + scanloc.linnum++; break; case 0: case 0x1A: error("unterminated string constant starting at %s", start.toChars()); - t->ustring = (unsigned char *)""; + t->ustring = (utf8_t *)""; t->len = 0; t->postfix = 0; return TOKstring; @@ -1402,7 +1377,7 @@ TOK Lexer::wysiwygStringConstant(Token *t, int tc) { t->len = stringbuffer.offset; stringbuffer.writeByte(0); - t->ustring = (unsigned char *)mem.malloc(stringbuffer.offset); + t->ustring = (utf8_t *)mem.malloc(stringbuffer.offset); memcpy(t->ustring, stringbuffer.data, stringbuffer.offset); stringPostfix(t); return TOKstring; @@ -1415,7 +1390,7 @@ TOK Lexer::wysiwygStringConstant(Token *t, int tc) unsigned u = decodeUTF(); p++; if (u == PS || u == LS) - loc.linnum++; + scanloc.linnum++; stringbuffer.writeUTF8(u); continue; } @@ -1431,8 +1406,9 @@ TOK Lexer::wysiwygStringConstant(Token *t, int tc) */ TOK Lexer::hexStringConstant(Token *t) -{ unsigned c; - Loc start = loc; +{ + unsigned c; + Loc start = scanloc; unsigned n = 0; unsigned v; @@ -1454,13 +1430,13 @@ TOK Lexer::hexStringConstant(Token *t) continue; // ignore // Treat isolated '\r' as if it were a '\n' case '\n': - loc.linnum++; + scanloc.linnum++; continue; case 0: case 0x1A: error("unterminated string constant starting at %s", start.toChars()); - t->ustring = (unsigned char *)""; + t->ustring = (utf8_t *)""; t->len = 0; t->postfix = 0; return TOKstring; @@ -1472,7 +1448,7 @@ TOK Lexer::hexStringConstant(Token *t) } t->len = stringbuffer.offset; stringbuffer.writeByte(0); - t->ustring = (unsigned char *)mem.malloc(stringbuffer.offset); + t->ustring = (utf8_t *)mem.malloc(stringbuffer.offset); memcpy(t->ustring, stringbuffer.data, stringbuffer.offset); stringPostfix(t); return TOKstring; @@ -1489,7 +1465,7 @@ TOK Lexer::hexStringConstant(Token *t) unsigned u = decodeUTF(); p++; if (u == PS || u == LS) - loc.linnum++; + scanloc.linnum++; else error("non-hex character \\u%04x", u); } @@ -1522,8 +1498,9 @@ TOK Lexer::hexStringConstant(Token *t) */ TOK Lexer::delimitedStringConstant(Token *t) -{ unsigned c; - Loc start = loc; +{ + unsigned c; + Loc start = scanloc; unsigned delimleft = 0; unsigned delimright = 0; unsigned nest = 1; @@ -1542,7 +1519,7 @@ TOK Lexer::delimitedStringConstant(Token *t) { case '\n': Lnextline: - loc.linnum++; + scanloc.linnum++; startline = 1; if (blankrol) { blankrol = 0; @@ -1637,7 +1614,7 @@ TOK Lexer::delimitedStringConstant(Token *t) #endif ) { Token t; - unsigned char *psave = p; + utf8_t *psave = p; p--; scan(&t); // read in possible heredoc identifier //printf("endid = '%s'\n", t.ident->toChars()); @@ -1660,14 +1637,14 @@ Ldone: error("delimited string must end in %c\"", delimright); t->len = stringbuffer.offset; stringbuffer.writeByte(0); - t->ustring = (unsigned char *)mem.malloc(stringbuffer.offset); + t->ustring = (utf8_t *)mem.malloc(stringbuffer.offset); memcpy(t->ustring, stringbuffer.data, stringbuffer.offset); stringPostfix(t); return TOKstring; Lerror: error("unterminated string constant starting at %s", start.toChars()); - t->ustring = (unsigned char *)""; + t->ustring = (utf8_t *)""; t->len = 0; t->postfix = 0; return TOKstring; @@ -1685,8 +1662,8 @@ Lerror: TOK Lexer::tokenStringConstant(Token *t) { unsigned nest = 1; - Loc start = loc; - unsigned char *pstart = ++p; + Loc start = scanloc; + utf8_t *pstart = ++p; while (1) { Token tok; @@ -1713,7 +1690,7 @@ TOK Lexer::tokenStringConstant(Token *t) Ldone: t->len = p - 1 - pstart; - t->ustring = (unsigned char *)mem.malloc(t->len + 1); + t->ustring = (utf8_t *)mem.malloc(t->len + 1); memcpy(t->ustring, pstart, t->len); t->ustring[t->len] = 0; stringPostfix(t); @@ -1721,7 +1698,7 @@ Ldone: Lerror: error("unterminated token string constant starting at %s", start.toChars()); - t->ustring = (unsigned char *)""; + t->ustring = (utf8_t *)""; t->len = 0; t->postfix = 0; return TOKstring; @@ -1734,8 +1711,9 @@ Lerror: */ TOK Lexer::escapeStringConstant(Token *t, int wide) -{ unsigned c; - Loc start = loc; +{ + unsigned c; + Loc start = scanloc; p++; stringbuffer.reset(); @@ -1762,20 +1740,20 @@ TOK Lexer::escapeStringConstant(Token *t, int wide) break; #endif case '\n': - loc.linnum++; + scanloc.linnum++; break; case '\r': if (*p == '\n') continue; // ignore c = '\n'; // treat EndOfLine as \n character - loc.linnum++; + scanloc.linnum++; break; case '"': t->len = stringbuffer.offset; stringbuffer.writeByte(0); - t->ustring = (unsigned char *)mem.malloc(stringbuffer.offset); + t->ustring = (utf8_t *)mem.malloc(stringbuffer.offset); memcpy(t->ustring, stringbuffer.data, stringbuffer.offset); stringPostfix(t); return TOKstring; @@ -1784,7 +1762,7 @@ TOK Lexer::escapeStringConstant(Token *t, int wide) case 0x1A: p--; error("unterminated string constant starting at %s", start.toChars()); - t->ustring = (unsigned char *)""; + t->ustring = (utf8_t *)""; t->len = 0; t->postfix = 0; return TOKstring; @@ -1796,7 +1774,7 @@ TOK Lexer::escapeStringConstant(Token *t, int wide) c = decodeUTF(); if (c == LS || c == PS) { c = '\n'; - loc.linnum++; + scanloc.linnum++; } p++; stringbuffer.writeUTF8(c); @@ -1844,7 +1822,7 @@ TOK Lexer::charConstant(Token *t, int wide) #endif case '\n': L1: - loc.linnum++; + scanloc.linnum++; case '\r': case 0: case 0x1A: @@ -1915,7 +1893,7 @@ TOK Lexer::number(Token *t) enum STATE { STATE_initial, STATE_0, STATE_decimal, STATE_octal, STATE_octale, STATE_hex, STATE_binary, STATE_hex0, STATE_binary0, STATE_hexh, STATE_error }; - enum STATE state; + STATE state; enum FLAGS { @@ -1924,10 +1902,10 @@ TOK Lexer::number(Token *t) FLAGS_unsigned = 2, // u or U suffix FLAGS_long = 4, // l or L suffix }; - enum FLAGS flags = FLAGS_decimal; + FLAGS flags = FLAGS_decimal; unsigned c; - unsigned char *start; + utf8_t *start; TOK result; //printf("Lexer::number()\n"); @@ -2117,7 +2095,7 @@ done: p += 2, r = 16; else if (p[1] == 'b' || p[1] == 'B') p += 2, r = 2; - else if (isdigit((unsigned char)p[1])) + else if (isdigit((utf8_t)p[1])) p += 1, r = 8; } @@ -2152,9 +2130,9 @@ done: } // Parse trailing 'u', 'U', 'l' or 'L' in any combination - const unsigned char *psuffix = p; + const utf8_t *psuffix = p; while (1) - { unsigned char f; + { utf8_t f; switch (*p) { case 'U': @@ -2367,52 +2345,25 @@ done: stringbuffer.writeByte(0); -#if _WIN32 && __DMC__ - const char *save = __locale_decpoint; - __locale_decpoint = "."; -#endif -#ifdef IN_GCC - t->float80value = real_t::parse((char *)stringbuffer.data, real_t::LongDouble); -#else t->float80value = Port::strtold((char *)stringbuffer.data, NULL); -#endif errno = 0; - float strtofres; - double strtodres; switch (*p) { case 'F': case 'f': -#ifdef IN_GCC - real_t::parse((char *)stringbuffer.data, real_t::Float); -#else - strtofres = strtof((char *)stringbuffer.data, NULL); -#ifdef IN_LLVM -#ifdef _MSC_VER -#define HUGE_VALF HUGE_VAL -#endif - // LDC change: don't error on gradual underflow - if (errno == ERANGE && - strtofres != 0 && strtofres != HUGE_VALF && strtofres != -HUGE_VALF) - errno = 0; -#endif -#endif + // Only interested in errno return + (void)Port::strtof((char *)stringbuffer.data, NULL); result = TOKfloat32v; p++; break; default: -#ifdef IN_GCC - real_t::parse((char *)stringbuffer.data, real_t::Double); -#else - strtodres = strtod((char *)stringbuffer.data, NULL); -#ifdef IN_LLVM - // LDC change: don't error on gradual underflow - if (errno == ERANGE && - strtodres != 0 && strtodres != HUGE_VAL && strtodres != -HUGE_VAL) - errno = 0; -#endif -#endif + /* Should do our own strtod(), since dmc and linux gcc + * accept 2.22507e-308, while apple gcc will only take + * 2.22508e-308. Not sure who is right. + */ + // Only interested in errno return + (void)Port::strtod((char *)stringbuffer.data, NULL); result = TOKfloat64v; break; @@ -2442,9 +2393,6 @@ done: default: break; } } -#if _WIN32 && __DMC__ - __locale_decpoint = save; -#endif if (errno == ERANGE) error("number is not representable"); return result; @@ -2453,6 +2401,7 @@ done: /********************************************* * parse: * #line linnum [filespec] + * also allow __LINE__ for linnum, and __FILE__ for filespec */ void Lexer::poundLine() @@ -2460,7 +2409,7 @@ void Lexer::poundLine() Token tok; int linnum; char *filespec = NULL; - Loc loc = this->loc; + Loc loc = this->scanloc; scan(&tok); if (tok.value == TOKint32v || tok.value == TOKint64v) @@ -2468,6 +2417,10 @@ void Lexer::poundLine() if (linnum != tok.uns64value - 1) error("line number out of range"); } + else if (tok.value == TOKline) + { + linnum = this->scanloc.linnum; + } else goto Lerr; @@ -2479,9 +2432,9 @@ void Lexer::poundLine() case 0x1A: case '\n': Lnewline: - this->loc.linnum = linnum; + this->scanloc.linnum = linnum; if (filespec) - this->loc.filename = filespec; + this->scanloc.filename = filespec; return; case '\r': @@ -2503,7 +2456,7 @@ void Lexer::poundLine() if (mod && memcmp(p, "__FILE__", 8) == 0) { p += 8; - filespec = mem.strdup(loc.filename ? loc.filename : mod->ident->toChars()); + filespec = mem.strdup(scanloc.filename ? scanloc.filename : mod->ident->toChars()); continue; } goto Lerr; @@ -2569,8 +2522,8 @@ Lerr: unsigned Lexer::decodeUTF() { dchar_t u; - unsigned char c; - unsigned char *s = p; + utf8_t c; + utf8_t *s = p; size_t len; size_t idx; const char *msg; @@ -2606,13 +2559,13 @@ void Lexer::getDocComment(Token *t, unsigned lineComment) { /* ct tells us which kind of comment it is: '/', '*', or '+' */ - unsigned char ct = t->ptr[2]; + utf8_t ct = t->ptr[2]; /* Start of comment text skips over / * *, / + +, or / / / */ - unsigned char *q = t->ptr + 3; // start of comment text + utf8_t *q = t->ptr + 3; // start of comment text - unsigned char *qend = p; + utf8_t *qend = p; if (ct == '*' || ct == '+') qend -= 2; @@ -2643,7 +2596,7 @@ void Lexer::getDocComment(Token *t, unsigned lineComment) for (; q < qend; q++) { - unsigned char c = *q; + utf8_t c = *q; switch (c) { @@ -2705,15 +2658,15 @@ void Lexer::getDocComment(Token *t, unsigned lineComment) // It's a line comment if the start of the doc comment comes // after other non-whitespace on the same line. - unsigned char** dc = (lineComment && anyToken) + utf8_t** dc = (lineComment && anyToken) ? &t->lineComment : &t->blockComment; // Combine with previous doc comment, if any if (*dc) - *dc = combineComments(*dc, (unsigned char *)buf.data); + *dc = combineComments(*dc, (utf8_t *)buf.data); else - *dc = (unsigned char *)buf.extractData(); + *dc = (utf8_t *)buf.extractData(); } /******************************************** @@ -2721,11 +2674,11 @@ void Lexer::getDocComment(Token *t, unsigned lineComment) * separated by a newline. */ -unsigned char *Lexer::combineComments(unsigned char *c1, unsigned char *c2) +utf8_t *Lexer::combineComments(utf8_t *c1, utf8_t *c2) { //printf("Lexer::combineComments('%s', '%s')\n", c1, c2); - unsigned char *c = c2; + utf8_t *c = c2; if (c1) { c = c1; @@ -2733,7 +2686,7 @@ unsigned char *Lexer::combineComments(unsigned char *c1, unsigned char *c2) { size_t len1 = strlen((char *)c1); size_t len2 = strlen((char *)c2); - c = (unsigned char *)mem.malloc(len1 + 1 + len2 + 1); + c = (utf8_t *)mem.malloc(len1 + 1 + len2 + 1); memcpy(c, c1, len1); if (len1 && c1[len1 - 1] != '\n') { c[len1] = '\n'; @@ -2746,38 +2699,6 @@ unsigned char *Lexer::combineComments(unsigned char *c1, unsigned char *c2) return c; } -/******************************************* - * Search actual location of current token - * even when infinite look-ahead was done. - */ -Loc Lexer::tokenLoc() -{ - Loc result = this->loc; - Token* last = &token; - while (last->next) - last = last->next; - - unsigned char* start = token.ptr; - unsigned char* stop = last->ptr; - - for (unsigned char* p = start; p < stop; ++p) - { - switch (*p) - { - case '\n': - result.linnum--; - break; - case '\r': - if (p[1] != '\n') - result.linnum--; - break; - default: - break; - } - } - return result; -} - /******************************************** * Create an identifier in the string table. */ @@ -2790,7 +2711,7 @@ Identifier *Lexer::idPool(const char *s) if (!id) { id = new Identifier(sv->toDchars(), TOKidentifier); - sv->ptrvalue = id; + sv->ptrvalue = (char *)id; } return id; } @@ -2819,7 +2740,7 @@ Identifier *Lexer::uniqueId(const char *s) struct Keyword { const char *name; - enum TOK value; + TOK value; }; static Keyword keywords[] = @@ -2972,18 +2893,15 @@ void Lexer::initKeywords() stringtable._init(6151); - if (global.params.Dversion == 1) - nkeywords -= 2; - cmtable_init(); for (size_t u = 0; u < nkeywords; u++) { //printf("keyword[%d] = '%s'\n",u, keywords[u].name); const char *s = keywords[u].name; - enum TOK v = keywords[u].value; + TOK v = keywords[u].value; StringValue *sv = stringtable.insert(s, strlen(s)); - sv->ptrvalue = (void *) new Identifier(sv->toDchars(),v); + sv->ptrvalue = (char *)new Identifier(sv->toDchars(),v); //printf("tochars[%d] = '%s'\n",v, s); Token::tochars[v] = s; @@ -3116,8 +3034,8 @@ void unittest_lexer() /* Not much here, just trying things out. */ - const unsigned char text[] = "int"; - Lexer lex1(NULL, (unsigned char *)text, 0, sizeof(text), 0, 0); + const utf8_t text[] = "int"; + Lexer lex1(NULL, (utf8_t *)text, 0, sizeof(text), 0, 0); TOK tok; tok = lex1.nextToken(); //printf("tok == %s, %d, %d\n", Token::toChars(tok), tok, TOKint32); diff --git a/dmd2/lexer.h b/dmd2/lexer.h index 88fdb4d6..b595de70 100644 --- a/dmd2/lexer.h +++ b/dmd2/lexer.h @@ -19,8 +19,8 @@ #include "mars.h" struct StringTable; -struct Identifier; -struct Module; +class Identifier; +class Module; /* Tokens: ( ) @@ -69,6 +69,8 @@ enum TOK TOKnewanonclass, TOKcomment, TOKarrayliteral, TOKassocarrayliteral, TOKstructliteral, + TOKclassreference, + TOKthrownexception, // Operators TOKlt, TOKgt, @@ -229,10 +231,11 @@ enum TOK struct Token { Token *next; - unsigned char *ptr; // pointer to first character of this token within buffer - enum TOK value; - unsigned char *blockComment; // doc comment string prior to this token - unsigned char *lineComment; // doc comment for previous token + Loc loc; + utf8_t *ptr; // pointer to first character of this token within buffer + TOK value; + utf8_t *blockComment; // doc comment string prior to this token + utf8_t *lineComment; // doc comment for previous token union { // Integers @@ -242,23 +245,16 @@ struct Token d_uns64 uns64value; // Floats -#ifdef IN_GCC - // real_t float80value; // can't use this in a union! -#else d_float80 float80value; -#endif struct - { unsigned char *ustring; // UTF8 string + { utf8_t *ustring; // UTF8 string unsigned len; unsigned char postfix; // 'c', 'w', 'd' }; Identifier *ident; }; -#ifdef IN_GCC - real_t float80value; // can't use this in a union! -#endif static const char *tochars[TOKMAX]; static void *operator new(size_t sz); @@ -269,20 +265,21 @@ struct Token void print(); #endif const char *toChars(); - static const char *toChars(enum TOK); + static const char *toChars(TOK); }; -struct Lexer +class Lexer { +public: static StringTable stringtable; static OutBuffer stringbuffer; static Token *freelist; - Loc loc; // for error messages + Loc scanloc; // for error messages - unsigned char *base; // pointer to start of buffer - unsigned char *end; // past end of buffer - unsigned char *p; // current character + utf8_t *base; // pointer to start of buffer + utf8_t *end; // past end of buffer + utf8_t *p; // current character Token token; Module *mod; int doDocComment; // collect doc comment information @@ -290,7 +287,7 @@ struct Lexer int commentToken; // !=0 means comments are TOKcomment's Lexer(Module *mod, - unsigned char *base, size_t begoffset, size_t endoffset, + utf8_t *base, size_t begoffset, size_t endoffset, int doDocComment, int commentToken); static void initKeywords(); @@ -324,9 +321,7 @@ struct Lexer void getDocComment(Token *t, unsigned lineComment); static int isValidIdentifier(char *p); - static unsigned char *combineComments(unsigned char *c1, unsigned char *c2); - - Loc tokenLoc(); + static utf8_t *combineComments(utf8_t *c1, utf8_t *c2); }; #endif /* DMD_LEXER_H */ diff --git a/dmd2/macro.c b/dmd2/macro.c index ae53002a..2bc63f6d 100644 --- a/dmd2/macro.c +++ b/dmd2/macro.c @@ -21,16 +21,16 @@ #include "macro.h" -int isIdStart(unsigned char *p); -int isIdTail(unsigned char *p); -int utfStride(unsigned char *p); +int isIdStart(utf8_t *p); +int isIdTail(utf8_t *p); +int utfStride(utf8_t *p); -unsigned char *memdup(unsigned char *p, size_t len) +utf8_t *memdup(utf8_t *p, size_t len) { - return (unsigned char *)memcpy(mem.malloc(len), p, len); + return (utf8_t *)memcpy(mem.malloc(len), p, len); } -Macro::Macro(unsigned char *name, size_t namelen, unsigned char *text, size_t textlen) +Macro::Macro(utf8_t *name, size_t namelen, utf8_t *text, size_t textlen) { next = NULL; @@ -51,7 +51,7 @@ Macro::Macro(unsigned char *name, size_t namelen, unsigned char *text, size_t te } -Macro *Macro::search(unsigned char *name, size_t namelen) +Macro *Macro::search(utf8_t *name, size_t namelen) { Macro *table; //printf("Macro::search(%.*s)\n", namelen, name); @@ -67,7 +67,7 @@ Macro *Macro::search(unsigned char *name, size_t namelen) return table; } -Macro *Macro::define(Macro **ptable, unsigned char *name, size_t namelen, unsigned char *text, size_t textlen) +Macro *Macro::define(Macro **ptable, utf8_t *name, size_t namelen, utf8_t *text, size_t textlen) { //printf("Macro::define('%.*s' = '%.*s')\n", namelen, name, textlen, text); @@ -98,7 +98,7 @@ Macro *Macro::define(Macro **ptable, unsigned char *name, size_t namelen, unsign * -1: get 2nd through end */ -size_t extractArgN(unsigned char *p, size_t end, unsigned char **pmarg, size_t *pmarglen, int n) +size_t extractArgN(utf8_t *p, size_t end, utf8_t **pmarg, size_t *pmarglen, int n) { /* Scan forward for matching right parenthesis. * Nest parentheses. @@ -130,7 +130,7 @@ size_t extractArgN(unsigned char *p, size_t end, unsigned char **pmarg, size_t * *pmarg = p + v; for (; v < end; v++) - { unsigned char c = p[v]; + { utf8_t c = p[v]; switch (c) { @@ -238,7 +238,7 @@ size_t extractArgN(unsigned char *p, size_t end, unsigned char **pmarg, size_t * */ void Macro::expand(OutBuffer *buf, size_t start, size_t *pend, - unsigned char *arg, size_t arglen) + utf8_t *arg, size_t arglen) { #if 0 printf("Macro::expand(buf[%d..%d], arg = '%.*s')\n", start, *pend, arglen, arg); @@ -259,7 +259,7 @@ void Macro::expand(OutBuffer *buf, size_t start, size_t *pend, arg = memdup(arg, arglen); for (size_t u = start; u + 1 < end; ) { - unsigned char *p = buf->data; // buf->data is not loop invariant + utf8_t *p = buf->data; // buf->data is not loop invariant /* Look for $0, but not $$0, and replace it with arg. */ @@ -273,10 +273,10 @@ void Macro::expand(OutBuffer *buf, size_t start, size_t *pend, continue; } - unsigned char c = p[u + 1]; + utf8_t c = p[u + 1]; int n = (c == '+') ? -1 : c - '0'; - unsigned char *marg; + utf8_t *marg; size_t marglen; extractArgN(arg, arglen, &marg, &marglen, n); if (marglen == 0) @@ -327,7 +327,7 @@ void Macro::expand(OutBuffer *buf, size_t start, size_t *pend, */ for (size_t u = start; u + 4 < end; ) { - unsigned char *p = buf->data; // buf->data is not loop invariant + utf8_t *p = buf->data; // buf->data is not loop invariant /* A valid start of macro expansion is $(c, where c is * an id start character, and not $$(c. @@ -335,10 +335,10 @@ void Macro::expand(OutBuffer *buf, size_t start, size_t *pend, if (p[u] == '$' && p[u + 1] == '(' && isIdStart(p+u+2)) { //printf("\tfound macro start '%c'\n", p[u + 2]); - unsigned char *name = p + u + 2; + utf8_t *name = p + u + 2; size_t namelen = 0; - unsigned char *marg; + utf8_t *marg; size_t marglen; size_t v; @@ -346,7 +346,7 @@ void Macro::expand(OutBuffer *buf, size_t start, size_t *pend, * beginning of macro argument (marg). */ for (v = u + 2; v < end; v+=utfStride(p+v)) - { unsigned char c = p[v]; + { utf8_t c = p[v]; if (!isIdTail(p+v)) { // We've gone past the end of the macro name. diff --git a/dmd2/macro.h b/dmd2/macro.h index d29a8cf0..4c0f53c9 100644 --- a/dmd2/macro.h +++ b/dmd2/macro.h @@ -24,22 +24,22 @@ struct Macro private: Macro *next; // next in list - unsigned char *name; // macro name + utf8_t *name; // macro name size_t namelen; // length of macro name - unsigned char *text; // macro replacement text + utf8_t *text; // macro replacement text size_t textlen; // length of replacement text int inuse; // macro is in use (don't expand) - Macro(unsigned char *name, size_t namelen, unsigned char *text, size_t textlen); - Macro *search(unsigned char *name, size_t namelen); + Macro(utf8_t *name, size_t namelen, utf8_t *text, size_t textlen); + Macro *search(utf8_t *name, size_t namelen); public: - static Macro *define(Macro **ptable, unsigned char *name, size_t namelen, unsigned char *text, size_t textlen); + static Macro *define(Macro **ptable, utf8_t *name, size_t namelen, utf8_t *text, size_t textlen); void expand(OutBuffer *buf, size_t start, size_t *pend, - unsigned char *arg, size_t arglen); + utf8_t *arg, size_t arglen); }; #endif diff --git a/dmd2/mangle.c b/dmd2/mangle.c index 4d876ed8..45881436 100644 --- a/dmd2/mangle.c +++ b/dmd2/mangle.c @@ -46,7 +46,7 @@ char *mangle(Declaration *sthis, bool isv) do { //printf("mangle: s = %p, '%s', parent = %p\n", s, s->toChars(), s->parent); - if (s->ident) + if (s->getIdent()) { FuncDeclaration *fd = s->isFuncDeclaration(); if (s != sthis && fd) @@ -79,6 +79,17 @@ L1: buf.writeByte(Type::needThisPrefix()); if (isv && fd && (fd->inferRetType || getFuncTemplateDecl(fd))) { +#if DDMD + TypeFunction *tfn = (TypeFunction *)sthis->type->copy(); + TypeFunction *tfo = (TypeFunction *)sthis->originalType; + tfn->purity = tfo->purity; + tfn->isnothrow = tfo->isnothrow; + tfn->isproperty = tfo->isproperty; + tfn->isref = fd->storage_class & STCauto ? false : tfo->isref; + tfn->trust = tfo->trust; + tfn->next = NULL; // do not mangle return type + tfn->toDecoBuffer(&buf, 0); +#else TypeFunction tfn = *(TypeFunction *)sthis->type; TypeFunction *tfo = (TypeFunction *)sthis->originalType; tfn.purity = tfo->purity; @@ -88,6 +99,7 @@ L1: tfn.trust = tfo->trust; tfn.next = NULL; // do not mangle return type tfn.toDecoBuffer(&buf, 0); +#endif } else if (sthis->type->deco) buf.writestring(sthis->type->deco); @@ -167,7 +179,49 @@ const char *Declaration::mangle(bool isv) return p; } +/****************************************************************************** + * Normally FuncDeclaration and FuncAliasDeclaration have overloads. + * If and only if there is no overloads, mangle() could return + * exact mangled name. + * + * module test; + * void foo(long) {} // _D4test3fooFlZv + * void foo(string) {} // _D4test3fooFAyaZv + * + * // from FuncDeclaration::mangle(). + * pragma(msg, foo.mangleof); // prints unexact mangled name "4test3foo" + * // by calling Dsymbol::mangle() + * + * // from FuncAliasDeclaration::mangle() + * pragma(msg, __traits(getOverloads, test, "foo")[0].mangleof); // "_D4test3fooFlZv" + * pragma(msg, __traits(getOverloads, test, "foo")[1].mangleof); // "_D4test3fooFAyaZv" + * + * If a function has no overloads, .mangleof property still returns exact mangled name. + * + * void bar() {} + * pragma(msg, bar.mangleof); // still prints "_D4test3barFZv" + * // by calling FuncDeclaration::mangleExact(). + */ const char *FuncDeclaration::mangle(bool isv) +{ + return isUnique() ? mangleExact(isv) : Dsymbol::mangle(isv); +} +// ditto +const char *FuncAliasDeclaration::mangle(bool isv) +{ + FuncDeclaration *f = toAliasFunc(); + FuncAliasDeclaration *fa = f->isFuncAliasDeclaration(); + if (!hasOverloads && !fa) + return f->mangleExact(isv); + if (fa) + return fa->mangle(isv); + return Dsymbol::mangle(isv); +} + +/****************************************************************************** + * Returns exact mangled name of function. + */ +const char *FuncDeclaration::mangleExact(bool isv) #if __DMC__ __out(result) { @@ -176,9 +230,11 @@ const char *FuncDeclaration::mangle(bool isv) __body #endif { + assert(!isFuncAliasDeclaration()); + if (mangleOverride) - return mangleOverride; - + return mangleOverride; + if (isMain()) return (char *)"_Dmain"; @@ -253,10 +309,8 @@ const char *ClassDeclaration::mangle(bool isv) ident == Id::TypeInfo_Typedef || ident == Id::TypeInfo_Tuple || this == object || - this == classinfo || -#if !MODULEINFO_IS_STRUCT + this == Type::typeinfoclass || this == Module::moduleinfo || -#endif memcmp(ident->toChars(), "TypeInfo_", 9) == 0 ) parent = NULL; @@ -277,6 +331,7 @@ const char *TemplateInstance::mangle(bool isv) printf(" parent = %s %s", parent->kind(), parent->toChars()); printf("\n"); #endif + getIdent(); const char *id = ident ? ident->toChars() : toChars(); if (!tempdecl) error("is not defined"); @@ -285,7 +340,7 @@ const char *TemplateInstance::mangle(bool isv) Dsymbol *par = enclosing || isTemplateMixin() ? parent : tempdecl->parent; if (par) { - const char *p = par->mangle(); + const char *p = par->mangle(isv); if (p[0] == '_' && p[1] == 'D') p += 2; buf.writestring(p); @@ -314,7 +369,8 @@ const char *Dsymbol::mangle(bool isv) id = ident ? ident->toChars() : toChars(); if (parent) { - const char *p = parent->mangle(isv); + FuncDeclaration *f = parent->isFuncDeclaration(); + const char *p = f ? f->mangleExact(isv) : parent->mangle(isv); if (p[0] == '_' && p[1] == 'D') p += 2; buf.writestring(p); diff --git a/dmd2/mars.c b/dmd2/mars.c index 125f7c38..4ecc5ee7 100644 --- a/dmd2/mars.c +++ b/dmd2/mars.c @@ -29,12 +29,14 @@ #include "mars.h" #include "module.h" +#include "scope.h" #include "mtype.h" #include "id.h" #include "cond.h" #include "expression.h" #include "lexer.h" #if !IN_LLVM +#include "parse.h" #include "lib.h" #include "json.h" #endif @@ -57,6 +59,36 @@ void printCtfePerformanceStats(); static bool parse_arch(size_t argc, char** argv, bool is64bit); +/** Normalize path by turning forward slashes into backslashes */ +void toWinPath(char *src) +{ + if (src == NULL) + return; + + while (*src != '\0') + { + if (*src == '/') + *src = '\\'; + src++; + } +} + +Ungag::~Ungag() +{ + //printf("+ungag dtor gag %d => %d\n", global.gag, oldgag); + global.gag = oldgag; +} + +Ungag Dsymbol::ungagSpeculative() +{ + unsigned oldgag = global.gag; + + if (global.isSpeculativeGagging() && !isSpeculative()) + global.gag = 0; + + return Ungag(oldgag); +} + Global global; void Global::init() @@ -104,6 +136,7 @@ void Global::init() #if IN_LLVM compiler.vendor = "LDC"; #endif + stdmsg = stdout; main_d = "__main.d"; @@ -137,6 +170,13 @@ bool Global::isSpeculativeGagging() return gag && gag == speculativeGag; } +void Global::increaseErrorCount() +{ + if (gag) + ++gaggedErrors; + ++errors; +} + char *Loc::toChars() { @@ -233,6 +273,7 @@ void verrorPrint(Loc loc, const char *header, const char *format, va_list ap, } // header is "Error: " by default (see mars.h) +extern "C" { void verror(Loc loc, const char *format, va_list ap, const char *p1, const char *p2, const char *header) { @@ -249,6 +290,7 @@ void verror(Loc loc, const char *format, va_list ap, } global.errors++; } +} // Doesn't increase error count, doesn't print "Error:". void verrorSupplemental(Loc loc, const char *format, va_list ap) @@ -328,7 +370,7 @@ Usage:\n\ @cmdfile read arguments from cmdfile\n\ -c do not link\n\ -cov do code coverage analysis\n\ - -cov=nnn require at least %%nnn code coverage\n\ + -cov=nnn require at least nnn%% code coverage\n\ -D generate documentation\n\ -Dddocdir write documentation file to docdir directory\n\ -Dffilename write documentation file to filename\n\ @@ -340,8 +382,9 @@ Usage:\n\ -debug=ident compile in debug code identified by ident\n\ -debuglib=name set symbolic debug library to name\n\ -defaultlib=name set default library to name\n\ - -deps=filename write module dependencies to filename\n%s" -" -g add symbolic debug info\n\ + -deps print module dependencies (imports/file/version/debug/lib)\n\ + -deps=filename write module dependencies to filename (only imports - deprecated)\n%s\ + -g add symbolic debug info\n\ -gc add symbolic debug info, pretend to be C\n\ -gs always emit stack frame\n\ -gx add stack stomp code\n\ @@ -354,12 +397,10 @@ Usage:\n\ -inline do function inlining\n\ -Jpath where to look for string imports\n\ -Llinkerflag pass linkerflag to link\n\ - -lib generate library rather than object files\n" -#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS -" -m32 generate 32 bit code\n\ - -m64 generate 64 bit code\n" -#endif -" -main add default main() (e.g. for unittesting)\n\ + -lib generate library rather than object files\n\ + -m32 generate 32 bit code\n\ + -m64 generate 64 bit code\n\ + -main add default main() (e.g. for unittesting)\n\ -man open web browser on manual page\n\ -map generate linker .map file\n\ -noboundscheck turns off array bounds checking for all functions\n\ @@ -398,6 +439,52 @@ extern "C" } #endif +static Module *entrypoint = NULL; + +/************************************ + * Generate C main() in response to seeing D main(). + * This used to be in druntime, but contained a reference to _Dmain + * which didn't work when druntime was made into a dll and was linked + * to a program, such as a C++ program, that didn't have a _Dmain. + */ + +void genCmain(Scope *sc) +{ + if (entrypoint) + return; + + /* The D code to be generated is provided as D source code in the form of a string. + * Note that Solaris, for unknown reasons, requires both a main() and an _main() + */ + static utf8_t code[] = "extern(C) {\n\ + int _d_run_main(int argc, char **argv, void* mainFunc);\n\ + int _Dmain(char[][] args);\n\ + int main(int argc, char **argv) { return _d_run_main(argc, argv, &_Dmain); }\n\ + version (Solaris) int _main(int argc, char** argv) { return main(argc, argv); }\n\ + }\n\ + "; + + Identifier *id = Id::entrypoint; + Module *m = new Module("__entrypoint.d", id, 0, 0); + + Parser p(m, code, sizeof(code) / sizeof(code[0]), 0); + p.scanloc = Loc(); + p.nextToken(); + m->members = p.parseModule(); + assert(p.token.value == TOKeof); + + char v = global.params.verbose; + global.params.verbose = 0; + m->importedFrom = sc->module; + m->importAll(NULL); + m->semantic(); + m->semantic2(); + m->semantic3(); + global.params.verbose = v; + + entrypoint = m; +} + int tryMain(size_t argc, char *argv[]) { mem.init(); // initialize storage allocator @@ -452,7 +539,6 @@ int tryMain(size_t argc, char *argv[]) global.params.useSwitchError = 1; global.params.useInline = 0; global.params.obj = 1; - global.params.Dversion = 2; global.params.quiet = 1; global.params.useDeprecated = 2; @@ -564,7 +650,7 @@ int tryMain(size_t argc, char *argv[]) // -cov=nnn if (p[4] == '=') { - if (isdigit((unsigned char)p[5])) + if (isdigit((utf8_t)p[5])) { long percent; errno = 0; @@ -579,17 +665,25 @@ int tryMain(size_t argc, char *argv[]) else if (p[4]) goto Lerror; } - else if (strcmp(p + 1, "shared") == 0 -#if TARGET_OSX - // backwards compatibility with old switch - || strcmp(p + 1, "dylib") == 0 -#endif - ) + else if (strcmp(p + 1, "shared") == 0) global.params.dll = 1; -#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS - else if (strcmp(p + 1, "fPIC") == 0) - global.params.pic = 1; + else if (strcmp(p + 1, "dylib") == 0) + { +#if TARGET_OSX + warning(Loc(), "use -shared instead of -dylib"); + global.params.dll = 1; +#else + goto Lerror; #endif + } + else if (strcmp(p + 1, "fPIC") == 0) + { +#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS + global.params.pic = 1; +#else + goto Lerror; +#endif + } else if (strcmp(p + 1, "map") == 0) global.params.map = 1; else if (strcmp(p + 1, "multiobj") == 0) @@ -639,7 +733,7 @@ Language changes listed by -transition=id:\n\ #endif return EXIT_FAILURE; } - if (isdigit((unsigned char)p[12])) + if (isdigit((utf8_t)p[12])) { long num; errno = 0; @@ -660,7 +754,7 @@ Language changes listed by -transition=id:\n\ if (strcmp(p + 12, "tls") == 0) global.params.vtls = 1; #if PULL93 - else if (strcmp(p + 12, "field") == 0) + if (strcmp(p + 12, "field") == 0) global.params.vfield = 1; #endif } @@ -671,15 +765,6 @@ Language changes listed by -transition=id:\n\ goto Lerror; } #endif - else if (strcmp(p + 1, "v1") == 0) - { -#if DMDV1 - global.params.Dversion = 1; -#else - error(Loc(), "use DMD 1.0 series compilers for -v1 switch"); - break; -#endif - } else if (strcmp(p + 1, "w") == 0) global.params.warnings = 1; else if (strcmp(p + 1, "wi") == 0) @@ -697,12 +782,18 @@ Language changes listed by -transition=id:\n\ case 'd': if (!p[3]) goto Lnoarg; +#if _WIN32 + toWinPath(p + 3); +#endif global.params.objdir = p + 3; break; case 'f': if (!p[3]) goto Lnoarg; +#if _WIN32 + toWinPath(p + 3); +#endif global.params.objname = p + 3; break; @@ -824,7 +915,7 @@ Language changes listed by -transition=id:\n\ // -debug=identifier if (p[6] == '=') { - if (isdigit((unsigned char)p[7])) + if (isdigit((utf8_t)p[7])) { long level; errno = 0; @@ -850,7 +941,7 @@ Language changes listed by -transition=id:\n\ // -version=identifier if (p[8] == '=') { - if (isdigit((unsigned char)p[9])) + if (isdigit((utf8_t)p[9])) { long level; errno = 0; @@ -897,11 +988,23 @@ Language changes listed by -transition=id:\n\ setdebuglib = 1; global.params.debuglibname = p + 1 + 9; } - else if (memcmp(p + 1, "deps=", 5) == 0) + else if (memcmp(p + 1, "deps", 4) == 0) { - global.params.moduleDepsFile = p + 1 + 5; - if (!global.params.moduleDepsFile[0]) - goto Lnoarg; + if(global.params.moduleDeps) + { + error(Loc(), "-deps[=file] can only be provided once!"); + break; + } + if (p[5] == '=') + { + global.params.moduleDepsFile = p + 1 + 5; + if (!global.params.moduleDepsFile[0]) + goto Lnoarg; + } // Else output to stdout. + else if (p[5]!='\0') + { + goto Lerror; + } global.params.moduleDeps = new OutBuffer; } else if (strcmp(p + 1, "main") == 0) @@ -999,6 +1102,9 @@ Language changes listed by -transition=id:\n\ error(Loc(), "the architecture must not be changed in the %s section of %s", is64bit ? "Environment64" : "Environment32", inifilename); + // Target uses 64bit pointers. + global.params.isLP64 = global.params.is64bit; + if (global.errors) { fatal(); @@ -1095,7 +1201,6 @@ Language changes listed by -transition=id:\n\ { VersionCondition::addPredefinedGlobalIdent("D_InlineAsm_X86_64"); VersionCondition::addPredefinedGlobalIdent("X86_64"); - VersionCondition::addPredefinedGlobalIdent("D_LP64"); VersionCondition::addPredefinedGlobalIdent("D_SIMD"); #if TARGET_WINDOS VersionCondition::addPredefinedGlobalIdent("Win64"); @@ -1118,6 +1223,8 @@ Language changes listed by -transition=id:\n\ VersionCondition::addPredefinedGlobalIdent("Win32"); #endif } + if (global.params.isLP64) + VersionCondition::addPredefinedGlobalIdent("D_LP64"); if (global.params.doDocComments) VersionCondition::addPredefinedGlobalIdent("D_Ddoc"); if (global.params.cov) @@ -1144,9 +1251,9 @@ Language changes listed by -transition=id:\n\ initPrecedence(); if (global.params.verbose) - { printf("binary %s\n", argv[0]); - printf("version %s\n", global.version); - printf("config %s\n", inifilename ? inifilename : "(none)"); + { fprintf(global.stdmsg, "binary %s\n", argv[0]); + fprintf(global.stdmsg, "version %s\n", global.version); + fprintf(global.stdmsg, "config %s\n", inifilename ? inifilename : "(none)"); } //printf("%d source files\n",files.dim); @@ -1349,7 +1456,7 @@ Language changes listed by -transition=id:\n\ for (size_t i = 0; i < modules.dim; i++) { m = modules[i]; - m->read(0); + m->read(Loc()); } #endif @@ -1360,10 +1467,10 @@ Language changes listed by -transition=id:\n\ { m = modules[modi]; if (global.params.verbose) - printf("parse %s\n", m->toChars()); + fprintf(global.stdmsg, "parse %s\n", m->toChars()); if (!Module::rootModule) Module::rootModule = m; - m->importedFrom = m; + m->importedFrom = m; // m->isRoot() == true if (!global.params.oneobj || modi == 0 || m->isDocFile) m->deleteObjFile(); #if ASYNCREAD @@ -1420,7 +1527,7 @@ Language changes listed by -transition=id:\n\ { m = modules[i]; if (global.params.verbose) - printf("import %s\n", m->toChars()); + fprintf(global.stdmsg, "import %s\n", m->toChars()); m->genhdrfile(); } } @@ -1432,7 +1539,7 @@ Language changes listed by -transition=id:\n\ { m = modules[i]; if (global.params.verbose) - printf("importall %s\n", m->toChars()); + fprintf(global.stdmsg, "importall %s\n", m->toChars()); m->importAll(NULL); } if (global.errors) @@ -1445,7 +1552,7 @@ Language changes listed by -transition=id:\n\ { m = modules[i]; if (global.params.verbose) - printf("semantic %s\n", m->toChars()); + fprintf(global.stdmsg, "semantic %s\n", m->toChars()); m->semantic(); } if (global.errors) @@ -1459,7 +1566,7 @@ Language changes listed by -transition=id:\n\ { m = modules[i]; if (global.params.verbose) - printf("semantic2 %s\n", m->toChars()); + fprintf(global.stdmsg, "semantic2 %s\n", m->toChars()); m->semantic2(); } if (global.errors) @@ -1470,12 +1577,11 @@ Language changes listed by -transition=id:\n\ { m = modules[i]; if (global.params.verbose) - printf("semantic3 %s\n", m->toChars()); + fprintf(global.stdmsg, "semantic3 %s\n", m->toChars()); m->semantic3(); } if (global.errors) fatal(); - if (global.params.useInline) { /* The problem with useArrayBounds and useAssert is that the @@ -1492,22 +1598,28 @@ Language changes listed by -transition=id:\n\ { m = Module::amodules[i]; if (global.params.verbose) - printf("semantic3 %s\n", m->toChars()); + fprintf(global.stdmsg, "semantic3 %s\n", m->toChars()); m->semantic3(); } if (global.errors) fatal(); } } + Module::runDeferredSemantic3(); + if (global.errors) + fatal(); - if (global.params.moduleDeps != NULL) + if (global.params.moduleDeps) { - assert(global.params.moduleDepsFile != NULL); - - File deps(global.params.moduleDepsFile); OutBuffer* ob = global.params.moduleDeps; - deps.setbuffer((void*)ob->data, ob->offset); - deps.writev(); + if (global.params.moduleDepsFile) + { + File deps(global.params.moduleDepsFile); + deps.setbuffer((void*)ob->data, ob->offset); + deps.writev(); + } + else + printf("%.*s", (int)ob->offset, ob->data); } // Scan for functions to inline @@ -1517,7 +1629,7 @@ Language changes listed by -transition=id:\n\ { m = modules[i]; if (global.params.verbose) - printf("inline scan %s\n", m->toChars()); + fprintf(global.stdmsg, "inline scan %s\n", m->toChars()); m->inlineScan(); } } @@ -1592,14 +1704,21 @@ Language changes listed by -transition=id:\n\ if (global.params.oneobj) { + if (modules.dim) + obj_start(modules[0]->srcfile->toChars()); for (size_t i = 0; i < modules.dim; i++) { m = modules[i]; if (global.params.verbose) - printf("code %s\n", m->toChars()); - if (i == 0) - obj_start(m->srcfile->toChars()); + fprintf(global.stdmsg, "code %s\n", m->toChars()); m->genobjfile(0); + if (entrypoint && m == entrypoint->importedFrom) + { + char v = global.params.verbose; + global.params.verbose = 0; + entrypoint->genobjfile(0); + global.params.verbose = v; + } if (!global.errors && global.params.doDocComments) m->gendocfile(); } @@ -1614,10 +1733,18 @@ Language changes listed by -transition=id:\n\ { m = modules[i]; if (global.params.verbose) - printf("code %s\n", m->toChars()); + fprintf(global.stdmsg, "code %s\n", m->toChars()); if (global.params.obj) - { obj_start(m->srcfile->toChars()); + { + obj_start(m->srcfile->toChars()); m->genobjfile(global.params.multiobj); + if (entrypoint && m == entrypoint->importedFrom) + { + char v = global.params.verbose; + global.params.verbose = 0; + entrypoint->genobjfile(global.params.multiobj); + global.params.verbose = v; + } obj_end(library, m->objfile); obj_write_deferred(library); } @@ -1662,8 +1789,7 @@ Language changes listed by -transition=id:\n\ */ for (size_t i = 0; i < modules.dim; i++) { - Module *m = modules[i]; - m->deleteObjFile(); + modules[i]->deleteObjFile(); if (global.params.oneobj) break; } @@ -1814,12 +1940,33 @@ Ldone: assert(argc == argv->dim); argv->reserve(argc_left); for (int i = 0; i < argc_left; i++) - argv->data[argc++] = (void *)(*pargv)[i]; + (*argv)[argc++] = (*pargv)[i]; *pargc = argc; *pargv = argv->tdata(); } +void escapePath(OutBuffer *buf, const char *fname) +{ + while (1) + { + switch (*fname) + { + case 0: + return; + case '(': + case ')': + case '\\': + buf->writebyte('\\'); + default: + buf->writebyte(*fname); + break; + } + fname++; + } +} + + /*********************************** * Parse command line arguments for -m32 or -m64 * to detect the desired architecture. diff --git a/dmd2/mars.h b/dmd2/mars.h index e36b0ab3..2bb54e8a 100644 --- a/dmd2/mars.h +++ b/dmd2/mars.h @@ -94,10 +94,6 @@ void unittests(); # endif #endif -#ifdef IN_GCC -/* Changes for the GDC compiler by David Friedman */ -#endif - #define DMDV1 0 #define DMDV2 1 // Version 2.0 features #define SNAN_DEFAULT_INIT DMDV2 // if floats are default initialized to signalling NaN @@ -137,9 +133,9 @@ void unittests(); struct OutBuffer; // Can't include arraytypes.h here, need to declare these directly. -template struct ArrayBase; -typedef ArrayBase Identifiers; -typedef ArrayBase Strings; +template struct Array; +typedef Array Identifiers; +typedef Array Strings; #if IN_LLVM enum OUTPUTFLAG @@ -164,6 +160,7 @@ struct Param ubyte symdebug; // insert debug symbolic information bool trace; // insert profiling hooks bool is64bit; // generate 64 bit code + bool isLP64; // generate code for LP64 bool isLinux; // generate code for linux bool isOSX; // generate code for Mac OSX bool isWindows; // generate code for Windows @@ -185,6 +182,7 @@ struct Param bool optimize; // run optimizer char map; // generate linker .map file char is64bit; // generate 64 bit code + char isLP64; // generate code for LP64 char isLinux; // generate code for linux char isOSX; // generate code for Mac OSX char isWindows; // generate code for Windows @@ -225,7 +223,6 @@ struct Param bool cov; // generate code coverage data unsigned char covPercent; // 0..100 code coverage percentage required bool nofloat; // code should not pull in floating point support - char Dversion; // D version number char ignoreUnsupportedPragmas; // rather than error on them char enforcePropertySyntax; char betterC; // be a "better C" compiler; no dependency on D runtime @@ -256,8 +253,6 @@ struct Param unsigned versionlevel; // version level Strings *versionids; // version identifiers - bool dump_source; - Strings *defaultlibnames; // default libraries for non-debug builds Strings *debuglibnames; // default libraries for debug builds @@ -322,6 +317,14 @@ typedef unsigned structalign_t; #define STRUCTALIGN_DEFAULT ~0 // magic value means "match whatever the underlying C compiler does" // other values are all powers of 2 +struct Ungag +{ + unsigned oldgag; + + Ungag(unsigned old) : oldgag(old) {} + ~Ungag(); +}; + struct Global { const char *mars_ext; @@ -358,6 +361,7 @@ struct Global Param params; unsigned errors; // number of errors reported so far unsigned warnings; // number of warnings reported so far + FILE *stdmsg; // where to send verbose messages unsigned gag; // !=0 means gag reporting of errors & warnings unsigned gaggedErrors; // number of errors reported while gagged @@ -375,6 +379,12 @@ struct Global */ bool endGagging(unsigned oldGagged); + /* Increment the error count to record that an error + * has occured in the current context. An error message + * may or may not have been printed. + */ + void increaseErrorCount(); + void init(); }; @@ -391,12 +401,7 @@ extern Global global; #include typedef _Complex long double complex_t; #else - #ifndef IN_GCC - #include "complex_t.h" - #endif - #ifdef __APPLE__ - //#include "complex.h"//This causes problems with include the c++ and not the C "complex.h" - #endif + #include "complex_t.h" #endif // Be careful not to care about sign when using dinteger_t @@ -425,17 +430,10 @@ typedef d_uns8 d_char; typedef d_uns16 d_wchar; typedef d_uns32 d_dchar; -#ifdef IN_GCC -#include "d-gcc-real.h" -#else typedef longdouble real_t; -#endif -#ifdef IN_GCC -#include "d-gcc-complex_t.h" -#endif -struct Module; +class Module; //typedef unsigned Loc; // file location struct Loc @@ -456,7 +454,9 @@ struct Loc }; #ifndef GCC_SAFE_DMD +#undef TRUE #define TRUE 1 +#undef FALSE #define FALSE 0 #endif @@ -508,7 +508,9 @@ void warning(Loc loc, const char *format, ...); void deprecation(Loc loc, const char *format, ...); void error(Loc loc, const char *format, ...); void errorSupplemental(Loc loc, const char *format, ...); +extern "C" { void verror(Loc loc, const char *format, va_list ap, const char *p1 = NULL, const char *p2 = NULL, const char *header = "Error: "); +} void vwarning(Loc loc, const char *format, va_list); void verrorSupplemental(Loc loc, const char *format, va_list ap); void verrorPrint(Loc loc, const char *header, const char *format, va_list ap, const char *p1 = NULL, const char *p2 = NULL); @@ -530,14 +532,11 @@ int runProgram(); const char *inifile(const char *argv0, const char *inifile, const char* envsectionname); #endif void halt(); -#if !IN_LLVM -void util_progress(); -#endif #if !IN_LLVM -struct Dsymbol; +class Dsymbol; class Library; -struct File; +class File; void obj_start(char *srcfile); void obj_end(Library *library, File *objfile); void obj_append(Dsymbol *s); @@ -545,5 +544,7 @@ void obj_write_deferred(Library *library); #endif const char *importHint(const char *s); +/// Little helper function for writting out deps. +void escapePath(OutBuffer *buf, const char *fname); #endif /* DMD_MARS_H */ diff --git a/dmd2/module.c b/dmd2/module.c index ec4ca973..4339a4bb 100644 --- a/dmd2/module.c +++ b/dmd2/module.c @@ -34,8 +34,11 @@ DsymbolTable *Module::modules; Modules Module::amodules; Dsymbols Module::deferred; // deferred Dsymbol's needing semantic() run on them +Dsymbols Module::deferred3; unsigned Module::dprogress; +const char *lookForSourceFile(const char *filename); + void Module::init() { modules = new DsymbolTable(); @@ -59,13 +62,7 @@ Module::Module(char *filename, Identifier *ident, int doDocComment, int doHdrGen needmoduleinfo = 0; selfimports = 0; insearch = 0; - searchCacheIdent = NULL; - searchCacheSymbol = NULL; - searchCacheFlags = 0; - semanticstarted = 0; - semanticRun = 0; decldefs = NULL; - vmoduleinfo = NULL; #if IN_DMD massert = NULL; munittest = NULL; @@ -78,7 +75,6 @@ Module::Module(char *filename, Identifier *ident, int doDocComment, int doHdrGen stest = NULL; sfilename = NULL; #endif - root = 0; importedFrom = NULL; srcfile = NULL; objfile = NULL; @@ -134,7 +130,6 @@ Module::Module(char *filename, Identifier *ident, int doDocComment, int doHdrGen moduleInfoVar = NULL; this->doDocComment = doDocComment; this->doHdrGen = doHdrGen; - this->isRoot = false; this->arrayfuncs = 0; #endif } @@ -241,55 +236,23 @@ Module *Module::load(Loc loc, Identifiers *packages, Identifier *ident) m = new Module(filename, ident, 0, 0); m->loc = loc; - /* Search along global.path for .di file, then .d file. + /* Look for the source file */ - const char *result = NULL; - const char *fdi = FileName::forceExt(filename, global.hdr_ext); - const char *fd = FileName::forceExt(filename, global.mars_ext); - const char *sdi = fdi; - const char *sd = fd; - - if (FileName::exists(sdi)) - result = sdi; - else if (FileName::exists(sd)) - result = sd; - else if (FileName::absolute(filename)) - ; - else if (!global.path) - ; - else - { - for (size_t i = 0; i < global.path->dim; i++) - { - const char *p = (*global.path)[i]; - const char *n = FileName::combine(p, sdi); - if (FileName::exists(n)) - { result = n; - break; - } - FileName::free(n); - n = FileName::combine(p, sd); - if (FileName::exists(n)) - { result = n; - break; - } - FileName::free(n); - } - } + const char *result = lookForSourceFile(filename); if (result) m->srcfile = new File(result); if (global.params.verbose) { - printf("import "); + fprintf(global.stdmsg, "import "); if (packages) { for (size_t i = 0; i < packages->dim; i++) { Identifier *pid = (*packages)[i]; - printf("%s.", pid->toChars()); + fprintf(global.stdmsg, "%s.", pid->toChars()); } } - printf("%s\t(%s)\n", ident->toChars(), m->srcfile->toChars()); + fprintf(global.stdmsg, "%s\t(%s)\n", ident->toChars(), m->srcfile->toChars()); } if (!m->read(loc)) @@ -316,7 +279,15 @@ bool Module::read(Loc loc) } else { - error(loc, "is in file '%s' which cannot be read", srcfile->toChars()); + // if module is not named 'package' but we're trying to read 'package.d', we're looking for a package module + bool isPackageMod = (strcmp(toChars(), "package") != 0) && + (strcmp(srcfile->name->name(), "package.d") == 0); + + if (isPackageMod) + ::error(loc, "importing package '%s' requires a 'package.d' file which cannot be found in '%s'", + toChars(), srcfile->toChars()); + else + error(loc, "is in file '%s' which cannot be read", srcfile->toChars()); } if (!global.gag) @@ -422,7 +393,7 @@ void Module::parse() char *srcname = srcfile->name->toChars(); //printf("Module::parse(srcname = '%s')\n", srcname); - unsigned char *buf = srcfile->buffer; + utf8_t *buf = srcfile->buffer; size_t buflen = srcfile->len; if (buflen >= 2) @@ -472,7 +443,7 @@ void Module::parse() } dbuf.writeByte(0); // add 0 as sentinel for scanner buflen = dbuf.offset - 1; // don't include sentinel in count - buf = (unsigned char *) dbuf.extractData(); + buf = (utf8_t *) dbuf.extractData(); } else { // UTF-16LE (X86) @@ -525,7 +496,7 @@ void Module::parse() } dbuf.writeByte(0); // add 0 as sentinel for scanner buflen = dbuf.offset - 1; // don't include sentinel in count - buf = (unsigned char *) dbuf.extractData(); + buf = (utf8_t *) dbuf.extractData(); } } else if (buf[0] == 0xFE && buf[1] == 0xFF) @@ -586,14 +557,6 @@ void Module::parse() } } -#ifdef IN_GCC - // dump utf-8 encoded source - if (global.params.dump_source) - { // %% srcname could contain a path ... - d_gcc_dump_source(srcname, "utf-8", buf, buflen); - } -#endif - /* If it starts with the string "Ddoc", then it's a documentation * source file. */ @@ -623,25 +586,36 @@ void Module::parse() srcfile->len = 0; md = p.md; - numlines = p.loc.linnum; + numlines = p.scanloc.linnum; + /* The symbol table into which the module is to be inserted. + */ DsymbolTable *dst; if (md) - { this->ident = md->id; + { /* A ModuleDeclaration, md, was provided. + * The ModuleDeclaration sets the packages this module appears in, and + * the name of this module. + */ + this->ident = md->id; this->safe = md->safe; Package *ppack = NULL; dst = Package::resolve(md->packages, &this->parent, &ppack); + assert(dst); +#if 0 if (ppack && ppack->isModule()) { error(loc, "package name '%s' in file %s conflicts with usage as a module name in file %s", ppack->toChars(), srcname, ppack->isModule()->srcfile->toChars()); dst = modules; } +#endif } else - { - dst = modules; + { /* The name of the module is set to the source file name. + * There are no packages. + */ + dst = modules; // and so this module goes into global module symbol table /* Check to see if module name is a valid identifier */ @@ -649,9 +623,40 @@ void Module::parse() error("has non-identifier characters in filename, use module declaration instead"); } - // Update global list of modules - if (!dst->insert(this)) + // Insert module into the symbol table + Dsymbol *s = this; + bool isPackageMod = strcmp(srcfile->name->name(), "package.d") == 0; + if (isPackageMod) { + /* If the source tree is as follows: + * pkg/ + * +- package.d + * +- common.d + * the 'pkg' will be incorporated to the internal package tree in two ways: + * import pkg; + * and: + * import pkg.common; + * + * If both are used in one compilation, 'pkg' as a module (== pkg/package.d) + * and a package name 'pkg' will conflict each other. + * + * To avoid the conflict: + * 1. If preceding package name insertion had occurred by Package::resolve, + * later package.d loading will change Package::isPkgMod to PKGmodule and set Package::mod. + * 2. Otherwise, 'package.d' wrapped by 'Package' is inserted to the internal tree in here. + */ + Package *p = new Package(ident); + p->parent = this->parent; + p->isPkgMod = PKGmodule; + p->mod = this; + p->symtab = new DsymbolTable(); + s = p; + } + if (!dst->insert(s)) + { + /* It conflicts with a name that is already in the symbol table. + * Figure out what went wrong, and issue error message. + */ Dsymbol *prev = dst->lookup(ident); assert(prev); Module *mprev = prev->isModule(); @@ -668,12 +673,22 @@ void Module::parse() { Package *pkg = prev->isPackage(); assert(pkg); - error(pkg->loc, "from file %s conflicts with package name %s", - srcname, pkg->toChars()); + if (pkg->isPkgMod == PKGunknown && isPackageMod) + { + /* If the previous inserted Package is not yet determined as package.d, + * link it to the actual module. + */ + pkg->isPkgMod = PKGmodule; + pkg->mod = this; + } + else + error(pkg->loc, "from file %s conflicts with package name %s", + srcname, pkg->toChars()); } } else { + // Add to global array of all modules amodules.push(this); } } @@ -743,18 +758,18 @@ void Module::importAll(Scope *prevsc) void Module::semantic() { - if (semanticstarted) + if (semanticRun != PASSinit) return; //printf("+Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent); - semanticstarted = 1; + semanticRun = PASSsemantic; // Note that modules get their own scope, from scratch. // This is so regardless of where in the syntax a module // gets imported, it is unaffected by context. Scope *sc = scope; // see if already got one from importAll() if (!sc) - { printf("test2\n"); + { Scope::createGlobal(this); // create root scope } @@ -786,14 +801,6 @@ void Module::semantic() } #endif - // Do semantic() on members that don't depend on others - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (*members)[i]; - - //printf("\tModule('%s'): '%s'.semantic0()\n", toChars(), s->toChars()); - s->semantic0(sc); - } - // Pass 1 semantic routines: do public side of the definition for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (*members)[i]; @@ -807,7 +814,7 @@ void Module::semantic() { sc = sc->pop(); sc->pop(); // 2 pops because Scope::createGlobal() created 2 } - semanticRun = semanticstarted; + semanticRun = PASSsemanticdone; //printf("-Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent); } @@ -824,12 +831,9 @@ void Module::semantic2() return; } //printf("Module::semantic2('%s'): parent = %p\n", toChars(), parent); - if (semanticRun == 0) // semantic() not completed yet - could be recursive call + if (semanticRun != PASSsemanticdone) // semantic() not completed yet - could be recursive call return; - if (semanticstarted >= 2) - return; - assert(semanticstarted == 1); - semanticstarted = 2; + semanticRun = PASSsemantic2; // Note that modules get their own scope, from scratch. // This is so regardless of where in the syntax a module @@ -847,17 +851,16 @@ void Module::semantic2() sc = sc->pop(); sc->pop(); - semanticRun = semanticstarted; + semanticRun = PASSsemantic2done; //printf("-Module::semantic2('%s'): parent = %p\n", toChars(), parent); } void Module::semantic3() { //printf("Module::semantic3('%s'): parent = %p\n", toChars(), parent); - if (semanticstarted >= 3) + if (semanticRun != PASSsemantic2done) return; - assert(semanticstarted == 2); - semanticstarted = 3; + semanticRun = PASSsemantic3; // Note that modules get their own scope, from scratch. // This is so regardless of where in the syntax a module @@ -876,15 +879,14 @@ void Module::semantic3() sc = sc->pop(); sc->pop(); - semanticRun = semanticstarted; + semanticRun = PASSsemantic3done; } void Module::inlineScan() { - if (semanticstarted >= 4) + if (semanticRun != PASSsemantic3done) return; - assert(semanticstarted == 3); - semanticstarted = 4; + semanticRun = PASSinline; // Note that modules get their own scope, from scratch. // This is so regardless of where in the syntax a module @@ -894,11 +896,11 @@ void Module::inlineScan() for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (*members)[i]; //if (global.params.verbose) - //printf("inline scan symbol %s\n", s->toChars()); + //fprintf(global.stdmsg, "inline scan symbol %s\n", s->toChars()); s->inlineScan(); } - semanticRun = semanticstarted; + semanticRun = PASSinlinedone; } /**************************************************** @@ -951,38 +953,15 @@ Dsymbol *Module::search(Loc loc, Identifier *ident, int flags) Dsymbol *s; if (insearch) s = NULL; - else if (searchCacheIdent == ident && searchCacheFlags == flags) - { - 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; s = ScopeDsymbol::search(loc, ident, flags); insearch = 0; - - searchCacheIdent = ident; - searchCacheSymbol = s; - searchCacheFlags = flags; } return s; } -Dsymbol *Module::symtabInsert(Dsymbol *s) -{ - searchCacheIdent = NULL; // symbol is inserted, so invalidate cache - return Package::symtabInsert(s); -} - -void Module::clearCache() -{ - for (size_t i = 0; i < amodules.dim; i++) - { Module *m = amodules[i]; - m->searchCacheIdent = NULL; - } -} - /******************************************* * Can't run semantic on s now, try again later. */ @@ -1057,6 +1036,33 @@ void Module::runDeferredSemantic() //printf("-Module::runDeferredSemantic(), len = %d\n", deferred.dim); } +void Module::addDeferredSemantic3(Dsymbol *s) +{ + // Don't add it if it is already there + for (size_t i = 0; i < deferred3.dim; i++) + { + Dsymbol *sd = deferred3[i]; + if (sd == s) + return; + } + deferred3.push(s); +} + +void Module::runDeferredSemantic3() +{ + Dsymbols *a = &Module::deferred3; + for (size_t i = 0; i < a->dim; i++) + { + Dsymbol *s = (*a)[i]; + //printf("[%d] %s semantic3a\n", i, s->toPrettyChars()); + + s->semantic3(NULL); + + if (global.errors) + break; + } +} + /************************************ * Recursively look at every module this module imports, * return TRUE if it imports m. @@ -1116,8 +1122,9 @@ int Module::selfImports() /* =========================== ModuleDeclaration ===================== */ -ModuleDeclaration::ModuleDeclaration(Identifiers *packages, Identifier *id, bool safe) +ModuleDeclaration::ModuleDeclaration(Loc loc, Identifiers *packages, Identifier *id, bool safe) { + this->loc = loc; this->packages = packages; this->id = id; this->safe = safe; @@ -1146,6 +1153,8 @@ char *ModuleDeclaration::toChars() Package::Package(Identifier *ident) : ScopeDsymbol(ident) { + this->isPkgMod = PKGunknown; + this->mod = NULL; } @@ -1154,6 +1163,15 @@ const char *Package::kind() return "package"; } +/**************************************************** + * Input: + * packages[] the pkg1.pkg2 of pkg1.pkg2.mod + * Returns: + * the symbol table that mod should be inserted into + * Output: + * *pparent the rightmost package, i.e. pkg2, or NULL if no packages + * *ppkg the leftmost package, i.e. pkg1, or NULL if no packages + */ DsymbolTable *Package::resolve(Identifiers *packages, Dsymbol **pparent, Package **ppkg) { @@ -1168,39 +1186,126 @@ DsymbolTable *Package::resolve(Identifiers *packages, Dsymbol **pparent, Package { for (size_t i = 0; i < packages->dim; i++) { Identifier *pid = (*packages)[i]; - Dsymbol *p; - p = dst->lookup(pid); + Package *pkg; + Dsymbol *p = dst->lookup(pid); if (!p) { - p = new Package(pid); - dst->insert(p); - p->parent = parent; - ((ScopeDsymbol *)p)->symtab = new DsymbolTable(); + pkg = new Package(pid); + dst->insert(pkg); + pkg->parent = parent; + pkg->symtab = new DsymbolTable(); } else { - assert(p->isPackage()); + pkg = p->isPackage(); + assert(pkg); // It might already be a module, not a package, but that needs // to be checked at a higher level, where a nice error message // can be generated. // dot net needs modules and packages with same name + + // But we still need a symbol table for it + if (!pkg->symtab) + pkg->symtab = new DsymbolTable(); } - parent = p; - dst = ((Package *)p)->symtab; + parent = pkg; + dst = pkg->symtab; if (ppkg && !*ppkg) - *ppkg = (Package *)p; - if (p->isModule()) + *ppkg = pkg; +#if 0 + if (pkg->isModule()) { // Return the module so that a nice error message can be generated if (ppkg) *ppkg = (Package *)p; break; } - } - if (pparent) - { - *pparent = parent; +#endif } } + if (pparent) + *pparent = parent; return dst; } + +Dsymbol *Package::search(Loc loc, Identifier *ident, int flags) +{ + if (!isModule() && mod) + { + // Prefer full package name. + Dsymbol *s = symtab ? symtab->lookup(ident) : NULL; + if (s) + return s; + //printf("[%s] through pkdmod: %s\n", loc.toChars(), toChars()); + return mod->search(loc, ident, flags); + } + + return ScopeDsymbol::search(loc, ident, flags); +} + +/* =========================== ===================== */ + +/******************************************** + * Look for the source file if it's different from filename. + * Look for .di, .d, directory, and along global.path. + * Does not open the file. + * Input: + * filename as supplied by the user + * global.path + * Returns: + * NULL if it's not different from filename. + */ + +const char *lookForSourceFile(const char *filename) +{ + + /* Search along global.path for .di file, then .d file. + */ + + const char *sdi = FileName::forceExt(filename, global.hdr_ext); + if (FileName::exists(sdi) == 1) + return sdi; + + const char *sd = FileName::forceExt(filename, global.mars_ext); + if (FileName::exists(sd) == 1) + return sd; + + if (FileName::exists(filename) == 2) + { + /* The filename exists and it's a directory. + * Therefore, the result should be: filename/package.d + */ + return FileName::combine(filename, "package.d"); + } + + if (FileName::absolute(filename)) + return NULL; + + if (!global.path) + return NULL; + + for (size_t i = 0; i < global.path->dim; i++) + { + const char *p = (*global.path)[i]; + + const char *n = FileName::combine(p, sdi); + if (FileName::exists(n) == 1) + return n; + FileName::free(n); + + n = FileName::combine(p, sd); + if (FileName::exists(n) == 1) + return n; + FileName::free(n); + + const char *b = FileName::removeExt(filename); + n = FileName::combine(p, b); + FileName::free(b); + if (FileName::exists(n) == 2) + return FileName::combine(n, "package.d"); + FileName::free(n); + } + return NULL; +} + + diff --git a/dmd2/module.h b/dmd2/module.h index 7d616e61..b1a19b53 100644 --- a/dmd2/module.h +++ b/dmd2/module.h @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars +// Copyright (c) 1999-2013 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -18,12 +18,11 @@ #include "root.h" #include "dsymbol.h" -struct ModuleInfoDeclaration; -struct ClassDeclaration; +class ClassDeclaration; struct ModuleDeclaration; struct Macro; struct Escape; -struct VarDeclaration; +class VarDeclaration; class Library; // Back end @@ -39,14 +38,25 @@ namespace llvm { #else #ifdef IN_GCC -union tree_node; typedef union tree_node elem; +typedef union tree_node elem; #else struct elem; #endif #endif -struct Package : ScopeDsymbol +enum PKG { + PKGunknown, // not yet determined whether it's a package.d or not + PKGmodule, // already determined that's an actual package.d + PKGpackage, // already determined that's an actual package +}; + +class Package : public ScopeDsymbol +{ +public: + PKG isPkgMod; + Module *mod; // != NULL if isPkgMod == PKGmodule + Package(Identifier *ident); const char *kind(); @@ -54,15 +64,18 @@ struct Package : ScopeDsymbol Package *isPackage() { return this; } - virtual void semantic(Scope *sc) { } + virtual void semantic(Scope *) { } + Dsymbol *search(Loc loc, Identifier *ident, int flags); }; -struct Module : Package +class Module : public Package { +public: static Module *rootModule; static DsymbolTable *modules; // symbol table of all modules static Modules amodules; // array of all modules static Dsymbols deferred; // deferred Dsymbol's needing semantic() run on them + static Dsymbols deferred3; // deferred Dsymbol's needing semantic3() run on them static unsigned dprogress; // progress resolving the deferred list static void init(); @@ -85,15 +98,7 @@ struct Module : Package int selfImports(); // returns !=0 if module imports itself int insearch; - Identifier *searchCacheIdent; - Dsymbol *searchCacheSymbol; // cached value of search - int searchCacheFlags; // cached flags - int semanticstarted; // has semantic() been started? - int semanticRun; // has semantic() been done? - int root; // != 0 if this is a 'root' module, - // i.e. a module that will be taken all the - // way to an object file Module *importedFrom; // module from command line we're imported from, // i.e. a module that will be taken all the // way to an object file @@ -102,8 +107,6 @@ struct Module : Package Modules aimports; // all imported modules - ModuleInfoDeclaration *vmoduleinfo; - unsigned debuglevel; // debug level Strings *debugids; // debug identifiers Strings *debugidsNot; // forward referenced debug identifiers @@ -114,7 +117,7 @@ struct Module : Package Macro *macrotable; // document comment macros Escape *escapetable; // document comment escapes - bool safe; // TRUE if module is marked as 'safe' + bool safe; // true if module is marked as 'safe' size_t nameoffset; // offset of module name from start of ModuleInfo size_t namelen; // length of module name in characters @@ -154,13 +157,17 @@ struct Module : Package void gendocfile(); int needModuleInfo(); Dsymbol *search(Loc loc, Identifier *ident, int flags); - Dsymbol *symtabInsert(Dsymbol *s); void deleteObjFile(); - void addDeferredSemantic(Dsymbol *s); + static void addDeferredSemantic(Dsymbol *s); static void runDeferredSemantic(); - static void clearCache(); + static void addDeferredSemantic3(Dsymbol *s); + static void runDeferredSemantic3(); int imports(Module *m); + bool isRoot() { return this->importedFrom == this; } + // true if the module source file is directly + // listed in command line. + // Back end #if IN_DMD int doppelganger; // sub-module @@ -186,7 +193,6 @@ struct Module : Package Symbol *toModuleArray(); // get module array bounds function - static Symbol *gencritsec(); elem *toEfilename(); Symbol *toSymbol(); @@ -206,19 +212,18 @@ struct Module : Package // array ops emitted in this module already AA *arrayfuncs; - - bool isRoot; #endif }; struct ModuleDeclaration { + Loc loc; Identifier *id; Identifiers *packages; // array of Identifier's representing packages bool safe; - ModuleDeclaration(Identifiers *packages, Identifier *id, bool safe); + ModuleDeclaration(Loc loc, Identifiers *packages, Identifier *id, bool safe); char *toChars(); }; diff --git a/dmd2/mtype.c b/dmd2/mtype.c index 7f74e68d..e3b535c4 100644 --- a/dmd2/mtype.c +++ b/dmd2/mtype.c @@ -50,8 +50,8 @@ #include "aggregate.h" #include "hdrgen.h" - FuncDeclaration *hasThis(Scope *sc); +void sizeToCBuffer(OutBuffer *buf, HdrGenState *hgs, Expression *e); #define LOGDOTEXP 0 // log ::dotExp() #define LOGDEFAULTINIT 0 // log ::defaultInit() @@ -64,7 +64,7 @@ int Tptrdiff_t = Tint32; /***************************** Type *****************************/ -ClassDeclaration *Type::typeinfo; +ClassDeclaration *Type::dtypeinfo; ClassDeclaration *Type::typeinfoclass; ClassDeclaration *Type::typeinfointerface; ClassDeclaration *Type::typeinfostruct; @@ -165,6 +165,13 @@ const char *Type::kind() return NULL; } +Type *Type::copy() +{ + Type *t = (Type *)mem.malloc(sizeTy[ty]); + memcpy((void*)t, (void*)this, sizeTy[ty]); + return t; +} + Type *Type::syntaxCopy() { print(); @@ -173,20 +180,19 @@ Type *Type::syntaxCopy() return this; } -int Type::equals(Object *o) -{ Type *t; - - t = (Type *)o; +bool Type::equals(RootObject *o) +{ + Type *t = (Type *)o; //printf("Type::equals(%s, %s)\n", toChars(), t->toChars()); if (this == o || ((t && deco == t->deco) && // deco strings are unique deco != NULL)) // and semantic() has been run { //printf("deco = '%s', t->deco = '%s'\n", deco, t->deco); - return 1; + return true; } //if (deco && t && t->deco) printf("deco = '%s', t->deco = '%s'\n", deco, t->deco); - return 0; + return false; } char Type::needThisPrefix() @@ -332,10 +338,10 @@ void Type::init() tnull->deco = tnull->merge()->deco; tvoidptr = tvoid->pointerTo(); - tstring = tchar->invariantOf()->arrayOf(); + tstring = tchar->immutableOf()->arrayOf(); tvalist = tvoid->pointerTo(); - if (global.params.is64bit) + if (global.params.isLP64) { Tsize_t = Tuns64; Tptrdiff_t = Tint64; @@ -384,7 +390,7 @@ Type *Type::trySemantic(Loc loc, Scope *sc) //printf("+trySemantic(%s) %d\n", toChars(), global.errors); unsigned errors = global.startGagging(); Type *t = semantic(loc, sc); - if (global.endGagging(errors)) // if any errors happened + if (global.endGagging(errors) || t->ty == Terror) // if any errors happened { t = NULL; } @@ -401,7 +407,7 @@ Type *Type::nullAttributes() { unsigned sz = sizeTy[ty]; Type *t = (Type *)mem.malloc(sz); - memcpy(t, this, sz); + memcpy((void*)t, (void*)this, sz); // t->mod = NULL; // leave mod unchanged t->deco = NULL; t->arrayof = NULL; @@ -446,9 +452,9 @@ Type *Type::constOf() * Convert to 'immutable'. */ -Type *Type::invariantOf() +Type *Type::immutableOf() { - //printf("Type::invariantOf() %p %s\n", this, toChars()); + //printf("Type::immutableOf() %p %s\n", this, toChars()); if (isImmutable()) { return this; @@ -929,7 +935,7 @@ void Type::check() } Type *tn = nextOf(); - if (tn && ty != Tfunction && tn->ty != Tfunction) + if (tn && ty != Tfunction && tn->ty != Tfunction && ty != Tenum) { // Verify transitivity switch (mod) { @@ -1073,7 +1079,7 @@ Type *Type::castMod(unsigned mod) break; case MODimmutable: - t = invariantOf(); + t = immutableOf(); break; case MODshared: @@ -1125,7 +1131,7 @@ Type *Type::addMod(unsigned mod) break; case MODimmutable: - t = invariantOf(); + t = immutableOf(); break; case MODshared: @@ -1192,10 +1198,15 @@ Type *Type::pointerTo() if (ty == Terror) return this; if (!pto) - { Type *t; - - t = new TypePointer(this); - pto = t->merge(); + { + Type *t = new TypePointer(this); + if (ty == Tfunction) + { + t->deco = t->merge()->deco; + pto = t; + } + else + pto = t->merge(); } return pto; } @@ -1289,7 +1300,7 @@ Type *Type::aliasthisOf() int Type::checkAliasThisRec() { Type *tb = toBasetype(); - enum AliasThisRec* pflag; + AliasThisRec* pflag; if (tb->ty == Tstruct) pflag = &((TypeStruct *)tb)->att; else if (tb->ty == Tclass) @@ -1297,7 +1308,7 @@ int Type::checkAliasThisRec() else return 0; - enum AliasThisRec flag = (enum AliasThisRec)(*pflag & ~RECtracing); + AliasThisRec flag = (AliasThisRec)(*pflag & ~RECtracing); if (flag == RECfwdref) { Type *att = aliasthisOf(); @@ -1382,57 +1393,19 @@ int MODmerge(unsigned char mod1, unsigned char mod2) return mod1; //printf("MODmerge(1 = %x, 2 = %x)\n", modfrom, modto); - #define X(m, n) (((m) << 4) | (n)) - // cases are commutative - #define Y(m, n) X(m, n): case X(n, m) - switch (X(mod1, mod2)) - { -#if 0 - case X(0, 0): - case X(MODconst, MODconst): - case X(MODimmutable, MODimmutable): - case X(MODshared, MODshared): - case X(MODshared | MODconst, MODshared | MODconst): - case X(MODwild, MODwild): - case X(MODshared | MODwild, MODshared | MODwild): -#endif + unsigned char result = 0; - case Y(0, MODconst): - case Y(0, MODimmutable): - case Y(MODconst, MODimmutable): - case Y(MODconst, MODwild): - case Y(0, MODwild): - case Y(MODimmutable, MODwild): - return MODconst; - - case Y(0, MODshared): - return MODshared; - - case Y(0, MODshared | MODconst): - case Y(MODconst, MODshared): - case Y(MODconst, MODshared | MODconst): - case Y(MODimmutable, MODshared): - case Y(MODimmutable, MODshared | MODconst): - case Y(MODshared, MODshared | MODconst): - case Y(0, MODshared | MODwild): - case Y(MODconst, MODshared | MODwild): - case Y(MODimmutable, MODshared | MODwild): - case Y(MODshared, MODwild): - case Y(MODshared, MODshared | MODwild): - case Y(MODshared | MODconst, MODwild): - case Y(MODshared | MODconst, MODshared | MODwild): - return MODshared | MODconst; - - case Y(MODwild, MODshared | MODwild): - return MODshared | MODwild; - - default: - assert(0); - } - #undef Y - #undef X - assert(0); - return 0; + // If either type is shared, the result will be shared + if ((mod1 | mod2) & MODshared) + result |= MODshared; + // If both types are wild, the result will be wild + // Otherwise if either type is const or immutable or wild + // the result will be const + if (mod1 & mod2 & MODwild) + result |= MODwild; + else if ((mod1 | mod2) & (MODconst | MODimmutable | MODwild)) + result |= MODconst; + return result; } /********************************* @@ -1508,6 +1481,7 @@ void MODtoBuffer(OutBuffer *buf, unsigned char mod) char *MODtoChars(unsigned char mod) { OutBuffer buf; + buf.reserve(16); MODtoBuffer(&buf, mod); buf.writebyte(0); return buf.extractData(); @@ -1533,12 +1507,13 @@ void Type::toDecoBuffer(OutBuffer *buf, int flag) */ char *Type::toChars() -{ OutBuffer *buf; +{ OutBuffer buf; + buf.reserve(16); HdrGenState hgs; - buf = new OutBuffer(); - toCBuffer(buf, NULL, &hgs); - return buf->toChars(); + toCBuffer(&buf, NULL, &hgs); + buf.writebyte(0); + return buf.extractData(); } void Type::toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) @@ -1604,11 +1579,91 @@ void Type::modToBuffer(OutBuffer *buf) char *Type::modToChars() { OutBuffer buf; + buf.reserve(16); modToBuffer(&buf); buf.writebyte(0); return buf.extractData(); } +/************************************ + * Strip all parameter's idenfiers and their default arguments for merging types. + * If some of parameter types or return type are function pointer, delegate, or + * the types which contains either, then strip also from them. + */ + +Type *stripDefaultArgs(Type *t) +{ + struct N + { + static Parameters *stripParams(Parameters *arguments) + { + Parameters *args = arguments; + if (args && args->dim > 0) + { + for (size_t i = 0; i < args->dim; i++) + { + Parameter *a = (*args)[i]; + Type *ta = stripDefaultArgs(a->type); + if (ta != a->type || a->defaultArg || a->ident) + { + if (args == arguments) + { + args = new Parameters(); + args->setDim(arguments->dim); + for (size_t j = 0; j < args->dim; j++) + (*args)[j] = (*arguments)[j]; + } + (*args)[i] = new Parameter(a->storageClass, ta, NULL, NULL); + } + } + } + return args; + } + }; + + if (t == NULL) + return t; + + if (t->ty == Tfunction) + { + TypeFunction *tf = (TypeFunction *)t; + Type *tret = stripDefaultArgs(tf->next); + Parameters *args = N::stripParams(tf->parameters); + if (tret == tf->next && args == tf->parameters) + goto Lnot; + tf = (TypeFunction *)tf->copy(); + tf->parameters = args; + tf->next = tret; + //printf("strip %s\n <- %s\n", tf->toChars(), t->toChars()); + t = tf; + } + else if (t->ty == Ttuple) + { + TypeTuple *tt = (TypeTuple *)t; + Parameters *args = N::stripParams(tt->arguments); + if (args == tt->arguments) + goto Lnot; + t = new TypeTuple(args); + } + else if (t->ty == Tenum) + { + // TypeEnum::nextOf() may be != NULL, but it's not necessary here. + goto Lnot; + } + else + { + Type *tn = t->nextOf(); + Type *n = stripDefaultArgs(tn); + if (n == tn) + goto Lnot; + t = t->copy(); + ((TypeNext *)t)->next = n; + } + //printf("strip %s\n", t->toChars()); +Lnot: + return t; +} + /************************************ */ @@ -1620,7 +1675,7 @@ Type *Type::merge() if (ty == Tinstance) return this; if (ty == Taarray && !((TypeAArray *)this)->index->merge()->deco) return this; - if (nextOf() && !nextOf()->deco) + if (ty != Tenum && nextOf() && !nextOf()->deco) return this; //printf("merge(%s)\n", toChars()); @@ -1629,12 +1684,12 @@ Type *Type::merge() if (!deco) { OutBuffer buf; - StringValue *sv; + buf.reserve(32); //if (next) //next = next->merge(); toDecoBuffer(&buf); - sv = stringtable.update((char *)buf.data, buf.offset); + StringValue *sv = stringtable.update((char *)buf.data, buf.offset); if (sv->ptrvalue) { t = (Type *) sv->ptrvalue; #ifdef DEBUG @@ -1646,8 +1701,8 @@ Type *Type::merge() } else { - sv->ptrvalue = this; - deco = (char *)sv->toDchars(); + sv->ptrvalue = (char *)(t = stripDefaultArgs(t)); + deco = t->deco = (char *)sv->toDchars(); //printf("new value, deco = '%s' %p\n", t->deco, t->deco); } } @@ -1817,12 +1872,8 @@ MATCH Type::implicitConvTo(Type *to) //printf("Type::implicitConvTo(this=%p, to=%p)\n", this, to); //printf("from: %s\n", toChars()); //printf("to : %s\n", to->toChars()); - if (this == to) + if (this->equals(to)) return MATCHexact; -#if IN_LLVM - if (deco == to->deco) - return MATCHexact; -#endif return MATCHnomatch; } @@ -1874,10 +1925,17 @@ Type *Type::substWildTo(unsigned mod) //printf("+Type::substWildTo this = %s, mod = x%x\n", toChars(), mod); Type *t; - if (nextOf()) + if (Type *tn = nextOf()) { - t = nextOf()->substWildTo(mod); - if (t == nextOf()) + // substitution has no effect on function pointer type. + if (ty == Tpointer && tn->ty == Tfunction) + { + t = this; + goto L1; + } + + t = tn->substWildTo(mod); + if (t == tn) t = this; else { @@ -1892,6 +1950,10 @@ Type *Type::substWildTo(unsigned mod) t = new TypeAArray(t, ((TypeAArray *)this)->index->syntaxCopy()); ((TypeAArray *)t)->sc = ((TypeAArray *)this)->sc; // duplicate scope } + else if (ty == Tdelegate) + { + t = new TypeDelegate(t); + } else assert(0); @@ -1901,12 +1963,13 @@ Type *Type::substWildTo(unsigned mod) else t = this; +L1: if (isWild()) { if (mod & MODconst) t = isShared() ? t->sharedConstOf() : t->constOf(); else if (mod & MODimmutable) - t = t->invariantOf(); + t = t->immutableOf(); else if (mod & MODwild) t = isShared() ? t->sharedWildOf() : t->wildOf(); else @@ -1917,6 +1980,47 @@ Type *Type::substWildTo(unsigned mod) return t; } +Type *TypeFunction::substWildTo(unsigned) +{ + if (!iswild && !(mod & MODwild)) + return this; + + // Substitude inout qualifier of function type to mutable or immutable + // would break type system. Instead substitude inout to the most weak + // qualifer - const. + unsigned m = MODconst; + + assert(next); + Type *tret = next->substWildTo(m); + Parameters *params = parameters; + if (mod & MODwild) + params = parameters->copy(); + for (size_t i = 0; i < params->dim; i++) + { + Parameter *p = (*params)[i]; + Type *t = p->type->substWildTo(m); + if (t == p->type) + continue; + if (params == parameters) + params = parameters->copy(); + (*params)[i] = new Parameter(p->storageClass, t, NULL, NULL); + } + if (next == tret && params == parameters) + return this; + + // Similar to TypeFunction::syntaxCopy; + TypeFunction *t = new TypeFunction(params, tret, varargs, linkage); + t->mod = ((mod & MODwild) ? (mod & ~MODwild) | MODconst : mod); + t->isnothrow = isnothrow; + t->purity = purity; + t->isproperty = isproperty; + t->isref = isref; + t->iswild = false; // done + t->trust = trust; + t->fargs = fargs; + return t->merge(); +} + /************************** * Return type with the top level of it being mutable. */ @@ -2023,14 +2127,17 @@ Expression *Type::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag) #if LOGDOTEXP printf("Type::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars()); #endif - if (e->op == TOKdotvar) + Expression *ex = e; + while (ex->op == TOKcomma) + ex = ((CommaExp *)ex)->e2; + if (ex->op == TOKdotvar) { - DotVarExp *dv = (DotVarExp *)e; + DotVarExp *dv = (DotVarExp *)ex; v = dv->var->isVarDeclaration(); } - else if (e->op == TOKvar) + else if (ex->op == TOKvar) { - VarExp *ve = (VarExp *)e; + VarExp *ve = (VarExp *)ex; v = ve->var->isVarDeclaration(); } if (v) @@ -2155,6 +2262,11 @@ Expression *Type::noMember(Scope *sc, Expression *e, Identifier *ident, int flag DotTemplateInstanceExp *dti = new DotTemplateInstanceExp(e->loc, e, Id::opDispatch, tiargs); dti->ti->tempdecl = td; + /* opDispatch, which doesn't need IFTI, may occur instantiate error. + * It should be gagged if flag != 0. + * e.g. + * tempalte opDispatch(name) if (isValid!name) { ... } + */ unsigned errors = flag ? global.startGagging() : 0; Expression *e = dti->semanticY(sc, 0); if (flag && global.endGagging(errors)) @@ -2197,6 +2309,7 @@ Identifier *Type::getTypeInfoIdent(int internal) { // _init_10TypeInfo_%s OutBuffer buf; + buf.reserve(32); if (internal) { buf.writeByte(mangleChar[ty]); @@ -2237,7 +2350,7 @@ TypeBasic *Type::isTypeBasic() } -void Type::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps) +void Type::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid) { //printf("Type::resolve() %s, %d\n", toChars(), ty); Type *t = semantic(loc, sc); @@ -2300,6 +2413,18 @@ Type *Type::nextOf() return NULL; } +/************************************* + * If this is a type of static array, return its base element type. + */ + +Type *Type::baseElemOf() +{ + Type *t = toBasetype(); + while (t->ty == Tsarray) + t = ((TypeSArray *)t)->next->toBasetype(); + return t; +} + /**************************************** * Return the mask that an integral type will * fit into. @@ -2432,7 +2557,7 @@ Type *TypeNext::makeInvariant() if (ty != Tfunction && next->ty != Tfunction && //(next->deco || next->ty == Tfunction) && !next->isImmutable()) - { t->next = next->invariantOf(); + { t->next = next->immutableOf(); } if (ty == Taarray) { @@ -2826,11 +2951,7 @@ Expression *TypeBasic::getProperty(Loc loc, Identifier *ident, int flag) { Expression *e; d_int64 ivalue; -#ifdef IN_GCC - real_t fvalue; -#else d_float80 fvalue; -#endif //printf("TypeBasic::getProperty('%s')\n", ident->toChars()); if (ident == Id::max) @@ -2921,7 +3042,7 @@ Expression *TypeBasic::getProperty(Loc loc, Identifier *ident, int flag) case Tfloat64: case Tfloat80: { - fvalue = Port::nan; + fvalue = Port::ldbl_nan; goto Lfvalue; } } @@ -2939,7 +3060,7 @@ Expression *TypeBasic::getProperty(Loc loc, Identifier *ident, int flag) case Tfloat32: case Tfloat64: case Tfloat80: - fvalue = Port::infinity; + fvalue = Port::ldbl_infinity; goto Lfvalue; } } @@ -3159,42 +3280,12 @@ Expression *TypeBasic::dotExp(Scope *sc, Expression *e, Identifier *ident, int f } Expression *TypeBasic::defaultInit(Loc loc) -{ dinteger_t value = 0; - -#if SNAN_DEFAULT_INIT - /* - * Use a payload which is different from the machine NaN, - * so that uninitialised variables can be - * detected even if exceptions are disabled. - */ -#if IN_LLVM - union - { unsigned short us[8]; - longdouble ld; - } snan = -#if __LITTLE_ENDIAN__ - {{ 0, 0, 0, 0xA000, 0x7FFF }}; -#else - {{ 0x7FFF, 0xA000, 0, 0, 0 }}; -#endif -#else - union - { unsigned short us[8]; - longdouble ld; - } snan = {{ 0, 0, 0, 0xA000, 0x7FFF }}; -#endif - /* - * Although long doubles are 10 bytes long, some - * C ABIs pad them out to 12 or even 16 bytes, so - * leave enough space in the snan array. - */ - assert(Target::realsize <= sizeof(snan)); - d_float80 fvalue = snan.ld; -#endif - +{ #if LOGDEFAULTINIT printf("TypeBasic::defaultInit() '%s'\n", toChars()); #endif + dinteger_t value = 0; + switch (ty) { case Tchar: @@ -3213,7 +3304,7 @@ Expression *TypeBasic::defaultInit(Loc loc) case Tfloat64: case Tfloat80: #if SNAN_DEFAULT_INIT - return new RealExp(loc, fvalue, this); + return new RealExp(loc, Port::snan, this); #else return getProperty(loc, Id::nan); #endif @@ -3224,8 +3315,8 @@ Expression *TypeBasic::defaultInit(Loc loc) #if SNAN_DEFAULT_INIT { // Can't use fvalue + I*fvalue (the im part becomes a quiet NaN). complex_t cvalue; - ((real_t *)&cvalue)[0] = fvalue; - ((real_t *)&cvalue)[1] = fvalue; + ((real_t *)&cvalue)[0] = Port::snan; + ((real_t *)&cvalue)[1] = Port::snan; return new ComplexExp(loc, cvalue, this); } #else @@ -3422,16 +3513,6 @@ Type *TypeVector::semantic(Loc loc, Scope *sc) return terror; } TypeSArray *t = (TypeSArray *)basetype; - - if (sc && sc->parameterSpecialization && t->dim->op == TOKvar && - ((VarExp *)t->dim)->var->storage_class & STCtemplateparameter) - { - /* It could be a template parameter N which has no value yet: - * template Foo(T : __vector(T[N]), size_t N); - */ - return this; - } - d_uns64 sz = t->size(loc); if (sz != 16 && sz != 32) { error(loc, "base type of __vector must be a 16 or 32 byte static array, not %s", t->toChars()); @@ -3519,12 +3600,10 @@ Expression *TypeVector::defaultInit(Loc loc) return basetype->defaultInit(loc); } -#if IN_LLVM Expression *TypeVector::defaultInitLiteral(Loc loc) { return basetype->defaultInitLiteral(loc); } -#endif int TypeVector::isZeroInit(Loc loc) { @@ -3562,6 +3641,11 @@ MATCH TypeVector::implicitConvTo(Type *to) return MATCHnomatch; } +Type *TypeVector::reliesOnTident(TemplateParameters *tparams) +{ + return basetype->reliesOnTident(tparams); +} + /***************************** TypeArray *****************************/ TypeArray::TypeArray(TY ty, Type *next) @@ -3585,24 +3669,19 @@ Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int f if (ident == Id::reverse && (n->ty == Tchar || n->ty == Twchar)) { - static const char *name[2] = { "_adReverseChar", "_adReverseWchar" }; + static const char *reverseName[2] = { "_adReverseChar", "_adReverseWchar" }; + static FuncDeclaration *reverseFd[2] = { NULL, NULL }; -#if IN_LLVM // LDC: Build parameters. - static FuncDeclaration *funcs[2] = { 0, 0 }; int i = n->ty == Twchar; - if (!funcs[i]) { + if (!reverseFd[i]) { Parameters *args = new Parameters; Type *next = n->ty == Twchar ? Type::twchar : Type::tchar; Type *arrty = next->arrayOf(); args->push(new Parameter(STCin, arrty, NULL, NULL)); - funcs[i] = FuncDeclaration::genCfunc(args, arrty, name[i]); + reverseFd[i] = FuncDeclaration::genCfunc(args, arrty, reverseName[i]); } - FuncDeclaration *fd = funcs[i]; -#else - const char *nm = name[n->ty == Twchar]; - FuncDeclaration *fd = FuncDeclaration::genCfunc(Type::tindex, nm); -#endif - Expression *ec = new VarExp(Loc(), fd); + + Expression *ec = new VarExp(Loc(), reverseFd[i]); e = e->castTo(sc, n->arrayOf()); // convert to dynamic array Expressions *arguments = new Expressions(); arguments->push(e); @@ -3611,31 +3690,21 @@ Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int f } else if (ident == Id::sort && (n->ty == Tchar || n->ty == Twchar)) { - Expression *ec; - FuncDeclaration *fd; - Expressions *arguments; - const char *nm; - static const char *name[2] = { "_adSortChar", "_adSortWchar" }; + static const char *sortName[2] = { "_adSortChar", "_adSortWchar" }; + static FuncDeclaration *sortFd[2] = { NULL, NULL }; -#if IN_LLVM // LDC: Build parameters. - static FuncDeclaration *funcs[2] = { 0, 0 }; int i = n->ty == Twchar; - if (!funcs[i]) { + if (!sortFd[i]) { Parameters *args = new Parameters; Type *next = n->ty == Twchar ? Type::twchar : Type::tchar; Type *arrty = next->arrayOf(); args->push(new Parameter(STCin, arrty, NULL, NULL)); - funcs[i] = FuncDeclaration::genCfunc(args, arrty, name[i]); + sortFd[i] = FuncDeclaration::genCfunc(args, arrty, sortName[i]); } - fd = funcs[i]; -#else - nm = name[n->ty == Twchar]; - fd = FuncDeclaration::genCfunc(Type::tindex, nm); -#endif - ec = new VarExp(Loc(), fd); + Expression *ec = new VarExp(Loc(), sortFd[i]); e = e->castTo(sc, n->arrayOf()); // convert to dynamic array - arguments = new Expressions(); + Expressions *arguments = new Expressions(); arguments->push(e); e = new CallExp(e->loc, ec, arguments); e->type = next->arrayOf(); @@ -3651,19 +3720,18 @@ Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int f Expression *olde = e; assert(size); dup = (ident == Id::dup || ident == Id::idup); -#if IN_LLVM // LDC: Build parameters. - Parameters *args = new Parameters; + if (dup) { - static FuncDeclaration *adDup_fd = 0; + static FuncDeclaration *adDup_fd = NULL; if (!adDup_fd) { Parameters* args = new Parameters; - args->push(new Parameter(STCin, Type::typeinfo->type, NULL, NULL)); + args->push(new Parameter(STCin, Type::dtypeinfo->type, NULL, NULL)); args->push(new Parameter(STCin, Type::tvoid->arrayOf(), NULL, NULL)); adDup_fd = FuncDeclaration::genCfunc(args, Type::tvoid->arrayOf(), Id::adDup); } fd = adDup_fd; } else { - static FuncDeclaration *adReverse_fd = 0; + static FuncDeclaration *adReverse_fd = NULL; if (!adReverse_fd) { Parameters* args = new Parameters; args->push(new Parameter(STCin, Type::tvoid->arrayOf(), NULL, NULL)); @@ -3672,9 +3740,7 @@ Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int f } fd = adReverse_fd; } -#else - fd = FuncDeclaration::genCfunc(Type::tindex, dup ? Id::adDup : Id::adReverse); -#endif + ec = new VarExp(Loc(), fd); e = e->castTo(sc, n->arrayOf()); // convert to dynamic array arguments = new Expressions(); @@ -3685,7 +3751,7 @@ Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int f arguments->push(new IntegerExp(Loc(), size, Type::tsize_t)); e = new CallExp(e->loc, ec, arguments); if (ident == Id::idup) - { Type *einv = next->invariantOf(); + { Type *einv = next->immutableOf(); if (next->implicitConvTo(einv) < MATCHconst) { error(e->loc, "cannot implicitly convert element type %s to immutable in %s.idup", next->toChars(), olde->toChars()); @@ -3708,20 +3774,16 @@ Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int f } else if (ident == Id::sort) { + static FuncDeclaration *fd = NULL; Expression *ec; Expressions *arguments; -#if IN_LLVM // LDC: Build parameters. - static FuncDeclaration *fd = NULL; if (!fd) { Parameters* args = new Parameters; args->push(new Parameter(STCin, Type::tvoid->arrayOf(), NULL, NULL)); - args->push(new Parameter(STCin, Type::typeinfo->type, NULL, NULL)); + args->push(new Parameter(STCin, Type::dtypeinfo->type, NULL, NULL)); fd = FuncDeclaration::genCfunc(args, Type::tvoid->arrayOf(), "_adSort"); } -#else - fd = FuncDeclaration::genCfunc(tint32->arrayOf(), "_adSort"); -#endif ec = new VarExp(Loc(), fd); e = e->castTo(sc, n->arrayOf()); // convert to dynamic array arguments = new Expressions(); @@ -3802,16 +3864,24 @@ unsigned TypeSArray::alignsize() Expression *semanticLength(Scope *sc, Type *t, Expression *exp) { if (t->ty == Ttuple) - { ScopeDsymbol *sym = new ArrayScopeSymbol(sc, (TypeTuple *)t); + { + ScopeDsymbol *sym = new ArrayScopeSymbol(sc, (TypeTuple *)t); sym->parent = sc->scopesym; sc = sc->push(sym); - exp = exp->ctfeSemantic(sc); + sc = sc->startCTFE(); + exp = exp->semantic(sc); + sc = sc->endCTFE(); sc->pop(); } else - exp = exp->ctfeSemantic(sc); + { + sc = sc->startCTFE(); + exp = exp->semantic(sc); + sc = sc->endCTFE(); + } + return exp; } @@ -3821,19 +3891,22 @@ Expression *semanticLength(Scope *sc, TupleDeclaration *s, Expression *exp) sym->parent = sc->scopesym; sc = sc->push(sym); - exp = exp->ctfeSemantic(sc); + sc = sc->startCTFE(); + exp = exp->semantic(sc); + sc = sc->endCTFE(); sc->pop(); return exp; } -void TypeSArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps) +void TypeSArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid) { //printf("TypeSArray::resolve() %s\n", toChars()); - next->resolve(loc, sc, pe, pt, ps); + next->resolve(loc, sc, pe, pt, ps, intypeid); //printf("s = %p, e = %p, t = %p\n", *ps, *pe, *pt); if (*pe) - { // It's really an index expression + { + // It's really an index expression Expressions *exps = new Expressions(); exps->setDim(1); (*exps)[0] = dim; @@ -3842,25 +3915,28 @@ void TypeSArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol *pe = new ArrayExp(loc, *pe, exps); } else if (*ps) - { Dsymbol *s = *ps; + { + Dsymbol *s = *ps; TupleDeclaration *td = s->isTupleDeclaration(); if (td) { ScopeDsymbol *sym = new ArrayScopeSymbol(sc, td); sym->parent = sc->scopesym; sc = sc->push(sym); + sc = sc->startCTFE(); + dim = dim->semantic(sc); + sc = sc->endCTFE(); + sc = sc->pop(); - dim = dim->ctfeSemantic(sc); dim = dim->ctfeInterpret(); uinteger_t d = dim->toUInteger(); - sc = sc->pop(); - if (d >= td->objects->dim) - { error(loc, "tuple index %llu exceeds length %u", d, td->objects->dim); + { + error(loc, "tuple index %llu exceeds length %u", d, td->objects->dim); goto Ldefault; } - Object *o = (*td->objects)[(size_t)d]; + RootObject *o = (*td->objects)[(size_t)d]; if (o->dyncast() == DYNCAST_DSYMBOL) { *ps = (Dsymbol *)o; @@ -3906,7 +3982,7 @@ void TypeSArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol else { Ldefault: - Type::resolve(loc, sc, pe, pt, ps); + Type::resolve(loc, sc, pe, pt, ps, intypeid); } } @@ -3929,7 +4005,7 @@ Type *TypeSArray::semantic(Loc loc, Scope *sc) { error(loc, "tuple index %llu exceeds %u", d, sd->objects->dim); return Type::terror; } - Object *o = (*sd->objects)[(size_t)d]; + RootObject *o = (*sd->objects)[(size_t)d]; if (o->dyncast() != DYNCAST_TYPE) { error(loc, "%s is not a type", toChars()); return Type::terror; @@ -3938,7 +4014,7 @@ Type *TypeSArray::semantic(Loc loc, Scope *sc) return t; } - Type *tn = next->semantic(loc,sc); + Type *tn = next->semantic(loc, sc); if (tn->ty == Terror) return terror; @@ -3953,14 +4029,6 @@ Type *TypeSArray::semantic(Loc loc, Scope *sc) goto Lerror; dim = dim->optimize(WANTvalue); - if (sc && sc->parameterSpecialization && dim->op == TOKvar && - ((VarExp *)dim)->var->storage_class & STCtemplateparameter) - { - /* It could be a template parameter N which has no value yet: - * template Foo(T : T[N], size_t N); - */ - return this; - } dim = dim->ctfeInterpret(); errors = global.errors; dinteger_t d1 = dim->toInteger(); @@ -3985,6 +4053,7 @@ Type *TypeSArray::semantic(Loc loc, Scope *sc) tbn->ty == Tarray || tbn->ty == Tsarray || tbn->ty == Taarray || + (tbn->ty == Tstruct && (((TypeStruct *)tbn)->sym->sizeok == SIZEOKdone)) || tbn->ty == Tclass) { /* Only do this for types that don't need to have semantic() @@ -4044,6 +4113,19 @@ Lerror: return Type::terror; } +// Make corresponding static array type without semantic +Type *TypeSArray::makeType(Loc loc, Type *tn, dinteger_t dim) +{ + assert(tn->deco); + Type *t = new TypeSArray(tn, new IntegerExp(loc, dim, Type::tindex)); + + // according to TypeSArray::semantic() + t = t->addMod(tn->mod); + t = t->merge(); + + return t; +} + void TypeSArray::toDecoBuffer(OutBuffer *buf, int flag) { Type::toDecoBuffer(buf, flag); @@ -4065,7 +4147,9 @@ void TypeSArray::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) return; } next->toCBuffer2(buf, hgs, this->mod); - buf->printf("[%s]", dim->toChars()); + buf->writeByte('['); + sizeToCBuffer(buf, hgs, dim); + buf->writeByte(']'); } Expression *TypeSArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag) @@ -4093,7 +4177,7 @@ Expression *TypeSArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int { e = TypeArray::dotExp(sc, e, ident, flag); } - if (!flag && e) + if (!flag || e) e = e->semantic(sc); return e; } @@ -4191,7 +4275,10 @@ Expression *TypeSArray::defaultInit(Loc loc) #if LOGDEFAULTINIT printf("TypeSArray::defaultInit() '%s'\n", toChars()); #endif - return next->defaultInit(loc); + if (next->ty == Tvoid) + return tuns8->defaultInit(loc); + else + return next->defaultInit(loc); } int TypeSArray::isZeroInit(Loc loc) @@ -4322,13 +4409,14 @@ Type *TypeDArray::semantic(Loc loc, Scope *sc) return merge(); } -void TypeDArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps) +void TypeDArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid) { //printf("TypeDArray::resolve() %s\n", toChars()); - next->resolve(loc, sc, pe, pt, ps); + next->resolve(loc, sc, pe, pt, ps, intypeid); //printf("s = %p, e = %p, t = %p\n", *ps, *pe, *pt); if (*pe) - { // It's really a slice expression + { + // It's really a slice expression if (Dsymbol *s = getDsymbol(*pe)) *pe = new DsymbolExp(loc, s, 1); *pe = new SliceExp(loc, *pe, NULL, NULL); @@ -4344,7 +4432,7 @@ void TypeDArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol else { Ldefault: - Type::resolve(loc, sc, pe, pt, ps); + Type::resolve(loc, sc, pe, pt, ps, intypeid); } } @@ -4539,22 +4627,23 @@ Type *TypeAArray::semantic(Loc loc, Scope *sc) index->resolve(loc, sc, &e, &t, &s); if (e) - { // It was an expression - + { + // It was an expression - // Rewrite as a static array - TypeSArray *tsa; - - tsa = new TypeSArray(next, e); - return tsa->semantic(loc,sc); + TypeSArray *tsa = new TypeSArray(next, e); + return tsa->semantic(loc, sc); } else if (t) - index = t; + index = t->semantic(loc, sc); else - { index->error(loc, "index is not a type or an expression"); + { + index->error(loc, "index is not a type or an expression"); return Type::terror; } } else index = index->semantic(loc,sc); + index = index->merge2(); if (index->nextOf() && !index->nextOf()->isImmutable()) { @@ -4581,7 +4670,7 @@ printf("index->ito->ito = x%x\n", index->ito->ito); case Terror: return Type::terror; } - next = next->semantic(loc,sc); + next = next->semantic(loc,sc)->merge2(); transitive(); switch (next->toBasetype()->ty) @@ -4647,6 +4736,7 @@ StructDeclaration *TypeAArray::getImpl() #endif // Instantiate on the root module of import dependency graph. Scope *scx = sc->push(sc->module->importedFrom); + scx->instantiatingModule = sc->module->importedFrom; ti->semantic(scx); ti->semantic2(scx); ti->semantic3(scx); @@ -4663,7 +4753,7 @@ StructDeclaration *TypeAArray::getImpl() return impl; } -void TypeAArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps) +void TypeAArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid) { //printf("TypeAArray::resolve() %s\n", toChars()); @@ -4675,20 +4765,21 @@ void TypeAArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol Type *t; Dsymbol *s; - index->resolve(loc, sc, &e, &t, &s); + index->resolve(loc, sc, &e, &t, &s, intypeid); if (e) - { // It was an expression - + { + // It was an expression - // Rewrite as a static array - TypeSArray *tsa = new TypeSArray(next, e); - return tsa->addMod(this->mod)->resolve(loc, sc, pe, pt, ps); + tsa->mod = this->mod; // just copy mod field so tsa's semantic is not yet done + return tsa->resolve(loc, sc, pe, pt, ps, intypeid); } else if (t) index = t; else index->error(loc, "index is not a type or an expression"); } - Type::resolve(loc, sc, pe, pt, ps); + Type::resolve(loc, sc, pe, pt, ps, intypeid); } @@ -4884,7 +4975,7 @@ Type *TypePointer::semantic(Loc loc, Scope *sc) { transitive(); return merge(); } -#if 1 +#if 0 return merge(); #else deco = merge()->deco; @@ -5088,7 +5179,7 @@ int TypeReference::isZeroInit(Loc loc) /***************************** TypeFunction *****************************/ -TypeFunction::TypeFunction(Parameters *parameters, Type *treturn, int varargs, enum LINK linkage, StorageClass stc) +TypeFunction::TypeFunction(Parameters *parameters, Type *treturn, int varargs, LINK linkage, StorageClass stc) : TypeNext(Tfunction, treturn) { //if (!treturn) *(char*)0=0; @@ -5129,13 +5220,6 @@ const char *TypeFunction::kind() return "function"; } -TypeFunction *TypeFunction::copy() -{ - TypeFunction *tf = (TypeFunction *)mem.malloc(sizeof(TypeFunction)); - memcpy(tf, this, sizeof(TypeFunction)); - return tf; -} - Type *TypeFunction::syntaxCopy() { Type *treturn = next ? next->syntaxCopy() : NULL; @@ -5146,6 +5230,7 @@ Type *TypeFunction::syntaxCopy() t->purity = purity; t->isproperty = isproperty; t->isref = isref; + t->iswild = iswild; t->trust = trust; t->fargs = fargs; return t; @@ -5205,12 +5290,7 @@ int Type::covariant(Type *t, StorageClass *pstc) if (!arg1->type->equals(arg2->type)) { -#if 0 // turn on this for contravariant argument types, see bugzilla 3075 - // BUG: cannot convert ref to const to ref to immutable - // We can add const, but not subtract it - if (arg2->type->implicitConvTo(arg1->type) < MATCHconst) -#endif - goto Ldistinct; + goto Ldistinct; } const StorageClass sc = STCref | STCin | STCout | STClazy; if ((arg1->storageClass & sc) != (arg2->storageClass & sc)) @@ -5256,13 +5336,9 @@ int Type::covariant(Type *t, StorageClass *pstc) // If t1n is forward referenced: ClassDeclaration *cd = ((TypeClass *)t1n)->sym; -// if (cd->scope) -// cd->semantic(NULL); -#if 0 - if (!cd->baseClass && cd->baseclasses->dim && !cd->isInterfaceDeclaration()) -#else + if (cd->scope) + cd->semantic(NULL); if (!cd->isBaseInfoComplete()) -#endif { return 3; // forward references } @@ -5588,13 +5664,13 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc) * This can produce redundant copies if inferring return type, * as semantic() will get called again on this. */ - TypeFunction *tf = copy(); + TypeFunction *tf = (TypeFunction *)copy(); if (parameters) { tf->parameters = (Parameters *)parameters->copy(); for (size_t i = 0; i < parameters->dim; i++) { Parameter *arg = (*parameters)[i]; Parameter *cpy = (Parameter *)mem.malloc(sizeof(Parameter)); - memcpy(cpy, arg, sizeof(Parameter)); + memcpy((void*)cpy, (void*)arg, sizeof(Parameter)); (*tf->parameters)[i] = cpy; } } @@ -5641,18 +5717,30 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc) sc->stc &= ~(STC_TYPECTOR | STC_FUNCATTR); tf->next = tf->next->semantic(loc,sc); sc = sc->pop(); - if (tf->next->toBasetype()->ty == Tfunction) - { error(loc, "functions cannot return a function"); + Type *tb = tf->next->toBasetype(); + if (tb->ty == Tfunction) + { + error(loc, "functions cannot return a function"); tf->next = Type::terror; } - if (tf->next->toBasetype()->ty == Ttuple) - { error(loc, "functions cannot return a tuple"); + else if (tb->ty == Ttuple) + { + error(loc, "functions cannot return a tuple"); tf->next = Type::terror; } + else if (tb->ty == Tstruct) + { + StructDeclaration *sd = ((TypeStruct *)tb)->sym; + if (sd->isforwardRef()) + { + error(loc, "cannot return opaque struct %s by value", tb->toChars()); + tf->next = Type::terror; + } + } + else if (tb->ty == Tvoid) + tf->isref = FALSE; // rewrite "ref void" as just "void" if (tf->next->isscope() && !(sc->flags & SCOPEctor)) error(loc, "functions cannot return scope %s", tf->next->toChars()); - if (tf->next->toBasetype()->ty == Tvoid) - tf->isref = FALSE; // rewrite "ref void" as just "void" if (tf->next->hasWild() && !(tf->next->ty == Tpointer && tf->next->nextOf()->ty == Tfunction || tf->next->ty == Tdelegate)) wildreturn = TRUE; @@ -5686,15 +5774,27 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc) Type *t = fparam->type->toBasetype(); - if (fparam->storageClass & (STCout | STCref | STClazy)) - { - //if (t->ty == Tsarray) - //error(loc, "cannot have out or ref parameter of type %s", t->toChars()); - if (fparam->storageClass & STCout && fparam->type->mod & (STCconst | STCimmutable)) - error(loc, "cannot have const or immutable out parameter of type %s", t->toChars()); - } if (!(fparam->storageClass & STClazy) && t->ty == Tvoid) error(loc, "cannot have parameter of type %s", fparam->type->toChars()); + if (fparam->storageClass & (STCref | STClazy)) + { + } + else if (fparam->storageClass & STCout) + { + if (unsigned m = fparam->type->mod & (MODimmutable | MODconst | MODwild)) + error(loc, "cannot have %s out parameter of type %s", MODtoChars(m), t->toChars()); + else + { + Type *tv = t; + while (tv->ty == Tsarray) + tv = tv->nextOf()->toBasetype(); + if (tv->ty == Tstruct && ((TypeStruct *)tv)->sym->noDefaultCtor) + { + error(loc, "cannot have out parameter of type %s because the default construction is disbaled", + fparam->type->toChars()); + } + } + } if (t->hasWild() && !(t->ty == Tpointer && t->nextOf()->ty == Tfunction || t->ty == Tdelegate)) @@ -5770,7 +5870,10 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc) if (fparam->storageClass & STCauto) { if (fargs && i < fargs->dim) - { Expression *farg = (*fargs)[i]; + { + Expression *farg = (*fargs)[i]; + if (Expression *e = farg->isTemp()) + farg = e; if (farg->isLvalue()) ; // ref parameter else @@ -6032,20 +6135,23 @@ MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag) if (m && !arg->isLvalue()) { if (arg->op == TOKstring && tprmb->ty == Tsarray) - { if (targb->ty != Tsarray) - { - targb = new TypeSArray(tprmb->nextOf()->castMod(targb->nextOf()->mod), - new IntegerExp(Loc(), ((StringExp *)arg)->len, - Type::tindex)); - targb = targb->semantic(Loc(), NULL); + { + if (targb->ty != Tsarray) + { + Type *tn = tprmb->nextOf()->castMod(targb->nextOf()->mod); + dinteger_t dim = ((StringExp *)arg)->len; + targb = TypeSArray::makeType(Loc(), tn, dim); } } else if (arg->op == TOKslice && tprmb->ty == Tsarray) - { // Allow conversion from T[lwr .. upr] to ref T[upr-lwr] - targb = new TypeSArray(targb->nextOf(), - new IntegerExp(Loc(), ((TypeSArray *)tprmb)->dim->toUInteger(), - Type::tindex)); - targb = targb->semantic(Loc(), NULL); + { + // Allow conversion from T[lwr .. upr] to ref T[upr-lwr] + if (targb->ty != Tsarray) + { + Type *tn = targb->nextOf(); + dinteger_t dim = ((TypeSArray *)tprmb)->dim->toUInteger(); + targb = TypeSArray::makeType(Loc(), tn, dim); + } } else goto Nomatch; @@ -6305,7 +6411,7 @@ Type *TypeDelegate::semantic(Loc loc, Scope *sc) * be removed from next before the merge. */ -#if 1 +#if 0 return merge(); #else /* Don't return merge(), because arg identifiers and default args @@ -6419,7 +6525,7 @@ void TypeQualified::syntaxCopyHelper(TypeQualified *t) idents.setDim(t->idents.dim); for (size_t i = 0; i < idents.dim; i++) { - Object *id = t->idents[i]; + RootObject *id = t->idents[i]; if (id->dyncast() == DYNCAST_DSYMBOL) { TemplateInstance *ti = (TemplateInstance *)id; @@ -6445,7 +6551,7 @@ void TypeQualified::addInst(TemplateInstance *inst) void TypeQualified::toCBuffer2Helper(OutBuffer *buf, HdrGenState *hgs) { for (size_t i = 0; i < idents.dim; i++) - { Object *id = idents[i]; + { RootObject *id = idents[i]; buf->writeByte('.'); @@ -6475,7 +6581,7 @@ d_uns64 TypeQualified::size(Loc loc) void TypeQualified::resolveHelper(Loc loc, Scope *sc, Dsymbol *s, Dsymbol *scopesym, - Expression **pe, Type **pt, Dsymbol **ps) + Expression **pe, Type **pt, Dsymbol **ps, bool intypeid) { #if 0 printf("TypeQualified::resolveHelper(sc = %p, idents = '%s')\n", sc, toChars()); @@ -6493,16 +6599,19 @@ void TypeQualified::resolveHelper(Loc loc, Scope *sc, //printf("\t2: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind()); for (size_t i = 0; i < idents.dim; i++) { - Object *id = idents[i]; + RootObject *id = idents[i]; + Type *t = s->getType(); // type symbol, type alias, or type tuple? Dsymbol *sm = s->searchX(loc, sc, id); - //printf("\t3: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind()); - //printf("\tgetType = '%s'\n", s->getType()->toChars()); + //printf("\t3: s = %p %s %s, sm = %p\n", s, s->kind(), s->toChars(), sm); + if (intypeid && !t && sm && sm->needThis()) + goto L3; if (!sm) { - Type *t = s->getType(); // type symbol, type alias, or type tuple? if (!t) - { if (s->isDeclaration()) // var, func, or tuple declaration? - { t = s->isDeclaration()->type; + { + if (s->isDeclaration()) // var, func, or tuple declaration? + { + t = s->isDeclaration()->type; if (!t && s->isTupleDeclaration()) // expression tuple? goto L3; } @@ -6522,11 +6631,17 @@ void TypeQualified::resolveHelper(Loc loc, Scope *sc, goto L2; } L3: - Expression *e = new DsymbolExp(loc, s); + Expression *e; + VarDeclaration *v = s->isVarDeclaration(); + FuncDeclaration *f = s->isFuncDeclaration(); + if (intypeid || !v && !f) + e = new DsymbolExp(loc, s); + else + e = new VarExp(loc, s->isDeclaration()); e = e->semantic(sc); for (; i < idents.dim; i++) { - Object *id = idents[i]; + RootObject *id = idents[i]; //printf("e: '%s', id: '%s', type = %s\n", e->toChars(), id->toChars(), e->type->toChars()); if (id->dyncast() == DYNCAST_IDENTIFIER) { @@ -6534,7 +6649,8 @@ void TypeQualified::resolveHelper(Loc loc, Scope *sc, e = die->semanticY(sc, 0); } else - { assert(id->dyncast() == DYNCAST_DSYMBOL); + { + assert(id->dyncast() == DYNCAST_DSYMBOL); TemplateInstance *ti = ((Dsymbol *)id)->isTemplateInstance(); assert(ti); DotTemplateInstanceExp *dte = new DotTemplateInstanceExp(e->loc, e, ti->name, ti->tiargs); @@ -6548,7 +6664,6 @@ void TypeQualified::resolveHelper(Loc loc, Scope *sc, } else { - Lerror: if (id->dyncast() == DYNCAST_DSYMBOL) { // searchX already handles errors for template instances assert(global.errors); @@ -6718,7 +6833,7 @@ void TypeIdentifier::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) * if type, *pt is set */ -void TypeIdentifier::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps) +void TypeIdentifier::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid) { Dsymbol *scopesym; @@ -6747,7 +6862,7 @@ void TypeIdentifier::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsy } Dsymbol *s = sc->search(loc, ident, &scopesym); - resolveHelper(loc, sc, s, scopesym, pe, pt, ps); + resolveHelper(loc, sc, s, scopesym, pe, pt, ps, intypeid); if (*pt) (*pt) = (*pt)->addMod(mod); } @@ -6770,7 +6885,7 @@ Dsymbol *TypeIdentifier::toDsymbol(Scope *sc) { for (size_t i = 0; i < idents.dim; i++) { - Object *id = idents[i]; + RootObject *id = idents[i]; s = s->searchX(loc, sc, id); if (!s) // failed to find a symbol { //printf("\tdidn't find a symbol\n"); @@ -6794,8 +6909,8 @@ Type *TypeIdentifier::semantic(Loc loc, Scope *sc) //printf("\tit's a type %d, %s, %s\n", t->ty, t->toChars(), t->deco); if (t->ty == Ttypedef) - { TypeTypedef *tt = (TypeTypedef *)t; - + { + TypeTypedef *tt = (TypeTypedef *)t; if (tt->sym->sem == SemanticIn) { error(loc, "circular reference of typedef %s", tt->toChars()); return terror; @@ -6822,14 +6937,11 @@ Type *TypeIdentifier::reliesOnTident(TemplateParameters *tparams) { if (tparams) { - if (idents.dim == 0) + for (size_t i = 0; i < tparams->dim; i++) { - for (size_t i = 0; i < tparams->dim; i++) - { TemplateParameter *tp = (*tparams)[i]; - - if (tp->ident->equals(ident)) - return this; - } + TemplateParameter *tp = (*tparams)[i]; + if (tp->ident->equals(ident)) + return this; } return NULL; } @@ -6842,13 +6954,14 @@ Expression *TypeIdentifier::toExpression() Expression *e = new IdentifierExp(loc, ident); for (size_t i = 0; i < idents.dim; i++) { - Object *id = idents[i]; + RootObject *id = idents[i]; if (id->dyncast() == DYNCAST_IDENTIFIER) { e = new DotIdExp(loc, e, (Identifier *)id); } else - { assert(id->dyncast() == DYNCAST_DSYMBOL); + { + assert(id->dyncast() == DYNCAST_DSYMBOL); TemplateInstance *ti = ((Dsymbol *)id)->isTemplateInstance(); assert(ti); e = new DotTemplateInstanceExp(loc, e, ti->name, ti->tiargs); @@ -6893,7 +7006,7 @@ void TypeInstance::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) toCBuffer2Helper(buf, hgs); } -void TypeInstance::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps) +void TypeInstance::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid) { // Note close similarity to TypeIdentifier::resolve() @@ -6914,10 +7027,11 @@ void TypeInstance::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymb //printf("TypeInstance::resolve(sc = %p, idents = '%s')\n", sc, id->toChars()); s = tempinst; if (s) - { //printf("s = %s\n", s->toChars()); + { + //printf("s = %s\n", s->toChars()); s->semantic(sc); } - resolveHelper(loc, sc, s, NULL, pe, pt, ps); + resolveHelper(loc, sc, s, NULL, pe, pt, ps, intypeid); if (*pt) *pt = (*pt)->addMod(mod); //printf("pt = '%s'\n", (*pt)->toChars()); @@ -6930,18 +7044,6 @@ Type *TypeInstance::semantic(Loc loc, Scope *sc) Dsymbol *s; //printf("TypeInstance::semantic(%p, %s)\n", this, toChars()); - - if (sc->parameterSpecialization) - { - unsigned errors = global.startGagging(); - resolve(loc, sc, &e, &t, &s); - - if (global.endGagging(errors)) - { - return this; - } - } - else { unsigned errors = global.errors; resolve(loc, sc, &e, &t, &s); @@ -6971,18 +7073,7 @@ Dsymbol *TypeInstance::toDsymbol(Scope *sc) Dsymbol *s; //printf("TypeInstance::semantic(%s)\n", toChars()); - - if (sc->parameterSpecialization) - { - unsigned errors = global.startGagging(); - - resolve(loc, sc, &e, &t, &s); - - if (global.endGagging(errors)) - return NULL; - } - else - resolve(loc, sc, &e, &t, &s); + resolve(loc, sc, &e, &t, &s); return s; } @@ -7016,7 +7107,24 @@ Type *TypeInstance::reliesOnTident(TemplateParameters *tparams) Expression *TypeInstance::toExpression() { - return new ScopeExp(loc, tempinst); + Expression *e = new ScopeExp(loc, tempinst); + for (size_t i = 0; i < idents.dim; i++) + { + RootObject *id = idents[i]; + if (id->dyncast() == DYNCAST_IDENTIFIER) + { + e = new DotIdExp(loc, e, (Identifier *)id); + } + else + { + assert(id->dyncast() == DYNCAST_DSYMBOL); + TemplateInstance *ti = ((Dsymbol *)id)->isTemplateInstance(); + assert(ti); + e = new DotTemplateInstanceExp(loc, e, ti->name, ti->tiargs); + } + } + + return e; } @@ -7067,7 +7175,7 @@ void TypeTypeof::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) toCBuffer2Helper(buf, hgs); } -void TypeTypeof::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps) +void TypeTypeof::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid) { *pe = NULL; *pt = NULL; @@ -7093,13 +7201,10 @@ void TypeTypeof::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol if (global.gag) global.speculativeGag = global.gag; exp = exp->semantic(sc2); - global.speculativeGag = oldspecgag; - #if DMDV2 - if (exp->type && exp->type->ty == Tfunction && - ((TypeFunction *)exp->type)->isproperty) - exp = resolveProperties(sc2, exp); + exp = resolvePropertiesOnly(sc2, exp); #endif + global.speculativeGag = oldspecgag; sc2->pop(); if (exp->op == TOKtype) { @@ -7113,7 +7218,8 @@ void TypeTypeof::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol goto Lerr; } if (t->ty == Ttypeof) - { error(loc, "forward reference to %s", toChars()); + { + error(loc, "forward reference to %s", toChars()); goto Lerr; } } @@ -7122,13 +7228,13 @@ void TypeTypeof::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol else { if (Dsymbol *s = t->toDsymbol(sc)) - resolveHelper(loc, sc, s, NULL, pe, pt, ps); + resolveHelper(loc, sc, s, NULL, pe, pt, ps, intypeid); else { Expression *e = new TypeExp(loc, t); for (size_t i = 0; i < idents.dim; i++) { - Object *id = idents[i]; + RootObject *id = idents[i]; switch (id->dyncast()) { case DYNCAST_IDENTIFIER: @@ -7221,7 +7327,7 @@ Dsymbol *TypeReturn::toDsymbol(Scope *sc) return t->toDsymbol(sc); } -void TypeReturn::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps) +void TypeReturn::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid) { *pe = NULL; *pt = NULL; @@ -7232,7 +7338,8 @@ void TypeReturn::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol { FuncDeclaration *func = sc->func; if (!func) - { error(loc, "typeof(return) must be inside function"); + { + error(loc, "typeof(return) must be inside function"); goto Lerr; } if (func->fes) @@ -7250,13 +7357,13 @@ void TypeReturn::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol else { if (Dsymbol *s = t->toDsymbol(sc)) - resolveHelper(loc, sc, s, NULL, pe, pt, ps); + resolveHelper(loc, sc, s, NULL, pe, pt, ps, intypeid); else { Expression *e = new TypeExp(loc, t); for (size_t i = 0; i < idents.dim; i++) { - Object *id = idents[i]; + RootObject *id = idents[i]; switch (id->dyncast()) { case DYNCAST_IDENTIFIER: @@ -7348,28 +7455,22 @@ Type *TypeEnum::syntaxCopy() Type *TypeEnum::semantic(Loc loc, Scope *sc) { //printf("TypeEnum::semantic() %s\n", toChars()); - //sym->semantic(sc); + if (deco) + return this; return merge(); } d_uns64 TypeEnum::size(Loc loc) { - if (!sym->memtype) - { - error(loc, "enum %s is forward referenced", sym->toChars()); - return SIZE_INVALID; - } - return sym->memtype->size(loc); + return sym->getMemtype(loc)->size(loc); } unsigned TypeEnum::alignsize() { - if (!sym->memtype) - { - error(Loc(), "enum %s is forward referenced", sym->toChars()); + Type *t = sym->getMemtype(Loc()); + if (t->ty == Terror) return 4; - } - return sym->memtype->alignsize(); + return t->alignsize(); } Dsymbol *TypeEnum::toDsymbol(Scope *sc) @@ -7379,30 +7480,14 @@ Dsymbol *TypeEnum::toDsymbol(Scope *sc) Type *TypeEnum::toBasetype() { - if (sym->scope) - { // Enum is forward referenced. We don't need to resolve the whole thing, - // just the base type - if (sym->memtype) - { sym->memtype = sym->memtype->semantic(sym->loc, sym->scope); - } - else - { if (!sym->isAnonymous()) - sym->memtype = Type::tint32; - } - } - if (!sym->memtype) - { - error(sym->loc, "enum %s is forward referenced", sym->toChars()); - return Type::terror; - } - return sym->memtype->toBasetype(); + return sym->getMemtype(Loc())->toBasetype(); } void TypeEnum::toDecoBuffer(OutBuffer *buf, int flag) { const char *name = sym->mangle(); Type::toDecoBuffer(buf, flag); - buf->printf("%s", name); + buf->writestring(name); } void TypeEnum::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) @@ -7431,7 +7516,7 @@ Expression *TypeEnum::dotExp(Scope *sc, Expression *e, Identifier *ident, int fl { return getProperty(e->loc, ident, flag); } - return sym->memtype->dotExp(sc, e, ident, flag); + return sym->getMemtype(Loc())->dotExp(sc, e, ident, flag); } EnumMember *m = s->isEnumMember(); return m->getVarExp(e->loc, sc); @@ -7440,17 +7525,9 @@ Expression *TypeEnum::dotExp(Scope *sc, Expression *e, Identifier *ident, int fl Expression *TypeEnum::getProperty(Loc loc, Identifier *ident, int flag) { Expression *e; - if (ident == Id::max) - { - if (!sym->maxval) - goto Lfwd; - e = sym->maxval; - } - else if (ident == Id::min) - { - if (!sym->minval) - goto Lfwd; - e = sym->minval; + if (ident == Id::max || ident == Id::min) + { + return sym->getMaxMinValue(loc, ident); } else if (ident == Id::init) { @@ -7471,10 +7548,6 @@ Expression *TypeEnum::getProperty(Loc loc, Identifier *ident, int flag) e = toBasetype()->getProperty(loc, ident, flag); } return e; - -Lfwd: - error(loc, "forward reference of %s.%s", toChars(), ident->toChars()); - return new ErrorExp(); } int TypeEnum::isintegral() @@ -7512,6 +7585,11 @@ int TypeEnum::isscalar() return sym->memtype->isscalar(); } +int TypeEnum::isString() +{ + return sym->memtype->isString(); +} + int TypeEnum::isAssignable() { return sym->memtype->isAssignable(); @@ -7562,30 +7640,15 @@ Expression *TypeEnum::defaultInit(Loc loc) printf("TypeEnum::defaultInit() '%s'\n", toChars()); #endif // Initialize to first member of enum - //printf("%s\n", sym->defaultval->type->toChars()); - if (!sym->defaultval) - { - error(loc, "forward reference of %s.init", toChars()); - return new ErrorExp(); - } - Expression *e = sym->defaultval; + Expression *e = sym->getDefaultValue(loc); e = e->copy(); - e->type = this; + e->type = this; // to deal with const, immutable, etc., variants return e; } int TypeEnum::isZeroInit(Loc loc) { - if (!sym->defaultval && sym->scope) - { // Enum is forward referenced. We need to resolve the whole thing. - sym->semantic(NULL); - } - if (!sym->defaultval) - { - error(loc, "enum %s is forward referenced", sym->toChars()); - return 0; - } - return sym->defaultval->isBool(FALSE); + return sym->getDefaultValue(loc)->isBool(FALSE); } int TypeEnum::hasPointers() @@ -7593,6 +7656,17 @@ int TypeEnum::hasPointers() return toBasetype()->hasPointers(); } +Type *TypeEnum::nextOf() +{ + if (sym->semanticRun == PASSinit) + { + assert(sym->scope); + sym->semantic(sym->scope); + } + assert(sym->memtype); + return sym->memtype->nextOf(); +} + /***************************** TypeTypedef *****************************/ TypeTypedef::TypeTypedef(TypedefDeclaration *sym) @@ -7645,7 +7719,7 @@ void TypeTypedef::toDecoBuffer(OutBuffer *buf, int flag) { Type::toDecoBuffer(buf, flag); const char *name = sym->mangle(); - buf->printf("%s", name); + buf->writestring(name); } void TypeTypedef::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) @@ -7837,7 +7911,13 @@ Expression *TypeTypedef::defaultInitLiteral(Loc loc) if (sym->init) { //sym->init->toExpression()->print(); - return sym->init->toExpression(); + Expression *e = sym->init->toExpression(); + if (!e) + { + error(loc, "void initializer has no value"); + e = new ErrorExp(); + } + return e; } Type *bt = sym->basetype; Expression *e = bt->defaultInitLiteral(loc); @@ -7947,7 +8027,7 @@ void TypeStruct::toDecoBuffer(OutBuffer *buf, int flag) const char *name = sym->mangle(); //printf("TypeStruct::toDecoBuffer('%s') = '%s'\n", toChars(), name); Type::toDecoBuffer(buf, flag); - buf->printf("%s", name); + buf->writestring(name); } void TypeStruct::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) @@ -7991,11 +8071,11 @@ Expression *TypeStruct::dotExp(Scope *sc, Expression *e, Identifier *ident, int exps->reserve(sym->fields.dim); Expression *e0 = NULL; - Expression *ev = e; - if (sc->func && e->hasSideEffect()) + Expression *ev = e->op == TOKtype ? NULL : e; + if (sc->func && ev && ev->hasSideEffect()) { Identifier *id = Lexer::uniqueId("__tup"); - ExpInitializer *ei = new ExpInitializer(e->loc, e); + ExpInitializer *ei = new ExpInitializer(e->loc, ev); VarDeclaration *vd = new VarDeclaration(e->loc, NULL, id, ei); vd->storage_class |= STCctfe | STCref | STCforeach; @@ -8005,13 +8085,21 @@ Expression *TypeStruct::dotExp(Scope *sc, Expression *e, Identifier *ident, int for (size_t i = 0; i < sym->fields.dim; i++) { VarDeclaration *v = sym->fields[i]; - exps->push(new DotVarExp(ev->loc, ev, v)); + Expression *ex; + if (ev) + ex = new DotVarExp(e->loc, ev, v); + else + { + ex = new VarExp(e->loc, v); + ex->type = ex->type->addMod(e->type->mod); + } + exps->push(ex); } e = new TupleExp(e->loc, e0, exps); - sc = sc->push(); - sc->noaccesscheck = 1; - e = e->semantic(sc); - sc->pop(); + Scope *sc2 = sc->push(); + sc2->flags = sc->flags | SCOPEnoaccesscheck; + e = e->semantic(sc2); + sc2->pop(); return e; } @@ -8237,7 +8325,10 @@ Expression *TypeStruct::defaultInitLiteral(Loc loc) } else e = vd->type->defaultInitLiteral(loc); - offset = vd->offset + vd->type->size(); + if (e && e->op == TOKerror) + return e; + if (e) + offset = vd->offset + vd->type->size(); (*structelems)[j] = e; } StructLiteralExp *structinit = new StructLiteralExp(loc, (StructDeclaration *)sym, structelems); @@ -8354,26 +8445,40 @@ MATCH TypeStruct::implicitConvTo(Type *to) } if (ty == to->ty && sym == ((TypeStruct *)to)->sym) - { m = MATCHexact; // exact match + { + m = MATCHexact; // exact match if (mod != to->mod) { m = MATCHconst; if (MODimplicitConv(mod, to->mod)) ; else - { /* Check all the fields. If they can all be converted, + { + /* Check all the fields. If they can all be converted, * allow the conversion. */ + unsigned offset; for (size_t i = 0; i < sym->fields.dim; i++) - { Dsymbol *s = sym->fields[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v && v->isField()); + { + VarDeclaration *v = sym->fields[i]; + if (i == 0) + ; + else if (v->offset == offset) + { + if (m) + continue; + } + else + { + if (!m) + return m; + } // 'from' type Type *tvf = v->type->addMod(mod); // 'to' type - Type *tv = v->type->castMod(to->mod); + Type *tv = v->type->addMod(to->mod); // field match MATCH mf = tvf->implicitConvTo(tv); @@ -8383,6 +8488,7 @@ MATCH TypeStruct::implicitConvTo(Type *to) return mf; if (mf < m) // if field match is worse m = mf; + offset = v->offset; } } } @@ -8481,7 +8587,7 @@ void TypeClass::toDecoBuffer(OutBuffer *buf, int flag) const char *name = sym->mangle(); //printf("TypeClass::toDecoBuffer('%s' flag=%d mod=%x) = '%s'\n", toChars(), flag, mod, name); Type::toDecoBuffer(buf, flag); - buf->printf("%s", name); + buf->writestring(name); } void TypeClass::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) @@ -8536,11 +8642,11 @@ Expression *TypeClass::dotExp(Scope *sc, Expression *e, Identifier *ident, int f exps->reserve(sym->fields.dim); Expression *e0 = NULL; - Expression *ev = e; - if (sc->func && e->hasSideEffect()) + Expression *ev = e->op == TOKtype ? NULL : e; + if (sc->func && ev && ev->hasSideEffect()) { Identifier *id = Lexer::uniqueId("__tup"); - ExpInitializer *ei = new ExpInitializer(e->loc, e); + ExpInitializer *ei = new ExpInitializer(e->loc, ev); VarDeclaration *vd = new VarDeclaration(e->loc, NULL, id, ei); vd->storage_class |= STCctfe | STCref | STCforeach; @@ -8548,17 +8654,26 @@ Expression *TypeClass::dotExp(Scope *sc, Expression *e, Identifier *ident, int f ev = new VarExp(e->loc, vd); } for (size_t i = 0; i < sym->fields.dim; i++) - { VarDeclaration *v = sym->fields[i]; + { + VarDeclaration *v = sym->fields[i]; // Don't include hidden 'this' pointer if (v->isThisDeclaration()) continue; - exps->push(new DotVarExp(ev->loc, ev, v)); + Expression *ex; + if (ev) + ex = new DotVarExp(e->loc, ev, v); + else + { + ex = new VarExp(e->loc, v); + ex->type = ex->type->addMod(e->type->mod); + } + exps->push(ex); } e = new TupleExp(e->loc, e0, exps); - sc = sc->push(); - sc->noaccesscheck = 1; - e = e->semantic(sc); - sc->pop(); + Scope *sc2 = sc->push(); + sc2->flags = sc->flags | SCOPEnoaccesscheck; + e = e->semantic(sc2); + sc2->pop(); return e; } @@ -8586,8 +8701,8 @@ L1: if (ident == Id::classinfo) { - assert(ClassDeclaration::classinfo); - Type *t = ClassDeclaration::classinfo->type; + assert(Type::typeinfoclass); + Type *t = Type::typeinfoclass->type; if (e->op == TOKtype || e->op == TOKdottype) { /* For type.classinfo, we know the classinfo @@ -8633,7 +8748,7 @@ L1: { /* The pointer to the vtbl[] * *cast(invariant(void*)**)e */ - e = e->castTo(sc, tvoidptr->invariantOf()->pointerTo()->pointerTo()); + e = e->castTo(sc, tvoidptr->immutableOf()->pointerTo()->pointerTo()); e = new PtrExp(e->loc, e); e = e->semantic(sc); return e; @@ -8754,6 +8869,12 @@ L1: /* It's: * Class.d */ + + // If Class is in a failed template, return an error + TemplateInstance *tiparent = d->inTemplateInstance(); + if (tiparent && tiparent->errors) + return new ErrorExp(); + if (TupleDeclaration *tup = d->isTupleDeclaration()) { e = new TupleExp(e->loc, tup); @@ -8890,19 +9011,14 @@ MATCH TypeClass::implicitConvTo(Type *to) { if (cdto->scope) cdto->semantic(NULL); + if (sym->scope) + sym->semantic(NULL); if (cdto->isBaseOf(sym, NULL) && MODimplicitConv(mod, to->mod)) { //printf("'to' is base\n"); return MATCHconvert; } } - if (global.params.Dversion == 1) - { - // Allow conversion to (void *) - if (to->ty == Tpointer && ((TypePointer *)to)->next->ty == Tvoid) - return MATCHconvert; - } - m = MATCHnomatch; if (sym->aliasthis && !(att & RECtracing)) { @@ -9076,31 +9192,28 @@ Type *TypeTuple::semantic(Loc loc, Scope *sc) return this; } -int TypeTuple::equals(Object *o) -{ Type *t; - - t = (Type *)o; +bool TypeTuple::equals(RootObject *o) +{ + Type *t = (Type *)o; //printf("TypeTuple::equals(%s, %s)\n", toChars(), t->toChars()); if (this == t) - { - return 1; - } + return true; if (t->ty == Ttuple) - { TypeTuple *tt = (TypeTuple *)t; - + { + TypeTuple *tt = (TypeTuple *)t; if (arguments->dim == tt->arguments->dim) { for (size_t i = 0; i < tt->arguments->dim; i++) - { Parameter *arg1 = (*arguments)[i]; + { + Parameter *arg1 = (*arguments)[i]; Parameter *arg2 = (*tt->arguments)[i]; - if (!arg1->type->equals(arg2->type)) - return 0; + return false; } - return 1; + return true; } } - return 0; + return false; } Type *TypeTuple::reliesOnTident(TemplateParameters *tparams) @@ -9146,6 +9259,7 @@ void TypeTuple::toDecoBuffer(OutBuffer *buf, int flag) //printf("TypeTuple::toDecoBuffer() this = %p, %s\n", this, toChars()); Type::toDecoBuffer(buf, flag); OutBuffer buf2; + buf2.reserve(32); Parameter::argsToDecoBuffer(&buf2, arguments); int len = (int)buf2.offset; buf->printf("%d%.*s", len, len, (char *)buf2.extractData()); @@ -9255,17 +9369,19 @@ Type *TypeSlice::semantic(Loc loc, Scope *sc) return t; } -void TypeSlice::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps) +void TypeSlice::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid) { - next->resolve(loc, sc, pe, pt, ps); + next->resolve(loc, sc, pe, pt, ps, intypeid); if (*pe) - { // It's really a slice expression + { + // It's really a slice expression if (Dsymbol *s = getDsymbol(*pe)) *pe = new DsymbolExp(loc, s, 1); *pe = new SliceExp(loc, *pe, lwr, upr); } else if (*ps) - { Dsymbol *s = *ps; + { + Dsymbol *s = *ps; TupleDeclaration *td = s->isTupleDeclaration(); if (td) { @@ -9274,19 +9390,20 @@ void TypeSlice::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol ScopeDsymbol *sym = new ArrayScopeSymbol(sc, td); sym->parent = sc->scopesym; sc = sc->push(sym); - - lwr = lwr->ctfeSemantic(sc); - lwr = lwr->ctfeInterpret(); - uinteger_t i1 = lwr->toUInteger(); - - upr = upr->ctfeSemantic(sc); - upr = upr->ctfeInterpret(); - uinteger_t i2 = upr->toUInteger(); - + sc = sc->startCTFE(); + lwr = lwr->semantic(sc); + upr = upr->semantic(sc); + sc = sc->endCTFE(); sc = sc->pop(); + lwr = lwr->ctfeInterpret(); + upr = upr->ctfeInterpret(); + uinteger_t i1 = lwr->toUInteger(); + uinteger_t i2 = upr->toUInteger(); + if (!(i1 <= i2 && i2 <= td->objects->dim)) - { error(loc, "slice [%llu..%llu] is out of range of [0..%u]", i1, i2, td->objects->dim); + { + error(loc, "slice [%llu..%llu] is out of range of [0..%u]", i1, i2, td->objects->dim); goto Ldefault; } @@ -9315,7 +9432,7 @@ void TypeSlice::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol else { Ldefault: - Type::resolve(loc, sc, pe, pt, ps); + Type::resolve(loc, sc, pe, pt, ps, intypeid); } } @@ -9327,8 +9444,11 @@ void TypeSlice::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) } next->toCBuffer2(buf, hgs, this->mod); - buf->printf("[%s .. ", lwr->toChars()); - buf->printf("%s]", upr->toChars()); + buf->writeByte('['); + sizeToCBuffer(buf, hgs, lwr); + buf->writestring(" .. "); + sizeToCBuffer(buf, hgs, upr); + buf->writeByte(']'); } /***************************** TypeNull *****************************/ @@ -9428,12 +9548,14 @@ Parameters *Parameter::arraySyntaxCopy(Parameters *args) char *Parameter::argsTypesToChars(Parameters *args, int varargs) { - OutBuffer *buf = new OutBuffer(); + OutBuffer buf; + buf.reserve(16); HdrGenState hgs; - argsToCBuffer(buf, &hgs, args, varargs); + argsToCBuffer(&buf, &hgs, args, varargs); - return buf->toChars(); + buf.writebyte(0); + return buf.extractData(); } void Parameter::argsToCBuffer(OutBuffer *buf, HdrGenState *hgs, Parameters *arguments, int varargs) @@ -9442,6 +9564,7 @@ void Parameter::argsToCBuffer(OutBuffer *buf, HdrGenState *hgs, Parameters *argu if (arguments) { OutBuffer argbuf; + argbuf.reserve(32); size_t dim = Parameter::dim(arguments); for (size_t i = 0; i < dim; i++) @@ -9456,8 +9579,7 @@ void Parameter::argsToCBuffer(OutBuffer *buf, HdrGenState *hgs, Parameters *argu if (arg->storageClass & STCout) buf->writestring("out "); else if (arg->storageClass & STCref) - buf->writestring((global.params.Dversion == 1) - ? "inout " : "ref "); + buf->writestring("ref "); else if (arg->storageClass & STCin) buf->writestring("in "); else if (arg->storageClass & STClazy) diff --git a/dmd2/mtype.h b/dmd2/mtype.h index 7aa4075f..d4f81bc4 100644 --- a/dmd2/mtype.h +++ b/dmd2/mtype.h @@ -28,29 +28,28 @@ class IrType; #endif struct Scope; -struct Identifier; -struct Expression; -struct StructDeclaration; -struct ClassDeclaration; -struct VarDeclaration; -struct EnumDeclaration; -struct TypedefDeclaration; -struct TypeInfoDeclaration; -struct Dsymbol; -struct TemplateInstance; +class Identifier; +class Expression; +class StructDeclaration; +class ClassDeclaration; +class VarDeclaration; +class EnumDeclaration; +class TypedefDeclaration; +class TypeInfoDeclaration; +class Dsymbol; +class TemplateInstance; struct CppMangleState; -struct TemplateDeclaration; +class TemplateDeclaration; struct JsonOut; enum LINK; -struct TypeBasic; +class TypeBasic; struct HdrGenState; -struct Parameter; +class Parameter; // Back end #ifdef IN_GCC -union tree_node; typedef union tree_node TYPE; -typedef TYPE type; +typedef union tree_node type; #elif IN_LLVM #else typedef struct TYPE type; @@ -60,7 +59,7 @@ typedef struct TYPE type; struct Symbol; #endif -struct TypeTuple; +class TypeTuple; enum ENUMTY { @@ -131,13 +130,14 @@ extern int Tptrdiff_t; #define MODwild 8 // type is wild #define MODmutable 0x10 // type is mutable (only used in wildcard matching) -struct Type : Object +class Type : public RootObject { +public: TY ty; unsigned char mod; // modifiers MODxxxx char *deco; - /* These are cached values that are lazily evaluated by constOf(), invariantOf(), etc. + /* These are cached values that are lazily evaluated by constOf(), immutableOf(), etc. * They should not be referenced by anybody but mtype.c. * They can be NULL if not lazily evaluated yet. * Note that there is no "shared immutable", because that is just immutable @@ -202,7 +202,7 @@ struct Type : Object static Type *thash_t; // matches hash_t alias static Type *tindex; // array/ptr index - static ClassDeclaration *typeinfo; + static ClassDeclaration *dtypeinfo; static ClassDeclaration *typeinfoclass; static ClassDeclaration *typeinfointerface; static ClassDeclaration *typeinfostruct; @@ -240,8 +240,9 @@ struct Type : Object Type(TY ty); virtual const char *kind(); + Type *copy(); virtual Type *syntaxCopy(); - int equals(Object *o); + bool equals(RootObject *o); int dyncast() { return DYNCAST_TYPE; } // kludge for template.isType() int covariant(Type *t, StorageClass *pstc = NULL); char *toChars(); @@ -288,7 +289,7 @@ struct Type : Object int isNaked() { return mod == 0; } Type *nullAttributes(); Type *constOf(); - Type *invariantOf(); + Type *immutableOf(); Type *mutableOf(); Type *sharedOf(); Type *sharedConstOf(); @@ -319,7 +320,7 @@ struct Type : Object virtual MATCH implicitConvTo(Type *to); virtual MATCH constConv(Type *to); virtual unsigned wildConvTo(Type *tprm); - Type *substWildTo(unsigned mod); + virtual Type *substWildTo(unsigned mod); virtual Type *toHeadMutable(); virtual ClassDeclaration *isClassHandle(); virtual Expression *getProperty(Loc loc, Identifier *ident, int flag); @@ -335,7 +336,7 @@ struct Type : Object #endif Identifier *getTypeInfoIdent(int internal); virtual MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch = NULL); - virtual void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); + virtual void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false); Expression *getInternalTypeInfo(Scope *sc); Expression *getTypeInfo(Scope *sc); virtual TypeInfoDeclaration *getTypeInfoDeclaration(); @@ -346,6 +347,7 @@ struct Type : Object virtual int hasPointers(); virtual TypeTuple *toArgTypes(); virtual Type *nextOf(); + Type *baseElemOf(); uinteger_t sizemask(); virtual int needsDestruction(); virtual bool needsNested(); @@ -370,8 +372,9 @@ struct Type : Object #endif }; -struct TypeError : Type +class TypeError : public Type { +public: TypeError(); Type *syntaxCopy(); @@ -385,8 +388,9 @@ struct TypeError : Type TypeTuple *toArgTypes(); }; -struct TypeNext : Type +class TypeNext : public Type { +public: Type *next; TypeNext(TY ty, Type *next); @@ -407,8 +411,9 @@ struct TypeNext : Type void transitive(); }; -struct TypeBasic : Type +class TypeBasic : public Type { +public: const char *dstring; unsigned flags; @@ -444,8 +449,9 @@ struct TypeBasic : Type TypeBasic *isTypeBasic(); }; -struct TypeVector : Type +class TypeVector : public Type { +public: Type *basetype; TypeVector(Loc loc, Type *basetype); @@ -461,6 +467,7 @@ struct TypeVector : Type void toDecoBuffer(OutBuffer *buf, int flag); void toJson(JsonOut *json); MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch = NULL); + Type *reliesOnTident(TemplateParameters *tparams); #if CPP_MANGLE void toCppMangle(OutBuffer *buf, CppMangleState *cms); #endif @@ -471,9 +478,7 @@ struct TypeVector : Type int checkBoolean(); MATCH implicitConvTo(Type *to); Expression *defaultInit(Loc loc); -#if IN_LLVM Expression *defaultInitLiteral(Loc loc); -#endif TypeBasic *elementType(); int isZeroInit(Loc loc); TypeInfoDeclaration *getTypeInfoDeclaration(); @@ -484,15 +489,17 @@ struct TypeVector : Type #endif }; -struct TypeArray : TypeNext +class TypeArray : public TypeNext { +public: TypeArray(TY ty, Type *next); Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag); }; // Static array, one with a fixed dimension -struct TypeSArray : TypeArray +class TypeSArray : public TypeArray { +public: Expression *dim; TypeSArray(Type *t, Expression *dim); @@ -501,7 +508,7 @@ struct TypeSArray : TypeArray d_uns64 size(Loc loc); unsigned alignsize(); Type *semantic(Loc loc, Scope *sc); - void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); + void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false); void toDecoBuffer(OutBuffer *buf, int flag); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); void toJson(JsonOut *json); @@ -529,6 +536,8 @@ struct TypeSArray : TypeArray void toCppMangle(OutBuffer *buf, CppMangleState *cms); #endif + static Type *makeType(Loc loc, Type *tn, dinteger_t dim); + #if IN_DMD type *toCtype(); type *toCParamtype(); @@ -536,15 +545,16 @@ struct TypeSArray : TypeArray }; // Dynamic array, no dimension -struct TypeDArray : TypeArray +class TypeDArray : public TypeArray { +public: TypeDArray(Type *t); const char *kind(); Type *syntaxCopy(); d_uns64 size(Loc loc); unsigned alignsize(); Type *semantic(Loc loc, Scope *sc); - void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); + void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false); void toDecoBuffer(OutBuffer *buf, int flag); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); void toJson(JsonOut *json); @@ -568,8 +578,9 @@ struct TypeDArray : TypeArray #endif }; -struct TypeAArray : TypeArray +class TypeAArray : public TypeArray { +public: Type *index; // key type Loc loc; Scope *sc; @@ -582,7 +593,7 @@ struct TypeAArray : TypeArray d_uns64 size(Loc loc); Type *semantic(Loc loc, Scope *sc); StructDeclaration *getImpl(); - void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); + void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false); void toDecoBuffer(OutBuffer *buf, int flag); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); void toJson(JsonOut *json); @@ -610,8 +621,9 @@ struct TypeAArray : TypeArray #endif }; -struct TypePointer : TypeNext +class TypePointer : public TypeNext { +public: TypePointer(Type *t); const char *kind(); Type *syntaxCopy(); @@ -636,8 +648,9 @@ struct TypePointer : TypeNext #endif }; -struct TypeReference : TypeNext +class TypeReference : public TypeNext { +public: TypeReference(Type *t); const char *kind(); Type *syntaxCopy(); @@ -676,8 +689,9 @@ enum PURE PUREfwdref = 4, // it's pure, but not known which level yet }; -struct TypeFunction : TypeNext +class TypeFunction : public TypeNext { +public: // .next is the return type Parameters *parameters; // function parameters @@ -686,17 +700,16 @@ struct TypeFunction : TypeNext bool isnothrow; // true: nothrow bool isproperty; // can be called without parentheses bool isref; // true: returns a reference - enum LINK linkage; // calling convention - enum TRUST trust; // level of trust - enum PURE purity; // PURExxxx + LINK linkage; // calling convention + TRUST trust; // level of trust + PURE purity; // PURExxxx bool iswild; // is inout function Expressions *fargs; // function arguments int inuse; - TypeFunction(Parameters *parameters, Type *treturn, int varargs, enum LINK linkage, StorageClass stc = 0); + TypeFunction(Parameters *parameters, Type *treturn, int varargs, LINK linkage, StorageClass stc = 0); const char *kind(); - TypeFunction *copy(); Type *syntaxCopy(); Type *semantic(Loc loc, Scope *sc); void purityLevel(); @@ -716,12 +729,13 @@ struct TypeFunction : TypeNext bool parameterEscapes(Parameter *p); Type *addStorageClass(StorageClass stc); + Type *substWildTo(unsigned mod); MATCH callMatch(Type *tthis, Expressions *toargs, int flag = 0); #if IN_DMD type *toCtype(); #endif - enum RET retStyle(); + RET retStyle(); #if IN_DMD unsigned totym(); @@ -734,8 +748,9 @@ struct TypeFunction : TypeNext #endif }; -struct TypeDelegate : TypeNext +class TypeDelegate : public TypeNext { +public: // .next is a TypeFunction TypeDelegate(Type *t); @@ -767,8 +782,9 @@ struct TypeDelegate : TypeNext #endif }; -struct TypeQualified : Type +class TypeQualified : public Type { +public: Loc loc; Objects idents; // array of Identifier and TypeInstance, // representing ident.ident!tiargs.ident. ... etc. @@ -781,11 +797,12 @@ struct TypeQualified : Type void toJson(JsonOut *json); d_uns64 size(Loc loc); void resolveHelper(Loc loc, Scope *sc, Dsymbol *s, Dsymbol *scopesym, - Expression **pe, Type **pt, Dsymbol **ps); + Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false); }; -struct TypeIdentifier : TypeQualified +class TypeIdentifier : public TypeQualified { +public: Identifier *ident; Dsymbol *originalSymbol; // The symbol representing this identifier, before alias resolution @@ -796,7 +813,7 @@ struct TypeIdentifier : TypeQualified void toDecoBuffer(OutBuffer *buf, int flag); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); void toJson(JsonOut *json); - void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); + void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false); Dsymbol *toDsymbol(Scope *sc); Type *semantic(Loc loc, Scope *sc); MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch = NULL); @@ -806,8 +823,9 @@ struct TypeIdentifier : TypeQualified /* Similar to TypeIdentifier, but with a TemplateInstance as the root */ -struct TypeInstance : TypeQualified +class TypeInstance : public TypeQualified { +public: TemplateInstance *tempinst; TypeInstance(Loc loc, TemplateInstance *tempinst); @@ -817,7 +835,7 @@ struct TypeInstance : TypeQualified //void toDecoBuffer(OutBuffer *buf, int flag); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); void toJson(JsonOut *json); - void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); + void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false); Type *semantic(Loc loc, Scope *sc); Dsymbol *toDsymbol(Scope *sc); Type *reliesOnTident(TemplateParameters *tparams = NULL); @@ -825,8 +843,9 @@ struct TypeInstance : TypeQualified Expression *toExpression(); }; -struct TypeTypeof : TypeQualified +class TypeTypeof : public TypeQualified { +public: Expression *exp; int inuse; @@ -836,18 +855,19 @@ struct TypeTypeof : TypeQualified Dsymbol *toDsymbol(Scope *sc); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); void toJson(JsonOut *json); - void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); + void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false); Type *semantic(Loc loc, Scope *sc); d_uns64 size(Loc loc); }; -struct TypeReturn : TypeQualified +class TypeReturn : public TypeQualified { +public: TypeReturn(Loc loc); const char *kind(); Type *syntaxCopy(); Dsymbol *toDsymbol(Scope *sc); - void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); + void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false); Type *semantic(Loc loc, Scope *sc); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); void toJson(JsonOut *json); @@ -863,10 +883,11 @@ enum AliasThisRec RECtracing = 0x4, // mark in progress of implicitConvTo/wildConvTo }; -struct TypeStruct : Type +class TypeStruct : public Type { +public: StructDeclaration *sym; - enum AliasThisRec att; + AliasThisRec att; TypeStruct(StructDeclaration *sym); const char *kind(); @@ -914,8 +935,9 @@ struct TypeStruct : Type #endif }; -struct TypeEnum : Type +class TypeEnum : public Type { +public: EnumDeclaration *sym; TypeEnum(EnumDeclaration *sym); @@ -939,6 +961,7 @@ struct TypeEnum : Type int isscalar(); int isunsigned(); int checkBoolean(); + int isString(); int isAssignable(); int needsDestruction(); bool needsNested(); @@ -951,6 +974,7 @@ struct TypeEnum : Type TypeInfoDeclaration *getTypeInfoDeclaration(); int hasPointers(); TypeTuple *toArgTypes(); + Type *nextOf(); #if CPP_MANGLE void toCppMangle(OutBuffer *buf, CppMangleState *cms); #endif @@ -960,8 +984,9 @@ struct TypeEnum : Type #endif }; -struct TypeTypedef : Type +class TypeTypedef : public Type { +public: TypedefDeclaration *sym; TypeTypedef(TypedefDeclaration *sym); @@ -1014,10 +1039,11 @@ struct TypeTypedef : Type #endif }; -struct TypeClass : Type +class TypeClass : public Type { +public: ClassDeclaration *sym; - enum AliasThisRec att; + AliasThisRec att; TypeClass(ClassDeclaration *sym); const char *kind(); @@ -1056,8 +1082,9 @@ struct TypeClass : Type #endif }; -struct TypeTuple : Type +class TypeTuple : public Type { +public: Parameters *arguments; // types making up the tuple TypeTuple(Parameters *arguments); @@ -1068,7 +1095,7 @@ struct TypeTuple : Type const char *kind(); Type *syntaxCopy(); Type *semantic(Loc loc, Scope *sc); - int equals(Object *o); + bool equals(RootObject *o); Type *reliesOnTident(TemplateParameters *tparams = NULL); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); void toDecoBuffer(OutBuffer *buf, int flag); @@ -1078,8 +1105,9 @@ struct TypeTuple : Type TypeInfoDeclaration *getTypeInfoDeclaration(); }; -struct TypeSlice : TypeNext +class TypeSlice : public TypeNext { +public: Expression *lwr; Expression *upr; @@ -1087,13 +1115,14 @@ struct TypeSlice : TypeNext const char *kind(); Type *syntaxCopy(); Type *semantic(Loc loc, Scope *sc); - void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); + void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); void toJson(JsonOut *json); }; -struct TypeNull : Type +class TypeNull : public Type { +public: TypeNull(); const char *kind(); @@ -1113,8 +1142,9 @@ struct TypeNull : Type //enum InOut { None, In, Out, InOut, Lazy }; -struct Parameter : Object +class Parameter : public RootObject { +public: //enum InOut inout; StorageClass storageClass; Type *type; diff --git a/dmd2/opover.c b/dmd2/opover.c index a4ddc520..87f36a53 100644 --- a/dmd2/opover.c +++ b/dmd2/opover.c @@ -39,7 +39,6 @@ static Dsymbol *inferApplyArgTypesX(Expression *ethis, FuncDeclaration *fstart, Parameters *arguments); static void inferApplyArgTypesZ(TemplateDeclaration *tstart, Parameters *arguments); static int inferApplyArgTypesY(TypeFunction *tf, Parameters *arguments, int flags = 0); -static void templateResolve(Match *m, TemplateDeclaration *td, Loc loc, Scope *sc, Objects *tiargs, Expression *ethis, Expressions *arguments); /******************************** Expression **************************/ @@ -182,7 +181,7 @@ AggregateDeclaration *isAggregate(Type *t) /******************************************* * Helper function to turn operator into template argument list */ -Objects *opToArg(Scope *sc, enum TOK op) +Objects *opToArg(Scope *sc, TOK op) { /* Remove the = from op= */ @@ -236,10 +235,11 @@ Expression *UnaExp::op_overload(Scope *sc) Dsymbol *fd = search_function(ad, Id::opIndexUnary); if (fd) { - ae = resolveOpDollar(sc, ae); + Expression *e0 = resolveOpDollar(sc, ae); Objects *tiargs = opToArg(sc, op); Expression *e = new DotTemplateInstanceExp(loc, ae->e1, fd->ident, tiargs); e = new CallExp(loc, e, ae->arguments); + e = combine(e0, e); e = e->semantic(sc); return e; } @@ -277,16 +277,18 @@ Expression *UnaExp::op_overload(Scope *sc) Dsymbol *fd = search_function(ad, Id::opSliceUnary); if (fd) { - se = resolveOpDollar(sc, se); + Expression *e0 = resolveOpDollar(sc, se); Expressions *a = new Expressions(); assert(!se->lwr || se->upr); if (se->lwr) - { a->push(se->lwr); + { + a->push(se->lwr); a->push(se->upr); } Objects *tiargs = opToArg(sc, op); Expression *e = new DotTemplateInstanceExp(loc, se->e1, fd->ident, tiargs); e = new CallExp(loc, e, a); + e = combine(e0, e); e = e->semantic(sc); return e; } @@ -388,9 +390,10 @@ Expression *ArrayExp::op_overload(Scope *sc) /* Rewrite op e1[arguments] as: * e1.opIndex(arguments) */ - ArrayExp *ae = resolveOpDollar(sc, this); - Expression *e = new DotIdExp(loc, ae->e1, fd->ident); - e = new CallExp(loc, e, ae->arguments); + Expression *e0 = resolveOpDollar(sc, this); + Expression *e = new DotIdExp(loc, e1, fd->ident); + e = new CallExp(loc, e, arguments); + e = combine(e0, e); e = e->semantic(sc); return e; } @@ -546,8 +549,10 @@ Expression *BinExp::op_overload(Scope *sc) args1.setDim(1); args1[0] = e1; + expandTuples(&args1); args2.setDim(1); args2[0] = e2; + expandTuples(&args2); argsset = 1; Match m; @@ -555,32 +560,12 @@ Expression *BinExp::op_overload(Scope *sc) m.last = MATCHnomatch; if (s) - { - FuncDeclaration *fd = s->isFuncDeclaration(); - if (fd) - { - overloadResolveX(&m, fd, NULL, &args2); - } - else - { TemplateDeclaration *td = s->isTemplateDeclaration(); - templateResolve(&m, td, loc, sc, tiargs, e1, &args2); - } - } + functionResolve(&m, s, loc, sc, tiargs, e1->type, &args2); FuncDeclaration *lastf = m.lastf; if (s_r) - { - FuncDeclaration *fd = s_r->isFuncDeclaration(); - if (fd) - { - overloadResolveX(&m, fd, NULL, &args1); - } - else - { TemplateDeclaration *td = s_r->isTemplateDeclaration(); - templateResolve(&m, td, loc, sc, tiargs, e2, &args1); - } - } + functionResolve(&m, s_r, loc, sc, tiargs, e2->type, &args1); if (m.count > 1) { @@ -637,10 +622,13 @@ L1: */ if (!argsset) - { args1.setDim(1); + { + args1.setDim(1); args1[0] = e1; + expandTuples(&args1); args2.setDim(1); args2[0] = e2; + expandTuples(&args2); } Match m; @@ -648,31 +636,12 @@ L1: m.last = MATCHnomatch; if (s_r) - { - FuncDeclaration *fd = s_r->isFuncDeclaration(); - if (fd) - { - overloadResolveX(&m, fd, NULL, &args2); - } - else - { TemplateDeclaration *td = s_r->isTemplateDeclaration(); - templateResolve(&m, td, loc, sc, tiargs, e1, &args2); - } - } + functionResolve(&m, s_r, loc, sc, tiargs, e1->type, &args2); + FuncDeclaration *lastf = m.lastf; if (s) - { - FuncDeclaration *fd = s->isFuncDeclaration(); - if (fd) - { - overloadResolveX(&m, fd, NULL, &args1); - } - else - { TemplateDeclaration *td = s->isTemplateDeclaration(); - templateResolve(&m, td, loc, sc, tiargs, e2, &args1); - } - } + functionResolve(&m, s, loc, sc, tiargs, e2->type, &args1); if (m.count > 1) { @@ -805,8 +774,10 @@ Expression *BinExp::compare_overload(Scope *sc, Identifier *id) args1.setDim(1); args1[0] = e1; + expandTuples(&args1); args2.setDim(1); args2[0] = e2; + expandTuples(&args2); Match m; memset(&m, 0, sizeof(m)); @@ -819,33 +790,13 @@ Expression *BinExp::compare_overload(Scope *sc, Identifier *id) } if (s) - { - FuncDeclaration *fd = s->isFuncDeclaration(); - if (fd) - { - overloadResolveX(&m, fd, NULL, &args2); - } - else - { TemplateDeclaration *td = s->isTemplateDeclaration(); - templateResolve(&m, td, loc, sc, tiargs, e1, &args2); - } - } + functionResolve(&m, s, loc, sc, tiargs, e1->type, &args2); FuncDeclaration *lastf = m.lastf; int count = m.count; if (s_r) - { - FuncDeclaration *fd = s_r->isFuncDeclaration(); - if (fd) - { - overloadResolveX(&m, fd, NULL, &args1); - } - else - { TemplateDeclaration *td = s_r->isTemplateDeclaration(); - templateResolve(&m, td, loc, sc, tiargs, e2, &args1); - } - } + functionResolve(&m, s_r, loc, sc, tiargs, e2->type, &args1); if (m.count > 1) { @@ -953,7 +904,7 @@ Expression *EqualExp::op_overload(Scope *sc) { ClassDeclaration *cd1 = t1->isClassHandle(); ClassDeclaration *cd2 = t2->isClassHandle(); - if (!(cd1->isCPPinterface() || cd2->isCPPinterface())) + if (!(cd1->cpp || cd2->cpp)) { /* Rewrite as: * .object.opEquals(e1, e2) @@ -1013,13 +964,14 @@ Expression *BinAssignExp::op_overload(Scope *sc) Dsymbol *fd = search_function(ad, Id::opIndexOpAssign); if (fd) { - ae = resolveOpDollar(sc, ae); + Expression *e0 = resolveOpDollar(sc, ae); Expressions *a = (Expressions *)ae->arguments->copy(); a->insert(0, e2); Objects *tiargs = opToArg(sc, op); Expression *e = new DotTemplateInstanceExp(loc, ae->e1, fd->ident, tiargs); e = new CallExp(loc, e, a); + e = combine(e0, e); e = e->semantic(sc); return e; } @@ -1057,18 +1009,20 @@ Expression *BinAssignExp::op_overload(Scope *sc) Dsymbol *fd = search_function(ad, Id::opSliceOpAssign); if (fd) { - se = resolveOpDollar(sc, se); + Expression *e0 = resolveOpDollar(sc, se); Expressions *a = new Expressions(); a->push(e2); assert(!se->lwr || se->upr); if (se->lwr) - { a->push(se->lwr); + { + a->push(se->lwr); a->push(se->upr); } Objects *tiargs = opToArg(sc, op); Expression *e = new DotTemplateInstanceExp(loc, se->e1, fd->ident, tiargs); e = new CallExp(loc, e, a); + e = combine(e0, e); e = e->semantic(sc); return e; } @@ -1147,23 +1101,14 @@ Expression *BinAssignExp::op_overload(Scope *sc) args2.setDim(1); args2[0] = e2; + expandTuples(&args2); Match m; memset(&m, 0, sizeof(m)); m.last = MATCHnomatch; if (s) - { - FuncDeclaration *fd = s->isFuncDeclaration(); - if (fd) - { - overloadResolveX(&m, fd, NULL, &args2); - } - else - { TemplateDeclaration *td = s->isTemplateDeclaration(); - templateResolve(&m, td, loc, sc, tiargs, e1, &args2); - } - } + functionResolve(&m, s, loc, sc, tiargs, e1->type, &args2); if (m.count > 1) { @@ -1540,47 +1485,51 @@ int ForeachStatement::inferApplyArgTypes(Scope *sc, Dsymbol *&sapply) static Dsymbol *inferApplyArgTypesX(Expression *ethis, FuncDeclaration *fstart, Parameters *arguments) { - struct Param3 + struct ParamOpOver + { + Parameters *arguments; + int mod; + MATCH match; + FuncDeclaration *fd_best; + FuncDeclaration *fd_ambig; + + static int fp(void *param, Dsymbol *s) { - Parameters *arguments; - int mod; - MATCH match; - FuncDeclaration *fd_best; - FuncDeclaration *fd_ambig; - - static int fp(void *param, FuncDeclaration *f) - { - Param3 *p = (Param3 *)param; - TypeFunction *tf = (TypeFunction *)f->type; - MATCH m = MATCHexact; - - if (f->isThis()) - { if (!MODimplicitConv(p->mod, tf->mod)) - m = MATCHnomatch; - else if (p->mod != tf->mod) - m = MATCHconst; - } - if (!inferApplyArgTypesY(tf, p->arguments, 1)) - m = MATCHnomatch; - - if (m > p->match) - { p->fd_best = f; - p->fd_ambig = NULL; - p->match = m; - } - else if (m == p->match) - p->fd_ambig = f; + FuncDeclaration *f = s->isFuncDeclaration(); + if (!f) return 0; - } - }; + ParamOpOver *p = (ParamOpOver *)param; + TypeFunction *tf = (TypeFunction *)f->type; + MATCH m = MATCHexact; - Param3 p; + if (f->isThis()) + { + if (!MODimplicitConv(p->mod, tf->mod)) + m = MATCHnomatch; + else if (p->mod != tf->mod) + m = MATCHconst; + } + if (!inferApplyArgTypesY(tf, p->arguments, 1)) + m = MATCHnomatch; + + if (m > p->match) + { + p->fd_best = f; + p->fd_ambig = NULL; + p->match = m; + } + else if (m == p->match) + p->fd_ambig = f; + return 0; + } + }; + ParamOpOver p; p.arguments = arguments; p.mod = ethis->type->mod; p.match = MATCHnomatch; p.fd_best = NULL; p.fd_ambig = NULL; - overloadApply(fstart, &Param3::fp, &p); + overloadApply(fstart, &p, &ParamOpOver::fp); if (p.fd_best) { inferApplyArgTypesY((TypeFunction *)p.fd_best->type, arguments); @@ -1637,10 +1586,10 @@ static int inferApplyArgTypesY(TypeFunction *tf, Parameters *arguments, int flag arg->type = arg->type->addStorageClass(arg->storageClass); } } - Lmatch: +Lmatch: return 1; - Lnomatch: +Lnomatch: return 0; } @@ -1676,29 +1625,3 @@ void inferApplyArgTypesZ(TemplateDeclaration *tstart, Parameters *arguments) } } #endif - -/************************************** - */ - -static void templateResolve(Match *m, TemplateDeclaration *td, Loc loc, Scope *sc, - Objects *tiargs, Expression *ethis, Expressions *arguments) -{ - FuncDeclaration *fd; - - assert(td); - fd = td->deduceFunctionTemplate(loc, sc, tiargs, ethis->type, arguments, 1); - if (!fd) - return; - m->anyf = fd; - if (m->last >= MATCHexact) - { - m->nextf = fd; - m->count++; - } - else - { - m->last = MATCHexact; - m->lastf = fd; - m->count = 1; - } -} diff --git a/dmd2/optimize.c b/dmd2/optimize.c index 6b23a1e8..af6f4e73 100644 --- a/dmd2/optimize.c +++ b/dmd2/optimize.c @@ -25,13 +25,6 @@ #include "init.h" #include "enum.h" -#ifdef IN_GCC -#include "d-gcc-real.h" -#endif - -static real_t zero; // work around DMC bug for now - - /************************************* * If variable has a const initializer, * return that initializer. @@ -51,12 +44,10 @@ Expression *expandVar(int result, VarDeclaration *v) { if (!v->type) { - //error("ICE"); return e; } Type *tb = v->type->toBasetype(); - if (result & WANTinterpret || - v->storage_class & STCmanifest || + if ( v->storage_class & STCmanifest || v->type->toBasetype()->isscalar() || ((result & WANTexpand) && (tb->ty != Tsarray && tb->ty != Tstruct)) ) @@ -65,25 +56,25 @@ Expression *expandVar(int result, VarDeclaration *v) { if (v->inuse) { if (v->storage_class & STCmanifest) + { v->error("recursive initialization of constant"); + goto Lerror; + } goto L1; } Expression *ei = v->getConstInitializer(); if (!ei) { if (v->storage_class & STCmanifest) + { v->error("enum cannot be initialized with %s", v->init->toChars()); + goto Lerror; + } goto L1; } if (ei->op == TOKconstruct || ei->op == TOKblit) { AssignExp *ae = (AssignExp *)ei; ei = ae->e2; - if (result & WANTinterpret) - { - v->inuse++; - ei = ei->optimize(result); - v->inuse--; - } - else if (ei->isConst() != 1 && ei->op != TOKstring) + if (ei->isConst() != 1 && ei->op != TOKstring) goto L1; if (ei->type == v->type) @@ -97,8 +88,7 @@ Expression *expandVar(int result, VarDeclaration *v) else goto L1; } - else if (!(result & WANTinterpret) && - !(v->storage_class & STCmanifest) && + else if (!(v->storage_class & STCmanifest) && ei->isConst() != 1 && ei->op != TOKstring && ei->op != TOKaddress) { @@ -135,6 +125,9 @@ Expression *expandVar(int result, VarDeclaration *v) L1: //if (e) printf("\te = %p, %s, e->type = %d, %s\n", e, e->toChars(), e->type->ty, e->type->toChars()); return e; + +Lerror: + return new ErrorExp(); } @@ -166,16 +159,6 @@ Expression *fromConstInitializer(int result, Expression *e1) else { e = e1; - /* If we needed to interpret, generate an error. - * Don't give an error if it's a template parameter - */ - if (v && (result & WANTinterpret) && - !(v->storage_class & STCtemplateparameter)) - { - e1->error("variable %s cannot be read at compile time", v->toChars()); - e = e->copy(); - e->type = Type::terror; - } } } return e; @@ -202,11 +185,11 @@ Expression *VarExp::optimize(int result, bool keepLvalue) Expression *TupleExp::optimize(int result, bool keepLvalue) { if (e0) - e0 = e0->optimize(WANTvalue | (result & WANTinterpret)); + e0 = e0->optimize(WANTvalue); for (size_t i = 0; i < exps->dim; i++) { Expression *e = (*exps)[i]; - e = e->optimize(WANTvalue | (result & WANTinterpret)); + e = e->optimize(WANTvalue); (*exps)[i] = e; } return this; @@ -219,7 +202,7 @@ Expression *ArrayLiteralExp::optimize(int result, bool keepLvalue) for (size_t i = 0; i < elements->dim; i++) { Expression *e = (*elements)[i]; - e = e->optimize(WANTvalue | (result & (WANTinterpret | WANTexpand))); + e = e->optimize(WANTvalue | (result & WANTexpand)); (*elements)[i] = e; } } @@ -232,11 +215,11 @@ Expression *AssocArrayLiteralExp::optimize(int result, bool keepLvalue) for (size_t i = 0; i < keys->dim; i++) { Expression *e = (*keys)[i]; - e = e->optimize(WANTvalue | (result & (WANTinterpret | WANTexpand))); + e = e->optimize(WANTvalue | (result & WANTexpand)); (*keys)[i] = e; e = (*values)[i]; - e = e->optimize(WANTvalue | (result & (WANTinterpret | WANTexpand))); + e = e->optimize(WANTvalue | (result & WANTexpand)); (*values)[i] = e; } return this; @@ -253,7 +236,7 @@ Expression *StructLiteralExp::optimize(int result, bool keepLvalue) { Expression *e = (*elements)[i]; if (!e) continue; - e = e->optimize(WANTvalue | (result & (WANTinterpret | WANTexpand))); + e = e->optimize(WANTvalue | (result & WANTexpand)); (*elements)[i] = e; } } @@ -328,8 +311,6 @@ Expression *BoolExp::optimize(int result, bool keepLvalue) Expression *SymOffExp::optimize(int result, bool keepLvalue) { assert(var); - if ((result & WANTinterpret) && var->isThreadlocal()) - error("cannot take address of thread-local variable %s at compile time", var->toChars()); return this; } @@ -382,7 +363,7 @@ Expression *AddrExp::optimize(int result, bool keepLvalue) if (ae->e2->op == TOKint64 && ae->e1->op == TOKvar) { - dinteger_t index = ae->e2->toInteger(); + sinteger_t index = ae->e2->toInteger(); VarExp *ve = (VarExp *)ae->e1; if (ve->type->ty == Tsarray && !ve->var->isImportedSymbol()) @@ -390,7 +371,10 @@ Expression *AddrExp::optimize(int result, bool keepLvalue) TypeSArray *ts = (TypeSArray *)ve->type; sinteger_t dim = ts->dim->toInteger(); if (index < 0 || index >= dim) + { error("array index %lld is out of bounds [0..%lld]", index, dim); + return new ErrorExp(); + } e = new SymOffExp(loc, ve->var, index * ts->nextOf()->size()); e->type = type; return e; @@ -499,16 +483,6 @@ Expression *NewExp::optimize(int result, bool keepLvalue) (*arguments)[i] = e; } } - if (result & WANTinterpret) - { - Expression *eresult = interpret(NULL); - if (eresult == EXP_CANT_INTERPRET) - return this; - if (eresult && eresult != EXP_VOID_INTERPRET) - return eresult; - else - error("cannot evaluate %s at compile time", toChars()); - } return this; } @@ -540,49 +514,19 @@ Expression *CallExp::optimize(int result, bool keepLvalue) return this; #if 1 - if (result & WANTinterpret) - { - Expression *eresult = interpret(NULL); - if (eresult == EXP_CANT_INTERPRET) - return e; - if (eresult && eresult != EXP_VOID_INTERPRET) - e = eresult; - else - error("cannot evaluate %s at compile time", toChars()); - } #else if (e1->op == TOKvar) { FuncDeclaration *fd = ((VarExp *)e1)->var->isFuncDeclaration(); if (fd) { - enum BUILTIN b = fd->isBuiltin(); + BUILTIN b = fd->isBuiltin(); if (b) { e = eval_builtin(b, arguments); if (!e) // failed e = this; // evaluate at runtime } - else if (result & WANTinterpret) - { - Expression *eresult = fd->interpret(NULL, arguments); - if (eresult && eresult != EXP_VOID_INTERPRET) - e = eresult; - else - error("cannot evaluate %s at compile time", toChars()); - } - } - } - else if (e1->op == TOKdotvar && result & WANTinterpret) - { DotVarExp *dve = (DotVarExp *)e1; - FuncDeclaration *fd = dve->var->isFuncDeclaration(); - if (fd) - { - Expression *eresult = fd->interpret(NULL, arguments, dve->e1); - if (eresult && eresult != EXP_VOID_INTERPRET) - e = eresult; - else - error("cannot evaluate %s at compile time", toChars()); } } #endif @@ -598,7 +542,7 @@ Expression *CastExp::optimize(int result, bool keepLvalue) //printf("e1->type %s\n", e1->type->toChars()); //printf("type = %p\n", type); assert(type); - enum TOK op1 = e1->op; + TOK op1 = e1->op; #define X 0 Expression *e1old = e1; @@ -709,7 +653,7 @@ Expression *BinExp::optimize(int result, bool keepLvalue) d_uns64 sz = e1->type->size() * 8; if (i2 < 0 || i2 >= sz) { error("shift assign by %lld is outside the range 0..%llu", i2, (ulonglong)sz - 1); - e2 = new IntegerExp(0); + return new ErrorExp(); } } } @@ -722,6 +666,10 @@ Expression *AddExp::optimize(int result, bool keepLvalue) //printf("AddExp::optimize(%s)\n", toChars()); e1 = e1->optimize(result); e2 = e2->optimize(result); + if (e1->op == TOKerror) + return e1; + if (e2->op == TOKerror) + return e2; if (e1->isConst() && e2->isConst()) { if (e1->op == TOKsymoff && e2->op == TOKsymoff) @@ -738,6 +686,10 @@ Expression *MinExp::optimize(int result, bool keepLvalue) e1 = e1->optimize(result); e2 = e2->optimize(result); + if (e1->op == TOKerror) + return e1; + if (e2->op == TOKerror) + return e2; if (e1->isConst() && e2->isConst()) { if (e2->op == TOKsymoff) @@ -755,6 +707,10 @@ Expression *MulExp::optimize(int result, bool keepLvalue) //printf("MulExp::optimize(result = %d) %s\n", result, toChars()); e1 = e1->optimize(result); e2 = e2->optimize(result); + if (e1->op == TOKerror) + return e1; + if (e2->op == TOKerror) + return e2; if (e1->isConst() == 1 && e2->isConst() == 1) { e = Mul(type, e1, e2); @@ -770,6 +726,10 @@ Expression *DivExp::optimize(int result, bool keepLvalue) //printf("DivExp::optimize(%s)\n", toChars()); e1 = e1->optimize(result); e2 = e2->optimize(result); + if (e1->op == TOKerror) + return e1; + if (e2->op == TOKerror) + return e2; if (e1->isConst() == 1 && e2->isConst() == 1) { e = Div(type, e1, e2); @@ -784,6 +744,10 @@ Expression *ModExp::optimize(int result, bool keepLvalue) e1 = e1->optimize(result); e2 = e2->optimize(result); + if (e1->op == TOKerror) + return e1; + if (e2->op == TOKerror) + return e2; if (e1->isConst() == 1 && e2->isConst() == 1) { e = Mod(type, e1, e2); @@ -798,13 +762,17 @@ Expression *shift_optimize(int result, BinExp *e, Expression *(*shift)(Type *, E e->e1 = e->e1->optimize(result); e->e2 = e->e2->optimize(result); + if (e->e1->op == TOKerror) + return e->e1; + if (e->e2->op == TOKerror) + return e->e2; if (e->e2->isConst() == 1) { sinteger_t i2 = e->e2->toInteger(); d_uns64 sz = e->e1->type->size() * 8; if (i2 < 0 || i2 >= sz) { e->error("shift by %lld is outside the range 0..%llu", i2, (ulonglong)sz - 1); - e->e2 = new IntegerExp(0); + return new ErrorExp(); } if (e->e1->isConst() == 1) ex = (*shift)(e->type, e->e1, e->e2); @@ -835,6 +803,10 @@ Expression *AndExp::optimize(int result, bool keepLvalue) e1 = e1->optimize(result); e2 = e2->optimize(result); + if (e1->op == TOKerror) + return e1; + if (e2->op == TOKerror) + return e2; if (e1->isConst() == 1 && e2->isConst() == 1) e = And(type, e1, e2); else @@ -847,6 +819,10 @@ Expression *OrExp::optimize(int result, bool keepLvalue) e1 = e1->optimize(result); e2 = e2->optimize(result); + if (e1->op == TOKerror) + return e1; + if (e2->op == TOKerror) + return e2; if (e1->isConst() == 1 && e2->isConst() == 1) e = Or(type, e1, e2); else @@ -859,6 +835,10 @@ Expression *XorExp::optimize(int result, bool keepLvalue) e1 = e1->optimize(result); e2 = e2->optimize(result); + if (e1->op == TOKerror) + return e1; + if (e2->op == TOKerror) + return e2; if (e1->isConst() == 1 && e2->isConst() == 1) e = Xor(type, e1, e2); else @@ -871,6 +851,10 @@ Expression *PowExp::optimize(int result, bool keepLvalue) e1 = e1->optimize(result); e2 = e2->optimize(result); + if (e1->op == TOKerror) + return e1; + if (e2->op == TOKerror) + return e2; // Replace 1 ^^ x or 1.0^^x by (x, 1) if ((e1->op == TOKint64 && e1->toInteger() == 1) || @@ -928,6 +912,21 @@ Expression *PowExp::optimize(int result, bool keepLvalue) } e = this; } + + if (e1->op == TOKint64 && e1->toInteger() > 0 && + !((e1->toInteger() - 1) & e1->toInteger()) && // is power of two + e2->type->isintegral() && e2->type->isunsigned()) + { + dinteger_t i = e1->toInteger(); + dinteger_t mul = 1; + while ((i >>= 1) > 1) + mul++; + Expression *shift = new MulExp(loc, e2, new IntegerExp(loc, mul, e2->type)); + shift->type = Type::tshiftcnt; + e = new ShlExp(loc, new IntegerExp(loc, 1, e1->type), shift); + e->type = type; + } + return e; } @@ -941,15 +940,10 @@ Expression *CommaExp::optimize(int result, bool keepLvalue) // In particular, if the comma returns a temporary variable, it needs // to be an lvalue (this is particularly important for struct constructors) - if (result & WANTinterpret) - { // Interpreting comma needs special treatment, because it may - // contain compiler-generated declarations. - e = interpret(NULL); - return (e == EXP_CANT_INTERPRET) ? this : e; - } - - e1 = e1->optimize(result & WANTinterpret); + e1 = e1->optimize(0); e2 = e2->optimize(result, keepLvalue); + if (e1->op == TOKerror) + return e1; if (!e1 || e1->op == TOKint64 || e1->op == TOKfloat64 || !e1->hasSideEffect()) { e = e2; @@ -966,9 +960,12 @@ Expression *ArrayLengthExp::optimize(int result, bool keepLvalue) { Expression *e; //printf("ArrayLengthExp::optimize(result = %d) %s\n", result, toChars()); - e1 = e1->optimize(WANTvalue | WANTexpand | (result & WANTinterpret)); + e1 = e1->optimize(WANTvalue | WANTexpand); + if (e1->op == TOKerror) + return e1; e = this; - if (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKassocarrayliteral) + if (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKassocarrayliteral || + e1->type->toBasetype()->ty == Tsarray) { e = ArrayLength(type, e1); } @@ -978,11 +975,15 @@ Expression *ArrayLengthExp::optimize(int result, bool keepLvalue) Expression *EqualExp::optimize(int result, bool keepLvalue) { //printf("EqualExp::optimize(result = %x) %s\n", result, toChars()); - e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); - e2 = e2->optimize(WANTvalue | (result & WANTinterpret)); + e1 = e1->optimize(WANTvalue); + e2 = e2->optimize(WANTvalue); Expression *e1 = fromConstInitializer(result, this->e1); Expression *e2 = fromConstInitializer(result, this->e2); + if (e1->op == TOKerror) + return e1; + if (e2->op == TOKerror) + return e2; Expression *e = Equal(op, type, e1, e2); if (e == EXP_CANT_INTERPRET) @@ -993,13 +994,19 @@ Expression *EqualExp::optimize(int result, bool keepLvalue) Expression *IdentityExp::optimize(int result, bool keepLvalue) { //printf("IdentityExp::optimize(result = %d) %s\n", result, toChars()); - e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); - e2 = e2->optimize(WANTvalue | (result & WANTinterpret)); + e1 = e1->optimize(WANTvalue); + e2 = e2->optimize(WANTvalue); + + if (e1->op == TOKerror) + return e1; + if (e2->op == TOKerror) + return e2; + Expression *e = this; if ((this->e1->isConst() && this->e2->isConst()) || - (this->e1->op == TOKnull && this->e2->op == TOKnull) || - (result & WANTinterpret)) + (this->e1->op == TOKnull && this->e2->op == TOKnull) + ) { e = Identity(op, type, this->e1, this->e2); if (e == EXP_CANT_INTERPRET) @@ -1042,13 +1049,13 @@ Expression *IndexExp::optimize(int result, bool keepLvalue) { Expression *e; //printf("IndexExp::optimize(result = %d) %s\n", result, toChars()); - e1 = e1->optimize(WANTvalue | (result & (WANTinterpret| WANTexpand))); + e1 = e1->optimize(WANTvalue | (result & WANTexpand)); Expression *ex = fromConstInitializer(result, e1); // We might know $ now setLengthVarIfKnown(lengthVar, ex); - e2 = e2->optimize(WANTvalue | (result & WANTinterpret)); + e2 = e2->optimize(WANTvalue); if (keepLvalue) return this; e = Index(type, ex, e2); @@ -1063,7 +1070,7 @@ Expression *SliceExp::optimize(int result, bool keepLvalue) //printf("SliceExp::optimize(result = %d) %s\n", result, toChars()); e = this; - e1 = e1->optimize(WANTvalue | (result & (WANTinterpret|WANTexpand))); + e1 = e1->optimize(WANTvalue | (result & WANTexpand)); if (!lwr) { if (e1->op == TOKstring) { // Convert slice of string literal into dynamic array @@ -1076,8 +1083,8 @@ Expression *SliceExp::optimize(int result, bool keepLvalue) e1 = fromConstInitializer(result, e1); // We might know $ now setLengthVarIfKnown(lengthVar, e1); - lwr = lwr->optimize(WANTvalue | (result & WANTinterpret)); - upr = upr->optimize(WANTvalue | (result & WANTinterpret)); + lwr = lwr->optimize(WANTvalue); + upr = upr->optimize(WANTvalue); e = Slice(type, e1, lwr, upr); if (e == EXP_CANT_INTERPRET) e = this; @@ -1089,7 +1096,9 @@ Expression *AndAndExp::optimize(int result, bool keepLvalue) { Expression *e; //printf("AndAndExp::optimize(%d) %s\n", result, toChars()); - e1 = e1->optimize(WANTflags | (result & WANTinterpret)); + e1 = e1->optimize(WANTflags); + if (e1->op == TOKerror) + return e1; e = this; if (e1->isBool(FALSE)) { @@ -1103,9 +1112,12 @@ Expression *AndAndExp::optimize(int result, bool keepLvalue) } else { - e2 = e2->optimize(WANTflags | (result & WANTinterpret)); + e2 = e2->optimize(WANTflags); if (result && e2->type->toBasetype()->ty == Tvoid && !global.errors) + { error("void has no value"); + return new ErrorExp(); + } if (e1->isConst()) { if (e2->isConst()) @@ -1128,7 +1140,9 @@ Expression *AndAndExp::optimize(int result, bool keepLvalue) Expression *OrOrExp::optimize(int result, bool keepLvalue) { Expression *e; - e1 = e1->optimize(WANTflags | (result & WANTinterpret)); + e1 = e1->optimize(WANTflags); + if (e1->op == TOKerror) + return e1; e = this; if (e1->isBool(TRUE)) { // Replace with (e1, 1) @@ -1138,9 +1152,12 @@ Expression *OrOrExp::optimize(int result, bool keepLvalue) } else { - e2 = e2->optimize(WANTflags | (result & WANTinterpret)); + e2 = e2->optimize(WANTflags); if (result && e2->type->toBasetype()->ty == Tvoid && !global.errors) + { error("void has no value"); + return new ErrorExp(); + } if (e1->isConst()) { if (e2->isConst()) @@ -1165,8 +1182,8 @@ Expression *CmpExp::optimize(int result, bool keepLvalue) { Expression *e; //printf("CmpExp::optimize() %s\n", toChars()); - e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); - e2 = e2->optimize(WANTvalue | (result & WANTinterpret)); + e1 = e1->optimize(WANTvalue); + e2 = e2->optimize(WANTvalue); Expression *e1 = fromConstInitializer(result, this->e1); Expression *e2 = fromConstInitializer(result, this->e2); @@ -1193,7 +1210,7 @@ Expression *CatExp::optimize(int result, bool keepLvalue) Expression *CondExp::optimize(int result, bool keepLvalue) { Expression *e; - econd = econd->optimize(WANTflags | (result & WANTinterpret)); + econd = econd->optimize(WANTflags); if (econd->isBool(TRUE)) e = e1->optimize(result, keepLvalue); else if (econd->isBool(FALSE)) diff --git a/dmd2/parse.c b/dmd2/parse.c index 0f827fdf..05b125e4 100644 --- a/dmd2/parse.c +++ b/dmd2/parse.c @@ -55,7 +55,7 @@ // Support D1 inout #define D1INOUT 0 -Parser::Parser(Module *module, unsigned char *base, size_t length, int doDocComment) +Parser::Parser(Module *module, utf8_t *base, size_t length, int doDocComment) : Lexer(module, base, 0, length, doDocComment, 0) { //printf("Parser::Parser()\n"); @@ -74,7 +74,8 @@ Dsymbols *Parser::parseModule() // ModuleDeclation leads off if (token.value == TOKmodule) { - unsigned char *comment = token.blockComment; + Loc loc = token.loc; + utf8_t *comment = token.blockComment; bool safe = FALSE; nextToken(); @@ -120,7 +121,7 @@ Dsymbols *Parser::parseModule() id = token.ident; } - md = new ModuleDeclaration(a, id, safe); + md = new ModuleDeclaration(loc, a, id, safe); if (token.value != TOKsemicolon) error("';' expected following module declaration instead of %s", token.toChars()); @@ -131,7 +132,8 @@ Dsymbols *Parser::parseModule() decldefs = parseDeclDefs(0); if (token.value != TOKeof) - { error(loc, "unrecognized declaration"); + { + error(token.loc, "unrecognized declaration"); goto Lerr; } return decldefs; @@ -148,11 +150,11 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl) Dsymbols *decldefs; Dsymbols *a; Dsymbols *aelse; - enum PROT prot; + PROT prot; StorageClass stc; StorageClass storageClass; Condition *condition; - unsigned char *comment; + utf8_t *comment; Dsymbol *lastDecl = NULL; // used to link unittest to its previous declaration if (!pLastDecl) pLastDecl = &lastDecl; @@ -195,7 +197,8 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl) break; case TOKmixin: - { Loc loc = this->loc; + { + Loc loc = token.loc; switch (peekNext()) { case TOKlparen: @@ -264,7 +267,7 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl) } else { - deprecation("use of 'invariant' rather than 'immutable' is deprecated"); + error("use 'immutable' instead of 'invariant'"); stc = STCimmutable; goto Lstc; } @@ -273,7 +276,7 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl) case TOKunittest: s = parseUnitTest(); - if (*pLastDecl) (*pLastDecl)->unittest = (UnitTestDeclaration *)s; + if (*pLastDecl) (*pLastDecl)->ddocUnittest = (UnitTestDeclaration *)s; break; case TOKnew: @@ -299,20 +302,21 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl) else if (token.value == TOKassert) s = parseStaticAssert(); else if (token.value == TOKif) - { condition = parseStaticIfCondition(); + { + condition = parseStaticIfCondition(); if (token.value == TOKcolon) a = parseBlock(pLastDecl); else { Loc lookingForElseSave = lookingForElse; - lookingForElse = loc; + lookingForElse = token.loc; a = parseBlock(pLastDecl); lookingForElse = lookingForElseSave; } aelse = NULL; if (token.value == TOKelse) { - Loc elseloc = this->loc; + Loc elseloc = token.loc; nextToken(); aelse = parseBlock(pLastDecl); checkDanglingElse(elseloc); @@ -423,7 +427,7 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl) else { if (token.value == TOKinvariant) - deprecation("use of 'invariant' rather than 'immutable' is deprecated"); + error("use 'immutable' instead of 'invariant'"); stc = STCimmutable; } goto Lstc; @@ -509,7 +513,7 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl) case TOKlbracket: { - warning(loc, "use @(attributes) instead of [attributes]"); + warning(token.loc, "use @(attributes) instead of [attributes]"); Expressions *exps = parseArguments(); a = parseBlock(pLastDecl); s = new UserAttributeDeclaration(exps, a); @@ -522,7 +526,7 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl) goto Lstc; } { - enum LINK linksave = linkage; + LINK linksave = linkage; linkage = parseLinkage(); a = parseBlock(pLastDecl); s = new LinkDeclaration(linkage, a); @@ -582,8 +586,9 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl) } case TOKpragma: - { Identifier *ident; + { Expressions *args = NULL; + Loc loc = token.loc; nextToken(); check(TOKlparen); @@ -591,7 +596,7 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl) { error("pragma(identifier) expected"); goto Lerror; } - ident = token.ident; + Identifier *ident = token.ident; nextToken(); if (token.value == TOKcomma && peekNext() != TOKrparen) args = parseArguments(); // pragma(identifier, args...) @@ -612,9 +617,9 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl) { nextToken(); if (token.value == TOKidentifier) - s = new DebugSymbol(loc, token.ident); + s = new DebugSymbol(token.loc, token.ident); else if (token.value == TOKint32v || token.value == TOKint64v) - s = new DebugSymbol(loc, (unsigned)token.uns64value); + s = new DebugSymbol(token.loc, (unsigned)token.uns64value); else { error("identifier or integer expected, not %s", token.toChars()); s = NULL; @@ -635,9 +640,9 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl) { nextToken(); if (token.value == TOKidentifier) - s = new VersionSymbol(loc, token.ident); + s = new VersionSymbol(token.loc, token.ident); else if (token.value == TOKint32v || token.value == TOKint64v) - s = new VersionSymbol(loc, (unsigned)token.uns64value); + s = new VersionSymbol(token.loc, (unsigned)token.uns64value); else { error("identifier or integer expected, not %s", token.toChars()); s = NULL; @@ -658,7 +663,7 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl) else { Loc lookingForElseSave = lookingForElse; - lookingForElse = loc; + lookingForElse = token.loc; a = parseBlock(pLastDecl); lookingForElse = lookingForElseSave; } @@ -666,7 +671,7 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl) aelse = NULL; if (token.value == TOKelse) { - Loc elseloc = this->loc; + Loc elseloc = token.loc; nextToken(); aelse = parseBlock(pLastDecl); checkDanglingElse(elseloc); @@ -753,7 +758,10 @@ StorageClass Parser::parseAttribute(Expressions **pudas) { // Allow identifier, template instantiation, or function call Expression *exp = parsePrimaryExp(); if (token.value == TOKlparen) + { + Loc loc = token.loc; exp = new CallExp(loc, exp, parseArguments()); + } udas = new Expressions(); udas->push(exp); @@ -796,7 +804,7 @@ StorageClass Parser::parsePostfix() { case TOKconst: stc |= STCconst; break; case TOKinvariant: - deprecation("use of 'invariant' rather than 'immutable' is deprecated"); + error("use 'immutable' instead of 'invariant'"); case TOKimmutable: stc |= STCimmutable; break; case TOKshared: stc |= STCshared; break; case TOKwild: stc |= STCwild; break; @@ -830,7 +838,7 @@ StorageClass Parser::parseTypeCtor() { case TOKconst: stc |= STCconst; break; case TOKinvariant: - deprecation("use of 'invariant' rather than 'immutable' is deprecated"); + error("use 'immutable' instead of 'invariant'"); case TOKimmutable: stc |= STCimmutable; break; case TOKshared: stc |= STCshared; break; case TOKwild: stc |= STCwild; break; @@ -901,7 +909,7 @@ Dsymbols *Parser::parseBlock(Dsymbol **pLastDecl) StaticAssert *Parser::parseStaticAssert() { - Loc loc = this->loc; + Loc loc = token.loc; Expression *exp; Expression *msg = NULL; @@ -925,8 +933,9 @@ StaticAssert *Parser::parseStaticAssert() #if DMDV2 TypeQualified *Parser::parseTypeof() -{ TypeQualified *t; - Loc loc = this->loc; +{ + TypeQualified *t; + Loc loc = token.loc; nextToken(); check(TOKlparen); @@ -936,7 +945,8 @@ TypeQualified *Parser::parseTypeof() t = new TypeReturn(loc); } else - { Expression *exp = parseExpression(); // typeof(expression) + { + Expression *exp = parseExpression(); // typeof(expression) t = new TypeTypeof(loc, exp); } check(TOKrparen); @@ -952,7 +962,7 @@ TypeQualified *Parser::parseTypeof() #if DMDV2 Type *Parser::parseVector() { - Loc loc = this->loc; + Loc loc = token.loc; nextToken(); check(TOKlparen); Type *tb = parseType(); @@ -966,9 +976,9 @@ Type *Parser::parseVector() * The parser is on the 'extern' token. */ -enum LINK Parser::parseLinkage() +LINK Parser::parseLinkage() { - enum LINK link = LINKdefault; + LINK link = LINKdefault; nextToken(); assert(token.value == TOKlparen); nextToken(); @@ -992,18 +1002,7 @@ enum LINK Parser::parseLinkage() } else if (id == Id::System) { -#if IN_LLVM - if (global.params.isWindows) - link = LINKwindows; - else - link = LINKc; -#else -#if _WIN32 - link = LINKwindows; -#else - link = LINKc; -#endif -#endif + link = global.params.isWindows ? LINKwindows : LINKc; } else { @@ -1098,9 +1097,10 @@ Condition *Parser::parseVersionCondition() */ Condition *Parser::parseStaticIfCondition() -{ Expression *exp; +{ + Expression *exp; Condition *condition; - Loc loc = this->loc; + Loc loc = token.loc; nextToken(); if (token.value == TOKlparen) @@ -1110,7 +1110,8 @@ Condition *Parser::parseStaticIfCondition() check(TOKrparen); } else - { error("(expression) expected following static if"); + { + error("(expression) expected following static if"); exp = NULL; } condition = new StaticIfCondition(loc, exp); @@ -1130,11 +1131,12 @@ Condition *Parser::parseStaticIfCondition() Dsymbol *Parser::parseCtor() { - Loc loc = this->loc; + Loc loc = token.loc; nextToken(); if (token.value == TOKlparen && peekNext() == TOKthis && peekNext2() == TOKrparen) - { // this(this) { ... } + { + // this(this) { ... } nextToken(); nextToken(); check(TOKrparen); @@ -1150,7 +1152,8 @@ Dsymbol *Parser::parseCtor() */ TemplateParameters *tpl = NULL; if (token.value == TOKlparen && peekPastParen(&token)->value == TOKlparen) - { tpl = parseTemplateParameterList(); + { + tpl = parseTemplateParameterList(); int varargs; Parameters *parameters = parseParameters(&varargs); @@ -1194,7 +1197,7 @@ Dsymbol *Parser::parseCtor() DtorDeclaration *Parser::parseDtor() { DtorDeclaration *f; - Loc loc = this->loc; + Loc loc = token.loc; nextToken(); check(TOKthis); @@ -1215,7 +1218,7 @@ DtorDeclaration *Parser::parseDtor() StaticCtorDeclaration *Parser::parseStaticCtor() { - Loc loc = this->loc; + Loc loc = token.loc; nextToken(); check(TOKlparen); @@ -1234,7 +1237,7 @@ StaticCtorDeclaration *Parser::parseStaticCtor() SharedStaticCtorDeclaration *Parser::parseSharedStaticCtor() { - Loc loc = this->loc; + Loc loc = token.loc; nextToken(); nextToken(); @@ -1255,14 +1258,17 @@ SharedStaticCtorDeclaration *Parser::parseSharedStaticCtor() StaticDtorDeclaration *Parser::parseStaticDtor() { - Loc loc = this->loc; + Loc loc = token.loc; nextToken(); check(TOKthis); check(TOKlparen); check(TOKrparen); + StorageClass stc = parsePostfix(); + if (stc & STCshared) + error("to create a 'shared' static destructor, move 'shared' in front of the declaration"); - StaticDtorDeclaration *f = new StaticDtorDeclaration(loc, Loc()); + StaticDtorDeclaration *f = new StaticDtorDeclaration(loc, Loc(), stc); parseContracts(f); return f; } @@ -1275,7 +1281,7 @@ StaticDtorDeclaration *Parser::parseStaticDtor() SharedStaticDtorDeclaration *Parser::parseSharedStaticDtor() { - Loc loc = this->loc; + Loc loc = token.loc; nextToken(); nextToken(); @@ -1283,8 +1289,11 @@ SharedStaticDtorDeclaration *Parser::parseSharedStaticDtor() check(TOKthis); check(TOKlparen); check(TOKrparen); + StorageClass stc = parsePostfix(); + if (stc & STCshared) + error("static destructor is 'shared' already"); - SharedStaticDtorDeclaration *f = new SharedStaticDtorDeclaration(loc, Loc()); + SharedStaticDtorDeclaration *f = new SharedStaticDtorDeclaration(loc, Loc(), stc); parseContracts(f); return f; } @@ -1298,7 +1307,7 @@ SharedStaticDtorDeclaration *Parser::parseSharedStaticDtor() InvariantDeclaration *Parser::parseInvariant() { InvariantDeclaration *f; - Loc loc = this->loc; + Loc loc = token.loc; nextToken(); if (token.value == TOKlparen) // optional () @@ -1322,11 +1331,11 @@ UnitTestDeclaration *Parser::parseUnitTest() { UnitTestDeclaration *f; Statement *body; - Loc loc = this->loc; + Loc loc = token.loc; nextToken(); - unsigned char *begPtr = token.ptr + 1; // skip '{' - unsigned char *endPtr = NULL; + utf8_t *begPtr = token.ptr + 1; // skip '{' + utf8_t *endPtr = NULL; body = parseStatement(PScurly, &endPtr); /** Extract unittest body as a string. Must be done eagerly since memory @@ -1335,7 +1344,7 @@ UnitTestDeclaration *Parser::parseUnitTest() if (global.params.doDocComments && endPtr > begPtr) { /* Remove trailing whitespaces */ - for (unsigned char *p = endPtr - 1; + for (utf8_t *p = endPtr - 1; begPtr <= p && (*p == ' ' || *p == '\n' || *p == '\t'); --p) { endPtr = p; @@ -1351,7 +1360,7 @@ UnitTestDeclaration *Parser::parseUnitTest() } } - f = new UnitTestDeclaration(loc, this->loc, docline); + f = new UnitTestDeclaration(loc, token.loc, docline); f->fbody = body; return f; } @@ -1367,7 +1376,7 @@ NewDeclaration *Parser::parseNew() NewDeclaration *f; Parameters *arguments; int varargs; - Loc loc = this->loc; + Loc loc = token.loc; nextToken(); arguments = parseParameters(&varargs); @@ -1387,7 +1396,7 @@ DeleteDeclaration *Parser::parseDelete() DeleteDeclaration *f; Parameters *arguments; int varargs; - Loc loc = this->loc; + Loc loc = token.loc; nextToken(); arguments = parseParameters(&varargs); @@ -1441,7 +1450,7 @@ Parameters *Parser::parseParameters(int *pvarargs, TemplateParameters **tpl) if (peek(&token)->value == TOKlparen) goto Ldefault; if (token.value == TOKinvariant) - deprecation("use of 'invariant' rather than 'immutable' is deprecated"); + error("use 'immutable' instead of 'invariant'"); stc = STCimmutable; goto L2; @@ -1510,10 +1519,6 @@ Parameters *Parser::parseParameters(int *pvarargs, TemplateParameters **tpl) if (stc & (stc - 1) && // if stc is not a power of 2 !(stc == (STCin | STCref))) error("incompatible parameter storage classes"); - if ((storageClass & (STCconst | STCout)) == (STCconst | STCout)) - error("out cannot be const"); - if ((storageClass & (STCimmutable | STCout)) == (STCimmutable | STCout)) - error("out cannot be immutable"); if ((storageClass & STCscope) && (storageClass & (STCref | STCout))) error("scope cannot be ref or out"); @@ -1527,7 +1532,9 @@ Parameters *Parser::parseParameters(int *pvarargs, TemplateParameters **tpl) t->value == TOKrparen || t->value == TOKdotdotdot))) #endif - { Identifier *id = Lexer::uniqueId("__T"); + { + Identifier *id = Lexer::uniqueId("__T"); + Loc loc = token.loc; at = new TypeIdentifier(loc, id); if (!*tpl) *tpl = new TemplateParameters(); @@ -1564,7 +1571,6 @@ Parameters *Parser::parseParameters(int *pvarargs, TemplateParameters **tpl) nextToken(); break; } - L3: a = new Parameter(storageClass, at, ai, ae); arguments->push(a); if (token.value == TOKcomma) @@ -1590,15 +1596,17 @@ Parameters *Parser::parseParameters(int *pvarargs, TemplateParameters **tpl) */ EnumDeclaration *Parser::parseEnum() -{ EnumDeclaration *e; +{ + EnumDeclaration *e; Identifier *id; Type *memtype; - Loc loc = this->loc; + Loc loc = token.loc; //printf("Parser::parseEnum()\n"); nextToken(); if (token.value == TOKidentifier) - { id = token.ident; + { + id = token.ident; nextToken(); } else @@ -1621,7 +1629,7 @@ EnumDeclaration *Parser::parseEnum() //printf("enum definition\n"); e->members = new Dsymbols(); nextToken(); - unsigned char *comment = token.blockComment; + utf8_t *comment = token.blockComment; while (token.value != TOKrcurly) { /* Can take the following forms: @@ -1630,7 +1638,7 @@ EnumDeclaration *Parser::parseEnum() * 3. type ident = value */ - loc = this->loc; + loc = token.loc; Type *type = NULL; Identifier *ident; @@ -1693,15 +1701,16 @@ EnumDeclaration *Parser::parseEnum() */ Dsymbol *Parser::parseAggregate() -{ AggregateDeclaration *a = NULL; +{ + AggregateDeclaration *a = NULL; int anon = 0; - enum TOK tok; Identifier *id; TemplateParameters *tpl = NULL; Expression *constraint = NULL; + Loc loc = token.loc; + TOK tok = token.value; //printf("Parser::parseAggregate()\n"); - tok = token.value; nextToken(); if (token.value != TOKidentifier) { id = NULL; @@ -1719,9 +1728,9 @@ Dsymbol *Parser::parseAggregate() } } - Loc loc = this->loc; switch (tok) - { case TOKclass: + { + case TOKclass: case TOKinterface: { if (!id) @@ -1751,7 +1760,10 @@ Dsymbol *Parser::parseAggregate() } if (tok == TOKclass) - a = new ClassDeclaration(loc, id, baseclasses); + { + bool inObject = md && !md->packages && md->id == Id::object; + a = new ClassDeclaration(loc, id, baseclasses, inObject); + } else a = new InterfaceDeclaration(loc, id, baseclasses); break; @@ -1790,7 +1802,7 @@ Dsymbol *Parser::parseAggregate() { /* Anonymous structs/unions are more like attributes. */ - return new AnonDeclaration(loc, anon - 1, decl); + return new AnonDeclaration(loc, anon == 2, decl); } else a->members = decl; @@ -1824,7 +1836,7 @@ BaseClasses *Parser::parseBaseClasses() for (; 1; nextToken()) { bool prot = false; - enum PROT protection = PROTpublic; + PROT protection = PROTpublic; switch (token.value) { case TOKprivate: @@ -1891,7 +1903,7 @@ TemplateDeclaration *Parser::parseTemplateDeclaration(int ismixin) TemplateParameters *tpl; Dsymbols *decldefs; Expression *constraint = NULL; - Loc loc = this->loc; + Loc loc = token.loc; nextToken(); if (token.value != TOKidentifier) @@ -1947,10 +1959,12 @@ TemplateParameters *Parser::parseTemplateParameterList(int flag) // Get array of TemplateParameters if (flag || token.value != TOKrparen) - { int isvariadic = 0; - + { + int isvariadic = 0; while (token.value != TOKrparen) - { TemplateParameter *tp; + { + TemplateParameter *tp; + Loc loc; Identifier *tp_ident = NULL; Type *tp_spectype = NULL; Type *tp_valtype = NULL; @@ -1966,6 +1980,7 @@ TemplateParameters *Parser::parseTemplateParameterList(int flag) if (token.value == TOKalias) { // AliasParameter nextToken(); + loc = token.loc; // todo Type *spectype = NULL; if (isDeclaration(&token, 2, TOKreserved, NULL)) { @@ -1974,13 +1989,14 @@ TemplateParameters *Parser::parseTemplateParameterList(int flag) else { if (token.value != TOKidentifier) - { error("identifier expected for template alias parameter"); + { + error("identifier expected for template alias parameter"); goto Lerr; } tp_ident = token.ident; nextToken(); } - Object *spec = NULL; + RootObject *spec = NULL; if (token.value == TOKcolon) // : Type { nextToken(); @@ -1989,7 +2005,7 @@ TemplateParameters *Parser::parseTemplateParameterList(int flag) else spec = parseCondExp(); } - Object *def = NULL; + RootObject *def = NULL; if (token.value == TOKassign) // = Type { nextToken(); @@ -1998,15 +2014,18 @@ TemplateParameters *Parser::parseTemplateParameterList(int flag) else def = parseCondExp(); } - tp = new TemplateAliasParameter(loc, tp_ident, spectype, spec, def); + tp = new TemplateAliasParameter(loc/*todo*/, tp_ident, spectype, spec, def); } else if (t->value == TOKcolon || t->value == TOKassign || t->value == TOKcomma || t->value == TOKrparen) - { // TypeParameter + { + // TypeParameter if (token.value != TOKidentifier) - { error("identifier expected for template type parameter"); + { + error("identifier expected for template type parameter"); goto Lerr; } + loc = token.loc; tp_ident = token.ident; nextToken(); if (token.value == TOKcolon) // : Type @@ -2022,10 +2041,12 @@ TemplateParameters *Parser::parseTemplateParameterList(int flag) tp = new TemplateTypeParameter(loc, tp_ident, tp_spectype, tp_defaulttype); } else if (token.value == TOKidentifier && t->value == TOKdotdotdot) - { // ident... + { + // ident... if (isvariadic) error("variadic template parameter must be last"); isvariadic = 1; + loc = token.loc; tp_ident = token.ident; nextToken(); nextToken(); @@ -2033,12 +2054,15 @@ TemplateParameters *Parser::parseTemplateParameterList(int flag) } #if DMDV2 else if (token.value == TOKthis) - { // ThisParameter + { + // ThisParameter nextToken(); if (token.value != TOKidentifier) - { error("identifier expected for template this parameter"); + { + error("identifier expected for template this parameter"); goto Lerr; } + loc = token.loc; tp_ident = token.ident; nextToken(); if (token.value == TOKcolon) // : Type @@ -2055,7 +2079,9 @@ TemplateParameters *Parser::parseTemplateParameterList(int flag) } #endif else - { // ValueParameter + { + // ValueParameter + loc = token.loc; // todo tp_valtype = parseType(&tp_ident); if (!tp_ident) { @@ -2072,7 +2098,7 @@ TemplateParameters *Parser::parseTemplateParameterList(int flag) nextToken(); tp_defaultvalue = parseDefaultInitExp(); } - tp = new TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue); + tp = new TemplateValueParameter(loc/*todo*/, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue); } tpl->push(tp); if (token.value != TOKcomma) @@ -2098,12 +2124,14 @@ Dsymbol *Parser::parseMixin() { TemplateMixin *tm; Identifier *id; - TypeQualified *tqual; Objects *tiargs; //printf("parseMixin()\n"); - nextToken(); - tqual = NULL; + Loc locMixin = token.loc; + nextToken(); // skip 'mixin' + + Loc loc = token.loc; + TypeQualified *tqual = NULL; if (token.value == TOKdot) { id = Id::empty; @@ -2138,7 +2166,8 @@ Dsymbol *Parser::parseMixin() } if (tiargs && token.value == TOKdot) - { TemplateInstance *tempinst = new TemplateInstance(loc, id); + { + TemplateInstance *tempinst = new TemplateInstance(loc, id); tempinst->tiargs = tiargs; if (!tqual) tqual = new TypeInstance(loc, tempinst); @@ -2159,9 +2188,11 @@ Dsymbol *Parser::parseMixin() nextToken(); if (token.value != TOKidentifier) - { error("identifier expected following '.' instead of '%s'", token.toChars()); + { + error("identifier expected following '.' instead of '%s'", token.toChars()); break; } + loc = token.loc; id = token.ident; nextToken(); } @@ -2174,7 +2205,7 @@ Dsymbol *Parser::parseMixin() else id = NULL; - tm = new TemplateMixin(loc, id, tqual, tiargs); + tm = new TemplateMixin(locMixin, id, tqual, tiargs); if (token.value != TOKsemicolon) error("';' expected after mixin"); nextToken(); @@ -2204,7 +2235,7 @@ Objects *Parser::parseTemplateArgumentList2() { //printf("Parser::parseTemplateArgumentList2()\n"); Objects *tiargs = new Objects(); - enum TOK endtok = TOKrparen; + TOK endtok = TOKrparen; nextToken(); // Get TemplateArgumentList @@ -2244,7 +2275,7 @@ Objects *Parser::parseTemplateArgument() switch (token.value) { case TOKidentifier: - ta = new TypeIdentifier(loc, token.ident); + ta = new TypeIdentifier(token.loc, token.ident); goto LabelX; case TOKvector: @@ -2291,7 +2322,7 @@ Objects *Parser::parseTemplateArgument() } if (token.value == TOKnot) { - enum TOK tok = peekNext(); + TOK tok = peekNext(); if (tok != TOKis && tok != TOKin) error("multiple ! arguments are not allowed"); } @@ -2299,11 +2330,8 @@ Objects *Parser::parseTemplateArgument() } Import *Parser::parseImport(Dsymbols *decldefs, int isstatic) -{ Import *s; - Identifier *id; +{ Identifier *aliasid = NULL; - Identifiers *a; - Loc loc; //printf("Parser::parseImport()\n"); do @@ -2315,9 +2343,9 @@ Import *Parser::parseImport(Dsymbols *decldefs, int isstatic) break; } - loc = this->loc; - a = NULL; - id = token.ident; + Loc loc = token.loc; + Identifier *id = token.ident; + Identifiers *a = NULL; nextToken(); if (!aliasid && token.value == TOKassign) { @@ -2338,7 +2366,7 @@ Import *Parser::parseImport(Dsymbols *decldefs, int isstatic) nextToken(); } - s = new Import(loc, a, id, aliasid, isstatic); + Import *s = new Import(loc, a, id, aliasid, isstatic); decldefs->push(s); /* Look for @@ -2465,7 +2493,9 @@ Type *Parser::parseType(Identifier **pident, TemplateParameters **tpl) #endif Type *Parser::parseBasicType() -{ Type *t; +{ + Type *t; + Loc loc; Identifier *id; TypeQualified *tid; @@ -2479,10 +2509,12 @@ Type *Parser::parseBasicType() case TOKthis: case TOKsuper: case TOKidentifier: + loc = token.loc; id = token.ident; nextToken(); if (token.value == TOKnot) - { // ident!(template_arguments) + { + // ident!(template_arguments) TemplateInstance *tempinst = new TemplateInstance(loc, id); nextToken(); if (token.value == TOKlparen) @@ -2498,11 +2530,14 @@ Type *Parser::parseBasicType() tid = new TypeIdentifier(loc, id); Lident2: while (token.value == TOKdot) - { nextToken(); + { + nextToken(); if (token.value != TOKidentifier) - { error("identifier expected following '.' instead of '%s'", token.toChars()); + { + error("identifier expected following '.' instead of '%s'", token.toChars()); break; } + loc = token.loc; id = token.ident; nextToken(); if (token.value == TOKnot) @@ -2525,6 +2560,7 @@ Type *Parser::parseBasicType() case TOKdot: // Leading . as in .foo + loc = token.loc; id = Id::empty; goto Lident; @@ -2552,7 +2588,7 @@ Type *Parser::parseBasicType() break; case TOKinvariant: - deprecation("use of 'invariant' rather than 'immutable' is deprecated"); + error("use 'immutable' instead of 'invariant'"); case TOKimmutable: // invariant(type) nextToken(); @@ -2666,7 +2702,7 @@ Type *Parser::parseBasicType2(Type *t) // t function(parameter list) nothrow pure Parameters *arguments; int varargs; - enum TOK save = token.value; + TOK save = token.value; nextToken(); arguments = parseParameters(&varargs); @@ -2739,7 +2775,8 @@ Type *Parser::parseDeclarator(Type *t, Identifier **pident, TemplateParameters * * Improve error messages for the common bug of a missing return type * by looking to see if (a) looks like a parameter list. */ - if (isParameters(&peekt)) { + if (isParameters(&peekt)) + { error("function declaration without return type. " "(Note that constructors are always named 'this')"); } @@ -2856,7 +2893,7 @@ Type *Parser::parseDeclarator(Type *t, Identifier **pident, TemplateParameters * * Return array of Declaration *'s. */ -Dsymbols *Parser::parseDeclarations(StorageClass storage_class, unsigned char *comment) +Dsymbols *Parser::parseDeclarations(StorageClass storage_class, utf8_t *comment) { StorageClass stc; int disable; @@ -2865,10 +2902,10 @@ Dsymbols *Parser::parseDeclarations(StorageClass storage_class, unsigned char *c Type *tfirst; Identifier *ident; Dsymbols *a; - enum TOK tok = TOKreserved; - enum LINK link = linkage; + TOK tok = TOKreserved; + LINK link = linkage; unsigned structalign = 0; - Loc loc = this->loc; + Loc loc = token.loc; Expressions *udas = NULL; //printf("parseDeclarations() %s\n", token.toChars()); @@ -2883,6 +2920,7 @@ Dsymbols *Parser::parseDeclarations(StorageClass storage_class, unsigned char *c switch (token.value) { case TOKalias: + { /* Look for: * alias identifier this; */ @@ -2918,32 +2956,51 @@ Dsymbols *Parser::parseDeclarations(StorageClass storage_class, unsigned char *c #endif /* Look for: * alias identifier = type; + * alias identifier(...) = type; */ - if (token.value == TOKidentifier && peekNext() == TOKassign) + Token *tk = &token; + if (tk->value == TOKidentifier && + ((tk = peek(tk))->value == TOKlparen + ? skipParens(tk, &tk) && (tk = peek(tk), 1) : 1) && + tk->value == TOKassign) { a = new Dsymbols(); while (1) { ident = token.ident; nextToken(); + TemplateParameters *tpl = NULL; + if (token.value == TOKlparen) + tpl = parseTemplateParameterList(); check(TOKassign); t = parseType(); - Declaration *v = new AliasDeclaration(loc, ident, t); - a->push(v); + Dsymbol *s = new AliasDeclaration(loc, ident, t); + if (tpl) + { + Dsymbols *a2 = new Dsymbols(); + a2->push(s); + TemplateDeclaration *tempdecl = + new TemplateDeclaration(loc, ident, tpl, NULL/*constraint*/, a2, 0); + s = tempdecl; + } + a->push(s); switch (token.value) - { case TOKsemicolon: + { + case TOKsemicolon: nextToken(); - addComment(v, comment); + addComment(s, comment); break; case TOKcomma: nextToken(); - addComment(v, comment); + addComment(s, comment); if (token.value != TOKidentifier) - { error("Identifier expected following comma, not %s", token.toChars()); + { + error("Identifier expected following comma, not %s", token.toChars()); break; } - else if (peek(&token)->value != TOKassign) - { error("= expected following identifier"); + if (peekNext() != TOKassign && peekNext() != TOKlparen) + { + error("= expected following identifier"); nextToken(); break; } @@ -2956,10 +3013,74 @@ Dsymbols *Parser::parseDeclarations(StorageClass storage_class, unsigned char *c } return a; } - break; + } + case TOKenum: + { + /* Look for: + * enum identifier(...) = type; + */ + tok = token.value; + Token *tk = peek(&token); + if (tk->value == TOKidentifier && + (tk = peek(tk))->value == TOKlparen && skipParens(tk, &tk) && + (tk = peek(tk))->value == TOKassign) + { + nextToken(); + a = new Dsymbols(); + while (1) + { + ident = token.ident; + nextToken(); + TemplateParameters *tpl = NULL; + if (token.value == TOKlparen) + tpl = parseTemplateParameterList(); + check(TOKassign); + Initializer *init = parseInitializer(); + VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init); + v->storage_class = STCmanifest; + Dsymbol *s = v; + if (tpl) + { + Dsymbols *a2 = new Dsymbols(); + a2->push(s); + TemplateDeclaration *tempdecl = + new TemplateDeclaration(loc, ident, tpl, NULL/*constraint*/, a2, 0); + s = tempdecl; + } + a->push(s); + switch (token.value) + { + case TOKsemicolon: + nextToken(); + addComment(s, comment); + break; + case TOKcomma: + nextToken(); + addComment(s, comment); + if (token.value != TOKidentifier) + { + error("Identifier expected following comma, not %s", token.toChars()); + break; + } + if (peekNext() != TOKassign && peekNext() != TOKlparen) + { + error("= expected following identifier"); + nextToken(); + break; + } + continue; + default: + error("semicolon expected to close %s declaration", Token::toChars(tok)); + break; + } + break; + } + return a; + } + break; + } case TOKtypedef: - deprecation("use of typedef is deprecated; use alias instead"); tok = token.value; nextToken(); break; @@ -2982,7 +3103,7 @@ Dsymbols *Parser::parseDeclarations(StorageClass storage_class, unsigned char *c if (peek(&token)->value == TOKlparen) break; if (token.value == TOKinvariant) - deprecation("use of 'invariant' rather than 'immutable' is deprecated"); + error("use 'immutable' instead of 'invariant'"); stc = STCimmutable; goto L1; @@ -3148,7 +3269,7 @@ L2: while (1) { - loc = this->loc; + loc = token.loc; TemplateParameters *tpl = NULL; ident = NULL; @@ -3181,8 +3302,9 @@ L2: init = parseInitializer(); } if (tok == TOKtypedef) - { v = new TypedefDeclaration(loc, ident, t, init); + { deprecation("use of typedef is deprecated; use alias instead"); + v = new TypedefDeclaration(loc, ident, t, init); } else { @@ -3326,12 +3448,13 @@ L2: */ #if DMDV2 -Dsymbols *Parser::parseAutoDeclarations(StorageClass storageClass, unsigned char *comment) +Dsymbols *Parser::parseAutoDeclarations(StorageClass storageClass, utf8_t *comment) { Dsymbols *a = new Dsymbols; while (1) { + Loc loc = token.loc; Identifier *ident = token.ident; nextToken(); // skip over ident assert(token.value == TOKassign); @@ -3371,7 +3494,7 @@ Dsymbols *Parser::parseAutoDeclarations(StorageClass storageClass, unsigned char void Parser::parseContracts(FuncDeclaration *f) { - enum LINK linksave = linkage; + LINK linksave = linkage; // The following is irrelevant, as it is overridden by sc->linkage in // TypeFunction::semantic @@ -3470,7 +3593,7 @@ Initializer *Parser::parseInitializer() Identifier *id; Initializer *value; int comma; - Loc loc = this->loc; + Loc loc = token.loc; Token *t; int braces; int brackets; @@ -3697,18 +3820,18 @@ Expression *Parser::parseDefaultInitExp() { Token *t = peek(&token); if (t->value == TOKcomma || t->value == TOKrparen) - { Expression *e; - + { + Expression *e; if (token.value == TOKfile) - e = new FileInitExp(loc); + e = new FileInitExp(token.loc); else if (token.value == TOKline) - e = new LineInitExp(loc); + e = new LineInitExp(token.loc); else if (token.value == TOKmodulestring) - e = new ModuleInitExp(loc); + e = new ModuleInitExp(token.loc); else if (token.value == TOKfuncstring) - e = new FuncInitExp(loc); + e = new FuncInitExp(token.loc); else if (token.value == TOKprettyfunc) - e = new PrettyFuncInitExp(loc); + e = new PrettyFuncInitExp(token.loc); nextToken(); return e; } @@ -3738,13 +3861,14 @@ void Parser::checkDanglingElse(Loc elseloc) * flags PSxxxx */ -Statement *Parser::parseStatement(int flags, unsigned char** endPtr) -{ Statement *s; +Statement *Parser::parseStatement(int flags, utf8_t** endPtr) +{ + Statement *s; Condition *condition; Statement *ifbody; Statement *elsebody; bool isfinal; - Loc loc = this->loc; + Loc loc = token.loc; //printf("parseStatement()\n"); @@ -3985,7 +4109,7 @@ Statement *Parser::parseStatement(int flags, unsigned char** endPtr) statements->push(parseStatement(PSsemi | PScurlyscope)); } if (endPtr) *endPtr = token.ptr; - endloc = this->loc; + endloc = token.loc; s = new CompoundStatement(loc, statements); if (flags & (PSscope | PScurlyscope)) s = new ScopeStatement(loc, s); @@ -4080,15 +4204,13 @@ Statement *Parser::parseStatement(int flags, unsigned char** endPtr) } body = parseStatement(PSscope); s = new ForStatement(loc, init, condition, increment, body); - if (init) - s = new ScopeStatement(loc, s); break; } case TOKforeach: case TOKforeach_reverse: { - enum TOK op = token.value; + TOK op = token.value; nextToken(); check(TOKlparen); @@ -4133,7 +4255,7 @@ Statement *Parser::parseStatement(int flags, unsigned char** endPtr) { stc = STCimmutable; if (token.value == TOKinvariant) - deprecation("use of 'invariant' rather than 'immutable' is deprecated"); + error("use 'immutable' instead of 'invariant'"); goto Lagain; } break; @@ -4199,7 +4321,8 @@ Statement *Parser::parseStatement(int flags, unsigned char** endPtr) } case TOKif: - { Parameter *arg = NULL; + { + Parameter *arg = NULL; Expression *condition; Statement *ifbody; Statement *elsebody; @@ -4239,7 +4362,7 @@ Statement *Parser::parseStatement(int flags, unsigned char** endPtr) { stc = STCimmutable; if (token.value == TOKinvariant) - deprecation("use of 'invariant' rather than 'immutable' is deprecated"); + error("use 'immutable' instead of 'invariant'"); goto LagainStc; } break; @@ -4290,6 +4413,8 @@ Statement *Parser::parseStatement(int flags, unsigned char** endPtr) } condition = parseExpression(); + if (condition->op == TOKassign) + error("assignment cannot be used as a condition, perhaps == was meant?"); check(TOKrparen); { Loc lookingForElseSave = lookingForElse; @@ -4299,7 +4424,7 @@ Statement *Parser::parseStatement(int flags, unsigned char** endPtr) } if (token.value == TOKelse) { - Loc elseloc = this->loc; + Loc elseloc = token.loc; nextToken(); elsebody = parseStatement(PSscope); checkDanglingElse(elseloc); @@ -4361,7 +4486,7 @@ Statement *Parser::parseStatement(int flags, unsigned char** endPtr) elsebody = NULL; if (token.value == TOKelse) { - Loc elseloc = this->loc; + Loc elseloc = token.loc; nextToken(); elsebody = parseStatement(0 /*PSsemi*/); checkDanglingElse(elseloc); @@ -4628,7 +4753,7 @@ Statement *Parser::parseStatement(int flags, unsigned char** endPtr) Catch *c; Type *t; Identifier *id; - Loc loc = this->loc; + Loc loc = token.loc; nextToken(); if (token.value == TOKlcurly || token.value != TOKlparen) @@ -4714,7 +4839,7 @@ Statement *Parser::parseStatement(int flags, unsigned char** endPtr) if (t->value == TOKcolon) { // It's a label label = token.ident; - labelloc = this->loc; + labelloc = token.loc; nextToken(); nextToken(); continue; @@ -4745,8 +4870,9 @@ Statement *Parser::parseStatement(int flags, unsigned char** endPtr) s = NULL; if (toklist || label) - { // Create AsmStatement from list of tokens we've saved - s = new AsmStatement(this->loc, toklist); + { + // Create AsmStatement from list of tokens we've saved + s = new AsmStatement(token.loc, toklist); toklist = NULL; ptoklist = &toklist; if (label) @@ -4813,19 +4939,19 @@ Statement *Parser::parseStatement(int flags, unsigned char** endPtr) return s; } -void Parser::check(enum TOK value) +void Parser::check(TOK value) { - check(loc, value); + check(token.loc, value); } -void Parser::check(Loc loc, enum TOK value) +void Parser::check(Loc loc, TOK value) { if (token.value != value) error(loc, "found '%s' when expecting '%s'", token.toChars(), Token::toChars(value)); nextToken(); } -void Parser::check(enum TOK value, const char *string) +void Parser::check(TOK value, const char *string) { if (token.value != value) error("found '%s' when expecting '%s' following %s", @@ -4833,10 +4959,10 @@ void Parser::check(enum TOK value, const char *string) nextToken(); } -void Parser::checkParens(enum TOK value, Expression *e) +void Parser::checkParens(TOK value, Expression *e) { if (precedence[e->op] == PREC_rel && !e->parens) - error(loc, "%s must be parenthesized when next to operator %s", e->toChars(), Token::toChars(value)); + error(e->loc, "%s must be parenthesized when next to operator %s", e->toChars(), Token::toChars(value)); } /************************************ @@ -4849,7 +4975,7 @@ void Parser::checkParens(enum TOK value, Expression *e) * if *pt is not NULL, it is set to the ending token, which would be endtok */ -int Parser::isDeclaration(Token *t, int needId, enum TOK endtok, Token **pt) +int Parser::isDeclaration(Token *t, int needId, TOK endtok, Token **pt) { //printf("isDeclaration(needId = %d)\n", needId); int haveId = 0; @@ -4905,7 +5031,6 @@ int Parser::isBasicType(Token **pt) { // This code parallels parseBasicType() Token *t = *pt; - int haveId = 0; switch (t->value) { @@ -5024,7 +5149,7 @@ Lfalse: return FALSE; } -int Parser::isDeclarator(Token **pt, int *haveId, int *haveTpl, enum TOK endtok) +int Parser::isDeclarator(Token **pt, int *haveId, int *haveTpl, TOK endtok) { // This code parallels parseDeclarator() Token *t = *pt; int parens; @@ -5534,11 +5659,12 @@ int Parser::skipAttributes(Token *t, Token **pt) /********************************* Expression Parser ***************************/ Expression *Parser::parsePrimaryExp() -{ Expression *e; +{ + Expression *e; Type *t; Identifier *id; - enum TOK save; - Loc loc = this->loc; + TOK save; + Loc loc = token.loc; //printf("parsePrimaryExp(): loc = %d\n", loc.linnum); switch (token.value) @@ -5658,7 +5784,8 @@ Expression *Parser::parsePrimaryExp() break; case TOKmodulestring: - { const char *s = md->toChars(); + { + const char *s = md ? md->toChars() : mod->toChars(); e = new StringExp(loc, (char *)s, strlen(s), 0); nextToken(); break; @@ -5703,7 +5830,7 @@ Expression *Parser::parsePrimaryExp() case TOKstring: { // cat adjacent strings - unsigned char *s = token.ustring; + utf8_t *s = token.ustring; size_t len = token.len; unsigned char postfix = token.postfix; while (1) @@ -5720,9 +5847,9 @@ Expression *Parser::parsePrimaryExp() size_t len1 = len; size_t len2 = token.len; len = len1 + len2; - unsigned char *s2 = (unsigned char *)mem.malloc((len + 1) * sizeof(unsigned char)); - memcpy(s2, s, len1 * sizeof(unsigned char)); - memcpy(s2 + len1, token.ustring, (len2 + 1) * sizeof(unsigned char)); + utf8_t *s2 = (utf8_t *)mem.malloc((len + 1) * sizeof(utf8_t)); + memcpy(s2, s, len1 * sizeof(utf8_t)); + memcpy(s2 + len1, token.ustring, (len2 + 1) * sizeof(utf8_t)); s = s2; } else @@ -5761,7 +5888,7 @@ Expression *Parser::parsePrimaryExp() { nextToken(); check(TOKlparen, "typeid"); - Object *o; + RootObject *o; if (isDeclaration(&token, 0, TOKreserved, NULL)) { // argument is a type o = parseType(); @@ -5801,13 +5928,14 @@ Expression *Parser::parsePrimaryExp() #endif case TOKis: - { Type *targ; + { + Type *targ; Identifier *ident = NULL; Type *tspec = NULL; - enum TOK tok = TOKreserved; - enum TOK tok2 = TOKreserved; + TOK tok = TOKreserved; + TOK tok2 = TOKreserved; TemplateParameters *tpl = NULL; - Loc loc = this->loc; + Loc loc = token.loc; nextToken(); if (token.value == TOKlparen) @@ -5839,9 +5967,12 @@ Expression *Parser::parsePrimaryExp() token.value == TOKdelegate || token.value == TOKreturn)) { - if (token.value == TOKinvariant) - deprecation("use of 'invariant' rather than 'immutable' is deprecated"); tok2 = token.value; + if (token.value == TOKinvariant) + { + error("use 'immutable' instead of 'invariant'"); + tok2 = TOKimmutable; + } nextToken(); } else @@ -5904,11 +6035,15 @@ Expression *Parser::parsePrimaryExp() break; } + case TOKnew: + e = parseNewExp(NULL); + break; + case TOKlparen: { Token *tk = peekPastParen(&token); if (skipAttributes(tk, &tk)) { - enum TOK past = tk->value; + TOK past = tk->value; if (past == TOKgoesto) { // (arguments) => expression goto case_delegate; @@ -5974,8 +6109,8 @@ Expression *Parser::parsePrimaryExp() int varargs = 0; Type *tret = NULL; StorageClass stc = 0; - enum TOK save = TOKreserved; - Loc loc = this->loc; + TOK save = TOKreserved; + Loc loc = token.loc; switch (token.value) { @@ -6002,7 +6137,6 @@ Expression *Parser::parsePrimaryExp() /* fall through to TOKlparen */ case TOKlparen: - Lparen: { // (parameters) => expression // (parameters) { statements... } parameters = parseParameters(&varargs, &tpl); @@ -6041,10 +6175,10 @@ Expression *Parser::parsePrimaryExp() if (token.value == TOKgoesto) { check(TOKgoesto); - Loc loc = this->loc; + Loc loc = token.loc; Expression *ae = parseAssignExp(); fd->fbody = new ReturnStatement(loc, ae); - fd->endloc = this->loc; + fd->endloc = token.loc; } else { @@ -6081,7 +6215,7 @@ Expression *Parser::parsePostExp(Expression *e) while (1) { - loc = this->loc; + loc = token.loc; switch (token.value) { case TOKdot: @@ -6092,7 +6226,6 @@ Expression *Parser::parsePostExp(Expression *e) nextToken(); if (token.value == TOKnot && peekNext() != TOKis && peekNext() != TOKin) { // identifier!(template-argument-list) - TemplateInstance *tempinst = new TemplateInstance(loc, id); Objects *tiargs; nextToken(); if (token.value == TOKlparen) @@ -6185,8 +6318,9 @@ Expression *Parser::parsePostExp(Expression *e) } Expression *Parser::parseUnaryExp() -{ Expression *e; - Loc loc = this->loc; +{ + Expression *e; + Loc loc = token.loc; switch (token.value) { @@ -6246,10 +6380,6 @@ Expression *Parser::parseUnaryExp() e = new DeleteExp(loc, e); break; - case TOKnew: - e = parseNewExp(NULL); - break; - case TOKcast: // cast(type) expression { nextToken(); @@ -6271,7 +6401,7 @@ Expression *Parser::parseUnaryExp() else if ((token.value == TOKimmutable || token.value == TOKinvariant) && peekNext() == TOKrparen) { if (token.value == TOKinvariant) - deprecation("use of 'invariant' rather than 'immutable' is deprecated"); + error("use 'immutable' instead of 'invariant'"); m = MODimmutable; goto Lmod2; } @@ -6417,8 +6547,9 @@ Expression *Parser::parseUnaryExp() // or .identifier!( ... ) if (token.value == TOKdot) { - if (peekNext() != TOKidentifier) - { error("Identifier expected following (type)."); + if (peekNext() != TOKidentifier && peekNext() != TOKnew) + { + error("identifier or new keyword expected following (...)."); return NULL; } e = new TypeExp(loc, t); @@ -6460,9 +6591,10 @@ Expression *Parser::parseUnaryExp() } Expression *Parser::parseMulExp() -{ Expression *e; +{ + Expression *e; Expression *e2; - Loc loc = this->loc; + Loc loc = token.loc; e = parseUnaryExp(); while (1) @@ -6482,9 +6614,10 @@ Expression *Parser::parseMulExp() } Expression *Parser::parseAddExp() -{ Expression *e; +{ + Expression *e; Expression *e2; - Loc loc = this->loc; + Loc loc = token.loc; e = parseMulExp(); while (1) @@ -6504,9 +6637,10 @@ Expression *Parser::parseAddExp() } Expression *Parser::parseShiftExp() -{ Expression *e; +{ + Expression *e; Expression *e2; - Loc loc = this->loc; + Loc loc = token.loc; e = parseAddExp(); while (1) @@ -6527,10 +6661,11 @@ Expression *Parser::parseShiftExp() #if DMDV1 Expression *Parser::parseRelExp() -{ Expression *e; +{ + Expression *e; Expression *e2; - enum TOK op; - Loc loc = this->loc; + TOK op; + Loc loc = token.loc; e = parseShiftExp(); while (1) @@ -6584,14 +6719,15 @@ Expression *Parser::parseRelExp() #if DMDV1 Expression *Parser::parseEqualExp() -{ Expression *e; +{ + Expression *e; Expression *e2; Token *t; - Loc loc = this->loc; + Loc loc = token.loc; e = parseRelExp(); while (1) - { enum TOK value = token.value; + { TOK value = token.value; switch (value) { @@ -6639,13 +6775,14 @@ Expression *Parser::parseEqualExp() #endif Expression *Parser::parseCmpExp() -{ Expression *e; +{ + Expression *e; Expression *e2; Token *t; - Loc loc = this->loc; + Loc loc = token.loc; e = parseShiftExp(); - enum TOK op = token.value; + TOK op = token.value; switch (op) { @@ -6715,7 +6852,7 @@ Expression *Parser::parseCmpExp() Expression *Parser::parseAndExp() { - Loc loc = this->loc; + Loc loc = token.loc; Expression *e = parseCmpExp(); while (token.value == TOKand) @@ -6725,14 +6862,14 @@ Expression *Parser::parseAndExp() Expression *e2 = parseCmpExp(); checkParens(TOKand, e2); e = new AndExp(loc,e,e2); - loc = this->loc; + loc = token.loc; } return e; } Expression *Parser::parseXorExp() { - Loc loc = this->loc; + Loc loc = token.loc; Expression *e = parseAndExp(); while (token.value == TOKxor) @@ -6748,7 +6885,7 @@ Expression *Parser::parseXorExp() Expression *Parser::parseOrExp() { - Loc loc = this->loc; + Loc loc = token.loc; Expression *e = parseXorExp(); while (token.value == TOKor) @@ -6763,9 +6900,10 @@ Expression *Parser::parseOrExp() } Expression *Parser::parseAndAndExp() -{ Expression *e; +{ + Expression *e; Expression *e2; - Loc loc = this->loc; + Loc loc = token.loc; e = parseOrExp(); while (token.value == TOKandand) @@ -6778,9 +6916,10 @@ Expression *Parser::parseAndAndExp() } Expression *Parser::parseOrOrExp() -{ Expression *e; +{ + Expression *e; Expression *e2; - Loc loc = this->loc; + Loc loc = token.loc; e = parseAndAndExp(); while (token.value == TOKoror) @@ -6793,10 +6932,11 @@ Expression *Parser::parseOrOrExp() } Expression *Parser::parseCondExp() -{ Expression *e; +{ + Expression *e; Expression *e1; Expression *e2; - Loc loc = this->loc; + Loc loc = token.loc; e = parseOrOrExp(); if (token.value == TOKquestion) @@ -6811,14 +6951,15 @@ Expression *Parser::parseCondExp() } Expression *Parser::parseAssignExp() -{ Expression *e; +{ + Expression *e; Expression *e2; Loc loc; e = parseCondExp(); while (1) { - loc = this->loc; + loc = token.loc; switch (token.value) { #define X(tok,ector) \ @@ -6849,9 +6990,10 @@ Expression *Parser::parseAssignExp() } Expression *Parser::parseExpression() -{ Expression *e; +{ + Expression *e; Expression *e2; - Loc loc = this->loc; + Loc loc = token.loc; //printf("Parser::parseExpression() loc = %d\n", loc.linnum); e = parseAssignExp(); @@ -6860,7 +7002,7 @@ Expression *Parser::parseExpression() nextToken(); e2 = parseAssignExp(); e = new CommaExp(loc, e, e2); - loc = this->loc; + loc = token.loc; } return e; } @@ -6875,7 +7017,7 @@ Expressions *Parser::parseArguments() { // function call Expressions *arguments; Expression *arg; - enum TOK endtok; + TOK endtok; arguments = new Expressions(); if (token.value == TOKlbracket) @@ -6902,11 +7044,12 @@ Expressions *Parser::parseArguments() */ Expression *Parser::parseNewExp(Expression *thisexp) -{ Type *t; +{ + Type *t; Expressions *newargs; Expressions *arguments = NULL; Expression *e; - Loc loc = this->loc; + Loc loc = token.loc; nextToken(); newargs = NULL; @@ -6988,7 +7131,7 @@ Expression *Parser::parseNewExp(Expression *thisexp) /********************************************** */ -void Parser::addComment(Dsymbol *s, unsigned char *blockComment) +void Parser::addComment(Dsymbol *s, utf8_t *blockComment) { s->addComment(combineComments(blockComment, token.lineComment)); token.lineComment = NULL; @@ -6999,7 +7142,7 @@ void Parser::addComment(Dsymbol *s, unsigned char *blockComment) * Set operator precedence for each operator. */ -enum PREC precedence[TOKMAX]; +PREC precedence[TOKMAX]; void initPrecedence() { @@ -7024,6 +7167,7 @@ void initPrecedence() precedence[TOKstring] = PREC_primary; precedence[TOKarrayliteral] = PREC_primary; precedence[TOKassocarrayliteral] = PREC_primary; + precedence[TOKclassreference] = PREC_primary; #if DMDV2 precedence[TOKfile] = PREC_primary; precedence[TOKline] = PREC_primary; diff --git a/dmd2/parse.h b/dmd2/parse.h index 946b9570..cb5cf662 100644 --- a/dmd2/parse.h +++ b/dmd2/parse.h @@ -19,32 +19,32 @@ #include "lexer.h" #include "enum.h" -struct Type; -struct TypeQualified; -struct Expression; -struct Declaration; -struct Statement; -struct Import; -struct Initializer; -struct FuncDeclaration; -struct CtorDeclaration; -struct PostBlitDeclaration; -struct DtorDeclaration; -struct StaticCtorDeclaration; -struct StaticDtorDeclaration; -struct SharedStaticCtorDeclaration; -struct SharedStaticDtorDeclaration; -struct ConditionalDeclaration; -struct InvariantDeclaration; -struct UnitTestDeclaration; -struct NewDeclaration; -struct DeleteDeclaration; -struct Condition; -struct Module; +class Type; +class TypeQualified; +class Expression; +class Declaration; +class Statement; +class Import; +class Initializer; +class FuncDeclaration; +class CtorDeclaration; +class PostBlitDeclaration; +class DtorDeclaration; +class StaticCtorDeclaration; +class StaticDtorDeclaration; +class SharedStaticCtorDeclaration; +class SharedStaticDtorDeclaration; +class ConditionalDeclaration; +class InvariantDeclaration; +class UnitTestDeclaration; +class NewDeclaration; +class DeleteDeclaration; +class Condition; +class Module; struct ModuleDeclaration; -struct TemplateDeclaration; -struct TemplateInstance; -struct StaticAssert; +class TemplateDeclaration; +class TemplateInstance; +class StaticAssert; /************************************ * These control how parseStatement() works. @@ -60,19 +60,20 @@ enum ParseStatementFlags }; -struct Parser : Lexer +class Parser : public Lexer { +public: ModuleDeclaration *md; - enum LINK linkage; + LINK linkage; Loc endloc; // set to location of last right curly int inBrackets; // inside [] of array index or slice Loc lookingForElse; // location of lonely if looking for an else - Parser(Module *module, unsigned char *base, size_t length, int doDocComment); + Parser(Module *module, utf8_t *base, size_t length, int doDocComment); Dsymbols *parseModule(); Dsymbols *parseDeclDefs(int once, Dsymbol **pLastDecl = NULL); - Dsymbols *parseAutoDeclarations(StorageClass storageClass, unsigned char *comment); + Dsymbols *parseAutoDeclarations(StorageClass storageClass, utf8_t *comment); Dsymbols *parseBlock(Dsymbol **pLastDecl); void composeStorageClass(StorageClass stc); StorageClass parseAttribute(Expressions **pexps); @@ -88,7 +89,7 @@ struct Parser : Lexer StaticAssert *parseStaticAssert(); TypeQualified *parseTypeof(); Type *parseVector(); - enum LINK parseLinkage(); + LINK parseLinkage(); Condition *parseDebugCondition(); Condition *parseVersionCondition(); Condition *parseStaticIfCondition(); @@ -111,20 +112,20 @@ struct Parser : Lexer Type *parseBasicType(); Type *parseBasicType2(Type *t); Type *parseDeclarator(Type *t, Identifier **pident, TemplateParameters **tpl = NULL, StorageClass storage_class = 0, int* pdisable = NULL); - Dsymbols *parseDeclarations(StorageClass storage_class, unsigned char *comment); + Dsymbols *parseDeclarations(StorageClass storage_class, utf8_t *comment); void parseContracts(FuncDeclaration *f); void checkDanglingElse(Loc elseloc); /** endPtr used for documented unittests */ - Statement *parseStatement(int flags, unsigned char** endPtr = NULL); + Statement *parseStatement(int flags, utf8_t** endPtr = NULL); Initializer *parseInitializer(); Expression *parseDefaultInitExp(); - void check(Loc loc, enum TOK value); - void check(enum TOK value); - void check(enum TOK value, const char *string); - void checkParens(enum TOK value, Expression *e); - int isDeclaration(Token *t, int needId, enum TOK endtok, Token **pt); + void check(Loc loc, TOK value); + void check(TOK value); + void check(TOK value, const char *string); + void checkParens(TOK value, Expression *e); + int isDeclaration(Token *t, int needId, TOK endtok, Token **pt); int isBasicType(Token **pt); - int isDeclarator(Token **pt, int *haveId, int *haveTpl, enum TOK endtok); + int isDeclarator(Token **pt, int *haveId, int *haveTpl, TOK endtok); int isParameters(Token **pt); int isExpression(Token **pt); int skipParens(Token *t, Token **pt); @@ -154,7 +155,7 @@ struct Parser : Lexer Expression *parseNewExp(Expression *thisexp); - void addComment(Dsymbol *s, unsigned char *blockComment); + void addComment(Dsymbol *s, utf8_t *blockComment); }; // Operator precedence - greater values are higher precedence @@ -180,7 +181,7 @@ enum PREC PREC_primary, }; -extern enum PREC precedence[TOKMAX]; +extern PREC precedence[TOKMAX]; void initPrecedence(); diff --git a/dmd2/root/aav.c b/dmd2/root/aav.c index 7a515a13..17054938 100644 --- a/dmd2/root/aav.c +++ b/dmd2/root/aav.c @@ -14,20 +14,17 @@ #include #include +#include #include #include "aav.h" -static const size_t prime_list[] = { - 31UL, - 97UL, 389UL, - 1543UL, 6151UL, - 24593UL, 98317UL, - 393241UL, 1572869UL, - 6291469UL, 25165843UL, - 100663319UL, 402653189UL, - 1610612741UL, 4294967291UL, -}; + +inline size_t hash(size_t a) +{ + a ^= (a >> 20) ^ (a >> 12); + return a ^ (a >> 7) ^ (a >> 4); +} struct aaA { @@ -42,9 +39,9 @@ struct AA size_t b_length; size_t nodes; // total number of aaA nodes aaA* binit[4]; // initial value of b[] -}; -static const AA bbinit = { NULL, }; + aaA aafirst; // a lot of these AA's have only one entry +}; /**************************************************** * Determine number of entries in associative array. @@ -67,16 +64,20 @@ Value* _aaGet(AA** paa, Key key) if (!*paa) { AA *a = new AA(); - *a = bbinit; a->b = a->binit; a->b_length = sizeof(a->binit) / sizeof(a->binit[0]); + a->nodes = 0; + a->binit[0] = NULL; + a->binit[1] = NULL; + a->binit[2] = NULL; + a->binit[3] = NULL; *paa = a; assert((*paa)->b_length == 4); } //printf("paa = %p, *paa = %p\n", paa, *paa); assert((*paa)->b_length); - size_t i = (size_t)key % (*paa)->b_length; + size_t i = hash((size_t)key) & ((*paa)->b_length - 1); aaA** pe = &(*paa)->b[i]; aaA *e; while ((e = *pe) != NULL) @@ -88,15 +89,17 @@ Value* _aaGet(AA** paa, Key key) // Not found, create new elem //printf("create new one\n"); - e = new aaA(); + + size_t nodes = ++(*paa)->nodes; + e = (nodes != 1) ? new aaA() : &(*paa)->aafirst; + //e = new aaA(); e->next = NULL; e->key = key; e->value = NULL; *pe = e; - size_t nodes = ++(*paa)->nodes; - //printf("length = %d, nodes = %d\n", paa.a.b.length, nodes); - if (nodes > (*paa)->b_length * 4) + //printf("length = %d, nodes = %d\n", (*paa)->b_length, nodes); + if (nodes > (*paa)->b_length * 2) { //printf("rehash\n"); _aaRehash(paa); @@ -114,14 +117,11 @@ Value* _aaGet(AA** paa, Key key) Value _aaGetRvalue(AA* aa, Key key) { //printf("_aaGetRvalue(key = %p)\n", key); - if (!aa) - return NULL; - - size_t len = aa->b_length; - - if (len) + if (aa) { - size_t i = (size_t)key % len; + size_t i; + size_t len = aa->b_length; + i = hash((size_t)key) & (len-1); aaA* e = aa->b[i]; while (e) { @@ -143,39 +143,33 @@ void _aaRehash(AA** paa) //printf("Rehash\n"); if (*paa) { - AA newb = bbinit; AA *aa = *paa; - size_t len = _aaLen(*paa); - if (len) - { size_t i; - - for (i = 0; i < sizeof(prime_list)/sizeof(prime_list[0]) - 1; i++) - { - if (len <= prime_list[i]) - break; - } - len = prime_list[i]; - newb.b = new aaA*[len]; - memset(newb.b, 0, len * sizeof(aaA*)); - newb.b_length = len; + if (aa) + { + size_t len = aa->b_length; + if (len == 4) + len = 32; + else + len *= 4; + aaA** newb = new aaA*[len]; + memset(newb, 0, len * sizeof(aaA*)); for (size_t k = 0; k < aa->b_length; k++) { aaA *e = aa->b[k]; while (e) { aaA* enext = e->next; - size_t j = (size_t)e->key % len; - e->next = newb.b[j]; - newb.b[j] = e; + size_t j = hash((size_t)e->key) & (len-1); + e->next = newb[j]; + newb[j] = e; e = enext; } } if (aa->b != aa->binit) delete[] aa->b; - newb.nodes = aa->nodes; + aa->b = newb; + aa->b_length = len; } - - **paa = newb; } } diff --git a/dmd2/root/array.c b/dmd2/root/array.c deleted file mode 100644 index 6f949755..00000000 --- a/dmd2/root/array.c +++ /dev/null @@ -1,222 +0,0 @@ - -// Copyright (c) 1999-2013 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include -#include - -#include "port.h" -#include "root.h" -#include "rmem.h" - - -/********************************* Array ****************************/ - -Array::Array() -{ - data = SMALLARRAYCAP ? &smallarray[0] : NULL; - dim = 0; - allocdim = SMALLARRAYCAP; -} - -Array::~Array() -{ - if (data != &smallarray[0]) - mem.free(data); -} - -void Array::mark() -{ - mem.mark(data); - for (size_t u = 0; u < dim; u++) - mem.mark(data[u]); // BUG: what if arrays of Object's? -} - -void Array::reserve(size_t nentries) -{ - //printf("Array::reserve: dim = %d, allocdim = %d, nentries = %d\n", (int)dim, (int)allocdim, (int)nentries); - if (allocdim - dim < nentries) - { - if (allocdim == 0) - { // Not properly initialized, someone memset it to zero - if (nentries <= SMALLARRAYCAP) - { allocdim = SMALLARRAYCAP; - data = SMALLARRAYCAP ? &smallarray[0] : NULL; - } - else - { allocdim = nentries; - data = (void **)mem.malloc(allocdim * sizeof(*data)); - } - } - else if (allocdim == SMALLARRAYCAP) - { - allocdim = dim + nentries; - data = (void **)mem.malloc(allocdim * sizeof(*data)); - memcpy(data, &smallarray[0], dim * sizeof(*data)); - } - else - { allocdim = dim + nentries; - data = (void **)mem.realloc(data, allocdim * sizeof(*data)); - } - } -} - -void Array::setDim(size_t newdim) -{ - if (dim < newdim) - { - reserve(newdim - dim); - } - dim = newdim; -} - -void Array::fixDim() -{ - if (dim != allocdim) - { - if (allocdim >= SMALLARRAYCAP) - { - if (dim <= SMALLARRAYCAP) - { - memcpy(&smallarray[0], data, dim * sizeof(*data)); - mem.free(data); - } - else - data = (void **)mem.realloc(data, dim * sizeof(*data)); - } - allocdim = dim; - } -} - -void Array::push(void *ptr) -{ - reserve(1); - data[dim++] = ptr; -} - -void *Array::pop() -{ - return data[--dim]; -} - -void Array::shift(void *ptr) -{ - reserve(1); - memmove(data + 1, data, dim * sizeof(*data)); - data[0] = ptr; - dim++; -} - -void Array::insert(size_t index, void *ptr) -{ - reserve(1); - memmove(data + index + 1, data + index, (dim - index) * sizeof(*data)); - data[index] = ptr; - dim++; -} - - -void Array::insert(size_t index, Array *a) -{ - if (a) - { - size_t d = a->dim; - reserve(d); - if (dim != index) - memmove(data + index + d, data + index, (dim - index) * sizeof(*data)); - memcpy(data + index, a->data, d * sizeof(*data)); - dim += d; - } -} - - -/*********************************** - * Append array a to this array. - */ - -void Array::append(Array *a) -{ - insert(dim, a); -} - -void Array::remove(size_t i) -{ - if (dim - i - 1) - memmove(data + i, data + i + 1, (dim - i - 1) * sizeof(data[0])); - dim--; -} - -char *Array::toChars() -{ - char **buf = (char **)malloc(dim * sizeof(char *)); - assert(buf); - size_t len = 2; - for (size_t u = 0; u < dim; u++) - { - buf[u] = ((Object *)data[u])->toChars(); - len += strlen(buf[u]) + 1; - } - char *str = (char *)mem.malloc(len); - - str[0] = '['; - char *p = str + 1; - for (size_t u = 0; u < dim; u++) - { - if (u) - *p++ = ','; - len = strlen(buf[u]); - memcpy(p,buf[u],len); - p += len; - } - *p++ = ']'; - *p = 0; - free(buf); - return str; -} - -void Array::zero() -{ - memset(data,0,dim * sizeof(data[0])); -} - -void *Array::tos() -{ - return dim ? data[dim - 1] : NULL; -} - -int -#if _WIN32 - __cdecl -#endif - Array_sort_compare(const void *x, const void *y) -{ - Object *ox = *(Object **)x; - Object *oy = *(Object **)y; - - return ox->compare(oy); -} - -void Array::sort() -{ - if (dim) - { - qsort(data, dim, sizeof(Object *), Array_sort_compare); - } -} - -Array *Array::copy() -{ - Array *a = new Array(); - - a->setDim(dim); - memcpy(a->data, data, dim * sizeof(void *)); - return a; -} - diff --git a/dmd2/root/longdouble.c b/dmd2/root/longdouble.c index 6244c6cb..4c03d8ec 100644 --- a/dmd2/root/longdouble.c +++ b/dmd2/root/longdouble.c @@ -481,9 +481,9 @@ FM1: // We don't use fprem1 because for some inexplicable ////////////////////////////////////////////////////////////// -longdouble ld_qnan = { 0x8000000000000000ULL, 0x7fff, 0 }; -longdouble ld_snan = { 0x0000000000000001ULL, 0x7fff, 0 }; -longdouble ld_inf = { 0x0000000000000000ULL, 0x7fff, 0 }; +longdouble ld_qnan = { 0xC000000000000000ULL, 0x7fff, 0 }; +longdouble ld_snan = { 0xC000000000000001ULL, 0x7fff, 0 }; +longdouble ld_inf = { 0x8000000000000000ULL, 0x7fff, 0 }; longdouble ld_zero = { 0, 0, 0 }; longdouble ld_one = { 0x8000000000000000ULL, 0x3fff, 0 }; diff --git a/dmd2/root/longdouble.h b/dmd2/root/longdouble.h index 8add2787..d5fbf944 100644 --- a/dmd2/root/longdouble.h +++ b/dmd2/root/longdouble.h @@ -13,19 +13,7 @@ #ifndef __LONG_DOUBLE_H__ #define __LONG_DOUBLE_H__ -#if IN_GCC -#include "d-gcc-real.h" -typedef real_t longdouble; - -template longdouble ldouble(T x) { return (longdouble) x; } -inline size_t ld_sprint(char* str, int fmt, longdouble x) -{ - if(fmt == 'a' || fmt == 'A') - return x.formatHex(buffer, 46); // don't know the size here, but 46 is the max - return x.format(buffer, 46); -} - -#elif !_MSC_VER // has native 10 byte doubles +#if !_MSC_VER // has native 10 byte doubles #include typedef long double longdouble; typedef volatile long double volatile_longdouble; @@ -143,8 +131,18 @@ inline longdouble ldouble(unsigned long long mantissa, int exp, int sign = 0) d.sign = sign; return d; } -template inline longdouble ldouble(T x) { longdouble d; d.set(x); return d; } -//template inline longdouble ldouble(volatile T x) { longdouble d; d.set(x); return d; } + +// codegen bug in VS2010/VS2012, if the set() function not inlined +// (this passed on stack, but expected in ECX; RVO?) +#if _MSC_VER >= 1600 +#define LDOUBLE_INLINE __declspec(noinline) +#else +#define LDOUBLE_INLINE inline +#endif + +template LDOUBLE_INLINE longdouble ldouble(T x) { longdouble d; d.set(x); return d; } + +#undef LDOUBLE_INLINE longdouble operator+(longdouble ld1, longdouble ld2); longdouble operator-(longdouble ld1, longdouble ld2); @@ -200,6 +198,7 @@ longdouble tanl (longdouble ld); longdouble fmodl(longdouble x, longdouble y); longdouble ldexpl(longdouble ldval, int exp); // see strtold +longdouble strtold(const char *p,char **endp); inline longdouble fabs (longdouble ld) { return fabsl(ld); } inline longdouble sqrt (longdouble ld) { return sqrtl(ld); } @@ -236,38 +235,6 @@ extern longdouble ld_inf; extern longdouble ld_qnan; extern longdouble ld_snan; -/////////////////////////////////////////////////////////////////////// -// CLASS numeric_limits -template<> class _CRTIMP2_PURE std::numeric_limits -: public _Num_float_base -{ // limits for type long double -public: - typedef longdouble _Ty; - - static _Ty (__CRTDECL min)() _THROW0() { return LDBL_MIN; } - static _Ty (__CRTDECL max)() _THROW0() { return LDBL_MAX; } - static _Ty __CRTDECL epsilon() _THROW0() { return LDBL_EPSILON; } - static _Ty __CRTDECL round_error() _THROW0() { return ldouble(0.5); } - static _Ty __CRTDECL denorm_min() _THROW0() { return ldouble(0x0000000000000001ULL, 1); } - static _Ty __CRTDECL infinity() _THROW0() { return ld_inf; } - static _Ty __CRTDECL quiet_NaN() _THROW0() { return ld_qnan; } - static _Ty __CRTDECL signaling_NaN() _THROW0() { return ld_snan; } - - _STCONS(int, digits, LDBL_MANT_DIG); - _STCONS(int, digits10, LDBL_DIG); - _STCONS(int, max_exponent, (int)LDBL_MAX_EXP); - _STCONS(int, max_exponent10, (int)LDBL_MAX_10_EXP); - _STCONS(int, min_exponent, (int)LDBL_MIN_EXP); - _STCONS(int, min_exponent10, (int)LDBL_MIN_10_EXP); -}; - -//_STCONSDEF(numeric_limits, int, digits) -//_STCONSDEF(numeric_limits, int, digits10) -//_STCONSDEF(numeric_limits, int, max_exponent) -//_STCONSDEF(numeric_limits, int, max_exponent10) -//_STCONSDEF(numeric_limits, int, min_exponent) -//_STCONSDEF(numeric_limits, int, min_exponent10) - size_t ld_sprint(char* str, int fmt, longdouble x); #endif // !_MSC_VER diff --git a/dmd2/root/port.c b/dmd2/root/port.c index 4422809a..bf8ae7c5 100644 --- a/dmd2/root/port.c +++ b/dmd2/root/port.c @@ -16,11 +16,33 @@ #include double Port::nan = NAN; +longdouble Port::ldbl_nan = NAN; +longdouble Port::snan; + double Port::infinity = INFINITY; +longdouble Port::ldbl_infinity = INFINITY; + double Port::dbl_max = DBL_MAX; double Port::dbl_min = DBL_MIN; longdouble Port::ldbl_max = LDBL_MAX; +struct PortInitializer +{ + PortInitializer(); +}; + +static PortInitializer portinitializer; + +PortInitializer::PortInitializer() +{ + union + { unsigned int ui[4]; + longdouble ld; + } snan = {{ 0, 0xA0000000, 0x7FFF, 0 }}; + + Port::snan = snan.ld; +} + int Port::isNan(double r) { return ::isnan(r); @@ -47,68 +69,22 @@ int Port::isSignallingNan(longdouble r) return isNan(r) && !((((unsigned char*)&r)[7]) & 0x40); } -int Port::isFinite(double r) -{ - return ::isfinite(r); -} - int Port::isInfinity(double r) { return (::fpclassify(r) == FP_INFINITE); } -int Port::Signbit(double r) -{ - return ::signbit(r); -} - -double Port::floor(double d) -{ - return ::floor(d); -} - -double Port::pow(double x, double y) -{ - return ::pow(x, y); -} - longdouble Port::fmodl(longdouble x, longdouble y) { return ::fmodl(x, y); } -unsigned long long Port::strtoull(const char *p, char **pend, int base) +int Port::fequal(longdouble x, longdouble y) { - return ::strtoull(p, pend, base); -} - -char *Port::ull_to_string(char *buffer, ulonglong ull) -{ - sprintf(buffer, "%llu", ull); - return buffer; -} - -wchar_t *Port::ull_to_string(wchar_t *buffer, ulonglong ull) -{ - swprintf(buffer, sizeof(ulonglong) * 3 + 1, L"%llu", ull); - return buffer; -} - -double Port::ull_to_double(ulonglong ull) -{ - return (double) ull; -} - -const char *Port::list_separator() -{ - // LOCALE_SLIST for Windows - return ","; -} - -const wchar_t *Port::wlist_separator() -{ - // LOCALE_SLIST for Windows - return L","; + /* In some cases, the REALPAD bytes get garbage in them, + * so be sure and ignore them. + */ + return memcmp(&x, &y, 10) == 0; } char *Port::strupr(char *s) @@ -126,6 +102,36 @@ int Port::stricmp(const char *s1, const char *s2) return ::stricmp(s1, s2); } + +extern "C" const char * __cdecl __locale_decpoint; + +float Port::strtof(const char *buffer, char **endp) +{ + const char *save = __locale_decpoint; + __locale_decpoint = "."; + float result = ::strtof(buffer, endp); + __locale_decpoint = save; + return result; +} + +double Port::strtod(const char *buffer, char **endp) +{ + const char *save = __locale_decpoint; + __locale_decpoint = "."; + double result = ::strtod(buffer, endp); + __locale_decpoint = save; + return result; +} + +longdouble Port::strtold(const char *buffer, char **endp) +{ + const char *save = __locale_decpoint; + __locale_decpoint = "."; + longdouble result = ::strtold(buffer, endp); + __locale_decpoint = save; + return result; +} + #endif #if _MSC_VER @@ -134,7 +140,7 @@ int Port::stricmp(const char *s1, const char *s2) #pragma warning (disable : 4514) #include -#include +#include // for _isnan #include #include #include @@ -143,13 +149,12 @@ int Port::stricmp(const char *s1, const char *s2) #include #include // for std::numeric_limits -static unsigned long nanarray[2]= { 0xFFFFFFFF, 0x7FFFFFFF }; -//static unsigned long nanarray[2] = {0,0x7FF80000 }; -double Port::nan = (*(double *)nanarray); +double Port::nan; +longdouble Port::ldbl_nan; +longdouble Port::snan; -//static unsigned long infinityarray[2] = {0,0x7FF00000 }; -static double zero = 0; -double Port::infinity = 1 / zero; +double Port::infinity; +longdouble Port::ldbl_infinity; double Port::dbl_max = DBL_MAX; double Port::dbl_min = DBL_MIN; @@ -164,7 +169,16 @@ static PortInitializer portinitializer; PortInitializer::PortInitializer() { + union { + unsigned long ul[2]; + double d; + } nan = {{ 0, 0x7FF80000 }}; + + Port::nan = nan.d; + Port::ldbl_nan = ld_qnan; + Port::snan = ld_snan; Port::infinity = std::numeric_limits::infinity(); + Port::ldbl_infinity = ld_inf; } int Port::isNan(double r) @@ -192,145 +206,22 @@ int Port::isSignallingNan(longdouble r) return isSignallingNan((double) r); } -int Port::isFinite(double r) -{ - return ::_finite(r); -} - int Port::isInfinity(double r) { return (::_fpclass(r) & (_FPCLASS_NINF | _FPCLASS_PINF)); } -int Port::Signbit(double r) -{ - return (long)(((long *)&(r))[1] & 0x80000000); -} - -double Port::floor(double d) -{ - return ::floor(d); -} - -double Port::pow(double x, double y) -{ - if (y == 0) - return 1; // even if x is NAN - return ::pow(x, y); -} - longdouble Port::fmodl(longdouble x, longdouble y) { return ::fmodl(x, y); } -unsigned _int64 Port::strtoull(const char *p, char **pend, int base) +int Port::fequal(longdouble x, longdouble y) { - unsigned _int64 number = 0; - int c; - int error; -#ifndef ULLONG_MAX - #define ULLONG_MAX ((unsigned _int64)~0I64) -#endif - - while (isspace((unsigned char)*p)) /* skip leading white space */ - p++; - if (*p == '+') - p++; - switch (base) - { case 0: - base = 10; /* assume decimal base */ - if (*p == '0') - { base = 8; /* could be octal */ - p++; - switch (*p) - { case 'x': - case 'X': - base = 16; /* hex */ - p++; - break; -#if BINARY - case 'b': - case 'B': - base = 2; /* binary */ - p++; - break; -#endif - } - } - break; - case 16: /* skip over '0x' and '0X' */ - if (*p == '0' && (p[1] == 'x' || p[1] == 'X')) - p += 2; - break; -#if BINARY - case 2: /* skip over '0b' and '0B' */ - if (*p == '0' && (p[1] == 'b' || p[1] == 'B')) - p += 2; - break; -#endif - } - error = 0; - for (;;) - { c = *p; - if (isdigit(c)) - c -= '0'; - else if (isalpha(c)) - c = (c & ~0x20) - ('A' - 10); - else /* unrecognized character */ - break; - if (c >= base) /* not in number base */ - break; - if ((ULLONG_MAX - c) / base < number) - error = 1; - number = number * base + c; - p++; - } - if (pend) - *pend = (char *)p; - if (error) - { number = ULLONG_MAX; - errno = ERANGE; - } - return number; -} - -char *Port::ull_to_string(char *buffer, ulonglong ull) -{ - _ui64toa(ull, buffer, 10); - return buffer; -} - -wchar_t *Port::ull_to_string(wchar_t *buffer, ulonglong ull) -{ - _ui64tow(ull, buffer, 10); - return buffer; -} - -double Port::ull_to_double(ulonglong ull) -{ double d; - - if ((__int64) ull < 0) - { - // MSVC doesn't implement the conversion - d = (double) (__int64)(ull - 0x8000000000000000i64); - d += (double)(signed __int64)(0x7FFFFFFFFFFFFFFFi64) + 1.0; - } - else - d = (double)(__int64)ull; - return d; -} - -const char *Port::list_separator() -{ - // LOCALE_SLIST for Windows - return ","; -} - -const wchar_t *Port::wlist_separator() -{ - // LOCALE_SLIST for Windows - return L","; + /* In some cases, the REALPAD bytes get garbage in them, + * so be sure and ignore them. + */ + return memcmp(&x, &y, 10) == 0; } char *Port::strupr(char *s) @@ -348,6 +239,197 @@ int Port::stricmp(const char *s1, const char *s2) return ::stricmp(s1, s2); } +float Port::strtof(const char *p, char **endp) +{ + return static_cast(::strtod(p, endp)); +} + +double Port::strtod(const char *p, char **endp) +{ + return ::strtod(p, endp); +} + +// See backend/strtold.c. +longdouble Port::strtold(const char *p, char **endp) +{ + return ::strtold(p, endp); +} + +#endif + +#if __MINGW32__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +double Port::nan; +longdouble Port::ldbl_nan; +longdouble Port::snan; + +static double zero = 0; +double Port::infinity = 1 / zero; +longdouble Port::ldbl_infinity = 1 / zero; + +double Port::dbl_max = 1.7976931348623157e308; +double Port::dbl_min = 5e-324; +longdouble Port::ldbl_max = LDBL_MAX; + +struct PortInitializer +{ + PortInitializer(); +}; + +static PortInitializer portinitializer; + +PortInitializer::PortInitializer() +{ + union + { unsigned int ui[2]; + double d; + } nan = {{ 0, 0x7FF80000 }}; + + Port::nan = nan.d; + assert(!signbit(Port::nan)); + + union + { unsigned int ui[4]; + longdouble ld; + } ldbl_nan = {{ 0, 0xC0000000, 0x7FFF, 0}}; + + Port::ldbl_nan = ldbl_nan.ld; + assert(!signbit(Port::ldbl_nan)); + + union + { unsigned int ui[4]; + longdouble ld; + } snan = {{ 0, 0xA0000000, 0x7FFF, 0 }}; + + Port::snan = snan.ld; +} + +int Port::isNan(double r) +{ + return isnan(r); +} + +int Port::isNan(longdouble r) +{ + return isnan(r); +} + +int Port::isSignallingNan(double r) +{ + /* A signalling NaN is a NaN with 0 as the most significant bit of + * its significand, which is bit 51 of 0..63 for 64 bit doubles. + */ + return isNan(r) && !((((unsigned char*)&r)[6]) & 8); +} + +int Port::isSignallingNan(longdouble r) +{ + /* A signalling NaN is a NaN with 0 as the most significant bit of + * its significand, which is bit 62 of 0..79 for 80 bit reals. + */ + return isNan(r) && !((((unsigned char*)&r)[7]) & 0x40); +} + +int Port::isInfinity(double r) +{ + return isinf(r); +} + +longdouble Port::fmodl(longdouble x, longdouble y) +{ + return ::fmodl(x, y); +} + +int Port::fequal(longdouble x, longdouble y) +{ + /* In some cases, the REALPAD bytes get garbage in them, + * so be sure and ignore them. + */ + return memcmp(&x, &y, 10) == 0; +} + +char *Port::strupr(char *s) +{ + char *t = s; + + while (*s) + { + *s = toupper(*s); + s++; + } + + return t; +} + +int Port::memicmp(const char *s1, const char *s2, int n) +{ + int result = 0; + + for (int i = 0; i < n; i++) + { char c1 = s1[i]; + char c2 = s2[i]; + + result = c1 - c2; + if (result) + { + result = toupper(c1) - toupper(c2); + if (result) + break; + } + } + return result; +} + +int Port::stricmp(const char *s1, const char *s2) +{ + int result = 0; + + for (;;) + { char c1 = *s1; + char c2 = *s2; + + result = c1 - c2; + if (result) + { + result = toupper(c1) - toupper(c2); + if (result) + break; + } + if (!c1) + break; + s1++; + s2++; + } + return result; +} + +float Port::strtof(const char *p, char **endp) +{ + return ::strtof(p, endp); +} + +double Port::strtod(const char *p, char **endp) +{ + return ::strtod(p, endp); +} + +longdouble Port::strtold(const char *p, char **endp) +{ + return ::__mingw_strtold(p, endp); +} + // See vcbuild/strtold.c. longdouble strtold(const char *p, char **endp); @@ -557,14 +639,20 @@ longdouble Port::strtold(const char *p, char **endp) #include #include #include +#include #include #include #include #include +double Port::nan; +longdouble Port::ldbl_nan; +longdouble Port::snan; + static double zero = 0; -double Port::nan = copysign(NAN, 1.0); double Port::infinity = 1 / zero; +longdouble Port::ldbl_infinity = 1 / zero; + double Port::dbl_max = 1.7976931348623157e308; double Port::dbl_min = 5e-324; longdouble Port::ldbl_max = LDBL_MAX; @@ -578,8 +666,29 @@ static PortInitializer portinitializer; PortInitializer::PortInitializer() { + union + { unsigned int ui[2]; + double d; + } nan = {{ 0, 0x7FF80000 }}; + + Port::nan = nan.d; assert(!signbit(Port::nan)); + union + { unsigned int ui[4]; + longdouble ld; + } ldbl_nan = {{ 0, 0xC0000000, 0x7FFF, 0}}; + + Port::ldbl_nan = ldbl_nan.ld; + assert(!signbit(Port::ldbl_nan)); + + union + { unsigned int ui[4]; + longdouble ld; + } snan = {{ 0, 0xA0000000, 0x7FFF, 0 }}; + + Port::snan = snan.ld; + #if __FreeBSD__ && __i386__ // LDBL_MAX comes out as infinity. Fix. static unsigned char x[sizeof(longdouble)] = @@ -640,14 +749,6 @@ int Port::isSignallingNan(longdouble r) return isNan(r) && !((((unsigned char*)&r)[7]) & 0x40); } -#undef isfinite -int Port::isFinite(double r) -{ - return ::finite(r); -} - -#if !defined __HAIKU__ -#endif int Port::isInfinity(double r) { #if __APPLE__ @@ -660,24 +761,6 @@ int Port::isInfinity(double r) #endif } -#undef signbit -int Port::Signbit(double r) -{ - union { double d; long long ll; } u; - u.d = r; - return u.ll < 0; -} - -double Port::floor(double d) -{ - return ::floor(d); -} - -double Port::pow(double x, double y) -{ - return ::pow(x, y); -} - longdouble Port::fmodl(longdouble x, longdouble y) { #if __FreeBSD__ || __OpenBSD__ @@ -687,40 +770,12 @@ longdouble Port::fmodl(longdouble x, longdouble y) #endif } -unsigned long long Port::strtoull(const char *p, char **pend, int base) +int Port::fequal(longdouble x, longdouble y) { - return ::strtoull(p, pend, base); -} - -char *Port::ull_to_string(char *buffer, ulonglong ull) -{ - sprintf(buffer, "%llu", ull); - return buffer; -} - -wchar_t *Port::ull_to_string(wchar_t *buffer, ulonglong ull) -{ -#if __OpenBSD__ - assert(0); -#else - swprintf(buffer, sizeof(ulonglong) * 3 + 1, L"%llu", ull); -#endif - return buffer; -} - -double Port::ull_to_double(ulonglong ull) -{ - return (double) ull; -} - -const char *Port::list_separator() -{ - return ","; -} - -const wchar_t *Port::wlist_separator() -{ - return L","; + /* In some cases, the REALPAD bytes get garbage in them, + * so be sure and ignore them. + */ + return memcmp(&x, &y, 10) == 0; } char *Port::strupr(char *s) @@ -778,6 +833,16 @@ int Port::stricmp(const char *s1, const char *s2) return result; } +float Port::strtof(const char *p, char **endp) +{ + return ::strtof(p, endp); +} + +double Port::strtod(const char *p, char **endp) +{ + return ::strtod(p, endp); +} + longdouble Port::strtold(const char *p, char **endp) { return ::strtold(p, endp); @@ -794,14 +859,20 @@ longdouble Port::strtold(const char *p, char **endp) #include #include #include +#include #include #include #include #include +double Port::nan; +longdouble Port::ldbl_nan; +longdouble Port::snan; + static double zero = 0; -double Port::nan = NAN; double Port::infinity = 1 / zero; +longdouble Port::ldbl_infinity = 1 / zero; + double Port::dbl_max = 1.7976931348623157e308; double Port::dbl_min = 5e-324; longdouble Port::ldbl_max = LDBL_MAX; @@ -815,14 +886,28 @@ static PortInitializer portinitializer; PortInitializer::PortInitializer() { - // gcc nan's have the sign bit set by default, so turn it off - // Need the volatile to prevent gcc from doing incorrect - // constant folding. - volatile longdouble foo; - foo = NAN; - if (signbit(foo)) // signbit sometimes, not always, set - foo = -foo; // turn off sign bit - Port::nan = foo; + union + { unsigned int ui[2]; + double d; + } nan = {{ 0, 0x7FF80000 }}; + + Port::nan = nan.d; + assert(!signbit(Port::nan)); + + union + { unsigned int ui[4]; + longdouble ld; + } ldbl_nan = {{ 0, 0xC0000000, 0x7FFF, 0}}; + + Port::ldbl_nan = ldbl_nan.ld; + assert(!signbit(Port::ldbl_nan)); + + union + { unsigned int ui[4]; + longdouble ld; + } snan = {{ 0, 0xA0000000, 0x7FFF, 0 }}; + + Port::snan = snan.ld; } int Port::isNan(double r) @@ -851,68 +936,22 @@ int Port::isSignallingNan(longdouble r) return isNan(r) && !((((unsigned char*)&r)[7]) & 0x40); } -#undef isfinite -int Port::isFinite(double r) -{ - return finite(r); -} - int Port::isInfinity(double r) { return isinf(r); } -#undef signbit -int Port::Signbit(double r) -{ - return (long)(((long *)&r)[1] & 0x80000000); -} - -double Port::floor(double d) -{ - return ::floor(d); -} - -double Port::pow(double x, double y) -{ - return ::pow(x, y); -} - longdouble Port::fmodl(longdouble x, longdouble y) { return ::fmodl(x, y); } -unsigned long long Port::strtoull(const char *p, char **pend, int base) +int Port::fequal(longdouble x, longdouble y) { - return ::strtoull(p, pend, base); -} - -char *Port::ull_to_string(char *buffer, ulonglong ull) -{ - sprintf(buffer, "%llu", ull); - return buffer; -} - -wchar_t *Port::ull_to_string(wchar_t *buffer, ulonglong ull) -{ - swprintf(buffer, sizeof(ulonglong) * 3 + 1, L"%llu", ull); - return buffer; -} - -double Port::ull_to_double(ulonglong ull) -{ - return (double) ull; -} - -const char *Port::list_separator() -{ - return ","; -} - -const wchar_t *Port::wlist_separator() -{ - return L","; + /* In some cases, the REALPAD bytes get garbage in them, + * so be sure and ignore them. + */ + return memcmp(&x, &y, 10) == 0; } char *Port::strupr(char *s) @@ -928,6 +967,21 @@ char *Port::strupr(char *s) return t; } +float Port::strtof(const char *p, char **endp) +{ + return ::strtof(p, endp); +} + +double Port::strtod(const char *p, char **endp) +{ + return ::strtod(p, endp); +} + +longdouble Port::strtold(const char *p, char **endp) +{ + return ::strtold(p, endp); +} + longdouble Port::strtold(const char *p, char **endp) { return ::strtold(p, endp); diff --git a/dmd2/root/port.h b/dmd2/root/port.h index 41c2aaff..399cf2da 100644 --- a/dmd2/root/port.h +++ b/dmd2/root/port.h @@ -13,15 +13,13 @@ #if defined(IN_LLVM) && (LDC_LLVM_VER >= 303) #include "llvm/Config/config.h" #endif +#include // for alloca +#include #include "longdouble.h" #if _MSC_VER -#include // for _isnan -#include // for alloca -#define strtof strtod -#define isnan _isnan - +#include typedef __int64 longlong; typedef unsigned __int64 ulonglong; #else @@ -29,12 +27,17 @@ typedef long long longlong; typedef unsigned long long ulonglong; #endif -typedef double d_time; +typedef unsigned char utf8_t; struct Port { static double nan; + static longdouble ldbl_nan; + static longdouble snan; + static double infinity; + static longdouble ldbl_infinity; + static double dbl_max; static double dbl_min; static longdouble ldbl_max; @@ -45,32 +48,18 @@ struct Port static int isSignallingNan(double); static int isSignallingNan(longdouble); - static int isFinite(double); static int isInfinity(double); - static int Signbit(double); - - static double floor(double); - static double pow(double x, double y); static longdouble fmodl(longdouble x, longdouble y); - - static ulonglong strtoull(const char *p, char **pend, int base); - - static char *ull_to_string(char *buffer, ulonglong ull); - static wchar_t *ull_to_string(wchar_t *buffer, ulonglong ull); - - // Convert ulonglong to double - static double ull_to_double(ulonglong ull); - - // Get locale-dependent list separator - static const char *list_separator(); - static const wchar_t *wlist_separator(); + static int fequal(longdouble x, longdouble y); static char *strupr(char *); static int memicmp(const char *s1, const char *s2, int n); static int stricmp(const char *s1, const char *s2); + static float strtof(const char *p, char **endp); + static double strtod(const char *p, char **endp); static longdouble strtold(const char *p, char **endp); }; diff --git a/dmd2/root/rmem.c b/dmd2/root/rmem.c index ce6b3e0d..2024e117 100644 --- a/dmd2/root/rmem.c +++ b/dmd2/root/rmem.c @@ -11,11 +11,7 @@ #include #include -#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun -#include "../root/rmem.h" -#else #include "rmem.h" -#endif /* This implementation of the storage allocator uses the standard C allocation package. */ @@ -142,6 +138,61 @@ void Mem::addroots(char* pStart, char* pEnd) /* =================================================== */ +#if 1 + +/* Allocate, but never release + */ + +// Allocate a little less than 64kB because the C runtime adds some overhead that +// causes the actual memory block to be larger than 64kB otherwise. E.g. the dmc +// runtime rounds the size up to 128kB, but the remaining space in the chunk is less +// than 64kB, so it cannot be used by another chunk. +#define CHUNK_SIZE (4096 * 16 - 64) + +static size_t heapleft = 0; +static void *heapp; + +void * operator new(size_t m_size) +{ + // 16 byte alignment is better (and sometimes needed) for doubles + m_size = (m_size + 15) & ~15; + + // The layout of the code is selected so the most common case is straight through + if (m_size <= heapleft) + { + L1: + heapleft -= m_size; + void *p = heapp; + heapp = (void *)((char *)heapp + m_size); + return p; + } + + if (m_size > CHUNK_SIZE) + { + void *p = malloc(m_size); + if (p) + return p; + printf("Error: out of memory\n"); + exit(EXIT_FAILURE); + return p; + } + + heapleft = CHUNK_SIZE; + heapp = malloc(CHUNK_SIZE); + if (!heapp) + { + printf("Error: out of memory\n"); + exit(EXIT_FAILURE); + } + goto L1; +} + +void operator delete(void *p) +{ +} + +#else + void * operator new(size_t m_size) { void *p = malloc(m_size); @@ -157,4 +208,4 @@ void operator delete(void *p) free(p); } - +#endif diff --git a/dmd2/root/root.c b/dmd2/root/root.c index 900a3e65..35f64e66 100644 --- a/dmd2/root/root.c +++ b/dmd2/root/root.c @@ -98,42 +98,42 @@ void warning(const char *format, ...) /****************************** Object ********************************/ -int Object::equals(Object *o) +bool RootObject::equals(RootObject *o) { return o == this; } -hash_t Object::hashCode() +hash_t RootObject::hashCode() { return (hash_t) this; } -int Object::compare(Object *obj) +int RootObject::compare(RootObject *obj) { return this - obj; } -void Object::print() +void RootObject::print() { printf("%s %p\n", toChars(), this); } -char *Object::toChars() +char *RootObject::toChars() { return (char *)"Object"; } -int Object::dyncast() +int RootObject::dyncast() { return 0; } -void Object::toBuffer(OutBuffer *b) +void RootObject::toBuffer(OutBuffer *b) { b->writestring("Object"); } -void Object::mark() +void RootObject::mark() { } @@ -206,12 +206,12 @@ size_t String::len() return strlen(str); } -int String::equals(Object *obj) +bool String::equals(RootObject *obj) { return strcmp(str,((String *)obj)->str) == 0; } -int String::compare(Object *obj) +int String::compare(RootObject *obj) { return strcmp(str,((String *)obj)->str); } @@ -279,7 +279,7 @@ Strings *FileName::splitPath(const char *path) do { char instring = 0; - while (isspace((unsigned char)*p)) // skip leading whitespace + while (isspace((utf8_t)*p)) // skip leading whitespace p++; buf.reserve(strlen(p) + 1); // guess size of path for (; ; p++) @@ -345,7 +345,7 @@ hash_t FileName::hashCode() // We need a different hashCode because it must be case-insensitive size_t len = strlen(str); hash_t hash = 0; - unsigned char *s = (unsigned char *)str; + utf8_t *s = (utf8_t *)str; for (;;) { @@ -384,7 +384,7 @@ hash_t FileName::hashCode() #endif } -int FileName::compare(Object *obj) +int FileName::compare(RootObject *obj) { return compare(str, ((FileName *)obj)->str); } @@ -398,7 +398,7 @@ int FileName::compare(const char *name1, const char *name2) #endif } -int FileName::equals(Object *obj) +bool FileName::equals(RootObject *obj) { return compare(obj) == 0; } @@ -696,7 +696,7 @@ const char *FileName::searchPath(Strings *path, const char *name, int cwd) for (size_t i = 0; i < path->dim; i++) { - const char *p = path->tdata()[i]; + const char *p = (*path)[i]; const char *n = combine(p, name); if (exists(n)) @@ -756,7 +756,7 @@ const char *FileName::safeSearchPath(Strings *path, const char *name) for (size_t i = 0; i < path->dim; i++) { const char *cname = NULL; - const char *cpath = canonicalName(path->tdata()[i]); + const char *cpath = canonicalName((*path)[i]); //printf("FileName::safeSearchPath(): name=%s; path=%s; cpath=%s\n", // name, (char *)path->data[i], cpath); if (cpath == NULL) @@ -829,7 +829,8 @@ void FileName::ensurePathExists(const char *path) { #if _WIN32 size_t len = strlen(path); - if (len > 2 && p[-1] == ':' && path + 2 == p) + if ((len > 2 && p[-1] == ':' && strcmp(path + 2, p) == 0) || + len == strlen(p)) { mem.free((void *)p); return; } @@ -838,19 +839,20 @@ void FileName::ensurePathExists(const char *path) mem.free((void *)p); } #if _WIN32 - if (path[strlen(path) - 1] != '\\') -#endif -#if POSIX - if (path[strlen(path) - 1] != '\\') + char sep = '\\'; +#elif POSIX + char sep = '/'; #endif + if (path[strlen(path) - 1] != sep) { //printf("mkdir(%s)\n", path); #if _WIN32 - if (_mkdir(path)) + int r = _mkdir(path); #endif #if POSIX - if (mkdir(path, 0777)) + int r = mkdir(path, 0777); #endif + if (r) { /* Don't error out if another instance of dmd just created * this directory @@ -1017,7 +1019,7 @@ int File::read() goto err2; } size = buf.st_size; - buffer = (unsigned char *) ::malloc(size + 2); + buffer = (utf8_t *) ::malloc(size + 2); if (!buffer) { printf("\tmalloc error, errno = %d\n",errno); @@ -1075,7 +1077,7 @@ err1: ref = 0; size = GetFileSize(h,NULL); - buffer = (unsigned char *) ::malloc(size + 2); + buffer = (utf8_t *) ::malloc(size + 2); if (!buffer) goto err2; @@ -1151,7 +1153,7 @@ int File::mmread() if (!ref) mem.free(buffer); ref = 2; - buffer = (unsigned char *)MapViewOfFileEx(hFileMap, FILE_MAP_READ,0,0,size,NULL); + buffer = (utf8_t *)MapViewOfFileEx(hFileMap, FILE_MAP_READ,0,0,size,NULL); if (CloseHandle(hFileMap) != TRUE) goto Lerr; if (buffer == NULL) // mapping view failed @@ -1359,7 +1361,7 @@ int File::exists() void File::remove() { #if POSIX - ::remove(this->name->toChars()); + int dummy = ::remove(this->name->toChars()); #elif _WIN32 DeleteFileA(this->name->toChars()); #else @@ -1469,7 +1471,7 @@ OutBuffer::OutBuffer() doindent = 0; level = 0; - linehead = 1; + notlinehead = 0; } OutBuffer::~OutBuffer() @@ -1499,7 +1501,8 @@ void OutBuffer::reserve(size_t nbytes) if (size - offset < nbytes) { size = (offset + nbytes) * 2; - data = (unsigned char *)mem.realloc(data, size); + size = (size + 15) & ~15; + data = (utf8_t *)mem.realloc(data, size); } } @@ -1515,7 +1518,7 @@ void OutBuffer::setsize(size_t size) void OutBuffer::write(const void *data, size_t nbytes) { - if (doindent && linehead) + if (doindent && !notlinehead) { if (level) { @@ -1526,14 +1529,14 @@ void OutBuffer::write(const void *data, size_t nbytes) offset++; } } - linehead = 0; + notlinehead = 1; } reserve(nbytes); memcpy(this->data + offset, data, nbytes); offset += nbytes; } -void OutBuffer::writebstring(unsigned char *string) +void OutBuffer::writebstring(utf8_t *string) { write(string,*string + 1); } @@ -1560,12 +1563,12 @@ void OutBuffer::writenl() writeByte('\n'); #endif if (doindent) - linehead = 1; + notlinehead = 0; } void OutBuffer::writeByte(unsigned b) { - if (doindent && linehead + if (doindent && !notlinehead && b != '\n') { if (level) @@ -1577,7 +1580,7 @@ void OutBuffer::writeByte(unsigned b) offset++; } } - linehead = 0; + notlinehead = 1; } reserve(1); this->data[offset] = (unsigned char)b; @@ -1655,12 +1658,13 @@ void OutBuffer::writewchar(unsigned w) void OutBuffer::writeword(unsigned w) { - if (doindent && linehead #if _WIN32 - && w != 0x0A0D) + unsigned newline = 0x0A0D; #else - && w != '\n') + unsigned newline = '\n'; #endif + if (doindent && !notlinehead + && w != newline) { if (level) { @@ -1671,7 +1675,7 @@ void OutBuffer::writeword(unsigned w) offset++; } } - linehead = 0; + notlinehead = 1; } reserve(2); *(unsigned short *)(this->data + offset) = (unsigned short)w; @@ -1698,12 +1702,12 @@ void OutBuffer::writeUTF16(unsigned w) void OutBuffer::write4(unsigned w) { - if (doindent && linehead #if _WIN32 - && w != 0x000A000D) + bool notnewline = w != 0x000A000D; #else - ) + bool notnewline = true; #endif + if (doindent && !notlinehead && notnewline) { if (level) { @@ -1714,7 +1718,7 @@ void OutBuffer::write4(unsigned w) offset++; } } - linehead = 0; + notlinehead = 1; } reserve(4); *(unsigned *)(this->data + offset) = w; @@ -1730,7 +1734,7 @@ void OutBuffer::write(OutBuffer *buf) } } -void OutBuffer::write(Object *obj) +void OutBuffer::write(RootObject *obj) { if (obj) { diff --git a/dmd2/root/root.h b/dmd2/root/root.h index 5935d4b5..3e1ce634 100644 --- a/dmd2/root/root.h +++ b/dmd2/root/root.h @@ -12,10 +12,10 @@ #include #include -#ifdef DEBUG +#include #include -#endif #include "port.h" +#include "rmem.h" #if __DMC__ #pragma once @@ -30,17 +30,18 @@ typedef size_t hash_t; struct OutBuffer; // Can't include arraytypes.h here, need to declare these directly. -template struct ArrayBase; -typedef ArrayBase Files; -typedef ArrayBase Strings; +template struct Array; +typedef Array Files; +typedef Array Strings; -struct Object +class RootObject { - Object() { } - virtual ~Object() { } +public: + RootObject() { } + virtual ~RootObject() { } - virtual int equals(Object *o); + virtual bool equals(RootObject *o); /** * Returns a hash code, useful for things like building hash tables of Objects. @@ -51,7 +52,7 @@ struct Object * Return <0, ==0, or >0 if this is less than, equal to, or greater than obj. * Useful for sorting Objects. */ - virtual int compare(Object *obj); + virtual int compare(RootObject *obj); /** * Pretty-print an Object. Useful for debugging the old-fashioned way. @@ -74,8 +75,9 @@ struct Object void mark(); }; -struct String : Object +class String : public RootObject { +public: const char *str; // the string itself String(const char *str); @@ -85,20 +87,21 @@ struct String : Object static hash_t calcHash(const char *str); hash_t hashCode(); size_t len(); - int equals(Object *obj); - int compare(Object *obj); + bool equals(RootObject *obj); + int compare(RootObject *obj); char *toChars(); void print(); void mark(); }; -struct FileName : String +class FileName : public String { +public: FileName(const char *str); hash_t hashCode(); - int equals(Object *obj); + bool equals(RootObject *obj); static int equals(const char *name1, const char *name2); - int compare(Object *obj); + int compare(RootObject *obj); static int compare(const char *name1, const char *name2); static int absolute(const char *name); static const char *ext(const char *); @@ -128,8 +131,9 @@ struct FileName : String static void free(const char *str); }; -struct File : Object +class File : public RootObject { +public: int ref; // != 0 if this is a reference to someone else's buffer unsigned char *buffer; // data for our file size_t len; // amount of data in buffer[] @@ -233,13 +237,15 @@ struct File : Object void remove(); // delete file }; -struct OutBuffer : Object +struct OutBuffer { unsigned char *data; size_t offset; size_t size; - int doindent, level, linehead; + int doindent; + int level; + int notlinehead; OutBuffer(); ~OutBuffer(); @@ -263,7 +269,7 @@ struct OutBuffer : Object void writeUTF16(unsigned w); void write4(unsigned w); void write(OutBuffer *buf); - void write(Object *obj); + void write(RootObject *obj); void fill0(size_t nbytes); void align(size_t size); void vprintf(const char *format, va_list args); @@ -277,45 +283,178 @@ struct OutBuffer : Object char *extractString(); }; +template struct Array { size_t dim; - void **data; + TYPE **data; private: size_t allocdim; #define SMALLARRAYCAP 1 - void *smallarray[SMALLARRAYCAP]; // inline storage for small arrays + TYPE *smallarray[SMALLARRAYCAP]; // inline storage for small arrays public: - Array(); - ~Array(); - //Array(const Array&); - void mark(); - char *toChars(); + Array() + { + data = SMALLARRAYCAP ? &smallarray[0] : NULL; + dim = 0; + allocdim = SMALLARRAYCAP; + } - void reserve(size_t nentries); - void setDim(size_t newdim); - void fixDim(); - void push(void *ptr); - void *pop(); - void shift(void *ptr); - void insert(size_t index, void *ptr); - void insert(size_t index, Array *a); - void append(Array *a); - void remove(size_t i); - void zero(); - void *tos(); - void sort(); - Array *copy(); -}; + ~Array() + { + if (data != &smallarray[0]) + mem.free(data); + } + + void mark() + { + mem.mark(data); + for (size_t u = 0; u < dim; u++) + mem.mark(data[u]); // BUG: what if arrays of Object's? + } + + char *toChars() + { + char **buf = (char **)malloc(dim * sizeof(char *)); + assert(buf); + size_t len = 2; + for (size_t u = 0; u < dim; u++) + { + buf[u] = ((RootObject *)data[u])->toChars(); + len += strlen(buf[u]) + 1; + } + char *str = (char *)mem.malloc(len); + + str[0] = '['; + char *p = str + 1; + for (size_t u = 0; u < dim; u++) + { + if (u) + *p++ = ','; + len = strlen(buf[u]); + memcpy(p,buf[u],len); + p += len; + } + *p++ = ']'; + *p = 0; + free(buf); + return str; + } + + void reserve(size_t nentries) + { + //printf("Array::reserve: dim = %d, allocdim = %d, nentries = %d\n", (int)dim, (int)allocdim, (int)nentries); + if (allocdim - dim < nentries) + { + if (allocdim == 0) + { // Not properly initialized, someone memset it to zero + if (nentries <= SMALLARRAYCAP) + { allocdim = SMALLARRAYCAP; + data = SMALLARRAYCAP ? &smallarray[0] : NULL; + } + else + { allocdim = nentries; + data = (TYPE **)mem.malloc(allocdim * sizeof(*data)); + } + } + else if (allocdim == SMALLARRAYCAP) + { + allocdim = dim + nentries; + data = (TYPE **)mem.malloc(allocdim * sizeof(*data)); + memcpy(data, &smallarray[0], dim * sizeof(*data)); + } + else + { allocdim = dim + nentries; + data = (TYPE **)mem.realloc(data, allocdim * sizeof(*data)); + } + } + } + + void setDim(size_t newdim) + { + if (dim < newdim) + { + reserve(newdim - dim); + } + dim = newdim; + } + + void fixDim() + { + if (dim != allocdim) + { + if (allocdim >= SMALLARRAYCAP) + { + if (dim <= SMALLARRAYCAP) + { + memcpy(&smallarray[0], data, dim * sizeof(*data)); + mem.free(data); + } + else + data = (TYPE **)mem.realloc(data, dim * sizeof(*data)); + } + allocdim = dim; + } + } + + TYPE *pop() + { + return data[--dim]; + } + + void shift(TYPE *ptr) + { + reserve(1); + memmove(data + 1, data, dim * sizeof(*data)); + data[0] = ptr; + dim++; + } + + void remove(size_t i) + { + if (dim - i - 1) + memmove(data + i, data + i + 1, (dim - i - 1) * sizeof(data[0])); + dim--; + } + + void zero() + { + memset(data,0,dim * sizeof(data[0])); + } + + TYPE *tos() + { + return dim ? data[dim - 1] : NULL; + } + + void sort() + { + struct ArraySort + { + static int + #if _WIN32 + __cdecl + #endif + Array_sort_compare(const void *x, const void *y) + { + RootObject *ox = *(RootObject **)x; + RootObject *oy = *(RootObject **)y; + + return ox->compare(oy); + } + }; + + if (dim) + { + qsort(data, dim, sizeof(RootObject *), &ArraySort::Array_sort_compare); + } + } -template -struct ArrayBase : Array -{ TYPE **tdata() { - return (TYPE **)data; + return data; } TYPE*& operator[] (size_t index) @@ -323,36 +462,52 @@ struct ArrayBase : Array #ifdef DEBUG assert(index < dim); #endif - return ((TYPE **)data)[index]; + return data[index]; } void insert(size_t index, TYPE *v) { - Array::insert(index, (void *)v); + reserve(1); + memmove(data + index + 1, data + index, (dim - index) * sizeof(*data)); + data[index] = v; + dim++; } - void insert(size_t index, ArrayBase *a) + void insert(size_t index, Array *a) { - Array::insert(index, (Array *)a); + if (a) + { + size_t d = a->dim; + reserve(d); + if (dim != index) + memmove(data + index + d, data + index, (dim - index) * sizeof(*data)); + memcpy(data + index, a->data, d * sizeof(*data)); + dim += d; + } } - void append(ArrayBase *a) + void append(Array *a) { - Array::append((Array *)a); + insert(dim, a); } void push(TYPE *a) { - Array::push((void *)a); + reserve(1); + data[dim++] = a; } - ArrayBase *copy() + Array *copy() { - return (ArrayBase *)Array::copy(); + Array *a = new Array(); + + a->setDim(dim); + memcpy(a->data, data, dim * sizeof(*data)); + return a; } - typedef int (*ArrayBase_apply_ft_t)(TYPE *, void *); - int apply(ArrayBase_apply_ft_t fp, void *param) + typedef int (*Array_apply_ft_t)(TYPE *, void *); + int apply(Array_apply_ft_t fp, void *param) { for (size_t i = 0; i < dim; i++) { TYPE *e = (*this)[i]; @@ -368,8 +523,9 @@ struct ArrayBase : Array }; // TODO: Remove (only used by disabled GC) -struct Bits : Object +class Bits : public RootObject { +public: unsigned bitdim; unsigned allocdim; unsigned *data; diff --git a/dmd2/scope.c b/dmd2/scope.c index d6166ed2..be12f2cb 100644 --- a/dmd2/scope.c +++ b/dmd2/scope.c @@ -21,6 +21,7 @@ #include "dsymbol.h" #include "scope.h" #include "declaration.h" +#include "statement.h" #include "aggregate.h" #include "module.h" #include "id.h" @@ -50,6 +51,7 @@ Scope::Scope() //printf("Scope::Scope() %p\n", this); this->module = NULL; + this->instantiatingModule = NULL; this->scopesym = NULL; this->sd = NULL; this->enclosing = NULL; @@ -74,12 +76,11 @@ Scope::Scope() this->inunion = 0; this->nofree = 0; this->noctor = 0; - this->noaccesscheck = 0; - this->needctfe = 0; this->intypeof = 0; this->speculative = 0; - this->parameterSpecialization = 0; this->callSuper = 0; + this->fieldinit = NULL; + this->fieldinit_dim = 0; this->flags = 0; this->lastdc = NULL; this->lastoffset = 0; @@ -92,6 +93,7 @@ Scope::Scope(Scope *enclosing) //printf("Scope::Scope(enclosing = %p) %p\n", enclosing, this); assert(!(enclosing->flags & SCOPEfree)); this->module = enclosing->module; + this->instantiatingModule = enclosing->instantiatingModule; this->func = enclosing->func; this->parent = enclosing->parent; this->scopesym = NULL; @@ -125,13 +127,12 @@ Scope::Scope(Scope *enclosing) this->inunion = enclosing->inunion; this->nofree = 0; this->noctor = enclosing->noctor; - this->noaccesscheck = enclosing->noaccesscheck; - this->needctfe = enclosing->needctfe; this->intypeof = enclosing->intypeof; this->speculative = enclosing->speculative; - this->parameterSpecialization = enclosing->parameterSpecialization; this->callSuper = enclosing->callSuper; - this->flags = (enclosing->flags & (SCOPEcontract | SCOPEdebug)); + this->fieldinit = enclosing->saveFieldInit(); + this->fieldinit_dim = enclosing->fieldinit_dim; + this->flags = (enclosing->flags & (SCOPEcontract | SCOPEdebug | SCOPEctfe)); this->lastdc = NULL; this->lastoffset = 0; this->docbuf = enclosing->docbuf; @@ -183,7 +184,17 @@ Scope *Scope::pop() Scope *enc = enclosing; if (enclosing) + { enclosing->callSuper |= callSuper; + if (enclosing->fieldinit && fieldinit) + { + size_t dim = fieldinit_dim; + for (size_t i = 0; i < dim; i++) + enclosing->fieldinit[i] |= fieldinit[i]; + delete[] fieldinit; + fieldinit = NULL; + } + } if (!nofree) { enclosing = freelist; @@ -194,6 +205,19 @@ Scope *Scope::pop() return enc; } +Scope *Scope::startCTFE() +{ + Scope *sc = this->push(); + sc->flags = this->flags | SCOPEctfe; + return sc; +} + +Scope *Scope::endCTFE() +{ + assert(flags & SCOPEctfe); + return pop(); +} + void Scope::mergeCallSuper(Loc loc, unsigned cs) { // This does a primitive flow analysis to support the restrictions @@ -247,6 +271,131 @@ void Scope::mergeCallSuper(Loc loc, unsigned cs) } } +unsigned *Scope::saveFieldInit() +{ + unsigned *fi = NULL; + if (fieldinit) // copy + { + size_t dim = fieldinit_dim; + fi = new unsigned[dim]; + fi[0] = dim; + for (size_t i = 0; i < dim; i++) + fi[i] = fieldinit[i]; + } + return fi; +} + +bool mergeFieldInit(Loc loc, unsigned &fieldInit, unsigned fi, bool mustInit) +{ + if (fi != fieldInit) + { + + // Have any branches returned? + bool aRet = (fi & CSXreturn) != 0; + bool bRet = (fieldInit & CSXreturn) != 0; + + bool ok; + + if (aRet) + { + ok = !mustInit || (fi & CSXthis_ctor); + fieldInit = fieldInit; + } + else if (bRet) + { + ok = !mustInit || (fieldInit & CSXthis_ctor); + fieldInit = fi; + } + else + { + ok = !mustInit || !((fieldInit ^ fi) & CSXthis_ctor); + fieldInit |= fi; + } + + return ok; + } +#if 0 + // This does a primitive flow analysis to support the restrictions + // regarding when and how constructors can appear. + // It merges the results of two paths. + // The two paths are fieldInit and fi; the result is merged into fieldInit. + + if (fi != fieldInit) + { // Have ALL branches called a constructor? + int aAll = (fi & CSXthis_ctor) != 0; + int bAll = (fieldInit & CSXthis_ctor) != 0; + + // Have ANY branches called a constructor? + bool aAny = (fi & CSXany_ctor) != 0; + bool bAny = (fieldInit & CSXany_ctor) != 0; + + // Have any branches returned? + bool aRet = (fi & CSXreturn) != 0; + bool bRet = (fieldInit & CSXreturn) != 0; + + bool ok = true; + +printf("L%d fieldInit = x%x, fi = x%x\n", __LINE__, fieldInit, fi); + + // If one has returned without a constructor call, there must be never + // have been ctor calls in the other. + if ( (aRet && !aAny && bAny) || + (bRet && !bAny && aAny)) + { ok = false; +printf("L%d\n", __LINE__); + } + // If one branch has called a ctor and then exited, anything the + // other branch has done is OK (except returning without a + // ctor call, but we already checked that). + else if (aRet && aAll) + { + //fieldInit |= fi & (CSXany_ctor | CSXlabel); +printf("L%d -> fieldInit = x%x\n", __LINE__, fieldInit); + } + else if (bRet && bAll) + { + fieldInit = fi;// | (fieldInit & (CSXany_ctor | CSXlabel)); +printf("L%d -> fieldInit = x%x\n", __LINE__, fieldInit); + } + else + { // Both branches must have called ctors, or both not. + ok = (aAll == bAll); + // If one returned without a ctor, we must remember that + // (Don't bother if we've already found an error) + if (ok && aRet && !aAny) + fieldInit |= CSXreturn; + fieldInit |= fi & (CSXany_ctor | CSXlabel); +printf("L%d ok = %d, fieldInit = x%x, fi = x%x\n", __LINE__, ok, fieldInit, fi); + } + return ok; + } +#endif + return true; +} + +void Scope::mergeFieldInit(Loc loc, unsigned *fies) +{ + if (fieldinit && fies) + { + FuncDeclaration *f = func; + if (fes) f = fes->func; + AggregateDeclaration *ad = f->isAggregateMember2(); + assert(ad); + + for (size_t i = 0; i < ad->fields.dim; i++) + { + VarDeclaration *v = ad->fields[i]; + bool mustInit = (v->storage_class & STCnodefaultctor || + v->type->needsNested()); + + if (!::mergeFieldInit(loc, fieldinit[i], fies[i], mustInit)) + { + ::error(loc, "one path skips field %s", ad->fields[i]->toChars()); + } + } + } +} + Dsymbol *Scope::search(Loc loc, Identifier *ident, Dsymbol **pscopesym) { Dsymbol *s; Scope *sc; @@ -282,8 +431,7 @@ Dsymbol *Scope::search(Loc loc, Identifier *ident, Dsymbol **pscopesym) s = sc->scopesym->search(loc, ident, 0); if (s) { - if (global.params.Dversion > 1 && - ident == Id::length && + if (ident == Id::length && sc->scopesym->isArrayScopeSymbol() && sc->enclosing && sc->enclosing->search(loc, ident, NULL)) @@ -414,9 +562,8 @@ void *scope_search_fp(void *arg, const char *seed) assert(id); Scope *sc = (Scope *)arg; - Module::clearCache(); Dsymbol *s = sc->search(Loc(), id, NULL); - return s; + return (void*)s; } Dsymbol *Scope::search_correct(Identifier *ident) diff --git a/dmd2/scope.h b/dmd2/scope.h index 6a7868bf..cac2f3f8 100644 --- a/dmd2/scope.h +++ b/dmd2/scope.h @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2012 by Digital Mars +// Copyright (c) 1999-2013 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -14,20 +14,20 @@ #pragma once #endif -struct Dsymbol; -struct ScopeDsymbol; -struct Identifier; -struct Module; -struct Statement; -struct SwitchStatement; -struct TryFinallyStatement; -struct LabelStatement; -struct ForeachStatement; -struct ClassDeclaration; -struct AggregateDeclaration; -struct FuncDeclaration; +class Dsymbol; +class ScopeDsymbol; +class Identifier; +class Module; +class Statement; +class SwitchStatement; +class TryFinallyStatement; +class LabelStatement; +class ForeachStatement; +class ClassDeclaration; +class AggregateDeclaration; +class FuncDeclaration; struct DocComment; -struct TemplateInstance; +class TemplateInstance; #if IN_LLVM struct EnclosingHandler; @@ -51,22 +51,26 @@ enum PROT; #define CSXreturn 0x20 // seen a return statement #define CSXany_ctor 0x40 // either this() or super() was called -#define SCOPEctor 1 // constructor type -#define SCOPEstaticif 2 // inside static if -#define SCOPEfree 4 // is on free list -#define SCOPEstaticassert 8 // inside static assert -#define SCOPEdebug 0x10 // inside debug conditional +#define SCOPEctor 0x0001 // constructor type +#define SCOPEstaticif 0x0002 // inside static if +#define SCOPEfree 0x0004 // is on free list +#define SCOPEstaticassert 0x0008 // inside static assert +#define SCOPEdebug 0x0010 // inside debug conditional -#define SCOPEinvariant 0x20 // inside invariant code -#define SCOPErequire 0x40 // inside in contract code -#define SCOPEensure 0x60 // inside out contract code -#define SCOPEcontract 0x60 // [mask] we're inside contract code +#define SCOPEinvariant 0x0020 // inside invariant code +#define SCOPErequire 0x0040 // inside in contract code +#define SCOPEensure 0x0060 // inside out contract code +#define SCOPEcontract 0x0060 // [mask] we're inside contract code + +#define SCOPEctfe 0x0080 // inside a ctfe-only expression +#define SCOPEnoaccesscheck 0x0100 // don't do access checks struct Scope { Scope *enclosing; // enclosing Scope Module *module; // Root module + Module *instantiatingModule; // top level module that started a chain of template instantiations ScopeDsymbol *scopesym; // current symbol ScopeDsymbol *sd; // if in static if, and declaring new symbols, // sd gets the addMember() @@ -91,16 +95,15 @@ struct Scope int noctor; // set if constructor calls aren't allowed int intypeof; // in typeof(exp) bool speculative; // in __traits(compiles) or typeof(exp) - int parameterSpecialization; // if in template parameter specialization - int noaccesscheck; // don't do access checks - int needctfe; // inside a ctfe-only expression unsigned callSuper; // primitive flow analysis for constructors + unsigned *fieldinit; + unsigned fieldinit_dim; structalign_t structalign; // alignment for struct members - enum LINK linkage; // linkage for external functions + LINK linkage; // linkage for external functions - enum PROT protection; // protection for class members + PROT protection; // protection for class members int explicitProtection; // set if in an explicit protection attribute StorageClass stc; // storage class @@ -125,8 +128,14 @@ struct Scope Scope *push(ScopeDsymbol *ss); Scope *pop(); + Scope *startCTFE(); + Scope *endCTFE(); + void mergeCallSuper(Loc loc, unsigned cs); + unsigned *saveFieldInit(); + void mergeFieldInit(Loc loc, unsigned *cses); + Dsymbol *search(Loc loc, Identifier *ident, Dsymbol **pscopesym); Dsymbol *search_correct(Identifier *ident); Dsymbol *insert(Dsymbol *s); diff --git a/dmd2/statement.c b/dmd2/statement.c index 28f4d77d..4a386199 100644 --- a/dmd2/statement.c +++ b/dmd2/statement.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars +// Copyright (c) 1999-2013 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -34,32 +34,6 @@ #if IN_LLVM // From pragma.cpp bool matchPragma(Identifier* needle, Identifier* ident, Identifier* oldIdent); -#if defined(_MSC_VER) -#include -#else -#include -#endif - -// sizes based on those from tollvm.cpp:DtoMutexType() -int os_critsecsize() -{ -#if defined(_MSC_VER) - // Return sizeof(RTL_CRITICAL_SECTION) - return global.params.is64bit ? 40 : 24; -#else - if (global.params.targetTriple.isOSWindows()) - return global.params.is64bit ? 40 : 24; - else if (global.params.targetTriple.getOS() == llvm::Triple::FreeBSD) - return sizeof(size_t); - else - return sizeof(pthread_mutex_t); -#endif -} -#elif IN_DMD - -extern int os_critsecsize32(); -extern int os_critsecsize64(); - #endif Identifier *fixupLabelName(Scope *sc, Identifier *ident) @@ -83,6 +57,14 @@ Identifier *fixupLabelName(Scope *sc, Identifier *ident) return ident; } +LabelStatement *checkLabeledLoop(Scope *sc, Statement *statement) +{ + if (sc->slabel && sc->slabel->statement == statement) + { + return sc->slabel; + } + return NULL; +} /******************************** Statement ***************************/ @@ -106,12 +88,13 @@ void Statement::print() } char *Statement::toChars() -{ OutBuffer *buf; +{ HdrGenState hgs; - buf = new OutBuffer(); - toCBuffer(buf, &hgs); - return buf->toChars(); + OutBuffer buf; + toCBuffer(&buf, &hgs); + buf.writebyte(0); + return buf.extractData(); } void Statement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) @@ -306,6 +289,28 @@ Statements *Statement::flatten(Scope *sc) } +/******************************** ErrorStatement ***************************/ + +ErrorStatement::ErrorStatement() + : Statement(Loc()) +{ +} + +Statement *ErrorStatement::syntaxCopy() +{ + return this; +} + +Statement *ErrorStatement::semantic(Scope *sc) +{ + return this; +} + +int ErrorStatement::blockExit(bool mustNotThrow) +{ + return BEany; +} + /******************************** PeelStatement ***************************/ PeelStatement::PeelStatement(Statement *s) @@ -387,6 +392,8 @@ Statement *ExpStatement::semantic(Scope *sc) exp = resolveProperties(sc, exp); exp->discardValue(); exp = exp->optimize(0); + if (exp->op == TOKerror) + return new ErrorStatement(); } return this; } @@ -502,28 +509,38 @@ void CompileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) Statements *CompileStatement::flatten(Scope *sc) { //printf("CompileStatement::flatten() %s\n", exp->toChars()); - exp = exp->ctfeSemantic(sc); + sc = sc->startCTFE(); + exp = exp->semantic(sc); exp = resolveProperties(sc, exp); + sc = sc->endCTFE(); exp = exp->ctfeInterpret(); - if (exp->op == TOKerror) - return NULL; - StringExp *se = exp->toString(); - if (!se) - { error("argument to mixin must be a string, not (%s)", exp->toChars()); - return NULL; - } - se = se->toUTF8(sc); - Parser p(sc->module, (unsigned char *)se->string, se->len, 0); - p.loc = loc; - p.nextToken(); Statements *a = new Statements(); - while (p.token.value != TOKeof) + if (exp->op != TOKerror) { - Statement *s = p.parseStatement(PSsemi | PScurlyscope); - if (s) // if no parsing errors - a->push(s); + StringExp *se = exp->toString(); + if (!se) + error("argument to mixin must be a string, not (%s)", exp->toChars()); + else + { + se = se->toUTF8(sc); + Parser p(sc->module, (utf8_t *)se->string, se->len, 0); + p.scanloc = loc; + p.nextToken(); + + while (p.token.value != TOKeof) + { + unsigned errors = global.errors; + Statement *s = p.parseStatement(PSsemi | PScurlyscope); + if (!s || global.errors != errors) + goto Lerror; + a->push(s); + } + return a; + } } +Lerror: + a->push(new ErrorStatement()); return a; } @@ -702,7 +719,21 @@ Statement *CompoundStatement::semantic(Scope *sc) } i++; } - if (statements->dim == 1 && !isAsmBlockStatement()) + for (size_t i = 0; i < statements->dim; ++i) + { + s = (*statements)[i]; + if (s) + { + Statement *se = s->isErrorStatement(); + if (se) + return se; + } + } + if (statements->dim == 1 +#if IN_LLVM + && !isAsmBlockStatement() +#endif + ) { return (*statements)[0]; } @@ -906,11 +937,10 @@ Statement *UnrolledLoopStatement::semantic(Scope *sc) { //printf("UnrolledLoopStatement::semantic(this = %p, sc = %p)\n", this, sc); - sc->noctor++; Scope *scd = sc->push(); scd->sbreak = this; scd->scontinue = this; - + Statement *serror = NULL; for (size_t i = 0; i < statements->dim; i++) { Statement *s = (*statements)[i]; @@ -919,12 +949,14 @@ Statement *UnrolledLoopStatement::semantic(Scope *sc) //printf("[%d]: %s\n", i, s->toChars()); s = s->semantic(scd); (*statements)[i] = s; + + if (s && !serror) + serror = s->isErrorStatement(); } } scd->pop(); - sc->noctor--; - return this; + return serror ? serror : this; } void UnrolledLoopStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) @@ -995,13 +1027,12 @@ Statement *ScopeStatement::semantic(Scope *sc) //printf("ScopeStatement::semantic(sc = %p)\n", sc); if (statement) - { Statements *a; - + { sym = new ScopeDsymbol(); sym->parent = sc->scopesym; sc = sc->push(sym); - a = statement->flatten(sc); + Statements *a = statement->flatten(sc); if (a) { statement = new CompoundStatement(loc, a); @@ -1010,6 +1041,12 @@ Statement *ScopeStatement::semantic(Scope *sc) statement = statement->semantic(sc); if (statement) { + if (statement->isErrorStatement()) + { + sc->pop(); + return statement; + } + Statement *sentry; Statement *sexception; Statement *sfinally; @@ -1143,6 +1180,12 @@ Statement *DoStatement::semantic(Scope *sc) condition = condition->checkToBoolean(sc); + if (condition->op == TOKerror) + return new ErrorStatement(); + + if (body && body->isErrorStatement()) + return body; + return this; } @@ -1201,7 +1244,6 @@ ForStatement::ForStatement(Loc loc, Statement *init, Expression *condition, Expr this->condition = condition; this->increment = increment; this->body = body; - this->nest = 0; this->relatedLabeled = NULL; } @@ -1220,112 +1262,45 @@ Statement *ForStatement::syntaxCopy() return s; } -/* - * Run semantic on init recursively. - * Rewrite: - * for (auto x=X(), y = Y(); ...; ...) {} - * as: - * try { - * try { - * for (auto x=X(), auto y=Y(); ...; ...) {} - * } - * finally { y.~this(); } - * } - * finally { x.~this(); } - */ -Statement *ForStatement::semanticInit(Scope *sc, Statements *ainit, size_t i) -{ - Statement *statement = this; - if (i < ainit->dim) - { - Statement *s = (*ainit)[i]; - (*ainit)[i] = s = s->semantic(sc); - if (!s) - return semanticInit(sc, ainit, i + 1); - - Statement *sentry; - Statement *sexception; - Statement *sfinally; - (*ainit)[i] = s->scopeCode(sc, &sentry, &sexception, &sfinally); - - /* Rewrite to: - * ainit = - * [ ..., sentry, ainit[i], ... ] - * statement = - * try { // sfinally != NULL - * try { // sexception != NULL - * statement; - * } catch (__o) { // sexception != NULL - * sexception; // sexception != NULL - * throw __o; // sexception != NULL (internalThrow = true) - * } // sexception != NULL - * } finally { sfinally; } // sfinally != NULL - */ - if (sentry) - { sentry = sentry->semantic(sc); - if (sentry) - ainit->insert(i++, sentry); - } - if (sexception) - sexception = sexception->semantic(sc); - - statement = semanticInit(sc, ainit, i + 1); - - if (sexception) - { - Identifier *id = Lexer::uniqueId("__o"); - Statement *handler; - if (sexception->blockExit(FALSE) & BEfallthru) - { handler = new ThrowStatement(Loc(), new IdentifierExp(Loc(), id)); - ((ThrowStatement *)handler)->internalThrow = true; - handler = new CompoundStatement(Loc(), sexception, handler); - } - else - handler = sexception; - Catches *catches = new Catches(); - Catch *ctch = new Catch(Loc(), NULL, id, handler); - catches->push(ctch); - statement = new TryCatchStatement(Loc(), statement, catches); - } - if (sfinally) - statement = new TryFinallyStatement(Loc(), statement, sfinally); - } - - //printf("-ForStatement::semanticInit %s\n", statement->toChars()); - return statement; -} - Statement *ForStatement::semantic(Scope *sc) { //printf("ForStatement::semantic %s\n", toChars()); - if (!nest) + if (init) { - ScopeDsymbol *sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - sc = sc->push(sym); - } - if (!nest && init) - { - Loc loc = init->loc; - Statements *ainit = init->flatten(sc); - if (!ainit) - (ainit = new Statements())->push(init); - init = NULL; - - Statement *s = semanticInit(sc, ainit, 0); - ++nest; + /* Rewrite: + * for (auto v1 = i1, v2 = i2; condition; increment) { ... } + * to: + * { auto v1 = i1, v2 = i2; for (; condition; increment) { ... } } + * then lowered to: + * auto v1 = i1; + * try { + * auto v2 = i2; + * try { + * for (; condition; increment) { ... } + * } finally { v2.~this(); } + * } finally { v1.~this(); } + */ + Statements *ainit = new Statements(); + ainit->push(init), init = NULL; + ainit->push(this); + Statement *s = new CompoundStatement(loc, ainit); + s = new ScopeStatement(loc, s); s = s->semantic(sc); - --nest; - - init = new CompoundStatement(loc, ainit); - relatedLabeled = s; - - sc->pop(); + if (!s->isErrorStatement()) + { + if (LabelStatement *ls = checkLabeledLoop(sc, this)) + ls->gotoTarget = this; + relatedLabeled = s; + } return s; } assert(init == NULL); + ScopeDsymbol *sym = new ScopeDsymbol(); + sym->parent = sc->scopesym; + sc = sc->push(sym); + sc->noctor++; if (condition) { condition = condition->semantic(sc); @@ -1345,8 +1320,12 @@ Statement *ForStatement::semantic(Scope *sc) body = body->semanticNoScope(sc); sc->noctor--; - if (!nest) - sc->pop(); + sc->pop(); + + if (condition && condition->op == TOKerror || + increment && increment->op == TOKerror || + body && body->isErrorStatement()) + return new ErrorStatement(); return this; } @@ -1432,7 +1411,7 @@ void ForStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) /******************************** ForeachStatement ***************************/ -ForeachStatement::ForeachStatement(Loc loc, enum TOK op, Parameters *arguments, +ForeachStatement::ForeachStatement(Loc loc, TOK op, Parameters *arguments, Expression *aggr, Statement *body) : Statement(loc) { @@ -1478,7 +1457,8 @@ Statement *ForeachStatement::semantic(Scope *sc) if (!inferAggregate(sc, sapply)) { error("invalid foreach aggregate %s", aggr->toChars()); - return this; + Lerror: + return new ErrorStatement(); } /* Check for inference errors @@ -1487,7 +1467,7 @@ Statement *ForeachStatement::semantic(Scope *sc) { //printf("dim = %d, arguments->dim = %d\n", dim, arguments->dim); error("cannot uniquely infer foreach argument types"); - return this; + goto Lerror; } Type *tab = aggr->type->toBasetype(); @@ -1497,12 +1477,15 @@ Statement *ForeachStatement::semantic(Scope *sc) if (dim < 1 || dim > 2) { error("only one (value) or two (key,value) arguments for tuple foreach"); - return s; + goto Lerror; } Type *argtype = (*arguments)[dim-1]->type; if (argtype) - argtype = argtype->semantic(loc, sc); + { argtype = argtype->semantic(loc, sc); + if (argtype->ty == Terror) + goto Lerror; + } TypeTuple *tuple = (TypeTuple *)tab; Statements *statements = new Statements(); @@ -1533,7 +1516,9 @@ Statement *ForeachStatement::semantic(Scope *sc) if (dim == 2) { // Declare key if (arg->storageClass & (STCout | STCref | STClazy)) - error("no storage class for key %s", arg->ident->toChars()); + { error("no storage class for key %s", arg->ident->toChars()); + goto Lerror; + } arg->type = arg->type->semantic(loc, sc); TY keyty = arg->type->ty; if (keyty != Tint32 && keyty != Tuns32) @@ -1541,10 +1526,14 @@ Statement *ForeachStatement::semantic(Scope *sc) if (global.params.is64bit) { if (keyty != Tint64 && keyty != Tuns64) - error("foreach: key type must be int or uint, long or ulong, not %s", arg->type->toChars()); + { error("foreach: key type must be int or uint, long or ulong, not %s", arg->type->toChars()); + goto Lerror; + } } else - error("foreach: key type must be int or uint, not %s", arg->type->toChars()); + { error("foreach: key type must be int or uint, not %s", arg->type->toChars()); + goto Lerror; + } } Initializer *ie = new ExpInitializer(Loc(), new IntegerExp(k)); VarDeclaration *var = new VarDeclaration(loc, arg->type, arg->ident, ie); @@ -1556,7 +1545,10 @@ Statement *ForeachStatement::semantic(Scope *sc) // Declare value if (arg->storageClass & (STCout | STClazy) || arg->storageClass & STCref && !te) + { error("no storage class for value %s", arg->ident->toChars()); + goto Lerror; + } Dsymbol *var; if (te) { Type *tb = e->type->toBasetype(); @@ -1572,20 +1564,26 @@ Statement *ForeachStatement::semantic(Scope *sc) { var = new AliasDeclaration(loc, arg->ident, s); if (arg->storageClass & STCref) - error("symbol %s cannot be ref", s->toChars()); - if (argtype && argtype->ty != Terror) - error("cannot specify element type for symbol %s", s->toChars()); + { error("symbol %s cannot be ref", s->toChars()); + goto Lerror; + } + if (argtype) + { error("cannot specify element type for symbol %s", s->toChars()); + goto Lerror; + } } else if (e->op == TOKtype) { var = new AliasDeclaration(loc, arg->ident, e->type); - if (argtype && argtype->ty != Terror) - error("cannot specify element type for type %s", e->type->toChars()); + if (argtype) + { error("cannot specify element type for type %s", e->type->toChars()); + goto Lerror; + } } else { arg->type = e->type; - if (argtype && argtype->ty != Terror) + if (argtype) arg->type = argtype; Initializer *ie = new ExpInitializer(Loc(), e); VarDeclaration *v = new VarDeclaration(loc, arg->type, arg->ident, ie); @@ -1594,7 +1592,9 @@ Statement *ForeachStatement::semantic(Scope *sc) if (e->isConst() || e->op == TOKstring || e->op == TOKstructliteral || e->op == TOKarrayliteral) { if (v->storage_class & STCref) - error("constant value %s cannot be ref", ie->toChars()); + { error("constant value %s cannot be ref", ie->toChars()); + goto Lerror; + } else v->storage_class |= STCmanifest; } @@ -1604,8 +1604,10 @@ Statement *ForeachStatement::semantic(Scope *sc) else { var = new AliasDeclaration(loc, arg->ident, t); - if (argtype && argtype->ty != Terror) - error("cannot specify element type for symbol %s", s->toChars()); + if (argtype) + { error("cannot specify element type for symbol %s", s->toChars()); + goto Lerror; + } } DeclarationExp *de = new DeclarationExp(loc, var); st->push(new ExpStatement(loc, de)); @@ -1617,6 +1619,8 @@ Statement *ForeachStatement::semantic(Scope *sc) } s = new UnrolledLoopStatement(loc, statements); + if (LabelStatement *ls = checkLabeledLoop(sc, this)) + ls->gotoTarget = s; if (te && te->e0) s = new CompoundStatement(loc, new ExpStatement(te->e0->loc, te->e0), s); @@ -1641,7 +1645,7 @@ Lagain: if (dim < 1 || dim > 2) { error("only one or two arguments for array foreach"); - break; + goto Lerror2; } /* Look for special case of parsing char types out of char type @@ -1649,10 +1653,9 @@ Lagain: */ tn = tab->nextOf()->toBasetype(); if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar) - { Parameter *arg; - + { int i = (dim == 1) ? 0 : 1; // index of value - arg = (*arguments)[i]; + Parameter *arg = (*arguments)[i]; arg->type = arg->type->semantic(loc, sc); arg->type = arg->type->addStorageClass(arg->storageClass); tnv = arg->type->toBasetype(); @@ -1660,11 +1663,15 @@ Lagain: (tnv->ty == Tchar || tnv->ty == Twchar || tnv->ty == Tdchar)) { if (arg->storageClass & STCref) - error("foreach: value of UTF conversion cannot be ref"); + { error("foreach: value of UTF conversion cannot be ref"); + goto Lerror2; + } if (dim == 2) { arg = (*arguments)[0]; if (arg->storageClass & STCref) - error("foreach: key cannot be ref"); + { error("foreach: key cannot be ref"); + goto Lerror2; + } } goto Lapply; } @@ -1687,11 +1694,12 @@ Lagain: key = var; if (arg->storageClass & STCref) { - if (!var->type->invariantOf()->equals(arg->type->invariantOf()) || + if (!var->type->immutableOf()->equals(arg->type->immutableOf()) || !MODimplicitConv(var->type->mod, arg->type->mod)) { error("key type mismatch, %s to ref %s", var->type->toChars(), arg->type->toChars()); + goto Lerror2; } } } @@ -1714,11 +1722,12 @@ Lagain: var->storage_class |= STCconst; Type *t = tab->nextOf(); - if (!t->invariantOf()->equals(arg->type->invariantOf()) || + if (!t->immutableOf()->equals(arg->type->immutableOf()) || !MODimplicitConv(t->mod, arg->type->mod)) { error("argument type mismatch, %s to ref %s", t->toChars(), arg->type->toChars()); + goto Lerror2; } } } @@ -1795,6 +1804,8 @@ Lagain: body = new CompoundStatement(loc, ds, body); s = new ForStatement(loc, forinit, cond, increment, body); + if (LabelStatement *ls = checkLabeledLoop(sc, this)) + ls->gotoTarget = s; s = s->semantic(sc); break; } @@ -1839,7 +1850,7 @@ Lagain: if (dim < 1 || dim > 2) { error("only one or two arguments for associative array foreach"); - break; + goto Lerror2; } /* This only works if Key or Value is a static array. @@ -1970,6 +1981,8 @@ Lagain: makeargs, this->body); s = new ForStatement(loc, init, condition, increment, forbody); + if (LabelStatement *ls = checkLabeledLoop(sc, this)) + ls->gotoTarget = s; #if 0 printf("init: %s\n", init->toChars()); printf("condition: %s\n", condition->toChars()); @@ -1981,7 +1994,7 @@ Lagain: Lrangeerr: error("cannot infer argument types"); - break; + goto Lerror2; } #endif case Tdelegate: @@ -1995,8 +2008,6 @@ Lagain: return this; } - Type *tret = func->type->nextOf(); - TypeFunction *tfld = NULL; if (sapply) { FuncDeclaration *fdapply = sapply->isFuncDeclaration(); @@ -2044,7 +2055,9 @@ Lagain: id = arg->ident; // argument copy is not need. if ((arg->storageClass & STCref) != stc) { if (!stc) - error("foreach: cannot make %s ref", arg->ident->toChars()); + { error("foreach: cannot make %s ref", arg->ident->toChars()); + goto Lerror2; + } goto LcopyArg; } } @@ -2119,27 +2132,28 @@ Lagain: if (dim == 2) { if (arg->storageClass & STCref) - error("foreach: index cannot be ref"); + { error("foreach: index cannot be ref"); + goto Lerror2; + } if (!arg->type->equals(taa->index)) - error("foreach: index must be type %s, not %s", taa->index->toChars(), arg->type->toChars()); + { error("foreach: index must be type %s, not %s", taa->index->toChars(), arg->type->toChars()); + goto Lerror2; + } arg = (*arguments)[1]; } if (!arg->type->equals(taa->nextOf())) - error("foreach: value must be type %s, not %s", taa->nextOf()->toChars(), arg->type->toChars()); - + { error("foreach: value must be type %s, not %s", taa->nextOf()->toChars(), arg->type->toChars()); + goto Lerror2; + } /* Call: * _aaApply(aggr, keysize, flde) */ -#if IN_LLVM // LDC: Build parameters. - static const char *names[2] = { "_aaApply", "_aaApply2" }; - static FuncDeclaration *funcs[2] = { NULL, NULL }; - static TypeDelegate *dgs[2] = { NULL, NULL }; - - FuncDeclaration *fdapply; - TypeDelegate *fldeTy; + static const char *name[2] = { "_aaApply", "_aaApply2" }; + static FuncDeclaration *fdapply[2] = { NULL, NULL }; + static TypeDelegate *fldeTy[2] = { NULL, NULL }; unsigned char i = dim == 2; - if (!funcs[i]) { + if (!fdapply[i]) { Parameters* args = new Parameters; args->push(new Parameter(STCin, Type::tvoid->pointerTo(), NULL, NULL)); args->push(new Parameter(STCin, Type::tsize_t, NULL, NULL)); @@ -2147,49 +2161,32 @@ Lagain: dgargs->push(new Parameter(STCin, Type::tvoidptr, NULL, NULL)); if (dim == 2) dgargs->push(new Parameter(STCin, Type::tvoidptr, NULL, NULL)); - dgs[i] = new TypeDelegate(new TypeFunction(dgargs, Type::tint32, 0, LINKd)); - args->push(new Parameter(STCin, dgs[i], NULL, NULL)); - funcs[i] = FuncDeclaration::genCfunc(args, Type::tint32, names[i]); + fldeTy[i] = new TypeDelegate(new TypeFunction(dgargs, Type::tint32, 0, LINKd)); + args->push(new Parameter(STCin, fldeTy[i], NULL, NULL)); + fdapply[i] = FuncDeclaration::genCfunc(args, Type::tint32, name[i]); } - fdapply = funcs[i]; - fldeTy = dgs[i]; -#else - FuncDeclaration *fdapply; - if (dim == 2) - fdapply = FuncDeclaration::genCfunc(Type::tindex, "_aaApply2"); - else - fdapply = FuncDeclaration::genCfunc(Type::tindex, "_aaApply"); -#endif - ec = new VarExp(Loc(), fdapply); + ec = new VarExp(Loc(), fdapply[i]); Expressions *exps = new Expressions(); exps->push(aggr); size_t keysize = taa->index->size(); keysize = (keysize + ((size_t)Target::ptrsize-1)) & ~((size_t)Target::ptrsize-1); - exps->push(new IntegerExp(Loc(), keysize, Type::tsize_t)); - -#if IN_LLVM - // LDC paint delegate argument to the type runtime expects - if (!fldeTy->equals(flde->type)) - { + // paint delegate argument to the type runtime expects + if (!fldeTy[i]->equals(flde->type)) { flde = new CastExp(loc, flde, flde->type); - flde->type = fldeTy; + flde->type = fldeTy[i]; } -#endif + exps->push(new IntegerExp(Loc(), keysize, Type::tsize_t)); exps->push(flde); e = new CallExp(loc, ec, exps); -#if !IN_LLVM - e->type = Type::tindex; // don't run semantic() on e -#else e->type = Type::tint32; // don't run semantic() on e -#endif } else if (tab->ty == Tarray || tab->ty == Tsarray) { /* Call: * _aApply(aggr, flde) */ - static char fntab[9][3] = + static const char fntab[9][3] = { "cc","cw","cd", "wc","cc","wd", "dc","dw","dd" @@ -2214,7 +2211,7 @@ Lagain: const char *r = (op == TOKforeach_reverse) ? "R" : ""; int j = sprintf(fdname, "_aApply%s%.*s%llu", r, 2, fntab[flag], (ulonglong)dim); assert(j < sizeof(fdname) / sizeof(fdname[0])); -#if IN_LLVM // LDC: Build parameters. + FuncDeclaration *fdapply; TypeDelegate *dgty; Parameters* args = new Parameters; @@ -2227,30 +2224,19 @@ Lagain: args->push(new Parameter(STCin, dgty, NULL, NULL)); fdapply = FuncDeclaration::genCfunc(args, Type::tint32, fdname); -#else - FuncDeclaration *fdapply = FuncDeclaration::genCfunc(Type::tindex, fdname); -#endif - ec = new VarExp(Loc(), fdapply); Expressions *exps = new Expressions(); if (tab->ty == Tsarray) aggr = aggr->castTo(sc, tn->arrayOf()); exps->push(aggr); -#if IN_LLVM - // LDC paint delegate argument to the type runtime expects - if (!dgty->equals(flde->type)) - { + // paint delegate argument to the type runtime expects + if (!dgty->equals(flde->type)) { flde = new CastExp(loc, flde, flde->type); flde->type = dgty; } -#endif exps->push(flde); e = new CallExp(loc, ec, exps); -#if IN_LLVM e->type = Type::tint32; // don't run semantic() on e -#else - e->type = Type::tindex; // don't run semantic() on e -#endif } else if (tab->ty == Tdelegate) { @@ -2267,7 +2253,9 @@ Lagain: e = new CallExp(loc, aggr, exps); e = e->semantic(sc); if (e->type != Type::tint32) - error("opApply() function for %s must return an int", tab->toChars()); + { error("opApply() function for %s must return an int", tab->toChars()); + goto Lerror2; + } } else { @@ -2297,7 +2285,9 @@ Lagain: e = new CallExp(loc, ec, exps); e = e->semantic(sc); if (e->type != Type::tint32) - error("opApply() function for %s must return an int", tab->toChars()); + { error("opApply() function for %s must return an int", tab->toChars()); + goto Lerror2; + } } if (!cases->dim) @@ -2328,13 +2318,13 @@ Lagain: break; } case Terror: - s = NULL; + Lerror2: + s = new ErrorStatement(); break; default: error("foreach: %s is not an aggregate type", aggr->type->toChars()); - s = NULL; // error recovery - break; + goto Lerror2; } sc->noctor--; sc->pop(); @@ -2390,8 +2380,7 @@ void ForeachStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) if (i) buf->writestring(", "); if (a->storageClass & STCref) - buf->writestring((global.params.Dversion == 1) - ? (char*)"inout " : (char*)"ref "); + buf->writestring((char*)"ref "); if (a->type) a->type->toCBuffer(buf, a->ident, hgs); else @@ -2415,7 +2404,7 @@ void ForeachStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) #if DMDV2 -ForeachRangeStatement::ForeachRangeStatement(Loc loc, enum TOK op, Parameter *arg, +ForeachRangeStatement::ForeachRangeStatement(Loc loc, TOK op, Parameter *arg, Expression *lwr, Expression *upr, Statement *body) : Statement(loc) { @@ -2441,15 +2430,14 @@ Statement *ForeachRangeStatement::syntaxCopy() Statement *ForeachRangeStatement::semantic(Scope *sc) { //printf("ForeachRangeStatement::semantic() %p\n", this); - Statement *s = this; - lwr = lwr->semantic(sc); lwr = resolveProperties(sc, lwr); lwr = lwr->optimize(WANTvalue); if (!lwr->type) { error("invalid range lower bound %s", lwr->toChars()); - return this; + Lerror: + return new ErrorStatement(); } upr = upr->semantic(sc); @@ -2458,7 +2446,7 @@ Statement *ForeachRangeStatement::semantic(Scope *sc) if (!upr->type) { error("invalid range upper bound %s", upr->toChars()); - return this; + goto Lerror; } if (arg->type) @@ -2478,19 +2466,24 @@ Statement *ForeachRangeStatement::semantic(Scope *sc) /* Just picking the first really isn't good enough. */ arg->type = lwr->type; - arg->type = arg->type->addStorageClass(arg->storageClass); + } + else if (lwr->type == upr->type) + { + /* Same logic as CondExp ?lwr:upr + */ + arg->type = lwr->type; } else { AddExp ea(loc, lwr, upr); Expression *e = ea.typeCombine(sc); arg->type = ea.type; - arg->type = arg->type->addStorageClass(arg->storageClass); lwr = ea.e1; upr = ea.e2; } + arg->type = arg->type->addStorageClass(arg->storageClass); } -#if 1 + /* Convert to a for loop: * foreach (key; lwr .. upr) => * for (auto key = lwr, auto tmp = upr; key < tmp; ++key) @@ -2561,7 +2554,7 @@ Statement *ForeachRangeStatement::semantic(Scope *sc) } if (arg->storageClass & STCref) { - if (!key->type->invariantOf()->equals(arg->type->invariantOf()) || + if (!key->type->immutableOf()->equals(arg->type->immutableOf()) || !MODimplicitConv(key->type->mod, arg->type->mod)) { error("argument type mismatch, %s to ref %s", @@ -2569,34 +2562,10 @@ Statement *ForeachRangeStatement::semantic(Scope *sc) } } - ForStatement *fs = new ForStatement(loc, forinit, cond, increment, body); - s = fs->semantic(sc); - return s; -#else - if (!arg->type->isscalar()) - error("%s is not a scalar type", arg->type->toChars()); - - sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - sc = sc->push(sym); - - sc->noctor++; - - key = new VarDeclaration(loc, arg->type, arg->ident, NULL); - DeclarationExp *de = new DeclarationExp(loc, key); - de->semantic(sc); - - if (key->storage_class) - error("foreach range: key cannot have storage class"); - - sc->sbreak = this; - sc->scontinue = this; - body = body->semantic(sc); - - sc->noctor--; - sc->pop(); - return s; -#endif + ForStatement *s = new ForStatement(loc, forinit, cond, increment, body); + if (LabelStatement *ls = checkLabeledLoop(sc, this)) + ls->gotoTarget = s; + return s->semantic(sc); } bool ForeachRangeStatement::hasBreak() @@ -2676,15 +2645,16 @@ Statement *IfStatement::semantic(Scope *sc) // Evaluate at runtime unsigned cs0 = sc->callSuper; unsigned cs1; + unsigned *fi0 = fi0 = sc->saveFieldInit(); + unsigned *fi1 = NULL; - Scope *scd; + ScopeDsymbol *sym = new ScopeDsymbol(); + sym->parent = sc->scopesym; + Scope *scd = sc->push(sym); if (arg) { /* Declare arg, which we will set to be the * result of condition. */ - ScopeDsymbol *sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - scd = sc->push(sym); match = new VarDeclaration(loc, arg->type, arg->ident, new ExpInitializer(loc, condition)); match->parent = sc->func; @@ -2708,7 +2678,6 @@ Statement *IfStatement::semantic(Scope *sc) condition = condition->semantic(sc); condition = condition->addDtorHook(sc); condition = resolveProperties(sc, condition); - scd = sc->push(); } // Convert to boolean after declaring arg so this works: @@ -2724,11 +2693,20 @@ Statement *IfStatement::semantic(Scope *sc) scd->pop(); cs1 = sc->callSuper; + fi1 = sc->fieldinit; sc->callSuper = cs0; + sc->fieldinit = fi0; if (elsebody) elsebody = elsebody->semanticScope(sc, NULL, NULL); sc->mergeCallSuper(loc, cs1); + sc->mergeFieldInit(loc, fi1); + if (condition->op == TOKerror || + (ifbody && ifbody->isErrorStatement()) || + (elsebody && elsebody->isErrorStatement())) + { + return new ErrorStatement(); + } return this; } @@ -2941,10 +2919,12 @@ Statement *PragmaStatement::semantic(Scope *sc) { Expression *e = (*args)[i]; - e = e->ctfeSemantic(sc); + sc = sc->startCTFE(); + e = e->semantic(sc); e = resolveProperties(sc, e); - if (e->op != TOKerror && e->op != TOKtype) - e = e->ctfeInterpret(); + sc = sc->endCTFE(); + // pragma(msg) is allowed to contain types as well as expressions + e = ctfeInterpretForPragmaMsg(e); if (e->op == TOKerror) { errorSupplemental(loc, "while evaluating pragma(msg, %s)", (*args)[i]->toChars()); goto Lerror; @@ -2973,8 +2953,11 @@ Statement *PragmaStatement::semantic(Scope *sc) { Expression *e = (*args)[0]; - e = e->ctfeSemantic(sc); + sc = sc->startCTFE(); + e = e->semantic(sc); e = resolveProperties(sc, e); + sc = sc->endCTFE(); + e = e->ctfeInterpret(); (*args)[0] = e; StringExp *se = e->toString(); @@ -2985,7 +2968,7 @@ Statement *PragmaStatement::semantic(Scope *sc) char *name = (char *)mem.malloc(se->len + 1); memcpy(name, se->string, se->len); name[se->len] = 0; - printf("library %s\n", name); + fprintf(global.stdmsg, "library %s\n", name); mem.free(name); } } @@ -3010,8 +2993,12 @@ Statement *PragmaStatement::semantic(Scope *sc) else { Expression *e = (*args)[0]; - e = e->ctfeSemantic(sc); + + sc = sc->startCTFE(); + e = e->semantic(sc); e = resolveProperties(sc, e); + sc = sc->endCTFE(); + e = e->ctfeInterpret(); (*args)[0] = e; Dsymbol *sa = getDsymbol(e); @@ -3163,8 +3150,9 @@ Statement *SwitchStatement::semantic(Scope *sc) condition->type = condition->type->constOf(); } else - { condition = condition->integralPromotions(sc); - if (!condition->type->isintegral()) + { + condition = condition->integralPromotions(sc); + if (condition->op != TOKerror && !condition->type->isintegral()) error("'%s' must be of integral or string type, it is a %s", condition->toChars(), condition->type->toChars()); } condition = condition->optimize(WANTvalue); @@ -3233,8 +3221,11 @@ Statement *SwitchStatement::semantic(Scope *sc) if (em) { for (size_t j = 0; j < cases->dim; j++) - { CaseStatement *cs = (*cases)[j]; - if (cs->exp->equals(em->value) || cs->exp->toInteger() == em->value->toInteger()) + { + CaseStatement *cs = (*cases)[j]; + if (cs->exp->equals(em->value) || + (!cs->exp->type->isString() && !em->value->type->isString() && + cs->exp->toInteger() == em->value->toInteger())) goto L1; } error("enum member %s not represented in final switch", em->toChars()); @@ -3251,7 +3242,7 @@ Statement *SwitchStatement::semantic(Scope *sc) if (!sc->sw->sdefault && (!isFinal || needswitcherror || global.params.useAssert)) { hasNoDefault = 1; - if (!isFinal) + if (!isFinal && !body->isErrorStatement()) deprecation("non-final switch statement without a default is deprecated"); // Generate runtime error if the default is hit @@ -3352,11 +3343,14 @@ Statement *CaseStatement::syntaxCopy() } Statement *CaseStatement::semantic(Scope *sc) -{ SwitchStatement *sw = sc->sw; +{ + SwitchStatement *sw = sc->sw; //printf("CaseStatement::semantic() %s\n", toChars()); - exp = exp->ctfeSemantic(sc); + sc = sc->startCTFE(); + exp = exp->semantic(sc); exp = resolveProperties(sc, exp); + sc = sc->endCTFE(); if (sw) { #if IN_LLVM @@ -3430,7 +3424,7 @@ Statement *CaseStatement::semantic(Scope *sc) return this; } -int CaseStatement::compare(Object *obj) +int CaseStatement::compare(RootObject *obj) { // Sort cases so we can do an efficient lookup CaseStatement *cs2 = (CaseStatement *)(obj); @@ -3476,17 +3470,27 @@ Statement *CaseRangeStatement::syntaxCopy() Statement *CaseRangeStatement::semantic(Scope *sc) { SwitchStatement *sw = sc->sw; + if (sw == NULL) + { + error("case range not in switch statement"); + return NULL; + } + //printf("CaseRangeStatement::semantic() %s\n", toChars()); if (sw->isFinal) error("case ranges not allowed in final switch"); - first = first->ctfeSemantic(sc); + sc = sc->startCTFE(); + first = first->semantic(sc); first = resolveProperties(sc, first); + sc = sc->endCTFE(); first = first->implicitCastTo(sc, sw->condition->type); first = first->ctfeInterpret(); - last = last->ctfeSemantic(sc); + sc = sc->startCTFE(); + last = last->semantic(sc); last = resolveProperties(sc, last); + sc = sc->endCTFE(); last = last->implicitCastTo(sc, sw->condition->type); last = last->ctfeInterpret(); @@ -3806,17 +3810,14 @@ Statement *ReturnStatement::semantic(Scope *sc) if (!tf->isref) exp = exp->optimize(WANTvalue); + if (Expression *e = exp->isTemp()) + exp = e; // don't need temporary if (exp->op == TOKcall) - valueNoDtor(exp); - else - { - Expression *e = exp->isTemp(); - if (e) - exp = e; // don't need temporary - } + exp = valueNoDtor(exp); if (fd->nrvo_can && exp->op == TOKvar) - { VarExp *ve = (VarExp *)exp; + { + VarExp *ve = (VarExp *)exp; VarDeclaration *v = ve->var->isVarDeclaration(); if (isRefReturn) @@ -3825,8 +3826,10 @@ Statement *ReturnStatement::semantic(Scope *sc) else if (!v || v->isOut() || v->isRef()) fd->nrvo_can = 0; else if (fd->nrvo_var == NULL) - { if (!v->isDataseg() && !v->isParameter() && v->toParent2() == fd) - { //printf("Setting nrvo to %s\n", v->toChars()); + { + if (!v->isDataseg() && !v->isParameter() && v->toParent2() == fd) + { + //printf("Setting nrvo to %s\n", v->toChars()); fd->nrvo_var = v; } else @@ -3902,14 +3905,11 @@ Statement *ReturnStatement::semantic(Scope *sc) tf->next = exp->type; //fd->type = tf->semantic(loc, sc); // Removed with 6902 if (!fd->tintro) - { tret = tf->next; + { + tret = tf->next; tbret = tret->toBasetype(); } } - if (!fd->nrvo_can && exp->isLvalue() && !isRefReturn) - { - exp = callCpCtor(exp->loc, sc, exp, 1); - } if (fd->returnLabel) eorg = exp->copy(); @@ -3919,16 +3919,11 @@ Statement *ReturnStatement::semantic(Scope *sc) } else if (tbret->ty != Tvoid) { - if (!fd->nrvo_can && exp->isLvalue() && !isRefReturn) - { - exp = callCpCtor(exp->loc, sc, exp, 1); - } - if (!exp->type->implicitConvTo(tret) && fd->parametersIntersect(exp->type)) { - if (exp->type->invariantOf()->implicitConvTo(tret)) - exp = exp->castTo(sc, exp->type->invariantOf()); + if (exp->type->immutableOf()->implicitConvTo(tret)) + exp = exp->castTo(sc, exp->type->immutableOf()); else if (exp->type->wildOf()->implicitConvTo(tret)) exp = exp->castTo(sc, exp->type->wildOf()); } @@ -3942,6 +3937,10 @@ Statement *ReturnStatement::semantic(Scope *sc) if (!isRefReturn) exp = exp->optimize(WANTvalue); + + if (!fd->returns) + fd->returns = new ReturnStatements(); + fd->returns->push(this); } } else if (fd->inferRetType) @@ -4054,8 +4053,23 @@ Statement *ReturnStatement::semantic(Scope *sc) if (sc->callSuper & CSXany_ctor && !(sc->callSuper & (CSXthis_ctor | CSXsuper_ctor))) error("return without calling constructor"); - sc->callSuper |= CSXreturn; + if (sc->fieldinit) + { + AggregateDeclaration *ad = fd->isAggregateMember2(); + assert(ad); + size_t dim = sc->fieldinit_dim; + for (size_t i = 0; i < dim; i++) + { + VarDeclaration *v = ad->fields[i]; + bool mustInit = (v->storage_class & STCnodefaultctor || + v->type->needsNested()); + if (mustInit && !(sc->fieldinit[i] & CSXthis_ctor)) + error("an earlier return statement skips field %s initialization", v->toChars()); + + sc->fieldinit[i] |= CSXreturn; + } + } // See if all returns are instead to be replaced with a goto returnLabel; if (fd->returnLabel) @@ -4075,19 +4089,20 @@ Statement *ReturnStatement::semantic(Scope *sc) if (exp && tbret->ty == Tvoid && !implicit0) { - /* Replace: - * return exp; - * with: - * exp; return; - */ - Statement *s = new ExpStatement(loc, exp); - s = s->semantic(sc); - if (exp->type->ty != Tvoid) { error("cannot return non-void from void function"); } + /* Replace: + * return exp; + * with: + * cast(void)exp; return; + */ + Expression *ce = new CastExp(loc, exp, Type::tvoid); + Statement *s = new ExpStatement(loc, ce); + s = s->semantic(sc); + exp = NULL; return new CompoundStatement(loc, s, this); } @@ -4136,13 +4151,10 @@ Statement *BreakStatement::semantic(Scope *sc) { ident = fixupLabelName(sc, ident); - Scope *scx; FuncDeclaration *thisfunc = sc->func; - for (scx = sc; scx; scx = scx->enclosing) + for (Scope *scx = sc; scx; scx = scx->enclosing) { - LabelStatement *ls; - if (scx->func != thisfunc) // if in enclosing function { if (sc->fes) // if this is the body of a foreach @@ -4154,15 +4166,14 @@ Statement *BreakStatement::semantic(Scope *sc) * Case numbers start with 2, not 0, as 0 is continue * and 1 is break. */ - Statement *s; sc->fes->cases->push(this); - s = new ReturnStatement(Loc(), new IntegerExp(sc->fes->cases->dim + 1)); + Statement *s = new ReturnStatement(Loc(), new IntegerExp(sc->fes->cases->dim + 1)); return s; } break; // can't break to it } - ls = scx->slabel; + LabelStatement *ls = scx->slabel; if (ls && ls->ident == ident) { Statement *s = ls->statement; @@ -4170,30 +4181,37 @@ Statement *BreakStatement::semantic(Scope *sc) if (!s->hasBreak()) error("label '%s' has no break", ident->toChars()); #if !IN_LLVM - if (ls->tf != sc->tf) + else if (ls->tf != sc->tf) #else - if (ls->enclosingFinally != sc->enclosingFinally) + else if (ls->enclosingFinally != sc->enclosingFinally) #endif error("cannot break out of finally block"); - + else #if IN_LLVM - this->target = ls; + { + this->target = ls; #endif - return this; + return this; +#if IN_LLVM + } +#endif + return new ErrorStatement(); + } } error("enclosing label '%s' for break not found", ident->toChars()); + return new ErrorStatement(); } else if (!sc->sbreak) { if (sc->fes) - { Statement *s; - + { // Replace break; with return 1; - s = new ReturnStatement(Loc(), new IntegerExp(1)); + Statement *s = new ReturnStatement(Loc(), new IntegerExp(1)); return s; } error("break is not inside a loop or switch"); + return new ErrorStatement(); } return this; } @@ -4265,9 +4283,8 @@ Statement *ContinueStatement::semantic(Scope *sc) * Case numbers start with 2, not 0, as 0 is continue * and 1 is break. */ - Statement *s; sc->fes->cases->push(this); - s = new ReturnStatement(Loc(), new IntegerExp(sc->fes->cases->dim + 1)); + Statement *s = new ReturnStatement(Loc(), new IntegerExp(sc->fes->cases->dim + 1)); return s; } break; // can't continue to it @@ -4281,27 +4298,32 @@ Statement *ContinueStatement::semantic(Scope *sc) if (!s->hasContinue()) error("label '%s' has no continue", ident->toChars()); #if !IN_LLVM - if (ls->tf != sc->tf) + else if (ls->tf != sc->tf) #else - if (ls->enclosingFinally != sc->enclosingFinally) + else if (ls->enclosingFinally != sc->enclosingFinally) #endif error("cannot continue out of finally block"); - + else #if IN_LLVM - this->target = ls; + { + this->target = ls; #endif - return this; + return this; +#if IN_LLVM + } +#endif + return new ErrorStatement(); } } error("enclosing label '%s' for continue not found", ident->toChars()); + return new ErrorStatement(); } else if (!sc->scontinue) { if (sc->fes) - { Statement *s; - + { // Replace continue; with return 0; - s = new ReturnStatement(Loc(), new IntegerExp(0)); + Statement *s = new ReturnStatement(Loc(), new IntegerExp(0)); return s; } error("continue is not inside a loop"); @@ -4367,7 +4389,10 @@ Statement *SynchronizedStatement::semantic(Scope *sc) goto Lbody; ClassDeclaration *cd = exp->type->isClassHandle(); if (!cd) + { error("can only synchronize on class objects, not '%s'", exp->type->toChars()); + return new ErrorStatement(); + } else if (cd->isInterfaceDeclaration()) { /* Cast the interface to an object, as the object has the monitor, * not the interface. @@ -4399,22 +4424,15 @@ Statement *SynchronizedStatement::semantic(Scope *sc) Statements *cs = new Statements(); cs->push(new ExpStatement(loc, tmp)); -#if IN_LLVM // LDC: Build parameters. Parameters* args = new Parameters; args->push(new Parameter(STCin, ClassDeclaration::object->type, NULL, NULL)); + FuncDeclaration *fdenter = FuncDeclaration::genCfunc(args, Type::tvoid, Id::monitorenter); -#else - FuncDeclaration *fdenter = FuncDeclaration::genCfunc(Type::tvoid, Id::monitorenter); -#endif Expression *e = new CallExp(loc, new VarExp(loc, fdenter), new VarExp(loc, tmp)); e->type = Type::tvoid; // do not run semantic on e cs->push(new ExpStatement(loc, e)); -#if IN_LLVM // LDC: Build parameters. FuncDeclaration *fdexit = FuncDeclaration::genCfunc(args, Type::tvoid, Id::monitorexit); -#else - FuncDeclaration *fdexit = FuncDeclaration::genCfunc(Type::tvoid, Id::monitorexit); -#endif e = new CallExp(loc, new VarExp(loc, fdexit), new VarExp(loc, tmp)); e->type = Type::tvoid; // do not run semantic on e Statement *s = new ExpStatement(loc, e); @@ -4433,36 +4451,24 @@ Statement *SynchronizedStatement::semantic(Scope *sc) * try { body } finally { _d_criticalexit(critsec.ptr); } */ Identifier *id = Lexer::uniqueId("__critsec"); -#if !IN_LLVM - Type *t = new TypeSArray(Type::tint8, new IntegerExp(Target::ptrsize + (global.params.is64bit ? os_critsecsize64() : os_critsecsize32()))); -#else - Type *t = new TypeSArray(Type::tint8, new IntegerExp(Target::ptrsize + os_critsecsize())); -#endif + Type *t = new TypeSArray(Type::tint8, new IntegerExp(Target::ptrsize + Target::critsecsize())); VarDeclaration *tmp = new VarDeclaration(loc, t, id, NULL); tmp->storage_class |= STCgshared | STCstatic; Statements *cs = new Statements(); cs->push(new ExpStatement(loc, tmp)); -#if IN_LLVM // LDC: Build parameters. Parameters* args = new Parameters; args->push(new Parameter(STCin, t->pointerTo(), NULL, NULL)); FuncDeclaration *fdenter = FuncDeclaration::genCfunc(args, Type::tvoid, Id::criticalenter); -#else - FuncDeclaration *fdenter = FuncDeclaration::genCfunc(Type::tvoid, Id::criticalenter); -#endif Expression *e = new DotIdExp(loc, new VarExp(loc, tmp), Id::ptr); e = e->semantic(sc); e = new CallExp(loc, new VarExp(loc, fdenter), e); e->type = Type::tvoid; // do not run semantic on e cs->push(new ExpStatement(loc, e)); -#if IN_LLVM // LDC: Build parameters. FuncDeclaration *fdexit = FuncDeclaration::genCfunc(args, Type::tvoid, Id::criticalexit); -#else - FuncDeclaration *fdexit = FuncDeclaration::genCfunc(Type::tvoid, Id::criticalexit); -#endif e = new DotIdExp(loc, new VarExp(loc, tmp), Id::ptr); e = e->semantic(sc); e = new CallExp(loc, new VarExp(loc, fdexit), e); @@ -4487,6 +4493,8 @@ Lbody: sc->enclosingScopeExit = oldScopeExit; } #endif + if (body && body->isErrorStatement()) + return body; return this; } @@ -4545,7 +4553,7 @@ Statement *WithStatement::semantic(Scope *sc) exp = exp->semantic(sc); exp = resolveProperties(sc, exp); if (exp->op == TOKerror) - return NULL; + return new ErrorStatement(); if (exp->op == TOKimport) { ScopeExp *es = (ScopeExp *)exp; @@ -4558,13 +4566,21 @@ Statement *WithStatement::semantic(Scope *sc) sym = s ? s->isScopeDsymbol() : NULL; if (!sym) { error("with type %s has no members", es->toChars()); - if (body) - body = body->semantic(sc); - return this; + return new ErrorStatement(); } } else - { Type *t = exp->type; + { + Type *t = exp->type; + t = t->toBasetype(); + + Expression *olde = exp; + if (t->ty == Tpointer) + { + exp = new PtrExp(loc, exp); + exp = exp->semantic(sc); + t = exp->type->toBasetype(); + } assert(t); t = t->toBasetype(); @@ -4591,19 +4607,25 @@ Statement *WithStatement::semantic(Scope *sc) wthis = new VarDeclaration(loc, e->type, Id::withSym, init); wthis->semantic(sc); sym = new WithScopeSymbol(this); + // Need to set the scope to make use of resolveAliasThis + sym->setScope(sc); sym->parent = sc->scopesym; } else - { error("with expressions must be aggregate types, not '%s'", exp->type->toChars()); - return NULL; + { + error("with expressions must be aggregate types or pointers to them, not '%s'", olde->type->toChars()); + return new ErrorStatement(); } } - sc = sc->push(sym); if (body) + { + sc = sc->push(sym); body = body->semantic(sc); - - sc->pop(); + sc->pop(); + if (body && body->isErrorStatement()) + return body; + } return this; } @@ -4660,9 +4682,14 @@ Statement *TryCatchStatement::semantic(Scope *sc) /* Even if body is NULL, still do semantic analysis on catches */ + bool catchErrors = false; for (size_t i = 0; i < catches->dim; i++) { Catch *c = (*catches)[i]; c->semantic(sc); + if (c->type->ty == Terror) + { catchErrors = true; + continue; + } // Determine if current catch 'hides' any previous catches for (size_t j = 0; j < i; j++) @@ -4671,11 +4698,22 @@ Statement *TryCatchStatement::semantic(Scope *sc) char *sj = cj->loc.toChars(); if (c->type->toBasetype()->implicitConvTo(cj->type->toBasetype())) + { error("catch at %s hides catch at %s", sj, si); + catchErrors = true; + } } } + if (catchErrors) + return new ErrorStatement(); - if (!body || !body->hasCode()) + if (!body) + return NULL; + + if (body->isErrorStatement()) + return body; + + if (!body->hasCode()) { return NULL; } @@ -4728,7 +4766,11 @@ int TryCatchStatement::blockExit(bool mustNotThrow) /* If we're catching Object, then there is no throwing */ Identifier *id = c->type->toBasetype()->isClassHandle()->ident; - if (id == Id::Object || id == Id::Throwable || id == Id::Exception) + if (id == Id::Object || id == Id::Throwable) + { + result &= ~(BEthrow | BEerrthrow); + } + if (id == Id::Exception) { result &= ~BEthrow; } @@ -4779,9 +4821,6 @@ Catch *Catch::syntaxCopy() void Catch::semantic(Scope *sc) { - if (type && type->deco) - return; - //printf("Catch::semantic(%s)\n", ident->toChars()); #ifndef IN_GCC @@ -4829,7 +4868,7 @@ void Catch::semantic(Scope *sc) else if (ident) { var = new VarDeclaration(loc, type, ident, NULL); - var->parent = sc->parent; + var->semantic(sc); sc->insert(var); } handler = handler->semantic(sc); @@ -5070,10 +5109,13 @@ Statement *ThrowStatement::semantic(Scope *sc) exp = exp->semantic(sc); exp = resolveProperties(sc, exp); if (exp->op == TOKerror) - return this; + return new ErrorStatement(); ClassDeclaration *cd = exp->type->toBasetype()->isClassHandle(); if (!cd || ((cd != ClassDeclaration::throwable) && !ClassDeclaration::throwable->isBaseOf(cd, NULL))) + { error("can only throw class objects derived from Throwable, not type %s", exp->type->toChars()); + return new ErrorStatement(); + } return this; } @@ -5081,18 +5123,19 @@ Statement *ThrowStatement::semantic(Scope *sc) int ThrowStatement::blockExit(bool mustNotThrow) { Type *t = exp->type->toBasetype(); - if (mustNotThrow && t->ty != Terror) - { - ClassDeclaration *cd = t->isClassHandle(); - assert(cd); + ClassDeclaration *cd = t->isClassHandle(); + assert(cd); - // Bugzilla 8675 - // Throwing Errors is allowed even if mustNotThrow - if (!internalThrow && - cd != ClassDeclaration::errorException && - !ClassDeclaration::errorException->isBaseOf(cd, NULL)) - error("%s is thrown but not caught", exp->type->toChars()); + if (cd == ClassDeclaration::errorException || + ClassDeclaration::errorException->isBaseOf(cd, NULL)) + { + return BEerrthrow; } + // Bugzilla 8675 + // Throwing Errors is allowed even if mustNotThrow + if (!internalThrow && mustNotThrow) + error("%s is thrown but not caught", exp->type->toChars()); + return BEthrow; } @@ -5211,7 +5254,10 @@ Statement *GotoStatement::semantic(Scope *sc) #else if (label->statement && label->statement->enclosingFinally != sc->enclosingFinally) #endif + { error("cannot goto in or out of finally block"); + return new ErrorStatement(); + } return this; } @@ -5243,6 +5289,7 @@ LabelStatement::LabelStatement(Loc loc, Identifier *ident, Statement *statement) this->enclosingFinally = NULL; this->enclosingScopeExit = NULL; #endif + this->gotoTarget = NULL; this->lblock = NULL; this->fwdrefs = NULL; } @@ -5262,7 +5309,10 @@ Statement *LabelStatement::semantic(Scope *sc) ls = fd->searchLabel(ident); if (ls->statement) + { error("Label '%s' already defined", ls->toChars()); + return new ErrorStatement(); + } else ls->statement = this; #if !IN_LLVM @@ -5274,6 +5324,12 @@ Statement *LabelStatement::semantic(Scope *sc) sc = sc->push(); sc->scopesym = sc->enclosing->scopesym; sc->callSuper |= CSXlabel; + if (sc->fieldinit) + { + size_t dim = sc->fieldinit_dim; + for (size_t i = 0; i < dim; i++) + sc->fieldinit[i] |= CSXlabel; + } sc->slabel = this; if (statement) statement = statement->semanticNoScope(sc); diff --git a/dmd2/statement.h b/dmd2/statement.h index 3636ec79..84689ba1 100644 --- a/dmd2/statement.h +++ b/dmd2/statement.h @@ -23,40 +23,42 @@ struct OutBuffer; struct Scope; -struct Expression; -struct LabelDsymbol; -struct Identifier; -struct IfStatement; -struct ExpStatement; -struct DefaultStatement; -struct VarDeclaration; -struct Condition; -struct Module; +class Expression; +class LabelDsymbol; +class Identifier; +class IfStatement; +class ExpStatement; +class DefaultStatement; +class VarDeclaration; +class Condition; +class Module; struct Token; struct InlineCostState; struct InlineDoState; struct InlineScanState; -struct ReturnStatement; -struct CompoundStatement; -struct Parameter; -struct StaticAssert; -struct AsmStatement; +class ErrorStatement; +class ReturnStatement; +class CompoundStatement; +class Parameter; +class StaticAssert; +class AsmStatement; #if IN_LLVM -struct AsmBlockStatement; +class AsmBlockStatement; #endif -struct GotoStatement; -struct ScopeStatement; -struct TryCatchStatement; -struct TryFinallyStatement; -struct CaseStatement; -struct DefaultStatement; -struct LabelStatement; +class GotoStatement; +class ScopeStatement; +class TryCatchStatement; +class TryFinallyStatement; +class CaseStatement; +class DefaultStatement; +class LabelStatement; struct HdrGenState; struct InterState; +struct CompiledCtfeFunction; #if IN_LLVM -struct CaseStatement; -struct LabelStatement; -struct SynchronizedStatement; +class CaseStatement; +class LabelStatement; +class SynchronizedStatement; #endif enum TOK; @@ -77,8 +79,8 @@ struct IRState; struct Blockx; #ifdef IN_GCC -union tree_node; typedef union tree_node block; -union tree_node; typedef union tree_node elem; +typedef union tree_node block; +typedef union tree_node elem; #elif IN_LLVM class DValue; typedef DValue elem; @@ -100,11 +102,13 @@ enum BE BEhalt = 0x10, BEbreak = 0x20, BEcontinue = 0x40, + BEerrthrow = 0x80, BEany = (BEfallthru | BEthrow | BEreturn | BEgoto | BEhalt), }; -struct Statement : Object +class Statement : public RootObject { +public: Loc loc; virtual ~Statement() {} @@ -118,7 +122,6 @@ struct Statement : Object void warning(const char *format, ...); void deprecation(const char *format, ...); virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - virtual ScopeStatement *isScopeStatement() { return NULL; } virtual Statement *semantic(Scope *sc); Statement *semanticScope(Scope *sc, Statement *sbreak, Statement *scontinue); Statement *semanticNoScope(Scope *sc); @@ -136,6 +139,7 @@ struct Statement : Object virtual Statements *flatten(Scope *sc); virtual Expression *interpret(InterState *istate); virtual bool apply(sapply_fp_t fp, void *param); + virtual void ctfeCompile(CompiledCtfeFunction *ccf); virtual Statement *last(); virtual int inlineCost(InlineCostState *ics); @@ -147,6 +151,8 @@ struct Statement : Object virtual void toIR(IRState *irs); // Avoid dynamic_cast + virtual ErrorStatement *isErrorStatement() { return NULL; } + virtual ScopeStatement *isScopeStatement() { return NULL; } virtual ExpStatement *isExpStatement() { return NULL; } virtual CompoundStatement *isCompoundStatement() { return NULL; } virtual ReturnStatement *isReturnStatement() { return NULL; } @@ -162,8 +168,23 @@ struct Statement : Object #endif }; -struct PeelStatement : Statement +/** Any Statement that fails semantic() or has a component that is an ErrorExp or + * a TypeError should return an ErrorStatement from semantic(). + */ +class ErrorStatement : public Statement { +public: + ErrorStatement(); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + int blockExit(bool mustNotThrow); + + ErrorStatement *isErrorStatement() { return this; } +}; + +class PeelStatement : public Statement +{ +public: Statement *s; PeelStatement(Statement *s); @@ -171,8 +192,9 @@ struct PeelStatement : Statement bool apply(sapply_fp_t fp, void *param); }; -struct ExpStatement : Statement +class ExpStatement : public Statement { +public: Expression *exp; ExpStatement(Loc loc, Expression *exp); @@ -181,6 +203,7 @@ struct ExpStatement : Statement void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Statement *semantic(Scope *sc); Expression *interpret(InterState *istate); + void ctfeCompile(CompiledCtfeFunction *ccf); int blockExit(bool mustNotThrow); bool hasCodeImpl(); Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); @@ -198,8 +221,9 @@ struct ExpStatement : Statement #endif }; -struct DtorExpStatement : ExpStatement +class DtorExpStatement : public ExpStatement { +public: /* Wraps an expression that is the destruction of 'var' */ @@ -210,8 +234,9 @@ struct DtorExpStatement : ExpStatement void toIR(IRState *irs); }; -struct CompileStatement : Statement +class CompileStatement : public Statement { +public: Expression *exp; CompileStatement(Loc loc, Expression *exp); @@ -222,8 +247,9 @@ struct CompileStatement : Statement int blockExit(bool mustNotThrow); }; -struct CompoundStatement : Statement +class CompoundStatement : public Statement { +public: Statements *statements; CompoundStatement(Loc loc, Statements *s); @@ -238,6 +264,7 @@ struct CompoundStatement : Statement ReturnStatement *isReturnStatement(); Expression *interpret(InterState *istate); bool apply(sapply_fp_t fp, void *param); + void ctfeCompile(CompiledCtfeFunction *ccf); Statement *last(); int inlineCost(InlineCostState *ics); @@ -255,8 +282,9 @@ struct CompoundStatement : Statement #endif }; -struct CompoundDeclarationStatement : CompoundStatement +class CompoundDeclarationStatement : public CompoundStatement { +public: CompoundDeclarationStatement(Loc loc, Statements *s); Statement *syntaxCopy(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -265,8 +293,9 @@ struct CompoundDeclarationStatement : CompoundStatement /* The purpose of this is so that continue will go to the next * of the statements, and break will go to the end of the statements. */ -struct UnrolledLoopStatement : Statement +class UnrolledLoopStatement : public Statement { +public: Statements *statements; UnrolledLoopStatement(Loc loc, Statements *statements); @@ -277,6 +306,7 @@ struct UnrolledLoopStatement : Statement int blockExit(bool mustNotThrow); Expression *interpret(InterState *istate); bool apply(sapply_fp_t fp, void *param); + void ctfeCompile(CompiledCtfeFunction *ccf); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); int inlineCost(InlineCostState *ics); @@ -287,8 +317,9 @@ struct UnrolledLoopStatement : Statement void toIR(IRState *irs); }; -struct ScopeStatement : Statement +class ScopeStatement : public Statement { +public: Statement *statement; ScopeStatement(Loc loc, Statement *s); @@ -302,6 +333,7 @@ struct ScopeStatement : Statement bool hasCodeImpl(); Expression *interpret(InterState *istate); bool apply(sapply_fp_t fp, void *param); + void ctfeCompile(CompiledCtfeFunction *ccf); int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); @@ -311,8 +343,9 @@ struct ScopeStatement : Statement void toIR(IRState *irs); }; -struct WhileStatement : Statement +class WhileStatement : public Statement { +public: Expression *condition; Statement *body; @@ -324,6 +357,7 @@ struct WhileStatement : Statement int blockExit(bool mustNotThrow); Expression *interpret(InterState *istate); bool apply(sapply_fp_t fp, void *param); + void ctfeCompile(CompiledCtfeFunction *ccf); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Statement *inlineScan(InlineScanState *iss); @@ -331,8 +365,9 @@ struct WhileStatement : Statement void toIR(IRState *irs); }; -struct DoStatement : Statement +class DoStatement : public Statement { +public: Statement *body; Expression *condition; @@ -344,6 +379,7 @@ struct DoStatement : Statement int blockExit(bool mustNotThrow); Expression *interpret(InterState *istate); bool apply(sapply_fp_t fp, void *param); + void ctfeCompile(CompiledCtfeFunction *ccf); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Statement *inlineScan(InlineScanState *iss); @@ -351,13 +387,13 @@ struct DoStatement : Statement void toIR(IRState *irs); }; -struct ForStatement : Statement +class ForStatement : public Statement { +public: Statement *init; Expression *condition; Expression *increment; Statement *body; - int nest; // When wrapped in try/finally clauses, this points to the outermost one, // which may have an associated label. Internal break/continue statements @@ -366,7 +402,6 @@ struct ForStatement : Statement ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body); Statement *syntaxCopy(); - Statement *semanticInit(Scope *sc, Statements *ainit, size_t i); Statement *semantic(Scope *sc); Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); Statement *getRelatedLabeled() { return relatedLabeled ? relatedLabeled : this; } @@ -375,6 +410,7 @@ struct ForStatement : Statement int blockExit(bool mustNotThrow); Expression *interpret(InterState *istate); bool apply(sapply_fp_t fp, void *param); + void ctfeCompile(CompiledCtfeFunction *ccf); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); int inlineCost(InlineCostState *ics); @@ -384,9 +420,10 @@ struct ForStatement : Statement void toIR(IRState *irs); }; -struct ForeachStatement : Statement +class ForeachStatement : public Statement { - enum TOK op; // TOKforeach or TOKforeach_reverse +public: + TOK op; // TOKforeach or TOKforeach_reverse Parameters *arguments; // array of Parameter*'s Expression *aggr; Statement *body; @@ -399,7 +436,7 @@ struct ForeachStatement : Statement Statements *cases; // put breaks, continues, gotos and returns here CompoundStatements *gotos; // forward referenced goto's go here - ForeachStatement(Loc loc, enum TOK op, Parameters *arguments, Expression *aggr, Statement *body); + ForeachStatement(Loc loc, TOK op, Parameters *arguments, Expression *aggr, Statement *body); Statement *syntaxCopy(); Statement *semantic(Scope *sc); bool checkForArgTypes(); @@ -410,6 +447,7 @@ struct ForeachStatement : Statement int blockExit(bool mustNotThrow); Expression *interpret(InterState *istate); bool apply(sapply_fp_t fp, void *param); + void ctfeCompile(CompiledCtfeFunction *ccf); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Statement *inlineScan(InlineScanState *iss); @@ -418,9 +456,10 @@ struct ForeachStatement : Statement }; #if DMDV2 -struct ForeachRangeStatement : Statement +class ForeachRangeStatement : public Statement { - enum TOK op; // TOKforeach or TOKforeach_reverse +public: + TOK op; // TOKforeach or TOKforeach_reverse Parameter *arg; // loop index variable Expression *lwr; Expression *upr; @@ -428,7 +467,7 @@ struct ForeachRangeStatement : Statement VarDeclaration *key; - ForeachRangeStatement(Loc loc, enum TOK op, Parameter *arg, + ForeachRangeStatement(Loc loc, TOK op, Parameter *arg, Expression *lwr, Expression *upr, Statement *body); Statement *syntaxCopy(); Statement *semantic(Scope *sc); @@ -437,6 +476,7 @@ struct ForeachRangeStatement : Statement int blockExit(bool mustNotThrow); Expression *interpret(InterState *istate); bool apply(sapply_fp_t fp, void *param); + void ctfeCompile(CompiledCtfeFunction *ccf); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Statement *inlineScan(InlineScanState *iss); @@ -445,8 +485,9 @@ struct ForeachRangeStatement : Statement }; #endif -struct IfStatement : Statement +class IfStatement : public Statement { +public: Parameter *arg; Expression *condition; Statement *ifbody; @@ -459,6 +500,7 @@ struct IfStatement : Statement Statement *semantic(Scope *sc); Expression *interpret(InterState *istate); bool apply(sapply_fp_t fp, void *param); + void ctfeCompile(CompiledCtfeFunction *ccf); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); int blockExit(bool mustNotThrow); IfStatement *isIfStatement() { return this; } @@ -471,8 +513,9 @@ struct IfStatement : Statement void toIR(IRState *irs); }; -struct ConditionalStatement : Statement +class ConditionalStatement : public Statement { +public: Condition *condition; Statement *ifbody; Statement *elsebody; @@ -487,8 +530,9 @@ struct ConditionalStatement : Statement void toCBuffer(OutBuffer *buf, HdrGenState *hgs); }; -struct PragmaStatement : Statement +class PragmaStatement : public Statement { +public: Identifier *ident; Expressions *args; // array of Expression's Statement *body; @@ -504,8 +548,9 @@ struct PragmaStatement : Statement void toIR(IRState *irs); }; -struct StaticAssertStatement : Statement +class StaticAssertStatement : public Statement { +public: StaticAssert *sa; StaticAssertStatement(StaticAssert *sa); @@ -516,8 +561,9 @@ struct StaticAssertStatement : Statement void toCBuffer(OutBuffer *buf, HdrGenState *hgs); }; -struct SwitchStatement : Statement +class SwitchStatement : public Statement { +public: Expression *condition; Statement *body; bool isFinal; @@ -542,6 +588,7 @@ struct SwitchStatement : Statement int blockExit(bool mustNotThrow); Expression *interpret(InterState *istate); bool apply(sapply_fp_t fp, void *param); + void ctfeCompile(CompiledCtfeFunction *ccf); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Statement *inlineScan(InlineScanState *iss); @@ -549,8 +596,9 @@ struct SwitchStatement : Statement void toIR(IRState *irs); }; -struct CaseStatement : Statement +class CaseStatement : public Statement { +public: Expression *exp; Statement *statement; @@ -564,11 +612,12 @@ struct CaseStatement : Statement CaseStatement(Loc loc, Expression *exp, Statement *s); Statement *syntaxCopy(); Statement *semantic(Scope *sc); - int compare(Object *obj); + int compare(RootObject *obj); int blockExit(bool mustNotThrow); bool comeFromImpl(); Expression *interpret(InterState *istate); bool apply(sapply_fp_t fp, void *param); + void ctfeCompile(CompiledCtfeFunction *ccf); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); CaseStatement *isCaseStatement() { return this; } @@ -584,8 +633,9 @@ struct CaseStatement : Statement #if DMDV2 -struct CaseRangeStatement : Statement +class CaseRangeStatement : public Statement { +public: Expression *first; Expression *last; Statement *statement; @@ -599,8 +649,9 @@ struct CaseRangeStatement : Statement #endif -struct DefaultStatement : Statement +class DefaultStatement : public Statement { +public: Statement *statement; #ifdef IN_GCC block *cblock; // back end: label for the block @@ -617,6 +668,7 @@ struct DefaultStatement : Statement bool comeFromImpl(); Expression *interpret(InterState *istate); bool apply(sapply_fp_t fp, void *param); + void ctfeCompile(CompiledCtfeFunction *ccf); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); DefaultStatement *isDefaultStatement() { return this; } @@ -629,22 +681,25 @@ struct DefaultStatement : Statement #endif }; -struct GotoDefaultStatement : Statement +class GotoDefaultStatement : public Statement { +public: SwitchStatement *sw; GotoDefaultStatement(Loc loc); Statement *syntaxCopy(); Statement *semantic(Scope *sc); Expression *interpret(InterState *istate); + void ctfeCompile(CompiledCtfeFunction *ccf); int blockExit(bool mustNotThrow); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void toIR(IRState *irs); }; -struct GotoCaseStatement : Statement +class GotoCaseStatement : public Statement { +public: Expression *exp; // NULL, or which case to goto CaseStatement *cs; // case statement it resolves to SwitchStatement *sw; @@ -653,23 +708,27 @@ struct GotoCaseStatement : Statement Statement *syntaxCopy(); Statement *semantic(Scope *sc); Expression *interpret(InterState *istate); + void ctfeCompile(CompiledCtfeFunction *ccf); int blockExit(bool mustNotThrow); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void toIR(IRState *irs); }; -struct SwitchErrorStatement : Statement +class SwitchErrorStatement : public Statement { +public: SwitchErrorStatement(Loc loc); int blockExit(bool mustNotThrow); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void ctfeCompile(CompiledCtfeFunction *ccf); void toIR(IRState *irs); }; -struct ReturnStatement : Statement +class ReturnStatement : public Statement { +public: Expression *exp; bool implicit0; // this is an implicit "return 0;" @@ -679,6 +738,7 @@ struct ReturnStatement : Statement Statement *semantic(Scope *sc); int blockExit(bool mustNotThrow); Expression *interpret(InterState *istate); + void ctfeCompile(CompiledCtfeFunction *ccf); int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); @@ -690,14 +750,16 @@ struct ReturnStatement : Statement ReturnStatement *isReturnStatement() { return this; } }; -struct BreakStatement : Statement +class BreakStatement : public Statement { +public: Identifier *ident; BreakStatement(Loc loc, Identifier *ident); Statement *syntaxCopy(); Statement *semantic(Scope *sc); Expression *interpret(InterState *istate); + void ctfeCompile(CompiledCtfeFunction *ccf); int blockExit(bool mustNotThrow); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -709,14 +771,16 @@ struct BreakStatement : Statement #endif }; -struct ContinueStatement : Statement +class ContinueStatement : public Statement { +public: Identifier *ident; ContinueStatement(Loc loc, Identifier *ident); Statement *syntaxCopy(); Statement *semantic(Scope *sc); Expression *interpret(InterState *istate); + void ctfeCompile(CompiledCtfeFunction *ccf); int blockExit(bool mustNotThrow); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -728,8 +792,9 @@ struct ContinueStatement : Statement #endif }; -struct SynchronizedStatement : Statement +class SynchronizedStatement : public Statement { +public: Expression *exp; Statement *body; @@ -754,8 +819,9 @@ struct SynchronizedStatement : Statement #endif }; -struct WithStatement : Statement +class WithStatement : public Statement { +public: Expression *exp; Statement *body; VarDeclaration *wthis; @@ -767,14 +833,16 @@ struct WithStatement : Statement int blockExit(bool mustNotThrow); Expression *interpret(InterState *istate); bool apply(sapply_fp_t fp, void *param); + void ctfeCompile(CompiledCtfeFunction *ccf); Statement *inlineScan(InlineScanState *iss); void toIR(IRState *irs); }; -struct TryCatchStatement : Statement +class TryCatchStatement : public Statement { +public: Statement *body; Catches *catches; @@ -786,6 +854,7 @@ struct TryCatchStatement : Statement int blockExit(bool mustNotThrow); Expression *interpret(InterState *istate); bool apply(sapply_fp_t fp, void *param); + void ctfeCompile(CompiledCtfeFunction *ccf); Statement *inlineScan(InlineScanState *iss); @@ -793,8 +862,9 @@ struct TryCatchStatement : Statement void toCBuffer(OutBuffer *buf, HdrGenState *hgs); }; -struct Catch : Object +class Catch : public RootObject { +public: Loc loc; Type *type; Identifier *ident; @@ -810,8 +880,9 @@ struct Catch : Object void toCBuffer(OutBuffer *buf, HdrGenState *hgs); }; -struct TryFinallyStatement : Statement +class TryFinallyStatement : public Statement { +public: Statement *body; Statement *finalbody; @@ -825,14 +896,16 @@ struct TryFinallyStatement : Statement int blockExit(bool mustNotThrow); Expression *interpret(InterState *istate); bool apply(sapply_fp_t fp, void *param); + void ctfeCompile(CompiledCtfeFunction *ccf); Statement *inlineScan(InlineScanState *iss); void toIR(IRState *irs); }; -struct OnScopeStatement : Statement +class OnScopeStatement : public Statement { +public: TOK tok; Statement *statement; @@ -845,12 +918,14 @@ struct OnScopeStatement : Statement Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); Expression *interpret(InterState *istate); bool apply(sapply_fp_t fp, void *param); + void ctfeCompile(CompiledCtfeFunction *ccf); void toIR(IRState *irs); }; -struct ThrowStatement : Statement +class ThrowStatement : public Statement { +public: Expression *exp; bool internalThrow; // was generated by the compiler, // wasn't present in source code @@ -861,14 +936,16 @@ struct ThrowStatement : Statement void toCBuffer(OutBuffer *buf, HdrGenState *hgs); int blockExit(bool mustNotThrow); Expression *interpret(InterState *istate); + void ctfeCompile(CompiledCtfeFunction *ccf); Statement *inlineScan(InlineScanState *iss); void toIR(IRState *irs); }; -struct DebugStatement : Statement +class DebugStatement : public Statement { +public: Statement *statement; DebugStatement(Loc loc, Statement *statement); @@ -879,8 +956,9 @@ struct DebugStatement : Statement void toCBuffer(OutBuffer *buf, HdrGenState *hgs); }; -struct GotoStatement : Statement +class GotoStatement : public Statement { +public: Identifier *ident; LabelDsymbol *label; #if !IN_LLVM @@ -895,13 +973,15 @@ struct GotoStatement : Statement Statement *semantic(Scope *sc); int blockExit(bool mustNotThrow); Expression *interpret(InterState *istate); + void ctfeCompile(CompiledCtfeFunction *ccf); void toIR(IRState *irs); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); }; -struct LabelStatement : Statement +class LabelStatement : public Statement { +public: Identifier *ident; Statement *statement; #if !IN_LLVM @@ -910,6 +990,7 @@ struct LabelStatement : Statement TryFinallyStatement *enclosingFinally; Statement* enclosingScopeExit; #endif + Statement *gotoTarget; // interpret block *lblock; // back end Blocks *fwdrefs; // forward references to this LabelStatement @@ -922,6 +1003,7 @@ struct LabelStatement : Statement bool comeFromImpl(); Expression *interpret(InterState *istate); bool apply(sapply_fp_t fp, void *param); + void ctfeCompile(CompiledCtfeFunction *ccf); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Statement *inlineScan(InlineScanState *iss); @@ -934,16 +1016,18 @@ struct LabelStatement : Statement #endif }; -struct LabelDsymbol : Dsymbol +class LabelDsymbol : public Dsymbol { +public: LabelStatement *statement; LabelDsymbol(Identifier *ident); LabelDsymbol *isLabel(); }; -struct AsmStatement : Statement +class AsmStatement : public Statement { +public: Token *tokens; code *asmcode; unsigned asmalign; // alignment of this statement @@ -957,6 +1041,7 @@ struct AsmStatement : Statement int blockExit(bool mustNotThrow); bool comeFromImpl(); Expression *interpret(InterState *istate); + void ctfeCompile(CompiledCtfeFunction *ccf); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -974,8 +1059,9 @@ struct AsmStatement : Statement #endif }; -struct ImportStatement : Statement +class ImportStatement : public Statement { +public: Dsymbols *imports; // Array of Import's ImportStatement(Loc loc, Dsymbols *imports); @@ -984,6 +1070,7 @@ struct ImportStatement : Statement int blockExit(bool mustNotThrow); bool hasCodeImpl(); Expression *interpret(InterState *istate); + void ctfeCompile(CompiledCtfeFunction *ccf); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -995,8 +1082,9 @@ struct ImportStatement : Statement }; #if IN_LLVM -struct AsmBlockStatement : CompoundStatement +class AsmBlockStatement : public CompoundStatement { +public: TryFinallyStatement* enclosingFinally; Statement* enclosingScopeExit; diff --git a/dmd2/staticassert.c b/dmd2/staticassert.c index 94fc83a0..308ab783 100644 --- a/dmd2/staticassert.c +++ b/dmd2/staticassert.c @@ -55,9 +55,16 @@ void StaticAssert::semantic2(Scope *sc) ScopeDsymbol *sd = new ScopeDsymbol(); sc = sc->push(sd); sc->flags |= SCOPEstaticassert; - Expression *e = exp->ctfeSemantic(sc); + + sc = sc->startCTFE(); + Expression *e = exp->semantic(sc); e = resolveProperties(sc, e); + sc = sc->endCTFE(); sc = sc->pop(); + + // Simplify expression, to make error messages nicer if CTFE fails + e = e->optimize(0); + if (!e->type->checkBoolean()) { if (e->type->toBasetype() != Type::terror) @@ -73,11 +80,14 @@ void StaticAssert::semantic2(Scope *sc) else if (e->isBool(FALSE)) { if (msg) - { HdrGenState hgs; + { + HdrGenState hgs; OutBuffer buf; - msg = msg->ctfeSemantic(sc); + sc = sc->startCTFE(); + msg = msg->semantic(sc); msg = resolveProperties(sc, msg); + sc = sc->endCTFE(); msg = msg->ctfeInterpret(); hgs.console = 1; StringExp * s = msg->toString(); @@ -101,11 +111,11 @@ void StaticAssert::semantic2(Scope *sc) } } -int StaticAssert::oneMember(Dsymbol **ps, Identifier *ident) +bool StaticAssert::oneMember(Dsymbol **ps, Identifier *ident) { //printf("StaticAssert::oneMember())\n"); *ps = NULL; - return TRUE; + return true; } void StaticAssert::inlineScan() diff --git a/dmd2/staticassert.h b/dmd2/staticassert.h index 8d64416c..8125fab6 100644 --- a/dmd2/staticassert.h +++ b/dmd2/staticassert.h @@ -17,11 +17,12 @@ #include "dsymbol.h" -struct Expression; +class Expression; struct HdrGenState; -struct StaticAssert : Dsymbol +class StaticAssert : public Dsymbol { +public: Expression *exp; Expression *msg; @@ -32,7 +33,7 @@ struct StaticAssert : Dsymbol void semantic(Scope *sc); void semantic2(Scope *sc); void inlineScan(); - int oneMember(Dsymbol **ps, Identifier *ident); + bool oneMember(Dsymbol **ps, Identifier *ident); void toObjFile(int multiobj); const char *kind(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); diff --git a/dmd2/struct.c b/dmd2/struct.c index 39fe40bb..09c27907 100644 --- a/dmd2/struct.c +++ b/dmd2/struct.c @@ -22,6 +22,75 @@ #include "template.h" FuncDeclaration *StructDeclaration::xerreq; // object.xopEquals +FuncDeclaration *StructDeclaration::xerrcmp; // object.xopCmp + +bool inNonRoot(Dsymbol *s) +{ + if (!s || !s->parent) + return false; + s = s->parent; + for (; s; s = s->parent) + { + if (TemplateInstance *ti = s->isTemplateInstance()) + { + if (!ti->instantiatingModule || !ti->instantiatingModule->isRoot()) + return true; + return false; + } + else if (Module *m = s->isModule()) + { + if (!m->isRoot()) + return true; + break; + } + } + return false; +} + +/*************************************** + * Search toHash member function for TypeInfo_Struct. + * const hash_t toHash(); + */ +FuncDeclaration *search_toHash(StructDeclaration *sd) +{ + Dsymbol *s = search_function(sd, Id::tohash); + FuncDeclaration *fd = s ? s->isFuncDeclaration() : NULL; + if (fd) + { + static TypeFunction *tftohash; + if (!tftohash) + { + tftohash = new TypeFunction(NULL, Type::thash_t, 0, LINKd); + tftohash->mod = MODconst; + tftohash = (TypeFunction *)tftohash->merge(); + } + + fd = fd->overloadExactMatch(tftohash); + } + return fd; +} + +/*************************************** + * Search toString member function for TypeInfo_Struct. + * string toString(); + */ +FuncDeclaration *search_toString(StructDeclaration *sd) +{ + Dsymbol *s = search_function(sd, Id::tostring); + FuncDeclaration *fd = s ? s->isFuncDeclaration() : NULL; + if (fd) + { + static TypeFunction *tftostring; + if (!tftostring) + { + tftostring = new TypeFunction(NULL, Type::tstring, 0, LINKd); + tftostring = (TypeFunction *)tftostring->merge(); + } + + fd = fd->overloadExactMatch(tftostring); + } + return fd; +} /********************************* AggregateDeclaration ****************************/ @@ -66,7 +135,7 @@ AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id) #endif } -enum PROT AggregateDeclaration::prot() +PROT AggregateDeclaration::prot() { return protection; } @@ -109,6 +178,10 @@ void AggregateDeclaration::semantic3(Scope *sc) //printf("AggregateDeclaration::semantic3(%s)\n", toChars()); if (members) { + StructDeclaration *sd = isStructDeclaration(); + if (!sc) // from runDeferredSemantic3 for TypeInfo generation + goto Lxop; + sc = sc->push(this); sc->parent = this; for (size_t i = 0; i < members->dim; i++) @@ -116,20 +189,13 @@ void AggregateDeclaration::semantic3(Scope *sc) Dsymbol *s = (*members)[i]; s->semantic3(sc); } - - if (StructDeclaration *sd = isStructDeclaration()) - { - //if (sd->xeq != NULL) printf("sd = %s xeq @ [%s]\n", sd->toChars(), sd->loc.toChars()); - //assert(sd->xeq == NULL); - if (sd->xeq == NULL) - sd->xeq = sd->buildXopEquals(sc); - } sc = sc->pop(); if (!getRTInfo && Type::rtinfo && (!isDeprecated() || global.params.useDeprecated) && // don't do it for unused deprecated types (type && type->ty != Terror)) // or error types - { // Evaluate: gcinfo!type + { + // Evaluate: RTinfo!type Objects *tiargs = new Objects(); tiargs->push(type); TemplateInstance *ti = new TemplateInstance(loc, Type::rtinfo, tiargs); @@ -138,10 +204,55 @@ void AggregateDeclaration::semantic3(Scope *sc) ti->semantic3(sc); Dsymbol *s = ti->toAlias(); Expression *e = new DsymbolExp(Loc(), s, 0); - e = e->ctfeSemantic(ti->tempdecl->scope); + + Scope *sc2 = ti->tempdecl->scope->startCTFE(); + sc2->instantiatingModule = sc->instantiatingModule ? sc->instantiatingModule : sc->module; + e = e->semantic(sc2); + sc2->endCTFE(); + e = e->ctfeInterpret(); getRTInfo = e; } + + if (sd) + { + Lxop: + if (sd->xeq && + sd->xeq->scope && + sd->xeq->semanticRun < PASSsemantic3done) + { + unsigned errors = global.startGagging(); + sd->xeq->semantic3(sd->xeq->scope); + if (global.endGagging(errors)) + sd->xeq = sd->xerreq; + } + + if (sd->xcmp && + sd->xcmp->scope && + sd->xcmp->semanticRun < PASSsemantic3done) + { + unsigned errors = global.startGagging(); + sd->xcmp->semantic3(sd->xcmp->scope); + if (global.endGagging(errors)) + sd->xcmp = sd->xerrcmp; + } + + FuncDeclaration *ftostr = search_toString(sd); + if (ftostr && + ftostr->scope && + ftostr->semanticRun < PASSsemantic3done) + { + ftostr->semantic3(ftostr->scope); + } + + FuncDeclaration *ftohash = search_toHash(sd); + if (ftohash && + ftohash->scope && + ftohash->semanticRun < PASSsemantic3done) + { + ftohash->semantic3(ftohash->scope); + } + } } } @@ -164,8 +275,6 @@ unsigned AggregateDeclaration::size(Loc loc) //printf("AggregateDeclaration::size() %s, scope = %p\n", toChars(), scope); if (loc.linnum == 0) loc = this->loc; - if (!members) - error(loc, "unknown size"); if (sizeok != SIZEOKdone && scope) semantic(NULL); @@ -209,8 +318,13 @@ unsigned AggregateDeclaration::size(Loc loc) L1: ; } - if (sizeok != SIZEOKdone) - { error(loc, "no size yet for forward reference"); + if (!members) + { + error(loc, "unknown size"); + } + else if (sizeok != SIZEOKdone) + { + error(loc, "no size yet for forward reference"); //*(char*)0=0; } return structsize; @@ -226,7 +340,7 @@ bool AggregateDeclaration::isDeprecated() return isdeprecated; } -int AggregateDeclaration::isExport() +bool AggregateDeclaration::isExport() { return protection == PROTexport; } @@ -244,11 +358,11 @@ void AggregateDeclaration::alignmember( //printf("alignment = %d, size = %d, offset = %d\n",alignment,size,offset); switch (alignment) { - case 1: + case (structalign_t) 1: // No alignment break; - case STRUCTALIGN_DEFAULT: + case (structalign_t) STRUCTALIGN_DEFAULT: { /* Must match what the corresponding C compiler's default * alignment behavior is. */ @@ -427,6 +541,25 @@ int AggregateDeclaration::numFieldsInUnion(int firstIndex) return count; } +/******************************************* + * Look for constructor declaration. + */ +void AggregateDeclaration::searchCtor() +{ + ctor = search(Loc(), Id::ctor, 0); + if (ctor) + { + if (!(ctor->isCtorDeclaration() || + ctor->isTemplateDeclaration() || + ctor->isOverloadSet())) + { + error("%s %s is not a constructor; identifiers starting with __ are reserved for the implementation", ctor->kind(), ctor->toChars()); + errors = true; + ctor = NULL; + } + } +} + /********************************* StructDeclaration ****************************/ StructDeclaration::StructDeclaration(Loc loc, Identifier *id) @@ -440,6 +573,7 @@ StructDeclaration::StructDeclaration(Loc loc, Identifier *id) postblit = NULL; xeq = NULL; + xcmp = NULL; alignment = 0; #endif arg1type = NULL; @@ -500,14 +634,13 @@ void StructDeclaration::semantic(Scope *sc) Scope *scx = NULL; if (scope) - { sc = scope; + { + sc = scope; scx = scope; // save so we don't make redundant copies scope = NULL; } - - int errors = global.errors; - unsigned dprogress_save = Module::dprogress; + int errors = global.errors; parent = sc->parent; type = type->semantic(loc, sc); @@ -547,15 +680,10 @@ void StructDeclaration::semantic(Scope *sc) * resolve individual members like enums. */ for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (*members)[i]; - /* There are problems doing this in the general case because - * Scope keeps track of things like 'offset' - */ - //if (s->isEnumDeclaration() || (s->isAggregateDeclaration() && s->ident)) - { - //printf("struct: setScope %s %s\n", s->kind(), s->toChars()); - s->setScope(sc2); - } + { + Dsymbol *s = (*members)[i]; + //printf("struct: setScope %s %s\n", s->kind(), s->toChars()); + s->setScope(sc2); } for (size_t i = 0; i < members->dim; i++) @@ -572,14 +700,10 @@ void StructDeclaration::semantic(Scope *sc) if (sizeok == SIZEOKnone && s->isAliasDeclaration()) finalizeSize(sc2); } + // Ungag errors when not speculative - unsigned oldgag = global.gag; - if (global.isSpeculativeGagging() && !isSpeculative()) - { - global.gag = 0; - } + Ungag ungag = ungagSpeculative(); s->semantic(sc2); - global.gag = oldgag; } finalizeSize(sc2); @@ -704,6 +828,19 @@ void StructDeclaration::semantic(Scope *sc) buildOpAssign(sc2); buildOpEquals(sc2); + + xeq = buildXopEquals(sc2); + xcmp = buildXopCmp(sc2); + + /* Even if the struct is merely imported and its semantic3 is not run, + * the TypeInfo object would be speculatively stored in each object + * files. To set correct function pointer, run semantic3 for xeq and xcmp. + */ + //if ((xeq && xeq != xerreq || xcmp && xcmp != xerrcmp) && isImportedSym(this)) + // Module::addDeferredSemantic3(this); + /* Defer requesting semantic3 until TypeInfo generation is actually invoked. + * See Type::getTypeInfo(). + */ #endif inv = buildInv(sc2); @@ -711,9 +848,7 @@ void StructDeclaration::semantic(Scope *sc) /* Look for special member functions. */ -#if DMDV2 - ctor = search(Loc(), Id::ctor, 0); -#endif + searchCtor(); aggNew = (NewDeclaration *)search(Loc(), Id::classNew, 0); aggDelete = (DeleteDeclaration *)search(Loc(), Id::classDelete, 0); @@ -735,6 +870,7 @@ void StructDeclaration::semantic(Scope *sc) if (global.errors != errors) { // The type is no good. type = Type::terror; + this->errors = true; } if (deferred && !global.gag) @@ -743,14 +879,12 @@ void StructDeclaration::semantic(Scope *sc) deferred->semantic3(sc); } -#if 0 if (type->ty == Tstruct && ((TypeStruct *)type)->sym != this) { - printf("this = %p %s\n", this, this->toChars()); - printf("type = %d sym = %p\n", type->ty, ((TypeStruct *)type)->sym); + error("failed semantic analysis"); + this->errors = true; + type = Type::terror; } -#endif - assert(type->ty != Tstruct || ((TypeStruct *)type)->sym == this); } Dsymbol *StructDeclaration::search(Loc loc, Identifier *ident, int flags) @@ -830,13 +964,10 @@ bool StructDeclaration::isPOD() assert(v && v->isField()); if (v->storage_class & STCref) continue; - Type *tv = v->type->toBasetype(); - while (tv->ty == Tsarray) - { TypeSArray *ta = (TypeSArray *)tv; - tv = tv->nextOf()->toBasetype(); - } + Type *tv = v->type->baseElemOf(); if (tv->ty == Tstruct) - { TypeStruct *ts = (TypeStruct *)tv; + { + TypeStruct *ts = (TypeStruct *)tv; StructDeclaration *sd = ts->sym; if (!sd->isPOD()) return false; diff --git a/dmd2/target.h b/dmd2/target.h index 4ec6f3d3..724eb137 100644 --- a/dmd2/target.h +++ b/dmd2/target.h @@ -14,7 +14,7 @@ // At present it is incomplete, but in future it should grow to contain // most or all target machine and target O/S specific information. -struct Type; +class Type; struct Target { @@ -26,6 +26,7 @@ struct Target static void init(); static unsigned alignsize(Type* type); static unsigned fieldalign(Type* type); + static unsigned critsecsize(); }; #endif diff --git a/dmd2/template.c b/dmd2/template.c index 5afb6d50..25dfdc63 100644 --- a/dmd2/template.c +++ b/dmd2/template.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars +// Copyright (c) 1999-2013 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -44,13 +44,16 @@ long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep); #define IDX_NOTFOUND (0x12345678) // index is not found size_t templateParameterLookup(Type *tparam, TemplateParameters *parameters); +int arrayObjectMatch(Objects *oa1, Objects *oa2); +hash_t arrayObjectHash(Objects *oa1); +int arrayCheckRecursiveExpansion(Objects *oa1, TemplateDeclaration *tempdecl, Scope *sc); /******************************************** * These functions substitute for dynamic_cast. dynamic_cast does not work * on earlier versions of gcc. */ -Expression *isExpression(Object *o) +Expression *isExpression(RootObject *o) { //return dynamic_cast(o); if (!o || o->dyncast() != DYNCAST_EXPRESSION) @@ -58,7 +61,7 @@ Expression *isExpression(Object *o) return (Expression *)o; } -Dsymbol *isDsymbol(Object *o) +Dsymbol *isDsymbol(RootObject *o) { //return dynamic_cast(o); if (!o || o->dyncast() != DYNCAST_DSYMBOL) @@ -66,7 +69,7 @@ Dsymbol *isDsymbol(Object *o) return (Dsymbol *)o; } -Type *isType(Object *o) +Type *isType(RootObject *o) { //return dynamic_cast(o); if (!o || o->dyncast() != DYNCAST_TYPE) @@ -74,7 +77,7 @@ Type *isType(Object *o) return (Type *)o; } -Tuple *isTuple(Object *o) +Tuple *isTuple(RootObject *o) { //return dynamic_cast(o); if (!o || o->dyncast() != DYNCAST_TUPLE) @@ -82,7 +85,7 @@ Tuple *isTuple(Object *o) return (Tuple *)o; } -Parameter *isParameter(Object *o) +Parameter *isParameter(RootObject *o) { //return dynamic_cast(o); if (!o || o->dyncast() != DYNCAST_PARAMETER) @@ -93,7 +96,7 @@ Parameter *isParameter(Object *o) /************************************** * Is this Object an error? */ -int isError(Object *o) +int isError(RootObject *o) { Type *t = isType(o); if (t) @@ -117,7 +120,7 @@ int arrayObjectIsError(Objects *args) { for (size_t i = 0; i < args->dim; i++) { - Object *o = (*args)[i]; + RootObject *o = (*args)[i]; if (isError(o)) return 1; } @@ -128,7 +131,7 @@ int arrayObjectIsError(Objects *args) * Try to get arg as a type. */ -Type *getType(Object *o) +Type *getType(RootObject *o) { Type *t = isType(o); if (!t) @@ -139,7 +142,7 @@ Type *getType(Object *o) return t; } -Dsymbol *getDsymbol(Object *oarg) +Dsymbol *getDsymbol(RootObject *oarg) { //printf("getDsymbol()\n"); //printf("e %p s %p t %p v %p\n", isExpression(oarg), isDsymbol(oarg), isType(oarg), isTuple(oarg)); @@ -206,7 +209,7 @@ Expression *getValue(Dsymbol *&s) * Else, return 0. */ -int match(Object *o1, Object *o2, TemplateDeclaration *tempdecl, Scope *sc) +int match(RootObject *o1, RootObject *o2) { Type *t1 = isType(o1); Type *t2 = isType(o2); @@ -230,25 +233,6 @@ int match(Object *o1, Object *o2, TemplateDeclaration *tempdecl, Scope *sc) if (t1) { - /* if t1 is an instance of ti, then give error - * about recursive expansions. - */ - Dsymbol *s = t1->toDsymbol(sc); - if (s && s->parent) - { TemplateInstance *ti1 = s->parent->isTemplateInstance(); - if (ti1 && ti1->tempdecl == tempdecl) - { - for (Scope *sc1 = sc; sc1; sc1 = sc1->enclosing) - { - if (sc1->scopesym == ti1) - { - tempdecl->error("recursive template expansion for template argument %s", t1->toChars()); - return 1; // fake a match - } - } - } - } - //printf("t1 = %s\n", t1->toChars()); //printf("t2 = %s\n", t2->toChars()); if (!t2 || !t1->equals(t2)) @@ -271,22 +255,26 @@ int match(Object *o1, Object *o2, TemplateDeclaration *tempdecl, Scope *sc) } else if (s1) { - if (!s2 || !s1->equals(s2) || s1->parent != s2->parent) + if (s2) + { + if (!s1->equals(s2)) + goto Lnomatch; + if (s1->parent != s2->parent && + !s1->isFuncDeclaration() && + !s2->isFuncDeclaration()) + { + goto Lnomatch; + } + } + else goto Lnomatch; } else if (u1) { if (!u2) goto Lnomatch; - if (u1->objects.dim != u2->objects.dim) + if (!arrayObjectMatch(&u1->objects, &u2->objects)) goto Lnomatch; - for (size_t i = 0; i < u1->objects.dim; i++) - { - if (!match(u1->objects[i], - u2->objects[i], - tempdecl, sc)) - goto Lnomatch; - } } //printf("match\n"); return 1; // match @@ -300,16 +288,16 @@ Lnomatch: /************************************ * Match an array of them. */ -int arrayObjectMatch(Objects *oa1, Objects *oa2, TemplateDeclaration *tempdecl, Scope *sc) +int arrayObjectMatch(Objects *oa1, Objects *oa2) { if (oa1 == oa2) return 1; if (oa1->dim != oa2->dim) return 0; for (size_t j = 0; j < oa1->dim; j++) - { Object *o1 = (*oa1)[j]; - Object *o2 = (*oa2)[j]; - if (!match(o1, o2, tempdecl, sc)) + { RootObject *o1 = (*oa1)[j]; + RootObject *o2 = (*oa2)[j]; + if (!match(o1, o2)) { return 0; } @@ -317,12 +305,105 @@ int arrayObjectMatch(Objects *oa1, Objects *oa2, TemplateDeclaration *tempdecl, return 1; } + +/************************************ + * Return hash of Objects. + */ +hash_t arrayObjectHash(Objects *oa1) +{ + hash_t hash = 0; + for (size_t j = 0; j < oa1->dim; j++) + { /* Must follow the logic of match() + */ + RootObject *o1 = (*oa1)[j]; + if (Type *t1 = isType(o1)) + hash += (size_t)t1->deco; + else + { + Dsymbol *s1 = isDsymbol(o1); + Expression *e1 = s1 ? getValue(s1) : getValue(isExpression(o1)); + if (e1) + { + if (e1->op == TOKint64) + { + IntegerExp *ne = (IntegerExp *)e1; + hash += (size_t)ne->value; + } + } + else if (s1) + { + FuncAliasDeclaration *fa1 = s1->isFuncAliasDeclaration(); + if (fa1) + s1 = fa1->toAliasFunc(); + hash += (size_t)(void *)s1->getIdent() + (size_t)(void *)s1->parent; + } + else if (Tuple *u1 = isTuple(o1)) + hash += arrayObjectHash(&u1->objects); + } + } + return hash; +} + + +/****************************** + * Check template argument o1 to see if it is a recursive expansion of tempdecl in scope sc. + * If so, issue error and return 1. + */ + +int checkRecursiveExpansion(RootObject *o1, TemplateDeclaration *tempdecl, Scope *sc) +{ + if (Type *t1 = isType(o1)) + { + /* if t1 is an instance of ti, then give error + * about recursive expansions. + */ + Dsymbol *s = t1->toDsymbol(sc); + if (s && s->parent) + { + TemplateInstance *ti1 = s->parent->isTemplateInstance(); + if (ti1 && ti1->tempdecl == tempdecl) + { + for (Scope *sc1 = sc; sc1; sc1 = sc1->enclosing) + { + if (sc1->scopesym == ti1) + { + tempdecl->error("recursive template expansion for template argument %s", t1->toChars()); + return 1; + } + } + } + } + } + else if (Tuple *u1 = isTuple(o1)) + { + return arrayCheckRecursiveExpansion(&u1->objects, tempdecl, sc); + } + return 0; // no error +} + + +/************************************ + * Match an array of them. + */ +int arrayCheckRecursiveExpansion(Objects *oa1, TemplateDeclaration *tempdecl, Scope *sc) +{ + for (size_t j = 0; j < oa1->dim; j++) + { + RootObject *o1 = (*oa1)[j]; + if (checkRecursiveExpansion(o1, tempdecl, sc)) + return 1; + } + return 0; +} + + + /**************************************** * This makes a 'pretty' version of the template arguments. * It's analogous to genIdent() which makes a mangled version. */ -void ObjectToCBuffer(OutBuffer *buf, HdrGenState *hgs, Object *oarg) +void ObjectToCBuffer(OutBuffer *buf, HdrGenState *hgs, RootObject *oarg) { //printf("ObjectToCBuffer()\n"); Type *t = isType(oarg); @@ -356,7 +437,7 @@ void ObjectToCBuffer(OutBuffer *buf, HdrGenState *hgs, Object *oarg) { if (i) buf->writestring(", "); - Object *o = (*args)[i]; + RootObject *o = (*args)[i]; ObjectToCBuffer(buf, hgs, o); } } @@ -374,7 +455,7 @@ void ObjectToCBuffer(OutBuffer *buf, HdrGenState *hgs, Object *oarg) } #if DMDV2 -Object *objectSyntaxCopy(Object *o) +RootObject *objectSyntaxCopy(RootObject *o) { if (!o) return NULL; @@ -418,15 +499,17 @@ TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id, this->members = decldefs; this->overnext = NULL; this->overroot = NULL; - this->semanticRun = PASSinit; + this->funcroot = NULL; this->onemember = NULL; this->literal = 0; this->ismixin = ismixin; this->previous = NULL; this->protection = PROTundefined; + this->numinstances = 0; // Compute in advance for Ddoc's use - if (members) + // Bugzilla 11153: ident could be NULL if parsing fails. + if (members && ident) { Dsymbol *s; if (Dsymbol::oneMembers(members, &s, ident) && s) @@ -472,7 +555,7 @@ void TemplateDeclaration::semantic(Scope *sc) printf("sc->stc = %llx\n", sc->stc); printf("sc->module = %s\n", sc->module->toChars()); #endif - if (semanticRun) + if (semanticRun != PASSinit) return; // semantic() already run semanticRun = PASSsemantic; @@ -530,7 +613,6 @@ void TemplateDeclaration::semantic(Scope *sc) ScopeDsymbol *paramsym = new ScopeDsymbol(); paramsym->parent = sc->parent; Scope *paramscope = sc->push(paramsym); - paramscope->parameterSpecialization = 1; paramscope->stc = 0; if (!parent) @@ -560,7 +642,7 @@ void TemplateDeclaration::semantic(Scope *sc) { TemplateParameter *tp = (*parameters)[i]; - tp->semantic(paramscope); + tp->semantic(paramscope, parameters); if (i + 1 != parameters->dim && tp->isTemplateTupleParameter()) { error("template tuple parameter must be last one"); errors = true; @@ -595,17 +677,26 @@ const char *TemplateDeclaration::kind() /********************************** * Overload existing TemplateDeclaration 'this' with the new one 's'. - * Return !=0 if successful; i.e. no conflict. + * Return true if successful; i.e. no conflict. */ -int TemplateDeclaration::overloadInsert(Dsymbol *s) +bool TemplateDeclaration::overloadInsert(Dsymbol *s) { #if LOG printf("TemplateDeclaration::overloadInsert('%s')\n", s->toChars()); #endif + FuncDeclaration *fd = s->isFuncDeclaration(); + if (fd) + { + if (funcroot) + return funcroot->overloadInsert(fd); + funcroot = fd; + return funcroot->overloadInsert(this); + } + TemplateDeclaration *td = s->isTemplateDeclaration(); if (!td) - return FALSE; + return false; TemplateDeclaration *pthis = this; TemplateDeclaration **ptd; @@ -631,7 +722,7 @@ int TemplateDeclaration::overloadInsert(Dsymbol *s) #if LOG printf("\tfalse: conflict\n"); #endif - return FALSE; + return false; Lcontinue: ; @@ -643,7 +734,7 @@ int TemplateDeclaration::overloadInsert(Dsymbol *s) #if LOG printf("\ttrue: no conflict\n"); #endif - return TRUE; + return true; } /**************************** @@ -715,7 +806,7 @@ void TemplateDeclaration::makeParamNamesVisibleInConstraint(Scope *paramscope, E * Return match level. */ -MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, +MATCH TemplateDeclaration::matchWithInstance(Scope *sc, TemplateInstance *ti, Objects *dedtypes, Expressions *fargs, int flag) { MATCH m; size_t dedtypes_dim = dedtypes->dim; @@ -757,12 +848,16 @@ MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, ScopeDsymbol *paramsym = new ScopeDsymbol(); paramsym->parent = scope->parent; Scope *paramscope = scope->push(paramsym); + Module *mi = ti->instantiatingModule ? ti->instantiatingModule : sc->instantiatingModule; + paramscope->instantiatingModule = mi; + paramscope->callsc = sc; paramscope->stc = 0; // Attempt type deduction m = MATCHexact; for (size_t i = 0; i < dedtypes_dim; i++) - { MATCH m2; + { + MATCH m2; TemplateParameter *tp = (*parameters)[i]; Declaration *sparam; @@ -774,7 +869,7 @@ MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, printf("\tparameter[%d] is %s : %s\n", i, tp->ident->toChars(), ttp->specType ? ttp->specType->toChars() : ""); #endif - m2 = tp->matchArg(paramscope, ti->tiargs, i, parameters, dedtypes, &sparam); + m2 = tp->matchArg(ti->loc, paramscope, ti->tiargs, i, parameters, dedtypes, &sparam); //printf("\tm2 = %d\n", m2); if (m2 == MATCHnomatch) @@ -790,8 +885,9 @@ MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, if (!flag) sparam->semantic(paramscope); - if (!paramscope->insert(sparam)) - goto Lnomatch; + if (!paramscope->insert(sparam)) // TODO: This check can make more early + goto Lnomatch; // in TemplateDeclaration::semantic, and + // then we don't need to make sparam if flags == 0 } if (!flag) @@ -810,11 +906,11 @@ MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, #if DMDV2 if (m && constraint && !flag) - { /* Check to see if constraint is satisfied. + { + /* Check to see if constraint is satisfied. */ makeParamNamesVisibleInConstraint(paramscope, fargs); Expression *e = constraint->syntaxCopy(); - Scope *sc = paramscope->push(); /* There's a chicken-and-egg problem here. We don't know yet if this template * instantiation will be a local one (enclosing is set), and we won't know until @@ -822,7 +918,36 @@ MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, * is not on the sc scope chain, and this can cause errors in FuncDeclaration::getLevel(). * Workaround the problem by setting a flag to relax the checking on frame errors. */ - sc->flags |= SCOPEstaticif; + + int nmatches = 0; + for (Previous *p = previous; p; p = p->prev) + { + if (arrayCheckRecursiveExpansion(p->dedargs, this, sc)) + goto Lnomatch; + + if (arrayObjectMatch(p->dedargs, dedtypes)) + { + //printf("recursive, no match p->sc=%p %p %s\n", p->sc, this, this->toChars()); + /* It must be a subscope of p->sc, other scope chains are not recursive + * instantiations. + */ + for (Scope *scx = sc; scx; scx = scx->enclosing) + { + if (scx == p->sc) + goto Lnomatch; + } + } + /* BUG: should also check for ref param differences + */ + } + + Previous pr; + pr.prev = previous; + pr.sc = paramscope; + pr.dedargs = dedtypes; + previous = ≺ // add this to threaded list + + int nerrors = global.errors; FuncDeclaration *fd = onemember && onemember->toAlias() ? onemember->toAlias()->isFuncDeclaration() : NULL; @@ -837,15 +962,22 @@ MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, fd->vthis = fd->declareThis(paramscope, ad); } - e = e->ctfeSemantic(sc); - e = resolveProperties(sc, e); - if (e->op == TOKerror) - goto Lnomatch; + Scope *scx = paramscope->startCTFE(); + scx->flags |= SCOPEstaticif; + e = e->semantic(scx); + e = resolveProperties(scx, e); + scx = scx->endCTFE(); if (fd && fd->vthis) fd->vthis = vthissave; - sc->pop(); + previous = pr.prev; // unlink from threaded list + + if (nerrors != global.errors) // if any errors from evaluating the constraint, no match + goto Lnomatch; + if (e->op == TOKerror) + goto Lnomatch; + e = e->ctfeInterpret(); if (e->isBool(TRUE)) ; @@ -868,7 +1000,7 @@ MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, for (size_t i = 0; i < dedtypes_dim; i++) { TemplateParameter *tp = (*parameters)[i]; - Object *oarg; + RootObject *oarg; printf(" [%d]", i); @@ -909,7 +1041,7 @@ Lret: * 0 td2 is more specialized than this */ -MATCH TemplateDeclaration::leastAsSpecialized(TemplateDeclaration *td2, Expressions *fargs) +MATCH TemplateDeclaration::leastAsSpecialized(Scope *sc, TemplateDeclaration *td2, Expressions *fargs) { /* This works by taking the template parameters to this template * declaration and feeding them to td2 as if it were a template @@ -935,7 +1067,7 @@ MATCH TemplateDeclaration::leastAsSpecialized(TemplateDeclaration *td2, Expressi { TemplateParameter *tp = (*parameters)[i]; - Object *p = (Object *)tp->dummyArg(); + RootObject *p = (RootObject *)tp->dummyArg(); if (p) (*ti.tiargs)[i] = p; else @@ -947,7 +1079,7 @@ MATCH TemplateDeclaration::leastAsSpecialized(TemplateDeclaration *td2, Expressi dedtypes.setDim(td2->parameters->dim); // Attempt a type deduction - MATCH m = td2->matchWithInstance(&ti, &dedtypes, fargs, 1); + MATCH m = td2->matchWithInstance(sc, &ti, &dedtypes, fargs, 1); if (m) { /* A non-variadic template is more specialized than a @@ -985,7 +1117,7 @@ MATCH TemplateDeclaration::leastAsSpecialized(TemplateDeclaration *td2, Expressi * bit 4-7 Match template parameters by initial template arguments */ -MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Loc loc, Scope *sc, Objects *tiargs, +MATCH TemplateDeclaration::deduceFunctionTemplateMatch(FuncDeclaration *f, Loc loc, Scope *sc, Objects *tiargs, Type *tthis, Expressions *fargs, Objects *dedargs) { @@ -996,7 +1128,7 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Loc loc, Scope *sc, Objec size_t tuple_dim = 0; MATCH match = MATCHexact; MATCH matchTiargs = MATCHexact; - FuncDeclaration *fd = onemember->toAlias()->isFuncDeclaration(); + FuncDeclaration *fd = f; Parameters *fparameters; // function parameter list int fvarargs; // function varargs Objects dedtypes; // for T:T*, the dedargs is the T*, dedtypes is the T @@ -1032,6 +1164,12 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Loc loc, Scope *sc, Objec ScopeDsymbol *paramsym = new ScopeDsymbol(); paramsym->parent = scope->parent; Scope *paramscope = scope->push(paramsym); + + paramscope->instantiatingModule = sc->instantiatingModule; + Module *mi = sc->instantiatingModule ? sc->instantiatingModule : sc->module; + if (!sc->instantiatingModule || sc->instantiatingModule->isRoot()) + paramscope->instantiatingModule = mi; + paramscope->callsc = sc; paramscope->stc = 0; @@ -1042,7 +1180,7 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Loc loc, Scope *sc, Objec for (size_t i = 0; i < dedargs->dim; i++) { printf("\tdedarg[%d] = ", i); - Object *oarg = (*dedargs)[i]; + RootObject *oarg = (*dedargs)[i]; if (oarg) printf("%s", oarg->toChars()); printf("\n"); } @@ -1088,7 +1226,7 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Loc loc, Scope *sc, Objec MATCH m; Declaration *sparam = NULL; - m = tp->matchArg(paramscope, dedargs, i, parameters, &dedtypes, &sparam); + m = tp->matchArg(loc, paramscope, dedargs, i, parameters, &dedtypes, &sparam); //printf("\tdeduceType m = %d\n", m); if (m == MATCHnomatch) goto Lnomatch; @@ -1099,7 +1237,7 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Loc loc, Scope *sc, Objec if (!paramscope->insert(sparam)) goto Lnomatch; } - if (n < parameters->dim) + if (n < parameters->dim && !tp_is_declared) { inferparams = new TemplateParameters(); inferparams->setDim(parameters->dim - n); @@ -1109,12 +1247,13 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Loc loc, Scope *sc, Objec } else inferparams = NULL; + //printf("tiargs matchTiargs = %d\n", matchTiargs); } #if 0 for (size_t i = 0; i < dedargs->dim; i++) { printf("\tdedarg[%d] = ", i); - Object *oarg = (*dedargs)[i]; + RootObject *oarg = (*dedargs)[i]; if (oarg) printf("%s", oarg->toChars()); printf("\n"); } @@ -1132,6 +1271,9 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Loc loc, Scope *sc, Objec */ if (tp) // if variadic { + // TemplateTupleParameter always makes most lesser matching. + matchTiargs = MATCHconvert; + if (nfparams == 0 && nfargs != 0) // if no function parameters { if (!tp_is_declared) @@ -1277,6 +1419,8 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Loc loc, Scope *sc, Objec } } + if (nfargs - argi < rem) + goto Lnomatch; tuple_dim = nfargs - argi - rem; t->objects.setDim(tuple_dim); for (size_t i = 0; i < tuple_dim; i++) @@ -1533,20 +1677,21 @@ Lretry: ((TypeIdentifier *)taai)->idents.dim == 0)) { if (farg->op == TOKstring) - { StringExp *se = (StringExp *)farg; - argtype = new TypeSArray(argtype->nextOf(), new IntegerExp(se->loc, se->len, Type::tindex)); - argtype = argtype->semantic(se->loc, NULL); + { + StringExp *se = (StringExp *)farg; + argtype = TypeSArray::makeType(se->loc, argtype->nextOf(), se->len); } else if (farg->op == TOKslice) - { SliceExp *se = (SliceExp *)farg; + { + SliceExp *se = (SliceExp *)farg; Type *tsa = se->toStaticArrayType(); if (tsa) argtype = tsa; } else if (farg->op == TOKarrayliteral) - { ArrayLiteralExp *ae = (ArrayLiteralExp *)farg; - argtype = new TypeSArray(argtype->nextOf(), new IntegerExp(ae->loc, ae->elements->dim, Type::tindex)); - argtype = argtype->semantic(ae->loc, NULL); + { + ArrayLiteralExp *ae = (ArrayLiteralExp *)farg; + argtype = TypeSArray::makeType(ae->loc, argtype->nextOf(), ae->elements->dim); } } @@ -1705,7 +1850,7 @@ Lretry: } else { // This code matches code in TypeInstance::deduceType() - TemplateParameter *tprm = parameters->tdata()[i]; + TemplateParameter *tprm = (*parameters)[i]; TemplateValueParameter *tvp = tprm->isTemplateValueParameter(); if (!tvp) goto Lnomatch; @@ -1799,8 +1944,8 @@ Lmatch: /* For T:T*, the dedargs is the T*, dedtypes is the T * But for function templates, we really need them to match */ - Object *oarg = (*dedargs)[i]; - Object *oded = dedtypes[i]; + RootObject *oarg = (*dedargs)[i]; + RootObject *oded = dedtypes[i]; //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded); //if (oarg) printf("oarg: %s\n", oarg->toChars()); //if (oded) printf("oded: %s\n", oded->toChars()); @@ -1808,21 +1953,25 @@ Lmatch: { if (oded) { - if (tparam->specialization()) + if (tparam->specialization() || !tparam->isTemplateTypeParameter()) { /* The specialization can work as long as afterwards * the oded == oarg */ - Declaration *sparam; (*dedargs)[i] = oded; - MATCH m2 = tparam->matchArg(paramscope, dedargs, i, parameters, &dedtypes, &sparam); + MATCH m2 = tparam->matchArg(loc, paramscope, dedargs, i, parameters, &dedtypes, NULL); //printf("m2 = %d\n", m2); if (!m2) goto Lnomatch; - if (m2 < match) - match = m2; // pick worst match + if (m2 < matchTiargs) + matchTiargs = m2; // pick worst match if (dedtypes[i] != oded) error("specialization not allowed for deduced parameter %s", tparam->ident->toChars()); } + else + { + if (MATCHconvert < matchTiargs) + matchTiargs = MATCHconvert; + } } else { oded = tparam->defaultArg(loc, paramscope); @@ -1832,7 +1981,7 @@ Lmatch: fptupindex == IDX_NOTFOUND && // tuple parameter was not in function parameter list and ntargs == dedargs->dim - 1) // we're one argument short (i.e. no tuple argument) { // make tuple argument an empty tuple - oded = (Object *)new Tuple(); + oded = (RootObject *)new Tuple(); } else goto Lnomatch; @@ -1845,12 +1994,12 @@ Lmatch: #if DMDV2 if (constraint) - { /* Check to see if constraint is satisfied. + { + /* Check to see if constraint is satisfied. * Most of this code appears twice; this is a good candidate for refactoring. */ makeParamNamesVisibleInConstraint(paramscope, fargs); Expression *e = constraint->syntaxCopy(); - paramscope->flags |= SCOPEstaticif; /* Detect recursive attempts to instantiate this template declaration, * Bugzilla 4072 @@ -1861,7 +2010,10 @@ Lmatch: int nmatches = 0; for (Previous *p = previous; p; p = p->prev) { - if (arrayObjectMatch(p->dedargs, dedargs, this, sc)) + if (arrayCheckRecursiveExpansion(p->dedargs, this, sc)) + goto Lnomatch; + + if (arrayObjectMatch(p->dedargs, dedargs)) { //printf("recursive, no match p->sc=%p %p %s\n", p->sc, this, this->toChars()); /* It must be a subscope of p->sc, other scope chains are not recursive @@ -1885,8 +2037,7 @@ Lmatch: int nerrors = global.errors; - FuncDeclaration *fd = onemember && onemember->toAlias() ? - onemember->toAlias()->isFuncDeclaration() : NULL; + FuncDeclaration *fd = f; Dsymbol *s = parent; while (s->isTemplateInstance() || s->isTemplateMixin()) s = s->parent; @@ -1898,8 +2049,11 @@ Lmatch: fd->vthis = fd->declareThis(paramscope, ad); } - e = e->ctfeSemantic(paramscope); - e = resolveProperties(sc, e); + Scope *scx = paramscope->startCTFE(); + scx->flags |= SCOPEstaticif; + e = e->semantic(scx); + e = resolveProperties(scx, e); + scx->endCTFE(); if (fd && fd->vthis) fd->vthis = vthissave; @@ -1944,7 +2098,7 @@ Lnomatch: * Declare template parameter tp with value o, and install it in the scope sc. */ -Object *TemplateDeclaration::declareParameter(Scope *sc, TemplateParameter *tp, Object *o) +RootObject *TemplateDeclaration::declareParameter(Scope *sc, TemplateParameter *tp, RootObject *o) { //printf("TemplateDeclaration::declareParameter('%s', o = %p)\n", tp->ident->toChars(), o); @@ -1956,27 +2110,19 @@ Object *TemplateDeclaration::declareParameter(Scope *sc, TemplateParameter *tp, Dsymbol *s; VarDeclaration *v = NULL; - // See if tp->ident already exists with a matching definition - Dsymbol *scopesym; - s = sc->search(loc, tp->ident, &scopesym); - if (s && scopesym == sc->scopesym) - { - TupleDeclaration *td = s->isTupleDeclaration(); - if (va && td) - { Tuple tup; - tup.objects = *td->objects; - if (match(va, &tup, this, sc)) - { - return o; - } - } - } if (ea && ea->op == TOKtype) targ = ea->type; else if (ea && ea->op == TOKimport) sa = ((ScopeExp *)ea)->sds; else if (ea && (ea->op == TOKthis || ea->op == TOKsuper)) sa = ((ThisExp *)ea)->var; + else if (ea && ea->op == TOKfunction) + { + if (((FuncExp *)ea)->td) + sa = ((FuncExp *)ea)->td; + else + sa = ((FuncExp *)ea)->fd; + } if (targ) { @@ -1988,14 +2134,6 @@ Object *TemplateDeclaration::declareParameter(Scope *sc, TemplateParameter *tp, //printf("Alias %s %s;\n", sa->ident->toChars(), tp->ident->toChars()); s = new AliasDeclaration(Loc(), tp->ident, sa); } - else if (ea && ea->op == TOKfunction) - { - if (((FuncExp *)ea)->td) - sa = ((FuncExp *)ea)->td; - else - sa = ((FuncExp *)ea)->fd; - s = new AliasDeclaration(Loc(), tp->ident, sa); - } else if (ea) { // tdtypes.data[i] always matches ea here @@ -2026,7 +2164,7 @@ Object *TemplateDeclaration::declareParameter(Scope *sc, TemplateParameter *tp, /* So the caller's o gets updated with the result of semantic() being run on o */ if (v) - return (Object *)v->init->toExpression(); + return (RootObject *)v->init->toExpression(); return o; } @@ -2052,42 +2190,33 @@ TemplateTupleParameter *TemplateDeclaration::isVariadic() * We can overload templates. */ -int TemplateDeclaration::isOverloadable() +bool TemplateDeclaration::isOverloadable() { - return 1; + return true; } /************************************************* * Given function arguments, figure out which template function - * to expand, and return that function. - * If no match, give error message and return NULL. + * to expand, and return matching result. * Input: + * m matching result + * dstart the root of overloaded function templates * loc instantiation location * sc instantiation scope * tiargs initial list of template arguments * tthis if !NULL, the 'this' pointer argument * fargs arguments to function - * flags 1: do not issue error message on no match, just return NULL */ -FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Loc loc, Scope *sc, - Objects *tiargs, Type *tthis, Expressions *fargs, int flags) +void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc, + Objects *tiargs, Type *tthis, Expressions *fargs) { - MATCH m_best = MATCHnomatch; - MATCH m_best2 = MATCHnomatch; - TemplateDeclaration *td_ambig = NULL; - TemplateDeclaration *td_best = NULL; - Objects *tdargs = new Objects(); - TemplateInstance *ti; - FuncDeclaration *fd_best; - Type *tthis_best = NULL; - #if 0 - printf("TemplateDeclaration::deduceFunctionTemplate() %s\n", toChars()); + printf("functionResolve() dstart = %s\n", dstart->toChars()); printf(" tiargs:\n"); if (tiargs) { for (size_t i = 0; i < tiargs->dim; i++) - { Object *arg = (*tiargs)[i]; + { RootObject *arg = (*tiargs)[i]; printf("\t%s\n", arg->toChars()); } } @@ -2097,17 +2226,163 @@ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Loc loc, Scope *sc, printf("\t%s %s\n", arg->type->toChars(), arg->toChars()); //printf("\tty = %d\n", arg->type->ty); } - printf("stc = %llx\n", scope->stc); + //printf("stc = %llx\n", dstart->scope->stc); + //printf("match:t/f = %d/%d\n", ta_last, m->last); #endif - for (TemplateDeclaration *td = this; td; td = td->overnext) + struct ParamDeduce + { + // context + Loc loc; + Scope *sc; + Type *tthis; + Objects *tiargs; + Expressions *fargs; + // result + Match *m; + int property; // 0: unintialized + // 1: seen @property + // 2: not @property + size_t ov_index; + TemplateDeclaration *td_best; + MATCH ta_last; + Objects *tdargs; + Type *tthis_best; + + static int fp(void *param, Dsymbol *s) { - if (!td->semanticRun) + if (FuncDeclaration *fd = s->isFuncDeclaration()) + return ((ParamDeduce *)param)->fp(fd); + if (TemplateDeclaration *td = s->isTemplateDeclaration()) + return ((ParamDeduce *)param)->fp(td); + return 0; + } + int fp(FuncDeclaration *fd) + { + // skip duplicates + if (fd == m->lastf) + return 0; + // explicitly specified tiargs never match to non template function + if (tiargs && tiargs->dim > 0) + return 0; + + //printf("fd = %s %s\n", fd->toChars(), fd->type->toChars()); + m->anyf = fd; + TypeFunction *tf = (TypeFunction *)fd->type; + + int prop = (tf->isproperty) ? 1 : 2; + if (property == 0) + property = prop; + else if (property != prop) + error(fd->loc, "cannot overload both property and non-property functions"); + + /* For constructors, qualifier check will be opposite direction. + * Qualified constructor always makes qualified object, then will be checked + * that it is implicitly convertible to tthis. + */ + Type *tthis_fd = fd->needThis() ? tthis : NULL; + if (tthis_fd && fd->isCtorDeclaration()) { - error("forward reference to template %s", td->toChars()); + //printf("%s tf->mod = x%x tthis_fd->mod = x%x %d\n", tf->toChars(), + // tf->mod, tthis_fd->mod, fd->isolateReturn()); + if (MODimplicitConv(tf->mod, tthis_fd->mod) || + tf->isWild() && tf->isShared() == tthis_fd->isShared() || + fd->isolateReturn()/* && tf->isShared() == tthis_fd->isShared()*/) + { // Uniquely constructed object can ignore shared qualifier. + // TODO: Is this appropriate? + tthis_fd = NULL; + } + else + return 0; // MATCHnomatch + } + MATCH mfa = tf->callMatch(tthis_fd, fargs); + //printf("test1: mfa = %d\n", mfa); + if (mfa != MATCHnomatch) + { + if (mfa > m->last) goto LfIsBetter; + if (mfa < m->last) goto LlastIsBetter; + + /* See if one of the matches overrides the other. + */ + assert(m->lastf); + if (m->lastf->overrides(fd)) goto LlastIsBetter; + if (fd->overrides(m->lastf)) goto LfIsBetter; + + /* Try to disambiguate using template-style partial ordering rules. + * In essence, if f() and g() are ambiguous, if f() can call g(), + * but g() cannot call f(), then pick f(). + * This is because f() is "more specialized." + */ + { + MATCH c1 = fd->leastAsSpecialized(m->lastf); + MATCH c2 = m->lastf->leastAsSpecialized(fd); + //printf("c1 = %d, c2 = %d\n", c1, c2); + if (c1 > c2) goto LfIsBetter; + if (c1 < c2) goto LlastIsBetter; + } + + /* If the two functions are the same function, like: + * int foo(int); + * int foo(int x) { ... } + * then pick the one with the body. + */ + if (tf->equals(m->lastf->type) && + fd->storage_class == m->lastf->storage_class && + fd->parent == m->lastf->parent && + fd->protection == m->lastf->protection && + fd->linkage == m->lastf->linkage) + { + if ( fd->fbody && !m->lastf->fbody) goto LfIsBetter; + if (!fd->fbody && m->lastf->fbody) goto LlastIsBetter; + } + + Lambiguous: + m->nextf = fd; + m->count++; + return 0; + + LlastIsBetter: + return 0; + + LfIsBetter: + td_best = NULL; + ta_last = MATCHexact; + m->last = mfa; + m->lastf = fd; + tthis_best = tthis_fd; + ov_index = 0; + m->count = 1; + tdargs->setDim(0); + return 0; + } + return 0; + } + int fp(TemplateDeclaration *td) + { + // skip duplicates + if (td == td_best) + return 0; + + if (!sc) + sc = td->scope; // workaround for Type::aliasthisOf + + if (td->semanticRun == PASSinit) + { + if (td->scope) + { + // Try to fix forward reference. Ungag errors while doing so. + Ungag ungag = td->ungagSpeculative(); + td->semantic(td->scope); + } + } + if (td->semanticRun == PASSinit) + { + ::error(loc, "forward reference to template %s", td->toChars()); goto Lerror; } - if (!td->onemember || !td->onemember->toAlias()->isFuncDeclaration()) + FuncDeclaration *f; + f = td->onemember ? td->onemember/*->toAlias()*/->isFuncDeclaration() : NULL; + if (!f) { if (!tiargs) tiargs = new Objects(); @@ -2115,273 +2390,261 @@ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Loc loc, Scope *sc, Objects dedtypes; dedtypes.setDim(td->parameters->dim); - assert(td->semanticRun); - MATCH m2 = td->matchWithInstance(ti, &dedtypes, fargs, 0); - //printf("matchWithInstance = %d\n", m2); - if (!m2 || m2 < m_best2) // no match or less match - continue; + assert(td->semanticRun != PASSinit); + MATCH mta = td->matchWithInstance(sc, ti, &dedtypes, fargs, 0); + //printf("matchWithInstance = %d\n", mta); + if (!mta || mta < ta_last) // no match or less match + return 0; ti->semantic(sc, fargs); if (!ti->inst) // if template failed to expand - continue; + return 0; Dsymbol *s = ti->inst->toAlias(); - FuncDeclaration *fd = s->isFuncDeclaration(); - if (!fd) - { - td->error("is not a function template"); + if (!s->isFuncDeclaration() && !s->isTemplateDeclaration()) goto Lerror; - } - fd = resolveFuncCall(loc, sc, fd, NULL, tthis, fargs, flags); + FuncDeclaration *fd = resolveFuncCall(loc, sc, s, NULL, tthis, fargs, 1); if (!fd) - continue; + return 0; + + Type *tthis_fd = fd->needThis() && !fd->isCtorDeclaration() ? tthis : NULL; TypeFunction *tf = (TypeFunction *)fd->type; - MATCH m = (MATCH) tf->callMatch(fd->needThis() && !fd->isCtorDeclaration() ? tthis : NULL, fargs); - if (m < m_best) - continue; + MATCH mfa = tf->callMatch(tthis_fd, fargs); + if (mfa < m->last) + return 0; // td is the new best match - td_ambig = NULL; assert(td->scope); td_best = td; - fd_best = fd; - m_best = m; - m_best2 = m2; + property = 0; // (backward compatibility) + ta_last = mta; + m->last = mfa; + m->lastf = fd; + tthis_best = tthis_fd; + ov_index = 0; + m->nextf = NULL; + m->count = 1; + tdargs->setDim(dedtypes.dim); + memcpy(tdargs->tdata(), dedtypes.tdata(), tdargs->dim * sizeof(void *)); + return 0; + } + + //printf("td = %s\n", td->toChars()); + for (size_t ovi = 0; f; f = f->overnext0, ovi++) + { + Objects dedtypes; + FuncDeclaration *fd = NULL; + int x = td->deduceFunctionTemplateMatch(f, loc, sc, tiargs, tthis, fargs, &dedtypes); + MATCH mta = (MATCH)(x >> 4); + MATCH mfa = (MATCH)(x & 0xF); + //printf("match:t/f = %d/%d\n", mta, mfa); + if (!mfa) // if no match + continue; + + Type *tthis_fd = NULL; + if (f->isCtorDeclaration()) + { + // Constructor call requires additional check. + // For that, do instantiate in early stage. + fd = td->doHeaderInstantiation(sc, &dedtypes, tthis, fargs); + if (!fd) + goto Lerror; + + TypeFunction *tf = (TypeFunction *)fd->type; + tthis_fd = fd->needThis() ? tthis : NULL; + if (tthis_fd) + { + assert(tf->next); + if (MODimplicitConv(tf->mod, tthis_fd->mod) || + tf->isWild() && tf->isShared() == tthis_fd->isShared() || + fd->isolateReturn()) + { + tthis_fd = NULL; + } + else + continue; // MATCHnomatch + } + } + + if (mta < ta_last) goto Ltd_best; + if (mta > ta_last) goto Ltd; + + if (mfa < m->last) goto Ltd_best; + if (mfa > m->last) goto Ltd; + + if (td_best) + { + // Disambiguate by picking the most specialized TemplateDeclaration + MATCH c1 = td->leastAsSpecialized(sc, td_best, fargs); + MATCH c2 = td_best->leastAsSpecialized(sc, td, fargs); + //printf("1: c1 = %d, c2 = %d\n", c1, c2); + if (c1 > c2) goto Ltd; + if (c1 < c2) goto Ltd_best; + } + + if (!m->lastf) + { + assert(td_best); + m->lastf = td_best->doHeaderInstantiation(sc, tdargs, tthis, fargs); + if (!m->lastf) goto Lerror; + tthis_best = m->lastf->needThis() ? tthis : NULL; + } + if (!fd) + { + fd = td->doHeaderInstantiation(sc, &dedtypes, tthis, fargs); + if (!fd) goto Lerror; + tthis_fd = fd->needThis() ? tthis : NULL; + } + assert(fd && m->lastf); + + { + // Disambiguate by tf->callMatch + TypeFunction *tf1 = (TypeFunction *)fd->type; + TypeFunction *tf2 = (TypeFunction *)m->lastf->type; + MATCH c1 = tf1->callMatch(tthis_fd, fargs); + MATCH c2 = tf2->callMatch(tthis_best, fargs); + //printf("2: c1 = %d, c2 = %d\n", c1, c2); + if (c1 > c2) goto Ltd; + if (c1 < c2) goto Ltd_best; + } + { + // Disambiguate by picking the most specialized FunctionDeclaration + MATCH c1 = fd->leastAsSpecialized(m->lastf); + MATCH c2 = m->lastf->leastAsSpecialized(fd); + //printf("3: c1 = %d, c2 = %d\n", c1, c2); + if (c1 > c2) goto Ltd; + if (c1 < c2) goto Ltd_best; + } + + Lambig: // td_best and td are ambiguous + //printf("Lambig\n"); + m->nextf = fd; // Caution! m->nextf isn't complete instantiated fd, so must not call toPrettyChars() + m->count++; + continue; + + Ltd_best: // td_best is the best match so far + continue; + + Ltd: // td is the new best match + assert(td->scope); + td_best = td; + property = 0; // (backward compatibility) + ta_last = mta; + m->last = mfa; + m->lastf = fd; + tthis_best = tthis_fd; + ov_index = ovi; + m->nextf = NULL; + m->count = 1; tdargs->setDim(dedtypes.dim); memcpy(tdargs->tdata(), dedtypes.tdata(), tdargs->dim * sizeof(void *)); continue; } + return 0; - MATCH m, m2; - Objects dedargs; - FuncDeclaration *fd = NULL; - - m = td->deduceFunctionTemplateMatch(loc, sc, tiargs, tthis, fargs, &dedargs); - m2 = (MATCH)(m >> 4); - m = (MATCH)(m & 0xF); - //printf("deduceFunctionTemplateMatch = %d, m2 = %d\n", m, m2); - if (!m) // if no match - continue; - - Type *tthis_fd = NULL; - if (td->onemember->toAlias()->isFuncDeclaration()->isCtorDeclaration()) - { - // Constructor call requires additional check. - // For that, do instantiate in early stage. - fd = td->doHeaderInstantiation(sc, &dedargs, tthis, fargs); - if (!fd) - goto Lerror; - - TypeFunction *tf = (TypeFunction *)fd->type; - tthis_fd = fd->needThis() ? tthis : NULL; - if (tthis_fd) - { - assert(tf->next); - if (MODimplicitConv(tf->mod, tthis_fd->mod) || - tf->isWild() && tf->isShared() == tthis_fd->isShared() || - fd->isolateReturn()) - { - tthis_fd = NULL; - } - else - continue; // MATCHnomatch - } - } - - if (m2 < m_best2) - goto Ltd_best; - if (m2 > m_best2) - goto Ltd; - - if (m < m_best) - goto Ltd_best; - if (m > m_best) - goto Ltd; - - { - // Disambiguate by picking the most specialized TemplateDeclaration - MATCH c1 = td->leastAsSpecialized(td_best, fargs); - MATCH c2 = td_best->leastAsSpecialized(td, fargs); - //printf("1: c1 = %d, c2 = %d\n", c1, c2); - - if (c1 > c2) - goto Ltd; - else if (c1 < c2) - goto Ltd_best; - } - - if (!fd_best) - { - fd_best = td_best->doHeaderInstantiation(sc, tdargs, tthis, fargs); - if (!fd_best) - goto Lerror; - tthis_best = fd_best->needThis() ? tthis : NULL; - } - if (!fd) - { - fd = td->doHeaderInstantiation(sc, &dedargs, tthis, fargs); - if (!fd) - goto Lerror; - tthis_fd = fd->needThis() ? tthis : NULL; - } - assert(fd && fd_best); - - { - // Disambiguate by tf->callMatch - TypeFunction *tf1 = (TypeFunction *)fd->type; - TypeFunction *tf2 = (TypeFunction *)fd_best->type; - MATCH c1 = tf1->callMatch(tthis_fd, fargs); - MATCH c2 = tf2->callMatch(tthis_best, fargs); - //printf("2: c1 = %d, c2 = %d\n", c1, c2); - - if (c1 > c2) - goto Ltd; - if (c1 < c2) - goto Ltd_best; - } - - { - // Disambiguate by picking the most specialized FunctionDeclaration - MATCH c1 = fd->leastAsSpecialized(fd_best); - MATCH c2 = fd_best->leastAsSpecialized(fd); - //printf("3: c1 = %d, c2 = %d\n", c1, c2); - - if (c1 > c2) - goto Ltd; - if (c1 < c2) - goto Ltd_best; - } - - Lambig: // td_best and td are ambiguous - td_ambig = td; - continue; - - Ltd_best: // td_best is the best match so far - td_ambig = NULL; - continue; - - Ltd: // td is the new best match - td_ambig = NULL; - assert(td->scope); - td_best = td; - fd_best = fd; - tthis_best = tthis_fd; - m_best = m; - m_best2 = m2; - tdargs->setDim(dedargs.dim); - memcpy(tdargs->tdata(), dedargs.tdata(), tdargs->dim * sizeof(void *)); - continue; + Lerror: + m->lastf = NULL; + m->count = 0; + m->last = MATCHnomatch; + return 1; } - if (!td_best) + }; + ParamDeduce p; + // context + p.loc = loc; + p.sc = sc; + p.tthis = tthis; + p.tiargs = tiargs; + p.fargs = fargs; + + // result + p.m = m; + p.property = 0; + p.ov_index = 0; + p.td_best = NULL; + p.ta_last = m->last ? MATCHexact : MATCHnomatch; + p.tdargs = new Objects(); + p.tthis_best = NULL; + + FuncDeclaration *fd = dstart->isFuncDeclaration(); + TemplateDeclaration *td = dstart->isTemplateDeclaration(); + if (td && td->funcroot) + dstart = td->funcroot; + overloadApply(dstart, &p, &ParamDeduce::fp); + + //printf("td_best = %p, m->lastf = %p, match:t/f = %d/%d\n", td_best, m->lastf, mta, mfa); + if (p.td_best) { - if (!(flags & 1)) + // Matches to template function + if (!p.td_best->onemember || !p.td_best->onemember->toAlias()->isFuncDeclaration()) + return; // goto Lerror? + + /* The best match is td_best with arguments tdargs. + * Now instantiate the template. + */ + assert(p.td_best->scope); + if (!sc) sc = p.td_best->scope; // workaround for Type::aliasthisOf + TemplateInstance *ti; + ti = new TemplateInstance(loc, p.td_best, p.tdargs); + ti->semantic(sc, fargs); + m->lastf = ti->toAlias()->isFuncDeclaration(); + if (!m->lastf) + goto Lerror; + + // look forward instantiated overload function + // Dsymbol::oneMembers is alredy called in TemplateInstance::semantic. + // it has filled overnext0d + while (p.ov_index--) { - ::error(loc, "%s %s.%s does not match any function template declaration. Candidates are:", - kind(), parent->toPrettyChars(), ident->toChars()); - - // Display candidate template functions - int numToDisplay = 5; // sensible number to display - for (TemplateDeclaration *td = this; td; td = td->overnext) - { - ::errorSupplemental(td->loc, "%s", td->toPrettyChars()); - if (!global.params.verbose && --numToDisplay == 0) - { - // Too many overloads to sensibly display. - // Just show count of remaining overloads. - int remaining = 0; - for (; td; td = td->overnext) - ++remaining; - if (remaining > 0) - ::errorSupplemental(loc, "... (%d more, -v to show) ...", remaining); - break; - } - } + m->lastf = m->lastf->overnext0; + assert(m->lastf); } - goto Lerror; - } - if (td_ambig) - { - ::error(loc, "%s %s.%s matches more than one template declaration, %s(%d):%s and %s(%d):%s", - kind(), parent->toPrettyChars(), ident->toChars(), - td_best->loc.filename, td_best->loc.linnum, td_best->toChars(), - td_ambig->loc.filename, td_ambig->loc.linnum, td_ambig->toChars()); - } - if (!td_best->onemember || !td_best->onemember->toAlias()->isFuncDeclaration()) - return fd_best; + p.tthis_best = m->lastf->needThis() && !m->lastf->isCtorDeclaration() ? tthis : NULL; - /* The best match is td_best with arguments tdargs. - * Now instantiate the template. - */ - assert(td_best->scope); - ti = new TemplateInstance(loc, td_best, tdargs); - ti->semantic(sc, fargs); - fd_best = ti->toAlias()->isFuncDeclaration(); - if (!fd_best) - goto Lerror; - if (!((TypeFunction*)fd_best->type)->callMatch(fd_best->needThis() && !fd_best->isCtorDeclaration() ? tthis : NULL, fargs)) - goto Lerror; - - if (FuncLiteralDeclaration *fld = fd_best->isFuncLiteralDeclaration()) - { - // Inside template constraint, nested reference check doesn't work correctly. - if (!(sc->flags & SCOPEstaticif) && fld->tok == TOKreserved) - { // change to non-nested - fld->tok = TOKfunction; - fld->vthis = NULL; - } - } - - /* As Bugzilla 3682 shows, a template instance can be matched while instantiating - * that same template. Thus, the function type can be incomplete. Complete it. - * - * Bugzilla 9208: For auto function, completion should be deferred to the end of - * its semantic3. Should not complete it in here. - */ - { TypeFunction *tf = (TypeFunction *)fd_best->type; + TypeFunction *tf = (TypeFunction *)m->lastf->type; assert(tf->ty == Tfunction); - if (tf->next && !fd_best->inferRetType) + if (!tf->callMatch(p.tthis_best, fargs)) + goto Lerror; + + if (FuncLiteralDeclaration *fld = m->lastf->isFuncLiteralDeclaration()) { - fd_best->type = tf->semantic(loc, sc); - } - } - - if (!(flags & 1)) - fd_best->functionSemantic(); - - return fd_best; - - Lerror: -#if DMDV2 - if (!(flags & 1)) -#endif - { - HdrGenState hgs; - - OutBuffer bufa; - Objects *args = tiargs; - if (args) - { for (size_t i = 0; i < args->dim; i++) + if ((sc->flags & SCOPEstaticif) || sc->intypeof) { - if (i) - bufa.writestring(", "); - Object *oarg = (*args)[i]; - ObjectToCBuffer(&bufa, &hgs, oarg); + // Inside template constraint, or inside typeof, + // nested reference check doesn't work correctly. + } + else if (fld->tok == TOKreserved) + { + // change to non-nested + fld->tok = TOKfunction; + fld->vthis = NULL; } } - OutBuffer buf; - argExpTypesToCBuffer(&buf, fargs, &hgs); - if (this->overnext) - ::error(this->loc, "%s %s.%s cannot deduce template function from argument types !(%s)(%s)", - kind(), parent->toPrettyChars(), ident->toChars(), - bufa.toChars(), buf.toChars()); - else - error(loc, "cannot deduce template function from argument types !(%s)(%s)", - bufa.toChars(), buf.toChars()); + /* As Bugzilla 3682 shows, a template instance can be matched while instantiating + * that same template. Thus, the function type can be incomplete. Complete it. + * + * Bugzilla 9208: For auto function, completion should be deferred to the end of + * its semantic3. Should not complete it in here. + */ + if (tf->next && !m->lastf->inferRetType) + { + m->lastf->type = tf->semantic(loc, sc); + } + } + else if (m->lastf) + { + // Matches to non template function + } + else + { + Lerror: + m->lastf = NULL; + m->count = 0; + m->last = MATCHnomatch; } - return NULL; } /************************************************* @@ -2397,15 +2660,15 @@ FuncDeclaration *TemplateDeclaration::doHeaderInstantiation(Scope *sc, #if 0 printf("doHeaderInstantiation this = %s\n", toChars()); for (size_t i = 0; i < tdargs->dim; ++i) - printf("\ttdargs[%d] = %s\n", i, ((Object *)tdargs->data[i])->toChars()); + printf("\ttdargs[%d] = %s\n", i, ((RootObject *)tdargs->data[i])->toChars()); #endif assert(scope); TemplateInstance *ti = new TemplateInstance(loc, this, tdargs); ti->tinst = sc->tinst; { - ti->tdtypes.setDim(ti->tempdecl->parameters->dim); - if (!ti->tempdecl->matchWithInstance(ti, &ti->tdtypes, fargs, 2)) + ti->tdtypes.setDim(parameters->dim); + if (!matchWithInstance(sc, ti, &ti->tdtypes, fargs, 2)) return NULL; } @@ -2419,11 +2682,13 @@ FuncDeclaration *TemplateDeclaration::doHeaderInstantiation(Scope *sc, fd = new FuncDeclaration(fd->loc, fd->endloc, fd->ident, fd->storage_class, fd->type->syntaxCopy()); fd->parent = ti; - Scope *scope = this->scope; + Module *mi = sc->instantiatingModule ? sc->instantiatingModule : sc->module; + Scope *scope = this->scope; ti->argsym = new ScopeDsymbol(); ti->argsym->parent = scope->parent; scope = scope->push(ti->argsym); + scope->instantiatingModule = mi; bool hasttp = false; @@ -2591,11 +2856,117 @@ char *TemplateDeclaration::toChars() return (char *)buf.extractData(); } -enum PROT TemplateDeclaration::prot() +PROT TemplateDeclaration::prot() { return protection; } +/**************************************************** + * Given a new instance tithis of this TemplateDeclaration, + * see if there already exists an instance. + * If so, return that existing instance. + */ + +TemplateInstance *TemplateDeclaration::findExistingInstance(TemplateInstance *tithis, Expressions *fargs) +{ + tithis->fargs = fargs; + hash_t hash = tithis->hashCode(); + + if (!buckets.dim) + { + buckets.setDim(7); + buckets.zero(); + } + size_t bi = hash % buckets.dim; + TemplateInstances *instances = buckets[bi]; + if (instances) + { + for (size_t i = 0; i < instances->dim; i++) + { + TemplateInstance *ti = (*instances)[i]; +#if LOG + printf("\t%s: checking for match with instance %d (%p): '%s'\n", tithis->toChars(), i, ti, ti->toChars()); +#endif + if (hash == ti->hash && + tithis->compare(ti) == 0) + { + //printf("hash = %p yes %d n = %d\n", hash, instances->dim, numinstances); + return ti; + } + } + } + //printf("hash = %p no\n", hash); + return NULL; // didn't find a match +} + +/******************************************** + * Add instance ti to TemplateDeclaration's table of instances. + * Return a handle we can use to later remove it if it fails instantiation. + */ + +TemplateInstance *TemplateDeclaration::addInstance(TemplateInstance *ti) +{ + /* See if we need to rehash + */ + if (numinstances > buckets.dim * 4) + { // rehash + //printf("rehash\n"); + size_t newdim = buckets.dim * 2 + 1; + TemplateInstances **newp = (TemplateInstances **)::calloc(newdim, sizeof(TemplateInstances *)); + assert(newp); + for (size_t bi = 0; bi < buckets.dim; ++bi) + { + TemplateInstances *instances = buckets[bi]; + if (instances) + { + for (size_t i = 0; i < instances->dim; i++) + { + TemplateInstance *ti1 = (*instances)[i]; + size_t newbi = ti1->hash % newdim; + TemplateInstances *newinstances = newp[newbi]; + if (!newinstances) + newp[newbi] = newinstances = new TemplateInstances(); + newinstances->push(ti1); + } + delete instances; + } + } + buckets.setDim(newdim); + memcpy(buckets.tdata(), newp, newdim * sizeof(TemplateInstance *)); + ::free(newp); + } + + // Insert ti into hash table + size_t bi = ti->hash % buckets.dim; + TemplateInstances *instances = buckets[bi]; + if (!instances) + buckets[bi] = instances = new TemplateInstances(); + instances->push(ti); + ++numinstances; + return ti; +} + +/******************************************* + * Remove TemplateInstance from table of instances. + * Input: + * handle returned by addInstance() + */ + +void TemplateDeclaration::removeInstance(TemplateInstance *handle) +{ + size_t bi = handle->hash % buckets.dim; + TemplateInstances *instances = buckets[bi]; + for (size_t i = 0; i < instances->dim; i++) + { + TemplateInstance *ti = (*instances)[i]; + if (handle == ti) + { instances->remove(i); + break; + } + } + --numinstances; +} + /* ======================== Type ============================================ */ /**** @@ -2620,10 +2991,7 @@ size_t templateParameterLookup(Type *tparam, TemplateParameters *parameters) { TypeIdentifier *tident = (TypeIdentifier *)tparam; //printf("\ttident = '%s'\n", tident->toChars()); - if (tident->idents.dim == 0) - { - return templateIdentifierLookup(tident->ident, parameters); - } + return templateIdentifierLookup(tident->ident, parameters); } return IDX_NOTFOUND; } @@ -2685,6 +3053,63 @@ MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, TemplateParameter *tp = (*parameters)[i]; + TypeIdentifier *tident = (TypeIdentifier *)tparam; + if (tident->idents.dim > 0) + { + //printf("matching %s to %s\n", tparam->toChars(), toChars()); + Dsymbol *s = this->toDsymbol(sc); + for (size_t j = tident->idents.dim; j-- > 0; ) + { + RootObject *id = tident->idents[j]; + if (id->dyncast() == DYNCAST_IDENTIFIER) + { + if (!s || !s->parent) + goto Lnomatch; + Dsymbol *s2 = s->parent->searchX(Loc(), sc, id); + if (!s2) + goto Lnomatch; + s2 = s2->toAlias(); + //printf("[%d] s = %s %s, s2 = %s %s\n", j, s->kind(), s->toChars(), s2->kind(), s2->toChars()); + if (s != s2) + { + if (Type *t = s2->getType()) + { + if (s != t->toDsymbol(sc)) + goto Lnomatch; + } + else + goto Lnomatch; + } + s = s->parent; + } + else + goto Lnomatch; + } + //printf("[e] s = %s\n", s?s->toChars():"(null)"); + if (TemplateTypeParameter *ttp = tp->isTemplateTypeParameter()) + { + Type *tt = s->getType(); + if (!tt) + goto Lnomatch; + Type *at = (Type *)(*dedtypes)[i]; + if (!at || tt->equals(at)) + { + (*dedtypes)[i] = tt; + goto Lexact; + } + } + if (TemplateAliasParameter *tap = tp->isTemplateAliasParameter()) + { + Dsymbol *s2 = (Dsymbol *)(*dedtypes)[i]; + if (!s2 || s == s2) + { + (*dedtypes)[i] = s; + goto Lexact; + } + } + goto Lnomatch; + } + // Found the corresponding parameter tp if (!tp->isTemplateTypeParameter()) goto Lnomatch; @@ -2942,7 +3367,12 @@ MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, } if (nextOf()) + { + if (tparam->deco && !tparam->hasWild()) + return implicitConvTo(tparam); + return nextOf()->deduceType(sc, tparam->nextOf(), parameters, dedtypes, wildmatch); + } Lexact: return MATCHexact; @@ -3034,24 +3464,9 @@ MATCH TypeSArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parame size_t i = templateIdentifierLookup(id, parameters); if (i == IDX_NOTFOUND) goto Lnomatch; - TemplateParameter *tprm = (*parameters)[i]; - TemplateValueParameter *tvp = tprm->isTemplateValueParameter(); - if (!tvp) + TemplateParameter *tp = (*parameters)[i]; + if (!tp->matchArg(sc, dim, i, parameters, dedtypes, NULL)) goto Lnomatch; - Expression *e = (Expression *)(*dedtypes)[i]; - if (e) - { - if (!dim->equals(e)) - goto Lnomatch; - } - else - { - Type *vt = tvp->valType->semantic(Loc(), sc); - MATCH m = (MATCH)dim->implicitConvTo(vt); - if (!m) - goto Lnomatch; - (*dedtypes)[i] = dim; - } return next->deduceType(sc, tparam->nextOf(), parameters, dedtypes, wildmatch); } } @@ -3143,7 +3558,7 @@ MATCH TypeFunction::deduceType(Scope *sc, Type *tparam, TemplateParameters *para /* See if existing tuple, and whether it matches or not */ - Object *o = (*dedtypes)[tupi]; + RootObject *o = (*dedtypes)[tupi]; if (o) { // Existing deduced argument must be a tuple, and must match Tuple *t = isTuple(o); @@ -3194,8 +3609,8 @@ MATCH TypeIdentifier::deduceType(Scope *sc, Type *tparam, TemplateParameters *pa for (size_t i = 0; i < idents.dim; i++) { - Object *id1 = idents[i]; - Object *id2 = tp->idents[i]; + RootObject *id1 = idents[i]; + RootObject *id2 = tp->idents[i]; if (!id1->equals(id2)) return MATCHnomatch; @@ -3213,13 +3628,15 @@ MATCH TypeInstance::deduceType(Scope *sc, printf("\tthis = %d, ", ty); print(); printf("\ttparam = %d, ", tparam->ty); tparam->print(); #endif + TemplateDeclaration *tempdecl = tempinst->tempdecl->isTemplateDeclaration(); + assert(tempdecl); // Extra check if (tparam && tparam->ty == Tinstance) { TypeInstance *tp = (TypeInstance *)tparam; - //printf("tempinst->tempdecl = %p\n", tempinst->tempdecl); + //printf("tempinst->tempdecl = %p\n", tempdecl); //printf("tp->tempinst->tempdecl = %p\n", tp->tempinst->tempdecl); if (!tp->tempinst->tempdecl) { //printf("tp->tempinst->name = '%s'\n", tp->tempinst->name->toChars()); @@ -3250,32 +3667,17 @@ MATCH TypeInstance::deduceType(Scope *sc, { s = s->toAlias(); TemplateDeclaration *td = s->isTemplateDeclaration(); - if (td && td == tempinst->tempdecl) + if (td && td == tempdecl) goto L2; } goto Lnomatch; } TemplateParameter *tpx = (*parameters)[i]; - // This logic duplicates tpx->matchArg() - TemplateAliasParameter *ta = tpx->isTemplateAliasParameter(); - if (!ta) + if (!tpx->matchArg(sc, tempdecl, i, parameters, dedtypes, NULL)) goto Lnomatch; - Object *sa = tempinst->tempdecl; - if (!sa) - goto Lnomatch; - if (ta->specAlias && sa != ta->specAlias) - goto Lnomatch; - if ((*dedtypes)[i]) - { // Must match already deduced symbol - Object *s = (*dedtypes)[i]; - - if (s != sa) - goto Lnomatch; - } - (*dedtypes)[i] = sa; } } - else if (tempinst->tempdecl != tp->tempinst->tempdecl) + else if (tempdecl != tp->tempinst->tempdecl) goto Lnomatch; L2: @@ -3283,7 +3685,7 @@ MATCH TypeInstance::deduceType(Scope *sc, for (size_t i = 0; 1; i++) { //printf("\ttest: tempinst->tiargs[%d]\n", i); - Object *o1 = NULL; + RootObject *o1 = NULL; if (i < tempinst->tiargs->dim) o1 = (*tempinst->tiargs)[i]; else if (i < tempinst->tdtypes.dim && i < tp->tempinst->tiargs->dim) @@ -3295,7 +3697,7 @@ MATCH TypeInstance::deduceType(Scope *sc, if (i >= tp->tempinst->tiargs->dim) goto Lnomatch; - Object *o2 = (*tp->tempinst->tiargs)[i]; + RootObject *o2 = (*tp->tempinst->tiargs)[i]; Type *t2 = isType(o2); size_t j; @@ -3316,12 +3718,12 @@ MATCH TypeInstance::deduceType(Scope *sc, /* Create tuple from remaining args */ Tuple *vt = new Tuple(); - size_t vtdim = (tempinst->tempdecl->isVariadic() + size_t vtdim = (tempdecl->isVariadic() ? tempinst->tiargs->dim : tempinst->tdtypes.dim) - i; vt->objects.setDim(vtdim); for (size_t k = 0; k < vtdim; k++) { - Object *o; + RootObject *o; if (k < tempinst->tiargs->dim) o = (*tempinst->tiargs)[i + k]; else // Pick up default arg @@ -3332,7 +3734,9 @@ MATCH TypeInstance::deduceType(Scope *sc, Tuple *v = (Tuple *)(*dedtypes)[j]; if (v) { - if (!match(v, vt, tempinst->tempdecl, sc)) + if (checkRecursiveExpansion(v, tempdecl, sc)) + goto Lnomatch; + if (!match(v, vt)) goto Lnomatch; } else @@ -3369,19 +3773,29 @@ MATCH TypeInstance::deduceType(Scope *sc, { Le: e1 = e1->ctfeInterpret(); + + /* If it is one of the template parameters for this template, + * we should not attempt to interpret it. It already has a value. + */ + if (e2->op == TOKvar && + (((VarExp *)e2)->var->storage_class & STCtemplateparameter)) + { + /* + * (T:Number!(e2), int e2) + */ + j = templateIdentifierLookup(((VarExp *)e2)->var->ident, parameters); + if (j != IDX_NOTFOUND) + goto L1; + // The template parameter was not from this template + // (it may be from a parent template, for example) + } + e2 = e2->ctfeInterpret(); //printf("e1 = %s, type = %s %d\n", e1->toChars(), e1->type->toChars(), e1->type->ty); //printf("e2 = %s, type = %s %d\n", e2->toChars(), e2->type->toChars(), e2->type->ty); if (!e1->equals(e2)) - { if (e2->op == TOKvar) - { - /* - * (T:Number!(e2), int e2) - */ - j = templateIdentifierLookup(((VarExp *)e2)->var->ident, parameters); - goto L1; - } + { if (!e2->implicitConvTo(e1->type)) goto Lnomatch; @@ -3403,35 +3817,7 @@ MATCH TypeInstance::deduceType(Scope *sc, goto Lnomatch; } TemplateParameter *tp = (*parameters)[j]; - // BUG: use tp->matchArg() instead of the following - TemplateValueParameter *tv = tp->isTemplateValueParameter(); - TemplateAliasParameter *ta = tp->isTemplateAliasParameter(); - if (tv) - { - Expression *e = (Expression *)(*dedtypes)[j]; - if (e) - { - if (!e1->equals(e)) - goto Lnomatch; - } - else - { Type *vt = tv->valType->semantic(Loc(), sc); - MATCH m = (MATCH)e1->implicitConvTo(vt); - if (!m) - goto Lnomatch; - (*dedtypes)[j] = e1; - } - } - else if (ta) - { - if (ta->specType) - { - if (!e1->type->equals(ta->specType)) - goto Lnomatch; - } - (*dedtypes)[j] = e1; - } - else + if (!tp->matchArg(sc, e1, j, parameters, dedtypes, NULL)) goto Lnomatch; } else if (s1 && s2) @@ -3451,20 +3837,8 @@ MATCH TypeInstance::deduceType(Scope *sc, goto Lnomatch; } TemplateParameter *tp = (*parameters)[j]; - // BUG: use tp->matchArg() instead of the following - TemplateAliasParameter *ta = tp->isTemplateAliasParameter(); - if (!ta) + if (!tp->matchArg(sc, s1, j, parameters, dedtypes, NULL)) goto Lnomatch; - Dsymbol *s = (Dsymbol *)(*dedtypes)[j]; - if (s) - { - if (!s1->equals(s)) - goto Lnomatch; - } - else - { - (*dedtypes)[j] = s1; - } } else goto Lnomatch; @@ -3502,7 +3876,7 @@ MATCH TypeStruct::deduceType(Scope *sc, Type *tparam, TemplateParameters *parame */ TypeInstance *tpi = (TypeInstance *)tparam; if (tpi->idents.dim) - { Object *id = tpi->idents[tpi->idents.dim - 1]; + { RootObject *id = tpi->idents[tpi->idents.dim - 1]; if (id->dyncast() == DYNCAST_IDENTIFIER && sym->ident->equals((Identifier *)id)) { Type *tparent = sym->parent->getType(); @@ -3646,7 +4020,7 @@ MATCH TypeClass::deduceType(Scope *sc, Type *tparam, TemplateParameters *paramet */ TypeInstance *tpi = (TypeInstance *)tparam; if (tpi->idents.dim) - { Object *id = tpi->idents[tpi->idents.dim - 1]; + { RootObject *id = tpi->idents[tpi->idents.dim - 1]; if (id->dyncast() == DYNCAST_IDENTIFIER && sym->ident->equals((Identifier *)id)) { Type *tparent = sym->parent->getType(); @@ -3751,6 +4125,45 @@ TemplateThisParameter *TemplateParameter::isTemplateThisParameter() } #endif +/******************************************* + * Match to a particular TemplateParameter. + * Input: + * i i'th argument + * tiargs[] actual arguments to template instance + * parameters[] template parameters + * dedtypes[] deduced arguments to template instance + * *psparam set to symbol declared and initialized to dedtypes[i] + */ + +MATCH TemplateParameter::matchArg(Loc loc, Scope *sc, Objects *tiargs, + size_t i, TemplateParameters *parameters, Objects *dedtypes, + Declaration **psparam) +{ + RootObject *oarg; + + if (i < tiargs->dim) + oarg = (*tiargs)[i]; + else + { + // Get default argument instead + oarg = defaultArg(loc, sc); + if (!oarg) + { + assert(i < dedtypes->dim); + // It might have already been deduced + oarg = (*dedtypes)[i]; + if (!oarg) + goto Lnomatch; + } + } + return matchArg(sc, oarg, i, parameters, dedtypes, psparam); + +Lnomatch: + if (psparam) + *psparam = NULL; + return MATCHnomatch; +} + /* ======================== TemplateTypeParameter =========================== */ // type-parameter @@ -3790,10 +4203,10 @@ void TemplateTypeParameter::declareParameter(Scope *sc) error(loc, "parameter '%s' multiply defined", ident->toChars()); } -void TemplateTypeParameter::semantic(Scope *sc) +void TemplateTypeParameter::semantic(Scope *sc, TemplateParameters *parameters) { //printf("TemplateTypeParameter::semantic('%s')\n", ident->toChars()); - if (specType) + if (specType && !specType->reliesOnTident(parameters)) { specType = specType->semantic(loc, sc); } @@ -3832,42 +4245,13 @@ Lnomatch: return 0; } -/******************************************* - * Match to a particular TemplateParameter. - * Input: - * i i'th argument - * tiargs[] actual arguments to template instance - * parameters[] template parameters - * dedtypes[] deduced arguments to template instance - * *psparam set to symbol declared and initialized to dedtypes[i] - */ - -MATCH TemplateTypeParameter::matchArg(Scope *sc, Objects *tiargs, +MATCH TemplateTypeParameter::matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam) { //printf("TemplateTypeParameter::matchArg()\n"); - Object *oarg; MATCH m = MATCHexact; - Type *ta; - - if (i < tiargs->dim) - oarg = (*tiargs)[i]; - else - { // Get default argument instead - oarg = defaultArg(loc, sc); - if (!oarg) - { assert(i < dedtypes->dim); - // It might have already been deduced - oarg = (*dedtypes)[i]; - if (!oarg) - { - goto Lnomatch; - } - } - } - - ta = isType(oarg); + Type *ta = isType(oarg); if (!ta) { //printf("%s %p %p %p\n", oarg->toChars(), isExpression(oarg), isDsymbol(oarg), isTuple(oarg)); @@ -3911,18 +4295,20 @@ MATCH TemplateTypeParameter::matchArg(Scope *sc, Objects *tiargs, } (*dedtypes)[i] = ta; - *psparam = new AliasDeclaration(loc, ident, ta); + if (psparam) + *psparam = new AliasDeclaration(loc, ident, ta); //printf("\tm = %d\n", m); return m; Lnomatch: - *psparam = NULL; + if (psparam) + *psparam = NULL; //printf("\tm = %d\n", MATCHnomatch); return MATCHnomatch; } -void TemplateTypeParameter::print(Object *oarg, Object *oded) +void TemplateTypeParameter::print(RootObject *oarg, RootObject *oded) { printf(" %s\n", ident->toChars()); @@ -3971,13 +4357,13 @@ void *TemplateTypeParameter::dummyArg() } -Object *TemplateTypeParameter::specialization() +RootObject *TemplateTypeParameter::specialization() { return specType; } -Object *TemplateTypeParameter::defaultArg(Loc loc, Scope *sc) +RootObject *TemplateTypeParameter::defaultArg(Loc loc, Scope *sc) { Type *t; @@ -4031,7 +4417,7 @@ void TemplateThisParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) Dsymbol *TemplateAliasParameter::sdummy = NULL; TemplateAliasParameter::TemplateAliasParameter(Loc loc, Identifier *ident, - Type *specType, Object *specAlias, Object *defaultAlias) + Type *specType, RootObject *specAlias, RootObject *defaultAlias) : TemplateParameter(loc, ident) { this->ident = ident; @@ -4063,13 +4449,13 @@ void TemplateAliasParameter::declareParameter(Scope *sc) error(loc, "parameter '%s' multiply defined", ident->toChars()); } -Object *aliasParameterSemantic(Loc loc, Scope *sc, Object *o) +RootObject *aliasParameterSemantic(Loc loc, Scope *sc, RootObject *o, TemplateParameters *parameters) { if (o) { Expression *ea = isExpression(o); Type *ta = isType(o); - if (ta) + if (ta && (!parameters || !ta->reliesOnTident(parameters))) { Dsymbol *s = ta->toDsymbol(sc); if (s) o = s; @@ -4078,20 +4464,22 @@ Object *aliasParameterSemantic(Loc loc, Scope *sc, Object *o) } else if (ea) { - ea = ea->ctfeSemantic(sc); + sc = sc->startCTFE(); + ea = ea->semantic(sc); + sc = sc->endCTFE(); o = ea->ctfeInterpret(); } } return o; } -void TemplateAliasParameter::semantic(Scope *sc) +void TemplateAliasParameter::semantic(Scope *sc, TemplateParameters *parameters) { - if (specType) + if (specType && !specType->reliesOnTident(parameters)) { specType = specType->semantic(loc, sc); } - specAlias = aliasParameterSemantic(loc, sc, specAlias); + specAlias = aliasParameterSemantic(loc, sc, specAlias, parameters); #if 0 // Don't do semantic() until instantiation if (defaultAlias) defaultAlias = defaultAlias->semantic(loc, sc); @@ -4126,7 +4514,7 @@ Lnomatch: * } // because Sym template cannot * void main() { S s; s.foo(); } // access to the valid 'this' symbol. */ -bool isPseudoDsymbol(Object *o) +bool isPseudoDsymbol(RootObject *o) { Dsymbol *s = isDsymbol(o); Expression *e = isExpression(o); @@ -4153,33 +4541,13 @@ bool isPseudoDsymbol(Object *o) return false; } -MATCH TemplateAliasParameter::matchArg(Scope *sc, Objects *tiargs, +MATCH TemplateAliasParameter::matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam) { - Object *sa; - Object *oarg; - Expression *ea; - Dsymbol *s; - //printf("TemplateAliasParameter::matchArg()\n"); - - if (i < tiargs->dim) - oarg = (*tiargs)[i]; - else - { // Get default argument instead - oarg = defaultArg(loc, sc); - if (!oarg) - { assert(i < dedtypes->dim); - // It might have already been deduced - oarg = (*dedtypes)[i]; - if (!oarg) - goto Lnomatch; - } - } - - sa = getDsymbol(oarg); - ea = isExpression(oarg); + RootObject *sa = getDsymbol(oarg); + Expression *ea = isExpression(oarg); if (ea && (ea->op == TOKthis || ea->op == TOKsuper)) sa = ((ThisExp *)ea)->var; else if (ea && ea->op == TOKimport) @@ -4229,37 +4597,42 @@ MATCH TemplateAliasParameter::matchArg(Scope *sc, Objects *tiargs, } else if ((*dedtypes)[i]) { // Must match already deduced symbol - Object *si = (*dedtypes)[i]; + RootObject *si = (*dedtypes)[i]; if (!sa || si != sa) goto Lnomatch; } (*dedtypes)[i] = sa; - s = isDsymbol(sa); - if (s) - *psparam = new AliasDeclaration(loc, ident, s); - else + if (psparam) { - assert(ea); + if (Dsymbol *s = isDsymbol(sa)) + { + *psparam = new AliasDeclaration(loc, ident, s); + } + else + { + assert(ea); - // Declare manifest constant - Initializer *init = new ExpInitializer(loc, ea); - VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init); - v->storage_class = STCmanifest; - v->semantic(sc); - *psparam = v; + // Declare manifest constant + Initializer *init = new ExpInitializer(loc, ea); + VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init); + v->storage_class = STCmanifest; + v->semantic(sc); + *psparam = v; + } } return MATCHexact; Lnomatch: - *psparam = NULL; + if (psparam) + *psparam = NULL; //printf("\tm = %d\n", MATCHnomatch); return MATCHnomatch; } -void TemplateAliasParameter::print(Object *oarg, Object *oded) +void TemplateAliasParameter::print(RootObject *oarg, RootObject *oded) { printf(" %s\n", ident->toChars()); @@ -4292,7 +4665,7 @@ void TemplateAliasParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) void *TemplateAliasParameter::dummyArg() -{ Object *s; +{ RootObject *s; s = specAlias; if (!s) @@ -4305,15 +4678,15 @@ void *TemplateAliasParameter::dummyArg() } -Object *TemplateAliasParameter::specialization() +RootObject *TemplateAliasParameter::specialization() { return specAlias; } -Object *TemplateAliasParameter::defaultArg(Loc loc, Scope *sc) +RootObject *TemplateAliasParameter::defaultArg(Loc loc, Scope *sc) { - Object *da = defaultAlias; + RootObject *da = defaultAlias; Type *ta = isType(defaultAlias); if (ta) { @@ -4324,7 +4697,7 @@ Object *TemplateAliasParameter::defaultArg(Loc loc, Scope *sc) } } - Object *o = aliasParameterSemantic(loc, sc, da); + RootObject *o = aliasParameterSemantic(loc, sc, da, NULL); return o; } @@ -4370,7 +4743,7 @@ void TemplateValueParameter::declareParameter(Scope *sc) sparam = v; } -void TemplateValueParameter::semantic(Scope *sc) +void TemplateValueParameter::semantic(Scope *sc, TemplateParameters *parameters) { bool wasSame = (sparam->type == valType); sparam->semantic(sc); @@ -4392,9 +4765,11 @@ void TemplateValueParameter::semantic(Scope *sc) #if 0 // defer semantic analysis to arg match if (specValue) - { Expression *e = specValue; - - e = e->ctfeSemantic(sc); + { + Expression *e = specValue; + sc = sc->startCTFE(); + e = e->semantic(sc); + sc = sc->endCTFE(); e = e->implicitCastTo(sc, valType); e = e->ctfeInterpret(); if (e->op == TOKint64 || e->op == TOKfloat64 || @@ -4404,9 +4779,11 @@ void TemplateValueParameter::semantic(Scope *sc) } if (defaultValue) - { Expression *e = defaultValue; - - e = e->ctfeSemantic(sc); + { + Expression *e = defaultValue; + sc = sc->startCTFE(); + e = e->semantic(sc); + sc = sc->endCTFE(); e = e->implicitCastTo(sc, valType); e = e->ctfeInterpret(); if (e->op == TOKint64) @@ -4438,34 +4815,15 @@ Lnomatch: return 0; } - -MATCH TemplateValueParameter::matchArg(Scope *sc, - Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, +MATCH TemplateValueParameter::matchArg(Scope *sc, RootObject *oarg, + size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam) { //printf("TemplateValueParameter::matchArg()\n"); - Initializer *init; - Declaration *sparam; MATCH m = MATCHexact; - Expression *ei; - Object *oarg; - if (i < tiargs->dim) - oarg = (*tiargs)[i]; - else - { // Get default argument instead - oarg = defaultArg(loc, sc); - if (!oarg) - { assert(i < dedtypes->dim); - // It might have already been deduced - oarg = (*dedtypes)[i]; - if (!oarg) - goto Lnomatch; - } - } - - ei = isExpression(oarg); + Expression *ei = isExpression(oarg); Type *vt; if (!ei && oarg) @@ -4478,6 +4836,11 @@ MATCH TemplateValueParameter::matchArg(Scope *sc, ei = ei->semantic(sc); if (!f->needThis()) ei = resolveProperties(sc, ei); + /* If it was really a property, it will become a CallExp. + * If it stayed as a var, it cannot be interpreted. + */ + if (ei->op == TOKvar) + goto Lnomatch; ei = ei->ctfeInterpret(); } else @@ -4490,7 +4853,7 @@ MATCH TemplateValueParameter::matchArg(Scope *sc, } //printf("\tvalType: %s, ty = %d\n", valType->toChars(), valType->ty); - vt = valType->semantic(Loc(), sc); + vt = valType->semantic(loc, sc); //printf("ei: %s, ei->type: %s\n", ei->toChars(), ei->type->toChars()); //printf("vt = %s\n", vt->toChars()); @@ -4500,6 +4863,11 @@ MATCH TemplateValueParameter::matchArg(Scope *sc, //printf("m: %d\n", m); if (!m) goto Lnomatch; + if (m != MATCHexact) + { + ei = ei->implicitCastTo(sc, vt); + ei = ei->ctfeInterpret(); + } } if (specValue) @@ -4509,13 +4877,17 @@ MATCH TemplateValueParameter::matchArg(Scope *sc, Expression *e = specValue; - e = e->ctfeSemantic(sc); + sc = sc->startCTFE(); + e = e->semantic(sc); e = resolveProperties(sc, e); + sc = sc->endCTFE(); e = e->implicitCastTo(sc, vt); e = e->ctfeInterpret(); ei = ei->syntaxCopy(); - ei = ei->ctfeSemantic(sc); + sc = sc->startCTFE(); + ei = ei->semantic(sc); + sc = sc->endCTFE(); ei = ei->implicitCastTo(sc, vt); ei = ei->ctfeInterpret(); //printf("\tei: %s, %s\n", ei->toChars(), ei->type->toChars()); @@ -4532,28 +4904,27 @@ MATCH TemplateValueParameter::matchArg(Scope *sc, if (!ei || !ei->equals(e)) goto Lnomatch; } - else if (m != MATCHexact) - { - ei = ei->implicitCastTo(sc, vt); - ei = ei->ctfeInterpret(); - } } (*dedtypes)[i] = ei; - init = new ExpInitializer(loc, ei); - sparam = new VarDeclaration(loc, vt, ident, init); - sparam->storage_class = STCmanifest; - *psparam = sparam; + if (psparam) + { + Initializer *init = new ExpInitializer(loc, ei); + Declaration *sparam = new VarDeclaration(loc, vt, ident, init); + sparam->storage_class = STCmanifest; + *psparam = sparam; + } return m; Lnomatch: //printf("\tno match\n"); - *psparam = NULL; + if (psparam) + *psparam = NULL; return MATCHnomatch; } -void TemplateValueParameter::print(Object *oarg, Object *oded) +void TemplateValueParameter::print(RootObject *oarg, RootObject *oded) { printf(" %s\n", ident->toChars()); @@ -4597,13 +4968,13 @@ void *TemplateValueParameter::dummyArg() } -Object *TemplateValueParameter::specialization() +RootObject *TemplateValueParameter::specialization() { return specValue; } -Object *TemplateValueParameter::defaultArg(Loc loc, Scope *sc) +RootObject *TemplateValueParameter::defaultArg(Loc loc, Scope *sc) { Expression *e = defaultValue; if (e) @@ -4647,7 +5018,7 @@ void TemplateTupleParameter::declareParameter(Scope *sc) error(loc, "parameter '%s' multiply defined", ident->toChars()); } -void TemplateTupleParameter::semantic(Scope *sc) +void TemplateTupleParameter::semantic(Scope *sc, TemplateParameters *parameters) { } @@ -4663,12 +5034,10 @@ int TemplateTupleParameter::overloadMatch(TemplateParameter *tp) return 0; } -MATCH TemplateTupleParameter::matchArg(Scope *sc, Objects *tiargs, +MATCH TemplateTupleParameter::matchArg(Loc loc, Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam) { - //printf("TemplateTupleParameter::matchArg()\n"); - /* The rest of the actual arguments (tiargs[]) form the match * for the variadic parameter. */ @@ -4692,13 +5061,26 @@ MATCH TemplateTupleParameter::matchArg(Scope *sc, Objects *tiargs, ovar->objects[j] = (*tiargs)[i + j]; } } - *psparam = new TupleDeclaration(loc, ident, &ovar->objects); + return matchArg(sc, ovar, i, parameters, dedtypes, psparam); +} + +MATCH TemplateTupleParameter::matchArg(Scope *sc, RootObject *oarg, + size_t i, TemplateParameters *parameters, Objects *dedtypes, + Declaration **psparam) +{ + //printf("TemplateTupleParameter::matchArg()\n"); + Tuple *ovar = isTuple(oarg); + if (!ovar) + return MATCHnomatch; (*dedtypes)[i] = ovar; + + if (psparam) + *psparam = new TupleDeclaration(loc, ident, &ovar->objects); return MATCHexact; } -void TemplateTupleParameter::print(Object *oarg, Object *oded) +void TemplateTupleParameter::print(RootObject *oarg, RootObject *oded) { printf(" %s... [", ident->toChars()); Tuple *v = isTuple(oded); @@ -4710,7 +5092,7 @@ void TemplateTupleParameter::print(Object *oarg, Object *oded) if (i) printf(", "); - Object *o = v->objects[i]; + RootObject *o = v->objects[i]; Dsymbol *sa = isDsymbol(o); if (sa) @@ -4743,13 +5125,13 @@ void *TemplateTupleParameter::dummyArg() } -Object *TemplateTupleParameter::specialization() +RootObject *TemplateTupleParameter::specialization() { return NULL; } -Object *TemplateTupleParameter::defaultArg(Loc loc, Scope *sc) +RootObject *TemplateTupleParameter::defaultArg(Loc loc, Scope *sc) { return NULL; } @@ -4766,21 +5148,23 @@ TemplateInstance::TemplateInstance(Loc loc, Identifier *ident) this->name = ident; this->tiargs = NULL; this->tempdecl = NULL; + this->instantiatingModule = NULL; this->inst = NULL; this->tinst = NULL; this->argsym = NULL; this->aliasdecl = NULL; - this->semanticRun = PASSinit; - this->semantictiargsdone = 0; + this->semantictiargsdone = false; this->withsym = NULL; this->nest = 0; - this->havetempdecl = 0; + this->havetempdecl = false; this->enclosing = NULL; - this->speculative = 0; - + this->speculative = false; + this->hash = 0; + this->fargs = NULL; #if IN_LLVM this->emittedInModule = NULL; #endif + } /***************** @@ -4798,17 +5182,19 @@ TemplateInstance::TemplateInstance(Loc loc, TemplateDeclaration *td, Objects *ti this->name = td->ident; this->tiargs = tiargs; this->tempdecl = td; + this->instantiatingModule = NULL; this->inst = NULL; this->tinst = NULL; this->argsym = NULL; this->aliasdecl = NULL; - this->semanticRun = PASSinit; - this->semantictiargsdone = 1; + this->semantictiargsdone = true; this->withsym = NULL; this->nest = 0; - this->havetempdecl = 1; + this->havetempdecl = true; this->enclosing = NULL; - this->speculative = 0; + this->speculative = false; + this->hash = 0; + this->fargs = NULL; #if IN_LLVM this->emittedInModule = NULL; @@ -4843,8 +5229,9 @@ Dsymbol *TemplateInstance::syntaxCopy(Dsymbol *s) ti->tiargs = arraySyntaxCopy(tiargs); - if (inst) - tempdecl->ScopeDsymbol::syntaxCopy(ti); + TemplateDeclaration *td; + if (inst && tempdecl && (td = tempdecl->isTemplateDeclaration()) != NULL) + td->ScopeDsymbol::syntaxCopy(ti); else ScopeDsymbol::syntaxCopy(ti); return ti; @@ -4946,6 +5333,28 @@ void TemplateInstance::trySemantic3(Scope *sc2) void TemplateInstance::semantic(Scope *sc, Expressions *fargs) { //printf("TemplateInstance::semantic('%s', this=%p, gag = %d, sc = %p)\n", toChars(), this, global.gag, sc); +#if 0 + for (Dsymbol *s = this; s; s = s->parent) + { + printf("\t%s\n", s->toChars()); + } + printf("Scope\n"); + for (Scope *scx = sc; scx; scx = scx->enclosing) + { + printf("\t%s parent %s instantiatingModule %p\n", scx->module ? scx->module->toChars() : "null", scx->parent ? scx->parent->toChars() : "null", scx->instantiatingModule); + } +#endif + + Module *mi = sc->instantiatingModule ? sc->instantiatingModule : sc->module; + + /* If a TemplateInstance is ever instantiated by non-root modules, + * we do not have to generate code for it, + * because it will be generated when the non-root module is compiled. + */ + if (!instantiatingModule || instantiatingModule->isRoot()) + instantiatingModule = mi; + //printf("mi = %s\n", mi->toChars()); + #if LOG printf("\n+TemplateInstance::semantic('%s', this=%p)\n", toChars(), this); #endif @@ -4974,36 +5383,20 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) #if LOG printf("\tdo semantic\n"); #endif - if (havetempdecl) + /* Find template declaration first, + * then run semantic on each argument (place results in tiargs[]), + * last find most specialized template from overload list/set. + */ + if (!findTemplateDeclaration(sc) || + !semanticTiargs(sc) || + !findBestMatch(sc, fargs)) { - assert(tempdecl->scope); - // Deduce tdtypes - tdtypes.setDim(tempdecl->parameters->dim); - if (!tempdecl->matchWithInstance(this, &tdtypes, fargs, 2)) - { - error("incompatible arguments for template instantiation"); - inst = this; - return; - } - } - else - { - /* Find template declaration first, - * then run semantic on each argument (place results in tiargs[]), - * last find most specialized template from overload list/set. - */ - if (!findTemplateDeclaration(sc) || - !semanticTiargs(sc) || - !findBestMatch(sc, fargs)) - { - if (!sc->parameterSpecialization) - inst = this; - //printf("error return %p, %d\n", tempdecl, global.errors); - if (inst) - inst->errors = true; - return; // error recovery - } + inst = this; + inst->errors = true; + return; // error recovery } + TemplateDeclaration *tempdecl = this->tempdecl->isTemplateDeclaration(); + assert(tempdecl); // If tempdecl is a mixin, disallow it if (tempdecl->ismixin) @@ -5011,88 +5404,47 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) hasNestedArgs(tiargs); + arrayCheckRecursiveExpansion(&tdtypes, tempdecl, sc); + /* See if there is an existing TemplateInstantiation that already * implements the typeargs. If so, just refer to that one instead. */ - - for (size_t i = 0; i < tempdecl->instances.dim; i++) { - TemplateInstance *ti = tempdecl->instances[i]; -#if LOG - printf("\t%s: checking for match with instance %d (%p): '%s'\n", toChars(), i, ti, ti->toChars()); -#endif - assert(tdtypes.dim == ti->tdtypes.dim); - - // Nesting must match - if (enclosing != ti->enclosing) + TemplateInstance *ti = tempdecl->findExistingInstance(this, fargs); + if (ti) { - //printf("test2 enclosing %s ti->enclosing %s\n", enclosing ? enclosing->toChars() : "", ti->enclosing ? ti->enclosing->toChars() : ""); - continue; - } - //printf("parent = %s, ti->parent = %s\n", tempdecl->parent->toPrettyChars(), ti->parent->toPrettyChars()); + // It's a match + inst = ti; + parent = ti->parent; - if (!arrayObjectMatch(&tdtypes, &ti->tdtypes, tempdecl, sc)) - goto L1; - - /* Template functions may have different instantiations based on - * "auto ref" parameters. - */ - if (fargs) - { - FuncDeclaration *fd = ti->toAlias()->isFuncDeclaration(); - if (fd) + // If both this and the previous instantiation were speculative, + // use the number of errors that happened last time. + if (inst->speculative && global.gag) { - Parameters *fparameters = fd->getParameters(NULL); - size_t nfparams = Parameter::dim(fparameters); // Num function parameters - for (size_t j = 0; j < nfparams && j < fargs->dim; j++) - { Parameter *fparam = Parameter::getNth(fparameters, j); - Expression *farg = (*fargs)[j]; - if (fparam->storageClass & STCauto) // if "auto ref" - { - if (farg->isLvalue()) - { if (!(fparam->storageClass & STCref)) - goto L1; // auto ref's don't match - } - else - { if (fparam->storageClass & STCref) - goto L1; // auto ref's don't match - } - } - } + global.errors += inst->errors; + global.gaggedErrors += inst->errors; } - } - // It's a match - inst = ti; - parent = ti->parent; - - // If both this and the previous instantiation were speculative, - // use the number of errors that happened last time. - if (inst->speculative && global.gag) - { - global.errors += inst->errors; - global.gaggedErrors += inst->errors; - } - - // If the first instantiation was speculative, but this is not: - if (inst->speculative && !global.gag) - { - // If the first instantiation had failed, re-run semantic, - // so that error messages are shown. - if (inst->errors) - goto L1; - // It had succeeded, mark it is a non-speculative instantiation, - // and reuse it. - inst->speculative = 0; - } + // If the first instantiation was speculative, but this is not: + if (inst->speculative && !global.gag) + { + // If the first instantiation had failed, re-run semantic, + // so that error messages are shown. + if (inst->errors) + goto L1; + // It had succeeded, mark it is a non-speculative instantiation, + // and reuse it. + inst->speculative = 0; + } #if LOG - printf("\tit's a match with instance %p, %d\n", inst, inst->semanticRun); + printf("\tit's a match with instance %p, %d\n", inst, inst->semanticRun); #endif - return; - - L1: - ; + if (!inst->instantiatingModule || inst->instantiatingModule->isRoot()) + inst->instantiatingModule = mi; + return; + } + L1: ; } /* So, we need to implement 'this' instance. @@ -5107,29 +5459,21 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) if (global.gag && sc->speculative) speculative = 1; - size_t tempdecl_instance_idx = tempdecl->instances.dim; - tempdecl->instances.push(this); - parent = tempdecl->parent; + TemplateInstance *tempdecl_instance_idx = tempdecl->addInstance(this); + + parent = enclosing ? enclosing : tempdecl->parent; //printf("parent = '%s'\n", parent->kind()); - ident = genIdent(tiargs); // need an identifier for name mangling purposes. - -#if 1 - if (enclosing) - parent = enclosing; -#endif - //printf("parent = '%s'\n", parent->kind()); + //getIdent(); // Add 'this' to the enclosing scope's members[] so the semantic routines // will get called on the instance members. Store the place we added it to // in target_symbol_list(_idx) so we can remove it later if we encounter // an error. #if 1 - int dosemantic3 = 0; Dsymbols *target_symbol_list = NULL; size_t target_symbol_list_idx; - if (!sc->parameterSpecialization) { Dsymbols *a; Scope *scx = sc; @@ -5140,8 +5484,8 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) #endif //if (scx && scx->scopesym) printf("3: scx is %s %s\n", scx->scopesym->kind(), scx->scopesym->toChars()); - if (scx && scx->scopesym && - scx->scopesym->members && !scx->scopesym->isTemplateMixin() + if (scx && scx->scopesym && scx->scopesym->members && + !scx->scopesym->isTemplateMixin() #if 0 // removed because it bloated compile times /* The problem is if A imports B, and B imports A, and both A * and B instantiate the same template, does the compilation of A @@ -5153,18 +5497,43 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) #endif ) { + /* A module can have explicit template instance and its alias + * in module scope (e,g, `alias Base64Impl!('+', '/') Base64;`). + * When the module is just imported, compiler can assume that + * its instantiated code would be contained in the separately compiled + * obj/lib file (e.g. phobos.lib). So we can omit their semantic3 running. + */ + //if (scx->scopesym->isModule()) + // printf("module level instance %s\n", toChars()); + //printf("\t1: adding to %s %s\n", scx->scopesym->kind(), scx->scopesym->toChars()); a = scx->scopesym->members; } else { - Module *m = (enclosing ? sc : tempdecl->scope)->module->importedFrom; + Dsymbol *s = enclosing ? enclosing : tempdecl->parent; + for (; s; s = s->toParent2()) + { + if (s->isModule()) + break; + } + assert(s); + Module *m = (Module *)s; + if (!m->isRoot()) + { + //if (tinst && tinst->objFileModule) + // m = tinst->objFileModule; + //else + m = m->importedFrom; + } //printf("\t2: adding to module %s instead of module %s\n", m->toChars(), sc->module->toChars()); a = m->members; - if (m->semanticRun >= 3) - { - dosemantic3 = 1; - } + + /* Defer semantic3 running in order to avoid mutual forward reference. + * See test/runnable/test10736.d + */ + if (m->semanticRun >= PASSsemantic3done) + Module::addDeferredSemantic3(this); } for (size_t i = 0; 1; i++) { @@ -5220,7 +5589,7 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) // Create our own scope for the template parameters Scope *scope = tempdecl->scope; - if (!tempdecl->semanticRun) + if (tempdecl->semanticRun == PASSinit) { error("template instantiation %s forward references template declaration %s", toChars(), tempdecl->toChars()); return; @@ -5232,6 +5601,7 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) argsym = new ScopeDsymbol(); argsym->parent = scope->parent; scope = scope->push(argsym); + scope->instantiatingModule = mi; // scope->stc = 0; // Declare each template parameter as an alias for the argument type @@ -5321,8 +5691,8 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) */ bool found_deferred_ad = false; for (size_t i = 0; i < Module::deferred.dim; i++) - { Dsymbol *sd = Module::deferred[i]; - + { + Dsymbol *sd = Module::deferred[i]; AggregateDeclaration *ad = sd->isAggregateDeclaration(); if (ad && ad->parent && ad->parent->isTemplateInstance()) { @@ -5336,7 +5706,7 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) } } } - if (found_deferred_ad) + if (found_deferred_ad || Module::deferred.dim) goto Laftersemantic; /* ConditionalDeclaration may introduce eponymous declaration, @@ -5365,14 +5735,15 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) * for initializers inside a function. */ // if (sc->parent->isFuncDeclaration()) - + { /* BUG 782: this has problems if the classes this depends on * are forward referenced. Find a way to defer semantic() * on this template. */ semantic2(sc2); + } - if (sc->func || dosemantic3) + if (sc->func) { trySemantic3(sc2); } @@ -5389,14 +5760,14 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) if (tinst) { tinst->printInstantiationTrace(); } - errors = 1; + errors = true; if (global.gag) { // Errors are gagged, so remove the template instance from the // instance/symbol lists we added it to and reset our state to // finish clean and so we can try to instantiate it again later // (see bugzilla 4302 and 6602). - tempdecl->instances.remove(tempdecl_instance_idx); + tempdecl->removeInstance(tempdecl_instance_idx); if (target_symbol_list) { // Because we added 'this' in the last position above, we @@ -5415,6 +5786,199 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) } +/********************************************** + * Find template declaration corresponding to template instance. + */ + +bool TemplateInstance::findTemplateDeclaration(Scope *sc) +{ + if (havetempdecl) + return true; + + //printf("TemplateInstance::findTemplateDeclaration() %s\n", toChars()); + if (!tempdecl) + { + /* Given: + * foo!( ... ) + * figure out which TemplateDeclaration foo refers to. + */ + Identifier *id = name; + Dsymbol *scopesym; + Dsymbol *s = sc->search(loc, id, &scopesym); + if (!s) + { + s = sc->search_correct(id); + if (s) + error("template '%s' is not defined, did you mean %s?", id->toChars(), s->toChars()); + else + error("template '%s' is not defined", id->toChars()); + return false; + } + +#if LOG + printf("It's an instance of '%s' kind '%s'\n", s->toChars(), s->kind()); + if (s->parent) + printf("s->parent = '%s'\n", s->parent->toChars()); +#endif + withsym = scopesym->isWithScopeSymbol(); + + /* We might have found an alias within a template when + * we really want the template. + */ + TemplateInstance *ti; + if (s->parent && + (ti = s->parent->isTemplateInstance()) != NULL) + { + if (ti->tempdecl && ti->tempdecl->ident == id) + { + /* This is so that one can refer to the enclosing + * template, even if it has the same name as a member + * of the template, if it has a !(arguments) + */ + TemplateDeclaration *td = ti->tempdecl->isTemplateDeclaration(); + assert(td); + if (td->overroot) // if not start of overloaded list of TemplateDeclaration's + td = td->overroot; // then get the start + s = td; + } + } + + if (!updateTemplateDeclaration(sc, s)) + { + return false; + } + } + assert(tempdecl); + + struct ParamFwdTi + { + static int fp(void *param, Dsymbol *s) + { + TemplateDeclaration *td = s->isTemplateDeclaration(); + if (!td) + return 0; + + TemplateInstance *ti = (TemplateInstance *)param; + if (td->semanticRun == PASSinit) + { + if (td->scope) + { + // Try to fix forward reference. Ungag errors while doing so. + Ungag ungag = td->ungagSpeculative(); + td->semantic(td->scope); + } + if (td->semanticRun == PASSinit) + { + ti->error("%s forward references template declaration %s", ti->toChars(), td->toChars()); + return 1; + } + } + return 0; + } + }; + // Look for forward references + OverloadSet *tovers = tempdecl->isOverloadSet(); + size_t overs_dim = tovers ? tovers->a.dim : 1; + for (size_t oi = 0; oi < overs_dim; oi++) + { + if (overloadApply(tovers ? tovers->a[oi] : tempdecl, (void *)this, &ParamFwdTi::fp)) + return false; + } + return true; +} + +/********************************************** + * Confirm s is a valid template, then store it. + */ + +bool TemplateInstance::updateTemplateDeclaration(Scope *sc, Dsymbol *s) +{ + if (s) + { + Identifier *id = name; + s = s->toAlias(); + + /* If an OverloadSet, look for a unique member that is a template declaration + */ + OverloadSet *os = s->isOverloadSet(); + if (os) + { + s = NULL; + for (size_t i = 0; i < os->a.dim; i++) + { + Dsymbol *s2 = os->a[i]; + if (FuncDeclaration *f = s2->isFuncDeclaration()) + s2 = f->findTemplateDeclRoot(); + else + s2 = s2->isTemplateDeclaration(); + if (s2) + { + if (s) + { + tempdecl = os; + return true; + } + s = s2; + } + } + if (!s) + { + error("template '%s' is not defined", id->toChars()); + return false; + } + } + + /* It should be a TemplateDeclaration, not some other symbol + */ + if (FuncDeclaration *f = s->isFuncDeclaration()) + tempdecl = f->findTemplateDeclRoot(); + else + tempdecl = s->isTemplateDeclaration(); + if (!tempdecl) + { + if (!s->parent && global.errors) + return false; + if (!s->parent && s->getType()) + { + Dsymbol *s2 = s->getType()->toDsymbol(sc); + if (!s2) + { + error("%s is not a template declaration, it is a %s", id->toChars(), s->kind()); + return false; + } + s = s2; + } +#ifdef DEBUG + //if (!s->parent) printf("s = %s %s\n", s->kind(), s->toChars()); +#endif + //assert(s->parent); + TemplateInstance *ti = s->parent ? s->parent->isTemplateInstance() : NULL; + if (ti && + (ti->name == s->ident || + ti->toAlias()->ident == s->ident) + && + ti->tempdecl) + { + /* This is so that one can refer to the enclosing + * template, even if it has the same name as a member + * of the template, if it has a !(arguments) + */ + TemplateDeclaration *td = ti->tempdecl->isTemplateDeclaration(); + assert(td); + if (td->overroot) // if not start of overloaded list of TemplateDeclaration's + td = td->overroot; // then get the start + tempdecl = td; + } + else + { + error("%s is not a template declaration, it is a %s", id->toChars(), s->kind()); + return false; + } + } + } + return (tempdecl != NULL); +} + bool TemplateInstance::semanticTiargs(Scope *sc) { //printf("+TemplateInstance::semanticTiargs() %s\n", toChars()); @@ -5425,6 +5989,62 @@ bool TemplateInstance::semanticTiargs(Scope *sc) return arrayObjectIsError(tiargs) == 0; } +/********************************** + * Return true if e could be valid only as a template value parameter. + * Return false if it might be an alias or tuple. + * (Note that even in this case, it could still turn out to be a value). + */ +bool definitelyValueParameter(Expression *e) +{ + // None of these can be value parameters + if (e->op == TOKtuple || e->op == TOKimport || + e->op == TOKtype || e->op == TOKdottype || + e->op == TOKtemplate || e->op == TOKdottd || + e->op == TOKfunction || e->op == TOKerror || + e->op == TOKthis || e->op == TOKsuper) + return false; + + if (e->op != TOKdotvar) + return true; + + /* Template instantiations involving a DotVar expression are difficult. + * In most cases, they should be treated as a value parameter, and interpreted. + * But they might also just be a fully qualified name, which should be treated + * as an alias. + */ + + // x.y.f cannot be a value + FuncDeclaration *f = ((DotVarExp *)e)->var->isFuncDeclaration(); + if (f) + return false; + + while (e->op == TOKdotvar) + { + e = ((DotVarExp *)e)->e1; + } + // this.x.y and super.x.y couldn't possibly be valid values. + if (e->op == TOKthis || e->op == TOKsuper) + return false; + + // e.type.x could be an alias + if (e->op == TOKdottype) + return false; + + // var.x.y is the only other possible form of alias + if (e->op != TOKvar) + return true; + + VarDeclaration *v = ((VarExp *)e)->var->isVarDeclaration(); + + // func.x.y is not an alias + if (!v) + return true; + + // TODO: Should we force CTFE if it is a global constant? + + return false; +} + /********************************** * Input: * flags 1: replace const variables with their initializers @@ -5439,7 +6059,7 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f return; for (size_t j = 0; j < tiargs->dim; j++) { - Object *o = (*tiargs)[j]; + RootObject *o = (*tiargs)[j]; Type *ta = isType(o); Expression *ea = isExpression(o); Dsymbol *sa = isDsymbol(o); @@ -5477,16 +6097,15 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f j--; continue; } - (*tiargs)[j] = ta; + (*tiargs)[j] = ta->merge2(); } else if (ea) { Lexpr: //printf("+[%d] ea = %s %s\n", j, Token::toChars(ea->op), ea->toChars()); - if (flags & 1) - ea = ea->semantic(sc); - else - ea = ea->ctfeSemantic(sc); + if (!(flags & 1)) sc = sc->startCTFE(); + ea = ea->semantic(sc); + if (!(flags & 1)) sc = sc->endCTFE(); if (flags & 1) // only used by __traits, must not interpret the args { VarDeclaration *v; @@ -5509,10 +6128,7 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f * const substitution in TemplateValueParameter::matchArg(). */ } - else if (ea->op != TOKtuple && - ea->op != TOKimport && ea->op != TOKtype && - ea->op != TOKfunction && ea->op != TOKerror && - ea->op != TOKthis && ea->op != TOKsuper) + else if (definitelyValueParameter(ea)) { int olderrs = global.errors; ea = ea->ctfeInterpret(); @@ -5561,8 +6177,8 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f else if (fe->td) { /* If template argument is a template lambda, * get template declaration itself. */ - sa = fe->td; - goto Ldsym; + //sa = fe->td; + //goto Ldsym; } } if (ea->op == TOKdotvar) @@ -5597,10 +6213,20 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f j--; continue; } + if (FuncAliasDeclaration *fa = sa->isFuncAliasDeclaration()) + { + FuncDeclaration *f = fa->toAliasFunc(); + if (!fa->hasOverloads && f->isUnique()) + { + // Strip FuncAlias only when the aliased function + // does not have any overloads. + sa = f; + } + } (*tiargs)[j] = sa; TemplateDeclaration *td = sa->isTemplateDeclaration(); - if (td && !td->semanticRun && td->literal) + if (td && td->semanticRun == PASSinit && td->literal) { td->semantic(sc); } @@ -5621,7 +6247,7 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f printf("-TemplateInstance::semanticTiargs()\n"); for (size_t j = 0; j < tiargs->dim; j++) { - Object *o = (*tiargs)[j]; + RootObject *o = (*tiargs)[j]; Type *ta = isType(o); Expression *ea = isExpression(o); Dsymbol *sa = isDsymbol(o); @@ -5632,273 +6258,310 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f #endif } -/********************************************** - * Find template declaration corresponding to template instance. - */ - -bool TemplateInstance::findTemplateDeclaration(Scope *sc) -{ - //printf("TemplateInstance::findTemplateDeclaration() %s\n", toChars()); - if (!tempdecl) - { - /* Given: - * foo!( ... ) - * figure out which TemplateDeclaration foo refers to. - */ - Dsymbol *s; - Dsymbol *scopesym; - Identifier *id; - - id = name; - s = sc->search(loc, id, &scopesym); - if (!s) - { - s = sc->search_correct(id); - if (s) - error("template '%s' is not defined, did you mean %s?", id->toChars(), s->toChars()); - else - error("template '%s' is not defined", id->toChars()); - return false; - } - - /* If an OverloadSet, look for a unique member that is a template declaration - */ - OverloadSet *os = s->isOverloadSet(); - if (os) - { s = NULL; - for (size_t i = 0; i < os->a.dim; i++) - { Dsymbol *s2 = os->a[i]; - if (s2->isTemplateDeclaration()) - { - if (s) - error("ambiguous template declaration %s and %s", s->toPrettyChars(), s2->toPrettyChars()); - s = s2; - } - } - if (!s) - { error("template '%s' is not defined", id->toChars()); - return false; - } - } - -#if LOG - printf("It's an instance of '%s' kind '%s'\n", s->toChars(), s->kind()); - if (s->parent) - printf("s->parent = '%s'\n", s->parent->toChars()); -#endif - withsym = scopesym->isWithScopeSymbol(); - - /* We might have found an alias within a template when - * we really want the template. - */ - TemplateInstance *ti; - if (s->parent && - (ti = s->parent->isTemplateInstance()) != NULL) - { - if (ti->tempdecl && ti->tempdecl->ident == id) - { - /* This is so that one can refer to the enclosing - * template, even if it has the same name as a member - * of the template, if it has a !(arguments) - */ - tempdecl = ti->tempdecl; - if (tempdecl->overroot) // if not start of overloaded list of TemplateDeclaration's - tempdecl = tempdecl->overroot; // then get the start - s = tempdecl; - } - } - - s = s->toAlias(); - - /* It should be a TemplateDeclaration, not some other symbol - */ - tempdecl = s->isTemplateDeclaration(); - if (!tempdecl) - { - if (!s->parent && global.errors) - return false; - if (!s->parent && s->getType()) - { Dsymbol *s2 = s->getType()->toDsymbol(sc); - if (!s2) - { - error("%s is not a template declaration, it is a %s", id->toChars(), s->kind()); - return false; - } - s = s2; - } -#ifdef DEBUG - //if (!s->parent) printf("s = %s %s\n", s->kind(), s->toChars()); -#endif - //assert(s->parent); - TemplateInstance *ti = s->parent ? s->parent->isTemplateInstance() : NULL; - if (ti && - (ti->name == id || - ti->toAlias()->ident == id) - && - ti->tempdecl) - { - /* This is so that one can refer to the enclosing - * template, even if it has the same name as a member - * of the template, if it has a !(arguments) - */ - tempdecl = ti->tempdecl; - if (tempdecl->overroot) // if not start of overloaded list of TemplateDeclaration's - tempdecl = tempdecl->overroot; // then get the start - } - else - { - error("%s is not a template declaration, it is a %s", id->toChars(), s->kind()); - return false; - } - } - } - else - assert(tempdecl->isTemplateDeclaration()); - return (tempdecl != NULL); -} - bool TemplateInstance::findBestMatch(Scope *sc, Expressions *fargs) { - /* Since there can be multiple TemplateDeclaration's with the same - * name, look for the best match. - */ - TemplateDeclaration *td_ambig = NULL; - TemplateDeclaration *td_best = NULL; - MATCH m_best = MATCHnomatch; - Objects dedtypes; - unsigned errs = global.errors; + if (havetempdecl) + { + TemplateDeclaration *tempdecl = this->tempdecl->isTemplateDeclaration(); + assert(tempdecl); + assert(tempdecl->scope); + // Deduce tdtypes + tdtypes.setDim(tempdecl->parameters->dim); + if (!tempdecl->matchWithInstance(sc, this, &tdtypes, fargs, 2)) + { + error("incompatible arguments for template instantiation"); + return false; + } + return true; + } #if LOG printf("TemplateInstance::findBestMatch()\n"); #endif - // First look for forward references - for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) + unsigned errs = global.errors; + + struct ParamBest + { + // context + Scope *sc; + TemplateInstance *ti; + Objects dedtypes; + // result + TemplateDeclaration *td_best; + TemplateDeclaration *td_ambig; + MATCH m_best; + + static int fp(void *param, Dsymbol *s) { - if (!td->semanticRun) - { - if (td->scope) - { // Try to fix forward reference. Ungag errors while doing so. - int oldgag = global.gag; - if (global.isSpeculativeGagging() && !td->isSpeculative()) - global.gag = 0; - - td->semantic(td->scope); - - global.gag = oldgag; - } - if (!td->semanticRun) - { - error("%s forward references template declaration %s", toChars(), td->toChars()); - return false; - } - } + return ((ParamBest *)param)->fp(s); } - - for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) + int fp(Dsymbol *s) { - MATCH m; + TemplateDeclaration *td = s->isTemplateDeclaration(); + if (!td) + return 0; -//if (tiargs->dim) printf("2: tiargs->dim = %d, data[0] = %p\n", tiargs->dim, (*tiargs)[0]); + if (td == td_best) // skip duplicates + return 0; + + //printf("td = %s\n", td->toPrettyChars()); // If more arguments than parameters, // then this is no match. - if (td->parameters->dim < tiargs->dim) + if (td->parameters->dim < ti->tiargs->dim) { if (!td->isVariadic()) - continue; + return 0; } dedtypes.setDim(td->parameters->dim); dedtypes.zero(); - assert(td->semanticRun); - m = td->matchWithInstance(this, &dedtypes, fargs, 0); + assert(td->semanticRun != PASSinit); + MATCH m = td->matchWithInstance(sc, ti, &dedtypes, ti->fargs, 0); //printf("matchWithInstance = %d\n", m); if (!m) // no match at all - continue; + return 0; - if (m < m_best) - goto Ltd_best; - if (m > m_best) - goto Ltd; + if (m < m_best) goto Ltd_best; + if (m > m_best) goto Ltd; { // Disambiguate by picking the most specialized TemplateDeclaration - MATCH c1 = td->leastAsSpecialized(td_best, fargs); - MATCH c2 = td_best->leastAsSpecialized(td, fargs); + MATCH c1 = td->leastAsSpecialized(sc, td_best, ti->fargs); + MATCH c2 = td_best->leastAsSpecialized(sc, td, ti->fargs); //printf("c1 = %d, c2 = %d\n", c1, c2); - - if (c1 > c2) - goto Ltd; - else if (c1 < c2) - goto Ltd_best; - else - goto Lambig; + if (c1 > c2) goto Ltd; + if (c1 < c2) goto Ltd_best; } Lambig: // td_best and td are ambiguous td_ambig = td; - continue; + return 0; Ltd_best: // td_best is the best match so far td_ambig = NULL; - continue; + return 0; Ltd: // td is the new best match td_ambig = NULL; td_best = td; m_best = m; - tdtypes.setDim(dedtypes.dim); - memcpy(tdtypes.tdata(), dedtypes.tdata(), tdtypes.dim * sizeof(void *)); - continue; + ti->tdtypes.setDim(dedtypes.dim); + memcpy(ti->tdtypes.tdata(), dedtypes.tdata(), ti->tdtypes.dim * sizeof(void *)); + return 0; } + }; + ParamBest p; + // context + p.ti = this; + p.sc = sc; - if (!td_best) - { - if (errs != global.errors) - errorSupplemental(loc, "while looking for match for %s", toChars()); - else if (tempdecl && !tempdecl->overnext) - // Only one template, so we can give better error message - error("does not match template declaration %s", tempdecl->toChars()); - else - ::error(loc, "%s %s.%s does not match any template declaration", - tempdecl->kind(), tempdecl->parent->toPrettyChars(), tempdecl->ident->toChars()); - return false; - } - if (td_ambig) - { - ::error(loc, "%s %s.%s matches more than one template declaration, %s(%d):%s and %s(%d):%s", - td_best->kind(), td_best->parent->toPrettyChars(), td_best->ident->toChars(), - td_best->loc.filename, td_best->loc.linnum, td_best->toChars(), - td_ambig->loc.filename, td_ambig->loc.linnum, td_ambig->toChars()); - } - - /* The best match is td_best + /* Since there can be multiple TemplateDeclaration's with the same + * name, look for the best match. */ - tempdecl = td_best; + TemplateDeclaration *td_last = NULL; -#if 0 - /* Cast any value arguments to be same type as value parameter - */ - for (size_t i = 0; i < tiargs->dim; i++) - { Object *o = (*tiargs)[i]; - Expression *ea = isExpression(o); // value argument - TemplateParameter *tp = (*tempdecl->parameters)[i]; - assert(tp); - TemplateValueParameter *tvp = tp->isTemplateValueParameter(); - if (tvp) + OverloadSet *tovers = tempdecl->isOverloadSet(); + size_t overs_dim = tovers ? tovers->a.dim : 1; + for (size_t oi = 0; oi < overs_dim; oi++) + { + // result + p.td_best = NULL; + p.td_ambig = NULL; + p.m_best = MATCHnomatch; + overloadApply(tovers ? tovers->a[oi] : tempdecl, &p, &ParamBest::fp); + + if (p.td_ambig) { - assert(ea); - ea = ea->castTo(tvp->valType); - ea = ea->ctfeInterpret(); - (*tiargs)[i] = (Object *)ea; + ::error(loc, "%s %s.%s matches more than one template declaration:\n\t%s(%d):%s\nand\n\t%s(%d):%s", + p.td_best->kind(), p.td_best->parent->toPrettyChars(), p.td_best->ident->toChars(), + p.td_best->loc.filename, p.td_best->loc.linnum, p.td_best->toChars(), + p.td_ambig->loc.filename, p.td_ambig->loc.linnum, p.td_ambig->toChars()); + return false; + } + if (p.td_best) + { + if (!td_last) + td_last = p.td_best; + else if (td_last != p.td_best) + { + ScopeDsymbol::multiplyDefined(loc, td_last, p.td_best); + return false; + } } } -#endif + + if (!td_last) + { + TemplateDeclaration *tdecl = tempdecl->isTemplateDeclaration(); + + if (errs != global.errors) + errorSupplemental(loc, "while looking for match for %s", toChars()); + else if (tovers) + error("does not match template overload set %s", tovers->toChars()); + else if (tdecl && !tdecl->overnext) + // Only one template, so we can give better error message + error("does not match template declaration %s", tdecl->toChars()); + else + ::error(loc, "%s %s.%s does not match any template declaration", + tdecl->kind(), tdecl->parent->toPrettyChars(), tdecl->ident->toChars()); + return false; + } + + /* The best match is td_last + */ + tempdecl = td_last; #if LOG printf("\tIt's a match with template declaration '%s'\n", tempdecl->toChars()); #endif - return (errs == global.errors) && tempdecl; + return (errs == global.errors); +} + +/***************************************************** + * Determine if template instance is really a template function, + * and that template function needs to infer types from the function + * arguments. + * + * Like findBestMatch, iterate possible template candidates, + * but just looks only the necessity of type inference. + */ + +bool TemplateInstance::needsTypeInference(Scope *sc, int flag) +{ + //printf("TemplateInstance::needsTypeInference() %s\n", toChars()); + + struct ParamNeedsInf + { + // context + Scope *sc; + TemplateInstance *ti; + int flag; + // result + Objects dedtypes; + size_t count; + + static int fp(void *param, Dsymbol *s) + { + return ((ParamNeedsInf *)param)->fp(s); + } + int fp(Dsymbol *s) + { + TemplateDeclaration *td = s->isTemplateDeclaration(); + if (!td) + { + Lcontinue: + return 0; + } + + /* If any of the overloaded template declarations need inference, + * then return true + */ + FuncDeclaration *fd; + if (!td->onemember) + return 0; + if (TemplateDeclaration *td2 = td->onemember->isTemplateDeclaration()) + { + if (!td2->onemember || !td2->onemember->isFuncDeclaration()) + return 0; + if (ti->tiargs->dim > td->parameters->dim && !td->isVariadic()) + return 0; + return 1; + } + if ((fd = td->onemember->isFuncDeclaration()) == NULL || + fd->type->ty != Tfunction) + { + return 0; + } + + for (size_t i = 0; i < td->parameters->dim; i++) + { + if ((*td->parameters)[i]->isTemplateThisParameter()) + return 1; + } + + /* Determine if the instance arguments, tiargs, are all that is necessary + * to instantiate the template. + */ + //printf("tp = %p, td->parameters->dim = %d, tiargs->dim = %d\n", tp, td->parameters->dim, ti->tiargs->dim); + TypeFunction *tf = (TypeFunction *)fd->type; + if (size_t dim = Parameter::dim(tf->parameters)) + { + TemplateParameter *tp = td->isVariadic(); + if (tp && td->parameters->dim > 1) + return 1; + + if (ti->tiargs->dim < td->parameters->dim) + { + // Can remain tiargs be filled by default arguments? + for (size_t i = ti->tiargs->dim; i < td->parameters->dim; i++) + { + tp = (*td->parameters)[i]; + if (TemplateTypeParameter *ttp = tp->isTemplateTypeParameter()) + { + if (!ttp->defaultType) + return 1; + } + else if (TemplateAliasParameter *tap = tp->isTemplateAliasParameter()) + { + if (!tap->defaultAlias) + return 1; + } + else if (TemplateValueParameter *tvp = tp->isTemplateValueParameter()) + { + if (!tvp->defaultValue) + return 1; + } + } + } + + for (size_t i = 0; i < dim; i++) + { + // 'auto ref' needs inference. + if (Parameter::getNth(tf->parameters, i)->storageClass & STCauto) + return 1; + } + } + + if (!flag) + { + /* Calculate the need for overload resolution. + * When only one template can match with tiargs, inference is not necessary. + */ + dedtypes.setDim(td->parameters->dim); + dedtypes.zero(); + assert(td->semanticRun != PASSinit); + MATCH m = td->matchWithInstance(sc, ti, &dedtypes, NULL, 0); + if (m == MATCHnomatch) + return 0; + } + + /* If there is more than one function template which matches, we may + * need type inference (see Bugzilla 4430) + */ + if (++count > 1) + return 1; + + return 0; + } + }; + ParamNeedsInf p; + // context + p.ti = this; + p.sc = sc; + p.flag = flag; + // result + p.count = 0; + + OverloadSet *tovers = tempdecl->isOverloadSet(); + size_t overs_dim = tovers ? tovers->a.dim : 1; + for (size_t oi = 0; oi < overs_dim; oi++) + { + if (int r = overloadApply(tovers ? tovers->a[oi] : tempdecl, &p, &ParamNeedsInf::fp)) + return true; + } + //printf("false\n"); + return false; } @@ -5908,15 +6571,17 @@ bool TemplateInstance::findBestMatch(Scope *sc, Expressions *fargs) * Sets enclosing property if so, and returns != 0; */ -int TemplateInstance::hasNestedArgs(Objects *args) -{ int nested = 0; +bool TemplateInstance::hasNestedArgs(Objects *args) +{ + int nested = 0; //printf("TemplateInstance::hasNestedArgs('%s')\n", tempdecl->ident->toChars()); /* A nested instance happens when an argument references a local * symbol that is on the stack. */ for (size_t i = 0; i < args->dim; i++) - { Object *o = (*args)[i]; + { + RootObject *o = (*args)[i]; Expression *ea = isExpression(o); Dsymbol *sa = isDsymbol(o); Tuple *va = isTuple(o); @@ -5958,15 +6623,35 @@ int TemplateInstance::hasNestedArgs(Objects *args) sa = ((FuncExp *)ea)->fd; goto Lsa; } + // Emulate Expression::toMangleBuffer call that had exist in TemplateInstance::genIdent. + if (ea->op != TOKint64 && // IntegerExp + ea->op != TOKfloat64 && // RealExp + ea->op != TOKcomplex80 && // CompexExp + ea->op != TOKnull && // NullExp + ea->op != TOKstring && // StringExp + ea->op != TOKarrayliteral && // ArrayLiteralExp + ea->op != TOKassocarrayliteral && // AssocArrayLiteralExp + ea->op != TOKstructliteral) // StructLiteralExp + { + ea->error("expression %s is not a valid template value argument", ea->toChars()); + } } else if (sa) { Lsa: sa = sa->toAlias(); TemplateDeclaration *td = sa->isTemplateDeclaration(); + if (td) + { + TemplateInstance *ti = sa->toParent()->isTemplateInstance(); + if (ti && ti->enclosing) + sa = ti; + } + TemplateInstance *ti = sa->isTemplateInstance(); AggregateDeclaration *ad = sa->isAggregateDeclaration(); Declaration *d = sa->isDeclaration(); if ((td && td->literal) || + (ti && ti->enclosing) || #if FIXBUG8863 (ad && ad->isNested()) || #endif @@ -5980,7 +6665,8 @@ int TemplateInstance::hasNestedArgs(Objects *args) { // if module level template if (tempdecl->toParent()->isModule()) - { Dsymbol *dparent = sa->toParent2(); + { + Dsymbol *dparent = sa->toParent2(); if (!enclosing) enclosing = dparent; else if (enclosing != dparent) @@ -6017,7 +6703,7 @@ int TemplateInstance::hasNestedArgs(Objects *args) } } //printf("-TemplateInstance::hasNestedArgs('%s') = %d\n", tempdecl->ident->toChars(), nested); - return nested; + return nested != 0; } /**************************************** @@ -6027,13 +6713,16 @@ int TemplateInstance::hasNestedArgs(Objects *args) */ Identifier *TemplateInstance::genIdent(Objects *args) -{ OutBuffer buf; +{ + assert(tempdecl); //printf("TemplateInstance::genIdent('%s')\n", tempdecl->ident->toChars()); + OutBuffer buf; char *id = tempdecl->ident->toChars(); buf.printf("__T%llu%s", (ulonglong)strlen(id), id); for (size_t i = 0; i < args->dim; i++) - { Object *o = (*args)[i]; + { + RootObject *o = (*args)[i]; Type *ta = isType(o); Expression *ea = isExpression(o); Dsymbol *sa = isDsymbol(o); @@ -6108,14 +6797,8 @@ Identifier *TemplateInstance::genIdent(Objects *args) buf.writeByte('S'); sa = sa->toAlias(); Declaration *d = sa->isDeclaration(); - Lsa2: if (d && (!d->type || !d->type->deco)) { - FuncAliasDeclaration *fad = d->isFuncAliasDeclaration(); - if (fad) - { d = fad->toAliasFunc(); - goto Lsa2; - } error("forward reference of %s %s", d->kind(), d->toChars()); continue; } @@ -6157,6 +6840,17 @@ Identifier *TemplateInstance::genIdent(Objects *args) return Lexer::idPool(id); } +/************************************* + * Lazily generate identifier for template instance. + * This is because 75% of the ident's are never needed. + */ + +Identifier *TemplateInstance::getIdent() +{ + if (!ident && inst) + ident = genIdent(tiargs); // need an identifier for name mangling purposes. + return ident; +} /**************************************************** * Declare parameters of template instance, initialize them with the @@ -6165,12 +6859,15 @@ Identifier *TemplateInstance::genIdent(Objects *args) void TemplateInstance::declareParameters(Scope *sc) { + TemplateDeclaration *tempdecl = this->tempdecl->isTemplateDeclaration(); + assert(tempdecl); + //printf("TemplateInstance::declareParameters()\n"); for (size_t i = 0; i < tdtypes.dim; i++) { TemplateParameter *tp = (*tempdecl->parameters)[i]; - //Object *o = (*tiargs)[i]; - Object *o = tdtypes[i]; // initializer for tp + //RootObject *o = (*tiargs)[i]; + RootObject *o = tdtypes[i]; // initializer for tp //printf("\ttdtypes[%d] = %p\n", i, o); tempdecl->declareParameter(sc, tp, o); @@ -6182,79 +6879,6 @@ void TemplateInstance::declareParameters(Scope *sc) } } -/***************************************************** - * Determine if template instance is really a template function, - * and that template function needs to infer types from the function - * arguments. - */ - -int TemplateInstance::needsTypeInference(Scope *sc) -{ - //printf("TemplateInstance::needsTypeInference() %s\n", toChars()); - if (!findTemplateDeclaration(sc)) - return FALSE; - - int multipleMatches = FALSE; - for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) - { - /* If any of the overloaded template declarations need inference, - * then return TRUE - */ - FuncDeclaration *fd; - if (!td->onemember || - (fd = td->onemember/*->toAlias()*/->isFuncDeclaration()) == NULL || - fd->type->ty != Tfunction) - { - /* Not a template function, therefore type inference is not possible. - */ - //printf("false\n"); - return FALSE; - } - - for (size_t i = 0; i < td->parameters->dim; i++) - if ((*td->parameters)[i]->isTemplateThisParameter()) - return TRUE; - - /* Determine if the instance arguments, tiargs, are all that is necessary - * to instantiate the template. - */ - //printf("tp = %p, td->parameters->dim = %d, tiargs->dim = %d\n", tp, td->parameters->dim, tiargs->dim); - TypeFunction *fdtype = (TypeFunction *)fd->type; - if (Parameter::dim(fdtype->parameters)) - { - TemplateParameter *tp = td->isVariadic(); - if (tp && td->parameters->dim > 1) - return TRUE; - - if (tiargs->dim < td->parameters->dim) - { // Can remain tiargs be filled by default arguments? - for (size_t i = tiargs->dim; i < td->parameters->dim; i++) - { tp = (*td->parameters)[i]; - if (TemplateTypeParameter *ttp = tp->isTemplateTypeParameter()) - { if (!ttp->defaultType) - return TRUE; - } - else if (TemplateAliasParameter *tap = tp->isTemplateAliasParameter()) - { if (!tap->defaultAlias) - return TRUE; - } - else if (TemplateValueParameter *tvp = tp->isTemplateValueParameter()) - { if (!tvp->defaultValue) - return TRUE; - } - } - } - } - /* If there is more than one function template which matches, we may - * need type inference (see Bugzilla 4430) - */ - if (td != tempdecl) - multipleMatches = TRUE; - } - //printf("false\n"); - return multipleMatches; -} - void TemplateInstance::semantic2(Scope *sc) { if (semanticRun >= PASSsemantic2) @@ -6268,6 +6892,7 @@ void TemplateInstance::semantic2(Scope *sc) sc = tempdecl->scope; assert(sc); sc = sc->push(argsym); + sc->instantiatingModule = instantiatingModule; sc = sc->push(this); sc->tinst = this; for (size_t i = 0; i < members->dim; i++) @@ -6299,17 +6924,19 @@ void TemplateInstance::semantic3(Scope *sc) { sc = tempdecl->scope; sc = sc->push(argsym); + sc->instantiatingModule = instantiatingModule; sc = sc->push(this); sc->tinst = this; - int oldgag = global.gag; + int needGagging = (speculative && !global.gag); int olderrors = global.errors; + int oldGaggedErrors; /* If this is a speculative instantiation, gag errors. * Future optimisation: If the results are actually needed, errors * would already be gagged, so we don't really need to run semantic * on the members. */ - if (speculative && !oldgag) - olderrors = global.startGagging(); + if (needGagging) + oldGaggedErrors = global.startGagging(); for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (*members)[i]; @@ -6317,10 +6944,10 @@ void TemplateInstance::semantic3(Scope *sc) if (speculative && global.errors != olderrors) break; } - if (speculative && !oldgag) + if (needGagging) { // If errors occurred, this instantiation failed - errors += global.errors - olderrors; - global.endGagging(olderrors); + if (global.endGagging(oldGaggedErrors)) + errors = true; } sc = sc->pop(); sc->pop(); @@ -6423,23 +7050,55 @@ void TemplateInstance::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { Identifier *id = name; buf->writestring(id->toChars()); - buf->writestring("!("); + toCBufferTiargs(buf, hgs); +} + +void TemplateInstance::toCBufferTiargs(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writeByte('!'); if (nest) - buf->writestring("..."); + buf->writestring("(...)"); else { + if (tiargs->dim == 1) + { + RootObject *oarg = (*tiargs)[0]; + if (Type *t = isType(oarg)) + { + if (t->equals(Type::tstring) || + t->mod == 0 && + (t->isTypeBasic() || + t->ty == Tident && ((TypeIdentifier *)t)->idents.dim == 0)) + { + buf->writestring(t->toChars()); + return; + } + } + else if (Expression *e = isExpression(oarg)) + { + if (e->op == TOKint64 || // IntegerExp(10, true, false, 'c') + e->op == TOKfloat64 || // RealExp(3.14, 1.4i) + e->op == TOKnull || // NullExp + e->op == TOKstring || // StringExp + e->op == TOKthis) + { + buf->writestring(e->toChars()); + return; + } + } + } + buf->writeByte('('); nest++; - Objects *args = tiargs; - for (size_t i = 0; i < args->dim; i++) + for (size_t i = 0; i < tiargs->dim; i++) { if (i) buf->writestring(", "); - Object *oarg = (*args)[i]; + RootObject *oarg = (*tiargs)[i]; ObjectToCBuffer(buf, hgs, oarg); } nest--; + buf->writeByte(')'); } - buf->writeByte(')'); } @@ -6463,8 +7122,9 @@ Dsymbol *TemplateInstance::toAlias() // inst = NULL; // trigger fwd ref error } if (!inst) - { error("cannot resolve forward reference"); - errors = 1; + { + error("cannot resolve forward reference"); + errors = true; return this; } } @@ -6490,10 +7150,10 @@ const char *TemplateInstance::kind() return "template instance"; } -int TemplateInstance::oneMember(Dsymbol **ps, Identifier *ident) +bool TemplateInstance::oneMember(Dsymbol **ps, Identifier *ident) { *ps = NULL; - return TRUE; + return true; } char *TemplateInstance::toChars() @@ -6508,6 +7168,74 @@ char *TemplateInstance::toChars() return s; } +int TemplateInstance::compare(RootObject *o) +{ + TemplateInstance *ti = (TemplateInstance *)o; + + //printf("this = %p, ti = %p\n", this, ti); + assert(tdtypes.dim == ti->tdtypes.dim); + + // Nesting must match + if (enclosing != ti->enclosing) + { + //printf("test2 enclosing %s ti->enclosing %s\n", enclosing ? enclosing->toChars() : "", ti->enclosing ? ti->enclosing->toChars() : ""); + goto Lnotequals; + } + //printf("parent = %s, ti->parent = %s\n", parent->toPrettyChars(), ti->parent->toPrettyChars()); + + if (!arrayObjectMatch(&tdtypes, &ti->tdtypes)) + goto Lnotequals; + + /* Template functions may have different instantiations based on + * "auto ref" parameters. + */ + if (fargs) + { + FuncDeclaration *fd = ti->toAlias()->isFuncDeclaration(); + if (fd) + { + Parameters *fparameters = fd->getParameters(NULL); + size_t nfparams = Parameter::dim(fparameters); // Num function parameters + for (size_t j = 0; j < nfparams && j < fargs->dim; j++) + { + Parameter *fparam = Parameter::getNth(fparameters, j); + Expression *farg = (*fargs)[j]; + if (Expression *e = farg->isTemp()) + farg = e; + if (fparam->storageClass & STCauto) // if "auto ref" + { + if (farg->isLvalue()) + { + if (!(fparam->storageClass & STCref)) + goto Lnotequals; // auto ref's don't match + } + else + { + if (fparam->storageClass & STCref) + goto Lnotequals; // auto ref's don't match + } + } + } + } + } + return 0; + + Lnotequals: + return 1; +} + +hash_t TemplateInstance::hashCode() +{ + if (!hash) + { + hash = (size_t)(void *)enclosing; + hash += arrayObjectHash(&tdtypes); + } + return hash; +} + + + /* ======================== TemplateMixin ================================ */ TemplateMixin::TemplateMixin(Loc loc, Identifier *ident, TypeQualified *tqual, Objects *tiargs) @@ -6528,13 +7256,91 @@ Dsymbol *TemplateMixin::syntaxCopy(Dsymbol *s) return tm; } +bool TemplateMixin::findTemplateDeclaration(Scope *sc) +{ + // Follow qualifications to find the TemplateDeclaration + if (!tempdecl) + { + Expression *e; + Type *t; + Dsymbol *s; + tqual->resolve(loc, sc, &e, &t, &s); + if (!s) + { + error("is not defined"); + return false; + } + s = s->toAlias(); + tempdecl = s->isTemplateDeclaration(); + OverloadSet *os = s->isOverloadSet(); + + /* If an OverloadSet, look for a unique member that is a template declaration + */ + if (os) + { + Dsymbol *s = NULL; + for (size_t i = 0; i < os->a.dim; i++) + { + Dsymbol *s2 = os->a[i]->isTemplateDeclaration(); + if (s2) + { + if (s) + { + tempdecl = os; + break; + } + s = s2; + } + } + } + if (!tempdecl) + { + error("%s isn't a template", s->toChars()); + return false; + } + } + assert(tempdecl); + + struct ParamFwdResTm + { + static int fp(void *param, Dsymbol *s) + { + TemplateDeclaration *td = s->isTemplateDeclaration(); + if (!td) + return 0; + + TemplateMixin *tm = (TemplateMixin *)param; + if (td->semanticRun == PASSinit) + { + if (td->scope) + td->semantic(td->scope); + else + { + tm->semanticRun = PASSinit; + return 1; + } + } + return 0; + } + }; + // Look for forward references + OverloadSet *tovers = tempdecl->isOverloadSet(); + size_t overs_dim = tovers ? tovers->a.dim : 1; + for (size_t oi = 0; oi < overs_dim; oi++) + { + if (overloadApply(tovers ? tovers->a[oi] : tempdecl, (void *)this, &ParamFwdResTm::fp)) + return false; + } + return true; +} + void TemplateMixin::semantic(Scope *sc) { #if LOG printf("+TemplateMixin::semantic('%s', this=%p)\n", toChars(), this); fflush(stdout); #endif - if (semanticRun) + if (semanticRun != PASSinit) { // This for when a class/struct contains mixin members, and // is done over because of forward references @@ -6552,89 +7358,56 @@ void TemplateMixin::semantic(Scope *sc) return; } } - if (!semanticRun) + if (semanticRun == PASSinit) semanticRun = PASSsemantic; #if LOG printf("\tdo semantic\n"); #endif -#if !IN_LLVM && !IN_GCC - // dont know what this is - util_progress(); -#endif - Scope *scx = NULL; if (scope) - { sc = scope; + { + sc = scope; scx = scope; // save so we don't make redundant copies scope = NULL; } - // Follow qualifications to find the TemplateDeclaration - if (!tempdecl) - { - Expression *e; - Type *t; - Dsymbol *s; - tqual->resolve(loc, sc, &e, &t, &s); - if (!s) - { - error("is not defined"); - inst = this; - return; - } - tempdecl = s->toAlias()->isTemplateDeclaration(); - if (!tempdecl) - { - error("%s isn't a template", s->toChars()); - inst = this; - return; - } - } - - // Look for forward reference - assert(tempdecl); - for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) - { - if (!td->semanticRun) - { - if (td->scope) - td->semantic(td->scope); - else - { - /* Cannot handle forward references if mixin is a struct member, - * because addField must happen during struct's semantic, not - * during the mixin semantic. - * runDeferred will re-run mixin's semantic outside of the struct's - * semantic. - */ - semanticRun = PASSinit; - AggregateDeclaration *ad = toParent()->isAggregateDeclaration(); - if (ad) - ad->sizeok = SIZEOKfwd; - else - { - // Forward reference - //printf("forward reference - deferring\n"); - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - scope->module->addDeferredSemantic(this); - } - return; - } - } - } /* Run semantic on each argument, place results in tiargs[], * then find best match template with tiargs */ - if (!semanticTiargs(sc) || + if (!findTemplateDeclaration(sc) || + !semanticTiargs(sc) || !findBestMatch(sc, NULL)) { + if (semanticRun == PASSinit) // forward reference had occured + { + /* Cannot handle forward references if mixin is a struct member, + * because addField must happen during struct's semantic, not + * during the mixin semantic. + * runDeferred will re-run mixin's semantic outside of the struct's + * semantic. + */ + AggregateDeclaration *ad = toParent()->isAggregateDeclaration(); + if (ad) + ad->sizeok = SIZEOKfwd; + else + { + // Forward reference + //printf("forward reference - deferring\n"); + scope = scx ? scx : new Scope(*sc); + scope->setNoFree(); + scope->module->addDeferredSemantic(this); + } + return; + } + inst = this; inst->errors = true; return; // error recovery } + TemplateDeclaration *tempdecl = this->tempdecl->isTemplateDeclaration(); + assert(tempdecl); if (!ident) ident = genIdent(tiargs); @@ -6657,11 +7430,12 @@ void TemplateMixin::semantic(Scope *sc) continue; for (size_t i = 0; i < tiargs->dim; i++) - { Object *o = (*tiargs)[i]; + { + RootObject *o = (*tiargs)[i]; Type *ta = isType(o); Expression *ea = isExpression(o); Dsymbol *sa = isDsymbol(o); - Object *tmo = (*tm->tiargs)[i]; + RootObject *tmo = (*tm->tiargs)[i]; if (ta) { Type *tmta = isType(tmo); @@ -6671,7 +7445,8 @@ void TemplateMixin::semantic(Scope *sc) goto Lcontinue; } else if (ea) - { Expression *tme = isExpression(tmo); + { + Expression *tme = isExpression(tmo); if (!tme || !ea->equals(tme)) goto Lcontinue; } @@ -6728,9 +7503,9 @@ void TemplateMixin::semantic(Scope *sc) // Add members to enclosing scope, as well as this scope for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (*members)[i]; + { + Dsymbol *s = (*members)[i]; s->addMember(argscope, this, i); - //sc->insert(s); //printf("sc->parent = %p, sc->scopesym = %p\n", sc->parent, sc->scopesym); //printf("s->parent = %s\n", s->parent->toChars()); } @@ -6808,13 +7583,9 @@ void TemplateMixin::semantic(Scope *sc) } sc2->pop(); - argscope->pop(); + scy->pop(); -// if (!isAnonymous()) - { - scy->pop(); - } #if LOG printf("-TemplateMixin::semantic('%s', this=%p)\n", toChars(), this); #endif @@ -6860,6 +7631,7 @@ void TemplateMixin::semantic3(Scope *sc) if (members) { sc = sc->push(argsym); + sc->instantiatingModule = instantiatingModule; sc = sc->push(this); for (size_t i = 0; i < members->dim; i++) { @@ -6881,7 +7653,7 @@ const char *TemplateMixin::kind() return "mixin"; } -int TemplateMixin::oneMember(Dsymbol **ps, Identifier *ident) +bool TemplateMixin::oneMember(Dsymbol **ps, Identifier *ident) { return Dsymbol::oneMember(ps, ident); } @@ -6902,21 +7674,23 @@ int TemplateMixin::apply(Dsymbol_apply_ft_t fp, void *param) return 0; } -int TemplateMixin::hasPointers() +bool TemplateMixin::hasPointers() { //printf("TemplateMixin::hasPointers() %s\n", toChars()); if (members) + { for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (*members)[i]; //printf(" s = %s %s\n", s->kind(), s->toChars()); if (s->hasPointers()) { - return 1; + return true; } } - return 0; + } + return false; } void TemplateMixin::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion) @@ -6951,36 +7725,8 @@ void TemplateMixin::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writestring("mixin "); tqual->toCBuffer(buf, NULL, hgs); - buf->writestring("!("); - if (tiargs) - { - for (size_t i = 0; i < tiargs->dim; i++) - { if (i) - buf->writestring(", "); - Object *oarg = (*tiargs)[i]; - Type *t = isType(oarg); - Expression *e = isExpression(oarg); - Dsymbol *s = isDsymbol(oarg); - if (t) - t->toCBuffer(buf, NULL, hgs); - else if (e) - e->toCBuffer(buf, hgs); - else if (s) - { - char *p = s->ident ? s->ident->toChars() : s->toChars(); - buf->writestring(p); - } - else if (!oarg) - { - buf->writestring("NULL"); - } - else - { - assert(0); - } - } - } - buf->writebyte(')'); + toCBufferTiargs(buf, hgs); + if (ident) { buf->writebyte(' '); diff --git a/dmd2/template.h b/dmd2/template.h index eb00d66b..b963548d 100644 --- a/dmd2/template.h +++ b/dmd2/template.h @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars +// Copyright (c) 1999-2013 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -24,52 +24,56 @@ struct OutBuffer; -struct Identifier; -struct TemplateInstance; -struct TemplateParameter; -struct TemplateTypeParameter; -struct TemplateThisParameter; -struct TemplateValueParameter; -struct TemplateAliasParameter; -struct TemplateTupleParameter; -struct Type; -struct TypeQualified; -struct TypeTypeof; +class Identifier; +class TemplateInstance; +class TemplateParameter; +class TemplateTypeParameter; +class TemplateThisParameter; +class TemplateValueParameter; +class TemplateAliasParameter; +class TemplateTupleParameter; +class Type; +class TypeQualified; +class TypeTypeof; struct Scope; -struct Expression; -struct AliasDeclaration; -struct FuncDeclaration; +class Expression; +class AliasDeclaration; +class FuncDeclaration; struct HdrGenState; -struct Parameter; +class Parameter; enum MATCH; enum PASS; -struct Tuple : Object +class Tuple : public RootObject { +public: Objects objects; int dyncast() { return DYNCAST_TUPLE; } // kludge for template.isType() }; -struct TemplateDeclaration : ScopeDsymbol +class TemplateDeclaration : public ScopeDsymbol { +public: TemplateParameters *parameters; // array of TemplateParameter's TemplateParameters *origParameters; // originals for Ddoc Expression *constraint; - TemplateInstances instances; // array of TemplateInstance's + + // Hash table to look up TemplateInstance's of this TemplateDeclaration + Array buckets; + size_t numinstances; // number of instances in the hash table TemplateDeclaration *overnext; // next overloaded TemplateDeclaration TemplateDeclaration *overroot; // first in overnext list - - enum PASS semanticRun; // 1 semantic() run + FuncDeclaration *funcroot; // first function in unified overload list Dsymbol *onemember; // if !=NULL then one member of this template int literal; // this template declaration is a literal int ismixin; // template declaration is only to be used as a mixin - enum PROT protection; + PROT protection; struct Previous { Previous *prev; @@ -82,7 +86,7 @@ struct TemplateDeclaration : ScopeDsymbol Expression *constraint, Dsymbols *decldefs, int ismixin); Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); - int overloadInsert(Dsymbol *s); + bool overloadInsert(Dsymbol *s); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); bool hasStaticCtorOrDtor(); const char *kind(); @@ -91,21 +95,23 @@ struct TemplateDeclaration : ScopeDsymbol void emitComment(Scope *sc); void toJson(JsonOut *json); virtual void jsonProperties(JsonOut *json); - enum PROT prot(); + PROT prot(); // void toDocBuffer(OutBuffer *buf); - MATCH matchWithInstance(TemplateInstance *ti, Objects *atypes, Expressions *fargs, int flag); - MATCH leastAsSpecialized(TemplateDeclaration *td2, Expressions *fargs); + MATCH matchWithInstance(Scope *sc, TemplateInstance *ti, Objects *atypes, Expressions *fargs, int flag); + MATCH leastAsSpecialized(Scope *sc, TemplateDeclaration *td2, Expressions *fargs); - MATCH deduceFunctionTemplateMatch(Loc loc, Scope *sc, Objects *tiargs, Type *tthis, Expressions *fargs, Objects *dedargs); - FuncDeclaration *deduceFunctionTemplate(Loc loc, Scope *sc, Objects *tiargs, Type *tthis, Expressions *fargs, int flags = 0); - Object *declareParameter(Scope *sc, TemplateParameter *tp, Object *o); + MATCH deduceFunctionTemplateMatch(FuncDeclaration *f, Loc loc, Scope *sc, Objects *tiargs, Type *tthis, Expressions *fargs, Objects *dedargs); + RootObject *declareParameter(Scope *sc, TemplateParameter *tp, RootObject *o); FuncDeclaration *doHeaderInstantiation(Scope *sc, Objects *tdargs, Type *tthis, Expressions *fargs); + TemplateInstance *findExistingInstance(TemplateInstance *tithis, Expressions *fargs); + TemplateInstance *addInstance(TemplateInstance *ti); + void removeInstance(TemplateInstance *handle); TemplateDeclaration *isTemplateDeclaration() { return this; } TemplateTupleParameter *isVariadic(); - int isOverloadable(); + bool isOverloadable(); void makeParamNamesVisibleInConstraint(Scope *paramscope, Expressions *fargs); #if IN_LLVM @@ -114,8 +120,9 @@ struct TemplateDeclaration : ScopeDsymbol #endif }; -struct TemplateParameter +class TemplateParameter { +public: /* For type-parameter: * template Foo(ident) // specType is set to NULL * template Foo(ident : specType) @@ -145,11 +152,11 @@ struct TemplateParameter virtual TemplateParameter *syntaxCopy() = 0; virtual void declareParameter(Scope *sc) = 0; - virtual void semantic(Scope *) = 0; - virtual void print(Object *oarg, Object *oded) = 0; + virtual void semantic(Scope *sc, TemplateParameters *parameters) = 0; + virtual void print(RootObject *oarg, RootObject *oded) = 0; virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs) = 0; - virtual Object *specialization() = 0; - virtual Object *defaultArg(Loc loc, Scope *sc) = 0; + virtual RootObject *specialization() = 0; + virtual RootObject *defaultArg(Loc loc, Scope *sc) = 0; /* If TemplateParameter's match as far as overloading goes. */ @@ -157,15 +164,17 @@ struct TemplateParameter /* Match actual argument against parameter. */ - virtual MATCH matchArg(Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam) = 0; + virtual MATCH matchArg(Loc loc, Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); + virtual MATCH matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam) = 0; /* Create dummy argument based on parameter. */ virtual void *dummyArg() = 0; }; -struct TemplateTypeParameter : TemplateParameter +class TemplateTypeParameter : public TemplateParameter { +public: /* Syntax: * ident : specType = defaultType */ @@ -179,19 +188,20 @@ struct TemplateTypeParameter : TemplateParameter TemplateTypeParameter *isTemplateTypeParameter(); TemplateParameter *syntaxCopy(); void declareParameter(Scope *sc); - void semantic(Scope *); - void print(Object *oarg, Object *oded); + void semantic(Scope *sc, TemplateParameters *parameters); + void print(RootObject *oarg, RootObject *oded); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Object *specialization(); - Object *defaultArg(Loc loc, Scope *sc); + RootObject *specialization(); + RootObject *defaultArg(Loc loc, Scope *sc); int overloadMatch(TemplateParameter *); - MATCH matchArg(Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); + MATCH matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); void *dummyArg(); }; #if DMDV2 -struct TemplateThisParameter : TemplateTypeParameter +class TemplateThisParameter : public TemplateTypeParameter { +public: /* Syntax: * this ident : specType = defaultType */ @@ -204,8 +214,9 @@ struct TemplateThisParameter : TemplateTypeParameter }; #endif -struct TemplateValueParameter : TemplateParameter +class TemplateValueParameter : public TemplateParameter { +public: /* Syntax: * valType ident : specValue = defaultValue */ @@ -221,45 +232,47 @@ struct TemplateValueParameter : TemplateParameter TemplateValueParameter *isTemplateValueParameter(); TemplateParameter *syntaxCopy(); void declareParameter(Scope *sc); - void semantic(Scope *); - void print(Object *oarg, Object *oded); + void semantic(Scope *sc, TemplateParameters *parameters); + void print(RootObject *oarg, RootObject *oded); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Object *specialization(); - Object *defaultArg(Loc loc, Scope *sc); + RootObject *specialization(); + RootObject *defaultArg(Loc loc, Scope *sc); int overloadMatch(TemplateParameter *); - MATCH matchArg(Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); + MATCH matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); void *dummyArg(); }; -struct TemplateAliasParameter : TemplateParameter +class TemplateAliasParameter : public TemplateParameter { +public: /* Syntax: * specType ident : specAlias = defaultAlias */ Type *specType; - Object *specAlias; - Object *defaultAlias; + RootObject *specAlias; + RootObject *defaultAlias; static Dsymbol *sdummy; - TemplateAliasParameter(Loc loc, Identifier *ident, Type *specType, Object *specAlias, Object *defaultAlias); + TemplateAliasParameter(Loc loc, Identifier *ident, Type *specType, RootObject *specAlias, RootObject *defaultAlias); TemplateAliasParameter *isTemplateAliasParameter(); TemplateParameter *syntaxCopy(); void declareParameter(Scope *sc); - void semantic(Scope *); - void print(Object *oarg, Object *oded); + void semantic(Scope *sc, TemplateParameters *parameters); + void print(RootObject *oarg, RootObject *oded); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Object *specialization(); - Object *defaultArg(Loc loc, Scope *sc); + RootObject *specialization(); + RootObject *defaultArg(Loc loc, Scope *sc); int overloadMatch(TemplateParameter *); - MATCH matchArg(Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); + MATCH matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); void *dummyArg(); }; -struct TemplateTupleParameter : TemplateParameter +class TemplateTupleParameter : public TemplateParameter { +public: /* Syntax: * ident ... */ @@ -269,25 +282,26 @@ struct TemplateTupleParameter : TemplateParameter TemplateTupleParameter *isTemplateTupleParameter(); TemplateParameter *syntaxCopy(); void declareParameter(Scope *sc); - void semantic(Scope *); - void print(Object *oarg, Object *oded); + void semantic(Scope *sc, TemplateParameters *parameters); + void print(RootObject *oarg, RootObject *oded); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Object *specialization(); - Object *defaultArg(Loc loc, Scope *sc); + RootObject *specialization(); + RootObject *defaultArg(Loc loc, Scope *sc); int overloadMatch(TemplateParameter *); - MATCH matchArg(Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); + MATCH matchArg(Loc loc, Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); + MATCH matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); void *dummyArg(); }; -struct TemplateInstance : ScopeDsymbol +class TemplateInstance : public ScopeDsymbol { +public: /* Given: * foo!(args) => * name = foo * tiargs = args */ Identifier *name; - //Identifiers idents; Objects *tiargs; // Array of Types/Expressions of template // instance arguments [int*, char, 10*10] @@ -295,19 +309,21 @@ struct TemplateInstance : ScopeDsymbol // to TemplateDeclaration.parameters // [int, char, 100] - TemplateDeclaration *tempdecl; // referenced by foo.bar.abc + Dsymbol *tempdecl; // referenced by foo.bar.abc TemplateInstance *inst; // refer to existing instance TemplateInstance *tinst; // enclosing template instance ScopeDsymbol *argsym; // argument symbol table AliasDeclaration *aliasdecl; // !=NULL if instance is an alias for its // sole member WithScopeSymbol *withsym; // if a member of a with statement - enum PASS semanticRun; // has semantic() been done? - int semantictiargsdone; // has semanticTiargs() been done? - int nest; // for recursion detection - int havetempdecl; // 1 if used second constructor - Dsymbol *enclosing; // if referencing local symbols, this is the context - int speculative; // 1 if only instantiated with errors gagged + int nest; // for recursion detection + bool semantictiargsdone; // has semanticTiargs() been done? + bool havetempdecl; // if used second constructor + bool speculative; // if only instantiated with errors gagged + Dsymbol *enclosing; // if referencing local symbols, this is the context + hash_t hash; // cached result of hashCode() + Expressions *fargs; // for function template, these are the function arguments + Module *instantiatingModule; // the top module that instantiated this instance #ifdef IN_GCC /* On some targets, it is necessary to know whether a symbol will be emitted in the output or not before the symbol @@ -325,25 +341,30 @@ struct TemplateInstance : ScopeDsymbol void semantic3(Scope *sc); void inlineScan(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void toCBufferTiargs(OutBuffer *buf, HdrGenState *hgs); Dsymbol *toAlias(); // resolve real symbol const char *kind(); - int oneMember(Dsymbol **ps, Identifier *ident); - int needsTypeInference(Scope *sc); + bool oneMember(Dsymbol **ps, Identifier *ident); char *toChars(); const char *mangle(bool isv = false); void printInstantiationTrace(); + Identifier *getIdent(); + int compare(RootObject *o); + hash_t hashCode(); #if IN_DMD void toObjFile(int multiobj); // compile to .obj file #endif // Internal + bool findTemplateDeclaration(Scope *sc); + bool updateTemplateDeclaration(Scope *sc, Dsymbol *s); static void semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int flags); bool semanticTiargs(Scope *sc); - bool findTemplateDeclaration(Scope *sc); bool findBestMatch(Scope *sc, Expressions *fargs); + bool needsTypeInference(Scope *sc, int flag = 0); + bool hasNestedArgs(Objects *tiargs); void declareParameters(Scope *sc); - int hasNestedArgs(Objects *tiargs); Identifier *genIdent(Objects *args); void expandMembers(Scope *sc); void tryExpandMembers(Scope *sc); @@ -359,8 +380,9 @@ struct TemplateInstance : ScopeDsymbol #endif }; -struct TemplateMixin : TemplateInstance +class TemplateMixin : public TemplateInstance { +public: TypeQualified *tqual; TemplateMixin(Loc loc, Identifier *ident, TypeQualified *tqual, Objects *tiargs); @@ -370,9 +392,9 @@ struct TemplateMixin : TemplateInstance void semantic3(Scope *sc); void inlineScan(); const char *kind(); - int oneMember(Dsymbol **ps, Identifier *ident); + bool oneMember(Dsymbol **ps, Identifier *ident); int apply(Dsymbol_apply_ft_t fp, void *param); - int hasPointers(); + bool hasPointers(); void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); char *toChars(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -382,6 +404,8 @@ struct TemplateMixin : TemplateInstance void toObjFile(int multiobj); // compile to .obj file #endif + bool findTemplateDeclaration(Scope *sc); + TemplateMixin *isTemplateMixin() { return this; } #if IN_LLVM @@ -389,17 +413,17 @@ struct TemplateMixin : TemplateInstance #endif }; -Expression *isExpression(Object *o); -Dsymbol *isDsymbol(Object *o); -Type *isType(Object *o); -Tuple *isTuple(Object *o); -Parameter *isParameter(Object *o); +Expression *isExpression(RootObject *o); +Dsymbol *isDsymbol(RootObject *o); +Type *isType(RootObject *o); +Tuple *isTuple(RootObject *o); +Parameter *isParameter(RootObject *o); int arrayObjectIsError(Objects *args); -int isError(Object *o); -Type *getType(Object *o); -Dsymbol *getDsymbol(Object *o); +int isError(RootObject *o); +Type *getType(RootObject *o); +Dsymbol *getDsymbol(RootObject *o); -void ObjectToCBuffer(OutBuffer *buf, HdrGenState *hgs, Object *oarg); -Object *objectSyntaxCopy(Object *o); +void ObjectToCBuffer(OutBuffer *buf, HdrGenState *hgs, RootObject *oarg); +RootObject *objectSyntaxCopy(RootObject *o); #endif /* DMD_TEMPLATE_H */ diff --git a/dmd2/traits.c b/dmd2/traits.c index b80c517c..7fc0d25d 100644 --- a/dmd2/traits.c +++ b/dmd2/traits.c @@ -15,6 +15,7 @@ #include #include "rmem.h" +#include "aav.h" //#include "port.h" #include "mtype.h" @@ -51,9 +52,13 @@ struct Ptrait Identifier *ident; // which trait we're looking for }; -static int fptraits(void *param, FuncDeclaration *f) -{ Ptrait *p = (Ptrait *)param; +static int fptraits(void *param, Dsymbol *s) +{ + FuncDeclaration *f = s->isFuncDeclaration(); + if (!f) + return 0; + Ptrait *p = (Ptrait *)param; if (p->ident == Id::getVirtualFunctions && !f->isVirtual()) return 0; @@ -71,6 +76,52 @@ static int fptraits(void *param, FuncDeclaration *f) return 0; } +/** + * Collects all unit test functions from the given array of symbols. + * + * This is a helper function used by the implementation of __traits(getUnitTests). + * + * Input: + * symbols array of symbols to collect the functions from + * uniqueUnitTests an associative array (should actually be a set) to + * keep track of already collected functions. We're + * using an AA here to avoid doing a linear search of unitTests + * + * Output: + * unitTests array of DsymbolExp's of the collected unit test functions + * uniqueUnitTests updated with symbols from unitTests[ ] + */ +static void collectUnitTests(Dsymbols *symbols, AA *uniqueUnitTests, Expressions *unitTests) +{ + for (size_t i = 0; i < symbols->dim; i++) + { + Dsymbol *symbol = (*symbols)[i]; + UnitTestDeclaration *unitTest = symbol->isUnitTestDeclaration(); + if (unitTest) + { + if (!_aaGetRvalue(uniqueUnitTests, unitTest)) + { + FuncAliasDeclaration* alias = new FuncAliasDeclaration(unitTest, 0); + alias->protection = unitTest->protection; + Expression* e = new DsymbolExp(Loc(), alias); + unitTests->push(e); + bool* value = (bool*) _aaGet(&uniqueUnitTests, unitTest); + *value = true; + } + } + else + { + AttribDeclaration *attrDecl = symbol->isAttribDeclaration(); + + if (attrDecl) + { + Dsymbols *decl = attrDecl->include(NULL, NULL); + collectUnitTests(decl, uniqueUnitTests, unitTests); + } + } + } +} + /************************ TraitsExp ************************************/ Expression *TraitsExp::semantic(Scope *sc) @@ -79,7 +130,7 @@ Expression *TraitsExp::semantic(Scope *sc) printf("TraitsExp::semantic() %s\n", toChars()); #endif if (ident != Id::compiles && ident != Id::isSame && - ident != Id::identifier) + ident != Id::identifier && ident != Id::getProtection) { TemplateInstance::semanticTiargs(loc, sc, args, 1); } @@ -152,7 +203,7 @@ Expression *TraitsExp::semantic(Scope *sc) { if (dim != 1) goto Ldimerror; - Object *o = (*args)[0]; + RootObject *o = (*args)[0]; Type *t = isType(o); StructDeclaration *sd; if (!t) @@ -174,7 +225,7 @@ Expression *TraitsExp::semantic(Scope *sc) { if (dim != 1) goto Ldimerror; - Object *o = (*args)[0]; + RootObject *o = (*args)[0]; Dsymbol *s = getDsymbol(o); AggregateDeclaration *a; FuncDeclaration *f; @@ -216,7 +267,7 @@ Expression *TraitsExp::semantic(Scope *sc) else if (ident == Id::isFinalFunction) { FuncDeclaration *f; - ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && f->isFinal()) + ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && f->isFinalFunc()) } #if DMDV2 else if (ident == Id::isStaticFunction) @@ -247,7 +298,7 @@ Expression *TraitsExp::semantic(Scope *sc) if (dim != 1) goto Ldimerror; - Object *o = (*args)[0]; + RootObject *o = (*args)[0]; Parameter *po = isParameter(o); Identifier *id; if (po) @@ -271,7 +322,13 @@ Expression *TraitsExp::semantic(Scope *sc) { if (dim != 1) goto Ldimerror; - Object *o = (*args)[0]; + + Scope *sc2 = sc->push(); + sc2->flags = sc->flags | SCOPEnoaccesscheck; + TemplateInstance::semanticTiargs(loc, sc2, args, 1); + sc2->pop(); + + RootObject *o = (*args)[0]; Dsymbol *s = getDsymbol(o); if (!s) { @@ -279,7 +336,8 @@ Expression *TraitsExp::semantic(Scope *sc) error("argument %s has no protection", o->toChars()); goto Lfalse; } - + if (s->scope) + s->semantic(s->scope); PROT protection = s->prot(); const char *protName = Pprotectionnames[protection]; @@ -292,7 +350,7 @@ Expression *TraitsExp::semantic(Scope *sc) { if (dim != 1) goto Ldimerror; - Object *o = (*args)[0]; + RootObject *o = (*args)[0]; Dsymbol *s = getDsymbol(o); if (s) { @@ -317,7 +375,7 @@ Expression *TraitsExp::semantic(Scope *sc) { if (dim != 2) goto Ldimerror; - Object *o = (*args)[0]; + RootObject *o = (*args)[0]; Expression *e = isExpression((*args)[1]); if (!e) { error("expression expected as second argument of __traits %s", ident->toChars()); @@ -410,7 +468,7 @@ Expression *TraitsExp::semantic(Scope *sc) p.exps = exps; p.e1 = e; p.ident = ident; - overloadApply(f, &fptraits, &p); + overloadApply(f, &p, &fptraits); TupleExp *tup = new TupleExp(loc, exps); return tup->semantic(sc); @@ -422,7 +480,7 @@ Expression *TraitsExp::semantic(Scope *sc) { if (dim != 1) goto Ldimerror; - Object *o = (*args)[0]; + RootObject *o = (*args)[0]; Dsymbol *s = getDsymbol(o); ClassDeclaration *cd; if (!s || (cd = s->isClassDeclaration()) == NULL) @@ -436,7 +494,7 @@ Expression *TraitsExp::semantic(Scope *sc) { if (dim != 1) goto Ldimerror; - Object *o = (*args)[0]; + RootObject *o = (*args)[0]; Dsymbol *s = getDsymbol(o); if (!s) { @@ -459,7 +517,7 @@ Expression *TraitsExp::semantic(Scope *sc) { if (dim != 1) goto Ldimerror; - Object *o = (*args)[0]; + RootObject *o = (*args)[0]; Dsymbol *s = getDsymbol(o); ScopeDsymbol *sd; if (!s) @@ -488,6 +546,14 @@ Expression *TraitsExp::semantic(Scope *sc) //printf("\t[%i] %s %s\n", i, sm->kind(), sm->toChars()); if (sm->ident) { + if (sm->ident != Id::ctor && // backword compatibility + sm->ident != Id::dtor && // backword compatibility + sm->ident != Id::_postblit && // backword compatibility + memcmp(sm->ident->string, "__", 2) == 0) + { + return 0; + } + //printf("\t%s\n", sm->ident->toChars()); Identifiers *idents = (Identifiers *)ctx; @@ -570,37 +636,42 @@ Expression *TraitsExp::semantic(Scope *sc) goto Lfalse; for (size_t i = 0; i < dim; i++) - { Object *o = (*args)[i]; - Expression *e; - + { unsigned errors = global.startGagging(); unsigned oldspec = global.speculativeGag; global.speculativeGag = global.gag; - bool scSpec = sc->speculative; + sc = sc->push(); sc->speculative = true; + sc->flags = sc->enclosing->flags & ~SCOPEctfe; // inherit without CTFEing + bool err = false; + RootObject *o = (*args)[i]; Type *t = isType(o); - if (t) - { Dsymbol *s; + Expression *e = t ? t->toExpression() : isExpression(o); + if (!e && t) + { + Dsymbol *s; t->resolve(loc, sc, &e, &t, &s); if (t) + { t->semantic(loc, sc); - else if (e) - { e = e->semantic(sc); - e = e->optimize(WANTvalue); + if (t->ty == Terror) + err = true; } + else if (s && s->errors) + err = true; } - else - { e = isExpression(o); - if (e) - { e = e->semantic(sc); - e = e->optimize(WANTvalue); - } + if (e) + { + e = e->semantic(sc); + e = e->optimize(WANTvalue); + if (e->op == TOKerror) + err = true; } - sc->speculative = scSpec; + sc = sc->pop(); global.speculativeGag = oldspec; - if (global.endGagging(errors)) + if (global.endGagging(errors) || err) { goto Lfalse; } @@ -613,8 +684,8 @@ Expression *TraitsExp::semantic(Scope *sc) if (dim != 2) goto Ldimerror; TemplateInstance::semanticTiargs(loc, sc, args, 0); - Object *o1 = (*args)[0]; - Object *o2 = (*args)[1]; + RootObject *o1 = (*args)[0]; + RootObject *o2 = (*args)[1]; Dsymbol *s1 = getDsymbol(o1); Dsymbol *s2 = getDsymbol(o2); @@ -660,6 +731,64 @@ Expression *TraitsExp::semantic(Scope *sc) else goto Lfalse; } + else if (ident == Id::getUnitTests) + { + if (dim != 1) + goto Ldimerror; + RootObject *o = (*args)[0]; + Dsymbol *s = getDsymbol(o); + if (!s) + { + error("argument %s to __traits(getUnitTests) must be a module or aggregate", o->toChars()); + goto Lfalse; + } + + Import *imp = s->isImport(); + if (imp) // Bugzilla 10990 + s = imp->mod; + + ScopeDsymbol* scope = s->isScopeDsymbol(); + + if (!scope) + { + error("argument %s to __traits(getUnitTests) must be a module or aggregate, not a %s", s->toChars(), s->kind()); + goto Lfalse; + } + + Expressions* unitTests = new Expressions(); + Dsymbols* symbols = scope->members; + + if (global.params.useUnitTests && symbols) + { + // Should actually be a set + AA* uniqueUnitTests = NULL; + collectUnitTests(symbols, uniqueUnitTests, unitTests); + } + + TupleExp *tup = new TupleExp(loc, unitTests); + return tup->semantic(sc); + } + else if (ident == Id::isOverrideFunction) + { + FuncDeclaration *f; + ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && f->isOverride()) + } + else if(ident == Id::getVirtualIndex) + { + if (dim != 1) + goto Ldimerror; + RootObject *o = (*args)[0]; + Dsymbol *s = getDsymbol(o); + FuncDeclaration *fd; + if (!s || (fd = s->isFuncDeclaration()) == NULL) + { + error("first argument to __traits(getVirtualIndex) must be a function"); + goto Lfalse; + } + fd = fd->toAliasFunc(); // Neccessary to support multiple overloads. + ptrdiff_t result = fd->isVirtual() ? fd->vtblIndex : -1; + return new IntegerExp(loc, fd->vtblIndex, Type::tptrdiff_t); + } else { error("unrecognized trait %s", ident->toChars()); goto Lfalse; @@ -679,5 +808,4 @@ Ltrue: return new IntegerExp(loc, 1, Type::tbool); } - #endif diff --git a/dmd2/version.c b/dmd2/version.c index 37f33c06..bfe3eaaf 100644 --- a/dmd2/version.c +++ b/dmd2/version.c @@ -57,11 +57,17 @@ int DebugSymbol::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) if (ident) { if (!m) + { error("declaration must be at module level"); + errors = true; + } else { if (findCondition(m->debugidsNot, ident)) + { error("defined after use"); + errors = true; + } if (!m->debugids) m->debugids = new Strings(); m->debugids->push(ident->toChars()); @@ -70,7 +76,10 @@ int DebugSymbol::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) else { if (!m) + { error("level declaration must be at module level"); + errors = true; + } else m->debuglevel = level; } @@ -138,11 +147,17 @@ int VersionSymbol::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) { VersionCondition::checkPredefined(loc, ident->toChars()); if (!m) + { error("declaration must be at module level"); + errors = true; + } else { if (findCondition(m->versionidsNot, ident)) + { error("defined after use"); + errors = true; + } if (!m->versionids) m->versionids = new Strings(); m->versionids->push(ident->toChars()); @@ -151,7 +166,10 @@ int VersionSymbol::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) else { if (!m) + { error("level declaration must be at module level"); + errors = true; + } else m->versionlevel = level; } diff --git a/dmd2/version.h b/dmd2/version.h index b5ae51d2..dbb066f2 100644 --- a/dmd2/version.h +++ b/dmd2/version.h @@ -20,8 +20,9 @@ struct OutBuffer; struct HdrGenState; -struct DebugSymbol : Dsymbol +class DebugSymbol : public Dsymbol { +public: unsigned level; DebugSymbol(Loc loc, Identifier *ident); @@ -34,8 +35,9 @@ struct DebugSymbol : Dsymbol const char *kind(); }; -struct VersionSymbol : Dsymbol +class VersionSymbol : public Dsymbol { +public: unsigned level; VersionSymbol(Loc loc, Identifier *ident); diff --git a/driver/main.cpp b/driver/main.cpp index 50c4563f..decbbf80 100644 --- a/driver/main.cpp +++ b/driver/main.cpp @@ -12,8 +12,10 @@ #include "mars.h" #include "module.h" #include "mtype.h" +#include "parse.h" #include "rmem.h" #include "root.h" +#include "scope.h" #include "dmd2/target.h" #include "driver/cl_options.h" #include "driver/configfile.h" @@ -270,7 +272,7 @@ static void parseCommandLine(int argc, char **argv, Strings &sourceFiles, bool & if (global.params.verbose) { const std::string& path = cfg_file.path(); if (!path.empty()) - printf("config %s\n", path.c_str()); + fprintf(global.stdmsg, "config %s\n", path.c_str()); } // Negated options @@ -354,7 +356,7 @@ static void parseCommandLine(int argc, char **argv, Strings &sourceFiles, bool & if (!I->empty()) sourceFiles.push(mem.strdup(I->c_str())); - Array* libs; + Strings* libs; if (global.params.symdebug) { libs = global.params.debuglibnames; @@ -644,6 +646,46 @@ static void registerPredefinedVersions() { #undef STR } +static Module *entrypoint = NULL; + +/// Callback to generate a C main() function, invoked by the frontend. +void genCmain(Scope *sc) +{ + if (entrypoint) + return; + + /* The D code to be generated is provided as D source code in the form of a string. + * Note that Solaris, for unknown reasons, requires both a main() and an _main() + */ + static utf8_t code[] = "extern(C) {\n\ + int _d_run_main(int argc, char **argv, void* mainFunc);\n\ + int _Dmain(char[][] args);\n\ + int main(int argc, char **argv) { return _d_run_main(argc, argv, &_Dmain); }\n\ + version (Solaris) int _main(int argc, char** argv) { return main(argc, argv); }\n\ + }\n\ + "; + + Identifier *id = Id::entrypoint; + Module *m = new Module("__entrypoint.d", id, 0, 0); + + Parser p(m, code, sizeof(code) / sizeof(code[0]), 0); + p.scanloc = Loc(); + p.nextToken(); + m->members = p.parseModule(); + assert(p.token.value == TOKeof); + + char v = global.params.verbose; + global.params.verbose = 0; + m->importedFrom = sc->module; + m->importAll(NULL); + m->semantic(); + m->semantic2(); + m->semantic3(); + global.params.verbose = v; + + entrypoint = m; +} + int main(int argc, char **argv) { mem.init(); // initialize storage allocator @@ -709,6 +751,8 @@ int main(int argc, char **argv) global.params.isFreeBSD = triple.getOS() == llvm::Triple::FreeBSD; global.params.isOpenBSD = triple.getOS() == llvm::Triple::OpenBSD; global.params.isSolaris = triple.getOS() == llvm::Triple::Solaris; + // FIXME: Correctly handle the x32 ABI (AMD64 ILP32) here. + global.params.isLP64 = triple.isArch64Bit(); global.params.is64bit = triple.isArch64Bit(); } @@ -885,7 +929,6 @@ int main(int argc, char **argv) id = Lexer::idPool(name); Module *m = new Module(static_cast(files.data[i]), id, global.params.doDocComments, global.params.doHdrGeneration); - m->isRoot = true; modules.push(m); } @@ -894,7 +937,7 @@ int main(int argc, char **argv) { Module *m = modules[i]; if (global.params.verbose) - printf("parse %s\n", m->toChars()); + fprintf(global.stdmsg, "parse %s\n", m->toChars()); if (!Module::rootModule) Module::rootModule = m; m->importedFrom = m; @@ -935,7 +978,7 @@ int main(int argc, char **argv) for (unsigned i = 0; i < modules.dim; i++) { if (global.params.verbose) - printf("import %s\n", modules[i]->toChars()); + fprintf(global.stdmsg, "import %s\n", modules[i]->toChars()); modules[i]->genhdrfile(); } } @@ -946,7 +989,7 @@ int main(int argc, char **argv) for (unsigned i = 0; i < modules.dim; i++) { if (global.params.verbose) - printf("importall %s\n", modules[i]->toChars()); + fprintf(global.stdmsg, "importall %s\n", modules[i]->toChars()); modules[i]->importAll(0); } if (global.errors) @@ -956,7 +999,7 @@ int main(int argc, char **argv) for (unsigned i = 0; i < modules.dim; i++) { if (global.params.verbose) - printf("semantic %s\n", modules[i]->toChars()); + fprintf(global.stdmsg, "semantic %s\n", modules[i]->toChars()); modules[i]->semantic(); } if (global.errors) @@ -969,7 +1012,7 @@ int main(int argc, char **argv) for (unsigned i = 0; i < modules.dim; i++) { if (global.params.verbose) - printf("semantic2 %s\n", modules[i]->toChars()); + fprintf(global.stdmsg, "semantic2 %s\n", modules[i]->toChars()); modules[i]->semantic2(); } if (global.errors) @@ -979,7 +1022,7 @@ int main(int argc, char **argv) for (unsigned i = 0; i < modules.dim; i++) { if (global.params.verbose) - printf("semantic3 %s\n", modules[i]->toChars()); + fprintf(global.stdmsg, "semantic3 %s\n", modules[i]->toChars()); modules[i]->semantic3(); } if (global.errors) @@ -1013,7 +1056,7 @@ int main(int argc, char **argv) { Module *m = Module::amodules[i]; if (global.params.verbose) - printf("semantic3 %s\n", m->toChars()); + fprintf(global.stdmsg, "semantic3 %s\n", m->toChars()); m->semantic2(); m->semantic3(); } @@ -1022,6 +1065,9 @@ int main(int argc, char **argv) } global.inExtraInliningSemantic = false; } + + Module::runDeferredSemantic3(); + if (global.errors || global.warnings) fatal(); @@ -1045,10 +1091,30 @@ int main(int argc, char **argv) { Module *m = modules[i]; if (global.params.verbose) - printf("code %s\n", m->toChars()); + fprintf(global.stdmsg, "code %s\n", m->toChars()); if (global.params.obj) { llvm::Module* lm = m->genLLVMModule(context); + if (entrypoint && entrypoint->importedFrom == m) + { +#if LDC_LLVM_VER >= 303 + llvm::Linker linker(lm); +#else + llvm::Linker linker("ldc", lm); +#endif + + llvm::Module* entryModule = entrypoint->genLLVMModule(context); + std::string linkError; + +#if LDC_LLVM_VER >= 303 + const bool hadError = linker.linkInModule(entryModule, &linkError); +#else + const bool hadError= linker.LinkInModule(entryModule, &linkError); + linker.releaseModule(); +#endif + if (hadError) + error("%s", linkError.c_str()); + } if (!singleObj) { m->deleteObjFile(); @@ -1061,11 +1127,8 @@ int main(int argc, char **argv) } if (global.errors) m->deleteObjFile(); - else - { - if (global.params.doDocComments) + else if (global.params.doDocComments) m->gendocfile(); - } } // internal linking for singleobj diff --git a/gen/aa.h b/gen/aa.h index ac941451..b1185b51 100644 --- a/gen/aa.h +++ b/gen/aa.h @@ -19,7 +19,7 @@ enum TOK; class DValue; struct Loc; -struct Type; +class Type; namespace llvm { class Value; } DValue* DtoAAIndex(Loc& loc, Type* type, DValue* aa, DValue* key, bool lvalue); diff --git a/gen/abi-x86-64.cpp b/gen/abi-x86-64.cpp index 1e6a539d..fece68ab 100644 --- a/gen/abi-x86-64.cpp +++ b/gen/abi-x86-64.cpp @@ -177,10 +177,9 @@ namespace { } } } else if (ty->ty == Tstruct) { - Array* fields = &static_cast(ty)->sym->fields; - for (size_t i = 0; i < fields->dim; i++) { - VarDeclaration* field = static_cast(fields->data[i]); - classifyType(accum, field->type, offset + field->offset); + VarDeclarations& fields = static_cast(ty)->sym->fields; + for (size_t i = 0; i < fields.dim; i++) { + classifyType(accum, fields[i]->type, offset + fields[i]->offset); } } else { if (Logger::enabled()) diff --git a/gen/abi.h b/gen/abi.h index 66da7dfe..1338e4f0 100644 --- a/gen/abi.h +++ b/gen/abi.h @@ -25,8 +25,8 @@ #endif #include -struct Type; -struct TypeFunction; +class Type; +class TypeFunction; struct IrFuncTy; struct IrFuncTyArg; class DValue; diff --git a/gen/arrays.h b/gen/arrays.h index f72a912a..eb31eb4d 100644 --- a/gen/arrays.h +++ b/gen/arrays.h @@ -17,14 +17,14 @@ #include "lexer.h" #include "gen/llvm.h" -struct ArrayInitializer; -struct ArrayLiteralExp; +class ArrayInitializer; +class ArrayLiteralExp; class DSliceValue; class DValue; -struct Expression; +class Expression; struct IRState; struct Loc; -struct Type; +class Type; llvm::StructType* DtoArrayType(Type* arrayTy); llvm::StructType* DtoArrayType(LLType* elemTy); diff --git a/gen/asm-x86.h b/gen/asm-x86.h index 1d5ea7d7..b5d7ca51 100644 --- a/gen/asm-x86.h +++ b/gen/asm-x86.h @@ -1870,7 +1870,7 @@ namespace AsmParserx8664 Reg segmentPrefix; Reg reg; sinteger_t constDisplacement; // use to build up.. should be int constant in the end.. - Array symbolDisplacement; // array of expressions or.. + Expressions symbolDisplacement; // array of expressions or.. Reg baseReg; Reg indexReg; int scale; @@ -3158,7 +3158,7 @@ namespace AsmParserx8664 llvm_unreachable("Unknown integer operation."); } e = e->semantic ( sc ); - return e->optimize ( WANTvalue | WANTinterpret ); + return e->ctfeInterpret(); } else { @@ -3626,7 +3626,7 @@ namespace AsmParserx8664 // parse primary: DMD allows 'MyAlign' (const int) but not '2+2' // GAS is padding with NOPs last time I checked. - Expression * e = parseAsmExp()->optimize ( WANTvalue | WANTinterpret ); + Expression * e = parseAsmExp()->ctfeInterpret(); uinteger_t align = e->toUInteger(); if ( ( align & ( align - 1 ) ) == 0 ) diff --git a/gen/cl_helpers.h b/gen/cl_helpers.h index 3870119c..8b43b36e 100644 --- a/gen/cl_helpers.h +++ b/gen/cl_helpers.h @@ -19,8 +19,8 @@ #include "llvm/Support/Compiler.h" #include -template struct ArrayBase; -typedef ArrayBase Strings; +template struct Array; +typedef Array Strings; namespace opts { namespace cl = llvm::cl; diff --git a/gen/classes.cpp b/gen/classes.cpp index 75874099..af41debc 100644 --- a/gen/classes.cpp +++ b/gen/classes.cpp @@ -321,7 +321,7 @@ DValue* DtoDynamicCastObject(DValue* val, Type* _to) // Object _d_dynamic_cast(Object o, ClassInfo c) DtoResolveClass(ClassDeclaration::object); - DtoResolveClass(ClassDeclaration::classinfo); + DtoResolveClass(Type::typeinfoclass); llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_d_dynamic_cast"); LLFunctionType* funcTy = func->getFunctionType(); @@ -384,7 +384,7 @@ DValue* DtoDynamicCastInterface(DValue* val, Type* _to) // Object _d_interface_cast(void* p, ClassInfo c) DtoResolveClass(ClassDeclaration::object); - DtoResolveClass(ClassDeclaration::classinfo); + DtoResolveClass(Type::typeinfoclass); llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_d_interface_cast"); LLFunctionType* funcTy = func->getFunctionType(); @@ -467,7 +467,7 @@ LLValue* DtoVirtualFunctionPointer(DValue* inst, FuncDeclaration* fdecl, char* n { // sanity checks assert(fdecl->isVirtual()); - assert(!fdecl->isFinal()); + assert(!fdecl->isFinalFunc()); assert(inst->getType()->toBasetype()->ty == Tclass); // 0 is always ClassInfo/Interface* unless it is a CPP interface assert(fdecl->vtblIndex > 0 || (fdecl->vtblIndex == 0 && fdecl->linkage == LINKcpp)); @@ -650,7 +650,7 @@ LLConstant* DtoDefineClassInfo(ClassDeclaration* cd) IrAggr* ir = cd->ir.irAggr; assert(ir); - ClassDeclaration* cinfo = ClassDeclaration::classinfo; + ClassDeclaration* cinfo = Type::typeinfoclass; if (cinfo->fields.dim != 12) { @@ -659,7 +659,7 @@ LLConstant* DtoDefineClassInfo(ClassDeclaration* cd) } // use the rtti builder - RTTIBuilder b(ClassDeclaration::classinfo); + RTTIBuilder b(cinfo); LLConstant* c; diff --git a/gen/classes.h b/gen/classes.h index a451443e..658e792c 100644 --- a/gen/classes.h +++ b/gen/classes.h @@ -17,11 +17,11 @@ #include "gen/structs.h" -struct ClassDeclaration; -struct CtorDeclaration; -struct FuncDeclaration; -struct NewExp; -struct TypeClass; +class ClassDeclaration; +class CtorDeclaration; +class FuncDeclaration; +class NewExp; +class TypeClass; /// Resolves the llvm type for a class declaration void DtoResolveClass(ClassDeclaration* cd); @@ -41,7 +41,6 @@ llvm::Constant* DtoDefineClassInfo(ClassDeclaration* cd); DValue* DtoNewClass(Loc loc, TypeClass* type, NewExp* newexp); void DtoInitClass(TypeClass* tc, llvm::Value* dst); -DValue* DtoCallClassCtor(TypeClass* type, CtorDeclaration* ctor, Array* arguments, llvm::Value* mem); void DtoFinalizeClass(llvm::Value* inst); DValue* DtoCastClass(DValue* val, Type* to); diff --git a/gen/complex.h b/gen/complex.h index 17e5163f..9d385f4f 100644 --- a/gen/complex.h +++ b/gen/complex.h @@ -19,7 +19,7 @@ class DValue; struct Loc; -struct Type; +class Type; namespace llvm { class Constant; diff --git a/gen/declarations.cpp b/gen/declarations.cpp index 7d10f429..f209d1a6 100644 --- a/gen/declarations.cpp +++ b/gen/declarations.cpp @@ -340,13 +340,13 @@ void TemplateMixin::codegen(IRState *p) void AttribDeclaration::codegen(IRState *p) { - Array *d = include(NULL, NULL); + Dsymbols *d = include(NULL, NULL); if (d) { for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = static_cast(d->data[i]); - s->codegen(p); + { + (*d)[i]->codegen(p); } } } diff --git a/gen/dibuilder.cpp b/gen/dibuilder.cpp index 209a3254..46c331de 100644 --- a/gen/dibuilder.cpp +++ b/gen/dibuilder.cpp @@ -578,7 +578,7 @@ llvm::DISubprogram ldc::DIBuilder::EmitSubProgram(FuncDeclaration *fd) return DBuilder.createFunction( CU, // context fd->toPrettyChars(), // name - fd->mangle(), // linkage name + fd->mangleExact(), // linkage name file, // file fd->loc.linnum, // line no DIFnType, // type diff --git a/gen/dibuilder.h b/gen/dibuilder.h index 712391a4..5eb6faff 100644 --- a/gen/dibuilder.h +++ b/gen/dibuilder.h @@ -35,12 +35,12 @@ struct IRState; -struct ClassDeclaration; -struct Dsymbol; -struct FuncDeclaration; -struct Module; -struct Type; -struct VarDeclaration; +class ClassDeclaration; +class Dsymbol; +class FuncDeclaration; +class Module; +class Type; +class VarDeclaration; namespace llvm { class GlobalVariable; diff --git a/gen/dvalue.h b/gen/dvalue.h index ac48216e..d14237ba 100644 --- a/gen/dvalue.h +++ b/gen/dvalue.h @@ -20,10 +20,10 @@ #include "root.h" #include -struct Type; -struct Dsymbol; -struct VarDeclaration; -struct FuncDeclaration; +class Type; +class Dsymbol; +class VarDeclaration; +class FuncDeclaration; namespace llvm { diff --git a/gen/functions.cpp b/gen/functions.cpp index 2761991e..f2df0451 100644 --- a/gen/functions.cpp +++ b/gen/functions.cpp @@ -49,6 +49,8 @@ llvm::FunctionType* DtoFunctionType(Type* type, IrFuncTy &irFty, Type* thistype, // sanity check assert(type->ty == Tfunction); TypeFunction* f = static_cast(type); + assert(f->next && "Encountered function type with invalid return type; " + "trying to codegen function ignored by the frontend?"); TargetABI* abi = (f->linkage == LINKintrinsic ? TargetABI::getIntrinsic() : gABI); // Tell the ABI we're resolving a new function type @@ -158,7 +160,7 @@ llvm::FunctionType* DtoFunctionType(Type* type, IrFuncTy &irFty, Type* thistype, if (f->varargs == 1) { // _arguments - newIrFty.arg_arguments = new IrFuncTyArg(Type::typeinfo->type->arrayOf(), false); + newIrFty.arg_arguments = new IrFuncTyArg(Type::dtypeinfo->type->arrayOf(), false); lidx++; // _argptr #if LDC_LLVM_VER >= 303 @@ -298,7 +300,7 @@ llvm::FunctionType* DtoFunctionType(Type* type, IrFuncTy &irFty, Type* thistype, LLFunction* DtoInlineIRFunction(FuncDeclaration* fdecl) { - const char* mangled_name = fdecl->mangle(); + const char* mangled_name = fdecl->mangleExact(); TemplateInstance* tinst = fdecl->parent->isTemplateInstance(); assert(tinst); @@ -483,54 +485,56 @@ void DtoResolveFunction(FuncDeclaration* fdecl) if (fdecl->parent) if (TemplateInstance* tinst = fdecl->parent->isTemplateInstance()) { - TemplateDeclaration* tempdecl = tinst->tempdecl; - if (tempdecl->llvmInternal == LLVMva_arg) + if (TemplateDeclaration* tempdecl = tinst->tempdecl->isTemplateDeclaration()) { - Logger::println("magic va_arg found"); - fdecl->llvmInternal = LLVMva_arg; - fdecl->ir.resolved = true; - fdecl->ir.declared = true; - fdecl->ir.initialized = true; - fdecl->ir.defined = true; - return; // this gets mapped to an instruction so a declaration makes no sence - } - else if (tempdecl->llvmInternal == LLVMva_start) - { - Logger::println("magic va_start found"); - fdecl->llvmInternal = LLVMva_start; - } - else if (tempdecl->llvmInternal == LLVMintrinsic) - { - Logger::println("overloaded intrinsic found"); - fdecl->llvmInternal = LLVMintrinsic; - DtoOverloadedIntrinsicName(tinst, tempdecl, fdecl->intrinsicName); - fdecl->linkage = LINKintrinsic; - static_cast(fdecl->type)->linkage = LINKintrinsic; - } - else if (tempdecl->llvmInternal == LLVMinline_asm) - { - Logger::println("magic inline asm found"); - TypeFunction* tf = static_cast(fdecl->type); - if (tf->varargs != 1 || (fdecl->parameters && fdecl->parameters->dim != 0)) + if (tempdecl->llvmInternal == LLVMva_arg) { - error("invalid __asm declaration, must be a D style variadic with no explicit parameters"); - fatal(); + Logger::println("magic va_arg found"); + fdecl->llvmInternal = LLVMva_arg; + fdecl->ir.resolved = true; + fdecl->ir.declared = true; + fdecl->ir.initialized = true; + fdecl->ir.defined = true; + return; // this gets mapped to an instruction so a declaration makes no sence + } + else if (tempdecl->llvmInternal == LLVMva_start) + { + Logger::println("magic va_start found"); + fdecl->llvmInternal = LLVMva_start; + } + else if (tempdecl->llvmInternal == LLVMintrinsic) + { + Logger::println("overloaded intrinsic found"); + fdecl->llvmInternal = LLVMintrinsic; + DtoOverloadedIntrinsicName(tinst, tempdecl, fdecl->intrinsicName); + fdecl->linkage = LINKintrinsic; + static_cast(fdecl->type)->linkage = LINKintrinsic; + } + else if (tempdecl->llvmInternal == LLVMinline_asm) + { + Logger::println("magic inline asm found"); + TypeFunction* tf = static_cast(fdecl->type); + if (tf->varargs != 1 || (fdecl->parameters && fdecl->parameters->dim != 0)) + { + error("invalid __asm declaration, must be a D style variadic with no explicit parameters"); + fatal(); + } + fdecl->llvmInternal = LLVMinline_asm; + fdecl->ir.resolved = true; + fdecl->ir.declared = true; + fdecl->ir.initialized = true; + fdecl->ir.defined = true; + return; // this gets mapped to a special inline asm call, no point in going on. + } + else if (tempdecl->llvmInternal == LLVMinline_ir) + { + fdecl->llvmInternal = LLVMinline_ir; + fdecl->linkage = LINKc; + fdecl->ir.defined = true; + Type* type = fdecl->type; + assert(type->ty == Tfunction); + static_cast(type)->linkage = LINKc; } - fdecl->llvmInternal = LLVMinline_asm; - fdecl->ir.resolved = true; - fdecl->ir.declared = true; - fdecl->ir.initialized = true; - fdecl->ir.defined = true; - return; // this gets mapped to a special inline asm call, no point in going on. - } - else if (tempdecl->llvmInternal == LLVMinline_ir) - { - fdecl->llvmInternal = LLVMinline_ir; - fdecl->linkage = LINKc; - fdecl->ir.defined = true; - Type* type = fdecl->type; - assert(type->ty == Tfunction); - static_cast(type)->linkage = LINKc; } } @@ -747,7 +751,7 @@ void DtoDeclareFunction(FuncDeclaration* fdecl) if (fdecl->llvmInternal == LLVMintrinsic) mangledName = fdecl->intrinsicName; else - mangledName = fdecl->mangle(); + mangledName = fdecl->mangleExact(); mangledName = gABI->mangleForLLVM(mangledName, link); // construct function @@ -766,7 +770,7 @@ void DtoDeclareFunction(FuncDeclaration* fdecl) llvm::GlobalValue::ExternalLinkage, mangledName, gIR->module); } } else if (func->getFunctionType() != functype) { - error(fdecl->loc, "Function type does not match previously declared function with the same mangled name: %s", fdecl->mangle()); + error(fdecl->loc, "Function type does not match previously declared function with the same mangled name: %s", fdecl->mangleExact()); fatal(); } @@ -898,16 +902,56 @@ void DtoDeclareFunction(FuncDeclaration* fdecl) void DtoDefineFunction(FuncDeclaration* fd) { - DtoDeclareFunction(fd); - - assert(fd->ir.declared); - if (Logger::enabled()) Logger::println("DtoDefineFunction(%s): %s", fd->toPrettyChars(), fd->loc.toChars()); LOG_SCOPE; - // Be sure to call DtoDeclareFunction first, as LDC_inline_asm functions are - // "defined" there. TODO: Clean this up. + if (fd->ir.defined) return; + + // Skip generating code if this part of a TemplateInstance that is instantiated + // only by non-root modules (i.e. modules not listed on the command line). + // See DMD's FuncDeclaration::toObjFile. Check this before calling + // DtoDeclareFunction DtoDeclareFunction to avoid touching unanalyzed code. + TemplateInstance *ti = fd->inTemplateInstance(); + if (!global.params.useUnitTests && + ti && ti->instantiatingModule && !ti->instantiatingModule->isRoot()) + { + Module *mi = ti->instantiatingModule; + + // If mi imports any root modules, we still need to generate the code. + for (size_t i = 0; i < Module::amodules.dim; ++i) + { + Module *m = Module::amodules[i]; + m->insearch = 0; + } + bool importsRoot = false; + for (size_t i = 0; i < Module::amodules.dim; ++i) + { + Module *m = Module::amodules[i]; + if (m->isRoot() && mi->imports(m)) + { + importsRoot = true; + break; + } + } + for (size_t i = 0; i < Module::amodules.dim; ++i) + { + Module *m = Module::amodules[i]; + m->insearch = 0; + } + if (!importsRoot) + { + IF_LOG Logger::println("Ignoring; already instantiated in %s (%s)", ti->instantiatingModule->toChars(), ti->toChars()); + fd->ir.defined = true; + return; + } + } + + DtoDeclareFunction(fd); + assert(fd->ir.declared); + + // DtoResolveFunction might also set the defined flag for functions we + // should not touch. if (fd->ir.defined) return; fd->ir.defined = true; diff --git a/gen/functions.h b/gen/functions.h index 7c413ebd..3289d9a5 100644 --- a/gen/functions.h +++ b/gen/functions.h @@ -17,12 +17,12 @@ #include "mars.h" class DValue; -struct Expression; -struct FuncDeclaration; +class Expression; +class FuncDeclaration; struct IRAsmBlock; struct IrFuncTy; -struct Parameter; -struct Type; +class Parameter; +class Type; namespace llvm { class FunctionType; diff --git a/gen/irstate.h b/gen/irstate.h index 8083cad3..abd59ee4 100644 --- a/gen/irstate.h +++ b/gen/irstate.h @@ -46,14 +46,14 @@ extern const llvm::TargetData* gDataLayout; #endif extern TargetABI* gABI; -struct TypeFunction; -struct TypeStruct; -struct ClassDeclaration; -struct FuncDeclaration; -struct Module; -struct TypeStruct; +class TypeFunction; +class TypeStruct; +class ClassDeclaration; +class FuncDeclaration; +class Module; +class TypeStruct; struct BaseClass; -struct AnonDeclaration; +class AnonDeclaration; struct IrModule; diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 0819f2ed..5d58754a 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -1247,11 +1247,11 @@ DValue* DtoDeclarationExp(Dsymbol* declaration) { Logger::println("AttribDeclaration"); // choose the right set in case this is a conditional declaration - Array *d = a->include(NULL, NULL); + Dsymbols *d = a->include(NULL, NULL); if (d) for (unsigned i=0; i < d->dim; ++i) { - DtoDeclarationExp(static_cast(d->data[i])); + DtoDeclarationExp((*d)[i]); } } // mixin declaration @@ -1368,12 +1368,6 @@ LLConstant* DtoConstInitializer(Loc loc, Type* type, Initializer* init) Logger::println("const expression initializer"); _init = DtoConstExpInit(loc, type, ex->exp); } - else if (StructInitializer* si = init->isStructInitializer()) - { - Logger::println("const struct initializer"); - DtoResolveDsymbol(si->ad); - return si->ad->ir.irAggr->createStructInitializer(si); - } else if (ArrayInitializer* ai = init->isArrayInitializer()) { Logger::println("const array initializer"); @@ -1385,7 +1379,10 @@ LLConstant* DtoConstInitializer(Loc loc, Type* type, Initializer* init) LLType* ty = voidToI8(DtoType(type)); _init = LLConstant::getNullValue(ty); } - else { + else + { + // StructInitializer is no longer suposed to make it to the glue layer + // in DMD 2.064. Logger::println("unsupported const initializer: %s", init->toChars()); } return _init; @@ -1488,7 +1485,7 @@ LLConstant* DtoTypeInfoOf(Type* type, bool base) LLConstant* c = isaConstant(tidecl->ir.irGlobal->value); assert(c != NULL); if (base) - return llvm::ConstantExpr::getBitCast(c, DtoType(Type::typeinfo->type)); + return llvm::ConstantExpr::getBitCast(c, DtoType(Type::dtypeinfo->type)); return c; } diff --git a/gen/module.cpp b/gen/module.cpp index 7685d894..84fc662a 100644 --- a/gen/module.cpp +++ b/gen/module.cpp @@ -382,10 +382,6 @@ llvm::Module* Module::genLLVMModule(llvm::LLVMContext& context) error("is missing 'class Object'"); fatal(); } - if (!ClassDeclaration::classinfo) { - error("is missing 'class ClassInfo'"); - fatal(); - } LLVM_D_InitRuntime(); @@ -471,8 +467,8 @@ void Module::genmoduleinfo() // check for patch else { - unsigned sizeof_ModuleInfo = 16 * Target::ptrsize; - if (sizeof_ModuleInfo != moduleinfo->structsize) + // The base struct should consist only of _flags/_index. + if (moduleinfo->structsize != 4 + 4) { error("object.d ModuleInfo class is incorrect"); fatal(); @@ -484,7 +480,7 @@ void Module::genmoduleinfo() // some types LLType* moduleinfoTy = moduleinfo->type->irtype->getLLType(); - LLType* classinfoTy = ClassDeclaration::classinfo->type->irtype->getLLType(); + LLType* classinfoTy = Type::typeinfoclass->type->irtype->getLLType(); // importedModules[] std::vector importInits; diff --git a/gen/naked.cpp b/gen/naked.cpp index 0e598091..7cd6a1b5 100644 --- a/gen/naked.cpp +++ b/gen/naked.cpp @@ -96,7 +96,7 @@ void LabelStatement::toNakedIR(IRState *p) Logger::println("LabelStatement::toNakedIR(): %s", loc.toChars()); LOG_SCOPE; - printLabelName(p->nakedAsm, p->func()->decl->mangle(), ident->toChars()); + printLabelName(p->nakedAsm, p->func()->decl->mangleExact(), ident->toChars()); p->nakedAsm << ":"; if (statement) @@ -107,7 +107,7 @@ void LabelStatement::toNakedIR(IRState *p) void DtoDefineNakedFunction(FuncDeclaration* fd) { - Logger::println("DtoDefineNakedFunction(%s)", fd->mangle()); + Logger::println("DtoDefineNakedFunction(%s)", fd->mangleExact()); LOG_SCOPE; assert(fd->ir.irFunc); @@ -122,7 +122,7 @@ void DtoDefineNakedFunction(FuncDeclaration* fd) // FIXME: could we perhaps use llvm asmwriter to give us these details ? - const char* mangle = fd->mangle(); + const char* mangle = fd->mangleExact(); std::ostringstream tmpstr; bool const isWin = global.params.targetTriple.isOSWindows(); @@ -215,7 +215,7 @@ void DtoDefineNakedFunction(FuncDeclaration* fd) void emitABIReturnAsmStmt(IRAsmBlock* asmblock, Loc loc, FuncDeclaration* fdecl) { - Logger::println("emitABIReturnAsmStmt(%s)", fdecl->mangle()); + Logger::println("emitABIReturnAsmStmt(%s)", fdecl->mangleExact()); LOG_SCOPE; IRAsmStmt* as = new IRAsmStmt; diff --git a/gen/pragma.h b/gen/pragma.h index 2763bd0b..3bdcf910 100644 --- a/gen/pragma.h +++ b/gen/pragma.h @@ -16,8 +16,8 @@ #include -struct PragmaDeclaration; -struct Dsymbol; +class PragmaDeclaration; +class Dsymbol; struct Scope; enum Pragma diff --git a/gen/rttibuilder.h b/gen/rttibuilder.h index ebacc098..ff35e43f 100644 --- a/gen/rttibuilder.h +++ b/gen/rttibuilder.h @@ -22,14 +22,14 @@ #include "llvm/Constant.h" #endif -struct AggregateDeclaration; -struct ClassDeclaration; -struct Dsymbol; -struct FuncDeclaration; +class AggregateDeclaration; +class ClassDeclaration; +class Dsymbol; +class FuncDeclaration; struct IrGlobal; struct IrAggr; -struct Type; -struct TypeClass; +class Type; +class TypeClass; namespace llvm { class StructType; } struct RTTIBuilder diff --git a/gen/runtime.cpp b/gen/runtime.cpp index 60b748f1..72a80a62 100644 --- a/gen/runtime.cpp +++ b/gen/runtime.cpp @@ -188,8 +188,8 @@ static void LLVM_D_BuildRuntimeModule() LLType* dstringTy = DtoType(Type::tdchar->arrayOf()); LLType* objectTy = DtoType(ClassDeclaration::object->type); - LLType* classInfoTy = DtoType(ClassDeclaration::classinfo->type); - LLType* typeInfoTy = DtoType(Type::typeinfo->type); + LLType* classInfoTy = DtoType(Type::typeinfoclass->type); + LLType* typeInfoTy = DtoType(Type::dtypeinfo->type); LLType* aaTypeInfoTy = DtoType(Type::typeinfoassociativearray->type); LLType* aaTy = rt_ptr(LLStructType::get(gIR->context())); diff --git a/gen/statements.cpp b/gen/statements.cpp index a166102a..39245cba 100644 --- a/gen/statements.cpp +++ b/gen/statements.cpp @@ -805,7 +805,7 @@ void ThrowStatement::toIR(IRState* p) ////////////////////////////////////////////////////////////////////////////// // used to build the sorted list of cases -struct Case : Object +struct Case : RootObject { StringExp* str; size_t index; @@ -815,7 +815,7 @@ struct Case : Object index = i; } - int compare(Object *obj) { + int compare(RootObject *obj) { Case* c2 = static_cast(obj); return str->compare(c2->str); } @@ -922,7 +922,7 @@ void SwitchStatement::toIR(IRState* p) { // string switch? llvm::Value* switchTable = 0; - Array caseArray; + Objects caseArray; if (!condition->type->isintegral()) { Logger::println("is string switch"); @@ -1388,7 +1388,7 @@ void LabelStatement::toIR(IRState* p) { IRAsmStmt* a = new IRAsmStmt; std::stringstream label; - printLabelName(label, p->func()->decl->mangle(), ident->toChars()); + printLabelName(label, p->func()->decl->mangleExact(), ident->toChars()); label << ":"; a->code = label.str(); p->asmBlock->s.push_back(a); diff --git a/gen/structs.cpp b/gen/structs.cpp index ed2171c9..173f9747 100644 --- a/gen/structs.cpp +++ b/gen/structs.cpp @@ -137,19 +137,18 @@ LLType* DtoUnpaddedStructType(Type* dty) { return it->second; TypeStruct* sty = static_cast(dty); - Array& fields = sty->sym->fields; + VarDeclarations& fields = sty->sym->fields; std::vector types; types.reserve(fields.dim); for (unsigned i = 0; i < fields.dim; i++) { - VarDeclaration* vd = static_cast(fields.data[i]); LLType* fty; - if (vd->type->ty == Tstruct) { + if (fields[i]->type->ty == Tstruct) { // Nested structs are the only members that can contain padding - fty = DtoUnpaddedStructType(vd->type); + fty = DtoUnpaddedStructType(fields[i]->type); } else { - fty = DtoType(vd->type); + fty = DtoType(fields[i]->type); } types.push_back(fty); } @@ -165,17 +164,16 @@ LLType* DtoUnpaddedStructType(Type* dty) { LLValue* DtoUnpaddedStruct(Type* dty, LLValue* v) { assert(dty->ty == Tstruct); TypeStruct* sty = static_cast(dty); - Array& fields = sty->sym->fields; + VarDeclarations& fields = sty->sym->fields; LLValue* newval = llvm::UndefValue::get(DtoUnpaddedStructType(dty)); for (unsigned i = 0; i < fields.dim; i++) { - VarDeclaration* vd = static_cast(fields.data[i]); - LLValue* fieldptr = DtoIndexStruct(v, sty->sym, vd); + LLValue* fieldptr = DtoIndexStruct(v, sty->sym, fields[i]); LLValue* fieldval; - if (vd->type->ty == Tstruct) { + if (fields[i]->type->ty == Tstruct) { // Nested structs are the only members that can contain padding - fieldval = DtoUnpaddedStruct(vd->type, fieldptr); + fieldval = DtoUnpaddedStruct(fields[i]->type, fieldptr); } else { fieldval = DtoLoad(fieldptr); } @@ -188,15 +186,14 @@ LLValue* DtoUnpaddedStruct(Type* dty, LLValue* v) { void DtoPaddedStruct(Type* dty, LLValue* v, LLValue* lval) { assert(dty->ty == Tstruct); TypeStruct* sty = static_cast(dty); - Array& fields = sty->sym->fields; + VarDeclarations& fields = sty->sym->fields; for (unsigned i = 0; i < fields.dim; i++) { - VarDeclaration* vd = static_cast(fields.data[i]); - LLValue* fieldptr = DtoIndexStruct(lval, sty->sym, vd); + LLValue* fieldptr = DtoIndexStruct(lval, sty->sym, fields[i]); LLValue* fieldval = DtoExtractValue(v, i); - if (vd->type->ty == Tstruct) { + if (fields[i]->type->ty == Tstruct) { // Nested structs are the only members that can contain padding - DtoPaddedStruct(vd->type, fieldval, fieldptr); + DtoPaddedStruct(fields[i]->type, fieldval, fieldptr); } else { DtoStore(fieldval, fieldptr); } diff --git a/gen/structs.h b/gen/structs.h index 2ae04e07..1dd4f25a 100644 --- a/gen/structs.h +++ b/gen/structs.h @@ -18,10 +18,10 @@ #include class DValue; -struct StructDeclaration; -struct StructInitializer; -struct Type; -struct VarDeclaration; +class StructDeclaration; +class StructInitializer; +class Type; +class VarDeclaration; namespace llvm { class Constant; diff --git a/gen/target.cpp b/gen/target.cpp index 6c2b8f39..64fc54c1 100644 --- a/gen/target.cpp +++ b/gen/target.cpp @@ -7,12 +7,17 @@ // //===----------------------------------------------------------------------===// -#include - #include "target.h" #include "gen/irstate.h" #include "mars.h" #include "mtype.h" +#include + +#if defined(_MSC_VER) +#include +#else +#include +#endif int Target::ptrsize; int Target::realsize; @@ -49,3 +54,19 @@ unsigned Target::fieldalign (Type* type) // LDC_FIXME: Verify this. return type->alignsize(); } + +// sizes based on those from tollvm.cpp:DtoMutexType() +unsigned Target::critsecsize() +{ +#if defined(_MSC_VER) + // Return sizeof(RTL_CRITICAL_SECTION) + return global.params.is64bit ? 40 : 24; +#else + if (global.params.targetTriple.isOSWindows()) + return global.params.is64bit ? 40 : 24; + else if (global.params.targetTriple.getOS() == llvm::Triple::FreeBSD) + return sizeof(size_t); + else + return sizeof(pthread_mutex_t); +#endif +} diff --git a/gen/tocall.cpp b/gen/tocall.cpp index f67a447e..9d0e2d16 100644 --- a/gen/tocall.cpp +++ b/gen/tocall.cpp @@ -269,7 +269,7 @@ void DtoBuildDVarArgList(std::vector& args, } // build type info array - LLType* typeinfotype = DtoType(Type::typeinfo->type); + LLType* typeinfotype = DtoType(Type::dtypeinfo->type); LLArrayType* typeinfoarraytype = LLArrayType::get(typeinfotype,vtype->getNumElements()); llvm::GlobalVariable* typeinfomem = @@ -294,7 +294,7 @@ void DtoBuildDVarArgList(std::vector& args, DtoConstSize_t(vtype->getNumElements()), llvm::ConstantExpr::getBitCast(typeinfomem, getPtrToType(typeinfotype)) }; - LLType* tiarrty = DtoType(Type::typeinfo->type->arrayOf()); + LLType* tiarrty = DtoType(Type::dtypeinfo->type->arrayOf()); tiinits = LLConstantStruct::get(isaStruct(tiarrty), llvm::ArrayRef(pinits)); LLValue* typeinfoarrayparam = new llvm::GlobalVariable(*gIR->module, tiarrty, true, llvm::GlobalValue::InternalLinkage, tiinits, "._arguments.array"); diff --git a/gen/toir.cpp b/gen/toir.cpp index 2f3acc09..e346a4cf 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -1589,8 +1589,8 @@ DValue* DotVarExp::toElem(IRState* p) // This is a bit more convoluted than it would need to be, because it // has to take templated interface methods into account, for which - // isFinal is not necessarily true. - const bool nonFinal = !fdecl->isFinal() && + // isFinalFunc is not necessarily true. + const bool nonFinal = !fdecl->isFinalFunc() && (fdecl->isAbstract() || fdecl->isVirtual()); // If we are calling a non-final interface function, we need to get @@ -2532,7 +2532,7 @@ DValue* DelegateExp::toElem(IRState* p) LLValue* castfptr; - if (e1->op != TOKsuper && e1->op != TOKdottype && func->isVirtual() && !func->isFinal()) + if (e1->op != TOKsuper && e1->op != TOKdottype && func->isVirtual() && !func->isFinalFunc()) castfptr = DtoVirtualFunctionPointer(u, func, toChars()); else if (func->isAbstract()) llvm_unreachable("Delegate to abstract method not implemented."); diff --git a/gen/tollvm.cpp b/gen/tollvm.cpp index 9bbaceaf..4ce5c3e9 100644 --- a/gen/tollvm.cpp +++ b/gen/tollvm.cpp @@ -937,7 +937,7 @@ LLStructType* DtoInterfaceInfoType() // build interface info type LLSmallVector types; // ClassInfo classinfo - ClassDeclaration* cd2 = ClassDeclaration::classinfo; + ClassDeclaration* cd2 = Type::typeinfoclass; DtoResolveClass(cd2); types.push_back(DtoType(cd2->type)); // void*[] vtbl diff --git a/gen/typeinf.h b/gen/typeinf.h index e2d37b6b..3c7edb6f 100644 --- a/gen/typeinf.h +++ b/gen/typeinf.h @@ -15,7 +15,7 @@ #ifndef LDC_GEN_TYPEINF_H #define LDC_GEN_TYPEINF_H -struct TypeInfoDeclaration; +class TypeInfoDeclaration; void DtoResolveTypeInfo(TypeInfoDeclaration* tid); void DtoConstInitTypeInfo(TypeInfoDeclaration* tid); diff --git a/gen/typinf.cpp b/gen/typinf.cpp index d1394a05..07b5917d 100644 --- a/gen/typinf.cpp +++ b/gen/typinf.cpp @@ -118,7 +118,7 @@ Expression *Type::getTypeInfo(Scope *sc) IF_LOG Logger::println("Type::getTypeInfo(): %s", toChars()); LOG_SCOPE - if (!Type::typeinfo) + if (!Type::dtypeinfo) { error(Loc(), "TypeInfo not found. object.d may be incorrectly installed or corrupt, compile with -v switch"); fatal(); @@ -343,7 +343,7 @@ void TypeInfoDeclaration::codegen(IRState* p) assert(irg->type->isStructTy()); } else { if (tinfo->builtinTypeInfo()) // this is a declaration of a builtin __initZ var - irg->type = Type::typeinfo->type->irtype->isClass()->getMemoryLLType(); + irg->type = Type::dtypeinfo->type->irtype->isClass()->getMemoryLLType(); else irg->type = LLStructType::create(gIR->context(), toPrettyChars()); irg->value = new llvm::GlobalVariable(*gIR->module, irg->type, true, @@ -370,7 +370,7 @@ void TypeInfoDeclaration::llvmDefine() Logger::println("TypeInfoDeclaration::llvmDefine() %s", toChars()); LOG_SCOPE; - RTTIBuilder b(Type::typeinfo); + RTTIBuilder b(Type::dtypeinfo); b.finalize(ir.irGlobal); } @@ -434,7 +434,7 @@ void TypeInfoEnumDeclaration::llvmDefine() // void[] init // emit void[] with the default initialier, the array is null if the default // initializer is zero - if (!sd->defaultval || tinfo->isZeroInit(Loc())) + if (!sd->members || tinfo->isZeroInit(loc)) { b.push_null_void_array(); } @@ -444,10 +444,11 @@ void TypeInfoEnumDeclaration::llvmDefine() Type *memtype = sd->memtype; LLType *memty = DtoType(memtype); LLConstant *C; + Expression *defaultval = sd->getDefaultValue(loc); if (memtype->isintegral()) - C = LLConstantInt::get(memty, sd->defaultval->toInteger(), !isLLVMUnsigned(memtype)); + C = LLConstantInt::get(memty, defaultval->toInteger(), !isLLVMUnsigned(memtype)); else if (memtype->isString()) - C = DtoConstString(static_cast(sd->defaultval->toString()->string)); + C = DtoConstString(static_cast(defaultval->toString()->string)); else llvm_unreachable("Unsupported type"); @@ -631,7 +632,7 @@ void TypeInfoStructDeclaration::llvmDefine() tftohash ->mod = MODconst; tftohash = static_cast(tftohash->semantic(Loc(), &sc)); - Type *retType = Type::tchar->invariantOf()->arrayOf(); + Type *retType = Type::tchar->immutableOf()->arrayOf(); tftostring = new TypeFunction(NULL, retType, 0, LINKd); tftostring = static_cast(tftostring->semantic(Loc(), &sc)); } @@ -708,7 +709,7 @@ void TypeInfoStructDeclaration::llvmDefine() b.push_typeinfo(targ); } else - b.push_null(Type::typeinfo->type); + b.push_null(Type::dtypeinfo->type); } } @@ -791,7 +792,7 @@ void TypeInfoTupleDeclaration::llvmDefine() std::vector arrInits; arrInits.reserve(dim); - LLType* tiTy = DtoType(Type::typeinfo->type); + LLType* tiTy = DtoType(Type::dtypeinfo->type); for (size_t i = 0; i < dim; i++) { @@ -806,7 +807,7 @@ void TypeInfoTupleDeclaration::llvmDefine() RTTIBuilder b(Type::typeinfotypelist); // push TypeInfo[] - b.push_array(arrC, dim, Type::typeinfo->type, NULL); + b.push_array(arrC, dim, Type::dtypeinfo->type, NULL); // finish b.finalize(ir.irGlobal); diff --git a/gen/utils.h b/gen/utils.h index b2c57b24..1c675142 100644 --- a/gen/utils.h +++ b/gen/utils.h @@ -20,26 +20,26 @@ template struct ArrayIter { - Array* array; + Array* array; size_t index; - ArrayIter(Array& arr, size_t idx = 0) + ArrayIter(Array& arr, size_t idx = 0) : array(&arr), index(idx) { } - ArrayIter(Array* arr, size_t idx = 0) + ArrayIter(Array* arr, size_t idx = 0) : array(arr), index(idx) { assert(arr && "null array"); } - ArrayIter& operator=(const Array& arr) + ArrayIter& operator=(const Array& arr) { - array = const_cast(&arr); + array = const_cast*>(&arr); index = 0; return *this; } - ArrayIter& operator=(const Array* arr) + ArrayIter& operator=(const Array* arr) { assert(arr && "null array"); - array = const_cast(arr); + array = const_cast*>(arr); index = 0; return *this; } @@ -54,7 +54,7 @@ struct ArrayIter } C* get() { - return static_cast(array->data[index]); + return (*array)[index]; } C* operator->() { return get(); diff --git a/ir/iraggr.cpp b/ir/iraggr.cpp index 2f457b1d..ef0f6945 100644 --- a/ir/iraggr.cpp +++ b/ir/iraggr.cpp @@ -127,68 +127,6 @@ size_t add_zeros(llvm::SmallVectorImpl& constants, size_t diff) ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// -LLConstant * IrAggr::createStructInitializer(StructInitializer * si) -{ - IF_LOG Logger::println("Building StructInitializer of type %s", si->ad->toPrettyChars()); - LOG_SCOPE; - - // sanity check - assert(si->ad == aggrdecl && "struct type mismatch"); - assert(si->vars.dim == si->value.dim && "inconsistent StructInitializer"); - - // array of things to build - VarInitMap initConsts; - - // fill in explicit initializers - const size_t n = si->vars.dim; - for (size_t i = 0; i < n; i++) - { - VarDeclaration* vd = si->vars[i]; - Initializer* ini = si->value[i]; - if (!ini) - { - // Unclear when this occurs - createInitializerConstant will just - // fill in default initializer. - continue; - } - - VarInitMap::iterator it, end = initConsts.end(); - for (it = initConsts.begin(); it != end; ++it) - { - if (it->first == vd) - { - error(ini->loc, "duplicate initialization of %s", vd->toChars()); - continue; - } - - const unsigned f_begin = it->first->offset; - const unsigned f_end = f_begin + it->first->type->size(); - - if (vd->offset < f_end && (vd->offset + vd->type->size()) > f_begin) - { - error(ini->loc, "initializer for %s overlaps previous initialization of %s", - vd->toChars(), it->first->toChars()); - } - } - - IF_LOG Logger::println("Explicit initializer: %s @+%u", vd->toChars(), vd->offset); - LOG_SCOPE; - - initConsts[vd] = DtoConstInitializer(ini->loc, vd->type, ini); - } - // stop if there were errors - if (global.errors) - { - fatal(); - } - - llvm::Constant* init = createInitializerConstant(initConsts, si->ltype); - si->ltype = static_cast(init->getType()); - return init; -} - -////////////////////////////////////////////////////////////////////////////// - typedef std::pair VarInitConst; static bool struct_init_data_sort(const VarInitConst& a, const VarInitConst& b) diff --git a/ir/iraggr.h b/ir/iraggr.h index 99d88d67..e050eef8 100644 --- a/ir/iraggr.h +++ b/ir/iraggr.h @@ -20,7 +20,7 @@ #include // DMD forward declarations -struct StructInitializer; +class StructInitializer; ////////////////////////////////////////////////////////////////////////////// @@ -64,9 +64,6 @@ struct IrAggr /// Create the __interfaceInfos symbol lazily. LLGlobalVariable* getInterfaceArraySymbol(); - /// Creates a StructInitializer constant. - LLConstant* createStructInitializer(StructInitializer* si); - ////////////////////////////////////////////////////////////////////////// /// Initialize interface. diff --git a/ir/irclass.cpp b/ir/irclass.cpp index a9618298..03ae5ae3 100644 --- a/ir/irclass.cpp +++ b/ir/irclass.cpp @@ -80,7 +80,7 @@ LLGlobalVariable * IrAggr::getClassInfoSymbol() // The type is also ClassInfo for interfaces – the actual TypeInfo for them // is a TypeInfo_Interface instance that references __ClassZ in its "base" // member. - ClassDeclaration* cinfo = ClassDeclaration::classinfo; + ClassDeclaration* cinfo = Type::typeinfoclass; DtoType(cinfo->type); IrTypeClass* tc = stripModifiers(cinfo->type)->irtype->isClass(); assert(tc && "invalid ClassInfo type"); @@ -127,7 +127,7 @@ LLGlobalVariable * IrAggr::getInterfaceArraySymbol() assert(n > 0 && "getting ClassInfo.interfaces storage symbol, but we " "don't implement any interfaces"); - VarDeclarationIter idx(ClassDeclaration::classinfo->fields, 3); + VarDeclarationIter idx(Type::typeinfoclass->fields, 3); LLType* InterfaceTy = DtoType(idx->type->nextOf()); // create Interface[N] @@ -162,7 +162,7 @@ LLConstant * IrAggr::getVtblInit() // start with the classinfo llvm::Constant* c = getClassInfoSymbol(); - c = DtoBitCast(c, DtoType(ClassDeclaration::classinfo->type)); + c = DtoBitCast(c, DtoType(Type::typeinfoclass->type)); constants.push_back(c); // add virtual function pointers @@ -285,7 +285,7 @@ llvm::GlobalVariable * IrAggr::getInterfaceVtbl(BaseClass * b, bool new_instance if (!b->base->isCPPinterface()) { // skip interface info for CPP interfaces // start with the interface info - VarDeclarationIter interfaces_idx(ClassDeclaration::classinfo->fields, 3); + VarDeclarationIter interfaces_idx(Type::typeinfoclass->fields, 3); // index into the interfaces array llvm::Constant* idxs[2] = { @@ -335,7 +335,7 @@ llvm::GlobalVariable * IrAggr::getInterfaceVtbl(BaseClass * b, bool new_instance OutBuffer name; name.writestring("Th"); name.printf("%i", b->offset); - name.writestring(fd->mangle()); + name.writestring(fd->mangleExact()); LLFunction *thunk = LLFunction::Create(isaFunction(fn->getType()->getContainedType(0)), DtoLinkage(fd), name.toChars(), gIR->module); @@ -414,7 +414,7 @@ LLConstant * IrAggr::getClassInfoInterfaces() assert(stripModifiers(type)->irtype->isClass()->getNumInterfaceVtbls() == n && "inconsistent number of interface vtables in this class"); - VarDeclarationIter interfaces_idx(ClassDeclaration::classinfo->fields, 3); + VarDeclarationIter interfaces_idx(Type::typeinfoclass->fields, 3); if (n == 0) return getNullValue(DtoType(interfaces_idx->type)); @@ -431,10 +431,10 @@ LLConstant * IrAggr::getClassInfoInterfaces() LLSmallVector constants; constants.reserve(cd->vtblInterfaces->dim); - LLType* classinfo_type = DtoType(ClassDeclaration::classinfo->type); + LLType* classinfo_type = DtoType(Type::typeinfoclass->type); LLType* voidptrptr_type = DtoType( Type::tvoid->pointerTo()->pointerTo()); - VarDeclarationIter idx(ClassDeclaration::classinfo->fields, 3); + VarDeclarationIter idx(Type::typeinfoclass->fields, 3); LLStructType* interface_type = isaStruct(DtoType(idx->type->nextOf())); assert(interface_type); diff --git a/ir/irdsymbol.h b/ir/irdsymbol.h index 62131628..cfa8fef0 100644 --- a/ir/irdsymbol.h +++ b/ir/irdsymbol.h @@ -24,8 +24,8 @@ struct IrLocal; struct IrParameter; struct IrField; struct IrVar; -struct Dsymbol; -struct Module; +class Dsymbol; +class Module; namespace llvm { class Value; diff --git a/ir/irforw.h b/ir/irforw.h index 87b46330..81509e18 100644 --- a/ir/irforw.h +++ b/ir/irforw.h @@ -16,26 +16,26 @@ #define LDC_IR_IRFORW_H // dmd forward declarations -struct Module; -struct Dsymbol; +class Module; +class Dsymbol; struct Declaration; -struct VarDeclaration; -struct FuncDeclaration; +class VarDeclaration; +class FuncDeclaration; struct AggregateDeclaration; -struct StructDeclaration; -struct ClassDeclaration; +class StructDeclaration; +class ClassDeclaration; struct InterfaceDeclaration; struct Expression; struct BaseClass; struct Array; struct Argument; -struct Type; -struct TypeStruct; -struct TypeClass; +class Type; +class TypeStruct; +class TypeClass; struct TypeEnum; struct TypeArray; -struct TypeFunction; +class TypeFunction; // llvm forward declarations namespace llvm diff --git a/ir/irfunction.h b/ir/irfunction.h index 55727ef4..4b9ef9d7 100644 --- a/ir/irfunction.h +++ b/ir/irfunction.h @@ -22,7 +22,7 @@ #include #include -struct Statement; +class Statement; struct EnclosingHandler; // scope statements that can be target of jumps diff --git a/ir/irfuncty.h b/ir/irfuncty.h index 66efc566..f2dfd419 100644 --- a/ir/irfuncty.h +++ b/ir/irfuncty.h @@ -26,7 +26,7 @@ #include class DValue; -struct Type; +class Type; struct ABIRewrite; namespace llvm { class Type; diff --git a/ir/irmodule.h b/ir/irmodule.h index bf5ee250..1991db38 100644 --- a/ir/irmodule.h +++ b/ir/irmodule.h @@ -15,7 +15,7 @@ #ifndef LDC_IR_IRMODULE_H #define LDC_IR_IRMODULE_H -struct Module; +class Module; namespace llvm { class GlobalVariable; diff --git a/ir/irtype.h b/ir/irtype.h index 6b388468..6bce1ec8 100644 --- a/ir/irtype.h +++ b/ir/irtype.h @@ -26,7 +26,7 @@ namespace llvm class Type; } -struct Type; +class Type; class IrTypeAggr; class IrTypeArray; diff --git a/ir/irtypeaggr.h b/ir/irtypeaggr.h index 2fdc7b9f..1342cfe7 100644 --- a/ir/irtypeaggr.h +++ b/ir/irtypeaggr.h @@ -25,8 +25,8 @@ namespace llvm { class StructType; } -struct AggregateDeclaration; -struct VarDeclaration; +class AggregateDeclaration; +class VarDeclaration; /// Base class of IrTypes for aggregate types. class IrTypeAggr : public IrType diff --git a/ir/irtypeclass.cpp b/ir/irtypeclass.cpp index de8c44be..f719cece 100644 --- a/ir/irtypeclass.cpp +++ b/ir/irtypeclass.cpp @@ -188,7 +188,7 @@ void IrTypeClass::addBaseClassData( ArrayIter it2(*base->vtblInterfaces); - VarDeclarationIter interfaces_idx(ClassDeclaration::classinfo->fields, 3); + VarDeclarationIter interfaces_idx(Type::typeinfoclass->fields, 3); Type* first = interfaces_idx->type->nextOf()->pointerTo(); // align offset @@ -284,7 +284,16 @@ IrTypeClass* IrTypeClass::get(ClassDeclaration* cd) // VTBL // set vtbl type body - t->vtbl_type->setBody(t->buildVtblType(ClassDeclaration::classinfo->type, &cd->vtbl)); + FuncDeclarations vtbl; + vtbl.reserve(cd->vtbl.dim); + vtbl.push(0); + for (size_t i = 1; i < cd->vtbl.dim; ++i) + { + FuncDeclaration *fd = cd->vtbl[i]->isFuncDeclaration(); + assert(fd); + vtbl.push(fd); + } + t->vtbl_type->setBody(t->buildVtblType(Type::typeinfoclass->type, &vtbl)); IF_LOG Logger::cout() << "class type: " << *t->type << std::endl; @@ -293,7 +302,7 @@ IrTypeClass* IrTypeClass::get(ClassDeclaration* cd) ////////////////////////////////////////////////////////////////////////////// -std::vector IrTypeClass::buildVtblType(Type* first, Array* vtbl_array) +std::vector IrTypeClass::buildVtblType(Type* first, FuncDeclarations* vtbl_array) { IF_LOG Logger::println("Building vtbl type for class %s", cd->toPrettyChars()); LOG_SCOPE; @@ -305,13 +314,13 @@ std::vector IrTypeClass::buildVtblType(Type* first, Array* vtbl_arr types.push_back(DtoType(first)); // then come the functions - ArrayIter it(*vtbl_array); + ArrayIter it(*vtbl_array); it.index = 1; for (; !it.done(); it.next()) { - Dsymbol* dsym = it.get(); - if (dsym == NULL) + FuncDeclaration* fd = it.get(); + if (fd == NULL) { // FIXME // why is this null? @@ -320,9 +329,6 @@ std::vector IrTypeClass::buildVtblType(Type* first, Array* vtbl_arr continue; } - FuncDeclaration* fd = dsym->isFuncDeclaration(); - assert(fd && "invalid vtbl entry"); - IF_LOG Logger::println("Adding type of %s", fd->toPrettyChars()); // If inferring return type and semantic3 has not been run, do it now. diff --git a/ir/irtypeclass.h b/ir/irtypeclass.h index 9b5fbf8e..9c4f41af 100644 --- a/ir/irtypeclass.h +++ b/ir/irtypeclass.h @@ -21,6 +21,9 @@ #include "llvm/DerivedTypes.h" #endif +template struct Array; +typedef Array FuncDeclarations; + /// class IrTypeClass : public IrTypeAggr { @@ -82,7 +85,7 @@ protected: /// Builds a vtable type given the type of the first entry and an array /// of all entries. - std::vector buildVtblType(Type* first, Array* vtbl_array); + std::vector buildVtblType(Type* first, FuncDeclarations* vtbl_array); /// void addBaseClassData( diff --git a/ir/irtypestruct.h b/ir/irtypestruct.h index 8c32dc5b..8247abe9 100644 --- a/ir/irtypestruct.h +++ b/ir/irtypestruct.h @@ -12,8 +12,8 @@ #include "ir/irtypeaggr.h" -struct StructDeclaration; -struct TypeStruct; +class StructDeclaration; +class TypeStruct; /// IrType for struct/union types. class IrTypeStruct : public IrTypeAggr diff --git a/ir/irvar.h b/ir/irvar.h index d4b00663..552b8e7b 100644 --- a/ir/irvar.h +++ b/ir/irvar.h @@ -22,7 +22,7 @@ #endif struct IrFuncTyArg; -struct VarDeclaration; +class VarDeclaration; struct IrVar { diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index f5fd158f..517bfb9c 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -89,7 +89,6 @@ if(APPLE) endif() file(GLOB_RECURSE CORE_D_UNIX ${RUNTIME_DIR}/src/core/sys/posix/*.d) file(GLOB_RECURSE CORE_D_FREEBSD ${RUNTIME_DIR}/src/core/sys/freebsd/*.d) -file(GLOB_RECURSE CORE_D_LINUX ${RUNTIME_DIR}/src/core/sys/linux/*.d) file(GLOB_RECURSE CORE_D_OSX ${RUNTIME_DIR}/src/core/sys/osx/*.d) file(GLOB_RECURSE CORE_D_WIN ${RUNTIME_DIR}/src/core/sys/windows/*.d) set(CORE_D_SYS) @@ -99,9 +98,6 @@ if(UNIX) if(${CMAKE_SYSTEM} MATCHES "FreeBSD") list(APPEND CORE_D_SYS ${CORE_D_FREEBSD}) endif() - if(${CMAKE_SYSTEM} MATCHES "Linux") - list(APPEND CORE_D_SYS ${CORE_D_LINUX}) - endif() list(APPEND DCRT_ASM ${RUNTIME_DIR}/src/core/threadasm.S) if(APPLE) list(APPEND CORE_D_SYS ${CORE_D_OSX}) diff --git a/runtime/druntime b/runtime/druntime index 822720b8..43854621 160000 --- a/runtime/druntime +++ b/runtime/druntime @@ -1 +1 @@ -Subproject commit 822720b8637bf5ad0d2301aa00807216a9d334bd +Subproject commit 438546212cf6d1b82d5e6174056aa689f4caeb3c diff --git a/runtime/phobos b/runtime/phobos index 89a22959..2b2d38ab 160000 --- a/runtime/phobos +++ b/runtime/phobos @@ -1 +1 @@ -Subproject commit 89a229598dae3f8d2d0542679873f18f0436b0ee +Subproject commit 2b2d38ab4ae811762d5bcec9adbdcadd4871513c