changeset 92:70d6113eeb8c trunk

[svn r96] Updated to DMD 1.023. Regular bugfixes.
author lindquist
date Thu, 08 Nov 2007 19:13:28 +0100
parents 3f949c6e2e9d
children 08508eebbb3e
files dmd/declaration.c dmd/declaration.h dmd/expression.c dmd/expression.h dmd/func.c dmd/inline.c dmd/link.c dmd/mars.c dmd/mtype.c dmd/mtype.h dmd/optimize.c dmd/parse.c dmd/statement.c dmd/template.c dmd/template.h gen/toir.cpp gen/tollvm.cpp gen/tollvm.h lphobos/std/c/linux/socket.d test/bug51.d test/bug55.d test/bug56.d test/ray.d test/sqrts.d
diffstat 24 files changed, 497 insertions(+), 168 deletions(-) [+]
line wrap: on
line diff
--- a/dmd/declaration.c	Wed Nov 07 04:52:56 2007 +0100
+++ b/dmd/declaration.c	Thu Nov 08 19:13:28 2007 +0100
@@ -770,7 +770,8 @@
     }
 
     if (!init && !sc->inunion && !isStatic() && !isConst() && fd &&
-	!(storage_class & (STCfield | STCin | STCforeach)))
+	!(storage_class & (STCfield | STCin | STCforeach)) &&
+	type->size() != 0)
     {
 	// Provide a default initializer
 	//printf("Providing default initializer for '%s'\n", toChars());
@@ -863,19 +864,19 @@
 		t = type->toBasetype();
 		if (t->ty == Tsarray)
 		{
-		    dim = ((TypeSArray *)t)->dim->toInteger();
-		    // If multidimensional static array, treat as one large array
-		    while (1)
+		    ei->exp = ei->exp->semantic(sc);
+		    if (!ei->exp->implicitConvTo(type))
 		    {
-			t = t->next->toBasetype();
-			if (t->ty != Tsarray)
-			    break;
-			if (t->next->toBasetype()->ty == Tbit)
-			    // t->size() gives size in bytes, convert to bits
-			    dim *= t->size() * 8;
-			else
+			dim = ((TypeSArray *)t)->dim->toInteger();
+			// If multidimensional static array, treat as one large array
+			while (1)
+			{
+			    t = t->nextOf()->toBasetype();
+			    if (t->ty != Tsarray)
+				break;
 			    dim *= ((TypeSArray *)t)->dim->toInteger();
-			e1->type = new TypeSArray(t->next, new IntegerExp(0, dim, Type::tindex));
+			    e1->type = new TypeSArray(t->nextOf(), new IntegerExp(0, dim, Type::tindex));
+			}
 		    }
 		    e1 = new SliceExp(loc, e1, NULL, NULL);
 		}
@@ -1042,7 +1043,7 @@
 
 void VarDeclaration::checkNestedReference(Scope *sc, Loc loc)
 {
-    if (!isDataseg() && parent != sc->parent && parent)
+    if (parent && !isDataseg() && parent != sc->parent)
     {
 	FuncDeclaration *fdv = toParent()->isFuncDeclaration();
 	FuncDeclaration *fdthis = sc->parent->isFuncDeclaration();
@@ -1180,6 +1181,24 @@
     assert(linkage == LINKc);
 }
 
+/***************************** TypeInfoConstDeclaration **********************/
+
+#if V2
+TypeInfoConstDeclaration::TypeInfoConstDeclaration(Type *tinfo)
+    : TypeInfoDeclaration(tinfo, 0)
+{
+}
+#endif
+
+/***************************** TypeInfoInvariantDeclaration **********************/
+
+#if V2
+TypeInfoInvariantDeclaration::TypeInfoInvariantDeclaration(Type *tinfo)
+    : TypeInfoDeclaration(tinfo, 0)
+{
+}
+#endif
+
 /***************************** TypeInfoStructDeclaration **********************/
 
 TypeInfoStructDeclaration::TypeInfoStructDeclaration(Type *tinfo)
--- a/dmd/declaration.h	Wed Nov 07 04:52:56 2007 +0100
+++ b/dmd/declaration.h	Thu Nov 08 19:13:28 2007 +0100
@@ -424,6 +424,23 @@
 
 /**************************************************************/
 
+#if V2
+
+enum BUILTIN
+{
+    BUILTINunknown = -1,	// not known if this is a builtin
+    BUILTINnot,			// this is not a builtin
+    BUILTINsin,			// std.math.sin
+    BUILTINcos,			// std.math.cos
+    BUILTINtan,			// std.math.tan
+    BUILTINsqrt,		// std.math.sqrt
+    BUILTINfabs,		// std.math.fabs
+};
+
+Expression *eval_builtin(enum BUILTIN builtin, Expressions *arguments);
+
+#endif
+
 struct FuncDeclaration : Declaration
 {
     Array *fthrows;			// Array of Type's of exceptions (not used)
@@ -453,7 +470,6 @@
     int inlineNest;			// !=0 if nested inline
     int cantInterpret;			// !=0 if cannot interpret function
     int semanticRun;			// !=0 if semantic3() had been run
-    int nestedFrameRef;			// !=0 if nested variables referenced frame ptr
     ForeachStatement *fes;		// if foreach body, this is the foreach
     int introducing;			// !=0 if 'introducing' function
     Type *tintro;			// if !=NULL, then this is the type
@@ -473,6 +489,20 @@
     VarDeclaration *nrvo_var;		// variable to replace with shidden
     Symbol *shidden;			// hidden pointer passed to function
 
+#if V2
+    enum BUILTIN builtin;		// set if this is a known, builtin
+					// function we can evaluate at compile
+					// time
+
+    int tookAddressOf;			// set if someone took the address of
+					// this function
+    Dsymbols closureVars;		// local variables in this function
+					// which are referenced by nested
+					// functions
+#else
+    int nestedFrameRef;			// !=0 if nested variables referenced
+#endif
+
     FuncDeclaration(Loc loc, Loc endloc, Identifier *id, enum STC storage_class, Type *type);
     Dsymbol *syntaxCopy(Dsymbol *);
     void semantic(Scope *sc);
--- a/dmd/expression.c	Wed Nov 07 04:52:56 2007 +0100
+++ b/dmd/expression.c	Thu Nov 08 19:13:28 2007 +0100
@@ -852,10 +852,13 @@
     return this;
 }
 
-void Expression::checkArithmetic()
+Expression *Expression::checkArithmetic()
 {
     if (!type->isintegral() && !type->isfloating())
-	error("'%s' is not an arithmetic type", toChars());
+    {	error("'%s' is not of arithmetic type, it is a %s", toChars(), type->toChars());
+	return new IntegerExp(0);
+    }
+    return this;
 }
 
 void Expression::checkDeprecated(Scope *sc, Dsymbol *s)
@@ -6990,6 +6993,31 @@
     e2 = resolveProperties(sc, e2);
     assert(e1->type);
 
+    /* Rewrite tuple assignment as a tuple of assignments.
+     */
+    if (e1->op == TOKtuple && e2->op == TOKtuple)
+    {	TupleExp *tup1 = (TupleExp *)e1;
+	TupleExp *tup2 = (TupleExp *)e2;
+	size_t dim = tup1->exps->dim;
+	if (dim != tup2->exps->dim)
+	{
+	    error("mismatched tuple lengths, %d and %d", (int)dim, (int)tup2->exps->dim);
+	}
+	else
+	{   Expressions *exps = new Expressions;
+	    exps->setDim(dim);
+
+	    for (int i = 0; i < dim; i++)
+	    {	Expression *ex1 = (Expression *)tup1->exps->data[i];
+		Expression *ex2 = (Expression *)tup2->exps->data[i];
+		exps->data[i] = (void *) new AssignExp(loc, ex1, ex2);
+	    }
+	    Expression *e = new TupleExp(loc, exps);
+	    e = e->semantic(sc);
+	    return e;
+	}
+    }
+
     t1 = e1->type->toBasetype();
 
     if (t1->ty == Tfunction)
@@ -7032,21 +7060,14 @@
     }
 
     if (e1->op == TOKslice &&
-	t1->next &&
-	!(t1->next->equals(e2->type->next) /*||
-	  (t1->next->ty == Tchar && e2->op == TOKstring)*/)
+	t1->nextOf() &&
+	e2->implicitConvTo(t1->nextOf())
+//	!(t1->nextOf()->equals(e2->type->nextOf()))
        )
     {	// memset
+	ismemset = 1;	// make it easy for back end to tell what this is
 	e2 = e2->implicitCastTo(sc, t1->next);
     }
-#if 0
-    else if (e1->op == TOKslice &&
-	     e2->op == TOKstring &&
-	     ((StringExp *)e2)->len == 1)
-    {	// memset
-	e2 = e2->implicitCastTo(sc, e1->type->next);
-    }
-#endif
     else if (t1->ty == Tsarray)
     {
 	error("cannot assign to static array %s", e1->toChars());
@@ -7197,10 +7218,10 @@
 	e = scaleFactor(sc);
     else
     {
+	e1 = e1->checkArithmetic();
+	e2 = e2->checkArithmetic();
 	type = e1->type;
 	typeCombine(sc);
-	e1->checkArithmetic();
-	e2->checkArithmetic();
 	if (type->isreal() || type->isimaginary())
 	{
 	    assert(e2->type->isfloating());
--- a/dmd/expression.h	Wed Nov 07 04:52:56 2007 +0100
+++ b/dmd/expression.h	Thu Nov 08 19:13:28 2007 +0100
@@ -118,7 +118,7 @@
     void checkScalar();
     void checkNoBool();
     Expression *checkIntegral();
-    void checkArithmetic();
+    Expression *checkArithmetic();
     void checkDeprecated(Scope *sc, Dsymbol *s);
     virtual Expression *checkToBoolean();
     Expression *checkToPointer();
@@ -364,6 +364,7 @@
     Expression *optimize(int result);
     Expression *interpret(InterState *istate);
     Expression *castTo(Scope *sc, Type *t);
+    elem *toElem(IRState *irs);
 
     int inlineCost(InlineCostState *ics);
     Expression *doInline(InlineDoState *ids);
--- a/dmd/func.c	Wed Nov 07 04:52:56 2007 +0100
+++ b/dmd/func.c	Thu Nov 08 19:13:28 2007 +0100
@@ -557,6 +557,8 @@
 
     if (!parent)
     {
+	if (global.errors)
+	    return;
 	printf("FuncDeclaration::semantic3(%s '%s', sc = %p)\n", kind(), toChars(), sc);
 	assert(0);
     }
--- a/dmd/inline.c	Wed Nov 07 04:52:56 2007 +0100
+++ b/dmd/inline.c	Thu Nov 08 19:13:28 2007 +0100
@@ -546,8 +546,6 @@
 	    ;
 	else
 	{
-	    ExpInitializer *ie;
-	    ExpInitializer *ieto;
 	    VarDeclaration *vto;
 
 	    vto = new VarDeclaration(vd->loc, vd->type, vd->ident, vd->init);
@@ -559,16 +557,18 @@
 	    ids->from.push(vd);
 	    ids->to.push(vto);
 
-	    if (vd->init->isVoidInitializer())
+	    if (vd->init)
 	    {
-		vto->init = new VoidInitializer(vd->init->loc);
-	    }
-	    else
-	    {
-		ie = vd->init->isExpInitializer();
-		assert(ie);
-		ieto = new ExpInitializer(ie->loc, ie->exp->doInline(ids));
-		vto->init = ieto;
+		if (vd->init->isVoidInitializer())
+		{
+		    vto->init = new VoidInitializer(vd->init->loc);
+		}
+		else
+		{
+		    ExpInitializer *ie = vd->init->isExpInitializer();
+		    assert(ie);
+		    vto->init = new ExpInitializer(ie->loc, ie->exp->doInline(ids));
+		}
 	    }
 	    de->declaration = (Dsymbol *) (void *)vto;
 	}
@@ -854,7 +854,8 @@
 Statement *ForeachStatement::inlineScan(InlineScanState *iss)
 {
     aggr = aggr->inlineScan(iss);
-    body = body->inlineScan(iss);
+    if (body)
+	body = body->inlineScan(iss);
     return this;
 }
 
@@ -864,7 +865,8 @@
 {
     lwr = lwr->inlineScan(iss);
     upr = upr->inlineScan(iss);
-    body = body->inlineScan(iss);
+    if (body)
+	body = body->inlineScan(iss);
     return this;
 }
 #endif
@@ -1288,7 +1290,11 @@
 #endif
 	isSynchronized() ||
 	isImportedSymbol() ||
+#if V2
+	closureVars.dim ||	// no nested references to this frame
+#else
 	nestedFrameRef ||	// no nested references to this frame
+#endif
 	(isVirtual() && !isFinal())
        ))
     {
--- a/dmd/link.c	Wed Nov 07 04:52:56 2007 +0100
+++ b/dmd/link.c	Thu Nov 08 19:13:28 2007 +0100
@@ -278,15 +278,16 @@
     /* Standard libraries must go after user specified libraries
      * passed with -l.
      */
-    //argv.push((void *)"-lphobos");	// turns into /usr/lib/libphobos.a
-    //argv.push((void *)"-lpthread");
-    //argv.push((void *)"-lm");
 
     std::string corelibpath = global.params.runtimeImppath;
     corelibpath.append("/llvmdcore.bc");
     argv.append(global.params.objfiles);
     argv.push((void *)corelibpath.c_str());
-    
+
+    //argv.push((void *)"-lphobos");    // turns into /usr/lib/libphobos.a
+    //argv.push((void *)"-lpthread");
+    argv.push((void *)"-l=m");
+
     if (!global.params.quiet)
     {
 	// Print it
--- a/dmd/mars.c	Wed Nov 07 04:52:56 2007 +0100
+++ b/dmd/mars.c	Thu Nov 08 19:13:28 2007 +0100
@@ -71,7 +71,7 @@
     copyright = "Copyright (c) 1999-2007 by Digital Mars and Tomas Lindquist Olsen";
     written = "written by Walter Bright and Tomas Lindquist Olsen";
     llvmdc_version = "0.1";
-    version = "v1.022";
+    version = "v1.023";
     global.structalign = 8;
 
     memset(&params, 0, sizeof(Param));
--- a/dmd/mtype.c	Wed Nov 07 04:52:56 2007 +0100
+++ b/dmd/mtype.c	Thu Nov 08 19:13:28 2007 +0100
@@ -489,7 +489,7 @@
 }
 
 
-Expression *Type::defaultInit()
+Expression *Type::defaultInit(Loc loc)
 {
 #if LOGDEFAULTINIT
     printf("Type::defaultInit() '%s'\n", toChars());
@@ -556,8 +556,7 @@
     {
 	if (ty == Tvoid)
 	    error(loc, "void does not have an initializer");
-	e = defaultInit();
-	e->loc = loc;
+	e = defaultInit(loc);
     }
     else if (ident == Id::mangleof)
     {
@@ -634,7 +633,7 @@
 			    e->isBool(0) &&
 			    v->type->toBasetype()->ty == Tstruct)
 			{
-			    e = v->type->defaultInit();
+			    e = v->type->defaultInit(loc);
 			}
 		    }
 		    e = e->optimize(WANTvalue | WANTinterpret);
@@ -644,8 +643,7 @@
 		return e;
 	    }
 #endif
-	    Expression *ex = defaultInit();
-	    ex->loc = e->loc;
+	    Expression *ex = defaultInit(e->loc);
 	    return ex;
 	}
     }
