changeset 1640:9bf06e02070b

Merge DMD 1.057.
author Christian Kamm <kamm incasoftware de>
date Mon, 08 Mar 2010 21:39:20 +0100
parents 41145d30acb8
children 00cd99bedf06
files dmd/dsymbol.c dmd/dsymbol.h dmd/expression.c dmd/func.c dmd/inline.c dmd/interpret.c dmd/mars.c dmd/mars.h dmd/module.c dmd/module.h dmd/mtype.c dmd/root/root.c dmd/root/root.h dmd/scope.c dmd/scope.h dmd/statement.c dmd/template.c
diffstat 17 files changed, 348 insertions(+), 81 deletions(-) [+]
line wrap: on
line diff
--- a/dmd/dsymbol.c	Mon Mar 08 20:09:18 2010 +0100
+++ b/dmd/dsymbol.c	Mon Mar 08 21:39:20 2010 +0100
@@ -1,6 +1,6 @@
 
 // Compiler implementation of the D programming language
-// Copyright (c) 1999-2009 by Digital Mars
+// Copyright (c) 1999-2010 by Digital Mars
 // All Rights Reserved
 // written by Walter Bright
 // http://www.digitalmars.com
@@ -13,6 +13,7 @@
 #include <assert.h>
 
 #include "rmem.h"
+#include "speller.h"
 
 #include "mars.h"
 #include "dsymbol.h"
@@ -347,6 +348,27 @@
     return NULL;
 }
 
+/***************************************************
+ * Search for symbol with correct spelling.
+ */
+
+void *symbol_search_fp(void *arg, const char *seed)
+{
+    Dsymbol *s = (Dsymbol *)arg;
+    Identifier id(seed, 0);
+    Module::clearCache();
+    s = s->search(0, &id, 4|2);
+    return s;
+}
+
+Dsymbol *Dsymbol::search_correct(Identifier *ident)
+{
+    if (global.gag)
+	return NULL;		// don't do it for speculative compiles; too time consuming
+
+    return (Dsymbol *)speller(ident->toChars(), &symbol_search_fp, this, idchars);
+}
+
 /***************************************
  * Search for identifier id as a member of 'this'.
  * id may be a template instance.
--- a/dmd/dsymbol.h	Mon Mar 08 20:09:18 2010 +0100
+++ b/dmd/dsymbol.h	Mon Mar 08 21:39:20 2010 +0100
@@ -1,6 +1,6 @@
 
 // Compiler implementation of the D programming language
-// Copyright (c) 1999-2009 by Digital Mars
+// Copyright (c) 1999-2010 by Digital Mars
 // All Rights Reserved
 // written by Walter Bright
 // http://www.digitalmars.com
@@ -167,6 +167,7 @@
     virtual void semantic3(Scope *sc);
     virtual void inlineScan();
     virtual Dsymbol *search(Loc loc, Identifier *ident, int flags);
+    Dsymbol *search_correct(Identifier *id);
     Dsymbol *searchX(Loc loc, Scope *sc, Identifier *id);
     virtual int overloadInsert(Dsymbol *s);
 #ifdef _DH
--- a/dmd/expression.c	Mon Mar 08 20:09:18 2010 +0100
+++ b/dmd/expression.c	Mon Mar 08 21:39:20 2010 +0100
@@ -55,6 +55,7 @@
 #include "hdrgen.h"
 #include "parse.h"
 
+
 Expression *expandVar(int result, VarDeclaration *v);
 
 #define LOGSEMANTIC	0
@@ -1059,13 +1060,10 @@
 
 void Expression::warning(const char *format, ...)
 {
-    if (global.params.warnings && !global.gag)
-    {
-	va_list ap;
-	va_start(ap, format);
-	::vwarning(loc, format, ap);
-	va_end( ap );
-    }
+    va_list ap;
+    va_start(ap, format);
+    ::vwarning(loc, format, ap);
+    va_end( ap );
 }
 
 void Expression::rvalue()
@@ -1076,7 +1074,7 @@
 	dump(0);
 	halt();
 #endif
-	type = Type::tint32;
+	type = Type::terror;
     }
 }
 
@@ -1138,6 +1136,9 @@
 void Expression::toMangleBuffer(OutBuffer *buf)
 {
     error("expression %s is not a valid template value argument", toChars());
+#ifdef DEBUG
+dump(0);
+#endif
 }
 
 /***************************************
@@ -1666,7 +1667,18 @@
     if ((sinteger_t)value < 0)
 	buf->printf("N%jd", -value);
     else
+    {
+	/* This is an awful hack to maintain backwards compatibility.
+	 * There really always should be an 'i' before a number, but
+	 * there wasn't in earlier implementations, so to maintain
+	 * backwards compatibility it is only done if necessary to disambiguate.
+	 * See bugzilla 3029
+	 */
+	if (buf->offset > 0 && isdigit(buf->data[buf->offset - 1]))
+	    buf->writeByte('i');
+
 	buf->printf("%jd", value);
