This patch merges the D front-end implementation with upstream dmd a5c86f5b9, adding the following new `__traits' to the D language.
- isDeprecated: used to detect if a function is deprecated. - isDisabled: used to detect if a function is marked with @disable. - isFuture: used to detect if a function is marked with @__future. - isModule: used to detect if a given symbol represents a module, this enhancement also adds support using `is(sym == module)'. - isPackage: used to detect if a given symbol represents a package, this enhancement also adds support using `is(sym == package)'. - child: takes two arguments. The first must be a symbol or expression and the second must be a symbol, such as an alias to a member of the first 'parent' argument. The result is the second 'member' argument interpreted with its 'this' context set to 'parent'. This is the inverse of `__traits(parent, member)'. - isReturnOnStack: determines if a function's return value is placed on the stack, or is returned via registers. - isZeroInit: used to detect if a type's default initializer has no non-zero bits. - getTargetInfo: used to query features of the target being compiled for, the back-end can expand this to register any key to handle the given argument, however a reliable subset exists which includes "cppRuntimeLibrary", "cppStd", "floatAbi", and "objectFormat". - getLocation: returns a tuple whose entries correspond to the filename, line number, and column number of where the argument was declared. - hasPostblit: used to detect if a type is a struct with a postblit. - isCopyable: used to detect if a type allows copying its value. - getVisibility: an alias for the getProtection trait. Bootstrapped and regression tested on x86_64-linux-gnu, with -m32 and -mx32 multilibs, and committed to mainline. Regards Iain. --- gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd a5c86f5b9. * d-builtins.cc (d_eval_constant_expression): Handle ADDR_EXPR trees created by build_string_literal. * d-frontend.cc (retStyle): Remove function. * d-target.cc (d_language_target_info): New variable. (d_target_info_table): Likewise. (Target::_init): Initialize d_target_info_table. (Target::isReturnOnStack): New function. (d_add_target_info_handlers): Likewise. (d_handle_target_cpp_std): Likewise. (d_handle_target_cpp_runtime_library): Likewise. (Target::getTargetInfo): Likewise. * d-target.h (struct d_target_info_spec): New type. (d_add_target_info_handlers): Declare. --- gcc/d/d-builtins.cc | 14 + gcc/d/d-frontend.cc | 20 - gcc/d/d-target.cc | 104 +++ gcc/d/d-target.h | 15 + gcc/d/dmd/MERGE | 2 +- gcc/d/dmd/declaration.h | 3 +- gcc/d/dmd/dmodule.c | 289 ++++---- gcc/d/dmd/dstruct.c | 118 ++- gcc/d/dmd/dtemplate.c | 6 +- gcc/d/dmd/expression.c | 9 +- gcc/d/dmd/expressionsem.c | 67 +- gcc/d/dmd/func.c | 39 +- gcc/d/dmd/globals.h | 2 +- gcc/d/dmd/idgen.c | 13 + gcc/d/dmd/module.h | 2 +- gcc/d/dmd/mtype.c | 1 + gcc/d/dmd/parse.c | 15 +- gcc/d/dmd/root/filename.c | 14 + gcc/d/dmd/root/filename.h | 1 + gcc/d/dmd/target.h | 3 + gcc/d/dmd/traits.c | 684 ++++++++++++++---- gcc/testsuite/gdc.test/compilable/Test16206.d | 28 + .../compilable/imports/pkgmodule/package.d | 3 + .../imports/pkgmodule/plainmodule.d | 2 + .../imports/plainpackage/plainmodule.d | 4 + .../gdc.test/compilable/isZeroInit.d | 78 ++ .../gdc.test/compilable/isreturnonstack.d | 7 + gcc/testsuite/gdc.test/compilable/line.d | 4 +- gcc/testsuite/gdc.test/compilable/test16002.d | 24 + gcc/testsuite/gdc.test/compilable/test17791.d | 28 + gcc/testsuite/gdc.test/compilable/traits.d | 130 ++++ .../gdc.test/fail_compilation/fail16206a.d | 12 + .../gdc.test/fail_compilation/fail16206b.d | 12 + .../fail_compilation/fail_isZeroInit.d | 12 + .../fail_compilation/isreturnonstack.d | 12 + .../gdc.test/fail_compilation/test16002.d | 15 + .../gdc.test/fail_compilation/test17096.d | 50 ++ .../gdc.test/fail_compilation/trait_loc_err.d | 15 + .../fail_compilation/trait_loc_ov_err.d | 40 + .../gdc.test/fail_compilation/traits.d | 27 + .../gdc.test/fail_compilation/traits_child.d | 17 + .../runnable/imports/test18322import.d | 14 + gcc/testsuite/gdc.test/runnable/test17373.d | 20 + gcc/testsuite/gdc.test/runnable/test17878.d | 19 + gcc/testsuite/gdc.test/runnable/test18322.d | 21 + gcc/testsuite/gdc.test/runnable/traits.d | 180 +++-- .../gdc.test/runnable/traits_child.d | 122 ++++ 47 files changed, 1886 insertions(+), 431 deletions(-) create mode 100644 gcc/testsuite/gdc.test/compilable/Test16206.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/pkgmodule/package.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/pkgmodule/plainmodule.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/plainpackage/plainmodule.d create mode 100644 gcc/testsuite/gdc.test/compilable/isZeroInit.d create mode 100644 gcc/testsuite/gdc.test/compilable/isreturnonstack.d create mode 100644 gcc/testsuite/gdc.test/compilable/test16002.d create mode 100644 gcc/testsuite/gdc.test/compilable/test17791.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail16206a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail16206b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail_isZeroInit.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/isreturnonstack.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test16002.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test17096.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/trait_loc_err.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/trait_loc_ov_err.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/traits.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/traits_child.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test18322import.d create mode 100644 gcc/testsuite/gdc.test/runnable/test17373.d create mode 100644 gcc/testsuite/gdc.test/runnable/test17878.d create mode 100644 gcc/testsuite/gdc.test/runnable/test18322.d create mode 100644 gcc/testsuite/gdc.test/runnable/traits_child.d diff --git a/gcc/d/d-builtins.cc b/gcc/d/d-builtins.cc index 9d0c91af7db..26ccd00c79a 100644 --- a/gcc/d/d-builtins.cc +++ b/gcc/d/d-builtins.cc @@ -393,6 +393,20 @@ d_eval_constant_expression (const Loc &loc, tree cst) return VectorExp::create (loc, e, type); } + else if (code == ADDR_EXPR) + { + /* Special handling for trees constructed by build_string_literal. + What we receive is an `&"string"[0]' expression, strip off the + outer ADDR_EXPR and ARRAY_REF to get to the underlying CST. */ + tree pointee = TREE_OPERAND (cst, 0); + + if (TREE_CODE (pointee) != ARRAY_REF + || TREE_OPERAND (pointee, 1) != integer_zero_node + || TREE_CODE (TREE_OPERAND (pointee, 0)) != STRING_CST) + return NULL; + + return d_eval_constant_expression (loc, TREE_OPERAND (pointee, 0)); + } } return NULL; diff --git a/gcc/d/d-frontend.cc b/gcc/d/d-frontend.cc index 73548e197ac..32550ecfd64 100644 --- a/gcc/d/d-frontend.cc +++ b/gcc/d/d-frontend.cc @@ -139,26 +139,6 @@ Loc::equals (const Loc &loc) /* Implements back-end specific interfaces used by the frontend. */ -/* Determine return style of function - whether in registers or through a - hidden pointer to the caller's stack. */ - -RET -retStyle (TypeFunction *tf) -{ - /* Need the backend type to determine this, but this is called from the - frontend before semantic processing is finished. An accurate value - is not currently needed anyway. */ - if (tf->isref) - return RETregs; - - Type *tn = tf->next->toBasetype (); - - if (tn->ty == Tstruct || tn->ty == Tsarray) - return RETstack; - - return RETregs; -} - /* Determine if function FD is a builtin one that we can evaluate in CTFE. */ BUILTIN diff --git a/gcc/d/d-target.cc b/gcc/d/d-target.cc index 48c141460ed..d50fcef22e2 100644 --- a/gcc/d/d-target.cc +++ b/gcc/d/d-target.cc @@ -44,6 +44,25 @@ along with GCC; see the file COPYING3. If not see Target target; +/* Internal key handlers for `__traits(getTargetInfo)'. */ +static tree d_handle_target_cpp_std (void); +static tree d_handle_target_cpp_runtime_library (void); + +/* In [traits/getTargetInfo], a reliable subset of getTargetInfo keys exists + which are always available. */ +static const struct d_target_info_spec d_language_target_info[] = +{ + /* { name, handler } */ + { "cppStd", d_handle_target_cpp_std }, + { "cppRuntimeLibrary", d_handle_target_cpp_runtime_library }, + { "floatAbi", NULL }, + { "objectFormat", NULL }, + { NULL, NULL }, +}; + +/* Table `__traits(getTargetInfo)' keys. */ +static vec<d_target_info_spec> d_target_info_table; + /* Initialize the floating-point constants for TYPE. */ @@ -167,6 +186,10 @@ Target::_init (const Param &) real_convert (&CTFloat::one.rv (), mode, &dconst1); real_convert (&CTFloat::minusone.rv (), mode, &dconstm1); real_convert (&CTFloat::half.rv (), mode, &dconsthalf); + + /* Initialize target info tables, the keys required by the language are added + last, so that the OS and CPU handlers can override. */ + d_add_target_info_handlers (d_language_target_info); } /* Return GCC memory alignment size for type TYPE. */ @@ -413,3 +436,84 @@ Target::toArgTypes (Type *) /* Not implemented, however this is not currently used anywhere. */ return NULL; } + +/* Determine return style of function, whether in registers or through a + hidden pointer to the caller's stack. */ + +bool +Target::isReturnOnStack (TypeFunction *tf, bool) +{ + /* Need the back-end type to determine this, but this is called from the + frontend before semantic processing is finished. An accurate value + is not currently needed anyway. */ + if (tf->isref) + return false; + + Type *tn = tf->next->toBasetype (); + + return (tn->ty == Tstruct || tn->ty == Tsarray); +} + +/* Add all target info in HANDLERS to D_TARGET_INFO_TABLE for use by + Target::getTargetInfo(). */ + +void +d_add_target_info_handlers (const d_target_info_spec *handlers) +{ + gcc_assert (handlers != NULL); + + if (d_target_info_table.is_empty ()) + d_target_info_table.create (8); + + for (size_t i = 0; handlers[i].name != NULL; i++) + d_target_info_table.safe_push (handlers[i]); +} + +/* Handle a call to `__traits(getTargetInfo, "cppStd")'. */ + +tree +d_handle_target_cpp_std (void) +{ + return build_integer_cst (global.params.cplusplus); +} + +/* Handle a call to `__traits(getTargetInfo, "cppRuntimeLibrary")'. */ + +tree +d_handle_target_cpp_runtime_library (void) +{ + /* The driver only ever optionally links to libstdc++. */ + const char *libstdcxx = "libstdc++"; + return build_string_literal (strlen (libstdcxx) + 1, libstdcxx); +} + +/* Look up the target info KEY in the available getTargetInfo tables, and return + the result as an Expression, or NULL if KEY is not found. When the key must + always exist, but is not supported, an empty string expression is returned. + LOC is the location to use for the returned expression. */ + +Expression * +Target::getTargetInfo (const char *key, const Loc &loc) +{ + unsigned ix; + d_target_info_spec *spec; + + FOR_EACH_VEC_ELT (d_target_info_table, ix, spec) + { + tree result; + + if (strcmp (key, spec->name) != 0) + continue; + + /* Get the requested information, or empty string if unhandled. */ + if (spec->handler) + result = (spec->handler) (); + else + result = build_string_literal (1, ""); + + gcc_assert (result); + return d_eval_constant_expression (loc, result); + } + + return NULL; +} diff --git a/gcc/d/d-target.h b/gcc/d/d-target.h index 211f72fdb7e..56595d225bf 100644 --- a/gcc/d/d-target.h +++ b/gcc/d/d-target.h @@ -31,4 +31,19 @@ extern struct gcc_targetdm targetdm; /* Used by target to add predefined version idenditiers. */ extern void d_add_builtin_version (const char *); +/* Structure describing a supported key for `__traits(getTargetInfo)' and a + function to handle it. */ +struct d_target_info_spec +{ + /* The name of the key or NULL to mark the end of a table of keys. */ + const char *name; + /* Function to handle this key, the return value of the handler must be a CST. + This pointer may be NULL if no special handling is required, for instance, + the key must always be available according to the D language spec. */ + tree (*handler) (); +}; + +/* Used by target to add getTargetInfo handlers. */ +extern void d_add_target_info_handlers (const d_target_info_spec *); + #endif /* GCC_D_TARGET_H */ diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index 1f695b9d23c..1629b4535ee 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -2bd4fc3fed8b8cd9760e77c6b2a1905cd84d0e70 +a5c86f5b92c4cd3afde910c89881ccaea11de554 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/declaration.h b/gcc/d/dmd/declaration.h index 65ac3f75b27..a4e776697fc 100644 --- a/gcc/d/dmd/declaration.h +++ b/gcc/d/dmd/declaration.h @@ -149,6 +149,7 @@ public: bool isSynchronized() { return (storage_class & STCsynchronized) != 0; } bool isParameter() { return (storage_class & STCparameter) != 0; } bool isDeprecated() { return (storage_class & STCdeprecated) != 0; } + bool isDisabled() { return (storage_class & STCdisable) != 0; } bool isOverride() { return (storage_class & STCoverride) != 0; } bool isResult() { return (storage_class & STCresult) != 0; } bool isField() { return (storage_class & STCfield) != 0; } @@ -669,7 +670,7 @@ public: static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, const char *name, StorageClass stc=0); static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, Identifier *id, StorageClass stc=0); void checkDmain(); - bool checkNrvo(); + bool checkNRVO(); FuncDeclaration *isFuncDeclaration() { return this; } diff --git a/gcc/d/dmd/dmodule.c b/gcc/d/dmd/dmodule.c index 8f09f2db856..305b1331146 100644 --- a/gcc/d/dmd/dmodule.c +++ b/gcc/d/dmd/dmodule.c @@ -34,7 +34,6 @@ Dsymbols Module::deferred2; // deferred Dsymbol's needing semantic2() run on the Dsymbols Module::deferred3; // deferred Dsymbol's needing semantic3() run on them unsigned Module::dprogress; -const char *lookForSourceFile(const char **path, const char *filename); StringExp *semanticString(Scope *sc, Expression *exp, const char *s); void Module::_init() @@ -72,7 +71,6 @@ Module::Module(const char *filename, Identifier *ident, int doDocComment, int do sfilename = NULL; importedFrom = NULL; srcfile = NULL; - srcfilePath = NULL; docfile = NULL; debuglevel = 0; @@ -109,9 +107,6 @@ Module::Module(const char *filename, Identifier *ident, int doDocComment, int do fatal(); } srcfile = new File(srcfilename); - if (!FileName::absolute(srcfilename)) - srcfilePath = getcwd(NULL, 0); - objfile = setOutfile(global.params.objname.ptr, global.params.objdir.ptr, filename, global.obj_ext.ptr); if (doDocComment) @@ -215,57 +210,149 @@ static void checkModFileAlias(OutBuffer *buf, OutBuffer *dotmods, dotmods->writeByte('.'); } -Module *Module::load(Loc loc, Identifiers *packages, Identifier *ident) +/** + * Converts a chain of identifiers to the filename of the module + * + * Params: + * packages = the names of the "parent" packages + * ident = the name of the child package or module + * + * Returns: + * the filename of the child package or module + */ +static const char *getFilename(Identifiers *packages, Identifier *ident) { - //printf("Module::load(ident = '%s')\n", ident->toChars()); - - // Build module filename by turning: - // foo.bar.baz - // into: - // foo\bar\baz const char *filename = ident->toChars(); - if (packages && packages->length) - { - OutBuffer buf; - OutBuffer dotmods; - Array<const char *> *ms = &global.params.modFileAliasStrings; - const size_t msdim = ms ? ms->length : 0; - for (size_t i = 0; i < packages->length; i++) - { - Identifier *pid = (*packages)[i]; - const char *p = pid->toChars(); - buf.writestring(p); - if (msdim) - checkModFileAlias(&buf, &dotmods, ms, msdim, p); + if (packages == NULL || packages->length == 0) + return filename; + + OutBuffer buf; + OutBuffer dotmods; + Array<const char *> *ms = &global.params.modFileAliasStrings; + const size_t msdim = ms ? ms->length : 0; + + for (size_t i = 0; i < packages->length; i++) + { + Identifier *pid = (*packages)[i]; + const char *p = pid->toChars(); + buf.writestring(p); + if (msdim) + checkModFileAlias(&buf, &dotmods, ms, msdim, p); #if _WIN32 - buf.writeByte('\\'); + buf.writeByte('\\'); #else - buf.writeByte('/'); + buf.writeByte('/'); #endif - } - buf.writestring(filename); - if (msdim) - checkModFileAlias(&buf, &dotmods, ms, msdim, filename); - buf.writeByte(0); - filename = (char *)buf.extractData(); } + buf.writestring(filename); + if (msdim) + checkModFileAlias(&buf, &dotmods, ms, msdim, filename); + buf.writeByte(0); + filename = (char *)buf.extractData(); - Module *m = new Module(filename, ident, 0, 0); - m->loc = loc; + return filename; +} + +/******************************************** + * Look for the source file if it's different from filename. + * Look for .di, .d, directory, and along global.path. + * Does not open the file. + * Input: + * filename as supplied by the user + * global.path + * Returns: + * NULL if it's not different from filename. + */ - /* Look for the source file +static const char *lookForSourceFile(const char *filename) +{ + /* Search along global.path for .di file, then .d file. */ - const char *path; - const char *result = lookForSourceFile(&path, filename); - if (result) + const char *sdi = FileName::forceExt(filename, global.hdr_ext.ptr); + if (FileName::exists(sdi) == 1) + return sdi; + + const char *sd = FileName::forceExt(filename, global.mars_ext.ptr); + if (FileName::exists(sd) == 1) + return sd; + + if (FileName::exists(filename) == 2) { - m->srcfile = new File(result); - if (path) - m->srcfilePath = path; - else if (!FileName::absolute(result)) - m->srcfilePath = getcwd(NULL, 0); + /* The filename exists and it's a directory. + * Therefore, the result should be: filename/package.d + * iff filename/package.d is a file + */ + const char *ni = FileName::combine(filename, "package.di"); + if (FileName::exists(ni) == 1) + return ni; + FileName::free(ni); + const char *n = FileName::combine(filename, "package.d"); + if (FileName::exists(n) == 1) + return n; + FileName::free(n); + } + + if (FileName::absolute(filename)) + return NULL; + + if (!global.path) + return NULL; + + for (size_t i = 0; i < global.path->length; i++) + { + const char *p = (*global.path)[i]; + const char *n = FileName::combine(p, sdi); + if (FileName::exists(n) == 1) + { + return n; + } + FileName::free(n); + + n = FileName::combine(p, sd); + if (FileName::exists(n) == 1) + { + return n; + } + FileName::free(n); + + const char *b = FileName::removeExt(filename); + n = FileName::combine(p, b); + FileName::free(b); + if (FileName::exists(n) == 2) + { + const char *n2i = FileName::combine(n, "package.di"); + if (FileName::exists(n2i) == 1) + return n2i; + FileName::free(n2i); + const char *n2 = FileName::combine(n, "package.d"); + if (FileName::exists(n2) == 1) + { + return n2; + } + FileName::free(n2); + } + FileName::free(n); } + return NULL; +} + +Module *Module::load(Loc loc, Identifiers *packages, Identifier *ident) +{ + //printf("Module::load(ident = '%s')\n", ident->toChars()); + + // Build module filename by turning: + // foo.bar.baz + // into: + // foo\bar\baz + const char *filename = getFilename(packages, ident); + // Look for the source file + const char *result = lookForSourceFile(filename); + if (result) + filename = result; + + Module *m = new Module(filename, ident, 0, 0); + m->loc = loc; if (!m->read(loc)) return NULL; @@ -1158,6 +1245,27 @@ Module *Package::isPackageMod() return NULL; } +/** + * Checks for the existence of a package.d to set isPkgMod appropriately + * if isPkgMod == PKGunknown + */ +void Package::resolvePKGunknown() +{ + if (isModule()) + return; + if (isPkgMod != PKGunknown) + return; + + Identifiers packages; + for (Dsymbol *s = this->parent; s; s = s->parent) + packages.insert(0, s->ident); + + if (lookForSourceFile(getFilename(&packages, ident))) + Module::load(Loc(), &packages, this->ident); + else + isPkgMod = PKGpackage; +} + /** * Checks if pkg is a sub-package of this * @@ -1266,96 +1374,3 @@ Dsymbol *Package::search(const Loc &loc, Identifier *ident, int flags) return ScopeDsymbol::search(loc, ident, flags); } - -/* =========================== ===================== */ - -/******************************************** - * Look for the source file if it's different from filename. - * Look for .di, .d, directory, and along global.path. - * Does not open the file. - * Output: - * path the path where the file was found if it was not the current directory - * Input: - * filename as supplied by the user - * global.path - * Returns: - * NULL if it's not different from filename. - */ - -const char *lookForSourceFile(const char **path, const char *filename) -{ - /* Search along global.path for .di file, then .d file. - */ - *path = NULL; - - const char *sdi = FileName::forceExt(filename, global.hdr_ext.ptr); - if (FileName::exists(sdi) == 1) - return sdi; - - const char *sd = FileName::forceExt(filename, global.mars_ext.ptr); - if (FileName::exists(sd) == 1) - return sd; - - if (FileName::exists(filename) == 2) - { - /* The filename exists and it's a directory. - * Therefore, the result should be: filename/package.d - * iff filename/package.d is a file - */ - const char *ni = FileName::combine(filename, "package.di"); - if (FileName::exists(ni) == 1) - return ni; - FileName::free(ni); - const char *n = FileName::combine(filename, "package.d"); - if (FileName::exists(n) == 1) - return n; - FileName::free(n); - } - - if (FileName::absolute(filename)) - return NULL; - - if (!global.path) - return NULL; - - for (size_t i = 0; i < global.path->length; i++) - { - const char *p = (*global.path)[i]; - - const char *n = FileName::combine(p, sdi); - if (FileName::exists(n) == 1) - { - *path = p; - return n; - } - FileName::free(n); - - n = FileName::combine(p, sd); - if (FileName::exists(n) == 1) - { - *path = p; - return n; - } - FileName::free(n); - - const char *b = FileName::removeExt(filename); - n = FileName::combine(p, b); - FileName::free(b); - if (FileName::exists(n) == 2) - { - const char *n2i = FileName::combine(n, "package.di"); - if (FileName::exists(n2i) == 1) - return n2i; - FileName::free(n2i); - const char *n2 = FileName::combine(n, "package.d"); - if (FileName::exists(n2) == 1) - { - *path = p; - return n2; - } - FileName::free(n2); - } - FileName::free(n); - } - return NULL; -} diff --git a/gcc/d/dmd/dstruct.c b/gcc/d/dmd/dstruct.c index 2b87154142c..8829367dab4 100644 --- a/gcc/d/dmd/dstruct.c +++ b/gcc/d/dmd/dstruct.c @@ -23,6 +23,8 @@ #include "template.h" #include "tokens.h" #include "target.h" +#include "utf.h" +#include "root/ctfloat.h" Type *getTypeInfoType(Loc loc, Type *t, Scope *sc); void unSpeculative(Scope *sc, RootObject *o); @@ -1245,6 +1247,102 @@ Dsymbol *StructDeclaration::search(const Loc &loc, Identifier *ident, int flags) return ScopeDsymbol::search(loc, ident, flags); } +/********************************** + * Determine if exp is all binary zeros. + * Params: + * exp = expression to check + * Returns: + * true if it's all binary 0 + */ +static bool isZeroInit(Expression *exp) +{ + switch (exp->op) + { + case TOKint64: + return exp->toInteger() == 0; + + case TOKnull: + case TOKfalse: + return true; + + case TOKstructliteral: + { + StructLiteralExp *sle = (StructLiteralExp *) exp; + for (size_t i = 0; i < sle->sd->fields.length; i++) + { + VarDeclaration *field = sle->sd->fields[i]; + if (field->type->size(field->loc)) + { + Expression *e = (*sle->elements)[i]; + if (e ? !isZeroInit(e) + : !field->type->isZeroInit(field->loc)) + return false; + } + } + return true; + } + + case TOKarrayliteral: + { + ArrayLiteralExp *ale = (ArrayLiteralExp *) exp; + + const size_t dim = ale->elements ? ale->elements->length : 0; + + if (ale->type->toBasetype()->ty == Tarray) // if initializing a dynamic array + return dim == 0; + + for (size_t i = 0; i < dim; i++) + { + if (!isZeroInit(ale->getElement(i))) + return false; + } + /* Note that true is returned for all T[0] + */ + return true; + } + + case TOKstring: + { + StringExp *se = exp->toStringExp(); + + if (se->type->toBasetype()->ty == Tarray) // if initializing a dynamic array + return se->len == 0; + + void *s = se->string; + for (size_t i = 0; i < se->len; i++) + { + dinteger_t val; + switch (se->sz) + { + case 1: val = (( utf8_t *)s)[i]; break; + case 2: val = ((utf16_t *)s)[i]; break; + case 4: val = ((utf32_t *)s)[i]; break; + default: assert(0); break; + } + if (val) + return false; + } + return true; + } + + case TOKvector: + { + VectorExp *ve = (VectorExp *) exp; + return isZeroInit(ve->e1); + } + + case TOKfloat64: + case TOKcomplex80: + { + return (exp->toReal() == CTFloat::zero) && + (exp->toImaginary() == CTFloat::zero); + } + + default: + return false; + } +} + void StructDeclaration::finalizeSize() { //printf("StructDeclaration::finalizeSize() %s, sizeok = %d\n", toChars(), sizeok); @@ -1301,9 +1399,23 @@ void StructDeclaration::finalizeSize() VarDeclaration *vd = fields[i]; if (vd->_init) { - // Should examine init to see if it is really all 0's - zeroInit = 0; - break; + if (vd->_init->isVoidInitializer()) + /* Treat as 0 for the purposes of putting the initializer + * in the BSS segment, or doing a mass set to 0 + */ + continue; + + // Zero size fields are zero initialized + if (vd->type->size(vd->loc) == 0) + continue; + + // Examine init to see if it is all 0s. + Expression *exp = vd->getConstInitializer(); + if (!exp || !isZeroInit(exp)) + { + zeroInit = 0; + break; + } } else if (!vd->type->isZeroInit(loc)) { diff --git a/gcc/d/dmd/dtemplate.c b/gcc/d/dmd/dtemplate.c index fe65bd23e3c..1035f829e12 100644 --- a/gcc/d/dmd/dtemplate.c +++ b/gcc/d/dmd/dtemplate.c @@ -6783,7 +6783,7 @@ bool TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f { //printf("type %s\n", ta->toChars()); // It might really be an Expression or an Alias - ta->resolve(loc, sc, &ea, &ta, &sa); + ta->resolve(loc, sc, &ea, &ta, &sa, (flags & 1) != 0); if (ea) goto Lexpr; if (sa) goto Ldsym; if (ta == NULL) @@ -6914,7 +6914,7 @@ bool TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f //goto Ldsym; } } - if (ea->op == TOKdotvar) + if (ea->op == TOKdotvar && !(flags & 1)) { // translate expression to dsymbol. sa = ((DotVarExp *)ea)->var; @@ -6925,7 +6925,7 @@ bool TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f sa = ((TemplateExp *)ea)->td; goto Ldsym; } - if (ea->op == TOKdottd) + if (ea->op == TOKdottd && !(flags & 1)) { // translate expression to dsymbol. sa = ((DotTemplateExp *)ea)->td; diff --git a/gcc/d/dmd/expression.c b/gcc/d/dmd/expression.c index 09dd3af6eac..78918320192 100644 --- a/gcc/d/dmd/expression.c +++ b/gcc/d/dmd/expression.c @@ -3337,7 +3337,7 @@ ClassReferenceExp *Expression::isClassReferenceExp() /**************************************** - * Resolve __FILE__, __LINE__, __MODULE__, __FUNCTION__, __PRETTY_FUNCTION__ to loc. + * Resolve __FILE__, __LINE__, __MODULE__, __FUNCTION__, __PRETTY_FUNCTION__, __FILE__FULL_PATH__ to loc. */ Expression *Expression::resolveLoc(Loc, Scope *) @@ -7170,9 +7170,12 @@ FileInitExp::FileInitExp(Loc loc, TOK tok) Expression *FileInitExp::resolveLoc(Loc loc, Scope *sc) { //printf("FileInitExp::resolve() %s\n", toChars()); - const char *s = loc.filename ? loc.filename : sc->_module->ident->toChars(); + const char *s; if (subop == TOKfilefullpath) - s = FileName::combine(sc->_module->srcfilePath, s); + s = FileName::toAbsolute(loc.filename != NULL ? loc.filename : sc->_module->srcfile->name->toChars()); + else + s = loc.filename != NULL ? loc.filename : sc->_module->ident->toChars(); + Expression *e = new StringExp(loc, const_cast<char *>(s)); e = semantic(e, sc); e = e->castTo(sc, type); diff --git a/gcc/d/dmd/expressionsem.c b/gcc/d/dmd/expressionsem.c index d2519969a2c..7dfe995b711 100644 --- a/gcc/d/dmd/expressionsem.c +++ b/gcc/d/dmd/expressionsem.c @@ -119,6 +119,36 @@ static bool preFunctionParameters(Scope *sc, Expressions *exps) return err; } +/** + * Determines whether a symbol represents a module or package + * (Used as a helper for is(type == module) and is(type == package)) + * + * Params: + * sym = the symbol to be checked + * + * Returns: + * the symbol which `sym` represents (or `null` if it doesn't represent a `Package`) + */ +Package *resolveIsPackage(Dsymbol *sym) +{ + Package *pkg; + if (Import *imp = sym->isImport()) + { + if (imp->pkg == NULL) + { + error(sym->loc, "Internal Compiler Error: unable to process forward-referenced import `%s`", + imp->toChars()); + assert(0); + } + pkg = imp->pkg; + } + else + pkg = sym->isPackage(); + if (pkg) + pkg->resolvePKGunknown(); + return pkg; +} + class ExpressionSemanticVisitor : public Visitor { public: @@ -1920,15 +1950,34 @@ public: } Type *tded = NULL; - Scope *sc2 = sc->copy(); // keep sc->flags - sc2->tinst = NULL; - sc2->minst = NULL; - sc2->flags |= SCOPEfullinst; - Type *t = e->targ->trySemantic(e->loc, sc2); - sc2->pop(); - if (!t) - goto Lno; // errors, so condition is false - e->targ = t; + if (e->tok2 == TOKpackage || e->tok2 == TOKmodule) // These is() expressions are special because they can work on modules, not just types. + { + Dsymbol *sym = e->targ->toDsymbol(sc); + if (sym == NULL) + goto Lno; + Package *p = resolveIsPackage(sym); + if (p == NULL) + goto Lno; + if (e->tok2 == TOKpackage && p->isModule()) // Note that isModule() will return null for package modules because they're not actually instances of Module. + goto Lno; + else if(e->tok2 == TOKmodule && !(p->isModule() || p->isPackageMod())) + goto Lno; + tded = e->targ; + goto Lyes; + } + + { + Scope *sc2 = sc->copy(); // keep sc->flags + sc2->tinst = NULL; + sc2->minst = NULL; + sc2->flags |= SCOPEfullinst; + Type *t = e->targ->trySemantic(e->loc, sc2); + sc2->pop(); + if (!t) // errors, so condition is false + goto Lno; + e->targ = t; + } + if (e->tok2 != TOKreserved) { switch (e->tok2) diff --git a/gcc/d/dmd/func.c b/gcc/d/dmd/func.c index dbc5fa6352c..fe1ad1118e0 100644 --- a/gcc/d/dmd/func.c +++ b/gcc/d/dmd/func.c @@ -41,7 +41,6 @@ Expression *semantic(Expression *e, Scope *sc); int blockExit(Statement *s, FuncDeclaration *func, bool mustNotThrow); TypeIdentifier *getThrowable(); -RET retStyle(TypeFunction *tf); void MODtoBuffer(OutBuffer *buf, MOD mod); char *MODtoChars(MOD mod); bool MODimplicitConv(MOD modfrom, MOD modto); @@ -970,7 +969,7 @@ void FuncDeclaration::semantic(Scope *sc) { if (fdv->isFuture()) { - ::deprecation(loc, "@future base class method %s is being overridden by %s; rename the latter", + ::deprecation(loc, "@__future base class method %s is being overridden by %s; rename the latter", fdv->toPrettyChars(), toPrettyChars()); // Treat 'this' as an introducing function, giving it a separate hierarchy in the vtbl[] goto Lintro; @@ -1758,7 +1757,7 @@ void FuncDeclaration::semantic3(Scope *sc) if (storage_class & STCauto) storage_class &= ~STCauto; } - if (retStyle(f) != RETstack || checkNrvo()) + if (!target.isReturnOnStack(f, needThis()) || !checkNRVO()) nrvo_can = 0; if (fbody->isErrorStatement()) @@ -4275,19 +4274,16 @@ void FuncDeclaration::checkDmain() * using NRVO is possible. * * Returns: - * true if the result cannot be returned by hidden reference. + * `false` if the result cannot be returned by hidden reference. */ -bool FuncDeclaration::checkNrvo() +bool FuncDeclaration::checkNRVO() { - if (!nrvo_can) - return true; - - if (returns == NULL) - return true; + if (!nrvo_can || returns == NULL) + return false; TypeFunction *tf = type->toTypeFunction(); if (tf->isref) - return true; + return false; for (size_t i = 0; i < returns->length; i++) { @@ -4297,24 +4293,23 @@ bool FuncDeclaration::checkNrvo() { VarDeclaration *v = ve->var->isVarDeclaration(); if (!v || v->isOut() || v->isRef()) - return true; + return false; else if (nrvo_var == NULL) { - if (!v->isDataseg() && !v->isParameter() && v->toParent2() == this) - { - //printf("Setting nrvo to %s\n", v->toChars()); - nrvo_var = v; - } - else - return true; + // Variables in the data segment (e.g. globals, TLS or not), + // parameters and closure variables cannot be NRVOed. + if (v->isDataseg() || v->isParameter() || v->toParent2() != this) + return false; + //printf("Setting nrvo to %s\n", v->toChars()); + nrvo_var = v; } else if (nrvo_var != v) - return true; + return false; } else //if (!exp->isLvalue()) // keep NRVO-ability - return true; + return false; } - return false; + return true; } const char *FuncDeclaration::kind() const diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h index 6aff9b4b079..502bae29c48 100644 --- a/gcc/d/dmd/globals.h +++ b/gcc/d/dmd/globals.h @@ -286,7 +286,7 @@ typedef uint64_t d_uns64; // file location struct Loc { - const char *filename; + const char *filename; // either absolute or relative to cwd unsigned linnum; unsigned charnum; diff --git a/gcc/d/dmd/idgen.c b/gcc/d/dmd/idgen.c index 16f3b5f29ec..09855a05688 100644 --- a/gcc/d/dmd/idgen.c +++ b/gcc/d/dmd/idgen.c @@ -322,6 +322,9 @@ Msgtable msgtable[] = { "isFinalClass", NULL }, { "isTemplate", NULL }, { "isPOD", NULL }, + { "isDeprecated", NULL }, + { "isDisabled", NULL }, + { "isFuture" , NULL }, { "isNested", NULL }, { "isFloating", NULL }, { "isIntegral", NULL }, @@ -334,13 +337,17 @@ Msgtable msgtable[] = { "isFinalFunction", NULL }, { "isOverrideFunction", NULL }, { "isStaticFunction", NULL }, + { "isModule", NULL }, + { "isPackage", NULL }, { "isRef", NULL }, { "isOut", NULL }, { "isLazy", NULL }, { "hasMember", NULL }, { "identifier", NULL }, { "getProtection", NULL }, + { "getVisibility", NULL }, { "parent", NULL }, + { "child", NULL }, { "getMember", NULL }, { "getOverloads", NULL }, { "getVirtualFunctions", NULL }, @@ -360,6 +367,12 @@ Msgtable msgtable[] = { "getUnitTests", NULL }, { "getVirtualIndex", NULL }, { "getPointerBitmap", NULL }, + { "isReturnOnStack", NULL }, + { "isZeroInit", NULL }, + { "getTargetInfo", NULL }, + { "getLocation", NULL }, + { "hasPostblit", NULL }, + { "isCopyable", NULL }, // For C++ mangling { "allocator", NULL }, diff --git a/gcc/d/dmd/module.h b/gcc/d/dmd/module.h index 17ad5904523..4968ec7e1b5 100644 --- a/gcc/d/dmd/module.h +++ b/gcc/d/dmd/module.h @@ -48,6 +48,7 @@ public: void accept(Visitor *v) { v->visit(this); } Module *isPackageMod(); + void resolvePKGunknown(); }; class Module : public Package @@ -68,7 +69,6 @@ public: const char *arg; // original argument name ModuleDeclaration *md; // if !NULL, the contents of the ModuleDeclaration declaration File *srcfile; // input source file - const char* srcfilePath; // the path prefix to the srcfile if it applies File *objfile; // output .obj file File *hdrfile; // 'header' file File *docfile; // output documentation file diff --git a/gcc/d/dmd/mtype.c b/gcc/d/dmd/mtype.c index 6f0195af305..94e2082f5b2 100644 --- a/gcc/d/dmd/mtype.c +++ b/gcc/d/dmd/mtype.c @@ -6682,6 +6682,7 @@ Type *TypeTraits::semantic(Loc, Scope *sc) exp->ident != Id::derivedMembers && exp->ident != Id::getMember && exp->ident != Id::parent && + exp->ident != Id::child && exp->ident != Id::getOverloads && exp->ident != Id::getVirtualFunctions && exp->ident != Id::getVirtualMethods && diff --git a/gcc/d/dmd/parse.c b/gcc/d/dmd/parse.c index 3e4dd066c31..be861fa92f6 100644 --- a/gcc/d/dmd/parse.c +++ b/gcc/d/dmd/parse.c @@ -5949,7 +5949,10 @@ bool Parser::isDeclaration(Token *t, int needId, TOK endtok, Token **pt) } if (!isDeclarator(&t, &haveId, &haveTpl, endtok, needId != 3)) goto Lisnot; - if (needId == 1 || (needId == 0 && !haveId) || ((needId == 2 || needId == 3) && haveId)) + if ((needId == 0 && !haveId) || + (needId == 1) || + (needId == 2 && haveId) || + (needId == 3 && haveId)) { if (pt) *pt = t; @@ -6821,12 +6824,8 @@ Expression *Parser::parsePrimaryExp() case TOKfilefullpath: { - const char *srcfile = mod->srcfile->name->toChars(); - const char *s; - if (loc.filename && !FileName::equals(loc.filename, srcfile)) - s = loc.filename; - else - s = FileName::combine(mod->srcfilePath, srcfile); + assert(loc.filename); // __FILE_FULL_PATH__ does not work with an invalid location + const char *s = FileName::toAbsolute(loc.filename); e = new StringExp(loc, const_cast<char *>(s), strlen(s), 0); nextToken(); break; @@ -7039,6 +7038,8 @@ Expression *Parser::parsePrimaryExp() token.value == TOKsuper || token.value == TOKenum || token.value == TOKinterface || + token.value == TOKmodule || + token.value == TOKpackage || token.value == TOKargTypes || token.value == TOKparameters || (token.value == TOKconst && peek(&token)->value == TOKrparen) || diff --git a/gcc/d/dmd/root/filename.c b/gcc/d/dmd/root/filename.c index 50b67404062..f0e0213e701 100644 --- a/gcc/d/dmd/root/filename.c +++ b/gcc/d/dmd/root/filename.c @@ -175,6 +175,20 @@ bool FileName::absolute(const char *name) #endif } +/** +Return the given name as an absolute path + +Params: + name = path + base = the absolute base to prefix name with if it is relative + +Returns: name as an absolute path relative to base +*/ +const char *FileName::toAbsolute(const char *name, const char *base) +{ + return absolute(name) ? name : combine(base ? base : getcwd(NULL, 0), name); +} + /******************************** * Return filename extension (read-only). * Points past '.' of extension. diff --git a/gcc/d/dmd/root/filename.h b/gcc/d/dmd/root/filename.h index 62a5a6869a1..6ef515c6441 100644 --- a/gcc/d/dmd/root/filename.h +++ b/gcc/d/dmd/root/filename.h @@ -24,6 +24,7 @@ struct FileName int compare(RootObject *obj); static int compare(const char *name1, const char *name2); static bool absolute(const char *name); + static const char *toAbsolute(const char *name, const char *base = NULL); static const char *ext(const char *); const char *ext(); static const char *removeExt(const char *str); diff --git a/gcc/d/dmd/target.h b/gcc/d/dmd/target.h index f2a55d6a134..5a2dd4d9133 100644 --- a/gcc/d/dmd/target.h +++ b/gcc/d/dmd/target.h @@ -22,6 +22,7 @@ class Expression; class FuncDeclaration; class Parameter; class Type; +class TypeFunction; class TypeTuple; struct OutBuffer; @@ -105,6 +106,8 @@ public: // ABI and backend. LINK systemLinkage(); TypeTuple *toArgTypes(Type *t); + bool isReturnOnStack(TypeFunction *tf, bool needsThis); + Expression *getTargetInfo(const char* name, const Loc& loc); }; extern Target target; diff --git a/gcc/d/dmd/traits.c b/gcc/d/dmd/traits.c index bc1e2c3c234..658529943ea 100644 --- a/gcc/d/dmd/traits.c +++ b/gcc/d/dmd/traits.c @@ -32,11 +32,13 @@ #include "attrib.h" #include "parse.h" #include "root/speller.h" +#include "target.h" typedef int (*ForeachDg)(void *ctx, size_t idx, Dsymbol *s); int ScopeDsymbol_foreach(Scope *sc, Dsymbols *members, ForeachDg dg, void *ctx, size_t *pn = NULL); void freeFieldinit(Scope *sc); Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads); +Package *resolveIsPackage(Dsymbol *sym); Expression *trySemantic(Expression *e, Scope *sc); Expression *semantic(Expression *e, Scope *sc); Expression *typeToExpression(Type *t); @@ -49,32 +51,69 @@ Expression *typeToExpression(Type *t); struct Ptrait { + Dsymbol *sym; Expression *e1; Expressions *exps; // collected results Identifier *ident; // which trait we're looking for + bool includeTemplates; + AA **funcTypeHash; }; +/* Compute the function signature and insert it in the + * hashtable, if not present. This is needed so that + * traits(getOverlods, F3, "visit") does not count `int visit(int)` + * twice in the following example: + * + * ============================================= + * interface F1 { int visit(int);} + * interface F2 { int visit(int); void visit(); } + * interface F3 : F2, F1 {} + *============================================== + */ +static void insertInterfaceInheritedFunction(Ptrait *p, FuncDeclaration *fd, Expression *e) +{ + Identifier *signature = Identifier::idPool(fd->type->toChars()); + //printf("%s - %s\n", fd->toChars, signature); + if (!dmd_aaGetRvalue(*p->funcTypeHash, (void *)signature)) + { + bool* value = (bool*) dmd_aaGet(p->funcTypeHash, (void *)signature); + *value = true; + p->exps->push(e); + } +} + static int fptraits(void *param, Dsymbol *s) { - FuncDeclaration *f = s->isFuncDeclaration(); - if (!f) + Ptrait *p = (Ptrait *)param; + if (p->includeTemplates) + { + p->exps->push(new DsymbolExp(Loc(),s, false)); + return 0; + } + FuncDeclaration *fd = s->isFuncDeclaration(); + if (!fd) return 0; - Ptrait *p = (Ptrait *)param; - if (p->ident == Id::getVirtualFunctions && !f->isVirtual()) + if (p->ident == Id::getVirtualFunctions && !fd->isVirtual()) return 0; - if (p->ident == Id::getVirtualMethods && !f->isVirtualMethod()) + if (p->ident == Id::getVirtualMethods && !fd->isVirtualMethod()) return 0; Expression *e; - FuncAliasDeclaration* ad = new FuncAliasDeclaration(f->ident, f, false); - ad->protection = f->protection; + FuncAliasDeclaration* ad = new FuncAliasDeclaration(fd->ident, fd, false); + ad->protection = fd->protection; if (p->e1) e = new DotVarExp(Loc(), p->e1, ad, false); else e = new DsymbolExp(Loc(), ad, false); - p->exps->push(e); + // if the parent is an interface declaration + // we must check for functions with the same signature + // in different inherited interfaces + if (p->sym && p->sym->isInterfaceDeclaration()) + insertInterfaceInheritedFunction(p, fd, e); + else + p->exps->push(e); return 0; } @@ -126,22 +165,111 @@ static void collectUnitTests(Dsymbols *symbols, AA *uniqueUnitTests, Expressions } } +/*************************************************** + * Determine if type t is copyable. + * Params: + * t = type to check + * Returns: + * true if we can copy it + */ +static bool isCopyable(Type *t) +{ + //printf("isCopyable() %s\n", t->toChars()); + if (TypeStruct *ts = t->isTypeStruct()) + { + if (ts->sym->postblit && + (ts->sym->postblit->storage_class & STCdisable)) + return false; + } + return true; +} + /************************ TraitsExp ************************************/ static Expression *True(TraitsExp *e) { return new IntegerExp(e->loc, true, Type::tbool); } static Expression *False(TraitsExp *e) { return new IntegerExp(e->loc, false, Type::tbool); } -bool isTypeArithmetic(Type *t) { return t->isintegral() || t->isfloating(); } -bool isTypeFloating(Type *t) { return t->isfloating(); } -bool isTypeIntegral(Type *t) { return t->isintegral(); } -bool isTypeScalar(Type *t) { return t->isscalar(); } -bool isTypeUnsigned(Type *t) { return t->isunsigned(); } -bool isTypeAssociativeArray(Type *t) { return t->toBasetype()->ty == Taarray; } -bool isTypeStaticArray(Type *t) { return t->toBasetype()->ty == Tsarray; } -bool isTypeAbstractClass(Type *t) { return t->toBasetype()->ty == Tclass && ((TypeClass *)t->toBasetype())->sym->isAbstract(); } -bool isTypeFinalClass(Type *t) { return t->toBasetype()->ty == Tclass && (((TypeClass *)t->toBasetype())->sym->storage_class & STCfinal) != 0; } - -Expression *isTypeX(TraitsExp *e, bool (*fp)(Type *t)) +/************************************** + * Convert `Expression` or `Type` to corresponding `Dsymbol`, + * additionally strip off expression contexts. + * + * Some symbol related `__traits` ignore arguments expression contexts. + * For example: + * struct S { void f() {} } + * S s; + * pragma(msg, __traits(isNested, s.f)); + * // s.f is DotVarExp, but __traits(isNested) needs a FuncDeclaration. + * + * This is used for that common `__traits` behavior. + */ +static Dsymbol *getDsymbolWithoutExpCtx(RootObject *oarg) +{ + if (Expression *e = isExpression(oarg)) + { + if (e->op == TOKdotvar) + return ((DotVarExp *)e)->var; + if (e->op == TOKdottd) + return ((DotTemplateExp *)e)->td; + } + return getDsymbol(oarg); +} + +/** + Gets the function type from a given AST node + if the node is a function of some sort. + + Params: + o = an AST node to check for a `TypeFunction` + fdp = optional pointer to a function declararion, to be set + if `o` is a function declarartion. + + Returns: + a type node if `o` is a declaration of + a delegate, function, function-pointer + or a variable of the former. Otherwise, `null`. +*/ +static TypeFunction *toTypeFunction(RootObject *o, FuncDeclaration **fdp = NULL) +{ + Dsymbol *s = getDsymbolWithoutExpCtx(o); + Type *t = isType(o); + TypeFunction *tf = NULL; + + if (s) + { + FuncDeclaration *fd = s->isFuncDeclaration(); + if (fd) + { + t = fd->type; + if (fdp) + *fdp = fd; + } + else if (VarDeclaration *vd = s->isVarDeclaration()) + t = vd->type; + } + if (t) + { + if (t->ty == Tfunction) + tf = (TypeFunction *)t; + else if (t->ty == Tdelegate) + tf = (TypeFunction *)t->nextOf(); + else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction) + tf = (TypeFunction *)t->nextOf(); + } + + return tf; +} + +static bool isTypeArithmetic(Type *t) { return t->isintegral() || t->isfloating(); } +static bool isTypeFloating(Type *t) { return t->isfloating(); } +static bool isTypeIntegral(Type *t) { return t->isintegral(); } +static bool isTypeScalar(Type *t) { return t->isscalar(); } +static bool isTypeUnsigned(Type *t) { return t->isunsigned(); } +static bool isTypeAssociativeArray(Type *t) { return t->toBasetype()->ty == Taarray; } +static bool isTypeStaticArray(Type *t) { return t->toBasetype()->ty == Tsarray; } +static bool isTypeAbstractClass(Type *t) { return t->toBasetype()->ty == Tclass && ((TypeClass *)t->toBasetype())->sym->isAbstract(); } +static bool isTypeFinalClass(Type *t) { return t->toBasetype()->ty == Tclass && (((TypeClass *)t->toBasetype())->sym->storage_class & STCfinal) != 0; } + +static Expression *isTypeX(TraitsExp *e, bool (*fp)(Type *t)) { if (!e->args || !e->args->length) return False(e); @@ -154,20 +282,52 @@ Expression *isTypeX(TraitsExp *e, bool (*fp)(Type *t)) return True(e); } -bool isFuncAbstractFunction(FuncDeclaration *f) { return f->isAbstract(); } -bool isFuncVirtualFunction(FuncDeclaration *f) { return f->isVirtual(); } -bool isFuncVirtualMethod(FuncDeclaration *f) { return f->isVirtualMethod(); } -bool isFuncFinalFunction(FuncDeclaration *f) { return f->isFinalFunc(); } -bool isFuncStaticFunction(FuncDeclaration *f) { return !f->needThis() && !f->isNested(); } -bool isFuncOverrideFunction(FuncDeclaration *f) { return f->isOverride(); } +static bool isDsymDeprecated(Dsymbol *s) { return s->isDeprecated(); } + +static int fpisTemplate(void *, Dsymbol *s) +{ + if (s->isTemplateDeclaration()) + return 1; + + return 0; +} + +bool isTemplate(Dsymbol *s) +{ + if (!s->toAlias()->isOverloadable()) + return false; + + return overloadApply(s, NULL, &fpisTemplate) != 0; +} + +static Expression *isDsymX(TraitsExp *e, bool (*fp)(Dsymbol *s)) +{ + if (!e->args || !e->args->length) + return False(e); + for (size_t i = 0; i < e->args->length; i++) + { + Dsymbol *s = getDsymbolWithoutExpCtx((*e->args)[i]); + if (!s || !fp(s)) + return False(e); + } + return True(e); +} + +static bool isFuncDisabled(FuncDeclaration *f) { return f->isDisabled(); } +static bool isFuncAbstractFunction(FuncDeclaration *f) { return f->isAbstract(); } +static bool isFuncVirtualFunction(FuncDeclaration *f) { return f->isVirtual(); } +static bool isFuncVirtualMethod(FuncDeclaration *f) { return f->isVirtualMethod(); } +static bool isFuncFinalFunction(FuncDeclaration *f) { return f->isFinalFunc(); } +static bool isFuncStaticFunction(FuncDeclaration *f) { return !f->needThis() && !f->isNested(); } +static bool isFuncOverrideFunction(FuncDeclaration *f) { return f->isOverride(); } -Expression *isFuncX(TraitsExp *e, bool (*fp)(FuncDeclaration *f)) +static Expression *isFuncX(TraitsExp *e, bool (*fp)(FuncDeclaration *f)) { if (!e->args || !e->args->length) return False(e); for (size_t i = 0; i < e->args->length; i++) { - Dsymbol *s = getDsymbol((*e->args)[i]); + Dsymbol *s = getDsymbolWithoutExpCtx((*e->args)[i]); if (!s) return False(e); FuncDeclaration *f = s->isFuncDeclaration(); @@ -177,17 +337,18 @@ Expression *isFuncX(TraitsExp *e, bool (*fp)(FuncDeclaration *f)) return True(e); } -bool isDeclRef(Declaration *d) { return d->isRef(); } -bool isDeclOut(Declaration *d) { return d->isOut(); } -bool isDeclLazy(Declaration *d) { return (d->storage_class & STClazy) != 0; } +static bool isDeclFuture(Declaration *d) { return d->isFuture(); } +static bool isDeclRef(Declaration *d) { return d->isRef(); } +static bool isDeclOut(Declaration *d) { return d->isOut(); } +static bool isDeclLazy(Declaration *d) { return (d->storage_class & STClazy) != 0; } -Expression *isDeclX(TraitsExp *e, bool (*fp)(Declaration *d)) +static Expression *isDeclX(TraitsExp *e, bool (*fp)(Declaration *d)) { if (!e->args || !e->args->length) return False(e); for (size_t i = 0; i < e->args->length; i++) { - Dsymbol *s = getDsymbol((*e->args)[i]); + Dsymbol *s = getDsymbolWithoutExpCtx((*e->args)[i]); if (!s) return False(e); Declaration *d = s->isDeclaration(); @@ -197,6 +358,25 @@ Expression *isDeclX(TraitsExp *e, bool (*fp)(Declaration *d)) return True(e); } +static bool isPkgModule(Package *p) { return p->isModule() || p->isPackageMod(); } +static bool isPkgPackage(Package *p) { return p->isModule() == NULL; } + +static Expression *isPkgX(TraitsExp *e, bool (*fp)(Package *p)) +{ + if (!e->args || !e->args->length) + return False(e); + for (size_t i = 0; i < e->args->length; i++) + { + Dsymbol *s = getDsymbolWithoutExpCtx((*e->args)[i]); + if (!s) + return False(e); + Package *p = resolveIsPackage(s); + if (!p || !fp(p)) + return False(e); + } + return True(e); +} + // callback for TypeFunction::attributesApply struct PushAttributes { @@ -225,6 +405,9 @@ TraitsInitializer::TraitsInitializer() "isAbstractClass", "isArithmetic", "isAssociativeArray", + "isDisabled", + "isDeprecated", + "isFuture", "isFinalClass", "isPOD", "isNested", @@ -239,13 +422,18 @@ TraitsInitializer::TraitsInitializer() "isFinalFunction", "isOverrideFunction", "isStaticFunction", + "isModule", + "isPackage", "isRef", "isOut", "isLazy", + "isReturnOnStack", "hasMember", "identifier", "getProtection", + "getVisibility", "parent", + "child", "getLinkage", "getMember", "getOverloads", @@ -265,10 +453,15 @@ TraitsInitializer::TraitsInitializer() "getUnitTests", "getVirtualIndex", "getPointerBitmap", + "isZeroInit", + "getTargetInfo", + "getLocation", + "hasPostblit", + "isCopyable", NULL }; - traitsStringTable._init(40); + traitsStringTable._init(56); for (size_t idx = 0;; idx++) { @@ -291,35 +484,6 @@ void *trait_search_fp(void *, const char *seed, int* cost) return sv ? (void*)sv->ptrvalue : NULL; } -static int fpisTemplate(void *, Dsymbol *s) -{ - if (s->isTemplateDeclaration()) - return 1; - - return 0; -} - -bool isTemplate(Dsymbol *s) -{ - if (!s->toAlias()->isOverloadable()) - return false; - - return overloadApply(s, NULL, &fpisTemplate) != 0; -} - -Expression *isSymbolX(TraitsExp *e, bool (*fp)(Dsymbol *s)) -{ - if (!e->args || !e->args->length) - return False(e); - for (size_t i = 0; i < e->args->length; i++) - { - Dsymbol *s = getDsymbol((*e->args)[i]); - if (!s || !fp(s)) - return False(e); - } - return True(e); -} - /** * get an array of size_t values that indicate possible pointer words in memory * if interpreted as the type given as argument @@ -491,11 +655,22 @@ static Expression *dimError(TraitsExp *e, int expected, int dim) Expression *semanticTraits(TraitsExp *e, Scope *sc) { - if (e->ident != Id::compiles && e->ident != Id::isSame && - e->ident != Id::identifier && e->ident != Id::getProtection) + if (e->ident != Id::compiles && + e->ident != Id::isSame && + e->ident != Id::identifier && + e->ident != Id::getProtection && e->ident != Id::getVisibility) { + // Pretend we're in a deprecated scope so that deprecation messages + // aren't triggered when checking if a symbol is deprecated + const StorageClass save = sc->stc; + if (e->ident == Id::isDeprecated) + sc->stc |= STCdeprecated; if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 1)) + { + sc->stc = save; return new ErrorExp(); + } + sc->stc = save; } size_t dim = e->args ? e->args->length : 0; @@ -523,6 +698,14 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) { return isTypeX(e, &isTypeAssociativeArray); } + else if (e->ident == Id::isDeprecated) + { + return isDsymX(e, &isDsymDeprecated); + } + else if (e->ident == Id::isFuture) + { + return isDeclX(e, &isDeclFuture); + } else if (e->ident == Id::isStaticArray) { return isTypeX(e, &isTypeStaticArray); @@ -537,7 +720,10 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) } else if (e->ident == Id::isTemplate) { - return isSymbolX(e, &isTemplate); + if (dim != 1) + return dimError(e, 1, dim); + + return isDsymX(e, &isTemplate); } else if (e->ident == Id::isPOD) { @@ -560,13 +746,50 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) } return True(e); } + else if (e->ident == Id::hasPostblit) + { + if (dim != 1) + return dimError(e, 1, dim); + + RootObject *o = (*e->args)[0]; + Type *t = isType(o); + if (!t) + { + e->error("type expected as second argument of __traits %s instead of %s", + e->ident->toChars(), o->toChars()); + return new ErrorExp(); + } + + Type *tb = t->baseElemOf(); + if (StructDeclaration *sd = (tb->ty == Tstruct) ? ((TypeStruct *)tb)->sym : NULL) + { + return sd->postblit ? True(e) : False(e); + } + return False(e); + } + else if (e->ident == Id::isCopyable) + { + if (dim != 1) + return dimError(e, 1, dim); + + RootObject *o = (*e->args)[0]; + Type *t = isType(o); + if (!t) + { + e->error("type expected as second argument of __traits %s instead of %s", + e->ident->toChars(), o->toChars()); + return new ErrorExp(); + } + + return isCopyable(t) ? True(e) : False(e); + } else if (e->ident == Id::isNested) { if (dim != 1) return dimError(e, 1, dim); RootObject *o = (*e->args)[0]; - Dsymbol *s = getDsymbol(o); + Dsymbol *s = getDsymbolWithoutExpCtx(o); if (!s) { } @@ -582,40 +805,88 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) e->error("aggregate or function expected instead of '%s'", o->toChars()); return new ErrorExp(); } + else if (e->ident == Id::isDisabled) + { + if (dim != 1) + return dimError(e, 1, dim); + + return isFuncX(e, &isFuncDisabled); + } else if (e->ident == Id::isAbstractFunction) { + if (dim != 1) + return dimError(e, 1, dim); + return isFuncX(e, &isFuncAbstractFunction); } else if (e->ident == Id::isVirtualFunction) { + if (dim != 1) + return dimError(e, 1, dim); + return isFuncX(e, &isFuncVirtualFunction); } else if (e->ident == Id::isVirtualMethod) { + if (dim != 1) + return dimError(e, 1, dim); + return isFuncX(e, &isFuncVirtualMethod); } else if (e->ident == Id::isFinalFunction) { + if (dim != 1) + return dimError(e, 1, dim); + return isFuncX(e, &isFuncFinalFunction); } else if (e->ident == Id::isOverrideFunction) { + if (dim != 1) + return dimError(e, 1, dim); + return isFuncX(e, &isFuncOverrideFunction); } else if (e->ident == Id::isStaticFunction) { + if (dim != 1) + return dimError(e, 1, dim); + return isFuncX(e, &isFuncStaticFunction); } + else if (e->ident == Id::isModule) + { + if (dim != 1) + return dimError(e, 1, dim); + + return isPkgX(e, &isPkgModule); + } + else if (e->ident == Id::isPackage) + { + if (dim != 1) + return dimError(e, 1, dim); + + return isPkgX(e, &isPkgPackage); + } else if (e->ident == Id::isRef) { + if (dim != 1) + return dimError(e, 1, dim); + return isDeclX(e, &isDeclRef); } else if (e->ident == Id::isOut) { + if (dim != 1) + return dimError(e, 1, dim); + return isDeclX(e, &isDeclOut); } else if (e->ident == Id::isLazy) { + if (dim != 1) + return dimError(e, 1, dim); + return isDeclX(e, &isDeclLazy); } else if (e->ident == Id::identifier) @@ -639,7 +910,7 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) } else { - Dsymbol *s = getDsymbol(o); + Dsymbol *s = getDsymbolWithoutExpCtx(o); if (!s || !s->ident) { e->error("argument %s has no identifier", o->toChars()); @@ -651,7 +922,7 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) StringExp *se = new StringExp(e->loc, const_cast<char *>(id->toChars())); return semantic(se, sc); } - else if (e->ident == Id::getProtection) + else if (e->ident == Id::getProtection || e->ident == Id::getVisibility) { if (dim != 1) return dimError(e, 1, dim); @@ -664,7 +935,7 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) return new ErrorExp(); RootObject *o = (*e->args)[0]; - Dsymbol *s = getDsymbol(o); + Dsymbol *s = getDsymbolWithoutExpCtx(o); if (!s) { if (!isError(o)) @@ -685,7 +956,7 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) return dimError(e, 1, dim); RootObject *o = (*e->args)[0]; - Dsymbol *s = getDsymbol(o); + Dsymbol *s = getDsymbolWithoutExpCtx(o); if (s) { if (FuncDeclaration *fd = s->isFuncDeclaration()) // Bugzilla 8943 @@ -720,13 +991,51 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) return resolve(e->loc, sc, s, false); } + else if (e->ident == Id::child) + { + if (dim != 2) + return dimError(e, 2, dim); + + Expression *ex; + RootObject *op = (*e->args)[0]; + if (Dsymbol *symp = getDsymbol(op)) + ex = new DsymbolExp(e->loc, symp); + else if (Expression *exp = isExpression(op)) + ex = exp; + else + { + e->error("symbol or expression expected as first argument of __traits `child` instead of `%s`", op->toChars()); + return new ErrorExp(); + } + + ex = semantic(ex, sc); + RootObject *oc = (*e->args)[1]; + Dsymbol *symc = getDsymbol(oc); + if (!symc) + { + e->error("symbol expected as second argument of __traits `child` instead of `%s`", oc->toChars()); + return new ErrorExp(); + } + + if (Declaration *d = symc->isDeclaration()) + ex = new DotVarExp(e->loc, ex, d); + else if (TemplateDeclaration *td = symc->isTemplateDeclaration()) + ex = new DotExp(e->loc, ex, new TemplateExp(e->loc, td)); + else if (ScopeDsymbol *ti = symc->isScopeDsymbol()) + ex = new DotExp(e->loc, ex, new ScopeExp(e->loc, ti)); + else + assert(0); + + ex = semantic(ex, sc); + return ex; + } else if (e->ident == Id::hasMember || e->ident == Id::getMember || e->ident == Id::getOverloads || e->ident == Id::getVirtualMethods || e->ident == Id::getVirtualFunctions) { - if (dim != 2) + if (dim != 2 && !(dim == 3 && e->ident == Id::getOverloads)) return dimError(e, 2, dim); RootObject *o = (*e->args)[0]; @@ -738,6 +1047,19 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) } ex = ex->ctfeInterpret(); + bool includeTemplates = false; + if (dim == 3 && e->ident == Id::getOverloads) + { + Expression *b = isExpression((*e->args)[2]); + b = b->ctfeInterpret(); + if (!b->type->equals(Type::tbool)) + { + e->error("`bool` expected as third argument of `__traits(getOverloads)`, not `%s` of type `%s`", b->toChars(), b->type->toChars()); + return new ErrorExp(); + } + includeTemplates = b->isBool(true); + } + StringExp *se = ex->toStringExp(); if (!se || se->len == 0) { @@ -758,6 +1080,11 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) Dsymbol *sym = getDsymbol(o); if (sym) { + if (e->ident == Id::hasMember) + { + if (sym->search(e->loc, id) != NULL) + return True(e); + } ex = new DsymbolExp(e->loc, sym); ex = new DotIdExp(e->loc, ex, id); } @@ -773,12 +1100,6 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) if (e->ident == Id::hasMember) { - if (sym) - { - if (sym->search(e->loc, id)) - return True(e); - } - /* Take any errors as meaning it wasn't found */ Scope *scx = sc->push(); @@ -814,7 +1135,7 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) /* Create tuple of functions of ex */ Expressions *exps = new Expressions(); - FuncDeclaration *f; + Dsymbol *f; if (ex->op == TOKvar) { VarExp *ve = (VarExp *)ex; @@ -830,13 +1151,43 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) else ex = dve->e1; } + else if (ex->op == TOKtemplate) + { + TemplateExp *te = (TemplateExp *)ex; + TemplateDeclaration *td = te->td; + f = td; + if (td && td->funcroot) + f = td->funcroot; + ex = NULL; + } else f = NULL; Ptrait p; + p.sym = sym; p.exps = exps; p.e1 = ex; p.ident = e->ident; - overloadApply(f, &p, &fptraits); + p.includeTemplates = includeTemplates; + AA *funcTypeHash = NULL; + p.funcTypeHash = &funcTypeHash; + + InterfaceDeclaration *ifd = NULL; + if (sym) + ifd = sym->isInterfaceDeclaration(); + // If the symbol passed as a parameter is an + // interface that inherits other interfaces + if (ifd && ifd->interfaces.length) + { + // check the overloads of each inherited interface individually + for (size_t i = 0; i < ifd->interfaces.length; i++) + { + BaseClass *bc = ifd->interfaces.ptr[i]; + if (Dsymbol *fd = bc->sym->search(e->loc, f->ident)) + overloadApply(fd, &p, &fptraits); + } + } + else + overloadApply(f, &p, &fptraits); ex = new TupleExp(e->loc, exps); ex = semantic(ex, scx); @@ -898,7 +1249,7 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) return dimError(e, 1, dim); RootObject *o = (*e->args)[0]; - Dsymbol *s = getDsymbol(o); + Dsymbol *s = getDsymbolWithoutExpCtx(o); if (!s) { e->error("first argument is not a symbol"); @@ -917,30 +1268,14 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) } else if (e->ident == Id::getFunctionAttributes) { - /// extract all function attributes as a tuple (const/shared/inout/pure/nothrow/etc) except UDAs. + /* extract all function attributes as a tuple (const/shared/inout/pure/nothrow/etc) except UDAs. + * https://dlang.org/spec/traits.html#getFunctionAttributes + */ if (dim != 1) return dimError(e, 1, dim); - RootObject *o = (*e->args)[0]; - Dsymbol *s = getDsymbol(o); - Type *t = isType(o); - TypeFunction *tf = NULL; - if (s) - { - if (FuncDeclaration *f = s->isFuncDeclaration()) - t = f->type; - else if (VarDeclaration *v = s->isVarDeclaration()) - t = v->type; - } - if (t) - { - if (t->ty == Tfunction) - tf = (TypeFunction *)t; - else if (t->ty == Tdelegate) - tf = (TypeFunction *)t->nextOf(); - else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction) - tf = (TypeFunction *)t->nextOf(); - } + TypeFunction *tf = toTypeFunction((*e->args)[0]); + if (!tf) { e->error("first argument is not a function"); @@ -956,6 +1291,27 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) TupleExp *tup = new TupleExp(e->loc, mods); return semantic(tup, sc); } + else if (e->ident == Id::isReturnOnStack) + { + /* Extract as a boolean if function return value is on the stack + * https://dlang.org/spec/traits.html#isReturnOnStack + */ + if (dim != 1) + return dimError(e, 1, dim); + + RootObject *o = (*e->args)[0]; + FuncDeclaration *fd = NULL; + TypeFunction *tf = toTypeFunction(o, &fd); + + if (!tf) + { + e->error("argument to `__traits(isReturnOnStack, %s)` is not a function", o->toChars()); + return new ErrorExp(); + } + + bool value = target.isReturnOnStack(tf, fd && fd->needThis()); + return new IntegerExp(e->loc, value, Type::tbool); + } else if (e->ident == Id::getFunctionVariadicStyle) { /* Accept a symbol or a type. Returns one of the following: @@ -971,17 +1327,9 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) LINK link; VarArg varargs; RootObject *o = (*e->args)[0]; - Type *t = isType(o); - TypeFunction *tf = NULL; - if (t) - { - if (t->ty == Tfunction) - tf = (TypeFunction *)t; - else if (t->ty == Tdelegate) - tf = (TypeFunction *)t->nextOf(); - else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction) - tf = (TypeFunction *)t->nextOf(); - } + FuncDeclaration *fd = NULL; + TypeFunction *tf = toTypeFunction(o, &fd); + if (tf) { link = tf->linkage; @@ -989,9 +1337,7 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) } else { - Dsymbol *s = getDsymbol(o); - FuncDeclaration *fd = NULL; - if (!s || (fd = s->isFuncDeclaration()) == NULL) + if (!fd) { e->error("argument to `__traits(getFunctionVariadicStyle, %s)` is not a function", o->toChars()); return new ErrorExp(); @@ -1021,19 +1367,12 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) if (dim != 2) return dimError(e, 2, dim); - RootObject *o1 = (*e->args)[1]; RootObject *o = (*e->args)[0]; - Type *t = isType(o); - TypeFunction *tf = NULL; - if (t) - { - if (t->ty == Tfunction) - tf = (TypeFunction *)t; - else if (t->ty == Tdelegate) - tf = (TypeFunction *)t->nextOf(); - else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction) - tf = (TypeFunction *)t->nextOf(); - } + RootObject *o1 = (*e->args)[1]; + + FuncDeclaration *fd = NULL; + TypeFunction *tf = toTypeFunction(o, &fd); + ParameterList fparams; if (tf) { @@ -1041,9 +1380,7 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) } else { - Dsymbol *s = getDsymbol(o); - FuncDeclaration *fd = NULL; - if (!s || (fd = s->isFuncDeclaration()) == NULL) + if (!fd) { e->error("first argument to `__traits(getParameterStorageClasses, %s, %s)` is not a function", o->toChars(), o1->toChars()); @@ -1118,17 +1455,9 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) LINK link; RootObject *o = (*e->args)[0]; - Type *t = isType(o); - TypeFunction *tf = NULL; - if (t) - { - if (t->ty == Tfunction) - tf = (TypeFunction *)t; - else if (t->ty == Tdelegate) - tf = (TypeFunction *)t->nextOf(); - else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction) - tf = (TypeFunction *)t->nextOf(); - } + + TypeFunction *tf = toTypeFunction(o); + if (tf) link = tf->linkage; else @@ -1421,7 +1750,7 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) return dimError(e, 1, dim); RootObject *o = (*e->args)[0]; - Dsymbol *s = getDsymbol(o); + Dsymbol *s = getDsymbolWithoutExpCtx(o); if (!s) { e->error("argument %s to __traits(getUnitTests) must be a module or aggregate", @@ -1455,7 +1784,7 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) return dimError(e, 1, dim); RootObject *o = (*e->args)[0]; - Dsymbol *s = getDsymbol(o); + Dsymbol *s = getDsymbolWithoutExpCtx(o); FuncDeclaration *fd = s ? s->isFuncDeclaration() : NULL; if (!fd) @@ -1471,6 +1800,75 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) { return pointerBitmap(e); } + else if (e->ident == Id::isZeroInit) + { + if (dim != 1) + return dimError(e, 1, dim); + + RootObject *o = (*e->args)[0]; + Type *t = isType(o); + if (!t) + { + e->error("type expected as second argument of __traits `%s` instead of `%s`", + e->ident->toChars(), o->toChars()); + return new ErrorExp(); + } + + Type *tb = t->baseElemOf(); + return tb->isZeroInit(e->loc) ? True(e) : False(e); + } + else if (e->ident == Id::getTargetInfo) + { + if (dim != 1) + return dimError(e, 1, dim); + + Expression *ex = isExpression((*e->args)[0]); + StringExp *se = ex ? ex->ctfeInterpret()->toStringExp() : NULL; + if (!ex || !se || se->len == 0) + { + e->error("string expected as argument of __traits `%s` instead of `%s`", e->ident->toChars(), ex->toChars()); + return new ErrorExp(); + } + se = se->toUTF8(sc); + + Expression *r = target.getTargetInfo(se->toPtr(), e->loc); + if (!r) + { + e->error("`getTargetInfo` key `\"%s\"` not supported by this implementation", se->toPtr()); + return new ErrorExp(); + } + return semantic(r, sc); + } + else if (e->ident == Id::getLocation) + { + if (dim != 1) + return dimError(e, 1, dim); + RootObject *arg0 = (*e->args)[0]; + Dsymbol *s = getDsymbolWithoutExpCtx(arg0); + if (!s || !s->loc.filename) + { + e->error("can only get the location of a symbol, not `%s`", arg0->toChars()); + return new ErrorExp(); + } + + const FuncDeclaration *fd = s->isFuncDeclaration(); + if (fd && fd->overnext) + { + e->error("cannot get location of an overload set, " + "use `__traits(getOverloads, ..., \"%s\"%s)[N]` " + "to get the Nth overload", + arg0->toChars(), ""); + return new ErrorExp(); + } + + Expressions *exps = new Expressions(); + exps->setDim(3); + (*exps)[0] = new StringExp(e->loc, const_cast<char *>(s->loc.filename), strlen(s->loc.filename)); + (*exps)[1] = new IntegerExp(e->loc, s->loc.linnum, Type::tint32); + (*exps)[2] = new IntegerExp(e->loc, s->loc.charnum, Type::tint32); + TupleExp *tup = new TupleExp(e->loc, exps); + return semantic(tup, sc); + } if (const char *sub = (const char *)speller(e->ident->toChars(), &trait_search_fp, NULL, idchars)) e->error("unrecognized trait '%s', did you mean '%s'?", e->ident->toChars(), sub); diff --git a/gcc/testsuite/gdc.test/compilable/Test16206.d b/gcc/testsuite/gdc.test/compilable/Test16206.d new file mode 100644 index 00000000000..0b9ccf31876 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/Test16206.d @@ -0,0 +1,28 @@ +struct S { + static int foo()() { return 0; } + static int foo()(int n) { return 1; } + static int foo(string s) { return 2; } + enum foo(int[] arr) = arr.length; +} + +alias AliasSeq(T...) = T; + +alias allFoos = AliasSeq!(__traits(getOverloads, S, "foo", true)); + +static assert(allFoos.length == 4); + +static assert(allFoos[0]("") == 2); +static assert(allFoos[1]() == 0); +static assert(allFoos[2](1) == 1); +alias foo3 = allFoos[3]; +static assert(foo3!([]) == 0); + +static assert(S.foo() == 0); +static assert(S.foo(1) == 1); +static assert(S.foo("") == 2); +static assert(S.foo!([]) == 0); + + +alias fooFuns = AliasSeq!(__traits(getOverloads, S, "foo")); +static assert(fooFuns.length == 1); +static assert(fooFuns[0]("") == 2); \ No newline at end of file diff --git a/gcc/testsuite/gdc.test/compilable/imports/pkgmodule/package.d b/gcc/testsuite/gdc.test/compilable/imports/pkgmodule/package.d new file mode 100644 index 00000000000..b6e98ff011b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/pkgmodule/package.d @@ -0,0 +1,3 @@ +/// Used to test is(x == package) and is(x == module) + +module imports.pkgmodule; diff --git a/gcc/testsuite/gdc.test/compilable/imports/pkgmodule/plainmodule.d b/gcc/testsuite/gdc.test/compilable/imports/pkgmodule/plainmodule.d new file mode 100644 index 00000000000..948a87e5fee --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/pkgmodule/plainmodule.d @@ -0,0 +1,2 @@ +/// Used to test is(x == module) +module imports.pkgmodule.plainmodule; diff --git a/gcc/testsuite/gdc.test/compilable/imports/plainpackage/plainmodule.d b/gcc/testsuite/gdc.test/compilable/imports/plainpackage/plainmodule.d new file mode 100644 index 00000000000..9e9933b379b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/plainpackage/plainmodule.d @@ -0,0 +1,4 @@ +/// Used to test is(x == module) + +module imports.plainpackage.plainmodule; + diff --git a/gcc/testsuite/gdc.test/compilable/isZeroInit.d b/gcc/testsuite/gdc.test/compilable/isZeroInit.d new file mode 100644 index 00000000000..b5423cfb636 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/isZeroInit.d @@ -0,0 +1,78 @@ +alias AliasSeq(T...) = T; + +struct Holder(T, ubyte val) +{ + T x = val; +} + +struct SArrayHolder(T, ubyte val) +{ + T[2] x = val; +} + +static foreach (T; AliasSeq!(bool, byte, short, int, long, + ubyte, ushort, uint, ulong, + char, wchar, dchar, + float, double, real)) +{ + static assert(__traits(isZeroInit, T) == (T.init is T(0))); + static assert(__traits(isZeroInit, T[2]) == (T.init is T(0))); + + static assert(!__traits(isZeroInit, Holder!(T, 1))); + static assert(__traits(isZeroInit, Holder!(T, 0))); + + static assert(__traits(isZeroInit, SArrayHolder!(T, 0))); + static assert(!__traits(isZeroInit, SArrayHolder!(T, 1))); + +} + +static assert(__traits(isZeroInit, void)); // For initializing arrays of element type `void`. +static assert(__traits(isZeroInit, void*)); +static assert(__traits(isZeroInit, void[])); +static assert(__traits(isZeroInit, float[])); +static assert(__traits(isZeroInit, Object)); +class C1 : Object +{ + int x = 1; +} +static assert(__traits(isZeroInit, C1)); // An Object's fields are irrelevant. + +struct S1 +{ + int[] a; + int b; +} +static assert(__traits(isZeroInit, S1)); + +struct S2 +{ + alias H = Holder!(int, 1); + H h; + int a; +} +static assert(!__traits(isZeroInit, S2)); + +struct S3 +{ + S1 h; + float f = 0; +} +static assert(__traits(isZeroInit, S3)); + +struct S4 +{ + S2 h = S2(S2.H(0), 0); + int a; +} +static assert(__traits(isZeroInit, S4)); + +struct S5 +{ + Object o = null; +} +static assert(__traits(isZeroInit, S5)); + +version(D_SIMD): +import core.simd : int4; +static assert(__traits(isZeroInit, Holder!(int4, 0))); +static assert(!__traits(isZeroInit, Holder!(int4, 1))); diff --git a/gcc/testsuite/gdc.test/compilable/isreturnonstack.d b/gcc/testsuite/gdc.test/compilable/isreturnonstack.d new file mode 100644 index 00000000000..8bdb97de13f --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/isreturnonstack.d @@ -0,0 +1,7 @@ +struct S { int[10] a; } +int test1(); +S test2(); + +static assert(__traits(isReturnOnStack, test1) == false); +static assert(__traits(isReturnOnStack, test2) == true); + diff --git a/gcc/testsuite/gdc.test/compilable/line.d b/gcc/testsuite/gdc.test/compilable/line.d index 5122ed3cbf8..14e178988c8 100644 --- a/gcc/testsuite/gdc.test/compilable/line.d +++ b/gcc/testsuite/gdc.test/compilable/line.d @@ -19,12 +19,12 @@ static assert(__FILE_FULL_PATH__[$-__FILE__.length..$] == __FILE__); static assert(__LINE__ == 101); static assert(__FILE__ == "newfile.d"); -static assert(__FILE_FULL_PATH__ == "newfile.d"); +static assert(__FILE_FULL_PATH__[$ - 9 .. $] == "newfile.d"); # line 200 static assert(__LINE__ == 201); static assert(__FILE__ == "newfile.d"); -static assert(__FILE_FULL_PATH__ == "newfile.d"); +static assert(__FILE_FULL_PATH__[$ - 9 .. $] == "newfile.d"); diff --git a/gcc/testsuite/gdc.test/compilable/test16002.d b/gcc/testsuite/gdc.test/compilable/test16002.d new file mode 100644 index 00000000000..f3303c0e310 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test16002.d @@ -0,0 +1,24 @@ +module test.compilable.test16002; + +import imports.plainpackage.plainmodule; +import imports.pkgmodule.plainmodule; + +struct MyStruct; + +alias a = imports.plainpackage; +alias b = imports.pkgmodule.plainmodule; + +static assert(is(imports.plainpackage == package)); +static assert(is(a == package)); +static assert(!is(imports.plainpackage.plainmodule == package)); +static assert(!is(b == package)); +static assert(is(imports.pkgmodule == package)); +static assert(!is(MyStruct == package)); + +static assert(!is(imports.plainpackage == module)); +static assert(!is(a == module)); +static assert(is(imports.plainpackage.plainmodule == module)); +static assert(is(b == module)); +// This is supposed to work even though we haven't directly imported imports.pkgmodule. +static assert(is(imports.pkgmodule == module)); +static assert(!is(MyStruct == module)); diff --git a/gcc/testsuite/gdc.test/compilable/test17791.d b/gcc/testsuite/gdc.test/compilable/test17791.d new file mode 100644 index 00000000000..3244c129aa9 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test17791.d @@ -0,0 +1,28 @@ +/* +REQUIRED_ARGS: -de +TEST_OUTPUT: +--- +--- +*/ +deprecated("A deprecated class") { +class DepClass +{ +} +} + +class NewClass +{ +} + +void main() +{ + // test that a symbol (which is not likely to be deprecated) + // is not depercated + static assert(!__traits(isDeprecated, int)); + // check that a class marked deprecated "isDeprecated" + static assert(__traits(isDeprecated, DepClass)); + // check that a class not marked deprecated is not deprecated + static assert(!__traits(isDeprecated, NewClass)); + // Check for expressions (18617) + static assert(__traits(isDeprecated, { scope foo = new DepClass; })); +} diff --git a/gcc/testsuite/gdc.test/compilable/traits.d b/gcc/testsuite/gdc.test/compilable/traits.d index 736eae4a89d..4d8a5e140c4 100644 --- a/gcc/testsuite/gdc.test/compilable/traits.d +++ b/gcc/testsuite/gdc.test/compilable/traits.d @@ -1,10 +1,140 @@ // REQUIRED_ARGS: +// EXTRA_FILES: imports/plainpackage/plainmodule.d imports/pkgmodule/package.d imports/pkgmodule/plainmodule.d // This file is intended to contain all compilable traits-related tests in an // effort to keep the number of files in the `compilable` folder to a minimum. +// https://issues.dlang.org/show_bug.cgi?id=19152 +module traits; + +class C19152 +{ + int OnExecute() + { + auto name = __traits(getOverloads, this, "OnExecute").stringof; + return 0; + } +} + +static assert(is(typeof(__traits(getTargetInfo, "cppRuntimeLibrary")) == string)); +version (CppRuntime_Microsoft) +{ + static assert(__traits(getTargetInfo, "cppRuntimeLibrary") == "libcmt"); +} + +import imports.plainpackage.plainmodule; +import imports.pkgmodule.plainmodule; + +#line 40 +struct MyStruct; + +alias a = imports.plainpackage; +alias b = imports.pkgmodule.plainmodule; + +static assert(__traits(isPackage, imports.plainpackage)); +static assert(__traits(isPackage, a)); +static assert(!__traits(isPackage, imports.plainpackage.plainmodule)); +static assert(!__traits(isPackage, b)); +static assert(__traits(isPackage, imports.pkgmodule)); +static assert(!__traits(isPackage, MyStruct)); + +static assert(!__traits(isModule, imports.plainpackage)); +static assert(!__traits(isModule, a)); +static assert(__traits(isModule, imports.plainpackage.plainmodule)); +static assert(__traits(isModule, b)); +// This is supposed to work even though we haven't directly imported imports.pkgmodule. +static assert(__traits(isModule, imports.pkgmodule)); +static assert(!__traits(isModule, MyStruct)); + /******************************************/ // https://issues.dlang.org/show_bug.cgi?id=19942 static assert(!__traits(compiles, { a.init; })); static assert(!__traits(compiles, { import m : a; a.init; })); + +version(Windows) + static assert(__traits(getLocation, MyStruct)[0] == `compilable\traits.d`); +else + static assert(__traits(getLocation, MyStruct)[0] == "compilable/traits.d"); +static assert(__traits(getLocation, MyStruct)[1] == 40); +static assert(__traits(getLocation, MyStruct)[2] == 1); + +int foo(); +int foo(int); + +static assert(__traits(getLocation, __traits(getOverloads, traits, "foo")[1])[1] == 74); + +mixin("int bar;"); +static assert(__traits(getLocation, bar)[1] == 78); + +struct Outer +{ + struct Nested{} + + void method() {} +} +static assert(__traits(getLocation, Outer.Nested)[1] == 83); +static assert(__traits(getLocation, Outer.method)[1] == 85); + +/******************************************/ +// https://issues.dlang.org/show_bug.cgi?id=19902 +// Define hasElaborateCopyConstructor trait +// but done as two independent traits per conversation +// in https://github.com/dlang/dmd/pull/10265 + +struct S +{ + this (ref S rhs) {} +} + +struct OuterS +{ + struct S + { + this (ref S rhs) {} + } + + S s; +} + +void foo(T)() +{ + struct S(U) + { + this (ref S rhs) {} + } +} + +struct U(T) +{ + this (ref U rhs) {} +} + +struct SPostblit +{ + this(this) {} +} + +struct DisabledPostblit +{ + @disable this(this); +} + +struct NoCpCtor { } +class C19902 { } + +static assert(__traits(compiles, foo!int)); +static assert(__traits(compiles, foo!S)); +static assert(!__traits(hasPostblit, U!S)); +static assert(__traits(hasPostblit, SPostblit)); + +static assert(!__traits(hasPostblit, NoCpCtor)); +static assert(!__traits(hasPostblit, C19902)); +static assert(!__traits(hasPostblit, int)); + +// Check that invalid use cases don't compile +static assert(!__traits(compiles, __traits(hasPostblit))); +static assert(!__traits(compiles, __traits(hasPostblit, S()))); + +static assert(__traits(isCopyable, int)); +static assert(!__traits(isCopyable, DisabledPostblit)); diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail16206a.d b/gcc/testsuite/gdc.test/fail_compilation/fail16206a.d new file mode 100644 index 00000000000..3c1cc56782e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail16206a.d @@ -0,0 +1,12 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail16206a.d(12): Error: `bool` expected as third argument of `__traits(getOverloads)`, not `"Not a bool"` of type `string` +--- +*/ + +struct S { + static int foo()() { return 0; } +} +alias AliasSeq(T...) = T; +alias allFoos = AliasSeq!(__traits(getOverloads, S, "foo", "Not a bool")); \ No newline at end of file diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail16206b.d b/gcc/testsuite/gdc.test/fail_compilation/fail16206b.d new file mode 100644 index 00000000000..9b3a69c0914 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail16206b.d @@ -0,0 +1,12 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail16206b.d(12): Error: expected 2 arguments for `hasMember` but had 3 +--- +*/ + +struct S { + static int foo()() { return 0; } +} +alias AliasSeq(T...) = T; +alias allFoos = AliasSeq!(__traits(hasMember, S, "foo", true)); \ No newline at end of file diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_isZeroInit.d b/gcc/testsuite/gdc.test/fail_compilation/fail_isZeroInit.d new file mode 100644 index 00000000000..a352984742f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail_isZeroInit.d @@ -0,0 +1,12 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail_isZeroInit.d(11): Error: type expected as second argument of __traits `isZeroInit` instead of `a` +--- +*/ +void test() +{ + int a = 3; + // Providing a specific variable rather than a type isn't allowed. + enum bool az = __traits(isZeroInit, a); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/isreturnonstack.d b/gcc/testsuite/gdc.test/fail_compilation/isreturnonstack.d new file mode 100644 index 00000000000..1dde6991baa --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/isreturnonstack.d @@ -0,0 +1,12 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/isreturnonstack.d(11): Error: argument to `__traits(isReturnOnStack, int)` is not a function +fail_compilation/isreturnonstack.d(12): Error: expected 1 arguments for `isReturnOnStack` but had 2 +--- +*/ + +int test() { return 0; } + +enum b = __traits(isReturnOnStack, int); +enum c = __traits(isReturnOnStack, test, int); diff --git a/gcc/testsuite/gdc.test/fail_compilation/test16002.d b/gcc/testsuite/gdc.test/fail_compilation/test16002.d new file mode 100644 index 00000000000..80ae40b6b88 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test16002.d @@ -0,0 +1,15 @@ +/* +REQUIRED_ARGS: +PERMUTE_ARGS: +TEST_OUTPUT: +--- +fail_compilation/test16002.d(100): Error: undefined identifier `imports.nonexistent` +fail_compilation/test16002.d(101): Error: undefined identifier `imports.nonexistent` +--- +*/ + +module test.fail_compilation.test16002; + +#line 100 +enum A = is(imports.nonexistent == package); +enum B = is(imports.nonexistent == module); diff --git a/gcc/testsuite/gdc.test/fail_compilation/test17096.d b/gcc/testsuite/gdc.test/fail_compilation/test17096.d new file mode 100644 index 00000000000..e421419ae2d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test17096.d @@ -0,0 +1,50 @@ +/* TEST_OUTPUT: +--- +fail_compilation/test17096.d(28): Error: expected 1 arguments for `isPOD` but had 2 +fail_compilation/test17096.d(29): Error: expected 1 arguments for `isNested` but had 2 +fail_compilation/test17096.d(30): Error: expected 1 arguments for `isVirtualFunction` but had 2 +fail_compilation/test17096.d(31): Error: expected 1 arguments for `isVirtualMethod` but had 2 +fail_compilation/test17096.d(32): Error: expected 1 arguments for `isAbstractFunction` but had 2 +fail_compilation/test17096.d(33): Error: expected 1 arguments for `isFinalFunction` but had 2 +fail_compilation/test17096.d(34): Error: expected 1 arguments for `isOverrideFunction` but had 2 +fail_compilation/test17096.d(35): Error: expected 1 arguments for `isStaticFunction` but had 2 +fail_compilation/test17096.d(36): Error: expected 1 arguments for `isRef` but had 2 +fail_compilation/test17096.d(37): Error: expected 1 arguments for `isOut` but had 2 +fail_compilation/test17096.d(38): Error: expected 1 arguments for `isLazy` but had 2 +fail_compilation/test17096.d(39): Error: expected 1 arguments for `identifier` but had 2 +fail_compilation/test17096.d(40): Error: expected 1 arguments for `getProtection` but had 2 +fail_compilation/test17096.d(41): Error: expected 1 arguments for `parent` but had 2 +fail_compilation/test17096.d(42): Error: expected 1 arguments for `classInstanceSize` but had 2 +fail_compilation/test17096.d(43): Error: expected 1 arguments for `allMembers` but had 2 +fail_compilation/test17096.d(44): Error: expected 1 arguments for `derivedMembers` but had 2 +fail_compilation/test17096.d(45): Error: expected 1 arguments for `getAliasThis` but had 2 +fail_compilation/test17096.d(46): Error: expected 1 arguments for `getAttributes` but had 2 +fail_compilation/test17096.d(47): Error: expected 1 arguments for `getFunctionAttributes` but had 2 +fail_compilation/test17096.d(48): Error: expected 1 arguments for `getUnitTests` but had 2 +fail_compilation/test17096.d(49): Error: expected 1 arguments for `getVirtualIndex` but had 2 +fail_compilation/test17096.d(50): Error: a single type expected for trait pointerBitmap +--- +*/ +enum b03 = __traits(isPOD, 1, 2); +enum b04 = __traits(isNested, 1, 2); +enum b05 = __traits(isVirtualFunction, 1, 2); +enum b06 = __traits(isVirtualMethod, 1, 2); +enum b07 = __traits(isAbstractFunction, 1, 2); +enum b08 = __traits(isFinalFunction, 1, 2); +enum b09 = __traits(isOverrideFunction, 1, 2); +enum b10 = __traits(isStaticFunction, 1, 2); +enum b11 = __traits(isRef, 1, 2); +enum b12 = __traits(isOut, 1, 2); +enum b13 = __traits(isLazy, 1, 2); +enum b14 = __traits(identifier, 1, 2); +enum b15 = __traits(getProtection, 1, 2); +enum b16 = __traits(parent, 1, 2); +enum b17 = __traits(classInstanceSize, 1, 2); +enum b18 = __traits(allMembers, 1, 2); +enum b19 = __traits(derivedMembers, 1, 2); +enum b20 = __traits(getAliasThis, 1, 2); +enum b21 = __traits(getAttributes, 1, 2); +enum b22 = __traits(getFunctionAttributes, 1, 2); +enum b23 = __traits(getUnitTests, 1, 2); +enum b24 = __traits(getVirtualIndex, 1, 2); +enum b25 = __traits(getPointerBitmap, 1, 2); diff --git a/gcc/testsuite/gdc.test/fail_compilation/trait_loc_err.d b/gcc/testsuite/gdc.test/fail_compilation/trait_loc_err.d new file mode 100644 index 00000000000..8d5d480174e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/trait_loc_err.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/trait_loc_err.d(13): Error: can only get the location of a symbol, not `trait_loc_err` +fail_compilation/trait_loc_err.d(14): Error: can only get the location of a symbol, not `std` +--- +*/ +module trait_loc_err; +import std.stdio; + +void main() +{ + __traits(getLocation, __traits(parent, main)); + __traits(getLocation, __traits(parent, std.stdio)); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/trait_loc_ov_err.d b/gcc/testsuite/gdc.test/fail_compilation/trait_loc_ov_err.d new file mode 100644 index 00000000000..313e57da4c9 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/trait_loc_ov_err.d @@ -0,0 +1,40 @@ +module trait_loc_ov_err; +/* +TEST_OUTPUT: +--- +fail_compilation/trait_loc_ov_err.d(24): Error: cannot get location of an overload set, use `__traits(getOverloads, ..., "ov1")[N]` to get the Nth overload +fail_compilation/trait_loc_ov_err.d(25): Error: cannot get location of an overload set, use `__traits(getOverloads, ..., "ov2")[N]` to get the Nth overload +--- +*/ + +void ov1(){} +void ov1(int){} + +void ov21(){} +void ov22(int){} +alias ov2 = ov21; +alias ov2 = ov22; + +template OvT(T, U){} +template OvT(T){} + +auto func(T)(T t) {} +auto func(T,U)(T t,U u) {} + +enum e1 = __traits(getLocation, ov1); +enum e2 = __traits(getLocation, ov2); + +enum e3 = __traits(getLocation, OvT); +enum e4 = __traits(getLocation, func); + +enum e5 = __traits(getLocation, __traits(getOverloads, trait_loc_ov_err, "ov1")[0]); +enum e6 = __traits(getLocation, __traits(getOverloads, trait_loc_ov_err, "ov1")[1]); + +enum e7 = __traits(getLocation, __traits(getOverloads, trait_loc_ov_err, "ov2")[0]); +enum e8 = __traits(getLocation, __traits(getOverloads, trait_loc_ov_err, "ov2")[1]); + +enum e9 = __traits(getLocation, __traits(getOverloads, trait_loc_ov_err, "OvT", true)[1]); +enum e10 = __traits(getLocation, __traits(getOverloads, trait_loc_ov_err, "OvT", true)[0]); + +enum e11 = __traits(getLocation, __traits(getOverloads, trait_loc_ov_err, "func", true)[0]); +enum e12 = __traits(getLocation, __traits(getOverloads, trait_loc_ov_err, "func", true)[1]); diff --git a/gcc/testsuite/gdc.test/fail_compilation/traits.d b/gcc/testsuite/gdc.test/fail_compilation/traits.d new file mode 100644 index 00000000000..bee29ed1d76 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/traits.d @@ -0,0 +1,27 @@ +/************************************************************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/traits.d(100): Error: `getTargetInfo` key `"not_a_target_info"` not supported by this implementation +fail_compilation/traits.d(101): Error: string expected as argument of __traits `getTargetInfo` instead of `100` +fail_compilation/traits.d(102): Error: expected 1 arguments for `getTargetInfo` but had 2 +fail_compilation/traits.d(103): Error: expected 1 arguments for `getTargetInfo` but had 0 +fail_compilation/traits.d(200): Error: undefined identifier `imports.nonexistent` +fail_compilation/traits.d(201): Error: undefined identifier `imports.nonexistent` +fail_compilation/traits.d(202): Error: expected 1 arguments for `isPackage` but had 0 +fail_compilation/traits.d(203): Error: expected 1 arguments for `isModule` but had 0 +--- +*/ + +#line 100 +enum A1 = __traits(getTargetInfo, "not_a_target_info"); +enum B1 = __traits(getTargetInfo, 100); +enum C1 = __traits(getTargetInfo, "cppRuntimeLibrary", "bits"); +enum D1 = __traits(getTargetInfo); + +#line 200 +enum A2 = __traits(isPackage, imports.nonexistent); +enum B2 = __traits(isModule, imports.nonexistent); +enum C2 = __traits(isPackage); +enum D2 = __traits(isModule); diff --git a/gcc/testsuite/gdc.test/fail_compilation/traits_child.d b/gcc/testsuite/gdc.test/fail_compilation/traits_child.d new file mode 100644 index 00000000000..7a0b75e0c9c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/traits_child.d @@ -0,0 +1,17 @@ +/************************************************************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/traits_child.d(100): Error: expected 2 arguments for `child` but had 1 +fail_compilation/traits_child.d(101): Error: symbol or expression expected as first argument of __traits +child` instead of `long` +fail_compilation/traits_child.d(102): Error: symbol expected as second argument of __traits `child` inste +d of `3` +--- +*/ + +#line 100 +enum a = __traits(child, long); +enum b = __traits(child, long, 3); +enum c = __traits(child, "hi", 3); diff --git a/gcc/testsuite/gdc.test/runnable/imports/test18322import.d b/gcc/testsuite/gdc.test/runnable/imports/test18322import.d new file mode 100644 index 00000000000..8916cfd2a90 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/imports/test18322import.d @@ -0,0 +1,14 @@ +module test18322import; +void fun(string templateFileFullPath = __FILE_FULL_PATH__, + string templateFile = __FILE__)(string expectedFilename, string fileFullPath = __FILE_FULL_PATH__) +{ + // make sure it is an absolute path + version(Windows) + assert(fileFullPath[1..3] == ":\\"); + else + assert(fileFullPath[0] == '/'); + + assert(templateFileFullPath == fileFullPath); + assert(fileFullPath[$ - expectedFilename.length .. $] == expectedFilename); + assert(fileFullPath[$ - templateFile.length .. $] == templateFile); +} diff --git a/gcc/testsuite/gdc.test/runnable/test17373.d b/gcc/testsuite/gdc.test/runnable/test17373.d new file mode 100644 index 00000000000..93753baf27b --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/test17373.d @@ -0,0 +1,20 @@ +interface Foo { void visit (int); } +interface Bar { void visit(double); } +interface FooBar : Foo, Bar {} +static assert(__traits(getOverloads, FooBar, "visit").length == 2); + +interface Fbar { void visit(char); void visit(double); } +interface Triple : Foo, Bar, Fbar {} +static assert(__traits(getOverloads, Triple, "visit").length == 3); + +interface InheritanceMadness : FooBar, Triple {} +static assert(__traits(getOverloads, Triple, "visit").length == 3); + +interface Simple +{ + int square(int); + real square(real); +} +static assert(__traits(getOverloads, Simple, "square").length == 2); + +void main() {} diff --git a/gcc/testsuite/gdc.test/runnable/test17878.d b/gcc/testsuite/gdc.test/runnable/test17878.d new file mode 100644 index 00000000000..77b5a52bb28 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/test17878.d @@ -0,0 +1,19 @@ +@__future int foo() +{ + return 0; +} + +int bar() +{ + return 1; +} + +@__future int c; + + +void main() +{ + static assert(__traits(isFuture, foo)); + static assert(!__traits(isFuture, bar)); + static assert(__traits(isFuture, c)); +} diff --git a/gcc/testsuite/gdc.test/runnable/test18322.d b/gcc/testsuite/gdc.test/runnable/test18322.d new file mode 100644 index 00000000000..97e2e976440 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/test18322.d @@ -0,0 +1,21 @@ +/* +REQUIRED_ARGS: -Irunnable/imports +COMPILED_IMPORTS: imports/test18322import.d +PERMUTE_ARGS: +*/ +import test18322import; +void main(){ + version(Windows) + auto sep = "\\"; + else + auto sep = "/"; + + auto filename = "runnable" ~ sep ~ "test18322.d"; + + fun(filename); + mixin(`fun(filename ~ "-mixin-16");`); + + #line 100 "poundlinefile.d" + fun("poundlinefile.d"); + mixin(`fun("poundlinefile.d-mixin-101");`); +} diff --git a/gcc/testsuite/gdc.test/runnable/traits.d b/gcc/testsuite/gdc.test/runnable/traits.d index 547976f6598..3cdfe83afa0 100644 --- a/gcc/testsuite/gdc.test/runnable/traits.d +++ b/gcc/testsuite/gdc.test/runnable/traits.d @@ -12,6 +12,7 @@ class AC2 { abstract void foo(); } class AC3 : AC2 { } final class FC { void foo() { } } enum E { EMEM } +struct D1 { @disable void true_(); void false_(){} } /********************************************************/ @@ -623,7 +624,7 @@ struct Test24 private void test24(int, int){} } -static assert(__traits(getProtection, __traits(getOverloads, Test24, "test24")[1]) == "private"); +static assert(__traits(getVisibility, __traits(getOverloads, Test24, "test24")[1]) == "private"); /********************************************************/ // 1369 @@ -878,7 +879,7 @@ protected struct TestProt3 {} public struct TestProt4 {} export struct TestProt5 {} -void getProtection() +void getVisibility() { class Test { @@ -891,52 +892,52 @@ void getProtection() Test t; // TOKvar and VarDeclaration - static assert(__traits(getProtection, Test.va) == "private"); - static assert(__traits(getProtection, Test.vb) == "package"); - static assert(__traits(getProtection, Test.vc) == "protected"); - static assert(__traits(getProtection, Test.vd) == "public"); - static assert(__traits(getProtection, Test.ve) == "export"); + static assert(__traits(getVisibility, Test.va) == "private"); + static assert(__traits(getVisibility, Test.vb) == "package"); + static assert(__traits(getVisibility, Test.vc) == "protected"); + static assert(__traits(getVisibility, Test.vd) == "public"); + static assert(__traits(getVisibility, Test.ve) == "export"); // TOKdotvar and VarDeclaration - static assert(__traits(getProtection, t.va) == "private"); - static assert(__traits(getProtection, t.vb) == "package"); - static assert(__traits(getProtection, t.vc) == "protected"); - static assert(__traits(getProtection, t.vd) == "public"); - static assert(__traits(getProtection, t.ve) == "export"); + static assert(__traits(getVisibility, t.va) == "private"); + static assert(__traits(getVisibility, t.vb) == "package"); + static assert(__traits(getVisibility, t.vc) == "protected"); + static assert(__traits(getVisibility, t.vd) == "public"); + static assert(__traits(getVisibility, t.ve) == "export"); // TOKvar and FuncDeclaration - static assert(__traits(getProtection, Test.fa) == "private"); - static assert(__traits(getProtection, Test.fb) == "package"); - static assert(__traits(getProtection, Test.fc) == "protected"); - static assert(__traits(getProtection, Test.fd) == "public"); - static assert(__traits(getProtection, Test.fe) == "export"); + static assert(__traits(getVisibility, Test.fa) == "private"); + static assert(__traits(getVisibility, Test.fb) == "package"); + static assert(__traits(getVisibility, Test.fc) == "protected"); + static assert(__traits(getVisibility, Test.fd) == "public"); + static assert(__traits(getVisibility, Test.fe) == "export"); // TOKdotvar and FuncDeclaration - static assert(__traits(getProtection, t.fa) == "private"); - static assert(__traits(getProtection, t.fb) == "package"); - static assert(__traits(getProtection, t.fc) == "protected"); - static assert(__traits(getProtection, t.fd) == "public"); - static assert(__traits(getProtection, t.fe) == "export"); + static assert(__traits(getVisibility, t.fa) == "private"); + static assert(__traits(getVisibility, t.fb) == "package"); + static assert(__traits(getVisibility, t.fc) == "protected"); + static assert(__traits(getVisibility, t.fd) == "public"); + static assert(__traits(getVisibility, t.fe) == "export"); // TOKtype - static assert(__traits(getProtection, TestProt1) == "private"); - static assert(__traits(getProtection, TestProt2) == "package"); - static assert(__traits(getProtection, TestProt3) == "protected"); - static assert(__traits(getProtection, TestProt4) == "public"); - static assert(__traits(getProtection, TestProt5) == "export"); + static assert(__traits(getVisibility, TestProt1) == "private"); + static assert(__traits(getVisibility, TestProt2) == "package"); + static assert(__traits(getVisibility, TestProt3) == "protected"); + static assert(__traits(getVisibility, TestProt4) == "public"); + static assert(__traits(getVisibility, TestProt5) == "export"); // This specific pattern is important to ensure it always works // through reflection, however that becomes implemented - static assert(__traits(getProtection, __traits(getMember, t, "va")) == "private"); - static assert(__traits(getProtection, __traits(getMember, t, "vb")) == "package"); - static assert(__traits(getProtection, __traits(getMember, t, "vc")) == "protected"); - static assert(__traits(getProtection, __traits(getMember, t, "vd")) == "public"); - static assert(__traits(getProtection, __traits(getMember, t, "ve")) == "export"); - static assert(__traits(getProtection, __traits(getMember, t, "fa")) == "private"); - static assert(__traits(getProtection, __traits(getMember, t, "fb")) == "package"); - static assert(__traits(getProtection, __traits(getMember, t, "fc")) == "protected"); - static assert(__traits(getProtection, __traits(getMember, t, "fd")) == "public"); - static assert(__traits(getProtection, __traits(getMember, t, "fe")) == "export"); + static assert(__traits(getVisibility, __traits(getMember, t, "va")) == "private"); + static assert(__traits(getVisibility, __traits(getMember, t, "vb")) == "package"); + static assert(__traits(getVisibility, __traits(getMember, t, "vc")) == "protected"); + static assert(__traits(getVisibility, __traits(getMember, t, "vd")) == "public"); + static assert(__traits(getVisibility, __traits(getMember, t, "ve")) == "export"); + static assert(__traits(getVisibility, __traits(getMember, t, "fa")) == "private"); + static assert(__traits(getVisibility, __traits(getMember, t, "fb")) == "package"); + static assert(__traits(getVisibility, __traits(getMember, t, "fc")) == "protected"); + static assert(__traits(getVisibility, __traits(getMember, t, "fd")) == "public"); + static assert(__traits(getVisibility, __traits(getMember, t, "fe")) == "export"); } /********************************************************/ @@ -947,47 +948,47 @@ void test9546() import imports.a9546 : S; S s; - static assert(__traits(getProtection, s.privA) == "private"); - static assert(__traits(getProtection, s.protA) == "protected"); - static assert(__traits(getProtection, s.packA) == "package"); - static assert(__traits(getProtection, S.privA) == "private"); - static assert(__traits(getProtection, S.protA) == "protected"); - static assert(__traits(getProtection, S.packA) == "package"); - - static assert(__traits(getProtection, mixin("s.privA")) == "private"); - static assert(__traits(getProtection, mixin("s.protA")) == "protected"); - static assert(__traits(getProtection, mixin("s.packA")) == "package"); - static assert(__traits(getProtection, mixin("S.privA")) == "private"); - static assert(__traits(getProtection, mixin("S.protA")) == "protected"); - static assert(__traits(getProtection, mixin("S.packA")) == "package"); - - static assert(__traits(getProtection, __traits(getMember, s, "privA")) == "private"); - static assert(__traits(getProtection, __traits(getMember, s, "protA")) == "protected"); - static assert(__traits(getProtection, __traits(getMember, s, "packA")) == "package"); - static assert(__traits(getProtection, __traits(getMember, S, "privA")) == "private"); - static assert(__traits(getProtection, __traits(getMember, S, "protA")) == "protected"); - static assert(__traits(getProtection, __traits(getMember, S, "packA")) == "package"); - - static assert(__traits(getProtection, s.privF) == "private"); - static assert(__traits(getProtection, s.protF) == "protected"); - static assert(__traits(getProtection, s.packF) == "package"); - static assert(__traits(getProtection, S.privF) == "private"); - static assert(__traits(getProtection, S.protF) == "protected"); - static assert(__traits(getProtection, S.packF) == "package"); - - static assert(__traits(getProtection, mixin("s.privF")) == "private"); - static assert(__traits(getProtection, mixin("s.protF")) == "protected"); - static assert(__traits(getProtection, mixin("s.packF")) == "package"); - static assert(__traits(getProtection, mixin("S.privF")) == "private"); - static assert(__traits(getProtection, mixin("S.protF")) == "protected"); - static assert(__traits(getProtection, mixin("S.packF")) == "package"); - - static assert(__traits(getProtection, __traits(getMember, s, "privF")) == "private"); - static assert(__traits(getProtection, __traits(getMember, s, "protF")) == "protected"); - static assert(__traits(getProtection, __traits(getMember, s, "packF")) == "package"); - static assert(__traits(getProtection, __traits(getMember, S, "privF")) == "private"); - static assert(__traits(getProtection, __traits(getMember, S, "protF")) == "protected"); - static assert(__traits(getProtection, __traits(getMember, S, "packF")) == "package"); + static assert(__traits(getVisibility, s.privA) == "private"); + static assert(__traits(getVisibility, s.protA) == "protected"); + static assert(__traits(getVisibility, s.packA) == "package"); + static assert(__traits(getVisibility, S.privA) == "private"); + static assert(__traits(getVisibility, S.protA) == "protected"); + static assert(__traits(getVisibility, S.packA) == "package"); + + static assert(__traits(getVisibility, mixin("s.privA")) == "private"); + static assert(__traits(getVisibility, mixin("s.protA")) == "protected"); + static assert(__traits(getVisibility, mixin("s.packA")) == "package"); + static assert(__traits(getVisibility, mixin("S.privA")) == "private"); + static assert(__traits(getVisibility, mixin("S.protA")) == "protected"); + static assert(__traits(getVisibility, mixin("S.packA")) == "package"); + + static assert(__traits(getVisibility, __traits(getMember, s, "privA")) == "private"); + static assert(__traits(getVisibility, __traits(getMember, s, "protA")) == "protected"); + static assert(__traits(getVisibility, __traits(getMember, s, "packA")) == "package"); + static assert(__traits(getVisibility, __traits(getMember, S, "privA")) == "private"); + static assert(__traits(getVisibility, __traits(getMember, S, "protA")) == "protected"); + static assert(__traits(getVisibility, __traits(getMember, S, "packA")) == "package"); + + static assert(__traits(getVisibility, s.privF) == "private"); + static assert(__traits(getVisibility, s.protF) == "protected"); + static assert(__traits(getVisibility, s.packF) == "package"); + static assert(__traits(getVisibility, S.privF) == "private"); + static assert(__traits(getVisibility, S.protF) == "protected"); + static assert(__traits(getVisibility, S.packF) == "package"); + + static assert(__traits(getVisibility, mixin("s.privF")) == "private"); + static assert(__traits(getVisibility, mixin("s.protF")) == "protected"); + static assert(__traits(getVisibility, mixin("s.packF")) == "package"); + static assert(__traits(getVisibility, mixin("S.privF")) == "private"); + static assert(__traits(getVisibility, mixin("S.protF")) == "protected"); + static assert(__traits(getVisibility, mixin("S.packF")) == "package"); + + static assert(__traits(getVisibility, __traits(getMember, s, "privF")) == "private"); + static assert(__traits(getVisibility, __traits(getMember, s, "protF")) == "protected"); + static assert(__traits(getVisibility, __traits(getMember, s, "packF")) == "package"); + static assert(__traits(getVisibility, __traits(getMember, S, "privF")) == "private"); + static assert(__traits(getVisibility, __traits(getMember, S, "protF")) == "protected"); + static assert(__traits(getVisibility, __traits(getMember, S, "packF")) == "package"); } /********************************************************/ @@ -1547,6 +1548,19 @@ void async(ARGS...)(ARGS) alias test17495 = async!(int, int); +/********************************************************/ +// 15094 + +void test15094() +{ + static struct Foo { int i; } + static struct Bar { Foo foo; } + + Bar bar; + auto n = __traits(getMember, bar.foo, "i"); + assert(n == bar.foo.i); +} + /********************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10100 @@ -1564,6 +1578,15 @@ static assert( /********************************************************/ +void testIsDisabled() +{ + static assert(__traits(isDisabled, D1.true_)); + static assert(!__traits(isDisabled, D1.false_)); + static assert(!__traits(isDisabled, D1)); +} + +/********************************************************/ + int main() { test1(); @@ -1603,6 +1626,7 @@ int main() test_getFunctionAttributes(); test_isOverrideFunction(); test12237(); + test15094(); writeln("Success"); return 0; diff --git a/gcc/testsuite/gdc.test/runnable/traits_child.d b/gcc/testsuite/gdc.test/runnable/traits_child.d new file mode 100644 index 00000000000..056b8f120ac --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/traits_child.d @@ -0,0 +1,122 @@ +struct A +{ + ulong i; + void foo(ulong a) + { + i = a; + } + + void foo(string s) + { + i = s.length; + } + + void bar(T)(T a) + { + i = a; + } + + void bar(T : string)(T s) + { + i = s.length; + } +} + +alias ai = A.i; +alias afoo = A.foo; +alias abar = A.bar; +alias abar_ulong = A.bar!ulong; +alias abar_string = A.bar!string; + +struct B +{ + A a; +} + +alias ba = B.a; + +template T(alias x) +{ + void set(int n) + { + x = n; + } +} + +mixin template M(alias x) +{ + void set(int n) + { + x = n; + } +} + +struct C +{ + int i; + alias t = T!i; + mixin M!i m; +} + +alias ct = C.t; +alias ctset = C.t.set; +alias cm = C.m; +alias cmset = C.m.set; + + +// adapted from http://thecybershadow.net/d/dconf2017/#/21 +struct S { string a, b, c; } + +static string printField(alias field)() +{ + S s = { a: "aa", b: "bb", c: "cc" }; + return __traits(child, s, field); +} + +void main() +{ + auto f = printField!(S.b)(); + assert(f == "bb"); + + A a; + __traits(child, a, ai) = 3; + assert(a.i == 3); + assert(__traits(child, a, ai) == 3); + __traits(child, a, afoo)(2); + assert(a.i == 2); + __traits(child, a, afoo)("hello"); + assert(a.i == 5); + __traits(child, a, abar)(6); + assert(a.i == 6); + __traits(child, a, abar_ulong)(7); + assert(a.i == 7); + __traits(child, a, abar_string)("hi"); + assert(a.i == 2); + + __traits(child, a, A.i) = 7; + assert(a.i == 7); + __traits(child, a, A.bar)(3); + assert(a.i == 3); + __traits(child, a, A.bar!ulong)(4); + assert(a.i == 4); + __traits(child, a, __traits(getMember, A, "i")) = 5; + assert(a.i == 5); + __traits(child, a, __traits(getOverloads, A, "bar", true)[1])("hi!"); + assert(a.i == 3); + + B b; + __traits(child, b.a, ai) = 2; + assert(b.a.i == 2); + __traits(child, __traits(child, b, ba), ai) = 3; + assert(b.a.i == 3); + + C c; + __traits(child, c, ct).set(3); + assert(c.i == 3); + __traits(child, c, ctset)(4); + assert(c.i == 4); + __traits(child, c, cm).set(5); + assert(c.i == 5); + __traits(child, c, cmset)(6); + assert(c.i == 6); +} -- 2.27.0