@@ -1327,7 +1325,7 @@
     return e;
 }
 
-Expression *TypeBasic::defaultInit()
+Expression *TypeBasic::defaultInit(Loc loc)
 {   integer_t value = 0;
 
 #if LOGDEFAULTINIT
@@ -1353,9 +1351,9 @@
 	case Tcomplex32:
 	case Tcomplex64:
 	case Tcomplex80:
-	    return getProperty(0, Id::nan);
-    }
-    return new IntegerExp(0, value, this);
+	    return getProperty(loc, Id::nan);
+    }
+    return new IntegerExp(loc, value, this);
 }
 
 int TypeBasic::isZeroInit()
@@ -1825,6 +1823,14 @@
 	dim = semanticLength(sc, tbn, dim);
 
 	dim = dim->optimize(WANTvalue | WANTinterpret);
+	if (sc->parameterSpecialization && dim->op == TOKvar &&
+	    ((VarExp *)dim)->var->storage_class & STCtemplateparameter)
+	{
+	    /* It could be a template parameter N which has no value yet:
+	     *   template Foo(T : T[N], size_t N);
+	     */
+	    return this;
+	}
 	integer_t d1 = dim->toInteger();
 	dim = dim->castTo(sc, tsize_t);
 	dim = dim->optimize(WANTvalue);
