diff dmd/Module.d @ 0:10317f0c89a5

Initial commit
author korDen
date Sat, 24 Oct 2009 08:42:06 +0400
parents
children 7427ded8caf7
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/Module.d	Sat Oct 24 08:42:06 2009 +0400
@@ -0,0 +1,1564 @@
+module dmd.Module;
+
+import dmd.Package;
+import dmd.DsymbolTable;
+import dmd.backend.TYM;
+import dmd.Array;
+import dmd.StaticDtorDeclaration;
+import dmd.Scope;
+import dmd.Id;
+import dmd.Import;
+import dmd.ClassDeclaration;
+import dmd.ModuleDeclaration;
+import dmd.File;
+import dmd.Identifier;
+import dmd.Dsymbol;
+import dmd.ModuleInfoDeclaration;
+import dmd.FuncDeclaration;
+import dmd.Loc;
+import dmd.Macro;
+import dmd.Escape;
+import dmd.OutBuffer;
+import dmd.HdrGenState;
+import dmd.ArrayTypes;
+import dmd.FileName;
+import dmd.Global;
+import dmd.Parser;
+import dmd.Lexer;
+import dmd.Util;
+import dmd.String;
+import dmd.ScopeDsymbol;
+import dmd.Type;
+import dmd.backend.TYPE;
+import dmd.backend.Cstate;
+import dmd.backend.OPER;
+import dmd.backend.REG;
+import dmd.backend.Symbol;
+import dmd.backend.elem;
+import dmd.backend.mTYman;
+import dmd.backend.Util;
+import dmd.backend.SC;
+import dmd.backend.FL;
+import dmd.backend.SFL;
+import dmd.backend.TF;
+import dmd.backend.RTLSYM;
+import dmd.backend.BC;
+import dmd.backend.block;
+import dmd.backend.targ_types;
+import dmd.backend.dt_t;
+import dmd.backend.TYM;
+import dmd.backend.Util;
+import dmd.backend.Classsym;
+import dmd.backend.glue;
+import dmd.backend.LIST;
+import dmd.codegen.Util;
+
+import core.stdc.string;
+import core.stdc.stdlib;
+
+uint readwordLE(ushort* p)
+{
+version (__I86__) {
+    return *p;
+} else {
+    return ((cast(ubyte*)p)[1] << 8) | (cast(ubyte*)p)[0];
+}
+}
+
+uint readwordBE(ushort* p)
+{
+    return ((cast(ubyte*)p)[0] << 8) | (cast(ubyte*)p)[1];
+}
+
+uint readlongLE(uint* p)
+{
+version (__I86__) {
+    return *p;
+} else {
+    return (cast(ubyte*)p)[0] |
+	((cast(ubyte*)p)[1] << 8) |
+	((cast(ubyte*)p)[2] << 16) |
+	((cast(ubyte*)p)[3] << 24);
+}
+}
+
+uint readlongBE(uint* p)
+{
+    return (cast(ubyte*)p)[3] |
+	((cast(ubyte*)p)[2] << 8) |
+	((cast(ubyte*)p)[1] << 16) |
+	((cast(ubyte*)p)[0] << 24);
+}
+
+/* Segments	*/
+enum Segment {
+	CODE = 1,	/* code segment			*/
+	DATA = 2,	/* initialized data		*/
+	CDATA = 3,	/* constant data		*/
+	UDATA = 4,	/* uninitialized data		*/
+	UNKNOWN	= -1,	/* unknown segment		*/
+}
+
+struct seg_data 
+{
+    int              SDseg;		// omf file segment index
+    targ_size_t		 SDoffset;	// starting offset for data
+
+    bool isfarseg;
+    int seg;				// segment number
+    int lnameidx;			// lname idx of segment name
+    int classidx;			// lname idx of class name
+    uint attr;			// segment attribute
+    targ_size_t origsize;		// original size
+    int seek;				// seek position in output file
+}
+
+extern (C) extern __gshared seg_data** SegData;
+
+ref targ_size_t Offset(Segment seg) {
+	return SegData[seg].SDoffset;
+}
+
+ref targ_size_t Doffset() {
+	return SegData[Segment.DATA].SDoffset;
+}
+
+ref targ_size_t CDoffset() {
+	return SegData[Segment.CDATA].SDoffset;
+}
+
+ref targ_size_t UDoffset() {
+	return SegData[Segment.UDATA].SDoffset;
+}
+
+enum CF {
+	CFes	        = 1,	// generate an ES: segment override for this instr
+	CFjmp16	        =  2,	// need 16 bit jump offset (long branch)
+	CFtarg	        =  4,	// this code is the target of a jump
+	CFseg	        =  8,	// get segment of immediate value
+	CFoff	       = 0x10,	// get offset of immediate value
+	CFss	       = 0x20,	// generate an SS: segment override (not with
+			// CFes at the same time, though!)
+	CFpsw	       = 0x40,	// we need the flags result after this instruction
+	CFopsize       = 0x80,	// prefix with operand size
+	CFaddrsize    = 0x100, 	// prefix with address size
+	CFds	      = 0x200,	// need DS override (not with es, ss, or cs )	
+	CFcs	      = 0x400,	// need CS override
+	CFfs	      = 0x800,	// need FS override
+	CFgs	= (CFcs | CFfs),	// need GS override
+	CFwait      = 0x1000,	// If I32 it indicates when to output a WAIT
+	CFselfrel   = 0x2000, 	// if self-relative
+	CFunambig   = 0x4000,    	// indicates cannot be accessed by other addressing
+				// modes
+	CFtarg2	    = 0x8000,	// like CFtarg, but we can't optimize this away
+	CFvolatile  = 0x10000,	// volatile reference, do not schedule
+	CFclassinit = 0x20000,	// class init code
+
+	CFSEG	= (CFes | CFss | CFds | CFcs | CFfs | CFgs),
+	CFPREFIX = (CFSEG | CFopsize | CFaddrsize),
+}
+
+class Module : Package
+{
+    static Module rootModule;
+    static DsymbolTable modules;	// symbol table of all modules
+    static Array amodules;		// array of all modules
+    static Array deferred;	// deferred Dsymbol's needing semantic() run on them
+    static uint dprogress;	// progress resolving the deferred list
+
+    static void init()
+	{
+		modules = new DsymbolTable();
+		amodules = new Array();
+		deferred = new Array();
+	}
+
+    static ClassDeclaration moduleinfo;
+
+
+    string arg;	// original argument name
+    ModuleDeclaration md; // if !null, the contents of the ModuleDeclaration declaration
+    File srcfile;	// input source file
+    File objfile;	// output .obj file
+    File hdrfile;	// 'header' file
+    File symfile;	// output symbol file
+    File docfile;	// output documentation file
+    uint errors;	// if any errors in file
+    uint numlines;	// number of lines in source file
+    int isHtml;		// if it is an HTML file
+    int isDocFile;	// if it is a documentation input file, not D source
+    int needmoduleinfo; /// TODO: change to bool
+version (IN_GCC) {
+    int strictlyneedmoduleinfo;
+}
+
+    int selfimports;		// 0: don't know, 1: does not, 2: does
+    int selfImports()		// returns !=0 if module imports itself
+	{
+		assert(false);
+	}
+
+    int insearch;
+    Identifier searchCacheIdent;
+    Dsymbol searchCacheSymbol;	// cached value of search
+    int searchCacheFlags;	// cached flags
+
+    int semanticstarted;	// has semantic() been started?
+    int semanticRun;		// has semantic() been done?
+    int root;			// != 0 if this is a 'root' module,
+				// i.e. a module that will be taken all the
+				// way to an object file
+    Module importedFrom;	// module from command line we're imported from,
+				// i.e. a module that will be taken all the
+				// way to an object file
+
+    Array decldefs;		// top level declarations for this Module
+
+    Array aimports;		// all imported modules
+
+    ModuleInfoDeclaration vmoduleinfo;
+
+    uint debuglevel;	// debug level
+    Array debugids;		// debug identifiers
+    Array debugidsNot;		// forward referenced debug identifiers
+
+    uint versionlevel;	// version level
+    Array versionids;		// version identifiers
+    Array versionidsNot;	// forward referenced version identifiers
+
+    Macro macrotable;		// document comment macros
+    Escape escapetable;	// document comment escapes
+    bool safe;			// TRUE if module is marked as 'safe'
+
+    this(string filename, Identifier ident, int doDocComment, int doHdrGen)
+	{
+		super(ident);
+		FileName objfilename;
+		
+		aimports = new Array();
+
+	    //writef("Module.Module(filename = '%s', ident = '%s')\n", filename, ident.toChars());
+		this.arg = filename;
+
+		FileName srcfilename = FileName.defaultExt(filename, global.mars_ext);
+		if (!srcfilename.equalsExt(global.mars_ext) &&
+			!srcfilename.equalsExt(global.hdr_ext) &&
+			!srcfilename.equalsExt("dd"))
+		{
+			if (srcfilename.equalsExt("html") ||
+				srcfilename.equalsExt("htm")  ||
+				srcfilename.equalsExt("xhtml"))
+			{
+				if (!global.params.useDeprecated)
+					error("html source files is deprecated %s", srcfilename.toChars());
+				isHtml = 1;
+			}
+			else
+			{
+				error("source file name '%s' must have .%s extension", srcfilename.toChars(), global.mars_ext);
+				fatal();
+			}
+		}
+
+		string argobj;
+		if (global.params.objname)
+			argobj = global.params.objname;
+		else if (global.params.preservePaths)
+			argobj = filename;
+		else
+			argobj = FileName.name(filename);
+		if (!FileName.absolute(argobj))
+		{
+			argobj = FileName.combine(global.params.objdir, argobj);
+		}
+
+		if (global.params.objname)
+			objfilename = new FileName(argobj);
+		else
+			objfilename = FileName.forceExt(argobj, global.obj_ext);
+
+		FileName symfilename = FileName.forceExt(filename, global.sym_ext);
+
+		srcfile = new File(srcfilename);
+
+		if (doDocComment) {
+			setDocfile();
+		}
+
+		if (doHdrGen) {
+			setHdrfile();
+		}
+
+		objfile = new File(objfilename);
+		symfile = new File(symfilename);
+	}
+
+    static Module load(Loc loc, Array packages, Identifier ident)
+	{
+		Module m;
+		string filename;
+
+		//writef("Module.load(ident = '%s')\n", ident.toChars());
+
+		// Build module filename by turning:
+		//	foo.bar.baz
+		// into:
+		//	foo\bar\baz
+		filename = ident.toChars();
+		if (packages && packages.dim)
+		{
+			scope OutBuffer buf = new OutBuffer();
+			int i;
+
+			for (i = 0; i < packages.dim; i++)
+			{   
+				Identifier pid = cast(Identifier)packages.data[i];
+
+				buf.writestring(pid.toChars());
+version (_WIN32) {
+				buf.writeByte('\\');
+} else {
+				buf.writeByte('/');
+}
+			}
+			buf.writestring(filename);
+			filename = buf.extractString();
+		}
+
+		m = new Module(filename, ident, 0, 0);
+		m.loc = loc;
+
+		/* Search along global.path for .di file, then .d file.
+		 */
+		string result = null;
+		FileName fdi = FileName.forceExt(filename, global.hdr_ext);
+		FileName fd  = FileName.forceExt(filename, global.mars_ext);
+		string sdi = fdi.toChars();
+		string sd  = fd.toChars();
+		
+		if (FileName.exists(sdi)) {
+			result = sdi;
+		} else if (FileName.exists(sd)) {
+			result = sd;
+		} else if (FileName.absolute(filename)) {
+			;
+		}
+		else
+		{
+			foreach (p; global.path)
+			{
+				string n = FileName.combine(p, sdi);
+
+				if (FileName.exists(n))
+				{
+					result = n;
+					break;
+				}
+
+				n = FileName.combine(p, sd);
+				if (FileName.exists(n))
+				{
+					result = n;
+					break;
+				}
+			}
+		}
+
+		if (result)
+			m.srcfile = new File(result);
+
+		if (global.params.verbose)
+		{
+			writef("import    ");
+			if (packages)
+			{
+				for (size_t i = 0; i < packages.dim; i++)
+				{   
+					Identifier pid = cast(Identifier)packages.data[i];
+					writef("%s.", pid.toChars());
+				}
+			}
+			writef("%s\t(%s)\n", ident.toChars(), m.srcfile.toChars());
+		}
+
+		m.read(loc);
+		m.parse();
+
+version (IN_GCC) {
+		d_gcc_magic_module(m);
+}
+
+		return m;
+	}
+
+    void toCBuffer(OutBuffer buf, HdrGenState* hgs)
+	{
+		assert(false);
+	}
+	
+    string kind()
+	{
+		return "module";
+	}
+	
+    void setDocfile()	// set docfile member
+	{
+		assert(false);
+	}
+	
+    void read(Loc loc)	// read file
+	{
+		//writef("Module.read('%s') file '%s'\n", toChars(), srcfile.toChars());
+		if (srcfile.read())
+		{
+			error(loc, "cannot read file '%s'", srcfile.toChars());
+			fatal();
+		}
+	}
+	
+version (IN_GCC) {
+    void parse(bool dump_source = false)	// syntactic parse
+	{
+		assert(false);
+	}
+} else {
+    void parse()	// syntactic parse
+	{
+		uint le;
+		uint bom;
+
+		//printf("Module.parse()\n");
+
+		string srcname = srcfile.name.toChars();
+		//printf("Module.parse(srcname = '%s')\n", srcname);
+
+		ubyte* buf = srcfile.buffer;
+		uint buflen = srcfile.len;
+
+		if (buflen >= 2)
+		{
+		/* Convert all non-UTF-8 formats to UTF-8.
+		 * BOM : http://www.unicode.org/faq/utf_bom.html
+		 * 00 00 FE FF	UTF-32BE, big-endian
+		 * FF FE 00 00	UTF-32LE, little-endian
+		 * FE FF	UTF-16BE, big-endian
+		 * FF FE	UTF-16LE, little-endian
+		 * EF BB BF	UTF-8
+		 */
+
+		bom = 1;		// assume there's a BOM
+		if (buf[0] == 0xFF && buf[1] == 0xFE)
+		{
+			if (buflen >= 4 && buf[2] == 0 && buf[3] == 0)
+			{	// UTF-32LE
+			le = 1;
+
+			Lutf32:
+			OutBuffer dbuf;
+			uint* pu = cast(uint*)buf;
+			uint* pumax = &pu[buflen / 4];
+
+			if (buflen & 3)
+			{   error("odd length of UTF-32 char source %u", buflen);
+				fatal();
+			}
+
+			dbuf.reserve(buflen / 4);
+			for (pu += bom; pu < pumax; pu++)
+			{  
+				uint u = le ? readlongLE(pu) : readlongBE(pu);
+				if (u & ~0x7F)
+				{
+					if (u > 0x10FFFF)
+					{   error("UTF-32 value %08x greater than 0x10FFFF", u);
+						fatal();
+					}
+					dbuf.writeUTF8(u);
+				}
+				else
+					dbuf.writeByte(u);
+			}
+			dbuf.writeByte(0);		// add 0 as sentinel for scanner
+			buflen = dbuf.offset - 1;	// don't include sentinel in count
+			buf = cast(ubyte*) dbuf.extractData();
+			}
+			else
+			{   
+				// UTF-16LE (X86)
+				// Convert it to UTF-8
+				le = 1;
+
+				Lutf16:
+				OutBuffer dbuf;
+				ushort* pu = cast(ushort*)(buf);
+				ushort *pumax = &pu[buflen / 2];
+
+				if (buflen & 1)
+				{   error("odd length of UTF-16 char source %u", buflen);
+					fatal();
+				}
+
+				dbuf.reserve(buflen / 2);
+				for (pu += bom; pu < pumax; pu++)
+				{
+					uint u = le ? readwordLE(pu) : readwordBE(pu);
+					if (u & ~0x7F)
+					{
+						if (u >= 0xD800 && u <= 0xDBFF)
+						{   uint u2;
+
+							if (++pu > pumax)
+							{   error("surrogate UTF-16 high value %04x at EOF", u);
+							fatal();
+							}
+							u2 = le ? readwordLE(pu) : readwordBE(pu);
+							if (u2 < 0xDC00 || u2 > 0xDFFF)
+							{   error("surrogate UTF-16 low value %04x out of range", u2);
+							fatal();
+							}
+							u = (u - 0xD7C0) << 10;
+							u |= (u2 - 0xDC00);
+						}
+						else if (u >= 0xDC00 && u <= 0xDFFF)
+						{
+							error("unpaired surrogate UTF-16 value %04x", u);
+							fatal();
+						}
+						else if (u == 0xFFFE || u == 0xFFFF)
+						{
+							error("illegal UTF-16 value %04x", u);
+							fatal();
+						}
+						dbuf.writeUTF8(u);
+					}
+					else
+						dbuf.writeByte(u);
+				}
+				dbuf.writeByte(0);		// add 0 as sentinel for scanner
+				buflen = dbuf.offset - 1;	// don't include sentinel in count
+				buf = cast(ubyte*) dbuf.extractData();
+			}
+		}
+		else if (buf[0] == 0xFE && buf[1] == 0xFF)
+		{   // UTF-16BE
+			le = 0;
+			goto Lutf16;
+		}
+		else if (buflen >= 4 && buf[0] == 0 && buf[1] == 0 && buf[2] == 0xFE && buf[3] == 0xFF)
+		{   // UTF-32BE
+			le = 0;
+			goto Lutf32;
+		}
+		else if (buflen >= 3 && buf[0] == 0xEF && buf[1] == 0xBB && buf[2] == 0xBF)
+		{   // UTF-8
+
+			buf += 3;
+			buflen -= 3;
+		}
+		else
+		{
+			/* There is no BOM. Make use of Arcane Jill's insight that
+			 * the first char of D source must be ASCII to
+			 * figure out the encoding.
+			 */
+
+			bom = 0;
+			if (buflen >= 4)
+			{   if (buf[1] == 0 && buf[2] == 0 && buf[3] == 0)
+			{   // UTF-32LE
+				le = 1;
+				goto Lutf32;
+			}
+			else if (buf[0] == 0 && buf[1] == 0 && buf[2] == 0)
+			{   // UTF-32BE
+				le = 0;
+				goto Lutf32;
+			}
+			}
+			if (buflen >= 2)
+			{
+			if (buf[1] == 0)
+			{   // UTF-16LE
+				le = 1;
+				goto Lutf16;
+			}
+			else if (buf[0] == 0)
+			{   // UTF-16BE
+				le = 0;
+				goto Lutf16;
+			}
+			}
+
+			// It's UTF-8
+			if (buf[0] >= 0x80)
+			{	error("source file must start with BOM or ASCII character, not \\x%02X", buf[0]);
+			fatal();
+			}
+		}
+		}
+
+version (IN_GCC) {
+		// dump utf-8 encoded source 
+		if (dump_source)
+		{	// %% srcname could contain a path ...
+			d_gcc_dump_source(srcname, "utf-8", buf, buflen);
+		}
+}
+
+		/* If it starts with the string "Ddoc", then it's a documentation
+		 * source file.
+		 */
+		if (buflen >= 4 && memcmp(buf, "Ddoc".ptr, 4) == 0)
+		{
+		comment = buf + 4;
+		isDocFile = 1;
+		if (!docfile)
+			setDocfile();
+		return;
+		}
+		if (isHtml)
+		{
+			assert(false);
+			///OutBuffer dbuf = new OutBuffer();
+			///Html h = new Html(srcname, buf, buflen);
+			///h.extractCode(dbuf);
+			///buf = dbuf.data;
+			///buflen = dbuf.offset;
+
+version (IN_GCC) {
+			// dump extracted source
+			///if (dump_source)
+			///	d_gcc_dump_source(srcname, "d.utf-8", buf, buflen);
+}
+		}
+
+		Parser p = new Parser(this, buf, buflen, docfile !is null);
+		p.nextToken();
+		members = p.parseModule();
+		md = p.md;
+		numlines = p.loc.linnum;
+
+		DsymbolTable dst;
+
+		if (md !is null)
+		{
+			this.ident = md.id;
+			this.safe = md.safe;
+			dst = super.resolve(md.packages, &this.parent, null);
+		}
+		else
+		{
+			dst = modules;
+
+			/* Check to see if module name is a valid identifier
+			 */
+			if (!Lexer.isValidIdentifier(this.ident.toChars()))
+				error("has non-identifier characters in filename, use module declaration instead");
+			}
+			
+			// Update global list of modules
+			if (!dst.insert(this))
+			{
+				if (md)
+					error(loc, "is in multiple packages %s", md.toChars());
+				else
+					error(loc, "is in multiple defined");
+			}
+			else
+			{
+				amodules.push(cast(void*)this);
+			}
+		}
+	}
+
+    void semantic()	// semantic analysis
+	{
+		int i;
+
+		if (semanticstarted)
+			return;
+
+		//printf("+Module.semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent);
+		semanticstarted = 1;
+
+		// Note that modules get their own scope, from scratch.
+		// This is so regardless of where in the syntax a module
+		// gets imported, it is unaffected by context.
+		Scope sc = Scope.createGlobal(this);	// create root scope
+
+		//printf("Module = %p, linkage = %d\n", sc.scopesym, sc.linkage);
+
+		// Add import of "object" if this module isn't "object"
+		if (ident !is Id.object)
+		{
+			Import im = new Import(Loc(0), null, Id.object, null, 0);
+			members.shift(cast(void*)im);
+		}
+
+		// Add all symbols into module's symbol table
+		symtab = new DsymbolTable();
+		for (i = 0; i < members.dim; i++)
+		{	
+			Dsymbol s = cast(Dsymbol)members.data[i];
+			s.addMember(null, sc.scopesym, 1);
+		}
+
+		/* Set scope for the symbols so that if we forward reference
+		 * a symbol, it can possibly be resolved on the spot.
+		 * If this works out well, it can be extended to all modules
+		 * before any semantic() on any of them.
+		 */
+		for (i = 0; i < members.dim; i++)
+		{	
+			Dsymbol s = cast(Dsymbol)members.data[i];
+			s.setScope(sc);
+		}
+
+		// Pass 1 semantic routines: do public side of the definition
+		for (i = 0; i < members.dim; i++)
+		{	
+			Dsymbol s = cast(Dsymbol)members.data[i];
+
+			//writef("\tModule('%s'): '%s'.semantic()\n", toChars(), s.toChars());
+			s.semantic(sc);
+			runDeferredSemantic();
+		}
+
+		sc = sc.pop();
+		sc.pop();		// 2 pops because Scope.createGlobal() created 2
+		semanticRun = semanticstarted;
+		//printf("-Module.semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent);
+	}
+	
+    void semantic2()	// pass 2 semantic analysis
+	{
+		if (deferred.dim)
+		{
+			for (int i = 0; i < deferred.dim; i++)
+			{
+				Dsymbol sd = cast(Dsymbol)deferred.data[i];
+
+				sd.error("unable to resolve forward reference in definition");
+			}
+			return;
+		}
+		//printf("Module.semantic2('%s'): parent = %p\n", toChars(), parent);
+		if (semanticstarted >= 2)
+			return;
+		assert(semanticstarted == 1);
+		semanticstarted = 2;
+
+		// Note that modules get their own scope, from scratch.
+		// This is so regardless of where in the syntax a module
+		// gets imported, it is unaffected by context.
+		Scope sc = Scope.createGlobal(this);	// create root scope
+		//printf("Module = %p\n", sc.scopesym);
+
+		// Pass 2 semantic routines: do initializers and function bodies
+		for (int i = 0; i < members.dim; i++)
+		{	
+			Dsymbol s = cast(Dsymbol)members.data[i];
+			s.semantic2(sc);
+		}
+
+		sc = sc.pop();
+		sc.pop();
+		semanticRun = semanticstarted;
+		//printf("-Module.semantic2('%s'): parent = %p\n", toChars(), parent);
+	}
+	
+    void semantic3()	// pass 3 semantic analysis
+	{
+		//printf("Module.semantic3('%s'): parent = %p\n", toChars(), parent);
+		if (semanticstarted >= 3)
+			return;
+		assert(semanticstarted == 2);
+		semanticstarted = 3;
+
+		// Note that modules get their own scope, from scratch.
+		// This is so regardless of where in the syntax a module
+		// gets imported, it is unaffected by context.
+		Scope sc = Scope.createGlobal(this);	// create root scope
+		//printf("Module = %p\n", sc.scopesym);
+
+		// Pass 3 semantic routines: do initializers and function bodies
+		for (int i = 0; i < members.dim; i++)
+		{	
+			Dsymbol s = cast(Dsymbol)members.data[i];
+			//printf("Module %s: %s.semantic3()\n", toChars(), s.toChars());
+			s.semantic3(sc);
+		}
+
+		sc = sc.pop();
+		sc.pop();
+		semanticRun = semanticstarted;
+	}
+	
+    void inlineScan()	// scan for functions to inline
+	{
+		int i;
+
+		if (semanticstarted >= 4)
+			return;
+
+		assert(semanticstarted == 3);
+		semanticstarted = 4;
+
+		// Note that modules get their own scope, from scratch.
+		// This is so regardless of where in the syntax a module
+		// gets imported, it is unaffected by context.
+		//printf("Module = %p\n", sc.scopesym);
+
+		for (i = 0; i < members.dim; i++)
+		{	
+			Dsymbol s = cast(Dsymbol)members.data[i];
+			//if (global.params.verbose)
+				//printf("inline scan symbol %s\n", s.toChars());
+			s.inlineScan();
+		}
+
+		semanticRun = semanticstarted;
+	}
+	
+    void setHdrfile()	// set hdrfile member
+	{
+		FileName hdrfilename;
+		string arghdr;
+
+		if (global.params.hdrname)
+			arghdr = global.params.hdrname;
+		else if (global.params.preservePaths)
+			arghdr = arg;
+		else
+			arghdr = FileName.name(arg);
+		if (!FileName.absolute(arghdr))
+		{	
+			//FileName.ensurePathExists(global.params.hdrdir);
+			arghdr = FileName.combine(global.params.hdrdir, arghdr);
+		}
+		if (global.params.hdrname)
+			hdrfilename = new FileName(arghdr);
+		else
+			hdrfilename = FileName.forceExt(arghdr, global.hdr_ext);
+
+		if (hdrfilename.str == srcfile.name.str)
+		{   
+			error("Source file and 'header' file have same name '%s'", srcfile.name.str);
+			fatal();
+		}
+
+		hdrfile = new File(hdrfilename);
+	}
+	
+version (_DH) {
+    void genhdrfile()  // generate D import file
+	{
+		assert(false);
+	}
+}
+	
+	/**************************************
+	 * Generate .obj file for Module.
+	 */
+    void genobjfile(int multiobj)
+	{
+		//EEcontext *ee = env.getEEcontext();
+
+		//printf("Module.genobjfile(multiobj = %d) %s\n", multiobj, toChars());
+
+		lastmname = srcfile.toChars();	/// global mutation
+
+		obj_initfile(toStringz(lastmname), null, toStringz(toPrettyChars()));
+
+		eictor = null;
+		ictorlocalgot = null;
+		ector = null;
+		ectorgates.setDim(0);
+		edtor = null;
+		etest = null;
+		dtorcount = 0;
+
+		if (doppelganger)
+		{
+			/* Generate a reference to the moduleinfo, so the module constructors
+			 * and destructors get linked in.
+			 */
+			Module m = cast(Module)aimports.data[0];
+			assert(m);
+			if (m.sictor || m.sctor || m.sdtor)
+			{
+				Symbol* s = m.toSymbol();
+				//objextern(s);
+				//if (!s.Sxtrnnum) objextdef(s.Sident);
+				if (!s.Sxtrnnum)
+				{
+					//printf("%s\n", s.Sident);
+static if (false) {
+					/* This should work, but causes optlink to fail in common/newlib.asm */
+					objextdef(s.Sident);
+} else {
+	version (XXX) {///ELFOBJ || MACHOBJ
+				int nbytes = reftoident(DATA, Offset(DATA), s, 0, CFoff);
+				Offset(DATA) += nbytes;
+	} else {
+				int nbytes = reftoident(Segment.DATA, Doffset, s, 0, CF.CFoff);
+				Doffset() += nbytes;
+	}
+}
+				}
+			}
+		}
+
+		if (global.params.cov)
+		{
+			/* Create coverage identifier:
+			 *  private uint[numlines] __coverage;
+			 */
+			cov = symbol_calloc("__coverage");
+			cov.Stype = type_fake(TYM.TYint);
+			cov.Stype.Tmangle = mTYman.mTYman_c;
+			cov.Stype.Tcount++;
+			cov.Sclass = SC.SCstatic;
+			cov.Sfl = FL.FLdata;
+version (ELFOBJ_OR_MACHOBJ) {
+			cov.Sseg = Segment.UDATA;
+}
+			dtnzeros(&cov.Sdt, 4 * numlines);
+			outdata(cov);
+			slist_add(cov);
+
+			covb = cast(uint*)calloc((numlines + 32) / 32, (*covb).sizeof);
+		}
+
+		for (int i = 0; i < members.dim; i++)
+		{
+			Dsymbol member = cast(Dsymbol)members.data[i];
+			member.toObjFile(multiobj);
+		}
+
+		if (global.params.cov)
+		{
+			/* Generate
+			 *	bit[numlines] __bcoverage;
+			 */
+			Symbol* bcov = symbol_calloc("__bcoverage");
+			bcov.Stype = type_fake(TYM.TYuint);
+			bcov.Stype.Tcount++;
+			bcov.Sclass = SC.SCstatic;
+			bcov.Sfl = FL.FLdata;
+version (ELFOBJ_OR_MACHOBJ) {
+			bcov.Sseg = Segment.DATA;
+}
+			dtnbytes(&bcov.Sdt, (numlines + 32) / 32 * (*covb).sizeof, cast(char*)covb);
+			outdata(bcov);
+
+			free(covb);
+			covb = null;
+
+			/* Generate:
+			 *  _d_cover_register(uint[] __coverage, BitArray __bcoverage, string filename);
+			 * and prepend it to the static constructor.
+			 */
+
+			/* t will be the type of the functions generated:
+			 *	extern (C) void func();
+			 */
+			type* t = type_alloc(TYM.TYnfunc);
+			t.Tflags |= TF.TFprototype | TF.TFfixed;
+			t.Tmangle = mTYman.mTYman_c;
+			t.Tnext = tsvoid;
+			tsvoid.Tcount++;
+
+			sictor = toSymbolX("__modictor", SC.SCglobal, t, "FZv");
+			cstate.CSpsymtab = &sictor.Sfunc.Flocsym;
+			localgot = ictorlocalgot;
+			elem* e;
+
+			e = el_params(el_ptr(cov), el_long(TYM.TYuint, numlines),
+					  el_ptr(bcov), el_long(TYM.TYuint, numlines),
+					  toEfilename(),
+					  null);
+			e = el_bin(OPER.OPcall, TYM.TYvoid, el_var(rtlsym[RTLSYM.RTLSYM_DCOVER]), e);
+			eictor = el_combine(e, eictor);
+			ictorlocalgot = localgot;
+		}
+
+		// If coverage / static constructor / destructor / unittest calls
+		if (eictor || ector || ectorgates.dim || edtor || etest)
+		{
+			/* t will be the type of the functions generated:
+			 *	extern (C) void func();
+			 */
+			type* t = type_alloc(TYM.TYnfunc);
+			t.Tflags |= TF.TFprototype | TF.TFfixed;
+			t.Tmangle = mTYman.mTYman_c;
+			t.Tnext = tsvoid;
+			tsvoid.Tcount++;
+
+			static string moddeco = "FZv";
+
+			if (eictor)
+			{
+				localgot = ictorlocalgot;
+
+				block* b = block_calloc();
+				b.BC = BC.BCret;
+				b.Belem = eictor;
+				sictor.Sfunc.Fstartblock = b;
+				writefunc(sictor);
+			}
+
+			if (ector || ectorgates.dim)
+			{
+				localgot = null;
+				sctor = toSymbolX("__modctor", SC.SCglobal, t, moddeco);
+				cstate.CSpsymtab = &sctor.Sfunc.Flocsym;
+
+				for (int i = 0; i < ectorgates.dim; i++)
+				{	
+					StaticDtorDeclaration f = cast(StaticDtorDeclaration)ectorgates.data[i];
+
+					Symbol* s = f.vgate.toSymbol();
+					elem* e = el_var(s);
+					e = el_bin(OPER.OPaddass, TYM.TYint, e, el_long(TYM.TYint, 1));
+					ector = el_combine(ector, e);
+				}
+
+				block* b = block_calloc();
+				b.BC = BC.BCret;
+				b.Belem = ector;
+				sctor.Sfunc.Fstartblock = b;
+				writefunc(sctor);
+version (STATICCTOR) {
+				obj_staticctor(sctor, dtorcount, 1);
+}
+			}
+
+			if (edtor)
+			{
+				localgot = null;
+				sdtor = toSymbolX("__moddtor", SC.SCglobal, t, moddeco);
+
+				block* b = block_calloc();
+				b.BC = BC.BCret;
+				b.Belem = edtor;
+				sdtor.Sfunc.Fstartblock = b;
+				writefunc(sdtor);
+			}
+
+			if (etest)
+			{
+				localgot = null;
+				stest = toSymbolX("__modtest", SC.SCglobal, t, moddeco);
+
+				block* b = block_calloc();
+				b.BC = BC.BCret;
+				b.Belem = etest;
+				stest.Sfunc.Fstartblock = b;
+				writefunc(stest);
+			}
+
+			if (doppelganger)
+				genmoduleinfo();
+		}
+
+		if (doppelganger)
+		{
+			obj_termfile();
+			return;
+		}
+
+		if (global.params.multiobj)
+		{	/* This is necessary because the main .obj for this module is written
+			 * first, but determining whether marray or massert are needed is done
+			 * possibly later in the doppelganger modules.
+			 * Another way to fix it is do the main one last.
+			 */
+			toModuleAssert();
+			toModuleArray();
+		}
+
+		// If module assert
+		for (int i = 0; i < 2; i++)
+		{
+			Symbol* ma = i ? marray : massert;
+
+			if (ma)
+			{
+				elem* elinnum;
+				elem* efilename;
+
+				localgot = null;
+
+				// Call dassert(filename, line)
+				// Get sole parameter, linnum
+				{
+					Symbol* sp;
+
+					sp = symbol_calloc("linnum".ptr);
+					sp.Stype = type_fake(TYM.TYint);
+					sp.Stype.Tcount++;
+					sp.Sclass = SC.SCfastpar;
+					sp.Spreg = REG.AX;
+					sp.Sflags &= ~SFL.SFLspill;
+					sp.Sfl = FL.FLpara;	// FLauto?
+					cstate.CSpsymtab = &ma.Sfunc.Flocsym;
+					symbol_add(sp);
+
+					elinnum = el_var(sp);
+				}
+
+				efilename = toEmodulename();
+
+				elem *e = el_var(rtlsym[i ? RTLSYM.RTLSYM_DARRAY : RTLSYM.RTLSYM_DASSERT]);
+				e = el_bin(OPER.OPcall, TYM.TYvoid, e, el_param(elinnum, efilename));
+
+				block* b = block_calloc();
+				b.BC = BC.BCret;
+				b.Belem = e;
+				ma.Sfunc.Fstartblock = b;
+				ma.Sclass = SC.SCglobal;
+				ma.Sfl = 0;
+				writefunc(ma);
+			}
+		}
+
+static if (true) {
+		// Always generate module info, because of templates and -cov
+		if (1 || needModuleInfo())
+			genmoduleinfo();
+		}
+		
+		obj_termfile();
+	}
+	
+    void gensymfile()
+	{
+		assert(false);
+	}
+	
+    void gendocfile()
+	{
+		assert(false);
+	}
+	
+	/**********************************
+	 * Determine if we need to generate an instance of ModuleInfo
+	 * for this Module.
+	 */
+    bool needModuleInfo()
+	{
+		return needmoduleinfo || global.params.cov;
+	}
+	
+    Dsymbol search(Loc loc, Identifier ident, int flags)
+	{
+		/* Since modules can be circularly referenced,
+		 * need to stop infinite recursive searches.
+		 */
+
+		//printf("%s Module.search('%s', flags = %d) insearch = %d\n", toChars(), ident.toChars(), flags, insearch);
+		Dsymbol s;
+		if (insearch)
+			s = null;
+		else if (searchCacheIdent is ident && searchCacheFlags == flags)
+			s = searchCacheSymbol;
+		else
+		{
+			insearch = 1;
+			s = ScopeDsymbol.search(loc, ident, flags);
+			insearch = 0;
+
+			searchCacheIdent = ident;
+			searchCacheSymbol = s;
+			searchCacheFlags = flags;
+		}
+		return s;
+	}
+	
+    void deleteObjFile()
+	{
+		if (global.params.obj)
+			objfile.remove();
+		if (docfile)
+			docfile.remove();
+	}
+
+    void addDeferredSemantic(Dsymbol s)
+	{
+		assert(false);
+	}
+	
+	/******************************************
+	 * Run semantic() on deferred symbols.
+	 */
+
+    void runDeferredSemantic()
+	{
+		size_t len;
+
+		static int nested;
+		if (nested)
+		return;
+		//if (deferred.dim) printf("+Module.runDeferredSemantic('%s'), len = %d\n", toChars(), deferred.dim);
+		nested++;
+
+		do
+		{
+			dprogress = 0;
+			len = deferred.dim;
+			if (!len)
+				break;
+
+			Dsymbol *todo;
+			Dsymbol tmp;
+			if (len == 1)
+			{
+				todo = &tmp;
+			}
+			else
+			{
+				todo = cast(Dsymbol*)alloca(len * (Dsymbol*).sizeof);
+				assert(todo);
+			}
+			memcpy(todo, deferred.data, len * (Dsymbol*).sizeof);
+			deferred.setDim(0);
+
+			for (int i = 0; i < len; i++)
+			{
+				Dsymbol s = todo[i];
+
+				s.semantic(null);
+				//printf("deferred: %s, parent = %s\n", s.toChars(), s.parent.toChars());
+			}
+			//printf("\tdeferred.dim = %d, len = %d, dprogress = %d\n", deferred.dim, len, dprogress);
+		} while (deferred.dim < len || dprogress);	// while making progress
+		nested--;
+		//printf("-Module.runDeferredSemantic('%s'), len = %d\n", toChars(), deferred.dim);
+	}
+	
+    int imports(Module m)
+	{
+		assert(false);
+	}
+
+    // Back end
+
+    int doppelganger;		// sub-module
+    Symbol* cov;		// private uint[] __coverage;
+    uint* covb;		// bit array of valid code line numbers
+
+    Symbol* sictor;		// module order independent constructor
+    Symbol* sctor;		// module constructor
+    Symbol* sdtor;		// module destructor
+    Symbol* stest;		// module unit test
+
+    Symbol* sfilename;		// symbol for filename
+
+    Symbol* massert;		// module assert function
+    Symbol* toModuleAssert()	// get module assert function
+	{
+		if (!massert)
+		{
+			type* t;
+
+			t = type_alloc(TYjfunc);
+			t.Tflags |= TFprototype | TFfixed;
+			t.Tmangle = mTYman_d;
+			t.Tnext = tsvoid;
+			tsvoid.Tcount++;
+
+			massert = toSymbolX("__assert", SCextern, t, "FiZv");
+			massert.Sfl = FLextern;
+			massert.Sflags |= SFLnodebug;
+			slist_add(massert);
+		}
+		return massert;
+	}
+
+    Symbol* marray;		// module array bounds function
+
+	Symbol* toModuleArray()	// get module array bounds function
+	{
+		if (!marray)
+		{
+			type* t;
+
+			t = type_alloc(TYjfunc);
+			t.Tflags |= TFprototype | TFfixed;
+			t.Tmangle = mTYman_d;
+			t.Tnext = tsvoid;
+			tsvoid.Tcount++;
+
+			marray = toSymbolX("__array", SCextern, t, "Z");
+			marray.Sfl = FLextern;
+			marray.Sflags |= SFLnodebug;
+			slist_add(marray);
+		}
+		return marray;
+	}
+
+    static Symbol* gencritsec()
+	{
+		assert(false);
+	}
+	
+    elem* toEfilename()
+	{
+		elem* efilename;
+
+		if (!sfilename)
+		{
+			dt_t* dt = null;
+
+			string id = srcfile.toChars();
+			int len = id.length;
+			dtdword(&dt, len);
+			dtabytes(&dt,TYnptr, 0, len + 1, toStringz(id));
+
+			sfilename = symbol_generate(SCstatic,type_fake(TYdarray));
+			sfilename.Sdt = dt;
+			sfilename.Sfl = FLdata;
+		version (ELFOBJ) {
+			sfilename.Sseg = Segment.CDATA;
+		}
+		version (MACHOBJ) {
+			// Because of PIC and CDATA being in the _TEXT segment, cannot
+			// have pointers in CDATA
+			sfilename.Sseg = Segment.DATA;
+		}
+			outdata(sfilename);
+		}
+
+		efilename = el_var(sfilename);
+		return efilename;
+	}
+	
+	/**************************************
+	 * Generate elem that is a pointer to the module file name.
+	 */
+    elem* toEmodulename()
+	{
+		elem *efilename;
+
+		// Get filename
+		if (needModuleInfo())
+		{   
+			/* Class ModuleInfo is defined in std.moduleinfo.
+			 * The first member is the name of it, char name[],
+			 * which will be at offset 8.
+			 */
+
+			Symbol* si = toSymbol();
+		static if (true) {
+			// Use this instead so -fPIC will work
+			efilename = el_ptr(si);
+			efilename = el_bin(OPadd, TYnptr, efilename, el_long(TYuint, 8));
+			efilename = el_una(OPind, TYdarray, efilename);
+		} else {
+			efilename = el_var(si);
+			efilename.Ety = TYdarray;
+			efilename.EV.sp.Voffset += 8;
+		}
+		}
+		else // generate our own filename
+		{
+			efilename = toEfilename();
+		}
+		return efilename;
+	}
+
+	/*************************************
+	 * Create the "ModuleInfo" symbol
+	 */
+    Symbol* toSymbol()
+	{
+		if (!csym)
+		{
+			Symbol* s;
+			static Classsym* scc;
+
+			if (!scc) {
+				scc = fake_classsym(Id.ClassInfo);
+			}
+
+			s = toSymbolX("__ModuleInfo", SC.SCextern, scc.Stype, "Z");
+			s.Sfl = FL.FLextern;
+			s.Sflags |= SFL.SFLnodebug;
+			csym = s;
+			slist_add(s);
+		}
+		return csym;
+	}
+
+	// Put out instance of ModuleInfo for this Module
+    void genmoduleinfo()
+	{
+		//printf("Module.genmoduleinfo() %s\n", toChars());
+
+		Symbol* msym = toSymbol();
+
+		//dumpSymbol(msym);
+		
+		uint offset;
+	version (DMDV2) {
+		uint sizeof_ModuleInfo = 18 * PTRSIZE;
+	} else {
+		uint sizeof_ModuleInfo = 14 * PTRSIZE;
+	}
+
+		//////////////////////////////////////////////
+
+		csym.Sclass = SC.SCglobal;
+
+		csym.Sfl = FL.FLdata;
+
+		/* The layout is:
+		   {
+			void **vptr;
+			monitor_t monitor;
+			char[] name;		// class name
+			ModuleInfo importedModules[];
+			ClassInfo localClasses[];
+			uint flags;			// initialization state
+			void *ctor;
+			void *dtor;
+			void *unitTest;
+			const(MemberInfo[]) function(string) xgetMembers;	// module getMembers() function
+			void *ictor;
+			void*[4] reserved;
+		   }
+		 */
+		dt_t* dt = null;
+
+		if (moduleinfo)
+			dtxoff(&dt, moduleinfo.toVtblSymbol(), 0, TYM.TYnptr); // vtbl for ModuleInfo
+		else
+		{	
+			//printf("moduleinfo is null\n");
+			dtdword(&dt, 0);		// BUG: should be an assert()
+		}
+		dtdword(&dt, 0);			// monitor
+
+		// name[]
+		string name = toPrettyChars();
+		size_t namelen = name.length;
+		dtdword(&dt, namelen);
+		dtabytes(&dt, TYM.TYnptr, 0, namelen + 1, toStringz(name));
+
+		ClassDeclarations aclasses = new ClassDeclarations();
+
+		//printf("members.dim = %d\n", members.dim);
+		for (int i = 0; i < members.dim; i++)
+		{	
+			Dsymbol member = cast(Dsymbol)members.data[i];
+
+			//printf("\tmember '%s'\n", member.toChars());
+			member.addLocalClass(aclasses);
+		}
+
+		// importedModules[]
+		int aimports_dim = aimports.dim;
+		for (int i = 0; i < aimports.dim; i++)
+		{	
+			Module m = cast(Module)aimports.data[i];
+			if (!m.needModuleInfo())
+				aimports_dim--;
+		}
+
+		dtdword(&dt, aimports_dim);
+		if (aimports_dim)
+			dtxoff(&dt, csym, sizeof_ModuleInfo, TYM.TYnptr);
+		else
+			dtdword(&dt, 0);
+
+		// localClasses[]
+		dtdword(&dt, aclasses.dim);
+		if (aclasses.dim)
+			dtxoff(&dt, csym, sizeof_ModuleInfo + aimports_dim * PTRSIZE, TYM.TYnptr);
+		else
+			dtdword(&dt, 0);
+
+		if (needmoduleinfo)
+			dtdword(&dt, 8|0);		// flags (4 means MIstandalone)
+		else
+			dtdword(&dt, 8|4);		// flags (4 means MIstandalone)
+
+		if (sctor)
+			dtxoff(&dt, sctor, 0, TYM.TYnptr);
+		else
+			dtdword(&dt, 0);
+
+		if (sdtor)
+			dtxoff(&dt, sdtor, 0, TYM.TYnptr);
+		else
+			dtdword(&dt, 0);
+
+		if (stest)
+			dtxoff(&dt, stest, 0, TYM.TYnptr);
+		else
+			dtdword(&dt, 0);
+
+///	version (DMDV2) {
+		FuncDeclaration sgetmembers = findGetMembers();
+		if (sgetmembers)
+			dtxoff(&dt, sgetmembers.toSymbol(), 0, TYM.TYnptr);
+		else
+///	}
+			dtdword(&dt, 0);			// xgetMembers
+
+		if (sictor)
+			dtxoff(&dt, sictor, 0, TYM.TYnptr);
+		else
+			dtdword(&dt, 0);
+
+	version (DMDV2) {
+		// void*[4] reserved;
+		dtdword(&dt, 0);
+		dtdword(&dt, 0);
+		dtdword(&dt, 0);
+		dtdword(&dt, 0);
+	}
+		//////////////////////////////////////////////
+
+		for (int i = 0; i < aimports.dim; i++)
+		{	
+			Module m = cast(Module)aimports.data[i];
+
+			if (m.needModuleInfo())
+			{   
+				Symbol* s = m.toSymbol();
+
+				/* Weak references don't pull objects in from the library,
+				 * they resolve to 0 if not pulled in by something else.
+				 * Don't pull in a module just because it was imported.
+				 */
+	version (OMFOBJ) {// Optlink crashes with weak symbols at EIP 41AFE7, 402000
+	} else {
+				s.Sflags |= SFL.SFLweak;
+	}
+				dtxoff(&dt, s, 0, TYM.TYnptr);
+			}
+		}
+
+		for (int i = 0; i < aclasses.dim; i++)
+		{
+			ClassDeclaration cd = cast(ClassDeclaration)aclasses.data[i];
+			dtxoff(&dt, cd.toSymbol(), 0, TYM.TYnptr);
+		}
+
+		csym.Sdt = dt;
+	version (ELFOBJ_OR_MACHOBJ) {
+		// Cannot be CONST because the startup code sets flag bits in it
+		csym.Sseg = Segment.DATA;
+	}
+
+		outdata(csym);
+
+		//////////////////////////////////////////////
+
+		obj_moduleinfo(msym);
+	}
+
+    Module isModule() { return this; }
+}
\ No newline at end of file