d: Merge upstream dmd a5c86f5b9

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.
This commit is contained in:
Iain Buclaw 2021-01-04 19:05:38 +01:00
parent ae1ada95fe
commit c5e94699ef
47 changed files with 1882 additions and 427 deletions

View 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;

View 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

View 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;
}

View 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 */

View 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.

View 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; }

View 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,6 +210,133 @@ static void checkModFileAlias(OutBuffer *buf, OutBuffer *dotmods,
dotmods->writeByte('.');
}
/**
* 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)
{
const char *filename = ident->toChars();
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('\\');
#else
buf.writeByte('/');
#endif
}
buf.writestring(filename);
if (msdim)
checkModFileAlias(&buf, &dotmods, ms, msdim, filename);
buf.writeByte(0);
filename = (char *)buf.extractData();
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.
*/
static const char *lookForSourceFile(const char *filename)
{
/* Search along global.path for .di file, then .d file.
*/
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)
{
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());
@ -223,50 +345,15 @@ Module *Module::load(Loc loc, Identifiers *packages, Identifier *ident)
// 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 _WIN32
buf.writeByte('\\');
#else
buf.writeByte('/');
#endif
}
buf.writestring(filename);
if (msdim)
checkModFileAlias(&buf, &dotmods, ms, msdim, filename);
buf.writeByte(0);
filename = (char *)buf.extractData();
}
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;
/* Look for the source file
*/
const char *path;
const char *result = lookForSourceFile(&path, filename);
if (result)
{
m->srcfile = new File(result);
if (path)
m->srcfilePath = path;
else if (!FileName::absolute(result))
m->srcfilePath = getcwd(NULL, 0);
}
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;
}

View 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))
{

View 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;

View 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);

View 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)

View 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

View 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;

View 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 },

View 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

View 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 &&

View 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) ||

View 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.

View 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);

View 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;

File diff suppressed because it is too large Load diff

View file

@ -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);

View file

@ -0,0 +1,3 @@
/// Used to test is(x == package) and is(x == module)
module imports.pkgmodule;

View file

@ -0,0 +1,2 @@
/// Used to test is(x == module)
module imports.pkgmodule.plainmodule;

View file

@ -0,0 +1,4 @@
/// Used to test is(x == module)
module imports.plainpackage.plainmodule;

View file

@ -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)));

View file

@ -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);

View 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");

View file

@ -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));

View file

@ -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; }));
}

View file

@ -1,10 +1,140 @@
// REQUIRED_ARGS:
// EXTRA_FILES: imports/plainpackage/plainmodule.d imports/pkgmodule/package.d imports/pkgmodule/plainmodule.d
// This file is intended to contain all compilable traits-related tests in an
// effort to keep the number of files in the `compilable` folder to a minimum.
// https://issues.dlang.org/show_bug.cgi?id=19152
module traits;
class C19152
{
int OnExecute()
{
auto name = __traits(getOverloads, this, "OnExecute").stringof;
return 0;
}
}
static assert(is(typeof(__traits(getTargetInfo, "cppRuntimeLibrary")) == string));
version (CppRuntime_Microsoft)
{
static assert(__traits(getTargetInfo, "cppRuntimeLibrary") == "libcmt");
}
import imports.plainpackage.plainmodule;
import imports.pkgmodule.plainmodule;
#line 40
struct MyStruct;
alias a = imports.plainpackage;
alias b = imports.pkgmodule.plainmodule;
static assert(__traits(isPackage, imports.plainpackage));
static assert(__traits(isPackage, a));
static assert(!__traits(isPackage, imports.plainpackage.plainmodule));
static assert(!__traits(isPackage, b));
static assert(__traits(isPackage, imports.pkgmodule));
static assert(!__traits(isPackage, MyStruct));
static assert(!__traits(isModule, imports.plainpackage));
static assert(!__traits(isModule, a));
static assert(__traits(isModule, imports.plainpackage.plainmodule));
static assert(__traits(isModule, b));
// This is supposed to work even though we haven't directly imported imports.pkgmodule.
static assert(__traits(isModule, imports.pkgmodule));
static assert(!__traits(isModule, MyStruct));
/******************************************/
// https://issues.dlang.org/show_bug.cgi?id=19942
static assert(!__traits(compiles, { a.init; }));
static assert(!__traits(compiles, { import m : a; a.init; }));
version(Windows)
static assert(__traits(getLocation, MyStruct)[0] == `compilable\traits.d`);
else
static assert(__traits(getLocation, MyStruct)[0] == "compilable/traits.d");
static assert(__traits(getLocation, MyStruct)[1] == 40);
static assert(__traits(getLocation, MyStruct)[2] == 1);
int foo();
int foo(int);
static assert(__traits(getLocation, __traits(getOverloads, traits, "foo")[1])[1] == 74);
mixin("int bar;");
static assert(__traits(getLocation, bar)[1] == 78);
struct Outer
{
struct Nested{}
void method() {}
}
static assert(__traits(getLocation, Outer.Nested)[1] == 83);
static assert(__traits(getLocation, Outer.method)[1] == 85);
/******************************************/
// https://issues.dlang.org/show_bug.cgi?id=19902
// Define hasElaborateCopyConstructor trait
// but done as two independent traits per conversation
// in https://github.com/dlang/dmd/pull/10265
struct S
{
this (ref S rhs) {}
}
struct OuterS
{
struct S
{
this (ref S rhs) {}
}
S s;
}
void foo(T)()
{
struct S(U)
{
this (ref S rhs) {}
}
}
struct U(T)
{
this (ref U rhs) {}
}
struct SPostblit
{
this(this) {}
}
struct DisabledPostblit
{
@disable this(this);
}
struct NoCpCtor { }
class C19902 { }
static assert(__traits(compiles, foo!int));
static assert(__traits(compiles, foo!S));
static assert(!__traits(hasPostblit, U!S));
static assert(__traits(hasPostblit, SPostblit));
static assert(!__traits(hasPostblit, NoCpCtor));
static assert(!__traits(hasPostblit, C19902));
static assert(!__traits(hasPostblit, int));
// Check that invalid use cases don't compile
static assert(!__traits(compiles, __traits(hasPostblit)));
static assert(!__traits(compiles, __traits(hasPostblit, S())));
static assert(__traits(isCopyable, int));
static assert(!__traits(isCopyable, DisabledPostblit));

View file

@ -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"));

View file

@ -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));

View file

@ -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);
}

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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));
}

View file

@ -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]);

View file

@ -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);

View file

@ -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);

View file

@ -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);
}

View file

@ -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() {}

View file

@ -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));
}

View file

@ -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");`);
}

View 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(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(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(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(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(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(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(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(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(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(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, __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;

View file

@ -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);
}