diff options
author | Iain Buclaw <ibuclaw@gdcproject.org> | 2021-01-04 19:05:38 +0100 |
---|---|---|
committer | Iain Buclaw <ibuclaw@gdcproject.org> | 2021-01-05 22:09:10 +0100 |
commit | c5e94699efa816444c0ae49ad55d0e01a48203df (patch) | |
tree | f527fd1748c2f034d74ca1b268d4f56fc36cf050 /gcc/d | |
parent | ae1ada95fee1ee4fac0dec0486076d9787988a03 (diff) | |
download | gcc-c5e94699efa816444c0ae49ad55d0e01a48203df.zip gcc-c5e94699efa816444c0ae49ad55d0e01a48203df.tar.gz gcc-c5e94699efa816444c0ae49ad55d0e01a48203df.tar.bz2 |
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.
Diffstat (limited to 'gcc/d')
-rw-r--r-- | gcc/d/d-builtins.cc | 14 | ||||
-rw-r--r-- | gcc/d/d-frontend.cc | 20 | ||||
-rw-r--r-- | gcc/d/d-target.cc | 104 | ||||
-rw-r--r-- | gcc/d/d-target.h | 15 | ||||
-rw-r--r-- | gcc/d/dmd/MERGE | 2 | ||||
-rw-r--r-- | gcc/d/dmd/declaration.h | 3 | ||||
-rw-r--r-- | gcc/d/dmd/dmodule.c | 289 | ||||
-rw-r--r-- | gcc/d/dmd/dstruct.c | 118 | ||||
-rw-r--r-- | gcc/d/dmd/dtemplate.c | 6 | ||||
-rw-r--r-- | gcc/d/dmd/expression.c | 9 | ||||
-rw-r--r-- | gcc/d/dmd/expressionsem.c | 67 | ||||
-rw-r--r-- | gcc/d/dmd/func.c | 39 | ||||
-rw-r--r-- | gcc/d/dmd/globals.h | 2 | ||||
-rw-r--r-- | gcc/d/dmd/idgen.c | 13 | ||||
-rw-r--r-- | gcc/d/dmd/module.h | 2 | ||||
-rw-r--r-- | gcc/d/dmd/mtype.c | 1 | ||||
-rw-r--r-- | gcc/d/dmd/parse.c | 15 | ||||
-rw-r--r-- | gcc/d/dmd/root/filename.c | 14 | ||||
-rw-r--r-- | gcc/d/dmd/root/filename.h | 1 | ||||
-rw-r--r-- | gcc/d/dmd/target.h | 3 | ||||
-rw-r--r-- | gcc/d/dmd/traits.c | 684 |
21 files changed, 1070 insertions, 351 deletions
diff --git a/gcc/d/d-builtins.cc b/gcc/d/d-builtins.cc index 9d0c91a..26ccd00 100644 --- a/gcc/d/d-builtins.cc +++ b/gcc/d/d-builtins.cc @@ -393,6 +393,20 @@ d_eval_constant_expression (const Loc &loc, tree cst) return VectorExp::create (loc, e, type); } + else if (code == ADDR_EXPR) + { + /* Special handling for trees constructed by build_string_literal. + What we receive is an `&"string"[0]' expression, strip off the + outer ADDR_EXPR and ARRAY_REF to get to the underlying CST. */ + tree pointee = TREE_OPERAND (cst, 0); + + if (TREE_CODE (pointee) != ARRAY_REF + || TREE_OPERAND (pointee, 1) != integer_zero_node + || TREE_CODE (TREE_OPERAND (pointee, 0)) != STRING_CST) + return NULL; + + return d_eval_constant_expression (loc, TREE_OPERAND (pointee, 0)); + } } return NULL; diff --git a/gcc/d/d-frontend.cc b/gcc/d/d-frontend.cc index 73548e1..32550ec 100644 --- a/gcc/d/d-frontend.cc +++ b/gcc/d/d-frontend.cc @@ -139,26 +139,6 @@ Loc::equals (const Loc &loc) /* Implements back-end specific interfaces used by the frontend. */ -/* Determine return style of function - whether in registers or through a - hidden pointer to the caller's stack. */ - -RET -retStyle (TypeFunction *tf) -{ - /* Need the backend type to determine this, but this is called from the - frontend before semantic processing is finished. An accurate value - is not currently needed anyway. */ - if (tf->isref) - return RETregs; - - Type *tn = tf->next->toBasetype (); - - if (tn->ty == Tstruct || tn->ty == Tsarray) - return RETstack; - - return RETregs; -} - /* Determine if function FD is a builtin one that we can evaluate in CTFE. */ BUILTIN diff --git a/gcc/d/d-target.cc b/gcc/d/d-target.cc index 48c1414..d50fcef 100644 --- a/gcc/d/d-target.cc +++ b/gcc/d/d-target.cc @@ -44,6 +44,25 @@ along with GCC; see the file COPYING3. If not see Target target; +/* Internal key handlers for `__traits(getTargetInfo)'. */ +static tree d_handle_target_cpp_std (void); +static tree d_handle_target_cpp_runtime_library (void); + +/* In [traits/getTargetInfo], a reliable subset of getTargetInfo keys exists + which are always available. */ +static const struct d_target_info_spec d_language_target_info[] = +{ + /* { name, handler } */ + { "cppStd", d_handle_target_cpp_std }, + { "cppRuntimeLibrary", d_handle_target_cpp_runtime_library }, + { "floatAbi", NULL }, + { "objectFormat", NULL }, + { NULL, NULL }, +}; + +/* Table `__traits(getTargetInfo)' keys. */ +static vec<d_target_info_spec> d_target_info_table; + /* Initialize the floating-point constants for TYPE. */ @@ -167,6 +186,10 @@ Target::_init (const Param &) real_convert (&CTFloat::one.rv (), mode, &dconst1); real_convert (&CTFloat::minusone.rv (), mode, &dconstm1); real_convert (&CTFloat::half.rv (), mode, &dconsthalf); + + /* Initialize target info tables, the keys required by the language are added + last, so that the OS and CPU handlers can override. */ + d_add_target_info_handlers (d_language_target_info); } /* Return GCC memory alignment size for type TYPE. */ @@ -413,3 +436,84 @@ Target::toArgTypes (Type *) /* Not implemented, however this is not currently used anywhere. */ return NULL; } + +/* Determine return style of function, whether in registers or through a + hidden pointer to the caller's stack. */ + +bool +Target::isReturnOnStack (TypeFunction *tf, bool) +{ + /* Need the back-end type to determine this, but this is called from the + frontend before semantic processing is finished. An accurate value + is not currently needed anyway. */ + if (tf->isref) + return false; + + Type *tn = tf->next->toBasetype (); + + return (tn->ty == Tstruct || tn->ty == Tsarray); +} + +/* Add all target info in HANDLERS to D_TARGET_INFO_TABLE for use by + Target::getTargetInfo(). */ + +void +d_add_target_info_handlers (const d_target_info_spec *handlers) +{ + gcc_assert (handlers != NULL); + + if (d_target_info_table.is_empty ()) + d_target_info_table.create (8); + + for (size_t i = 0; handlers[i].name != NULL; i++) + d_target_info_table.safe_push (handlers[i]); +} + +/* Handle a call to `__traits(getTargetInfo, "cppStd")'. */ + +tree +d_handle_target_cpp_std (void) +{ + return build_integer_cst (global.params.cplusplus); +} + +/* Handle a call to `__traits(getTargetInfo, "cppRuntimeLibrary")'. */ + +tree +d_handle_target_cpp_runtime_library (void) +{ + /* The driver only ever optionally links to libstdc++. */ + const char *libstdcxx = "libstdc++"; + return build_string_literal (strlen (libstdcxx) + 1, libstdcxx); +} + +/* Look up the target info KEY in the available getTargetInfo tables, and return + the result as an Expression, or NULL if KEY is not found. When the key must + always exist, but is not supported, an empty string expression is returned. + LOC is the location to use for the returned expression. */ + +Expression * +Target::getTargetInfo (const char *key, const Loc &loc) +{ + unsigned ix; + d_target_info_spec *spec; + + FOR_EACH_VEC_ELT (d_target_info_table, ix, spec) + { + tree result; + + if (strcmp (key, spec->name) != 0) + continue; + + /* Get the requested information, or empty string if unhandled. */ + if (spec->handler) + result = (spec->handler) (); + else + result = build_string_literal (1, ""); + + gcc_assert (result); + return d_eval_constant_expression (loc, result); + } + + return NULL; +} diff --git a/gcc/d/d-target.h b/gcc/d/d-target.h index 211f72f..56595d2 100644 --- a/gcc/d/d-target.h +++ b/gcc/d/d-target.h @@ -31,4 +31,19 @@ extern struct gcc_targetdm targetdm; /* Used by target to add predefined version idenditiers. */ extern void d_add_builtin_version (const char *); +/* Structure describing a supported key for `__traits(getTargetInfo)' and a + function to handle it. */ +struct d_target_info_spec +{ + /* The name of the key or NULL to mark the end of a table of keys. */ + const char *name; + /* Function to handle this key, the return value of the handler must be a CST. + This pointer may be NULL if no special handling is required, for instance, + the key must always be available according to the D language spec. */ + tree (*handler) (); +}; + +/* Used by target to add getTargetInfo handlers. */ +extern void d_add_target_info_handlers (const d_target_info_spec *); + #endif /* GCC_D_TARGET_H */ diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index 1f695b9..1629b45 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -2bd4fc3fed8b8cd9760e77c6b2a1905cd84d0e70 +a5c86f5b92c4cd3afde910c89881ccaea11de554 The first line of this file holds the git revision number of the last merge done from the dlang/dmd repository. diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h index 65ac3f7..a4e7766 100644 --- a/gcc/d/dmd/declaration.h +++ b/gcc/d/dmd/declaration.h @@ -149,6 +149,7 @@ public: bool isSynchronized() { return (storage_class & STCsynchronized) != 0; } bool isParameter() { return (storage_class & STCparameter) != 0; } bool isDeprecated() { return (storage_class & STCdeprecated) != 0; } + bool isDisabled() { return (storage_class & STCdisable) != 0; } bool isOverride() { return (storage_class & STCoverride) != 0; } bool isResult() { return (storage_class & STCresult) != 0; } bool isField() { return (storage_class & STCfield) != 0; } @@ -669,7 +670,7 @@ public: static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, const char *name, StorageClass stc=0); static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, Identifier *id, StorageClass stc=0); void checkDmain(); - bool checkNrvo(); + bool checkNRVO(); FuncDeclaration *isFuncDeclaration() { return this; } diff --git a/gcc/d/dmd/dmodule.c b/gcc/d/dmd/dmodule.c index 8f09f2d..305b133 100644 --- a/gcc/d/dmd/dmodule.c +++ b/gcc/d/dmd/dmodule.c @@ -34,7 +34,6 @@ Dsymbols Module::deferred2; // deferred Dsymbol's needing semantic2() run on the Dsymbols Module::deferred3; // deferred Dsymbol's needing semantic3() run on them unsigned Module::dprogress; -const char *lookForSourceFile(const char **path, const char *filename); StringExp *semanticString(Scope *sc, Expression *exp, const char *s); void Module::_init() @@ -72,7 +71,6 @@ Module::Module(const char *filename, Identifier *ident, int doDocComment, int do sfilename = NULL; importedFrom = NULL; srcfile = NULL; - srcfilePath = NULL; docfile = NULL; debuglevel = 0; @@ -109,9 +107,6 @@ Module::Module(const char *filename, Identifier *ident, int doDocComment, int do fatal(); } srcfile = new File(srcfilename); - if (!FileName::absolute(srcfilename)) - srcfilePath = getcwd(NULL, 0); - objfile = setOutfile(global.params.objname.ptr, global.params.objdir.ptr, filename, global.obj_ext.ptr); if (doDocComment) @@ -215,57 +210,149 @@ static void checkModFileAlias(OutBuffer *buf, OutBuffer *dotmods, dotmods->writeByte('.'); } -Module *Module::load(Loc loc, Identifiers *packages, Identifier *ident) +/** + * Converts a chain of identifiers to the filename of the module + * + * Params: + * packages = the names of the "parent" packages + * ident = the name of the child package or module + * + * Returns: + * the filename of the child package or module + */ +static const char *getFilename(Identifiers *packages, Identifier *ident) { - //printf("Module::load(ident = '%s')\n", ident->toChars()); - - // Build module filename by turning: - // foo.bar.baz - // into: - // foo\bar\baz const char *filename = ident->toChars(); - if (packages && packages->length) - { - OutBuffer buf; - OutBuffer dotmods; - Array<const char *> *ms = &global.params.modFileAliasStrings; - const size_t msdim = ms ? ms->length : 0; - for (size_t i = 0; i < packages->length; i++) - { - Identifier *pid = (*packages)[i]; - const char *p = pid->toChars(); - buf.writestring(p); - if (msdim) - checkModFileAlias(&buf, &dotmods, ms, msdim, p); + if (packages == NULL || packages->length == 0) + return filename; + + OutBuffer buf; + OutBuffer dotmods; + Array<const char *> *ms = &global.params.modFileAliasStrings; + const size_t msdim = ms ? ms->length : 0; + + for (size_t i = 0; i < packages->length; i++) + { + Identifier *pid = (*packages)[i]; + const char *p = pid->toChars(); + buf.writestring(p); + if (msdim) + checkModFileAlias(&buf, &dotmods, ms, msdim, p); #if _WIN32 - buf.writeByte('\\'); + buf.writeByte('\\'); #else - buf.writeByte('/'); + buf.writeByte('/'); #endif - } - buf.writestring(filename); - if (msdim) - checkModFileAlias(&buf, &dotmods, ms, msdim, filename); - buf.writeByte(0); - filename = (char *)buf.extractData(); } + buf.writestring(filename); + if (msdim) + checkModFileAlias(&buf, &dotmods, ms, msdim, filename); + buf.writeByte(0); + filename = (char *)buf.extractData(); - Module *m = new Module(filename, ident, 0, 0); - m->loc = loc; + return filename; +} + +/******************************************** + * Look for the source file if it's different from filename. + * Look for .di, .d, directory, and along global.path. + * Does not open the file. + * Input: + * filename as supplied by the user + * global.path + * Returns: + * NULL if it's not different from filename. + */ - /* Look for the source file +static const char *lookForSourceFile(const char *filename) +{ + /* Search along global.path for .di file, then .d file. */ - const char *path; - const char *result = lookForSourceFile(&path, filename); - if (result) + const char *sdi = FileName::forceExt(filename, global.hdr_ext.ptr); + if (FileName::exists(sdi) == 1) + return sdi; + + const char *sd = FileName::forceExt(filename, global.mars_ext.ptr); + if (FileName::exists(sd) == 1) + return sd; + + if (FileName::exists(filename) == 2) { - m->srcfile = new File(result); - if (path) - m->srcfilePath = path; - else if (!FileName::absolute(result)) - m->srcfilePath = getcwd(NULL, 0); + /* The filename exists and it's a directory. + * Therefore, the result should be: filename/package.d + * iff filename/package.d is a file + */ + const char *ni = FileName::combine(filename, "package.di"); + if (FileName::exists(ni) == 1) + return ni; + FileName::free(ni); + const char *n = FileName::combine(filename, "package.d"); + if (FileName::exists(n) == 1) + return n; + FileName::free(n); + } + + if (FileName::absolute(filename)) + return NULL; + + if (!global.path) + return NULL; + + for (size_t i = 0; i < global.path->length; i++) + { + const char *p = (*global.path)[i]; + const char *n = FileName::combine(p, sdi); + if (FileName::exists(n) == 1) + { + return n; + } + FileName::free(n); + + n = FileName::combine(p, sd); + if (FileName::exists(n) == 1) + { + return n; + } + FileName::free(n); + + const char *b = FileName::removeExt(filename); + n = FileName::combine(p, b); + FileName::free(b); + if (FileName::exists(n) == 2) + { + const char *n2i = FileName::combine(n, "package.di"); + if (FileName::exists(n2i) == 1) + return n2i; + FileName::free(n2i); + const char *n2 = FileName::combine(n, "package.d"); + if (FileName::exists(n2) == 1) + { + return n2; + } + FileName::free(n2); + } + FileName::free(n); } + return NULL; +} + +Module *Module::load(Loc loc, Identifiers *packages, Identifier *ident) +{ + //printf("Module::load(ident = '%s')\n", ident->toChars()); + + // Build module filename by turning: + // foo.bar.baz + // into: + // foo\bar\baz + const char *filename = getFilename(packages, ident); + // Look for the source file + const char *result = lookForSourceFile(filename); + if (result) + filename = result; + + Module *m = new Module(filename, ident, 0, 0); + m->loc = loc; if (!m->read(loc)) return NULL; @@ -1159,6 +1246,27 @@ Module *Package::isPackageMod() } /** + * 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 * * For example, if this qualifies to 'a1.a2' and pkg - to 'a1.a2.a3', @@ -1266,96 +1374,3 @@ Dsymbol *Package::search(const Loc &loc, Identifier *ident, int flags) return ScopeDsymbol::search(loc, ident, flags); } - -/* =========================== ===================== */ - -/******************************************** - * Look for the source file if it's different from filename. - * Look for .di, .d, directory, and along global.path. - * Does not open the file. - * Output: - * path the path where the file was found if it was not the current directory - * Input: - * filename as supplied by the user - * global.path - * Returns: - * NULL if it's not different from filename. - */ - -const char *lookForSourceFile(const char **path, const char *filename) -{ - /* Search along global.path for .di file, then .d file. - */ - *path = NULL; - - const char *sdi = FileName::forceExt(filename, global.hdr_ext.ptr); - if (FileName::exists(sdi) == 1) - return sdi; - - const char *sd = FileName::forceExt(filename, global.mars_ext.ptr); - if (FileName::exists(sd) == 1) - return sd; - - if (FileName::exists(filename) == 2) - { - /* The filename exists and it's a directory. - * Therefore, the result should be: filename/package.d - * iff filename/package.d is a file - */ - const char *ni = FileName::combine(filename, "package.di"); - if (FileName::exists(ni) == 1) - return ni; - FileName::free(ni); - const char *n = FileName::combine(filename, "package.d"); - if (FileName::exists(n) == 1) - return n; - FileName::free(n); - } - - if (FileName::absolute(filename)) - return NULL; - - if (!global.path) - return NULL; - - for (size_t i = 0; i < global.path->length; i++) - { - const char *p = (*global.path)[i]; - - const char *n = FileName::combine(p, sdi); - if (FileName::exists(n) == 1) - { - *path = p; - return n; - } - FileName::free(n); - - n = FileName::combine(p, sd); - if (FileName::exists(n) == 1) - { - *path = p; - return n; - } - FileName::free(n); - - const char *b = FileName::removeExt(filename); - n = FileName::combine(p, b); - FileName::free(b); - if (FileName::exists(n) == 2) - { - const char *n2i = FileName::combine(n, "package.di"); - if (FileName::exists(n2i) == 1) - return n2i; - FileName::free(n2i); - const char *n2 = FileName::combine(n, "package.d"); - if (FileName::exists(n2) == 1) - { - *path = p; - return n2; - } - FileName::free(n2); - } - FileName::free(n); - } - return NULL; -} diff --git a/gcc/d/dmd/dstruct.c b/gcc/d/dmd/dstruct.c index 2b87154..8829367 100644 --- a/gcc/d/dmd/dstruct.c +++ b/gcc/d/dmd/dstruct.c @@ -23,6 +23,8 @@ #include "template.h" #include "tokens.h" #include "target.h" +#include "utf.h" +#include "root/ctfloat.h" Type *getTypeInfoType(Loc loc, Type *t, Scope *sc); void unSpeculative(Scope *sc, RootObject *o); @@ -1245,6 +1247,102 @@ Dsymbol *StructDeclaration::search(const Loc &loc, Identifier *ident, int flags) return ScopeDsymbol::search(loc, ident, flags); } +/********************************** + * Determine if exp is all binary zeros. + * Params: + * exp = expression to check + * Returns: + * true if it's all binary 0 + */ +static bool isZeroInit(Expression *exp) +{ + switch (exp->op) + { + case TOKint64: + return exp->toInteger() == 0; + + case TOKnull: + case TOKfalse: + return true; + + case TOKstructliteral: + { + StructLiteralExp *sle = (StructLiteralExp *) exp; + for (size_t i = 0; i < sle->sd->fields.length; i++) + { + VarDeclaration *field = sle->sd->fields[i]; + if (field->type->size(field->loc)) + { + Expression *e = (*sle->elements)[i]; + if (e ? !isZeroInit(e) + : !field->type->isZeroInit(field->loc)) + return false; + } + } + return true; + } + + case TOKarrayliteral: + { + ArrayLiteralExp *ale = (ArrayLiteralExp *) exp; + + const size_t dim = ale->elements ? ale->elements->length : 0; + + if (ale->type->toBasetype()->ty == Tarray) // if initializing a dynamic array + return dim == 0; + + for (size_t i = 0; i < dim; i++) + { + if (!isZeroInit(ale->getElement(i))) + return false; + } + /* Note that true is returned for all T[0] + */ + return true; + } + + case TOKstring: + { + StringExp *se = exp->toStringExp(); + + if (se->type->toBasetype()->ty == Tarray) // if initializing a dynamic array + return se->len == 0; + + void *s = se->string; + for (size_t i = 0; i < se->len; i++) + { + dinteger_t val; + switch (se->sz) + { + case 1: val = (( utf8_t *)s)[i]; break; + case 2: val = ((utf16_t *)s)[i]; break; + case 4: val = ((utf32_t *)s)[i]; break; + default: assert(0); break; + } + if (val) + return false; + } + return true; + } + + case TOKvector: + { + VectorExp *ve = (VectorExp *) exp; + return isZeroInit(ve->e1); + } + + case TOKfloat64: + case TOKcomplex80: + { + return (exp->toReal() == CTFloat::zero) && + (exp->toImaginary() == CTFloat::zero); + } + + default: + return false; + } +} + void StructDeclaration::finalizeSize() { //printf("StructDeclaration::finalizeSize() %s, sizeok = %d\n", toChars(), sizeok); @@ -1301,9 +1399,23 @@ void StructDeclaration::finalizeSize() VarDeclaration *vd = fields[i]; if (vd->_init) { - // Should examine init to see if it is really all 0's - zeroInit = 0; - break; + if (vd->_init->isVoidInitializer()) + /* Treat as 0 for the purposes of putting the initializer + * in the BSS segment, or doing a mass set to 0 + */ + continue; + + // Zero size fields are zero initialized + if (vd->type->size(vd->loc) == 0) + continue; + + // Examine init to see if it is all 0s. + Expression *exp = vd->getConstInitializer(); + if (!exp || !isZeroInit(exp)) + { + zeroInit = 0; + break; + } } else if (!vd->type->isZeroInit(loc)) { diff --git a/gcc/d/dmd/dtemplate.c b/gcc/d/dmd/dtemplate.c index fe65bd2..1035f82 100644 --- a/gcc/d/dmd/dtemplate.c +++ b/gcc/d/dmd/dtemplate.c @@ -6783,7 +6783,7 @@ bool TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f { //printf("type %s\n", ta->toChars()); // It might really be an Expression or an Alias - ta->resolve(loc, sc, &ea, &ta, &sa); + ta->resolve(loc, sc, &ea, &ta, &sa, (flags & 1) != 0); if (ea) goto Lexpr; if (sa) goto Ldsym; if (ta == NULL) @@ -6914,7 +6914,7 @@ bool TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f //goto Ldsym; } } - if (ea->op == TOKdotvar) + if (ea->op == TOKdotvar && !(flags & 1)) { // translate expression to dsymbol. sa = ((DotVarExp *)ea)->var; @@ -6925,7 +6925,7 @@ bool TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f sa = ((TemplateExp *)ea)->td; goto Ldsym; } - if (ea->op == TOKdottd) + if (ea->op == TOKdottd && !(flags & 1)) { // translate expression to dsymbol. sa = ((DotTemplateExp *)ea)->td; diff --git a/gcc/d/dmd/expression.c b/gcc/d/dmd/expression.c index 09dd3af..7891832 100644 --- a/gcc/d/dmd/expression.c +++ b/gcc/d/dmd/expression.c @@ -3337,7 +3337,7 @@ ClassReferenceExp *Expression::isClassReferenceExp() /**************************************** - * Resolve __FILE__, __LINE__, __MODULE__, __FUNCTION__, __PRETTY_FUNCTION__ to loc. + * Resolve __FILE__, __LINE__, __MODULE__, __FUNCTION__, __PRETTY_FUNCTION__, __FILE__FULL_PATH__ to loc. */ Expression *Expression::resolveLoc(Loc, Scope *) @@ -7170,9 +7170,12 @@ FileInitExp::FileInitExp(Loc loc, TOK tok) Expression *FileInitExp::resolveLoc(Loc loc, Scope *sc) { //printf("FileInitExp::resolve() %s\n", toChars()); - const char *s = loc.filename ? loc.filename : sc->_module->ident->toChars(); + const char *s; if (subop == TOKfilefullpath) - s = FileName::combine(sc->_module->srcfilePath, s); + s = FileName::toAbsolute(loc.filename != NULL ? loc.filename : sc->_module->srcfile->name->toChars()); + else + s = loc.filename != NULL ? loc.filename : sc->_module->ident->toChars(); + Expression *e = new StringExp(loc, const_cast<char *>(s)); e = semantic(e, sc); e = e->castTo(sc, type); diff --git a/gcc/d/dmd/expressionsem.c b/gcc/d/dmd/expressionsem.c index d251996..7dfe995 100644 --- a/gcc/d/dmd/expressionsem.c +++ b/gcc/d/dmd/expressionsem.c @@ -119,6 +119,36 @@ static bool preFunctionParameters(Scope *sc, Expressions *exps) return err; } +/** + * Determines whether a symbol represents a module or package + * (Used as a helper for is(type == module) and is(type == package)) + * + * Params: + * sym = the symbol to be checked + * + * Returns: + * the symbol which `sym` represents (or `null` if it doesn't represent a `Package`) + */ +Package *resolveIsPackage(Dsymbol *sym) +{ + Package *pkg; + if (Import *imp = sym->isImport()) + { + if (imp->pkg == NULL) + { + error(sym->loc, "Internal Compiler Error: unable to process forward-referenced import `%s`", + imp->toChars()); + assert(0); + } + pkg = imp->pkg; + } + else + pkg = sym->isPackage(); + if (pkg) + pkg->resolvePKGunknown(); + return pkg; +} + class ExpressionSemanticVisitor : public Visitor { public: @@ -1920,15 +1950,34 @@ public: } Type *tded = NULL; - Scope *sc2 = sc->copy(); // keep sc->flags - sc2->tinst = NULL; - sc2->minst = NULL; - sc2->flags |= SCOPEfullinst; - Type *t = e->targ->trySemantic(e->loc, sc2); - sc2->pop(); - if (!t) - goto Lno; // errors, so condition is false - e->targ = t; + if (e->tok2 == TOKpackage || e->tok2 == TOKmodule) // These is() expressions are special because they can work on modules, not just types. + { + Dsymbol *sym = e->targ->toDsymbol(sc); + if (sym == NULL) + goto Lno; + Package *p = resolveIsPackage(sym); + if (p == NULL) + goto Lno; + if (e->tok2 == TOKpackage && p->isModule()) // Note that isModule() will return null for package modules because they're not actually instances of Module. + goto Lno; + else if(e->tok2 == TOKmodule && !(p->isModule() || p->isPackageMod())) + goto Lno; + tded = e->targ; + goto Lyes; + } + + { + Scope *sc2 = sc->copy(); // keep sc->flags + sc2->tinst = NULL; + sc2->minst = NULL; + sc2->flags |= SCOPEfullinst; + Type *t = e->targ->trySemantic(e->loc, sc2); + sc2->pop(); + if (!t) // errors, so condition is false + goto Lno; + e->targ = t; + } + if (e->tok2 != TOKreserved) { switch (e->tok2) diff --git a/gcc/d/dmd/func.c b/gcc/d/dmd/func.c index dbc5fa6..fe1ad11 100644 --- a/gcc/d/dmd/func.c +++ b/gcc/d/dmd/func.c @@ -41,7 +41,6 @@ Expression *semantic(Expression *e, Scope *sc); int blockExit(Statement *s, FuncDeclaration *func, bool mustNotThrow); TypeIdentifier *getThrowable(); -RET retStyle(TypeFunction *tf); void MODtoBuffer(OutBuffer *buf, MOD mod); char *MODtoChars(MOD mod); bool MODimplicitConv(MOD modfrom, MOD modto); @@ -970,7 +969,7 @@ void FuncDeclaration::semantic(Scope *sc) { if (fdv->isFuture()) { - ::deprecation(loc, "@future base class method %s is being overridden by %s; rename the latter", + ::deprecation(loc, "@__future base class method %s is being overridden by %s; rename the latter", fdv->toPrettyChars(), toPrettyChars()); // Treat 'this' as an introducing function, giving it a separate hierarchy in the vtbl[] goto Lintro; @@ -1758,7 +1757,7 @@ void FuncDeclaration::semantic3(Scope *sc) if (storage_class & STCauto) storage_class &= ~STCauto; } - if (retStyle(f) != RETstack || checkNrvo()) + if (!target.isReturnOnStack(f, needThis()) || !checkNRVO()) nrvo_can = 0; if (fbody->isErrorStatement()) @@ -4275,19 +4274,16 @@ void FuncDeclaration::checkDmain() * using NRVO is possible. * * Returns: - * true if the result cannot be returned by hidden reference. + * `false` if the result cannot be returned by hidden reference. */ -bool FuncDeclaration::checkNrvo() +bool FuncDeclaration::checkNRVO() { - if (!nrvo_can) - return true; - - if (returns == NULL) - return true; + if (!nrvo_can || returns == NULL) + return false; TypeFunction *tf = type->toTypeFunction(); if (tf->isref) - return true; + return false; for (size_t i = 0; i < returns->length; i++) { @@ -4297,24 +4293,23 @@ bool FuncDeclaration::checkNrvo() { VarDeclaration *v = ve->var->isVarDeclaration(); if (!v || v->isOut() || v->isRef()) - return true; + return false; else if (nrvo_var == NULL) { - if (!v->isDataseg() && !v->isParameter() && v->toParent2() == this) - { - //printf("Setting nrvo to %s\n", v->toChars()); - nrvo_var = v; - } - else - return true; + // Variables in the data segment (e.g. globals, TLS or not), + // parameters and closure variables cannot be NRVOed. + if (v->isDataseg() || v->isParameter() || v->toParent2() != this) + return false; + //printf("Setting nrvo to %s\n", v->toChars()); + nrvo_var = v; } else if (nrvo_var != v) - return true; + return false; } else //if (!exp->isLvalue()) // keep NRVO-ability - return true; + return false; } - return false; + return true; } const char *FuncDeclaration::kind() const diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h index 6aff9b4..502bae2 100644 --- a/gcc/d/dmd/globals.h +++ b/gcc/d/dmd/globals.h @@ -286,7 +286,7 @@ typedef uint64_t d_uns64; // file location struct Loc { - const char *filename; + const char *filename; // either absolute or relative to cwd unsigned linnum; unsigned charnum; diff --git a/gcc/d/dmd/idgen.c b/gcc/d/dmd/idgen.c index 16f3b5f..09855a0 100644 --- a/gcc/d/dmd/idgen.c +++ b/gcc/d/dmd/idgen.c @@ -322,6 +322,9 @@ Msgtable msgtable[] = { "isFinalClass", NULL }, { "isTemplate", NULL }, { "isPOD", NULL }, + { "isDeprecated", NULL }, + { "isDisabled", NULL }, + { "isFuture" , NULL }, { "isNested", NULL }, { "isFloating", NULL }, { "isIntegral", NULL }, @@ -334,13 +337,17 @@ Msgtable msgtable[] = { "isFinalFunction", NULL }, { "isOverrideFunction", NULL }, { "isStaticFunction", NULL }, + { "isModule", NULL }, + { "isPackage", NULL }, { "isRef", NULL }, { "isOut", NULL }, { "isLazy", NULL }, { "hasMember", NULL }, { "identifier", NULL }, { "getProtection", NULL }, + { "getVisibility", NULL }, { "parent", NULL }, + { "child", NULL }, { "getMember", NULL }, { "getOverloads", NULL }, { "getVirtualFunctions", NULL }, @@ -360,6 +367,12 @@ Msgtable msgtable[] = { "getUnitTests", NULL }, { "getVirtualIndex", NULL }, { "getPointerBitmap", NULL }, + { "isReturnOnStack", NULL }, + { "isZeroInit", NULL }, + { "getTargetInfo", NULL }, + { "getLocation", NULL }, + { "hasPostblit", NULL }, + { "isCopyable", NULL }, // For C++ mangling { "allocator", NULL }, diff --git a/gcc/d/dmd/module.h b/gcc/d/dmd/module.h index 17ad590..4968ec7 100644 --- a/gcc/d/dmd/module.h +++ b/gcc/d/dmd/module.h @@ -48,6 +48,7 @@ public: void accept(Visitor *v) { v->visit(this); } Module *isPackageMod(); + void resolvePKGunknown(); }; class Module : public Package @@ -68,7 +69,6 @@ public: const char *arg; // original argument name ModuleDeclaration *md; // if !NULL, the contents of the ModuleDeclaration declaration File *srcfile; // input source file - const char* srcfilePath; // the path prefix to the srcfile if it applies File *objfile; // output .obj file File *hdrfile; // 'header' file File *docfile; // output documentation file diff --git a/gcc/d/dmd/mtype.c b/gcc/d/dmd/mtype.c index 6f0195a..94e2082 100644 --- a/gcc/d/dmd/mtype.c +++ b/gcc/d/dmd/mtype.c @@ -6682,6 +6682,7 @@ Type *TypeTraits::semantic(Loc, Scope *sc) exp->ident != Id::derivedMembers && exp->ident != Id::getMember && exp->ident != Id::parent && + exp->ident != Id::child && exp->ident != Id::getOverloads && exp->ident != Id::getVirtualFunctions && exp->ident != Id::getVirtualMethods && diff --git a/gcc/d/dmd/parse.c b/gcc/d/dmd/parse.c index 3e4dd06..be861fa 100644 --- a/gcc/d/dmd/parse.c +++ b/gcc/d/dmd/parse.c @@ -5949,7 +5949,10 @@ bool Parser::isDeclaration(Token *t, int needId, TOK endtok, Token **pt) } if (!isDeclarator(&t, &haveId, &haveTpl, endtok, needId != 3)) goto Lisnot; - if (needId == 1 || (needId == 0 && !haveId) || ((needId == 2 || needId == 3) && haveId)) + if ((needId == 0 && !haveId) || + (needId == 1) || + (needId == 2 && haveId) || + (needId == 3 && haveId)) { if (pt) *pt = t; @@ -6821,12 +6824,8 @@ Expression *Parser::parsePrimaryExp() case TOKfilefullpath: { - const char *srcfile = mod->srcfile->name->toChars(); - const char *s; - if (loc.filename && !FileName::equals(loc.filename, srcfile)) - s = loc.filename; - else - s = FileName::combine(mod->srcfilePath, srcfile); + assert(loc.filename); // __FILE_FULL_PATH__ does not work with an invalid location + const char *s = FileName::toAbsolute(loc.filename); e = new StringExp(loc, const_cast<char *>(s), strlen(s), 0); nextToken(); break; @@ -7039,6 +7038,8 @@ Expression *Parser::parsePrimaryExp() token.value == TOKsuper || token.value == TOKenum || token.value == TOKinterface || + token.value == TOKmodule || + token.value == TOKpackage || token.value == TOKargTypes || token.value == TOKparameters || (token.value == TOKconst && peek(&token)->value == TOKrparen) || diff --git a/gcc/d/dmd/root/filename.c b/gcc/d/dmd/root/filename.c index 50b6740..f0e0213 100644 --- a/gcc/d/dmd/root/filename.c +++ b/gcc/d/dmd/root/filename.c @@ -175,6 +175,20 @@ bool FileName::absolute(const char *name) #endif } +/** +Return the given name as an absolute path + +Params: + name = path + base = the absolute base to prefix name with if it is relative + +Returns: name as an absolute path relative to base +*/ +const char *FileName::toAbsolute(const char *name, const char *base) +{ + return absolute(name) ? name : combine(base ? base : getcwd(NULL, 0), name); +} + /******************************** * Return filename extension (read-only). * Points past '.' of extension. diff --git a/gcc/d/dmd/root/filename.h b/gcc/d/dmd/root/filename.h index 62a5a68..6ef515c 100644 --- a/gcc/d/dmd/root/filename.h +++ b/gcc/d/dmd/root/filename.h @@ -24,6 +24,7 @@ struct FileName int compare(RootObject *obj); static int compare(const char *name1, const char *name2); static bool absolute(const char *name); + static const char *toAbsolute(const char *name, const char *base = NULL); static const char *ext(const char *); const char *ext(); static const char *removeExt(const char *str); diff --git a/gcc/d/dmd/target.h b/gcc/d/dmd/target.h index f2a55d6..5a2dd4d 100644 --- a/gcc/d/dmd/target.h +++ b/gcc/d/dmd/target.h @@ -22,6 +22,7 @@ class Expression; class FuncDeclaration; class Parameter; class Type; +class TypeFunction; class TypeTuple; struct OutBuffer; @@ -105,6 +106,8 @@ public: // ABI and backend. LINK systemLinkage(); TypeTuple *toArgTypes(Type *t); + bool isReturnOnStack(TypeFunction *tf, bool needsThis); + Expression *getTargetInfo(const char* name, const Loc& loc); }; extern Target target; diff --git a/gcc/d/dmd/traits.c b/gcc/d/dmd/traits.c index bc1e2c3..6585299 100644 --- a/gcc/d/dmd/traits.c +++ b/gcc/d/dmd/traits.c @@ -32,11 +32,13 @@ #include "attrib.h" #include "parse.h" #include "root/speller.h" +#include "target.h" typedef int (*ForeachDg)(void *ctx, size_t idx, Dsymbol *s); int ScopeDsymbol_foreach(Scope *sc, Dsymbols *members, ForeachDg dg, void *ctx, size_t *pn = NULL); void freeFieldinit(Scope *sc); Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads); +Package *resolveIsPackage(Dsymbol *sym); Expression *trySemantic(Expression *e, Scope *sc); Expression *semantic(Expression *e, Scope *sc); Expression *typeToExpression(Type *t); @@ -49,32 +51,69 @@ Expression *typeToExpression(Type *t); struct Ptrait { + Dsymbol *sym; Expression *e1; Expressions *exps; // collected results Identifier *ident; // which trait we're looking for + bool includeTemplates; + AA **funcTypeHash; }; +/* Compute the function signature and insert it in the + * hashtable, if not present. This is needed so that + * traits(getOverlods, F3, "visit") does not count `int visit(int)` + * twice in the following example: + * + * ============================================= + * interface F1 { int visit(int);} + * interface F2 { int visit(int); void visit(); } + * interface F3 : F2, F1 {} + *============================================== + */ +static void insertInterfaceInheritedFunction(Ptrait *p, FuncDeclaration *fd, Expression *e) +{ + Identifier *signature = Identifier::idPool(fd->type->toChars()); + //printf("%s - %s\n", fd->toChars, signature); + if (!dmd_aaGetRvalue(*p->funcTypeHash, (void *)signature)) + { + bool* value = (bool*) dmd_aaGet(p->funcTypeHash, (void *)signature); + *value = true; + p->exps->push(e); + } +} + static int fptraits(void *param, Dsymbol *s) { - FuncDeclaration *f = s->isFuncDeclaration(); - if (!f) + Ptrait *p = (Ptrait *)param; + if (p->includeTemplates) + { + p->exps->push(new DsymbolExp(Loc(),s, false)); + return 0; + } + FuncDeclaration *fd = s->isFuncDeclaration(); + if (!fd) return 0; - Ptrait *p = (Ptrait *)param; - if (p->ident == Id::getVirtualFunctions && !f->isVirtual()) + if (p->ident == Id::getVirtualFunctions && !fd->isVirtual()) return 0; - if (p->ident == Id::getVirtualMethods && !f->isVirtualMethod()) + if (p->ident == Id::getVirtualMethods && !fd->isVirtualMethod()) return 0; Expression *e; - FuncAliasDeclaration* ad = new FuncAliasDeclaration(f->ident, f, false); - ad->protection = f->protection; + FuncAliasDeclaration* ad = new FuncAliasDeclaration(fd->ident, fd, false); + ad->protection = fd->protection; if (p->e1) e = new DotVarExp(Loc(), p->e1, ad, false); else e = new DsymbolExp(Loc(), ad, false); - p->exps->push(e); + // if the parent is an interface declaration + // we must check for functions with the same signature + // in different inherited interfaces + if (p->sym && p->sym->isInterfaceDeclaration()) + insertInterfaceInheritedFunction(p, fd, e); + else + p->exps->push(e); return 0; } @@ -126,22 +165,111 @@ static void collectUnitTests(Dsymbols *symbols, AA *uniqueUnitTests, Expressions } } +/*************************************************** + * Determine if type t is copyable. + * Params: + * t = type to check + * Returns: + * true if we can copy it + */ +static bool isCopyable(Type *t) +{ + //printf("isCopyable() %s\n", t->toChars()); + if (TypeStruct *ts = t->isTypeStruct()) + { + if (ts->sym->postblit && + (ts->sym->postblit->storage_class & STCdisable)) + return false; + } + return true; +} + /************************ TraitsExp ************************************/ static Expression *True(TraitsExp *e) { return new IntegerExp(e->loc, true, Type::tbool); } static Expression *False(TraitsExp *e) { return new IntegerExp(e->loc, false, Type::tbool); } -bool isTypeArithmetic(Type *t) { return t->isintegral() || t->isfloating(); } -bool isTypeFloating(Type *t) { return t->isfloating(); } -bool isTypeIntegral(Type *t) { return t->isintegral(); } -bool isTypeScalar(Type *t) { return t->isscalar(); } -bool isTypeUnsigned(Type *t) { return t->isunsigned(); } -bool isTypeAssociativeArray(Type *t) { return t->toBasetype()->ty == Taarray; } -bool isTypeStaticArray(Type *t) { return t->toBasetype()->ty == Tsarray; } -bool isTypeAbstractClass(Type *t) { return t->toBasetype()->ty == Tclass && ((TypeClass *)t->toBasetype())->sym->isAbstract(); } -bool isTypeFinalClass(Type *t) { return t->toBasetype()->ty == Tclass && (((TypeClass *)t->toBasetype())->sym->storage_class & STCfinal) != 0; } - -Expression *isTypeX(TraitsExp *e, bool (*fp)(Type *t)) +/************************************** + * Convert `Expression` or `Type` to corresponding `Dsymbol`, + * additionally strip off expression contexts. + * + * Some symbol related `__traits` ignore arguments expression contexts. + * For example: + * struct S { void f() {} } + * S s; + * pragma(msg, __traits(isNested, s.f)); + * // s.f is DotVarExp, but __traits(isNested) needs a FuncDeclaration. + * + * This is used for that common `__traits` behavior. + */ +static Dsymbol *getDsymbolWithoutExpCtx(RootObject *oarg) +{ + if (Expression *e = isExpression(oarg)) + { + if (e->op == TOKdotvar) + return ((DotVarExp *)e)->var; + if (e->op == TOKdottd) + return ((DotTemplateExp *)e)->td; + } + return getDsymbol(oarg); +} + +/** + Gets the function type from a given AST node + if the node is a function of some sort. + + Params: + o = an AST node to check for a `TypeFunction` + fdp = optional pointer to a function declararion, to be set + if `o` is a function declarartion. + + Returns: + a type node if `o` is a declaration of + a delegate, function, function-pointer + or a variable of the former. Otherwise, `null`. +*/ +static TypeFunction *toTypeFunction(RootObject *o, FuncDeclaration **fdp = NULL) +{ + Dsymbol *s = getDsymbolWithoutExpCtx(o); + Type *t = isType(o); + TypeFunction *tf = NULL; + + if (s) + { + FuncDeclaration *fd = s->isFuncDeclaration(); + if (fd) + { + t = fd->type; + if (fdp) + *fdp = fd; + } + else if (VarDeclaration *vd = s->isVarDeclaration()) + t = vd->type; + } + if (t) + { + if (t->ty == Tfunction) + tf = (TypeFunction *)t; + else if (t->ty == Tdelegate) + tf = (TypeFunction *)t->nextOf(); + else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction) + tf = (TypeFunction *)t->nextOf(); + } + + return tf; +} + +static bool isTypeArithmetic(Type *t) { return t->isintegral() || t->isfloating(); } +static bool isTypeFloating(Type *t) { return t->isfloating(); } +static bool isTypeIntegral(Type *t) { return t->isintegral(); } +static bool isTypeScalar(Type *t) { return t->isscalar(); } +static bool isTypeUnsigned(Type *t) { return t->isunsigned(); } +static bool isTypeAssociativeArray(Type *t) { return t->toBasetype()->ty == Taarray; } +static bool isTypeStaticArray(Type *t) { return t->toBasetype()->ty == Tsarray; } +static bool isTypeAbstractClass(Type *t) { return t->toBasetype()->ty == Tclass && ((TypeClass *)t->toBasetype())->sym->isAbstract(); } +static bool isTypeFinalClass(Type *t) { return t->toBasetype()->ty == Tclass && (((TypeClass *)t->toBasetype())->sym->storage_class & STCfinal) != 0; } + +static Expression *isTypeX(TraitsExp *e, bool (*fp)(Type *t)) { if (!e->args || !e->args->length) return False(e); @@ -154,20 +282,52 @@ Expression *isTypeX(TraitsExp *e, bool (*fp)(Type *t)) return True(e); } -bool isFuncAbstractFunction(FuncDeclaration *f) { return f->isAbstract(); } -bool isFuncVirtualFunction(FuncDeclaration *f) { return f->isVirtual(); } -bool isFuncVirtualMethod(FuncDeclaration *f) { return f->isVirtualMethod(); } -bool isFuncFinalFunction(FuncDeclaration *f) { return f->isFinalFunc(); } -bool isFuncStaticFunction(FuncDeclaration *f) { return !f->needThis() && !f->isNested(); } -bool isFuncOverrideFunction(FuncDeclaration *f) { return f->isOverride(); } +static bool isDsymDeprecated(Dsymbol *s) { return s->isDeprecated(); } + +static int fpisTemplate(void *, Dsymbol *s) +{ + if (s->isTemplateDeclaration()) + return 1; + + return 0; +} + +bool isTemplate(Dsymbol *s) +{ + if (!s->toAlias()->isOverloadable()) + return false; + + return overloadApply(s, NULL, &fpisTemplate) != 0; +} + +static Expression *isDsymX(TraitsExp *e, bool (*fp)(Dsymbol *s)) +{ + if (!e->args || !e->args->length) + return False(e); + for (size_t i = 0; i < e->args->length; i++) + { + Dsymbol *s = getDsymbolWithoutExpCtx((*e->args)[i]); + if (!s || !fp(s)) + return False(e); + } + return True(e); +} + +static bool isFuncDisabled(FuncDeclaration *f) { return f->isDisabled(); } +static bool isFuncAbstractFunction(FuncDeclaration *f) { return f->isAbstract(); } +static bool isFuncVirtualFunction(FuncDeclaration *f) { return f->isVirtual(); } +static bool isFuncVirtualMethod(FuncDeclaration *f) { return f->isVirtualMethod(); } +static bool isFuncFinalFunction(FuncDeclaration *f) { return f->isFinalFunc(); } +static bool isFuncStaticFunction(FuncDeclaration *f) { return !f->needThis() && !f->isNested(); } +static bool isFuncOverrideFunction(FuncDeclaration *f) { return f->isOverride(); } -Expression *isFuncX(TraitsExp *e, bool (*fp)(FuncDeclaration *f)) +static Expression *isFuncX(TraitsExp *e, bool (*fp)(FuncDeclaration *f)) { if (!e->args || !e->args->length) return False(e); for (size_t i = 0; i < e->args->length; i++) { - Dsymbol *s = getDsymbol((*e->args)[i]); + Dsymbol *s = getDsymbolWithoutExpCtx((*e->args)[i]); if (!s) return False(e); FuncDeclaration *f = s->isFuncDeclaration(); @@ -177,17 +337,18 @@ Expression *isFuncX(TraitsExp *e, bool (*fp)(FuncDeclaration *f)) return True(e); } -bool isDeclRef(Declaration *d) { return d->isRef(); } -bool isDeclOut(Declaration *d) { return d->isOut(); } -bool isDeclLazy(Declaration *d) { return (d->storage_class & STClazy) != 0; } +static bool isDeclFuture(Declaration *d) { return d->isFuture(); } +static bool isDeclRef(Declaration *d) { return d->isRef(); } +static bool isDeclOut(Declaration *d) { return d->isOut(); } +static bool isDeclLazy(Declaration *d) { return (d->storage_class & STClazy) != 0; } -Expression *isDeclX(TraitsExp *e, bool (*fp)(Declaration *d)) +static Expression *isDeclX(TraitsExp *e, bool (*fp)(Declaration *d)) { if (!e->args || !e->args->length) return False(e); for (size_t i = 0; i < e->args->length; i++) { - Dsymbol *s = getDsymbol((*e->args)[i]); + Dsymbol *s = getDsymbolWithoutExpCtx((*e->args)[i]); if (!s) return False(e); Declaration *d = s->isDeclaration(); @@ -197,6 +358,25 @@ Expression *isDeclX(TraitsExp *e, bool (*fp)(Declaration *d)) return True(e); } +static bool isPkgModule(Package *p) { return p->isModule() || p->isPackageMod(); } +static bool isPkgPackage(Package *p) { return p->isModule() == NULL; } + +static Expression *isPkgX(TraitsExp *e, bool (*fp)(Package *p)) +{ + if (!e->args || !e->args->length) + return False(e); + for (size_t i = 0; i < e->args->length; i++) + { + Dsymbol *s = getDsymbolWithoutExpCtx((*e->args)[i]); + if (!s) + return False(e); + Package *p = resolveIsPackage(s); + if (!p || !fp(p)) + return False(e); + } + return True(e); +} + // callback for TypeFunction::attributesApply struct PushAttributes { @@ -225,6 +405,9 @@ TraitsInitializer::TraitsInitializer() "isAbstractClass", "isArithmetic", "isAssociativeArray", + "isDisabled", + "isDeprecated", + "isFuture", "isFinalClass", "isPOD", "isNested", @@ -239,13 +422,18 @@ TraitsInitializer::TraitsInitializer() "isFinalFunction", "isOverrideFunction", "isStaticFunction", + "isModule", + "isPackage", "isRef", "isOut", "isLazy", + "isReturnOnStack", "hasMember", "identifier", "getProtection", + "getVisibility", "parent", + "child", "getLinkage", "getMember", "getOverloads", @@ -265,10 +453,15 @@ TraitsInitializer::TraitsInitializer() "getUnitTests", "getVirtualIndex", "getPointerBitmap", + "isZeroInit", + "getTargetInfo", + "getLocation", + "hasPostblit", + "isCopyable", NULL }; - traitsStringTable._init(40); + traitsStringTable._init(56); for (size_t idx = 0;; idx++) { @@ -291,35 +484,6 @@ void *trait_search_fp(void *, const char *seed, int* cost) return sv ? (void*)sv->ptrvalue : NULL; } -static int fpisTemplate(void *, Dsymbol *s) -{ - if (s->isTemplateDeclaration()) - return 1; - - return 0; -} - -bool isTemplate(Dsymbol *s) -{ - if (!s->toAlias()->isOverloadable()) - return false; - - return overloadApply(s, NULL, &fpisTemplate) != 0; -} - -Expression *isSymbolX(TraitsExp *e, bool (*fp)(Dsymbol *s)) -{ - if (!e->args || !e->args->length) - return False(e); - for (size_t i = 0; i < e->args->length; i++) - { - Dsymbol *s = getDsymbol((*e->args)[i]); - if (!s || !fp(s)) - return False(e); - } - return True(e); -} - /** * get an array of size_t values that indicate possible pointer words in memory * if interpreted as the type given as argument @@ -491,11 +655,22 @@ static Expression *dimError(TraitsExp *e, int expected, int dim) Expression *semanticTraits(TraitsExp *e, Scope *sc) { - if (e->ident != Id::compiles && e->ident != Id::isSame && - e->ident != Id::identifier && e->ident != Id::getProtection) + if (e->ident != Id::compiles && + e->ident != Id::isSame && + e->ident != Id::identifier && + e->ident != Id::getProtection && e->ident != Id::getVisibility) { + // Pretend we're in a deprecated scope so that deprecation messages + // aren't triggered when checking if a symbol is deprecated + const StorageClass save = sc->stc; + if (e->ident == Id::isDeprecated) + sc->stc |= STCdeprecated; if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 1)) + { + sc->stc = save; return new ErrorExp(); + } + sc->stc = save; } size_t dim = e->args ? e->args->length : 0; @@ -523,6 +698,14 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) { return isTypeX(e, &isTypeAssociativeArray); } + else if (e->ident == Id::isDeprecated) + { + return isDsymX(e, &isDsymDeprecated); + } + else if (e->ident == Id::isFuture) + { + return isDeclX(e, &isDeclFuture); + } else if (e->ident == Id::isStaticArray) { return isTypeX(e, &isTypeStaticArray); @@ -537,7 +720,10 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) } else if (e->ident == Id::isTemplate) { - return isSymbolX(e, &isTemplate); + if (dim != 1) + return dimError(e, 1, dim); + + return isDsymX(e, &isTemplate); } else if (e->ident == Id::isPOD) { @@ -560,13 +746,50 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) } return True(e); } + else if (e->ident == Id::hasPostblit) + { + if (dim != 1) + return dimError(e, 1, dim); + + RootObject *o = (*e->args)[0]; + Type *t = isType(o); + if (!t) + { + e->error("type expected as second argument of __traits %s instead of %s", + e->ident->toChars(), o->toChars()); + return new ErrorExp(); + } + + Type *tb = t->baseElemOf(); + if (StructDeclaration *sd = (tb->ty == Tstruct) ? ((TypeStruct *)tb)->sym : NULL) + { + return sd->postblit ? True(e) : False(e); + } + return False(e); + } + else if (e->ident == Id::isCopyable) + { + if (dim != 1) + return dimError(e, 1, dim); + + RootObject *o = (*e->args)[0]; + Type *t = isType(o); + if (!t) + { + e->error("type expected as second argument of __traits %s instead of %s", + e->ident->toChars(), o->toChars()); + return new ErrorExp(); + } + + return isCopyable(t) ? True(e) : False(e); + } else if (e->ident == Id::isNested) { if (dim != 1) return dimError(e, 1, dim); RootObject *o = (*e->args)[0]; - Dsymbol *s = getDsymbol(o); + Dsymbol *s = getDsymbolWithoutExpCtx(o); if (!s) { } @@ -582,40 +805,88 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) e->error("aggregate or function expected instead of '%s'", o->toChars()); return new ErrorExp(); } + else if (e->ident == Id::isDisabled) + { + if (dim != 1) + return dimError(e, 1, dim); + + return isFuncX(e, &isFuncDisabled); + } else if (e->ident == Id::isAbstractFunction) { + if (dim != 1) + return dimError(e, 1, dim); + return isFuncX(e, &isFuncAbstractFunction); } else if (e->ident == Id::isVirtualFunction) { + if (dim != 1) + return dimError(e, 1, dim); + return isFuncX(e, &isFuncVirtualFunction); } else if (e->ident == Id::isVirtualMethod) { + if (dim != 1) + return dimError(e, 1, dim); + return isFuncX(e, &isFuncVirtualMethod); } else if (e->ident == Id::isFinalFunction) { + if (dim != 1) + return dimError(e, 1, dim); + return isFuncX(e, &isFuncFinalFunction); } else if (e->ident == Id::isOverrideFunction) { + if (dim != 1) + return dimError(e, 1, dim); + return isFuncX(e, &isFuncOverrideFunction); } else if (e->ident == Id::isStaticFunction) { + if (dim != 1) + return dimError(e, 1, dim); + return isFuncX(e, &isFuncStaticFunction); } + else if (e->ident == Id::isModule) + { + if (dim != 1) + return dimError(e, 1, dim); + + return isPkgX(e, &isPkgModule); + } + else if (e->ident == Id::isPackage) + { + if (dim != 1) + return dimError(e, 1, dim); + + return isPkgX(e, &isPkgPackage); + } else if (e->ident == Id::isRef) { + if (dim != 1) + return dimError(e, 1, dim); + return isDeclX(e, &isDeclRef); } else if (e->ident == Id::isOut) { + if (dim != 1) + return dimError(e, 1, dim); + return isDeclX(e, &isDeclOut); } else if (e->ident == Id::isLazy) { + if (dim != 1) + return dimError(e, 1, dim); + return isDeclX(e, &isDeclLazy); } else if (e->ident == Id::identifier) @@ -639,7 +910,7 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) } else { - Dsymbol *s = getDsymbol(o); + Dsymbol *s = getDsymbolWithoutExpCtx(o); if (!s || !s->ident) { e->error("argument %s has no identifier", o->toChars()); @@ -651,7 +922,7 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) StringExp *se = new StringExp(e->loc, const_cast<char *>(id->toChars())); return semantic(se, sc); } - else if (e->ident == Id::getProtection) + else if (e->ident == Id::getProtection || e->ident == Id::getVisibility) { if (dim != 1) return dimError(e, 1, dim); @@ -664,7 +935,7 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) return new ErrorExp(); RootObject *o = (*e->args)[0]; - Dsymbol *s = getDsymbol(o); + Dsymbol *s = getDsymbolWithoutExpCtx(o); if (!s) { if (!isError(o)) @@ -685,7 +956,7 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) return dimError(e, 1, dim); RootObject *o = (*e->args)[0]; - Dsymbol *s = getDsymbol(o); + Dsymbol *s = getDsymbolWithoutExpCtx(o); if (s) { if (FuncDeclaration *fd = s->isFuncDeclaration()) // Bugzilla 8943 @@ -720,13 +991,51 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) return resolve(e->loc, sc, s, false); } + else if (e->ident == Id::child) + { + if (dim != 2) + return dimError(e, 2, dim); + + Expression *ex; + RootObject *op = (*e->args)[0]; + if (Dsymbol *symp = getDsymbol(op)) + ex = new DsymbolExp(e->loc, symp); + else if (Expression *exp = isExpression(op)) + ex = exp; + else + { + e->error("symbol or expression expected as first argument of __traits `child` instead of `%s`", op->toChars()); + return new ErrorExp(); + } + + ex = semantic(ex, sc); + RootObject *oc = (*e->args)[1]; + Dsymbol *symc = getDsymbol(oc); + if (!symc) + { + e->error("symbol expected as second argument of __traits `child` instead of `%s`", oc->toChars()); + return new ErrorExp(); + } + + if (Declaration *d = symc->isDeclaration()) + ex = new DotVarExp(e->loc, ex, d); + else if (TemplateDeclaration *td = symc->isTemplateDeclaration()) + ex = new DotExp(e->loc, ex, new TemplateExp(e->loc, td)); + else if (ScopeDsymbol *ti = symc->isScopeDsymbol()) + ex = new DotExp(e->loc, ex, new ScopeExp(e->loc, ti)); + else + assert(0); + + ex = semantic(ex, sc); + return ex; + } else if (e->ident == Id::hasMember || e->ident == Id::getMember || e->ident == Id::getOverloads || e->ident == Id::getVirtualMethods || e->ident == Id::getVirtualFunctions) { - if (dim != 2) + if (dim != 2 && !(dim == 3 && e->ident == Id::getOverloads)) return dimError(e, 2, dim); RootObject *o = (*e->args)[0]; @@ -738,6 +1047,19 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) } ex = ex->ctfeInterpret(); + bool includeTemplates = false; + if (dim == 3 && e->ident == Id::getOverloads) + { + Expression *b = isExpression((*e->args)[2]); + b = b->ctfeInterpret(); + if (!b->type->equals(Type::tbool)) + { + e->error("`bool` expected as third argument of `__traits(getOverloads)`, not `%s` of type `%s`", b->toChars(), b->type->toChars()); + return new ErrorExp(); + } + includeTemplates = b->isBool(true); + } + StringExp *se = ex->toStringExp(); if (!se || se->len == 0) { @@ -758,6 +1080,11 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) Dsymbol *sym = getDsymbol(o); if (sym) { + if (e->ident == Id::hasMember) + { + if (sym->search(e->loc, id) != NULL) + return True(e); + } ex = new DsymbolExp(e->loc, sym); ex = new DotIdExp(e->loc, ex, id); } @@ -773,12 +1100,6 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) if (e->ident == Id::hasMember) { - if (sym) - { - if (sym->search(e->loc, id)) - return True(e); - } - /* Take any errors as meaning it wasn't found */ Scope *scx = sc->push(); @@ -814,7 +1135,7 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) /* Create tuple of functions of ex */ Expressions *exps = new Expressions(); - FuncDeclaration *f; + Dsymbol *f; if (ex->op == TOKvar) { VarExp *ve = (VarExp *)ex; @@ -830,13 +1151,43 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) else ex = dve->e1; } + else if (ex->op == TOKtemplate) + { + TemplateExp *te = (TemplateExp *)ex; + TemplateDeclaration *td = te->td; + f = td; + if (td && td->funcroot) + f = td->funcroot; + ex = NULL; + } else f = NULL; Ptrait p; + p.sym = sym; p.exps = exps; p.e1 = ex; p.ident = e->ident; - overloadApply(f, &p, &fptraits); + p.includeTemplates = includeTemplates; + AA *funcTypeHash = NULL; + p.funcTypeHash = &funcTypeHash; + + InterfaceDeclaration *ifd = NULL; + if (sym) + ifd = sym->isInterfaceDeclaration(); + // If the symbol passed as a parameter is an + // interface that inherits other interfaces + if (ifd && ifd->interfaces.length) + { + // check the overloads of each inherited interface individually + for (size_t i = 0; i < ifd->interfaces.length; i++) + { + BaseClass *bc = ifd->interfaces.ptr[i]; + if (Dsymbol *fd = bc->sym->search(e->loc, f->ident)) + overloadApply(fd, &p, &fptraits); + } + } + else + overloadApply(f, &p, &fptraits); ex = new TupleExp(e->loc, exps); ex = semantic(ex, scx); @@ -898,7 +1249,7 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) return dimError(e, 1, dim); RootObject *o = (*e->args)[0]; - Dsymbol *s = getDsymbol(o); + Dsymbol *s = getDsymbolWithoutExpCtx(o); if (!s) { e->error("first argument is not a symbol"); @@ -917,30 +1268,14 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) } else if (e->ident == Id::getFunctionAttributes) { - /// extract all function attributes as a tuple (const/shared/inout/pure/nothrow/etc) except UDAs. + /* extract all function attributes as a tuple (const/shared/inout/pure/nothrow/etc) except UDAs. + * https://dlang.org/spec/traits.html#getFunctionAttributes + */ if (dim != 1) return dimError(e, 1, dim); - RootObject *o = (*e->args)[0]; - Dsymbol *s = getDsymbol(o); - Type *t = isType(o); - TypeFunction *tf = NULL; - if (s) - { - if (FuncDeclaration *f = s->isFuncDeclaration()) - t = f->type; - else if (VarDeclaration *v = s->isVarDeclaration()) - t = v->type; - } - if (t) - { - if (t->ty == Tfunction) - tf = (TypeFunction *)t; - else if (t->ty == Tdelegate) - tf = (TypeFunction *)t->nextOf(); - else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction) - tf = (TypeFunction *)t->nextOf(); - } + TypeFunction *tf = toTypeFunction((*e->args)[0]); + if (!tf) { e->error("first argument is not a function"); @@ -956,6 +1291,27 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) TupleExp *tup = new TupleExp(e->loc, mods); return semantic(tup, sc); } + else if (e->ident == Id::isReturnOnStack) + { + /* Extract as a boolean if function return value is on the stack + * https://dlang.org/spec/traits.html#isReturnOnStack + */ + if (dim != 1) + return dimError(e, 1, dim); + + RootObject *o = (*e->args)[0]; + FuncDeclaration *fd = NULL; + TypeFunction *tf = toTypeFunction(o, &fd); + + if (!tf) + { + e->error("argument to `__traits(isReturnOnStack, %s)` is not a function", o->toChars()); + return new ErrorExp(); + } + + bool value = target.isReturnOnStack(tf, fd && fd->needThis()); + return new IntegerExp(e->loc, value, Type::tbool); + } else if (e->ident == Id::getFunctionVariadicStyle) { /* Accept a symbol or a type. Returns one of the following: @@ -971,17 +1327,9 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) LINK link; VarArg varargs; RootObject *o = (*e->args)[0]; - Type *t = isType(o); - TypeFunction *tf = NULL; - if (t) - { - if (t->ty == Tfunction) - tf = (TypeFunction *)t; - else if (t->ty == Tdelegate) - tf = (TypeFunction *)t->nextOf(); - else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction) - tf = (TypeFunction *)t->nextOf(); - } + FuncDeclaration *fd = NULL; + TypeFunction *tf = toTypeFunction(o, &fd); + if (tf) { link = tf->linkage; @@ -989,9 +1337,7 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) } else { - Dsymbol *s = getDsymbol(o); - FuncDeclaration *fd = NULL; - if (!s || (fd = s->isFuncDeclaration()) == NULL) + if (!fd) { e->error("argument to `__traits(getFunctionVariadicStyle, %s)` is not a function", o->toChars()); return new ErrorExp(); @@ -1021,19 +1367,12 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) if (dim != 2) return dimError(e, 2, dim); - RootObject *o1 = (*e->args)[1]; RootObject *o = (*e->args)[0]; - Type *t = isType(o); - TypeFunction *tf = NULL; - if (t) - { - if (t->ty == Tfunction) - tf = (TypeFunction *)t; - else if (t->ty == Tdelegate) - tf = (TypeFunction *)t->nextOf(); - else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction) - tf = (TypeFunction *)t->nextOf(); - } + RootObject *o1 = (*e->args)[1]; + + FuncDeclaration *fd = NULL; + TypeFunction *tf = toTypeFunction(o, &fd); + ParameterList fparams; if (tf) { @@ -1041,9 +1380,7 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) } else { - Dsymbol *s = getDsymbol(o); - FuncDeclaration *fd = NULL; - if (!s || (fd = s->isFuncDeclaration()) == NULL) + if (!fd) { e->error("first argument to `__traits(getParameterStorageClasses, %s, %s)` is not a function", o->toChars(), o1->toChars()); @@ -1118,17 +1455,9 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) LINK link; RootObject *o = (*e->args)[0]; - Type *t = isType(o); - TypeFunction *tf = NULL; - if (t) - { - if (t->ty == Tfunction) - tf = (TypeFunction *)t; - else if (t->ty == Tdelegate) - tf = (TypeFunction *)t->nextOf(); - else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction) - tf = (TypeFunction *)t->nextOf(); - } + + TypeFunction *tf = toTypeFunction(o); + if (tf) link = tf->linkage; else @@ -1421,7 +1750,7 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) return dimError(e, 1, dim); RootObject *o = (*e->args)[0]; - Dsymbol *s = getDsymbol(o); + Dsymbol *s = getDsymbolWithoutExpCtx(o); if (!s) { e->error("argument %s to __traits(getUnitTests) must be a module or aggregate", @@ -1455,7 +1784,7 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) return dimError(e, 1, dim); RootObject *o = (*e->args)[0]; - Dsymbol *s = getDsymbol(o); + Dsymbol *s = getDsymbolWithoutExpCtx(o); FuncDeclaration *fd = s ? s->isFuncDeclaration() : NULL; if (!fd) @@ -1471,6 +1800,75 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) { return pointerBitmap(e); } + else if (e->ident == Id::isZeroInit) + { + if (dim != 1) + return dimError(e, 1, dim); + + RootObject *o = (*e->args)[0]; + Type *t = isType(o); + if (!t) + { + e->error("type expected as second argument of __traits `%s` instead of `%s`", + e->ident->toChars(), o->toChars()); + return new ErrorExp(); + } + + Type *tb = t->baseElemOf(); + return tb->isZeroInit(e->loc) ? True(e) : False(e); + } + else if (e->ident == Id::getTargetInfo) + { + if (dim != 1) + return dimError(e, 1, dim); + + Expression *ex = isExpression((*e->args)[0]); + StringExp *se = ex ? ex->ctfeInterpret()->toStringExp() : NULL; + if (!ex || !se || se->len == 0) + { + e->error("string expected as argument of __traits `%s` instead of `%s`", e->ident->toChars(), ex->toChars()); + return new ErrorExp(); + } + se = se->toUTF8(sc); + + Expression *r = target.getTargetInfo(se->toPtr(), e->loc); + if (!r) + { + e->error("`getTargetInfo` key `\"%s\"` not supported by this implementation", se->toPtr()); + return new ErrorExp(); + } + return semantic(r, sc); + } + else if (e->ident == Id::getLocation) + { + if (dim != 1) + return dimError(e, 1, dim); + RootObject *arg0 = (*e->args)[0]; + Dsymbol *s = getDsymbolWithoutExpCtx(arg0); + if (!s || !s->loc.filename) + { + e->error("can only get the location of a symbol, not `%s`", arg0->toChars()); + return new ErrorExp(); + } + + const FuncDeclaration *fd = s->isFuncDeclaration(); + if (fd && fd->overnext) + { + e->error("cannot get location of an overload set, " + "use `__traits(getOverloads, ..., \"%s\"%s)[N]` " + "to get the Nth overload", + arg0->toChars(), ""); + return new ErrorExp(); + } + + Expressions *exps = new Expressions(); + exps->setDim(3); + (*exps)[0] = new StringExp(e->loc, const_cast<char *>(s->loc.filename), strlen(s->loc.filename)); + (*exps)[1] = new IntegerExp(e->loc, s->loc.linnum, Type::tint32); + (*exps)[2] = new IntegerExp(e->loc, s->loc.charnum, Type::tint32); + TupleExp *tup = new TupleExp(e->loc, exps); + return semantic(tup, sc); + } if (const char *sub = (const char *)speller(e->ident->toChars(), &trait_search_fp, NULL, idchars)) e->error("unrecognized trait '%s', did you mean '%s'?", e->ident->toChars(), sub); |