mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-08-15 19:00:05 +02:00
Merge v2.056
This commit is contained in:
@@ -186,6 +186,12 @@ list(REMOVE_ITEM FE_SRC
|
||||
${PROJECT_SOURCE_DIR}/${DMDFE_PATH}/id.c
|
||||
${PROJECT_SOURCE_DIR}/${DMDFE_PATH}/impcnvtab.c
|
||||
)
|
||||
# exclude root/win32.c on non-windows systems
|
||||
if(NOT WIN32)
|
||||
list(REMOVE_ITEM FE_SRC ${PROJECT_SOURCE_DIR}/${DMDFE_PATH}/root/win32.c)
|
||||
endif(NOT WIN32)
|
||||
# disable dmd gc
|
||||
list(REMOVE_ITEM FE_SRC ${PROJECT_SOURCE_DIR}/${DMDFE_PATH}/root/dmgcmem.c)
|
||||
set(LDC_SOURCE_FILES
|
||||
${LDC_GENERATED}
|
||||
${FE_SRC}
|
||||
|
||||
@@ -150,11 +150,13 @@ struct StructDeclaration : AggregateDeclaration
|
||||
int zeroInit; // !=0 if initialize with 0 fill
|
||||
#if DMDV2
|
||||
int hasIdentityAssign; // !=0 if has identity opAssign
|
||||
int hasIdentityEquals; // !=0 if has identity opEquals
|
||||
FuncDeclaration *cpctor; // generated copy-constructor, if any
|
||||
FuncDeclaration *eq; // bool opEquals(ref const T), if any
|
||||
|
||||
FuncDeclarations postblits; // Array of postblit functions
|
||||
FuncDeclaration *postblit; // aggregate postblit
|
||||
|
||||
FuncDeclaration *xeq; // TypeInfo_Struct.xopEquals
|
||||
static FuncDeclaration *xerreq; // object.xopEquals
|
||||
#endif
|
||||
|
||||
StructDeclaration(Loc loc, Identifier *id);
|
||||
@@ -174,6 +176,8 @@ struct StructDeclaration : AggregateDeclaration
|
||||
FuncDeclaration *buildOpEquals(Scope *sc);
|
||||
FuncDeclaration *buildPostBlit(Scope *sc);
|
||||
FuncDeclaration *buildCpCtor(Scope *sc);
|
||||
|
||||
FuncDeclaration *buildXopEquals(Scope *sc);
|
||||
#endif
|
||||
void toDocBuffer(OutBuffer *buf);
|
||||
|
||||
|
||||
@@ -52,7 +52,12 @@ void AliasThis::semantic(Scope *sc)
|
||||
assert(ad->members);
|
||||
Dsymbol *s = ad->search(loc, ident, 0);
|
||||
if (!s)
|
||||
::error(loc, "undefined identifier %s", ident->toChars());
|
||||
{ s = sc->search(loc, ident, 0);
|
||||
if (s)
|
||||
::error(loc, "%s is not a member of %s", s->toChars(), ad->toChars());
|
||||
else
|
||||
::error(loc, "undefined identifier %s", ident->toChars());
|
||||
}
|
||||
ad->aliasthis = s;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
// Copyright (c) 1999-2010 by Digital Mars
|
||||
// Copyright (c) 1999-2011 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
#include "rmem.h"
|
||||
|
||||
#include "stringtable.h"
|
||||
#include "aav.h"
|
||||
|
||||
#include "expression.h"
|
||||
#include "statement.h"
|
||||
@@ -31,7 +31,7 @@ extern int binary(const char *p , const char **tab, int high);
|
||||
* Hash table of array op functions already generated or known about.
|
||||
*/
|
||||
|
||||
StringTable arrayfuncs;
|
||||
AA *arrayfuncs;
|
||||
#endif
|
||||
|
||||
/**********************************************
|
||||
@@ -126,16 +126,17 @@ Expression *BinExp::arrayOp(Scope *sc)
|
||||
|
||||
size_t namelen = buf.offset;
|
||||
buf.writeByte(0);
|
||||
char *name = (char *)buf.extractData();
|
||||
char *name = buf.toChars();
|
||||
Identifier *ident = Lexer::idPool(name);
|
||||
|
||||
/* Look up name in hash table
|
||||
*/
|
||||
#if IN_LLVM
|
||||
StringValue *sv = sc->module->arrayfuncs.update(name, namelen);
|
||||
FuncDeclaration **pfd = (FuncDeclaration **)_aaGet(&sc->module->arrayfuncs, ident);
|
||||
#else
|
||||
StringValue *sv = arrayfuncs.update(name, namelen);
|
||||
FuncDeclaration **pfd = (FuncDeclaration **)_aaGet(&arrayfuncs, ident);
|
||||
#endif
|
||||
FuncDeclaration *fd = (FuncDeclaration *)sv->ptrvalue;
|
||||
FuncDeclaration *fd = (FuncDeclaration *)*pfd;
|
||||
if (!fd)
|
||||
{
|
||||
#if IN_DMD
|
||||
@@ -326,7 +327,7 @@ Expression *BinExp::arrayOp(Scope *sc)
|
||||
|
||||
Parameters *fparams = new Parameters();
|
||||
Expression *loopbody = buildArrayLoop(fparams);
|
||||
Parameter *p = fparams->tdata()[0 /*fparams->dim - 1*/];
|
||||
Parameter *p = (*fparams)[0 /*fparams->dim - 1*/];
|
||||
#if DMDV1
|
||||
// for (size_t i = 0; i < p.length; i++)
|
||||
Initializer *init = new ExpInitializer(0, new IntegerExp(0, 0, Type::tsize_t));
|
||||
@@ -352,7 +353,7 @@ Expression *BinExp::arrayOp(Scope *sc)
|
||||
*/
|
||||
TypeFunction *ftype = new TypeFunction(fparams, type, 0, LINKc);
|
||||
//printf("ftype: %s\n", ftype->toChars());
|
||||
fd = new FuncDeclaration(loc, 0, Lexer::idPool(name), STCundefined, ftype);
|
||||
fd = new FuncDeclaration(loc, 0, ident, STCundefined, ftype);
|
||||
fd->fbody = fbody;
|
||||
fd->protection = PROTpublic;
|
||||
fd->linkage = LINKd;
|
||||
@@ -373,10 +374,10 @@ Expression *BinExp::arrayOp(Scope *sc)
|
||||
else
|
||||
{ /* In library, refer to it.
|
||||
*/
|
||||
fd = FuncDeclaration::genCfunc(type, name);
|
||||
fd = FuncDeclaration::genCfunc(type, ident);
|
||||
}
|
||||
#endif
|
||||
sv->ptrvalue = fd; // cache symbol in hash table
|
||||
*pfd = fd; // cache symbol in hash table
|
||||
}
|
||||
|
||||
/* Call the function fd(arguments)
|
||||
@@ -537,7 +538,7 @@ Expression *AssignExp::buildArrayLoop(Parameters *fparams)
|
||||
ex2 = new CastExp(0, ex2, e1->type->nextOf());
|
||||
#endif
|
||||
Expression *ex1 = e1->buildArrayLoop(fparams);
|
||||
Parameter *param = fparams->tdata()[0];
|
||||
Parameter *param = (*fparams)[0];
|
||||
param->storageClass = 0;
|
||||
Expression *e = new AssignExp(0, ex1, ex2);
|
||||
return e;
|
||||
@@ -550,7 +551,7 @@ Expression *Str##AssignExp::buildArrayLoop(Parameters *fparams) \
|
||||
*/ \
|
||||
Expression *ex2 = e2->buildArrayLoop(fparams); \
|
||||
Expression *ex1 = e1->buildArrayLoop(fparams); \
|
||||
Parameter *param = fparams->tdata()[0]; \
|
||||
Parameter *param = (*fparams)[0]; \
|
||||
param->storageClass = 0; \
|
||||
Expression *e = new Str##AssignExp(0, ex1, ex2); \
|
||||
return e; \
|
||||
|
||||
@@ -384,6 +384,35 @@ Dsymbol *StorageClassDeclaration::syntaxCopy(Dsymbol *s)
|
||||
return scd;
|
||||
}
|
||||
|
||||
int StorageClassDeclaration::oneMember(Dsymbol **ps)
|
||||
{
|
||||
|
||||
int t = Dsymbol::oneMembers(decl, ps);
|
||||
if (t && *ps)
|
||||
{
|
||||
/* This is to deal with the following case:
|
||||
* struct Tick {
|
||||
* template to(T) { const T to() { ... } }
|
||||
* }
|
||||
* For eponymous function templates, the 'const' needs to get attached to 'to'
|
||||
* before the semantic analysis of 'to', so that template overloading based on the
|
||||
* 'this' pointer can be successful.
|
||||
*/
|
||||
|
||||
FuncDeclaration *fd = (*ps)->isFuncDeclaration();
|
||||
if (fd)
|
||||
{
|
||||
/* Use storage_class2 instead of storage_class otherwise when we do .di generation
|
||||
* we'll wind up with 'const const' rather than 'const'.
|
||||
*/
|
||||
/* Don't think we need to worry about mutually exclusive storage classes here
|
||||
*/
|
||||
fd->storage_class2 |= stc;
|
||||
}
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
void StorageClassDeclaration::setScope(Scope *sc)
|
||||
{
|
||||
if (decl)
|
||||
|
||||
@@ -73,6 +73,7 @@ struct StorageClassDeclaration: AttribDeclaration
|
||||
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||
void setScope(Scope *sc);
|
||||
void semantic(Scope *sc);
|
||||
int oneMember(Dsymbol **ps);
|
||||
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||
|
||||
static void stcToCBuffer(OutBuffer *buf, StorageClass stc);
|
||||
|
||||
109
dmd2/builtin.c
109
dmd2/builtin.c
@@ -43,6 +43,12 @@ enum 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)
|
||||
static const char FuintZint[] = "FNaNbkZi"; // pure nothrow int function(uint)
|
||||
static const char FuintZuint[] = "FNaNbkZk"; // pure nothrow uint function(uint)
|
||||
static const char FulongZulong[] = "FNaNbkZk"; // pure nothrow int function(ulong)
|
||||
static const char FulongZint[] = "FNaNbmZi"; // pure nothrow int function(uint)
|
||||
static const char FrealrealZreal [] = "FNaNbNfeeZe"; // @safe pure nothrow real function(real, real)
|
||||
static const char FrealZlong [] = "FNaNbNfeZl"; // @safe pure nothrow long function(real)
|
||||
|
||||
//printf("FuncDeclaration::isBuiltin() %s, %d\n", toChars(), builtin);
|
||||
if (builtin == BUILTINunknown)
|
||||
@@ -68,6 +74,10 @@ enum BUILTIN FuncDeclaration::isBuiltin()
|
||||
builtin = BUILTINsqrt;
|
||||
else if (ident == Id::fabs)
|
||||
builtin = BUILTINfabs;
|
||||
else if (ident == Id::expm1)
|
||||
builtin = BUILTINexpm1;
|
||||
else if (ident == Id::exp2)
|
||||
builtin = BUILTINexp2;
|
||||
//printf("builtin = %d\n", builtin);
|
||||
}
|
||||
// if float or double versions
|
||||
@@ -77,19 +87,83 @@ enum BUILTIN FuncDeclaration::isBuiltin()
|
||||
if (ident == Id::_sqrt)
|
||||
builtin = BUILTINsqrt;
|
||||
}
|
||||
else if (strcmp(type->deco, FrealrealZreal) == 0)
|
||||
{
|
||||
if (ident == Id::atan2)
|
||||
builtin = BUILTINatan2;
|
||||
else if (ident == Id::yl2x)
|
||||
builtin = BUILTINyl2x;
|
||||
else if (ident == Id::yl2xp1)
|
||||
builtin = BUILTINyl2xp1;
|
||||
}
|
||||
else if (strcmp(type->deco, FrealZlong) == 0 && ident == Id::rndtol)
|
||||
builtin = BUILTINrndtol;
|
||||
}
|
||||
if (parent->ident == Id::bitop &&
|
||||
parent->parent && parent->parent->ident == Id::core &&
|
||||
!parent->parent->parent)
|
||||
{
|
||||
//printf("deco = %s\n", type->deco);
|
||||
if (strcmp(type->deco, FuintZint) == 0 || strcmp(type->deco, FulongZint) == 0)
|
||||
{
|
||||
if (ident == Id::bsf)
|
||||
builtin = BUILTINbsf;
|
||||
else if (ident == Id::bsr)
|
||||
builtin = BUILTINbsr;
|
||||
}
|
||||
else if (strcmp(type->deco, FuintZuint) == 0)
|
||||
{
|
||||
if (ident == Id::bswap)
|
||||
builtin = BUILTINbswap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return builtin;
|
||||
}
|
||||
|
||||
int eval_bsf(uinteger_t n)
|
||||
{
|
||||
n = (n ^ (n - 1)) >> 1; // convert trailing 0s to 1, and zero rest
|
||||
int k = 0;
|
||||
while( n )
|
||||
{ ++k;
|
||||
n >>=1;
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
||||
int eval_bsr(uinteger_t n)
|
||||
{ int k= 0;
|
||||
while(n>>=1)
|
||||
{
|
||||
++k;
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
||||
uinteger_t eval_bswap(Expression *arg0)
|
||||
{ uinteger_t n = arg0->toInteger();
|
||||
#define BYTEMASK 0x00FF00FF00FF00FFLL
|
||||
#define SHORTMASK 0x0000FFFF0000FFFFLL
|
||||
#define INTMASK 0x0000FFFF0000FFFFLL
|
||||
// swap adjacent ubytes
|
||||
n = ((n >> 8 ) & BYTEMASK) | ((n & BYTEMASK) << 8 );
|
||||
// swap adjacent ushorts
|
||||
n = ((n >> 16) & SHORTMASK) | ((n & SHORTMASK) << 16);
|
||||
TY ty = arg0->type->toBasetype()->ty;
|
||||
// If 64 bits, we need to swap high and low uints
|
||||
if (ty == Tint64 || ty == Tuns64)
|
||||
n = ((n >> 32) & INTMASK) | ((n & INTMASK) << 32);
|
||||
return n;
|
||||
}
|
||||
|
||||
/**************************************
|
||||
* Evaluate builtin function.
|
||||
* Return result; NULL if cannot evaluate it.
|
||||
*/
|
||||
|
||||
Expression *eval_builtin(enum BUILTIN builtin, Expressions *arguments)
|
||||
Expression *eval_builtin(Loc loc, enum BUILTIN builtin, Expressions *arguments)
|
||||
{
|
||||
assert(arguments && arguments->dim);
|
||||
Expression *arg0 = arguments->tdata()[0];
|
||||
@@ -120,6 +194,39 @@ Expression *eval_builtin(enum BUILTIN builtin, Expressions *arguments)
|
||||
if (arg0->op == TOKfloat64)
|
||||
e = new RealExp(0, fabsl(arg0->toReal()), arg0->type);
|
||||
break;
|
||||
// These math intrinsics are not yet implemented
|
||||
case BUILTINatan2:
|
||||
break;
|
||||
case BUILTINrndtol:
|
||||
break;
|
||||
case BUILTINexpm1:
|
||||
break;
|
||||
case BUILTINexp2:
|
||||
break;
|
||||
case BUILTINyl2x:
|
||||
break;
|
||||
case BUILTINyl2xp1:
|
||||
break;
|
||||
case BUILTINbsf:
|
||||
if (arg0->op == TOKint64)
|
||||
{ if (arg0->toInteger()==0)
|
||||
error(loc, "bsf(0) is undefined");
|
||||
else
|
||||
e = new IntegerExp(loc, eval_bsf(arg0->toInteger()), Type::tint32);
|
||||
}
|
||||
break;
|
||||
case BUILTINbsr:
|
||||
if (arg0->op == TOKint64)
|
||||
{ if (arg0->toInteger()==0)
|
||||
error(loc, "bsr(0) is undefined");
|
||||
else
|
||||
e = new IntegerExp(loc, eval_bsr(arg0->toInteger()), Type::tint32);
|
||||
}
|
||||
break;
|
||||
case BUILTINbswap:
|
||||
if (arg0->op == TOKint64)
|
||||
e = new IntegerExp(loc, eval_bswap(arg0), arg0->type);
|
||||
break;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
20
dmd2/cast.c
20
dmd2/cast.c
@@ -143,6 +143,8 @@ MATCH Expression::implicitConvTo(Type *t)
|
||||
toChars(), type->toChars(), t->toChars());
|
||||
#endif
|
||||
//static int nest; if (++nest == 10) halt();
|
||||
if (t == Type::terror)
|
||||
return MATCHnomatch;
|
||||
if (!type)
|
||||
{ error("%s is not an expression", toChars());
|
||||
type = Type::terror;
|
||||
@@ -543,6 +545,10 @@ MATCH ArrayLiteralExp::implicitConvTo(Type *t)
|
||||
if (result == MATCHnomatch)
|
||||
break; // no need to check for worse
|
||||
}
|
||||
|
||||
if (!result)
|
||||
result = type->implicitConvTo(t);
|
||||
|
||||
return result;
|
||||
}
|
||||
else
|
||||
@@ -590,7 +596,7 @@ MATCH CallExp::implicitConvTo(Type *t)
|
||||
/* Allow the result of strongly pure functions to
|
||||
* convert to immutable
|
||||
*/
|
||||
if (f && f->isPure() == PUREstrong)
|
||||
if (f && f->isPure() == PUREstrong && !f->type->hasWild())
|
||||
return type->invariantOf()->implicitConvTo(t);
|
||||
|
||||
return MATCHnomatch;
|
||||
@@ -1720,7 +1726,8 @@ Lagain:
|
||||
if (t1 == t2)
|
||||
{
|
||||
}
|
||||
else if (t1->ty == Tpointer && t2->ty == Tpointer)
|
||||
else if ((t1->ty == Tpointer && t2->ty == Tpointer) ||
|
||||
(t1->ty == Tdelegate && t2->ty == Tdelegate))
|
||||
{
|
||||
// Bring pointers to compatible type
|
||||
Type *t1n = t1->nextOf();
|
||||
@@ -1760,7 +1767,14 @@ Lagain:
|
||||
else
|
||||
d->trust = TRUSTtrusted;
|
||||
|
||||
Type *tx = d->pointerTo();
|
||||
Type *tx = NULL;
|
||||
if (t1->ty == Tdelegate)
|
||||
{
|
||||
tx = new TypeDelegate(d);
|
||||
tx = tx->merge();
|
||||
}
|
||||
else
|
||||
tx = d->pointerTo();
|
||||
|
||||
if (t1->implicitConvTo(tx) && t2->implicitConvTo(tx))
|
||||
{
|
||||
|
||||
59
dmd2/class.c
59
dmd2/class.c
@@ -970,7 +970,10 @@ int ClassDeclaration::isFuncHidden(FuncDeclaration *fd)
|
||||
{
|
||||
FuncDeclaration *fdstart = s->isFuncDeclaration();
|
||||
//printf("%s fdstart = %p\n", s->kind(), fdstart);
|
||||
return !overloadApply(fdstart, &isf, fd);
|
||||
if (overloadApply(fdstart, &isf, fd))
|
||||
return 0;
|
||||
|
||||
return !fd->parent->isTemplateMixin();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -983,6 +986,8 @@ int ClassDeclaration::isFuncHidden(FuncDeclaration *fd)
|
||||
FuncDeclaration *ClassDeclaration::findFunc(Identifier *ident, TypeFunction *tf)
|
||||
{
|
||||
//printf("ClassDeclaration::findFunc(%s, %s) %s\n", ident->toChars(), tf->toChars(), toChars());
|
||||
FuncDeclaration *fdmatch = NULL;
|
||||
FuncDeclaration *fdambig = NULL;
|
||||
|
||||
ClassDeclaration *cd = this;
|
||||
Dsymbols *vtbl = &cd->vtbl;
|
||||
@@ -996,11 +1001,43 @@ FuncDeclaration *ClassDeclaration::findFunc(Identifier *ident, TypeFunction *tf)
|
||||
|
||||
//printf("\t[%d] = %s\n", i, fd->toChars());
|
||||
if (ident == fd->ident &&
|
||||
//tf->equals(fd->type)
|
||||
fd->type->covariant(tf) == 1
|
||||
)
|
||||
{ //printf("\t\tfound\n");
|
||||
return fd;
|
||||
fd->type->covariant(tf) == 1)
|
||||
{ //printf("fd->parent->isClassDeclaration() = %p", fd->parent->isClassDeclaration());
|
||||
if (!fdmatch)
|
||||
goto Lfd;
|
||||
|
||||
{
|
||||
// Function type matcing: exact > covariant
|
||||
int m1 = tf->equals(fd ->type) ? MATCHexact : MATCHnomatch;
|
||||
int m2 = tf->equals(fdmatch->type) ? MATCHexact : MATCHnomatch;
|
||||
if (m1 > m2)
|
||||
goto Lfd;
|
||||
else if (m1 < m2)
|
||||
goto Lfdmatch;
|
||||
}
|
||||
|
||||
{
|
||||
// The way of definition: non-mixin > mixin
|
||||
int m1 = fd ->parent->isClassDeclaration() ? MATCHexact : MATCHnomatch;
|
||||
int m2 = fdmatch->parent->isClassDeclaration() ? MATCHexact : MATCHnomatch;
|
||||
if (m1 > m2)
|
||||
goto Lfd;
|
||||
else if (m1 < m2)
|
||||
goto Lfdmatch;
|
||||
}
|
||||
|
||||
Lambig:
|
||||
fdambig = fd;
|
||||
//printf("Lambig fdambig = %s %s [%s]\n", fdambig->toChars(), fdambig->type->toChars(), fdambig->loc.toChars());
|
||||
continue;
|
||||
|
||||
Lfd:
|
||||
fdmatch = fd, fdambig = NULL;
|
||||
//printf("Lfd fdmatch = %s %s [%s]\n", fdmatch->toChars(), fdmatch->type->toChars(), fdmatch->loc.toChars());
|
||||
continue;
|
||||
|
||||
Lfdmatch:
|
||||
continue;
|
||||
}
|
||||
//else printf("\t\t%d\n", fd->type->covariant(tf));
|
||||
}
|
||||
@@ -1010,7 +1047,9 @@ FuncDeclaration *ClassDeclaration::findFunc(Identifier *ident, TypeFunction *tf)
|
||||
cd = cd->baseClass;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
if (fdambig)
|
||||
error("ambiguous virtual function %s", fdambig->toChars());
|
||||
return fdmatch;
|
||||
}
|
||||
|
||||
void ClassDeclaration::interfaceSemantic(Scope *sc)
|
||||
@@ -1302,15 +1341,15 @@ void InterfaceDeclaration::semantic(Scope *sc)
|
||||
}
|
||||
|
||||
sc = sc->push(this);
|
||||
sc->stc &= ~(STCfinal | STCauto | STCscope | STCstatic |
|
||||
STCabstract | STCdeprecated | STC_TYPECTOR | STCtls | STCgshared);
|
||||
sc->stc |= storage_class & STC_TYPECTOR;
|
||||
sc->stc &= STCsafe | STCtrusted | STCsystem;
|
||||
sc->parent = this;
|
||||
if (isCOMinterface())
|
||||
sc->linkage = LINKwindows;
|
||||
else if (isCPPinterface())
|
||||
sc->linkage = LINKcpp;
|
||||
sc->structalign = 8;
|
||||
sc->protection = PROTpublic;
|
||||
sc->explicitProtection = 0;
|
||||
structalign = sc->structalign;
|
||||
sc->offset = PTRSIZE * 2;
|
||||
inuse++;
|
||||
|
||||
234
dmd2/clone.c
234
dmd2/clone.c
@@ -21,6 +21,7 @@
|
||||
#include "expression.h"
|
||||
#include "statement.h"
|
||||
#include "init.h"
|
||||
#include "template.h"
|
||||
|
||||
|
||||
/*******************************************
|
||||
@@ -71,48 +72,6 @@ Lneed:
|
||||
#undef X
|
||||
}
|
||||
|
||||
/*******************************************
|
||||
* We need an opEquals for the struct if
|
||||
* any fields has an opEquals.
|
||||
* Generate one if a user-specified one does not exist.
|
||||
*/
|
||||
|
||||
int StructDeclaration::needOpEquals()
|
||||
{
|
||||
#define X 0
|
||||
if (X) printf("StructDeclaration::needOpEquals() %s\n", toChars());
|
||||
|
||||
/* If any of the fields has an opEquals, then we
|
||||
* need it too.
|
||||
*/
|
||||
for (size_t i = 0; i < fields.dim; i++)
|
||||
{
|
||||
Dsymbol *s = fields.tdata()[i];
|
||||
VarDeclaration *v = s->isVarDeclaration();
|
||||
assert(v && v->storage_class & STCfield);
|
||||
if (v->storage_class & STCref)
|
||||
continue;
|
||||
Type *tv = v->type->toBasetype();
|
||||
while (tv->ty == Tsarray)
|
||||
{ TypeSArray *ta = (TypeSArray *)tv;
|
||||
tv = tv->nextOf()->toBasetype();
|
||||
}
|
||||
if (tv->ty == Tstruct)
|
||||
{ TypeStruct *ts = (TypeStruct *)tv;
|
||||
StructDeclaration *sd = ts->sym;
|
||||
if (sd->eq)
|
||||
goto Lneed;
|
||||
}
|
||||
}
|
||||
if (X) printf("\tdontneed\n");
|
||||
return 0;
|
||||
|
||||
Lneed:
|
||||
if (X) printf("\tneed\n");
|
||||
return 1;
|
||||
#undef X
|
||||
}
|
||||
|
||||
/******************************************
|
||||
* Build opAssign for struct.
|
||||
* S* opAssign(S s) { ... }
|
||||
@@ -232,33 +191,99 @@ FuncDeclaration *StructDeclaration::buildOpAssign(Scope *sc)
|
||||
return fop;
|
||||
}
|
||||
|
||||
/*******************************************
|
||||
* We need an opEquals for the struct if
|
||||
* any fields has an opEquals.
|
||||
* Generate one if a user-specified one does not exist.
|
||||
*/
|
||||
|
||||
int StructDeclaration::needOpEquals()
|
||||
{
|
||||
#define X 0
|
||||
if (X) printf("StructDeclaration::needOpEquals() %s\n", toChars());
|
||||
|
||||
if (hasIdentityEquals)
|
||||
goto Lneed;
|
||||
|
||||
/* If any of the fields has an opEquals, then we
|
||||
* need it too.
|
||||
*/
|
||||
for (size_t i = 0; i < fields.dim; i++)
|
||||
{
|
||||
Dsymbol *s = fields.tdata()[i];
|
||||
VarDeclaration *v = s->isVarDeclaration();
|
||||
assert(v && v->storage_class & STCfield);
|
||||
if (v->storage_class & STCref)
|
||||
continue;
|
||||
Type *tv = v->type->toBasetype();
|
||||
while (tv->ty == Tsarray)
|
||||
{ TypeSArray *ta = (TypeSArray *)tv;
|
||||
tv = tv->nextOf()->toBasetype();
|
||||
}
|
||||
if (tv->ty == Tstruct)
|
||||
{ TypeStruct *ts = (TypeStruct *)tv;
|
||||
StructDeclaration *sd = ts->sym;
|
||||
if (sd->needOpEquals())
|
||||
goto Lneed;
|
||||
}
|
||||
}
|
||||
if (X) printf("\tdontneed\n");
|
||||
return 0;
|
||||
|
||||
Lneed:
|
||||
if (X) printf("\tneed\n");
|
||||
return 1;
|
||||
#undef X
|
||||
}
|
||||
|
||||
/******************************************
|
||||
* Build opEquals for struct.
|
||||
* const bool opEquals(const ref S s) { ... }
|
||||
* const bool opEquals(const S s) { ... }
|
||||
*/
|
||||
|
||||
FuncDeclaration *StructDeclaration::buildOpEquals(Scope *sc)
|
||||
{
|
||||
Dsymbol *eq = search_function(this, Id::eq);
|
||||
if (eq)
|
||||
{
|
||||
for (size_t i = 0; i <= 1; i++)
|
||||
{
|
||||
Expression *e =
|
||||
i == 0 ? new NullExp(loc, type->constOf()) // dummy rvalue
|
||||
: type->constOf()->defaultInit(); // dummy lvalue
|
||||
Expressions *arguments = new Expressions();
|
||||
arguments->push(e);
|
||||
|
||||
// check identity opEquals exists
|
||||
FuncDeclaration *fd = eq->isFuncDeclaration();
|
||||
if (fd)
|
||||
{ fd = fd->overloadResolve(loc, e, arguments, 1);
|
||||
if (fd && !(fd->storage_class & STCdisable))
|
||||
return fd;
|
||||
}
|
||||
|
||||
TemplateDeclaration *td = eq->isTemplateDeclaration();
|
||||
if (td)
|
||||
{ fd = td->deduceFunctionTemplate(sc, loc, NULL, e, arguments, 1);
|
||||
if (fd && !(fd->storage_class & STCdisable))
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!needOpEquals())
|
||||
return NULL;
|
||||
|
||||
//printf("StructDeclaration::buildOpEquals() %s\n", toChars());
|
||||
Loc loc = this->loc;
|
||||
|
||||
Parameters *parameters = new Parameters;
|
||||
#if STRUCTTHISREF
|
||||
// bool opEquals(ref const T) const;
|
||||
Parameter *param = new Parameter(STCref, type->constOf(), Id::p, NULL);
|
||||
#else
|
||||
// bool opEquals(const T*) const;
|
||||
Parameter *param = new Parameter(STCin, type->pointerTo(), Id::p, NULL);
|
||||
#endif
|
||||
parameters->push(new Parameter(STCin, type, Id::p, NULL));
|
||||
TypeFunction *tf = new TypeFunction(parameters, Type::tbool, 0, LINKd);
|
||||
tf->mod = MODconst;
|
||||
tf = (TypeFunction *)tf->semantic(loc, sc);
|
||||
|
||||
parameters->push(param);
|
||||
TypeFunction *ftype = new TypeFunction(parameters, Type::tbool, 0, LINKd);
|
||||
ftype->mod = MODconst;
|
||||
ftype = (TypeFunction *)ftype->semantic(loc, sc);
|
||||
|
||||
FuncDeclaration *fop = new FuncDeclaration(loc, 0, Id::eq, STCundefined, ftype);
|
||||
FuncDeclaration *fop = new FuncDeclaration(loc, 0, Id::eq, STCundefined, tf);
|
||||
|
||||
Expression *e = NULL;
|
||||
/* Do memberwise compare
|
||||
@@ -300,16 +325,90 @@ FuncDeclaration *StructDeclaration::buildOpEquals(Scope *sc)
|
||||
return fop;
|
||||
}
|
||||
|
||||
/******************************************
|
||||
* Build __xopEquals for TypeInfo_Struct
|
||||
* bool __xopEquals(in void* p, in void* q) { ... }
|
||||
*/
|
||||
|
||||
FuncDeclaration *StructDeclaration::buildXopEquals(Scope *sc)
|
||||
{
|
||||
if (!search_function(this, Id::eq))
|
||||
return NULL;
|
||||
|
||||
/* static bool__xopEquals(in void* p, in void* q) {
|
||||
* return ( *cast(const S*)(p) ).opEquals( *cast(const S*)(q) );
|
||||
* }
|
||||
*/
|
||||
|
||||
Parameters *parameters = new Parameters;
|
||||
parameters->push(new Parameter(STCin, Type::tvoidptr, Id::p, NULL));
|
||||
parameters->push(new Parameter(STCin, Type::tvoidptr, Id::q, NULL));
|
||||
TypeFunction *tf = new TypeFunction(parameters, Type::tbool, 0, LINKd);
|
||||
tf = (TypeFunction *)tf->semantic(loc, sc);
|
||||
|
||||
Identifier *id = Lexer::idPool("__xopEquals");
|
||||
FuncDeclaration *fop = new FuncDeclaration(loc, 0, id, STCstatic, tf);
|
||||
|
||||
Expression *e = new CallExp(0,
|
||||
new DotIdExp(0,
|
||||
new PtrExp(0, new CastExp(0,
|
||||
new IdentifierExp(0, Id::p), type->pointerTo()->constOf())),
|
||||
Id::eq),
|
||||
new PtrExp(0, new CastExp(0,
|
||||
new IdentifierExp(0, Id::q), type->pointerTo()->constOf())));
|
||||
|
||||
fop->fbody = new ReturnStatement(loc, e);
|
||||
|
||||
size_t index = members->dim;
|
||||
members->push(fop);
|
||||
|
||||
sc = sc->push();
|
||||
sc->stc = 0;
|
||||
sc->linkage = LINKd;
|
||||
|
||||
unsigned errors = global.startGagging();
|
||||
fop->semantic(sc);
|
||||
if (errors == global.gaggedErrors)
|
||||
{ fop->semantic2(sc);
|
||||
if (errors == global.gaggedErrors)
|
||||
{ fop->semantic3(sc);
|
||||
if (errors == global.gaggedErrors)
|
||||
fop->addMember(sc, this, 1);
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
sc->pop();
|
||||
|
||||
return fop;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************
|
||||
* Build copy constructor for struct.
|
||||
* Copy constructors are compiler generated only, and are only
|
||||
* callable from the compiler. They are not user accessible.
|
||||
* A copy constructor is:
|
||||
* void cpctpr(ref S s)
|
||||
* void cpctpr(ref const S s) const
|
||||
* {
|
||||
* *this = s;
|
||||
* this.postBlit();
|
||||
* (*cast(S*)&this) = *cast(S*)s;
|
||||
* (*cast(S*)&this).postBlit();
|
||||
* }
|
||||
* This is done so:
|
||||
* - postBlit() never sees uninitialized data
|
||||
@@ -329,10 +428,11 @@ FuncDeclaration *StructDeclaration::buildCpCtor(Scope *sc)
|
||||
{
|
||||
//printf("generating cpctor\n");
|
||||
|
||||
Parameter *param = new Parameter(STCref, type, Id::p, NULL);
|
||||
Parameter *param = new Parameter(STCref, type->constOf(), Id::p, NULL);
|
||||
Parameters *fparams = new Parameters;
|
||||
fparams->push(param);
|
||||
Type *ftype = new TypeFunction(fparams, Type::tvoid, FALSE, LINKd);
|
||||
ftype->mod = MODconst;
|
||||
|
||||
fcp = new FuncDeclaration(loc, 0, Id::cpctor, STCundefined, ftype);
|
||||
fcp->storage_class |= postblit->storage_class & STCdisable;
|
||||
@@ -344,12 +444,20 @@ FuncDeclaration *StructDeclaration::buildCpCtor(Scope *sc)
|
||||
#if !STRUCTTHISREF
|
||||
e = new PtrExp(0, e);
|
||||
#endif
|
||||
AssignExp *ea = new AssignExp(0, e, new IdentifierExp(0, Id::p));
|
||||
AssignExp *ea = new AssignExp(0,
|
||||
new PtrExp(0, new CastExp(0, new AddrExp(0, e), type->mutableOf()->pointerTo())),
|
||||
new PtrExp(0, new CastExp(0, new AddrExp(0, new IdentifierExp(0, Id::p)), type->mutableOf()->pointerTo()))
|
||||
);
|
||||
ea->op = TOKblit;
|
||||
Statement *s = new ExpStatement(0, ea);
|
||||
|
||||
// Build postBlit();
|
||||
e = new VarExp(0, postblit, 0);
|
||||
e = new ThisExp(0);
|
||||
#if !STRUCTTHISREF
|
||||
e = new PtrExp(0, e);
|
||||
#endif
|
||||
e = new PtrExp(0, new CastExp(0, new AddrExp(0, e), type->mutableOf()->pointerTo()));
|
||||
e = new DotVarExp(0, e, postblit, 0);
|
||||
e = new CallExp(0, e);
|
||||
|
||||
s = new CompoundStatement(0, s, new ExpStatement(0, e));
|
||||
|
||||
100
dmd2/constfold.c
100
dmd2/constfold.c
@@ -558,6 +558,83 @@ Expression *Mod(Type *type, Expression *e1, Expression *e2)
|
||||
return e;
|
||||
}
|
||||
|
||||
Expression *Pow(Type *type, Expression *e1, Expression *e2)
|
||||
{ Expression *e;
|
||||
Loc loc = e1->loc;
|
||||
|
||||
// Handle integer power operations.
|
||||
if (e2->type->isintegral())
|
||||
{
|
||||
Expression * r;
|
||||
Expression * v;
|
||||
dinteger_t n = e2->toInteger();
|
||||
bool neg;
|
||||
|
||||
if (!e2->type->isunsigned() && (sinteger_t)n < 0)
|
||||
{
|
||||
if (e1->type->isintegral())
|
||||
return EXP_CANT_INTERPRET;
|
||||
|
||||
// Don't worry about overflow, from now on n is unsigned.
|
||||
neg = true;
|
||||
n = -n;
|
||||
}
|
||||
else
|
||||
neg = false;
|
||||
|
||||
if (e1->type->isfloating())
|
||||
{
|
||||
r = new RealExp(loc, e1->toReal(), e1->type);
|
||||
v = new RealExp(loc, 1.0, e1->type);
|
||||
}
|
||||
else
|
||||
{
|
||||
r = new RealExp(loc, e1->toReal(), Type::tfloat64);
|
||||
v = new RealExp(loc, 1.0, Type::tfloat64);
|
||||
}
|
||||
|
||||
while (n != 0)
|
||||
{
|
||||
if (n & 1)
|
||||
v = Mul(v->type, v, r);
|
||||
n >>= 1;
|
||||
r = Mul(r->type, r, r);
|
||||
}
|
||||
|
||||
if (neg)
|
||||
v = Div(v->type, new RealExp(loc, 1.0, v->type), v);
|
||||
|
||||
if (type->isintegral())
|
||||
e = new IntegerExp(loc, v->toInteger(), type);
|
||||
else
|
||||
e = new RealExp(loc, v->toReal(), type);
|
||||
}
|
||||
else if (e2->type->isfloating())
|
||||
{
|
||||
// x ^^ y for x < 0 and y not an integer is not defined
|
||||
if (e1->toReal() < 0.0)
|
||||
{
|
||||
e = new RealExp(loc, Port::nan, type);
|
||||
}
|
||||
else if (e2->toReal() == 0.5)
|
||||
{
|
||||
// Special case: call sqrt directly.
|
||||
Expressions args;
|
||||
args.setDim(1);
|
||||
args.tdata()[0] = e1;
|
||||
e = eval_builtin(loc, BUILTINsqrt, &args);
|
||||
if (!e)
|
||||
e = EXP_CANT_INTERPRET;
|
||||
}
|
||||
else
|
||||
e = EXP_CANT_INTERPRET;
|
||||
}
|
||||
else
|
||||
e = EXP_CANT_INTERPRET;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
Expression *Shl(Type *type, Expression *e1, Expression *e2)
|
||||
{ Expression *e;
|
||||
Loc loc = e1->loc;
|
||||
@@ -581,6 +658,7 @@ Expression *Shr(Type *type, Expression *e1, Expression *e2)
|
||||
break;
|
||||
|
||||
case Tuns8:
|
||||
case Tchar:
|
||||
value = (d_uns8)(value) >> count;
|
||||
break;
|
||||
|
||||
@@ -589,6 +667,7 @@ Expression *Shr(Type *type, Expression *e1, Expression *e2)
|
||||
break;
|
||||
|
||||
case Tuns16:
|
||||
case Twchar:
|
||||
value = (d_uns16)(value) >> count;
|
||||
break;
|
||||
|
||||
@@ -597,6 +676,7 @@ Expression *Shr(Type *type, Expression *e1, Expression *e2)
|
||||
break;
|
||||
|
||||
case Tuns32:
|
||||
case Tdchar:
|
||||
value = (d_uns32)(value) >> count;
|
||||
break;
|
||||
|
||||
@@ -630,18 +710,21 @@ Expression *Ushr(Type *type, Expression *e1, Expression *e2)
|
||||
{
|
||||
case Tint8:
|
||||
case Tuns8:
|
||||
case Tchar:
|
||||
// Possible only with >>>=. >>> always gets promoted to int.
|
||||
value = (value & 0xFF) >> count;
|
||||
break;
|
||||
|
||||
case Tint16:
|
||||
case Tuns16:
|
||||
case Twchar:
|
||||
// Possible only with >>>=. >>> always gets promoted to int.
|
||||
value = (value & 0xFFFF) >> count;
|
||||
break;
|
||||
|
||||
case Tint32:
|
||||
case Tuns32:
|
||||
case Tdchar:
|
||||
value = (value & 0xFFFFFFFF) >> count;
|
||||
break;
|
||||
|
||||
@@ -1270,7 +1353,10 @@ Expression *Index(Type *type, Expression *e1, Expression *e2)
|
||||
uinteger_t i = e2->toInteger();
|
||||
|
||||
if (i >= es1->len)
|
||||
{
|
||||
e1->error("string index %ju is out of bounds [0 .. %zu]", i, es1->len);
|
||||
e = new ErrorExp();
|
||||
}
|
||||
else
|
||||
{
|
||||
e = new IntegerExp(loc, es1->charAt(i), type);
|
||||
@@ -1282,7 +1368,9 @@ Expression *Index(Type *type, Expression *e1, Expression *e2)
|
||||
uinteger_t i = e2->toInteger();
|
||||
|
||||
if (i >= length)
|
||||
{ e1->error("array index %ju is out of bounds %s[0 .. %ju]", i, e1->toChars(), length);
|
||||
{
|
||||
e1->error("array index %ju is out of bounds %s[0 .. %ju]", i, e1->toChars(), length);
|
||||
e = new ErrorExp();
|
||||
}
|
||||
else if (e1->op == TOKarrayliteral)
|
||||
{ ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
|
||||
@@ -1299,7 +1387,9 @@ Expression *Index(Type *type, Expression *e1, Expression *e2)
|
||||
if (e1->op == TOKarrayliteral)
|
||||
{ ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
|
||||
if (i >= ale->elements->dim)
|
||||
{ e1->error("array index %ju is out of bounds %s[0 .. %u]", i, e1->toChars(), ale->elements->dim);
|
||||
{
|
||||
e1->error("array index %ju is out of bounds %s[0 .. %u]", i, e1->toChars(), ale->elements->dim);
|
||||
e = new ErrorExp();
|
||||
}
|
||||
else
|
||||
{ e = ale->elements->tdata()[i];
|
||||
@@ -1353,7 +1443,10 @@ Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr)
|
||||
uinteger_t iupr = upr->toInteger();
|
||||
|
||||
if (iupr > es1->len || ilwr > iupr)
|
||||
{
|
||||
e1->error("string slice [%ju .. %ju] is out of bounds", ilwr, iupr);
|
||||
e = new ErrorExp();
|
||||
}
|
||||
else
|
||||
{
|
||||
void *s;
|
||||
@@ -1380,7 +1473,10 @@ Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr)
|
||||
uinteger_t iupr = upr->toInteger();
|
||||
|
||||
if (iupr > es1->elements->dim || ilwr > iupr)
|
||||
{
|
||||
e1->error("array slice [%ju .. %ju] is out of bounds", ilwr, iupr);
|
||||
e = new ErrorExp();
|
||||
}
|
||||
else
|
||||
{
|
||||
Expressions *elements = new Expressions();
|
||||
|
||||
@@ -107,6 +107,8 @@ void Declaration::checkModify(Loc loc, Scope *sc, Type *t)
|
||||
p = "const";
|
||||
else if (isImmutable())
|
||||
p = "immutable";
|
||||
else if (isWild())
|
||||
p = "inout";
|
||||
else if (storage_class & STCmanifest)
|
||||
p = "enum";
|
||||
else if (!t->isAssignable())
|
||||
@@ -291,14 +293,31 @@ void TypedefDeclaration::semantic(Scope *sc)
|
||||
//printf("TypedefDeclaration::semantic(%s) sem = %d\n", toChars(), sem);
|
||||
if (sem == SemanticStart)
|
||||
{ sem = SemanticIn;
|
||||
parent = sc->parent;
|
||||
int errors = global.errors;
|
||||
Type *savedbasetype = basetype;
|
||||
basetype = basetype->semantic(loc, sc);
|
||||
if (errors != global.errors)
|
||||
{
|
||||
basetype = savedbasetype;
|
||||
sem = SemanticStart;
|
||||
return;
|
||||
}
|
||||
sem = SemanticDone;
|
||||
#if DMDV2
|
||||
type = type->addStorageClass(storage_class);
|
||||
#endif
|
||||
Type *savedtype = type;
|
||||
type = type->semantic(loc, sc);
|
||||
if (sc->parent->isFuncDeclaration() && init)
|
||||
semantic2(sc);
|
||||
if (errors != global.errors)
|
||||
{
|
||||
basetype = savedbasetype;
|
||||
type = savedtype;
|
||||
sem = SemanticStart;
|
||||
return;
|
||||
}
|
||||
storage_class |= sc->stc & STCdeprecated;
|
||||
}
|
||||
else if (sem == SemanticIn)
|
||||
@@ -314,7 +333,14 @@ void TypedefDeclaration::semantic2(Scope *sc)
|
||||
{ sem = Semantic2Done;
|
||||
if (init)
|
||||
{
|
||||
Initializer *savedinit = init;
|
||||
int errors = global.errors;
|
||||
init = init->semantic(sc, basetype, WANTinterpret);
|
||||
if (errors != global.errors)
|
||||
{
|
||||
init = savedinit;
|
||||
return;
|
||||
}
|
||||
|
||||
ExpInitializer *ie = init->isExpInitializer();
|
||||
if (ie)
|
||||
@@ -440,6 +466,9 @@ void AliasDeclaration::semantic(Scope *sc)
|
||||
// type. If it is a symbol, then aliassym is set and type is NULL -
|
||||
// toAlias() will return aliasssym.
|
||||
|
||||
int errors = global.errors;
|
||||
Type *savedtype = type;
|
||||
|
||||
Dsymbol *s;
|
||||
Type *t;
|
||||
Expression *e;
|
||||
@@ -486,12 +515,15 @@ void AliasDeclaration::semantic(Scope *sc)
|
||||
}
|
||||
else if (t)
|
||||
{
|
||||
type = t;
|
||||
type = t->semantic(loc, sc);
|
||||
//printf("\talias resolved to type %s\n", type->toChars());
|
||||
}
|
||||
if (overnext)
|
||||
ScopeDsymbol::multiplyDefined(0, this, overnext);
|
||||
this->inSemantic = 0;
|
||||
|
||||
if (errors != global.errors)
|
||||
type = savedtype;
|
||||
return;
|
||||
|
||||
L2:
|
||||
@@ -505,6 +537,7 @@ void AliasDeclaration::semantic(Scope *sc)
|
||||
}
|
||||
else
|
||||
{
|
||||
Dsymbol *savedovernext = overnext;
|
||||
FuncDeclaration *f = s->toAlias()->isFuncDeclaration();
|
||||
if (f)
|
||||
{
|
||||
@@ -528,6 +561,14 @@ void AliasDeclaration::semantic(Scope *sc)
|
||||
assert(global.errors);
|
||||
s = NULL;
|
||||
}
|
||||
if (errors != global.errors)
|
||||
{
|
||||
type = savedtype;
|
||||
overnext = savedovernext;
|
||||
aliassym = NULL;
|
||||
inSemantic = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
//printf("setting aliassym %s to %s %s\n", toChars(), s->kind(), s->toChars());
|
||||
aliassym = s;
|
||||
@@ -585,7 +626,7 @@ Dsymbol *AliasDeclaration::toAlias()
|
||||
//static int count; if (++count == 10) *(char*)0=0;
|
||||
if (inSemantic)
|
||||
{ error("recursive alias declaration");
|
||||
aliassym = new TypedefDeclaration(loc, ident, Type::terror, NULL);
|
||||
aliassym = new AliasDeclaration(loc, ident, Type::terror);
|
||||
type = Type::terror;
|
||||
}
|
||||
else if (!aliassym && scope)
|
||||
@@ -988,6 +1029,8 @@ Lnomatch:
|
||||
}
|
||||
|
||||
VarDeclaration *v = new VarDeclaration(loc, arg->type, id, ti);
|
||||
if (arg->storageClass & STCparameter)
|
||||
v->storage_class |= arg->storageClass;
|
||||
//printf("declaring field %s of type %s\n", v->toChars(), v->type->toChars());
|
||||
v->semantic(sc);
|
||||
|
||||
@@ -1110,11 +1153,19 @@ Lnomatch:
|
||||
error("only parameters or foreach declarations can be ref");
|
||||
}
|
||||
|
||||
if ((storage_class & (STCstatic | STCextern | STCtls | STCgshared | STCmanifest) ||
|
||||
isDataseg()) &&
|
||||
type->hasWild())
|
||||
if (type->hasWild() &&
|
||||
!(type->ty == Tpointer && type->nextOf()->ty == Tfunction || type->ty == Tdelegate))
|
||||
{
|
||||
error("only fields, parameters or stack based variables can be inout");
|
||||
if (storage_class & (STCstatic | STCextern | STCtls | STCgshared | STCmanifest | STCfield) ||
|
||||
isDataseg()
|
||||
)
|
||||
{
|
||||
error("only parameters or stack based variables can be inout");
|
||||
}
|
||||
if (sc->func && !sc->func->type->hasWild())
|
||||
{
|
||||
error("inout variables can only be declared inside inout functions");
|
||||
}
|
||||
}
|
||||
|
||||
if (!(storage_class & (STCctfe | STCref)) && tb->ty == Tstruct &&
|
||||
@@ -1401,9 +1452,7 @@ Lnomatch:
|
||||
|
||||
if (!global.errors && !inferred)
|
||||
{
|
||||
unsigned errors = global.errors;
|
||||
global.gag++;
|
||||
//printf("+gag\n");
|
||||
unsigned errors = global.startGagging();
|
||||
Expression *e;
|
||||
Initializer *i2 = init;
|
||||
inuse++;
|
||||
@@ -1462,12 +1511,8 @@ Lnomatch:
|
||||
i2 = i2->semantic(sc, type, WANTinterpret);
|
||||
}
|
||||
inuse--;
|
||||
global.gag--;
|
||||
//printf("-gag\n");
|
||||
if (errors != global.errors) // if errors happened
|
||||
if (global.endGagging(errors)) // if errors happened
|
||||
{
|
||||
if (global.gag == 0)
|
||||
global.errors = errors; // act as if nothing happened
|
||||
#if DMDV2
|
||||
/* Save scope for later use, to try again
|
||||
*/
|
||||
|
||||
@@ -87,6 +87,7 @@ enum PURE;
|
||||
// but not typed as "shared"
|
||||
#define STCwild 0x80000000LL // for "wild" type constructor
|
||||
#define STC_TYPECTOR (STCconst | STCimmutable | STCshared | STCwild)
|
||||
#define STC_FUNCATTR (STCref | STCnothrow | STCpure | STCproperty | STCsafe | STCtrusted | STCsystem)
|
||||
|
||||
#define STCproperty 0x100000000LL
|
||||
#define STCsafe 0x200000000LL
|
||||
@@ -154,6 +155,7 @@ struct Declaration : Dsymbol
|
||||
int isAbstract() { return storage_class & STCabstract; }
|
||||
int isConst() { return storage_class & STCconst; }
|
||||
int isImmutable() { return storage_class & STCimmutable; }
|
||||
int isWild() { return storage_class & STCwild; }
|
||||
int isAuto() { return storage_class & STCauto; }
|
||||
int isScope() { return storage_class & STCscope; }
|
||||
int isSynchronized() { return storage_class & STCsynchronized; }
|
||||
@@ -680,9 +682,18 @@ enum BUILTIN
|
||||
BUILTINtan, // std.math.tan
|
||||
BUILTINsqrt, // std.math.sqrt
|
||||
BUILTINfabs, // std.math.fabs
|
||||
BUILTINatan2, // std.math.atan2
|
||||
BUILTINrndtol, // std.math.rndtol
|
||||
BUILTINexpm1, // std.math.expm1
|
||||
BUILTINexp2, // std.math.exp2
|
||||
BUILTINyl2x, // std.math.yl2x
|
||||
BUILTINyl2xp1, // std.math.yl2xp1
|
||||
BUILTINbsr, // core.bitop.bsr
|
||||
BUILTINbsf, // core.bitop.bsf
|
||||
BUILTINbswap, // core.bitop.bswap
|
||||
};
|
||||
|
||||
Expression *eval_builtin(enum BUILTIN builtin, Expressions *arguments);
|
||||
Expression *eval_builtin(Loc loc, enum BUILTIN builtin, Expressions *arguments);
|
||||
|
||||
#else
|
||||
enum BUILTIN { };
|
||||
@@ -729,6 +740,7 @@ struct FuncDeclaration : Declaration
|
||||
// of the 'introducing' function
|
||||
// this one is overriding
|
||||
int inferRetType; // !=0 if return type is to be inferred
|
||||
StorageClass storage_class2; // storage class for template onemember's
|
||||
|
||||
// Things that should really go into Scope
|
||||
int hasReturnExp; // 1 if there's a return exp; statement
|
||||
@@ -907,7 +919,6 @@ struct CtorDeclaration : FuncDeclaration
|
||||
CtorDeclaration(Loc loc, Loc endloc, StorageClass stc, Type *type);
|
||||
Dsymbol *syntaxCopy(Dsymbol *);
|
||||
void semantic(Scope *sc);
|
||||
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||
const char *kind();
|
||||
char *toChars();
|
||||
int isVirtual();
|
||||
|
||||
@@ -44,7 +44,11 @@ Expression *Expression::toDelegate(Scope *sc, Type *t)
|
||||
#else
|
||||
e = this->syntaxCopy();
|
||||
#endif
|
||||
Statement *s = new ReturnStatement(loc, e);
|
||||
Statement *s;
|
||||
if (t->ty == Tvoid)
|
||||
s = new ExpStatement(loc, e);
|
||||
else
|
||||
s = new ReturnStatement(loc, e);
|
||||
fld->fbody = s;
|
||||
e = new FuncExp(loc, fld);
|
||||
e = e->semantic(sc);
|
||||
|
||||
@@ -553,35 +553,28 @@ int Dsymbol::addMember(Scope *sc, ScopeDsymbol *sd, int memnum)
|
||||
void Dsymbol::error(const char *format, ...)
|
||||
{
|
||||
//printf("Dsymbol::error()\n");
|
||||
if (!global.gag)
|
||||
if (!loc.filename) // avoid bug 5861.
|
||||
{
|
||||
char *p = locToChars();
|
||||
Module *m = getModule();
|
||||
|
||||
if (*p)
|
||||
fprintf(stdmsg, "%s: ", p);
|
||||
mem.free(p);
|
||||
|
||||
fprintf(stdmsg, "Error: ");
|
||||
if (isAnonymous())
|
||||
fprintf(stdmsg, "%s ", kind());
|
||||
else
|
||||
fprintf(stdmsg, "%s %s ", kind(), toPrettyChars());
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vfprintf(stdmsg, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
fprintf(stdmsg, "\n");
|
||||
fflush(stdmsg);
|
||||
//halt();
|
||||
if (m && m->srcfile)
|
||||
loc.filename = m->srcfile->toChars();
|
||||
}
|
||||
global.errors++;
|
||||
|
||||
//fatal();
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
verror(loc, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void Dsymbol::error(Loc loc, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
verror(loc, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void Dsymbol::verror(Loc loc, const char *format, va_list ap)
|
||||
{
|
||||
if (!global.gag)
|
||||
{
|
||||
@@ -596,15 +589,16 @@ void Dsymbol::error(Loc loc, const char *format, ...)
|
||||
fprintf(stdmsg, "Error: ");
|
||||
fprintf(stdmsg, "%s %s ", kind(), toPrettyChars());
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vfprintf(stdmsg, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
fprintf(stdmsg, "\n");
|
||||
fflush(stdmsg);
|
||||
halt();
|
||||
}
|
||||
else
|
||||
{
|
||||
global.gaggedErrors++;
|
||||
}
|
||||
|
||||
global.errors++;
|
||||
|
||||
@@ -721,7 +715,7 @@ Dsymbols *Dsymbol::arraySyntaxCopy(Dsymbols *a)
|
||||
Dsymbols *b = NULL;
|
||||
if (a)
|
||||
{
|
||||
b = (Dsymbols *)a->copy();
|
||||
b = a->copy();
|
||||
for (size_t i = 0; i < b->dim; i++)
|
||||
{
|
||||
Dsymbol *s = (*b)[i];
|
||||
@@ -1032,11 +1026,19 @@ size_t ScopeDsymbol::dim(Dsymbols *members)
|
||||
for (size_t i = 0; i < members->dim; i++)
|
||||
{ Dsymbol *s = (*members)[i];
|
||||
AttribDeclaration *a = s->isAttribDeclaration();
|
||||
TemplateMixin *tm = s->isTemplateMixin();
|
||||
TemplateInstance *ti = s->isTemplateInstance();
|
||||
|
||||
if (a)
|
||||
{
|
||||
n += dim(a->decl);
|
||||
}
|
||||
else if (tm)
|
||||
{
|
||||
n += dim(tm->members);
|
||||
}
|
||||
else if (ti)
|
||||
;
|
||||
else
|
||||
n++;
|
||||
}
|
||||
@@ -1262,7 +1264,9 @@ Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags)
|
||||
* or a variable (in which case an expression is created in
|
||||
* toir.c).
|
||||
*/
|
||||
v->init = new VoidInitializer(0);
|
||||
VoidInitializer *e = new VoidInitializer(0);
|
||||
e->type = Type::tsize_t;
|
||||
v->init = e;
|
||||
}
|
||||
*pvar = v;
|
||||
}
|
||||
@@ -1279,6 +1283,7 @@ DsymbolTable::DsymbolTable()
|
||||
{
|
||||
#if STRINGTABLE
|
||||
tab = new StringTable;
|
||||
tab->init();
|
||||
#else
|
||||
tab = NULL;
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2010 by Digital Mars
|
||||
// Copyright (c) 1999-2011 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
@@ -151,6 +151,7 @@ struct Dsymbol : Object
|
||||
int isAnonymous();
|
||||
void error(Loc loc, const char *format, ...) IS_PRINTF(3);
|
||||
void error(const char *format, ...) IS_PRINTF(2);
|
||||
void verror(Loc loc, const char *format, va_list ap);
|
||||
void checkDeprecated(Loc loc, Scope *sc);
|
||||
Module *getModule(); // module where declared
|
||||
Module *getCompilationModule(); // possibly different for templates
|
||||
@@ -360,11 +361,7 @@ struct OverloadSet : Dsymbol
|
||||
|
||||
struct DsymbolTable : Object
|
||||
{
|
||||
#if STRINGTABLE
|
||||
StringTable *tab;
|
||||
#else
|
||||
AA *tab;
|
||||
#endif
|
||||
|
||||
DsymbolTable();
|
||||
~DsymbolTable();
|
||||
|
||||
@@ -649,6 +649,23 @@ Expression *callCpCtor(Loc loc, Scope *sc, Expression *e, int noscope)
|
||||
}
|
||||
#endif
|
||||
|
||||
// Check if this function is a member of a template which has only been
|
||||
// instantiated speculatively, eg from inside is(typeof()).
|
||||
// Return the speculative template instance it is part of,
|
||||
// or NULL if not speculative.
|
||||
TemplateInstance *isSpeculativeFunction(FuncDeclaration *fd)
|
||||
{
|
||||
Dsymbol * par = fd->parent;
|
||||
while (par)
|
||||
{
|
||||
TemplateInstance *ti = par->isTemplateInstance();
|
||||
if (ti && ti->speculative)
|
||||
return ti;
|
||||
par = par->toParent();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/****************************************
|
||||
* Now that we know the exact type of the function we're calling,
|
||||
* the arguments[] need to be adjusted:
|
||||
@@ -662,7 +679,7 @@ Expression *callCpCtor(Loc loc, Scope *sc, Expression *e, int noscope)
|
||||
*/
|
||||
|
||||
Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf,
|
||||
Expressions *arguments, FuncDeclaration *fd)
|
||||
Expression *ethis, Expressions *arguments, FuncDeclaration *fd)
|
||||
{
|
||||
//printf("functionParameters()\n");
|
||||
assert(arguments);
|
||||
@@ -675,7 +692,15 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf,
|
||||
|
||||
// If inferring return type, and semantic3() needs to be run if not already run
|
||||
if (!tf->next && fd->inferRetType)
|
||||
{
|
||||
TemplateInstance *spec = isSpeculativeFunction(fd);
|
||||
int olderrs = global.errors;
|
||||
fd->semantic3(fd->scope);
|
||||
// Update the template instantiation with the number
|
||||
// of errors which occured.
|
||||
if (spec && global.errors != olderrs)
|
||||
spec->errors = global.errors - olderrs;
|
||||
}
|
||||
|
||||
unsigned n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams)
|
||||
|
||||
@@ -718,7 +743,9 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf,
|
||||
//printf("\t\tvarargs == 2, p->type = '%s'\n", p->type->toChars());
|
||||
if (arg->implicitConvTo(p->type))
|
||||
{
|
||||
if (nargs != nparams)
|
||||
if (p->type->nextOf() && arg->implicitConvTo(p->type->nextOf()))
|
||||
goto L2;
|
||||
else if (nargs != nparams)
|
||||
{ error(loc, "expected %zu function arguments, not %zu", nparams, nargs);
|
||||
return tf->next;
|
||||
}
|
||||
@@ -801,7 +828,16 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf,
|
||||
L1:
|
||||
if (!(p->storageClass & STClazy && p->type->ty == Tvoid))
|
||||
{
|
||||
if (p->type != arg->type)
|
||||
if (p->type->hasWild())
|
||||
{ unsigned mod = p->type->wildMatch(arg->type);
|
||||
if (mod)
|
||||
{
|
||||
wildmatch |= mod;
|
||||
arg = arg->implicitCastTo(sc, p->type->substWildTo(mod));
|
||||
arg = arg->optimize(WANTvalue);
|
||||
}
|
||||
}
|
||||
else if (p->type != arg->type)
|
||||
{
|
||||
//printf("arg->type = %s, p->type = %s\n", arg->type->toChars(), p->type->toChars());
|
||||
if (arg->op == TOKtype)
|
||||
@@ -809,20 +845,6 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf,
|
||||
arg = new ErrorExp();
|
||||
goto L3;
|
||||
}
|
||||
if (p->type->isWild() && tf->next->isWild())
|
||||
{ Type *t = p->type;
|
||||
MATCH m = arg->implicitConvTo(t);
|
||||
if (m == MATCHnomatch)
|
||||
{ t = t->constOf();
|
||||
m = arg->implicitConvTo(t);
|
||||
if (m == MATCHnomatch)
|
||||
{ t = t->sharedConstOf();
|
||||
m = arg->implicitConvTo(t);
|
||||
}
|
||||
wildmatch |= p->type->wildMatch(arg->type);
|
||||
}
|
||||
arg = arg->implicitCastTo(sc, t);
|
||||
}
|
||||
else
|
||||
arg = arg->implicitCastTo(sc, p->type);
|
||||
arg = arg->optimize(WANTvalue);
|
||||
@@ -989,6 +1011,19 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf,
|
||||
break;
|
||||
}
|
||||
|
||||
if (ethis && tf->isWild())
|
||||
{
|
||||
Type *tthis = ethis->type;
|
||||
if (tthis->isWild())
|
||||
wildmatch |= MODwild;
|
||||
else if (tthis->isConst())
|
||||
wildmatch |= MODconst;
|
||||
else if (tthis->isImmutable())
|
||||
wildmatch |= MODimmutable;
|
||||
else
|
||||
wildmatch |= MODmutable;
|
||||
}
|
||||
|
||||
#if !IN_LLVM
|
||||
// If D linkage and variadic, add _arguments[] as first argument
|
||||
if (tf->linkage == LINKd && tf->varargs == 1)
|
||||
@@ -1003,15 +1038,16 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf,
|
||||
if (wildmatch)
|
||||
{ /* Adjust function return type based on wildmatch
|
||||
*/
|
||||
//printf("wildmatch = x%x\n", wildmatch);
|
||||
assert(tret->isWild());
|
||||
//printf("wildmatch = x%x, tret = %s\n", wildmatch, tret->toChars());
|
||||
if (wildmatch & MODconst || wildmatch & (wildmatch - 1))
|
||||
tret = tret->constOf();
|
||||
tret = tret->substWildTo(MODconst);
|
||||
else if (wildmatch & MODimmutable)
|
||||
tret = tret->invariantOf();
|
||||
tret = tret->substWildTo(MODimmutable);
|
||||
else if (wildmatch & MODwild)
|
||||
;
|
||||
else
|
||||
{ assert(wildmatch & MODmutable);
|
||||
tret = tret->mutableOf();
|
||||
tret = tret->substWildTo(MODmutable);
|
||||
}
|
||||
}
|
||||
return tret;
|
||||
@@ -1159,13 +1195,10 @@ Expression *Expression::semantic(Scope *sc)
|
||||
Expression *Expression::trySemantic(Scope *sc)
|
||||
{
|
||||
//printf("+trySemantic(%s)\n", toChars());
|
||||
unsigned errors = global.errors;
|
||||
global.gag++;
|
||||
unsigned errors = global.startGagging();
|
||||
Expression *e = semantic(sc);
|
||||
global.gag--;
|
||||
if (errors != global.errors)
|
||||
if (global.endGagging(errors))
|
||||
{
|
||||
global.errors = errors;
|
||||
e = NULL;
|
||||
}
|
||||
//printf("-trySemantic(%s)\n", toChars());
|
||||
@@ -2542,7 +2575,7 @@ Expression *IdentifierExp::semantic(Scope *sc)
|
||||
if (hasThis(sc))
|
||||
{
|
||||
AggregateDeclaration *ad = sc->getStructClassScope();
|
||||
if (ad->aliasthis)
|
||||
if (ad && ad->aliasthis)
|
||||
{
|
||||
Expression *e;
|
||||
e = new IdentifierExp(loc, Id::This);
|
||||
@@ -2648,9 +2681,10 @@ Lagain:
|
||||
return this;
|
||||
if (!s->isFuncDeclaration()) // functions are checked after overloading
|
||||
checkDeprecated(sc, s);
|
||||
Dsymbol *olds = s;
|
||||
s = s->toAlias();
|
||||
//printf("s = '%s', s->kind = '%s', s->needThis() = %p\n", s->toChars(), s->kind(), s->needThis());
|
||||
if (!s->isFuncDeclaration())
|
||||
if (s != olds && !s->isFuncDeclaration())
|
||||
checkDeprecated(sc, s);
|
||||
|
||||
if (sc->func)
|
||||
@@ -2727,7 +2761,15 @@ Lagain:
|
||||
|
||||
// if inferring return type, sematic3 needs to be run
|
||||
if (f->inferRetType && f->scope && f->type && !f->type->nextOf())
|
||||
{
|
||||
TemplateInstance *spec = isSpeculativeFunction(f);
|
||||
int olderrs = global.errors;
|
||||
f->semantic3(f->scope);
|
||||
// Update the template instantiation with the number
|
||||
// of errors which occured.
|
||||
if (spec && global.errors != olderrs)
|
||||
spec->errors = global.errors - olderrs;
|
||||
}
|
||||
|
||||
if (f->isUnitTestDeclaration())
|
||||
{
|
||||
@@ -2785,7 +2827,8 @@ Lagain:
|
||||
t = s->getType();
|
||||
if (t)
|
||||
{
|
||||
return new TypeExp(loc, t);
|
||||
TypeExp *te = new TypeExp(loc, t);
|
||||
return te->semantic(sc);
|
||||
}
|
||||
|
||||
TupleDeclaration *tup = s->isTupleDeclaration();
|
||||
@@ -2859,10 +2902,7 @@ ThisExp::ThisExp(Loc loc)
|
||||
}
|
||||
|
||||
Expression *ThisExp::semantic(Scope *sc)
|
||||
{ FuncDeclaration *fd;
|
||||
FuncDeclaration *fdthis;
|
||||
int nested = 0;
|
||||
|
||||
{
|
||||
#if LOGSEMANTIC
|
||||
printf("ThisExp::semantic()\n");
|
||||
#endif
|
||||
@@ -2874,13 +2914,15 @@ Expression *ThisExp::semantic(Scope *sc)
|
||||
return this;
|
||||
}
|
||||
|
||||
FuncDeclaration *fd = hasThis(sc); // fd is the uplevel function with the 'this' variable
|
||||
|
||||
/* Special case for typeof(this) and typeof(super) since both
|
||||
* should work even if they are not inside a non-static member function
|
||||
*/
|
||||
if (sc->intypeof)
|
||||
if (!fd && sc->intypeof)
|
||||
{
|
||||
// Find enclosing struct or class
|
||||
for (Dsymbol *s = sc->parent; 1; s = s->parent)
|
||||
for (Dsymbol *s = sc->getStructClassScope(); 1; s = s->parent)
|
||||
{
|
||||
if (!s)
|
||||
{
|
||||
@@ -2905,9 +2947,6 @@ Expression *ThisExp::semantic(Scope *sc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fdthis = sc->parent->isFuncDeclaration();
|
||||
fd = hasThis(sc); // fd is the uplevel function with the 'this' variable
|
||||
if (!fd)
|
||||
goto Lerr;
|
||||
|
||||
@@ -3823,7 +3862,10 @@ Expression *StructLiteralExp::semantic(Scope *sc)
|
||||
Initializer *i2 = v->init->syntaxCopy();
|
||||
i2 = i2->semantic(v->scope, v->type, WANTinterpret);
|
||||
e = i2->toExpression();
|
||||
v->scope = NULL;
|
||||
// remove v->scope (see bug 3426)
|
||||
// but not if gagged, for we might be called again.
|
||||
if (!global.gag)
|
||||
v->scope = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4358,7 +4400,7 @@ Lagain:
|
||||
|
||||
if (!arguments)
|
||||
arguments = new Expressions();
|
||||
functionParameters(loc, sc, tf, arguments, f);
|
||||
functionParameters(loc, sc, tf, NULL, arguments, f);
|
||||
|
||||
type = type->addMod(tf->nextOf()->mod);
|
||||
}
|
||||
@@ -4383,7 +4425,7 @@ Lagain:
|
||||
assert(allocator);
|
||||
|
||||
TypeFunction *tf = (TypeFunction *)f->type;
|
||||
functionParameters(loc, sc, tf, newargs, f);
|
||||
functionParameters(loc, sc, tf, NULL, newargs, f);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -4418,7 +4460,7 @@ Lagain:
|
||||
|
||||
if (!arguments)
|
||||
arguments = new Expressions();
|
||||
functionParameters(loc, sc, tf, arguments, f);
|
||||
functionParameters(loc, sc, tf, NULL, arguments, f);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -4442,7 +4484,7 @@ Lagain:
|
||||
assert(allocator);
|
||||
|
||||
tf = (TypeFunction *)f->type;
|
||||
functionParameters(loc, sc, tf, newargs, f);
|
||||
functionParameters(loc, sc, tf, NULL, newargs, f);
|
||||
#if 0
|
||||
e = new VarExp(loc, f);
|
||||
e = new CallExp(loc, e, newargs);
|
||||
@@ -4962,10 +5004,6 @@ Expression *TupleExp::semantic(Scope *sc)
|
||||
}
|
||||
|
||||
expandTuples(exps);
|
||||
if (0 && exps->dim == 1)
|
||||
{
|
||||
return (*exps)[0];
|
||||
}
|
||||
type = new TypeTuple(exps);
|
||||
type = type->semantic(loc, sc);
|
||||
//printf("-TupleExp::semantic(%s)\n", toChars());
|
||||
@@ -5027,27 +5065,28 @@ Expression *FuncExp::semantic(Scope *sc)
|
||||
#endif
|
||||
if (!type)
|
||||
{
|
||||
unsigned olderrors = global.errors;
|
||||
fd->semantic(sc);
|
||||
//fd->parent = sc->parent;
|
||||
if (global.errors)
|
||||
if (olderrors != global.errors)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
fd->semantic2(sc);
|
||||
if (!global.errors ||
|
||||
if ( (olderrors == global.errors) ||
|
||||
// need to infer return type
|
||||
(fd->type && fd->type->ty == Tfunction && !fd->type->nextOf()))
|
||||
{
|
||||
fd->semantic3(sc);
|
||||
|
||||
if (!global.errors && global.params.useInline)
|
||||
if ( (olderrors == global.errors) && global.params.useInline)
|
||||
fd->inlineScan();
|
||||
}
|
||||
}
|
||||
|
||||
// need to infer return type
|
||||
if (global.errors && fd->type && fd->type->ty == Tfunction && !fd->type->nextOf())
|
||||
if ((olderrors != global.errors) && fd->type && fd->type->ty == Tfunction && !fd->type->nextOf())
|
||||
((TypeFunction *)fd->type)->next = Type::terror;
|
||||
|
||||
// Type is a "delegate to" or "pointer to" the function literal
|
||||
@@ -5099,6 +5138,8 @@ Expression *DeclarationExp::semantic(Scope *sc)
|
||||
printf("DeclarationExp::semantic() %s\n", toChars());
|
||||
#endif
|
||||
|
||||
unsigned olderrors = global.errors;
|
||||
|
||||
/* This is here to support extern(linkage) declaration,
|
||||
* where the extern(linkage) winds up being an AttribDeclaration
|
||||
* wrapper.
|
||||
@@ -5164,14 +5205,14 @@ Expression *DeclarationExp::semantic(Scope *sc)
|
||||
sc2->pop();
|
||||
s->parent = sc->parent;
|
||||
}
|
||||
if (!global.errors)
|
||||
if (global.errors == olderrors)
|
||||
{
|
||||
declaration->semantic2(sc);
|
||||
if (!global.errors)
|
||||
if (global.errors == olderrors)
|
||||
{
|
||||
declaration->semantic3(sc);
|
||||
|
||||
if (!global.errors && global.params.useInline)
|
||||
if ((global.errors == olderrors) && global.params.useInline)
|
||||
declaration->inlineScan();
|
||||
}
|
||||
}
|
||||
@@ -6578,22 +6619,20 @@ Expression *DotIdExp::semantic(Scope *sc, int flag)
|
||||
return e->type->dotExp(sc, e, ident);
|
||||
}
|
||||
#if DMDV2
|
||||
else if (t1b->ty == Tarray ||
|
||||
t1b->ty == Tsarray ||
|
||||
t1b->ty == Taarray)
|
||||
else if ((t1b->ty == Tarray || t1b->ty == Tsarray ||
|
||||
t1b->ty == Taarray) &&
|
||||
ident != Id::sort && ident != Id::reverse &&
|
||||
ident != Id::dup && ident != Id::idup)
|
||||
{ /* If ident is not a valid property, rewrite:
|
||||
* e1.ident
|
||||
* as:
|
||||
* .ident(e1)
|
||||
*/
|
||||
unsigned errors = global.errors;
|
||||
global.gag++;
|
||||
unsigned errors = global.startGagging();
|
||||
Type *t1 = e1->type;
|
||||
e = e1->type->dotExp(sc, e1, ident);
|
||||
global.gag--;
|
||||
if (errors != global.errors) // if failed to find the property
|
||||
if (global.endGagging(errors)) // if failed to find the property
|
||||
{
|
||||
global.errors = errors;
|
||||
e1->type = t1; // kludge to restore type
|
||||
e = new DotIdExp(loc, new IdentifierExp(loc, Id::empty), ident);
|
||||
e = new CallExp(loc, e, e1);
|
||||
@@ -6773,7 +6812,7 @@ void modifyFieldVar(Loc loc, Scope *sc, VarDeclaration *var, Expression *e1)
|
||||
if (fd &&
|
||||
((fd->isCtorDeclaration() && var->storage_class & STCfield) ||
|
||||
(fd->isStaticCtorDeclaration() && !(var->storage_class & STCfield))) &&
|
||||
fd->toParent2() == var->toParent() &&
|
||||
fd->toParent2() == var->toParent2() &&
|
||||
(!e1 || e1->op == TOKthis)
|
||||
)
|
||||
{
|
||||
@@ -6901,7 +6940,13 @@ L1:
|
||||
TemplateDeclaration *td = dte->td;
|
||||
eleft = dte->e1;
|
||||
ti->tempdecl = td;
|
||||
ti->semantic(sc);
|
||||
if (ti->needsTypeInference(sc))
|
||||
{
|
||||
e = new CallExp(loc, this);
|
||||
return e->semantic(sc);
|
||||
}
|
||||
else
|
||||
ti->semantic(sc);
|
||||
if (!ti->inst) // if template failed to expand
|
||||
return new ErrorExp();
|
||||
Dsymbol *s = ti->inst->toAlias();
|
||||
@@ -7291,7 +7336,8 @@ Lagain:
|
||||
|
||||
if (ve->var->storage_class & STClazy)
|
||||
{
|
||||
TypeFunction *tf = new TypeFunction(NULL, ve->var->type, 0, LINKd);
|
||||
// lazy paramaters can be called without violating purity and safety
|
||||
TypeFunction *tf = new TypeFunction(NULL, ve->var->type, 0, LINKd, STCsafe | STCpure);
|
||||
TypeDelegate *t = new TypeDelegate(tf);
|
||||
ve->type = t->semantic(loc, sc);
|
||||
}
|
||||
@@ -7462,6 +7508,7 @@ Lagain:
|
||||
if (f->needThis())
|
||||
{
|
||||
ue->e1 = getRightThis(loc, sc, ad, ue->e1, f);
|
||||
ethis = ue->e1;
|
||||
}
|
||||
|
||||
/* Cannot call public functions from inside invariant
|
||||
@@ -7700,10 +7747,7 @@ Lagain:
|
||||
tf = (TypeFunction *)(td->next);
|
||||
if (sc->func && !tf->purity && !(sc->flags & SCOPEdebug))
|
||||
{
|
||||
if (e1->op == TOKvar && ((VarExp *)e1)->var->storage_class & STClazy)
|
||||
{ // lazy paramaters can be called without violating purity
|
||||
// since they are checked explicitly
|
||||
} else if (sc->func->setImpure())
|
||||
if (sc->func->setImpure())
|
||||
error("pure function '%s' cannot call impure delegate '%s'", sc->func->toChars(), e1->toChars());
|
||||
}
|
||||
if (sc->func && tf->trust <= TRUSTsystem)
|
||||
@@ -7783,6 +7827,8 @@ Lagain:
|
||||
|
||||
accessCheck(loc, sc, NULL, f);
|
||||
|
||||
ethis = NULL;
|
||||
|
||||
ve->var = f;
|
||||
// ve->hasOverloads = 0;
|
||||
ve->type = f->type;
|
||||
@@ -7796,7 +7842,7 @@ Lcheckargs:
|
||||
|
||||
if (!arguments)
|
||||
arguments = new Expressions();
|
||||
type = functionParameters(loc, sc, tf, arguments, f);
|
||||
type = functionParameters(loc, sc, tf, ethis, arguments, f);
|
||||
|
||||
if (!type)
|
||||
{
|
||||
@@ -8328,7 +8374,7 @@ Expression *DeleteExp::semantic(Scope *sc)
|
||||
|
||||
UnaExp::semantic(sc);
|
||||
e1 = resolveProperties(sc, e1);
|
||||
e1 = e1->toLvalue(sc, NULL);
|
||||
e1 = e1->modifiableLvalue(sc, NULL);
|
||||
if (e1->op == TOKerror)
|
||||
return e1;
|
||||
type = Type::tvoid;
|
||||
@@ -8539,7 +8585,9 @@ Expression *CastExp::semantic(Scope *sc)
|
||||
}
|
||||
|
||||
// Struct casts are possible only when the sizes match
|
||||
if (tob->ty == Tstruct || t1b->ty == Tstruct)
|
||||
// Same with static array -> static array
|
||||
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);
|
||||
@@ -8870,12 +8918,11 @@ Lagain:
|
||||
return e;
|
||||
}
|
||||
|
||||
if (t->ty == Tarray)
|
||||
{
|
||||
type = t->nextOf()->arrayOf();
|
||||
// Allow typedef[] -> typedef[]
|
||||
if (type->equals(t))
|
||||
type = e1->type;
|
||||
}
|
||||
else
|
||||
type = t->nextOf()->arrayOf();
|
||||
|
||||
return e;
|
||||
|
||||
Lerror:
|
||||
@@ -9277,7 +9324,7 @@ Expression *IndexExp::semantic(Scope *sc)
|
||||
goto Lerr;
|
||||
}
|
||||
if (e2->type->ty == Ttuple && ((TupleExp *)e2)->exps->dim == 1) // bug 4444 fix
|
||||
e2 = (Expression *)((TupleExp *)e2)->exps->data[0];
|
||||
e2 = ((TupleExp *)e2)->exps->tdata()[0];
|
||||
e2 = resolveProperties(sc, e2);
|
||||
if (e2->type == Type::terror)
|
||||
goto Lerr;
|
||||
@@ -9897,6 +9944,9 @@ Ltupleassign:
|
||||
{ /* 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);
|
||||
if (ec)
|
||||
@@ -9915,7 +9965,7 @@ Ltupleassign:
|
||||
}
|
||||
else if (t1->ty == Tclass)
|
||||
{ // Disallow assignment operator overloads for same type
|
||||
if (!e2->type->implicitConvTo(e1->type))
|
||||
if (!e2->implicitConvTo(e1->type))
|
||||
{
|
||||
Expression *e = op_overload(sc);
|
||||
if (e)
|
||||
@@ -11160,6 +11210,8 @@ Expression *PowExp::semantic(Scope *sc)
|
||||
return e;
|
||||
|
||||
assert(e1->type && e2->type);
|
||||
typeCombine(sc);
|
||||
|
||||
if (e1->op == TOKslice)
|
||||
{
|
||||
// Check element types are arithmetic
|
||||
@@ -11183,64 +11235,14 @@ Expression *PowExp::semantic(Scope *sc)
|
||||
// TODO: backend support, especially for e1 ^^ 2.
|
||||
|
||||
bool wantSqrt = false;
|
||||
e1 = e1->optimize(0);
|
||||
e2 = e2->optimize(0);
|
||||
|
||||
// Replace 1 ^^ x or 1.0^^x by (x, 1)
|
||||
if ((e1->op == TOKint64 && e1->toInteger() == 1) ||
|
||||
(e1->op == TOKfloat64 && e1->toReal() == 1.0))
|
||||
// First, attempt to fold the expression.
|
||||
e = optimize(WANTvalue);
|
||||
if (e->op != TOKpow)
|
||||
{
|
||||
typeCombine(sc);
|
||||
e = new CommaExp(loc, e2, e1);
|
||||
e = e->semantic(sc);
|
||||
return e;
|
||||
}
|
||||
// Replace -1 ^^ x by (x&1) ? -1 : 1, where x is integral
|
||||
if (e2->type->isintegral() && e1->op == TOKint64 && (sinteger_t)e1->toInteger() == -1L)
|
||||
{
|
||||
typeCombine(sc);
|
||||
Type* resultType = type;
|
||||
e = new AndExp(loc, e2, new IntegerExp(loc, 1, e2->type));
|
||||
e = new CondExp(loc, e, new IntegerExp(loc, -1L, resultType), new IntegerExp(loc, 1L, resultType));
|
||||
e = e->semantic(sc);
|
||||
return e;
|
||||
}
|
||||
// Replace x ^^ 0 or x^^0.0 by (x, 1)
|
||||
if ((e2->op == TOKint64 && e2->toInteger() == 0) ||
|
||||
(e2->op == TOKfloat64 && e2->toReal() == 0.0))
|
||||
{
|
||||
if (e1->type->isintegral())
|
||||
e = new IntegerExp(loc, 1, e1->type);
|
||||
else
|
||||
e = new RealExp(loc, 1.0, e1->type);
|
||||
|
||||
typeCombine(sc);
|
||||
e = new CommaExp(loc, e1, e);
|
||||
e = e->semantic(sc);
|
||||
return e;
|
||||
}
|
||||
// Replace x ^^ 1 or x^^1.0 by (x)
|
||||
if ((e2->op == TOKint64 && e2->toInteger() == 1) ||
|
||||
(e2->op == TOKfloat64 && e2->toReal() == 1.0))
|
||||
{
|
||||
typeCombine(sc);
|
||||
return e1;
|
||||
}
|
||||
// Replace x ^^ -1.0 by (1.0 / x)
|
||||
if ((e2->op == TOKfloat64 && e2->toReal() == -1.0))
|
||||
{
|
||||
typeCombine(sc);
|
||||
e = new DivExp(loc, new RealExp(loc, 1.0, e2->type), e1);
|
||||
e = e->semantic(sc);
|
||||
return e;
|
||||
}
|
||||
// All other negative integral powers are illegal
|
||||
if ((e1->type->isintegral()) && (e2->op == TOKint64) && (sinteger_t)e2->toInteger() < 0)
|
||||
{
|
||||
error("cannot raise %s to a negative integer power. Did you mean (cast(real)%s)^^%s ?",
|
||||
e1->type->toBasetype()->toChars(), e1->toChars(), e2->toChars());
|
||||
return new ErrorExp();
|
||||
}
|
||||
|
||||
// Determine if we're raising to an integer power.
|
||||
sinteger_t intpow = 0;
|
||||
@@ -11252,7 +11254,6 @@ Expression *PowExp::semantic(Scope *sc)
|
||||
// Deal with x^^2, x^^3 immediately, since they are of practical importance.
|
||||
if (intpow == 2 || intpow == 3)
|
||||
{
|
||||
typeCombine(sc);
|
||||
// Replace x^^2 with (tmp = x, tmp*tmp)
|
||||
// Replace x^^3 with (tmp = x, tmp*tmp*tmp)
|
||||
Identifier *idtmp = Lexer::uniqueId("__powtmp");
|
||||
@@ -11293,27 +11294,14 @@ Expression *PowExp::semantic(Scope *sc)
|
||||
e = new DotIdExp(loc, e, Id::math);
|
||||
if (e2->op == TOKfloat64 && e2->toReal() == 0.5)
|
||||
{ // Replace e1 ^^ 0.5 with .std.math.sqrt(x)
|
||||
typeCombine(sc);
|
||||
e = new CallExp(loc, new DotIdExp(loc, e, Id::_sqrt), e1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Replace e1 ^^ e2 with .std.math.pow(e1, e2)
|
||||
// We don't combine the types if raising to an integer power (because
|
||||
// integer powers are treated specially by std.math.pow).
|
||||
if (!e2->type->isintegral())
|
||||
typeCombine(sc);
|
||||
// In fact, if it *could* have been an integer, make it one.
|
||||
if (e2->op == TOKfloat64 && intpow != 0)
|
||||
e2 = new IntegerExp(loc, intpow, Type::tint64);
|
||||
e = new CallExp(loc, new DotIdExp(loc, e, Id::_pow), e1, e2);
|
||||
}
|
||||
e = e->semantic(sc);
|
||||
// Always constant fold integer powers of literals. This will run the interpreter
|
||||
// on .std.math.pow
|
||||
if ((e1->op == TOKfloat64 || e1->op == TOKint64) && (e2->op == TOKint64))
|
||||
e = e->optimize(WANTvalue | WANTinterpret);
|
||||
|
||||
return e;
|
||||
}
|
||||
incompatibleTypes();
|
||||
@@ -11825,6 +11813,33 @@ EqualExp::EqualExp(enum TOK op, Loc loc, Expression *e1, Expression *e2)
|
||||
assert(op == TOKequal || op == TOKnotequal);
|
||||
}
|
||||
|
||||
int needDirectEq(Type *t1, Type *t2)
|
||||
{
|
||||
assert(t1->ty == Tarray || t1->ty == Tsarray);
|
||||
assert(t2->ty == Tarray || t2->ty == Tsarray);
|
||||
|
||||
Type *t1n = t1->nextOf()->toBasetype();
|
||||
Type *t2n = t2->nextOf()->toBasetype();
|
||||
|
||||
if (((t1n->ty == Tchar || t1n->ty == Twchar || t1n->ty == Tdchar) &&
|
||||
(t2n->ty == Tchar || t2n->ty == Twchar || t2n->ty == Tdchar)) ||
|
||||
(t1n->ty == Tvoid || t2n->ty == Tvoid))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (t1n->constOf() != t2n->constOf())
|
||||
return TRUE;
|
||||
|
||||
Type *t = t1n;
|
||||
while (t->toBasetype()->nextOf())
|
||||
t = t->nextOf()->toBasetype();
|
||||
if (t->ty != Tstruct)
|
||||
return FALSE;
|
||||
|
||||
return ((TypeStruct *)t)->sym->xeq == StructDeclaration::xerreq;
|
||||
}
|
||||
|
||||
Expression *EqualExp::semantic(Scope *sc)
|
||||
{ Expression *e;
|
||||
|
||||
@@ -11868,13 +11883,8 @@ Expression *EqualExp::semantic(Scope *sc)
|
||||
|
||||
if ((t1->ty == Tarray || t1->ty == Tsarray) &&
|
||||
(t2->ty == Tarray || t2->ty == Tsarray))
|
||||
{ Type *t1n = t1->nextOf()->toBasetype();
|
||||
Type *t2n = t2->nextOf()->toBasetype();
|
||||
if (t1n->constOf() != t2n->constOf() &&
|
||||
!((t1n->ty == Tchar || t1n->ty == Twchar || t1n->ty == Tdchar) &&
|
||||
(t2n->ty == Tchar || t2n->ty == Twchar || t2n->ty == Tdchar)) &&
|
||||
!(t1n->ty == Tvoid || t2n->ty == Tvoid)
|
||||
)
|
||||
{
|
||||
if (needDirectEq(t1, t2))
|
||||
{ /* Rewrite as:
|
||||
* _ArrayEq(e1, e2)
|
||||
*/
|
||||
@@ -11885,7 +11895,11 @@ Expression *EqualExp::semantic(Scope *sc)
|
||||
e = new CallExp(loc, eq, args);
|
||||
if (op == TOKnotequal)
|
||||
e = new NotExp(loc, e);
|
||||
e = e->semantic(sc);
|
||||
e = e->trySemantic(sc); // for better error message
|
||||
if (!e)
|
||||
{ error("cannot compare %s and %s", t1->toChars(), t2->toChars());
|
||||
return new ErrorExp();
|
||||
}
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1562,6 +1562,9 @@ ASSIGNEXP(Mod)
|
||||
ASSIGNEXP(And)
|
||||
ASSIGNEXP(Or)
|
||||
ASSIGNEXP(Xor)
|
||||
#if DMDV2
|
||||
ASSIGNEXP(Pow)
|
||||
#endif
|
||||
#undef X
|
||||
|
||||
#define X(a)
|
||||
@@ -1575,18 +1578,6 @@ ASSIGNEXP(Cat)
|
||||
#undef ASSIGNEXP
|
||||
#undef ASSIGNEXP_TOELEM
|
||||
|
||||
// Only a reduced subset of operations for now.
|
||||
struct PowAssignExp : BinAssignExp
|
||||
{
|
||||
PowAssignExp(Loc loc, Expression *e1, Expression *e2);
|
||||
Expression *semantic(Scope *sc);
|
||||
void buildArrayIdent(OutBuffer *buf, Expressions *arguments);
|
||||
Expression *buildArrayLoop(Parameters *fparams);
|
||||
|
||||
// For operator overloading
|
||||
Identifier *opId();
|
||||
};
|
||||
|
||||
struct AddExp : BinExp
|
||||
{
|
||||
AddExp(Loc loc, Expression *e1, Expression *e2);
|
||||
@@ -1731,12 +1722,22 @@ struct PowExp : BinExp
|
||||
{
|
||||
PowExp(Loc loc, Expression *e1, Expression *e2);
|
||||
Expression *semantic(Scope *sc);
|
||||
Expression *optimize(int result);
|
||||
Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue);
|
||||
void buildArrayIdent(OutBuffer *buf, Expressions *arguments);
|
||||
Expression *buildArrayLoop(Parameters *fparams);
|
||||
|
||||
// For operator overloading
|
||||
Identifier *opId();
|
||||
Identifier *opId_r();
|
||||
|
||||
#if IN_DMD
|
||||
elem *toElem(IRState *irs);
|
||||
#endif
|
||||
|
||||
#if IN_LLVM
|
||||
DValue* toElem(IRState* irs);
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -1958,6 +1959,7 @@ struct InExp : BinExp
|
||||
struct RemoveExp : BinExp
|
||||
{
|
||||
RemoveExp(Loc loc, Expression *e1, Expression *e2);
|
||||
Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue);
|
||||
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||
#if IN_DMD
|
||||
elem *toElem(IRState *irs);
|
||||
@@ -2119,6 +2121,7 @@ Expression *Min(Type *type, Expression *e1, Expression *e2);
|
||||
Expression *Mul(Type *type, Expression *e1, Expression *e2);
|
||||
Expression *Div(Type *type, Expression *e1, Expression *e2);
|
||||
Expression *Mod(Type *type, Expression *e1, Expression *e2);
|
||||
Expression *Pow(Type *type, Expression *e1, Expression *e2);
|
||||
Expression *Shl(Type *type, Expression *e1, Expression *e2);
|
||||
Expression *Shr(Type *type, Expression *e1, Expression *e2);
|
||||
Expression *Ushr(Type *type, Expression *e1, Expression *e2);
|
||||
|
||||
57
dmd2/func.c
57
dmd2/func.c
@@ -38,6 +38,8 @@ FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, StorageCla
|
||||
//printf("storage_class = x%x\n", storage_class);
|
||||
this->storage_class = storage_class;
|
||||
this->type = type;
|
||||
if (type)
|
||||
this->storage_class &= ~(STC_TYPECTOR | STC_FUNCATTR);
|
||||
this->loc = loc;
|
||||
this->endloc = endloc;
|
||||
fthrows = NULL;
|
||||
@@ -77,6 +79,7 @@ FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, StorageCla
|
||||
* NULL for the return type.
|
||||
*/
|
||||
inferRetType = (type && type->nextOf() == NULL);
|
||||
storage_class2 = 0;
|
||||
hasReturnExp = 0;
|
||||
nrvo_can = 1;
|
||||
nrvo_var = NULL;
|
||||
@@ -199,8 +202,15 @@ void FuncDeclaration::semantic(Scope *sc)
|
||||
if (!type->deco)
|
||||
{
|
||||
sc = sc->push();
|
||||
sc->stc |= storage_class & (STCref | STCnothrow | STCpure | STCdisable
|
||||
| STCsafe | STCtrusted | STCsystem | STCproperty); // forward to function type
|
||||
sc->stc |= storage_class & STCdisable; // forward to function type
|
||||
TypeFunction *tf = (TypeFunction *)type;
|
||||
if (tf->isref) sc->stc |= STCref;
|
||||
if (tf->isnothrow) sc->stc |= STCnothrow;
|
||||
if (tf->isproperty) sc->stc |= STCproperty;
|
||||
if (tf->purity == PUREfwdref) sc->stc |= STCpure;
|
||||
if (tf->trust == TRUSTsafe) sc->stc |= STCsafe;
|
||||
if (tf->trust == TRUSTsystem) sc->stc |= STCsystem;
|
||||
if (tf->trust == TRUSTtrusted) sc->stc |= STCtrusted;
|
||||
|
||||
if (isCtorDeclaration())
|
||||
sc->flags |= SCOPEctor;
|
||||
@@ -287,12 +297,9 @@ void FuncDeclaration::semantic(Scope *sc)
|
||||
if (fbody &&
|
||||
(isFuncLiteralDeclaration() || parent->isTemplateInstance()))
|
||||
{
|
||||
if (f->purity == PUREimpure && // purity not specified
|
||||
!f->hasLazyParameters()
|
||||
)
|
||||
{
|
||||
if (f->purity == PUREimpure) // purity not specified
|
||||
flags |= FUNCFLAGpurityInprocess;
|
||||
}
|
||||
|
||||
if (f->trust == TRUSTdefault)
|
||||
flags |= FUNCFLAGsafetyInprocess;
|
||||
|
||||
@@ -517,12 +524,13 @@ void FuncDeclaration::semantic(Scope *sc)
|
||||
warning(loc, "overrides base class function %s, but is not marked with 'override'", fdv->toPrettyChars());
|
||||
#endif
|
||||
|
||||
if (fdv->toParent() == parent)
|
||||
FuncDeclaration *fdc = ((Dsymbol *)cd->vtbl.data[vi])->isFuncDeclaration();
|
||||
if (fdc->toParent() == parent)
|
||||
{
|
||||
// If both are mixins, then error.
|
||||
// If either is not, the one that is not overrides
|
||||
// the other.
|
||||
if (fdv->parent->isClassDeclaration())
|
||||
if (fdc->parent->isClassDeclaration())
|
||||
break;
|
||||
if (!this->parent->isClassDeclaration()
|
||||
#if !BREAKABI
|
||||
@@ -2951,7 +2959,7 @@ int FuncDeclaration::addPreInvariant()
|
||||
return (ad &&
|
||||
//ad->isClassDeclaration() &&
|
||||
global.params.useInvariants &&
|
||||
(protection == PROTpublic || protection == PROTexport) &&
|
||||
(protection == PROTprotected || protection == PROTpublic || protection == PROTexport) &&
|
||||
!naked &&
|
||||
ident != Id::cpctor);
|
||||
}
|
||||
@@ -2963,7 +2971,7 @@ int FuncDeclaration::addPostInvariant()
|
||||
ad->inv &&
|
||||
//ad->isClassDeclaration() &&
|
||||
global.params.useInvariants &&
|
||||
(protection == PROTpublic || protection == PROTexport) &&
|
||||
(protection == PROTprotected || protection == PROTpublic || protection == PROTexport) &&
|
||||
!naked &&
|
||||
ident != Id::cpctor);
|
||||
}
|
||||
@@ -3224,10 +3232,10 @@ void CtorDeclaration::semantic(Scope *sc)
|
||||
//printf("CtorDeclaration::semantic() %s\n", toChars());
|
||||
TypeFunction *tf = (TypeFunction *)type;
|
||||
assert(tf && tf->ty == Tfunction);
|
||||
Expressions *fargs = ((TypeFunction *)type)->fargs; // for auto ref
|
||||
|
||||
sc = sc->push();
|
||||
sc->stc &= ~STCstatic; // not a static constructor
|
||||
sc->flags |= SCOPEctor;
|
||||
|
||||
parent = sc->parent;
|
||||
Dsymbol *parent = toParent2();
|
||||
@@ -3243,17 +3251,16 @@ void CtorDeclaration::semantic(Scope *sc)
|
||||
{ tret = ad->handle;
|
||||
assert(tret);
|
||||
tret = tret->addStorageClass(storage_class | sc->stc);
|
||||
tret = tret->addMod(type->mod);
|
||||
}
|
||||
tf = new TypeFunction(tf->parameters, tret, tf->varargs, LINKd, storage_class | sc->stc);
|
||||
tf->fargs = fargs;
|
||||
type = tf;
|
||||
tf->next = tret;
|
||||
type = type->semantic(loc, sc);
|
||||
|
||||
#if STRUCTTHISREF
|
||||
if (ad && ad->isStructDeclaration())
|
||||
{ ((TypeFunction *)type)->isref = 1;
|
||||
if (!originalType)
|
||||
// Leave off the "ref"
|
||||
originalType = new TypeFunction(tf->parameters, tret, tf->varargs, LINKd, storage_class | sc->stc);
|
||||
{ if (!originalType)
|
||||
originalType = type->syntaxCopy();
|
||||
((TypeFunction *)type)->isref = 1;
|
||||
}
|
||||
#endif
|
||||
if (!originalType)
|
||||
@@ -3319,18 +3326,6 @@ int CtorDeclaration::addPostInvariant()
|
||||
}
|
||||
|
||||
|
||||
void CtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
|
||||
{
|
||||
TypeFunction *tf = (TypeFunction *)type;
|
||||
assert(tf && tf->ty == Tfunction);
|
||||
|
||||
if (originalType && originalType->ty == Tfunction)
|
||||
((TypeFunction *)originalType)->attributesToCBuffer(buf, 0);
|
||||
buf->writestring("this");
|
||||
Parameter::argsToCBuffer(buf, hgs, tf->parameters, tf->varargs);
|
||||
bodyToCBuffer(buf, hgs);
|
||||
}
|
||||
|
||||
/********************************* PostBlitDeclaration ****************************/
|
||||
|
||||
#if DMDV2
|
||||
|
||||
11
dmd2/idgen.c
11
dmd2/idgen.c
@@ -73,6 +73,7 @@ Msgtable msgtable[] =
|
||||
{ "line" },
|
||||
{ "empty", "" },
|
||||
{ "p" },
|
||||
{ "q" },
|
||||
{ "coverage", "__coverage" },
|
||||
{ "__vptr" },
|
||||
{ "__monitor" },
|
||||
@@ -310,7 +311,17 @@ Msgtable msgtable[] =
|
||||
{ "tan" },
|
||||
{ "_sqrt", "sqrt" },
|
||||
{ "_pow", "pow" },
|
||||
{ "atan2" },
|
||||
{ "rndtol" },
|
||||
{ "expm1" },
|
||||
{ "exp2" },
|
||||
{ "yl2x" },
|
||||
{ "yl2xp1" },
|
||||
{ "fabs" },
|
||||
{ "bitop" },
|
||||
{ "bsf" },
|
||||
{ "bsr" },
|
||||
{ "bswap" },
|
||||
|
||||
// Traits
|
||||
{ "isAbstractClass" },
|
||||
|
||||
@@ -810,6 +810,9 @@ Initializer *ExpInitializer::semantic(Scope *sc, Type *t, int needInterpret)
|
||||
if (!global.gag && olderrors != global.errors)
|
||||
return this; // Failed, suppress duplicate error messages
|
||||
|
||||
if (exp->op == TOKtype)
|
||||
error("initializer must be an expression, not '%s'", exp->toChars());
|
||||
|
||||
// Make sure all pointers are constants
|
||||
if (needInterpret && hasNonConstPointers(exp))
|
||||
{
|
||||
|
||||
@@ -54,7 +54,7 @@ int CompoundStatement::inlineCost(InlineCostState *ics)
|
||||
{ int cost = 0;
|
||||
|
||||
for (size_t i = 0; i < statements->dim; i++)
|
||||
{ Statement *s = statements->tdata()[i];
|
||||
{ Statement *s = (*statements)[i];
|
||||
if (s)
|
||||
{
|
||||
cost += s->inlineCost(ics);
|
||||
@@ -69,7 +69,7 @@ int UnrolledLoopStatement::inlineCost(InlineCostState *ics)
|
||||
{ int cost = 0;
|
||||
|
||||
for (size_t i = 0; i < statements->dim; i++)
|
||||
{ Statement *s = statements->tdata()[i];
|
||||
{ Statement *s = (*statements)[i];
|
||||
if (s)
|
||||
{
|
||||
cost += s->inlineCost(ics);
|
||||
@@ -147,7 +147,7 @@ int arrayInlineCost(InlineCostState *ics, Expressions *arguments)
|
||||
if (arguments)
|
||||
{
|
||||
for (size_t i = 0; i < arguments->dim; i++)
|
||||
{ Expression *e = arguments->tdata()[i];
|
||||
{ Expression *e = (*arguments)[i];
|
||||
|
||||
if (e)
|
||||
cost += e->inlineCost(ics);
|
||||
@@ -211,6 +211,8 @@ int AssocArrayLiteralExp::inlineCost(InlineCostState *ics)
|
||||
|
||||
int StructLiteralExp::inlineCost(InlineCostState *ics)
|
||||
{
|
||||
if (sd->isnested)
|
||||
return COST_MAX;
|
||||
return 1 + arrayInlineCost(ics, elements);
|
||||
}
|
||||
|
||||
@@ -246,7 +248,7 @@ int DeclarationExp::inlineCost(InlineCostState *ics)
|
||||
return COST_MAX; // finish DeclarationExp::doInline
|
||||
#else
|
||||
for (size_t i = 0; i < td->objects->dim; i++)
|
||||
{ Object *o = td->objects->tdata()[i];
|
||||
{ Object *o = (*td->objects)[i];
|
||||
if (o->dyncast() != DYNCAST_EXPRESSION)
|
||||
return COST_MAX;
|
||||
Expression *eo = (Expression *)o;
|
||||
@@ -379,7 +381,7 @@ Expression *CompoundStatement::doInline(InlineDoState *ids)
|
||||
|
||||
//printf("CompoundStatement::doInline() %d\n", statements->dim);
|
||||
for (size_t i = 0; i < statements->dim; i++)
|
||||
{ Statement *s = statements->tdata()[i];
|
||||
{ Statement *s = (*statements)[i];
|
||||
if (s)
|
||||
{
|
||||
Expression *e2 = s->doInline(ids);
|
||||
@@ -411,7 +413,7 @@ Expression *UnrolledLoopStatement::doInline(InlineDoState *ids)
|
||||
|
||||
//printf("UnrolledLoopStatement::doInline() %d\n", statements->dim);
|
||||
for (size_t i = 0; i < statements->dim; i++)
|
||||
{ Statement *s = statements->tdata()[i];
|
||||
{ Statement *s = (*statements)[i];
|
||||
if (s)
|
||||
{
|
||||
Expression *e2 = s->doInline(ids);
|
||||
@@ -843,9 +845,9 @@ Statement *ExpStatement::inlineScan(InlineScanState *iss)
|
||||
Statement *CompoundStatement::inlineScan(InlineScanState *iss)
|
||||
{
|
||||
for (size_t i = 0; i < statements->dim; i++)
|
||||
{ Statement *s = statements->tdata()[i];
|
||||
{ Statement *s = (*statements)[i];
|
||||
if (s)
|
||||
statements->tdata()[i] = s->inlineScan(iss);
|
||||
(*statements)[i] = s->inlineScan(iss);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
@@ -853,9 +855,9 @@ Statement *CompoundStatement::inlineScan(InlineScanState *iss)
|
||||
Statement *UnrolledLoopStatement::inlineScan(InlineScanState *iss)
|
||||
{
|
||||
for (size_t i = 0; i < statements->dim; i++)
|
||||
{ Statement *s = statements->tdata()[i];
|
||||
{ Statement *s = (*statements)[i];
|
||||
if (s)
|
||||
statements->tdata()[i] = s->inlineScan(iss);
|
||||
(*statements)[i] = s->inlineScan(iss);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
702
dmd2/interpret.c
702
dmd2/interpret.c
File diff suppressed because it is too large
Load Diff
44
dmd2/lexer.c
44
dmd2/lexer.c
@@ -102,7 +102,7 @@ void Token::print()
|
||||
|
||||
const char *Token::toChars()
|
||||
{ const char *p;
|
||||
static char buffer[3 + 3 * sizeof(value) + 1];
|
||||
static char buffer[3 + 3 * sizeof(float80value) + 1];
|
||||
|
||||
p = buffer;
|
||||
switch (value)
|
||||
@@ -298,28 +298,21 @@ Lexer::Lexer(Module *mod,
|
||||
|
||||
void Lexer::error(const char *format, ...)
|
||||
{
|
||||
if (mod && !global.gag)
|
||||
{
|
||||
char *p = loc.toChars();
|
||||
if (*p)
|
||||
fprintf(stdmsg, "%s: ", p);
|
||||
mem.free(p);
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vfprintf(stdmsg, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
fprintf(stdmsg, "\n");
|
||||
fflush(stdmsg);
|
||||
|
||||
if (global.errors >= 20) // moderate blizzard of cascading messages
|
||||
fatal();
|
||||
}
|
||||
global.errors++;
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
verror(loc, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void Lexer::error(Loc loc, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
verror(loc, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void Lexer::verror(Loc loc, const char *format, va_list ap)
|
||||
{
|
||||
if (mod && !global.gag)
|
||||
{
|
||||
@@ -328,10 +321,7 @@ void Lexer::error(Loc loc, const char *format, ...)
|
||||
fprintf(stdmsg, "%s: ", p);
|
||||
mem.free(p);
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vfprintf(stdmsg, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
fprintf(stdmsg, "\n");
|
||||
fflush(stdmsg);
|
||||
@@ -339,6 +329,10 @@ void Lexer::error(Loc loc, const char *format, ...)
|
||||
if (global.errors >= 20) // moderate blizzard of cascading messages
|
||||
fatal();
|
||||
}
|
||||
else
|
||||
{
|
||||
global.gaggedErrors++;
|
||||
}
|
||||
global.errors++;
|
||||
}
|
||||
|
||||
@@ -2286,9 +2280,11 @@ done:
|
||||
break;
|
||||
}
|
||||
|
||||
#if DMDV2
|
||||
if (state == STATE_octal && n >= 8 && !global.params.useDeprecated)
|
||||
error("octal literals 0%llo%.*s are deprecated, use std.conv.octal!%llo%.*s instead",
|
||||
n, p - psuffix, psuffix, n, p - psuffix, psuffix);
|
||||
#endif
|
||||
|
||||
switch (flags)
|
||||
{
|
||||
@@ -3041,6 +3037,8 @@ void Lexer::initKeywords()
|
||||
enum TOK v;
|
||||
unsigned nkeywords = sizeof(keywords) / sizeof(keywords[0]);
|
||||
|
||||
stringtable.init();
|
||||
|
||||
if (global.params.Dversion == 1)
|
||||
nkeywords -= 2;
|
||||
|
||||
|
||||
@@ -307,6 +307,7 @@ struct Lexer
|
||||
TOK inreal(Token *t);
|
||||
void error(const char *format, ...) IS_PRINTF(2);
|
||||
void error(Loc loc, const char *format, ...) IS_PRINTF(3);
|
||||
void verror(Loc loc, const char *format, va_list ap);
|
||||
void pragma();
|
||||
unsigned decodeUTF();
|
||||
void getDocComment(Token *t, unsigned lineComment);
|
||||
|
||||
1195
dmd2/mars.c
1195
dmd2/mars.c
File diff suppressed because it is too large
Load Diff
16
dmd2/mars.h
16
dmd2/mars.h
@@ -189,6 +189,7 @@ struct Param
|
||||
#endif
|
||||
ARCH cpu; // target CPU
|
||||
OS os;
|
||||
bool alwaysframe; // always emit standard stack frame
|
||||
char map; // generate linker .map file
|
||||
bool isLE; // generate little endian code
|
||||
bool is64bit; // generate 64 bit code
|
||||
@@ -307,9 +308,18 @@ struct Global
|
||||
#endif
|
||||
|
||||
Param params;
|
||||
unsigned errors; // number of errors reported so far
|
||||
unsigned warnings; // number of warnings reported so far
|
||||
unsigned gag; // !=0 means gag reporting of errors & warnings
|
||||
unsigned errors; // number of errors reported so far
|
||||
unsigned warnings; // number of warnings reported so far
|
||||
unsigned gag; // !=0 means gag reporting of errors & warnings
|
||||
unsigned gaggedErrors; // number of errors reported while gagged
|
||||
|
||||
// Start gagging. Return the current number of gagged errors
|
||||
unsigned startGagging();
|
||||
|
||||
/* End gagging, restoring the old gagged state.
|
||||
* Return true if errors occured while gagged.
|
||||
*/
|
||||
bool endGagging(unsigned oldGagged);
|
||||
|
||||
Global();
|
||||
};
|
||||
|
||||
@@ -133,6 +133,10 @@ void Mem::mark(void *pointer)
|
||||
(void) pointer; // necessary for VC /W4
|
||||
}
|
||||
|
||||
void Mem::setStackBottom(void */*bottom*/)
|
||||
{
|
||||
}
|
||||
|
||||
/* =================================================== */
|
||||
|
||||
void * operator new(size_t m_size)
|
||||
@@ -262,4 +266,8 @@ void Mem::mark(void *pointer)
|
||||
{
|
||||
}
|
||||
|
||||
void Mem::setStackBottom(void */*stackbottom*/)
|
||||
{
|
||||
}
|
||||
|
||||
#endif // USE_BOEHM_GC
|
||||
|
||||
@@ -475,7 +475,7 @@ Module *Module::load(Loc loc, Identifiers *packages, Identifier *ident)
|
||||
{
|
||||
for (size_t i = 0; i < global.path->dim; i++)
|
||||
{
|
||||
char *p = global.path->tdata()[i];
|
||||
char *p = (*global.path)[i];
|
||||
char *n = FileName::combine(p, sdi);
|
||||
if (FileName::exists(n))
|
||||
{ result = n;
|
||||
@@ -795,6 +795,11 @@ void Module::parse()
|
||||
#endif
|
||||
p.nextToken();
|
||||
members = p.parseModule();
|
||||
|
||||
::free(srcfile->buffer);
|
||||
srcfile->buffer = NULL;
|
||||
srcfile->len = 0;
|
||||
|
||||
md = p.md;
|
||||
numlines = p.loc.linnum;
|
||||
|
||||
@@ -855,7 +860,7 @@ void Module::importAll(Scope *prevsc)
|
||||
// Add import of "object" if this module isn't "object"
|
||||
if (ident != Id::object)
|
||||
{
|
||||
if (members->dim == 0 || members->tdata()[0]->ident != Id::object)
|
||||
if (members->dim == 0 || ((*members)[0])->ident != Id::object)
|
||||
{
|
||||
Import *im = new Import(0, NULL, Id::object, NULL, 0);
|
||||
members->shift(im);
|
||||
|
||||
@@ -211,7 +211,7 @@ struct Module : Package
|
||||
llvm::PATypeHolder* moduleInfoType;
|
||||
|
||||
// array ops emitted in this module already
|
||||
StringTable arrayfuncs;
|
||||
AA *arrayfuncs;
|
||||
|
||||
bool isRoot;
|
||||
#endif
|
||||
|
||||
335
dmd2/mtype.c
335
dmd2/mtype.c
@@ -198,6 +198,10 @@ void Type::init(Ir* _sir)
|
||||
void Type::init()
|
||||
#endif
|
||||
{
|
||||
stringtable.init();
|
||||
#if IN_LLVM
|
||||
deco_stringtable.init();
|
||||
#endif
|
||||
Lexer::initKeywords();
|
||||
|
||||
for (size_t i = 0; i < TMAX; i++)
|
||||
@@ -362,13 +366,10 @@ Type *Type::semantic(Loc loc, Scope *sc)
|
||||
Type *Type::trySemantic(Loc loc, Scope *sc)
|
||||
{
|
||||
//printf("+trySemantic(%s) %d\n", toChars(), global.errors);
|
||||
unsigned errors = global.errors;
|
||||
global.gag++; // suppress printing of error messages
|
||||
unsigned errors = global.startGagging();
|
||||
Type *t = semantic(loc, sc);
|
||||
global.gag--;
|
||||
if (errors != global.errors) // if any errors happened
|
||||
if (global.endGagging(errors)) // if any errors happened
|
||||
{
|
||||
global.errors = errors;
|
||||
t = NULL;
|
||||
}
|
||||
//printf("-trySemantic(%s) %d\n", toChars(), global.errors);
|
||||
@@ -1098,6 +1099,37 @@ Type *Type::makeMutable()
|
||||
return t;
|
||||
}
|
||||
|
||||
/*************************************
|
||||
* Apply STCxxxx bits to existing type.
|
||||
* Use *before* semantic analysis is run.
|
||||
*/
|
||||
|
||||
Type *Type::addSTC(StorageClass stc)
|
||||
{ Type *t = this;
|
||||
|
||||
if (stc & STCconst)
|
||||
{ if (t->isShared())
|
||||
t = t->makeSharedConst();
|
||||
else
|
||||
t = t->makeConst();
|
||||
}
|
||||
if (stc & STCimmutable)
|
||||
t = t->makeInvariant();
|
||||
if (stc & STCshared)
|
||||
{ if (t->isConst())
|
||||
t = t->makeSharedConst();
|
||||
else
|
||||
t = t->makeShared();
|
||||
}
|
||||
if (stc & STCwild)
|
||||
{ if (t->isShared())
|
||||
t = t->makeSharedWild();
|
||||
else
|
||||
t = t->makeWild();
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
/************************************
|
||||
* Apply MODxxxx bits to existing type.
|
||||
*/
|
||||
@@ -1531,6 +1563,7 @@ void Type::modToBuffer(OutBuffer *buf)
|
||||
Type *Type::merge()
|
||||
{ Type *t;
|
||||
|
||||
if (ty == Terror) return this;
|
||||
//printf("merge(%s)\n", toChars());
|
||||
t = this;
|
||||
assert(t);
|
||||
@@ -2056,11 +2089,96 @@ int Type::hasWild()
|
||||
* Return MOD bits matching argument type (targ) to wild parameter type (this).
|
||||
*/
|
||||
|
||||
unsigned getWildModConv(Type *twild, Type *targ)
|
||||
{
|
||||
assert(twild);
|
||||
assert(targ);
|
||||
|
||||
unsigned mod = 0;
|
||||
|
||||
if (twild->nextOf())
|
||||
mod = getWildModConv(twild->nextOf(), targ->nextOf());
|
||||
|
||||
if (!mod)
|
||||
{
|
||||
if (twild->isWild())
|
||||
{
|
||||
if (targ->isWild())
|
||||
mod = MODwild;
|
||||
else if (targ->isConst())
|
||||
mod = MODconst;
|
||||
else if (targ->isImmutable())
|
||||
mod = MODimmutable;
|
||||
else if (targ->isMutable())
|
||||
mod = MODmutable;
|
||||
else
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
return mod;
|
||||
}
|
||||
|
||||
unsigned Type::wildMatch(Type *targ)
|
||||
{
|
||||
//printf("Type::wildMatch this = '%s', targ = '%s'\n", toChars(), targ->toChars());
|
||||
assert(hasWild());
|
||||
|
||||
Type *tc = substWildTo(MODconst);
|
||||
if (targ->implicitConvTo(tc))
|
||||
return getWildModConv(this, targ);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Type *Type::substWildTo(unsigned mod)
|
||||
{
|
||||
//printf("+Type::substWildTo this = %s, mod = x%x\n", toChars(), mod);
|
||||
Type *t;
|
||||
|
||||
if (nextOf())
|
||||
{
|
||||
t = nextOf()->substWildTo(mod);
|
||||
if (t == nextOf())
|
||||
t = this;
|
||||
else
|
||||
{
|
||||
if (ty == Tpointer)
|
||||
t = t->pointerTo();
|
||||
else if (ty == Tarray)
|
||||
t = t->arrayOf();
|
||||
else if (ty == Tsarray)
|
||||
t = new TypeSArray(t, ((TypeSArray *)this)->dim->syntaxCopy());
|
||||
else if (ty == Taarray)
|
||||
{
|
||||
t = new TypeAArray(t, ((TypeAArray *)this)->index->syntaxCopy());
|
||||
t = t->merge();
|
||||
}
|
||||
else
|
||||
assert(0);
|
||||
|
||||
t = t->addMod(this->mod);
|
||||
}
|
||||
}
|
||||
else
|
||||
t = this;
|
||||
|
||||
if (isWild())
|
||||
{
|
||||
if (mod & MODconst)
|
||||
t = t->constOf();
|
||||
else if (mod & MODimmutable)
|
||||
t = t->invariantOf();
|
||||
else if (mod & MODwild)
|
||||
t = t->wildOf();
|
||||
else
|
||||
t = t->mutableOf();
|
||||
}
|
||||
|
||||
//printf("-Type::substWildTo t = %s\n", t->toChars());
|
||||
return t;
|
||||
}
|
||||
|
||||
/********************************
|
||||
* We've mistakenly parsed this as a type.
|
||||
* Redo it as an Expression.
|
||||
@@ -2168,30 +2286,7 @@ Type *TypeNext::reliesOnTident()
|
||||
|
||||
int TypeNext::hasWild()
|
||||
{
|
||||
return mod == MODwild || next->hasWild();
|
||||
}
|
||||
|
||||
/***************************************
|
||||
* Return MOD bits matching argument type (targ) to wild parameter type (this).
|
||||
*/
|
||||
|
||||
unsigned TypeNext::wildMatch(Type *targ)
|
||||
{ unsigned mod;
|
||||
|
||||
Type *tb = targ->nextOf();
|
||||
if (!tb)
|
||||
return 0;
|
||||
tb = tb->toBasetype();
|
||||
if (tb->isMutable())
|
||||
mod = MODmutable;
|
||||
else if (tb->isConst() || tb->isWild())
|
||||
return MODconst;
|
||||
else if (tb->isImmutable())
|
||||
mod = MODimmutable;
|
||||
else
|
||||
assert(0);
|
||||
mod |= next->wildMatch(tb);
|
||||
return mod;
|
||||
return mod & MODwild || (next && next->hasWild());
|
||||
}
|
||||
|
||||
|
||||
@@ -3152,6 +3247,11 @@ Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident)
|
||||
#if LOGDOTEXP
|
||||
printf("TypeArray::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
|
||||
#endif
|
||||
|
||||
if (!n->isMutable())
|
||||
if (ident == Id::sort || ident == Id::reverse)
|
||||
error(e->loc, "can only %s a mutable array\n", ident->toChars());
|
||||
|
||||
if (ident == Id::reverse && (n->ty == Tchar || n->ty == Twchar))
|
||||
{
|
||||
Expression *ec;
|
||||
@@ -3221,6 +3321,7 @@ Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident)
|
||||
int size = next->size(e->loc);
|
||||
int dup;
|
||||
|
||||
Expression *olde = e;
|
||||
assert(size);
|
||||
dup = (ident == Id::dup || ident == Id::idup);
|
||||
//LDC: Build arguments.
|
||||
@@ -3263,9 +3364,18 @@ Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident)
|
||||
if (ident == Id::idup)
|
||||
{ Type *einv = next->invariantOf();
|
||||
if (next->implicitConvTo(einv) < MATCHconst)
|
||||
error(e->loc, "cannot implicitly convert element type %s to immutable", next->toChars());
|
||||
error(e->loc, "cannot implicitly convert element type %s to immutable in %s.idup",
|
||||
next->toChars(), olde->toChars());
|
||||
e->type = einv->arrayOf();
|
||||
}
|
||||
else if (ident == Id::dup)
|
||||
{
|
||||
Type *emut = next->mutableOf();
|
||||
if (next->implicitConvTo(emut) < MATCHconst)
|
||||
error(e->loc, "cannot implicitly convert element type %s to mutable in %s.dup",
|
||||
next->toChars(), olde->toChars());
|
||||
e->type = emut->arrayOf();
|
||||
}
|
||||
else
|
||||
e->type = next->mutableOf()->arrayOf();
|
||||
}
|
||||
@@ -3479,10 +3589,11 @@ Type *TypeSArray::semantic(Loc loc, Scope *sc)
|
||||
return t;
|
||||
}
|
||||
|
||||
next = next->semantic(loc,sc);
|
||||
transitive();
|
||||
Type *tn = next->semantic(loc,sc);
|
||||
if (tn->ty == Terror)
|
||||
return terror;
|
||||
|
||||
Type *tbn = next->toBasetype();
|
||||
Type *tbn = tn->toBasetype();
|
||||
|
||||
if (dim)
|
||||
{ dinteger_t n, n2;
|
||||
@@ -3571,7 +3682,9 @@ Type *TypeSArray::semantic(Loc loc, Scope *sc)
|
||||
/* Ensure things like const(immutable(T)[3]) become immutable(T[3])
|
||||
* and const(T)[3] become const(T[3])
|
||||
*/
|
||||
t = addMod(next->mod);
|
||||
next = tn;
|
||||
transitive();
|
||||
t = addMod(tn->mod);
|
||||
|
||||
return t->merge();
|
||||
|
||||
@@ -3860,6 +3973,8 @@ Expression *TypeDArray::dotExp(Scope *sc, Expression *e, Identifier *ident)
|
||||
|
||||
return new IntegerExp(se->loc, se->len, Type::tindex);
|
||||
}
|
||||
if (e->op == TOKnull)
|
||||
return new IntegerExp(e->loc, 0, Type::tindex);
|
||||
e = new ArrayLengthExp(e->loc, e);
|
||||
e->type = Type::tsize_t;
|
||||
return e;
|
||||
@@ -4002,6 +4117,9 @@ d_uns64 TypeAArray::size(Loc loc)
|
||||
Type *TypeAArray::semantic(Loc loc, Scope *sc)
|
||||
{
|
||||
//printf("TypeAArray::semantic() %s index->ty = %d\n", toChars(), index->ty);
|
||||
if (deco)
|
||||
return this;
|
||||
|
||||
this->loc = loc;
|
||||
this->sc = sc;
|
||||
if (sc)
|
||||
@@ -4614,6 +4732,9 @@ TypeFunction::TypeFunction(Parameters *parameters, Type *treturn, int varargs, e
|
||||
if (stc & STCproperty)
|
||||
this->isproperty = true;
|
||||
|
||||
if (stc & STCref)
|
||||
this->isref = true;
|
||||
|
||||
this->trust = TRUSTdefault;
|
||||
if (stc & STCsafe)
|
||||
this->trust = TRUSTsafe;
|
||||
@@ -4703,7 +4824,12 @@ int Type::covariant(Type *t)
|
||||
}
|
||||
}
|
||||
else if (t1->parameters != t2->parameters)
|
||||
goto Ldistinct;
|
||||
{
|
||||
size_t dim1 = !t1->parameters ? 0 : t1->parameters->dim;
|
||||
size_t dim2 = !t2->parameters ? 0 : t2->parameters->dim;
|
||||
if (dim1 || dim2)
|
||||
goto Ldistinct;
|
||||
}
|
||||
|
||||
// The argument lists match
|
||||
if (inoutmismatch)
|
||||
@@ -4879,8 +5005,6 @@ void TypeFunction::toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs
|
||||
void TypeFunction::toCBufferWithAttributes(OutBuffer *buf, Identifier *ident, HdrGenState* hgs, TypeFunction *attrs, TemplateDeclaration *td)
|
||||
{
|
||||
//printf("TypeFunction::toCBuffer() this = %p\n", this);
|
||||
const char *p = NULL;
|
||||
|
||||
if (inuse)
|
||||
{ inuse = 2; // flag error to caller
|
||||
return;
|
||||
@@ -4919,19 +5043,16 @@ void TypeFunction::toCBufferWithAttributes(OutBuffer *buf, Identifier *ident, Hd
|
||||
break;
|
||||
}
|
||||
|
||||
if (next && (!ident || ident->toHChars2() == ident->toChars()))
|
||||
next->toCBuffer2(buf, hgs, 0);
|
||||
else if (hgs->ddoc && !next)
|
||||
buf->writestring("auto");
|
||||
if (hgs->ddoc != 1)
|
||||
{
|
||||
const char *p = NULL;
|
||||
switch (attrs->linkage)
|
||||
{
|
||||
case LINKd: p = NULL; break;
|
||||
case LINKc: p = "C "; break;
|
||||
case LINKwindows: p = "Windows "; break;
|
||||
case LINKpascal: p = "Pascal "; break;
|
||||
case LINKcpp: p = "C++ "; break;
|
||||
case LINKc: p = "C"; break;
|
||||
case LINKwindows: p = "Windows"; break;
|
||||
case LINKpascal: p = "Pascal"; break;
|
||||
case LINKcpp: p = "C++"; break;
|
||||
|
||||
// LDC
|
||||
case LINKintrinsic: p = "Intrinsic"; break;
|
||||
@@ -4939,14 +5060,28 @@ void TypeFunction::toCBufferWithAttributes(OutBuffer *buf, Identifier *ident, Hd
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
if (!hgs->hdrgen && p)
|
||||
{
|
||||
buf->writestring("extern (");
|
||||
buf->writestring(p);
|
||||
buf->writestring(") ");
|
||||
}
|
||||
}
|
||||
|
||||
if (!ident || ident->toHChars2() == ident->toChars())
|
||||
{ if (next)
|
||||
next->toCBuffer2(buf, hgs, 0);
|
||||
else if (hgs->ddoc)
|
||||
buf->writestring("auto");
|
||||
}
|
||||
|
||||
if (!hgs->hdrgen && p)
|
||||
buf->writestring(p);
|
||||
if (ident)
|
||||
{ buf->writeByte(' ');
|
||||
{
|
||||
if (next || hgs->ddoc)
|
||||
buf->writeByte(' ');
|
||||
buf->writestring(ident->toHChars2());
|
||||
}
|
||||
|
||||
if (td)
|
||||
{ buf->writeByte('(');
|
||||
for (size_t i = 0; i < td->origParameters->dim; i++)
|
||||
@@ -4965,24 +5100,21 @@ void TypeFunction::toCBufferWithAttributes(OutBuffer *buf, Identifier *ident, Hd
|
||||
void TypeFunction::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
|
||||
{
|
||||
//printf("TypeFunction::toCBuffer2() this = %p, ref = %d\n", this, isref);
|
||||
const char *p = NULL;
|
||||
|
||||
if (inuse)
|
||||
{ inuse = 2; // flag error to caller
|
||||
return;
|
||||
}
|
||||
inuse++;
|
||||
if (next)
|
||||
next->toCBuffer2(buf, hgs, 0);
|
||||
if (hgs->ddoc != 1)
|
||||
{
|
||||
const char *p = NULL;
|
||||
switch (linkage)
|
||||
{
|
||||
case LINKd: p = NULL; break;
|
||||
case LINKc: p = " C"; break;
|
||||
case LINKwindows: p = " Windows"; break;
|
||||
case LINKpascal: p = " Pascal"; break;
|
||||
case LINKcpp: p = " C++"; break;
|
||||
case LINKc: p = "C"; break;
|
||||
case LINKwindows: p = "Windows"; break;
|
||||
case LINKpascal: p = "Pascal"; break;
|
||||
case LINKcpp: p = "C++"; break;
|
||||
|
||||
// LDC
|
||||
case LINKintrinsic: p = "Intrinsic"; break;
|
||||
@@ -4990,11 +5122,19 @@ void TypeFunction::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
if (!hgs->hdrgen && p)
|
||||
{
|
||||
buf->writestring("extern (");
|
||||
buf->writestring(p);
|
||||
buf->writestring(") ");
|
||||
}
|
||||
}
|
||||
|
||||
if (!hgs->hdrgen && p)
|
||||
buf->writestring(p);
|
||||
buf->writestring(" function");
|
||||
if (next)
|
||||
{
|
||||
next->toCBuffer2(buf, hgs, 0);
|
||||
buf->writeByte(' ');
|
||||
}
|
||||
buf->writestring("function");
|
||||
Parameter::argsToCBuffer(buf, hgs, parameters, varargs);
|
||||
attributesToCBuffer(buf, mod);
|
||||
inuse--;
|
||||
@@ -5091,7 +5231,10 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc)
|
||||
bool wildreturn = FALSE;
|
||||
if (tf->next)
|
||||
{
|
||||
sc = sc->push();
|
||||
sc->stc &= ~(STC_TYPECTOR | STC_FUNCATTR);
|
||||
tf->next = tf->next->semantic(loc,sc);
|
||||
sc = sc->pop();
|
||||
#if !SARRAYVALUE
|
||||
if (tf->next->toBasetype()->ty == Tsarray)
|
||||
{ error(loc, "functions cannot return static array %s", tf->next->toChars());
|
||||
@@ -5110,7 +5253,8 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc)
|
||||
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->isWild())
|
||||
if (tf->next->hasWild() &&
|
||||
!(tf->next->ty == Tpointer && tf->next->nextOf()->ty == Tfunction || tf->next->ty == Tdelegate))
|
||||
wildreturn = TRUE;
|
||||
}
|
||||
|
||||
@@ -5152,7 +5296,8 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc)
|
||||
if (!(fparam->storageClass & STClazy) && t->ty == Tvoid)
|
||||
error(loc, "cannot have parameter of type %s", fparam->type->toChars());
|
||||
|
||||
if (t->isWild())
|
||||
if (t->hasWild() &&
|
||||
!(t->ty == Tpointer && t->nextOf()->ty == Tfunction || t->ty == Tdelegate))
|
||||
{
|
||||
wildparams = TRUE;
|
||||
if (tf->next && !wildreturn)
|
||||
@@ -5211,6 +5356,9 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc)
|
||||
}
|
||||
argsc->pop();
|
||||
}
|
||||
if (tf->isWild())
|
||||
wildparams = TRUE;
|
||||
|
||||
if (wildreturn && !wildparams)
|
||||
error(loc, "inout on return means inout must be on a parameter as well for %s", toChars());
|
||||
if (wildsubparams && wildparams)
|
||||
@@ -5338,6 +5486,11 @@ int TypeFunction::callMatch(Expression *ethis, Expressions *args, int flag)
|
||||
{
|
||||
if (MODimplicitConv(t->mod, mod))
|
||||
match = MATCHconst;
|
||||
else if ((mod & MODwild)
|
||||
&& MODimplicitConv(t->mod, (mod & ~MODwild) | MODconst))
|
||||
{
|
||||
match = MATCHconst;
|
||||
}
|
||||
else
|
||||
return MATCHnomatch;
|
||||
}
|
||||
@@ -5406,15 +5559,15 @@ int TypeFunction::callMatch(Expression *ethis, Expressions *args, int flag)
|
||||
else
|
||||
m = arg->implicitConvTo(p->type);
|
||||
//printf("match %d\n", m);
|
||||
if (p->type->isWild())
|
||||
if (p->type->hasWild())
|
||||
{
|
||||
if (m == MATCHnomatch)
|
||||
{
|
||||
m = arg->implicitConvTo(p->type->constOf());
|
||||
if (m == MATCHnomatch)
|
||||
m = arg->implicitConvTo(p->type->sharedConstOf());
|
||||
if (m != MATCHnomatch)
|
||||
if (p->type->wildMatch(arg->type))
|
||||
{
|
||||
wildmatch = TRUE; // mod matched to wild
|
||||
m = MATCHconst;
|
||||
}
|
||||
}
|
||||
else
|
||||
exactwildmatch = TRUE; // wild matched to wild
|
||||
@@ -5422,11 +5575,17 @@ int TypeFunction::callMatch(Expression *ethis, Expressions *args, int flag)
|
||||
/* If both are allowed, then there could be more than one
|
||||
* binding of mod to wild, leaving a gaping type hole.
|
||||
*/
|
||||
if (wildmatch && exactwildmatch)
|
||||
m = MATCHnomatch;
|
||||
//if (wildmatch && exactwildmatch)
|
||||
// m = MATCHnomatch;
|
||||
}
|
||||
}
|
||||
|
||||
/* prefer matching the element type rather than the array
|
||||
* type when more arguments are present with T[]...
|
||||
*/
|
||||
if (varargs == 2 && u + 1 == nparams && nargs > nparams)
|
||||
goto L1;
|
||||
|
||||
//printf("\tm = %d\n", m);
|
||||
if (m == MATCHnomatch) // if no match
|
||||
{
|
||||
@@ -5823,7 +5982,14 @@ void TypeQualified::resolveHelper(Loc loc, Scope *sc,
|
||||
|
||||
t = s->getType();
|
||||
if (!t && s->isDeclaration())
|
||||
t = s->isDeclaration()->type;
|
||||
{ t = s->isDeclaration()->type;
|
||||
if (!t && s->isTupleDeclaration())
|
||||
{
|
||||
e = new TupleExp(loc, s->isTupleDeclaration());
|
||||
e = e->semantic(sc);
|
||||
t = e->type;
|
||||
}
|
||||
}
|
||||
if (t)
|
||||
{
|
||||
sm = t->toDsymbol(sc);
|
||||
@@ -6192,15 +6358,12 @@ Type *TypeInstance::semantic(Loc loc, Scope *sc)
|
||||
|
||||
if (sc->parameterSpecialization)
|
||||
{
|
||||
unsigned errors = global.errors;
|
||||
global.gag++;
|
||||
unsigned errors = global.startGagging();
|
||||
|
||||
resolve(loc, sc, &e, &t, &s);
|
||||
|
||||
global.gag--;
|
||||
if (errors != global.errors)
|
||||
{ if (global.gag == 0)
|
||||
global.errors = errors;
|
||||
if (global.endGagging(errors))
|
||||
{
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -6225,17 +6388,12 @@ Dsymbol *TypeInstance::toDsymbol(Scope *sc)
|
||||
|
||||
if (sc->parameterSpecialization)
|
||||
{
|
||||
unsigned errors = global.errors;
|
||||
global.gag++;
|
||||
unsigned errors = global.startGagging();
|
||||
|
||||
resolve(loc, sc, &e, &t, &s);
|
||||
|
||||
global.gag--;
|
||||
if (errors != global.errors)
|
||||
{ if (global.gag == 0)
|
||||
global.errors = errors;
|
||||
if (global.endGagging(errors))
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
resolve(loc, sc, &e, &t, &s);
|
||||
@@ -6790,7 +6948,10 @@ char *TypeTypedef::toChars()
|
||||
Type *TypeTypedef::semantic(Loc loc, Scope *sc)
|
||||
{
|
||||
//printf("TypeTypedef::semantic(%s), sem = %d\n", toChars(), sym->sem);
|
||||
int errors = global.errors;
|
||||
sym->semantic(sc);
|
||||
if (errors != global.errors)
|
||||
return terror;
|
||||
return merge();
|
||||
}
|
||||
|
||||
@@ -7024,6 +7185,7 @@ int TypeTypedef::hasPointers()
|
||||
|
||||
int TypeTypedef::hasWild()
|
||||
{
|
||||
assert(toBasetype());
|
||||
return mod & MODwild || toBasetype()->hasWild();
|
||||
}
|
||||
|
||||
@@ -7459,13 +7621,10 @@ MATCH TypeStruct::implicitConvTo(Type *to)
|
||||
/* If there is an error instantiating AssociativeArray!(), it shouldn't
|
||||
* be reported -- it just means implicit conversion is impossible.
|
||||
*/
|
||||
++global.gag;
|
||||
int errs = global.errors;
|
||||
int errs = global.startGagging();
|
||||
to = ((TypeAArray*)to)->getImpl()->type;
|
||||
--global.gag;
|
||||
if (errs != global.errors)
|
||||
if (global.endGagging(errs))
|
||||
{
|
||||
global.errors = errs;
|
||||
return MATCHnomatch;
|
||||
}
|
||||
}
|
||||
|
||||
27
dmd2/mtype.h
27
dmd2/mtype.h
@@ -286,6 +286,7 @@ struct Type : Object
|
||||
Type *sharedWildOf();
|
||||
void fixTo(Type *t);
|
||||
void check();
|
||||
Type *addSTC(StorageClass stc);
|
||||
Type *castMod(unsigned mod);
|
||||
Type *addMod(unsigned mod);
|
||||
Type *addStorageClass(StorageClass stc);
|
||||
@@ -317,7 +318,7 @@ struct Type : Object
|
||||
virtual dt_t **toDt(dt_t **pdt);
|
||||
#endif
|
||||
Identifier *getTypeInfoIdent(int internal);
|
||||
virtual MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes);
|
||||
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);
|
||||
Expression *getInternalTypeInfo(Scope *sc);
|
||||
Expression *getTypeInfo(Scope *sc);
|
||||
@@ -325,7 +326,8 @@ struct Type : Object
|
||||
virtual int builtinTypeInfo();
|
||||
virtual Type *reliesOnTident();
|
||||
virtual int hasWild();
|
||||
virtual unsigned wildMatch(Type *targ);
|
||||
unsigned wildMatch(Type *targ);
|
||||
Type *substWildTo(unsigned mod);
|
||||
virtual Expression *toExpression();
|
||||
virtual int hasPointers();
|
||||
virtual TypeTuple *toArgTypes();
|
||||
@@ -376,7 +378,6 @@ struct TypeNext : Type
|
||||
void checkDeprecated(Loc loc, Scope *sc);
|
||||
Type *reliesOnTident();
|
||||
int hasWild();
|
||||
unsigned wildMatch(Type *targ);
|
||||
Type *nextOf();
|
||||
Type *makeConst();
|
||||
Type *makeInvariant();
|
||||
@@ -456,7 +457,7 @@ struct TypeSArray : TypeArray
|
||||
dt_t **toDt(dt_t **pdt);
|
||||
dt_t **toDtElem(dt_t **pdt, Expression *e);
|
||||
#endif
|
||||
MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes);
|
||||
MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch = NULL);
|
||||
TypeInfoDeclaration *getTypeInfoDeclaration();
|
||||
Expression *toExpression();
|
||||
int hasPointers();
|
||||
@@ -489,7 +490,7 @@ struct TypeDArray : TypeArray
|
||||
MATCH implicitConvTo(Type *to);
|
||||
Expression *defaultInit(Loc loc);
|
||||
int builtinTypeInfo();
|
||||
MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes);
|
||||
MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch = NULL);
|
||||
TypeInfoDeclaration *getTypeInfoDeclaration();
|
||||
int hasPointers();
|
||||
TypeTuple *toArgTypes();
|
||||
@@ -520,7 +521,7 @@ struct TypeAArray : TypeArray
|
||||
void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod);
|
||||
Expression *dotExp(Scope *sc, Expression *e, Identifier *ident);
|
||||
Expression *defaultInit(Loc loc);
|
||||
MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes);
|
||||
MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch = NULL);
|
||||
int isZeroInit(Loc loc);
|
||||
int checkBoolean();
|
||||
TypeInfoDeclaration *getTypeInfoDeclaration();
|
||||
@@ -630,7 +631,7 @@ struct TypeFunction : TypeNext
|
||||
void toCBufferWithAttributes(OutBuffer *buf, Identifier *ident, HdrGenState* hgs, TypeFunction *attrs, TemplateDeclaration *td);
|
||||
void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod);
|
||||
void attributesToCBuffer(OutBuffer *buf, int mod);
|
||||
MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes);
|
||||
MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch = NULL);
|
||||
TypeInfoDeclaration *getTypeInfoDeclaration();
|
||||
Type *reliesOnTident();
|
||||
bool hasLazyParameters();
|
||||
@@ -713,7 +714,7 @@ struct TypeIdentifier : TypeQualified
|
||||
void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps);
|
||||
Dsymbol *toDsymbol(Scope *sc);
|
||||
Type *semantic(Loc loc, Scope *sc);
|
||||
MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes);
|
||||
MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch = NULL);
|
||||
Type *reliesOnTident();
|
||||
Expression *toExpression();
|
||||
};
|
||||
@@ -732,7 +733,7 @@ struct TypeInstance : TypeQualified
|
||||
void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps);
|
||||
Type *semantic(Loc loc, Scope *sc);
|
||||
Dsymbol *toDsymbol(Scope *sc);
|
||||
MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes);
|
||||
MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch = NULL);
|
||||
};
|
||||
|
||||
struct TypeTypeof : TypeQualified
|
||||
@@ -781,7 +782,7 @@ struct TypeStruct : Type
|
||||
#if IN_DMD
|
||||
dt_t **toDt(dt_t **pdt);
|
||||
#endif
|
||||
MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes);
|
||||
MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch = NULL);
|
||||
TypeInfoDeclaration *getTypeInfoDeclaration();
|
||||
int hasPointers();
|
||||
TypeTuple *toArgTypes();
|
||||
@@ -832,7 +833,7 @@ struct TypeEnum : Type
|
||||
Type *toBasetype();
|
||||
Expression *defaultInit(Loc loc);
|
||||
int isZeroInit(Loc loc);
|
||||
MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes);
|
||||
MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch = NULL);
|
||||
TypeInfoDeclaration *getTypeInfoDeclaration();
|
||||
int hasPointers();
|
||||
TypeTuple *toArgTypes();
|
||||
@@ -879,7 +880,7 @@ struct TypeTypedef : Type
|
||||
#if IN_DMD
|
||||
dt_t **toDt(dt_t **pdt);
|
||||
#endif
|
||||
MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes);
|
||||
MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch = NULL);
|
||||
TypeInfoDeclaration *getTypeInfoDeclaration();
|
||||
int hasPointers();
|
||||
TypeTuple *toArgTypes();
|
||||
@@ -913,7 +914,7 @@ struct TypeClass : Type
|
||||
MATCH implicitConvTo(Type *to);
|
||||
Expression *defaultInit(Loc loc);
|
||||
int isZeroInit(Loc loc);
|
||||
MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes);
|
||||
MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch = NULL);
|
||||
int isscope();
|
||||
int checkBoolean();
|
||||
TypeInfoDeclaration *getTypeInfoDeclaration();
|
||||
|
||||
@@ -1275,7 +1275,10 @@ void inferApplyArgTypes(enum TOK op, Parameters *arguments, Expression *aggr, Mo
|
||||
break;
|
||||
goto Lapply;
|
||||
}
|
||||
// Resolve inout qualifier of front type
|
||||
arg->type = fd->type->nextOf();
|
||||
if (arg->type)
|
||||
arg->type = arg->type->substWildTo(tab->mod);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -874,6 +874,71 @@ Expression *XorExp::optimize(int result)
|
||||
return e;
|
||||
}
|
||||
|
||||
Expression *PowExp::optimize(int result)
|
||||
{ Expression *e;
|
||||
|
||||
e1 = e1->optimize(result);
|
||||
e2 = e2->optimize(result);
|
||||
|
||||
// Replace 1 ^^ x or 1.0^^x by (x, 1)
|
||||
if ((e1->op == TOKint64 && e1->toInteger() == 1) ||
|
||||
(e1->op == TOKfloat64 && e1->toReal() == 1.0))
|
||||
{
|
||||
e = new CommaExp(loc, e2, e1);
|
||||
}
|
||||
// Replace -1 ^^ x by (x&1) ? -1 : 1, where x is integral
|
||||
else if (e2->type->isintegral() && e1->op == TOKint64 && (sinteger_t)e1->toInteger() == -1L)
|
||||
{
|
||||
Type* resultType = type;
|
||||
e = new AndExp(loc, e2, new IntegerExp(loc, 1, e2->type));
|
||||
e = new CondExp(loc, e, new IntegerExp(loc, -1L, resultType), new IntegerExp(loc, 1L, resultType));
|
||||
}
|
||||
// Replace x ^^ 0 or x^^0.0 by (x, 1)
|
||||
else if ((e2->op == TOKint64 && e2->toInteger() == 0) ||
|
||||
(e2->op == TOKfloat64 && e2->toReal() == 0.0))
|
||||
{
|
||||
if (e1->type->isintegral())
|
||||
e = new IntegerExp(loc, 1, e1->type);
|
||||
else
|
||||
e = new RealExp(loc, 1.0, e1->type);
|
||||
|
||||
e = new CommaExp(loc, e1, e);
|
||||
}
|
||||
// Replace x ^^ 1 or x^^1.0 by (x)
|
||||
else if ((e2->op == TOKint64 && e2->toInteger() == 1) ||
|
||||
(e2->op == TOKfloat64 && e2->toReal() == 1.0))
|
||||
{
|
||||
e = e1;
|
||||
}
|
||||
// Replace x ^^ -1.0 by (1.0 / x)
|
||||
else if ((e2->op == TOKfloat64 && e2->toReal() == -1.0))
|
||||
{
|
||||
e = new DivExp(loc, new RealExp(loc, 1.0, e2->type), e1);
|
||||
}
|
||||
// All other negative integral powers are illegal
|
||||
else if ((e1->type->isintegral()) && (e2->op == TOKint64) && (sinteger_t)e2->toInteger() < 0)
|
||||
{
|
||||
error("cannot raise %s to a negative integer power. Did you mean (cast(real)%s)^^%s ?",
|
||||
e1->type->toBasetype()->toChars(), e1->toChars(), e2->toChars());
|
||||
e = new ErrorExp();
|
||||
}
|
||||
else
|
||||
{
|
||||
// If e2 *could* have been an integer, make it one.
|
||||
if (e2->op == TOKfloat64 && (e2->toReal() == (sinteger_t)(e2->toReal())))
|
||||
e2 = new IntegerExp(loc, e2->toInteger(), Type::tint64);
|
||||
|
||||
if (e1->isConst() == 1 && e2->isConst() == 1)
|
||||
{
|
||||
e = Pow(type, e1, e2);
|
||||
if (e != EXP_CANT_INTERPRET)
|
||||
return e;
|
||||
}
|
||||
e = this;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
Expression *CommaExp::optimize(int result)
|
||||
{ Expression *e;
|
||||
|
||||
|
||||
62
dmd2/parse.c
62
dmd2/parse.c
@@ -386,10 +386,16 @@ Dsymbols *Parser::parseDeclDefs(int once)
|
||||
storageClass |= stc;
|
||||
switch (token.value)
|
||||
{
|
||||
case TOKshared:
|
||||
// Look for "shared static this" or "shared static ~this"
|
||||
if (peekNext() == TOKstatic)
|
||||
{ TOK next2 = peekNext2();
|
||||
if (next2 == TOKthis || next2 == TOKtilde)
|
||||
break;
|
||||
}
|
||||
case TOKconst:
|
||||
case TOKinvariant:
|
||||
case TOKimmutable:
|
||||
case TOKshared:
|
||||
case TOKwild:
|
||||
// If followed by a (, it is not a storage class
|
||||
if (peek(&token)->value == TOKlparen)
|
||||
@@ -547,7 +553,7 @@ Dsymbols *Parser::parseDeclDefs(int once)
|
||||
nextToken();
|
||||
if (token.value == TOKidentifier)
|
||||
s = new DebugSymbol(loc, token.ident);
|
||||
else if (token.value == TOKint32v)
|
||||
else if (token.value == TOKint32v || token.value == TOKint64v)
|
||||
s = new DebugSymbol(loc, (unsigned)token.uns64value);
|
||||
else
|
||||
{ error("identifier or integer expected, not %s", token.toChars());
|
||||
@@ -570,7 +576,7 @@ Dsymbols *Parser::parseDeclDefs(int once)
|
||||
nextToken();
|
||||
if (token.value == TOKidentifier)
|
||||
s = new VersionSymbol(loc, token.ident);
|
||||
else if (token.value == TOKint32v)
|
||||
else if (token.value == TOKint32v || token.value == TOKint64v)
|
||||
s = new VersionSymbol(loc, (unsigned)token.uns64value);
|
||||
else
|
||||
{ error("identifier or integer expected, not %s", token.toChars());
|
||||
@@ -699,10 +705,9 @@ StorageClass Parser::parsePostfix()
|
||||
case TOKpure: stc |= STCpure; break;
|
||||
case TOKat: stc |= parseAttribute(); break;
|
||||
|
||||
default:
|
||||
composeStorageClass(stc);
|
||||
return stc;
|
||||
default: return stc;
|
||||
}
|
||||
composeStorageClass(stc);
|
||||
nextToken();
|
||||
}
|
||||
}
|
||||
@@ -876,7 +881,7 @@ Condition *Parser::parseDebugCondition()
|
||||
|
||||
if (token.value == TOKidentifier)
|
||||
id = token.ident;
|
||||
else if (token.value == TOKint32v)
|
||||
else if (token.value == TOKint32v || token.value == TOKint64v)
|
||||
level = (unsigned)token.uns64value;
|
||||
else
|
||||
error("identifier or integer expected, not %s", token.toChars());
|
||||
@@ -905,7 +910,7 @@ Condition *Parser::parseVersionCondition()
|
||||
nextToken();
|
||||
if (token.value == TOKidentifier)
|
||||
id = token.ident;
|
||||
else if (token.value == TOKint32v)
|
||||
else if (token.value == TOKint32v || token.value == TOKint64v)
|
||||
level = (unsigned)token.uns64value;
|
||||
#if DMDV2
|
||||
/* Allow:
|
||||
@@ -995,7 +1000,9 @@ Dsymbol *Parser::parseCtor()
|
||||
|
||||
Expression *constraint = tpl ? parseConstraint() : NULL;
|
||||
|
||||
Type *tf = new TypeFunction(parameters, NULL, varargs, linkage, stc); // RetrunType -> auto
|
||||
Type *tf = new TypeFunction(parameters, NULL, varargs, linkage, stc); // RetrunType -> auto
|
||||
tf = tf->addSTC(stc);
|
||||
|
||||
CtorDeclaration *f = new CtorDeclaration(loc, 0, stc, tf);
|
||||
parseContracts(f);
|
||||
|
||||
@@ -1012,7 +1019,9 @@ Dsymbol *Parser::parseCtor()
|
||||
int varargs;
|
||||
Parameters *parameters = parseParameters(&varargs);
|
||||
StorageClass stc = parsePostfix();
|
||||
Type *tf = new TypeFunction(parameters, NULL, varargs, linkage, stc); // RetrunType -> auto
|
||||
Type *tf = new TypeFunction(parameters, NULL, varargs, linkage, stc); // RetrunType -> auto
|
||||
tf = tf->addSTC(stc);
|
||||
|
||||
CtorDeclaration *f = new CtorDeclaration(loc, 0, stc, tf);
|
||||
parseContracts(f);
|
||||
return f;
|
||||
@@ -2633,27 +2642,7 @@ Type *Parser::parseDeclarator(Type *t, Identifier **pident, TemplateParameters *
|
||||
StorageClass stc = parsePostfix();
|
||||
stc |= storage_class; // merge prefix storage classes
|
||||
Type *tf = new TypeFunction(arguments, t, varargs, linkage, stc);
|
||||
|
||||
if (stc & STCconst)
|
||||
{ if (tf->isShared())
|
||||
tf = tf->makeSharedConst();
|
||||
else
|
||||
tf = tf->makeConst();
|
||||
}
|
||||
if (stc & STCimmutable)
|
||||
tf = tf->makeInvariant();
|
||||
if (stc & STCshared)
|
||||
{ if (tf->isConst())
|
||||
tf = tf->makeSharedConst();
|
||||
else
|
||||
tf = tf->makeShared();
|
||||
}
|
||||
if (stc & STCwild)
|
||||
{ if (tf->isShared())
|
||||
tf = tf->makeSharedWild();
|
||||
else
|
||||
tf = tf->makeWild();
|
||||
}
|
||||
tf = tf->addSTC(stc);
|
||||
|
||||
/* Insert tf into
|
||||
* ts -> ... -> t
|
||||
@@ -3681,6 +3670,10 @@ Statement *Parser::parseStatement(int flags)
|
||||
check(TOKlparen);
|
||||
condition = parseExpression();
|
||||
check(TOKrparen);
|
||||
if (token.value == TOKsemicolon)
|
||||
nextToken();
|
||||
else if (!global.params.useDeprecated)
|
||||
error("do-while statement requires terminating ;");
|
||||
s = new DoStatement(loc, body, condition);
|
||||
break;
|
||||
}
|
||||
@@ -5764,9 +5757,12 @@ Expression *Parser::parseUnaryExp()
|
||||
case TOKimmutable: // immutable(type)(arguments)
|
||||
{
|
||||
Type *t = parseBasicType();
|
||||
if (token.value != TOKlparen)
|
||||
error("(arguments) expected following type");
|
||||
e = new TypeExp(loc, t);
|
||||
if (token.value != TOKlparen)
|
||||
{
|
||||
error("(arguments) expected following %s", t->toChars());
|
||||
return e;
|
||||
}
|
||||
e = new CallExp(loc, e, parseArguments());
|
||||
break;
|
||||
}
|
||||
|
||||
16
dmd2/rmem.h
16
dmd2/rmem.h
@@ -1,16 +0,0 @@
|
||||
#ifndef __RMEM_H__
|
||||
#define __RMEM_H__
|
||||
|
||||
// jam memory stuff here
|
||||
|
||||
#include "mem.h"
|
||||
|
||||
#if (defined (__SVR4) && defined (__sun))
|
||||
#include <alloca.h>
|
||||
#endif
|
||||
|
||||
#ifdef __MINGW32__
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
#endif // __RMEM_H__
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <process.h>
|
||||
|
||||
#include "root.h"
|
||||
#include "rmem.h"
|
||||
|
||||
static unsigned __stdcall startthread(void *p);
|
||||
|
||||
@@ -41,7 +40,7 @@ struct AsyncRead
|
||||
|
||||
AsyncRead *AsyncRead::create(size_t nfiles)
|
||||
{
|
||||
AsyncRead *aw = (AsyncRead *)mem.calloc(1, sizeof(AsyncRead) +
|
||||
AsyncRead *aw = (AsyncRead *)calloc(1, sizeof(AsyncRead) +
|
||||
(nfiles - 1) * sizeof(FileData));
|
||||
aw->filesmax = nfiles;
|
||||
return aw;
|
||||
@@ -92,7 +91,7 @@ int AsyncRead::read(size_t i)
|
||||
|
||||
void AsyncRead::dispose(AsyncRead *aw)
|
||||
{
|
||||
delete aw;
|
||||
free(aw);
|
||||
}
|
||||
|
||||
|
||||
@@ -119,7 +118,6 @@ unsigned __stdcall startthread(void *p)
|
||||
#include <time.h>
|
||||
|
||||
#include "root.h"
|
||||
#include "rmem.h"
|
||||
|
||||
void *startthread(void *arg);
|
||||
|
||||
@@ -155,7 +153,7 @@ struct AsyncRead
|
||||
|
||||
AsyncRead *AsyncRead::create(size_t nfiles)
|
||||
{
|
||||
AsyncRead *aw = (AsyncRead *)mem.calloc(1, sizeof(AsyncRead) +
|
||||
AsyncRead *aw = (AsyncRead *)calloc(1, sizeof(AsyncRead) +
|
||||
(nfiles - 1) * sizeof(FileData));
|
||||
aw->filesmax = nfiles;
|
||||
return aw;
|
||||
@@ -228,7 +226,7 @@ void AsyncRead::dispose(AsyncRead *aw)
|
||||
if (status != 0)
|
||||
err_abort(status, "mutex destroy");
|
||||
}
|
||||
delete aw;
|
||||
free(aw);
|
||||
}
|
||||
|
||||
|
||||
@@ -265,7 +263,6 @@ void *startthread(void *p)
|
||||
#include <errno.h>
|
||||
|
||||
#include "root.h"
|
||||
#include "rmem.h"
|
||||
|
||||
struct FileData
|
||||
{
|
||||
@@ -292,7 +289,7 @@ struct AsyncRead
|
||||
|
||||
AsyncRead *AsyncRead::create(size_t nfiles)
|
||||
{
|
||||
AsyncRead *aw = (AsyncRead *)mem.calloc(1, sizeof(AsyncRead) +
|
||||
AsyncRead *aw = (AsyncRead *)calloc(1, sizeof(AsyncRead) +
|
||||
(nfiles - 1) * sizeof(FileData));
|
||||
aw->filesmax = nfiles;
|
||||
return aw;
|
||||
@@ -322,7 +319,7 @@ int AsyncRead::read(size_t i)
|
||||
|
||||
void AsyncRead::dispose(AsyncRead *aw)
|
||||
{
|
||||
delete aw;
|
||||
free(aw);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
43
dmd2/root/bits.c
Normal file
43
dmd2/root/bits.c
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright (c) 2000-2011 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 <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "bits.h"
|
||||
|
||||
GCBits::GCBits()
|
||||
{
|
||||
data = NULL;
|
||||
nwords = 0;
|
||||
nbits = 0;
|
||||
}
|
||||
|
||||
GCBits::~GCBits()
|
||||
{
|
||||
if (data)
|
||||
::free(data);
|
||||
data = NULL;
|
||||
}
|
||||
|
||||
void GCBits::invariant()
|
||||
{
|
||||
if (data)
|
||||
{
|
||||
assert(nwords * sizeof(*data) * 8 >= nbits);
|
||||
}
|
||||
}
|
||||
|
||||
void GCBits::alloc(unsigned nbits)
|
||||
{
|
||||
this->nbits = nbits;
|
||||
nwords = (nbits + (BITS_PER_WORD - 1)) >> BITS_SHIFT;
|
||||
data = (unsigned *)::calloc(nwords + 2, sizeof(unsigned));
|
||||
assert(data);
|
||||
}
|
||||
83
dmd2/root/bits.h
Normal file
83
dmd2/root/bits.h
Normal file
@@ -0,0 +1,83 @@
|
||||
// Copyright (c) 2000-2011 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 <string.h>
|
||||
|
||||
#if __DMC__
|
||||
// Inline bit operations
|
||||
#include <bitops.h>
|
||||
#endif
|
||||
|
||||
#ifdef linux
|
||||
#include "gccbitops.h"
|
||||
#endif
|
||||
|
||||
#if _MSC_VER
|
||||
// Disable useless warnings about unreferenced functions
|
||||
#pragma warning (disable : 4514)
|
||||
#endif // _MSC_VER
|
||||
|
||||
|
||||
#define BITS_PER_WORD 32
|
||||
#define BITS_SHIFT 5
|
||||
#define BITS_MASK 31
|
||||
|
||||
struct Mem;
|
||||
|
||||
struct GCBits
|
||||
{
|
||||
unsigned *data;
|
||||
unsigned nwords; // allocated words in data[] excluding sentinals
|
||||
unsigned nbits; // number of bits in data[] excluding sentinals
|
||||
|
||||
GCBits();
|
||||
~GCBits();
|
||||
void invariant();
|
||||
|
||||
void alloc(unsigned nbits);
|
||||
|
||||
#if __DMC__
|
||||
unsigned test(unsigned i) { return _inline_bt(data + 1, i); }
|
||||
void set(unsigned i) { _inline_bts(data + 1, i); }
|
||||
void clear(unsigned i) { _inline_btr(data + 1, i); }
|
||||
unsigned testClear(unsigned i) { return _inline_btr(data + 1, i); }
|
||||
unsigned testSet(unsigned i) { return _inline_bts(data + 1, i); }
|
||||
#elif 0 //defined linux
|
||||
// for unknown reasons, GCC does badly with this
|
||||
unsigned test(unsigned i) { return _inline_bt(data + 1, i); }
|
||||
void set(unsigned i) { _inline_bts(data + 1, i); }
|
||||
void clear(unsigned i) { _inline_btr(data + 1, i); }
|
||||
unsigned testClear(unsigned i) { return _inline_btr(data + 1, i); }
|
||||
unsigned testSet(unsigned i) { return _inline_bts(data + 1, i); }
|
||||
#else
|
||||
unsigned test(unsigned i) { return data[1 + (i >> BITS_SHIFT)] & (1 << (i & BITS_MASK)); }
|
||||
void set(unsigned i) { data[1 + (i >> BITS_SHIFT)] |= (1 << (i & BITS_MASK)); }
|
||||
void clear(unsigned i) { data[1 + (i >> BITS_SHIFT)] &= ~(1 << (i & BITS_MASK)); }
|
||||
unsigned testClear(unsigned i)
|
||||
{
|
||||
unsigned *p = &data[1 + (i >> BITS_SHIFT)];
|
||||
unsigned mask = (1 << (i & BITS_MASK));
|
||||
unsigned result = *p & mask;
|
||||
*p &= ~mask;
|
||||
return result;
|
||||
}
|
||||
unsigned testSet(unsigned i)
|
||||
{
|
||||
unsigned *p = &data[1 + (i >> BITS_SHIFT)];
|
||||
unsigned mask = (1 << (i & BITS_MASK));
|
||||
unsigned result = *p & mask;
|
||||
*p |= mask;
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
void zero() { memset(data + 1, 0, nwords * sizeof(unsigned)); }
|
||||
void copy(GCBits *f) { memcpy(data + 1, f->data + 1, nwords * sizeof(unsigned)); }
|
||||
|
||||
unsigned *base() { return data + 1; }
|
||||
};
|
||||
499
dmd2/root/dmgcmem.c
Normal file
499
dmd2/root/dmgcmem.c
Normal file
@@ -0,0 +1,499 @@
|
||||
|
||||
|
||||
// Copyright (c) 2000-2011 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#include "rmem.h"
|
||||
#include "gc/gc.h"
|
||||
//#include "printf.h"
|
||||
|
||||
/* This implementation of the storage allocator uses the Digital Mars gc.
|
||||
*/
|
||||
|
||||
Mem mem;
|
||||
|
||||
//static int nuncollectable;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
void gc_init();
|
||||
GC *gc_get();
|
||||
}
|
||||
|
||||
void Mem::init()
|
||||
{
|
||||
gc_init();
|
||||
}
|
||||
|
||||
char *Mem::strdup(const char *s)
|
||||
{
|
||||
return gc_get()->strdup(s);
|
||||
}
|
||||
|
||||
void *Mem::malloc(size_t size)
|
||||
{
|
||||
if (gc) // if cached allocator
|
||||
{
|
||||
// PRINTF("Using cached gc for size %d, file = '%s', line = %d\n", size, GC::file, GC::line);
|
||||
// GC::file = NULL;
|
||||
// GC::line = 0;
|
||||
return ((GC *)gc)->malloc(size);
|
||||
}
|
||||
if (this == &mem) // don't cache global mem
|
||||
{
|
||||
// PRINTF("Using global gc for size %d, file = '%s', line = %d\n", size, GC::file, GC::line);
|
||||
// GC::file = NULL;
|
||||
// GC::line = 0;
|
||||
return gc_get()->malloc(size);
|
||||
}
|
||||
// PRINTF("Generating cached gc for size %d, file = '%s', line = %d\n", size, GC::file, GC::line);
|
||||
gc = gc_get();
|
||||
return gc->malloc(size);
|
||||
}
|
||||
|
||||
void *Mem::malloc_uncollectable(size_t size)
|
||||
{ void *p;
|
||||
|
||||
p = ::malloc(size);
|
||||
if (!p)
|
||||
error();
|
||||
addroots((char *)p, (char *)p + size);
|
||||
|
||||
#if 0
|
||||
++nuncollectable;
|
||||
WPRINTF(L"malloc_uncollectable(%u) = %x, n=%d\n", size, p, nuncollectable);
|
||||
#endif
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void *Mem::calloc(size_t size, size_t n)
|
||||
{
|
||||
return gc_get()->calloc(size, n);
|
||||
}
|
||||
|
||||
void *Mem::realloc(void *p, size_t size)
|
||||
{
|
||||
return gc_get()->realloc(p, size);
|
||||
}
|
||||
|
||||
void Mem::free(void *p)
|
||||
{
|
||||
gc_get()->free(p);
|
||||
}
|
||||
|
||||
void Mem::free_uncollectable(void *p)
|
||||
{
|
||||
if (p)
|
||||
{ removeroots((char *)p);
|
||||
::free(p);
|
||||
|
||||
#if 0
|
||||
--nuncollectable;
|
||||
WPRINTF(L"free_uncollectable(%x) n=%d\n", p, nuncollectable);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
gc_get()->fullcollect();
|
||||
|
||||
GCStats stats;
|
||||
|
||||
getStats(&stats);
|
||||
WPRINTF(L"poolsize = %x, usedsize = %x, freelistsize = %x\n",
|
||||
stats.poolsize, stats.usedsize, stats.freelistsize);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void *Mem::mallocdup(void *o, size_t size)
|
||||
{
|
||||
return gc_get()->mallocdup(o, size);
|
||||
}
|
||||
|
||||
void Mem::check(void *p)
|
||||
{
|
||||
if (gc)
|
||||
gc->check(p);
|
||||
else
|
||||
gc_get()->check(p);
|
||||
}
|
||||
|
||||
void Mem::error()
|
||||
{
|
||||
#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__
|
||||
assert(0);
|
||||
#endif
|
||||
printf("Error: out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
void Mem::fullcollect()
|
||||
{
|
||||
gc_get()->fullcollect();
|
||||
|
||||
#if 0
|
||||
{
|
||||
GCStats stats;
|
||||
|
||||
gc_get()->getStats(&stats);
|
||||
WPRINTF(L"Thread %x ", Thread::getId());
|
||||
WPRINTF(L"poolsize=x%x, usedsize=x%x, freelistsize=x%x, freeblocks=%d, pageblocks=%d\n",
|
||||
stats.poolsize, stats.usedsize, stats.freelistsize, stats.freeblocks, stats.pageblocks);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void Mem::fullcollectNoStack()
|
||||
{
|
||||
gc_get()->fullcollectNoStack();
|
||||
|
||||
#if 0
|
||||
{
|
||||
GCStats stats;
|
||||
|
||||
gc_get()->getStats(&stats);
|
||||
WPRINTF(L"Thread %x ", Thread::getId());
|
||||
WPRINTF(L"poolsize=x%x, usedsize=x%x, freelistsize=x%x, freeblocks=%d, pageblocks=%d\n",
|
||||
stats.poolsize, stats.usedsize, stats.freelistsize, stats.freeblocks, stats.pageblocks);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void Mem::mark(void *pointer)
|
||||
{
|
||||
(void) pointer; // for VC /W4 compatibility
|
||||
}
|
||||
|
||||
|
||||
void Mem::addroots(char* pStart, char* pEnd)
|
||||
{
|
||||
gc_get()->addRange(pStart, pEnd);
|
||||
}
|
||||
|
||||
|
||||
void Mem::removeroots(char* pStart)
|
||||
{
|
||||
gc_get()->removeRange(pStart);
|
||||
}
|
||||
|
||||
|
||||
void Mem::setFinalizer(void* pObj, FINALIZERPROC pFn, void* pClientData)
|
||||
{
|
||||
(void)pClientData;
|
||||
gc_get()->setFinalizer(pObj, pFn);
|
||||
}
|
||||
|
||||
|
||||
void Mem::setStackBottom(void *stackbottom)
|
||||
{
|
||||
gc_get()->setStackBottom(stackbottom);
|
||||
}
|
||||
|
||||
|
||||
GC *Mem::getThreadGC()
|
||||
{
|
||||
return gc_get();
|
||||
}
|
||||
|
||||
|
||||
/* =================================================== */
|
||||
|
||||
#if 1
|
||||
void * operator new(size_t m_size)
|
||||
{
|
||||
//PRINTF("Call to global operator new(%d), file = '%s', line = %d\n", m_size, GC::file ? GC::file : "(null)", GC::line);
|
||||
GC::file = NULL;
|
||||
GC::line = 0;
|
||||
return mem.malloc(m_size);
|
||||
}
|
||||
|
||||
void operator delete(void *p)
|
||||
{
|
||||
//WPRINTF(L"Call to global operator delete\n");
|
||||
mem.free(p);
|
||||
}
|
||||
|
||||
void* operator new[](size_t size)
|
||||
{
|
||||
return operator new(size);
|
||||
}
|
||||
|
||||
void operator delete[](void *pv)
|
||||
{
|
||||
operator delete(pv);
|
||||
}
|
||||
#endif
|
||||
|
||||
void * Mem::operator new(size_t m_size)
|
||||
{ void *p;
|
||||
|
||||
p = gc_get()->malloc(m_size);
|
||||
//printf("Mem::operator new(%d) = %p\n", m_size, p);
|
||||
if (!p)
|
||||
mem.error();
|
||||
return p;
|
||||
}
|
||||
|
||||
void * Mem::operator new(size_t m_size, Mem *mem)
|
||||
{ void *p;
|
||||
|
||||
p = mem->malloc(m_size);
|
||||
//printf("Mem::operator new(%d) = %p\n", m_size, p);
|
||||
if (!p)
|
||||
::mem.error();
|
||||
return p;
|
||||
}
|
||||
|
||||
void * Mem::operator new(size_t m_size, GC *gc)
|
||||
{ void *p;
|
||||
|
||||
// if (!gc)
|
||||
// WPRINTF(L"gc is NULL\n");
|
||||
p = gc->malloc(m_size);
|
||||
//printf("Mem::operator new(%d) = %p\n", m_size, p);
|
||||
if (!p)
|
||||
::mem.error();
|
||||
return p;
|
||||
}
|
||||
|
||||
void Mem::operator delete(void *p)
|
||||
{
|
||||
// printf("Mem::operator delete(%p)\n", p);
|
||||
gc_get()->free(p);
|
||||
}
|
||||
|
||||
/* ============================================================ */
|
||||
|
||||
/* The following section of code exists to find the right
|
||||
* garbage collector for this thread. There is one independent instance
|
||||
* of the collector per thread.
|
||||
*/
|
||||
|
||||
/* ===================== linux ================================ */
|
||||
|
||||
#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#define LOG 0 // log thread creation / destruction
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
// Key identifying the thread-specific data
|
||||
static pthread_key_t gc_key;
|
||||
|
||||
/* "Once" variable ensuring that the key for gc_alloc will be allocated
|
||||
* exactly once.
|
||||
*/
|
||||
static pthread_once_t gc_alloc_key_once = PTHREAD_ONCE_INIT;
|
||||
|
||||
/* Forward functions */
|
||||
static void gc_alloc_key();
|
||||
static void gc_alloc_destroy_gc(void * accu);
|
||||
|
||||
|
||||
void gc_init()
|
||||
{
|
||||
#if LOG
|
||||
WPRINTF(L"Thread %lx: gc_init()\n", pthread_self());
|
||||
#endif
|
||||
pthread_once(&gc_alloc_key_once, gc_alloc_key);
|
||||
#if LOG
|
||||
WPRINTF(L"Thread %lx: gc_init() return\n", pthread_self());
|
||||
#endif
|
||||
}
|
||||
|
||||
GC *gc_get()
|
||||
{
|
||||
GC *gc;
|
||||
|
||||
// Get the thread-specific data associated with the key
|
||||
gc = (GC *) pthread_getspecific(gc_key);
|
||||
|
||||
// It's initially NULL, meaning that we must allocate the buffer first.
|
||||
if (gc == NULL)
|
||||
{
|
||||
GC_LOG();
|
||||
gc = new GC();
|
||||
gc->init();
|
||||
|
||||
// Store the buffer pointer in the thread-specific data.
|
||||
pthread_setspecific(gc_key, (void *) gc);
|
||||
#if LOG
|
||||
WPRINTF(L"Thread %lx: allocating gc at %x\n", pthread_self(), gc);
|
||||
#endif
|
||||
}
|
||||
return gc;
|
||||
}
|
||||
|
||||
// Function to allocate the key for gc_alloc thread-specific data.
|
||||
|
||||
static void gc_alloc_key()
|
||||
{
|
||||
pthread_key_create(&gc_key, gc_alloc_destroy_gc);
|
||||
#if LOG
|
||||
WPRINTF(L"Thread %lx: allocated gc key %d\n", pthread_self(), gc_key);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Function to free the buffer when the thread exits.
|
||||
// Called only when the thread-specific data is not NULL.
|
||||
|
||||
static void gc_alloc_destroy_gc(void *gc)
|
||||
{
|
||||
#if LOG
|
||||
WPRINTF(L"Thread %x: freeing gc at %x\n", pthread_self(), gc);
|
||||
#endif
|
||||
delete (GC *)gc;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* ===================== win32 ================================ */
|
||||
|
||||
#if !defined(linux) && defined(_WIN32)
|
||||
|
||||
#if 1 // single threaded version
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
static GC *gc;
|
||||
|
||||
void gc_init()
|
||||
{
|
||||
if (!gc)
|
||||
{ gc = (GC *)::malloc(sizeof(GC));
|
||||
gc->init();
|
||||
}
|
||||
}
|
||||
|
||||
GC *gc_get()
|
||||
{
|
||||
return gc;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#else // multi threaded version
|
||||
|
||||
#include "mutex.h"
|
||||
#include "thread.h"
|
||||
|
||||
/* This is the win32 version. It suffers from the bug that
|
||||
* when the thread exits the data structure is not cleared,
|
||||
* but the memory pool it points to is free'd.
|
||||
* Thus, if a new thread comes along with the same thread id,
|
||||
* the data will look initialized, but will point to garbage.
|
||||
*
|
||||
* What needs to happen is when a thread exits, the associated
|
||||
* GC_context data struct is cleared.
|
||||
*/
|
||||
|
||||
struct GC_context
|
||||
{
|
||||
ThreadId threadid; // identifier of current thread
|
||||
GC *gc;
|
||||
};
|
||||
|
||||
Mutex gc_mutex;
|
||||
|
||||
static GC_context array[64];
|
||||
|
||||
// Array of pointers to GC_context objects, one per threadid
|
||||
GC_context *gccontext = array;
|
||||
unsigned gccontext_allocdim = 64;
|
||||
unsigned gccontext_dim;
|
||||
|
||||
ThreadId gc_cache_ti;
|
||||
GC_context *gc_cache_cc;
|
||||
|
||||
extern "C" void gc_init()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
extern "C" GC *gc_get()
|
||||
{
|
||||
/* This works by creating an array of GC_context's, one
|
||||
* for each thread. We match up by thread id.
|
||||
*/
|
||||
|
||||
ThreadId ti;
|
||||
GC_context *cc;
|
||||
|
||||
//PRINTF("gc_get()\n");
|
||||
|
||||
ti = Thread::getId();
|
||||
gc_mutex.acquire();
|
||||
|
||||
// Used cached version if we can
|
||||
if (ti == gc_cache_ti)
|
||||
{
|
||||
cc = gc_cache_cc;
|
||||
//exception(L"getGC_context(): cache x%x", ti);
|
||||
}
|
||||
else
|
||||
{
|
||||
// This does a linear search through gccontext[].
|
||||
// A hash table might be faster if there are more
|
||||
// than a dozen threads.
|
||||
GC_context *ccp;
|
||||
GC_context *ccptop = &gccontext[gccontext_dim];
|
||||
for (ccp = gccontext; ccp < ccptop; ccp++)
|
||||
{
|
||||
cc = ccp;
|
||||
if (cc->threadid == ti)
|
||||
{
|
||||
WPRINTF(L"getGC_context(): existing x%x", ti);
|
||||
goto Lret;
|
||||
}
|
||||
}
|
||||
|
||||
// Do not allocate with garbage collector, as this must reside
|
||||
// global to all threads.
|
||||
|
||||
assert(gccontext_dim < gccontext_allocdim);
|
||||
cc = ccp;
|
||||
memset(cc, 0, sizeof(*cc));
|
||||
cc->threadid = ti;
|
||||
cc->gc = new GC();
|
||||
cc->gc->init();
|
||||
|
||||
gccontext_dim++;
|
||||
WPRINTF(L"getGC_context(): new x%x\n", ti);
|
||||
|
||||
Lret:
|
||||
// Cache for next time
|
||||
gc_cache_ti = ti;
|
||||
gc_cache_cc = cc;
|
||||
}
|
||||
|
||||
gc_mutex.release();
|
||||
return cc->gc;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
2223
dmd2/root/gc.c
Normal file
2223
dmd2/root/gc.c
Normal file
File diff suppressed because it is too large
Load Diff
68
dmd2/root/gc.h
Normal file
68
dmd2/root/gc.h
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright (c) 2000-2011 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.
|
||||
|
||||
#ifndef GC_H
|
||||
#define GC_H
|
||||
|
||||
struct Gcx; // private data
|
||||
|
||||
typedef void (*GC_FINALIZER)(void *p, void *dummy);
|
||||
|
||||
struct GCStats
|
||||
{
|
||||
unsigned poolsize; // total size of pool
|
||||
unsigned usedsize; // bytes allocated
|
||||
unsigned freeblocks; // number of blocks marked FREE
|
||||
unsigned freelistsize; // total of memory on free lists
|
||||
unsigned pageblocks; // number of blocks marked PAGE
|
||||
};
|
||||
|
||||
struct GC
|
||||
{
|
||||
// For passing to debug code
|
||||
static unsigned line;
|
||||
static char *file;
|
||||
// #define GC_LOG() ((GC::line = __LINE__), (GC::file = __FILE__))
|
||||
#define GC_LOG() ((void)0)
|
||||
|
||||
Gcx *gcx; // implementation
|
||||
|
||||
~GC();
|
||||
|
||||
void init();
|
||||
|
||||
char *strdup(const char *s);
|
||||
void *malloc(size_t size);
|
||||
void *malloc_atomic(size_t size);
|
||||
void *calloc(size_t size, size_t n);
|
||||
void *realloc(void *p, size_t size);
|
||||
void free(void *p);
|
||||
void *mallocdup(void *o, size_t size);
|
||||
void check(void *p);
|
||||
void error();
|
||||
|
||||
void setStackBottom(void *p);
|
||||
|
||||
void addRoot(void *p); // add p to list of roots
|
||||
void removeRoot(void *p); // remove p from list of roots
|
||||
|
||||
void addRange(void *pbot, void *ptop); // add range to scan for roots
|
||||
void removeRange(void *pbot); // remove range
|
||||
|
||||
void fullcollect(); // do full garbage collection
|
||||
void fullcollectNoStack(); // do full garbage collection; no scan stack
|
||||
void gencollect(); // do generational garbage collection
|
||||
void minimize(); // minimize physical memory usage
|
||||
|
||||
void setFinalizer(void *p, GC_FINALIZER pFn);
|
||||
|
||||
void getStats(GCStats *stats);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
69
dmd2/root/gccbitops.h
Normal file
69
dmd2/root/gccbitops.h
Normal file
@@ -0,0 +1,69 @@
|
||||
// Copyright (c) 2000-2011 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.
|
||||
|
||||
// Bit operations for GCC and I386
|
||||
|
||||
#ifndef GCCBITOPS_H
|
||||
#define GCCBITOPS_H 1
|
||||
|
||||
inline int _inline_bsf(int w)
|
||||
{ int index;
|
||||
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"bsfl %1, %0 \n\t"
|
||||
: "=r" (index)
|
||||
: "r" (w)
|
||||
);
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
inline int _inline_bt(unsigned *p, int i)
|
||||
{
|
||||
char result;
|
||||
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"btl %2,%1 \n\t"
|
||||
"setc %0 \n\t"
|
||||
:"=r" (result)
|
||||
:"m" (*p), "r" (i)
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline int _inline_bts(unsigned *p, int i)
|
||||
{
|
||||
char result;
|
||||
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"btsl %2,%1 \n\t"
|
||||
"setc %0 \n\t"
|
||||
:"=r" (result)
|
||||
:"m" (*p), "r" (i)
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline int _inline_btr(unsigned *p, int i)
|
||||
{
|
||||
char result;
|
||||
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"btrl %2,%1 \n\t"
|
||||
"setc %0 \n\t"
|
||||
:"=r" (result)
|
||||
:"m" (*p), "r" (i)
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
96
dmd2/root/linux.c
Normal file
96
dmd2/root/linux.c
Normal file
@@ -0,0 +1,96 @@
|
||||
// Copyright (c) 2000-2011 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 <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
|
||||
/*************************************
|
||||
* This is all necessary to get fd initialized at startup.
|
||||
*/
|
||||
|
||||
#define FDMAP 0
|
||||
|
||||
#if FDMAP
|
||||
#include <fcntl.h>
|
||||
|
||||
struct OS_INIT
|
||||
{
|
||||
static int fd;
|
||||
|
||||
OS_INIT();
|
||||
};
|
||||
|
||||
OS_INIT os_init;
|
||||
|
||||
int OS_INIT::fd = 0;
|
||||
|
||||
OS_INIT::OS_INIT()
|
||||
{
|
||||
fd = open("/dev/zero", O_RDONLY);
|
||||
}
|
||||
#endif
|
||||
|
||||
/***********************************
|
||||
* Map memory.
|
||||
*/
|
||||
|
||||
void *os_mem_map(unsigned nbytes)
|
||||
{ void *p;
|
||||
|
||||
errno = 0;
|
||||
#if FDMAP
|
||||
p = mmap(NULL, nbytes, PROT_READ | PROT_WRITE, MAP_PRIVATE, OS_INIT::fd, 0);
|
||||
#else
|
||||
p = mmap(NULL, nbytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||
#endif
|
||||
return (p == MAP_FAILED) ? NULL : p;
|
||||
}
|
||||
|
||||
/***********************************
|
||||
* Commit memory.
|
||||
* Returns:
|
||||
* 0 success
|
||||
* !=0 failure
|
||||
*/
|
||||
|
||||
int os_mem_commit(void *base, unsigned offset, unsigned nbytes)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/***********************************
|
||||
* Decommit memory.
|
||||
* Returns:
|
||||
* 0 success
|
||||
* !=0 failure
|
||||
*/
|
||||
|
||||
int os_mem_decommit(void *base, unsigned offset, unsigned nbytes)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***********************************
|
||||
* Unmap memory allocated with os_mem_map().
|
||||
* Returns:
|
||||
* 0 success
|
||||
* !=0 failure
|
||||
*/
|
||||
|
||||
int os_mem_unmap(void *base, unsigned nbytes)
|
||||
{
|
||||
return munmap(base, nbytes);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
25
dmd2/root/mscbitops.h
Normal file
25
dmd2/root/mscbitops.h
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) 2000-2011 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.
|
||||
|
||||
// Bit operations for MSC and I386
|
||||
|
||||
#ifndef MSCBITOPS_H
|
||||
#define MSCBITOPS_H 1
|
||||
|
||||
inline int _inline_bsf(int w)
|
||||
{ int index;
|
||||
|
||||
index = 0;
|
||||
while (!(w & 1))
|
||||
{ index++;
|
||||
w >>= 1;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
#endif
|
||||
25
dmd2/root/os.h
Normal file
25
dmd2/root/os.h
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) 2000-2011 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.
|
||||
|
||||
|
||||
// OS specific routines
|
||||
|
||||
void *os_mem_map(unsigned nbytes);
|
||||
int os_mem_commit(void *base, unsigned offset, unsigned nbytes);
|
||||
int os_mem_decommit(void *base, unsigned offset, unsigned nbytes);
|
||||
int os_mem_unmap(void *base, unsigned nbytes);
|
||||
|
||||
|
||||
// Threading
|
||||
|
||||
#if defined linux
|
||||
#include <pthread.h>
|
||||
#else
|
||||
typedef long pthread_t;
|
||||
pthread_t pthread_self();
|
||||
#endif
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2000-2001 by Chromium Communications
|
||||
// Copyright (C) 2000-2011 by Digital Mars
|
||||
// All Rights Reserved
|
||||
|
||||
#ifndef ROOT_MEM_H
|
||||
|
||||
@@ -1087,7 +1087,7 @@ int File::read()
|
||||
}
|
||||
|
||||
if (!ref)
|
||||
mem.free(buffer);
|
||||
::free(buffer);
|
||||
ref = 0; // we own the buffer now
|
||||
|
||||
//printf("\tfile opened\n");
|
||||
@@ -1097,7 +1097,7 @@ int File::read()
|
||||
goto err2;
|
||||
}
|
||||
size = buf.st_size;
|
||||
buffer = (unsigned char *) mem.malloc(size + 2);
|
||||
buffer = (unsigned char *) ::malloc(size + 2);
|
||||
if (!buffer)
|
||||
{
|
||||
printf("\tmalloc error, errno = %d\n",errno);
|
||||
@@ -1130,7 +1130,7 @@ int File::read()
|
||||
err2:
|
||||
close(fd);
|
||||
err:
|
||||
mem.free(buffer);
|
||||
::free(buffer);
|
||||
buffer = NULL;
|
||||
len = 0;
|
||||
|
||||
@@ -1151,11 +1151,11 @@ err1:
|
||||
goto err1;
|
||||
|
||||
if (!ref)
|
||||
mem.free(buffer);
|
||||
::free(buffer);
|
||||
ref = 0;
|
||||
|
||||
size = GetFileSize(h,NULL);
|
||||
buffer = (unsigned char *) mem.malloc(size + 2);
|
||||
buffer = (unsigned char *) ::malloc(size + 2);
|
||||
if (!buffer)
|
||||
goto err2;
|
||||
|
||||
@@ -1184,7 +1184,7 @@ err1:
|
||||
err2:
|
||||
CloseHandle(h);
|
||||
err:
|
||||
mem.free(buffer);
|
||||
::free(buffer);
|
||||
buffer = NULL;
|
||||
len = 0;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
// Copyright (c) 1999-2008 by Digital Mars
|
||||
// Copyright (c) 1999-2011 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
@@ -18,7 +18,7 @@
|
||||
#include "lstring.h"
|
||||
#include "stringtable.h"
|
||||
|
||||
StringTable::StringTable(unsigned size)
|
||||
void StringTable::init(unsigned size)
|
||||
{
|
||||
table = (void **)mem.calloc(size, sizeof(void *));
|
||||
tabledim = size;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 1999-2008 by Digital Mars
|
||||
// Copyright (c) 1999-2011 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
@@ -28,13 +28,13 @@ struct StringValue
|
||||
Lstring lstring;
|
||||
};
|
||||
|
||||
struct StringTable : Object
|
||||
struct StringTable
|
||||
{
|
||||
void **table;
|
||||
unsigned count;
|
||||
unsigned tabledim;
|
||||
|
||||
StringTable(unsigned size = 37);
|
||||
void init(unsigned size = 37);
|
||||
~StringTable();
|
||||
|
||||
StringValue *lookup(const dchar *s, unsigned len);
|
||||
|
||||
72
dmd2/root/win32.c
Normal file
72
dmd2/root/win32.c
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright (c) 2000-2011 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 <windows.h>
|
||||
|
||||
#include "os.h"
|
||||
|
||||
/***********************************
|
||||
* Map memory.
|
||||
*/
|
||||
|
||||
void *os_mem_map(unsigned nbytes)
|
||||
{
|
||||
return VirtualAlloc(NULL, nbytes, MEM_RESERVE, PAGE_READWRITE);
|
||||
}
|
||||
|
||||
/***********************************
|
||||
* Commit memory.
|
||||
* Returns:
|
||||
* 0 success
|
||||
* !=0 failure
|
||||
*/
|
||||
|
||||
int os_mem_commit(void *base, unsigned offset, unsigned nbytes)
|
||||
{
|
||||
void *p;
|
||||
|
||||
p = VirtualAlloc((char *)base + offset, nbytes, MEM_COMMIT, PAGE_READWRITE);
|
||||
return (p == NULL);
|
||||
}
|
||||
|
||||
|
||||
/***********************************
|
||||
* Decommit memory.
|
||||
* Returns:
|
||||
* 0 success
|
||||
* !=0 failure
|
||||
*/
|
||||
|
||||
int os_mem_decommit(void *base, unsigned offset, unsigned nbytes)
|
||||
{
|
||||
return VirtualFree((char *)base + offset, nbytes, MEM_DECOMMIT) == 0;
|
||||
}
|
||||
|
||||
/***********************************
|
||||
* Unmap memory allocated with os_mem_map().
|
||||
* Memory must have already been decommitted.
|
||||
* Returns:
|
||||
* 0 success
|
||||
* !=0 failure
|
||||
*/
|
||||
|
||||
int os_mem_unmap(void *base, unsigned nbytes)
|
||||
{
|
||||
(void)nbytes;
|
||||
return VirtualFree(base, 0, MEM_RELEASE) == 0;
|
||||
}
|
||||
|
||||
|
||||
/********************************************
|
||||
*/
|
||||
|
||||
pthread_t pthread_self()
|
||||
{
|
||||
return (pthread_t) GetCurrentThreadId();
|
||||
}
|
||||
@@ -679,7 +679,8 @@ int CompoundStatement::blockExit(bool mustNotThrow)
|
||||
if (global.params.warnings && result & BEfallthru && slast)
|
||||
{
|
||||
slast = slast->last();
|
||||
if (slast && (s->isCaseStatement() || s->isDefaultStatement()))
|
||||
if (slast && (slast->isCaseStatement() || slast->isDefaultStatement()) &&
|
||||
(s->isCaseStatement() || s->isDefaultStatement()))
|
||||
{
|
||||
// Allow if last case/default was empty
|
||||
CaseStatement *sc = slast->isCaseStatement();
|
||||
@@ -1210,7 +1211,7 @@ void DoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
|
||||
body->toCBuffer(buf, hgs);
|
||||
buf->writestring("while (");
|
||||
condition->toCBuffer(buf, hgs);
|
||||
buf->writebyte(')');
|
||||
buf->writestring(");");
|
||||
}
|
||||
|
||||
/******************************** ForStatement ***************************/
|
||||
@@ -1516,18 +1517,22 @@ Lretry:
|
||||
Dsymbol *var;
|
||||
if (te)
|
||||
{ Type *tb = e->type->toBasetype();
|
||||
Dsymbol *s = NULL;
|
||||
if ((tb->ty == Tfunction || tb->ty == Tsarray) && e->op == TOKvar)
|
||||
{ VarExp *ve = (VarExp *)e;
|
||||
var = new AliasDeclaration(loc, arg->ident, ve->var);
|
||||
}
|
||||
s = ((VarExp *)e)->var;
|
||||
else if (e->op == TOKtemplate)
|
||||
s =((TemplateExp *)e)->td;
|
||||
else if (e->op == TOKimport)
|
||||
s =((ScopeExp *)e)->sds;
|
||||
|
||||
if (s)
|
||||
var = new AliasDeclaration(loc, arg->ident, s);
|
||||
else
|
||||
{
|
||||
arg->type = e->type;
|
||||
Initializer *ie = new ExpInitializer(0, e);
|
||||
VarDeclaration *v = new VarDeclaration(loc, arg->type, arg->ident, ie);
|
||||
if (e->isConst())
|
||||
v->storage_class |= STCconst;
|
||||
if (e->op == TOKstring)
|
||||
if (e->isConst() || e->op == TOKstring)
|
||||
v->storage_class |= STCmanifest;
|
||||
var = v;
|
||||
}
|
||||
@@ -1849,6 +1854,9 @@ Lagain:
|
||||
if (!ve->type || ve->type->ty == Terror)
|
||||
goto Lrangeerr;
|
||||
|
||||
// Resolve inout qualifier of front type
|
||||
ve->type = ve->type->substWildTo(tab->mod);
|
||||
|
||||
Expressions *exps = new Expressions();
|
||||
exps->push(ve);
|
||||
int pos = 0;
|
||||
@@ -1858,7 +1866,7 @@ Lagain:
|
||||
if (pos == -1)
|
||||
break;
|
||||
}
|
||||
if (exps->dim > dim)
|
||||
if (exps->dim != dim)
|
||||
goto Lrangeerr;
|
||||
|
||||
for (size_t i = 0; i < dim; i++)
|
||||
@@ -1893,6 +1901,9 @@ Lagain:
|
||||
printf("increment: %s\n", increment->toChars());
|
||||
printf("body: %s\n", forbody->toChars());
|
||||
#endif
|
||||
if (prelude)
|
||||
s = new CompoundStatement(loc,
|
||||
new ExpStatement(prelude->loc, prelude), s);
|
||||
s = s->semantic(sc);
|
||||
break;
|
||||
|
||||
@@ -3718,13 +3729,10 @@ Statement *ReturnStatement::semantic(Scope *sc)
|
||||
* (but first ensure it doesn't fail the "check for
|
||||
* escaping reference" test)
|
||||
*/
|
||||
unsigned errors = global.errors;
|
||||
global.gag++;
|
||||
unsigned errors = global.startGagging();
|
||||
exp->checkEscapeRef();
|
||||
global.gag--;
|
||||
if (errors != global.errors)
|
||||
if (global.endGagging(errors))
|
||||
{ tf->isref = FALSE; // return by value
|
||||
global.errors = errors;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -3832,7 +3840,7 @@ Statement *ReturnStatement::semantic(Scope *sc)
|
||||
{
|
||||
if (((TypeFunction *)fd->type)->isref && !fd->isCtorDeclaration())
|
||||
{ // Function returns a reference
|
||||
if (tbret->isMutable())
|
||||
if (tret->isMutable())
|
||||
exp = exp->modifiableLvalue(sc, exp);
|
||||
else
|
||||
exp = exp->toLvalue(sc, exp);
|
||||
@@ -3893,8 +3901,14 @@ Statement *ReturnStatement::semantic(Scope *sc)
|
||||
* exp; return;
|
||||
*/
|
||||
Statement *s = new ExpStatement(loc, exp);
|
||||
exp = NULL;
|
||||
s = s->semantic(sc);
|
||||
|
||||
if (exp->type->ty != Tvoid)
|
||||
{
|
||||
error("cannot return non-void from void function");
|
||||
}
|
||||
|
||||
exp = NULL;
|
||||
return new CompoundStatement(loc, s, this);
|
||||
}
|
||||
|
||||
|
||||
162
dmd2/struct.c
162
dmd2/struct.c
@@ -21,6 +21,8 @@
|
||||
#include "statement.h"
|
||||
#include "template.h"
|
||||
|
||||
FuncDeclaration *StructDeclaration::xerreq; // object.xopEquals
|
||||
|
||||
/********************************* AggregateDeclaration ****************************/
|
||||
|
||||
AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id)
|
||||
@@ -314,9 +316,11 @@ StructDeclaration::StructDeclaration(Loc loc, Identifier *id)
|
||||
zeroInit = 0; // assume false until we do semantic processing
|
||||
#if DMDV2
|
||||
hasIdentityAssign = 0;
|
||||
hasIdentityEquals = 0;
|
||||
cpctor = NULL;
|
||||
postblit = NULL;
|
||||
eq = NULL;
|
||||
|
||||
xeq = NULL;
|
||||
#endif
|
||||
|
||||
// For forward references
|
||||
@@ -497,6 +501,65 @@ void StructDeclaration::semantic(Scope *sc)
|
||||
#endif
|
||||
}
|
||||
|
||||
if (sizeok == 2)
|
||||
{ // semantic() failed because of forward references.
|
||||
// Unwind what we did, and defer it for later
|
||||
fields.setDim(0);
|
||||
structsize = 0;
|
||||
alignsize = 0;
|
||||
structalign = 0;
|
||||
|
||||
scope = scx ? scx : new Scope(*sc);
|
||||
scope->setNoFree();
|
||||
scope->module->addDeferredSemantic(this);
|
||||
|
||||
Module::dprogress = dprogress_save;
|
||||
//printf("\tdeferring %s\n", toChars());
|
||||
return;
|
||||
}
|
||||
|
||||
// 0 sized struct's are set to 1 byte
|
||||
if (structsize == 0)
|
||||
{
|
||||
structsize = 1;
|
||||
alignsize = 1;
|
||||
}
|
||||
|
||||
// Round struct size up to next alignsize boundary.
|
||||
// This will ensure that arrays of structs will get their internals
|
||||
// aligned properly.
|
||||
structsize = (structsize + alignsize - 1) & ~(alignsize - 1);
|
||||
|
||||
sizeok = 1;
|
||||
Module::dprogress++;
|
||||
|
||||
//printf("-StructDeclaration::semantic(this=%p, '%s')\n", this, toChars());
|
||||
|
||||
// Determine if struct is all zeros or not
|
||||
zeroInit = 1;
|
||||
for (size_t i = 0; i < fields.dim; i++)
|
||||
{
|
||||
Dsymbol *s = fields.tdata()[i];
|
||||
VarDeclaration *vd = s->isVarDeclaration();
|
||||
if (vd && !vd->isDataseg())
|
||||
{
|
||||
if (vd->init)
|
||||
{
|
||||
// Should examine init to see if it is really all 0's
|
||||
zeroInit = 0;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!vd->type->isZeroInit(loc))
|
||||
{
|
||||
zeroInit = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if DMDV1
|
||||
/* This doesn't work for DMDV2 because (ref S) and (S) parameter
|
||||
* lists will overload the same.
|
||||
@@ -560,107 +623,18 @@ void StructDeclaration::semantic(Scope *sc)
|
||||
}
|
||||
#endif
|
||||
#if DMDV2
|
||||
/* Try to find the opEquals function. Build it if necessary.
|
||||
*/
|
||||
TypeFunction *tfeqptr;
|
||||
{ // bool opEquals(const T*) const;
|
||||
Parameters *parameters = new Parameters;
|
||||
#if STRUCTTHISREF
|
||||
// bool opEquals(ref const T) const;
|
||||
Parameter *param = new Parameter(STCref, type->constOf(), NULL, NULL);
|
||||
#else
|
||||
// bool opEquals(const T*) const;
|
||||
Parameter *param = new Parameter(STCin, type->pointerTo(), NULL, NULL);
|
||||
#endif
|
||||
|
||||
parameters->push(param);
|
||||
tfeqptr = new TypeFunction(parameters, Type::tbool, 0, LINKd);
|
||||
tfeqptr->mod = MODconst;
|
||||
tfeqptr = (TypeFunction *)tfeqptr->semantic(0, sc2);
|
||||
|
||||
Dsymbol *s = search_function(this, Id::eq);
|
||||
FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL;
|
||||
if (fdx)
|
||||
{
|
||||
eq = fdx->overloadExactMatch(tfeqptr, getModule());
|
||||
if (!eq)
|
||||
fdx->error("type signature should be %s not %s", tfeqptr->toChars(), fdx->type->toChars());
|
||||
}
|
||||
|
||||
TemplateDeclaration *td = s ? s->isTemplateDeclaration() : NULL;
|
||||
// BUG: should also check that td is a function template, not just a template
|
||||
|
||||
if (!eq && !td)
|
||||
eq = buildOpEquals(sc2);
|
||||
}
|
||||
|
||||
dtor = buildDtor(sc2);
|
||||
postblit = buildPostBlit(sc2);
|
||||
cpctor = buildCpCtor(sc2);
|
||||
|
||||
buildOpAssign(sc2);
|
||||
hasIdentityEquals = (buildOpEquals(sc2) != NULL);
|
||||
|
||||
xeq = buildXopEquals(sc2);
|
||||
#endif
|
||||
|
||||
sc2->pop();
|
||||
|
||||
if (sizeok == 2)
|
||||
{ // semantic() failed because of forward references.
|
||||
// Unwind what we did, and defer it for later
|
||||
fields.setDim(0);
|
||||
structsize = 0;
|
||||
alignsize = 0;
|
||||
structalign = 0;
|
||||
|
||||
scope = scx ? scx : new Scope(*sc);
|
||||
scope->setNoFree();
|
||||
scope->module->addDeferredSemantic(this);
|
||||
|
||||
Module::dprogress = dprogress_save;
|
||||
//printf("\tdeferring %s\n", toChars());
|
||||
return;
|
||||
}
|
||||
|
||||
// 0 sized struct's are set to 1 byte
|
||||
if (structsize == 0)
|
||||
{
|
||||
structsize = 1;
|
||||
alignsize = 1;
|
||||
}
|
||||
|
||||
// Round struct size up to next alignsize boundary.
|
||||
// This will ensure that arrays of structs will get their internals
|
||||
// aligned properly.
|
||||
structsize = (structsize + alignsize - 1) & ~(alignsize - 1);
|
||||
|
||||
sizeok = 1;
|
||||
Module::dprogress++;
|
||||
|
||||
//printf("-StructDeclaration::semantic(this=%p, '%s')\n", this, toChars());
|
||||
|
||||
// Determine if struct is all zeros or not
|
||||
zeroInit = 1;
|
||||
for (size_t i = 0; i < fields.dim; i++)
|
||||
{
|
||||
Dsymbol *s = fields.tdata()[i];
|
||||
VarDeclaration *vd = s->isVarDeclaration();
|
||||
if (vd && !vd->isDataseg())
|
||||
{
|
||||
if (vd->init)
|
||||
{
|
||||
// Should examine init to see if it is really all 0's
|
||||
zeroInit = 0;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!vd->type->isZeroInit(loc))
|
||||
{
|
||||
zeroInit = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Look for special member functions.
|
||||
*/
|
||||
#if DMDV2
|
||||
|
||||
253
dmd2/template.c
253
dmd2/template.c
@@ -603,39 +603,45 @@ void TemplateDeclaration::makeParamNamesVisibleInConstraint(Scope *paramscope, E
|
||||
onemember->toAlias()->isFuncDeclaration() : NULL;
|
||||
if (fd)
|
||||
{
|
||||
/*
|
||||
Making parameters is similar to FuncDeclaration::semantic3
|
||||
*/
|
||||
paramscope->parent = fd;
|
||||
int fvarargs; // function varargs
|
||||
Parameters *fparameters = fd->getParameters(&fvarargs);
|
||||
|
||||
TypeFunction *tf = (TypeFunction *)fd->type->syntaxCopy();
|
||||
|
||||
// Shouldn't run semantic on default arguments and return type.
|
||||
for (int i = 0; i<tf->parameters->dim; i++)
|
||||
tf->parameters->tdata()[i]->defaultArg = NULL;
|
||||
tf->next = NULL;
|
||||
|
||||
// Resolve parameter types and 'auto ref's.
|
||||
tf->fargs = fargs;
|
||||
tf = (TypeFunction *)tf->semantic(loc, paramscope);
|
||||
|
||||
Parameters *fparameters = tf->parameters;
|
||||
int fvarargs = tf->varargs;
|
||||
|
||||
size_t nfparams = Parameter::dim(fparameters); // Num function parameters
|
||||
for (size_t i = 0; i < nfparams; i++)
|
||||
{
|
||||
Parameter *fparam = Parameter::getNth(fparameters, i)->syntaxCopy();
|
||||
Parameter *fparam = Parameter::getNth(fparameters, i);
|
||||
// Remove addMod same as func.d L1065 of FuncDeclaration::semantic3
|
||||
//Type *vtype = fparam->type;
|
||||
//if (fd->type && fd->isPure())
|
||||
// vtype = vtype->addMod(MODconst);
|
||||
fparam->storageClass &= (STCin | STCout | STCref | STClazy | STCfinal | STC_TYPECTOR | STCnodtor);
|
||||
fparam->storageClass |= STCparameter;
|
||||
if (fvarargs == 2 && i + 1 == nfparams)
|
||||
fparam->storageClass |= STCvariadic;
|
||||
}
|
||||
for (size_t i = 0; i < fparameters->dim; i++)
|
||||
{
|
||||
Parameter *fparam = fparameters->tdata()[i];
|
||||
if (!fparam->ident)
|
||||
continue; // don't add it, if it has no name
|
||||
Type *vtype = fparam->type->syntaxCopy();
|
||||
// isPure will segfault if called on a ctor, because fd->type is null.
|
||||
if (fd->type && fd->isPure())
|
||||
vtype = vtype->addMod(MODconst);
|
||||
VarDeclaration *v = new VarDeclaration(loc, vtype, fparam->ident, NULL);
|
||||
v->storage_class |= STCparameter;
|
||||
// Not sure if this condition is correct/necessary.
|
||||
// It's from func.c
|
||||
if (//fd->type && fd->type->ty == Tfunction &&
|
||||
fvarargs == 2 && i + 1 == nfparams)
|
||||
v->storage_class |= STCvariadic;
|
||||
|
||||
v->storage_class |= fparam->storageClass & (STCin | STCout | STCref | STClazy | STCfinal | STC_TYPECTOR | STCnodtor);
|
||||
if (fparam->storageClass & STCauto)
|
||||
{
|
||||
if (fargs && i < fargs->dim)
|
||||
{ Expression *farg = fargs->tdata()[i];
|
||||
if (farg->isLvalue())
|
||||
; // ref parameter
|
||||
else
|
||||
v->storage_class &= ~STCref; // value parameter
|
||||
}
|
||||
}
|
||||
|
||||
VarDeclaration *v = new VarDeclaration(loc, fparam->type, fparam->ident, NULL);
|
||||
v->storage_class = fparam->storageClass;
|
||||
v->semantic(paramscope);
|
||||
if (!paramscope->insert(v))
|
||||
error("parameter %s.%s is already defined", toChars(), v->toChars());
|
||||
@@ -912,6 +918,9 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Scope *sc, Loc loc, Objec
|
||||
Parameters *fparameters; // function parameter list
|
||||
int fvarargs; // function varargs
|
||||
Objects dedtypes; // for T:T*, the dedargs is the T*, dedtypes is the T
|
||||
unsigned wildmatch = 0;
|
||||
|
||||
TypeFunction *tf = (TypeFunction *)fd->type;
|
||||
|
||||
#if 0
|
||||
printf("\nTemplateDeclaration::deduceFunctionTemplateMatch() %s\n", toChars());
|
||||
@@ -1114,7 +1123,7 @@ L2:
|
||||
{
|
||||
Type *tthis = ethis->type;
|
||||
unsigned mod = fd->type->mod;
|
||||
StorageClass stc = scope->stc;
|
||||
StorageClass stc = scope->stc | fd->storage_class2;
|
||||
// Propagate parent storage class (see bug 5504)
|
||||
Dsymbol *p = parent;
|
||||
while (p->isTemplateDeclaration() || p->isTemplateInstance())
|
||||
@@ -1202,8 +1211,11 @@ L2:
|
||||
#endif
|
||||
|
||||
MATCH m;
|
||||
m = argtype->deduceType(paramscope, fparam->type, parameters, &dedtypes);
|
||||
m = argtype->deduceType(paramscope, fparam->type, parameters, &dedtypes,
|
||||
tf->hasWild() ? &wildmatch : NULL);
|
||||
//printf("\tdeduceType m = %d\n", m);
|
||||
//if (tf->hasWild())
|
||||
// printf("\twildmatch = x%x m = %d\n", wildmatch, m);
|
||||
|
||||
/* If no match, see if there's a conversion to a delegate
|
||||
*/
|
||||
@@ -1791,7 +1803,7 @@ int templateParameterLookup(Type *tparam, TemplateParameters *parameters)
|
||||
*/
|
||||
|
||||
MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters,
|
||||
Objects *dedtypes)
|
||||
Objects *dedtypes, unsigned *wildmatch)
|
||||
{
|
||||
#if 0
|
||||
printf("Type::deduceType()\n");
|
||||
@@ -1827,7 +1839,7 @@ MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters,
|
||||
*/
|
||||
tparam = tparam->semantic(loc, sc);
|
||||
assert(tparam->ty != Tident);
|
||||
return deduceType(sc, tparam, parameters, dedtypes);
|
||||
return deduceType(sc, tparam, parameters, dedtypes, wildmatch);
|
||||
}
|
||||
|
||||
TemplateParameter *tp = parameters->tdata()[i];
|
||||
@@ -1841,6 +1853,59 @@ MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters,
|
||||
// 7*7 == 49 cases
|
||||
|
||||
#define X(U,T) ((U) << 4) | (T)
|
||||
|
||||
if (wildmatch && (tparam->mod & MODwild))
|
||||
{
|
||||
switch (X(tparam->mod, mod))
|
||||
{
|
||||
case X(MODwild, MODwild):
|
||||
case X(MODwild | MODshared, MODwild | MODshared):
|
||||
case X(MODwild, 0):
|
||||
case X(MODwild, MODconst):
|
||||
case X(MODwild, MODimmutable):
|
||||
case X(MODwild | MODshared, MODshared):
|
||||
case X(MODwild | MODshared, MODconst | MODshared):
|
||||
|
||||
if (!at)
|
||||
{
|
||||
if (mod & MODwild)
|
||||
*wildmatch |= MODwild;
|
||||
else if (mod == 0)
|
||||
*wildmatch |= MODmutable;
|
||||
else
|
||||
*wildmatch |= (mod & ~MODshared);
|
||||
tt = mutableOf();
|
||||
dedtypes->tdata()[i] = tt;
|
||||
goto Lconst;
|
||||
}
|
||||
|
||||
//printf("\t> tt = %s, at = %s\n", tt->toChars(), at->toChars());
|
||||
//printf("\t> tt->implicitConvTo(at->constOf()) = %d\n", tt->implicitConvTo(at->constOf()));
|
||||
//printf("\t> at->implicitConvTo(tt->constOf()) = %d\n", at->implicitConvTo(tt->constOf()));
|
||||
|
||||
if (tt->equals(at))
|
||||
{
|
||||
goto Lconst;
|
||||
}
|
||||
else if (tt->implicitConvTo(at->constOf()))
|
||||
{
|
||||
dedtypes->tdata()[i] = at->constOf()->mutableOf();
|
||||
*wildmatch |= MODconst;
|
||||
goto Lconst;
|
||||
}
|
||||
else if (at->implicitConvTo(tt->constOf()))
|
||||
{
|
||||
dedtypes->tdata()[i] = tt->constOf()->mutableOf();
|
||||
*wildmatch |= MODconst;
|
||||
goto Lconst;
|
||||
}
|
||||
goto Lnomatch;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (X(tparam->mod, mod))
|
||||
{
|
||||
case X(0, 0):
|
||||
@@ -2003,7 +2068,7 @@ MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters,
|
||||
}
|
||||
|
||||
if (nextOf())
|
||||
return nextOf()->deduceType(sc, tparam->nextOf(), parameters, dedtypes);
|
||||
return nextOf()->deduceType(sc, tparam->nextOf(), parameters, dedtypes, wildmatch);
|
||||
|
||||
Lexact:
|
||||
return MATCHexact;
|
||||
@@ -2019,19 +2084,19 @@ Lconst:
|
||||
|
||||
#if DMDV2
|
||||
MATCH TypeDArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters,
|
||||
Objects *dedtypes)
|
||||
Objects *dedtypes, unsigned *wildmatch)
|
||||
{
|
||||
#if 0
|
||||
printf("TypeDArray::deduceType()\n");
|
||||
printf("\tthis = %d, ", ty); print();
|
||||
printf("\ttparam = %d, ", tparam->ty); tparam->print();
|
||||
#endif
|
||||
return Type::deduceType(sc, tparam, parameters, dedtypes);
|
||||
return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch);
|
||||
}
|
||||
#endif
|
||||
|
||||
MATCH TypeSArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters,
|
||||
Objects *dedtypes)
|
||||
Objects *dedtypes, unsigned *wildmatch)
|
||||
{
|
||||
#if 0
|
||||
printf("TypeSArray::deduceType()\n");
|
||||
@@ -2100,7 +2165,7 @@ MATCH TypeSArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parame
|
||||
else
|
||||
{ dedtypes->tdata()[i] = dim;
|
||||
}
|
||||
return next->deduceType(sc, tparam->nextOf(), parameters, dedtypes);
|
||||
return next->deduceType(sc, tparam->nextOf(), parameters, dedtypes, wildmatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2109,19 +2174,19 @@ MATCH TypeSArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parame
|
||||
else if (tparam->ty == Tarray)
|
||||
{ MATCH m;
|
||||
|
||||
m = next->deduceType(sc, tparam->nextOf(), parameters, dedtypes);
|
||||
m = next->deduceType(sc, tparam->nextOf(), parameters, dedtypes, wildmatch);
|
||||
if (m == MATCHexact)
|
||||
m = MATCHconvert;
|
||||
return m;
|
||||
}
|
||||
}
|
||||
return Type::deduceType(sc, tparam, parameters, dedtypes);
|
||||
return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch);
|
||||
|
||||
Lnomatch:
|
||||
return MATCHnomatch;
|
||||
}
|
||||
|
||||
MATCH TypeAArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes)
|
||||
MATCH TypeAArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch)
|
||||
{
|
||||
#if 0
|
||||
printf("TypeAArray::deduceType()\n");
|
||||
@@ -2133,15 +2198,15 @@ MATCH TypeAArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parame
|
||||
if (tparam && tparam->ty == Taarray)
|
||||
{
|
||||
TypeAArray *tp = (TypeAArray *)tparam;
|
||||
if (!index->deduceType(sc, tp->index, parameters, dedtypes))
|
||||
if (!index->deduceType(sc, tp->index, parameters, dedtypes, wildmatch))
|
||||
{
|
||||
return MATCHnomatch;
|
||||
}
|
||||
}
|
||||
return Type::deduceType(sc, tparam, parameters, dedtypes);
|
||||
return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch);
|
||||
}
|
||||
|
||||
MATCH TypeFunction::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes)
|
||||
MATCH TypeFunction::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch)
|
||||
{
|
||||
//printf("TypeFunction::deduceType()\n");
|
||||
//printf("\tthis = %d, ", ty); print();
|
||||
@@ -2237,14 +2302,14 @@ MATCH TypeFunction::deduceType(Scope *sc, Type *tparam, TemplateParameters *para
|
||||
Parameter *a = Parameter::getNth(this->parameters, i);
|
||||
Parameter *ap = Parameter::getNth(tp->parameters, i);
|
||||
if (a->storageClass != ap->storageClass ||
|
||||
!a->type->deduceType(sc, ap->type, parameters, dedtypes))
|
||||
!a->type->deduceType(sc, ap->type, parameters, dedtypes, wildmatch))
|
||||
return MATCHnomatch;
|
||||
}
|
||||
}
|
||||
return Type::deduceType(sc, tparam, parameters, dedtypes);
|
||||
return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch);
|
||||
}
|
||||
|
||||
MATCH TypeIdentifier::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes)
|
||||
MATCH TypeIdentifier::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch)
|
||||
{
|
||||
// Extra check
|
||||
if (tparam && tparam->ty == Tident)
|
||||
@@ -2260,12 +2325,12 @@ MATCH TypeIdentifier::deduceType(Scope *sc, Type *tparam, TemplateParameters *pa
|
||||
return MATCHnomatch;
|
||||
}
|
||||
}
|
||||
return Type::deduceType(sc, tparam, parameters, dedtypes);
|
||||
return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch);
|
||||
}
|
||||
|
||||
MATCH TypeInstance::deduceType(Scope *sc,
|
||||
Type *tparam, TemplateParameters *parameters,
|
||||
Objects *dedtypes)
|
||||
Objects *dedtypes, unsigned *wildmatch)
|
||||
{
|
||||
#if 0
|
||||
printf("TypeInstance::deduceType()\n");
|
||||
@@ -2406,7 +2471,7 @@ MATCH TypeInstance::deduceType(Scope *sc,
|
||||
|
||||
if (t1 && t2)
|
||||
{
|
||||
if (!t1->deduceType(sc, t2, parameters, dedtypes))
|
||||
if (!t1->deduceType(sc, t2, parameters, dedtypes, wildmatch))
|
||||
goto Lnomatch;
|
||||
}
|
||||
else if (e1 && e2)
|
||||
@@ -2479,14 +2544,14 @@ MATCH TypeInstance::deduceType(Scope *sc,
|
||||
goto Lnomatch;
|
||||
}
|
||||
}
|
||||
return Type::deduceType(sc, tparam, parameters, dedtypes);
|
||||
return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch);
|
||||
|
||||
Lnomatch:
|
||||
//printf("no match\n");
|
||||
return MATCHnomatch;
|
||||
}
|
||||
|
||||
MATCH TypeStruct::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes)
|
||||
MATCH TypeStruct::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch)
|
||||
{
|
||||
//printf("TypeStruct::deduceType()\n");
|
||||
//printf("\tthis->parent = %s, ", sym->parent->toChars()); print();
|
||||
@@ -2503,7 +2568,7 @@ MATCH TypeStruct::deduceType(Scope *sc, Type *tparam, TemplateParameters *parame
|
||||
if (ti && ti->toAlias() == sym)
|
||||
{
|
||||
TypeInstance *t = new TypeInstance(0, ti);
|
||||
return t->deduceType(sc, tparam, parameters, dedtypes);
|
||||
return t->deduceType(sc, tparam, parameters, dedtypes, wildmatch);
|
||||
}
|
||||
|
||||
/* Match things like:
|
||||
@@ -2520,7 +2585,7 @@ MATCH TypeStruct::deduceType(Scope *sc, Type *tparam, TemplateParameters *parame
|
||||
/* Slice off the .foo in S!(T).foo
|
||||
*/
|
||||
tpi->idents.dim--;
|
||||
MATCH m = tparent->deduceType(sc, tpi, parameters, dedtypes);
|
||||
MATCH m = tparent->deduceType(sc, tpi, parameters, dedtypes, wildmatch);
|
||||
tpi->idents.dim++;
|
||||
return m;
|
||||
}
|
||||
@@ -2536,10 +2601,10 @@ MATCH TypeStruct::deduceType(Scope *sc, Type *tparam, TemplateParameters *parame
|
||||
if (sym != tp->sym)
|
||||
return MATCHnomatch;
|
||||
}
|
||||
return Type::deduceType(sc, tparam, parameters, dedtypes);
|
||||
return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch);
|
||||
}
|
||||
|
||||
MATCH TypeEnum::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes)
|
||||
MATCH TypeEnum::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch)
|
||||
{
|
||||
// Extra check
|
||||
if (tparam && tparam->ty == Tenum)
|
||||
@@ -2549,10 +2614,10 @@ MATCH TypeEnum::deduceType(Scope *sc, Type *tparam, TemplateParameters *paramete
|
||||
if (sym != tp->sym)
|
||||
return MATCHnomatch;
|
||||
}
|
||||
return Type::deduceType(sc, tparam, parameters, dedtypes);
|
||||
return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch);
|
||||
}
|
||||
|
||||
MATCH TypeTypedef::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes)
|
||||
MATCH TypeTypedef::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch)
|
||||
{
|
||||
// Extra check
|
||||
if (tparam && tparam->ty == Ttypedef)
|
||||
@@ -2562,7 +2627,7 @@ MATCH TypeTypedef::deduceType(Scope *sc, Type *tparam, TemplateParameters *param
|
||||
if (sym != tp->sym)
|
||||
return MATCHnomatch;
|
||||
}
|
||||
return Type::deduceType(sc, tparam, parameters, dedtypes);
|
||||
return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch);
|
||||
}
|
||||
|
||||
/* Helper for TypeClass::deduceType().
|
||||
@@ -2622,7 +2687,7 @@ void deduceBaseClassParameters(BaseClass *b,
|
||||
|
||||
}
|
||||
|
||||
MATCH TypeClass::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes)
|
||||
MATCH TypeClass::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch)
|
||||
{
|
||||
//printf("TypeClass::deduceType(this = %s)\n", toChars());
|
||||
|
||||
@@ -2637,7 +2702,7 @@ MATCH TypeClass::deduceType(Scope *sc, Type *tparam, TemplateParameters *paramet
|
||||
if (ti && ti->toAlias() == sym)
|
||||
{
|
||||
TypeInstance *t = new TypeInstance(0, ti);
|
||||
MATCH m = t->deduceType(sc, tparam, parameters, dedtypes);
|
||||
MATCH m = t->deduceType(sc, tparam, parameters, dedtypes, wildmatch);
|
||||
// Even if the match fails, there is still a chance it could match
|
||||
// a base class.
|
||||
if (m != MATCHnomatch)
|
||||
@@ -2658,7 +2723,7 @@ MATCH TypeClass::deduceType(Scope *sc, Type *tparam, TemplateParameters *paramet
|
||||
/* Slice off the .foo in S!(T).foo
|
||||
*/
|
||||
tpi->idents.dim--;
|
||||
MATCH m = tparent->deduceType(sc, tpi, parameters, dedtypes);
|
||||
MATCH m = tparent->deduceType(sc, tpi, parameters, dedtypes, wildmatch);
|
||||
tpi->idents.dim++;
|
||||
return m;
|
||||
}
|
||||
@@ -2666,7 +2731,7 @@ MATCH TypeClass::deduceType(Scope *sc, Type *tparam, TemplateParameters *paramet
|
||||
}
|
||||
|
||||
// If it matches exactly or via implicit conversion, we're done
|
||||
MATCH m = Type::deduceType(sc, tparam, parameters, dedtypes);
|
||||
MATCH m = Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch);
|
||||
if (m != MATCHnomatch)
|
||||
return m;
|
||||
|
||||
@@ -2715,7 +2780,7 @@ MATCH TypeClass::deduceType(Scope *sc, Type *tparam, TemplateParameters *paramet
|
||||
//printf("\t%d\n", (MATCH) implicitConvTo(tp));
|
||||
return implicitConvTo(tp);
|
||||
}
|
||||
return Type::deduceType(sc, tparam, parameters, dedtypes);
|
||||
return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch);
|
||||
}
|
||||
|
||||
/* ======================== TemplateParameter =============================== */
|
||||
@@ -3703,6 +3768,7 @@ TemplateInstance::TemplateInstance(Loc loc, Identifier *ident)
|
||||
this->havetempdecl = 0;
|
||||
this->isnested = NULL;
|
||||
this->errors = 0;
|
||||
this->speculative = 0;
|
||||
|
||||
#if IN_LLVM
|
||||
// LDC
|
||||
@@ -3737,6 +3803,7 @@ TemplateInstance::TemplateInstance(Loc loc, TemplateDeclaration *td, Objects *ti
|
||||
this->havetempdecl = 1;
|
||||
this->isnested = NULL;
|
||||
this->errors = 0;
|
||||
this->speculative = 0;
|
||||
|
||||
#if IN_LLVM
|
||||
// LDC
|
||||
@@ -3934,6 +4001,27 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs)
|
||||
// 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 LOG
|
||||
printf("\tit's a match with instance %p\n", inst);
|
||||
#endif
|
||||
@@ -3951,6 +4039,10 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs)
|
||||
#endif
|
||||
unsigned errorsave = global.errors;
|
||||
inst = this;
|
||||
// Mark as speculative if we are instantiated from inside is(typeof())
|
||||
if (global.gag && sc->intypeof)
|
||||
speculative = 1;
|
||||
|
||||
int tempdecl_instance_idx = tempdecl->instances.dim;
|
||||
tempdecl->instances.push(this);
|
||||
parent = tempdecl->parent;
|
||||
@@ -4233,7 +4325,12 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs)
|
||||
// (see bugzilla 4302 and 6602).
|
||||
tempdecl->instances.remove(tempdecl_instance_idx);
|
||||
if (target_symbol_list)
|
||||
{
|
||||
// Because we added 'this' in the last position above, we
|
||||
// should be able to remove it without messing other indices up.
|
||||
assert(target_symbol_list->tdata()[target_symbol_list_idx] == this);
|
||||
target_symbol_list->remove(target_symbol_list_idx);
|
||||
}
|
||||
semanticRun = 0;
|
||||
inst = NULL;
|
||||
}
|
||||
@@ -4293,7 +4390,9 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f
|
||||
tiargs->tdata()[j] = ea;
|
||||
}
|
||||
else if (sa)
|
||||
{ tiargs->tdata()[j] = sa;
|
||||
{
|
||||
Ldsym:
|
||||
tiargs->tdata()[j] = sa;
|
||||
TupleDeclaration *d = sa->toAlias()->isTupleDeclaration();
|
||||
if (d)
|
||||
{
|
||||
@@ -4339,13 +4438,17 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f
|
||||
ea = ea->semantic(sc);
|
||||
if (flags & 1) // only used by __traits, must not interpret the args
|
||||
ea = ea->optimize(WANTvalue);
|
||||
else if (ea->op != TOKvar)
|
||||
else if (ea->op != TOKvar && ea->op != TOKtuple)
|
||||
ea = ea->optimize(WANTvalue | WANTinterpret);
|
||||
tiargs->tdata()[j] = ea;
|
||||
if (ea->op == TOKtype)
|
||||
{ ta = ea->type;
|
||||
goto Ltype;
|
||||
}
|
||||
if (ea->op == TOKimport)
|
||||
{ sa = ((ScopeExp *)ea)->sds;
|
||||
goto Ldsym;
|
||||
}
|
||||
if (ea->op == TOKtuple)
|
||||
{ // Expand tuple
|
||||
TupleExp *te = (TupleExp *)ea;
|
||||
@@ -4901,6 +5004,10 @@ int TemplateInstance::needsTypeInference(Scope *sc)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < td->parameters->dim; i++)
|
||||
if (td->parameters->tdata()[i]->isTemplateThisParameter())
|
||||
return TRUE;
|
||||
|
||||
/* Determine if the instance arguments, tiargs, are all that is necessary
|
||||
* to instantiate the template.
|
||||
*/
|
||||
@@ -4908,7 +5015,7 @@ int TemplateInstance::needsTypeInference(Scope *sc)
|
||||
//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) &&
|
||||
(tp || tiargs->dim < td->parameters->dim))
|
||||
((tp && td->parameters->dim > 1) || tiargs->dim < td->parameters->dim))
|
||||
return TRUE;
|
||||
/* If there is more than one function template which matches, we may
|
||||
* need type inference (see Bugzilla 4430)
|
||||
@@ -4967,10 +5074,26 @@ void TemplateInstance::semantic3(Scope *sc)
|
||||
sc = sc->push(argsym);
|
||||
sc = sc->push(this);
|
||||
sc->tinst = this;
|
||||
int oldgag = global.gag;
|
||||
int olderrors = global.errors;
|
||||
/* 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();
|
||||
for (size_t i = 0; i < members->dim; i++)
|
||||
{
|
||||
Dsymbol *s = members->tdata()[i];
|
||||
s->semantic3(sc);
|
||||
if (speculative && global.errors != olderrors)
|
||||
break;
|
||||
}
|
||||
if (speculative && !oldgag)
|
||||
{ // If errors occurred, this instantiation failed
|
||||
errors += global.errors - olderrors;
|
||||
global.endGagging(olderrors);
|
||||
}
|
||||
sc = sc->pop();
|
||||
sc->pop();
|
||||
|
||||
@@ -301,6 +301,7 @@ struct TemplateInstance : ScopeDsymbol
|
||||
int havetempdecl; // 1 if used second constructor
|
||||
Dsymbol *isnested; // if referencing local symbols, this is the context
|
||||
int errors; // 1 if compiled with errors
|
||||
int speculative; // 1 if only instantiated with errors gagged
|
||||
#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
|
||||
|
||||
@@ -263,7 +263,10 @@ Expression *TraitsExp::semantic(Scope *sc)
|
||||
e = e->trySemantic(sc);
|
||||
if (!e)
|
||||
{ if (global.gag)
|
||||
{
|
||||
global.errors++;
|
||||
global.gaggedErrors++;
|
||||
}
|
||||
goto Lfalse;
|
||||
}
|
||||
else
|
||||
@@ -400,8 +403,7 @@ Expression *TraitsExp::semantic(Scope *sc)
|
||||
{ Object *o = args->tdata()[i];
|
||||
Expression *e;
|
||||
|
||||
unsigned errors = global.errors;
|
||||
global.gag++;
|
||||
unsigned errors = global.startGagging();
|
||||
|
||||
Type *t = isType(o);
|
||||
if (t)
|
||||
@@ -422,10 +424,8 @@ Expression *TraitsExp::semantic(Scope *sc)
|
||||
}
|
||||
}
|
||||
|
||||
global.gag--;
|
||||
if (errors != global.errors)
|
||||
if (global.endGagging(errors))
|
||||
{
|
||||
global.errors = errors;
|
||||
goto Lfalse;
|
||||
}
|
||||
}
|
||||
|
||||
2
druntime
2
druntime
Submodule druntime updated: fba10fa9f6...00264712aa
@@ -4,7 +4,7 @@
|
||||
#include "declaration.h"
|
||||
#include "enum.h"
|
||||
#include "id.h"
|
||||
#include "mem.h"
|
||||
#include "rmem.h"
|
||||
#include "template.h"
|
||||
|
||||
#include "gen/irstate.h"
|
||||
|
||||
14
gen/main.cpp
14
gen/main.cpp
@@ -127,8 +127,22 @@ static void initFromString(char*& dest, const cl::opt<std::string>& src) {
|
||||
}
|
||||
}
|
||||
|
||||
#if _WIN32
|
||||
extern "C"
|
||||
{
|
||||
extern int _xi_a;
|
||||
extern int _end;
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
mem.init(); // initialize storage allocator
|
||||
mem.setStackBottom(&argv);
|
||||
#if _WIN32
|
||||
mem.addroots((char *)&_xi_a, (char *)&_end);
|
||||
#endif
|
||||
|
||||
// stack trace on signals
|
||||
llvm::sys::PrintStackTraceOnErrorSignal();
|
||||
|
||||
|
||||
@@ -3016,6 +3016,8 @@ STUB(ScopeExp);
|
||||
|
||||
#if DMDV2
|
||||
STUB(SymbolExp);
|
||||
STUB(PowExp);
|
||||
STUB(PowAssignExp);
|
||||
#endif
|
||||
|
||||
#define CONSTSTUB(x) LLConstant* x::toConstElem(IRState * p) { \
|
||||
|
||||
@@ -666,7 +666,7 @@ void TypeInfoStructDeclaration::llvmDefine()
|
||||
|
||||
// opEquals
|
||||
#if DMDV2
|
||||
fd = sd->eq;
|
||||
fd = sd->xeq;
|
||||
#else
|
||||
fd = find_method_overload(sd, Id::eq, tfcmpptr, gm);
|
||||
#endif
|
||||
|
||||
2
phobos
2
phobos
Submodule phobos updated: a8106d9d48...2bebc8f8ba
Reference in New Issue
Block a user