@@ -1969,12 +1975,12 @@
     return Type::implicitConvTo(to);
 }
 
-Expression *TypeSArray::defaultInit()
+Expression *TypeSArray::defaultInit(Loc loc)
 {
 #if LOGDEFAULTINIT
     printf("TypeSArray::defaultInit() '%s'\n", toChars());
 #endif
-    return next->defaultInit();
+    return next->defaultInit(loc);
 }
 
 int TypeSArray::isZeroInit()
@@ -2127,13 +2133,13 @@
     return Type::implicitConvTo(to);
 }
 
-Expression *TypeDArray::defaultInit()
+Expression *TypeDArray::defaultInit(Loc loc)
 {
 #if LOGDEFAULTINIT
     printf("TypeDArray::defaultInit() '%s'\n", toChars());
 #endif
     Expression *e;
-    e = new NullExp(0);
+    e = new NullExp(loc);
     e->type = this;
     return e;
 }
@@ -2341,13 +2347,13 @@
     buf->writeByte(']');
 }
 
-Expression *TypeAArray::defaultInit()
+Expression *TypeAArray::defaultInit(Loc loc)
 {
 #if LOGDEFAULTINIT
     printf("TypeAArray::defaultInit() '%s'\n", toChars());
 #endif
     Expression *e;
-    e = new NullExp(0);
+    e = new NullExp(loc);
     e->type = this;
     return e;
 }
@@ -2449,13 +2455,13 @@
     return TRUE;
 }
 
-Expression *TypePointer::defaultInit()
+Expression *TypePointer::defaultInit(Loc loc)
 {
 #if LOGDEFAULTINIT
     printf("TypePointer::defaultInit() '%s'\n", toChars());
 #endif
     Expression *e;
-    e = new NullExp(0);
+    e = new NullExp(loc);
     e->type = this;
     return e;
 }
@@ -2516,13 +2522,13 @@
     return next->dotExp(sc, e, ident);
 }
 
-Expression *TypeReference::defaultInit()
+Expression *TypeReference::defaultInit(Loc loc)
 {
 #if LOGDEFAULTINIT
     printf("TypeReference::defaultInit() '%s'\n", toChars());
 #endif
     Expression *e;
-    e = new NullExp(0);
+    e = new NullExp(loc);
     e->type = this;
     return e;
 }
@@ -3000,13 +3006,13 @@
 #endif
 }
 
-Expression *TypeDelegate::defaultInit()
+Expression *TypeDelegate::defaultInit(Loc loc)
 {
 #if LOGDEFAULTINIT
     printf("TypeDelegate::defaultInit() '%s'\n", toChars());
 #endif
     Expression *e;
-    e = new NullExp(0);
+    e = new NullExp(loc);
     e->type = this;
     return e;
 }
@@ -3800,7 +3806,7 @@
     {
 	if (!sym->symtab)
 	    goto Lfwd;
-	e = defaultInit();
+	e = defaultInit(loc);
     }
     else
     {
@@ -3849,14 +3855,14 @@
     return m;
 }
 