+    }
 }
 
 /******************************** ErrorExp **************************/
@@ -2103,7 +2115,21 @@
 	}
 	return e->semantic(sc);
     }
-    error("undefined identifier %s", ident->toChars());
+#if DMDV2
+    if (ident == Id::ctfe)
+    {  // Create the magic __ctfe bool variable
+       VarDeclaration *vd = new VarDeclaration(loc, Type::tbool, Id::ctfe, NULL);
+       Expression *e = new VarExp(loc, vd);
+       e = e->semantic(sc);
+       return e;
+    }
+#endif
+
+    s = sc->search_correct(ident);
+    if (s)
+	error("undefined identifier %s, did you mean %s %s?", ident->toChars(), s->kind(), s->toChars());
+    else
+	error("undefined identifier %s", ident->toChars());
     type = Type::terror;
     return this;
 }
@@ -5275,14 +5301,14 @@
 	goto Lerror;
     }
 
-    if (name != FileName::name(name))
-    {	error("use -Jpath switch to provide path for filename %s", name);
-	goto Lerror;
-    }
-
-    name = FileName::searchPath(global.filePath, name, 0);
+    /* Be wary of CWE-22: Improper Limitation of a Pathname to a Restricted Directory
+     * ('Path Traversal') attacks.
+     * http://cwe.mitre.org/data/definitions/22.html
+     */
+
+    name = FileName::safeSearchPath(global.filePath, name);
     if (!name)
-    {	error("file %s cannot be found, check -Jpath", se->toChars());
+    {	error("file %s cannot be found or not in a path specified with -J", se->toChars());
 	goto Lerror;
     }
 
@@ -5820,6 +5846,14 @@
 		    e = e->semantic(sc);
 		    return e;
 		}
+		if (v->init)
+		{   Expression *e = v->init->toExpression();
+		    if (e)
+		    {	e = e->copy();
+			e = e->semantic(sc);
+			return e;
+		    }
+		}
 	    }
 	}
     }
@@ -5941,11 +5975,15 @@
     e = e->semantic(sc);
     if (e->op == TOKdottd)
     {
+	if (global.errors)
+	    return new ErrorExp();	// TemplateInstance::semantic() will fail anyway
 	DotTemplateExp *dte = (DotTemplateExp *)e;
 	TemplateDeclaration *td = dte->td;
 	eleft = dte->e1;
 	ti->tempdecl = td;
 	ti->semantic(sc);
+	if (!ti->inst)			// if template failed to expand
+	    return new ErrorExp();
 	Dsymbol *s = ti->inst->toAlias();
 	Declaration *v = s->isDeclaration();
 	if (v)
@@ -7377,6 +7415,12 @@
 	    }
 	}
     }
+
+    if (!e1->type)
+    {	error("cannot cast %s", e1->toChars());
+	return new ErrorExp();
+    }
+
     e = e1->castTo(sc, to);
     return e;
 }
--- a/dmd/func.c	Mon Mar 08 20:09:18 2010 +0100
+++ b/dmd/func.c	Mon Mar 08 21:39:20 2010 +0100
@@ -640,15 +640,15 @@
 	    fdrequire = fd;
 	}
 
