aboutsummaryrefslogtreecommitdiff
path: root/gcc/d
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gdcproject.org>2021-04-02 13:29:22 +0200
committerIain Buclaw <ibuclaw@gdcproject.org>2021-04-04 01:26:20 +0200
commit5a0aa603b2452dca48ad86d97d4b918187d259fc (patch)
tree67439099b8129248a45826b5791912b20ff3c3fb /gcc/d
parentba0f6902666430e5d065a92b3d5292cba91813d3 (diff)
d: Merge upstream dmd 3b808e838, druntime 483bc129, phobos f89dc217a
D front-end changes: - Explicit package visibility attribute is now always applied to introducing scopes. - Added `__traits(totype, string)' to convert mangled type string to an existing type. - Printf-like and scanf-like functions are now detected by prefixing them with `pragma(printf)' for printf-like functions or `pragma(scanf)' for scanf-like functions. - Added `__c_wchar_t', `__c_complex_float', `__c_complex_double', and `__c_complex_real' types for interfacing with C and C++. - Template alias parameters can now be instantiated with basic types, such as `int` or `void function()`. - Mixins can now be used as types in the form `mixin(string) var'. - Mixin expressions can take an argument list, same as `pragma(msg)'. - Implement DIP1034, add `typeof(*null)' types to represent `noreturn'. - `pragma(msg)' can print expressions of type `void'. - It is now an error to use private variables selectively imported from other modules. Due to a bug, some imported private members were visible from other modules, violating the specification. - Added new syntax to declare an alias to a function type using the `alias' syntax based on the assignment operator. - Function literals can now return a value by reference. Phobos changes: - Synchronize C bindings with the latest port fixes in upstream druntime. - Added alias for a `noreturn' type in object.d - Make use of the new `pragma(printf)' and `pragma(scanf)' pragmas, fix all code that got flagged as being incorrect. - Fixed code that relied on bugs in the D import package system. Reviewed-on: https://github.com/dlang/dmd/pull/12339 https://github.com/dlang/druntime/pull/3422 https://github.com/dlang/phobos/pull/7932 gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd 3b808e838. * Make-lang.in (D_FRONTEND_OBJS): Add d/chkformat.o. * d-codegen.cc (build_struct_literal): Handle special enums. * d-convert.cc (convert_expr): Handle noreturn type. (convert_for_condition): Likewise. * d-target.cc (Target::_init): Set type for wchar_t. (TargetCPP::derivedClassOffset): New method. (Target::libraryObjectMonitors): New method. * decl.cc (get_symbol_decl): Set TREE_THIS_VOLATILE for functions of type noreturn. * toir.cc (IRVisitor::visit (ReturnStatement *)): Handle returning noreturn types. * types.cc (TypeVisitor::visit (TypeNoreturn *)): New method. (TypeVisitor::visit (TypeEnum *)): Handle special enums. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime 483bc129. * libdruntime/Makefile.am (DRUNTIME_DSOURCES_DARWIN): Add core/sys/darwin/fcntl.d. (DRUNTIME_DSOURCES_OPENBSD): Add core/sys/openbsd/unistd.d. (DRUNTIME_DSOURCES_WINDOWS): Add core/sys/windows/stdc/malloc.d. * libdruntime/Makefile.in: Regenerate. * src/MERGE: Merge upstream phobos f89dc217a. * src/Makefile.am (PHOBOS_DSOURCES): Add std/regex/internal/tests2.d. * src/Makefile.in: Regenerate. * testsuite/libphobos.exceptions/chain.d: Fix format arguments. * testsuite/libphobos.exceptions/line_trace.d: Likewise.
Diffstat (limited to 'gcc/d')
-rw-r--r--gcc/d/Make-lang.in1
-rw-r--r--gcc/d/d-codegen.cc8
-rw-r--r--gcc/d/d-convert.cc14
-rw-r--r--gcc/d/d-target.cc28
-rw-r--r--gcc/d/decl.cc4
-rw-r--r--gcc/d/dmd/MERGE2
-rw-r--r--gcc/d/dmd/attrib.c39
-rw-r--r--gcc/d/dmd/attrib.h4
-rw-r--r--gcc/d/dmd/blockexit.c2
-rw-r--r--gcc/d/dmd/chkformat.c975
-rw-r--r--gcc/d/dmd/cppmangle.c18
-rw-r--r--gcc/d/dmd/ctfeexpr.c2
-rw-r--r--gcc/d/dmd/dcast.c5
-rw-r--r--gcc/d/dmd/dclass.c20
-rw-r--r--gcc/d/dmd/declaration.h4
-rw-r--r--gcc/d/dmd/denum.c19
-rw-r--r--gcc/d/dmd/dimport.c80
-rw-r--r--gcc/d/dmd/dmangle.c37
-rw-r--r--gcc/d/dmd/dmodule.c33
-rw-r--r--gcc/d/dmd/dscope.c6
-rw-r--r--gcc/d/dmd/dsymbol.c32
-rw-r--r--gcc/d/dmd/dsymbol.h3
-rw-r--r--gcc/d/dmd/dsymbolsem.c139
-rw-r--r--gcc/d/dmd/dtemplate.c210
-rw-r--r--gcc/d/dmd/expression.c1884
-rw-r--r--gcc/d/dmd/expression.h9
-rw-r--r--gcc/d/dmd/expressionsem.c2055
-rw-r--r--gcc/d/dmd/func.c18
-rw-r--r--gcc/d/dmd/hdrgen.c57
-rw-r--r--gcc/d/dmd/hdrgen.h1
-rw-r--r--gcc/d/dmd/idgen.c8
-rw-r--r--gcc/d/dmd/import.h1
-rw-r--r--gcc/d/dmd/module.h1
-rw-r--r--gcc/d/dmd/mtype.c282
-rw-r--r--gcc/d/dmd/mtype.h38
-rw-r--r--gcc/d/dmd/parse.c217
-rw-r--r--gcc/d/dmd/parse.h1
-rw-r--r--gcc/d/dmd/scope.h4
-rw-r--r--gcc/d/dmd/semantic2.c20
-rw-r--r--gcc/d/dmd/semantic3.c34
-rw-r--r--gcc/d/dmd/statement.c36
-rw-r--r--gcc/d/dmd/statement.h3
-rw-r--r--gcc/d/dmd/statementsem.c2
-rw-r--r--gcc/d/dmd/target.h4
-rw-r--r--gcc/d/dmd/template.h1
-rw-r--r--gcc/d/dmd/templateparamsem.c2
-rw-r--r--gcc/d/dmd/traits.c103
-rw-r--r--gcc/d/dmd/typesem.c77
-rw-r--r--gcc/d/dmd/visitor.h4
-rw-r--r--gcc/d/toir.cc7
-rw-r--r--gcc/d/types.cc47
51 files changed, 4332 insertions, 2269 deletions
diff --git a/gcc/d/Make-lang.in b/gcc/d/Make-lang.in
index 75857d81ec7..b3c77a08f46 100644
--- a/gcc/d/Make-lang.in
+++ b/gcc/d/Make-lang.in
@@ -64,6 +64,7 @@ D_FRONTEND_OBJS = \
d/blockexit.o \
d/canthrow.o \
d/checkedint.o \
+ d/chkformat.o \
d/clone.o \
d/cond.o \
d/constfold.o \
diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc
index 5e6f240cb90..608abcd94f5 100644
--- a/gcc/d/d-codegen.cc
+++ b/gcc/d/d-codegen.cc
@@ -1153,6 +1153,14 @@ build_struct_literal (tree type, vec <constructor_elt, va_gc> *init)
if (vec_safe_is_empty (init))
return build_constructor (type, NULL);
+ /* Struct literals can be seen for special enums representing `_Complex',
+ make sure to reinterpret the literal as the correct type. */
+ if (COMPLEX_FLOAT_TYPE_P (type))
+ {
+ gcc_assert (vec_safe_length (init) == 2);
+ return build_complex (type, (*init)[0].value, (*init)[1].value);
+ }
+
vec <constructor_elt, va_gc> *ve = NULL;
HOST_WIDE_INT offset = 0;
bool constant_p = true;
diff --git a/gcc/d/d-convert.cc b/gcc/d/d-convert.cc
index f407a46da6e..3073edaae9f 100644
--- a/gcc/d/d-convert.cc
+++ b/gcc/d/d-convert.cc
@@ -559,7 +559,9 @@ convert_expr (tree exp, Type *etype, Type *totype)
break;
case Tnull:
- /* Casting from typeof(null) is represented as all zeros. */
+ case Tnoreturn:
+ /* Casting from `typeof(null)' for `null' expressions, or `typeof(*null)'
+ for `noreturn' expressions is represented as all zeros. */
result = build_typeof_null_value (totype);
/* Make sure the expression is still evaluated if necessary. */
@@ -742,6 +744,16 @@ convert_for_condition (tree expr, Type *type)
break;
}
+ case Tnoreturn:
+ /* Front-end allows conditionals that never return, represent the
+ conditional result value as all zeros. */
+ result = build_zero_cst (d_bool_type);
+
+ /* Make sure the expression is still evaluated if necessary. */
+ if (TREE_SIDE_EFFECTS (expr))
+ result = compound_expr (expr, result);
+ break;
+
default:
result = expr;
break;
diff --git a/gcc/d/d-target.cc b/gcc/d/d-target.cc
index d50fcef22e2..a1dc2ee286f 100644
--- a/gcc/d/d-target.cc
+++ b/gcc/d/d-target.cc
@@ -164,6 +164,15 @@ Target::_init (const Param &)
this->c.longsize = int_size_in_bytes (long_integer_type_node);
this->c.long_doublesize = int_size_in_bytes (long_double_type_node);
+ /* Define what type to use for wchar_t. We don't want to support wide
+ characters less than "short" in D. */
+ if (WCHAR_TYPE_SIZE == 32)
+ this->c.twchar_t = Type::basic[Tdchar];
+ else if (WCHAR_TYPE_SIZE == 16)
+ this->c.twchar_t = Type::basic[Twchar];
+ else
+ sorry ("D does not support wide characters on this target.");
+
/* Set-up target C++ ABI. */
this->cpp.reverseOverloads = false;
this->cpp.exceptions = true;
@@ -417,6 +426,15 @@ TargetCPP::fundamentalType (const Type *, bool &)
return false;
}
+/* Get the starting offset position for fields of an `extern(C++)` class
+ that is derived from the given BASE_CLASS. */
+
+unsigned
+TargetCPP::derivedClassOffset(ClassDeclaration *base_class)
+{
+ return base_class->structsize;
+}
+
/* Return the default system linkage for the target. */
LINK
@@ -517,3 +535,13 @@ Target::getTargetInfo (const char *key, const Loc &loc)
return NULL;
}
+
+/**
+ * Returns true if the implementation for object monitors is always defined
+ * in the D runtime library (rt/monitor_.d). */
+
+bool
+Target::libraryObjectMonitors (FuncDeclaration *, Statement *)
+{
+ return true;
+}
diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc
index 042abbfc48a..0ec19345272 100644
--- a/gcc/d/decl.cc
+++ b/gcc/d/decl.cc
@@ -1277,6 +1277,10 @@ get_symbol_decl (Declaration *decl)
if (decl->storage_class & STCfinal)
DECL_FINAL_P (decl->csym) = 1;
+ /* Function is of type `noreturn' or `typeof(*null)'. */
+ if (fd->type->nextOf ()->ty == Tnoreturn)
+ TREE_THIS_VOLATILE (decl->csym) = 1;
+
/* Check whether this function is expanded by the frontend. */
DECL_INTRINSIC_CODE (decl->csym) = INTRINSIC_NONE;
maybe_set_intrinsic (fd);
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index 78b454c1c64..86475c80d35 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@
-a3c9bf422e7ff54d45846b8c577ee82da4234db1
+3b808e838bb00f527eb4ed5281cd985756237b8f
The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository.
diff --git a/gcc/d/dmd/attrib.c b/gcc/d/dmd/attrib.c
index 56b8ce816be..a808b8a6c3f 100644
--- a/gcc/d/dmd/attrib.c
+++ b/gcc/d/dmd/attrib.c
@@ -80,8 +80,8 @@ Scope *AttribDeclaration::createNewScope(Scope *sc,
if (stc != sc->stc ||
linkage != sc->linkage ||
cppmangle != sc->cppmangle ||
- !protection.isSubsetOf(sc->protection) ||
explicitProtection != sc->explicitProtection ||
+ !(protection == sc->protection) ||
aligndecl != sc->aligndecl ||
inlining != sc->inlining)
{
@@ -552,10 +552,21 @@ void ProtDeclaration::addMember(Scope *sc, ScopeDsymbol *sds)
if (protection.kind == Prot::package_ && protection.pkg && sc->_module)
{
Module *m = sc->_module;
- Package* pkg = m->parent ? m->parent->isPackage() : NULL;
- if (!pkg || !protection.pkg->isAncestorPackageOf(pkg))
- error("does not bind to one of ancestor packages of module `%s`",
- m->toPrettyChars(true));
+
+ // While isAncestorPackageOf does an equality check, the fix for issue 17441 adds a check to see if
+ // each package's .isModule() properites are equal.
+ //
+ // Properties generated from `package(foo)` i.e. protection.pkg have .isModule() == null.
+ // This breaks package declarations of the package in question if they are declared in
+ // the same package.d file, which _do_ have a module associated with them, and hence a non-null
+ // isModule()
+ if (!m->isPackage() || !protection.pkg->ident->equals(m->isPackage()->ident))
+ {
+ Package* pkg = m->parent ? m->parent->isPackage() : NULL;
+ if (!pkg || !protection.pkg->isAncestorPackageOf(pkg))
+ error("does not bind to one of ancestor packages of module `%s`",
+ m->toPrettyChars(true));
+ }
}
return AttribDeclaration::addMember(sc, sds);
@@ -795,6 +806,18 @@ Scope *PragmaDeclaration::newScope(Scope *sc)
sc->protection, sc->explicitProtection, sc->aligndecl,
inlining);
}
+ if (ident == Id::printf || ident == Id::scanf)
+ {
+ Scope *sc2 = sc->push();
+
+ if (ident == Id::printf)
+ // Override previous setting, never let both be set
+ sc2->flags = (sc2->flags & ~SCOPEscanf) | SCOPEprintf;
+ else
+ sc2->flags = (sc2->flags & ~SCOPEprintf) | SCOPEscanf;
+
+ return sc2;
+ }
return sc;
}
@@ -1164,12 +1187,12 @@ void ForwardingAttribDeclaration::addMember(Scope *sc, ScopeDsymbol *sds)
// These are mixin declarations, like mixin("int x");
-CompileDeclaration::CompileDeclaration(Loc loc, Expression *exp)
+CompileDeclaration::CompileDeclaration(Loc loc, Expressions *exps)
: AttribDeclaration(NULL)
{
//printf("CompileDeclaration(loc = %d)\n", loc.linnum);
this->loc = loc;
- this->exp = exp;
+ this->exps = exps;
this->scopesym = NULL;
this->compiled = false;
}
@@ -1177,7 +1200,7 @@ CompileDeclaration::CompileDeclaration(Loc loc, Expression *exp)
Dsymbol *CompileDeclaration::syntaxCopy(Dsymbol *)
{
//printf("CompileDeclaration::syntaxCopy('%s')\n", toChars());
- return new CompileDeclaration(loc, exp->syntaxCopy());
+ return new CompileDeclaration(loc, Expression::arraySyntaxCopy(exps));
}
void CompileDeclaration::addMember(Scope *, ScopeDsymbol *sds)
diff --git a/gcc/d/dmd/attrib.h b/gcc/d/dmd/attrib.h
index 74364176128..174d3c1ad5b 100644
--- a/gcc/d/dmd/attrib.h
+++ b/gcc/d/dmd/attrib.h
@@ -234,12 +234,12 @@ public:
class CompileDeclaration : public AttribDeclaration
{
public:
- Expression *exp;
+ Expressions *exps;
ScopeDsymbol *scopesym;
bool compiled;
- CompileDeclaration(Loc loc, Expression *exp);
+ CompileDeclaration(Loc loc, Expressions *exps);
Dsymbol *syntaxCopy(Dsymbol *s);
void addMember(Scope *sc, ScopeDsymbol *sds);
void setScope(Scope *sc);
diff --git a/gcc/d/dmd/blockexit.c b/gcc/d/dmd/blockexit.c
index 44e3cc13bd3..1895d36fb1e 100644
--- a/gcc/d/dmd/blockexit.c
+++ b/gcc/d/dmd/blockexit.c
@@ -62,6 +62,8 @@ int blockExit(Statement *s, FuncDeclaration *func, bool mustNotThrow)
return;
}
}
+ if (s->exp->type->toBasetype()->isTypeNoreturn())
+ result = BEhalt;
if (canThrow(s->exp, func, mustNotThrow))
result |= BEthrow;
}
diff --git a/gcc/d/dmd/chkformat.c b/gcc/d/dmd/chkformat.c
new file mode 100644
index 00000000000..d00b658ca00
--- /dev/null
+++ b/gcc/d/dmd/chkformat.c
@@ -0,0 +1,975 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ */
+
+// Check the arguments to `printf` and `scanf` against the `format` string.
+
+#include "root/dsystem.h"
+#include "root/dcompat.h"
+
+#include "arraytypes.h"
+#include "cond.h"
+#include "errors.h"
+#include "expression.h"
+#include "globals.h"
+#include "identifier.h"
+#include "mtype.h"
+#include "target.h"
+
+
+/* Different kinds of formatting specifications, variations we don't
+ care about are merged. (Like we don't care about the difference between
+ f, e, g, a, etc.)
+
+ For `scanf`, every format is a pointer.
+ */
+enum Format
+{
+ Format_d, // int
+ Format_hhd, // signed char
+ Format_hd, // short int
+ Format_ld, // long int
+ Format_lld, // long long int
+ Format_jd, // intmax_t
+ Format_zd, // size_t
+ Format_td, // ptrdiff_t
+ Format_u, // unsigned int
+ Format_hhu, // unsigned char
+ Format_hu, // unsigned short int
+ Format_lu, // unsigned long int
+ Format_llu, // unsigned long long int
+ Format_ju, // uintmax_t
+ Format_g, // float (scanf) / double (printf)
+ Format_lg, // double (scanf)
+ Format_Lg, // long double (both)
+ Format_s, // char string (both)
+ Format_ls, // wchar_t string (both)
+ Format_c, // char (printf)
+ Format_lc, // wint_t (printf)
+ Format_p, // pointer
+ Format_n, // pointer to int
+ Format_hhn, // pointer to signed char
+ Format_hn, // pointer to short
+ Format_ln, // pointer to long int
+ Format_lln, // pointer to long long int
+ Format_jn, // pointer to intmax_t
+ Format_zn, // pointer to size_t
+ Format_tn, // pointer to ptrdiff_t
+ Format_GNU_a, // GNU ext. : address to a string with no maximum size (scanf)
+ Format_GNU_m, // GNU ext. : string corresponding to the error code in errno (printf) / length modifier (scanf)
+ Format_percent, // %% (i.e. no argument)
+ Format_error, // invalid format specification
+};
+
+/**************************************
+ * Parse the *length specifier* and the *specifier* of the following form:
+ * `[length]specifier`
+ *
+ * Params:
+ * format = format string
+ * idx = index of of start of format specifier,
+ * which gets updated to index past the end of it,
+ * even if `Format_error` is returned
+ * genSpecifier = Generic specifier. For instance, it will be set to `d` if the
+ * format is `hdd`.
+ * Returns:
+ * Format
+ */
+static Format parseGenericFormatSpecifier(const char *format,
+ size_t &idx, char &genSpecifier, bool useGNUExts =
+ findCondition(global.versionids, Identifier::idPool("CRuntime_Glibc")))
+{
+ genSpecifier = 0;
+
+ const size_t length = strlen(format);
+
+ /* Read the `length modifier`
+ */
+ const char lm = format[idx];
+ bool lm1= false; // if jztL
+ bool lm2= false; // if `hh` or `ll`
+ if (lm == 'j' ||
+ lm == 'z' ||
+ lm == 't' ||
+ lm == 'L')
+ {
+ ++idx;
+ if (idx == length)
+ return Format_error;
+ lm1 = true;
+ }
+ else if (lm == 'h' || lm == 'l')
+ {
+ ++idx;
+ if (idx == length)
+ return Format_error;
+ lm2 = lm == format[idx];
+ if (lm2)
+ {
+ ++idx;
+ if (idx == length)
+ return Format_error;
+ }
+ }
+
+ /* Read the `specifier`
+ */
+ Format specifier;
+ const char sc = format[idx];
+ genSpecifier = sc;
+ switch (sc)
+ {
+ case 'd':
+ case 'i':
+ if (lm == 'L')
+ specifier = Format_error;
+ else
+ specifier = lm == 'h' && lm2 ? Format_hhd :
+ lm == 'h' ? Format_hd :
+ lm == 'l' && lm2 ? Format_lld :
+ lm == 'l' ? Format_ld :
+ lm == 'j' ? Format_jd :
+ lm == 'z' ? Format_zd :
+ lm == 't' ? Format_td :
+ Format_d;
+ break;
+
+ case 'u':
+ case 'o':
+ case 'x':
+ case 'X':
+ if (lm == 'L')
+ specifier = Format_error;
+ else
+ specifier = lm == 'h' && lm2 ? Format_hhu :
+ lm == 'h' ? Format_hu :
+ lm == 'l' && lm2 ? Format_llu :
+ lm == 'l' ? Format_lu :
+ lm == 'j' ? Format_ju :
+ lm == 'z' ? Format_zd :
+ lm == 't' ? Format_td :
+ Format_u;
+ break;
+
+ case 'a':
+ if (useGNUExts)
+ {
+ // https://www.gnu.org/software/libc/manual/html_node/Dynamic-String-Input.html
+ specifier = Format_GNU_a;
+ break;
+ }
+ /* fall through */
+
+ case 'f':
+ case 'F':
+ case 'e':
+ case 'E':
+ case 'g':
+ case 'G':
+ case 'A':
+ if (lm == 'L')
+ specifier = Format_Lg;
+ else if (lm1 || lm2 || lm == 'h')
+ specifier = Format_error;
+ else
+ specifier = lm == 'l' ? Format_lg : Format_g;
+ break;
+
+ case 'c':
+ if (lm1 || lm2 || lm == 'h')
+ specifier = Format_error;
+ else
+ specifier = lm == 'l' ? Format_lc : Format_c;
+ break;
+
+ case 's':
+ if (lm1 || lm2 || lm == 'h')
+ specifier = Format_error;
+ else
+ specifier = lm == 'l' ? Format_ls : Format_s;
+ break;
+
+ case 'p':
+ if (lm1 || lm2 || lm == 'h' || lm == 'l')
+ specifier = Format_error;
+ else
+ specifier = Format_p;
+ break;
+
+ case 'n':
+ if (lm == 'L')
+ specifier = Format_error;
+ else
+ specifier = lm == 'l' && lm2 ? Format_lln :
+ lm == 'l' ? Format_ln :
+ lm == 'h' && lm2 ? Format_hhn :
+ lm == 'h' ? Format_hn :
+ lm == 'j' ? Format_jn :
+ lm == 'z' ? Format_zn :
+ lm == 't' ? Format_tn :
+ Format_n;
+ break;
+
+ case 'm':
+ if (useGNUExts)
+ {
+ // http://www.gnu.org/software/libc/manual/html_node/Other-Output-Conversions.html
+ specifier = Format_GNU_m;
+ break;
+ }
+ goto Ldefault;
+
+ default:
+ Ldefault:
+ specifier = Format_error;
+ break;
+ }
+
+ ++idx;
+ return specifier; // success
+}
+
+Format formatError(size_t &idx, size_t i)
+{
+ idx = i;
+ return Format_error;
+}
+
+/**************************************
+ * Parse the *format specifier* which is of the form:
+ *
+ * `%[*][width][length]specifier`
+ *
+ * Params:
+ * format = format string
+ * idx = index of `%` of start of format specifier,
+ * which gets updated to index past the end of it,
+ * even if `Format_error` is returned
+ * asterisk = set if there is a `*` sub-specifier
+ * Returns:
+ * Format
+ */
+static Format parseScanfFormatSpecifier(const char *format, size_t &idx,
+ bool &asterisk)
+{
+ asterisk = false;
+
+ size_t i = idx;
+ assert(format[i] == '%');
+ const size_t length = strlen(format);
+
+ ++i;
+ if (i == length)
+ return formatError(idx, i);
+
+ if (format[i] == '%')
+ {
+ idx = i + 1;
+ return Format_percent;
+ }
+
+ // * sub-specifier
+ if (format[i] == '*')
+ {
+ ++i;
+ if (i == length)
+ return formatError(idx, i);
+ asterisk = true;
+ }
+
+ // fieldWidth
+ while (isdigit(format[i]))
+ {
+ i++;
+ if (i == length)
+ return formatError(idx, i);
+ }
+
+ /* Read the scanset
+ * A scanset can be anything, so we just check that it is paired
+ */
+ if (format[i] == '[')
+ {
+ while (i < length)
+ {
+ if (format[i] == ']')
+ break;
+ ++i;
+ }
+
+ // no `]` found
+ if (i == length)
+ return formatError(idx, i);
+
+ ++i;
+ // no specifier after `]`
+ // it could be mixed with the one above, but then idx won't have the right index
+ if (i == length)
+ return formatError(idx, i);
+ }
+
+ /* Read the specifier
+ */
+ char genSpec;
+ Format specifier = parseGenericFormatSpecifier(format, i, genSpec);
+ if (specifier == Format_error)
+ return formatError(idx, i);
+
+ idx = i;
+ return specifier; // success
+}
+
+/**************************************
+ * Parse the *format specifier* which is of the form:
+ *
+ * `%[flags][field width][.precision][length modifier]specifier`
+ *
+ * Params:
+ * format = format string
+ * idx = index of `%` of start of format specifier,
+ * which gets updated to index past the end of it,
+ * even if `Format_error` is returned
+ * widthStar = set if * for width
+ * precisionStar = set if * for precision
+ * Returns:
+ * Format
+ */
+static Format parsePrintfFormatSpecifier(const char *format, size_t &idx,
+ bool &widthStar, bool &precisionStar)
+{
+ widthStar = false;
+ precisionStar = false;
+
+ size_t i = idx;
+ assert(format[i] == '%');
+ const size_t format_length = strlen(format);
+ const size_t length = format_length;
+ bool hash = false;
+ bool zero = false;
+ bool flags = false;
+ bool width = false;
+ bool precision = false;
+
+ ++i;
+ if (i == length)
+ return formatError(idx, i);
+
+ if (format[i] == '%')
+ {
+ idx = i + 1;
+ return Format_percent;
+ }
+
+ /* Read the `flags`
+ */
+ while (1)
+ {
+ const char c = format[i];
+ if (c == '-' ||
+ c == '+' ||
+ c == ' ')
+ {
+ flags = true;
+ }
+ else if (c == '#')
+ {
+ hash = true;
+ }
+ else if (c == '0')
+ {
+ zero = true;
+ }
+ else
+ break;
+ ++i;
+ if (i == length)
+ return formatError(idx, i);
+ }
+
+ /* Read the `field width`
+ */
+ {
+ const char c = format[i];
+ if (c == '*')
+ {
+ width = true;
+ widthStar = true;
+ ++i;
+ if (i == length)
+ return formatError(idx, i);
+ }
+ else if ('1' <= c && c <= '9')
+ {
+ width = true;
+ ++i;
+ if (i == length)
+ return formatError(idx, i);
+ while ('0' <= format[i] && format[i] <= '9')
+ {
+ ++i;
+ if (i == length)
+ return formatError(idx, i);
+ }
+ }
+ }
+
+ /* Read the `precision`
+ */
+ if (format[i] == '.')
+ {
+ precision = true;
+ ++i;
+ if (i == length)
+ return formatError(idx, i);
+ const char c = format[i];
+ if (c == '*')
+ {
+ precisionStar = true;
+ ++i;
+ if (i == length)
+ return formatError(idx, i);
+ }
+ else if ('0' <= c && c <= '9')
+ {
+ ++i;
+ if (i == length)
+ return formatError(idx, i);
+ while ('0' <= format[i] && format[i] <= '9')
+ {
+ ++i;
+ if (i == length)
+ return formatError(idx, i);
+ }
+ }
+ }
+
+ /* Read the specifier
+ */
+ char genSpec;
+ Format specifier = parseGenericFormatSpecifier(format, i, genSpec);
+ if (specifier == Format_error)
+ return formatError(idx, i);
+
+ switch (genSpec)
+ {
+ case 'c':
+ case 's':
+ if (hash || zero)
+ return formatError(idx, i);
+ break;
+
+ case 'd':
+ case 'i':
+ if (hash)
+ return formatError(idx, i);
+ break;
+
+ case 'n':
+ if (hash || zero || precision || width || flags)
+ return formatError(idx, i);
+ break;
+
+ default:
+ break;
+ }
+
+ idx = i;
+ return specifier; // success
+}
+
+/*******************************************/
+
+static Expression *getNextPrintfArg(const Loc &loc, Expressions &args, size_t &n,
+ size_t gnu_m_count, bool &skip)
+{
+ if (n == args.length)
+ {
+ if (args.length < (n + 1) - gnu_m_count)
+ deprecation(loc, "more format specifiers than %d arguments", (int)n);
+ else
+ skip = true;
+ return NULL;
+ }
+ return args[n++];
+}
+
+static void errorPrintfFormat(const char *prefix, DString &slice, Expression *arg,
+ const char *texpect, Type *tactual)
+{
+ deprecation(arg->loc, "%sargument `%s` for format specification `\"%.*s\"` must be `%s`, not `%s`",
+ prefix ? prefix : "", arg->toChars(), (int)slice.length, slice.ptr, texpect, tactual->toChars());
+}
+
+/******************************************
+ * Check that arguments to a printf format string are compatible
+ * with that string. Issue errors for incompatibilities.
+ *
+ * Follows the C99 specification for printf.
+ *
+ * Takes a generous, rather than strict, view of compatiblity.
+ * For example, an unsigned value can be formatted with a signed specifier.
+ *
+ * Diagnosed incompatibilities are:
+ *
+ * 1. incompatible sizes which will cause argument misalignment
+ * 2. deferencing arguments that are not pointers
+ * 3. insufficient number of arguments
+ * 4. struct arguments
+ * 5. array and slice arguments
+ * 6. non-pointer arguments to `s` specifier
+ * 7. non-standard formats
+ * 8. undefined behavior per C99
+ *
+ * Per the C Standard, extra arguments are ignored.
+ *
+ * No attempt is made to fix the arguments or the format string.
+ *
+ * Params:
+ * loc = location for error messages
+ * format = format string
+ * args = arguments to match with format string
+ * isVa_list = if a "v" function (format check only)
+ *
+ * Returns:
+ * `true` if errors occurred
+ * References:
+ * C99 7.19.6.1
+ * http://www.cplusplus.com/reference/cstdio/printf/
+ */
+bool checkPrintfFormat(const Loc &loc, const char *format, Expressions &args, bool isVa_list)
+{
+ //printf("checkPrintFormat('%s')\n", format);
+ size_t n = 0; // index in args
+ size_t gnu_m_count = 0; // number of Format_GNU_m
+ const size_t format_length = strlen(format);
+ for (size_t i = 0; i < format_length;)
+ {
+ if (format[i] != '%')
+ {
+ ++i;
+ continue;
+ }
+ bool widthStar = false;
+ bool precisionStar = false;
+ size_t j = i;
+ const Format fmt = parsePrintfFormatSpecifier(format, j, widthStar, precisionStar);
+ DString slice = DString(j - i, format + i);
+ i = j;
+
+ if (fmt == Format_percent)
+ continue; // "%%", no arguments
+
+ if (isVa_list)
+ {
+ // format check only
+ if (fmt == Format_error)
+ deprecation(loc, "format specifier `\"%.*s\"` is invalid", (int)slice.length, slice.ptr);
+ continue;
+ }
+
+ if (fmt == Format_GNU_m)
+ ++gnu_m_count;
+
+ if (widthStar)
+ {
+ bool skip = false;
+ Expression *e = getNextPrintfArg(loc, args, n, gnu_m_count, skip);
+ if (skip)
+ continue;
+ if (!e)
+ return true;
+ Type *t = e->type->toBasetype();
+ if (t->ty != Tint32 && t->ty != Tuns32)
+ errorPrintfFormat("width ", slice, e, "int", t);
+ }
+
+ if (precisionStar)
+ {
+ bool skip = false;
+ Expression *e = getNextPrintfArg(loc, args, n, gnu_m_count, skip);
+ if (skip)
+ continue;
+ if (!e)
+ return true;
+ Type *t = e->type->toBasetype();
+ if (t->ty != Tint32 && t->ty != Tuns32)
+ errorPrintfFormat("precision ", slice, e, "int", t);
+ }
+
+ bool skip = false;
+ Expression *e = getNextPrintfArg(loc, args, n, gnu_m_count, skip);
+ if (skip)
+ continue;
+ if (!e)
+ return true;
+ Type *t = e->type->toBasetype();
+ Type *tnext = t->nextOf();
+ const unsigned c_longsize = target.c.longsize;
+ const bool is64bit = global.params.is64bit;
+
+ // Types which are promoted to int are allowed.
+ // Spec: C99 6.5.2.2.7
+ switch (fmt)
+ {
+ case Format_u: // unsigned int
+ case Format_d: // int
+ if (t->ty != Tint32 && t->ty != Tuns32)
+ errorPrintfFormat(NULL, slice, e, "int", t);
+ break;
+
+ case Format_hhu: // unsigned char
+ case Format_hhd: // signed char
+ if (t->ty != Tint32 && t->ty != Tuns32 && t->ty != Tint8 && t->ty != Tuns8)
+ errorPrintfFormat(NULL, slice, e, "byte", t);
+ break;
+
+ case Format_hu: // unsigned short int
+ case Format_hd: // short int
+ if (t->ty != Tint32 && t->ty != Tuns32 && t->ty != Tint16 && t->ty != Tuns16)
+ errorPrintfFormat(NULL, slice, e, "short", t);
+ break;
+
+ case Format_lu: // unsigned long int
+ case Format_ld: // long int
+ if (!(t->isintegral() && t->size() == c_longsize))
+ errorPrintfFormat(NULL, slice, e, (c_longsize == 4 ? "int" : "long"), t);
+ break;
+
+ case Format_llu: // unsigned long long int
+ case Format_lld: // long long int
+ if (t->ty != Tint64 && t->ty != Tuns64)
+ errorPrintfFormat(NULL, slice, e, "long", t);
+ break;
+
+ case Format_ju: // uintmax_t
+ case Format_jd: // intmax_t
+ if (t->ty != Tint64 && t->ty != Tuns64)
+ errorPrintfFormat(NULL, slice, e, "core.stdc.stdint.intmax_t", t);
+ break;
+
+ case Format_zd: // size_t
+ if (!(t->isintegral() && t->size() == (is64bit ? 8 : 4)))
+ errorPrintfFormat(NULL, slice, e, "size_t", t);
+ break;
+
+ case Format_td: // ptrdiff_t
+ if (!(t->isintegral() && t->size() == (is64bit ? 8 : 4)))
+ errorPrintfFormat(NULL, slice, e, "ptrdiff_t", t);
+ break;
+
+ case Format_GNU_a: // Format_GNU_a is only for scanf
+ case Format_lg:
+ case Format_g: // double
+ if (t->ty != Tfloat64 && t->ty != Timaginary64)
+ errorPrintfFormat(NULL, slice, e, "double", t);
+ break;
+
+ case Format_Lg: // long double
+ if (t->ty != Tfloat80 && t->ty != Timaginary80)
+ errorPrintfFormat(NULL, slice, e, "real", t);
+ break;
+
+ case Format_p: // pointer
+ if (t->ty != Tpointer && t->ty != Tnull && t->ty != Tclass && t->ty != Tdelegate && t->ty != Taarray)
+ errorPrintfFormat(NULL, slice, e, "void*", t);
+ break;
+
+ case Format_n: // pointer to int
+ if (!(t->ty == Tpointer && tnext->ty == Tint32))
+ errorPrintfFormat(NULL, slice, e, "int*", t);
+ break;
+
+ case Format_ln: // pointer to long int
+ if (!(t->ty == Tpointer && tnext->isintegral() && tnext->size() == c_longsize))
+ errorPrintfFormat(NULL, slice, e, (c_longsize == 4 ? "int*" : "long*"), t);
+ break;
+
+ case Format_lln: // pointer to long long int
+ if (!(t->ty == Tpointer && tnext->ty == Tint64))
+ errorPrintfFormat(NULL, slice, e, "long*", t);
+ break;
+
+ case Format_hn: // pointer to short
+ if (!(t->ty == Tpointer && tnext->ty == Tint16))
+ errorPrintfFormat(NULL, slice, e, "short*", t);
+ break;
+
+ case Format_hhn: // pointer to signed char
+ if (!(t->ty == Tpointer && tnext->ty == Tint16))
+ errorPrintfFormat(NULL, slice, e, "byte*", t);
+ break;
+
+ case Format_jn: // pointer to intmax_t
+ if (!(t->ty == Tpointer && tnext->ty == Tint64))
+ errorPrintfFormat(NULL, slice, e, "core.stdc.stdint.intmax_t*", t);
+ break;
+
+ case Format_zn: // pointer to size_t
+ if (!(t->ty == Tpointer && tnext->ty == (is64bit ? Tuns64 : Tuns32)))
+ errorPrintfFormat(NULL, slice, e, "size_t*", t);
+ break;
+
+ case Format_tn: // pointer to ptrdiff_t
+ if (!(t->ty == Tpointer && tnext->ty == (is64bit ? Tint64 : Tint32)))
+ errorPrintfFormat(NULL, slice, e, "ptrdiff_t*", t);
+ break;
+
+ case Format_c: // char
+ if (t->ty != Tint32 && t->ty != Tuns32)
+ errorPrintfFormat(NULL, slice, e, "char", t);
+ break;
+
+ case Format_lc: // wint_t
+ if (t->ty != Tint32 && t->ty != Tuns32)
+ errorPrintfFormat(NULL, slice, e, "wchar_t", t);
+ break;
+
+ case Format_s: // pointer to char string
+ if (!(t->ty == Tpointer && (tnext->ty == Tchar || tnext->ty == Tint8 || tnext->ty == Tuns8)))
+ errorPrintfFormat(NULL, slice, e, "char*", t);
+ break;
+
+ case Format_ls: // pointer to wchar_t string
+ {
+ if (!(t->ty == Tpointer && tnext == target.c.twchar_t))
+ errorPrintfFormat(NULL, slice, e, "wchar_t*", t);
+ break;
+ }
+ case Format_error:
+ deprecation(loc, "format specifier `\"%.*s\"` is invalid", (int)slice.length, slice.ptr);
+ break;
+
+ case Format_GNU_m:
+ break; // not assert(0) because it may go through it if there are extra arguments
+
+ case Format_percent:
+ default:
+ assert(0);
+ }
+ }
+ return false;
+}
+
+/*******************************************/
+
+static Expression *getNextScanfArg(const Loc &loc, Expressions &args, size_t &n, bool asterisk)
+{
+ if (n == args.length)
+ {
+ if (!asterisk)
+ deprecation(loc, "more format specifiers than %d arguments", (int)n);
+ return NULL;
+ }
+ return args[n++];
+}
+
+static void errorScanfFormat(const char *prefix, DString &slice,
+ Expression *arg, const char *texpect, Type *tactual)
+{
+ deprecation(arg->loc, "%sargument `%s` for format specification `\"%.*s\"` must be `%s`, not `%s`",
+ prefix ? prefix : "", arg->toChars(), (int)slice.length, slice.ptr, texpect, tactual->toChars());
+}
+
+/******************************************
+ * Check that arguments to a scanf format string are compatible
+ * with that string. Issue errors for incompatibilities.
+ *
+ * Follows the C99 specification for scanf.
+ *
+ * Takes a generous, rather than strict, view of compatiblity.
+ * For example, an unsigned value can be formatted with a signed specifier.
+ *
+ * Diagnosed incompatibilities are:
+ *
+ * 1. incompatible sizes which will cause argument misalignment
+ * 2. deferencing arguments that are not pointers
+ * 3. insufficient number of arguments
+ * 4. struct arguments
+ * 5. array and slice arguments
+ * 6. non-standard formats
+ * 7. undefined behavior per C99
+ *
+ * Per the C Standard, extra arguments are ignored.
+ *
+ * No attempt is made to fix the arguments or the format string.
+ *
+ * Params:
+ * loc = location for error messages
+ * format = format string
+ * args = arguments to match with format string
+ * isVa_list = if a "v" function (format check only)
+ *
+ * Returns:
+ * `true` if errors occurred
+ * References:
+ * C99 7.19.6.2
+ * http://www.cplusplus.com/reference/cstdio/scanf/
+ */
+bool checkScanfFormat(const Loc &loc, const char *format, Expressions &args, bool isVa_list)
+{
+ size_t n = 0;
+ const size_t format_length = strlen(format);
+ for (size_t i = 0; i < format_length;)
+ {
+ if (format[i] != '%')
+ {
+ ++i;
+ continue;
+ }
+ bool asterisk = false;
+ size_t j = i;
+ const Format fmt = parseScanfFormatSpecifier(format, j, asterisk);
+ DString slice = DString(j - i, format + i);
+ i = j;
+
+ if (fmt == Format_percent || asterisk)
+ continue; // "%%", "%*": no arguments
+
+ if (isVa_list)
+ {
+ // format check only
+ if (fmt == Format_error)
+ deprecation(loc, "format specifier `\"%.*s\"` is invalid", (int)slice.length, slice.ptr);
+ continue;
+ }
+
+ Expression *e = getNextScanfArg(loc, args, n, asterisk);
+ if (!e)
+ return true;
+
+ Type *t = e->type->toBasetype();
+ Type *tnext = t->nextOf();
+ const unsigned c_longsize = target.c.longsize;
+ const bool is64bit = global.params.is64bit;
+
+ switch (fmt)
+ {
+ case Format_n:
+ case Format_d: // pointer to int
+ if (!(t->ty == Tpointer && tnext->ty == Tint32))
+ errorScanfFormat(NULL, slice, e, "int*", t);
+ break;
+
+ case Format_hhn:
+ case Format_hhd: // pointer to signed char
+ if (!(t->ty == Tpointer && tnext->ty == Tint16))
+ errorScanfFormat(NULL, slice, e, "byte*", t);
+ break;
+
+ case Format_hn:
+ case Format_hd: // pointer to short
+ if (!(t->ty == Tpointer && tnext->ty == Tint16))
+ errorScanfFormat(NULL, slice, e, "short*", t);
+ break;
+
+ case Format_ln:
+ case Format_ld: // pointer to long int
+ if (!(t->ty == Tpointer && tnext->isintegral() && tnext->size() == c_longsize))
+ errorScanfFormat(NULL, slice, e, (c_longsize == 4 ? "int*" : "long*"), t);
+ break;
+
+ case Format_lln:
+ case Format_lld: // pointer to long long int
+ if (!(t->ty == Tpointer && tnext->ty == Tint64))
+ errorScanfFormat(NULL, slice, e, "long*", t);
+ break;
+
+ case Format_jn:
+ case Format_jd: // pointer to intmax_t
+ if (!(t->ty == Tpointer && tnext->ty == Tint64))
+ errorScanfFormat(NULL, slice, e, "core.stdc.stdint.intmax_t*", t);
+ break;
+
+ case Format_zn:
+ case Format_zd: // pointer to size_t
+ if (!(t->ty == Tpointer && tnext->ty == (is64bit ? Tuns64 : Tuns32)))
+ errorScanfFormat(NULL, slice, e, "size_t*", t);
+ break;
+
+ case Format_tn:
+ case Format_td: // pointer to ptrdiff_t
+ if (!(t->ty == Tpointer && tnext->ty == (is64bit ? Tint64 : Tint32)))
+ errorScanfFormat(NULL, slice, e, "ptrdiff_t*", t);
+ break;
+
+ case Format_u: // pointer to unsigned int
+ if (!(t->ty == Tpointer && tnext->ty == Tuns32))
+ errorScanfFormat(NULL, slice, e, "uint*", t);
+ break;
+
+ case Format_hhu: // pointer to unsigned char
+ if (!(t->ty == Tpointer && tnext->ty == Tuns8))
+ errorScanfFormat(NULL, slice, e, "ubyte*", t);
+ break;
+
+ case Format_hu: // pointer to unsigned short int
+ if (!(t->ty == Tpointer && tnext->ty == Tuns16))
+ errorScanfFormat(NULL, slice, e, "ushort*", t);
+ break;
+
+ case Format_lu: // pointer to unsigned long int
+ if (!(t->ty == Tpointer && tnext->ty == (is64bit ? Tuns64 : Tuns32)))
+ errorScanfFormat(NULL, slice, e, (c_longsize == 4 ? "uint*" : "ulong*"), t);
+ break;
+
+ case Format_llu: // pointer to unsigned long long int
+ if (!(t->ty == Tpointer && tnext->ty == Tuns64))
+ errorScanfFormat(NULL, slice, e, "ulong*", t);
+ break;
+
+ case Format_ju: // pointer to uintmax_t
+ if (!(t->ty == Tpointer && tnext->ty == (is64bit ? Tuns64 : Tuns32)))
+ errorScanfFormat(NULL, slice, e, "ulong*", t);
+ break;
+
+ case Format_g: // pointer to float
+ if (!(t->ty == Tpointer && tnext->ty == Tfloat32))
+ errorScanfFormat(NULL, slice, e, "float*", t);
+ break;
+
+ case Format_lg: // pointer to double
+ if (!(t->ty == Tpointer && tnext->ty == Tfloat64))
+ errorScanfFormat(NULL, slice, e, "double*", t);
+ break;
+
+ case Format_Lg: // pointer to long double
+ if (!(t->ty == Tpointer && tnext->ty == Tfloat80))
+ errorScanfFormat(NULL, slice, e, "real*", t);
+ break;
+
+ case Format_GNU_a:
+ case Format_GNU_m:
+ case Format_c:
+ case Format_s: // pointer to char string
+ if (!(t->ty == Tpointer && (tnext->ty == Tchar || tnext->ty == Tint8 || tnext->ty == Tuns8)))
+ errorScanfFormat(NULL, slice, e, "char*", t);
+ break;
+
+ case Format_lc:
+ case Format_ls: // pointer to wchar_t string
+ {
+ if (!(t->ty == Tpointer && tnext == target.c.twchar_t))
+ errorScanfFormat(NULL, slice, e, "wchar_t*", t);
+ break;
+ }
+ case Format_p: // double pointer
+ if (!(t->ty == Tpointer && tnext->ty == Tpointer))
+ errorScanfFormat(NULL, slice, e, "void**", t);
+ break;
+
+ case Format_error:
+ deprecation(loc, "format specifier `\"%.*s\"` is invalid", (int)slice.length, slice.ptr);
+ break;
+
+ case Format_percent:
+ default:
+ assert(0);
+ }
+ }
+ return false;
+}
diff --git a/gcc/d/dmd/cppmangle.c b/gcc/d/dmd/cppmangle.c
index a0e0b5fb993..baf64c5653e 100644
--- a/gcc/d/dmd/cppmangle.c
+++ b/gcc/d/dmd/cppmangle.c
@@ -806,6 +806,14 @@ public:
writeBasicType(t, 'D', 'n');
}
+ void visit(TypeNoreturn *t)
+ {
+ if (t->isImmutable() || t->isShared())
+ return error(t);
+
+ writeBasicType(t, 0, 'v'); // mangle like `void`
+ }
+
void visit(TypeBasic *t)
{
if (t->isImmutable() || t->isShared())
@@ -1012,7 +1020,7 @@ public:
if (t->isImmutable() || t->isShared())
return error(t);
- /* __c_(u)long(long) get special mangling
+ /* __c_(u)long(long) and others get special mangling
*/
Identifier *id = t->sym->ident;
//printf("enum id = '%s'\n", id->toChars());
@@ -1020,10 +1028,18 @@ public:
return writeBasicType(t, 0, 'l');
else if (id == Id::__c_ulong)
return writeBasicType(t, 0, 'm');
+ else if (id == Id::__c_wchar_t)
+ return writeBasicType(t, 0, 'w');
else if (id == Id::__c_longlong)
return writeBasicType(t, 0, 'x');
else if (id == Id::__c_ulonglong)
return writeBasicType(t, 0, 'y');
+ else if (id == Id::__c_complex_float)
+ return writeBasicType(t, 'C', 'f');
+ else if (id == Id::__c_complex_double)
+ return writeBasicType(t, 'C', 'd');
+ else if (id == Id::__c_complex_real)
+ return writeBasicType(t, 'C', 'e');
doSymbol(t);
}
diff --git a/gcc/d/dmd/ctfeexpr.c b/gcc/d/dmd/ctfeexpr.c
index 1d669e595e5..a8e97833ad0 100644
--- a/gcc/d/dmd/ctfeexpr.c
+++ b/gcc/d/dmd/ctfeexpr.c
@@ -162,7 +162,7 @@ const char *CTFEExp::toChars()
switch (op)
{
case TOKcantexp: return "<cant>";
- case TOKvoidexp: return "<void>";
+ case TOKvoidexp: return "cast(void)0";
case TOKbreak: return "<break>";
case TOKcontinue: return "<continue>";
case TOKgoto: return "<goto>";
diff --git a/gcc/d/dmd/dcast.c b/gcc/d/dmd/dcast.c
index 61e28fe8d13..4dd648bcc48 100644
--- a/gcc/d/dmd/dcast.c
+++ b/gcc/d/dmd/dcast.c
@@ -26,6 +26,7 @@
FuncDeclaration *isFuncAddress(Expression *e, bool *hasOverloads = NULL);
bool isCommutative(TOK op);
MOD MODmerge(MOD mod1, MOD mod2);
+void toAutoQualChars(const char **result, Type *t1, Type *t2);
/* ==================== implicitCast ====================== */
@@ -90,8 +91,10 @@ Expression *implicitCastTo(Expression *e, Scope *sc, Type *t)
//printf("type %p ty %d deco %p\n", type, type->ty, type->deco);
//type = type->semantic(loc, sc);
//printf("type %s t %s\n", type->deco, t->deco);
+ const char *ts[2];
+ toAutoQualChars(ts, e->type, t);
e->error("cannot implicitly convert expression (%s) of type %s to %s",
- e->toChars(), e->type->toChars(), t->toChars());
+ e->toChars(), ts[0], ts[1]);
}
}
result = new ErrorExp();
diff --git a/gcc/d/dmd/dclass.c b/gcc/d/dmd/dclass.c
index c7dbbbea5d3..3f33014da9f 100644
--- a/gcc/d/dmd/dclass.c
+++ b/gcc/d/dmd/dclass.c
@@ -277,15 +277,10 @@ Scope *ClassDeclaration::newScope(Scope *sc)
Scope *sc2 = AggregateDeclaration::newScope(sc);
if (isCOMclass())
{
- if (global.params.isWindows)
- sc2->linkage = LINKwindows;
- else
- {
- /* This enables us to use COM objects under Linux and
- * work with things like XPCOM
- */
- sc2->linkage = LINKc;
- }
+ /* This enables us to use COM objects under Linux and
+ * work with things like XPCOM
+ */
+ sc2->linkage = target.systemLinkage();
}
return sc2;
}
@@ -491,9 +486,10 @@ void ClassDeclaration::finalizeSize()
assert(baseClass->sizeok == SIZEOKdone);
alignsize = baseClass->alignsize;
- structsize = baseClass->structsize;
- if (isCPPclass() && global.params.isWindows)
- structsize = (structsize + alignsize - 1) & ~(alignsize - 1);
+ if (classKind == ClassKind::cpp)
+ structsize = target.cpp.derivedClassOffset(baseClass);
+ else
+ structsize = baseClass->structsize;
}
else if (isInterfaceDeclaration())
{
diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h
index 81b563f4b0f..55c814288e0 100644
--- a/gcc/d/dmd/declaration.h
+++ b/gcc/d/dmd/declaration.h
@@ -118,7 +118,7 @@ struct Match
FuncDeclaration *anyf; // pick a func, any func, to use for error recovery
};
-void functionResolve(Match *m, Dsymbol *fd, Loc loc, Scope *sc, Objects *tiargs, Type *tthis, Expressions *fargs);
+void functionResolve(Match *m, Dsymbol *fd, Loc loc, Scope *sc, Objects *tiargs, Type *tthis, Expressions *fargs, const char **pMessage = NULL);
int overloadApply(Dsymbol *fstart, void *param, int (*fp)(void *, Dsymbol *));
void aliasSemantic(AliasDeclaration *ds, Scope *sc);
@@ -551,6 +551,8 @@ void builtin_init();
#define FUNCFLAGreturnInprocess 0x10 // working on inferring 'return' for parameters
#define FUNCFLAGinlineScanned 0x20 // function has been scanned for inline possibilities
#define FUNCFLAGinferScope 0x40 // infer 'scope' for parameters
+#define FUNCFLAGprintf 0x200 // is a printf-like function
+#define FUNCFLAGscanf 0x400 // is a scanf-like function
class FuncDeclaration : public Declaration
{
diff --git a/gcc/d/dmd/denum.c b/gcc/d/dmd/denum.c
index ca1d3bb771c..bfd3b7274f4 100644
--- a/gcc/d/dmd/denum.c
+++ b/gcc/d/dmd/denum.c
@@ -22,6 +22,19 @@
#include "declaration.h"
#include "init.h"
+bool isSpecialEnumIdent(const Identifier *ident)
+{
+ return ident == Id::__c_long ||
+ ident == Id::__c_ulong ||
+ ident == Id::__c_longlong ||
+ ident == Id::__c_ulonglong ||
+ ident == Id::__c_long_double ||
+ ident == Id::__c_wchar_t ||
+ ident == Id::__c_complex_float ||
+ ident == Id::__c_complex_double ||
+ ident == Id::__c_complex_real;
+}
+
/********************************* EnumDeclaration ****************************/
EnumDeclaration::EnumDeclaration(Loc loc, Identifier *id, Type *memtype)
@@ -187,11 +200,7 @@ Lerrors:
*/
bool EnumDeclaration::isSpecial() const
{
- return (ident == Id::__c_long ||
- ident == Id::__c_ulong ||
- ident == Id::__c_longlong ||
- ident == Id::__c_ulonglong ||
- ident == Id::__c_long_double) && memtype;
+ return isSpecialEnumIdent(ident) && memtype;
}
Expression *EnumDeclaration::getDefaultValue(Loc loc)
diff --git a/gcc/d/dmd/dimport.c b/gcc/d/dmd/dimport.c
index 0d93ed80e58..7b63a186552 100644
--- a/gcc/d/dmd/dimport.c
+++ b/gcc/d/dmd/dimport.c
@@ -161,37 +161,75 @@ void Import::load(Scope *sc)
if (mod && !mod->importedFrom)
mod->importedFrom = sc ? sc->_module->importedFrom : Module::rootModule;
if (!pkg)
- pkg = mod;
+ {
+ if (mod && mod->isPackageFile)
+ {
+ // one level depth package.d file (import pkg; ./pkg/package.d)
+ // it's necessary to use the wrapping Package already created
+ pkg = mod->pkg;
+ }
+ else
+ pkg = mod;
+ }
//printf("-Import::load('%s'), pkg = %p\n", toChars(), pkg);
}
void Import::importAll(Scope *sc)
{
- if (!mod)
+ if (mod) return; // Already done
+ load(sc);
+ if (!mod) return; // Failed
+
+ if (sc->stc & STCstatic)
+ isstatic = true;
+ mod->importAll(NULL);
+ if (mod->md && mod->md->isdeprecated)
{
- load(sc);
- if (mod) // if successfully loaded module
- {
- mod->importAll(NULL);
-
- if (mod->md && mod->md->isdeprecated)
- {
- Expression *msg = mod->md->msg;
- if (StringExp *se = msg ? msg->toStringExp() : NULL)
- mod->deprecation(loc, "is deprecated - %s", se->string);
- else
- mod->deprecation(loc, "is deprecated");
- }
+ Expression *msg = mod->md->msg;
+ if (StringExp *se = msg ? msg->toStringExp() : NULL)
+ mod->deprecation(loc, "is deprecated - %s", se->string);
+ else
+ mod->deprecation(loc, "is deprecated");
+ }
+ if (sc->explicitProtection)
+ protection = sc->protection;
+ if (!isstatic && !aliasId && !names.length)
+ sc->scopesym->importScope(mod, protection);
+ // Enable access to pkgs/mod as soon as posible, because compiler
+ // can traverse them before the import gets semantic (Issue: 21501)
+ if (!aliasId && !names.length)
+ addPackageAccess(sc->scopesym);
+}
- if (sc->explicitProtection)
- protection = sc->protection;
- if (!isstatic && !aliasId && !names.length)
- {
- sc->scopesym->importScope(mod, protection);
- }
+/*******************************
+ * Mark the imported packages as accessible from the current
+ * scope. This access check is necessary when using FQN b/c
+ * we're using a single global package tree.
+ * https://issues.dlang.org/show_bug.cgi?id=313
+ */
+void Import::addPackageAccess(ScopeDsymbol *scopesym)
+{
+ //printf("Import::addPackageAccess('%s') %p\n", toPrettyChars(), this);
+ if (packages)
+ {
+ // import a.b.c.d;
+ Package *p = pkg; // a
+ scopesym->addAccessiblePackage(p, protection);
+ for (size_t i = 1; i < packages->length; i++) // [b, c]
+ {
+ Identifier *id = (*packages)[i];
+ p = (Package *) p->symtab->lookup(id);
+ // https://issues.dlang.org/show_bug.cgi?id=17991
+ // An import of truly empty file/package can happen
+ // https://issues.dlang.org/show_bug.cgi?id=20151
+ // Package in the path conflicts with a module name
+ if (p == NULL)
+ return;
+ scopesym->addAccessiblePackage(p, protection);
}
}
+ scopesym->addAccessiblePackage(mod, protection); // d
}
Dsymbol *Import::toAlias()
diff --git a/gcc/d/dmd/dmangle.c b/gcc/d/dmd/dmangle.c
index 303ae617874..83f4c18bee8 100644
--- a/gcc/d/dmd/dmangle.c
+++ b/gcc/d/dmd/dmangle.c
@@ -82,6 +82,8 @@ void initTypeMangle()
mangleChar[Treturn] = "@";
mangleChar[Tvector] = "@";
mangleChar[Ttraits] = "@";
+ mangleChar[Tmixin] = "@";
+ mangleChar[Tnoreturn] = "@"; // becomes 'Nn'
mangleChar[Tnull] = "n"; // same as TypeNone
@@ -150,7 +152,7 @@ public:
* using upper case letters for all digits but the last digit which uses
* a lower case letter.
* The decoder has to look up the referenced position to determine
- * whether the back reference is an identifer (starts with a digit)
+ * whether the back reference is an identifier (starts with a digit)
* or a type (starts with a letter).
*
* Params:
@@ -414,6 +416,11 @@ public:
visit((Type *)t);
}
+ void visit(TypeNoreturn *)
+ {
+ buf->writestring("Nn");
+ }
+
////////////////////////////////////////////////////////////////////////////
void mangleDecl(Declaration *sthis)
@@ -1085,3 +1092,31 @@ void mangleToBuffer(TemplateInstance *ti, OutBuffer *buf)
Mangler v(buf);
v.mangleTemplateInstance(ti);
}
+
+/**********************************************
+ * Convert a string representing a type (the deco) and
+ * return its equivalent Type.
+ * Params:
+ * deco = string containing the deco
+ * Returns:
+ * null for failed to convert
+ * Type for succeeded
+ */
+
+Type *decoToType(const char *deco)
+{
+ if (!deco)
+ return NULL;
+
+ //printf("decoToType(): %s\n", deco)
+ if (StringValue *sv = Type::stringtable.lookup(deco, strlen(deco)))
+ {
+ if (sv->ptrvalue)
+ {
+ Type *t = (Type *)sv->ptrvalue;
+ assert(t->deco);
+ return t;
+ }
+ }
+ return NULL;
+}
diff --git a/gcc/d/dmd/dmodule.c b/gcc/d/dmd/dmodule.c
index ed01858f06b..472b2b9e7f8 100644
--- a/gcc/d/dmd/dmodule.c
+++ b/gcc/d/dmd/dmodule.c
@@ -52,6 +52,7 @@ Module::Module(const char *filename, Identifier *ident, int doDocComment, int do
members = NULL;
isDocFile = 0;
isPackageFile = false;
+ pkg = NULL;
needmoduleinfo = 0;
selfimports = 0;
rootimports = 0;
@@ -685,15 +686,27 @@ Module *Module::parse()
*
* To avoid the conflict:
* 1. If preceding package name insertion had occurred by Package::resolve,
- * later package.d loading will change Package::isPkgMod to PKGmodule and set Package::mod.
+ * reuse the previous wrapping 'Package' if it exists
* 2. Otherwise, 'package.d' wrapped by 'Package' is inserted to the internal tree in here.
+ *
+ * Then change Package::isPkgMod to PKGmodule and set Package::mod.
+ *
+ * Note that the 'wrapping Package' is the Package that contains package.d and other submodules,
+ * the one inserted to the symbol table.
*/
- Package *p = new Package(ident);
+ Dsymbol *ps = dst->lookup(ident);
+ Package *p = ps ? ps->isPackage() : NULL;
+ if (p == NULL)
+ {
+ p = new Package(ident);
+ p->tag = this->tag; // reuse the same package tag
+ p->symtab = new DsymbolTable();
+ }
+ this->tag= p->tag; // reuse the 'older' package tag
+ this->pkg = p;
p->parent = this->parent;
p->isPkgMod = PKGmodule;
p->mod = this;
- p->tag = this->tag; // reuse the same package tag
- p->symtab = new DsymbolTable();
s = p;
}
if (!dst->insert(s))
@@ -720,15 +733,9 @@ Module *Module::parse()
}
else if (Package *pkg = prev->isPackage())
{
- if (pkg->isPkgMod == PKGunknown && isPackageFile)
- {
- /* If the previous inserted Package is not yet determined as package.d,
- * link it to the actual module.
- */
- pkg->isPkgMod = PKGmodule;
- pkg->mod = this;
- pkg->tag = this->tag; // reuse the same package tag
- }
+ // 'package.d' loaded after a previous 'Package' insertion
+ if (isPackageFile)
+ amodules.push(this); // Add to global array of all modules
else
error(md ? md->loc : loc, "from file %s conflicts with package name %s",
srcname, pkg->toChars());
diff --git a/gcc/d/dmd/dscope.c b/gcc/d/dmd/dscope.c
index 65e6734b035..e56f3936ee0 100644
--- a/gcc/d/dmd/dscope.c
+++ b/gcc/d/dmd/dscope.c
@@ -24,6 +24,7 @@
#include "aggregate.h"
#include "module.h"
#include "id.h"
+#include "target.h"
#include "template.h"
Scope *Scope::freelist = NULL;
@@ -155,7 +156,8 @@ Scope *Scope::push()
s->nofree = 0;
s->fieldinit = saveFieldInit();
s->flags = (flags & (SCOPEcontract | SCOPEdebug | SCOPEctfe | SCOPEcompile | SCOPEconstraint |
- SCOPEnoaccesscheck | SCOPEignoresymbolvisibility));
+ SCOPEnoaccesscheck | SCOPEignoresymbolvisibility |
+ SCOPEprintf | SCOPEscanf));
s->lastdc = NULL;
assert(this != s);
@@ -637,7 +639,7 @@ const char *Scope::search_correct_C(Identifier *ident)
else if (ident == Id::C_unsigned)
tok = TOKuns32;
else if (ident == Id::C_wchar_t)
- tok = global.params.isWindows ? TOKwchar : TOKdchar;
+ tok = target.c.twchar_t->ty == Twchar ? TOKwchar : TOKdchar;
else
return NULL;
return Token::toChars(tok);
diff --git a/gcc/d/dmd/dsymbol.c b/gcc/d/dmd/dsymbol.c
index 89c55576a55..f0c1cf6d93c 100644
--- a/gcc/d/dmd/dsymbol.c
+++ b/gcc/d/dmd/dsymbol.c
@@ -515,7 +515,7 @@ Dsymbol *Dsymbol::search_correct(Identifier *ident)
* Returns:
* symbol found, NULL if not
*/
-Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, RootObject *id)
+Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, RootObject *id, int flags)
{
//printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars());
Dsymbol *s = toAlias();
@@ -533,7 +533,7 @@ Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, RootObject *id)
switch (id->dyncast())
{
case DYNCAST_IDENTIFIER:
- sm = s->search(loc, (Identifier *)id);
+ sm = s->search(loc, (Identifier *)id, flags);
break;
case DYNCAST_DSYMBOL:
@@ -1801,31 +1801,3 @@ bool Prot::operator==(const Prot& other) const
}
return false;
}
-
-/**
- * Checks if parent defines different access restrictions than this one.
- *
- * Params:
- * parent = protection attribute for scope that hosts this one
- *
- * Returns:
- * 'true' if parent is already more restrictive than this one and thus
- * no differentiation is needed.
- */
-bool Prot::isSubsetOf(const Prot& parent) const
-{
- if (this->kind != parent.kind)
- return false;
-
- if (this->kind == Prot::package_)
- {
- if (!this->pkg)
- return true;
- if (!parent.pkg)
- return false;
- if (parent.pkg->isAncestorPackageOf(this->pkg))
- return true;
- }
-
- return true;
-}
diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h
index 1ddfe06e6a1..4aabb5d3c6c 100644
--- a/gcc/d/dmd/dsymbol.h
+++ b/gcc/d/dmd/dsymbol.h
@@ -107,7 +107,6 @@ struct Prot
bool isMoreRestrictiveThan(const Prot other) const;
bool operator==(const Prot& other) const;
- bool isSubsetOf(const Prot& other) const;
};
// in hdrgen.c
@@ -207,7 +206,7 @@ public:
virtual void importAll(Scope *sc);
virtual Dsymbol *search(const Loc &loc, Identifier *ident, int flags = IgnoreNone);
Dsymbol *search_correct(Identifier *id);
- Dsymbol *searchX(Loc loc, Scope *sc, RootObject *id);
+ Dsymbol *searchX(Loc loc, Scope *sc, RootObject *id, int flags);
virtual bool overloadInsert(Dsymbol *s);
virtual d_uns64 size(Loc loc);
virtual bool isforwardRef();
diff --git a/gcc/d/dmd/dsymbolsem.c b/gcc/d/dmd/dsymbolsem.c
index 5d5c9fca769..26e23e98587 100644
--- a/gcc/d/dmd/dsymbolsem.c
+++ b/gcc/d/dmd/dsymbolsem.c
@@ -42,6 +42,8 @@ VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e);
Initializer *inferType(Initializer *init, Scope *sc);
void MODtoBuffer(OutBuffer *buf, MOD mod);
bool reliesOnTident(Type *t, TemplateParameters *tparams = NULL, size_t iStart = 0);
+bool expressionsToString(OutBuffer &buf, Scope *sc, Expressions *exps);
+bool symbolIsVisible(Scope *sc, Dsymbol *s);
Objc *objc();
static unsigned setMangleOverride(Dsymbol *s, char *sym)
@@ -1098,22 +1100,7 @@ public:
scopesym->importScope(imp->mod, imp->protection);
}
- // Mark the imported packages as accessible from the current
- // scope. This access check is necessary when using FQN b/c
- // we're using a single global package tree. See Bugzilla 313.
- if (imp->packages)
- {
- // import a.b.c.d;
- Package *p = imp->pkg; // a
- scopesym->addAccessiblePackage(p, imp->protection);
- for (size_t i = 1; i < imp->packages->length; i++) // [b, c]
- {
- Identifier *id = (*imp->packages)[i];
- p = (Package *) p->symtab->lookup(id);
- scopesym->addAccessiblePackage(p, imp->protection);
- }
- }
- scopesym->addAccessiblePackage(imp->mod, imp->protection); // d
+ imp->addPackageAccess(scopesym);
}
dsymbolSemantic(imp->mod, NULL);
@@ -1130,8 +1117,12 @@ public:
{
AliasDeclaration *ad = imp->aliasdecls[i];
//printf("\tImport %s alias %s = %s, scope = %p\n", toPrettyChars(), imp->aliases[i]->toChars(), imp->names[i]->toChars(), ad->_scope);
- if (imp->mod->search(imp->loc, imp->names[i]))
+ Dsymbol *sym = imp->mod->search(imp->loc, imp->names[i], IgnorePrivateImports);
+ if (sym)
{
+ if (!symbolIsVisible(sc, sym))
+ imp->mod->error(imp->loc, "member `%s` is not visible from module `%s`",
+ imp->names[i]->toChars(), sc->_module->toChars());
dsymbolSemantic(ad, sc);
// If the import declaration is in non-root module,
// analysis of the aliased symbol is deferred.
@@ -1141,7 +1132,7 @@ public:
{
Dsymbol *s = imp->mod->search_correct(imp->names[i]);
if (s)
- imp->mod->error(imp->loc, "import `%s` not found, did you mean %s `%s`?", imp->names[i]->toChars(), s->kind(), s->toChars());
+ imp->mod->error(imp->loc, "import `%s` not found, did you mean %s `%s`?", imp->names[i]->toChars(), s->kind(), s->toPrettyChars());
else
imp->mod->error(imp->loc, "import `%s` not found", imp->names[i]->toChars());
ad->type = Type::terror;
@@ -1312,8 +1303,6 @@ public:
e = expressionSemantic(e, sc);
e = resolveProperties(sc, e);
sc = sc->endCTFE();
-
- // pragma(msg) is allowed to contain types as well as expressions
e = ctfeInterpretForPragmaMsg(e);
if (e->op == TOKerror)
{
@@ -1458,6 +1447,12 @@ public:
}
}
}
+ else if (pd->ident == Id::printf || pd->ident == Id::scanf)
+ {
+ if (pd->args && pd->args->length != 0)
+ pd->error("takes no argument");
+ goto Ldecl;
+ }
else if (global.params.ignoreUnsupportedPragmas)
{
if (global.params.verbose)
@@ -1547,13 +1542,14 @@ public:
Dsymbols *compileIt(CompileDeclaration *cd)
{
//printf("CompileDeclaration::compileIt(loc = %d) %s\n", cd->loc.linnum, cd->exp->toChars());
- StringExp *se = semanticString(sc, cd->exp, "argument to mixin");
- if (!se)
+ OutBuffer buf;
+ if (expressionsToString(buf, sc, cd->exps))
return NULL;
- se = se->toUTF8(sc);
unsigned errors = global.errors;
- Parser p(cd->loc, sc->_module, (utf8_t *)se->string, se->len, 0);
+ const size_t len = buf.length();
+ const char *str = buf.extractChars();
+ Parser p(cd->loc, sc->_module, (const utf8_t *)str, len, false);
p.nextToken();
Dsymbols *d = p.parseDeclDefs(0);
@@ -1562,7 +1558,7 @@ public:
if (p.token.value != TOKeof)
{
- cd->exp->error("incomplete mixin declaration (%s)", se->toChars());
+ cd->error("incomplete mixin declaration (%s)", str);
return NULL;
}
return d;
@@ -1637,7 +1633,7 @@ public:
Scope *sc = m->_scope; // see if already got one from importAll()
if (!sc)
{
- Scope::createGlobal(m); // create root scope
+ sc = Scope::createGlobal(m); // create root scope
}
//printf("Module = %p, linkage = %d\n", sc->scopesym, sc->linkage);
@@ -1735,7 +1731,7 @@ public:
// memtype is forward referenced, so try again later
ed->_scope = scx ? scx : sc->copy();
ed->_scope->setNoFree();
- ed->_scope->_module->addDeferredSemantic(ed);
+ Module::addDeferredSemantic(ed);
Module::dprogress = dprogress_save;
//printf("\tdeferring %s\n", ed->toChars());
ed->semanticRun = PASSinit;
@@ -2233,7 +2229,7 @@ public:
//printf("forward reference - deferring\n");
tm->_scope = scx ? scx : sc->copy();
tm->_scope->setNoFree();
- tm->_scope->_module->addDeferredSemantic(tm);
+ Module::addDeferredSemantic(tm);
return;
}
@@ -2457,6 +2453,23 @@ public:
ns->semanticRun = PASSsemanticdone;
}
+
+private:
+ static bool isPointerToChar(Parameter *p)
+ {
+ if (TypePointer *tptr = p->type->isTypePointer())
+ {
+ return tptr->next->ty == Tchar;
+ }
+ return false;
+ }
+
+ static bool isVa_list(Parameter *p, FuncDeclaration *funcdecl, Scope *sc)
+ {
+ return p->type->equals(target.va_listType(funcdecl->loc, sc));
+ }
+
+public:
void funcDeclarationSemantic(FuncDeclaration *funcdecl)
{
TypeFunction *f;
@@ -2771,6 +2784,45 @@ public:
if (funcdecl->isAbstract() && funcdecl->isFinalFunc())
funcdecl->error("cannot be both final and abstract");
+ if (const unsigned pors = sc->flags & (SCOPEprintf | SCOPEscanf))
+ {
+ /* printf/scanf-like functions must be of the form:
+ * extern (C/C++) T printf([parameters...], const(char)* format, ...);
+ * or:
+ * extern (C/C++) T vprintf([parameters...], const(char)* format, va_list);
+ */
+ const size_t nparams = f->parameterList.length();
+ if ((f->linkage == LINKc || f->linkage == LINKcpp) &&
+
+ ((f->parameterList.varargs == VARARGvariadic &&
+ nparams >= 1 &&
+ isPointerToChar(f->parameterList[nparams - 1])) ||
+ (f->parameterList.varargs == VARARGnone &&
+ nparams >= 2 &&
+ isPointerToChar(f->parameterList[nparams - 2]) &&
+ isVa_list(f->parameterList[nparams - 1], funcdecl, sc))
+ )
+ )
+ {
+ funcdecl->flags |= (pors == SCOPEprintf) ? FUNCFLAGprintf : FUNCFLAGscanf;
+ }
+ else
+ {
+ const char *p = (pors == SCOPEprintf ? Id::printf : Id::scanf)->toChars();
+ if (f->parameterList.varargs == VARARGvariadic)
+ {
+ funcdecl->error("`pragma(%s)` functions must be `extern(C) %s %s([parameters...], const(char)*, ...)`"
+ " not `%s`",
+ p, f->next->toChars(), funcdecl->toChars(), funcdecl->type->toChars());
+ }
+ else
+ {
+ funcdecl->error("`pragma(%s)` functions must be `extern(C) %s %s([parameters...], const(char)*, va_list)`",
+ p, f->next->toChars(), funcdecl->toChars());
+ }
+ }
+ }
+
id = parent->isInterfaceDeclaration();
if (id)
{
@@ -3831,7 +3883,7 @@ public:
sd->_scope = scx ? scx : sc->copy();
sd->_scope->setNoFree();
- sd->_scope->_module->addDeferredSemantic(sd);
+ Module::addDeferredSemantic(sd);
//printf("\tdeferring %s\n", sd->toChars());
return;
@@ -4079,7 +4131,7 @@ public:
{
//printf("\ttry later, forward reference of base class %s\n", tc->sym->toChars());
if (tc->sym->_scope)
- tc->sym->_scope->_module->addDeferredSemantic(tc->sym);
+ Module::addDeferredSemantic(tc->sym);
cldec->baseok = BASEOKnone;
}
L7: ;
@@ -4131,7 +4183,7 @@ public:
{
//printf("\ttry later, forward reference of base %s\n", tc->sym->toChars());
if (tc->sym->_scope)
- tc->sym->_scope->_module->addDeferredSemantic(tc->sym);
+ Module::addDeferredSemantic(tc->sym);
cldec->baseok = BASEOKnone;
}
i++;
@@ -4141,7 +4193,7 @@ public:
// Forward referencee of one or more bases, try again later
cldec->_scope = scx ? scx : sc->copy();
cldec->_scope->setNoFree();
- cldec->_scope->_module->addDeferredSemantic(cldec);
+ Module::addDeferredSemantic(cldec);
//printf("\tL%d semantic('%s') failed due to forward references\n", __LINE__, cldec->toChars());
return;
}
@@ -4254,8 +4306,8 @@ public:
cldec->_scope = scx ? scx : sc->copy();
cldec->_scope->setNoFree();
if (tc->sym->_scope)
- tc->sym->_scope->_module->addDeferredSemantic(tc->sym);
- cldec->_scope->_module->addDeferredSemantic(cldec);
+ Module::addDeferredSemantic(tc->sym);
+ Module::addDeferredSemantic(cldec);
//printf("\tL%d semantic('%s') failed due to forward references\n", __LINE__, cldec->toChars());
return;
}
@@ -4359,7 +4411,7 @@ public:
cldec->_scope = scx ? scx : sc->copy();
cldec->_scope->setNoFree();
- cldec->_scope->_module->addDeferredSemantic(cldec);
+ Module::addDeferredSemantic(cldec);
//printf("\tdeferring %s\n", cldec->toChars());
return;
}
@@ -4628,7 +4680,7 @@ public:
{
//printf("\ttry later, forward reference of base %s\n", tc->sym->toChars());
if (tc->sym->_scope)
- tc->sym->_scope->_module->addDeferredSemantic(tc->sym);
+ Module::addDeferredSemantic(tc->sym);
idec->baseok = BASEOKnone;
}
i++;
@@ -4638,7 +4690,7 @@ public:
// Forward referencee of one or more bases, try again later
idec->_scope = scx ? scx : sc->copy();
idec->_scope->setNoFree();
- idec->_scope->_module->addDeferredSemantic(idec);
+ Module::addDeferredSemantic(idec);
return;
}
idec->baseok = BASEOKdone;
@@ -4682,8 +4734,8 @@ public:
idec->_scope = scx ? scx : sc->copy();
idec->_scope->setNoFree();
if (tc->sym->_scope)
- tc->sym->_scope->_module->addDeferredSemantic(tc->sym);
- idec->_scope->_module->addDeferredSemantic(idec);
+ Module::addDeferredSemantic(tc->sym);
+ Module::addDeferredSemantic(idec);
return;
}
}
@@ -5335,6 +5387,7 @@ void aliasSemantic(AliasDeclaration *ds, Scope *sc)
ds->userAttribDecl = sc->userAttribDecl;
// TypeTraits needs to know if it's located in an AliasDeclaration
+ const unsigned oldflags = sc->flags;
sc->flags |= SCOPEalias;
if (ds->aliassym)
@@ -5345,7 +5398,7 @@ void aliasSemantic(AliasDeclaration *ds, Scope *sc)
{
if (fd && fd->semanticRun >= PASSsemanticdone)
{
- sc->flags &= ~SCOPEalias;
+ sc->flags = oldflags;
return;
}
@@ -5361,13 +5414,13 @@ void aliasSemantic(AliasDeclaration *ds, Scope *sc)
ds->aliassym = NULL;
ds->type = Type::terror;
}
- sc->flags &= ~SCOPEalias;
+ sc->flags = oldflags;
return;
}
if (ds->aliassym->isTemplateInstance())
dsymbolSemantic(ds->aliassym, sc);
- sc->flags &= ~SCOPEalias;
+ sc->flags = oldflags;
return;
}
ds->inuse = 1;
@@ -5472,7 +5525,7 @@ void aliasSemantic(AliasDeclaration *ds, Scope *sc)
if (!ds->overloadInsert(sx))
ScopeDsymbol::multiplyDefined(Loc(), sx, ds);
}
- sc->flags &= ~SCOPEalias;
+ sc->flags = oldflags;
}
diff --git a/gcc/d/dmd/dtemplate.c b/gcc/d/dmd/dtemplate.c
index b868e9ad388..208b064aafb 100644
--- a/gcc/d/dmd/dtemplate.c
+++ b/gcc/d/dmd/dtemplate.c
@@ -156,17 +156,14 @@ Dsymbol *getDsymbol(RootObject *oarg)
if (ea)
{
// Try to convert Expression to symbol
- if (ea->op == TOKvar)
- sa = ((VarExp *)ea)->var;
- else if (ea->op == TOKfunction)
- {
- if (((FuncExp *)ea)->td)
- sa = ((FuncExp *)ea)->td;
- else
- sa = ((FuncExp *)ea)->fd;
- }
- else if (ea->op == TOKtemplate)
- sa = ((TemplateExp *)ea)->td;
+ if (VarExp *ve = ea->isVarExp())
+ sa = ve->var;
+ else if (FuncExp *fe = ea->isFuncExp())
+ sa = fe->td ? (Dsymbol *)fe->td : (Dsymbol *)fe->fd;
+ else if (TemplateExp *te = ea->isTemplateExp())
+ sa = te->td;
+ else if (ScopeExp *se = ea->isScopeExp())
+ sa = se->sds;
else
sa = NULL;
}
@@ -536,6 +533,7 @@ TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id,
this->isstatic = true;
this->previous = NULL;
this->protection = Prot(Prot::undefined);
+ this->inuse = 0;
this->instances = NULL;
// Compute in advance for Ddoc's use
@@ -770,7 +768,9 @@ MATCH TemplateDeclaration::matchWithInstance(Scope *sc, TemplateInstance *ti,
Declaration *sparam;
//printf("\targument [%d]\n", i);
+ inuse++;
m2 = tp->matchArg(ti->loc, paramscope, ti->tiargs, i, parameters, dedtypes, &sparam);
+ inuse--;
//printf("\tm2 = %d\n", m2);
if (m2 == MATCHnomatch)
@@ -1397,7 +1397,9 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(
}
else
{
+ inuse++;
oded = tparam->defaultArg(instLoc, paramscope);
+ inuse--;
if (oded)
(*dedargs)[i] = declareParameter(paramscope, tparam, oded);
}
@@ -1771,7 +1773,9 @@ Lmatch:
}
else
{
+ inuse++;
oded = tparam->defaultArg(instLoc, paramscope);
+ inuse--;
if (!oded)
{
// if tuple parameter and
@@ -1997,18 +2001,19 @@ bool TemplateDeclaration::isOverloadable()
/*************************************************
* Given function arguments, figure out which template function
* to expand, and return matching result.
- * Input:
- * m matching result
- * dstart the root of overloaded function templates
- * loc instantiation location
- * sc instantiation scope
- * tiargs initial list of template arguments
- * tthis if !NULL, the 'this' pointer argument
- * fargs arguments to function
+ * Params:
+ * m = matching result
+ * dstart = the root of overloaded function templates
+ * loc = instantiation location
+ * sc = instantiation scope
+ * tiargs = initial list of template arguments
+ * tthis = if !NULL, the 'this' pointer argument
+ * fargs = arguments to function
+ * pMessage = address to store error message, or null
*/
void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc,
- Objects *tiargs, Type *tthis, Expressions *fargs)
+ Objects *tiargs, Type *tthis, Expressions *fargs, const char **pMessage)
{
struct ParamDeduce
{
@@ -2018,6 +2023,7 @@ void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc,
Type *tthis;
Objects *tiargs;
Expressions *fargs;
+ const char **pMessage;
// result
Match *m;
int property; // 0: unintialized
@@ -2093,7 +2099,7 @@ void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc,
else
return 0; // MATCHnomatch
}
- MATCH mfa = tf->callMatch(tthis_fd, fargs);
+ MATCH mfa = tf->callMatch(tthis_fd, fargs, 0, pMessage);
//printf("test1: mfa = %d\n", mfa);
if (mfa > MATCHnomatch)
{
@@ -2180,8 +2186,12 @@ void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc,
int applyTemplate(TemplateDeclaration *td)
{
//printf("applyTemplate()\n");
- // skip duplicates
- if (td == td_best)
+ if (td->inuse)
+ {
+ td->error(loc, "recursive template expansion");
+ return 1;
+ }
+ if (td == td_best) // skip duplicates
return 0;
if (!sc)
@@ -2431,6 +2441,7 @@ void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc,
p.tthis = tthis;
p.tiargs = tiargs;
p.fargs = fargs;
+ p.pMessage = pMessage;
// result
p.m = m;
@@ -5165,6 +5176,16 @@ MATCH TemplateAliasParameter::matchArg(Scope *sc, RootObject *oarg,
* template X(T) {} // T => sa
*/
}
+ else if (ta && ta->ty != Tident)
+ {
+ /* Match any type that's not a TypeIdentifier to alias parameters,
+ * but prefer type parameter.
+ * template X(alias a) { } // a == ta
+ *
+ * TypeIdentifiers are excluded because they might be not yet resolved aliases.
+ */
+ m = MATCHconvert;
+ }
else
goto Lnomatch;
}
@@ -5485,12 +5506,15 @@ RootObject *TemplateValueParameter::defaultArg(Loc instLoc, Scope *sc)
if (e)
{
e = e->syntaxCopy();
+ unsigned olderrs = global.errors;
if ((e = expressionSemantic(e, sc)) == NULL)
return NULL;
if ((e = resolveProperties(sc, e)) == NULL)
return NULL;
e = e->resolveLoc(instLoc, sc); // use the instantiated loc
e = e->optimize(WANTvalue);
+ if (global.errors != olderrs)
+ e = new ErrorExp();
}
return e;
}
@@ -6049,6 +6073,7 @@ bool TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f
if (ta)
{
//printf("type %s\n", ta->toChars());
+
// It might really be an Expression or an Alias
ta->resolve(loc, sc, &ea, &ta, &sa, (flags & 1) != 0);
if (ea) goto Lexpr;
@@ -6270,6 +6295,7 @@ bool TemplateInstance::findBestMatch(Scope *sc, Expressions *fargs)
}
unsigned errs = global.errors;
+ TemplateDeclaration *td_last = NULL;
struct ParamBest
{
@@ -6291,7 +6317,11 @@ bool TemplateInstance::findBestMatch(Scope *sc, Expressions *fargs)
TemplateDeclaration *td = s->isTemplateDeclaration();
if (!td)
return 0;
-
+ if (td->inuse)
+ {
+ td->error(ti->loc, "recursive template expansion");
+ return 1;
+ }
if (td == td_best) // skip duplicates
return 0;
@@ -6349,8 +6379,6 @@ bool TemplateInstance::findBestMatch(Scope *sc, Expressions *fargs)
/* Since there can be multiple TemplateDeclaration's with the same
* name, look for the best match.
*/
- TemplateDeclaration *td_last = NULL;
-
OverloadSet *tovers = tempdecl->isOverloadSet();
size_t overs_dim = tovers ? tovers->a.length : 1;
for (size_t oi = 0; oi < overs_dim; oi++)
@@ -6359,7 +6387,9 @@ bool TemplateInstance::findBestMatch(Scope *sc, Expressions *fargs)
p.td_best = NULL;
p.td_ambig = NULL;
p.m_best = MATCHnomatch;
- overloadApply(tovers ? tovers->a[oi] : tempdecl, &p, &ParamBest::fp);
+
+ Dsymbol *dstart = tovers ? tovers->a[oi] : tempdecl;
+ overloadApply(dstart, &p, &ParamBest::fp);
if (p.td_ambig)
{
@@ -6481,8 +6511,11 @@ bool TemplateInstance::needsTypeInference(Scope *sc, int flag)
{
TemplateDeclaration *td = s->isTemplateDeclaration();
if (!td)
- {
return 0;
+ if (td->inuse)
+ {
+ td->error(ti->loc, "recursive template expansion");
+ return 1;
}
/* If any of the overloaded template declarations need inference,
@@ -7128,6 +7161,68 @@ void unSpeculative(Scope *sc, RootObject *o)
unSpeculative(sc, ti);
}
+/**
+ Returns: true if the instances' innards are discardable.
+
+ The idea of this function is to see if the template instantiation
+ can be 100% replaced with its eponymous member. All other members
+ can be discarded, even in the compiler to free memory (for example,
+ the template could be expanded in a region allocator, deemed trivial,
+ the end result copied back out independently and the entire region freed),
+ and can be elided entirely from the binary.
+
+ The current implementation affects code that generally looks like:
+
+ ---
+ template foo(args...) {
+ some_basic_type_or_string helper() { .... }
+ enum foo = helper();
+ }
+ ---
+
+ since it was the easiest starting point of implementation but it can and
+ should be expanded more later.
+*/
+static bool isDiscardable(TemplateInstance *ti)
+{
+ if (ti->aliasdecl == NULL)
+ return false;
+
+ VarDeclaration *v = ti->aliasdecl->isVarDeclaration();
+ if (v == NULL)
+ return false;
+
+ if (!(v->storage_class & STCmanifest))
+ return false;
+
+ // Currently only doing basic types here because it is the easiest proof-of-concept
+ // implementation with minimal risk of side effects, but it could likely be
+ // expanded to any type that already exists outside this particular instance.
+ if (!(v->type->equals(Type::tstring) || (v->type->isTypeBasic() != NULL)))
+ return false;
+
+ // Static ctors and dtors, even in an eponymous enum template, are still run,
+ // so if any of them are in here, we'd better not assume it is trivial lest
+ // we break useful code
+ for (size_t i = 0; i < ti->members->length; i++)
+ {
+ Dsymbol *member = (*ti->members)[i];
+ if (member->hasStaticCtorOrDtor())
+ return false;
+ if (member->isStaticDtorDeclaration())
+ return false;
+ if (member->isStaticCtorDeclaration())
+ return false;
+ }
+
+ // but if it passes through this gauntlet... it should be fine. D code will
+ // see only the eponymous member, outside stuff can never access it, even through
+ // reflection; the outside world ought to be none the wiser. Even dmd should be
+ // able to simply free the memory of everything except the final result.
+
+ return true;
+}
+
/***********************************************
* Returns true if this is not instantiated in non-root module, and
* is a part of non-speculative instantiatiation.
@@ -7137,38 +7232,6 @@ void unSpeculative(Scope *sc, RootObject *o)
*/
bool TemplateInstance::needsCodegen()
{
- // Now -allInst is just for the backward compatibility.
- if (global.params.allInst)
- {
- //printf("%s minst = %s, enclosing (%s)->isNonRoot = %d\n",
- // toPrettyChars(), minst ? minst->toChars() : NULL,
- // enclosing ? enclosing->toPrettyChars() : NULL, enclosing && enclosing->inNonRoot());
- if (enclosing)
- {
- // Bugzilla 14588: If the captured context is not a function
- // (e.g. class), the instance layout determination is guaranteed,
- // because the semantic/semantic2 pass will be executed
- // even for non-root instances.
- if (!enclosing->isFuncDeclaration())
- return true;
-
- // Bugzilla 14834: If the captured context is a function,
- // this excessive instantiation may cause ODR violation, because
- // -allInst and others doesn't guarantee the semantic3 execution
- // for that function.
-
- // If the enclosing is also an instantiated function,
- // we have to rely on the ancestor's needsCodegen() result.
- if (TemplateInstance *ti = enclosing->isInstantiated())
- return ti->needsCodegen();
-
- // Bugzilla 13415: If and only if the enclosing scope needs codegen,
- // this nested templates would also need code generation.
- return !enclosing->inNonRoot();
- }
- return true;
- }
-
if (!minst)
{
// If this is a speculative instantiation,
@@ -7185,6 +7248,10 @@ bool TemplateInstance::needsCodegen()
if (tinst && tinst->needsCodegen())
{
minst = tinst->minst; // cache result
+ if (global.params.allInst && minst)
+ {
+ return true;
+ }
assert(minst);
assert(minst->isRoot() || minst->rootImports());
return true;
@@ -7192,6 +7259,10 @@ bool TemplateInstance::needsCodegen()
if (tnext && (tnext->needsCodegen() || tnext->minst))
{
minst = tnext->minst; // cache result
+ if (global.params.allInst && minst)
+ {
+ return true;
+ }
assert(minst);
return minst->isRoot() || minst->rootImports();
}
@@ -7200,6 +7271,16 @@ bool TemplateInstance::needsCodegen()
return false;
}
+ if (global.params.allInst)
+ {
+ return true;
+ }
+
+ if (isDiscardable(this))
+ {
+ return false;
+ }
+
/* Even when this is reached to the codegen pass,
* a non-root nested template should not generate code,
* due to avoid ODR violation.
@@ -7221,14 +7302,7 @@ bool TemplateInstance::needsCodegen()
return false;
}
- /* The issue is that if the importee is compiled with a different -debug
- * setting than the importer, the importer may believe it exists
- * in the compiled importee when it does not, when the instantiation
- * is behind a conditional debug declaration.
- */
- // workaround for Bugzilla 11239
- if (global.params.useUnitTests ||
- global.params.debuglevel)
+ if (global.params.useUnitTests)
{
// Prefer instantiations from root modules, to maximize link-ability.
if (minst->isRoot())
diff --git a/gcc/d/dmd/expression.c b/gcc/d/dmd/expression.c
index c90392d16a2..2592b38d961 100644
--- a/gcc/d/dmd/expression.c
+++ b/gcc/d/dmd/expression.c
@@ -43,110 +43,10 @@ VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e);
Expression *extractSideEffect(Scope *sc, const char *name, Expression **e0, Expression *e, bool alwaysCopy = false);
char *MODtoChars(MOD mod);
bool MODimplicitConv(MOD modfrom, MOD modto);
-MOD MODmerge(MOD mod1, MOD mod2);
void MODMatchToBuffer(OutBuffer *buf, unsigned char lhsMod, unsigned char rhsMod);
Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
bool checkUnsafeAccess(Scope *sc, Expression *e, bool readonly, bool printmsg);
-
-/*************************************************************
- * Given var, we need to get the
- * right 'this' pointer if var is in an outer class, but our
- * existing 'this' pointer is in an inner class.
- * Input:
- * e1 existing 'this'
- * ad struct or class we need the correct 'this' for
- * var the specific member of ad we're accessing
- */
-
-Expression *getRightThis(Loc loc, Scope *sc, AggregateDeclaration *ad,
- Expression *e1, Declaration *var, int flag = 0)
-{
- //printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1->toChars(), ad->toChars(), var->toChars());
- L1:
- Type *t = e1->type->toBasetype();
- //printf("e1->type = %s, var->type = %s\n", e1->type->toChars(), var->type->toChars());
-
- /* If e1 is not the 'this' pointer for ad
- */
- if (ad &&
- !(t->ty == Tpointer && t->nextOf()->ty == Tstruct &&
- ((TypeStruct *)t->nextOf())->sym == ad)
- &&
- !(t->ty == Tstruct &&
- ((TypeStruct *)t)->sym == ad)
- )
- {
- ClassDeclaration *cd = ad->isClassDeclaration();
- ClassDeclaration *tcd = t->isClassHandle();
-
- /* e1 is the right this if ad is a base class of e1
- */
- if (!cd || !tcd ||
- !(tcd == cd || cd->isBaseOf(tcd, NULL))
- )
- {
- /* Only classes can be inner classes with an 'outer'
- * member pointing to the enclosing class instance
- */
- if (tcd && tcd->isNested())
- {
- /* e1 is the 'this' pointer for an inner class: tcd.
- * Rewrite it as the 'this' pointer for the outer class.
- */
-
- e1 = new DotVarExp(loc, e1, tcd->vthis);
- e1->type = tcd->vthis->type;
- e1->type = e1->type->addMod(t->mod);
- // Do not call checkNestedRef()
- //e1 = expressionSemantic(e1, sc);
-
- // Skip up over nested functions, and get the enclosing
- // class type.
- int n = 0;
- Dsymbol *s;
- for (s = tcd->toParent();
- s && s->isFuncDeclaration();
- s = s->toParent())
- {
- FuncDeclaration *f = s->isFuncDeclaration();
- if (f->vthis)
- {
- //printf("rewriting e1 to %s's this\n", f->toChars());
- n++;
- e1 = new VarExp(loc, f->vthis);
- }
- else
- {
- e1->error("need `this` of type %s to access member %s"
- " from static function %s",
- ad->toChars(), var->toChars(), f->toChars());
- e1 = new ErrorExp();
- return e1;
- }
- }
- if (s && s->isClassDeclaration())
- {
- e1->type = s->isClassDeclaration()->type;
- e1->type = e1->type->addMod(t->mod);
- if (n > 1)
- e1 = expressionSemantic(e1, sc);
- }
- else
- e1 = expressionSemantic(e1, sc);
- goto L1;
- }
-
- /* Can't find a path from e1 to ad
- */
- if (flag)
- return NULL;
- e1->error("this for %s needs to be type %s not type %s",
- var->toChars(), ad->toChars(), t->toChars());
- return new ErrorExp();
- }
- }
- return e1;
-}
+void toAutoQualChars(const char **result, Type *t1, Type *t2);
/*****************************************
* Determine if 'this' is available.
@@ -230,497 +130,6 @@ bool isNeedThisScope(Scope *sc, Declaration *d)
return true;
}
-/***************************************
- * Pull out any properties.
- */
-
-Expression *resolvePropertiesX(Scope *sc, Expression *e1, Expression *e2 = NULL)
-{
- //printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", Token::toChars(e1->op), e1->toChars(), e2 ? e2->toChars() : NULL);
- Loc loc = e1->loc;
-
- OverloadSet *os;
- Dsymbol *s;
- Objects *tiargs;
- Type *tthis;
- if (e1->op == TOKdot)
- {
- DotExp *de = (DotExp *)e1;
- if (de->e2->op == TOKoverloadset)
- {
- tiargs = NULL;
- tthis = de->e1->type;
- os = ((OverExp *)de->e2)->vars;
- goto Los;
- }
- }
- else if (e1->op == TOKoverloadset)
- {
- tiargs = NULL;
- tthis = NULL;
- os = ((OverExp *)e1)->vars;
- Los:
- assert(os);
- FuncDeclaration *fd = NULL;
- if (e2)
- {
- e2 = expressionSemantic(e2, sc);
- if (e2->op == TOKerror)
- return new ErrorExp();
- e2 = resolveProperties(sc, e2);
-
- Expressions a;
- a.push(e2);
-
- for (size_t i = 0; i < os->a.length; i++)
- {
- FuncDeclaration *f = resolveFuncCall(loc, sc, os->a[i], tiargs, tthis, &a, 1);
- if (f)
- {
- if (f->errors)
- return new ErrorExp();
- fd = f;
- assert(fd->type->ty == Tfunction);
- }
- }
- if (fd)
- {
- Expression *e = new CallExp(loc, e1, e2);
- return expressionSemantic(e, sc);
- }
- }
- {
- for (size_t i = 0; i < os->a.length; i++)
- {
- FuncDeclaration *f = resolveFuncCall(loc, sc, os->a[i], tiargs, tthis, NULL, 1);
- if (f)
- {
- if (f->errors)
- return new ErrorExp();
- fd = f;
- assert(fd->type->ty == Tfunction);
- TypeFunction *tf = (TypeFunction *)fd->type;
- if (!tf->isref && e2)
- goto Leproplvalue;
- }
- }
- if (fd)
- {
- Expression *e = new CallExp(loc, e1);
- if (e2)
- e = new AssignExp(loc, e, e2);
- return expressionSemantic(e, sc);
- }
- }
- if (e2)
- goto Leprop;
- }
- else if (e1->op == TOKdotti)
- {
- DotTemplateInstanceExp* dti = (DotTemplateInstanceExp *)e1;
- if (!dti->findTempDecl(sc))
- goto Leprop;
- if (!dti->ti->semanticTiargs(sc))
- goto Leprop;
- tiargs = dti->ti->tiargs;
- tthis = dti->e1->type;
- if ((os = dti->ti->tempdecl->isOverloadSet()) != NULL)
- goto Los;
- if ((s = dti->ti->tempdecl) != NULL)
- goto Lfd;
- }
- else if (e1->op == TOKdottd)
- {
- DotTemplateExp *dte = (DotTemplateExp *)e1;
- s = dte->td;
- tiargs = NULL;
- tthis = dte->e1->type;
- goto Lfd;
- }
- else if (e1->op == TOKscope)
- {
- s = ((ScopeExp *)e1)->sds;
- TemplateInstance *ti = s->isTemplateInstance();
- if (ti && !ti->semanticRun && ti->tempdecl)
- {
- //assert(ti->needsTypeInference(sc));
- if (!ti->semanticTiargs(sc))
- goto Leprop;
- tiargs = ti->tiargs;
- tthis = NULL;
- if ((os = ti->tempdecl->isOverloadSet()) != NULL)
- goto Los;
- if ((s = ti->tempdecl) != NULL)
- goto Lfd;
- }
- }
- else if (e1->op == TOKtemplate)
- {
- s = ((TemplateExp *)e1)->td;
- tiargs = NULL;
- tthis = NULL;
- goto Lfd;
- }
- else if (e1->op == TOKdotvar && e1->type && e1->type->toBasetype()->ty == Tfunction)
- {
- DotVarExp *dve = (DotVarExp *)e1;
- s = dve->var->isFuncDeclaration();
- tiargs = NULL;
- tthis = dve->e1->type;
- goto Lfd;
- }
- else if (e1->op == TOKvar && e1->type && e1->type->toBasetype()->ty == Tfunction)
- {
- s = ((VarExp *)e1)->var->isFuncDeclaration();
- tiargs = NULL;
- tthis = NULL;
- Lfd:
- assert(s);
- if (e2)
- {
- e2 = expressionSemantic(e2, sc);
- if (e2->op == TOKerror)
- return new ErrorExp();
- e2 = resolveProperties(sc, e2);
-
- Expressions a;
- a.push(e2);
-
- FuncDeclaration *fd = resolveFuncCall(loc, sc, s, tiargs, tthis, &a, 1);
- if (fd && fd->type)
- {
- if (fd->errors)
- return new ErrorExp();
- assert(fd->type->ty == Tfunction);
- Expression *e = new CallExp(loc, e1, e2);
- return expressionSemantic(e, sc);
- }
- }
- {
- FuncDeclaration *fd = resolveFuncCall(loc, sc, s, tiargs, tthis, NULL, 1);
- if (fd && fd->type)
- {
- if (fd->errors)
- return new ErrorExp();
- assert(fd->type->ty == Tfunction);
- TypeFunction *tf = (TypeFunction *)fd->type;
- if (!e2 || tf->isref)
- {
- Expression *e = new CallExp(loc, e1);
- if (e2)
- e = new AssignExp(loc, e, e2);
- return expressionSemantic(e, sc);
- }
- }
- }
- if (FuncDeclaration *fd = s->isFuncDeclaration())
- {
- // Keep better diagnostic message for invalid property usage of functions
- assert(fd->type->ty == Tfunction);
- Expression *e = new CallExp(loc, e1, e2);
- return expressionSemantic(e, sc);
- }
- if (e2)
- goto Leprop;
- }
- if (e1->op == TOKvar)
- {
- VarExp *ve = (VarExp *)e1;
- VarDeclaration *v = ve->var->isVarDeclaration();
- if (v && ve->checkPurity(sc, v))
- return new ErrorExp();
- }
- if (e2)
- return NULL;
-
- if (e1->type &&
- e1->op != TOKtype) // function type is not a property
- {
- /* Look for e1 being a lazy parameter; rewrite as delegate call
- */
- if (e1->op == TOKvar)
- {
- VarExp *ve = (VarExp *)e1;
-
- if (ve->var->storage_class & STClazy)
- {
- Expression *e = new CallExp(loc, e1);
- return expressionSemantic(e, sc);
- }
- }
- else if (e1->op == TOKdotvar)
- {
- // Check for reading overlapped pointer field in @safe code.
- if (checkUnsafeAccess(sc, e1, true, true))
- return new ErrorExp();
- }
- else if (e1->op == TOKdot)
- {
- e1->error("expression has no value");
- return new ErrorExp();
- }
- else if (e1->op == TOKcall)
- {
- CallExp *ce = (CallExp *)e1;
- // Check for reading overlapped pointer field in @safe code.
- if (checkUnsafeAccess(sc, ce->e1, true, true))
- return new ErrorExp();
- }
- }
-
- if (!e1->type)
- {
- error(loc, "cannot resolve type for %s", e1->toChars());
- e1 = new ErrorExp();
- }
- return e1;
-
-Leprop:
- error(loc, "not a property %s", e1->toChars());
- return new ErrorExp();
-
-Leproplvalue:
- error(loc, "%s is not an lvalue", e1->toChars());
- return new ErrorExp();
-}
-
-Expression *resolveProperties(Scope *sc, Expression *e)
-{
- //printf("resolveProperties(%s)\n", e->toChars());
-
- e = resolvePropertiesX(sc, e);
- if (e->checkRightThis(sc))
- return new ErrorExp();
- return e;
-}
-
-/******************************
- * Check the tail CallExp is really property function call.
- */
-static bool checkPropertyCall(Expression *e)
-{
- while (e->op == TOKcomma)
- e = ((CommaExp *)e)->e2;
-
- if (e->op == TOKcall)
- {
- CallExp *ce = (CallExp *)e;
- TypeFunction *tf;
- if (ce->f)
- {
- tf = (TypeFunction *)ce->f->type;
- /* If a forward reference to ce->f, try to resolve it
- */
- if (!tf->deco && ce->f->semanticRun < PASSsemanticdone)
- {
- dsymbolSemantic(ce->f, NULL);
- tf = (TypeFunction *)ce->f->type;
- }
- }
- else if (ce->e1->type->ty == Tfunction)
- tf = (TypeFunction *)ce->e1->type;
- else if (ce->e1->type->ty == Tdelegate)
- tf = (TypeFunction *)ce->e1->type->nextOf();
- else if (ce->e1->type->ty == Tpointer && ce->e1->type->nextOf()->ty == Tfunction)
- tf = (TypeFunction *)ce->e1->type->nextOf();
- else
- assert(0);
- }
- return false;
-}
-
-/******************************
- * If e1 is a property function (template), resolve it.
- */
-
-Expression *resolvePropertiesOnly(Scope *sc, Expression *e1)
-{
- //printf("e1 = %s %s\n", Token::toChars(e1->op), e1->toChars());
- OverloadSet *os;
- FuncDeclaration *fd;
- TemplateDeclaration *td;
-
- if (e1->op == TOKdot)
- {
- DotExp *de = (DotExp *)e1;
- if (de->e2->op == TOKoverloadset)
- {
- os = ((OverExp *)de->e2)->vars;
- goto Los;
- }
- }
- else if (e1->op == TOKoverloadset)
- {
- os = ((OverExp *)e1)->vars;
- Los:
- assert(os);
- for (size_t i = 0; i < os->a.length; i++)
- {
- Dsymbol *s = os->a[i];
- fd = s->isFuncDeclaration();
- td = s->isTemplateDeclaration();
- if (fd)
- {
- if (((TypeFunction *)fd->type)->isproperty)
- return resolveProperties(sc, e1);
- }
- else if (td && td->onemember &&
- (fd = td->onemember->isFuncDeclaration()) != NULL)
- {
- if (((TypeFunction *)fd->type)->isproperty ||
- (fd->storage_class2 & STCproperty) ||
- (td->_scope->stc & STCproperty))
- {
- return resolveProperties(sc, e1);
- }
- }
- }
- }
- else if (e1->op == TOKdotti)
- {
- DotTemplateInstanceExp* dti = (DotTemplateInstanceExp *)e1;
- if (dti->ti->tempdecl && (td = dti->ti->tempdecl->isTemplateDeclaration()) != NULL)
- goto Ltd;
- }
- else if (e1->op == TOKdottd)
- {
- td = ((DotTemplateExp *)e1)->td;
- goto Ltd;
- }
- else if (e1->op == TOKscope)
- {
- Dsymbol *s = ((ScopeExp *)e1)->sds;
- TemplateInstance *ti = s->isTemplateInstance();
- if (ti && !ti->semanticRun && ti->tempdecl)
- {
- if ((td = ti->tempdecl->isTemplateDeclaration()) != NULL)
- goto Ltd;
- }
- }
- else if (e1->op == TOKtemplate)
- {
- td = ((TemplateExp *)e1)->td;
- Ltd:
- assert(td);
- if (td->onemember &&
- (fd = td->onemember->isFuncDeclaration()) != NULL)
- {
- if (((TypeFunction *)fd->type)->isproperty ||
- (fd->storage_class2 & STCproperty) ||
- (td->_scope->stc & STCproperty))
- {
- return resolveProperties(sc, e1);
- }
- }
- }
- else if (e1->op == TOKdotvar && e1->type->ty == Tfunction)
- {
- DotVarExp *dve = (DotVarExp *)e1;
- fd = dve->var->isFuncDeclaration();
- goto Lfd;
- }
- else if (e1->op == TOKvar && e1->type->ty == Tfunction &&
- (sc->intypeof || !((VarExp *)e1)->var->needThis()))
- {
- fd = ((VarExp *)e1)->var->isFuncDeclaration();
- Lfd:
- assert(fd);
- if (((TypeFunction *)fd->type)->isproperty)
- return resolveProperties(sc, e1);
- }
- return e1;
-}
-
-
-// TODO: merge with Scope::search::searchScopes()
-static Dsymbol *searchScopes(Scope *sc, Loc loc, Identifier *ident, int flags)
-{
- Dsymbol *s = NULL;
- for (Scope *scx = sc; scx; scx = scx->enclosing)
- {
- if (!scx->scopesym)
- continue;
- if (scx->scopesym->isModule())
- flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed
- s = scx->scopesym->search(loc, ident, flags);
- if (s)
- {
- // overload set contains only module scope symbols.
- if (s->isOverloadSet())
- break;
- // selective/renamed imports also be picked up
- if (AliasDeclaration *ad = s->isAliasDeclaration())
- {
- if (ad->_import)
- break;
- }
- // See only module scope symbols for UFCS target.
- Dsymbol *p = s->toParent2();
- if (p && p->isModule())
- break;
- }
- s = NULL;
-
- // Stop when we hit a module, but keep going if that is not just under the global scope
- if (scx->scopesym->isModule() && !(scx->enclosing && !scx->enclosing->enclosing))
- break;
- }
- return s;
-}
-
-/******************************
- * Find symbol in accordance with the UFCS name look up rule
- */
-
-static Expression *searchUFCS(Scope *sc, UnaExp *ue, Identifier *ident)
-{
- //printf("searchUFCS(ident = %s)\n", ident->toChars());
- Loc loc = ue->loc;
- int flags = 0;
- Dsymbol *s = NULL;
-
- if (sc->flags & SCOPEignoresymbolvisibility)
- flags |= IgnoreSymbolVisibility;
-
- // First look in local scopes
- s = searchScopes(sc, loc, ident, flags | SearchLocalsOnly);
- if (!s)
- {
- // Second look in imported modules
- s = searchScopes(sc, loc, ident, flags | SearchImportsOnly);
- }
-
- if (!s)
- return ue->e1->type->Type::getProperty(loc, ident, 0);
-
- FuncDeclaration *f = s->isFuncDeclaration();
- if (f)
- {
- TemplateDeclaration *td = getFuncTemplateDecl(f);
- if (td)
- {
- if (td->overroot)
- td = td->overroot;
- s = td;
- }
- }
-
- if (ue->op == TOKdotti)
- {
- DotTemplateInstanceExp *dti = (DotTemplateInstanceExp *)ue;
- TemplateInstance *ti = new TemplateInstance(loc, s->ident);
- ti->tiargs = dti->ti->tiargs; // for better diagnostic message
- if (!ti->updateTempDecl(sc, s))
- return new ErrorExp();
- return new ScopeExp(loc, ti);
- }
- else
- {
- //printf("-searchUFCS() %s\n", s->toChars());
- return new DsymbolExp(loc, s);
- }
-}
-
/******************************
* check e is exp.opDispatch!(tiargs) or not
* It's used to switch to UFCS the semantic analysis path
@@ -732,220 +141,6 @@ bool isDotOpDispatch(Expression *e)
((DotTemplateInstanceExp *)e)->ti->name == Id::opDispatch;
}
-/******************************
- * Pull out callable entity with UFCS.
- */
-
-Expression *resolveUFCS(Scope *sc, CallExp *ce)
-{
- Loc loc = ce->loc;
- Expression *eleft;
- Expression *e;
-
- if (ce->e1->op == TOKdotid)
- {
- DotIdExp *die = (DotIdExp *)ce->e1;
- Identifier *ident = die->ident;
-
- Expression *ex = semanticX(die, sc);
- if (ex != die)
- {
- ce->e1 = ex;
- return NULL;
- }
- eleft = die->e1;
-
- Type *t = eleft->type->toBasetype();
- if (t->ty == Tarray || t->ty == Tsarray ||
- t->ty == Tnull || (t->isTypeBasic() && t->ty != Tvoid))
- {
- /* Built-in types and arrays have no callable properties, so do shortcut.
- * It is necessary in: e.init()
- */
- }
- else if (t->ty == Taarray)
- {
- if (ident == Id::remove)
- {
- /* Transform:
- * aa.remove(arg) into delete aa[arg]
- */
- if (!ce->arguments || ce->arguments->length != 1)
- {
- ce->error("expected key as argument to aa.remove()");
- return new ErrorExp();
- }
- if (!eleft->type->isMutable())
- {
- ce->error("cannot remove key from %s associative array %s",
- MODtoChars(t->mod), eleft->toChars());
- return new ErrorExp();
- }
- Expression *key = (*ce->arguments)[0];
- key = expressionSemantic(key, sc);
- key = resolveProperties(sc, key);
-
- TypeAArray *taa = (TypeAArray *)t;
- key = key->implicitCastTo(sc, taa->index);
-
- if (key->checkValue())
- return new ErrorExp();
-
- semanticTypeInfo(sc, taa->index);
-
- return new RemoveExp(loc, eleft, key);
- }
- }
- else
- {
- if (Expression *ey = semanticY(die, sc, 1))
- {
- if (ey->op == TOKerror)
- return ey;
- ce->e1 = ey;
- if (isDotOpDispatch(ey))
- {
- unsigned errors = global.startGagging();
- e = expressionSemantic(ce->syntaxCopy(), sc);
- if (!global.endGagging(errors))
- return e;
- /* fall down to UFCS */
- }
- else
- return NULL;
- }
- }
- e = searchUFCS(sc, die, ident);
- }
- else if (ce->e1->op == TOKdotti)
- {
- DotTemplateInstanceExp *dti = (DotTemplateInstanceExp *)ce->e1;
- if (Expression *ey = semanticY(dti, sc, 1))
- {
- ce->e1 = ey;
- return NULL;
- }
- eleft = dti->e1;
- e = searchUFCS(sc, dti, dti->ti->name);
- }
- else
- return NULL;
-
- // Rewrite
- ce->e1 = e;
- if (!ce->arguments)
- ce->arguments = new Expressions();
- ce->arguments->shift(eleft);
-
- return NULL;
-}
-
-/******************************
- * Pull out property with UFCS.
- */
-
-Expression *resolveUFCSProperties(Scope *sc, Expression *e1, Expression *e2 = NULL)
-{
- Loc loc = e1->loc;
- Expression *eleft;
- Expression *e;
-
- if (e1->op == TOKdotid)
- {
- DotIdExp *die = (DotIdExp *)e1;
- eleft = die->e1;
- e = searchUFCS(sc, die, die->ident);
- }
- else if (e1->op == TOKdotti)
- {
- DotTemplateInstanceExp *dti;
- dti = (DotTemplateInstanceExp *)e1;
- eleft = dti->e1;
- e = searchUFCS(sc, dti, dti->ti->name);
- }
- else
- return NULL;
-
- if (e == NULL)
- return NULL;
-
- // Rewrite
- if (e2)
- {
- // run semantic without gagging
- e2 = expressionSemantic(e2, sc);
-
- /* f(e1) = e2
- */
- Expression *ex = e->copy();
- Expressions *a1 = new Expressions();
- a1->setDim(1);
- (*a1)[0] = eleft;
- ex = new CallExp(loc, ex, a1);
- ex = trySemantic(ex, sc);
-
- /* f(e1, e2)
- */
- Expressions *a2 = new Expressions();
- a2->setDim(2);
- (*a2)[0] = eleft;
- (*a2)[1] = e2;
- e = new CallExp(loc, e, a2);
- if (ex)
- { // if fallback setter exists, gag errors
- e = trySemantic(e, sc);
- if (!e)
- { checkPropertyCall(ex);
- ex = new AssignExp(loc, ex, e2);
- return expressionSemantic(ex, sc);
- }
- }
- else
- { // strict setter prints errors if fails
- e = expressionSemantic(e, sc);
- }
- checkPropertyCall(e);
- return e;
- }
- else
- {
- /* f(e1)
- */
- Expressions *arguments = new Expressions();
- arguments->setDim(1);
- (*arguments)[0] = eleft;
- e = new CallExp(loc, e, arguments);
- e = expressionSemantic(e, sc);
- checkPropertyCall(e);
- return expressionSemantic(e, sc);
- }
-}
-
-/******************************
- * Perform semantic() on an array of Expressions.
- */
-
-bool arrayExpressionSemantic(Expressions *exps, Scope *sc, bool preserveErrors)
-{
- bool err = false;
- if (exps)
- {
- for (size_t i = 0; i < exps->length; i++)
- {
- Expression *e = (*exps)[i];
- if (e)
- {
- e = expressionSemantic(e, sc);
- if (e->op == TOKerror)
- err = true;
- if (preserveErrors || e->op != TOKerror)
- (*exps)[i] = e;
- }
- }
- }
- return err;
-}
-
/****************************************
* Expand tuples.
* Input:
@@ -1065,120 +260,6 @@ int expandAliasThisTuples(Expressions *exps, size_t starti)
}
/****************************************
- * The common type is determined by applying ?: to each pair.
- * Output:
- * exps[] properties resolved, implicitly cast to common type, rewritten in place
- * *pt if pt is not NULL, set to the common type
- * Returns:
- * true a semantic error was detected
- */
-
-bool arrayExpressionToCommonType(Scope *sc, Expressions *exps, Type **pt)
-{
- /* Still have a problem with:
- * ubyte[][] = [ cast(ubyte[])"hello", [1]];
- * which works if the array literal is initialized top down with the ubyte[][]
- * type, but fails with this function doing bottom up typing.
- */
- //printf("arrayExpressionToCommonType()\n");
- IntegerExp integerexp(0);
- CondExp condexp(Loc(), &integerexp, NULL, NULL);
-
- Type *t0 = NULL;
- Expression *e0 = NULL; // dead-store to prevent spurious warning
- size_t j0 = ~0; // dead-store to prevent spurious warning
- bool foundType = false;
-
- for (size_t i = 0; i < exps->length; i++)
- {
- Expression *e = (*exps)[i];
- if (!e)
- continue;
-
- e = resolveProperties(sc, e);
- if (!e->type)
- {
- e->error("%s has no value", e->toChars());
- t0 = Type::terror;
- continue;
- }
- if (e->op == TOKtype)
- {
- foundType = true; // do not break immediately, there might be more errors
- e->checkValue(); // report an error "type T has no value"
- t0 = Type::terror;
- continue;
- }
- if (e->type->ty == Tvoid)
- {
- // void expressions do not concur to the determination of the common
- // type.
- continue;
- }
- if (checkNonAssignmentArrayOp(e))
- {
- t0 = Type::terror;
- continue;
- }
-
- e = doCopyOrMove(sc, e);
-
- if (!foundType && t0 && !t0->equals(e->type))
- {
- /* This applies ?: to merge the types. It's backwards;
- * ?: should call this function to merge types.
- */
- condexp.type = NULL;
- condexp.e1 = e0;
- condexp.e2 = e;
- condexp.loc = e->loc;
- Expression *ex = expressionSemantic(&condexp, sc);
- if (ex->op == TOKerror)
- e = ex;
- else
- {
- (*exps)[j0] = condexp.e1;
- e = condexp.e2;
- }
- }
- j0 = i;
- e0 = e;
- t0 = e->type;
- if (e->op != TOKerror)
- (*exps)[i] = e;
- }
-
- if (!t0)
- t0 = Type::tvoid; // [] is typed as void[]
- else if (t0->ty != Terror)
- {
- for (size_t i = 0; i < exps->length; i++)
- {
- Expression *e = (*exps)[i];
- if (!e)
- continue;
-
- e = e->implicitCastTo(sc, t0);
- //assert(e->op != TOKerror);
- if (e->op == TOKerror)
- {
- /* Bugzilla 13024: a workaround for the bug in typeMerge -
- * it should paint e1 and e2 by deduced common type,
- * but doesn't in this particular case.
- */
- t0 = Type::terror;
- break;
- }
- (*exps)[i] = e;
- }
- }
- if (pt)
- *pt = t0;
-
- return (t0 == Type::terror);
-}
-
-/****************************************
* Get TemplateDeclaration enclosing FuncDeclaration.
*/
@@ -1249,27 +330,6 @@ Expression *valueNoDtor(Expression *e)
return e;
}
-/********************************************
- * Issue an error if default construction is disabled for type t.
- * Default construction is required for arrays and 'out' parameters.
- * Returns:
- * true an error was issued
- */
-bool checkDefCtor(Loc loc, Type *t)
-{
- t = t->baseElemOf();
- if (t->ty == Tstruct)
- {
- StructDeclaration *sd = ((TypeStruct *)t)->sym;
- if (sd->noDefaultCtor)
- {
- sd->error(loc, "default construction is disabled");
- return true;
- }
- }
- return false;
-}
-
/*********************************************
* If e is an instance of a struct, and that struct has a copy constructor,
* rewrite e as:
@@ -1322,648 +382,6 @@ Expression *doCopyOrMove(Scope *sc, Expression *e)
return e;
}
-/****************************************
- * Now that we know the exact type of the function we're calling,
- * the arguments[] need to be adjusted:
- * 1. implicitly convert argument to the corresponding parameter type
- * 2. add default arguments for any missing arguments
- * 3. do default promotions on arguments corresponding to ...
- * 4. add hidden _arguments[] argument
- * 5. call copy constructor for struct value arguments
- * Input:
- * tf type of the function
- * fd the function being called, NULL if called indirectly
- * Output:
- * *prettype return type of function
- * *peprefix expression to execute before arguments[] are evaluated, NULL if none
- * Returns:
- * true errors happened
- */
-
-bool functionParameters(Loc loc, Scope *sc, TypeFunction *tf,
- Type *tthis, Expressions *arguments, FuncDeclaration *fd, Type **prettype, Expression **peprefix)
-{
- //printf("functionParameters()\n");
- assert(arguments);
- assert(fd || tf->next);
- size_t nargs = arguments ? arguments->length : 0;
- size_t nparams = tf->parameterList.length();
- unsigned olderrors = global.errors;
- bool err = false;
- *prettype = Type::terror;
- Expression *eprefix = NULL;
- *peprefix = NULL;
-
- if (nargs > nparams && tf->parameterList.varargs == VARARGnone)
- {
- error(loc, "expected %llu arguments, not %llu for non-variadic function type %s", (ulonglong)nparams, (ulonglong)nargs, tf->toChars());
- return true;
- }
-
- // If inferring return type, and semantic3() needs to be run if not already run
- if (!tf->next && fd->inferRetType)
- {
- fd->functionSemantic();
- }
- else if (fd && fd->parent)
- {
- TemplateInstance *ti = fd->parent->isTemplateInstance();
- if (ti && ti->tempdecl)
- {
- fd->functionSemantic3();
- }
- }
- bool isCtorCall = fd && fd->needThis() && fd->isCtorDeclaration();
-
- size_t n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams)
-
- /* If the function return type has wildcards in it, we'll need to figure out the actual type
- * based on the actual argument types.
- */
- MOD wildmatch = 0;
- if (tthis && tf->isWild() && !isCtorCall)
- {
- Type *t = tthis;
- if (t->isImmutable())
- wildmatch = MODimmutable;
- else if (t->isWildConst())
- wildmatch = MODwildconst;
- else if (t->isWild())
- wildmatch = MODwild;
- else if (t->isConst())
- wildmatch = MODconst;
- else
- wildmatch = MODmutable;
- }
-
- int done = 0;
- for (size_t i = 0; i < n; i++)
- {
- Expression *arg;
-
- if (i < nargs)
- arg = (*arguments)[i];
- else
- arg = NULL;
-
- if (i < nparams)
- {
- Parameter *p = tf->parameterList[i];
-
- if (!arg)
- {
- if (!p->defaultArg)
- {
- if (tf->parameterList.varargs == VARARGtypesafe && i + 1 == nparams)
- goto L2;
- error(loc, "expected %llu function arguments, not %llu", (ulonglong)nparams, (ulonglong)nargs);
- return true;
- }
- arg = p->defaultArg;
- arg = inlineCopy(arg, sc);
- // __FILE__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__
- arg = arg->resolveLoc(loc, sc);
- arguments->push(arg);
- nargs++;
- }
-
- if (tf->parameterList.varargs == VARARGtypesafe && i + 1 == nparams)
- {
- //printf("\t\tvarargs == 2, p->type = '%s'\n", p->type->toChars());
- {
- MATCH m;
- if ((m = arg->implicitConvTo(p->type)) > MATCHnomatch)
- {
- if (p->type->nextOf() && arg->implicitConvTo(p->type->nextOf()) >= m)
- goto L2;
- else if (nargs != nparams)
- { error(loc, "expected %llu function arguments, not %llu", (ulonglong)nparams, (ulonglong)nargs);
- return true;
- }
- goto L1;
- }
- }
- L2:
- Type *tb = p->type->toBasetype();
- Type *tret = p->isLazyArray();
- switch (tb->ty)
- {
- case Tsarray:
- case Tarray:
- {
- /* Create a static array variable v of type arg->type:
- * T[dim] __arrayArg = [ arguments[i], ..., arguments[nargs-1] ];
- *
- * The array literal in the initializer of the hidden variable
- * is now optimized. See Bugzilla 2356.
- */
- Type *tbn = ((TypeArray *)tb)->next;
-
- Expressions *elements = new Expressions();
- elements->setDim(nargs - i);
- for (size_t u = 0; u < elements->length; u++)
- {
- Expression *a = (*arguments)[i + u];
- if (tret && a->implicitConvTo(tret))
- {
- a = a->implicitCastTo(sc, tret);
- a = a->optimize(WANTvalue);
- a = toDelegate(a, a->type, sc);
- }
- else
- a = a->implicitCastTo(sc, tbn);
- (*elements)[u] = a;
- }
- // Bugzilla 14395: Convert to a static array literal, or its slice.
- arg = new ArrayLiteralExp(loc, tbn->sarrayOf(nargs - i), elements);
- if (tb->ty == Tarray)
- {
- arg = new SliceExp(loc, arg, NULL, NULL);
- arg->type = p->type;
- }
- break;
- }
- case Tclass:
- {
- /* Set arg to be:
- * new Tclass(arg0, arg1, ..., argn)
- */
- Expressions *args = new Expressions();
- args->setDim(nargs - i);
- for (size_t u = i; u < nargs; u++)
- (*args)[u - i] = (*arguments)[u];
- arg = new NewExp(loc, NULL, NULL, p->type, args);
- break;
- }
- default:
- if (!arg)
- {
- error(loc, "not enough arguments");
- return true;
- }
- break;
- }
- arg = expressionSemantic(arg, sc);
- //printf("\targ = '%s'\n", arg->toChars());
- arguments->setDim(i + 1);
- (*arguments)[i] = arg;
- nargs = i + 1;
- done = 1;
- }
-
- L1:
- if (!(p->storageClass & STClazy && p->type->ty == Tvoid))
- {
- bool isRef = (p->storageClass & (STCref | STCout)) != 0;
- if (unsigned char wm = arg->type->deduceWild(p->type, isRef))
- {
- if (wildmatch)
- wildmatch = MODmerge(wildmatch, wm);
- else
- wildmatch = wm;
- //printf("[%d] p = %s, a = %s, wm = %d, wildmatch = %d\n", i, p->type->toChars(), arg->type->toChars(), wm, wildmatch);
- }
- }
- }
- if (done)
- break;
- }
- if ((wildmatch == MODmutable || wildmatch == MODimmutable) &&
- tf->next->hasWild() &&
- (tf->isref || !tf->next->implicitConvTo(tf->next->immutableOf())))
- {
- if (fd)
- {
- /* If the called function may return the reference to
- * outer inout data, it should be rejected.
- *
- * void foo(ref inout(int) x) {
- * ref inout(int) bar(inout(int)) { return x; }
- * struct S { ref inout(int) bar() inout { return x; } }
- * bar(int.init) = 1; // bad!
- * S().bar() = 1; // bad!
- * }
- */
- Dsymbol *s = NULL;
- if (fd->isThis() || fd->isNested())
- s = fd->toParent2();
- for (; s; s = s->toParent2())
- {
- if (AggregateDeclaration *ad = s->isAggregateDeclaration())
- {
- if (ad->isNested())
- continue;
- break;
- }
- if (FuncDeclaration *ff = s->isFuncDeclaration())
- {
- if (((TypeFunction *)ff->type)->iswild)
- goto Linouterr;
-
- if (ff->isNested() || ff->isThis())
- continue;
- }
- break;
- }
- }
- else if (tf->isWild())
- {
- Linouterr:
- const char *s = wildmatch == MODmutable ? "mutable" : MODtoChars(wildmatch);
- error(loc, "modify inout to %s is not allowed inside inout function", s);
- return true;
- }
- }
-
- assert(nargs >= nparams);
- for (size_t i = 0; i < nargs; i++)
- {
- Expression *arg = (*arguments)[i];
- assert(arg);
- if (i < nparams)
- {
- Parameter *p = tf->parameterList[i];
-
- if (!(p->storageClass & STClazy && p->type->ty == Tvoid))
- {
- Type *tprm = p->type;
- if (p->type->hasWild())
- tprm = p->type->substWildTo(wildmatch);
- if (!tprm->equals(arg->type))
- {
- //printf("arg->type = %s, p->type = %s\n", arg->type->toChars(), p->type->toChars());
- arg = arg->implicitCastTo(sc, tprm);
- arg = arg->optimize(WANTvalue, (p->storageClass & (STCref | STCout)) != 0);
- }
- }
- if (p->storageClass & STCref)
- {
- arg = arg->toLvalue(sc, arg);
-
- // Look for mutable misaligned pointer, etc., in @safe mode
- err |= checkUnsafeAccess(sc, arg, false, true);
- }
- else if (p->storageClass & STCout)
- {
- Type *t = arg->type;
- if (!t->isMutable() || !t->isAssignable()) // check blit assignable
- {
- arg->error("cannot modify struct %s with immutable members", arg->toChars());
- err = true;
- }
- else
- {
- // Look for misaligned pointer, etc., in @safe mode
- err |= checkUnsafeAccess(sc, arg, false, true);
- err |= checkDefCtor(arg->loc, t); // t must be default constructible
- }
- arg = arg->toLvalue(sc, arg);
- }
- else if (p->storageClass & STClazy)
- {
- // Convert lazy argument to a delegate
- if (p->type->ty == Tvoid)
- arg = toDelegate(arg, p->type, sc);
- else
- arg = toDelegate(arg, arg->type, sc);
- }
-
- //printf("arg: %s\n", arg->toChars());
- //printf("type: %s\n", arg->type->toChars());
- if (tf->parameterEscapes(p))
- {
- /* Argument value can escape from the called function.
- * Check arg to see if it matters.
- */
- if (global.params.vsafe)
- err |= checkParamArgumentEscape(sc, fd, p->ident, arg, false);
- }
- else
- {
- /* Argument value cannot escape from the called function.
- */
- Expression *a = arg;
- if (a->op == TOKcast)
- a = ((CastExp *)a)->e1;
-
- if (a->op == TOKfunction)
- {
- /* Function literals can only appear once, so if this
- * appearance was scoped, there cannot be any others.
- */
- FuncExp *fe = (FuncExp *)a;
- fe->fd->tookAddressOf = 0;
- }
- else if (a->op == TOKdelegate)
- {
- /* For passing a delegate to a scoped parameter,
- * this doesn't count as taking the address of it.
- * We only worry about 'escaping' references to the function.
- */
- DelegateExp *de = (DelegateExp *)a;
- if (de->e1->op == TOKvar)
- { VarExp *ve = (VarExp *)de->e1;
- FuncDeclaration *f = ve->var->isFuncDeclaration();
- if (f)
- { f->tookAddressOf--;
- //printf("tookAddressOf = %d\n", f->tookAddressOf);
- }
- }
- }
- }
- arg = arg->optimize(WANTvalue, (p->storageClass & (STCref | STCout)) != 0);
- }
- else
- {
- // These will be the trailing ... arguments
-
- // If not D linkage, do promotions
- if (tf->linkage != LINKd)
- {
- // Promote bytes, words, etc., to ints
- arg = integralPromotions(arg, sc);
-
- // Promote floats to doubles
- switch (arg->type->ty)
- {
- case Tfloat32:
- arg = arg->castTo(sc, Type::tfloat64);
- break;
-
- case Timaginary32:
- arg = arg->castTo(sc, Type::timaginary64);
- break;
- }
-
- if (tf->parameterList.varargs == VARARGvariadic)
- {
- const char *p = tf->linkage == LINKc ? "extern(C)" : "extern(C++)";
- if (arg->type->ty == Tarray)
- {
- arg->error("cannot pass dynamic arrays to %s vararg functions", p);
- err = true;
- }
- if (arg->type->ty == Tsarray)
- {
- arg->error("cannot pass static arrays to %s vararg functions", p);
- err = true;
- }
- }
- }
-
- // Do not allow types that need destructors
- if (arg->type->needsDestruction())
- {
- arg->error("cannot pass types that need destruction as variadic arguments");
- err = true;
- }
-
- // Convert static arrays to dynamic arrays
- // BUG: I don't think this is right for D2
- Type *tb = arg->type->toBasetype();
- if (tb->ty == Tsarray)
- {
- TypeSArray *ts = (TypeSArray *)tb;
- Type *ta = ts->next->arrayOf();
- if (ts->size(arg->loc) == 0)
- arg = new NullExp(arg->loc, ta);
- else
- arg = arg->castTo(sc, ta);
- }
- if (tb->ty == Tstruct)
- {
- //arg = callCpCtor(sc, arg);
- }
-
- // Give error for overloaded function addresses
- if (arg->op == TOKsymoff)
- { SymOffExp *se = (SymOffExp *)arg;
- if (se->hasOverloads &&
- !se->var->isFuncDeclaration()->isUnique())
- { arg->error("function %s is overloaded", arg->toChars());
- err = true;
- }
- }
- if (arg->checkValue())
- err = true;
- arg = arg->optimize(WANTvalue);
- }
- (*arguments)[i] = arg;
- }
-
- /* Remaining problems:
- * 1. order of evaluation - some function push L-to-R, others R-to-L. Until we resolve what array assignment does (which is
- * implemented by calling a function) we'll defer this for now.
- * 2. value structs (or static arrays of them) that need to be copy constructed
- * 3. value structs (or static arrays of them) that have destructors, and subsequent arguments that may throw before the
- * function gets called (functions normally destroy their parameters)
- * 2 and 3 are handled by doing the argument construction in 'eprefix' so that if a later argument throws, they are cleaned
- * up properly. Pushing arguments on the stack then cannot fail.
- */
- if (1)
- {
- /* TODO: tackle problem 1)
- */
- const bool leftToRight = true; // TODO: something like !fd.isArrayOp
- if (!leftToRight)
- assert(nargs == nparams); // no variadics for RTL order, as they would probably be evaluated LTR and so add complexity
-
- const ptrdiff_t start = (leftToRight ? 0 : (ptrdiff_t)nargs - 1);
- const ptrdiff_t end = (leftToRight ? (ptrdiff_t)nargs : -1);
- const ptrdiff_t step = (leftToRight ? 1 : -1);
-
- /* Compute indices of last throwing argument and first arg needing destruction.
- * Used to not set up destructors unless an arg needs destruction on a throw
- * in a later argument.
- */
- ptrdiff_t lastthrow = -1;
- ptrdiff_t firstdtor = -1;
- for (ptrdiff_t i = start; i != end; i += step)
- {
- Expression *arg = (*arguments)[i];
- if (canThrow(arg, sc->func, false))
- lastthrow = i;
- if (firstdtor == -1 && arg->type->needsDestruction())
- {
- Parameter *p = (i >= (ptrdiff_t)nparams ? NULL : tf->parameterList[i]);
- if (!(p && (p->storageClass & (STClazy | STCref | STCout))))
- firstdtor = i;
- }
- }
-
- /* Does problem 3) apply to this call?
- */
- const bool needsPrefix = (firstdtor >= 0 && lastthrow >= 0
- && (lastthrow - firstdtor) * step > 0);
-
- /* If so, initialize 'eprefix' by declaring the gate
- */
- VarDeclaration *gate = NULL;
- if (needsPrefix)
- {
- // eprefix => bool __gate [= false]
- Identifier *idtmp = Identifier::generateId("__gate");
- gate = new VarDeclaration(loc, Type::tbool, idtmp, NULL);
- gate->storage_class |= STCtemp | STCctfe | STCvolatile;
- dsymbolSemantic(gate, sc);
-
- Expression *ae = new DeclarationExp(loc, gate);
- eprefix = expressionSemantic(ae, sc);
- }
-
- for (ptrdiff_t i = start; i != end; i += step)
- {
- Expression *arg = (*arguments)[i];
-
- Parameter *parameter = (i >= (ptrdiff_t)nparams ? NULL : tf->parameterList[i]);
- const bool isRef = (parameter && (parameter->storageClass & (STCref | STCout)));
- const bool isLazy = (parameter && (parameter->storageClass & STClazy));
-
- /* Skip lazy parameters
- */
- if (isLazy)
- continue;
-
- /* Do we have a gate? Then we have a prefix and we're not yet past the last throwing arg.
- * Declare a temporary variable for this arg and append that declaration to 'eprefix',
- * which will implicitly take care of potential problem 2) for this arg.
- * 'eprefix' will therefore finally contain all args up to and including the last
- * potentially throwing arg, excluding all lazy parameters.
- */
- if (gate)
- {
- const bool needsDtor = (!isRef && arg->type->needsDestruction() && i != lastthrow);
-
- /* Declare temporary 'auto __pfx = arg' (needsDtor) or 'auto __pfy = arg' (!needsDtor)
- */
- VarDeclaration *tmp = copyToTemp(0,
- needsDtor ? "__pfx" : "__pfy",
- !isRef ? arg : arg->addressOf());
- dsymbolSemantic(tmp, sc);
-
- /* Modify the destructor so it only runs if gate==false, i.e.,
- * only if there was a throw while constructing the args
- */
- if (!needsDtor)
- {
- if (tmp->edtor)
- {
- assert(i == lastthrow);
- tmp->edtor = NULL;
- }
- }
- else
- {
- // edtor => (__gate || edtor)
- assert(tmp->edtor);
- Expression *e = tmp->edtor;
- e = new LogicalExp(e->loc, TOKoror, new VarExp(e->loc, gate), e);
- tmp->edtor = expressionSemantic(e, sc);
- //printf("edtor: %s\n", tmp->edtor->toChars());
- }
-
- // eprefix => (eprefix, auto __pfx/y = arg)
- DeclarationExp *ae = new DeclarationExp(loc, tmp);
- eprefix = Expression::combine(eprefix, expressionSemantic(ae, sc));
-
- // arg => __pfx/y
- arg = new VarExp(loc, tmp);
- arg = expressionSemantic(arg, sc);
- if (isRef)
- {
- arg = new PtrExp(loc, arg);
- arg = expressionSemantic(arg, sc);
- }
-
- /* Last throwing arg? Then finalize eprefix => (eprefix, gate = true),
- * i.e., disable the dtors right after constructing the last throwing arg.
- * From now on, the callee will take care of destructing the args because
- * the args are implicitly moved into function parameters.
- *
- * Set gate to null to let the next iterations know they don't need to
- * append to eprefix anymore.
- */
- if (i == lastthrow)
- {
- Expression *e = new AssignExp(gate->loc, new VarExp(gate->loc, gate), new IntegerExp(gate->loc, 1, Type::tbool));
- eprefix = Expression::combine(eprefix, expressionSemantic(e, sc));
- gate = NULL;
- }
- }
- else
- {
- /* No gate, no prefix to append to.
- * Handle problem 2) by calling the copy constructor for value structs
- * (or static arrays of them) if appropriate.
- */
- Type *tv = arg->type->baseElemOf();
- if (!isRef && tv->ty == Tstruct)
- arg = doCopyOrMove(sc, arg);
- }
-
- (*arguments)[i] = arg;
- }
- }
- //if (eprefix) printf("eprefix: %s\n", eprefix->toChars());
-
- // If D linkage and variadic, add _arguments[] as first argument
- if (tf->isDstyleVariadic())
- {
- assert(arguments->length >= nparams);
-
- Parameters *args = new Parameters;
- args->setDim(arguments->length - nparams);
- for (size_t i = 0; i < arguments->length - nparams; i++)
- {
- Parameter *arg = new Parameter(STCin, (*arguments)[nparams + i]->type, NULL, NULL, NULL);
- (*args)[i] = arg;
- }
-
- TypeTuple *tup = new TypeTuple(args);
- Expression *e = new TypeidExp(loc, tup);
- e = expressionSemantic(e, sc);
- arguments->insert(0, e);
- }
-
- Type *tret = tf->next;
- if (isCtorCall)
- {
- //printf("[%s] fd = %s %s, %d %d %d\n", loc.toChars(), fd->toChars(), fd->type->toChars(),
- // wildmatch, tf->isWild(), fd->isolateReturn());
- if (!tthis)
- {
- assert(sc->intypeof || global.errors);
- tthis = fd->isThis()->type->addMod(fd->type->mod);
- }
- if (tf->isWild() && !fd->isolateReturn())
- {
- if (wildmatch)
- tret = tret->substWildTo(wildmatch);
- int offset;
- if (!tret->implicitConvTo(tthis) &&
- !(MODimplicitConv(tret->mod, tthis->mod) && tret->isBaseOf(tthis, &offset) && offset == 0))
- {
- const char* s1 = tret ->isNaked() ? " mutable" : tret ->modToChars();
- const char* s2 = tthis->isNaked() ? " mutable" : tthis->modToChars();
- ::error(loc, "inout constructor %s creates%s object, not%s",
- fd->toPrettyChars(), s1, s2);
- err = true;
- }
- }
- tret = tthis;
- }
- else if (wildmatch && tret)
- {
- /* Adjust function return type based on wildmatch
- */
- //printf("wildmatch = x%x, tret = %s\n", wildmatch, tret->toChars());
- tret = tret->substWildTo(wildmatch);
- }
- *prettype = tret;
- *peprefix = eprefix;
- return (err || olderrors != global.errors);
-}
-
/******************************** Expression **************************/
Expression::Expression(Loc loc, TOK op, int size)
@@ -5288,8 +3706,10 @@ MATCH FuncExp::matchType(Type *to, Scope *sc, FuncExp **presult, int flag)
}
else if (!flag)
{
+ const char *ts[2];
+ toAutoQualChars(ts, tx, to);
error("cannot implicitly convert expression (%s) of type %s to %s",
- toChars(), tx->toChars(), to->toChars());
+ toChars(), ts[0], ts[1]);
}
return m;
}
@@ -5644,11 +4064,17 @@ Expression *BinExp::incompatibleTypes()
error("incompatible types for ((%s) %s (%s)): cannot use `%s` with types",
e1->toChars(), Token::toChars(thisOp), e2->toChars(), Token::toChars(op));
}
+ else if (e1->type->equals(e2->type))
+ {
+ error("incompatible types for ((%s) %s (%s)): both operands are of type `%s`",
+ e1->toChars(), Token::toChars(thisOp), e2->toChars(), e1->type->toChars());
+ }
else
{
+ const char *ts[2];
+ toAutoQualChars(ts, e1->type, e2->type);
error("incompatible types for ((%s) %s (%s)): `%s` and `%s`",
- e1->toChars(), Token::toChars(thisOp), e2->toChars(),
- e1->type->toChars(), e2->type->toChars());
+ e1->toChars(), Token::toChars(thisOp), e2->toChars(), ts[0], ts[1]);
}
return new ErrorExp();
}
@@ -5693,9 +4119,36 @@ Expression *BinAssignExp::modifiableLvalue(Scope *sc, Expression *)
/************************************************************/
-CompileExp::CompileExp(Loc loc, Expression *e)
- : UnaExp(loc, TOKmixin, sizeof(CompileExp), e)
+CompileExp::CompileExp(Loc loc, Expressions *exps)
+ : Expression(loc, TOKmixin, sizeof(CompileExp))
+{
+ this->exps = exps;
+}
+
+Expression *CompileExp::syntaxCopy()
{
+ return new CompileExp(loc, arraySyntaxCopy(exps));
+}
+
+bool CompileExp::equals(RootObject *o)
+{
+ if (this == o)
+ return true;
+ if (o && o->dyncast() == DYNCAST_EXPRESSION && ((Expression *)o)->op == TOKmixin)
+ {
+ CompileExp *ce = (CompileExp *)o;
+ if (exps->length != ce->exps->length)
+ return false;
+ for (size_t i = 0; i < exps->length; i++)
+ {
+ Expression *e1 = (*exps)[i];
+ Expression *e2 = (*ce->exps)[i];
+ if (e1 != e2 && (!e1 || !e2 || !e1->equals(e2)))
+ return false;
+ }
+ return true;
+ }
+ return false;
}
/************************************************************/
@@ -6362,64 +4815,6 @@ ArrayLengthExp::ArrayLengthExp(Loc loc, Expression *e1)
{
}
-Expression *opAssignToOp(Loc loc, TOK op, Expression *e1, Expression *e2)
-{ Expression *e;
-
- switch (op)
- {
- case TOKaddass: e = new AddExp(loc, e1, e2); break;
- case TOKminass: e = new MinExp(loc, e1, e2); break;
- case TOKmulass: e = new MulExp(loc, e1, e2); break;
- case TOKdivass: e = new DivExp(loc, e1, e2); break;
- case TOKmodass: e = new ModExp(loc, e1, e2); break;
- case TOKandass: e = new AndExp(loc, e1, e2); break;
- case TOKorass: e = new OrExp (loc, e1, e2); break;
- case TOKxorass: e = new XorExp(loc, e1, e2); break;
- case TOKshlass: e = new ShlExp(loc, e1, e2); break;
- case TOKshrass: e = new ShrExp(loc, e1, e2); break;
- case TOKushrass: e = new UshrExp(loc, e1, e2); break;
- default: assert(0);
- }
- return e;
-}
-
-/*********************
- * Rewrite:
- * array.length op= e2
- * as:
- * array.length = array.length op e2
- * or:
- * auto tmp = &array;
- * (*tmp).length = (*tmp).length op e2
- */
-
-Expression *ArrayLengthExp::rewriteOpAssign(BinExp *exp)
-{
- Expression *e;
-
- assert(exp->e1->op == TOKarraylength);
- ArrayLengthExp *ale = (ArrayLengthExp *)exp->e1;
- if (ale->e1->op == TOKvar)
- {
- e = opAssignToOp(exp->loc, exp->op, ale, exp->e2);
- e = new AssignExp(exp->loc, ale->syntaxCopy(), e);
- }
- else
- {
- /* auto tmp = &array;
- * (*tmp).length = (*tmp).length op e2
- */
- VarDeclaration *tmp = copyToTemp(0, "__arraylength", new AddrExp(ale->loc, ale->e1));
-
- Expression *e1 = new ArrayLengthExp(ale->loc, new PtrExp(ale->loc, new VarExp(ale->loc, tmp)));
- Expression *elvalue = e1->syntaxCopy();
- e = opAssignToOp(exp->loc, exp->op, e1, exp->e2);
- e = new AssignExp(exp->loc, elvalue, e);
- e = new CommaExp(exp->loc, new DeclarationExp(ale->loc, tmp), e);
- }
- return e;
-}
-
/*********************** IntervalExp ********************************/
// Mainly just a placeholder
@@ -7248,203 +5643,6 @@ Expression *PrettyFuncInitExp::resolveLoc(Loc loc, Scope *sc)
return e;
}
-/****************************************************************/
-
-Expression *extractOpDollarSideEffect(Scope *sc, UnaExp *ue)
-{
- Expression *e0;
- Expression *e1 = Expression::extractLast(ue->e1, &e0);
- // Bugzilla 12585: Extract the side effect part if ue->e1 is comma.
-
- if (!isTrivialExp(e1))
- {
- /* Even if opDollar is needed, 'e1' should be evaluate only once. So
- * Rewrite:
- * e1.opIndex( ... use of $ ... )
- * e1.opSlice( ... use of $ ... )
- * as:
- * (ref __dop = e1, __dop).opIndex( ... __dop.opDollar ...)
- * (ref __dop = e1, __dop).opSlice( ... __dop.opDollar ...)
- */
- e1 = extractSideEffect(sc, "__dop", &e0, e1, false);
- assert(e1->op == TOKvar);
- VarExp *ve = (VarExp *)e1;
- ve->var->storage_class |= STCexptemp; // lifetime limited to expression
- }
- ue->e1 = e1;
- return e0;
-}
-
-/**************************************
- * Runs semantic on ae->arguments. Declares temporary variables
- * if '$' was used.
- */
-Expression *resolveOpDollar(Scope *sc, ArrayExp *ae, Expression **pe0)
-{
- assert(!ae->lengthVar);
-
- *pe0 = NULL;
-
- AggregateDeclaration *ad = isAggregate(ae->e1->type);
- Dsymbol *slice = search_function(ad, Id::slice);
- //printf("slice = %s %s\n", slice->kind(), slice->toChars());
-
- for (size_t i = 0; i < ae->arguments->length; i++)
- {
- if (i == 0)
- *pe0 = extractOpDollarSideEffect(sc, ae);
-
- Expression *e = (*ae->arguments)[i];
- if (e->op == TOKinterval && !(slice && slice->isTemplateDeclaration()))
- {
- Lfallback:
- if (ae->arguments->length == 1)
- return NULL;
- ae->error("multi-dimensional slicing requires template opSlice");
- return new ErrorExp();
- }
- //printf("[%d] e = %s\n", i, e->toChars());
-
- // Create scope for '$' variable for this dimension
- ArrayScopeSymbol *sym = new ArrayScopeSymbol(sc, ae);
- sym->loc = ae->loc;
- sym->parent = sc->scopesym;
- sc = sc->push(sym);
- ae->lengthVar = NULL; // Create it only if required
- ae->currentDimension = i; // Dimension for $, if required
-
- e = expressionSemantic(e, sc);
- e = resolveProperties(sc, e);
-
- if (ae->lengthVar && sc->func)
- {
- // If $ was used, declare it now
- Expression *de = new DeclarationExp(ae->loc, ae->lengthVar);
- de = expressionSemantic(de, sc);
- *pe0 = Expression::combine(*pe0, de);
- }
- sc = sc->pop();
-
- if (e->op == TOKinterval)
- {
- IntervalExp *ie = (IntervalExp *)e;
-
- Objects *tiargs = new Objects();
- Expression *edim = new IntegerExp(ae->loc, i, Type::tsize_t);
- edim = expressionSemantic(edim, sc);
- tiargs->push(edim);
-
- Expressions *fargs = new Expressions();
- fargs->push(ie->lwr);
- fargs->push(ie->upr);
-
- unsigned xerrors = global.startGagging();
- sc = sc->push();
- FuncDeclaration *fslice = resolveFuncCall(ae->loc, sc, slice, tiargs, ae->e1->type, fargs, 1);
- sc = sc->pop();
- global.endGagging(xerrors);
- if (!fslice)
- goto Lfallback;
-
- e = new DotTemplateInstanceExp(ae->loc, ae->e1, slice->ident, tiargs);
- e = new CallExp(ae->loc, e, fargs);
- e = expressionSemantic(e, sc);
- }
-
- if (!e->type)
- {
- ae->error("%s has no value", e->toChars());
- e = new ErrorExp();
- }
- if (e->op == TOKerror)
- return e;
-
- (*ae->arguments)[i] = e;
- }
-
- return ae;
-}
-
-/***********************************************************
- * Resolve `exp` as a compile-time known string.
- * Params:
- * sc = scope
- * exp = Expression which expected as a string
- * s = What the string is expected for, will be used in error diagnostic.
- * Returns:
- * String literal, or `null` if error happens.
- */
-StringExp *semanticString(Scope *sc, Expression *exp, const char *s)
-{
- sc = sc->startCTFE();
- exp = expressionSemantic(exp, sc);
- exp = resolveProperties(sc, exp);
- sc = sc->endCTFE();
-
- if (exp->op == TOKerror)
- return NULL;
-
- Expression *e = exp;
- if (exp->type->isString())
- {
- e = e->ctfeInterpret();
- if (e->op == TOKerror)
- return NULL;
- }
-
- StringExp *se = e->toStringExp();
- if (!se)
- {
- exp->error("string expected for %s, not (%s) of type %s",
- s, exp->toChars(), exp->type->toChars());
- return NULL;
- }
- return se;
-}
-
-/**************************************
- * Runs semantic on se->lwr and se->upr. Declares a temporary variable
- * if '$' was used.
- */
-Expression *resolveOpDollar(Scope *sc, ArrayExp *ae, IntervalExp *ie, Expression **pe0)
-{
- //assert(!ae->lengthVar);
- if (!ie)
- return ae;
-
- VarDeclaration *lengthVar = ae->lengthVar;
-
- // create scope for '$'
- ArrayScopeSymbol *sym = new ArrayScopeSymbol(sc, ae);
- sym->loc = ae->loc;
- sym->parent = sc->scopesym;
- sc = sc->push(sym);
-
- for (size_t i = 0; i < 2; ++i)
- {
- Expression *e = i == 0 ? ie->lwr : ie->upr;
- e = expressionSemantic(e, sc);
- e = resolveProperties(sc, e);
- if (!e->type)
- {
- ae->error("%s has no value", e->toChars());
- return new ErrorExp();
- }
- (i == 0 ? ie->lwr : ie->upr) = e;
- }
-
- if (lengthVar != ae->lengthVar && sc->func)
- {
- // If $ was used, declare it now
- Expression *de = new DeclarationExp(ae->loc, ae->lengthVar);
- de = expressionSemantic(de, sc);
- *pe0 = Expression::combine(*pe0, de);
- }
- sc = sc->pop();
-
- return ae;
-}
-
Expression *BinExp::reorderSettingAAElem(Scope *sc)
{
BinExp *be = this;
diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h
index f0ae2805df4..2ed8fac373e 100644
--- a/gcc/d/dmd/expression.h
+++ b/gcc/d/dmd/expression.h
@@ -883,10 +883,14 @@ public:
/****************************************************************/
-class CompileExp : public UnaExp
+class CompileExp : public Expression
{
public:
- CompileExp(Loc loc, Expression *e);
+ Expressions *exps;
+
+ CompileExp(Loc loc, Expressions *exps);
+ Expression *syntaxCopy();
+ bool equals(RootObject *o);
void accept(Visitor *v) { v->visit(this); }
};
@@ -1124,7 +1128,6 @@ class ArrayLengthExp : public UnaExp
public:
ArrayLengthExp(Loc loc, Expression *e1);
- static Expression *rewriteOpAssign(BinExp *exp);
void accept(Visitor *v) { v->visit(this); }
};
diff --git a/gcc/d/dmd/expressionsem.c b/gcc/d/dmd/expressionsem.c
index 7cccd956966..4a37d0fcba2 100644
--- a/gcc/d/dmd/expressionsem.c
+++ b/gcc/d/dmd/expressionsem.c
@@ -47,26 +47,1252 @@ bool symbolIsVisible(Scope *sc, Dsymbol *s);
VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e);
Expression *extractSideEffect(Scope *sc, const char *name, Expression **e0, Expression *e, bool alwaysCopy = false);
Type *getTypeInfoType(Loc loc, Type *t, Scope *sc);
+char *MODtoChars(MOD mod);
bool MODimplicitConv(MOD modfrom, MOD modto);
+MOD MODmerge(MOD mod1, MOD mod2);
MATCH MODmethodConv(MOD modfrom, MOD modto);
void MODMatchToBuffer(OutBuffer *buf, unsigned char lhsMod, unsigned char rhsMod);
void unSpeculative(Scope *sc, RootObject *o);
-bool arrayExpressionToCommonType(Scope *sc, Expressions *exps, Type **pt);
-bool checkDefCtor(Loc loc, Type *t);
bool isDotOpDispatch(Expression *e);
-bool functionParameters(Loc loc, Scope *sc, TypeFunction *tf, Type *tthis, Expressions *arguments, FuncDeclaration *fd, Type **prettype, Expression **peprefix);
-Expression *getRightThis(Loc loc, Scope *sc, AggregateDeclaration *ad, Expression *e1, Declaration *var, int flag = 0);
bool isNeedThisScope(Scope *sc, Declaration *d);
-Expression *resolveUFCS(Scope *sc, CallExp *ce);
bool checkUnsafeAccess(Scope *sc, Expression *e, bool readonly, bool printmsg);
bool isSafeCast(Expression *e, Type *tfrom, Type *tto);
FuncDeclaration *isFuncAddress(Expression *e, bool *hasOverloads = NULL);
Expression *callCpCtor(Scope *sc, Expression *e);
Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
-Expression *resolveUFCSProperties(Scope *sc, Expression *e1, Expression *e2 = NULL);
-Expression *resolvePropertiesX(Scope *sc, Expression *e1, Expression *e2 = NULL);
+
+bool checkPrintfFormat(const Loc &loc, const char *format, Expressions &args, bool isVa_list);
+bool checkScanfFormat(const Loc &loc, const char *format, Expressions &args, bool isVa_list);
+
+/********************************************************
+ * Perform semantic analysis and CTFE on expressions to produce
+ * a string.
+ * Params:
+ * buf = append generated string to buffer
+ * sc = context
+ * exps = array of Expressions
+ * Returns:
+ * true on error
+ */
+bool expressionsToString(OutBuffer &buf, Scope *sc, Expressions *exps)
+{
+ if (!exps)
+ return false;
+
+ for (size_t i = 0; i < exps->length; i++)
+ {
+ Expression *ex = (*exps)[i];
+ if (!ex)
+ continue;
+ Scope *sc2 = sc->startCTFE();
+ Expression *e2 = expressionSemantic(ex, sc2);
+ Expression *e3 = resolveProperties(sc2, e2);
+ sc2->endCTFE();
+
+ // allowed to contain types as well as expressions
+ Expression *e4 = ctfeInterpretForPragmaMsg(e3);
+ if (!e4 || e4->op == TOKerror)
+ return true;
+
+ // expand tuple
+ if (TupleExp *te = e4->isTupleExp())
+ {
+ if (expressionsToString(buf, sc, te->exps))
+ return true;
+ continue;
+ }
+ // char literals exp `.toStringExp` return `null` but we cant override it
+ // because in most contexts we don't want the conversion to succeed.
+ IntegerExp *ie = e4->isIntegerExp();
+ const TY ty = (ie && ie->type) ? ie->type->ty : (TY)Terror;
+ if (ty == Tchar || ty == Twchar || ty == Tdchar)
+ {
+ TypeSArray *tsa = new TypeSArray(ie->type, new IntegerExp(ex->loc, 1, Type::tint32));
+ e4 = new ArrayLiteralExp(ex->loc, tsa, ie);
+ }
+
+ if (StringExp *se = e4->toStringExp())
+ buf.writestring(se->toUTF8(sc)->toPtr());
+ else
+ buf.writestring(e4->toChars());
+ }
+ return false;
+}
+
+/***********************************************************
+ * Resolve `exp` as a compile-time known string.
+ * Params:
+ * sc = scope
+ * exp = Expression which expected as a string
+ * s = What the string is expected for, will be used in error diagnostic.
+ * Returns:
+ * String literal, or `null` if error happens.
+ */
+StringExp *semanticString(Scope *sc, Expression *exp, const char *s)
+{
+ sc = sc->startCTFE();
+ exp = expressionSemantic(exp, sc);
+ exp = resolveProperties(sc, exp);
+ sc = sc->endCTFE();
+
+ if (exp->op == TOKerror)
+ return NULL;
+
+ Expression *e = exp;
+ if (exp->type->isString())
+ {
+ e = e->ctfeInterpret();
+ if (e->op == TOKerror)
+ return NULL;
+ }
+
+ StringExp *se = e->toStringExp();
+ if (!se)
+ {
+ exp->error("string expected for %s, not (%s) of type %s",
+ s, exp->toChars(), exp->type->toChars());
+ return NULL;
+ }
+ return se;
+}
+
+/****************************************************************/
+
+static Expression *extractOpDollarSideEffect(Scope *sc, UnaExp *ue)
+{
+ Expression *e0;
+ Expression *e1 = Expression::extractLast(ue->e1, &e0);
+ // Bugzilla 12585: Extract the side effect part if ue->e1 is comma.
+
+ if (!isTrivialExp(e1))
+ {
+ /* Even if opDollar is needed, 'e1' should be evaluate only once. So
+ * Rewrite:
+ * e1.opIndex( ... use of $ ... )
+ * e1.opSlice( ... use of $ ... )
+ * as:
+ * (ref __dop = e1, __dop).opIndex( ... __dop.opDollar ...)
+ * (ref __dop = e1, __dop).opSlice( ... __dop.opDollar ...)
+ */
+ e1 = extractSideEffect(sc, "__dop", &e0, e1, false);
+ assert(e1->op == TOKvar);
+ VarExp *ve = (VarExp *)e1;
+ ve->var->storage_class |= STCexptemp; // lifetime limited to expression
+ }
+ ue->e1 = e1;
+ return e0;
+}
+
+/**************************************
+ * Runs semantic on ae->arguments. Declares temporary variables
+ * if '$' was used.
+ */
+Expression *resolveOpDollar(Scope *sc, ArrayExp *ae, Expression **pe0)
+{
+ assert(!ae->lengthVar);
+
+ *pe0 = NULL;
+
+ AggregateDeclaration *ad = isAggregate(ae->e1->type);
+ Dsymbol *slice = search_function(ad, Id::slice);
+ //printf("slice = %s %s\n", slice->kind(), slice->toChars());
+
+ for (size_t i = 0; i < ae->arguments->length; i++)
+ {
+ if (i == 0)
+ *pe0 = extractOpDollarSideEffect(sc, ae);
+
+ Expression *e = (*ae->arguments)[i];
+ if (e->op == TOKinterval && !(slice && slice->isTemplateDeclaration()))
+ {
+ Lfallback:
+ if (ae->arguments->length == 1)
+ return NULL;
+ ae->error("multi-dimensional slicing requires template opSlice");
+ return new ErrorExp();
+ }
+ //printf("[%d] e = %s\n", i, e->toChars());
+
+ // Create scope for '$' variable for this dimension
+ ArrayScopeSymbol *sym = new ArrayScopeSymbol(sc, ae);
+ sym->loc = ae->loc;
+ sym->parent = sc->scopesym;
+ sc = sc->push(sym);
+ ae->lengthVar = NULL; // Create it only if required
+ ae->currentDimension = i; // Dimension for $, if required
+
+ e = expressionSemantic(e, sc);
+ e = resolveProperties(sc, e);
+
+ if (ae->lengthVar && sc->func)
+ {
+ // If $ was used, declare it now
+ Expression *de = new DeclarationExp(ae->loc, ae->lengthVar);
+ de = expressionSemantic(de, sc);
+ *pe0 = Expression::combine(*pe0, de);
+ }
+ sc = sc->pop();
+
+ if (e->op == TOKinterval)
+ {
+ IntervalExp *ie = (IntervalExp *)e;
+
+ Objects *tiargs = new Objects();
+ Expression *edim = new IntegerExp(ae->loc, i, Type::tsize_t);
+ edim = expressionSemantic(edim, sc);
+ tiargs->push(edim);
+
+ Expressions *fargs = new Expressions();
+ fargs->push(ie->lwr);
+ fargs->push(ie->upr);
+
+ unsigned xerrors = global.startGagging();
+ sc = sc->push();
+ FuncDeclaration *fslice = resolveFuncCall(ae->loc, sc, slice, tiargs, ae->e1->type, fargs, 1);
+ sc = sc->pop();
+ global.endGagging(xerrors);
+ if (!fslice)
+ goto Lfallback;
+
+ e = new DotTemplateInstanceExp(ae->loc, ae->e1, slice->ident, tiargs);
+ e = new CallExp(ae->loc, e, fargs);
+ e = expressionSemantic(e, sc);
+ }
+
+ if (!e->type)
+ {
+ ae->error("%s has no value", e->toChars());
+ e = new ErrorExp();
+ }
+ if (e->op == TOKerror)
+ return e;
+
+ (*ae->arguments)[i] = e;
+ }
+
+ return ae;
+}
+
+/**************************************
+ * Runs semantic on se->lwr and se->upr. Declares a temporary variable
+ * if '$' was used.
+ */
+Expression *resolveOpDollar(Scope *sc, ArrayExp *ae, IntervalExp *ie, Expression **pe0)
+{
+ //assert(!ae->lengthVar);
+ if (!ie)
+ return ae;
+
+ VarDeclaration *lengthVar = ae->lengthVar;
+
+ // create scope for '$'
+ ArrayScopeSymbol *sym = new ArrayScopeSymbol(sc, ae);
+ sym->loc = ae->loc;
+ sym->parent = sc->scopesym;
+ sc = sc->push(sym);
+
+ for (size_t i = 0; i < 2; ++i)
+ {
+ Expression *e = i == 0 ? ie->lwr : ie->upr;
+ e = expressionSemantic(e, sc);
+ e = resolveProperties(sc, e);
+ if (!e->type)
+ {
+ ae->error("%s has no value", e->toChars());
+ return new ErrorExp();
+ }
+ (i == 0 ? ie->lwr : ie->upr) = e;
+ }
+
+ if (lengthVar != ae->lengthVar && sc->func)
+ {
+ // If $ was used, declare it now
+ Expression *de = new DeclarationExp(ae->loc, ae->lengthVar);
+ de = expressionSemantic(de, sc);
+ *pe0 = Expression::combine(*pe0, de);
+ }
+ sc = sc->pop();
+
+ return ae;
+}
+
+/******************************
+ * Perform semantic() on an array of Expressions.
+ */
+
+bool arrayExpressionSemantic(Expressions *exps, Scope *sc, bool preserveErrors)
+{
+ bool err = false;
+ if (exps)
+ {
+ for (size_t i = 0; i < exps->length; i++)
+ {
+ Expression *e = (*exps)[i];
+ if (e)
+ {
+ e = expressionSemantic(e, sc);
+ if (e->op == TOKerror)
+ err = true;
+ if (preserveErrors || e->op != TOKerror)
+ (*exps)[i] = e;
+ }
+ }
+ }
+ return err;
+}
+
+/******************************
+ * Check the tail CallExp is really property function call.
+ */
+static bool checkPropertyCall(Expression *e)
+{
+ while (e->op == TOKcomma)
+ e = ((CommaExp *)e)->e2;
+
+ if (e->op == TOKcall)
+ {
+ CallExp *ce = (CallExp *)e;
+ TypeFunction *tf;
+ if (ce->f)
+ {
+ tf = (TypeFunction *)ce->f->type;
+ /* If a forward reference to ce->f, try to resolve it
+ */
+ if (!tf->deco && ce->f->semanticRun < PASSsemanticdone)
+ {
+ dsymbolSemantic(ce->f, NULL);
+ tf = (TypeFunction *)ce->f->type;
+ }
+ }
+ else if (ce->e1->type->ty == Tfunction)
+ tf = (TypeFunction *)ce->e1->type;
+ else if (ce->e1->type->ty == Tdelegate)
+ tf = (TypeFunction *)ce->e1->type->nextOf();
+ else if (ce->e1->type->ty == Tpointer && ce->e1->type->nextOf()->ty == Tfunction)
+ tf = (TypeFunction *)ce->e1->type->nextOf();
+ else
+ assert(0);
+ }
+ return false;
+}
+
+// TODO: merge with Scope::search::searchScopes()
+static Dsymbol *searchScopes(Scope *sc, Loc loc, Identifier *ident, int flags)
+{
+ Dsymbol *s = NULL;
+ for (Scope *scx = sc; scx; scx = scx->enclosing)
+ {
+ if (!scx->scopesym)
+ continue;
+ if (scx->scopesym->isModule())
+ flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed
+ s = scx->scopesym->search(loc, ident, flags);
+ if (s)
+ {
+ // overload set contains only module scope symbols.
+ if (s->isOverloadSet())
+ break;
+ // selective/renamed imports also be picked up
+ if (AliasDeclaration *ad = s->isAliasDeclaration())
+ {
+ if (ad->_import)
+ break;
+ }
+ // See only module scope symbols for UFCS target.
+ Dsymbol *p = s->toParent2();
+ if (p && p->isModule())
+ break;
+ }
+ s = NULL;
+
+ // Stop when we hit a module, but keep going if that is not just under the global scope
+ if (scx->scopesym->isModule() && !(scx->enclosing && !scx->enclosing->enclosing))
+ break;
+ }
+ return s;
+}
+
+/******************************
+ * Find symbol in accordance with the UFCS name look up rule
+ */
+
+static Expression *searchUFCS(Scope *sc, UnaExp *ue, Identifier *ident)
+{
+ //printf("searchUFCS(ident = %s)\n", ident->toChars());
+ Loc loc = ue->loc;
+ int flags = 0;
+ Dsymbol *s = NULL;
+
+ if (sc->flags & SCOPEignoresymbolvisibility)
+ flags |= IgnoreSymbolVisibility;
+
+ // First look in local scopes
+ s = searchScopes(sc, loc, ident, flags | SearchLocalsOnly);
+ if (!s)
+ {
+ // Second look in imported modules
+ s = searchScopes(sc, loc, ident, flags | SearchImportsOnly);
+ }
+
+ if (!s)
+ return ue->e1->type->Type::getProperty(loc, ident, 0);
+
+ FuncDeclaration *f = s->isFuncDeclaration();
+ if (f)
+ {
+ TemplateDeclaration *td = getFuncTemplateDecl(f);
+ if (td)
+ {
+ if (td->overroot)
+ td = td->overroot;
+ s = td;
+ }
+ }
+
+ if (ue->op == TOKdotti)
+ {
+ DotTemplateInstanceExp *dti = (DotTemplateInstanceExp *)ue;
+ TemplateInstance *ti = new TemplateInstance(loc, s->ident);
+ ti->tiargs = dti->ti->tiargs; // for better diagnostic message
+ if (!ti->updateTempDecl(sc, s))
+ return new ErrorExp();
+ return new ScopeExp(loc, ti);
+ }
+ else
+ {
+ //printf("-searchUFCS() %s\n", s->toChars());
+ return new DsymbolExp(loc, s);
+ }
+}
+
+/******************************
+ * Pull out callable entity with UFCS.
+ */
+
+static Expression *resolveUFCS(Scope *sc, CallExp *ce)
+{
+ Loc loc = ce->loc;
+ Expression *eleft;
+ Expression *e;
+
+ if (ce->e1->op == TOKdotid)
+ {
+ DotIdExp *die = (DotIdExp *)ce->e1;
+ Identifier *ident = die->ident;
+
+ Expression *ex = semanticX(die, sc);
+ if (ex != die)
+ {
+ ce->e1 = ex;
+ return NULL;
+ }
+ eleft = die->e1;
+
+ Type *t = eleft->type->toBasetype();
+ if (t->ty == Tarray || t->ty == Tsarray ||
+ t->ty == Tnull || (t->isTypeBasic() && t->ty != Tvoid))
+ {
+ /* Built-in types and arrays have no callable properties, so do shortcut.
+ * It is necessary in: e.init()
+ */
+ }
+ else if (t->ty == Taarray)
+ {
+ if (ident == Id::remove)
+ {
+ /* Transform:
+ * aa.remove(arg) into delete aa[arg]
+ */
+ if (!ce->arguments || ce->arguments->length != 1)
+ {
+ ce->error("expected key as argument to aa.remove()");
+ return new ErrorExp();
+ }
+ if (!eleft->type->isMutable())
+ {
+ ce->error("cannot remove key from %s associative array %s",
+ MODtoChars(t->mod), eleft->toChars());
+ return new ErrorExp();
+ }
+ Expression *key = (*ce->arguments)[0];
+ key = expressionSemantic(key, sc);
+ key = resolveProperties(sc, key);
+
+ TypeAArray *taa = (TypeAArray *)t;
+ key = key->implicitCastTo(sc, taa->index);
+
+ if (key->checkValue())
+ return new ErrorExp();
+
+ semanticTypeInfo(sc, taa->index);
+
+ return new RemoveExp(loc, eleft, key);
+ }
+ }
+ else
+ {
+ if (Expression *ey = semanticY(die, sc, 1))
+ {
+ if (ey->op == TOKerror)
+ return ey;
+ ce->e1 = ey;
+ if (isDotOpDispatch(ey))
+ {
+ unsigned errors = global.startGagging();
+ e = expressionSemantic(ce->syntaxCopy(), sc);
+ if (!global.endGagging(errors))
+ return e;
+ /* fall down to UFCS */
+ }
+ else
+ return NULL;
+ }
+ }
+ e = searchUFCS(sc, die, ident);
+ }
+ else if (ce->e1->op == TOKdotti)
+ {
+ DotTemplateInstanceExp *dti = (DotTemplateInstanceExp *)ce->e1;
+ if (Expression *ey = semanticY(dti, sc, 1))
+ {
+ ce->e1 = ey;
+ return NULL;
+ }
+ eleft = dti->e1;
+ e = searchUFCS(sc, dti, dti->ti->name);
+ }
+ else
+ return NULL;
+
+ // Rewrite
+ ce->e1 = e;
+ if (!ce->arguments)
+ ce->arguments = new Expressions();
+ ce->arguments->shift(eleft);
+
+ return NULL;
+}
+
+/******************************
+ * Pull out property with UFCS.
+ */
+
+static Expression *resolveUFCSProperties(Scope *sc, Expression *e1, Expression *e2 = NULL)
+{
+ Loc loc = e1->loc;
+ Expression *eleft;
+ Expression *e;
+
+ if (e1->op == TOKdotid)
+ {
+ DotIdExp *die = (DotIdExp *)e1;
+ eleft = die->e1;
+ e = searchUFCS(sc, die, die->ident);
+ }
+ else if (e1->op == TOKdotti)
+ {
+ DotTemplateInstanceExp *dti;
+ dti = (DotTemplateInstanceExp *)e1;
+ eleft = dti->e1;
+ e = searchUFCS(sc, dti, dti->ti->name);
+ }
+ else
+ return NULL;
+
+ if (e == NULL)
+ return NULL;
+
+ // Rewrite
+ if (e2)
+ {
+ // run semantic without gagging
+ e2 = expressionSemantic(e2, sc);
+
+ /* f(e1) = e2
+ */
+ Expression *ex = e->copy();
+ Expressions *a1 = new Expressions();
+ a1->setDim(1);
+ (*a1)[0] = eleft;
+ ex = new CallExp(loc, ex, a1);
+ ex = trySemantic(ex, sc);
+
+ /* f(e1, e2)
+ */
+ Expressions *a2 = new Expressions();
+ a2->setDim(2);
+ (*a2)[0] = eleft;
+ (*a2)[1] = e2;
+ e = new CallExp(loc, e, a2);
+ if (ex)
+ { // if fallback setter exists, gag errors
+ e = trySemantic(e, sc);
+ if (!e)
+ { checkPropertyCall(ex);
+ ex = new AssignExp(loc, ex, e2);
+ return expressionSemantic(ex, sc);
+ }
+ }
+ else
+ { // strict setter prints errors if fails
+ e = expressionSemantic(e, sc);
+ }
+ checkPropertyCall(e);
+ return e;
+ }
+ else
+ {
+ /* f(e1)
+ */
+ Expressions *arguments = new Expressions();
+ arguments->setDim(1);
+ (*arguments)[0] = eleft;
+ e = new CallExp(loc, e, arguments);
+ e = expressionSemantic(e, sc);
+ checkPropertyCall(e);
+ return expressionSemantic(e, sc);
+ }
+}
+
+/******************************
+ * If e1 is a property function (template), resolve it.
+ */
+
+Expression *resolvePropertiesOnly(Scope *sc, Expression *e1)
+{
+ //printf("e1 = %s %s\n", Token::toChars(e1->op), e1->toChars());
+ OverloadSet *os;
+ FuncDeclaration *fd;
+ TemplateDeclaration *td;
+
+ if (e1->op == TOKdot)
+ {
+ DotExp *de = (DotExp *)e1;
+ if (de->e2->op == TOKoverloadset)
+ {
+ os = ((OverExp *)de->e2)->vars;
+ goto Los;
+ }
+ }
+ else if (e1->op == TOKoverloadset)
+ {
+ os = ((OverExp *)e1)->vars;
+ Los:
+ assert(os);
+ for (size_t i = 0; i < os->a.length; i++)
+ {
+ Dsymbol *s = os->a[i];
+ fd = s->isFuncDeclaration();
+ td = s->isTemplateDeclaration();
+ if (fd)
+ {
+ if (((TypeFunction *)fd->type)->isproperty)
+ return resolveProperties(sc, e1);
+ }
+ else if (td && td->onemember &&
+ (fd = td->onemember->isFuncDeclaration()) != NULL)
+ {
+ if (((TypeFunction *)fd->type)->isproperty ||
+ (fd->storage_class2 & STCproperty) ||
+ (td->_scope->stc & STCproperty))
+ {
+ return resolveProperties(sc, e1);
+ }
+ }
+ }
+ }
+ else if (e1->op == TOKdotti)
+ {
+ DotTemplateInstanceExp* dti = (DotTemplateInstanceExp *)e1;
+ if (dti->ti->tempdecl && (td = dti->ti->tempdecl->isTemplateDeclaration()) != NULL)
+ goto Ltd;
+ }
+ else if (e1->op == TOKdottd)
+ {
+ td = ((DotTemplateExp *)e1)->td;
+ goto Ltd;
+ }
+ else if (e1->op == TOKscope)
+ {
+ Dsymbol *s = ((ScopeExp *)e1)->sds;
+ TemplateInstance *ti = s->isTemplateInstance();
+ if (ti && !ti->semanticRun && ti->tempdecl)
+ {
+ if ((td = ti->tempdecl->isTemplateDeclaration()) != NULL)
+ goto Ltd;
+ }
+ }
+ else if (e1->op == TOKtemplate)
+ {
+ td = ((TemplateExp *)e1)->td;
+ Ltd:
+ assert(td);
+ if (td->onemember &&
+ (fd = td->onemember->isFuncDeclaration()) != NULL)
+ {
+ if (((TypeFunction *)fd->type)->isproperty ||
+ (fd->storage_class2 & STCproperty) ||
+ (td->_scope->stc & STCproperty))
+ {
+ return resolveProperties(sc, e1);
+ }
+ }
+ }
+ else if (e1->op == TOKdotvar && e1->type->ty == Tfunction)
+ {
+ DotVarExp *dve = (DotVarExp *)e1;
+ fd = dve->var->isFuncDeclaration();
+ goto Lfd;
+ }
+ else if (e1->op == TOKvar && e1->type->ty == Tfunction &&
+ (sc->intypeof || !((VarExp *)e1)->var->needThis()))
+ {
+ fd = ((VarExp *)e1)->var->isFuncDeclaration();
+ Lfd:
+ assert(fd);
+ if (((TypeFunction *)fd->type)->isproperty)
+ return resolveProperties(sc, e1);
+ }
+ return e1;
+}
+
+/*************************************************************
+ * Given var, we need to get the
+ * right 'this' pointer if var is in an outer class, but our
+ * existing 'this' pointer is in an inner class.
+ * Input:
+ * e1 existing 'this'
+ * ad struct or class we need the correct 'this' for
+ * var the specific member of ad we're accessing
+ */
+
+static Expression *getRightThis(Loc loc, Scope *sc, AggregateDeclaration *ad,
+ Expression *e1, Declaration *var, int flag = 0)
+{
+ //printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1->toChars(), ad->toChars(), var->toChars());
+ L1:
+ Type *t = e1->type->toBasetype();
+ //printf("e1->type = %s, var->type = %s\n", e1->type->toChars(), var->type->toChars());
+
+ /* If e1 is not the 'this' pointer for ad
+ */
+ if (ad &&
+ !(t->ty == Tpointer && t->nextOf()->ty == Tstruct &&
+ ((TypeStruct *)t->nextOf())->sym == ad)
+ &&
+ !(t->ty == Tstruct &&
+ ((TypeStruct *)t)->sym == ad)
+ )
+ {
+ ClassDeclaration *cd = ad->isClassDeclaration();
+ ClassDeclaration *tcd = t->isClassHandle();
+
+ /* e1 is the right this if ad is a base class of e1
+ */
+ if (!cd || !tcd ||
+ !(tcd == cd || cd->isBaseOf(tcd, NULL))
+ )
+ {
+ /* Only classes can be inner classes with an 'outer'
+ * member pointing to the enclosing class instance
+ */
+ if (tcd && tcd->isNested())
+ {
+ /* e1 is the 'this' pointer for an inner class: tcd.
+ * Rewrite it as the 'this' pointer for the outer class.
+ */
+
+ e1 = new DotVarExp(loc, e1, tcd->vthis);
+ e1->type = tcd->vthis->type;
+ e1->type = e1->type->addMod(t->mod);
+ // Do not call checkNestedRef()
+ //e1 = expressionSemantic(e1, sc);
+
+ // Skip up over nested functions, and get the enclosing
+ // class type.
+ int n = 0;
+ Dsymbol *s;
+ for (s = tcd->toParent();
+ s && s->isFuncDeclaration();
+ s = s->toParent())
+ {
+ FuncDeclaration *f = s->isFuncDeclaration();
+ if (f->vthis)
+ {
+ //printf("rewriting e1 to %s's this\n", f->toChars());
+ n++;
+ e1 = new VarExp(loc, f->vthis);
+ }
+ else
+ {
+ e1->error("need `this` of type %s to access member %s"
+ " from static function %s",
+ ad->toChars(), var->toChars(), f->toChars());
+ e1 = new ErrorExp();
+ return e1;
+ }
+ }
+ if (s && s->isClassDeclaration())
+ {
+ e1->type = s->isClassDeclaration()->type;
+ e1->type = e1->type->addMod(t->mod);
+ if (n > 1)
+ e1 = expressionSemantic(e1, sc);
+ }
+ else
+ e1 = expressionSemantic(e1, sc);
+ goto L1;
+ }
+
+ /* Can't find a path from e1 to ad
+ */
+ if (flag)
+ return NULL;
+ e1->error("this for %s needs to be type %s not type %s",
+ var->toChars(), ad->toChars(), t->toChars());
+ return new ErrorExp();
+ }
+ }
+ return e1;
+}
+
+/***************************************
+ * Pull out any properties.
+ */
+
+static Expression *resolvePropertiesX(Scope *sc, Expression *e1, Expression *e2 = NULL)
+{
+ //printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", Token::toChars(e1->op), e1->toChars(), e2 ? e2->toChars() : NULL);
+ Loc loc = e1->loc;
+
+ OverloadSet *os;
+ Dsymbol *s;
+ Objects *tiargs;
+ Type *tthis;
+ if (e1->op == TOKdot)
+ {
+ DotExp *de = (DotExp *)e1;
+ if (de->e2->op == TOKoverloadset)
+ {
+ tiargs = NULL;
+ tthis = de->e1->type;
+ os = ((OverExp *)de->e2)->vars;
+ goto Los;
+ }
+ }
+ else if (e1->op == TOKoverloadset)
+ {
+ tiargs = NULL;
+ tthis = NULL;
+ os = ((OverExp *)e1)->vars;
+ Los:
+ assert(os);
+ FuncDeclaration *fd = NULL;
+ if (e2)
+ {
+ e2 = expressionSemantic(e2, sc);
+ if (e2->op == TOKerror)
+ return new ErrorExp();
+ e2 = resolveProperties(sc, e2);
+
+ Expressions a;
+ a.push(e2);
+
+ for (size_t i = 0; i < os->a.length; i++)
+ {
+ FuncDeclaration *f = resolveFuncCall(loc, sc, os->a[i], tiargs, tthis, &a, 1);
+ if (f)
+ {
+ if (f->errors)
+ return new ErrorExp();
+ fd = f;
+ assert(fd->type->ty == Tfunction);
+ }
+ }
+ if (fd)
+ {
+ Expression *e = new CallExp(loc, e1, e2);
+ return expressionSemantic(e, sc);
+ }
+ }
+ {
+ for (size_t i = 0; i < os->a.length; i++)
+ {
+ FuncDeclaration *f = resolveFuncCall(loc, sc, os->a[i], tiargs, tthis, NULL, 1);
+ if (f)
+ {
+ if (f->errors)
+ return new ErrorExp();
+ fd = f;
+ assert(fd->type->ty == Tfunction);
+ TypeFunction *tf = (TypeFunction *)fd->type;
+ if (!tf->isref && e2)
+ goto Leproplvalue;
+ }
+ }
+ if (fd)
+ {
+ Expression *e = new CallExp(loc, e1);
+ if (e2)
+ e = new AssignExp(loc, e, e2);
+ return expressionSemantic(e, sc);
+ }
+ }
+ if (e2)
+ goto Leprop;
+ }
+ else if (e1->op == TOKdotti)
+ {
+ DotTemplateInstanceExp* dti = (DotTemplateInstanceExp *)e1;
+ if (!dti->findTempDecl(sc))
+ goto Leprop;
+ if (!dti->ti->semanticTiargs(sc))
+ goto Leprop;
+ tiargs = dti->ti->tiargs;
+ tthis = dti->e1->type;
+ if ((os = dti->ti->tempdecl->isOverloadSet()) != NULL)
+ goto Los;
+ if ((s = dti->ti->tempdecl) != NULL)
+ goto Lfd;
+ }
+ else if (e1->op == TOKdottd)
+ {
+ DotTemplateExp *dte = (DotTemplateExp *)e1;
+ s = dte->td;
+ tiargs = NULL;
+ tthis = dte->e1->type;
+ goto Lfd;
+ }
+ else if (e1->op == TOKscope)
+ {
+ s = ((ScopeExp *)e1)->sds;
+ TemplateInstance *ti = s->isTemplateInstance();
+ if (ti && !ti->semanticRun && ti->tempdecl)
+ {
+ //assert(ti->needsTypeInference(sc));
+ if (!ti->semanticTiargs(sc))
+ goto Leprop;
+ tiargs = ti->tiargs;
+ tthis = NULL;
+ if ((os = ti->tempdecl->isOverloadSet()) != NULL)
+ goto Los;
+ if ((s = ti->tempdecl) != NULL)
+ goto Lfd;
+ }
+ }
+ else if (e1->op == TOKtemplate)
+ {
+ s = ((TemplateExp *)e1)->td;
+ tiargs = NULL;
+ tthis = NULL;
+ goto Lfd;
+ }
+ else if (e1->op == TOKdotvar && e1->type && e1->type->toBasetype()->ty == Tfunction)
+ {
+ DotVarExp *dve = (DotVarExp *)e1;
+ s = dve->var->isFuncDeclaration();
+ tiargs = NULL;
+ tthis = dve->e1->type;
+ goto Lfd;
+ }
+ else if (e1->op == TOKvar && e1->type && e1->type->toBasetype()->ty == Tfunction)
+ {
+ s = ((VarExp *)e1)->var->isFuncDeclaration();
+ tiargs = NULL;
+ tthis = NULL;
+ Lfd:
+ assert(s);
+ if (e2)
+ {
+ e2 = expressionSemantic(e2, sc);
+ if (e2->op == TOKerror)
+ return new ErrorExp();
+ e2 = resolveProperties(sc, e2);
+
+ Expressions a;
+ a.push(e2);
+
+ FuncDeclaration *fd = resolveFuncCall(loc, sc, s, tiargs, tthis, &a, 1);
+ if (fd && fd->type)
+ {
+ if (fd->errors)
+ return new ErrorExp();
+ assert(fd->type->ty == Tfunction);
+ Expression *e = new CallExp(loc, e1, e2);
+ return expressionSemantic(e, sc);
+ }
+ }
+ {
+ FuncDeclaration *fd = resolveFuncCall(loc, sc, s, tiargs, tthis, NULL, 1);
+ if (fd && fd->type)
+ {
+ if (fd->errors)
+ return new ErrorExp();
+ assert(fd->type->ty == Tfunction);
+ TypeFunction *tf = (TypeFunction *)fd->type;
+ if (!e2 || tf->isref)
+ {
+ Expression *e = new CallExp(loc, e1);
+ if (e2)
+ e = new AssignExp(loc, e, e2);
+ return expressionSemantic(e, sc);
+ }
+ }
+ }
+ if (FuncDeclaration *fd = s->isFuncDeclaration())
+ {
+ // Keep better diagnostic message for invalid property usage of functions
+ assert(fd->type->ty == Tfunction);
+ Expression *e = new CallExp(loc, e1, e2);
+ return expressionSemantic(e, sc);
+ }
+ if (e2)
+ goto Leprop;
+ }
+ if (e1->op == TOKvar)
+ {
+ VarExp *ve = (VarExp *)e1;
+ VarDeclaration *v = ve->var->isVarDeclaration();
+ if (v && ve->checkPurity(sc, v))
+ return new ErrorExp();
+ }
+ if (e2)
+ return NULL;
+
+ if (e1->type &&
+ e1->op != TOKtype) // function type is not a property
+ {
+ /* Look for e1 being a lazy parameter; rewrite as delegate call
+ */
+ if (e1->op == TOKvar)
+ {
+ VarExp *ve = (VarExp *)e1;
+
+ if (ve->var->storage_class & STClazy)
+ {
+ Expression *e = new CallExp(loc, e1);
+ return expressionSemantic(e, sc);
+ }
+ }
+ else if (e1->op == TOKdotvar)
+ {
+ // Check for reading overlapped pointer field in @safe code.
+ if (checkUnsafeAccess(sc, e1, true, true))
+ return new ErrorExp();
+ }
+ else if (e1->op == TOKdot)
+ {
+ e1->error("expression has no value");
+ return new ErrorExp();
+ }
+ else if (e1->op == TOKcall)
+ {
+ CallExp *ce = (CallExp *)e1;
+ // Check for reading overlapped pointer field in @safe code.
+ if (checkUnsafeAccess(sc, ce->e1, true, true))
+ return new ErrorExp();
+ }
+ }
+
+ if (!e1->type)
+ {
+ error(loc, "cannot resolve type for %s", e1->toChars());
+ e1 = new ErrorExp();
+ }
+ return e1;
+
+Leprop:
+ error(loc, "not a property %s", e1->toChars());
+ return new ErrorExp();
+
+Leproplvalue:
+ error(loc, "%s is not an lvalue", e1->toChars());
+ return new ErrorExp();
+}
+
+Expression *resolveProperties(Scope *sc, Expression *e)
+{
+ //printf("resolveProperties(%s)\n", e->toChars());
+
+ e = resolvePropertiesX(sc, e);
+ if (e->checkRightThis(sc))
+ return new ErrorExp();
+ return e;
+}
+
+/****************************************
+ * The common type is determined by applying ?: to each pair.
+ * Output:
+ * exps[] properties resolved, implicitly cast to common type, rewritten in place
+ * *pt if pt is not NULL, set to the common type
+ * Returns:
+ * true a semantic error was detected
+ */
+
+static bool arrayExpressionToCommonType(Scope *sc, Expressions *exps, Type **pt)
+{
+ /* Still have a problem with:
+ * ubyte[][] = [ cast(ubyte[])"hello", [1]];
+ * which works if the array literal is initialized top down with the ubyte[][]
+ * type, but fails with this function doing bottom up typing.
+ */
+ //printf("arrayExpressionToCommonType()\n");
+ IntegerExp integerexp(0);
+ CondExp condexp(Loc(), &integerexp, NULL, NULL);
+
+ Type *t0 = NULL;
+ Expression *e0 = NULL; // dead-store to prevent spurious warning
+ size_t j0 = ~0; // dead-store to prevent spurious warning
+ bool foundType = false;
+
+ for (size_t i = 0; i < exps->length; i++)
+ {
+ Expression *e = (*exps)[i];
+ if (!e)
+ continue;
+
+ e = resolveProperties(sc, e);
+ if (!e->type)
+ {
+ e->error("%s has no value", e->toChars());
+ t0 = Type::terror;
+ continue;
+ }
+ if (e->op == TOKtype)
+ {
+ foundType = true; // do not break immediately, there might be more errors
+ e->checkValue(); // report an error "type T has no value"
+ t0 = Type::terror;
+ continue;
+ }
+ if (e->type->ty == Tvoid)
+ {
+ // void expressions do not concur to the determination of the common
+ // type.
+ continue;
+ }
+ if (checkNonAssignmentArrayOp(e))
+ {
+ t0 = Type::terror;
+ continue;
+ }
+
+ e = doCopyOrMove(sc, e);
+
+ if (!foundType && t0 && !t0->equals(e->type))
+ {
+ /* This applies ?: to merge the types. It's backwards;
+ * ?: should call this function to merge types.
+ */
+ condexp.type = NULL;
+ condexp.e1 = e0;
+ condexp.e2 = e;
+ condexp.loc = e->loc;
+ Expression *ex = expressionSemantic(&condexp, sc);
+ if (ex->op == TOKerror)
+ e = ex;
+ else
+ {
+ (*exps)[j0] = condexp.e1;
+ e = condexp.e2;
+ }
+ }
+ j0 = i;
+ e0 = e;
+ t0 = e->type;
+ if (e->op != TOKerror)
+ (*exps)[i] = e;
+ }
+
+ if (!t0)
+ t0 = Type::tvoid; // [] is typed as void[]
+ else if (t0->ty != Terror)
+ {
+ for (size_t i = 0; i < exps->length; i++)
+ {
+ Expression *e = (*exps)[i];
+ if (!e)
+ continue;
+
+ e = e->implicitCastTo(sc, t0);
+ //assert(e->op != TOKerror);
+ if (e->op == TOKerror)
+ {
+ /* Bugzilla 13024: a workaround for the bug in typeMerge -
+ * it should paint e1 and e2 by deduced common type,
+ * but doesn't in this particular case.
+ */
+ t0 = Type::terror;
+ break;
+ }
+ (*exps)[i] = e;
+ }
+ }
+ if (pt)
+ *pt = t0;
+
+ return (t0 == Type::terror);
+}
+
+static Expression *opAssignToOp(Loc loc, TOK op, Expression *e1, Expression *e2)
+{ Expression *e;
+
+ switch (op)
+ {
+ case TOKaddass: e = new AddExp(loc, e1, e2); break;
+ case TOKminass: e = new MinExp(loc, e1, e2); break;
+ case TOKmulass: e = new MulExp(loc, e1, e2); break;
+ case TOKdivass: e = new DivExp(loc, e1, e2); break;
+ case TOKmodass: e = new ModExp(loc, e1, e2); break;
+ case TOKandass: e = new AndExp(loc, e1, e2); break;
+ case TOKorass: e = new OrExp (loc, e1, e2); break;
+ case TOKxorass: e = new XorExp(loc, e1, e2); break;
+ case TOKshlass: e = new ShlExp(loc, e1, e2); break;
+ case TOKshrass: e = new ShrExp(loc, e1, e2); break;
+ case TOKushrass: e = new UshrExp(loc, e1, e2); break;
+ default: assert(0);
+ }
+ return e;
+}
+
+/*********************
+ * Rewrite:
+ * array.length op= e2
+ * as:
+ * array.length = array.length op e2
+ * or:
+ * auto tmp = &array;
+ * (*tmp).length = (*tmp).length op e2
+ */
+
+static Expression *rewriteOpAssign(BinExp *exp)
+{
+ Expression *e;
+
+ assert(exp->e1->op == TOKarraylength);
+ ArrayLengthExp *ale = (ArrayLengthExp *)exp->e1;
+ if (ale->e1->op == TOKvar)
+ {
+ e = opAssignToOp(exp->loc, exp->op, ale, exp->e2);
+ e = new AssignExp(exp->loc, ale->syntaxCopy(), e);
+ }
+ else
+ {
+ /* auto tmp = &array;
+ * (*tmp).length = (*tmp).length op e2
+ */
+ VarDeclaration *tmp = copyToTemp(0, "__arraylength", new AddrExp(ale->loc, ale->e1));
+
+ Expression *e1 = new ArrayLengthExp(ale->loc, new PtrExp(ale->loc, new VarExp(ale->loc, tmp)));
+ Expression *elvalue = e1->syntaxCopy();
+ e = opAssignToOp(exp->loc, exp->op, e1, exp->e2);
+ e = new AssignExp(exp->loc, elvalue, e);
+ e = new CommaExp(exp->loc, new DeclarationExp(ale->loc, tmp), e);
+ }
+ return e;
+}
/****************************************
* Preprocess arguments to function.
@@ -111,6 +1337,695 @@ static bool preFunctionParameters(Scope *sc, Expressions *exps)
return err;
}
+/********************************************
+ * Issue an error if default construction is disabled for type t.
+ * Default construction is required for arrays and 'out' parameters.
+ * Returns:
+ * true an error was issued
+ */
+static bool checkDefCtor(Loc loc, Type *t)
+{
+ t = t->baseElemOf();
+ if (t->ty == Tstruct)
+ {
+ StructDeclaration *sd = ((TypeStruct *)t)->sym;
+ if (sd->noDefaultCtor)
+ {
+ sd->error(loc, "default construction is disabled");
+ return true;
+ }
+ }
+ return false;
+}
+
+/****************************************
+ * Now that we know the exact type of the function we're calling,
+ * the arguments[] need to be adjusted:
+ * 1. implicitly convert argument to the corresponding parameter type
+ * 2. add default arguments for any missing arguments
+ * 3. do default promotions on arguments corresponding to ...
+ * 4. add hidden _arguments[] argument
+ * 5. call copy constructor for struct value arguments
+ * Input:
+ * tf type of the function
+ * fd the function being called, NULL if called indirectly
+ * Output:
+ * *prettype return type of function
+ * *peprefix expression to execute before arguments[] are evaluated, NULL if none
+ * Returns:
+ * true errors happened
+ */
+
+static bool functionParameters(Loc loc, Scope *sc, TypeFunction *tf,
+ Type *tthis, Expressions *arguments, FuncDeclaration *fd, Type **prettype, Expression **peprefix)
+{
+ //printf("functionParameters()\n");
+ assert(arguments);
+ assert(fd || tf->next);
+ size_t nargs = arguments ? arguments->length : 0;
+ size_t nparams = tf->parameterList.length();
+ unsigned olderrors = global.errors;
+ bool err = false;
+ *prettype = Type::terror;
+ Expression *eprefix = NULL;
+ *peprefix = NULL;
+
+ if (nargs > nparams && tf->parameterList.varargs == VARARGnone)
+ {
+ error(loc, "expected %llu arguments, not %llu for non-variadic function type %s", (ulonglong)nparams, (ulonglong)nargs, tf->toChars());
+ return true;
+ }
+
+ // If inferring return type, and semantic3() needs to be run if not already run
+ if (!tf->next && fd->inferRetType)
+ {
+ fd->functionSemantic();
+ }
+ else if (fd && fd->parent)
+ {
+ TemplateInstance *ti = fd->parent->isTemplateInstance();
+ if (ti && ti->tempdecl)
+ {
+ fd->functionSemantic3();
+ }
+ }
+ bool isCtorCall = fd && fd->needThis() && fd->isCtorDeclaration();
+
+ size_t n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams)
+
+ /* If the function return type has wildcards in it, we'll need to figure out the actual type
+ * based on the actual argument types.
+ */
+ MOD wildmatch = 0;
+ if (tthis && tf->isWild() && !isCtorCall)
+ {
+ Type *t = tthis;
+ if (t->isImmutable())
+ wildmatch = MODimmutable;
+ else if (t->isWildConst())
+ wildmatch = MODwildconst;
+ else if (t->isWild())
+ wildmatch = MODwild;
+ else if (t->isConst())
+ wildmatch = MODconst;
+ else
+ wildmatch = MODmutable;
+ }
+
+ int done = 0;
+ for (size_t i = 0; i < n; i++)
+ {
+ Expression *arg;
+
+ if (i < nargs)
+ arg = (*arguments)[i];
+ else
+ arg = NULL;
+
+ if (i < nparams)
+ {
+ Parameter *p = tf->parameterList[i];
+
+ if (!arg)
+ {
+ if (!p->defaultArg)
+ {
+ if (tf->parameterList.varargs == VARARGtypesafe && i + 1 == nparams)
+ goto L2;
+ error(loc, "expected %llu function arguments, not %llu", (ulonglong)nparams, (ulonglong)nargs);
+ return true;
+ }
+ arg = p->defaultArg;
+ arg = inlineCopy(arg, sc);
+ // __FILE__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__
+ arg = arg->resolveLoc(loc, sc);
+ arguments->push(arg);
+ nargs++;
+ }
+
+ if (tf->parameterList.varargs == VARARGtypesafe && i + 1 == nparams)
+ {
+ //printf("\t\tvarargs == 2, p->type = '%s'\n", p->type->toChars());
+ {
+ MATCH m;
+ if ((m = arg->implicitConvTo(p->type)) > MATCHnomatch)
+ {
+ if (p->type->nextOf() && arg->implicitConvTo(p->type->nextOf()) >= m)
+ goto L2;
+ else if (nargs != nparams)
+ { error(loc, "expected %llu function arguments, not %llu", (ulonglong)nparams, (ulonglong)nargs);
+ return true;
+ }
+ goto L1;
+ }
+ }
+ L2:
+ Type *tb = p->type->toBasetype();
+ Type *tret = p->isLazyArray();
+ switch (tb->ty)
+ {
+ case Tsarray:
+ case Tarray:
+ {
+ /* Create a static array variable v of type arg->type:
+ * T[dim] __arrayArg = [ arguments[i], ..., arguments[nargs-1] ];
+ *
+ * The array literal in the initializer of the hidden variable
+ * is now optimized. See Bugzilla 2356.
+ */
+ Type *tbn = ((TypeArray *)tb)->next;
+
+ Expressions *elements = new Expressions();
+ elements->setDim(nargs - i);
+ for (size_t u = 0; u < elements->length; u++)
+ {
+ Expression *a = (*arguments)[i + u];
+ if (tret && a->implicitConvTo(tret))
+ {
+ a = a->implicitCastTo(sc, tret);
+ a = a->optimize(WANTvalue);
+ a = toDelegate(a, a->type, sc);
+ }
+ else
+ a = a->implicitCastTo(sc, tbn);
+ (*elements)[u] = a;
+ }
+ // Bugzilla 14395: Convert to a static array literal, or its slice.
+ arg = new ArrayLiteralExp(loc, tbn->sarrayOf(nargs - i), elements);
+ if (tb->ty == Tarray)
+ {
+ arg = new SliceExp(loc, arg, NULL, NULL);
+ arg->type = p->type;
+ }
+ break;
+ }
+ case Tclass:
+ {
+ /* Set arg to be:
+ * new Tclass(arg0, arg1, ..., argn)
+ */
+ Expressions *args = new Expressions();
+ args->setDim(nargs - i);
+ for (size_t u = i; u < nargs; u++)
+ (*args)[u - i] = (*arguments)[u];
+ arg = new NewExp(loc, NULL, NULL, p->type, args);
+ break;
+ }
+ default:
+ if (!arg)
+ {
+ error(loc, "not enough arguments");
+ return true;
+ }
+ break;
+ }
+ arg = expressionSemantic(arg, sc);
+ //printf("\targ = '%s'\n", arg->toChars());
+ arguments->setDim(i + 1);
+ (*arguments)[i] = arg;
+ nargs = i + 1;
+ done = 1;
+ }
+
+ L1:
+ if (!(p->storageClass & STClazy && p->type->ty == Tvoid))
+ {
+ bool isRef = (p->storageClass & (STCref | STCout)) != 0;
+ if (unsigned char wm = arg->type->deduceWild(p->type, isRef))
+ {
+ if (wildmatch)
+ wildmatch = MODmerge(wildmatch, wm);
+ else
+ wildmatch = wm;
+ //printf("[%d] p = %s, a = %s, wm = %d, wildmatch = %d\n", i, p->type->toChars(), arg->type->toChars(), wm, wildmatch);
+ }
+ }
+ }
+ if (done)
+ break;
+ }
+ if ((wildmatch == MODmutable || wildmatch == MODimmutable) &&
+ tf->next->hasWild() &&
+ (tf->isref || !tf->next->implicitConvTo(tf->next->immutableOf())))
+ {
+ if (fd)
+ {
+ /* If the called function may return the reference to
+ * outer inout data, it should be rejected.
+ *
+ * void foo(ref inout(int) x) {
+ * ref inout(int) bar(inout(int)) { return x; }
+ * struct S { ref inout(int) bar() inout { return x; } }
+ * bar(int.init) = 1; // bad!
+ * S().bar() = 1; // bad!
+ * }
+ */
+ Dsymbol *s = NULL;
+ if (fd->isThis() || fd->isNested())
+ s = fd->toParent2();
+ for (; s; s = s->toParent2())
+ {
+ if (AggregateDeclaration *ad = s->isAggregateDeclaration())
+ {
+ if (ad->isNested())
+ continue;
+ break;
+ }
+ if (FuncDeclaration *ff = s->isFuncDeclaration())
+ {
+ if (((TypeFunction *)ff->type)->iswild)
+ goto Linouterr;
+
+ if (ff->isNested() || ff->isThis())
+ continue;
+ }
+ break;
+ }
+ }
+ else if (tf->isWild())
+ {
+ Linouterr:
+ const char *s = wildmatch == MODmutable ? "mutable" : MODtoChars(wildmatch);
+ error(loc, "modify inout to %s is not allowed inside inout function", s);
+ return true;
+ }
+ }
+
+ assert(nargs >= nparams);
+ for (size_t i = 0; i < nargs; i++)
+ {
+ Expression *arg = (*arguments)[i];
+ assert(arg);
+ if (i < nparams)
+ {
+ Parameter *p = tf->parameterList[i];
+
+ if (!(p->storageClass & STClazy && p->type->ty == Tvoid))
+ {
+ Type *tprm = p->type;
+ if (p->type->hasWild())
+ tprm = p->type->substWildTo(wildmatch);
+ if (!tprm->equals(arg->type))
+ {
+ //printf("arg->type = %s, p->type = %s\n", arg->type->toChars(), p->type->toChars());
+ arg = arg->implicitCastTo(sc, tprm);
+ arg = arg->optimize(WANTvalue, (p->storageClass & (STCref | STCout)) != 0);
+ }
+ }
+ if (p->storageClass & STCref)
+ {
+ arg = arg->toLvalue(sc, arg);
+
+ // Look for mutable misaligned pointer, etc., in @safe mode
+ err |= checkUnsafeAccess(sc, arg, false, true);
+ }
+ else if (p->storageClass & STCout)
+ {
+ Type *t = arg->type;
+ if (!t->isMutable() || !t->isAssignable()) // check blit assignable
+ {
+ arg->error("cannot modify struct %s with immutable members", arg->toChars());
+ err = true;
+ }
+ else
+ {
+ // Look for misaligned pointer, etc., in @safe mode
+ err |= checkUnsafeAccess(sc, arg, false, true);
+ err |= checkDefCtor(arg->loc, t); // t must be default constructible
+ }
+ arg = arg->toLvalue(sc, arg);
+ }
+ else if (p->storageClass & STClazy)
+ {
+ // Convert lazy argument to a delegate
+ if (p->type->ty == Tvoid)
+ arg = toDelegate(arg, p->type, sc);
+ else
+ arg = toDelegate(arg, arg->type, sc);
+ }
+
+ //printf("arg: %s\n", arg->toChars());
+ //printf("type: %s\n", arg->type->toChars());
+ if (tf->parameterEscapes(p))
+ {
+ /* Argument value can escape from the called function.
+ * Check arg to see if it matters.
+ */
+ if (global.params.vsafe)
+ err |= checkParamArgumentEscape(sc, fd, p->ident, arg, false);
+ }
+ else
+ {
+ /* Argument value cannot escape from the called function.
+ */
+ Expression *a = arg;
+ if (a->op == TOKcast)
+ a = ((CastExp *)a)->e1;
+
+ if (a->op == TOKfunction)
+ {
+ /* Function literals can only appear once, so if this
+ * appearance was scoped, there cannot be any others.
+ */
+ FuncExp *fe = (FuncExp *)a;
+ fe->fd->tookAddressOf = 0;
+ }
+ else if (a->op == TOKdelegate)
+ {
+ /* For passing a delegate to a scoped parameter,
+ * this doesn't count as taking the address of it.
+ * We only worry about 'escaping' references to the function.
+ */
+ DelegateExp *de = (DelegateExp *)a;
+ if (de->e1->op == TOKvar)
+ { VarExp *ve = (VarExp *)de->e1;
+ FuncDeclaration *f = ve->var->isFuncDeclaration();
+ if (f)
+ { f->tookAddressOf--;
+ //printf("tookAddressOf = %d\n", f->tookAddressOf);
+ }
+ }
+ }
+ }
+ arg = arg->optimize(WANTvalue, (p->storageClass & (STCref | STCout)) != 0);
+ }
+ else
+ {
+ // These will be the trailing ... arguments
+
+ // If not D linkage, do promotions
+ if (tf->linkage != LINKd)
+ {
+ // Promote bytes, words, etc., to ints
+ arg = integralPromotions(arg, sc);
+
+ // Promote floats to doubles
+ switch (arg->type->ty)
+ {
+ case Tfloat32:
+ arg = arg->castTo(sc, Type::tfloat64);
+ break;
+
+ case Timaginary32:
+ arg = arg->castTo(sc, Type::timaginary64);
+ break;
+ }
+
+ if (tf->parameterList.varargs == VARARGvariadic)
+ {
+ const char *p = tf->linkage == LINKc ? "extern(C)" : "extern(C++)";
+ if (arg->type->ty == Tarray)
+ {
+ arg->error("cannot pass dynamic arrays to %s vararg functions", p);
+ err = true;
+ }
+ if (arg->type->ty == Tsarray)
+ {
+ arg->error("cannot pass static arrays to %s vararg functions", p);
+ err = true;
+ }
+ }
+ }
+
+ // Do not allow types that need destructors
+ if (arg->type->needsDestruction())
+ {
+ arg->error("cannot pass types that need destruction as variadic arguments");
+ err = true;
+ }
+
+ // Convert static arrays to dynamic arrays
+ // BUG: I don't think this is right for D2
+ Type *tb = arg->type->toBasetype();
+ if (tb->ty == Tsarray)
+ {
+ TypeSArray *ts = (TypeSArray *)tb;
+ Type *ta = ts->next->arrayOf();
+ if (ts->size(arg->loc) == 0)
+ arg = new NullExp(arg->loc, ta);
+ else
+ arg = arg->castTo(sc, ta);
+ }
+ if (tb->ty == Tstruct)
+ {
+ //arg = callCpCtor(sc, arg);
+ }
+
+ // Give error for overloaded function addresses
+ if (arg->op == TOKsymoff)
+ { SymOffExp *se = (SymOffExp *)arg;
+ if (se->hasOverloads &&
+ !se->var->isFuncDeclaration()->isUnique())
+ { arg->error("function %s is overloaded", arg->toChars());
+ err = true;
+ }
+ }
+ if (arg->checkValue())
+ err = true;
+ arg = arg->optimize(WANTvalue);
+ }
+ (*arguments)[i] = arg;
+ }
+
+ /* If calling C scanf(), printf(), or any variants, check the format string against the arguments
+ */
+ const bool isVa_list = tf->parameterList.varargs == VARARGnone;
+ if (fd && (fd->flags & FUNCFLAGprintf))
+ {
+ if (StringExp *se = (*arguments)[nparams - 1 - isVa_list]->isStringExp())
+ {
+ Expressions argslice;
+ argslice.reserve(nargs - nparams);
+ for (size_t i = nparams; i < nargs; i++)
+ argslice.push((*arguments)[i]);
+ checkPrintfFormat(se->loc, se->toPtr(), argslice, isVa_list);
+ }
+ }
+ else if (fd && (fd->flags & FUNCFLAGscanf))
+ {
+ if (StringExp *se = (*arguments)[nparams - 1 - isVa_list]->isStringExp())
+ {
+ Expressions argslice;
+ argslice.reserve(nargs - nparams);
+ for (size_t i = nparams; i < nargs; i++)
+ argslice.push((*arguments)[i]);
+ checkPrintfFormat(se->loc, se->toPtr(), argslice, isVa_list);
+ }
+ }
+
+ /* Remaining problems:
+ * 1. order of evaluation - some function push L-to-R, others R-to-L. Until we resolve what array assignment does (which is
+ * implemented by calling a function) we'll defer this for now.
+ * 2. value structs (or static arrays of them) that need to be copy constructed
+ * 3. value structs (or static arrays of them) that have destructors, and subsequent arguments that may throw before the
+ * function gets called (functions normally destroy their parameters)
+ * 2 and 3 are handled by doing the argument construction in 'eprefix' so that if a later argument throws, they are cleaned
+ * up properly. Pushing arguments on the stack then cannot fail.
+ */
+ if (1)
+ {
+ /* TODO: tackle problem 1)
+ */
+ const bool leftToRight = true; // TODO: something like !fd.isArrayOp
+ if (!leftToRight)
+ assert(nargs == nparams); // no variadics for RTL order, as they would probably be evaluated LTR and so add complexity
+
+ const ptrdiff_t start = (leftToRight ? 0 : (ptrdiff_t)nargs - 1);
+ const ptrdiff_t end = (leftToRight ? (ptrdiff_t)nargs : -1);
+ const ptrdiff_t step = (leftToRight ? 1 : -1);
+
+ /* Compute indices of last throwing argument and first arg needing destruction.
+ * Used to not set up destructors unless an arg needs destruction on a throw
+ * in a later argument.
+ */
+ ptrdiff_t lastthrow = -1;
+ ptrdiff_t firstdtor = -1;
+ for (ptrdiff_t i = start; i != end; i += step)
+ {
+ Expression *arg = (*arguments)[i];
+ if (canThrow(arg, sc->func, false))
+ lastthrow = i;
+ if (firstdtor == -1 && arg->type->needsDestruction())
+ {
+ Parameter *p = (i >= (ptrdiff_t)nparams ? NULL : tf->parameterList[i]);
+ if (!(p && (p->storageClass & (STClazy | STCref | STCout))))
+ firstdtor = i;
+ }
+ }
+
+ /* Does problem 3) apply to this call?
+ */
+ const bool needsPrefix = (firstdtor >= 0 && lastthrow >= 0
+ && (lastthrow - firstdtor) * step > 0);
+
+ /* If so, initialize 'eprefix' by declaring the gate
+ */
+ VarDeclaration *gate = NULL;
+ if (needsPrefix)
+ {
+ // eprefix => bool __gate [= false]
+ Identifier *idtmp = Identifier::generateId("__gate");
+ gate = new VarDeclaration(loc, Type::tbool, idtmp, NULL);
+ gate->storage_class |= STCtemp | STCctfe | STCvolatile;
+ dsymbolSemantic(gate, sc);
+
+ Expression *ae = new DeclarationExp(loc, gate);
+ eprefix = expressionSemantic(ae, sc);
+ }
+
+ for (ptrdiff_t i = start; i != end; i += step)
+ {
+ Expression *arg = (*arguments)[i];
+
+ Parameter *parameter = (i >= (ptrdiff_t)nparams ? NULL : tf->parameterList[i]);
+ const bool isRef = (parameter && (parameter->storageClass & (STCref | STCout)));
+ const bool isLazy = (parameter && (parameter->storageClass & STClazy));
+
+ /* Skip lazy parameters
+ */
+ if (isLazy)
+ continue;
+
+ /* Do we have a gate? Then we have a prefix and we're not yet past the last throwing arg.
+ * Declare a temporary variable for this arg and append that declaration to 'eprefix',
+ * which will implicitly take care of potential problem 2) for this arg.
+ * 'eprefix' will therefore finally contain all args up to and including the last
+ * potentially throwing arg, excluding all lazy parameters.
+ */
+ if (gate)
+ {
+ const bool needsDtor = (!isRef && arg->type->needsDestruction() && i != lastthrow);
+
+ /* Declare temporary 'auto __pfx = arg' (needsDtor) or 'auto __pfy = arg' (!needsDtor)
+ */
+ VarDeclaration *tmp = copyToTemp(0,
+ needsDtor ? "__pfx" : "__pfy",
+ !isRef ? arg : arg->addressOf());
+ dsymbolSemantic(tmp, sc);
+
+ /* Modify the destructor so it only runs if gate==false, i.e.,
+ * only if there was a throw while constructing the args
+ */
+ if (!needsDtor)
+ {
+ if (tmp->edtor)
+ {
+ assert(i == lastthrow);
+ tmp->edtor = NULL;
+ }
+ }
+ else
+ {
+ // edtor => (__gate || edtor)
+ assert(tmp->edtor);
+ Expression *e = tmp->edtor;
+ e = new LogicalExp(e->loc, TOKoror, new VarExp(e->loc, gate), e);
+ tmp->edtor = expressionSemantic(e, sc);
+ //printf("edtor: %s\n", tmp->edtor->toChars());
+ }
+
+ // eprefix => (eprefix, auto __pfx/y = arg)
+ DeclarationExp *ae = new DeclarationExp(loc, tmp);
+ eprefix = Expression::combine(eprefix, expressionSemantic(ae, sc));
+
+ // arg => __pfx/y
+ arg = new VarExp(loc, tmp);
+ arg = expressionSemantic(arg, sc);
+ if (isRef)
+ {
+ arg = new PtrExp(loc, arg);
+ arg = expressionSemantic(arg, sc);
+ }
+
+ /* Last throwing arg? Then finalize eprefix => (eprefix, gate = true),
+ * i.e., disable the dtors right after constructing the last throwing arg.
+ * From now on, the callee will take care of destructing the args because
+ * the args are implicitly moved into function parameters.
+ *
+ * Set gate to null to let the next iterations know they don't need to
+ * append to eprefix anymore.
+ */
+ if (i == lastthrow)
+ {
+ Expression *e = new AssignExp(gate->loc, new VarExp(gate->loc, gate), new IntegerExp(gate->loc, 1, Type::tbool));
+ eprefix = Expression::combine(eprefix, expressionSemantic(e, sc));
+ gate = NULL;
+ }
+ }
+ else
+ {
+ /* No gate, no prefix to append to.
+ * Handle problem 2) by calling the copy constructor for value structs
+ * (or static arrays of them) if appropriate.
+ */
+ Type *tv = arg->type->baseElemOf();
+ if (!isRef && tv->ty == Tstruct)
+ arg = doCopyOrMove(sc, arg);
+ }
+
+ (*arguments)[i] = arg;
+ }
+ }
+ //if (eprefix) printf("eprefix: %s\n", eprefix->toChars());
+
+ // If D linkage and variadic, add _arguments[] as first argument
+ if (tf->isDstyleVariadic())
+ {
+ assert(arguments->length >= nparams);
+
+ Parameters *args = new Parameters;
+ args->setDim(arguments->length - nparams);
+ for (size_t i = 0; i < arguments->length - nparams; i++)
+ {
+ Parameter *arg = new Parameter(STCin, (*arguments)[nparams + i]->type, NULL, NULL, NULL);
+ (*args)[i] = arg;
+ }
+
+ TypeTuple *tup = new TypeTuple(args);
+ Expression *e = new TypeidExp(loc, tup);
+ e = expressionSemantic(e, sc);
+ arguments->insert(0, e);
+ }
+
+ Type *tret = tf->next;
+ if (isCtorCall)
+ {
+ //printf("[%s] fd = %s %s, %d %d %d\n", loc.toChars(), fd->toChars(), fd->type->toChars(),
+ // wildmatch, tf->isWild(), fd->isolateReturn());
+ if (!tthis)
+ {
+ assert(sc->intypeof || global.errors);
+ tthis = fd->isThis()->type->addMod(fd->type->mod);
+ }
+ if (tf->isWild() && !fd->isolateReturn())
+ {
+ if (wildmatch)
+ tret = tret->substWildTo(wildmatch);
+ int offset;
+ if (!tret->implicitConvTo(tthis) &&
+ !(MODimplicitConv(tret->mod, tthis->mod) && tret->isBaseOf(tthis, &offset) && offset == 0))
+ {
+ const char* s1 = tret ->isNaked() ? " mutable" : tret ->modToChars();
+ const char* s2 = tthis->isNaked() ? " mutable" : tthis->modToChars();
+ ::error(loc, "inout constructor %s creates%s object, not%s",
+ fd->toPrettyChars(), s1, s2);
+ err = true;
+ }
+ }
+ tret = tthis;
+ }
+ else if (wildmatch && tret)
+ {
+ /* Adjust function return type based on wildmatch
+ */
+ //printf("wildmatch = x%x, tret = %s\n", wildmatch, tret->toChars());
+ tret = tret->substWildTo(wildmatch);
+ }
+ *prettype = tret;
+ *peprefix = eprefix;
+ return (err || olderrors != global.errors);
+}
+
/**
* Determines whether a symbol represents a module or package
* (Used as a helper for is(type == module) and is(type == package))
@@ -134,6 +2049,8 @@ Package *resolveIsPackage(Dsymbol *sym)
}
pkg = imp->pkg;
}
+ else if (Module *mod = sym->isModule())
+ pkg = mod->isPackageFile ? mod->pkg : sym->isPackage();
else
pkg = sym->isPackage();
if (pkg)
@@ -141,6 +2058,25 @@ Package *resolveIsPackage(Dsymbol *sym)
return pkg;
}
+static Module *loadStdMath()
+{
+ static Import *impStdMath = NULL;
+ if (!impStdMath)
+ {
+ Identifiers *a = new Identifiers();
+ a->push(Id::std);
+ Import *s = new Import(Loc(), a, Id::math, NULL, false);
+ s->load(NULL);
+ if (s->mod)
+ {
+ s->mod->importAll(NULL);
+ dsymbolSemantic(s->mod, NULL);
+ }
+ impStdMath = s;
+ }
+ return impStdMath->mod;
+}
+
class ExpressionSemanticVisitor : public Visitor
{
public:
@@ -1938,7 +3874,7 @@ public:
void visit(HaltExp *e)
{
- e->type = Type::tvoid;
+ e->type = Type::tnoreturn;
result = e;
}
@@ -1959,7 +3895,9 @@ public:
Type *tded = NULL;
if (e->tok2 == TOKpackage || e->tok2 == TOKmodule) // These is() expressions are special because they can work on modules, not just types.
{
+ const unsigned oldErrors = global.startGagging();
Dsymbol *sym = e->targ->toDsymbol(sc);
+ global.endGagging(oldErrors);
if (sym == NULL)
goto Lno;
Package *p = resolveIsPackage(sym);
@@ -2292,7 +4230,7 @@ public:
if (exp->e1->op == TOKarraylength)
{
// arr.length op= e2;
- e = ArrayLengthExp::rewriteOpAssign(exp);
+ e = rewriteOpAssign(exp);
e = expressionSemantic(e, sc);
result = e;
return;
@@ -2382,27 +4320,39 @@ public:
result = ((BinExp *)e)->reorderSettingAAElem(sc);
}
- void visit(CompileExp *exp)
+private:
+ Expression *compileIt(CompileExp *exp)
{
- StringExp *se = semanticString(sc, exp->e1, "argument to mixin");
- if (!se)
- return setError();
- se = se->toUTF8(sc);
+ OutBuffer buf;
+ if (expressionsToString(buf, sc, exp->exps))
+ return NULL;
+
unsigned errors = global.errors;
- Parser p(exp->loc, sc->_module, (utf8_t *)se->string, se->len, 0);
+ const size_t len = buf.length();
+ const char *str = buf.extractChars();
+ Parser p(exp->loc, sc->_module, (const utf8_t *)str, len, false);
p.nextToken();
//printf("p.loc.linnum = %d\n", p.loc.linnum);
+
Expression *e = p.parseExpression();
- if (p.errors)
- {
- assert(global.errors != errors); // should have caught all these cases
- return setError();
- }
+ if (global.errors != errors)
+ return NULL;
+
if (p.token.value != TOKeof)
{
- exp->error("incomplete mixin expression (%s)", se->toChars());
- return setError();
+ exp->error("incomplete mixin expression (%s)", str);
+ return NULL;
}
+ return e;
+ }
+
+public:
+ void visit(CompileExp *exp)
+ {
+ //printf("CompileExp::semantic('%s')\n", exp->toChars());
+ Expression *e = compileIt(exp);
+ if (!e)
+ return setError();
result = expressionSemantic(e, sc);
}
@@ -2508,6 +4458,8 @@ public:
if (exp->e1->isBool(false))
{
+ /* This is an `assert(0)` which means halt program execution
+ */
FuncDeclaration *fd = sc->parent->isFuncDeclaration();
if (fd)
fd->hasReturnExp |= 4;
@@ -2525,8 +4477,10 @@ public:
result = e;
return;
}
+ exp->type = Type::tnoreturn;
}
- exp->type = Type::tvoid;
+ else
+ exp->type = Type::tvoid;
result = exp;
}
@@ -3484,7 +5438,8 @@ public:
return setError();
}
- if (!tf->callMatch(NULL, exp->arguments))
+ const char *failMessage = NULL;
+ if (!tf->callMatch(NULL, exp->arguments, 0, &failMessage))
{
OutBuffer buf;
@@ -3495,10 +5450,11 @@ public:
tthis->modToBuffer(&buf);
//printf("tf = %s, args = %s\n", tf->deco, (*exp->arguments)[0]->type->deco);
- ::error(exp->loc, "%s %s %s is not callable using argument types %s",
+ ::error(exp->loc, "%s `%s%s` is not callable using argument types `%s`",
p, exp->e1->toChars(), parametersTypeToChars(tf->parameterList),
buf.peekChars());
-
+ if (failMessage)
+ errorSupplemental(exp->loc, failMessage);
return setError();
}
@@ -3553,13 +5509,14 @@ public:
assert(exp->f);
tiargs = NULL;
- if (ve->hasOverloads)
+ if (exp->f->overnext)
exp->f = resolveFuncCall(exp->loc, sc, exp->f, tiargs, NULL, exp->arguments, 2);
else
{
exp->f = exp->f->toAliasFunc();
TypeFunction *tf = (TypeFunction *)exp->f->type;
- if (!tf->callMatch(NULL, exp->arguments))
+ const char *failMessage = NULL;
+ if (!tf->callMatch(NULL, exp->arguments, 0, &failMessage))
{
OutBuffer buf;
@@ -3568,10 +5525,11 @@ public:
buf.writeByte(')');
//printf("tf = %s, args = %s\n", tf->deco, (*exp->arguments)[0]->type->deco);
- ::error(exp->loc, "%s %s is not callable using argument types %s",
- exp->e1->toChars(), parametersTypeToChars(tf->parameterList),
+ ::error(exp->loc, "%s `%s%s` is not callable using argument types `%s`",
+ exp->f->kind(), exp->e1->toChars(), parametersTypeToChars(tf->parameterList),
buf.peekChars());
-
+ if (failMessage)
+ errorSupplemental(exp->loc, failMessage);
exp->f = NULL;
}
}
@@ -3954,6 +5912,10 @@ public:
exp->e1 = exp->e1->castTo(sc, exp->type->pointerTo());
break;
+ case Tnull:
+ exp->type = Type::tnoreturn; // typeof(*null) is bottom type
+ break;
+
default:
exp->error("can only * a pointer, not a `%s`", exp->e1->type->toChars());
/* fall through */
@@ -7109,25 +9071,6 @@ public:
result = exp;
}
- Module *loadStdMath()
- {
- static Import *impStdMath = NULL;
- if (!impStdMath)
- {
- Identifiers *a = new Identifiers();
- a->push(Id::std);
- Import *s = new Import(Loc(), a, Id::math, NULL, false);
- s->load(NULL);
- if (s->mod)
- {
- s->mod->importAll(NULL);
- dsymbolSemantic(s->mod, NULL);
- }
- impStdMath = s;
- }
- return impStdMath->mod;
- }
-
void visit(PowExp *exp)
{
if (exp->type)
@@ -7579,7 +9522,7 @@ public:
exp->error("%s is not an expression", exp->e2->toChars());
return setError();
}
- if (e1x->op == TOKerror)
+ if (e1x->op == TOKerror || e1x->type->ty == Tnoreturn)
{
result = e1x;
return;
@@ -8032,10 +9975,18 @@ public:
Type *t1 = exp->e1->type;
Type *t2 = exp->e2->type;
+ if (t1->ty == Tnoreturn)
+ {
+ exp->type = t2;
+ }
+ else if (t2->ty == Tnoreturn)
+ {
+ exp->type = t1;
+ }
// If either operand is void the result is void, we have to cast both
// the expression to void so that we explicitly discard the expression
// value if any (bugzilla 16598)
- if (t1->ty == Tvoid || t2->ty == Tvoid)
+ else if (t1->ty == Tvoid || t2->ty == Tvoid)
{
exp->type = Type::tvoid;
exp->e1 = exp->e1->castTo(sc, exp->type);
diff --git a/gcc/d/dmd/func.c b/gcc/d/dmd/func.c
index 7a216a97941..b8e1e318376 100644
--- a/gcc/d/dmd/func.c
+++ b/gcc/d/dmd/func.c
@@ -1473,7 +1473,8 @@ FuncDeclaration *resolveFuncCall(Loc loc, Scope *sc, Dsymbol *s,
memset(&m, 0, sizeof(m));
m.last = MATCHnomatch;
- functionResolve(&m, s, loc, sc, tiargs, tthis, fargs);
+ const char *failMessage = NULL;
+ functionResolve(&m, s, loc, sc, tiargs, tthis, fargs, &failMessage);
if (m.last > MATCHnomatch && m.lastf)
{
@@ -1555,20 +1556,23 @@ FuncDeclaration *resolveFuncCall(Loc loc, Scope *sc, Dsymbol *s,
::error(loc, "none of the overloads of `%s` are callable using a %sobject, candidates are:",
fd->ident->toChars(), thisBuf.peekChars());
else
- ::error(loc, "%smethod %s is not callable using a %sobject",
+ ::error(loc, "%smethod `%s` is not callable using a %sobject",
funcBuf.peekChars(), fd->toPrettyChars(), thisBuf.peekChars());
}
else
{
//printf("tf = %s, args = %s\n", tf->deco, (*fargs)[0]->type->deco);
if (hasOverloads)
- ::error(loc, "none of the overloads of `%s` are callable using argument types %s, candidates are:",
+ ::error(loc, "none of the overloads of `%s` are callable using argument types `%s`, candidates are:",
fd->ident->toChars(), fargsBuf.peekChars());
else
- fd->error(loc, "%s%s is not callable using argument types %s",
- parametersTypeToChars(tf->parameterList),
- tf->modToChars(),
- fargsBuf.peekChars());
+ {
+ fd->error(loc, "%s `%s%s%s` is not callable using argument types `%s`",
+ fd->kind(), fd->toPrettyChars(), parametersTypeToChars(tf->parameterList),
+ tf->modToChars(), fargsBuf.peekChars());
+ if (failMessage)
+ errorSupplemental(loc, failMessage);
+ }
}
// Display candidate functions
diff --git a/gcc/d/dmd/hdrgen.c b/gcc/d/dmd/hdrgen.c
index a11c9c353d9..9eba88f1118 100644
--- a/gcc/d/dmd/hdrgen.c
+++ b/gcc/d/dmd/hdrgen.c
@@ -122,7 +122,7 @@ public:
void visit(CompileStatement *s)
{
buf->writestring("mixin(");
- s->exp->accept(this);
+ argsToBuffer(s->exps);
buf->writestring(");");
if (!hgs->forStmtInit)
buf->writenl();
@@ -1104,6 +1104,18 @@ public:
buf->writestring("typeof(null)");
}
+ void visit(TypeMixin *t)
+ {
+ buf->writestring("mixin(");
+ argsToBuffer(t->exps);
+ buf->writeByte(')');
+ }
+
+ void visit(TypeNoreturn *)
+ {
+ buf->writestring("noreturn");
+ }
+
////////////////////////////////////////////////////////////////////////////
void visit(Dsymbol *s)
@@ -1418,7 +1430,7 @@ public:
void visit(CompileDeclaration *d)
{
buf->writestring("mixin(");
- d->exp->accept(this);
+ argsToBuffer(d->exps);
buf->writestring(");");
buf->writenl();
}
@@ -2408,8 +2420,15 @@ public:
buf->writeByte(')');
if (target.ptrsize == 8)
goto L4;
- else
+ else if (target.ptrsize == 4 ||
+ target.ptrsize == 2)
goto L3;
+ else
+ assert(0);
+
+ case Tvoid:
+ buf->writestring("cast(void)0");
+ break;
default:
/* This can happen if errors, such as
@@ -2822,7 +2841,7 @@ public:
void visit(CompileExp *e)
{
buf->writestring("mixin(");
- expToBuffer(e->e1, PREC_assign);
+ argsToBuffer(e->exps);
buf->writeByte(')');
}
@@ -3528,6 +3547,13 @@ void arrayObjectsToBuffer(OutBuffer *buf, Objects *objects)
}
}
+/*************************************************************
+ * Pretty print function parameters.
+ * Params:
+ * parameters = parameters to print, such as TypeFunction.parameters.
+ * varargs = kind of varargs, see TypeFunction.varargs.
+ * Returns: Null-terminated string representing parameters.
+ */
const char *parametersTypeToChars(ParameterList pl)
{
OutBuffer buf;
@@ -3536,3 +3562,26 @@ const char *parametersTypeToChars(ParameterList pl)
v.parametersToBuffer(pl.parameters, pl.varargs);
return buf.extractChars();
}
+
+/*************************************************************
+ * Pretty print function parameter.
+ * Params:
+ * parameter = parameter to print.
+ * tf = TypeFunction which holds parameter.
+ * fullQual = whether to fully qualify types.
+ * Returns: Null-terminated string representing parameters.
+ */
+const char *parameterToChars(Parameter *parameter, TypeFunction *tf, bool fullQual)
+{
+ OutBuffer buf;
+ HdrGenState hgs;
+ hgs.fullQual = fullQual;
+ PrettyPrintVisitor v(&buf, &hgs);
+
+ parameter->accept(&v);
+ if (tf->parameterList.varargs == 2 && parameter == tf->parameterList[tf->parameterList.parameters->length - 1])
+ {
+ buf.writestring("...");
+ }
+ return buf.extractChars();
+}
diff --git a/gcc/d/dmd/hdrgen.h b/gcc/d/dmd/hdrgen.h
index d464d4aa618..6822aaf44a9 100644
--- a/gcc/d/dmd/hdrgen.h
+++ b/gcc/d/dmd/hdrgen.h
@@ -47,6 +47,7 @@ void arrayObjectsToBuffer(OutBuffer *buf, Objects *objects);
void moduleToBuffer(OutBuffer *buf, Module *m);
const char *parametersTypeToChars(ParameterList pl);
+const char *parameterToChars(Parameter *parameter, TypeFunction *tf, bool fullQual);
bool stcToBuffer(OutBuffer *buf, StorageClass stc);
const char *stcToChars(StorageClass& stc);
diff --git a/gcc/d/dmd/idgen.c b/gcc/d/dmd/idgen.c
index 59faa993b9b..0740653709a 100644
--- a/gcc/d/dmd/idgen.c
+++ b/gcc/d/dmd/idgen.c
@@ -86,10 +86,16 @@ Msgtable msgtable[] =
{ "__c_longlong", NULL },
{ "__c_ulonglong", NULL },
{ "__c_long_double", NULL },
+ { "__c_wchar_t", NULL },
+ { "__c_complex_float", NULL },
+ { "__c_complex_double", NULL },
+ { "__c_complex_real", NULL },
{ "cpp_type_info_ptr", "__cpp_type_info_ptr" },
{ "_assert", "assert" },
{ "_unittest", "unittest" },
{ "_body", "body" },
+ { "printf", NULL },
+ { "scanf", NULL },
{ "TypeInfo", NULL },
{ "TypeInfo_Class", NULL },
@@ -395,7 +401,6 @@ Msgtable msgtable[] =
{ "derivedMembers", NULL },
{ "isSame", NULL },
{ "compiles", NULL },
- { "parameters", NULL },
{ "getAliasThis", NULL },
{ "getAttributes", NULL },
{ "getFunctionAttributes", NULL },
@@ -411,6 +416,7 @@ Msgtable msgtable[] =
{ "getLocation", NULL },
{ "hasPostblit", NULL },
{ "isCopyable", NULL },
+ { "toType", NULL },
// For C++ mangling
{ "allocator", NULL },
diff --git a/gcc/d/dmd/import.h b/gcc/d/dmd/import.h
index e49ad15c2d3..07fb32aa070 100644
--- a/gcc/d/dmd/import.h
+++ b/gcc/d/dmd/import.h
@@ -47,6 +47,7 @@ public:
Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees
void load(Scope *sc);
void importAll(Scope *sc);
+ void addPackageAccess(ScopeDsymbol *scopesym);
Dsymbol *toAlias();
void addMember(Scope *sc, ScopeDsymbol *sds);
void setScope(Scope* sc);
diff --git a/gcc/d/dmd/module.h b/gcc/d/dmd/module.h
index 03078b5e833..1664492bc2d 100644
--- a/gcc/d/dmd/module.h
+++ b/gcc/d/dmd/module.h
@@ -75,6 +75,7 @@ public:
unsigned numlines; // number of lines in source file
int isDocFile; // if it is a documentation input file, not D source
bool isPackageFile; // if it is a package.d
+ Package *pkg; // if isPackageFile is true, the Package that contains this package.d
Strings contentImportedFiles; // array of files whose content was imported
int needmoduleinfo;
diff --git a/gcc/d/dmd/mtype.c b/gcc/d/dmd/mtype.c
index c1071b2f278..6b01999bc7c 100644
--- a/gcc/d/dmd/mtype.c
+++ b/gcc/d/dmd/mtype.c
@@ -39,6 +39,7 @@ Expression *extractSideEffect(Scope *sc, const char *name, Expression **e0, Expr
Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
Expression *typeToExpression(Type *t);
Expression *typeToExpressionHelper(TypeQualified *t, Expression *e, size_t i = 0);
+RootObject *compileTypeMixin(TypeMixin *tm, Loc loc, Scope *sc);
/***************************** Type *****************************/
@@ -93,6 +94,7 @@ Type *Type::tdchar;
Type *Type::tshiftcnt;
Type *Type::terror;
Type *Type::tnull;
+Type *Type::tnoreturn;
Type *Type::tsize_t;
Type *Type::tptrdiff_t;
@@ -195,6 +197,8 @@ void Type::_init()
sizeTy[Tnull] = sizeof(TypeNull);
sizeTy[Tvector] = sizeof(TypeVector);
sizeTy[Ttraits] = sizeof(TypeTraits);
+ sizeTy[Tmixin] = sizeof(TypeMixin);
+ sizeTy[Tnoreturn] = sizeof(TypeNoreturn);
initTypeMangle();
@@ -216,6 +220,10 @@ void Type::_init()
}
basic[Terror] = new TypeError();
+ tnoreturn = new TypeNoreturn();
+ tnoreturn->deco = tnoreturn->merge()->deco;
+ basic[Tnoreturn] = tnoreturn;
+
tvoid = basic[Tvoid];
tint8 = basic[Tint8];
tuns8 = basic[Tuns8];
@@ -246,7 +254,7 @@ void Type::_init()
tshiftcnt = tint32;
terror = basic[Terror];
- tnull = basic[Tnull];
+ tnoreturn = basic[Tnoreturn];
tnull = new TypeNull();
tnull->deco = tnull->merge()->deco;
@@ -2079,7 +2087,7 @@ Expression *Type::getProperty(Loc loc, Identifier *ident, int flag)
if (this != Type::terror)
{
if (s)
- error(loc, "no property `%s` for type `%s`, did you mean `%s`?", ident->toChars(), toChars(), s->toChars());
+ error(loc, "no property `%s` for type `%s`, did you mean `%s`?", ident->toChars(), toChars(), s->toPrettyChars());
else
error(loc, "no property `%s` for type `%s`", ident->toChars(), toChars());
}
@@ -2413,6 +2421,16 @@ TypeTraits *Type::isTypeTraits()
return ty == Ttraits ? (TypeTraits *)this : NULL;
}
+TypeMixin *Type::isTypeMixin()
+{
+ return ty == Tmixin ? (TypeMixin *)this : NULL;
+}
+
+TypeNoreturn *Type::isTypeNoreturn()
+{
+ return ty == Tnoreturn ? (TypeNoreturn *)this : NULL;
+}
+
TypeFunction *Type::toTypeFunction()
{
if (ty != Tfunction)
@@ -5175,16 +5193,47 @@ void TypeFunction::purityLevel()
tf->purity = purity;
}
+// arguments get specially formatted
+static const char *getParamError(TypeFunction *tf, Expression *arg, Parameter *par)
+{
+ if (global.gag && !global.params.showGaggedErrors)
+ return NULL;
+ // show qualification when toChars() is the same but types are different
+ const char *at = arg->type->toChars();
+ bool qual = !arg->type->equals(par->type) && strcmp(at, par->type->toChars()) == 0;
+ if (qual)
+ at = arg->type->toPrettyChars(true);
+ OutBuffer buf;
+ // only mention rvalue if it's relevant
+ const bool rv = !arg->isLvalue() && (par->storageClass & (STCref | STCout)) != 0;
+ buf.printf("cannot pass %sargument `%s` of type `%s` to parameter `%s`",
+ rv ? "rvalue " : "", arg->toChars(), at,
+ parameterToChars(par, tf, qual));
+ return buf.extractChars();
+}
+
+static const char *getMatchError(const char *format, ...)
+{
+ if (global.gag && !global.params.showGaggedErrors)
+ return NULL;
+ OutBuffer buf;
+ va_list ap;
+ va_start(ap, format);
+ buf.vprintf(format, ap);
+ return buf.extractChars();
+}
+
/********************************
* 'args' are being matched to function 'this'
* Determine match level.
* Input:
* flag 1 performing a partial ordering match
+ * pMessage address to store error message, or null
* Returns:
* MATCHxxxx
*/
-MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag)
+MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag, const char **pMessage)
{
//printf("TypeFunction::callMatch() %s\n", toChars());
MATCH match = MATCHexact; // assume exact match
@@ -5221,12 +5270,15 @@ MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag)
size_t nparams = parameterList.length();
size_t nargs = args ? args->length : 0;
- if (nparams == nargs)
- ;
- else if (nargs > nparams)
+ if (nargs > nparams)
{
if (parameterList.varargs == VARARGnone)
- goto Nomatch; // too many args; no match
+ {
+ // suppress early exit if an error message is wanted,
+ // so we can check any matching args are valid
+ if (!pMessage)
+ goto Nomatch; // too many args; no match
+ }
match = MATCHconvert; // match ... with a "conversion" match level
}
@@ -5309,7 +5361,10 @@ MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag)
if (m && !arg->isLvalue())
{
if (p->storageClass & STCout)
+ {
+ if (pMessage) *pMessage = getParamError(this, arg, p);
goto Nomatch;
+ }
if (arg->op == TOKstring && tp->ty == Tsarray)
{
@@ -5331,7 +5386,10 @@ MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag)
}
}
else
+ {
+ if (pMessage) *pMessage = getParamError(this, arg, p);
goto Nomatch;
+ }
}
/* Find most derived alias this type being matched.
@@ -5351,7 +5409,10 @@ MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag)
* ref T[dim] <- an lvalue of const(T[dim]) argument
*/
if (!ta->constConv(tp))
+ {
+ if (pMessage) *pMessage = getParamError(this, arg, p);
goto Nomatch;
+ }
}
}
@@ -5377,7 +5438,11 @@ MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag)
tsa = (TypeSArray *)tb;
sz = tsa->dim->toInteger();
if (sz != nargs - u)
+ {
+ if (pMessage)
+ *pMessage = getMatchError("expected %llu variadic argument(s), not %zu", sz, nargs - u);
goto Nomatch;
+ }
/* fall through */
case Tarray:
{
@@ -5408,7 +5473,10 @@ MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag)
m = arg->implicitConvTo(ta->next);
if (m == MATCHnomatch)
+ {
+ if (pMessage) *pMessage = getParamError(this, arg, p);
goto Nomatch;
+ }
if (m < match)
match = m;
}
@@ -5420,9 +5488,14 @@ MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag)
goto Ldone;
default:
- goto Nomatch;
+ break;
}
}
+ if (pMessage && u < nargs)
+ *pMessage = getParamError(this, (*args)[u], p);
+ else if (pMessage)
+ *pMessage = getMatchError("missing argument for parameter #%d: `%s`",
+ u + 1, parameterToChars(p, this, false));
goto Nomatch;
}
if (m < match)
@@ -5430,6 +5503,12 @@ MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag)
}
Ldone:
+ if (pMessage && !parameterList.varargs && nargs > nparams)
+ {
+ // all parameters had a match, but there are surplus args
+ *pMessage = getMatchError("expected %d argument(s), not %d", nparams, nargs);
+ goto Nomatch;
+ }
//printf("match = %d\n", match);
return match;
@@ -5797,6 +5876,20 @@ Type *TypeTraits::syntaxCopy()
return tt;
}
+Dsymbol *TypeTraits::toDsymbol(Scope *sc)
+{
+ Type *t = NULL;
+ Expression *e = NULL;
+ Dsymbol *s = NULL;
+ resolve(loc, sc, &e, &t, &s);
+ if (t && t->ty != Terror)
+ s = t->toDsymbol(sc);
+ else if (e)
+ s = getDsymbol(e);
+
+ return s;
+}
+
void TypeTraits::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool)
{
*pt = NULL;
@@ -5816,6 +5909,90 @@ d_uns64 TypeTraits::size(Loc)
return SIZE_INVALID;
}
+/***************************** TypeMixin *****************************/
+
+/******
+ * Implements mixin types.
+ *
+ * Semantic analysis will convert it to a real type.
+ */
+TypeMixin::TypeMixin(const Loc &loc, Expressions *exps)
+ : Type(Tmixin)
+{
+ this->loc = loc;
+ this->exps = exps;
+ this->obj = NULL; // cached result of semantic analysis.
+}
+
+const char *TypeMixin::kind()
+{
+ return "mixin";
+}
+
+Type *TypeMixin::syntaxCopy()
+{
+ return new TypeMixin(loc, Expression::arraySyntaxCopy(exps));
+}
+
+Dsymbol *TypeMixin::toDsymbol(Scope *sc)
+{
+ Type *t = NULL;
+ Expression *e = NULL;
+ Dsymbol *s = NULL;
+ resolve(loc, sc, &e, &t, &s);
+ if (t)
+ s = t->toDsymbol(sc);
+ else if (e)
+ s = getDsymbol(e);
+
+ return s;
+}
+
+void TypeMixin::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
+{
+ // if already resolved just set pe/pt/ps and return.
+ if (obj)
+ {
+ *pe = isExpression(obj);
+ *pt = isType(obj);
+ *ps = isDsymbol(obj);
+ return;
+ }
+
+ RootObject *o = compileTypeMixin(this, loc, sc);
+ if (Type *t = isType(o))
+ {
+ t->resolve(loc, sc, pe, pt, ps, intypeid);
+ if (*pt)
+ (*pt) = (*pt)->addMod(mod);
+ }
+ else if (Expression *e = isExpression(o))
+ {
+ e = expressionSemantic(e, sc);
+ if (TypeExp *et = e->isTypeExp())
+ {
+ *pe = NULL;
+ *pt = et->type->addMod(mod);
+ *ps = NULL;
+ }
+ else
+ {
+ *pe = e;
+ *pt = NULL;
+ *ps = NULL;
+ }
+ }
+ else
+ {
+ *pe = NULL;
+ *pt = Type::terror;
+ *ps = NULL;
+ }
+
+ // save the result
+ obj = *pe ? (RootObject *)*pe : (*pt ? (RootObject *)*pt : (RootObject *)*ps);
+}
+
/***************************** TypeQualified *****************************/
TypeQualified::TypeQualified(TY ty, Loc loc)
@@ -6003,11 +6180,25 @@ void TypeQualified::resolveHelper(Loc loc, Scope *sc,
Type *t = s->getType(); // type symbol, type alias, or type tuple?
unsigned errorsave = global.errors;
- Dsymbol *sm = s->searchX(loc, sc, id);
- if (sm && !(sc->flags & SCOPEignoresymbolvisibility) && !symbolIsVisible(sc, sm))
+ int flags = t == NULL ? SearchLocalsOnly : IgnorePrivateImports;
+ Dsymbol *sm = s->searchX(loc, sc, id, flags);
+ if (sm)
{
- ::error(loc, "`%s` is not visible from module `%s`", sm->toPrettyChars(), sc->_module->toChars());
- sm = NULL;
+ if (!(sc->flags & SCOPEignoresymbolvisibility) && !symbolIsVisible(sc, sm))
+ {
+ ::error(loc, "`%s` is not visible from module `%s`", sm->toPrettyChars(), sc->_module->toChars());
+ sm = NULL;
+ }
+ // Same check as in Expression::semanticY(DotIdExp)
+ else if (sm->isPackage() && checkAccess(sc, (Package *)sm))
+ {
+ // @@@DEPRECATED_2.096@@@
+ // Should be an error in 2.106. Just remove the deprecation call
+ // and uncomment the null assignment
+ ::deprecation(loc, "%s %s is not accessible here, perhaps add 'static import %s;'",
+ sm->kind(), sm->toPrettyChars(), sm->toPrettyChars());
+ //sm = null;
+ }
}
if (global.errors != errorsave)
{
@@ -6052,7 +6243,7 @@ void TypeQualified::resolveHelper(Loc loc, Scope *sc,
sm = t->toDsymbol(sc);
if (sm && id->dyncast() == DYNCAST_IDENTIFIER)
{
- sm = sm->search(loc, (Identifier *)id);
+ sm = sm->search(loc, (Identifier *)id, IgnorePrivateImports);
if (sm)
goto L2;
}
@@ -8177,6 +8368,49 @@ Expression *TypeNull::defaultInit(Loc)
return new NullExp(Loc(), Type::tnull);
}
+/***************************** TypeNoreturn *****************************/
+
+TypeNoreturn::TypeNoreturn()
+ : Type(Tnoreturn)
+{
+ //printf("TypeNoreturn %p\n", this);
+}
+
+const char *TypeNoreturn::kind()
+{
+ return "noreturn";
+}
+
+Type *TypeNoreturn::syntaxCopy()
+{
+ // No semantic analysis done, no need to copy
+ return this;
+}
+
+MATCH TypeNoreturn::implicitConvTo(Type *to)
+{
+ //printf("TypeNoreturn::implicitConvTo(this=%p, to=%p)\n", this, to);
+ //printf("from: %s\n", toChars());
+ //printf("to : %s\n", to.toChars());
+ MATCH m = Type::implicitConvTo(to);
+ return (m == MATCHexact) ? MATCHexact : MATCHconvert;
+}
+
+bool TypeNoreturn::isBoolean()
+{
+ return true; // bottom type can be implicitly converted to any other type
+}
+
+d_uns64 TypeNoreturn::size(Loc)
+{
+ return 0;
+}
+
+unsigned TypeNoreturn::alignsize()
+{
+ return 0;
+}
+
/***********************************************************
* Encapsulate Parameters* so .length and [i] can be used on it.
* https://dlang.org/spec/function.html#ParameterList
@@ -8472,3 +8706,25 @@ bool Parameter::isCovariantScope(bool returnByRef, StorageClass from, StorageCla
return covariant[SR::buildSR(returnByRef, from)][SR::buildSR(returnByRef, to)];
}
+
+/**
+ * For printing two types with qualification when necessary.
+ * Params:
+ * t1 = The first type to receive the type name for
+ * t2 = The second type to receive the type name for
+ * Returns:
+ * The fully-qualified names of both types if the two type names are not the same,
+ * or the unqualified names of both types if the two type names are the same.
+ */
+void toAutoQualChars(const char **result, Type *t1, Type *t2)
+{
+ const char *s1 = t1->toChars();
+ const char *s2 = t2->toChars();
+ if (strcmp(s1, s2) == 0)
+ {
+ s1 = t1->toPrettyChars(true);
+ s2 = t2->toPrettyChars(true);
+ }
+ result[0] = s1;
+ result[1] = s2;
+}
diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h
index 083d707f8f3..3687053488d 100644
--- a/gcc/d/dmd/mtype.h
+++ b/gcc/d/dmd/mtype.h
@@ -96,6 +96,8 @@ enum ENUMTY
Tint128,
Tuns128,
Ttraits,
+ Tmixin,
+ Tnoreturn,
TMAX
};
typedef unsigned char TY; // ENUMTY
@@ -201,6 +203,7 @@ public:
static Type *tdstring; // immutable(dchar)[]
static Type *terror; // for error recovery
static Type *tnull; // for null type
+ static Type *tnoreturn; // for bottom type typeof(*null)
static Type *tsize_t; // matches size_t alias
static Type *tptrdiff_t; // matches ptrdiff_t alias
@@ -367,7 +370,9 @@ public:
TypeTuple *isTypeTuple();
TypeSlice *isTypeSlice();
TypeNull *isTypeNull();
+ TypeMixin *isTypeMixin();
TypeTraits *isTypeTraits();
+ TypeNoreturn *isTypeNoreturn();
void accept(Visitor *v) { v->visit(this); }
};
@@ -686,7 +691,7 @@ public:
int attributesApply(void *param, int (*fp)(void *, const char *), TRUSTformat trustFormat = TRUSTformatDefault);
Type *substWildTo(unsigned mod);
- MATCH callMatch(Type *tthis, Expressions *toargs, int flag = 0);
+ MATCH callMatch(Type *tthis, Expressions *toargs, int flag = 0, const char **pMessage = NULL);
bool checkRetType(Loc loc);
Expression *defaultInit(Loc loc) /*const*/;
@@ -726,11 +731,27 @@ public:
TypeTraits(const Loc &loc, TraitsExp *exp);
Type *syntaxCopy();
+ Dsymbol *toDsymbol(Scope *sc);
void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
d_uns64 size(Loc loc);
void accept(Visitor *v) { v->visit(this); }
};
+class TypeMixin : public Type
+{
+public:
+ Loc loc;
+ Expressions *exps;
+ RootObject *obj;
+
+ TypeMixin(const Loc &loc, Expressions *exps);
+ const char *kind();
+ Type *syntaxCopy();
+ Dsymbol *toDsymbol(Scope *sc);
+ void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
class TypeQualified : public Type
{
public:
@@ -966,6 +987,21 @@ public:
void accept(Visitor *v) { v->visit(this); }
};
+class TypeNoreturn : public Type
+{
+public:
+ TypeNoreturn();
+ const char *kind();
+
+ Type *syntaxCopy();
+ MATCH implicitConvTo(Type *to);
+ bool isBoolean() /*const*/;
+
+ d_uns64 size(Loc loc) /*const*/;
+ unsigned alignsize();
+ void accept(Visitor *v) { v->visit(this); }
+};
+
/**************************************************************/
bool arrayTypeCompatible(Loc loc, Type *t1, Type *t2);
diff --git a/gcc/d/dmd/parse.c b/gcc/d/dmd/parse.c
index c050b050404..e1f13214d58 100644
--- a/gcc/d/dmd/parse.c
+++ b/gcc/d/dmd/parse.c
@@ -328,11 +328,9 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl, PrefixAttributes
{
// mixin(string)
nextToken();
- check(TOKlparen, "mixin");
- Expression *e = parseAssignExp();
- check(TOKrparen);
+ Expressions *exps = parseArguments();
check(TOKsemicolon);
- s = new CompileDeclaration(loc, e);
+ s = new CompileDeclaration(loc, exps);
break;
}
case TOKtemplate:
@@ -1336,7 +1334,7 @@ LINK Parser::parseLinkage(Identifiers **pidents, CPPMANGLE *pcppmangle, bool *pc
}
else if (!Identifier::isValidIdentifier(name))
{
- error("expected valid identifer for C++ namespace but got `%s`", name);
+ error("expected valid identifier for C++ namespace but got `%s`", name);
idents = NULL;
break;
}
@@ -2922,6 +2920,18 @@ Objects *Parser::parseTemplateArguments()
return tiargs;
}
+/***************************************
+ * Parse a Type or an Expression
+ * Returns:
+ * RootObject representing the AST
+ */
+RootObject *Parser::parseTypeOrAssignExp(TOK endtoken)
+{
+ return isDeclaration(&token, 0, endtoken, NULL)
+ ? (RootObject *)parseType() // argument is a type
+ : (RootObject *)parseAssignExp(); // argument is an expression
+}
+
/******************************************
* Parse template argument list.
* Input:
@@ -2942,20 +2952,10 @@ Objects *Parser::parseTemplateArgumentList()
// Get TemplateArgumentList
while (token.value != endtok)
{
- // See if it is an Expression or a Type
- if (isDeclaration(&token, 0, TOKreserved, NULL))
- { // Template argument is a type
- Type *ta = parseType();
- tiargs->push(ta);
- }
- else
- { // Template argument is an expression
- Expression *ea = parseAssignExp();
- tiargs->push(ea);
- }
- if (token.value != TOKcomma)
- break;
- nextToken();
+ tiargs->push(parseTypeOrAssignExp());
+ if (token.value != TOKcomma)
+ break;
+ nextToken();
}
check(endtok, "template argument list");
return tiargs;
@@ -3288,6 +3288,15 @@ Type *Parser::parseBasicType(bool dontLookDotIdents)
}
break;
+ case TOKmixin:
+ // https://dlang.org/spec/expression.html#mixin_types
+ loc = token.loc;
+ nextToken();
+ if (token.value != TOKlparen)
+ error("found `%s` when expecting `%s` following %s", token.toChars(), Token::toChars(TOKlparen), "`mixin`");
+ t = new TypeMixin(loc, parseArguments());
+ break;
+
case TOKdot:
// Leading . as in .foo
t = parseBasicTypeStartingAt(new TypeIdentifier(token.loc, Id::empty), dontLookDotIdents);
@@ -3602,7 +3611,7 @@ Type *Parser::parseDeclarator(Type *t, int *palt, Identifier **pident,
if (pident)
*pident = token.ident;
else
- error("unexpected identifer `%s` in declarator", token.ident->toChars());
+ error("unexpected identifier `%s` in declarator", token.ident->toChars());
ts = t;
nextToken();
break;
@@ -3863,6 +3872,21 @@ void Parser::parseStorageClasses(StorageClass &storage_class, LINK &link,
}
}
+static void parseAttributes(Parser *p, bool &hasParsedAttributes,
+ StorageClass &storage_class, LINK &link, bool &setAlignment,
+ Expression *&ealign, Expressions *&udas)
+{
+ if (hasParsedAttributes) // only parse once
+ return;
+ hasParsedAttributes = true;
+ udas = NULL;
+ storage_class = STCundefined;
+ link = p->linkage;
+ setAlignment = false;
+ ealign = NULL;
+ p->parseStorageClasses(storage_class, link, setAlignment, ealign, udas);
+}
+
/**********************************
* Parse Declarations.
* These can be:
@@ -3936,26 +3960,48 @@ Dsymbols *Parser::parseDeclarations(bool autodecl, PrefixAttributes *pAttrs, con
bool hasParsedAttributes = false;
if (token.value == TOKat)
{
- if (!hasParsedAttributes)
- {
- hasParsedAttributes = true;
- storage_class = STCundefined;
- link = linkage;
- setAlignment = false;
- ealign = NULL;
- udas = NULL;
- parseStorageClasses(storage_class, link, setAlignment, ealign, udas);
- }
+ parseAttributes(this, hasParsedAttributes,
+ storage_class, link, setAlignment, ealign, udas);
}
Declaration *v;
- if (token.value == TOKfunction ||
+ Dsymbol *s;
+
+ // try to parse function type:
+ // TypeCtors? BasicType ( Parameters ) MemberFunctionAttributes
+ bool attributesAppended = false;
+ const StorageClass funcStc = parseTypeCtor();
+ Token *tlu = &token;
+ if (token.value != TOKfunction &&
+ token.value != TOKdelegate &&
+ isBasicType(&tlu) && tlu &&
+ tlu->value == TOKlparen)
+ {
+ VarArg vargs;
+ Type *tret = parseBasicType();
+ Parameters *prms = parseParameters(&vargs);
+ ParameterList pl = ParameterList(prms, vargs);
+
+ parseAttributes(this, hasParsedAttributes,
+ storage_class, link, setAlignment, ealign, udas);
+ if (udas)
+ error("user-defined attributes not allowed for `alias` declarations");
+
+ attributesAppended = true;
+ storage_class = appendStorageClass(storage_class, funcStc);
+ Type *tf = new TypeFunction(pl, tret, link, storage_class);
+ v = new AliasDeclaration(loc, ident, tf);
+ }
+ else if (token.value == TOKfunction ||
token.value == TOKdelegate ||
(token.value == TOKlparen &&
skipAttributes(peekPastParen(&token), &tk) &&
(tk->value == TOKgoesto || tk->value == TOKlcurly)) ||
token.value == TOKlcurly ||
- (token.value == TOKidentifier && peekNext() == TOKgoesto))
+ (token.value == TOKidentifier && peekNext() == TOKgoesto) ||
+ (token.value == TOKref && peekNext() == TOKlparen &&
+ skipAttributes(peekPastParen(peek(&token)), &tk) &&
+ (tk->value == TOKgoesto || tk->value == TOKlcurly)))
{
// function (parameters) { statements... }
// delegate (parameters) { statements... }
@@ -3963,8 +4009,10 @@ Dsymbols *Parser::parseDeclarations(bool autodecl, PrefixAttributes *pAttrs, con
// (parameters) => expression
// { statements... }
// identifier => expression
+ // ref (parameters) { statements... }
+ // ref (parameters) => expression
- Dsymbol *s = parseFunctionLiteral();
+ s = parseFunctionLiteral();
if (udas != NULL)
{
@@ -3985,26 +4033,19 @@ Dsymbols *Parser::parseDeclarations(bool autodecl, PrefixAttributes *pAttrs, con
else
{
// StorageClasses type
- if (!hasParsedAttributes)
- {
- hasParsedAttributes = true;
- storage_class = STCundefined;
- link = linkage;
- setAlignment = false;
- ealign = NULL;
- udas = NULL;
- parseStorageClasses(storage_class, link, setAlignment, ealign, udas);
- }
-
+ parseAttributes(this, hasParsedAttributes,
+ storage_class, link, setAlignment, ealign, udas);
if (udas)
error("user-defined attributes not allowed for %s declarations", Token::toChars(tok));
t = parseType();
v = new AliasDeclaration(loc, ident, t);
}
+ if (!attributesAppended)
+ storage_class = appendStorageClass(storage_class, funcStc);
v->storage_class = storage_class;
- Dsymbol *s = v;
+ s = v;
if (tpl)
{
Dsymbols *a2 = new Dsymbols();
@@ -4358,6 +4399,13 @@ Dsymbol *Parser::parseFunctionLiteral()
case TOKdelegate:
save = token.value;
nextToken();
+ if (token.value == TOKref)
+ {
+ // function ref (parameters) { statements... }
+ // delegate ref (parameters) { statements... }
+ stc = STCref;
+ nextToken();
+ }
if (token.value != TOKlparen && token.value != TOKlcurly)
{
// function type (parameters) { statements... }
@@ -4377,14 +4425,22 @@ Dsymbol *Parser::parseFunctionLiteral()
// delegate { statements... }
break;
}
- /* fall through */
+ goto LTOKlparen;
+
+ case TOKref:
+ // ref (parameters) => expression
+ // ref (parameters) { statements... }
+ stc = STCref;
+ nextToken();
+ goto LTOKlparen;
case TOKlparen:
+ LTOKlparen:
{
// (parameters) => expression
// (parameters) { statements... }
parameters = parseParameters(&varargs, &tpl);
- stc = parsePostfix(STCundefined, NULL);
+ stc = parsePostfix(stc, NULL);
if (StorageClass modStc = stc & STC_TYPECTOR)
{
if (save == TOKfunction)
@@ -5093,7 +5149,7 @@ Statement *Parser::parseForeach(Loc loc, bool *isRange, bool isDecl)
check(TOKrparen);
Loc endloc;
Statement *body = (!isDecl) ? parseStatement(0, NULL, &endloc) : NULL;
- if (isRange)
+ if (isRange)
*isRange = false;
return new ForeachStatement(loc, op, parameters, aggr, body, endloc);
}
@@ -5378,15 +5434,19 @@ Statement *Parser::parseStatement(int flags, const utf8_t** endPtr, Loc *pEndloc
}
case TOKmixin:
- { Token *t = peek(&token);
+ {
+ if (isDeclaration(&token, 3, TOKreserved, NULL))
+ goto Ldeclaration;
+ Token *t = peek(&token);
if (t->value == TOKlparen)
- { // mixin(string)
+ {
+ // mixin(string)
Expression *e = parseAssignExp();
check(TOKsemicolon);
if (e->op == TOKmixin)
{
CompileExp *cpe = (CompileExp *)e;
- s = new CompileStatement(loc, cpe->e1);
+ s = new CompileStatement(loc, cpe->exps);
}
else
{
@@ -6332,6 +6392,7 @@ bool Parser::isBasicType(Token **pt)
case TOKtypeof:
case TOKvector:
+ case TOKmixin:
/* typeof(exp).identifier...
*/
t = peek(t);
@@ -6592,9 +6653,11 @@ bool Parser::isDeclarator(Token **pt, int *haveId, int *haveTpl, TOK endtok, boo
case TOKin:
case TOKout:
case TOKdo:
+ LTOKdo:
// The !parens is to disallow unnecessary parentheses
if (!parens && (endtok == TOKreserved || endtok == t->value))
- { *pt = t;
+ {
+ *pt = t;
return true;
}
return false;
@@ -6602,6 +6665,12 @@ bool Parser::isDeclarator(Token **pt, int *haveId, int *haveTpl, TOK endtok, boo
case TOKif:
return haveTpl ? true : false;
+ // Used for mixin type parsing
+ case TOKeof:
+ if (endtok == TOKeof)
+ goto LTOKdo;
+ return false;
+
default:
Ldefault:
return false;
@@ -7229,15 +7298,7 @@ Expression *Parser::parsePrimaryExp()
{
nextToken();
check(TOKlparen, "typeid");
- RootObject *o;
- if (isDeclaration(&token, 0, TOKreserved, NULL))
- { // argument is a type
- o = parseType();
- }
- else
- { // argument is an expression
- o = parseAssignExp();
- }
+ RootObject *o = parseTypeOrAssignExp();
check(TOKrparen);
e = new TypeidExp(loc, o);
break;
@@ -7279,6 +7340,14 @@ Expression *Parser::parsePrimaryExp()
if (token.value == TOKlparen)
{
nextToken();
+ if (token.value == TOKidentifier && peekNext() == TOKlparen)
+ {
+ error(loc, "unexpected `(` after `%s`, inside `is` expression. Try enclosing the contents of `is` with a `typeof` expression", token.toChars());
+ nextToken();
+ Token *tempTok = peekPastParen(&token);
+ memcpy(&token, tempTok, sizeof(Token));
+ goto Lerr;
+ }
targ = parseType(&ident);
if (token.value == TOKcolon || token.value == TOKequal)
{
@@ -7357,11 +7426,11 @@ Expression *Parser::parsePrimaryExp()
case TOKmixin:
{
+ // https://dlang.org/spec/expression.html#mixin_expressions
nextToken();
- check(TOKlparen, "mixin");
- e = parseAssignExp();
- check(TOKrparen);
- e = new CompileExp(loc, e);
+ if (token.value != TOKlparen)
+ error("found `%s` when expecting `%s` following %s", token.toChars(), Token::toChars(TOKlparen), "`mixin`");
+ e = new CompileExp(loc, parseArguments());
break;
}
@@ -7379,6 +7448,24 @@ Expression *Parser::parsePrimaryExp()
e = parseNewExp(NULL);
break;
+ case TOKref:
+ {
+ if (peekNext() == TOKlparen)
+ {
+ Token *tk = peekPastParen(peek(&token));
+ if (skipAttributes(tk, &tk) &&
+ (tk->value == TOKgoesto || tk->value == TOKlcurly))
+ {
+ // ref (arguments) => expression
+ // ref (arguments) { statements... }
+ goto case_delegate;
+ }
+ }
+ nextToken();
+ error("found `%s` when expecting function literal following `ref`", token.toChars());
+ goto Lerr;
+ }
+
case TOKlparen:
{
Token *tk = peekPastParen(&token);
diff --git a/gcc/d/dmd/parse.h b/gcc/d/dmd/parse.h
index 82ce3254607..a2ad47882ef 100644
--- a/gcc/d/dmd/parse.h
+++ b/gcc/d/dmd/parse.h
@@ -83,6 +83,7 @@ public:
TemplateParameters *parseTemplateParameterList(int flag = 0);
Dsymbol *parseMixin();
Objects *parseTemplateArguments();
+ RootObject *parseTypeOrAssignExp(TOK endtoken = TOKreserved);
Objects *parseTemplateArgumentList();
Objects *parseTemplateSingleArgument();
StaticAssert *parseStaticAssert();
diff --git a/gcc/d/dmd/scope.h b/gcc/d/dmd/scope.h
index ea3bf3874e1..ea3061b8fa6 100644
--- a/gcc/d/dmd/scope.h
+++ b/gcc/d/dmd/scope.h
@@ -66,6 +66,10 @@ enum PINLINE;
#define SCOPEfullinst 0x10000 // fully instantiate templates
#define SCOPEalias 0x20000 // inside alias declaration
+// The following are mutually exclusive
+#define SCOPEprintf 0x40000 // printf-style function
+#define SCOPEscanf 0x80000 // scanf-style function
+
struct Scope
{
Scope *enclosing; // enclosing Scope
diff --git a/gcc/d/dmd/semantic2.c b/gcc/d/dmd/semantic2.c
index 7bcf6ce4f33..194a3fb9661 100644
--- a/gcc/d/dmd/semantic2.c
+++ b/gcc/d/dmd/semantic2.c
@@ -163,6 +163,15 @@ public:
if (vd->_init && !vd->toParent()->isFuncDeclaration())
{
vd->inuse++;
+
+ /* https://issues.dlang.org/show_bug.cgi?id=20280
+ *
+ * Template instances may import modules that have not
+ * finished semantic1.
+ */
+ if (!vd->type)
+ dsymbolSemantic(vd, sc);
+
// Bugzilla 14166: Don't run CTFE for the temporary variables inside typeof
vd->_init = initializerSemantic(vd->_init, sc, vd->type, sc->intypeof == 1 ? INITnointerpret : INITinterpret);
vd->inuse--;
@@ -265,6 +274,17 @@ public:
{
if (fd->semanticRun >= PASSsemantic2done)
return;
+
+ if (fd->semanticRun < PASSsemanticdone && !fd->errors)
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=21614
+ *
+ * Template instances may import modules that have not
+ * finished semantic1.
+ */
+ dsymbolSemantic(fd, sc);
+ }
+
assert(fd->semanticRun <= PASSsemantic2);
fd->semanticRun = PASSsemantic2;
diff --git a/gcc/d/dmd/semantic3.c b/gcc/d/dmd/semantic3.c
index 304eaeeb119..6bd9a6d2e27 100644
--- a/gcc/d/dmd/semantic3.c
+++ b/gcc/d/dmd/semantic3.c
@@ -850,32 +850,18 @@ public:
}
assert(!funcdecl->returnLabel);
}
+ else if (f->next->ty == Tnoreturn)
+ {
+ }
else
{
const bool inlineAsm = (funcdecl->hasReturnExp & 8) != 0;
if ((blockexit & BEfallthru) && f->next->ty != Tvoid && !inlineAsm)
{
- Expression *e;
if (!funcdecl->hasReturnExp)
- funcdecl->error("has no return statement, but is expected to return a value of type %s", f->next->toChars());
- else
- funcdecl->error("no return exp; or assert(0); at end of function");
- if (global.params.useAssert == CHECKENABLEon &&
- !global.params.useInline)
- {
- /* Add an assert(0, msg); where the missing return
- * should be.
- */
- e = new AssertExp(funcdecl->endloc,
- new IntegerExp(0),
- new StringExp(funcdecl->loc, const_cast<char *>("missing return expression")));
- }
+ funcdecl->error("has no `return` statement, but is expected to return a value of type `%s`", f->next->toChars());
else
- e = new HaltExp(funcdecl->endloc);
- e = new CommaExp(Loc(), e, f->next->defaultInit());
- e = expressionSemantic(e, sc2);
- Statement *s = new ExpStatement(Loc(), e);
- funcdecl->fbody = new CompoundStatement(Loc(), funcdecl->fbody, s);
+ funcdecl->error("no `return exp;` or `assert(0);` at end of function");
}
}
@@ -1162,15 +1148,7 @@ public:
if (cd)
{
- if (!global.params.is64bit &&
- global.params.isWindows &&
- !funcdecl->isStatic() && !sbody->usesEH() && !global.params.trace)
- {
- /* The back end uses the "jmonitor" hack for syncing;
- * no need to do the sync at this level.
- */
- }
- else
+ if (target.libraryObjectMonitors(funcdecl, sbody))
{
Expression *vsync;
if (funcdecl->isStatic())
diff --git a/gcc/d/dmd/statement.c b/gcc/d/dmd/statement.c
index 2f7b7e13ffc..1f8e5122b1a 100644
--- a/gcc/d/dmd/statement.c
+++ b/gcc/d/dmd/statement.c
@@ -31,6 +31,7 @@ StorageClass mergeFuncAttrs(StorageClass s1, FuncDeclaration *f);
bool checkEscapeRef(Scope *sc, Expression *e, bool gag);
VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e);
Statement *makeTupleForeachStatic(Scope *sc, ForeachStatement *fs, bool needExpansion);
+bool expressionsToString(OutBuffer &buf, Scope *sc, Expressions *exps);
Identifier *fixupLabelName(Scope *sc, Identifier *ident)
{
@@ -504,12 +505,19 @@ Statement *DtorExpStatement::syntaxCopy()
CompileStatement::CompileStatement(Loc loc, Expression *exp)
: Statement(loc)
{
- this->exp = exp;
+ this->exps = new Expressions();
+ this->exps->push(exp);
+}
+
+CompileStatement::CompileStatement(Loc loc, Expressions *exps)
+ : Statement(loc)
+{
+ this->exps = exps;
}
Statement *CompileStatement::syntaxCopy()
{
- return new CompileStatement(loc, exp->syntaxCopy());
+ return new CompileStatement(loc, Expression::arraySyntaxCopy(exps));
}
static Statements *errorStatements()
@@ -519,32 +527,36 @@ static Statements *errorStatements()
return a;
}
-Statements *CompileStatement::flatten(Scope *sc)
+static Statements *compileIt(CompileStatement *cs, Scope *sc)
{
- //printf("CompileStatement::flatten() %s\n", exp->toChars());
- StringExp *se = semanticString(sc, exp, "argument to mixin");
- if (!se)
+ //printf("CompileStatement::compileIt() %s\n", exp->toChars());
+ OutBuffer buf;
+ if (expressionsToString(buf, sc, cs->exps))
return errorStatements();
- se = se->toUTF8(sc);
unsigned errors = global.errors;
- Parser p(loc, sc->_module, (utf8_t *)se->string, se->len, 0);
+ const size_t len = buf.length();
+ const char *str = buf.extractChars();
+ Parser p(cs->loc, sc->_module, (const utf8_t *)str, len, false);
p.nextToken();
Statements *a = new Statements();
while (p.token.value != TOKeof)
{
Statement *s = p.parseStatement(PSsemi | PScurlyscope);
- if (!s || p.errors)
- {
- assert(!p.errors || global.errors != errors); // make sure we caught all the cases
+ if (!s || global.errors != errors)
return errorStatements();
- }
a->push(s);
}
return a;
}
+Statements *CompileStatement::flatten(Scope *sc)
+{
+ //printf("CompileStatement::flatten() %s\n", exp->toChars());
+ return compileIt(this, sc);
+}
+
/******************************** CompoundStatement ***************************/
CompoundStatement::CompoundStatement(Loc loc, Statements *s)
diff --git a/gcc/d/dmd/statement.h b/gcc/d/dmd/statement.h
index 2d8b46c9487..c64e51a5be7 100644
--- a/gcc/d/dmd/statement.h
+++ b/gcc/d/dmd/statement.h
@@ -173,9 +173,10 @@ public:
class CompileStatement : public Statement
{
public:
- Expression *exp;
+ Expressions *exps;
CompileStatement(Loc loc, Expression *exp);
+ CompileStatement(Loc loc, Expressions *exps);
Statement *syntaxCopy();
Statements *flatten(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
diff --git a/gcc/d/dmd/statementsem.c b/gcc/d/dmd/statementsem.c
index 5579c1ca893..491d9c9bce9 100644
--- a/gcc/d/dmd/statementsem.c
+++ b/gcc/d/dmd/statementsem.c
@@ -581,7 +581,7 @@ public:
{
fs->error("constant value %s cannot be ref", ie->toChars());
}
- else
+ else
{
fs->error("constant value %s cannot be ref", ident->toChars());
}
diff --git a/gcc/d/dmd/target.h b/gcc/d/dmd/target.h
index a91880fd0fc..f8f977c9aea 100644
--- a/gcc/d/dmd/target.h
+++ b/gcc/d/dmd/target.h
@@ -21,6 +21,7 @@ class Dsymbol;
class Expression;
class FuncDeclaration;
class Parameter;
+class Statement;
class Type;
class TypeFunction;
class TypeTuple;
@@ -30,6 +31,7 @@ struct TargetC
{
unsigned longsize; // size of a C 'long' or 'unsigned long' type
unsigned long_doublesize; // size of a C 'long double'
+ Type *twchar_t; // C 'wchar_t' type
};
struct TargetCPP
@@ -44,6 +46,7 @@ struct TargetCPP
const char *typeMangle(Type *t);
Type *parameterType(Parameter *p);
bool fundamentalType(const Type *t, bool& isFundamental);
+ unsigned derivedClassOffset(ClassDeclaration *baseClass);
};
struct TargetObjC
@@ -108,6 +111,7 @@ public:
TypeTuple *toArgTypes(Type *t);
bool isReturnOnStack(TypeFunction *tf, bool needsThis);
Expression *getTargetInfo(const char* name, const Loc& loc);
+ bool libraryObjectMonitors(FuncDeclaration *fd, Statement *fbody);
};
extern Target target;
diff --git a/gcc/d/dmd/template.h b/gcc/d/dmd/template.h
index dac1e85b433..fb842ac5b76 100644
--- a/gcc/d/dmd/template.h
+++ b/gcc/d/dmd/template.h
@@ -78,6 +78,7 @@ public:
bool ismixin; // template declaration is only to be used as a mixin
bool isstatic; // this is static template declaration
Prot protection;
+ int inuse; // for recursive expansion detection
TemplatePrevious *previous; // threaded list of previous instantiation attempts on stack
diff --git a/gcc/d/dmd/templateparamsem.c b/gcc/d/dmd/templateparamsem.c
index 11cd52e351b..d3e9b2390e9 100644
--- a/gcc/d/dmd/templateparamsem.c
+++ b/gcc/d/dmd/templateparamsem.c
@@ -25,7 +25,7 @@ public:
{
this->sc = sc;
this->parameters = parameters;
- this->result = false;
+ this->result = false;
}
void visit(TemplateTypeParameter *ttp)
diff --git a/gcc/d/dmd/traits.c b/gcc/d/dmd/traits.c
index b7c612c2af2..99b5457f031 100644
--- a/gcc/d/dmd/traits.c
+++ b/gcc/d/dmd/traits.c
@@ -40,6 +40,8 @@ void freeFieldinit(Scope *sc);
Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
Package *resolveIsPackage(Dsymbol *sym);
Expression *typeToExpression(Type *t);
+Type *decoToType(const char *deco);
+bool expressionsToString(OutBuffer &buf, Scope *sc, Expressions *exps);
/************************************************
@@ -442,7 +444,6 @@ TraitsInitializer::TraitsInitializer()
"derivedMembers",
"isSame",
"compiles",
- "parameters",
"getAliasThis",
"getAttributes",
"getFunctionAttributes",
@@ -1032,6 +1033,34 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc)
ex = expressionSemantic(ex, sc);
return ex;
}
+ else if (e->ident == Id::toType)
+ {
+ if (dim != 1)
+ return dimError(e, 1, dim);
+
+ Expression *ex = isExpression((*e->args)[0]);
+ if (!ex)
+ {
+ e->error("expression expected as second argument of __traits `%s`", e->ident->toChars());
+ return new ErrorExp();
+ }
+ ex = ex->ctfeInterpret();
+
+ StringExp *se = semanticString(sc, ex, "__traits(toType, string)");
+ if (!se)
+ {
+ return new ErrorExp();
+ }
+ Type *t = decoToType(se->toUTF8(sc)->toPtr());
+ if (!t)
+ {
+ e->error("cannot determine `%s`", e->toChars());
+ return new ErrorExp();
+ }
+ ex = new TypeExp(e->loc, t);
+ ex = expressionSemantic(ex, sc);
+ return ex;
+ }
else if (e->ident == Id::hasMember ||
e->ident == Id::getMember ||
e->ident == Id::getOverloads ||
@@ -1674,33 +1703,67 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc)
RootObject *o = (*e->args)[i];
Type *t = isType(o);
- Expression *ex = t ? typeToExpression(t) : isExpression(o);
- if (!ex && t)
+ while (t)
{
- Dsymbol *s;
- t->resolve(e->loc, sc2, &ex, &t, &s);
- if (t)
+ if (TypeMixin *tm = t->isTypeMixin())
{
- typeSemantic(t, e->loc, sc2);
- if (t->ty == Terror)
+ /* The mixin string could be a type or an expression.
+ * Have to try compiling it to see.
+ */
+ OutBuffer buf;
+ if (expressionsToString(buf, sc, tm->exps))
+ {
+ err = true;
+ break;
+ }
+ const size_t len = buf.length();
+ const char *str = buf.extractChars();
+ Parser p(e->loc, sc->_module, (const utf8_t *)str, len, false);
+ p.nextToken();
+ //printf("p.loc.linnum = %d\n", p.loc.linnum);
+
+ o = p.parseTypeOrAssignExp(TOKeof);
+ if (p.errors || p.token.value != TOKeof)
+ {
err = true;
+ break;
+ }
+ t = isType(o);
}
- else if (s && s->errors)
- err = true;
+ else
+ break;
}
- if (ex)
+
+ if (!err)
{
- ex = expressionSemantic(ex, sc2);
- ex = resolvePropertiesOnly(sc2, ex);
- ex = ex->optimize(WANTvalue);
- if (sc2->func && sc2->func->type->ty == Tfunction)
+ Expression *ex = t ? typeToExpression(t) : isExpression(o);
+ if (!ex && t)
{
- TypeFunction *tf = (TypeFunction *)sc2->func->type;
- canThrow(ex, sc2->func, tf->isnothrow);
+ Dsymbol *s;
+ t->resolve(e->loc, sc2, &ex, &t, &s);
+ if (t)
+ {
+ typeSemantic(t, e->loc, sc2);
+ if (t->ty == Terror)
+ err = true;
+ }
+ else if (s && s->errors)
+ err = true;
+ }
+ if (ex)
+ {
+ ex = expressionSemantic(ex, sc2);
+ ex = resolvePropertiesOnly(sc2, ex);
+ ex = ex->optimize(WANTvalue);
+ if (sc2->func && sc2->func->type->ty == Tfunction)
+ {
+ TypeFunction *tf = (TypeFunction *)sc2->func->type;
+ canThrow(ex, sc2->func, tf->isnothrow);
+ }
+ ex = checkGC(sc2, ex);
+ if (ex->op == TOKerror)
+ err = true;
}
- ex = checkGC(sc2, ex);
- if (ex->op == TOKerror)
- err = true;
}
// Carefully detach the scope from the parent and throw it away as
diff --git a/gcc/d/dmd/typesem.c b/gcc/d/dmd/typesem.c
index 496cfe3a855..670144d1282 100644
--- a/gcc/d/dmd/typesem.c
+++ b/gcc/d/dmd/typesem.c
@@ -18,6 +18,7 @@
#include "hdrgen.h"
#include "id.h"
#include "init.h"
+#include "parse.h"
#include "scope.h"
#include "target.h"
#include "template.h"
@@ -25,6 +26,7 @@
Expression *typeToExpression(Type *t);
Expression *typeToExpressionHelper(TypeQualified *t, Expression *e, size_t i = 0);
+bool expressionsToString(OutBuffer &buf, Scope *sc, Expressions *exps);
char *MODtoChars(MOD mod);
class TypeToExpressionVisitor : public Visitor
@@ -76,6 +78,11 @@ public:
{
result = typeToExpressionHelper(t, new ScopeExp(t->loc, t->tempinst));
}
+
+ void visit(TypeMixin *t)
+ {
+ result = new TypeExp(t->loc, t);
+ }
};
/* We've mistakenly parsed this as a type.
@@ -84,6 +91,8 @@ public:
*/
Expression *typeToExpression(Type *t)
{
+ if (t->mod)
+ return NULL;
TypeToExpressionVisitor v = TypeToExpressionVisitor(t);
t->accept(&v);
return v.result;
@@ -178,6 +187,48 @@ static Expression *semanticLength(Scope *sc, TupleDeclaration *s, Expression *ex
}
/******************************************
+ * Compile the MixinType, returning the type or expression AST.
+ *
+ * Doesn't run semantic() on the returned object.
+ * Params:
+ * tm = mixin to compile as a type or expression
+ * loc = location for error messages
+ * sc = context
+ * Return:
+ * null if error, else RootObject AST as parsed
+ */
+RootObject *compileTypeMixin(TypeMixin *tm, Loc loc, Scope *sc)
+{
+ OutBuffer buf;
+ if (expressionsToString(buf, sc, tm->exps))
+ return NULL;
+
+ const unsigned errors = global.errors;
+ const size_t len = buf.length();
+ const char *str = buf.extractChars();
+ Parser p(loc, sc->_module, (const utf8_t *)str, len, false);
+ p.nextToken();
+ //printf("p.loc.linnum = %d\n", p.loc.linnum);
+
+ RootObject *o = p.parseTypeOrAssignExp(TOKeof);
+ if (errors != global.errors)
+ {
+ assert(global.errors != errors); // should have caught all these cases
+ return NULL;
+ }
+ if (p.token.value != TOKeof)
+ {
+ ::error(loc, "incomplete mixin type `%s`", str);
+ return NULL;
+ }
+
+ Type *t = isType(o);
+ Expression *e = t ? typeToExpression(t) : isExpression(o);
+
+ return (!e && t) ? (RootObject *)t : (RootObject *)e;
+}
+
+/******************************************
* Perform semantic analysis on a type.
* Params:
* type = Type AST node
@@ -440,7 +491,7 @@ Type *typeSemantic(Type *type, const Loc &loc, Scope *sc)
// Deal with the case where we thought the index was a type, but
// in reality it was an expression.
if (mtype->index->ty == Tident || mtype->index->ty == Tinstance || mtype->index->ty == Tsarray ||
- mtype->index->ty == Ttypeof || mtype->index->ty == Treturn)
+ mtype->index->ty == Ttypeof || mtype->index->ty == Treturn || mtype->index->ty == Tmixin)
{
Expression *e;
Type *t;
@@ -1072,6 +1123,7 @@ Type *typeSemantic(Type *type, const Loc &loc, Scope *sc)
mtype->exp->ident != Id::getMember &&
mtype->exp->ident != Id::parent &&
mtype->exp->ident != Id::child &&
+ mtype->exp->ident != Id::toType &&
mtype->exp->ident != Id::getOverloads &&
mtype->exp->ident != Id::getVirtualFunctions &&
mtype->exp->ident != Id::getVirtualMethods &&
@@ -1275,7 +1327,7 @@ Type *typeSemantic(Type *type, const Loc &loc, Scope *sc)
void visit(TypeStruct *mtype)
{
- //printf("TypeStruct::semantic('%s')\n", mtype->sym->toChars());
+ //printf("TypeStruct::semantic('%s')\n", mtype->toChars());
if (mtype->deco)
{
if (sc && sc->cppmangle != CPPMANGLEdefault)
@@ -1304,7 +1356,7 @@ Type *typeSemantic(Type *type, const Loc &loc, Scope *sc)
void visit(TypeClass *mtype)
{
- //printf("TypeClass::semantic(%s)\n", mtype->sym->toChars());
+ //printf("TypeClass::semantic(%s)\n", mtype->toChars());
if (mtype->deco)
{
if (sc && sc->cppmangle != CPPMANGLEdefault)
@@ -1386,6 +1438,25 @@ Type *typeSemantic(Type *type, const Loc &loc, Scope *sc)
Type *t = new TypeTuple(args);
result = typeSemantic(t, loc, sc);
}
+
+ void visit(TypeMixin *mtype)
+ {
+ //printf("TypeMixin::semantic() %s\n", mtype->toChars());
+
+ Expression *e = NULL;
+ Type *t = NULL;
+ Dsymbol *s = NULL;
+ mtype->resolve(loc, sc, &e, &t, &s);
+
+ if (t && t->ty != Terror)
+ {
+ result = t;
+ return;
+ }
+
+ ::error(mtype->loc, "`mixin(%s)` does not give a valid type", mtype->obj->toChars());
+ return error();
+ }
};
TypeSemanticVisitor v(loc, sc);
type->accept(&v);
diff --git a/gcc/d/dmd/visitor.h b/gcc/d/dmd/visitor.h
index a274e6f083e..09ba2024e30 100644
--- a/gcc/d/dmd/visitor.h
+++ b/gcc/d/dmd/visitor.h
@@ -81,7 +81,9 @@ class TypeClass;
class TypeTuple;
class TypeSlice;
class TypeNull;
+class TypeNoreturn;
class TypeTraits;
+class TypeMixin;
class Dsymbol;
@@ -374,7 +376,9 @@ public:
virtual void visit(TypeTuple *t) { visit((Type *)t); }
virtual void visit(TypeSlice *t) { visit((TypeNext *)t); }
virtual void visit(TypeNull *t) { visit((Type *)t); }
+ virtual void visit(TypeNoreturn *t) { visit((Type *)t); }
virtual void visit(TypeTraits *t) { visit((Type *)t); }
+ virtual void visit(TypeMixin *t) { visit((Type *)t); }
virtual void visit(Dsymbol *) { assert(0); }
diff --git a/gcc/d/toir.cc b/gcc/d/toir.cc
index ee3e3d5bdd5..41d07a7b70e 100644
--- a/gcc/d/toir.cc
+++ b/gcc/d/toir.cc
@@ -1068,6 +1068,13 @@ public:
add_stmt (return_expr (decl));
}
+ else if (tf->next->ty == Tnoreturn)
+ {
+ /* Returning an expression that has no value, but has a side effect
+ that should never return. */
+ add_stmt (build_expr_dtor (s->exp));
+ add_stmt (return_expr (NULL_TREE));
+ }
else
{
/* Convert for initializing the DECL_RESULT. */
diff --git a/gcc/d/types.cc b/gcc/d/types.cc
index 3cddfc5dd46..924d8298211 100644
--- a/gcc/d/types.cc
+++ b/gcc/d/types.cc
@@ -603,6 +603,12 @@ public:
t->ctype = ptr_type_node;
}
+ /* Bottom type used for functions that never return. */
+
+ void visit (TypeNoreturn *t)
+ {
+ t->ctype = void_type_node;
+ }
/* Basic Data Types. */
@@ -852,7 +858,46 @@ public:
tree basetype = (t->sym->memtype)
? build_ctype (t->sym->memtype) : void_type_node;
- if (!INTEGRAL_TYPE_P (basetype) || TREE_CODE (basetype) == BOOLEAN_TYPE)
+ if (t->sym->isSpecial ())
+ {
+ /* Special enums are opaque types that bind to C types. */
+ const char *ident = t->toChars ();
+ Type *underlying = NULL;
+
+ /* Skip over the prefixing `__c_'. */
+ gcc_assert (strncmp (ident, "__c_", strlen ("__c_")) == 0);
+ ident = ident + strlen ("__c_");
+
+ /* To keep things compatible within the code generation we stick to
+ mapping to equivalent D types. However it should be OK to use the
+ GCC provided C types here as the front-end enforces that everything
+ must be explicitly cast from a D type to any of the opaque types. */
+ if (strcmp (ident, "long") == 0)
+ underlying = build_frontend_type (long_integer_type_node);
+ else if (strcmp (ident, "ulong") == 0)
+ underlying = build_frontend_type (long_unsigned_type_node);
+ else if (strcmp (ident, "wchar_t") == 0)
+ underlying = target.c.twchar_t;
+ else if (strcmp (ident, "longlong") == 0)
+ underlying = build_frontend_type (long_long_integer_type_node);
+ else if (strcmp (ident, "ulonglong") == 0)
+ underlying = build_frontend_type (long_long_unsigned_type_node);
+ else if (strcmp (ident, "long_double") == 0)
+ underlying = build_frontend_type (long_double_type_node);
+ else if (strcmp (ident, "complex_real") == 0)
+ underlying = build_frontend_type (complex_long_double_type_node);
+ else if (strcmp (ident, "complex_float") == 0)
+ underlying = build_frontend_type (complex_float_type_node);
+ else if (strcmp (ident, "complex_double") == 0)
+ underlying = build_frontend_type (complex_double_type_node);
+
+ /* Conversion failed or there's an unhandled special type. */
+ gcc_assert (underlying != NULL);
+
+ t->ctype = build_variant_type_copy (build_ctype (underlying));
+ build_type_decl (t->ctype, t->sym);
+ }
+ else if (!INTEGRAL_TYPE_P (basetype) || TREE_CODE (basetype) == BOOLEAN_TYPE)
{
/* Enums in D2 can have a base type that is not necessarily integral.
For these, we simplify this a little by using the base type directly