-Expression *TypeEnum::defaultInit()
+Expression *TypeEnum::defaultInit(Loc loc)
 {
 #if LOGDEFAULTINIT
     printf("TypeEnum::defaultInit() '%s'\n", toChars());
 #endif
     // Initialize to first member of enum
     Expression *e;
-    e = new IntegerExp(0, sym->defaultval, this);
+    e = new IntegerExp(loc, sym->defaultval, this);
     return e;
 }
 
@@ -4024,7 +4030,7 @@
     return m;
 }
 
-Expression *TypeTypedef::defaultInit()
+Expression *TypeTypedef::defaultInit(Loc loc)
 {   Expression *e;
     Type *bt;
 
@@ -4037,7 +4043,7 @@
 	return sym->init->toExpression();
     }
     bt = sym->basetype;
-    e = bt->defaultInit();
+    e = bt->defaultInit(loc);
     e->type = this;
     while (bt->ty == Tsarray)
     {
@@ -4316,7 +4322,7 @@
     return sym->structalign;
 }
 
-Expression *TypeStruct::defaultInit()
+Expression *TypeStruct::defaultInit(Loc loc)
 {   Symbol *s;
     Declaration *d;
 
@@ -4701,13 +4707,13 @@
     return MATCHnomatch;
 }
 
-Expression *TypeClass::defaultInit()
+Expression *TypeClass::defaultInit(Loc loc)
 {
 #if LOGDEFAULTINIT
     printf("TypeClass::defaultInit() '%s'\n", toChars());
 #endif
     Expression *e;
-    e = new NullExp(0);
+    e = new NullExp(loc);
     e->type = this;
     return e;
 }
--- a/dmd/mtype.h	Wed Nov 07 04:52:56 2007 +0100
+++ b/dmd/mtype.h	Thu Nov 08 19:13:28 2007 +0100
@@ -227,7 +227,7 @@
     virtual Expression *getProperty(Loc loc, Identifier *ident);
     virtual Expression *dotExp(Scope *sc, Expression *e, Identifier *ident);
     virtual unsigned memalign(unsigned salign);
-    virtual Expression *defaultInit();
+    virtual Expression *defaultInit(Loc loc = 0);
     virtual int isZeroInit();		// if initializer is 0
     virtual dt_t **toDt(dt_t **pdt);
     Identifier *getTypeInfoIdent(int internal);
@@ -279,7 +279,7 @@
     int isscalar();
     int isunsigned();
     MATCH implicitConvTo(Type *to);
-    Expression *defaultInit();
+    Expression *defaultInit(Loc loc);
     int isZeroInit();
     int builtinTypeInfo();
 
@@ -314,7 +314,7 @@
     int isZeroInit();
     unsigned memalign(unsigned salign);
     MATCH implicitConvTo(Type *to);
-    Expression *defaultInit();
+    Expression *defaultInit(Loc loc);
     dt_t **toDt(dt_t **pdt);
     dt_t **toDtElem(dt_t **pdt, Expression *e);
     MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes);
@@ -342,7 +342,7 @@
     int isZeroInit();
     int checkBoolean();
     MATCH implicitConvTo(Type *to);
-    Expression *defaultInit();
+    Expression *defaultInit(Loc loc);
     int builtinTypeInfo();
     TypeInfoDeclaration *getTypeInfoDeclaration();
     int hasPointers();
@@ -362,7 +362,7 @@
     void toDecoBuffer(OutBuffer *buf);
     void toPrettyBracket(OutBuffer *buf, HdrGenState *hgs);
     Expression *dotExp(Scope *sc, Expression *e, Identifier *ident);
-    Expression *defaultInit();
+    Expression *defaultInit(Loc loc);
     MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes);
     int checkBoolean();
     TypeInfoDeclaration *getTypeInfoDeclaration();
@@ -383,7 +383,7 @@
     void toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs);
     MATCH implicitConvTo(Type *to);
     int isscalar();
-    Expression *defaultInit();
+    Expression *defaultInit(Loc loc);
     int isZeroInit();
     TypeInfoDeclaration *getTypeInfoDeclaration();
     int hasPointers();
@@ -398,7 +398,7 @@
     d_uns64 size(Loc loc);
     void toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs);
     Expression *dotExp(Scope *sc, Expression *e, Identifier *ident);
-    Expression *defaultInit();
+    Expression *defaultInit(Loc loc);
     int isZeroInit();
 };
 
@@ -445,7 +445,7 @@
     Type *semantic(Loc loc, Scope *sc);
     d_uns64 size(Loc loc);
     void toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs);
-    Expression *defaultInit();
+    Expression *defaultInit(Loc loc);
     int isZeroInit();
     int checkBoolean();
     TypeInfoDeclaration *getTypeInfoDeclaration();
@@ -530,7 +530,7 @@
     void toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs);
     Expression *dotExp(Scope *sc, Expression *e, Identifier *ident);
     unsigned memalign(unsigned salign);
-    Expression *defaultInit();
+    Expression *defaultInit(Loc loc);
     int isZeroInit();
     int checkBoolean();
     dt_t **toDt(dt_t **pdt);
@@ -564,7 +564,7 @@
     int isunsigned();
     MATCH implicitConvTo(Type *to);
     Type *toBasetype();
-    Expression *defaultInit();
+    Expression *defaultInit(Loc loc);
     int isZeroInit();
     MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes);
     TypeInfoDeclaration *getTypeInfoDeclaration();
@@ -599,7 +599,7 @@
     int checkBoolean();
     Type *toBasetype();
     MATCH implicitConvTo(Type *to);
-    Expression *defaultInit();
+    Expression *defaultInit(Loc loc);
     int isZeroInit();
     dt_t **toDt(dt_t **pdt);
     MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes);
@@ -626,7 +626,7 @@
     ClassDeclaration *isClassHandle();
     int isBaseOf(Type *t, int *poffset);
     MATCH implicitConvTo(Type *to);
-    Expression *defaultInit();
+    Expression *defaultInit(Loc loc);
     int isZeroInit();
     MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes);
     int isauto();
--- a/dmd/optimize.c	Wed Nov 07 04:52:56 2007 +0100
+++ b/dmd/optimize.c	Thu Nov 08 19:13:28 2007 +0100
@@ -284,7 +284,7 @@
 	if (fd)
 	{
 	    Expression *eresult = fd->interpret(NULL, arguments);
-	    if (eresult)
+	    if (eresult && eresult != EXP_VOID_INTERPRET)
 		e = eresult;
 	    else if (result & WANTinterpret)
 		error("cannot evaluate %s at compile time", toChars());
--- a/dmd/parse.c	Wed Nov 07 04:52:56 2007 +0100
+++ b/dmd/parse.c	Thu Nov 08 19:13:28 2007 +0100
@@ -2248,6 +2248,9 @@
 			    break;
 			continue;
 
+		    case TOKeof:
+			break;
+
 		    default:
 			continue;
 		}
