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;
/* 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
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. */
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. */
/* 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;
+}
/* 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 */
-2bd4fc3fed8b8cd9760e77c6b2a1905cd84d0e70
+a5c86f5b92c4cd3afde910c89881ccaea11de554
The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository.
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; }
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; }
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()
sfilename = NULL;
importedFrom = NULL;
srcfile = NULL;
- srcfilePath = NULL;
docfile = NULL;
debuglevel = 0;
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)
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;
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
*
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;
-}
#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);
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);
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))
{
{
//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)
//goto Ldsym;
}
}
- if (ea->op == TOKdotvar)
+ if (ea->op == TOKdotvar && !(flags & 1))
{
// translate expression to dsymbol.
sa = ((DotVarExp *)ea)->var;
sa = ((TemplateExp *)ea)->td;
goto Ldsym;
}
- if (ea->op == TOKdottd)
+ if (ea->op == TOKdottd && !(flags & 1))
{
// translate expression to dsymbol.
sa = ((DotTemplateExp *)ea)->td;
/****************************************
- * 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 *)
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);
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:
}
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)
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);
{
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;
if (storage_class & STCauto)
storage_class &= ~STCauto;
}
- if (retStyle(f) != RETstack || checkNrvo())
+ if (!target.isReturnOnStack(f, needThis()) || !checkNRVO())
nrvo_can = 0;
if (fbody->isErrorStatement())
* 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++)
{
{
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
// file location
struct Loc
{
- const char *filename;
+ const char *filename; // either absolute or relative to cwd
unsigned linnum;
unsigned charnum;
{ "isFinalClass", NULL },
{ "isTemplate", NULL },
{ "isPOD", NULL },
+ { "isDeprecated", NULL },
+ { "isDisabled", NULL },
+ { "isFuture" , NULL },
{ "isNested", NULL },
{ "isFloating", NULL },
{ "isIntegral", NULL },
{ "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 },
{ "getUnitTests", NULL },
{ "getVirtualIndex", NULL },
{ "getPointerBitmap", NULL },
+ { "isReturnOnStack", NULL },
+ { "isZeroInit", NULL },
+ { "getTargetInfo", NULL },
+ { "getLocation", NULL },
+ { "hasPostblit", NULL },
+ { "isCopyable", NULL },
// For C++ mangling
{ "allocator", NULL },
void accept(Visitor *v) { v->visit(this); }
Module *isPackageMod();
+ void resolvePKGunknown();
};
class Module : public Package
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
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 &&
}
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;
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;
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) ||
#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.
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);
class FuncDeclaration;
class Parameter;
class Type;
+class TypeFunction;
class TypeTuple;
struct OutBuffer;
// 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;
#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);
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;
}
}
}
+/***************************************************
+ * 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);
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();
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();
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
{
"isAbstractClass",
"isArithmetic",
"isAssociativeArray",
+ "isDisabled",
+ "isDeprecated",
+ "isFuture",
"isFinalClass",
"isPOD",
"isNested",
"isFinalFunction",
"isOverrideFunction",
"isStaticFunction",
+ "isModule",
+ "isPackage",
"isRef",
"isOut",
"isLazy",
+ "isReturnOnStack",
"hasMember",
"identifier",
"getProtection",
+ "getVisibility",
"parent",
+ "child",
"getLinkage",
"getMember",
"getOverloads",
"getUnitTests",
"getVirtualIndex",
"getPointerBitmap",
+ "isZeroInit",
+ "getTargetInfo",
+ "getLocation",
+ "hasPostblit",
+ "isCopyable",
NULL
};
- traitsStringTable._init(40);
+ traitsStringTable._init(56);
for (size_t idx = 0;; idx++)
{
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
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;
{
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);
}
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)
{
}
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)
{
}
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)
}
else
{
- Dsymbol *s = getDsymbol(o);
+ Dsymbol *s = getDsymbolWithoutExpCtx(o);
if (!s || !s->ident)
{
e->error("argument %s has no identifier", o->toChars());
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);
return new ErrorExp();
RootObject *o = (*e->args)[0];
- Dsymbol *s = getDsymbol(o);
+ Dsymbol *s = getDsymbolWithoutExpCtx(o);
if (!s)
{
if (!isError(o))
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
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];
}
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)
{
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);
}
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();
/* Create tuple of functions of ex
*/
Expressions *exps = new Expressions();
- FuncDeclaration *f;
+ Dsymbol *f;
if (ex->op == TOKvar)
{
VarExp *ve = (VarExp *)ex;
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);
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");
}
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");
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:
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;
}
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();
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)
{
}
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());
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
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",
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)
{
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);
--- /dev/null
+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
--- /dev/null
+/// Used to test is(x == package) and is(x == module)
+
+module imports.pkgmodule;
--- /dev/null
+/// Used to test is(x == module)
+module imports.pkgmodule.plainmodule;
--- /dev/null
+/// Used to test is(x == module)
+
+module imports.plainpackage.plainmodule;
+
--- /dev/null
+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)));
--- /dev/null
+struct S { int[10] a; }
+int test1();
+S test2();
+
+static assert(__traits(isReturnOnStack, test1) == false);
+static assert(__traits(isReturnOnStack, test2) == true);
+
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");
--- /dev/null
+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));
--- /dev/null
+/*
+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; }));
+}
// 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));
--- /dev/null
+/*
+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
--- /dev/null
+/*
+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
--- /dev/null
+/*
+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);
+}
--- /dev/null
+/*
+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);
--- /dev/null
+/*
+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);
--- /dev/null
+/* 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);
--- /dev/null
+/*
+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));
+}
--- /dev/null
+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]);
--- /dev/null
+/************************************************************/
+
+/*
+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);
--- /dev/null
+/************************************************************/
+
+/*
+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);
--- /dev/null
+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);
+}
--- /dev/null
+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() {}
--- /dev/null
+@__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));
+}
--- /dev/null
+/*
+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");`);
+}
class AC3 : AC2 { }
final class FC { void foo() { } }
enum E { EMEM }
+struct D1 { @disable void true_(); void false_(){} }
/********************************************************/
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
public struct TestProt4 {}
export struct TestProt5 {}
-void getProtection()
+void getVisibility()
{
class Test
{
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");
}
/********************************************************/
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");
}
/********************************************************/
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
/********************************************************/
+void testIsDisabled()
+{
+ static assert(__traits(isDisabled, D1.true_));
+ static assert(!__traits(isDisabled, D1.false_));
+ static assert(!__traits(isDisabled, D1));
+}
+
+/********************************************************/
+
int main()
{
test1();
test_getFunctionAttributes();
test_isOverrideFunction();
test12237();
+ test15094();
writeln("Success");
return 0;
--- /dev/null
+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);
+}