view dmd/Module.d @ 178:e3afd1303184

Many small bugs fixed Made all classes derive from TObject to detect memory leaks (functionality is disabled for now) Began work on overriding backend memory allocations (to avoid memory leaks)
author korDen
date Sun, 17 Oct 2010 07:42:00 +0400
parents fa9a71a9f5a8
children cd48cb899aee
line wrap: on
line source

module dmd.Module;

import dmd.common;
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.Json;
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;

import core.memory;

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
{
    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
    Vector!string debugids;		// debug identifiers
    Vector!string debugidsNot;		// forward referenced debug identifiers

    uint versionlevel;	// version level
    Vector!(string) versionids;		// version identifiers
    Vector!(string) 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)
	{
		register();

		super(ident);

		versionids = new Vector!string;
		versionidsNot = new Vector!string;

		FileName objfilename;

		aimports = new Array();

	    //writefln("Module.Module(filename = '%s', ident = '%s')", 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);

		//writeln(srcfilename.toChars());
		srcfile = new File(srcfilename);

		if (doDocComment) {
			setDocfile();
		}

		if (doHdrGen) {
			setHdrfile();
		}

		objfile = new File(objfilename);
		symfile = new File(symfilename);
	}

    static Module load(Loc loc, Vector!Identifier 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();

			foreach (pid; packages)
			{
				buf.writestring(pid.toChars());
version (Windows)
{
				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)
		{
			write("import    ");
			if (packages)
			{
				foreach (pid; packages)
				{
					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;
	}

    override void toCBuffer(OutBuffer buf, HdrGenState* hgs)
	{
		assert(false);
	}

    override void toJsonBuffer(OutBuffer buf)
    {
		buf.writestring("{\n");

		if (md)
			JsonProperty(buf, Pname, md.toChars());

		JsonProperty(buf, Pkind, kind());

		JsonProperty(buf, Pfile, srcfile.toChars());

		if (comment)
			JsonProperty(buf, Pcomment, comment);

		JsonString(buf, Pmembers);
		buf.writestring(" : [\n");

		size_t offset = buf.offset;
		foreach (Dsymbol s; members)
		{
			if (offset != buf.offset)
			{
				buf.writestring(",\n");
				offset = buf.offset;
			}
			s.toJsonBuffer(buf);
		}

		JsonRemoveComma(buf);
		buf.writestring("]\n");

		buf.writestring("}\n");
	}

    override string kind()
	{
		return "module";
	}

    void setDocfile()	// set docfile member
	{
		assert(false);
	}

    void read(Loc loc)	// read file
	{
		//writefln("Module.read('%s') file '%s'", 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 = new OutBuffer();
			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 = new OutBuffer();
				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 = cast(string) ((buf + 4)[0 .. buflen]);
		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);
}
		}

		auto 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 = global.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
			{
				global.amodules.push(cast(void*)this);
			}
		}
	}

	override void importAll(Scope prevsc)
	{
		//writef("+Module.importAll(this = %p, '%s'): parent = %p\n", this, toChars(), parent);

		if (scope_ !is null)
			return;			// already done

		/* 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.
		 * Ignore prevsc.
		 */
		Scope sc = Scope.createGlobal(this);	// create root scope

		// Add import of "object" if this module isn't "object"
		if (ident != Id.object)
		{
			if (members.dim == 0 || members[0].ident != Id.object)
			{
				Import im = new Import(Loc(), null, Id.object, null, 0);
				members.shift(im);
			}
		}

		if (!symtab)
		{
			// Add all symbols into module's symbol table
			symtab = new DsymbolTable();
			foreach (Dsymbol s; members)
				s.addMember(null, sc.scopesym, 1);
		}
		// anything else should be run after addMember, so version/debug symbols are defined

		/* 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.
		 */
		setScope(sc);		// remember module scope for semantic
		foreach (Dsymbol s; members)
			s.setScope(sc);

		foreach (Dsymbol s; members)
			s.importAll(sc);

		sc = sc.pop();
		sc.pop();		// 2 pops because Scope::createGlobal() created 2
	}

    void semantic()	// semantic analysis
	{
		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_; // // see if already got one from importAll()
		if (!sc)
	    {
			writef("test2\n");
			Scope.createGlobal(this);	// create root scope
	    }

		//writef("Module = %p, linkage = %d\n", sc.scopesym, sc.linkage);

static if (false)
{
		// Add import of "object" if this module isn't "object"
		if (ident !is Id.object)
		{
			auto im = new Import(Loc(0), null, Id.object, null, 0);
			members.shift(im);
		}

		// Add all symbols into module's symbol table
		symtab = new DsymbolTable();
		foreach(s; members)
		{
			s.addMember(null, sc.scopesym, true);
		}

		/* 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.
		 */
		foreach(Dsymbol s; members)
			s.setScope(sc);
}

		// Pass 1 semantic routines: do public side of the definition
		foreach (Dsymbol s; members)
		{
			//writef("\tModule('%s'): '%s'.semantic()\n", toChars(), s.toChars());
			s.semantic(sc);
			runDeferredSemantic();
		}

		if (!scope_)
	    {
			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
	{
		auto deferred = global.deferred;
		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
		foreach(Dsymbol s; members)
			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
		foreach(Dsymbol s; members)
		{
			//printf("Module %s: %s.semantic3()\n", toChars(), s.toChars());
			s.semantic3(sc);
		}

		sc = sc.pop();
		sc.pop();
		semanticRun = semanticstarted;
	}

    override void inlineScan()	// scan for functions to inline
	{
		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);

		foreach(Dsymbol s; members)
		{
			//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());

		auto lastmname = global.lastmname = srcfile.toChars();

		obj_initfile(toStringz(lastmname), null, toStringz(toPrettyChars()));

		global.eictor = null;
		global.ictorlocalgot = null;
		global.ector = null;
		global.ectorgates.setDim(0);
		global.edtor = null;
		global.etest = null;
		global.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 (ELFOBJ_OR_MACHOBJ) {///ELFOBJ || MACHOBJ
				int nbytes = reftoident(Segment.DATA, Offset(Segment.DATA), s, 0, CF.CFoff);
				Offset(Segment.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*)GC.calloc(((numlines + 32) / 32) * (*covb).sizeof);
		}

		foreach(Dsymbol member; members)
			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;
			global.localgot = global.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);
			global.eictor = el_combine(e, global.eictor);
			global.ictorlocalgot = global.localgot;
		}

		// If coverage / static constructor / destructor / unittest calls
		if (global.eictor || global.ector || global.ectorgates.dim || global.edtor || global.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++;

			enum moddeco = "FZv";

			if (global.eictor)
			{
				global.localgot = global.ictorlocalgot;

				block* b = block_calloc();
				b.BC = BC.BCret;
				b.Belem = global.eictor;
				sictor.Sfunc.Fstartblock = b;
				writefunc(sictor);
			}

			if (global.ector || global.ectorgates.dim)
			{
				global.localgot = null;
				sctor = toSymbolX("__modctor", SC.SCglobal, t, moddeco);
				cstate.CSpsymtab = &sctor.Sfunc.Flocsym;

				for (int i = 0; i < global.ectorgates.dim; i++)
				{
					StaticDtorDeclaration f = cast(StaticDtorDeclaration)global.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));
					global.ector = el_combine(global.ector, e);
				}

				block* b = block_calloc();
				b.BC = BC.BCret;
				b.Belem = global.ector;
				sctor.Sfunc.Fstartblock = b;
				writefunc(sctor);
version (STATICCTOR) {
				obj_staticctor(sctor, dtorcount, 1);
}
			}

			if (global.edtor)
			{
				global.localgot = null;
				sdtor = toSymbolX("__moddtor", SC.SCglobal, t, moddeco);

				block* b = block_calloc();
				b.BC = BC.BCret;
				b.Belem = global.edtor;
				sdtor.Sfunc.Fstartblock = b;
				writefunc(sdtor);
			}

			if (global.etest)
			{
				global.localgot = null;
				stest = toSymbolX("__modtest", SC.SCglobal, t, moddeco);

				block* b = block_calloc();
				b.BC = BC.BCret;
				b.Belem = global.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;

				global.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()
	{
    	// writef("needModuleInfo() %s, %d, %d\n", toChars(), needmoduleinfo, global.params.cov);
		return needmoduleinfo || global.params.cov;
	}

    override Dsymbol search(Loc loc, Identifier ident, int flags)
	{
		/* Since modules can be circularly referenced,
		 * need to stop infinite recursive searches.
		 * This is done with the cache.
		 */

		//printf("%s Module.search('%s', flags = %d) insearch = %d\n", toChars(), ident.toChars(), flags, insearch);
		Dsymbol s;
		if (insearch)
			s = null;
	    else if (searchCacheIdent == ident && searchCacheFlags == flags)
		{
			s = searchCacheSymbol;
			//printf("%s Module.search('%s', flags = %d) insearch = %d searchCacheSymbol = %s\n", toChars(), ident.toChars(), flags, insearch, searchCacheSymbol ? searchCacheSymbol.toChars() : "null");
		}
		else
		{
			insearch = 1;
			s = ScopeDsymbol.search(loc, ident, flags);
			insearch = 0;

			searchCacheIdent = ident;
			searchCacheSymbol = s;
			searchCacheFlags = flags;
		}
		return s;
	}

    void deleteObjFile()
	{
		if (global.params.obj)
			objfile.remove();
		if (docfile)
			docfile.remove();
	}

	override Dsymbol symtabInsert(Dsymbol s)
	{
		searchCacheIdent = null;	// symbol is inserted, so invalidate cache
		return Package.symtabInsert(s);
	}

	/*******************************************
	 * Can't run semantic on s now, try again later.
	 */
	void addDeferredSemantic(Dsymbol s)
	{
		auto deferred = global.deferred;
	    // Don't add it if it is already there
	    for (int i = 0; i < deferred.dim; i++)
	    {
		Dsymbol sd = cast(Dsymbol)deferred.data[i];

		if (sd == s)
		    return;
	    }

	    //printf("Module::addDeferredSemantic('%s')\n", s.toChars());
	    deferred.push(cast(void*)s);
	}

	/******************************************
	 * Run semantic() on deferred symbols.
	 */

    void runDeferredSemantic()
	{
		if (global.nested)
			return;
		//if (deferred.dim) printf("+Module.runDeferredSemantic('%s'), len = %d\n", toChars(), deferred.dim);
		global.nested++;

		size_t len;

		auto deferred = global.deferred;

		do
		{
			global.dprogress = 0;
			len = deferred.dim;
			if (!len)
				break;

			Dsymbol *todo;
			Dsymbol tmp;
			if (len == 1)
			{
				todo = &tmp;
			}
			else
			{
				version(Bug4054)
				todo = cast(Dsymbol*)GC.malloc(len * (Dsymbol*).sizeof);
				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 || global.dprogress);	// while making progress
		global.nested--;
		//printf("-Module.runDeferredSemantic('%s'), len = %d\n", toChars(), deferred.dim);
	}

	/************************************
	 * Recursively look at every module this module imports,
	 * return TRUE if it imports m.
	 * Can be used to detect circular imports.
	 */
	bool imports(Module m)
	{
//		writef("%s Module::imports(%s)\n", toChars(), m.toChars());
		int aimports_dim = aimports.dim;
static if (false)
{
		for (int i = 0; i < aimports.dim; i++)
		{   Module mi = cast(Module)aimports.data[i];
			writef("\t[%d] %s\n", i, mi.toChars());
		}
}
		for (int i = 0; i < aimports.dim; i++)
		{   Module mi = cast(Module)aimports.data[i];
			if (mi == m)
				return true;
			if (!mi.insearch)
			{
				mi.insearch = 1;
				bool r = mi.imports(m);
				if (r)
					return r;
			}
		}
		return 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
	 */
    override Symbol* toSymbol()
	{
		if (!csym)
		{
			Symbol* s;

			s = toSymbolX("__ModuleInfo", SC.SCextern, global.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 (global.moduleinfo)
			dtxoff(&dt, global.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);
		foreach(Dsymbol member; members)
		{
			//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);
			}
		}

		foreach (cd; aclasses)
		{
			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);
	}

    override Module isModule() { return this; }
}