@@ -2288,6 +2291,10 @@
 			nextToken();
 			break;
 
+		    case TOKeof:
+			error("found EOF instead of initializer");
+			break;
+
 		    default:
 			value = parseInitializer();
 			is->addInit(NULL, value);
--- a/dmd/statement.c	Wed Nov 07 04:52:56 2007 +0100
+++ b/dmd/statement.c	Thu Nov 08 19:13:28 2007 +0100
@@ -642,25 +642,18 @@
 }
 
 int UnrolledLoopStatement::fallOffEnd()
-{   int falloff = TRUE;
-
+{
     //printf("UnrolledLoopStatement::fallOffEnd()\n");
     for (size_t i = 0; i < statements->dim; i++)
     {	Statement *s = (Statement *)statements->data[i];
 
-	if (!s)
-	    continue;
-
-	if (!falloff && global.params.warnings && !s->comeFrom())
-	{
-	    fprintf(stdmsg, "warning - ");
-	    s->error("statement is not reachable");
-	}
-	falloff = s->fallOffEnd();
+	if (s)
+	    s->fallOffEnd();
     }
-    return falloff;
+    return TRUE;
 }
 
+
 int UnrolledLoopStatement::comeFrom()
 {   int comefrom = FALSE;
 
--- a/dmd/template.c	Wed Nov 07 04:52:56 2007 +0100
+++ b/dmd/template.c	Thu Nov 08 19:13:28 2007 +0100
@@ -75,6 +75,7 @@
     return (Tuple *)o;
 }
 
+
 /***********************
  * Try to get arg as a type.
  */
@@ -202,12 +203,15 @@
 
 void ObjectToCBuffer(OutBuffer *buf, HdrGenState *hgs, Object *oarg)
 {
+    //printf("ObjectToCBuffer()\n");
     Type *t = isType(oarg);
     Expression *e = isExpression(oarg);
     Dsymbol *s = isDsymbol(oarg);
     Tuple *v = isTuple(oarg);
     if (t)
+    {	//printf("\tt: %s ty = %d\n", t->toChars(), t->ty);
 	t->toCBuffer(buf, NULL, hgs);
+    }
     else if (e)
 	e->toCBuffer(buf, hgs);
     else if (s)
@@ -444,7 +448,7 @@
     int dedtypes_dim = dedtypes->dim;
 
 #if LOG
-    printf("+TemplateDeclaration::matchWithInstance(this = %p, ti = %p, flag = %d)\n", this, ti, flag);
+    printf("+TemplateDeclaration::matchWithInstance(this = %s, ti = %s, flag = %d)\n", toChars(), ti->toChars(), flag);
 #endif
 
 #if 0
@@ -486,13 +490,14 @@
 
 	//printf("\targument [%d]\n", i);
 #if 0
-	printf("\targument [%d] is %s\n", i, oarg ? oarg->toChars() : "null");
+	//printf("\targument [%d] is %s\n", i, oarg ? oarg->toChars() : "null");
 	TemplateTypeParameter *ttp = tp->isTemplateTypeParameter();
 	if (ttp)
 	    printf("\tparameter[%d] is %s : %s\n", i, tp->ident->toChars(), ttp->specType ? ttp->specType->toChars() : "");
 #endif
 
 	m2 = tp->matchArg(paramscope, ti->tiargs, i, parameters, dedtypes, &sparam);
+	//printf("\tm2 = %d\n", m2);
 
 	if (m2 == MATCHnomatch)
 	{
@@ -583,7 +588,7 @@
      * as td2.
      */
 
-    TemplateInstance ti(0, ident);		// create dummy template instance
+    TemplateInstance ti(0, ident);	// create dummy template instance
     Objects dedtypes;
 
 #define LOG_LEASTAS	0
@@ -803,12 +808,12 @@
 	    if (!m && fparam->type->toBasetype()->ty == Tdelegate)
 	    {
 		TypeDelegate *td = (TypeDelegate *)fparam->type->toBasetype();
-		TypeFunction *tf = (TypeFunction *)td->nextOf();
+		TypeFunction *tf = (TypeFunction *)td->next;
 
 		if (!tf->varargs && Argument::dim(tf->parameters) == 0)
 		{
-		    m = farg->type->deduceType(scope, tf->nextOf(), parameters, &dedtypes);
-		    if (!m && tf->nextOf()->toBasetype()->ty == Tvoid)
+		    m = farg->type->deduceType(scope, tf->next, parameters, &dedtypes);
+		    if (!m && tf->next->toBasetype()->ty == Tvoid)
 			m = MATCHconvert;
 		}
 		//printf("\tm2 = %d\n", m);
@@ -962,6 +967,15 @@
     return ::isVariadic(parameters);
 }
 
+/***********************************
+ * We can overload templates.
+ */
+
+int TemplateDeclaration::isOverloadable()
+{
+    return 1;
+}
+
 /*************************************************
  * Given function arguments, figure out which template function
  * to expand, and return that function.
@@ -1152,6 +1166,17 @@
  * Return -1 if not found.
  */
 
+int templateIdentifierLookup(Identifier *id, TemplateParameters *parameters)
+{
+    for (size_t i = 0; i < parameters->dim; i++)
+    {   TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+
+	if (tp->ident->equals(id))
+	    return i;
+    }
+    return -1;
+}
+
 int templateParameterLookup(Type *tparam, TemplateParameters *parameters)
 {
     assert(tparam->ty == Tident);
@@ -1159,14 +1184,7 @@
     //printf("\ttident = '%s'\n", tident->toChars());
     if (tident->idents.dim == 0)
     {
-	Identifier *id = tident->ident;
-
-	for (size_t i = 0; i < parameters->dim; i++)
-	{   TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
-
-	    if (tp->ident->equals(id))
-		return i;
-	}
+	return templateIdentifierLookup(tident->ident, parameters);
     }
     return -1;
 }
@@ -1268,7 +1286,32 @@
 	if (tparam->ty == Tsarray)
 	{
 	    TypeSArray *tp = (TypeSArray *)tparam;
-	    if (dim->toInteger() != tp->dim->toInteger())
+
+	    if (tp->dim->op == TOKvar &&
+		((VarExp *)tp->dim)->var->storage_class & STCtemplateparameter)
+	    {	int i = templateIdentifierLookup(((VarExp *)tp->dim)->var->ident, parameters);
+		// This code matches code in TypeInstance::deduceType()
+		if (i == -1)
+		    goto Lnomatch;
+		TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+		TemplateValueParameter *tvp = tp->isTemplateValueParameter();
+		if (!tvp)
+		    goto Lnomatch;
+		Expression *e = (Expression *)dedtypes->data[i];
+		if (e)
+		{
+		    if (!dim->equals(e))
+			goto Lnomatch;
+		}
+		else
+		{   Type *vt = tvp->valType->semantic(0, sc);
+		    MATCH m = (MATCH)dim->implicitConvTo(vt);
+		    if (!m)
+			goto Lnomatch;
+		    dedtypes->data[i] = dim;
+		}
+	    }
+	    else if (dim->toInteger() != tp->dim->toInteger())
 		return MATCHnomatch;
 	}
 	else if (tparam->ty == Taarray)
@@ -1321,9 +1364,11 @@
 
 MATCH TypeAArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes)
 {
-    //printf("TypeAArray::deduceType()\n");
-    //printf("\tthis   = %d, ", ty); print();
-    //printf("\ttparam = %d, ", tparam->ty); tparam->print();
+#if 0
+    printf("TypeAArray::deduceType()\n");
+    printf("\tthis   = %d, ", ty); print();
+    printf("\ttparam = %d, ", tparam->ty); tparam->print();
+#endif
 
     // Extra check that index type must match
     if (tparam && tparam->ty == Taarray)
@@ -1463,8 +1508,34 @@
 	//printf("tempinst->tempdecl = %p\n", tempinst->tempdecl);
 	//printf("tp->tempinst->tempdecl = %p\n", tp->tempinst->tempdecl);
 	if (!tp->tempinst->tempdecl)
-	{   if (!tp->tempinst->name->equals(tempinst->name))
-		goto Lnomatch;
+	{   //printf("tp->tempinst->name = '%s'\n", tp->tempinst->name->toChars());
+	    if (!tp->tempinst->name->equals(tempinst->name))
+	    {
+		/* Handle case of:
+		 *  template Foo(T : sa!(T), alias sa)
+		 */
+		int i = templateIdentifierLookup(tp->tempinst->name, parameters);
+		if (i == -1)
+		    goto Lnomatch;
+		TemplateParameter *tpx = (TemplateParameter *)parameters->data[i];
+		// This logic duplicates tpx->matchArg()
+		TemplateAliasParameter *ta = tpx->isTemplateAliasParameter();
+		if (!ta)
+		    goto Lnomatch;
+		Dsymbol *sa = tempinst->tempdecl;
+		if (!sa)
+		    goto Lnomatch;
+		if (ta->specAlias && sa != ta->specAlias)
+		    goto Lnomatch;
+		if (dedtypes->data[i])
+		{   // Must match already deduced symbol
+		    Dsymbol *s = (Dsymbol *)dedtypes->data[i];
+
+		    if (s != sa)
+			goto Lnomatch;
+		}
+		dedtypes->data[i] = sa;
+	    }
 	}
 	else if (tempinst->tempdecl != tp->tempinst->tempdecl)
 	    goto Lnomatch;
@@ -1830,6 +1901,7 @@
 	if (t)
 	{   // Must match already deduced type
 
+	    m = MATCHexact;
 	    if (!t->equals(ta))
 		goto Lnomatch;
 	}
@@ -2987,7 +3059,8 @@
 	}
 #if LOG
 	printf("It's an instance of '%s' kind '%s'\n", s->toChars(), s->kind());
-	printf("s->parent = '%s'\n", s->parent->toChars());
+	if (s->parent)
+	    printf("s->parent = '%s'\n", s->parent->toChars());
 #endif
 	withsym = scopesym->isWithScopeSymbol();
 
@@ -3092,12 +3165,14 @@
 	}
 
 	dedtypes.setDim(td->parameters->dim);
+	dedtypes.zero();
 	if (!td->scope)
 	{
 	    error("forward reference to template declaration %s", td->toChars());
 	    return NULL;
 	}
 	m = td->matchWithInstance(this, &dedtypes, 0);
+	//printf("m = %d\n", m);
 	if (!m)			// no match at all
 	    continue;
 
@@ -3757,6 +3832,8 @@
     argsym->parent = scy->parent;
     Scope *scope = scy->push(argsym);
 
+    unsigned errorsave = global.errors;
+
     // Declare each template parameter as an alias for the argument type
     declareParameters(scope);
 
@@ -3798,6 +3875,12 @@
 	semantic3(sc2);
     }
 
+    // Give additional context info if error occurred during instantiation
+    if (global.errors != errorsave)
+    {
+	error("error instantiating");
+    }
+
     sc2->pop();
 
     scope->pop();
--- a/dmd/template.h	Wed Nov 07 04:52:56 2007 +0100
+++ b/dmd/template.h	Thu Nov 08 19:13:28 2007 +0100
@@ -78,6 +78,7 @@
     TemplateDeclaration *isTemplateDeclaration() { return this; }
 
     TemplateTupleParameter *isVariadic();
+    int isOverloadable();
 };
 
 struct TemplateParameter
