From e03e027002eed721d03d44fd75362f4ec674fbcf Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 26 Aug 2012 21:07:25 +0200 Subject: [PATCH 01/33] Removed all CRLF line endings from DMD source. Some files in our copy of the DMD 2 source had CRLF line endings. This was not only inconsistent, but also made merging DMD patches (where LF is used throughout) unnecessarily painful. --- dmd2/artistic.txt | 234 +- dmd2/doc.c | 4458 +++++++-------- dmd2/dsymbol.c | 3056 +++++------ dmd2/dsymbol.h | 792 +-- dmd2/gpl.txt | 496 +- dmd2/mars.c | 3272 +++++------ dmd2/readme.txt | 48 +- dmd2/template.c | 12882 ++++++++++++++++++++++---------------------- dmd2/total.h | 92 +- 9 files changed, 12665 insertions(+), 12665 deletions(-) diff --git a/dmd2/artistic.txt b/dmd2/artistic.txt index cd17757e..cae432b7 100644 --- a/dmd2/artistic.txt +++ b/dmd2/artistic.txt @@ -1,117 +1,117 @@ - - - - - The "Artistic License" - - Preamble - -The intent of this document is to state the conditions under which a -Package may be copied, such that the Copyright Holder maintains some -semblance of artistic control over the development of the package, -while giving the users of the package the right to use and distribute -the Package in a more-or-less customary fashion, plus the right to make -reasonable modifications. - -Definitions: - - "Package" refers to the collection of files distributed by the - Copyright Holder, and derivatives of that collection of files - created through textual modification. - - "Standard Version" refers to such a Package if it has not been - modified, or has been modified in accordance with the wishes - of the Copyright Holder as specified below. - - "Copyright Holder" is whoever is named in the copyright or - copyrights for the package. - - "You" is you, if you're thinking about copying or distributing - this Package. - - "Reasonable copying fee" is whatever you can justify on the - basis of media cost, duplication charges, time of people involved, - and so on. (You will not be required to justify it to the - Copyright Holder, but only to the computing community at large - as a market that must bear the fee.) - - "Freely Available" means that no fee is charged for the item - itself, though there may be fees involved in handling the item. - It also means that recipients of the item may redistribute it - under the same conditions they received it. - -1. You may make and give away verbatim copies of the source form of the -Standard Version of this Package without restriction, provided that you -duplicate all of the original copyright notices and associated disclaimers. - -2. You may apply bug fixes, portability fixes and other modifications -derived from the Public Domain or from the Copyright Holder. A Package -modified in such a way shall still be considered the Standard Version. - -3. You may otherwise modify your copy of this Package in any way, provided -that you insert a prominent notice in each changed file stating how and -when you changed that file, and provided that you do at least ONE of the -following: - - a) place your modifications in the Public Domain or otherwise make them - Freely Available, such as by posting said modifications to Usenet or - an equivalent medium, or placing the modifications on a major archive - site such as uunet.uu.net, or by allowing the Copyright Holder to include - your modifications in the Standard Version of the Package. - - b) use the modified Package only within your corporation or organization. - - c) rename any non-standard executables so the names do not conflict - with standard executables, which must also be provided, and provide - a separate manual page for each non-standard executable that clearly - documents how it differs from the Standard Version. - - d) make other distribution arrangements with the Copyright Holder. - -4. You may distribute the programs of this Package in object code or -executable form, provided that you do at least ONE of the following: - - a) distribute a Standard Version of the executables and library files, - together with instructions (in the manual page or equivalent) on where - to get the Standard Version. - - b) accompany the distribution with the machine-readable source of - the Package with your modifications. - - c) give non-standard executables non-standard names, and clearly - document the differences in manual pages (or equivalent), together - with instructions on where to get the Standard Version. - - d) make other distribution arrangements with the Copyright Holder. - -5. You may charge a reasonable copying fee for any distribution of this -Package. You may charge any fee you choose for support of this -Package. You may not charge a fee for this Package itself. However, -you may distribute this Package in aggregate with other (possibly -commercial) programs as part of a larger (possibly commercial) software -distribution provided that you do not advertise this Package as a -product of your own. You may embed this Package's interpreter within -an executable of yours (by linking); this shall be construed as a mere -form of aggregation, provided that the complete Standard Version of the -interpreter is so embedded. - -6. The source code and object code supplied as input to or produced as -output from the programs of this Package do not automatically fall -under the copyright of this Package, but belong to whoever generated -them, and may be sold commercially, and may be aggregated with this -Package. - -7. Aggregation of this Package with a commercial distribution is always -permitted provided that the use of this Package is embedded; that is, -when no overt attempt is made to make this Package's interfaces visible -to the end user of the commercial distribution. Such use shall not be -construed as a distribution of this Package. - -8. The name of the Copyright Holder may not be used to endorse or promote -products derived from this software without specific prior written permission. - -9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED -WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - - The End + + + + + The "Artistic License" + + Preamble + +The intent of this document is to state the conditions under which a +Package may be copied, such that the Copyright Holder maintains some +semblance of artistic control over the development of the package, +while giving the users of the package the right to use and distribute +the Package in a more-or-less customary fashion, plus the right to make +reasonable modifications. + +Definitions: + + "Package" refers to the collection of files distributed by the + Copyright Holder, and derivatives of that collection of files + created through textual modification. + + "Standard Version" refers to such a Package if it has not been + modified, or has been modified in accordance with the wishes + of the Copyright Holder as specified below. + + "Copyright Holder" is whoever is named in the copyright or + copyrights for the package. + + "You" is you, if you're thinking about copying or distributing + this Package. + + "Reasonable copying fee" is whatever you can justify on the + basis of media cost, duplication charges, time of people involved, + and so on. (You will not be required to justify it to the + Copyright Holder, but only to the computing community at large + as a market that must bear the fee.) + + "Freely Available" means that no fee is charged for the item + itself, though there may be fees involved in handling the item. + It also means that recipients of the item may redistribute it + under the same conditions they received it. + +1. You may make and give away verbatim copies of the source form of the +Standard Version of this Package without restriction, provided that you +duplicate all of the original copyright notices and associated disclaimers. + +2. You may apply bug fixes, portability fixes and other modifications +derived from the Public Domain or from the Copyright Holder. A Package +modified in such a way shall still be considered the Standard Version. + +3. You may otherwise modify your copy of this Package in any way, provided +that you insert a prominent notice in each changed file stating how and +when you changed that file, and provided that you do at least ONE of the +following: + + a) place your modifications in the Public Domain or otherwise make them + Freely Available, such as by posting said modifications to Usenet or + an equivalent medium, or placing the modifications on a major archive + site such as uunet.uu.net, or by allowing the Copyright Holder to include + your modifications in the Standard Version of the Package. + + b) use the modified Package only within your corporation or organization. + + c) rename any non-standard executables so the names do not conflict + with standard executables, which must also be provided, and provide + a separate manual page for each non-standard executable that clearly + documents how it differs from the Standard Version. + + d) make other distribution arrangements with the Copyright Holder. + +4. You may distribute the programs of this Package in object code or +executable form, provided that you do at least ONE of the following: + + a) distribute a Standard Version of the executables and library files, + together with instructions (in the manual page or equivalent) on where + to get the Standard Version. + + b) accompany the distribution with the machine-readable source of + the Package with your modifications. + + c) give non-standard executables non-standard names, and clearly + document the differences in manual pages (or equivalent), together + with instructions on where to get the Standard Version. + + d) make other distribution arrangements with the Copyright Holder. + +5. You may charge a reasonable copying fee for any distribution of this +Package. You may charge any fee you choose for support of this +Package. You may not charge a fee for this Package itself. However, +you may distribute this Package in aggregate with other (possibly +commercial) programs as part of a larger (possibly commercial) software +distribution provided that you do not advertise this Package as a +product of your own. You may embed this Package's interpreter within +an executable of yours (by linking); this shall be construed as a mere +form of aggregation, provided that the complete Standard Version of the +interpreter is so embedded. + +6. The source code and object code supplied as input to or produced as +output from the programs of this Package do not automatically fall +under the copyright of this Package, but belong to whoever generated +them, and may be sold commercially, and may be aggregated with this +Package. + +7. Aggregation of this Package with a commercial distribution is always +permitted provided that the use of this Package is embedded; that is, +when no overt attempt is made to make this Package's interfaces visible +to the end user of the commercial distribution. Such use shall not be +construed as a distribution of this Package. + +8. The name of the Copyright Holder may not be used to endorse or promote +products derived from this software without specific prior written permission. + +9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + The End diff --git a/dmd2/doc.c b/dmd2/doc.c index 094d5947..4d8f104d 100644 --- a/dmd2/doc.c +++ b/dmd2/doc.c @@ -1,2229 +1,2229 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -// This implements the Ddoc capability. - -#include -#include -#include -#include -#include - -#include "rmem.h" -#include "root.h" - -#include "mars.h" -#include "dsymbol.h" -#include "macro.h" -#include "template.h" -#include "lexer.h" -#include "aggregate.h" -#include "declaration.h" -#include "enum.h" -#include "id.h" -#include "module.h" -#include "scope.h" -#include "hdrgen.h" -#include "doc.h" -#include "mtype.h" -#include "utf.h" - -struct Escape -{ - const char *strings[256]; - - static const char *escapeChar(unsigned c); -}; - -struct Section -{ - unsigned char *name; - unsigned namelen; - - unsigned char *body; - unsigned bodylen; - - int nooutput; - - virtual void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf); -}; - -struct ParamSection : Section -{ - void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf); -}; - -struct MacroSection : Section -{ - void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf); -}; - -typedef ArrayBase
Sections; - -struct DocComment -{ - Sections sections; // Section*[] - - Section *summary; - Section *copyright; - Section *macros; - Macro **pmacrotable; - Escape **pescapetable; - - DocComment(); - - static DocComment *parse(Scope *sc, Dsymbol *s, unsigned char *comment); - static void parseMacros(Escape **pescapetable, Macro **pmacrotable, unsigned char *m, unsigned mlen); - static void parseEscapes(Escape **pescapetable, unsigned char *textstart, unsigned textlen); - - void parseSections(unsigned char *comment); - void writeSections(Scope *sc, Dsymbol *s, OutBuffer *buf); -}; - - -int cmp(const char *stringz, void *s, size_t slen); -int icmp(const char *stringz, void *s, size_t slen); -int isDitto(unsigned char *comment); -unsigned char *skipwhitespace(unsigned char *p); -unsigned skiptoident(OutBuffer *buf, size_t i); -unsigned skippastident(OutBuffer *buf, size_t i); -unsigned skippastURL(OutBuffer *buf, size_t i); -void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); -void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); -void highlightCode2(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); -Parameter *isFunctionParameter(Dsymbol *s, unsigned char *p, unsigned len); - -int isIdStart(unsigned char *p); -int isIdTail(unsigned char *p); -int utfStride(unsigned char *p); - -static unsigned char ddoc_default[] = "\ -DDOC = \n\ - \n\ - $(TITLE)\n\ - \n\ -

$(TITLE)

\n\ - $(BODY)\n\ -
$(SMALL Page generated by $(LINK2 http://www.digitalmars.com/d/2.0/ddoc.html, Ddoc). $(COPYRIGHT))\n\ - \n\ -\n\ -B = $0\n\ -I = $0\n\ -U = $0\n\ -P =

$0

\n\ -DL =
$0
\n\ -DT =
$0
\n\ -DD =
$0
\n\ -TABLE = $0
\n\ -TR = $0\n\ -TH = $0\n\ -TD = $0\n\ -OL =
    $0
\n\ -UL =
    $0
\n\ -LI =
  • $0
  • \n\ -BIG = $0\n\ -SMALL = $0\n\ -BR =
    \n\ -LINK = $0\n\ -LINK2 = $+\n\ -LPAREN= (\n\ -RPAREN= )\n\ -DOLLAR= $\n\ -\n\ -RED = $0\n\ -BLUE = $0\n\ -GREEN = $0\n\ -YELLOW =$0\n\ -BLACK = $0\n\ -WHITE = $0\n\ -\n\ -D_CODE =
    $0
    \n\ -D_COMMENT = $(GREEN $0)\n\ -D_STRING = $(RED $0)\n\ -D_KEYWORD = $(BLUE $0)\n\ -D_PSYMBOL = $(U $0)\n\ -D_PARAM = $(I $0)\n\ -\n\ -DDOC_COMMENT = \n\ -DDOC_DECL = $(DT $(BIG $0))\n\ -DDOC_DECL_DD = $(DD $0)\n\ -DDOC_DITTO = $(BR)$0\n\ -DDOC_SECTIONS = $0\n\ -DDOC_SUMMARY = $0$(BR)$(BR)\n\ -DDOC_DESCRIPTION = $0$(BR)$(BR)\n\ -DDOC_AUTHORS = $(B Authors:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_BUGS = $(RED BUGS:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_COPYRIGHT = $(B Copyright:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_DATE = $(B Date:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_DEPRECATED = $(RED Deprecated:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_EXAMPLES = $(B Examples:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_HISTORY = $(B History:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_LICENSE = $(B License:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_RETURNS = $(B Returns:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_SEE_ALSO = $(B See Also:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_STANDARDS = $(B Standards:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_THROWS = $(B Throws:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_VERSION = $(B Version:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_SECTION_H = $(B $0)$(BR)\n\ -DDOC_SECTION = $0$(BR)$(BR)\n\ -DDOC_MEMBERS = $(DL $0)\n\ -DDOC_MODULE_MEMBERS = $(DDOC_MEMBERS $0)\n\ -DDOC_CLASS_MEMBERS = $(DDOC_MEMBERS $0)\n\ -DDOC_STRUCT_MEMBERS = $(DDOC_MEMBERS $0)\n\ -DDOC_ENUM_MEMBERS = $(DDOC_MEMBERS $0)\n\ -DDOC_TEMPLATE_MEMBERS = $(DDOC_MEMBERS $0)\n\ -DDOC_PARAMS = $(B Params:)$(BR)\n$(TABLE $0)$(BR)\n\ -DDOC_PARAM_ROW = $(TR $0)\n\ -DDOC_PARAM_ID = $(TD $0)\n\ -DDOC_PARAM_DESC = $(TD $0)\n\ -DDOC_BLANKLINE = $(BR)$(BR)\n\ -\n\ -DDOC_PSYMBOL = $(U $0)\n\ -DDOC_KEYWORD = $(B $0)\n\ -DDOC_PARAM = $(I $0)\n\ -\n\ -ESCAPES = //>/\n\ - /&/&/\n\ -"; - -static char ddoc_decl_s[] = "$(DDOC_DECL "; -static char ddoc_decl_e[] = ")\n"; - -static char ddoc_decl_dd_s[] = "$(DDOC_DECL_DD "; -static char ddoc_decl_dd_e[] = ")\n"; - - -/**************************************************** - */ - -void Module::gendocfile() -{ - static OutBuffer mbuf; - static int mbuf_done; - - OutBuffer buf; - - //printf("Module::gendocfile()\n"); - - if (!mbuf_done) // if not already read the ddoc files - { mbuf_done = 1; - - // Use our internal default - mbuf.write(ddoc_default, sizeof(ddoc_default) - 1); - - // Override with DDOCFILE specified in the sc.ini file - char *p = getenv("DDOCFILE"); - if (p) - global.params.ddocfiles->shift(p); - - // Override with the ddoc macro files from the command line - for (size_t i = 0; i < global.params.ddocfiles->dim; i++) - { - FileName f(global.params.ddocfiles->tdata()[i], 0); - File file(&f); - file.readv(); - // BUG: convert file contents to UTF-8 before use - - //printf("file: '%.*s'\n", file.len, file.buffer); - mbuf.write(file.buffer, file.len); - } - } - DocComment::parseMacros(&escapetable, ¯otable, mbuf.data, mbuf.offset); - - Scope *sc = Scope::createGlobal(this); // create root scope - sc->docbuf = &buf; - - DocComment *dc = DocComment::parse(sc, this, comment); - dc->pmacrotable = ¯otable; - dc->pescapetable = &escapetable; - - // Generate predefined macros - - // Set the title to be the name of the module - { const char *p = toPrettyChars(); - Macro::define(¯otable, (unsigned char *)"TITLE", 5, (unsigned char *)p, strlen(p)); - } - - // Set time macros - { time_t t; - time(&t); - char *p = ctime(&t); - p = mem.strdup(p); - Macro::define(¯otable, (unsigned char *)"DATETIME", 8, (unsigned char *)p, strlen(p)); - Macro::define(¯otable, (unsigned char *)"YEAR", 4, (unsigned char *)p + 20, 4); - } - - char *srcfilename = srcfile->toChars(); - Macro::define(¯otable, (unsigned char *)"SRCFILENAME", 11, (unsigned char *)srcfilename, strlen(srcfilename)); - - char *docfilename = docfile->toChars(); - Macro::define(¯otable, (unsigned char *)"DOCFILENAME", 11, (unsigned char *)docfilename, strlen(docfilename)); - - if (dc->copyright) - { - dc->copyright->nooutput = 1; - Macro::define(¯otable, (unsigned char *)"COPYRIGHT", 9, dc->copyright->body, dc->copyright->bodylen); - } - - buf.printf("$(DDOC_COMMENT Generated by Ddoc from %s)\n", srcfile->toChars()); - if (isDocFile) - { - size_t commentlen = strlen((char *)comment); - if (dc->macros) - { - commentlen = dc->macros->name - comment; - dc->macros->write(dc, sc, this, sc->docbuf); - } - sc->docbuf->write(comment, commentlen); - highlightText(NULL, this, sc->docbuf, 0); - } - else - { - dc->writeSections(sc, this, sc->docbuf); - emitMemberComments(sc); - } - - //printf("BODY= '%.*s'\n", buf.offset, buf.data); - Macro::define(¯otable, (unsigned char *)"BODY", 4, buf.data, buf.offset); - - OutBuffer buf2; - buf2.writestring("$(DDOC)\n"); - unsigned end = buf2.offset; - macrotable->expand(&buf2, 0, &end, NULL, 0); - -#if 1 - /* Remove all the escape sequences from buf2, - * and make CR-LF the newline. - */ - { - buf.setsize(0); - buf.reserve(buf2.offset); - unsigned char *p = buf2.data; - for (unsigned j = 0; j < buf2.offset; j++) - { - unsigned char c = p[j]; - if (c == 0xFF && j + 1 < buf2.offset) - { - j++; - continue; - } - if (c == '\n') - buf.writeByte('\r'); - else if (c == '\r') - { - buf.writestring("\r\n"); - if (j + 1 < buf2.offset && p[j + 1] == '\n') - { - j++; - } - continue; - } - buf.writeByte(c); - } - } - - // Transfer image to file - assert(docfile); - docfile->setbuffer(buf.data, buf.offset); - docfile->ref = 1; - char *pt = FileName::path(docfile->toChars()); - if (*pt) - FileName::ensurePathExists(pt); - mem.free(pt); - docfile->writev(); -#else - /* Remove all the escape sequences from buf2 - */ - { unsigned i = 0; - unsigned char *p = buf2.data; - for (unsigned j = 0; j < buf2.offset; j++) - { - if (p[j] == 0xFF && j + 1 < buf2.offset) - { - j++; - continue; - } - p[i] = p[j]; - i++; - } - buf2.setsize(i); - } - - // Transfer image to file - docfile->setbuffer(buf2.data, buf2.offset); - docfile->ref = 1; - char *pt = FileName::path(docfile->toChars()); - if (*pt) - FileName::ensurePathExists(pt); - mem.free(pt); - docfile->writev(); -#endif -} - -/**************************************************** - * Having unmatched parentheses can hose the output of Ddoc, - * as the macros depend on properly nested parentheses. - * This function replaces all ( with $(LPAREN) and ) with $(RPAREN) - * to preserve text literally. This also means macros in the - * text won't be expanded. - */ -void escapeDdocString(OutBuffer *buf, unsigned start) -{ - for (unsigned u = start; u < buf->offset; u++) - { - unsigned char c = buf->data[u]; - switch(c) - { - case '$': - buf->remove(u, 1); - buf->insert(u, "$(DOLLAR)", 9); - u += 8; - break; - - case '(': - buf->remove(u, 1); //remove the ( - buf->insert(u, "$(LPAREN)", 9); //insert this instead - u += 8; //skip over newly inserted macro - break; - - case ')': - buf->remove(u, 1); //remove the ) - buf->insert(u, "$(RPAREN)", 9); //insert this instead - u += 8; //skip over newly inserted macro - break; - } - } -} - -/**************************************************** - * Having unmatched parentheses can hose the output of Ddoc, - * as the macros depend on properly nested parentheses. - - * Fix by replacing unmatched ( with $(LPAREN) and unmatched ) with $(RPAREN). - */ -void escapeStrayParenthesis(OutBuffer *buf, unsigned start, Loc loc) -{ - unsigned par_open = 0; - - for (unsigned u = start; u < buf->offset; u++) - { - unsigned char c = buf->data[u]; - switch(c) - { - case '(': - par_open++; - break; - - case ')': - if (par_open == 0) - { - //stray ')' - if (global.params.warnings) - warning(loc, "Ddoc: Stray ')'. This may cause incorrect Ddoc output." - " Use $(RPAREN) instead for unpaired right parentheses."); - buf->remove(u, 1); //remove the ) - buf->insert(u, "$(RPAREN)", 9); //insert this instead - u += 8; //skip over newly inserted macro - } - else - par_open--; - break; -#if 0 - // For this to work, loc must be set to the beginning of the passed - // text which is currently not possible - // (loc is set to the Loc of the Dsymbol) - case '\n': - loc.linnum++; - break; -#endif - } - } - - if (par_open) // if any unmatched lparens - { par_open = 0; - for (unsigned u = buf->offset; u > start;) - { u--; - unsigned char c = buf->data[u]; - switch(c) - { - case ')': - par_open++; - break; - - case '(': - if (par_open == 0) - { - //stray '(' - if (global.params.warnings) - warning(loc, "Ddoc: Stray '('. This may cause incorrect Ddoc output." - " Use $(LPAREN) instead for unpaired left parentheses."); - buf->remove(u, 1); //remove the ( - buf->insert(u, "$(LPAREN)", 9); //insert this instead - } - else - par_open--; - break; - } - } - } -} - -/******************************* emitComment **********************************/ - -/* - * Emit doc comment to documentation file - */ - -void Dsymbol::emitDitto(Scope *sc) -{ - //printf("Dsymbol::emitDitto() %s %s\n", kind(), toChars()); - OutBuffer *buf = sc->docbuf; - unsigned o; - OutBuffer b; - - b.writestring("$(DDOC_DITTO "); - o = b.offset; - toDocBuffer(&b); - //printf("b: '%.*s'\n", b.offset, b.data); - /* If 'this' is a function template, then highlightCode() was - * already run by FuncDeclaration::toDocbuffer(). - */ - TemplateDeclaration *td; - if (parent && - (td = parent->isTemplateDeclaration()) != NULL && - td->onemember == this) - { - } - else - highlightCode(sc, this, &b, o); - b.writeByte(')'); - buf->spread(sc->lastoffset, b.offset); - memcpy(buf->data + sc->lastoffset, b.data, b.offset); - sc->lastoffset += b.offset; -} - -void ScopeDsymbol::emitMemberComments(Scope *sc) -{ - //printf("ScopeDsymbol::emitMemberComments() %s\n", toChars()); - OutBuffer *buf = sc->docbuf; - - if (members) - { const char *m = "$(DDOC_MEMBERS \n"; - - if (isModule()) - m = "$(DDOC_MODULE_MEMBERS \n"; - else if (isClassDeclaration()) - m = "$(DDOC_CLASS_MEMBERS \n"; - else if (isStructDeclaration()) - m = "$(DDOC_STRUCT_MEMBERS \n"; - else if (isEnumDeclaration()) - m = "$(DDOC_ENUM_MEMBERS \n"; - else if (isTemplateDeclaration()) - m = "$(DDOC_TEMPLATE_MEMBERS \n"; - - unsigned offset1 = buf->offset; // save starting offset - buf->writestring(m); - unsigned offset2 = buf->offset; // to see if we write anything - sc = sc->push(this); - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; - //printf("\ts = '%s'\n", s->toChars()); - s->emitComment(sc); - } - sc->pop(); - if (buf->offset == offset2) - { - /* Didn't write out any members, so back out last write - */ - buf->offset = offset1; - } - else - buf->writestring(")\n"); - } -} - -void emitProtection(OutBuffer *buf, PROT prot) -{ - const char *p; - - switch (prot) - { - case PROTpackage: p = "package"; break; - case PROTprotected: p = "protected"; break; - case PROTexport: p = "export"; break; - default: p = NULL; break; - } - if (p) - buf->printf("%s ", p); -} - -void Dsymbol::emitComment(Scope *sc) { } -void InvariantDeclaration::emitComment(Scope *sc) { } -#if DMDV2 -void PostBlitDeclaration::emitComment(Scope *sc) { } -#endif -void DtorDeclaration::emitComment(Scope *sc) { } -void StaticCtorDeclaration::emitComment(Scope *sc) { } -void StaticDtorDeclaration::emitComment(Scope *sc) { } -void ClassInfoDeclaration::emitComment(Scope *sc) { } -void ModuleInfoDeclaration::emitComment(Scope *sc) { } -void TypeInfoDeclaration::emitComment(Scope *sc) { } - - -void Declaration::emitComment(Scope *sc) -{ - //printf("Declaration::emitComment(%p '%s'), comment = '%s'\n", this, toChars(), comment); - //printf("type = %p\n", type); - - if (protection == PROTprivate || !ident || - (!type && !isCtorDeclaration() && !isAliasDeclaration())) - return; - if (!comment) - return; - - OutBuffer *buf = sc->docbuf; - DocComment *dc = DocComment::parse(sc, this, comment); - unsigned o; - - if (!dc) - { - emitDitto(sc); - return; - } - dc->pmacrotable = &sc->module->macrotable; - - buf->writestring(ddoc_decl_s); - o = buf->offset; - toDocBuffer(buf); - highlightCode(sc, this, buf, o); - sc->lastoffset = buf->offset; - buf->writestring(ddoc_decl_e); - - buf->writestring(ddoc_decl_dd_s); - dc->writeSections(sc, this, buf); - buf->writestring(ddoc_decl_dd_e); -} - -void AggregateDeclaration::emitComment(Scope *sc) -{ - //printf("AggregateDeclaration::emitComment() '%s'\n", toChars()); - if (prot() == PROTprivate) - return; - if (!comment) - return; - - OutBuffer *buf = sc->docbuf; - DocComment *dc = DocComment::parse(sc, this, comment); - - if (!dc) - { - emitDitto(sc); - return; - } - dc->pmacrotable = &sc->module->macrotable; - - buf->writestring(ddoc_decl_s); - toDocBuffer(buf); - sc->lastoffset = buf->offset; - buf->writestring(ddoc_decl_e); - - buf->writestring(ddoc_decl_dd_s); - dc->writeSections(sc, this, buf); - emitMemberComments(sc); - buf->writestring(ddoc_decl_dd_e); -} - -void TemplateDeclaration::emitComment(Scope *sc) -{ - //printf("TemplateDeclaration::emitComment() '%s', kind = %s\n", toChars(), kind()); - if (prot() == PROTprivate) - return; - - unsigned char *com = comment; - int hasmembers = 1; - - Dsymbol *ss = this; - - if (onemember) - { - ss = onemember->isAggregateDeclaration(); - if (!ss) - { - ss = onemember->isFuncDeclaration(); - if (ss) - { hasmembers = 0; - if (com != ss->comment) - com = Lexer::combineComments(com, ss->comment); - } - else - ss = this; - } - } - - if (!com) - return; - - OutBuffer *buf = sc->docbuf; - DocComment *dc = DocComment::parse(sc, this, com); - unsigned o; - - if (!dc) - { - ss->emitDitto(sc); - return; - } - dc->pmacrotable = &sc->module->macrotable; - - buf->writestring(ddoc_decl_s); - o = buf->offset; - ss->toDocBuffer(buf); - if (ss == this) - highlightCode(sc, this, buf, o); - sc->lastoffset = buf->offset; - buf->writestring(ddoc_decl_e); - - buf->writestring(ddoc_decl_dd_s); - dc->writeSections(sc, this, buf); - if (hasmembers) - ((ScopeDsymbol *)ss)->emitMemberComments(sc); - buf->writestring(ddoc_decl_dd_e); -} - -void EnumDeclaration::emitComment(Scope *sc) -{ - if (prot() == PROTprivate) - return; -// if (!comment) - { if (isAnonymous() && members) - { - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; - s->emitComment(sc); - } - return; - } - } - if (!comment) - return; - if (isAnonymous()) - return; - - OutBuffer *buf = sc->docbuf; - DocComment *dc = DocComment::parse(sc, this, comment); - - if (!dc) - { - emitDitto(sc); - return; - } - dc->pmacrotable = &sc->module->macrotable; - - buf->writestring(ddoc_decl_s); - toDocBuffer(buf); - sc->lastoffset = buf->offset; - buf->writestring(ddoc_decl_e); - - buf->writestring(ddoc_decl_dd_s); - dc->writeSections(sc, this, buf); - emitMemberComments(sc); - buf->writestring(ddoc_decl_dd_e); -} - -void EnumMember::emitComment(Scope *sc) -{ - //printf("EnumMember::emitComment(%p '%s'), comment = '%s'\n", this, toChars(), comment); - if (prot() == PROTprivate) - return; - if (!comment) - return; - - OutBuffer *buf = sc->docbuf; - DocComment *dc = DocComment::parse(sc, this, comment); - unsigned o; - - if (!dc) - { - emitDitto(sc); - return; - } - dc->pmacrotable = &sc->module->macrotable; - - buf->writestring(ddoc_decl_s); - o = buf->offset; - toDocBuffer(buf); - highlightCode(sc, this, buf, o); - sc->lastoffset = buf->offset; - buf->writestring(ddoc_decl_e); - - buf->writestring(ddoc_decl_dd_s); - dc->writeSections(sc, this, buf); - buf->writestring(ddoc_decl_dd_e); -} - -/******************************* toDocBuffer **********************************/ - -void Dsymbol::toDocBuffer(OutBuffer *buf) -{ - //printf("Dsymbol::toDocbuffer() %s\n", toChars()); - HdrGenState hgs; - - hgs.ddoc = 1; - toCBuffer(buf, &hgs); -} - -void prefix(OutBuffer *buf, Dsymbol *s) -{ - if (s->isDeprecated()) - buf->writestring("deprecated "); - Declaration *d = s->isDeclaration(); - if (d) - { - emitProtection(buf, d->protection); - if (d->isAbstract()) - buf->writestring("abstract "); - if (d->isStatic()) - buf->writestring("static "); - if (d->isConst()) - buf->writestring("const "); -#if DMDV2 - if (d->isImmutable()) - buf->writestring("immutable "); -#endif - if (d->isFinal()) - buf->writestring("final "); - if (d->isSynchronized()) - buf->writestring("synchronized "); - } -} - -void declarationToDocBuffer(Declaration *decl, OutBuffer *buf, TemplateDeclaration *td) -{ - //printf("declarationToDocBuffer() %s, originalType = %s, td = %s\n", decl->toChars(), decl->originalType ? decl->originalType->toChars() : "--", td ? td->toChars() : "--"); - if (decl->ident) - { - prefix(buf, decl); - - if (decl->type) - { HdrGenState hgs; - hgs.ddoc = 1; - Type *origType = decl->originalType ? decl->originalType : decl->type; - if (origType->ty == Tfunction) - { - TypeFunction *attrType = (TypeFunction*)(decl->ident == Id::ctor ? origType : decl->type); - ((TypeFunction*)origType)->toCBufferWithAttributes(buf, decl->ident, &hgs, attrType, td); - } - else - origType->toCBuffer(buf, decl->ident, &hgs); - } - else - buf->writestring(decl->ident->toChars()); - buf->writestring(";\n"); - } -} - -void Declaration::toDocBuffer(OutBuffer *buf) -{ - declarationToDocBuffer(this, buf, NULL); -} - -void AliasDeclaration::toDocBuffer(OutBuffer *buf) -{ - //printf("AliasDeclaration::toDocbuffer() %s\n", toChars()); - if (ident) - { - if (isDeprecated()) - buf->writestring("deprecated "); - - emitProtection(buf, protection); - buf->writestring("alias "); - buf->writestring(toChars()); - buf->writestring(";\n"); - } -} - - -void TypedefDeclaration::toDocBuffer(OutBuffer *buf) -{ - if (ident) - { - if (isDeprecated()) - buf->writestring("deprecated "); - - emitProtection(buf, protection); - buf->writestring("typedef "); - buf->writestring(toChars()); - buf->writestring(";\n"); - } -} - - -void FuncDeclaration::toDocBuffer(OutBuffer *buf) -{ - //printf("FuncDeclaration::toDocbuffer() %s\n", toChars()); - if (ident) - { - TemplateDeclaration *td; - - if (parent && - (td = parent->isTemplateDeclaration()) != NULL && - td->onemember == this) - { /* It's a function template - */ - unsigned o = buf->offset; - - declarationToDocBuffer(this, buf, td); - - highlightCode(NULL, this, buf, o); - } - else - { - Declaration::toDocBuffer(buf); - } - } -} - -#if DMDV1 -void CtorDeclaration::toDocBuffer(OutBuffer *buf) -{ - HdrGenState hgs; - - buf->writestring("this"); - Parameter::argsToCBuffer(buf, &hgs, arguments, varargs); - buf->writestring(";\n"); -} -#endif - -void AggregateDeclaration::toDocBuffer(OutBuffer *buf) -{ - if (ident) - { -#if 0 - emitProtection(buf, protection); -#endif - buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); - buf->writestring(";\n"); - } -} - -void StructDeclaration::toDocBuffer(OutBuffer *buf) -{ - //printf("StructDeclaration::toDocbuffer() %s\n", toChars()); - if (ident) - { -#if 0 - emitProtection(buf, protection); -#endif - TemplateDeclaration *td; - - if (parent && - (td = parent->isTemplateDeclaration()) != NULL && - td->onemember == this) - { unsigned o = buf->offset; - td->toDocBuffer(buf); - highlightCode(NULL, this, buf, o); - } - else - { - buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); - } - buf->writestring(";\n"); - } -} - -void ClassDeclaration::toDocBuffer(OutBuffer *buf) -{ - //printf("ClassDeclaration::toDocbuffer() %s\n", toChars()); - if (ident) - { -#if 0 - emitProtection(buf, protection); -#endif - TemplateDeclaration *td; - - if (parent && - (td = parent->isTemplateDeclaration()) != NULL && - td->onemember == this) - { unsigned o = buf->offset; - td->toDocBuffer(buf); - highlightCode(NULL, this, buf, o); - } - else - { - if (isAbstract()) - buf->writestring("abstract "); - buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); - } - int any = 0; - for (size_t i = 0; i < baseclasses->dim; i++) - { BaseClass *bc = (*baseclasses)[i]; - - if (bc->protection == PROTprivate) - continue; - if (bc->base && bc->base->ident == Id::Object) - continue; - - if (any) - buf->writestring(", "); - else - { buf->writestring(": "); - any = 1; - } - emitProtection(buf, bc->protection); - if (bc->base) - { - buf->writestring(bc->base->toPrettyChars()); - } - else - { - HdrGenState hgs; - bc->type->toCBuffer(buf, NULL, &hgs); - } - } - buf->writestring(";\n"); - } -} - - -void EnumDeclaration::toDocBuffer(OutBuffer *buf) -{ - if (ident) - { - buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); - buf->writestring(";\n"); - } -} - -void EnumMember::toDocBuffer(OutBuffer *buf) -{ - if (ident) - { - buf->writestring(toChars()); - } -} - - -/********************************* DocComment *********************************/ - -DocComment::DocComment() -{ - memset(this, 0, sizeof(DocComment)); -} - -DocComment *DocComment::parse(Scope *sc, Dsymbol *s, unsigned char *comment) -{ - //printf("parse(%s): '%s'\n", s->toChars(), comment); - if (sc->lastdc && isDitto(comment)) - return NULL; - - DocComment *dc = new DocComment(); - if (!comment) - return dc; - - dc->parseSections(comment); - - for (size_t i = 0; i < dc->sections.dim; i++) - { Section *sec = dc->sections[i]; - - if (icmp("copyright", sec->name, sec->namelen) == 0) - { - dc->copyright = sec; - } - if (icmp("macros", sec->name, sec->namelen) == 0) - { - dc->macros = sec; - } - } - - sc->lastdc = dc; - return dc; -} - -/***************************************** - * Parse next paragraph out of *pcomment. - * Update *pcomment to point past paragraph. - * Returns NULL if no more paragraphs. - * If paragraph ends in 'identifier:', - * then (*pcomment)[0 .. idlen] is the identifier. - */ - -void DocComment::parseSections(unsigned char *comment) -{ unsigned char *p; - unsigned char *pstart; - unsigned char *pend; - unsigned char *idstart; - unsigned idlen; - - unsigned char *name = NULL; - unsigned namelen = 0; - - //printf("parseSections('%s')\n", comment); - p = comment; - while (*p) - { - p = skipwhitespace(p); - pstart = p; - pend = p; - - /* Find end of section, which is ended by one of: - * 'identifier:' (but not inside a code section) - * '\0' - */ - idlen = 0; - int inCode = 0; - while (1) - { - // Check for start/end of a code section - if (*p == '-') - { - int numdash = 0; - while (*p == '-') - { - ++numdash; - p++; - } - // BUG: handle UTF PS and LS too - if (!*p || *p == '\r' || *p == '\n' && numdash >= 3) - inCode ^= 1; - pend = p; - } - - if (!inCode && isIdStart(p)) - { - unsigned char *q = p + utfStride(p); - while (isIdTail(q)) - q += utfStride(q); - if (*q == ':') // identifier: ends it - { idlen = q - p; - idstart = p; - for (pend = p; pend > pstart; pend--) - { if (pend[-1] == '\n') - break; - } - p = q + 1; - break; - } - } - while (1) - { - if (!*p) - goto L1; - if (*p == '\n') - { p++; - if (*p == '\n' && !summary && !namelen && !inCode) - { - pend = p; - p++; - goto L1; - } - break; - } - p++; - pend = p; - } - p = skipwhitespace(p); - } - L1: - - if (namelen || pstart < pend) - { - Section *s; - if (icmp("Params", name, namelen) == 0) - s = new ParamSection(); - else if (icmp("Macros", name, namelen) == 0) - s = new MacroSection(); - else - s = new Section(); - s->name = name; - s->namelen = namelen; - s->body = pstart; - s->bodylen = pend - pstart; - s->nooutput = 0; - - //printf("Section: '%.*s' = '%.*s'\n", s->namelen, s->name, s->bodylen, s->body); - - sections.push(s); - - if (!summary && !namelen) - summary = s; - } - - if (idlen) - { name = idstart; - namelen = idlen; - } - else - { name = NULL; - namelen = 0; - if (!*p) - break; - } - } -} - -void DocComment::writeSections(Scope *sc, Dsymbol *s, OutBuffer *buf) -{ - //printf("DocComment::writeSections()\n"); - if (sections.dim) - { - buf->writestring("$(DDOC_SECTIONS \n"); - for (size_t i = 0; i < sections.dim; i++) - { Section *sec = sections[i]; - - if (sec->nooutput) - continue; - //printf("Section: '%.*s' = '%.*s'\n", sec->namelen, sec->name, sec->bodylen, sec->body); - if (sec->namelen || i) - sec->write(this, sc, s, buf); - else - { - buf->writestring("$(DDOC_SUMMARY "); - unsigned o = buf->offset; - buf->write(sec->body, sec->bodylen); - escapeStrayParenthesis(buf, o, s->loc); - highlightText(sc, s, buf, o); - buf->writestring(")\n"); - } - } - buf->writestring(")\n"); - } - else - { - buf->writestring("$(DDOC_BLANKLINE)\n"); - } -} - -/*************************************************** - */ - -void Section::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) -{ - if (namelen) - { - static const char *table[] = - { "AUTHORS", "BUGS", "COPYRIGHT", "DATE", - "DEPRECATED", "EXAMPLES", "HISTORY", "LICENSE", - "RETURNS", "SEE_ALSO", "STANDARDS", "THROWS", - "VERSION" }; - - for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) - { - if (icmp(table[i], name, namelen) == 0) - { - buf->printf("$(DDOC_%s ", table[i]); - goto L1; - } - } - - buf->writestring("$(DDOC_SECTION "); - // Replace _ characters with spaces - buf->writestring("$(DDOC_SECTION_H "); - unsigned o = buf->offset; - for (unsigned u = 0; u < namelen; u++) - { unsigned char c = name[u]; - buf->writeByte((c == '_') ? ' ' : c); - } - escapeStrayParenthesis(buf, o, s->loc); - buf->writestring(":)\n"); - } - else - { - buf->writestring("$(DDOC_DESCRIPTION "); - } - L1: - unsigned o = buf->offset; - buf->write(body, bodylen); - escapeStrayParenthesis(buf, o, s->loc); - highlightText(sc, s, buf, o); - buf->writestring(")\n"); -} - -/*************************************************** - */ - -void ParamSection::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) -{ - unsigned char *p = body; - unsigned len = bodylen; - unsigned char *pend = p + len; - - unsigned char *tempstart; - unsigned templen; - - unsigned char *namestart; - unsigned namelen = 0; // !=0 if line continuation - - unsigned char *textstart; - unsigned textlen; - - unsigned o; - Parameter *arg; - - buf->writestring("$(DDOC_PARAMS \n"); - while (p < pend) - { - // Skip to start of macro - while (1) - { - switch (*p) - { - case ' ': - case '\t': - p++; - continue; - - case '\n': - p++; - goto Lcont; - - default: - if (isIdStart(p)) - break; - if (namelen) - goto Ltext; // continuation of prev macro - goto Lskipline; - } - break; - } - tempstart = p; - - while (isIdTail(p)) - p += utfStride(p); - templen = p - tempstart; - - while (*p == ' ' || *p == '\t') - p++; - - if (*p != '=') - { if (namelen) - goto Ltext; // continuation of prev macro - goto Lskipline; - } - p++; - - if (namelen) - { // Output existing param - - L1: - //printf("param '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart); - HdrGenState hgs; - buf->writestring("$(DDOC_PARAM_ROW "); - buf->writestring("$(DDOC_PARAM_ID "); - o = buf->offset; - arg = isFunctionParameter(s, namestart, namelen); - if (arg && arg->type && arg->ident) - arg->type->toCBuffer(buf, arg->ident, &hgs); - else - buf->write(namestart, namelen); - escapeStrayParenthesis(buf, o, s->loc); - highlightCode(sc, s, buf, o); - buf->writestring(")\n"); - - buf->writestring("$(DDOC_PARAM_DESC "); - o = buf->offset; - buf->write(textstart, textlen); - escapeStrayParenthesis(buf, o, s->loc); - highlightText(sc, s, buf, o); - buf->writestring(")"); - buf->writestring(")\n"); - namelen = 0; - if (p >= pend) - break; - } - - namestart = tempstart; - namelen = templen; - - while (*p == ' ' || *p == '\t') - p++; - textstart = p; - - Ltext: - while (*p != '\n') - p++; - textlen = p - textstart; - p++; - - Lcont: - continue; - - Lskipline: - // Ignore this line - while (*p++ != '\n') - ; - } - if (namelen) - goto L1; // write out last one - buf->writestring(")\n"); -} - -/*************************************************** - */ - -void MacroSection::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) -{ - //printf("MacroSection::write()\n"); - DocComment::parseMacros(dc->pescapetable, dc->pmacrotable, body, bodylen); -} - -/************************************************ - * Parse macros out of Macros: section. - * Macros are of the form: - * name1 = value1 - * - * name2 = value2 - */ - -void DocComment::parseMacros(Escape **pescapetable, Macro **pmacrotable, unsigned char *m, unsigned mlen) -{ - unsigned char *p = m; - unsigned len = mlen; - unsigned char *pend = p + len; - - unsigned char *tempstart; - unsigned templen; - - unsigned char *namestart; - unsigned namelen = 0; // !=0 if line continuation - - unsigned char *textstart; - unsigned textlen; - - while (p < pend) - { - // Skip to start of macro - while (1) - { - if (p >= pend) - goto Ldone; - switch (*p) - { - case ' ': - case '\t': - p++; - continue; - - case '\n': - p++; - goto Lcont; - - default: - if (isIdStart(p)) - break; - if (namelen) - goto Ltext; // continuation of prev macro - goto Lskipline; - } - break; - } - tempstart = p; - - while (1) - { - if (p >= pend) - goto Ldone; - if (!isIdTail(p)) - break; - p += utfStride(p); - } - templen = p - tempstart; - - while (1) - { - if (p >= pend) - goto Ldone; - if (!(*p == ' ' || *p == '\t')) - break; - p++; - } - - if (*p != '=') - { if (namelen) - goto Ltext; // continuation of prev macro - goto Lskipline; - } - p++; - if (p >= pend) - goto Ldone; - - if (namelen) - { // Output existing macro - L1: - //printf("macro '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart); - if (icmp("ESCAPES", namestart, namelen) == 0) - parseEscapes(pescapetable, textstart, textlen); - else - Macro::define(pmacrotable, namestart, namelen, textstart, textlen); - namelen = 0; - if (p >= pend) - break; - } - - namestart = tempstart; - namelen = templen; - - while (p < pend && (*p == ' ' || *p == '\t')) - p++; - textstart = p; - - Ltext: - while (p < pend && *p != '\n') - p++; - textlen = p - textstart; - - // Remove trailing \r if there is one - if (p > m && p[-1] == '\r') - textlen--; - - p++; - //printf("p = %p, pend = %p\n", p, pend); - - Lcont: - continue; - - Lskipline: - // Ignore this line - while (p < pend && *p++ != '\n') - ; - } -Ldone: - if (namelen) - goto L1; // write out last one -} - -/************************************** - * Parse escapes of the form: - * /c/string/ - * where c is a single character. - * Multiple escapes can be separated - * by whitespace and/or commas. - */ - -void DocComment::parseEscapes(Escape **pescapetable, unsigned char *textstart, unsigned textlen) -{ Escape *escapetable = *pescapetable; - - if (!escapetable) - { escapetable = new Escape; - *pescapetable = escapetable; - } - unsigned char *p = textstart; - unsigned char *pend = p + textlen; - - while (1) - { - while (1) - { - if (p + 4 >= pend) - return; - if (!(*p == ' ' || *p == '\t' || *p == '\n' || *p == ',')) - break; - p++; - } - if (p[0] != '/' || p[2] != '/') - return; - unsigned char c = p[1]; - p += 3; - unsigned char *start = p; - while (1) - { - if (p >= pend) - return; - if (*p == '/') - break; - p++; - } - size_t len = p - start; - char *s = (char *)memcpy(mem.malloc(len + 1), start, len); - s[len] = 0; - escapetable->strings[c] = s; - //printf("%c = '%s'\n", c, s); - p++; - } -} - - -/****************************************** - * Compare 0-terminated string with length terminated string. - * Return < 0, ==0, > 0 - */ - -int cmp(const char *stringz, void *s, size_t slen) -{ - size_t len1 = strlen(stringz); - - if (len1 != slen) - return len1 - slen; - return memcmp(stringz, s, slen); -} - -int icmp(const char *stringz, void *s, size_t slen) -{ - size_t len1 = strlen(stringz); - - if (len1 != slen) - return len1 - slen; - return memicmp(stringz, (char *)s, slen); -} - -/***************************************** - * Return !=0 if comment consists entirely of "ditto". - */ - -int isDitto(unsigned char *comment) -{ - if (comment) - { - unsigned char *p = skipwhitespace(comment); - - if (memicmp((char *)p, "ditto", 5) == 0 && *skipwhitespace(p + 5) == 0) - return 1; - } - return 0; -} - -/********************************************** - * Skip white space. - */ - -unsigned char *skipwhitespace(unsigned char *p) -{ - for (; 1; p++) - { switch (*p) - { - case ' ': - case '\t': - case '\n': - continue; - } - break; - } - return p; -} - - -/************************************************ - * Scan forward to one of: - * start of identifier - * beginning of next line - * end of buf - */ - -unsigned skiptoident(OutBuffer *buf, size_t i) -{ - while (i < buf->offset) - { dchar_t c; - - size_t oi = i; - if (utf_decodeChar((unsigned char *)buf->data, buf->offset, &i, &c)) - /* Ignore UTF errors, but still consume input - */ - break; - if (c >= 0x80) - { - if (!isUniAlpha(c)) - continue; - } - else if (!(isalpha(c) || c == '_' || c == '\n')) - continue; - i = oi; - break; - } - return i; -} - -/************************************************ - * Scan forward past end of identifier. - */ - -unsigned skippastident(OutBuffer *buf, size_t i) -{ - while (i < buf->offset) - { dchar_t c; - - size_t oi = i; - if (utf_decodeChar((unsigned char *)buf->data, buf->offset, &i, &c)) - /* Ignore UTF errors, but still consume input - */ - break; - if (c >= 0x80) - { - if (isUniAlpha(c)) - continue; - } - else if (isalnum(c) || c == '_') - continue; - i = oi; - break; - } - return i; -} - - -/************************************************ - * Scan forward past URL starting at i. - * We don't want to highlight parts of a URL. - * Returns: - * i if not a URL - * index just past it if it is a URL - */ - -unsigned skippastURL(OutBuffer *buf, size_t i) -{ unsigned length = buf->offset - i; - unsigned char *p = &buf->data[i]; - unsigned j; - unsigned sawdot = 0; - - if (length > 7 && memicmp((char *)p, "http://", 7) == 0) - { - j = 7; - } - else if (length > 8 && memicmp((char *)p, "https://", 8) == 0) - { - j = 8; - } - else - goto Lno; - - for (; j < length; j++) - { unsigned char c = p[j]; - if (isalnum(c)) - continue; - if (c == '-' || c == '_' || c == '?' || - c == '=' || c == '%' || c == '&' || - c == '/' || c == '+' || c == '#' || - c == '~') - continue; - if (c == '.') - { - sawdot = 1; - continue; - } - break; - } - if (sawdot) - return i + j; - -Lno: - return i; -} - - -/**************************************************** - */ - -int isKeyword(unsigned char *p, unsigned len) -{ - static const char *table[] = { "true", "false", "null" }; - - for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) - { - if (cmp(table[i], p, len) == 0) - return 1; - } - return 0; -} - -/**************************************************** - */ - -Parameter *isFunctionParameter(Dsymbol *s, unsigned char *p, unsigned len) -{ - FuncDeclaration *f = s->isFuncDeclaration(); - - /* f->type may be NULL for template members. - */ - if (f && f->type) - { - TypeFunction *tf; - if (f->originalType) - { - tf = (TypeFunction *)f->originalType; - } - else - tf = (TypeFunction *)f->type; - - if (tf->parameters) - { - for (size_t k = 0; k < tf->parameters->dim; k++) - { Parameter *arg = (*tf->parameters)[k]; - - if (arg->ident && cmp(arg->ident->toChars(), p, len) == 0) - { - return arg; - } - } - } - } - return NULL; -} - -/************************************************** - * Highlight text section. - */ - -void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) -{ - //printf("highlightText()\n"); - const char *sid = s->ident->toChars(); - FuncDeclaration *f = s->isFuncDeclaration(); - unsigned char *p; - const char *se; - - int leadingBlank = 1; - int inCode = 0; - int inComment = 0; // in comment - unsigned iCodeStart; // start of code section - - unsigned iLineStart = offset; - - for (unsigned i = offset; i < buf->offset; i++) - { unsigned char c = buf->data[i]; - - Lcont: - switch (c) - { - case ' ': - case '\t': - break; - - case '\n': - if (sc && !inCode && i == iLineStart && i + 1 < buf->offset) // if "\n\n" - { - static char blankline[] = "$(DDOC_BLANKLINE)\n"; - - i = buf->insert(i, blankline, sizeof(blankline) - 1); - } - leadingBlank = 1; - iLineStart = i + 1; - break; - - case '<': - leadingBlank = 0; - if (inCode) - break; - p = &buf->data[i]; - - // Skip over comments - if (p[1] == '!' && p[2] == '-' && p[3] == '-') - { unsigned j = i + 4; - p += 4; - while (1) - { - if (j == buf->offset) - goto L1; - if (p[0] == '-' && p[1] == '-' && p[2] == '>') - { - i = j + 2; // place on closing '>' - break; - } - j++; - p++; - } - break; - } - - // Skip over HTML tag - if (isalpha(p[1]) || (p[1] == '/' && isalpha(p[2]))) - { unsigned j = i + 2; - p += 2; - while (1) - { - if (j == buf->offset) - goto L1; - if (p[0] == '>') - { - i = j; // place on closing '>' - break; - } - j++; - p++; - } - break; - } - - L1: - // Replace '<' with '<' character entity - se = Escape::escapeChar('<'); - if (se) - { size_t len = strlen(se); - buf->remove(i, 1); - i = buf->insert(i, se, len); - i--; // point to ';' - } - break; - - case '>': - leadingBlank = 0; - if (inCode) - break; - // Replace '>' with '>' character entity - se = Escape::escapeChar('>'); - if (se) - { size_t len = strlen(se); - buf->remove(i, 1); - i = buf->insert(i, se, len); - i--; // point to ';' - } - break; - - case '&': - leadingBlank = 0; - if (inCode) - break; - p = &buf->data[i]; - if (p[1] == '#' || isalpha(p[1])) - break; // already a character entity - // Replace '&' with '&' character entity - se = Escape::escapeChar('&'); - if (se) - { size_t len = strlen(se); - buf->remove(i, 1); - i = buf->insert(i, se, len); - i--; // point to ';' - } - break; - - case '-': - /* A line beginning with --- delimits a code section. - * inCode tells us if it is start or end of a code section. - */ - if (leadingBlank) - { int istart = i; - int eollen = 0; - - leadingBlank = 0; - while (1) - { - ++i; - if (i >= buf->offset) - break; - c = buf->data[i]; - if (c == '\n') - { eollen = 1; - break; - } - if (c == '\r') - { - eollen = 1; - if (i + 1 >= buf->offset) - break; - if (buf->data[i + 1] == '\n') - { eollen = 2; - break; - } - } - // BUG: handle UTF PS and LS too - if (c != '-') - goto Lcont; - } - if (i - istart < 3) - goto Lcont; - - // We have the start/end of a code section - - // Remove the entire --- line, including blanks and \n - buf->remove(iLineStart, i - iLineStart + eollen); - i = iLineStart; - - if (inCode && (i <= iCodeStart)) - { // Empty code section, just remove it completely. - inCode = 0; - break; - } - - if (inCode) - { - inCode = 0; - // The code section is from iCodeStart to i - OutBuffer codebuf; - - codebuf.write(buf->data + iCodeStart, i - iCodeStart); - codebuf.writeByte(0); - highlightCode2(sc, s, &codebuf, 0); - buf->remove(iCodeStart, i - iCodeStart); - i = buf->insert(iCodeStart, codebuf.data, codebuf.offset); - i = buf->insert(i, ")\n", 2); - i--; - } - else - { static char pre[] = "$(D_CODE \n"; - - inCode = 1; - i = buf->insert(i, pre, sizeof(pre) - 1); - iCodeStart = i; - i--; // place i on > - leadingBlank = true; - } - } - break; - - default: - leadingBlank = 0; - if (sc && !inCode && isIdStart(&buf->data[i])) - { unsigned j; - - j = skippastident(buf, i); - if (j > i) - { - unsigned k = skippastURL(buf, i); - if (k > i) - { i = k - 1; - break; - } - - if (buf->data[i] == '_') // leading '_' means no highlight - { - buf->remove(i, 1); - i = j - 1; - } - else - { - if (cmp(sid, buf->data + i, j - i) == 0) - { - i = buf->bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1; - break; - } - else if (isKeyword(buf->data + i, j - i)) - { - i = buf->bracket(i, "$(DDOC_KEYWORD ", j, ")") - 1; - break; - } - else - { - if (f && isFunctionParameter(f, buf->data + i, j - i)) - { - //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); - i = buf->bracket(i, "$(DDOC_PARAM ", j, ")") - 1; - break; - } - } - i = j - 1; - } - } - } - break; - } - } - if (inCode) - s->error("unmatched --- in DDoc comment"); - ; -} - -/************************************************** - * Highlight code for DDOC section. - */ - -void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) -{ - char *sid = s->ident->toChars(); - FuncDeclaration *f = s->isFuncDeclaration(); - - //printf("highlightCode(s = '%s', kind = %s)\n", sid, s->kind()); - for (unsigned i = offset; i < buf->offset; i++) - { unsigned char c = buf->data[i]; - const char *se; - - se = Escape::escapeChar(c); - if (se) - { - size_t len = strlen(se); - buf->remove(i, 1); - i = buf->insert(i, se, len); - i--; // point to ';' - } - else if (isIdStart(&buf->data[i])) - { unsigned j; - - j = skippastident(buf, i); - if (j > i) - { - if (cmp(sid, buf->data + i, j - i) == 0) - { - i = buf->bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1; - continue; - } - else if (f) - { - if (isFunctionParameter(f, buf->data + i, j - i)) - { - //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); - i = buf->bracket(i, "$(DDOC_PARAM ", j, ")") - 1; - continue; - } - } - i = j - 1; - } - } - } -} - -/**************************************** - */ - -void highlightCode3(OutBuffer *buf, unsigned char *p, unsigned char *pend) -{ - for (; p < pend; p++) - { const char *s = Escape::escapeChar(*p); - if (s) - buf->writestring(s); - else - buf->writeByte(*p); - } -} - -/************************************************** - * Highlight code for CODE section. - */ - - -void highlightCode2(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) -{ - char *sid = s->ident->toChars(); - FuncDeclaration *f = s->isFuncDeclaration(); - unsigned errorsave = global.errors; - Lexer lex(NULL, buf->data, 0, buf->offset - 1, 0, 1); - Token tok; - OutBuffer res; - unsigned char *lastp = buf->data; - const char *highlight; - - //printf("highlightCode2('%.*s')\n", buf->offset - 1, buf->data); - res.reserve(buf->offset); - while (1) - { - lex.scan(&tok); - highlightCode3(&res, lastp, tok.ptr); - highlight = NULL; - switch (tok.value) - { - case TOKidentifier: - if (!sc) - break; - if (cmp(sid, tok.ptr, lex.p - tok.ptr) == 0) - { - highlight = "$(D_PSYMBOL "; - break; - } - else if (f) - { - if (isFunctionParameter(f, tok.ptr, lex.p - tok.ptr)) - { - //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); - highlight = "$(D_PARAM "; - break; - } - } - break; - - case TOKcomment: - highlight = "$(D_COMMENT "; - break; - - case TOKstring: - highlight = "$(D_STRING "; - break; - - default: - if (tok.isKeyword()) - highlight = "$(D_KEYWORD "; - break; - } - if (highlight) - res.writestring(highlight); - highlightCode3(&res, tok.ptr, lex.p); - if (highlight) - res.writeByte(')'); - if (tok.value == TOKeof) - break; - lastp = lex.p; - } - buf->setsize(offset); - buf->write(&res); - global.errors = errorsave; -} - -/*************************************** - * Find character string to replace c with. - */ - -const char *Escape::escapeChar(unsigned c) -{ const char *s; - - switch (c) - { - case '<': - s = "<"; - break; - case '>': - s = ">"; - break; - case '&': - s = "&"; - break; - default: - s = NULL; - break; - } - return s; -} - -/**************************************** - * Determine if p points to the start of an identifier. - */ - -int isIdStart(unsigned char *p) -{ - unsigned c = *p; - if (isalpha(c) || c == '_') - return 1; - if (c >= 0x80) - { size_t i = 0; - if (utf_decodeChar(p, 4, &i, &c)) - return 0; // ignore errors - if (isUniAlpha(c)) - return 1; - } - return 0; -} - -/**************************************** - * Determine if p points to the rest of an identifier. - */ - -int isIdTail(unsigned char *p) -{ - unsigned c = *p; - if (isalnum(c) || c == '_') - return 1; - if (c >= 0x80) - { size_t i = 0; - if (utf_decodeChar(p, 4, &i, &c)) - return 0; // ignore errors - if (isUniAlpha(c)) - return 1; - } - return 0; -} - -/***************************************** - * Return number of bytes in UTF character. - */ - -int utfStride(unsigned char *p) -{ - unsigned c = *p; - if (c < 0x80) - return 1; - size_t i = 0; - utf_decodeChar(p, 4, &i, &c); // ignore errors, but still consume input - return i; -} + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2012 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +// This implements the Ddoc capability. + +#include +#include +#include +#include +#include + +#include "rmem.h" +#include "root.h" + +#include "mars.h" +#include "dsymbol.h" +#include "macro.h" +#include "template.h" +#include "lexer.h" +#include "aggregate.h" +#include "declaration.h" +#include "enum.h" +#include "id.h" +#include "module.h" +#include "scope.h" +#include "hdrgen.h" +#include "doc.h" +#include "mtype.h" +#include "utf.h" + +struct Escape +{ + const char *strings[256]; + + static const char *escapeChar(unsigned c); +}; + +struct Section +{ + unsigned char *name; + unsigned namelen; + + unsigned char *body; + unsigned bodylen; + + int nooutput; + + virtual void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf); +}; + +struct ParamSection : Section +{ + void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf); +}; + +struct MacroSection : Section +{ + void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf); +}; + +typedef ArrayBase
    Sections; + +struct DocComment +{ + Sections sections; // Section*[] + + Section *summary; + Section *copyright; + Section *macros; + Macro **pmacrotable; + Escape **pescapetable; + + DocComment(); + + static DocComment *parse(Scope *sc, Dsymbol *s, unsigned char *comment); + static void parseMacros(Escape **pescapetable, Macro **pmacrotable, unsigned char *m, unsigned mlen); + static void parseEscapes(Escape **pescapetable, unsigned char *textstart, unsigned textlen); + + void parseSections(unsigned char *comment); + void writeSections(Scope *sc, Dsymbol *s, OutBuffer *buf); +}; + + +int cmp(const char *stringz, void *s, size_t slen); +int icmp(const char *stringz, void *s, size_t slen); +int isDitto(unsigned char *comment); +unsigned char *skipwhitespace(unsigned char *p); +unsigned skiptoident(OutBuffer *buf, size_t i); +unsigned skippastident(OutBuffer *buf, size_t i); +unsigned skippastURL(OutBuffer *buf, size_t i); +void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); +void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); +void highlightCode2(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); +Parameter *isFunctionParameter(Dsymbol *s, unsigned char *p, unsigned len); + +int isIdStart(unsigned char *p); +int isIdTail(unsigned char *p); +int utfStride(unsigned char *p); + +static unsigned char ddoc_default[] = "\ +DDOC = \n\ + \n\ + $(TITLE)\n\ + \n\ +

    $(TITLE)

    \n\ + $(BODY)\n\ +
    $(SMALL Page generated by $(LINK2 http://www.digitalmars.com/d/2.0/ddoc.html, Ddoc). $(COPYRIGHT))\n\ + \n\ +\n\ +B = $0\n\ +I = $0\n\ +U = $0\n\ +P =

    $0

    \n\ +DL =
    $0
    \n\ +DT =
    $0
    \n\ +DD =
    $0
    \n\ +TABLE = $0
    \n\ +TR = $0\n\ +TH = $0\n\ +TD = $0\n\ +OL =
      $0
    \n\ +UL =
      $0
    \n\ +LI =
  • $0
  • \n\ +BIG = $0\n\ +SMALL = $0\n\ +BR =
    \n\ +LINK = $0\n\ +LINK2 = $+\n\ +LPAREN= (\n\ +RPAREN= )\n\ +DOLLAR= $\n\ +\n\ +RED = $0\n\ +BLUE = $0\n\ +GREEN = $0\n\ +YELLOW =$0\n\ +BLACK = $0\n\ +WHITE = $0\n\ +\n\ +D_CODE =
    $0
    \n\ +D_COMMENT = $(GREEN $0)\n\ +D_STRING = $(RED $0)\n\ +D_KEYWORD = $(BLUE $0)\n\ +D_PSYMBOL = $(U $0)\n\ +D_PARAM = $(I $0)\n\ +\n\ +DDOC_COMMENT = \n\ +DDOC_DECL = $(DT $(BIG $0))\n\ +DDOC_DECL_DD = $(DD $0)\n\ +DDOC_DITTO = $(BR)$0\n\ +DDOC_SECTIONS = $0\n\ +DDOC_SUMMARY = $0$(BR)$(BR)\n\ +DDOC_DESCRIPTION = $0$(BR)$(BR)\n\ +DDOC_AUTHORS = $(B Authors:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_BUGS = $(RED BUGS:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_COPYRIGHT = $(B Copyright:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_DATE = $(B Date:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_DEPRECATED = $(RED Deprecated:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_EXAMPLES = $(B Examples:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_HISTORY = $(B History:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_LICENSE = $(B License:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_RETURNS = $(B Returns:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_SEE_ALSO = $(B See Also:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_STANDARDS = $(B Standards:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_THROWS = $(B Throws:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_VERSION = $(B Version:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_SECTION_H = $(B $0)$(BR)\n\ +DDOC_SECTION = $0$(BR)$(BR)\n\ +DDOC_MEMBERS = $(DL $0)\n\ +DDOC_MODULE_MEMBERS = $(DDOC_MEMBERS $0)\n\ +DDOC_CLASS_MEMBERS = $(DDOC_MEMBERS $0)\n\ +DDOC_STRUCT_MEMBERS = $(DDOC_MEMBERS $0)\n\ +DDOC_ENUM_MEMBERS = $(DDOC_MEMBERS $0)\n\ +DDOC_TEMPLATE_MEMBERS = $(DDOC_MEMBERS $0)\n\ +DDOC_PARAMS = $(B Params:)$(BR)\n$(TABLE $0)$(BR)\n\ +DDOC_PARAM_ROW = $(TR $0)\n\ +DDOC_PARAM_ID = $(TD $0)\n\ +DDOC_PARAM_DESC = $(TD $0)\n\ +DDOC_BLANKLINE = $(BR)$(BR)\n\ +\n\ +DDOC_PSYMBOL = $(U $0)\n\ +DDOC_KEYWORD = $(B $0)\n\ +DDOC_PARAM = $(I $0)\n\ +\n\ +ESCAPES = //>/\n\ + /&/&/\n\ +"; + +static char ddoc_decl_s[] = "$(DDOC_DECL "; +static char ddoc_decl_e[] = ")\n"; + +static char ddoc_decl_dd_s[] = "$(DDOC_DECL_DD "; +static char ddoc_decl_dd_e[] = ")\n"; + + +/**************************************************** + */ + +void Module::gendocfile() +{ + static OutBuffer mbuf; + static int mbuf_done; + + OutBuffer buf; + + //printf("Module::gendocfile()\n"); + + if (!mbuf_done) // if not already read the ddoc files + { mbuf_done = 1; + + // Use our internal default + mbuf.write(ddoc_default, sizeof(ddoc_default) - 1); + + // Override with DDOCFILE specified in the sc.ini file + char *p = getenv("DDOCFILE"); + if (p) + global.params.ddocfiles->shift(p); + + // Override with the ddoc macro files from the command line + for (size_t i = 0; i < global.params.ddocfiles->dim; i++) + { + FileName f(global.params.ddocfiles->tdata()[i], 0); + File file(&f); + file.readv(); + // BUG: convert file contents to UTF-8 before use + + //printf("file: '%.*s'\n", file.len, file.buffer); + mbuf.write(file.buffer, file.len); + } + } + DocComment::parseMacros(&escapetable, ¯otable, mbuf.data, mbuf.offset); + + Scope *sc = Scope::createGlobal(this); // create root scope + sc->docbuf = &buf; + + DocComment *dc = DocComment::parse(sc, this, comment); + dc->pmacrotable = ¯otable; + dc->pescapetable = &escapetable; + + // Generate predefined macros + + // Set the title to be the name of the module + { const char *p = toPrettyChars(); + Macro::define(¯otable, (unsigned char *)"TITLE", 5, (unsigned char *)p, strlen(p)); + } + + // Set time macros + { time_t t; + time(&t); + char *p = ctime(&t); + p = mem.strdup(p); + Macro::define(¯otable, (unsigned char *)"DATETIME", 8, (unsigned char *)p, strlen(p)); + Macro::define(¯otable, (unsigned char *)"YEAR", 4, (unsigned char *)p + 20, 4); + } + + char *srcfilename = srcfile->toChars(); + Macro::define(¯otable, (unsigned char *)"SRCFILENAME", 11, (unsigned char *)srcfilename, strlen(srcfilename)); + + char *docfilename = docfile->toChars(); + Macro::define(¯otable, (unsigned char *)"DOCFILENAME", 11, (unsigned char *)docfilename, strlen(docfilename)); + + if (dc->copyright) + { + dc->copyright->nooutput = 1; + Macro::define(¯otable, (unsigned char *)"COPYRIGHT", 9, dc->copyright->body, dc->copyright->bodylen); + } + + buf.printf("$(DDOC_COMMENT Generated by Ddoc from %s)\n", srcfile->toChars()); + if (isDocFile) + { + size_t commentlen = strlen((char *)comment); + if (dc->macros) + { + commentlen = dc->macros->name - comment; + dc->macros->write(dc, sc, this, sc->docbuf); + } + sc->docbuf->write(comment, commentlen); + highlightText(NULL, this, sc->docbuf, 0); + } + else + { + dc->writeSections(sc, this, sc->docbuf); + emitMemberComments(sc); + } + + //printf("BODY= '%.*s'\n", buf.offset, buf.data); + Macro::define(¯otable, (unsigned char *)"BODY", 4, buf.data, buf.offset); + + OutBuffer buf2; + buf2.writestring("$(DDOC)\n"); + unsigned end = buf2.offset; + macrotable->expand(&buf2, 0, &end, NULL, 0); + +#if 1 + /* Remove all the escape sequences from buf2, + * and make CR-LF the newline. + */ + { + buf.setsize(0); + buf.reserve(buf2.offset); + unsigned char *p = buf2.data; + for (unsigned j = 0; j < buf2.offset; j++) + { + unsigned char c = p[j]; + if (c == 0xFF && j + 1 < buf2.offset) + { + j++; + continue; + } + if (c == '\n') + buf.writeByte('\r'); + else if (c == '\r') + { + buf.writestring("\r\n"); + if (j + 1 < buf2.offset && p[j + 1] == '\n') + { + j++; + } + continue; + } + buf.writeByte(c); + } + } + + // Transfer image to file + assert(docfile); + docfile->setbuffer(buf.data, buf.offset); + docfile->ref = 1; + char *pt = FileName::path(docfile->toChars()); + if (*pt) + FileName::ensurePathExists(pt); + mem.free(pt); + docfile->writev(); +#else + /* Remove all the escape sequences from buf2 + */ + { unsigned i = 0; + unsigned char *p = buf2.data; + for (unsigned j = 0; j < buf2.offset; j++) + { + if (p[j] == 0xFF && j + 1 < buf2.offset) + { + j++; + continue; + } + p[i] = p[j]; + i++; + } + buf2.setsize(i); + } + + // Transfer image to file + docfile->setbuffer(buf2.data, buf2.offset); + docfile->ref = 1; + char *pt = FileName::path(docfile->toChars()); + if (*pt) + FileName::ensurePathExists(pt); + mem.free(pt); + docfile->writev(); +#endif +} + +/**************************************************** + * Having unmatched parentheses can hose the output of Ddoc, + * as the macros depend on properly nested parentheses. + * This function replaces all ( with $(LPAREN) and ) with $(RPAREN) + * to preserve text literally. This also means macros in the + * text won't be expanded. + */ +void escapeDdocString(OutBuffer *buf, unsigned start) +{ + for (unsigned u = start; u < buf->offset; u++) + { + unsigned char c = buf->data[u]; + switch(c) + { + case '$': + buf->remove(u, 1); + buf->insert(u, "$(DOLLAR)", 9); + u += 8; + break; + + case '(': + buf->remove(u, 1); //remove the ( + buf->insert(u, "$(LPAREN)", 9); //insert this instead + u += 8; //skip over newly inserted macro + break; + + case ')': + buf->remove(u, 1); //remove the ) + buf->insert(u, "$(RPAREN)", 9); //insert this instead + u += 8; //skip over newly inserted macro + break; + } + } +} + +/**************************************************** + * Having unmatched parentheses can hose the output of Ddoc, + * as the macros depend on properly nested parentheses. + + * Fix by replacing unmatched ( with $(LPAREN) and unmatched ) with $(RPAREN). + */ +void escapeStrayParenthesis(OutBuffer *buf, unsigned start, Loc loc) +{ + unsigned par_open = 0; + + for (unsigned u = start; u < buf->offset; u++) + { + unsigned char c = buf->data[u]; + switch(c) + { + case '(': + par_open++; + break; + + case ')': + if (par_open == 0) + { + //stray ')' + if (global.params.warnings) + warning(loc, "Ddoc: Stray ')'. This may cause incorrect Ddoc output." + " Use $(RPAREN) instead for unpaired right parentheses."); + buf->remove(u, 1); //remove the ) + buf->insert(u, "$(RPAREN)", 9); //insert this instead + u += 8; //skip over newly inserted macro + } + else + par_open--; + break; +#if 0 + // For this to work, loc must be set to the beginning of the passed + // text which is currently not possible + // (loc is set to the Loc of the Dsymbol) + case '\n': + loc.linnum++; + break; +#endif + } + } + + if (par_open) // if any unmatched lparens + { par_open = 0; + for (unsigned u = buf->offset; u > start;) + { u--; + unsigned char c = buf->data[u]; + switch(c) + { + case ')': + par_open++; + break; + + case '(': + if (par_open == 0) + { + //stray '(' + if (global.params.warnings) + warning(loc, "Ddoc: Stray '('. This may cause incorrect Ddoc output." + " Use $(LPAREN) instead for unpaired left parentheses."); + buf->remove(u, 1); //remove the ( + buf->insert(u, "$(LPAREN)", 9); //insert this instead + } + else + par_open--; + break; + } + } + } +} + +/******************************* emitComment **********************************/ + +/* + * Emit doc comment to documentation file + */ + +void Dsymbol::emitDitto(Scope *sc) +{ + //printf("Dsymbol::emitDitto() %s %s\n", kind(), toChars()); + OutBuffer *buf = sc->docbuf; + unsigned o; + OutBuffer b; + + b.writestring("$(DDOC_DITTO "); + o = b.offset; + toDocBuffer(&b); + //printf("b: '%.*s'\n", b.offset, b.data); + /* If 'this' is a function template, then highlightCode() was + * already run by FuncDeclaration::toDocbuffer(). + */ + TemplateDeclaration *td; + if (parent && + (td = parent->isTemplateDeclaration()) != NULL && + td->onemember == this) + { + } + else + highlightCode(sc, this, &b, o); + b.writeByte(')'); + buf->spread(sc->lastoffset, b.offset); + memcpy(buf->data + sc->lastoffset, b.data, b.offset); + sc->lastoffset += b.offset; +} + +void ScopeDsymbol::emitMemberComments(Scope *sc) +{ + //printf("ScopeDsymbol::emitMemberComments() %s\n", toChars()); + OutBuffer *buf = sc->docbuf; + + if (members) + { const char *m = "$(DDOC_MEMBERS \n"; + + if (isModule()) + m = "$(DDOC_MODULE_MEMBERS \n"; + else if (isClassDeclaration()) + m = "$(DDOC_CLASS_MEMBERS \n"; + else if (isStructDeclaration()) + m = "$(DDOC_STRUCT_MEMBERS \n"; + else if (isEnumDeclaration()) + m = "$(DDOC_ENUM_MEMBERS \n"; + else if (isTemplateDeclaration()) + m = "$(DDOC_TEMPLATE_MEMBERS \n"; + + unsigned offset1 = buf->offset; // save starting offset + buf->writestring(m); + unsigned offset2 = buf->offset; // to see if we write anything + sc = sc->push(this); + for (size_t i = 0; i < members->dim; i++) + { + Dsymbol *s = (*members)[i]; + //printf("\ts = '%s'\n", s->toChars()); + s->emitComment(sc); + } + sc->pop(); + if (buf->offset == offset2) + { + /* Didn't write out any members, so back out last write + */ + buf->offset = offset1; + } + else + buf->writestring(")\n"); + } +} + +void emitProtection(OutBuffer *buf, PROT prot) +{ + const char *p; + + switch (prot) + { + case PROTpackage: p = "package"; break; + case PROTprotected: p = "protected"; break; + case PROTexport: p = "export"; break; + default: p = NULL; break; + } + if (p) + buf->printf("%s ", p); +} + +void Dsymbol::emitComment(Scope *sc) { } +void InvariantDeclaration::emitComment(Scope *sc) { } +#if DMDV2 +void PostBlitDeclaration::emitComment(Scope *sc) { } +#endif +void DtorDeclaration::emitComment(Scope *sc) { } +void StaticCtorDeclaration::emitComment(Scope *sc) { } +void StaticDtorDeclaration::emitComment(Scope *sc) { } +void ClassInfoDeclaration::emitComment(Scope *sc) { } +void ModuleInfoDeclaration::emitComment(Scope *sc) { } +void TypeInfoDeclaration::emitComment(Scope *sc) { } + + +void Declaration::emitComment(Scope *sc) +{ + //printf("Declaration::emitComment(%p '%s'), comment = '%s'\n", this, toChars(), comment); + //printf("type = %p\n", type); + + if (protection == PROTprivate || !ident || + (!type && !isCtorDeclaration() && !isAliasDeclaration())) + return; + if (!comment) + return; + + OutBuffer *buf = sc->docbuf; + DocComment *dc = DocComment::parse(sc, this, comment); + unsigned o; + + if (!dc) + { + emitDitto(sc); + return; + } + dc->pmacrotable = &sc->module->macrotable; + + buf->writestring(ddoc_decl_s); + o = buf->offset; + toDocBuffer(buf); + highlightCode(sc, this, buf, o); + sc->lastoffset = buf->offset; + buf->writestring(ddoc_decl_e); + + buf->writestring(ddoc_decl_dd_s); + dc->writeSections(sc, this, buf); + buf->writestring(ddoc_decl_dd_e); +} + +void AggregateDeclaration::emitComment(Scope *sc) +{ + //printf("AggregateDeclaration::emitComment() '%s'\n", toChars()); + if (prot() == PROTprivate) + return; + if (!comment) + return; + + OutBuffer *buf = sc->docbuf; + DocComment *dc = DocComment::parse(sc, this, comment); + + if (!dc) + { + emitDitto(sc); + return; + } + dc->pmacrotable = &sc->module->macrotable; + + buf->writestring(ddoc_decl_s); + toDocBuffer(buf); + sc->lastoffset = buf->offset; + buf->writestring(ddoc_decl_e); + + buf->writestring(ddoc_decl_dd_s); + dc->writeSections(sc, this, buf); + emitMemberComments(sc); + buf->writestring(ddoc_decl_dd_e); +} + +void TemplateDeclaration::emitComment(Scope *sc) +{ + //printf("TemplateDeclaration::emitComment() '%s', kind = %s\n", toChars(), kind()); + if (prot() == PROTprivate) + return; + + unsigned char *com = comment; + int hasmembers = 1; + + Dsymbol *ss = this; + + if (onemember) + { + ss = onemember->isAggregateDeclaration(); + if (!ss) + { + ss = onemember->isFuncDeclaration(); + if (ss) + { hasmembers = 0; + if (com != ss->comment) + com = Lexer::combineComments(com, ss->comment); + } + else + ss = this; + } + } + + if (!com) + return; + + OutBuffer *buf = sc->docbuf; + DocComment *dc = DocComment::parse(sc, this, com); + unsigned o; + + if (!dc) + { + ss->emitDitto(sc); + return; + } + dc->pmacrotable = &sc->module->macrotable; + + buf->writestring(ddoc_decl_s); + o = buf->offset; + ss->toDocBuffer(buf); + if (ss == this) + highlightCode(sc, this, buf, o); + sc->lastoffset = buf->offset; + buf->writestring(ddoc_decl_e); + + buf->writestring(ddoc_decl_dd_s); + dc->writeSections(sc, this, buf); + if (hasmembers) + ((ScopeDsymbol *)ss)->emitMemberComments(sc); + buf->writestring(ddoc_decl_dd_e); +} + +void EnumDeclaration::emitComment(Scope *sc) +{ + if (prot() == PROTprivate) + return; +// if (!comment) + { if (isAnonymous() && members) + { + for (size_t i = 0; i < members->dim; i++) + { + Dsymbol *s = (*members)[i]; + s->emitComment(sc); + } + return; + } + } + if (!comment) + return; + if (isAnonymous()) + return; + + OutBuffer *buf = sc->docbuf; + DocComment *dc = DocComment::parse(sc, this, comment); + + if (!dc) + { + emitDitto(sc); + return; + } + dc->pmacrotable = &sc->module->macrotable; + + buf->writestring(ddoc_decl_s); + toDocBuffer(buf); + sc->lastoffset = buf->offset; + buf->writestring(ddoc_decl_e); + + buf->writestring(ddoc_decl_dd_s); + dc->writeSections(sc, this, buf); + emitMemberComments(sc); + buf->writestring(ddoc_decl_dd_e); +} + +void EnumMember::emitComment(Scope *sc) +{ + //printf("EnumMember::emitComment(%p '%s'), comment = '%s'\n", this, toChars(), comment); + if (prot() == PROTprivate) + return; + if (!comment) + return; + + OutBuffer *buf = sc->docbuf; + DocComment *dc = DocComment::parse(sc, this, comment); + unsigned o; + + if (!dc) + { + emitDitto(sc); + return; + } + dc->pmacrotable = &sc->module->macrotable; + + buf->writestring(ddoc_decl_s); + o = buf->offset; + toDocBuffer(buf); + highlightCode(sc, this, buf, o); + sc->lastoffset = buf->offset; + buf->writestring(ddoc_decl_e); + + buf->writestring(ddoc_decl_dd_s); + dc->writeSections(sc, this, buf); + buf->writestring(ddoc_decl_dd_e); +} + +/******************************* toDocBuffer **********************************/ + +void Dsymbol::toDocBuffer(OutBuffer *buf) +{ + //printf("Dsymbol::toDocbuffer() %s\n", toChars()); + HdrGenState hgs; + + hgs.ddoc = 1; + toCBuffer(buf, &hgs); +} + +void prefix(OutBuffer *buf, Dsymbol *s) +{ + if (s->isDeprecated()) + buf->writestring("deprecated "); + Declaration *d = s->isDeclaration(); + if (d) + { + emitProtection(buf, d->protection); + if (d->isAbstract()) + buf->writestring("abstract "); + if (d->isStatic()) + buf->writestring("static "); + if (d->isConst()) + buf->writestring("const "); +#if DMDV2 + if (d->isImmutable()) + buf->writestring("immutable "); +#endif + if (d->isFinal()) + buf->writestring("final "); + if (d->isSynchronized()) + buf->writestring("synchronized "); + } +} + +void declarationToDocBuffer(Declaration *decl, OutBuffer *buf, TemplateDeclaration *td) +{ + //printf("declarationToDocBuffer() %s, originalType = %s, td = %s\n", decl->toChars(), decl->originalType ? decl->originalType->toChars() : "--", td ? td->toChars() : "--"); + if (decl->ident) + { + prefix(buf, decl); + + if (decl->type) + { HdrGenState hgs; + hgs.ddoc = 1; + Type *origType = decl->originalType ? decl->originalType : decl->type; + if (origType->ty == Tfunction) + { + TypeFunction *attrType = (TypeFunction*)(decl->ident == Id::ctor ? origType : decl->type); + ((TypeFunction*)origType)->toCBufferWithAttributes(buf, decl->ident, &hgs, attrType, td); + } + else + origType->toCBuffer(buf, decl->ident, &hgs); + } + else + buf->writestring(decl->ident->toChars()); + buf->writestring(";\n"); + } +} + +void Declaration::toDocBuffer(OutBuffer *buf) +{ + declarationToDocBuffer(this, buf, NULL); +} + +void AliasDeclaration::toDocBuffer(OutBuffer *buf) +{ + //printf("AliasDeclaration::toDocbuffer() %s\n", toChars()); + if (ident) + { + if (isDeprecated()) + buf->writestring("deprecated "); + + emitProtection(buf, protection); + buf->writestring("alias "); + buf->writestring(toChars()); + buf->writestring(";\n"); + } +} + + +void TypedefDeclaration::toDocBuffer(OutBuffer *buf) +{ + if (ident) + { + if (isDeprecated()) + buf->writestring("deprecated "); + + emitProtection(buf, protection); + buf->writestring("typedef "); + buf->writestring(toChars()); + buf->writestring(";\n"); + } +} + + +void FuncDeclaration::toDocBuffer(OutBuffer *buf) +{ + //printf("FuncDeclaration::toDocbuffer() %s\n", toChars()); + if (ident) + { + TemplateDeclaration *td; + + if (parent && + (td = parent->isTemplateDeclaration()) != NULL && + td->onemember == this) + { /* It's a function template + */ + unsigned o = buf->offset; + + declarationToDocBuffer(this, buf, td); + + highlightCode(NULL, this, buf, o); + } + else + { + Declaration::toDocBuffer(buf); + } + } +} + +#if DMDV1 +void CtorDeclaration::toDocBuffer(OutBuffer *buf) +{ + HdrGenState hgs; + + buf->writestring("this"); + Parameter::argsToCBuffer(buf, &hgs, arguments, varargs); + buf->writestring(";\n"); +} +#endif + +void AggregateDeclaration::toDocBuffer(OutBuffer *buf) +{ + if (ident) + { +#if 0 + emitProtection(buf, protection); +#endif + buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); + buf->writestring(";\n"); + } +} + +void StructDeclaration::toDocBuffer(OutBuffer *buf) +{ + //printf("StructDeclaration::toDocbuffer() %s\n", toChars()); + if (ident) + { +#if 0 + emitProtection(buf, protection); +#endif + TemplateDeclaration *td; + + if (parent && + (td = parent->isTemplateDeclaration()) != NULL && + td->onemember == this) + { unsigned o = buf->offset; + td->toDocBuffer(buf); + highlightCode(NULL, this, buf, o); + } + else + { + buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); + } + buf->writestring(";\n"); + } +} + +void ClassDeclaration::toDocBuffer(OutBuffer *buf) +{ + //printf("ClassDeclaration::toDocbuffer() %s\n", toChars()); + if (ident) + { +#if 0 + emitProtection(buf, protection); +#endif + TemplateDeclaration *td; + + if (parent && + (td = parent->isTemplateDeclaration()) != NULL && + td->onemember == this) + { unsigned o = buf->offset; + td->toDocBuffer(buf); + highlightCode(NULL, this, buf, o); + } + else + { + if (isAbstract()) + buf->writestring("abstract "); + buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); + } + int any = 0; + for (size_t i = 0; i < baseclasses->dim; i++) + { BaseClass *bc = (*baseclasses)[i]; + + if (bc->protection == PROTprivate) + continue; + if (bc->base && bc->base->ident == Id::Object) + continue; + + if (any) + buf->writestring(", "); + else + { buf->writestring(": "); + any = 1; + } + emitProtection(buf, bc->protection); + if (bc->base) + { + buf->writestring(bc->base->toPrettyChars()); + } + else + { + HdrGenState hgs; + bc->type->toCBuffer(buf, NULL, &hgs); + } + } + buf->writestring(";\n"); + } +} + + +void EnumDeclaration::toDocBuffer(OutBuffer *buf) +{ + if (ident) + { + buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); + buf->writestring(";\n"); + } +} + +void EnumMember::toDocBuffer(OutBuffer *buf) +{ + if (ident) + { + buf->writestring(toChars()); + } +} + + +/********************************* DocComment *********************************/ + +DocComment::DocComment() +{ + memset(this, 0, sizeof(DocComment)); +} + +DocComment *DocComment::parse(Scope *sc, Dsymbol *s, unsigned char *comment) +{ + //printf("parse(%s): '%s'\n", s->toChars(), comment); + if (sc->lastdc && isDitto(comment)) + return NULL; + + DocComment *dc = new DocComment(); + if (!comment) + return dc; + + dc->parseSections(comment); + + for (size_t i = 0; i < dc->sections.dim; i++) + { Section *sec = dc->sections[i]; + + if (icmp("copyright", sec->name, sec->namelen) == 0) + { + dc->copyright = sec; + } + if (icmp("macros", sec->name, sec->namelen) == 0) + { + dc->macros = sec; + } + } + + sc->lastdc = dc; + return dc; +} + +/***************************************** + * Parse next paragraph out of *pcomment. + * Update *pcomment to point past paragraph. + * Returns NULL if no more paragraphs. + * If paragraph ends in 'identifier:', + * then (*pcomment)[0 .. idlen] is the identifier. + */ + +void DocComment::parseSections(unsigned char *comment) +{ unsigned char *p; + unsigned char *pstart; + unsigned char *pend; + unsigned char *idstart; + unsigned idlen; + + unsigned char *name = NULL; + unsigned namelen = 0; + + //printf("parseSections('%s')\n", comment); + p = comment; + while (*p) + { + p = skipwhitespace(p); + pstart = p; + pend = p; + + /* Find end of section, which is ended by one of: + * 'identifier:' (but not inside a code section) + * '\0' + */ + idlen = 0; + int inCode = 0; + while (1) + { + // Check for start/end of a code section + if (*p == '-') + { + int numdash = 0; + while (*p == '-') + { + ++numdash; + p++; + } + // BUG: handle UTF PS and LS too + if (!*p || *p == '\r' || *p == '\n' && numdash >= 3) + inCode ^= 1; + pend = p; + } + + if (!inCode && isIdStart(p)) + { + unsigned char *q = p + utfStride(p); + while (isIdTail(q)) + q += utfStride(q); + if (*q == ':') // identifier: ends it + { idlen = q - p; + idstart = p; + for (pend = p; pend > pstart; pend--) + { if (pend[-1] == '\n') + break; + } + p = q + 1; + break; + } + } + while (1) + { + if (!*p) + goto L1; + if (*p == '\n') + { p++; + if (*p == '\n' && !summary && !namelen && !inCode) + { + pend = p; + p++; + goto L1; + } + break; + } + p++; + pend = p; + } + p = skipwhitespace(p); + } + L1: + + if (namelen || pstart < pend) + { + Section *s; + if (icmp("Params", name, namelen) == 0) + s = new ParamSection(); + else if (icmp("Macros", name, namelen) == 0) + s = new MacroSection(); + else + s = new Section(); + s->name = name; + s->namelen = namelen; + s->body = pstart; + s->bodylen = pend - pstart; + s->nooutput = 0; + + //printf("Section: '%.*s' = '%.*s'\n", s->namelen, s->name, s->bodylen, s->body); + + sections.push(s); + + if (!summary && !namelen) + summary = s; + } + + if (idlen) + { name = idstart; + namelen = idlen; + } + else + { name = NULL; + namelen = 0; + if (!*p) + break; + } + } +} + +void DocComment::writeSections(Scope *sc, Dsymbol *s, OutBuffer *buf) +{ + //printf("DocComment::writeSections()\n"); + if (sections.dim) + { + buf->writestring("$(DDOC_SECTIONS \n"); + for (size_t i = 0; i < sections.dim; i++) + { Section *sec = sections[i]; + + if (sec->nooutput) + continue; + //printf("Section: '%.*s' = '%.*s'\n", sec->namelen, sec->name, sec->bodylen, sec->body); + if (sec->namelen || i) + sec->write(this, sc, s, buf); + else + { + buf->writestring("$(DDOC_SUMMARY "); + unsigned o = buf->offset; + buf->write(sec->body, sec->bodylen); + escapeStrayParenthesis(buf, o, s->loc); + highlightText(sc, s, buf, o); + buf->writestring(")\n"); + } + } + buf->writestring(")\n"); + } + else + { + buf->writestring("$(DDOC_BLANKLINE)\n"); + } +} + +/*************************************************** + */ + +void Section::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) +{ + if (namelen) + { + static const char *table[] = + { "AUTHORS", "BUGS", "COPYRIGHT", "DATE", + "DEPRECATED", "EXAMPLES", "HISTORY", "LICENSE", + "RETURNS", "SEE_ALSO", "STANDARDS", "THROWS", + "VERSION" }; + + for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) + { + if (icmp(table[i], name, namelen) == 0) + { + buf->printf("$(DDOC_%s ", table[i]); + goto L1; + } + } + + buf->writestring("$(DDOC_SECTION "); + // Replace _ characters with spaces + buf->writestring("$(DDOC_SECTION_H "); + unsigned o = buf->offset; + for (unsigned u = 0; u < namelen; u++) + { unsigned char c = name[u]; + buf->writeByte((c == '_') ? ' ' : c); + } + escapeStrayParenthesis(buf, o, s->loc); + buf->writestring(":)\n"); + } + else + { + buf->writestring("$(DDOC_DESCRIPTION "); + } + L1: + unsigned o = buf->offset; + buf->write(body, bodylen); + escapeStrayParenthesis(buf, o, s->loc); + highlightText(sc, s, buf, o); + buf->writestring(")\n"); +} + +/*************************************************** + */ + +void ParamSection::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) +{ + unsigned char *p = body; + unsigned len = bodylen; + unsigned char *pend = p + len; + + unsigned char *tempstart; + unsigned templen; + + unsigned char *namestart; + unsigned namelen = 0; // !=0 if line continuation + + unsigned char *textstart; + unsigned textlen; + + unsigned o; + Parameter *arg; + + buf->writestring("$(DDOC_PARAMS \n"); + while (p < pend) + { + // Skip to start of macro + while (1) + { + switch (*p) + { + case ' ': + case '\t': + p++; + continue; + + case '\n': + p++; + goto Lcont; + + default: + if (isIdStart(p)) + break; + if (namelen) + goto Ltext; // continuation of prev macro + goto Lskipline; + } + break; + } + tempstart = p; + + while (isIdTail(p)) + p += utfStride(p); + templen = p - tempstart; + + while (*p == ' ' || *p == '\t') + p++; + + if (*p != '=') + { if (namelen) + goto Ltext; // continuation of prev macro + goto Lskipline; + } + p++; + + if (namelen) + { // Output existing param + + L1: + //printf("param '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart); + HdrGenState hgs; + buf->writestring("$(DDOC_PARAM_ROW "); + buf->writestring("$(DDOC_PARAM_ID "); + o = buf->offset; + arg = isFunctionParameter(s, namestart, namelen); + if (arg && arg->type && arg->ident) + arg->type->toCBuffer(buf, arg->ident, &hgs); + else + buf->write(namestart, namelen); + escapeStrayParenthesis(buf, o, s->loc); + highlightCode(sc, s, buf, o); + buf->writestring(")\n"); + + buf->writestring("$(DDOC_PARAM_DESC "); + o = buf->offset; + buf->write(textstart, textlen); + escapeStrayParenthesis(buf, o, s->loc); + highlightText(sc, s, buf, o); + buf->writestring(")"); + buf->writestring(")\n"); + namelen = 0; + if (p >= pend) + break; + } + + namestart = tempstart; + namelen = templen; + + while (*p == ' ' || *p == '\t') + p++; + textstart = p; + + Ltext: + while (*p != '\n') + p++; + textlen = p - textstart; + p++; + + Lcont: + continue; + + Lskipline: + // Ignore this line + while (*p++ != '\n') + ; + } + if (namelen) + goto L1; // write out last one + buf->writestring(")\n"); +} + +/*************************************************** + */ + +void MacroSection::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) +{ + //printf("MacroSection::write()\n"); + DocComment::parseMacros(dc->pescapetable, dc->pmacrotable, body, bodylen); +} + +/************************************************ + * Parse macros out of Macros: section. + * Macros are of the form: + * name1 = value1 + * + * name2 = value2 + */ + +void DocComment::parseMacros(Escape **pescapetable, Macro **pmacrotable, unsigned char *m, unsigned mlen) +{ + unsigned char *p = m; + unsigned len = mlen; + unsigned char *pend = p + len; + + unsigned char *tempstart; + unsigned templen; + + unsigned char *namestart; + unsigned namelen = 0; // !=0 if line continuation + + unsigned char *textstart; + unsigned textlen; + + while (p < pend) + { + // Skip to start of macro + while (1) + { + if (p >= pend) + goto Ldone; + switch (*p) + { + case ' ': + case '\t': + p++; + continue; + + case '\n': + p++; + goto Lcont; + + default: + if (isIdStart(p)) + break; + if (namelen) + goto Ltext; // continuation of prev macro + goto Lskipline; + } + break; + } + tempstart = p; + + while (1) + { + if (p >= pend) + goto Ldone; + if (!isIdTail(p)) + break; + p += utfStride(p); + } + templen = p - tempstart; + + while (1) + { + if (p >= pend) + goto Ldone; + if (!(*p == ' ' || *p == '\t')) + break; + p++; + } + + if (*p != '=') + { if (namelen) + goto Ltext; // continuation of prev macro + goto Lskipline; + } + p++; + if (p >= pend) + goto Ldone; + + if (namelen) + { // Output existing macro + L1: + //printf("macro '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart); + if (icmp("ESCAPES", namestart, namelen) == 0) + parseEscapes(pescapetable, textstart, textlen); + else + Macro::define(pmacrotable, namestart, namelen, textstart, textlen); + namelen = 0; + if (p >= pend) + break; + } + + namestart = tempstart; + namelen = templen; + + while (p < pend && (*p == ' ' || *p == '\t')) + p++; + textstart = p; + + Ltext: + while (p < pend && *p != '\n') + p++; + textlen = p - textstart; + + // Remove trailing \r if there is one + if (p > m && p[-1] == '\r') + textlen--; + + p++; + //printf("p = %p, pend = %p\n", p, pend); + + Lcont: + continue; + + Lskipline: + // Ignore this line + while (p < pend && *p++ != '\n') + ; + } +Ldone: + if (namelen) + goto L1; // write out last one +} + +/************************************** + * Parse escapes of the form: + * /c/string/ + * where c is a single character. + * Multiple escapes can be separated + * by whitespace and/or commas. + */ + +void DocComment::parseEscapes(Escape **pescapetable, unsigned char *textstart, unsigned textlen) +{ Escape *escapetable = *pescapetable; + + if (!escapetable) + { escapetable = new Escape; + *pescapetable = escapetable; + } + unsigned char *p = textstart; + unsigned char *pend = p + textlen; + + while (1) + { + while (1) + { + if (p + 4 >= pend) + return; + if (!(*p == ' ' || *p == '\t' || *p == '\n' || *p == ',')) + break; + p++; + } + if (p[0] != '/' || p[2] != '/') + return; + unsigned char c = p[1]; + p += 3; + unsigned char *start = p; + while (1) + { + if (p >= pend) + return; + if (*p == '/') + break; + p++; + } + size_t len = p - start; + char *s = (char *)memcpy(mem.malloc(len + 1), start, len); + s[len] = 0; + escapetable->strings[c] = s; + //printf("%c = '%s'\n", c, s); + p++; + } +} + + +/****************************************** + * Compare 0-terminated string with length terminated string. + * Return < 0, ==0, > 0 + */ + +int cmp(const char *stringz, void *s, size_t slen) +{ + size_t len1 = strlen(stringz); + + if (len1 != slen) + return len1 - slen; + return memcmp(stringz, s, slen); +} + +int icmp(const char *stringz, void *s, size_t slen) +{ + size_t len1 = strlen(stringz); + + if (len1 != slen) + return len1 - slen; + return memicmp(stringz, (char *)s, slen); +} + +/***************************************** + * Return !=0 if comment consists entirely of "ditto". + */ + +int isDitto(unsigned char *comment) +{ + if (comment) + { + unsigned char *p = skipwhitespace(comment); + + if (memicmp((char *)p, "ditto", 5) == 0 && *skipwhitespace(p + 5) == 0) + return 1; + } + return 0; +} + +/********************************************** + * Skip white space. + */ + +unsigned char *skipwhitespace(unsigned char *p) +{ + for (; 1; p++) + { switch (*p) + { + case ' ': + case '\t': + case '\n': + continue; + } + break; + } + return p; +} + + +/************************************************ + * Scan forward to one of: + * start of identifier + * beginning of next line + * end of buf + */ + +unsigned skiptoident(OutBuffer *buf, size_t i) +{ + while (i < buf->offset) + { dchar_t c; + + size_t oi = i; + if (utf_decodeChar((unsigned char *)buf->data, buf->offset, &i, &c)) + /* Ignore UTF errors, but still consume input + */ + break; + if (c >= 0x80) + { + if (!isUniAlpha(c)) + continue; + } + else if (!(isalpha(c) || c == '_' || c == '\n')) + continue; + i = oi; + break; + } + return i; +} + +/************************************************ + * Scan forward past end of identifier. + */ + +unsigned skippastident(OutBuffer *buf, size_t i) +{ + while (i < buf->offset) + { dchar_t c; + + size_t oi = i; + if (utf_decodeChar((unsigned char *)buf->data, buf->offset, &i, &c)) + /* Ignore UTF errors, but still consume input + */ + break; + if (c >= 0x80) + { + if (isUniAlpha(c)) + continue; + } + else if (isalnum(c) || c == '_') + continue; + i = oi; + break; + } + return i; +} + + +/************************************************ + * Scan forward past URL starting at i. + * We don't want to highlight parts of a URL. + * Returns: + * i if not a URL + * index just past it if it is a URL + */ + +unsigned skippastURL(OutBuffer *buf, size_t i) +{ unsigned length = buf->offset - i; + unsigned char *p = &buf->data[i]; + unsigned j; + unsigned sawdot = 0; + + if (length > 7 && memicmp((char *)p, "http://", 7) == 0) + { + j = 7; + } + else if (length > 8 && memicmp((char *)p, "https://", 8) == 0) + { + j = 8; + } + else + goto Lno; + + for (; j < length; j++) + { unsigned char c = p[j]; + if (isalnum(c)) + continue; + if (c == '-' || c == '_' || c == '?' || + c == '=' || c == '%' || c == '&' || + c == '/' || c == '+' || c == '#' || + c == '~') + continue; + if (c == '.') + { + sawdot = 1; + continue; + } + break; + } + if (sawdot) + return i + j; + +Lno: + return i; +} + + +/**************************************************** + */ + +int isKeyword(unsigned char *p, unsigned len) +{ + static const char *table[] = { "true", "false", "null" }; + + for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) + { + if (cmp(table[i], p, len) == 0) + return 1; + } + return 0; +} + +/**************************************************** + */ + +Parameter *isFunctionParameter(Dsymbol *s, unsigned char *p, unsigned len) +{ + FuncDeclaration *f = s->isFuncDeclaration(); + + /* f->type may be NULL for template members. + */ + if (f && f->type) + { + TypeFunction *tf; + if (f->originalType) + { + tf = (TypeFunction *)f->originalType; + } + else + tf = (TypeFunction *)f->type; + + if (tf->parameters) + { + for (size_t k = 0; k < tf->parameters->dim; k++) + { Parameter *arg = (*tf->parameters)[k]; + + if (arg->ident && cmp(arg->ident->toChars(), p, len) == 0) + { + return arg; + } + } + } + } + return NULL; +} + +/************************************************** + * Highlight text section. + */ + +void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) +{ + //printf("highlightText()\n"); + const char *sid = s->ident->toChars(); + FuncDeclaration *f = s->isFuncDeclaration(); + unsigned char *p; + const char *se; + + int leadingBlank = 1; + int inCode = 0; + int inComment = 0; // in comment + unsigned iCodeStart; // start of code section + + unsigned iLineStart = offset; + + for (unsigned i = offset; i < buf->offset; i++) + { unsigned char c = buf->data[i]; + + Lcont: + switch (c) + { + case ' ': + case '\t': + break; + + case '\n': + if (sc && !inCode && i == iLineStart && i + 1 < buf->offset) // if "\n\n" + { + static char blankline[] = "$(DDOC_BLANKLINE)\n"; + + i = buf->insert(i, blankline, sizeof(blankline) - 1); + } + leadingBlank = 1; + iLineStart = i + 1; + break; + + case '<': + leadingBlank = 0; + if (inCode) + break; + p = &buf->data[i]; + + // Skip over comments + if (p[1] == '!' && p[2] == '-' && p[3] == '-') + { unsigned j = i + 4; + p += 4; + while (1) + { + if (j == buf->offset) + goto L1; + if (p[0] == '-' && p[1] == '-' && p[2] == '>') + { + i = j + 2; // place on closing '>' + break; + } + j++; + p++; + } + break; + } + + // Skip over HTML tag + if (isalpha(p[1]) || (p[1] == '/' && isalpha(p[2]))) + { unsigned j = i + 2; + p += 2; + while (1) + { + if (j == buf->offset) + goto L1; + if (p[0] == '>') + { + i = j; // place on closing '>' + break; + } + j++; + p++; + } + break; + } + + L1: + // Replace '<' with '<' character entity + se = Escape::escapeChar('<'); + if (se) + { size_t len = strlen(se); + buf->remove(i, 1); + i = buf->insert(i, se, len); + i--; // point to ';' + } + break; + + case '>': + leadingBlank = 0; + if (inCode) + break; + // Replace '>' with '>' character entity + se = Escape::escapeChar('>'); + if (se) + { size_t len = strlen(se); + buf->remove(i, 1); + i = buf->insert(i, se, len); + i--; // point to ';' + } + break; + + case '&': + leadingBlank = 0; + if (inCode) + break; + p = &buf->data[i]; + if (p[1] == '#' || isalpha(p[1])) + break; // already a character entity + // Replace '&' with '&' character entity + se = Escape::escapeChar('&'); + if (se) + { size_t len = strlen(se); + buf->remove(i, 1); + i = buf->insert(i, se, len); + i--; // point to ';' + } + break; + + case '-': + /* A line beginning with --- delimits a code section. + * inCode tells us if it is start or end of a code section. + */ + if (leadingBlank) + { int istart = i; + int eollen = 0; + + leadingBlank = 0; + while (1) + { + ++i; + if (i >= buf->offset) + break; + c = buf->data[i]; + if (c == '\n') + { eollen = 1; + break; + } + if (c == '\r') + { + eollen = 1; + if (i + 1 >= buf->offset) + break; + if (buf->data[i + 1] == '\n') + { eollen = 2; + break; + } + } + // BUG: handle UTF PS and LS too + if (c != '-') + goto Lcont; + } + if (i - istart < 3) + goto Lcont; + + // We have the start/end of a code section + + // Remove the entire --- line, including blanks and \n + buf->remove(iLineStart, i - iLineStart + eollen); + i = iLineStart; + + if (inCode && (i <= iCodeStart)) + { // Empty code section, just remove it completely. + inCode = 0; + break; + } + + if (inCode) + { + inCode = 0; + // The code section is from iCodeStart to i + OutBuffer codebuf; + + codebuf.write(buf->data + iCodeStart, i - iCodeStart); + codebuf.writeByte(0); + highlightCode2(sc, s, &codebuf, 0); + buf->remove(iCodeStart, i - iCodeStart); + i = buf->insert(iCodeStart, codebuf.data, codebuf.offset); + i = buf->insert(i, ")\n", 2); + i--; + } + else + { static char pre[] = "$(D_CODE \n"; + + inCode = 1; + i = buf->insert(i, pre, sizeof(pre) - 1); + iCodeStart = i; + i--; // place i on > + leadingBlank = true; + } + } + break; + + default: + leadingBlank = 0; + if (sc && !inCode && isIdStart(&buf->data[i])) + { unsigned j; + + j = skippastident(buf, i); + if (j > i) + { + unsigned k = skippastURL(buf, i); + if (k > i) + { i = k - 1; + break; + } + + if (buf->data[i] == '_') // leading '_' means no highlight + { + buf->remove(i, 1); + i = j - 1; + } + else + { + if (cmp(sid, buf->data + i, j - i) == 0) + { + i = buf->bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1; + break; + } + else if (isKeyword(buf->data + i, j - i)) + { + i = buf->bracket(i, "$(DDOC_KEYWORD ", j, ")") - 1; + break; + } + else + { + if (f && isFunctionParameter(f, buf->data + i, j - i)) + { + //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); + i = buf->bracket(i, "$(DDOC_PARAM ", j, ")") - 1; + break; + } + } + i = j - 1; + } + } + } + break; + } + } + if (inCode) + s->error("unmatched --- in DDoc comment"); + ; +} + +/************************************************** + * Highlight code for DDOC section. + */ + +void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) +{ + char *sid = s->ident->toChars(); + FuncDeclaration *f = s->isFuncDeclaration(); + + //printf("highlightCode(s = '%s', kind = %s)\n", sid, s->kind()); + for (unsigned i = offset; i < buf->offset; i++) + { unsigned char c = buf->data[i]; + const char *se; + + se = Escape::escapeChar(c); + if (se) + { + size_t len = strlen(se); + buf->remove(i, 1); + i = buf->insert(i, se, len); + i--; // point to ';' + } + else if (isIdStart(&buf->data[i])) + { unsigned j; + + j = skippastident(buf, i); + if (j > i) + { + if (cmp(sid, buf->data + i, j - i) == 0) + { + i = buf->bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1; + continue; + } + else if (f) + { + if (isFunctionParameter(f, buf->data + i, j - i)) + { + //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); + i = buf->bracket(i, "$(DDOC_PARAM ", j, ")") - 1; + continue; + } + } + i = j - 1; + } + } + } +} + +/**************************************** + */ + +void highlightCode3(OutBuffer *buf, unsigned char *p, unsigned char *pend) +{ + for (; p < pend; p++) + { const char *s = Escape::escapeChar(*p); + if (s) + buf->writestring(s); + else + buf->writeByte(*p); + } +} + +/************************************************** + * Highlight code for CODE section. + */ + + +void highlightCode2(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) +{ + char *sid = s->ident->toChars(); + FuncDeclaration *f = s->isFuncDeclaration(); + unsigned errorsave = global.errors; + Lexer lex(NULL, buf->data, 0, buf->offset - 1, 0, 1); + Token tok; + OutBuffer res; + unsigned char *lastp = buf->data; + const char *highlight; + + //printf("highlightCode2('%.*s')\n", buf->offset - 1, buf->data); + res.reserve(buf->offset); + while (1) + { + lex.scan(&tok); + highlightCode3(&res, lastp, tok.ptr); + highlight = NULL; + switch (tok.value) + { + case TOKidentifier: + if (!sc) + break; + if (cmp(sid, tok.ptr, lex.p - tok.ptr) == 0) + { + highlight = "$(D_PSYMBOL "; + break; + } + else if (f) + { + if (isFunctionParameter(f, tok.ptr, lex.p - tok.ptr)) + { + //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); + highlight = "$(D_PARAM "; + break; + } + } + break; + + case TOKcomment: + highlight = "$(D_COMMENT "; + break; + + case TOKstring: + highlight = "$(D_STRING "; + break; + + default: + if (tok.isKeyword()) + highlight = "$(D_KEYWORD "; + break; + } + if (highlight) + res.writestring(highlight); + highlightCode3(&res, tok.ptr, lex.p); + if (highlight) + res.writeByte(')'); + if (tok.value == TOKeof) + break; + lastp = lex.p; + } + buf->setsize(offset); + buf->write(&res); + global.errors = errorsave; +} + +/*************************************** + * Find character string to replace c with. + */ + +const char *Escape::escapeChar(unsigned c) +{ const char *s; + + switch (c) + { + case '<': + s = "<"; + break; + case '>': + s = ">"; + break; + case '&': + s = "&"; + break; + default: + s = NULL; + break; + } + return s; +} + +/**************************************** + * Determine if p points to the start of an identifier. + */ + +int isIdStart(unsigned char *p) +{ + unsigned c = *p; + if (isalpha(c) || c == '_') + return 1; + if (c >= 0x80) + { size_t i = 0; + if (utf_decodeChar(p, 4, &i, &c)) + return 0; // ignore errors + if (isUniAlpha(c)) + return 1; + } + return 0; +} + +/**************************************** + * Determine if p points to the rest of an identifier. + */ + +int isIdTail(unsigned char *p) +{ + unsigned c = *p; + if (isalnum(c) || c == '_') + return 1; + if (c >= 0x80) + { size_t i = 0; + if (utf_decodeChar(p, 4, &i, &c)) + return 0; // ignore errors + if (isUniAlpha(c)) + return 1; + } + return 0; +} + +/***************************************** + * Return number of bytes in UTF character. + */ + +int utfStride(unsigned char *p) +{ + unsigned c = *p; + if (c < 0x80) + return 1; + size_t i = 0; + utf_decodeChar(p, 4, &i, &c); // ignore errors, but still consume input + return i; +} diff --git a/dmd2/dsymbol.c b/dmd2/dsymbol.c index ef23de74..71efca43 100644 --- a/dmd2/dsymbol.c +++ b/dmd2/dsymbol.c @@ -1,1528 +1,1528 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include - -#include "rmem.h" -#include "speller.h" -#include "aav.h" - -#include "mars.h" -#include "dsymbol.h" -#include "aggregate.h" -#include "identifier.h" -#include "module.h" -#include "mtype.h" -#include "expression.h" -#include "statement.h" -#include "declaration.h" -#include "id.h" -#include "scope.h" -#include "init.h" -#include "import.h" -#include "template.h" -#include "attrib.h" -#if IN_LLVM -#include "../gen/pragma.h" -#endif - -/****************************** Dsymbol ******************************/ - -Dsymbol::Dsymbol() -{ - //printf("Dsymbol::Dsymbol(%p)\n", this); - this->ident = NULL; - this->c_ident = NULL; - this->parent = NULL; -#if IN_DMD - this->csym = NULL; - this->isym = NULL; -#endif - this->loc = 0; - this->comment = NULL; - this->scope = NULL; - this->errors = false; - -#if IN_LLVM - this->llvmInternal = LLVMnone; - this->irsym = NULL; -#endif -} - -Dsymbol::Dsymbol(Identifier *ident) -{ - //printf("Dsymbol::Dsymbol(%p, ident)\n", this); - this->ident = ident; - this->c_ident = NULL; - this->parent = NULL; -#if IN_DMD - this->csym = NULL; - this->isym = NULL; -#endif - this->loc = 0; - this->comment = NULL; - this->scope = NULL; - this->errors = false; - -#if IN_LLVM - this->llvmInternal = LLVMnone; - this->irsym = NULL; -#endif -} - -int Dsymbol::equals(Object *o) -{ Dsymbol *s; - - if (this == o) - return TRUE; - s = (Dsymbol *)(o); - // Overload sets don't have an ident - if (s && ident && s->ident && ident->equals(s->ident)) - return TRUE; - return FALSE; -} - -/************************************** - * Copy the syntax. - * Used for template instantiations. - * If s is NULL, allocate the new object, otherwise fill it in. - */ - -Dsymbol *Dsymbol::syntaxCopy(Dsymbol *s) -{ - print(); - printf("%s %s\n", kind(), toChars()); - assert(0); - return NULL; -} - -/************************************** - * Determine if this symbol is only one. - * Returns: - * FALSE, *ps = NULL: There are 2 or more symbols - * TRUE, *ps = NULL: There are zero symbols - * TRUE, *ps = symbol: The one and only one symbol - */ - -int Dsymbol::oneMember(Dsymbol **ps, Identifier *ident) -{ - //printf("Dsymbol::oneMember()\n"); - *ps = this; - return TRUE; -} - -/***************************************** - * Same as Dsymbol::oneMember(), but look at an array of Dsymbols. - */ - -int Dsymbol::oneMembers(Dsymbols *members, Dsymbol **ps, Identifier *ident) -{ - //printf("Dsymbol::oneMembers() %d\n", members ? members->dim : 0); - Dsymbol *s = NULL; - - if (members) - { - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *sx = (*members)[i]; - - int x = sx->oneMember(ps, ident); - //printf("\t[%d] kind %s = %d, s = %p\n", i, sx->kind(), x, *ps); - if (!x) - { - //printf("\tfalse 1\n"); - assert(*ps == NULL); - return FALSE; - } - if (*ps) - { - if (ident) - { - if (!(*ps)->ident || !(*ps)->ident->equals(ident)) - continue; - } - if (!s) - s = *ps; - else if (s->isOverloadable() && (*ps)->isOverloadable()) - ; // keep head of overload set - else // more than one symbol - { *ps = NULL; - //printf("\tfalse 2\n"); - return FALSE; - } - } - } - } - *ps = s; // s is the one symbol, NULL if none - //printf("\ttrue\n"); - return TRUE; -} - -/***************************************** - * Is Dsymbol a variable that contains pointers? - */ - -int Dsymbol::hasPointers() -{ - //printf("Dsymbol::hasPointers() %s\n", toChars()); - return 0; -} - -bool Dsymbol::hasStaticCtorOrDtor() -{ - //printf("Dsymbol::hasStaticCtorOrDtor() %s\n", toChars()); - return FALSE; -} - -void Dsymbol::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion) -{ -} - -char *Dsymbol::toChars() -{ - return ident ? ident->toChars() : (char *)"__anonymous"; -} - -const char *Dsymbol::toPrettyChars() -{ Dsymbol *p; - char *s; - char *q; - size_t len; - - //printf("Dsymbol::toPrettyChars() '%s'\n", toChars()); - if (!parent) - return toChars(); - - len = 0; - for (p = this; p; p = p->parent) - len += strlen(p->toChars()) + 1; - - s = (char *)mem.malloc(len); - q = s + len - 1; - *q = 0; - for (p = this; p; p = p->parent) - { - char *t = p->toChars(); - len = strlen(t); - q -= len; - memcpy(q, t, len); - if (q == s) - break; - q--; -#if TARGET_NET - if (AggregateDeclaration* ad = p->isAggregateDeclaration()) - { - if (ad->isNested() && p->parent && p->parent->isAggregateDeclaration()) - { - *q = '/'; - continue; - } - } -#endif - *q = '.'; - } - return s; -} - -char *Dsymbol::locToChars() -{ - OutBuffer buf; - - if (!loc.filename) // avoid bug 5861. - { - Module *m = getModule(); - - if (m && m->srcfile) - loc.filename = m->srcfile->toChars(); - } - return loc.toChars(); -} - -const char *Dsymbol::kind() -{ - return "symbol"; -} - -/********************************* - * If this symbol is really an alias for another, - * return that other. - */ - -Dsymbol *Dsymbol::toAlias() -{ - return this; -} - -Dsymbol *Dsymbol::toParent() -{ - return parent ? parent->pastMixin() : NULL; -} - -Dsymbol *Dsymbol::pastMixin() -{ - Dsymbol *s = this; - - //printf("Dsymbol::pastMixin() %s\n", toChars()); - while (s && s->isTemplateMixin()) - s = s->parent; - return s; -} - -/********************************** - * Use this instead of toParent() when looking for the - * 'this' pointer of the enclosing function/class. - */ - -Dsymbol *Dsymbol::toParent2() -{ - Dsymbol *s = parent; - while (s && s->isTemplateInstance()) - s = s->parent; - return s; -} - -TemplateInstance *Dsymbol::inTemplateInstance() -{ - for (Dsymbol *parent = this->parent; parent; parent = parent->parent) - { - TemplateInstance *ti = parent->isTemplateInstance(); - if (ti) - return ti; - } - return NULL; -} - -// Check if this function is a member of a template which has only been -// instantiated speculatively, eg from inside is(typeof()). -// Return the speculative template instance it is part of, -// or NULL if not speculative. -TemplateInstance *Dsymbol::isSpeculative() -{ - Dsymbol * par = parent; - while (par) - { - TemplateInstance *ti = par->isTemplateInstance(); - if (ti && ti->speculative) - return ti; - par = par->toParent(); - } - return NULL; -} - -int Dsymbol::isAnonymous() -{ - return ident ? 0 : 1; -} - -/************************************* - * Set scope for future semantic analysis so we can - * deal better with forward references. - */ - -void Dsymbol::setScope(Scope *sc) -{ - //printf("Dsymbol::setScope() %p %s, %p stc = %llx\n", this, toChars(), sc, sc->stc); - if (!sc->nofree) - sc->setNoFree(); // may need it even after semantic() finishes - scope = sc; -} - -void Dsymbol::importAll(Scope *sc) -{ -} - -/************************************* - * Does semantic analysis on the public face of declarations. - */ - -void Dsymbol::semantic0(Scope *sc) -{ -} - -void Dsymbol::semantic(Scope *sc) -{ - error("%p has no semantic routine", this); -} - -/************************************* - * Does semantic analysis on initializers and members of aggregates. - */ - -void Dsymbol::semantic2(Scope *sc) -{ - // Most Dsymbols have no further semantic analysis needed -} - -/************************************* - * Does semantic analysis on function bodies. - */ - -void Dsymbol::semantic3(Scope *sc) -{ - // Most Dsymbols have no further semantic analysis needed -} - -/************************************* - * Look for function inlining possibilities. - */ - -void Dsymbol::inlineScan() -{ - // Most Dsymbols aren't functions -} - -/********************************************* - * Search for ident as member of s. - * Input: - * flags: 1 don't find private members - * 2 don't give error messages - * 4 return NULL if ambiguous - * Returns: - * NULL if not found - */ - -Dsymbol *Dsymbol::search(Loc loc, Identifier *ident, int flags) -{ - //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars()); - return NULL; -} - -/*************************************************** - * Search for symbol with correct spelling. - */ - -void *symbol_search_fp(void *arg, const char *seed) -{ - /* If not in the lexer's string table, it certainly isn't in the symbol table. - * Doing this first is a lot faster. - */ - size_t len = strlen(seed); - if (!len) - return NULL; - StringValue *sv = Lexer::stringtable.lookup(seed, len); - if (!sv) - return NULL; - Identifier *id = (Identifier *)sv->ptrvalue; - assert(id); - - Dsymbol *s = (Dsymbol *)arg; - Module::clearCache(); - return s->search(0, id, 4|2); -} - -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. - * Returns: - * symbol found, NULL if not - */ - -Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, Identifier *id) -{ - //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars()); - Dsymbol *s = toAlias(); - Dsymbol *sm; - - switch (id->dyncast()) - { - case DYNCAST_IDENTIFIER: - sm = s->search(loc, id, 0); - break; - - case DYNCAST_DSYMBOL: - { // It's a template instance - //printf("\ttemplate instance id\n"); - Dsymbol *st = (Dsymbol *)id; - TemplateInstance *ti = st->isTemplateInstance(); - id = ti->name; - sm = s->search(loc, id, 0); - if (!sm) - { - sm = s->search_correct(id); - if (sm) - error("template identifier '%s' is not a member of '%s %s', did you mean '%s %s'?", - id->toChars(), s->kind(), s->toChars(), sm->kind(), sm->toChars()); - else - error("template identifier '%s' is not a member of '%s %s'", - id->toChars(), s->kind(), s->toChars()); - return NULL; - } - sm = sm->toAlias(); - TemplateDeclaration *td = sm->isTemplateDeclaration(); - if (!td) - { - error("%s is not a template, it is a %s", id->toChars(), sm->kind()); - return NULL; - } - ti->tempdecl = td; - if (!ti->semanticRun) - ti->semantic(sc); - sm = ti->toAlias(); - break; - } - - default: - assert(0); - } - return sm; -} - -int Dsymbol::overloadInsert(Dsymbol *s) -{ - //printf("Dsymbol::overloadInsert('%s')\n", s->toChars()); - return FALSE; -} - -void Dsymbol::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(toChars()); -} - -unsigned Dsymbol::size(Loc loc) -{ - error("Dsymbol '%s' has no size\n", toChars()); - return 0; -} - -int Dsymbol::isforwardRef() -{ - return FALSE; -} - -AggregateDeclaration *Dsymbol::isThis() -{ - return NULL; -} - -AggregateDeclaration *Dsymbol::isAggregateMember() // are we a member of an aggregate? -{ - Dsymbol *parent = toParent(); - if (parent && parent->isAggregateDeclaration()) - return (AggregateDeclaration *)parent; - return NULL; -} - -ClassDeclaration *Dsymbol::isClassMember() // are we a member of a class? -{ - AggregateDeclaration *ad = isAggregateMember(); - return ad ? ad->isClassDeclaration() : NULL; -} - -void Dsymbol::defineRef(Dsymbol *s) -{ - assert(0); -} - -int Dsymbol::isExport() -{ - return FALSE; -} - -int Dsymbol::isImportedSymbol() -{ - return FALSE; -} - -int Dsymbol::isDeprecated() -{ - return FALSE; -} - -#if DMDV2 -int Dsymbol::isOverloadable() -{ - return 0; -} - -int Dsymbol::hasOverloads() -{ - return 0; -} -#endif - -LabelDsymbol *Dsymbol::isLabel() // is this a LabelDsymbol()? -{ - return NULL; -} - -AggregateDeclaration *Dsymbol::isMember() // is this a member of an AggregateDeclaration? -{ - //printf("Dsymbol::isMember() %s\n", toChars()); - Dsymbol *parent = toParent(); - //printf("parent is %s %s\n", parent->kind(), parent->toChars()); - return parent ? parent->isAggregateDeclaration() : NULL; -} - -Type *Dsymbol::getType() -{ - return NULL; -} - -int Dsymbol::needThis() -{ - return FALSE; -} - -int Dsymbol::apply(Dsymbol_apply_ft_t fp, void *param) -{ - return (*fp)(this, param); -} - -int Dsymbol::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) -{ - //printf("Dsymbol::addMember('%s')\n", toChars()); - //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sd->toChars()); - //printf("Dsymbol::addMember(this = %p, '%s' sd = %p, sd->symtab = %p)\n", this, toChars(), sd, sd->symtab); - parent = sd; - if (!isAnonymous()) // no name, so can't add it to symbol table - { - if (!sd->symtabInsert(this)) // if name is already defined - { - Dsymbol *s2; - - s2 = sd->symtab->lookup(ident); - if (!s2->overloadInsert(this)) - { - sd->multiplyDefined(0, this, s2); - } - } - if (sd->isAggregateDeclaration() || sd->isEnumDeclaration()) - { - if (ident == Id::__sizeof || ident == Id::__xalignof || ident == Id::mangleof) - error(".%s property cannot be redefined", ident->toChars()); - } - return 1; - } - return 0; -} - -void Dsymbol::error(const char *format, ...) -{ - //printf("Dsymbol::error()\n"); - if (!loc.filename) // avoid bug 5861. - { - Module *m = getModule(); - - if (m && m->srcfile) - loc.filename = m->srcfile->toChars(); - } - va_list ap; - va_start(ap, format); - verror(loc, format, ap); - va_end(ap); -} - -void Dsymbol::error(Loc loc, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - verror(loc, format, ap); - va_end(ap); -} - -void Dsymbol::verror(Loc loc, const char *format, va_list ap) -{ - if (!global.gag) - { - char *p = loc.toChars(); - if (!*p) - p = locToChars(); - - if (*p) - fprintf(stdmsg, "%s: ", p); - mem.free(p); - - fprintf(stdmsg, "Error: "); - fprintf(stdmsg, "%s %s ", kind(), toPrettyChars()); - - vfprintf(stdmsg, format, ap); - - fprintf(stdmsg, "\n"); - fflush(stdmsg); -halt(); - } - else - { - global.gaggedErrors++; - } - - global.errors++; - - //fatal(); -} - -void Dsymbol::checkDeprecated(Loc loc, Scope *sc) -{ - if (!global.params.useDeprecated && isDeprecated()) - { - // Don't complain if we're inside a deprecated symbol's scope - for (Dsymbol *sp = sc->parent; sp; sp = sp->parent) - { if (sp->isDeprecated()) - goto L1; - } - - for (Scope *sc2 = sc; sc2; sc2 = sc2->enclosing) - { - if (sc2->scopesym && sc2->scopesym->isDeprecated()) - goto L1; - - // If inside a StorageClassDeclaration that is deprecated - if (sc2->stc & STCdeprecated) - goto L1; - } - - error(loc, "is deprecated"); - } - - L1: - Declaration *d = isDeclaration(); - if (d && d->storage_class & STCdisable) - { - if (!(sc->func && sc->func->storage_class & STCdisable)) - { - if (d->ident == Id::cpctor && d->toParent()) - d->toParent()->error(loc, "is not copyable because it is annotated with @disable"); - else - error(loc, "is not callable because it is annotated with @disable"); - } - } -} - -/********************************** - * Determine which Module a Dsymbol is in. - */ - -Module *Dsymbol::getModule() -{ - //printf("Dsymbol::getModule()\n"); - TemplateDeclaration *td = getFuncTemplateDecl(this); - if (td) - return td->getModule(); - - Dsymbol *s = this; - while (s) - { - //printf("\ts = %s '%s'\n", s->kind(), s->toPrettyChars()); - Module *m = s->isModule(); - if (m) - return m; - s = s->parent; - } - return NULL; -} - -/********************************** - * Determine which Module a Dsymbol is in, as far as access rights go. - */ - -Module *Dsymbol::getAccessModule() -{ - //printf("Dsymbol::getAccessModule()\n"); - TemplateDeclaration *td = getFuncTemplateDecl(this); - if (td) - return td->getAccessModule(); - - Dsymbol *s = this; - while (s) - { - //printf("\ts = %s '%s'\n", s->kind(), s->toPrettyChars()); - Module *m = s->isModule(); - if (m) - return m; - TemplateInstance *ti = s->isTemplateInstance(); - if (ti && ti->isnested) - /* Because of local template instantiation, the parent isn't where the access - * rights come from - it's the template declaration - */ - s = ti->tempdecl; - else - s = s->parent; - } - return NULL; -} - -/************************************* - */ - -enum PROT Dsymbol::prot() -{ - return PROTpublic; -} - -/************************************* - * Do syntax copy of an array of Dsymbol's. - */ - - -Dsymbols *Dsymbol::arraySyntaxCopy(Dsymbols *a) -{ - - Dsymbols *b = NULL; - if (a) - { - b = a->copy(); - for (size_t i = 0; i < b->dim; i++) - { - Dsymbol *s = (*b)[i]; - - s = s->syntaxCopy(NULL); - (*b)[i] = s; - } - } - return b; -} - - -/**************************************** - * Add documentation comment to Dsymbol. - * Ignore NULL comments. - */ - -void Dsymbol::addComment(unsigned char *comment) -{ - //if (comment) - //printf("adding comment '%s' to symbol %p '%s'\n", comment, this, toChars()); - - if (!this->comment) - this->comment = comment; -#if 1 - else if (comment && strcmp((char *)comment, (char *)this->comment)) - { // Concatenate the two - this->comment = Lexer::combineComments(this->comment, comment); - } -#endif -} - -/********************************* OverloadSet ****************************/ - -#if DMDV2 -OverloadSet::OverloadSet() - : Dsymbol() -{ -} - -void OverloadSet::push(Dsymbol *s) -{ - a.push(s); -} - -const char *OverloadSet::kind() -{ - return "overloadset"; -} -#endif - - -/********************************* ScopeDsymbol ****************************/ - -ScopeDsymbol::ScopeDsymbol() - : Dsymbol() -{ - members = NULL; - symtab = NULL; - imports = NULL; - prots = NULL; -} - -ScopeDsymbol::ScopeDsymbol(Identifier *id) - : Dsymbol(id) -{ - members = NULL; - symtab = NULL; - imports = NULL; - prots = NULL; -} - -Dsymbol *ScopeDsymbol::syntaxCopy(Dsymbol *s) -{ - //printf("ScopeDsymbol::syntaxCopy('%s')\n", toChars()); - - ScopeDsymbol *sd; - if (s) - sd = (ScopeDsymbol *)s; - else - sd = new ScopeDsymbol(ident); - sd->members = arraySyntaxCopy(members); - return sd; -} - -Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags) -{ - //printf("%s->ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident->toChars(), flags); - //if (strcmp(ident->toChars(),"c") == 0) *(char*)0=0; - - // Look in symbols declared in this module - Dsymbol *s = symtab ? symtab->lookup(ident) : NULL; - //printf("\ts = %p, imports = %p, %d\n", s, imports, imports ? imports->dim : 0); - // hide the aliases generated by selective or renamed private imports - if (s && flags & 1) - if (AliasDeclaration* ad = s->isAliasDeclaration()) - // may be a private alias to a function that is overloaded. these - // are sorted out during overload resolution, accept them here - if (ad->importprot == PROTprivate && !ad->aliassym->isFuncAliasDeclaration()) - s = NULL; - - if (s) - { - //printf("\ts = '%s.%s'\n",toChars(),s->toChars()); - } - else if (imports) - { - OverloadSet *a = NULL; - - // Look in imported modules - for (size_t i = 0; i < imports->dim; i++) - { Dsymbol *ss = (*imports)[i]; - Dsymbol *s2; - - // If private import, don't search it - if (flags & 1 && prots[i] == PROTprivate) - continue; - - //printf("\tscanning import '%s', prots = %d, isModule = %p, isImport = %p\n", ss->toChars(), prots[i], ss->isModule(), ss->isImport()); - /* Don't find private members if ss is a module - */ - s2 = ss->search(loc, ident, ss->isModule() ? 1 : 0); - if (!s) - s = s2; - else if (s2 && s != s2) - { - if (s->toAlias() == s2->toAlias()) - { - /* After following aliases, we found the same - * symbol, so it's not an ambiguity. But if one - * alias is deprecated or less accessible, prefer - * the other. - */ - if (s->isDeprecated() || - s2->prot() > s->prot() && s2->prot() != PROTnone) - s = s2; - } - else - { - /* Two imports of the same module should be regarded as - * the same. - */ - Import *i1 = s->isImport(); - Import *i2 = s2->isImport(); - if (!(i1 && i2 && - (i1->mod == i2->mod || - (!i1->parent->isImport() && !i2->parent->isImport() && - i1->ident->equals(i2->ident)) - ) - ) - ) - { - /* If both s2 and s are overloadable (though we only - * need to check s once) - */ - if (s2->isOverloadable() && (a || s->isOverloadable())) - { if (!a) - a = new OverloadSet(); - /* Don't add to a[] if s2 is alias of previous sym - */ - for (size_t j = 0; j < a->a.dim; j++) - { Dsymbol *s3 = a->a[j]; - if (s2->toAlias() == s3->toAlias()) - { - if (s3->isDeprecated() || - s2->prot() > s3->prot() && s2->prot() != PROTnone) - a->a[j] = s2; - goto Lcontinue; - } - } - a->push(s2); - Lcontinue: - continue; - } - if (flags & 4) // if return NULL on ambiguity - return NULL; - if (!(flags & 2)) - ScopeDsymbol::multiplyDefined(loc, s, s2); - break; - } - } - } - } - - /* Build special symbol if we had multiple finds - */ - if (a) - { assert(s); - a->push(s); - s = a; - } - - if (s) - { - Declaration *d = s->isDeclaration(); - if (d && d->protection == PROTprivate && - !d->parent->isTemplateMixin() && - !(flags & 2)) - error(loc, "%s is private", d->toPrettyChars()); - } - } - return s; -} - -void ScopeDsymbol::importScope(Dsymbol *s, enum PROT protection) -{ - //printf("%s->ScopeDsymbol::importScope(%s, %d)\n", toChars(), s->toChars(), protection); - - // No circular or redundant import's - if (s != this) - { - if (!imports) - imports = new Dsymbols(); - else - { - for (size_t i = 0; i < imports->dim; i++) - { Dsymbol *ss = (*imports)[i]; - if (ss == s) // if already imported - { - if (protection > prots[i]) - prots[i] = protection; // upgrade access - return; - } - } - } - imports->push(s); - prots = (unsigned char *)mem.realloc(prots, imports->dim * sizeof(prots[0])); - prots[imports->dim - 1] = protection; - } -} - -int ScopeDsymbol::isforwardRef() -{ - return (members == NULL); -} - -void ScopeDsymbol::defineRef(Dsymbol *s) -{ - ScopeDsymbol *ss; - - ss = s->isScopeDsymbol(); - members = ss->members; - ss->members = NULL; -} - -void ScopeDsymbol::multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2) -{ -#if 0 - printf("ScopeDsymbol::multiplyDefined()\n"); - printf("s1 = %p, '%s' kind = '%s', parent = %s\n", s1, s1->toChars(), s1->kind(), s1->parent ? s1->parent->toChars() : ""); - printf("s2 = %p, '%s' kind = '%s', parent = %s\n", s2, s2->toChars(), s2->kind(), s2->parent ? s2->parent->toChars() : ""); -#endif - if (loc.filename) - { ::error(loc, "%s at %s conflicts with %s at %s", - s1->toPrettyChars(), - s1->locToChars(), - s2->toPrettyChars(), - s2->locToChars()); - } - else - { - s1->error(loc, "conflicts with %s %s at %s", - s2->kind(), - s2->toPrettyChars(), - s2->locToChars()); - } -} - -Dsymbol *ScopeDsymbol::nameCollision(Dsymbol *s) -{ - Dsymbol *sprev; - - // Look to see if we are defining a forward referenced symbol - - sprev = symtab->lookup(s->ident); - assert(sprev); - if (s->equals(sprev)) // if the same symbol - { - if (s->isforwardRef()) // if second declaration is a forward reference - return sprev; - if (sprev->isforwardRef()) - { - sprev->defineRef(s); // copy data from s into sprev - return sprev; - } - } - multiplyDefined(0, s, sprev); - return sprev; -} - -const char *ScopeDsymbol::kind() -{ - return "ScopeDsymbol"; -} - -Dsymbol *ScopeDsymbol::symtabInsert(Dsymbol *s) -{ - return symtab->insert(s); -} - -/**************************************** - * Return true if any of the members are static ctors or static dtors, or if - * any members have members that are. - */ - -bool ScopeDsymbol::hasStaticCtorOrDtor() -{ - if (members) - { - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *member = (*members)[i]; - - if (member->hasStaticCtorOrDtor()) - return TRUE; - } - } - return FALSE; -} - -/*************************************** - * Determine number of Dsymbols, folding in AttribDeclaration members. - */ - -#if DMDV2 -static int dimDg(void *ctx, size_t n, Dsymbol *) -{ - ++*(size_t *)ctx; - return 0; -} - -size_t ScopeDsymbol::dim(Dsymbols *members) -{ - size_t n = 0; - foreach(NULL, members, &dimDg, &n); - return n; -} -#endif - -/*************************************** - * Get nth Dsymbol, folding in AttribDeclaration members. - * Returns: - * Dsymbol* nth Dsymbol - * NULL not found, *pn gets incremented by the number - * of Dsymbols - */ - -#if DMDV2 -struct GetNthSymbolCtx -{ - size_t nth; - Dsymbol *sym; -}; - -static int getNthSymbolDg(void *ctx, size_t n, Dsymbol *sym) -{ - GetNthSymbolCtx *p = (GetNthSymbolCtx *)ctx; - if (n == p->nth) - { p->sym = sym; - return 1; - } - return 0; -} - -Dsymbol *ScopeDsymbol::getNth(Dsymbols *members, size_t nth, size_t *pn) -{ - GetNthSymbolCtx ctx = { nth, NULL }; - int res = foreach(NULL, members, &getNthSymbolDg, &ctx); - return res ? ctx.sym : NULL; -} -#endif - -/*************************************** - * Expands attribute declarations in members in depth first - * order. Calls dg(void *ctx, size_t symidx, Dsymbol *sym) for each - * member. - * If dg returns !=0, stops and returns that value else returns 0. - * Use this function to avoid the O(N + N^2/2) complexity of - * calculating dim and calling N times getNth. - */ - -#if DMDV2 -int ScopeDsymbol::foreach(Scope *sc, Dsymbols *members, ScopeDsymbol::ForeachDg dg, void *ctx, size_t *pn) -{ - assert(dg); - if (!members) - return 0; - - size_t n = pn ? *pn : 0; // take over index - int result = 0; - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (*members)[i]; - - if (AttribDeclaration *a = s->isAttribDeclaration()) - result = foreach(sc, a->include(sc, NULL), dg, ctx, &n); - else if (TemplateMixin *tm = s->isTemplateMixin()) - result = foreach(sc, tm->members, dg, ctx, &n); - else if (s->isTemplateInstance()) - ; - else - result = dg(ctx, n++, s); - - if (result) - break; - } - - if (pn) - *pn = n; // update index - return result; -} -#endif - -/******************************************* - * Look for member of the form: - * const(MemberInfo)[] getMembers(string); - * Returns NULL if not found - */ - -#if DMDV2 -FuncDeclaration *ScopeDsymbol::findGetMembers() -{ - Dsymbol *s = search_function(this, Id::getmembers); - FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL; - -#if 0 // Finish - static TypeFunction *tfgetmembers; - - if (!tfgetmembers) - { - Scope sc; - Parameters *arguments = new Parameters; - Parameters *arg = new Parameter(STCin, Type::tchar->constOf()->arrayOf(), NULL, NULL); - arguments->push(arg); - - Type *tret = NULL; - tfgetmembers = new TypeFunction(arguments, tret, 0, LINKd); - tfgetmembers = (TypeFunction *)tfgetmembers->semantic(0, &sc); - } - if (fdx) - fdx = fdx->overloadExactMatch(tfgetmembers); -#endif - if (fdx && fdx->isVirtual()) - fdx = NULL; - - return fdx; -} -#endif - - -/****************************** WithScopeSymbol ******************************/ - -WithScopeSymbol::WithScopeSymbol(WithStatement *withstate) - : ScopeDsymbol() -{ - this->withstate = withstate; -} - -Dsymbol *WithScopeSymbol::search(Loc loc, Identifier *ident, int flags) -{ - // Acts as proxy to the with class declaration - return withstate->exp->type->toDsymbol(NULL)->search(loc, ident, 0); -} - -/****************************** ArrayScopeSymbol ******************************/ - -ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, Expression *e) - : ScopeDsymbol() -{ - assert(e->op == TOKindex || e->op == TOKslice || e->op == TOKarray); - exp = e; - type = NULL; - td = NULL; - this->sc = sc; -} - -ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, TypeTuple *t) - : ScopeDsymbol() -{ - exp = NULL; - type = t; - td = NULL; - this->sc = sc; -} - -ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, TupleDeclaration *s) - : ScopeDsymbol() -{ - exp = NULL; - type = NULL; - td = s; - this->sc = sc; -} - -Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags) -{ - //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident->toChars(), flags); - if (ident == Id::length || ident == Id::dollar) - { VarDeclaration **pvar; - Expression *ce; - - if (ident == Id::length && !global.params.useDeprecated) - error("using 'length' inside [ ] is deprecated, use '$' instead"); - - L1: - - if (td) - { /* $ gives the number of elements in the tuple - */ - VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); - Expression *e = new IntegerExp(0, td->objects->dim, Type::tsize_t); - v->init = new ExpInitializer(0, e); - v->storage_class |= STCstatic | STCconst; - v->semantic(sc); - return v; - } - - if (type) - { /* $ gives the number of type entries in the type tuple - */ - VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); - Expression *e = new IntegerExp(0, type->arguments->dim, Type::tsize_t); - v->init = new ExpInitializer(0, e); - v->storage_class |= STCstatic | STCconst; - v->semantic(sc); - return v; - } - - if (exp->op == TOKindex) - { /* array[index] where index is some function of $ - */ - IndexExp *ie = (IndexExp *)exp; - - pvar = &ie->lengthVar; - ce = ie->e1; - } - else if (exp->op == TOKslice) - { /* array[lwr .. upr] where lwr or upr is some function of $ - */ - SliceExp *se = (SliceExp *)exp; - - pvar = &se->lengthVar; - ce = se->e1; - } - else if (exp->op == TOKarray) - { /* array[e0, e1, e2, e3] where e0, e1, e2 are some function of $ - * $ is a opDollar!(dim)() where dim is the dimension(0,1,2,...) - */ - ArrayExp *ae = (ArrayExp *)exp; - AggregateDeclaration *ad = NULL; - - Type *t = ae->e1->type->toBasetype(); - if (t->ty == Tclass) - { - ad = ((TypeClass *)t)->sym; - } - else if (t->ty == Tstruct) - { - ad = ((TypeStruct *)t)->sym; - } - assert(ad); - - Dsymbol *dsym = search_function(ad, Id::opDollar); - if (!dsym) // no dollar exists -- search in higher scope - return NULL; - VarDeclaration *v = ae->lengthVar; - if (!v) - { // $ is lazily initialized. Create it now. - TemplateDeclaration *td = dsym->isTemplateDeclaration(); - if (td) - { // Instantiate opDollar!(dim) with the index as a template argument - Objects *tdargs = new Objects(); - tdargs->setDim(1); - - Expression *x = new IntegerExp(0, ae->currentDimension, Type::tsize_t); - x = x->semantic(sc); - tdargs->data[0] = x; - - //TemplateInstance *ti = new TemplateInstance(loc, td, tdargs); - //ti->semantic(sc); - - DotTemplateInstanceExp *dte = new DotTemplateInstanceExp(loc, ae->e1, td->ident, tdargs); - - v = new VarDeclaration(loc, NULL, Id::dollar, new ExpInitializer(0, dte)); - } - else - { /* opDollar exists, but it's a function, not a template. - * This is acceptable ONLY for single-dimension indexing. - * Note that it's impossible to have both template & function opDollar, - * because both take no arguments. - */ - if (ae->arguments->dim != 1) { - ae->error("%s only defines opDollar for one dimension", ad->toChars()); - return NULL; - } - FuncDeclaration *fd = dsym->isFuncDeclaration(); - assert(fd); - Expression * x = new DotVarExp(loc, ae->e1, fd); - - v = new VarDeclaration(loc, NULL, Id::dollar, new ExpInitializer(0, x)); - } - v->semantic(sc); - ae->lengthVar = v; - } - return v; - } - else - /* Didn't find $, look in enclosing scope(s). - */ - return NULL; - - /* If we are indexing into an array that is really a type - * tuple, rewrite this as an index into a type tuple and - * try again. - */ - if (ce->op == TOKtype) - { - Type *t = ((TypeExp *)ce)->type; - if (t->ty == Ttuple) - { type = (TypeTuple *)t; - goto L1; - } - } - - /* *pvar is lazily initialized, so if we refer to $ - * multiple times, it gets set only once. - */ - if (!*pvar) // if not already initialized - { /* Create variable v and set it to the value of $ - */ - VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); - if (ce->op == TOKtuple) - { /* It is for an expression tuple, so the - * length will be a const. - */ - Expression *e = new IntegerExp(0, ((TupleExp *)ce)->exps->dim, Type::tsize_t); - v->init = new ExpInitializer(0, e); - v->storage_class |= STCstatic | STCconst; - } - else - { /* For arrays, $ will either be a compile-time constant - * (in which case its value in set during constant-folding), - * or a variable (in which case an expression is created in - * toir.c). - */ - VoidInitializer *e = new VoidInitializer(0); - e->type = Type::tsize_t; - v->init = e; - } - *pvar = v; - } - (*pvar)->semantic(sc); - return (*pvar); - } - return NULL; -} - - -/****************************** DsymbolTable ******************************/ - -DsymbolTable::DsymbolTable() -{ -#if STRINGTABLE - tab = new StringTable; - tab->init(); -#else - tab = NULL; -#endif -} - -DsymbolTable::~DsymbolTable() -{ -#if STRINGTABLE - delete tab; -#endif -} - -Dsymbol *DsymbolTable::lookup(Identifier *ident) -{ -#if STRINGTABLE -#ifdef DEBUG - assert(ident); - assert(tab); -#endif - //printf("DsymbolTable::lookup(%s)\n", (char*)ident->string); - StringValue *sv = tab->lookup((char*)ident->string, ident->len); - return (Dsymbol *)(sv ? sv->ptrvalue : NULL); -#else - //printf("DsymbolTable::lookup(%s)\n", (char*)ident->string); - return (Dsymbol *)_aaGetRvalue(tab, ident); -#endif -} - -Dsymbol *DsymbolTable::insert(Dsymbol *s) -{ - //printf("DsymbolTable::insert(this = %p, '%s')\n", this, s->ident->toChars()); - Identifier *ident = s->ident; -#if STRINGTABLE -#ifdef DEBUG - assert(ident); - assert(tab); -#endif - StringValue *sv = tab->insert(ident->toChars(), ident->len); - if (!sv) - return NULL; // already in table - sv->ptrvalue = s; - return s; -#else - Dsymbol **ps = (Dsymbol **)_aaGet(&tab, ident); - if (*ps) - return NULL; // already in table - *ps = s; - return s; -#endif -} - -Dsymbol *DsymbolTable::insert(Identifier *ident, Dsymbol *s) -{ - //printf("DsymbolTable::insert()\n"); -#if STRINGTABLE - StringValue *sv = tab->insert(ident->toChars(), ident->len); - if (!sv) - return NULL; // already in table - sv->ptrvalue = s; - return s; -#else - Dsymbol **ps = (Dsymbol **)_aaGet(&tab, ident); - if (*ps) - return NULL; // already in table - *ps = s; - return s; -#endif -} - -Dsymbol *DsymbolTable::update(Dsymbol *s) -{ - Identifier *ident = s->ident; -#if STRINGTABLE - StringValue *sv = tab->update(ident->toChars(), ident->len); - sv->ptrvalue = s; - return s; -#else - Dsymbol **ps = (Dsymbol **)_aaGet(&tab, ident); - *ps = s; - return s; -#endif -} - - - - + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2012 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include +#include +#include + +#include "rmem.h" +#include "speller.h" +#include "aav.h" + +#include "mars.h" +#include "dsymbol.h" +#include "aggregate.h" +#include "identifier.h" +#include "module.h" +#include "mtype.h" +#include "expression.h" +#include "statement.h" +#include "declaration.h" +#include "id.h" +#include "scope.h" +#include "init.h" +#include "import.h" +#include "template.h" +#include "attrib.h" +#if IN_LLVM +#include "../gen/pragma.h" +#endif + +/****************************** Dsymbol ******************************/ + +Dsymbol::Dsymbol() +{ + //printf("Dsymbol::Dsymbol(%p)\n", this); + this->ident = NULL; + this->c_ident = NULL; + this->parent = NULL; +#if IN_DMD + this->csym = NULL; + this->isym = NULL; +#endif + this->loc = 0; + this->comment = NULL; + this->scope = NULL; + this->errors = false; + +#if IN_LLVM + this->llvmInternal = LLVMnone; + this->irsym = NULL; +#endif +} + +Dsymbol::Dsymbol(Identifier *ident) +{ + //printf("Dsymbol::Dsymbol(%p, ident)\n", this); + this->ident = ident; + this->c_ident = NULL; + this->parent = NULL; +#if IN_DMD + this->csym = NULL; + this->isym = NULL; +#endif + this->loc = 0; + this->comment = NULL; + this->scope = NULL; + this->errors = false; + +#if IN_LLVM + this->llvmInternal = LLVMnone; + this->irsym = NULL; +#endif +} + +int Dsymbol::equals(Object *o) +{ Dsymbol *s; + + if (this == o) + return TRUE; + s = (Dsymbol *)(o); + // Overload sets don't have an ident + if (s && ident && s->ident && ident->equals(s->ident)) + return TRUE; + return FALSE; +} + +/************************************** + * Copy the syntax. + * Used for template instantiations. + * If s is NULL, allocate the new object, otherwise fill it in. + */ + +Dsymbol *Dsymbol::syntaxCopy(Dsymbol *s) +{ + print(); + printf("%s %s\n", kind(), toChars()); + assert(0); + return NULL; +} + +/************************************** + * Determine if this symbol is only one. + * Returns: + * FALSE, *ps = NULL: There are 2 or more symbols + * TRUE, *ps = NULL: There are zero symbols + * TRUE, *ps = symbol: The one and only one symbol + */ + +int Dsymbol::oneMember(Dsymbol **ps, Identifier *ident) +{ + //printf("Dsymbol::oneMember()\n"); + *ps = this; + return TRUE; +} + +/***************************************** + * Same as Dsymbol::oneMember(), but look at an array of Dsymbols. + */ + +int Dsymbol::oneMembers(Dsymbols *members, Dsymbol **ps, Identifier *ident) +{ + //printf("Dsymbol::oneMembers() %d\n", members ? members->dim : 0); + Dsymbol *s = NULL; + + if (members) + { + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *sx = (*members)[i]; + + int x = sx->oneMember(ps, ident); + //printf("\t[%d] kind %s = %d, s = %p\n", i, sx->kind(), x, *ps); + if (!x) + { + //printf("\tfalse 1\n"); + assert(*ps == NULL); + return FALSE; + } + if (*ps) + { + if (ident) + { + if (!(*ps)->ident || !(*ps)->ident->equals(ident)) + continue; + } + if (!s) + s = *ps; + else if (s->isOverloadable() && (*ps)->isOverloadable()) + ; // keep head of overload set + else // more than one symbol + { *ps = NULL; + //printf("\tfalse 2\n"); + return FALSE; + } + } + } + } + *ps = s; // s is the one symbol, NULL if none + //printf("\ttrue\n"); + return TRUE; +} + +/***************************************** + * Is Dsymbol a variable that contains pointers? + */ + +int Dsymbol::hasPointers() +{ + //printf("Dsymbol::hasPointers() %s\n", toChars()); + return 0; +} + +bool Dsymbol::hasStaticCtorOrDtor() +{ + //printf("Dsymbol::hasStaticCtorOrDtor() %s\n", toChars()); + return FALSE; +} + +void Dsymbol::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion) +{ +} + +char *Dsymbol::toChars() +{ + return ident ? ident->toChars() : (char *)"__anonymous"; +} + +const char *Dsymbol::toPrettyChars() +{ Dsymbol *p; + char *s; + char *q; + size_t len; + + //printf("Dsymbol::toPrettyChars() '%s'\n", toChars()); + if (!parent) + return toChars(); + + len = 0; + for (p = this; p; p = p->parent) + len += strlen(p->toChars()) + 1; + + s = (char *)mem.malloc(len); + q = s + len - 1; + *q = 0; + for (p = this; p; p = p->parent) + { + char *t = p->toChars(); + len = strlen(t); + q -= len; + memcpy(q, t, len); + if (q == s) + break; + q--; +#if TARGET_NET + if (AggregateDeclaration* ad = p->isAggregateDeclaration()) + { + if (ad->isNested() && p->parent && p->parent->isAggregateDeclaration()) + { + *q = '/'; + continue; + } + } +#endif + *q = '.'; + } + return s; +} + +char *Dsymbol::locToChars() +{ + OutBuffer buf; + + if (!loc.filename) // avoid bug 5861. + { + Module *m = getModule(); + + if (m && m->srcfile) + loc.filename = m->srcfile->toChars(); + } + return loc.toChars(); +} + +const char *Dsymbol::kind() +{ + return "symbol"; +} + +/********************************* + * If this symbol is really an alias for another, + * return that other. + */ + +Dsymbol *Dsymbol::toAlias() +{ + return this; +} + +Dsymbol *Dsymbol::toParent() +{ + return parent ? parent->pastMixin() : NULL; +} + +Dsymbol *Dsymbol::pastMixin() +{ + Dsymbol *s = this; + + //printf("Dsymbol::pastMixin() %s\n", toChars()); + while (s && s->isTemplateMixin()) + s = s->parent; + return s; +} + +/********************************** + * Use this instead of toParent() when looking for the + * 'this' pointer of the enclosing function/class. + */ + +Dsymbol *Dsymbol::toParent2() +{ + Dsymbol *s = parent; + while (s && s->isTemplateInstance()) + s = s->parent; + return s; +} + +TemplateInstance *Dsymbol::inTemplateInstance() +{ + for (Dsymbol *parent = this->parent; parent; parent = parent->parent) + { + TemplateInstance *ti = parent->isTemplateInstance(); + if (ti) + return ti; + } + return NULL; +} + +// Check if this function is a member of a template which has only been +// instantiated speculatively, eg from inside is(typeof()). +// Return the speculative template instance it is part of, +// or NULL if not speculative. +TemplateInstance *Dsymbol::isSpeculative() +{ + Dsymbol * par = parent; + while (par) + { + TemplateInstance *ti = par->isTemplateInstance(); + if (ti && ti->speculative) + return ti; + par = par->toParent(); + } + return NULL; +} + +int Dsymbol::isAnonymous() +{ + return ident ? 0 : 1; +} + +/************************************* + * Set scope for future semantic analysis so we can + * deal better with forward references. + */ + +void Dsymbol::setScope(Scope *sc) +{ + //printf("Dsymbol::setScope() %p %s, %p stc = %llx\n", this, toChars(), sc, sc->stc); + if (!sc->nofree) + sc->setNoFree(); // may need it even after semantic() finishes + scope = sc; +} + +void Dsymbol::importAll(Scope *sc) +{ +} + +/************************************* + * Does semantic analysis on the public face of declarations. + */ + +void Dsymbol::semantic0(Scope *sc) +{ +} + +void Dsymbol::semantic(Scope *sc) +{ + error("%p has no semantic routine", this); +} + +/************************************* + * Does semantic analysis on initializers and members of aggregates. + */ + +void Dsymbol::semantic2(Scope *sc) +{ + // Most Dsymbols have no further semantic analysis needed +} + +/************************************* + * Does semantic analysis on function bodies. + */ + +void Dsymbol::semantic3(Scope *sc) +{ + // Most Dsymbols have no further semantic analysis needed +} + +/************************************* + * Look for function inlining possibilities. + */ + +void Dsymbol::inlineScan() +{ + // Most Dsymbols aren't functions +} + +/********************************************* + * Search for ident as member of s. + * Input: + * flags: 1 don't find private members + * 2 don't give error messages + * 4 return NULL if ambiguous + * Returns: + * NULL if not found + */ + +Dsymbol *Dsymbol::search(Loc loc, Identifier *ident, int flags) +{ + //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars()); + return NULL; +} + +/*************************************************** + * Search for symbol with correct spelling. + */ + +void *symbol_search_fp(void *arg, const char *seed) +{ + /* If not in the lexer's string table, it certainly isn't in the symbol table. + * Doing this first is a lot faster. + */ + size_t len = strlen(seed); + if (!len) + return NULL; + StringValue *sv = Lexer::stringtable.lookup(seed, len); + if (!sv) + return NULL; + Identifier *id = (Identifier *)sv->ptrvalue; + assert(id); + + Dsymbol *s = (Dsymbol *)arg; + Module::clearCache(); + return s->search(0, id, 4|2); +} + +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. + * Returns: + * symbol found, NULL if not + */ + +Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, Identifier *id) +{ + //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars()); + Dsymbol *s = toAlias(); + Dsymbol *sm; + + switch (id->dyncast()) + { + case DYNCAST_IDENTIFIER: + sm = s->search(loc, id, 0); + break; + + case DYNCAST_DSYMBOL: + { // It's a template instance + //printf("\ttemplate instance id\n"); + Dsymbol *st = (Dsymbol *)id; + TemplateInstance *ti = st->isTemplateInstance(); + id = ti->name; + sm = s->search(loc, id, 0); + if (!sm) + { + sm = s->search_correct(id); + if (sm) + error("template identifier '%s' is not a member of '%s %s', did you mean '%s %s'?", + id->toChars(), s->kind(), s->toChars(), sm->kind(), sm->toChars()); + else + error("template identifier '%s' is not a member of '%s %s'", + id->toChars(), s->kind(), s->toChars()); + return NULL; + } + sm = sm->toAlias(); + TemplateDeclaration *td = sm->isTemplateDeclaration(); + if (!td) + { + error("%s is not a template, it is a %s", id->toChars(), sm->kind()); + return NULL; + } + ti->tempdecl = td; + if (!ti->semanticRun) + ti->semantic(sc); + sm = ti->toAlias(); + break; + } + + default: + assert(0); + } + return sm; +} + +int Dsymbol::overloadInsert(Dsymbol *s) +{ + //printf("Dsymbol::overloadInsert('%s')\n", s->toChars()); + return FALSE; +} + +void Dsymbol::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(toChars()); +} + +unsigned Dsymbol::size(Loc loc) +{ + error("Dsymbol '%s' has no size\n", toChars()); + return 0; +} + +int Dsymbol::isforwardRef() +{ + return FALSE; +} + +AggregateDeclaration *Dsymbol::isThis() +{ + return NULL; +} + +AggregateDeclaration *Dsymbol::isAggregateMember() // are we a member of an aggregate? +{ + Dsymbol *parent = toParent(); + if (parent && parent->isAggregateDeclaration()) + return (AggregateDeclaration *)parent; + return NULL; +} + +ClassDeclaration *Dsymbol::isClassMember() // are we a member of a class? +{ + AggregateDeclaration *ad = isAggregateMember(); + return ad ? ad->isClassDeclaration() : NULL; +} + +void Dsymbol::defineRef(Dsymbol *s) +{ + assert(0); +} + +int Dsymbol::isExport() +{ + return FALSE; +} + +int Dsymbol::isImportedSymbol() +{ + return FALSE; +} + +int Dsymbol::isDeprecated() +{ + return FALSE; +} + +#if DMDV2 +int Dsymbol::isOverloadable() +{ + return 0; +} + +int Dsymbol::hasOverloads() +{ + return 0; +} +#endif + +LabelDsymbol *Dsymbol::isLabel() // is this a LabelDsymbol()? +{ + return NULL; +} + +AggregateDeclaration *Dsymbol::isMember() // is this a member of an AggregateDeclaration? +{ + //printf("Dsymbol::isMember() %s\n", toChars()); + Dsymbol *parent = toParent(); + //printf("parent is %s %s\n", parent->kind(), parent->toChars()); + return parent ? parent->isAggregateDeclaration() : NULL; +} + +Type *Dsymbol::getType() +{ + return NULL; +} + +int Dsymbol::needThis() +{ + return FALSE; +} + +int Dsymbol::apply(Dsymbol_apply_ft_t fp, void *param) +{ + return (*fp)(this, param); +} + +int Dsymbol::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) +{ + //printf("Dsymbol::addMember('%s')\n", toChars()); + //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sd->toChars()); + //printf("Dsymbol::addMember(this = %p, '%s' sd = %p, sd->symtab = %p)\n", this, toChars(), sd, sd->symtab); + parent = sd; + if (!isAnonymous()) // no name, so can't add it to symbol table + { + if (!sd->symtabInsert(this)) // if name is already defined + { + Dsymbol *s2; + + s2 = sd->symtab->lookup(ident); + if (!s2->overloadInsert(this)) + { + sd->multiplyDefined(0, this, s2); + } + } + if (sd->isAggregateDeclaration() || sd->isEnumDeclaration()) + { + if (ident == Id::__sizeof || ident == Id::__xalignof || ident == Id::mangleof) + error(".%s property cannot be redefined", ident->toChars()); + } + return 1; + } + return 0; +} + +void Dsymbol::error(const char *format, ...) +{ + //printf("Dsymbol::error()\n"); + if (!loc.filename) // avoid bug 5861. + { + Module *m = getModule(); + + if (m && m->srcfile) + loc.filename = m->srcfile->toChars(); + } + va_list ap; + va_start(ap, format); + verror(loc, format, ap); + va_end(ap); +} + +void Dsymbol::error(Loc loc, const char *format, ...) +{ + va_list ap; + va_start(ap, format); + verror(loc, format, ap); + va_end(ap); +} + +void Dsymbol::verror(Loc loc, const char *format, va_list ap) +{ + if (!global.gag) + { + char *p = loc.toChars(); + if (!*p) + p = locToChars(); + + if (*p) + fprintf(stdmsg, "%s: ", p); + mem.free(p); + + fprintf(stdmsg, "Error: "); + fprintf(stdmsg, "%s %s ", kind(), toPrettyChars()); + + vfprintf(stdmsg, format, ap); + + fprintf(stdmsg, "\n"); + fflush(stdmsg); +halt(); + } + else + { + global.gaggedErrors++; + } + + global.errors++; + + //fatal(); +} + +void Dsymbol::checkDeprecated(Loc loc, Scope *sc) +{ + if (!global.params.useDeprecated && isDeprecated()) + { + // Don't complain if we're inside a deprecated symbol's scope + for (Dsymbol *sp = sc->parent; sp; sp = sp->parent) + { if (sp->isDeprecated()) + goto L1; + } + + for (Scope *sc2 = sc; sc2; sc2 = sc2->enclosing) + { + if (sc2->scopesym && sc2->scopesym->isDeprecated()) + goto L1; + + // If inside a StorageClassDeclaration that is deprecated + if (sc2->stc & STCdeprecated) + goto L1; + } + + error(loc, "is deprecated"); + } + + L1: + Declaration *d = isDeclaration(); + if (d && d->storage_class & STCdisable) + { + if (!(sc->func && sc->func->storage_class & STCdisable)) + { + if (d->ident == Id::cpctor && d->toParent()) + d->toParent()->error(loc, "is not copyable because it is annotated with @disable"); + else + error(loc, "is not callable because it is annotated with @disable"); + } + } +} + +/********************************** + * Determine which Module a Dsymbol is in. + */ + +Module *Dsymbol::getModule() +{ + //printf("Dsymbol::getModule()\n"); + TemplateDeclaration *td = getFuncTemplateDecl(this); + if (td) + return td->getModule(); + + Dsymbol *s = this; + while (s) + { + //printf("\ts = %s '%s'\n", s->kind(), s->toPrettyChars()); + Module *m = s->isModule(); + if (m) + return m; + s = s->parent; + } + return NULL; +} + +/********************************** + * Determine which Module a Dsymbol is in, as far as access rights go. + */ + +Module *Dsymbol::getAccessModule() +{ + //printf("Dsymbol::getAccessModule()\n"); + TemplateDeclaration *td = getFuncTemplateDecl(this); + if (td) + return td->getAccessModule(); + + Dsymbol *s = this; + while (s) + { + //printf("\ts = %s '%s'\n", s->kind(), s->toPrettyChars()); + Module *m = s->isModule(); + if (m) + return m; + TemplateInstance *ti = s->isTemplateInstance(); + if (ti && ti->isnested) + /* Because of local template instantiation, the parent isn't where the access + * rights come from - it's the template declaration + */ + s = ti->tempdecl; + else + s = s->parent; + } + return NULL; +} + +/************************************* + */ + +enum PROT Dsymbol::prot() +{ + return PROTpublic; +} + +/************************************* + * Do syntax copy of an array of Dsymbol's. + */ + + +Dsymbols *Dsymbol::arraySyntaxCopy(Dsymbols *a) +{ + + Dsymbols *b = NULL; + if (a) + { + b = a->copy(); + for (size_t i = 0; i < b->dim; i++) + { + Dsymbol *s = (*b)[i]; + + s = s->syntaxCopy(NULL); + (*b)[i] = s; + } + } + return b; +} + + +/**************************************** + * Add documentation comment to Dsymbol. + * Ignore NULL comments. + */ + +void Dsymbol::addComment(unsigned char *comment) +{ + //if (comment) + //printf("adding comment '%s' to symbol %p '%s'\n", comment, this, toChars()); + + if (!this->comment) + this->comment = comment; +#if 1 + else if (comment && strcmp((char *)comment, (char *)this->comment)) + { // Concatenate the two + this->comment = Lexer::combineComments(this->comment, comment); + } +#endif +} + +/********************************* OverloadSet ****************************/ + +#if DMDV2 +OverloadSet::OverloadSet() + : Dsymbol() +{ +} + +void OverloadSet::push(Dsymbol *s) +{ + a.push(s); +} + +const char *OverloadSet::kind() +{ + return "overloadset"; +} +#endif + + +/********************************* ScopeDsymbol ****************************/ + +ScopeDsymbol::ScopeDsymbol() + : Dsymbol() +{ + members = NULL; + symtab = NULL; + imports = NULL; + prots = NULL; +} + +ScopeDsymbol::ScopeDsymbol(Identifier *id) + : Dsymbol(id) +{ + members = NULL; + symtab = NULL; + imports = NULL; + prots = NULL; +} + +Dsymbol *ScopeDsymbol::syntaxCopy(Dsymbol *s) +{ + //printf("ScopeDsymbol::syntaxCopy('%s')\n", toChars()); + + ScopeDsymbol *sd; + if (s) + sd = (ScopeDsymbol *)s; + else + sd = new ScopeDsymbol(ident); + sd->members = arraySyntaxCopy(members); + return sd; +} + +Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags) +{ + //printf("%s->ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident->toChars(), flags); + //if (strcmp(ident->toChars(),"c") == 0) *(char*)0=0; + + // Look in symbols declared in this module + Dsymbol *s = symtab ? symtab->lookup(ident) : NULL; + //printf("\ts = %p, imports = %p, %d\n", s, imports, imports ? imports->dim : 0); + // hide the aliases generated by selective or renamed private imports + if (s && flags & 1) + if (AliasDeclaration* ad = s->isAliasDeclaration()) + // may be a private alias to a function that is overloaded. these + // are sorted out during overload resolution, accept them here + if (ad->importprot == PROTprivate && !ad->aliassym->isFuncAliasDeclaration()) + s = NULL; + + if (s) + { + //printf("\ts = '%s.%s'\n",toChars(),s->toChars()); + } + else if (imports) + { + OverloadSet *a = NULL; + + // Look in imported modules + for (size_t i = 0; i < imports->dim; i++) + { Dsymbol *ss = (*imports)[i]; + Dsymbol *s2; + + // If private import, don't search it + if (flags & 1 && prots[i] == PROTprivate) + continue; + + //printf("\tscanning import '%s', prots = %d, isModule = %p, isImport = %p\n", ss->toChars(), prots[i], ss->isModule(), ss->isImport()); + /* Don't find private members if ss is a module + */ + s2 = ss->search(loc, ident, ss->isModule() ? 1 : 0); + if (!s) + s = s2; + else if (s2 && s != s2) + { + if (s->toAlias() == s2->toAlias()) + { + /* After following aliases, we found the same + * symbol, so it's not an ambiguity. But if one + * alias is deprecated or less accessible, prefer + * the other. + */ + if (s->isDeprecated() || + s2->prot() > s->prot() && s2->prot() != PROTnone) + s = s2; + } + else + { + /* Two imports of the same module should be regarded as + * the same. + */ + Import *i1 = s->isImport(); + Import *i2 = s2->isImport(); + if (!(i1 && i2 && + (i1->mod == i2->mod || + (!i1->parent->isImport() && !i2->parent->isImport() && + i1->ident->equals(i2->ident)) + ) + ) + ) + { + /* If both s2 and s are overloadable (though we only + * need to check s once) + */ + if (s2->isOverloadable() && (a || s->isOverloadable())) + { if (!a) + a = new OverloadSet(); + /* Don't add to a[] if s2 is alias of previous sym + */ + for (size_t j = 0; j < a->a.dim; j++) + { Dsymbol *s3 = a->a[j]; + if (s2->toAlias() == s3->toAlias()) + { + if (s3->isDeprecated() || + s2->prot() > s3->prot() && s2->prot() != PROTnone) + a->a[j] = s2; + goto Lcontinue; + } + } + a->push(s2); + Lcontinue: + continue; + } + if (flags & 4) // if return NULL on ambiguity + return NULL; + if (!(flags & 2)) + ScopeDsymbol::multiplyDefined(loc, s, s2); + break; + } + } + } + } + + /* Build special symbol if we had multiple finds + */ + if (a) + { assert(s); + a->push(s); + s = a; + } + + if (s) + { + Declaration *d = s->isDeclaration(); + if (d && d->protection == PROTprivate && + !d->parent->isTemplateMixin() && + !(flags & 2)) + error(loc, "%s is private", d->toPrettyChars()); + } + } + return s; +} + +void ScopeDsymbol::importScope(Dsymbol *s, enum PROT protection) +{ + //printf("%s->ScopeDsymbol::importScope(%s, %d)\n", toChars(), s->toChars(), protection); + + // No circular or redundant import's + if (s != this) + { + if (!imports) + imports = new Dsymbols(); + else + { + for (size_t i = 0; i < imports->dim; i++) + { Dsymbol *ss = (*imports)[i]; + if (ss == s) // if already imported + { + if (protection > prots[i]) + prots[i] = protection; // upgrade access + return; + } + } + } + imports->push(s); + prots = (unsigned char *)mem.realloc(prots, imports->dim * sizeof(prots[0])); + prots[imports->dim - 1] = protection; + } +} + +int ScopeDsymbol::isforwardRef() +{ + return (members == NULL); +} + +void ScopeDsymbol::defineRef(Dsymbol *s) +{ + ScopeDsymbol *ss; + + ss = s->isScopeDsymbol(); + members = ss->members; + ss->members = NULL; +} + +void ScopeDsymbol::multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2) +{ +#if 0 + printf("ScopeDsymbol::multiplyDefined()\n"); + printf("s1 = %p, '%s' kind = '%s', parent = %s\n", s1, s1->toChars(), s1->kind(), s1->parent ? s1->parent->toChars() : ""); + printf("s2 = %p, '%s' kind = '%s', parent = %s\n", s2, s2->toChars(), s2->kind(), s2->parent ? s2->parent->toChars() : ""); +#endif + if (loc.filename) + { ::error(loc, "%s at %s conflicts with %s at %s", + s1->toPrettyChars(), + s1->locToChars(), + s2->toPrettyChars(), + s2->locToChars()); + } + else + { + s1->error(loc, "conflicts with %s %s at %s", + s2->kind(), + s2->toPrettyChars(), + s2->locToChars()); + } +} + +Dsymbol *ScopeDsymbol::nameCollision(Dsymbol *s) +{ + Dsymbol *sprev; + + // Look to see if we are defining a forward referenced symbol + + sprev = symtab->lookup(s->ident); + assert(sprev); + if (s->equals(sprev)) // if the same symbol + { + if (s->isforwardRef()) // if second declaration is a forward reference + return sprev; + if (sprev->isforwardRef()) + { + sprev->defineRef(s); // copy data from s into sprev + return sprev; + } + } + multiplyDefined(0, s, sprev); + return sprev; +} + +const char *ScopeDsymbol::kind() +{ + return "ScopeDsymbol"; +} + +Dsymbol *ScopeDsymbol::symtabInsert(Dsymbol *s) +{ + return symtab->insert(s); +} + +/**************************************** + * Return true if any of the members are static ctors or static dtors, or if + * any members have members that are. + */ + +bool ScopeDsymbol::hasStaticCtorOrDtor() +{ + if (members) + { + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *member = (*members)[i]; + + if (member->hasStaticCtorOrDtor()) + return TRUE; + } + } + return FALSE; +} + +/*************************************** + * Determine number of Dsymbols, folding in AttribDeclaration members. + */ + +#if DMDV2 +static int dimDg(void *ctx, size_t n, Dsymbol *) +{ + ++*(size_t *)ctx; + return 0; +} + +size_t ScopeDsymbol::dim(Dsymbols *members) +{ + size_t n = 0; + foreach(NULL, members, &dimDg, &n); + return n; +} +#endif + +/*************************************** + * Get nth Dsymbol, folding in AttribDeclaration members. + * Returns: + * Dsymbol* nth Dsymbol + * NULL not found, *pn gets incremented by the number + * of Dsymbols + */ + +#if DMDV2 +struct GetNthSymbolCtx +{ + size_t nth; + Dsymbol *sym; +}; + +static int getNthSymbolDg(void *ctx, size_t n, Dsymbol *sym) +{ + GetNthSymbolCtx *p = (GetNthSymbolCtx *)ctx; + if (n == p->nth) + { p->sym = sym; + return 1; + } + return 0; +} + +Dsymbol *ScopeDsymbol::getNth(Dsymbols *members, size_t nth, size_t *pn) +{ + GetNthSymbolCtx ctx = { nth, NULL }; + int res = foreach(NULL, members, &getNthSymbolDg, &ctx); + return res ? ctx.sym : NULL; +} +#endif + +/*************************************** + * Expands attribute declarations in members in depth first + * order. Calls dg(void *ctx, size_t symidx, Dsymbol *sym) for each + * member. + * If dg returns !=0, stops and returns that value else returns 0. + * Use this function to avoid the O(N + N^2/2) complexity of + * calculating dim and calling N times getNth. + */ + +#if DMDV2 +int ScopeDsymbol::foreach(Scope *sc, Dsymbols *members, ScopeDsymbol::ForeachDg dg, void *ctx, size_t *pn) +{ + assert(dg); + if (!members) + return 0; + + size_t n = pn ? *pn : 0; // take over index + int result = 0; + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *s = (*members)[i]; + + if (AttribDeclaration *a = s->isAttribDeclaration()) + result = foreach(sc, a->include(sc, NULL), dg, ctx, &n); + else if (TemplateMixin *tm = s->isTemplateMixin()) + result = foreach(sc, tm->members, dg, ctx, &n); + else if (s->isTemplateInstance()) + ; + else + result = dg(ctx, n++, s); + + if (result) + break; + } + + if (pn) + *pn = n; // update index + return result; +} +#endif + +/******************************************* + * Look for member of the form: + * const(MemberInfo)[] getMembers(string); + * Returns NULL if not found + */ + +#if DMDV2 +FuncDeclaration *ScopeDsymbol::findGetMembers() +{ + Dsymbol *s = search_function(this, Id::getmembers); + FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL; + +#if 0 // Finish + static TypeFunction *tfgetmembers; + + if (!tfgetmembers) + { + Scope sc; + Parameters *arguments = new Parameters; + Parameters *arg = new Parameter(STCin, Type::tchar->constOf()->arrayOf(), NULL, NULL); + arguments->push(arg); + + Type *tret = NULL; + tfgetmembers = new TypeFunction(arguments, tret, 0, LINKd); + tfgetmembers = (TypeFunction *)tfgetmembers->semantic(0, &sc); + } + if (fdx) + fdx = fdx->overloadExactMatch(tfgetmembers); +#endif + if (fdx && fdx->isVirtual()) + fdx = NULL; + + return fdx; +} +#endif + + +/****************************** WithScopeSymbol ******************************/ + +WithScopeSymbol::WithScopeSymbol(WithStatement *withstate) + : ScopeDsymbol() +{ + this->withstate = withstate; +} + +Dsymbol *WithScopeSymbol::search(Loc loc, Identifier *ident, int flags) +{ + // Acts as proxy to the with class declaration + return withstate->exp->type->toDsymbol(NULL)->search(loc, ident, 0); +} + +/****************************** ArrayScopeSymbol ******************************/ + +ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, Expression *e) + : ScopeDsymbol() +{ + assert(e->op == TOKindex || e->op == TOKslice || e->op == TOKarray); + exp = e; + type = NULL; + td = NULL; + this->sc = sc; +} + +ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, TypeTuple *t) + : ScopeDsymbol() +{ + exp = NULL; + type = t; + td = NULL; + this->sc = sc; +} + +ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, TupleDeclaration *s) + : ScopeDsymbol() +{ + exp = NULL; + type = NULL; + td = s; + this->sc = sc; +} + +Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags) +{ + //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident->toChars(), flags); + if (ident == Id::length || ident == Id::dollar) + { VarDeclaration **pvar; + Expression *ce; + + if (ident == Id::length && !global.params.useDeprecated) + error("using 'length' inside [ ] is deprecated, use '$' instead"); + + L1: + + if (td) + { /* $ gives the number of elements in the tuple + */ + VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); + Expression *e = new IntegerExp(0, td->objects->dim, Type::tsize_t); + v->init = new ExpInitializer(0, e); + v->storage_class |= STCstatic | STCconst; + v->semantic(sc); + return v; + } + + if (type) + { /* $ gives the number of type entries in the type tuple + */ + VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); + Expression *e = new IntegerExp(0, type->arguments->dim, Type::tsize_t); + v->init = new ExpInitializer(0, e); + v->storage_class |= STCstatic | STCconst; + v->semantic(sc); + return v; + } + + if (exp->op == TOKindex) + { /* array[index] where index is some function of $ + */ + IndexExp *ie = (IndexExp *)exp; + + pvar = &ie->lengthVar; + ce = ie->e1; + } + else if (exp->op == TOKslice) + { /* array[lwr .. upr] where lwr or upr is some function of $ + */ + SliceExp *se = (SliceExp *)exp; + + pvar = &se->lengthVar; + ce = se->e1; + } + else if (exp->op == TOKarray) + { /* array[e0, e1, e2, e3] where e0, e1, e2 are some function of $ + * $ is a opDollar!(dim)() where dim is the dimension(0,1,2,...) + */ + ArrayExp *ae = (ArrayExp *)exp; + AggregateDeclaration *ad = NULL; + + Type *t = ae->e1->type->toBasetype(); + if (t->ty == Tclass) + { + ad = ((TypeClass *)t)->sym; + } + else if (t->ty == Tstruct) + { + ad = ((TypeStruct *)t)->sym; + } + assert(ad); + + Dsymbol *dsym = search_function(ad, Id::opDollar); + if (!dsym) // no dollar exists -- search in higher scope + return NULL; + VarDeclaration *v = ae->lengthVar; + if (!v) + { // $ is lazily initialized. Create it now. + TemplateDeclaration *td = dsym->isTemplateDeclaration(); + if (td) + { // Instantiate opDollar!(dim) with the index as a template argument + Objects *tdargs = new Objects(); + tdargs->setDim(1); + + Expression *x = new IntegerExp(0, ae->currentDimension, Type::tsize_t); + x = x->semantic(sc); + tdargs->data[0] = x; + + //TemplateInstance *ti = new TemplateInstance(loc, td, tdargs); + //ti->semantic(sc); + + DotTemplateInstanceExp *dte = new DotTemplateInstanceExp(loc, ae->e1, td->ident, tdargs); + + v = new VarDeclaration(loc, NULL, Id::dollar, new ExpInitializer(0, dte)); + } + else + { /* opDollar exists, but it's a function, not a template. + * This is acceptable ONLY for single-dimension indexing. + * Note that it's impossible to have both template & function opDollar, + * because both take no arguments. + */ + if (ae->arguments->dim != 1) { + ae->error("%s only defines opDollar for one dimension", ad->toChars()); + return NULL; + } + FuncDeclaration *fd = dsym->isFuncDeclaration(); + assert(fd); + Expression * x = new DotVarExp(loc, ae->e1, fd); + + v = new VarDeclaration(loc, NULL, Id::dollar, new ExpInitializer(0, x)); + } + v->semantic(sc); + ae->lengthVar = v; + } + return v; + } + else + /* Didn't find $, look in enclosing scope(s). + */ + return NULL; + + /* If we are indexing into an array that is really a type + * tuple, rewrite this as an index into a type tuple and + * try again. + */ + if (ce->op == TOKtype) + { + Type *t = ((TypeExp *)ce)->type; + if (t->ty == Ttuple) + { type = (TypeTuple *)t; + goto L1; + } + } + + /* *pvar is lazily initialized, so if we refer to $ + * multiple times, it gets set only once. + */ + if (!*pvar) // if not already initialized + { /* Create variable v and set it to the value of $ + */ + VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); + if (ce->op == TOKtuple) + { /* It is for an expression tuple, so the + * length will be a const. + */ + Expression *e = new IntegerExp(0, ((TupleExp *)ce)->exps->dim, Type::tsize_t); + v->init = new ExpInitializer(0, e); + v->storage_class |= STCstatic | STCconst; + } + else + { /* For arrays, $ will either be a compile-time constant + * (in which case its value in set during constant-folding), + * or a variable (in which case an expression is created in + * toir.c). + */ + VoidInitializer *e = new VoidInitializer(0); + e->type = Type::tsize_t; + v->init = e; + } + *pvar = v; + } + (*pvar)->semantic(sc); + return (*pvar); + } + return NULL; +} + + +/****************************** DsymbolTable ******************************/ + +DsymbolTable::DsymbolTable() +{ +#if STRINGTABLE + tab = new StringTable; + tab->init(); +#else + tab = NULL; +#endif +} + +DsymbolTable::~DsymbolTable() +{ +#if STRINGTABLE + delete tab; +#endif +} + +Dsymbol *DsymbolTable::lookup(Identifier *ident) +{ +#if STRINGTABLE +#ifdef DEBUG + assert(ident); + assert(tab); +#endif + //printf("DsymbolTable::lookup(%s)\n", (char*)ident->string); + StringValue *sv = tab->lookup((char*)ident->string, ident->len); + return (Dsymbol *)(sv ? sv->ptrvalue : NULL); +#else + //printf("DsymbolTable::lookup(%s)\n", (char*)ident->string); + return (Dsymbol *)_aaGetRvalue(tab, ident); +#endif +} + +Dsymbol *DsymbolTable::insert(Dsymbol *s) +{ + //printf("DsymbolTable::insert(this = %p, '%s')\n", this, s->ident->toChars()); + Identifier *ident = s->ident; +#if STRINGTABLE +#ifdef DEBUG + assert(ident); + assert(tab); +#endif + StringValue *sv = tab->insert(ident->toChars(), ident->len); + if (!sv) + return NULL; // already in table + sv->ptrvalue = s; + return s; +#else + Dsymbol **ps = (Dsymbol **)_aaGet(&tab, ident); + if (*ps) + return NULL; // already in table + *ps = s; + return s; +#endif +} + +Dsymbol *DsymbolTable::insert(Identifier *ident, Dsymbol *s) +{ + //printf("DsymbolTable::insert()\n"); +#if STRINGTABLE + StringValue *sv = tab->insert(ident->toChars(), ident->len); + if (!sv) + return NULL; // already in table + sv->ptrvalue = s; + return s; +#else + Dsymbol **ps = (Dsymbol **)_aaGet(&tab, ident); + if (*ps) + return NULL; // already in table + *ps = s; + return s; +#endif +} + +Dsymbol *DsymbolTable::update(Dsymbol *s) +{ + Identifier *ident = s->ident; +#if STRINGTABLE + StringValue *sv = tab->update(ident->toChars(), ident->len); + sv->ptrvalue = s; + return s; +#else + Dsymbol **ps = (Dsymbol **)_aaGet(&tab, ident); + *ps = s; + return s; +#endif +} + + + + diff --git a/dmd2/dsymbol.h b/dmd2/dsymbol.h index b895d9a2..850b880a 100644 --- a/dmd2/dsymbol.h +++ b/dmd2/dsymbol.h @@ -1,396 +1,396 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_DSYMBOL_H -#define DMD_DSYMBOL_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "root.h" -#include "stringtable.h" - -#include "mars.h" -#include "arraytypes.h" - -#if IN_LLVM -#if defined(_MSC_VER) -#undef min -#undef max -#endif -#include "../ir/irdsymbol.h" -#endif - -struct Identifier; -struct Scope; -struct DsymbolTable; -struct Declaration; -struct ThisDeclaration; -struct TupleDeclaration; -struct TypedefDeclaration; -struct AliasDeclaration; -struct AggregateDeclaration; -struct EnumDeclaration; -struct ClassDeclaration; -struct InterfaceDeclaration; -struct StructDeclaration; -struct UnionDeclaration; -struct FuncDeclaration; -struct FuncAliasDeclaration; -struct FuncLiteralDeclaration; -struct CtorDeclaration; -struct PostBlitDeclaration; -struct DtorDeclaration; -struct StaticCtorDeclaration; -struct StaticDtorDeclaration; -struct SharedStaticCtorDeclaration; -struct SharedStaticDtorDeclaration; -struct InvariantDeclaration; -struct UnitTestDeclaration; -struct NewDeclaration; -struct VarDeclaration; -struct AttribDeclaration; -#if IN_DMD -struct Symbol; -#endif -struct Package; -struct Module; -struct Import; -struct Type; -struct TypeTuple; -struct WithStatement; -struct LabelDsymbol; -struct ScopeDsymbol; -struct TemplateDeclaration; -struct TemplateInstance; -struct TemplateMixin; -struct EnumMember; -struct ScopeDsymbol; -struct WithScopeSymbol; -struct ArrayScopeSymbol; -struct StaticStructInitDeclaration; -struct Expression; -struct DeleteDeclaration; -struct HdrGenState; -struct OverloadSet; -struct AA; -#if TARGET_NET -struct PragmaScope; -#endif -#if IN_LLVM -struct TypeInfoDeclaration; -struct ClassInfoDeclaration; -#endif - -#if IN_GCC -union tree_node; -typedef union tree_node TYPE; -#else -struct TYPE; -#endif - -#if IN_LLVM -class Ir; -class IrSymbol; -namespace llvm -{ - class Value; -} -#endif -#if IN_DMD -// Back end -struct Classsym; -#endif - -enum PROT -{ - PROTundefined, - PROTnone, // no access - PROTprivate, - PROTpackage, - PROTprotected, - PROTpublic, - PROTexport, -}; - -/* State of symbol in winding its way through the passes of the compiler - */ -enum PASS -{ - PASSinit, // initial state - PASSsemantic, // semantic() started - PASSsemanticdone, // semantic() done - PASSsemantic2, // semantic2() run - PASSsemantic3, // semantic3() started - PASSsemantic3done, // semantic3() done - PASSobj, // toObjFile() run -}; - -typedef int (*Dsymbol_apply_ft_t)(Dsymbol *, void *); - -struct Dsymbol : Object -{ - Identifier *ident; - Identifier *c_ident; - Dsymbol *parent; -#if IN_DMD - Symbol *csym; // symbol for code generator - Symbol *isym; // import version of csym -#endif - unsigned char *comment; // documentation comment for this Dsymbol - Loc loc; // where defined - Scope *scope; // !=NULL means context to use for semantic() - bool errors; // this symbol failed to pass semantic() - - Dsymbol(); - Dsymbol(Identifier *); - char *toChars(); - char *locToChars(); - int equals(Object *o); - int isAnonymous(); - void error(Loc loc, const char *format, ...) IS_PRINTF(3); - void error(const char *format, ...) IS_PRINTF(2); - void verror(Loc loc, const char *format, va_list ap); - void checkDeprecated(Loc loc, Scope *sc); - Module *getModule(); // module where declared - Module *getAccessModule(); - Dsymbol *pastMixin(); - Dsymbol *toParent(); - Dsymbol *toParent2(); - TemplateInstance *inTemplateInstance(); - TemplateInstance *isSpeculative(); - - int dyncast() { return DYNCAST_DSYMBOL; } // kludge for template.isSymbol() - - static Dsymbols *arraySyntaxCopy(Dsymbols *a); - - virtual const char *toPrettyChars(); - virtual const char *kind(); - virtual Dsymbol *toAlias(); // resolve real symbol - virtual int apply(Dsymbol_apply_ft_t fp, void *param); - virtual int addMember(Scope *sc, ScopeDsymbol *s, int memnum); - virtual void setScope(Scope *sc); - virtual void importAll(Scope *sc); - virtual void semantic0(Scope *sc); - virtual void semantic(Scope *sc); - virtual void semantic2(Scope *sc); - 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); - char *toHChars(); - virtual void toHBuffer(OutBuffer *buf, HdrGenState *hgs); - virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - virtual void toDocBuffer(OutBuffer *buf); - virtual void toJsonBuffer(OutBuffer *buf); - virtual unsigned size(Loc loc); - virtual int isforwardRef(); - virtual void defineRef(Dsymbol *s); - virtual AggregateDeclaration *isThis(); // is a 'this' required to access the member - AggregateDeclaration *isAggregateMember(); // are we a member of an aggregate? - ClassDeclaration *isClassMember(); // are we a member of a class? - virtual int isExport(); // is Dsymbol exported? - virtual int isImportedSymbol(); // is Dsymbol imported? - virtual int isDeprecated(); // is Dsymbol deprecated? -#if DMDV2 - virtual int isOverloadable(); - virtual int hasOverloads(); -#endif - virtual LabelDsymbol *isLabel(); // is this a LabelDsymbol? - virtual AggregateDeclaration *isMember(); // is this symbol a member of an AggregateDeclaration? - virtual Type *getType(); // is this a type? - virtual char *mangle(); - virtual int needThis(); // need a 'this' pointer? - virtual enum PROT prot(); - virtual Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees - virtual int oneMember(Dsymbol **ps, Identifier *ident); - static int oneMembers(Dsymbols *members, Dsymbol **ps, Identifier *ident = NULL); - virtual void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); - virtual int hasPointers(); - virtual bool hasStaticCtorOrDtor(); - virtual void addLocalClass(ClassDeclarations *) { } - virtual void checkCtorConstInit() { } - - virtual void addComment(unsigned char *comment); - virtual void emitComment(Scope *sc); - void emitDitto(Scope *sc); - -#if IN_DMD - // Backend - - virtual Symbol *toSymbol(); // to backend symbol - virtual void toObjFile(int multiobj); // compile to .obj file - virtual int cvMember(unsigned char *p); // emit cv debug info for member - - Symbol *toImport(); // to backend import symbol - static Symbol *toImport(Symbol *s); // to backend import symbol - - Symbol *toSymbolX(const char *prefix, int sclass, TYPE *t, const char *suffix); // helper -#endif - - // Eliminate need for dynamic_cast - virtual Package *isPackage() { return NULL; } - virtual Module *isModule() { return NULL; } - virtual EnumMember *isEnumMember() { return NULL; } - virtual TemplateDeclaration *isTemplateDeclaration() { return NULL; } - virtual TemplateInstance *isTemplateInstance() { return NULL; } - virtual TemplateMixin *isTemplateMixin() { return NULL; } - virtual Declaration *isDeclaration() { return NULL; } - virtual ThisDeclaration *isThisDeclaration() { return NULL; } - virtual TupleDeclaration *isTupleDeclaration() { return NULL; } - virtual TypedefDeclaration *isTypedefDeclaration() { return NULL; } - virtual AliasDeclaration *isAliasDeclaration() { return NULL; } - virtual AggregateDeclaration *isAggregateDeclaration() { return NULL; } - virtual FuncDeclaration *isFuncDeclaration() { return NULL; } - virtual FuncAliasDeclaration *isFuncAliasDeclaration() { return NULL; } - virtual FuncLiteralDeclaration *isFuncLiteralDeclaration() { return NULL; } - virtual CtorDeclaration *isCtorDeclaration() { return NULL; } - virtual PostBlitDeclaration *isPostBlitDeclaration() { return NULL; } - virtual DtorDeclaration *isDtorDeclaration() { return NULL; } - virtual StaticCtorDeclaration *isStaticCtorDeclaration() { return NULL; } - virtual StaticDtorDeclaration *isStaticDtorDeclaration() { return NULL; } - virtual SharedStaticCtorDeclaration *isSharedStaticCtorDeclaration() { return NULL; } - virtual SharedStaticDtorDeclaration *isSharedStaticDtorDeclaration() { return NULL; } - virtual InvariantDeclaration *isInvariantDeclaration() { return NULL; } - virtual UnitTestDeclaration *isUnitTestDeclaration() { return NULL; } - virtual NewDeclaration *isNewDeclaration() { return NULL; } - virtual VarDeclaration *isVarDeclaration() { return NULL; } - virtual ClassDeclaration *isClassDeclaration() { return NULL; } - virtual StructDeclaration *isStructDeclaration() { return NULL; } - virtual UnionDeclaration *isUnionDeclaration() { return NULL; } - virtual InterfaceDeclaration *isInterfaceDeclaration() { return NULL; } - virtual ScopeDsymbol *isScopeDsymbol() { return NULL; } - virtual WithScopeSymbol *isWithScopeSymbol() { return NULL; } - virtual ArrayScopeSymbol *isArrayScopeSymbol() { return NULL; } - virtual Import *isImport() { return NULL; } - virtual EnumDeclaration *isEnumDeclaration() { return NULL; } - virtual DeleteDeclaration *isDeleteDeclaration() { return NULL; } - virtual StaticStructInitDeclaration *isStaticStructInitDeclaration() { return NULL; } - virtual AttribDeclaration *isAttribDeclaration() { return NULL; } - virtual OverloadSet *isOverloadSet() { return NULL; } - virtual TypeInfoDeclaration* isTypeInfoDeclaration() { return NULL; } - virtual ClassInfoDeclaration* isClassInfoDeclaration() { return NULL; } -#if TARGET_NET - virtual PragmaScope* isPragmaScope() { return NULL; } -#endif -#if IN_LLVM - /// Codegen traversal - virtual void codegen(Ir* ir); - - // llvm stuff - int llvmInternal; - - IrDsymbol ir; - IrSymbol* irsym; -#endif -}; - -// Dsymbol that generates a scope - -struct ScopeDsymbol : Dsymbol -{ - Dsymbols *members; // all Dsymbol's in this scope - DsymbolTable *symtab; // members[] sorted into table - - Dsymbols *imports; // imported Dsymbol's - unsigned char *prots; // array of PROT, one for each import - - ScopeDsymbol(); - ScopeDsymbol(Identifier *id); - Dsymbol *syntaxCopy(Dsymbol *s); - Dsymbol *search(Loc loc, Identifier *ident, int flags); - void importScope(Dsymbol *s, enum PROT protection); - int isforwardRef(); - void defineRef(Dsymbol *s); - static void multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2); - Dsymbol *nameCollision(Dsymbol *s); - const char *kind(); - FuncDeclaration *findGetMembers(); - virtual Dsymbol *symtabInsert(Dsymbol *s); - bool hasStaticCtorOrDtor(); - - void emitMemberComments(Scope *sc); - - static size_t dim(Dsymbols *members); - static Dsymbol *getNth(Dsymbols *members, size_t nth, size_t *pn = NULL); - - typedef int (*ForeachDg)(void *ctx, size_t idx, Dsymbol *s); - static int foreach(Scope *sc, Dsymbols *members, ForeachDg dg, void *ctx, size_t *pn=NULL); - - ScopeDsymbol *isScopeDsymbol() { return this; } -}; - -// With statement scope - -struct WithScopeSymbol : ScopeDsymbol -{ - WithStatement *withstate; - - WithScopeSymbol(WithStatement *withstate); - Dsymbol *search(Loc loc, Identifier *ident, int flags); - - WithScopeSymbol *isWithScopeSymbol() { return this; } -}; - -// Array Index/Slice scope - -struct ArrayScopeSymbol : ScopeDsymbol -{ - Expression *exp; // IndexExp or SliceExp - TypeTuple *type; // for tuple[length] - TupleDeclaration *td; // for tuples of objects - Scope *sc; - - ArrayScopeSymbol(Scope *sc, Expression *e); - ArrayScopeSymbol(Scope *sc, TypeTuple *t); - ArrayScopeSymbol(Scope *sc, TupleDeclaration *td); - Dsymbol *search(Loc loc, Identifier *ident, int flags); - - ArrayScopeSymbol *isArrayScopeSymbol() { return this; } -}; - -// Overload Sets - -#if DMDV2 -struct OverloadSet : Dsymbol -{ - Dsymbols a; // array of Dsymbols - - OverloadSet(); - void push(Dsymbol *s); - OverloadSet *isOverloadSet() { return this; } - const char *kind(); -}; -#endif - -// Table of Dsymbol's - -struct DsymbolTable : Object -{ - AA *tab; - - DsymbolTable(); - ~DsymbolTable(); - - // Look up Identifier. Return Dsymbol if found, NULL if not. - Dsymbol *lookup(Identifier *ident); - - // Insert Dsymbol in table. Return NULL if already there. - Dsymbol *insert(Dsymbol *s); - - // Look for Dsymbol in table. If there, return it. If not, insert s and return that. - Dsymbol *update(Dsymbol *s); - Dsymbol *insert(Identifier *ident, Dsymbol *s); // when ident and s are not the same -}; - -#endif /* DMD_DSYMBOL_H */ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2012 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#ifndef DMD_DSYMBOL_H +#define DMD_DSYMBOL_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +#include "root.h" +#include "stringtable.h" + +#include "mars.h" +#include "arraytypes.h" + +#if IN_LLVM +#if defined(_MSC_VER) +#undef min +#undef max +#endif +#include "../ir/irdsymbol.h" +#endif + +struct Identifier; +struct Scope; +struct DsymbolTable; +struct Declaration; +struct ThisDeclaration; +struct TupleDeclaration; +struct TypedefDeclaration; +struct AliasDeclaration; +struct AggregateDeclaration; +struct EnumDeclaration; +struct ClassDeclaration; +struct InterfaceDeclaration; +struct StructDeclaration; +struct UnionDeclaration; +struct FuncDeclaration; +struct FuncAliasDeclaration; +struct FuncLiteralDeclaration; +struct CtorDeclaration; +struct PostBlitDeclaration; +struct DtorDeclaration; +struct StaticCtorDeclaration; +struct StaticDtorDeclaration; +struct SharedStaticCtorDeclaration; +struct SharedStaticDtorDeclaration; +struct InvariantDeclaration; +struct UnitTestDeclaration; +struct NewDeclaration; +struct VarDeclaration; +struct AttribDeclaration; +#if IN_DMD +struct Symbol; +#endif +struct Package; +struct Module; +struct Import; +struct Type; +struct TypeTuple; +struct WithStatement; +struct LabelDsymbol; +struct ScopeDsymbol; +struct TemplateDeclaration; +struct TemplateInstance; +struct TemplateMixin; +struct EnumMember; +struct ScopeDsymbol; +struct WithScopeSymbol; +struct ArrayScopeSymbol; +struct StaticStructInitDeclaration; +struct Expression; +struct DeleteDeclaration; +struct HdrGenState; +struct OverloadSet; +struct AA; +#if TARGET_NET +struct PragmaScope; +#endif +#if IN_LLVM +struct TypeInfoDeclaration; +struct ClassInfoDeclaration; +#endif + +#if IN_GCC +union tree_node; +typedef union tree_node TYPE; +#else +struct TYPE; +#endif + +#if IN_LLVM +class Ir; +class IrSymbol; +namespace llvm +{ + class Value; +} +#endif +#if IN_DMD +// Back end +struct Classsym; +#endif + +enum PROT +{ + PROTundefined, + PROTnone, // no access + PROTprivate, + PROTpackage, + PROTprotected, + PROTpublic, + PROTexport, +}; + +/* State of symbol in winding its way through the passes of the compiler + */ +enum PASS +{ + PASSinit, // initial state + PASSsemantic, // semantic() started + PASSsemanticdone, // semantic() done + PASSsemantic2, // semantic2() run + PASSsemantic3, // semantic3() started + PASSsemantic3done, // semantic3() done + PASSobj, // toObjFile() run +}; + +typedef int (*Dsymbol_apply_ft_t)(Dsymbol *, void *); + +struct Dsymbol : Object +{ + Identifier *ident; + Identifier *c_ident; + Dsymbol *parent; +#if IN_DMD + Symbol *csym; // symbol for code generator + Symbol *isym; // import version of csym +#endif + unsigned char *comment; // documentation comment for this Dsymbol + Loc loc; // where defined + Scope *scope; // !=NULL means context to use for semantic() + bool errors; // this symbol failed to pass semantic() + + Dsymbol(); + Dsymbol(Identifier *); + char *toChars(); + char *locToChars(); + int equals(Object *o); + int isAnonymous(); + void error(Loc loc, const char *format, ...) IS_PRINTF(3); + void error(const char *format, ...) IS_PRINTF(2); + void verror(Loc loc, const char *format, va_list ap); + void checkDeprecated(Loc loc, Scope *sc); + Module *getModule(); // module where declared + Module *getAccessModule(); + Dsymbol *pastMixin(); + Dsymbol *toParent(); + Dsymbol *toParent2(); + TemplateInstance *inTemplateInstance(); + TemplateInstance *isSpeculative(); + + int dyncast() { return DYNCAST_DSYMBOL; } // kludge for template.isSymbol() + + static Dsymbols *arraySyntaxCopy(Dsymbols *a); + + virtual const char *toPrettyChars(); + virtual const char *kind(); + virtual Dsymbol *toAlias(); // resolve real symbol + virtual int apply(Dsymbol_apply_ft_t fp, void *param); + virtual int addMember(Scope *sc, ScopeDsymbol *s, int memnum); + virtual void setScope(Scope *sc); + virtual void importAll(Scope *sc); + virtual void semantic0(Scope *sc); + virtual void semantic(Scope *sc); + virtual void semantic2(Scope *sc); + 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); + char *toHChars(); + virtual void toHBuffer(OutBuffer *buf, HdrGenState *hgs); + virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + virtual void toDocBuffer(OutBuffer *buf); + virtual void toJsonBuffer(OutBuffer *buf); + virtual unsigned size(Loc loc); + virtual int isforwardRef(); + virtual void defineRef(Dsymbol *s); + virtual AggregateDeclaration *isThis(); // is a 'this' required to access the member + AggregateDeclaration *isAggregateMember(); // are we a member of an aggregate? + ClassDeclaration *isClassMember(); // are we a member of a class? + virtual int isExport(); // is Dsymbol exported? + virtual int isImportedSymbol(); // is Dsymbol imported? + virtual int isDeprecated(); // is Dsymbol deprecated? +#if DMDV2 + virtual int isOverloadable(); + virtual int hasOverloads(); +#endif + virtual LabelDsymbol *isLabel(); // is this a LabelDsymbol? + virtual AggregateDeclaration *isMember(); // is this symbol a member of an AggregateDeclaration? + virtual Type *getType(); // is this a type? + virtual char *mangle(); + virtual int needThis(); // need a 'this' pointer? + virtual enum PROT prot(); + virtual Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees + virtual int oneMember(Dsymbol **ps, Identifier *ident); + static int oneMembers(Dsymbols *members, Dsymbol **ps, Identifier *ident = NULL); + virtual void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); + virtual int hasPointers(); + virtual bool hasStaticCtorOrDtor(); + virtual void addLocalClass(ClassDeclarations *) { } + virtual void checkCtorConstInit() { } + + virtual void addComment(unsigned char *comment); + virtual void emitComment(Scope *sc); + void emitDitto(Scope *sc); + +#if IN_DMD + // Backend + + virtual Symbol *toSymbol(); // to backend symbol + virtual void toObjFile(int multiobj); // compile to .obj file + virtual int cvMember(unsigned char *p); // emit cv debug info for member + + Symbol *toImport(); // to backend import symbol + static Symbol *toImport(Symbol *s); // to backend import symbol + + Symbol *toSymbolX(const char *prefix, int sclass, TYPE *t, const char *suffix); // helper +#endif + + // Eliminate need for dynamic_cast + virtual Package *isPackage() { return NULL; } + virtual Module *isModule() { return NULL; } + virtual EnumMember *isEnumMember() { return NULL; } + virtual TemplateDeclaration *isTemplateDeclaration() { return NULL; } + virtual TemplateInstance *isTemplateInstance() { return NULL; } + virtual TemplateMixin *isTemplateMixin() { return NULL; } + virtual Declaration *isDeclaration() { return NULL; } + virtual ThisDeclaration *isThisDeclaration() { return NULL; } + virtual TupleDeclaration *isTupleDeclaration() { return NULL; } + virtual TypedefDeclaration *isTypedefDeclaration() { return NULL; } + virtual AliasDeclaration *isAliasDeclaration() { return NULL; } + virtual AggregateDeclaration *isAggregateDeclaration() { return NULL; } + virtual FuncDeclaration *isFuncDeclaration() { return NULL; } + virtual FuncAliasDeclaration *isFuncAliasDeclaration() { return NULL; } + virtual FuncLiteralDeclaration *isFuncLiteralDeclaration() { return NULL; } + virtual CtorDeclaration *isCtorDeclaration() { return NULL; } + virtual PostBlitDeclaration *isPostBlitDeclaration() { return NULL; } + virtual DtorDeclaration *isDtorDeclaration() { return NULL; } + virtual StaticCtorDeclaration *isStaticCtorDeclaration() { return NULL; } + virtual StaticDtorDeclaration *isStaticDtorDeclaration() { return NULL; } + virtual SharedStaticCtorDeclaration *isSharedStaticCtorDeclaration() { return NULL; } + virtual SharedStaticDtorDeclaration *isSharedStaticDtorDeclaration() { return NULL; } + virtual InvariantDeclaration *isInvariantDeclaration() { return NULL; } + virtual UnitTestDeclaration *isUnitTestDeclaration() { return NULL; } + virtual NewDeclaration *isNewDeclaration() { return NULL; } + virtual VarDeclaration *isVarDeclaration() { return NULL; } + virtual ClassDeclaration *isClassDeclaration() { return NULL; } + virtual StructDeclaration *isStructDeclaration() { return NULL; } + virtual UnionDeclaration *isUnionDeclaration() { return NULL; } + virtual InterfaceDeclaration *isInterfaceDeclaration() { return NULL; } + virtual ScopeDsymbol *isScopeDsymbol() { return NULL; } + virtual WithScopeSymbol *isWithScopeSymbol() { return NULL; } + virtual ArrayScopeSymbol *isArrayScopeSymbol() { return NULL; } + virtual Import *isImport() { return NULL; } + virtual EnumDeclaration *isEnumDeclaration() { return NULL; } + virtual DeleteDeclaration *isDeleteDeclaration() { return NULL; } + virtual StaticStructInitDeclaration *isStaticStructInitDeclaration() { return NULL; } + virtual AttribDeclaration *isAttribDeclaration() { return NULL; } + virtual OverloadSet *isOverloadSet() { return NULL; } + virtual TypeInfoDeclaration* isTypeInfoDeclaration() { return NULL; } + virtual ClassInfoDeclaration* isClassInfoDeclaration() { return NULL; } +#if TARGET_NET + virtual PragmaScope* isPragmaScope() { return NULL; } +#endif +#if IN_LLVM + /// Codegen traversal + virtual void codegen(Ir* ir); + + // llvm stuff + int llvmInternal; + + IrDsymbol ir; + IrSymbol* irsym; +#endif +}; + +// Dsymbol that generates a scope + +struct ScopeDsymbol : Dsymbol +{ + Dsymbols *members; // all Dsymbol's in this scope + DsymbolTable *symtab; // members[] sorted into table + + Dsymbols *imports; // imported Dsymbol's + unsigned char *prots; // array of PROT, one for each import + + ScopeDsymbol(); + ScopeDsymbol(Identifier *id); + Dsymbol *syntaxCopy(Dsymbol *s); + Dsymbol *search(Loc loc, Identifier *ident, int flags); + void importScope(Dsymbol *s, enum PROT protection); + int isforwardRef(); + void defineRef(Dsymbol *s); + static void multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2); + Dsymbol *nameCollision(Dsymbol *s); + const char *kind(); + FuncDeclaration *findGetMembers(); + virtual Dsymbol *symtabInsert(Dsymbol *s); + bool hasStaticCtorOrDtor(); + + void emitMemberComments(Scope *sc); + + static size_t dim(Dsymbols *members); + static Dsymbol *getNth(Dsymbols *members, size_t nth, size_t *pn = NULL); + + typedef int (*ForeachDg)(void *ctx, size_t idx, Dsymbol *s); + static int foreach(Scope *sc, Dsymbols *members, ForeachDg dg, void *ctx, size_t *pn=NULL); + + ScopeDsymbol *isScopeDsymbol() { return this; } +}; + +// With statement scope + +struct WithScopeSymbol : ScopeDsymbol +{ + WithStatement *withstate; + + WithScopeSymbol(WithStatement *withstate); + Dsymbol *search(Loc loc, Identifier *ident, int flags); + + WithScopeSymbol *isWithScopeSymbol() { return this; } +}; + +// Array Index/Slice scope + +struct ArrayScopeSymbol : ScopeDsymbol +{ + Expression *exp; // IndexExp or SliceExp + TypeTuple *type; // for tuple[length] + TupleDeclaration *td; // for tuples of objects + Scope *sc; + + ArrayScopeSymbol(Scope *sc, Expression *e); + ArrayScopeSymbol(Scope *sc, TypeTuple *t); + ArrayScopeSymbol(Scope *sc, TupleDeclaration *td); + Dsymbol *search(Loc loc, Identifier *ident, int flags); + + ArrayScopeSymbol *isArrayScopeSymbol() { return this; } +}; + +// Overload Sets + +#if DMDV2 +struct OverloadSet : Dsymbol +{ + Dsymbols a; // array of Dsymbols + + OverloadSet(); + void push(Dsymbol *s); + OverloadSet *isOverloadSet() { return this; } + const char *kind(); +}; +#endif + +// Table of Dsymbol's + +struct DsymbolTable : Object +{ + AA *tab; + + DsymbolTable(); + ~DsymbolTable(); + + // Look up Identifier. Return Dsymbol if found, NULL if not. + Dsymbol *lookup(Identifier *ident); + + // Insert Dsymbol in table. Return NULL if already there. + Dsymbol *insert(Dsymbol *s); + + // Look for Dsymbol in table. If there, return it. If not, insert s and return that. + Dsymbol *update(Dsymbol *s); + Dsymbol *insert(Identifier *ident, Dsymbol *s); // when ident and s are not the same +}; + +#endif /* DMD_DSYMBOL_H */ diff --git a/dmd2/gpl.txt b/dmd2/gpl.txt index cc468912..43cd72c3 100644 --- a/dmd2/gpl.txt +++ b/dmd2/gpl.txt @@ -1,248 +1,248 @@ - GNU GENERAL PUBLIC LICENSE - Version 1, February 1989 - - Copyright (C) 1989 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The license agreements of most software companies try to keep users -at the mercy of those companies. By contrast, our General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. The -General Public License applies to the Free Software Foundation's -software and to any other program whose authors commit to using it. -You can use it for your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Specifically, the General Public License is designed to make -sure that you have the freedom to give away or sell copies of free -software, that you receive source code or can get it if you want it, -that you can change the software or use pieces of it in new free -programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of a such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must tell them their rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any program or other work which -contains a notice placed by the copyright holder saying it may be -distributed under the terms of this General Public License. The -"Program", below, refers to any such program or work, and a "work based -on the Program" means either the Program or any work containing the -Program or a portion of it, either verbatim or with modifications. Each -licensee is addressed as "you". - - 1. You may copy and distribute verbatim copies of the Program's source -code as you receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice and -disclaimer of warranty; keep intact all the notices that refer to this -General Public License and to the absence of any warranty; and give any -other recipients of the Program a copy of this General Public License -along with the Program. You may charge a fee for the physical act of -transferring a copy. - - 2. You may modify your copy or copies of the Program or any portion of -it, and copy and distribute such modifications under the terms of Paragraph -1 above, provided that you also do the following: - - a) cause the modified files to carry prominent notices stating that - you changed the files and the date of any change; and - - b) cause the whole of any work that you distribute or publish, that - in whole or in part contains the Program or any part thereof, either - with or without modifications, to be licensed at no charge to all - third parties under the terms of this General Public License (except - that you may choose to grant warranty protection to some or all - third parties, at your option). - - c) If the modified program normally reads commands interactively when - run, you must cause it, when started running for such interactive use - in the simplest and most usual way, to print or display an - announcement including an appropriate copyright notice and a notice - that there is no warranty (or else, saying that you provide a - warranty) and that users may redistribute the program under these - conditions, and telling the user how to view a copy of this General - Public License. - - d) You may charge a fee for the physical act of transferring a - copy, and you may at your option offer warranty protection in - exchange for a fee. - -Mere aggregation of another independent work with the Program (or its -derivative) on a volume of a storage or distribution medium does not bring -the other work under the scope of these terms. - - 3. You may copy and distribute the Program (or a portion or derivative of -it, under Paragraph 2) in object code or executable form under the terms of -Paragraphs 1 and 2 above provided that you also do one of the following: - - a) accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of - Paragraphs 1 and 2 above; or, - - b) accompany it with a written offer, valid for at least three - years, to give any third party free (except for a nominal charge - for the cost of distribution) a complete machine-readable copy of the - corresponding source code, to be distributed under the terms of - Paragraphs 1 and 2 above; or, - - c) accompany it with the information you received as to where the - corresponding source code may be obtained. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form alone.) - -Source code for a work means the preferred form of the work for making -modifications to it. For an executable file, complete source code means -all the source code for all modules it contains; but, as a special -exception, it need not include source code for modules which are standard -libraries that accompany the operating system on which the executable -file runs, or for standard header files or definitions files that -accompany that operating system. - - 4. You may not copy, modify, sublicense, distribute or transfer the -Program except as expressly provided under this General Public License. -Any attempt otherwise to copy, modify, sublicense, distribute or transfer -the Program is void, and will automatically terminate your rights to use -the Program under this License. However, parties who have received -copies, or rights to use copies, from you under this General Public -License will not have their licenses terminated so long as such parties -remain in full compliance. - - 5. By copying, distributing or modifying the Program (or any work based -on the Program) you indicate your acceptance of this license to do so, -and all its terms and conditions. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the original -licensor to copy, distribute or modify the Program subject to these -terms and conditions. You may not impose any further restrictions on the -recipients' exercise of the rights granted herein. - - 7. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of the license which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -the license, you may choose any version ever published by the Free Software -Foundation. - - 8. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - Appendix: How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to humanity, the best way to achieve this is to make it -free software which everyone can redistribute and change under these -terms. - - To do so, attach the following notices to the program. It is safest to -attach them to the start of each source file to most effectively convey -the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) 19yy - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 1, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) 19xx name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the -appropriate parts of the General Public License. Of course, the -commands you use may be called something other than `show w' and `show -c'; they could even be mouse-clicks or menu items--whatever suits your -program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - program `Gnomovision' (a program to direct compilers to make passes - at assemblers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -That's all there is to it! + GNU GENERAL PUBLIC LICENSE + Version 1, February 1989 + + Copyright (C) 1989 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The license agreements of most software companies try to keep users +at the mercy of those companies. By contrast, our General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. The +General Public License applies to the Free Software Foundation's +software and to any other program whose authors commit to using it. +You can use it for your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Specifically, the General Public License is designed to make +sure that you have the freedom to give away or sell copies of free +software, that you receive source code or can get it if you want it, +that you can change the software or use pieces of it in new free +programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of a such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must tell them their rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any program or other work which +contains a notice placed by the copyright holder saying it may be +distributed under the terms of this General Public License. The +"Program", below, refers to any such program or work, and a "work based +on the Program" means either the Program or any work containing the +Program or a portion of it, either verbatim or with modifications. Each +licensee is addressed as "you". + + 1. You may copy and distribute verbatim copies of the Program's source +code as you receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice and +disclaimer of warranty; keep intact all the notices that refer to this +General Public License and to the absence of any warranty; and give any +other recipients of the Program a copy of this General Public License +along with the Program. You may charge a fee for the physical act of +transferring a copy. + + 2. You may modify your copy or copies of the Program or any portion of +it, and copy and distribute such modifications under the terms of Paragraph +1 above, provided that you also do the following: + + a) cause the modified files to carry prominent notices stating that + you changed the files and the date of any change; and + + b) cause the whole of any work that you distribute or publish, that + in whole or in part contains the Program or any part thereof, either + with or without modifications, to be licensed at no charge to all + third parties under the terms of this General Public License (except + that you may choose to grant warranty protection to some or all + third parties, at your option). + + c) If the modified program normally reads commands interactively when + run, you must cause it, when started running for such interactive use + in the simplest and most usual way, to print or display an + announcement including an appropriate copyright notice and a notice + that there is no warranty (or else, saying that you provide a + warranty) and that users may redistribute the program under these + conditions, and telling the user how to view a copy of this General + Public License. + + d) You may charge a fee for the physical act of transferring a + copy, and you may at your option offer warranty protection in + exchange for a fee. + +Mere aggregation of another independent work with the Program (or its +derivative) on a volume of a storage or distribution medium does not bring +the other work under the scope of these terms. + + 3. You may copy and distribute the Program (or a portion or derivative of +it, under Paragraph 2) in object code or executable form under the terms of +Paragraphs 1 and 2 above provided that you also do one of the following: + + a) accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of + Paragraphs 1 and 2 above; or, + + b) accompany it with a written offer, valid for at least three + years, to give any third party free (except for a nominal charge + for the cost of distribution) a complete machine-readable copy of the + corresponding source code, to be distributed under the terms of + Paragraphs 1 and 2 above; or, + + c) accompany it with the information you received as to where the + corresponding source code may be obtained. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form alone.) + +Source code for a work means the preferred form of the work for making +modifications to it. For an executable file, complete source code means +all the source code for all modules it contains; but, as a special +exception, it need not include source code for modules which are standard +libraries that accompany the operating system on which the executable +file runs, or for standard header files or definitions files that +accompany that operating system. + + 4. You may not copy, modify, sublicense, distribute or transfer the +Program except as expressly provided under this General Public License. +Any attempt otherwise to copy, modify, sublicense, distribute or transfer +the Program is void, and will automatically terminate your rights to use +the Program under this License. However, parties who have received +copies, or rights to use copies, from you under this General Public +License will not have their licenses terminated so long as such parties +remain in full compliance. + + 5. By copying, distributing or modifying the Program (or any work based +on the Program) you indicate your acceptance of this license to do so, +and all its terms and conditions. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the original +licensor to copy, distribute or modify the Program subject to these +terms and conditions. You may not impose any further restrictions on the +recipients' exercise of the rights granted herein. + + 7. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of the license which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +the license, you may choose any version ever published by the Free Software +Foundation. + + 8. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to humanity, the best way to achieve this is to make it +free software which everyone can redistribute and change under these +terms. + + To do so, attach the following notices to the program. It is safest to +attach them to the start of each source file to most effectively convey +the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19xx name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the +appropriate parts of the General Public License. Of course, the +commands you use may be called something other than `show w' and `show +c'; they could even be mouse-clicks or menu items--whatever suits your +program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + program `Gnomovision' (a program to direct compilers to make passes + at assemblers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/dmd2/mars.c b/dmd2/mars.c index 9ccf07d7..ea79ce2f 100644 --- a/dmd2/mars.c +++ b/dmd2/mars.c @@ -1,1636 +1,1636 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// https://github.com/D-Programming-Language/dmd/blob/master/src/mars.c -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include -#include -#include -#include -#include - -#if POSIX -#include -#endif - -#include "rmem.h" -#include "root.h" -#if !IN_LLVM -#include "async.h" -#endif - -#include "mars.h" -#include "module.h" -#include "mtype.h" -#include "id.h" -#include "cond.h" -#include "expression.h" -#include "lexer.h" -#if !IN_LLVM -#include "lib.h" -#include "json.h" -#endif - -#if WINDOWS_SEH -#include -long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep); -#endif - -#if !IN_LLVM -int response_expand(int *pargc, char ***pargv); -void browse(const char *url); -void getenv_setargv(const char *envvar, int *pargc, char** *pargv); - -void obj_start(char *srcfile); -void obj_end(Library *library, File *objfile); -#endif - -void printCtfePerformanceStats(); - -Global global; - -Global::Global() -{ - mars_ext = "d"; - sym_ext = "d"; - hdr_ext = "di"; - doc_ext = "html"; - ddoc_ext = "ddoc"; - json_ext = "json"; - map_ext = "map"; - -#if IN_LLVM - ll_ext = "ll"; - bc_ext = "bc"; - s_ext = "s"; - obj_ext = "o"; -#if _WIN32 - obj_ext_alt = "obj"; -#endif -#else -#if TARGET_WINDOS - obj_ext = "obj"; -#elif TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS - obj_ext = "o"; -#elif TARGET_NET -#else -#error "fix this" -#endif - -#if TARGET_WINDOS - lib_ext = "lib"; -#elif TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS - lib_ext = "a"; -#elif TARGET_NET -#else -#error "fix this" -#endif -#endif - - copyright = "Copyright (c) 1999-2012 by Digital Mars"; - written = "written by Walter Bright" -#if TARGET_NET - "\nMSIL back-end (alpha release) by Cristian L. Vlasceanu and associates."; -#endif - ; - version = "v2.059"; -#if IN_LLVM - ldc_version = "LDC trunk"; - llvm_version = "LLVM "LDC_LLVM_VERSION_STRING; -#endif - global.structalign = 8; - - // This should only be used as a global, so the other fields are - // automatically initialized to zero when the program is loaded. - // In particular, DO NOT zero-initialize .params here (like DMD - // does) because command-line options initialize some of those - // fields to non-zero defaults, and do so from constructors that - // may run before this one. -} - -unsigned Global::startGagging() -{ - ++gag; - return gaggedErrors; -} - -bool Global::endGagging(unsigned oldGagged) -{ - bool anyErrs = (gaggedErrors != oldGagged); - --gag; - // Restore the original state of gagged errors; set total errors - // to be original errors + new ungagged errors. - errors -= (gaggedErrors - oldGagged); - gaggedErrors = oldGagged; - return anyErrs; -} - -bool Global::isSpeculativeGagging() -{ - return gag && gag == speculativeGag; -} - - -char *Loc::toChars() -{ - OutBuffer buf; - - if (filename) - { - buf.printf("%s", filename); - } - - if (linnum) - buf.printf("(%d)", linnum); - buf.writeByte(0); - return (char *)buf.extractData(); -} - -Loc::Loc(Module *mod, unsigned linnum) -{ - this->linnum = linnum; - this->filename = mod ? mod->srcfile->toChars() : NULL; -} - -bool Loc::equals(const Loc& loc) -{ - return linnum == loc.linnum && FileName::equals(filename, loc.filename); -} - -/************************************** - * Print error message - */ - -void error(Loc loc, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - verror(loc, format, ap); - va_end( ap ); -} - -void warning(Loc loc, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - vwarning(loc, format, ap); - va_end( ap ); -} - -/************************************** - * Print supplementary message about the last error - * Used for backtraces, etc - */ -void errorSupplemental(Loc loc, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - verrorSupplemental(loc, format, ap); - va_end( ap ); -} - -void verror(Loc loc, const char *format, va_list ap) -{ - if (!global.gag) - { - char *p = loc.toChars(); - - if (*p) - fprintf(stdmsg, "%s: ", p); - mem.free(p); - - fprintf(stdmsg, "Error: "); - // MS doesn't recognize %zu format - OutBuffer tmp; - tmp.vprintf(format, ap); -#if _MSC_VER - fprintf(stdmsg, "%s", tmp.toChars()); -#else - vfprintf(stdmsg, format, ap); -#endif - fprintf(stdmsg, "\n"); - fflush(stdmsg); -//halt(); - } - else - { - global.gaggedErrors++; - } - global.errors++; -} - -// Doesn't increase error count, doesn't print "Error:". -void verrorSupplemental(Loc loc, const char *format, va_list ap) -{ - if (!global.gag) - { - fprintf(stdmsg, "%s: ", loc.toChars()); -#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); - } -} - -void vwarning(Loc loc, const char *format, va_list ap) -{ - if (global.params.warnings && !global.gag) - { - char *p = loc.toChars(); - - if (*p) - fprintf(stdmsg, "%s: ", p); - mem.free(p); - - 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 - } -} - -/*************************************** - * Call this after printing out fatal error messages to clean up and exit - * the compiler. - */ - -void fatal() -{ -#if 0 - halt(); -#endif - exit(EXIT_FAILURE); -} - -/************************************** - * Try to stop forgetting to remove the breakpoints from - * release builds. - */ -void halt() -{ -#ifdef DEBUG - *(volatile char*)0=0; -#endif -} - -#if !IN_LLVM - -extern void backend_init(); -extern void backend_term(); - -void usage() -{ -#if TARGET_LINUX - const char fpic[] ="\ - -fPIC generate position independent code\n\ -"; -#else - const char fpic[] = ""; -#endif - printf("DMD%s D Compiler %s\n%s %s\n", - sizeof(size_t) == 4 ? "32" : "64", - global.version, global.copyright, global.written); - printf("\ -Documentation: http://www.dlang.org/index.html\n\ -Usage:\n\ - dmd files.d ... { -switch }\n\ -\n\ - files.d D source files\n\ - @cmdfile read arguments from cmdfile\n\ - -c do not link\n\ - -cov do code coverage analysis\n\ - -D generate documentation\n\ - -Dddocdir write documentation file to docdir directory\n\ - -Dffilename write documentation file to filename\n\ - -d allow deprecated features\n\ - -debug compile in debug code\n\ - -debug=level compile in debug code <= level\n\ - -debug=ident compile in debug code identified by ident\n\ - -debuglib=name set symbolic debug library to name\n\ - -defaultlib=name set default library to name\n\ - -deps=filename write module dependencies to filename\n%s" -" -g add symbolic debug info\n\ - -gc add symbolic debug info, pretend to be C\n\ - -gs always emit stack frame\n\ - -H generate 'header' file\n\ - -Hddirectory write 'header' file to directory\n\ - -Hffilename write 'header' file to filename\n\ - --help print help\n\ - -Ipath where to look for imports\n\ - -ignore ignore unsupported pragmas\n\ - -inline do function inlining\n\ - -Jpath where to look for string imports\n\ - -Llinkerflag pass linkerflag to link\n\ - -lib generate library rather than object files\n" -#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS -" -m32 generate 32 bit code\n\ - -m64 generate 64 bit code\n" -#endif -" -man open web browser on manual page\n\ - -map generate linker .map file\n\ - -noboundscheck turns off array bounds checking for all functions\n\ - -nofloat do not emit reference to floating point\n\ - -O optimize\n\ - -o- do not write object file\n\ - -odobjdir write object & library files to directory objdir\n\ - -offilename name output file to filename\n\ - -op do not strip paths from source file\n\ - -profile profile runtime performance of generated code\n\ - -property enforce property syntax\n\ - -quiet suppress unnecessary messages\n\ - -release compile release version\n\ - -run srcfile args... run resulting program, passing args\n" -#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS -" -shared generate shared library\n" -#endif -" -unittest compile in unit tests\n\ - -v verbose\n\ - -version=level compile in version code >= level\n\ - -version=ident compile in version code identified by ident\n\ - -vtls list all variables going into thread local storage\n\ - -w enable warnings\n\ - -wi enable informational warnings\n\ - -X generate JSON file\n\ - -Xffilename write JSON file to filename\n\ -", fpic); -} - -extern signed char tyalignsize[]; - -#if _WIN32 && __DMC__ -extern "C" -{ - extern int _xi_a; - extern int _end; -} -#endif - -int tryMain(int argc, char *argv[]) -{ - mem.init(); // initialize storage allocator - mem.setStackBottom(&argv); -#if _WIN32 && __DMC__ - mem.addroots((char *)&_xi_a, (char *)&_end); -#endif - - Strings files; - Strings libmodules; - char *p; - Module *m; - int status = EXIT_SUCCESS; - int argcstart = argc; - int setdebuglib = 0; - char noboundscheck = 0; - const char *inifilename = NULL; - -#ifdef DEBUG - printf("DMD %s DEBUG\n", global.version); -#endif - - unittests(); - - // Check for malformed input - if (argc < 1 || !argv) - { - Largs: - error(0, "missing or null command line arguments"); - fatal(); - } - for (size_t i = 0; i < argc; i++) - { - if (!argv[i]) - goto Largs; - } - - if (response_expand(&argc,&argv)) // expand response files - error(0, "can't open response file"); - - files.reserve(argc - 1); - - // Set default values - global.params.argv0 = argv[0]; - global.params.link = 1; - global.params.useAssert = 1; - global.params.useInvariants = 1; - global.params.useIn = 1; - global.params.useOut = 1; - global.params.useArrayBounds = 2; // default to all functions - global.params.useSwitchError = 1; - global.params.useInline = 0; - global.params.obj = 1; - global.params.Dversion = 2; - global.params.quiet = 1; - - global.params.linkswitches = new Strings(); - global.params.libfiles = new Strings(); - global.params.objfiles = new Strings(); - global.params.ddocfiles = new Strings(); - - // Default to -m32 for 32 bit dmd, -m64 for 64 bit dmd - global.params.is64bit = (sizeof(size_t) == 8); - -#if TARGET_WINDOS - global.params.is64bit = 0; - global.params.defaultlibname = "phobos"; -#elif TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS - global.params.defaultlibname = "phobos2"; -#elif TARGET_NET -#else -#error "fix this" -#endif - - // Predefine version identifiers - VersionCondition::addPredefinedGlobalIdent("DigitalMars"); - -#if TARGET_WINDOS - VersionCondition::addPredefinedGlobalIdent("Windows"); - global.params.isWindows = 1; -#if TARGET_NET - // TARGET_NET macro is NOT mutually-exclusive with TARGET_WINDOS - VersionCondition::addPredefinedGlobalIdent("D_NET"); -#endif -#elif TARGET_LINUX - VersionCondition::addPredefinedGlobalIdent("Posix"); - VersionCondition::addPredefinedGlobalIdent("linux"); - global.params.isLinux = 1; -#elif TARGET_OSX - VersionCondition::addPredefinedGlobalIdent("Posix"); - VersionCondition::addPredefinedGlobalIdent("OSX"); - global.params.isOSX = 1; - - // For legacy compatibility - VersionCondition::addPredefinedGlobalIdent("darwin"); -#elif TARGET_FREEBSD - VersionCondition::addPredefinedGlobalIdent("Posix"); - VersionCondition::addPredefinedGlobalIdent("FreeBSD"); - global.params.isFreeBSD = 1; -#elif TARGET_OPENBSD - VersionCondition::addPredefinedGlobalIdent("Posix"); - VersionCondition::addPredefinedGlobalIdent("OpenBSD"); - global.params.isFreeBSD = 1; -#elif TARGET_SOLARIS - VersionCondition::addPredefinedGlobalIdent("Posix"); - VersionCondition::addPredefinedGlobalIdent("Solaris"); - global.params.isSolaris = 1; -#else -#error "fix this" -#endif - - VersionCondition::addPredefinedGlobalIdent("LittleEndian"); - //VersionCondition::addPredefinedGlobalIdent("D_Bits"); -#if DMDV2 - VersionCondition::addPredefinedGlobalIdent("D_Version2"); -#endif - VersionCondition::addPredefinedGlobalIdent("all"); - -#if _WIN32 - inifilename = inifile(argv[0], "sc.ini"); -#elif linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4 - inifilename = inifile(argv[0], "dmd.conf"); -#else -#error "fix this" -#endif - getenv_setargv("DFLAGS", &argc, &argv); - -#if 0 - for (size_t i = 0; i < argc; i++) - { - printf("argv[%d] = '%s'\n", i, argv[i]); - } -#endif - - for (size_t i = 1; i < argc; i++) - { - p = argv[i]; - if (*p == '-') - { - if (strcmp(p + 1, "d") == 0) - global.params.useDeprecated = 1; - else if (strcmp(p + 1, "c") == 0) - global.params.link = 0; - else if (strcmp(p + 1, "cov") == 0) - global.params.cov = 1; -#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS - else if (strcmp(p + 1, "shared") == 0 -#if TARGET_OSX - // backwards compatibility with old switch - || strcmp(p + 1, "dylib") == 0 -#endif - ) - global.params.dll = 1; - else if (strcmp(p + 1, "fPIC") == 0) - global.params.pic = 1; -#endif - else if (strcmp(p + 1, "map") == 0) - global.params.map = 1; - else if (strcmp(p + 1, "multiobj") == 0) - global.params.multiobj = 1; - else if (strcmp(p + 1, "g") == 0) - global.params.symdebug = 1; - else if (strcmp(p + 1, "gc") == 0) - global.params.symdebug = 2; - else if (strcmp(p + 1, "gs") == 0) - global.params.alwaysframe = 1; - else if (strcmp(p + 1, "gt") == 0) - { error(0, "use -profile instead of -gt\n"); - global.params.trace = 1; - } - else if (strcmp(p + 1, "m32") == 0) - global.params.is64bit = 0; - else if (strcmp(p + 1, "m64") == 0) - global.params.is64bit = 1; - else if (strcmp(p + 1, "profile") == 0) - global.params.trace = 1; - else if (strcmp(p + 1, "v") == 0) - global.params.verbose = 1; -#if DMDV2 - else if (strcmp(p + 1, "vtls") == 0) - global.params.vtls = 1; -#endif - else if (strcmp(p + 1, "v1") == 0) - { -#if DMDV1 - global.params.Dversion = 1; -#else - error(0, "use DMD 1.0 series compilers for -v1 switch"); - break; -#endif - } - else if (strcmp(p + 1, "w") == 0) - global.params.warnings = 1; - else if (strcmp(p + 1, "wi") == 0) - global.params.warnings = 2; - else if (strcmp(p + 1, "O") == 0) - global.params.optimize = 1; - else if (p[1] == 'o') - { - switch (p[2]) - { - case '-': - global.params.obj = 0; - break; - - case 'd': - if (!p[3]) - goto Lnoarg; - global.params.objdir = p + 3; - break; - - case 'f': - if (!p[3]) - goto Lnoarg; - global.params.objname = p + 3; - break; - - case 'p': - if (p[3]) - goto Lerror; - global.params.preservePaths = 1; - break; - - case 0: - error(0, "-o no longer supported, use -of or -od"); - break; - - default: - goto Lerror; - } - } - else if (p[1] == 'D') - { global.params.doDocComments = 1; - switch (p[2]) - { - case 'd': - if (!p[3]) - goto Lnoarg; - global.params.docdir = p + 3; - break; - case 'f': - if (!p[3]) - goto Lnoarg; - global.params.docname = p + 3; - break; - - case 0: - break; - - default: - goto Lerror; - } - } - else if (p[1] == 'H') - { global.params.doHdrGeneration = 1; - switch (p[2]) - { - case 'd': - if (!p[3]) - goto Lnoarg; - global.params.hdrdir = p + 3; - break; - - case 'f': - if (!p[3]) - goto Lnoarg; - global.params.hdrname = p + 3; - break; - - case 0: - break; - - default: - goto Lerror; - } - } - else if (p[1] == 'X') - { global.params.doXGeneration = 1; - switch (p[2]) - { - case 'f': - if (!p[3]) - goto Lnoarg; - global.params.xfilename = p + 3; - break; - - case 0: - break; - - default: - goto Lerror; - } - } - else if (strcmp(p + 1, "ignore") == 0) - global.params.ignoreUnsupportedPragmas = 1; - else if (strcmp(p + 1, "property") == 0) - global.params.enforcePropertySyntax = 1; - else if (strcmp(p + 1, "inline") == 0) - global.params.useInline = 1; - else if (strcmp(p + 1, "lib") == 0) - global.params.lib = 1; - else if (strcmp(p + 1, "nofloat") == 0) - global.params.nofloat = 1; - else if (strcmp(p + 1, "quiet") == 0) - global.params.quiet = 1; - else if (strcmp(p + 1, "release") == 0) - global.params.release = 1; -#if DMDV2 - else if (strcmp(p + 1, "noboundscheck") == 0) - noboundscheck = 1; -#endif - else if (strcmp(p + 1, "unittest") == 0) - global.params.useUnitTests = 1; - else if (p[1] == 'I') - { - if (!global.params.imppath) - global.params.imppath = new Strings(); - global.params.imppath->push(p + 2); - } - else if (p[1] == 'J') - { - if (!global.params.fileImppath) - global.params.fileImppath = new Strings(); - global.params.fileImppath->push(p + 2); - } - else if (memcmp(p + 1, "debug", 5) == 0 && p[6] != 'l') - { - // Parse: - // -debug - // -debug=number - // -debug=identifier - if (p[6] == '=') - { - if (isdigit((unsigned char)p[7])) - { long level; - - errno = 0; - level = strtol(p + 7, &p, 10); - if (*p || errno || level > INT_MAX) - goto Lerror; - DebugCondition::setGlobalLevel((int)level); - } - else if (Lexer::isValidIdentifier(p + 7)) - DebugCondition::addGlobalIdent(p + 7); - else - goto Lerror; - } - else if (p[6]) - goto Lerror; - else - global.params.debuglevel = 1; - } - else if (memcmp(p + 1, "version", 5) == 0) - { - // Parse: - // -version=number - // -version=identifier - if (p[8] == '=') - { - if (isdigit((unsigned char)p[9])) - { long level; - - errno = 0; - level = strtol(p + 9, &p, 10); - if (*p || errno || level > INT_MAX) - goto Lerror; - VersionCondition::setGlobalLevel((int)level); - } - else if (Lexer::isValidIdentifier(p + 9)) - VersionCondition::addGlobalIdent(p + 9); - else - goto Lerror; - } - else - goto Lerror; - } - else if (strcmp(p + 1, "-b") == 0) - global.params.debugb = 1; - else if (strcmp(p + 1, "-c") == 0) - global.params.debugc = 1; - else if (strcmp(p + 1, "-f") == 0) - global.params.debugf = 1; - else if (strcmp(p + 1, "-help") == 0) - { usage(); - exit(EXIT_SUCCESS); - } - else if (strcmp(p + 1, "-r") == 0) - global.params.debugr = 1; - else if (strcmp(p + 1, "-x") == 0) - global.params.debugx = 1; - else if (strcmp(p + 1, "-y") == 0) - global.params.debugy = 1; - else if (p[1] == 'L') - { - global.params.linkswitches->push(p + 2); - } - else if (memcmp(p + 1, "defaultlib=", 11) == 0) - { - global.params.defaultlibname = p + 1 + 11; - } - else if (memcmp(p + 1, "debuglib=", 9) == 0) - { - setdebuglib = 1; - global.params.debuglibname = p + 1 + 9; - } - else if (memcmp(p + 1, "deps=", 5) == 0) - { - global.params.moduleDepsFile = p + 1 + 5; - if (!global.params.moduleDepsFile[0]) - goto Lnoarg; - global.params.moduleDeps = new OutBuffer; - } - else if (memcmp(p + 1, "man", 3) == 0) - { -#if _WIN32 -#if DMDV1 - browse("http://www.digitalmars.com/d/1.0/dmd-windows.html"); -#else - browse("http://www.dlang.org/dmd-windows.html"); -#endif -#endif -#if linux -#if DMDV1 - browse("http://www.digitalmars.com/d/1.0/dmd-linux.html"); -#else - browse("http://www.dlang.org/dmd-linux.html"); -#endif -#endif -#if __APPLE__ -#if DMDV1 - browse("http://www.digitalmars.com/d/1.0/dmd-osx.html"); -#else - browse("http://www.dlang.org/dmd-osx.html"); -#endif -#endif -#if __FreeBSD__ -#if DMDV1 - browse("http://www.digitalmars.com/d/1.0/dmd-freebsd.html"); -#else - browse("http://www.dlang.org/dmd-freebsd.html"); -#endif -#endif -#if __OpenBSD__ -#if DMDV1 - browse("http://www.digitalmars.com/d/1.0/dmd-openbsd.html"); -#else - browse("http://www.dlang.org/dmd-openbsd.html"); -#endif -#endif - exit(EXIT_SUCCESS); - } - else if (strcmp(p + 1, "run") == 0) - { global.params.run = 1; - global.params.runargs_length = ((i >= argcstart) ? argc : argcstart) - i - 1; - if (global.params.runargs_length) - { - files.push(argv[i + 1]); - global.params.runargs = &argv[i + 2]; - i += global.params.runargs_length; - global.params.runargs_length--; - } - else - { global.params.run = 0; - goto Lnoarg; - } - } - else - { - Lerror: - error(0, "unrecognized switch '%s'", argv[i]); - continue; - - Lnoarg: - error(0, "argument expected for switch '%s'", argv[i]); - continue; - } - } - else - { -#if TARGET_WINDOS - char *ext = FileName::ext(p); - if (ext && FileName::compare(ext, "exe") == 0) - { - global.params.objname = p; - continue; - } -#endif - files.push(p); - } - } - if (global.errors) - { - fatal(); - } - if (files.dim == 0) - { usage(); - return EXIT_FAILURE; - } - - if (!setdebuglib) - global.params.debuglibname = global.params.defaultlibname; - -#if TARGET_OSX - global.params.pic = 1; -#endif - -#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS - if (global.params.lib && global.params.dll) - error(0, "cannot mix -lib and -shared\n"); -#endif - - if (global.params.release) - { global.params.useInvariants = 0; - global.params.useIn = 0; - global.params.useOut = 0; - global.params.useAssert = 0; - global.params.useArrayBounds = 1; - global.params.useSwitchError = 0; - } - if (noboundscheck) - global.params.useArrayBounds = 0; - - if (global.params.run) - global.params.quiet = 1; - - if (global.params.useUnitTests) - global.params.useAssert = 1; - - if (!global.params.obj || global.params.lib) - global.params.link = 0; - - if (global.params.link) - { - global.params.exefile = global.params.objname; - global.params.oneobj = 1; - if (global.params.objname) - { - /* Use this to name the one object file with the same - * name as the exe file. - */ - global.params.objname = FileName::forceExt(global.params.objname, global.obj_ext)->toChars(); - - /* If output directory is given, use that path rather than - * the exe file path. - */ - if (global.params.objdir) - { char *name = FileName::name(global.params.objname); - global.params.objname = FileName::combine(global.params.objdir, name); - } - } - } - else if (global.params.lib) - { - global.params.libname = global.params.objname; - global.params.objname = NULL; - - // Haven't investigated handling these options with multiobj - if (!global.params.cov && !global.params.trace -#if 0 && TARGET_WINDOS - /* multiobj causes class/struct debug info to be attached to init-data, - * but this will not be linked into the executable, so this info is lost. - * Bugzilla 4014 - */ - && !global.params.symdebug -#endif - ) - global.params.multiobj = 1; - } - else if (global.params.run) - { - error(0, "flags conflict with -run"); - fatal(); - } - else - { - if (global.params.objname && files.dim > 1) - { - global.params.oneobj = 1; - //error("multiple source files, but only one .obj name"); - //fatal(); - } - } - if (global.params.is64bit) - { - VersionCondition::addPredefinedGlobalIdent("D_InlineAsm_X86_64"); - VersionCondition::addPredefinedGlobalIdent("X86_64"); - VersionCondition::addPredefinedGlobalIdent("D_LP64"); - VersionCondition::addPredefinedGlobalIdent("D_SIMD"); -#if TARGET_WINDOS - VersionCondition::addPredefinedGlobalIdent("Win64"); -#endif - } - else - { - VersionCondition::addPredefinedGlobalIdent("D_InlineAsm"); - VersionCondition::addPredefinedGlobalIdent("D_InlineAsm_X86"); - VersionCondition::addPredefinedGlobalIdent("X86"); -#if TARGET_OSX - VersionCondition::addPredefinedGlobalIdent("D_SIMD"); -#endif -#if TARGET_WINDOS - VersionCondition::addPredefinedGlobalIdent("Win32"); -#endif - } - if (global.params.doDocComments) - VersionCondition::addPredefinedGlobalIdent("D_Ddoc"); - if (global.params.cov) - VersionCondition::addPredefinedGlobalIdent("D_Coverage"); - if (global.params.pic) - VersionCondition::addPredefinedGlobalIdent("D_PIC"); -#if DMDV2 - if (global.params.useUnitTests) - VersionCondition::addPredefinedGlobalIdent("unittest"); -#endif - - // Initialization - Type::init(); - Id::initialize(); - Module::init(); - initPrecedence(); - - if (global.params.verbose) - { printf("binary %s\n", argv[0]); - printf("version %s\n", global.version); - printf("config %s\n", inifilename ? inifilename : "(none)"); - } - - //printf("%d source files\n",files.dim); - - // Build import search path - if (global.params.imppath) - { - for (size_t i = 0; i < global.params.imppath->dim; i++) - { - char *path = (*global.params.imppath)[i]; - Strings *a = FileName::splitPath(path); - - if (a) - { - if (!global.path) - global.path = new Strings(); - global.path->append(a); - } - } - } - - // Build string import search path - if (global.params.fileImppath) - { - for (size_t i = 0; i < global.params.fileImppath->dim; i++) - { - char *path = global.params.fileImppath->tdata()[i]; - Strings *a = FileName::splitPath(path); - - if (a) - { - if (!global.filePath) - global.filePath = new Strings(); - global.filePath->append(a); - } - } - } - - // Create Modules - Modules modules; - modules.reserve(files.dim); - int firstmodule = 1; - for (size_t i = 0; i < files.dim; i++) - { - char *ext; - char *name; - - p = files.tdata()[i]; - -#if _WIN32 - // Convert / to \ so linker will work - for (size_t j = 0; p[j]; j++) - { - if (p[j] == '/') - p[j] = '\\'; - } -#endif - - p = FileName::name(p); // strip path - ext = FileName::ext(p); - if (ext) - { /* Deduce what to do with a file based on its extension - */ - if (FileName::equals(ext, global.obj_ext)) - { - global.params.objfiles->push(files.tdata()[i]); - libmodules.push(files.tdata()[i]); - continue; - } - - if (FileName::equals(ext, global.lib_ext)) - { - global.params.libfiles->push(files.tdata()[i]); - libmodules.push(files.tdata()[i]); - continue; - } - - if (strcmp(ext, global.ddoc_ext) == 0) - { - global.params.ddocfiles->push(files.tdata()[i]); - continue; - } - - if (FileName::equals(ext, global.json_ext)) - { - global.params.doXGeneration = 1; - global.params.xfilename = files.tdata()[i]; - continue; - } - - if (FileName::equals(ext, global.map_ext)) - { - global.params.mapfile = files.tdata()[i]; - continue; - } - -#if TARGET_WINDOS - if (FileName::equals(ext, "res")) - { - global.params.resfile = files.tdata()[i]; - continue; - } - - if (FileName::equals(ext, "def")) - { - global.params.deffile = files.tdata()[i]; - continue; - } - - if (FileName::equals(ext, "exe")) - { - assert(0); // should have already been handled - } -#endif - - /* Examine extension to see if it is a valid - * D source file extension - */ - if (FileName::equals(ext, global.mars_ext) || - FileName::equals(ext, global.hdr_ext) || - FileName::equals(ext, "dd") || - FileName::equals(ext, "htm") || - FileName::equals(ext, "html") || - FileName::equals(ext, "xhtml")) - { - ext--; // skip onto '.' - assert(*ext == '.'); - name = (char *)mem.malloc((ext - p) + 1); - memcpy(name, p, ext - p); - name[ext - p] = 0; // strip extension - - if (name[0] == 0 || - strcmp(name, "..") == 0 || - strcmp(name, ".") == 0) - { - Linvalid: - error(0, "invalid file name '%s'", files.tdata()[i]); - fatal(); - } - } - else - { error(0, "unrecognized file extension %s\n", ext); - fatal(); - } - } - else - { name = p; - if (!*name) - goto Linvalid; - } - - /* At this point, name is the D source file name stripped of - * its path and extension. - */ - - Identifier *id = Lexer::idPool(name); - m = new Module(files[i], id, global.params.doDocComments, global.params.doHdrGeneration); - modules.push(m); - - if (firstmodule) - { global.params.objfiles->push(m->objfile->name->str); - firstmodule = 0; - } - } - - // Read files -#define ASYNCREAD 1 -#if ASYNCREAD - // Multi threaded - AsyncRead *aw = AsyncRead::create(modules.dim); - for (size_t i = 0; i < modules.dim; i++) - { - m = modules[i]; - aw->addFile(m->srcfile); - } - aw->start(); -#else - // Single threaded - for (size_t i = 0; i < modules.dim; i++) - { - m = modules[i]; - m->read(0); - } -#endif - - // Parse files - bool anydocfiles = false; - size_t filecount = modules.dim; - for (size_t filei = 0, modi = 0; filei < filecount; filei++, modi++) - { - m = modules[modi]; - if (global.params.verbose) - printf("parse %s\n", m->toChars()); - if (!Module::rootModule) - Module::rootModule = m; - m->importedFrom = m; - if (!global.params.oneobj || modi == 0 || m->isDocFile) - m->deleteObjFile(); -#if ASYNCREAD - if (aw->read(filei)) - { - error(0, "cannot read file %s", m->srcfile->name->toChars()); - fatal(); - } -#endif - m->parse(); - if (m->isDocFile) - { - anydocfiles = true; - m->gendocfile(); - - // Remove m from list of modules - modules.remove(modi); - modi--; - - // Remove m's object file from list of object files - for (size_t j = 0; j < global.params.objfiles->dim; j++) - { - if (m->objfile->name->str == global.params.objfiles->tdata()[j]) - { - global.params.objfiles->remove(j); - break; - } - } - - if (global.params.objfiles->dim == 0) - global.params.link = 0; - } - } -#if ASYNCREAD - AsyncRead::dispose(aw); -#endif - - if (anydocfiles && modules.dim && - (global.params.oneobj || global.params.objname)) - { - error(0, "conflicting Ddoc and obj generation options"); - fatal(); - } - if (global.errors) - fatal(); - if (global.params.doHdrGeneration) - { - /* Generate 'header' import files. - * Since 'header' import files must be independent of command - * line switches and what else is imported, they are generated - * before any semantic analysis. - */ - for (size_t i = 0; i < modules.dim; i++) - { - m = modules[i]; - if (global.params.verbose) - printf("import %s\n", m->toChars()); - m->genhdrfile(); - } - } - if (global.errors) - fatal(); - - // load all unconditional imports for better symbol resolving - for (size_t i = 0; i < modules.dim; i++) - { - m = modules[i]; - if (global.params.verbose) - printf("importall %s\n", m->toChars()); - m->importAll(0); - } - if (global.errors) - fatal(); - - backend_init(); - - // Do semantic analysis - for (size_t i = 0; i < modules.dim; i++) - { - m = modules[i]; - if (global.params.verbose) - printf("semantic %s\n", m->toChars()); - m->semantic(); - } - if (global.errors) - fatal(); - - Module::dprogress = 1; - Module::runDeferredSemantic(); - - // Do pass 2 semantic analysis - for (size_t i = 0; i < modules.dim; i++) - { - m = modules[i]; - if (global.params.verbose) - printf("semantic2 %s\n", m->toChars()); - m->semantic2(); - } - if (global.errors) - fatal(); - - // Do pass 3 semantic analysis - for (size_t i = 0; i < modules.dim; i++) - { - m = modules[i]; - if (global.params.verbose) - printf("semantic3 %s\n", m->toChars()); - m->semantic3(); - } - if (global.errors) - fatal(); - - if (global.params.moduleDeps != NULL) - { - assert(global.params.moduleDepsFile != NULL); - - File deps(global.params.moduleDepsFile); - OutBuffer* ob = global.params.moduleDeps; - deps.setbuffer((void*)ob->data, ob->offset); - deps.writev(); - } - - - // Scan for functions to inline - if (global.params.useInline) - { - /* The problem with useArrayBounds and useAssert is that the - * module being linked to may not have generated them, so if - * we inline functions from those modules, the symbols for them will - * not be found at link time. - */ - if (!global.params.useArrayBounds && !global.params.useAssert) - { - // Do pass 3 semantic analysis on all imported modules, - // since otherwise functions in them cannot be inlined - for (size_t i = 0; i < Module::amodules.dim; i++) - { - m = Module::amodules[i]; - if (global.params.verbose) - printf("semantic3 %s\n", m->toChars()); - m->semantic3(); - } - if (global.errors) - fatal(); - } - - for (size_t i = 0; i < modules.dim; i++) - { - m = modules[i]; - if (global.params.verbose) - printf("inline scan %s\n", m->toChars()); - m->inlineScan(); - } - } - - // Do not attempt to generate output files if errors or warnings occurred - if (global.errors || global.warnings) - fatal(); - - printCtfePerformanceStats(); - - Library *library = NULL; - if (global.params.lib) - { - library = new Library(); - library->setFilename(global.params.objdir, global.params.libname); - - // Add input object and input library files to output library - for (size_t i = 0; i < libmodules.dim; i++) - { - char *p = libmodules[i]; - library->addObject(p, NULL, 0); - } - } - - // Generate output files - - if (global.params.doXGeneration) - json_generate(&modules); - - if (global.params.oneobj) - { - for (size_t i = 0; i < modules.dim; i++) - { - m = modules[i]; - if (global.params.verbose) - printf("code %s\n", m->toChars()); - if (i == 0) - obj_start(m->srcfile->toChars()); - m->genobjfile(0); - if (!global.errors && global.params.doDocComments) - m->gendocfile(); - } - if (!global.errors && modules.dim) - { - obj_end(library, modules.tdata()[0]->objfile); - } - } - else - { - for (size_t i = 0; i < modules.dim; i++) - { - m = modules[i]; - if (global.params.verbose) - printf("code %s\n", m->toChars()); - if (global.params.obj) - { obj_start(m->srcfile->toChars()); - m->genobjfile(global.params.multiobj); - obj_end(library, m->objfile); - obj_write_deferred(library); - } - if (global.errors) - { - if (!global.params.lib) - m->deleteObjFile(); - } - else - { - if (global.params.doDocComments) - m->gendocfile(); - } - } - } - - if (global.params.lib && !global.errors) - library->write(); - - backend_term(); - if (global.errors) - fatal(); - - if (!global.params.objfiles->dim) - { - if (global.params.link) - error(0, "no object files to link"); - } - else - { - if (global.params.link) - status = runLINK(); - - if (global.params.run) - { - if (!status) - { - status = runProgram(); - - /* Delete .obj files and .exe file - */ - for (size_t i = 0; i < modules.dim; i++) - { - Module *m = modules[i]; - m->deleteObjFile(); - if (global.params.oneobj) - break; - } - deleteExeFile(); - } - } - } - - return status; -} - -int main(int argc, char *argv[]) -{ - int status = -1; -#if WINDOWS_SEH - __try - { -#endif - status = tryMain(argc, argv); -#if WINDOWS_SEH - } - __except (__ehfilter(GetExceptionInformation())) - { - printf("Stack overflow\n"); - fatal(); - } -#endif - return status; -} - -#endif // !IN_LLVM - -/*********************************** - * Parse and append contents of environment variable envvar - * to argc and argv[]. - * The string is separated into arguments, processing \ and ". - */ - -void getenv_setargv(const char *envvar, int *pargc, char** *pargv) -{ - char *p; - - int instring; - int slash; - char c; - - char *env = getenv(envvar); - if (!env) - return; - - env = mem.strdup(env); // create our own writable copy - - int argc = *pargc; - Strings *argv = new Strings(); - argv->setDim(argc); - - int argc_left = 0; - for (int i = 0; i < argc; i++) { - if (!strcmp((*pargv)[i], "-run") || !strcmp((*pargv)[i], "--run")) { - // HACK: set flag to indicate we saw '-run' here - global.params.run = true; - // Don't eat -run yet so the program arguments don't get changed - argc_left = argc - i; - argc = i; - *pargv = &(*pargv)[i]; - argv->setDim(i); - break; - } else { - } - } - // HACK to stop required values from command line being drawn from DFLAGS - argv->push((char*)""); - argc++; - - size_t j = 1; // leave argv[0] alone - while (1) - { - int wildcard = 1; // do wildcard expansion - switch (*env) - { - case ' ': - case '\t': - env++; - break; - - case 0: - goto Ldone; - - case '"': - wildcard = 0; - default: - argv->push(env); // append - //argv->insert(j, env); // insert at position j - j++; - argc++; - p = env; - slash = 0; - instring = 0; - c = 0; - - while (1) - { - c = *env++; - switch (c) - { - case '"': - p -= (slash >> 1); - if (slash & 1) - { p--; - goto Laddc; - } - instring ^= 1; - slash = 0; - continue; - - case ' ': - case '\t': - if (instring) - goto Laddc; - *p = 0; - //if (wildcard) - //wildcardexpand(); // not implemented - break; - - case '\\': - slash++; - *p++ = c; - continue; - - case 0: - *p = 0; - //if (wildcard) - //wildcardexpand(); // not implemented - goto Ldone; - - default: - Laddc: - slash = 0; - *p++ = c; - continue; - } - break; - } - } - } - -Ldone: - assert(argc == argv->dim); - argv->reserve(argc_left); - for (int i = 0; i < argc_left; i++) - argv->data[argc++] = (void *)(*pargv)[i]; - - *pargc = argc; - *pargv = argv->tdata(); -} - -#if WINDOWS_SEH - -long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep) -{ - //printf("%x\n", ep->ExceptionRecord->ExceptionCode); - if (ep->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW) - { -#if 1 //ndef DEBUG - return EXCEPTION_EXECUTE_HANDLER; -#endif - } - return EXCEPTION_CONTINUE_SEARCH; -} - -#endif + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2012 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// https://github.com/D-Programming-Language/dmd/blob/master/src/mars.c +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include +#include +#include +#include +#include +#include +#include + +#if POSIX +#include +#endif + +#include "rmem.h" +#include "root.h" +#if !IN_LLVM +#include "async.h" +#endif + +#include "mars.h" +#include "module.h" +#include "mtype.h" +#include "id.h" +#include "cond.h" +#include "expression.h" +#include "lexer.h" +#if !IN_LLVM +#include "lib.h" +#include "json.h" +#endif + +#if WINDOWS_SEH +#include +long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep); +#endif + +#if !IN_LLVM +int response_expand(int *pargc, char ***pargv); +void browse(const char *url); +void getenv_setargv(const char *envvar, int *pargc, char** *pargv); + +void obj_start(char *srcfile); +void obj_end(Library *library, File *objfile); +#endif + +void printCtfePerformanceStats(); + +Global global; + +Global::Global() +{ + mars_ext = "d"; + sym_ext = "d"; + hdr_ext = "di"; + doc_ext = "html"; + ddoc_ext = "ddoc"; + json_ext = "json"; + map_ext = "map"; + +#if IN_LLVM + ll_ext = "ll"; + bc_ext = "bc"; + s_ext = "s"; + obj_ext = "o"; +#if _WIN32 + obj_ext_alt = "obj"; +#endif +#else +#if TARGET_WINDOS + obj_ext = "obj"; +#elif TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS + obj_ext = "o"; +#elif TARGET_NET +#else +#error "fix this" +#endif + +#if TARGET_WINDOS + lib_ext = "lib"; +#elif TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS + lib_ext = "a"; +#elif TARGET_NET +#else +#error "fix this" +#endif +#endif + + copyright = "Copyright (c) 1999-2012 by Digital Mars"; + written = "written by Walter Bright" +#if TARGET_NET + "\nMSIL back-end (alpha release) by Cristian L. Vlasceanu and associates."; +#endif + ; + version = "v2.059"; +#if IN_LLVM + ldc_version = "LDC trunk"; + llvm_version = "LLVM "LDC_LLVM_VERSION_STRING; +#endif + global.structalign = 8; + + // This should only be used as a global, so the other fields are + // automatically initialized to zero when the program is loaded. + // In particular, DO NOT zero-initialize .params here (like DMD + // does) because command-line options initialize some of those + // fields to non-zero defaults, and do so from constructors that + // may run before this one. +} + +unsigned Global::startGagging() +{ + ++gag; + return gaggedErrors; +} + +bool Global::endGagging(unsigned oldGagged) +{ + bool anyErrs = (gaggedErrors != oldGagged); + --gag; + // Restore the original state of gagged errors; set total errors + // to be original errors + new ungagged errors. + errors -= (gaggedErrors - oldGagged); + gaggedErrors = oldGagged; + return anyErrs; +} + +bool Global::isSpeculativeGagging() +{ + return gag && gag == speculativeGag; +} + + +char *Loc::toChars() +{ + OutBuffer buf; + + if (filename) + { + buf.printf("%s", filename); + } + + if (linnum) + buf.printf("(%d)", linnum); + buf.writeByte(0); + return (char *)buf.extractData(); +} + +Loc::Loc(Module *mod, unsigned linnum) +{ + this->linnum = linnum; + this->filename = mod ? mod->srcfile->toChars() : NULL; +} + +bool Loc::equals(const Loc& loc) +{ + return linnum == loc.linnum && FileName::equals(filename, loc.filename); +} + +/************************************** + * Print error message + */ + +void error(Loc loc, const char *format, ...) +{ + va_list ap; + va_start(ap, format); + verror(loc, format, ap); + va_end( ap ); +} + +void warning(Loc loc, const char *format, ...) +{ + va_list ap; + va_start(ap, format); + vwarning(loc, format, ap); + va_end( ap ); +} + +/************************************** + * Print supplementary message about the last error + * Used for backtraces, etc + */ +void errorSupplemental(Loc loc, const char *format, ...) +{ + va_list ap; + va_start(ap, format); + verrorSupplemental(loc, format, ap); + va_end( ap ); +} + +void verror(Loc loc, const char *format, va_list ap) +{ + if (!global.gag) + { + char *p = loc.toChars(); + + if (*p) + fprintf(stdmsg, "%s: ", p); + mem.free(p); + + fprintf(stdmsg, "Error: "); + // MS doesn't recognize %zu format + OutBuffer tmp; + tmp.vprintf(format, ap); +#if _MSC_VER + fprintf(stdmsg, "%s", tmp.toChars()); +#else + vfprintf(stdmsg, format, ap); +#endif + fprintf(stdmsg, "\n"); + fflush(stdmsg); +//halt(); + } + else + { + global.gaggedErrors++; + } + global.errors++; +} + +// Doesn't increase error count, doesn't print "Error:". +void verrorSupplemental(Loc loc, const char *format, va_list ap) +{ + if (!global.gag) + { + fprintf(stdmsg, "%s: ", loc.toChars()); +#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); + } +} + +void vwarning(Loc loc, const char *format, va_list ap) +{ + if (global.params.warnings && !global.gag) + { + char *p = loc.toChars(); + + if (*p) + fprintf(stdmsg, "%s: ", p); + mem.free(p); + + 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 + } +} + +/*************************************** + * Call this after printing out fatal error messages to clean up and exit + * the compiler. + */ + +void fatal() +{ +#if 0 + halt(); +#endif + exit(EXIT_FAILURE); +} + +/************************************** + * Try to stop forgetting to remove the breakpoints from + * release builds. + */ +void halt() +{ +#ifdef DEBUG + *(volatile char*)0=0; +#endif +} + +#if !IN_LLVM + +extern void backend_init(); +extern void backend_term(); + +void usage() +{ +#if TARGET_LINUX + const char fpic[] ="\ + -fPIC generate position independent code\n\ +"; +#else + const char fpic[] = ""; +#endif + printf("DMD%s D Compiler %s\n%s %s\n", + sizeof(size_t) == 4 ? "32" : "64", + global.version, global.copyright, global.written); + printf("\ +Documentation: http://www.dlang.org/index.html\n\ +Usage:\n\ + dmd files.d ... { -switch }\n\ +\n\ + files.d D source files\n\ + @cmdfile read arguments from cmdfile\n\ + -c do not link\n\ + -cov do code coverage analysis\n\ + -D generate documentation\n\ + -Dddocdir write documentation file to docdir directory\n\ + -Dffilename write documentation file to filename\n\ + -d allow deprecated features\n\ + -debug compile in debug code\n\ + -debug=level compile in debug code <= level\n\ + -debug=ident compile in debug code identified by ident\n\ + -debuglib=name set symbolic debug library to name\n\ + -defaultlib=name set default library to name\n\ + -deps=filename write module dependencies to filename\n%s" +" -g add symbolic debug info\n\ + -gc add symbolic debug info, pretend to be C\n\ + -gs always emit stack frame\n\ + -H generate 'header' file\n\ + -Hddirectory write 'header' file to directory\n\ + -Hffilename write 'header' file to filename\n\ + --help print help\n\ + -Ipath where to look for imports\n\ + -ignore ignore unsupported pragmas\n\ + -inline do function inlining\n\ + -Jpath where to look for string imports\n\ + -Llinkerflag pass linkerflag to link\n\ + -lib generate library rather than object files\n" +#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS +" -m32 generate 32 bit code\n\ + -m64 generate 64 bit code\n" +#endif +" -man open web browser on manual page\n\ + -map generate linker .map file\n\ + -noboundscheck turns off array bounds checking for all functions\n\ + -nofloat do not emit reference to floating point\n\ + -O optimize\n\ + -o- do not write object file\n\ + -odobjdir write object & library files to directory objdir\n\ + -offilename name output file to filename\n\ + -op do not strip paths from source file\n\ + -profile profile runtime performance of generated code\n\ + -property enforce property syntax\n\ + -quiet suppress unnecessary messages\n\ + -release compile release version\n\ + -run srcfile args... run resulting program, passing args\n" +#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS +" -shared generate shared library\n" +#endif +" -unittest compile in unit tests\n\ + -v verbose\n\ + -version=level compile in version code >= level\n\ + -version=ident compile in version code identified by ident\n\ + -vtls list all variables going into thread local storage\n\ + -w enable warnings\n\ + -wi enable informational warnings\n\ + -X generate JSON file\n\ + -Xffilename write JSON file to filename\n\ +", fpic); +} + +extern signed char tyalignsize[]; + +#if _WIN32 && __DMC__ +extern "C" +{ + extern int _xi_a; + extern int _end; +} +#endif + +int tryMain(int argc, char *argv[]) +{ + mem.init(); // initialize storage allocator + mem.setStackBottom(&argv); +#if _WIN32 && __DMC__ + mem.addroots((char *)&_xi_a, (char *)&_end); +#endif + + Strings files; + Strings libmodules; + char *p; + Module *m; + int status = EXIT_SUCCESS; + int argcstart = argc; + int setdebuglib = 0; + char noboundscheck = 0; + const char *inifilename = NULL; + +#ifdef DEBUG + printf("DMD %s DEBUG\n", global.version); +#endif + + unittests(); + + // Check for malformed input + if (argc < 1 || !argv) + { + Largs: + error(0, "missing or null command line arguments"); + fatal(); + } + for (size_t i = 0; i < argc; i++) + { + if (!argv[i]) + goto Largs; + } + + if (response_expand(&argc,&argv)) // expand response files + error(0, "can't open response file"); + + files.reserve(argc - 1); + + // Set default values + global.params.argv0 = argv[0]; + global.params.link = 1; + global.params.useAssert = 1; + global.params.useInvariants = 1; + global.params.useIn = 1; + global.params.useOut = 1; + global.params.useArrayBounds = 2; // default to all functions + global.params.useSwitchError = 1; + global.params.useInline = 0; + global.params.obj = 1; + global.params.Dversion = 2; + global.params.quiet = 1; + + global.params.linkswitches = new Strings(); + global.params.libfiles = new Strings(); + global.params.objfiles = new Strings(); + global.params.ddocfiles = new Strings(); + + // Default to -m32 for 32 bit dmd, -m64 for 64 bit dmd + global.params.is64bit = (sizeof(size_t) == 8); + +#if TARGET_WINDOS + global.params.is64bit = 0; + global.params.defaultlibname = "phobos"; +#elif TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS + global.params.defaultlibname = "phobos2"; +#elif TARGET_NET +#else +#error "fix this" +#endif + + // Predefine version identifiers + VersionCondition::addPredefinedGlobalIdent("DigitalMars"); + +#if TARGET_WINDOS + VersionCondition::addPredefinedGlobalIdent("Windows"); + global.params.isWindows = 1; +#if TARGET_NET + // TARGET_NET macro is NOT mutually-exclusive with TARGET_WINDOS + VersionCondition::addPredefinedGlobalIdent("D_NET"); +#endif +#elif TARGET_LINUX + VersionCondition::addPredefinedGlobalIdent("Posix"); + VersionCondition::addPredefinedGlobalIdent("linux"); + global.params.isLinux = 1; +#elif TARGET_OSX + VersionCondition::addPredefinedGlobalIdent("Posix"); + VersionCondition::addPredefinedGlobalIdent("OSX"); + global.params.isOSX = 1; + + // For legacy compatibility + VersionCondition::addPredefinedGlobalIdent("darwin"); +#elif TARGET_FREEBSD + VersionCondition::addPredefinedGlobalIdent("Posix"); + VersionCondition::addPredefinedGlobalIdent("FreeBSD"); + global.params.isFreeBSD = 1; +#elif TARGET_OPENBSD + VersionCondition::addPredefinedGlobalIdent("Posix"); + VersionCondition::addPredefinedGlobalIdent("OpenBSD"); + global.params.isFreeBSD = 1; +#elif TARGET_SOLARIS + VersionCondition::addPredefinedGlobalIdent("Posix"); + VersionCondition::addPredefinedGlobalIdent("Solaris"); + global.params.isSolaris = 1; +#else +#error "fix this" +#endif + + VersionCondition::addPredefinedGlobalIdent("LittleEndian"); + //VersionCondition::addPredefinedGlobalIdent("D_Bits"); +#if DMDV2 + VersionCondition::addPredefinedGlobalIdent("D_Version2"); +#endif + VersionCondition::addPredefinedGlobalIdent("all"); + +#if _WIN32 + inifilename = inifile(argv[0], "sc.ini"); +#elif linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4 + inifilename = inifile(argv[0], "dmd.conf"); +#else +#error "fix this" +#endif + getenv_setargv("DFLAGS", &argc, &argv); + +#if 0 + for (size_t i = 0; i < argc; i++) + { + printf("argv[%d] = '%s'\n", i, argv[i]); + } +#endif + + for (size_t i = 1; i < argc; i++) + { + p = argv[i]; + if (*p == '-') + { + if (strcmp(p + 1, "d") == 0) + global.params.useDeprecated = 1; + else if (strcmp(p + 1, "c") == 0) + global.params.link = 0; + else if (strcmp(p + 1, "cov") == 0) + global.params.cov = 1; +#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS + else if (strcmp(p + 1, "shared") == 0 +#if TARGET_OSX + // backwards compatibility with old switch + || strcmp(p + 1, "dylib") == 0 +#endif + ) + global.params.dll = 1; + else if (strcmp(p + 1, "fPIC") == 0) + global.params.pic = 1; +#endif + else if (strcmp(p + 1, "map") == 0) + global.params.map = 1; + else if (strcmp(p + 1, "multiobj") == 0) + global.params.multiobj = 1; + else if (strcmp(p + 1, "g") == 0) + global.params.symdebug = 1; + else if (strcmp(p + 1, "gc") == 0) + global.params.symdebug = 2; + else if (strcmp(p + 1, "gs") == 0) + global.params.alwaysframe = 1; + else if (strcmp(p + 1, "gt") == 0) + { error(0, "use -profile instead of -gt\n"); + global.params.trace = 1; + } + else if (strcmp(p + 1, "m32") == 0) + global.params.is64bit = 0; + else if (strcmp(p + 1, "m64") == 0) + global.params.is64bit = 1; + else if (strcmp(p + 1, "profile") == 0) + global.params.trace = 1; + else if (strcmp(p + 1, "v") == 0) + global.params.verbose = 1; +#if DMDV2 + else if (strcmp(p + 1, "vtls") == 0) + global.params.vtls = 1; +#endif + else if (strcmp(p + 1, "v1") == 0) + { +#if DMDV1 + global.params.Dversion = 1; +#else + error(0, "use DMD 1.0 series compilers for -v1 switch"); + break; +#endif + } + else if (strcmp(p + 1, "w") == 0) + global.params.warnings = 1; + else if (strcmp(p + 1, "wi") == 0) + global.params.warnings = 2; + else if (strcmp(p + 1, "O") == 0) + global.params.optimize = 1; + else if (p[1] == 'o') + { + switch (p[2]) + { + case '-': + global.params.obj = 0; + break; + + case 'd': + if (!p[3]) + goto Lnoarg; + global.params.objdir = p + 3; + break; + + case 'f': + if (!p[3]) + goto Lnoarg; + global.params.objname = p + 3; + break; + + case 'p': + if (p[3]) + goto Lerror; + global.params.preservePaths = 1; + break; + + case 0: + error(0, "-o no longer supported, use -of or -od"); + break; + + default: + goto Lerror; + } + } + else if (p[1] == 'D') + { global.params.doDocComments = 1; + switch (p[2]) + { + case 'd': + if (!p[3]) + goto Lnoarg; + global.params.docdir = p + 3; + break; + case 'f': + if (!p[3]) + goto Lnoarg; + global.params.docname = p + 3; + break; + + case 0: + break; + + default: + goto Lerror; + } + } + else if (p[1] == 'H') + { global.params.doHdrGeneration = 1; + switch (p[2]) + { + case 'd': + if (!p[3]) + goto Lnoarg; + global.params.hdrdir = p + 3; + break; + + case 'f': + if (!p[3]) + goto Lnoarg; + global.params.hdrname = p + 3; + break; + + case 0: + break; + + default: + goto Lerror; + } + } + else if (p[1] == 'X') + { global.params.doXGeneration = 1; + switch (p[2]) + { + case 'f': + if (!p[3]) + goto Lnoarg; + global.params.xfilename = p + 3; + break; + + case 0: + break; + + default: + goto Lerror; + } + } + else if (strcmp(p + 1, "ignore") == 0) + global.params.ignoreUnsupportedPragmas = 1; + else if (strcmp(p + 1, "property") == 0) + global.params.enforcePropertySyntax = 1; + else if (strcmp(p + 1, "inline") == 0) + global.params.useInline = 1; + else if (strcmp(p + 1, "lib") == 0) + global.params.lib = 1; + else if (strcmp(p + 1, "nofloat") == 0) + global.params.nofloat = 1; + else if (strcmp(p + 1, "quiet") == 0) + global.params.quiet = 1; + else if (strcmp(p + 1, "release") == 0) + global.params.release = 1; +#if DMDV2 + else if (strcmp(p + 1, "noboundscheck") == 0) + noboundscheck = 1; +#endif + else if (strcmp(p + 1, "unittest") == 0) + global.params.useUnitTests = 1; + else if (p[1] == 'I') + { + if (!global.params.imppath) + global.params.imppath = new Strings(); + global.params.imppath->push(p + 2); + } + else if (p[1] == 'J') + { + if (!global.params.fileImppath) + global.params.fileImppath = new Strings(); + global.params.fileImppath->push(p + 2); + } + else if (memcmp(p + 1, "debug", 5) == 0 && p[6] != 'l') + { + // Parse: + // -debug + // -debug=number + // -debug=identifier + if (p[6] == '=') + { + if (isdigit((unsigned char)p[7])) + { long level; + + errno = 0; + level = strtol(p + 7, &p, 10); + if (*p || errno || level > INT_MAX) + goto Lerror; + DebugCondition::setGlobalLevel((int)level); + } + else if (Lexer::isValidIdentifier(p + 7)) + DebugCondition::addGlobalIdent(p + 7); + else + goto Lerror; + } + else if (p[6]) + goto Lerror; + else + global.params.debuglevel = 1; + } + else if (memcmp(p + 1, "version", 5) == 0) + { + // Parse: + // -version=number + // -version=identifier + if (p[8] == '=') + { + if (isdigit((unsigned char)p[9])) + { long level; + + errno = 0; + level = strtol(p + 9, &p, 10); + if (*p || errno || level > INT_MAX) + goto Lerror; + VersionCondition::setGlobalLevel((int)level); + } + else if (Lexer::isValidIdentifier(p + 9)) + VersionCondition::addGlobalIdent(p + 9); + else + goto Lerror; + } + else + goto Lerror; + } + else if (strcmp(p + 1, "-b") == 0) + global.params.debugb = 1; + else if (strcmp(p + 1, "-c") == 0) + global.params.debugc = 1; + else if (strcmp(p + 1, "-f") == 0) + global.params.debugf = 1; + else if (strcmp(p + 1, "-help") == 0) + { usage(); + exit(EXIT_SUCCESS); + } + else if (strcmp(p + 1, "-r") == 0) + global.params.debugr = 1; + else if (strcmp(p + 1, "-x") == 0) + global.params.debugx = 1; + else if (strcmp(p + 1, "-y") == 0) + global.params.debugy = 1; + else if (p[1] == 'L') + { + global.params.linkswitches->push(p + 2); + } + else if (memcmp(p + 1, "defaultlib=", 11) == 0) + { + global.params.defaultlibname = p + 1 + 11; + } + else if (memcmp(p + 1, "debuglib=", 9) == 0) + { + setdebuglib = 1; + global.params.debuglibname = p + 1 + 9; + } + else if (memcmp(p + 1, "deps=", 5) == 0) + { + global.params.moduleDepsFile = p + 1 + 5; + if (!global.params.moduleDepsFile[0]) + goto Lnoarg; + global.params.moduleDeps = new OutBuffer; + } + else if (memcmp(p + 1, "man", 3) == 0) + { +#if _WIN32 +#if DMDV1 + browse("http://www.digitalmars.com/d/1.0/dmd-windows.html"); +#else + browse("http://www.dlang.org/dmd-windows.html"); +#endif +#endif +#if linux +#if DMDV1 + browse("http://www.digitalmars.com/d/1.0/dmd-linux.html"); +#else + browse("http://www.dlang.org/dmd-linux.html"); +#endif +#endif +#if __APPLE__ +#if DMDV1 + browse("http://www.digitalmars.com/d/1.0/dmd-osx.html"); +#else + browse("http://www.dlang.org/dmd-osx.html"); +#endif +#endif +#if __FreeBSD__ +#if DMDV1 + browse("http://www.digitalmars.com/d/1.0/dmd-freebsd.html"); +#else + browse("http://www.dlang.org/dmd-freebsd.html"); +#endif +#endif +#if __OpenBSD__ +#if DMDV1 + browse("http://www.digitalmars.com/d/1.0/dmd-openbsd.html"); +#else + browse("http://www.dlang.org/dmd-openbsd.html"); +#endif +#endif + exit(EXIT_SUCCESS); + } + else if (strcmp(p + 1, "run") == 0) + { global.params.run = 1; + global.params.runargs_length = ((i >= argcstart) ? argc : argcstart) - i - 1; + if (global.params.runargs_length) + { + files.push(argv[i + 1]); + global.params.runargs = &argv[i + 2]; + i += global.params.runargs_length; + global.params.runargs_length--; + } + else + { global.params.run = 0; + goto Lnoarg; + } + } + else + { + Lerror: + error(0, "unrecognized switch '%s'", argv[i]); + continue; + + Lnoarg: + error(0, "argument expected for switch '%s'", argv[i]); + continue; + } + } + else + { +#if TARGET_WINDOS + char *ext = FileName::ext(p); + if (ext && FileName::compare(ext, "exe") == 0) + { + global.params.objname = p; + continue; + } +#endif + files.push(p); + } + } + if (global.errors) + { + fatal(); + } + if (files.dim == 0) + { usage(); + return EXIT_FAILURE; + } + + if (!setdebuglib) + global.params.debuglibname = global.params.defaultlibname; + +#if TARGET_OSX + global.params.pic = 1; +#endif + +#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS + if (global.params.lib && global.params.dll) + error(0, "cannot mix -lib and -shared\n"); +#endif + + if (global.params.release) + { global.params.useInvariants = 0; + global.params.useIn = 0; + global.params.useOut = 0; + global.params.useAssert = 0; + global.params.useArrayBounds = 1; + global.params.useSwitchError = 0; + } + if (noboundscheck) + global.params.useArrayBounds = 0; + + if (global.params.run) + global.params.quiet = 1; + + if (global.params.useUnitTests) + global.params.useAssert = 1; + + if (!global.params.obj || global.params.lib) + global.params.link = 0; + + if (global.params.link) + { + global.params.exefile = global.params.objname; + global.params.oneobj = 1; + if (global.params.objname) + { + /* Use this to name the one object file with the same + * name as the exe file. + */ + global.params.objname = FileName::forceExt(global.params.objname, global.obj_ext)->toChars(); + + /* If output directory is given, use that path rather than + * the exe file path. + */ + if (global.params.objdir) + { char *name = FileName::name(global.params.objname); + global.params.objname = FileName::combine(global.params.objdir, name); + } + } + } + else if (global.params.lib) + { + global.params.libname = global.params.objname; + global.params.objname = NULL; + + // Haven't investigated handling these options with multiobj + if (!global.params.cov && !global.params.trace +#if 0 && TARGET_WINDOS + /* multiobj causes class/struct debug info to be attached to init-data, + * but this will not be linked into the executable, so this info is lost. + * Bugzilla 4014 + */ + && !global.params.symdebug +#endif + ) + global.params.multiobj = 1; + } + else if (global.params.run) + { + error(0, "flags conflict with -run"); + fatal(); + } + else + { + if (global.params.objname && files.dim > 1) + { + global.params.oneobj = 1; + //error("multiple source files, but only one .obj name"); + //fatal(); + } + } + if (global.params.is64bit) + { + VersionCondition::addPredefinedGlobalIdent("D_InlineAsm_X86_64"); + VersionCondition::addPredefinedGlobalIdent("X86_64"); + VersionCondition::addPredefinedGlobalIdent("D_LP64"); + VersionCondition::addPredefinedGlobalIdent("D_SIMD"); +#if TARGET_WINDOS + VersionCondition::addPredefinedGlobalIdent("Win64"); +#endif + } + else + { + VersionCondition::addPredefinedGlobalIdent("D_InlineAsm"); + VersionCondition::addPredefinedGlobalIdent("D_InlineAsm_X86"); + VersionCondition::addPredefinedGlobalIdent("X86"); +#if TARGET_OSX + VersionCondition::addPredefinedGlobalIdent("D_SIMD"); +#endif +#if TARGET_WINDOS + VersionCondition::addPredefinedGlobalIdent("Win32"); +#endif + } + if (global.params.doDocComments) + VersionCondition::addPredefinedGlobalIdent("D_Ddoc"); + if (global.params.cov) + VersionCondition::addPredefinedGlobalIdent("D_Coverage"); + if (global.params.pic) + VersionCondition::addPredefinedGlobalIdent("D_PIC"); +#if DMDV2 + if (global.params.useUnitTests) + VersionCondition::addPredefinedGlobalIdent("unittest"); +#endif + + // Initialization + Type::init(); + Id::initialize(); + Module::init(); + initPrecedence(); + + if (global.params.verbose) + { printf("binary %s\n", argv[0]); + printf("version %s\n", global.version); + printf("config %s\n", inifilename ? inifilename : "(none)"); + } + + //printf("%d source files\n",files.dim); + + // Build import search path + if (global.params.imppath) + { + for (size_t i = 0; i < global.params.imppath->dim; i++) + { + char *path = (*global.params.imppath)[i]; + Strings *a = FileName::splitPath(path); + + if (a) + { + if (!global.path) + global.path = new Strings(); + global.path->append(a); + } + } + } + + // Build string import search path + if (global.params.fileImppath) + { + for (size_t i = 0; i < global.params.fileImppath->dim; i++) + { + char *path = global.params.fileImppath->tdata()[i]; + Strings *a = FileName::splitPath(path); + + if (a) + { + if (!global.filePath) + global.filePath = new Strings(); + global.filePath->append(a); + } + } + } + + // Create Modules + Modules modules; + modules.reserve(files.dim); + int firstmodule = 1; + for (size_t i = 0; i < files.dim; i++) + { + char *ext; + char *name; + + p = files.tdata()[i]; + +#if _WIN32 + // Convert / to \ so linker will work + for (size_t j = 0; p[j]; j++) + { + if (p[j] == '/') + p[j] = '\\'; + } +#endif + + p = FileName::name(p); // strip path + ext = FileName::ext(p); + if (ext) + { /* Deduce what to do with a file based on its extension + */ + if (FileName::equals(ext, global.obj_ext)) + { + global.params.objfiles->push(files.tdata()[i]); + libmodules.push(files.tdata()[i]); + continue; + } + + if (FileName::equals(ext, global.lib_ext)) + { + global.params.libfiles->push(files.tdata()[i]); + libmodules.push(files.tdata()[i]); + continue; + } + + if (strcmp(ext, global.ddoc_ext) == 0) + { + global.params.ddocfiles->push(files.tdata()[i]); + continue; + } + + if (FileName::equals(ext, global.json_ext)) + { + global.params.doXGeneration = 1; + global.params.xfilename = files.tdata()[i]; + continue; + } + + if (FileName::equals(ext, global.map_ext)) + { + global.params.mapfile = files.tdata()[i]; + continue; + } + +#if TARGET_WINDOS + if (FileName::equals(ext, "res")) + { + global.params.resfile = files.tdata()[i]; + continue; + } + + if (FileName::equals(ext, "def")) + { + global.params.deffile = files.tdata()[i]; + continue; + } + + if (FileName::equals(ext, "exe")) + { + assert(0); // should have already been handled + } +#endif + + /* Examine extension to see if it is a valid + * D source file extension + */ + if (FileName::equals(ext, global.mars_ext) || + FileName::equals(ext, global.hdr_ext) || + FileName::equals(ext, "dd") || + FileName::equals(ext, "htm") || + FileName::equals(ext, "html") || + FileName::equals(ext, "xhtml")) + { + ext--; // skip onto '.' + assert(*ext == '.'); + name = (char *)mem.malloc((ext - p) + 1); + memcpy(name, p, ext - p); + name[ext - p] = 0; // strip extension + + if (name[0] == 0 || + strcmp(name, "..") == 0 || + strcmp(name, ".") == 0) + { + Linvalid: + error(0, "invalid file name '%s'", files.tdata()[i]); + fatal(); + } + } + else + { error(0, "unrecognized file extension %s\n", ext); + fatal(); + } + } + else + { name = p; + if (!*name) + goto Linvalid; + } + + /* At this point, name is the D source file name stripped of + * its path and extension. + */ + + Identifier *id = Lexer::idPool(name); + m = new Module(files[i], id, global.params.doDocComments, global.params.doHdrGeneration); + modules.push(m); + + if (firstmodule) + { global.params.objfiles->push(m->objfile->name->str); + firstmodule = 0; + } + } + + // Read files +#define ASYNCREAD 1 +#if ASYNCREAD + // Multi threaded + AsyncRead *aw = AsyncRead::create(modules.dim); + for (size_t i = 0; i < modules.dim; i++) + { + m = modules[i]; + aw->addFile(m->srcfile); + } + aw->start(); +#else + // Single threaded + for (size_t i = 0; i < modules.dim; i++) + { + m = modules[i]; + m->read(0); + } +#endif + + // Parse files + bool anydocfiles = false; + size_t filecount = modules.dim; + for (size_t filei = 0, modi = 0; filei < filecount; filei++, modi++) + { + m = modules[modi]; + if (global.params.verbose) + printf("parse %s\n", m->toChars()); + if (!Module::rootModule) + Module::rootModule = m; + m->importedFrom = m; + if (!global.params.oneobj || modi == 0 || m->isDocFile) + m->deleteObjFile(); +#if ASYNCREAD + if (aw->read(filei)) + { + error(0, "cannot read file %s", m->srcfile->name->toChars()); + fatal(); + } +#endif + m->parse(); + if (m->isDocFile) + { + anydocfiles = true; + m->gendocfile(); + + // Remove m from list of modules + modules.remove(modi); + modi--; + + // Remove m's object file from list of object files + for (size_t j = 0; j < global.params.objfiles->dim; j++) + { + if (m->objfile->name->str == global.params.objfiles->tdata()[j]) + { + global.params.objfiles->remove(j); + break; + } + } + + if (global.params.objfiles->dim == 0) + global.params.link = 0; + } + } +#if ASYNCREAD + AsyncRead::dispose(aw); +#endif + + if (anydocfiles && modules.dim && + (global.params.oneobj || global.params.objname)) + { + error(0, "conflicting Ddoc and obj generation options"); + fatal(); + } + if (global.errors) + fatal(); + if (global.params.doHdrGeneration) + { + /* Generate 'header' import files. + * Since 'header' import files must be independent of command + * line switches and what else is imported, they are generated + * before any semantic analysis. + */ + for (size_t i = 0; i < modules.dim; i++) + { + m = modules[i]; + if (global.params.verbose) + printf("import %s\n", m->toChars()); + m->genhdrfile(); + } + } + if (global.errors) + fatal(); + + // load all unconditional imports for better symbol resolving + for (size_t i = 0; i < modules.dim; i++) + { + m = modules[i]; + if (global.params.verbose) + printf("importall %s\n", m->toChars()); + m->importAll(0); + } + if (global.errors) + fatal(); + + backend_init(); + + // Do semantic analysis + for (size_t i = 0; i < modules.dim; i++) + { + m = modules[i]; + if (global.params.verbose) + printf("semantic %s\n", m->toChars()); + m->semantic(); + } + if (global.errors) + fatal(); + + Module::dprogress = 1; + Module::runDeferredSemantic(); + + // Do pass 2 semantic analysis + for (size_t i = 0; i < modules.dim; i++) + { + m = modules[i]; + if (global.params.verbose) + printf("semantic2 %s\n", m->toChars()); + m->semantic2(); + } + if (global.errors) + fatal(); + + // Do pass 3 semantic analysis + for (size_t i = 0; i < modules.dim; i++) + { + m = modules[i]; + if (global.params.verbose) + printf("semantic3 %s\n", m->toChars()); + m->semantic3(); + } + if (global.errors) + fatal(); + + if (global.params.moduleDeps != NULL) + { + assert(global.params.moduleDepsFile != NULL); + + File deps(global.params.moduleDepsFile); + OutBuffer* ob = global.params.moduleDeps; + deps.setbuffer((void*)ob->data, ob->offset); + deps.writev(); + } + + + // Scan for functions to inline + if (global.params.useInline) + { + /* The problem with useArrayBounds and useAssert is that the + * module being linked to may not have generated them, so if + * we inline functions from those modules, the symbols for them will + * not be found at link time. + */ + if (!global.params.useArrayBounds && !global.params.useAssert) + { + // Do pass 3 semantic analysis on all imported modules, + // since otherwise functions in them cannot be inlined + for (size_t i = 0; i < Module::amodules.dim; i++) + { + m = Module::amodules[i]; + if (global.params.verbose) + printf("semantic3 %s\n", m->toChars()); + m->semantic3(); + } + if (global.errors) + fatal(); + } + + for (size_t i = 0; i < modules.dim; i++) + { + m = modules[i]; + if (global.params.verbose) + printf("inline scan %s\n", m->toChars()); + m->inlineScan(); + } + } + + // Do not attempt to generate output files if errors or warnings occurred + if (global.errors || global.warnings) + fatal(); + + printCtfePerformanceStats(); + + Library *library = NULL; + if (global.params.lib) + { + library = new Library(); + library->setFilename(global.params.objdir, global.params.libname); + + // Add input object and input library files to output library + for (size_t i = 0; i < libmodules.dim; i++) + { + char *p = libmodules[i]; + library->addObject(p, NULL, 0); + } + } + + // Generate output files + + if (global.params.doXGeneration) + json_generate(&modules); + + if (global.params.oneobj) + { + for (size_t i = 0; i < modules.dim; i++) + { + m = modules[i]; + if (global.params.verbose) + printf("code %s\n", m->toChars()); + if (i == 0) + obj_start(m->srcfile->toChars()); + m->genobjfile(0); + if (!global.errors && global.params.doDocComments) + m->gendocfile(); + } + if (!global.errors && modules.dim) + { + obj_end(library, modules.tdata()[0]->objfile); + } + } + else + { + for (size_t i = 0; i < modules.dim; i++) + { + m = modules[i]; + if (global.params.verbose) + printf("code %s\n", m->toChars()); + if (global.params.obj) + { obj_start(m->srcfile->toChars()); + m->genobjfile(global.params.multiobj); + obj_end(library, m->objfile); + obj_write_deferred(library); + } + if (global.errors) + { + if (!global.params.lib) + m->deleteObjFile(); + } + else + { + if (global.params.doDocComments) + m->gendocfile(); + } + } + } + + if (global.params.lib && !global.errors) + library->write(); + + backend_term(); + if (global.errors) + fatal(); + + if (!global.params.objfiles->dim) + { + if (global.params.link) + error(0, "no object files to link"); + } + else + { + if (global.params.link) + status = runLINK(); + + if (global.params.run) + { + if (!status) + { + status = runProgram(); + + /* Delete .obj files and .exe file + */ + for (size_t i = 0; i < modules.dim; i++) + { + Module *m = modules[i]; + m->deleteObjFile(); + if (global.params.oneobj) + break; + } + deleteExeFile(); + } + } + } + + return status; +} + +int main(int argc, char *argv[]) +{ + int status = -1; +#if WINDOWS_SEH + __try + { +#endif + status = tryMain(argc, argv); +#if WINDOWS_SEH + } + __except (__ehfilter(GetExceptionInformation())) + { + printf("Stack overflow\n"); + fatal(); + } +#endif + return status; +} + +#endif // !IN_LLVM + +/*********************************** + * Parse and append contents of environment variable envvar + * to argc and argv[]. + * The string is separated into arguments, processing \ and ". + */ + +void getenv_setargv(const char *envvar, int *pargc, char** *pargv) +{ + char *p; + + int instring; + int slash; + char c; + + char *env = getenv(envvar); + if (!env) + return; + + env = mem.strdup(env); // create our own writable copy + + int argc = *pargc; + Strings *argv = new Strings(); + argv->setDim(argc); + + int argc_left = 0; + for (int i = 0; i < argc; i++) { + if (!strcmp((*pargv)[i], "-run") || !strcmp((*pargv)[i], "--run")) { + // HACK: set flag to indicate we saw '-run' here + global.params.run = true; + // Don't eat -run yet so the program arguments don't get changed + argc_left = argc - i; + argc = i; + *pargv = &(*pargv)[i]; + argv->setDim(i); + break; + } else { + } + } + // HACK to stop required values from command line being drawn from DFLAGS + argv->push((char*)""); + argc++; + + size_t j = 1; // leave argv[0] alone + while (1) + { + int wildcard = 1; // do wildcard expansion + switch (*env) + { + case ' ': + case '\t': + env++; + break; + + case 0: + goto Ldone; + + case '"': + wildcard = 0; + default: + argv->push(env); // append + //argv->insert(j, env); // insert at position j + j++; + argc++; + p = env; + slash = 0; + instring = 0; + c = 0; + + while (1) + { + c = *env++; + switch (c) + { + case '"': + p -= (slash >> 1); + if (slash & 1) + { p--; + goto Laddc; + } + instring ^= 1; + slash = 0; + continue; + + case ' ': + case '\t': + if (instring) + goto Laddc; + *p = 0; + //if (wildcard) + //wildcardexpand(); // not implemented + break; + + case '\\': + slash++; + *p++ = c; + continue; + + case 0: + *p = 0; + //if (wildcard) + //wildcardexpand(); // not implemented + goto Ldone; + + default: + Laddc: + slash = 0; + *p++ = c; + continue; + } + break; + } + } + } + +Ldone: + assert(argc == argv->dim); + argv->reserve(argc_left); + for (int i = 0; i < argc_left; i++) + argv->data[argc++] = (void *)(*pargv)[i]; + + *pargc = argc; + *pargv = argv->tdata(); +} + +#if WINDOWS_SEH + +long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep) +{ + //printf("%x\n", ep->ExceptionRecord->ExceptionCode); + if (ep->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW) + { +#if 1 //ndef DEBUG + return EXCEPTION_EXECUTE_HANDLER; +#endif + } + return EXCEPTION_CONTINUE_SEARCH; +} + +#endif diff --git a/dmd2/readme.txt b/dmd2/readme.txt index 5f2f1516..e8109070 100644 --- a/dmd2/readme.txt +++ b/dmd2/readme.txt @@ -1,24 +1,24 @@ - - The D Programming Language - Compiler Front End Source - Copyright (c) 1999-2009, by Digital Mars - http://www.digitalmars.com - All Rights Reserved - - -This is the source code to the front end Digital Mars D compiler. -It covers the lexical analysis, parsing, and semantic analysis -of the D Programming Language defined in the documents at -http://www.digitalmars.com/d/ - -These sources are free, they are redistributable and modifiable -under the terms of the GNU General Public License (attached as gpl.txt), -or the Artistic License (attached as artistic.txt). - -The optimizer and code generator sources are -covered under a separate license, backendlicense.txt. - -It does not apply to anything else distributed by Digital Mars, -including D compiler executables. - --Walter Bright + + The D Programming Language + Compiler Front End Source + Copyright (c) 1999-2009, by Digital Mars + http://www.digitalmars.com + All Rights Reserved + + +This is the source code to the front end Digital Mars D compiler. +It covers the lexical analysis, parsing, and semantic analysis +of the D Programming Language defined in the documents at +http://www.digitalmars.com/d/ + +These sources are free, they are redistributable and modifiable +under the terms of the GNU General Public License (attached as gpl.txt), +or the Artistic License (attached as artistic.txt). + +The optimizer and code generator sources are +covered under a separate license, backendlicense.txt. + +It does not apply to anything else distributed by Digital Mars, +including D compiler executables. + +-Walter Bright diff --git a/dmd2/template.c b/dmd2/template.c index 6bf52076..2f8ce392 100644 --- a/dmd2/template.c +++ b/dmd2/template.c @@ -1,6441 +1,6441 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -// Handle template implementation - -#include -#include - -#include "root.h" -#include "aav.h" -#include "rmem.h" -#include "stringtable.h" -#include "mars.h" -#include "identifier.h" -#include "mtype.h" -#include "template.h" -#include "init.h" -#include "expression.h" -#include "scope.h" -#include "module.h" -#include "aggregate.h" -#include "declaration.h" -#include "dsymbol.h" -#include "hdrgen.h" -#include "id.h" - -#if WINDOWS_SEH -#include -long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep); -#endif - -#define LOG 0 - -/******************************************** - * These functions substitute for dynamic_cast. dynamic_cast does not work - * on earlier versions of gcc. - */ - -Expression *isExpression(Object *o) -{ - //return dynamic_cast(o); - if (!o || o->dyncast() != DYNCAST_EXPRESSION) - return NULL; - return (Expression *)o; -} - -Dsymbol *isDsymbol(Object *o) -{ - //return dynamic_cast(o); - if (!o || o->dyncast() != DYNCAST_DSYMBOL) - return NULL; - return (Dsymbol *)o; -} - -Type *isType(Object *o) -{ - //return dynamic_cast(o); - if (!o || o->dyncast() != DYNCAST_TYPE) - return NULL; - return (Type *)o; -} - -Tuple *isTuple(Object *o) -{ - //return dynamic_cast(o); - if (!o || o->dyncast() != DYNCAST_TUPLE) - return NULL; - return (Tuple *)o; -} - -/************************************** - * Is this Object an error? - */ -int isError(Object *o) -{ - Type *t = isType(o); - if (t) - return (t->ty == Terror); - Expression *e = isExpression(o); - if (e) - return (e->op == TOKerror); - Tuple *v = isTuple(o); - if (v) - return arrayObjectIsError(&v->objects); - return 0; -} - -/************************************** - * Are any of the Objects an error? - */ -int arrayObjectIsError(Objects *args) -{ - for (size_t i = 0; i < args->dim; i++) - { - Object *o = args->tdata()[i]; - if (isError(o)) - return 1; - } - return 0; -} - -/*********************** - * Try to get arg as a type. - */ - -Type *getType(Object *o) -{ - Type *t = isType(o); - if (!t) - { Expression *e = isExpression(o); - if (e) - t = e->type; - } - return t; -} - -Dsymbol *getDsymbol(Object *oarg) -{ - Dsymbol *sa; - Expression *ea = isExpression(oarg); - if (ea) - { // Try to convert Expression to symbol - if (ea->op == TOKvar) - sa = ((VarExp *)ea)->var; - else if (ea->op == TOKfunction) - sa = ((FuncExp *)ea)->fd; - else - sa = NULL; - } - else - { // Try to convert Type to symbol - Type *ta = isType(oarg); - if (ta) - sa = ta->toDsymbol(NULL); - else - sa = isDsymbol(oarg); // if already a symbol - } - return sa; -} - -/****************************** - * If o1 matches o2, return 1. - * Else, return 0. - */ - -int match(Object *o1, Object *o2, TemplateDeclaration *tempdecl, Scope *sc) -{ - Type *t1 = isType(o1); - Type *t2 = isType(o2); - Expression *e1 = isExpression(o1); - Expression *e2 = isExpression(o2); - Dsymbol *s1 = isDsymbol(o1); - Dsymbol *s2 = isDsymbol(o2); - Tuple *u1 = isTuple(o1); - Tuple *u2 = isTuple(o2); - - //printf("\t match t1 %p t2 %p, e1 %p e2 %p, s1 %p s2 %p, u1 %p u2 %p\n", t1,t2,e1,e2,s1,s2,u1,u2); - - /* A proper implementation of the various equals() overrides - * should make it possible to just do o1->equals(o2), but - * we'll do that another day. - */ - - if (s1) - { - VarDeclaration *v1 = s1->isVarDeclaration(); - if (v1 && v1->storage_class & STCmanifest) - { ExpInitializer *ei1 = v1->init->isExpInitializer(); - if (ei1) - e1 = ei1->exp, s1 = NULL; - } - } - if (s2) - { - VarDeclaration *v2 = s2->isVarDeclaration(); - if (v2 && v2->storage_class & STCmanifest) - { ExpInitializer *ei2 = v2->init->isExpInitializer(); - if (ei2) - e2 = ei2->exp, s2 = NULL; - } - } - - if (t1) - { - /* if t1 is an instance of ti, then give error - * about recursive expansions. - */ - Dsymbol *s = t1->toDsymbol(sc); - if (s && s->parent) - { TemplateInstance *ti1 = s->parent->isTemplateInstance(); - if (ti1 && ti1->tempdecl == tempdecl) - { - for (Scope *sc1 = sc; sc1; sc1 = sc1->enclosing) - { - if (sc1->scopesym == ti1) - { - tempdecl->error("recursive template expansion for template argument %s", t1->toChars()); - return 1; // fake a match - } - } - } - } - - //printf("t1 = %s\n", t1->toChars()); - //printf("t2 = %s\n", t2->toChars()); - if (!t2 || !t1->equals(t2)) - goto Lnomatch; - } - else if (e1) - { -#if 0 - if (e1 && e2) - { - printf("match %d\n", e1->equals(e2)); - e1->print(); - e2->print(); - e1->type->print(); - e2->type->print(); - } -#endif - if (!e2) - goto Lnomatch; - if (!e1->equals(e2)) - goto Lnomatch; - } - else if (s1) - { - if (!s2 || !s1->equals(s2) || s1->parent != s2->parent) - goto Lnomatch; - } - else if (u1) - { - if (!u2) - goto Lnomatch; - if (u1->objects.dim != u2->objects.dim) - goto Lnomatch; - for (size_t i = 0; i < u1->objects.dim; i++) - { - if (!match(u1->objects.tdata()[i], - u2->objects.tdata()[i], - tempdecl, sc)) - goto Lnomatch; - } - } - //printf("match\n"); - return 1; // match - -Lnomatch: - //printf("nomatch\n"); - return 0; // nomatch; -} - - -/************************************ - * Match an array of them. - */ -int arrayObjectMatch(Objects *oa1, Objects *oa2, TemplateDeclaration *tempdecl, Scope *sc) -{ - if (oa1 == oa2) - return 1; - if (oa1->dim != oa2->dim) - return 0; - for (size_t j = 0; j < oa1->dim; j++) - { Object *o1 = oa1->tdata()[j]; - Object *o2 = oa2->tdata()[j]; - if (!match(o1, o2, tempdecl, sc)) - { - return 0; - } - } - return 1; -} - -/**************************************** - * This makes a 'pretty' version of the template arguments. - * It's analogous to genIdent() which makes a mangled version. - */ - -void ObjectToCBuffer(OutBuffer *buf, HdrGenState *hgs, Object *oarg) -{ - //printf("ObjectToCBuffer()\n"); - Type *t = isType(oarg); - Expression *e = isExpression(oarg); - Dsymbol *s = isDsymbol(oarg); - Tuple *v = isTuple(oarg); - /* The logic of this should match what genIdent() does. The _dynamic_cast() - * function relies on all the pretty strings to be unique for different classes - * (see Bugzilla 7375). - * Perhaps it would be better to demangle what genIdent() does. - */ - if (t) - { //printf("\tt: %s ty = %d\n", t->toChars(), t->ty); - t->toCBuffer(buf, NULL, hgs); - } - else if (e) - { - if (e->op == TOKvar) - e = e->optimize(WANTvalue); // added to fix Bugzilla 7375 - e->toCBuffer(buf, hgs); - } - else if (s) - { - char *p = s->ident ? s->ident->toChars() : s->toChars(); - buf->writestring(p); - } - else if (v) - { - Objects *args = &v->objects; - for (size_t i = 0; i < args->dim; i++) - { - if (i) - buf->writeByte(','); - Object *o = (*args)[i]; - ObjectToCBuffer(buf, hgs, o); - } - } - else if (!oarg) - { - buf->writestring("NULL"); - } - else - { -#ifdef DEBUG - printf("bad Object = %p\n", oarg); -#endif - assert(0); - } -} - -#if DMDV2 -Object *objectSyntaxCopy(Object *o) -{ - if (!o) - return NULL; - Type *t = isType(o); - if (t) - return t->syntaxCopy(); - Expression *e = isExpression(o); - if (e) - return e->syntaxCopy(); - return o; -} -#endif - - -/* ======================== TemplateDeclaration ============================= */ - -TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id, - TemplateParameters *parameters, Expression *constraint, Dsymbols *decldefs, int ismixin) - : ScopeDsymbol(id) -{ -#if LOG - printf("TemplateDeclaration(this = %p, id = '%s')\n", this, id->toChars()); -#endif -#if 0 - if (parameters) - for (int i = 0; i < parameters->dim; i++) - { TemplateParameter *tp = parameters->tdata()[i]; - //printf("\tparameter[%d] = %p\n", i, tp); - TemplateTypeParameter *ttp = tp->isTemplateTypeParameter(); - - if (ttp) - { - printf("\tparameter[%d] = %s : %s\n", i, tp->ident->toChars(), ttp->specType ? ttp->specType->toChars() : ""); - } - } -#endif - this->loc = loc; - this->parameters = parameters; - this->origParameters = parameters; - this->constraint = constraint; - this->members = decldefs; - this->overnext = NULL; - this->overroot = NULL; - this->semanticRun = PASSinit; - this->onemember = NULL; - this->literal = 0; - this->ismixin = ismixin; - this->previous = NULL; - - // Compute in advance for Ddoc's use - if (members) - { - Dsymbol *s; - if (Dsymbol::oneMembers(members, &s, ident) && s) - { - onemember = s; - s->parent = this; - } - } -} - -Dsymbol *TemplateDeclaration::syntaxCopy(Dsymbol *) -{ - //printf("TemplateDeclaration::syntaxCopy()\n"); - TemplateDeclaration *td; - TemplateParameters *p; - - p = NULL; - if (parameters) - { - p = new TemplateParameters(); - p->setDim(parameters->dim); - for (size_t i = 0; i < p->dim; i++) - { TemplateParameter *tp = (*parameters)[i]; - p->tdata()[i] = tp->syntaxCopy(); - } - } - Expression *e = NULL; - if (constraint) - e = constraint->syntaxCopy(); - Dsymbols *d = Dsymbol::arraySyntaxCopy(members); - td = new TemplateDeclaration(loc, ident, p, e, d, ismixin); - -#if IN_LLVM - td->intrinsicName = intrinsicName; -#endif - - return td; -} - -void TemplateDeclaration::semantic(Scope *sc) -{ -#if LOG - printf("TemplateDeclaration::semantic(this = %p, id = '%s')\n", this, ident->toChars()); - printf("sc->stc = %llx\n", sc->stc); - printf("sc->module = %s\n", sc->module->toChars()); -#endif - if (semanticRun) - return; // semantic() already run - semanticRun = PASSsemantic; - - if (sc->module && sc->module->ident == Id::object && ident == Id::AssociativeArray) - { Type::associativearray = this; - } - - if (sc->func) - { -#if DMDV1 - error("cannot declare template at function scope %s", sc->func->toChars()); -#endif - } - - if (/*global.params.useArrayBounds &&*/ sc->module) - { - // Generate this function as it may be used - // when template is instantiated in other modules - // FIXME: LDC - //sc->module->toModuleArray(); - } - - if (/*global.params.useAssert &&*/ sc->module) - { - // Generate this function as it may be used - // when template is instantiated in other modules - // FIXME: LDC - //sc->module->toModuleAssert(); - } - -#if DMDV2 - if (/*global.params.useUnitTests &&*/ sc->module) - { - // Generate this function as it may be used - // when template is instantiated in other modules - // FIXME: LDC - // sc->module->toModuleUnittest(); - } -#endif - - /* Remember Scope for later instantiations, but make - * a copy since attributes can change. - */ - if (!this->scope) - { this->scope = new Scope(*sc); - this->scope->setNoFree(); - } - - // Set up scope for parameters - ScopeDsymbol *paramsym = new ScopeDsymbol(); - paramsym->parent = sc->parent; - Scope *paramscope = sc->push(paramsym); - paramscope->parameterSpecialization = 1; - paramscope->stc = 0; - - if (!parent) - parent = sc->parent; - - if (global.params.doDocComments) - { - origParameters = new TemplateParameters(); - origParameters->setDim(parameters->dim); - for (size_t i = 0; i < parameters->dim; i++) - { - TemplateParameter *tp = (*parameters)[i]; - origParameters->tdata()[i] = tp->syntaxCopy(); - } - } - - for (size_t i = 0; i < parameters->dim; i++) - { - TemplateParameter *tp = parameters->tdata()[i]; - - tp->declareParameter(paramscope); - } - - for (size_t i = 0; i < parameters->dim; i++) - { - TemplateParameter *tp = (*parameters)[i]; - - tp->semantic(paramscope); - if (i + 1 != parameters->dim && tp->isTemplateTupleParameter()) - { error("template tuple parameter must be last one"); - errors = true; - } - } - - paramscope->pop(); - - // Compute again - onemember = NULL; - if (members) - { - Dsymbol *s; - if (Dsymbol::oneMembers(members, &s, ident) && s) - { - onemember = s; - s->parent = this; - } - } - - /* BUG: should check: - * o no virtual functions or non-static data members of classes - */ -} - -const char *TemplateDeclaration::kind() -{ - return (onemember && onemember->isAggregateDeclaration()) - ? onemember->kind() - : (char *)"template"; -} - -/********************************** - * Overload existing TemplateDeclaration 'this' with the new one 's'. - * Return !=0 if successful; i.e. no conflict. - */ - -int TemplateDeclaration::overloadInsert(Dsymbol *s) -{ - TemplateDeclaration **pf; - TemplateDeclaration *f; - -#if LOG - printf("TemplateDeclaration::overloadInsert('%s')\n", s->toChars()); -#endif - f = s->isTemplateDeclaration(); - if (!f) - return FALSE; - TemplateDeclaration *pthis = this; - for (pf = &pthis; *pf; pf = &(*pf)->overnext) - { -#if 0 - // Conflict if TemplateParameter's match - // Will get caught anyway later with TemplateInstance, but - // should check it now. - TemplateDeclaration *f2 = *pf; - - if (f->parameters->dim != f2->parameters->dim) - goto Lcontinue; - - for (size_t i = 0; i < f->parameters->dim; i++) - { TemplateParameter *p1 = f->parameters->tdata()[i]; - TemplateParameter *p2 = f2->parameters->tdata()[i]; - - if (!p1->overloadMatch(p2)) - goto Lcontinue; - } - -#if LOG - printf("\tfalse: conflict\n"); -#endif - return FALSE; - - Lcontinue: - ; -#endif - } - - f->overroot = this; - *pf = f; -#if LOG - printf("\ttrue: no conflict\n"); -#endif - return TRUE; -} - -/**************************** - * Declare all the function parameters as variables - * and add them to the scope - */ -void TemplateDeclaration::makeParamNamesVisibleInConstraint(Scope *paramscope, Expressions *fargs) -{ - /* We do this ONLY if there is only one function in the template. - */ - FuncDeclaration *fd = onemember && onemember->toAlias() ? - onemember->toAlias()->isFuncDeclaration() : NULL; - if (fd) - { - /* - Making parameters is similar to FuncDeclaration::semantic3 - */ - paramscope->parent = fd; - - TypeFunction *tf = (TypeFunction *)fd->type->syntaxCopy(); - - // Shouldn't run semantic on default arguments and return type. - for (int i = 0; iparameters->dim; i++) - tf->parameters->tdata()[i]->defaultArg = NULL; - tf->next = NULL; - - // Resolve parameter types and 'auto ref's. - tf->fargs = fargs; - tf = (TypeFunction *)tf->semantic(loc, paramscope); - - Parameters *fparameters = tf->parameters; - int fvarargs = tf->varargs; - - size_t nfparams = Parameter::dim(fparameters); // Num function parameters - for (size_t i = 0; i < nfparams; i++) - { - Parameter *fparam = Parameter::getNth(fparameters, i); - // Remove addMod same as func.d L1065 of FuncDeclaration::semantic3 - //Type *vtype = fparam->type; - //if (fd->type && fd->isPure()) - // vtype = vtype->addMod(MODconst); - fparam->storageClass &= (STCin | STCout | STCref | STClazy | STCfinal | STC_TYPECTOR | STCnodtor); - fparam->storageClass |= STCparameter; - if (fvarargs == 2 && i + 1 == nfparams) - fparam->storageClass |= STCvariadic; - } - for (size_t i = 0; i < fparameters->dim; i++) - { - Parameter *fparam = fparameters->tdata()[i]; - if (!fparam->ident) - continue; // don't add it, if it has no name - VarDeclaration *v = new VarDeclaration(loc, fparam->type, fparam->ident, NULL); - v->storage_class = fparam->storageClass; - v->semantic(paramscope); - if (!paramscope->insert(v)) - error("parameter %s.%s is already defined", toChars(), v->toChars()); - else - v->parent = this; - } - } -} - -/*************************************** - * Given that ti is an instance of this TemplateDeclaration, - * deduce the types of the parameters to this, and store - * those deduced types in dedtypes[]. - * Input: - * flag 1: don't do semantic() because of dummy types - * 2: don't change types in matchArg() - * Output: - * dedtypes deduced arguments - * Return match level. - */ - -MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, - Objects *dedtypes, Expressions *fargs, int flag) -{ MATCH m; - size_t dedtypes_dim = dedtypes->dim; - -#define LOGM 0 -#if LOGM - printf("\n+TemplateDeclaration::matchWithInstance(this = %s, ti = %s, flag = %d)\n", toChars(), ti->toChars(), flag); -#endif - -#if 0 - printf("dedtypes->dim = %d, parameters->dim = %d\n", dedtypes_dim, parameters->dim); - if (ti->tiargs->dim) - printf("ti->tiargs->dim = %d, [0] = %p\n", - ti->tiargs->dim, - ti->tiargs->tdata()[0]); -#endif - dedtypes->zero(); - - if (errors) - return MATCHnomatch; - - size_t parameters_dim = parameters->dim; - int variadic = isVariadic() != NULL; - - // If more arguments than parameters, no match - if (ti->tiargs->dim > parameters_dim && !variadic) - { -#if LOGM - printf(" no match: more arguments than parameters\n"); -#endif - return MATCHnomatch; - } - - assert(dedtypes_dim == parameters_dim); - assert(dedtypes_dim >= ti->tiargs->dim || variadic); - - // Set up scope for parameters - assert((size_t)scope > 0x10000); - ScopeDsymbol *paramsym = new ScopeDsymbol(); - paramsym->parent = scope->parent; - Scope *paramscope = scope->push(paramsym); - paramscope->stc = 0; - - // Attempt type deduction - m = MATCHexact; - for (size_t i = 0; i < dedtypes_dim; i++) - { MATCH m2; - TemplateParameter *tp = parameters->tdata()[i]; - Declaration *sparam; - - //printf("\targument [%d]\n", i); -#if LOGM - //printf("\targument [%d] is %s\n", i, oarg ? oarg->toChars() : "null"); - TemplateTypeParameter *ttp = tp->isTemplateTypeParameter(); - if (ttp) - printf("\tparameter[%d] is %s : %s\n", i, tp->ident->toChars(), ttp->specType ? ttp->specType->toChars() : ""); -#endif - - m2 = tp->matchArg(paramscope, ti->tiargs, i, parameters, dedtypes, &sparam); - //printf("\tm2 = %d\n", m2); - - if (m2 == MATCHnomatch) - { -#if 0 - printf("\tmatchArg() for parameter %i failed\n", i); -#endif - goto Lnomatch; - } - - if (m2 < m) - m = m2; - - if (!flag) - sparam->semantic(paramscope); - if (!paramscope->insert(sparam)) - goto Lnomatch; - } - - if (!flag) - { - /* Any parameter left without a type gets the type of - * its corresponding arg - */ - for (size_t i = 0; i < dedtypes_dim; i++) - { - if (!dedtypes->tdata()[i]) - { assert(i < ti->tiargs->dim); - dedtypes->tdata()[i] = (Type *)ti->tiargs->tdata()[i]; - } - } - } - -#if DMDV2 - if (m && constraint && !flag) - { /* Check to see if constraint is satisfied. - */ - makeParamNamesVisibleInConstraint(paramscope, fargs); - Expression *e = constraint->syntaxCopy(); - Scope *sc = paramscope->push(); - - /* There's a chicken-and-egg problem here. We don't know yet if this template - * instantiation will be a local one (isnested is set), and we won't know until - * after selecting the correct template. Thus, function we're nesting inside - * is not on the sc scope chain, and this can cause errors in FuncDeclaration::getLevel(). - * Workaround the problem by setting a flag to relax the checking on frame errors. - */ - sc->flags |= SCOPEstaticif; - - FuncDeclaration *fd = onemember && onemember->toAlias() ? - onemember->toAlias()->isFuncDeclaration() : NULL; - Dsymbol *s = parent; - while (s->isTemplateInstance() || s->isTemplateMixin()) - s = s->parent; - AggregateDeclaration *ad = s->isAggregateDeclaration(); - VarDeclaration *vthissave; - if (fd && ad) - { - vthissave = fd->vthis; - fd->vthis = fd->declareThis(paramscope, ad); - } - - e = e->semantic(sc); - - if (fd && fd->vthis) - fd->vthis = vthissave; - - sc->pop(); - e = e->optimize(WANTvalue | WANTinterpret); - if (e->isBool(TRUE)) - ; - else if (e->isBool(FALSE)) - goto Lnomatch; - else - { - e->error("constraint %s is not constant or does not evaluate to a bool", e->toChars()); - } - } -#endif - -#if LOGM - // Print out the results - printf("--------------------------\n"); - printf("template %s\n", toChars()); - printf("instance %s\n", ti->toChars()); - if (m) - { - for (size_t i = 0; i < dedtypes_dim; i++) - { - TemplateParameter *tp = parameters->tdata()[i]; - Object *oarg; - - printf(" [%d]", i); - - if (i < ti->tiargs->dim) - oarg = ti->tiargs->tdata()[i]; - else - oarg = NULL; - tp->print(oarg, dedtypes->tdata()[i]); - } - } - else - goto Lnomatch; -#endif - -#if LOGM - printf(" match = %d\n", m); -#endif - goto Lret; - -Lnomatch: -#if LOGM - printf(" no match\n"); -#endif - m = MATCHnomatch; - -Lret: - paramscope->pop(); -#if LOGM - printf("-TemplateDeclaration::matchWithInstance(this = %p, ti = %p) = %d\n", this, ti, m); -#endif - return m; -} - -/******************************************** - * Determine partial specialization order of 'this' vs td2. - * Returns: - * match this is at least as specialized as td2 - * 0 td2 is more specialized than this - */ - -MATCH TemplateDeclaration::leastAsSpecialized(TemplateDeclaration *td2, Expressions *fargs) -{ - /* This works by taking the template parameters to this template - * declaration and feeding them to td2 as if it were a template - * instance. - * If it works, then this template is at least as specialized - * as td2. - */ - - TemplateInstance ti(0, ident); // create dummy template instance - Objects dedtypes; - -#define LOG_LEASTAS 0 - -#if LOG_LEASTAS - printf("%s.leastAsSpecialized(%s)\n", toChars(), td2->toChars()); -#endif - - // Set type arguments to dummy template instance to be types - // generated from the parameters to this template declaration - ti.tiargs = new Objects(); - ti.tiargs->setDim(parameters->dim); - for (size_t i = 0; i < ti.tiargs->dim; i++) - { - TemplateParameter *tp = parameters->tdata()[i]; - - Object *p = (Object *)tp->dummyArg(); - if (p) - ti.tiargs->tdata()[i] = p; - else - ti.tiargs->setDim(i); - } - - // Temporary Array to hold deduced types - //dedtypes.setDim(parameters->dim); - dedtypes.setDim(td2->parameters->dim); - - // Attempt a type deduction - MATCH m = td2->matchWithInstance(&ti, &dedtypes, fargs, 1); - if (m) - { - /* A non-variadic template is more specialized than a - * variadic one. - */ - if (isVariadic() && !td2->isVariadic()) - goto L1; - -#if LOG_LEASTAS - printf(" matches %d, so is least as specialized\n", m); -#endif - return m; - } - L1: -#if LOG_LEASTAS - printf(" doesn't match, so is not as specialized\n"); -#endif - return MATCHnomatch; -} - - -/************************************************* - * Match function arguments against a specific template function. - * Input: - * loc instantiation location - * targsi Expression/Type initial list of template arguments - * ethis 'this' argument if !NULL - * fargs arguments to function - * Output: - * dedargs Expression/Type deduced template arguments - * Returns: - * match level - */ - -MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Scope *sc, Loc loc, Objects *targsi, - Expression *ethis, Expressions *fargs, - Objects *dedargs) -{ - size_t nfparams; - size_t nfargs; - size_t nargsi; // array size of targsi - int fptupindex = -1; - int tuple_dim = 0; - MATCH match = MATCHexact; - FuncDeclaration *fd = onemember->toAlias()->isFuncDeclaration(); - Parameters *fparameters; // function parameter list - int fvarargs; // function varargs - Objects dedtypes; // for T:T*, the dedargs is the T*, dedtypes is the T - unsigned wildmatch = 0; - - TypeFunction *tf = (TypeFunction *)fd->type; - -#if 0 - printf("\nTemplateDeclaration::deduceFunctionTemplateMatch() %s\n", toChars()); - for (size_t i = 0; i < fargs->dim; i++) - { Expression *e = fargs->tdata()[i]; - printf("\tfarg[%d] is %s, type is %s\n", i, e->toChars(), e->type->toChars()); - } - printf("fd = %s\n", fd->toChars()); - printf("fd->type = %s\n", fd->type->toChars()); - if (ethis) - printf("ethis->type = %s\n", ethis->type->toChars()); -#endif - - assert((size_t)scope > 0x10000); - - dedargs->setDim(parameters->dim); - dedargs->zero(); - - dedtypes.setDim(parameters->dim); - dedtypes.zero(); - - if (errors) - return MATCHnomatch; - - // Set up scope for parameters - ScopeDsymbol *paramsym = new ScopeDsymbol(); - paramsym->parent = scope->parent; - Scope *paramscope = scope->push(paramsym); - paramscope->stc = 0; - - TemplateTupleParameter *tp = isVariadic(); - int tp_is_declared = 0; - -#if 0 - for (size_t i = 0; i < dedargs->dim; i++) - { - printf("\tdedarg[%d] = ", i); - Object *oarg = dedargs->tdata()[i]; - if (oarg) printf("%s", oarg->toChars()); - printf("\n"); - } -#endif - - - nargsi = 0; - if (targsi) - { // Set initial template arguments - - nargsi = targsi->dim; - size_t n = parameters->dim; - if (tp) - n--; - if (nargsi > n) - { if (!tp) - goto Lnomatch; - - /* The extra initial template arguments - * now form the tuple argument. - */ - Tuple *t = new Tuple(); - assert(parameters->dim); - dedargs->tdata()[parameters->dim - 1] = t; - - tuple_dim = nargsi - n; - t->objects.setDim(tuple_dim); - for (size_t i = 0; i < tuple_dim; i++) - { - t->objects.tdata()[i] = targsi->tdata()[n + i]; - } - declareParameter(paramscope, tp, t); - tp_is_declared = 1; - } - else - n = nargsi; - - memcpy(dedargs->tdata(), targsi->tdata(), n * sizeof(*dedargs->tdata())); - - for (size_t i = 0; i < n; i++) - { assert(i < parameters->dim); - TemplateParameter *tp = parameters->tdata()[i]; - MATCH m; - Declaration *sparam = NULL; - - m = tp->matchArg(paramscope, dedargs, i, parameters, &dedtypes, &sparam); - //printf("\tdeduceType m = %d\n", m); - if (m == MATCHnomatch) - goto Lnomatch; - if (m < match) - match = m; - - sparam->semantic(paramscope); - if (!paramscope->insert(sparam)) - goto Lnomatch; - } - } -#if 0 - for (size_t i = 0; i < dedargs->dim; i++) - { - printf("\tdedarg[%d] = ", i); - Object *oarg = dedargs->tdata()[i]; - if (oarg) printf("%s", oarg->toChars()); - printf("\n"); - } -#endif - - fparameters = fd->getParameters(&fvarargs); - nfparams = Parameter::dim(fparameters); // number of function parameters - nfargs = fargs ? fargs->dim : 0; // number of function arguments - - /* Check for match of function arguments with variadic template - * parameter, such as: - * - * template Foo(T, A...) { void Foo(T t, A a); } - * void main() { Foo(1,2,3); } - */ - if (tp) // if variadic - { - if (nfparams == 0 && nfargs != 0) // if no function parameters - { - if (tp_is_declared) - goto L2; - Tuple *t = new Tuple(); - //printf("t = %p\n", t); - dedargs->tdata()[parameters->dim - 1] = t; - declareParameter(paramscope, tp, t); - goto L2; - } - else if (nfargs < nfparams - 1) - goto L1; - else - { - /* Figure out which of the function parameters matches - * the tuple template parameter. Do this by matching - * type identifiers. - * Set the index of this function parameter to fptupindex. - */ - for (fptupindex = 0; fptupindex < nfparams; fptupindex++) - { - Parameter *fparam = fparameters->tdata()[fptupindex]; - if (fparam->type->ty != Tident) - continue; - TypeIdentifier *tid = (TypeIdentifier *)fparam->type; - if (!tp->ident->equals(tid->ident) || tid->idents.dim) - continue; - - if (fvarargs) // variadic function doesn't - goto Lnomatch; // go with variadic template - - if (tp_is_declared) - goto L2; - - // Apply function parameter storage classes to parameter type - tid = (TypeIdentifier *)tid->addStorageClass(fparam->storageClass); - - /* The types of the function arguments - * now form the tuple argument. - */ - Tuple *t = new Tuple(); - dedargs->tdata()[parameters->dim - 1] = t; - - tuple_dim = nfargs - (nfparams - 1); - t->objects.setDim(tuple_dim); - for (size_t i = 0; i < tuple_dim; i++) - { Expression *farg = fargs->tdata()[fptupindex + i]; - - // Check invalid arguments to detect errors early. - if (farg->op == TOKerror || farg->type->ty == Terror) - goto Lnomatch; - - if (!(fparam->storageClass & STClazy) && farg->type->ty == Tvoid) - goto Lnomatch; - - unsigned mod = farg->type->mod; - Type *tt; - MATCH m; - - #define X(U,T) ((U) << 4) | (T) - if (tid->mod & MODwild) - { - switch (X(tid->mod, mod)) - { - case X(MODwild, MODwild): - case X(MODwild | MODshared, MODwild | MODshared): - case X(MODwild, 0): - case X(MODwild, MODconst): - case X(MODwild, MODimmutable): - case X(MODwild | MODshared, MODshared): - case X(MODwild | MODshared, MODconst | MODshared): - - if (mod & MODwild) - wildmatch |= MODwild; - else if (mod == 0) - wildmatch |= MODmutable; - else - wildmatch |= (mod & ~MODshared); - tt = farg->type->mutableOf(); - m = MATCHconst; - goto Lx; - - default: - break; - } - } - - switch (X(tid->mod, mod)) - { - case X(0, 0): - case X(0, MODconst): - case X(0, MODimmutable): - case X(0, MODshared): - case X(0, MODconst | MODshared): - case X(0, MODwild): - case X(0, MODwild | MODshared): - // foo(U:U) T => T - // foo(U:U) const(T) => const(T) - // foo(U:U) immutable(T) => immutable(T) - // foo(U:U) shared(T) => shared(T) - // foo(U:U) const(shared(T)) => const(shared(T)) - // foo(U:U) wild(T) => wild(T) - // foo(U:U) wild(shared(T)) => wild(shared(T)) - - tt = farg->type; - m = MATCHexact; - break; - - case X(MODconst, MODconst): - case X(MODimmutable, MODimmutable): - case X(MODshared, MODshared): - case X(MODconst | MODshared, MODconst | MODshared): - case X(MODwild, MODwild): - case X(MODwild | MODshared, MODwild | MODshared): - // foo(U:const(U)) const(T) => T - // foo(U:immutable(U)) immutable(T) => T - // foo(U:shared(U)) shared(T) => T - // foo(U:const(shared(U)) const(shared(T)) => T - // foo(U:wild(U)) wild(T) => T - // foo(U:wild(shared(U)) wild(shared(T)) => T - - tt = farg->type->mutableOf()->unSharedOf(); - m = MATCHexact; - break; - - case X(MODconst, 0): - case X(MODconst, MODimmutable): - case X(MODconst, MODconst | MODshared): - case X(MODconst | MODshared, MODimmutable): - case X(MODconst, MODwild): - case X(MODconst, MODwild | MODshared): - // foo(U:const(U)) T => T - // foo(U:const(U)) immutable(T) => T - // foo(U:const(U)) const(shared(T)) => shared(T) - // foo(U:const(shared(U)) immutable(T) => T - // foo(U:const(U)) wild(shared(T)) => shared(T) - - tt = farg->type->mutableOf(); - m = MATCHconst; - break; - - case X(MODshared, MODconst | MODshared): - case X(MODconst | MODshared, MODshared): - case X(MODshared, MODwild | MODshared): - // foo(U:shared(U)) const(shared(T)) => const(T) - // foo(U:const(shared(U)) shared(T) => T - // foo(U:shared(U)) wild(shared(T)) => wild(T) - tt = farg->type->unSharedOf(); - m = MATCHconst; - break; - - case X(MODimmutable, 0): - case X(MODimmutable, MODconst): - case X(MODimmutable, MODshared): - case X(MODimmutable, MODconst | MODshared): - case X(MODconst, MODshared): - case X(MODshared, 0): - case X(MODshared, MODconst): - case X(MODshared, MODimmutable): - case X(MODconst | MODshared, 0): - case X(MODconst | MODshared, MODconst): - case X(MODimmutable, MODwild): - case X(MODshared, MODwild): - case X(MODconst | MODshared, MODwild): - case X(MODwild, 0): - case X(MODwild, MODconst): - case X(MODwild, MODimmutable): - case X(MODwild, MODshared): - case X(MODwild, MODconst | MODshared): - case X(MODwild | MODshared, 0): - case X(MODwild | MODshared, MODconst): - case X(MODwild | MODshared, MODimmutable): - case X(MODwild | MODshared, MODshared): - case X(MODwild | MODshared, MODconst | MODshared): - case X(MODwild | MODshared, MODwild): - case X(MODimmutable, MODwild | MODshared): - case X(MODconst | MODshared, MODwild | MODshared): - case X(MODwild, MODwild | MODshared): - - // foo(U:immutable(U)) T => nomatch - // foo(U:immutable(U)) const(T) => nomatch - // foo(U:immutable(U)) shared(T) => nomatch - // foo(U:immutable(U)) const(shared(T)) => nomatch - // foo(U:const(U)) shared(T) => nomatch - // foo(U:shared(U)) T => nomatch - // foo(U:shared(U)) const(T) => nomatch - // foo(U:shared(U)) immutable(T) => nomatch - // foo(U:const(shared(U)) T => nomatch - // foo(U:const(shared(U)) const(T) => nomatch - // foo(U:immutable(U)) wild(T) => nomatch - // foo(U:shared(U)) wild(T) => nomatch - // foo(U:const(shared(U)) wild(T) => nomatch - // foo(U:wild(U)) T => nomatch - // foo(U:wild(U)) const(T) => nomatch - // foo(U:wild(U)) immutable(T) => nomatch - // foo(U:wild(U)) shared(T) => nomatch - // foo(U:wild(U)) const(shared(T)) => nomatch - // foo(U:wild(shared(U)) T => nomatch - // foo(U:wild(shared(U)) const(T) => nomatch - // foo(U:wild(shared(U)) immutable(T) => nomatch - // foo(U:wild(shared(U)) shared(T) => nomatch - // foo(U:wild(shared(U)) const(shared(T)) => nomatch - // foo(U:wild(shared(U)) wild(T) => nomatch - // foo(U:immutable(U)) wild(shared(T)) => nomatch - // foo(U:const(shared(U))) wild(shared(T)) => nomatch - // foo(U:wild(U)) wild(shared(T)) => nomatch - m = MATCHnomatch; - break; - - default: - assert(0); - } - #undef X - - Lx: - if (m == MATCHnomatch) - goto Lnomatch; - if (m < match) - match = m; - - t->objects.tdata()[i] = tt; - } - declareParameter(paramscope, tp, t); - goto L2; - } - fptupindex = -1; - } - } - -L1: - if (nfparams == nfargs) - ; - else if (nfargs > nfparams) - { - if (fvarargs == 0) - goto Lnomatch; // too many args, no match - match = MATCHconvert; // match ... with a conversion - } - -L2: -#if DMDV2 - if (ethis) - { - // Match 'ethis' to any TemplateThisParameter's - for (size_t i = 0; i < parameters->dim; i++) - { TemplateParameter *tp = parameters->tdata()[i]; - TemplateThisParameter *ttp = tp->isTemplateThisParameter(); - if (ttp) - { MATCH m; - - Type *t = new TypeIdentifier(0, ttp->ident); - m = ethis->type->deduceType(paramscope, t, parameters, &dedtypes); - if (!m) - goto Lnomatch; - if (m < match) - match = m; // pick worst match - } - } - - // Match attributes of ethis against attributes of fd - if (fd->type) - { - Type *tthis = ethis->type; - unsigned mod = fd->type->mod; - StorageClass stc = scope->stc | fd->storage_class2; - // Propagate parent storage class (see bug 5504) - Dsymbol *p = parent; - while (p->isTemplateDeclaration() || p->isTemplateInstance()) - p = p->parent; - AggregateDeclaration *ad = p->isAggregateDeclaration(); - if (ad) - stc |= ad->storage_class; - - if (stc & (STCshared | STCsynchronized)) - mod |= MODshared; - if (stc & STCimmutable) - mod |= MODimmutable; - if (stc & STCconst) - mod |= MODconst; - if (stc & STCwild) - mod |= MODwild; - // Fix mod - if (mod & MODimmutable) - mod = MODimmutable; - if (mod & MODconst) - mod &= ~STCwild; - if (tthis->mod != mod) - { - if (!MODmethodConv(tthis->mod, mod)) - goto Lnomatch; - if (MATCHconst < match) - match = MATCHconst; - } - } - } -#endif - - // Loop through the function parameters - for (size_t parami = 0; parami < nfparams; parami++) - { - /* Skip over function parameters which wound up - * as part of a template tuple parameter. - */ - if (parami == fptupindex) - continue; - /* Set i = index into function arguments - * Function parameters correspond to function arguments as follows. - * Note that tuple_dim may be zero, and there may be default or - * variadic arguments at the end. - * arg [0..fptupindex] == param[0..fptupindex] - * arg [fptupindex..fptupindex+tuple_dim] == param[fptupindex] - * arg[fputupindex+dim.. ] == param[fptupindex+1.. ] - */ - size_t i = parami; - if (fptupindex >= 0 && parami > fptupindex) - i += tuple_dim - 1; - - Parameter *fparam = Parameter::getNth(fparameters, parami); - - if (i >= nfargs) // if not enough arguments - { - if (fparam->defaultArg) - { /* Default arguments do not participate in template argument - * deduction. - */ - goto Lmatch; - } - } - else - { - Expression *farg = fargs->tdata()[i]; - - // Check invalid arguments to detect errors early. - if (farg->op == TOKerror || farg->type->ty == Terror) - goto Lnomatch; - -Lretry: -#if 0 - printf("\tfarg->type = %s\n", farg->type->toChars()); - printf("\tfparam->type = %s\n", fparam->type->toChars()); -#endif - Type *argtype = farg->type; - - // Apply function parameter storage classes to parameter types - fparam->type = fparam->type->addStorageClass(fparam->storageClass); - -#if DMDV2 - /* Allow string literals which are type [] to match with [dim] - */ - if (farg->op == TOKstring) - { StringExp *se = (StringExp *)farg; - if (!se->committed && argtype->ty == Tarray && - fparam->type->toBasetype()->ty == Tsarray) - { - argtype = new TypeSArray(argtype->nextOf(), new IntegerExp(se->loc, se->len, Type::tindex)); - argtype = argtype->semantic(se->loc, NULL); - argtype = argtype->invariantOf(); - } - } - - /* Allow implicit function literals to delegate conversion - */ - if (farg->op == TOKfunction) - { FuncExp *fe = (FuncExp *)farg; - Type *tp = fparam->type; - Expression *e = fe->inferType(tp, 1, parameters); - if (!e) - goto Lvarargs; - farg = e; - argtype = farg->type; - } - - if (!(fparam->storageClass & STClazy) && argtype->ty == Tvoid) - goto Lnomatch; - - /* Remove top const for dynamic array types and pointer types - */ - if ((argtype->ty == Tarray || argtype->ty == Tpointer) && - !argtype->isMutable() && - (!(fparam->storageClass & STCref) || - (fparam->storageClass & STCauto) && !farg->isLvalue())) - { - argtype = argtype->mutableOf(); - } -#endif - - if (fvarargs == 2 && i + 1 == nfparams && i + 1 < nfargs) - goto Lvarargs; - - unsigned wm = 0; - MATCH m = argtype->deduceType(paramscope, fparam->type, parameters, &dedtypes, &wm); - //printf("\tdeduceType m = %d\n", m); - //printf("\twildmatch = x%x m = %d\n", wildmatch, m); - wildmatch |= wm; - - /* If no match, see if there's a conversion to a delegate - */ - if (!m) - { Type *tbp = fparam->type->toBasetype(); - Type *tba = farg->type->toBasetype(); - AggregateDeclaration *ad; - if (tbp->ty == Tdelegate) - { - TypeDelegate *td = (TypeDelegate *)fparam->type->toBasetype(); - TypeFunction *tf = (TypeFunction *)td->next; - - if (!tf->varargs && Parameter::dim(tf->parameters) == 0) - { - m = farg->type->deduceType(paramscope, tf->next, parameters, &dedtypes); - if (!m && tf->next->toBasetype()->ty == Tvoid) - m = MATCHconvert; - } - //printf("\tm2 = %d\n", m); - } - else if (tba->ty == Tclass) - { - ad = ((TypeClass *)tba)->sym; - goto Lad; - } - else if (tba->ty == Tstruct) - { - ad = ((TypeStruct *)tba)->sym; - Lad: - if (ad->aliasthis) - { /* If a semantic error occurs while doing alias this, - * eg purity(bug 7295), just regard it as not a match. - */ - unsigned olderrors = global.startGagging(); - Expression *e = resolveAliasThis(sc, farg); - if (!global.endGagging(olderrors)) - { farg = e; - goto Lretry; - } - } - } - } - - if (m && (fparam->storageClass & (STCref | STCauto)) == STCref) - { if (!farg->isLvalue()) - { - if (farg->op == TOKstructliteral) - m = MATCHconvert; - else if (farg->op == TOKcall) - { - CallExp *ce = (CallExp *)farg; - if (ce->e1->op == TOKdotvar && - ((DotVarExp *)ce->e1)->var->isCtorDeclaration()) - { - m = MATCHconvert; - } - else - goto Lnomatch; - } - else - goto Lnomatch; - } - } - if (m && (fparam->storageClass & STCout)) - { if (!farg->isLvalue()) - goto Lnomatch; - } - if (!m && (fparam->storageClass & STClazy) && fparam->type->ty == Tvoid && - farg->type->ty != Tvoid) - m = MATCHconvert; - - if (m) - { if (m < match) - match = m; // pick worst match - continue; - } - } - - Lvarargs: - /* The following code for variadic arguments closely - * matches TypeFunction::callMatch() - */ - if (!(fvarargs == 2 && i + 1 == nfparams)) - goto Lnomatch; - - /* Check for match with function parameter T... - */ - Type *tb = fparam->type->toBasetype(); - switch (tb->ty) - { - // Perhaps we can do better with this, see TypeFunction::callMatch() - case Tsarray: - { TypeSArray *tsa = (TypeSArray *)tb; - dinteger_t sz = tsa->dim->toInteger(); - if (sz != nfargs - i) - goto Lnomatch; - } - case Tarray: - { TypeArray *ta = (TypeArray *)tb; - for (; i < nfargs; i++) - { - Expression *arg = fargs->tdata()[i]; - assert(arg); - - if (arg->op == TOKfunction) - { FuncExp *fe = (FuncExp *)arg; - Type *tp = tb->nextOf(); - - Expression *e = fe->inferType(tp, 1, parameters); - if (!e) - goto Lnomatch; - arg = e; - } - - MATCH m; - /* If lazy array of delegates, - * convert arg(s) to delegate(s) - */ - Type *tret = fparam->isLazyArray(); - if (tret) - { - if (ta->next->equals(arg->type)) - { m = MATCHexact; - } - else - { - m = arg->implicitConvTo(tret); - if (m == MATCHnomatch) - { - if (tret->toBasetype()->ty == Tvoid) - m = MATCHconvert; - } - } - } - else - { - m = arg->type->deduceType(paramscope, ta->next, parameters, &dedtypes); - //m = arg->implicitConvTo(ta->next); - } - if (m == MATCHnomatch) - goto Lnomatch; - if (m < match) - match = m; - } - goto Lmatch; - } - case Tclass: - case Tident: - goto Lmatch; - - default: - goto Lnomatch; - } - } - -Lmatch: - - for (size_t i = nargsi; i < dedargs->dim; i++) - { - TemplateParameter *tparam = parameters->tdata()[i]; - //printf("tparam[%d] = %s\n", i, tparam->ident->toChars()); - /* For T:T*, the dedargs is the T*, dedtypes is the T - * But for function templates, we really need them to match - */ - Object *oarg = dedargs->tdata()[i]; - Object *oded = dedtypes.tdata()[i]; - //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded); - //if (oarg) printf("oarg: %s\n", oarg->toChars()); - //if (oded) printf("oded: %s\n", oded->toChars()); - if (!oarg) - { - if (oded) - { - if (tparam->specialization()) - { /* The specialization can work as long as afterwards - * the oded == oarg - */ - Declaration *sparam; - dedargs->tdata()[i] = oded; - MATCH m2 = tparam->matchArg(paramscope, dedargs, i, parameters, &dedtypes, &sparam); - //printf("m2 = %d\n", m2); - if (!m2) - goto Lnomatch; - if (m2 < match) - match = m2; // pick worst match - if (dedtypes.tdata()[i] != oded) - error("specialization not allowed for deduced parameter %s", tparam->ident->toChars()); - } - } - else - { oded = tparam->defaultArg(loc, paramscope); - if (!oded) - { - if (tp && // if tuple parameter and - fptupindex < 0 && // tuple parameter was not in function parameter list and - nargsi == dedargs->dim - 1) // we're one argument short (i.e. no tuple argument) - { // make tuple argument an empty tuple - oded = (Object *)new Tuple(); - } - else - goto Lnomatch; - } - } - declareParameter(paramscope, tparam, oded); - dedargs->tdata()[i] = oded; - } - } - -#if DMDV2 - if (constraint) - { /* Check to see if constraint is satisfied. - * Most of this code appears twice; this is a good candidate for refactoring. - */ - makeParamNamesVisibleInConstraint(paramscope, fargs); - Expression *e = constraint->syntaxCopy(); - paramscope->ignoreTemplates++; - paramscope->flags |= SCOPEstaticif; - - /* Detect recursive attempts to instantiate this template declaration, - * Bugzilla 4072 - * void foo(T)(T x) if (is(typeof(foo(x)))) { } - * static assert(!is(typeof(foo(7)))); - * Recursive attempts are regarded as a constraint failure. - */ - int nmatches = 0; - for (Previous *p = previous; p; p = p->prev) - { - if (arrayObjectMatch(p->dedargs, dedargs, this, sc)) - { - //printf("recursive, no match p->sc=%p %p %s\n", p->sc, this, this->toChars()); - /* It must be a subscope of p->sc, other scope chains are not recursive - * instantiations. - */ - for (Scope *scx = sc; scx; scx = scx->enclosing) - { - if (scx == p->sc) - goto Lnomatch; - } - } - /* BUG: should also check for ref param differences - */ - } - - Previous pr; - pr.prev = previous; - pr.sc = paramscope; - pr.dedargs = dedargs; - previous = ≺ // add this to threaded list - - int nerrors = global.errors; - - FuncDeclaration *fd = onemember && onemember->toAlias() ? - onemember->toAlias()->isFuncDeclaration() : NULL; - Dsymbol *s = parent; - while (s->isTemplateInstance() || s->isTemplateMixin()) - s = s->parent; - AggregateDeclaration *ad = s->isAggregateDeclaration(); - VarDeclaration *vthissave; - if (fd && ad) - { - vthissave = fd->vthis; - fd->vthis = fd->declareThis(paramscope, ad); - } - - e = e->semantic(paramscope); - - if (fd && fd->vthis) - fd->vthis = vthissave; - - previous = pr.prev; // unlink from threaded list - - if (nerrors != global.errors) // if any errors from evaluating the constraint, no match - goto Lnomatch; - - e = e->optimize(WANTvalue | WANTinterpret); - if (e->isBool(TRUE)) - ; - else if (e->isBool(FALSE)) - goto Lnomatch; - else - { - e->error("constraint %s is not constant or does not evaluate to a bool", e->toChars()); - } - } -#endif - -#if 0 - for (i = 0; i < dedargs->dim; i++) - { Type *t = dedargs->tdata()[i]; - printf("\tdedargs[%d] = %d, %s\n", i, t->dyncast(), t->toChars()); - } -#endif - - paramscope->pop(); - //printf("\tmatch %d\n", match); - return match; - -Lnomatch: - paramscope->pop(); - //printf("\tnomatch\n"); - return MATCHnomatch; -} - -/************************************************** - * Declare template parameter tp with value o, and install it in the scope sc. - */ - -void TemplateDeclaration::declareParameter(Scope *sc, TemplateParameter *tp, Object *o) -{ - //printf("TemplateDeclaration::declareParameter('%s', o = %p)\n", tp->ident->toChars(), o); - - Type *targ = isType(o); - Expression *ea = isExpression(o); - Dsymbol *sa = isDsymbol(o); - Tuple *va = isTuple(o); - - Dsymbol *s; - - // See if tp->ident already exists with a matching definition - Dsymbol *scopesym; - s = sc->search(loc, tp->ident, &scopesym); - if (s && scopesym == sc->scopesym) - { - TupleDeclaration *td = s->isTupleDeclaration(); - if (va && td) - { Tuple tup; - tup.objects = *td->objects; - if (match(va, &tup, this, sc)) - { - return; - } - } - } - - if (targ) - { - //printf("type %s\n", targ->toChars()); - s = new AliasDeclaration(0, tp->ident, targ); - } - else if (sa) - { - //printf("Alias %s %s;\n", sa->ident->toChars(), tp->ident->toChars()); - s = new AliasDeclaration(0, tp->ident, sa); - } - else if (ea) - { - // tdtypes.data[i] always matches ea here - Initializer *init = new ExpInitializer(loc, ea); - TemplateValueParameter *tvp = tp->isTemplateValueParameter(); - - Type *t = tvp ? tvp->valType : NULL; - - VarDeclaration *v = new VarDeclaration(loc, t, tp->ident, init); - v->storage_class = STCmanifest; - s = v; - } - else if (va) - { - //printf("\ttuple\n"); - s = new TupleDeclaration(loc, tp->ident, &va->objects); - } - else - { -#ifdef DEBUG - o->print(); -#endif - assert(0); - } - if (!sc->insert(s)) - error("declaration %s is already defined", tp->ident->toChars()); - s->semantic(sc); -} - -/************************************** - * Determine if TemplateDeclaration is variadic. - */ - -TemplateTupleParameter *isVariadic(TemplateParameters *parameters) -{ size_t dim = parameters->dim; - TemplateTupleParameter *tp = NULL; - - if (dim) - tp = (parameters->tdata()[dim - 1])->isTemplateTupleParameter(); - return tp; -} - -TemplateTupleParameter *TemplateDeclaration::isVariadic() -{ - return ::isVariadic(parameters); -} - -/*********************************** - * We can overload templates. - */ - -int TemplateDeclaration::isOverloadable() -{ - return 1; -} - -/************************************************* - * Given function arguments, figure out which template function - * to expand, and return that function. - * If no match, give error message and return NULL. - * Input: - * sc instantiation scope - * loc instantiation location - * targsi initial list of template arguments - * ethis if !NULL, the 'this' pointer argument - * fargs arguments to function - * flags 1: do not issue error message on no match, just return NULL - */ - -FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, - Objects *targsi, Expression *ethis, Expressions *fargs, int flags) -{ - MATCH m_best = MATCHnomatch; - TemplateDeclaration *td_ambig = NULL; - TemplateDeclaration *td_best = NULL; - Objects *tdargs = new Objects(); - TemplateInstance *ti; - FuncDeclaration *fd_best; - -#if 0 - printf("TemplateDeclaration::deduceFunctionTemplate() %s\n", toChars()); - printf(" targsi:\n"); - if (targsi) - { for (size_t i = 0; i < targsi->dim; i++) - { Object *arg = targsi->tdata()[i]; - printf("\t%s\n", arg->toChars()); - } - } - printf(" fargs:\n"); - for (size_t i = 0; i < fargs->dim; i++) - { Expression *arg = fargs->tdata()[i]; - printf("\t%s %s\n", arg->type->toChars(), arg->toChars()); - //printf("\tty = %d\n", arg->type->ty); - } - printf("stc = %llx\n", scope->stc); -#endif - - for (TemplateDeclaration *td = this; td; td = td->overnext) - { - if (!td->semanticRun) - { - error("forward reference to template %s", td->toChars()); - goto Lerror; - } - if (!td->onemember || !td->onemember->toAlias()->isFuncDeclaration()) - { - error("is not a function template"); - goto Lerror; - } - - Objects dedargs; - FuncDeclaration *fd = NULL; - - MATCH m = td->deduceFunctionTemplateMatch(sc, loc, targsi, ethis, fargs, &dedargs); - //printf("deduceFunctionTemplateMatch = %d\n", m); - if (!m) // if no match - continue; - - if (m < m_best) - goto Ltd_best; - if (m > m_best) - goto Ltd; - - { - // Disambiguate by picking the most specialized TemplateDeclaration - MATCH c1 = td->leastAsSpecialized(td_best, fargs); - MATCH c2 = td_best->leastAsSpecialized(td, fargs); - //printf("1: c1 = %d, c2 = %d\n", c1, c2); - - if (c1 > c2) - goto Ltd; - else if (c1 < c2) - goto Ltd_best; - } - - if (!fd_best) - { - fd_best = td_best->doHeaderInstantiation(sc, tdargs, fargs); - if (!fd_best) - goto Lerror; - } - { - fd = td->doHeaderInstantiation(sc, &dedargs, fargs); - if (!fd) - goto Lerror; - } - assert(fd && fd_best); - - { - // Disambiguate by tf->callMatch - TypeFunction *tf1 = (TypeFunction *)fd->type; - TypeFunction *tf2 = (TypeFunction *)fd_best->type; - MATCH c1 = (MATCH) tf1->callMatch(fd->needThis() && !fd->isCtorDeclaration() ? ethis : NULL, fargs); - MATCH c2 = (MATCH) tf2->callMatch(fd_best->needThis() && !fd->isCtorDeclaration() ? ethis : NULL, fargs); - //printf("2: c1 = %d, c2 = %d\n", c1, c2); - - if (c1 > c2) - goto Ltd; - if (c1 < c2) - goto Ltd_best; - } - - { - // Disambiguate by picking the most specialized FunctionDeclaration - MATCH c1 = fd->leastAsSpecialized(fd_best); - MATCH c2 = fd_best->leastAsSpecialized(fd); - //printf("3: c1 = %d, c2 = %d\n", c1, c2); - - if (c1 > c2) - goto Ltd; - if (c1 < c2) - goto Ltd_best; - } - - Lambig: // td_best and td are ambiguous - td_ambig = td; - continue; - - Ltd_best: // td_best is the best match so far - td_ambig = NULL; - continue; - - Ltd: // td is the new best match - td_ambig = NULL; - assert((size_t)td->scope > 0x10000); - td_best = td; - fd_best = fd; - m_best = m; - tdargs->setDim(dedargs.dim); - memcpy(tdargs->tdata(), dedargs.tdata(), tdargs->dim * sizeof(void *)); - continue; - } - if (!td_best) - { - if (!(flags & 1)) - ::error(loc, "%s %s.%s does not match any function template declaration", - kind(), parent->toPrettyChars(), ident->toChars()); - goto Lerror; - } - if (td_ambig) - { - ::error(loc, "%s %s.%s matches more than one template declaration, %s(%d):%s and %s(%d):%s", - kind(), parent->toPrettyChars(), ident->toChars(), - td_best->loc.filename, td_best->loc.linnum, td_best->toChars(), - td_ambig->loc.filename, td_ambig->loc.linnum, td_ambig->toChars()); - } - - /* The best match is td_best with arguments tdargs. - * Now instantiate the template. - */ - assert((size_t)td_best->scope > 0x10000); - ti = new TemplateInstance(loc, td_best, tdargs); - ti->semantic(sc, fargs); - fd_best = ti->toAlias()->isFuncDeclaration(); - if (!fd_best || !((TypeFunction*)fd_best->type)->callMatch(ethis, fargs, flags)) - goto Lerror; - - /* As Bugzilla 3682 shows, a template instance can be matched while instantiating - * that same template. Thus, the function type can be incomplete. Complete it. - */ - { TypeFunction *tf = (TypeFunction *)fd_best->type; - assert(tf->ty == Tfunction); - if (tf->next) - fd_best->type = tf->semantic(loc, sc); - } - - return fd_best; - - Lerror: -#if DMDV2 - if (!(flags & 1)) -#endif - { - HdrGenState hgs; - - OutBuffer bufa; - Objects *args = targsi; - if (args) - { for (size_t i = 0; i < args->dim; i++) - { - if (i) - bufa.writeByte(','); - Object *oarg = args->tdata()[i]; - ObjectToCBuffer(&bufa, &hgs, oarg); - } - } - - OutBuffer buf; - argExpTypesToCBuffer(&buf, fargs, &hgs); - if (this->overnext) - ::error(loc, "%s %s.%s cannot deduce template function from argument types !(%s)(%s)", - kind(), parent->toPrettyChars(), ident->toChars(), - bufa.toChars(), buf.toChars()); - else - error("cannot deduce template function from argument types !(%s)(%s)", - bufa.toChars(), buf.toChars()); - } - return NULL; -} - -/************************************************* - * Limited function template instantiation for using fd->leastAsSpecialized() - */ -FuncDeclaration *TemplateDeclaration::doHeaderInstantiation(Scope *sc, - Objects *tdargs, Expressions *fargs) -{ - FuncDeclaration *fd = onemember->toAlias()->isFuncDeclaration(); - if (!fd) - return NULL; - -#if 0 - printf("doHeaderInstantiation this = %s\n", toChars()); - for (size_t i = 0; i < tdargs->dim; ++i) - printf("\ttdargs[%d] = %s\n", i, ((Object *)tdargs->data[i])->toChars()); -#endif - - assert((size_t)scope > 0x10000); - TemplateInstance *ti = new TemplateInstance(loc, this, tdargs); - ti->tinst = sc->tinst; - { - ti->tdtypes.setDim(ti->tempdecl->parameters->dim); - if (!ti->tempdecl->matchWithInstance(ti, &ti->tdtypes, fargs, 2)) - return NULL; - } - - ti->parent = parent; - - // function body and contracts are not need - //fd = fd->syntaxCopy(NULL)->isFuncDeclaration(); - fd = new FuncDeclaration(fd->loc, fd->endloc, fd->ident, fd->storage_class, fd->type->syntaxCopy()); - fd->parent = ti; - - Scope *scope = this->scope; - - ti->argsym = new ScopeDsymbol(); - ti->argsym->parent = scope->parent; - scope = scope->push(ti->argsym); - - Scope *paramscope = scope->push(); - paramscope->stc = 0; - ti->declareParameters(paramscope); - paramscope->pop(); - - { - TypeFunction *tf = (TypeFunction *)fd->type; - if (tf && tf->ty == Tfunction) - tf->fargs = fargs; - } - - Scope *sc2; - sc2 = scope->push(ti); - sc2->parent = /*isnested ? sc->parent :*/ ti; - sc2->tinst = ti; - - { - Scope *sc = sc2; - sc = sc->push(); - - if (fd->isCtorDeclaration()) - sc->flags |= SCOPEctor; - fd->type = fd->type->semantic(fd->loc, sc); - sc = sc->pop(); - } - //printf("\t[%s] fd->type = %s, mod = %x, ", loc.toChars(), fd->type->toChars(), fd->type->mod); - //printf("fd->needThis() = %d\n", fd->needThis()); - - sc2->pop(); - scope->pop(); - - return fd; -} - -bool TemplateDeclaration::hasStaticCtorOrDtor() -{ - return FALSE; // don't scan uninstantiated templates -} - -void TemplateDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ -#if 0 // Should handle template functions for doc generation - if (onemember && onemember->isFuncDeclaration()) - buf->writestring("foo "); -#endif - if (hgs->ddoc) - buf->writestring(kind()); - else - buf->writestring("template"); - buf->writeByte(' '); - buf->writestring(ident->toChars()); - buf->writeByte('('); - for (size_t i = 0; i < parameters->dim; i++) - { - TemplateParameter *tp = parameters->tdata()[i]; - if (hgs->ddoc) - tp = origParameters->tdata()[i]; - if (i) - buf->writeByte(','); - tp->toCBuffer(buf, hgs); - } - buf->writeByte(')'); -#if DMDV2 - if (constraint) - { buf->writestring(" if ("); - constraint->toCBuffer(buf, hgs); - buf->writeByte(')'); - } -#endif - - if (hgs->hdrgen) - { - hgs->tpltMember++; - buf->writenl(); - buf->writebyte('{'); - buf->writenl(); - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[i]; - s->toCBuffer(buf, hgs); - } - buf->writebyte('}'); - buf->writenl(); - hgs->tpltMember--; - } -} - - -char *TemplateDeclaration::toChars() -{ OutBuffer buf; - HdrGenState hgs; - - memset(&hgs, 0, sizeof(hgs)); - buf.writestring(ident->toChars()); - buf.writeByte('('); - for (size_t i = 0; i < parameters->dim; i++) - { - TemplateParameter *tp = parameters->tdata()[i]; - if (i) - buf.writeByte(','); - tp->toCBuffer(&buf, &hgs); - } - buf.writeByte(')'); -#if DMDV2 - if (constraint) - { buf.writestring(" if ("); - constraint->toCBuffer(&buf, &hgs); - buf.writeByte(')'); - } -#endif - buf.writeByte(0); - return (char *)buf.extractData(); -} - -/* ======================== Type ============================================ */ - -/**** - * Given an identifier, figure out which TemplateParameter it is. - * Return -1 if not found. - */ - -int templateIdentifierLookup(Identifier *id, TemplateParameters *parameters) -{ - for (size_t i = 0; i < parameters->dim; i++) - { TemplateParameter *tp = parameters->tdata()[i]; - - if (tp->ident->equals(id)) - return i; - } - return -1; -} - -int templateParameterLookup(Type *tparam, TemplateParameters *parameters) -{ - assert(tparam->ty == Tident); - TypeIdentifier *tident = (TypeIdentifier *)tparam; - //printf("\ttident = '%s'\n", tident->toChars()); - if (tident->idents.dim == 0) - { - return templateIdentifierLookup(tident->ident, parameters); - } - return -1; -} - -/* These form the heart of template argument deduction. - * Given 'this' being the type argument to the template instance, - * it is matched against the template declaration parameter specialization - * 'tparam' to determine the type to be used for the parameter. - * Example: - * template Foo(T:T*) // template declaration - * Foo!(int*) // template instantiation - * Input: - * this = int* - * tparam = T* - * parameters = [ T:T* ] // Array of TemplateParameter's - * Output: - * dedtypes = [ int ] // Array of Expression/Type's - */ - -MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, - Objects *dedtypes, unsigned *wildmatch) -{ -#if 0 - printf("Type::deduceType()\n"); - printf("\tthis = %d, ", ty); print(); - printf("\ttparam = %d, ", tparam->ty); tparam->print(); -#endif - if (!tparam) - goto Lnomatch; - - if (this == tparam) - goto Lexact; - - if (tparam->ty == Tident) - { - // Determine which parameter tparam is - int i = templateParameterLookup(tparam, parameters); - if (i == -1) - { - if (!sc) - goto Lnomatch; - - /* Need a loc to go with the semantic routine. - */ - Loc loc; - if (parameters->dim) - { - TemplateParameter *tp = parameters->tdata()[0]; - loc = tp->loc; - } - - /* BUG: what if tparam is a template instance, that - * has as an argument another Tident? - */ - tparam = tparam->semantic(loc, sc); - assert(tparam->ty != Tident); - return deduceType(sc, tparam, parameters, dedtypes, wildmatch); - } - - TemplateParameter *tp = parameters->tdata()[i]; - - // Found the corresponding parameter tp - if (!tp->isTemplateTypeParameter()) - goto Lnomatch; - Type *tt = this; - Type *at = (Type *)dedtypes->tdata()[i]; - - // 7*7 == 49 cases - - #define X(U,T) ((U) << 4) | (T) - - if (wildmatch && (tparam->mod & MODwild)) - { - switch (X(tparam->mod, mod)) - { - case X(MODwild, 0): - case X(MODwild, MODshared): - case X(MODwild, MODconst): - case X(MODwild, MODconst | MODshared): - case X(MODwild, MODimmutable): - case X(MODwild, MODwild): - case X(MODwild, MODwild | MODshared): - case X(MODwild | MODshared, MODshared): - case X(MODwild | MODshared, MODconst | MODshared): - case X(MODwild | MODshared, MODimmutable): - case X(MODwild | MODshared, MODwild | MODshared): - - if (!at) - { - if (mod & MODwild) - *wildmatch |= MODwild; - else if (mod == 0) - *wildmatch |= MODmutable; - else - *wildmatch |= (mod & ~MODshared); - tt = mutableOf()->substWildTo(MODmutable); - dedtypes->tdata()[i] = tt; - goto Lconst; - } - - //printf("\t> tt = %s, at = %s\n", tt->toChars(), at->toChars()); - //printf("\t> tt->implicitConvTo(at->constOf()) = %d\n", tt->implicitConvTo(at->constOf())); - //printf("\t> at->implicitConvTo(tt->constOf()) = %d\n", at->implicitConvTo(tt->constOf())); - - if (tt->equals(at)) - { - goto Lconst; - } - else if (tt->implicitConvTo(at->constOf())) - { - dedtypes->tdata()[i] = at->constOf()->mutableOf(); - *wildmatch |= MODconst; - goto Lconst; - } - else if (at->implicitConvTo(tt->constOf())) - { - dedtypes->tdata()[i] = tt->constOf()->mutableOf(); - *wildmatch |= MODconst; - goto Lconst; - } - goto Lnomatch; - - default: - break; - } - } - - switch (X(tparam->mod, mod)) - { - case X(0, 0): - case X(0, MODconst): - case X(0, MODimmutable): - case X(0, MODshared): - case X(0, MODconst | MODshared): - case X(0, MODwild): - case X(0, MODwild | MODshared): - // foo(U:U) T => T - // foo(U:U) const(T) => const(T) - // foo(U:U) immutable(T) => immutable(T) - // foo(U:U) shared(T) => shared(T) - // foo(U:U) const(shared(T)) => const(shared(T)) - // foo(U:U) wild(T) => wild(T) - // foo(U:U) wild(shared(T)) => wild(shared(T)) - if (!at) - { dedtypes->tdata()[i] = tt; - goto Lexact; - } - break; - - case X(MODconst, MODconst): - case X(MODimmutable, MODimmutable): - case X(MODshared, MODshared): - case X(MODconst | MODshared, MODconst | MODshared): - case X(MODwild, MODwild): - case X(MODwild | MODshared, MODwild | MODshared): - // foo(U:const(U)) const(T) => T - // foo(U:immutable(U)) immutable(T) => T - // foo(U:shared(U)) shared(T) => T - // foo(U:const(shared(U)) const(shared(T)) => T - // foo(U:wild(U)) wild(T) => T - // foo(U:wild(shared(U)) wild(shared(T)) => T - tt = mutableOf()->unSharedOf(); - if (!at) - { dedtypes->tdata()[i] = tt; - goto Lexact; - } - break; - - case X(MODconst, 0): - case X(MODconst, MODimmutable): - case X(MODconst, MODconst | MODshared): - case X(MODconst | MODshared, MODimmutable): - case X(MODconst, MODwild): - case X(MODconst, MODwild | MODshared): - // foo(U:const(U)) T => T - // foo(U:const(U)) immutable(T) => T - // foo(U:const(U)) const(shared(T)) => shared(T) - // foo(U:const(shared(U)) immutable(T) => T - // foo(U:const(U)) wild(shared(T)) => shared(T) - tt = mutableOf(); - if (!at) - { dedtypes->tdata()[i] = tt; - goto Lconst; - } - break; - - case X(MODshared, MODconst | MODshared): - case X(MODconst | MODshared, MODshared): - case X(MODshared, MODwild | MODshared): - // foo(U:shared(U)) const(shared(T)) => const(T) - // foo(U:const(shared(U)) shared(T) => T - // foo(U:shared(U)) wild(shared(T)) => wild(T) - tt = unSharedOf(); - if (!at) - { dedtypes->tdata()[i] = tt; - goto Lconst; - } - break; - - case X(MODconst, MODshared): - // foo(U:const(U)) shared(T) => shared(T) - if (!at) - { (*dedtypes)[i] = tt; - goto Lconst; - } - break; - - case X(MODimmutable, 0): - case X(MODimmutable, MODconst): - case X(MODimmutable, MODshared): - case X(MODimmutable, MODconst | MODshared): - case X(MODshared, 0): - case X(MODshared, MODconst): - case X(MODshared, MODimmutable): - case X(MODconst | MODshared, 0): - case X(MODconst | MODshared, MODconst): - case X(MODimmutable, MODwild): - case X(MODshared, MODwild): - case X(MODconst | MODshared, MODwild): - case X(MODwild, 0): - case X(MODwild, MODconst): - case X(MODwild, MODimmutable): - case X(MODwild, MODshared): - case X(MODwild, MODconst | MODshared): - case X(MODwild | MODshared, 0): - case X(MODwild | MODshared, MODconst): - case X(MODwild | MODshared, MODimmutable): - case X(MODwild | MODshared, MODshared): - case X(MODwild | MODshared, MODconst | MODshared): - case X(MODwild | MODshared, MODwild): - case X(MODimmutable, MODwild | MODshared): - case X(MODconst | MODshared, MODwild | MODshared): - case X(MODwild, MODwild | MODshared): - - // foo(U:immutable(U)) T => nomatch - // foo(U:immutable(U)) const(T) => nomatch - // foo(U:immutable(U)) shared(T) => nomatch - // foo(U:immutable(U)) const(shared(T)) => nomatch - // foo(U:const(U)) shared(T) => nomatch - // foo(U:shared(U)) T => nomatch - // foo(U:shared(U)) const(T) => nomatch - // foo(U:shared(U)) immutable(T) => nomatch - // foo(U:const(shared(U)) T => nomatch - // foo(U:const(shared(U)) const(T) => nomatch - // foo(U:immutable(U)) wild(T) => nomatch - // foo(U:shared(U)) wild(T) => nomatch - // foo(U:const(shared(U)) wild(T) => nomatch - // foo(U:wild(U)) T => nomatch - // foo(U:wild(U)) const(T) => nomatch - // foo(U:wild(U)) immutable(T) => nomatch - // foo(U:wild(U)) shared(T) => nomatch - // foo(U:wild(U)) const(shared(T)) => nomatch - // foo(U:wild(shared(U)) T => nomatch - // foo(U:wild(shared(U)) const(T) => nomatch - // foo(U:wild(shared(U)) immutable(T) => nomatch - // foo(U:wild(shared(U)) shared(T) => nomatch - // foo(U:wild(shared(U)) const(shared(T)) => nomatch - // foo(U:wild(shared(U)) wild(T) => nomatch - // foo(U:immutable(U)) wild(shared(T)) => nomatch - // foo(U:const(shared(U))) wild(shared(T)) => nomatch - // foo(U:wild(U)) wild(shared(T)) => nomatch - //if (!at) - goto Lnomatch; - break; - - default: - assert(0); - } - #undef X - - if (tt->equals(at)) - goto Lexact; - else if (tt->ty == Tclass && at->ty == Tclass) - { - return tt->implicitConvTo(at); - } - else if (tt->ty == Tsarray && at->ty == Tarray && - tt->nextOf()->implicitConvTo(at->nextOf()) >= MATCHconst) - { - goto Lexact; - } - else - goto Lnomatch; - } - else if (tparam->ty == Ttypeof) - { - /* Need a loc to go with the semantic routine. - */ - Loc loc; - if (parameters->dim) - { - TemplateParameter *tp = parameters->tdata()[0]; - loc = tp->loc; - } - - tparam = tparam->semantic(loc, sc); - } - - if (ty != tparam->ty) - { -#if DMDV2 - // Can't instantiate AssociativeArray!() without a scope - if (tparam->ty == Taarray && !((TypeAArray*)tparam)->sc) - ((TypeAArray*)tparam)->sc = sc; - - MATCH m = implicitConvTo(tparam); - if (m == MATCHnomatch) - { - Type *at = aliasthisOf(); - if (at) - m = at->deduceType(sc, tparam, parameters, dedtypes, wildmatch); - } - return m; -#else - return implicitConvTo(tparam); -#endif - } - - if (nextOf()) - return nextOf()->deduceType(sc, tparam->nextOf(), parameters, dedtypes, wildmatch); - -Lexact: - return MATCHexact; - -Lnomatch: - return MATCHnomatch; - -#if DMDV2 -Lconst: - return MATCHconst; -#endif -} - -#if DMDV2 -MATCH TypeVector::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, - Objects *dedtypes, unsigned *wildmatch) -{ -#if 0 - printf("TypeVector::deduceType()\n"); - printf("\tthis = %d, ", ty); print(); - printf("\ttparam = %d, ", tparam->ty); tparam->print(); -#endif - if (tparam->ty == Tvector) - { TypeVector *tp = (TypeVector *)tparam; - return basetype->deduceType(sc, tp->basetype, parameters, dedtypes, wildmatch); - } - return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); -} -#endif - -#if DMDV2 -MATCH TypeDArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, - Objects *dedtypes, unsigned *wildmatch) -{ -#if 0 - printf("TypeDArray::deduceType()\n"); - printf("\tthis = %d, ", ty); print(); - printf("\ttparam = %d, ", tparam->ty); tparam->print(); -#endif - return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); -} -#endif - -MATCH TypeSArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, - Objects *dedtypes, unsigned *wildmatch) -{ -#if 0 - printf("TypeSArray::deduceType()\n"); - printf("\tthis = %d, ", ty); print(); - printf("\ttparam = %d, ", tparam->ty); tparam->print(); -#endif - - // Extra check that array dimensions must match - if (tparam) - { - if (tparam->ty == Tarray) - { MATCH m; - - m = next->deduceType(sc, tparam->nextOf(), parameters, dedtypes, wildmatch); - if (m == MATCHexact) - m = MATCHconvert; - return m; - } - - Identifier *id = NULL; - if (tparam->ty == Tsarray) - { - TypeSArray *tp = (TypeSArray *)tparam; - if (tp->dim->op == TOKvar && - ((VarExp *)tp->dim)->var->storage_class & STCtemplateparameter) - { - id = ((VarExp *)tp->dim)->var->ident; - } - else if (dim->toInteger() != tp->dim->toInteger()) - return MATCHnomatch; - } - else if (tparam->ty == Taarray) - { - TypeAArray *tp = (TypeAArray *)tparam; - if (tp->index->ty == Tident && - ((TypeIdentifier *)tp->index)->idents.dim == 0) - { - id = ((TypeIdentifier *)tp->index)->ident; - } - } - if (id) - { - // This code matches code in TypeInstance::deduceType() - int i = templateIdentifierLookup(id, parameters); - if (i == -1) - goto Lnomatch; - TemplateParameter *tprm = parameters->tdata()[i]; - TemplateValueParameter *tvp = tprm->isTemplateValueParameter(); - if (!tvp) - goto Lnomatch; - Expression *e = (Expression *)dedtypes->tdata()[i]; - if (e) - { - if (!dim->equals(e)) - goto Lnomatch; - } - else - { - Type *vt = tvp->valType->semantic(0, sc); - MATCH m = (MATCH)dim->implicitConvTo(vt); - if (!m) - goto Lnomatch; - dedtypes->tdata()[i] = dim; - } - return next->deduceType(sc, tparam->nextOf(), parameters, dedtypes, wildmatch); - } - } - return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); - - Lnomatch: - return MATCHnomatch; -} - -MATCH TypeAArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch) -{ -#if 0 - printf("TypeAArray::deduceType()\n"); - printf("\tthis = %d, ", ty); print(); - printf("\ttparam = %d, ", tparam->ty); tparam->print(); -#endif - - // Extra check that index type must match - if (tparam && tparam->ty == Taarray) - { - TypeAArray *tp = (TypeAArray *)tparam; - if (!index->deduceType(sc, tp->index, parameters, dedtypes, wildmatch)) - { - return MATCHnomatch; - } - } - return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); -} - -MATCH TypeFunction::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch) -{ - //printf("TypeFunction::deduceType()\n"); - //printf("\tthis = %d, ", ty); print(); - //printf("\ttparam = %d, ", tparam->ty); tparam->print(); - - // Extra check that function characteristics must match - if (tparam && tparam->ty == Tfunction) - { - TypeFunction *tp = (TypeFunction *)tparam; - if (varargs != tp->varargs || - linkage != tp->linkage) - return MATCHnomatch; - - size_t nfargs = Parameter::dim(this->parameters); - size_t nfparams = Parameter::dim(tp->parameters); - - // bug 2579 fix: Apply function parameter storage classes to parameter types - for (size_t i = 0; i < nfparams; i++) - { - Parameter *fparam = Parameter::getNth(tp->parameters, i); - fparam->type = fparam->type->addStorageClass(fparam->storageClass); - fparam->storageClass &= ~(STC_TYPECTOR | STCin); - } - //printf("\t-> this = %d, ", ty); print(); - //printf("\t-> tparam = %d, ", tparam->ty); tparam->print(); - - /* See if tuple match - */ - if (nfparams > 0 && nfargs >= nfparams - 1) - { - /* See if 'A' of the template parameter matches 'A' - * of the type of the last function parameter. - */ - Parameter *fparam = Parameter::getNth(tp->parameters, nfparams - 1); - assert(fparam); - assert(fparam->type); - if (fparam->type->ty != Tident) - goto L1; - TypeIdentifier *tid = (TypeIdentifier *)fparam->type; - if (tid->idents.dim) - goto L1; - - /* Look through parameters to find tuple matching tid->ident - */ - size_t tupi = 0; - for (; 1; tupi++) - { if (tupi == parameters->dim) - goto L1; - TemplateParameter *t = parameters->tdata()[tupi]; - TemplateTupleParameter *tup = t->isTemplateTupleParameter(); - if (tup && tup->ident->equals(tid->ident)) - break; - } - - /* The types of the function arguments [nfparams - 1 .. nfargs] - * now form the tuple argument. - */ - size_t tuple_dim = nfargs - (nfparams - 1); - - /* See if existing tuple, and whether it matches or not - */ - Object *o = dedtypes->tdata()[tupi]; - if (o) - { // Existing deduced argument must be a tuple, and must match - Tuple *t = isTuple(o); - if (!t || t->objects.dim != tuple_dim) - return MATCHnomatch; - for (size_t i = 0; i < tuple_dim; i++) - { Parameter *arg = Parameter::getNth(this->parameters, nfparams - 1 + i); - if (!arg->type->equals(t->objects.tdata()[i])) - return MATCHnomatch; - } - } - else - { // Create new tuple - Tuple *t = new Tuple(); - t->objects.setDim(tuple_dim); - for (size_t i = 0; i < tuple_dim; i++) - { Parameter *arg = Parameter::getNth(this->parameters, nfparams - 1 + i); - t->objects.tdata()[i] = arg->type; - } - dedtypes->tdata()[tupi] = t; - } - nfparams--; // don't consider the last parameter for type deduction - goto L2; - } - - L1: - if (nfargs != nfparams) - return MATCHnomatch; - L2: - for (size_t i = 0; i < nfparams; i++) - { - Parameter *a = Parameter::getNth(this->parameters, i); - Parameter *ap = Parameter::getNth(tp->parameters, i); - if (a->storageClass != ap->storageClass || - !a->type->deduceType(sc, ap->type, parameters, dedtypes, wildmatch)) - return MATCHnomatch; - } - } - return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); -} - -MATCH TypeIdentifier::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch) -{ - // Extra check - if (tparam && tparam->ty == Tident) - { - TypeIdentifier *tp = (TypeIdentifier *)tparam; - - for (size_t i = 0; i < idents.dim; i++) - { - Identifier *id1 = idents.tdata()[i]; - Identifier *id2 = tp->idents.tdata()[i]; - - if (!id1->equals(id2)) - return MATCHnomatch; - } - } - return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); -} - -MATCH TypeInstance::deduceType(Scope *sc, - Type *tparam, TemplateParameters *parameters, - Objects *dedtypes, unsigned *wildmatch) -{ -#if 0 - printf("TypeInstance::deduceType()\n"); - printf("\tthis = %d, ", ty); print(); - printf("\ttparam = %d, ", tparam->ty); tparam->print(); -#endif - - // Extra check - if (tparam && tparam->ty == Tinstance) - { - TypeInstance *tp = (TypeInstance *)tparam; - - //printf("tempinst->tempdecl = %p\n", tempinst->tempdecl); - //printf("tp->tempinst->tempdecl = %p\n", tp->tempinst->tempdecl); - if (!tp->tempinst->tempdecl) - { //printf("tp->tempinst->name = '%s'\n", tp->tempinst->name->toChars()); - if (!tp->tempinst->name->equals(tempinst->name)) - { - /* Handle case of: - * template Foo(T : sa!(T), alias sa) - */ - int i = templateIdentifierLookup(tp->tempinst->name, parameters); - if (i == -1) - { /* Didn't find it as a parameter identifier. Try looking - * it up and seeing if is an alias. See Bugzilla 1454 - */ - Dsymbol *s = tempinst->tempdecl->scope->search(0, tp->tempinst->name, NULL); - if (s) - { - s = s->toAlias(); - TemplateDeclaration *td = s->isTemplateDeclaration(); - if (td && td == tempinst->tempdecl) - goto L2; - } - goto Lnomatch; - } - TemplateParameter *tpx = parameters->tdata()[i]; - // This logic duplicates tpx->matchArg() - TemplateAliasParameter *ta = tpx->isTemplateAliasParameter(); - if (!ta) - goto Lnomatch; - Object *sa = tempinst->tempdecl; - if (!sa) - goto Lnomatch; - if (ta->specAlias && sa != ta->specAlias) - goto Lnomatch; - if (dedtypes->tdata()[i]) - { // Must match already deduced symbol - Object *s = dedtypes->tdata()[i]; - - if (s != sa) - goto Lnomatch; - } - dedtypes->tdata()[i] = sa; - } - } - else if (tempinst->tempdecl != tp->tempinst->tempdecl) - goto Lnomatch; - - L2: - - for (size_t i = 0; 1; i++) - { - //printf("\ttest: tempinst->tiargs[%d]\n", i); - Object *o1; - if (i < tempinst->tiargs->dim) - o1 = tempinst->tiargs->tdata()[i]; - else if (i < tempinst->tdtypes.dim && i < tp->tempinst->tiargs->dim) - // Pick up default arg - o1 = tempinst->tdtypes.tdata()[i]; - else - break; - - if (i >= tp->tempinst->tiargs->dim) - goto Lnomatch; - - Object *o2 = tp->tempinst->tiargs->tdata()[i]; - - Type *t1 = isType(o1); - Type *t2 = isType(o2); - - Expression *e1 = isExpression(o1); - Expression *e2 = isExpression(o2); - - Dsymbol *s1 = isDsymbol(o1); - Dsymbol *s2 = isDsymbol(o2); - - Tuple *v1 = isTuple(o1); - Tuple *v2 = isTuple(o2); -#if 0 - if (t1) printf("t1 = %s\n", t1->toChars()); - if (t2) printf("t2 = %s\n", t2->toChars()); - if (e1) printf("e1 = %s\n", e1->toChars()); - if (e2) printf("e2 = %s\n", e2->toChars()); - if (s1) printf("s1 = %s\n", s1->toChars()); - if (s2) printf("s2 = %s\n", s2->toChars()); - if (v1) printf("v1 = %s\n", v1->toChars()); - if (v2) printf("v2 = %s\n", v2->toChars()); -#endif - - TemplateTupleParameter *ttp; - int j; - if (t2 && - t2->ty == Tident && - i == tp->tempinst->tiargs->dim - 1 && - i == tempinst->tempdecl->parameters->dim - 1 && - (ttp = tempinst->tempdecl->isVariadic()) != NULL) - { - /* Given: - * struct A(B...) {} - * alias A!(int, float) X; - * static if (!is(X Y == A!(Z), Z)) - * deduce that Z is a tuple(int, float) - */ - - j = templateParameterLookup(t2, parameters); - if (j == -1) - goto Lnomatch; - - /* Create tuple from remaining args - */ - Tuple *vt = new Tuple(); - size_t vtdim = tempinst->tiargs->dim - i; - vt->objects.setDim(vtdim); - for (size_t k = 0; k < vtdim; k++) - vt->objects.tdata()[k] = tempinst->tiargs->tdata()[i + k]; - - Tuple *v = (Tuple *)dedtypes->tdata()[j]; - if (v) - { - if (!match(v, vt, tempinst->tempdecl, sc)) - goto Lnomatch; - } - else - dedtypes->tdata()[j] = vt; - break; //return MATCHexact; - } - - if (t1 && t2) - { - if (!t1->deduceType(sc, t2, parameters, dedtypes, wildmatch)) - goto Lnomatch; - } - else if (e1 && e2) - { - if (!e1->equals(e2)) - { if (e2->op == TOKvar) - { - /* - * (T:Number!(e2), int e2) - */ - j = templateIdentifierLookup(((VarExp *)e2)->var->ident, parameters); - goto L1; - } - goto Lnomatch; - } - } - else if (e1 && t2 && t2->ty == Tident) - { - j = templateParameterLookup(t2, parameters); - L1: - if (j == -1) - goto Lnomatch; - TemplateParameter *tp = parameters->tdata()[j]; - // BUG: use tp->matchArg() instead of the following - TemplateValueParameter *tv = tp->isTemplateValueParameter(); - if (!tv) - goto Lnomatch; - Expression *e = (Expression *)dedtypes->tdata()[j]; - if (e) - { - if (!e1->equals(e)) - goto Lnomatch; - } - else - { Type *vt = tv->valType->semantic(0, sc); - MATCH m = (MATCH)e1->implicitConvTo(vt); - if (!m) - goto Lnomatch; - dedtypes->tdata()[j] = e1; - } - } - else if (s1 && t2 && t2->ty == Tident) - { - j = templateParameterLookup(t2, parameters); - if (j == -1) - goto Lnomatch; - TemplateParameter *tp = parameters->tdata()[j]; - // BUG: use tp->matchArg() instead of the following - TemplateAliasParameter *ta = tp->isTemplateAliasParameter(); - if (!ta) - goto Lnomatch; - Dsymbol *s = (Dsymbol *)dedtypes->tdata()[j]; - if (s) - { - if (!s1->equals(s)) - goto Lnomatch; - } - else - { - dedtypes->tdata()[j] = s1; - } - } - else if (s1 && s2) - { - if (!s1->equals(s2)) - goto Lnomatch; - } - // BUG: Need to handle tuple parameters - else - goto Lnomatch; - } - } - return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); - -Lnomatch: - //printf("no match\n"); - return MATCHnomatch; -} - -MATCH TypeStruct::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch) -{ - //printf("TypeStruct::deduceType()\n"); - //printf("\tthis->parent = %s, ", sym->parent->toChars()); print(); - //printf("\ttparam = %d, ", tparam->ty); tparam->print(); - - /* If this struct is a template struct, and we're matching - * it against a template instance, convert the struct type - * to a template instance, too, and try again. - */ - TemplateInstance *ti = sym->parent->isTemplateInstance(); - - if (tparam && tparam->ty == Tinstance) - { - if (ti && ti->toAlias() == sym) - { - TypeInstance *t = new TypeInstance(0, ti); - return t->deduceType(sc, tparam, parameters, dedtypes, wildmatch); - } - - /* Match things like: - * S!(T).foo - */ - TypeInstance *tpi = (TypeInstance *)tparam; - if (tpi->idents.dim) - { Identifier *id = tpi->idents.tdata()[tpi->idents.dim - 1]; - if (id->dyncast() == DYNCAST_IDENTIFIER && sym->ident->equals(id)) - { - Type *tparent = sym->parent->getType(); - if (tparent) - { - /* Slice off the .foo in S!(T).foo - */ - tpi->idents.dim--; - MATCH m = tparent->deduceType(sc, tpi, parameters, dedtypes, wildmatch); - tpi->idents.dim++; - return m; - } - } - } - } - - // Extra check - if (tparam && tparam->ty == Tstruct) - { - TypeStruct *tp = (TypeStruct *)tparam; - - //printf("\t%d\n", (MATCH) implicitConvTo(tp)); - return implicitConvTo(tp); - } - return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); -} - -MATCH TypeEnum::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch) -{ - // Extra check - if (tparam && tparam->ty == Tenum) - { - TypeEnum *tp = (TypeEnum *)tparam; - - if (sym != tp->sym) - return MATCHnomatch; - } - return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); -} - -MATCH TypeTypedef::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch) -{ - // Extra check - if (tparam && tparam->ty == Ttypedef) - { - TypeTypedef *tp = (TypeTypedef *)tparam; - - if (sym != tp->sym) - return MATCHnomatch; - } - return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); -} - -/* Helper for TypeClass::deduceType(). - * Classes can match with implicit conversion to a base class or interface. - * This is complicated, because there may be more than one base class which - * matches. In such cases, one or more parameters remain ambiguous. - * For example, - * - * interface I(X, Y) {} - * class C : I(uint, double), I(char, double) {} - * C x; - * foo(T, U)( I!(T, U) x) - * - * deduces that U is double, but T remains ambiguous (could be char or uint). - * - * Given a baseclass b, and initial deduced types 'dedtypes', this function - * tries to match tparam with b, and also tries all base interfaces of b. - * If a match occurs, numBaseClassMatches is incremented, and the new deduced - * types are ANDed with the current 'best' estimate for dedtypes. - */ -void deduceBaseClassParameters(BaseClass *b, - Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, - Objects *best, int &numBaseClassMatches) -{ - TemplateInstance *parti = b->base ? b->base->parent->isTemplateInstance() : NULL; - if (parti) - { - // Make a temporary copy of dedtypes so we don't destroy it - Objects *tmpdedtypes = new Objects(); - tmpdedtypes->setDim(dedtypes->dim); - memcpy(tmpdedtypes->tdata(), dedtypes->tdata(), dedtypes->dim * sizeof(void *)); - - TypeInstance *t = new TypeInstance(0, parti); - MATCH m = t->deduceType(sc, tparam, parameters, tmpdedtypes); - if (m != MATCHnomatch) - { - // If this is the first ever match, it becomes our best estimate - if (numBaseClassMatches==0) - memcpy(best->tdata(), tmpdedtypes->tdata(), tmpdedtypes->dim * sizeof(void *)); - else for (size_t k = 0; k < tmpdedtypes->dim; ++k) - { - // If we've found more than one possible type for a parameter, - // mark it as unknown. - if (tmpdedtypes->tdata()[k] != best->tdata()[k]) - best->tdata()[k] = dedtypes->tdata()[k]; - } - ++numBaseClassMatches; - } - } - // Now recursively test the inherited interfaces - for (size_t j = 0; j < b->baseInterfaces_dim; ++j) - { - deduceBaseClassParameters( &(b->baseInterfaces)[j], - sc, tparam, parameters, dedtypes, - best, numBaseClassMatches); - } - -} - -MATCH TypeClass::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch) -{ - //printf("TypeClass::deduceType(this = %s)\n", toChars()); - - /* If this class is a template class, and we're matching - * it against a template instance, convert the class type - * to a template instance, too, and try again. - */ - TemplateInstance *ti = sym->parent->isTemplateInstance(); - - if (tparam && tparam->ty == Tinstance) - { - if (ti && ti->toAlias() == sym) - { - TypeInstance *t = new TypeInstance(0, ti); - MATCH m = t->deduceType(sc, tparam, parameters, dedtypes, wildmatch); - // Even if the match fails, there is still a chance it could match - // a base class. - if (m != MATCHnomatch) - return m; - } - - /* Match things like: - * S!(T).foo - */ - TypeInstance *tpi = (TypeInstance *)tparam; - if (tpi->idents.dim) - { Identifier *id = tpi->idents.tdata()[tpi->idents.dim - 1]; - if (id->dyncast() == DYNCAST_IDENTIFIER && sym->ident->equals(id)) - { - Type *tparent = sym->parent->getType(); - if (tparent) - { - /* Slice off the .foo in S!(T).foo - */ - tpi->idents.dim--; - MATCH m = tparent->deduceType(sc, tpi, parameters, dedtypes, wildmatch); - tpi->idents.dim++; - return m; - } - } - } - - // If it matches exactly or via implicit conversion, we're done - MATCH m = Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); - if (m != MATCHnomatch) - return m; - - /* There is still a chance to match via implicit conversion to - * a base class or interface. Because there could be more than one such - * match, we need to check them all. - */ - - int numBaseClassMatches = 0; // Have we found an interface match? - - // Our best guess at dedtypes - Objects *best = new Objects(); - best->setDim(dedtypes->dim); - - ClassDeclaration *s = sym; - while(s && s->baseclasses->dim > 0) - { - // Test the base class - deduceBaseClassParameters((s->baseclasses->tdata()[0]), - sc, tparam, parameters, dedtypes, - best, numBaseClassMatches); - - // Test the interfaces inherited by the base class - for (size_t i = 0; i < s->interfaces_dim; ++i) - { - BaseClass *b = s->interfaces[i]; - deduceBaseClassParameters(b, sc, tparam, parameters, dedtypes, - best, numBaseClassMatches); - } - s = ((s->baseclasses->tdata()[0]))->base; - } - - if (numBaseClassMatches == 0) - return MATCHnomatch; - - // If we got at least one match, copy the known types into dedtypes - memcpy(dedtypes->tdata(), best->tdata(), best->dim * sizeof(void *)); - return MATCHconvert; - } - - // Extra check - if (tparam && tparam->ty == Tclass) - { - TypeClass *tp = (TypeClass *)tparam; - - //printf("\t%d\n", (MATCH) implicitConvTo(tp)); - return implicitConvTo(tp); - } - return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); -} - -/* ======================== TemplateParameter =============================== */ - -TemplateParameter::TemplateParameter(Loc loc, Identifier *ident) -{ - this->loc = loc; - this->ident = ident; - this->sparam = NULL; -} - -TemplateTypeParameter *TemplateParameter::isTemplateTypeParameter() -{ - return NULL; -} - -TemplateValueParameter *TemplateParameter::isTemplateValueParameter() -{ - return NULL; -} - -TemplateAliasParameter *TemplateParameter::isTemplateAliasParameter() -{ - return NULL; -} - -TemplateTupleParameter *TemplateParameter::isTemplateTupleParameter() -{ - return NULL; -} - -#if DMDV2 -TemplateThisParameter *TemplateParameter::isTemplateThisParameter() -{ - return NULL; -} -#endif - -/* ======================== TemplateTypeParameter =========================== */ - -// type-parameter - -Type *TemplateTypeParameter::tdummy = NULL; - -TemplateTypeParameter::TemplateTypeParameter(Loc loc, Identifier *ident, Type *specType, - Type *defaultType) - : TemplateParameter(loc, ident) -{ - this->ident = ident; - this->specType = specType; - this->defaultType = defaultType; -} - -TemplateTypeParameter *TemplateTypeParameter::isTemplateTypeParameter() -{ - return this; -} - -TemplateParameter *TemplateTypeParameter::syntaxCopy() -{ - TemplateTypeParameter *tp = new TemplateTypeParameter(loc, ident, specType, defaultType); - if (tp->specType) - tp->specType = specType->syntaxCopy(); - if (defaultType) - tp->defaultType = defaultType->syntaxCopy(); - return tp; -} - -void TemplateTypeParameter::declareParameter(Scope *sc) -{ - //printf("TemplateTypeParameter::declareParameter('%s')\n", ident->toChars()); - TypeIdentifier *ti = new TypeIdentifier(loc, ident); - sparam = new AliasDeclaration(loc, ident, ti); - if (!sc->insert(sparam)) - error(loc, "parameter '%s' multiply defined", ident->toChars()); -} - -void TemplateTypeParameter::semantic(Scope *sc) -{ - //printf("TemplateTypeParameter::semantic('%s')\n", ident->toChars()); - if (specType) - { - specType = specType->semantic(loc, sc); - } -#if 0 // Don't do semantic() until instantiation - if (defaultType) - { - defaultType = defaultType->semantic(loc, sc); - } -#endif -} - -/**************************************** - * Determine if two TemplateParameters are the same - * as far as TemplateDeclaration overloading goes. - * Returns: - * 1 match - * 0 no match - */ - -int TemplateTypeParameter::overloadMatch(TemplateParameter *tp) -{ - TemplateTypeParameter *ttp = tp->isTemplateTypeParameter(); - - if (ttp) - { - if (specType != ttp->specType) - goto Lnomatch; - - if (specType && !specType->equals(ttp->specType)) - goto Lnomatch; - - return 1; // match - } - -Lnomatch: - return 0; -} - -/******************************************* - * Match to a particular TemplateParameter. - * Input: - * i i'th argument - * tiargs[] actual arguments to template instance - * parameters[] template parameters - * dedtypes[] deduced arguments to template instance - * *psparam set to symbol declared and initialized to dedtypes[i] - */ - -MATCH TemplateTypeParameter::matchArg(Scope *sc, Objects *tiargs, - size_t i, TemplateParameters *parameters, Objects *dedtypes, - Declaration **psparam) -{ - //printf("TemplateTypeParameter::matchArg()\n"); - Object *oarg; - MATCH m = MATCHexact; - Type *ta; - - if (i < tiargs->dim) - oarg = tiargs->tdata()[i]; - else - { // Get default argument instead - oarg = defaultArg(loc, sc); - if (!oarg) - { assert(i < dedtypes->dim); - // It might have already been deduced - oarg = dedtypes->tdata()[i]; - if (!oarg) - { - goto Lnomatch; - } - } - } - - ta = isType(oarg); - if (!ta) - { - //printf("%s %p %p %p\n", oarg->toChars(), isExpression(oarg), isDsymbol(oarg), isTuple(oarg)); - goto Lnomatch; - } - //printf("ta is %s\n", ta->toChars()); - - if (specType) - { - if (!ta || ta == tdummy) - goto Lnomatch; - - //printf("\tcalling deduceType(): ta is %s, specType is %s\n", ta->toChars(), specType->toChars()); - MATCH m2 = ta->deduceType(sc, specType, parameters, dedtypes); - if (m2 == MATCHnomatch) - { //printf("\tfailed deduceType\n"); - goto Lnomatch; - } - - if (m2 < m) - m = m2; - if (dedtypes->tdata()[i]) - ta = (Type *)dedtypes->tdata()[i]; - } - else - { - if (dedtypes->tdata()[i]) - { // Must match already deduced type - Type *t = (Type *)dedtypes->tdata()[i]; - - if (!t->equals(ta)) - { //printf("t = %s ta = %s\n", t->toChars(), ta->toChars()); - goto Lnomatch; - } - } - else - { - // So that matches with specializations are better - m = MATCHconvert; - } - } - dedtypes->tdata()[i] = ta; - - *psparam = new AliasDeclaration(loc, ident, ta); - //printf("\tm = %d\n", m); - return m; - -Lnomatch: - *psparam = NULL; - //printf("\tm = %d\n", MATCHnomatch); - return MATCHnomatch; -} - - -void TemplateTypeParameter::print(Object *oarg, Object *oded) -{ - printf(" %s\n", ident->toChars()); - - Type *t = isType(oarg); - Type *ta = isType(oded); - - assert(ta); - - if (specType) - printf("\tSpecialization: %s\n", specType->toChars()); - if (defaultType) - printf("\tDefault: %s\n", defaultType->toChars()); - printf("\tParameter: %s\n", t ? t->toChars() : "NULL"); - printf("\tDeduced Type: %s\n", ta->toChars()); -} - - -void TemplateTypeParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(ident->toChars()); - if (specType) - { - buf->writestring(" : "); - specType->toCBuffer(buf, NULL, hgs); - } - if (defaultType) - { - buf->writestring(" = "); - defaultType->toCBuffer(buf, NULL, hgs); - } -} - - -void *TemplateTypeParameter::dummyArg() -{ Type *t; - - if (specType) - t = specType; - else - { // Use this for alias-parameter's too (?) - if (!tdummy) - tdummy = new TypeIdentifier(loc, ident); - t = tdummy; - } - return (void *)t; -} - - -Object *TemplateTypeParameter::specialization() -{ - return specType; -} - - -Object *TemplateTypeParameter::defaultArg(Loc loc, Scope *sc) -{ - Type *t; - - t = defaultType; - if (t) - { - t = t->syntaxCopy(); - t = t->semantic(loc, sc); - } - return t; -} - -/* ======================== TemplateThisParameter =========================== */ - -#if DMDV2 -// this-parameter - -TemplateThisParameter::TemplateThisParameter(Loc loc, Identifier *ident, - Type *specType, - Type *defaultType) - : TemplateTypeParameter(loc, ident, specType, defaultType) -{ -} - -TemplateThisParameter *TemplateThisParameter::isTemplateThisParameter() -{ - return this; -} - -TemplateParameter *TemplateThisParameter::syntaxCopy() -{ - TemplateThisParameter *tp = new TemplateThisParameter(loc, ident, specType, defaultType); - if (tp->specType) - tp->specType = specType->syntaxCopy(); - if (defaultType) - tp->defaultType = defaultType->syntaxCopy(); - return tp; -} - -void TemplateThisParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("this "); - TemplateTypeParameter::toCBuffer(buf, hgs); -} -#endif - -/* ======================== TemplateAliasParameter ========================== */ - -// alias-parameter - -Dsymbol *TemplateAliasParameter::sdummy = NULL; - -TemplateAliasParameter::TemplateAliasParameter(Loc loc, Identifier *ident, - Type *specType, Object *specAlias, Object *defaultAlias) - : TemplateParameter(loc, ident) -{ - this->ident = ident; - this->specType = specType; - this->specAlias = specAlias; - this->defaultAlias = defaultAlias; -} - -TemplateAliasParameter *TemplateAliasParameter::isTemplateAliasParameter() -{ - return this; -} - -TemplateParameter *TemplateAliasParameter::syntaxCopy() -{ - TemplateAliasParameter *tp = new TemplateAliasParameter(loc, ident, specType, specAlias, defaultAlias); - if (tp->specType) - tp->specType = specType->syntaxCopy(); - tp->specAlias = objectSyntaxCopy(specAlias); - tp->defaultAlias = objectSyntaxCopy(defaultAlias); - return tp; -} - -void TemplateAliasParameter::declareParameter(Scope *sc) -{ - TypeIdentifier *ti = new TypeIdentifier(loc, ident); - sparam = new AliasDeclaration(loc, ident, ti); - if (!sc->insert(sparam)) - error(loc, "parameter '%s' multiply defined", ident->toChars()); -} - -Object *aliasParameterSemantic(Loc loc, Scope *sc, Object *o) -{ - if (o) - { - Expression *ea = isExpression(o); - Type *ta = isType(o); - if (ta) - { Dsymbol *s = ta->toDsymbol(sc); - if (s) - o = s; - else - o = ta->semantic(loc, sc); - } - else if (ea) - { - ea = ea->semantic(sc); - o = ea->optimize(WANTvalue | WANTinterpret); - } - } - return o; -} - -void TemplateAliasParameter::semantic(Scope *sc) -{ - if (specType) - { - specType = specType->semantic(loc, sc); - } - specAlias = aliasParameterSemantic(loc, sc, specAlias); -#if 0 // Don't do semantic() until instantiation - if (defaultAlias) - defaultAlias = defaultAlias->semantic(loc, sc); -#endif -} - -int TemplateAliasParameter::overloadMatch(TemplateParameter *tp) -{ - TemplateAliasParameter *tap = tp->isTemplateAliasParameter(); - - if (tap) - { - if (specAlias != tap->specAlias) - goto Lnomatch; - - return 1; // match - } - -Lnomatch: - return 0; -} - -MATCH TemplateAliasParameter::matchArg(Scope *sc, Objects *tiargs, - size_t i, TemplateParameters *parameters, Objects *dedtypes, - Declaration **psparam) -{ - Object *sa; - Object *oarg; - Expression *ea; - Dsymbol *s; - - //printf("TemplateAliasParameter::matchArg()\n"); - - if (i < tiargs->dim) - oarg = tiargs->tdata()[i]; - else - { // Get default argument instead - oarg = defaultArg(loc, sc); - if (!oarg) - { assert(i < dedtypes->dim); - // It might have already been deduced - oarg = dedtypes->tdata()[i]; - if (!oarg) - goto Lnomatch; - } - } - - sa = getDsymbol(oarg); - if (sa) - { - /* specType means the alias must be a declaration with a type - * that matches specType. - */ - if (specType) - { Declaration *d = ((Dsymbol *)sa)->isDeclaration(); - if (!d) - goto Lnomatch; - if (!d->type->equals(specType)) - goto Lnomatch; - } - } - else - { - sa = oarg; - ea = isExpression(oarg); - if (ea) - { if (specType) - { - if (!ea->type->equals(specType)) - goto Lnomatch; - } - } - else - goto Lnomatch; - } - - if (specAlias) - { - if (sa == sdummy) - goto Lnomatch; - if (sa != specAlias) - goto Lnomatch; - } - else if (dedtypes->tdata()[i]) - { // Must match already deduced symbol - Object *si = dedtypes->tdata()[i]; - - if (!sa || si != sa) - goto Lnomatch; - } - dedtypes->tdata()[i] = sa; - - s = isDsymbol(sa); - if (s) - *psparam = new AliasDeclaration(loc, ident, s); - else - { - assert(ea); - - // Declare manifest constant - Initializer *init = new ExpInitializer(loc, ea); - VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init); - v->storage_class = STCmanifest; - v->semantic(sc); - *psparam = v; - } - return MATCHexact; - -Lnomatch: - *psparam = NULL; - //printf("\tm = %d\n", MATCHnomatch); - return MATCHnomatch; -} - - -void TemplateAliasParameter::print(Object *oarg, Object *oded) -{ - printf(" %s\n", ident->toChars()); - - Dsymbol *sa = isDsymbol(oded); - assert(sa); - - printf("\tParameter alias: %s\n", sa->toChars()); -} - -void TemplateAliasParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("alias "); - if (specType) - { HdrGenState hgs1; - specType->toCBuffer(buf, ident, &hgs1); - } - else - buf->writestring(ident->toChars()); - if (specAlias) - { - buf->writestring(" : "); - ObjectToCBuffer(buf, hgs, specAlias); - } - if (defaultAlias) - { - buf->writestring(" = "); - ObjectToCBuffer(buf, hgs, defaultAlias); - } -} - - -void *TemplateAliasParameter::dummyArg() -{ Object *s; - - s = specAlias; - if (!s) - { - if (!sdummy) - sdummy = new Dsymbol(); - s = sdummy; - } - return (void*)s; -} - - -Object *TemplateAliasParameter::specialization() -{ - return specAlias; -} - - -Object *TemplateAliasParameter::defaultArg(Loc loc, Scope *sc) -{ - Object *da = defaultAlias; - Type *ta = isType(defaultAlias); - if (ta) - { - if (ta->ty == Tinstance) - { - // If the default arg is a template, instantiate for each type - da = ta->syntaxCopy(); - } - } - - Object *o = aliasParameterSemantic(loc, sc, da); - return o; -} - -/* ======================== TemplateValueParameter ========================== */ - -// value-parameter - -AA *TemplateValueParameter::edummies = NULL; - -TemplateValueParameter::TemplateValueParameter(Loc loc, Identifier *ident, Type *valType, - Expression *specValue, Expression *defaultValue) - : TemplateParameter(loc, ident) -{ - this->ident = ident; - this->valType = valType; - this->specValue = specValue; - this->defaultValue = defaultValue; -} - -TemplateValueParameter *TemplateValueParameter::isTemplateValueParameter() -{ - return this; -} - -TemplateParameter *TemplateValueParameter::syntaxCopy() -{ - TemplateValueParameter *tp = - new TemplateValueParameter(loc, ident, valType, specValue, defaultValue); - tp->valType = valType->syntaxCopy(); - if (specValue) - tp->specValue = specValue->syntaxCopy(); - if (defaultValue) - tp->defaultValue = defaultValue->syntaxCopy(); - return tp; -} - -void TemplateValueParameter::declareParameter(Scope *sc) -{ - VarDeclaration *v = new VarDeclaration(loc, valType, ident, NULL); - v->storage_class = STCtemplateparameter; - if (!sc->insert(v)) - error(loc, "parameter '%s' multiply defined", ident->toChars()); - sparam = v; -} - -void TemplateValueParameter::semantic(Scope *sc) -{ - bool wasSame = (sparam->type == valType); - sparam->semantic(sc); - if (sparam->type == Type::terror && wasSame) - { /* If sparam has a type error, avoid duplicate errors - * The simple solution of leaving that function if sparam->type == Type::terror - * doesn't quite work because it causes failures in xtest46 for bug 6295 - */ - valType = Type::terror; - return; - } - valType = valType->semantic(loc, sc); - if (!(valType->isintegral() || valType->isfloating() || valType->isString()) && - valType->ty != Tident) - { - if (valType != Type::terror) - error(loc, "arithmetic/string type expected for value-parameter, not %s", valType->toChars()); - } - -#if 0 // defer semantic analysis to arg match - if (specValue) - { Expression *e = specValue; - - e = e->semantic(sc); - e = e->implicitCastTo(sc, valType); - e = e->optimize(WANTvalue | WANTinterpret); - if (e->op == TOKint64 || e->op == TOKfloat64 || - e->op == TOKcomplex80 || e->op == TOKnull || e->op == TOKstring) - specValue = e; - //e->toInteger(); - } - - if (defaultValue) - { Expression *e = defaultValue; - - e = e->semantic(sc); - e = e->implicitCastTo(sc, valType); - e = e->optimize(WANTvalue | WANTinterpret); - if (e->op == TOKint64) - defaultValue = e; - //e->toInteger(); - } -#endif -} - -int TemplateValueParameter::overloadMatch(TemplateParameter *tp) -{ - TemplateValueParameter *tvp = tp->isTemplateValueParameter(); - - if (tvp) - { - if (valType != tvp->valType) - goto Lnomatch; - - if (valType && !valType->equals(tvp->valType)) - goto Lnomatch; - - if (specValue != tvp->specValue) - goto Lnomatch; - - return 1; // match - } - -Lnomatch: - return 0; -} - - -MATCH TemplateValueParameter::matchArg(Scope *sc, - Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, - Declaration **psparam) -{ - //printf("TemplateValueParameter::matchArg()\n"); - - Initializer *init; - Declaration *sparam; - MATCH m = MATCHexact; - Expression *ei; - Object *oarg; - - if (i < tiargs->dim) - oarg = tiargs->tdata()[i]; - else - { // Get default argument instead - oarg = defaultArg(loc, sc); - if (!oarg) - { assert(i < dedtypes->dim); - // It might have already been deduced - oarg = dedtypes->tdata()[i]; - if (!oarg) - goto Lnomatch; - } - } - - ei = isExpression(oarg); - Type *vt; - - if (!ei && oarg) - goto Lnomatch; - - if (ei && ei->op == TOKvar) - { // Resolve const variables that we had skipped earlier - ei = ei->optimize(WANTvalue | WANTinterpret); - } - - //printf("\tvalType: %s, ty = %d\n", valType->toChars(), valType->ty); - vt = valType->semantic(0, sc); - //printf("ei: %s, ei->type: %s\n", ei->toChars(), ei->type->toChars()); - //printf("vt = %s\n", vt->toChars()); - - if (ei->type) - { - m = (MATCH)ei->implicitConvTo(vt); - //printf("m: %d\n", m); - if (!m) - goto Lnomatch; - } - - if (specValue) - { - if (!ei || _aaGetRvalue(edummies, ei->type) == ei) - goto Lnomatch; - - Expression *e = specValue; - - e = e->semantic(sc); - e = e->implicitCastTo(sc, vt); - e = e->optimize(WANTvalue | WANTinterpret); - - ei = ei->syntaxCopy(); - ei = ei->semantic(sc); - ei = ei->implicitCastTo(sc, vt); - ei = ei->optimize(WANTvalue | WANTinterpret); - //printf("\tei: %s, %s\n", ei->toChars(), ei->type->toChars()); - //printf("\te : %s, %s\n", e->toChars(), e->type->toChars()); - if (!ei->equals(e)) - goto Lnomatch; - } - else - { - if (dedtypes->tdata()[i]) - { // Must match already deduced value - Expression *e = (Expression *)dedtypes->tdata()[i]; - - if (!ei || !ei->equals(e)) - goto Lnomatch; - } - else if (m != MATCHexact) - { - ei = ei->implicitCastTo(sc, vt); - ei = ei->optimize(WANTvalue | WANTinterpret); - } - } - dedtypes->tdata()[i] = ei; - - init = new ExpInitializer(loc, ei); - sparam = new VarDeclaration(loc, vt, ident, init); - sparam->storage_class = STCmanifest; - *psparam = sparam; - return m; - -Lnomatch: - //printf("\tno match\n"); - *psparam = NULL; - return MATCHnomatch; -} - - -void TemplateValueParameter::print(Object *oarg, Object *oded) -{ - printf(" %s\n", ident->toChars()); - - Expression *ea = isExpression(oded); - - if (specValue) - printf("\tSpecialization: %s\n", specValue->toChars()); - printf("\tParameter Value: %s\n", ea ? ea->toChars() : "NULL"); -} - - -void TemplateValueParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - valType->toCBuffer(buf, ident, hgs); - if (specValue) - { - buf->writestring(" : "); - specValue->toCBuffer(buf, hgs); - } - if (defaultValue) - { - buf->writestring(" = "); - defaultValue->toCBuffer(buf, hgs); - } -} - - -void *TemplateValueParameter::dummyArg() -{ Expression *e; - - e = specValue; - if (!e) - { - // Create a dummy value - Expression **pe = (Expression **)_aaGet(&edummies, valType); - if (!*pe) - *pe = valType->defaultInit(); - e = *pe; - } - return (void *)e; -} - - -Object *TemplateValueParameter::specialization() -{ - return specValue; -} - - -Object *TemplateValueParameter::defaultArg(Loc loc, Scope *sc) -{ - Expression *e = defaultValue; - if (e) - { - e = e->syntaxCopy(); - e = e->semantic(sc); -#if DMDV2 - e = e->resolveLoc(loc, sc); -#endif - } - return e; -} - -/* ======================== TemplateTupleParameter ========================== */ - -// variadic-parameter - -TemplateTupleParameter::TemplateTupleParameter(Loc loc, Identifier *ident) - : TemplateParameter(loc, ident) -{ - this->ident = ident; -} - -TemplateTupleParameter *TemplateTupleParameter::isTemplateTupleParameter() -{ - return this; -} - -TemplateParameter *TemplateTupleParameter::syntaxCopy() -{ - TemplateTupleParameter *tp = new TemplateTupleParameter(loc, ident); - return tp; -} - -void TemplateTupleParameter::declareParameter(Scope *sc) -{ - TypeIdentifier *ti = new TypeIdentifier(loc, ident); - sparam = new AliasDeclaration(loc, ident, ti); - if (!sc->insert(sparam)) - error(loc, "parameter '%s' multiply defined", ident->toChars()); -} - -void TemplateTupleParameter::semantic(Scope *sc) -{ -} - -int TemplateTupleParameter::overloadMatch(TemplateParameter *tp) -{ - TemplateTupleParameter *tvp = tp->isTemplateTupleParameter(); - - if (tvp) - { - return 1; // match - } - - return 0; -} - -MATCH TemplateTupleParameter::matchArg(Scope *sc, Objects *tiargs, - size_t i, TemplateParameters *parameters, Objects *dedtypes, - Declaration **psparam) -{ - //printf("TemplateTupleParameter::matchArg()\n"); - - /* The rest of the actual arguments (tiargs[]) form the match - * for the variadic parameter. - */ - assert(i + 1 == dedtypes->dim); // must be the last one - Tuple *ovar; - - if (dedtypes->tdata()[i] && isTuple(dedtypes->tdata()[i])) - // It was already been deduced - ovar = isTuple(dedtypes->tdata()[i]); - else if (i + 1 == tiargs->dim && isTuple(tiargs->tdata()[i])) - ovar = isTuple(tiargs->tdata()[i]); - else - { - ovar = new Tuple(); - //printf("ovar = %p\n", ovar); - if (i < tiargs->dim) - { - //printf("i = %d, tiargs->dim = %d\n", i, tiargs->dim); - ovar->objects.setDim(tiargs->dim - i); - for (size_t j = 0; j < ovar->objects.dim; j++) - ovar->objects.tdata()[j] = tiargs->tdata()[i + j]; - } - } - *psparam = new TupleDeclaration(loc, ident, &ovar->objects); - dedtypes->tdata()[i] = ovar; - return MATCHexact; -} - - -void TemplateTupleParameter::print(Object *oarg, Object *oded) -{ - printf(" %s... [", ident->toChars()); - Tuple *v = isTuple(oded); - assert(v); - - //printf("|%d| ", v->objects.dim); - for (size_t i = 0; i < v->objects.dim; i++) - { - if (i) - printf(", "); - - Object *o = v->objects.tdata()[i]; - - Dsymbol *sa = isDsymbol(o); - if (sa) - printf("alias: %s", sa->toChars()); - - Type *ta = isType(o); - if (ta) - printf("type: %s", ta->toChars()); - - Expression *ea = isExpression(o); - if (ea) - printf("exp: %s", ea->toChars()); - - assert(!isTuple(o)); // no nested Tuple arguments - } - - printf("]\n"); -} - -void TemplateTupleParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(ident->toChars()); - buf->writestring("..."); -} - - -void *TemplateTupleParameter::dummyArg() -{ - return NULL; -} - - -Object *TemplateTupleParameter::specialization() -{ - return NULL; -} - - -Object *TemplateTupleParameter::defaultArg(Loc loc, Scope *sc) -{ - return NULL; -} - -/* ======================== TemplateInstance ================================ */ - -TemplateInstance::TemplateInstance(Loc loc, Identifier *ident) - : ScopeDsymbol(NULL) -{ -#if LOG - printf("TemplateInstance(this = %p, ident = '%s')\n", this, ident ? ident->toChars() : "null"); -#endif - this->loc = loc; - this->name = ident; - this->tiargs = NULL; - this->tempdecl = NULL; - this->inst = NULL; - this->tinst = NULL; - this->argsym = NULL; - this->aliasdecl = NULL; - this->semanticRun = PASSinit; - this->semantictiargsdone = 0; - this->withsym = NULL; - this->nest = 0; - this->havetempdecl = 0; - this->isnested = NULL; - this->speculative = 0; - this->ignore = true; - -#if IN_LLVM - this->emittedInModule = NULL; - this->tmodule = NULL; -#endif -} - -/***************** - * This constructor is only called when we figured out which function - * template to instantiate. - */ - -TemplateInstance::TemplateInstance(Loc loc, TemplateDeclaration *td, Objects *tiargs) - : ScopeDsymbol(NULL) -{ -#if LOG - printf("TemplateInstance(this = %p, tempdecl = '%s')\n", this, td->toChars()); -#endif - this->loc = loc; - this->name = td->ident; - this->tiargs = tiargs; - this->tempdecl = td; - this->inst = NULL; - this->tinst = NULL; - this->argsym = NULL; - this->aliasdecl = NULL; - this->semanticRun = PASSinit; - this->semantictiargsdone = 1; - this->withsym = NULL; - this->nest = 0; - this->havetempdecl = 1; - this->isnested = NULL; - this->speculative = 0; - this->ignore = true; - -#if IN_LLVM - this->tinst = NULL; - this->emittedInModule = NULL; - this->tmodule = NULL; -#endif - - assert((size_t)tempdecl->scope > 0x10000); -} - - -Objects *TemplateInstance::arraySyntaxCopy(Objects *objs) -{ - Objects *a = NULL; - if (objs) - { a = new Objects(); - a->setDim(objs->dim); - for (size_t i = 0; i < objs->dim; i++) - { - a->tdata()[i] = objectSyntaxCopy(objs->tdata()[i]); - } - } - return a; -} - -Dsymbol *TemplateInstance::syntaxCopy(Dsymbol *s) -{ - TemplateInstance *ti; - - if (s) - ti = (TemplateInstance *)s; - else - ti = new TemplateInstance(loc, name); - - ti->tiargs = arraySyntaxCopy(tiargs); - - ScopeDsymbol::syntaxCopy(ti); - return ti; -} - - -void TemplateInstance::semantic(Scope *sc) -{ - semantic(sc, NULL); -} - -void TemplateInstance::expandMembers(Scope *sc2) -{ - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (*members)[i]; - s->setScope(sc2); - } - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[i]; - //printf("\t[%d] semantic on '%s' %p kind %s in '%s'\n", i, s->toChars(), s, s->kind(), this->toChars()); - //printf("test: isnested = %d, sc2->parent = %s\n", isnested, sc2->parent->toChars()); -// if (isnested) -// s->parent = sc->parent; - //printf("test3: isnested = %d, s->parent = %s\n", isnested, s->parent->toChars()); - s->semantic(sc2); - //printf("test4: isnested = %d, s->parent = %s\n", isnested, s->parent->toChars()); - sc2->module->runDeferredSemantic(); - } -} - -void TemplateInstance::tryExpandMembers(Scope *sc2) -{ - static int nest; - // extracted to a function to allow windows SEH to work without destructors in the same function - //printf("%d\n", nest); - if (++nest > 500) - { - global.gag = 0; // ensure error message gets printed - error("recursive expansion"); - fatal(); - } - -#if WINDOWS_SEH - if(nest == 1) - { - // do not catch at every nesting level, because generating the output error might cause more stack - // errors in the __except block otherwise - __try - { - expandMembers(sc2); - } - __except (__ehfilter(GetExceptionInformation())) - { - global.gag = 0; // ensure error message gets printed - error("recursive expansion"); - fatal(); - } - } - else -#endif - expandMembers(sc2); - nest--; -} - -void TemplateInstance::trySemantic3(Scope *sc2) -{ - // extracted to a function to allow windows SEH to work without destructors in the same function - static int nest; - if (++nest > 300) - { - global.gag = 0; // ensure error message gets printed - error("recursive expansion"); - fatal(); - } -#if WINDOWS_SEH - if(nest == 1) - { - // do not catch at every nesting level, because generating the output error might cause more stack - // errors in the __except block otherwise - __try - { - semantic3(sc2); - } - __except (__ehfilter(GetExceptionInformation())) - { - global.gag = 0; // ensure error message gets printed - error("recursive expansion"); - fatal(); - } - } - else -#endif - semantic3(sc2); - - --nest; -} - -void TemplateInstance::semantic(Scope *sc, Expressions *fargs) -{ - //printf("TemplateInstance::semantic('%s', this=%p, gag = %d, sc = %p)\n", toChars(), this, global.gag, sc); -#if LOG - printf("\n+TemplateInstance::semantic('%s', this=%p)\n", toChars(), this); -#endif - if (inst) // if semantic() was already run - { -#if LOG - printf("-TemplateInstance::semantic('%s', this=%p) already run\n", inst->toChars(), inst); -#endif - return; - } - - if (!sc->ignoreTemplates) - ignore = false; - - - // get the enclosing template instance from the scope tinst - tinst = sc->tinst; - - if (semanticRun != PASSinit) - { -#if LOG - printf("Recursive template expansion\n"); -#endif - error(loc, "recursive template expansion"); -// inst = this; - return; - } - semanticRun = PASSsemantic; -#if IN_LLVM - // get the enclosing template instance from the scope tinst - tinst = sc->tinst; - - // get the module of the outermost enclosing instantiation - if (tinst) - tmodule = tinst->tmodule; - else - tmodule = sc->module; - //printf("%s in %s\n", toChars(), tmodule->toChars()); -#endif - -#if LOG - printf("\tdo semantic\n"); -#endif - if (havetempdecl) - { - assert((size_t)tempdecl->scope > 0x10000); - // Deduce tdtypes - tdtypes.setDim(tempdecl->parameters->dim); - if (!tempdecl->matchWithInstance(this, &tdtypes, fargs, 2)) - { - error("incompatible arguments for template instantiation"); - inst = this; - return; - } - } - else - { - /* Run semantic on each argument, place results in tiargs[] - * (if we havetempdecl, then tiargs is already evaluated) - */ - semanticTiargs(sc); - if (arrayObjectIsError(tiargs)) - { inst = this; - //printf("error return %p, %d\n", tempdecl, global.errors); - return; // error recovery - } - unsigned errs = global.errors; - tempdecl = findTemplateDeclaration(sc); - if (tempdecl) - tempdecl = findBestMatch(sc, fargs); - if (!tempdecl || (errs != global.errors)) - { inst = this; - //printf("error return %p, %d\n", tempdecl, global.errors); - return; // error recovery - } - } - - // If tempdecl is a mixin, disallow it - if (tempdecl->ismixin) - error("mixin templates are not regular templates"); - - hasNestedArgs(tiargs); - - /* See if there is an existing TemplateInstantiation that already - * implements the typeargs. If so, just refer to that one instead. - */ - - for (size_t i = 0; i < tempdecl->instances.dim; i++) - { - TemplateInstance *ti = tempdecl->instances.tdata()[i]; -#if LOG - printf("\t%s: checking for match with instance %d (%p): '%s'\n", toChars(), i, ti, ti->toChars()); -#endif - assert(tdtypes.dim == ti->tdtypes.dim); - - // Nesting must match - if (isnested != ti->isnested) - { - //printf("test2 isnested %s ti->isnested %s\n", isnested ? isnested->toChars() : "", ti->isnested ? ti->isnested->toChars() : ""); - continue; - } - //printf("parent = %s, ti->parent = %s\n", tempdecl->parent->toPrettyChars(), ti->parent->toPrettyChars()); - - if (!arrayObjectMatch(&tdtypes, &ti->tdtypes, tempdecl, sc)) - goto L1; - - /* Template functions may have different instantiations based on - * "auto ref" parameters. - */ - if (fargs) - { - FuncDeclaration *fd = ti->toAlias()->isFuncDeclaration(); - if (fd) - { - Parameters *fparameters = fd->getParameters(NULL); - size_t nfparams = Parameter::dim(fparameters); // Num function parameters - for (size_t j = 0; j < nfparams && j < fargs->dim; j++) - { Parameter *fparam = Parameter::getNth(fparameters, j); - Expression *farg = fargs->tdata()[j]; - if (fparam->storageClass & STCauto) // if "auto ref" - { - if (farg->isLvalue()) - { if (!(fparam->storageClass & STCref)) - goto L1; // auto ref's don't match - } - else - { if (fparam->storageClass & STCref) - goto L1; // auto ref's don't match - } - } - } - } - } - - // It's a match - inst = ti; - parent = ti->parent; - - // If both this and the previous instantiation were speculative, - // use the number of errors that happened last time. - if (inst->speculative && global.gag) - { - global.errors += inst->errors; - global.gaggedErrors += inst->errors; - } - - // If the first instantiation was speculative, but this is not: - if (inst->speculative && !global.gag) - { - // If the first instantiation had failed, re-run semantic, - // so that error messages are shown. - if (inst->errors) - goto L1; - // It had succeeded, mark it is a non-speculative instantiation, - // and reuse it. - inst->speculative = 0; - } - -#if LOG - printf("\tit's a match with instance %p, %d\n", inst, inst->semanticRun); -#endif - return; - - L1: - ; - } - - /* So, we need to implement 'this' instance. - */ -#if LOG - printf("\timplement template instance %s '%s'\n", tempdecl->parent->toChars(), toChars()); - printf("\ttempdecl %s\n", tempdecl->toChars()); -#endif - unsigned errorsave = global.errors; - inst = this; - // Mark as speculative if we are instantiated from inside is(typeof()) - if (global.gag && sc->speculative) - speculative = 1; - - int tempdecl_instance_idx = tempdecl->instances.dim; - tempdecl->instances.push(this); - parent = tempdecl->parent; - //printf("parent = '%s'\n", parent->kind()); - - ident = genIdent(tiargs); // need an identifier for name mangling purposes. - -#if 1 - if (isnested) - parent = isnested; -#endif - //printf("parent = '%s'\n", parent->kind()); - - // Add 'this' to the enclosing scope's members[] so the semantic routines - // will get called on the instance members. Store the place we added it to - // in target_symbol_list(_idx) so we can remove it later if we encounter - // an error. -#if 1 - int dosemantic3 = 0; - Dsymbols *target_symbol_list = NULL; - int target_symbol_list_idx; - - if (!sc->parameterSpecialization) - { Dsymbols *a; - - Scope *scx = sc; -#if 0 - for (scx = sc; scx; scx = scx->enclosing) - if (scx->scopesym) - break; -#endif - - //if (scx && scx->scopesym) printf("3: scx is %s %s\n", scx->scopesym->kind(), scx->scopesym->toChars()); - if (scx && scx->scopesym && - scx->scopesym->members && !scx->scopesym->isTemplateMixin() -#if 0 // removed because it bloated compile times - /* The problem is if A imports B, and B imports A, and both A - * and B instantiate the same template, does the compilation of A - * or the compilation of B do the actual instantiation? - * - * see bugzilla 2500. - */ - && !scx->module->selfImports() -#endif - ) - { - //printf("\t1: adding to %s %s\n", scx->scopesym->kind(), scx->scopesym->toChars()); - a = scx->scopesym->members; - } - else - { Module *m = sc->module->importedFrom; - //printf("\t2: adding to module %s instead of module %s\n", m->toChars(), sc->module->toChars()); - a = m->members; - if (m->semanticRun >= 3) - { - dosemantic3 = 1; - } - } - for (int i = 0; 1; i++) - { - if (i == a->dim) - { - target_symbol_list = a; - target_symbol_list_idx = i; - a->push(this); - break; - } - if (this == a->tdata()[i]) // if already in Array - break; - } - } -#endif - - // Copy the syntax trees from the TemplateDeclaration - members = Dsymbol::arraySyntaxCopy(tempdecl->members); - - // Create our own scope for the template parameters - Scope *scope = tempdecl->scope; - if (!tempdecl->semanticRun) - { - error("template instantiation %s forward references template declaration %s\n", toChars(), tempdecl->toChars()); - return; - } - -#if LOG - printf("\tcreate scope for template parameters '%s'\n", toChars()); -#endif - argsym = new ScopeDsymbol(); - argsym->parent = scope->parent; - scope = scope->push(argsym); -// scope->stc = 0; - - // Declare each template parameter as an alias for the argument type - Scope *paramscope = scope->push(); - paramscope->stc = 0; - declareParameters(paramscope); - paramscope->pop(); - - // Add members of template instance to template instance symbol table -// parent = scope->scopesym; - symtab = new DsymbolTable(); - int memnum = 0; - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[i]; -#if LOG - printf("\t[%d] adding member '%s' %p kind %s to '%s', memnum = %d\n", i, s->toChars(), s, s->kind(), this->toChars(), memnum); -#endif - memnum |= s->addMember(scope, this, memnum); - } -#if LOG - printf("adding members done\n"); -#endif - - /* See if there is only one member of template instance, and that - * member has the same name as the template instance. - * If so, this template instance becomes an alias for that member. - */ - //printf("members->dim = %d\n", members->dim); - if (members->dim) - { - Dsymbol *s; - if (Dsymbol::oneMembers(members, &s, tempdecl->ident) && s) - { - //printf("s->kind = '%s'\n", s->kind()); - //s->print(); - //printf("'%s', '%s'\n", s->ident->toChars(), tempdecl->ident->toChars()); - //printf("setting aliasdecl\n"); - aliasdecl = new AliasDeclaration(loc, s->ident, s); - -#if IN_LLVM - // LDC propagate internal information - if (tempdecl->llvmInternal) { - s->llvmInternal = tempdecl->llvmInternal; - if (FuncDeclaration* fd = s->isFuncDeclaration()) { - fd->intrinsicName = tempdecl->intrinsicName; - } - } -#endif - } - } - - /* If function template declaration - */ - if (fargs && aliasdecl) - { - FuncDeclaration *fd = aliasdecl->toAlias()->isFuncDeclaration(); - if (fd) - { - /* Transmit fargs to type so that TypeFunction::semantic() can - * resolve any "auto ref" storage classes. - */ - TypeFunction *tf = (TypeFunction *)fd->type; - if (tf && tf->ty == Tfunction) - tf->fargs = fargs; - } - } - - // Do semantic() analysis on template instance members -#if LOG - printf("\tdo semantic() on template instance members '%s'\n", toChars()); -#endif - Scope *sc2; - sc2 = scope->push(this); - //printf("isnested = %d, sc->parent = %s\n", isnested, sc->parent->toChars()); - sc2->parent = /*isnested ? sc->parent :*/ this; - sc2->tinst = this; - - tryExpandMembers(sc2); - - semanticRun = PASSsemanticdone; - - /* If any of the instantiation members didn't get semantic() run - * on them due to forward references, we cannot run semantic2() - * or semantic3() yet. - */ - for (size_t i = 0; i < Module::deferred.dim; i++) - { Dsymbol *sd = Module::deferred.tdata()[i]; - - if (sd->parent == this) - { - //printf("deferred %s %s\n", sd->parent->toChars(), sd->toChars()); - AggregateDeclaration *ad = sd->isAggregateDeclaration(); - if (ad) - ad->deferred = this; - goto Laftersemantic; - } - } - - /* ConditionalDeclaration may introduce eponymous declaration, - * so we should find it once again after semantic. - */ - if (members->dim) - { - Dsymbol *s; - if (Dsymbol::oneMembers(members, &s, tempdecl->ident) && s) - { - if (!aliasdecl || aliasdecl->toAlias() != s) - { - //printf("s->kind = '%s'\n", s->kind()); - //s->print(); - //printf("'%s', '%s'\n", s->ident->toChars(), tempdecl->ident->toChars()); - //printf("setting aliasdecl 2\n"); - aliasdecl = new AliasDeclaration(loc, s->ident, s); - } - } - else if (aliasdecl) - aliasdecl = NULL; - } - - /* The problem is when to parse the initializer for a variable. - * Perhaps VarDeclaration::semantic() should do it like it does - * for initializers inside a function. - */ -// if (sc->parent->isFuncDeclaration()) - - /* BUG 782: this has problems if the classes this depends on - * are forward referenced. Find a way to defer semantic() - * on this template. - */ - semantic2(sc2); - - if (sc->func || dosemantic3) - { - trySemantic3(sc2); - } - - Laftersemantic: - sc2->pop(); - - scope->pop(); - - // Give additional context info if error occurred during instantiation - if (global.errors != errorsave) - { - error(loc, "error instantiating"); - if (tinst) - { tinst->printInstantiationTrace(); - } - errors = 1; - if (global.gag) - { - // Errors are gagged, so remove the template instance from the - // instance/symbol lists we added it to and reset our state to - // finish clean and so we can try to instantiate it again later - // (see bugzilla 4302 and 6602). - tempdecl->instances.remove(tempdecl_instance_idx); - if (target_symbol_list) - { - // Because we added 'this' in the last position above, we - // should be able to remove it without messing other indices up. - assert(target_symbol_list->tdata()[target_symbol_list_idx] == this); - target_symbol_list->remove(target_symbol_list_idx); - } - semanticRun = PASSinit; - inst = NULL; - } - } - -#if LOG - printf("-TemplateInstance::semantic('%s', this=%p)\n", toChars(), this); -#endif -} - - -void TemplateInstance::semanticTiargs(Scope *sc) -{ - //printf("+TemplateInstance::semanticTiargs() %s\n", toChars()); - if (semantictiargsdone) - return; - semantictiargsdone = 1; - semanticTiargs(loc, sc, tiargs, 0); -} - -/********************************** - * Input: - * flags 1: replace const variables with their initializers - */ - -void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int flags) -{ - // Run semantic on each argument, place results in tiargs[] - //printf("+TemplateInstance::semanticTiargs()\n"); - if (!tiargs) - return; - for (size_t j = 0; j < tiargs->dim; j++) - { - Object *o = tiargs->tdata()[j]; - Type *ta = isType(o); - Expression *ea = isExpression(o); - Dsymbol *sa = isDsymbol(o); - - //printf("1: tiargs->tdata()[%d] = %p, %p, %p, ea=%p, ta=%p\n", j, o, isDsymbol(o), isTuple(o), ea, ta); - if (ta) - { - //printf("type %s\n", ta->toChars()); - // It might really be an Expression or an Alias - ta->resolve(loc, sc, &ea, &ta, &sa); - if (ea) - { - ea = ea->semantic(sc); - /* This test is to skip substituting a const var with - * its initializer. The problem is the initializer won't - * match with an 'alias' parameter. Instead, do the - * const substitution in TemplateValueParameter::matchArg(). - */ - if (flags & 1) // only used by __traits, must not interpret the args - ea = ea->optimize(WANTvalue); - else if (ea->op != TOKvar) - ea = ea->optimize(WANTvalue | WANTinterpret); - tiargs->tdata()[j] = ea; - } - else if (sa) - { - Ldsym: - tiargs->tdata()[j] = sa; - TupleDeclaration *d = sa->toAlias()->isTupleDeclaration(); - if (d) - { - size_t dim = d->objects->dim; - tiargs->remove(j); - tiargs->insert(j, d->objects); - j--; - } - } - else if (ta) - { - Ltype: - if (ta->ty == Ttuple) - { // Expand tuple - TypeTuple *tt = (TypeTuple *)ta; - size_t dim = tt->arguments->dim; - tiargs->remove(j); - if (dim) - { tiargs->reserve(dim); - for (size_t i = 0; i < dim; i++) - { Parameter *arg = tt->arguments->tdata()[i]; - tiargs->insert(j + i, arg->type); - } - } - j--; - } - else - tiargs->tdata()[j] = ta; - } - else - { - assert(global.errors); - tiargs->tdata()[j] = Type::terror; - } - } - else if (ea) - { - if (!ea) - { assert(global.errors); - ea = new ErrorExp(); - } - assert(ea); - ea = ea->semantic(sc); - if (flags & 1) // only used by __traits, must not interpret the args - ea = ea->optimize(WANTvalue); - else if (ea->op != TOKvar && ea->op != TOKtuple) - ea = ea->optimize(WANTvalue | WANTinterpret); - tiargs->tdata()[j] = ea; - if (ea->op == TOKtype) - { ta = ea->type; - goto Ltype; - } - if (ea->op == TOKimport) - { sa = ((ScopeExp *)ea)->sds; - goto Ldsym; - } - if (ea->op == TOKtuple) - { // Expand tuple - TupleExp *te = (TupleExp *)ea; - size_t dim = te->exps->dim; - tiargs->remove(j); - if (dim) - { tiargs->reserve(dim); - for (size_t i = 0; i < dim; i++) - tiargs->insert(j + i, te->exps->tdata()[i]); - } - j--; - } - } - else if (sa) - { - TemplateDeclaration *td = sa->isTemplateDeclaration(); - if (td && !td->semanticRun && td->literal) - td->semantic(sc); - } - else - { - assert(0); - } - //printf("1: tiargs->tdata()[%d] = %p\n", j, tiargs->tdata()[j]); - } -#if 0 - printf("-TemplateInstance::semanticTiargs()\n"); - for (size_t j = 0; j < tiargs->dim; j++) - { - Object *o = tiargs->tdata()[j]; - Type *ta = isType(o); - Expression *ea = isExpression(o); - Dsymbol *sa = isDsymbol(o); - Tuple *va = isTuple(o); - - printf("\ttiargs[%d] = ta %p, ea %p, sa %p, va %p\n", j, ta, ea, sa, va); - } -#endif -} - -/********************************************** - * Find template declaration corresponding to template instance. - */ - -TemplateDeclaration *TemplateInstance::findTemplateDeclaration(Scope *sc) -{ - //printf("TemplateInstance::findTemplateDeclaration() %s\n", toChars()); - if (!tempdecl) - { - /* Given: - * foo!( ... ) - * figure out which TemplateDeclaration foo refers to. - */ - Dsymbol *s; - Dsymbol *scopesym; - Identifier *id; - - id = name; - s = sc->search(loc, id, &scopesym); - if (!s) - { - 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 an OverloadSet, look for a unique member that is a template declaration - */ - OverloadSet *os = s->isOverloadSet(); - if (os) - { s = NULL; - for (size_t i = 0; i < os->a.dim; i++) - { Dsymbol *s2 = os->a.tdata()[i]; - if (s2->isTemplateDeclaration()) - { - if (s) - error("ambiguous template declaration %s and %s", s->toPrettyChars(), s2->toPrettyChars()); - s = s2; - } - } - if (!s) - { error("template '%s' is not defined", id->toChars()); - return NULL; - } - } - -#if LOG - printf("It's an instance of '%s' kind '%s'\n", s->toChars(), s->kind()); - if (s->parent) - printf("s->parent = '%s'\n", s->parent->toChars()); -#endif - withsym = scopesym->isWithScopeSymbol(); - - /* We might have found an alias within a template when - * we really want the template. - */ - TemplateInstance *ti; - if (s->parent && - (ti = s->parent->isTemplateInstance()) != NULL) - { - if (ti->tempdecl && ti->tempdecl->ident == id) - { - /* This is so that one can refer to the enclosing - * template, even if it has the same name as a member - * of the template, if it has a !(arguments) - */ - tempdecl = ti->tempdecl; - if (tempdecl->overroot) // if not start of overloaded list of TemplateDeclaration's - tempdecl = tempdecl->overroot; // then get the start - s = tempdecl; - } - } - - s = s->toAlias(); - - /* It should be a TemplateDeclaration, not some other symbol - */ - tempdecl = s->isTemplateDeclaration(); - if (!tempdecl) - { - if (!s->parent && global.errors) - return NULL; - if (!s->parent && s->getType()) - { Dsymbol *s2 = s->getType()->toDsymbol(sc); - if (!s2) - { - error("%s is not a template declaration, it is a %s", id->toChars(), s->kind()); - return NULL; - } - s = s2; - } -#ifdef DEBUG - //if (!s->parent) printf("s = %s %s\n", s->kind(), s->toChars()); -#endif - //assert(s->parent); - TemplateInstance *ti = s->parent ? s->parent->isTemplateInstance() : NULL; - if (ti && - (ti->name == id || - ti->toAlias()->ident == id) - && - ti->tempdecl) - { - /* This is so that one can refer to the enclosing - * template, even if it has the same name as a member - * of the template, if it has a !(arguments) - */ - tempdecl = ti->tempdecl; - if (tempdecl->overroot) // if not start of overloaded list of TemplateDeclaration's - tempdecl = tempdecl->overroot; // then get the start - } - else - { - error("%s is not a template declaration, it is a %s", id->toChars(), s->kind()); - return NULL; - } - } - } - else - assert(tempdecl->isTemplateDeclaration()); - return tempdecl; -} - -TemplateDeclaration *TemplateInstance::findBestMatch(Scope *sc, Expressions *fargs) -{ - /* Since there can be multiple TemplateDeclaration's with the same - * name, look for the best match. - */ - TemplateDeclaration *td_ambig = NULL; - TemplateDeclaration *td_best = NULL; - MATCH m_best = MATCHnomatch; - Objects dedtypes; - -#if LOG - printf("TemplateInstance::findBestMatch()\n"); -#endif - // First look for forward references - for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) - { - if (!td->semanticRun) - { - if (td->scope) - { // Try to fix forward reference - td->semantic(td->scope); - } - if (!td->semanticRun) - { - error("%s forward references template declaration %s\n", toChars(), td->toChars()); - return NULL; - } - } - } - - for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) - { - MATCH m; - -//if (tiargs->dim) printf("2: tiargs->dim = %d, data[0] = %p\n", tiargs->dim, tiargs->tdata()[0]); - - // If more arguments than parameters, - // then this is no match. - if (td->parameters->dim < tiargs->dim) - { - if (!td->isVariadic()) - continue; - } - - dedtypes.setDim(td->parameters->dim); - dedtypes.zero(); - assert(td->semanticRun); - m = td->matchWithInstance(this, &dedtypes, fargs, 0); - //printf("matchWithInstance = %d\n", m); - if (!m) // no match at all - continue; - - if (m < m_best) - goto Ltd_best; - if (m > m_best) - goto Ltd; - - { - // Disambiguate by picking the most specialized TemplateDeclaration - MATCH c1 = td->leastAsSpecialized(td_best, fargs); - MATCH c2 = td_best->leastAsSpecialized(td, fargs); - //printf("c1 = %d, c2 = %d\n", c1, c2); - - if (c1 > c2) - goto Ltd; - else if (c1 < c2) - goto Ltd_best; - else - goto Lambig; - } - - Lambig: // td_best and td are ambiguous - td_ambig = td; - continue; - - Ltd_best: // td_best is the best match so far - td_ambig = NULL; - continue; - - Ltd: // td is the new best match - td_ambig = NULL; - td_best = td; - m_best = m; - tdtypes.setDim(dedtypes.dim); - memcpy(tdtypes.tdata(), dedtypes.tdata(), tdtypes.dim * sizeof(void *)); - continue; - } - - if (!td_best) - { - if (tempdecl && !tempdecl->overnext) - // Only one template, so we can give better error message - error("%s does not match template declaration %s", toChars(), tempdecl->toChars()); - else - ::error(loc, "%s %s.%s does not match any template declaration", - tempdecl->kind(), tempdecl->parent->toPrettyChars(), tempdecl->ident->toChars()); - return NULL; - } - if (td_ambig) - { - ::error(loc, "%s %s.%s matches more than one template declaration, %s(%d):%s and %s(%d):%s", - td_best->kind(), td_best->parent->toPrettyChars(), td_best->ident->toChars(), - td_best->loc.filename, td_best->loc.linnum, td_best->toChars(), - td_ambig->loc.filename, td_ambig->loc.linnum, td_ambig->toChars()); - } - - /* The best match is td_best - */ - tempdecl = td_best; - -#if 0 - /* Cast any value arguments to be same type as value parameter - */ - for (size_t i = 0; i < tiargs->dim; i++) - { Object *o = tiargs->tdata()[i]; - Expression *ea = isExpression(o); // value argument - TemplateParameter *tp = tempdecl->parameters->tdata()[i]; - assert(tp); - TemplateValueParameter *tvp = tp->isTemplateValueParameter(); - if (tvp) - { - assert(ea); - ea = ea->castTo(tvp->valType); - ea = ea->optimize(WANTvalue | WANTinterpret); - tiargs->tdata()[i] = (Object *)ea; - } - } -#endif - -#if LOG - printf("\tIt's a match with template declaration '%s'\n", tempdecl->toChars()); -#endif - return tempdecl; -} - - -/***************************************** - * Determines if a TemplateInstance will need a nested - * generation of the TemplateDeclaration. - */ - -int TemplateInstance::hasNestedArgs(Objects *args) -{ int nested = 0; - //printf("TemplateInstance::hasNestedArgs('%s')\n", tempdecl->ident->toChars()); - - /* A nested instance happens when an argument references a local - * symbol that is on the stack. - */ - for (size_t i = 0; i < args->dim; i++) - { Object *o = args->tdata()[i]; - Expression *ea = isExpression(o); - Dsymbol *sa = isDsymbol(o); - Tuple *va = isTuple(o); - if (ea) - { - if (ea->op == TOKvar) - { - sa = ((VarExp *)ea)->var; - goto Lsa; - } - if (ea->op == TOKthis) - { - sa = ((ThisExp *)ea)->var; - goto Lsa; - } - if (ea->op == TOKfunction) - { - sa = ((FuncExp *)ea)->fd; - goto Lsa; - } - } - else if (sa) - { - Lsa: - TemplateDeclaration *td = sa->isTemplateDeclaration(); - Declaration *d = sa->isDeclaration(); - if ((td && td->literal) || - (d && !d->isDataseg() && -#if DMDV2 - !(d->storage_class & STCmanifest) && -#endif - (!d->isFuncDeclaration() || d->isFuncDeclaration()->isNested()) && - !isTemplateMixin() - )) - { - // if module level template - if (tempdecl->toParent()->isModule()) - { Dsymbol *dparent = sa->toParent(); - if (!isnested) - isnested = dparent; - else if (isnested != dparent) - { - /* Select the more deeply nested of the two. - * Error if one is not nested inside the other. - */ - for (Dsymbol *p = isnested; p; p = p->parent) - { - if (p == dparent) - goto L1; // isnested is most nested - } - for (Dsymbol *p = dparent; p; p = p->parent) - { - if (p == isnested) - { isnested = dparent; - goto L1; // dparent is most nested - } - } - error("%s is nested in both %s and %s", - toChars(), isnested->toChars(), dparent->toChars()); - } - L1: - //printf("\tnested inside %s\n", isnested->toChars()); - nested |= 1; - } - else - error("cannot use local '%s' as parameter to non-global template %s", sa->toChars(), tempdecl->toChars()); - } - } - else if (va) - { - nested |= hasNestedArgs(&va->objects); - } - } - return nested; -} - -/**************************************** - * This instance needs an identifier for name mangling purposes. - * Create one by taking the template declaration name and adding - * the type signature for it. - */ - -Identifier *TemplateInstance::genIdent(Objects *args) -{ OutBuffer buf; - - //printf("TemplateInstance::genIdent('%s')\n", tempdecl->ident->toChars()); - char *id = tempdecl->ident->toChars(); - buf.printf("__T%llu%s", (ulonglong)strlen(id), id); - for (size_t i = 0; i < args->dim; i++) - { Object *o = args->tdata()[i]; - Type *ta = isType(o); - Expression *ea = isExpression(o); - Dsymbol *sa = isDsymbol(o); - Tuple *va = isTuple(o); - //printf("\to [%d] %p ta %p ea %p sa %p va %p\n", i, o, ta, ea, sa, va); - if (ta) - { - buf.writeByte('T'); - if (ta->deco) - buf.writestring(ta->deco); - else - { -#ifdef DEBUG - if (!global.errors) - printf("ta = %d, %s\n", ta->ty, ta->toChars()); -#endif - assert(global.errors); - } - } - else if (ea) - { - // Don't interpret it yet, it might actually be an alias - ea = ea->optimize(WANTvalue); - if (ea->op == TOKvar) - { - sa = ((VarExp *)ea)->var; - ea = NULL; - goto Lsa; - } - if (ea->op == TOKthis) - { - sa = ((ThisExp *)ea)->var; - ea = NULL; - goto Lsa; - } - if (ea->op == TOKfunction) - { - sa = ((FuncExp *)ea)->fd; - ea = NULL; - goto Lsa; - } - buf.writeByte('V'); - if (ea->op == TOKtuple) - { ea->error("tuple is not a valid template value argument"); - continue; - } - // Now that we know it is not an alias, we MUST obtain a value - unsigned olderr = global.errors; - ea = ea->optimize(WANTvalue | WANTinterpret); - if (ea->op == TOKerror || olderr != global.errors) - continue; -#if 1 - /* Use deco that matches what it would be for a function parameter - */ - buf.writestring(ea->type->deco); -#else - // Use type of parameter, not type of argument - TemplateParameter *tp = tempdecl->parameters->tdata()[i]; - assert(tp); - TemplateValueParameter *tvp = tp->isTemplateValueParameter(); - assert(tvp); - buf.writestring(tvp->valType->deco); -#endif - ea->toMangleBuffer(&buf); - } - else if (sa) - { - Lsa: - buf.writeByte('S'); - Declaration *d = sa->isDeclaration(); - if (d && (!d->type || !d->type->deco)) - { error("forward reference of %s", d->toChars()); - continue; - } -#if 0 - VarDeclaration *v = sa->isVarDeclaration(); - if (v && v->storage_class & STCmanifest) - { ExpInitializer *ei = v->init->isExpInitializer(); - if (ei) - { - ea = ei->exp; - goto Lea; - } - } -#endif - const char *p = sa->mangle(); - - /* Bugzilla 3043: if the first character of p is a digit this - * causes ambiguity issues because the digits of the two numbers are adjacent. - * Current demanglers resolve this by trying various places to separate the - * numbers until one gets a successful demangle. - * Unfortunately, fixing this ambiguity will break existing binary - * compatibility and the demanglers, so we'll leave it as is. - */ - buf.printf("%llu%s", (ulonglong)strlen(p), p); - } - else if (va) - { - assert(i + 1 == args->dim); // must be last one - args = &va->objects; - i = -1; - } - else - assert(0); - } - buf.writeByte('Z'); - id = buf.toChars(); - //buf.data = NULL; // we can free the string after call to idPool() - //printf("\tgenIdent = %s\n", id); - return Lexer::idPool(id); -} - - -/**************************************************** - * Declare parameters of template instance, initialize them with the - * template instance arguments. - */ - -void TemplateInstance::declareParameters(Scope *sc) -{ - //printf("TemplateInstance::declareParameters()\n"); - for (size_t i = 0; i < tdtypes.dim; i++) - { - TemplateParameter *tp = tempdecl->parameters->tdata()[i]; - //Object *o = tiargs->tdata()[i]; - Object *o = tdtypes.tdata()[i]; // initializer for tp - - //printf("\ttdtypes[%d] = %p\n", i, o); - tempdecl->declareParameter(sc, tp, o); - } -} - -/***************************************************** - * Determine if template instance is really a template function, - * and that template function needs to infer types from the function - * arguments. - */ - -int TemplateInstance::needsTypeInference(Scope *sc) -{ - //printf("TemplateInstance::needsTypeInference() %s\n", toChars()); - if (!tempdecl) - tempdecl = findTemplateDeclaration(sc); - int multipleMatches = FALSE; - for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) - { - /* If any of the overloaded template declarations need inference, - * then return TRUE - */ - FuncDeclaration *fd; - if (!td->onemember || - (fd = td->onemember->toAlias()->isFuncDeclaration()) == NULL || - fd->type->ty != Tfunction) - { - /* Not a template function, therefore type inference is not possible. - */ - //printf("false\n"); - return FALSE; - } - - for (size_t i = 0; i < td->parameters->dim; i++) - if (td->parameters->tdata()[i]->isTemplateThisParameter()) - return TRUE; - - /* Determine if the instance arguments, tiargs, are all that is necessary - * to instantiate the template. - */ - //printf("tp = %p, td->parameters->dim = %d, tiargs->dim = %d\n", tp, td->parameters->dim, tiargs->dim); - TypeFunction *fdtype = (TypeFunction *)fd->type; - if (Parameter::dim(fdtype->parameters)) - { - TemplateParameter *tp = td->isVariadic(); - if (tp && td->parameters->dim > 1) - return TRUE; - - if (tiargs->dim < td->parameters->dim) - { // Can remain tiargs be filled by default arguments? - for (size_t i = tiargs->dim; i < td->parameters->dim; i++) - { tp = (*td->parameters)[i]; - if (TemplateTypeParameter *ttp = tp->isTemplateTypeParameter()) - { if (!ttp->defaultType) - return TRUE; - } - else if (TemplateAliasParameter *tap = tp->isTemplateAliasParameter()) - { if (!tap->defaultAlias) - return TRUE; - } - else if (TemplateValueParameter *tvp = tp->isTemplateValueParameter()) - { if (!tvp->defaultValue) - return TRUE; - } - } - } - } - /* If there is more than one function template which matches, we may - * need type inference (see Bugzilla 4430) - */ - if (td != tempdecl) - multipleMatches = TRUE; - } - //printf("false\n"); - return multipleMatches; -} - -void TemplateInstance::semantic2(Scope *sc) -{ int i; - - if (semanticRun >= PASSsemantic2) - return; - semanticRun = PASSsemantic2; -#if LOG - printf("+TemplateInstance::semantic2('%s')\n", toChars()); -#endif - if (!errors && members) - { - sc = tempdecl->scope; - assert(sc); - sc = sc->push(argsym); - sc = sc->push(this); - sc->tinst = this; - for (i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[i]; -#if LOG -printf("\tmember '%s', kind = '%s'\n", s->toChars(), s->kind()); -#endif - s->semantic2(sc); - } - sc = sc->pop(); - sc->pop(); - } -#if LOG - printf("-TemplateInstance::semantic2('%s')\n", toChars()); -#endif -} - -void TemplateInstance::semantic3(Scope *sc) -{ -#if LOG - printf("TemplateInstance::semantic3('%s'), semanticRun = %d\n", toChars(), semanticRun); -#endif -//if (toChars()[0] == 'D') *(char*)0=0; - if (semanticRun >= PASSsemantic3) - return; - semanticRun = PASSsemantic3; - if (!errors && members) - { - sc = tempdecl->scope; - sc = sc->push(argsym); - sc = sc->push(this); - sc->tinst = this; - if (ignore) - sc->ignoreTemplates++; - int oldgag = global.gag; - int olderrors = global.errors; - /* If this is a speculative instantiation, gag errors. - * Future optimisation: If the results are actually needed, errors - * would already be gagged, so we don't really need to run semantic - * on the members. - */ - if (speculative && !oldgag) - olderrors = global.startGagging(); - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[i]; - s->semantic3(sc); - if (speculative && global.errors != olderrors) - break; - } - if (speculative && !oldgag) - { // If errors occurred, this instantiation failed - errors += global.errors - olderrors; - global.endGagging(olderrors); - } - sc = sc->pop(); - sc->pop(); - } -} - -#if IN_DMD - -/************************************** - * Given an error instantiating the TemplateInstance, - * give the nested TemplateInstance instantiations that got - * us here. Those are a list threaded into the nested scopes. - */ -void TemplateInstance::printInstantiationTrace() -{ - if (global.gag) - return; - - const unsigned max_shown = 6; - const char format[] = "instantiated from here: %s"; - - // determine instantiation depth and number of recursive instantiations - int n_instantiations = 1; - int n_totalrecursions = 0; - for (TemplateInstance *cur = this; cur; cur = cur->tinst) - { - ++n_instantiations; - // If two instantiations use the same declaration, they are recursive. - // (this works even if they are instantiated from different places in the - // same template). - // In principle, we could also check for multiple-template recursion, but it's - // probably not worthwhile. - if (cur->tinst && cur->tempdecl && cur->tinst->tempdecl - && cur->tempdecl->loc.equals(cur->tinst->tempdecl->loc)) - ++n_totalrecursions; - } - - // show full trace only if it's short or verbose is on - if (n_instantiations <= max_shown || global.params.verbose) - { - for (TemplateInstance *cur = this; cur; cur = cur->tinst) - { - errorSupplemental(cur->loc, format, cur->toChars()); - } - } - else if (n_instantiations - n_totalrecursions <= max_shown) - { - // By collapsing recursive instantiations into a single line, - // we can stay under the limit. - int recursionDepth=0; - for (TemplateInstance *cur = this; cur; cur = cur->tinst) - { - if (cur->tinst && cur->tempdecl && cur->tinst->tempdecl - && cur->tempdecl->loc.equals(cur->tinst->tempdecl->loc)) - { - ++recursionDepth; - } - else - { - if (recursionDepth) - errorSupplemental(cur->loc, "%d recursive instantiations from here: %s", recursionDepth+2, cur->toChars()); - else - errorSupplemental(cur->loc, format, cur->toChars()); - recursionDepth = 0; - } - } - } - else - { - // Even after collapsing the recursions, the depth is too deep. - // Just display the first few and last few instantiations. - unsigned i = 0; - for (TemplateInstance *cur = this; cur; cur = cur->tinst) - { - if (i == max_shown / 2) - errorSupplemental(cur->loc, "... (%d instantiations, -v to show) ...", n_instantiations - max_shown); - - if (i < max_shown / 2 || - i >= n_instantiations - max_shown + max_shown / 2) - errorSupplemental(cur->loc, format, cur->toChars()); - ++i; - } - } -} - -void TemplateInstance::toObjFile(int multiobj) -{ -#if LOG - printf("TemplateInstance::toObjFile('%s', this = %p)\n", toChars(), this); -#endif - if (!errors && members) - { - if (multiobj) - // Append to list of object files to be written later - obj_append(this); - else - { - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[i]; - s->toObjFile(multiobj); - } - } - } -} - -#endif - -void TemplateInstance::inlineScan() -{ -#if LOG - printf("TemplateInstance::inlineScan('%s')\n", toChars()); -#endif - if (!errors && members) - { - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[i]; - s->inlineScan(); - } - } -} - -void TemplateInstance::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - int i; - - Identifier *id = name; - buf->writestring(id->toChars()); - buf->writestring("!("); - if (nest) - buf->writestring("..."); - else - { - nest++; - Objects *args = tiargs; - for (i = 0; i < args->dim; i++) - { - if (i) - buf->writeByte(','); - Object *oarg = (*args)[i]; - ObjectToCBuffer(buf, hgs, oarg); - } - nest--; - } - buf->writeByte(')'); -} - - -Dsymbol *TemplateInstance::toAlias() -{ -#if LOG - printf("TemplateInstance::toAlias()\n"); -#endif - if (!inst) - { - // Maybe we can resolve it - if (scope) - { - /* Anything that affects scope->offset must be - * done in lexical order. Fwd ref error if it is affected, otherwise allow. - */ - unsigned offset = scope->offset; - Scope *sc = scope; - semantic(scope); -// if (offset != sc->offset) -// inst = NULL; // trigger fwd ref error - } - if (!inst) - { error("cannot resolve forward reference"); - errors = 1; - return this; - } - } - - if (inst != this) - return inst->toAlias(); - - if (aliasdecl) - { - return aliasdecl->toAlias(); - } - - return inst; -} - -AliasDeclaration *TemplateInstance::isAliasDeclaration() -{ - return aliasdecl; -} - -const char *TemplateInstance::kind() -{ - return "template instance"; -} - -int TemplateInstance::oneMember(Dsymbol **ps, Identifier *ident) -{ - *ps = NULL; - return TRUE; -} - -char *TemplateInstance::toChars() -{ - OutBuffer buf; - HdrGenState hgs; - char *s; - - toCBuffer(&buf, &hgs); - s = buf.toChars(); - buf.data = NULL; - return s; -} - -#if IN_LLVM - -void TemplateInstance::printInstantiationTrace() -{ - if(global.gag) - return; - - const int max_shown = 6; - - // determine instantiation depth - int n_instantiations = 1; - TemplateInstance* cur = this; - while(cur = cur->tinst) - ++n_instantiations; - - // show full trace only if it's short or verbose is on - if(n_instantiations <= max_shown || global.params.verbose) - { - cur = this; - while(cur) - { - fprintf(stdmsg," instantiatied in %s: %s\n", cur->loc.toChars(), cur->toChars()); - cur = cur->tinst; - } - } - else - { - cur = this; - size_t i = 0; - for(; i < max_shown/2; ++i, cur = cur->tinst) - fprintf(stdmsg," instantiatied in %s: %s\n", cur->loc.toChars(), cur->toChars()); - fprintf(stdmsg," ... (%d instantiations, -v to show) ...\n", n_instantiations - max_shown); - for(; i < n_instantiations - max_shown + max_shown/2; ++i, cur = cur->tinst) - {} - for(; i < n_instantiations; ++i, cur = cur->tinst) - fprintf(stdmsg," instantiatied in %s: %s\n", cur->loc.toChars(), cur->toChars()); - } -} - -#endif - -/* ======================== TemplateMixin ================================ */ - -TemplateMixin::TemplateMixin(Loc loc, Identifier *ident, Type *tqual, - Identifiers *idents, Objects *tiargs) - : TemplateInstance(loc, idents->tdata()[idents->dim - 1]) -{ - //printf("TemplateMixin(ident = '%s')\n", ident ? ident->toChars() : ""); - this->ident = ident; - this->tqual = tqual; - this->idents = idents; - this->tiargs = tiargs ? tiargs : new Objects(); -} - -Dsymbol *TemplateMixin::syntaxCopy(Dsymbol *s) -{ TemplateMixin *tm; - - Identifiers *ids = new Identifiers(); - ids->setDim(idents->dim); - for (size_t i = 0; i < idents->dim; i++) - { // Matches TypeQualified::syntaxCopyHelper() - Identifier *id = idents->tdata()[i]; - if (id->dyncast() == DYNCAST_DSYMBOL) - { - TemplateInstance *ti = (TemplateInstance *)id; - - ti = (TemplateInstance *)ti->syntaxCopy(NULL); - id = (Identifier *)ti; - } - ids->tdata()[i] = id; - } - - tm = new TemplateMixin(loc, ident, - (Type *)(tqual ? tqual->syntaxCopy() : NULL), - ids, tiargs); - TemplateInstance::syntaxCopy(tm); - return tm; -} - -void TemplateMixin::semantic(Scope *sc) -{ -#if LOG - printf("+TemplateMixin::semantic('%s', this=%p)\n", toChars(), this); - fflush(stdout); -#endif - if (semanticRun) - { - // This for when a class/struct contains mixin members, and - // is done over because of forward references - if (parent && toParent()->isAggregateDeclaration()) - semanticRun = PASSsemantic; // do over - else - { -#if LOG - printf("\tsemantic done\n"); -#endif - return; - } - } - if (!semanticRun) - semanticRun = PASSsemantic; -#if LOG - printf("\tdo semantic\n"); -#endif - -#if !IN_LLVM && !IN_GCC - // dont know what this is - util_progress(); -#endif - - Scope *scx = NULL; - if (scope) - { sc = scope; - scx = scope; // save so we don't make redundant copies - scope = NULL; - } - - // Follow qualifications to find the TemplateDeclaration - if (!tempdecl) - { Dsymbol *s; - size_t i; - Identifier *id; - - if (tqual) - { s = tqual->toDsymbol(sc); - i = 0; - } - else - { - i = 1; - id = idents->tdata()[0]; - switch (id->dyncast()) - { - case DYNCAST_IDENTIFIER: - s = sc->search(loc, id, NULL); - break; - - case DYNCAST_DSYMBOL: - { - TemplateInstance *ti = (TemplateInstance *)id; - ti->semantic(sc); - s = ti; - break; - } - default: - assert(0); - } - } - - for (; i < idents->dim; i++) - { - if (!s) - break; - id = idents->tdata()[i]; - s = s->searchX(loc, sc, id); - } - if (!s) - { - error("is not defined"); - inst = this; - return; - } - tempdecl = s->toAlias()->isTemplateDeclaration(); - if (!tempdecl) - { - error("%s isn't a template", s->toChars()); - inst = this; - return; - } - } - - // Look for forward reference - assert(tempdecl); - for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) - { - if (!td->semanticRun) - { - /* Cannot handle forward references if mixin is a struct member, - * because addField must happen during struct's semantic, not - * during the mixin semantic. - * runDeferred will re-run mixin's semantic outside of the struct's - * semantic. - */ - semanticRun = PASSinit; - AggregateDeclaration *ad = toParent()->isAggregateDeclaration(); - if (ad) - ad->sizeok = SIZEOKfwd; - else - { - // Forward reference - //printf("forward reference - deferring\n"); - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - scope->module->addDeferredSemantic(this); - } - return; - } - } - - // Run semantic on each argument, place results in tiargs[] - semanticTiargs(sc); - if (errors || arrayObjectIsError(tiargs)) - return; - - tempdecl = findBestMatch(sc, NULL); - if (!tempdecl) - { inst = this; - return; // error recovery - } - - if (!ident) - ident = genIdent(tiargs); - - inst = this; - parent = sc->parent; - - /* Detect recursive mixin instantiations. - */ - for (Dsymbol *s = parent; s; s = s->parent) - { - //printf("\ts = '%s'\n", s->toChars()); - TemplateMixin *tm = s->isTemplateMixin(); - if (!tm || tempdecl != tm->tempdecl) - continue; - - /* Different argument list lengths happen with variadic args - */ - if (tiargs->dim != tm->tiargs->dim) - continue; - - for (size_t i = 0; i < tiargs->dim; i++) - { Object *o = (*tiargs)[i]; - Type *ta = isType(o); - Expression *ea = isExpression(o); - Dsymbol *sa = isDsymbol(o); - Object *tmo = (*tm->tiargs)[i]; - if (ta) - { - Type *tmta = isType(tmo); - if (!tmta) - goto Lcontinue; - if (!ta->equals(tmta)) - goto Lcontinue; - } - else if (ea) - { Expression *tme = isExpression(tmo); - if (!tme || !ea->equals(tme)) - goto Lcontinue; - } - else if (sa) - { - Dsymbol *tmsa = isDsymbol(tmo); - if (sa != tmsa) - goto Lcontinue; - } - else - assert(0); - } - error("recursive mixin instantiation"); - return; - - Lcontinue: - continue; - } - - // Copy the syntax trees from the TemplateDeclaration - members = Dsymbol::arraySyntaxCopy(tempdecl->members); - if (!members) - return; - - symtab = new DsymbolTable(); - - for (Scope *sce = sc; 1; sce = sce->enclosing) - { - ScopeDsymbol *sds = (ScopeDsymbol *)sce->scopesym; - if (sds) - { - sds->importScope(this, PROTpublic); - break; - } - } - -#if LOG - printf("\tcreate scope for template parameters '%s'\n", toChars()); -#endif - Scope *scy = sc; - scy = sc->push(this); - scy->parent = this; - - argsym = new ScopeDsymbol(); - argsym->parent = scy->parent; - Scope *argscope = scy->push(argsym); - - unsigned errorsave = global.errors; - - // Declare each template parameter as an alias for the argument type - declareParameters(argscope); - - // Add members to enclosing scope, as well as this scope - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (*members)[i]; - s->addMember(argscope, this, i); - //sc->insert(s); - //printf("sc->parent = %p, sc->scopesym = %p\n", sc->parent, sc->scopesym); - //printf("s->parent = %s\n", s->parent->toChars()); - } - - // Do semantic() analysis on template instance members -#if LOG - printf("\tdo semantic() on template instance members '%s'\n", toChars()); -#endif - Scope *sc2; - sc2 = argscope->push(this); - sc2->offset = sc->offset; - - static int nest; - //printf("%d\n", nest); - if (++nest > 500) - { - global.gag = 0; // ensure error message gets printed - error("recursive expansion"); - fatal(); - } - - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; - s->semantic(sc2); - } - - nest--; - - sc->offset = sc2->offset; - - /* The problem is when to parse the initializer for a variable. - * Perhaps VarDeclaration::semantic() should do it like it does - * for initializers inside a function. - */ -// if (sc->parent->isFuncDeclaration()) - - semantic2(sc2); - - if (sc->func) - { - semantic3(sc2); - } - - // Give additional context info if error occurred during instantiation - if (global.errors != errorsave) - { - error("error instantiating"); - } - - sc2->pop(); - - argscope->pop(); - -// if (!isAnonymous()) - { - scy->pop(); - } -#if LOG - printf("-TemplateMixin::semantic('%s', this=%p)\n", toChars(), this); -#endif -} - -void TemplateMixin::semantic2(Scope *sc) -{ - if (semanticRun >= PASSsemantic2) - return; - semanticRun = PASSsemantic2; -#if LOG - printf("+TemplateMixin::semantic2('%s')\n", toChars()); -#endif - if (members) - { - assert(sc); - sc = sc->push(argsym); - sc = sc->push(this); - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; -#if LOG - printf("\tmember '%s', kind = '%s'\n", s->toChars(), s->kind()); -#endif - s->semantic2(sc); - } - sc = sc->pop(); - sc->pop(); - } -#if LOG - printf("-TemplateMixin::semantic2('%s')\n", toChars()); -#endif -} - -void TemplateMixin::semantic3(Scope *sc) -{ - if (semanticRun >= PASSsemantic3) - return; - semanticRun = PASSsemantic3; -#if LOG - printf("TemplateMixin::semantic3('%s')\n", toChars()); -#endif - if (members) - { - sc = sc->push(argsym); - sc = sc->push(this); - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[i]; - s->semantic3(sc); - } - sc = sc->pop(); - sc->pop(); - } -} - -void TemplateMixin::inlineScan() -{ - TemplateInstance::inlineScan(); -} - -const char *TemplateMixin::kind() -{ - return "mixin"; -} - -int TemplateMixin::oneMember(Dsymbol **ps, Identifier *ident) -{ - return Dsymbol::oneMember(ps, ident); -} - -int TemplateMixin::apply(Dsymbol_apply_ft_t fp, void *param) -{ - if (members) - { - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (*members)[i]; - if (s) - { - if (s->apply(fp, param)) - return 1; - } - } - } - return 0; -} - -int TemplateMixin::hasPointers() -{ - //printf("TemplateMixin::hasPointers() %s\n", toChars()); - - if (members) - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; - //printf(" s = %s %s\n", s->kind(), s->toChars()); - if (s->hasPointers()) - { - return 1; - } - } - return 0; -} - -void TemplateMixin::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion) -{ - if (members) - { - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (*members)[i]; - s->setFieldOffset(ad, poffset, isunion); - } - } -} - -char *TemplateMixin::toChars() -{ - OutBuffer buf; - HdrGenState hgs; - char *s; - - TemplateInstance::toCBuffer(&buf, &hgs); - s = buf.toChars(); - buf.data = NULL; - return s; -} - -void TemplateMixin::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("mixin "); - - for (size_t i = 0; i < idents->dim; i++) - { Identifier *id = idents->tdata()[i]; - - if (i) - buf->writeByte('.'); - buf->writestring(id->toChars()); - } - buf->writestring("!("); - if (tiargs) - { - for (size_t i = 0; i < tiargs->dim; i++) - { if (i) - buf->writebyte(','); - Object *oarg = tiargs->tdata()[i]; - Type *t = isType(oarg); - Expression *e = isExpression(oarg); - Dsymbol *s = isDsymbol(oarg); - if (t) - t->toCBuffer(buf, NULL, hgs); - else if (e) - e->toCBuffer(buf, hgs); - else if (s) - { - char *p = s->ident ? s->ident->toChars() : s->toChars(); - buf->writestring(p); - } - else if (!oarg) - { - buf->writestring("NULL"); - } - else - { - assert(0); - } - } - } - buf->writebyte(')'); - if (ident) - { - buf->writebyte(' '); - buf->writestring(ident->toChars()); - } - buf->writebyte(';'); - buf->writenl(); -} - - -#if IN_DMD -void TemplateMixin::toObjFile(int multiobj) -{ - //printf("TemplateMixin::toObjFile('%s')\n", toChars()); - TemplateInstance::toObjFile(multiobj); -} -#endif - + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2012 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +// Handle template implementation + +#include +#include + +#include "root.h" +#include "aav.h" +#include "rmem.h" +#include "stringtable.h" +#include "mars.h" +#include "identifier.h" +#include "mtype.h" +#include "template.h" +#include "init.h" +#include "expression.h" +#include "scope.h" +#include "module.h" +#include "aggregate.h" +#include "declaration.h" +#include "dsymbol.h" +#include "hdrgen.h" +#include "id.h" + +#if WINDOWS_SEH +#include +long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep); +#endif + +#define LOG 0 + +/******************************************** + * These functions substitute for dynamic_cast. dynamic_cast does not work + * on earlier versions of gcc. + */ + +Expression *isExpression(Object *o) +{ + //return dynamic_cast(o); + if (!o || o->dyncast() != DYNCAST_EXPRESSION) + return NULL; + return (Expression *)o; +} + +Dsymbol *isDsymbol(Object *o) +{ + //return dynamic_cast(o); + if (!o || o->dyncast() != DYNCAST_DSYMBOL) + return NULL; + return (Dsymbol *)o; +} + +Type *isType(Object *o) +{ + //return dynamic_cast(o); + if (!o || o->dyncast() != DYNCAST_TYPE) + return NULL; + return (Type *)o; +} + +Tuple *isTuple(Object *o) +{ + //return dynamic_cast(o); + if (!o || o->dyncast() != DYNCAST_TUPLE) + return NULL; + return (Tuple *)o; +} + +/************************************** + * Is this Object an error? + */ +int isError(Object *o) +{ + Type *t = isType(o); + if (t) + return (t->ty == Terror); + Expression *e = isExpression(o); + if (e) + return (e->op == TOKerror); + Tuple *v = isTuple(o); + if (v) + return arrayObjectIsError(&v->objects); + return 0; +} + +/************************************** + * Are any of the Objects an error? + */ +int arrayObjectIsError(Objects *args) +{ + for (size_t i = 0; i < args->dim; i++) + { + Object *o = args->tdata()[i]; + if (isError(o)) + return 1; + } + return 0; +} + +/*********************** + * Try to get arg as a type. + */ + +Type *getType(Object *o) +{ + Type *t = isType(o); + if (!t) + { Expression *e = isExpression(o); + if (e) + t = e->type; + } + return t; +} + +Dsymbol *getDsymbol(Object *oarg) +{ + Dsymbol *sa; + Expression *ea = isExpression(oarg); + if (ea) + { // Try to convert Expression to symbol + if (ea->op == TOKvar) + sa = ((VarExp *)ea)->var; + else if (ea->op == TOKfunction) + sa = ((FuncExp *)ea)->fd; + else + sa = NULL; + } + else + { // Try to convert Type to symbol + Type *ta = isType(oarg); + if (ta) + sa = ta->toDsymbol(NULL); + else + sa = isDsymbol(oarg); // if already a symbol + } + return sa; +} + +/****************************** + * If o1 matches o2, return 1. + * Else, return 0. + */ + +int match(Object *o1, Object *o2, TemplateDeclaration *tempdecl, Scope *sc) +{ + Type *t1 = isType(o1); + Type *t2 = isType(o2); + Expression *e1 = isExpression(o1); + Expression *e2 = isExpression(o2); + Dsymbol *s1 = isDsymbol(o1); + Dsymbol *s2 = isDsymbol(o2); + Tuple *u1 = isTuple(o1); + Tuple *u2 = isTuple(o2); + + //printf("\t match t1 %p t2 %p, e1 %p e2 %p, s1 %p s2 %p, u1 %p u2 %p\n", t1,t2,e1,e2,s1,s2,u1,u2); + + /* A proper implementation of the various equals() overrides + * should make it possible to just do o1->equals(o2), but + * we'll do that another day. + */ + + if (s1) + { + VarDeclaration *v1 = s1->isVarDeclaration(); + if (v1 && v1->storage_class & STCmanifest) + { ExpInitializer *ei1 = v1->init->isExpInitializer(); + if (ei1) + e1 = ei1->exp, s1 = NULL; + } + } + if (s2) + { + VarDeclaration *v2 = s2->isVarDeclaration(); + if (v2 && v2->storage_class & STCmanifest) + { ExpInitializer *ei2 = v2->init->isExpInitializer(); + if (ei2) + e2 = ei2->exp, s2 = NULL; + } + } + + if (t1) + { + /* if t1 is an instance of ti, then give error + * about recursive expansions. + */ + Dsymbol *s = t1->toDsymbol(sc); + if (s && s->parent) + { TemplateInstance *ti1 = s->parent->isTemplateInstance(); + if (ti1 && ti1->tempdecl == tempdecl) + { + for (Scope *sc1 = sc; sc1; sc1 = sc1->enclosing) + { + if (sc1->scopesym == ti1) + { + tempdecl->error("recursive template expansion for template argument %s", t1->toChars()); + return 1; // fake a match + } + } + } + } + + //printf("t1 = %s\n", t1->toChars()); + //printf("t2 = %s\n", t2->toChars()); + if (!t2 || !t1->equals(t2)) + goto Lnomatch; + } + else if (e1) + { +#if 0 + if (e1 && e2) + { + printf("match %d\n", e1->equals(e2)); + e1->print(); + e2->print(); + e1->type->print(); + e2->type->print(); + } +#endif + if (!e2) + goto Lnomatch; + if (!e1->equals(e2)) + goto Lnomatch; + } + else if (s1) + { + if (!s2 || !s1->equals(s2) || s1->parent != s2->parent) + goto Lnomatch; + } + else if (u1) + { + if (!u2) + goto Lnomatch; + if (u1->objects.dim != u2->objects.dim) + goto Lnomatch; + for (size_t i = 0; i < u1->objects.dim; i++) + { + if (!match(u1->objects.tdata()[i], + u2->objects.tdata()[i], + tempdecl, sc)) + goto Lnomatch; + } + } + //printf("match\n"); + return 1; // match + +Lnomatch: + //printf("nomatch\n"); + return 0; // nomatch; +} + + +/************************************ + * Match an array of them. + */ +int arrayObjectMatch(Objects *oa1, Objects *oa2, TemplateDeclaration *tempdecl, Scope *sc) +{ + if (oa1 == oa2) + return 1; + if (oa1->dim != oa2->dim) + return 0; + for (size_t j = 0; j < oa1->dim; j++) + { Object *o1 = oa1->tdata()[j]; + Object *o2 = oa2->tdata()[j]; + if (!match(o1, o2, tempdecl, sc)) + { + return 0; + } + } + return 1; +} + +/**************************************** + * This makes a 'pretty' version of the template arguments. + * It's analogous to genIdent() which makes a mangled version. + */ + +void ObjectToCBuffer(OutBuffer *buf, HdrGenState *hgs, Object *oarg) +{ + //printf("ObjectToCBuffer()\n"); + Type *t = isType(oarg); + Expression *e = isExpression(oarg); + Dsymbol *s = isDsymbol(oarg); + Tuple *v = isTuple(oarg); + /* The logic of this should match what genIdent() does. The _dynamic_cast() + * function relies on all the pretty strings to be unique for different classes + * (see Bugzilla 7375). + * Perhaps it would be better to demangle what genIdent() does. + */ + if (t) + { //printf("\tt: %s ty = %d\n", t->toChars(), t->ty); + t->toCBuffer(buf, NULL, hgs); + } + else if (e) + { + if (e->op == TOKvar) + e = e->optimize(WANTvalue); // added to fix Bugzilla 7375 + e->toCBuffer(buf, hgs); + } + else if (s) + { + char *p = s->ident ? s->ident->toChars() : s->toChars(); + buf->writestring(p); + } + else if (v) + { + Objects *args = &v->objects; + for (size_t i = 0; i < args->dim; i++) + { + if (i) + buf->writeByte(','); + Object *o = (*args)[i]; + ObjectToCBuffer(buf, hgs, o); + } + } + else if (!oarg) + { + buf->writestring("NULL"); + } + else + { +#ifdef DEBUG + printf("bad Object = %p\n", oarg); +#endif + assert(0); + } +} + +#if DMDV2 +Object *objectSyntaxCopy(Object *o) +{ + if (!o) + return NULL; + Type *t = isType(o); + if (t) + return t->syntaxCopy(); + Expression *e = isExpression(o); + if (e) + return e->syntaxCopy(); + return o; +} +#endif + + +/* ======================== TemplateDeclaration ============================= */ + +TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id, + TemplateParameters *parameters, Expression *constraint, Dsymbols *decldefs, int ismixin) + : ScopeDsymbol(id) +{ +#if LOG + printf("TemplateDeclaration(this = %p, id = '%s')\n", this, id->toChars()); +#endif +#if 0 + if (parameters) + for (int i = 0; i < parameters->dim; i++) + { TemplateParameter *tp = parameters->tdata()[i]; + //printf("\tparameter[%d] = %p\n", i, tp); + TemplateTypeParameter *ttp = tp->isTemplateTypeParameter(); + + if (ttp) + { + printf("\tparameter[%d] = %s : %s\n", i, tp->ident->toChars(), ttp->specType ? ttp->specType->toChars() : ""); + } + } +#endif + this->loc = loc; + this->parameters = parameters; + this->origParameters = parameters; + this->constraint = constraint; + this->members = decldefs; + this->overnext = NULL; + this->overroot = NULL; + this->semanticRun = PASSinit; + this->onemember = NULL; + this->literal = 0; + this->ismixin = ismixin; + this->previous = NULL; + + // Compute in advance for Ddoc's use + if (members) + { + Dsymbol *s; + if (Dsymbol::oneMembers(members, &s, ident) && s) + { + onemember = s; + s->parent = this; + } + } +} + +Dsymbol *TemplateDeclaration::syntaxCopy(Dsymbol *) +{ + //printf("TemplateDeclaration::syntaxCopy()\n"); + TemplateDeclaration *td; + TemplateParameters *p; + + p = NULL; + if (parameters) + { + p = new TemplateParameters(); + p->setDim(parameters->dim); + for (size_t i = 0; i < p->dim; i++) + { TemplateParameter *tp = (*parameters)[i]; + p->tdata()[i] = tp->syntaxCopy(); + } + } + Expression *e = NULL; + if (constraint) + e = constraint->syntaxCopy(); + Dsymbols *d = Dsymbol::arraySyntaxCopy(members); + td = new TemplateDeclaration(loc, ident, p, e, d, ismixin); + +#if IN_LLVM + td->intrinsicName = intrinsicName; +#endif + + return td; +} + +void TemplateDeclaration::semantic(Scope *sc) +{ +#if LOG + printf("TemplateDeclaration::semantic(this = %p, id = '%s')\n", this, ident->toChars()); + printf("sc->stc = %llx\n", sc->stc); + printf("sc->module = %s\n", sc->module->toChars()); +#endif + if (semanticRun) + return; // semantic() already run + semanticRun = PASSsemantic; + + if (sc->module && sc->module->ident == Id::object && ident == Id::AssociativeArray) + { Type::associativearray = this; + } + + if (sc->func) + { +#if DMDV1 + error("cannot declare template at function scope %s", sc->func->toChars()); +#endif + } + + if (/*global.params.useArrayBounds &&*/ sc->module) + { + // Generate this function as it may be used + // when template is instantiated in other modules + // FIXME: LDC + //sc->module->toModuleArray(); + } + + if (/*global.params.useAssert &&*/ sc->module) + { + // Generate this function as it may be used + // when template is instantiated in other modules + // FIXME: LDC + //sc->module->toModuleAssert(); + } + +#if DMDV2 + if (/*global.params.useUnitTests &&*/ sc->module) + { + // Generate this function as it may be used + // when template is instantiated in other modules + // FIXME: LDC + // sc->module->toModuleUnittest(); + } +#endif + + /* Remember Scope for later instantiations, but make + * a copy since attributes can change. + */ + if (!this->scope) + { this->scope = new Scope(*sc); + this->scope->setNoFree(); + } + + // Set up scope for parameters + ScopeDsymbol *paramsym = new ScopeDsymbol(); + paramsym->parent = sc->parent; + Scope *paramscope = sc->push(paramsym); + paramscope->parameterSpecialization = 1; + paramscope->stc = 0; + + if (!parent) + parent = sc->parent; + + if (global.params.doDocComments) + { + origParameters = new TemplateParameters(); + origParameters->setDim(parameters->dim); + for (size_t i = 0; i < parameters->dim; i++) + { + TemplateParameter *tp = (*parameters)[i]; + origParameters->tdata()[i] = tp->syntaxCopy(); + } + } + + for (size_t i = 0; i < parameters->dim; i++) + { + TemplateParameter *tp = parameters->tdata()[i]; + + tp->declareParameter(paramscope); + } + + for (size_t i = 0; i < parameters->dim; i++) + { + TemplateParameter *tp = (*parameters)[i]; + + tp->semantic(paramscope); + if (i + 1 != parameters->dim && tp->isTemplateTupleParameter()) + { error("template tuple parameter must be last one"); + errors = true; + } + } + + paramscope->pop(); + + // Compute again + onemember = NULL; + if (members) + { + Dsymbol *s; + if (Dsymbol::oneMembers(members, &s, ident) && s) + { + onemember = s; + s->parent = this; + } + } + + /* BUG: should check: + * o no virtual functions or non-static data members of classes + */ +} + +const char *TemplateDeclaration::kind() +{ + return (onemember && onemember->isAggregateDeclaration()) + ? onemember->kind() + : (char *)"template"; +} + +/********************************** + * Overload existing TemplateDeclaration 'this' with the new one 's'. + * Return !=0 if successful; i.e. no conflict. + */ + +int TemplateDeclaration::overloadInsert(Dsymbol *s) +{ + TemplateDeclaration **pf; + TemplateDeclaration *f; + +#if LOG + printf("TemplateDeclaration::overloadInsert('%s')\n", s->toChars()); +#endif + f = s->isTemplateDeclaration(); + if (!f) + return FALSE; + TemplateDeclaration *pthis = this; + for (pf = &pthis; *pf; pf = &(*pf)->overnext) + { +#if 0 + // Conflict if TemplateParameter's match + // Will get caught anyway later with TemplateInstance, but + // should check it now. + TemplateDeclaration *f2 = *pf; + + if (f->parameters->dim != f2->parameters->dim) + goto Lcontinue; + + for (size_t i = 0; i < f->parameters->dim; i++) + { TemplateParameter *p1 = f->parameters->tdata()[i]; + TemplateParameter *p2 = f2->parameters->tdata()[i]; + + if (!p1->overloadMatch(p2)) + goto Lcontinue; + } + +#if LOG + printf("\tfalse: conflict\n"); +#endif + return FALSE; + + Lcontinue: + ; +#endif + } + + f->overroot = this; + *pf = f; +#if LOG + printf("\ttrue: no conflict\n"); +#endif + return TRUE; +} + +/**************************** + * Declare all the function parameters as variables + * and add them to the scope + */ +void TemplateDeclaration::makeParamNamesVisibleInConstraint(Scope *paramscope, Expressions *fargs) +{ + /* We do this ONLY if there is only one function in the template. + */ + FuncDeclaration *fd = onemember && onemember->toAlias() ? + onemember->toAlias()->isFuncDeclaration() : NULL; + if (fd) + { + /* + Making parameters is similar to FuncDeclaration::semantic3 + */ + paramscope->parent = fd; + + TypeFunction *tf = (TypeFunction *)fd->type->syntaxCopy(); + + // Shouldn't run semantic on default arguments and return type. + for (int i = 0; iparameters->dim; i++) + tf->parameters->tdata()[i]->defaultArg = NULL; + tf->next = NULL; + + // Resolve parameter types and 'auto ref's. + tf->fargs = fargs; + tf = (TypeFunction *)tf->semantic(loc, paramscope); + + Parameters *fparameters = tf->parameters; + int fvarargs = tf->varargs; + + size_t nfparams = Parameter::dim(fparameters); // Num function parameters + for (size_t i = 0; i < nfparams; i++) + { + Parameter *fparam = Parameter::getNth(fparameters, i); + // Remove addMod same as func.d L1065 of FuncDeclaration::semantic3 + //Type *vtype = fparam->type; + //if (fd->type && fd->isPure()) + // vtype = vtype->addMod(MODconst); + fparam->storageClass &= (STCin | STCout | STCref | STClazy | STCfinal | STC_TYPECTOR | STCnodtor); + fparam->storageClass |= STCparameter; + if (fvarargs == 2 && i + 1 == nfparams) + fparam->storageClass |= STCvariadic; + } + for (size_t i = 0; i < fparameters->dim; i++) + { + Parameter *fparam = fparameters->tdata()[i]; + if (!fparam->ident) + continue; // don't add it, if it has no name + VarDeclaration *v = new VarDeclaration(loc, fparam->type, fparam->ident, NULL); + v->storage_class = fparam->storageClass; + v->semantic(paramscope); + if (!paramscope->insert(v)) + error("parameter %s.%s is already defined", toChars(), v->toChars()); + else + v->parent = this; + } + } +} + +/*************************************** + * Given that ti is an instance of this TemplateDeclaration, + * deduce the types of the parameters to this, and store + * those deduced types in dedtypes[]. + * Input: + * flag 1: don't do semantic() because of dummy types + * 2: don't change types in matchArg() + * Output: + * dedtypes deduced arguments + * Return match level. + */ + +MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, + Objects *dedtypes, Expressions *fargs, int flag) +{ MATCH m; + size_t dedtypes_dim = dedtypes->dim; + +#define LOGM 0 +#if LOGM + printf("\n+TemplateDeclaration::matchWithInstance(this = %s, ti = %s, flag = %d)\n", toChars(), ti->toChars(), flag); +#endif + +#if 0 + printf("dedtypes->dim = %d, parameters->dim = %d\n", dedtypes_dim, parameters->dim); + if (ti->tiargs->dim) + printf("ti->tiargs->dim = %d, [0] = %p\n", + ti->tiargs->dim, + ti->tiargs->tdata()[0]); +#endif + dedtypes->zero(); + + if (errors) + return MATCHnomatch; + + size_t parameters_dim = parameters->dim; + int variadic = isVariadic() != NULL; + + // If more arguments than parameters, no match + if (ti->tiargs->dim > parameters_dim && !variadic) + { +#if LOGM + printf(" no match: more arguments than parameters\n"); +#endif + return MATCHnomatch; + } + + assert(dedtypes_dim == parameters_dim); + assert(dedtypes_dim >= ti->tiargs->dim || variadic); + + // Set up scope for parameters + assert((size_t)scope > 0x10000); + ScopeDsymbol *paramsym = new ScopeDsymbol(); + paramsym->parent = scope->parent; + Scope *paramscope = scope->push(paramsym); + paramscope->stc = 0; + + // Attempt type deduction + m = MATCHexact; + for (size_t i = 0; i < dedtypes_dim; i++) + { MATCH m2; + TemplateParameter *tp = parameters->tdata()[i]; + Declaration *sparam; + + //printf("\targument [%d]\n", i); +#if LOGM + //printf("\targument [%d] is %s\n", i, oarg ? oarg->toChars() : "null"); + TemplateTypeParameter *ttp = tp->isTemplateTypeParameter(); + if (ttp) + printf("\tparameter[%d] is %s : %s\n", i, tp->ident->toChars(), ttp->specType ? ttp->specType->toChars() : ""); +#endif + + m2 = tp->matchArg(paramscope, ti->tiargs, i, parameters, dedtypes, &sparam); + //printf("\tm2 = %d\n", m2); + + if (m2 == MATCHnomatch) + { +#if 0 + printf("\tmatchArg() for parameter %i failed\n", i); +#endif + goto Lnomatch; + } + + if (m2 < m) + m = m2; + + if (!flag) + sparam->semantic(paramscope); + if (!paramscope->insert(sparam)) + goto Lnomatch; + } + + if (!flag) + { + /* Any parameter left without a type gets the type of + * its corresponding arg + */ + for (size_t i = 0; i < dedtypes_dim; i++) + { + if (!dedtypes->tdata()[i]) + { assert(i < ti->tiargs->dim); + dedtypes->tdata()[i] = (Type *)ti->tiargs->tdata()[i]; + } + } + } + +#if DMDV2 + if (m && constraint && !flag) + { /* Check to see if constraint is satisfied. + */ + makeParamNamesVisibleInConstraint(paramscope, fargs); + Expression *e = constraint->syntaxCopy(); + Scope *sc = paramscope->push(); + + /* There's a chicken-and-egg problem here. We don't know yet if this template + * instantiation will be a local one (isnested is set), and we won't know until + * after selecting the correct template. Thus, function we're nesting inside + * is not on the sc scope chain, and this can cause errors in FuncDeclaration::getLevel(). + * Workaround the problem by setting a flag to relax the checking on frame errors. + */ + sc->flags |= SCOPEstaticif; + + FuncDeclaration *fd = onemember && onemember->toAlias() ? + onemember->toAlias()->isFuncDeclaration() : NULL; + Dsymbol *s = parent; + while (s->isTemplateInstance() || s->isTemplateMixin()) + s = s->parent; + AggregateDeclaration *ad = s->isAggregateDeclaration(); + VarDeclaration *vthissave; + if (fd && ad) + { + vthissave = fd->vthis; + fd->vthis = fd->declareThis(paramscope, ad); + } + + e = e->semantic(sc); + + if (fd && fd->vthis) + fd->vthis = vthissave; + + sc->pop(); + e = e->optimize(WANTvalue | WANTinterpret); + if (e->isBool(TRUE)) + ; + else if (e->isBool(FALSE)) + goto Lnomatch; + else + { + e->error("constraint %s is not constant or does not evaluate to a bool", e->toChars()); + } + } +#endif + +#if LOGM + // Print out the results + printf("--------------------------\n"); + printf("template %s\n", toChars()); + printf("instance %s\n", ti->toChars()); + if (m) + { + for (size_t i = 0; i < dedtypes_dim; i++) + { + TemplateParameter *tp = parameters->tdata()[i]; + Object *oarg; + + printf(" [%d]", i); + + if (i < ti->tiargs->dim) + oarg = ti->tiargs->tdata()[i]; + else + oarg = NULL; + tp->print(oarg, dedtypes->tdata()[i]); + } + } + else + goto Lnomatch; +#endif + +#if LOGM + printf(" match = %d\n", m); +#endif + goto Lret; + +Lnomatch: +#if LOGM + printf(" no match\n"); +#endif + m = MATCHnomatch; + +Lret: + paramscope->pop(); +#if LOGM + printf("-TemplateDeclaration::matchWithInstance(this = %p, ti = %p) = %d\n", this, ti, m); +#endif + return m; +} + +/******************************************** + * Determine partial specialization order of 'this' vs td2. + * Returns: + * match this is at least as specialized as td2 + * 0 td2 is more specialized than this + */ + +MATCH TemplateDeclaration::leastAsSpecialized(TemplateDeclaration *td2, Expressions *fargs) +{ + /* This works by taking the template parameters to this template + * declaration and feeding them to td2 as if it were a template + * instance. + * If it works, then this template is at least as specialized + * as td2. + */ + + TemplateInstance ti(0, ident); // create dummy template instance + Objects dedtypes; + +#define LOG_LEASTAS 0 + +#if LOG_LEASTAS + printf("%s.leastAsSpecialized(%s)\n", toChars(), td2->toChars()); +#endif + + // Set type arguments to dummy template instance to be types + // generated from the parameters to this template declaration + ti.tiargs = new Objects(); + ti.tiargs->setDim(parameters->dim); + for (size_t i = 0; i < ti.tiargs->dim; i++) + { + TemplateParameter *tp = parameters->tdata()[i]; + + Object *p = (Object *)tp->dummyArg(); + if (p) + ti.tiargs->tdata()[i] = p; + else + ti.tiargs->setDim(i); + } + + // Temporary Array to hold deduced types + //dedtypes.setDim(parameters->dim); + dedtypes.setDim(td2->parameters->dim); + + // Attempt a type deduction + MATCH m = td2->matchWithInstance(&ti, &dedtypes, fargs, 1); + if (m) + { + /* A non-variadic template is more specialized than a + * variadic one. + */ + if (isVariadic() && !td2->isVariadic()) + goto L1; + +#if LOG_LEASTAS + printf(" matches %d, so is least as specialized\n", m); +#endif + return m; + } + L1: +#if LOG_LEASTAS + printf(" doesn't match, so is not as specialized\n"); +#endif + return MATCHnomatch; +} + + +/************************************************* + * Match function arguments against a specific template function. + * Input: + * loc instantiation location + * targsi Expression/Type initial list of template arguments + * ethis 'this' argument if !NULL + * fargs arguments to function + * Output: + * dedargs Expression/Type deduced template arguments + * Returns: + * match level + */ + +MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Scope *sc, Loc loc, Objects *targsi, + Expression *ethis, Expressions *fargs, + Objects *dedargs) +{ + size_t nfparams; + size_t nfargs; + size_t nargsi; // array size of targsi + int fptupindex = -1; + int tuple_dim = 0; + MATCH match = MATCHexact; + FuncDeclaration *fd = onemember->toAlias()->isFuncDeclaration(); + Parameters *fparameters; // function parameter list + int fvarargs; // function varargs + Objects dedtypes; // for T:T*, the dedargs is the T*, dedtypes is the T + unsigned wildmatch = 0; + + TypeFunction *tf = (TypeFunction *)fd->type; + +#if 0 + printf("\nTemplateDeclaration::deduceFunctionTemplateMatch() %s\n", toChars()); + for (size_t i = 0; i < fargs->dim; i++) + { Expression *e = fargs->tdata()[i]; + printf("\tfarg[%d] is %s, type is %s\n", i, e->toChars(), e->type->toChars()); + } + printf("fd = %s\n", fd->toChars()); + printf("fd->type = %s\n", fd->type->toChars()); + if (ethis) + printf("ethis->type = %s\n", ethis->type->toChars()); +#endif + + assert((size_t)scope > 0x10000); + + dedargs->setDim(parameters->dim); + dedargs->zero(); + + dedtypes.setDim(parameters->dim); + dedtypes.zero(); + + if (errors) + return MATCHnomatch; + + // Set up scope for parameters + ScopeDsymbol *paramsym = new ScopeDsymbol(); + paramsym->parent = scope->parent; + Scope *paramscope = scope->push(paramsym); + paramscope->stc = 0; + + TemplateTupleParameter *tp = isVariadic(); + int tp_is_declared = 0; + +#if 0 + for (size_t i = 0; i < dedargs->dim; i++) + { + printf("\tdedarg[%d] = ", i); + Object *oarg = dedargs->tdata()[i]; + if (oarg) printf("%s", oarg->toChars()); + printf("\n"); + } +#endif + + + nargsi = 0; + if (targsi) + { // Set initial template arguments + + nargsi = targsi->dim; + size_t n = parameters->dim; + if (tp) + n--; + if (nargsi > n) + { if (!tp) + goto Lnomatch; + + /* The extra initial template arguments + * now form the tuple argument. + */ + Tuple *t = new Tuple(); + assert(parameters->dim); + dedargs->tdata()[parameters->dim - 1] = t; + + tuple_dim = nargsi - n; + t->objects.setDim(tuple_dim); + for (size_t i = 0; i < tuple_dim; i++) + { + t->objects.tdata()[i] = targsi->tdata()[n + i]; + } + declareParameter(paramscope, tp, t); + tp_is_declared = 1; + } + else + n = nargsi; + + memcpy(dedargs->tdata(), targsi->tdata(), n * sizeof(*dedargs->tdata())); + + for (size_t i = 0; i < n; i++) + { assert(i < parameters->dim); + TemplateParameter *tp = parameters->tdata()[i]; + MATCH m; + Declaration *sparam = NULL; + + m = tp->matchArg(paramscope, dedargs, i, parameters, &dedtypes, &sparam); + //printf("\tdeduceType m = %d\n", m); + if (m == MATCHnomatch) + goto Lnomatch; + if (m < match) + match = m; + + sparam->semantic(paramscope); + if (!paramscope->insert(sparam)) + goto Lnomatch; + } + } +#if 0 + for (size_t i = 0; i < dedargs->dim; i++) + { + printf("\tdedarg[%d] = ", i); + Object *oarg = dedargs->tdata()[i]; + if (oarg) printf("%s", oarg->toChars()); + printf("\n"); + } +#endif + + fparameters = fd->getParameters(&fvarargs); + nfparams = Parameter::dim(fparameters); // number of function parameters + nfargs = fargs ? fargs->dim : 0; // number of function arguments + + /* Check for match of function arguments with variadic template + * parameter, such as: + * + * template Foo(T, A...) { void Foo(T t, A a); } + * void main() { Foo(1,2,3); } + */ + if (tp) // if variadic + { + if (nfparams == 0 && nfargs != 0) // if no function parameters + { + if (tp_is_declared) + goto L2; + Tuple *t = new Tuple(); + //printf("t = %p\n", t); + dedargs->tdata()[parameters->dim - 1] = t; + declareParameter(paramscope, tp, t); + goto L2; + } + else if (nfargs < nfparams - 1) + goto L1; + else + { + /* Figure out which of the function parameters matches + * the tuple template parameter. Do this by matching + * type identifiers. + * Set the index of this function parameter to fptupindex. + */ + for (fptupindex = 0; fptupindex < nfparams; fptupindex++) + { + Parameter *fparam = fparameters->tdata()[fptupindex]; + if (fparam->type->ty != Tident) + continue; + TypeIdentifier *tid = (TypeIdentifier *)fparam->type; + if (!tp->ident->equals(tid->ident) || tid->idents.dim) + continue; + + if (fvarargs) // variadic function doesn't + goto Lnomatch; // go with variadic template + + if (tp_is_declared) + goto L2; + + // Apply function parameter storage classes to parameter type + tid = (TypeIdentifier *)tid->addStorageClass(fparam->storageClass); + + /* The types of the function arguments + * now form the tuple argument. + */ + Tuple *t = new Tuple(); + dedargs->tdata()[parameters->dim - 1] = t; + + tuple_dim = nfargs - (nfparams - 1); + t->objects.setDim(tuple_dim); + for (size_t i = 0; i < tuple_dim; i++) + { Expression *farg = fargs->tdata()[fptupindex + i]; + + // Check invalid arguments to detect errors early. + if (farg->op == TOKerror || farg->type->ty == Terror) + goto Lnomatch; + + if (!(fparam->storageClass & STClazy) && farg->type->ty == Tvoid) + goto Lnomatch; + + unsigned mod = farg->type->mod; + Type *tt; + MATCH m; + + #define X(U,T) ((U) << 4) | (T) + if (tid->mod & MODwild) + { + switch (X(tid->mod, mod)) + { + case X(MODwild, MODwild): + case X(MODwild | MODshared, MODwild | MODshared): + case X(MODwild, 0): + case X(MODwild, MODconst): + case X(MODwild, MODimmutable): + case X(MODwild | MODshared, MODshared): + case X(MODwild | MODshared, MODconst | MODshared): + + if (mod & MODwild) + wildmatch |= MODwild; + else if (mod == 0) + wildmatch |= MODmutable; + else + wildmatch |= (mod & ~MODshared); + tt = farg->type->mutableOf(); + m = MATCHconst; + goto Lx; + + default: + break; + } + } + + switch (X(tid->mod, mod)) + { + case X(0, 0): + case X(0, MODconst): + case X(0, MODimmutable): + case X(0, MODshared): + case X(0, MODconst | MODshared): + case X(0, MODwild): + case X(0, MODwild | MODshared): + // foo(U:U) T => T + // foo(U:U) const(T) => const(T) + // foo(U:U) immutable(T) => immutable(T) + // foo(U:U) shared(T) => shared(T) + // foo(U:U) const(shared(T)) => const(shared(T)) + // foo(U:U) wild(T) => wild(T) + // foo(U:U) wild(shared(T)) => wild(shared(T)) + + tt = farg->type; + m = MATCHexact; + break; + + case X(MODconst, MODconst): + case X(MODimmutable, MODimmutable): + case X(MODshared, MODshared): + case X(MODconst | MODshared, MODconst | MODshared): + case X(MODwild, MODwild): + case X(MODwild | MODshared, MODwild | MODshared): + // foo(U:const(U)) const(T) => T + // foo(U:immutable(U)) immutable(T) => T + // foo(U:shared(U)) shared(T) => T + // foo(U:const(shared(U)) const(shared(T)) => T + // foo(U:wild(U)) wild(T) => T + // foo(U:wild(shared(U)) wild(shared(T)) => T + + tt = farg->type->mutableOf()->unSharedOf(); + m = MATCHexact; + break; + + case X(MODconst, 0): + case X(MODconst, MODimmutable): + case X(MODconst, MODconst | MODshared): + case X(MODconst | MODshared, MODimmutable): + case X(MODconst, MODwild): + case X(MODconst, MODwild | MODshared): + // foo(U:const(U)) T => T + // foo(U:const(U)) immutable(T) => T + // foo(U:const(U)) const(shared(T)) => shared(T) + // foo(U:const(shared(U)) immutable(T) => T + // foo(U:const(U)) wild(shared(T)) => shared(T) + + tt = farg->type->mutableOf(); + m = MATCHconst; + break; + + case X(MODshared, MODconst | MODshared): + case X(MODconst | MODshared, MODshared): + case X(MODshared, MODwild | MODshared): + // foo(U:shared(U)) const(shared(T)) => const(T) + // foo(U:const(shared(U)) shared(T) => T + // foo(U:shared(U)) wild(shared(T)) => wild(T) + tt = farg->type->unSharedOf(); + m = MATCHconst; + break; + + case X(MODimmutable, 0): + case X(MODimmutable, MODconst): + case X(MODimmutable, MODshared): + case X(MODimmutable, MODconst | MODshared): + case X(MODconst, MODshared): + case X(MODshared, 0): + case X(MODshared, MODconst): + case X(MODshared, MODimmutable): + case X(MODconst | MODshared, 0): + case X(MODconst | MODshared, MODconst): + case X(MODimmutable, MODwild): + case X(MODshared, MODwild): + case X(MODconst | MODshared, MODwild): + case X(MODwild, 0): + case X(MODwild, MODconst): + case X(MODwild, MODimmutable): + case X(MODwild, MODshared): + case X(MODwild, MODconst | MODshared): + case X(MODwild | MODshared, 0): + case X(MODwild | MODshared, MODconst): + case X(MODwild | MODshared, MODimmutable): + case X(MODwild | MODshared, MODshared): + case X(MODwild | MODshared, MODconst | MODshared): + case X(MODwild | MODshared, MODwild): + case X(MODimmutable, MODwild | MODshared): + case X(MODconst | MODshared, MODwild | MODshared): + case X(MODwild, MODwild | MODshared): + + // foo(U:immutable(U)) T => nomatch + // foo(U:immutable(U)) const(T) => nomatch + // foo(U:immutable(U)) shared(T) => nomatch + // foo(U:immutable(U)) const(shared(T)) => nomatch + // foo(U:const(U)) shared(T) => nomatch + // foo(U:shared(U)) T => nomatch + // foo(U:shared(U)) const(T) => nomatch + // foo(U:shared(U)) immutable(T) => nomatch + // foo(U:const(shared(U)) T => nomatch + // foo(U:const(shared(U)) const(T) => nomatch + // foo(U:immutable(U)) wild(T) => nomatch + // foo(U:shared(U)) wild(T) => nomatch + // foo(U:const(shared(U)) wild(T) => nomatch + // foo(U:wild(U)) T => nomatch + // foo(U:wild(U)) const(T) => nomatch + // foo(U:wild(U)) immutable(T) => nomatch + // foo(U:wild(U)) shared(T) => nomatch + // foo(U:wild(U)) const(shared(T)) => nomatch + // foo(U:wild(shared(U)) T => nomatch + // foo(U:wild(shared(U)) const(T) => nomatch + // foo(U:wild(shared(U)) immutable(T) => nomatch + // foo(U:wild(shared(U)) shared(T) => nomatch + // foo(U:wild(shared(U)) const(shared(T)) => nomatch + // foo(U:wild(shared(U)) wild(T) => nomatch + // foo(U:immutable(U)) wild(shared(T)) => nomatch + // foo(U:const(shared(U))) wild(shared(T)) => nomatch + // foo(U:wild(U)) wild(shared(T)) => nomatch + m = MATCHnomatch; + break; + + default: + assert(0); + } + #undef X + + Lx: + if (m == MATCHnomatch) + goto Lnomatch; + if (m < match) + match = m; + + t->objects.tdata()[i] = tt; + } + declareParameter(paramscope, tp, t); + goto L2; + } + fptupindex = -1; + } + } + +L1: + if (nfparams == nfargs) + ; + else if (nfargs > nfparams) + { + if (fvarargs == 0) + goto Lnomatch; // too many args, no match + match = MATCHconvert; // match ... with a conversion + } + +L2: +#if DMDV2 + if (ethis) + { + // Match 'ethis' to any TemplateThisParameter's + for (size_t i = 0; i < parameters->dim; i++) + { TemplateParameter *tp = parameters->tdata()[i]; + TemplateThisParameter *ttp = tp->isTemplateThisParameter(); + if (ttp) + { MATCH m; + + Type *t = new TypeIdentifier(0, ttp->ident); + m = ethis->type->deduceType(paramscope, t, parameters, &dedtypes); + if (!m) + goto Lnomatch; + if (m < match) + match = m; // pick worst match + } + } + + // Match attributes of ethis against attributes of fd + if (fd->type) + { + Type *tthis = ethis->type; + unsigned mod = fd->type->mod; + StorageClass stc = scope->stc | fd->storage_class2; + // Propagate parent storage class (see bug 5504) + Dsymbol *p = parent; + while (p->isTemplateDeclaration() || p->isTemplateInstance()) + p = p->parent; + AggregateDeclaration *ad = p->isAggregateDeclaration(); + if (ad) + stc |= ad->storage_class; + + if (stc & (STCshared | STCsynchronized)) + mod |= MODshared; + if (stc & STCimmutable) + mod |= MODimmutable; + if (stc & STCconst) + mod |= MODconst; + if (stc & STCwild) + mod |= MODwild; + // Fix mod + if (mod & MODimmutable) + mod = MODimmutable; + if (mod & MODconst) + mod &= ~STCwild; + if (tthis->mod != mod) + { + if (!MODmethodConv(tthis->mod, mod)) + goto Lnomatch; + if (MATCHconst < match) + match = MATCHconst; + } + } + } +#endif + + // Loop through the function parameters + for (size_t parami = 0; parami < nfparams; parami++) + { + /* Skip over function parameters which wound up + * as part of a template tuple parameter. + */ + if (parami == fptupindex) + continue; + /* Set i = index into function arguments + * Function parameters correspond to function arguments as follows. + * Note that tuple_dim may be zero, and there may be default or + * variadic arguments at the end. + * arg [0..fptupindex] == param[0..fptupindex] + * arg [fptupindex..fptupindex+tuple_dim] == param[fptupindex] + * arg[fputupindex+dim.. ] == param[fptupindex+1.. ] + */ + size_t i = parami; + if (fptupindex >= 0 && parami > fptupindex) + i += tuple_dim - 1; + + Parameter *fparam = Parameter::getNth(fparameters, parami); + + if (i >= nfargs) // if not enough arguments + { + if (fparam->defaultArg) + { /* Default arguments do not participate in template argument + * deduction. + */ + goto Lmatch; + } + } + else + { + Expression *farg = fargs->tdata()[i]; + + // Check invalid arguments to detect errors early. + if (farg->op == TOKerror || farg->type->ty == Terror) + goto Lnomatch; + +Lretry: +#if 0 + printf("\tfarg->type = %s\n", farg->type->toChars()); + printf("\tfparam->type = %s\n", fparam->type->toChars()); +#endif + Type *argtype = farg->type; + + // Apply function parameter storage classes to parameter types + fparam->type = fparam->type->addStorageClass(fparam->storageClass); + +#if DMDV2 + /* Allow string literals which are type [] to match with [dim] + */ + if (farg->op == TOKstring) + { StringExp *se = (StringExp *)farg; + if (!se->committed && argtype->ty == Tarray && + fparam->type->toBasetype()->ty == Tsarray) + { + argtype = new TypeSArray(argtype->nextOf(), new IntegerExp(se->loc, se->len, Type::tindex)); + argtype = argtype->semantic(se->loc, NULL); + argtype = argtype->invariantOf(); + } + } + + /* Allow implicit function literals to delegate conversion + */ + if (farg->op == TOKfunction) + { FuncExp *fe = (FuncExp *)farg; + Type *tp = fparam->type; + Expression *e = fe->inferType(tp, 1, parameters); + if (!e) + goto Lvarargs; + farg = e; + argtype = farg->type; + } + + if (!(fparam->storageClass & STClazy) && argtype->ty == Tvoid) + goto Lnomatch; + + /* Remove top const for dynamic array types and pointer types + */ + if ((argtype->ty == Tarray || argtype->ty == Tpointer) && + !argtype->isMutable() && + (!(fparam->storageClass & STCref) || + (fparam->storageClass & STCauto) && !farg->isLvalue())) + { + argtype = argtype->mutableOf(); + } +#endif + + if (fvarargs == 2 && i + 1 == nfparams && i + 1 < nfargs) + goto Lvarargs; + + unsigned wm = 0; + MATCH m = argtype->deduceType(paramscope, fparam->type, parameters, &dedtypes, &wm); + //printf("\tdeduceType m = %d\n", m); + //printf("\twildmatch = x%x m = %d\n", wildmatch, m); + wildmatch |= wm; + + /* If no match, see if there's a conversion to a delegate + */ + if (!m) + { Type *tbp = fparam->type->toBasetype(); + Type *tba = farg->type->toBasetype(); + AggregateDeclaration *ad; + if (tbp->ty == Tdelegate) + { + TypeDelegate *td = (TypeDelegate *)fparam->type->toBasetype(); + TypeFunction *tf = (TypeFunction *)td->next; + + if (!tf->varargs && Parameter::dim(tf->parameters) == 0) + { + m = farg->type->deduceType(paramscope, tf->next, parameters, &dedtypes); + if (!m && tf->next->toBasetype()->ty == Tvoid) + m = MATCHconvert; + } + //printf("\tm2 = %d\n", m); + } + else if (tba->ty == Tclass) + { + ad = ((TypeClass *)tba)->sym; + goto Lad; + } + else if (tba->ty == Tstruct) + { + ad = ((TypeStruct *)tba)->sym; + Lad: + if (ad->aliasthis) + { /* If a semantic error occurs while doing alias this, + * eg purity(bug 7295), just regard it as not a match. + */ + unsigned olderrors = global.startGagging(); + Expression *e = resolveAliasThis(sc, farg); + if (!global.endGagging(olderrors)) + { farg = e; + goto Lretry; + } + } + } + } + + if (m && (fparam->storageClass & (STCref | STCauto)) == STCref) + { if (!farg->isLvalue()) + { + if (farg->op == TOKstructliteral) + m = MATCHconvert; + else if (farg->op == TOKcall) + { + CallExp *ce = (CallExp *)farg; + if (ce->e1->op == TOKdotvar && + ((DotVarExp *)ce->e1)->var->isCtorDeclaration()) + { + m = MATCHconvert; + } + else + goto Lnomatch; + } + else + goto Lnomatch; + } + } + if (m && (fparam->storageClass & STCout)) + { if (!farg->isLvalue()) + goto Lnomatch; + } + if (!m && (fparam->storageClass & STClazy) && fparam->type->ty == Tvoid && + farg->type->ty != Tvoid) + m = MATCHconvert; + + if (m) + { if (m < match) + match = m; // pick worst match + continue; + } + } + + Lvarargs: + /* The following code for variadic arguments closely + * matches TypeFunction::callMatch() + */ + if (!(fvarargs == 2 && i + 1 == nfparams)) + goto Lnomatch; + + /* Check for match with function parameter T... + */ + Type *tb = fparam->type->toBasetype(); + switch (tb->ty) + { + // Perhaps we can do better with this, see TypeFunction::callMatch() + case Tsarray: + { TypeSArray *tsa = (TypeSArray *)tb; + dinteger_t sz = tsa->dim->toInteger(); + if (sz != nfargs - i) + goto Lnomatch; + } + case Tarray: + { TypeArray *ta = (TypeArray *)tb; + for (; i < nfargs; i++) + { + Expression *arg = fargs->tdata()[i]; + assert(arg); + + if (arg->op == TOKfunction) + { FuncExp *fe = (FuncExp *)arg; + Type *tp = tb->nextOf(); + + Expression *e = fe->inferType(tp, 1, parameters); + if (!e) + goto Lnomatch; + arg = e; + } + + MATCH m; + /* If lazy array of delegates, + * convert arg(s) to delegate(s) + */ + Type *tret = fparam->isLazyArray(); + if (tret) + { + if (ta->next->equals(arg->type)) + { m = MATCHexact; + } + else + { + m = arg->implicitConvTo(tret); + if (m == MATCHnomatch) + { + if (tret->toBasetype()->ty == Tvoid) + m = MATCHconvert; + } + } + } + else + { + m = arg->type->deduceType(paramscope, ta->next, parameters, &dedtypes); + //m = arg->implicitConvTo(ta->next); + } + if (m == MATCHnomatch) + goto Lnomatch; + if (m < match) + match = m; + } + goto Lmatch; + } + case Tclass: + case Tident: + goto Lmatch; + + default: + goto Lnomatch; + } + } + +Lmatch: + + for (size_t i = nargsi; i < dedargs->dim; i++) + { + TemplateParameter *tparam = parameters->tdata()[i]; + //printf("tparam[%d] = %s\n", i, tparam->ident->toChars()); + /* For T:T*, the dedargs is the T*, dedtypes is the T + * But for function templates, we really need them to match + */ + Object *oarg = dedargs->tdata()[i]; + Object *oded = dedtypes.tdata()[i]; + //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded); + //if (oarg) printf("oarg: %s\n", oarg->toChars()); + //if (oded) printf("oded: %s\n", oded->toChars()); + if (!oarg) + { + if (oded) + { + if (tparam->specialization()) + { /* The specialization can work as long as afterwards + * the oded == oarg + */ + Declaration *sparam; + dedargs->tdata()[i] = oded; + MATCH m2 = tparam->matchArg(paramscope, dedargs, i, parameters, &dedtypes, &sparam); + //printf("m2 = %d\n", m2); + if (!m2) + goto Lnomatch; + if (m2 < match) + match = m2; // pick worst match + if (dedtypes.tdata()[i] != oded) + error("specialization not allowed for deduced parameter %s", tparam->ident->toChars()); + } + } + else + { oded = tparam->defaultArg(loc, paramscope); + if (!oded) + { + if (tp && // if tuple parameter and + fptupindex < 0 && // tuple parameter was not in function parameter list and + nargsi == dedargs->dim - 1) // we're one argument short (i.e. no tuple argument) + { // make tuple argument an empty tuple + oded = (Object *)new Tuple(); + } + else + goto Lnomatch; + } + } + declareParameter(paramscope, tparam, oded); + dedargs->tdata()[i] = oded; + } + } + +#if DMDV2 + if (constraint) + { /* Check to see if constraint is satisfied. + * Most of this code appears twice; this is a good candidate for refactoring. + */ + makeParamNamesVisibleInConstraint(paramscope, fargs); + Expression *e = constraint->syntaxCopy(); + paramscope->ignoreTemplates++; + paramscope->flags |= SCOPEstaticif; + + /* Detect recursive attempts to instantiate this template declaration, + * Bugzilla 4072 + * void foo(T)(T x) if (is(typeof(foo(x)))) { } + * static assert(!is(typeof(foo(7)))); + * Recursive attempts are regarded as a constraint failure. + */ + int nmatches = 0; + for (Previous *p = previous; p; p = p->prev) + { + if (arrayObjectMatch(p->dedargs, dedargs, this, sc)) + { + //printf("recursive, no match p->sc=%p %p %s\n", p->sc, this, this->toChars()); + /* It must be a subscope of p->sc, other scope chains are not recursive + * instantiations. + */ + for (Scope *scx = sc; scx; scx = scx->enclosing) + { + if (scx == p->sc) + goto Lnomatch; + } + } + /* BUG: should also check for ref param differences + */ + } + + Previous pr; + pr.prev = previous; + pr.sc = paramscope; + pr.dedargs = dedargs; + previous = ≺ // add this to threaded list + + int nerrors = global.errors; + + FuncDeclaration *fd = onemember && onemember->toAlias() ? + onemember->toAlias()->isFuncDeclaration() : NULL; + Dsymbol *s = parent; + while (s->isTemplateInstance() || s->isTemplateMixin()) + s = s->parent; + AggregateDeclaration *ad = s->isAggregateDeclaration(); + VarDeclaration *vthissave; + if (fd && ad) + { + vthissave = fd->vthis; + fd->vthis = fd->declareThis(paramscope, ad); + } + + e = e->semantic(paramscope); + + if (fd && fd->vthis) + fd->vthis = vthissave; + + previous = pr.prev; // unlink from threaded list + + if (nerrors != global.errors) // if any errors from evaluating the constraint, no match + goto Lnomatch; + + e = e->optimize(WANTvalue | WANTinterpret); + if (e->isBool(TRUE)) + ; + else if (e->isBool(FALSE)) + goto Lnomatch; + else + { + e->error("constraint %s is not constant or does not evaluate to a bool", e->toChars()); + } + } +#endif + +#if 0 + for (i = 0; i < dedargs->dim; i++) + { Type *t = dedargs->tdata()[i]; + printf("\tdedargs[%d] = %d, %s\n", i, t->dyncast(), t->toChars()); + } +#endif + + paramscope->pop(); + //printf("\tmatch %d\n", match); + return match; + +Lnomatch: + paramscope->pop(); + //printf("\tnomatch\n"); + return MATCHnomatch; +} + +/************************************************** + * Declare template parameter tp with value o, and install it in the scope sc. + */ + +void TemplateDeclaration::declareParameter(Scope *sc, TemplateParameter *tp, Object *o) +{ + //printf("TemplateDeclaration::declareParameter('%s', o = %p)\n", tp->ident->toChars(), o); + + Type *targ = isType(o); + Expression *ea = isExpression(o); + Dsymbol *sa = isDsymbol(o); + Tuple *va = isTuple(o); + + Dsymbol *s; + + // See if tp->ident already exists with a matching definition + Dsymbol *scopesym; + s = sc->search(loc, tp->ident, &scopesym); + if (s && scopesym == sc->scopesym) + { + TupleDeclaration *td = s->isTupleDeclaration(); + if (va && td) + { Tuple tup; + tup.objects = *td->objects; + if (match(va, &tup, this, sc)) + { + return; + } + } + } + + if (targ) + { + //printf("type %s\n", targ->toChars()); + s = new AliasDeclaration(0, tp->ident, targ); + } + else if (sa) + { + //printf("Alias %s %s;\n", sa->ident->toChars(), tp->ident->toChars()); + s = new AliasDeclaration(0, tp->ident, sa); + } + else if (ea) + { + // tdtypes.data[i] always matches ea here + Initializer *init = new ExpInitializer(loc, ea); + TemplateValueParameter *tvp = tp->isTemplateValueParameter(); + + Type *t = tvp ? tvp->valType : NULL; + + VarDeclaration *v = new VarDeclaration(loc, t, tp->ident, init); + v->storage_class = STCmanifest; + s = v; + } + else if (va) + { + //printf("\ttuple\n"); + s = new TupleDeclaration(loc, tp->ident, &va->objects); + } + else + { +#ifdef DEBUG + o->print(); +#endif + assert(0); + } + if (!sc->insert(s)) + error("declaration %s is already defined", tp->ident->toChars()); + s->semantic(sc); +} + +/************************************** + * Determine if TemplateDeclaration is variadic. + */ + +TemplateTupleParameter *isVariadic(TemplateParameters *parameters) +{ size_t dim = parameters->dim; + TemplateTupleParameter *tp = NULL; + + if (dim) + tp = (parameters->tdata()[dim - 1])->isTemplateTupleParameter(); + return tp; +} + +TemplateTupleParameter *TemplateDeclaration::isVariadic() +{ + return ::isVariadic(parameters); +} + +/*********************************** + * We can overload templates. + */ + +int TemplateDeclaration::isOverloadable() +{ + return 1; +} + +/************************************************* + * Given function arguments, figure out which template function + * to expand, and return that function. + * If no match, give error message and return NULL. + * Input: + * sc instantiation scope + * loc instantiation location + * targsi initial list of template arguments + * ethis if !NULL, the 'this' pointer argument + * fargs arguments to function + * flags 1: do not issue error message on no match, just return NULL + */ + +FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, + Objects *targsi, Expression *ethis, Expressions *fargs, int flags) +{ + MATCH m_best = MATCHnomatch; + TemplateDeclaration *td_ambig = NULL; + TemplateDeclaration *td_best = NULL; + Objects *tdargs = new Objects(); + TemplateInstance *ti; + FuncDeclaration *fd_best; + +#if 0 + printf("TemplateDeclaration::deduceFunctionTemplate() %s\n", toChars()); + printf(" targsi:\n"); + if (targsi) + { for (size_t i = 0; i < targsi->dim; i++) + { Object *arg = targsi->tdata()[i]; + printf("\t%s\n", arg->toChars()); + } + } + printf(" fargs:\n"); + for (size_t i = 0; i < fargs->dim; i++) + { Expression *arg = fargs->tdata()[i]; + printf("\t%s %s\n", arg->type->toChars(), arg->toChars()); + //printf("\tty = %d\n", arg->type->ty); + } + printf("stc = %llx\n", scope->stc); +#endif + + for (TemplateDeclaration *td = this; td; td = td->overnext) + { + if (!td->semanticRun) + { + error("forward reference to template %s", td->toChars()); + goto Lerror; + } + if (!td->onemember || !td->onemember->toAlias()->isFuncDeclaration()) + { + error("is not a function template"); + goto Lerror; + } + + Objects dedargs; + FuncDeclaration *fd = NULL; + + MATCH m = td->deduceFunctionTemplateMatch(sc, loc, targsi, ethis, fargs, &dedargs); + //printf("deduceFunctionTemplateMatch = %d\n", m); + if (!m) // if no match + continue; + + if (m < m_best) + goto Ltd_best; + if (m > m_best) + goto Ltd; + + { + // Disambiguate by picking the most specialized TemplateDeclaration + MATCH c1 = td->leastAsSpecialized(td_best, fargs); + MATCH c2 = td_best->leastAsSpecialized(td, fargs); + //printf("1: c1 = %d, c2 = %d\n", c1, c2); + + if (c1 > c2) + goto Ltd; + else if (c1 < c2) + goto Ltd_best; + } + + if (!fd_best) + { + fd_best = td_best->doHeaderInstantiation(sc, tdargs, fargs); + if (!fd_best) + goto Lerror; + } + { + fd = td->doHeaderInstantiation(sc, &dedargs, fargs); + if (!fd) + goto Lerror; + } + assert(fd && fd_best); + + { + // Disambiguate by tf->callMatch + TypeFunction *tf1 = (TypeFunction *)fd->type; + TypeFunction *tf2 = (TypeFunction *)fd_best->type; + MATCH c1 = (MATCH) tf1->callMatch(fd->needThis() && !fd->isCtorDeclaration() ? ethis : NULL, fargs); + MATCH c2 = (MATCH) tf2->callMatch(fd_best->needThis() && !fd->isCtorDeclaration() ? ethis : NULL, fargs); + //printf("2: c1 = %d, c2 = %d\n", c1, c2); + + if (c1 > c2) + goto Ltd; + if (c1 < c2) + goto Ltd_best; + } + + { + // Disambiguate by picking the most specialized FunctionDeclaration + MATCH c1 = fd->leastAsSpecialized(fd_best); + MATCH c2 = fd_best->leastAsSpecialized(fd); + //printf("3: c1 = %d, c2 = %d\n", c1, c2); + + if (c1 > c2) + goto Ltd; + if (c1 < c2) + goto Ltd_best; + } + + Lambig: // td_best and td are ambiguous + td_ambig = td; + continue; + + Ltd_best: // td_best is the best match so far + td_ambig = NULL; + continue; + + Ltd: // td is the new best match + td_ambig = NULL; + assert((size_t)td->scope > 0x10000); + td_best = td; + fd_best = fd; + m_best = m; + tdargs->setDim(dedargs.dim); + memcpy(tdargs->tdata(), dedargs.tdata(), tdargs->dim * sizeof(void *)); + continue; + } + if (!td_best) + { + if (!(flags & 1)) + ::error(loc, "%s %s.%s does not match any function template declaration", + kind(), parent->toPrettyChars(), ident->toChars()); + goto Lerror; + } + if (td_ambig) + { + ::error(loc, "%s %s.%s matches more than one template declaration, %s(%d):%s and %s(%d):%s", + kind(), parent->toPrettyChars(), ident->toChars(), + td_best->loc.filename, td_best->loc.linnum, td_best->toChars(), + td_ambig->loc.filename, td_ambig->loc.linnum, td_ambig->toChars()); + } + + /* The best match is td_best with arguments tdargs. + * Now instantiate the template. + */ + assert((size_t)td_best->scope > 0x10000); + ti = new TemplateInstance(loc, td_best, tdargs); + ti->semantic(sc, fargs); + fd_best = ti->toAlias()->isFuncDeclaration(); + if (!fd_best || !((TypeFunction*)fd_best->type)->callMatch(ethis, fargs, flags)) + goto Lerror; + + /* As Bugzilla 3682 shows, a template instance can be matched while instantiating + * that same template. Thus, the function type can be incomplete. Complete it. + */ + { TypeFunction *tf = (TypeFunction *)fd_best->type; + assert(tf->ty == Tfunction); + if (tf->next) + fd_best->type = tf->semantic(loc, sc); + } + + return fd_best; + + Lerror: +#if DMDV2 + if (!(flags & 1)) +#endif + { + HdrGenState hgs; + + OutBuffer bufa; + Objects *args = targsi; + if (args) + { for (size_t i = 0; i < args->dim; i++) + { + if (i) + bufa.writeByte(','); + Object *oarg = args->tdata()[i]; + ObjectToCBuffer(&bufa, &hgs, oarg); + } + } + + OutBuffer buf; + argExpTypesToCBuffer(&buf, fargs, &hgs); + if (this->overnext) + ::error(loc, "%s %s.%s cannot deduce template function from argument types !(%s)(%s)", + kind(), parent->toPrettyChars(), ident->toChars(), + bufa.toChars(), buf.toChars()); + else + error("cannot deduce template function from argument types !(%s)(%s)", + bufa.toChars(), buf.toChars()); + } + return NULL; +} + +/************************************************* + * Limited function template instantiation for using fd->leastAsSpecialized() + */ +FuncDeclaration *TemplateDeclaration::doHeaderInstantiation(Scope *sc, + Objects *tdargs, Expressions *fargs) +{ + FuncDeclaration *fd = onemember->toAlias()->isFuncDeclaration(); + if (!fd) + return NULL; + +#if 0 + printf("doHeaderInstantiation this = %s\n", toChars()); + for (size_t i = 0; i < tdargs->dim; ++i) + printf("\ttdargs[%d] = %s\n", i, ((Object *)tdargs->data[i])->toChars()); +#endif + + assert((size_t)scope > 0x10000); + TemplateInstance *ti = new TemplateInstance(loc, this, tdargs); + ti->tinst = sc->tinst; + { + ti->tdtypes.setDim(ti->tempdecl->parameters->dim); + if (!ti->tempdecl->matchWithInstance(ti, &ti->tdtypes, fargs, 2)) + return NULL; + } + + ti->parent = parent; + + // function body and contracts are not need + //fd = fd->syntaxCopy(NULL)->isFuncDeclaration(); + fd = new FuncDeclaration(fd->loc, fd->endloc, fd->ident, fd->storage_class, fd->type->syntaxCopy()); + fd->parent = ti; + + Scope *scope = this->scope; + + ti->argsym = new ScopeDsymbol(); + ti->argsym->parent = scope->parent; + scope = scope->push(ti->argsym); + + Scope *paramscope = scope->push(); + paramscope->stc = 0; + ti->declareParameters(paramscope); + paramscope->pop(); + + { + TypeFunction *tf = (TypeFunction *)fd->type; + if (tf && tf->ty == Tfunction) + tf->fargs = fargs; + } + + Scope *sc2; + sc2 = scope->push(ti); + sc2->parent = /*isnested ? sc->parent :*/ ti; + sc2->tinst = ti; + + { + Scope *sc = sc2; + sc = sc->push(); + + if (fd->isCtorDeclaration()) + sc->flags |= SCOPEctor; + fd->type = fd->type->semantic(fd->loc, sc); + sc = sc->pop(); + } + //printf("\t[%s] fd->type = %s, mod = %x, ", loc.toChars(), fd->type->toChars(), fd->type->mod); + //printf("fd->needThis() = %d\n", fd->needThis()); + + sc2->pop(); + scope->pop(); + + return fd; +} + +bool TemplateDeclaration::hasStaticCtorOrDtor() +{ + return FALSE; // don't scan uninstantiated templates +} + +void TemplateDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ +#if 0 // Should handle template functions for doc generation + if (onemember && onemember->isFuncDeclaration()) + buf->writestring("foo "); +#endif + if (hgs->ddoc) + buf->writestring(kind()); + else + buf->writestring("template"); + buf->writeByte(' '); + buf->writestring(ident->toChars()); + buf->writeByte('('); + for (size_t i = 0; i < parameters->dim; i++) + { + TemplateParameter *tp = parameters->tdata()[i]; + if (hgs->ddoc) + tp = origParameters->tdata()[i]; + if (i) + buf->writeByte(','); + tp->toCBuffer(buf, hgs); + } + buf->writeByte(')'); +#if DMDV2 + if (constraint) + { buf->writestring(" if ("); + constraint->toCBuffer(buf, hgs); + buf->writeByte(')'); + } +#endif + + if (hgs->hdrgen) + { + hgs->tpltMember++; + buf->writenl(); + buf->writebyte('{'); + buf->writenl(); + for (size_t i = 0; i < members->dim; i++) + { + Dsymbol *s = members->tdata()[i]; + s->toCBuffer(buf, hgs); + } + buf->writebyte('}'); + buf->writenl(); + hgs->tpltMember--; + } +} + + +char *TemplateDeclaration::toChars() +{ OutBuffer buf; + HdrGenState hgs; + + memset(&hgs, 0, sizeof(hgs)); + buf.writestring(ident->toChars()); + buf.writeByte('('); + for (size_t i = 0; i < parameters->dim; i++) + { + TemplateParameter *tp = parameters->tdata()[i]; + if (i) + buf.writeByte(','); + tp->toCBuffer(&buf, &hgs); + } + buf.writeByte(')'); +#if DMDV2 + if (constraint) + { buf.writestring(" if ("); + constraint->toCBuffer(&buf, &hgs); + buf.writeByte(')'); + } +#endif + buf.writeByte(0); + return (char *)buf.extractData(); +} + +/* ======================== Type ============================================ */ + +/**** + * Given an identifier, figure out which TemplateParameter it is. + * Return -1 if not found. + */ + +int templateIdentifierLookup(Identifier *id, TemplateParameters *parameters) +{ + for (size_t i = 0; i < parameters->dim; i++) + { TemplateParameter *tp = parameters->tdata()[i]; + + if (tp->ident->equals(id)) + return i; + } + return -1; +} + +int templateParameterLookup(Type *tparam, TemplateParameters *parameters) +{ + assert(tparam->ty == Tident); + TypeIdentifier *tident = (TypeIdentifier *)tparam; + //printf("\ttident = '%s'\n", tident->toChars()); + if (tident->idents.dim == 0) + { + return templateIdentifierLookup(tident->ident, parameters); + } + return -1; +} + +/* These form the heart of template argument deduction. + * Given 'this' being the type argument to the template instance, + * it is matched against the template declaration parameter specialization + * 'tparam' to determine the type to be used for the parameter. + * Example: + * template Foo(T:T*) // template declaration + * Foo!(int*) // template instantiation + * Input: + * this = int* + * tparam = T* + * parameters = [ T:T* ] // Array of TemplateParameter's + * Output: + * dedtypes = [ int ] // Array of Expression/Type's + */ + +MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, + Objects *dedtypes, unsigned *wildmatch) +{ +#if 0 + printf("Type::deduceType()\n"); + printf("\tthis = %d, ", ty); print(); + printf("\ttparam = %d, ", tparam->ty); tparam->print(); +#endif + if (!tparam) + goto Lnomatch; + + if (this == tparam) + goto Lexact; + + if (tparam->ty == Tident) + { + // Determine which parameter tparam is + int i = templateParameterLookup(tparam, parameters); + if (i == -1) + { + if (!sc) + goto Lnomatch; + + /* Need a loc to go with the semantic routine. + */ + Loc loc; + if (parameters->dim) + { + TemplateParameter *tp = parameters->tdata()[0]; + loc = tp->loc; + } + + /* BUG: what if tparam is a template instance, that + * has as an argument another Tident? + */ + tparam = tparam->semantic(loc, sc); + assert(tparam->ty != Tident); + return deduceType(sc, tparam, parameters, dedtypes, wildmatch); + } + + TemplateParameter *tp = parameters->tdata()[i]; + + // Found the corresponding parameter tp + if (!tp->isTemplateTypeParameter()) + goto Lnomatch; + Type *tt = this; + Type *at = (Type *)dedtypes->tdata()[i]; + + // 7*7 == 49 cases + + #define X(U,T) ((U) << 4) | (T) + + if (wildmatch && (tparam->mod & MODwild)) + { + switch (X(tparam->mod, mod)) + { + case X(MODwild, 0): + case X(MODwild, MODshared): + case X(MODwild, MODconst): + case X(MODwild, MODconst | MODshared): + case X(MODwild, MODimmutable): + case X(MODwild, MODwild): + case X(MODwild, MODwild | MODshared): + case X(MODwild | MODshared, MODshared): + case X(MODwild | MODshared, MODconst | MODshared): + case X(MODwild | MODshared, MODimmutable): + case X(MODwild | MODshared, MODwild | MODshared): + + if (!at) + { + if (mod & MODwild) + *wildmatch |= MODwild; + else if (mod == 0) + *wildmatch |= MODmutable; + else + *wildmatch |= (mod & ~MODshared); + tt = mutableOf()->substWildTo(MODmutable); + dedtypes->tdata()[i] = tt; + goto Lconst; + } + + //printf("\t> tt = %s, at = %s\n", tt->toChars(), at->toChars()); + //printf("\t> tt->implicitConvTo(at->constOf()) = %d\n", tt->implicitConvTo(at->constOf())); + //printf("\t> at->implicitConvTo(tt->constOf()) = %d\n", at->implicitConvTo(tt->constOf())); + + if (tt->equals(at)) + { + goto Lconst; + } + else if (tt->implicitConvTo(at->constOf())) + { + dedtypes->tdata()[i] = at->constOf()->mutableOf(); + *wildmatch |= MODconst; + goto Lconst; + } + else if (at->implicitConvTo(tt->constOf())) + { + dedtypes->tdata()[i] = tt->constOf()->mutableOf(); + *wildmatch |= MODconst; + goto Lconst; + } + goto Lnomatch; + + default: + break; + } + } + + switch (X(tparam->mod, mod)) + { + case X(0, 0): + case X(0, MODconst): + case X(0, MODimmutable): + case X(0, MODshared): + case X(0, MODconst | MODshared): + case X(0, MODwild): + case X(0, MODwild | MODshared): + // foo(U:U) T => T + // foo(U:U) const(T) => const(T) + // foo(U:U) immutable(T) => immutable(T) + // foo(U:U) shared(T) => shared(T) + // foo(U:U) const(shared(T)) => const(shared(T)) + // foo(U:U) wild(T) => wild(T) + // foo(U:U) wild(shared(T)) => wild(shared(T)) + if (!at) + { dedtypes->tdata()[i] = tt; + goto Lexact; + } + break; + + case X(MODconst, MODconst): + case X(MODimmutable, MODimmutable): + case X(MODshared, MODshared): + case X(MODconst | MODshared, MODconst | MODshared): + case X(MODwild, MODwild): + case X(MODwild | MODshared, MODwild | MODshared): + // foo(U:const(U)) const(T) => T + // foo(U:immutable(U)) immutable(T) => T + // foo(U:shared(U)) shared(T) => T + // foo(U:const(shared(U)) const(shared(T)) => T + // foo(U:wild(U)) wild(T) => T + // foo(U:wild(shared(U)) wild(shared(T)) => T + tt = mutableOf()->unSharedOf(); + if (!at) + { dedtypes->tdata()[i] = tt; + goto Lexact; + } + break; + + case X(MODconst, 0): + case X(MODconst, MODimmutable): + case X(MODconst, MODconst | MODshared): + case X(MODconst | MODshared, MODimmutable): + case X(MODconst, MODwild): + case X(MODconst, MODwild | MODshared): + // foo(U:const(U)) T => T + // foo(U:const(U)) immutable(T) => T + // foo(U:const(U)) const(shared(T)) => shared(T) + // foo(U:const(shared(U)) immutable(T) => T + // foo(U:const(U)) wild(shared(T)) => shared(T) + tt = mutableOf(); + if (!at) + { dedtypes->tdata()[i] = tt; + goto Lconst; + } + break; + + case X(MODshared, MODconst | MODshared): + case X(MODconst | MODshared, MODshared): + case X(MODshared, MODwild | MODshared): + // foo(U:shared(U)) const(shared(T)) => const(T) + // foo(U:const(shared(U)) shared(T) => T + // foo(U:shared(U)) wild(shared(T)) => wild(T) + tt = unSharedOf(); + if (!at) + { dedtypes->tdata()[i] = tt; + goto Lconst; + } + break; + + case X(MODconst, MODshared): + // foo(U:const(U)) shared(T) => shared(T) + if (!at) + { (*dedtypes)[i] = tt; + goto Lconst; + } + break; + + case X(MODimmutable, 0): + case X(MODimmutable, MODconst): + case X(MODimmutable, MODshared): + case X(MODimmutable, MODconst | MODshared): + case X(MODshared, 0): + case X(MODshared, MODconst): + case X(MODshared, MODimmutable): + case X(MODconst | MODshared, 0): + case X(MODconst | MODshared, MODconst): + case X(MODimmutable, MODwild): + case X(MODshared, MODwild): + case X(MODconst | MODshared, MODwild): + case X(MODwild, 0): + case X(MODwild, MODconst): + case X(MODwild, MODimmutable): + case X(MODwild, MODshared): + case X(MODwild, MODconst | MODshared): + case X(MODwild | MODshared, 0): + case X(MODwild | MODshared, MODconst): + case X(MODwild | MODshared, MODimmutable): + case X(MODwild | MODshared, MODshared): + case X(MODwild | MODshared, MODconst | MODshared): + case X(MODwild | MODshared, MODwild): + case X(MODimmutable, MODwild | MODshared): + case X(MODconst | MODshared, MODwild | MODshared): + case X(MODwild, MODwild | MODshared): + + // foo(U:immutable(U)) T => nomatch + // foo(U:immutable(U)) const(T) => nomatch + // foo(U:immutable(U)) shared(T) => nomatch + // foo(U:immutable(U)) const(shared(T)) => nomatch + // foo(U:const(U)) shared(T) => nomatch + // foo(U:shared(U)) T => nomatch + // foo(U:shared(U)) const(T) => nomatch + // foo(U:shared(U)) immutable(T) => nomatch + // foo(U:const(shared(U)) T => nomatch + // foo(U:const(shared(U)) const(T) => nomatch + // foo(U:immutable(U)) wild(T) => nomatch + // foo(U:shared(U)) wild(T) => nomatch + // foo(U:const(shared(U)) wild(T) => nomatch + // foo(U:wild(U)) T => nomatch + // foo(U:wild(U)) const(T) => nomatch + // foo(U:wild(U)) immutable(T) => nomatch + // foo(U:wild(U)) shared(T) => nomatch + // foo(U:wild(U)) const(shared(T)) => nomatch + // foo(U:wild(shared(U)) T => nomatch + // foo(U:wild(shared(U)) const(T) => nomatch + // foo(U:wild(shared(U)) immutable(T) => nomatch + // foo(U:wild(shared(U)) shared(T) => nomatch + // foo(U:wild(shared(U)) const(shared(T)) => nomatch + // foo(U:wild(shared(U)) wild(T) => nomatch + // foo(U:immutable(U)) wild(shared(T)) => nomatch + // foo(U:const(shared(U))) wild(shared(T)) => nomatch + // foo(U:wild(U)) wild(shared(T)) => nomatch + //if (!at) + goto Lnomatch; + break; + + default: + assert(0); + } + #undef X + + if (tt->equals(at)) + goto Lexact; + else if (tt->ty == Tclass && at->ty == Tclass) + { + return tt->implicitConvTo(at); + } + else if (tt->ty == Tsarray && at->ty == Tarray && + tt->nextOf()->implicitConvTo(at->nextOf()) >= MATCHconst) + { + goto Lexact; + } + else + goto Lnomatch; + } + else if (tparam->ty == Ttypeof) + { + /* Need a loc to go with the semantic routine. + */ + Loc loc; + if (parameters->dim) + { + TemplateParameter *tp = parameters->tdata()[0]; + loc = tp->loc; + } + + tparam = tparam->semantic(loc, sc); + } + + if (ty != tparam->ty) + { +#if DMDV2 + // Can't instantiate AssociativeArray!() without a scope + if (tparam->ty == Taarray && !((TypeAArray*)tparam)->sc) + ((TypeAArray*)tparam)->sc = sc; + + MATCH m = implicitConvTo(tparam); + if (m == MATCHnomatch) + { + Type *at = aliasthisOf(); + if (at) + m = at->deduceType(sc, tparam, parameters, dedtypes, wildmatch); + } + return m; +#else + return implicitConvTo(tparam); +#endif + } + + if (nextOf()) + return nextOf()->deduceType(sc, tparam->nextOf(), parameters, dedtypes, wildmatch); + +Lexact: + return MATCHexact; + +Lnomatch: + return MATCHnomatch; + +#if DMDV2 +Lconst: + return MATCHconst; +#endif +} + +#if DMDV2 +MATCH TypeVector::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, + Objects *dedtypes, unsigned *wildmatch) +{ +#if 0 + printf("TypeVector::deduceType()\n"); + printf("\tthis = %d, ", ty); print(); + printf("\ttparam = %d, ", tparam->ty); tparam->print(); +#endif + if (tparam->ty == Tvector) + { TypeVector *tp = (TypeVector *)tparam; + return basetype->deduceType(sc, tp->basetype, parameters, dedtypes, wildmatch); + } + return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); +} +#endif + +#if DMDV2 +MATCH TypeDArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, + Objects *dedtypes, unsigned *wildmatch) +{ +#if 0 + printf("TypeDArray::deduceType()\n"); + printf("\tthis = %d, ", ty); print(); + printf("\ttparam = %d, ", tparam->ty); tparam->print(); +#endif + return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); +} +#endif + +MATCH TypeSArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, + Objects *dedtypes, unsigned *wildmatch) +{ +#if 0 + printf("TypeSArray::deduceType()\n"); + printf("\tthis = %d, ", ty); print(); + printf("\ttparam = %d, ", tparam->ty); tparam->print(); +#endif + + // Extra check that array dimensions must match + if (tparam) + { + if (tparam->ty == Tarray) + { MATCH m; + + m = next->deduceType(sc, tparam->nextOf(), parameters, dedtypes, wildmatch); + if (m == MATCHexact) + m = MATCHconvert; + return m; + } + + Identifier *id = NULL; + if (tparam->ty == Tsarray) + { + TypeSArray *tp = (TypeSArray *)tparam; + if (tp->dim->op == TOKvar && + ((VarExp *)tp->dim)->var->storage_class & STCtemplateparameter) + { + id = ((VarExp *)tp->dim)->var->ident; + } + else if (dim->toInteger() != tp->dim->toInteger()) + return MATCHnomatch; + } + else if (tparam->ty == Taarray) + { + TypeAArray *tp = (TypeAArray *)tparam; + if (tp->index->ty == Tident && + ((TypeIdentifier *)tp->index)->idents.dim == 0) + { + id = ((TypeIdentifier *)tp->index)->ident; + } + } + if (id) + { + // This code matches code in TypeInstance::deduceType() + int i = templateIdentifierLookup(id, parameters); + if (i == -1) + goto Lnomatch; + TemplateParameter *tprm = parameters->tdata()[i]; + TemplateValueParameter *tvp = tprm->isTemplateValueParameter(); + if (!tvp) + goto Lnomatch; + Expression *e = (Expression *)dedtypes->tdata()[i]; + if (e) + { + if (!dim->equals(e)) + goto Lnomatch; + } + else + { + Type *vt = tvp->valType->semantic(0, sc); + MATCH m = (MATCH)dim->implicitConvTo(vt); + if (!m) + goto Lnomatch; + dedtypes->tdata()[i] = dim; + } + return next->deduceType(sc, tparam->nextOf(), parameters, dedtypes, wildmatch); + } + } + return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); + + Lnomatch: + return MATCHnomatch; +} + +MATCH TypeAArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch) +{ +#if 0 + printf("TypeAArray::deduceType()\n"); + printf("\tthis = %d, ", ty); print(); + printf("\ttparam = %d, ", tparam->ty); tparam->print(); +#endif + + // Extra check that index type must match + if (tparam && tparam->ty == Taarray) + { + TypeAArray *tp = (TypeAArray *)tparam; + if (!index->deduceType(sc, tp->index, parameters, dedtypes, wildmatch)) + { + return MATCHnomatch; + } + } + return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); +} + +MATCH TypeFunction::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch) +{ + //printf("TypeFunction::deduceType()\n"); + //printf("\tthis = %d, ", ty); print(); + //printf("\ttparam = %d, ", tparam->ty); tparam->print(); + + // Extra check that function characteristics must match + if (tparam && tparam->ty == Tfunction) + { + TypeFunction *tp = (TypeFunction *)tparam; + if (varargs != tp->varargs || + linkage != tp->linkage) + return MATCHnomatch; + + size_t nfargs = Parameter::dim(this->parameters); + size_t nfparams = Parameter::dim(tp->parameters); + + // bug 2579 fix: Apply function parameter storage classes to parameter types + for (size_t i = 0; i < nfparams; i++) + { + Parameter *fparam = Parameter::getNth(tp->parameters, i); + fparam->type = fparam->type->addStorageClass(fparam->storageClass); + fparam->storageClass &= ~(STC_TYPECTOR | STCin); + } + //printf("\t-> this = %d, ", ty); print(); + //printf("\t-> tparam = %d, ", tparam->ty); tparam->print(); + + /* See if tuple match + */ + if (nfparams > 0 && nfargs >= nfparams - 1) + { + /* See if 'A' of the template parameter matches 'A' + * of the type of the last function parameter. + */ + Parameter *fparam = Parameter::getNth(tp->parameters, nfparams - 1); + assert(fparam); + assert(fparam->type); + if (fparam->type->ty != Tident) + goto L1; + TypeIdentifier *tid = (TypeIdentifier *)fparam->type; + if (tid->idents.dim) + goto L1; + + /* Look through parameters to find tuple matching tid->ident + */ + size_t tupi = 0; + for (; 1; tupi++) + { if (tupi == parameters->dim) + goto L1; + TemplateParameter *t = parameters->tdata()[tupi]; + TemplateTupleParameter *tup = t->isTemplateTupleParameter(); + if (tup && tup->ident->equals(tid->ident)) + break; + } + + /* The types of the function arguments [nfparams - 1 .. nfargs] + * now form the tuple argument. + */ + size_t tuple_dim = nfargs - (nfparams - 1); + + /* See if existing tuple, and whether it matches or not + */ + Object *o = dedtypes->tdata()[tupi]; + if (o) + { // Existing deduced argument must be a tuple, and must match + Tuple *t = isTuple(o); + if (!t || t->objects.dim != tuple_dim) + return MATCHnomatch; + for (size_t i = 0; i < tuple_dim; i++) + { Parameter *arg = Parameter::getNth(this->parameters, nfparams - 1 + i); + if (!arg->type->equals(t->objects.tdata()[i])) + return MATCHnomatch; + } + } + else + { // Create new tuple + Tuple *t = new Tuple(); + t->objects.setDim(tuple_dim); + for (size_t i = 0; i < tuple_dim; i++) + { Parameter *arg = Parameter::getNth(this->parameters, nfparams - 1 + i); + t->objects.tdata()[i] = arg->type; + } + dedtypes->tdata()[tupi] = t; + } + nfparams--; // don't consider the last parameter for type deduction + goto L2; + } + + L1: + if (nfargs != nfparams) + return MATCHnomatch; + L2: + for (size_t i = 0; i < nfparams; i++) + { + Parameter *a = Parameter::getNth(this->parameters, i); + Parameter *ap = Parameter::getNth(tp->parameters, i); + if (a->storageClass != ap->storageClass || + !a->type->deduceType(sc, ap->type, parameters, dedtypes, wildmatch)) + return MATCHnomatch; + } + } + return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); +} + +MATCH TypeIdentifier::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch) +{ + // Extra check + if (tparam && tparam->ty == Tident) + { + TypeIdentifier *tp = (TypeIdentifier *)tparam; + + for (size_t i = 0; i < idents.dim; i++) + { + Identifier *id1 = idents.tdata()[i]; + Identifier *id2 = tp->idents.tdata()[i]; + + if (!id1->equals(id2)) + return MATCHnomatch; + } + } + return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); +} + +MATCH TypeInstance::deduceType(Scope *sc, + Type *tparam, TemplateParameters *parameters, + Objects *dedtypes, unsigned *wildmatch) +{ +#if 0 + printf("TypeInstance::deduceType()\n"); + printf("\tthis = %d, ", ty); print(); + printf("\ttparam = %d, ", tparam->ty); tparam->print(); +#endif + + // Extra check + if (tparam && tparam->ty == Tinstance) + { + TypeInstance *tp = (TypeInstance *)tparam; + + //printf("tempinst->tempdecl = %p\n", tempinst->tempdecl); + //printf("tp->tempinst->tempdecl = %p\n", tp->tempinst->tempdecl); + if (!tp->tempinst->tempdecl) + { //printf("tp->tempinst->name = '%s'\n", tp->tempinst->name->toChars()); + if (!tp->tempinst->name->equals(tempinst->name)) + { + /* Handle case of: + * template Foo(T : sa!(T), alias sa) + */ + int i = templateIdentifierLookup(tp->tempinst->name, parameters); + if (i == -1) + { /* Didn't find it as a parameter identifier. Try looking + * it up and seeing if is an alias. See Bugzilla 1454 + */ + Dsymbol *s = tempinst->tempdecl->scope->search(0, tp->tempinst->name, NULL); + if (s) + { + s = s->toAlias(); + TemplateDeclaration *td = s->isTemplateDeclaration(); + if (td && td == tempinst->tempdecl) + goto L2; + } + goto Lnomatch; + } + TemplateParameter *tpx = parameters->tdata()[i]; + // This logic duplicates tpx->matchArg() + TemplateAliasParameter *ta = tpx->isTemplateAliasParameter(); + if (!ta) + goto Lnomatch; + Object *sa = tempinst->tempdecl; + if (!sa) + goto Lnomatch; + if (ta->specAlias && sa != ta->specAlias) + goto Lnomatch; + if (dedtypes->tdata()[i]) + { // Must match already deduced symbol + Object *s = dedtypes->tdata()[i]; + + if (s != sa) + goto Lnomatch; + } + dedtypes->tdata()[i] = sa; + } + } + else if (tempinst->tempdecl != tp->tempinst->tempdecl) + goto Lnomatch; + + L2: + + for (size_t i = 0; 1; i++) + { + //printf("\ttest: tempinst->tiargs[%d]\n", i); + Object *o1; + if (i < tempinst->tiargs->dim) + o1 = tempinst->tiargs->tdata()[i]; + else if (i < tempinst->tdtypes.dim && i < tp->tempinst->tiargs->dim) + // Pick up default arg + o1 = tempinst->tdtypes.tdata()[i]; + else + break; + + if (i >= tp->tempinst->tiargs->dim) + goto Lnomatch; + + Object *o2 = tp->tempinst->tiargs->tdata()[i]; + + Type *t1 = isType(o1); + Type *t2 = isType(o2); + + Expression *e1 = isExpression(o1); + Expression *e2 = isExpression(o2); + + Dsymbol *s1 = isDsymbol(o1); + Dsymbol *s2 = isDsymbol(o2); + + Tuple *v1 = isTuple(o1); + Tuple *v2 = isTuple(o2); +#if 0 + if (t1) printf("t1 = %s\n", t1->toChars()); + if (t2) printf("t2 = %s\n", t2->toChars()); + if (e1) printf("e1 = %s\n", e1->toChars()); + if (e2) printf("e2 = %s\n", e2->toChars()); + if (s1) printf("s1 = %s\n", s1->toChars()); + if (s2) printf("s2 = %s\n", s2->toChars()); + if (v1) printf("v1 = %s\n", v1->toChars()); + if (v2) printf("v2 = %s\n", v2->toChars()); +#endif + + TemplateTupleParameter *ttp; + int j; + if (t2 && + t2->ty == Tident && + i == tp->tempinst->tiargs->dim - 1 && + i == tempinst->tempdecl->parameters->dim - 1 && + (ttp = tempinst->tempdecl->isVariadic()) != NULL) + { + /* Given: + * struct A(B...) {} + * alias A!(int, float) X; + * static if (!is(X Y == A!(Z), Z)) + * deduce that Z is a tuple(int, float) + */ + + j = templateParameterLookup(t2, parameters); + if (j == -1) + goto Lnomatch; + + /* Create tuple from remaining args + */ + Tuple *vt = new Tuple(); + size_t vtdim = tempinst->tiargs->dim - i; + vt->objects.setDim(vtdim); + for (size_t k = 0; k < vtdim; k++) + vt->objects.tdata()[k] = tempinst->tiargs->tdata()[i + k]; + + Tuple *v = (Tuple *)dedtypes->tdata()[j]; + if (v) + { + if (!match(v, vt, tempinst->tempdecl, sc)) + goto Lnomatch; + } + else + dedtypes->tdata()[j] = vt; + break; //return MATCHexact; + } + + if (t1 && t2) + { + if (!t1->deduceType(sc, t2, parameters, dedtypes, wildmatch)) + goto Lnomatch; + } + else if (e1 && e2) + { + if (!e1->equals(e2)) + { if (e2->op == TOKvar) + { + /* + * (T:Number!(e2), int e2) + */ + j = templateIdentifierLookup(((VarExp *)e2)->var->ident, parameters); + goto L1; + } + goto Lnomatch; + } + } + else if (e1 && t2 && t2->ty == Tident) + { + j = templateParameterLookup(t2, parameters); + L1: + if (j == -1) + goto Lnomatch; + TemplateParameter *tp = parameters->tdata()[j]; + // BUG: use tp->matchArg() instead of the following + TemplateValueParameter *tv = tp->isTemplateValueParameter(); + if (!tv) + goto Lnomatch; + Expression *e = (Expression *)dedtypes->tdata()[j]; + if (e) + { + if (!e1->equals(e)) + goto Lnomatch; + } + else + { Type *vt = tv->valType->semantic(0, sc); + MATCH m = (MATCH)e1->implicitConvTo(vt); + if (!m) + goto Lnomatch; + dedtypes->tdata()[j] = e1; + } + } + else if (s1 && t2 && t2->ty == Tident) + { + j = templateParameterLookup(t2, parameters); + if (j == -1) + goto Lnomatch; + TemplateParameter *tp = parameters->tdata()[j]; + // BUG: use tp->matchArg() instead of the following + TemplateAliasParameter *ta = tp->isTemplateAliasParameter(); + if (!ta) + goto Lnomatch; + Dsymbol *s = (Dsymbol *)dedtypes->tdata()[j]; + if (s) + { + if (!s1->equals(s)) + goto Lnomatch; + } + else + { + dedtypes->tdata()[j] = s1; + } + } + else if (s1 && s2) + { + if (!s1->equals(s2)) + goto Lnomatch; + } + // BUG: Need to handle tuple parameters + else + goto Lnomatch; + } + } + return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); + +Lnomatch: + //printf("no match\n"); + return MATCHnomatch; +} + +MATCH TypeStruct::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch) +{ + //printf("TypeStruct::deduceType()\n"); + //printf("\tthis->parent = %s, ", sym->parent->toChars()); print(); + //printf("\ttparam = %d, ", tparam->ty); tparam->print(); + + /* If this struct is a template struct, and we're matching + * it against a template instance, convert the struct type + * to a template instance, too, and try again. + */ + TemplateInstance *ti = sym->parent->isTemplateInstance(); + + if (tparam && tparam->ty == Tinstance) + { + if (ti && ti->toAlias() == sym) + { + TypeInstance *t = new TypeInstance(0, ti); + return t->deduceType(sc, tparam, parameters, dedtypes, wildmatch); + } + + /* Match things like: + * S!(T).foo + */ + TypeInstance *tpi = (TypeInstance *)tparam; + if (tpi->idents.dim) + { Identifier *id = tpi->idents.tdata()[tpi->idents.dim - 1]; + if (id->dyncast() == DYNCAST_IDENTIFIER && sym->ident->equals(id)) + { + Type *tparent = sym->parent->getType(); + if (tparent) + { + /* Slice off the .foo in S!(T).foo + */ + tpi->idents.dim--; + MATCH m = tparent->deduceType(sc, tpi, parameters, dedtypes, wildmatch); + tpi->idents.dim++; + return m; + } + } + } + } + + // Extra check + if (tparam && tparam->ty == Tstruct) + { + TypeStruct *tp = (TypeStruct *)tparam; + + //printf("\t%d\n", (MATCH) implicitConvTo(tp)); + return implicitConvTo(tp); + } + return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); +} + +MATCH TypeEnum::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch) +{ + // Extra check + if (tparam && tparam->ty == Tenum) + { + TypeEnum *tp = (TypeEnum *)tparam; + + if (sym != tp->sym) + return MATCHnomatch; + } + return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); +} + +MATCH TypeTypedef::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch) +{ + // Extra check + if (tparam && tparam->ty == Ttypedef) + { + TypeTypedef *tp = (TypeTypedef *)tparam; + + if (sym != tp->sym) + return MATCHnomatch; + } + return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); +} + +/* Helper for TypeClass::deduceType(). + * Classes can match with implicit conversion to a base class or interface. + * This is complicated, because there may be more than one base class which + * matches. In such cases, one or more parameters remain ambiguous. + * For example, + * + * interface I(X, Y) {} + * class C : I(uint, double), I(char, double) {} + * C x; + * foo(T, U)( I!(T, U) x) + * + * deduces that U is double, but T remains ambiguous (could be char or uint). + * + * Given a baseclass b, and initial deduced types 'dedtypes', this function + * tries to match tparam with b, and also tries all base interfaces of b. + * If a match occurs, numBaseClassMatches is incremented, and the new deduced + * types are ANDed with the current 'best' estimate for dedtypes. + */ +void deduceBaseClassParameters(BaseClass *b, + Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, + Objects *best, int &numBaseClassMatches) +{ + TemplateInstance *parti = b->base ? b->base->parent->isTemplateInstance() : NULL; + if (parti) + { + // Make a temporary copy of dedtypes so we don't destroy it + Objects *tmpdedtypes = new Objects(); + tmpdedtypes->setDim(dedtypes->dim); + memcpy(tmpdedtypes->tdata(), dedtypes->tdata(), dedtypes->dim * sizeof(void *)); + + TypeInstance *t = new TypeInstance(0, parti); + MATCH m = t->deduceType(sc, tparam, parameters, tmpdedtypes); + if (m != MATCHnomatch) + { + // If this is the first ever match, it becomes our best estimate + if (numBaseClassMatches==0) + memcpy(best->tdata(), tmpdedtypes->tdata(), tmpdedtypes->dim * sizeof(void *)); + else for (size_t k = 0; k < tmpdedtypes->dim; ++k) + { + // If we've found more than one possible type for a parameter, + // mark it as unknown. + if (tmpdedtypes->tdata()[k] != best->tdata()[k]) + best->tdata()[k] = dedtypes->tdata()[k]; + } + ++numBaseClassMatches; + } + } + // Now recursively test the inherited interfaces + for (size_t j = 0; j < b->baseInterfaces_dim; ++j) + { + deduceBaseClassParameters( &(b->baseInterfaces)[j], + sc, tparam, parameters, dedtypes, + best, numBaseClassMatches); + } + +} + +MATCH TypeClass::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch) +{ + //printf("TypeClass::deduceType(this = %s)\n", toChars()); + + /* If this class is a template class, and we're matching + * it against a template instance, convert the class type + * to a template instance, too, and try again. + */ + TemplateInstance *ti = sym->parent->isTemplateInstance(); + + if (tparam && tparam->ty == Tinstance) + { + if (ti && ti->toAlias() == sym) + { + TypeInstance *t = new TypeInstance(0, ti); + MATCH m = t->deduceType(sc, tparam, parameters, dedtypes, wildmatch); + // Even if the match fails, there is still a chance it could match + // a base class. + if (m != MATCHnomatch) + return m; + } + + /* Match things like: + * S!(T).foo + */ + TypeInstance *tpi = (TypeInstance *)tparam; + if (tpi->idents.dim) + { Identifier *id = tpi->idents.tdata()[tpi->idents.dim - 1]; + if (id->dyncast() == DYNCAST_IDENTIFIER && sym->ident->equals(id)) + { + Type *tparent = sym->parent->getType(); + if (tparent) + { + /* Slice off the .foo in S!(T).foo + */ + tpi->idents.dim--; + MATCH m = tparent->deduceType(sc, tpi, parameters, dedtypes, wildmatch); + tpi->idents.dim++; + return m; + } + } + } + + // If it matches exactly or via implicit conversion, we're done + MATCH m = Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); + if (m != MATCHnomatch) + return m; + + /* There is still a chance to match via implicit conversion to + * a base class or interface. Because there could be more than one such + * match, we need to check them all. + */ + + int numBaseClassMatches = 0; // Have we found an interface match? + + // Our best guess at dedtypes + Objects *best = new Objects(); + best->setDim(dedtypes->dim); + + ClassDeclaration *s = sym; + while(s && s->baseclasses->dim > 0) + { + // Test the base class + deduceBaseClassParameters((s->baseclasses->tdata()[0]), + sc, tparam, parameters, dedtypes, + best, numBaseClassMatches); + + // Test the interfaces inherited by the base class + for (size_t i = 0; i < s->interfaces_dim; ++i) + { + BaseClass *b = s->interfaces[i]; + deduceBaseClassParameters(b, sc, tparam, parameters, dedtypes, + best, numBaseClassMatches); + } + s = ((s->baseclasses->tdata()[0]))->base; + } + + if (numBaseClassMatches == 0) + return MATCHnomatch; + + // If we got at least one match, copy the known types into dedtypes + memcpy(dedtypes->tdata(), best->tdata(), best->dim * sizeof(void *)); + return MATCHconvert; + } + + // Extra check + if (tparam && tparam->ty == Tclass) + { + TypeClass *tp = (TypeClass *)tparam; + + //printf("\t%d\n", (MATCH) implicitConvTo(tp)); + return implicitConvTo(tp); + } + return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); +} + +/* ======================== TemplateParameter =============================== */ + +TemplateParameter::TemplateParameter(Loc loc, Identifier *ident) +{ + this->loc = loc; + this->ident = ident; + this->sparam = NULL; +} + +TemplateTypeParameter *TemplateParameter::isTemplateTypeParameter() +{ + return NULL; +} + +TemplateValueParameter *TemplateParameter::isTemplateValueParameter() +{ + return NULL; +} + +TemplateAliasParameter *TemplateParameter::isTemplateAliasParameter() +{ + return NULL; +} + +TemplateTupleParameter *TemplateParameter::isTemplateTupleParameter() +{ + return NULL; +} + +#if DMDV2 +TemplateThisParameter *TemplateParameter::isTemplateThisParameter() +{ + return NULL; +} +#endif + +/* ======================== TemplateTypeParameter =========================== */ + +// type-parameter + +Type *TemplateTypeParameter::tdummy = NULL; + +TemplateTypeParameter::TemplateTypeParameter(Loc loc, Identifier *ident, Type *specType, + Type *defaultType) + : TemplateParameter(loc, ident) +{ + this->ident = ident; + this->specType = specType; + this->defaultType = defaultType; +} + +TemplateTypeParameter *TemplateTypeParameter::isTemplateTypeParameter() +{ + return this; +} + +TemplateParameter *TemplateTypeParameter::syntaxCopy() +{ + TemplateTypeParameter *tp = new TemplateTypeParameter(loc, ident, specType, defaultType); + if (tp->specType) + tp->specType = specType->syntaxCopy(); + if (defaultType) + tp->defaultType = defaultType->syntaxCopy(); + return tp; +} + +void TemplateTypeParameter::declareParameter(Scope *sc) +{ + //printf("TemplateTypeParameter::declareParameter('%s')\n", ident->toChars()); + TypeIdentifier *ti = new TypeIdentifier(loc, ident); + sparam = new AliasDeclaration(loc, ident, ti); + if (!sc->insert(sparam)) + error(loc, "parameter '%s' multiply defined", ident->toChars()); +} + +void TemplateTypeParameter::semantic(Scope *sc) +{ + //printf("TemplateTypeParameter::semantic('%s')\n", ident->toChars()); + if (specType) + { + specType = specType->semantic(loc, sc); + } +#if 0 // Don't do semantic() until instantiation + if (defaultType) + { + defaultType = defaultType->semantic(loc, sc); + } +#endif +} + +/**************************************** + * Determine if two TemplateParameters are the same + * as far as TemplateDeclaration overloading goes. + * Returns: + * 1 match + * 0 no match + */ + +int TemplateTypeParameter::overloadMatch(TemplateParameter *tp) +{ + TemplateTypeParameter *ttp = tp->isTemplateTypeParameter(); + + if (ttp) + { + if (specType != ttp->specType) + goto Lnomatch; + + if (specType && !specType->equals(ttp->specType)) + goto Lnomatch; + + return 1; // match + } + +Lnomatch: + return 0; +} + +/******************************************* + * Match to a particular TemplateParameter. + * Input: + * i i'th argument + * tiargs[] actual arguments to template instance + * parameters[] template parameters + * dedtypes[] deduced arguments to template instance + * *psparam set to symbol declared and initialized to dedtypes[i] + */ + +MATCH TemplateTypeParameter::matchArg(Scope *sc, Objects *tiargs, + size_t i, TemplateParameters *parameters, Objects *dedtypes, + Declaration **psparam) +{ + //printf("TemplateTypeParameter::matchArg()\n"); + Object *oarg; + MATCH m = MATCHexact; + Type *ta; + + if (i < tiargs->dim) + oarg = tiargs->tdata()[i]; + else + { // Get default argument instead + oarg = defaultArg(loc, sc); + if (!oarg) + { assert(i < dedtypes->dim); + // It might have already been deduced + oarg = dedtypes->tdata()[i]; + if (!oarg) + { + goto Lnomatch; + } + } + } + + ta = isType(oarg); + if (!ta) + { + //printf("%s %p %p %p\n", oarg->toChars(), isExpression(oarg), isDsymbol(oarg), isTuple(oarg)); + goto Lnomatch; + } + //printf("ta is %s\n", ta->toChars()); + + if (specType) + { + if (!ta || ta == tdummy) + goto Lnomatch; + + //printf("\tcalling deduceType(): ta is %s, specType is %s\n", ta->toChars(), specType->toChars()); + MATCH m2 = ta->deduceType(sc, specType, parameters, dedtypes); + if (m2 == MATCHnomatch) + { //printf("\tfailed deduceType\n"); + goto Lnomatch; + } + + if (m2 < m) + m = m2; + if (dedtypes->tdata()[i]) + ta = (Type *)dedtypes->tdata()[i]; + } + else + { + if (dedtypes->tdata()[i]) + { // Must match already deduced type + Type *t = (Type *)dedtypes->tdata()[i]; + + if (!t->equals(ta)) + { //printf("t = %s ta = %s\n", t->toChars(), ta->toChars()); + goto Lnomatch; + } + } + else + { + // So that matches with specializations are better + m = MATCHconvert; + } + } + dedtypes->tdata()[i] = ta; + + *psparam = new AliasDeclaration(loc, ident, ta); + //printf("\tm = %d\n", m); + return m; + +Lnomatch: + *psparam = NULL; + //printf("\tm = %d\n", MATCHnomatch); + return MATCHnomatch; +} + + +void TemplateTypeParameter::print(Object *oarg, Object *oded) +{ + printf(" %s\n", ident->toChars()); + + Type *t = isType(oarg); + Type *ta = isType(oded); + + assert(ta); + + if (specType) + printf("\tSpecialization: %s\n", specType->toChars()); + if (defaultType) + printf("\tDefault: %s\n", defaultType->toChars()); + printf("\tParameter: %s\n", t ? t->toChars() : "NULL"); + printf("\tDeduced Type: %s\n", ta->toChars()); +} + + +void TemplateTypeParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(ident->toChars()); + if (specType) + { + buf->writestring(" : "); + specType->toCBuffer(buf, NULL, hgs); + } + if (defaultType) + { + buf->writestring(" = "); + defaultType->toCBuffer(buf, NULL, hgs); + } +} + + +void *TemplateTypeParameter::dummyArg() +{ Type *t; + + if (specType) + t = specType; + else + { // Use this for alias-parameter's too (?) + if (!tdummy) + tdummy = new TypeIdentifier(loc, ident); + t = tdummy; + } + return (void *)t; +} + + +Object *TemplateTypeParameter::specialization() +{ + return specType; +} + + +Object *TemplateTypeParameter::defaultArg(Loc loc, Scope *sc) +{ + Type *t; + + t = defaultType; + if (t) + { + t = t->syntaxCopy(); + t = t->semantic(loc, sc); + } + return t; +} + +/* ======================== TemplateThisParameter =========================== */ + +#if DMDV2 +// this-parameter + +TemplateThisParameter::TemplateThisParameter(Loc loc, Identifier *ident, + Type *specType, + Type *defaultType) + : TemplateTypeParameter(loc, ident, specType, defaultType) +{ +} + +TemplateThisParameter *TemplateThisParameter::isTemplateThisParameter() +{ + return this; +} + +TemplateParameter *TemplateThisParameter::syntaxCopy() +{ + TemplateThisParameter *tp = new TemplateThisParameter(loc, ident, specType, defaultType); + if (tp->specType) + tp->specType = specType->syntaxCopy(); + if (defaultType) + tp->defaultType = defaultType->syntaxCopy(); + return tp; +} + +void TemplateThisParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("this "); + TemplateTypeParameter::toCBuffer(buf, hgs); +} +#endif + +/* ======================== TemplateAliasParameter ========================== */ + +// alias-parameter + +Dsymbol *TemplateAliasParameter::sdummy = NULL; + +TemplateAliasParameter::TemplateAliasParameter(Loc loc, Identifier *ident, + Type *specType, Object *specAlias, Object *defaultAlias) + : TemplateParameter(loc, ident) +{ + this->ident = ident; + this->specType = specType; + this->specAlias = specAlias; + this->defaultAlias = defaultAlias; +} + +TemplateAliasParameter *TemplateAliasParameter::isTemplateAliasParameter() +{ + return this; +} + +TemplateParameter *TemplateAliasParameter::syntaxCopy() +{ + TemplateAliasParameter *tp = new TemplateAliasParameter(loc, ident, specType, specAlias, defaultAlias); + if (tp->specType) + tp->specType = specType->syntaxCopy(); + tp->specAlias = objectSyntaxCopy(specAlias); + tp->defaultAlias = objectSyntaxCopy(defaultAlias); + return tp; +} + +void TemplateAliasParameter::declareParameter(Scope *sc) +{ + TypeIdentifier *ti = new TypeIdentifier(loc, ident); + sparam = new AliasDeclaration(loc, ident, ti); + if (!sc->insert(sparam)) + error(loc, "parameter '%s' multiply defined", ident->toChars()); +} + +Object *aliasParameterSemantic(Loc loc, Scope *sc, Object *o) +{ + if (o) + { + Expression *ea = isExpression(o); + Type *ta = isType(o); + if (ta) + { Dsymbol *s = ta->toDsymbol(sc); + if (s) + o = s; + else + o = ta->semantic(loc, sc); + } + else if (ea) + { + ea = ea->semantic(sc); + o = ea->optimize(WANTvalue | WANTinterpret); + } + } + return o; +} + +void TemplateAliasParameter::semantic(Scope *sc) +{ + if (specType) + { + specType = specType->semantic(loc, sc); + } + specAlias = aliasParameterSemantic(loc, sc, specAlias); +#if 0 // Don't do semantic() until instantiation + if (defaultAlias) + defaultAlias = defaultAlias->semantic(loc, sc); +#endif +} + +int TemplateAliasParameter::overloadMatch(TemplateParameter *tp) +{ + TemplateAliasParameter *tap = tp->isTemplateAliasParameter(); + + if (tap) + { + if (specAlias != tap->specAlias) + goto Lnomatch; + + return 1; // match + } + +Lnomatch: + return 0; +} + +MATCH TemplateAliasParameter::matchArg(Scope *sc, Objects *tiargs, + size_t i, TemplateParameters *parameters, Objects *dedtypes, + Declaration **psparam) +{ + Object *sa; + Object *oarg; + Expression *ea; + Dsymbol *s; + + //printf("TemplateAliasParameter::matchArg()\n"); + + if (i < tiargs->dim) + oarg = tiargs->tdata()[i]; + else + { // Get default argument instead + oarg = defaultArg(loc, sc); + if (!oarg) + { assert(i < dedtypes->dim); + // It might have already been deduced + oarg = dedtypes->tdata()[i]; + if (!oarg) + goto Lnomatch; + } + } + + sa = getDsymbol(oarg); + if (sa) + { + /* specType means the alias must be a declaration with a type + * that matches specType. + */ + if (specType) + { Declaration *d = ((Dsymbol *)sa)->isDeclaration(); + if (!d) + goto Lnomatch; + if (!d->type->equals(specType)) + goto Lnomatch; + } + } + else + { + sa = oarg; + ea = isExpression(oarg); + if (ea) + { if (specType) + { + if (!ea->type->equals(specType)) + goto Lnomatch; + } + } + else + goto Lnomatch; + } + + if (specAlias) + { + if (sa == sdummy) + goto Lnomatch; + if (sa != specAlias) + goto Lnomatch; + } + else if (dedtypes->tdata()[i]) + { // Must match already deduced symbol + Object *si = dedtypes->tdata()[i]; + + if (!sa || si != sa) + goto Lnomatch; + } + dedtypes->tdata()[i] = sa; + + s = isDsymbol(sa); + if (s) + *psparam = new AliasDeclaration(loc, ident, s); + else + { + assert(ea); + + // Declare manifest constant + Initializer *init = new ExpInitializer(loc, ea); + VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init); + v->storage_class = STCmanifest; + v->semantic(sc); + *psparam = v; + } + return MATCHexact; + +Lnomatch: + *psparam = NULL; + //printf("\tm = %d\n", MATCHnomatch); + return MATCHnomatch; +} + + +void TemplateAliasParameter::print(Object *oarg, Object *oded) +{ + printf(" %s\n", ident->toChars()); + + Dsymbol *sa = isDsymbol(oded); + assert(sa); + + printf("\tParameter alias: %s\n", sa->toChars()); +} + +void TemplateAliasParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("alias "); + if (specType) + { HdrGenState hgs1; + specType->toCBuffer(buf, ident, &hgs1); + } + else + buf->writestring(ident->toChars()); + if (specAlias) + { + buf->writestring(" : "); + ObjectToCBuffer(buf, hgs, specAlias); + } + if (defaultAlias) + { + buf->writestring(" = "); + ObjectToCBuffer(buf, hgs, defaultAlias); + } +} + + +void *TemplateAliasParameter::dummyArg() +{ Object *s; + + s = specAlias; + if (!s) + { + if (!sdummy) + sdummy = new Dsymbol(); + s = sdummy; + } + return (void*)s; +} + + +Object *TemplateAliasParameter::specialization() +{ + return specAlias; +} + + +Object *TemplateAliasParameter::defaultArg(Loc loc, Scope *sc) +{ + Object *da = defaultAlias; + Type *ta = isType(defaultAlias); + if (ta) + { + if (ta->ty == Tinstance) + { + // If the default arg is a template, instantiate for each type + da = ta->syntaxCopy(); + } + } + + Object *o = aliasParameterSemantic(loc, sc, da); + return o; +} + +/* ======================== TemplateValueParameter ========================== */ + +// value-parameter + +AA *TemplateValueParameter::edummies = NULL; + +TemplateValueParameter::TemplateValueParameter(Loc loc, Identifier *ident, Type *valType, + Expression *specValue, Expression *defaultValue) + : TemplateParameter(loc, ident) +{ + this->ident = ident; + this->valType = valType; + this->specValue = specValue; + this->defaultValue = defaultValue; +} + +TemplateValueParameter *TemplateValueParameter::isTemplateValueParameter() +{ + return this; +} + +TemplateParameter *TemplateValueParameter::syntaxCopy() +{ + TemplateValueParameter *tp = + new TemplateValueParameter(loc, ident, valType, specValue, defaultValue); + tp->valType = valType->syntaxCopy(); + if (specValue) + tp->specValue = specValue->syntaxCopy(); + if (defaultValue) + tp->defaultValue = defaultValue->syntaxCopy(); + return tp; +} + +void TemplateValueParameter::declareParameter(Scope *sc) +{ + VarDeclaration *v = new VarDeclaration(loc, valType, ident, NULL); + v->storage_class = STCtemplateparameter; + if (!sc->insert(v)) + error(loc, "parameter '%s' multiply defined", ident->toChars()); + sparam = v; +} + +void TemplateValueParameter::semantic(Scope *sc) +{ + bool wasSame = (sparam->type == valType); + sparam->semantic(sc); + if (sparam->type == Type::terror && wasSame) + { /* If sparam has a type error, avoid duplicate errors + * The simple solution of leaving that function if sparam->type == Type::terror + * doesn't quite work because it causes failures in xtest46 for bug 6295 + */ + valType = Type::terror; + return; + } + valType = valType->semantic(loc, sc); + if (!(valType->isintegral() || valType->isfloating() || valType->isString()) && + valType->ty != Tident) + { + if (valType != Type::terror) + error(loc, "arithmetic/string type expected for value-parameter, not %s", valType->toChars()); + } + +#if 0 // defer semantic analysis to arg match + if (specValue) + { Expression *e = specValue; + + e = e->semantic(sc); + e = e->implicitCastTo(sc, valType); + e = e->optimize(WANTvalue | WANTinterpret); + if (e->op == TOKint64 || e->op == TOKfloat64 || + e->op == TOKcomplex80 || e->op == TOKnull || e->op == TOKstring) + specValue = e; + //e->toInteger(); + } + + if (defaultValue) + { Expression *e = defaultValue; + + e = e->semantic(sc); + e = e->implicitCastTo(sc, valType); + e = e->optimize(WANTvalue | WANTinterpret); + if (e->op == TOKint64) + defaultValue = e; + //e->toInteger(); + } +#endif +} + +int TemplateValueParameter::overloadMatch(TemplateParameter *tp) +{ + TemplateValueParameter *tvp = tp->isTemplateValueParameter(); + + if (tvp) + { + if (valType != tvp->valType) + goto Lnomatch; + + if (valType && !valType->equals(tvp->valType)) + goto Lnomatch; + + if (specValue != tvp->specValue) + goto Lnomatch; + + return 1; // match + } + +Lnomatch: + return 0; +} + + +MATCH TemplateValueParameter::matchArg(Scope *sc, + Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, + Declaration **psparam) +{ + //printf("TemplateValueParameter::matchArg()\n"); + + Initializer *init; + Declaration *sparam; + MATCH m = MATCHexact; + Expression *ei; + Object *oarg; + + if (i < tiargs->dim) + oarg = tiargs->tdata()[i]; + else + { // Get default argument instead + oarg = defaultArg(loc, sc); + if (!oarg) + { assert(i < dedtypes->dim); + // It might have already been deduced + oarg = dedtypes->tdata()[i]; + if (!oarg) + goto Lnomatch; + } + } + + ei = isExpression(oarg); + Type *vt; + + if (!ei && oarg) + goto Lnomatch; + + if (ei && ei->op == TOKvar) + { // Resolve const variables that we had skipped earlier + ei = ei->optimize(WANTvalue | WANTinterpret); + } + + //printf("\tvalType: %s, ty = %d\n", valType->toChars(), valType->ty); + vt = valType->semantic(0, sc); + //printf("ei: %s, ei->type: %s\n", ei->toChars(), ei->type->toChars()); + //printf("vt = %s\n", vt->toChars()); + + if (ei->type) + { + m = (MATCH)ei->implicitConvTo(vt); + //printf("m: %d\n", m); + if (!m) + goto Lnomatch; + } + + if (specValue) + { + if (!ei || _aaGetRvalue(edummies, ei->type) == ei) + goto Lnomatch; + + Expression *e = specValue; + + e = e->semantic(sc); + e = e->implicitCastTo(sc, vt); + e = e->optimize(WANTvalue | WANTinterpret); + + ei = ei->syntaxCopy(); + ei = ei->semantic(sc); + ei = ei->implicitCastTo(sc, vt); + ei = ei->optimize(WANTvalue | WANTinterpret); + //printf("\tei: %s, %s\n", ei->toChars(), ei->type->toChars()); + //printf("\te : %s, %s\n", e->toChars(), e->type->toChars()); + if (!ei->equals(e)) + goto Lnomatch; + } + else + { + if (dedtypes->tdata()[i]) + { // Must match already deduced value + Expression *e = (Expression *)dedtypes->tdata()[i]; + + if (!ei || !ei->equals(e)) + goto Lnomatch; + } + else if (m != MATCHexact) + { + ei = ei->implicitCastTo(sc, vt); + ei = ei->optimize(WANTvalue | WANTinterpret); + } + } + dedtypes->tdata()[i] = ei; + + init = new ExpInitializer(loc, ei); + sparam = new VarDeclaration(loc, vt, ident, init); + sparam->storage_class = STCmanifest; + *psparam = sparam; + return m; + +Lnomatch: + //printf("\tno match\n"); + *psparam = NULL; + return MATCHnomatch; +} + + +void TemplateValueParameter::print(Object *oarg, Object *oded) +{ + printf(" %s\n", ident->toChars()); + + Expression *ea = isExpression(oded); + + if (specValue) + printf("\tSpecialization: %s\n", specValue->toChars()); + printf("\tParameter Value: %s\n", ea ? ea->toChars() : "NULL"); +} + + +void TemplateValueParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + valType->toCBuffer(buf, ident, hgs); + if (specValue) + { + buf->writestring(" : "); + specValue->toCBuffer(buf, hgs); + } + if (defaultValue) + { + buf->writestring(" = "); + defaultValue->toCBuffer(buf, hgs); + } +} + + +void *TemplateValueParameter::dummyArg() +{ Expression *e; + + e = specValue; + if (!e) + { + // Create a dummy value + Expression **pe = (Expression **)_aaGet(&edummies, valType); + if (!*pe) + *pe = valType->defaultInit(); + e = *pe; + } + return (void *)e; +} + + +Object *TemplateValueParameter::specialization() +{ + return specValue; +} + + +Object *TemplateValueParameter::defaultArg(Loc loc, Scope *sc) +{ + Expression *e = defaultValue; + if (e) + { + e = e->syntaxCopy(); + e = e->semantic(sc); +#if DMDV2 + e = e->resolveLoc(loc, sc); +#endif + } + return e; +} + +/* ======================== TemplateTupleParameter ========================== */ + +// variadic-parameter + +TemplateTupleParameter::TemplateTupleParameter(Loc loc, Identifier *ident) + : TemplateParameter(loc, ident) +{ + this->ident = ident; +} + +TemplateTupleParameter *TemplateTupleParameter::isTemplateTupleParameter() +{ + return this; +} + +TemplateParameter *TemplateTupleParameter::syntaxCopy() +{ + TemplateTupleParameter *tp = new TemplateTupleParameter(loc, ident); + return tp; +} + +void TemplateTupleParameter::declareParameter(Scope *sc) +{ + TypeIdentifier *ti = new TypeIdentifier(loc, ident); + sparam = new AliasDeclaration(loc, ident, ti); + if (!sc->insert(sparam)) + error(loc, "parameter '%s' multiply defined", ident->toChars()); +} + +void TemplateTupleParameter::semantic(Scope *sc) +{ +} + +int TemplateTupleParameter::overloadMatch(TemplateParameter *tp) +{ + TemplateTupleParameter *tvp = tp->isTemplateTupleParameter(); + + if (tvp) + { + return 1; // match + } + + return 0; +} + +MATCH TemplateTupleParameter::matchArg(Scope *sc, Objects *tiargs, + size_t i, TemplateParameters *parameters, Objects *dedtypes, + Declaration **psparam) +{ + //printf("TemplateTupleParameter::matchArg()\n"); + + /* The rest of the actual arguments (tiargs[]) form the match + * for the variadic parameter. + */ + assert(i + 1 == dedtypes->dim); // must be the last one + Tuple *ovar; + + if (dedtypes->tdata()[i] && isTuple(dedtypes->tdata()[i])) + // It was already been deduced + ovar = isTuple(dedtypes->tdata()[i]); + else if (i + 1 == tiargs->dim && isTuple(tiargs->tdata()[i])) + ovar = isTuple(tiargs->tdata()[i]); + else + { + ovar = new Tuple(); + //printf("ovar = %p\n", ovar); + if (i < tiargs->dim) + { + //printf("i = %d, tiargs->dim = %d\n", i, tiargs->dim); + ovar->objects.setDim(tiargs->dim - i); + for (size_t j = 0; j < ovar->objects.dim; j++) + ovar->objects.tdata()[j] = tiargs->tdata()[i + j]; + } + } + *psparam = new TupleDeclaration(loc, ident, &ovar->objects); + dedtypes->tdata()[i] = ovar; + return MATCHexact; +} + + +void TemplateTupleParameter::print(Object *oarg, Object *oded) +{ + printf(" %s... [", ident->toChars()); + Tuple *v = isTuple(oded); + assert(v); + + //printf("|%d| ", v->objects.dim); + for (size_t i = 0; i < v->objects.dim; i++) + { + if (i) + printf(", "); + + Object *o = v->objects.tdata()[i]; + + Dsymbol *sa = isDsymbol(o); + if (sa) + printf("alias: %s", sa->toChars()); + + Type *ta = isType(o); + if (ta) + printf("type: %s", ta->toChars()); + + Expression *ea = isExpression(o); + if (ea) + printf("exp: %s", ea->toChars()); + + assert(!isTuple(o)); // no nested Tuple arguments + } + + printf("]\n"); +} + +void TemplateTupleParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(ident->toChars()); + buf->writestring("..."); +} + + +void *TemplateTupleParameter::dummyArg() +{ + return NULL; +} + + +Object *TemplateTupleParameter::specialization() +{ + return NULL; +} + + +Object *TemplateTupleParameter::defaultArg(Loc loc, Scope *sc) +{ + return NULL; +} + +/* ======================== TemplateInstance ================================ */ + +TemplateInstance::TemplateInstance(Loc loc, Identifier *ident) + : ScopeDsymbol(NULL) +{ +#if LOG + printf("TemplateInstance(this = %p, ident = '%s')\n", this, ident ? ident->toChars() : "null"); +#endif + this->loc = loc; + this->name = ident; + this->tiargs = NULL; + this->tempdecl = NULL; + this->inst = NULL; + this->tinst = NULL; + this->argsym = NULL; + this->aliasdecl = NULL; + this->semanticRun = PASSinit; + this->semantictiargsdone = 0; + this->withsym = NULL; + this->nest = 0; + this->havetempdecl = 0; + this->isnested = NULL; + this->speculative = 0; + this->ignore = true; + +#if IN_LLVM + this->emittedInModule = NULL; + this->tmodule = NULL; +#endif +} + +/***************** + * This constructor is only called when we figured out which function + * template to instantiate. + */ + +TemplateInstance::TemplateInstance(Loc loc, TemplateDeclaration *td, Objects *tiargs) + : ScopeDsymbol(NULL) +{ +#if LOG + printf("TemplateInstance(this = %p, tempdecl = '%s')\n", this, td->toChars()); +#endif + this->loc = loc; + this->name = td->ident; + this->tiargs = tiargs; + this->tempdecl = td; + this->inst = NULL; + this->tinst = NULL; + this->argsym = NULL; + this->aliasdecl = NULL; + this->semanticRun = PASSinit; + this->semantictiargsdone = 1; + this->withsym = NULL; + this->nest = 0; + this->havetempdecl = 1; + this->isnested = NULL; + this->speculative = 0; + this->ignore = true; + +#if IN_LLVM + this->tinst = NULL; + this->emittedInModule = NULL; + this->tmodule = NULL; +#endif + + assert((size_t)tempdecl->scope > 0x10000); +} + + +Objects *TemplateInstance::arraySyntaxCopy(Objects *objs) +{ + Objects *a = NULL; + if (objs) + { a = new Objects(); + a->setDim(objs->dim); + for (size_t i = 0; i < objs->dim; i++) + { + a->tdata()[i] = objectSyntaxCopy(objs->tdata()[i]); + } + } + return a; +} + +Dsymbol *TemplateInstance::syntaxCopy(Dsymbol *s) +{ + TemplateInstance *ti; + + if (s) + ti = (TemplateInstance *)s; + else + ti = new TemplateInstance(loc, name); + + ti->tiargs = arraySyntaxCopy(tiargs); + + ScopeDsymbol::syntaxCopy(ti); + return ti; +} + + +void TemplateInstance::semantic(Scope *sc) +{ + semantic(sc, NULL); +} + +void TemplateInstance::expandMembers(Scope *sc2) +{ + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *s = (*members)[i]; + s->setScope(sc2); + } + for (size_t i = 0; i < members->dim; i++) + { + Dsymbol *s = members->tdata()[i]; + //printf("\t[%d] semantic on '%s' %p kind %s in '%s'\n", i, s->toChars(), s, s->kind(), this->toChars()); + //printf("test: isnested = %d, sc2->parent = %s\n", isnested, sc2->parent->toChars()); +// if (isnested) +// s->parent = sc->parent; + //printf("test3: isnested = %d, s->parent = %s\n", isnested, s->parent->toChars()); + s->semantic(sc2); + //printf("test4: isnested = %d, s->parent = %s\n", isnested, s->parent->toChars()); + sc2->module->runDeferredSemantic(); + } +} + +void TemplateInstance::tryExpandMembers(Scope *sc2) +{ + static int nest; + // extracted to a function to allow windows SEH to work without destructors in the same function + //printf("%d\n", nest); + if (++nest > 500) + { + global.gag = 0; // ensure error message gets printed + error("recursive expansion"); + fatal(); + } + +#if WINDOWS_SEH + if(nest == 1) + { + // do not catch at every nesting level, because generating the output error might cause more stack + // errors in the __except block otherwise + __try + { + expandMembers(sc2); + } + __except (__ehfilter(GetExceptionInformation())) + { + global.gag = 0; // ensure error message gets printed + error("recursive expansion"); + fatal(); + } + } + else +#endif + expandMembers(sc2); + nest--; +} + +void TemplateInstance::trySemantic3(Scope *sc2) +{ + // extracted to a function to allow windows SEH to work without destructors in the same function + static int nest; + if (++nest > 300) + { + global.gag = 0; // ensure error message gets printed + error("recursive expansion"); + fatal(); + } +#if WINDOWS_SEH + if(nest == 1) + { + // do not catch at every nesting level, because generating the output error might cause more stack + // errors in the __except block otherwise + __try + { + semantic3(sc2); + } + __except (__ehfilter(GetExceptionInformation())) + { + global.gag = 0; // ensure error message gets printed + error("recursive expansion"); + fatal(); + } + } + else +#endif + semantic3(sc2); + + --nest; +} + +void TemplateInstance::semantic(Scope *sc, Expressions *fargs) +{ + //printf("TemplateInstance::semantic('%s', this=%p, gag = %d, sc = %p)\n", toChars(), this, global.gag, sc); +#if LOG + printf("\n+TemplateInstance::semantic('%s', this=%p)\n", toChars(), this); +#endif + if (inst) // if semantic() was already run + { +#if LOG + printf("-TemplateInstance::semantic('%s', this=%p) already run\n", inst->toChars(), inst); +#endif + return; + } + + if (!sc->ignoreTemplates) + ignore = false; + + + // get the enclosing template instance from the scope tinst + tinst = sc->tinst; + + if (semanticRun != PASSinit) + { +#if LOG + printf("Recursive template expansion\n"); +#endif + error(loc, "recursive template expansion"); +// inst = this; + return; + } + semanticRun = PASSsemantic; +#if IN_LLVM + // get the enclosing template instance from the scope tinst + tinst = sc->tinst; + + // get the module of the outermost enclosing instantiation + if (tinst) + tmodule = tinst->tmodule; + else + tmodule = sc->module; + //printf("%s in %s\n", toChars(), tmodule->toChars()); +#endif + +#if LOG + printf("\tdo semantic\n"); +#endif + if (havetempdecl) + { + assert((size_t)tempdecl->scope > 0x10000); + // Deduce tdtypes + tdtypes.setDim(tempdecl->parameters->dim); + if (!tempdecl->matchWithInstance(this, &tdtypes, fargs, 2)) + { + error("incompatible arguments for template instantiation"); + inst = this; + return; + } + } + else + { + /* Run semantic on each argument, place results in tiargs[] + * (if we havetempdecl, then tiargs is already evaluated) + */ + semanticTiargs(sc); + if (arrayObjectIsError(tiargs)) + { inst = this; + //printf("error return %p, %d\n", tempdecl, global.errors); + return; // error recovery + } + unsigned errs = global.errors; + tempdecl = findTemplateDeclaration(sc); + if (tempdecl) + tempdecl = findBestMatch(sc, fargs); + if (!tempdecl || (errs != global.errors)) + { inst = this; + //printf("error return %p, %d\n", tempdecl, global.errors); + return; // error recovery + } + } + + // If tempdecl is a mixin, disallow it + if (tempdecl->ismixin) + error("mixin templates are not regular templates"); + + hasNestedArgs(tiargs); + + /* See if there is an existing TemplateInstantiation that already + * implements the typeargs. If so, just refer to that one instead. + */ + + for (size_t i = 0; i < tempdecl->instances.dim; i++) + { + TemplateInstance *ti = tempdecl->instances.tdata()[i]; +#if LOG + printf("\t%s: checking for match with instance %d (%p): '%s'\n", toChars(), i, ti, ti->toChars()); +#endif + assert(tdtypes.dim == ti->tdtypes.dim); + + // Nesting must match + if (isnested != ti->isnested) + { + //printf("test2 isnested %s ti->isnested %s\n", isnested ? isnested->toChars() : "", ti->isnested ? ti->isnested->toChars() : ""); + continue; + } + //printf("parent = %s, ti->parent = %s\n", tempdecl->parent->toPrettyChars(), ti->parent->toPrettyChars()); + + if (!arrayObjectMatch(&tdtypes, &ti->tdtypes, tempdecl, sc)) + goto L1; + + /* Template functions may have different instantiations based on + * "auto ref" parameters. + */ + if (fargs) + { + FuncDeclaration *fd = ti->toAlias()->isFuncDeclaration(); + if (fd) + { + Parameters *fparameters = fd->getParameters(NULL); + size_t nfparams = Parameter::dim(fparameters); // Num function parameters + for (size_t j = 0; j < nfparams && j < fargs->dim; j++) + { Parameter *fparam = Parameter::getNth(fparameters, j); + Expression *farg = fargs->tdata()[j]; + if (fparam->storageClass & STCauto) // if "auto ref" + { + if (farg->isLvalue()) + { if (!(fparam->storageClass & STCref)) + goto L1; // auto ref's don't match + } + else + { if (fparam->storageClass & STCref) + goto L1; // auto ref's don't match + } + } + } + } + } + + // It's a match + inst = ti; + parent = ti->parent; + + // If both this and the previous instantiation were speculative, + // use the number of errors that happened last time. + if (inst->speculative && global.gag) + { + global.errors += inst->errors; + global.gaggedErrors += inst->errors; + } + + // If the first instantiation was speculative, but this is not: + if (inst->speculative && !global.gag) + { + // If the first instantiation had failed, re-run semantic, + // so that error messages are shown. + if (inst->errors) + goto L1; + // It had succeeded, mark it is a non-speculative instantiation, + // and reuse it. + inst->speculative = 0; + } + +#if LOG + printf("\tit's a match with instance %p, %d\n", inst, inst->semanticRun); +#endif + return; + + L1: + ; + } + + /* So, we need to implement 'this' instance. + */ +#if LOG + printf("\timplement template instance %s '%s'\n", tempdecl->parent->toChars(), toChars()); + printf("\ttempdecl %s\n", tempdecl->toChars()); +#endif + unsigned errorsave = global.errors; + inst = this; + // Mark as speculative if we are instantiated from inside is(typeof()) + if (global.gag && sc->speculative) + speculative = 1; + + int tempdecl_instance_idx = tempdecl->instances.dim; + tempdecl->instances.push(this); + parent = tempdecl->parent; + //printf("parent = '%s'\n", parent->kind()); + + ident = genIdent(tiargs); // need an identifier for name mangling purposes. + +#if 1 + if (isnested) + parent = isnested; +#endif + //printf("parent = '%s'\n", parent->kind()); + + // Add 'this' to the enclosing scope's members[] so the semantic routines + // will get called on the instance members. Store the place we added it to + // in target_symbol_list(_idx) so we can remove it later if we encounter + // an error. +#if 1 + int dosemantic3 = 0; + Dsymbols *target_symbol_list = NULL; + int target_symbol_list_idx; + + if (!sc->parameterSpecialization) + { Dsymbols *a; + + Scope *scx = sc; +#if 0 + for (scx = sc; scx; scx = scx->enclosing) + if (scx->scopesym) + break; +#endif + + //if (scx && scx->scopesym) printf("3: scx is %s %s\n", scx->scopesym->kind(), scx->scopesym->toChars()); + if (scx && scx->scopesym && + scx->scopesym->members && !scx->scopesym->isTemplateMixin() +#if 0 // removed because it bloated compile times + /* The problem is if A imports B, and B imports A, and both A + * and B instantiate the same template, does the compilation of A + * or the compilation of B do the actual instantiation? + * + * see bugzilla 2500. + */ + && !scx->module->selfImports() +#endif + ) + { + //printf("\t1: adding to %s %s\n", scx->scopesym->kind(), scx->scopesym->toChars()); + a = scx->scopesym->members; + } + else + { Module *m = sc->module->importedFrom; + //printf("\t2: adding to module %s instead of module %s\n", m->toChars(), sc->module->toChars()); + a = m->members; + if (m->semanticRun >= 3) + { + dosemantic3 = 1; + } + } + for (int i = 0; 1; i++) + { + if (i == a->dim) + { + target_symbol_list = a; + target_symbol_list_idx = i; + a->push(this); + break; + } + if (this == a->tdata()[i]) // if already in Array + break; + } + } +#endif + + // Copy the syntax trees from the TemplateDeclaration + members = Dsymbol::arraySyntaxCopy(tempdecl->members); + + // Create our own scope for the template parameters + Scope *scope = tempdecl->scope; + if (!tempdecl->semanticRun) + { + error("template instantiation %s forward references template declaration %s\n", toChars(), tempdecl->toChars()); + return; + } + +#if LOG + printf("\tcreate scope for template parameters '%s'\n", toChars()); +#endif + argsym = new ScopeDsymbol(); + argsym->parent = scope->parent; + scope = scope->push(argsym); +// scope->stc = 0; + + // Declare each template parameter as an alias for the argument type + Scope *paramscope = scope->push(); + paramscope->stc = 0; + declareParameters(paramscope); + paramscope->pop(); + + // Add members of template instance to template instance symbol table +// parent = scope->scopesym; + symtab = new DsymbolTable(); + int memnum = 0; + for (size_t i = 0; i < members->dim; i++) + { + Dsymbol *s = members->tdata()[i]; +#if LOG + printf("\t[%d] adding member '%s' %p kind %s to '%s', memnum = %d\n", i, s->toChars(), s, s->kind(), this->toChars(), memnum); +#endif + memnum |= s->addMember(scope, this, memnum); + } +#if LOG + printf("adding members done\n"); +#endif + + /* See if there is only one member of template instance, and that + * member has the same name as the template instance. + * If so, this template instance becomes an alias for that member. + */ + //printf("members->dim = %d\n", members->dim); + if (members->dim) + { + Dsymbol *s; + if (Dsymbol::oneMembers(members, &s, tempdecl->ident) && s) + { + //printf("s->kind = '%s'\n", s->kind()); + //s->print(); + //printf("'%s', '%s'\n", s->ident->toChars(), tempdecl->ident->toChars()); + //printf("setting aliasdecl\n"); + aliasdecl = new AliasDeclaration(loc, s->ident, s); + +#if IN_LLVM + // LDC propagate internal information + if (tempdecl->llvmInternal) { + s->llvmInternal = tempdecl->llvmInternal; + if (FuncDeclaration* fd = s->isFuncDeclaration()) { + fd->intrinsicName = tempdecl->intrinsicName; + } + } +#endif + } + } + + /* If function template declaration + */ + if (fargs && aliasdecl) + { + FuncDeclaration *fd = aliasdecl->toAlias()->isFuncDeclaration(); + if (fd) + { + /* Transmit fargs to type so that TypeFunction::semantic() can + * resolve any "auto ref" storage classes. + */ + TypeFunction *tf = (TypeFunction *)fd->type; + if (tf && tf->ty == Tfunction) + tf->fargs = fargs; + } + } + + // Do semantic() analysis on template instance members +#if LOG + printf("\tdo semantic() on template instance members '%s'\n", toChars()); +#endif + Scope *sc2; + sc2 = scope->push(this); + //printf("isnested = %d, sc->parent = %s\n", isnested, sc->parent->toChars()); + sc2->parent = /*isnested ? sc->parent :*/ this; + sc2->tinst = this; + + tryExpandMembers(sc2); + + semanticRun = PASSsemanticdone; + + /* If any of the instantiation members didn't get semantic() run + * on them due to forward references, we cannot run semantic2() + * or semantic3() yet. + */ + for (size_t i = 0; i < Module::deferred.dim; i++) + { Dsymbol *sd = Module::deferred.tdata()[i]; + + if (sd->parent == this) + { + //printf("deferred %s %s\n", sd->parent->toChars(), sd->toChars()); + AggregateDeclaration *ad = sd->isAggregateDeclaration(); + if (ad) + ad->deferred = this; + goto Laftersemantic; + } + } + + /* ConditionalDeclaration may introduce eponymous declaration, + * so we should find it once again after semantic. + */ + if (members->dim) + { + Dsymbol *s; + if (Dsymbol::oneMembers(members, &s, tempdecl->ident) && s) + { + if (!aliasdecl || aliasdecl->toAlias() != s) + { + //printf("s->kind = '%s'\n", s->kind()); + //s->print(); + //printf("'%s', '%s'\n", s->ident->toChars(), tempdecl->ident->toChars()); + //printf("setting aliasdecl 2\n"); + aliasdecl = new AliasDeclaration(loc, s->ident, s); + } + } + else if (aliasdecl) + aliasdecl = NULL; + } + + /* The problem is when to parse the initializer for a variable. + * Perhaps VarDeclaration::semantic() should do it like it does + * for initializers inside a function. + */ +// if (sc->parent->isFuncDeclaration()) + + /* BUG 782: this has problems if the classes this depends on + * are forward referenced. Find a way to defer semantic() + * on this template. + */ + semantic2(sc2); + + if (sc->func || dosemantic3) + { + trySemantic3(sc2); + } + + Laftersemantic: + sc2->pop(); + + scope->pop(); + + // Give additional context info if error occurred during instantiation + if (global.errors != errorsave) + { + error(loc, "error instantiating"); + if (tinst) + { tinst->printInstantiationTrace(); + } + errors = 1; + if (global.gag) + { + // Errors are gagged, so remove the template instance from the + // instance/symbol lists we added it to and reset our state to + // finish clean and so we can try to instantiate it again later + // (see bugzilla 4302 and 6602). + tempdecl->instances.remove(tempdecl_instance_idx); + if (target_symbol_list) + { + // Because we added 'this' in the last position above, we + // should be able to remove it without messing other indices up. + assert(target_symbol_list->tdata()[target_symbol_list_idx] == this); + target_symbol_list->remove(target_symbol_list_idx); + } + semanticRun = PASSinit; + inst = NULL; + } + } + +#if LOG + printf("-TemplateInstance::semantic('%s', this=%p)\n", toChars(), this); +#endif +} + + +void TemplateInstance::semanticTiargs(Scope *sc) +{ + //printf("+TemplateInstance::semanticTiargs() %s\n", toChars()); + if (semantictiargsdone) + return; + semantictiargsdone = 1; + semanticTiargs(loc, sc, tiargs, 0); +} + +/********************************** + * Input: + * flags 1: replace const variables with their initializers + */ + +void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int flags) +{ + // Run semantic on each argument, place results in tiargs[] + //printf("+TemplateInstance::semanticTiargs()\n"); + if (!tiargs) + return; + for (size_t j = 0; j < tiargs->dim; j++) + { + Object *o = tiargs->tdata()[j]; + Type *ta = isType(o); + Expression *ea = isExpression(o); + Dsymbol *sa = isDsymbol(o); + + //printf("1: tiargs->tdata()[%d] = %p, %p, %p, ea=%p, ta=%p\n", j, o, isDsymbol(o), isTuple(o), ea, ta); + if (ta) + { + //printf("type %s\n", ta->toChars()); + // It might really be an Expression or an Alias + ta->resolve(loc, sc, &ea, &ta, &sa); + if (ea) + { + ea = ea->semantic(sc); + /* This test is to skip substituting a const var with + * its initializer. The problem is the initializer won't + * match with an 'alias' parameter. Instead, do the + * const substitution in TemplateValueParameter::matchArg(). + */ + if (flags & 1) // only used by __traits, must not interpret the args + ea = ea->optimize(WANTvalue); + else if (ea->op != TOKvar) + ea = ea->optimize(WANTvalue | WANTinterpret); + tiargs->tdata()[j] = ea; + } + else if (sa) + { + Ldsym: + tiargs->tdata()[j] = sa; + TupleDeclaration *d = sa->toAlias()->isTupleDeclaration(); + if (d) + { + size_t dim = d->objects->dim; + tiargs->remove(j); + tiargs->insert(j, d->objects); + j--; + } + } + else if (ta) + { + Ltype: + if (ta->ty == Ttuple) + { // Expand tuple + TypeTuple *tt = (TypeTuple *)ta; + size_t dim = tt->arguments->dim; + tiargs->remove(j); + if (dim) + { tiargs->reserve(dim); + for (size_t i = 0; i < dim; i++) + { Parameter *arg = tt->arguments->tdata()[i]; + tiargs->insert(j + i, arg->type); + } + } + j--; + } + else + tiargs->tdata()[j] = ta; + } + else + { + assert(global.errors); + tiargs->tdata()[j] = Type::terror; + } + } + else if (ea) + { + if (!ea) + { assert(global.errors); + ea = new ErrorExp(); + } + assert(ea); + ea = ea->semantic(sc); + if (flags & 1) // only used by __traits, must not interpret the args + ea = ea->optimize(WANTvalue); + else if (ea->op != TOKvar && ea->op != TOKtuple) + ea = ea->optimize(WANTvalue | WANTinterpret); + tiargs->tdata()[j] = ea; + if (ea->op == TOKtype) + { ta = ea->type; + goto Ltype; + } + if (ea->op == TOKimport) + { sa = ((ScopeExp *)ea)->sds; + goto Ldsym; + } + if (ea->op == TOKtuple) + { // Expand tuple + TupleExp *te = (TupleExp *)ea; + size_t dim = te->exps->dim; + tiargs->remove(j); + if (dim) + { tiargs->reserve(dim); + for (size_t i = 0; i < dim; i++) + tiargs->insert(j + i, te->exps->tdata()[i]); + } + j--; + } + } + else if (sa) + { + TemplateDeclaration *td = sa->isTemplateDeclaration(); + if (td && !td->semanticRun && td->literal) + td->semantic(sc); + } + else + { + assert(0); + } + //printf("1: tiargs->tdata()[%d] = %p\n", j, tiargs->tdata()[j]); + } +#if 0 + printf("-TemplateInstance::semanticTiargs()\n"); + for (size_t j = 0; j < tiargs->dim; j++) + { + Object *o = tiargs->tdata()[j]; + Type *ta = isType(o); + Expression *ea = isExpression(o); + Dsymbol *sa = isDsymbol(o); + Tuple *va = isTuple(o); + + printf("\ttiargs[%d] = ta %p, ea %p, sa %p, va %p\n", j, ta, ea, sa, va); + } +#endif +} + +/********************************************** + * Find template declaration corresponding to template instance. + */ + +TemplateDeclaration *TemplateInstance::findTemplateDeclaration(Scope *sc) +{ + //printf("TemplateInstance::findTemplateDeclaration() %s\n", toChars()); + if (!tempdecl) + { + /* Given: + * foo!( ... ) + * figure out which TemplateDeclaration foo refers to. + */ + Dsymbol *s; + Dsymbol *scopesym; + Identifier *id; + + id = name; + s = sc->search(loc, id, &scopesym); + if (!s) + { + 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 an OverloadSet, look for a unique member that is a template declaration + */ + OverloadSet *os = s->isOverloadSet(); + if (os) + { s = NULL; + for (size_t i = 0; i < os->a.dim; i++) + { Dsymbol *s2 = os->a.tdata()[i]; + if (s2->isTemplateDeclaration()) + { + if (s) + error("ambiguous template declaration %s and %s", s->toPrettyChars(), s2->toPrettyChars()); + s = s2; + } + } + if (!s) + { error("template '%s' is not defined", id->toChars()); + return NULL; + } + } + +#if LOG + printf("It's an instance of '%s' kind '%s'\n", s->toChars(), s->kind()); + if (s->parent) + printf("s->parent = '%s'\n", s->parent->toChars()); +#endif + withsym = scopesym->isWithScopeSymbol(); + + /* We might have found an alias within a template when + * we really want the template. + */ + TemplateInstance *ti; + if (s->parent && + (ti = s->parent->isTemplateInstance()) != NULL) + { + if (ti->tempdecl && ti->tempdecl->ident == id) + { + /* This is so that one can refer to the enclosing + * template, even if it has the same name as a member + * of the template, if it has a !(arguments) + */ + tempdecl = ti->tempdecl; + if (tempdecl->overroot) // if not start of overloaded list of TemplateDeclaration's + tempdecl = tempdecl->overroot; // then get the start + s = tempdecl; + } + } + + s = s->toAlias(); + + /* It should be a TemplateDeclaration, not some other symbol + */ + tempdecl = s->isTemplateDeclaration(); + if (!tempdecl) + { + if (!s->parent && global.errors) + return NULL; + if (!s->parent && s->getType()) + { Dsymbol *s2 = s->getType()->toDsymbol(sc); + if (!s2) + { + error("%s is not a template declaration, it is a %s", id->toChars(), s->kind()); + return NULL; + } + s = s2; + } +#ifdef DEBUG + //if (!s->parent) printf("s = %s %s\n", s->kind(), s->toChars()); +#endif + //assert(s->parent); + TemplateInstance *ti = s->parent ? s->parent->isTemplateInstance() : NULL; + if (ti && + (ti->name == id || + ti->toAlias()->ident == id) + && + ti->tempdecl) + { + /* This is so that one can refer to the enclosing + * template, even if it has the same name as a member + * of the template, if it has a !(arguments) + */ + tempdecl = ti->tempdecl; + if (tempdecl->overroot) // if not start of overloaded list of TemplateDeclaration's + tempdecl = tempdecl->overroot; // then get the start + } + else + { + error("%s is not a template declaration, it is a %s", id->toChars(), s->kind()); + return NULL; + } + } + } + else + assert(tempdecl->isTemplateDeclaration()); + return tempdecl; +} + +TemplateDeclaration *TemplateInstance::findBestMatch(Scope *sc, Expressions *fargs) +{ + /* Since there can be multiple TemplateDeclaration's with the same + * name, look for the best match. + */ + TemplateDeclaration *td_ambig = NULL; + TemplateDeclaration *td_best = NULL; + MATCH m_best = MATCHnomatch; + Objects dedtypes; + +#if LOG + printf("TemplateInstance::findBestMatch()\n"); +#endif + // First look for forward references + for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) + { + if (!td->semanticRun) + { + if (td->scope) + { // Try to fix forward reference + td->semantic(td->scope); + } + if (!td->semanticRun) + { + error("%s forward references template declaration %s\n", toChars(), td->toChars()); + return NULL; + } + } + } + + for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) + { + MATCH m; + +//if (tiargs->dim) printf("2: tiargs->dim = %d, data[0] = %p\n", tiargs->dim, tiargs->tdata()[0]); + + // If more arguments than parameters, + // then this is no match. + if (td->parameters->dim < tiargs->dim) + { + if (!td->isVariadic()) + continue; + } + + dedtypes.setDim(td->parameters->dim); + dedtypes.zero(); + assert(td->semanticRun); + m = td->matchWithInstance(this, &dedtypes, fargs, 0); + //printf("matchWithInstance = %d\n", m); + if (!m) // no match at all + continue; + + if (m < m_best) + goto Ltd_best; + if (m > m_best) + goto Ltd; + + { + // Disambiguate by picking the most specialized TemplateDeclaration + MATCH c1 = td->leastAsSpecialized(td_best, fargs); + MATCH c2 = td_best->leastAsSpecialized(td, fargs); + //printf("c1 = %d, c2 = %d\n", c1, c2); + + if (c1 > c2) + goto Ltd; + else if (c1 < c2) + goto Ltd_best; + else + goto Lambig; + } + + Lambig: // td_best and td are ambiguous + td_ambig = td; + continue; + + Ltd_best: // td_best is the best match so far + td_ambig = NULL; + continue; + + Ltd: // td is the new best match + td_ambig = NULL; + td_best = td; + m_best = m; + tdtypes.setDim(dedtypes.dim); + memcpy(tdtypes.tdata(), dedtypes.tdata(), tdtypes.dim * sizeof(void *)); + continue; + } + + if (!td_best) + { + if (tempdecl && !tempdecl->overnext) + // Only one template, so we can give better error message + error("%s does not match template declaration %s", toChars(), tempdecl->toChars()); + else + ::error(loc, "%s %s.%s does not match any template declaration", + tempdecl->kind(), tempdecl->parent->toPrettyChars(), tempdecl->ident->toChars()); + return NULL; + } + if (td_ambig) + { + ::error(loc, "%s %s.%s matches more than one template declaration, %s(%d):%s and %s(%d):%s", + td_best->kind(), td_best->parent->toPrettyChars(), td_best->ident->toChars(), + td_best->loc.filename, td_best->loc.linnum, td_best->toChars(), + td_ambig->loc.filename, td_ambig->loc.linnum, td_ambig->toChars()); + } + + /* The best match is td_best + */ + tempdecl = td_best; + +#if 0 + /* Cast any value arguments to be same type as value parameter + */ + for (size_t i = 0; i < tiargs->dim; i++) + { Object *o = tiargs->tdata()[i]; + Expression *ea = isExpression(o); // value argument + TemplateParameter *tp = tempdecl->parameters->tdata()[i]; + assert(tp); + TemplateValueParameter *tvp = tp->isTemplateValueParameter(); + if (tvp) + { + assert(ea); + ea = ea->castTo(tvp->valType); + ea = ea->optimize(WANTvalue | WANTinterpret); + tiargs->tdata()[i] = (Object *)ea; + } + } +#endif + +#if LOG + printf("\tIt's a match with template declaration '%s'\n", tempdecl->toChars()); +#endif + return tempdecl; +} + + +/***************************************** + * Determines if a TemplateInstance will need a nested + * generation of the TemplateDeclaration. + */ + +int TemplateInstance::hasNestedArgs(Objects *args) +{ int nested = 0; + //printf("TemplateInstance::hasNestedArgs('%s')\n", tempdecl->ident->toChars()); + + /* A nested instance happens when an argument references a local + * symbol that is on the stack. + */ + for (size_t i = 0; i < args->dim; i++) + { Object *o = args->tdata()[i]; + Expression *ea = isExpression(o); + Dsymbol *sa = isDsymbol(o); + Tuple *va = isTuple(o); + if (ea) + { + if (ea->op == TOKvar) + { + sa = ((VarExp *)ea)->var; + goto Lsa; + } + if (ea->op == TOKthis) + { + sa = ((ThisExp *)ea)->var; + goto Lsa; + } + if (ea->op == TOKfunction) + { + sa = ((FuncExp *)ea)->fd; + goto Lsa; + } + } + else if (sa) + { + Lsa: + TemplateDeclaration *td = sa->isTemplateDeclaration(); + Declaration *d = sa->isDeclaration(); + if ((td && td->literal) || + (d && !d->isDataseg() && +#if DMDV2 + !(d->storage_class & STCmanifest) && +#endif + (!d->isFuncDeclaration() || d->isFuncDeclaration()->isNested()) && + !isTemplateMixin() + )) + { + // if module level template + if (tempdecl->toParent()->isModule()) + { Dsymbol *dparent = sa->toParent(); + if (!isnested) + isnested = dparent; + else if (isnested != dparent) + { + /* Select the more deeply nested of the two. + * Error if one is not nested inside the other. + */ + for (Dsymbol *p = isnested; p; p = p->parent) + { + if (p == dparent) + goto L1; // isnested is most nested + } + for (Dsymbol *p = dparent; p; p = p->parent) + { + if (p == isnested) + { isnested = dparent; + goto L1; // dparent is most nested + } + } + error("%s is nested in both %s and %s", + toChars(), isnested->toChars(), dparent->toChars()); + } + L1: + //printf("\tnested inside %s\n", isnested->toChars()); + nested |= 1; + } + else + error("cannot use local '%s' as parameter to non-global template %s", sa->toChars(), tempdecl->toChars()); + } + } + else if (va) + { + nested |= hasNestedArgs(&va->objects); + } + } + return nested; +} + +/**************************************** + * This instance needs an identifier for name mangling purposes. + * Create one by taking the template declaration name and adding + * the type signature for it. + */ + +Identifier *TemplateInstance::genIdent(Objects *args) +{ OutBuffer buf; + + //printf("TemplateInstance::genIdent('%s')\n", tempdecl->ident->toChars()); + char *id = tempdecl->ident->toChars(); + buf.printf("__T%llu%s", (ulonglong)strlen(id), id); + for (size_t i = 0; i < args->dim; i++) + { Object *o = args->tdata()[i]; + Type *ta = isType(o); + Expression *ea = isExpression(o); + Dsymbol *sa = isDsymbol(o); + Tuple *va = isTuple(o); + //printf("\to [%d] %p ta %p ea %p sa %p va %p\n", i, o, ta, ea, sa, va); + if (ta) + { + buf.writeByte('T'); + if (ta->deco) + buf.writestring(ta->deco); + else + { +#ifdef DEBUG + if (!global.errors) + printf("ta = %d, %s\n", ta->ty, ta->toChars()); +#endif + assert(global.errors); + } + } + else if (ea) + { + // Don't interpret it yet, it might actually be an alias + ea = ea->optimize(WANTvalue); + if (ea->op == TOKvar) + { + sa = ((VarExp *)ea)->var; + ea = NULL; + goto Lsa; + } + if (ea->op == TOKthis) + { + sa = ((ThisExp *)ea)->var; + ea = NULL; + goto Lsa; + } + if (ea->op == TOKfunction) + { + sa = ((FuncExp *)ea)->fd; + ea = NULL; + goto Lsa; + } + buf.writeByte('V'); + if (ea->op == TOKtuple) + { ea->error("tuple is not a valid template value argument"); + continue; + } + // Now that we know it is not an alias, we MUST obtain a value + unsigned olderr = global.errors; + ea = ea->optimize(WANTvalue | WANTinterpret); + if (ea->op == TOKerror || olderr != global.errors) + continue; +#if 1 + /* Use deco that matches what it would be for a function parameter + */ + buf.writestring(ea->type->deco); +#else + // Use type of parameter, not type of argument + TemplateParameter *tp = tempdecl->parameters->tdata()[i]; + assert(tp); + TemplateValueParameter *tvp = tp->isTemplateValueParameter(); + assert(tvp); + buf.writestring(tvp->valType->deco); +#endif + ea->toMangleBuffer(&buf); + } + else if (sa) + { + Lsa: + buf.writeByte('S'); + Declaration *d = sa->isDeclaration(); + if (d && (!d->type || !d->type->deco)) + { error("forward reference of %s", d->toChars()); + continue; + } +#if 0 + VarDeclaration *v = sa->isVarDeclaration(); + if (v && v->storage_class & STCmanifest) + { ExpInitializer *ei = v->init->isExpInitializer(); + if (ei) + { + ea = ei->exp; + goto Lea; + } + } +#endif + const char *p = sa->mangle(); + + /* Bugzilla 3043: if the first character of p is a digit this + * causes ambiguity issues because the digits of the two numbers are adjacent. + * Current demanglers resolve this by trying various places to separate the + * numbers until one gets a successful demangle. + * Unfortunately, fixing this ambiguity will break existing binary + * compatibility and the demanglers, so we'll leave it as is. + */ + buf.printf("%llu%s", (ulonglong)strlen(p), p); + } + else if (va) + { + assert(i + 1 == args->dim); // must be last one + args = &va->objects; + i = -1; + } + else + assert(0); + } + buf.writeByte('Z'); + id = buf.toChars(); + //buf.data = NULL; // we can free the string after call to idPool() + //printf("\tgenIdent = %s\n", id); + return Lexer::idPool(id); +} + + +/**************************************************** + * Declare parameters of template instance, initialize them with the + * template instance arguments. + */ + +void TemplateInstance::declareParameters(Scope *sc) +{ + //printf("TemplateInstance::declareParameters()\n"); + for (size_t i = 0; i < tdtypes.dim; i++) + { + TemplateParameter *tp = tempdecl->parameters->tdata()[i]; + //Object *o = tiargs->tdata()[i]; + Object *o = tdtypes.tdata()[i]; // initializer for tp + + //printf("\ttdtypes[%d] = %p\n", i, o); + tempdecl->declareParameter(sc, tp, o); + } +} + +/***************************************************** + * Determine if template instance is really a template function, + * and that template function needs to infer types from the function + * arguments. + */ + +int TemplateInstance::needsTypeInference(Scope *sc) +{ + //printf("TemplateInstance::needsTypeInference() %s\n", toChars()); + if (!tempdecl) + tempdecl = findTemplateDeclaration(sc); + int multipleMatches = FALSE; + for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) + { + /* If any of the overloaded template declarations need inference, + * then return TRUE + */ + FuncDeclaration *fd; + if (!td->onemember || + (fd = td->onemember->toAlias()->isFuncDeclaration()) == NULL || + fd->type->ty != Tfunction) + { + /* Not a template function, therefore type inference is not possible. + */ + //printf("false\n"); + return FALSE; + } + + for (size_t i = 0; i < td->parameters->dim; i++) + if (td->parameters->tdata()[i]->isTemplateThisParameter()) + return TRUE; + + /* Determine if the instance arguments, tiargs, are all that is necessary + * to instantiate the template. + */ + //printf("tp = %p, td->parameters->dim = %d, tiargs->dim = %d\n", tp, td->parameters->dim, tiargs->dim); + TypeFunction *fdtype = (TypeFunction *)fd->type; + if (Parameter::dim(fdtype->parameters)) + { + TemplateParameter *tp = td->isVariadic(); + if (tp && td->parameters->dim > 1) + return TRUE; + + if (tiargs->dim < td->parameters->dim) + { // Can remain tiargs be filled by default arguments? + for (size_t i = tiargs->dim; i < td->parameters->dim; i++) + { tp = (*td->parameters)[i]; + if (TemplateTypeParameter *ttp = tp->isTemplateTypeParameter()) + { if (!ttp->defaultType) + return TRUE; + } + else if (TemplateAliasParameter *tap = tp->isTemplateAliasParameter()) + { if (!tap->defaultAlias) + return TRUE; + } + else if (TemplateValueParameter *tvp = tp->isTemplateValueParameter()) + { if (!tvp->defaultValue) + return TRUE; + } + } + } + } + /* If there is more than one function template which matches, we may + * need type inference (see Bugzilla 4430) + */ + if (td != tempdecl) + multipleMatches = TRUE; + } + //printf("false\n"); + return multipleMatches; +} + +void TemplateInstance::semantic2(Scope *sc) +{ int i; + + if (semanticRun >= PASSsemantic2) + return; + semanticRun = PASSsemantic2; +#if LOG + printf("+TemplateInstance::semantic2('%s')\n", toChars()); +#endif + if (!errors && members) + { + sc = tempdecl->scope; + assert(sc); + sc = sc->push(argsym); + sc = sc->push(this); + sc->tinst = this; + for (i = 0; i < members->dim; i++) + { + Dsymbol *s = members->tdata()[i]; +#if LOG +printf("\tmember '%s', kind = '%s'\n", s->toChars(), s->kind()); +#endif + s->semantic2(sc); + } + sc = sc->pop(); + sc->pop(); + } +#if LOG + printf("-TemplateInstance::semantic2('%s')\n", toChars()); +#endif +} + +void TemplateInstance::semantic3(Scope *sc) +{ +#if LOG + printf("TemplateInstance::semantic3('%s'), semanticRun = %d\n", toChars(), semanticRun); +#endif +//if (toChars()[0] == 'D') *(char*)0=0; + if (semanticRun >= PASSsemantic3) + return; + semanticRun = PASSsemantic3; + if (!errors && members) + { + sc = tempdecl->scope; + sc = sc->push(argsym); + sc = sc->push(this); + sc->tinst = this; + if (ignore) + sc->ignoreTemplates++; + int oldgag = global.gag; + int olderrors = global.errors; + /* If this is a speculative instantiation, gag errors. + * Future optimisation: If the results are actually needed, errors + * would already be gagged, so we don't really need to run semantic + * on the members. + */ + if (speculative && !oldgag) + olderrors = global.startGagging(); + for (size_t i = 0; i < members->dim; i++) + { + Dsymbol *s = members->tdata()[i]; + s->semantic3(sc); + if (speculative && global.errors != olderrors) + break; + } + if (speculative && !oldgag) + { // If errors occurred, this instantiation failed + errors += global.errors - olderrors; + global.endGagging(olderrors); + } + sc = sc->pop(); + sc->pop(); + } +} + +#if IN_DMD + +/************************************** + * Given an error instantiating the TemplateInstance, + * give the nested TemplateInstance instantiations that got + * us here. Those are a list threaded into the nested scopes. + */ +void TemplateInstance::printInstantiationTrace() +{ + if (global.gag) + return; + + const unsigned max_shown = 6; + const char format[] = "instantiated from here: %s"; + + // determine instantiation depth and number of recursive instantiations + int n_instantiations = 1; + int n_totalrecursions = 0; + for (TemplateInstance *cur = this; cur; cur = cur->tinst) + { + ++n_instantiations; + // If two instantiations use the same declaration, they are recursive. + // (this works even if they are instantiated from different places in the + // same template). + // In principle, we could also check for multiple-template recursion, but it's + // probably not worthwhile. + if (cur->tinst && cur->tempdecl && cur->tinst->tempdecl + && cur->tempdecl->loc.equals(cur->tinst->tempdecl->loc)) + ++n_totalrecursions; + } + + // show full trace only if it's short or verbose is on + if (n_instantiations <= max_shown || global.params.verbose) + { + for (TemplateInstance *cur = this; cur; cur = cur->tinst) + { + errorSupplemental(cur->loc, format, cur->toChars()); + } + } + else if (n_instantiations - n_totalrecursions <= max_shown) + { + // By collapsing recursive instantiations into a single line, + // we can stay under the limit. + int recursionDepth=0; + for (TemplateInstance *cur = this; cur; cur = cur->tinst) + { + if (cur->tinst && cur->tempdecl && cur->tinst->tempdecl + && cur->tempdecl->loc.equals(cur->tinst->tempdecl->loc)) + { + ++recursionDepth; + } + else + { + if (recursionDepth) + errorSupplemental(cur->loc, "%d recursive instantiations from here: %s", recursionDepth+2, cur->toChars()); + else + errorSupplemental(cur->loc, format, cur->toChars()); + recursionDepth = 0; + } + } + } + else + { + // Even after collapsing the recursions, the depth is too deep. + // Just display the first few and last few instantiations. + unsigned i = 0; + for (TemplateInstance *cur = this; cur; cur = cur->tinst) + { + if (i == max_shown / 2) + errorSupplemental(cur->loc, "... (%d instantiations, -v to show) ...", n_instantiations - max_shown); + + if (i < max_shown / 2 || + i >= n_instantiations - max_shown + max_shown / 2) + errorSupplemental(cur->loc, format, cur->toChars()); + ++i; + } + } +} + +void TemplateInstance::toObjFile(int multiobj) +{ +#if LOG + printf("TemplateInstance::toObjFile('%s', this = %p)\n", toChars(), this); +#endif + if (!errors && members) + { + if (multiobj) + // Append to list of object files to be written later + obj_append(this); + else + { + for (size_t i = 0; i < members->dim; i++) + { + Dsymbol *s = members->tdata()[i]; + s->toObjFile(multiobj); + } + } + } +} + +#endif + +void TemplateInstance::inlineScan() +{ +#if LOG + printf("TemplateInstance::inlineScan('%s')\n", toChars()); +#endif + if (!errors && members) + { + for (size_t i = 0; i < members->dim; i++) + { + Dsymbol *s = members->tdata()[i]; + s->inlineScan(); + } + } +} + +void TemplateInstance::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + int i; + + Identifier *id = name; + buf->writestring(id->toChars()); + buf->writestring("!("); + if (nest) + buf->writestring("..."); + else + { + nest++; + Objects *args = tiargs; + for (i = 0; i < args->dim; i++) + { + if (i) + buf->writeByte(','); + Object *oarg = (*args)[i]; + ObjectToCBuffer(buf, hgs, oarg); + } + nest--; + } + buf->writeByte(')'); +} + + +Dsymbol *TemplateInstance::toAlias() +{ +#if LOG + printf("TemplateInstance::toAlias()\n"); +#endif + if (!inst) + { + // Maybe we can resolve it + if (scope) + { + /* Anything that affects scope->offset must be + * done in lexical order. Fwd ref error if it is affected, otherwise allow. + */ + unsigned offset = scope->offset; + Scope *sc = scope; + semantic(scope); +// if (offset != sc->offset) +// inst = NULL; // trigger fwd ref error + } + if (!inst) + { error("cannot resolve forward reference"); + errors = 1; + return this; + } + } + + if (inst != this) + return inst->toAlias(); + + if (aliasdecl) + { + return aliasdecl->toAlias(); + } + + return inst; +} + +AliasDeclaration *TemplateInstance::isAliasDeclaration() +{ + return aliasdecl; +} + +const char *TemplateInstance::kind() +{ + return "template instance"; +} + +int TemplateInstance::oneMember(Dsymbol **ps, Identifier *ident) +{ + *ps = NULL; + return TRUE; +} + +char *TemplateInstance::toChars() +{ + OutBuffer buf; + HdrGenState hgs; + char *s; + + toCBuffer(&buf, &hgs); + s = buf.toChars(); + buf.data = NULL; + return s; +} + +#if IN_LLVM + +void TemplateInstance::printInstantiationTrace() +{ + if(global.gag) + return; + + const int max_shown = 6; + + // determine instantiation depth + int n_instantiations = 1; + TemplateInstance* cur = this; + while(cur = cur->tinst) + ++n_instantiations; + + // show full trace only if it's short or verbose is on + if(n_instantiations <= max_shown || global.params.verbose) + { + cur = this; + while(cur) + { + fprintf(stdmsg," instantiatied in %s: %s\n", cur->loc.toChars(), cur->toChars()); + cur = cur->tinst; + } + } + else + { + cur = this; + size_t i = 0; + for(; i < max_shown/2; ++i, cur = cur->tinst) + fprintf(stdmsg," instantiatied in %s: %s\n", cur->loc.toChars(), cur->toChars()); + fprintf(stdmsg," ... (%d instantiations, -v to show) ...\n", n_instantiations - max_shown); + for(; i < n_instantiations - max_shown + max_shown/2; ++i, cur = cur->tinst) + {} + for(; i < n_instantiations; ++i, cur = cur->tinst) + fprintf(stdmsg," instantiatied in %s: %s\n", cur->loc.toChars(), cur->toChars()); + } +} + +#endif + +/* ======================== TemplateMixin ================================ */ + +TemplateMixin::TemplateMixin(Loc loc, Identifier *ident, Type *tqual, + Identifiers *idents, Objects *tiargs) + : TemplateInstance(loc, idents->tdata()[idents->dim - 1]) +{ + //printf("TemplateMixin(ident = '%s')\n", ident ? ident->toChars() : ""); + this->ident = ident; + this->tqual = tqual; + this->idents = idents; + this->tiargs = tiargs ? tiargs : new Objects(); +} + +Dsymbol *TemplateMixin::syntaxCopy(Dsymbol *s) +{ TemplateMixin *tm; + + Identifiers *ids = new Identifiers(); + ids->setDim(idents->dim); + for (size_t i = 0; i < idents->dim; i++) + { // Matches TypeQualified::syntaxCopyHelper() + Identifier *id = idents->tdata()[i]; + if (id->dyncast() == DYNCAST_DSYMBOL) + { + TemplateInstance *ti = (TemplateInstance *)id; + + ti = (TemplateInstance *)ti->syntaxCopy(NULL); + id = (Identifier *)ti; + } + ids->tdata()[i] = id; + } + + tm = new TemplateMixin(loc, ident, + (Type *)(tqual ? tqual->syntaxCopy() : NULL), + ids, tiargs); + TemplateInstance::syntaxCopy(tm); + return tm; +} + +void TemplateMixin::semantic(Scope *sc) +{ +#if LOG + printf("+TemplateMixin::semantic('%s', this=%p)\n", toChars(), this); + fflush(stdout); +#endif + if (semanticRun) + { + // This for when a class/struct contains mixin members, and + // is done over because of forward references + if (parent && toParent()->isAggregateDeclaration()) + semanticRun = PASSsemantic; // do over + else + { +#if LOG + printf("\tsemantic done\n"); +#endif + return; + } + } + if (!semanticRun) + semanticRun = PASSsemantic; +#if LOG + printf("\tdo semantic\n"); +#endif + +#if !IN_LLVM && !IN_GCC + // dont know what this is + util_progress(); +#endif + + Scope *scx = NULL; + if (scope) + { sc = scope; + scx = scope; // save so we don't make redundant copies + scope = NULL; + } + + // Follow qualifications to find the TemplateDeclaration + if (!tempdecl) + { Dsymbol *s; + size_t i; + Identifier *id; + + if (tqual) + { s = tqual->toDsymbol(sc); + i = 0; + } + else + { + i = 1; + id = idents->tdata()[0]; + switch (id->dyncast()) + { + case DYNCAST_IDENTIFIER: + s = sc->search(loc, id, NULL); + break; + + case DYNCAST_DSYMBOL: + { + TemplateInstance *ti = (TemplateInstance *)id; + ti->semantic(sc); + s = ti; + break; + } + default: + assert(0); + } + } + + for (; i < idents->dim; i++) + { + if (!s) + break; + id = idents->tdata()[i]; + s = s->searchX(loc, sc, id); + } + if (!s) + { + error("is not defined"); + inst = this; + return; + } + tempdecl = s->toAlias()->isTemplateDeclaration(); + if (!tempdecl) + { + error("%s isn't a template", s->toChars()); + inst = this; + return; + } + } + + // Look for forward reference + assert(tempdecl); + for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) + { + if (!td->semanticRun) + { + /* Cannot handle forward references if mixin is a struct member, + * because addField must happen during struct's semantic, not + * during the mixin semantic. + * runDeferred will re-run mixin's semantic outside of the struct's + * semantic. + */ + semanticRun = PASSinit; + AggregateDeclaration *ad = toParent()->isAggregateDeclaration(); + if (ad) + ad->sizeok = SIZEOKfwd; + else + { + // Forward reference + //printf("forward reference - deferring\n"); + scope = scx ? scx : new Scope(*sc); + scope->setNoFree(); + scope->module->addDeferredSemantic(this); + } + return; + } + } + + // Run semantic on each argument, place results in tiargs[] + semanticTiargs(sc); + if (errors || arrayObjectIsError(tiargs)) + return; + + tempdecl = findBestMatch(sc, NULL); + if (!tempdecl) + { inst = this; + return; // error recovery + } + + if (!ident) + ident = genIdent(tiargs); + + inst = this; + parent = sc->parent; + + /* Detect recursive mixin instantiations. + */ + for (Dsymbol *s = parent; s; s = s->parent) + { + //printf("\ts = '%s'\n", s->toChars()); + TemplateMixin *tm = s->isTemplateMixin(); + if (!tm || tempdecl != tm->tempdecl) + continue; + + /* Different argument list lengths happen with variadic args + */ + if (tiargs->dim != tm->tiargs->dim) + continue; + + for (size_t i = 0; i < tiargs->dim; i++) + { Object *o = (*tiargs)[i]; + Type *ta = isType(o); + Expression *ea = isExpression(o); + Dsymbol *sa = isDsymbol(o); + Object *tmo = (*tm->tiargs)[i]; + if (ta) + { + Type *tmta = isType(tmo); + if (!tmta) + goto Lcontinue; + if (!ta->equals(tmta)) + goto Lcontinue; + } + else if (ea) + { Expression *tme = isExpression(tmo); + if (!tme || !ea->equals(tme)) + goto Lcontinue; + } + else if (sa) + { + Dsymbol *tmsa = isDsymbol(tmo); + if (sa != tmsa) + goto Lcontinue; + } + else + assert(0); + } + error("recursive mixin instantiation"); + return; + + Lcontinue: + continue; + } + + // Copy the syntax trees from the TemplateDeclaration + members = Dsymbol::arraySyntaxCopy(tempdecl->members); + if (!members) + return; + + symtab = new DsymbolTable(); + + for (Scope *sce = sc; 1; sce = sce->enclosing) + { + ScopeDsymbol *sds = (ScopeDsymbol *)sce->scopesym; + if (sds) + { + sds->importScope(this, PROTpublic); + break; + } + } + +#if LOG + printf("\tcreate scope for template parameters '%s'\n", toChars()); +#endif + Scope *scy = sc; + scy = sc->push(this); + scy->parent = this; + + argsym = new ScopeDsymbol(); + argsym->parent = scy->parent; + Scope *argscope = scy->push(argsym); + + unsigned errorsave = global.errors; + + // Declare each template parameter as an alias for the argument type + declareParameters(argscope); + + // Add members to enclosing scope, as well as this scope + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *s = (*members)[i]; + s->addMember(argscope, this, i); + //sc->insert(s); + //printf("sc->parent = %p, sc->scopesym = %p\n", sc->parent, sc->scopesym); + //printf("s->parent = %s\n", s->parent->toChars()); + } + + // Do semantic() analysis on template instance members +#if LOG + printf("\tdo semantic() on template instance members '%s'\n", toChars()); +#endif + Scope *sc2; + sc2 = argscope->push(this); + sc2->offset = sc->offset; + + static int nest; + //printf("%d\n", nest); + if (++nest > 500) + { + global.gag = 0; // ensure error message gets printed + error("recursive expansion"); + fatal(); + } + + for (size_t i = 0; i < members->dim; i++) + { + Dsymbol *s = (*members)[i]; + s->semantic(sc2); + } + + nest--; + + sc->offset = sc2->offset; + + /* The problem is when to parse the initializer for a variable. + * Perhaps VarDeclaration::semantic() should do it like it does + * for initializers inside a function. + */ +// if (sc->parent->isFuncDeclaration()) + + semantic2(sc2); + + if (sc->func) + { + semantic3(sc2); + } + + // Give additional context info if error occurred during instantiation + if (global.errors != errorsave) + { + error("error instantiating"); + } + + sc2->pop(); + + argscope->pop(); + +// if (!isAnonymous()) + { + scy->pop(); + } +#if LOG + printf("-TemplateMixin::semantic('%s', this=%p)\n", toChars(), this); +#endif +} + +void TemplateMixin::semantic2(Scope *sc) +{ + if (semanticRun >= PASSsemantic2) + return; + semanticRun = PASSsemantic2; +#if LOG + printf("+TemplateMixin::semantic2('%s')\n", toChars()); +#endif + if (members) + { + assert(sc); + sc = sc->push(argsym); + sc = sc->push(this); + for (size_t i = 0; i < members->dim; i++) + { + Dsymbol *s = (*members)[i]; +#if LOG + printf("\tmember '%s', kind = '%s'\n", s->toChars(), s->kind()); +#endif + s->semantic2(sc); + } + sc = sc->pop(); + sc->pop(); + } +#if LOG + printf("-TemplateMixin::semantic2('%s')\n", toChars()); +#endif +} + +void TemplateMixin::semantic3(Scope *sc) +{ + if (semanticRun >= PASSsemantic3) + return; + semanticRun = PASSsemantic3; +#if LOG + printf("TemplateMixin::semantic3('%s')\n", toChars()); +#endif + if (members) + { + sc = sc->push(argsym); + sc = sc->push(this); + for (size_t i = 0; i < members->dim; i++) + { + Dsymbol *s = members->tdata()[i]; + s->semantic3(sc); + } + sc = sc->pop(); + sc->pop(); + } +} + +void TemplateMixin::inlineScan() +{ + TemplateInstance::inlineScan(); +} + +const char *TemplateMixin::kind() +{ + return "mixin"; +} + +int TemplateMixin::oneMember(Dsymbol **ps, Identifier *ident) +{ + return Dsymbol::oneMember(ps, ident); +} + +int TemplateMixin::apply(Dsymbol_apply_ft_t fp, void *param) +{ + if (members) + { + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *s = (*members)[i]; + if (s) + { + if (s->apply(fp, param)) + return 1; + } + } + } + return 0; +} + +int TemplateMixin::hasPointers() +{ + //printf("TemplateMixin::hasPointers() %s\n", toChars()); + + if (members) + for (size_t i = 0; i < members->dim; i++) + { + Dsymbol *s = (*members)[i]; + //printf(" s = %s %s\n", s->kind(), s->toChars()); + if (s->hasPointers()) + { + return 1; + } + } + return 0; +} + +void TemplateMixin::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion) +{ + if (members) + { + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *s = (*members)[i]; + s->setFieldOffset(ad, poffset, isunion); + } + } +} + +char *TemplateMixin::toChars() +{ + OutBuffer buf; + HdrGenState hgs; + char *s; + + TemplateInstance::toCBuffer(&buf, &hgs); + s = buf.toChars(); + buf.data = NULL; + return s; +} + +void TemplateMixin::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("mixin "); + + for (size_t i = 0; i < idents->dim; i++) + { Identifier *id = idents->tdata()[i]; + + if (i) + buf->writeByte('.'); + buf->writestring(id->toChars()); + } + buf->writestring("!("); + if (tiargs) + { + for (size_t i = 0; i < tiargs->dim; i++) + { if (i) + buf->writebyte(','); + Object *oarg = tiargs->tdata()[i]; + Type *t = isType(oarg); + Expression *e = isExpression(oarg); + Dsymbol *s = isDsymbol(oarg); + if (t) + t->toCBuffer(buf, NULL, hgs); + else if (e) + e->toCBuffer(buf, hgs); + else if (s) + { + char *p = s->ident ? s->ident->toChars() : s->toChars(); + buf->writestring(p); + } + else if (!oarg) + { + buf->writestring("NULL"); + } + else + { + assert(0); + } + } + } + buf->writebyte(')'); + if (ident) + { + buf->writebyte(' '); + buf->writestring(ident->toChars()); + } + buf->writebyte(';'); + buf->writenl(); +} + + +#if IN_DMD +void TemplateMixin::toObjFile(int multiobj) +{ + //printf("TemplateMixin::toObjFile('%s')\n", toChars()); + TemplateInstance::toObjFile(multiobj); +} +#endif + diff --git a/dmd2/total.h b/dmd2/total.h index 1a0c9a89..42f38765 100644 --- a/dmd2/total.h +++ b/dmd2/total.h @@ -1,46 +1,46 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2006 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_TOTAL_H -#define DMD_TOTAL_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include -#include -#include -#include -#include - -#include "root.h" -#include "stringtable.h" - -#include "arraytypes.h" -#include "mars.h" -#include "lexer.h" -#include "parse.h" -#include "identifier.h" -#include "enum.h" -#include "aggregate.h" -#include "mtype.h" -#include "expression.h" -#include "declaration.h" -#include "statement.h" -#include "scope.h" -#include "import.h" -#include "module.h" -#include "id.h" -#include "cond.h" -#include "version.h" -#include "lib.h" - -#endif /* DMD_TOTAL_H */ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2006 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#ifndef DMD_TOTAL_H +#define DMD_TOTAL_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +#include +#include +#include +#include +#include + +#include "root.h" +#include "stringtable.h" + +#include "arraytypes.h" +#include "mars.h" +#include "lexer.h" +#include "parse.h" +#include "identifier.h" +#include "enum.h" +#include "aggregate.h" +#include "mtype.h" +#include "expression.h" +#include "declaration.h" +#include "statement.h" +#include "scope.h" +#include "import.h" +#include "module.h" +#include "id.h" +#include "cond.h" +#include "version.h" +#include "lib.h" + +#endif /* DMD_TOTAL_H */ From 837ef30fec72471fee199b6453d127f2c7ce5ad7 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 26 Aug 2012 21:10:13 +0200 Subject: [PATCH 02/33] Merged DMD 2.060 frontend. Upstream Git tag v2.060 (e8fe11c20249cb9e42538be88c99b74ede4d12e3). --- dmd2/aggregate.h | 15 +- dmd2/aliasthis.c | 24 ++ dmd2/argtypes.c | 272 ++++++++++++- dmd2/arrayop.c | 24 +- dmd2/attrib.c | 79 ++-- dmd2/attrib.h | 7 +- dmd2/builtin.c | 10 +- dmd2/canthrow.c | 7 +- dmd2/cast.c | 140 +++++-- dmd2/class.c | 111 ++--- dmd2/clone.c | 32 +- dmd2/cond.c | 10 +- dmd2/constfold.c | 67 ++- dmd2/cppmangle.c | 11 +- dmd2/declaration.c | 178 +++++--- dmd2/declaration.h | 20 +- dmd2/dmd_msc.vcproj | 112 +++-- dmd2/doc.c | 17 +- dmd2/dsymbol.c | 41 +- dmd2/dsymbol.h | 3 +- dmd2/dump.c | 4 +- dmd2/enum.c | 20 +- dmd2/enum.h | 2 +- dmd2/expression.c | 880 ++++++++++++++++++++++++---------------- dmd2/expression.h | 20 +- dmd2/func.c | 589 ++++++++++++++------------- dmd2/hdrgen.c | 2 +- dmd2/hdrgen.h | 1 + dmd2/idgen.c | 4 +- dmd2/import.c | 42 +- dmd2/inifile.c | 6 +- dmd2/init.c | 77 +++- dmd2/init.h | 14 +- dmd2/inline.c | 96 ++++- dmd2/interpret.c | 803 ++++++++++++++++++++++++++---------- dmd2/intrange.h | 12 +- dmd2/json.c | 18 +- dmd2/lexer.c | 199 ++------- dmd2/lexer.h | 4 +- dmd2/lib.h | 54 +-- dmd2/mars.c | 80 ++-- dmd2/mars.h | 18 +- dmd2/module.c | 97 ++--- dmd2/module.h | 3 - dmd2/mtype.c | 476 +++++++++++++--------- dmd2/mtype.h | 17 +- dmd2/opover.c | 151 ++++--- dmd2/optimize.c | 33 +- dmd2/parse.c | 43 +- dmd2/readme.txt | 4 +- dmd2/root/aav.c | 9 + dmd2/root/aav.h | 8 + dmd2/root/array.c | 1 - dmd2/root/async.c | 8 + dmd2/root/dchar.c | 482 ---------------------- dmd2/root/dchar.h | 194 --------- dmd2/root/gnuc.c | 8 + dmd2/root/gnuc.h | 8 + dmd2/root/lstring.c | 63 --- dmd2/root/lstring.h | 74 ---- dmd2/root/response.c | 19 +- dmd2/root/rmem.c | 9 +- dmd2/root/rmem.h | 8 +- dmd2/root/root.c | 118 +----- dmd2/root/root.h | 10 - dmd2/root/speller.c | 8 + dmd2/root/speller.h | 8 + dmd2/root/stringtable.c | 92 ++++- dmd2/root/stringtable.h | 41 +- dmd2/scope.c | 1 + dmd2/scope.h | 4 +- dmd2/statement.c | 248 +++++++---- dmd2/statement.h | 8 +- dmd2/staticassert.c | 12 +- dmd2/struct.c | 160 ++++++-- dmd2/template.c | 688 +++++++++++++++++++------------ dmd2/traits.c | 32 +- dmd2/unialpha.c | 323 --------------- dmd2/unittests.c | 8 + dmd2/utf.c | 465 +++++++++++---------- dmd2/utf.h | 109 ++++- driver/main.cpp | 10 +- runtime/CMakeLists.txt | 2 +- runtime/druntime | 2 +- runtime/phobos | 2 +- 85 files changed, 4411 insertions(+), 3780 deletions(-) delete mode 100644 dmd2/root/dchar.c delete mode 100644 dmd2/root/dchar.h delete mode 100644 dmd2/root/lstring.c delete mode 100644 dmd2/root/lstring.h delete mode 100644 dmd2/unialpha.c diff --git a/dmd2/aggregate.h b/dmd2/aggregate.h index 46af2b3d..6deae43e 100644 --- a/dmd2/aggregate.h +++ b/dmd2/aggregate.h @@ -67,7 +67,6 @@ struct AggregateDeclaration : ScopeDsymbol Type *handle; // 'this' type unsigned structsize; // size of struct unsigned alignsize; // size of struct for alignment purposes - unsigned structalign; // struct member alignment in effect int hasUnions; // set if aggregate has overlapping fields VarDeclarations fields; // VarDeclaration fields enum Sizeok sizeok; // set when structsize contains valid data @@ -96,17 +95,18 @@ struct AggregateDeclaration : ScopeDsymbol #ifdef IN_GCC Expressions *attributes; // GCC decl/type attributes - FuncDeclarations methods; // flat list of all methods for debug information #endif + Expression *getRTInfo; // pointer to GC info generated by object.RTInfo(this) + AggregateDeclaration(Loc loc, Identifier *id); void semantic2(Scope *sc); void semantic3(Scope *sc); void inlineScan(); unsigned size(Loc loc); - static void alignmember(unsigned salign, unsigned size, unsigned *poffset); + static void alignmember(structalign_t salign, unsigned size, unsigned *poffset); static unsigned placeField(unsigned *nextoffset, - unsigned memsize, unsigned memalignsize, unsigned memalign, + unsigned memsize, unsigned memalignsize, structalign_t memalign, unsigned *paggsize, unsigned *paggalignsize, bool isunion); Type *getType(); int firstFieldInUnion(int indx); // first field in union that includes indx @@ -165,8 +165,14 @@ struct StructDeclaration : AggregateDeclaration FuncDeclaration *xeq; // TypeInfo_Struct.xopEquals static FuncDeclaration *xerreq; // object.xopEquals + + structalign_t alignment; // alignment applied outside of the struct #endif + // For 64 bit Efl function call/return ABI + Type *arg1type; + Type *arg2type; + StructDeclaration(Loc loc, Identifier *id); Dsymbol *syntaxCopy(Dsymbol *s); void semantic(Scope *sc); @@ -175,6 +181,7 @@ struct StructDeclaration : AggregateDeclaration char *mangle(); const char *kind(); void finalizeSize(Scope *sc); + bool isPOD(); #if DMDV1 Expression *cloneMembers(); #endif diff --git a/dmd2/aliasthis.c b/dmd2/aliasthis.c index 0f6ff452..b26731b9 100644 --- a/dmd2/aliasthis.c +++ b/dmd2/aliasthis.c @@ -18,6 +18,7 @@ #include "aggregate.h" #include "dsymbol.h" #include "mtype.h" +#include "declaration.h" #if DMDV2 @@ -78,9 +79,32 @@ void AliasThis::semantic(Scope *sc) ::error(loc, "%s is not a member of %s", s->toChars(), ad->toChars()); else ::error(loc, "undefined identifier %s", ident->toChars()); + return; } else if (ad->aliasthis && s != ad->aliasthis) error("there can be only one alias this"); + + /* disable the alias this conversion so the implicit conversion check + * doesn't use it. + */ + /* This should use ad->aliasthis directly, but with static foreach and templates + * ad->type->sym might be different to ad. + */ + AggregateDeclaration *ad2 = ad->type->toDsymbol(NULL)->isAggregateDeclaration(); + Dsymbol *save = ad2->aliasthis; + ad2->aliasthis = NULL; + + if (Declaration *d = s->isDeclaration()) + { + Type *t = d->type; + assert(t); + if (ad->type->implicitConvTo(t)) + { + ::error(loc, "alias this is not reachable as %s already converts to %s", ad->toChars(), t->toChars()); + } + } + + ad2->aliasthis = save; ad->aliasthis = s; } else diff --git a/dmd2/argtypes.c b/dmd2/argtypes.c index 3f1d3620..ffa38a86 100644 --- a/dmd2/argtypes.c +++ b/dmd2/argtypes.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 2010-2011 by Digital Mars +// Copyright (c) 2010-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -27,6 +27,9 @@ #include "aggregate.h" #include "hdrgen.h" +#define tfloat2 tfloat64 +//#define tfloat2 tcomplex32 + /**************************************************** * This breaks a type down into 'simpler' types that can be passed to a function * in registers, and returned in registers. @@ -40,6 +43,10 @@ TypeTuple *Type::toArgTypes() return NULL; // not valid for a parameter } +TypeTuple *TypeError::toArgTypes() +{ + return new TypeTuple(Type::terror); +} TypeTuple *TypeBasic::toArgTypes() { Type *t1 = NULL; @@ -78,7 +85,7 @@ TypeTuple *TypeBasic::toArgTypes() case Tcomplex32: if (global.params.is64bit) - t1 = Type::tfloat64; // weird, eh? + t1 = Type::tfloat2; else { t1 = Type::tfloat64; @@ -124,23 +131,39 @@ TypeTuple *TypeBasic::toArgTypes() return t; } +#if DMDV2 TypeTuple *TypeVector::toArgTypes() { - return new TypeTuple(Type::tfloat64); + return new TypeTuple(this); } +#endif TypeTuple *TypeSArray::toArgTypes() { #if DMDV2 + if (dim) + { + /* Should really be done as if it were a struct with dim members + * of the array's elements. + * I.e. int[2] should be done like struct S { int a; int b; } + */ + dinteger_t sz = dim->toInteger(); + if (sz == 1) + // T[1] should be passed like T + return next->toArgTypes(); + } return new TypeTuple(); // pass on the stack for efficiency #else - return new TypeTuple(Type::tvoidptr); + return new TypeTuple(); // pass on the stack for efficiency #endif } TypeTuple *TypeDArray::toArgTypes() { - return new TypeTuple(); // pass on the stack for efficiency + /* Should be done as if it were: + * struct S { size_t length; void* ptr; } + */ + return new TypeTuple(Type::tsize_t, Type::tvoidptr); } TypeTuple *TypeAArray::toArgTypes() @@ -150,30 +173,255 @@ TypeTuple *TypeAArray::toArgTypes() TypeTuple *TypePointer::toArgTypes() { - return new TypeTuple(this); + return new TypeTuple(Type::tvoidptr); } TypeTuple *TypeDelegate::toArgTypes() { - return new TypeTuple(); // pass on the stack for efficiency + /* Should be done as if it were: + * struct S { void* ptr; void* funcptr; } + */ + return new TypeTuple(Type::tvoidptr, Type::tvoidptr); +} + +/************************************* + * Convert a floating point type into the equivalent integral type. + */ + +Type *mergeFloatToInt(Type *t) +{ + switch (t->ty) + { + case Tfloat32: + case Timaginary32: + t = Type::tint32; + break; + case Tfloat64: + case Timaginary64: + case Tcomplex32: + t = Type::tint64; + break; + default: +#ifdef DEBUG + printf("mergeFloatToInt() %s\n", t->toChars()); +#endif + assert(0); + } + return t; +} + +/************************************* + * This merges two types into an 8byte type. + */ + +Type *argtypemerge(Type *t1, Type *t2, unsigned offset2) +{ + //printf("argtypemerge(%s, %s, %d)\n", t1 ? t1->toChars() : "", t2 ? t2->toChars() : "", offset2); + if (!t1) + { assert(!t2 || offset2 == 0); + return t2; + } + if (!t2) + return t1; + + unsigned sz1 = t1->size(0); + unsigned sz2 = t2->size(0); + + if (t1->ty != t2->ty && + (t1->ty == Tfloat80 || t2->ty == Tfloat80)) + return NULL; + + // [float,float] => [cfloat] + if (t1->ty == Tfloat32 && t2->ty == Tfloat32 && offset2 == 4) + return Type::tfloat2; + + // Merging floating and non-floating types produces the non-floating type + if (t1->isfloating()) + { + if (!t2->isfloating()) + t1 = mergeFloatToInt(t1); + } + else if (t2->isfloating()) + t2 = mergeFloatToInt(t2); + + Type *t; + + // Pick type with larger size + if (sz1 < sz2) + t = t2; + else + t = t1; + + // If t2 does not lie within t1, need to increase the size of t to enclose both + if (offset2 && sz1 < offset2 + sz2) + { + switch (offset2 + sz2) + { + case 2: + t = Type::tint16; + break; + case 3: + case 4: + t = Type::tint32; + break; + case 5: + case 6: + case 7: + case 8: + t = Type::tint64; + break; + default: + assert(0); + } + } + return t; } TypeTuple *TypeStruct::toArgTypes() { + //printf("TypeStruct::toArgTypes() %s\n", toChars()); + if (!sym->isPOD()) + { + Lmemory: + //printf("\ttoArgTypes() %s => [ ]\n", toChars()); + return new TypeTuple(); // pass on the stack + } + Type *t1 = NULL; + Type *t2 = NULL; d_uns64 sz = size(0); assert(sz < 0xFFFFFFFF); switch ((unsigned)sz) { case 1: - return new TypeTuple(Type::tint8); + t1 = Type::tint8; + break; case 2: - return new TypeTuple(Type::tint16); + t1 = Type::tint16; + break; case 4: - return new TypeTuple(Type::tint32); + t1 = Type::tint32; + break; case 8: - return new TypeTuple(Type::tint64); + t1 = Type::tint64; + break; + case 16: + t1 = NULL; // could be a TypeVector + break; + default: + goto Lmemory; } - return new TypeTuple(); // pass on the stack + if (global.params.is64bit && sym->fields.dim) + { +#if 1 + unsigned sz1 = 0; + unsigned sz2 = 0; + t1 = NULL; + for (size_t i = 0; i < sym->fields.dim; i++) + { VarDeclaration *f = sym->fields[i]; + //printf("f->type = %s\n", f->type->toChars()); + + TypeTuple *tup = f->type->toArgTypes(); + if (!tup) + goto Lmemory; + size_t dim = tup->arguments->dim; + Type *ft1 = NULL; + Type *ft2 = NULL; + switch (dim) + { + case 2: + ft1 = (*tup->arguments)[0]->type; + ft2 = (*tup->arguments)[1]->type; + break; + case 1: + if (f->offset < 8) + ft1 = (*tup->arguments)[0]->type; + else + ft2 = (*tup->arguments)[0]->type; + break; + default: + goto Lmemory; + } + + if (f->offset & 7) + { + // Misaligned fields goto Lmemory + unsigned alignsz = f->type->alignsize(); + if (f->offset & (alignsz - 1)) + goto Lmemory; + + // Fields that overlap the 8byte boundary goto Lmemory + unsigned fieldsz = f->type->size(0); + if (f->offset < 8 && (f->offset + fieldsz) > 8) + goto Lmemory; + } + + // First field in 8byte must be at start of 8byte + assert(t1 || f->offset == 0); + + if (ft1) + { + t1 = argtypemerge(t1, ft1, f->offset); + if (!t1) + goto Lmemory; + } + + if (ft2) + { + unsigned off2 = f->offset; + if (ft1) + off2 = 8; + assert(t2 || off2 == 8); + t2 = argtypemerge(t2, ft2, off2 - 8); + if (!t2) + goto Lmemory; + } + } + + if (t2) + { + if (t1->isfloating() && t2->isfloating()) + { + if (t1->ty == Tfloat64 && t2->ty == Tfloat64) + ; + else + goto Lmemory; + } + else if (t1->isfloating()) + goto Lmemory; + else if (t2->isfloating()) + goto Lmemory; + else + ; + } +#else + if (sym->fields.dim == 1) + { VarDeclaration *f = sym->fields[0]; + //printf("f->type = %s\n", f->type->toChars()); + TypeTuple *tup = f->type->toArgTypes(); + if (tup) + { + size_t dim = tup->arguments->dim; + if (dim == 1) + t1 = (*tup->arguments)[0]->type; + } + } +#endif + } + + //printf("\ttoArgTypes() %s => [%s,%s]\n", toChars(), t1 ? t1->toChars() : "", t2 ? t2->toChars() : ""); + + TypeTuple *t; + if (t1) + { + //if (t1) printf("test1: %s => %s\n", toChars(), t1->toChars()); + if (t2) + t = new TypeTuple(t1, t2); + else + t = new TypeTuple(t1); + } + else + goto Lmemory; + return t; } TypeTuple *TypeEnum::toArgTypes() diff --git a/dmd2/arrayop.c b/dmd2/arrayop.c index ed685c18..bac8391a 100644 --- a/dmd2/arrayop.c +++ b/dmd2/arrayop.c @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2011 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -142,7 +142,6 @@ Expression *BinExp::arrayOp(Scope *sc) buf.writestring(type->toBasetype()->nextOf()->toBasetype()->deco); #endif - size_t namelen = buf.offset; buf.writeByte(0); char *name = buf.toChars(); Identifier *ident = Lexer::idPool(name); @@ -349,7 +348,7 @@ Expression *BinExp::arrayOp(Scope *sc) Initializer *init = new ExpInitializer(0, new IntegerExp(0, 0, Type::tsize_t)); Dsymbol *d = new VarDeclaration(0, Type::tsize_t, Id::p, init); Statement *s1 = new ForStatement(0, - new DeclarationStatement(0, d), + new ExpStatement(0, d), new CmpExp(TOKlt, 0, new IdentifierExp(0, Id::p), new ArrayLengthExp(0, new IdentifierExp(0, p->ident))), new PostExp(TOKplusplus, 0, new IdentifierExp(0, Id::p)), new ExpStatement(0, loopbody)); @@ -357,7 +356,7 @@ Expression *BinExp::arrayOp(Scope *sc) // foreach (i; 0 .. p.length) Statement *s1 = new ForeachRangeStatement(0, TOKforeach, new Parameter(0, NULL, Id::p, NULL), - new IntegerExp(0, 0, Type::tint32), + new IntegerExp(0, 0, Type::tsize_t), new ArrayLengthExp(0, new IdentifierExp(0, p->ident)), new ExpStatement(0, loopbody)); #endif @@ -413,6 +412,23 @@ Expression *BinExp::arrayOp(Scope *sc) return e; } +Expression *BinAssignExp::arrayOp(Scope *sc) +{ + //printf("BinAssignExp::arrayOp() %s\n", toChars()); + + /* Check that the elements of e1 can be assigned to + */ + Type *tn = e1->type->toBasetype()->nextOf(); + + if (tn && (!tn->isMutable() || !tn->isAssignable())) + { + error("slice %s is not mutable", e1->toChars()); + return new ErrorExp(); + } + + return BinExp::arrayOp(sc); +} + /****************************************** * Construct the identifier for the array operation function, * and build the argument list to pass to it. diff --git a/dmd2/attrib.c b/dmd2/attrib.c index 776565d0..a21213f9 100644 --- a/dmd2/attrib.c +++ b/dmd2/attrib.c @@ -11,6 +11,7 @@ #include #include #include +#include // memcpy() #include "rmem.h" @@ -37,7 +38,7 @@ extern void obj_includelib(const char *name); #if IN_DMD -void obj_startaddress(Symbol *s); +bool obj_startaddress(Symbol *s); #endif @@ -90,7 +91,7 @@ int AttribDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) void AttribDeclaration::setScopeNewSc(Scope *sc, StorageClass stc, enum LINK linkage, enum PROT protection, int explicitProtection, - unsigned structalign) + structalign_t structalign) { if (decl) { @@ -125,7 +126,7 @@ void AttribDeclaration::setScopeNewSc(Scope *sc, void AttribDeclaration::semanticNewSc(Scope *sc, StorageClass stc, enum LINK linkage, enum PROT protection, int explicitProtection, - unsigned structalign) + structalign_t structalign) { if (decl) { @@ -760,7 +761,10 @@ void AlignDeclaration::semantic(Scope *sc) void AlignDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { - buf->printf("align (%d)", salign); + if (salign == STRUCTALIGN_DEFAULT) + buf->printf("align"); + else + buf->printf("align (%d)", salign); AttribDeclaration::toCBuffer(buf, hgs); } @@ -938,7 +942,7 @@ void PragmaDeclaration::setScope(Scope *sc) { Expression *e = (*args)[0]; e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); (*args)[0] = e; StringExp* se = e->toString(); if (!se) @@ -977,8 +981,8 @@ void PragmaDeclaration::semantic(Scope *sc) Expression *e = (*args)[i]; e = e->semantic(sc); - if (e->op != TOKerror) - e = e->optimize(WANTvalue | WANTinterpret); + if (e->op != TOKerror && e->op != TOKtype) + e = e->ctfeInterpret(); if (e->op == TOKerror) { errorSupplemental(loc, "while evaluating pragma(msg, %s)", (*args)[i]->toChars()); return; @@ -1004,7 +1008,7 @@ void PragmaDeclaration::semantic(Scope *sc) Expression *e = (*args)[0]; e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); (*args)[0] = e; if (e->op == TOKerror) goto Lnodecl; @@ -1022,7 +1026,7 @@ void PragmaDeclaration::semantic(Scope *sc) } goto Lnodecl; } -#if IN_GCC +#ifdef IN_GCC else if (ident == Id::GNU_asm) { if (! args || args->dim != 2) @@ -1046,7 +1050,7 @@ void PragmaDeclaration::semantic(Scope *sc) e = (*args)[1]; e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); e = e->toString(); if (e && ((StringExp *)e)->sz == 1) s = ((StringExp *)e); @@ -1068,7 +1072,7 @@ void PragmaDeclaration::semantic(Scope *sc) { Expression *e = (*args)[0]; e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); (*args)[0] = e; Dsymbol *sa = getDsymbol(e); if (!sa || !sa->isFuncDeclaration()) @@ -1105,7 +1109,7 @@ void PragmaDeclaration::semantic(Scope *sc) unsigned errors_save = global.errors; e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); if (i == 0) printf(" ("); else @@ -1175,21 +1179,19 @@ void PragmaDeclaration::toObjFile(int multiobj) char *name = (char *)mem.malloc(se->len + 1); memcpy(name, se->string, se->len); name[se->len] = 0; -#if OMFOBJ - /* The OMF format allows library names to be inserted - * into the object file. The linker will then automatically + + /* Embed the library names into the object file. + * The linker will then automatically * search that library, too. */ - obj_includelib(name); -#elif ELFOBJ || MACHOBJ - /* The format does not allow embedded library names, - * so instead append the library name to the list to be passed - * to the linker. - */ - global.params.libfiles->push(name); -#else - error("pragma lib not supported"); -#endif + if (!obj_includelib(name)) + { + /* The format does not allow embedded library names, + * so instead append the library name to the list to be passed + * to the linker. + */ + global.params.libfiles->push(name); + } } #if DMDV2 else if (ident == Id::startaddress) @@ -1406,6 +1408,31 @@ Dsymbol *StaticIfDeclaration::syntaxCopy(Dsymbol *s) return dd; } +Dsymbols *StaticIfDeclaration::include(Scope *sc, ScopeDsymbol *sd) +{ + //printf("StaticIfDeclaration::include(sc = %p) scope = %p\n", sc, scope); + + if (condition->inc == 0) + { + Dsymbols *d = ConditionalDeclaration::include(sc, sd); + + // Set the scopes lazily. + if (scope && d) + { + for (size_t i = 0; i < d->dim; i++) + { + Dsymbol *s = (*d)[i]; + + s->setScope(sc); + } + } + return d; + } + else + { + return ConditionalDeclaration::include(sc, sd); + } +} int StaticIfDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) { @@ -1512,7 +1539,7 @@ void CompileDeclaration::compileIt(Scope *sc) //printf("CompileDeclaration::compileIt(loc = %d) %s\n", loc.linnum, exp->toChars()); exp = exp->semantic(sc); exp = resolveProperties(sc, exp); - exp = exp->optimize(WANTvalue | WANTinterpret); + exp = exp->ctfeInterpret(); StringExp *se = exp->toString(); if (!se) { exp->error("argument to mixin must be a string, not (%s)", exp->toChars()); diff --git a/dmd2/attrib.h b/dmd2/attrib.h index 6762d338..aa8d0447 100644 --- a/dmd2/attrib.h +++ b/dmd2/attrib.h @@ -37,10 +37,10 @@ struct AttribDeclaration : Dsymbol int addMember(Scope *sc, ScopeDsymbol *s, int memnum); void setScopeNewSc(Scope *sc, StorageClass newstc, enum LINK linkage, enum PROT protection, int explictProtection, - unsigned structalign); + structalign_t structalign); void semanticNewSc(Scope *sc, StorageClass newstc, enum LINK linkage, enum PROT protection, int explictProtection, - unsigned structalign); + structalign_t structalign); void semantic(Scope *sc); void semantic2(Scope *sc); void semantic3(Scope *sc); @@ -122,7 +122,7 @@ struct AlignDeclaration : AttribDeclaration struct AnonDeclaration : AttribDeclaration { bool isunion; - unsigned alignment; + structalign_t alignment; int sem; // 1 if successful semantic() AnonDeclaration(Loc loc, int isunion, Dsymbols *decl); @@ -178,6 +178,7 @@ struct StaticIfDeclaration : ConditionalDeclaration StaticIfDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl); Dsymbol *syntaxCopy(Dsymbol *s); + Dsymbols *include(Scope *sc, ScopeDsymbol *s); int addMember(Scope *sc, ScopeDsymbol *s, int memnum); void semantic(Scope *sc); void importAll(Scope *sc); diff --git a/dmd2/builtin.c b/dmd2/builtin.c index 0c8a780a..c1494b5f 100644 --- a/dmd2/builtin.c +++ b/dmd2/builtin.c @@ -10,9 +10,9 @@ #include #include +#include // strcmp() #include - #include "mars.h" #include "declaration.h" #include "attrib.h" @@ -44,10 +44,10 @@ enum BUILTIN FuncDeclaration::isBuiltin() { static const char FeZe [] = "FNaNbNfeZe"; // @safe pure nothrow real function(real) static const char FeZe2[] = "FNaNbNeeZe"; // @trusted pure nothrow real function(real) - static const char FuintZint[] = "FNaNbkZi"; // pure nothrow int function(uint) - static const char FuintZuint[] = "FNaNbkZk"; // pure nothrow uint function(uint) + static const char FuintZint[] = "FNaNbNfkZi"; // @safe pure nothrow int function(uint) + static const char FuintZuint[] = "FNaNbNfkZk"; // @safe pure nothrow uint function(uint) static const char FulongZulong[] = "FNaNbkZk"; // pure nothrow int function(ulong) - static const char FulongZint[] = "FNaNbmZi"; // pure nothrow int function(uint) + static const char FulongZint[] = "FNaNbNfmZi"; // @safe pure nothrow int function(uint) static const char FrealrealZreal [] = "FNaNbNfeeZe"; // @safe pure nothrow real function(real, real) static const char FrealZlong [] = "FNaNbNfeZl"; // @safe pure nothrow long function(real) @@ -167,7 +167,7 @@ uinteger_t eval_bswap(Expression *arg0) Expression *eval_builtin(Loc loc, enum BUILTIN builtin, Expressions *arguments) { assert(arguments && arguments->dim); - Expression *arg0 = arguments->tdata()[0]; + Expression *arg0 = (*arguments)[0]; Expression *e = NULL; switch (builtin) { diff --git a/dmd2/canthrow.c b/dmd2/canthrow.c index 885b241a..27992b08 100644 --- a/dmd2/canthrow.c +++ b/dmd2/canthrow.c @@ -42,6 +42,7 @@ struct CanThrow int Expression::canThrow(bool mustNotThrow) { + //printf("Expression::canThrow(%d) %s\n", mustNotThrow, toChars()); CanThrow ct; ct.can = FALSE; ct.mustnot = mustNotThrow; @@ -132,7 +133,7 @@ int Dsymbol_canThrow(Dsymbol *s, bool mustNotThrow) { for (size_t i = 0; i < decl->dim; i++) { - s = decl->tdata()[i]; + s = (*decl)[i]; if (Dsymbol_canThrow(s, mustNotThrow)) return 1; } @@ -165,7 +166,7 @@ int Dsymbol_canThrow(Dsymbol *s, bool mustNotThrow) { for (size_t i = 0; i < tm->members->dim; i++) { - Dsymbol *sm = tm->members->tdata()[i]; + Dsymbol *sm = (*tm->members)[i]; if (Dsymbol_canThrow(sm, mustNotThrow)) return 1; } @@ -174,7 +175,7 @@ int Dsymbol_canThrow(Dsymbol *s, bool mustNotThrow) else if ((td = s->isTupleDeclaration()) != NULL) { for (size_t i = 0; i < td->objects->dim; i++) - { Object *o = td->objects->tdata()[i]; + { Object *o = (*td->objects)[i]; if (o->dyncast() == DYNCAST_EXPRESSION) { Expression *eo = (Expression *)o; if (eo->op == TOKdsymbol) diff --git a/dmd2/cast.c b/dmd2/cast.c index 7aaf2517..1d30d275 100644 --- a/dmd2/cast.c +++ b/dmd2/cast.c @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2011 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -9,6 +9,7 @@ #include #include +#include // mem{set|cpy}() #include "rmem.h" @@ -36,9 +37,10 @@ Expression *Expression::implicitCastTo(Scope *sc, Type *t) MATCH match = implicitConvTo(t); if (match) - { TY tyfrom = type->toBasetype()->ty; - TY tyto = t->toBasetype()->ty; + { #if DMDV1 + TY tyfrom = type->toBasetype()->ty; + TY tyto = t->toBasetype()->ty; if (global.params.warnings && Type::impcnvWarn[tyfrom][tyto] && op != TOKint64) @@ -138,7 +140,7 @@ Expression *ErrorExp::implicitCastTo(Scope *sc, Type *t) Expression *FuncExp::implicitCastTo(Scope *sc, Type *t) { //printf("FuncExp::implicitCastTo type = %p %s, t = %s\n", type, type ? type->toChars() : NULL, t->toChars()); - return inferType(t); + return inferType(t)->Expression::implicitCastTo(sc, t); } /******************************************* @@ -215,6 +217,7 @@ MATCH IntegerExp::implicitConvTo(Type *t) TY ty = type->toBasetype()->ty; TY toty = t->toBasetype()->ty; + TY oldty = ty; if (m == MATCHnomatch && t->ty == Tenum) goto Lno; @@ -282,6 +285,8 @@ MATCH IntegerExp::implicitConvTo(Type *t) goto Lyes; case Tchar: + if ((oldty == Twchar || oldty == Tdchar) && value > 0x7F) + goto Lno; case Tuns8: //printf("value = %llu %llu\n", (dinteger_t)(unsigned char)value, value); if ((unsigned char)value != value) @@ -293,6 +298,9 @@ MATCH IntegerExp::implicitConvTo(Type *t) goto Lno; goto Lyes; + case Twchar: + if (oldty == Tdchar && value > 0xD7FF && value < 0xE000) + goto Lno; case Tuns16: if ((unsigned short)value != value) goto Lno; @@ -319,11 +327,6 @@ MATCH IntegerExp::implicitConvTo(Type *t) goto Lno; goto Lyes; - case Twchar: - if ((unsigned short)value != value) - goto Lno; - goto Lyes; - case Tfloat32: { volatile float f; @@ -540,19 +543,28 @@ MATCH ArrayLiteralExp::implicitConvTo(Type *t) if ((tb->ty == Tarray || tb->ty == Tsarray) && (typeb->ty == Tarray || typeb->ty == Tsarray)) { + Type *typen = typeb->nextOf()->toBasetype(); + if (tb->ty == Tsarray) { TypeSArray *tsa = (TypeSArray *)tb; if (elements->dim != tsa->dim->toInteger()) result = MATCHnomatch; } - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (*elements)[i]; - MATCH m = (MATCH)e->implicitConvTo(tb->nextOf()); - if (m < result) - result = m; // remember worst match - if (result == MATCHnomatch) - break; // no need to check for worse + Type *telement = tb->nextOf(); + if (!elements->dim) + { if (typen->ty != Tvoid) + result = typen->implicitConvTo(telement); + } + else + { for (size_t i = 0; i < elements->dim; i++) + { Expression *e = (*elements)[i]; + if (result == MATCHnomatch) + break; // no need to check for worse + MATCH m = (MATCH)e->implicitConvTo(telement); + if (m < result) + result = m; // remember worst match + } } if (!result) @@ -560,25 +572,46 @@ MATCH ArrayLiteralExp::implicitConvTo(Type *t) return result; } + else if (tb->ty == Tvector && + (typeb->ty == Tarray || typeb->ty == Tsarray)) + { + // Convert array literal to vector type + TypeVector *tv = (TypeVector *)tb; + TypeSArray *tbase = (TypeSArray *)tv->basetype; + assert(tbase->ty == Tsarray); + if (elements->dim != tbase->dim->toInteger()) + return MATCHnomatch; + + Type *telement = tv->elementType(); + for (size_t i = 0; i < elements->dim; i++) + { Expression *e = (*elements)[i]; + MATCH m = (MATCH)e->implicitConvTo(telement); + if (m < result) + result = m; // remember worst match + if (result == MATCHnomatch) + break; // no need to check for worse + } + return result; + } else return Expression::implicitConvTo(t); } MATCH AssocArrayLiteralExp::implicitConvTo(Type *t) -{ MATCH result = MATCHexact; - +{ Type *typeb = type->toBasetype(); Type *tb = t->toBasetype(); if (tb->ty == Taarray && typeb->ty == Taarray) { + MATCH result = MATCHexact; for (size_t i = 0; i < keys->dim; i++) - { Expression *e = keys->tdata()[i]; + { Expression *e = (*keys)[i]; MATCH m = (MATCH)e->implicitConvTo(((TypeAArray *)tb)->index); if (m < result) result = m; // remember worst match if (result == MATCHnomatch) break; // no need to check for worse - e = values->tdata()[i]; + e = (*values)[i]; m = (MATCH)e->implicitConvTo(tb->nextOf()); if (m < result) result = m; // remember worst match @@ -905,6 +938,9 @@ Expression *Expression::castTo(Scope *sc, Type *t) } else if (tb->ty == Tvector && typeb->ty != Tvector) { + //printf("test1 e = %s, e->type = %s, tb = %s\n", e->toChars(), e->type->toChars(), tb->toChars()); + TypeVector *tv = (TypeVector *)tb; + e = new CastExp(loc, e, tv->elementType()); e = new VectorExp(loc, e, tb); e = e->semantic(sc); return e; @@ -1372,9 +1408,9 @@ Expression *TupleExp::castTo(Scope *sc, Type *t) { TupleExp *e = (TupleExp *)copy(); e->exps = (Expressions *)exps->copy(); for (size_t i = 0; i < e->exps->dim; i++) - { Expression *ex = e->exps->tdata()[i]; + { Expression *ex = (*e->exps)[i]; ex = ex->castTo(sc, t); - e->exps->tdata()[i] = ex; + (*e->exps)[i] = ex; } return e; } @@ -1420,6 +1456,28 @@ Expression *ArrayLiteralExp::castTo(Scope *sc, Type *t) e->type = tp; } } + else if (tb->ty == Tvector && + (typeb->ty == Tarray || typeb->ty == Tsarray)) + { + // Convert array literal to vector type + TypeVector *tv = (TypeVector *)tb; + TypeSArray *tbase = (TypeSArray *)tv->basetype; + assert(tbase->ty == Tsarray); + if (elements->dim != tbase->dim->toInteger()) + goto L1; + + e = (ArrayLiteralExp *)copy(); + e->elements = (Expressions *)elements->copy(); + Type *telement = tv->elementType(); + for (size_t i = 0; i < elements->dim; i++) + { Expression *ex = (*elements)[i]; + ex = ex->castTo(sc, telement); + (*e->elements)[i] = ex; + } + Expression *ev = new VectorExp(loc, e, tb); + ev = ev->semantic(sc); + return ev; + } L1: return e->Expression::castTo(sc, t); } @@ -1439,13 +1497,13 @@ Expression *AssocArrayLiteralExp::castTo(Scope *sc, Type *t) e->values = (Expressions *)values->copy(); assert(keys->dim == values->dim); for (size_t i = 0; i < keys->dim; i++) - { Expression *ex = values->tdata()[i]; + { Expression *ex = (*values)[i]; ex = ex->castTo(sc, tb->nextOf()); - e->values->tdata()[i] = ex; + (*e->values)[i] = ex; - ex = keys->tdata()[i]; + ex = (*keys)[i]; ex = ex->castTo(sc, ((TypeAArray *)tb)->index); - e->keys->tdata()[i] = ex; + (*e->keys)[i] = ex; } e->type = t; return e; @@ -1688,7 +1746,7 @@ Expression *FuncExp::inferType(Type *to, int flag, TemplateParameters *tparams) { if (to->ty == Tdelegate || to->ty == Tpointer && to->nextOf()->ty == Tfunction) - { treq = to; + { fd->treq = to; } return this; } @@ -1714,6 +1772,8 @@ Expression *FuncExp::inferType(Type *to, int flag, TemplateParameters *tparams) { TypeFunction *tfv = (TypeFunction *)t; TypeFunction *tfl = (TypeFunction *)fd->type; + //printf("\ttfv = %s\n", tfv->toChars()); + //printf("\ttfl = %s\n", tfl->toChars()); size_t dim = Parameter::dim(tfl->parameters); if (Parameter::dim(tfv->parameters) == dim && @@ -1740,6 +1800,13 @@ Expression *FuncExp::inferType(Type *to, int flag, TemplateParameters *tparams) } } + // Set target of return type inference + assert(td->onemember); + FuncLiteralDeclaration *fld = td->onemember->isFuncLiteralDeclaration(); + assert(fld); + if (!fld->type->nextOf() && tfv->next) + fld->treq = tfv; + TemplateInstance *ti = new TemplateInstance(loc, td, tiargs); e = (new ScopeExp(loc, ti))->semantic(td->scope); if (e->op == TOKfunction) @@ -1759,14 +1826,12 @@ Expression *FuncExp::inferType(Type *to, int flag, TemplateParameters *tparams) to->ty == Tdelegate) { Type *typen = type->nextOf(); - assert(typen->deco); - //if (typen->covariant(to->nextOf()) == 1) + if (typen->deco) { FuncExp *fe = (FuncExp *)copy(); fe->tok = TOKdelegate; fe->type = (new TypeDelegate(typen))->merge(); e = fe; - //e = fe->Expression::implicitCastTo(sc, to); } } else @@ -1879,7 +1944,7 @@ bool isVoidArrayLiteral(Expression *e, Type *other) while (e->op == TOKarrayliteral && e->type->ty == Tarray && (((ArrayLiteralExp *)e)->elements->dim == 1)) { - e = ((ArrayLiteralExp *)e)->elements->tdata()[0]; + e = (*((ArrayLiteralExp *)e)->elements)[0]; if (other->ty == Tsarray || other->ty == Tarray) other = other->nextOf(); else @@ -1910,6 +1975,7 @@ int typeMerge(Scope *sc, Expression *e, Type **pt, Expression **pe1, Expression //printf("typeMerge() %s op %s\n", (*pe1)->toChars(), (*pe2)->toChars()); //e->dump(0); + MATCH m; Expression *e1 = *pe1; Expression *e2 = *pe2; @@ -2110,10 +2176,20 @@ Lagain: */ goto Lx2; } - else if ((t1->ty == Tsarray || t1->ty == Tarray) && t1->implicitConvTo(t2)) + else if ((t1->ty == Tsarray || t1->ty == Tarray) && + (m = t1->implicitConvTo(t2)) != MATCHnomatch) { if (t1->ty == Tsarray && e2->op == TOKarrayliteral) goto Lt1; + if (m == MATCHconst && + (e->op == TOKaddass || e->op == TOKminass || e->op == TOKmulass || + e->op == TOKdivass || e->op == TOKmodass || e->op == TOKpowass || + e->op == TOKandass || e->op == TOKorass || e->op == TOKxorass) + ) + { // Don't make the lvalue const + t = t2; + goto Lret; + } goto Lt2; } else if ((t2->ty == Tsarray || t2->ty == Tarray) && t2->implicitConvTo(t1)) diff --git a/dmd2/class.c b/dmd2/class.c index 25644248..6721e925 100644 --- a/dmd2/class.c +++ b/dmd2/class.c @@ -11,6 +11,7 @@ #include #include #include +#include // mem{cpy|set}() #include "root.h" #include "rmem.h" @@ -177,6 +178,12 @@ ClassDeclaration::ClassDeclaration(Loc loc, Identifier *id, BaseClasses *basecla Type::typeinfowild->error("%s", msg); Type::typeinfowild = this; } + + if (id == Id::TypeInfo_Vector) + { if (Type::typeinfovector) + Type::typeinfovector->error("%s", msg); + Type::typeinfovector = this; + } #endif } @@ -241,9 +248,9 @@ Dsymbol *ClassDeclaration::syntaxCopy(Dsymbol *s) cd->baseclasses->setDim(this->baseclasses->dim); for (size_t i = 0; i < cd->baseclasses->dim; i++) { - BaseClass *b = this->baseclasses->tdata()[i]; + BaseClass *b = (*this->baseclasses)[i]; BaseClass *b2 = new BaseClass(b->type->syntaxCopy(), b->protection); - cd->baseclasses->tdata()[i] = b2; + (*cd->baseclasses)[i] = b2; } ScopeDsymbol::syntaxCopy(cd); @@ -292,10 +299,6 @@ void ClassDeclaration::semantic(Scope *sc) scope = NULL; } unsigned dprogress_save = Module::dprogress; -#ifdef IN_GCC - methods.setDim(0); -#endif - int errors = global.gaggedErrors; if (sc->stc & STCdeprecated) @@ -308,7 +311,7 @@ void ClassDeclaration::semantic(Scope *sc) // Expand any tuples in baseclasses[] for (size_t i = 0; i < baseclasses->dim; ) - { BaseClass *b = baseclasses->tdata()[i]; + { BaseClass *b = (*baseclasses)[i]; b->type = b->type->semantic(loc, sc); Type *tb = b->type->toBasetype(); @@ -333,7 +336,7 @@ void ClassDeclaration::semantic(Scope *sc) BaseClass *b; Type *tb; - b = baseclasses->tdata()[0]; + b = (*baseclasses)[0]; //b->type = b->type->semantic(loc, sc); tb = b->type->toBasetype(); if (tb->ty != Tclass) @@ -403,7 +406,7 @@ void ClassDeclaration::semantic(Scope *sc) BaseClass *b; Type *tb; - b = baseclasses->tdata()[i]; + b = (*baseclasses)[i]; b->type = b->type->semantic(loc, sc); tb = b->type->toBasetype(); if (tb->ty == Tclass) @@ -432,7 +435,7 @@ void ClassDeclaration::semantic(Scope *sc) // Check for duplicate interfaces for (size_t j = (baseClass ? 1 : 0); j < i; j++) { - BaseClass *b2 = baseclasses->tdata()[j]; + BaseClass *b2 = (*baseclasses)[j]; if (b2->base == tc->sym) error("inherits from duplicate interface %s", b2->base->toChars()); } @@ -464,22 +467,20 @@ void ClassDeclaration::semantic(Scope *sc) // If no base class, and this is not an Object, use Object as base class if (!baseClass && ident != Id::Object) { - // BUG: what if Object is redefined in an inner scope? - Type *tbase = new TypeIdentifier(0, Id::Object); - BaseClass *b; - TypeClass *tc; - Type *bt; - if (!object) { error("missing or corrupt object.d"); fatal(); } - bt = tbase->semantic(loc, sc)->toBasetype(); - b = new BaseClass(bt, PROTpublic); + + Type *t = object->type; + t = t->semantic(loc, sc)->toBasetype(); + assert(t->ty == Tclass); + TypeClass *tc = (TypeClass *)t; + + BaseClass *b = new BaseClass(tc, PROTpublic); baseclasses->shift(b); - assert(b->type->ty == Tclass); - tc = (TypeClass *)(b->type); + baseClass = tc->sym; assert(!baseClass->isInterfaceDeclaration()); b->base = baseClass; @@ -535,7 +536,9 @@ void ClassDeclaration::semantic(Scope *sc) isnested = 1; if (storage_class & STCstatic) error("static class cannot inherit from nested class %s", baseClass->toChars()); - if (toParent2() != baseClass->toParent2()) + if (toParent2() != baseClass->toParent2() && + (!toParent2() || + !baseClass->toParent2()->getType()->isBaseOf(toParent2()->getType(), NULL))) { if (toParent2()) { @@ -614,8 +617,7 @@ void ClassDeclaration::semantic(Scope *sc) } sc->protection = PROTpublic; sc->explicitProtection = 0; - sc->structalign = 8; - structalign = sc->structalign; + sc->structalign = STRUCTALIGN_DEFAULT; if (baseClass) { sc->offset = baseClass->structsize; alignsize = baseClass->alignsize; @@ -642,9 +644,10 @@ void ClassDeclaration::semantic(Scope *sc) if (s->isEnumDeclaration() || (s->isAggregateDeclaration() && s->ident) || s->isTemplateMixin() || + s->isAttribDeclaration() || s->isAliasDeclaration()) { - //printf("setScope %s %s\n", s->kind(), s->toChars()); + //printf("[%d] setScope %s %s, sc = %p\n", i, s->kind(), s->toChars(), sc); s->setScope(sc); } } @@ -682,7 +685,7 @@ void ClassDeclaration::semantic(Scope *sc) fields.setDim(0); structsize = 0; alignsize = 0; - structalign = 0; +// structalign = 0; sc = sc->pop(); @@ -757,7 +760,7 @@ void ClassDeclaration::semantic(Scope *sc) BaseClass *b = (*vtblInterfaces)[i]; unsigned thissize = PTRSIZE; - alignmember(structalign, thissize, &sc->offset); + alignmember(STRUCTALIGN_DEFAULT, thissize, &sc->offset); assert(b->offset == 0); b->offset = sc->offset; @@ -774,9 +777,12 @@ void ClassDeclaration::semantic(Scope *sc) } structsize = sc->offset; #if IN_LLVM - if (global.params.is64bit) - structsize = (structsize + structalign - 1) & ~(structalign - 1); + if (sc->structalign == STRUCTALIGN_DEFAULT) + structsize = (structsize + alignsize - 1) & ~(alignsize - 1); + else + structsize = (structsize + sc->structalign - 1) & ~(sc->structalign - 1); #endif + sizeok = SIZEOKdone; Module::dprogress++; @@ -788,7 +794,7 @@ void ClassDeclaration::semantic(Scope *sc) // Fill in base class vtbl[]s for (i = 0; i < vtblInterfaces->dim; i++) { - BaseClass *b = vtblInterfaces->tdata()[i]; + BaseClass *b = (*vtblInterfaces)[i]; //b->fillVtbl(this, &b->vtbl, 1); } @@ -813,7 +819,7 @@ void ClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) } for (size_t i = 0; i < baseclasses->dim; i++) { - BaseClass *b = baseclasses->tdata()[i]; + BaseClass *b = (*baseclasses)[i]; if (i) buf->writeByte(','); @@ -827,7 +833,7 @@ void ClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writenl(); for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = members->tdata()[i]; + Dsymbol *s = (*members)[i]; buf->writestring(" "); s->toCBuffer(buf, hgs); @@ -862,7 +868,7 @@ int ClassDeclaration::isBaseOf2(ClassDeclaration *cd) return 0; //printf("ClassDeclaration::isBaseOf2(this = '%s', cd = '%s')\n", toChars(), cd->toChars()); for (size_t i = 0; i < cd->baseclasses->dim; i++) - { BaseClass *b = cd->baseclasses->tdata()[i]; + { BaseClass *b = (*cd->baseclasses)[i]; if (b->base == this || isBaseOf2(b->base)) return 1; @@ -908,7 +914,7 @@ int ClassDeclaration::isBaseInfoComplete() if (!baseClass) return ident == Id::Object; for (size_t i = 0; i < baseclasses->dim; i++) - { BaseClass *b = baseclasses->tdata()[i]; + { BaseClass *b = (*baseclasses)[i]; if (!b->base || !b->base->isBaseInfoComplete()) return 0; } @@ -946,7 +952,7 @@ Dsymbol *ClassDeclaration::search(Loc loc, Identifier *ident, int flags) for (size_t i = 0; i < baseclasses->dim; i++) { - BaseClass *b = baseclasses->tdata()[i]; + BaseClass *b = (*baseclasses)[i]; if (b->base) { @@ -1011,7 +1017,7 @@ int ClassDeclaration::isFuncHidden(FuncDeclaration *fd) if (os) { for (size_t i = 0; i < os->a.dim; i++) - { Dsymbol *s2 = os->a.tdata()[i]; + { Dsymbol *s2 = os->a[i]; FuncDeclaration *f2 = s2->isFuncDeclaration(); if (f2 && overloadApply(f2, &isf, fd)) return 0; @@ -1054,9 +1060,11 @@ FuncDeclaration *ClassDeclaration::findFunc(Identifier *ident, TypeFunction *tf) //printf("\t[%d] = %s\n", i, fd->toChars()); if (ident == fd->ident && fd->type->covariant(tf) == 1) - { //printf("fd->parent->isClassDeclaration() = %p", fd->parent->isClassDeclaration()); + { //printf("fd->parent->isClassDeclaration() = %p\n", fd->parent->isClassDeclaration()); if (!fdmatch) goto Lfd; + if (fd == fdmatch) + goto Lfdmatch; { // Function type matcing: exact > covariant @@ -1068,6 +1076,15 @@ FuncDeclaration *ClassDeclaration::findFunc(Identifier *ident, TypeFunction *tf) goto Lfdmatch; } + { + int m1 = (tf->mod == fd ->type->mod) ? MATCHexact : MATCHnomatch; + int m2 = (tf->mod == fdmatch->type->mod) ? MATCHexact : MATCHnomatch; + if (m1 > m2) + goto Lfd; + else if (m1 < m2) + goto Lfdmatch; + } + { // The way of definition: non-mixin > mixin int m1 = fd ->parent->isClassDeclaration() ? MATCHexact : MATCHnomatch; @@ -1158,7 +1175,7 @@ int ClassDeclaration::isAbstract() return TRUE; for (size_t i = 1; i < vtbl.dim; i++) { - FuncDeclaration *fd = vtbl.tdata()[i]->isFuncDeclaration(); + FuncDeclaration *fd = vtbl[i]->isFuncDeclaration(); //printf("\tvtbl[%d] = %p\n", i, fd); if (!fd || fd->isAbstract()) @@ -1266,7 +1283,7 @@ void InterfaceDeclaration::semantic(Scope *sc) // Expand any tuples in baseclasses[] for (size_t i = 0; i < baseclasses->dim; ) - { BaseClass *b = (*baseclasses)[0]; + { BaseClass *b = (*baseclasses)[i]; b->type = b->type->semantic(loc, sc); Type *tb = b->type->toBasetype(); @@ -1294,7 +1311,7 @@ void InterfaceDeclaration::semantic(Scope *sc) BaseClass *b; Type *tb; - b = baseclasses->tdata()[i]; + b = (*baseclasses)[i]; b->type = b->type->semantic(loc, sc); tb = b->type->toBasetype(); if (tb->ty == Tclass) @@ -1312,7 +1329,7 @@ void InterfaceDeclaration::semantic(Scope *sc) // Check for duplicate interfaces for (size_t j = 0; j < i; j++) { - BaseClass *b2 = baseclasses->tdata()[j]; + BaseClass *b2 = (*baseclasses)[j]; if (b2->base == tc->sym) error("inherits from duplicate interface %s", b2->base->toChars()); } @@ -1373,7 +1390,7 @@ void InterfaceDeclaration::semantic(Scope *sc) { vtbl.reserve(d - 1); for (size_t j = 1; j < d; j++) - vtbl.push(b->base->vtbl.tdata()[j]); + vtbl.push(b->base->vtbl[j]); } } else @@ -1401,10 +1418,10 @@ void InterfaceDeclaration::semantic(Scope *sc) sc->linkage = LINKwindows; else if (isCPPinterface()) sc->linkage = LINKcpp; - sc->structalign = 8; + sc->structalign = STRUCTALIGN_DEFAULT; sc->protection = PROTpublic; sc->explicitProtection = 0; - structalign = sc->structalign; +// structalign = sc->structalign; sc->offset = PTRSIZE * 2; structsize = sc->offset; inuse++; @@ -1426,7 +1443,7 @@ void InterfaceDeclaration::semantic(Scope *sc) for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = members->tdata()[i]; + Dsymbol *s = (*members)[i]; s->semantic(sc); } @@ -1526,7 +1543,7 @@ int InterfaceDeclaration::isBaseInfoComplete() { assert(!baseClass); for (size_t i = 0; i < baseclasses->dim; i++) - { BaseClass *b = baseclasses->tdata()[i]; + { BaseClass *b = (*baseclasses)[i]; if (!b->base || !b->base->isBaseInfoComplete ()) return 0; } @@ -1610,7 +1627,7 @@ int BaseClass::fillVtbl(ClassDeclaration *cd, FuncDeclarations *vtbl, int newins // first entry is ClassInfo reference for (size_t j = base->vtblOffset(); j < base->vtbl.dim; j++) { - FuncDeclaration *ifd = base->vtbl.tdata()[j]->isFuncDeclaration(); + FuncDeclaration *ifd = base->vtbl[j]->isFuncDeclaration(); FuncDeclaration *fd; TypeFunction *tf; @@ -1647,7 +1664,7 @@ int BaseClass::fillVtbl(ClassDeclaration *cd, FuncDeclarations *vtbl, int newins fd = NULL; } if (vtbl) - vtbl->tdata()[j] = fd; + (*vtbl)[j] = fd; } return result; diff --git a/dmd2/clone.c b/dmd2/clone.c index d0b22c40..bfd167ae 100644 --- a/dmd2/clone.c +++ b/dmd2/clone.c @@ -45,7 +45,7 @@ int StructDeclaration::needOpAssign() */ for (size_t i = 0; i < fields.dim; i++) { - Dsymbol *s = fields.tdata()[i]; + Dsymbol *s = fields[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v && v->storage_class & STCfield); if (v->storage_class & STCref) @@ -153,7 +153,7 @@ FuncDeclaration *StructDeclaration::buildOpAssign(Scope *sc) //printf("\tmemberwise copy\n"); for (size_t i = 0; i < fields.dim; i++) { - Dsymbol *s = fields.tdata()[i]; + Dsymbol *s = fields[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v && v->storage_class & STCfield); // this.v = s.v; @@ -214,7 +214,7 @@ int StructDeclaration::needOpEquals() */ for (size_t i = 0; i < fields.dim; i++) { - Dsymbol *s = fields.tdata()[i]; + Dsymbol *s = fields[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v && v->storage_class & STCfield); if (v->storage_class & STCref) @@ -304,7 +304,7 @@ FuncDeclaration *StructDeclaration::buildOpEquals(Scope *sc) //printf("\tmemberwise compare\n"); for (size_t i = 0; i < fields.dim; i++) { - Dsymbol *s = fields.tdata()[i]; + Dsymbol *s = fields[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v && v->storage_class & STCfield); if (v->storage_class & STCref) @@ -513,13 +513,13 @@ FuncDeclaration *StructDeclaration::buildPostBlit(Scope *sc) for (size_t i = 0; i < fields.dim; i++) { - Dsymbol *s = fields.tdata()[i]; + Dsymbol *s = fields[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v && v->storage_class & STCfield); if (v->storage_class & STCref) continue; Type *tv = v->type->toBasetype(); - dinteger_t dim = (tv->ty == Tsarray ? 1 : 0); + dinteger_t dim = 1; while (tv->ty == Tsarray) { TypeSArray *ta = (TypeSArray *)tv; dim *= ((TypeSArray *)tv)->dim->toInteger(); @@ -528,7 +528,7 @@ FuncDeclaration *StructDeclaration::buildPostBlit(Scope *sc) if (tv->ty == Tstruct) { TypeStruct *ts = (TypeStruct *)tv; StructDeclaration *sd = ts->sym; - if (sd->postblit) + if (sd->postblit && dim) { stc |= sd->postblit->storage_class & STCdisable; @@ -542,7 +542,7 @@ FuncDeclaration *StructDeclaration::buildPostBlit(Scope *sc) Expression *ex = new ThisExp(0); ex = new DotVarExp(0, ex, v, 0); - if (dim == 0) + if (v->type->toBasetype()->ty == Tstruct) { // this.v.postblit() ex = new DotVarExp(0, ex, sd->postblit, 0); ex = new CallExp(0, ex); @@ -581,12 +581,12 @@ FuncDeclaration *StructDeclaration::buildPostBlit(Scope *sc) return NULL; case 1: - return postblits.tdata()[0]; + return postblits[0]; default: e = NULL; for (size_t i = 0; i < postblits.dim; i++) - { FuncDeclaration *fd = postblits.tdata()[i]; + { FuncDeclaration *fd = postblits[i]; stc |= fd->storage_class & STCdisable; if (stc & STCdisable) { @@ -625,13 +625,13 @@ FuncDeclaration *AggregateDeclaration::buildDtor(Scope *sc) #if DMDV2 for (size_t i = 0; i < fields.dim; i++) { - Dsymbol *s = fields.tdata()[i]; + Dsymbol *s = fields[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v && v->storage_class & STCfield); if (v->storage_class & STCref) continue; Type *tv = v->type->toBasetype(); - dinteger_t dim = (tv->ty == Tsarray ? 1 : 0); + dinteger_t dim = 1; while (tv->ty == Tsarray) { TypeSArray *ta = (TypeSArray *)tv; dim *= ((TypeSArray *)tv)->dim->toInteger(); @@ -640,14 +640,14 @@ FuncDeclaration *AggregateDeclaration::buildDtor(Scope *sc) if (tv->ty == Tstruct) { TypeStruct *ts = (TypeStruct *)tv; StructDeclaration *sd = ts->sym; - if (sd->dtor) + if (sd->dtor && dim) { Expression *ex; // this.v ex = new ThisExp(0); ex = new DotVarExp(0, ex, v, 0); - if (dim == 0) + if (v->type->toBasetype()->ty == Tstruct) { // this.v.dtor() ex = new DotVarExp(0, ex, sd->dtor, 0); ex = new CallExp(0, ex); @@ -686,12 +686,12 @@ FuncDeclaration *AggregateDeclaration::buildDtor(Scope *sc) return NULL; case 1: - return dtors.tdata()[0]; + return dtors[0]; default: e = NULL; for (size_t i = 0; i < dtors.dim; i++) - { FuncDeclaration *fd = dtors.tdata()[i]; + { FuncDeclaration *fd = dtors[i]; Expression *ex = new ThisExp(0); ex = new DotVarExp(0, ex, fd, 0); ex = new CallExp(0, ex); diff --git a/dmd2/cond.c b/dmd2/cond.c index afce513e..f54fd467 100644 --- a/dmd2/cond.c +++ b/dmd2/cond.c @@ -10,6 +10,7 @@ #include #include +#include // strcmp() #include "id.h" #include "init.h" @@ -266,7 +267,14 @@ int StaticIfCondition::include(Scope *sc, ScopeDsymbol *s) sc->flags |= SCOPEstaticif; Expression *e = exp->semantic(sc); sc->pop(); - e = e->optimize(WANTvalue | WANTinterpret); + if (!e->type->checkBoolean()) + { + if (e->type->toBasetype() != Type::terror) + exp->error("expression %s of type %s does not have a boolean value", exp->toChars(), e->type->toChars()); + inc = 0; + return 0; + } + e = e->ctfeInterpret(); --nest; if (e->op == TOKerror) { exp = e; diff --git a/dmd2/constfold.c b/dmd2/constfold.c index 0be4cb82..8ecd2b40 100644 --- a/dmd2/constfold.c +++ b/dmd2/constfold.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -11,6 +11,7 @@ #include #include #include +#include // mem{cpy|set|cmp}() #include #if __DMC__ @@ -621,7 +622,7 @@ Expression *Pow(Type *type, Expression *e1, Expression *e2) // Special case: call sqrt directly. Expressions args; args.setDim(1); - args.tdata()[0] = e1; + args[0] = e1; e = eval_builtin(loc, BUILTINsqrt, &args); if (!e) e = EXP_CANT_INTERPRET; @@ -1290,7 +1291,7 @@ Expression *Cast(Type *type, Type *to, Expression *e1) assert(sd); Expressions *elements = new Expressions; for (size_t i = 0; i < sd->fields.dim; i++) - { Dsymbol *s = sd->fields.tdata()[i]; + { Dsymbol *s = sd->fields[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v); @@ -1374,7 +1375,7 @@ Expression *Index(Type *type, Expression *e1, Expression *e2) } else if (e1->op == TOKarrayliteral) { ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; - e = ale->elements->tdata()[i]; + e = (*ale->elements)[i]; e->type = type; if (e->hasSideEffect()) e = EXP_CANT_INTERPRET; @@ -1392,7 +1393,7 @@ Expression *Index(Type *type, Expression *e1, Expression *e2) e = new ErrorExp(); } else - { e = ale->elements->tdata()[i]; + { e = (*ale->elements)[i]; e->type = type; if (e->hasSideEffect()) e = EXP_CANT_INTERPRET; @@ -1407,12 +1408,12 @@ Expression *Index(Type *type, Expression *e1, Expression *e2) for (size_t i = ae->keys->dim; i;) { i--; - Expression *ekey = ae->keys->tdata()[i]; + Expression *ekey = (*ae->keys)[i]; Expression *ex = Equal(TOKequal, Type::tbool, ekey, e2); if (ex == EXP_CANT_INTERPRET) return ex; if (ex->isBool(TRUE)) - { e = ae->values->tdata()[i]; + { e = (*ae->values)[i]; e->type = type; if (e->hasSideEffect()) e = EXP_CANT_INTERPRET; @@ -1483,7 +1484,7 @@ Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr) elements->setDim(iupr - ilwr); memcpy(elements->tdata(), es1->elements->tdata() + ilwr, - (iupr - ilwr) * sizeof(es1->elements->tdata()[0])); + (iupr - ilwr) * sizeof((*es1->elements)[0])); e = new ArrayLiteralExp(e1->loc, elements); e->type = type; } @@ -1512,7 +1513,7 @@ void sliceAssignArrayLiteralFromString(ArrayLiteralExp *existingAE, StringExp *n assert(0); break; } - existingAE->elements->tdata()[j+firstIndex] + (*existingAE->elements)[j+firstIndex] = new IntegerExp(newval->loc, val, elemType); } } @@ -1525,7 +1526,7 @@ void sliceAssignStringFromArrayLiteral(StringExp *existingSE, ArrayLiteralExp *n unsigned char *s = (unsigned char *)existingSE->string; for (size_t j = 0; j < newae->elements->dim; j++) { - unsigned value = (unsigned)(newae->elements->tdata()[j]->toInteger()); + unsigned value = (unsigned)((*newae->elements)[j]->toInteger()); switch (existingSE->sz) { case 1: s[j+firstIndex] = value; break; @@ -1549,6 +1550,48 @@ void sliceAssignStringFromString(StringExp *existingSE, StringExp *newstr, int f memcpy(s + firstIndex * sz, newstr->string, sz * newstr->len); } +/* Compare a string slice with another string slice. + * Conceptually equivalent to memcmp( se1[lo1..lo1+len], se2[lo2..lo2+len]) + */ +int sliceCmpStringWithString(StringExp *se1, StringExp *se2, size_t lo1, size_t lo2, size_t len) +{ + unsigned char *s1 = (unsigned char *)se1->string; + unsigned char *s2 = (unsigned char *)se2->string; + size_t sz = se1->sz; + assert(sz == se2->sz); + + return memcmp(s1 + sz * lo1, s2 + sz * lo2, sz * len); +} + +/* Compare a string slice with an array literal slice + * Conceptually equivalent to memcmp( se1[lo1..lo1+len], ae2[lo2..lo2+len]) + */ +int sliceCmpStringWithArray(StringExp *se1, ArrayLiteralExp *ae2, size_t lo1, size_t lo2, size_t len) +{ + unsigned char *s = (unsigned char *)se1->string; + size_t sz = se1->sz; + + int c = 0; + + for (size_t j = 0; j < len; j++) + { + unsigned value = (unsigned)((*ae2->elements)[j + lo2]->toInteger()); + unsigned svalue; + switch (sz) + { + case 1: svalue = s[j + lo1]; break; + case 2: svalue = ((unsigned short *)s)[j+lo1]; break; + case 4: svalue = ((unsigned *)s)[j + lo1]; break; + default: + assert(0); + } + int c = svalue - value; + if (c) + return c; + } + return 0; +} + /* Also return EXP_CANT_INTERPRET if this fails */ Expression *Cat(Type *type, Expression *e1, Expression *e2) @@ -1666,7 +1709,7 @@ Expression *Cat(Type *type, Expression *e1, Expression *e2) elems->setDim(len); for (size_t i= 0; i < ea->elements->dim; ++i) { - elems->tdata()[i] = ea->elements->tdata()[i]; + (*elems)[i] = (*ea->elements)[i]; } ArrayLiteralExp *dest = new ArrayLiteralExp(e1->loc, elems); dest->type = type; @@ -1684,7 +1727,7 @@ Expression *Cat(Type *type, Expression *e1, Expression *e2) elems->setDim(len); for (size_t i= 0; i < ea->elements->dim; ++i) { - elems->tdata()[es->len + i] = ea->elements->tdata()[i]; + (*elems)[es->len + i] = (*ea->elements)[i]; } ArrayLiteralExp *dest = new ArrayLiteralExp(e1->loc, elems); dest->type = type; diff --git a/dmd2/cppmangle.c b/dmd2/cppmangle.c index 915bb23c..f29eaa83 100644 --- a/dmd2/cppmangle.c +++ b/dmd2/cppmangle.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -9,6 +9,7 @@ // See the included readme.txt for details. #include +#include #include #include "mars.h" @@ -69,7 +70,7 @@ int CppMangleState::substitute(OutBuffer *buf, void *p) { for (size_t i = 0; i < components.dim; i++) { - if (p == components.tdata()[i]) + if (p == components[i]) { /* Sequence is S_, S0_, .., S9_, SA_, ..., SZ_, S10_, ... */ @@ -88,7 +89,7 @@ int CppMangleState::exist(void *p) { for (size_t i = 0; i < components.dim; i++) { - if (p == components.tdata()[i]) + if (p == components[i]) { return 1; } @@ -160,7 +161,7 @@ char *cpp_mangle(Dsymbol *s) cms.components.setDim(0); OutBuffer buf; -#if MACHOBJ +#if TARGET_OSX buf.writestring("__Z"); #else buf.writestring("_Z"); @@ -417,7 +418,7 @@ void Parameter::argsCppMangle(OutBuffer *buf, CppMangleState *cms, Parameters *a if (arguments) { for (size_t i = 0; i < arguments->dim; i++) - { Parameter *arg = arguments->tdata()[i]; + { Parameter *arg = (*arguments)[i]; Type *t = arg->type; if (arg->storageClass & (STCout | STCref)) t = t->referenceTo(); diff --git a/dmd2/declaration.c b/dmd2/declaration.c index 4da51432..23001ce8 100644 --- a/dmd2/declaration.c +++ b/dmd2/declaration.c @@ -122,6 +122,18 @@ void Declaration::checkModify(Loc loc, Scope *sc, Type *t) } #endif +Dsymbol *Declaration::search(Loc loc, Identifier *ident, int flags) +{ + Dsymbol *s = Dsymbol::search(loc, ident, flags); + if (!s && type) + { + s = type->toDsymbol(NULL); + if (s) + s = s->search(loc, ident, flags); + } + return s; +} + /********************************* TupleDeclaration ****************************/ @@ -159,7 +171,7 @@ Type *TupleDeclaration::getType() /* It's only a type tuple if all the Object's are types */ for (size_t i = 0; i < objects->dim; i++) - { Object *o = objects->tdata()[i]; + { Object *o = (*objects)[i]; if (o->dyncast() != DYNCAST_TYPE) { @@ -176,7 +188,7 @@ Type *TupleDeclaration::getType() OutBuffer buf; int hasdeco = 1; for (size_t i = 0; i < types->dim; i++) - { Type *t = types->tdata()[i]; + { Type *t = (*types)[i]; //printf("type = %s\n", t->toChars()); #if 0 @@ -187,7 +199,7 @@ Type *TupleDeclaration::getType() #else Parameter *arg = new Parameter(0, t, NULL, NULL); #endif - args->tdata()[i] = arg; + (*args)[i] = arg; if (!t->deco) hasdeco = 0; } @@ -204,7 +216,7 @@ int TupleDeclaration::needThis() { //printf("TupleDeclaration::needThis(%s)\n", toChars()); for (size_t i = 0; i < objects->dim; i++) - { Object *o = objects->tdata()[i]; + { Object *o = (*objects)[i]; if (o->dyncast() == DYNCAST_EXPRESSION) { Expression *e = (Expression *)o; if (e->op == TOKdsymbol) @@ -336,7 +348,7 @@ void TypedefDeclaration::semantic2(Scope *sc) { Initializer *savedinit = init; int errors = global.errors; - init = init->semantic(sc, basetype, WANTinterpret); + init = init->semantic(sc, basetype, INITinterpret); if (errors != global.errors) { init = savedinit; @@ -557,6 +569,17 @@ void AliasDeclaration::semantic(Scope *sc) s->parent = sc->parent; } } + OverloadSet *o = s->toAlias()->isOverloadSet(); + if (o) + { + if (overnext) + { + o->push(overnext); + overnext = NULL; + s = o; + s->parent = sc->parent; + } + } if (overnext) ScopeDsymbol::multiplyDefined(0, this, overnext); if (s == this) @@ -619,7 +642,9 @@ const char *AliasDeclaration::kind() Type *AliasDeclaration::getType() { - return type; + if (type) + return type; + return toAlias()->getType(); } Dsymbol *AliasDeclaration::toAlias() @@ -632,7 +657,9 @@ Dsymbol *AliasDeclaration::toAlias() aliassym = new AliasDeclaration(loc, ident, Type::terror); type = Type::terror; } - else if (!aliassym && scope) + else if (aliassym || type->deco) + ; // semantic is already done. + else if (scope) semantic(scope); Dsymbol *s = aliassym ? aliassym->toAlias() : this; return s; @@ -845,6 +872,14 @@ void VarDeclaration::semantic(Scope *sc) this->parent = sc->parent; //printf("this = %p, parent = %p, '%s'\n", this, parent, parent->toChars()); protection = sc->protection; + + /* If scope's alignment is the default, use the type's alignment, + * otherwise the scope overrrides. + */ + alignment = sc->structalign; + if (alignment == STRUCTALIGN_DEFAULT) + alignment = type->alignment(); // use type's alignment + //printf("sc->stc = %x\n", sc->stc); //printf("storage_class = x%x\n", storage_class); @@ -931,7 +966,7 @@ void VarDeclaration::semantic(Scope *sc) for (size_t pos = 0; pos < iexps->dim; pos++) { Lexpand1: - Expression *e = iexps->tdata()[pos]; + Expression *e = (*iexps)[pos]; Parameter *arg = Parameter::getNth(tt->arguments, pos); arg->type = arg->type->semantic(loc, sc); //printf("[%d] iexps->dim = %d, ", pos, iexps->dim); @@ -1028,7 +1063,7 @@ Lnomatch: Expression *einit = ie; if (ie && ie->op == TOKtuple) - { einit = ((TupleExp *)ie)->exps->tdata()[i]; + { einit = (*((TupleExp *)ie)->exps)[i]; } Initializer *ti = init; if (einit) @@ -1051,7 +1086,7 @@ Lnomatch: } #endif Expression *e = new DsymbolExp(loc, v); - exps->tdata()[i] = e; + (*exps)[i] = e; } TupleDeclaration *v2 = new TupleDeclaration(loc, ident, exps); v2->isexp = 1; @@ -1091,7 +1126,7 @@ Lnomatch: } else if (storage_class & STCfinal) { - error("final cannot be applied to variable"); + error("final cannot be applied to variable, perhaps you meant const?"); } if (storage_class & (STCstatic | STCextern | STCmanifest | STCtemplateparameter | STCtls | STCgshared | STCctfe)) @@ -1114,7 +1149,6 @@ Lnomatch: #endif { storage_class |= STCfield; - alignment = sc->structalign; #if DMDV2 if (tb->ty == Tstruct && ((TypeStruct *)tb)->sym->noDefaultCtor || tb->ty == Tclass && ((TypeClass *)tb)->sym->noDefaultCtor) @@ -1244,6 +1278,19 @@ Lnomatch: init = new ExpInitializer(loc, e); goto Ldtor; } + else if (type->ty == Tstruct && + (((TypeStruct *)type)->sym->isnested)) + { + /* Nested struct requires valid enclosing frame pointer. + * In StructLiteralExp::toElem(), it's calculated. + */ + Expression *e = type->defaultInitLiteral(loc); + Expression *e1 = new VarExp(loc, this); + e = new ConstructExp(loc, e1, e); + e = e->semantic(sc); + init = new ExpInitializer(loc, e); + goto Ldtor; + } else if (type->ty == Ttypedef) { TypeTypedef *td = (TypeTypedef *)type; if (td->sym->init) @@ -1313,7 +1360,8 @@ Lnomatch: Expression *e = init->toExpression(); if (!e) { - init = init->semantic(sc, type, 0); // Don't need to interpret + // Run semantic, but don't need to interpret + init = init->semantic(sc, type, INITnointerpret); e = init->toExpression(); if (!e) { error("is not a static and cannot have static initializer"); @@ -1395,16 +1443,26 @@ Lnomatch: { e = new ConstructExp(loc, new VarExp(loc, this), new IntegerExp(loc, 0, Type::tint32)); } + else if (sd->isNested()) + { e = new AssignExp(loc, new VarExp(loc, this), t->defaultInitLiteral(loc)); + e->op = TOKblit; + } else { e = new AssignExp(loc, new VarExp(loc, this), t->defaultInit(loc)); e->op = TOKblit; } e->type = t; - (*pinit) = new CommaExp(loc, e, (*pinit)); - /* Replace __ctmp being constructed with e1 + /* Replace __ctmp being constructed with e1. + * We need to copy constructor call expression, + * because it may be used in other place. */ - dve->e1 = e1; + DotVarExp *dvx = (DotVarExp *)dve->copy(); + dvx->e1 = e1; + CallExp *cx = (CallExp *)ce->copy(); + cx->e1 = dvx; + + (*pinit) = new CommaExp(loc, e, cx); (*pinit) = (*pinit)->semantic(sc); goto Ldtor; } @@ -1466,7 +1524,7 @@ Lnomatch: } else { - init = init->semantic(sc, type, WANTinterpret); + init = init->semantic(sc, type, INITinterpret); } } else if (storage_class & (STCconst | STCimmutable | STCmanifest) || @@ -1537,7 +1595,7 @@ Lnomatch: } else if (si || ai) { i2 = init->syntaxCopy(); - i2 = i2->semantic(sc, type, WANTinterpret); + i2 = i2->semantic(sc, type, INITinterpret); } inuse--; if (global.endGagging(errors)) // if errors happened @@ -1552,7 +1610,7 @@ Lnomatch: else if (ei) { if (isDataseg() || (storage_class & STCmanifest)) - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); else e = e->optimize(WANTvalue); switch (e->op) @@ -1639,7 +1697,7 @@ void VarDeclaration::semantic2(Scope *sc) printf("type = %p\n", ei->exp->type); } #endif - init = init->semantic(sc, type, WANTinterpret); + init = init->semantic(sc, type, INITinterpret); inuse--; } sem = Semantic2Done; @@ -1710,9 +1768,8 @@ void VarDeclaration::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, unsigned memsize = t->size(loc); // size of member unsigned memalignsize = t->alignsize(); // size of member for alignment purposes - unsigned memalign = t->memalign(alignment); // alignment boundaries - offset = AggregateDeclaration::placeField(poffset, memsize, memalignsize, memalign, + offset = AggregateDeclaration::placeField(poffset, memsize, memalignsize, alignment, &ad->structsize, &ad->alignsize, isunion); //printf("\t%s: alignsize = %d\n", toChars(), alignsize); @@ -1831,28 +1888,8 @@ void VarDeclaration::checkNestedReference(Scope *sc, Loc loc) // The current function FuncDeclaration *fdthis = sc->parent->isFuncDeclaration(); - if (fdv && fdthis && fdv != fdthis && fdthis->ident != Id::ensure && fdthis->ident != Id::require) + if (fdv && fdthis && fdv != fdthis) { - /* __ensure is always called directly, - * so it never becomes closure. - */ - - //printf("\tfdv = %s\n", fdv->toChars()); - //printf("\tfdthis = %s\n", fdthis->toChars()); - - if (loc.filename) - fdthis->getLevel(loc, sc, fdv); - - // Function literals from fdthis to fdv must be delegates - for (Dsymbol *s = fdthis; s && s != fdv; s = s->toParent2()) - { - // function literal has reference to enclosing scope is delegate - if (FuncLiteralDeclaration *fld = s->isFuncLiteralDeclaration()) - { - fld->tok = TOKdelegate; - } - } - // Add fdthis to nestedrefs[] if not already there for (size_t i = 0; 1; i++) { @@ -1865,23 +1902,46 @@ void VarDeclaration::checkNestedReference(Scope *sc, Loc loc) break; } - // Add this to fdv->closureVars[] if not already there - for (size_t i = 0; 1; i++) + if (fdthis->ident != Id::ensure) { - if (i == fdv->closureVars.dim) - { - fdv->closureVars.push(this); - break; - } - if (fdv->closureVars[i] == this) - break; - } + /* __ensure is always called directly, + * so it never becomes closure. + */ - //printf("fdthis is %s\n", fdthis->toChars()); - //printf("var %s in function %s is nested ref\n", toChars(), fdv->toChars()); - // __dollar creates problems because it isn't a real variable Bugzilla 3326 - if (ident == Id::dollar) - ::error(loc, "cannnot use $ inside a function literal"); + //printf("\tfdv = %s\n", fdv->toChars()); + //printf("\tfdthis = %s\n", fdthis->toChars()); + + if (loc.filename) + fdthis->getLevel(loc, sc, fdv); + + // Function literals from fdthis to fdv must be delegates + for (Dsymbol *s = fdthis; s && s != fdv; s = s->toParent2()) + { + // function literal has reference to enclosing scope is delegate + if (FuncLiteralDeclaration *fld = s->isFuncLiteralDeclaration()) + { + fld->tok = TOKdelegate; + } + } + + // Add this to fdv->closureVars[] if not already there + for (size_t i = 0; 1; i++) + { + if (i == fdv->closureVars.dim) + { + fdv->closureVars.push(this); + break; + } + if (fdv->closureVars[i] == this) + break; + } + + //printf("fdthis is %s\n", fdthis->toChars()); + //printf("var %s in function %s is nested ref\n", toChars(), fdv->toChars()); + // __dollar creates problems because it isn't a real variable Bugzilla 3326 + if (ident == Id::dollar) + ::error(loc, "cannnot use $ inside a function literal"); + } } } } @@ -2353,7 +2413,7 @@ TypeInfoAssociativeArrayDeclaration::TypeInfoAssociativeArrayDeclaration(Type *t TypeInfoVectorDeclaration::TypeInfoVectorDeclaration(Type *tinfo) : TypeInfoDeclaration(tinfo, 0) { - if (!Type::typeinfoarray) + if (!Type::typeinfovector) { ObjectNotFound(Id::TypeInfo_Vector); } diff --git a/dmd2/declaration.h b/dmd2/declaration.h index 5a546f63..0da189f1 100644 --- a/dmd2/declaration.h +++ b/dmd2/declaration.h @@ -101,6 +101,12 @@ enum PURE; #define STCdisable 0x2000000000LL // for functions that are not callable #define STCresult 0x4000000000LL // for result variables passed to out contracts #define STCnodefaultctor 0x8000000000LL // must be set inside constructor +#define STCtemp 0x10000000000LL // temporary variable introduced by inlining + // and used only in backend process, so it's rvalue + +#ifdef BUG6652 +#define STCbug6652 0x800000000000LL // +#endif struct Match { @@ -136,7 +142,7 @@ struct Declaration : Dsymbol enum LINK linkage; int inuse; // used to detect cycles -#if IN_GCC +#ifdef IN_GCC Expressions *attributes; // GCC decl/type attributes #endif @@ -148,6 +154,8 @@ struct Declaration : Dsymbol unsigned size(Loc loc); void checkModify(Loc loc, Scope *sc, Type *t); + Dsymbol *search(Loc loc, Identifier *ident, int flags); + void emitComment(Scope *sc); void toJsonBuffer(OutBuffer *buf); void toDocBuffer(OutBuffer *buf); @@ -288,7 +296,7 @@ struct VarDeclaration : Declaration #else int nestedref; // referenced by a lexically nested function #endif - unsigned short alignment; + structalign_t alignment; int ctorinit; // it has been initialized in a ctor int onstack; // 1: it has been allocated on the stack // 2: on stack, run destructor anyway @@ -710,7 +718,7 @@ enum BUILTIN BUILTINbsr, // core.bitop.bsr BUILTINbsf, // core.bitop.bsf BUILTINbswap, // core.bitop.bswap -#if IN_GCC +#ifdef IN_GCC BUILTINgcc, // GCC builtin #endif }; @@ -738,12 +746,14 @@ struct FuncDeclaration : Declaration Identifier *outId; // identifier for out statement VarDeclaration *vresult; // variable corresponding to outId LabelDsymbol *returnLabel; // where the return goes + Scope *scout; // out contract scope for vresult->semantic DsymbolTable *localsymtab; // used to prevent symbols in different // scopes from having the same name VarDeclaration *vthis; // 'this' parameter (member and nested) VarDeclaration *v_arguments; // '_arguments' parameter -#if IN_GCC +#ifdef IN_GCC + VarDeclaration *v_arguments_var; // '_arguments' variable VarDeclaration *v_argptr; // '_argptr' variable #endif VarDeclaration *v_argsave; // save area for args passed in registers for variadic functions @@ -861,6 +871,7 @@ struct FuncDeclaration : Declaration void checkNestedReference(Scope *sc, Loc loc); int needsClosure(); int hasNestedFrameRefs(); + void buildResultVar(); Statement *mergeFrequire(Statement *, Expressions *params = 0); Statement *mergeFensure(Statement *, Expressions *params = 0); Parameters *getParameters(int *pvarargs); @@ -941,6 +952,7 @@ struct FuncAliasDeclaration : FuncDeclaration struct FuncLiteralDeclaration : FuncDeclaration { enum TOK tok; // TOKfunction or TOKdelegate + Type *treq; // target of return type inference FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type, enum TOK tok, ForeachStatement *fes); diff --git a/dmd2/dmd_msc.vcproj b/dmd2/dmd_msc.vcproj index 94a9e4f9..1d27f7e3 100644 --- a/dmd2/dmd_msc.vcproj +++ b/dmd2/dmd_msc.vcproj @@ -1,7 +1,7 @@ + + + + + + + + + + + + - - - - + RelativePath=".\root\dmgcmem.c" > - - - - + RelativePath=".\root\man.c" > + + + + + + + + + + + + + + + + + + @@ -1656,7 +1718,7 @@ @@ -1667,7 +1729,7 @@ @@ -1678,7 +1740,7 @@ diff --git a/dmd2/doc.c b/dmd2/doc.c index 4d8f104d..e9631c42 100644 --- a/dmd2/doc.c +++ b/dmd2/doc.c @@ -19,6 +19,10 @@ #include "rmem.h" #include "root.h" +#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ +#include "gnuc.h" +#endif + #include "mars.h" #include "dsymbol.h" #include "macro.h" @@ -77,7 +81,9 @@ struct DocComment Macro **pmacrotable; Escape **pescapetable; - DocComment(); + DocComment() : + summary(NULL), copyright(NULL), macros(NULL), pmacrotable(NULL), pescapetable(NULL) + { } static DocComment *parse(Scope *sc, Dsymbol *s, unsigned char *comment); static void parseMacros(Escape **pescapetable, Macro **pmacrotable, unsigned char *m, unsigned mlen); @@ -227,7 +233,7 @@ void Module::gendocfile() // Override with the ddoc macro files from the command line for (size_t i = 0; i < global.params.ddocfiles->dim; i++) { - FileName f(global.params.ddocfiles->tdata()[i], 0); + FileName f((*global.params.ddocfiles)[i], 0); File file(&f); file.readv(); // BUG: convert file contents to UTF-8 before use @@ -1014,11 +1020,6 @@ void EnumMember::toDocBuffer(OutBuffer *buf) /********************************* DocComment *********************************/ -DocComment::DocComment() -{ - memset(this, 0, sizeof(DocComment)); -} - DocComment *DocComment::parse(Scope *sc, Dsymbol *s, unsigned char *comment) { //printf("parse(%s): '%s'\n", s->toChars(), comment); @@ -1780,7 +1781,7 @@ void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) int leadingBlank = 1; int inCode = 0; - int inComment = 0; // in comment + //int inComment = 0; // in comment unsigned iCodeStart; // start of code section unsigned iLineStart = offset; diff --git a/dmd2/dsymbol.c b/dmd2/dsymbol.c index 71efca43..fdc799ed 100644 --- a/dmd2/dsymbol.c +++ b/dmd2/dsymbol.c @@ -624,7 +624,7 @@ void Dsymbol::error(const char *format, ...) } va_list ap; va_start(ap, format); - verror(loc, format, ap); + verror(loc, format, ap, kind(), toPrettyChars()); va_end(ap); } @@ -632,41 +632,10 @@ void Dsymbol::error(Loc loc, const char *format, ...) { va_list ap; va_start(ap, format); - verror(loc, format, ap); + verror(loc, format, ap, kind(), toPrettyChars()); va_end(ap); } -void Dsymbol::verror(Loc loc, const char *format, va_list ap) -{ - if (!global.gag) - { - char *p = loc.toChars(); - if (!*p) - p = locToChars(); - - if (*p) - fprintf(stdmsg, "%s: ", p); - mem.free(p); - - fprintf(stdmsg, "Error: "); - fprintf(stdmsg, "%s %s ", kind(), toPrettyChars()); - - vfprintf(stdmsg, format, ap); - - fprintf(stdmsg, "\n"); - fflush(stdmsg); -halt(); - } - else - { - global.gaggedErrors++; - } - - global.errors++; - - //fatal(); -} - void Dsymbol::checkDeprecated(Loc loc, Scope *sc) { if (!global.params.useDeprecated && isDeprecated()) @@ -903,7 +872,8 @@ Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags) s = s2; else if (s2 && s != s2) { - if (s->toAlias() == s2->toAlias()) + if (s->toAlias() == s2->toAlias() || + s->getType() == s2->getType() && s->getType()) { /* After following aliases, we found the same * symbol, so it's not an ambiguity. But if one @@ -1175,6 +1145,8 @@ int ScopeDsymbol::foreach(Scope *sc, Dsymbols *members, ScopeDsymbol::ForeachDg result = foreach(sc, tm->members, dg, ctx, &n); else if (s->isTemplateInstance()) ; + else if (s->isUnitTestDeclaration()) + ; else result = dg(ctx, n++, s); @@ -1423,6 +1395,7 @@ Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags) VoidInitializer *e = new VoidInitializer(0); e->type = Type::tsize_t; v->init = e; + v->storage_class |= STCctfe; // it's never a true static variable } *pvar = v; } diff --git a/dmd2/dsymbol.h b/dmd2/dsymbol.h index 850b880a..47f97f2a 100644 --- a/dmd2/dsymbol.h +++ b/dmd2/dsymbol.h @@ -90,7 +90,7 @@ struct TypeInfoDeclaration; struct ClassInfoDeclaration; #endif -#if IN_GCC +#ifdef IN_GCC union tree_node; typedef union tree_node TYPE; #else @@ -158,7 +158,6 @@ struct Dsymbol : Object int isAnonymous(); void error(Loc loc, const char *format, ...) IS_PRINTF(3); void error(const char *format, ...) IS_PRINTF(2); - void verror(Loc loc, const char *format, va_list ap); void checkDeprecated(Loc loc, Scope *sc); Module *getModule(); // module where declared Module *getAccessModule(); diff --git a/dmd2/dump.c b/dmd2/dump.c index c9e4f5ff..e0d43186 100644 --- a/dmd2/dump.c +++ b/dmd2/dump.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -36,7 +36,7 @@ void dumpExpressions(int i, Expressions *exps) if (exps) { for (size_t j = 0; j < exps->dim; j++) - { Expression *e = exps->tdata()[j]; + { Expression *e = (*exps)[j]; indent(i); printf("(\n"); e->dump(i + 2); diff --git a/dmd2/enum.c b/dmd2/enum.c index a09a7e93..93fc79c4 100644 --- a/dmd2/enum.c +++ b/dmd2/enum.c @@ -185,11 +185,11 @@ void EnumDeclaration::semantic(Scope *sc) { assert(e->dyncast() == DYNCAST_EXPRESSION); e = e->semantic(sce); - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); if (memtype) { e = e->implicitCastTo(sce, memtype); - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); if (!isAnonymous()) e = e->castTo(sce, type); t = memtype; @@ -197,7 +197,7 @@ void EnumDeclaration::semantic(Scope *sc) else if (em->type) { e = e->implicitCastTo(sce, em->type); - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); assert(isAnonymous()); t = e->type; } @@ -214,7 +214,7 @@ void EnumDeclaration::semantic(Scope *sc) t = Type::tint32; e = new IntegerExp(em->loc, 0, Type::tint32); e = e->implicitCastTo(sce, t); - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); if (!isAnonymous()) e = e->castTo(sce, type); } @@ -225,7 +225,7 @@ void EnumDeclaration::semantic(Scope *sc) { emax = t->getProperty(0, Id::max); emax = emax->semantic(sce); - emax = emax->optimize(WANTvalue | WANTinterpret); + emax = emax->ctfeInterpret(); } // Set value to (elast + 1). @@ -233,7 +233,7 @@ void EnumDeclaration::semantic(Scope *sc) assert(elast); e = new EqualExp(TOKequal, em->loc, elast, emax); e = e->semantic(sce); - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); if (e->toInteger()) error("overflow of enum value %s", elast->toChars()); @@ -241,14 +241,14 @@ void EnumDeclaration::semantic(Scope *sc) e = new AddExp(em->loc, elast, new IntegerExp(em->loc, 1, Type::tint32)); e = e->semantic(sce); e = e->castTo(sce, elast->type); - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); if (t->isfloating()) { // Check that e != elast (not always true for floats) Expression *etest = new EqualExp(TOKequal, em->loc, e, elast); etest = etest->semantic(sce); - etest = etest->optimize(WANTvalue | WANTinterpret); + etest = etest->ctfeInterpret(); if (etest->toInteger()) error("enum member %s has inexact value, due to loss of precision", em->toChars()); } @@ -298,13 +298,13 @@ void EnumDeclaration::semantic(Scope *sc) // Compute if(e < minval) ec = new CmpExp(TOKlt, em->loc, e, minval); ec = ec->semantic(sce); - ec = ec->optimize(WANTvalue | WANTinterpret); + ec = ec->ctfeInterpret(); if (ec->toInteger()) minval = e; ec = new CmpExp(TOKgt, em->loc, e, maxval); ec = ec->semantic(sce); - ec = ec->optimize(WANTvalue | WANTinterpret); + ec = ec->ctfeInterpret(); if (ec->toInteger()) maxval = e; } diff --git a/dmd2/enum.h b/dmd2/enum.h index c13d90ca..1c7d5e9d 100644 --- a/dmd2/enum.h +++ b/dmd2/enum.h @@ -42,7 +42,7 @@ struct EnumDeclaration : ScopeDsymbol int isdeprecated; int isdone; // 0: not done // 1: semantic() successfully completed -#if IN_GCC +#ifdef IN_GCC Expressions *attributes; // GCC decl/type attributes #endif diff --git a/dmd2/expression.c b/dmd2/expression.c index 6fd1d480..c898cdb9 100644 --- a/dmd2/expression.c +++ b/dmd2/expression.c @@ -1,4 +1,3 @@ - // Compiler implementation of the D programming language // Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved @@ -116,6 +115,7 @@ Expression *getRightThis(Loc loc, Scope *sc, AggregateDeclaration *ad, e1 = new DotVarExp(loc, e1, tcd->vthis); e1->type = tcd->vthis->type; + e1->type = e1->type->addMod(t->mod); // Do not call checkNestedRef() //e1 = e1->semantic(sc); @@ -151,6 +151,7 @@ Expression *getRightThis(Loc loc, Scope *sc, AggregateDeclaration *ad, } if (s && s->isClassDeclaration()) { e1->type = s->isClassDeclaration()->type; + e1->type = e1->type->addMod(t->mod); if (n > 1) e1 = e1->semantic(sc); } @@ -570,14 +571,14 @@ int expandAliasThisTuples(Expressions *exps, int starti) for (size_t u = starti; u < exps->dim; u++) { - Expression *exp = exps->tdata()[u]; + Expression *exp = (*exps)[u]; TupleDeclaration *td = isAliasThisTuple(exp); if (td) { exps->remove(u); for (size_t i = 0; iobjects->dim; ++i) { - Expression *e = isExpression(td->objects->tdata()[i]); + Expression *e = isExpression((*td->objects)[i]); assert(e); assert(e->op == TOKdsymbol); DsymbolExp *se = (DsymbolExp *)e; @@ -592,7 +593,7 @@ int expandAliasThisTuples(Expressions *exps, int starti) printf("expansion ->\n"); for (size_t i = 0; idim; ++i) { - Expression *e = exps->tdata()[i]; + Expression *e = (*exps)[i]; printf("\texps[%d] e = %s %s\n", i, Token::tochars[e->op], e->toChars()); } #endif @@ -738,6 +739,12 @@ void preFunctionParameters(Loc loc, Scope *sc, Expressions *exps) { Expression *arg = (*exps)[i]; arg = resolveProperties(sc, arg); +#if 0 + if (arg->op == TOKtype) + { arg->error("%s is not an expression", arg->toChars()); + arg = new ErrorExp(); + } +#endif (*exps)[i] = arg; //arg->rvalue(); @@ -794,24 +801,41 @@ void valueNoDtor(Expression *e) #if DMDV2 Expression *callCpCtor(Loc loc, Scope *sc, Expression *e, int noscope) { - Type *tb = e->type->toBasetype(); - assert(tb->ty == Tstruct); - StructDeclaration *sd = ((TypeStruct *)tb)->sym; - if (sd->cpctor) + if (e->op == TOKarrayliteral) { - /* Create a variable tmp, and replace the argument e with: - * (tmp = e),tmp - * and let AssignExp() handle the construction. - * This is not the most efficent, ideally tmp would be constructed - * directly onto the stack. - */ - Identifier *idtmp = Lexer::uniqueId("__cpcttmp"); - VarDeclaration *tmp = new VarDeclaration(loc, tb, idtmp, new ExpInitializer(0, e)); - tmp->storage_class |= STCctfe; - tmp->noscope = noscope; - Expression *ae = new DeclarationExp(loc, tmp); - e = new CommaExp(loc, ae, new VarExp(loc, tmp)); - e = e->semantic(sc); + ArrayLiteralExp *ae = (ArrayLiteralExp *)e; + for (size_t i = 0; i < ae->elements->dim; i++) + { + ae->elements->tdata()[i] = + callCpCtor(loc, sc, ae->elements->tdata()[i], noscope); + } + e = ae->semantic(sc); + return e; + } + + Type *tb = e->type->toBasetype(); + Type *tv = tb; + while (tv->ty == Tsarray) + tv = tv->nextOf()->toBasetype(); + if (tv->ty == Tstruct) + { + StructDeclaration *sd = ((TypeStruct *)tv)->sym; + if (sd->cpctor) + { + /* Create a variable tmp, and replace the argument e with: + * (tmp = e),tmp + * and let AssignExp() handle the construction. + * This is not the most efficent, ideally tmp would be constructed + * directly onto the stack. + */ + Identifier *idtmp = Lexer::uniqueId("__cpcttmp"); + VarDeclaration *tmp = new VarDeclaration(loc, tb, idtmp, new ExpInitializer(0, e)); + tmp->storage_class |= STCctfe; + tmp->noscope = noscope; + Expression *ae = new DeclarationExp(loc, tmp); + e = new CommaExp(loc, ae, new VarExp(loc, tmp)); + e = e->semantic(sc); + } } return e; } @@ -825,6 +849,8 @@ Expression *callCpCtor(Loc loc, Scope *sc, Expression *e, int noscope) * 3. do default promotions on arguments corresponding to ... * 4. add hidden _arguments[] argument * 5. call copy constructor for struct value arguments + * Input: + * fd the function being called, NULL if called indirectly * Returns: * return type from function */ @@ -877,7 +903,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, Expression *arg; if (i < nargs) - arg = arguments->tdata()[i]; + arg = (*arguments)[i]; else arg = NULL; @@ -887,7 +913,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, if (!arg) { - if (!p->defaultArg) + if (!p->defaultArg || !fd) { if (tf->varargs == 2 && i + 1 == nparams) goto L2; @@ -908,7 +934,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, if (tf->varargs == 2 && i + 1 == nparams && pt->nextOf()) pt = pt->nextOf(); arg = arg->inferType(pt, 2); - arguments->tdata()[i] = arg; + (*arguments)[i] = arg; } if (tf->varargs == 2 && i + 1 == nparams) @@ -958,7 +984,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, c->type = v->type; for (size_t u = i; u < nargs; u++) - { Expression *a = arguments->tdata()[u]; + { Expression *a = (*arguments)[u]; if (tret && !((TypeArray *)tb)->next->equals(a->type)) a = a->toDelegate(sc, tret); @@ -982,7 +1008,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, Expressions *args = new Expressions(); args->setDim(nargs - i); for (size_t u = i; u < nargs; u++) - args->tdata()[u - i] = arguments->tdata()[u]; + (*args)[u - i] = (*arguments)[u]; arg = new NewExp(loc, NULL, NULL, p->type, args); break; } @@ -996,7 +1022,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, arg = arg->semantic(sc); //printf("\targ = '%s'\n", arg->toChars()); arguments->setDim(i + 1); - arguments->tdata()[i] = arg; + (*arguments)[i] = arg; nargs = i + 1; done = 1; } @@ -1032,7 +1058,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, assert(nargs >= nparams); for (size_t i = 0; i < nargs; i++) { - Expression *arg = arguments->tdata()[i]; + Expression *arg = (*arguments)[i]; assert(arg); if (i < nparams) @@ -1097,45 +1123,50 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, { arg = arg->modifiableLvalue(sc, arg); } - - Type *tb = arg->type->toBasetype(); -// LDC we don't want this! -#if !IN_LLVM -#if !SARRAYVALUE - // Convert static arrays to pointers - if (tb->ty == Tsarray) - { - arg = arg->checkToPointer(); + else if (p->storageClass & STClazy) + { // Convert lazy argument to a delegate + arg = arg->toDelegate(sc, p->type); } -#endif -#endif -#if DMDV2 - if (tb->ty == Tstruct && !(p->storageClass & (STCref | STCout))) + else { - if (arg->op == TOKcall) + Type *tb = arg->type->toBasetype(); + if (arg->op == TOKarrayliteral) { - /* The struct value returned from the function is transferred - * to the function, so the callee should not call the destructor - * on it. - */ - valueNoDtor(arg); - } - else - { /* Not transferring it, so call the copy constructor - */ arg = callCpCtor(loc, sc, arg, 1); } - } + else if (tb->ty == Tsarray) + { +#if !SARRAYVALUE && !IN_LLVM + // Convert static arrays to pointers + arg = arg->checkToPointer(); +#else + // call copy constructor of each element + arg = callCpCtor(loc, sc, arg, 1); #endif + } +#if DMDV2 + else if (tb->ty == Tstruct) + { + if (arg->op == TOKcall && !arg->isLvalue()) + { + /* The struct value returned from the function is transferred + * to the function, so the callee should not call the destructor + * on it. + */ + valueNoDtor(arg); + } + else + { /* Not transferring it, so call the copy constructor + */ + arg = callCpCtor(loc, sc, arg, 1); + } + } +#endif + } //printf("arg: %s\n", arg->toChars()); //printf("type: %s\n", arg->type->toChars()); - // Convert lazy argument to a delegate - if (p->storageClass & STClazy) - { - arg = arg->toDelegate(sc, p->type); - } #if DMDV2 /* Look for arguments that cannot 'escape' from the called * function. @@ -1253,7 +1284,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, } arg = arg->optimize(WANTvalue); L3: - arguments->tdata()[i] = arg; + (*arguments)[i] = arg; } #if !IN_LLVM @@ -1434,13 +1465,16 @@ void Expression::print() } char *Expression::toChars() -{ OutBuffer *buf; +{ HdrGenState hgs; - memset(&hgs, 0, sizeof(hgs)); - buf = new OutBuffer(); - toCBuffer(buf, &hgs); - return buf->toChars(); + + OutBuffer buf; + toCBuffer(&buf, &hgs); + buf.writeByte(0); + char *p = (char *)buf.data; + buf.data = NULL; + return p; } void Expression::error(const char *format, ...) @@ -1548,12 +1582,12 @@ void Expression::toMangleBuffer(OutBuffer *buf) /*************************************** * Return !=0 if expression is an lvalue. */ -#if DMDV2 + int Expression::isLvalue() { return 0; } -#endif + /******************************* * Give error if we're not an lvalue. @@ -1934,7 +1968,7 @@ Expressions *Expression::arraySyntaxCopy(Expressions *exps) if (e) e = e->syntaxCopy(); - a->tdata()[i] = e; + (*a)[i] = e; } } return a; @@ -2814,12 +2848,12 @@ void IdentifierExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writestring(ident->toChars()); } -#if DMDV2 + int IdentifierExp::isLvalue() { return 1; } -#endif + Expression *IdentifierExp::toLvalue(Scope *sc, Expression *e) { @@ -2854,7 +2888,7 @@ AggregateDeclaration *isAggregate(Type *t); Expression *DsymbolExp::semantic(Scope *sc) { #if LOGSEMANTIC - printf("DsymbolExp::semantic('%s')\n", s->toChars()); + printf("DsymbolExp::semantic(%s %s)\n", s->kind(), s->toChars()); #endif Lagain: @@ -2872,7 +2906,7 @@ Lagain: //printf("DsymbolExp:: %p '%s' is a symbol\n", this, toChars()); //printf("s = '%s', s->kind = '%s'\n", s->toChars(), s->kind()); - if (type) + if (type && !s->needThis()) return this; if (!s->isFuncDeclaration()) // functions are checked after overloading checkDeprecated(sc, s); @@ -3038,6 +3072,24 @@ Lagain: TupleDeclaration *tup = s->isTupleDeclaration(); if (tup) { + for (size_t i = 0; i < tup->objects->dim; i++) + { + Dsymbol *sa = getDsymbol((*tup->objects)[i]); + if (sa && sa->needThis()) + { + if (hasThis(sc) +#if DMDV2 + && !sa->isFuncDeclaration() +#endif + ) + { + // Supply an implicit 'this', as in + // this.ident + (*tup->objects)[i] = new DotVarExp(loc, new ThisExp(loc), sa->isDeclaration()); + } + } + } + e = new TupleExp(loc, tup); e = e->semantic(sc); return e; @@ -3050,6 +3102,8 @@ Lagain: s = ti->toAlias(); if (!s->isTemplateInstance()) goto Lagain; + if (ti->errors) + return new ErrorExp(); e = new ScopeExp(loc, ti); e = e->semantic(sc); return e; @@ -3085,12 +3139,12 @@ void DsymbolExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writestring(s->toChars()); } -#if DMDV2 + int DsymbolExp::isLvalue() { return 1; } -#endif + Expression *DsymbolExp::toLvalue(Scope *sc, Expression *e) { @@ -3187,12 +3241,12 @@ void ThisExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writestring("this"); } -#if DMDV2 + int ThisExp::isLvalue() { return 1; } -#endif + Expression *ThisExp::toLvalue(Scope *sc, Expression *e) { @@ -3404,20 +3458,6 @@ int StringExp::equals(Object *o) return FALSE; } -char *StringExp::toChars() -{ - OutBuffer buf; - HdrGenState hgs; - char *p; - - memset(&hgs, 0, sizeof(hgs)); - toCBuffer(&buf, &hgs); - buf.writeByte(0); - p = (char *)buf.data; - buf.data = NULL; - return p; -} - Expression *StringExp::semantic(Scope *sc) { #if LOGSEMANTIC @@ -3625,7 +3665,7 @@ int StringExp::isBool(int result) return result ? TRUE : FALSE; } -#if DMDV2 + int StringExp::isLvalue() { /* string literal is rvalue in default, but @@ -3633,7 +3673,7 @@ int StringExp::isLvalue() */ return 0; } -#endif + Expression *StringExp::toLvalue(Scope *sc, Expression *e) { @@ -3783,6 +3823,7 @@ ArrayLiteralExp::ArrayLiteralExp(Loc loc, Expression *e) { elements = new Expressions; elements->push(e); + this->ownedByCtfe = false; } Expression *ArrayLiteralExp::syntaxCopy() @@ -3838,10 +3879,10 @@ StringExp *ArrayLiteralExp::toString() if (elements) for (int i = 0; i < elements->dim; ++i) { - Expression *ch = elements->tdata()[i]; + Expression *ch = (*elements)[i]; if (ch->op != TOKint64) return NULL; - buf.writedchar(ch->toInteger()); + buf.writeUTF8(ch->toInteger()); } buf.writebyte(0); @@ -3849,7 +3890,8 @@ StringExp *ArrayLiteralExp::toString() if (telem == Twchar) prefix = 'w'; else if (telem == Tdchar) prefix = 'd'; - StringExp *se = new StringExp(loc, buf.extractData(), buf.size - 1, prefix); + const size_t len = buf.offset - 1; + StringExp *se = new StringExp(loc, buf.extractData(), len, prefix); se->type = type; return se; } @@ -3868,7 +3910,7 @@ void ArrayLiteralExp::toMangleBuffer(OutBuffer *buf) size_t dim = elements ? elements->dim : 0; buf->printf("A%zu", dim); for (size_t i = 0; i < dim; i++) - { Expression *e = elements->tdata()[i]; + { Expression *e = (*elements)[i]; e->toMangleBuffer(buf); } } @@ -3937,8 +3979,8 @@ void AssocArrayLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writeByte('['); for (size_t i = 0; i < keys->dim; i++) - { Expression *key = keys->tdata()[i]; - Expression *value = values->tdata()[i]; + { Expression *key = (*keys)[i]; + Expression *value = (*values)[i]; if (i) buf->writeByte(','); @@ -3954,8 +3996,8 @@ void AssocArrayLiteralExp::toMangleBuffer(OutBuffer *buf) size_t dim = keys->dim; buf->printf("A%zu", dim); for (size_t i = 0; i < dim; i++) - { Expression *key = keys->tdata()[i]; - Expression *value = values->tdata()[i]; + { Expression *key = (*keys)[i]; + Expression *value = (*values)[i]; key->toMangleBuffer(buf); value->toMangleBuffer(buf); @@ -4008,7 +4050,7 @@ Expression *StructLiteralExp::semantic(Scope *sc) expandTuples(elements); size_t offset = 0; for (size_t i = 0; i < elements->dim; i++) - { e = elements->tdata()[i]; + { e = (*elements)[i]; if (!e) continue; @@ -4022,7 +4064,7 @@ Expression *StructLiteralExp::semantic(Scope *sc) error("more initializers than fields (%d) of %s", nfields, sd->toChars()); return new ErrorExp(); } - Dsymbol *s = sd->fields.tdata()[i]; + Dsymbol *s = sd->fields[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v); if (v->offset < offset) @@ -4043,13 +4085,13 @@ Expression *StructLiteralExp::semantic(Scope *sc) e = e->implicitCastTo(sc, telem); - elements->tdata()[i] = e; + (*elements)[i] = e; } /* Fill out remainder of elements[] with default initializers for fields[] */ for (size_t i = elements->dim; i < nfields; i++) - { Dsymbol *s = sd->fields.tdata()[i]; + { Dsymbol *s = sd->fields[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v); assert(!v->isThisDeclaration()); @@ -4072,7 +4114,7 @@ Expression *StructLiteralExp::semantic(Scope *sc) else if (v->scope) { // Do deferred semantic analysis Initializer *i2 = v->init->syntaxCopy(); - i2 = i2->semantic(v->scope, v->type, WANTinterpret); + i2 = i2->semantic(v->scope, v->type, INITinterpret); e = i2->toExpression(); // remove v->scope (see bug 3426) // but not if gagged, for we might be called again. @@ -4124,7 +4166,7 @@ Expression *StructLiteralExp::getField(Type *type, unsigned offset) { //printf("\ti = %d\n", i); assert(i < elements->dim); - e = elements->tdata()[i]; + e = (*elements)[i]; if (e) { //printf("e = %s, e->type = %s\n", e->toChars(), e->type->toChars()); @@ -4138,7 +4180,7 @@ Expression *StructLiteralExp::getField(Type *type, unsigned offset) Expressions *z = new Expressions; z->setDim(length); for (int q = 0; q < length; ++q) - z->tdata()[q] = e->copy(); + (*z)[q] = e->copy(); e = new ArrayLiteralExp(loc, z); e->type = type; } @@ -4165,13 +4207,13 @@ int StructLiteralExp::getFieldIndex(Type *type, unsigned offset) { for (size_t i = 0; i < sd->fields.dim; i++) { - Dsymbol *s = sd->fields.tdata()[i]; + Dsymbol *s = sd->fields[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v); if (offset == v->offset && type->size() == v->type->size()) - { Expression *e = elements->tdata()[i]; + { Expression *e = (*elements)[i]; if (e) { return i; @@ -4196,7 +4238,7 @@ void StructLiteralExp::toMangleBuffer(OutBuffer *buf) size_t dim = elements ? elements->dim : 0; buf->printf("S%zu", dim); for (size_t i = 0; i < dim; i++) - { Expression *e = elements->tdata()[i]; + { Expression *e = (*elements)[i]; if (e) e->toMangleBuffer(buf); else @@ -4239,8 +4281,32 @@ Expression *TypeExp::syntaxCopy() Expression *TypeExp::semantic(Scope *sc) { //printf("TypeExp::semantic(%s)\n", type->toChars()); - type = type->semantic(loc, sc); - return this; + Expression *e; + Type *t; + Dsymbol *s; + + type->resolve(loc, sc, &e, &t, &s); + if (e) + { + //printf("e = %s %s\n", Token::toChars(e->op), e->toChars()); + e = e->semantic(sc); + } + else if (t) + { + //printf("t = %d %s\n", t->ty, t->toChars()); + type = t->semantic(loc, sc); + e = this; + } + else if (s) + { + //printf("s = %s %s\n", s->kind(), s->toChars()); + e = new DsymbolExp(loc, s, s->hasOverloads()); + e = e->semantic(sc); + } + else + assert(0); + + return e; } int TypeExp::rvalue() @@ -4289,6 +4355,8 @@ Lagain: ti->semantic(sc); if (ti->inst) { + if (ti->inst->errors) + return new ErrorExp(); Dsymbol *s = ti->inst->toAlias(); sds2 = s->isScopeDsymbol(); if (!sds2) @@ -4302,7 +4370,7 @@ Lagain: e = new DotVarExp(loc, e, s->isDeclaration()); } else - e = new DsymbolExp(loc, s); + e = new DsymbolExp(loc, s, s->hasOverloads()); e = e->semantic(sc); //printf("-1ScopeExp::semantic()\n"); return e; @@ -4425,6 +4493,13 @@ Lagain: sc = sc->push(cdthis); type = newtype->semantic(loc, sc); sc = sc->pop(); + + if (!MODimplicitConv(thisexp->type->mod, newtype->mod)) + { + error("nested type %s should have the same or weaker constancy as enclosing type %s", + newtype->toChars(), thisexp->type->toChars()); + goto Lerr; + } } else { @@ -4459,7 +4534,7 @@ Lagain: else if (cd->isAbstract()) { error("cannot create instance of abstract class %s", cd->toChars()); for (size_t i = 0; i < cd->vtbl.dim; i++) - { FuncDeclaration *fd = cd->vtbl.tdata()[i]->isFuncDeclaration(); + { FuncDeclaration *fd = cd->vtbl[i]->isFuncDeclaration(); if (fd && fd->isAbstract()) error("function %s is abstract", fd->toChars()); } @@ -4712,7 +4787,7 @@ Lagain: goto Lerr; } - Expression *arg = arguments->tdata()[i]; + Expression *arg = (*arguments)[i]; arg = resolveProperties(sc, arg); arg = arg->implicitCastTo(sc, Type::tsize_t); arg = arg->optimize(WANTvalue); @@ -4720,7 +4795,7 @@ Lagain: { error("negative array index %s", arg->toChars()); goto Lerr; } - arguments->tdata()[i] = arg; + (*arguments)[i] = arg; tb = ((TypeDArray *)tb)->next->toBasetype(); } } @@ -5018,14 +5093,14 @@ void VarExp::checkEscapeRef() } } -#if DMDV2 + int VarExp::isLvalue() { - if (var->storage_class & STClazy) + if (var->storage_class & (STClazy | STCtemp)) return 0; return 1; } -#endif + Expression *VarExp::toLvalue(Scope *sc, Expression *e) { @@ -5049,6 +5124,16 @@ Expression *VarExp::modifiableLvalue(Scope *sc, Expression *e) //if (type && type->toBasetype()->ty == Tsarray) //error("cannot change reference to static array '%s'", var->toChars()); +#if (BUG6652 == 1) + VarDeclaration *v = var->isVarDeclaration(); + if (v && (v->storage_class & STCbug6652) && global.params.warnings) + warning("Variable modified in foreach body requires ref storage class"); +#elif (BUG6652 == 2) + VarDeclaration *v = var->isVarDeclaration(); + if (v && (v->storage_class & STCbug6652) && !global.params.useDeprecated) + error("Variable modified in foreach body requires ref storage class"); +#endif + var->checkModify(loc, sc, type); // See if this expression is a modifiable lvalue (i.e. not const) @@ -5098,7 +5183,7 @@ TupleExp::TupleExp(Loc loc, TupleDeclaration *tup) exps->reserve(tup->objects->dim); for (size_t i = 0; i < tup->objects->dim; i++) - { Object *o = tup->objects->tdata()[i]; + { Object *o = (*tup->objects)[i]; if (o->dyncast() == DYNCAST_EXPRESSION) { Expression *e = (Expression *)o; @@ -5202,7 +5287,6 @@ FuncExp::FuncExp(Loc loc, FuncLiteralDeclaration *fd, TemplateDeclaration *td) this->fd = fd; this->td = td; tok = fd->tok; // save original kind of function/delegate/(infer) - treq = NULL; } Expression *FuncExp::syntaxCopy() @@ -5215,36 +5299,41 @@ Expression *FuncExp::semantic(Scope *sc) { #if LOGSEMANTIC printf("FuncExp::semantic(%s)\n", toChars()); - if (treq) printf(" treq = %s\n", treq->toChars()); + if (fd->treq) printf(" treq = %s\n", fd->treq->toChars()); #endif if (!type || type == Type::tvoid) { - if (treq) - treq = treq->semantic(loc, sc); + /* fd->treq might be incomplete type, + * so should not semantic it. + * void foo(T)(T delegate(int) dg){} + * foo(a=>a); // in IFTI, treq == T delegate(int) + */ + //if (fd->treq) + // fd->treq = fd->treq->semantic(loc, sc); // Set target of return type inference - if (treq && !fd->type->nextOf()) + if (fd->treq && !fd->type->nextOf()) { TypeFunction *tfv = NULL; - if (treq->ty == Tdelegate || - (treq->ty == Tpointer && treq->nextOf()->ty == Tfunction)) - tfv = (TypeFunction *)treq->nextOf(); + if (fd->treq->ty == Tdelegate || + (fd->treq->ty == Tpointer && fd->treq->nextOf()->ty == Tfunction)) + tfv = (TypeFunction *)fd->treq->nextOf(); if (tfv) { TypeFunction *tfl = (TypeFunction *)fd->type; tfl->next = tfv->nextOf(); } } - //printf("td = %p, treq = %p\n", td, treq); + //printf("td = %p, treq = %p\n", td, fd->treq); if (td) { assert(td->parameters && td->parameters->dim); td->semantic(sc); type = Type::tvoid; // temporary type - if (!treq) // defer type determination + if (!fd->treq) // defer type determination return this; - return inferType(treq); + return inferType(fd->treq); } unsigned olderrors = global.errors; @@ -5273,14 +5362,32 @@ Expression *FuncExp::semantic(Scope *sc) // Type is a "delegate to" or "pointer to" the function literal if ((fd->isNested() && fd->tok == TOKdelegate) || - (tok == TOKreserved && treq && treq->ty == Tdelegate)) + (tok == TOKreserved && fd->treq && fd->treq->ty == Tdelegate)) { type = new TypeDelegate(fd->type); type = type->semantic(loc, sc); + + fd->tok = TOKdelegate; } else { - type = fd->type->pointerTo(); + type = new TypePointer(fd->type); + type = type->semantic(loc, sc); + //type = fd->type->pointerTo(); + + /* A lambda expression deduced to function pointer might become + * to a delegate literal implicitly. + * + * auto foo(void function() fp) { return 1; } + * assert(foo({}) == 1); + * + * So, should keep fd->tok == TOKreserve if fd->treq == NULL. + */ + if (fd->treq && fd->treq->ty == Tpointer) + { // change to non-nested + fd->tok = TOKfunction; + fd->vthis = NULL; + } } fd->tookAddressOf++; } @@ -5293,7 +5400,7 @@ Expression *FuncExp::semantic(Scope *sc, Expressions *arguments) if ((!type || type == Type::tvoid) && td && arguments && arguments->dim) { for (size_t k = 0; k < arguments->dim; k++) - { Expression *checkarg = arguments->tdata()[k]; + { Expression *checkarg = (*arguments)[k]; if (checkarg->op == TOKerror) return checkarg; } @@ -5303,6 +5410,12 @@ Expression *FuncExp::semantic(Scope *sc, Expressions *arguments) TypeFunction *tfl = (TypeFunction *)fd->type; size_t dim = Parameter::dim(tfl->parameters); + if (arguments->dim < dim) + { // Default arguments are always typed, so they don't need inference. + Parameter *p = Parameter::getNth(tfl->parameters, arguments->dim); + if (p->defaultArg) + dim = arguments->dim; + } if ((!tfl->varargs && arguments->dim == dim) || ( tfl->varargs && arguments->dim >= dim)) @@ -5379,7 +5492,7 @@ Expression *DeclarationExp::semantic(Scope *sc) if (ad) { if (ad->decl && ad->decl->dim == 1) - s = ad->decl->tdata()[0]; + s = (*ad->decl)[0]; } if (s->isVarDeclaration()) @@ -5570,7 +5683,7 @@ void TraitsExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) for (size_t i = 0; i < args->dim; i++) { buf->writeByte(','); - Object *oarg = args->tdata()[i]; + Object *oarg = (*args)[i]; ObjectToCBuffer(buf, hgs, oarg); } } @@ -5623,8 +5736,8 @@ Expression *IsExp::syntaxCopy() p = new TemplateParameters(); p->setDim(parameters->dim); for (size_t i = 0; i < p->dim; i++) - { TemplateParameter *tp = parameters->tdata()[i]; - p->tdata()[i] = tp->syntaxCopy(); + { TemplateParameter *tp = (*parameters)[i]; + (*p)[i] = tp->syntaxCopy(); } } @@ -5734,7 +5847,7 @@ Expression *IsExp::semantic(Scope *sc) Parameters *args = new Parameters; args->reserve(cd->baseclasses->dim); for (size_t i = 0; i < cd->baseclasses->dim; i++) - { BaseClass *b = cd->baseclasses->tdata()[i]; + { BaseClass *b = (*cd->baseclasses)[i]; args->push(new Parameter(STCin, b->type, NULL, NULL)); } tded = new TypeTuple(args); @@ -5754,6 +5867,7 @@ Expression *IsExp::semantic(Scope *sc) break; case TOKfunction: + case TOKparameters: { if (targ->ty != Tfunction) goto Lno; @@ -5769,7 +5883,9 @@ Expression *IsExp::semantic(Scope *sc) for (size_t i = 0; i < dim; i++) { Parameter *arg = Parameter::getNth(params, i); assert(arg && arg->type); - args->push(new Parameter(arg->storageClass, arg->type, NULL, NULL)); + args->push(new Parameter(arg->storageClass, arg->type, + (tok2 == TOKparameters) ? arg->ident : NULL, + (tok2 == TOKparameters) ? arg->defaultArg : NULL)); } tded = new TypeTuple(args); break; @@ -5831,13 +5947,13 @@ Expression *IsExp::semantic(Scope *sc) } else { - tded = (Type *)dedtypes.tdata()[0]; + tded = (Type *)dedtypes[0]; if (!tded) tded = targ; #if DMDV2 Objects tiargs; tiargs.setDim(1); - tiargs.tdata()[0] = targ; + tiargs[0] = targ; /* Declare trailing parameters */ @@ -5936,7 +6052,7 @@ void IsExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) for (size_t i = 1; i < parameters->dim; i++) { buf->writeByte(','); - TemplateParameter *tp = parameters->tdata()[i]; + TemplateParameter *tp = (*parameters)[i]; tp->toCBuffer(buf, hgs); } } @@ -6342,7 +6458,7 @@ Expression *CompileExp::semantic(Scope *sc) error("argument to mixin must be a string type, not %s\n", e1->type->toChars()); return new ErrorExp(); } - e1 = e1->optimize(WANTvalue | WANTinterpret); + e1 = e1->ctfeInterpret(); StringExp *se = e1->toString(); if (!se) { error("argument to mixin must be a string, not (%s)", e1->toChars()); @@ -6384,7 +6500,7 @@ Expression *FileExp::semantic(Scope *sc) #endif UnaExp::semantic(sc); e1 = resolveProperties(sc, e1); - e1 = e1->optimize(WANTvalue | WANTinterpret); + e1 = e1->ctfeInterpret(); if (e1->op != TOKstring) { error("file name argument must be a string, not (%s)", e1->toChars()); goto Lerror; @@ -6576,8 +6692,30 @@ Expression *DotIdExp::semantic(Scope *sc, int flag) } } +// Type *t1save = e1->type; + UnaExp::semantic(sc); +#if 0 + /* + * Identify typeof(var).stringof and use the original type of var, if possible + */ + if (ident == Id::stringof && e1->op == TOKtype && t1save && t1save->ty == Ttypeof) + { TypeTypeof *t = (TypeTypeof *)t1save; + if (t->exp->op == TOKvar) + { + Type *ot = ((VarExp *)t->exp)->var->originalType; + if (ot) + { + char *s = ((VarExp *)t->exp)->var->originalType->toChars(); + e = new StringExp(loc, s, strlen(s), 'c'); + e = e->semantic(sc); + return e; + } + } + } +#endif + if (ident == Id::mangleof) { // symbol.mangleof Dsymbol *ds; @@ -6918,7 +7056,7 @@ Expression *DotVarExp::semantic(Scope *sc) exps->reserve(tup->objects->dim); for (size_t i = 0; i < tup->objects->dim; i++) - { Object *o = tup->objects->tdata()[i]; + { Object *o = (*tup->objects)[i]; if (o->dyncast() != DYNCAST_EXPRESSION) { error("%s is not an expression", o->toChars()); @@ -7003,12 +7141,12 @@ Lerr: return new ErrorExp(); } -#if DMDV2 + int DotVarExp::isLvalue() { return 1; } -#endif + Expression *DotVarExp::toLvalue(Scope *sc, Expression *e) { @@ -7153,15 +7291,31 @@ Expression *DotTemplateInstanceExp::semantic(Scope *sc, int flag) #endif UnaExp::semantic(sc); - Expression *e = new DotIdExp(loc, e1, ti->name); + if (e1->op == TOKerror) + return e1; - if (e1->op == TOKimport && ((ScopeExp *)e1)->sds->isModule()) - e = ((DotIdExp *)e)->semantic(sc, 1); + Expression *e; + DotIdExp *die = new DotIdExp(loc, e1, ti->name); + + if (flag || !e1->type || e1->op == TOKtype || + e1->op == TOKimport && ((ScopeExp *)e1)->sds->isModule()) + { + e = die->semantic(sc, 1); + } else { + Type *t1b = e1->type->toBasetype(); + if ((t1b->ty == Tarray || t1b->ty == Tsarray || t1b->ty == Taarray || + t1b->ty == Tnull || t1b->isTypeBasic() && t1b->ty != Tvoid)) + { + /* No built-in type has templatized property, so can short cut. + */ + return resolveUFCSProperties(sc, this); + } + unsigned errors = global.startGagging(); - e = ((DotIdExp *)e)->semantic(sc, 1); - if (global.endGagging(errors) && !flag) + e = die->semantic(sc, 1); + if (global.endGagging(errors)) { return resolveUFCSProperties(sc, this); } @@ -7367,7 +7521,7 @@ CallExp::CallExp(Loc loc, Expression *e, Expression *earg1) Expressions *arguments = new Expressions(); if (earg1) { arguments->setDim(1); - arguments->tdata()[0] = earg1; + (*arguments)[0] = earg1; } this->arguments = arguments; } @@ -7377,8 +7531,8 @@ CallExp::CallExp(Loc loc, Expression *e, Expression *earg1, Expression *earg2) { Expressions *arguments = new Expressions(); arguments->setDim(2); - arguments->tdata()[0] = earg1; - arguments->tdata()[1] = earg2; + (*arguments)[0] = earg1; + (*arguments)[1] = earg2; this->arguments = arguments; } @@ -7391,162 +7545,128 @@ Expression *CallExp::syntaxCopy() Expression *CallExp::resolveUFCS(Scope *sc) { - Expression *e = NULL; - DotIdExp *dotid; - DotTemplateInstanceExp *dotti; + Expression *e; Identifier *ident; + Objects *tiargs; if (e1->op == TOKdot) { - dotid = (DotIdExp *)e1; - ident = dotid->ident; - e = dotid->e1 = dotid->e1->semantic(sc); - if (e->op == TOKdotexp) - return NULL; - e = resolveProperties(sc, e); + DotIdExp *die = (DotIdExp *)e1; + e = (die->e1 = die->e1->semantic(sc)); + ident = die->ident; + tiargs = NULL; } else if (e1->op == TOKdotti) { - dotti = (DotTemplateInstanceExp *)e1; - ident = dotti->ti->name; - e = dotti->e1 = dotti->e1->semantic(sc); - if (e->op == TOKdotexp) - return NULL; - e = resolveProperties(sc, e); + DotTemplateInstanceExp *dti = (DotTemplateInstanceExp *)e1; + e = (dti->e1 = dti->e1->semantic(sc)); + ident = dti->ti->name; + tiargs = dti->ti->tiargs; } + else + return NULL; - if (e && e->type) + if (e->op == TOKerror || !e->type) + return NULL; + + if (e->op == TOKtype || e->op == TOKimport || e->op == TOKdotexp) + return NULL; + + e = resolveProperties(sc, e); + + Type *t = e->type->toBasetype(); + //printf("resolveUCSS %s, e = %s, %s, %s\n", + // toChars(), Token::toChars(e->op), t->toChars(), e->toChars()); + if (t->ty == Taarray) { - if (e->op == TOKtype || e->op == TOKimport) + if (tiargs) + { + goto Lshift; + } + else if (ident == Id::remove) + { + /* Transform: + * aa.remove(arg) into delete aa[arg] + */ + if (!arguments || arguments->dim != 1) + { error("expected key as argument to aa.remove()"); + return new ErrorExp(); + } + if (!e->type->isMutable()) + { const char *p = NULL; + if (e->type->isConst()) + p = "const"; + else if (e->type->isImmutable()) + p = "immutable"; + else + p = "inout"; + error("cannot remove key from %s associative array %s", p, e->toChars()); + return new ErrorExp(); + } + Expression *key = (*arguments)[0]; + key = key->semantic(sc); + key = resolveProperties(sc, key); + + TypeAArray *taa = (TypeAArray *)t; + key = key->implicitCastTo(sc, taa->index); + + if (!key->rvalue()) + return new ErrorExp(); + + return new RemoveExp(loc, e, key); + } + else if (ident == Id::apply || ident == Id::applyReverse) + { return NULL; - //printf("resolveUCSS %s, e->op = %s\n", toChars(), Token::toChars(e->op)); - AggregateDeclaration *ad; - Expression *esave = e; -Lagain: - Type *t = e->type->toBasetype(); - if (t->ty == Tpointer) - { Type *tn = t->nextOf(); - if (tn->ty == Tclass || tn->ty == Tstruct) - { - e = new PtrExp(e->loc, e); - e = e->semantic(sc); - t = e->type->toBasetype(); - } } - if (t->ty == Tclass) - { - ad = ((TypeClass *)t)->sym; - goto L1; - } - else if (t->ty == Tstruct) - { - ad = ((TypeStruct *)t)->sym; - L1: - if (ad->search(loc, ident, 0)) + else + { TypeAArray *taa = (TypeAArray *)t; + assert(taa->ty == Taarray); + StructDeclaration *sd = taa->getImpl(); + Dsymbol *s = sd->search(0, ident, 2); + if (s) return NULL; - if (ad->aliasthis) - { - e = resolveAliasThis(sc, e); - goto Lagain; - } - if (ad->search(loc, Id::opDot, 0)) - { - e = new DotIdExp(e->loc, e, Id::opDot); - e = e->semantic(sc); - e = resolveProperties(sc, e); - goto Lagain; - } - if (ad->search(loc, Id::opDispatch, 0)) - return NULL; - e = esave; goto Lshift; } - else if ((t->isTypeBasic() && t->ty != Tvoid) || - t->ty == Tenum || t->ty == Tnull) - { - goto Lshift; - } - else if (t->ty == Taarray && e1->op == TOKdot) - { - if (ident == Id::remove) - { - /* Transform: - * aa.remove(arg) into delete aa[arg] - */ - if (!arguments || arguments->dim != 1) - { error("expected key as argument to aa.remove()"); - return new ErrorExp(); - } - if (!e->type->isMutable()) - { const char *p = NULL; - if (e->type->isConst()) - p = "const"; - else if (e->type->isImmutable()) - p = "immutable"; - else - p = "inout"; - error("cannot remove key from %s associative array %s", p, e->toChars()); - return new ErrorExp(); - } - Expression *key = arguments->tdata()[0]; - key = key->semantic(sc); - key = resolveProperties(sc, key); - - TypeAArray *taa = (TypeAArray *)t; - key = key->implicitCastTo(sc, taa->index); - - if (!key->rvalue()) - return new ErrorExp(); - - return new RemoveExp(loc, e, key); - } - else if (ident == Id::apply || ident == Id::applyReverse) - { - return NULL; - } - else - { TypeAArray *taa = (TypeAArray *)t; - assert(taa->ty == Taarray); - StructDeclaration *sd = taa->getImpl(); - Dsymbol *s = sd->search(0, ident, 2); - if (s) - return NULL; - goto Lshift; - } - } - else if (t->ty == Tarray || t->ty == Tsarray) - { + } + else if (t->ty == Tarray || t->ty == Tsarray || + t->ty == Tnull || t->isTypeBasic() && t->ty != Tvoid) + { + /* In basic, built-in types don't have normal and templatized + * member functions. So can short cut. + */ Lshift: - if (!arguments) - arguments = new Expressions(); - arguments->shift(e); - if (e1->op == TOKdot) - { - /* Transform: - * array.id(args) into .id(array,args) - */ -#if DMDV2 - e1 = new DotIdExp(dotid->loc, - new IdentifierExp(dotid->loc, Id::empty), - ident); -#else - e1 = new IdentifierExp(dotid->loc, ident); -#endif - } - else if (e1->op == TOKdotti) - { - /* Transform: - * array.foo!(tiargs)(args) into .foo!(tiargs)(array,args) - */ -#if DMDV2 - e1 = new DotTemplateInstanceExp(dotti->loc, - new IdentifierExp(dotti->loc, Id::empty), - dotti->ti->name, dotti->ti->tiargs); -#else - e1 = new ScopeExp(dotti->loc, dotti->ti); -#endif - } - //printf("-> this = %s\n", toChars()); + if (!arguments) + arguments = new Expressions(); + arguments->shift(e); + if (!tiargs) + { + /* Transform: + * array.id(args) into .id(array,args) + */ + e1 = new DotIdExp(e1->loc, + new IdentifierExp(e1->loc, Id::empty), + ident); + } + else + { + /* Transform: + * array.foo!(tiargs)(args) into .foo!(tiargs)(array,args) + */ + e1 = new DotTemplateInstanceExp(e1->loc, + new IdentifierExp(e1->loc, Id::empty), + ident, tiargs); + } + } + else + { + DotIdExp *die = new DotIdExp(e->loc, e, ident); + + unsigned errors = global.startGagging(); + Expression *ex = die->semantic(sc, 1); + if (global.endGagging(errors)) + { + goto Lshift; } } return NULL; @@ -7568,7 +7688,7 @@ Expression *CallExp::semantic(Scope *sc) #if 0 if (arguments && arguments->dim) { - Expression *earg = arguments->tdata()[0]; + Expression *earg = (*arguments)[0]; earg->print(); if (earg->type) earg->type->print(); } @@ -7836,7 +7956,13 @@ Lagain: goto L1; // overload of opCall, therefore it's a call if (e1->op != TOKtype) - { error("%s %s does not overload ()", ad->kind(), ad->toChars()); + { + if (ad->aliasthis) + { + e1 = resolveAliasThis(sc, e1); + goto Lagain; + } + error("%s %s does not overload ()", ad->kind(), ad->toChars()); return new ErrorExp(); } @@ -7867,7 +7993,7 @@ Lagain: if (arguments && arguments->dim) { for (size_t k = 0; k < arguments->dim; k++) - { Expression *checkarg = arguments->tdata()[k]; + { Expression *checkarg = (*arguments)[k]; if (checkarg->op == TOKerror) return checkarg; } @@ -7880,7 +8006,7 @@ Lagain: if (targsi && targsi->dim) { for (size_t k = 0; k < targsi->dim; k++) - { Object *o = targsi->tdata()[k]; + { Object *o = (*targsi)[k]; if (isError(o)) return new ErrorExp(); } @@ -7894,13 +8020,23 @@ Lagain: AggregateDeclaration *ad; UnaExp *ue = (UnaExp *)(e1); + Expression *ue1 = ue->e1; + VarDeclaration *v; + if (ue1->op == TOKvar && + (v = ((VarExp *)ue1)->var->isVarDeclaration()) != NULL && + v->needThis()) + { + ue->e1 = new TypeExp(ue1->loc, ue1->type); + ue1 = NULL; + } + if (e1->op == TOKdotvar) { // Do overload resolution dve = (DotVarExp *)(e1); f = dve->var->isFuncDeclaration(); assert(f); - f = f->overloadResolve(loc, ue->e1, arguments); + f = f->overloadResolve(loc, ue1, arguments); ad = f->toParent()->isAggregateDeclaration(); } @@ -7911,7 +8047,7 @@ Lagain: if (!arguments) // Should fix deduceFunctionTemplate() so it works on NULL argument arguments = new Expressions(); - f = td->deduceFunctionTemplate(sc, loc, targsi, ue->e1, arguments); + f = td->deduceFunctionTemplate(sc, loc, targsi, ue1, arguments); if (!f) return new ErrorExp(); ad = td->toParent()->isAggregateDeclaration(); @@ -7960,6 +8096,7 @@ Lagain: { e1 = new DotVarExp(loc, dte->e1, f); e1 = e1->semantic(sc); + ue = (UnaExp *)e1; } #if 0 printf("ue->e1 = %s\n", ue->e1->toChars()); @@ -8115,7 +8252,7 @@ Lagain: FuncDeclaration *f = NULL; Dsymbol *s = NULL; for (size_t i = 0; i < eo->vars->a.dim; i++) - { s = eo->vars->a.tdata()[i]; + { s = eo->vars->a[i]; FuncDeclaration *f2 = s->isFuncDeclaration(); if (f2) { @@ -8157,7 +8294,17 @@ Lagain: { TypeFunction *tf; const char *p; - if (t1->ty == Tdelegate) + if (e1->op == TOKfunction) + { + // function literal that direct called is always inferred. + assert(((FuncExp *)e1)->fd); + f = ((FuncExp *)e1)->fd; + tf = (TypeFunction *)f->type; + p = "function literal"; + + f->checkNestedReference(sc, loc); + } + else if (t1->ty == Tdelegate) { TypeDelegate *td = (TypeDelegate *)t1; assert(td->next->ty == Tfunction); tf = (TypeFunction *)(td->next); @@ -8222,7 +8369,7 @@ Lagain: else buf.writeByte(')'); - //printf("tf = %s, args = %s\n", tf->deco, arguments->tdata()[0]->type->deco); + //printf("tf = %s, args = %s\n", tf->deco, (*arguments)[0]->type->deco); ::error(loc, "%s %s %s is not callable using argument types %s", p, e1->toChars(), Parameter::argsTypesToChars(tf->parameters, tf->varargs), buf.toChars()); @@ -8306,10 +8453,12 @@ Lagain: } -#if DMDV2 + int CallExp::isLvalue() { Type *tb = e1->type->toBasetype(); + if (tb->ty == Tdelegate || tb->ty == Tpointer) + tb = tb->nextOf(); if (tb->ty == Tfunction && ((TypeFunction *)tb)->isref) { if (e1->op == TOKdotvar) @@ -8319,7 +8468,7 @@ int CallExp::isLvalue() } return 0; } -#endif + Expression *CallExp::toLvalue(Scope *sc, Expression *e) { @@ -8404,8 +8553,10 @@ Expression *AddrExp::semantic(Scope *sc) m = sc->module; #endif UnaExp::semantic(sc); + Expression *olde1 = e1; if (e1->type == Type::terror) return new ErrorExp(); + int wasCond = e1->op == TOKquestion; e1 = e1->toLvalue(sc, NULL); if (e1->op == TOKerror) return e1; @@ -8515,6 +8666,24 @@ Expression *AddrExp::semantic(Scope *sc) } } } + else if (wasCond) + { + /* a ? b : c was transformed to *(a ? &b : &c), but we still + * need to do safety checks + */ + assert(e1->op == TOKstar); + PtrExp *pe = (PtrExp *)e1; + assert(pe->e1->op == TOKquestion); + CondExp *ce = (CondExp *)pe->e1; + assert(ce->e1->op == TOKaddress); + assert(ce->e2->op == TOKaddress); + + // Re-run semantic on the address expressions only + ce->e1->type = NULL; + ce->e1 = ce->e1->semantic(sc); + ce->e2->type = NULL; + ce->e2 = ce->e2->semantic(sc); + } return optimize(WANTvalue); } return this; @@ -8576,12 +8745,12 @@ Expression *PtrExp::semantic(Scope *sc) return this; } -#if DMDV2 + int PtrExp::isLvalue() { return 1; } -#endif + void PtrExp::checkEscapeRef() { @@ -8992,6 +9161,12 @@ Expression *CastExp::semantic(Scope *sc) { return new VectorExp(loc, e1, to); } + + if (tob->isintegral() && t1b->ty == Tarray && + !global.params.useDeprecated) + { + error("casting %s to %s is deprecated", e1->type->toChars(), to->toChars()); + } } else if (!to) { error("cannot cast tuple"); @@ -9122,7 +9297,7 @@ VectorExp::VectorExp(Loc loc, Expression *e, Type *t) : UnaExp(loc, TOKvector, sizeof(VectorExp), e) { assert(t->ty == Tvector); - to = t; + to = (TypeVector *)t; dim = ~0; } @@ -9295,8 +9470,8 @@ Lagain: if (t->ty == Ttuple) { - lwr = lwr->optimize(WANTvalue | WANTinterpret); - upr = upr->optimize(WANTvalue | WANTinterpret); + lwr = lwr->ctfeInterpret(); + upr = upr->ctfeInterpret(); uinteger_t i1 = lwr->toUInteger(); uinteger_t i2 = upr->toUInteger(); @@ -9384,12 +9559,12 @@ void SliceExp::checkEscapeRef() e1->checkEscapeRef(); } -#if DMDV2 + int SliceExp::isLvalue() { return 1; } -#endif + Expression *SliceExp::toLvalue(Scope *sc, Expression *e) { @@ -9540,6 +9715,8 @@ Expression *ArrayExp::semantic(Scope *sc) #endif UnaExp::semantic(sc); e1 = resolveProperties(sc, e1); + if (e1->op == TOKerror) + return e1; t1 = e1->type->toBasetype(); if (t1->ty != Tclass && t1->ty != Tstruct) @@ -9548,7 +9725,7 @@ Expression *ArrayExp::semantic(Scope *sc) { error("only one index allowed to index %s", t1->toChars()); goto Lerr; } - e = new IndexExp(loc, e1, arguments->tdata()[0]); + e = new IndexExp(loc, e1, (*arguments)[0]); return e->semantic(sc); } @@ -9563,14 +9740,14 @@ Lerr: return new ErrorExp(); } -#if DMDV2 + int ArrayExp::isLvalue() { if (type && type->toBasetype()->ty == Tvoid) return 0; return 1; } -#endif + Expression *ArrayExp::toLvalue(Scope *sc, Expression *e) { @@ -9652,12 +9829,12 @@ void CommaExp::checkEscapeRef() e2->checkEscapeRef(); } -#if DMDV2 + int CommaExp::isLvalue() { return e2->isLvalue(); } -#endif + Expression *CommaExp::toLvalue(Scope *sc, Expression *e) { @@ -9736,7 +9913,7 @@ Expression *IndexExp::semantic(Scope *sc) if (e2->type == Type::terror) goto Lerr; if (e2->type->ty == Ttuple && ((TupleExp *)e2)->exps->dim == 1) // bug 4444 fix - e2 = ((TupleExp *)e2)->exps->tdata()[0]; + e2 = (*((TupleExp *)e2)->exps)[0]; if (t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Ttuple) sc = sc->pop(); @@ -9787,7 +9964,7 @@ Expression *IndexExp::semantic(Scope *sc) case Ttuple: { e2 = e2->implicitCastTo(sc, Type::tsize_t); - e2 = e2->optimize(WANTvalue | WANTinterpret); + e2 = e2->ctfeInterpret(); uinteger_t index = e2->toUInteger(); size_t length; TupleExp *te; @@ -9844,12 +10021,12 @@ Lerr: return new ErrorExp(); } -#if DMDV2 + int IndexExp::isLvalue() { return 1; } -#endif + Expression *IndexExp::toLvalue(Scope *sc, Expression *e) { @@ -10064,7 +10241,7 @@ Expression *AssignExp::semantic(Scope *sc) { Expression *e = new DotIdExp(loc, ae->e1, Id::indexass); // Deal with $ for (size_t i = 0; i < ae->arguments->dim; i++) - { Expression *x = ae->arguments->tdata()[i]; + { Expression *x = (*ae->arguments)[i]; // Create scope for '$' variable for this dimension ArrayScopeSymbol *sym = new ArrayScopeSymbol(sc, ae); sym->loc = loc; @@ -10082,7 +10259,7 @@ Expression *AssignExp::semantic(Scope *sc) x = new CommaExp(0, av, x); x->semantic(sc); } - ae->arguments->tdata()[i] = x; + (*ae->arguments)[i] = x; sc = sc->pop(); } Expressions *a = (Expressions *)ae->arguments->copy(); @@ -10104,7 +10281,7 @@ Expression *AssignExp::semantic(Scope *sc) return new ErrorExp(); } - e = new CallExp(loc, e, ae->arguments->tdata()[0], e2); + e = new CallExp(loc, e, (*ae->arguments)[0], e2); e = e->semantic(sc); return e; } @@ -10385,7 +10562,7 @@ Ltupleassign: for (size_t u = 0; u < iexps->dim ; u++) { Lexpand: - Expression *e = iexps->tdata()[u]; + Expression *e = (*iexps)[u]; Parameter *arg = Parameter::getNth(tt->arguments, u); //printf("[%d] iexps->dim = %d, ", u, iexps->dim); @@ -10401,7 +10578,7 @@ Ltupleassign: goto Lnomatch; } } - iexps->tdata()[0] = new CommaExp(loc, new DeclarationExp(e2->loc, v), iexps->tdata()[0]); + (*iexps)[0] = new CommaExp(loc, new DeclarationExp(e2->loc, v), (*iexps)[0]); e2 = new TupleExp(e2->loc, iexps); e2 = e2->semantic(sc); goto Ltupleassign; @@ -10474,16 +10651,6 @@ Ltupleassign: sd->cpctor) { /* We have a copy constructor for this */ - // Scan past commma's - Expression *ec = NULL; - while (e2->op == TOKcomma) - { CommaExp *ecomma = (CommaExp *)e2; - e2 = ecomma->e2; - if (ec) - ec = new CommaExp(ecomma->loc, ec, ecomma->e1); - else - ec = ecomma->e1; - } if (e2->op == TOKquestion) { /* Write as: * a ? e1 = b : e1 = c; @@ -10494,15 +10661,9 @@ Ltupleassign: AssignExp *ea2 = new AssignExp(econd->e1->loc, e1, econd->e2); ea2->op = op; Expression *e = new CondExp(loc, econd->econd, ea1, ea2); - if (ec) - e = new CommaExp(loc, ec, e); return e->semantic(sc); } - else if (e2->op == TOKvar || - e2->op == TOKdotvar || - e2->op == TOKstar || - e2->op == TOKthis || - e2->op == TOKindex) + else if (e2->isLvalue()) { /* Write as: * e1.cpctor(e2); */ @@ -10511,8 +10672,6 @@ Ltupleassign: Expression *e = new DotVarExp(loc, e1, sd->cpctor, 0); e = new CallExp(loc, e, e2); - if (ec) - e = new CommaExp(loc, ec, e); return e->semantic(sc); } else if (e2->op == TOKcall) @@ -10537,6 +10696,21 @@ Ltupleassign: if (t1->ty == Tsarray && !refinit) { + Type *t2 = e2->type->toBasetype(); + + if (t2->ty == Tsarray && !t2->implicitConvTo(t1->nextOf())) + { // static array assignment should check their lengths + TypeSArray *tsa1 = (TypeSArray *)t1; + TypeSArray *tsa2 = (TypeSArray *)t2; + uinteger_t dim1 = tsa1->dim->toInteger(); + uinteger_t dim2 = tsa2->dim->toInteger(); + if (dim1 != dim2) + { + error("mismatched array lengths, %d and %d", (int)dim1, (int)dim2); + return new ErrorExp(); + } + } + if (e1->op == TOKindex && ((IndexExp *)e1)->e1->type->toBasetype()->ty == Taarray) { @@ -10548,7 +10722,6 @@ Ltupleassign: } else { - Type *t2 = e2->type->toBasetype(); // Convert e2 to e2[], unless e2-> e1[0] if (t2->ty == Tsarray && !t2->implicitConvTo(t1->nextOf())) { @@ -10567,6 +10740,11 @@ Ltupleassign: if (!e2->rvalue()) return new ErrorExp(); + if (e2->op == TOKarrayliteral) + { + e2 = callCpCtor(loc, sc, e2, 1); + } + if (e1->op == TOKarraylength) { // e1 is not an lvalue, but we let code generator handle it @@ -10741,7 +10919,9 @@ Expression *CatAssignExp::semantic(Scope *sc) (tb2->ty == Tarray || tb2->ty == Tsarray) && (e2->implicitConvTo(e1->type) #if DMDV2 - || tb2->nextOf()->implicitConvTo(tb1next) + || (tb2->nextOf()->implicitConvTo(tb1next) && + (tb2->nextOf()->size(0) == tb1next->size(0) || + tb1next->ty == Tchar || tb1next->ty == Twchar || tb1next->ty == Tdchar)) #endif ) ) @@ -11476,7 +11656,7 @@ Expression *PowExp::semantic(Scope *sc) { importMathChecked = 1; for (size_t i = 0; i < Module::amodules.dim; i++) - { Module *mi = Module::amodules.tdata()[i]; + { Module *mi = Module::amodules[i]; //printf("\t[%d] %s\n", i, mi->toChars()); if (mi->ident == Id::math && mi->parent->ident == Id::std && @@ -12315,12 +12495,12 @@ Expression *CondExp::semantic(Scope *sc) return this; } -#if DMDV2 + int CondExp::isLvalue() { return e1->isLvalue() && e2->isLvalue(); } -#endif + Expression *CondExp::toLvalue(Scope *sc, Expression *ex) { diff --git a/dmd2/expression.h b/dmd2/expression.h index 762ff71c..2e372650 100644 --- a/dmd2/expression.h +++ b/dmd2/expression.h @@ -18,6 +18,7 @@ #include "intrange.h" struct Type; +struct TypeVector; struct Scope; struct TupleDeclaration; struct VarDeclaration; @@ -183,6 +184,11 @@ struct Expression : Object // Same as WANTvalue, but also expand variables as far as possible #define WANTexpand 8 + // Entry point for CTFE. + // A compile-time result is required. Give an error if not possible + Expression *ctfeInterpret(); + + // Implementation of CTFE for this expression virtual Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); virtual int isConst(); @@ -432,7 +438,6 @@ struct StringExp : Expression StringExp(Loc loc, void *s, size_t len, unsigned char postfix); //Expression *syntaxCopy(); int equals(Object *o); - char *toChars(); Expression *semantic(Scope *sc); Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); size_t length(); @@ -793,7 +798,6 @@ struct FuncExp : Expression FuncLiteralDeclaration *fd; TemplateDeclaration *td; enum TOK tok; - Type *treq; FuncExp(Loc loc, FuncLiteralDeclaration *fd, TemplateDeclaration *td = NULL); Expression *syntaxCopy(); @@ -947,10 +951,11 @@ struct BinExp : Expression Expression *interpretCommon(InterState *istate, CtfeGoal goal, Expression *(*fp)(Type *, Expression *, Expression *)); Expression *interpretCommon2(InterState *istate, CtfeGoal goal, - Expression *(*fp)(TOK, Type *, Expression *, Expression *)); + Expression *(*fp)(Loc, TOK, Type *, Expression *, Expression *)); Expression *interpretAssignCommon(InterState *istate, CtfeGoal goal, Expression *(*fp)(Type *, Expression *, Expression *), int post = 0); - Expression *arrayOp(Scope *sc); + Expression *interpretFourPointerRelation(InterState *istate, CtfeGoal goal); + virtual Expression *arrayOp(Scope *sc); Expression *doInline(InlineDoState *ids); Expression *inlineScan(InlineScanState *iss); @@ -971,6 +976,7 @@ struct BinAssignExp : BinExp } Expression *semantic(Scope *sc); + Expression *arrayOp(Scope *sc); Expression *op_overload(Scope *sc); @@ -1330,7 +1336,7 @@ struct CastExp : UnaExp struct VectorExp : UnaExp { - Type *to; + TypeVector *to; // the target vector type before semantic() unsigned dim; // number of elements in the vector VectorExp(Loc loc, Expression *e, Type *t); @@ -1339,6 +1345,7 @@ struct VectorExp : UnaExp void toCBuffer(OutBuffer *buf, HdrGenState *hgs); #if IN_DMD elem *toElem(IRState *irs); + dt_t **toDt(dt_t **pdt); #endif #if IN_LLVM DValue* toElem(IRState* irs); @@ -2154,5 +2161,8 @@ void sliceAssignArrayLiteralFromString(ArrayLiteralExp *existingAE, StringExp *n void sliceAssignStringFromArrayLiteral(StringExp *existingSE, ArrayLiteralExp *newae, int firstIndex); void sliceAssignStringFromString(StringExp *existingSE, StringExp *newstr, int firstIndex); +int sliceCmpStringWithString(StringExp *se1, StringExp *se2, size_t lo1, size_t lo2, size_t len); +int sliceCmpStringWithArray(StringExp *se1, ArrayLiteralExp *ae2, size_t lo1, size_t lo2, size_t len); + #endif /* DMD_EXPRESSION_H */ diff --git a/dmd2/func.c b/dmd2/func.c index eb512522..62b493d0 100644 --- a/dmd2/func.c +++ b/dmd2/func.c @@ -51,13 +51,15 @@ FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, StorageCla outId = NULL; vresult = NULL; returnLabel = NULL; + scout = NULL; fensure = NULL; fbody = NULL; localsymtab = NULL; vthis = NULL; v_arguments = NULL; -#if IN_GCC +#ifdef IN_GCC v_argptr = NULL; + v_arguments_var = NULL; #endif v_argsave = NULL; parameters = NULL; @@ -223,11 +225,9 @@ void FuncDeclaration::semantic(Scope *sc) if (isCtorDeclaration()) sc->flags |= SCOPEctor; - type = type->semantic(loc, sc); - sc = sc->pop(); - /* Apply const, immutable and shared storage class - * to the function type + /* Apply const, immutable, wild and shared storage class + * to the function type. Do this before type semantic. */ StorageClass stc = storage_class; if (type->isImmutable()) @@ -250,35 +250,28 @@ void FuncDeclaration::semantic(Scope *sc) case STCimmutable | STCshared | STCwild: // Don't use toInvariant(), as that will do a merge() type = type->makeInvariant(); - goto Lmerge; + break; case STCconst: case STCconst | STCwild: type = type->makeConst(); - goto Lmerge; + break; case STCshared | STCconst: case STCshared | STCconst | STCwild: type = type->makeSharedConst(); - goto Lmerge; + break; case STCshared: type = type->makeShared(); - goto Lmerge; + break; case STCwild: type = type->makeWild(); - goto Lmerge; + break; case STCshared | STCwild: type = type->makeSharedWild(); - goto Lmerge; - - Lmerge: - if (!(type->ty == Tfunction && !type->nextOf())) - /* Can't do merge if return type is not known yet - */ - type->deco = type->merge()->deco; break; case 0: @@ -287,7 +280,11 @@ void FuncDeclaration::semantic(Scope *sc) default: assert(0); } + + type = type->semantic(loc, sc); + sc = sc->pop(); } + storage_class &= ~STCref; if (type->ty != Tfunction) { @@ -401,18 +398,6 @@ void FuncDeclaration::semantic(Scope *sc) if (!fbody && (fensure || frequire) && !(id && isVirtual())) error("in and out contracts require function body"); - /* Template member functions aren't virtual: - * interface TestInterface { void tpl(T)(); } - * and so won't work in interfaces - */ - if ((pd = toParent()) != NULL && - pd->isTemplateInstance() && - (pd = toParent2()) != NULL && - (id = pd->isInterfaceDeclaration()) != NULL) - { - error("template member functions are not allowed in interface %s", id->toChars()); - } - cd = parent->isClassDeclaration(); if (cd) { int vi; @@ -550,9 +535,6 @@ void FuncDeclaration::semantic(Scope *sc) break; else if (!this->parent->isClassDeclaration() // if both are mixins then error -#if !BREAKABI - && !isDtorDeclaration() -#endif #if DMDV2 && !isPostBlitDeclaration() #endif @@ -610,7 +592,7 @@ void FuncDeclaration::semantic(Scope *sc) return; default: - { FuncDeclaration *fdv = (FuncDeclaration *)b->base->vtbl.tdata()[vi]; + { FuncDeclaration *fdv = (FuncDeclaration *)b->base->vtbl[vi]; Type *ti = NULL; /* Remember which functions this overrides @@ -920,7 +902,7 @@ void FuncDeclaration::semantic3(Scope *sc) { for (int i = 0; i < fthrows->dim; i++) { - Type *t = fthrows->tdata()[i]; + Type *t = (*fthrows)[i]; t = t->semantic(loc, sc); if (!t->isClassHandle()) @@ -929,11 +911,17 @@ void FuncDeclaration::semantic3(Scope *sc) } #endif + if (!fbody && inferRetType && !type->nextOf()) + { + error("has no function body with return type inference"); + return; + } + if (frequire) { for (int i = 0; i < foverrides.dim; i++) { - FuncDeclaration *fdv = foverrides.tdata()[i]; + FuncDeclaration *fdv = foverrides[i]; if (fdv->fbody && !fdv->frequire) { @@ -971,7 +959,7 @@ void FuncDeclaration::semantic3(Scope *sc) STCproperty | STCsafe | STCtrusted | STCsystem); sc2->protection = PROTpublic; sc2->explicitProtection = 0; - sc2->structalign = 8; + sc2->structalign = STRUCTALIGN_DEFAULT; sc2->incontract = 0; #if !IN_LLVM sc2->tf = NULL; @@ -992,9 +980,6 @@ void FuncDeclaration::semantic3(Scope *sc) } else assert(!isNested() || sc->intypeof); // can't be both member and nested -#if IN_GCC - ad->methods.push(this); -#endif } vthis = declareThis(sc2, ad); @@ -1028,7 +1013,6 @@ void FuncDeclaration::semantic3(Scope *sc) if (f->linkage == LINKd) { // Declare _arguments[] -#if BREAKABI v_arguments = new VarDeclaration(0, Type::typeinfotypelist->type, Id::_arguments_typeinfo, NULL); v_arguments->storage_class = STCparameter; v_arguments->semantic(sc2); @@ -1041,18 +1025,10 @@ void FuncDeclaration::semantic3(Scope *sc) _arguments->semantic(sc2); sc2->insert(_arguments); _arguments->parent = this; -#else - t = Type::typeinfo->type->arrayOf(); - v_arguments = new VarDeclaration(0, t, Id::_arguments, NULL); - v_arguments->storage_class = STCparameter | STCin; - v_arguments->semantic(sc2); - sc2->insert(v_arguments); - v_arguments->parent = this; -#endif } if (f->linkage == LINKd || (f->parameters && Parameter::dim(f->parameters))) { // Declare _argptr -#if IN_GCC +#ifdef IN_GCC t = d_gcc_builtin_va_list_d_type; #else t = Type::tvoid->pointerTo(); @@ -1094,7 +1070,7 @@ void FuncDeclaration::semantic3(Scope *sc) if (f->parameters) { for (size_t i = 0; i < f->parameters->dim; i++) - { Parameter *arg = f->parameters->tdata()[i]; + { Parameter *arg = (*f->parameters)[i]; //printf("[%d] arg->type->ty = %d %s\n", i, arg->type->ty, arg->type->toChars()); if (arg->type->ty == Ttuple) @@ -1158,7 +1134,7 @@ void FuncDeclaration::semantic3(Scope *sc) if (f->parameters) { for (size_t i = 0; i < f->parameters->dim; i++) - { Parameter *arg = f->parameters->tdata()[i]; + { Parameter *arg = (*f->parameters)[i]; if (!arg->ident) continue; // never used, so ignore @@ -1173,7 +1149,7 @@ void FuncDeclaration::semantic3(Scope *sc) VarDeclaration *v = sc2->search(0, narg->ident, NULL)->isVarDeclaration(); assert(v); Expression *e = new VarExp(v->loc, v); - exps->tdata()[j] = e; + (*exps)[j] = e; } assert(arg->ident); TupleDeclaration *v = new TupleDeclaration(loc, arg->ident, exps); @@ -1187,151 +1163,120 @@ void FuncDeclaration::semantic3(Scope *sc) } } - /* Do the semantic analysis on the [in] preconditions and - * [out] postconditions. - */ - sc2->incontract++; + // Precondition invariant + Statement *fpreinv = NULL; + if (addPreInvariant()) + { + Expression *e = NULL; + if (isDtorDeclaration()) + { + // Call invariant directly only if it exists + InvariantDeclaration *inv = ad->inv; + ClassDeclaration *cd = ad->isClassDeclaration(); - if (frequire) - { /* frequire is composed of the [in] contracts - */ - // BUG: need to error if accessing out parameters - // BUG: need to treat parameters as const - // BUG: need to disallow returns and throws - // BUG: verify that all in and ref parameters are read - frequire = frequire->semantic(sc2); - labtab = NULL; // so body can't refer to labels + while (!inv && cd) + { + cd = cd->baseClass; + if (!cd) + break; + inv = cd->inv; + } + if (inv) + { + e = new DsymbolExp(0, inv); + e = new CallExp(0, e); + e = e->semantic(sc2); + } + } + else + { // Call invariant virtually +#if IN_LLVM + // We actually need a valid 'var' for codegen. + ThisExp* tv = new ThisExp(0); + tv->var = vthis; + Expression *v = tv; +#else + Expression *v = new ThisExp(0); +#endif + v->type = vthis->type; +#if STRUCTTHISREF + if (ad->isStructDeclaration()) + v = v->addressOf(sc); +#endif + Expression *se = new StringExp(0, (char *)"null this"); + se = se->semantic(sc); + se->type = Type::tchar->arrayOf(); + e = new AssertExp(loc, v, se); + } + if (e) + fpreinv = new ExpStatement(0, e); + } + + // Postcondition invariant + Statement *fpostinv = NULL; + if (addPostInvariant()) + { + Expression *e = NULL; + if (isCtorDeclaration()) + { + // Call invariant directly only if it exists + InvariantDeclaration *inv = ad->inv; + ClassDeclaration *cd = ad->isClassDeclaration(); + + while (!inv && cd) + { + cd = cd->baseClass; + if (!cd) + break; + inv = cd->inv; + } + if (inv) + { + e = new DsymbolExp(0, inv); + e = new CallExp(0, e); + e = e->semantic(sc2); + } + } + else + { // Call invariant virtually +#if IN_LLVM + // We actually need a valid 'var' for codegen. + ThisExp* tv = new ThisExp(0); + tv->var = vthis; + Expression *v = tv; +#else + Expression *v = new ThisExp(0); +#endif + v->type = vthis->type; +#if STRUCTTHISREF + if (ad->isStructDeclaration()) + v = v->addressOf(sc); +#endif + e = new AssertExp(0, v); + } + if (e) + fpostinv = new ExpStatement(0, e); } if (fensure || addPostInvariant()) - { /* fensure is composed of the [out] contracts - */ - if (!type->nextOf()) // if return type is inferred - { /* This case: - * auto fp = function() out { } body { }; - * Can fix by doing semantic() onf fbody first. - */ - error("post conditions are not supported if the return type is inferred"); - return; + { + if ((fensure && global.params.useOut) || fpostinv) + { returnLabel = new LabelDsymbol(Id::returnLabel); } + // scope of out contract (need for vresult->semantic) + ScopeDsymbol *sym = new ScopeDsymbol(); + sym->parent = sc2->scopesym; + scout = sc2->push(sym); + } + + if (fbody) + { ScopeDsymbol *sym = new ScopeDsymbol(); sym->parent = sc2->scopesym; sc2 = sc2->push(sym); - assert(type->nextOf()); - if (type->nextOf()->ty == Tvoid) - { - if (outId) - error("void functions have no result"); - } - else - { - if (!outId) - outId = Id::result; // provide a default - } - - if (outId) - { // Declare result variable - Loc loc = this->loc; - - if (fensure) - loc = fensure->loc; - - VarDeclaration *v = new VarDeclaration(loc, type->nextOf(), outId, NULL); - v->noscope = 1; - v->storage_class |= STCresult; -#if DMDV2 - if (!isVirtual()) - v->storage_class |= STCconst; - if (f->isref) - { - v->storage_class |= STCref | STCforeach; - } -#endif - sc2->incontract--; - v->semantic(sc2); - sc2->incontract++; - if (!sc2->insert(v)) - error("out result %s is already defined", v->toChars()); - v->parent = this; - vresult = v; - - // vresult gets initialized with the function return value - // in ReturnStatement::semantic() - } - - // BUG: need to treat parameters as const - // BUG: need to disallow returns and throws - if (fensure) - { fensure = fensure->semantic(sc2); - labtab = NULL; // so body can't refer to labels - } - - if (!global.params.useOut) - { fensure = NULL; // discard - vresult = NULL; - } - - // Postcondition invariant - if (addPostInvariant()) - { - Expression *e = NULL; - if (isCtorDeclaration()) - { - // Call invariant directly only if it exists - InvariantDeclaration *inv = ad->inv; - ClassDeclaration *cd = ad->isClassDeclaration(); - - while (!inv && cd) - { - cd = cd->baseClass; - if (!cd) - break; - inv = cd->inv; - } - if (inv) - { - e = new DsymbolExp(0, inv); - e = new CallExp(0, e); - e = e->semantic(sc2); - } - } - else - { // Call invariant virtually - ThisExp *tv = new ThisExp(0); - tv->type = vthis->type; - tv->var = vthis; - Expression* v = tv; - -#if STRUCTTHISREF - if (ad->isStructDeclaration()) - v = v->addressOf(sc); -#endif - e = new AssertExp(0, v); - } - if (e) - { - ExpStatement *s = new ExpStatement(0, e); - if (fensure) - fensure = new CompoundStatement(0, s, fensure); - else - fensure = s; - } - } - - if (fensure) - { returnLabel = new LabelDsymbol(Id::returnLabel); - LabelStatement *ls = new LabelStatement(0, Id::returnLabel, fensure); - returnLabel->statement = ls; - } - sc2 = sc2->pop(); - } - - sc2->incontract--; - - if (fbody) - { AggregateDeclaration *ad = isAggregateMember(); + AggregateDeclaration *ad = isAggregateMember(); /* If this is a class constructor */ @@ -1375,7 +1320,7 @@ void FuncDeclaration::semantic3(Scope *sc) else { for (size_t i = 0; i < pd->members->dim; i++) - { Dsymbol *s = pd->members->tdata()[i]; + { Dsymbol *s = (*pd->members)[i]; s->checkCtorConstInit(); } @@ -1460,15 +1405,7 @@ void FuncDeclaration::semantic3(Scope *sc) int offend = blockexit & BEfallthru; #endif - if (type->nextOf()->ty == Tvoid) - { - if (offend && isMain()) - { // Add a return 0; statement - Statement *s = new ReturnStatement(0, new IntegerExp(0)); - fbody = new CompoundStatement(0, fbody, s); - } - } - else + if (type->nextOf()->ty != Tvoid) { if (offend) { Expression *e; @@ -1497,6 +1434,66 @@ void FuncDeclaration::semantic3(Scope *sc) } } } + + sc2 = sc2->pop(); + } + + Statement *freq = frequire; + Statement *fens = fensure; + + /* Do the semantic analysis on the [in] preconditions and + * [out] postconditions. + */ + if (freq) + { /* frequire is composed of the [in] contracts + */ + ScopeDsymbol *sym = new ScopeDsymbol(); + sym->parent = sc2->scopesym; + sc2 = sc2->push(sym); + sc2->incontract++; + + // BUG: need to error if accessing out parameters + // BUG: need to treat parameters as const + // BUG: need to disallow returns and throws + // BUG: verify that all in and ref parameters are read + DsymbolTable *labtab_save = labtab; + labtab = NULL; // so in contract can't refer to out/body labels + freq = freq->semantic(sc2); + labtab = labtab_save; + + sc2->incontract--; + sc2 = sc2->pop(); + + if (!global.params.useIn) + freq = NULL; + } + + if (fens) + { /* fensure is composed of the [out] contracts + */ + if (type->nextOf()->ty == Tvoid && outId) + { + error("void functions have no result"); + } + + if (type->nextOf()->ty != Tvoid) + buildResultVar(); + + sc2 = scout; //push + sc2->incontract++; + + // BUG: need to treat parameters as const + // BUG: need to disallow returns and throws + DsymbolTable *labtab_save = labtab; + labtab = NULL; // so out contract can't refer to in/body labels + fens = fens->semantic(sc2); + labtab = labtab_save; + + sc2->incontract--; + sc2 = sc2->pop(); + + if (!global.params.useOut) + fens = NULL; } { @@ -1506,7 +1503,7 @@ void FuncDeclaration::semantic3(Scope *sc) if (parameters) { for (size_t i = 0; i < parameters->dim; i++) { - VarDeclaration *v = parameters->tdata()[i]; + VarDeclaration *v = (*parameters)[i]; if (v->storage_class & STCout) { assert(v->init); @@ -1548,7 +1545,7 @@ void FuncDeclaration::semantic3(Scope *sc) if (parameters && parameters->dim) { int lastNonref = parameters->dim -1; - p = parameters->tdata()[lastNonref]; + p = (*parameters)[lastNonref]; /* The trouble with out and ref parameters is that taking * the address of it doesn't work, because later processing * adds in an extra level of indirection. So we skip over them. @@ -1562,7 +1559,7 @@ void FuncDeclaration::semantic3(Scope *sc) p = v_arguments; break; } - p = parameters->tdata()[lastNonref]; + p = (*parameters)[lastNonref]; } } else @@ -1586,6 +1583,10 @@ void FuncDeclaration::semantic3(Scope *sc) if (_arguments) { +#ifdef IN_GCC + v_arguments_var = _arguments; + v_arguments_var->init = new VoidInitializer(loc); +#endif /* Advance to elements[] member of TypeInfo_Tuple with: * _arguments = v_arguments.elements; */ @@ -1601,74 +1602,32 @@ void FuncDeclaration::semantic3(Scope *sc) // Merge contracts together with body into one compound statement - if (frequire && global.params.useIn) - { frequire->incontract = 1; - a->push(frequire); - } - - // Precondition invariant - if (addPreInvariant()) + if (freq || fpreinv) { - Expression *e = NULL; - Expression *ee = NULL; - if (isDtorDeclaration()) - { - // Call invariant directly only if it exists - InvariantDeclaration *inv = ad->inv; - ClassDeclaration *cd = ad->isClassDeclaration(); + if (!freq) + freq = fpreinv; + else if (fpreinv) + freq = new CompoundStatement(0, freq, fpreinv); - while (!inv && cd) - { - cd = cd->baseClass; - if (!cd) - break; - inv = cd->inv; - } - if (inv) - { - e = new DsymbolExp(0, inv); - e = new CallExp(0, e); - e = e->semantic(sc2); - } - } - else - { // Call invariant virtually - ThisExp* tv = new ThisExp(0); - tv->type = vthis->type; - tv->var = vthis; - Expression *v = tv; - -#if STRUCTTHISREF - if (ad->isStructDeclaration()) - v = v->addressOf(sc); -#endif - Expression *se = new StringExp(0, (char *)"null this"); - se = se->semantic(sc); -#if !IN_LLVM - se->type = Type::tchar->arrayOf(); -#endif - e = new AssertExp(loc, v, se); - } - if (ee) - { - ExpStatement *s = new ExpStatement(0, ee); - a->push(s); - } - if (e) - { - ExpStatement *s = new ExpStatement(0, e); - a->push(s); - } + freq->incontract = 1; + a->push(freq); } if (fbody) a->push(fbody); - if (fensure) + if (fens || fpostinv) { + if (!fens) + fens = fpostinv; + else if (fpostinv) + fens = new CompoundStatement(0, fpostinv, fens); + + LabelStatement *ls = new LabelStatement(0, Id::returnLabel, fens); + returnLabel->statement = ls; a->push(returnLabel->statement); - if (type->nextOf()->ty != Tvoid) + if (type->nextOf()->ty != Tvoid && vresult) { #if IN_LLVM Expression *e = 0; @@ -1682,7 +1641,6 @@ void FuncDeclaration::semantic3(Scope *sc) } #else // Create: return vresult; - assert(vresult); Expression *e = new VarExp(0, vresult); #endif if (tintro) @@ -1693,6 +1651,11 @@ void FuncDeclaration::semantic3(Scope *sc) a->push(s); } } + if (isMain() && type->nextOf()->ty == Tvoid) + { // Add a return 0; statement + Statement *s = new ReturnStatement(0, new IntegerExp(0)); + a->push(s); + } fbody = new CompoundStatement(0, a); @@ -1740,17 +1703,19 @@ void FuncDeclaration::semantic3(Scope *sc) if (parameters) { for (size_t i = 0; i < parameters->dim; i++) { - VarDeclaration *v = parameters->tdata()[i]; + VarDeclaration *v = (*parameters)[i]; - if (v->storage_class & (STCref | STCout)) + if (v->storage_class & (STCref | STCout | STClazy)) continue; +#if !SARRAYVALUE /* Don't do this for static arrays, since static * arrays are called by reference. Remove this * when we change them to call by value. */ if (v->type->toBasetype()->ty == Tsarray) continue; +#endif if (v->noscope) continue; @@ -1987,6 +1952,48 @@ void FuncDeclaration::bodyToCBuffer(OutBuffer *buf, HdrGenState *hgs) } } +/**************************************************** + * Declare result variable lazily. + */ + +void FuncDeclaration::buildResultVar() +{ + if (vresult) + return; + + assert(type->nextOf()); + assert(type->nextOf()->toBasetype()->ty != Tvoid); + TypeFunction *tf = (TypeFunction *)(type); + + Loc loc = this->loc; + + if (fensure) + loc = fensure->loc; + + if (!outId) + outId = Id::result; // provide a default + + VarDeclaration *v = new VarDeclaration(loc, type->nextOf(), outId, NULL); + v->noscope = 1; + v->storage_class |= STCresult; +#if DMDV2 + if (!isVirtual()) + v->storage_class |= STCconst; + if (tf->isref) + { + v->storage_class |= STCref | STCforeach; + } +#endif + v->semantic(scout); + if (!scout->insert(v)) + error("out result %s is already defined", v->toChars()); + v->parent = this; + vresult = v; + + // vresult gets initialized with the function return value + // in ReturnStatement::semantic() +} + /**************************************************** * Merge into this function the 'in' contracts of all it overrides. * 'in's are OR'd together, i.e. only one of them needs to pass. @@ -2031,7 +2038,7 @@ Statement *FuncDeclaration::mergeFrequire(Statement *sf, Expressions *params) */ for (int i = 0; i < foverrides.dim; i++) { - FuncDeclaration *fdv = foverrides.tdata()[i]; + FuncDeclaration *fdv = foverrides[i]; /* The semantic pass on the contracts of the overridden functions must * be completed before code generation occurs (bug 3602). @@ -2089,7 +2096,7 @@ Statement *FuncDeclaration::mergeFensure(Statement *sf, Expressions *params) */ for (int i = 0; i < foverrides.dim; i++) { - FuncDeclaration *fdv = foverrides.tdata()[i]; + FuncDeclaration *fdv = foverrides[i]; /* The semantic pass on the contracts of the overridden functions must * be completed before code generation occurs (bug 3602 and 5230). @@ -2158,14 +2165,28 @@ int FuncDeclaration::findVtblIndex(Dsymbols *vtbl, int dim) FuncDeclaration *mismatch = NULL; StorageClass mismatchstc = 0; int mismatchvi = -1; + int exactvi = -1; int bestvi = -1; for (int vi = 0; vi < dim; vi++) { - FuncDeclaration *fdv = vtbl->tdata()[vi]->isFuncDeclaration(); + FuncDeclaration *fdv = (*vtbl)[vi]->isFuncDeclaration(); if (fdv && fdv->ident == ident) { if (type->equals(fdv->type)) // if exact match - return vi; // no need to look further + { + if (fdv->parent->isClassDeclaration()) + return vi; // no need to look further + + if (exactvi >= 0) + { + error("cannot determine overridden function"); + return exactvi; + } + exactvi = vi; + + bestvi = vi; + continue; + } StorageClass stc = 0; int cov = type->covariant(fdv->type, &stc); @@ -2527,7 +2548,7 @@ if (arguments) for (i = 0; i < arguments->dim; i++) { Expression *arg; - arg = arguments->tdata()[i]; + arg = (*arguments)[i]; assert(arg->type); printf("\t%s: ", arg->toChars()); arg->type->print(); @@ -2570,7 +2591,7 @@ if (arguments) OutBuffer buf2; tf->modToBuffer(&buf2); - //printf("tf = %s, args = %s\n", tf->deco, arguments->tdata()[0]->type->deco); + //printf("tf = %s, args = %s\n", tf->deco, (*arguments)[0]->type->deco); error(loc, "%s%s is not callable using argument types %s", Parameter::argsTypesToChars(tf->parameters, tf->varargs), buf2.toChars(), @@ -2656,7 +2677,7 @@ MATCH FuncDeclaration::leastAsSpecialized(FuncDeclaration *g) } else e = p->type->defaultInitLiteral(0); - args.tdata()[u] = e; + args[u] = e; } MATCH m = (MATCH) tg->callMatch(NULL, &args, 1); @@ -2797,14 +2818,25 @@ int FuncDeclaration::getLevel(Loc loc, Scope *sc, FuncDeclaration *fd) //printf("\ts = %s, '%s'\n", s->kind(), s->toChars()); FuncDeclaration *thisfd = s->isFuncDeclaration(); if (thisfd) - { if (!thisfd->isNested() && !thisfd->vthis) + { if (!thisfd->isNested() && !thisfd->vthis && !sc->intypeof) goto Lerr; } else { AggregateDeclaration *thiscd = s->isAggregateDeclaration(); if (thiscd) - { if (!thiscd->isNested()) + { + /* AggregateDeclaration::isNested returns true only when + * it has a hidden pointer. + * But, calling the function belongs unrelated lexical scope + * is still allowed inside typeof. + * + * struct Map(alias fun) { + * typeof({ return fun(); }) RetType; + * // No member function makes Map struct 'not nested'. + * } + */ + if (!thiscd->isNested() && !sc->intypeof) goto Lerr; } else @@ -3081,6 +3113,7 @@ int FuncDeclaration::isNested() FuncDeclaration *f = toAliasFunc(); //printf("\ttoParent2() = '%s'\n", f->toParent2()->toChars()); return ((f->storage_class & STCstatic) == 0) && + (f->linkage == LINKd) && (f->toParent2()->isFuncDeclaration() != NULL); } @@ -3222,12 +3255,12 @@ int FuncDeclaration::needsClosure() //printf("FuncDeclaration::needsClosure() %s\n", toChars()); for (int i = 0; i < closureVars.dim; i++) - { VarDeclaration *v = closureVars.tdata()[i]; + { VarDeclaration *v = closureVars[i]; assert(v->isVarDeclaration()); //printf("\tv = %s\n", v->toChars()); for (int j = 0; j < v->nestedrefs.dim; j++) - { FuncDeclaration *f = v->nestedrefs.tdata()[j]; + { FuncDeclaration *f = v->nestedrefs[j]; assert(f != this); //printf("\t\tf = %s, %d, %p, %d\n", f->toChars(), f->isVirtual(), f->isThis(), f->tookAddressOf); @@ -3298,7 +3331,7 @@ int FuncDeclaration::hasNestedFrameRefs() { for (size_t i = 0; i < foverrides.dim; i++) { - FuncDeclaration *fdv = foverrides.tdata()[i]; + FuncDeclaration *fdv = foverrides[i]; if (fdv->hasNestedFrameRefs()) return 1; } @@ -3386,6 +3419,7 @@ FuncLiteralDeclaration::FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type, this->ident = Lexer::uniqueId(id); this->tok = tok; this->fes = fes; + this->treq = NULL; //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this->ident->toChars(), type->toChars()); } @@ -3399,6 +3433,7 @@ Dsymbol *FuncLiteralDeclaration::syntaxCopy(Dsymbol *s) else { f = new FuncLiteralDeclaration(loc, endloc, type->syntaxCopy(), tok, fes); f->ident = ident; // keep old identifier + f->treq = treq; // don't need to copy } FuncDeclaration::syntaxCopy(f); return f; @@ -3713,14 +3748,8 @@ char *DtorDeclaration::toChars() int DtorDeclaration::isVirtual() { - /* This should be FALSE so that dtor's don't get put into the vtbl[], - * but doing so will require recompiling everything. - */ -#if BREAKABI + // FALSE so that dtor's don't get put into the vtbl[] return FALSE; -#else - return FuncDeclaration::isVirtual(); -#endif } void DtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) diff --git a/dmd2/hdrgen.c b/dmd2/hdrgen.c index 78dd4001..87b8368f 100644 --- a/dmd2/hdrgen.c +++ b/dmd2/hdrgen.c @@ -84,7 +84,7 @@ void Module::toCBuffer(OutBuffer *buf, HdrGenState *hgs) } for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = members->tdata()[i]; + { Dsymbol *s = (*members)[i]; s->toHBuffer(buf, hgs); } diff --git a/dmd2/hdrgen.h b/dmd2/hdrgen.h index 79cfb732..c60787ae 100644 --- a/dmd2/hdrgen.h +++ b/dmd2/hdrgen.h @@ -8,6 +8,7 @@ // in artistic.txt, or the GNU General Public License in gnu.txt. // See the included readme.txt for details. +#include // memset() struct HdrGenState { diff --git a/dmd2/idgen.c b/dmd2/idgen.c index 41f52ab7..457220bd 100644 --- a/dmd2/idgen.c +++ b/dmd2/idgen.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -66,6 +66,7 @@ Msgtable msgtable[] = { "outer" }, { "Exception" }, { "AssociativeArray" }, + { "RTInfo" }, { "Throwable" }, { "Error" }, { "withSym", "__withSym" }, @@ -356,6 +357,7 @@ Msgtable msgtable[] = { "derivedMembers" }, { "isSame" }, { "compiles" }, + { "parameters" }, }; diff --git a/dmd2/import.c b/dmd2/import.c index f4582c23..07670f4f 100644 --- a/dmd2/import.c +++ b/dmd2/import.c @@ -45,7 +45,7 @@ Import::Import(Loc loc, Identifiers *packages, Identifier *id, Identifier *alias this->ident = aliasId; // import [std].stdio; else if (packages && packages->dim) - this->ident = packages->tdata()[0]; + this->ident = (*packages)[0]; // import [foo]; else this->ident = id; @@ -112,8 +112,18 @@ void Import::load(Scope *sc) if (s->isModule()) mod = (Module *)s; else - ::error(loc, "can only import from a module, not from package %s.%s", - pkg->toPrettyChars(), id->toChars()); + { + if (pkg) + { + ::error(loc, "can only import from a module, not from package %s.%s", + pkg->toPrettyChars(), id->toChars()); + } + else + { + ::error(loc, "can only import from a module, not from package %s", + id->toChars()); + } + } #endif } @@ -356,8 +366,8 @@ int Import::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) */ for (size_t i = 0; i < names.dim; i++) { - Identifier *name = names.tdata()[i]; - Identifier *alias = aliases.tdata()[i]; + Identifier *name = names[i]; + Identifier *alias = aliases[i]; if (!alias) alias = name; @@ -413,12 +423,30 @@ void Import::toCBuffer(OutBuffer *buf, HdrGenState *hgs) if (packages && packages->dim) { for (size_t i = 0; i < packages->dim; i++) - { Identifier *pid = packages->tdata()[i]; + { Identifier *pid = (*packages)[i]; buf->printf("%s.", pid->toChars()); } } - buf->printf("%s;", id->toChars()); + buf->printf("%s", id->toChars()); + if (names.dim) + { + buf->writestring(" : "); + for (size_t i = 0; i < names.dim; i++) + { + Identifier *name = names[i]; + Identifier *alias = aliases[i]; + + if (alias) + buf->printf("%s = %s", alias->toChars(), name->toChars()); + else + buf->printf("%s", name->toChars()); + + if (i < names.dim - 1) + buf->writestring(", "); + } + } + buf->printf(";"); buf->writenl(); } diff --git a/dmd2/inifile.c b/dmd2/inifile.c index 1bed9fe7..36b2dd41 100644 --- a/dmd2/inifile.c +++ b/dmd2/inifile.c @@ -1,6 +1,6 @@ /* * Some portions copyright (c) 1994-1995 by Symantec - * Copyright (c) 1999-2011 by Digital Mars + * Copyright (c) 1999-2012 by Digital Mars * All Rights Reserved * http://www.digitalmars.com * Written by Walter Bright @@ -31,6 +31,10 @@ #include #endif +#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ +#include "gnuc.h" +#endif + #include "root.h" #include "rmem.h" diff --git a/dmd2/init.c b/dmd2/init.c index 5de6b114..23758bda 100644 --- a/dmd2/init.c +++ b/dmd2/init.c @@ -35,7 +35,7 @@ Initializer *Initializer::syntaxCopy() return this; } -Initializer *Initializer::semantic(Scope *sc, Type *t, int needInterpret) +Initializer *Initializer::semantic(Scope *sc, Type *t, NeedInterpret needInterpret) { return this; } @@ -88,7 +88,7 @@ Initializer *VoidInitializer::syntaxCopy() } -Initializer *VoidInitializer::semantic(Scope *sc, Type *t, int needInterpret) +Initializer *VoidInitializer::semantic(Scope *sc, Type *t, NeedInterpret needInterpret) { //printf("VoidInitializer::semantic(t = %p)\n", t); type = t; @@ -145,7 +145,7 @@ void StructInitializer::addInit(Identifier *field, Initializer *value) this->value.push(value); } -Initializer *StructInitializer::semantic(Scope *sc, Type *t, int needInterpret) +Initializer *StructInitializer::semantic(Scope *sc, Type *t, NeedInterpret needInterpret) { int errors = 0; @@ -227,7 +227,7 @@ Initializer *StructInitializer::semantic(Scope *sc, Type *t, int needInterpret) } if (s && (v = s->isVarDeclaration()) != NULL) { - val = val->semantic(sc, v->type, needInterpret); + val = val->semantic(sc, v->type->addMod(t->mod), needInterpret); value[i] = val; vars[i] = v; } @@ -353,8 +353,12 @@ Expression *StructInitializer::toExpression() else { if (!(*elements)[i]) - // Default initialize - (*elements)[i] = vd->type->defaultInit(); + { // Default initialize + if (vd->init) + (*elements)[i] = vd->init->toExpression(); + else + (*elements)[i] = vd->type->defaultInit(); + } } offset = vd->offset + vd->type->size(); i++; @@ -464,7 +468,7 @@ void ArrayInitializer::addInit(Expression *index, Initializer *value) type = NULL; } -Initializer *ArrayInitializer::semantic(Scope *sc, Type *t, int needInterpret) +Initializer *ArrayInitializer::semantic(Scope *sc, Type *t, NeedInterpret needInterpret) { unsigned i; unsigned length; const unsigned amax = 0x80000000; @@ -482,6 +486,10 @@ Initializer *ArrayInitializer::semantic(Scope *sc, Type *t, int needInterpret) case Tarray: break; + case Tvector: + t = ((TypeVector *)t)->basetype; + break; + default: error(loc, "cannot use array to initialize %s", type->toChars()); goto Lerr; @@ -493,14 +501,39 @@ Initializer *ArrayInitializer::semantic(Scope *sc, Type *t, int needInterpret) Expression *idx = index[i]; if (idx) { idx = idx->semantic(sc); - idx = idx->optimize(WANTvalue | WANTinterpret); + idx = idx->ctfeInterpret(); index[i] = idx; length = idx->toInteger(); } Initializer *val = value[i]; + ExpInitializer *ei = val->isExpInitializer(); + if (ei && !idx) + ei->expandTuples = 1; val = val->semantic(sc, t->nextOf(), needInterpret); - value[i] = val; + + ei = val->isExpInitializer(); + // found a tuple, expand it + if (ei && ei->exp->op == TOKtuple) + { + TupleExp *te = (TupleExp *)ei->exp; + index.remove(i); + value.remove(i); + + for (size_t j = 0; j < te->exps->dim; ++j) + { + Expression *e = (*te->exps)[j]; + index.insert(i + j, (Expression *)NULL); + value.insert(i + j, new ExpInitializer(e->loc, e)); + } + i--; + continue; + } + else + { + value[i] = val; + } + length++; if (length == 0) { error(loc, "array dimension overflow"); @@ -746,6 +779,7 @@ ExpInitializer::ExpInitializer(Loc loc, Expression *exp) : Initializer(loc) { this->exp = exp; + this->expandTuples = 0; } Initializer *ExpInitializer::syntaxCopy() @@ -757,6 +791,9 @@ bool arrayHasNonConstPointers(Expressions *elems); bool hasNonConstPointers(Expression *e) { + if (e->type->ty == Terror) + return false; + if (e->op == TOKnull) return false; if (e->op == TOKstructliteral) @@ -817,15 +854,19 @@ bool arrayHasNonConstPointers(Expressions *elems) -Initializer *ExpInitializer::semantic(Scope *sc, Type *t, int needInterpret) +Initializer *ExpInitializer::semantic(Scope *sc, Type *t, NeedInterpret needInterpret) { //printf("ExpInitializer::semantic(%s), type = %s\n", exp->toChars(), t->toChars()); exp = exp->semantic(sc); exp = resolveProperties(sc, exp); - int wantOptimize = needInterpret ? WANTinterpret|WANTvalue : WANTvalue; + if (exp->op == TOKerror) + return this; int olderrors = global.errors; - exp = exp->optimize(wantOptimize); + if (needInterpret) + exp = exp->ctfeInterpret(); + else + exp = exp->optimize(WANTvalue); if (!global.gag && olderrors != global.errors) return this; // Failed, suppress duplicate error messages @@ -841,6 +882,11 @@ Initializer *ExpInitializer::semantic(Scope *sc, Type *t, int needInterpret) Type *tb = t->toBasetype(); + if (exp->op == TOKtuple && + expandTuples && + !exp->implicitConvTo(t)) + return new ExpInitializer(loc, exp); + /* Look for case of initializing a static array with a too-short * string literal, such as: * char[5] foo = "abc"; @@ -870,8 +916,13 @@ Initializer *ExpInitializer::semantic(Scope *sc, Type *t, int needInterpret) } exp = exp->implicitCastTo(sc, t); + if (exp->op == TOKerror) + return this; L1: - exp = exp->optimize(wantOptimize); + if (needInterpret) + exp = exp->ctfeInterpret(); + else + exp = exp->optimize(WANTvalue); //printf("-ExpInitializer::semantic(): "); exp->print(); return this; } diff --git a/dmd2/init.h b/dmd2/init.h index d038dd9e..260f35c8 100644 --- a/dmd2/init.h +++ b/dmd2/init.h @@ -34,6 +34,7 @@ namespace llvm { } #endif +enum NeedInterpret { INITnointerpret, INITinterpret }; struct Initializer : Object { @@ -41,8 +42,8 @@ struct Initializer : Object Initializer(Loc loc); virtual Initializer *syntaxCopy(); - // needInterpret is WANTinterpret if must be a manifest constant, 0 if not. - virtual Initializer *semantic(Scope *sc, Type *t, int needInterpret); + // needInterpret is INITinterpret if must be a manifest constant, 0 if not. + virtual Initializer *semantic(Scope *sc, Type *t, NeedInterpret needInterpret); virtual Type *inferType(Scope *sc); virtual Expression *toExpression() = 0; virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs) = 0; @@ -66,7 +67,7 @@ struct VoidInitializer : Initializer VoidInitializer(Loc loc); Initializer *syntaxCopy(); - Initializer *semantic(Scope *sc, Type *t, int needInterpret); + Initializer *semantic(Scope *sc, Type *t, NeedInterpret needInterpret); Expression *toExpression(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -88,7 +89,7 @@ struct StructInitializer : Initializer StructInitializer(Loc loc); Initializer *syntaxCopy(); void addInit(Identifier *field, Initializer *value); - Initializer *semantic(Scope *sc, Type *t, int needInterpret); + Initializer *semantic(Scope *sc, Type *t, NeedInterpret needInterpret); Expression *toExpression(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -113,7 +114,7 @@ struct ArrayInitializer : Initializer ArrayInitializer(Loc loc); Initializer *syntaxCopy(); void addInit(Expression *index, Initializer *value); - Initializer *semantic(Scope *sc, Type *t, int needInterpret); + Initializer *semantic(Scope *sc, Type *t, NeedInterpret needInterpret); int isAssociativeArray(); Type *inferType(Scope *sc); Expression *toExpression(); @@ -131,10 +132,11 @@ struct ArrayInitializer : Initializer struct ExpInitializer : Initializer { Expression *exp; + int expandTuples; ExpInitializer(Loc loc, Expression *exp); Initializer *syntaxCopy(); - Initializer *semantic(Scope *sc, Type *t, int needInterpret); + Initializer *semantic(Scope *sc, Type *t, NeedInterpret needInterpret); Type *inferType(Scope *sc); Expression *toExpression(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); diff --git a/dmd2/inline.c b/dmd2/inline.c index 47eebe6d..a8e682b4 100644 --- a/dmd2/inline.c +++ b/dmd2/inline.c @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2011 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -14,6 +14,7 @@ #include #include #include +#include // memset() #include "id.h" #include "init.h" @@ -618,11 +619,11 @@ Expressions *arrayExpressiondoInline(Expressions *a, InlineDoState *ids) newa->setDim(a->dim); for (size_t i = 0; i < a->dim; i++) - { Expression *e = a->tdata()[i]; + { Expression *e = (*a)[i]; if (e) e = e->doInline(ids); - newa->tdata()[i] = e; + (*newa)[i] = e; } } return newa; @@ -639,11 +640,11 @@ Expression *SymOffExp::doInline(InlineDoState *ids) //printf("SymOffExp::doInline(%s)\n", toChars()); for (size_t i = 0; i < ids->from.dim; i++) { - if (var == ids->from.tdata()[i]) + if (var == ids->from[i]) { SymOffExp *se = (SymOffExp *)copy(); - se->var = (Declaration *)ids->to.tdata()[i]; + se->var = (Declaration *)ids->to[i]; return se; } } @@ -655,11 +656,11 @@ Expression *VarExp::doInline(InlineDoState *ids) //printf("VarExp::doInline(%s)\n", toChars()); for (size_t i = 0; i < ids->from.dim; i++) { - if (var == ids->from.tdata()[i]) + if (var == ids->from[i]) { VarExp *ve = (VarExp *)copy(); - ve->var = (Declaration *)ids->to.tdata()[i]; + ve->var = (Declaration *)ids->to[i]; return ve; } } @@ -709,7 +710,7 @@ Expression *DeclarationExp::doInline(InlineDoState *ids) if (td) { for (size_t i = 0; i < td->objects->dim; i++) - { DsymbolExp *se = td->objects->tdata()[i]; + { DsymbolExp *se = (*td->objects)[i]; assert(se->op == TOKdsymbol); se->s; } @@ -1098,8 +1099,8 @@ Statement *SwitchStatement::inlineScan(InlineScanState *iss) for (size_t i = 0; i < cases->dim; i++) { CaseStatement *s; - s = cases->tdata()[i]; - cases->tdata()[i] = (CaseStatement *)s->inlineScan(iss); + s = (*cases)[i]; + (*cases)[i] = (CaseStatement *)s->inlineScan(iss); } } return this; @@ -1130,6 +1131,65 @@ Statement *ReturnStatement::inlineScan(InlineScanState *iss) if (exp) { exp = exp->inlineScan(iss); + + FuncDeclaration *func = iss->fd; + TypeFunction *tf = (TypeFunction *)(func->type); + + /* Postblit call on return statement is processed in glue layer + * (Because NRVO may eliminate the copy), but inlining may remove + * ReturnStatement itself. To keep semantics we should insert + * temporary variable for postblit call. + * This is mostly the same as ReturnStatement::toIR. + */ + enum RET retmethod = tf->retStyle(); + if (retmethod == RETstack) + { + if (func->nrvo_can && func->nrvo_var) + ; + else + { + Type *tb = exp->type->toBasetype(); + if (exp->isLvalue() && tb->ty == Tstruct) + { StructDeclaration *sd = ((TypeStruct *)tb)->sym; + if (sd->postblit) + { FuncDeclaration *fd = sd->postblit; + if (fd->storage_class & STCdisable) + { + fd->toParent()->error(loc, "is not copyable because it is annotated with @disable"); + } + + /* Rewirte exp as: + * (__inlinectmp = exp), __inlinectmp.__postblit(), __inlinectmp + * And, __inlinectmp is marked as rvalue (See STCtemp comment) + */ + ExpInitializer *ei = new ExpInitializer(loc, exp); + + Identifier* tmp = Identifier::generateId("__inlinectmp"); + VarDeclaration *v = new VarDeclaration(loc, exp->type, tmp, ei); + v->storage_class = STCtemp; + v->linkage = LINKd; + v->parent = func; + + VarExp *ve = new VarExp(loc, v); + ve->type = exp->type; + + ei->exp = new ConstructExp(loc, ve, exp); + ei->exp->type = exp->type; + + DeclarationExp *de = new DeclarationExp(0, v); + de->type = Type::tvoid; + + Expression *e = new DotVarExp(ve->loc, ve, sd->postblit, 0); + e->type = sd->postblit->type; + e = new CallExp(ve->loc, e); + e->type = Type::tvoid; + + exp = Expression::combine(de, e); + exp = Expression::combine(exp, ve); + } + } + } + } } return this; } @@ -1162,7 +1222,7 @@ Statement *TryCatchStatement::inlineScan(InlineScanState *iss) if (catches) { for (size_t i = 0; i < catches->dim; i++) - { Catch *c = catches->tdata()[i]; + { Catch *c = (*catches)[i]; if (c->handler) c->handler = c->handler->inlineScan(iss); @@ -1212,12 +1272,12 @@ void arrayInlineScan(InlineScanState *iss, Expressions *arguments) if (arguments) { for (size_t i = 0; i < arguments->dim; i++) - { Expression *e = arguments->tdata()[i]; + { Expression *e = (*arguments)[i]; if (e) { e = e->inlineScan(iss); - arguments->tdata()[i] = e; + (*arguments)[i] = e; } } } @@ -1237,7 +1297,7 @@ void scanVar(Dsymbol *s, InlineScanState *iss) if (td) { for (size_t i = 0; i < td->objects->dim; i++) - { DsymbolExp *se = (DsymbolExp *)td->objects->tdata()[i]; + { DsymbolExp *se = (DsymbolExp *)(*td->objects)[i]; assert(se->op == TOKdsymbol); scanVar(se->s, iss); } @@ -1546,7 +1606,7 @@ int FuncDeclaration::canInline(int hasthis, int hdrscan, int statementsToo) { for (size_t i = 0; i < parameters->dim; i++) { - VarDeclaration *v = parameters->tdata()[i]; + VarDeclaration *v = (*parameters)[i]; if (v->type->toBasetype()->ty == Tsarray) goto Lno; } @@ -1701,9 +1761,9 @@ Expression *FuncDeclaration::expandInline(InlineScanState *iss, Expression *ethi for (size_t i = 0; i < arguments->dim; i++) { - VarDeclaration *vfrom = parameters->tdata()[i]; + VarDeclaration *vfrom = (*parameters)[i]; VarDeclaration *vto; - Expression *arg = arguments->tdata()[i]; + Expression *arg = (*arguments)[i]; ExpInitializer *ei; VarExp *ve; @@ -1778,7 +1838,7 @@ Expression *FuncDeclaration::expandInline(InlineScanState *iss, Expression *ethi Identifier* tmp = Identifier::generateId("__inlineretval"); VarDeclaration* vd = new VarDeclaration(loc, tf->next, tmp, ei); - vd->storage_class = tf->isref ? STCref : 0; + vd->storage_class = (tf->isref ? STCref : 0) | STCtemp; vd->linkage = tf->linkage; vd->parent = iss->fd; diff --git a/dmd2/interpret.c b/dmd2/interpret.c index 425a836d..b213d624 100644 --- a/dmd2/interpret.c +++ b/dmd2/interpret.c @@ -1,5 +1,5 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -10,6 +10,7 @@ #include #include #include +#include // mem{cpy|set}() #include "rmem.h" @@ -27,6 +28,8 @@ #include "attrib.h" // for AttribDeclaration #include "template.h" +#include "port.h" +int RealEquals(real_t x1, real_t x2); #define LOG 0 @@ -62,7 +65,7 @@ private: size_t framepointer; // current frame pointer size_t maxStackPointer; // most stack we've ever used public: - CtfeStack() : framepointer(0) + CtfeStack() : framepointer(0), maxStackPointer(0) { } size_t stackPointer() @@ -92,16 +95,16 @@ public: { assert(v->ctfeAdrOnStack >= 0 && v->ctfeAdrOnStack < globalValues.dim); - return globalValues.tdata()[v->ctfeAdrOnStack]; + return globalValues[v->ctfeAdrOnStack]; } assert(v->ctfeAdrOnStack >= 0 && v->ctfeAdrOnStack < stackPointer()); - return values.tdata()[v->ctfeAdrOnStack]; + return values[v->ctfeAdrOnStack]; } void setValue(VarDeclaration *v, Expression *e) { assert(!v->isDataseg() || v->isCTFE()); assert(v->ctfeAdrOnStack >= 0 && v->ctfeAdrOnStack < stackPointer()); - values.tdata()[v->ctfeAdrOnStack] = e; + values[v->ctfeAdrOnStack] = e; } void push(VarDeclaration *v) { @@ -109,7 +112,7 @@ public: if (v->ctfeAdrOnStack!= (size_t)-1 && v->ctfeAdrOnStack >= framepointer) { // Already exists in this frame, reuse it. - values.tdata()[v->ctfeAdrOnStack] = NULL; + values[v->ctfeAdrOnStack] = NULL; return; } savedId.push((void *)(v->ctfeAdrOnStack)); @@ -122,7 +125,7 @@ public: assert(!v->isDataseg() || v->isCTFE()); assert(!(v->storage_class & (STCref | STCout))); int oldid = v->ctfeAdrOnStack; - v->ctfeAdrOnStack = (size_t)(savedId.tdata()[oldid]); + v->ctfeAdrOnStack = (size_t)(savedId[oldid]); if (v->ctfeAdrOnStack == values.dim - 1) { values.pop(); @@ -137,8 +140,8 @@ public: assert(values.dim >= stackpointer && stackpointer >= 0); for (size_t i = stackpointer; i < values.dim; ++i) { - VarDeclaration *v = vars.tdata()[i]; - v->ctfeAdrOnStack = (size_t)(savedId.tdata()[i]); + VarDeclaration *v = vars[i]; + v->ctfeAdrOnStack = (size_t)(savedId[i]); } values.setDim(stackpointer); vars.setDim(stackpointer); @@ -221,6 +224,7 @@ Expression *evaluateIfBuiltin(InterState *istate, Loc loc, Expression *scrubReturnValue(Loc loc, Expression *e); bool isAssocArray(Type *t); bool isPointer(Type *t); +Expression *ctfeEqual(Loc loc, enum TOK op, Type *type, Expression *e1, Expression *e2); // CTFE only expressions #define TOKclassreference ((TOK)(TOKMAX+1)) @@ -258,7 +262,7 @@ struct ClassReferenceExp : Expression { fieldsSoFar += cd->fields.dim; cd = cd->baseClass; } - return cd->fields.tdata()[index - fieldsSoFar]; + return cd->fields[index - fieldsSoFar]; } // Return index of the field, or -1 if not found int getFieldIndex(Type *fieldtype, size_t fieldoffset) @@ -270,7 +274,7 @@ struct ClassReferenceExp : Expression { fieldsSoFar += cd->fields.dim; cd = cd->baseClass; } - Dsymbol *s = cd->fields.tdata()[j - fieldsSoFar]; + Dsymbol *s = cd->fields[j - fieldsSoFar]; VarDeclaration *v2 = s->isVarDeclaration(); if (fieldoffset == v2->offset && fieldtype->size() == v2->type->size()) @@ -290,7 +294,7 @@ struct ClassReferenceExp : Expression { fieldsSoFar += cd->fields.dim; cd = cd->baseClass; } - Dsymbol *s = cd->fields.tdata()[j - fieldsSoFar]; + Dsymbol *s = cd->fields[j - fieldsSoFar]; VarDeclaration *v2 = s->isVarDeclaration(); if (v == v2) { return value->elements->dim - fieldsSoFar - cd->fields.dim + (j-fieldsSoFar); @@ -328,7 +332,7 @@ int findFieldIndexByName(StructDeclaration *sd, VarDeclaration *v) { for (int i = 0; i < sd->fields.dim; ++i) { - if (sd->fields.tdata()[i] == v) + if (sd->fields[i] == v) return i; } return -1; @@ -449,8 +453,8 @@ void showCtfeExpr(Expression *e, int level = 0) return; } if (sd) - { s = sd->fields.tdata()[i]; - z = elements->tdata()[i]; + { s = sd->fields[i]; + z = (*elements)[i]; } else if (cd) { while (i - fieldsSoFar >= cd->fields.dim) @@ -459,11 +463,11 @@ void showCtfeExpr(Expression *e, int level = 0) for (int j = level; j>0; --j) printf(" "); printf(" BASE CLASS: %s\n", cd->toChars()); } - s = cd->fields.tdata()[i - fieldsSoFar]; + s = cd->fields[i - fieldsSoFar]; size_t indx = (elements->dim - fieldsSoFar)- cd->fields.dim + i; assert(indx >= 0); assert(indx < elements->dim); - z = elements->tdata()[indx]; + z = (*elements)[indx]; } if (!z) { for (int j = level; j>0; --j) printf(" "); @@ -488,6 +492,16 @@ void showCtfeExpr(Expression *e, int level = 0) } } +/************************************* + * + * Entry point for CTFE. + * A compile-time result is required. Give an error if not possible + */ +Expression *Expression::ctfeInterpret() +{ + return optimize(WANTvalue | WANTinterpret); +} + /************************************* * Attempt to interpret a function given the arguments. * Input: @@ -582,7 +596,7 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument Expressions eargs; eargs.setDim(dim); for (size_t i = 0; i < dim; i++) - { Expression *earg = arguments->tdata()[i]; + { Expression *earg = (*arguments)[i]; Parameter *arg = Parameter::getNth(tf->parameters, i); if (arg->storageClass & (STCout | STCref)) @@ -635,13 +649,13 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument ((ThrownExceptionExp *)earg)->generateUncaughtError(); return EXP_CANT_INTERPRET; } - eargs.tdata()[i] = earg; + eargs[i] = earg; } for (size_t i = 0; i < dim; i++) - { Expression *earg = eargs.tdata()[i]; + { Expression *earg = eargs[i]; Parameter *arg = Parameter::getNth(tf->parameters, i); - VarDeclaration *v = parameters->tdata()[i]; + VarDeclaration *v = (*parameters)[i]; #if LOG printf("arg[%d] = %s\n", i, earg->toChars()); #endif @@ -807,7 +821,7 @@ Expression *CompoundStatement::interpret(InterState *istate) if (statements) { for (size_t i = 0; i < statements->dim; i++) - { Statement *s = statements->tdata()[i]; + { Statement *s = (*statements)[i]; if (s) { @@ -834,7 +848,7 @@ Expression *UnrolledLoopStatement::interpret(InterState *istate) if (statements) { for (size_t i = 0; i < statements->dim; i++) - { Statement *s = statements->tdata()[i]; + { Statement *s = (*statements)[i]; e = s->interpret(istate); if (e == EXP_CANT_INTERPRET) @@ -954,19 +968,6 @@ uinteger_t resolveArrayLength(Expression *e) return 0; } -// As Equal, but resolves slices before comparing -Expression *ctfeEqual(Loc loc, enum TOK op, Type *type, Expression *e1, Expression *e2) -{ - if (e1->op == TOKslice) - e1 = resolveSlice(e1); - if (e2->op == TOKslice) - e2 = resolveSlice(e2); - Expression *e = Equal(op, type, e1, e2); - if (e == EXP_CANT_INTERPRET) - error(loc, "cannot evaluate %s==%s at compile time", e1->toChars(), e2->toChars()); - return e; -} - Expression *ctfeCat(Type *type, Expression *e1, Expression *e2) { Loc loc = e1->loc; @@ -1219,38 +1220,14 @@ Expression *DoStatement::interpret(InterState *istate) istate->start = NULL; Expression *e; - if (istate->start) - { - e = body ? body->interpret(istate) : NULL; - if (istate->start) - return NULL; - if (e == EXP_CANT_INTERPRET) - return e; - if (e == EXP_BREAK_INTERPRET) - { - if (!istate->gotoTarget || istate->gotoTarget == this) - { - istate->gotoTarget = NULL; - e = NULL; - } // else break at a higher level - return e; - } - if (e == EXP_CONTINUE_INTERPRET) - if (!istate->gotoTarget || istate->gotoTarget == this) - { - goto Lcontinue; - } - else // else continue at a higher level - return e; - if (e) - return e; - } - while (1) { + bool wasGoto = !!istate->start; e = body ? body->interpret(istate) : NULL; if (e == EXP_CANT_INTERPRET) break; + if (wasGoto && istate->start) + return NULL; if (e == EXP_BREAK_INTERPRET) { if (!istate->gotoTarget || istate->gotoTarget == this) @@ -1303,79 +1280,53 @@ Expression *ForStatement::interpret(InterState *istate) return e; assert(!e); } - - if (istate->start) + while (1) { + if (condition && !istate->start) + { + e = condition->interpret(istate); + if (exceptionOrCantInterpret(e)) + break; + if (!e->isConst()) + { e = EXP_CANT_INTERPRET; + break; + } + if (e->isBool(FALSE)) + { e = NULL; + break; + } + assert( isTrueBool(e) ); + } + + bool wasGoto = !!istate->start; e = body ? body->interpret(istate) : NULL; - if (istate->start) - return NULL; if (e == EXP_CANT_INTERPRET) - return e; + break; + if (wasGoto && istate->start) + return NULL; + if (e == EXP_BREAK_INTERPRET) { if (!istate->gotoTarget || istate->gotoTarget == this) { istate->gotoTarget = NULL; - return NULL; + e = NULL; } // else break at a higher level + break; } - if (e == EXP_CONTINUE_INTERPRET) - { - if (!istate->gotoTarget || istate->gotoTarget == this) - { - istate->gotoTarget = NULL; - goto Lcontinue; - } // else continue at a higher level - } - if (e) - return e; - } + if (e && e != EXP_CONTINUE_INTERPRET) + break; - while (1) - { - if (!condition) - goto Lhead; - e = condition->interpret(istate); - if (exceptionOrCantInterpret(e)) - break; - if (!e->isConst()) - { e = EXP_CANT_INTERPRET; - break; - } - if (isTrueBool(e)) + if (istate->gotoTarget && istate->gotoTarget != this) + break; // continue at a higher level + istate->gotoTarget = NULL; + + if (increment) { - Lhead: - e = body ? body->interpret(istate) : NULL; + e = increment->interpret(istate); if (e == EXP_CANT_INTERPRET) break; - if (e == EXP_BREAK_INTERPRET) - { - if (!istate->gotoTarget || istate->gotoTarget == this) - { - istate->gotoTarget = NULL; - e = NULL; - } // else break at a higher level - break; - } - if (e && e != EXP_CONTINUE_INTERPRET) - break; - if (istate->gotoTarget && istate->gotoTarget != this) - break; // continue at a higher level - Lcontinue: - istate->gotoTarget = NULL; - if (increment) - { - e = increment->interpret(istate); - if (e == EXP_CANT_INTERPRET) - break; - } } - else if (e->isBool(FALSE)) - { e = NULL; - break; - } - else - assert(0); } return e; } @@ -1433,7 +1384,7 @@ Expression *SwitchStatement::interpret(InterState *istate) { for (size_t i = 0; i < cases->dim; i++) { - CaseStatement *cs = cases->tdata()[i]; + CaseStatement *cs = (*cases)[i]; Expression * caseExp = cs->exp->interpret(istate); if (exceptionOrCantInterpret(caseExp)) return caseExp; @@ -1973,11 +1924,12 @@ Expression * resolveReferences(Expression *e, Expression *thisval) { VarExp *ve = (VarExp *)e; VarDeclaration *v = ve->var->isVarDeclaration(); + assert(v); if (v->type->ty == Tpointer) break; if (v->ctfeAdrOnStack == (size_t)-1) // If not on the stack, can't possibly be a ref. break; - if (v && v->getValue() && (v->getValue()->op == TOKslice)) + if (v->getValue() && (v->getValue()->op == TOKslice)) { SliceExp *se = (SliceExp *)v->getValue(); if (se->e1->op == TOKarrayliteral || se->e1->op == TOKassocarrayliteral || se->e1->op == TOKstring) @@ -1985,7 +1937,7 @@ Expression * resolveReferences(Expression *e, Expression *thisval) e = v->getValue(); continue; } - else if (v && v->getValue() && (v->getValue()->op==TOKindex || v->getValue()->op == TOKdotvar + else if (v->getValue() && (v->getValue()->op==TOKindex || v->getValue()->op == TOKdotvar || v->getValue()->op == TOKthis )) { e = v->getValue(); @@ -2076,10 +2028,10 @@ Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal e = EXP_CANT_INTERPRET; } else if (!e) - { - assert(0); - assert(v->init && v->init->isVoidInitializer()); - e = v->type->voidInitLiteral(v); + { assert(!(v->init && v->init->isVoidInitializer())); + // CTFE initiated from inside a function + error(loc, "variable %s cannot be read at compile time", v->toChars()); + return EXP_CANT_INTERPRET; } else if (exceptionOrCantInterpret(e)) return e; @@ -2261,7 +2213,7 @@ Expression *TupleExp::interpret(InterState *istate, CtfeGoal goal) Expressions *expsx = NULL; for (size_t i = 0; i < exps->dim; i++) - { Expression *e = exps->tdata()[i]; + { Expression *e = (*exps)[i]; Expression *ex; ex = e->interpret(istate); @@ -2289,10 +2241,10 @@ Expression *TupleExp::interpret(InterState *istate, CtfeGoal goal) expsx->setDim(exps->dim); for (size_t j = 0; j < i; j++) { - expsx->tdata()[j] = exps->tdata()[j]; + (*expsx)[j] = (*exps)[j]; } } - expsx->tdata()[i] = ex; + (*expsx)[i] = ex; } } if (expsx) @@ -2315,7 +2267,7 @@ Expression *ArrayLiteralExp::interpret(InterState *istate, CtfeGoal goal) if (elements) { for (size_t i = 0; i < elements->dim; i++) - { Expression *e = elements->tdata()[i]; + { Expression *e = (*elements)[i]; Expression *ex; if (e->op == TOKindex) // segfault bug 6250 @@ -2336,10 +2288,10 @@ Expression *ArrayLiteralExp::interpret(InterState *istate, CtfeGoal goal) expsx->setDim(elements->dim); for (size_t j = 0; j < elements->dim; j++) { - expsx->tdata()[j] = elements->tdata()[j]; + (*expsx)[j] = (*elements)[j]; } } - expsx->tdata()[i] = ex; + (*expsx)[i] = ex; } } } @@ -2481,7 +2433,7 @@ Expression *StructLiteralExp::interpret(InterState *istate, CtfeGoal goal) if (elements) { for (size_t i = 0; i < elements->dim; i++) - { Expression *e = elements->tdata()[i]; + { Expression *e = (*elements)[i]; if (!e) continue; @@ -2501,10 +2453,10 @@ Expression *StructLiteralExp::interpret(InterState *istate, CtfeGoal goal) expsx->setDim(elements->dim); for (size_t j = 0; j < elements->dim; j++) { - expsx->tdata()[j] = elements->tdata()[j]; + (*expsx)[j] = (*elements)[j]; } } - expsx->tdata()[i] = ex; + (*expsx)[i] = ex; } } } @@ -2536,7 +2488,7 @@ ArrayLiteralExp *createBlockDuplicatedArrayLiteral(Loc loc, Type *type, for (size_t i = 0; i < dim; i++) { if (mustCopy) elem = copyLiteral(elem); - elements->tdata()[i] = elem; + (*elements)[i] = elem; } ArrayLiteralExp *ae = new ArrayLiteralExp(loc, elements); ae->type = type; @@ -2576,7 +2528,7 @@ StringExp *createBlockDuplicatedStringLiteral(Loc loc, Type *type, Expression *recursivelyCreateArrayLiteral(Loc loc, Type *newtype, InterState *istate, Expressions *arguments, int argnum) { - Expression *lenExpr = ((arguments->tdata()[argnum]))->interpret(istate); + Expression *lenExpr = (((*arguments)[argnum]))->interpret(istate); if (exceptionOrCantInterpret(lenExpr)) return lenExpr; size_t len = (size_t)(lenExpr->toInteger()); @@ -2591,7 +2543,7 @@ Expression *recursivelyCreateArrayLiteral(Loc loc, Type *newtype, InterState *is Expressions *elements = new Expressions(); elements->setDim(len); for (size_t i = 0; i < len; i++) - elements->tdata()[i] = copyLiteral(elem); + (*elements)[i] = copyLiteral(elem); ArrayLiteralExp *ae = new ArrayLiteralExp(loc, elements); ae->type = newtype; ae->ownedByCtfe = true; @@ -2652,7 +2604,7 @@ Expression *NewExp::interpret(InterState *istate, CtfeGoal goal) fieldsSoFar -= c->fields.dim; for (size_t i = 0; i < c->fields.dim; i++) { - Dsymbol *s = c->fields.tdata()[i]; + Dsymbol *s = c->fields[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v); Expression *m = v->init ? v->init->toExpression() : v->type->defaultInitLiteral(loc); @@ -2930,20 +2882,24 @@ BIN_INTERPRET(Pow) #endif -typedef Expression *(*fp2_t)(enum TOK, Type *, Expression *, Expression *); +typedef Expression *(*fp2_t)(Loc loc, enum TOK, Type *, Expression *, Expression *); -// Return EXP_CANT_INTERPRET if they point to independent memory blocks -Expression *comparePointers(Loc loc, enum TOK op, Type *type, Expression *e1, Expression *e2) +/** Return true if agg1 and agg2 are pointers to the same memory block +*/ +bool pointToSameMemoryBlock(Expression *agg1, Expression *agg2) { - dinteger_t ofs1, ofs2; - Expression *agg1 = getAggregateFromPointer(e1, &ofs1); - Expression *agg2 = getAggregateFromPointer(e2, &ofs2); // Note that type painting can occur with VarExp, so we // must compare the variables being pointed to. - if (agg1 == agg2 || - (agg1->op == TOKvar && agg2->op == TOKvar && - ((VarExp *)agg1)->var == ((VarExp *)agg2)->var) - ) + return agg1 == agg2 || + (agg1->op == TOKvar && agg2->op == TOKvar && + ((VarExp *)agg1)->var == ((VarExp *)agg2)->var); +} + +// Return 1 if true, 0 if false +// -1 if comparison is illegal because they point to non-comparable memory blocks +int comparePointers(Loc loc, enum TOK op, Type *type, Expression *agg1, dinteger_t ofs1, Expression *agg2, dinteger_t ofs2) +{ + if ( pointToSameMemoryBlock(agg1, agg2) ) { dinteger_t cm = ofs1 - ofs2; dinteger_t n; @@ -2961,16 +2917,27 @@ Expression *comparePointers(Loc loc, enum TOK op, Type *type, Expression *e1, Ex default: assert(0); } - return new IntegerExp(loc, n, type); + return n; } + bool null1 = ( agg1->op == TOKnull ); + bool null2 = ( agg2->op == TOKnull ); + int cmp; - if (agg1->op == TOKnull) + if (null1 || null2) { - cmp = (agg2->op == TOKnull); - } - else if (agg2->op == TOKnull) - { - cmp = 0; + switch (op) + { + case TOKlt: cmp = null1 && !null2; break; + case TOKgt: cmp = !null1 && null2; break; + case TOKle: cmp = null1; break; + case TOKge: cmp = null2; break; + case TOKidentity: + case TOKequal: + case TOKnotidentity: // 'cmp' gets inverted below + case TOKnotequal: + cmp = (null1 == null2); + break; + } } else { @@ -2983,30 +2950,237 @@ Expression *comparePointers(Loc loc, enum TOK op, Type *type, Expression *e1, Ex cmp = 0; break; default: - return EXP_CANT_INTERPRET; + return -1; // memory blocks are different } } + if (op == TOKnotidentity || op == TOKnotequal) + cmp ^= 1; + return cmp; +} + + +int ctfeRawCmp(Loc loc, Expression *e1, Expression *e2); + +/* Conceptually the same as memcmp(e1, e2). + * e1 and e2 may be strings, arrayliterals, or slices. + * For string types, return <0 if e1 < e2, 0 if e1==e2, >0 if e1 > e2. + * For all other types, return 0 if e1 == e2, !=0 if e1 != e2. + */ +int ctfeCmpArrays(Loc loc, Expression *e1, Expression *e2, uinteger_t len) +{ + // Resolve slices, if necessary + uinteger_t lo1 = 0; + uinteger_t lo2 = 0; + + Expression *x = e1; + if (x->op == TOKslice) + { lo1 = ((SliceExp *)x)->lwr->toInteger(); + x = ((SliceExp*)x)->e1; + } + StringExp *se1 = (x->op == TOKstring) ? (StringExp *)x : 0; + ArrayLiteralExp *ae1 = (x->op == TOKarrayliteral) ? (ArrayLiteralExp *)x : 0; + + x = e2; + if (x->op == TOKslice) + { lo2 = ((SliceExp *)x)->lwr->toInteger(); + x = ((SliceExp*)x)->e1; + } + StringExp *se2 = (x->op == TOKstring) ? (StringExp *)x : 0; + ArrayLiteralExp *ae2 = (x->op == TOKarrayliteral) ? (ArrayLiteralExp *)x : 0; + + // Now both must be either TOKarrayliteral or TOKstring + if (se1 && se2) + return sliceCmpStringWithString(se1, se2, lo1, lo2, len); + if (se1 && ae2) + return sliceCmpStringWithArray(se1, ae2, lo1, lo2, len); + if (se2 && ae1) + return -sliceCmpStringWithArray(se2, ae1, lo2, lo1, len); + + assert (ae1 && ae2); + // Comparing two array literals. This case is potentially recursive. + // If they aren't strings, we just need an equality check rather than + // a full cmp. + bool needCmp = ae1->type->nextOf()->isintegral(); + for (size_t i = 0; i < len; i++) + { Expression *ee1 = (*ae1->elements)[lo1 + i]; + Expression *ee2 = (*ae2->elements)[lo2 + i]; + if (needCmp) + { int c = ee1->toInteger() - ee2->toInteger(); + if (c) + return c; + } + else + { if (ctfeRawCmp(loc, ee1, ee2)) + return 1; + } + } + return 0; +} + +bool isArray(Expression *e) +{ + return e->op == TOKarrayliteral || e->op == TOKstring || + e->op == TOKslice || e->op == TOKnull; +} + +/* For strings, return <0 if e1 < e2, 0 if e1==e2, >0 if e1 > e2. + * For all other types, return 0 if e1 == e2, !=0 if e1 != e2. + */ +int ctfeRawCmp(Loc loc, Expression *e1, Expression *e2) +{ + if (e1->op == TOKclassreference || e2->op == TOKclassreference) + { if (e1->op == TOKclassreference && e2->op == TOKclassreference && + ((ClassReferenceExp *)e1)->value == ((ClassReferenceExp *)e2)->value) + return 0; + return 1; + } + if (e1->op == TOKnull && e2->op == TOKnull) + return 0; + + if (e1->type->ty == Tpointer && e2->type->ty == Tpointer) + { // Can only be an equality test. + if (e1->op == TOKnull && e2->op == TOKnull) + return 0; + dinteger_t ofs1, ofs2; + Expression *agg1 = getAggregateFromPointer(e1, &ofs1); + Expression *agg2 = getAggregateFromPointer(e2, &ofs2); + if ((agg1 == agg2) || (agg1->op == TOKvar && agg2->op == TOKvar && + ((VarExp *)agg1)->var == ((VarExp *)agg2)->var)) + { if (ofs1 == ofs2) + return 0; + } + return 1; + } + if (isArray(e1) && isArray(e2)) + { + uinteger_t len1 = resolveArrayLength(e1); + uinteger_t len2 = resolveArrayLength(e2); + if (len1 != len2) // only for equality + return len1 - len2; + if (len1 == 0 || len2 == 0) + return len1 - len2; // Equal - both are empty + return ctfeCmpArrays(loc, e1, e2, len1); + } + if (e1->type->isintegral()) + { + return e1->toInteger() - e2->toInteger(); + } + real_t r1; + real_t r2; + if (e1->type->isreal()) + { + r1 = e1->toReal(); + r2 = e2->toReal(); + goto L1; + } + else if (e1->type->isimaginary()) + { + r1 = e1->toImaginary(); + r2 = e2->toImaginary(); + L1: +#if __DMC__ + return (r1 != r2); +#else + if (Port::isNan(r1) || Port::isNan(r2)) // if unordered + { + return 1; + } + else + { + return (r1 != r2); + } +#endif + } + else if (e1->type->iscomplex()) + { + return e1->toComplex() != e2->toComplex(); + } + + if (e1->op == TOKstructliteral && e2->op == TOKstructliteral) + { StructLiteralExp *es1 = (StructLiteralExp *)e1; + StructLiteralExp *es2 = (StructLiteralExp *)e2; + // For structs, we only need to return 0 or 1 (< and > aren't legal). + + if (es1->sd != es2->sd) + return 1; + else if ((!es1->elements || !es1->elements->dim) && + (!es2->elements || !es2->elements->dim)) + return 0; // both arrays are empty + else if (!es1->elements || !es2->elements) + return 1; + else if (es1->elements->dim != es2->elements->dim) + return 1; + else + { + for (size_t i = 0; i < es1->elements->dim; i++) + { Expression *ee1 = (*es1->elements)[i]; + Expression *ee2 = (*es2->elements)[i]; + + if (ee1 == ee2) + continue; + if (!ee1 || !ee2) + return 1; + int cmp = ctfeRawCmp(loc, ee1, ee2); + if (cmp) + return 1; + } + return 0; // All elements are equal + } + } + error(loc, "CTFE internal error: bad compare"); + assert(0); + return 0; +} + +// As Equal, but resolves slices before comparing +Expression *ctfeEqual(Loc loc, enum TOK op, Type *type, Expression *e1, Expression *e2) +{ + int cmp = !ctfeRawCmp(loc, e1, e2); + if (op == TOKnotequal) + cmp ^= 1; + return new IntegerExp(loc, cmp, type); +} + +Expression *ctfeIdentity(Loc loc, enum TOK op, Type *type, Expression *e1, Expression *e2) +{ + int cmp; + if (e1->op == TOKnull) + { + cmp = (e2->op == TOKnull); + } + else if (e2->op == TOKnull) + { + cmp = 0; + } + else if (e1->op == TOKsymoff && e2->op == TOKsymoff) + { + SymOffExp *es1 = (SymOffExp *)e1; + SymOffExp *es2 = (SymOffExp *)e2; + cmp = (es1->var == es2->var && es1->offset == es2->offset); + } + else if (e1->type->isreal()) + cmp = RealEquals(e1->toReal(), e2->toReal()); + else if (e1->type->isimaginary()) + cmp = RealEquals(e1->toImaginary(), e2->toImaginary()); + else if (e1->type->iscomplex()) + { complex_t v1 = e1->toComplex(); + complex_t v2 = e2->toComplex(); + cmp = RealEquals(creall(v1), creall(v2)) && + RealEquals(cimagl(v1), cimagl(v1)); + } + else + cmp = !ctfeRawCmp(loc, e1, e2); + if (op == TOKnotidentity || op == TOKnotequal) cmp ^= 1; return new IntegerExp(loc, cmp, type); } -Expression *ctfeIdentity(enum TOK op, Type *type, Expression *e1, Expression *e2) +Expression *ctfeCmp(Loc loc, enum TOK op, Type *type, Expression *e1, Expression *e2) { - if (e1->op == TOKclassreference || e2->op == TOKclassreference) - { - int cmp = 0; - if (e1->op == TOKclassreference && e2->op == TOKclassreference && - ((ClassReferenceExp *)e1)->value == ((ClassReferenceExp *)e2)->value) - cmp = 1; - if (op == TOKnotidentity || op == TOKnotequal) - cmp ^= 1; - return new IntegerExp(e1->loc, cmp, type); - } - return Identity(op, type, e1, e2); + return Cmp(op, type, e1, e2); } - Expression *BinExp::interpretCommon2(InterState *istate, CtfeGoal goal, fp2_t fp) { Expression *e; Expression *e1; @@ -3023,14 +3197,20 @@ Expression *BinExp::interpretCommon2(InterState *istate, CtfeGoal goal, fp2_t fp e2 = this->e2->interpret(istate, ctfeNeedLvalue); if (exceptionOrCantInterpret(e2)) return e2; - e = comparePointers(loc, op, type, e1, e2); - if (e == EXP_CANT_INTERPRET) + dinteger_t ofs1, ofs2; + Expression *agg1 = getAggregateFromPointer(e1, &ofs1); + Expression *agg2 = getAggregateFromPointer(e2, &ofs2); + int cmp = comparePointers(loc, op, type, agg1, ofs1, agg2, ofs2); + if (cmp == -1) { - error("%s and %s point to independent memory blocks and " - "cannot be compared at compile time", this->e1->toChars(), - this->e2->toChars()); + char dir = (op == TOKgt || op == TOKge) ? '<' : '>'; + error("The ordering of pointers to unrelated memory blocks is indeterminate in CTFE." + " To check if they point to the same memory block, use both > and < inside && or ||, " + "eg (%s && %s %c= %s + 1)", + toChars(), this->e1->toChars(), dir, this->e2->toChars()); + return EXP_CANT_INTERPRET; } - return e; + return new IntegerExp(loc, cmp, type); } e1 = this->e1->interpret(istate); if (exceptionOrCantInterpret(e1)) @@ -3064,7 +3244,7 @@ Expression *BinExp::interpretCommon2(InterState *istate, CtfeGoal goal, fp2_t fp error("cannot compare %s at compile time", e2->toChars()); goto Lcant; } - e = (*fp)(op, type, e1, e2); + e = (*fp)(loc, op, type, e1, e2); if (e == EXP_CANT_INTERPRET) error("%s cannot be interpreted at compile time", toChars()); return e; @@ -3079,9 +3259,9 @@ Expression *op##Exp::interpret(InterState *istate, CtfeGoal goal) \ return interpretCommon2(istate, goal, &opfunc); \ } -BIN_INTERPRET2(Equal, Equal) +BIN_INTERPRET2(Equal, ctfeEqual) BIN_INTERPRET2(Identity, ctfeIdentity) -BIN_INTERPRET2(Cmp, Cmp) +BIN_INTERPRET2(Cmp, ctfeCmp) /* Helper functions for BinExp::interpretAssignCommon */ @@ -3097,9 +3277,9 @@ Expressions *changeOneElement(Expressions *oldelems, size_t indexToChange, Expre for (size_t j = 0; j < expsx->dim; j++) { if (j == indexToChange) - expsx->tdata()[j] = newelem; + (*expsx)[j] = newelem; else - expsx->tdata()[j] = oldelems->tdata()[j]; + (*expsx)[j] = oldelems->tdata()[j]; } return expsx; } @@ -3299,7 +3479,7 @@ Expression *copyLiteral(Expression *e) Expression *m = oldelems->tdata()[i]; // We need the struct definition to detect block assignment AggregateDeclaration *sd = se->sd; - Dsymbol *s = sd->fields.tdata()[i]; + Dsymbol *s = sd->fields[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v); // If it is a void assignment, use the default initializer @@ -3591,7 +3771,8 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ } bool wantRef = false; if (!fp && this->e1->type->toBasetype() == this->e2->type->toBasetype() && - (e1->type->toBasetype()->ty == Tarray || isAssocArray(e1->type)) + (e1->type->toBasetype()->ty == Tarray || isAssocArray(e1->type) + || e1->type->toBasetype()->ty == Tclass) // e = *x is never a reference, because *x is always a value && this->e2->op != TOKstar ) @@ -3831,18 +4012,18 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ assert(oldval->op == TOKarrayliteral); ArrayLiteralExp *ae = (ArrayLiteralExp *)oldval; for (size_t i = 0; i < copylen; i++) - elements->tdata()[i] = ae->elements->tdata()[i]; + (*elements)[i] = ae->elements->tdata()[i]; if (elemType->ty == Tstruct || elemType->ty == Tsarray) { /* If it is an aggregate literal representing a value type, * we need to create a unique copy for each element */ for (size_t i = copylen; i < newlen; i++) - elements->tdata()[i] = copyLiteral(defaultElem); + (*elements)[i] = copyLiteral(defaultElem); } else { for (size_t i = copylen; i < newlen; i++) - elements->tdata()[i] = defaultElem; + (*elements)[i] = defaultElem; } ArrayLiteralExp *aae = new ArrayLiteralExp(0, elements); aae->type = t; @@ -4046,7 +4227,7 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ // (in which case, we already have the lvalue). if (this->e1->op != TOKcall && !(this->e1->op==TOKvar && ((VarExp*)this->e1)->var->storage_class & (STCref | STCout))) - e1 = e1->interpret(istate, ctfeNeedLvalue); + e1 = e1->interpret(istate, isPointer(type)? ctfeNeedLvalueRef : ctfeNeedLvalue); if (exceptionOrCantInterpret(e1)) return e1; if (e1->op == TOKstructliteral && newval->op == TOKstructliteral) @@ -4684,12 +4865,184 @@ Expression *PostExp::interpret(InterState *istate, CtfeGoal goal) return e; } +/* Return 1 if e is a p1 > p2 or p1 >= p2 pointer comparison; + * -1 if e is a p1 < p2 or p1 <= p2 pointer comparison; + * 0 otherwise + */ +int isPointerCmpExp(Expression *e, Expression **p1, Expression **p2) +{ + int ret = 1; + while (e->op == TOKnot) + { ret *= -1; + e = ((NotExp *)e)->e1; + } + switch(e->op) + { + case TOKlt: + case TOKle: + ret *= -1; + /* fall through */ + case TOKgt: + case TOKge: + *p1 = ((BinExp *)e)->e1; + *p2 = ((BinExp *)e)->e2; + if ( !(isPointer((*p1)->type) && isPointer((*p2)->type)) ) + ret = 0; + break; + default: + ret = 0; + break; + } + return ret; +} + +/** Negate a relational operator, eg >= becomes < + */ +TOK reverseRelation(TOK op) +{ + switch(op) + { + case TOKge: return TOKlt; + case TOKgt: return TOKle; + case TOKle: return TOKgt; + case TOKlt: return TOKge; + default: + return assert(0), TOKreserved; + } +} + +/** If this is a four pointer relation, evaluate it, else return NULL. + * + * This is an expression of the form (p1 > q1 && p2 < q2) or (p1 < q1 || p2 > q2) + * where p1, p2 are expressions yielding pointers to memory block p, + * and q1, q2 are expressions yielding pointers to memory block q. + * This expression is valid even if p and q are independent memory + * blocks and are therefore not normally comparable; the && form returns true + * if [p1..p2] lies inside [q1..q2], and false otherwise; the || form returns + * true if [p1..p2] lies outside [q1..q2], and false otherwise. + * + * Within the expression, any ordering of p1, p2, q1, q2 is permissible; + * the comparison operators can be any of >, <, <=, >=, provided that + * both directions (p > q and p < q) are checked. Additionally the + * relational sub-expressions can be negated, eg + * ( !(q1 < p1) && p2 <= q2 ) is valid. + */ +Expression *BinExp::interpretFourPointerRelation(InterState *istate, CtfeGoal goal) +{ + assert(op == TOKandand || op == TOKoror); + + /* It can only be an isInside expression, if both e1 and e2 are + * directional pointer comparisons. + * Note that this check can be made statically; it does not depends on + * any runtime values. This allows a JIT implementation to compile a + * special AndAndPossiblyInside, keeping the normal AndAnd case efficient. + */ + + // Save the pointer expressions and the comparison directions, + // so we can use them later. + Expression *p1, *p2, *p3, *p4; + int dir1 = isPointerCmpExp(e1, &p1, &p2); + int dir2 = isPointerCmpExp(e2, &p3, &p4); + if ( dir1 == 0 || dir2 == 0 ) + return NULL; + + //printf("FourPointerRelation %s\n", toChars()); + + // Evaluate the first two pointers + p1 = p1->interpret(istate); + if (exceptionOrCantInterpret(p1)) + return p1; + p2 = p2->interpret(istate); + if (exceptionOrCantInterpret(p1)) + return p1; + dinteger_t ofs1, ofs2; + Expression *agg1 = getAggregateFromPointer(p1, &ofs1); + Expression *agg2 = getAggregateFromPointer(p2, &ofs2); + + if ( !pointToSameMemoryBlock(agg1, agg2) + && agg1->op != TOKnull && agg2->op != TOKnull) + { // Here it is either CANT_INTERPRET, + // or an IsInside comparison returning FALSE. + p3 = p3->interpret(istate); + if (p3 == EXP_CANT_INTERPRET) + return p3; + // Note that it is NOT legal for it to throw an exception! + Expression *except = NULL; + if (exceptionOrCantInterpret(p3)) + except = p3; + else + { + p4 = p4->interpret(istate); + if (p4 == EXP_CANT_INTERPRET) + return p4; + if (exceptionOrCantInterpret(p3)) + except = p4; + } + if (except) + { error("Comparison %s of pointers to unrelated memory blocks remains " + "indeterminate at compile time " + "because exception %s was thrown while evaluating %s", + this->e1->toChars(), except->toChars(), this->e2->toChars()); + return EXP_CANT_INTERPRET; + } + dinteger_t ofs3,ofs4; + Expression *agg3 = getAggregateFromPointer(p3, &ofs3); + Expression *agg4 = getAggregateFromPointer(p4, &ofs4); + // The valid cases are: + // p1 > p2 && p3 > p4 (same direction, also for < && <) + // p1 > p2 && p3 < p4 (different direction, also < && >) + // Changing any > into >= doesnt affect the result + if ( (dir1 == dir2 && pointToSameMemoryBlock(agg1, agg4) + && pointToSameMemoryBlock(agg2, agg3)) + || (dir1 != dir2 && pointToSameMemoryBlock(agg1, agg3) + && pointToSameMemoryBlock(agg2, agg4)) ) + { // it's a legal two-sided comparison + return new IntegerExp(loc, (op == TOKandand) ? 0 : 1, type); + } + // It's an invalid four-pointer comparison. Either the second + // comparison is in the same direction as the first, or else + // more than two memory blocks are involved (either two independent + // invalid comparisons are present, or else agg3 == agg4). + error("Comparison %s of pointers to unrelated memory blocks is " + "indeterminate at compile time, even when combined with %s.", + e1->toChars(), e2->toChars()); + return EXP_CANT_INTERPRET; + } + // The first pointer expression didn't need special treatment, so we + // we need to interpret the entire expression exactly as a normal && or ||. + // This is easy because we haven't evaluated e2 at all yet, and we already + // know it will return a bool. + // But we mustn't evaluate the pointer expressions in e1 again, in case + // they have side-effects. + bool nott = false; + Expression *e = e1; + while (e->op == TOKnot) + { nott= !nott; + e = ((NotExp *)e)->e1; + } + TOK cmpop = e->op; + if (nott) + cmpop = reverseRelation(cmpop); + int cmp = comparePointers(loc, cmpop, e1->type, agg1, ofs1, agg2, ofs2); + // We already know this is a valid comparison. + assert(cmp >= 0); + if ( (op == TOKandand && cmp == 1) || (op == TOKoror && cmp == 0) ) + return e2->interpret(istate); + return new IntegerExp(loc, (op == TOKandand) ? 0 : 1, type); +} + Expression *AndAndExp::interpret(InterState *istate, CtfeGoal goal) { #if LOG printf("AndAndExp::interpret() %s\n", toChars()); #endif - Expression *e = e1->interpret(istate); + + // Check for an insidePointer expression, evaluate it if so + Expression *e = interpretFourPointerRelation(istate, goal); + if (e) + return e; + + e = e1->interpret(istate); if (exceptionOrCantInterpret(e)) return e; @@ -4708,17 +5061,14 @@ Expression *AndAndExp::interpret(InterState *istate, CtfeGoal goal) assert(type->ty == Tvoid); return NULL; } - if (e != EXP_CANT_INTERPRET) + if (e->isBool(FALSE)) + result = 0; + else if (isTrueBool(e)) + result = 1; + else { - if (e->isBool(FALSE)) - result = 0; - else if (isTrueBool(e)) - result = 1; - else - { - error("%s does not evaluate to a boolean", e->toChars()); - e = EXP_CANT_INTERPRET; - } + error("%s does not evaluate to a boolean", e->toChars()); + e = EXP_CANT_INTERPRET; } } else @@ -4737,7 +5087,13 @@ Expression *OrOrExp::interpret(InterState *istate, CtfeGoal goal) #if LOG printf("OrOrExp::interpret() %s\n", toChars()); #endif - Expression *e = e1->interpret(istate); + + // Check for an insidePointer expression, evaluate it if so + Expression *e = interpretFourPointerRelation(istate, goal); + if (e) + return e; + + e = e1->interpret(istate); if (exceptionOrCantInterpret(e)) return e; @@ -4997,7 +5353,7 @@ Expression *CallExp::interpret(InterState *istate, CtfeGoal goal) // Inline .dup. Special case because it needs the return type. if (!pthis && fd->ident == Id::adDup && arguments && arguments->dim == 2) { - e = arguments->tdata()[1]; + e = (*arguments)[1]; e = e->interpret(istate); if (exceptionOrCantInterpret(e)) return e; @@ -5233,7 +5589,7 @@ Expression *IndexExp::interpret(InterState *istate, CtfeGoal goal) if ( agg->op == TOKarrayliteral || agg->op == TOKstring) { dinteger_t len = ArrayLength(Type::tsize_t, agg)->toInteger(); - Type *pointee = ((TypePointer *)agg->type)->next; + //Type *pointee = ((TypePointer *)agg->type)->next; if ((indx + ofs) < 0 || (indx+ofs) > len) { error("pointer index [%lld] exceeds allocated memory block [0..%lld]", @@ -5402,7 +5758,7 @@ Expression *SliceExp::interpret(InterState *istate, CtfeGoal goal) } assert(agg->op == TOKarrayliteral || agg->op == TOKstring); dinteger_t len = ArrayLength(Type::tsize_t, agg)->toInteger(); - Type *pointee = ((TypePointer *)agg->type)->next; + //Type *pointee = ((TypePointer *)agg->type)->next; if ((ilwr + ofs) < 0 || (iupr+ofs) > (len + 1) || iupr < ilwr) { error("pointer slice [%lld..%lld] exceeds allocated memory block [0..%lld]", @@ -5561,7 +5917,9 @@ Expression *CatExp::interpret(InterState *istate, CtfeGoal goal) e2 = resolveSlice(e2); e = ctfeCat(type, e1, e2); if (e == EXP_CANT_INTERPRET) - error("%s cannot be interpreted at compile time", toChars()); + { error("%s cannot be interpreted at compile time", toChars()); + return e; + } // We know we still own it, because we interpreted both e1 and e2 if (e->op == TOKarrayliteral) ((ArrayLiteralExp *)e)->ownedByCtfe = true; @@ -5759,9 +6117,16 @@ Expression *CastExp::interpret(InterState *istate, CtfeGoal goal) } } if (to->ty == Tarray && e1->op == TOKslice) - { - e1 = new SliceExp(e1->loc, ((SliceExp *)e1)->e1, ((SliceExp *)e1)->lwr, - ((SliceExp *)e1)->upr); + { // Note that the slice may be void[], so when checking for dangerous + // casts, we need to use the original type, which is se->e1. + SliceExp *se = (SliceExp *)e1; + if ( !isSafePointerCast( se->e1->type->nextOf(), to->nextOf() ) ) + { + error("array cast from %s to %s is not supported at compile time", + se->e1->type->toChars(), to->toChars()); + return EXP_CANT_INTERPRET; + } + e1 = new SliceExp(e1->loc, se->e1, se->lwr, se->upr); e1->type = to; return e1; } @@ -5920,7 +6285,9 @@ Expression *PtrExp::interpret(InterState *istate, CtfeGoal goal) } if (ie->e1->op == TOKassocarrayliteral) { - e = Index(type, ie->e1, ie->e2); + e = findKeyInAA(loc, (AssocArrayLiteralExp *)ie->e1, ie->e2); + assert(e != EXP_CANT_INTERPRET); + e = paintTypeOntoLiteral(type, e); if (isGenuineIndex) { if (e->op == TOKindex) @@ -6206,8 +6573,8 @@ Expression *interpret_aaApply(InterState *istate, Expression *aa, Expression *de { Expression *ekey = ae->keys->tdata()[i]; Expression *evalue = ae->values->tdata()[i]; - args.tdata()[numParams - 1] = evalue; - if (numParams == 2) args.tdata()[0] = ekey; + args[numParams - 1] = evalue; + if (numParams == 2) args[0] = ekey; eresult = fd->interpret(istate, &args, pthis); if (exceptionOrCantInterpret(eresult)) @@ -6438,7 +6805,7 @@ Expression *foreachApplyUtf(InterState *istate, Expression *str, Expression *del // The index only needs to be set once if (numParams == 2) - args.tdata()[0] = new IntegerExp(deleg->loc, currentIndex, indexType); + args[0] = new IntegerExp(deleg->loc, currentIndex, indexType); Expression *val = NULL; @@ -6461,7 +6828,7 @@ Expression *foreachApplyUtf(InterState *istate, Expression *str, Expression *del } val = new IntegerExp(str->loc, codepoint, charType); - args.tdata()[numParams - 1] = val; + args[numParams - 1] = val; eresult = fd->interpret(istate, &args, pthis); if (exceptionOrCantInterpret(eresult)) @@ -6502,11 +6869,11 @@ Expression *evaluateIfBuiltin(InterState *istate, Loc loc, args.setDim(nargs); for (size_t i = 0; i < args.dim; i++) { - Expression *earg = arguments->tdata()[i]; + Expression *earg = (*arguments)[i]; earg = earg->interpret(istate); if (exceptionOrCantInterpret(earg)) return earg; - args.tdata()[i] = earg; + args[i] = earg; } e = eval_builtin(loc, b, &args); if (!e) @@ -6579,7 +6946,7 @@ Expression *evaluateIfBuiltin(InterState *istate, Loc loc, assert(arguments->dim <= se->elements->dim); for (int i = 0; i < arguments->dim; ++i) { - Expression *e = arguments->tdata()[i]->interpret(istate); + Expression *e = (*arguments)[i]->interpret(istate); if (exceptionOrCantInterpret(e)) return e; se->elements->tdata()[i] = e; @@ -6607,11 +6974,11 @@ Expression *evaluateIfBuiltin(InterState *istate, Loc loc, if ( (n == '1' || n == '2') && (c == 'c' || c == 'w' || c == 'd') && (s == 'c' || s == 'w' || s == 'd') && c != s) - { Expression *str = arguments->tdata()[0]; + { Expression *str = (*arguments)[0]; str = str->interpret(istate); if (exceptionOrCantInterpret(str)) return str; - return foreachApplyUtf(istate, str, arguments->tdata()[1], rvs); + return foreachApplyUtf(istate, str, (*arguments)[1], rvs); } } } diff --git a/dmd2/intrange.h b/dmd2/intrange.h index 77685b02..2904dab9 100644 --- a/dmd2/intrange.h +++ b/dmd2/intrange.h @@ -95,14 +95,14 @@ struct IntRange IntRange(const SignExtendedNumber& a) : imin(a), imax(a) {} /// Create a range with the lower and upper bounds. - IntRange(const SignExtendedNumber& lower, const SignExtendedNumber& upper) + IntRange(const SignExtendedNumber& lower, const SignExtendedNumber& upper) : imin(lower), imax(upper) {} - + /// Create the tightest range containing all valid integers in the specified - /// type. + /// type. static IntRange fromType(Type *type); /// Create the tightest range containing all valid integers in the type with - /// a forced signedness. + /// a forced signedness. static IntRange fromType(Type *type, bool isUnsigned); @@ -131,7 +131,7 @@ struct IntRange /// Check if this range contains 0. bool containsZero() const; - /// Compute the range of the negated absolute values of the original range. + /// Compute the range of the negated absolute values of the original range. IntRange absNeg() const; /// Compute the union of two ranges. @@ -139,7 +139,7 @@ struct IntRange void unionOrAssign(const IntRange& other, bool& union_); /// Dump the content of the integer range to the console. - const IntRange& dump(const char* funcName, Expression *e) const; + const IntRange& dump(const char* funcName, Expression *e) const; /// Split the range into two nonnegative- and negative-only subintervals. void splitBySign(IntRange& negRange, bool& hasNegRange, diff --git a/dmd2/json.c b/dmd2/json.c index d3efacf5..26daa65e 100644 --- a/dmd2/json.c +++ b/dmd2/json.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -53,7 +53,7 @@ void json_generate(Modules *modules) buf.writestring("[\n"); for (size_t i = 0; i < modules->dim; i++) - { Module *m = modules->tdata()[i]; + { Module *m = (*modules)[i]; if (global.params.verbose) printf("json gen %s\n", m->toChars()); m->toJsonBuffer(&buf); @@ -66,7 +66,7 @@ void json_generate(Modules *modules) char *arg = global.params.xfilename; if (!arg || !*arg) { // Generate lib file name from first obj name - char *n = global.params.objfiles->tdata()[0]; + char *n = (*global.params.objfiles)[0]; n = FileName::name(n); FileName *fn = FileName::forceExt(n, global.json_ext); @@ -195,7 +195,7 @@ void Module::toJsonBuffer(OutBuffer *buf) size_t offset = buf->offset; for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = members->tdata()[i]; + { Dsymbol *s = (*members)[i]; if (offset != buf->offset) { buf->writestring(",\n"); offset = buf->offset; @@ -219,7 +219,7 @@ void AttribDeclaration::toJsonBuffer(OutBuffer *buf) { size_t offset = buf->offset; for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = d->tdata()[i]; + { Dsymbol *s = (*d)[i]; //printf("AttribDeclaration::toJsonBuffer %s\n", s->toChars()); if (offset != buf->offset) { buf->writestring(",\n"); @@ -332,7 +332,7 @@ void AggregateDeclaration::toJsonBuffer(OutBuffer *buf) buf->writestring(" : [\n"); size_t offset = buf->offset; for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = members->tdata()[i]; + { Dsymbol *s = (*members)[i]; if (offset != buf->offset) { buf->writestring(",\n"); offset = buf->offset; @@ -369,7 +369,7 @@ void TemplateDeclaration::toJsonBuffer(OutBuffer *buf) buf->writestring(" : [\n"); size_t offset = buf->offset; for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = members->tdata()[i]; + { Dsymbol *s = (*members)[i]; if (offset != buf->offset) { buf->writestring(",\n"); offset = buf->offset; @@ -391,7 +391,7 @@ void EnumDeclaration::toJsonBuffer(OutBuffer *buf) { for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = members->tdata()[i]; + Dsymbol *s = (*members)[i]; s->toJsonBuffer(buf); buf->writestring(",\n"); } @@ -423,7 +423,7 @@ void EnumDeclaration::toJsonBuffer(OutBuffer *buf) buf->writestring(" : [\n"); size_t offset = buf->offset; for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = members->tdata()[i]; + { Dsymbol *s = (*members)[i]; if (offset != buf->offset) { buf->writestring(",\n"); offset = buf->offset; diff --git a/dmd2/lexer.c b/dmd2/lexer.c index ed3dfae0..741cc859 100644 --- a/dmd2/lexer.c +++ b/dmd2/lexer.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -108,14 +108,22 @@ const char *Token::toChars() switch (value) { case TOKint32v: +#if defined(IN_GCC) || defined(IN_LLVM) sprintf(buffer,"%d",(d_int32)int64value); +#else + sprintf(buffer,"%d",int32value); +#endif break; case TOKuns32v: case TOKcharv: case TOKwcharv: case TOKdcharv: +#ifdef defined(IN_GCC) || defined(IN_LLVM) sprintf(buffer,"%uU",(d_uns32)uns64value); +#else + sprintf(buffer,"%uU",uns32value); +#endif break; case TOKint64v: @@ -126,7 +134,7 @@ const char *Token::toChars() sprintf(buffer,"%lluUL",(uintmax_t)uns64value); break; -#if IN_GCC +#ifdef IN_GCC case TOKfloat32v: case TOKfloat64v: case TOKfloat80v: @@ -171,9 +179,6 @@ const char *Token::toChars() #endif case TOKstring: -#if CSTRINGS - p = string; -#else { OutBuffer buf; buf.writeByte('"'); @@ -208,7 +213,6 @@ const char *Token::toChars() buf.writeByte(0); p = (char *)buf.extractData(); } -#endif break; case TOKidentifier: @@ -305,7 +309,7 @@ void Lexer::error(const char *format, ...) { va_list ap; va_start(ap, format); - verror(tokenLoc(), format, ap); + ::verror(tokenLoc(), format, ap); va_end(ap); } @@ -313,34 +317,10 @@ void Lexer::error(Loc loc, const char *format, ...) { va_list ap; va_start(ap, format); - verror(loc, format, ap); + ::verror(loc, format, ap); va_end(ap); } -void Lexer::verror(Loc loc, const char *format, va_list ap) -{ - if (mod && !global.gag) - { - char *p = loc.toChars(); - if (*p) - fprintf(stdmsg, "%s: ", p); - mem.free(p); - - vfprintf(stdmsg, format, ap); - - fprintf(stdmsg, "\n"); - fflush(stdmsg); - - if (global.errors >= 20) // moderate blizzard of cascading messages - fatal(); - } - else - { - global.gaggedErrors++; - } - global.errors++; -} - TOK Lexer::nextToken() { Token *t; @@ -524,30 +504,6 @@ void Lexer::scan(Token *t) t->value = number(t); return; -#if CSTRINGS - case '\'': - t->value = charConstant(t, 0); - return; - - case '"': - t->value = stringConstant(t,0); - return; - - case 'l': - case 'L': - if (p[1] == '\'') - { - p++; - t->value = charConstant(t, 1); - return; - } - else if (p[1] == '"') - { - p++; - t->value = stringConstant(t, 1); - return; - } -#else case '\'': t->value = charConstant(t,0); return; @@ -627,12 +583,9 @@ void Lexer::scan(Token *t) } #endif - case 'l': - case 'L': -#endif case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': - case 'k': case 'm': case 'n': case 'o': + case 'k': case 'l': case 'm': case 'n': case 'o': #if DMDV2 case 'p': /*case 'q': case 'r':*/ case 's': case 't': #else @@ -642,7 +595,7 @@ void Lexer::scan(Token *t) case 'z': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': - case 'K': case 'M': case 'N': case 'O': + case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': @@ -669,7 +622,7 @@ void Lexer::scan(Token *t) StringValue *sv = stringtable.update((char *)t->ptr, p - t->ptr); Identifier *id = (Identifier *) sv->ptrvalue; if (!id) - { id = new Identifier(sv->lstring.string,TOKidentifier); + { id = new Identifier(sv->toDchars(),TOKidentifier); sv->ptrvalue = id; } t->ident = id; @@ -1228,10 +1181,10 @@ void Lexer::scan(Token *t) case '#': { p++; - Token *n = peek(t); - if (n->value == TOKidentifier && n->ident == Id::line) + Token n; + scan(&n); + if (n.value == TOKidentifier && n.ident == Id::line) { - nextToken(); poundLine(); continue; } @@ -1931,45 +1884,6 @@ void Lexer::stringPostfix(Token *t) } } -/*************************************** - * Read \u or \U unicode sequence - * Input: - * u 'u' or 'U' - */ - -#if 0 -unsigned Lexer::wchar(unsigned u) -{ - unsigned value; - unsigned n; - unsigned char c; - unsigned nchars; - - nchars = (u == 'U') ? 8 : 4; - value = 0; - for (n = 0; 1; n++) - { - ++p; - if (n == nchars) - break; - c = *p; - if (!ishex(c)) - { error("\\%c sequence must be followed by %d hex characters", u, nchars); - break; - } - if (isdigit(c)) - c -= '0'; - else if (islower(c)) - c -= 'a' - 10; - else - c -= 'A' - 10; - value <<= 4; - value |= c; - } - return value; -} -#endif - /************************************** * Read in a number. * If it's an integer, store it in tok.TKutok.Vlong. @@ -1996,14 +1910,12 @@ TOK Lexer::number(Token *t) }; enum FLAGS flags = FLAGS_decimal; - int base; unsigned c; unsigned char *start; TOK result; //printf("Lexer::number()\n"); state = STATE_initial; - base = 0; stringbuffer.reset(); start = p; while (1) @@ -2022,11 +1934,6 @@ TOK Lexer::number(Token *t) flags = (FLAGS) (flags & ~FLAGS_decimal); switch (c) { -#if ZEROH - case 'H': // 0h - case 'h': - goto hexh; -#endif case 'X': case 'x': state = STATE_hex0; @@ -2035,15 +1942,14 @@ TOK Lexer::number(Token *t) case '.': if (p[1] == '.') // .. is a separate token goto done; +#if DMDV2 + if (isalpha(p[1]) || p[1] == '_') + goto done; +#endif case 'i': case 'f': case 'F': goto real; -#if ZEROH - case 'E': - case 'e': - goto case_hex; -#endif case 'B': case 'b': state = STATE_binary0; @@ -2054,14 +1960,6 @@ TOK Lexer::number(Token *t) state = STATE_octal; break; -#if ZEROH - case '8': case '9': case 'A': - case 'C': case 'D': case 'F': - case 'a': case 'c': case 'd': case 'f': - case_hex: - state = STATE_hexh; - break; -#endif case '_': state = STATE_octal; p++; @@ -2080,12 +1978,6 @@ TOK Lexer::number(Token *t) case STATE_decimal: // reading decimal number if (!isdigit(c)) { -#if ZEROH - if (ishex(c) - || c == 'H' || c == 'h' - ) - goto hexh; -#endif if (c == '_') // ignore embedded _ { p++; continue; @@ -2130,41 +2022,10 @@ TOK Lexer::number(Token *t) state = STATE_hex; break; -#if ZEROH - hexh: - state = STATE_hexh; - case STATE_hexh: // parse numbers like 0FFh - if (!ishex(c)) - { - if (c == 'H' || c == 'h') - { - p++; - base = 16; - goto done; - } - else - { - // Check for something like 1E3 or 0E24 - if (memchr((char *)stringbuffer.data, 'E', stringbuffer.offset) || - memchr((char *)stringbuffer.data, 'e', stringbuffer.offset)) - goto real; - error("Hex digit expected, not '%c'", c); - goto done; - } - } - break; -#endif - case STATE_octal: // reading octal number case STATE_octale: // reading octal number with non-octal digits if (!isoctal(c)) { -#if ZEROH - if (ishex(c) - || c == 'H' || c == 'h' - ) - goto hexh; -#endif if (c == '_') // ignore embedded _ { p++; continue; @@ -2186,12 +2047,6 @@ TOK Lexer::number(Token *t) case STATE_binary: // reading binary number if (c != '0' && c != '1') { -#if ZEROH - if (ishex(c) - || c == 'H' || c == 'h' - ) - goto hexh; -#endif if (c == '_') // ignore embedded _ { p++; continue; @@ -2232,7 +2087,7 @@ done: // Convert string to integer #if __DMC__ errno = 0; - n = strtoull((char *)stringbuffer.data,NULL,base); + n = strtoull((char *)stringbuffer.data,NULL,0); if (errno == ERANGE) error("integer overflow"); #else @@ -2636,8 +2491,9 @@ void Lexer::poundLine() { p += 8; filespec = mem.strdup(loc.filename ? loc.filename : mod->ident->toChars()); + continue; } - continue; + goto Lerr; case '"': if (filespec) @@ -2920,7 +2776,7 @@ Identifier *Lexer::idPool(const char *s) Identifier *id = (Identifier *) sv->ptrvalue; if (!id) { - id = new Identifier(sv->lstring.string, TOKidentifier); + id = new Identifier(sv->toDchars(), TOKidentifier); sv->ptrvalue = id; } return id; @@ -3067,6 +2923,7 @@ static Keyword keywords[] = // Added after 1.0 { "__argTypes", TOKargTypes }, + { "__parameters", TOKparameters }, { "ref", TOKref }, { "macro", TOKmacro }, #if DMDV2 @@ -3111,7 +2968,7 @@ void Lexer::initKeywords() const char *s = keywords[u].name; enum TOK v = keywords[u].value; StringValue *sv = stringtable.insert(s, strlen(s)); - sv->ptrvalue = (void *) new Identifier(sv->lstring.string,v); + sv->ptrvalue = (void *) new Identifier(sv->toDchars(),v); //printf("tochars[%d] = '%s'\n",v, s); Token::tochars[v] = s; diff --git a/dmd2/lexer.h b/dmd2/lexer.h index 848d7123..293c9538 100644 --- a/dmd2/lexer.h +++ b/dmd2/lexer.h @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -156,6 +156,7 @@ enum TOK TOKref, TOKmacro, #if DMDV2 + TOKparameters, TOKtraits, TOKoverloadset, TOKpure, @@ -311,7 +312,6 @@ struct Lexer TOK inreal(Token *t); void error(const char *format, ...) IS_PRINTF(2); void error(Loc loc, const char *format, ...) IS_PRINTF(3); - void verror(Loc loc, const char *format, va_list ap); void poundLine(); unsigned decodeUTF(); void getDocComment(Token *t, unsigned lineComment); diff --git a/dmd2/lib.h b/dmd2/lib.h index 3a67ed30..d63e1ace 100644 --- a/dmd2/lib.h +++ b/dmd2/lib.h @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2008 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -15,53 +15,15 @@ #pragma once #endif /* __DMC__ */ -struct ObjModule; - -struct ObjSymbol +class Library { - char *name; - ObjModule *om; -}; + public: + static Library *factory(); -#include "arraytypes.h" - -typedef ArrayBase ObjModules; -typedef ArrayBase ObjSymbols; - -struct Library -{ - File *libfile; - ObjModules objmodules; // ObjModule[] - ObjSymbols objsymbols; // ObjSymbol[] - - StringTable tab; - - Library(); - void setFilename(char *dir, char *filename); - void addObject(const char *module_name, void *buf, size_t buflen); - void addLibrary(void *buf, size_t buflen); - void write(); - - private: - void addSymbol(ObjModule *om, char *name, int pickAny = 0); - void scanObjModule(ObjModule *om); - unsigned short numDictPages(unsigned padding); - int FillDict(unsigned char *bucketsP, unsigned short uNumPages); - void WriteLibToBuffer(OutBuffer *libbuf); - - void error(const char *format, ...) - { - Loc loc; - if (libfile) - { - loc.filename = libfile->name->toChars(); - loc.linnum = 0; - } - va_list ap; - va_start(ap, format); - ::verror(loc, format, ap); - va_end(ap); - } + virtual void setFilename(char *dir, char *filename) = 0; + virtual void addObject(const char *module_name, void *buf, size_t buflen) = 0; + virtual void addLibrary(void *buf, size_t buflen) = 0; + virtual void write() = 0; }; #endif /* DMD_LIB_H */ diff --git a/dmd2/mars.c b/dmd2/mars.c index ea79ce2f..0533e3fc 100644 --- a/dmd2/mars.c +++ b/dmd2/mars.c @@ -101,12 +101,12 @@ Global::Global() "\nMSIL back-end (alpha release) by Cristian L. Vlasceanu and associates."; #endif ; - version = "v2.059"; + version = "v2.060"; #if IN_LLVM ldc_version = "LDC trunk"; llvm_version = "LLVM "LDC_LLVM_VERSION_STRING; #endif - global.structalign = 8; + global.structalign = STRUCTALIGN_DEFAULT; // This should only be used as a global, so the other fields are // automatically initialized to zero when the program is loaded. @@ -197,7 +197,7 @@ void errorSupplemental(Loc loc, const char *format, ...) va_end( ap ); } -void verror(Loc loc, const char *format, va_list ap) +void verror(Loc loc, const char *format, va_list ap, const char *p1, const char *p2) { if (!global.gag) { @@ -208,16 +208,22 @@ void verror(Loc loc, const char *format, va_list ap) mem.free(p); fprintf(stdmsg, "Error: "); + if (p1) + fprintf(stdmsg, "%s ", p1); + if (p2) + fprintf(stdmsg, "%s ", p2); +#if _MSC_VER // MS doesn't recognize %zu format OutBuffer tmp; tmp.vprintf(format, ap); -#if _MSC_VER fprintf(stdmsg, "%s", tmp.toChars()); #else vfprintf(stdmsg, format, ap); #endif fprintf(stdmsg, "\n"); fflush(stdmsg); + if (global.errors >= 20) // moderate blizzard of cascading messages + fatal(); //halt(); } else @@ -372,8 +378,8 @@ Usage:\n\ -version=level compile in version code >= level\n\ -version=ident compile in version code identified by ident\n\ -vtls list all variables going into thread local storage\n\ - -w enable warnings\n\ - -wi enable informational warnings\n\ + -w warnings as errors (compilation will halt)\n\ + -wi warnings as messages (compilation will continue)\n\ -X generate JSON file\n\ -Xffilename write JSON file to filename\n\ ", fpic); @@ -1040,7 +1046,7 @@ int tryMain(int argc, char *argv[]) { for (size_t i = 0; i < global.params.fileImppath->dim; i++) { - char *path = global.params.fileImppath->tdata()[i]; + char *path = (*global.params.fileImppath)[i]; Strings *a = FileName::splitPath(path); if (a) @@ -1061,7 +1067,7 @@ int tryMain(int argc, char *argv[]) char *ext; char *name; - p = files.tdata()[i]; + p = files[i]; #if _WIN32 // Convert / to \ so linker will work @@ -1079,47 +1085,47 @@ int tryMain(int argc, char *argv[]) */ if (FileName::equals(ext, global.obj_ext)) { - global.params.objfiles->push(files.tdata()[i]); - libmodules.push(files.tdata()[i]); + global.params.objfiles->push(files[i]); + libmodules.push(files[i]); continue; } if (FileName::equals(ext, global.lib_ext)) { - global.params.libfiles->push(files.tdata()[i]); - libmodules.push(files.tdata()[i]); + global.params.libfiles->push(files[i]); + libmodules.push(files[i]); continue; } if (strcmp(ext, global.ddoc_ext) == 0) { - global.params.ddocfiles->push(files.tdata()[i]); + global.params.ddocfiles->push(files[i]); continue; } if (FileName::equals(ext, global.json_ext)) { global.params.doXGeneration = 1; - global.params.xfilename = files.tdata()[i]; + global.params.xfilename = files[i]; continue; } if (FileName::equals(ext, global.map_ext)) { - global.params.mapfile = files.tdata()[i]; + global.params.mapfile = files[i]; continue; } #if TARGET_WINDOS if (FileName::equals(ext, "res")) { - global.params.resfile = files.tdata()[i]; + global.params.resfile = files[i]; continue; } if (FileName::equals(ext, "def")) { - global.params.deffile = files.tdata()[i]; + global.params.deffile = files[i]; continue; } @@ -1134,10 +1140,7 @@ int tryMain(int argc, char *argv[]) */ if (FileName::equals(ext, global.mars_ext) || FileName::equals(ext, global.hdr_ext) || - FileName::equals(ext, "dd") || - FileName::equals(ext, "htm") || - FileName::equals(ext, "html") || - FileName::equals(ext, "xhtml")) + FileName::equals(ext, "dd")) { ext--; // skip onto '.' assert(*ext == '.'); @@ -1150,7 +1153,7 @@ int tryMain(int argc, char *argv[]) strcmp(name, ".") == 0) { Linvalid: - error(0, "invalid file name '%s'", files.tdata()[i]); + error(0, "invalid file name '%s'", files[i]); fatal(); } } @@ -1232,7 +1235,7 @@ int tryMain(int argc, char *argv[]) // Remove m's object file from list of object files for (size_t j = 0; j < global.params.objfiles->dim; j++) { - if (m->objfile->name->str == global.params.objfiles->tdata()[j]) + if (m->objfile->name->str == (*global.params.objfiles)[j]) { global.params.objfiles->remove(j); break; @@ -1322,24 +1325,13 @@ int tryMain(int argc, char *argv[]) if (global.errors) fatal(); - if (global.params.moduleDeps != NULL) - { - assert(global.params.moduleDepsFile != NULL); - - File deps(global.params.moduleDepsFile); - OutBuffer* ob = global.params.moduleDeps; - deps.setbuffer((void*)ob->data, ob->offset); - deps.writev(); - } - - - // Scan for functions to inline if (global.params.useInline) { /* The problem with useArrayBounds and useAssert is that the * module being linked to may not have generated them, so if * we inline functions from those modules, the symbols for them will * not be found at link time. + * We must do this BEFORE generating the .deps file! */ if (!global.params.useArrayBounds && !global.params.useAssert) { @@ -1355,7 +1347,21 @@ int tryMain(int argc, char *argv[]) if (global.errors) fatal(); } + } + if (global.params.moduleDeps != NULL) + { + assert(global.params.moduleDepsFile != NULL); + + File deps(global.params.moduleDepsFile); + OutBuffer* ob = global.params.moduleDeps; + deps.setbuffer((void*)ob->data, ob->offset); + deps.writev(); + } + + // Scan for functions to inline + if (global.params.useInline) + { for (size_t i = 0; i < modules.dim; i++) { m = modules[i]; @@ -1374,7 +1380,7 @@ int tryMain(int argc, char *argv[]) Library *library = NULL; if (global.params.lib) { - library = new Library(); + library = Library::factory(); library->setFilename(global.params.objdir, global.params.libname); // Add input object and input library files to output library @@ -1405,7 +1411,7 @@ int tryMain(int argc, char *argv[]) } if (!global.errors && modules.dim) { - obj_end(library, modules.tdata()[0]->objfile); + obj_end(library, modules[0]->objfile); } } else diff --git a/dmd2/mars.h b/dmd2/mars.h index 36dc7b51..e3db7751 100644 --- a/dmd2/mars.h +++ b/dmd2/mars.h @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -97,11 +97,13 @@ void unittests(); #define DMDV1 0 #define DMDV2 1 // Version 2.0 features -#define BREAKABI 1 // 0 if not ready to break the ABI just yet #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 +#define BUG6652 1 // Making foreach range statement parameter non-ref in default + // 1: Modifying iteratee in body is warned with -w switch + // 2: Modifying iteratee in body is error without -d switch // Set if C++ mangling is done by the front end #define CPP_MANGLE (DMDV2 && (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS)) @@ -279,6 +281,10 @@ struct Param #endif }; +typedef unsigned structalign_t; +#define STRUCTALIGN_DEFAULT ~0 // magic value means "match whatever the underlying C compiler does" +// other values are all powers of 2 + struct Global { const char *mars_ext; @@ -303,7 +309,9 @@ struct Global const char *written; Strings *path; // Array of char*'s which form the import lookup path Strings *filePath; // Array of char*'s which form the file import lookup path - int structalign; + + structalign_t structalign; // default alignment for struct fields + const char *version; #if IN_LLVM char *ldc_version; @@ -475,7 +483,7 @@ typedef uint64_t StorageClass; void warning(Loc loc, const char *format, ...) IS_PRINTF(2); void error(Loc loc, const char *format, ...) IS_PRINTF(2); void errorSupplemental(Loc loc, const char *format, ...); -void verror(Loc loc, const char *format, va_list); +void verror(Loc loc, const char *format, va_list, const char *p1 = NULL, const char *p2 = NULL); void vwarning(Loc loc, const char *format, va_list); void verrorSupplemental(Loc loc, const char *format, va_list); void fatal(); @@ -495,7 +503,7 @@ void util_progress(); #endif /*** Where to send error messages ***/ -#if IN_GCC || IN_LLVM +#if defined(IN_GCC) || IN_LLVM #define stdmsg stderr #else #define stdmsg stderr diff --git a/dmd2/module.c b/dmd2/module.c index bd381808..15f1272e 100644 --- a/dmd2/module.c +++ b/dmd2/module.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -20,7 +20,7 @@ #include #endif -#if IN_GCC +#ifdef IN_GCC #include "gdc_alloca.h" #endif @@ -37,7 +37,10 @@ #include "hdrgen.h" #include "lexer.h" -#include "html.h" +// stricmp +#if __GNUC__ && !_WIN32 +#include "gnuc.h" +#endif #ifdef IN_GCC #include "d-dmd-gcc.h" @@ -88,7 +91,6 @@ Module::Module(char *filename, Identifier *ident, int doDocComment, int doHdrGen errors = 0; numlines = 0; members = NULL; - isHtml = 0; isDocFile = 0; needmoduleinfo = 0; #ifdef IN_GCC @@ -146,17 +148,8 @@ Module::Module(char *filename, Identifier *ident, int doDocComment, int doHdrGen !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(); - } + error("source file name '%s' must have .%s extension", srcfilename->toChars(), global.mars_ext); + fatal(); } #if !IN_LLVM char *argobj; @@ -438,7 +431,7 @@ Module *Module::load(Loc loc, Identifiers *packages, Identifier *ident) OutBuffer buf; for (size_t i = 0; i < packages->dim; i++) - { Identifier *pid = packages->tdata()[i]; + { Identifier *pid = (*packages)[i]; buf.writestring(pid->toChars()); #if _WIN32 @@ -499,7 +492,7 @@ Module *Module::load(Loc loc, Identifiers *packages, Identifier *ident) if (packages) { for (size_t i = 0; i < packages->dim; i++) - { Identifier *pid = packages->tdata()[i]; + { Identifier *pid = (*packages)[i]; printf("%s.", pid->toChars()); } } @@ -530,7 +523,7 @@ bool Module::read(Loc loc) { for (size_t i = 0; i < global.path->dim; i++) { - char *p = global.path->tdata()[i]; + char *p = (*global.path)[i]; fprintf(stdmsg, "import path[%llu] = %s\n", (ulonglong)i, p); } } @@ -579,24 +572,17 @@ inline unsigned readlongBE(unsigned *p) #if IN_LLVM void Module::parse(bool gen_docs) -#elif IN_GCC -void Module::parse(bool dump_source) #else void Module::parse() #endif -{ char *srcname; - unsigned char *buf; - unsigned buflen; - unsigned le; - unsigned bom; - +{ //printf("Module::parse()\n"); - srcname = srcfile->name->toChars(); + char *srcname = srcfile->name->toChars(); //printf("Module::parse(srcname = '%s')\n", srcname); - buf = srcfile->buffer; - buflen = srcfile->len; + unsigned char *buf = srcfile->buffer; + unsigned buflen = srcfile->len; if (buflen >= 2) { @@ -609,7 +595,8 @@ void Module::parse() * EF BB BF UTF-8 */ - bom = 1; // assume there's a BOM + unsigned le; + unsigned bom = 1; // assume there's a BOM if (buf[0] == 0xFF && buf[1] == 0xFE) { if (buflen >= 4 && buf[2] == 0 && buf[3] == 0) @@ -760,7 +747,7 @@ void Module::parse() #ifdef IN_GCC // dump utf-8 encoded source - if (dump_source) + if (global.params.dump_source) { // %% srcname could contain a path ... d_gcc_dump_source(srcname, "utf-8", buf, buflen); } @@ -779,19 +766,6 @@ void Module::parse() #endif return; } - if (isHtml) - { - OutBuffer *dbuf = new OutBuffer(); - Html h(srcname, buf, buflen); - h.extractCode(dbuf); - buf = dbuf->data; - buflen = dbuf->offset; -#ifdef IN_GCC - // dump extracted source - if (dump_source) - d_gcc_dump_source(srcname, "d.utf-8", buf, buflen); -#endif - } #if IN_LLVM Parser p(this, buf, buflen, gen_docs); #else @@ -890,7 +864,7 @@ void Module::importAll(Scope *prevsc) symtab = new DsymbolTable(); for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = members->tdata()[i]; + Dsymbol *s = (*members)[i]; s->addMember(NULL, sc->scopesym, 1); } } @@ -903,13 +877,13 @@ void Module::importAll(Scope *prevsc) */ setScope(sc); // remember module scope for semantic for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = members->tdata()[i]; + { Dsymbol *s = (*members)[i]; s->setScope(sc); } for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = members->tdata()[i]; + Dsymbol *s = (*members)[i]; s->importAll(sc); } @@ -964,7 +938,7 @@ void Module::semantic(Scope* unused_sc) // Do semantic() on members that don't depend on others for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = members->tdata()[i]; + { Dsymbol *s = (*members)[i]; //printf("\tModule('%s'): '%s'.semantic0()\n", toChars(), s->toChars()); s->semantic0(sc); @@ -972,7 +946,7 @@ void Module::semantic(Scope* unused_sc) // Pass 1 semantic routines: do public side of the definition for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = members->tdata()[i]; + { Dsymbol *s = (*members)[i]; //printf("\tModule('%s'): '%s'.semantic()\n", toChars(), s->toChars()); s->semantic(sc); @@ -993,7 +967,7 @@ void Module::semantic2(Scope* unused_sc) { for (size_t i = 0; i < deferred.dim; i++) { - Dsymbol *sd = deferred.tdata()[i]; + Dsymbol *sd = deferred[i]; sd->error("unable to resolve forward reference in definition"); } @@ -1017,7 +991,7 @@ void Module::semantic2(Scope* unused_sc) for (size_t i = 0; i < members->dim; i++) { Dsymbol *s; - s = members->tdata()[i]; + s = (*members)[i]; s->semantic2(sc); } @@ -1045,7 +1019,7 @@ void Module::semantic3(Scope* unused_sc) for (size_t i = 0; i < members->dim; i++) { Dsymbol *s; - s = members->tdata()[i]; + s = (*members)[i]; //printf("Module %s: %s.semantic3()\n", toChars(), s->toChars()); s->semantic3(sc); } @@ -1068,7 +1042,7 @@ void Module::inlineScan() //printf("Module = %p\n", sc.scopesym); for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = members->tdata()[i]; + { Dsymbol *s = (*members)[i]; //if (global.params.verbose) //printf("inline scan symbol %s\n", s->toChars()); @@ -1093,7 +1067,7 @@ void Module::gensymfile() buf.writenl(); for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = members->tdata()[i]; + { Dsymbol *s = (*members)[i]; s->toCBuffer(&buf, &hgs); } @@ -1154,7 +1128,7 @@ Dsymbol *Module::symtabInsert(Dsymbol *s) void Module::clearCache() { for (size_t i = 0; i < amodules.dim; i++) - { Module *m = amodules.tdata()[i]; + { Module *m = amodules[i]; m->searchCacheIdent = NULL; } } @@ -1168,7 +1142,7 @@ void Module::addDeferredSemantic(Dsymbol *s) // Don't add it if it is already there for (size_t i = 0; i < deferred.dim; i++) { - Dsymbol *sd = deferred.tdata()[i]; + Dsymbol *sd = deferred[i]; if (sd == s) return; @@ -1238,7 +1212,6 @@ void Module::runDeferredSemantic() int Module::imports(Module *m) { //printf("%s Module::imports(%s)\n", toChars(), m->toChars()); - int aimports_dim = aimports.dim; #if 0 for (size_t i = 0; i < aimports.dim; i++) { Module *mi = (Module *)aimports.data[i]; @@ -1246,7 +1219,7 @@ int Module::imports(Module *m) } #endif for (size_t i = 0; i < aimports.dim; i++) - { Module *mi = aimports.tdata()[i]; + { Module *mi = aimports[i]; if (mi == m) return TRUE; if (!mi->insearch) @@ -1270,7 +1243,7 @@ int Module::selfImports() if (!selfimports) { for (size_t i = 0; i < amodules.dim; i++) - { Module *mi = amodules.tdata()[i]; + { Module *mi = amodules[i]; //printf("\t[%d] %s\n", i, mi->toChars()); mi->insearch = 0; } @@ -1278,7 +1251,7 @@ int Module::selfImports() selfimports = imports(this) + 1; for (size_t i = 0; i < amodules.dim; i++) - { Module *mi = amodules.tdata()[i]; + { Module *mi = amodules[i]; //printf("\t[%d] %s\n", i, mi->toChars()); mi->insearch = 0; } @@ -1303,7 +1276,7 @@ char *ModuleDeclaration::toChars() if (packages && packages->dim) { for (size_t i = 0; i < packages->dim; i++) - { Identifier *pid = packages->tdata()[i]; + { Identifier *pid = (*packages)[i]; buf.writestring(pid->toChars()); buf.writeByte('.'); @@ -1340,7 +1313,7 @@ DsymbolTable *Package::resolve(Identifiers *packages, Dsymbol **pparent, Package if (packages) { for (size_t i = 0; i < packages->dim; i++) - { Identifier *pid = packages->tdata()[i]; + { Identifier *pid = (*packages)[i]; Dsymbol *p; p = dst->lookup(pid); diff --git a/dmd2/module.h b/dmd2/module.h index 609017ea..82156d7d 100644 --- a/dmd2/module.h +++ b/dmd2/module.h @@ -79,7 +79,6 @@ struct Module : Package unsigned errors; // if any errors in file unsigned 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; #ifdef IN_GCC @@ -141,8 +140,6 @@ struct Module : Package bool read(Loc loc); // read file, returns 'true' if succeed, 'false' otherwise. #if IN_LLVM void parse(bool gen_docs = false); // syntactic parse -#elif IN_GCC - void parse(bool dump_source = false); // syntactic parse #else void parse(); // syntactic parse #endif diff --git a/dmd2/mtype.c b/dmd2/mtype.c index 2958f4e9..48faf831 100644 --- a/dmd2/mtype.c +++ b/dmd2/mtype.c @@ -87,10 +87,10 @@ int REALSIZE = 16; int REALPAD = 6; int REALALIGNSIZE = 16; #elif TARGET_LINUX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS -int REALSIZE = 12; +int REALSIZE = 12; // FIXME: We differ from DMD here, yet target defines are never set?! int REALPAD = 2; int REALALIGNSIZE = 4; -#elif IN_GCC +#elif defined(IN_GCC) int REALSIZE = 0; int REALPAD = 0; int REALALIGNSIZE = 0; @@ -131,6 +131,7 @@ ClassDeclaration *Type::typeinfoshared; ClassDeclaration *Type::typeinfowild; TemplateDeclaration *Type::associativearray; +TemplateDeclaration *Type::rtinfo; Type *Type::tvoidptr; Type *Type::tstring; @@ -1399,7 +1400,7 @@ Type *Type::aliasthisOf() if (spec && global.errors != olderrs) spec->errors = global.errors - olderrs; } - if (!global.errors) + if (!fd->errors) { Type *t = fd->type->nextOf(); t = t->substWildTo(mod == 0 ? MODmutable : mod); @@ -1728,9 +1729,11 @@ Type *Type::merge() { sv->ptrvalue = this; +#if IN_LLVM // we still need deco strings to be unique // or Type::equals fails, which breaks a bunch of stuff, // like covariant member function overloads. + // TODO: Check if and why this is still needed. OutBuffer mangle; toDecoBuffer(&mangle, 0, true); StringValue* sv2 = deco_stringtable.update((char *)mangle.data, mangle.offset); @@ -1742,8 +1745,11 @@ Type *Type::merge() else { sv2->ptrvalue = this; - deco = (char *)sv2->lstring.string; + deco = (char *)sv2->toDchars(); } +#else + deco = (char *)sv->toDchars(); +#endif //printf("new value, deco = '%s' %p\n", t->deco, t->deco); } } @@ -2044,7 +2050,13 @@ Expression *Type::getProperty(Loc loc, Identifier *ident) error(loc, "void does not have an initializer"); if (ty == Tfunction) error(loc, "function does not have an initializer"); - e = defaultInitLiteral(loc); + if (toBasetype()->ty == Tstruct && + ((TypeStruct *)toBasetype())->sym->isNested()) + { + e = defaultInit(loc); + } + else + e = defaultInitLiteral(loc); } else if (ident == Id::mangleof) { const char *s; @@ -2118,7 +2130,13 @@ Expression *Type::dotExp(Scope *sc, Expression *e, Identifier *ident) } else if (ident == Id::init) { - e = defaultInitLiteral(e->loc); + if (toBasetype()->ty == Tstruct && + ((TypeStruct *)toBasetype())->sym->isNested()) + { + e = defaultInit(e->loc); + } + else + e = defaultInitLiteral(e->loc); goto Lreturn; } } @@ -2143,6 +2161,15 @@ Lreturn: return e; } +/************************************ + * Return alignment to use for this type. + */ + +structalign_t Type::alignment() +{ + return STRUCTALIGN_DEFAULT; +} + /*************************************** * Figures out what to do with an undefined member reference * for classes and structs. @@ -2191,10 +2218,9 @@ Expression *Type::noMember(Scope *sc, Expression *e, Identifier *ident) StringExp *se = new StringExp(e->loc, ident->toChars()); Objects *tiargs = new Objects(); tiargs->push(se); - e = new DotTemplateInstanceExp(e->loc, e, Id::opDispatch, tiargs); - ((DotTemplateInstanceExp *)e)->ti->tempdecl = td; - e = e->semantic(sc); - return e; + DotTemplateInstanceExp *dti = new DotTemplateInstanceExp(e->loc, e, Id::opDispatch, tiargs); + dti->ti->tempdecl = td; + return dti->semantic(sc, 1); } /* See if we should forward to the alias this. @@ -2204,19 +2230,14 @@ Expression *Type::noMember(Scope *sc, Expression *e, Identifier *ident) * e.aliasthis.ident */ e = resolveAliasThis(sc, e); - e = new DotIdExp(e->loc, e, ident); - return e->semantic(sc); + DotIdExp *die = new DotIdExp(e->loc, e, ident); + return die->semantic(sc, 1); } } return Type::dotExp(sc, e, ident); } -unsigned Type::memalign(unsigned salign) -{ - return salign; -} - void Type::error(Loc loc, const char *format, ...) { va_list ap; @@ -2859,11 +2880,11 @@ unsigned TypeBasic::alignsize() } #if IN_LLVM -unsigned TypeBasic::memalign(unsigned salign) +unsigned TypeBasic::alignment() { if (global.params.cpu == ARCHx86_64 && (ty == Tfloat80 || ty == Timaginary80)) return 16; - return Type::memalign(salign); + return Type::alignment(); } #endif @@ -3354,7 +3375,7 @@ MATCH TypeBasic::implicitConvTo(Type *to) return MATCHnomatch; TypeBasic *tob; - if (to->ty == Tvector) + if (to->ty == Tvector && to->deco) { TypeVector *tv = (TypeVector *)to; tob = tv->elementType(); @@ -3422,6 +3443,8 @@ TypeBasic *TypeBasic::isTypeBasic() /* The basetype must be one of: * byte[16],ubyte[16],short[8],ushort[8],int[4],uint[4],long[2],ulong[2],float[4],double[2] + * For AVX: + * byte[32],ubyte[32],short[16],ushort[16],int[8],uint[8],long[4],ulong[4],float[8],double[4] */ TypeVector::TypeVector(Loc loc, Type *basetype) : Type(Tvector) @@ -3456,8 +3479,9 @@ Type *TypeVector::semantic(Loc loc, Scope *sc) return this; } - if (t->size(loc) != 16) - { error(loc, "base type of __vector must be a 16 byte static array, not %s", t->toChars()); + d_uns64 sz = t->size(loc); + if (sz != 16 && sz != 32) + { error(loc, "base type of __vector must be a 16 or 32 byte static array, not %s", t->toChars()); return terror; } TypeBasic *tb = t->nextOf()->isTypeBasic(); @@ -3511,12 +3535,12 @@ void TypeVector::toDecoBuffer(OutBuffer *buf, int flag, bool mangle) d_uns64 TypeVector::size(Loc loc) { - return 16; + return basetype->size(); } unsigned TypeVector::alignsize() { - return 16; + return (unsigned)basetype->size(); } Expression *TypeVector::getProperty(Loc loc, Identifier *ident) @@ -3865,7 +3889,7 @@ void TypeSArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol sc = sc->push(sym); dim = dim->semantic(sc); - dim = dim->optimize(WANTvalue | WANTinterpret); + dim = dim->ctfeInterpret(); uinteger_t d = dim->toUInteger(); sc = sc->pop(); @@ -3874,7 +3898,7 @@ void TypeSArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol { error(loc, "tuple index %llu exceeds length %u", d, td->objects->dim); goto Ldefault; } - Object *o = td->objects->tdata()[(size_t)d]; + Object *o = (*td->objects)[(size_t)d]; if (o->dyncast() == DYNCAST_DSYMBOL) { *ps = (Dsymbol *)o; @@ -3900,7 +3924,7 @@ void TypeSArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol */ Objects *objects = new Objects; objects->setDim(1); - objects->tdata()[0] = o; + (*objects)[0] = o; TupleDeclaration *tds = new TupleDeclaration(loc, td->ident, objects); *ps = tds; @@ -3927,14 +3951,14 @@ Type *TypeSArray::semantic(Loc loc, Scope *sc) { TupleDeclaration *sd = s->isTupleDeclaration(); dim = semanticLength(sc, sd, dim); - dim = dim->optimize(WANTvalue | WANTinterpret); + dim = dim->ctfeInterpret(); uinteger_t d = dim->toUInteger(); if (d >= sd->objects->dim) { error(loc, "tuple index %llu exceeds %u", d, sd->objects->dim); return Type::terror; } - Object *o = sd->objects->tdata()[(size_t)d]; + Object *o = (*sd->objects)[(size_t)d]; if (o->dyncast() != DYNCAST_TYPE) { error(loc, "%s is not a type", toChars()); return Type::terror; @@ -3966,11 +3990,17 @@ Type *TypeSArray::semantic(Loc loc, Scope *sc) */ return this; } - dim = dim->optimize(WANTvalue | WANTinterpret); + dim = dim->ctfeInterpret(); + errors = global.errors; dinteger_t d1 = dim->toInteger(); + if (errors != global.errors) + goto Lerror; dim = dim->implicitCastTo(sc, tsize_t); dim = dim->optimize(WANTvalue); + errors = global.errors; dinteger_t d2 = dim->toInteger(); + if (errors != global.errors) + goto Lerror; if (dim->op == TOKerror) goto Lerror; @@ -4015,7 +4045,7 @@ Type *TypeSArray::semantic(Loc loc, Scope *sc) { error(loc, "tuple index %llu exceeds %u", d, tt->arguments->dim); goto Lerror; } - Parameter *arg = tt->arguments->tdata()[(size_t)d]; + Parameter *arg = (*tt->arguments)[(size_t)d]; return arg->type; } case Tstruct: @@ -4094,17 +4124,17 @@ Expression *TypeSArray::dotExp(Scope *sc, Expression *e, Identifier *ident) return e; } +structalign_t TypeSArray::alignment() +{ + return next->alignment(); +} + int TypeSArray::isString() { TY nty = next->toBasetype()->ty; return nty == Tchar || nty == Twchar || nty == Tdchar; } -unsigned TypeSArray::memalign(unsigned salign) -{ - return next->memalign(salign); -} - MATCH TypeSArray::constConv(Type *to) { if (to->ty == Tsarray) @@ -4210,7 +4240,7 @@ Expression *TypeSArray::defaultInitLiteral(Loc loc) Expressions *elements = new Expressions(); elements->setDim(d); for (size_t i = 0; i < d; i++) - elements->tdata()[i] = elementinit; + (*elements)[i] = elementinit; ArrayLiteralExp *ae = new ArrayLiteralExp(0, elements); ae->type = this; return ae; @@ -4895,6 +4925,15 @@ MATCH TypeAArray::constConv(Type *to) return Type::constConv(to); } +Type *TypeAArray::reliesOnTident(TemplateParameters *tparams) +{ + Type *t = TypeNext::reliesOnTident(tparams); + if (!t) + t = index->reliesOnTident(tparams); + return t; +} + + /***************************** TypePointer *****************************/ TypePointer::TypePointer(Type *t) @@ -4916,7 +4955,7 @@ Type *TypePointer::syntaxCopy() Type *TypePointer::semantic(Loc loc, Scope *sc) { - //printf("TypePointer::semantic()\n"); + //printf("TypePointer::semantic() %s\n", toChars()); if (deco) return this; Type *n = next->semantic(loc, sc); @@ -4933,8 +4972,19 @@ Type *TypePointer::semantic(Loc loc, Scope *sc) } next = n; if (next->ty != Tfunction) - transitive(); + { transitive(); + return merge(); + } +#if 1 return merge(); +#else + deco = merge()->deco; + /* Don't return merge(), because arg identifiers and default args + * can be different + * even though the types match + */ + return this; +#endif } @@ -5302,6 +5352,8 @@ int Type::covariant(Type *t, StorageClass *pstc) } else if (t1n->ty == t2n->ty && t1n->implicitConvTo(t2n)) goto Lcovariant; + else if (t1n->ty == Tnull && t1n->implicitConvTo(t2n)) + goto Lcovariant; } goto Lnotcovariant; @@ -5536,7 +5588,7 @@ void TypeFunction::toCBufferWithAttributes(OutBuffer *buf, Identifier *ident, Hd { buf->writeByte('('); for (size_t i = 0; i < td->origParameters->dim; i++) { - TemplateParameter *tp = td->origParameters->tdata()[i]; + TemplateParameter *tp = (*td->origParameters)[i]; if (i) buf->writestring(", "); tp->toCBuffer(buf, hgs); @@ -5547,18 +5599,13 @@ void TypeFunction::toCBufferWithAttributes(OutBuffer *buf, Identifier *ident, Hd inuse--; } -void TypeFunction::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) +// kind is inserted before the argument list and will usually be "function" or "delegate". +void functionToCBuffer2(TypeFunction *t, OutBuffer *buf, HdrGenState *hgs, int mod, const char *kind) { - //printf("TypeFunction::toCBuffer2() this = %p, ref = %d\n", this, isref); - if (inuse) - { inuse = 2; // flag error to caller - return; - } - inuse++; if (hgs->ddoc != 1) { const char *p = NULL; - switch (linkage) + switch (t->linkage) { case LINKd: p = NULL; break; case LINKc: p = "C"; break; @@ -5579,14 +5626,27 @@ void TypeFunction::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) buf->writestring(") "); } } - if (next) + if (t->next) { - next->toCBuffer2(buf, hgs, 0); + t->next->toCBuffer2(buf, hgs, 0); buf->writeByte(' '); } - buf->writestring("function"); - Parameter::argsToCBuffer(buf, hgs, parameters, varargs); - attributesToCBuffer(buf, mod); + buf->writestring(kind); + Parameter::argsToCBuffer(buf, hgs, t->parameters, t->varargs); + t->attributesToCBuffer(buf, mod); +} + +void TypeFunction::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) +{ + //printf("TypeFunction::toCBuffer2() this = %p, ref = %d\n", this, isref); + if (inuse) + { inuse = 2; // flag error to caller + return; + } + inuse++; + + functionToCBuffer2(this, buf, hgs, mod, "function"); + inuse--; } @@ -5642,10 +5702,10 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc) if (parameters) { tf->parameters = (Parameters *)parameters->copy(); for (size_t i = 0; i < parameters->dim; i++) - { Parameter *arg = parameters->tdata()[i]; + { Parameter *arg = (*parameters)[i]; Parameter *cpy = (Parameter *)mem.malloc(sizeof(Parameter)); memcpy(cpy, arg, sizeof(Parameter)); - tf->parameters->tdata()[i] = cpy; + (*tf->parameters)[i] = cpy; } } @@ -5767,24 +5827,12 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc) e = resolveProperties(argsc, e); if (e->op == TOKfunction) // see Bugzilla 4820 { FuncExp *fe = (FuncExp *)e; - if (fe->fd) - { if (fe->fd->tok == TOKreserved) - { - if (fe->type->ty == Tpointer) - { - fe->fd->vthis = NULL; - fe->fd->tok = TOKfunction; - } - else - fe->fd->tok = TOKdelegate; - } - // Replace function literal with a function symbol, - // since default arg expression must be copied when used - // and copying the literal itself is wrong. - e = new VarExp(e->loc, fe->fd, 0); - e = new AddrExp(e->loc, e); - e = e->semantic(argsc); - } + // Replace function literal with a function symbol, + // since default arg expression must be copied when used + // and copying the literal itself is wrong. + e = new VarExp(e->loc, fe->fd, 0); + e = new AddrExp(e->loc, e); + e = e->semantic(argsc); } e = e->implicitCastTo(argsc, fparam->type); fparam->defaultArg = e; @@ -5795,8 +5843,13 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc) */ if (t->ty == Ttuple) { + /* TypeFunction::parameter also is used as the storage of + * Parameter objects for FuncDeclaration. So we should copy + * the elements of TypeTuple::arguments to avoid unintended + * sharing of Parameter object among other functions. + */ TypeTuple *tt = (TypeTuple *)t; - if (fparam->storageClass && tt->arguments && tt->arguments->dim) + if (tt->arguments && tt->arguments->dim) { /* Propagate additional storage class from tuple parameters to their * element-parameters. @@ -5807,7 +5860,7 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc) newparams->setDim(tdim); for (size_t j = 0; j < tdim; j++) { Parameter *narg = (*tt->arguments)[j]; - newparams->tdata()[j] = new Parameter(narg->storageClass | fparam->storageClass, + (*newparams)[j] = new Parameter(narg->storageClass | fparam->storageClass, narg->type, narg->ident, narg->defaultArg); } fparam->type = new TypeTuple(newparams); @@ -5828,7 +5881,7 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc) if (fparam->storageClass & STCauto) { if (fargs && i < fargs->dim) - { Expression *farg = fargs->tdata()[i]; + { Expression *farg = (*fargs)[i]; if (farg->isLvalue()) ; // ref parameter else @@ -6008,7 +6061,7 @@ int TypeFunction::callMatch(Expression *ethis, Expressions *args, int flag) if (u >= nparams) break; Parameter *p = Parameter::getNth(parameters, u); - Expression *arg = args->tdata()[u]; + Expression *arg = (*args)[u]; assert(arg); if (!(p->storageClass & STClazy && p->type->ty == Tvoid && arg->type->ty != Tvoid)) @@ -6049,7 +6102,7 @@ int TypeFunction::callMatch(Expression *ethis, Expressions *args, int flag) goto L1; // try typesafe variadics } { - Expression *arg = args->tdata()[u]; + Expression *arg = (*args)[u]; assert(arg); if (arg->op == TOKfunction) @@ -6064,17 +6117,38 @@ int TypeFunction::callMatch(Expression *ethis, Expressions *args, int flag) Type *targ = arg->type; Type *tprm = wildmatch ? p->type->substWildTo(wildmatch) : p->type; + if (p->storageClass & STClazy && tprm->ty == Tvoid && targ->ty != Tvoid) + m = MATCHconvert; + else + { + //printf("%s of type %s implicitConvTo %s\n", arg->toChars(), targ->toChars(), tprm->toChars()); + if (flag) + // for partial ordering, value is an irrelevant mockup, just look at the type + m = targ->implicitConvTo(tprm); + else + m = arg->implicitConvTo(tprm); + //printf("match %d\n", m); + } + // Non-lvalues do not match ref or out parameters if (p->storageClass & STCref) - { if (!arg->isLvalue()) - { if (arg->op == TOKstring && tprm->ty == Tsarray) + { if (m && !arg->isLvalue()) + { + Type *ta = targ->aliasthisOf(); + if (arg->op == TOKstring && tprm->ty == Tsarray) { if (targ->ty != Tsarray) targ = new TypeSArray(targ->nextOf(), new IntegerExp(0, ((StringExp *)arg)->len, Type::tindex)); } + else if (ta && ta->implicitConvTo(tprm)) + { + goto Nomatch; + } else if (arg->op == TOKstructliteral) + { match = MATCHconvert; + } else if (arg->op == TOKcall) { CallExp *ce = (CallExp *)arg; @@ -6090,13 +6164,24 @@ int TypeFunction::callMatch(Expression *ethis, Expressions *args, int flag) goto Nomatch; } - /* Don't allow static arrays to be passed to mutable references - * to static arrays if the argument cannot be modified. - */ Type *targb = targ->toBasetype(); Type *tprmb = tprm->toBasetype(); //printf("%s\n", targb->toChars()); //printf("%s\n", tprmb->toChars()); + + /* find most derived alias this type being matched. + */ + while (1) + { + Type *tat = targb->aliasthisOf(); + if (!tat || !tat->implicitConvTo(tprm)) + break; + targb = tat; + } + + /* Don't allow static arrays to be passed to mutable references + * to static arrays if the argument cannot be modified. + */ if (targb->nextOf() && tprmb->ty == Tsarray && !MODimplicitConv(targb->nextOf()->mod, tprmb->nextOf()->mod)) goto Nomatch; @@ -6106,22 +6191,9 @@ int TypeFunction::callMatch(Expression *ethis, Expressions *args, int flag) goto Nomatch; } else if (p->storageClass & STCout) - { if (!arg->isLvalue()) + { if (m && !arg->isLvalue()) goto Nomatch; } - - if (p->storageClass & STClazy && tprm->ty == Tvoid && targ->ty != Tvoid) - m = MATCHconvert; - else - { - //printf("%s of type %s implicitConvTo %s\n", arg->toChars(), targ->toChars(), tprm->toChars()); - if (flag) - // for partial ordering, value is an irrelevant mockup, just look at the type - m = targ->implicitConvTo(tprm); - else - m = arg->implicitConvTo(tprm); - //printf("match %d\n", m); - } } /* prefer matching the element type rather than the array @@ -6150,7 +6222,7 @@ int TypeFunction::callMatch(Expression *ethis, Expressions *args, int flag) { TypeArray *ta = (TypeArray *)tb; for (; u < nargs; u++) { - Expression *arg = args->tdata()[u]; + Expression *arg = (*args)[u]; assert(arg); #if 1 if (arg->op == TOKfunction) @@ -6338,6 +6410,7 @@ Type *TypeDelegate::syntaxCopy() Type *TypeDelegate::semantic(Loc loc, Scope *sc) { + //printf("TypeDelegate::semantic() %s\n", toChars()); if (deco) // if semantic() already run { //printf("already done\n"); @@ -6348,13 +6421,16 @@ Type *TypeDelegate::semantic(Loc loc, Scope *sc) * be removed from next before the merge. */ +#if 1 + return merge(); +#else /* Don't return merge(), because arg identifiers and default args * can be different * even though the types match */ - //deco = merge()->deco; - //return this; - return merge(); + deco = merge()->deco; + return this; +#endif } d_uns64 TypeDelegate::size(Loc loc) @@ -6390,12 +6466,8 @@ void TypeDelegate::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) { toCBuffer3(buf, hgs, mod); return; } - TypeFunction *tf = (TypeFunction *)next; - tf->next->toCBuffer2(buf, hgs, 0); - buf->writestring(" delegate"); - Parameter::argsToCBuffer(buf, hgs, tf->parameters, tf->varargs); - tf->attributesToCBuffer(buf, mod); + functionToCBuffer2((TypeFunction *)next, buf, hgs, mod, "delegate"); } Expression *TypeDelegate::defaultInit(Loc loc) @@ -6461,7 +6533,7 @@ void TypeQualified::syntaxCopyHelper(TypeQualified *t) idents.setDim(t->idents.dim); for (size_t i = 0; i < idents.dim; i++) { - Identifier *id = t->idents.tdata()[i]; + Identifier *id = t->idents[i]; if (id->dyncast() == DYNCAST_DSYMBOL) { TemplateInstance *ti = (TemplateInstance *)id; @@ -6469,7 +6541,7 @@ void TypeQualified::syntaxCopyHelper(TypeQualified *t) ti = (TemplateInstance *)ti->syntaxCopy(NULL); id = (Identifier *)ti; } - idents.tdata()[i] = id; + idents[i] = id; } } @@ -6482,7 +6554,7 @@ void TypeQualified::addIdent(Identifier *ident) void TypeQualified::toCBuffer2Helper(OutBuffer *buf, HdrGenState *hgs) { for (size_t i = 0; i < idents.dim; i++) - { Identifier *id = idents.tdata()[i]; + { Identifier *id = idents[i]; buf->writeByte('.'); @@ -6534,7 +6606,7 @@ void TypeQualified::resolveHelper(Loc loc, Scope *sc, //printf("\t2: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind()); for (size_t i = 0; i < idents.dim; i++) { - Identifier *id = idents.tdata()[i]; + Identifier *id = idents[i]; Dsymbol *sm = s->searchX(loc, sc, id); //printf("\t3: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind()); //printf("\tgetType = '%s'\n", s->getType()->toChars()); @@ -6544,9 +6616,7 @@ void TypeQualified::resolveHelper(Loc loc, Scope *sc, v = s->isVarDeclaration(); if (v && id == Id::length) { - e = v->getConstInitializer(); - if (!e) - e = new VarExp(loc, v); + e = new VarExp(loc, v); t = e->type; if (!t) goto Lerror; @@ -6557,7 +6627,7 @@ void TypeQualified::resolveHelper(Loc loc, Scope *sc, e = new DsymbolExp(loc, s, 0); do { - id = idents.tdata()[i]; + id = idents[i]; e = new DotIdExp(loc, e, id); } while (++i < idents.dim); e = e->semantic(sc); @@ -6590,7 +6660,7 @@ void TypeQualified::resolveHelper(Loc loc, Scope *sc, L3: for (; i < idents.dim; i++) { - id = idents.tdata()[i]; + id = idents[i]; //printf("e: '%s', id: '%s', type = %s\n", e->toChars(), id->toChars(), e->type->toChars()); e = new DotIdExp(e->loc, e, id); e = e->semantic(sc); @@ -6819,7 +6889,7 @@ Dsymbol *TypeIdentifier::toDsymbol(Scope *sc) { for (size_t i = 0; i < idents.dim; i++) { - Identifier *id = idents.tdata()[i]; + Identifier *id = idents[i]; s = s->searchX(loc, sc, id); if (!s) // failed to find a symbol { //printf("\tdidn't find a symbol\n"); @@ -6872,7 +6942,7 @@ Type *TypeIdentifier::reliesOnTident(TemplateParameters *tparams) if (idents.dim == 0) { for (size_t i = 0; i < tparams->dim; i++) - { TemplateParameter *tp = tparams->tdata()[i]; + { TemplateParameter *tp = (*tparams)[i]; if (tp->ident->equals(ident)) return this; @@ -6889,7 +6959,7 @@ Expression *TypeIdentifier::toExpression() Expression *e = new IdentifierExp(loc, ident); for (size_t i = 0; i < idents.dim; i++) { - Identifier *id = idents.tdata()[i]; + Identifier *id = idents[i]; e = new DotIdExp(loc, e, id); } @@ -7008,6 +7078,33 @@ Dsymbol *TypeInstance::toDsymbol(Scope *sc) return s; } +Type *TypeInstance::reliesOnTident(TemplateParameters *tparams) +{ + if (tparams) + { + for (size_t i = 0; i < tparams->dim; i++) + { + TemplateParameter *tp = (*tparams)[i]; + if (tempinst->name == tp->ident) + return this; + } + if (!tempinst->tiargs) + return NULL; + for (size_t i = 0; i < tempinst->tiargs->dim; i++) + { + Type *t = isType((*tempinst->tiargs)[i]); + t = t ? t->reliesOnTident(tparams) : NULL; + if (t) + return t; + } + return NULL; + } + else + { + return Type::reliesOnTident(tparams); + } +} + /***************************** TypeTypeof *****************************/ @@ -7160,7 +7257,7 @@ Type *TypeTypeof::semantic(Loc loc, Scope *sc) { if (!s) break; - Identifier *id = idents.tdata()[i]; + Identifier *id = idents[i]; s = s->searchX(loc, sc, id); } @@ -7240,7 +7337,7 @@ Type *TypeReturn::semantic(Loc loc, Scope *sc) { if (!s) break; - Identifier *id = idents.tdata()[i]; + Identifier *id = idents[i]; s = s->searchX(loc, sc, id); } if (s) @@ -7607,6 +7704,20 @@ Expression *TypeTypedef::dotExp(Scope *sc, Expression *e, Identifier *ident) return sym->basetype->dotExp(sc, e, ident); } +structalign_t TypeTypedef::alignment() +{ + if (sym->inuse) + { + sym->error("circular definition"); + sym->basetype = Type::terror; + return STRUCTALIGN_DEFAULT; + } + sym->inuse = 1; + structalign_t a = sym->basetype->alignment(); + sym->inuse = 0; + return a; +} + Expression *TypeTypedef::getProperty(Loc loc, Identifier *ident) { #if LOGDOTEXP @@ -7843,13 +7954,9 @@ d_uns64 TypeStruct::size(Loc loc) } unsigned TypeStruct::alignsize() -{ unsigned sz; - +{ sym->size(0); // give error for forward references - sz = sym->alignsize; - if (sz > sym->structalign) - sz = sym->structalign; - return sz; + return sym->alignsize; } Dsymbol *TypeStruct::toDsymbol(Scope *sc) @@ -7908,7 +8015,7 @@ Expression *TypeStruct::dotExp(Scope *sc, Expression *e, Identifier *ident) Expression *ev = e; for (size_t i = 0; i < sym->fields.dim; i++) - { VarDeclaration *v = sym->fields.tdata()[i]; + { VarDeclaration *v = sym->fields[i]; Expression *fe; if (i == 0 && sc->func && sym->fields.dim > 1 && e->hasSideEffect()) @@ -8061,7 +8168,10 @@ L1: e = e->semantic(sc); return e; } - return new VarExp(e->loc, d, 1); + VarExp *ve = new VarExp(e->loc, d, 1); + if (d->isVarDeclaration() && d->needThis()) + ve->type = d->type->addMod(e->type->mod); + return ve; } if (d->isDataseg()) @@ -8098,10 +8208,11 @@ L1: return de->semantic(sc); } -unsigned TypeStruct::memalign(unsigned salign) +structalign_t TypeStruct::alignment() { - sym->size(0); // give error for forward references - return sym->structalign; + if (sym->alignment == 0) + sym->size(0); + return sym->alignment; } Expression *TypeStruct::defaultInit(Loc loc) @@ -8124,13 +8235,13 @@ Expression *TypeStruct::defaultInitLiteral(Loc loc) #if LOGDEFAULTINIT printf("TypeStruct::defaultInitLiteral() '%s'\n", toChars()); #endif - if (sym->isNested()) - return defaultInit(loc); + //if (sym->isNested()) + // return defaultInit(loc); Expressions *structelems = new Expressions(); - structelems->setDim(sym->fields.dim); + structelems->setDim(sym->fields.dim - sym->isnested); for (size_t j = 0; j < structelems->dim; j++) { - VarDeclaration *vd = sym->fields.tdata()[j]; + VarDeclaration *vd = sym->fields[j]; Expression *e; if (vd->init) { if (vd->init->isVoidInitializer()) @@ -8148,7 +8259,7 @@ Expression *TypeStruct::defaultInitLiteral(Loc loc) /* Copy from the initializer symbol for larger symbols, * otherwise the literals expressed as code get excessively large. */ - if (size(loc) > PTRSIZE * 4) + if (size(loc) > PTRSIZE * 4 && !sym->isnested) structinit->sinit = sym->toInitializer(); #endif @@ -8183,7 +8294,7 @@ int TypeStruct::isAssignable() * then one cannot assign this struct. */ for (size_t i = 0; i < sym->fields.dim; i++) - { VarDeclaration *v = sym->fields.tdata()[i]; + { VarDeclaration *v = sym->fields[i]; //printf("%s [%d] v = (%s) %s, v->offset = %d, v->parent = %s", sym->toChars(), i, v->kind(), v->toChars(), v->offset, v->parent->kind()); if (i == 0) ; @@ -8217,7 +8328,7 @@ int TypeStruct::hasPointers() sym->size(0); // give error for forward references for (size_t i = 0; i < s->fields.dim; i++) { - Dsymbol *sm = s->fields.tdata()[i]; + Dsymbol *sm = s->fields[i]; Declaration *d = sm->isDeclaration(); if (d->storage_class & STCref || d->hasPointers()) return TRUE; @@ -8246,14 +8357,15 @@ MATCH TypeStruct::implicitConvTo(Type *to) { m = MATCHexact; // exact match if (mod != to->mod) { + m = MATCHconst; if (MODimplicitConv(mod, to->mod)) - m = MATCHconst; + ; else { /* Check all the fields. If they can all be converted, * allow the conversion. */ for (size_t i = 0; i < sym->fields.dim; i++) - { Dsymbol *s = sym->fields.tdata()[i]; + { Dsymbol *s = sym->fields[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v && v->storage_class & STCfield); @@ -8263,11 +8375,15 @@ MATCH TypeStruct::implicitConvTo(Type *to) // 'to' type Type *tv = v->type->castMod(to->mod); - //printf("\t%s => %s, match = %d\n", v->type->toChars(), tv->toChars(), tvf->implicitConvTo(tv)); - if (tvf->implicitConvTo(tv) < MATCHconst) - return MATCHnomatch; + // field match + MATCH mf = tvf->implicitConvTo(tv); + //printf("\t%s => %s, match = %d\n", v->type->toChars(), tv->toChars(), mf); + + if (mf == MATCHnomatch) + return mf; + if (mf < m) // if field match is worse + m = mf; } - m = MATCHconst; } } } @@ -8408,7 +8524,7 @@ Expression *TypeClass::dotExp(Scope *sc, Expression *e, Identifier *ident) Expression *ev = e; for (size_t i = 0; i < sym->fields.dim; i++) - { VarDeclaration *v = sym->fields.tdata()[i]; + { VarDeclaration *v = sym->fields[i]; // Don't include hidden 'this' pointer if (v->isThisDeclaration()) continue; @@ -8638,14 +8754,12 @@ L1: return de; } -#if 0 // shouldn't this be here? if (s->isImport() || s->isModule() || s->isPackage()) { e = new DsymbolExp(e->loc, s, 0); e = e->semantic(sc); return e; } -#endif OverloadSet *o = s->isOverloadSet(); if (o) @@ -8706,11 +8820,10 @@ L1: e = de->semantic(sc); return e; } - else - { - VarExp *ve = new VarExp(e->loc, d, 1); - return ve; - } + VarExp *ve = new VarExp(e->loc, d, 1); + if (d->isVarDeclaration() && d->needThis()) + ve->type = d->type->addMod(e->type->mod); + return ve; } if (d->isDataseg()) @@ -8772,7 +8885,7 @@ MATCH TypeClass::implicitConvTo(Type *to) { if (cdto->scope) cdto->semantic(NULL); - if (cdto->isBaseOf(sym, NULL)) + if (cdto->isBaseOf(sym, NULL) && MODimplicitConv(mod, to->mod)) { //printf("'to' is base\n"); return MATCHconvert; } @@ -8867,7 +8980,7 @@ TypeTuple::TypeTuple(Parameters *arguments) { for (size_t i = 0; i < arguments->dim; i++) { - Parameter *arg = arguments->tdata()[i]; + Parameter *arg = (*arguments)[i]; assert(arg && arg->type); } } @@ -8887,11 +9000,11 @@ TypeTuple::TypeTuple(Expressions *exps) { arguments->setDim(exps->dim); for (size_t i = 0; i < exps->dim; i++) - { Expression *e = exps->tdata()[i]; + { Expression *e = (*exps)[i]; if (e->type->ty == Ttuple) e->error("cannot form tuple of tuples"); Parameter *arg = new Parameter(STCundefined, e->type, NULL, NULL); - arguments->tdata()[i] = arg; + (*arguments)[i] = arg; } } this->arguments = arguments; @@ -8958,8 +9071,8 @@ int TypeTuple::equals(Object *o) if (arguments->dim == tt->arguments->dim) { for (size_t i = 0; i < tt->arguments->dim; i++) - { Parameter *arg1 = arguments->tdata()[i]; - Parameter *arg2 = tt->arguments->tdata()[i]; + { Parameter *arg1 = (*arguments)[i]; + Parameter *arg2 = (*tt->arguments)[i]; if (!arg1->type->equals(arg2->type)) return 0; @@ -8976,7 +9089,7 @@ Type *TypeTuple::reliesOnTident(TemplateParameters *tparams) { for (size_t i = 0; i < arguments->dim; i++) { - Parameter *arg = arguments->tdata()[i]; + Parameter *arg = (*arguments)[i]; Type *t = arg->type->reliesOnTident(tparams); if (t) return t; @@ -8995,9 +9108,9 @@ Type *TypeTuple::makeConst() t->arguments = new Parameters(); t->arguments->setDim(arguments->dim); for (size_t i = 0; i < arguments->dim; i++) - { Parameter *arg = arguments->tdata()[i]; + { Parameter *arg = (*arguments)[i]; Parameter *narg = new Parameter(arg->storageClass, arg->type->constOf(), arg->ident, arg->defaultArg); - t->arguments->tdata()[i] = (Parameter *)narg; + (*t->arguments)[i] = (Parameter *)narg; } return t; } @@ -9090,11 +9203,11 @@ Type *TypeSlice::semantic(Loc loc, Scope *sc) TypeTuple *tt = (TypeTuple *)tbn; lwr = semanticLength(sc, tbn, lwr); - lwr = lwr->optimize(WANTvalue | WANTinterpret); + lwr = lwr->ctfeInterpret(); uinteger_t i1 = lwr->toUInteger(); upr = semanticLength(sc, tbn, upr); - upr = upr->optimize(WANTvalue | WANTinterpret); + upr = upr->ctfeInterpret(); uinteger_t i2 = upr->toUInteger(); if (!(i1 <= i2 && i2 <= tt->arguments->dim)) @@ -9105,7 +9218,7 @@ Type *TypeSlice::semantic(Loc loc, Scope *sc) Parameters *args = new Parameters; args->reserve(i2 - i1); for (size_t i = i1; i < i2; i++) - { Parameter *arg = tt->arguments->tdata()[i]; + { Parameter *arg = (*tt->arguments)[i]; args->push(arg); } @@ -9134,11 +9247,11 @@ void TypeSlice::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol sc = sc->push(sym); lwr = lwr->semantic(sc); - lwr = lwr->optimize(WANTvalue | WANTinterpret); + lwr = lwr->ctfeInterpret(); uinteger_t i1 = lwr->toUInteger(); upr = upr->semantic(sc); - upr = upr->optimize(WANTvalue | WANTinterpret); + upr = upr->ctfeInterpret(); uinteger_t i2 = upr->toUInteger(); sc = sc->pop(); @@ -9161,7 +9274,7 @@ void TypeSlice::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol objects->setDim(i2 - i1); for (size_t i = 0; i < objects->dim; i++) { - objects->tdata()[i] = td->objects->tdata()[(size_t)i1 + i]; + (*objects)[i] = (*td->objects)[(size_t)i1 + i]; } TupleDeclaration *tds = new TupleDeclaration(loc, td->ident, objects); @@ -9268,10 +9381,10 @@ Parameters *Parameter::arraySyntaxCopy(Parameters *args) a = new Parameters(); a->setDim(args->dim); for (size_t i = 0; i < a->dim; i++) - { Parameter *arg = args->tdata()[i]; + { Parameter *arg = (*args)[i]; arg = arg->syntaxCopy(); - a->tdata()[i] = arg; + (*a)[i] = arg; } } return a; @@ -9281,32 +9394,9 @@ char *Parameter::argsTypesToChars(Parameters *args, int varargs) { OutBuffer *buf = new OutBuffer(); -#if 1 HdrGenState hgs; argsToCBuffer(buf, &hgs, args, varargs); -#else - buf->writeByte('('); - if (args) - { OutBuffer argbuf; - HdrGenState hgs; - for (size_t i = 0; i < args->dim; i++) - { if (i) - buf->writeByte(','); - Parameter *arg = args->tdata()[i]; - argbuf.reset(); - arg->type->toCBuffer2(&argbuf, &hgs, 0); - buf->write(&argbuf); - } - if (varargs) - { - if (i && varargs == 1) - buf->writeByte(','); - buf->writestring("..."); - } - } - buf->writeByte(')'); -#endif return buf->toChars(); } @@ -9532,7 +9622,7 @@ int Parameter::foreach(Parameters *args, Parameter::ForeachDg dg, void *ctx, siz size_t n = pn ? *pn : 0; // take over index int result = 0; for (size_t i = 0; i < args->dim; i++) - { Parameter *arg = args->tdata()[i]; + { Parameter *arg = (*args)[i]; Type *t = arg->type->toBasetype(); if (t->ty == Ttuple) diff --git a/dmd2/mtype.h b/dmd2/mtype.h index 8a2b1a76..a35f9f5c 100644 --- a/dmd2/mtype.h +++ b/dmd2/mtype.h @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -48,7 +48,7 @@ struct HdrGenState; struct Parameter; // Back end -#if IN_GCC +#ifdef IN_GCC union tree_node; typedef union tree_node TYPE; typedef TYPE type; #endif @@ -215,6 +215,7 @@ struct Type : Object static ClassDeclaration *typeinfowild; static TemplateDeclaration *associativearray; + static TemplateDeclaration *rtinfo; static Type *basic[TMAX]; static unsigned char mangleChar[TMAX]; @@ -317,8 +318,8 @@ struct Type : Object virtual ClassDeclaration *isClassHandle(); virtual Expression *getProperty(Loc loc, Identifier *ident); virtual Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); + virtual structalign_t alignment(); Expression *noMember(Scope *sc, Expression *e, Identifier *ident); - virtual unsigned memalign(unsigned salign); virtual Expression *defaultInit(Loc loc = 0); virtual Expression *defaultInitLiteral(Loc loc); virtual Expression *voidInitLiteral(VarDeclaration *var); @@ -375,6 +376,7 @@ struct TypeError : Type Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); Expression *defaultInit(Loc loc); Expression *defaultInitLiteral(Loc loc); + TypeTuple *toArgTypes(); }; struct TypeNext : Type @@ -409,7 +411,7 @@ struct TypeBasic : Type d_uns64 size(Loc loc); unsigned alignsize(); #if IN_LLVM - unsigned memalign(unsigned salign); + unsigned alignment(); #endif Expression *getProperty(Loc loc, Identifier *ident); Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); @@ -488,7 +490,7 @@ struct TypeSArray : TypeArray Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); int isString(); int isZeroInit(Loc loc); - unsigned memalign(unsigned salign); + structalign_t alignment(); MATCH constConv(Type *to); MATCH implicitConvTo(Type *to); Expression *defaultInit(Loc loc); @@ -567,6 +569,7 @@ struct TypeAArray : TypeArray int isZeroInit(Loc loc); int checkBoolean(); TypeInfoDeclaration *getTypeInfoDeclaration(); + Type *reliesOnTident(TemplateParameters *tparams); Expression *toExpression(); int hasPointers(); TypeTuple *toArgTypes(); @@ -778,6 +781,7 @@ struct TypeInstance : TypeQualified void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); Type *semantic(Loc loc, Scope *sc); Dsymbol *toDsymbol(Scope *sc); + Type *reliesOnTident(TemplateParameters *tparams = NULL); MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch = NULL); }; @@ -817,7 +821,7 @@ struct TypeStruct : Type void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - unsigned memalign(unsigned salign); + structalign_t alignment(); Expression *defaultInit(Loc loc); Expression *defaultInitLiteral(Loc loc); Expression *voidInitLiteral(VarDeclaration *var); @@ -907,6 +911,7 @@ struct TypeTypedef : Type void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); + structalign_t alignment(); Expression *getProperty(Loc loc, Identifier *ident); int isintegral(); int isfloating(); diff --git a/dmd2/opover.c b/dmd2/opover.c index bcf1828c..de57524a 100644 --- a/dmd2/opover.c +++ b/dmd2/opover.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -12,6 +12,7 @@ #include #include #include +#include // memset() #if _MSC_VER #include #else @@ -355,9 +356,11 @@ Expression *UnaExp::op_overload(Scope *sc) /* Rewrite op(e1) as: * op(e1.aliasthis) */ - UnaExp *e = (UnaExp *)syntaxCopy(); - e->e1 = new DotIdExp(loc, e->e1, ad->aliasthis->ident); - return e->trySemantic(sc); + Expression *e1 = new DotIdExp(loc, this->e1, ad->aliasthis->ident); + Expression *e = copy(); + ((UnaExp *)e)->e1 = e1; + e = e->trySemantic(sc); + return e; } #endif } @@ -374,7 +377,7 @@ Expression *ArrayExp::op_overload(Scope *sc) if (fd) { for (size_t i = 0; i < arguments->dim; i++) - { Expression *x = arguments->tdata()[i]; + { Expression *x = (*arguments)[i]; // Create scope for '$' variable for this dimension ArrayScopeSymbol *sym = new ArrayScopeSymbol(sc, this); sym->loc = loc; @@ -393,7 +396,7 @@ Expression *ArrayExp::op_overload(Scope *sc) x = new CommaExp(0, av, x); x->semantic(sc); } - arguments->tdata()[i] = x; + (*arguments)[i] = x; sc = sc->pop(); } @@ -412,9 +415,11 @@ Expression *ArrayExp::op_overload(Scope *sc) /* Rewrite op(e1) as: * op(e1.aliasthis) */ - UnaExp *e = (UnaExp *)syntaxCopy(); - e->e1 = new DotIdExp(loc, e->e1, ad->aliasthis->ident); - return e->trySemantic(sc); + Expression *e1 = new DotIdExp(loc, this->e1, ad->aliasthis->ident); + Expression *e = copy(); + ((UnaExp *)e)->e1 = e1; + e = e->trySemantic(sc); + return e; } } return NULL; @@ -457,9 +462,11 @@ Expression *CastExp::op_overload(Scope *sc) /* Rewrite op(e1) as: * op(e1.aliasthis) */ - UnaExp *e = (UnaExp *)syntaxCopy(); - e->e1 = new DotIdExp(loc, e->e1, ad->aliasthis->ident); - return e->trySemantic(sc); + Expression *e1 = new DotIdExp(loc, this->e1, ad->aliasthis->ident); + Expression *e = copy(); + ((UnaExp *)e)->e1 = e1; + e = e->trySemantic(sc); + return e; } } return NULL; @@ -529,9 +536,9 @@ Expression *BinExp::op_overload(Scope *sc) */ args1.setDim(1); - args1.tdata()[0] = e1; + args1[0] = e1; args2.setDim(1); - args2.tdata()[0] = e2; + args2[0] = e2; argsset = 1; Match m; @@ -622,9 +629,9 @@ L1: if (!argsset) { args1.setDim(1); - args1.tdata()[0] = e1; + args1[0] = e1; args2.setDim(1); - args2.tdata()[0] = e2; + args2[0] = e2; } Match m; @@ -715,9 +722,11 @@ L1: /* Rewrite (e1 op e2) as: * (e1.aliasthis op e2) */ - BinExp *e = (BinExp *)syntaxCopy(); - e->e1 = new DotIdExp(loc, e->e1, ad1->aliasthis->ident); - return e->trySemantic(sc); + Expression *e1 = new DotIdExp(loc, this->e1, ad1->aliasthis->ident); + Expression *e = copy(); + ((BinExp *)e)->e1 = e1; + e = e->trySemantic(sc); + return e; } // Try alias this on second operand @@ -730,9 +739,11 @@ L1: /* Rewrite (e1 op e2) as: * (e1 op e2.aliasthis) */ - BinExp *e = (BinExp *)syntaxCopy(); - e->e2 = new DotIdExp(loc, e->e2, ad2->aliasthis->ident); - return e->trySemantic(sc); + Expression *e2 = new DotIdExp(loc, this->e2, ad2->aliasthis->ident); + Expression *e = copy(); + ((BinExp *)e)->e2 = e2; + e = e->trySemantic(sc); + return e; } #endif return NULL; @@ -776,9 +787,9 @@ Expression *BinExp::compare_overload(Scope *sc, Identifier *id) Expressions args2; args1.setDim(1); - args1.tdata()[0] = e1; + args1[0] = e1; args2.setDim(1); - args2.tdata()[0] = e2; + args2[0] = e2; Match m; memset(&m, 0, sizeof(m)); @@ -884,9 +895,11 @@ Expression *BinExp::compare_overload(Scope *sc, Identifier *id) /* Rewrite (e1 op e2) as: * (e1.aliasthis op e2) */ - BinExp *e = (BinExp *)syntaxCopy(); - e->e1 = new DotIdExp(loc, e->e1, ad1->aliasthis->ident); - return e->trySemantic(sc); + Expression *e1 = new DotIdExp(loc, this->e1, ad1->aliasthis->ident); + Expression *e = copy(); + ((BinExp *)e)->e1 = e1; + e = e->trySemantic(sc); + return e; } // Try alias this on second operand @@ -895,9 +908,11 @@ Expression *BinExp::compare_overload(Scope *sc, Identifier *id) /* Rewrite (e1 op e2) as: * (e1 op e2.aliasthis) */ - BinExp *e = (BinExp *)syntaxCopy(); - e->e2 = new DotIdExp(loc, e->e2, ad2->aliasthis->ident); - return e->trySemantic(sc); + Expression *e2 = new DotIdExp(loc, this->e2, ad2->aliasthis->ident); + Expression *e = copy(); + ((BinExp *)e)->e2 = e2; + e = e->trySemantic(sc); + return e; } return NULL; @@ -916,12 +931,20 @@ Expression *EqualExp::op_overload(Scope *sc) if (!(cd1->isCPPinterface() || cd2->isCPPinterface())) { /* Rewrite as: - * .object.opEquals(cast(Object)e1, cast(Object)e2) + * .object.opEquals(e1, e2) + */ + Expression *e1x = e1; + Expression *e2x = e2; + + /* * The explicit cast is necessary for interfaces, * see http://d.puremagic.com/issues/show_bug.cgi?id=4088 */ - Expression *e1x = new CastExp(loc, e1, ClassDeclaration::object->getType()); - Expression *e2x = new CastExp(loc, e2, ClassDeclaration::object->getType()); + Type *to = ClassDeclaration::object->getType(); + if (cd1->isInterfaceDeclaration()) + e1x = new CastExp(loc, e1, t1->isMutable() ? to : to->constOf()); + if (cd2->isInterfaceDeclaration()) + e2x = new CastExp(loc, e2, t2->isMutable() ? to : to->constOf()); Expression *e = new IdentifierExp(loc, Id::empty); e = new DotIdExp(loc, e, Id::object); @@ -968,7 +991,7 @@ Expression *BinAssignExp::op_overload(Scope *sc) Expressions *a = new Expressions(); a->push(e2); for (size_t i = 0; i < ae->arguments->dim; i++) - a->push(ae->arguments->tdata()[i]); + a->push((*ae->arguments)[i]); Objects *targsi = opToArg(sc, op); Expression *e = new DotTemplateInstanceExp(loc, ae->e1, fd->ident, targsi); @@ -1085,7 +1108,7 @@ Expression *BinAssignExp::op_overload(Scope *sc) */ args2.setDim(1); - args2.tdata()[0] = e2; + args2[0] = e2; Match m; memset(&m, 0, sizeof(m)); @@ -1132,9 +1155,11 @@ L1: /* Rewrite (e1 op e2) as: * (e1.aliasthis op e2) */ - BinExp *e = (BinExp *)syntaxCopy(); - e->e1 = new DotIdExp(loc, e->e1, ad1->aliasthis->ident); - return e->trySemantic(sc); + Expression *e1 = new DotIdExp(loc, this->e1, ad1->aliasthis->ident); + Expression *e = copy(); + ((BinExp *)e)->e1 = e1; + e = e->trySemantic(sc); + return e; } // Try alias this on second operand @@ -1144,9 +1169,11 @@ L1: /* Rewrite (e1 op e2) as: * (e1 op e2.aliasthis) */ - BinExp *e = (BinExp *)syntaxCopy(); - e->e2 = new DotIdExp(loc, e->e2, ad2->aliasthis->ident); - return e->trySemantic(sc); + Expression *e2 = new DotIdExp(loc, this->e2, ad2->aliasthis->ident); + Expression *e = copy(); + ((BinExp *)e)->e2 = e2; + e = e->trySemantic(sc); + return e; } #endif return NULL; @@ -1209,7 +1236,7 @@ int ForeachStatement::inferAggregate(Scope *sc, Dsymbol *&sapply) { Identifier *idapply = (op == TOKforeach) ? Id::apply : Id::applyReverse; #if DMDV2 - Identifier *idhead = (op == TOKforeach) ? Id::Ffront : Id::Fback; + Identifier *idfront = (op == TOKforeach) ? Id::Ffront : Id::Fback; int sliced = 0; #endif Type *tab; @@ -1262,7 +1289,7 @@ int ForeachStatement::inferAggregate(Scope *sc, Dsymbol *&sapply) } } - if (Dsymbol *shead = search_function(ad, idhead)) + if (Dsymbol *shead = ad->search(0, idfront, 0)) { // range aggregate break; } @@ -1316,7 +1343,7 @@ int ForeachStatement::inferApplyArgTypes(Scope *sc, Dsymbol *&sapply) if (sapply) // prefer opApply { for (size_t u = 0; u < arguments->dim; u++) - { Parameter *arg = arguments->tdata()[u]; + { Parameter *arg = (*arguments)[u]; if (arg->type) arg->type = arg->type->semantic(loc, sc); } @@ -1350,14 +1377,14 @@ int ForeachStatement::inferApplyArgTypes(Scope *sc, Dsymbol *&sapply) /* Return if no arguments need types. */ for (size_t u = 0; u < arguments->dim; u++) - { Parameter *arg = arguments->tdata()[u]; + { Parameter *arg = (*arguments)[u]; if (!arg->type) break; } AggregateDeclaration *ad; - Parameter *arg = arguments->tdata()[0]; + Parameter *arg = (*arguments)[0]; Type *taggr = aggr->type; assert(taggr); Type *tab = taggr->toBasetype(); @@ -1370,7 +1397,7 @@ int ForeachStatement::inferApplyArgTypes(Scope *sc, Dsymbol *&sapply) { if (!arg->type) arg->type = Type::tsize_t; // key type - arg = arguments->tdata()[1]; + arg = (*arguments)[1]; } if (!arg->type && tab->ty != Ttuple) arg->type = tab->nextOf(); // value type @@ -1383,7 +1410,7 @@ int ForeachStatement::inferApplyArgTypes(Scope *sc, Dsymbol *&sapply) { if (!arg->type) arg->type = taa->index; // key type - arg = arguments->tdata()[1]; + arg = (*arguments)[1]; } if (!arg->type) arg->type = taa->next; // value type @@ -1403,20 +1430,24 @@ int ForeachStatement::inferApplyArgTypes(Scope *sc, Dsymbol *&sapply) { if (!arg->type) { - /* Look for a head() or rear() overload + /* Look for a front() or back() overload */ Identifier *id = (op == TOKforeach) ? Id::Ffront : Id::Fback; - Dsymbol *s = search_function(ad, id); + Dsymbol *s = ad->search(0, id, 0); FuncDeclaration *fd = s ? s->isFuncDeclaration() : NULL; - if (!fd) - { if (s && s->isTemplateDeclaration()) - break; - break; + if (fd) + { + // Resolve inout qualifier of front type + arg->type = fd->type->nextOf(); + if (arg->type) + arg->type = arg->type->substWildTo(tab->mod); } - // Resolve inout qualifier of front type - arg->type = fd->type->nextOf(); - if (arg->type) - arg->type = arg->type->substWildTo(tab->mod); + else if (s && s->isTemplateDeclaration()) + ; + else if (s && s->isDeclaration()) + arg->type = ((Declaration *)s)->type; + else + break; } break; } @@ -1522,7 +1553,7 @@ static int inferApplyArgTypesY(TypeFunction *tf, Parameters *arguments, int flag for (size_t u = 0; u < nparams; u++) { - Parameter *arg = arguments->tdata()[u]; + Parameter *arg = (*arguments)[u]; Parameter *param = Parameter::getNth(tf->parameters, u); if (arg->type) { if (!arg->type->equals(param->type)) @@ -1560,7 +1591,7 @@ void inferApplyArgTypesZ(TemplateDeclaration *tstart, Parameters *arguments) } if (!td->parameters || td->parameters->dim != 1) continue; - TemplateParameter *tp = td->parameters->tdata()[0]; + TemplateParameter *tp = (*td->parameters)[0]; TemplateAliasParameter *tap = tp->isTemplateAliasParameter(); if (!tap || !tap->specType || tap->specType->ty != Tfunction) continue; diff --git a/dmd2/optimize.c b/dmd2/optimize.c index f007751c..16e30130 100644 --- a/dmd2/optimize.c +++ b/dmd2/optimize.c @@ -153,7 +153,6 @@ Expression *fromConstInitializer(int result, Expression *e1) if (e1->op == TOKvar) { VarExp *ve = (VarExp *)e1; VarDeclaration *v = ve->var->isVarDeclaration(); - int fwdref = (v && !v->originalType && v->scope); e = expandVar(result, v); if (e) { @@ -202,10 +201,10 @@ Expression *VarExp::optimize(int result) Expression *TupleExp::optimize(int result) { for (size_t i = 0; i < exps->dim; i++) - { Expression *e = exps->tdata()[i]; + { Expression *e = (*exps)[i]; e = e->optimize(WANTvalue | (result & WANTinterpret)); - exps->tdata()[i] = e; + (*exps)[i] = e; } return this; } @@ -215,10 +214,10 @@ Expression *ArrayLiteralExp::optimize(int result) if (elements) { for (size_t i = 0; i < elements->dim; i++) - { Expression *e = elements->tdata()[i]; + { Expression *e = (*elements)[i]; e = e->optimize(WANTvalue | (result & (WANTinterpret | WANTexpand))); - elements->tdata()[i] = e; + (*elements)[i] = e; } } return this; @@ -228,14 +227,14 @@ Expression *AssocArrayLiteralExp::optimize(int result) { assert(keys->dim == values->dim); for (size_t i = 0; i < keys->dim; i++) - { Expression *e = keys->tdata()[i]; + { Expression *e = (*keys)[i]; e = e->optimize(WANTvalue | (result & (WANTinterpret | WANTexpand))); - keys->tdata()[i] = e; + (*keys)[i] = e; - e = values->tdata()[i]; + e = (*values)[i]; e = e->optimize(WANTvalue | (result & (WANTinterpret | WANTexpand))); - values->tdata()[i] = e; + (*values)[i] = e; } return this; } @@ -245,11 +244,11 @@ Expression *StructLiteralExp::optimize(int result) if (elements) { for (size_t i = 0; i < elements->dim; i++) - { Expression *e = elements->tdata()[i]; + { Expression *e = (*elements)[i]; if (!e) continue; e = e->optimize(WANTvalue | (result & (WANTinterpret | WANTexpand))); - elements->tdata()[i] = e; + (*elements)[i] = e; } } return this; @@ -495,20 +494,20 @@ Expression *NewExp::optimize(int result) if (newargs) { for (size_t i = 0; i < newargs->dim; i++) - { Expression *e = newargs->tdata()[i]; + { Expression *e = (*newargs)[i]; e = e->optimize(WANTvalue); - newargs->tdata()[i] = e; + (*newargs)[i] = e; } } if (arguments) { for (size_t i = 0; i < arguments->dim; i++) - { Expression *e = arguments->tdata()[i]; + { Expression *e = (*arguments)[i]; e = e->optimize(WANTvalue); - arguments->tdata()[i] = e; + (*arguments)[i] = e; } } if (result & WANTinterpret) @@ -527,10 +526,10 @@ Expression *CallExp::optimize(int result) if (arguments) { for (size_t i = 0; i < arguments->dim; i++) - { Expression *e = arguments->tdata()[i]; + { Expression *e = (*arguments)[i]; e = e->optimize(WANTvalue); - arguments->tdata()[i] = e; + (*arguments)[i] = e; } } diff --git a/dmd2/parse.c b/dmd2/parse.c index 6119ec54..8ad48ce7 100644 --- a/dmd2/parse.c +++ b/dmd2/parse.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -12,6 +12,7 @@ #include #include +#include // strlen(),memcpy() #include "rmem.h" #include "lexer.h" @@ -454,7 +455,10 @@ Dsymbols *Parser::parseDeclDefs(int once) ((tk = peek(tk)), 1) && skipAttributes(tk, &tk) && (tk->value == TOKlparen || - tk->value == TOKlcurly) + tk->value == TOKlcurly || + tk->value == TOKin || + tk->value == TOKout || + tk->value == TOKbody) ) { a = parseDeclarations(storageClass, comment); @@ -512,7 +516,11 @@ Dsymbols *Parser::parseDeclDefs(int once) { nextToken(); if (token.value == TOKint32v && token.uns64value > 0) + { + if (token.uns64value & (token.uns64value - 1)) + error("align(%s) must be a power of 2", token.toChars()); n = (unsigned)token.uns64value; + } else { error("positive integer expected, not %s", token.toChars()); n = 1; @@ -535,7 +543,7 @@ Dsymbols *Parser::parseDeclDefs(int once) nextToken(); check(TOKlparen); if (token.value != TOKidentifier) - { error("pragma(identifier expected"); + { error("pragma(identifier) expected"); goto Lerror; } ident = token.ident; @@ -1370,7 +1378,8 @@ Parameters *Parser::parseParameters(int *pvarargs, TemplateParameters **tpl) default: Ldefault: { stc = storageClass & (STCin | STCout | STCref | STClazy); - if (stc & (stc - 1)) // if stc is not a power of 2 + if (stc & (stc - 1) && // if stc is not a power of 2 + !(stc == (STCin | STCref))) error("incompatible parameter storage classes"); if ((storageClass & (STCconst | STCout)) == (STCconst | STCout)) error("out cannot be const"); @@ -2860,7 +2869,10 @@ Dsymbols *Parser::parseDeclarations(StorageClass storage_class, unsigned char *c ((tk = peek(tk)), 1) && skipAttributes(tk, &tk) && (tk->value == TOKlparen || - tk->value == TOKlcurly) + tk->value == TOKlcurly || + tk->value == TOKin || + tk->value == TOKout || + tk->value == TOKbody) ) { ts = NULL; @@ -3347,7 +3359,15 @@ Initializer *Parser::parseInitializer() if (comma == 1) error("comma expected separating array initializers, not %s", token.toChars()); value = parseInitializer(); - ia->addInit(NULL, value); + if (token.value == TOKcolon) + { + nextToken(); + e = value->toExpression(); + value = parseInitializer(); + } + else + e = NULL; + ia->addInit(e, value); comma = 1; continue; @@ -3601,7 +3621,7 @@ Statement *Parser::parseStatement(int flags) as->reserve(a->dim); for (size_t i = 0; i < a->dim; i++) { - Dsymbol *d = a->tdata()[i]; + Dsymbol *d = (*a)[i]; s = new ExpStatement(loc, d); as->push(s); } @@ -3609,7 +3629,7 @@ Statement *Parser::parseStatement(int flags) } else if (a->dim == 1) { - Dsymbol *d = a->tdata()[0]; + Dsymbol *d = (*a)[0]; s = new ExpStatement(loc, d); } else @@ -3841,7 +3861,7 @@ Statement *Parser::parseStatement(int flags) Expression *aggr = parseExpression(); if (token.value == TOKslice && arguments->dim == 1) { - Parameter *a = arguments->tdata()[0]; + Parameter *a = (*arguments)[0]; delete arguments; nextToken(); Expression *upr = parseExpression(); @@ -4087,7 +4107,7 @@ Statement *Parser::parseStatement(int flags) // Keep cases in order by building the case statements backwards for (size_t i = cases.dim; i; i--) { - exp = cases.tdata()[i - 1]; + exp = cases[i - 1]; s = new CaseStatement(loc, exp, s); } } @@ -4242,7 +4262,7 @@ Statement *Parser::parseStatement(int flags) Loc loc = this->loc; nextToken(); - if (token.value == TOKlcurly) + if (token.value == TOKlcurly || token.value != TOKlparen) { t = NULL; id = NULL; @@ -5406,6 +5426,7 @@ Expression *Parser::parsePrimaryExp() token.value == TOKenum || token.value == TOKinterface || token.value == TOKargTypes || + token.value == TOKparameters || #if DMDV2 token.value == TOKconst && peek(&token)->value == TOKrparen || token.value == TOKinvariant && peek(&token)->value == TOKrparen || diff --git a/dmd2/readme.txt b/dmd2/readme.txt index e8109070..0d72c9be 100644 --- a/dmd2/readme.txt +++ b/dmd2/readme.txt @@ -12,7 +12,9 @@ of the D Programming Language defined in the documents at http://www.digitalmars.com/d/ These sources are free, they are redistributable and modifiable -under the terms of the GNU General Public License (attached as gpl.txt), +under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version (attached as gpl.txt), or the Artistic License (attached as artistic.txt). The optimizer and code generator sources are diff --git a/dmd2/root/aav.c b/dmd2/root/aav.c index ca685d42..7a515a13 100644 --- a/dmd2/root/aav.c +++ b/dmd2/root/aav.c @@ -1,3 +1,12 @@ + +// Copyright (c) 2010-2012 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + /** * Implementation of associative arrays. * diff --git a/dmd2/root/aav.h b/dmd2/root/aav.h index 266b5a83..201ca48f 100644 --- a/dmd2/root/aav.h +++ b/dmd2/root/aav.h @@ -1,4 +1,12 @@ +// Copyright (c) 2010-2012 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + typedef void* Value; typedef void* Key; diff --git a/dmd2/root/array.c b/dmd2/root/array.c index f3440445..3ef48322 100644 --- a/dmd2/root/array.c +++ b/dmd2/root/array.c @@ -40,7 +40,6 @@ #include "port.h" #include "root.h" -#include "dchar.h" #include "rmem.h" diff --git a/dmd2/root/async.c b/dmd2/root/async.c index 78f17c68..92767c8e 100644 --- a/dmd2/root/async.c +++ b/dmd2/root/async.c @@ -1,4 +1,12 @@ +// Copyright (c) 2009-2012 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + #define _MT 1 #include diff --git a/dmd2/root/dchar.c b/dmd2/root/dchar.c deleted file mode 100644 index 0b11a8a4..00000000 --- a/dmd2/root/dchar.c +++ /dev/null @@ -1,482 +0,0 @@ - -// Copyright (c) 1999-2006 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - - -#include -#include -#include -#include - -#include "dchar.h" -#include "rmem.h" - -#if M_UNICODE - -// Converts a char string to Unicode - -dchar *Dchar::dup(char *p) -{ - dchar *s; - size_t len; - - if (!p) - return NULL; - len = strlen(p); - s = (dchar *)mem.malloc((len + 1) * sizeof(dchar)); - for (unsigned i = 0; i < len; i++) - { - s[i] = (dchar)(p[i] & 0xFF); - } - s[len] = 0; - return s; -} - -dchar *Dchar::memchr(dchar *p, int c, int count) -{ - int u; - - for (u = 0; u < count; u++) - { - if (p[u] == c) - return p + u; - } - return NULL; -} - -#if _WIN32 && __DMC__ -__declspec(naked) -unsigned Dchar::calcHash(const dchar *str, unsigned len) -{ - __asm - { - mov ECX,4[ESP] - mov EDX,8[ESP] - xor EAX,EAX - test EDX,EDX - je L92 - -LC8: cmp EDX,1 - je L98 - cmp EDX,2 - je LAE - - add EAX,[ECX] -// imul EAX,EAX,025h - lea EAX,[EAX][EAX*8] - add ECX,4 - sub EDX,2 - jmp LC8 - -L98: mov DX,[ECX] - and EDX,0FFFFh - add EAX,EDX - ret - -LAE: add EAX,[ECX] -L92: ret - } -} -#else -hash_t Dchar::calcHash(const dchar *str, size_t len) -{ - unsigned hash = 0; - - for (;;) - { - switch (len) - { - case 0: - return hash; - - case 1: - hash += *(const uint16_t *)str; - return hash; - - case 2: - hash += *(const uint32_t *)str; - return hash; - - default: - hash += *(const uint32_t *)str; - hash *= 37; - str += 2; - len -= 2; - break; - } - } -} -#endif - -hash_t Dchar::icalcHash(const dchar *str, size_t len) -{ - hash_t hash = 0; - - for (;;) - { - switch (len) - { - case 0: - return hash; - - case 1: - hash += *(const uint16_t *)str | 0x20; - return hash; - - case 2: - hash += *(const uint32_t *)str | 0x200020; - return hash; - - default: - hash += *(const uint32_t *)str | 0x200020; - hash *= 37; - str += 2; - len -= 2; - break; - } - } -} - -#elif MCBS - -hash_t Dchar::calcHash(const dchar *str, size_t len) -{ - hash_t hash = 0; - - while (1) - { - switch (len) - { - case 0: - return hash; - - case 1: - hash *= 37; - hash += *(const uint8_t *)str; - return hash; - - case 2: - hash *= 37; - hash += *(const uint16_t *)str; - return hash; - - case 3: - hash *= 37; - hash += (*(const uint16_t *)str << 8) + - ((const uint8_t *)str)[2]; - return hash; - - default: - hash *= 37; - hash += *(const uint32_t *)str; - str += 4; - len -= 4; - break; - } - } -} - -#elif UTF8 - -// Specification is: http://anubis.dkuug.dk/JTC1/SC2/WG2/docs/n1335 - -char Dchar::mblen[256] = -{ - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1, -}; - -dchar *Dchar::dec(dchar *pstart, dchar *p) -{ - while ((p[-1] & 0xC0) == 0x80) - p--; - return p; -} - -int Dchar::get(dchar *p) -{ - unsigned c; - unsigned char *q = (unsigned char *)p; - - c = q[0]; - switch (mblen[c]) - { - case 2: - c = ((c - 0xC0) << 6) | - (q[1] - 0x80); - break; - - case 3: - c = ((c - 0xE0) << 12) | - ((q[1] - 0x80) << 6) | - (q[2] - 0x80); - break; - - case 4: - c = ((c - 0xF0) << 18) | - ((q[1] - 0x80) << 12) | - ((q[2] - 0x80) << 6) | - (q[3] - 0x80); - break; - - case 5: - c = ((c - 0xF8) << 24) | - ((q[1] - 0x80) << 18) | - ((q[2] - 0x80) << 12) | - ((q[3] - 0x80) << 6) | - (q[4] - 0x80); - break; - - case 6: - c = ((c - 0xFC) << 30) | - ((q[1] - 0x80) << 24) | - ((q[2] - 0x80) << 18) | - ((q[3] - 0x80) << 12) | - ((q[4] - 0x80) << 6) | - (q[5] - 0x80); - break; - } - return c; -} - -dchar *Dchar::put(dchar *p, unsigned c) -{ - if (c <= 0x7F) - { - *p++ = c; - } - else if (c <= 0x7FF) - { - p[0] = 0xC0 + (c >> 6); - p[1] = 0x80 + (c & 0x3F); - p += 2; - } - else if (c <= 0xFFFF) - { - p[0] = 0xE0 + (c >> 12); - p[1] = 0x80 + ((c >> 6) & 0x3F); - p[2] = 0x80 + (c & 0x3F); - p += 3; - } - else if (c <= 0x1FFFFF) - { - p[0] = 0xF0 + (c >> 18); - p[1] = 0x80 + ((c >> 12) & 0x3F); - p[2] = 0x80 + ((c >> 6) & 0x3F); - p[3] = 0x80 + (c & 0x3F); - p += 4; - } - else if (c <= 0x3FFFFFF) - { - p[0] = 0xF8 + (c >> 24); - p[1] = 0x80 + ((c >> 18) & 0x3F); - p[2] = 0x80 + ((c >> 12) & 0x3F); - p[3] = 0x80 + ((c >> 6) & 0x3F); - p[4] = 0x80 + (c & 0x3F); - p += 5; - } - else if (c <= 0x7FFFFFFF) - { - p[0] = 0xFC + (c >> 30); - p[1] = 0x80 + ((c >> 24) & 0x3F); - p[2] = 0x80 + ((c >> 18) & 0x3F); - p[3] = 0x80 + ((c >> 12) & 0x3F); - p[4] = 0x80 + ((c >> 6) & 0x3F); - p[5] = 0x80 + (c & 0x3F); - p += 6; - } - else - assert(0); // not a UCS-4 character - return p; -} - -hash_t Dchar::calcHash(const dchar *str, size_t len) -{ - hash_t hash = 0; - - while (1) - { - switch (len) - { - case 0: - return hash; - - case 1: - hash *= 37; - hash += *(const uint8_t *)str; - return hash; - - case 2: - hash *= 37; -#if LITTLE_ENDIAN - hash += *(const uint16_t *)str; -#else - hash += str[0] * 256 + str[1]; -#endif - return hash; - - case 3: - hash *= 37; -#if LITTLE_ENDIAN - hash += (*(const uint16_t *)str << 8) + - ((const uint8_t *)str)[2]; -#else - hash += (str[0] * 256 + str[1]) * 256 + str[2]; -#endif - return hash; - - default: - hash *= 37; -#if LITTLE_ENDIAN - hash += *(const uint32_t *)str; -#else - hash += ((str[0] * 256 + str[1]) * 256 + str[2]) * 256 + str[3]; -#endif - - str += 4; - len -= 4; - break; - } - } -} - -#else // ascii - -hash_t Dchar::calcHash(const dchar *str, size_t len) -{ - hash_t hash = 0; - - while (1) - { - switch (len) - { - case 0: - return hash; - - case 1: - hash *= 37; - hash += *(const uint8_t *)str; - return hash; - - case 2: - hash *= 37; -#if LITTLE_ENDIAN - hash += *(const uint16_t *)str; -#else - hash += str[0] * 256 + str[1]; -#endif - return hash; - - case 3: - hash *= 37; -#if LITTLE_ENDIAN - hash += (*(const uint16_t *)str << 8) + - ((const uint8_t *)str)[2]; -#else - hash += (str[0] * 256 + str[1]) * 256 + str[2]; -#endif - return hash; - - default: - hash *= 37; -#if LITTLE_ENDIAN - hash += *(const uint32_t *)str; -#else - hash += ((str[0] * 256 + str[1]) * 256 + str[2]) * 256 + str[3]; -#endif - str += 4; - len -= 4; - break; - } - } -} - -hash_t Dchar::icalcHash(const dchar *str, size_t len) -{ - hash_t hash = 0; - - while (1) - { - switch (len) - { - case 0: - return hash; - - case 1: - hash *= 37; - hash += *(const uint8_t *)str | 0x20; - return hash; - - case 2: - hash *= 37; - hash += *(const uint16_t *)str | 0x2020; - return hash; - - case 3: - hash *= 37; - hash += ((*(const uint16_t *)str << 8) + - ((const uint8_t *)str)[2]) | 0x202020; - return hash; - - default: - hash *= 37; - hash += *(const uint32_t *)str | 0x20202020; - str += 4; - len -= 4; - break; - } - } -} - -#endif - -#if 0 -#include - -void main() -{ - // Print out values to hardcode into Dchar::mblen[] - int c; - int s; - - for (c = 0; c < 256; c++) - { - s = 1; - if (c >= 0xC0 && c <= 0xDF) - s = 2; - if (c >= 0xE0 && c <= 0xEF) - s = 3; - if (c >= 0xF0 && c <= 0xF7) - s = 4; - if (c >= 0xF8 && c <= 0xFB) - s = 5; - if (c >= 0xFC && c <= 0xFD) - s = 6; - - printf("%d", s); - if ((c & 15) == 15) - printf(",\n"); - else - printf(","); - } -} -#endif diff --git a/dmd2/root/dchar.h b/dmd2/root/dchar.h deleted file mode 100644 index 6ac7994c..00000000 --- a/dmd2/root/dchar.h +++ /dev/null @@ -1,194 +0,0 @@ - -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - - -#ifndef DCHAR_H -#define DCHAR_H - -#if __GNUC__ && !_WIN32 -#include "gnuc.h" -#endif - -#if _MSC_VER - // Disable useless warnings about unreferenced functions - #pragma warning (disable : 4514) -#endif - -//#include "root.h" -typedef size_t hash_t; - -#undef TEXT - -// NOTE: All functions accepting pointer arguments must not be NULL - -#if M_UNICODE - -#include -#include - -typedef wchar_t dchar; -#define TEXT(x) L##x - -#define Dchar_mbmax 1 - -struct Dchar -{ - static dchar *inc(dchar *p) { return p + 1; } - static dchar *dec(dchar *pstart, dchar *p) { (void)pstart; return p - 1; } - static int len(const dchar *p) { return wcslen(p); } - static dchar get(dchar *p) { return *p; } - static dchar getprev(dchar *pstart, dchar *p) { (void)pstart; return p[-1]; } - static dchar *put(dchar *p, dchar c) { *p = c; return p + 1; } - static int cmp(dchar *s1, dchar *s2) - { -#if __DMC__ - if (!*s1 && !*s2) // wcscmp is broken - return 0; -#endif - return wcscmp(s1, s2); -#if 0 - return (*s1 == *s2) - ? wcscmp(s1, s2) - : ((int)*s1 - (int)*s2); -#endif - } - static int memcmp(const dchar *s1, const dchar *s2, int nchars) { return ::memcmp(s1, s2, nchars * sizeof(dchar)); } - static int isDigit(dchar c) { return '0' <= c && c <= '9'; } - static int isAlpha(dchar c) { return iswalpha(c); } - static int isUpper(dchar c) { return iswupper(c); } - static int isLower(dchar c) { return iswlower(c); } - static int isLocaleUpper(dchar c) { return isUpper(c); } - static int isLocaleLower(dchar c) { return isLower(c); } - static int toLower(dchar c) { return isUpper(c) ? towlower(c) : c; } - static int toLower(dchar *p) { return toLower(*p); } - static int toUpper(dchar c) { return isLower(c) ? towupper(c) : c; } - static dchar *dup(dchar *p) { return ::_wcsdup(p); } // BUG: out of memory? - static dchar *dup(char *p); - static dchar *chr(dchar *p, unsigned c) { return wcschr(p, (dchar)c); } - static dchar *rchr(dchar *p, unsigned c) { return wcsrchr(p, (dchar)c); } - static dchar *memchr(dchar *p, int c, int count); - static dchar *cpy(dchar *s1, dchar *s2) { return wcscpy(s1, s2); } - static dchar *str(dchar *s1, dchar *s2) { return wcsstr(s1, s2); } - static hash_t calcHash(const dchar *str, size_t len); - - // Case insensitive versions - static int icmp(dchar *s1, dchar *s2) { return wcsicmp(s1, s2); } - static int memicmp(const dchar *s1, const dchar *s2, int nchars) { return ::wcsnicmp(s1, s2, nchars); } - static hash_t icalcHash(const dchar *str, size_t len); -}; - -#elif MCBS - -#include -#include - -typedef char dchar; -#define TEXT(x) x - -#define Dchar_mbmax MB_LEN_MAX - -#elif UTF8 - -typedef char dchar; -#define TEXT(x) x - -#define Dchar_mbmax 6 - -struct Dchar -{ - static char mblen[256]; - - static dchar *inc(dchar *p) { return p + mblen[*p & 0xFF]; } - static dchar *dec(dchar *pstart, dchar *p); - static int len(const dchar *p) { return strlen(p); } - static int get(dchar *p); - static int getprev(dchar *pstart, dchar *p) - { return *dec(pstart, p) & 0xFF; } - static dchar *put(dchar *p, unsigned c); - static int cmp(dchar *s1, dchar *s2) { return strcmp(s1, s2); } - static int memcmp(const dchar *s1, const dchar *s2, int nchars) { return ::memcmp(s1, s2, nchars); } - static int isDigit(dchar c) { return '0' <= c && c <= '9'; } - static int isAlpha(dchar c) { return c <= 0x7F ? isalpha(c) : 0; } - static int isUpper(dchar c) { return c <= 0x7F ? isupper(c) : 0; } - static int isLower(dchar c) { return c <= 0x7F ? islower(c) : 0; } - static int isLocaleUpper(dchar c) { return isUpper(c); } - static int isLocaleLower(dchar c) { return isLower(c); } - static int toLower(dchar c) { return isUpper(c) ? tolower(c) : c; } - static int toLower(dchar *p) { return toLower(*p); } - static int toUpper(dchar c) { return isLower(c) ? toupper(c) : c; } - static dchar *dup(dchar *p) { return ::strdup(p); } // BUG: out of memory? - static dchar *chr(dchar *p, int c) { return strchr(p, c); } - static dchar *rchr(dchar *p, int c) { return strrchr(p, c); } - static dchar *memchr(dchar *p, int c, int count) - { return (dchar *)::memchr(p, c, count); } - static dchar *cpy(dchar *s1, dchar *s2) { return strcpy(s1, s2); } - static dchar *str(dchar *s1, dchar *s2) { return strstr(s1, s2); } - static hash_t calcHash(const dchar *str, size_t len); - - // Case insensitive versions - static int icmp(dchar *s1, dchar *s2) { return _mbsicmp(s1, s2); } - static int memicmp(const dchar *s1, const dchar *s2, int nchars) { return ::_mbsnicmp(s1, s2, nchars); } -}; - -#else - -#include - -#ifndef GCC_SAFE_DMD -#include -#endif - -typedef char dchar; -#define TEXT(x) x - -#define Dchar_mbmax 1 - -struct Dchar -{ - static dchar *inc(dchar *p) { return p + 1; } - static dchar *dec(dchar *pstart, dchar *p) { (void)pstart; return p - 1; } - static int len(const dchar *p) { return strlen(p); } - static int get(dchar *p) { return *p & 0xFF; } - static int getprev(dchar *pstart, dchar *p) { (void)pstart; return p[-1] & 0xFF; } - static dchar *put(dchar *p, unsigned c) { *p = c; return p + 1; } - static int cmp(dchar *s1, dchar *s2) { return strcmp(s1, s2); } - static int memcmp(const dchar *s1, const dchar *s2, int nchars) { return ::memcmp(s1, s2, nchars); } - static int isDigit(dchar c) { return '0' <= c && c <= '9'; } -#ifndef GCC_SAFE_DMD - static int isAlpha(dchar c) { return isalpha((unsigned char)c); } - static int isUpper(dchar c) { return isupper((unsigned char)c); } - static int isLower(dchar c) { return islower((unsigned char)c); } - static int isLocaleUpper(dchar c) { return isupper((unsigned char)c); } - static int isLocaleLower(dchar c) { return islower((unsigned char)c); } - static int toLower(dchar c) { return isupper((unsigned char)c) ? tolower(c) : c; } - static int toLower(dchar *p) { return toLower(*p); } - static int toUpper(dchar c) { return islower((unsigned char)c) ? toupper(c) : c; } - static dchar *dup(dchar *p) { return ::strdup(p); } // BUG: out of memory? -#endif - static dchar *chr(dchar *p, int c) { return strchr(p, c); } - static dchar *rchr(dchar *p, int c) { return strrchr(p, c); } - static dchar *memchr(dchar *p, int c, int count) - { return (dchar *)::memchr(p, c, count); } - static dchar *cpy(dchar *s1, dchar *s2) { return strcpy(s1, s2); } - static dchar *str(dchar *s1, dchar *s2) { return strstr(s1, s2); } - static hash_t calcHash(const dchar *str, size_t len); - - // Case insensitive versions -#ifdef __GNUC__ - static int icmp(dchar *s1, dchar *s2) { return strcasecmp(s1, s2); } -#else - static int icmp(dchar *s1, dchar *s2) { return stricmp(s1, s2); } -#endif - static int memicmp(const dchar *s1, const dchar *s2, int nchars) { return ::memicmp(s1, s2, nchars); } - static hash_t icalcHash(const dchar *str, size_t len); -}; - -#endif -#endif - diff --git a/dmd2/root/gnuc.c b/dmd2/root/gnuc.c index 8f33d839..90358da1 100644 --- a/dmd2/root/gnuc.c +++ b/dmd2/root/gnuc.c @@ -1,4 +1,12 @@ +// Copyright (c) 2009-2012 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + // Put functions in here missing from gnu C #include "gnuc.h" diff --git a/dmd2/root/gnuc.h b/dmd2/root/gnuc.h index 00c9851d..6b25fbf2 100644 --- a/dmd2/root/gnuc.h +++ b/dmd2/root/gnuc.h @@ -1,4 +1,12 @@ +// Copyright (c) 2009-2012 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + #ifndef _GNUC_H #define _GNUC_H 1 diff --git a/dmd2/root/lstring.c b/dmd2/root/lstring.c deleted file mode 100644 index a4e41ed5..00000000 --- a/dmd2/root/lstring.c +++ /dev/null @@ -1,63 +0,0 @@ -// lstring.c - -// Copyright (c) 1999-2002 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include - -#include "dchar.h" -#include "rmem.h" -#include "lstring.h" - -#ifdef _MSC_VER // prevent compiler internal crash -Lstring Lstring::zero; -#else -Lstring Lstring::zero = LSTRING_EMPTY(); -#endif - -Lstring *Lstring::ctor(const dchar *p, unsigned length) -{ - Lstring *s; - - s = alloc(length); - memcpy(s->string, p, length * sizeof(dchar)); - return s; -} - -Lstring *Lstring::alloc(unsigned length) -{ - Lstring *s; - - s = (Lstring *)mem.malloc(size(length)); - s->length = length; - s->string[length] = 0; - return s; -} - -Lstring *Lstring::append(const Lstring *s) -{ - Lstring *t; - - if (!s->length) - return this; - t = alloc(length + s->length); - memcpy(t->string, string, length * sizeof(dchar)); - memcpy(t->string + length, s->string, s->length * sizeof(dchar)); - return t; -} - -Lstring *Lstring::substring(int start, int end) -{ - Lstring *t; - - if (start == end) - return &zero; - t = alloc(end - start); - memcpy(t->string, string + start, (end - start) * sizeof(dchar)); - return t; -} diff --git a/dmd2/root/lstring.h b/dmd2/root/lstring.h deleted file mode 100644 index 0c545790..00000000 --- a/dmd2/root/lstring.h +++ /dev/null @@ -1,74 +0,0 @@ - -// lstring.h -// length-prefixed strings - -// Copyright (c) 1999-2002 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef LSTRING_H -#define LSTRING_H 1 - -#include "dchar.h" - -struct Lstring -{ - unsigned length; - -#ifndef IN_GCC - // Disable warning about nonstandard extension - #pragma warning (disable : 4200) -#endif - dchar string[]; - - static Lstring zero; // 0 length string - - // No constructors because we want to be able to statically - // initialize Lstring's, and Lstrings are of variable size. - - #if M_UNICODE - #define LSTRING(p,length) { length, L##p } - #else - #define LSTRING(p,length) { length, p } - #endif - -#if __GNUC__ - #define LSTRING_EMPTY() { 0 } -#else - #define LSTRING_EMPTY() LSTRING("", 0) -#endif - - static Lstring *ctor(const dchar *p) { return ctor(p, Dchar::len(p)); } - static Lstring *ctor(const dchar *p, unsigned length); - static unsigned size(unsigned length) { return sizeof(Lstring) + (length + 1) * sizeof(dchar); } - static Lstring *alloc(unsigned length); - Lstring *clone(); - - unsigned len() { return length; } - - dchar *toDchars() { return string; } - - hash_t hash() { return Dchar::calcHash(string, length); } - hash_t ihash() { return Dchar::icalcHash(string, length); } - - static int cmp(const Lstring *s1, const Lstring *s2) - { - int c = s2->length - s1->length; - return c ? c : Dchar::memcmp(s1->string, s2->string, s1->length); - } - - static int icmp(const Lstring *s1, const Lstring *s2) - { - int c = s2->length - s1->length; - return c ? c : Dchar::memicmp(s1->string, s2->string, s1->length); - } - - Lstring *append(const Lstring *s); - Lstring *substring(int start, int end); -}; - -#endif diff --git a/dmd2/root/response.c b/dmd2/root/response.c index 31e35686..45f08662 100644 --- a/dmd2/root/response.c +++ b/dmd2/root/response.c @@ -109,6 +109,7 @@ int response_expand(int *pargc, char ***pargv) char *buffer; char *bufend; char *p; + int comment = 0; cp++; p = getenv(cp); @@ -171,15 +172,31 @@ int response_expand(int *pargc, char ***pargv) goto L2; case 0xD: + case '\n': + if (comment) + { + comment = 0; + } case 0: case ' ': case '\t': - case '\n': continue; // scan to start of argument + case '#': + comment = 1; + continue; + case '@': + if (comment) + { + continue; + } recurse = 1; default: /* start of new argument */ + if (comment) + { + continue; + } if (addargp(&n,p)) goto noexpand; instring = 0; diff --git a/dmd2/root/rmem.c b/dmd2/root/rmem.c index 2504ab93..fd202732 100644 --- a/dmd2/root/rmem.c +++ b/dmd2/root/rmem.c @@ -1,6 +1,11 @@ -/* Copyright (c) 2000 Digital Mars */ -/* All Rights Reserved */ +// Copyright (c) 2000-2012 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. #include #include diff --git a/dmd2/root/rmem.h b/dmd2/root/rmem.h index d22145a9..7307d97b 100644 --- a/dmd2/root/rmem.h +++ b/dmd2/root/rmem.h @@ -1,5 +1,11 @@ -// Copyright (C) 2000-2011 by Digital Mars + +// Copyright (c) 2000-2012 by Digital Mars // All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. #ifndef ROOT_MEM_H #define ROOT_MEM_H diff --git a/dmd2/root/root.c b/dmd2/root/root.c index 773a542a..d4697100 100644 --- a/dmd2/root/root.c +++ b/dmd2/root/root.c @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2011 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -18,6 +18,7 @@ #include #include #include +#include #if (defined (__SVR4) && defined (__sun)) #include @@ -49,7 +50,6 @@ #include "port.h" #include "root.h" -#include "dchar.h" #include "rmem.h" #if 0 //__SC__ //def DEBUG @@ -142,22 +142,6 @@ void error(const char *format, ...) exit(EXIT_FAILURE); } -#if M_UNICODE -void error(const dchar *format, ...) -{ - va_list ap; - - va_start(ap, format); - printf("Error: "); - vwprintf(format, ap); - va_end( ap ); - printf("\n"); - fflush(stdout); - - exit(EXIT_FAILURE); -} -#endif - void error_mem() { error("out of memory"); @@ -206,15 +190,6 @@ char *Object::toChars() return (char *)"Object"; } -dchar *Object::toDchars() -{ -#if M_UNICODE - return L"Object"; -#else - return toChars(); -#endif -} - int Object::dyncast() { return 0; @@ -1609,30 +1584,6 @@ void OutBuffer::writestring(const char *string) write(string,strlen(string)); } -void OutBuffer::writedstring(const char *string) -{ -#if M_UNICODE - for (; *string; string++) - { - writedchar(*string); - } -#else - write(string,strlen(string)); -#endif -} - -void OutBuffer::writedstring(const wchar_t *string) -{ -#if M_UNICODE - write(string,wcslen(string) * sizeof(wchar_t)); -#else - for (; *string; string++) - { - writedchar(*string); - } -#endif -} - void OutBuffer::prependstring(const char *string) { unsigned len; @@ -1646,18 +1597,10 @@ void OutBuffer::prependstring(const char *string) void OutBuffer::writenl() { #if _WIN32 -#if M_UNICODE - write4(0x000A000D); // newline is CR,LF on Microsoft OS's -#else writeword(0x0A0D); // newline is CR,LF on Microsoft OS's -#endif -#else -#if M_UNICODE - writeword('\n'); #else writeByte('\n'); #endif -#endif } void OutBuffer::writeByte(unsigned b) @@ -1719,13 +1662,6 @@ void OutBuffer::writeUTF8(unsigned b) assert(0); } -void OutBuffer::writedchar(unsigned b) -{ - reserve(Dchar_mbmax * sizeof(dchar)); - offset = (unsigned char *)Dchar::put((dchar *)(this->data + offset), (dchar)b) - - this->data; -} - void OutBuffer::prependbyte(unsigned b) { reserve(1); @@ -1873,46 +1809,6 @@ void OutBuffer::vprintf(const char *format, va_list args) write(p,count); } -#if M_UNICODE -void OutBuffer::vprintf(const wchar_t *format, va_list args) -{ - dchar buffer[128]; - dchar *p; - unsigned psize; - int count; - - WORKAROUND_C99_SPECIFIERS_BUG(wstring, fmt, format); - - p = buffer; - psize = sizeof(buffer) / sizeof(buffer[0]); - for (;;) - { -#if _WIN32 - count = _vsnwprintf(p,psize,format,args); - if (count != -1) - break; - psize *= 2; -#elif POSIX - va_list va; - va_copy(va, args); - count = vsnwprintf(p,psize,format,va); - va_end(va); - - if (count == -1) - psize *= 2; - else if (count >= psize) - psize = count + 1; - else - break; -#else - assert(0); -#endif - p = (dchar *) alloca(psize * 2); // buffer too small, try again with larger size - } - write(p,count * 2); -} -#endif - void OutBuffer::printf(const char *format, ...) { va_list ap; @@ -1921,16 +1817,6 @@ void OutBuffer::printf(const char *format, ...) va_end(ap); } -#if M_UNICODE -void OutBuffer::printf(const wchar_t *format, ...) -{ - va_list ap; - va_start(ap, format); - vprintf(format,ap); - va_end(ap); -} -#endif - void OutBuffer::bracket(char left, char right) { reserve(2); diff --git a/dmd2/root/root.h b/dmd2/root/root.h index 830ea43b..842222e3 100644 --- a/dmd2/root/root.h +++ b/dmd2/root/root.h @@ -1,5 +1,4 @@ - // Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright @@ -24,7 +23,6 @@ typedef size_t hash_t; #include "longdouble.h" -#include "dchar.h" char *wchar2ascii(wchar_t *); int wcharIsAscii(wchar_t *); @@ -92,7 +90,6 @@ struct Object virtual void print(); virtual char *toChars(); - virtual dchar *toDchars(); virtual void toBuffer(OutBuffer *buf); /** @@ -282,14 +279,11 @@ struct OutBuffer : Object void write(const void *data, unsigned nbytes); void writebstring(unsigned char *string); void writestring(const char *string); - void writedstring(const char *string); - void writedstring(const wchar_t *string); void prependstring(const char *string); void writenl(); // write newline void writeByte(unsigned b); void writebyte(unsigned b) { writeByte(b); } void writeUTF8(unsigned b); - void writedchar(unsigned b); void prependbyte(unsigned b); void writeword(unsigned w); void writeUTF16(unsigned w); @@ -300,10 +294,6 @@ struct OutBuffer : Object void align(unsigned size); void vprintf(const char *format, va_list args); void printf(const char *format, ...); -#if M_UNICODE - void vprintf(const unsigned short *format, va_list args); - void printf(const unsigned short *format, ...); -#endif void bracket(char left, char right); unsigned bracket(unsigned i, const char *left, unsigned j, const char *right); void spread(unsigned offset, unsigned nbytes); diff --git a/dmd2/root/speller.c b/dmd2/root/speller.c index 373baf6d..207b49c0 100644 --- a/dmd2/root/speller.c +++ b/dmd2/root/speller.c @@ -1,4 +1,12 @@ +// Copyright (c) 2010-2012 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + #include #include #include diff --git a/dmd2/root/speller.h b/dmd2/root/speller.h index bfffb739..5f4e28f4 100644 --- a/dmd2/root/speller.h +++ b/dmd2/root/speller.h @@ -1,4 +1,12 @@ +// Copyright (c) 2010-2012 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + typedef void *(fp_speller_t)(void *, const char *); extern const char idchars[]; diff --git a/dmd2/root/stringtable.c b/dmd2/root/stringtable.c index f1c0044a..58dcd0b6 100644 --- a/dmd2/root/stringtable.c +++ b/dmd2/root/stringtable.c @@ -9,15 +9,70 @@ #include -#include +#include // uint{8|16|32}_t +#include // memcpy() #include #include "root.h" -#include "rmem.h" -#include "dchar.h" -#include "lstring.h" +#include "rmem.h" // mem #include "stringtable.h" +hash_t calcHash(const char *str, size_t len) +{ + hash_t hash = 0; + + while (1) + { + switch (len) + { + case 0: + return hash; + + case 1: + hash *= 37; + hash += *(const uint8_t *)str; + return hash; + + case 2: + hash *= 37; +#if LITTLE_ENDIAN + hash += *(const uint16_t *)str; +#else + hash += str[0] * 256 + str[1]; +#endif + return hash; + + case 3: + hash *= 37; +#if LITTLE_ENDIAN + hash += (*(const uint16_t *)str << 8) + + ((const uint8_t *)str)[2]; +#else + hash += (str[0] * 256 + str[1]) * 256 + str[2]; +#endif + return hash; + + default: + hash *= 37; +#if LITTLE_ENDIAN + hash += *(const uint32_t *)str; +#else + hash += ((str[0] * 256 + str[1]) * 256 + str[2]) * 256 + str[3]; +#endif + str += 4; + len -= 4; + break; + } + } +} + +void StringValue::ctor(const char *p, unsigned length) +{ + this->length = length; + this->lstring[length] = 0; + memcpy(this->lstring, p, length * sizeof(char)); +} + void StringTable::init(unsigned size) { table = (void **)mem.calloc(size, sizeof(void *)); @@ -46,21 +101,20 @@ struct StringEntry StringValue value; - static StringEntry *alloc(const dchar *s, unsigned len); + static StringEntry *alloc(const char *s, unsigned len); }; -StringEntry *StringEntry::alloc(const dchar *s, unsigned len) +StringEntry *StringEntry::alloc(const char *s, unsigned len) { StringEntry *se; - se = (StringEntry *) mem.calloc(1,sizeof(StringEntry) - sizeof(Lstring) + Lstring::size(len)); - se->value.lstring.length = len; - se->hash = Dchar::calcHash(s,len); - memcpy(se->value.lstring.string, s, len * sizeof(dchar)); + se = (StringEntry *) mem.calloc(1,sizeof(StringEntry) + len + 1); + se->value.ctor(s, len); + se->hash = calcHash(s,len); return se; } -void **StringTable::search(const dchar *s, unsigned len) +void **StringTable::search(const char *s, unsigned len) { hash_t hash; unsigned u; @@ -68,7 +122,7 @@ void **StringTable::search(const dchar *s, unsigned len) StringEntry **se; //printf("StringTable::search(%p,%d)\n",s,len); - hash = Dchar::calcHash(s,len); + hash = calcHash(s,len); u = hash % tabledim; se = (StringEntry **)&table[u]; //printf("\thash = %d, u = %d\n",hash,u); @@ -77,10 +131,10 @@ void **StringTable::search(const dchar *s, unsigned len) cmp = (*se)->hash - hash; if (cmp == 0) { - cmp = (*se)->value.lstring.len() - len; + cmp = (*se)->value.len() - len; if (cmp == 0) { - cmp = Dchar::memcmp(s,(*se)->value.lstring.toDchars(),len); + cmp = ::memcmp(s,(*se)->value.toDchars(),len); if (cmp == 0) break; } @@ -94,7 +148,7 @@ void **StringTable::search(const dchar *s, unsigned len) return (void **)se; } -StringValue *StringTable::lookup(const dchar *s, unsigned len) +StringValue *StringTable::lookup(const char *s, unsigned len) { StringEntry *se; se = *(StringEntry **)search(s,len); @@ -104,7 +158,7 @@ StringValue *StringTable::lookup(const dchar *s, unsigned len) return NULL; } -StringValue *StringTable::update(const dchar *s, unsigned len) +StringValue *StringTable::update(const char *s, unsigned len) { StringEntry **pse; StringEntry *se; @@ -118,7 +172,7 @@ StringValue *StringTable::update(const dchar *s, unsigned len) return &se->value; } -StringValue *StringTable::insert(const dchar *s, unsigned len) +StringValue *StringTable::insert(const char *s, unsigned len) { StringEntry **pse; StringEntry *se; @@ -133,7 +187,3 @@ StringValue *StringTable::insert(const dchar *s, unsigned len) } return &se->value; } - - - - diff --git a/dmd2/root/stringtable.h b/dmd2/root/stringtable.h index ce714587..170894e6 100644 --- a/dmd2/root/stringtable.h +++ b/dmd2/root/stringtable.h @@ -1,3 +1,4 @@ + // Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright @@ -15,34 +16,56 @@ #endif #include "root.h" -#include "dchar.h" -#include "lstring.h" +struct StringEntry; + +// StringValue is a variable-length structure as indicated by the last array +// member with unspecified size. It has neither proper c'tors nor a factory +// method because the only thing which should be creating these is StringTable. struct StringValue { union - { int intvalue; + { void *ptrvalue; - dchar *string; + char *string; }; - Lstring lstring; +private: + unsigned length; + +#ifndef IN_GCC + // Disable warning about nonstandard extension + #pragma warning (disable : 4200) +#endif + char lstring[]; + +public: + unsigned len() const { return length; } + const char *toDchars() const { return lstring; } + +private: + friend struct StringEntry; + StringValue(); // not constructible + // This is more like a placement new c'tor + void ctor(const char *p, unsigned length); }; struct StringTable { +private: void **table; unsigned count; unsigned tabledim; +public: void init(unsigned size = 37); ~StringTable(); - StringValue *lookup(const dchar *s, unsigned len); - StringValue *insert(const dchar *s, unsigned len); - StringValue *update(const dchar *s, unsigned len); + StringValue *lookup(const char *s, unsigned len); + StringValue *insert(const char *s, unsigned len); + StringValue *update(const char *s, unsigned len); private: - void **search(const dchar *s, unsigned len); + void **search(const char *s, unsigned len); }; #endif diff --git a/dmd2/scope.c b/dmd2/scope.c index 010cdb1a..28f6b965 100644 --- a/dmd2/scope.c +++ b/dmd2/scope.c @@ -9,6 +9,7 @@ #include #include +#include // strlen() #include "root.h" #include "speller.h" diff --git a/dmd2/scope.h b/dmd2/scope.h index 4fee6539..2e54ab7b 100644 --- a/dmd2/scope.h +++ b/dmd2/scope.h @@ -87,7 +87,7 @@ struct Scope #define CSXreturn 0x20 // seen a return statement #define CSXany_ctor 0x40 // either this() or super() was called - unsigned structalign; // alignment for struct members + structalign_t structalign; // alignment for struct members enum LINK linkage; // linkage for external functions enum PROT protection; // protection for class members @@ -102,7 +102,7 @@ struct Scope #define SCOPEstaticassert 8 // inside static assert #define SCOPEdebug 0x10 // inside debug conditional -#if IN_GCC +#ifdef IN_GCC Expressions *attributes; // GCC decl/type attributes #endif diff --git a/dmd2/statement.c b/dmd2/statement.c index 66a32704..89d6194e 100644 --- a/dmd2/statement.c +++ b/dmd2/statement.c @@ -28,6 +28,7 @@ #include "parse.h" #include "template.h" #include "attrib.h" +#include "import.h" #if IN_LLVM #if defined(_MSC_VER) @@ -426,7 +427,7 @@ Statements *CompileStatement::flatten(Scope *sc) //printf("CompileStatement::flatten() %s\n", exp->toChars()); exp = exp->semantic(sc); exp = resolveProperties(sc, exp); - exp = exp->optimize(WANTvalue | WANTinterpret); + exp = exp->ctfeInterpret(); if (exp->op == TOKerror) return NULL; StringExp *se = exp->toString(); @@ -1585,6 +1586,10 @@ Statement *ForeachStatement::semantic(Scope *sc) return s; } + Type *argtype = (*arguments)[dim-1]->type; + if (argtype) + argtype = argtype->semantic(loc, sc); + TypeTuple *tuple = (TypeTuple *)tab; Statements *statements = new Statements(); //printf("aggr: op = %d, %s\n", aggr->op, aggr->toChars()); @@ -1599,9 +1604,8 @@ Statement *ForeachStatement::semantic(Scope *sc) ((DotVarExp *)(*te->exps)[0])->e1->isTemp()) { CommaExp *ce = (CommaExp *)((DotVarExp *)(*te->exps)[0])->e1; - - prelude = ce->e1; - ((DotVarExp *)(*te->exps)[0])->e1 = ce->e2; + prelude = ce->e1; + ((DotVarExp *)(*te->exps)[0])->e1 = ce->e2; } } else if (aggr->op == TOKtype) // type tuple @@ -1612,8 +1616,8 @@ Statement *ForeachStatement::semantic(Scope *sc) assert(0); for (size_t j = 0; j < n; j++) { size_t k = (op == TOKforeach) ? j : n - 1 - j; - Expression *e; - Type *t; + Expression *e = NULL; + Type *t = NULL; if (te) e = (*te->exps)[k]; else @@ -1664,14 +1668,20 @@ Statement *ForeachStatement::semantic(Scope *sc) var = new AliasDeclaration(loc, arg->ident, s); if (arg->storageClass & STCref) error("symbol %s cannot be ref", s->toChars()); + if (argtype && argtype->ty != Terror) + error("cannot specify element type for symbol %s", s->toChars()); } else if (e->op == TOKtype) { var = new AliasDeclaration(loc, arg->ident, e->type); + if (argtype && argtype->ty != Terror) + error("cannot specify element type for type %s", e->type->toChars()); } else { arg->type = e->type; + if (argtype && argtype->ty != Terror) + arg->type = argtype; Initializer *ie = new ExpInitializer(0, e); VarDeclaration *v = new VarDeclaration(loc, arg->type, arg->ident, ie); if (arg->storageClass & STCref) @@ -1688,6 +1698,8 @@ Statement *ForeachStatement::semantic(Scope *sc) else { var = new AliasDeclaration(loc, arg->ident, t); + if (argtype && argtype->ty != Terror) + error("cannot specify element type for symbol %s", s->toChars()); } DeclarationExp *de = new DeclarationExp(loc, var); st->push(new ExpStatement(loc, de)); @@ -1757,23 +1769,47 @@ Lagain: Type *argtype = arg->type->semantic(loc, sc); VarDeclaration *var; - var = new VarDeclaration(loc, argtype, arg->ident, NULL); - var->storage_class |= STCforeach; - var->storage_class |= arg->storageClass & (STCin | STCout | STCref | STC_TYPECTOR); - if (var->storage_class & (STCref | STCout)) - var->storage_class |= STCnodtor; if (dim == 2 && i == 0) - { key = var; - //var->storage_class |= STCfinal; + { +#if (BUG6652 == 1 || BUG6652 == 2) + var = new VarDeclaration(loc, arg->type, Lexer::uniqueId("__key"), NULL); + var->storage_class |= arg->storageClass & (STCin | STCout | STC_TYPECTOR); +#else + if (arg->storageClass & STCref) + var = new VarDeclaration(loc, argtype, arg->ident, NULL); + else + var = new VarDeclaration(loc, arg->type, Lexer::uniqueId("__key"), NULL); + var->storage_class |= arg->storageClass & (STCin | STCout | STC_TYPECTOR); +#endif + var->storage_class |= STCforeach; + if (var->storage_class & (STCref | STCout)) + var->storage_class |= STCnodtor; + + key = var; } else { + var = new VarDeclaration(loc, argtype, arg->ident, NULL); + var->storage_class |= STCforeach; + var->storage_class |= arg->storageClass & (STCin | STCout | STCref | STC_TYPECTOR); + if (var->storage_class & (STCref | STCout)) + var->storage_class |= STCnodtor; + value = var; - /* Reference to immutable data should be marked as const - */ - if (var->storage_class & STCref && !tn->isMutable()) + if (var->storage_class & STCref) { - var->storage_class |= STCconst; + /* Reference to immutable data should be marked as const + */ + if (!tn->isMutable()) + var->storage_class |= STCconst; + + Type *t = tab->nextOf(); + if (!t->invariantOf()->equals(argtype->invariantOf()) || + !MODimplicitConv(t->mod, argtype->mod)) + { + error("argument type mismatch, %s to ref %s", + t->toChars(), argtype->toChars()); + } } } #if 0 @@ -1831,6 +1867,30 @@ Lagain: value->init = new ExpInitializer(loc, new IndexExp(loc, new VarExp(loc, tmp), new VarExp(loc, key))); Statement *ds = new ExpStatement(loc, value); + if (dim == 2) + { Parameter *arg = (*arguments)[0]; +#if (BUG6652 == 1 || BUG6652 == 2) + if ((*arguments)[0]->storageClass & STCref) + { + AliasDeclaration *v = new AliasDeclaration(loc, arg->ident, key); + body = new CompoundStatement(loc, new ExpStatement(loc, v), body); + } + else + { + ExpInitializer *ie = new ExpInitializer(loc, new IdentifierExp(loc, key->ident)); + VarDeclaration *v = new VarDeclaration(loc, NULL, arg->ident, ie); + v->storage_class |= STCforeach | STCref | STCbug6652; + body = new CompoundStatement(loc, new ExpStatement(loc, v), body); + } +#else + if (!(arg->storageClass & STCref)) + { + ExpInitializer *ie = new ExpInitializer(loc, new IdentifierExp(loc, key->ident)); + VarDeclaration *v = new VarDeclaration(loc, NULL, arg->ident, ie); + body = new CompoundStatement(loc, new ExpStatement(loc, v), body); + } +#endif + } body = new CompoundStatement(loc, ds, body); s = new ForStatement(loc, forinit, cond, increment, body); @@ -1901,29 +1961,29 @@ Lagain: goto Lapply; { /* Look for range iteration, i.e. the properties - * .empty, .next, .retreat, .head and .rear + * .empty, .popFront, .popBack, .front and .back * foreach (e; aggr) { ... } * translates to: - * for (auto __r = aggr[]; !__r.empty; __r.next) - * { auto e = __r.head; + * for (auto __r = aggr[]; !__r.empty; __r.popFront) + * { auto e = __r.front; * ... * } */ AggregateDeclaration *ad = (tab->ty == Tclass) ? (AggregateDeclaration *)((TypeClass *)tab)->sym : (AggregateDeclaration *)((TypeStruct *)tab)->sym; - Identifier *idhead; - Identifier *idnext; + Identifier *idfront; + Identifier *idpopFront; if (op == TOKforeach) - { idhead = Id::Ffront; - idnext = Id::FpopFront; + { idfront = Id::Ffront; + idpopFront = Id::FpopFront; } else - { idhead = Id::Fback; - idnext = Id::FpopBack; + { idfront = Id::Fback; + idpopFront = Id::FpopBack; } - Dsymbol *shead = search_function(ad, idhead); - if (!shead) + Dsymbol *sfront = ad->search(0, idfront, 0); + if (!sfront) goto Lapply; /* Generate a temporary __r and initialize it with the aggregate. @@ -1939,13 +1999,13 @@ Lagain: // __r.next e = new VarExp(loc, r); - Expression *increment = new CallExp(loc, new DotIdExp(loc, e, idnext)); + Expression *increment = new CallExp(loc, new DotIdExp(loc, e, idpopFront)); /* Declaration statement for e: - * auto e = __r.idhead; + * auto e = __r.idfront; */ e = new VarExp(loc, r); - Expression *einit = new DotIdExp(loc, e, idhead); + Expression *einit = new DotIdExp(loc, e, idfront); Statement *makeargs, *forbody; if (dim == 1) { @@ -1968,7 +2028,7 @@ Lagain: makeargs = new ExpStatement(loc, de); Expression *ve = new VarExp(loc, vd); - ve->type = shead->isDeclaration()->type; + ve->type = sfront->isDeclaration()->type; if (ve->type->toBasetype()->ty == Tfunction) ve->type = ve->type->toBasetype()->nextOf(); if (!ve->type || ve->type->ty == Terror) @@ -2046,18 +2106,6 @@ Lagain: Type *tret = func->type->nextOf(); - // Need a variable to hold value from any return statements in body. - if (!sc->func->vresult && tret && tret != Type::tvoid) - { - VarDeclaration *v = new VarDeclaration(loc, tret, Id::result, NULL); - v->noscope = 1; - v->semantic(sc); - if (!sc->insert(v)) - assert(0); - v->parent = sc->func; - sc->func->vresult = v; - } - TypeFunction *tfld = NULL; if (sapply) { FuncDeclaration *fdapply = sapply->isFuncDeclaration(); @@ -2533,7 +2581,14 @@ Statement *ForeachRangeStatement::semantic(Scope *sc) */ ExpInitializer *ie = new ExpInitializer(loc, (op == TOKforeach) ? lwr : upr); - key = new VarDeclaration(loc, arg->type, arg->ident, ie); +#if (BUG6652 == 1 || BUG6652 == 2) + key = new VarDeclaration(loc, arg->type, Lexer::uniqueId("__key"), ie); +#else + if (arg->storageClass & STCref) + key = new VarDeclaration(loc, arg->type, arg->ident, ie); + else + key = new VarDeclaration(loc, arg->type, Lexer::uniqueId("__key"), ie); +#endif Identifier *id = Lexer::uniqueId("__limit"); ie = new ExpInitializer(loc, (op == TOKforeach) ? upr : lwr); @@ -2580,6 +2635,28 @@ Statement *ForeachRangeStatement::semantic(Scope *sc) //increment = new AddAssignExp(loc, new VarExp(loc, key), new IntegerExp(1)); increment = new PreExp(TOKpreplusplus, loc, new VarExp(loc, key)); +#if (BUG6652 == 1 || BUG6652 == 2) + if (arg->storageClass & STCref) + { + AliasDeclaration *v = new AliasDeclaration(loc, arg->ident, key); + body = new CompoundStatement(loc, new ExpStatement(loc, v), body); + } + else + { + ExpInitializer *ie = new ExpInitializer(loc, new IdentifierExp(loc, key->ident)); + VarDeclaration *v = new VarDeclaration(loc, NULL, arg->ident, ie); + v->storage_class |= STCforeach | STCref | STCbug6652; + body = new CompoundStatement(loc, new ExpStatement(loc, v), body); + } +#else + if (!(arg->storageClass & STCref)) + { + ExpInitializer *ie = new ExpInitializer(loc, new IdentifierExp(loc, key->ident)); + VarDeclaration *v = new VarDeclaration(loc, NULL, arg->ident, ie); + body = new CompoundStatement(loc, new ExpStatement(loc, v), body); + } +#endif + ForStatement *fs = new ForStatement(loc, forinit, cond, increment, body); s = fs->semantic(sc); return s; @@ -2971,8 +3048,8 @@ Statement *PragmaStatement::semantic(Scope *sc) Expression *e = (*args)[i]; e = e->semantic(sc); - if (e->op != TOKerror) - e = e->optimize(WANTvalue | WANTinterpret); + if (e->op != TOKerror && e->op != TOKtype) + e = e->ctfeInterpret(); if (e->op == TOKerror) { errorSupplemental(loc, "while evaluating pragma(msg, %s)", (*args)[i]->toChars()); goto Lerror; @@ -3002,7 +3079,7 @@ Statement *PragmaStatement::semantic(Scope *sc) Expression *e = (*args)[0]; e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); (*args)[0] = e; StringExp *se = e->toString(); if (!se) @@ -3033,7 +3110,7 @@ Statement *PragmaStatement::semantic(Scope *sc) { Expression *e = (*args)[0]; e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); (*args)[0] = e; Dsymbol *sa = getDsymbol(e); if (!sa || !sa->isFuncDeclaration()) @@ -3171,6 +3248,10 @@ Statement *SwitchStatement::semantic(Scope *sc) condition = condition->semantic(sc); condition = resolveProperties(sc, condition); + TypeEnum *te = NULL; + // preserve enum type for final switches + if (condition->type->ty == Tenum) + te = (TypeEnum *)condition->type; if (condition->type->isString()) { // If it's not an array, cast it to one @@ -3235,8 +3316,8 @@ Statement *SwitchStatement::semantic(Scope *sc) { // Don't use toBasetype() because that will skip past enums t = ((TypeTypedef *)t)->sym->basetype; } - if (condition->type->ty == Tenum) - { TypeEnum *te = (TypeEnum *)condition->type; + if (te) + { EnumDeclaration *ed = te->toDsymbol(sc)->isEnumDeclaration(); assert(ed); size_t dim = ed->members->dim; @@ -3247,7 +3328,7 @@ Statement *SwitchStatement::semantic(Scope *sc) { for (size_t j = 0; j < cases->dim; j++) { CaseStatement *cs = (*cases)[j]; - if (cs->exp->equals(em->value)) + if (cs->exp->equals(em->value) || cs->exp->toInteger() == em->value->toInteger()) goto L1; } error("enum member %s not represented in final switch", em->toChars()); @@ -3397,7 +3478,7 @@ Statement *CaseStatement::semantic(Scope *sc) } } else - exp = exp->optimize(WANTvalue | WANTinterpret); + exp = exp->ctfeInterpret(); if (exp->op != TOKstring && exp->op != TOKint64 && exp->op != TOKerror) { @@ -3503,12 +3584,11 @@ Statement *CaseRangeStatement::semantic(Scope *sc) first = first->semantic(sc); first = first->implicitCastTo(sc, sw->condition->type); - first = first->optimize(WANTvalue | WANTinterpret); - + first = first->ctfeInterpret(); last = last->semantic(sc); last = last->implicitCastTo(sc, sw->condition->type); - last = last->optimize(WANTvalue | WANTinterpret); + last = last->ctfeInterpret(); if (first->op == TOKerror || last->op == TOKerror) return statement ? statement->semantic(sc) : NULL; @@ -3574,12 +3654,12 @@ DefaultStatement::DefaultStatement(Loc loc, Statement *s) : Statement(loc) { this->statement = s; -#if IN_GCC +#ifdef IN_GCC cblock = NULL; -#endif +#elif IN_LLVM bodyBB = NULL; - // LDC enclosingScopeExit = NULL; +#endif } Statement *DefaultStatement::syntaxCopy() @@ -3749,6 +3829,7 @@ ReturnStatement::ReturnStatement(Loc loc, Expression *exp) : Statement(loc) { this->exp = exp; + this->implicit0 = 0; } Statement *ReturnStatement::syntaxCopy() @@ -3766,7 +3847,6 @@ Statement *ReturnStatement::semantic(Scope *sc) FuncDeclaration *fd = sc->parent->isFuncDeclaration(); Scope *scx = sc; - int implicit0 = 0; Expression *eorg = NULL; if (fd->fes) @@ -3810,8 +3890,11 @@ Statement *ReturnStatement::semantic(Scope *sc) { fd->hasReturnExp |= 1; + FuncLiteralDeclaration *fld = fd->isFuncLiteralDeclaration(); if (tret) exp = exp->inferType(tbret); + else if (fld && fld->treq && fld->treq->nextOf()) + exp = exp->inferType(fld->treq->nextOf()); exp = exp->semantic(sc); exp = resolveProperties(sc, exp); if (!((TypeFunction *)fd->type)->isref) @@ -3984,11 +4067,14 @@ Statement *ReturnStatement::semantic(Scope *sc) // Construct: return vresult; if (!fd->vresult) { // Declare vresult + Scope *sco = fd->scout ? fd->scout : scx; VarDeclaration *v = new VarDeclaration(loc, tret, Id::result, NULL); v->noscope = 1; v->storage_class |= STCresult; - v->semantic(scx); - if (!scx->insert(v)) + if (((TypeFunction *)fd->type)->isref) + v->storage_class |= STCref | STCforeach; + v->semantic(sco); + if (!sco->insert(v)) assert(0); v->parent = fd; fd->vresult = v; @@ -4027,7 +4113,7 @@ Statement *ReturnStatement::semantic(Scope *sc) if (fd->returnLabel && tbret->ty != Tvoid) { - assert(fd->vresult); + fd->buildResultVar(); VarExp *v = new VarExp(0, fd->vresult); assert(eorg); @@ -4357,9 +4443,16 @@ Statement *SynchronizedStatement::semantic(Scope *sc) { /* Cast the interface to an object, as the object has the monitor, * not the interface. */ - Type *t = new TypeIdentifier(0, Id::Object); + if (!ClassDeclaration::object) + { + error("missing or corrupt object.d"); + fatal(); + } + + Type *t = ClassDeclaration::object->type; + t = t->semantic(0, sc)->toBasetype(); + assert(t->ty == Tclass); - t = t->semantic(0, sc); exp = new CastExp(loc, exp, t); exp = exp->semantic(sc); } @@ -5313,9 +5406,6 @@ LabelDsymbol::LabelDsymbol(Identifier *ident) : Dsymbol(ident) { statement = NULL; -#if IN_GCC - asmLabelNum = 0; -#endif } LabelDsymbol *LabelDsymbol::isLabel() // is this a LabelDsymbol()? @@ -5410,9 +5500,29 @@ Statement *ImportStatement::syntaxCopy() Statement *ImportStatement::semantic(Scope *sc) { for (size_t i = 0; i < imports->dim; i++) - { Dsymbol *s = (*imports)[i]; + { Import *s = (*imports)[i]->isImport(); + + for (size_t i = 0; i < s->names.dim; i++) + { + Identifier *name = s->names[i]; + Identifier *alias = s->aliases[i]; + + if (!alias) + alias = name; + + TypeIdentifier *tname = new TypeIdentifier(s->loc, name); + AliasDeclaration *ad = new AliasDeclaration(s->loc, alias, tname); + + s->aliasdecls.push(ad); + } + s->semantic(sc); sc->insert(s); + + for (size_t i = 0; i < s->aliasdecls.dim; i++) + { + sc->insert(s->aliasdecls[i]); + } } return this; } diff --git a/dmd2/statement.h b/dmd2/statement.h index 2bd213dc..a06e79e2 100644 --- a/dmd2/statement.h +++ b/dmd2/statement.h @@ -79,7 +79,7 @@ struct DValue; typedef DValue elem; #endif -#if IN_GCC +#ifdef IN_GCC union tree_node; typedef union tree_node block; //union tree_node; typedef union tree_node elem; #else @@ -595,7 +595,7 @@ struct CaseRangeStatement : Statement struct DefaultStatement : Statement { Statement *statement; -#if IN_GCC +#ifdef IN_GCC block *cblock; // back end: label for the block #endif @@ -664,6 +664,7 @@ struct SwitchErrorStatement : Statement struct ReturnStatement : Statement { Expression *exp; + int implicit0; ReturnStatement(Loc loc, Expression *exp); Statement *syntaxCopy(); @@ -930,9 +931,6 @@ struct LabelStatement : Statement struct LabelDsymbol : Dsymbol { LabelStatement *statement; -#if IN_GCC - unsigned asmLabelNum; // GCC-specific -#endif LabelDsymbol(Identifier *ident); LabelDsymbol *isLabel(); diff --git a/dmd2/staticassert.c b/dmd2/staticassert.c index 8e3dcefa..6fa9606c 100644 --- a/dmd2/staticassert.c +++ b/dmd2/staticassert.c @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2011 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -59,10 +59,14 @@ void StaticAssert::semantic2(Scope *sc) ++sc->ignoreTemplates; Expression *e = exp->semantic(sc); sc = sc->pop(); - if (e->type == Type::terror) + if (!e->type->checkBoolean()) + { + if (e->type->toBasetype() != Type::terror) + exp->error("expression %s of type %s does not have a boolean value", exp->toChars(), e->type->toChars()); return; + } unsigned olderrs = global.errors; - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); if (global.errors != olderrs) { errorSupplemental(loc, "while evaluating: static assert(%s)", exp->toChars()); @@ -74,7 +78,7 @@ void StaticAssert::semantic2(Scope *sc) OutBuffer buf; msg = msg->semantic(sc); - msg = msg->optimize(WANTvalue | WANTinterpret); + msg = msg->ctfeInterpret(); hgs.console = 1; msg->toCBuffer(&buf, &hgs); error("%s", buf.toChars()); diff --git a/dmd2/struct.c b/dmd2/struct.c index 51e6c3a7..0b3e9b97 100644 --- a/dmd2/struct.c +++ b/dmd2/struct.c @@ -37,7 +37,6 @@ AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id) scope = 0; structsize = 0; // size of struct alignsize = 0; // size of struct for alignment purposes - structalign = 0; // struct member alignment in effect hasUnions = 0; sizeok = SIZEOKnone; // size not determined yet deferred = NULL; @@ -60,6 +59,7 @@ AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id) noDefaultCtor = FALSE; #endif dtor = NULL; + getRTInfo = NULL; #if IN_LLVM availableExternally = true; // assume this unless proven otherwise @@ -83,7 +83,7 @@ void AggregateDeclaration::semantic2(Scope *sc) sc = sc->push(this); for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = members->tdata()[i]; + Dsymbol *s = (*members)[i]; s->semantic2(sc); } sc->pop(); @@ -103,10 +103,25 @@ void AggregateDeclaration::semantic3(Scope *sc) sc = sc->push(this); for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = members->tdata()[i]; + Dsymbol *s = (*members)[i]; s->semantic3(sc); } sc->pop(); + + if (!getRTInfo) + { // Evaluate: gcinfo!type + Objects *tiargs = new Objects(); + tiargs->push(type); + TemplateInstance *ti = new TemplateInstance(loc, Type::rtinfo, tiargs); + ti->semantic(sc); + ti->semantic2(sc); + ti->semantic3(sc); + Dsymbol *s = ti->toAlias(); + Expression *e = new DsymbolExp(0, s, 0); + e = e->semantic(ti->tempdecl->scope); + e = e->ctfeInterpret(); + getRTInfo = e; + } } } @@ -117,7 +132,7 @@ void AggregateDeclaration::inlineScan() { for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = members->tdata()[i]; + Dsymbol *s = (*members)[i]; //printf("inline scan aggregate symbol '%s'\n", s->toChars()); s->inlineScan(); } @@ -127,6 +142,8 @@ void AggregateDeclaration::inlineScan() unsigned AggregateDeclaration::size(Loc loc) { //printf("AggregateDeclaration::size() %s, scope = %p\n", toChars(), scope); + if (loc.linnum == 0) + loc = this->loc; if (!members) error(loc, "unknown size"); if (sizeok != SIZEOKdone && scope) @@ -196,20 +213,33 @@ int AggregateDeclaration::isExport() */ void AggregateDeclaration::alignmember( - unsigned salign, // struct alignment that is in effect - unsigned size, // alignment requirement of field + structalign_t alignment, // struct alignment that is in effect + unsigned size, // alignment requirement of field unsigned *poffset) { - //printf("salign = %d, size = %d, offset = %d\n",salign,size,offset); - if (salign > 1) + //printf("alignment = %d, size = %d, offset = %d\n",alignment,size,offset); + switch (alignment) { - assert(size != 3); - unsigned sa = size; - if (sa == 0 || salign < sa) - sa = salign; - *poffset = (*poffset + sa - 1) & ~(sa - 1); + case 1: + // No alignment + break; + + case STRUCTALIGN_DEFAULT: + { /* Must match what the corresponding C compiler's default + * alignment behavior is. + */ + assert(size != 3); + unsigned sa = (size == 0 || 8 < size) ? 8 : size; + *poffset = (*poffset + sa - 1) & ~(sa - 1); + break; + } + + default: + // Align on alignment boundary, which must be a positive power of 2 + assert(alignment > 0 && !(alignment & (alignment - 1))); + *poffset = (*poffset + alignment - 1) & ~(alignment - 1); + break; } - //printf("result = %d\n",offset); } /**************************************** @@ -221,25 +251,36 @@ unsigned AggregateDeclaration::placeField( unsigned *nextoffset, // next location in aggregate unsigned memsize, // size of member unsigned memalignsize, // size of member for alignment purposes - unsigned memalign, // alignment in effect for this member + structalign_t alignment, // alignment in effect for this member unsigned *paggsize, // size of aggregate (updated) unsigned *paggalignsize, // size of aggregate for alignment purposes (updated) bool isunion // the aggregate is a union ) { unsigned ofs = *nextoffset; - alignmember(memalign, memalignsize, &ofs); + alignmember(alignment, memalignsize, &ofs); unsigned memoffset = ofs; ofs += memsize; if (ofs > *paggsize) *paggsize = ofs; if (!isunion) *nextoffset = ofs; - if (global.params.is64bit && memalign == 8 && memalignsize == 16) - /* Not sure how to handle this */ - ; - else if (memalign < memalignsize) - memalignsize = memalign; + + if (alignment == STRUCTALIGN_DEFAULT) + { + if (global.params.is64bit && memalignsize == 16) + ; + else if (8 < memalignsize) + memalignsize = 8; + else if (alignment < memalignsize) + memalignsize = alignment; + } + else + { + if (memalignsize < alignment) + memalignsize = alignment; + } + if (*paggalignsize < memalignsize) *paggalignsize = memalignsize; @@ -265,13 +306,13 @@ int AggregateDeclaration::firstFieldInUnion(int indx) { if (isUnionDeclaration()) return 0; - VarDeclaration * vd = fields.tdata()[indx]; + VarDeclaration * vd = fields[indx]; int firstNonZero = indx; // first index in the union with non-zero size for (; ;) { if (indx == 0) return firstNonZero; - VarDeclaration * v = fields.tdata()[indx - 1]; + VarDeclaration * v = fields[indx - 1]; if (v->offset != vd->offset) return firstNonZero; --indx; @@ -290,7 +331,7 @@ int AggregateDeclaration::firstFieldInUnion(int indx) */ int AggregateDeclaration::numFieldsInUnion(int firstIndex) { - VarDeclaration * vd = fields.tdata()[firstIndex]; + VarDeclaration * vd = fields[firstIndex]; /* If it is a zero-length field, AND we can't find an earlier non-zero * sized field with the same offset, we assume it's not part of a union. */ @@ -300,7 +341,7 @@ int AggregateDeclaration::numFieldsInUnion(int firstIndex) int count = 1; for (size_t i = firstIndex+1; i < fields.dim; ++i) { - VarDeclaration * v = fields.tdata()[i]; + VarDeclaration * v = fields[i]; // If offsets are different, they are not in the same union if (v->offset != vd->offset) break; @@ -322,7 +363,10 @@ StructDeclaration::StructDeclaration(Loc loc, Identifier *id) postblit = NULL; xeq = NULL; + alignment = 0; #endif + arg1type = NULL; + arg2type = NULL; // For forward references type = new TypeStruct(this); @@ -389,8 +433,8 @@ void StructDeclaration::semantic(Scope *sc) #else handle = type->pointerTo(); #endif - structalign = sc->structalign; protection = sc->protection; + alignment = sc->structalign; storage_class |= sc->stc; if (sc->stc & STCdeprecated) isdeprecated = true; @@ -403,7 +447,7 @@ void StructDeclaration::semantic(Scope *sc) int hasfunctions = 0; for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = members->tdata()[i]; + Dsymbol *s = (*members)[i]; //printf("adding member '%s' to '%s'\n", s->toChars(), this->toChars()); s->addMember(sc, this, 1); if (s->isFuncDeclaration()) @@ -452,6 +496,7 @@ void StructDeclaration::semantic(Scope *sc) sc2->inunion = 1; sc2->protection = PROTpublic; sc2->explicitProtection = 0; + sc2->structalign = STRUCTALIGN_DEFAULT; size_t members_dim = members->dim; @@ -507,7 +552,7 @@ void StructDeclaration::semantic(Scope *sc) fields.setDim(0); structsize = 0; alignsize = 0; - structalign = 0; +// structalign = 0; scope = scx ? scx : new Scope(*sc); scope->setNoFree(); @@ -631,6 +676,15 @@ void StructDeclaration::semantic(Scope *sc) aggNew = (NewDeclaration *)search(0, Id::classNew, 0); aggDelete = (DeleteDeclaration *)search(0, Id::classDelete, 0); + TypeTuple *tup = type->toArgTypes(); + size_t dim = tup->arguments->dim; + if (dim >= 1) + { assert(dim <= 2); + arg1type = (*tup->arguments)[0]->type; + if (dim == 2) + arg2type = (*tup->arguments)[1]->type; + } + if (sc->func) { semantic2(sc); @@ -667,6 +721,7 @@ Dsymbol *StructDeclaration::search(Loc loc, Identifier *ident, int flags) void StructDeclaration::finalizeSize(Scope *sc) { + //printf("StructDeclaration::finalizeSize() %s\n", toChars()); if (sizeok != SIZEOKnone) return; @@ -690,11 +745,56 @@ void StructDeclaration::finalizeSize(Scope *sc) // Round struct size up to next alignsize boundary. // This will ensure that arrays of structs will get their internals // aligned properly. - structsize = (structsize + alignsize - 1) & ~(alignsize - 1); + if (alignment == STRUCTALIGN_DEFAULT) + structsize = (structsize + alignsize - 1) & ~(alignsize - 1); + else + structsize = (structsize + alignment - 1) & ~(alignment - 1); sizeok = SIZEOKdone; } +/*************************************** + * Return true if struct is POD (Plain Old Data). + * This is defined as: + * not nested + * no postblits, constructors, destructors, or assignment operators + * no fields with with any of those + * The idea being these are compatible with C structs. + * + * Note that D struct constructors can mean POD, since there is always default + * construction with no ctor, but that interferes with OPstrpar which wants it + * on the stack in memory, not in registers. + */ +bool StructDeclaration::isPOD() +{ + if (isnested || cpctor || postblit || ctor || dtor) + return false; + + /* Recursively check any fields have a constructor. + * We should cache the results of this. + */ + for (size_t i = 0; i < fields.dim; i++) + { + Dsymbol *s = fields[i]; + VarDeclaration *v = s->isVarDeclaration(); + assert(v && v->storage_class & STCfield); + if (v->storage_class & STCref) + continue; + Type *tv = v->type->toBasetype(); + while (tv->ty == Tsarray) + { TypeSArray *ta = (TypeSArray *)tv; + tv = tv->nextOf()->toBasetype(); + } + if (tv->ty == Tstruct) + { TypeStruct *ts = (TypeStruct *)tv; + StructDeclaration *sd = ts->sym; + if (!sd->isPOD()) + return false; + } + } + return true; +} + void StructDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->printf("%s ", kind()); @@ -711,7 +811,7 @@ void StructDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writenl(); for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = members->tdata()[i]; + Dsymbol *s = (*members)[i]; buf->writestring(" "); s->toCBuffer(buf, hgs); diff --git a/dmd2/template.c b/dmd2/template.c index 2f8ce392..dd2a67fa 100644 --- a/dmd2/template.c +++ b/dmd2/template.c @@ -85,7 +85,7 @@ int isError(Object *o) return (t->ty == Terror); Expression *e = isExpression(o); if (e) - return (e->op == TOKerror); + return (e->op == TOKerror || !e->type || e->type->ty== Terror); Tuple *v = isTuple(o); if (v) return arrayObjectIsError(&v->objects); @@ -99,7 +99,7 @@ int arrayObjectIsError(Objects *args) { for (size_t i = 0; i < args->dim; i++) { - Object *o = args->tdata()[i]; + Object *o = (*args)[i]; if (isError(o)) return 1; } @@ -130,7 +130,12 @@ Dsymbol *getDsymbol(Object *oarg) if (ea->op == TOKvar) sa = ((VarExp *)ea)->var; else if (ea->op == TOKfunction) - sa = ((FuncExp *)ea)->fd; + { + if (((FuncExp *)ea)->td) + sa = ((FuncExp *)ea)->td; + else + sa = ((FuncExp *)ea)->fd; + } else sa = NULL; } @@ -243,8 +248,8 @@ int match(Object *o1, Object *o2, TemplateDeclaration *tempdecl, Scope *sc) goto Lnomatch; for (size_t i = 0; i < u1->objects.dim; i++) { - if (!match(u1->objects.tdata()[i], - u2->objects.tdata()[i], + if (!match(u1->objects[i], + u2->objects[i], tempdecl, sc)) goto Lnomatch; } @@ -268,8 +273,8 @@ int arrayObjectMatch(Objects *oa1, Objects *oa2, TemplateDeclaration *tempdecl, if (oa1->dim != oa2->dim) return 0; for (size_t j = 0; j < oa1->dim; j++) - { Object *o1 = oa1->tdata()[j]; - Object *o2 = oa2->tdata()[j]; + { Object *o1 = (*oa1)[j]; + Object *o2 = (*oa2)[j]; if (!match(o1, o2, tempdecl, sc)) { return 0; @@ -362,7 +367,7 @@ TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id, #if 0 if (parameters) for (int i = 0; i < parameters->dim; i++) - { TemplateParameter *tp = parameters->tdata()[i]; + { TemplateParameter *tp = (*parameters)[i]; //printf("\tparameter[%d] = %p\n", i, tp); TemplateTypeParameter *ttp = tp->isTemplateTypeParameter(); @@ -410,7 +415,7 @@ Dsymbol *TemplateDeclaration::syntaxCopy(Dsymbol *) p->setDim(parameters->dim); for (size_t i = 0; i < p->dim; i++) { TemplateParameter *tp = (*parameters)[i]; - p->tdata()[i] = tp->syntaxCopy(); + (*p)[i] = tp->syntaxCopy(); } } Expression *e = NULL; @@ -437,8 +442,13 @@ void TemplateDeclaration::semantic(Scope *sc) return; // semantic() already run semanticRun = PASSsemantic; - if (sc->module && sc->module->ident == Id::object && ident == Id::AssociativeArray) - { Type::associativearray = this; + // Remember templates defined in module object that we need to know about + if (sc->module && sc->module->ident == Id::object) + { + if (ident == Id::AssociativeArray) + Type::associativearray = this; + else if (ident == Id::RTInfo) + Type::rtinfo = this; } if (sc->func) @@ -465,7 +475,7 @@ void TemplateDeclaration::semantic(Scope *sc) } #if DMDV2 - if (/*global.params.useUnitTests &&*/ sc->module) + if (sc->module) { // Generate this function as it may be used // when template is instantiated in other modules @@ -499,13 +509,13 @@ void TemplateDeclaration::semantic(Scope *sc) for (size_t i = 0; i < parameters->dim; i++) { TemplateParameter *tp = (*parameters)[i]; - origParameters->tdata()[i] = tp->syntaxCopy(); + (*origParameters)[i] = tp->syntaxCopy(); } } for (size_t i = 0; i < parameters->dim; i++) { - TemplateParameter *tp = parameters->tdata()[i]; + TemplateParameter *tp = (*parameters)[i]; tp->declareParameter(paramscope); } @@ -576,8 +586,8 @@ int TemplateDeclaration::overloadInsert(Dsymbol *s) goto Lcontinue; for (size_t i = 0; i < f->parameters->dim; i++) - { TemplateParameter *p1 = f->parameters->tdata()[i]; - TemplateParameter *p2 = f2->parameters->tdata()[i]; + { TemplateParameter *p1 = (*f->parameters)[i]; + TemplateParameter *p2 = (*f2->parameters)[i]; if (!p1->overloadMatch(p2)) goto Lcontinue; @@ -622,7 +632,7 @@ void TemplateDeclaration::makeParamNamesVisibleInConstraint(Scope *paramscope, E // Shouldn't run semantic on default arguments and return type. for (int i = 0; iparameters->dim; i++) - tf->parameters->tdata()[i]->defaultArg = NULL; + (*tf->parameters)[i]->defaultArg = NULL; tf->next = NULL; // Resolve parameter types and 'auto ref's. @@ -647,7 +657,7 @@ void TemplateDeclaration::makeParamNamesVisibleInConstraint(Scope *paramscope, E } for (size_t i = 0; i < fparameters->dim; i++) { - Parameter *fparam = fparameters->tdata()[i]; + Parameter *fparam = (*fparameters)[i]; if (!fparam->ident) continue; // don't add it, if it has no name VarDeclaration *v = new VarDeclaration(loc, fparam->type, fparam->ident, NULL); @@ -688,7 +698,7 @@ MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, if (ti->tiargs->dim) printf("ti->tiargs->dim = %d, [0] = %p\n", ti->tiargs->dim, - ti->tiargs->tdata()[0]); + (*ti->tiargs)[0]); #endif dedtypes->zero(); @@ -721,7 +731,7 @@ MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, m = MATCHexact; for (size_t i = 0; i < dedtypes_dim; i++) { MATCH m2; - TemplateParameter *tp = parameters->tdata()[i]; + TemplateParameter *tp = (*parameters)[i]; Declaration *sparam; //printf("\targument [%d]\n", i); @@ -759,9 +769,9 @@ MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, */ for (size_t i = 0; i < dedtypes_dim; i++) { - if (!dedtypes->tdata()[i]) + if (!(*dedtypes)[i]) { assert(i < ti->tiargs->dim); - dedtypes->tdata()[i] = (Type *)ti->tiargs->tdata()[i]; + (*dedtypes)[i] = (Type *)(*ti->tiargs)[i]; } } } @@ -796,12 +806,14 @@ MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, } e = e->semantic(sc); + if (e->op == TOKerror) + goto Lnomatch; if (fd && fd->vthis) fd->vthis = vthissave; sc->pop(); - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); if (e->isBool(TRUE)) ; else if (e->isBool(FALSE)) @@ -822,16 +834,16 @@ MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, { for (size_t i = 0; i < dedtypes_dim; i++) { - TemplateParameter *tp = parameters->tdata()[i]; + TemplateParameter *tp = (*parameters)[i]; Object *oarg; printf(" [%d]", i); if (i < ti->tiargs->dim) - oarg = ti->tiargs->tdata()[i]; + oarg = (*ti->tiargs)[i]; else oarg = NULL; - tp->print(oarg, dedtypes->tdata()[i]); + tp->print(oarg, (*dedtypes)[i]); } } else @@ -888,11 +900,11 @@ MATCH TemplateDeclaration::leastAsSpecialized(TemplateDeclaration *td2, Expressi ti.tiargs->setDim(parameters->dim); for (size_t i = 0; i < ti.tiargs->dim; i++) { - TemplateParameter *tp = parameters->tdata()[i]; + TemplateParameter *tp = (*parameters)[i]; Object *p = (Object *)tp->dummyArg(); if (p) - ti.tiargs->tdata()[i] = p; + (*ti.tiargs)[i] = p; else ti.tiargs->setDim(i); } @@ -935,6 +947,8 @@ MATCH TemplateDeclaration::leastAsSpecialized(TemplateDeclaration *td2, Expressi * dedargs Expression/Type deduced template arguments * Returns: * match level + * bit 0-3 Match template parameters by inferred template arguments + * bit 4-7 Match template parameters by initial template arguments */ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Scope *sc, Loc loc, Objects *targsi, @@ -947,18 +961,20 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Scope *sc, Loc loc, Objec int fptupindex = -1; int tuple_dim = 0; MATCH match = MATCHexact; + MATCH matchTargsi = MATCHexact; FuncDeclaration *fd = onemember->toAlias()->isFuncDeclaration(); Parameters *fparameters; // function parameter list int fvarargs; // function varargs Objects dedtypes; // for T:T*, the dedargs is the T*, dedtypes is the T unsigned wildmatch = 0; + TemplateParameters *inferparams = parameters; TypeFunction *tf = (TypeFunction *)fd->type; #if 0 printf("\nTemplateDeclaration::deduceFunctionTemplateMatch() %s\n", toChars()); for (size_t i = 0; i < fargs->dim; i++) - { Expression *e = fargs->tdata()[i]; + { Expression *e = (*fargs)[i]; printf("\tfarg[%d] is %s, type is %s\n", i, e->toChars(), e->type->toChars()); } printf("fd = %s\n", fd->toChars()); @@ -991,7 +1007,7 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Scope *sc, Loc loc, Objec for (size_t i = 0; i < dedargs->dim; i++) { printf("\tdedarg[%d] = ", i); - Object *oarg = dedargs->tdata()[i]; + Object *oarg = (*dedargs)[i]; if (oarg) printf("%s", oarg->toChars()); printf("\n"); } @@ -1015,13 +1031,13 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Scope *sc, Loc loc, Objec */ Tuple *t = new Tuple(); assert(parameters->dim); - dedargs->tdata()[parameters->dim - 1] = t; + (*dedargs)[parameters->dim - 1] = t; tuple_dim = nargsi - n; t->objects.setDim(tuple_dim); for (size_t i = 0; i < tuple_dim; i++) { - t->objects.tdata()[i] = targsi->tdata()[n + i]; + t->objects[i] = (*targsi)[n + i]; } declareParameter(paramscope, tp, t); tp_is_declared = 1; @@ -1033,7 +1049,7 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Scope *sc, Loc loc, Objec for (size_t i = 0; i < n; i++) { assert(i < parameters->dim); - TemplateParameter *tp = parameters->tdata()[i]; + TemplateParameter *tp = (*parameters)[i]; MATCH m; Declaration *sparam = NULL; @@ -1041,19 +1057,29 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Scope *sc, Loc loc, Objec //printf("\tdeduceType m = %d\n", m); if (m == MATCHnomatch) goto Lnomatch; - if (m < match) - match = m; + if (m < matchTargsi) + matchTargsi = m; sparam->semantic(paramscope); if (!paramscope->insert(sparam)) goto Lnomatch; } + if (n < parameters->dim) + { + inferparams = new TemplateParameters(); + inferparams->setDim(parameters->dim - n); + memcpy(inferparams->tdata(), + parameters->tdata() + n, + inferparams->dim * sizeof(*inferparams->tdata())); + } + else + inferparams = NULL; } #if 0 for (size_t i = 0; i < dedargs->dim; i++) { printf("\tdedarg[%d] = ", i); - Object *oarg = dedargs->tdata()[i]; + Object *oarg = (*dedargs)[i]; if (oarg) printf("%s", oarg->toChars()); printf("\n"); } @@ -1077,7 +1103,7 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Scope *sc, Loc loc, Objec goto L2; Tuple *t = new Tuple(); //printf("t = %p\n", t); - dedargs->tdata()[parameters->dim - 1] = t; + (*dedargs)[parameters->dim - 1] = t; declareParameter(paramscope, tp, t); goto L2; } @@ -1092,7 +1118,7 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Scope *sc, Loc loc, Objec */ for (fptupindex = 0; fptupindex < nfparams; fptupindex++) { - Parameter *fparam = fparameters->tdata()[fptupindex]; + Parameter *fparam = (*fparameters)[fptupindex]; if (fparam->type->ty != Tident) continue; TypeIdentifier *tid = (TypeIdentifier *)fparam->type; @@ -1112,12 +1138,12 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Scope *sc, Loc loc, Objec * now form the tuple argument. */ Tuple *t = new Tuple(); - dedargs->tdata()[parameters->dim - 1] = t; + (*dedargs)[parameters->dim - 1] = t; tuple_dim = nfargs - (nfparams - 1); t->objects.setDim(tuple_dim); for (size_t i = 0; i < tuple_dim; i++) - { Expression *farg = fargs->tdata()[fptupindex + i]; + { Expression *farg = (*fargs)[fptupindex + i]; // Check invalid arguments to detect errors early. if (farg->op == TOKerror || farg->type->ty == Terror) @@ -1291,7 +1317,7 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Scope *sc, Loc loc, Objec if (m < match) match = m; - t->objects.tdata()[i] = tt; + t->objects[i] = tt; } declareParameter(paramscope, tp, t); goto L2; @@ -1316,7 +1342,7 @@ L2: { // Match 'ethis' to any TemplateThisParameter's for (size_t i = 0; i < parameters->dim; i++) - { TemplateParameter *tp = parameters->tdata()[i]; + { TemplateParameter *tp = (*parameters)[i]; TemplateThisParameter *ttp = tp->isTemplateThisParameter(); if (ttp) { MATCH m; @@ -1331,7 +1357,7 @@ L2: } // Match attributes of ethis against attributes of fd - if (fd->type) + if (fd->type && !fd->isCtorDeclaration()) { Type *tthis = ethis->type; unsigned mod = fd->type->mod; @@ -1389,6 +1415,7 @@ L2: i += tuple_dim - 1; Parameter *fparam = Parameter::getNth(fparameters, parami); + Type *prmtype = fparam->type; if (i >= nfargs) // if not enough arguments { @@ -1401,7 +1428,7 @@ L2: } else { - Expression *farg = fargs->tdata()[i]; + Expression *farg = (*fargs)[i]; // Check invalid arguments to detect errors early. if (farg->op == TOKerror || farg->type->ty == Terror) @@ -1410,12 +1437,20 @@ L2: Lretry: #if 0 printf("\tfarg->type = %s\n", farg->type->toChars()); - printf("\tfparam->type = %s\n", fparam->type->toChars()); + printf("\tfparam->type = %s\n", prmtype->toChars()); #endif Type *argtype = farg->type; // Apply function parameter storage classes to parameter types - fparam->type = fparam->type->addStorageClass(fparam->storageClass); + prmtype = prmtype->addStorageClass(fparam->storageClass); + + // If parameter type doesn't depend on inferred template parameters, + // semantic it to get actual type. + if (!inferparams || !prmtype->reliesOnTident(inferparams)) + { + // should copy prmtype to avoid affecting semantic result + prmtype = prmtype->syntaxCopy()->semantic(loc, paramscope); + } #if DMDV2 /* Allow string literals which are type [] to match with [dim] @@ -1423,7 +1458,7 @@ Lretry: if (farg->op == TOKstring) { StringExp *se = (StringExp *)farg; if (!se->committed && argtype->ty == Tarray && - fparam->type->toBasetype()->ty == Tsarray) + prmtype->toBasetype()->ty == Tsarray) { argtype = new TypeSArray(argtype->nextOf(), new IntegerExp(se->loc, se->len, Type::tindex)); argtype = argtype->semantic(se->loc, NULL); @@ -1435,7 +1470,7 @@ Lretry: */ if (farg->op == TOKfunction) { FuncExp *fe = (FuncExp *)farg; - Type *tp = fparam->type; + Type *tp = prmtype; Expression *e = fe->inferType(tp, 1, parameters); if (!e) goto Lvarargs; @@ -1461,20 +1496,26 @@ Lretry: goto Lvarargs; unsigned wm = 0; - MATCH m = argtype->deduceType(paramscope, fparam->type, parameters, &dedtypes, &wm); + MATCH m = argtype->deduceType(paramscope, prmtype, parameters, &dedtypes, &wm); //printf("\tdeduceType m = %d\n", m); //printf("\twildmatch = x%x m = %d\n", wildmatch, m); wildmatch |= wm; + /* If no match, see if the argument can be matched by using + * implicit conversions. + */ + if (!m) + m = farg->implicitConvTo(prmtype); + /* If no match, see if there's a conversion to a delegate */ if (!m) - { Type *tbp = fparam->type->toBasetype(); + { Type *tbp = prmtype->toBasetype(); Type *tba = farg->type->toBasetype(); AggregateDeclaration *ad; if (tbp->ty == Tdelegate) { - TypeDelegate *td = (TypeDelegate *)fparam->type->toBasetype(); + TypeDelegate *td = (TypeDelegate *)prmtype->toBasetype(); TypeFunction *tf = (TypeFunction *)td->next; if (!tf->varargs && Parameter::dim(tf->parameters) == 0) @@ -1532,7 +1573,7 @@ Lretry: { if (!farg->isLvalue()) goto Lnomatch; } - if (!m && (fparam->storageClass & STClazy) && fparam->type->ty == Tvoid && + if (!m && (fparam->storageClass & STClazy) && prmtype->ty == Tvoid && farg->type->ty != Tvoid) m = MATCHconvert; @@ -1552,7 +1593,7 @@ Lretry: /* Check for match with function parameter T... */ - Type *tb = fparam->type->toBasetype(); + Type *tb = prmtype->toBasetype(); switch (tb->ty) { // Perhaps we can do better with this, see TypeFunction::callMatch() @@ -1566,7 +1607,7 @@ Lretry: { TypeArray *ta = (TypeArray *)tb; for (; i < nfargs; i++) { - Expression *arg = fargs->tdata()[i]; + Expression *arg = (*fargs)[i]; assert(arg); if (arg->op == TOKfunction) @@ -1624,13 +1665,13 @@ Lmatch: for (size_t i = nargsi; i < dedargs->dim; i++) { - TemplateParameter *tparam = parameters->tdata()[i]; + TemplateParameter *tparam = (*parameters)[i]; //printf("tparam[%d] = %s\n", i, tparam->ident->toChars()); /* For T:T*, the dedargs is the T*, dedtypes is the T * But for function templates, we really need them to match */ - Object *oarg = dedargs->tdata()[i]; - Object *oded = dedtypes.tdata()[i]; + Object *oarg = (*dedargs)[i]; + Object *oded = dedtypes[i]; //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded); //if (oarg) printf("oarg: %s\n", oarg->toChars()); //if (oded) printf("oded: %s\n", oded->toChars()); @@ -1643,14 +1684,14 @@ Lmatch: * the oded == oarg */ Declaration *sparam; - dedargs->tdata()[i] = oded; + (*dedargs)[i] = oded; MATCH m2 = tparam->matchArg(paramscope, dedargs, i, parameters, &dedtypes, &sparam); //printf("m2 = %d\n", m2); if (!m2) goto Lnomatch; if (m2 < match) match = m2; // pick worst match - if (dedtypes.tdata()[i] != oded) + if (dedtypes[i] != oded) error("specialization not allowed for deduced parameter %s", tparam->ident->toChars()); } } @@ -1669,7 +1710,7 @@ Lmatch: } } declareParameter(paramscope, tparam, oded); - dedargs->tdata()[i] = oded; + (*dedargs)[i] = oded; } } @@ -1738,8 +1779,10 @@ Lmatch: if (nerrors != global.errors) // if any errors from evaluating the constraint, no match goto Lnomatch; + if (e->op == TOKerror) + goto Lnomatch; - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); if (e->isBool(TRUE)) ; else if (e->isBool(FALSE)) @@ -1753,14 +1796,14 @@ Lmatch: #if 0 for (i = 0; i < dedargs->dim; i++) - { Type *t = dedargs->tdata()[i]; + { Type *t = (*dedargs)[i]; printf("\tdedargs[%d] = %d, %s\n", i, t->dyncast(), t->toChars()); } #endif paramscope->pop(); //printf("\tmatch %d\n", match); - return match; + return (MATCH)(match | (matchTargsi<<4)); Lnomatch: paramscope->pop(); @@ -1798,6 +1841,12 @@ void TemplateDeclaration::declareParameter(Scope *sc, TemplateParameter *tp, Obj } } } + if (ea && ea->op == TOKtype) + targ = ea->type; + else if (ea && ea->op == TOKimport) + sa = ((ScopeExp *)ea)->sds; + else if (ea && (ea->op == TOKthis || ea->op == TOKsuper)) + sa = ((ThisExp *)ea)->var; if (targ) { @@ -1809,6 +1858,14 @@ void TemplateDeclaration::declareParameter(Scope *sc, TemplateParameter *tp, Obj //printf("Alias %s %s;\n", sa->ident->toChars(), tp->ident->toChars()); s = new AliasDeclaration(0, tp->ident, sa); } + else if (ea && ea->op == TOKfunction) + { + if (((FuncExp *)ea)->td) + sa = ((FuncExp *)ea)->td; + else + sa = ((FuncExp *)ea)->fd; + s = new AliasDeclaration(0, tp->ident, sa); + } else if (ea) { // tdtypes.data[i] always matches ea here @@ -1847,7 +1904,7 @@ TemplateTupleParameter *isVariadic(TemplateParameters *parameters) TemplateTupleParameter *tp = NULL; if (dim) - tp = (parameters->tdata()[dim - 1])->isTemplateTupleParameter(); + tp = ((*parameters)[dim - 1])->isTemplateTupleParameter(); return tp; } @@ -1882,6 +1939,7 @@ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, Objects *targsi, Expression *ethis, Expressions *fargs, int flags) { MATCH m_best = MATCHnomatch; + MATCH m_best2 = MATCHnomatch; TemplateDeclaration *td_ambig = NULL; TemplateDeclaration *td_best = NULL; Objects *tdargs = new Objects(); @@ -1893,13 +1951,13 @@ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, printf(" targsi:\n"); if (targsi) { for (size_t i = 0; i < targsi->dim; i++) - { Object *arg = targsi->tdata()[i]; + { Object *arg = (*targsi)[i]; printf("\t%s\n", arg->toChars()); } } printf(" fargs:\n"); for (size_t i = 0; i < fargs->dim; i++) - { Expression *arg = fargs->tdata()[i]; + { Expression *arg = (*fargs)[i]; printf("\t%s %s\n", arg->type->toChars(), arg->toChars()); //printf("\tty = %d\n", arg->type->ty); } @@ -1919,14 +1977,22 @@ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, goto Lerror; } + MATCH m, m2; Objects dedargs; FuncDeclaration *fd = NULL; - MATCH m = td->deduceFunctionTemplateMatch(sc, loc, targsi, ethis, fargs, &dedargs); - //printf("deduceFunctionTemplateMatch = %d\n", m); + m = td->deduceFunctionTemplateMatch(sc, loc, targsi, ethis, fargs, &dedargs); + m2 = (MATCH)(m >> 4); + m = (MATCH)(m & 0xF); + //printf("deduceFunctionTemplateMatch = %d, m2 = %d\n", m, m2); if (!m) // if no match continue; + if (m2 < m_best2) + goto Ltd_best; + if (m2 > m_best2) + goto Ltd; + if (m < m_best) goto Ltd_best; if (m > m_best) @@ -1962,7 +2028,7 @@ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, TypeFunction *tf1 = (TypeFunction *)fd->type; TypeFunction *tf2 = (TypeFunction *)fd_best->type; MATCH c1 = (MATCH) tf1->callMatch(fd->needThis() && !fd->isCtorDeclaration() ? ethis : NULL, fargs); - MATCH c2 = (MATCH) tf2->callMatch(fd_best->needThis() && !fd->isCtorDeclaration() ? ethis : NULL, fargs); + MATCH c2 = (MATCH) tf2->callMatch(fd_best->needThis() && !fd_best->isCtorDeclaration() ? ethis : NULL, fargs); //printf("2: c1 = %d, c2 = %d\n", c1, c2); if (c1 > c2) @@ -1997,6 +2063,7 @@ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, td_best = td; fd_best = fd; m_best = m; + m_best2 = m2; tdargs->setDim(dedargs.dim); memcpy(tdargs->tdata(), dedargs.tdata(), tdargs->dim * sizeof(void *)); continue; @@ -2023,8 +2090,20 @@ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, ti = new TemplateInstance(loc, td_best, tdargs); ti->semantic(sc, fargs); fd_best = ti->toAlias()->isFuncDeclaration(); - if (!fd_best || !((TypeFunction*)fd_best->type)->callMatch(ethis, fargs, flags)) + if (!fd_best) goto Lerror; + if (!((TypeFunction*)fd_best->type)->callMatch(fd_best->needThis() && !fd_best->isCtorDeclaration() ? ethis : NULL, fargs)) + goto Lerror; + + if (FuncLiteralDeclaration *fld = fd_best->isFuncLiteralDeclaration()) + { + // Inside template constraint, nested reference check doesn't work correctly. + if (!(sc->flags & SCOPEstaticif) && fld->tok == TOKreserved) + { // change to non-nested + fld->tok = TOKfunction; + fld->vthis = NULL; + } + } /* As Bugzilla 3682 shows, a template instance can be matched while instantiating * that same template. Thus, the function type can be incomplete. Complete it. @@ -2051,7 +2130,7 @@ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, { if (i) bufa.writeByte(','); - Object *oarg = args->tdata()[i]; + Object *oarg = (*args)[i]; ObjectToCBuffer(&bufa, &hgs, oarg); } } @@ -2059,7 +2138,7 @@ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, OutBuffer buf; argExpTypesToCBuffer(&buf, fargs, &hgs); if (this->overnext) - ::error(loc, "%s %s.%s cannot deduce template function from argument types !(%s)(%s)", + ::error(this->loc, "%s %s.%s cannot deduce template function from argument types !(%s)(%s)", kind(), parent->toPrettyChars(), ident->toChars(), bufa.toChars(), buf.toChars()); else @@ -2161,9 +2240,9 @@ void TemplateDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writeByte('('); for (size_t i = 0; i < parameters->dim; i++) { - TemplateParameter *tp = parameters->tdata()[i]; + TemplateParameter *tp = (*parameters)[i]; if (hgs->ddoc) - tp = origParameters->tdata()[i]; + tp = (*origParameters)[i]; if (i) buf->writeByte(','); tp->toCBuffer(buf, hgs); @@ -2185,7 +2264,7 @@ void TemplateDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writenl(); for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = members->tdata()[i]; + Dsymbol *s = (*members)[i]; s->toCBuffer(buf, hgs); } buf->writebyte('}'); @@ -2204,7 +2283,7 @@ char *TemplateDeclaration::toChars() buf.writeByte('('); for (size_t i = 0; i < parameters->dim; i++) { - TemplateParameter *tp = parameters->tdata()[i]; + TemplateParameter *tp = (*parameters)[i]; if (i) buf.writeByte(','); tp->toCBuffer(&buf, &hgs); @@ -2231,7 +2310,7 @@ char *TemplateDeclaration::toChars() int templateIdentifierLookup(Identifier *id, TemplateParameters *parameters) { for (size_t i = 0; i < parameters->dim; i++) - { TemplateParameter *tp = parameters->tdata()[i]; + { TemplateParameter *tp = (*parameters)[i]; if (tp->ident->equals(id)) return i; @@ -2294,7 +2373,7 @@ MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Loc loc; if (parameters->dim) { - TemplateParameter *tp = parameters->tdata()[0]; + TemplateParameter *tp = (*parameters)[0]; loc = tp->loc; } @@ -2306,13 +2385,13 @@ MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, return deduceType(sc, tparam, parameters, dedtypes, wildmatch); } - TemplateParameter *tp = parameters->tdata()[i]; + TemplateParameter *tp = (*parameters)[i]; // Found the corresponding parameter tp if (!tp->isTemplateTypeParameter()) goto Lnomatch; Type *tt = this; - Type *at = (Type *)dedtypes->tdata()[i]; + Type *at = (Type *)(*dedtypes)[i]; // 7*7 == 49 cases @@ -2343,7 +2422,7 @@ MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, else *wildmatch |= (mod & ~MODshared); tt = mutableOf()->substWildTo(MODmutable); - dedtypes->tdata()[i] = tt; + (*dedtypes)[i] = tt; goto Lconst; } @@ -2357,13 +2436,13 @@ MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, } else if (tt->implicitConvTo(at->constOf())) { - dedtypes->tdata()[i] = at->constOf()->mutableOf(); + (*dedtypes)[i] = at->constOf()->mutableOf(); *wildmatch |= MODconst; goto Lconst; } else if (at->implicitConvTo(tt->constOf())) { - dedtypes->tdata()[i] = tt->constOf()->mutableOf(); + (*dedtypes)[i] = tt->constOf()->mutableOf(); *wildmatch |= MODconst; goto Lconst; } @@ -2391,7 +2470,7 @@ MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, // foo(U:U) wild(T) => wild(T) // foo(U:U) wild(shared(T)) => wild(shared(T)) if (!at) - { dedtypes->tdata()[i] = tt; + { (*dedtypes)[i] = tt; goto Lexact; } break; @@ -2410,7 +2489,7 @@ MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, // foo(U:wild(shared(U)) wild(shared(T)) => T tt = mutableOf()->unSharedOf(); if (!at) - { dedtypes->tdata()[i] = tt; + { (*dedtypes)[i] = tt; goto Lexact; } break; @@ -2428,7 +2507,7 @@ MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, // foo(U:const(U)) wild(shared(T)) => shared(T) tt = mutableOf(); if (!at) - { dedtypes->tdata()[i] = tt; + { (*dedtypes)[i] = tt; goto Lconst; } break; @@ -2441,7 +2520,7 @@ MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, // foo(U:shared(U)) wild(shared(T)) => wild(T) tt = unSharedOf(); if (!at) - { dedtypes->tdata()[i] = tt; + { (*dedtypes)[i] = tt; goto Lconst; } break; @@ -2538,7 +2617,7 @@ MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Loc loc; if (parameters->dim) { - TemplateParameter *tp = parameters->tdata()[0]; + TemplateParameter *tp = (*parameters)[0]; loc = tp->loc; } @@ -2658,11 +2737,11 @@ MATCH TypeSArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parame int i = templateIdentifierLookup(id, parameters); if (i == -1) goto Lnomatch; - TemplateParameter *tprm = parameters->tdata()[i]; + TemplateParameter *tprm = (*parameters)[i]; TemplateValueParameter *tvp = tprm->isTemplateValueParameter(); if (!tvp) goto Lnomatch; - Expression *e = (Expression *)dedtypes->tdata()[i]; + Expression *e = (Expression *)(*dedtypes)[i]; if (e) { if (!dim->equals(e)) @@ -2674,7 +2753,7 @@ MATCH TypeSArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parame MATCH m = (MATCH)dim->implicitConvTo(vt); if (!m) goto Lnomatch; - dedtypes->tdata()[i] = dim; + (*dedtypes)[i] = dim; } return next->deduceType(sc, tparam->nextOf(), parameters, dedtypes, wildmatch); } @@ -2754,7 +2833,7 @@ MATCH TypeFunction::deduceType(Scope *sc, Type *tparam, TemplateParameters *para for (; 1; tupi++) { if (tupi == parameters->dim) goto L1; - TemplateParameter *t = parameters->tdata()[tupi]; + TemplateParameter *t = (*parameters)[tupi]; TemplateTupleParameter *tup = t->isTemplateTupleParameter(); if (tup && tup->ident->equals(tid->ident)) break; @@ -2767,7 +2846,7 @@ MATCH TypeFunction::deduceType(Scope *sc, Type *tparam, TemplateParameters *para /* See if existing tuple, and whether it matches or not */ - Object *o = dedtypes->tdata()[tupi]; + Object *o = (*dedtypes)[tupi]; if (o) { // Existing deduced argument must be a tuple, and must match Tuple *t = isTuple(o); @@ -2775,7 +2854,7 @@ MATCH TypeFunction::deduceType(Scope *sc, Type *tparam, TemplateParameters *para return MATCHnomatch; for (size_t i = 0; i < tuple_dim; i++) { Parameter *arg = Parameter::getNth(this->parameters, nfparams - 1 + i); - if (!arg->type->equals(t->objects.tdata()[i])) + if (!arg->type->equals(t->objects[i])) return MATCHnomatch; } } @@ -2785,9 +2864,9 @@ MATCH TypeFunction::deduceType(Scope *sc, Type *tparam, TemplateParameters *para t->objects.setDim(tuple_dim); for (size_t i = 0; i < tuple_dim; i++) { Parameter *arg = Parameter::getNth(this->parameters, nfparams - 1 + i); - t->objects.tdata()[i] = arg->type; + t->objects[i] = arg->type; } - dedtypes->tdata()[tupi] = t; + (*dedtypes)[tupi] = t; } nfparams--; // don't consider the last parameter for type deduction goto L2; @@ -2818,8 +2897,8 @@ MATCH TypeIdentifier::deduceType(Scope *sc, Type *tparam, TemplateParameters *pa for (size_t i = 0; i < idents.dim; i++) { - Identifier *id1 = idents.tdata()[i]; - Identifier *id2 = tp->idents.tdata()[i]; + Identifier *id1 = idents[i]; + Identifier *id2 = tp->idents[i]; if (!id1->equals(id2)) return MATCHnomatch; @@ -2857,7 +2936,19 @@ MATCH TypeInstance::deduceType(Scope *sc, { /* Didn't find it as a parameter identifier. Try looking * it up and seeing if is an alias. See Bugzilla 1454 */ - Dsymbol *s = tempinst->tempdecl->scope->search(0, tp->tempinst->name, NULL); + TypeIdentifier *tid = new TypeIdentifier(0, tp->tempinst->name); + Type *t; + Expression *e; + Dsymbol *s; + tid->resolve(0, sc, &e, &t, &s); + if (t) + { + s = t->toDsymbol(sc); + if (s) + { TemplateInstance *ti = s->parent->isTemplateInstance(); + s = ti ? ti->tempdecl : NULL; + } + } if (s) { s = s->toAlias(); @@ -2867,7 +2958,7 @@ MATCH TypeInstance::deduceType(Scope *sc, } goto Lnomatch; } - TemplateParameter *tpx = parameters->tdata()[i]; + TemplateParameter *tpx = (*parameters)[i]; // This logic duplicates tpx->matchArg() TemplateAliasParameter *ta = tpx->isTemplateAliasParameter(); if (!ta) @@ -2877,14 +2968,14 @@ MATCH TypeInstance::deduceType(Scope *sc, goto Lnomatch; if (ta->specAlias && sa != ta->specAlias) goto Lnomatch; - if (dedtypes->tdata()[i]) + if ((*dedtypes)[i]) { // Must match already deduced symbol - Object *s = dedtypes->tdata()[i]; + Object *s = (*dedtypes)[i]; if (s != sa) goto Lnomatch; } - dedtypes->tdata()[i] = sa; + (*dedtypes)[i] = sa; } } else if (tempinst->tempdecl != tp->tempinst->tempdecl) @@ -2895,22 +2986,66 @@ MATCH TypeInstance::deduceType(Scope *sc, for (size_t i = 0; 1; i++) { //printf("\ttest: tempinst->tiargs[%d]\n", i); - Object *o1; + Object *o1 = NULL; if (i < tempinst->tiargs->dim) - o1 = tempinst->tiargs->tdata()[i]; + o1 = (*tempinst->tiargs)[i]; else if (i < tempinst->tdtypes.dim && i < tp->tempinst->tiargs->dim) // Pick up default arg - o1 = tempinst->tdtypes.tdata()[i]; - else + o1 = tempinst->tdtypes[i]; + else if (i >= tp->tempinst->tiargs->dim) break; if (i >= tp->tempinst->tiargs->dim) goto Lnomatch; - Object *o2 = tp->tempinst->tiargs->tdata()[i]; + Object *o2 = (*tp->tempinst->tiargs)[i]; + Type *t2 = isType(o2); + + int j; + if (t2 && + t2->ty == Tident && + i == tp->tempinst->tiargs->dim - 1 && + (j = templateParameterLookup(t2, parameters), j != -1) && + j == parameters->dim - 1 && + (*parameters)[j]->isTemplateTupleParameter()) + { + /* Given: + * struct A(B...) {} + * alias A!(int, float) X; + * static if (is(X Y == A!(Z), Z...)) {} + * deduce that Z is a tuple(int, float) + */ + + /* Create tuple from remaining args + */ + Tuple *vt = new Tuple(); + size_t vtdim = (tempinst->tempdecl->isVariadic() + ? tempinst->tiargs->dim : tempinst->tdtypes.dim) - i; + vt->objects.setDim(vtdim); + for (size_t k = 0; k < vtdim; k++) + { + Object *o; + if (k < tempinst->tiargs->dim) + o = (*tempinst->tiargs)[i + k]; + else // Pick up default arg + o = tempinst->tdtypes[i + k]; + vt->objects[k] = o; + } + + Tuple *v = (Tuple *)(*dedtypes)[j]; + if (v) + { + if (!match(v, vt, tempinst->tempdecl, sc)) + goto Lnomatch; + } + else + (*dedtypes)[j] = vt; + break; //return MATCHexact; + } + else if (!o1) + break; Type *t1 = isType(o1); - Type *t2 = isType(o2); Expression *e1 = isExpression(o1); Expression *e2 = isExpression(o2); @@ -2931,44 +3066,6 @@ MATCH TypeInstance::deduceType(Scope *sc, if (v2) printf("v2 = %s\n", v2->toChars()); #endif - TemplateTupleParameter *ttp; - int j; - if (t2 && - t2->ty == Tident && - i == tp->tempinst->tiargs->dim - 1 && - i == tempinst->tempdecl->parameters->dim - 1 && - (ttp = tempinst->tempdecl->isVariadic()) != NULL) - { - /* Given: - * struct A(B...) {} - * alias A!(int, float) X; - * static if (!is(X Y == A!(Z), Z)) - * deduce that Z is a tuple(int, float) - */ - - j = templateParameterLookup(t2, parameters); - if (j == -1) - goto Lnomatch; - - /* Create tuple from remaining args - */ - Tuple *vt = new Tuple(); - size_t vtdim = tempinst->tiargs->dim - i; - vt->objects.setDim(vtdim); - for (size_t k = 0; k < vtdim; k++) - vt->objects.tdata()[k] = tempinst->tiargs->tdata()[i + k]; - - Tuple *v = (Tuple *)dedtypes->tdata()[j]; - if (v) - { - if (!match(v, vt, tempinst->tempdecl, sc)) - goto Lnomatch; - } - else - dedtypes->tdata()[j] = vt; - break; //return MATCHexact; - } - if (t1 && t2) { if (!t1->deduceType(sc, t2, parameters, dedtypes, wildmatch)) @@ -2976,6 +3073,12 @@ MATCH TypeInstance::deduceType(Scope *sc, } else if (e1 && e2) { + Le: + e1 = e1->ctfeInterpret(); + e2 = e2->ctfeInterpret(); + + //printf("e1 = %s, type = %s %d\n", e1->toChars(), e1->type->toChars(), e1->type->ty); + //printf("e2 = %s, type = %s %d\n", e2->toChars(), e2->type->toChars(), e2->type->ty); if (!e1->equals(e2)) { if (e2->op == TOKvar) { @@ -2985,7 +3088,13 @@ MATCH TypeInstance::deduceType(Scope *sc, j = templateIdentifierLookup(((VarExp *)e2)->var->ident, parameters); goto L1; } - goto Lnomatch; + if (!e2->implicitConvTo(e1->type)) + goto Lnomatch; + + e2 = e2->implicitCastTo(sc, e1->type); + e2 = e2->ctfeInterpret(); + if (!e1->equals(e2)) + goto Lnomatch; } } else if (e1 && t2 && t2->ty == Tident) @@ -2993,13 +3102,18 @@ MATCH TypeInstance::deduceType(Scope *sc, j = templateParameterLookup(t2, parameters); L1: if (j == -1) + { + t2->resolve(loc, sc, &e2, &t2, &s2); + if (e2) + goto Le; goto Lnomatch; - TemplateParameter *tp = parameters->tdata()[j]; + } + TemplateParameter *tp = (*parameters)[j]; // BUG: use tp->matchArg() instead of the following TemplateValueParameter *tv = tp->isTemplateValueParameter(); if (!tv) goto Lnomatch; - Expression *e = (Expression *)dedtypes->tdata()[j]; + Expression *e = (Expression *)(*dedtypes)[j]; if (e) { if (!e1->equals(e)) @@ -3010,20 +3124,31 @@ MATCH TypeInstance::deduceType(Scope *sc, MATCH m = (MATCH)e1->implicitConvTo(vt); if (!m) goto Lnomatch; - dedtypes->tdata()[j] = e1; + (*dedtypes)[j] = e1; } } + else if (s1 && s2) + { + Ls: + if (!s1->equals(s2)) + goto Lnomatch; + } else if (s1 && t2 && t2->ty == Tident) { j = templateParameterLookup(t2, parameters); if (j == -1) + { + t2->resolve(loc, sc, &e2, &t2, &s2); + if (s2) + goto Ls; goto Lnomatch; - TemplateParameter *tp = parameters->tdata()[j]; + } + TemplateParameter *tp = (*parameters)[j]; // BUG: use tp->matchArg() instead of the following TemplateAliasParameter *ta = tp->isTemplateAliasParameter(); if (!ta) goto Lnomatch; - Dsymbol *s = (Dsymbol *)dedtypes->tdata()[j]; + Dsymbol *s = (Dsymbol *)(*dedtypes)[j]; if (s) { if (!s1->equals(s)) @@ -3031,15 +3156,9 @@ MATCH TypeInstance::deduceType(Scope *sc, } else { - dedtypes->tdata()[j] = s1; + (*dedtypes)[j] = s1; } } - else if (s1 && s2) - { - if (!s1->equals(s2)) - goto Lnomatch; - } - // BUG: Need to handle tuple parameters else goto Lnomatch; } @@ -3076,7 +3195,7 @@ MATCH TypeStruct::deduceType(Scope *sc, Type *tparam, TemplateParameters *parame */ TypeInstance *tpi = (TypeInstance *)tparam; if (tpi->idents.dim) - { Identifier *id = tpi->idents.tdata()[tpi->idents.dim - 1]; + { Identifier *id = tpi->idents[tpi->idents.dim - 1]; if (id->dyncast() == DYNCAST_IDENTIFIER && sym->ident->equals(id)) { Type *tparent = sym->parent->getType(); @@ -3171,8 +3290,8 @@ void deduceBaseClassParameters(BaseClass *b, { // If we've found more than one possible type for a parameter, // mark it as unknown. - if (tmpdedtypes->tdata()[k] != best->tdata()[k]) - best->tdata()[k] = dedtypes->tdata()[k]; + if ((*tmpdedtypes)[k] != (*best)[k]) + (*best)[k] = (*dedtypes)[k]; } ++numBaseClassMatches; } @@ -3214,7 +3333,7 @@ MATCH TypeClass::deduceType(Scope *sc, Type *tparam, TemplateParameters *paramet */ TypeInstance *tpi = (TypeInstance *)tparam; if (tpi->idents.dim) - { Identifier *id = tpi->idents.tdata()[tpi->idents.dim - 1]; + { Identifier *id = tpi->idents[tpi->idents.dim - 1]; if (id->dyncast() == DYNCAST_IDENTIFIER && sym->ident->equals(id)) { Type *tparent = sym->parent->getType(); @@ -3250,7 +3369,7 @@ MATCH TypeClass::deduceType(Scope *sc, Type *tparam, TemplateParameters *paramet while(s && s->baseclasses->dim > 0) { // Test the base class - deduceBaseClassParameters((s->baseclasses->tdata()[0]), + deduceBaseClassParameters((*s->baseclasses)[0], sc, tparam, parameters, dedtypes, best, numBaseClassMatches); @@ -3261,7 +3380,7 @@ MATCH TypeClass::deduceType(Scope *sc, Type *tparam, TemplateParameters *paramet deduceBaseClassParameters(b, sc, tparam, parameters, dedtypes, best, numBaseClassMatches); } - s = ((s->baseclasses->tdata()[0]))->base; + s = (*s->baseclasses)[0]->base; } if (numBaseClassMatches == 0) @@ -3420,14 +3539,14 @@ MATCH TemplateTypeParameter::matchArg(Scope *sc, Objects *tiargs, Type *ta; if (i < tiargs->dim) - oarg = tiargs->tdata()[i]; + oarg = (*tiargs)[i]; else { // Get default argument instead oarg = defaultArg(loc, sc); if (!oarg) { assert(i < dedtypes->dim); // It might have already been deduced - oarg = dedtypes->tdata()[i]; + oarg = (*dedtypes)[i]; if (!oarg) { goto Lnomatch; @@ -3457,14 +3576,14 @@ MATCH TemplateTypeParameter::matchArg(Scope *sc, Objects *tiargs, if (m2 < m) m = m2; - if (dedtypes->tdata()[i]) - ta = (Type *)dedtypes->tdata()[i]; + if ((*dedtypes)[i]) + ta = (Type *)(*dedtypes)[i]; } else { - if (dedtypes->tdata()[i]) + if ((*dedtypes)[i]) { // Must match already deduced type - Type *t = (Type *)dedtypes->tdata()[i]; + Type *t = (Type *)(*dedtypes)[i]; if (!t->equals(ta)) { //printf("t = %s ta = %s\n", t->toChars(), ta->toChars()); @@ -3477,7 +3596,7 @@ MATCH TemplateTypeParameter::matchArg(Scope *sc, Objects *tiargs, m = MATCHconvert; } } - dedtypes->tdata()[i] = ta; + (*dedtypes)[i] = ta; *psparam = new AliasDeclaration(loc, ident, ta); //printf("\tm = %d\n", m); @@ -3647,7 +3766,7 @@ Object *aliasParameterSemantic(Loc loc, Scope *sc, Object *o) else if (ea) { ea = ea->semantic(sc); - o = ea->optimize(WANTvalue | WANTinterpret); + o = ea->ctfeInterpret(); } } return o; @@ -3694,20 +3813,25 @@ MATCH TemplateAliasParameter::matchArg(Scope *sc, Objects *tiargs, //printf("TemplateAliasParameter::matchArg()\n"); if (i < tiargs->dim) - oarg = tiargs->tdata()[i]; + oarg = (*tiargs)[i]; else { // Get default argument instead oarg = defaultArg(loc, sc); if (!oarg) { assert(i < dedtypes->dim); // It might have already been deduced - oarg = dedtypes->tdata()[i]; + oarg = (*dedtypes)[i]; if (!oarg) goto Lnomatch; } } sa = getDsymbol(oarg); + ea = isExpression(oarg); + if (ea && (ea->op == TOKthis || ea->op == TOKsuper)) + sa = ((ThisExp *)ea)->var; + else if (ea && ea->op == TOKimport) + sa = ((ScopeExp *)ea)->sds; if (sa) { /* specType means the alias must be a declaration with a type @@ -3724,7 +3848,6 @@ MATCH TemplateAliasParameter::matchArg(Scope *sc, Objects *tiargs, else { sa = oarg; - ea = isExpression(oarg); if (ea) { if (specType) { @@ -3740,17 +3863,26 @@ MATCH TemplateAliasParameter::matchArg(Scope *sc, Objects *tiargs, { if (sa == sdummy) goto Lnomatch; - if (sa != specAlias) - goto Lnomatch; + if (sa != specAlias && isDsymbol(sa)) + { + TemplateInstance *ti = isDsymbol(sa)->isTemplateInstance(); + Type *ta = isType(specAlias); + if (!ti || !ta) + goto Lnomatch; + Type *t = new TypeInstance(0, ti); + MATCH m = t->deduceType(sc, ta, parameters, dedtypes); + if (m == MATCHnomatch) + goto Lnomatch; + } } - else if (dedtypes->tdata()[i]) + else if ((*dedtypes)[i]) { // Must match already deduced symbol - Object *si = dedtypes->tdata()[i]; + Object *si = (*dedtypes)[i]; if (!sa || si != sa) goto Lnomatch; } - dedtypes->tdata()[i] = sa; + (*dedtypes)[i] = sa; s = isDsymbol(sa); if (s) @@ -3912,7 +4044,7 @@ void TemplateValueParameter::semantic(Scope *sc) e = e->semantic(sc); e = e->implicitCastTo(sc, valType); - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); if (e->op == TOKint64 || e->op == TOKfloat64 || e->op == TOKcomplex80 || e->op == TOKnull || e->op == TOKstring) specValue = e; @@ -3924,7 +4056,7 @@ void TemplateValueParameter::semantic(Scope *sc) e = e->semantic(sc); e = e->implicitCastTo(sc, valType); - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); if (e->op == TOKint64) defaultValue = e; //e->toInteger(); @@ -3968,14 +4100,14 @@ MATCH TemplateValueParameter::matchArg(Scope *sc, Object *oarg; if (i < tiargs->dim) - oarg = tiargs->tdata()[i]; + oarg = (*tiargs)[i]; else { // Get default argument instead oarg = defaultArg(loc, sc); if (!oarg) { assert(i < dedtypes->dim); // It might have already been deduced - oarg = dedtypes->tdata()[i]; + oarg = (*dedtypes)[i]; if (!oarg) goto Lnomatch; } @@ -3989,7 +4121,7 @@ MATCH TemplateValueParameter::matchArg(Scope *sc, if (ei && ei->op == TOKvar) { // Resolve const variables that we had skipped earlier - ei = ei->optimize(WANTvalue | WANTinterpret); + ei = ei->ctfeInterpret(); } //printf("\tvalType: %s, ty = %d\n", valType->toChars(), valType->ty); @@ -4014,12 +4146,12 @@ MATCH TemplateValueParameter::matchArg(Scope *sc, e = e->semantic(sc); e = e->implicitCastTo(sc, vt); - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); ei = ei->syntaxCopy(); ei = ei->semantic(sc); ei = ei->implicitCastTo(sc, vt); - ei = ei->optimize(WANTvalue | WANTinterpret); + ei = ei->ctfeInterpret(); //printf("\tei: %s, %s\n", ei->toChars(), ei->type->toChars()); //printf("\te : %s, %s\n", e->toChars(), e->type->toChars()); if (!ei->equals(e)) @@ -4027,9 +4159,9 @@ MATCH TemplateValueParameter::matchArg(Scope *sc, } else { - if (dedtypes->tdata()[i]) + if ((*dedtypes)[i]) { // Must match already deduced value - Expression *e = (Expression *)dedtypes->tdata()[i]; + Expression *e = (Expression *)(*dedtypes)[i]; if (!ei || !ei->equals(e)) goto Lnomatch; @@ -4037,10 +4169,10 @@ MATCH TemplateValueParameter::matchArg(Scope *sc, else if (m != MATCHexact) { ei = ei->implicitCastTo(sc, vt); - ei = ei->optimize(WANTvalue | WANTinterpret); + ei = ei->ctfeInterpret(); } } - dedtypes->tdata()[i] = ei; + (*dedtypes)[i] = ei; init = new ExpInitializer(loc, ei); sparam = new VarDeclaration(loc, vt, ident, init); @@ -4176,11 +4308,11 @@ MATCH TemplateTupleParameter::matchArg(Scope *sc, Objects *tiargs, assert(i + 1 == dedtypes->dim); // must be the last one Tuple *ovar; - if (dedtypes->tdata()[i] && isTuple(dedtypes->tdata()[i])) + if ((*dedtypes)[i] && isTuple((*dedtypes)[i])) // It was already been deduced - ovar = isTuple(dedtypes->tdata()[i]); - else if (i + 1 == tiargs->dim && isTuple(tiargs->tdata()[i])) - ovar = isTuple(tiargs->tdata()[i]); + ovar = isTuple((*dedtypes)[i]); + else if (i + 1 == tiargs->dim && isTuple((*tiargs)[i])) + ovar = isTuple((*tiargs)[i]); else { ovar = new Tuple(); @@ -4190,11 +4322,11 @@ MATCH TemplateTupleParameter::matchArg(Scope *sc, Objects *tiargs, //printf("i = %d, tiargs->dim = %d\n", i, tiargs->dim); ovar->objects.setDim(tiargs->dim - i); for (size_t j = 0; j < ovar->objects.dim; j++) - ovar->objects.tdata()[j] = tiargs->tdata()[i + j]; + ovar->objects[j] = (*tiargs)[i + j]; } } *psparam = new TupleDeclaration(loc, ident, &ovar->objects); - dedtypes->tdata()[i] = ovar; + (*dedtypes)[i] = ovar; return MATCHexact; } @@ -4211,7 +4343,7 @@ void TemplateTupleParameter::print(Object *oarg, Object *oded) if (i) printf(", "); - Object *o = v->objects.tdata()[i]; + Object *o = v->objects[i]; Dsymbol *sa = isDsymbol(o); if (sa) @@ -4332,7 +4464,7 @@ Objects *TemplateInstance::arraySyntaxCopy(Objects *objs) a->setDim(objs->dim); for (size_t i = 0; i < objs->dim; i++) { - a->tdata()[i] = objectSyntaxCopy(objs->tdata()[i]); + (*a)[i] = objectSyntaxCopy((*objs)[i]); } } return a; @@ -4367,7 +4499,7 @@ void TemplateInstance::expandMembers(Scope *sc2) } for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = members->tdata()[i]; + Dsymbol *s = (*members)[i]; //printf("\t[%d] semantic on '%s' %p kind %s in '%s'\n", i, s->toChars(), s, s->kind(), this->toChars()); //printf("test: isnested = %d, sc2->parent = %s\n", isnested, sc2->parent->toChars()); // if (isnested) @@ -4506,21 +4638,34 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) } else { - /* Run semantic on each argument, place results in tiargs[] - * (if we havetempdecl, then tiargs is already evaluated) + /* Find template declaration first. */ - semanticTiargs(sc); - if (arrayObjectIsError(tiargs)) - { inst = this; + tempdecl = findTemplateDeclaration(sc); + if (!tempdecl) + { if (!sc->parameterSpecialization) + inst = this; //printf("error return %p, %d\n", tempdecl, global.errors); return; // error recovery } + + /* Run semantic on each argument, place results in tiargs[] + * (if we have tempdecl, then tiargs is already evaluated) + */ + semanticTiargs(sc); + if (arrayObjectIsError(tiargs)) + { if (!sc->parameterSpecialization) + inst = this; + //printf("error return %p, %d\n", tempdecl, global.errors); + if (inst) + ++inst->errors; + return; // error recovery + } + unsigned errs = global.errors; - tempdecl = findTemplateDeclaration(sc); - if (tempdecl) - tempdecl = findBestMatch(sc, fargs); + tempdecl = findBestMatch(sc, fargs); if (!tempdecl || (errs != global.errors)) - { inst = this; + { if (!sc->parameterSpecialization) + inst = this; //printf("error return %p, %d\n", tempdecl, global.errors); return; // error recovery } @@ -4538,7 +4683,7 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) for (size_t i = 0; i < tempdecl->instances.dim; i++) { - TemplateInstance *ti = tempdecl->instances.tdata()[i]; + TemplateInstance *ti = tempdecl->instances[i]; #if LOG printf("\t%s: checking for match with instance %d (%p): '%s'\n", toChars(), i, ti, ti->toChars()); #endif @@ -4567,7 +4712,7 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) size_t nfparams = Parameter::dim(fparameters); // Num function parameters for (size_t j = 0; j < nfparams && j < fargs->dim; j++) { Parameter *fparam = Parameter::getNth(fparameters, j); - Expression *farg = fargs->tdata()[j]; + Expression *farg = (*fargs)[j]; if (fparam->storageClass & STCauto) // if "auto ref" { if (farg->isLvalue()) @@ -4695,7 +4840,7 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) a->push(this); break; } - if (this == a->tdata()[i]) // if already in Array + if (this == (*a)[i]) // if already in Array break; } } @@ -4732,7 +4877,7 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) int memnum = 0; for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = members->tdata()[i]; + Dsymbol *s = (*members)[i]; #if LOG printf("\t[%d] adding member '%s' %p kind %s to '%s', memnum = %d\n", i, s->toChars(), s, s->kind(), this->toChars(), memnum); #endif @@ -4805,7 +4950,7 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) * or semantic3() yet. */ for (size_t i = 0; i < Module::deferred.dim; i++) - { Dsymbol *sd = Module::deferred.tdata()[i]; + { Dsymbol *sd = Module::deferred[i]; if (sd->parent == this) { @@ -4879,7 +5024,7 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) { // Because we added 'this' in the last position above, we // should be able to remove it without messing other indices up. - assert(target_symbol_list->tdata()[target_symbol_list_idx] == this); + assert((*target_symbol_list)[target_symbol_list_idx] == this); target_symbol_list->remove(target_symbol_list_idx); } semanticRun = PASSinit; @@ -4915,12 +5060,12 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f return; for (size_t j = 0; j < tiargs->dim; j++) { - Object *o = tiargs->tdata()[j]; + Object *o = (*tiargs)[j]; Type *ta = isType(o); Expression *ea = isExpression(o); Dsymbol *sa = isDsymbol(o); - //printf("1: tiargs->tdata()[%d] = %p, %p, %p, ea=%p, ta=%p\n", j, o, isDsymbol(o), isTuple(o), ea, ta); + //printf("1: (*tiargs)[%d] = %p, %p, %p, ea=%p, ta=%p\n", j, o, isDsymbol(o), isTuple(o), ea, ta); if (ta) { //printf("type %s\n", ta->toChars()); @@ -4937,13 +5082,13 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f if (flags & 1) // only used by __traits, must not interpret the args ea = ea->optimize(WANTvalue); else if (ea->op != TOKvar) - ea = ea->optimize(WANTvalue | WANTinterpret); - tiargs->tdata()[j] = ea; + ea = ea->ctfeInterpret(); + (*tiargs)[j] = ea; } else if (sa) { Ldsym: - tiargs->tdata()[j] = sa; + (*tiargs)[j] = sa; TupleDeclaration *d = sa->toAlias()->isTupleDeclaration(); if (d) { @@ -4964,19 +5109,19 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f if (dim) { tiargs->reserve(dim); for (size_t i = 0; i < dim; i++) - { Parameter *arg = tt->arguments->tdata()[i]; + { Parameter *arg = (*tt->arguments)[i]; tiargs->insert(j + i, arg->type); } } j--; } else - tiargs->tdata()[j] = ta; + (*tiargs)[j] = ta; } else { assert(global.errors); - tiargs->tdata()[j] = Type::terror; + (*tiargs)[j] = Type::terror; } } else if (ea) @@ -4989,9 +5134,12 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f ea = ea->semantic(sc); if (flags & 1) // only used by __traits, must not interpret the args ea = ea->optimize(WANTvalue); - else if (ea->op != TOKvar && ea->op != TOKtuple) - ea = ea->optimize(WANTvalue | WANTinterpret); - tiargs->tdata()[j] = ea; + else if (ea->op != TOKvar && ea->op != TOKtuple && + ea->op != TOKimport && ea->op != TOKtype && + ea->op != TOKfunction && ea->op != TOKerror && + ea->op != TOKthis && ea->op != TOKsuper) + ea = ea->ctfeInterpret(); + (*tiargs)[j] = ea; if (ea->op == TOKtype) { ta = ea->type; goto Ltype; @@ -5000,6 +5148,18 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f { sa = ((ScopeExp *)ea)->sds; goto Ldsym; } + if (ea->op == TOKfunction) + { FuncExp *fe = (FuncExp *)ea; + /* A function literal, that is passed to template and + * already semanticed as function pointer, never requires + * outer frame. So convert it to global function is valid. + */ + if (fe->fd->tok == TOKreserved && fe->type->ty == Tpointer) + { // change to non-nested + fe->fd->tok = TOKfunction; + fe->fd->vthis = NULL; + } + } if (ea->op == TOKtuple) { // Expand tuple TupleExp *te = (TupleExp *)ea; @@ -5008,7 +5168,7 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f if (dim) { tiargs->reserve(dim); for (size_t i = 0; i < dim; i++) - tiargs->insert(j + i, te->exps->tdata()[i]); + tiargs->insert(j + i, (*te->exps)[i]); } j--; } @@ -5023,13 +5183,13 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f { assert(0); } - //printf("1: tiargs->tdata()[%d] = %p\n", j, tiargs->tdata()[j]); + //printf("1: (*tiargs)[%d] = %p\n", j, (*tiargs)[j]); } #if 0 printf("-TemplateInstance::semanticTiargs()\n"); for (size_t j = 0; j < tiargs->dim; j++) { - Object *o = tiargs->tdata()[j]; + Object *o = (*tiargs)[j]; Type *ta = isType(o); Expression *ea = isExpression(o); Dsymbol *sa = isDsymbol(o); @@ -5075,7 +5235,7 @@ TemplateDeclaration *TemplateInstance::findTemplateDeclaration(Scope *sc) if (os) { s = NULL; for (size_t i = 0; i < os->a.dim; i++) - { Dsymbol *s2 = os->a.tdata()[i]; + { Dsymbol *s2 = os->a[i]; if (s2->isTemplateDeclaration()) { if (s) @@ -5199,7 +5359,7 @@ TemplateDeclaration *TemplateInstance::findBestMatch(Scope *sc, Expressions *far { MATCH m; -//if (tiargs->dim) printf("2: tiargs->dim = %d, data[0] = %p\n", tiargs->dim, tiargs->tdata()[0]); +//if (tiargs->dim) printf("2: tiargs->dim = %d, data[0] = %p\n", tiargs->dim, (*tiargs)[0]); // If more arguments than parameters, // then this is no match. @@ -5279,17 +5439,17 @@ TemplateDeclaration *TemplateInstance::findBestMatch(Scope *sc, Expressions *far /* Cast any value arguments to be same type as value parameter */ for (size_t i = 0; i < tiargs->dim; i++) - { Object *o = tiargs->tdata()[i]; + { Object *o = (*tiargs)[i]; Expression *ea = isExpression(o); // value argument - TemplateParameter *tp = tempdecl->parameters->tdata()[i]; + TemplateParameter *tp = (*tempdecl->parameters)[i]; assert(tp); TemplateValueParameter *tvp = tp->isTemplateValueParameter(); if (tvp) { assert(ea); ea = ea->castTo(tvp->valType); - ea = ea->optimize(WANTvalue | WANTinterpret); - tiargs->tdata()[i] = (Object *)ea; + ea = ea->ctfeInterpret(); + (*tiargs)[i] = (Object *)ea; } } #endif @@ -5314,7 +5474,7 @@ int TemplateInstance::hasNestedArgs(Objects *args) * symbol that is on the stack. */ for (size_t i = 0; i < args->dim; i++) - { Object *o = args->tdata()[i]; + { Object *o = (*args)[i]; Expression *ea = isExpression(o); Dsymbol *sa = isDsymbol(o); Tuple *va = isTuple(o); @@ -5332,7 +5492,10 @@ int TemplateInstance::hasNestedArgs(Objects *args) } if (ea->op == TOKfunction) { - sa = ((FuncExp *)ea)->fd; + if (((FuncExp *)ea)->td) + sa = ((FuncExp *)ea)->td; + else + sa = ((FuncExp *)ea)->fd; goto Lsa; } } @@ -5404,7 +5567,7 @@ Identifier *TemplateInstance::genIdent(Objects *args) char *id = tempdecl->ident->toChars(); buf.printf("__T%llu%s", (ulonglong)strlen(id), id); for (size_t i = 0; i < args->dim; i++) - { Object *o = args->tdata()[i]; + { Object *o = (*args)[i]; Type *ta = isType(o); Expression *ea = isExpression(o); Dsymbol *sa = isDsymbol(o); @@ -5442,7 +5605,10 @@ Identifier *TemplateInstance::genIdent(Objects *args) } if (ea->op == TOKfunction) { - sa = ((FuncExp *)ea)->fd; + if (((FuncExp *)ea)->td) + sa = ((FuncExp *)ea)->td; + else + sa = ((FuncExp *)ea)->fd; ea = NULL; goto Lsa; } @@ -5453,7 +5619,7 @@ Identifier *TemplateInstance::genIdent(Objects *args) } // Now that we know it is not an alias, we MUST obtain a value unsigned olderr = global.errors; - ea = ea->optimize(WANTvalue | WANTinterpret); + ea = ea->ctfeInterpret(); if (ea->op == TOKerror || olderr != global.errors) continue; #if 1 @@ -5462,7 +5628,7 @@ Identifier *TemplateInstance::genIdent(Objects *args) buf.writestring(ea->type->deco); #else // Use type of parameter, not type of argument - TemplateParameter *tp = tempdecl->parameters->tdata()[i]; + TemplateParameter *tp = (*tempdecl->parameters)[i]; assert(tp); TemplateValueParameter *tvp = tp->isTemplateValueParameter(); assert(tvp); @@ -5528,9 +5694,9 @@ void TemplateInstance::declareParameters(Scope *sc) //printf("TemplateInstance::declareParameters()\n"); for (size_t i = 0; i < tdtypes.dim; i++) { - TemplateParameter *tp = tempdecl->parameters->tdata()[i]; - //Object *o = tiargs->tdata()[i]; - Object *o = tdtypes.tdata()[i]; // initializer for tp + TemplateParameter *tp = (*tempdecl->parameters)[i]; + //Object *o = (*tiargs)[i]; + Object *o = tdtypes[i]; // initializer for tp //printf("\ttdtypes[%d] = %p\n", i, o); tempdecl->declareParameter(sc, tp, o); @@ -5566,7 +5732,7 @@ int TemplateInstance::needsTypeInference(Scope *sc) } for (size_t i = 0; i < td->parameters->dim; i++) - if (td->parameters->tdata()[i]->isTemplateThisParameter()) + if ((*td->parameters)[i]->isTemplateThisParameter()) return TRUE; /* Determine if the instance arguments, tiargs, are all that is necessary @@ -5627,7 +5793,7 @@ void TemplateInstance::semantic2(Scope *sc) sc->tinst = this; for (i = 0; i < members->dim; i++) { - Dsymbol *s = members->tdata()[i]; + Dsymbol *s = (*members)[i]; #if LOG printf("\tmember '%s', kind = '%s'\n", s->toChars(), s->kind()); #endif @@ -5669,7 +5835,7 @@ void TemplateInstance::semantic3(Scope *sc) olderrors = global.startGagging(); for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = members->tdata()[i]; + Dsymbol *s = (*members)[i]; s->semantic3(sc); if (speculative && global.errors != olderrors) break; @@ -5777,7 +5943,7 @@ void TemplateInstance::toObjFile(int multiobj) { for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = members->tdata()[i]; + Dsymbol *s = (*members)[i]; s->toObjFile(multiobj); } } @@ -5795,7 +5961,7 @@ void TemplateInstance::inlineScan() { for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = members->tdata()[i]; + Dsymbol *s = (*members)[i]; s->inlineScan(); } } @@ -5937,7 +6103,7 @@ void TemplateInstance::printInstantiationTrace() TemplateMixin::TemplateMixin(Loc loc, Identifier *ident, Type *tqual, Identifiers *idents, Objects *tiargs) - : TemplateInstance(loc, idents->tdata()[idents->dim - 1]) + : TemplateInstance(loc, (*idents)[idents->dim - 1]) { //printf("TemplateMixin(ident = '%s')\n", ident ? ident->toChars() : ""); this->ident = ident; @@ -5953,7 +6119,7 @@ Dsymbol *TemplateMixin::syntaxCopy(Dsymbol *s) ids->setDim(idents->dim); for (size_t i = 0; i < idents->dim; i++) { // Matches TypeQualified::syntaxCopyHelper() - Identifier *id = idents->tdata()[i]; + Identifier *id = (*idents)[i]; if (id->dyncast() == DYNCAST_DSYMBOL) { TemplateInstance *ti = (TemplateInstance *)id; @@ -5961,7 +6127,7 @@ Dsymbol *TemplateMixin::syntaxCopy(Dsymbol *s) ti = (TemplateInstance *)ti->syntaxCopy(NULL); id = (Identifier *)ti; } - ids->tdata()[i] = id; + (*ids)[i] = id; } tm = new TemplateMixin(loc, ident, @@ -6022,7 +6188,7 @@ void TemplateMixin::semantic(Scope *sc) else { i = 1; - id = idents->tdata()[0]; + id = (*idents)[0]; switch (id->dyncast()) { case DYNCAST_IDENTIFIER: @@ -6045,7 +6211,7 @@ void TemplateMixin::semantic(Scope *sc) { if (!s) break; - id = idents->tdata()[i]; + id = (*idents)[i]; s = s->searchX(loc, sc, id); } if (!s) @@ -6301,7 +6467,7 @@ void TemplateMixin::semantic3(Scope *sc) sc = sc->push(this); for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = members->tdata()[i]; + Dsymbol *s = (*members)[i]; s->semantic3(sc); } sc = sc->pop(); @@ -6359,10 +6525,14 @@ int TemplateMixin::hasPointers() void TemplateMixin::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion) { + //printf("TemplateMixin::setFieldOffset() %s\n", toChars()); + if (scope) // if fwd reference + semantic(NULL); // try to resolve it if (members) { for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (*members)[i]; + //printf("\t%s\n", s->toChars()); s->setFieldOffset(ad, poffset, isunion); } } @@ -6385,7 +6555,7 @@ void TemplateMixin::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writestring("mixin "); for (size_t i = 0; i < idents->dim; i++) - { Identifier *id = idents->tdata()[i]; + { Identifier *id = (*idents)[i]; if (i) buf->writeByte('.'); @@ -6397,7 +6567,7 @@ void TemplateMixin::toCBuffer(OutBuffer *buf, HdrGenState *hgs) for (size_t i = 0; i < tiargs->dim; i++) { if (i) buf->writebyte(','); - Object *oarg = tiargs->tdata()[i]; + Object *oarg = (*tiargs)[i]; Type *t = isType(oarg); Expression *e = isExpression(oarg); Dsymbol *s = isDsymbol(oarg); diff --git a/dmd2/traits.c b/dmd2/traits.c index 68f7b2a1..7a678920 100644 --- a/dmd2/traits.c +++ b/dmd2/traits.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -89,7 +89,7 @@ Expression *TraitsExp::semantic(Scope *sc) #define ISTYPE(cond) \ for (size_t i = 0; i < dim; i++) \ - { Type *t = getType(args->tdata()[i]); \ + { Type *t = getType((*args)[i]); \ if (!t) \ goto Lfalse; \ if (!(cond)) \ @@ -101,7 +101,7 @@ Expression *TraitsExp::semantic(Scope *sc) #define ISDSYMBOL(cond) \ for (size_t i = 0; i < dim; i++) \ - { Dsymbol *s = getDsymbol(args->tdata()[i]); \ + { Dsymbol *s = getDsymbol((*args)[i]); \ if (!s) \ goto Lfalse; \ if (!(cond)) \ @@ -196,7 +196,7 @@ Expression *TraitsExp::semantic(Scope *sc) if (dim != 1) goto Ldimerror; - Object *o = args->tdata()[0]; + Object *o = (*args)[0]; Dsymbol *s = getDsymbol(o); if (!s || !s->ident) { @@ -210,7 +210,7 @@ Expression *TraitsExp::semantic(Scope *sc) { if (dim != 1) goto Ldimerror; - Object *o = args->tdata()[0]; + Object *o = (*args)[0]; Dsymbol *s = getDsymbol(o); if (s) s = s->toParent(); @@ -231,13 +231,13 @@ Expression *TraitsExp::semantic(Scope *sc) { if (dim != 2) goto Ldimerror; - Object *o = args->tdata()[0]; - Expression *e = isExpression(args->tdata()[1]); + Object *o = (*args)[0]; + Expression *e = isExpression((*args)[1]); if (!e) { error("expression expected as second argument of __traits %s", ident->toChars()); goto Lfalse; } - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); StringExp *se = e->toString(); if (!se || se->length() == 0) { error("string expected as second argument of __traits %s instead of %s", ident->toChars(), e->toChars()); @@ -336,7 +336,7 @@ Expression *TraitsExp::semantic(Scope *sc) { if (dim != 1) goto Ldimerror; - Object *o = args->tdata()[0]; + Object *o = (*args)[0]; Dsymbol *s = getDsymbol(o); ClassDeclaration *cd; if (!s || (cd = s->isClassDeclaration()) == NULL) @@ -350,7 +350,7 @@ Expression *TraitsExp::semantic(Scope *sc) { if (dim != 1) goto Ldimerror; - Object *o = args->tdata()[0]; + Object *o = (*args)[0]; Dsymbol *s = getDsymbol(o); ScopeDsymbol *sd; if (!s) @@ -380,7 +380,7 @@ Expression *TraitsExp::semantic(Scope *sc) /* Skip if already present in idents[] */ for (size_t j = 0; j < idents->dim; j++) - { Identifier *id = idents->tdata()[j]; + { Identifier *id = (*idents)[j]; if (id == sm->ident) return 0; #ifdef DEBUG @@ -421,9 +421,9 @@ Expression *TraitsExp::semantic(Scope *sc) assert(sizeof(Expressions) == sizeof(Identifiers)); Expressions *exps = (Expressions *)idents; for (size_t i = 0; i < idents->dim; i++) - { Identifier *id = idents->tdata()[i]; + { Identifier *id = (*idents)[i]; StringExp *se = new StringExp(loc, id->toChars()); - exps->tdata()[i] = se; + (*exps)[i] = se; } #if DMDV1 @@ -448,7 +448,7 @@ Expression *TraitsExp::semantic(Scope *sc) goto Lfalse; for (size_t i = 0; i < dim; i++) - { Object *o = args->tdata()[i]; + { Object *o = (*args)[i]; Expression *e; unsigned errors = global.startGagging(); @@ -491,8 +491,8 @@ Expression *TraitsExp::semantic(Scope *sc) if (dim != 2) goto Ldimerror; TemplateInstance::semanticTiargs(loc, sc, args, 0); - Object *o1 = args->tdata()[0]; - Object *o2 = args->tdata()[1]; + Object *o1 = (*args)[0]; + Object *o2 = (*args)[1]; Dsymbol *s1 = getDsymbol(o1); Dsymbol *s2 = getDsymbol(o2); diff --git a/dmd2/unialpha.c b/dmd2/unialpha.c deleted file mode 100644 index 5c407180..00000000 --- a/dmd2/unialpha.c +++ /dev/null @@ -1,323 +0,0 @@ - -// Copyright (c) 2003 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include - -/******************************* - * Return !=0 if unicode alpha. - * Use table from C99 Appendix D. - */ - -int isUniAlpha(unsigned u) -{ - static unsigned short table[][2] = - { - { 0x00AA, 0x00AA }, - { 0x00B5, 0x00B5 }, - { 0x00B7, 0x00B7 }, - { 0x00BA, 0x00BA }, - { 0x00C0, 0x00D6 }, - { 0x00D8, 0x00F6 }, - { 0x00F8, 0x01F5 }, - { 0x01FA, 0x0217 }, - { 0x0250, 0x02A8 }, - { 0x02B0, 0x02B8 }, - { 0x02BB, 0x02BB }, - { 0x02BD, 0x02C1 }, - { 0x02D0, 0x02D1 }, - { 0x02E0, 0x02E4 }, - { 0x037A, 0x037A }, - { 0x0386, 0x0386 }, - { 0x0388, 0x038A }, - { 0x038C, 0x038C }, - { 0x038E, 0x03A1 }, - { 0x03A3, 0x03CE }, - { 0x03D0, 0x03D6 }, - { 0x03DA, 0x03DA }, - { 0x03DC, 0x03DC }, - { 0x03DE, 0x03DE }, - { 0x03E0, 0x03E0 }, - { 0x03E2, 0x03F3 }, - { 0x0401, 0x040C }, - { 0x040E, 0x044F }, - { 0x0451, 0x045C }, - { 0x045E, 0x0481 }, - { 0x0490, 0x04C4 }, - { 0x04C7, 0x04C8 }, - { 0x04CB, 0x04CC }, - { 0x04D0, 0x04EB }, - { 0x04EE, 0x04F5 }, - { 0x04F8, 0x04F9 }, - { 0x0531, 0x0556 }, - { 0x0559, 0x0559 }, - { 0x0561, 0x0587 }, - { 0x05B0, 0x05B9 }, - { 0x05BB, 0x05BD }, - { 0x05BF, 0x05BF }, - { 0x05C1, 0x05C2 }, - { 0x05D0, 0x05EA }, - { 0x05F0, 0x05F2 }, - { 0x0621, 0x063A }, - { 0x0640, 0x0652 }, - { 0x0660, 0x0669 }, - { 0x0670, 0x06B7 }, - { 0x06BA, 0x06BE }, - { 0x06C0, 0x06CE }, - { 0x06D0, 0x06DC }, - { 0x06E5, 0x06E8 }, - { 0x06EA, 0x06ED }, - { 0x06F0, 0x06F9 }, - { 0x0901, 0x0903 }, - { 0x0905, 0x0939 }, - { 0x093D, 0x093D }, - { 0x093E, 0x094D }, - { 0x0950, 0x0952 }, - { 0x0958, 0x0963 }, - { 0x0966, 0x096F }, - { 0x0981, 0x0983 }, - { 0x0985, 0x098C }, - { 0x098F, 0x0990 }, - { 0x0993, 0x09A8 }, - { 0x09AA, 0x09B0 }, - { 0x09B2, 0x09B2 }, - { 0x09B6, 0x09B9 }, - { 0x09BE, 0x09C4 }, - { 0x09C7, 0x09C8 }, - { 0x09CB, 0x09CD }, - { 0x09DC, 0x09DD }, - { 0x09DF, 0x09E3 }, - { 0x09E6, 0x09EF }, - { 0x09F0, 0x09F1 }, - { 0x0A02, 0x0A02 }, - { 0x0A05, 0x0A0A }, - { 0x0A0F, 0x0A10 }, - { 0x0A13, 0x0A28 }, - { 0x0A2A, 0x0A30 }, - { 0x0A32, 0x0A33 }, - { 0x0A35, 0x0A36 }, - { 0x0A38, 0x0A39 }, - { 0x0A3E, 0x0A42 }, - { 0x0A47, 0x0A48 }, - { 0x0A4B, 0x0A4D }, - { 0x0A59, 0x0A5C }, - { 0x0A5E, 0x0A5E }, - { 0x0A66, 0x0A6F }, - { 0x0A74, 0x0A74 }, - { 0x0A81, 0x0A83 }, - { 0x0A85, 0x0A8B }, - { 0x0A8D, 0x0A8D }, - { 0x0A8F, 0x0A91 }, - { 0x0A93, 0x0AA8 }, - { 0x0AAA, 0x0AB0 }, - { 0x0AB2, 0x0AB3 }, - { 0x0AB5, 0x0AB9 }, - { 0x0ABD, 0x0AC5 }, - { 0x0AC7, 0x0AC9 }, - { 0x0ACB, 0x0ACD }, - { 0x0AD0, 0x0AD0 }, - { 0x0AE0, 0x0AE0 }, - { 0x0AE6, 0x0AEF }, - { 0x0B01, 0x0B03 }, - { 0x0B05, 0x0B0C }, - { 0x0B0F, 0x0B10 }, - { 0x0B13, 0x0B28 }, - { 0x0B2A, 0x0B30 }, - { 0x0B32, 0x0B33 }, - { 0x0B36, 0x0B39 }, - { 0x0B3D, 0x0B3D }, - { 0x0B3E, 0x0B43 }, - { 0x0B47, 0x0B48 }, - { 0x0B4B, 0x0B4D }, - { 0x0B5C, 0x0B5D }, - { 0x0B5F, 0x0B61 }, - { 0x0B66, 0x0B6F }, - { 0x0B82, 0x0B83 }, - { 0x0B85, 0x0B8A }, - { 0x0B8E, 0x0B90 }, - { 0x0B92, 0x0B95 }, - { 0x0B99, 0x0B9A }, - { 0x0B9C, 0x0B9C }, - { 0x0B9E, 0x0B9F }, - { 0x0BA3, 0x0BA4 }, - { 0x0BA8, 0x0BAA }, - { 0x0BAE, 0x0BB5 }, - { 0x0BB7, 0x0BB9 }, - { 0x0BBE, 0x0BC2 }, - { 0x0BC6, 0x0BC8 }, - { 0x0BCA, 0x0BCD }, - { 0x0BE7, 0x0BEF }, - { 0x0C01, 0x0C03 }, - { 0x0C05, 0x0C0C }, - { 0x0C0E, 0x0C10 }, - { 0x0C12, 0x0C28 }, - { 0x0C2A, 0x0C33 }, - { 0x0C35, 0x0C39 }, - { 0x0C3E, 0x0C44 }, - { 0x0C46, 0x0C48 }, - { 0x0C4A, 0x0C4D }, - { 0x0C60, 0x0C61 }, - { 0x0C66, 0x0C6F }, - { 0x0C82, 0x0C83 }, - { 0x0C85, 0x0C8C }, - { 0x0C8E, 0x0C90 }, - { 0x0C92, 0x0CA8 }, - { 0x0CAA, 0x0CB3 }, - { 0x0CB5, 0x0CB9 }, - { 0x0CBE, 0x0CC4 }, - { 0x0CC6, 0x0CC8 }, - { 0x0CCA, 0x0CCD }, - { 0x0CDE, 0x0CDE }, - { 0x0CE0, 0x0CE1 }, - { 0x0CE6, 0x0CEF }, - { 0x0D02, 0x0D03 }, - { 0x0D05, 0x0D0C }, - { 0x0D0E, 0x0D10 }, - { 0x0D12, 0x0D28 }, - { 0x0D2A, 0x0D39 }, - { 0x0D3E, 0x0D43 }, - { 0x0D46, 0x0D48 }, - { 0x0D4A, 0x0D4D }, - { 0x0D60, 0x0D61 }, - { 0x0D66, 0x0D6F }, - { 0x0E01, 0x0E3A }, - { 0x0E40, 0x0E5B }, -// { 0x0E50, 0x0E59 }, - { 0x0E81, 0x0E82 }, - { 0x0E84, 0x0E84 }, - { 0x0E87, 0x0E88 }, - { 0x0E8A, 0x0E8A }, - { 0x0E8D, 0x0E8D }, - { 0x0E94, 0x0E97 }, - { 0x0E99, 0x0E9F }, - { 0x0EA1, 0x0EA3 }, - { 0x0EA5, 0x0EA5 }, - { 0x0EA7, 0x0EA7 }, - { 0x0EAA, 0x0EAB }, - { 0x0EAD, 0x0EAE }, - { 0x0EB0, 0x0EB9 }, - { 0x0EBB, 0x0EBD }, - { 0x0EC0, 0x0EC4 }, - { 0x0EC6, 0x0EC6 }, - { 0x0EC8, 0x0ECD }, - { 0x0ED0, 0x0ED9 }, - { 0x0EDC, 0x0EDD }, - { 0x0F00, 0x0F00 }, - { 0x0F18, 0x0F19 }, - { 0x0F20, 0x0F33 }, - { 0x0F35, 0x0F35 }, - { 0x0F37, 0x0F37 }, - { 0x0F39, 0x0F39 }, - { 0x0F3E, 0x0F47 }, - { 0x0F49, 0x0F69 }, - { 0x0F71, 0x0F84 }, - { 0x0F86, 0x0F8B }, - { 0x0F90, 0x0F95 }, - { 0x0F97, 0x0F97 }, - { 0x0F99, 0x0FAD }, - { 0x0FB1, 0x0FB7 }, - { 0x0FB9, 0x0FB9 }, - { 0x10A0, 0x10C5 }, - { 0x10D0, 0x10F6 }, - { 0x1E00, 0x1E9B }, - { 0x1EA0, 0x1EF9 }, - { 0x1F00, 0x1F15 }, - { 0x1F18, 0x1F1D }, - { 0x1F20, 0x1F45 }, - { 0x1F48, 0x1F4D }, - { 0x1F50, 0x1F57 }, - { 0x1F59, 0x1F59 }, - { 0x1F5B, 0x1F5B }, - { 0x1F5D, 0x1F5D }, - { 0x1F5F, 0x1F7D }, - { 0x1F80, 0x1FB4 }, - { 0x1FB6, 0x1FBC }, - { 0x1FBE, 0x1FBE }, - { 0x1FC2, 0x1FC4 }, - { 0x1FC6, 0x1FCC }, - { 0x1FD0, 0x1FD3 }, - { 0x1FD6, 0x1FDB }, - { 0x1FE0, 0x1FEC }, - { 0x1FF2, 0x1FF4 }, - { 0x1FF6, 0x1FFC }, - { 0x203F, 0x2040 }, - { 0x207F, 0x207F }, - { 0x2102, 0x2102 }, - { 0x2107, 0x2107 }, - { 0x210A, 0x2113 }, - { 0x2115, 0x2115 }, - { 0x2118, 0x211D }, - { 0x2124, 0x2124 }, - { 0x2126, 0x2126 }, - { 0x2128, 0x2128 }, - { 0x212A, 0x2131 }, - { 0x2133, 0x2138 }, - { 0x2160, 0x2182 }, - { 0x3005, 0x3007 }, - { 0x3021, 0x3029 }, - { 0x3041, 0x3093 }, - { 0x309B, 0x309C }, - { 0x30A1, 0x30F6 }, - { 0x30FB, 0x30FC }, - { 0x3105, 0x312C }, - { 0x4E00, 0x9FA5 }, - { 0xAC00, 0xD7A3 }, - }; - -#ifdef DEBUG - for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) - { - //printf("%x\n", table[i][0]); - assert(table[i][0] <= table[i][1]); - if (i < sizeof(table) / sizeof(table[0]) - 1) - assert(table[i][1] < table[i + 1][0]); - } -#endif - - if (u > 0xD7A3) - goto Lisnot; - - // Binary search - int mid; - int low; - int high; - - low = 0; - high = sizeof(table) / sizeof(table[0]) - 1; - while (low <= high) - { - mid = (low + high) >> 1; - if (u < table[mid][0]) - high = mid - 1; - else if (u > table[mid][1]) - low = mid + 1; - else - goto Lis; - } - -Lisnot: -#ifdef DEBUG - for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) - { - assert(u < table[i][0] || u > table[i][1]); - } -#endif - return 0; - -Lis: -#ifdef DEBUG - for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) - { - if (u >= table[i][0] && u <= table[i][1]) - return 1; - } - assert(0); // should have been in table -#endif - return 1; -} - diff --git a/dmd2/unittests.c b/dmd2/unittests.c index 1b3c2770..3cadebe5 100644 --- a/dmd2/unittests.c +++ b/dmd2/unittests.c @@ -1,4 +1,12 @@ +// Copyright (c) 2010-2012 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + #include #include "mars.h" diff --git a/dmd2/utf.c b/dmd2/utf.c index 78f8cd4a..c74f0770 100644 --- a/dmd2/utf.c +++ b/dmd2/utf.c @@ -1,5 +1,5 @@ // utf.c -// Copyright (c) 2003-2009 by Digital Mars +// Copyright (c) 2003-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -7,22 +7,32 @@ // in artistic.txt, or the GNU General Public License in gnu.txt. // See the included readme.txt for details. -// Description of UTF-8 at: -// http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 +/// Description of UTF-8 in [1]. Unicode non-characters and private-use +/// code points described in [2],[4]. +/// +/// References: +/// [1] http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 +/// [2] http://en.wikipedia.org/wiki/Unicode +/// [3] http://unicode.org/faq/utf_bom.html +/// [4] http://www.unicode.org/versions/Unicode6.1.0/ch03.pdf -#include -#include #include #include "utf.h" -int utf_isValidDchar(dchar_t c) +namespace { - return c < 0xD800 || - (c > 0xDFFF && c <= 0x10FFFF && c != 0xFFFE && c != 0xFFFF); -} -static const unsigned char UTF8stride[256] = +/* The following encodings are valid, except for the 5 and 6 byte + * combinations: + * 0xxxxxxx + * 110xxxxx 10xxxxxx + * 1110xxxx 10xxxxxx 10xxxxxx + * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + * 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + * 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + */ +const unsigned UTF8_STRIDE[256] = { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, @@ -42,237 +52,73 @@ static const unsigned char UTF8stride[256] = 4,4,4,4,4,4,4,4,5,5,5,5,6,6,0xFF,0xFF, }; -/** - * stride() returns the length of a UTF-8 sequence starting at index i - * in string s. - * Returns: - * The number of bytes in the UTF-8 sequence or - * 0xFF meaning s[i] is not the start of of UTF-8 sequence. - */ +} // namespace -unsigned stride(unsigned char* s, size_t i) +namespace Unicode { - unsigned result = UTF8stride[s[i]]; - return result; + +// UTF-8 decoding errors +char const UTF8_DECODE_OUTSIDE_CODE_SPACE[] = "Outside Unicode code space"; +char const UTF8_DECODE_TRUNCATED_SEQUENCE[] = "Truncated UTF-8 sequence"; +char const UTF8_DECODE_OVERLONG[] = "Overlong UTF-8 sequence"; +char const UTF8_DECODE_INVALID_TRAILER[] = "Invalid trailing code unit"; +char const UTF8_DECODE_INVALID_CODE_POINT[] = "Invalid code point decoded"; + +// UTF-16 decoding errors +char const UTF16_DECODE_TRUNCATED_SEQUENCE[]= "Truncated UTF-16 sequence"; +char const UTF16_DECODE_INVALID_SURROGATE[] = "Invalid low surrogate"; +char const UTF16_DECODE_UNPAIRED_SURROGATE[]= "Unpaired surrogate"; +char const UTF16_DECODE_INVALID_CODE_POINT[]= "Invalid code point decoded"; + +} // namespace Unicode + +using namespace Unicode; + +/// The Unicode code space is the range of code points [0x000000,0x10FFFF] +/// except the UTF-16 surrogate pairs in the range [0xD800,0xDFFF] +/// and non-characters (which end in 0xFFFE or 0xFFFF). +bool utf_isValidDchar(dchar_t c) +{ + // TODO: Whether non-char code points should be rejected is pending review + return c <= 0x10FFFF // largest character code point + && !(0xD800 <= c && c <= 0xDFFF) // surrogate pairs + && (c & 0xFFFFFE) != 0x00FFFE // non-characters +// && (c & 0xFFFE) != 0xFFFE // non-characters +// && !(0x00FDD0 <= c && c <= 0x00FDEF) // non-characters + ; } -/******************************************** - * Decode a single UTF-8 character sequence. - * Returns: - * NULL success - * !=NULL error message string +/******************************* + * Return !=0 if unicode alpha. + * Use table from C99 Appendix D. */ -const char *utf_decodeChar(unsigned char *s, size_t len, size_t *pidx, dchar_t *presult) +bool isUniAlpha(dchar_t c) { - dchar_t V; - size_t i = *pidx; - unsigned char u = s[i]; - - //printf("utf_decodeChar(s = %02x, %02x, %02x len = %d)\n", u, s[1], s[2], len); - - assert(i >= 0 && i < len); - - if (u & 0x80) - { unsigned n; - unsigned char u2; - - /* The following encodings are valid, except for the 5 and 6 byte - * combinations: - * 0xxxxxxx - * 110xxxxx 10xxxxxx - * 1110xxxx 10xxxxxx 10xxxxxx - * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - * 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - * 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - */ - for (n = 1; ; n++) - { - if (n > 4) - goto Lerr; // only do the first 4 of 6 encodings - if (((u << n) & 0x80) == 0) - { - if (n == 1) - goto Lerr; - break; - } - } - - // Pick off (7 - n) significant bits of B from first byte of octet - V = (dchar_t)(u & ((1 << (7 - n)) - 1)); - - if (i + (n - 1) >= len) - goto Lerr; // off end of string - - /* The following combinations are overlong, and illegal: - * 1100000x (10xxxxxx) - * 11100000 100xxxxx (10xxxxxx) - * 11110000 1000xxxx (10xxxxxx 10xxxxxx) - * 11111000 10000xxx (10xxxxxx 10xxxxxx 10xxxxxx) - * 11111100 100000xx (10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx) - */ - u2 = s[i + 1]; - if ((u & 0xFE) == 0xC0 || - (u == 0xE0 && (u2 & 0xE0) == 0x80) || - (u == 0xF0 && (u2 & 0xF0) == 0x80) || - (u == 0xF8 && (u2 & 0xF8) == 0x80) || - (u == 0xFC && (u2 & 0xFC) == 0x80)) - goto Lerr; // overlong combination - - for (unsigned j = 1; j != n; j++) - { - u = s[i + j]; - if ((u & 0xC0) != 0x80) - goto Lerr; // trailing bytes are 10xxxxxx - V = (V << 6) | (u & 0x3F); - } - if (!utf_isValidDchar(V)) - goto Lerr; - i += n; - } - else + static size_t const END = sizeof(ALPHA_TABLE) / sizeof(ALPHA_TABLE[0]); + size_t high = END - 1; + // Shortcut search if c is out of range + size_t low + = (c < ALPHA_TABLE[0][0] || ALPHA_TABLE[high][1] < c) ? high + 1 : 0; + // Binary search + while (low <= high) { - V = (dchar_t) u; - i++; - } - - assert(utf_isValidDchar(V)); - *pidx = i; - *presult = V; - return NULL; - - Lerr: - *presult = (dchar_t) s[i]; - *pidx = i + 1; - return "invalid UTF-8 sequence"; -} - -/*************************************************** - * Validate a UTF-8 string. - * Returns: - * NULL success - * !=NULL error message string - */ - -const char *utf_validateString(unsigned char *s, size_t len) -{ - size_t idx; - const char *err = NULL; - dchar_t dc; - - for (idx = 0; idx < len; ) - { - err = utf_decodeChar(s, len, &idx, &dc); - if (err) - break; - } - return err; -} - - -/******************************************** - * Decode a single UTF-16 character sequence. - * Returns: - * NULL success - * !=NULL error message string - */ - - -const char *utf_decodeWchar(unsigned short *s, size_t len, size_t *pidx, dchar_t *presult) -{ - const char *msg; - size_t i = *pidx; - unsigned u = s[i]; - - assert(i >= 0 && i < len); - if (u & ~0x7F) - { if (u >= 0xD800 && u <= 0xDBFF) - { unsigned u2; - - if (i + 1 == len) - { msg = "surrogate UTF-16 high value past end of string"; - goto Lerr; - } - u2 = s[i + 1]; - if (u2 < 0xDC00 || u2 > 0xDFFF) - { msg = "surrogate UTF-16 low value out of range"; - goto Lerr; - } - u = ((u - 0xD7C0) << 10) + (u2 - 0xDC00); - i += 2; - } - else if (u >= 0xDC00 && u <= 0xDFFF) - { msg = "unpaired surrogate UTF-16 value"; - goto Lerr; - } - else if (u == 0xFFFE || u == 0xFFFF) - { msg = "illegal UTF-16 value"; - goto Lerr; - } + size_t mid = (low + high) >> 1; + if (c < ALPHA_TABLE[mid][0]) + high = mid - 1; + else if (ALPHA_TABLE[mid][1] < c) + low = mid + 1; else - i++; + { + assert(ALPHA_TABLE[mid][0] <= c && c <= ALPHA_TABLE[mid][1]); + return true; + } } - else - { - i++; - } - - assert(utf_isValidDchar(u)); - *pidx = i; - *presult = (dchar_t)u; - return NULL; - - Lerr: - *presult = (dchar_t)s[i]; - *pidx = i + 1; - return msg; + return false; } -void utf_encodeChar(unsigned char *s, dchar_t c) -{ - if (c <= 0x7F) - { - s[0] = (char) c; - } - else if (c <= 0x7FF) - { - s[0] = (char)(0xC0 | (c >> 6)); - s[1] = (char)(0x80 | (c & 0x3F)); - } - else if (c <= 0xFFFF) - { - s[0] = (char)(0xE0 | (c >> 12)); - s[1] = (char)(0x80 | ((c >> 6) & 0x3F)); - s[2] = (char)(0x80 | (c & 0x3F)); - } - else if (c <= 0x10FFFF) - { - s[0] = (char)(0xF0 | (c >> 18)); - s[1] = (char)(0x80 | ((c >> 12) & 0x3F)); - s[2] = (char)(0x80 | ((c >> 6) & 0x3F)); - s[3] = (char)(0x80 | (c & 0x3F)); - } - else - assert(0); -} - -void utf_encodeWchar(unsigned short *s, dchar_t c) -{ - if (c <= 0xFFFF) - { - s[0] = (wchar_t) c; - } - else - { - s[0] = (wchar_t) ((((c - 0x10000) >> 10) & 0x3FF) + 0xD800); - s[1] = (wchar_t) (((c - 0x10000) & 0x3FF) + 0xDC00); - } -} - - /** - * Returns the code length of c in the encoding. - * The code is returned in character count, not in bytes. + * Returns the code length of c in code units. */ int utf_codeLengthChar(dchar_t c) @@ -291,10 +137,10 @@ int utf_codeLengthWchar(dchar_t c) } /** - * Returns the code length of c in the encoding. + * Returns the code length of c in code units for the encoding. * sz is the encoding: 1 = utf8, 2 = utf16, 4 = utf32. - * The code is returned in character count, not in bytes. */ + int utf_codeLength(int sz, dchar_t c) { if (sz == 1) @@ -305,16 +151,161 @@ int utf_codeLength(int sz, dchar_t c) return 1; } -void utf_encode(int sz, void *s, dchar_t c) +void utf_encodeChar(utf8_t *s, dchar_t c) { - if (sz == 1) - utf_encodeChar((unsigned char *)s, c); - else if (sz == 2) - utf_encodeWchar((unsigned short *)s, c); + assert(s != NULL); + assert(utf_isValidDchar(c)); + if (c <= 0x7F) + { + s[0] = static_cast(c); + } + else if (c <= 0x07FF) + { + s[0] = static_cast(0xC0 | (c >> 6)); + s[1] = static_cast(0x80 | (c & 0x3F)); + } + else if (c <= 0xFFFF) + { + s[0] = static_cast(0xE0 | (c >> 12)); + s[1] = static_cast(0x80 | ((c >> 6) & 0x3F)); + s[2] = static_cast(0x80 | (c & 0x3F)); + } + else if (c <= 0x10FFFF) + { + s[0] = static_cast(0xF0 | (c >> 18)); + s[1] = static_cast(0x80 | ((c >> 12) & 0x3F)); + s[2] = static_cast(0x80 | ((c >> 6) & 0x3F)); + s[3] = static_cast(0x80 | (c & 0x3F)); + } + else + assert(0); +} + +void utf_encodeWchar(utf16_t *s, dchar_t c) +{ + assert(s != NULL); + assert(utf_isValidDchar(c)); + if (c <= 0xFFFF) + { + s[0] = static_cast(c); + } else { - assert(sz == 4); - memcpy((unsigned char *)s, &c, sz); + s[0] = static_cast((((c - 0x010000) >> 10) & 0x03FF) + 0xD800); + s[1] = static_cast(((c - 0x010000) & 0x03FF) + 0xDC00); } } +void utf_encode(int sz, void *s, dchar_t c) +{ + if (sz == 1) + utf_encodeChar((utf8_t *)s, c); + else if (sz == 2) + utf_encodeWchar((utf16_t *)s, c); + else + { + assert(sz == 4); + *((utf32_t *)s) = c; + } +} + +/******************************************** + * Decode a UTF-8 sequence as a single UTF-32 code point. + * Returns: + * NULL success + * !=NULL error message string + */ + +const char *utf_decodeChar(utf8_t const *s, size_t len, size_t *pidx, dchar_t *presult) +{ + assert(s != NULL); + assert(pidx != NULL); + assert(presult != NULL); + size_t i = (*pidx)++; + assert(i < len); + utf8_t u = s[i]; + // Pre-stage results for ASCII and error cases + *presult = u; + + //printf("utf_decodeChar(s = %02x, %02x, %02x len = %d)\n", u, s[1], s[2], len); + + // Get expected sequence length + unsigned n = UTF8_STRIDE[u]; + switch (n) + { + case 1: // ASCII + return UTF8_DECODE_OK; + case 2: case 3: case 4: // multi-byte UTF-8 + break; + default: // 5- or 6-byte sequence + return UTF8_DECODE_OUTSIDE_CODE_SPACE; + } + if (len < i + n) // source too short + return UTF8_DECODE_TRUNCATED_SEQUENCE; + + // Pick off 7 - n low bits from first code unit + utf32_t c = u & ((1 << (7 - n)) - 1); + /* The following combinations are overlong, and illegal: + * 1100000x (10xxxxxx) + * 11100000 100xxxxx (10xxxxxx) + * 11110000 1000xxxx (10xxxxxx 10xxxxxx) + * 11111000 10000xxx (10xxxxxx 10xxxxxx 10xxxxxx) + * 11111100 100000xx (10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx) + */ + utf8_t u2 = s[++i]; + if ((u & 0xFE) == 0xC0 || // overlong combination + (u == 0xE0 && (u2 & 0xE0) == 0x80) || + (u == 0xF0 && (u2 & 0xF0) == 0x80) || + (u == 0xF8 && (u2 & 0xF8) == 0x80) || + (u == 0xFC && (u2 & 0xFC) == 0x80)) + return UTF8_DECODE_OVERLONG; + // Decode remaining bits + for (n += i - 1; i != n; ++i) + { + u = s[i]; + if ((u & 0xC0) != 0x80) // trailing bytes are 10xxxxxx + return UTF8_DECODE_INVALID_TRAILER; + c = (c << 6) | (u & 0x3F); + } + if (!utf_isValidDchar(c)) + return UTF8_DECODE_INVALID_CODE_POINT; + *pidx = i; + *presult = c; + return UTF8_DECODE_OK; +} + +/******************************************** + * Decode a UTF-16 sequence as a single UTF-32 code point. + * Returns: + * NULL success + * !=NULL error message string + */ + +const char *utf_decodeWchar(utf16_t const *s, size_t len, size_t *pidx, dchar_t *presult) +{ + assert(s != NULL); + assert(pidx != NULL); + assert(presult != NULL); + size_t i = (*pidx)++; + assert(i < len); + // Pre-stage results for ASCII and error cases + utf32_t u = *presult = s[i]; + + if (u < 0x80) // ASCII + return UTF16_DECODE_OK; + if (0xD800 <= u && u <= 0xDBFF) // Surrogate pair + { if (len <= i + 1) + return UTF16_DECODE_TRUNCATED_SEQUENCE; + utf16_t u2 = s[i + 1]; + if (u2 < 0xDC00 || 0xDFFF < u) + return UTF16_DECODE_INVALID_SURROGATE; + u = ((u - 0xD7C0) << 10) + (u2 - 0xDC00); + ++*pidx; + } + else if (0xDC00 <= u && u <= 0xDFFF) + return UTF16_DECODE_UNPAIRED_SURROGATE; + if (!utf_isValidDchar(u)) + return UTF16_DECODE_INVALID_CODE_POINT; + *presult = u; + return UTF16_DECODE_OK; +} diff --git a/dmd2/utf.h b/dmd2/utf.h index 22d8d3eb..e48ffaab 100644 --- a/dmd2/utf.h +++ b/dmd2/utf.h @@ -11,25 +11,114 @@ #ifndef DMD_UTF_H #define DMD_UTF_H +#include -typedef unsigned dchar_t; +/// A UTF-8 code unit +typedef unsigned char utf8_t; +/// A UTF-16 code unit +typedef unsigned short utf16_t; +/// A UTF-32 code unit +typedef unsigned int utf32_t; +typedef utf32_t dchar_t; -int utf_isValidDchar(dchar_t c); +namespace Unicode +{ -const char *utf_decodeChar(unsigned char *s, size_t len, size_t *pidx, dchar_t *presult); -const char *utf_decodeWchar(unsigned short *s, size_t len, size_t *pidx, dchar_t *presult); +static utf16_t const ALPHA_TABLE[][2] = +{ + { 0x00AA, 0x00AA }, { 0x00B5, 0x00B5 }, { 0x00B7, 0x00B7 }, { 0x00BA, 0x00BA }, + { 0x00C0, 0x00D6 }, { 0x00D8, 0x00F6 }, { 0x00F8, 0x01F5 }, { 0x01FA, 0x0217 }, + { 0x0250, 0x02A8 }, { 0x02B0, 0x02B8 }, { 0x02BB, 0x02BB }, { 0x02BD, 0x02C1 }, + { 0x02D0, 0x02D1 }, { 0x02E0, 0x02E4 }, { 0x037A, 0x037A }, { 0x0386, 0x0386 }, + { 0x0388, 0x038A }, { 0x038C, 0x038C }, { 0x038E, 0x03A1 }, { 0x03A3, 0x03CE }, + { 0x03D0, 0x03D6 }, { 0x03DA, 0x03DA }, { 0x03DC, 0x03DC }, { 0x03DE, 0x03DE }, + { 0x03E0, 0x03E0 }, { 0x03E2, 0x03F3 }, { 0x0401, 0x040C }, { 0x040E, 0x044F }, + { 0x0451, 0x045C }, { 0x045E, 0x0481 }, { 0x0490, 0x04C4 }, { 0x04C7, 0x04C8 }, + { 0x04CB, 0x04CC }, { 0x04D0, 0x04EB }, { 0x04EE, 0x04F5 }, { 0x04F8, 0x04F9 }, + { 0x0531, 0x0556 }, { 0x0559, 0x0559 }, { 0x0561, 0x0587 }, { 0x05B0, 0x05B9 }, + { 0x05BB, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 }, { 0x05D0, 0x05EA }, + { 0x05F0, 0x05F2 }, { 0x0621, 0x063A }, { 0x0640, 0x0652 }, { 0x0660, 0x0669 }, + { 0x0670, 0x06B7 }, { 0x06BA, 0x06BE }, { 0x06C0, 0x06CE }, { 0x06D0, 0x06DC }, + { 0x06E5, 0x06E8 }, { 0x06EA, 0x06ED }, { 0x06F0, 0x06F9 }, { 0x0901, 0x0903 }, + { 0x0905, 0x0939 }, { 0x093D, 0x094D }, { 0x0950, 0x0952 }, { 0x0958, 0x0963 }, + { 0x0966, 0x096F }, { 0x0981, 0x0983 }, { 0x0985, 0x098C }, { 0x098F, 0x0990 }, + { 0x0993, 0x09A8 }, { 0x09AA, 0x09B0 }, { 0x09B2, 0x09B2 }, { 0x09B6, 0x09B9 }, + { 0x09BE, 0x09C4 }, { 0x09C7, 0x09C8 }, { 0x09CB, 0x09CD }, { 0x09DC, 0x09DD }, + { 0x09DF, 0x09E3 }, { 0x09E6, 0x09F1 }, { 0x0A02, 0x0A02 }, { 0x0A05, 0x0A0A }, + { 0x0A0F, 0x0A10 }, { 0x0A13, 0x0A28 }, { 0x0A2A, 0x0A30 }, { 0x0A32, 0x0A33 }, + { 0x0A35, 0x0A36 }, { 0x0A38, 0x0A39 }, { 0x0A3E, 0x0A42 }, { 0x0A47, 0x0A48 }, + { 0x0A4B, 0x0A4D }, { 0x0A59, 0x0A5C }, { 0x0A5E, 0x0A5E }, { 0x0A66, 0x0A6F }, + { 0x0A74, 0x0A74 }, { 0x0A81, 0x0A83 }, { 0x0A85, 0x0A8B }, { 0x0A8D, 0x0A8D }, + { 0x0A8F, 0x0A91 }, { 0x0A93, 0x0AA8 }, { 0x0AAA, 0x0AB0 }, { 0x0AB2, 0x0AB3 }, + { 0x0AB5, 0x0AB9 }, { 0x0ABD, 0x0AC5 }, { 0x0AC7, 0x0AC9 }, { 0x0ACB, 0x0ACD }, + { 0x0AD0, 0x0AD0 }, { 0x0AE0, 0x0AE0 }, { 0x0AE6, 0x0AEF }, { 0x0B01, 0x0B03 }, + { 0x0B05, 0x0B0C }, { 0x0B0F, 0x0B10 }, { 0x0B13, 0x0B28 }, { 0x0B2A, 0x0B30 }, + { 0x0B32, 0x0B33 }, { 0x0B36, 0x0B39 }, { 0x0B3D, 0x0B43 }, { 0x0B47, 0x0B48 }, + { 0x0B4B, 0x0B4D }, { 0x0B5C, 0x0B5D }, { 0x0B5F, 0x0B61 }, { 0x0B66, 0x0B6F }, + { 0x0B82, 0x0B83 }, { 0x0B85, 0x0B8A }, { 0x0B8E, 0x0B90 }, { 0x0B92, 0x0B95 }, + { 0x0B99, 0x0B9A }, { 0x0B9C, 0x0B9C }, { 0x0B9E, 0x0B9F }, { 0x0BA3, 0x0BA4 }, + { 0x0BA8, 0x0BAA }, { 0x0BAE, 0x0BB5 }, { 0x0BB7, 0x0BB9 }, { 0x0BBE, 0x0BC2 }, + { 0x0BC6, 0x0BC8 }, { 0x0BCA, 0x0BCD }, { 0x0BE7, 0x0BEF }, { 0x0C01, 0x0C03 }, + { 0x0C05, 0x0C0C }, { 0x0C0E, 0x0C10 }, { 0x0C12, 0x0C28 }, { 0x0C2A, 0x0C33 }, + { 0x0C35, 0x0C39 }, { 0x0C3E, 0x0C44 }, { 0x0C46, 0x0C48 }, { 0x0C4A, 0x0C4D }, + { 0x0C60, 0x0C61 }, { 0x0C66, 0x0C6F }, { 0x0C82, 0x0C83 }, { 0x0C85, 0x0C8C }, + { 0x0C8E, 0x0C90 }, { 0x0C92, 0x0CA8 }, { 0x0CAA, 0x0CB3 }, { 0x0CB5, 0x0CB9 }, + { 0x0CBE, 0x0CC4 }, { 0x0CC6, 0x0CC8 }, { 0x0CCA, 0x0CCD }, { 0x0CDE, 0x0CDE }, + { 0x0CE0, 0x0CE1 }, { 0x0CE6, 0x0CEF }, { 0x0D02, 0x0D03 }, { 0x0D05, 0x0D0C }, + { 0x0D0E, 0x0D10 }, { 0x0D12, 0x0D28 }, { 0x0D2A, 0x0D39 }, { 0x0D3E, 0x0D43 }, + { 0x0D46, 0x0D48 }, { 0x0D4A, 0x0D4D }, { 0x0D60, 0x0D61 }, { 0x0D66, 0x0D6F }, + { 0x0E01, 0x0E3A }, { 0x0E40, 0x0E5B }, /* { 0x0E50, 0x0E59 }, */ { 0x0E81, 0x0E82 }, + { 0x0E84, 0x0E84 }, { 0x0E87, 0x0E88 }, { 0x0E8A, 0x0E8A }, { 0x0E8D, 0x0E8D }, + { 0x0E94, 0x0E97 }, { 0x0E99, 0x0E9F }, { 0x0EA1, 0x0EA3 }, { 0x0EA5, 0x0EA5 }, + { 0x0EA7, 0x0EA7 }, { 0x0EAA, 0x0EAB }, { 0x0EAD, 0x0EAE }, { 0x0EB0, 0x0EB9 }, + { 0x0EBB, 0x0EBD }, { 0x0EC0, 0x0EC4 }, { 0x0EC6, 0x0EC6 }, { 0x0EC8, 0x0ECD }, + { 0x0ED0, 0x0ED9 }, { 0x0EDC, 0x0EDD }, { 0x0F00, 0x0F00 }, { 0x0F18, 0x0F19 }, + { 0x0F20, 0x0F33 }, { 0x0F35, 0x0F35 }, { 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, + { 0x0F3E, 0x0F47 }, { 0x0F49, 0x0F69 }, { 0x0F71, 0x0F84 }, { 0x0F86, 0x0F8B }, + { 0x0F90, 0x0F95 }, { 0x0F97, 0x0F97 }, { 0x0F99, 0x0FAD }, { 0x0FB1, 0x0FB7 }, + { 0x0FB9, 0x0FB9 }, { 0x10A0, 0x10C5 }, { 0x10D0, 0x10F6 }, { 0x1E00, 0x1E9B }, + { 0x1EA0, 0x1EF9 }, { 0x1F00, 0x1F15 }, { 0x1F18, 0x1F1D }, { 0x1F20, 0x1F45 }, + { 0x1F48, 0x1F4D }, { 0x1F50, 0x1F57 }, { 0x1F59, 0x1F59 }, { 0x1F5B, 0x1F5B }, + { 0x1F5D, 0x1F5D }, { 0x1F5F, 0x1F7D }, { 0x1F80, 0x1FB4 }, { 0x1FB6, 0x1FBC }, + { 0x1FBE, 0x1FBE }, { 0x1FC2, 0x1FC4 }, { 0x1FC6, 0x1FCC }, { 0x1FD0, 0x1FD3 }, + { 0x1FD6, 0x1FDB }, { 0x1FE0, 0x1FEC }, { 0x1FF2, 0x1FF4 }, { 0x1FF6, 0x1FFC }, + { 0x203F, 0x2040 }, { 0x207F, 0x207F }, { 0x2102, 0x2102 }, { 0x2107, 0x2107 }, + { 0x210A, 0x2113 }, { 0x2115, 0x2115 }, { 0x2118, 0x211D }, { 0x2124, 0x2124 }, + { 0x2126, 0x2126 }, { 0x2128, 0x2128 }, { 0x212A, 0x2131 }, { 0x2133, 0x2138 }, + { 0x2160, 0x2182 }, { 0x3005, 0x3007 }, { 0x3021, 0x3029 }, { 0x3041, 0x3093 }, + { 0x309B, 0x309C }, { 0x30A1, 0x30F6 }, { 0x30FB, 0x30FC }, { 0x3105, 0x312C }, + { 0x4E00, 0x9FA5 }, { 0xAC00, 0xD7A3 }, +}; -const char *utf_validateString(unsigned char *s, size_t len); +char const *const UTF8_DECODE_OK = NULL; +extern char const UTF8_DECODE_OUTSIDE_CODE_SPACE[]; +extern char const UTF8_DECODE_TRUNCATED_SEQUENCE[]; +extern char const UTF8_DECODE_OVERLONG[]; +extern char const UTF8_DECODE_INVALID_TRAILER[]; +extern char const UTF8_DECODE_INVALID_CODE_POINT[]; -extern int isUniAlpha(dchar_t); +char const *const UTF16_DECODE_OK = NULL; +extern char const UTF16_DECODE_TRUNCATED_SEQUENCE[]; +extern char const UTF16_DECODE_INVALID_SURROGATE[]; +extern char const UTF16_DECODE_UNPAIRED_SURROGATE[]; +extern char const UTF16_DECODE_INVALID_CODE_POINT[]; -void utf_encodeChar(unsigned char *s, dchar_t c); -void utf_encodeWchar(unsigned short *s, dchar_t c); +} // namespace Unicode + +/// \return true if \a c is a valid, non-private UTF-32 code point +bool utf_isValidDchar(dchar_t c); + +bool isUniAlpha(dchar_t c); int utf_codeLengthChar(dchar_t c); int utf_codeLengthWchar(dchar_t c); - int utf_codeLength(int sz, dchar_t c); + +void utf_encodeChar(utf8_t *s, dchar_t c); +void utf_encodeWchar(utf16_t *s, dchar_t c); void utf_encode(int sz, void *s, dchar_t c); -#endif +const char *utf_decodeChar(utf8_t const *s, size_t len, size_t *pidx, dchar_t *presult); +const char *utf_decodeWchar(utf16_t const *s, size_t len, size_t *pidx, dchar_t *presult); + +#endif // DMD_UTF_H diff --git a/driver/main.cpp b/driver/main.cpp index e570907a..13f4ee68 100644 --- a/driver/main.cpp +++ b/driver/main.cpp @@ -23,6 +23,11 @@ #include "rmem.h" #include "root.h" +// stricmp +#if __GNUC__ && !_WIN32 +#include "gnuc.h" +#endif + #include "mars.h" #include "module.h" #include "mtype.h" @@ -834,10 +839,7 @@ int main(int argc, char** argv) #endif if (stricmp(ext, global.mars_ext) == 0 || - stricmp(ext, global.hdr_ext) == 0 || - stricmp(ext, "htm") == 0 || - stricmp(ext, "html") == 0 || - stricmp(ext, "xhtml") == 0) + stricmp(ext, global.hdr_ext) == 0) { ext--; // skip onto '.' assert(*ext == '.'); diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index 3c36a1f8..63d55c54 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -384,5 +384,5 @@ if(PHOBOS2_DIR) install(DIRECTORY ${PHOBOS2_DIR}/etc DESTINATION ${INCLUDE_INSTALL_DIR} FILES_MATCHING PATTERN "*.d") install(FILES ${PHOBOS2_DIR}/crc32.d DESTINATION ${INCLUDE_INSTALL_DIR}) endif(PHOBOS2_DIR) -install(FILES ${RUNTIME_DIR}/import/object.di DESTINATION ${INCLUDE_INSTALL_DIR}/ldc) +install(FILES ${RUNTIME_DIR}/src/object.di DESTINATION ${INCLUDE_INSTALL_DIR}/ldc) install(DIRECTORY ${RUNTIME_DIR}/import/ldc DESTINATION ${INCLUDE_INSTALL_DIR} FILES_MATCHING PATTERN "*.di") diff --git a/runtime/druntime b/runtime/druntime index 6ac9475a..a1cb86b9 160000 --- a/runtime/druntime +++ b/runtime/druntime @@ -1 +1 @@ -Subproject commit 6ac9475aa22924887d5010f41a4dc577836fbbdf +Subproject commit a1cb86b9e1e91eae50494e6904e47d11aa869540 diff --git a/runtime/phobos b/runtime/phobos index 52b15ed3..e05ad809 160000 --- a/runtime/phobos +++ b/runtime/phobos @@ -1 +1 @@ -Subproject commit 52b15ed3c0abf1d8af58bc5371c90636e01c1073 +Subproject commit e05ad809add2722d4f6492d1a4f43dd26091bdb9 From 1645eff59606a05ab6da45f1f24a1c5cd85c44e5 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Wed, 29 Aug 2012 11:16:42 +0200 Subject: [PATCH 03/33] Created separate tests directory for D1. --- tests/{ => d1}/README | 0 tests/{ => d1}/findregressions.d | 0 tests/{ => d1}/makewebstatistics.d | 0 tests/{ => d1}/minicomplex/arrays1.d | 0 tests/{ => d1}/minicomplex/constructors.d | 0 tests/{ => d1}/minicomplex/files1.d | 0 tests/{ => d1}/minicomplex/gc2.d | 0 tests/{ => d1}/minicomplex/ina1.d | 0 tests/{ => d1}/minicomplex/l.d | 0 tests/{ => d1}/minicomplex/mem1.d | 0 tests/{ => d1}/minicomplex/mem4.d | 0 tests/{ => d1}/minicomplex/stdout1.d | 0 tests/{ => d1}/minicomplex/stdout2.d | 0 tests/{ => d1}/minicomplex/templ1.d | 0 tests/{ => d1}/minicomplex/u.d | 0 tests/{ => d1}/minicomplex/vararg1.d | 0 tests/{ => d1}/minicomplex/vararg2.d | 0 tests/{ => d1}/minicomplex/volatile1.d | 0 tests/{ => d1}/runminitest.d | 0 tests/{ => d1}/runtest | 0 tests/{ => d1}/testincludes/Makefile | 0 tests/{ => d1}/testincludes/object.di | 0 tests/{ => d1}/testincludes/std/IEEE.d | 0 tests/{ => d1}/testincludes/std/compat.d | 0 tests/{ => d1}/testincludes/std/gc.d | 0 tests/{ => d1}/testincludes/std/outofmemory.d | 0 tests/{ => d1}/testincludes/std/stdarg.d | 0 27 files changed, 0 insertions(+), 0 deletions(-) rename tests/{ => d1}/README (100%) rename tests/{ => d1}/findregressions.d (100%) rename tests/{ => d1}/makewebstatistics.d (100%) rename tests/{ => d1}/minicomplex/arrays1.d (100%) rename tests/{ => d1}/minicomplex/constructors.d (100%) rename tests/{ => d1}/minicomplex/files1.d (100%) rename tests/{ => d1}/minicomplex/gc2.d (100%) rename tests/{ => d1}/minicomplex/ina1.d (100%) rename tests/{ => d1}/minicomplex/l.d (100%) rename tests/{ => d1}/minicomplex/mem1.d (100%) rename tests/{ => d1}/minicomplex/mem4.d (100%) rename tests/{ => d1}/minicomplex/stdout1.d (100%) rename tests/{ => d1}/minicomplex/stdout2.d (100%) rename tests/{ => d1}/minicomplex/templ1.d (100%) rename tests/{ => d1}/minicomplex/u.d (100%) rename tests/{ => d1}/minicomplex/vararg1.d (100%) rename tests/{ => d1}/minicomplex/vararg2.d (100%) rename tests/{ => d1}/minicomplex/volatile1.d (100%) rename tests/{ => d1}/runminitest.d (100%) rename tests/{ => d1}/runtest (100%) rename tests/{ => d1}/testincludes/Makefile (100%) rename tests/{ => d1}/testincludes/object.di (100%) rename tests/{ => d1}/testincludes/std/IEEE.d (100%) rename tests/{ => d1}/testincludes/std/compat.d (100%) rename tests/{ => d1}/testincludes/std/gc.d (100%) rename tests/{ => d1}/testincludes/std/outofmemory.d (100%) rename tests/{ => d1}/testincludes/std/stdarg.d (100%) diff --git a/tests/README b/tests/d1/README similarity index 100% rename from tests/README rename to tests/d1/README diff --git a/tests/findregressions.d b/tests/d1/findregressions.d similarity index 100% rename from tests/findregressions.d rename to tests/d1/findregressions.d diff --git a/tests/makewebstatistics.d b/tests/d1/makewebstatistics.d similarity index 100% rename from tests/makewebstatistics.d rename to tests/d1/makewebstatistics.d diff --git a/tests/minicomplex/arrays1.d b/tests/d1/minicomplex/arrays1.d similarity index 100% rename from tests/minicomplex/arrays1.d rename to tests/d1/minicomplex/arrays1.d diff --git a/tests/minicomplex/constructors.d b/tests/d1/minicomplex/constructors.d similarity index 100% rename from tests/minicomplex/constructors.d rename to tests/d1/minicomplex/constructors.d diff --git a/tests/minicomplex/files1.d b/tests/d1/minicomplex/files1.d similarity index 100% rename from tests/minicomplex/files1.d rename to tests/d1/minicomplex/files1.d diff --git a/tests/minicomplex/gc2.d b/tests/d1/minicomplex/gc2.d similarity index 100% rename from tests/minicomplex/gc2.d rename to tests/d1/minicomplex/gc2.d diff --git a/tests/minicomplex/ina1.d b/tests/d1/minicomplex/ina1.d similarity index 100% rename from tests/minicomplex/ina1.d rename to tests/d1/minicomplex/ina1.d diff --git a/tests/minicomplex/l.d b/tests/d1/minicomplex/l.d similarity index 100% rename from tests/minicomplex/l.d rename to tests/d1/minicomplex/l.d diff --git a/tests/minicomplex/mem1.d b/tests/d1/minicomplex/mem1.d similarity index 100% rename from tests/minicomplex/mem1.d rename to tests/d1/minicomplex/mem1.d diff --git a/tests/minicomplex/mem4.d b/tests/d1/minicomplex/mem4.d similarity index 100% rename from tests/minicomplex/mem4.d rename to tests/d1/minicomplex/mem4.d diff --git a/tests/minicomplex/stdout1.d b/tests/d1/minicomplex/stdout1.d similarity index 100% rename from tests/minicomplex/stdout1.d rename to tests/d1/minicomplex/stdout1.d diff --git a/tests/minicomplex/stdout2.d b/tests/d1/minicomplex/stdout2.d similarity index 100% rename from tests/minicomplex/stdout2.d rename to tests/d1/minicomplex/stdout2.d diff --git a/tests/minicomplex/templ1.d b/tests/d1/minicomplex/templ1.d similarity index 100% rename from tests/minicomplex/templ1.d rename to tests/d1/minicomplex/templ1.d diff --git a/tests/minicomplex/u.d b/tests/d1/minicomplex/u.d similarity index 100% rename from tests/minicomplex/u.d rename to tests/d1/minicomplex/u.d diff --git a/tests/minicomplex/vararg1.d b/tests/d1/minicomplex/vararg1.d similarity index 100% rename from tests/minicomplex/vararg1.d rename to tests/d1/minicomplex/vararg1.d diff --git a/tests/minicomplex/vararg2.d b/tests/d1/minicomplex/vararg2.d similarity index 100% rename from tests/minicomplex/vararg2.d rename to tests/d1/minicomplex/vararg2.d diff --git a/tests/minicomplex/volatile1.d b/tests/d1/minicomplex/volatile1.d similarity index 100% rename from tests/minicomplex/volatile1.d rename to tests/d1/minicomplex/volatile1.d diff --git a/tests/runminitest.d b/tests/d1/runminitest.d similarity index 100% rename from tests/runminitest.d rename to tests/d1/runminitest.d diff --git a/tests/runtest b/tests/d1/runtest similarity index 100% rename from tests/runtest rename to tests/d1/runtest diff --git a/tests/testincludes/Makefile b/tests/d1/testincludes/Makefile similarity index 100% rename from tests/testincludes/Makefile rename to tests/d1/testincludes/Makefile diff --git a/tests/testincludes/object.di b/tests/d1/testincludes/object.di similarity index 100% rename from tests/testincludes/object.di rename to tests/d1/testincludes/object.di diff --git a/tests/testincludes/std/IEEE.d b/tests/d1/testincludes/std/IEEE.d similarity index 100% rename from tests/testincludes/std/IEEE.d rename to tests/d1/testincludes/std/IEEE.d diff --git a/tests/testincludes/std/compat.d b/tests/d1/testincludes/std/compat.d similarity index 100% rename from tests/testincludes/std/compat.d rename to tests/d1/testincludes/std/compat.d diff --git a/tests/testincludes/std/gc.d b/tests/d1/testincludes/std/gc.d similarity index 100% rename from tests/testincludes/std/gc.d rename to tests/d1/testincludes/std/gc.d diff --git a/tests/testincludes/std/outofmemory.d b/tests/d1/testincludes/std/outofmemory.d similarity index 100% rename from tests/testincludes/std/outofmemory.d rename to tests/d1/testincludes/std/outofmemory.d diff --git a/tests/testincludes/std/stdarg.d b/tests/d1/testincludes/std/stdarg.d similarity index 100% rename from tests/testincludes/std/stdarg.d rename to tests/d1/testincludes/std/stdarg.d From d1637997581e60e4efd4403df094ad8e85a79a90 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Wed, 29 Aug 2012 11:39:24 +0200 Subject: [PATCH 04/33] Imported D2 testsuite (v2.060) as submodule. --- .gitmodules | 3 +++ tests/d2/dmd-testsuite | 1 + 2 files changed, 4 insertions(+) create mode 160000 tests/d2/dmd-testsuite diff --git a/.gitmodules b/.gitmodules index 550a1db7..7ed0a278 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "phobos"] path = runtime/phobos url = git://github.com/ldc-developers/phobos.git +[submodule "tests/d2/dmd-testsuite"] + path = tests/d2/dmd-testsuite + url = git://github.com/ldc-developers/dmd-testsuite.git diff --git a/tests/d2/dmd-testsuite b/tests/d2/dmd-testsuite new file mode 160000 index 00000000..b28f473a --- /dev/null +++ b/tests/d2/dmd-testsuite @@ -0,0 +1 @@ +Subproject commit b28f473ae5b7e5ee50ec399ccf38d272fbbb21ac From 270979ffd618da73e94f49ad5092576062081b09 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Thu, 30 Aug 2012 14:53:53 +0200 Subject: [PATCH 05/33] Testsuite updates. --- tests/d2/dmd-testsuite | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/d2/dmd-testsuite b/tests/d2/dmd-testsuite index b28f473a..361caa2a 160000 --- a/tests/d2/dmd-testsuite +++ b/tests/d2/dmd-testsuite @@ -1 +1 @@ -Subproject commit b28f473ae5b7e5ee50ec399ccf38d272fbbb21ac +Subproject commit 361caa2ae2697c320bdcfb119e370ab5bb585325 From 31e732911ad35bc052b4f4f3ceeb16680b99b147 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Thu, 30 Aug 2012 15:18:04 +0200 Subject: [PATCH 06/33] Fixed templated interface member call codegen. Fixes DMD testcase 'test7618'. --- gen/toir.cpp | 56 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/gen/toir.cpp b/gen/toir.cpp index 77e17f78..7df9c52f 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -1425,25 +1425,32 @@ DValue* DotVarExp::toElem(IRState* p) { DtoResolveDsymbol(fdecl); - LLValue* funcval; - LLValue* vthis2 = 0; - if (e1type->ty == Tclass) { + // This is a bit more convoluted than it would need to be, because it + // has to take templated interface methods into account, for which + // isFinal is not necessarily true. + const bool nonFinal = !fdecl->isFinal() && + (fdecl->isAbstract() || fdecl->isVirtual()); + + // If we are calling a non-final interface function, we need to get + // the pointer to the underlying object instead of passing the + // interface pointer directly. + LLValue* passedThis = 0; + if (e1type->ty == Tclass) + { TypeClass* tc = static_cast(e1type); - if (tc->sym->isInterfaceDeclaration() && !fdecl->isFinal()) - vthis2 = DtoCastInterfaceToObject(l, NULL)->getRVal(); + if (tc->sym->isInterfaceDeclaration() && nonFinal) + passedThis = DtoCastInterfaceToObject(l, NULL)->getRVal(); } LLValue* vthis = l->getRVal(); - if (!vthis2) vthis2 = vthis; + if (!passedThis) passedThis = vthis; - // - // decide whether this function needs to be looked up in the vtable - // - bool vtbllookup = !fdecl->isFinal() && (fdecl->isAbstract() || fdecl->isVirtual()); - - // even virtual functions are looked up directly if super or DotTypeExp - // are used, thus we need to walk through the this expression and check + // Decide whether this function needs to be looked up in the vtable. + // Even virtual functions are looked up directly if super or DotTypeExp + // are used, thus we need to walk through the this expression and check. + bool vtbllookup = nonFinal; Expression* e = e1; - while (e && vtbllookup) { + while (e && vtbllookup) + { if (e->op == TOKsuper || e->op == TOKdottype) vtbllookup = false; else if (e->op == TOKcast) @@ -1452,20 +1459,21 @@ DValue* DotVarExp::toElem(IRState* p) break; } - // - // look up function - // - if (!vtbllookup) { + // Get the actual function value to call. + LLValue* funcval = 0; + if (vtbllookup) + { + DImValue thisVal(e1type, vthis); + funcval = DtoVirtualFunctionPointer(&thisVal, fdecl, toChars()); + } + else + { fdecl->codegen(Type::sir); funcval = fdecl->ir.irFunc->func; - assert(funcval); - } - else { - DImValue vthis3(e1type, vthis); - funcval = DtoVirtualFunctionPointer(&vthis3, fdecl, toChars()); } + assert(funcval); - return new DFuncValue(fdecl, funcval, vthis2); + return new DFuncValue(fdecl, funcval, passedThis); } else { printf("unsupported dotvarexp: %s\n", var->toChars()); From 0fe41a1f30eb7b5f00614c819f153478f6301133 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Thu, 30 Aug 2012 15:40:03 +0200 Subject: [PATCH 07/33] druntime updates. --- runtime/druntime | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/druntime b/runtime/druntime index a1cb86b9..095197b6 160000 --- a/runtime/druntime +++ b/runtime/druntime @@ -1 +1 @@ -Subproject commit a1cb86b9e1e91eae50494e6904e47d11aa869540 +Subproject commit 095197b629c2098549a2fe50c41c7438c79f101a From 9ac1582726ef82bbf95b1af78ecd9ef364079e97 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Fri, 31 Aug 2012 00:52:01 +0200 Subject: [PATCH 08/33] Update druntime/Phobos library version. --- runtime/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index 63d55c54..3bf28c35 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -15,7 +15,7 @@ else() endif() set(DMDFE_MINOR_VERSION 0) -set(DMDFE_PATCH_VERSION 59) +set(DMDFE_PATCH_VERSION 60) set(DMDFE_VERSION ${D_VERSION}.${DMDFE_MINOR_VERSION}.${DMDFE_PATCH_VERSION}) set(MULTILIB OFF CACHE BOOL "Build both 64-bit and 32-bit libraries") From 508652fd8b90d7590d7aec2f54fb0cbc12b1c4d9 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Fri, 31 Aug 2012 01:11:30 +0200 Subject: [PATCH 09/33] Initialization of vector types with single value. Fixes DMD testcase 'testargtypes'. --- gen/llvmhelpers.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 625dbb7a..30279c26 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -1501,6 +1501,12 @@ LLConstant* DtoConstExpInit(Loc loc, Type* type, Expression* exp) Logger::println("type is a static array, building constant array initializer to single value"); return expand_to_sarray(base, exp); } + else if (base->ty == Tvector) + { + LLConstant* val = exp->toConstElem(gIR); + TypeVector* tv = (TypeVector*)base; + return llvm::ConstantVector::getSplat(tv->size(loc), val); + } else { error("cannot yet convert default initializer %s of type %s to %s", exp->toChars(), exp->type->toChars(), type->toChars()); From 364cfb67145bcd20eb1646145de6c019b1131f4b Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Fri, 31 Aug 2012 01:14:00 +0200 Subject: [PATCH 10/33] Improved initializer ICE error message. --- gen/llvmhelpers.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 30279c26..87854689 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -1509,7 +1509,8 @@ LLConstant* DtoConstExpInit(Loc loc, Type* type, Expression* exp) } else { - error("cannot yet convert default initializer %s of type %s to %s", exp->toChars(), exp->type->toChars(), type->toChars()); + error(loc, "LDC internal error: cannot yet convert default initializer %s of type %s to %s", + exp->toChars(), exp->type->toChars(), type->toChars()); fatal(); } assert(0); From 7a162b6f6d52892a9a580fa6013742a3b630e3c5 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Fri, 31 Aug 2012 01:14:51 +0200 Subject: [PATCH 11/33] Fixed rvalue delegate property access. Covered by DMD testcase 'test42'. --- gen/toir.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/gen/toir.cpp b/gen/toir.cpp index 7df9c52f..6064b17d 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -3116,10 +3116,9 @@ LruntimeInit: DValue* GEPExp::toElem(IRState* p) { - // this should be good enough for now! - DValue* val = e1->toElem(p); - assert(val->isLVal()); - LLValue* v = DtoGEPi(val->getLVal(), 0, index); + // (&a.foo).funcptr is a case where e1->toElem is genuinely not an l-value. + LLValue* val = makeLValue(loc, e1->toElem(p)); + LLValue* v = DtoGEPi(val, 0, index); return new DVarValue(type, DtoBitCast(v, getPtrToType(DtoType(type)))); } From 6fea7358dc3ac8b88e1ca075dee49df42fb470f9 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Fri, 31 Aug 2012 01:58:54 +0200 Subject: [PATCH 12/33] Fixed several asm-related error message formats. --- dmd2/statement.c | 2 +- gen/asm-x86-32.h | 2 +- gen/asm-x86-64.h | 2 +- gen/asmstmt.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dmd2/statement.c b/dmd2/statement.c index 89d6194e..d48a0bab 100644 --- a/dmd2/statement.c +++ b/dmd2/statement.c @@ -5443,7 +5443,7 @@ int AsmStatement::comeFrom() int AsmStatement::blockExit(bool mustNotThrow) { if (mustNotThrow) - error("asm statements are assumed to throw", toChars()); + error("asm statements are assumed to throw"); // Assume the worst return BEfallthru | BEthrow | BEreturn | BEgoto | BEhalt; } diff --git a/gen/asm-x86-32.h b/gen/asm-x86-32.h index 7ae8ccba..127e6704 100644 --- a/gen/asm-x86-32.h +++ b/gen/asm-x86-32.h @@ -2189,7 +2189,7 @@ namespace AsmParserx8632 */ if ( isDollar ( e ) ) { - error ( "dollar labels are not supported", stmt->loc.toChars() ); + stmt->error("dollar labels are not supported"); asmcode->dollarLabel = 1; } else if ( e->op == TOKdsymbol ) diff --git a/gen/asm-x86-64.h b/gen/asm-x86-64.h index 044cba81..f0a5f9a1 100644 --- a/gen/asm-x86-64.h +++ b/gen/asm-x86-64.h @@ -2325,7 +2325,7 @@ namespace AsmParserx8664 */ if ( isDollar ( e ) ) { - error ( "dollar labels are not supported", stmt->loc.toChars() ); + stmt->error("dollar labels are not supported"); asmcode->dollarLabel = 1; } else if ( e->op == TOKdsymbol ) diff --git a/gen/asmstmt.cpp b/gen/asmstmt.cpp index be7da84e..5ae2656c 100644 --- a/gen/asmstmt.cpp +++ b/gen/asmstmt.cpp @@ -187,7 +187,7 @@ int AsmStatement::blockExit(bool mustNotThrow) //printf("AsmStatement::blockExit(%p)\n", this); #if DMDV2 if (mustNotThrow) - error("asm statements are assumed to throw", toChars()); + error("asm statements are assumed to throw"); #endif // Assume the worst return BEfallthru | BEthrow | BEreturn | BEgoto | BEhalt; From c941640d1773def8ea33aed12cf3830eb471adf6 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Fri, 31 Aug 2012 23:31:29 +0200 Subject: [PATCH 13/33] Fixed '-debug' and '-version' handling in LDMD. No idea how the old version once passed the test suite. --- driver/ldmd.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/driver/ldmd.cpp b/driver/ldmd.cpp index 1a8f6687..32bb9bbf 100644 --- a/driver/ldmd.cpp +++ b/driver/ldmd.cpp @@ -593,7 +593,8 @@ Params parseArgs(int originalArgc, char** originalArgv, ls::Path ldcPath) goto Lerror; result.debugLevel = (int)level; } - result.debugIdentifiers.push_back(p + 7); + else + result.debugIdentifiers.push_back(p + 7); } else if (p[6]) goto Lerror; @@ -616,7 +617,8 @@ Params parseArgs(int originalArgc, char** originalArgv, ls::Path ldcPath) goto Lerror; result.versionLevel = (int)level; } - result.versionIdentifiers.push_back(p + 9); + else + result.versionIdentifiers.push_back(p + 9); } else goto Lerror; @@ -769,7 +771,7 @@ void buildCommandLine(std::vector& r, const Params& p) if (p.debugFlag) r.push_back("-d-debug"); if (p.debugLevel) r.push_back(concat("-d-debug=", p.debugLevel)); pushSwitches("-d-debug=", p.debugIdentifiers, r); - if (p.debugLevel) r.push_back(concat("-d-version=", p.versionLevel)); + if (p.versionLevel) r.push_back(concat("-d-version=", p.versionLevel)); pushSwitches("-d-version=", p.versionIdentifiers, r); pushSwitches("-L=", p.linkerSwitches, r); if (p.defaultLibName) r.push_back(concat("-defaultlib=", p.defaultLibName)); From 8ebd2ce5a61896ecbea87fc4ce10d628d74143e0 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 2 Sep 2012 02:07:07 +0200 Subject: [PATCH 14/33] More CRLF->LF line ending conversion. --- gen/irstate.cpp | 350 ++++----- gen/irstate.h | 468 ++++++------ gen/typinf.cpp | 1848 +++++++++++++++++++++++------------------------ 3 files changed, 1333 insertions(+), 1333 deletions(-) diff --git a/gen/irstate.cpp b/gen/irstate.cpp index e2ca388d..73837b1f 100644 --- a/gen/irstate.cpp +++ b/gen/irstate.cpp @@ -1,175 +1,175 @@ -/* DMDFE backend stubs - * This file contains the implementations of the backend routines. - * For dmdfe these do nothing but print a message saying the module - * has been parsed. Substitute your own behaviors for these routimes. - */ - -#include - -#include "gen/llvm.h" - -#include "mtype.h" -#include "declaration.h" -#include "statement.h" - -#include "gen/irstate.h" -#include "tollvm.h" - -IRState* gIR = 0; -llvm::TargetMachine* gTargetMachine = 0; -const llvm::TargetData* gTargetData = 0; -TargetABI* gABI = 0; - -////////////////////////////////////////////////////////////////////////////////////////// -IRScope::IRScope() - : builder(gIR->context()) -{ - begin = end = NULL; -} - -IRScope::IRScope(llvm::BasicBlock* b, llvm::BasicBlock* e) - : builder(b) -{ - begin = b; - end = e; -} - -const IRScope& IRScope::operator=(const IRScope& rhs) -{ - begin = rhs.begin; - end = rhs.end; - builder.SetInsertPoint(begin); - return *this; -} - -////////////////////////////////////////////////////////////////////////////////////////// -IRTargetScope::IRTargetScope() -{ -} - -IRTargetScope::IRTargetScope(Statement* s, EnclosingHandler* enclosinghandler, llvm::BasicBlock* continueTarget, llvm::BasicBlock* breakTarget) -{ - this->s = s; - this->enclosinghandler = enclosinghandler; - this->breakTarget = breakTarget; - this->continueTarget = continueTarget; -} - -////////////////////////////////////////////////////////////////////////////////////////// -IRState::IRState(llvm::Module* m) - : module(m), dibuilder(*m) -{ - interfaceInfoType = NULL; - mutexType = NULL; - moduleRefType = NULL; - - dmodule = 0; - emitMain = false; - mainFunc = 0; - ir.state = this; - asmBlock = NULL; -} - -IrFunction* IRState::func() -{ - assert(!functions.empty() && "Function stack is empty!"); - return functions.back(); -} - -llvm::Function* IRState::topfunc() -{ - assert(!functions.empty() && "Function stack is empty!"); - return functions.back()->func; -} - -TypeFunction* IRState::topfunctype() -{ - assert(!functions.empty() && "Function stack is empty!"); - return functions.back()->type; -} - -llvm::Instruction* IRState::topallocapoint() -{ - assert(!functions.empty() && "AllocaPoint stack is empty!"); - return functions.back()->allocapoint; -} - -IrStruct* IRState::topstruct() -{ - assert(!structs.empty() && "Struct vector is empty!"); - return structs.back(); -} - -IRScope& IRState::scope() -{ - assert(!scopes.empty()); - return scopes.back(); -} - -llvm::BasicBlock* IRState::scopebb() -{ - IRScope& s = scope(); - assert(s.begin); - return s.begin; -} -llvm::BasicBlock* IRState::scopeend() -{ - IRScope& s = scope(); - assert(s.end); - return s.end; -} -bool IRState::scopereturned() -{ - //return scope().returned; - return !scopebb()->empty() && scopebb()->back().isTerminator(); -} - -LLCallSite IRState::CreateCallOrInvoke(LLValue* Callee, const char* Name) -{ - LLSmallVector args; - return CreateCallOrInvoke(Callee, args, Name); -} - -LLCallSite IRState::CreateCallOrInvoke(LLValue* Callee, LLValue* Arg1, const char* Name) -{ - LLSmallVector args; - args.push_back(Arg1); - return CreateCallOrInvoke(Callee, args, Name); -} - -LLCallSite IRState::CreateCallOrInvoke2(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, const char* Name) -{ - LLSmallVector args; - args.push_back(Arg1); - args.push_back(Arg2); - return CreateCallOrInvoke(Callee, args, Name); -} - -LLCallSite IRState::CreateCallOrInvoke3(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, LLValue* Arg3, const char* Name) -{ - LLSmallVector args; - args.push_back(Arg1); - args.push_back(Arg2); - args.push_back(Arg3); - return CreateCallOrInvoke(Callee, args, Name); -} - -LLCallSite IRState::CreateCallOrInvoke4(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, LLValue* Arg3, LLValue* Arg4, const char* Name) -{ - LLSmallVector args; - args.push_back(Arg1); - args.push_back(Arg2); - args.push_back(Arg3); - args.push_back(Arg4); - return CreateCallOrInvoke(Callee, args, Name); -} - - -////////////////////////////////////////////////////////////////////////////////////////// - -IRBuilder<>* IRBuilderHelper::operator->() -{ - IRBuilder<>& b = state->scope().builder; - assert(b.GetInsertBlock() != NULL); - return &b; -} +/* DMDFE backend stubs + * This file contains the implementations of the backend routines. + * For dmdfe these do nothing but print a message saying the module + * has been parsed. Substitute your own behaviors for these routimes. + */ + +#include + +#include "gen/llvm.h" + +#include "mtype.h" +#include "declaration.h" +#include "statement.h" + +#include "gen/irstate.h" +#include "tollvm.h" + +IRState* gIR = 0; +llvm::TargetMachine* gTargetMachine = 0; +const llvm::TargetData* gTargetData = 0; +TargetABI* gABI = 0; + +////////////////////////////////////////////////////////////////////////////////////////// +IRScope::IRScope() + : builder(gIR->context()) +{ + begin = end = NULL; +} + +IRScope::IRScope(llvm::BasicBlock* b, llvm::BasicBlock* e) + : builder(b) +{ + begin = b; + end = e; +} + +const IRScope& IRScope::operator=(const IRScope& rhs) +{ + begin = rhs.begin; + end = rhs.end; + builder.SetInsertPoint(begin); + return *this; +} + +////////////////////////////////////////////////////////////////////////////////////////// +IRTargetScope::IRTargetScope() +{ +} + +IRTargetScope::IRTargetScope(Statement* s, EnclosingHandler* enclosinghandler, llvm::BasicBlock* continueTarget, llvm::BasicBlock* breakTarget) +{ + this->s = s; + this->enclosinghandler = enclosinghandler; + this->breakTarget = breakTarget; + this->continueTarget = continueTarget; +} + +////////////////////////////////////////////////////////////////////////////////////////// +IRState::IRState(llvm::Module* m) + : module(m), dibuilder(*m) +{ + interfaceInfoType = NULL; + mutexType = NULL; + moduleRefType = NULL; + + dmodule = 0; + emitMain = false; + mainFunc = 0; + ir.state = this; + asmBlock = NULL; +} + +IrFunction* IRState::func() +{ + assert(!functions.empty() && "Function stack is empty!"); + return functions.back(); +} + +llvm::Function* IRState::topfunc() +{ + assert(!functions.empty() && "Function stack is empty!"); + return functions.back()->func; +} + +TypeFunction* IRState::topfunctype() +{ + assert(!functions.empty() && "Function stack is empty!"); + return functions.back()->type; +} + +llvm::Instruction* IRState::topallocapoint() +{ + assert(!functions.empty() && "AllocaPoint stack is empty!"); + return functions.back()->allocapoint; +} + +IrStruct* IRState::topstruct() +{ + assert(!structs.empty() && "Struct vector is empty!"); + return structs.back(); +} + +IRScope& IRState::scope() +{ + assert(!scopes.empty()); + return scopes.back(); +} + +llvm::BasicBlock* IRState::scopebb() +{ + IRScope& s = scope(); + assert(s.begin); + return s.begin; +} +llvm::BasicBlock* IRState::scopeend() +{ + IRScope& s = scope(); + assert(s.end); + return s.end; +} +bool IRState::scopereturned() +{ + //return scope().returned; + return !scopebb()->empty() && scopebb()->back().isTerminator(); +} + +LLCallSite IRState::CreateCallOrInvoke(LLValue* Callee, const char* Name) +{ + LLSmallVector args; + return CreateCallOrInvoke(Callee, args, Name); +} + +LLCallSite IRState::CreateCallOrInvoke(LLValue* Callee, LLValue* Arg1, const char* Name) +{ + LLSmallVector args; + args.push_back(Arg1); + return CreateCallOrInvoke(Callee, args, Name); +} + +LLCallSite IRState::CreateCallOrInvoke2(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, const char* Name) +{ + LLSmallVector args; + args.push_back(Arg1); + args.push_back(Arg2); + return CreateCallOrInvoke(Callee, args, Name); +} + +LLCallSite IRState::CreateCallOrInvoke3(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, LLValue* Arg3, const char* Name) +{ + LLSmallVector args; + args.push_back(Arg1); + args.push_back(Arg2); + args.push_back(Arg3); + return CreateCallOrInvoke(Callee, args, Name); +} + +LLCallSite IRState::CreateCallOrInvoke4(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, LLValue* Arg3, LLValue* Arg4, const char* Name) +{ + LLSmallVector args; + args.push_back(Arg1); + args.push_back(Arg2); + args.push_back(Arg3); + args.push_back(Arg4); + return CreateCallOrInvoke(Callee, args, Name); +} + + +////////////////////////////////////////////////////////////////////////////////////////// + +IRBuilder<>* IRBuilderHelper::operator->() +{ + IRBuilder<>& b = state->scope().builder; + assert(b.GetInsertBlock() != NULL); + return &b; +} diff --git a/gen/irstate.h b/gen/irstate.h index 3c4c7804..e4aa387c 100644 --- a/gen/irstate.h +++ b/gen/irstate.h @@ -1,234 +1,234 @@ -#ifndef LDC_GEN_IRSTATE_H -#define LDC_GEN_IRSTATE_H - -#include -#include -#include -#include - -#include "root.h" -#include "aggregate.h" - -#include "ir/irfunction.h" -#include "ir/irstruct.h" -#include "ir/irvar.h" - -#if LDC_LLVM_VER >= 302 -#include "llvm/DIBuilder.h" -#else -#include "llvm/Analysis/DIBuilder.h" -#endif -#include "llvm/Support/CallSite.h" - -namespace llvm { - class LLVMContext; - class TargetMachine; -} - -// global ir state for current module -struct IRState; -struct TargetABI; - -extern IRState* gIR; -extern llvm::TargetMachine* gTargetMachine; -extern const llvm::TargetData* gTargetData; -extern TargetABI* gABI; - -struct TypeFunction; -struct TypeStruct; -struct ClassDeclaration; -struct FuncDeclaration; -struct Module; -struct TypeStruct; -struct BaseClass; -struct AnonDeclaration; - -struct IrModule; - -// represents a scope -struct IRScope -{ - llvm::BasicBlock* begin; - llvm::BasicBlock* end; - IRBuilder<> builder; - - IRScope(); - IRScope(llvm::BasicBlock* b, llvm::BasicBlock* e); - - const IRScope& operator=(const IRScope& rhs); - -#if DMDV2 - // list of variables needing destruction - std::vector varsInScope; -#endif -}; - -struct IRBuilderHelper -{ - IRState* state; - IRBuilder<>* operator->(); -}; - -struct IRAsmStmt -{ - IRAsmStmt() - : isBranchToLabel(NULL) {} - - std::string code; - std::string out_c; - std::string in_c; - std::vector out; - std::vector in; - - // if this is nonzero, it contains the target label - Identifier* isBranchToLabel; -}; - -struct IRAsmBlock -{ - std::deque s; - std::set clobs; - size_t outputcount; - - // stores the labels within the asm block - std::vector internalLabels; - - AsmBlockStatement* asmBlock; - LLType* retty; - unsigned retn; - bool retemu; // emulate abi ret with a temporary - LLValue* (*retfixup)(IRBuilderHelper b, LLValue* orig); // Modifies retval - - IRAsmBlock(AsmBlockStatement* b) - : outputcount(0), asmBlock(b), retty(NULL), retn(0), retemu(false), - retfixup(NULL) - {} -}; - -// represents the module -struct IRState -{ - IRState(llvm::Module* m); - - // module - Module* dmodule; - llvm::Module* module; - - // interface info type, used in DtoInterfaceInfoType - LLStructType* interfaceInfoType; - LLStructType* mutexType; - LLStructType* moduleRefType; - - // helper to get the LLVMContext of the module - llvm::LLVMContext& context() const { return module->getContext(); } - - // functions - typedef std::vector FunctionVector; - FunctionVector functions; - IrFunction* func(); - - llvm::Function* topfunc(); - TypeFunction* topfunctype(); - llvm::Instruction* topallocapoint(); - - // structs - typedef std::vector StructVector; - StructVector structs; - IrStruct* topstruct(); - - // D main function - bool emitMain; - llvm::Function* mainFunc; - - // basic block scopes - std::vector scopes; - IRScope& scope(); -#if DMDV2 - std::vector &varsInScope() { return scope().varsInScope; } -#endif - llvm::BasicBlock* scopebb(); - llvm::BasicBlock* scopeend(); - bool scopereturned(); - - // create a call or invoke, depending on the landing pad info - // the template function is defined further down in this file - template - llvm::CallSite CreateCallOrInvoke(LLValue* Callee, const T& args, const char* Name=""); - llvm::CallSite CreateCallOrInvoke(LLValue* Callee, const char* Name=""); - llvm::CallSite CreateCallOrInvoke(LLValue* Callee, LLValue* Arg1, const char* Name=""); - llvm::CallSite CreateCallOrInvoke2(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, const char* Name=""); - llvm::CallSite CreateCallOrInvoke3(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, LLValue* Arg3, const char* Name=""); - llvm::CallSite CreateCallOrInvoke4(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, LLValue* Arg3, LLValue* Arg4, const char* Name=""); - - // this holds the array being indexed or sliced so $ will work - // might be a better way but it works. problem is I only get a - // VarDeclaration for __dollar, but I can't see how to get the - // array pointer from this :( - std::vector arrays; - - // builder helper - IRBuilderHelper ir; - - // debug info helper - llvm::DIBuilder dibuilder; - - // static ctors/dtors/unittests - typedef std::list FuncDeclList; - typedef std::list GatesList; - FuncDeclList ctors; - FuncDeclList dtors; -#if DMDV2 - FuncDeclList sharedCtors; - FuncDeclList sharedDtors; - GatesList gates; - GatesList sharedGates; -#endif - FuncDeclList unitTests; - - // all template instances that had members emitted - // currently only filled for singleobj - // used to make sure the complete template instance gets emitted in the - // first file that touches a member, see #318 - typedef std::set TemplateInstanceSet; - TemplateInstanceSet seenTemplateInstances; - - // for inline asm - IRAsmBlock* asmBlock; - std::ostringstream nakedAsm; - - // 'used' array solely for keeping a reference to globals - std::vector usedArray; -}; - -template -llvm::CallSite IRState::CreateCallOrInvoke(LLValue* Callee, const T &args, const char* Name) -{ - llvm::BasicBlock* pad = func()->gen->landingPad; - if(pad) - { - // intrinsics don't support invoking and 'nounwind' functions don't need it. - LLFunction* funcval = llvm::dyn_cast(Callee); - if (funcval && (funcval->isIntrinsic() || funcval->doesNotThrow())) - { - llvm::CallInst* call = ir->CreateCall(Callee, args, Name); - call->setAttributes(funcval->getAttributes()); - return call; - } - - llvm::BasicBlock* postinvoke = llvm::BasicBlock::Create(gIR->context(), "postinvoke", topfunc(), scopeend()); - llvm::InvokeInst* invoke = ir->CreateInvoke(Callee, postinvoke, pad, args, Name); - if (LLFunction* fn = llvm::dyn_cast(Callee)) - invoke->setAttributes(fn->getAttributes()); - scope() = IRScope(postinvoke, scopeend()); - return invoke; - } - else - { - llvm::CallInst* call = ir->CreateCall(Callee, args, Name); - if (LLFunction* fn = llvm::dyn_cast(Callee)) - call->setAttributes(fn->getAttributes()); - return call; - } -} - -#endif // LDC_GEN_IRSTATE_H +#ifndef LDC_GEN_IRSTATE_H +#define LDC_GEN_IRSTATE_H + +#include +#include +#include +#include + +#include "root.h" +#include "aggregate.h" + +#include "ir/irfunction.h" +#include "ir/irstruct.h" +#include "ir/irvar.h" + +#if LDC_LLVM_VER >= 302 +#include "llvm/DIBuilder.h" +#else +#include "llvm/Analysis/DIBuilder.h" +#endif +#include "llvm/Support/CallSite.h" + +namespace llvm { + class LLVMContext; + class TargetMachine; +} + +// global ir state for current module +struct IRState; +struct TargetABI; + +extern IRState* gIR; +extern llvm::TargetMachine* gTargetMachine; +extern const llvm::TargetData* gTargetData; +extern TargetABI* gABI; + +struct TypeFunction; +struct TypeStruct; +struct ClassDeclaration; +struct FuncDeclaration; +struct Module; +struct TypeStruct; +struct BaseClass; +struct AnonDeclaration; + +struct IrModule; + +// represents a scope +struct IRScope +{ + llvm::BasicBlock* begin; + llvm::BasicBlock* end; + IRBuilder<> builder; + + IRScope(); + IRScope(llvm::BasicBlock* b, llvm::BasicBlock* e); + + const IRScope& operator=(const IRScope& rhs); + +#if DMDV2 + // list of variables needing destruction + std::vector varsInScope; +#endif +}; + +struct IRBuilderHelper +{ + IRState* state; + IRBuilder<>* operator->(); +}; + +struct IRAsmStmt +{ + IRAsmStmt() + : isBranchToLabel(NULL) {} + + std::string code; + std::string out_c; + std::string in_c; + std::vector out; + std::vector in; + + // if this is nonzero, it contains the target label + Identifier* isBranchToLabel; +}; + +struct IRAsmBlock +{ + std::deque s; + std::set clobs; + size_t outputcount; + + // stores the labels within the asm block + std::vector internalLabels; + + AsmBlockStatement* asmBlock; + LLType* retty; + unsigned retn; + bool retemu; // emulate abi ret with a temporary + LLValue* (*retfixup)(IRBuilderHelper b, LLValue* orig); // Modifies retval + + IRAsmBlock(AsmBlockStatement* b) + : outputcount(0), asmBlock(b), retty(NULL), retn(0), retemu(false), + retfixup(NULL) + {} +}; + +// represents the module +struct IRState +{ + IRState(llvm::Module* m); + + // module + Module* dmodule; + llvm::Module* module; + + // interface info type, used in DtoInterfaceInfoType + LLStructType* interfaceInfoType; + LLStructType* mutexType; + LLStructType* moduleRefType; + + // helper to get the LLVMContext of the module + llvm::LLVMContext& context() const { return module->getContext(); } + + // functions + typedef std::vector FunctionVector; + FunctionVector functions; + IrFunction* func(); + + llvm::Function* topfunc(); + TypeFunction* topfunctype(); + llvm::Instruction* topallocapoint(); + + // structs + typedef std::vector StructVector; + StructVector structs; + IrStruct* topstruct(); + + // D main function + bool emitMain; + llvm::Function* mainFunc; + + // basic block scopes + std::vector scopes; + IRScope& scope(); +#if DMDV2 + std::vector &varsInScope() { return scope().varsInScope; } +#endif + llvm::BasicBlock* scopebb(); + llvm::BasicBlock* scopeend(); + bool scopereturned(); + + // create a call or invoke, depending on the landing pad info + // the template function is defined further down in this file + template + llvm::CallSite CreateCallOrInvoke(LLValue* Callee, const T& args, const char* Name=""); + llvm::CallSite CreateCallOrInvoke(LLValue* Callee, const char* Name=""); + llvm::CallSite CreateCallOrInvoke(LLValue* Callee, LLValue* Arg1, const char* Name=""); + llvm::CallSite CreateCallOrInvoke2(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, const char* Name=""); + llvm::CallSite CreateCallOrInvoke3(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, LLValue* Arg3, const char* Name=""); + llvm::CallSite CreateCallOrInvoke4(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, LLValue* Arg3, LLValue* Arg4, const char* Name=""); + + // this holds the array being indexed or sliced so $ will work + // might be a better way but it works. problem is I only get a + // VarDeclaration for __dollar, but I can't see how to get the + // array pointer from this :( + std::vector arrays; + + // builder helper + IRBuilderHelper ir; + + // debug info helper + llvm::DIBuilder dibuilder; + + // static ctors/dtors/unittests + typedef std::list FuncDeclList; + typedef std::list GatesList; + FuncDeclList ctors; + FuncDeclList dtors; +#if DMDV2 + FuncDeclList sharedCtors; + FuncDeclList sharedDtors; + GatesList gates; + GatesList sharedGates; +#endif + FuncDeclList unitTests; + + // all template instances that had members emitted + // currently only filled for singleobj + // used to make sure the complete template instance gets emitted in the + // first file that touches a member, see #318 + typedef std::set TemplateInstanceSet; + TemplateInstanceSet seenTemplateInstances; + + // for inline asm + IRAsmBlock* asmBlock; + std::ostringstream nakedAsm; + + // 'used' array solely for keeping a reference to globals + std::vector usedArray; +}; + +template +llvm::CallSite IRState::CreateCallOrInvoke(LLValue* Callee, const T &args, const char* Name) +{ + llvm::BasicBlock* pad = func()->gen->landingPad; + if(pad) + { + // intrinsics don't support invoking and 'nounwind' functions don't need it. + LLFunction* funcval = llvm::dyn_cast(Callee); + if (funcval && (funcval->isIntrinsic() || funcval->doesNotThrow())) + { + llvm::CallInst* call = ir->CreateCall(Callee, args, Name); + call->setAttributes(funcval->getAttributes()); + return call; + } + + llvm::BasicBlock* postinvoke = llvm::BasicBlock::Create(gIR->context(), "postinvoke", topfunc(), scopeend()); + llvm::InvokeInst* invoke = ir->CreateInvoke(Callee, postinvoke, pad, args, Name); + if (LLFunction* fn = llvm::dyn_cast(Callee)) + invoke->setAttributes(fn->getAttributes()); + scope() = IRScope(postinvoke, scopeend()); + return invoke; + } + else + { + llvm::CallInst* call = ir->CreateCall(Callee, args, Name); + if (LLFunction* fn = llvm::dyn_cast(Callee)) + call->setAttributes(fn->getAttributes()); + return call; + } +} + +#endif // LDC_GEN_IRSTATE_H diff --git a/gen/typinf.cpp b/gen/typinf.cpp index 2dca8aa6..acd2264e 100644 --- a/gen/typinf.cpp +++ b/gen/typinf.cpp @@ -1,924 +1,924 @@ - - -// Copyright (c) 1999-2004 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// 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. - -// Modifications for LDC: -// Copyright (c) 2007 by Tomas Lindquist Olsen -// tomas at famolsen dk - -#include -#include - -#include "gen/llvm.h" - -#include "mars.h" -#include "module.h" -#include "mtype.h" -#include "scope.h" -#include "init.h" -#include "expression.h" -#include "attrib.h" -#include "declaration.h" -#include "template.h" -#include "id.h" -#include "enum.h" -#include "import.h" -#include "aggregate.h" - -#include "gen/irstate.h" -#include "gen/logger.h" -#include "gen/runtime.h" -#include "gen/tollvm.h" -#include "gen/llvmhelpers.h" -#include "gen/arrays.h" -#include "gen/structs.h" -#include "gen/classes.h" -#include "gen/linkage.h" -#include "gen/metadata.h" -#include "gen/rttibuilder.h" - -#include "ir/irvar.h" -#include "ir/irtype.h" - -/******************************************* - * Get a canonicalized form of the TypeInfo for use with the internal - * runtime library routines. Canonicalized in that static arrays are - * represented as dynamic arrays, enums are represented by their - * underlying type, etc. This reduces the number of TypeInfo's needed, - * so we can use the custom internal ones more. - */ - -Expression *Type::getInternalTypeInfo(Scope *sc) -{ TypeInfoDeclaration *tid; - Expression *e; - Type *t; - static TypeInfoDeclaration *internalTI[TMAX]; - - //printf("Type::getInternalTypeInfo() %s\n", toChars()); - t = toBasetype(); - switch (t->ty) - { - case Tsarray: -#if 0 - // convert to corresponding dynamic array type - t = t->nextOf()->mutableOf()->arrayOf(); -#endif - break; - - case Tclass: - if (static_cast(t)->sym->isInterfaceDeclaration()) - break; - goto Linternal; - - case Tarray: - #if DMDV2 - // convert to corresponding dynamic array type - t = t->nextOf()->mutableOf()->arrayOf(); - #endif - if (t->nextOf()->ty != Tclass) - break; - goto Linternal; - - case Tfunction: - case Tdelegate: - case Tpointer: - Linternal: - tid = internalTI[t->ty]; - if (!tid) - { tid = new TypeInfoDeclaration(t, 1); - internalTI[t->ty] = tid; - } - e = new VarExp(0, tid); - e = e->addressOf(sc); - e->type = tid->type; // do this so we don't get redundant dereference - return e; - - default: - break; - } - //printf("\tcalling getTypeInfo() %s\n", t->toChars()); - return t->getTypeInfo(sc); -} - -/**************************************************** - * Get the exact TypeInfo. - */ - -Expression *Type::getTypeInfo(Scope *sc) -{ - //printf("Type::getTypeInfo() %p, %s\n", this, toChars()); - if (!Type::typeinfo) - { - error(0, "TypeInfo not found. object.d may be incorrectly installed or corrupt, compile with -v switch"); - fatal(); - } - - Expression *e = 0; - Type *t = merge2(); // do this since not all Type's are merge'd - - if (!t->vtinfo) - { -#if DMDV2 - if (t->isShared()) - t->vtinfo = new TypeInfoSharedDeclaration(t); - else if (t->isConst()) - t->vtinfo = new TypeInfoConstDeclaration(t); - else if (t->isImmutable()) - t->vtinfo = new TypeInfoInvariantDeclaration(t); - else if (t->isWild()) - t->vtinfo = new TypeInfoWildDeclaration(t); - else -#endif - t->vtinfo = t->getTypeInfoDeclaration(); - assert(t->vtinfo); - - /* If this has a custom implementation in std/typeinfo, then - * do not generate a COMDAT for it. - */ - if (!t->builtinTypeInfo()) - { // Generate COMDAT - if (sc) // if in semantic() pass - { // Find module that will go all the way to an object file - Module *m = sc->module->importedFrom; - m->members->push(t->vtinfo); - } - else // if in obj generation pass - { -#if IN_DMD - t->vtinfo->toObjFile(0); // TODO: multiobj -#else - t->vtinfo->codegen(sir); -#endif - } - } - } - e = new VarExp(0, t->vtinfo); - e = e->addressOf(sc); - e->type = t->vtinfo->type; // do this so we don't get redundant dereference - return e; -} - -enum RET TypeFunction::retStyle() -{ - return RETstack; -} - -TypeInfoDeclaration *Type::getTypeInfoDeclaration() -{ - //printf("Type::getTypeInfoDeclaration() %s\n", toChars()); - return new TypeInfoDeclaration(this, 0); -} - -TypeInfoDeclaration *TypeTypedef::getTypeInfoDeclaration() -{ - return new TypeInfoTypedefDeclaration(this); -} - -TypeInfoDeclaration *TypePointer::getTypeInfoDeclaration() -{ - return new TypeInfoPointerDeclaration(this); -} - -TypeInfoDeclaration *TypeDArray::getTypeInfoDeclaration() -{ - return new TypeInfoArrayDeclaration(this); -} - -TypeInfoDeclaration *TypeSArray::getTypeInfoDeclaration() -{ - return new TypeInfoStaticArrayDeclaration(this); -} - -TypeInfoDeclaration *TypeAArray::getTypeInfoDeclaration() -{ - return new TypeInfoAssociativeArrayDeclaration(this); -} - -TypeInfoDeclaration *TypeStruct::getTypeInfoDeclaration() -{ - return new TypeInfoStructDeclaration(this); -} - -TypeInfoDeclaration *TypeClass::getTypeInfoDeclaration() -{ - if (sym->isInterfaceDeclaration()) - return new TypeInfoInterfaceDeclaration(this); - else - return new TypeInfoClassDeclaration(this); -} - -#if DMDV2 -TypeInfoDeclaration *TypeVector::getTypeInfoDeclaration() -{ - return new TypeInfoVectorDeclaration(this); -} -#endif - -TypeInfoDeclaration *TypeEnum::getTypeInfoDeclaration() -{ - return new TypeInfoEnumDeclaration(this); -} - -TypeInfoDeclaration *TypeFunction::getTypeInfoDeclaration() -{ - return new TypeInfoFunctionDeclaration(this); -} - -TypeInfoDeclaration *TypeDelegate::getTypeInfoDeclaration() -{ - return new TypeInfoDelegateDeclaration(this); -} - -TypeInfoDeclaration *TypeTuple::getTypeInfoDeclaration() -{ - return new TypeInfoTupleDeclaration(this); -} - -/* ========================================================================= */ - -/* These decide if there's an instance for them already in std.typeinfo, - * because then the compiler doesn't need to build one. - */ - -int Type::builtinTypeInfo() -{ - return 0; -} - -int TypeBasic::builtinTypeInfo() -{ -#if DMDV2 - return mod ? 0 : 1; -#else - return 1; -#endif -} - -int TypeDArray::builtinTypeInfo() -{ -#if DMDV2 - return !mod && (next->isTypeBasic() != NULL && !next->mod || - // strings are so common, make them builtin - next->ty == Tchar && next->mod == MODimmutable); -#else - return next->isTypeBasic() != NULL; -#endif -} - -int TypeClass::builtinTypeInfo() -{ - /* This is statically put out with the ClassInfo, so - * claim it is built in so it isn't regenerated by each module. - */ -#if IN_DMD - return mod ? 0 : 1; -#elif IN_LLVM - // FIXME if I enable this, the way LDC does typeinfo will cause a bunch - // of linker errors to missing class typeinfo definitions. - return 0; -#endif -} - -/* ========================================================================= */ - -////////////////////////////////////////////////////////////////////////////// -// MAGIC PLACE -// (wut?) -////////////////////////////////////////////////////////////////////////////// - -void DtoResolveTypeInfo(TypeInfoDeclaration* tid); -void DtoDeclareTypeInfo(TypeInfoDeclaration* tid); - -void TypeInfoDeclaration::codegen(Ir*) -{ - DtoResolveTypeInfo(this); -} - -void DtoResolveTypeInfo(TypeInfoDeclaration* tid) -{ - if (tid->ir.resolved) return; - tid->ir.resolved = true; - - Logger::println("DtoResolveTypeInfo(%s)", tid->toChars()); - LOG_SCOPE; - - std::string mangle(tid->mangle()); - - IrGlobal* irg = new IrGlobal(tid); - irg->value = gIR->module->getGlobalVariable(mangle); - - if (!irg->value) { - if (tid->tinfo->builtinTypeInfo()) // this is a declaration of a builtin __initZ var - irg->type = Type::typeinfo->type->irtype->getType(); - else - irg->type = LLStructType::create(gIR->context(), tid->toPrettyChars()); - irg->value = new llvm::GlobalVariable(*gIR->module, irg->type, true, - TYPEINFO_LINKAGE_TYPE, NULL, mangle); - } else { - irg->type = irg->value->getType()->getContainedType(0); - } - - tid->ir.irGlobal = irg; - -#if USE_METADATA - // don't do this for void or llvm will crash - if (tid->tinfo->ty != Tvoid) { - // Add some metadata for use by optimization passes. - std::string metaname = std::string(TD_PREFIX) + mangle; - llvm::NamedMDNode* meta = gIR->module->getNamedMetadata(metaname); - // Don't generate metadata for non-concrete types - // (such as tuple types, slice types, typeof(expr), etc.) - if (!meta && tid->tinfo->toBasetype()->ty < Terror) { - // Construct the fields - MDNodeField* mdVals[TD_NumFields]; - if (TD_Confirm >= 0) - mdVals[TD_Confirm] = llvm::cast(irg->value); - mdVals[TD_Type] = llvm::UndefValue::get(DtoType(tid->tinfo)); - // Construct the metadata - llvm::MetadataBase* metadata = llvm::MDNode::get(gIR->context(), mdVals, TD_NumFields); - // Insert it into the module - llvm::NamedMDNode::Create(gIR->context(), metaname, &metadata, 1, gIR->module); - } - } -#endif // USE_METADATA - - DtoDeclareTypeInfo(tid); -} - -void DtoDeclareTypeInfo(TypeInfoDeclaration* tid) -{ - DtoResolveTypeInfo(tid); - - if (tid->ir.declared) return; - tid->ir.declared = true; - - Logger::println("DtoDeclareTypeInfo(%s)", tid->toChars()); - LOG_SCOPE; - - if (Logger::enabled()) - { - std::string mangled(tid->mangle()); - Logger::println("type = '%s'", tid->tinfo->toChars()); - Logger::println("typeinfo mangle: %s", mangled.c_str()); - } - - IrGlobal* irg = tid->ir.irGlobal; - assert(irg->value != NULL); - - // this is a declaration of a builtin __initZ var - if (tid->tinfo->builtinTypeInfo()) { - LLGlobalVariable* g = isaGlobalVar(irg->value); - g->setLinkage(llvm::GlobalValue::ExternalLinkage); - return; - } - - // define custom typedef - tid->llvmDefine(); -} - -/* ========================================================================= */ - -void TypeInfoDeclaration::llvmDefine() -{ - Logger::println("TypeInfoDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - RTTIBuilder b(Type::typeinfo); - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoTypedefDeclaration::llvmDefine() -{ - Logger::println("TypeInfoTypedefDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - RTTIBuilder b(Type::typeinfotypedef); - - assert(tinfo->ty == Ttypedef); - TypeTypedef *tc = static_cast(tinfo); - TypedefDeclaration *sd = tc->sym; - - // TypeInfo base - sd->basetype = sd->basetype->merge(); // dmd does it ... why? - b.push_typeinfo(sd->basetype); - - // char[] name - b.push_string(sd->toPrettyChars()); - - // void[] init - // emit null array if we should use the basetype, or if the basetype - // uses default initialization. - if (tinfo->isZeroInit(0) || !sd->init) - { - b.push_null_void_array(); - } - // otherwise emit a void[] with the default initializer - else - { - LLConstant* C = DtoConstInitializer(sd->loc, sd->basetype, sd->init); - b.push_void_array(C, sd->basetype, sd); - } - - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoEnumDeclaration::llvmDefine() -{ - Logger::println("TypeInfoEnumDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - RTTIBuilder b(Type::typeinfoenum); - - assert(tinfo->ty == Tenum); - TypeEnum *tc = static_cast(tinfo); - EnumDeclaration *sd = tc->sym; - - // TypeInfo base - b.push_typeinfo(sd->memtype); - - // char[] name - b.push_string(sd->toPrettyChars()); - - // void[] init - // emit void[] with the default initialier, the array is null if the default - // initializer is zero - if (!sd->defaultval || tinfo->isZeroInit(0)) - { - b.push_null_void_array(); - } - // otherwise emit a void[] with the default initializer - else - { - LLType* memty = DtoType(sd->memtype); -#if DMDV2 - LLConstant* C = LLConstantInt::get(memty, sd->defaultval->toInteger(), !sd->memtype->isunsigned()); -#else - LLConstant* C = LLConstantInt::get(memty, sd->defaultval, !sd->memtype->isunsigned()); -#endif - b.push_void_array(C, sd->memtype, sd); - } - - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoPointerDeclaration::llvmDefine() -{ - Logger::println("TypeInfoPointerDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - RTTIBuilder b(Type::typeinfopointer); - // TypeInfo base - b.push_typeinfo(tinfo->nextOf()); - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoArrayDeclaration::llvmDefine() -{ - Logger::println("TypeInfoArrayDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - RTTIBuilder b(Type::typeinfoarray); - // TypeInfo base - b.push_typeinfo(tinfo->nextOf()); - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoStaticArrayDeclaration::llvmDefine() -{ - Logger::println("TypeInfoStaticArrayDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - assert(tinfo->ty == Tsarray); - TypeSArray *tc = static_cast(tinfo); - - RTTIBuilder b(Type::typeinfostaticarray); - - // value typeinfo - b.push_typeinfo(tc->nextOf()); - - // length - b.push(DtoConstSize_t(static_cast(tc->dim->toUInteger()))); - - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoAssociativeArrayDeclaration::llvmDefine() -{ - Logger::println("TypeInfoAssociativeArrayDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - assert(tinfo->ty == Taarray); - TypeAArray *tc = static_cast(tinfo); - - RTTIBuilder b(Type::typeinfoassociativearray); - - // value typeinfo - b.push_typeinfo(tc->nextOf()); - - // key typeinfo - b.push_typeinfo(tc->index); - -#if DMDV2 - // impl typeinfo - b.push_typeinfo(tc->getImpl()->type); -#endif - - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoFunctionDeclaration::llvmDefine() -{ - Logger::println("TypeInfoFunctionDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - RTTIBuilder b(Type::typeinfofunction); - // TypeInfo base - b.push_typeinfo(tinfo->nextOf()); - // string deco - b.push_string(tinfo->deco); - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoDelegateDeclaration::llvmDefine() -{ - Logger::println("TypeInfoDelegateDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - assert(tinfo->ty == Tdelegate); - Type* ret_type = tinfo->nextOf()->nextOf(); - - RTTIBuilder b(Type::typeinfodelegate); - // TypeInfo base - b.push_typeinfo(ret_type); - // string deco - b.push_string(tinfo->deco); - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -static FuncDeclaration* find_method_overload(AggregateDeclaration* ad, Identifier* id, TypeFunction* tf, Module* mod) -{ - Dsymbol *s = search_function(ad, id); - FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL; - if (fdx) - { - FuncDeclaration *fd = fdx->overloadExactMatch(tf, mod); - if (fd) - { - return fd; - } - } - return NULL; -} - -void TypeInfoStructDeclaration::llvmDefine() -{ - Logger::println("TypeInfoStructDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - // make sure struct is resolved - assert(tinfo->ty == Tstruct); - TypeStruct *tc = static_cast(tinfo); - StructDeclaration *sd = tc->sym; - - // can't emit typeinfo for forward declarations - if (sd->sizeok != 1) - { - sd->error("cannot emit TypeInfo for forward declaration"); - fatal(); - } - - sd->codegen(Type::sir); - IrStruct* irstruct = sd->ir.irStruct; - - RTTIBuilder b(Type::typeinfostruct); - - // char[] name - b.push_string(sd->toPrettyChars()); - - // void[] init - // never emit a null array, even for zero initialized typeinfo - // the size() method uses this array! - size_t init_size = getTypeStoreSize(tc->irtype->getType()); - b.push_void_array(init_size, irstruct->getInitSymbol()); - - // toX functions ground work - static TypeFunction *tftohash; - static TypeFunction *tftostring; - - if (!tftohash) - { - Scope sc; - tftohash = new TypeFunction(NULL, Type::thash_t, 0, LINKd); -#if DMDV2 - tftohash ->mod = MODconst; -#endif - tftohash = static_cast(tftohash->semantic(0, &sc)); - -#if DMDV2 - Type *retType = Type::tchar->invariantOf()->arrayOf(); -#else - Type *retType = Type::tchar->arrayOf(); -#endif - tftostring = new TypeFunction(NULL, retType, 0, LINKd); - tftostring = static_cast(tftostring->semantic(0, &sc)); - } - - // this one takes a parameter, so we need to build a new one each time - // to get the right type. can we avoid this? - TypeFunction *tfcmpptr; - { - Scope sc; - Parameters *arguments = new Parameters; -#if STRUCTTHISREF - // arg type is ref const T - Parameter *arg = new Parameter(STCref, tc->constOf(), NULL, NULL); -#else - // arg type is const T* - Parameter *arg = new Parameter(STCin, tc->pointerTo(), NULL, NULL); -#endif - arguments->push(arg); - tfcmpptr = new TypeFunction(arguments, Type::tint32, 0, LINKd); -#if DMDV2 - tfcmpptr->mod = MODconst; -#endif - tfcmpptr = static_cast(tfcmpptr->semantic(0, &sc)); - } - - // well use this module for all overload lookups - Module *gm = getModule(); - - // toHash - FuncDeclaration* fd = find_method_overload(sd, Id::tohash, tftohash, gm); - b.push_funcptr(fd); - - // opEquals -#if DMDV2 - fd = sd->xeq; -#else - fd = find_method_overload(sd, Id::eq, tfcmpptr, gm); -#endif - b.push_funcptr(fd); - - // opCmp - fd = find_method_overload(sd, Id::cmp, tfcmpptr, gm); - b.push_funcptr(fd); - - // toString - fd = find_method_overload(sd, Id::tostring, tftostring, gm); - b.push_funcptr(fd); - - // uint m_flags; - unsigned hasptrs = tc->hasPointers() ? 1 : 0; - b.push_uint(hasptrs); - -#if DMDV2 - - ClassDeclaration* tscd = Type::typeinfostruct; - - assert((!global.params.is64bit && tscd->fields.dim == 11) || - (global.params.is64bit && tscd->fields.dim == 13)); - - // const(MemberInfo[]) function(in char[]) xgetMembers; - b.push_funcptr(sd->findGetMembers()); - - //void function(void*) xdtor; - b.push_funcptr(sd->dtor); - - //void function(void*) xpostblit; - FuncDeclaration *xpostblit = sd->postblit; - if (xpostblit && sd->postblit->storage_class & STCdisable) - xpostblit = 0; - b.push_funcptr(xpostblit); - - //uint m_align; - b.push_uint(tc->alignsize()); - - if (global.params.is64bit) - { - TypeTuple *tup = tc->toArgTypes(); - assert(tup->arguments->dim <= 2); - for (unsigned i = 0; i < 2; i++) - { - if (i < tup->arguments->dim) - { - Type *targ = static_cast(tup->arguments->data[i])->type; - targ = targ->merge(); - b.push_typeinfo(targ); - } - else - b.push_null(Type::typeinfo->type); - } - } - -#endif - - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -#if DMDV2 -void TypeInfoClassDeclaration::codegen(Ir*i) -{ - - IrGlobal* irg = new IrGlobal(this); - ir.irGlobal = irg; - assert(tinfo->ty == Tclass); - TypeClass *tc = static_cast(tinfo); - tc->sym->codegen(Type::sir); // make sure class is resolved - irg->value = tc->sym->ir.irStruct->getClassInfoSymbol(); -} -#endif - -void TypeInfoClassDeclaration::llvmDefine() -{ -#if DMDV2 - assert(0); -#endif - Logger::println("TypeInfoClassDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - // make sure class is resolved - assert(tinfo->ty == Tclass); - TypeClass *tc = static_cast(tinfo); - tc->sym->codegen(Type::sir); - - RTTIBuilder b(Type::typeinfoclass); - - // TypeInfo base - b.push_classinfo(tc->sym); - - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoInterfaceDeclaration::llvmDefine() -{ - Logger::println("TypeInfoInterfaceDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - // make sure interface is resolved - assert(tinfo->ty == Tclass); - TypeClass *tc = static_cast(tinfo); - tc->sym->codegen(Type::sir); - - RTTIBuilder b(Type::typeinfointerface); - - // TypeInfo base - b.push_classinfo(tc->sym); - - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoTupleDeclaration::llvmDefine() -{ - Logger::println("TypeInfoTupleDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - // create elements array - assert(tinfo->ty == Ttuple); - TypeTuple *tu = static_cast(tinfo); - - size_t dim = tu->arguments->dim; - std::vector arrInits; - arrInits.reserve(dim); - - LLType* tiTy = DtoType(Type::typeinfo->type); - - for (size_t i = 0; i < dim; i++) - { - Parameter *arg = static_cast(tu->arguments->data[i]); - arrInits.push_back(DtoTypeInfoOf(arg->type, true)); - } - - // build array - LLArrayType* arrTy = LLArrayType::get(tiTy, dim); - LLConstant* arrC = LLConstantArray::get(arrTy, arrInits); - - RTTIBuilder b(Type::typeinfotypelist); - - // push TypeInfo[] - b.push_array(arrC, dim, Type::typeinfo->type, NULL); - - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -#if DMDV2 - -void TypeInfoConstDeclaration::llvmDefine() -{ - Logger::println("TypeInfoConstDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - RTTIBuilder b(Type::typeinfoconst); - // TypeInfo base - b.push_typeinfo(tinfo->mutableOf()->merge()); - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoInvariantDeclaration::llvmDefine() -{ - Logger::println("TypeInfoInvariantDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - RTTIBuilder b(Type::typeinfoinvariant); - // TypeInfo base - b.push_typeinfo(tinfo->mutableOf()->merge()); - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoSharedDeclaration::llvmDefine() -{ - Logger::println("TypeInfoSharedDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - RTTIBuilder b(Type::typeinfoshared); - // TypeInfo base - b.push_typeinfo(tinfo->unSharedOf()->merge()); - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoWildDeclaration::llvmDefine() -{ - Logger::println("TypeInfoWildDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - RTTIBuilder b(Type::typeinfowild); - // TypeInfo base - b.push_typeinfo(tinfo->mutableOf()->merge()); - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -#if DMDV2 - -void TypeInfoVectorDeclaration::llvmDefine() -{ - Logger::println("TypeInfoVectorDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - assert(tinfo->ty == Tvector); - TypeVector *tv = static_cast(tinfo); - - RTTIBuilder b(Type::typeinfovector); - // TypeInfo base - b.push_typeinfo(tv->basetype); - // finish - b.finalize(ir.irGlobal); -} - -#endif - -#endif + + +// Copyright (c) 1999-2004 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// 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. + +// Modifications for LDC: +// Copyright (c) 2007 by Tomas Lindquist Olsen +// tomas at famolsen dk + +#include +#include + +#include "gen/llvm.h" + +#include "mars.h" +#include "module.h" +#include "mtype.h" +#include "scope.h" +#include "init.h" +#include "expression.h" +#include "attrib.h" +#include "declaration.h" +#include "template.h" +#include "id.h" +#include "enum.h" +#include "import.h" +#include "aggregate.h" + +#include "gen/irstate.h" +#include "gen/logger.h" +#include "gen/runtime.h" +#include "gen/tollvm.h" +#include "gen/llvmhelpers.h" +#include "gen/arrays.h" +#include "gen/structs.h" +#include "gen/classes.h" +#include "gen/linkage.h" +#include "gen/metadata.h" +#include "gen/rttibuilder.h" + +#include "ir/irvar.h" +#include "ir/irtype.h" + +/******************************************* + * Get a canonicalized form of the TypeInfo for use with the internal + * runtime library routines. Canonicalized in that static arrays are + * represented as dynamic arrays, enums are represented by their + * underlying type, etc. This reduces the number of TypeInfo's needed, + * so we can use the custom internal ones more. + */ + +Expression *Type::getInternalTypeInfo(Scope *sc) +{ TypeInfoDeclaration *tid; + Expression *e; + Type *t; + static TypeInfoDeclaration *internalTI[TMAX]; + + //printf("Type::getInternalTypeInfo() %s\n", toChars()); + t = toBasetype(); + switch (t->ty) + { + case Tsarray: +#if 0 + // convert to corresponding dynamic array type + t = t->nextOf()->mutableOf()->arrayOf(); +#endif + break; + + case Tclass: + if (static_cast(t)->sym->isInterfaceDeclaration()) + break; + goto Linternal; + + case Tarray: + #if DMDV2 + // convert to corresponding dynamic array type + t = t->nextOf()->mutableOf()->arrayOf(); + #endif + if (t->nextOf()->ty != Tclass) + break; + goto Linternal; + + case Tfunction: + case Tdelegate: + case Tpointer: + Linternal: + tid = internalTI[t->ty]; + if (!tid) + { tid = new TypeInfoDeclaration(t, 1); + internalTI[t->ty] = tid; + } + e = new VarExp(0, tid); + e = e->addressOf(sc); + e->type = tid->type; // do this so we don't get redundant dereference + return e; + + default: + break; + } + //printf("\tcalling getTypeInfo() %s\n", t->toChars()); + return t->getTypeInfo(sc); +} + +/**************************************************** + * Get the exact TypeInfo. + */ + +Expression *Type::getTypeInfo(Scope *sc) +{ + //printf("Type::getTypeInfo() %p, %s\n", this, toChars()); + if (!Type::typeinfo) + { + error(0, "TypeInfo not found. object.d may be incorrectly installed or corrupt, compile with -v switch"); + fatal(); + } + + Expression *e = 0; + Type *t = merge2(); // do this since not all Type's are merge'd + + if (!t->vtinfo) + { +#if DMDV2 + if (t->isShared()) + t->vtinfo = new TypeInfoSharedDeclaration(t); + else if (t->isConst()) + t->vtinfo = new TypeInfoConstDeclaration(t); + else if (t->isImmutable()) + t->vtinfo = new TypeInfoInvariantDeclaration(t); + else if (t->isWild()) + t->vtinfo = new TypeInfoWildDeclaration(t); + else +#endif + t->vtinfo = t->getTypeInfoDeclaration(); + assert(t->vtinfo); + + /* If this has a custom implementation in std/typeinfo, then + * do not generate a COMDAT for it. + */ + if (!t->builtinTypeInfo()) + { // Generate COMDAT + if (sc) // if in semantic() pass + { // Find module that will go all the way to an object file + Module *m = sc->module->importedFrom; + m->members->push(t->vtinfo); + } + else // if in obj generation pass + { +#if IN_DMD + t->vtinfo->toObjFile(0); // TODO: multiobj +#else + t->vtinfo->codegen(sir); +#endif + } + } + } + e = new VarExp(0, t->vtinfo); + e = e->addressOf(sc); + e->type = t->vtinfo->type; // do this so we don't get redundant dereference + return e; +} + +enum RET TypeFunction::retStyle() +{ + return RETstack; +} + +TypeInfoDeclaration *Type::getTypeInfoDeclaration() +{ + //printf("Type::getTypeInfoDeclaration() %s\n", toChars()); + return new TypeInfoDeclaration(this, 0); +} + +TypeInfoDeclaration *TypeTypedef::getTypeInfoDeclaration() +{ + return new TypeInfoTypedefDeclaration(this); +} + +TypeInfoDeclaration *TypePointer::getTypeInfoDeclaration() +{ + return new TypeInfoPointerDeclaration(this); +} + +TypeInfoDeclaration *TypeDArray::getTypeInfoDeclaration() +{ + return new TypeInfoArrayDeclaration(this); +} + +TypeInfoDeclaration *TypeSArray::getTypeInfoDeclaration() +{ + return new TypeInfoStaticArrayDeclaration(this); +} + +TypeInfoDeclaration *TypeAArray::getTypeInfoDeclaration() +{ + return new TypeInfoAssociativeArrayDeclaration(this); +} + +TypeInfoDeclaration *TypeStruct::getTypeInfoDeclaration() +{ + return new TypeInfoStructDeclaration(this); +} + +TypeInfoDeclaration *TypeClass::getTypeInfoDeclaration() +{ + if (sym->isInterfaceDeclaration()) + return new TypeInfoInterfaceDeclaration(this); + else + return new TypeInfoClassDeclaration(this); +} + +#if DMDV2 +TypeInfoDeclaration *TypeVector::getTypeInfoDeclaration() +{ + return new TypeInfoVectorDeclaration(this); +} +#endif + +TypeInfoDeclaration *TypeEnum::getTypeInfoDeclaration() +{ + return new TypeInfoEnumDeclaration(this); +} + +TypeInfoDeclaration *TypeFunction::getTypeInfoDeclaration() +{ + return new TypeInfoFunctionDeclaration(this); +} + +TypeInfoDeclaration *TypeDelegate::getTypeInfoDeclaration() +{ + return new TypeInfoDelegateDeclaration(this); +} + +TypeInfoDeclaration *TypeTuple::getTypeInfoDeclaration() +{ + return new TypeInfoTupleDeclaration(this); +} + +/* ========================================================================= */ + +/* These decide if there's an instance for them already in std.typeinfo, + * because then the compiler doesn't need to build one. + */ + +int Type::builtinTypeInfo() +{ + return 0; +} + +int TypeBasic::builtinTypeInfo() +{ +#if DMDV2 + return mod ? 0 : 1; +#else + return 1; +#endif +} + +int TypeDArray::builtinTypeInfo() +{ +#if DMDV2 + return !mod && (next->isTypeBasic() != NULL && !next->mod || + // strings are so common, make them builtin + next->ty == Tchar && next->mod == MODimmutable); +#else + return next->isTypeBasic() != NULL; +#endif +} + +int TypeClass::builtinTypeInfo() +{ + /* This is statically put out with the ClassInfo, so + * claim it is built in so it isn't regenerated by each module. + */ +#if IN_DMD + return mod ? 0 : 1; +#elif IN_LLVM + // FIXME if I enable this, the way LDC does typeinfo will cause a bunch + // of linker errors to missing class typeinfo definitions. + return 0; +#endif +} + +/* ========================================================================= */ + +////////////////////////////////////////////////////////////////////////////// +// MAGIC PLACE +// (wut?) +////////////////////////////////////////////////////////////////////////////// + +void DtoResolveTypeInfo(TypeInfoDeclaration* tid); +void DtoDeclareTypeInfo(TypeInfoDeclaration* tid); + +void TypeInfoDeclaration::codegen(Ir*) +{ + DtoResolveTypeInfo(this); +} + +void DtoResolveTypeInfo(TypeInfoDeclaration* tid) +{ + if (tid->ir.resolved) return; + tid->ir.resolved = true; + + Logger::println("DtoResolveTypeInfo(%s)", tid->toChars()); + LOG_SCOPE; + + std::string mangle(tid->mangle()); + + IrGlobal* irg = new IrGlobal(tid); + irg->value = gIR->module->getGlobalVariable(mangle); + + if (!irg->value) { + if (tid->tinfo->builtinTypeInfo()) // this is a declaration of a builtin __initZ var + irg->type = Type::typeinfo->type->irtype->getType(); + else + irg->type = LLStructType::create(gIR->context(), tid->toPrettyChars()); + irg->value = new llvm::GlobalVariable(*gIR->module, irg->type, true, + TYPEINFO_LINKAGE_TYPE, NULL, mangle); + } else { + irg->type = irg->value->getType()->getContainedType(0); + } + + tid->ir.irGlobal = irg; + +#if USE_METADATA + // don't do this for void or llvm will crash + if (tid->tinfo->ty != Tvoid) { + // Add some metadata for use by optimization passes. + std::string metaname = std::string(TD_PREFIX) + mangle; + llvm::NamedMDNode* meta = gIR->module->getNamedMetadata(metaname); + // Don't generate metadata for non-concrete types + // (such as tuple types, slice types, typeof(expr), etc.) + if (!meta && tid->tinfo->toBasetype()->ty < Terror) { + // Construct the fields + MDNodeField* mdVals[TD_NumFields]; + if (TD_Confirm >= 0) + mdVals[TD_Confirm] = llvm::cast(irg->value); + mdVals[TD_Type] = llvm::UndefValue::get(DtoType(tid->tinfo)); + // Construct the metadata + llvm::MetadataBase* metadata = llvm::MDNode::get(gIR->context(), mdVals, TD_NumFields); + // Insert it into the module + llvm::NamedMDNode::Create(gIR->context(), metaname, &metadata, 1, gIR->module); + } + } +#endif // USE_METADATA + + DtoDeclareTypeInfo(tid); +} + +void DtoDeclareTypeInfo(TypeInfoDeclaration* tid) +{ + DtoResolveTypeInfo(tid); + + if (tid->ir.declared) return; + tid->ir.declared = true; + + Logger::println("DtoDeclareTypeInfo(%s)", tid->toChars()); + LOG_SCOPE; + + if (Logger::enabled()) + { + std::string mangled(tid->mangle()); + Logger::println("type = '%s'", tid->tinfo->toChars()); + Logger::println("typeinfo mangle: %s", mangled.c_str()); + } + + IrGlobal* irg = tid->ir.irGlobal; + assert(irg->value != NULL); + + // this is a declaration of a builtin __initZ var + if (tid->tinfo->builtinTypeInfo()) { + LLGlobalVariable* g = isaGlobalVar(irg->value); + g->setLinkage(llvm::GlobalValue::ExternalLinkage); + return; + } + + // define custom typedef + tid->llvmDefine(); +} + +/* ========================================================================= */ + +void TypeInfoDeclaration::llvmDefine() +{ + Logger::println("TypeInfoDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + RTTIBuilder b(Type::typeinfo); + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoTypedefDeclaration::llvmDefine() +{ + Logger::println("TypeInfoTypedefDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + RTTIBuilder b(Type::typeinfotypedef); + + assert(tinfo->ty == Ttypedef); + TypeTypedef *tc = static_cast(tinfo); + TypedefDeclaration *sd = tc->sym; + + // TypeInfo base + sd->basetype = sd->basetype->merge(); // dmd does it ... why? + b.push_typeinfo(sd->basetype); + + // char[] name + b.push_string(sd->toPrettyChars()); + + // void[] init + // emit null array if we should use the basetype, or if the basetype + // uses default initialization. + if (tinfo->isZeroInit(0) || !sd->init) + { + b.push_null_void_array(); + } + // otherwise emit a void[] with the default initializer + else + { + LLConstant* C = DtoConstInitializer(sd->loc, sd->basetype, sd->init); + b.push_void_array(C, sd->basetype, sd); + } + + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoEnumDeclaration::llvmDefine() +{ + Logger::println("TypeInfoEnumDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + RTTIBuilder b(Type::typeinfoenum); + + assert(tinfo->ty == Tenum); + TypeEnum *tc = static_cast(tinfo); + EnumDeclaration *sd = tc->sym; + + // TypeInfo base + b.push_typeinfo(sd->memtype); + + // char[] name + b.push_string(sd->toPrettyChars()); + + // void[] init + // emit void[] with the default initialier, the array is null if the default + // initializer is zero + if (!sd->defaultval || tinfo->isZeroInit(0)) + { + b.push_null_void_array(); + } + // otherwise emit a void[] with the default initializer + else + { + LLType* memty = DtoType(sd->memtype); +#if DMDV2 + LLConstant* C = LLConstantInt::get(memty, sd->defaultval->toInteger(), !sd->memtype->isunsigned()); +#else + LLConstant* C = LLConstantInt::get(memty, sd->defaultval, !sd->memtype->isunsigned()); +#endif + b.push_void_array(C, sd->memtype, sd); + } + + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoPointerDeclaration::llvmDefine() +{ + Logger::println("TypeInfoPointerDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + RTTIBuilder b(Type::typeinfopointer); + // TypeInfo base + b.push_typeinfo(tinfo->nextOf()); + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoArrayDeclaration::llvmDefine() +{ + Logger::println("TypeInfoArrayDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + RTTIBuilder b(Type::typeinfoarray); + // TypeInfo base + b.push_typeinfo(tinfo->nextOf()); + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoStaticArrayDeclaration::llvmDefine() +{ + Logger::println("TypeInfoStaticArrayDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + assert(tinfo->ty == Tsarray); + TypeSArray *tc = static_cast(tinfo); + + RTTIBuilder b(Type::typeinfostaticarray); + + // value typeinfo + b.push_typeinfo(tc->nextOf()); + + // length + b.push(DtoConstSize_t(static_cast(tc->dim->toUInteger()))); + + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoAssociativeArrayDeclaration::llvmDefine() +{ + Logger::println("TypeInfoAssociativeArrayDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + assert(tinfo->ty == Taarray); + TypeAArray *tc = static_cast(tinfo); + + RTTIBuilder b(Type::typeinfoassociativearray); + + // value typeinfo + b.push_typeinfo(tc->nextOf()); + + // key typeinfo + b.push_typeinfo(tc->index); + +#if DMDV2 + // impl typeinfo + b.push_typeinfo(tc->getImpl()->type); +#endif + + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoFunctionDeclaration::llvmDefine() +{ + Logger::println("TypeInfoFunctionDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + RTTIBuilder b(Type::typeinfofunction); + // TypeInfo base + b.push_typeinfo(tinfo->nextOf()); + // string deco + b.push_string(tinfo->deco); + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoDelegateDeclaration::llvmDefine() +{ + Logger::println("TypeInfoDelegateDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + assert(tinfo->ty == Tdelegate); + Type* ret_type = tinfo->nextOf()->nextOf(); + + RTTIBuilder b(Type::typeinfodelegate); + // TypeInfo base + b.push_typeinfo(ret_type); + // string deco + b.push_string(tinfo->deco); + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +static FuncDeclaration* find_method_overload(AggregateDeclaration* ad, Identifier* id, TypeFunction* tf, Module* mod) +{ + Dsymbol *s = search_function(ad, id); + FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL; + if (fdx) + { + FuncDeclaration *fd = fdx->overloadExactMatch(tf, mod); + if (fd) + { + return fd; + } + } + return NULL; +} + +void TypeInfoStructDeclaration::llvmDefine() +{ + Logger::println("TypeInfoStructDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + // make sure struct is resolved + assert(tinfo->ty == Tstruct); + TypeStruct *tc = static_cast(tinfo); + StructDeclaration *sd = tc->sym; + + // can't emit typeinfo for forward declarations + if (sd->sizeok != 1) + { + sd->error("cannot emit TypeInfo for forward declaration"); + fatal(); + } + + sd->codegen(Type::sir); + IrStruct* irstruct = sd->ir.irStruct; + + RTTIBuilder b(Type::typeinfostruct); + + // char[] name + b.push_string(sd->toPrettyChars()); + + // void[] init + // never emit a null array, even for zero initialized typeinfo + // the size() method uses this array! + size_t init_size = getTypeStoreSize(tc->irtype->getType()); + b.push_void_array(init_size, irstruct->getInitSymbol()); + + // toX functions ground work + static TypeFunction *tftohash; + static TypeFunction *tftostring; + + if (!tftohash) + { + Scope sc; + tftohash = new TypeFunction(NULL, Type::thash_t, 0, LINKd); +#if DMDV2 + tftohash ->mod = MODconst; +#endif + tftohash = static_cast(tftohash->semantic(0, &sc)); + +#if DMDV2 + Type *retType = Type::tchar->invariantOf()->arrayOf(); +#else + Type *retType = Type::tchar->arrayOf(); +#endif + tftostring = new TypeFunction(NULL, retType, 0, LINKd); + tftostring = static_cast(tftostring->semantic(0, &sc)); + } + + // this one takes a parameter, so we need to build a new one each time + // to get the right type. can we avoid this? + TypeFunction *tfcmpptr; + { + Scope sc; + Parameters *arguments = new Parameters; +#if STRUCTTHISREF + // arg type is ref const T + Parameter *arg = new Parameter(STCref, tc->constOf(), NULL, NULL); +#else + // arg type is const T* + Parameter *arg = new Parameter(STCin, tc->pointerTo(), NULL, NULL); +#endif + arguments->push(arg); + tfcmpptr = new TypeFunction(arguments, Type::tint32, 0, LINKd); +#if DMDV2 + tfcmpptr->mod = MODconst; +#endif + tfcmpptr = static_cast(tfcmpptr->semantic(0, &sc)); + } + + // well use this module for all overload lookups + Module *gm = getModule(); + + // toHash + FuncDeclaration* fd = find_method_overload(sd, Id::tohash, tftohash, gm); + b.push_funcptr(fd); + + // opEquals +#if DMDV2 + fd = sd->xeq; +#else + fd = find_method_overload(sd, Id::eq, tfcmpptr, gm); +#endif + b.push_funcptr(fd); + + // opCmp + fd = find_method_overload(sd, Id::cmp, tfcmpptr, gm); + b.push_funcptr(fd); + + // toString + fd = find_method_overload(sd, Id::tostring, tftostring, gm); + b.push_funcptr(fd); + + // uint m_flags; + unsigned hasptrs = tc->hasPointers() ? 1 : 0; + b.push_uint(hasptrs); + +#if DMDV2 + + ClassDeclaration* tscd = Type::typeinfostruct; + + assert((!global.params.is64bit && tscd->fields.dim == 11) || + (global.params.is64bit && tscd->fields.dim == 13)); + + // const(MemberInfo[]) function(in char[]) xgetMembers; + b.push_funcptr(sd->findGetMembers()); + + //void function(void*) xdtor; + b.push_funcptr(sd->dtor); + + //void function(void*) xpostblit; + FuncDeclaration *xpostblit = sd->postblit; + if (xpostblit && sd->postblit->storage_class & STCdisable) + xpostblit = 0; + b.push_funcptr(xpostblit); + + //uint m_align; + b.push_uint(tc->alignsize()); + + if (global.params.is64bit) + { + TypeTuple *tup = tc->toArgTypes(); + assert(tup->arguments->dim <= 2); + for (unsigned i = 0; i < 2; i++) + { + if (i < tup->arguments->dim) + { + Type *targ = static_cast(tup->arguments->data[i])->type; + targ = targ->merge(); + b.push_typeinfo(targ); + } + else + b.push_null(Type::typeinfo->type); + } + } + +#endif + + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +#if DMDV2 +void TypeInfoClassDeclaration::codegen(Ir*i) +{ + + IrGlobal* irg = new IrGlobal(this); + ir.irGlobal = irg; + assert(tinfo->ty == Tclass); + TypeClass *tc = static_cast(tinfo); + tc->sym->codegen(Type::sir); // make sure class is resolved + irg->value = tc->sym->ir.irStruct->getClassInfoSymbol(); +} +#endif + +void TypeInfoClassDeclaration::llvmDefine() +{ +#if DMDV2 + assert(0); +#endif + Logger::println("TypeInfoClassDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + // make sure class is resolved + assert(tinfo->ty == Tclass); + TypeClass *tc = static_cast(tinfo); + tc->sym->codegen(Type::sir); + + RTTIBuilder b(Type::typeinfoclass); + + // TypeInfo base + b.push_classinfo(tc->sym); + + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoInterfaceDeclaration::llvmDefine() +{ + Logger::println("TypeInfoInterfaceDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + // make sure interface is resolved + assert(tinfo->ty == Tclass); + TypeClass *tc = static_cast(tinfo); + tc->sym->codegen(Type::sir); + + RTTIBuilder b(Type::typeinfointerface); + + // TypeInfo base + b.push_classinfo(tc->sym); + + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoTupleDeclaration::llvmDefine() +{ + Logger::println("TypeInfoTupleDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + // create elements array + assert(tinfo->ty == Ttuple); + TypeTuple *tu = static_cast(tinfo); + + size_t dim = tu->arguments->dim; + std::vector arrInits; + arrInits.reserve(dim); + + LLType* tiTy = DtoType(Type::typeinfo->type); + + for (size_t i = 0; i < dim; i++) + { + Parameter *arg = static_cast(tu->arguments->data[i]); + arrInits.push_back(DtoTypeInfoOf(arg->type, true)); + } + + // build array + LLArrayType* arrTy = LLArrayType::get(tiTy, dim); + LLConstant* arrC = LLConstantArray::get(arrTy, arrInits); + + RTTIBuilder b(Type::typeinfotypelist); + + // push TypeInfo[] + b.push_array(arrC, dim, Type::typeinfo->type, NULL); + + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +#if DMDV2 + +void TypeInfoConstDeclaration::llvmDefine() +{ + Logger::println("TypeInfoConstDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + RTTIBuilder b(Type::typeinfoconst); + // TypeInfo base + b.push_typeinfo(tinfo->mutableOf()->merge()); + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoInvariantDeclaration::llvmDefine() +{ + Logger::println("TypeInfoInvariantDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + RTTIBuilder b(Type::typeinfoinvariant); + // TypeInfo base + b.push_typeinfo(tinfo->mutableOf()->merge()); + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoSharedDeclaration::llvmDefine() +{ + Logger::println("TypeInfoSharedDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + RTTIBuilder b(Type::typeinfoshared); + // TypeInfo base + b.push_typeinfo(tinfo->unSharedOf()->merge()); + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoWildDeclaration::llvmDefine() +{ + Logger::println("TypeInfoWildDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + RTTIBuilder b(Type::typeinfowild); + // TypeInfo base + b.push_typeinfo(tinfo->mutableOf()->merge()); + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +#if DMDV2 + +void TypeInfoVectorDeclaration::llvmDefine() +{ + Logger::println("TypeInfoVectorDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + assert(tinfo->ty == Tvector); + TypeVector *tv = static_cast(tinfo); + + RTTIBuilder b(Type::typeinfovector); + // TypeInfo base + b.push_typeinfo(tv->basetype); + // finish + b.finalize(ir.irGlobal); +} + +#endif + +#endif From 4ae14449ea8e2f911554051390bb36aa961c5ad1 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 2 Sep 2012 02:09:14 +0200 Subject: [PATCH 15/33] Emit new TypeInfo layout. Includes untested support for RTInfo. --- gen/classes.cpp | 24 ++++++++++++++---------- gen/rttibuilder.cpp | 5 +++++ gen/rttibuilder.h | 1 + gen/typinf.cpp | 15 ++++++++++++--- 4 files changed, 32 insertions(+), 13 deletions(-) diff --git a/gen/classes.cpp b/gen/classes.cpp index 1ac63ced..4db73d7f 100644 --- a/gen/classes.cpp +++ b/gen/classes.cpp @@ -676,7 +676,7 @@ LLConstant* DtoDefineClassInfo(ClassDeclaration* cd) // OffsetTypeInfo[] offTi; // void *defaultConstructor; // version(D_Version2) -// const(MemberInfo[]) function(string) xgetMembers; +// immutable(void)* m_RTInfo; // else // TypeInfo typeinfo; // since dmd 1.045 // } @@ -761,10 +761,12 @@ LLConstant* DtoDefineClassInfo(ClassDeclaration* cd) b.push_funcptr(cd->inv, invVar->type); // uint flags + unsigned flags; if (cd->isInterfaceDeclaration()) - b.push_uint(4 | cd->isCOMinterface() | 32); + flags = 4 | cd->isCOMinterface() | 32; else - b.push_uint(build_classinfo_flags(cd)); + flags = build_classinfo_flags(cd); + b.push_uint(flags); // deallocator b.push_funcptr(cd->aggDelete, Type::tvoid->pointerTo()); @@ -790,16 +792,18 @@ LLConstant* DtoDefineClassInfo(ClassDeclaration* cd) b.push_funcptr(cd->defaultCtor, defConstructorVar->type); #if DMDV2 - - // xgetMembers - VarDeclaration* xgetVar = static_cast(cinfo->fields.data[11]); - b.push_funcptr(cd->findGetMembers(), xgetVar->type); - + // immutable(void)* m_RTInfo; + // The cases where getRTInfo is null are not quite here, but the code is + // modelled after what DMD does. + if (cd->getRTInfo) + b.push(cd->getRTInfo->toConstElem(gIR)); + else if (flags & 2) + b.push_size_as_vp(0); // no pointers + else + b.push_size_as_vp(1); // has pointers #else - // typeinfo - since 1.045 b.push_typeinfo(cd->type); - #endif /*size_t n = inits.size(); diff --git a/gen/rttibuilder.cpp b/gen/rttibuilder.cpp index 6a8e3eeb..985dcc97 100644 --- a/gen/rttibuilder.cpp +++ b/gen/rttibuilder.cpp @@ -121,6 +121,11 @@ void RTTIBuilder::push_size(uint64_t s) inits.push_back(DtoConstSize_t(s)); } +void RTTIBuilder::push_size_as_vp(uint64_t s) +{ + inits.push_back(llvm::ConstantExpr::getIntToPtr(DtoConstSize_t(s), getVoidPtrType())); +} + void RTTIBuilder::push_funcptr(FuncDeclaration* fd, Type* castto) { if (fd) diff --git a/gen/rttibuilder.h b/gen/rttibuilder.h index d7f54540..98f2598b 100644 --- a/gen/rttibuilder.h +++ b/gen/rttibuilder.h @@ -29,6 +29,7 @@ struct RTTIBuilder void push_null_void_array(); void push_uint(unsigned u); void push_size(uint64_t s); + void push_size_as_vp(uint64_t s); void push_string(const char* str); void push_typeinfo(Type* t); void push_classinfo(ClassDeclaration* cd); diff --git a/gen/typinf.cpp b/gen/typinf.cpp index acd2264e..53d12585 100644 --- a/gen/typinf.cpp +++ b/gen/typinf.cpp @@ -710,9 +710,6 @@ void TypeInfoStructDeclaration::llvmDefine() assert((!global.params.is64bit && tscd->fields.dim == 11) || (global.params.is64bit && tscd->fields.dim == 13)); - // const(MemberInfo[]) function(in char[]) xgetMembers; - b.push_funcptr(sd->findGetMembers()); - //void function(void*) xdtor; b.push_funcptr(sd->dtor); @@ -727,6 +724,8 @@ void TypeInfoStructDeclaration::llvmDefine() if (global.params.is64bit) { + // TypeInfo m_arg1; + // TypeInfo m_arg2; TypeTuple *tup = tc->toArgTypes(); assert(tup->arguments->dim <= 2); for (unsigned i = 0; i < 2; i++) @@ -742,6 +741,16 @@ void TypeInfoStructDeclaration::llvmDefine() } } + // immutable(void)* m_RTInfo; + // The cases where getRTInfo is null are not quite here, but the code is + // modelled after what DMD does. + if (sd->getRTInfo) + b.push(sd->getRTInfo->toConstElem(gIR)); + else if (!tc->hasPointers()) + b.push_size_as_vp(0); // no pointers + else + b.push_size_as_vp(1); // has pointers + #endif // finish From 8987f2da3072f9ce226236523853881c022659c8 Mon Sep 17 00:00:00 2001 From: kai Date: Sun, 2 Sep 2012 20:02:13 +0200 Subject: [PATCH 16/33] Fix format for MSVC. --- dmd2/mangle.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dmd2/mangle.c b/dmd2/mangle.c index fc97aa51..75c75b53 100644 --- a/dmd2/mangle.c +++ b/dmd2/mangle.c @@ -266,7 +266,7 @@ char *TemplateMixin::mangle() p += 2; buf.writestring(p); } - buf.printf("%zu%s", strlen(id), id); + buf.printf("%llu%s", (ulonglong)strlen(id), id); id = buf.toChars(); buf.data = NULL; //printf("TemplateMixin::mangle() %s = %s\n", toChars(), id); From 16847dd5d5f98feea2e069d20388e2399ea188f6 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 2 Sep 2012 20:56:44 +0200 Subject: [PATCH 17/33] Disregard modifiers when checking for initializer type match. Previously, only const'ness was dropped, but DMD 2.060 started to emit initializers with incompatible shared modifiers as well. --- gen/llvmhelpers.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 87854689..15283c77 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -1461,7 +1461,7 @@ static LLConstant* expand_to_sarray(Type *base, Expression* exp) TypeSArray* tsa = static_cast(t); dims.push_back(tsa->dim->toInteger()); assert(t->nextOf()); - t = t->nextOf()->toBasetype(); + t = stripModifiers(t->nextOf()->toBasetype()); } size_t i = dims.size(); @@ -1482,8 +1482,8 @@ static LLConstant* expand_to_sarray(Type *base, Expression* exp) LLConstant* DtoConstExpInit(Loc loc, Type* type, Expression* exp) { #if DMDV2 - Type* expbase = exp->type->toBasetype()->mutableOf()->merge(); - Type* base = type->toBasetype()->mutableOf()->merge(); + Type* expbase = stripModifiers(exp->type->toBasetype())->merge(); + Type* base = stripModifiers(type->toBasetype())->merge(); #else Type* expbase = exp->type->toBasetype(); Type* base = type->toBasetype(); From 1cb982f56848da2aad4586690b9596fe720dd94f Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 2 Sep 2012 20:58:08 +0200 Subject: [PATCH 18/33] druntime updates. --- runtime/druntime | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/druntime b/runtime/druntime index 095197b6..a382f23b 160000 --- a/runtime/druntime +++ b/runtime/druntime @@ -1 +1 @@ -Subproject commit 095197b629c2098549a2fe50c41c7438c79f101a +Subproject commit a382f23bdcfe9d3d22bfb056f97325af7a3b46a9 From 4b23e794ca9677808de8a5441f84968052fc794c Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 2 Sep 2012 21:25:08 +0200 Subject: [PATCH 19/33] Removed linkExecutable() (dead code). --- driver/linker.cpp | 161 ---------------------------------------------- driver/linker.h | 11 +--- 2 files changed, 2 insertions(+), 170 deletions(-) diff --git a/driver/linker.cpp b/driver/linker.cpp index b5113ef0..03027723 100644 --- a/driver/linker.cpp +++ b/driver/linker.cpp @@ -58,167 +58,6 @@ void linkModules(llvm::Module* dst, const Module_vector& MV) static llvm::sys::Path gExePath; -int linkExecutable(const char* argv0) -{ - Logger::println("*** Linking executable ***"); - - // error string - std::string errstr; - - // find the llvm-ld program - llvm::sys::Path ldpath = llvm::sys::Program::FindProgramByName("llvm-ld"); - if (ldpath.isEmpty()) - { - ldpath.set("llvm-ld"); - } - - // build arguments - std::vector args; - - // first the program name ?? - args.push_back("llvm-ld"); - - // output filename - std::string exestr; - if (global.params.exefile) - { // explicit - exestr = global.params.exefile; - } - else - { // inferred - // try root module name - if (Module::rootModule) - exestr = Module::rootModule->toChars(); - else - exestr = "a.out"; - } - if (global.params.os == OSWindows && !(exestr.substr(exestr.length()-4) == ".exe")) - exestr.append(".exe"); - - std::string outopt = "-o=" + exestr; - args.push_back(outopt.c_str()); - - // set the global gExePath - gExePath.set(exestr); - assert(gExePath.isValid()); - - // create path to exe - llvm::sys::Path exedir(llvm::sys::path::parent_path(gExePath.str())); - if (!llvm::sys::fs::exists(exedir.str())) - { - exedir.createDirectoryOnDisk(true, &errstr); - if (!errstr.empty()) - { - error("failed to create path to linking output: %s\n%s", exedir.c_str(), errstr.c_str()); - fatal(); - } - } - - // strip debug info - if (!global.params.symdebug) - args.push_back("-strip-debug"); - - // optimization level - if (!optimize()) - args.push_back("-disable-opt"); - else - { - switch(optLevel()) - { - case 0: - args.push_back("-disable-opt"); - break; - case 1: - args.push_back("-globaldce"); - args.push_back("-disable-opt"); - args.push_back("-globaldce"); - args.push_back("-mem2reg"); - case 2: - case 3: - case 4: - case 5: - // use default optimization - break; - default: - assert(0); - } - } - - // inlining - if (!(global.params.useInline || doInline())) - { - args.push_back("-disable-inlining"); - } - - // additional linker switches - for (unsigned i = 0; i < global.params.linkswitches->dim; i++) - { - char *p = static_cast(global.params.linkswitches->data[i]); - args.push_back(p); - } - - // native please - args.push_back("-native"); - - - // user libs - for (unsigned i = 0; i < global.params.libfiles->dim; i++) - { - char *p = static_cast(global.params.libfiles->data[i]); - args.push_back(p); - } - - // default libs - switch(global.params.os) { - case OSLinux: - case OSMacOSX: - args.push_back("-ldl"); - case OSFreeBSD: - args.push_back("-lpthread"); - args.push_back("-lm"); - break; - case OSHaiku: - args.push_back("-lroot"); - break; - case OSWindows: - // FIXME: I'd assume kernel32 etc - break; - } - - // object files - for (unsigned i = 0; i < global.params.objfiles->dim; i++) - { - char *p = static_cast(global.params.objfiles->data[i]); - args.push_back(p); - } - - // print link command? - if (!quiet || global.params.verbose) - { - // Print it - for (int i = 0; i < args.size(); i++) - printf("%s ", args[i]); - printf("\n"); - fflush(stdout); - } - - // terminate args list - args.push_back(NULL); - - // try to call linker!!! - if (int status = llvm::sys::Program::ExecuteAndWait(ldpath, &args[0], NULL, NULL, 0,0, &errstr)) - { - error("linking failed:\nstatus: %d", status); - if (!errstr.empty()) - error("message: %s", errstr.c_str()); - return status; - } - - return 0; -} - -////////////////////////////////////////////////////////////////////////////// - int linkObjToBinary(bool sharedLib) { Logger::println("*** Linking executable ***"); diff --git a/driver/linker.h b/driver/linker.h index d76c1778..e2844732 100644 --- a/driver/linker.h +++ b/driver/linker.h @@ -18,13 +18,6 @@ namespace llvm */ void linkModules(llvm::Module* dst, const std::vector& MV); -/** - * Link an executable. - * @param argv0 the argv[0] value as passed to main - * @return 0 on success. - */ -int linkExecutable(const char* argv0); - /** * Link an executable only from object files. * @param argv0 the argv[0] value as passed to main @@ -38,12 +31,12 @@ int linkObjToBinary(bool sharedLib); void createStaticLibrary(); /** - * Delete the executable that was previously linked with linkExecutable. + * Delete the executable that was previously linked with linkObjToBinary. */ void deleteExecutable(); /** - * Runs the executable that was previously linked with linkExecutable. + * Runs the executable that was previously linked with linkObjToBinary. * @return the return status of the executable. */ int runExecutable(); From 6b1b84a28d0069e7b843f53984c0839c3887002a Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 2 Sep 2012 21:34:21 +0200 Subject: [PATCH 20/33] Pass library file arguments to linker _before_ custom switches. This allows specifying a static D library specified at the LDC command line to pick up symbols from druntime/Phobos. Fixes DMD testcase 'test39'. --- driver/linker.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/driver/linker.cpp b/driver/linker.cpp index 03027723..067b76d1 100644 --- a/driver/linker.cpp +++ b/driver/linker.cpp @@ -83,6 +83,13 @@ int linkObjToBinary(bool sharedLib) args.push_back(p); } + // user libs + for (unsigned i = 0; i < global.params.libfiles->dim; i++) + { + char *p = static_cast(global.params.libfiles->data[i]); + args.push_back(p); + } + // output filename std::string output; if (!sharedLib && global.params.exefile) @@ -147,13 +154,6 @@ int linkObjToBinary(bool sharedLib) args.push_back(p); } - // user libs - for (unsigned i = 0; i < global.params.libfiles->dim; i++) - { - char *p = static_cast(global.params.libfiles->data[i]); - args.push_back(p); - } - // default libs bool addSoname = false; switch(global.params.os) { From ee4285f93455f33fcaf558775d9f996ed7784fd9 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Tue, 4 Sep 2012 01:36:52 +0200 Subject: [PATCH 21/33] Properly handle DMD-internal "reference variables". Previously, we just had a hack to make ref foreach statements work. This commit enables them to work in other cases as well, like the implicit __result variable for functions with out-contracts (which is such a magic ref variable for ref-returning functions). Fixes DMD testcase 'testcontracts'. --- gen/dvalue.cpp | 13 ++- gen/functions.cpp | 3 +- gen/llvmhelpers.cpp | 228 ++++++++++++++++++++++---------------------- gen/llvmhelpers.h | 9 ++ gen/nested.cpp | 63 +++--------- gen/toir.cpp | 24 +++++ ir/irvar.cpp | 1 - ir/irvar.h | 4 +- 8 files changed, 173 insertions(+), 172 deletions(-) diff --git a/gen/dvalue.cpp b/gen/dvalue.cpp index cf0a4bdd..e0057654 100644 --- a/gen/dvalue.cpp +++ b/gen/dvalue.cpp @@ -16,6 +16,8 @@ DVarValue::DVarValue(Type* t, VarDeclaration* vd, LLValue* llvmValue) : DValue(t), var(vd), val(llvmValue) { assert(isaPointer(llvmValue)); + assert(!isSpecialRefVar(vd) || + isaPointer(isaPointer(llvmValue)->getElementType())); } DVarValue::DVarValue(Type* t, LLValue* llvmValue) @@ -27,6 +29,8 @@ DVarValue::DVarValue(Type* t, LLValue* llvmValue) LLValue* DVarValue::getLVal() { assert(val); + if (var && isSpecialRefVar(var)) + return DtoLoad(val); return val; } @@ -34,9 +38,14 @@ LLValue* DVarValue::getRVal() { assert(val); Type* bt = type->toBasetype(); + + LLValue* tmp = val; + if (var && isSpecialRefVar(var)) + tmp = DtoLoad(tmp); + if (DtoIsPassedByRef(bt)) - return val; - return DtoLoad(val); + return tmp; + return DtoLoad(tmp); } ///////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/gen/functions.cpp b/gen/functions.cpp index 287464dc..5e540c21 100644 --- a/gen/functions.cpp +++ b/gen/functions.cpp @@ -815,8 +815,7 @@ void DtoDefineFunction(FuncDeclaration* fd) { DtoNestedInit(fd->vresult); } else if (fd->vresult) { - fd->vresult->ir.irLocal = new IrLocal(fd->vresult); - fd->vresult->ir.irLocal->value = DtoAlloca(fd->vresult->type, fd->vresult->toChars()); + DtoVarDeclaration(fd->vresult); } // copy _argptr and _arguments to a memory location diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 15283c77..de90a17f 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -1013,6 +1013,110 @@ void DtoConstInitGlobal(VarDeclaration* vd) /*//////////////////////////////////////////////////////////////////////////////////////// // DECLARATION EXP HELPER ////////////////////////////////////////////////////////////////////////////////////////*/ + +// TODO: Merge with DtoRawVarDeclaration! +void DtoVarDeclaration(VarDeclaration* vd) +{ + assert(!vd->isDataseg() && "Statics/globals are handled in DtoDeclarationExp."); + assert(!vd->aliassym && "Aliases are handled in DtoDeclarationExp."); + + Logger::println("vdtype = %s", vd->type->toChars()); + +#if DMDV2 + if (vd->nestedrefs.dim) +#else + if (vd->nestedref) +#endif + { + Logger::println("has nestedref set (referenced by nested function/delegate)"); + assert(vd->ir.irLocal); + DtoNestedInit(vd); + } + else if(vd->ir.irLocal) + { + // Nothing to do if it has already been allocated. + } +#if DMDV2 + /* Named Return Value Optimization (NRVO): + T f(){ + T ret; // &ret == hidden pointer + ret = ... + return ret; // NRVO. + } + */ + else if (gIR->func()->retArg && gIR->func()->decl->nrvo_can && gIR->func()->decl->nrvo_var == vd) { + assert(!isSpecialRefVar(vd) && "Can this happen?"); + vd->ir.irLocal = new IrLocal(vd); + vd->ir.irLocal->value = gIR->func()->retArg; + } +#endif + // normal stack variable, allocate storage on the stack if it has not already been done + else { + vd->ir.irLocal = new IrLocal(vd); + +#if DMDV2 + /* NRVO again: + T t = f(); // t's memory address is taken hidden pointer + */ + ExpInitializer *ei = 0; + if (vd->type->toBasetype()->ty == Tstruct && vd->init && + !!(ei = vd->init->isExpInitializer())) + { + if (ei->exp->op == TOKconstruct) { + AssignExp *ae = static_cast(ei->exp); + if (ae->e2->op == TOKcall) { + CallExp *ce = static_cast(ae->e2); + TypeFunction *tf = static_cast(ce->e1->type->toBasetype()); + if (tf->ty == Tfunction && tf->fty.arg_sret) { + LLValue* const val = ce->toElem(gIR)->getLVal(); + if (isSpecialRefVar(vd)) + { + vd->ir.irLocal->value = DtoAlloca( + vd->type->pointerTo(), vd->toChars()); + DtoStore(val, vd->ir.irLocal->value); + } + else + { + vd->ir.irLocal->value = val; + } + goto Lexit; + } + } + } + } +#endif + + Type* type = isSpecialRefVar(vd) ? vd->type->pointerTo() : vd->type; + LLType* lltype = DtoType(type); + + llvm::Value* allocainst; + if(gTargetData->getTypeSizeInBits(lltype) == 0) + allocainst = llvm::ConstantPointerNull::get(getPtrToType(lltype)); + else + allocainst = DtoAlloca(type, vd->toChars()); + + vd->ir.irLocal->value = allocainst; + + DtoDwarfLocalVariable(allocainst, vd); + } + + if (Logger::enabled()) + Logger::cout() << "llvm value for decl: " << *vd->ir.irLocal->value << '\n'; + + DtoInitializer(vd->ir.irLocal->value, vd->init); // TODO: Remove altogether? + +#if DMDV2 +Lexit: + /* Mark the point of construction of a variable that needs to be destructed. + */ + if (vd->edtor && !vd->noscope) + { + // Put vd on list of things needing destruction + gIR->varsInScope().push_back(vd); + } +#endif +} + DValue* DtoDeclarationExp(Dsymbol* declaration) { Logger::print("DtoDeclarationExp: %s\n", declaration->toChars()); @@ -1036,123 +1140,8 @@ DValue* DtoDeclarationExp(Dsymbol* declaration) } else { - if (global.params.llvmAnnotate) - DtoAnnotation(declaration->toChars()); - - Logger::println("vdtype = %s", vd->type->toChars()); - - // ref vardecls are generated when DMD lowers foreach to a for statement, - // and this is a hack to support them for this case only - if(vd->isRef()) - { - if (!vd->ir.irLocal) - vd->ir.irLocal = new IrLocal(vd); - - ExpInitializer* ex = vd->init->isExpInitializer(); - assert(ex && "ref vars must have expression initializer"); - assert(ex->exp); - AssignExp* as = ex->exp->isAssignExp(); - assert(as && "ref vars must be initialized by an assign exp"); - DValue *val = as->e2->toElem(gIR); - if (val->isLVal()) - { - vd->ir.irLocal->value = val->getLVal(); - } - else - { - LLValue *newVal = DtoAlloca(val->type); - DtoStore(val->getRVal(), newVal); - vd->ir.irLocal->value = newVal; - } - } - - // referenced by nested delegate? - #if DMDV2 - if (vd->nestedrefs.dim) { - #else - if (vd->nestedref) { - #endif - Logger::println("has nestedref set"); - assert(vd->ir.irLocal); - DtoNestedInit(vd); - // is it already allocated? - } else if(vd->ir.irLocal) { - // nothing to do... - } -#if DMDV2 - /* Named Return Value Optimization (NRVO): - T f(){ - T ret; // &ret == hidden pointer - ret = ... - return ret; // NRVO. - } - */ - else if (gIR->func()->retArg && gIR->func()->decl->nrvo_can && gIR->func()->decl->nrvo_var == vd) { - vd->ir.irLocal = new IrLocal(vd); - vd->ir.irLocal->value = gIR->func()->retArg; - } -#endif - // normal stack variable, allocate storage on the stack if it has not already been done - else if(!vd->isRef()) { - vd->ir.irLocal = new IrLocal(vd); - -#if DMDV2 - /* NRVO again: - T t = f(); // t's memory address is taken hidden pointer - */ - ExpInitializer *ei = 0; - if (vd->type->toBasetype()->ty == Tstruct && vd->init && - !!(ei = vd->init->isExpInitializer())) - { - if (ei->exp->op == TOKconstruct) { - AssignExp *ae = static_cast(ei->exp); - if (ae->e2->op == TOKcall) { - CallExp *ce = static_cast(ae->e2); - TypeFunction *tf = static_cast(ce->e1->type->toBasetype()); - if (tf->ty == Tfunction && tf->fty.arg_sret) { - vd->ir.irLocal->value = ce->toElem(gIR)->getLVal(); - goto Lexit; - } - } - } - } -#endif - - LLType* lltype = DtoType(vd->type); - - llvm::Value* allocainst; - if(gTargetData->getTypeSizeInBits(lltype) == 0) - allocainst = llvm::ConstantPointerNull::get(getPtrToType(lltype)); - else - allocainst = DtoAlloca(vd->type, vd->toChars()); - - //allocainst->setAlignment(vd->type->alignsize()); // TODO - vd->ir.irLocal->value = allocainst; - - DtoDwarfLocalVariable(allocainst, vd); - } - else - { - assert(vd->ir.irLocal->value); - } - - if (Logger::enabled()) - Logger::cout() << "llvm value for decl: " << *vd->ir.irLocal->value << '\n'; - if (!vd->isRef()) - DtoInitializer(vd->ir.irLocal->value, vd->init); // TODO: Remove altogether? - -#if DMDV2 - Lexit: - /* Mark the point of construction of a variable that needs to be destructed. - */ - if (vd->edtor && !vd->noscope) - { - // Put vd on list of things needing destruction - gIR->varsInScope().push_back(vd); - } -#endif + DtoVarDeclaration(vd); } - return new DVarValue(vd->type, vd, vd->ir.getIrValue()); } // struct declaration @@ -1921,6 +1910,13 @@ void callPostblit(Loc &loc, Expression *exp, LLValue *val) ////////////////////////////////////////////////////////////////////////////////////////// +bool isSpecialRefVar(VarDeclaration* vd) +{ + return (vd->storage_class & STCref) && (vd->storage_class & STCforeach); +} + +////////////////////////////////////////////////////////////////////////////////////////// + void printLabelName(std::ostream& target, const char* func_mangle, const char* label_name) { target << gTargetMachine->getMCAsmInfo()->getPrivateGlobalPrefix() << diff --git a/gen/llvmhelpers.h b/gen/llvmhelpers.h index ab80da92..1fd85a07 100644 --- a/gen/llvmhelpers.h +++ b/gen/llvmhelpers.h @@ -98,6 +98,7 @@ void DtoResolveDsymbol(Dsymbol* dsym); void DtoConstInitGlobal(VarDeclaration* vd); // declaration inside a declarationexp +void DtoVarDeclaration(VarDeclaration* var); DValue* DtoDeclarationExp(Dsymbol* declaration); LLValue* DtoRawVarDeclaration(VarDeclaration* var, LLValue* addr = 0); @@ -158,6 +159,14 @@ LLValue* makeLValue(Loc& loc, DValue* value); void callPostblit(Loc &loc, Expression *exp, LLValue *val); #endif +/// Returns whether the given variable is a DMD-internal "ref variable". +/// +/// D doesn't have reference variables (the ref keyword is only usable in +/// function signatures and foreach headers), but the DMD frontend internally +/// creates them in cases like lowering a ref foreach to a for loop or the +/// implicit __result variable for ref-return functions with out contracts. +bool isSpecialRefVar(VarDeclaration* vd); + //////////////////////////////////////////// // gen/tocall.cpp stuff below //////////////////////////////////////////// diff --git a/gen/nested.cpp b/gen/nested.cpp index 1e4213ab..7688d6da 100644 --- a/gen/nested.cpp +++ b/gen/nested.cpp @@ -211,7 +211,7 @@ DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd, bool byref) val = DtoGEPi(val, 0, vd->ir.irLocal->nestedIndex, vd->toChars()); Logger::cout() << "Addr: " << *val << '\n'; Logger::cout() << "of type: " << *val->getType() << '\n'; - if (vd->ir.irLocal->byref || byref) { + if (byref || (vd->isParameter() && vd->ir.irParam->arg->byref)) { val = DtoAlignedLoad(val); //dwarfOpDeref(dwarfAddr); Logger::cout() << "Was byref, now: " << *val << '\n'; @@ -251,27 +251,7 @@ void DtoNestedInit(VarDeclaration* vd) DtoAlignedStore(val, gep); } else if (nestedCtx == NCHybrid) { - assert(vd->ir.irLocal->value && "Nested variable without storage?"); - - if (!vd->isParameter() && (vd->isRef() || vd->isOut())) { - unsigned vardepth = vd->ir.irLocal->nestedDepth; - - LLValue* val = NULL; - // Retrieve frame pointer - if (vardepth == irfunc->depth) { - val = nestedVar; - } else { - FuncDeclaration *parentfunc = getParentFunc(vd, true); - assert(parentfunc && "No parent function for nested variable?"); - - val = DtoGEPi(nestedVar, 0, vardepth); - val = DtoAlignedLoad(val, (std::string(".frame.") + parentfunc->toChars()).c_str()); - } - val = DtoGEPi(val, 0, vd->ir.irLocal->nestedIndex, vd->toChars()); - storeVariable(vd, val); - } else { - // Already initialized in DtoCreateNestedContext - } + // Already initialized in DtoCreateNestedContext. } else { assert(0 && "Not implemented yet"); @@ -492,18 +472,13 @@ static void DtoCreateNestedContextType(FuncDeclaration* fd) { type = type->getContainedType(0); else type = DtoType(vd->type); - vd->ir.irParam->byref = false; } else { - vd->ir.irParam->byref = true; } types.push_back(type); - } else if (vd->isRef() || vd->isOut()) { - // Foreach variables can also be by reference, for instance. + } else if (isSpecialRefVar(vd)) { types.push_back(DtoType(vd->type->pointerTo())); - vd->ir.irLocal->byref = true; } else { types.push_back(DtoType(vd->type)); - vd->ir.irLocal->byref = false; } if (Logger::enabled()) { Logger::println("Nested var: %s", vd->toChars()); @@ -692,36 +667,26 @@ void DtoCreateNestedContext(FuncDeclaration* fd) { if (vd->isParameter()) { Logger::println("nested param: %s", vd->toChars()); LOG_SCOPE - LLValue* value = vd->ir.irLocal->value; - if (llvm::isa(llvm::GetUnderlyingObject(value))) { + IrParameter* parm = vd->ir.irParam; + + if (parm->arg->byref) + { + storeVariable(vd, gep); + } + else + { Logger::println("Copying to nested frame"); // The parameter value is an alloca'd stack slot. // Copy to the nesting frame and leave the alloca for // the optimizers to clean up. - assert(!vd->ir.irLocal->byref); - DtoStore(DtoLoad(value), gep); - gep->takeName(value); - vd->ir.irLocal->value = gep; - } else { - Logger::println("Adding pointer to nested frame"); - // The parameter value is something else, such as a - // passed-in pointer (for 'ref' or 'out' parameters) or - // a pointer arg with byval attribute. - // Store the address into the frame. - assert(vd->ir.irLocal->byref); - storeVariable(vd, gep); + DtoStore(DtoLoad(parm->value), gep); + gep->takeName(parm->value); + parm->value = gep; } - } else if (vd->isRef() || vd->isOut()) { - // This slot is initialized in DtoNestedInit, to handle things like byref foreach variables - // which move around in memory. - assert(vd->ir.irLocal->byref); } else { Logger::println("nested var: %s", vd->toChars()); - if (vd->ir.irLocal->value) - Logger::cout() << "Pre-existing value: " << *vd->ir.irLocal->value << '\n'; assert(!vd->ir.irLocal->value); vd->ir.irLocal->value = gep; - assert(!vd->ir.irLocal->byref); } if (global.params.symdebug) { diff --git a/gen/toir.cpp b/gen/toir.cpp index 6064b17d..c348dd10 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -583,6 +583,30 @@ DValue* AssignExp::toElem(IRState* p) return newlen; } + // Can't just override ConstructExp::toElem because not all TOKconstruct + // operations are actually instances of ConstructExp... Long live the DMD + // coding style! + if (op == TOKconstruct) + { + if (e1->op == TOKvar) + { + VarExp* ve = (VarExp*)e1; + if (ve->var->storage_class & STCref) + { + // Note that the variable value is accessed directly (instead + // of via getLValue(), which would perform a load from the + // uninitialized location), and that rhs is stored as an l-value! + + IrLocal* const local = ve->var->ir.irLocal; + assert(local && "ref var must be local and already initialized"); + + DValue* rhs = e2->toElem(p); + DtoStore(rhs->getLVal(), local->value); + return rhs; + } + } + } + Logger::println("performing normal assignment"); DValue* l = e1->toElem(p); diff --git a/ir/irvar.cpp b/ir/irvar.cpp index f41f6acb..e338f123 100644 --- a/ir/irvar.cpp +++ b/ir/irvar.cpp @@ -31,7 +31,6 @@ IrGlobal::IrGlobal(VarDeclaration* v): IrVar(v) IrLocal::IrLocal(VarDeclaration* v) : IrVar(v) { nestedIndex = -1; - byref = false; } ////////////////////////////////////////////////////////////////////////////// diff --git a/ir/irvar.h b/ir/irvar.h index 3d66cc39..680c112b 100644 --- a/ir/irvar.h +++ b/ir/irvar.h @@ -28,8 +28,8 @@ struct IrLocal : IrVar { IrLocal(VarDeclaration* v); - bool byref; // Not used for -nested-ctx=array - int nestedDepth; // ditto + // Used for hybrid nested context creation. + int nestedDepth; int nestedIndex; }; From d4eafe53e05d7ec6537653f98161f83eddb5ff7f Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Tue, 4 Sep 2012 01:58:19 +0200 Subject: [PATCH 22/33] Removed obsolete nested context styles. NChybrid was the only one that didn't instantly trigger a "not implemented" assertion on any code using nested function for a long time, and removing the cruft greatly improves code readability (maintainability is a moot point anyway given its current state). --- gen/functions.cpp | 8 +- gen/llvmhelpers.cpp | 8 +- gen/nested.cpp | 708 +++++++++++++++++--------------------------- gen/nested.h | 3 - 4 files changed, 272 insertions(+), 455 deletions(-) diff --git a/gen/functions.cpp b/gen/functions.cpp index 5e540c21..73eb433e 100644 --- a/gen/functions.cpp +++ b/gen/functions.cpp @@ -807,14 +807,14 @@ void DtoDefineFunction(FuncDeclaration* fd) DtoCreateNestedContext(fd); + if (fd->vresult && ! #if DMDV2 - if (fd->vresult && fd->vresult->nestedrefs.dim) // FIXME: not sure here :/ + fd->vresult->nestedrefs.dim // FIXME: not sure here :/ #else - if (fd->vresult && fd->vresult->nestedref) + fd->vresult->nestedref #endif + ) { - DtoNestedInit(fd->vresult); - } else if (fd->vresult) { DtoVarDeclaration(fd->vresult); } diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index de90a17f..8db92d06 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -1029,10 +1029,10 @@ void DtoVarDeclaration(VarDeclaration* vd) #endif { Logger::println("has nestedref set (referenced by nested function/delegate)"); - assert(vd->ir.irLocal); - DtoNestedInit(vd); + assert(vd->ir.irLocal && "irLocal is expected to be already set by DtoCreateNestedContext"); } - else if(vd->ir.irLocal) + + if(vd->ir.irLocal) { // Nothing to do if it has already been allocated. } @@ -1265,8 +1265,6 @@ LLValue* DtoRawVarDeclaration(VarDeclaration* var, LLValue* addr) } else assert(!addr || addr == var->ir.irLocal->value); - - DtoNestedInit(var); } // normal local variable else diff --git a/gen/nested.cpp b/gen/nested.cpp index 7688d6da..e84f7446 100644 --- a/gen/nested.cpp +++ b/gen/nested.cpp @@ -12,42 +12,6 @@ #include "llvm/Support/CommandLine.h" namespace cl = llvm::cl; -/// What the context pointer for a nested function looks like -enum NestedCtxType { - /// Context is void*[] of pointers to variables. - /// Variables from higher levels are at the front. - NCArray, - - /// Context is a struct containing variables belonging to the parent function. - /// If the parent function itself has a parent function, one of the members is - /// a pointer to its context. (linked-list style) - // FIXME: implement - // TODO: Functions without any variables accessed by nested functions, but - // with a parent whose variables are accessed, can use the parent's - // context. - // NOTE: This is what DMD seems to do. - NCStruct, - - /// Context is a list of pointers to structs of variables, followed by the - /// variables of the inner-most function with variables accessed by nested - /// functions. The initial pointers point to similar structs for enclosing - /// functions. - /// Only functions whose variables are accessed by nested functions create - /// new frames, others just pass on what got passed in. - NCHybrid -}; - -static cl::opt nestedCtx("nested-ctx", - cl::desc("How to construct a nested function's context:"), - cl::ZeroOrMore, - cl::values( - clEnumValN(NCArray, "array", "Array of pointers to variables (including multi-level)"), - //clEnumValN(NCStruct, "struct", "Struct of variables (with multi-level via linked list)"), - clEnumValN(NCHybrid, "hybrid", "List of pointers to structs of variables, one per level."), - clEnumValEnd), - cl::init(NCHybrid)); - - /****************************************************************************************/ /*//////////////////////////////////////////////////////////////////////////////////////// // NESTED VARIABLE HELPERS @@ -168,94 +132,51 @@ DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd, bool byref) //////////////////////////////////// // Extract variable from nested context - if (nestedCtx == NCArray) { - LLValue* val = DtoBitCast(ctx, getPtrToType(getVoidPtrType())); - val = DtoGEPi1(val, vd->ir.irLocal->nestedIndex); + LLValue* val = DtoBitCast(ctx, LLPointerType::getUnqual(irfunc->frameType)); + Logger::cout() << "Context: " << *val << '\n'; + Logger::cout() << "of type: " << *val->getType() << '\n'; + + unsigned vardepth = vd->ir.irLocal->nestedDepth; + unsigned funcdepth = irfunc->depth; + + Logger::cout() << "Variable: " << vd->toChars() << '\n'; + Logger::cout() << "Variable depth: " << vardepth << '\n'; + Logger::cout() << "Function: " << irfunc->decl->toChars() << '\n'; + Logger::cout() << "Function depth: " << funcdepth << '\n'; + + if (vardepth == funcdepth) { + // This is not always handled above because functions without + // variables accessed by nested functions don't create new frames. + Logger::println("Same depth"); + } else { + // Load frame pointer and index that... + if (dwarfValue && global.params.symdebug) { + dwarfOpOffset(dwarfAddr, val, vd->ir.irLocal->nestedDepth); + dwarfOpDeref(dwarfAddr); + } + Logger::println("Lower depth"); + val = DtoGEPi(val, 0, vd->ir.irLocal->nestedDepth); + Logger::cout() << "Frame index: " << *val << '\n'; + val = DtoAlignedLoad(val, (std::string(".frame.") + vdparent->toChars()).c_str()); + Logger::cout() << "Frame: " << *val << '\n'; + } + + if (dwarfValue && global.params.symdebug) + dwarfOpOffset(dwarfAddr, val, vd->ir.irLocal->nestedIndex); + val = DtoGEPi(val, 0, vd->ir.irLocal->nestedIndex, vd->toChars()); + Logger::cout() << "Addr: " << *val << '\n'; + Logger::cout() << "of type: " << *val->getType() << '\n'; + if (byref || (vd->isParameter() && vd->ir.irParam->arg->byref)) { val = DtoAlignedLoad(val); - assert(vd->ir.irLocal->value); - val = DtoBitCast(val, vd->ir.irLocal->value->getType(), vd->toChars()); - return new DVarValue(astype, vd, val); - } - else if (nestedCtx == NCHybrid) { - LLValue* val = DtoBitCast(ctx, LLPointerType::getUnqual(irfunc->frameType)); - Logger::cout() << "Context: " << *val << '\n'; + //dwarfOpDeref(dwarfAddr); + Logger::cout() << "Was byref, now: " << *val << '\n'; Logger::cout() << "of type: " << *val->getType() << '\n'; - - unsigned vardepth = vd->ir.irLocal->nestedDepth; - unsigned funcdepth = irfunc->depth; - - Logger::cout() << "Variable: " << vd->toChars() << '\n'; - Logger::cout() << "Variable depth: " << vardepth << '\n'; - Logger::cout() << "Function: " << irfunc->decl->toChars() << '\n'; - Logger::cout() << "Function depth: " << funcdepth << '\n'; - - if (vardepth == funcdepth) { - // This is not always handled above because functions without - // variables accessed by nested functions don't create new frames. - Logger::println("Same depth"); - } else { - // Load frame pointer and index that... - if (dwarfValue && global.params.symdebug) { - dwarfOpOffset(dwarfAddr, val, vd->ir.irLocal->nestedDepth); - dwarfOpDeref(dwarfAddr); - } - Logger::println("Lower depth"); - val = DtoGEPi(val, 0, vd->ir.irLocal->nestedDepth); - Logger::cout() << "Frame index: " << *val << '\n'; - val = DtoAlignedLoad(val, (std::string(".frame.") + vdparent->toChars()).c_str()); - Logger::cout() << "Frame: " << *val << '\n'; - } - - if (dwarfValue && global.params.symdebug) - dwarfOpOffset(dwarfAddr, val, vd->ir.irLocal->nestedIndex); - val = DtoGEPi(val, 0, vd->ir.irLocal->nestedIndex, vd->toChars()); - Logger::cout() << "Addr: " << *val << '\n'; - Logger::cout() << "of type: " << *val->getType() << '\n'; - if (byref || (vd->isParameter() && vd->ir.irParam->arg->byref)) { - val = DtoAlignedLoad(val); - //dwarfOpDeref(dwarfAddr); - Logger::cout() << "Was byref, now: " << *val << '\n'; - Logger::cout() << "of type: " << *val->getType() << '\n'; - } - - if (dwarfValue && global.params.symdebug) - DtoDwarfLocalVariable(dwarfValue, vd, dwarfAddr); - - return new DVarValue(astype, vd, val); } - else { - assert(0 && "Not implemented yet"); - } -} -void DtoNestedInit(VarDeclaration* vd) -{ - Logger::println("DtoNestedInit for %s", vd->toChars()); - LOG_SCOPE + if (dwarfValue && global.params.symdebug) + DtoDwarfLocalVariable(dwarfValue, vd, dwarfAddr); - IrFunction* irfunc = gIR->func()->decl->ir.irFunc; - LLValue* nestedVar = irfunc->nestedVar; - - if (nestedCtx == NCArray) { - // alloca as usual if no value already - if (!vd->ir.irLocal->value) - vd->ir.irLocal->value = DtoAlloca(vd->type, vd->toChars()); - - // store the address into the nested vars array - assert(vd->ir.irLocal->nestedIndex >= 0); - LLValue* gep = DtoGEPi(nestedVar, 0, vd->ir.irLocal->nestedIndex); - - assert(isaPointer(vd->ir.irLocal->value)); - LLValue* val = DtoBitCast(vd->ir.irLocal->value, getVoidPtrType()); - - DtoAlignedStore(val, gep); - } - else if (nestedCtx == NCHybrid) { - // Already initialized in DtoCreateNestedContext. - } - else { - assert(0 && "Not implemented yet"); - } + return new DVarValue(astype, vd, val); } #if DMDV2 @@ -316,60 +237,60 @@ LLValue* DtoNestedContext(Loc loc, Dsymbol* sym) { return llvm::UndefValue::get(getVoidPtrType()); } - if (nestedCtx == NCHybrid) { - struct FuncDeclaration* fd = 0; - #if DMDV2 - if (AggregateDeclaration *ad = sym->isAggregateDeclaration()) - // If sym is a nested struct or a nested class, pass the frame - // of the function where sym is declared. - fd = ad->toParent()->isFuncDeclaration(); - else - #endif - if (FuncDeclaration* symfd = sym->isFuncDeclaration()) { - // Make sure we've had a chance to analyze nested context usage - #if DMDV2 - DtoCreateNestedContextType(symfd); - #else - DtoDefineFunction(symfd); - #endif - // if this is for a function that doesn't access variables from - // enclosing scopes, it doesn't matter what we pass. - // Tell LLVM about it by passing an 'undef'. - if (symfd && symfd->ir.irFunc->depth == -1) - return llvm::UndefValue::get(getVoidPtrType()); + struct FuncDeclaration* fd = 0; +#if DMDV2 + if (AggregateDeclaration *ad = sym->isAggregateDeclaration()) + // If sym is a nested struct or a nested class, pass the frame + // of the function where sym is declared. + fd = ad->toParent()->isFuncDeclaration(); + else +#endif + if (FuncDeclaration* symfd = sym->isFuncDeclaration()) { + // Make sure we've had a chance to analyze nested context usage +#if DMDV2 + DtoCreateNestedContextType(symfd); +#else + DtoDefineFunction(symfd); +#endif - // If sym is a nested function, and it's parent context is different than the - // one we got, adjust it. - fd = getParentFunc(symfd, true); + // if this is for a function that doesn't access variables from + // enclosing scopes, it doesn't matter what we pass. + // Tell LLVM about it by passing an 'undef'. + if (symfd && symfd->ir.irFunc->depth == -1) + return llvm::UndefValue::get(getVoidPtrType()); + + // If sym is a nested function, and it's parent context is different than the + // one we got, adjust it. + fd = getParentFunc(symfd, true); + } + if (fd) { + Logger::println("For nested function, parent is %s", fd->toChars()); + FuncDeclaration* ctxfd = irfunc->decl; + Logger::println("Current function is %s", ctxfd->toChars()); + if (fromParent) { + ctxfd = getParentFunc(ctxfd, true); + assert(ctxfd && "Context from outer function, but no outer function?"); } - if (fd) { - Logger::println("For nested function, parent is %s", fd->toChars()); - FuncDeclaration* ctxfd = irfunc->decl; - Logger::println("Current function is %s", ctxfd->toChars()); - if (fromParent) { - ctxfd = getParentFunc(ctxfd, true); - assert(ctxfd && "Context from outer function, but no outer function?"); - } - Logger::println("Context is from %s", ctxfd->toChars()); + Logger::println("Context is from %s", ctxfd->toChars()); - unsigned neededDepth = fd->ir.irFunc->depth; - unsigned ctxDepth = ctxfd->ir.irFunc->depth; + unsigned neededDepth = fd->ir.irFunc->depth; + unsigned ctxDepth = ctxfd->ir.irFunc->depth; - Logger::cout() << "Needed depth: " << neededDepth << '\n'; - Logger::cout() << "Context depth: " << ctxDepth << '\n'; + Logger::cout() << "Needed depth: " << neededDepth << '\n'; + Logger::cout() << "Context depth: " << ctxDepth << '\n'; - if (neededDepth >= ctxDepth) { - // assert(neededDepth <= ctxDepth + 1 && "How are we going more than one nesting level up?"); - // fd needs the same context as we do, so all is well - Logger::println("Calling sibling function or directly nested function"); - } else { - val = DtoBitCast(val, LLPointerType::getUnqual(ctxfd->ir.irFunc->frameType)); - val = DtoGEPi(val, 0, neededDepth); - val = DtoAlignedLoad(val, (std::string(".frame.") + fd->toChars()).c_str()); - } + if (neededDepth >= ctxDepth) { + // assert(neededDepth <= ctxDepth + 1 && "How are we going more than one nesting level up?"); + // fd needs the same context as we do, so all is well + Logger::println("Calling sibling function or directly nested function"); + } else { + val = DtoBitCast(val, LLPointerType::getUnqual(ctxfd->ir.irFunc->frameType)); + val = DtoGEPi(val, 0, neededDepth); + val = DtoAlignedLoad(val, (std::string(".frame.") + fd->toChars()).c_str()); } } + Logger::cout() << "result = " << *val << '\n'; Logger::cout() << "of type " << *val->getType() << '\n'; return val; @@ -397,111 +318,106 @@ static void DtoCreateNestedContextType(FuncDeclaration* fd) { } #endif - if (nestedCtx == NCHybrid) { - // construct nested variables array - if (!fd->nestedVars.empty()) - { - Logger::println("has nested frame"); - // start with adding all enclosing parent frames until a static parent is reached + // construct nested variables array + if (!fd->nestedVars.empty()) + { + Logger::println("has nested frame"); + // start with adding all enclosing parent frames until a static parent is reached - LLStructType* innerFrameType = NULL; - unsigned depth = -1; - if (!fd->isStatic()) { - if (FuncDeclaration* parfd = getParentFunc(fd, true)) { - // Make sure the parent has already been analyzed. - DtoCreateNestedContextType(parfd); + LLStructType* innerFrameType = NULL; + unsigned depth = -1; + if (!fd->isStatic()) { + if (FuncDeclaration* parfd = getParentFunc(fd, true)) { + // Make sure the parent has already been analyzed. + DtoCreateNestedContextType(parfd); - innerFrameType = parfd->ir.irFunc->frameType; - if (innerFrameType) - depth = parfd->ir.irFunc->depth; - } + innerFrameType = parfd->ir.irFunc->frameType; + if (innerFrameType) + depth = parfd->ir.irFunc->depth; } - fd->ir.irFunc->depth = ++depth; - - Logger::cout() << "Function " << fd->toChars() << " has depth " << depth << '\n'; - - typedef std::vector TypeVec; - TypeVec types; - if (depth != 0) { - assert(innerFrameType); - // Add frame pointer types for all but last frame - if (depth > 1) { - for (unsigned i = 0; i < (depth - 1); ++i) { - types.push_back(innerFrameType->getElementType(i)); - } - } - // Add frame pointer type for last frame - types.push_back(LLPointerType::getUnqual(innerFrameType)); - } - - if (Logger::enabled()) { - Logger::println("Frame types: "); - LOG_SCOPE; - for (TypeVec::iterator i = types.begin(); i != types.end(); ++i) - Logger::cout() << **i << '\n'; - } - - // Add the direct nested variables of this function, and update their indices to match. - // TODO: optimize ordering for minimal space usage? - for (std::set::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) - { - VarDeclaration* vd = *i; - if (!vd->ir.irLocal) - vd->ir.irLocal = new IrLocal(vd); - - vd->ir.irLocal->nestedIndex = types.size(); - vd->ir.irLocal->nestedDepth = depth; - if (vd->isParameter()) { - // Parameters will have storage associated with them (to handle byref etc.), - // so handle those cases specially by storing a pointer instead of a value. - IrParameter * irparam = vd->ir.irParam; - LLValue* value = irparam->value; - assert(value); - LLType* type = value->getType(); - bool refout = vd->storage_class & (STCref | STCout); - bool lazy = vd->storage_class & STClazy; - bool byref = irparam->arg->byref; - #if STRUCTTHISREF - bool isVthisPtr = irparam->isVthis && !byref; - #else - bool isVthisPtr = irparam->isVthis; - #endif - if ((!refout && (!byref || lazy)) || isVthisPtr) { - // This will be copied to the nesting frame. - if (lazy) - type = type->getContainedType(0); - else - type = DtoType(vd->type); - } else { - } - types.push_back(type); - } else if (isSpecialRefVar(vd)) { - types.push_back(DtoType(vd->type->pointerTo())); - } else { - types.push_back(DtoType(vd->type)); - } - if (Logger::enabled()) { - Logger::println("Nested var: %s", vd->toChars()); - Logger::cout() << "of type: " << *types.back() << '\n'; - } - } - - LLStructType* frameType = LLStructType::create(gIR->context(), types, - std::string("nest.") + fd->toChars()); - - Logger::cout() << "frameType = " << *frameType << '\n'; - - // Store type in IrFunction - fd->ir.irFunc->frameType = frameType; - } else if (FuncDeclaration* parFunc = getParentFunc(fd, true)) { - // Propagate context arg properties if the context arg is passed on unmodified. - DtoCreateNestedContextType(parFunc); - fd->ir.irFunc->frameType = parFunc->ir.irFunc->frameType; - fd->ir.irFunc->depth = parFunc->ir.irFunc->depth; } - } - else { - assert(0 && "Not implemented yet"); + fd->ir.irFunc->depth = ++depth; + + Logger::cout() << "Function " << fd->toChars() << " has depth " << depth << '\n'; + + typedef std::vector TypeVec; + TypeVec types; + if (depth != 0) { + assert(innerFrameType); + // Add frame pointer types for all but last frame + if (depth > 1) { + for (unsigned i = 0; i < (depth - 1); ++i) { + types.push_back(innerFrameType->getElementType(i)); + } + } + // Add frame pointer type for last frame + types.push_back(LLPointerType::getUnqual(innerFrameType)); + } + + if (Logger::enabled()) { + Logger::println("Frame types: "); + LOG_SCOPE; + for (TypeVec::iterator i = types.begin(); i != types.end(); ++i) + Logger::cout() << **i << '\n'; + } + + // Add the direct nested variables of this function, and update their indices to match. + // TODO: optimize ordering for minimal space usage? + for (std::set::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) + { + VarDeclaration* vd = *i; + if (!vd->ir.irLocal) + vd->ir.irLocal = new IrLocal(vd); + + vd->ir.irLocal->nestedIndex = types.size(); + vd->ir.irLocal->nestedDepth = depth; + if (vd->isParameter()) { + // Parameters will have storage associated with them (to handle byref etc.), + // so handle those cases specially by storing a pointer instead of a value. + IrParameter * irparam = vd->ir.irParam; + LLValue* value = irparam->value; + assert(value); + LLType* type = value->getType(); + bool refout = vd->storage_class & (STCref | STCout); + bool lazy = vd->storage_class & STClazy; + bool byref = irparam->arg->byref; +#if STRUCTTHISREF + bool isVthisPtr = irparam->isVthis && !byref; +#else + bool isVthisPtr = irparam->isVthis; +#endif + if ((!refout && (!byref || lazy)) || isVthisPtr) { + // This will be copied to the nesting frame. + if (lazy) + type = type->getContainedType(0); + else + type = DtoType(vd->type); + } else { + } + types.push_back(type); + } else if (isSpecialRefVar(vd)) { + types.push_back(DtoType(vd->type->pointerTo())); + } else { + types.push_back(DtoType(vd->type)); + } + if (Logger::enabled()) { + Logger::println("Nested var: %s", vd->toChars()); + Logger::cout() << "of type: " << *types.back() << '\n'; + } + } + + LLStructType* frameType = LLStructType::create(gIR->context(), types, + std::string("nest.") + fd->toChars()); + + Logger::cout() << "frameType = " << *frameType << '\n'; + + // Store type in IrFunction + fd->ir.irFunc->frameType = frameType; + } else if (FuncDeclaration* parFunc = getParentFunc(fd, true)) { + // Propagate context arg properties if the context arg is passed on unmodified. + DtoCreateNestedContextType(parFunc); + fd->ir.irFunc->frameType = parFunc->ir.irFunc->frameType; + fd->ir.irFunc->depth = parFunc->ir.irFunc->depth; } } @@ -512,197 +428,103 @@ void DtoCreateNestedContext(FuncDeclaration* fd) { DtoCreateNestedContextType(fd); - if (nestedCtx == NCArray) { - // construct nested variables array - if (!fd->nestedVars.empty()) - { - Logger::println("has nested frame"); - // start with adding all enclosing parent frames until a static parent is reached - int nparelems = 0; - if (!fd->isStatic()) - { - Dsymbol* par = fd->toParent2(); - while (par) - { - if (FuncDeclaration* parfd = par->isFuncDeclaration()) - { - nparelems += parfd->nestedVars.size(); - // stop at first static - if (parfd->isStatic()) - break; - } - else if (par->isClassDeclaration()) - { - // nothing needed - } - else - { - break; - } + // construct nested variables array + if (!fd->nestedVars.empty()) + { + IrFunction* irfunction = fd->ir.irFunc; + unsigned depth = irfunction->depth; + LLStructType *frameType = irfunction->frameType; + // Create frame for current function and append to frames list + // FIXME: alignment ? + LLValue* frame = 0; +#if DMDV2 + if (fd->needsClosure()) + frame = DtoGcMalloc(frameType, ".frame"); + else +#endif + frame = DtoRawAlloca(frameType, 0, ".frame"); - par = par->toParent2(); - } + + // copy parent frames into beginning + if (depth != 0) { + LLValue* src = irfunction->nestArg; + if (!src) { + assert(irfunction->thisArg); + assert(fd->isMember2()); + LLValue* thisval = DtoLoad(irfunction->thisArg); +#if DMDV2 + AggregateDeclaration* cd = fd->isMember2(); +#else + ClassDeclaration* cd = fd->isMember2()->isClassDeclaration(); +#endif + assert(cd); + assert(cd->vthis); + Logger::println("Indexing to 'this'"); +#if DMDV2 + if (cd->isStructDeclaration()) + src = DtoExtractValue(thisval, cd->vthis->ir.irField->index, ".vthis"); + else +#endif + src = DtoLoad(DtoGEPi(thisval, 0, cd->vthis->ir.irField->index, ".vthis")); + } else { + src = DtoLoad(src); } - int nelems = fd->nestedVars.size() + nparelems; - - // make array type for nested vars - LLType* nestedVarsTy = LLArrayType::get(getVoidPtrType(), nelems); - - // alloca it - // FIXME align ? - LLValue* nestedVars = DtoRawAlloca(nestedVarsTy, 0, ".nested_vars"); - - IrFunction* irfunction = fd->ir.irFunc; - - // copy parent frame into beginning - if (nparelems) - { - LLValue* src = irfunction->nestArg; - if (!src) - { - assert(irfunction->thisArg); - assert(fd->isMember2()); - LLValue* thisval = DtoLoad(irfunction->thisArg); - ClassDeclaration* cd = fd->isMember2()->isClassDeclaration(); - assert(cd); - assert(cd->vthis); - src = DtoLoad(DtoGEPi(thisval, 0,cd->vthis->ir.irField->index, ".vthis")); - } else { - src = DtoLoad(src); - } - DtoMemCpy(nestedVars, src, DtoConstSize_t(nparelems*PTRSIZE), + if (depth > 1) { + src = DtoBitCast(src, getVoidPtrType()); + LLValue* dst = DtoBitCast(frame, getVoidPtrType()); + DtoMemCpy(dst, src, DtoConstSize_t((depth-1) * PTRSIZE), getABITypeAlign(getVoidPtrType())); } + // Copy nestArg into framelist; the outer frame is not in the list of pointers + src = DtoBitCast(src, frameType->getContainedType(depth-1)); + LLValue* gep = DtoGEPi(frame, 0, depth-1); + DtoAlignedStore(src, gep); + } - // store in IrFunction - irfunction->nestedVar = nestedVars; + // store context in IrFunction + irfunction->nestedVar = frame; - // go through all nested vars and assign indices - int idx = nparelems; - for (std::set::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) - { - VarDeclaration* vd = *i; - if (!vd->ir.irLocal) - vd->ir.irLocal = new IrLocal(vd); + // go through all nested vars and assign addresses where possible. + for (std::set::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) + { + VarDeclaration* vd = *i; - if (vd->isParameter()) + LLValue* gep = DtoGEPi(frame, 0, vd->ir.irLocal->nestedIndex, vd->toChars()); + if (vd->isParameter()) { + Logger::println("nested param: %s", vd->toChars()); + LOG_SCOPE + IrParameter* parm = vd->ir.irParam; + + if (parm->arg->byref) { - Logger::println("nested param: %s", vd->toChars()); - LLValue* gep = DtoGEPi(nestedVars, 0, idx); - LLValue* val = DtoBitCast(vd->ir.irLocal->value, getVoidPtrType()); - DtoAlignedStore(val, gep); + storeVariable(vd, gep); } else { - Logger::println("nested var: %s", vd->toChars()); + Logger::println("Copying to nested frame"); + // The parameter value is an alloca'd stack slot. + // Copy to the nesting frame and leave the alloca for + // the optimizers to clean up. + DtoStore(DtoLoad(parm->value), gep); + gep->takeName(parm->value); + parm->value = gep; } + } else { + Logger::println("nested var: %s", vd->toChars()); + assert(!vd->ir.irLocal->value); + vd->ir.irLocal->value = gep; + } - vd->ir.irLocal->nestedIndex = idx++; + if (global.params.symdebug) { + LLSmallVector addr; + dwarfOpOffset(addr, frameType, vd->ir.irLocal->nestedIndex); + DtoDwarfLocalVariable(frame, vd, addr); } } - } - else if (nestedCtx == NCHybrid) { - // construct nested variables array - if (!fd->nestedVars.empty()) - { - IrFunction* irfunction = fd->ir.irFunc; - unsigned depth = irfunction->depth; - LLStructType *frameType = irfunction->frameType; - // Create frame for current function and append to frames list - // FIXME: alignment ? - LLValue* frame = 0; -#if DMDV2 - if (fd->needsClosure()) - frame = DtoGcMalloc(frameType, ".frame"); - else -#endif - frame = DtoRawAlloca(frameType, 0, ".frame"); - - - // copy parent frames into beginning - if (depth != 0) { - LLValue* src = irfunction->nestArg; - if (!src) { - assert(irfunction->thisArg); - assert(fd->isMember2()); - LLValue* thisval = DtoLoad(irfunction->thisArg); -#if DMDV2 - AggregateDeclaration* cd = fd->isMember2(); -#else - ClassDeclaration* cd = fd->isMember2()->isClassDeclaration(); -#endif - assert(cd); - assert(cd->vthis); - Logger::println("Indexing to 'this'"); -#if DMDV2 - if (cd->isStructDeclaration()) - src = DtoExtractValue(thisval, cd->vthis->ir.irField->index, ".vthis"); - else -#endif - src = DtoLoad(DtoGEPi(thisval, 0, cd->vthis->ir.irField->index, ".vthis")); - } else { - src = DtoLoad(src); - } - if (depth > 1) { - src = DtoBitCast(src, getVoidPtrType()); - LLValue* dst = DtoBitCast(frame, getVoidPtrType()); - DtoMemCpy(dst, src, DtoConstSize_t((depth-1) * PTRSIZE), - getABITypeAlign(getVoidPtrType())); - } - // Copy nestArg into framelist; the outer frame is not in the list of pointers - src = DtoBitCast(src, frameType->getContainedType(depth-1)); - LLValue* gep = DtoGEPi(frame, 0, depth-1); - DtoAlignedStore(src, gep); - } - - // store context in IrFunction - irfunction->nestedVar = frame; - - // go through all nested vars and assign addresses where possible. - for (std::set::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) - { - VarDeclaration* vd = *i; - - LLValue* gep = DtoGEPi(frame, 0, vd->ir.irLocal->nestedIndex, vd->toChars()); - if (vd->isParameter()) { - Logger::println("nested param: %s", vd->toChars()); - LOG_SCOPE - IrParameter* parm = vd->ir.irParam; - - if (parm->arg->byref) - { - storeVariable(vd, gep); - } - else - { - Logger::println("Copying to nested frame"); - // The parameter value is an alloca'd stack slot. - // Copy to the nesting frame and leave the alloca for - // the optimizers to clean up. - DtoStore(DtoLoad(parm->value), gep); - gep->takeName(parm->value); - parm->value = gep; - } - } else { - Logger::println("nested var: %s", vd->toChars()); - assert(!vd->ir.irLocal->value); - vd->ir.irLocal->value = gep; - } - - if (global.params.symdebug) { - LLSmallVector addr; - dwarfOpOffset(addr, frameType, vd->ir.irLocal->nestedIndex); - DtoDwarfLocalVariable(frame, vd, addr); - } - } - } else if (FuncDeclaration* parFunc = getParentFunc(fd, true)) { - // Propagate context arg properties if the context arg is passed on unmodified. - DtoDeclareFunction(parFunc); - fd->ir.irFunc->frameType = parFunc->ir.irFunc->frameType; - fd->ir.irFunc->depth = parFunc->ir.irFunc->depth; - } - } - else { - assert(0 && "Not implemented yet"); + } else if (FuncDeclaration* parFunc = getParentFunc(fd, true)) { + // Propagate context arg properties if the context arg is passed on unmodified. + DtoDeclareFunction(parFunc); + fd->ir.irFunc->frameType = parFunc->ir.irFunc->frameType; + fd->ir.irFunc->depth = parFunc->ir.irFunc->depth; } } diff --git a/gen/nested.h b/gen/nested.h index 34fff976..91f0a002 100644 --- a/gen/nested.h +++ b/gen/nested.h @@ -13,9 +13,6 @@ /// Creates the context value for a nested function. void DtoCreateNestedContext(FuncDeclaration* fd); -/// Allocate space for variable accessed from nested function. -void DtoNestedInit(VarDeclaration* vd); - /// Resolves the nested context for classes and structs with arbitrary nesting. #if DMDV2 void DtoResolveNestedContext(Loc loc, AggregateDeclaration *decl, LLValue *value); From 207033c4278a059b239b67340ef8cc9443b2c5dd Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Tue, 4 Sep 2012 02:05:43 +0200 Subject: [PATCH 23/33] Removed LDC-only dead code. Helps avoid broken merges. --- dmd2/func.c | 39 --------------------------------------- 1 file changed, 39 deletions(-) diff --git a/dmd2/func.c b/dmd2/func.c index 62b493d0..e58c51fc 100644 --- a/dmd2/func.c +++ b/dmd2/func.c @@ -1658,45 +1658,6 @@ void FuncDeclaration::semantic3(Scope *sc) } fbody = new CompoundStatement(0, a); - -#if 0 // This seems to have been added in with dmd 2.032, see below - // wrap body of synchronized functions in a synchronized statement - if (isSynchronized()) - { - ClassDeclaration *cd = parent->isClassDeclaration(); - if (!cd) - error("synchronized function %s must be a member of a class", toChars()); - - Expression *sync; - if (isStatic()) - { - // static member functions synchronize on classinfo - sync = cd->type->dotExp(sc2, new TypeExp(loc, cd->type), Id::classinfo); - } - else - { - // non-static member functions synchronize on this - sync = new VarExp(loc, vthis); - } - - // we do not want to rerun semantics on the whole function, so we - // manually adjust all labels in the function that currently don't - // have an enclosingScopeExit to use the new SynchronizedStatement - SynchronizedStatement* s = new SynchronizedStatement(loc, sync, NULL); - s->semantic(sc2); - s->body = fbody; - - // LDC - LabelMap::iterator it, end = labmap.end(); - for (it = labmap.begin(); it != end; ++it) - if (it->second->enclosingScopeExit == NULL) - it->second->enclosingScopeExit = s; - - a = new Statements; - a->push(s); - fbody = new CompoundStatement(0, a); - } -#endif #if DMDV2 /* Append destructor calls for parameters as finally blocks. */ From 1cecab16cf234ea0c529d121f856ed49f818bac4 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Tue, 4 Sep 2012 02:49:05 +0200 Subject: [PATCH 24/33] Emit correct TypeInfo argument for _d_arrayassign. Fixes part of DMD testcase 'sdtor'. --- gen/arrays.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/gen/arrays.cpp b/gen/arrays.cpp index 0130c3a4..a39744c4 100644 --- a/gen/arrays.cpp +++ b/gen/arrays.cpp @@ -208,7 +208,10 @@ void DtoArrayAssign(DValue *array, DValue *value, int op) assert(value && array); assert(op != TOKblit); - Type *t = value->type->toBasetype(); + + // Use array->type instead of value->type so as to not accidentally pick + // up a superfluous const layer (TypeInfo_Const doesn't pass on postblit()). + Type *t = array->type->toBasetype(); assert(t->nextOf()); Type *elemType = t->nextOf()->toBasetype(); From 45d9efb20344a5556615493e9e3ffcfa06bba2a7 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Tue, 4 Sep 2012 02:58:03 +0200 Subject: [PATCH 25/33] Call element postblit on "return array[0]". Fixes DMD testcase 'sdtor'. --- gen/llvmhelpers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 8db92d06..3257bfb7 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -1889,7 +1889,7 @@ void callPostblit(Loc &loc, Expression *exp, LLValue *val) { Type *tb = exp->type->toBasetype(); - if ((exp->op == TOKvar || exp->op == TOKdotvar || exp->op == TOKstar || exp->op == TOKthis) && + if ((exp->op == TOKvar || exp->op == TOKdotvar || exp->op == TOKstar || exp->op == TOKthis || exp->op == TOKindex) && tb->ty == Tstruct) { StructDeclaration *sd = static_cast(tb)->sym; if (sd->postblit) From 6275c66a89e8b783f41333f18b7c3bee7b5bd89f Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Thu, 6 Sep 2012 03:37:21 +0200 Subject: [PATCH 26/33] Fixed segfault on invalid naked functions. Emitting a frontend error during codegen is somewhat problematic in any case, but stopping if an error ocurred should work just fine here. --- gen/naked.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/gen/naked.cpp b/gen/naked.cpp index 15bd27e7..b703f758 100644 --- a/gen/naked.cpp +++ b/gen/naked.cpp @@ -18,7 +18,7 @@ void Statement::toNakedIR(IRState *p) { - error("not allowed in naked function"); + error("statement not allowed in naked function"); } ////////////////////////////////////////////////////////////////////////////////////////// @@ -179,6 +179,11 @@ void DtoDefineNakedFunction(FuncDeclaration* fd) // emit body fd->fbody->toNakedIR(gIR); + // We could have generated new errors in toNakedIR(), but we are in codegen + // already so we have to abort here. + if (global.errors) + fatal(); + // emit size after body // llvm does this on linux, but not on osx or Win if (global.params.os != OSMacOSX && global.params.os != OSWindows) From 05b9b14fa9576af5b5934d1932bbeba00f6d2781 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Thu, 6 Sep 2012 03:39:41 +0200 Subject: [PATCH 27/33] Fixed -debuglib in LDMD. --- driver/ldmd.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver/ldmd.cpp b/driver/ldmd.cpp index 32bb9bbf..e170abca 100644 --- a/driver/ldmd.cpp +++ b/driver/ldmd.cpp @@ -775,7 +775,7 @@ void buildCommandLine(std::vector& r, const Params& p) pushSwitches("-d-version=", p.versionIdentifiers, r); pushSwitches("-L=", p.linkerSwitches, r); if (p.defaultLibName) r.push_back(concat("-defaultlib=", p.defaultLibName)); - if (p.debugLibName) r.push_back(concat("-deps=", p.moduleDepsFile)); + if (p.debugLibName) r.push_back(concat("-debuglib=", p.debugLibName)); if (p.hiddenDebugB) r.push_back("-hidden-debug-b"); if (p.hiddenDebugC) r.push_back("-hidden-debug-c"); if (p.hiddenDebugF) r.push_back("-hidden-debug-f"); From 88f08cf92728e03289634703b9c60ff83f2f1c82 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Thu, 6 Sep 2012 20:54:02 +0200 Subject: [PATCH 28/33] Workaround for LLVM bug 11479. The LLVM module name doesn't really seem to impact much aynway. --- gen/module.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/gen/module.cpp b/gen/module.cpp index e96d83ca..a52a4c1b 100644 --- a/gen/module.cpp +++ b/gen/module.cpp @@ -217,9 +217,16 @@ llvm::Module* Module::genLLVMModule(llvm::LLVMContext& context, Ir* sir) assert(!global.errors); // name the module +#if 1 + // Temporary workaround for http://llvm.org/bugs/show_bug.cgi?id=11479 – + // just use the source file name, as it is unlikely to collide with a + // symbol name used somewhere in the module. + llvm::StringRef mname(srcfile->toChars()); +#else llvm::StringRef mname(toChars()); if (md != 0) mname = md->toChars(); +#endif // create a new ir state // TODO look at making the instance static and moving most functionality into IrModule where it belongs From 57b2eb3dad25fe5b7fcff99a3fae777ef433f33e Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Thu, 6 Sep 2012 23:04:50 +0200 Subject: [PATCH 29/33] Fixed crash on nested functions with parameters that have a postblit. Implementing the recursion in DeclarationExp::apply, which seems more natural, lead to a "cannot interpret" CTFE error in Phobos. An upstream bug will be raised about this. --- dmd2/delegatize.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/dmd2/delegatize.c b/dmd2/delegatize.c index b08892f1..b6014892 100644 --- a/dmd2/delegatize.c +++ b/dmd2/delegatize.c @@ -20,6 +20,10 @@ #include "aggregate.h" #include "scope.h" +#if IN_LLVM +#include "init.h" +#endif + /******************************************** * Convert from expression to delegate that returns the expression, * i.e. convert: @@ -110,6 +114,36 @@ int lambdaCheckForNestedRef(Expression *e, void *param) */ switch (e->op) { +#if IN_LLVM + // We also need to consider the initializers of VarDeclarations in + // DeclarationExps, such as generated for postblit invocation for + // function parameters. + // + // Without this check, e.g. the nested reference to a in the delegate + // create for the lazy argument is not picked up in the following case: + // --- + // struct HasPostblit { this(this) {} } + // struct Foo { HasPostblit _data; } + // void receiver(Foo) {} + // void lazyFunc(E)(lazy E e) { e(); } + // void test() { Foo a; lazyFunc(receiver(a)); } + // --- + case TOKdeclaration: + { DeclarationExp *de = (DeclarationExp *)e; + if (VarDeclaration *vd = de->declaration->isVarDeclaration()) + { + if (vd->init) + { + if (ExpInitializer* ei = vd->init->isExpInitializer()) + { + ei->exp->apply(&lambdaCheckForNestedRef, sc); + } + // TODO: Other classes of initializers? + } + } + break; + } +#endif case TOKsymoff: { SymOffExp *se = (SymOffExp *)e; VarDeclaration *v = se->var->isVarDeclaration(); From 139e1a9c2abe5d0dbbb4c06d82ea7b11fca47643 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Fri, 7 Sep 2012 00:04:48 +0200 Subject: [PATCH 30/33] Implement stripModifiers using castMod(0). Reduces the potentail for bugs in the fragile code; castMod(0) is used like this in DMD code. --- gen/llvmhelpers.cpp | 80 +-------------------------------------------- 1 file changed, 1 insertion(+), 79 deletions(-) diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 3257bfb7..910e785d 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -1763,85 +1763,7 @@ Type * stripModifiers( Type * type ) #if DMDV2 if (type->ty == Tfunction) return type; - Type *t = type; - while (t->mod) - { - switch (t->mod) - { - case MODconst: - t = type->cto; - break; - case MODshared: - t = type->sto; - break; - case MODimmutable: - t = type->ito; - break; - case MODshared | MODconst: - t = type->scto; - break; - case MODwild: - t = type->wto; - break; - case MODshared | MODwild: - t = type->swto; - break; - default: - assert(0 && "Unhandled type modifier"); - } - - if (!t) - { - unsigned sz = type->sizeTy[type->ty]; - t = static_cast(malloc(sz)); - memcpy(t, type, sz); - t->mod = 0; - t->deco = NULL; - t->arrayof = NULL; - t->pto = NULL; - t->rto = NULL; - t->cto = NULL; - t->ito = NULL; - t->sto = NULL; - t->scto = NULL; - t->wto = NULL; - t->swto = NULL; - t->vtinfo = NULL; - t = t->merge(); - - t->fixTo(type); - switch (type->mod) - { - case MODconst: - t->cto = type; - break; - - case MODimmutable: - t->ito = type; - break; - - case MODshared: - t->sto = type; - break; - - case MODshared | MODconst: - t->scto = type; - break; - - case MODwild: - t->wto = type; - break; - - case MODshared | MODwild: - t->swto = type; - break; - - default: - assert(0); - } - } - } - return t; + return type->castMod(0); #else return type; #endif From bebc5cce288a1082e0e287642c13e72f3619b1d6 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Fri, 7 Sep 2012 03:12:33 +0200 Subject: [PATCH 31/33] Workaround for Voldemort return type handling issues. See the comment in DtoCallFunction for an explanation of what is going on. The struct zero initialization code was also refactored out to AssignExp::toElem and modified so that it is only triggered on integer->struct assignments, not for any types where the modifier-stripped types don't match up. This would have lead to silently wrong code in the cases where the assert would have been triggered otherwise. Fixes the Phobos testsuite build. --- gen/llvmhelpers.cpp | 14 +------------- gen/tocall.cpp | 34 +++++++++++++++++++++++++++++++++- gen/toir.cpp | 18 ++++++++++++++++-- 3 files changed, 50 insertions(+), 16 deletions(-) diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 910e785d..f8b8ae40 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -393,19 +393,7 @@ void DtoAssign(Loc& loc, DValue* lhs, DValue* rhs, int op) Type* t2 = rhs->getType()->toBasetype(); if (t->ty == Tstruct) { - if (!stripModifiers(t)->equals(stripModifiers(t2))) { - // FIXME: use 'rhs' for something !?! - DtoAggrZeroInit(lhs->getLVal()); -#if DMDV2 - TypeStruct *ts = static_cast(lhs->getType()); - if (ts->sym->isNested() && ts->sym->vthis) - DtoResolveNestedContext(loc, ts->sym, lhs->getLVal()); -#endif - } - else { - DtoAggrCopy(lhs->getLVal(), rhs->getRVal()); - } - + DtoAggrCopy(lhs->getLVal(), rhs->getRVal()); } else if (t->ty == Tarray) { // lhs is slice diff --git a/gen/tocall.cpp b/gen/tocall.cpp index 0a83c0ec..5b6b4696 100644 --- a/gen/tocall.cpp +++ b/gen/tocall.cpp @@ -652,7 +652,39 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* break; default: - assert(0 && "unhandled repainting of return value"); + // Unfortunately, DMD has quirks resp. bugs with regard to name + // mangling: For voldemort-type functions which return a nested + // struct, the mangled name of the return type changes during + // semantic analysis. + // + // (When the function deco is first computed as part of + // determining the return type deco, its return type part is + // left off to avoid cycles. If mangle/toDecoBuffer is then + // called again for the type, it will pick up the previous + // result and return the full deco string for the nested struct + // type, consisting of both the full mangled function name, and + // the struct identifier.) + // + // Thus, the type merging in stripModifiers does not work + // reliably, and the equality check above can fail even if the + // types only differ in a qualifier. + // + // Because a proper fix for this in the frontend is hard, we + // just carry on and hope that the frontend didn't mess up, + // i.e. that the LLVM types really match up. + // + // An example situation where this case occurs is: + // --- + // auto iota() { + // static struct Result { + // this(int) {} + // inout(Result) test() inout { return cast(inout)Result(0); } + // } + // return Result.init; + // } + // void main() { auto r = iota(); } + // --- + break; } if (Logger::enabled()) Logger::cout() << "final return value: " << *retllval << '\n'; diff --git a/gen/toir.cpp b/gen/toir.cpp index c348dd10..d5503094 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -607,10 +607,24 @@ DValue* AssignExp::toElem(IRState* p) } } - Logger::println("performing normal assignment"); - DValue* l = e1->toElem(p); DValue* r = e2->toElem(p); + + if (e1->type->toBasetype()->ty == Tstruct && e2->op == TOKint64) + { + Logger::println("performing aggregate zero initialization"); + assert(e2->toInteger() == 0); + DtoAggrZeroInit(l->getLVal()); +#if DMDV2 + TypeStruct *ts = static_cast(e1->type); + if (ts->sym->isNested() && ts->sym->vthis) + DtoResolveNestedContext(loc, ts->sym, l->getLVal()); +#endif + // Return value should be irrelevant. + return r; + } + + Logger::println("performing normal assignment"); DtoAssign(loc, l, r, op); if (l->isSlice()) From 81b462b12993c9ab940fb5df49445ee61d4914a9 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Fri, 7 Sep 2012 03:31:39 +0200 Subject: [PATCH 32/33] D1 build fix. --- gen/llvmhelpers.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index f8b8ae40..50c47c07 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -1476,12 +1476,14 @@ LLConstant* DtoConstExpInit(Loc loc, Type* type, Expression* exp) Logger::println("type is a static array, building constant array initializer to single value"); return expand_to_sarray(base, exp); } +#if DMDV2 else if (base->ty == Tvector) { LLConstant* val = exp->toConstElem(gIR); TypeVector* tv = (TypeVector*)base; return llvm::ConstantVector::getSplat(tv->size(loc), val); } +#endif else { error(loc, "LDC internal error: cannot yet convert default initializer %s of type %s to %s", From 2750541d0a68bf5b3b5c7ad41cd4e27b463ca618 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Fri, 7 Sep 2012 03:50:36 +0200 Subject: [PATCH 33/33] druntime and dmd-testsuite updates. --- runtime/druntime | 2 +- tests/d2/dmd-testsuite | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/druntime b/runtime/druntime index a382f23b..f611c6ca 160000 --- a/runtime/druntime +++ b/runtime/druntime @@ -1 +1 @@ -Subproject commit a382f23bdcfe9d3d22bfb056f97325af7a3b46a9 +Subproject commit f611c6cacfb158ef82de5c0ff57e89fe469c12ba diff --git a/tests/d2/dmd-testsuite b/tests/d2/dmd-testsuite index 361caa2a..b6145220 160000 --- a/tests/d2/dmd-testsuite +++ b/tests/d2/dmd-testsuite @@ -1 +1 @@ -Subproject commit 361caa2ae2697c320bdcfb119e370ab5bb585325 +Subproject commit b6145220cd266322519619b0cef8b271a0456240