+	if (!outId && f->nextOf()->toBasetype()->ty != Tvoid)
+	    outId = Id::result;	// provide a default
+
 	if (fensure)
 	{   /*   out (result) { ... }
 	     * becomes:
 	     *   tret __ensure(ref tret result) { ... }
 	     *   __ensure(result);
 	     */
-	    if (!outId && f->nextOf()->toBasetype()->ty != Tvoid)
-		outId = Id::result;	// provide a default
-
 	    Loc loc = fensure->loc;
 	    Parameters *arguments = new Parameters();
 	    Parameter *a = NULL;
@@ -772,14 +772,14 @@
 	if (ad)
 	{   VarDeclaration *v;
 
-	    if (isFuncLiteralDeclaration() && isNested())
+	    if (isFuncLiteralDeclaration() && isNested() && !sc->intypeof)
 	    {
-		error("literals cannot be class members");
+		error("function literals cannot be class members");
 		return;
 	    }
 	    else
 	    {
-		assert(!isNested());	// can't be both member and nested
+		assert(!isNested() || sc->intypeof);	// can't be both member and nested
 		assert(ad->handle);
 		v = new ThisDeclaration(loc, ad->handle);
 		v->storage_class |= STCparameter | STCin;
@@ -2628,15 +2628,9 @@
 
 void FuncLiteralDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
 {
-    static Identifier *idfunc;
-    static Identifier *iddel;
-
-    if (!idfunc)
-	idfunc = new Identifier("function", 0);
-    if (!iddel)
-	iddel = new Identifier("delegate", 0);
-
-    type->toCBuffer(buf, ((tok == TOKdelegate) ? iddel : idfunc), hgs);
+    buf->writestring(kind());
+    buf->writeByte(' ');
+    type->toCBuffer(buf, NULL, hgs);
     bodyToCBuffer(buf, hgs);
 }
 
--- a/dmd/inline.c	Mon Mar 08 20:09:18 2010 +0100
+++ b/dmd/inline.c	Mon Mar 08 21:39:20 2010 +0100
@@ -1,5 +1,5 @@
 
-// Copyright (c) 1999-2009 by Digital Mars
+// Copyright (c) 1999-2010 by Digital Mars
 // All Rights Reserved
 // written by Walter Bright
 // http://www.digitalmars.com
@@ -292,6 +292,11 @@
 
 int CallExp::inlineCost(InlineCostState *ics)
 {
+    // Bugzilla 3500: super.func() calls must be devirtualized, and the inliner
+    // can't handle that at present.
+    if (e1->op == TOKdotvar && ((DotVarExp *)e1)->e1->op == TOKsuper)
+	return COST_MAX;
+
     return 1 + e1->inlineCost(ics) + arrayInlineCost(ics, arguments);
 }
 
--- a/dmd/interpret.c	Mon Mar 08 20:09:18 2010 +0100
+++ b/dmd/interpret.c	Mon Mar 08 21:39:20 2010 +0100
@@ -115,7 +115,8 @@
     assert(tb->ty == Tfunction);
     TypeFunction *tf = (TypeFunction *)tb;
     Type *tret = tf->next->toBasetype();
-    if (tf->varargs && arguments && parameters && arguments->dim != parameters->dim)
+    if (tf->varargs && arguments &&
+	((parameters && arguments->dim != parameters->dim) || (!parameters && arguments->dim)))
     {	cantInterpret = 1;
 	error("C-style variadic functions are not yet implemented in CTFE");
 	return NULL;
--- a/dmd/mars.c	Mon Mar 08 20:09:18 2010 +0100
+++ b/dmd/mars.c	Mon Mar 08 21:39:20 2010 +0100
@@ -61,9 +61,9 @@
     obj_ext_alt = "obj";
 #endif
 
-    copyright = "Copyright (c) 1999-2009 by Digital Mars and Tomas Lindquist Olsen";
+    copyright = "Copyright (c) 1999-2010 by Digital Mars and Tomas Lindquist Olsen";
     written = "written by Walter Bright and Tomas Lindquist Olsen";
-    version = "v1.056";
+    version = "v1.057";
     ldc_version = LDC_REV;
     llvm_version = LLVM_REV_STR;
     global.structalign = 8;
@@ -116,13 +116,10 @@
 
 void warning(Loc loc, const char *format, ...)
 {
-    if (global.params.warnings && !global.gag)
-    {
-        va_list ap;
-        va_start(ap, format);
-        vwarning(loc, format, ap);
-        va_end( ap );
-    }
+    va_list ap;
+    va_start(ap, format);
+    vwarning(loc, format, ap);
+    va_end( ap );
 }
 
 void verror(Loc loc, const char *format, va_list ap)
@@ -147,16 +144,26 @@
 {
     if (global.params.warnings && !global.gag)
     {
-        char *p = loc.toChars();
+	char *p = loc.toChars();
 
-        if (*p)
-            fprintf(stdmsg, "%s: ", p);
-        mem.free(p);
+	if (*p)
+	    fprintf(stdmsg, "%s: ", p);
+	mem.free(p);
 
-        fprintf(stdmsg, "Warning: ");
-        vfprintf(stdmsg, format, ap);
-        fprintf(stdmsg, "\n");
-        fflush(stdmsg);
+	fprintf(stdmsg, "Warning: ");
+#if _MSC_VER
+	// MS doesn't recognize %zu format
+	OutBuffer tmp;
+	tmp.vprintf(format, ap);
+	fprintf(stdmsg, "%s", tmp.toChars());
+#else
+	vfprintf(stdmsg, format, ap);
+#endif
+	fprintf(stdmsg, "\n");
+	fflush(stdmsg);
+//halt();
+	if (global.params.warnings == 1)
+	    global.warnings++;	// warnings don't count if gagged
     }
 }
 
@@ -184,6 +191,7 @@
 #endif
 }
 
+
 /***********************************
  * Parse and append contents of environment variable envvar
  * to argc and argv[].
--- a/dmd/mars.h	Mon Mar 08 20:09:18 2010 +0100
+++ b/dmd/mars.h	Mon Mar 08 21:39:20 2010 +0100
@@ -94,6 +94,7 @@
 #define STRUCTTHISREF DMDV2	// if 'this' for struct is a reference, not a pointer
 #define SNAN_DEFAULT_INIT DMDV2	// if floats are default initialized to signalling NaN
 #define SARRAYVALUE DMDV2	// static arrays are value types
+#define MODULEINFO_IS_STRUCT DMDV2   // if ModuleInfo is a struct rather than a class
 
 // Set if C++ mangling is done by the front end
 #define CPP_MANGLE (DMDV2 && (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS))
@@ -182,6 +183,8 @@
     bool useInline;     // inline expand functions
     bool warnings;      // enable warnings
     ubyte Dversion;	// D version number
+			// 1: warnings as errors
+			// 2: informational warnings (no errors)
     char safe;		// enforce safe memory model
 
     char *argv0;	// program name
@@ -283,7 +286,8 @@
 
     Param params;
     unsigned errors;	// number of errors reported so far
-    unsigned gag;	// !=0 means gag reporting of errors
+    unsigned warnings;	// number of warnings reported so far
+    unsigned gag;	// !=0 means gag reporting of errors & warnings
 
     Global();
 };
@@ -426,10 +430,9 @@
 
 
 void warning(Loc loc, const char *format, ...) IS_PRINTF(2);
-void vwarning(Loc loc, const char *format, va_list);
 void error(Loc loc, const char *format, ...) IS_PRINTF(2);
 void verror(Loc loc, const char *format, va_list);
-
+void vwarning(Loc loc, const char *format, va_list);
 #ifdef __GNUC__
 __attribute__((noreturn))
 #endif
--- a/dmd/module.c	Mon Mar 08 20:09:18 2010 +0100
+++ b/dmd/module.c	Mon Mar 08 21:39:20 2010 +0100
@@ -905,6 +905,7 @@
 
 int Module::needModuleInfo()
 {
+    //printf("needModuleInfo() %s, %d, %d\n", toChars(), needmoduleinfo, global.params.cov);
     return needmoduleinfo;
 }
 
@@ -943,6 +944,13 @@
     return Package::symtabInsert(s);
 }
 
+void Module::clearCache()
+{
+    for (int i = 0; i < amodules.dim; i++)
+    {	Module *m = (Module *)amodules.data[i];
+	m->searchCacheIdent = NULL;
+    }
+}
 
 /*******************************************
  * Can't run semantic on s now, try again later.
--- a/dmd/module.h	Mon Mar 08 20:09:18 2010 +0100
+++ b/dmd/module.h	Mon Mar 08 21:39:20 2010 +0100
@@ -154,6 +154,7 @@
     void deleteObjFile();
     void addDeferredSemantic(Dsymbol *s);
     static void runDeferredSemantic();
+    static void clearCache();
     int imports(Module *m);
 
     // Back end
--- a/dmd/mtype.c	Mon Mar 08 20:09:18 2010 +0100
+++ b/dmd/mtype.c	Mon Mar 08 21:39:20 2010 +0100
@@ -1,6 +1,6 @@
 
 // Compiler implementation of the D programming language
-// Copyright (c) 1999-2009 by Digital Mars
+// Copyright (c) 1999-2010 by Digital Mars
 // All Rights Reserved
 // written by Walter Bright
 // http://www.digitalmars.com
@@ -135,6 +135,10 @@
 #if DMDV2
     this->cto = NULL;
     this->ito = NULL;
+    this->sto = NULL;
+    this->scto = NULL;
+    this->wto = NULL;
+    this->swto = NULL;
 #endif
     this->pto = NULL;
     this->rto = NULL;
@@ -641,7 +645,7 @@
     else if (ident == Id::size)
     {
 	error(loc, ".size property should be replaced with .sizeof");
-	e = new IntegerExp(loc, size(loc), Type::tsize_t);
+	e = new ErrorExp();
     }
     else if (ident == Id::alignof)
     {
@@ -679,8 +683,16 @@
     }
     else
     {
-	error(loc, "no property '%s' for type '%s'", ident->toChars(), toChars());
-	e = new IntegerExp(loc, 1, Type::tint32);
+	Dsymbol *s = NULL;
+	if (ty == Tstruct || ty == Tclass || ty == Tenum || ty == Ttypedef)
+	    s = toDsymbol(NULL);
+	if (s)
+	    s = s->search_correct(ident);
+	if (s)
+	    error(loc, "no property '%s' for type '%s', did you mean '%s'?", ident->toChars(), toChars(), s->toChars());
+	else
+	    error(loc, "no property '%s' for type '%s'", ident->toChars(), toChars());
+	e = new ErrorExp();
     }
     return e;
 }
@@ -785,13 +797,10 @@
 
 void Type::warning(Loc loc, const char *format, ...)
 {
-    if (global.params.warnings && !global.gag)
-    {
-	va_list ap;
-	va_start(ap, format);
-	::vwarning(loc, format, ap);
-	va_end( ap );
-    }
+    va_list ap;
+    va_start(ap, format);
+    ::vwarning(loc, format, ap);
+    va_end( ap );
 }
 
 Identifier *Type::getTypeInfoIdent(int internal)
@@ -4630,7 +4639,11 @@
     TemplateInstance *ti = s->isTemplateInstance();
     if (ti)
     {	if (!ti->semanticRun)
+	{
+	    if (global.errors)
+		return new ErrorExp();	// TemplateInstance::semantic() will fail anyway
 	    ti->semantic(sc);
+	}
 	s = ti->inst->toAlias();
 	if (!s->isTemplateInstance())
 	    goto L1;
@@ -5071,7 +5084,11 @@
     TemplateInstance *ti = s->isTemplateInstance();
     if (ti)
     {	if (!ti->semanticRun)
+	{
+	    if (global.errors)
+		return new ErrorExp();	// TemplateInstance::semantic() will fail anyway
 	    ti->semantic(sc);
+	}
 	s = ti->inst->toAlias();
 	if (!s->isTemplateInstance())
 	    goto L1;
--- a/dmd/root/root.c	Mon Mar 08 20:09:18 2010 +0100
+++ b/dmd/root/root.c	Mon Mar 08 21:39:20 2010 +0100
@@ -1,8 +1,8 @@
 
-// Copyright (c) 1999-2009 by Digital Mars
+// Copyright (c) 1999-2010 by Digital Mars
 // All Rights Reserved
 // written by Walter Bright
-// www.digitalmars.com
+// 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.
@@ -14,6 +14,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
+#include <limits.h>
 #include <string.h>
 #include <stdint.h>
 #include <assert.h>
@@ -819,6 +820,91 @@
     return NULL;
 }
 
+
+/*************************************
+ * Search Path for file in a safe manner.
+ *
+ * Be wary of CWE-22: Improper Limitation of a Pathname to a Restricted Directory
+ * ('Path Traversal') attacks.
+ *	http://cwe.mitre.org/data/definitions/22.html
+ * More info:
+ *	https://www.securecoding.cert.org/confluence/display/seccode/FIO02-C.+Canonicalize+path+names+originating+from+untrusted+sources
+ * Returns:
+ *	NULL	file not found
+ *	!=NULL	mem.malloc'd file name
+ */
+
+char *FileName::safeSearchPath(Array *path, const char *name)
+{
+#if _WIN32
+    /* Disallow % / \ : and .. in name characters
+     */
+    for (const char *p = name; *p; p++)
+    {
+	char c = *p;
+	if (c == '\\' || c == '/' || c == ':' || c == '%' ||
+	    (c == '.' && p[1] == '.'))
+	{
+	    return NULL;
+	}
+    }
+
+    return FileName::searchPath(path, name, 0);
+#elif POSIX
+    /* Even with realpath(), we must check for // and disallow it
+     */
+    for (const char *p = name; *p; p++)
+    {
+	char c = *p;
+	if (c == '/' && p[1] == '/')
+	{
+	    return NULL;
+	}
+    }
+
+    if (path)
+    {	unsigned i;
+
+	/* Each path is converted to a cannonical name and then a check is done to see
+	 * that the searched name is really a child one of the the paths searched.
+	 */
+	for (i = 0; i < path->dim; i++)
+	{
+	    char *cname = NULL;
+	    char *cpath = canonicalName((char *)path->data[i]);
+	    //printf("FileName::safeSearchPath(): name=%s; path=%s; cpath=%s\n",
+	    //	    name, (char *)path->data[i], cpath);
+	    if (cpath == NULL)
+		goto cont;
+	    cname = canonicalName(combine(cpath, name));
+	    //printf("FileName::safeSearchPath(): cname=%s\n", cname);
+	    if (cname == NULL)
+		goto cont;
+	    //printf("FileName::safeSearchPath(): exists=%i "
+	    //	    "strncmp(cpath, cname, %i)=%i\n", exists(cname),
+	    //	    strlen(cpath), strncmp(cpath, cname, strlen(cpath)));
+	    // exists and name is *really* a "child" of path
+	    if (exists(cname) && strncmp(cpath, cname, strlen(cpath)) == 0)
+	    {
+		free(cpath);
+		char *p = mem.strdup(cname);
+		free(cname);
+		return p;
+	    }
+cont:
+	    if (cpath)
+		free(cpath);
+	    if (cname)
+		free(cname);
+	}
+    }
+    return NULL;
+#else
+    assert(0);
+#endif
+}
+
+
 int FileName::exists(const char *name)
 {
 #if POSIX
@@ -886,6 +972,52 @@
     }
 }
 
+
+/******************************************
+ * Return canonical version of name in a malloc'd buffer.
+ * This code is high risk.
+ */
+char *FileName::canonicalName(const char *name)
+{
+#if linux
+    // Lovely glibc extension to do it for us
+    return canonicalize_file_name(name);
+#elif POSIX
+  #if _POSIX_VERSION >= 200809L || defined (linux)
+    // NULL destination buffer is allowed and preferred
+    return realpath(name, NULL);
+  #else
+    char *cname = NULL;
+    #if PATH_MAX
+	/* PATH_MAX must be defined as a constant in <limits.h>,
+	 * otherwise using it is unsafe due to TOCTOU
+	 */
+	size_t path_max = (size_t)PATH_MAX;
+	if (path_max > 0)
+	{
+	    /* Need to add one to PATH_MAX because of realpath() buffer overflow bug:
+	     * http://isec.pl/vulnerabilities/isec-0011-wu-ftpd.txt
+	     */
+	    cname = (char *)malloc(path_max + 1);
+	    if (cname == NULL)
+		return NULL;
+	}
+    #endif
+    return realpath(name, cname);
+  #endif
+#elif _WIN32
+    /* Apparently, there is no good way to do this on Windows.
+     * GetFullPathName isn't it.
+     */
+    assert(0);
+    return NULL;
+#else
+    assert(0);
+    return NULL;
+#endif
+}
+
+
 /****************************** File ********************************/
 
 File::File(FileName *n)
--- a/dmd/root/root.h	Mon Mar 08 20:09:18 2010 +0100
+++ b/dmd/root/root.h	Mon Mar 08 21:39:20 2010 +0100
@@ -1,9 +1,9 @@
 
 
-// Copyright (c) 1999-2006 by Digital Mars
+// Copyright (c) 1999-2010 by Digital Mars
 // All Rights Reserved
 // written by Walter Bright
-// www.digitalmars.com
+// 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.
@@ -156,8 +156,10 @@
 
     void CopyTo(FileName *to);
     static char *searchPath(Array *path, const char *name, int cwd);
+    static char *safeSearchPath(Array *path, const char *name);
     static int exists(const char *name);
     static void ensurePathExists(const char *path);
+    static char *canonicalName(const char *name);
 };
 
 struct File : Object
--- a/dmd/scope.c	Mon Mar 08 20:09:18 2010 +0100
+++ b/dmd/scope.c	Mon Mar 08 21:39:20 2010 +0100
@@ -1,5 +1,5 @@
 
-// Copyright (c) 1999-2005 by Digital Mars
+// Copyright (c) 1999-2010 by Digital Mars
 // All Rights Reserved
 // written by Walter Bright
 // http://www.digitalmars.com
@@ -11,6 +11,7 @@
 #include <assert.h>
 
 #include "root.h"
+#include "speller.h"
 
 #include "mars.h"
 #include "init.h"
@@ -361,3 +362,27 @@
 	    //assert(0);
     }
 }