--- a/gen/toir.cpp	Wed Nov 07 04:52:56 2007 +0100
+++ b/gen/toir.cpp	Thu Nov 08 19:13:28 2007 +0100
@@ -66,7 +66,8 @@
                 //allocainst->setAlignment(vd->type->alignsize()); // TODO
                 vd->llvmValue = allocainst;
             }
-            DValue* ie = DtoInitializer(vd->init);
+            DVarValue* vv = new DVarValue(type, vd->llvmValue, true);
+            DValue* ie = DtoInitializer(vd->init, vv);
             delete ie;
         }
 
@@ -322,7 +323,7 @@
 {
     Logger::print("ComplexExp::toElem(): %s | %s\n", toChars(), type->toChars());
     LOG_SCOPE;
-    assert(0);
+    assert(0 && "no complex yet");
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
@@ -331,7 +332,7 @@
 {
     Logger::print("ComplexExp::toConstElem(): %s | %s\n", toChars(), type->toChars());
     LOG_SCOPE;
-    assert(0);
+    assert(0 && "no complex yet");
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
@@ -462,10 +463,14 @@
 
     p->exps.pop_back();
 
-    if (l->isArrayLen())
-        DtoResizeDynArray(l->getLVal(), r->getRVal());
-    else
-        DtoAssign(l, r);
+    DImValue* im = r->isIm();
+    if (!im || !im->inPlace()) {
+        if (l->isArrayLen())
+            DtoResizeDynArray(l->getLVal(), r->getRVal());
+        else
+            DtoAssign(l, r);
+    }
+
     return l;
 
     /*
@@ -639,19 +644,22 @@
 
     Type* t = DtoDType(type);
     Type* e1type = DtoDType(e1->type);
+    Type* e1next = e1type->next ? DtoDType(e1type->next) : NULL;
     Type* e2type = DtoDType(e2->type);
 
     if (e1type != e2type) {
-        if (e1type->ty == Tpointer && e1type->next->ty == Tstruct) {
+        if (e1type->ty == Tpointer && e1next && e1next->ty == Tstruct) {
+            Logger::println("add to AddrExp of struct");
             assert(r->isConst());
             llvm::ConstantInt* cofs = llvm::cast<llvm::ConstantInt>(r->isConst()->c);
 
-            TypeStruct* ts = (TypeStruct*)e1type->next;
+            TypeStruct* ts = (TypeStruct*)e1next;
             std::vector<unsigned> offsets;
             llvm::Value* v = DtoIndexStruct(l->getRVal(), ts->sym, t->next, cofs->getZExtValue(), offsets);
             return new DFieldValue(type, v, true);
         }
-        else if (e1->type->ty == Tpointer) {
+        else if (e1type->ty == Tpointer) {
+            Logger::println("add to AddrExp of struct");
             llvm::Value* v = new llvm::GetElementPtrInst(l->getRVal(), r->getRVal(), "tmp", p->scopebb());
             return new DImValue(type, v);
         }
@@ -2667,13 +2675,14 @@
     Logger::print("ArrayLiteralExp::toElem: %s | %s\n", toChars(), type->toChars());
     LOG_SCOPE;
 
-    const llvm::Type* t = DtoType(type);
+    Type* ty = DtoDType(type);
+    const llvm::Type* t = DtoType(ty);
     Logger::cout() << "array literal has llvm type: " << *t << '\n';
 
     llvm::Value* mem = 0;
     if (!p->topexp() || p->topexp()->e2 != this) {
         assert(DtoDType(type)->ty == Tsarray);
-        mem = new llvm::AllocaInst(t,"tmparrayliteral",p->topallocapoint());
+        mem = new llvm::AllocaInst(t,"arrayliteral",p->topallocapoint());
     }
     else if (p->topexp()->e2 == this) {
         DValue* tlv = p->topexp()->v;
@@ -2688,8 +2697,10 @@
         if (!llvm::isa<llvm::PointerType>(mem->getType()) ||
             !llvm::isa<llvm::ArrayType>(mem->getType()->getContainedType(0)))
         {
-            error("TODO array literals can currently only be used to initialise static arrays");
-            fatal();
+            assert(ty->ty == Tarray);
+            // we need to give this array literal storage
+            const llvm::ArrayType* arrty = llvm::ArrayType::get(DtoType(ty->next), elements->dim);
+            mem = new llvm::AllocaInst(arrty, "arrayliteral", p->topallocapoint());
         }
     }
     else
@@ -2703,7 +2714,14 @@
         new llvm::StoreInst(e->getRVal(), elemAddr, p->scopebb());
     }
 
-    return new DImValue(type, mem, true);
+    if (ty->ty == Tsarray)
+        return new DImValue(type, mem, true);
+    else if (ty->ty == Tarray)
+        return new DSliceValue(type, DtoConstSize_t(elements->dim), DtoGEPi(mem,0,0,"tmp"));
+    else {
+        assert(0);
+        return 0;
+    }
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
@@ -2897,6 +2915,7 @@
 //STUB(ArrayLiteralExp);
 STUB(AssocArrayLiteralExp);
 //STUB(StructLiteralExp);
+STUB(TupleExp);
 
 #define CONSTSTUB(x) llvm::Constant* x::toConstElem(IRState * p) {error("const Exp type "#x" not implemented: '%s' type: '%s'", toChars(), type->toChars()); fatal(); return NULL; }
 CONSTSTUB(Expression);
--- a/gen/tollvm.cpp	Wed Nov 07 04:52:56 2007 +0100
+++ b/gen/tollvm.cpp	Thu Nov 08 19:13:28 2007 +0100
@@ -795,12 +795,15 @@
 
 //////////////////////////////////////////////////////////////////////////////////////////
 
-DValue* DtoInitializer(Initializer* init)
+DValue* DtoInitializer(Initializer* init, DValue* v)
 {
     if (ExpInitializer* ex = init->isExpInitializer())
     {
         Logger::println("expression initializer");
+        assert(ex->exp);
+        if (v) gIR->exps.push_back(IRExp(NULL,ex->exp,v));
         return ex->exp->toElem(gIR);
+        if (v) gIR->exps.pop_back();
     }
     else if (init->isVoidInitializer())
     {
@@ -1226,6 +1229,7 @@
 
 void DtoAssign(DValue* lhs, DValue* rhs)
 {
+    Logger::cout() << "DtoAssign(...);\n";
     Type* t = DtoDType(lhs->getType());
     Type* t2 = DtoDType(rhs->getType());
 
@@ -1425,7 +1429,7 @@
     llvm::Value* cond = gIR->ir->CreateICmpEQ(gIR->ir->CreateLoad(gflag,"tmp"),DtoConstBool(false));
     gIR->ir->CreateCondBr(cond, initbb, endinitbb);
     gIR->scope() = IRScope(initbb,endinitbb);
-    DValue* ie = DtoInitializer(init);
+    DValue* ie = DtoInitializer(init, NULL);
     if (!ie->inPlace()) {
         DValue* dst = new DVarValue(t, gvar, true);
         DtoAssign(dst, ie);
--- a/gen/tollvm.h	Wed Nov 07 04:52:56 2007 +0100
+++ b/gen/tollvm.h	Thu Nov 08 19:13:28 2007 +0100
@@ -34,7 +34,7 @@
 void DtoInitClass(TypeClass* tc, llvm::Value* dst);
 
 llvm::Constant* DtoConstInitializer(Type* type, Initializer* init);
-elem* DtoInitializer(Initializer* init);
+DValue* DtoInitializer(Initializer* init, DValue* v);
 
 llvm::Function* LLVM_DeclareMemSet32();
 llvm::Function* LLVM_DeclareMemSet64();
--- a/lphobos/std/c/linux/socket.d	Wed Nov 07 04:52:56 2007 +0100
+++ b/lphobos/std/c/linux/socket.d	Thu Nov 08 19:13:28 2007 +0100
@@ -331,7 +331,7 @@
 }
 
 
-const in6_addr IN6ADDR_ANY;
+const in6_addr IN6ADDR_ANY = { s6_addr8: 0 };
 const in6_addr IN6ADDR_LOOPBACK = { s6_addr8: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] };
 //alias IN6ADDR_ANY IN6ADDR_ANY_INIT;
 //alias IN6ADDR_LOOPBACK IN6ADDR_LOOPBACK_INIT;
--- a/test/bug51.d	Wed Nov 07 04:52:56 2007 +0100
+++ b/test/bug51.d	Thu Nov 08 19:13:28 2007 +0100
@@ -1,26 +1,5 @@
 module bug51;
-
-import std.stdint;
-
-union in6_addr
-{
-    private union _in6_u_t
-    {
-        uint8_t[16] u6_addr8;
-        uint16_t[8] u6_addr16;
-        uint32_t[4] u6_addr32;
-    }
-    _in6_u_t in6_u;
-
-    uint8_t[16] s6_addr8;
-    uint16_t[8] s6_addr16;
-    uint32_t[4] s6_addr32;
-}
-
-
-const in6_addr IN6ADDR_ANY = { s6_addr8: [0] };
-const in6_addr IN6ADDR_LOOPBACK = { s6_addr8: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] };
-
-void main()
-{
-}
+const ubyte[3] arr1 = 0;
+const ubyte[3] arr2 = [0];
+const ubyte[3] arr3 = [0:1];
+void main() {}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/bug55.d	Thu Nov 08 19:13:28 2007 +0100
@@ -0,0 +1,20 @@
+module bug55;
+
+int atoi(char[] s) {
+    int i, fac=1;
+    bool neg = (s.length) && (s[0] == '-');
+    char[] a = neg ? s[1..$] : s;
+    foreach_reverse(c; a) {
+        i += (c-'0') * fac;
+        fac *= 10;
+    }
+    return !neg ? i : -i;
+}
+
+void main()
+{
+    printf("64213 = %d\n", atoi("64213"));
+    printf("-64213 = %d\n", atoi("-64213"));
+    assert(atoi("64213") == 64213);
+    assert(atoi("-64213") == -64213);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/bug56.d	Thu Nov 08 19:13:28 2007 +0100
@@ -0,0 +1,8 @@
+module bug56;
+
+void main()
+{
+    int[] a;
+    a = [1,2,3];
+    {int[] b = [4,5,6];}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/ray.d	Thu Nov 08 19:13:28 2007 +0100
@@ -0,0 +1,117 @@
+//import std.stdio, std.math, std.string;
+//import tools.base;
+
+int atoi(char[] s) {
+    int i, fac=1;
+    bool neg = (s.length) && (s[0] == '-');
+    char[] a = neg ? s[1..$] : s;
+    foreach_reverse(c; a) {
+        i += (c-'0') * fac;
+        fac *= 10;
+    }
+    return !neg ? i : -i;
+}
+
+pragma(LLVM_internal, "intrinsic", "llvm.sqrt.f64")
+double sqrt(double val);
+
+double delta;
+static this() { delta=sqrt(real.epsilon); }
+
+struct Vec {
+  double x, y, z;
+  Vec opAdd(ref Vec other) { return Vec(x+other.x, y+other.y, z+other.z); }
+  Vec opSub(ref Vec other) { return Vec(x-other.x, y-other.y, z-other.z); }
+  Vec opMul(double a) { return Vec(x*a, y*a, z*a); }
+  double dot(ref Vec other) { return x*other.x+y*other.y+z*other.z; }
+  Vec unitise() { return opMul(1.0/sqrt(dot(*this))); }
+}
+
+struct Pair(T, U) { T first; U second; }
+typedef Pair!(double, Vec) Hit;
+
+struct Ray { Vec orig, dir; }
+
+class Scene {
+  //abstract void intersect(ref Hit, ref Ray);
+  void intersect(ref Hit, ref Ray) {}
+}
+
+class Sphere : Scene {
+  Vec center;
+  double radius;
+  //mixin This!("center, radius");
+  this(ref Vec c, double r)
+  {
+    center = c;
+    radius = r;
+  }
+  double ray_sphere(ref Ray ray) {
+    auto v = center - ray.orig, b = v.dot(ray.dir), disc=b*b - v.dot(v) + radius*radius;
+    if (disc < 0) return double.infinity;
+    auto d = sqrt(disc), t2 = b + d;
+    if (t2 < 0) return double.infinity;
+    auto t1 = b - d;
+    return (t1 > 0 ? t1 : t2);
+  }
+  void intersect(ref Hit hit, ref Ray ray) {
+    auto lambda = ray_sphere(ray);
+    if (lambda < hit.first)
+      hit = Hit(lambda, (ray.orig + lambda*ray.dir - center).unitise);
+  }
+}
+
+class Group : Scene {
+  Sphere bound;
+  Scene[] children;
+  //mixin This!("bound, children");
+  this (Sphere s, Scene[] c)
+  {
+    bound = s;
+    children = c;
+  }
+  void intersect(ref Hit hit, ref Ray ray) {
+    auto l = bound.ray_sphere(ray);
+    if (l < hit.first) foreach (child; children) child.intersect(hit, ray);
+  }
+}
+
+double ray_trace(ref Vec light, ref Ray ray, Scene s) {
+  auto hit=Hit(double.infinity, Vec(0, 0, 0));
+  s.intersect(hit, ray);
+  if (hit.first == double.infinity) return 0.0;
+  auto g = hit.second.dot(light);
+  if (g >= 0) return 0.0;
+  auto p = ray.orig + ray.dir*hit.first + hit.second*delta;
+  auto hit2=Hit(double.infinity, Vec(0, 0, 0));
+  s.intersect(hit2, Ray(p, light*-1.0));
+  return (hit2.first < double.infinity ? 0 : -g);
+}
+
+Scene create(int level, ref Vec c, double r) {
+  auto s = new Sphere(c, r);
+  if (level == 1) return s;
+  Scene[] children=[s];
+  double rn = 3*r/sqrt(12.0);
+  for (int dz=-1; dz<=1; dz+=2)
+    for (int dx=-1; dx<=1; dx+=2)
+      children~=create(level-1, c + Vec(dx, 1, dz)*rn, r/2);
+  return new Group(new Sphere(c, 3*r), children);
+}
+
+void main(string[] args) {
+  int level = (args.length==3 ? args[1].atoi() : 9),
+    n = (args.length==3 ? args[2].atoi() : 512), ss = 4;
+  auto light = Vec(-1, -3, 2).unitise();
+  auto s=create(level, Vec(0, -1, 0), 1);
+  printf("P5\n%d %d\n255", n, n);
+  for (int y=n-1; y>=0; --y)
+    for (int x=0; x<n; ++x) {
+      double g=0;
+      for (int d=0; d<ss*ss; ++d) {
+        auto dir=Vec(x+(d%ss)*1.0/ss-n/2.0, y+(d/ss)*1.0/ss-n/2.0, n).unitise();
+    g += ray_trace(light, Ray(Vec(0, 0, -4), dir), s);
+      }
+      printf("%c", cast(ubyte)(0.5 + 255.0 * g / (ss*ss)));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sqrts.d	Thu Nov 08 19:13:28 2007 +0100
@@ -0,0 +1,12 @@
+module sqrts;
+
+import std.c.math;
+
+double sqrt(double d)
+{
+    return std.c.math.sqrt(d);
+}
+
+void main()
+{
+}