d: Merge upstream dmd a5c86f5b9
authorIain Buclaw <ibuclaw@gdcproject.org>
Mon, 4 Jan 2021 18:05:38 +0000 (19:05 +0100)
committerIain Buclaw <ibuclaw@gdcproject.org>
Tue, 5 Jan 2021 21:09:10 +0000 (22:09 +0100)
Adds 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.

Reviewed-on: https://github.com/dlang/dmd/pull/12093

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.

47 files changed:
gcc/d/d-builtins.cc
gcc/d/d-frontend.cc
gcc/d/d-target.cc
gcc/d/d-target.h
gcc/d/dmd/MERGE
gcc/d/dmd/declaration.h
gcc/d/dmd/dmodule.c
gcc/d/dmd/dstruct.c
gcc/d/dmd/dtemplate.c
gcc/d/dmd/expression.c
gcc/d/dmd/expressionsem.c
gcc/d/dmd/func.c
gcc/d/dmd/globals.h
gcc/d/dmd/idgen.c
gcc/d/dmd/module.h
gcc/d/dmd/mtype.c
gcc/d/dmd/parse.c
gcc/d/dmd/root/filename.c
gcc/d/dmd/root/filename.h
gcc/d/dmd/target.h
gcc/d/dmd/traits.c
gcc/testsuite/gdc.test/compilable/Test16206.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/imports/pkgmodule/package.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/imports/pkgmodule/plainmodule.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/imports/plainpackage/plainmodule.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/isZeroInit.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/isreturnonstack.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/line.d
gcc/testsuite/gdc.test/compilable/test16002.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/test17791.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/traits.d
gcc/testsuite/gdc.test/fail_compilation/fail16206a.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/fail16206b.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/fail_isZeroInit.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/isreturnonstack.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/test16002.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/test17096.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/trait_loc_err.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/trait_loc_ov_err.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/traits.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/traits_child.d [new file with mode: 0644]
gcc/testsuite/gdc.test/runnable/imports/test18322import.d [new file with mode: 0644]
gcc/testsuite/gdc.test/runnable/test17373.d [new file with mode: 0644]
gcc/testsuite/gdc.test/runnable/test17878.d [new file with mode: 0644]
gcc/testsuite/gdc.test/runnable/test18322.d [new file with mode: 0644]
gcc/testsuite/gdc.test/runnable/traits.d
gcc/testsuite/gdc.test/runnable/traits_child.d [new file with mode: 0644]

index 9d0c91af7dba3c37c9db39d5b63e9ab6f4c1aee4..26ccd00c79a25252ae2c9668673e0d1491dade71 100644 (file)
@@ -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;
index 73548e197ac3ef955b9ccb259b8ba968ea117b0f..32550ecfd64bc1b71023870f0bbfff8aa06110d2 100644 (file)
@@ -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
index 48c141460ed2b39ab1d07f349d7292f2eafafb42..d50fcef22e24b05a394898473ff58adb2b80f2b8 100644 (file)
@@ -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;
+}
index 211f72fdb7e31b6422830263df3e1cd4350f11ac..56595d225bf5a0b39e5909880d8186861c591a00 100644 (file)
@@ -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  */
index 1f695b9d23c30f281cf1167e2fae65a84db312ee..1629b4535ee87eca6434bbb2e1591c2f630e493b 100644 (file)
@@ -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.
index 65ac3f75b2780b8d306e9dc6afc3fd527945eb72..a4e776697fccb3a385c82e9a7eef4a0dc4df5636 100644 (file)
@@ -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; }
 
index 8f09f2db8561dbc66562b0e2cd934aff69dd0374..305b1331146f4e50542aadd7510d04102dbba2ce 100644 (file)
@@ -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;
-}
index 2b87154142c1d311bdbd339a8a37d7b9ea3cd073..8829367dab4560bf17c59ca5db31c91d15d60bc9 100644 (file)
@@ -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))
         {
index fe65bd23e3cf71461a213dc0b08d55500dd49743..1035f829e126051fdc24b165971c244b91c8fea3 100644 (file)
@@ -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;
index 09dd3af6eacd84b004fd63390443c758fbaf4aaa..789183201924f3d560821d6e492607265c3fdd38 100644 (file)
@@ -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);
index d2519969a2ce48b299a4cdbf2323430f41dad19e..7dfe995b711e5d33d27602877a23c8324b8a5a4f 100644 (file)
@@ -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)
index dbc5fa6352c0cc5c336f1778bfc04ab195176ea3..fe1ad1118e0e219bd029506ef193c6e8f41cc60d 100644 (file)
@@ -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
index 6aff9b4b0790f6856406404986bb355dc79e02cb..502bae29c48484546c0c54dc9440edf7f94297cd 100644 (file)
@@ -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;
 