+
+
+/************************************************
+ * Given the failed search attempt, try to find
+ * one with a close spelling.
+ */
+
+void *scope_search_fp(void *arg, const char *seed)
+{
+    //printf("scope_search_fp('%s')\n", seed);
+    Scope *sc = (Scope *)arg;
+    Identifier id(seed, 0);
+    Module::clearCache();
+    Dsymbol *s = sc->search(0, &id, NULL);
+    return s;
+}
+
+Dsymbol *Scope::search_correct(Identifier *ident)
+{
+    if (global.gag)
+	return NULL;		// don't do it for speculative compiles; too time consuming
+
+    return (Dsymbol *)speller(ident->toChars(), &scope_search_fp, this, idchars);
+}
--- a/dmd/scope.h	Mon Mar 08 20:09:18 2010 +0100
+++ b/dmd/scope.h	Mon Mar 08 21:39:20 2010 +0100
@@ -116,6 +116,7 @@
     void mergeCallSuper(Loc loc, unsigned cs);
 
     Dsymbol *search(Loc loc, Identifier *ident, Dsymbol **pscopesym);
+    Dsymbol *search_correct(Identifier *ident);
     Dsymbol *insert(Dsymbol *s);
 
     ClassDeclaration *getClassScope();
--- a/dmd/statement.c	Mon Mar 08 20:09:18 2010 +0100
+++ b/dmd/statement.c	Mon Mar 08 21:39:20 2010 +0100
@@ -1,6 +1,6 @@
 
 // Compiler implementation of the D programming language