index 16f3b5f29ec5420b3baa6a201c35fd9e85da4c19..09855a056880e6bc895390e9802a6b87f33dbcd0 100644 (file)
@@ -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 },
index 17ad59045234f6cd6eab79fee61c80e24ac6b8e8..4968ec7e1b540bc6b37a30ea182f782485fbe308 100644 (file)
@@ -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
index 6f0195af30500511d28c61f1ff825d51051cf8b2..94e2082f5b23ae40f03f956f60d8227bfb0f3ca1 100644 (file)
@@ -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 &&
index 3e4dd066c319de0e7b6e214eb0bf2835d9430cf1..be861fa92f6e69a8c211e4a4e0107d133f13898b 100644 (file)
@@ -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) ||
index 50b67404062dc1e171b89e5e06b49beea2d304dc..f0e0213e701d79f970e64b55e270cd639126f883 100644 (file)
@@ -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.
index 62a5a6869a1b4cc414e1ea80ac08fd7fd6d49bad..6ef515c644145c3ff24f3e19f25e73b89ca548b5 100644 (file)
@@ -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);
index f2a55d6a134c05d30dc1b6c6490f8ef69abc366f..5a2dd4d913369b8a2989492090fea0b933746101 100644 (file)
@@ -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;
index bc1e2c3c2348eb3830c1841d5423ac124eee7fa1..658529943ea14aee5abeff40a407f5466a873ef5 100644 (file)
 #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 (file)
index 0000000..0b9ccf3
--- /dev/null
@@ -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 (file)
index 0000000..b6e98ff
--- /dev/null
@@ -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 (file)
index 0000000..948a87e
--- /dev/null
@@ -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 (file)
index 0000000..9e9933b
--- /dev/null
@@ -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 (file)
index 0000000..b5423cf
--- /dev/null
@@ -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 (file)
index 0000000..8bdb97d
--- /dev/null
@@ -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);
+
index 5122ed3cbf8693de4c042f71d7be4e6a70944824..14e178988c8f2add1f74247bebab0d919761c43b 100644 (file)
@@ -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 (file)
index 0000000..f3303c0
--- /dev/null
@@ -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 (file)
index 0000000..3244c12
--- /dev/null
@@ -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; }));
+}
index 736eae4a89deeeba3aab7dacafb242be121b5336..4d8a5e140c4b536ae8e7993dea09137b4899892a 100644 (file)
 // 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 (file)
index 0000000..3c1cc56
--- /dev/null
@@ -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 (file)
index 0000000..9b3a69c
--- /dev/null
@@ -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 (file)
index 0000000..a352984
--- /dev/null
@@ -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 (file)
index 0000000..1dde699
--- /dev/null
@@ -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 (file)
index 0000000..80ae40b
--- /dev/null
@@ -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 (file)
index 0000000..e421419
--- /dev/null
@@ -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 (file)
index 0000000..8d5d480
--- /dev/null
@@ -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 (file)
index 0000000..313e57d
--- /dev/null
@@ -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 (file)
index 0000000..bee29ed
--- /dev/null
@@ -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 (file)
index 0000000..7a0b75e
--- /dev/null
@@ -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 (file)
index 0000000..8916cfd
--- /dev/null
@@ -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 (file)
index 0000000..93753ba
--- /dev/null
@@ -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 (file)
index 0000000..77b5a52
--- /dev/null
@@ -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 (file)
index 0000000..97e2e97
--- /dev/null
@@ -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");`);
+}
index 547976f659834cc510187b43177395bd69901618..3cdfe83afa0a86f42e8465bb7715e29fbbc55bc7 100644 (file)
@@ -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 (file)
index 0000000..056b8f1
--- /dev/null
@@ -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);
+}