-// Copyright (c) 1999-2009 by Digital Mars
+// Copyright (c) 1999-2010 by Digital Mars
 // All Rights Reserved
 // written by Walter Bright
 // http://www.digitalmars.com
@@ -101,13 +101,10 @@
 
 void Statement::warning(const char *format, ...)
 {
-    if (global.params.warnings && !global.gag)
-    {
-	va_list ap;
-	va_start(ap, format);
-	::vwarning(loc, format, ap);
-	va_end( ap );
-    }
+    va_list ap;
+    va_start(ap, format);
+    ::vwarning(loc, format, ap);
+    va_end( ap );
 }
 
 int Statement::hasBreak()
@@ -737,6 +734,7 @@
 	Statement *s = (Statement *) statements->data[i];
 	if (s)
 	{
+	    //printf("[%d]: %s\n", i, s->toChars());
 	    s = s->semantic(scd);
 	    statements->data[i] = s;
 	}
@@ -798,6 +796,7 @@
     return result;
 }
 
+
 int UnrolledLoopStatement::comeFrom()
 {   int comefrom = FALSE;
 
@@ -3466,7 +3465,6 @@
 	Statement *s = new ExpStatement(loc, exp);
 	exp = NULL;
 	s = s->semantic(sc);
-	loc = 0;
 	return new CompoundStatement(loc, s, this);
     }
 
--- a/dmd/template.c	Mon Mar 08 20:09:18 2010 +0100
+++ b/dmd/template.c	Mon Mar 08 21:39:20 2010 +0100
@@ -3701,7 +3701,12 @@
 	id = name;
 	s = sc->search(loc, id, &scopesym);
 	if (!s)
-	{   error("template '%s' is not defined", id->toChars());
+	{
+	    s = sc->search_correct(id);
+	    if (s)
+		error("template '%s' is not defined, did you mean %s?", id->toChars(), s->toChars());
+	    else
+		error("template '%s' is not defined", id->toChars());
 	    return NULL;
 	}
 #if LOG