d: Merge upstream dmd 3b808e838, druntime 483bc129, phobos f89dc217a

D front-end changes:

 - Explicit package visibility attribute is now always applied to
   introducing scopes.

 - Added `__traits(totype, string)' to convert mangled type string to an
   existing type.

 - Printf-like and scanf-like functions are now detected by prefixing
   them with `pragma(printf)' for printf-like functions or
   `pragma(scanf)' for scanf-like functions.

 - Added `__c_wchar_t', `__c_complex_float', `__c_complex_double', and
   `__c_complex_real' types for interfacing with C and C++.

 - Template alias parameters can now be instantiated with basic types,
   such as `int` or `void function()`.

 - Mixins can now be used as types in the form `mixin(string) var'.

 - Mixin expressions can take an argument list, same as `pragma(msg)'.

 - Implement DIP1034, add `typeof(*null)' types to represent `noreturn'.

 - `pragma(msg)' can print expressions of type `void'.

 - It is now an error to use private variables selectively imported from
   other modules.  Due to a bug, some imported private members were
   visible from other modules, violating the specification.

 - Added new syntax to declare an alias to a function type using the
   `alias' syntax based on the assignment operator.

 - Function literals can now return a value by reference.

Phobos changes:

 - Synchronize C bindings with the latest port fixes in upstream druntime.

 - Added alias for a `noreturn' type in object.d

 - Make use of the new `pragma(printf)' and `pragma(scanf)' pragmas, fix
   all code that got flagged as being incorrect.

 - Fixed code that relied on bugs in the D import package system.

Reviewed-on: https://github.com/dlang/dmd/pull/12339
	     https://github.com/dlang/druntime/pull/3422
	     https://github.com/dlang/phobos/pull/7932

gcc/d/ChangeLog:

	* dmd/MERGE: Merge upstream dmd 3b808e838.
	* Make-lang.in (D_FRONTEND_OBJS): Add d/chkformat.o.
	* d-codegen.cc (build_struct_literal): Handle special enums.
	* d-convert.cc (convert_expr): Handle noreturn type.
	(convert_for_condition): Likewise.
	* d-target.cc (Target::_init): Set type for wchar_t.
	(TargetCPP::derivedClassOffset): New method.
	(Target::libraryObjectMonitors): New method.
	* decl.cc (get_symbol_decl): Set TREE_THIS_VOLATILE for functions of
	type noreturn.
	* toir.cc (IRVisitor::visit (ReturnStatement *)): Handle returning
	noreturn types.
	* types.cc (TypeVisitor::visit (TypeNoreturn *)): New method.
	(TypeVisitor::visit (TypeEnum *)): Handle special enums.

libphobos/ChangeLog:

	* libdruntime/MERGE: Merge upstream druntime 483bc129.
	* libdruntime/Makefile.am (DRUNTIME_DSOURCES_DARWIN): Add
	core/sys/darwin/fcntl.d.
	(DRUNTIME_DSOURCES_OPENBSD): Add core/sys/openbsd/unistd.d.
	(DRUNTIME_DSOURCES_WINDOWS): Add core/sys/windows/stdc/malloc.d.
	* libdruntime/Makefile.in: Regenerate.
	* src/MERGE: Merge upstream phobos f89dc217a.
	* src/Makefile.am (PHOBOS_DSOURCES): Add std/regex/internal/tests2.d.
	* src/Makefile.in: Regenerate.
	* testsuite/libphobos.exceptions/chain.d: Fix format arguments.
	* testsuite/libphobos.exceptions/line_trace.d: Likewise.
This commit is contained in:
Iain Buclaw 2021-04-02 13:29:22 +02:00
parent ba0f690266
commit 5a0aa603b2
191 changed files with 7471 additions and 3914 deletions

View file

@ -64,6 +64,7 @@ D_FRONTEND_OBJS = \
d/blockexit.o \
d/canthrow.o \
d/checkedint.o \
d/chkformat.o \
d/clone.o \
d/cond.o \
d/constfold.o \

View file

@ -1153,6 +1153,14 @@ build_struct_literal (tree type, vec <constructor_elt, va_gc> *init)
if (vec_safe_is_empty (init))
return build_constructor (type, NULL);
/* Struct literals can be seen for special enums representing `_Complex',
make sure to reinterpret the literal as the correct type. */
if (COMPLEX_FLOAT_TYPE_P (type))
{
gcc_assert (vec_safe_length (init) == 2);
return build_complex (type, (*init)[0].value, (*init)[1].value);
}
vec <constructor_elt, va_gc> *ve = NULL;
HOST_WIDE_INT offset = 0;
bool constant_p = true;

View file

@ -559,7 +559,9 @@ convert_expr (tree exp, Type *etype, Type *totype)
break;
case Tnull:
/* Casting from typeof(null) is represented as all zeros. */
case Tnoreturn:
/* Casting from `typeof(null)' for `null' expressions, or `typeof(*null)'
for `noreturn' expressions is represented as all zeros. */
result = build_typeof_null_value (totype);
/* Make sure the expression is still evaluated if necessary. */
@ -742,6 +744,16 @@ convert_for_condition (tree expr, Type *type)
break;
}
case Tnoreturn:
/* Front-end allows conditionals that never return, represent the
conditional result value as all zeros. */
result = build_zero_cst (d_bool_type);
/* Make sure the expression is still evaluated if necessary. */
if (TREE_SIDE_EFFECTS (expr))
result = compound_expr (expr, result);
break;
default:
result = expr;
break;

View file

@ -164,6 +164,15 @@ Target::_init (const Param &)
this->c.longsize = int_size_in_bytes (long_integer_type_node);
this->c.long_doublesize = int_size_in_bytes (long_double_type_node);
/* Define what type to use for wchar_t. We don't want to support wide
characters less than "short" in D. */
if (WCHAR_TYPE_SIZE == 32)
this->c.twchar_t = Type::basic[Tdchar];
else if (WCHAR_TYPE_SIZE == 16)
this->c.twchar_t = Type::basic[Twchar];
else
sorry ("D does not support wide characters on this target.");
/* Set-up target C++ ABI. */
this->cpp.reverseOverloads = false;
this->cpp.exceptions = true;
@ -417,6 +426,15 @@ TargetCPP::fundamentalType (const Type *, bool &)
return false;
}
/* Get the starting offset position for fields of an `extern(C++)` class
that is derived from the given BASE_CLASS. */
unsigned
TargetCPP::derivedClassOffset(ClassDeclaration *base_class)
{
return base_class->structsize;
}
/* Return the default system linkage for the target. */
LINK
@ -517,3 +535,13 @@ Target::getTargetInfo (const char *key, const Loc &loc)
return NULL;
}
/**
* Returns true if the implementation for object monitors is always defined
* in the D runtime library (rt/monitor_.d). */
bool
Target::libraryObjectMonitors (FuncDeclaration *, Statement *)
{
return true;
}

View file

@ -1277,6 +1277,10 @@ get_symbol_decl (Declaration *decl)
if (decl->storage_class & STCfinal)
DECL_FINAL_P (decl->csym) = 1;
/* Function is of type `noreturn' or `typeof(*null)'. */
if (fd->type->nextOf ()->ty == Tnoreturn)
TREE_THIS_VOLATILE (decl->csym) = 1;
/* Check whether this function is expanded by the frontend. */
DECL_INTRINSIC_CODE (decl->csym) = INTRINSIC_NONE;
maybe_set_intrinsic (fd);

View file

@ -1,4 +1,4 @@
a3c9bf422e7ff54d45846b8c577ee82da4234db1
3b808e838bb00f527eb4ed5281cd985756237b8f
The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository.

View file

@ -80,8 +80,8 @@ Scope *AttribDeclaration::createNewScope(Scope *sc,
if (stc != sc->stc ||
linkage != sc->linkage ||
cppmangle != sc->cppmangle ||
!protection.isSubsetOf(sc->protection) ||
explicitProtection != sc->explicitProtection ||
!(protection == sc->protection) ||
aligndecl != sc->aligndecl ||
inlining != sc->inlining)
{
@ -552,10 +552,21 @@ void ProtDeclaration::addMember(Scope *sc, ScopeDsymbol *sds)
if (protection.kind == Prot::package_ && protection.pkg && sc->_module)
{
Module *m = sc->_module;
Package* pkg = m->parent ? m->parent->isPackage() : NULL;
if (!pkg || !protection.pkg->isAncestorPackageOf(pkg))
error("does not bind to one of ancestor packages of module `%s`",
m->toPrettyChars(true));
// While isAncestorPackageOf does an equality check, the fix for issue 17441 adds a check to see if
// each package's .isModule() properites are equal.
//
// Properties generated from `package(foo)` i.e. protection.pkg have .isModule() == null.
// This breaks package declarations of the package in question if they are declared in
// the same package.d file, which _do_ have a module associated with them, and hence a non-null
// isModule()
if (!m->isPackage() || !protection.pkg->ident->equals(m->isPackage()->ident))
{
Package* pkg = m->parent ? m->parent->isPackage() : NULL;
if (!pkg || !protection.pkg->isAncestorPackageOf(pkg))
error("does not bind to one of ancestor packages of module `%s`",
m->toPrettyChars(true));
}
}
return AttribDeclaration::addMember(sc, sds);
@ -795,6 +806,18 @@ Scope *PragmaDeclaration::newScope(Scope *sc)
sc->protection, sc->explicitProtection, sc->aligndecl,
inlining);
}
if (ident == Id::printf || ident == Id::scanf)
{
Scope *sc2 = sc->push();
if (ident == Id::printf)
// Override previous setting, never let both be set
sc2->flags = (sc2->flags & ~SCOPEscanf) | SCOPEprintf;
else
sc2->flags = (sc2->flags & ~SCOPEprintf) | SCOPEscanf;
return sc2;
}
return sc;
}
@ -1164,12 +1187,12 @@ void ForwardingAttribDeclaration::addMember(Scope *sc, ScopeDsymbol *sds)
// These are mixin declarations, like mixin("int x");
CompileDeclaration::CompileDeclaration(Loc loc, Expression *exp)
CompileDeclaration::CompileDeclaration(Loc loc, Expressions *exps)
: AttribDeclaration(NULL)
{
//printf("CompileDeclaration(loc = %d)\n", loc.linnum);
this->loc = loc;
this->exp = exp;
this->exps = exps;
this->scopesym = NULL;
this->compiled = false;
}
@ -1177,7 +1200,7 @@ CompileDeclaration::CompileDeclaration(Loc loc, Expression *exp)
Dsymbol *CompileDeclaration::syntaxCopy(Dsymbol *)
{
//printf("CompileDeclaration::syntaxCopy('%s')\n", toChars());
return new CompileDeclaration(loc, exp->syntaxCopy());
return new CompileDeclaration(loc, Expression::arraySyntaxCopy(exps));
}
void CompileDeclaration::addMember(Scope *, ScopeDsymbol *sds)

View file

@ -234,12 +234,12 @@ public:
class CompileDeclaration : public AttribDeclaration
{
public:
Expression *exp;
Expressions *exps;
ScopeDsymbol *scopesym;
bool compiled;
CompileDeclaration(Loc loc, Expression *exp);
CompileDeclaration(Loc loc, Expressions *exps);
Dsymbol *syntaxCopy(Dsymbol *s);
void addMember(Scope *sc, ScopeDsymbol *sds);
void setScope(Scope *sc);

View file

@ -62,6 +62,8 @@ int blockExit(Statement *s, FuncDeclaration *func, bool mustNotThrow)
return;
}
}
if (s->exp->type->toBasetype()->isTypeNoreturn())
result = BEhalt;
if (canThrow(s->exp, func, mustNotThrow))
result |= BEthrow;
}

975
gcc/d/dmd/chkformat.c Normal file
View file

@ -0,0 +1,975 @@
/* Compiler implementation of the D programming language
* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* http://www.boost.org/LICENSE_1_0.txt
*/
// Check the arguments to `printf` and `scanf` against the `format` string.
#include "root/dsystem.h"
#include "root/dcompat.h"
#include "arraytypes.h"
#include "cond.h"
#include "errors.h"
#include "expression.h"
#include "globals.h"
#include "identifier.h"
#include "mtype.h"
#include "target.h"
/* Different kinds of formatting specifications, variations we don't
care about are merged. (Like we don't care about the difference between
f, e, g, a, etc.)
For `scanf`, every format is a pointer.
*/
enum Format
{
Format_d, // int
Format_hhd, // signed char
Format_hd, // short int
Format_ld, // long int
Format_lld, // long long int
Format_jd, // intmax_t
Format_zd, // size_t
Format_td, // ptrdiff_t
Format_u, // unsigned int
Format_hhu, // unsigned char
Format_hu, // unsigned short int
Format_lu, // unsigned long int
Format_llu, // unsigned long long int
Format_ju, // uintmax_t
Format_g, // float (scanf) / double (printf)
Format_lg, // double (scanf)
Format_Lg, // long double (both)
Format_s, // char string (both)
Format_ls, // wchar_t string (both)
Format_c, // char (printf)
Format_lc, // wint_t (printf)
Format_p, // pointer
Format_n, // pointer to int
Format_hhn, // pointer to signed char
Format_hn, // pointer to short
Format_ln, // pointer to long int
Format_lln, // pointer to long long int
Format_jn, // pointer to intmax_t
Format_zn, // pointer to size_t
Format_tn, // pointer to ptrdiff_t
Format_GNU_a, // GNU ext. : address to a string with no maximum size (scanf)
Format_GNU_m, // GNU ext. : string corresponding to the error code in errno (printf) / length modifier (scanf)
Format_percent, // %% (i.e. no argument)
Format_error, // invalid format specification
};
/**************************************
* Parse the *length specifier* and the *specifier* of the following form:
* `[length]specifier`
*
* Params:
* format = format string
* idx = index of of start of format specifier,
* which gets updated to index past the end of it,
* even if `Format_error` is returned
* genSpecifier = Generic specifier. For instance, it will be set to `d` if the
* format is `hdd`.
* Returns:
* Format
*/
static Format parseGenericFormatSpecifier(const char *format,
size_t &idx, char &genSpecifier, bool useGNUExts =
findCondition(global.versionids, Identifier::idPool("CRuntime_Glibc")))
{
genSpecifier = 0;
const size_t length = strlen(format);
/* Read the `length modifier`
*/
const char lm = format[idx];
bool lm1= false; // if jztL
bool lm2= false; // if `hh` or `ll`
if (lm == 'j' ||
lm == 'z' ||
lm == 't' ||
lm == 'L')
{
++idx;
if (idx == length)
return Format_error;
lm1 = true;
}
else if (lm == 'h' || lm == 'l')
{
++idx;
if (idx == length)
return Format_error;
lm2 = lm == format[idx];
if (lm2)
{
++idx;
if (idx == length)
return Format_error;
}
}
/* Read the `specifier`
*/
Format specifier;
const char sc = format[idx];
genSpecifier = sc;
switch (sc)
{
case 'd':
case 'i':
if (lm == 'L')
specifier = Format_error;
else
specifier = lm == 'h' && lm2 ? Format_hhd :
lm == 'h' ? Format_hd :
lm == 'l' && lm2 ? Format_lld :
lm == 'l' ? Format_ld :
lm == 'j' ? Format_jd :
lm == 'z' ? Format_zd :
lm == 't' ? Format_td :
Format_d;
break;
case 'u':
case 'o':
case 'x':
case 'X':
if (lm == 'L')
specifier = Format_error;
else
specifier = lm == 'h' && lm2 ? Format_hhu :
lm == 'h' ? Format_hu :
lm == 'l' && lm2 ? Format_llu :
lm == 'l' ? Format_lu :
lm == 'j' ? Format_ju :
lm == 'z' ? Format_zd :
lm == 't' ? Format_td :
Format_u;
break;
case 'a':
if (useGNUExts)
{
// https://www.gnu.org/software/libc/manual/html_node/Dynamic-String-Input.html
specifier = Format_GNU_a;
break;
}
/* fall through */
case 'f':
case 'F':
case 'e':
case 'E':
case 'g':
case 'G':
case 'A':
if (lm == 'L')
specifier = Format_Lg;
else if (lm1 || lm2 || lm == 'h')
specifier = Format_error;
else
specifier = lm == 'l' ? Format_lg : Format_g;
break;
case 'c':
if (lm1 || lm2 || lm == 'h')
specifier = Format_error;
else
specifier = lm == 'l' ? Format_lc : Format_c;
break;
case 's':
if (lm1 || lm2 || lm == 'h')
specifier = Format_error;
else
specifier = lm == 'l' ? Format_ls : Format_s;
break;
case 'p':
if (lm1 || lm2 || lm == 'h' || lm == 'l')
specifier = Format_error;
else
specifier = Format_p;
break;
case 'n':
if (lm == 'L')
specifier = Format_error;
else
specifier = lm == 'l' && lm2 ? Format_lln :
lm == 'l' ? Format_ln :
lm == 'h' && lm2 ? Format_hhn :
lm == 'h' ? Format_hn :
lm == 'j' ? Format_jn :
lm == 'z' ? Format_zn :
lm == 't' ? Format_tn :
Format_n;
break;
case 'm':
if (useGNUExts)
{
// http://www.gnu.org/software/libc/manual/html_node/Other-Output-Conversions.html
specifier = Format_GNU_m;
break;
}
goto Ldefault;
default:
Ldefault:
specifier = Format_error;
break;
}
++idx;
return specifier; // success
}
Format formatError(size_t &idx, size_t i)
{
idx = i;
return Format_error;
}
/**************************************
* Parse the *format specifier* which is of the form:
*
* `%[*][width][length]specifier`
*
* Params:
* format = format string
* idx = index of `%` of start of format specifier,
* which gets updated to index past the end of it,
* even if `Format_error` is returned
* asterisk = set if there is a `*` sub-specifier
* Returns:
* Format
*/
static Format parseScanfFormatSpecifier(const char *format, size_t &idx,
bool &asterisk)
{
asterisk = false;
size_t i = idx;
assert(format[i] == '%');
const size_t length = strlen(format);
++i;
if (i == length)
return formatError(idx, i);
if (format[i] == '%')
{
idx = i + 1;
return Format_percent;
}
// * sub-specifier
if (format[i] == '*')
{
++i;
if (i == length)
return formatError(idx, i);
asterisk = true;
}
// fieldWidth
while (isdigit(format[i]))
{
i++;
if (i == length)
return formatError(idx, i);
}
/* Read the scanset
* A scanset can be anything, so we just check that it is paired
*/
if (format[i] == '[')
{
while (i < length)
{
if (format[i] == ']')
break;
++i;
}
// no `]` found
if (i == length)
return formatError(idx, i);
++i;
// no specifier after `]`
// it could be mixed with the one above, but then idx won't have the right index
if (i == length)
return formatError(idx, i);
}
/* Read the specifier
*/
char genSpec;
Format specifier = parseGenericFormatSpecifier(format, i, genSpec);
if (specifier == Format_error)
return formatError(idx, i);
idx = i;
return specifier; // success
}
/**************************************
* Parse the *format specifier* which is of the form:
*
* `%[flags][field width][.precision][length modifier]specifier`
*
* Params:
* format = format string
* idx = index of `%` of start of format specifier,
* which gets updated to index past the end of it,
* even if `Format_error` is returned
* widthStar = set if * for width
* precisionStar = set if * for precision
* Returns:
* Format
*/
static Format parsePrintfFormatSpecifier(const char *format, size_t &idx,
bool &widthStar, bool &precisionStar)
{
widthStar = false;
precisionStar = false;
size_t i = idx;
assert(format[i] == '%');
const size_t format_length = strlen(format);
const size_t length = format_length;
bool hash = false;
bool zero = false;
bool flags = false;
bool width = false;
bool precision = false;
++i;
if (i == length)
return formatError(idx, i);
if (format[i] == '%')
{
idx = i + 1;
return Format_percent;
}
/* Read the `flags`
*/
while (1)
{
const char c = format[i];
if (c == '-' ||
c == '+' ||
c == ' ')
{
flags = true;
}
else if (c == '#')
{
hash = true;
}
else if (c == '0')
{
zero = true;
}
else
break;
++i;
if (i == length)
return formatError(idx, i);
}
/* Read the `field width`
*/
{
const char c = format[i];
if (c == '*')
{
width = true;
widthStar = true;
++i;
if (i == length)
return formatError(idx, i);
}
else if ('1' <= c && c <= '9')
{
width = true;
++i;
if (i == length)
return formatError(idx, i);
while ('0' <= format[i] && format[i] <= '9')
{
++i;
if (i == length)
return formatError(idx, i);
}
}
}
/* Read the `precision`
*/
if (format[i] == '.')
{
precision = true;
++i;
if (i == length)
return formatError(idx, i);
const char c = format[i];
if (c == '*')
{
precisionStar = true;
++i;
if (i == length)
return formatError(idx, i);
}
else if ('0' <= c && c <= '9')
{
++i;
if (i == length)
return formatError(idx, i);
while ('0' <= format[i] && format[i] <= '9')
{
++i;
if (i == length)
return formatError(idx, i);
}
}
}
/* Read the specifier
*/
char genSpec;
Format specifier = parseGenericFormatSpecifier(format, i, genSpec);
if (specifier == Format_error)
return formatError(idx, i);
switch (genSpec)
{
case 'c':
case 's':
if (hash || zero)
return formatError(idx, i);
break;
case 'd':
case 'i':
if (hash)
return formatError(idx, i);
break;
case 'n':
if (hash || zero || precision || width || flags)
return formatError(idx, i);
break;
default:
break;
}
idx = i;
return specifier; // success
}
/*******************************************/
static Expression *getNextPrintfArg(const Loc &loc, Expressions &args, size_t &n,
size_t gnu_m_count, bool &skip)
{
if (n == args.length)
{
if (args.length < (n + 1) - gnu_m_count)
deprecation(loc, "more format specifiers than %d arguments", (int)n);
else
skip = true;
return NULL;
}
return args[n++];
}
static void errorPrintfFormat(const char *prefix, DString &slice, Expression *arg,
const char *texpect, Type *tactual)
{
deprecation(arg->loc, "%sargument `%s` for format specification `\"%.*s\"` must be `%s`, not `%s`",
prefix ? prefix : "", arg->toChars(), (int)slice.length, slice.ptr, texpect, tactual->toChars());
}
/******************************************
* Check that arguments to a printf format string are compatible
* with that string. Issue errors for incompatibilities.
*
* Follows the C99 specification for printf.
*
* Takes a generous, rather than strict, view of compatiblity.
* For example, an unsigned value can be formatted with a signed specifier.
*
* Diagnosed incompatibilities are:
*
* 1. incompatible sizes which will cause argument misalignment
* 2. deferencing arguments that are not pointers
* 3. insufficient number of arguments
* 4. struct arguments
* 5. array and slice arguments
* 6. non-pointer arguments to `s` specifier
* 7. non-standard formats
* 8. undefined behavior per C99
*
* Per the C Standard, extra arguments are ignored.
*
* No attempt is made to fix the arguments or the format string.
*
* Params:
* loc = location for error messages
* format = format string
* args = arguments to match with format string
* isVa_list = if a "v" function (format check only)
*
* Returns:
* `true` if errors occurred
* References:
* C99 7.19.6.1
* http://www.cplusplus.com/reference/cstdio/printf/
*/
bool checkPrintfFormat(const Loc &loc, const char *format, Expressions &args, bool isVa_list)
{
//printf("checkPrintFormat('%s')\n", format);
size_t n = 0; // index in args
size_t gnu_m_count = 0; // number of Format_GNU_m
const size_t format_length = strlen(format);
for (size_t i = 0; i < format_length;)
{
if (format[i] != '%')
{
++i;
continue;
}
bool widthStar = false;
bool precisionStar = false;
size_t j = i;
const Format fmt = parsePrintfFormatSpecifier(format, j, widthStar, precisionStar);
DString slice = DString(j - i, format + i);
i = j;
if (fmt == Format_percent)
continue; // "%%", no arguments
if (isVa_list)
{
// format check only
if (fmt == Format_error)
deprecation(loc, "format specifier `\"%.*s\"` is invalid", (int)slice.length, slice.ptr);
continue;
}
if (fmt == Format_GNU_m)
++gnu_m_count;
if (widthStar)
{
bool skip = false;
Expression *e = getNextPrintfArg(loc, args, n, gnu_m_count, skip);
if (skip)
continue;
if (!e)
return true;
Type *t = e->type->toBasetype();
if (t->ty != Tint32 && t->ty != Tuns32)
errorPrintfFormat("width ", slice, e, "int", t);
}
if (precisionStar)
{
bool skip = false;
Expression *e = getNextPrintfArg(loc, args, n, gnu_m_count, skip);
if (skip)
continue;
if (!e)
return true;
Type *t = e->type->toBasetype();
if (t->ty != Tint32 && t->ty != Tuns32)
errorPrintfFormat("precision ", slice, e, "int", t);
}
bool skip = false;
Expression *e = getNextPrintfArg(loc, args, n, gnu_m_count, skip);
if (skip)
continue;
if (!e)
return true;
Type *t = e->type->toBasetype();
Type *tnext = t->nextOf();
const unsigned c_longsize = target.c.longsize;
const bool is64bit = global.params.is64bit;
// Types which are promoted to int are allowed.
// Spec: C99 6.5.2.2.7
switch (fmt)
{
case Format_u: // unsigned int
case Format_d: // int
if (t->ty != Tint32 && t->ty != Tuns32)
errorPrintfFormat(NULL, slice, e, "int", t);
break;
case Format_hhu: // unsigned char
case Format_hhd: // signed char
if (t->ty != Tint32 && t->ty != Tuns32 && t->ty != Tint8 && t->ty != Tuns8)
errorPrintfFormat(NULL, slice, e, "byte", t);
break;
case Format_hu: // unsigned short int
case Format_hd: // short int
if (t->ty != Tint32 && t->ty != Tuns32 && t->ty != Tint16 && t->ty != Tuns16)
errorPrintfFormat(NULL, slice, e, "short", t);
break;
case Format_lu: // unsigned long int
case Format_ld: // long int
if (!(t->isintegral() && t->size() == c_longsize))
errorPrintfFormat(NULL, slice, e, (c_longsize == 4 ? "int" : "long"), t);
break;
case Format_llu: // unsigned long long int
case Format_lld: // long long int
if (t->ty != Tint64 && t->ty != Tuns64)
errorPrintfFormat(NULL, slice, e, "long", t);
break;
case Format_ju: // uintmax_t
case Format_jd: // intmax_t
if (t->ty != Tint64 && t->ty != Tuns64)
errorPrintfFormat(NULL, slice, e, "core.stdc.stdint.intmax_t", t);
break;
case Format_zd: // size_t
if (!(t->isintegral() && t->size() == (is64bit ? 8 : 4)))
errorPrintfFormat(NULL, slice, e, "size_t", t);
break;
case Format_td: // ptrdiff_t
if (!(t->isintegral() && t->size() == (is64bit ? 8 : 4)))
errorPrintfFormat(NULL, slice, e, "ptrdiff_t", t);
break;
case Format_GNU_a: // Format_GNU_a is only for scanf
case Format_lg:
case Format_g: // double
if (t->ty != Tfloat64 && t->ty != Timaginary64)
errorPrintfFormat(NULL, slice, e, "double", t);
break;
case Format_Lg: // long double
if (t->ty != Tfloat80 && t->ty != Timaginary80)
errorPrintfFormat(NULL, slice, e, "real", t);
break;
case Format_p: // pointer
if (t->ty != Tpointer && t->ty != Tnull && t->ty != Tclass && t->ty != Tdelegate && t->ty != Taarray)
errorPrintfFormat(NULL, slice, e, "void*", t);
break;
case Format_n: // pointer to int
if (!(t->ty == Tpointer && tnext->ty == Tint32))
errorPrintfFormat(NULL, slice, e, "int*", t);
break;
case Format_ln: // pointer to long int
if (!(t->ty == Tpointer && tnext->isintegral() && tnext->size() == c_longsize))
errorPrintfFormat(NULL, slice, e, (c_longsize == 4 ? "int*" : "long*"), t);
break;
case Format_lln: // pointer to long long int
if (!(t->ty == Tpointer && tnext->ty == Tint64))
errorPrintfFormat(NULL, slice, e, "long*", t);
break;
case Format_hn: // pointer to short
if (!(t->ty == Tpointer && tnext->ty == Tint16))
errorPrintfFormat(NULL, slice, e, "short*", t);
break;
case Format_hhn: // pointer to signed char
if (!(t->ty == Tpointer && tnext->ty == Tint16))
errorPrintfFormat(NULL, slice, e, "byte*", t);
break;
case Format_jn: // pointer to intmax_t
if (!(t->ty == Tpointer && tnext->ty == Tint64))
errorPrintfFormat(NULL, slice, e, "core.stdc.stdint.intmax_t*", t);
break;
case Format_zn: // pointer to size_t
if (!(t->ty == Tpointer && tnext->ty == (is64bit ? Tuns64 : Tuns32)))
errorPrintfFormat(NULL, slice, e, "size_t*", t);
break;
case Format_tn: // pointer to ptrdiff_t
if (!(t->ty == Tpointer && tnext->ty == (is64bit ? Tint64 : Tint32)))
errorPrintfFormat(NULL, slice, e, "ptrdiff_t*", t);
break;
case Format_c: // char
if (t->ty != Tint32 && t->ty != Tuns32)
errorPrintfFormat(NULL, slice, e, "char", t);
break;
case Format_lc: // wint_t
if (t->ty != Tint32 && t->ty != Tuns32)
errorPrintfFormat(NULL, slice, e, "wchar_t", t);
break;
case Format_s: // pointer to char string
if (!(t->ty == Tpointer && (tnext->ty == Tchar || tnext->ty == Tint8 || tnext->ty == Tuns8)))
errorPrintfFormat(NULL, slice, e, "char*", t);
break;
case Format_ls: // pointer to wchar_t string
{
if (!(t->ty == Tpointer && tnext == target.c.twchar_t))
errorPrintfFormat(NULL, slice, e, "wchar_t*", t);
break;
}
case Format_error:
deprecation(loc, "format specifier `\"%.*s\"` is invalid", (int)slice.length, slice.ptr);
break;
case Format_GNU_m:
break; // not assert(0) because it may go through it if there are extra arguments
case Format_percent:
default:
assert(0);
}
}
return false;
}
/*******************************************/
static Expression *getNextScanfArg(const Loc &loc, Expressions &args, size_t &n, bool asterisk)
{
if (n == args.length)
{
if (!asterisk)
deprecation(loc, "more format specifiers than %d arguments", (int)n);
return NULL;
}
return args[n++];
}
static void errorScanfFormat(const char *prefix, DString &slice,
Expression *arg, const char *texpect, Type *tactual)
{
deprecation(arg->loc, "%sargument `%s` for format specification `\"%.*s\"` must be `%s`, not `%s`",
prefix ? prefix : "", arg->toChars(), (int)slice.length, slice.ptr, texpect, tactual->toChars());
}
/******************************************
* Check that arguments to a scanf format string are compatible
* with that string. Issue errors for incompatibilities.
*
* Follows the C99 specification for scanf.
*
* Takes a generous, rather than strict, view of compatiblity.
* For example, an unsigned value can be formatted with a signed specifier.
*
* Diagnosed incompatibilities are:
*
* 1. incompatible sizes which will cause argument misalignment
* 2. deferencing arguments that are not pointers
* 3. insufficient number of arguments
* 4. struct arguments
* 5. array and slice arguments
* 6. non-standard formats
* 7. undefined behavior per C99
*
* Per the C Standard, extra arguments are ignored.
*
* No attempt is made to fix the arguments or the format string.
*
* Params:
* loc = location for error messages
* format = format string
* args = arguments to match with format string
* isVa_list = if a "v" function (format check only)
*
* Returns:
* `true` if errors occurred
* References:
* C99 7.19.6.2
* http://www.cplusplus.com/reference/cstdio/scanf/
*/
bool checkScanfFormat(const Loc &loc, const char *format, Expressions &args, bool isVa_list)
{
size_t n = 0;
const size_t format_length = strlen(format);
for (size_t i = 0; i < format_length;)
{
if (format[i] != '%')
{
++i;
continue;
}
bool asterisk = false;
size_t j = i;
const Format fmt = parseScanfFormatSpecifier(format, j, asterisk);
DString slice = DString(j - i, format + i);
i = j;
if (fmt == Format_percent || asterisk)
continue; // "%%", "%*": no arguments
if (isVa_list)
{
// format check only
if (fmt == Format_error)
deprecation(loc, "format specifier `\"%.*s\"` is invalid", (int)slice.length, slice.ptr);
continue;
}
Expression *e = getNextScanfArg(loc, args, n, asterisk);
if (!e)
return true;
Type *t = e->type->toBasetype();
Type *tnext = t->nextOf();
const unsigned c_longsize = target.c.longsize;
const bool is64bit = global.params.is64bit;
switch (fmt)
{
case Format_n:
case Format_d: // pointer to int
if (!(t->ty == Tpointer && tnext->ty == Tint32))
errorScanfFormat(NULL, slice, e, "int*", t);
break;
case Format_hhn:
case Format_hhd: // pointer to signed char
if (!(t->ty == Tpointer && tnext->ty == Tint16))
errorScanfFormat(NULL, slice, e, "byte*", t);
break;
case Format_hn:
case Format_hd: // pointer to short
if (!(t->ty == Tpointer && tnext->ty == Tint16))
errorScanfFormat(NULL, slice, e, "short*", t);
break;
case Format_ln:
case Format_ld: // pointer to long int
if (!(t->ty == Tpointer && tnext->isintegral() && tnext->size() == c_longsize))
errorScanfFormat(NULL, slice, e, (c_longsize == 4 ? "int*" : "long*"), t);
break;
case Format_lln:
case Format_lld: // pointer to long long int
if (!(t->ty == Tpointer && tnext->ty == Tint64))
errorScanfFormat(NULL, slice, e, "long*", t);
break;
case Format_jn:
case Format_jd: // pointer to intmax_t
if (!(t->ty == Tpointer && tnext->ty == Tint64))
errorScanfFormat(NULL, slice, e, "core.stdc.stdint.intmax_t*", t);
break;
case Format_zn:
case Format_zd: // pointer to size_t
if (!(t->ty == Tpointer && tnext->ty == (is64bit ? Tuns64 : Tuns32)))
errorScanfFormat(NULL, slice, e, "size_t*", t);
break;
case Format_tn:
case Format_td: // pointer to ptrdiff_t
if (!(t->ty == Tpointer && tnext->ty == (is64bit ? Tint64 : Tint32)))
errorScanfFormat(NULL, slice, e, "ptrdiff_t*", t);
break;
case Format_u: // pointer to unsigned int
if (!(t->ty == Tpointer && tnext->ty == Tuns32))
errorScanfFormat(NULL, slice, e, "uint*", t);
break;
case Format_hhu: // pointer to unsigned char
if (!(t->ty == Tpointer && tnext->ty == Tuns8))
errorScanfFormat(NULL, slice, e, "ubyte*", t);
break;
case Format_hu: // pointer to unsigned short int
if (!(t->ty == Tpointer && tnext->ty == Tuns16))
errorScanfFormat(NULL, slice, e, "ushort*", t);
break;
case Format_lu: // pointer to unsigned long int
if (!(t->ty == Tpointer && tnext->ty == (is64bit ? Tuns64 : Tuns32)))
errorScanfFormat(NULL, slice, e, (c_longsize == 4 ? "uint*" : "ulong*"), t);
break;
case Format_llu: // pointer to unsigned long long int
if (!(t->ty == Tpointer && tnext->ty == Tuns64))
errorScanfFormat(NULL, slice, e, "ulong*", t);
break;
case Format_ju: // pointer to uintmax_t
if (!(t->ty == Tpointer && tnext->ty == (is64bit ? Tuns64 : Tuns32)))
errorScanfFormat(NULL, slice, e, "ulong*", t);
break;
case Format_g: // pointer to float
if (!(t->ty == Tpointer && tnext->ty == Tfloat32))
errorScanfFormat(NULL, slice, e, "float*", t);
break;
case Format_lg: // pointer to double
if (!(t->ty == Tpointer && tnext->ty == Tfloat64))
errorScanfFormat(NULL, slice, e, "double*", t);
break;
case Format_Lg: // pointer to long double
if (!(t->ty == Tpointer && tnext->ty == Tfloat80))
errorScanfFormat(NULL, slice, e, "real*", t);
break;
case Format_GNU_a:
case Format_GNU_m:
case Format_c:
case Format_s: // pointer to char string
if (!(t->ty == Tpointer && (tnext->ty == Tchar || tnext->ty == Tint8 || tnext->ty == Tuns8)))
errorScanfFormat(NULL, slice, e, "char*", t);
break;
case Format_lc:
case Format_ls: // pointer to wchar_t string
{
if (!(t->ty == Tpointer && tnext == target.c.twchar_t))
errorScanfFormat(NULL, slice, e, "wchar_t*", t);
break;
}
case Format_p: // double pointer
if (!(t->ty == Tpointer && tnext->ty == Tpointer))
errorScanfFormat(NULL, slice, e, "void**", t);
break;
case Format_error:
deprecation(loc, "format specifier `\"%.*s\"` is invalid", (int)slice.length, slice.ptr);
break;
case Format_percent:
default:
assert(0);
}
}
return false;
}

View file

@ -806,6 +806,14 @@ public:
writeBasicType(t, 'D', 'n');
}
void visit(TypeNoreturn *t)
{
if (t->isImmutable() || t->isShared())
return error(t);
writeBasicType(t, 0, 'v'); // mangle like `void`
}
void visit(TypeBasic *t)
{
if (t->isImmutable() || t->isShared())
@ -1012,7 +1020,7 @@ public:
if (t->isImmutable() || t->isShared())
return error(t);
/* __c_(u)long(long) get special mangling
/* __c_(u)long(long) and others get special mangling
*/
Identifier *id = t->sym->ident;
//printf("enum id = '%s'\n", id->toChars());
@ -1020,10 +1028,18 @@ public:
return writeBasicType(t, 0, 'l');
else if (id == Id::__c_ulong)
return writeBasicType(t, 0, 'm');
else if (id == Id::__c_wchar_t)
return writeBasicType(t, 0, 'w');
else if (id == Id::__c_longlong)
return writeBasicType(t, 0, 'x');
else if (id == Id::__c_ulonglong)
return writeBasicType(t, 0, 'y');
else if (id == Id::__c_complex_float)
return writeBasicType(t, 'C', 'f');
else if (id == Id::__c_complex_double)
return writeBasicType(t, 'C', 'd');
else if (id == Id::__c_complex_real)
return writeBasicType(t, 'C', 'e');
doSymbol(t);
}

View file

@ -162,7 +162,7 @@ const char *CTFEExp::toChars()
switch (op)
{
case TOKcantexp: return "<cant>";
case TOKvoidexp: return "<void>";
case TOKvoidexp: return "cast(void)0";
case TOKbreak: return "<break>";
case TOKcontinue: return "<continue>";
case TOKgoto: return "<goto>";

View file

@ -26,6 +26,7 @@
FuncDeclaration *isFuncAddress(Expression *e, bool *hasOverloads = NULL);
bool isCommutative(TOK op);
MOD MODmerge(MOD mod1, MOD mod2);
void toAutoQualChars(const char **result, Type *t1, Type *t2);
/* ==================== implicitCast ====================== */
@ -90,8 +91,10 @@ Expression *implicitCastTo(Expression *e, Scope *sc, Type *t)
//printf("type %p ty %d deco %p\n", type, type->ty, type->deco);
//type = type->semantic(loc, sc);
//printf("type %s t %s\n", type->deco, t->deco);
const char *ts[2];
toAutoQualChars(ts, e->type, t);
e->error("cannot implicitly convert expression (%s) of type %s to %s",
e->toChars(), e->type->toChars(), t->toChars());
e->toChars(), ts[0], ts[1]);
}
}
result = new ErrorExp();

View file

@ -277,15 +277,10 @@ Scope *ClassDeclaration::newScope(Scope *sc)
Scope *sc2 = AggregateDeclaration::newScope(sc);
if (isCOMclass())
{
if (global.params.isWindows)
sc2->linkage = LINKwindows;
else
{
/* This enables us to use COM objects under Linux and
* work with things like XPCOM
*/
sc2->linkage = LINKc;
}
/* This enables us to use COM objects under Linux and
* work with things like XPCOM
*/
sc2->linkage = target.systemLinkage();
}
return sc2;
}
@ -491,9 +486,10 @@ void ClassDeclaration::finalizeSize()
assert(baseClass->sizeok == SIZEOKdone);
alignsize = baseClass->alignsize;
structsize = baseClass->structsize;
if (isCPPclass() && global.params.isWindows)
structsize = (structsize + alignsize - 1) & ~(alignsize - 1);
if (classKind == ClassKind::cpp)
structsize = target.cpp.derivedClassOffset(baseClass);
else
structsize = baseClass->structsize;
}
else if (isInterfaceDeclaration())
{

View file

@ -118,7 +118,7 @@ struct Match
FuncDeclaration *anyf; // pick a func, any func, to use for error recovery
};
void functionResolve(Match *m, Dsymbol *fd, Loc loc, Scope *sc, Objects *tiargs, Type *tthis, Expressions *fargs);
void functionResolve(Match *m, Dsymbol *fd, Loc loc, Scope *sc, Objects *tiargs, Type *tthis, Expressions *fargs, const char **pMessage = NULL);
int overloadApply(Dsymbol *fstart, void *param, int (*fp)(void *, Dsymbol *));
void aliasSemantic(AliasDeclaration *ds, Scope *sc);
@ -551,6 +551,8 @@ void builtin_init();
#define FUNCFLAGreturnInprocess 0x10 // working on inferring 'return' for parameters
#define FUNCFLAGinlineScanned 0x20 // function has been scanned for inline possibilities
#define FUNCFLAGinferScope 0x40 // infer 'scope' for parameters
#define FUNCFLAGprintf 0x200 // is a printf-like function
#define FUNCFLAGscanf 0x400 // is a scanf-like function
class FuncDeclaration : public Declaration
{

View file

@ -22,6 +22,19 @@
#include "declaration.h"
#include "init.h"
bool isSpecialEnumIdent(const Identifier *ident)
{
return ident == Id::__c_long ||
ident == Id::__c_ulong ||
ident == Id::__c_longlong ||
ident == Id::__c_ulonglong ||
ident == Id::__c_long_double ||
ident == Id::__c_wchar_t ||
ident == Id::__c_complex_float ||
ident == Id::__c_complex_double ||
ident == Id::__c_complex_real;
}
/********************************* EnumDeclaration ****************************/
EnumDeclaration::EnumDeclaration(Loc loc, Identifier *id, Type *memtype)
@ -187,11 +200,7 @@ Lerrors:
*/
bool EnumDeclaration::isSpecial() const
{
return (ident == Id::__c_long ||
ident == Id::__c_ulong ||
ident == Id::__c_longlong ||
ident == Id::__c_ulonglong ||
ident == Id::__c_long_double) && memtype;
return isSpecialEnumIdent(ident) && memtype;
}
Expression *EnumDeclaration::getDefaultValue(Loc loc)

View file

@ -161,37 +161,75 @@ void Import::load(Scope *sc)
if (mod && !mod->importedFrom)
mod->importedFrom = sc ? sc->_module->importedFrom : Module::rootModule;
if (!pkg)
pkg = mod;
{
if (mod && mod->isPackageFile)
{
// one level depth package.d file (import pkg; ./pkg/package.d)
// it's necessary to use the wrapping Package already created
pkg = mod->pkg;
}
else
pkg = mod;
}
//printf("-Import::load('%s'), pkg = %p\n", toChars(), pkg);
}
void Import::importAll(Scope *sc)
{
if (!mod)
if (mod) return; // Already done
load(sc);
if (!mod) return; // Failed
if (sc->stc & STCstatic)
isstatic = true;
mod->importAll(NULL);
if (mod->md && mod->md->isdeprecated)
{
load(sc);
if (mod) // if successfully loaded module
Expression *msg = mod->md->msg;
if (StringExp *se = msg ? msg->toStringExp() : NULL)
mod->deprecation(loc, "is deprecated - %s", se->string);
else
mod->deprecation(loc, "is deprecated");
}
if (sc->explicitProtection)
protection = sc->protection;
if (!isstatic && !aliasId && !names.length)
sc->scopesym->importScope(mod, protection);
// Enable access to pkgs/mod as soon as posible, because compiler
// can traverse them before the import gets semantic (Issue: 21501)
if (!aliasId && !names.length)
addPackageAccess(sc->scopesym);
}
/*******************************
* Mark the imported packages as accessible from the current
* scope. This access check is necessary when using FQN b/c
* we're using a single global package tree.
* https://issues.dlang.org/show_bug.cgi?id=313
*/
void Import::addPackageAccess(ScopeDsymbol *scopesym)
{
//printf("Import::addPackageAccess('%s') %p\n", toPrettyChars(), this);
if (packages)
{
// import a.b.c.d;
Package *p = pkg; // a
scopesym->addAccessiblePackage(p, protection);
for (size_t i = 1; i < packages->length; i++) // [b, c]
{
mod->importAll(NULL);
if (mod->md && mod->md->isdeprecated)
{
Expression *msg = mod->md->msg;
if (StringExp *se = msg ? msg->toStringExp() : NULL)
mod->deprecation(loc, "is deprecated - %s", se->string);
else
mod->deprecation(loc, "is deprecated");
}
if (sc->explicitProtection)
protection = sc->protection;
if (!isstatic && !aliasId && !names.length)
{
sc->scopesym->importScope(mod, protection);
}
Identifier *id = (*packages)[i];
p = (Package *) p->symtab->lookup(id);
// https://issues.dlang.org/show_bug.cgi?id=17991
// An import of truly empty file/package can happen
// https://issues.dlang.org/show_bug.cgi?id=20151
// Package in the path conflicts with a module name
if (p == NULL)
return;
scopesym->addAccessiblePackage(p, protection);
}
}
scopesym->addAccessiblePackage(mod, protection); // d
}
Dsymbol *Import::toAlias()

View file

@ -82,6 +82,8 @@ void initTypeMangle()
mangleChar[Treturn] = "@";
mangleChar[Tvector] = "@";
mangleChar[Ttraits] = "@";
mangleChar[Tmixin] = "@";
mangleChar[Tnoreturn] = "@"; // becomes 'Nn'
mangleChar[Tnull] = "n"; // same as TypeNone
@ -150,7 +152,7 @@ public:
* using upper case letters for all digits but the last digit which uses
* a lower case letter.
* The decoder has to look up the referenced position to determine
* whether the back reference is an identifer (starts with a digit)
* whether the back reference is an identifier (starts with a digit)
* or a type (starts with a letter).
*
* Params:
@ -414,6 +416,11 @@ public:
visit((Type *)t);
}
void visit(TypeNoreturn *)
{
buf->writestring("Nn");
}
////////////////////////////////////////////////////////////////////////////
void mangleDecl(Declaration *sthis)
@ -1085,3 +1092,31 @@ void mangleToBuffer(TemplateInstance *ti, OutBuffer *buf)
Mangler v(buf);
v.mangleTemplateInstance(ti);
}
/**********************************************
* Convert a string representing a type (the deco) and
* return its equivalent Type.
* Params:
* deco = string containing the deco
* Returns:
* null for failed to convert
* Type for succeeded
*/
Type *decoToType(const char *deco)
{
if (!deco)
return NULL;
//printf("decoToType(): %s\n", deco)
if (StringValue *sv = Type::stringtable.lookup(deco, strlen(deco)))
{
if (sv->ptrvalue)
{
Type *t = (Type *)sv->ptrvalue;
assert(t->deco);
return t;
}
}
return NULL;
}

View file

@ -52,6 +52,7 @@ Module::Module(const char *filename, Identifier *ident, int doDocComment, int do
members = NULL;
isDocFile = 0;
isPackageFile = false;
pkg = NULL;
needmoduleinfo = 0;
selfimports = 0;
rootimports = 0;
@ -685,15 +686,27 @@ Module *Module::parse()
*
* To avoid the conflict:
* 1. If preceding package name insertion had occurred by Package::resolve,
* later package.d loading will change Package::isPkgMod to PKGmodule and set Package::mod.
* reuse the previous wrapping 'Package' if it exists
* 2. Otherwise, 'package.d' wrapped by 'Package' is inserted to the internal tree in here.
*
* Then change Package::isPkgMod to PKGmodule and set Package::mod.
*
* Note that the 'wrapping Package' is the Package that contains package.d and other submodules,
* the one inserted to the symbol table.
*/
Package *p = new Package(ident);
Dsymbol *ps = dst->lookup(ident);
Package *p = ps ? ps->isPackage() : NULL;
if (p == NULL)
{
p = new Package(ident);
p->tag = this->tag; // reuse the same package tag
p->symtab = new DsymbolTable();
}
this->tag= p->tag; // reuse the 'older' package tag
this->pkg = p;
p->parent = this->parent;
p->isPkgMod = PKGmodule;
p->mod = this;
p->tag = this->tag; // reuse the same package tag
p->symtab = new DsymbolTable();
s = p;
}
if (!dst->insert(s))
@ -720,15 +733,9 @@ Module *Module::parse()
}
else if (Package *pkg = prev->isPackage())
{
if (pkg->isPkgMod == PKGunknown && isPackageFile)
{
/* If the previous inserted Package is not yet determined as package.d,
* link it to the actual module.
*/
pkg->isPkgMod = PKGmodule;
pkg->mod = this;
pkg->tag = this->tag; // reuse the same package tag
}
// 'package.d' loaded after a previous 'Package' insertion
if (isPackageFile)
amodules.push(this); // Add to global array of all modules
else
error(md ? md->loc : loc, "from file %s conflicts with package name %s",
srcname, pkg->toChars());

View file

@ -24,6 +24,7 @@
#include "aggregate.h"
#include "module.h"
#include "id.h"
#include "target.h"
#include "template.h"
Scope *Scope::freelist = NULL;
@ -155,7 +156,8 @@ Scope *Scope::push()
s->nofree = 0;
s->fieldinit = saveFieldInit();
s->flags = (flags & (SCOPEcontract | SCOPEdebug | SCOPEctfe | SCOPEcompile | SCOPEconstraint |
SCOPEnoaccesscheck | SCOPEignoresymbolvisibility));
SCOPEnoaccesscheck | SCOPEignoresymbolvisibility |
SCOPEprintf | SCOPEscanf));
s->lastdc = NULL;
assert(this != s);
@ -637,7 +639,7 @@ const char *Scope::search_correct_C(Identifier *ident)
else if (ident == Id::C_unsigned)
tok = TOKuns32;
else if (ident == Id::C_wchar_t)
tok = global.params.isWindows ? TOKwchar : TOKdchar;
tok = target.c.twchar_t->ty == Twchar ? TOKwchar : TOKdchar;
else
return NULL;
return Token::toChars(tok);

View file

@ -515,7 +515,7 @@ Dsymbol *Dsymbol::search_correct(Identifier *ident)
* Returns:
* symbol found, NULL if not
*/
Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, RootObject *id)
Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, RootObject *id, int flags)
{
//printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars());
Dsymbol *s = toAlias();
@ -533,7 +533,7 @@ Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, RootObject *id)
switch (id->dyncast())
{
case DYNCAST_IDENTIFIER:
sm = s->search(loc, (Identifier *)id);
sm = s->search(loc, (Identifier *)id, flags);
break;
case DYNCAST_DSYMBOL:
@ -1801,31 +1801,3 @@ bool Prot::operator==(const Prot& other) const
}
return false;
}
/**
* Checks if parent defines different access restrictions than this one.
*
* Params:
* parent = protection attribute for scope that hosts this one
*
* Returns:
* 'true' if parent is already more restrictive than this one and thus
* no differentiation is needed.
*/
bool Prot::isSubsetOf(const Prot& parent) const
{
if (this->kind != parent.kind)
return false;
if (this->kind == Prot::package_)
{
if (!this->pkg)
return true;
if (!parent.pkg)
return false;
if (parent.pkg->isAncestorPackageOf(this->pkg))
return true;
}
return true;
}

View file

@ -107,7 +107,6 @@ struct Prot
bool isMoreRestrictiveThan(const Prot other) const;
bool operator==(const Prot& other) const;
bool isSubsetOf(const Prot& other) const;
};
// in hdrgen.c
@ -207,7 +206,7 @@ public:
virtual void importAll(Scope *sc);
virtual Dsymbol *search(const Loc &loc, Identifier *ident, int flags = IgnoreNone);
Dsymbol *search_correct(Identifier *id);
Dsymbol *searchX(Loc loc, Scope *sc, RootObject *id);
Dsymbol *searchX(Loc loc, Scope *sc, RootObject *id, int flags);
virtual bool overloadInsert(Dsymbol *s);
virtual d_uns64 size(Loc loc);
virtual bool isforwardRef();

View file

@ -42,6 +42,8 @@ VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e);
Initializer *inferType(Initializer *init, Scope *sc);
void MODtoBuffer(OutBuffer *buf, MOD mod);
bool reliesOnTident(Type *t, TemplateParameters *tparams = NULL, size_t iStart = 0);
bool expressionsToString(OutBuffer &buf, Scope *sc, Expressions *exps);
bool symbolIsVisible(Scope *sc, Dsymbol *s);
Objc *objc();
static unsigned setMangleOverride(Dsymbol *s, char *sym)
@ -1098,22 +1100,7 @@ public:
scopesym->importScope(imp->mod, imp->protection);
}
// Mark the imported packages as accessible from the current
// scope. This access check is necessary when using FQN b/c
// we're using a single global package tree. See Bugzilla 313.
if (imp->packages)
{
// import a.b.c.d;
Package *p = imp->pkg; // a
scopesym->addAccessiblePackage(p, imp->protection);
for (size_t i = 1; i < imp->packages->length; i++) // [b, c]
{
Identifier *id = (*imp->packages)[i];
p = (Package *) p->symtab->lookup(id);
scopesym->addAccessiblePackage(p, imp->protection);
}
}
scopesym->addAccessiblePackage(imp->mod, imp->protection); // d
imp->addPackageAccess(scopesym);
}
dsymbolSemantic(imp->mod, NULL);
@ -1130,8 +1117,12 @@ public:
{
AliasDeclaration *ad = imp->aliasdecls[i];
//printf("\tImport %s alias %s = %s, scope = %p\n", toPrettyChars(), imp->aliases[i]->toChars(), imp->names[i]->toChars(), ad->_scope);
if (imp->mod->search(imp->loc, imp->names[i]))
Dsymbol *sym = imp->mod->search(imp->loc, imp->names[i], IgnorePrivateImports);
if (sym)
{
if (!symbolIsVisible(sc, sym))
imp->mod->error(imp->loc, "member `%s` is not visible from module `%s`",
imp->names[i]->toChars(), sc->_module->toChars());
dsymbolSemantic(ad, sc);
// If the import declaration is in non-root module,
// analysis of the aliased symbol is deferred.
@ -1141,7 +1132,7 @@ public:
{
Dsymbol *s = imp->mod->search_correct(imp->names[i]);
if (s)
imp->mod->error(imp->loc, "import `%s` not found, did you mean %s `%s`?", imp->names[i]->toChars(), s->kind(), s->toChars());
imp->mod->error(imp->loc, "import `%s` not found, did you mean %s `%s`?", imp->names[i]->toChars(), s->kind(), s->toPrettyChars());
else
imp->mod->error(imp->loc, "import `%s` not found", imp->names[i]->toChars());
ad->type = Type::terror;
@ -1312,8 +1303,6 @@ public:
e = expressionSemantic(e, sc);
e = resolveProperties(sc, e);
sc = sc->endCTFE();
// pragma(msg) is allowed to contain types as well as expressions
e = ctfeInterpretForPragmaMsg(e);
if (e->op == TOKerror)
{
@ -1458,6 +1447,12 @@ public:
}
}
}
else if (pd->ident == Id::printf || pd->ident == Id::scanf)
{
if (pd->args && pd->args->length != 0)
pd->error("takes no argument");
goto Ldecl;
}
else if (global.params.ignoreUnsupportedPragmas)
{
if (global.params.verbose)
@ -1547,13 +1542,14 @@ public:
Dsymbols *compileIt(CompileDeclaration *cd)
{
//printf("CompileDeclaration::compileIt(loc = %d) %s\n", cd->loc.linnum, cd->exp->toChars());
StringExp *se = semanticString(sc, cd->exp, "argument to mixin");
if (!se)
OutBuffer buf;
if (expressionsToString(buf, sc, cd->exps))
return NULL;
se = se->toUTF8(sc);
unsigned errors = global.errors;
Parser p(cd->loc, sc->_module, (utf8_t *)se->string, se->len, 0);
const size_t len = buf.length();
const char *str = buf.extractChars();
Parser p(cd->loc, sc->_module, (const utf8_t *)str, len, false);
p.nextToken();
Dsymbols *d = p.parseDeclDefs(0);
@ -1562,7 +1558,7 @@ public:
if (p.token.value != TOKeof)
{
cd->exp->error("incomplete mixin declaration (%s)", se->toChars());
cd->error("incomplete mixin declaration (%s)", str);
return NULL;
}
return d;
@ -1637,7 +1633,7 @@ public:
Scope *sc = m->_scope; // see if already got one from importAll()
if (!sc)
{
Scope::createGlobal(m); // create root scope
sc = Scope::createGlobal(m); // create root scope
}
//printf("Module = %p, linkage = %d\n", sc->scopesym, sc->linkage);
@ -1735,7 +1731,7 @@ public:
// memtype is forward referenced, so try again later
ed->_scope = scx ? scx : sc->copy();
ed->_scope->setNoFree();
ed->_scope->_module->addDeferredSemantic(ed);
Module::addDeferredSemantic(ed);
Module::dprogress = dprogress_save;
//printf("\tdeferring %s\n", ed->toChars());
ed->semanticRun = PASSinit;
@ -2233,7 +2229,7 @@ public:
//printf("forward reference - deferring\n");
tm->_scope = scx ? scx : sc->copy();
tm->_scope->setNoFree();
tm->_scope->_module->addDeferredSemantic(tm);
Module::addDeferredSemantic(tm);
return;
}
@ -2457,6 +2453,23 @@ public:
ns->semanticRun = PASSsemanticdone;
}
private:
static bool isPointerToChar(Parameter *p)
{
if (TypePointer *tptr = p->type->isTypePointer())
{
return tptr->next->ty == Tchar;
}
return false;
}
static bool isVa_list(Parameter *p, FuncDeclaration *funcdecl, Scope *sc)
{
return p->type->equals(target.va_listType(funcdecl->loc, sc));
}
public:
void funcDeclarationSemantic(FuncDeclaration *funcdecl)
{
TypeFunction *f;
@ -2771,6 +2784,45 @@ public:
if (funcdecl->isAbstract() && funcdecl->isFinalFunc())
funcdecl->error("cannot be both final and abstract");
if (const unsigned pors = sc->flags & (SCOPEprintf | SCOPEscanf))
{
/* printf/scanf-like functions must be of the form:
* extern (C/C++) T printf([parameters...], const(char)* format, ...);
* or:
* extern (C/C++) T vprintf([parameters...], const(char)* format, va_list);
*/
const size_t nparams = f->parameterList.length();
if ((f->linkage == LINKc || f->linkage == LINKcpp) &&
((f->parameterList.varargs == VARARGvariadic &&
nparams >= 1 &&
isPointerToChar(f->parameterList[nparams - 1])) ||
(f->parameterList.varargs == VARARGnone &&
nparams >= 2 &&
isPointerToChar(f->parameterList[nparams - 2]) &&
isVa_list(f->parameterList[nparams - 1], funcdecl, sc))
)
)
{
funcdecl->flags |= (pors == SCOPEprintf) ? FUNCFLAGprintf : FUNCFLAGscanf;
}
else
{
const char *p = (pors == SCOPEprintf ? Id::printf : Id::scanf)->toChars();
if (f->parameterList.varargs == VARARGvariadic)
{
funcdecl->error("`pragma(%s)` functions must be `extern(C) %s %s([parameters...], const(char)*, ...)`"
" not `%s`",
p, f->next->toChars(), funcdecl->toChars(), funcdecl->type->toChars());
}
else
{
funcdecl->error("`pragma(%s)` functions must be `extern(C) %s %s([parameters...], const(char)*, va_list)`",
p, f->next->toChars(), funcdecl->toChars());
}
}
}
id = parent->isInterfaceDeclaration();
if (id)
{
@ -3831,7 +3883,7 @@ public:
sd->_scope = scx ? scx : sc->copy();
sd->_scope->setNoFree();
sd->_scope->_module->addDeferredSemantic(sd);
Module::addDeferredSemantic(sd);
//printf("\tdeferring %s\n", sd->toChars());
return;
@ -4079,7 +4131,7 @@ public:
{
//printf("\ttry later, forward reference of base class %s\n", tc->sym->toChars());
if (tc->sym->_scope)
tc->sym->_scope->_module->addDeferredSemantic(tc->sym);
Module::addDeferredSemantic(tc->sym);
cldec->baseok = BASEOKnone;
}
L7: ;
@ -4131,7 +4183,7 @@ public:
{
//printf("\ttry later, forward reference of base %s\n", tc->sym->toChars());
if (tc->sym->_scope)
tc->sym->_scope->_module->addDeferredSemantic(tc->sym);
Module::addDeferredSemantic(tc->sym);
cldec->baseok = BASEOKnone;
}
i++;
@ -4141,7 +4193,7 @@ public:
// Forward referencee of one or more bases, try again later
cldec->_scope = scx ? scx : sc->copy();
cldec->_scope->setNoFree();
cldec->_scope->_module->addDeferredSemantic(cldec);
Module::addDeferredSemantic(cldec);
//printf("\tL%d semantic('%s') failed due to forward references\n", __LINE__, cldec->toChars());
return;
}
@ -4254,8 +4306,8 @@ public:
cldec->_scope = scx ? scx : sc->copy();
cldec->_scope->setNoFree();
if (tc->sym->_scope)
tc->sym->_scope->_module->addDeferredSemantic(tc->sym);
cldec->_scope->_module->addDeferredSemantic(cldec);
Module::addDeferredSemantic(tc->sym);
Module::addDeferredSemantic(cldec);
//printf("\tL%d semantic('%s') failed due to forward references\n", __LINE__, cldec->toChars());
return;
}
@ -4359,7 +4411,7 @@ public:
cldec->_scope = scx ? scx : sc->copy();
cldec->_scope->setNoFree();
cldec->_scope->_module->addDeferredSemantic(cldec);
Module::addDeferredSemantic(cldec);
//printf("\tdeferring %s\n", cldec->toChars());
return;
}
@ -4628,7 +4680,7 @@ public:
{
//printf("\ttry later, forward reference of base %s\n", tc->sym->toChars());
if (tc->sym->_scope)
tc->sym->_scope->_module->addDeferredSemantic(tc->sym);
Module::addDeferredSemantic(tc->sym);
idec->baseok = BASEOKnone;
}
i++;
@ -4638,7 +4690,7 @@ public:
// Forward referencee of one or more bases, try again later
idec->_scope = scx ? scx : sc->copy();
idec->_scope->setNoFree();
idec->_scope->_module->addDeferredSemantic(idec);
Module::addDeferredSemantic(idec);
return;
}
idec->baseok = BASEOKdone;
@ -4682,8 +4734,8 @@ public:
idec->_scope = scx ? scx : sc->copy();
idec->_scope->setNoFree();
if (tc->sym->_scope)
tc->sym->_scope->_module->addDeferredSemantic(tc->sym);
idec->_scope->_module->addDeferredSemantic(idec);
Module::addDeferredSemantic(tc->sym);
Module::addDeferredSemantic(idec);
return;
}
}
@ -5335,6 +5387,7 @@ void aliasSemantic(AliasDeclaration *ds, Scope *sc)
ds->userAttribDecl = sc->userAttribDecl;
// TypeTraits needs to know if it's located in an AliasDeclaration
const unsigned oldflags = sc->flags;
sc->flags |= SCOPEalias;
if (ds->aliassym)
@ -5345,7 +5398,7 @@ void aliasSemantic(AliasDeclaration *ds, Scope *sc)
{
if (fd && fd->semanticRun >= PASSsemanticdone)
{
sc->flags &= ~SCOPEalias;
sc->flags = oldflags;
return;
}
@ -5361,13 +5414,13 @@ void aliasSemantic(AliasDeclaration *ds, Scope *sc)
ds->aliassym = NULL;
ds->type = Type::terror;
}
sc->flags &= ~SCOPEalias;
sc->flags = oldflags;
return;
}
if (ds->aliassym->isTemplateInstance())
dsymbolSemantic(ds->aliassym, sc);
sc->flags &= ~SCOPEalias;
sc->flags = oldflags;
return;
}
ds->inuse = 1;
@ -5472,7 +5525,7 @@ void aliasSemantic(AliasDeclaration *ds, Scope *sc)
if (!ds->overloadInsert(sx))
ScopeDsymbol::multiplyDefined(Loc(), sx, ds);
}
sc->flags &= ~SCOPEalias;
sc->flags = oldflags;
}

View file

@ -156,17 +156,14 @@ Dsymbol *getDsymbol(RootObject *oarg)
if (ea)
{
// Try to convert Expression to symbol
if (ea->op == TOKvar)
sa = ((VarExp *)ea)->var;
else if (ea->op == TOKfunction)
{
if (((FuncExp *)ea)->td)
sa = ((FuncExp *)ea)->td;
else
sa = ((FuncExp *)ea)->fd;
}
else if (ea->op == TOKtemplate)
sa = ((TemplateExp *)ea)->td;
if (VarExp *ve = ea->isVarExp())
sa = ve->var;
else if (FuncExp *fe = ea->isFuncExp())
sa = fe->td ? (Dsymbol *)fe->td : (Dsymbol *)fe->fd;
else if (TemplateExp *te = ea->isTemplateExp())
sa = te->td;
else if (ScopeExp *se = ea->isScopeExp())
sa = se->sds;
else
sa = NULL;
}
@ -536,6 +533,7 @@ TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id,
this->isstatic = true;
this->previous = NULL;
this->protection = Prot(Prot::undefined);
this->inuse = 0;
this->instances = NULL;
// Compute in advance for Ddoc's use
@ -770,7 +768,9 @@ MATCH TemplateDeclaration::matchWithInstance(Scope *sc, TemplateInstance *ti,
Declaration *sparam;
//printf("\targument [%d]\n", i);
inuse++;
m2 = tp->matchArg(ti->loc, paramscope, ti->tiargs, i, parameters, dedtypes, &sparam);
inuse--;
//printf("\tm2 = %d\n", m2);
if (m2 == MATCHnomatch)
@ -1397,7 +1397,9 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(
}
else
{
inuse++;
oded = tparam->defaultArg(instLoc, paramscope);
inuse--;
if (oded)
(*dedargs)[i] = declareParameter(paramscope, tparam, oded);
}
@ -1771,7 +1773,9 @@ Lmatch:
}
else
{
inuse++;
oded = tparam->defaultArg(instLoc, paramscope);
inuse--;
if (!oded)
{
// if tuple parameter and
@ -1997,18 +2001,19 @@ bool TemplateDeclaration::isOverloadable()
/*************************************************
* Given function arguments, figure out which template function
* to expand, and return matching result.
* Input:
* m matching result
* dstart the root of overloaded function templates
* loc instantiation location
* sc instantiation scope
* tiargs initial list of template arguments
* tthis if !NULL, the 'this' pointer argument
* fargs arguments to function
* Params:
* m = matching result
* dstart = the root of overloaded function templates
* loc = instantiation location
* sc = instantiation scope
* tiargs = initial list of template arguments
* tthis = if !NULL, the 'this' pointer argument
* fargs = arguments to function
* pMessage = address to store error message, or null
*/
void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc,
Objects *tiargs, Type *tthis, Expressions *fargs)
Objects *tiargs, Type *tthis, Expressions *fargs, const char **pMessage)
{
struct ParamDeduce
{
@ -2018,6 +2023,7 @@ void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc,
Type *tthis;
Objects *tiargs;
Expressions *fargs;
const char **pMessage;
// result
Match *m;
int property; // 0: unintialized
@ -2093,7 +2099,7 @@ void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc,
else
return 0; // MATCHnomatch
}
MATCH mfa = tf->callMatch(tthis_fd, fargs);
MATCH mfa = tf->callMatch(tthis_fd, fargs, 0, pMessage);
//printf("test1: mfa = %d\n", mfa);
if (mfa > MATCHnomatch)
{
@ -2180,8 +2186,12 @@ void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc,
int applyTemplate(TemplateDeclaration *td)
{
//printf("applyTemplate()\n");
// skip duplicates
if (td == td_best)
if (td->inuse)
{
td->error(loc, "recursive template expansion");
return 1;
}
if (td == td_best) // skip duplicates
return 0;
if (!sc)
@ -2431,6 +2441,7 @@ void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc,
p.tthis = tthis;
p.tiargs = tiargs;
p.fargs = fargs;
p.pMessage = pMessage;
// result
p.m = m;
@ -5165,6 +5176,16 @@ MATCH TemplateAliasParameter::matchArg(Scope *sc, RootObject *oarg,
* template X(T) {} // T => sa
*/
}
else if (ta && ta->ty != Tident)
{
/* Match any type that's not a TypeIdentifier to alias parameters,
* but prefer type parameter.
* template X(alias a) { } // a == ta
*
* TypeIdentifiers are excluded because they might be not yet resolved aliases.
*/
m = MATCHconvert;
}
else
goto Lnomatch;
}
@ -5485,12 +5506,15 @@ RootObject *TemplateValueParameter::defaultArg(Loc instLoc, Scope *sc)
if (e)
{
e = e->syntaxCopy();
unsigned olderrs = global.errors;
if ((e = expressionSemantic(e, sc)) == NULL)
return NULL;
if ((e = resolveProperties(sc, e)) == NULL)
return NULL;
e = e->resolveLoc(instLoc, sc); // use the instantiated loc
e = e->optimize(WANTvalue);
if (global.errors != olderrs)
e = new ErrorExp();
}
return e;
}
@ -6049,6 +6073,7 @@ bool TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f
if (ta)
{
//printf("type %s\n", ta->toChars());
// It might really be an Expression or an Alias
ta->resolve(loc, sc, &ea, &ta, &sa, (flags & 1) != 0);
if (ea) goto Lexpr;
@ -6270,6 +6295,7 @@ bool TemplateInstance::findBestMatch(Scope *sc, Expressions *fargs)
}
unsigned errs = global.errors;
TemplateDeclaration *td_last = NULL;
struct ParamBest
{
@ -6291,7 +6317,11 @@ bool TemplateInstance::findBestMatch(Scope *sc, Expressions *fargs)
TemplateDeclaration *td = s->isTemplateDeclaration();
if (!td)
return 0;
if (td->inuse)
{
td->error(ti->loc, "recursive template expansion");
return 1;
}
if (td == td_best) // skip duplicates
return 0;
@ -6349,8 +6379,6 @@ bool TemplateInstance::findBestMatch(Scope *sc, Expressions *fargs)
/* Since there can be multiple TemplateDeclaration's with the same
* name, look for the best match.
*/
TemplateDeclaration *td_last = NULL;
OverloadSet *tovers = tempdecl->isOverloadSet();
size_t overs_dim = tovers ? tovers->a.length : 1;
for (size_t oi = 0; oi < overs_dim; oi++)
@ -6359,7 +6387,9 @@ bool TemplateInstance::findBestMatch(Scope *sc, Expressions *fargs)
p.td_best = NULL;
p.td_ambig = NULL;
p.m_best = MATCHnomatch;
overloadApply(tovers ? tovers->a[oi] : tempdecl, &p, &ParamBest::fp);
Dsymbol *dstart = tovers ? tovers->a[oi] : tempdecl;
overloadApply(dstart, &p, &ParamBest::fp);
if (p.td_ambig)
{
@ -6481,8 +6511,11 @@ bool TemplateInstance::needsTypeInference(Scope *sc, int flag)
{
TemplateDeclaration *td = s->isTemplateDeclaration();
if (!td)
{
return 0;
if (td->inuse)
{
td->error(ti->loc, "recursive template expansion");
return 1;
}
/* If any of the overloaded template declarations need inference,
@ -7128,6 +7161,68 @@ void unSpeculative(Scope *sc, RootObject *o)
unSpeculative(sc, ti);
}
/**
Returns: true if the instances' innards are discardable.
The idea of this function is to see if the template instantiation
can be 100% replaced with its eponymous member. All other members
can be discarded, even in the compiler to free memory (for example,
the template could be expanded in a region allocator, deemed trivial,
the end result copied back out independently and the entire region freed),
and can be elided entirely from the binary.
The current implementation affects code that generally looks like:
---
template foo(args...) {
some_basic_type_or_string helper() { .... }
enum foo = helper();
}
---
since it was the easiest starting point of implementation but it can and
should be expanded more later.
*/
static bool isDiscardable(TemplateInstance *ti)
{
if (ti->aliasdecl == NULL)
return false;
VarDeclaration *v = ti->aliasdecl->isVarDeclaration();
if (v == NULL)
return false;
if (!(v->storage_class & STCmanifest))
return false;
// Currently only doing basic types here because it is the easiest proof-of-concept
// implementation with minimal risk of side effects, but it could likely be
// expanded to any type that already exists outside this particular instance.
if (!(v->type->equals(Type::tstring) || (v->type->isTypeBasic() != NULL)))
return false;
// Static ctors and dtors, even in an eponymous enum template, are still run,
// so if any of them are in here, we'd better not assume it is trivial lest
// we break useful code
for (size_t i = 0; i < ti->members->length; i++)
{
Dsymbol *member = (*ti->members)[i];
if (member->hasStaticCtorOrDtor())
return false;
if (member->isStaticDtorDeclaration())
return false;
if (member->isStaticCtorDeclaration())
return false;
}
// but if it passes through this gauntlet... it should be fine. D code will
// see only the eponymous member, outside stuff can never access it, even through
// reflection; the outside world ought to be none the wiser. Even dmd should be
// able to simply free the memory of everything except the final result.
return true;
}
/***********************************************
* Returns true if this is not instantiated in non-root module, and
* is a part of non-speculative instantiatiation.
@ -7137,38 +7232,6 @@ void unSpeculative(Scope *sc, RootObject *o)
*/
bool TemplateInstance::needsCodegen()
{
// Now -allInst is just for the backward compatibility.
if (global.params.allInst)
{
//printf("%s minst = %s, enclosing (%s)->isNonRoot = %d\n",
// toPrettyChars(), minst ? minst->toChars() : NULL,
// enclosing ? enclosing->toPrettyChars() : NULL, enclosing && enclosing->inNonRoot());
if (enclosing)
{
// Bugzilla 14588: If the captured context is not a function
// (e.g. class), the instance layout determination is guaranteed,
// because the semantic/semantic2 pass will be executed
// even for non-root instances.
if (!enclosing->isFuncDeclaration())
return true;
// Bugzilla 14834: If the captured context is a function,
// this excessive instantiation may cause ODR violation, because
// -allInst and others doesn't guarantee the semantic3 execution
// for that function.
// If the enclosing is also an instantiated function,
// we have to rely on the ancestor's needsCodegen() result.
if (TemplateInstance *ti = enclosing->isInstantiated())
return ti->needsCodegen();
// Bugzilla 13415: If and only if the enclosing scope needs codegen,
// this nested templates would also need code generation.
return !enclosing->inNonRoot();
}
return true;
}
if (!minst)
{
// If this is a speculative instantiation,
@ -7185,6 +7248,10 @@ bool TemplateInstance::needsCodegen()
if (tinst && tinst->needsCodegen())
{
minst = tinst->minst; // cache result
if (global.params.allInst && minst)
{
return true;
}
assert(minst);
assert(minst->isRoot() || minst->rootImports());
return true;
@ -7192,6 +7259,10 @@ bool TemplateInstance::needsCodegen()
if (tnext && (tnext->needsCodegen() || tnext->minst))
{
minst = tnext->minst; // cache result
if (global.params.allInst && minst)
{
return true;
}
assert(minst);
return minst->isRoot() || minst->rootImports();
}
@ -7200,6 +7271,16 @@ bool TemplateInstance::needsCodegen()
return false;
}
if (global.params.allInst)
{
return true;
}
if (isDiscardable(this))
{
return false;
}
/* Even when this is reached to the codegen pass,
* a non-root nested template should not generate code,
* due to avoid ODR violation.
@ -7221,14 +7302,7 @@ bool TemplateInstance::needsCodegen()
return false;
}
/* The issue is that if the importee is compiled with a different -debug
* setting than the importer, the importer may believe it exists
* in the compiled importee when it does not, when the instantiation
* is behind a conditional debug declaration.
*/
// workaround for Bugzilla 11239
if (global.params.useUnitTests ||
global.params.debuglevel)
if (global.params.useUnitTests)
{
// Prefer instantiations from root modules, to maximize link-ability.
if (minst->isRoot())

File diff suppressed because it is too large Load diff

View file

@ -883,10 +883,14 @@ public:
/****************************************************************/
class CompileExp : public UnaExp
class CompileExp : public Expression
{
public:
CompileExp(Loc loc, Expression *e);
Expressions *exps;
CompileExp(Loc loc, Expressions *exps);
Expression *syntaxCopy();
bool equals(RootObject *o);
void accept(Visitor *v) { v->visit(this); }
};
@ -1124,7 +1128,6 @@ class ArrayLengthExp : public UnaExp
public:
ArrayLengthExp(Loc loc, Expression *e1);
static Expression *rewriteOpAssign(BinExp *exp);
void accept(Visitor *v) { v->visit(this); }
};

File diff suppressed because it is too large Load diff

View file

@ -1473,7 +1473,8 @@ FuncDeclaration *resolveFuncCall(Loc loc, Scope *sc, Dsymbol *s,
memset(&m, 0, sizeof(m));
m.last = MATCHnomatch;
functionResolve(&m, s, loc, sc, tiargs, tthis, fargs);
const char *failMessage = NULL;
functionResolve(&m, s, loc, sc, tiargs, tthis, fargs, &failMessage);
if (m.last > MATCHnomatch && m.lastf)
{
@ -1555,20 +1556,23 @@ FuncDeclaration *resolveFuncCall(Loc loc, Scope *sc, Dsymbol *s,
::error(loc, "none of the overloads of `%s` are callable using a %sobject, candidates are:",
fd->ident->toChars(), thisBuf.peekChars());
else
::error(loc, "%smethod %s is not callable using a %sobject",
::error(loc, "%smethod `%s` is not callable using a %sobject",
funcBuf.peekChars(), fd->toPrettyChars(), thisBuf.peekChars());
}
else
{
//printf("tf = %s, args = %s\n", tf->deco, (*fargs)[0]->type->deco);
if (hasOverloads)
::error(loc, "none of the overloads of `%s` are callable using argument types %s, candidates are:",
::error(loc, "none of the overloads of `%s` are callable using argument types `%s`, candidates are:",
fd->ident->toChars(), fargsBuf.peekChars());
else
fd->error(loc, "%s%s is not callable using argument types %s",
parametersTypeToChars(tf->parameterList),
tf->modToChars(),
fargsBuf.peekChars());
{
fd->error(loc, "%s `%s%s%s` is not callable using argument types `%s`",
fd->kind(), fd->toPrettyChars(), parametersTypeToChars(tf->parameterList),
tf->modToChars(), fargsBuf.peekChars());
if (failMessage)
errorSupplemental(loc, failMessage);
}
}
// Display candidate functions

View file

@ -122,7 +122,7 @@ public:
void visit(CompileStatement *s)
{
buf->writestring("mixin(");
s->exp->accept(this);
argsToBuffer(s->exps);
buf->writestring(");");
if (!hgs->forStmtInit)
buf->writenl();
@ -1104,6 +1104,18 @@ public:
buf->writestring("typeof(null)");
}
void visit(TypeMixin *t)
{
buf->writestring("mixin(");
argsToBuffer(t->exps);
buf->writeByte(')');
}
void visit(TypeNoreturn *)
{
buf->writestring("noreturn");
}
////////////////////////////////////////////////////////////////////////////
void visit(Dsymbol *s)
@ -1418,7 +1430,7 @@ public:
void visit(CompileDeclaration *d)
{
buf->writestring("mixin(");
d->exp->accept(this);
argsToBuffer(d->exps);
buf->writestring(");");
buf->writenl();
}
@ -2408,8 +2420,15 @@ public:
buf->writeByte(')');
if (target.ptrsize == 8)
goto L4;
else
else if (target.ptrsize == 4 ||
target.ptrsize == 2)
goto L3;
else
assert(0);
case Tvoid:
buf->writestring("cast(void)0");
break;
default:
/* This can happen if errors, such as
@ -2822,7 +2841,7 @@ public:
void visit(CompileExp *e)
{
buf->writestring("mixin(");
expToBuffer(e->e1, PREC_assign);
argsToBuffer(e->exps);
buf->writeByte(')');
}
@ -3528,6 +3547,13 @@ void arrayObjectsToBuffer(OutBuffer *buf, Objects *objects)
}
}
/*************************************************************
* Pretty print function parameters.
* Params:
* parameters = parameters to print, such as TypeFunction.parameters.
* varargs = kind of varargs, see TypeFunction.varargs.
* Returns: Null-terminated string representing parameters.
*/
const char *parametersTypeToChars(ParameterList pl)
{
OutBuffer buf;
@ -3536,3 +3562,26 @@ const char *parametersTypeToChars(ParameterList pl)
v.parametersToBuffer(pl.parameters, pl.varargs);
return buf.extractChars();
}
/*************************************************************
* Pretty print function parameter.
* Params:
* parameter = parameter to print.
* tf = TypeFunction which holds parameter.
* fullQual = whether to fully qualify types.
* Returns: Null-terminated string representing parameters.
*/
const char *parameterToChars(Parameter *parameter, TypeFunction *tf, bool fullQual)
{
OutBuffer buf;
HdrGenState hgs;
hgs.fullQual = fullQual;
PrettyPrintVisitor v(&buf, &hgs);
parameter->accept(&v);
if (tf->parameterList.varargs == 2 && parameter == tf->parameterList[tf->parameterList.parameters->length - 1])
{
buf.writestring("...");
}
return buf.extractChars();
}

View file

@ -47,6 +47,7 @@ void arrayObjectsToBuffer(OutBuffer *buf, Objects *objects);
void moduleToBuffer(OutBuffer *buf, Module *m);
const char *parametersTypeToChars(ParameterList pl);
const char *parameterToChars(Parameter *parameter, TypeFunction *tf, bool fullQual);
bool stcToBuffer(OutBuffer *buf, StorageClass stc);
const char *stcToChars(StorageClass& stc);

View file

@ -86,10 +86,16 @@ Msgtable msgtable[] =
{ "__c_longlong", NULL },
{ "__c_ulonglong", NULL },
{ "__c_long_double", NULL },
{ "__c_wchar_t", NULL },
{ "__c_complex_float", NULL },
{ "__c_complex_double", NULL },
{ "__c_complex_real", NULL },
{ "cpp_type_info_ptr", "__cpp_type_info_ptr" },
{ "_assert", "assert" },
{ "_unittest", "unittest" },
{ "_body", "body" },
{ "printf", NULL },
{ "scanf", NULL },
{ "TypeInfo", NULL },
{ "TypeInfo_Class", NULL },
@ -395,7 +401,6 @@ Msgtable msgtable[] =
{ "derivedMembers", NULL },
{ "isSame", NULL },
{ "compiles", NULL },
{ "parameters", NULL },
{ "getAliasThis", NULL },
{ "getAttributes", NULL },
{ "getFunctionAttributes", NULL },
@ -411,6 +416,7 @@ Msgtable msgtable[] =
{ "getLocation", NULL },
{ "hasPostblit", NULL },
{ "isCopyable", NULL },
{ "toType", NULL },
// For C++ mangling
{ "allocator", NULL },

View file

@ -47,6 +47,7 @@ public:
Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees
void load(Scope *sc);
void importAll(Scope *sc);
void addPackageAccess(ScopeDsymbol *scopesym);
Dsymbol *toAlias();
void addMember(Scope *sc, ScopeDsymbol *sds);
void setScope(Scope* sc);

View file

@ -75,6 +75,7 @@ public:
unsigned numlines; // number of lines in source file
int isDocFile; // if it is a documentation input file, not D source
bool isPackageFile; // if it is a package.d
Package *pkg; // if isPackageFile is true, the Package that contains this package.d
Strings contentImportedFiles; // array of files whose content was imported
int needmoduleinfo;

View file

@ -39,6 +39,7 @@ Expression *extractSideEffect(Scope *sc, const char *name, Expression **e0, Expr
Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
Expression *typeToExpression(Type *t);
Expression *typeToExpressionHelper(TypeQualified *t, Expression *e, size_t i = 0);
RootObject *compileTypeMixin(TypeMixin *tm, Loc loc, Scope *sc);
/***************************** Type *****************************/
@ -93,6 +94,7 @@ Type *Type::tdchar;
Type *Type::tshiftcnt;
Type *Type::terror;
Type *Type::tnull;
Type *Type::tnoreturn;
Type *Type::tsize_t;
Type *Type::tptrdiff_t;
@ -195,6 +197,8 @@ void Type::_init()
sizeTy[Tnull] = sizeof(TypeNull);
sizeTy[Tvector] = sizeof(TypeVector);
sizeTy[Ttraits] = sizeof(TypeTraits);
sizeTy[Tmixin] = sizeof(TypeMixin);
sizeTy[Tnoreturn] = sizeof(TypeNoreturn);
initTypeMangle();
@ -216,6 +220,10 @@ void Type::_init()
}
basic[Terror] = new TypeError();
tnoreturn = new TypeNoreturn();
tnoreturn->deco = tnoreturn->merge()->deco;
basic[Tnoreturn] = tnoreturn;
tvoid = basic[Tvoid];
tint8 = basic[Tint8];
tuns8 = basic[Tuns8];
@ -246,7 +254,7 @@ void Type::_init()
tshiftcnt = tint32;
terror = basic[Terror];
tnull = basic[Tnull];
tnoreturn = basic[Tnoreturn];
tnull = new TypeNull();
tnull->deco = tnull->merge()->deco;
@ -2079,7 +2087,7 @@ Expression *Type::getProperty(Loc loc, Identifier *ident, int flag)
if (this != Type::terror)
{
if (s)
error(loc, "no property `%s` for type `%s`, did you mean `%s`?", ident->toChars(), toChars(), s->toChars());
error(loc, "no property `%s` for type `%s`, did you mean `%s`?", ident->toChars(), toChars(), s->toPrettyChars());
else
error(loc, "no property `%s` for type `%s`", ident->toChars(), toChars());
}
@ -2413,6 +2421,16 @@ TypeTraits *Type::isTypeTraits()
return ty == Ttraits ? (TypeTraits *)this : NULL;
}
TypeMixin *Type::isTypeMixin()
{
return ty == Tmixin ? (TypeMixin *)this : NULL;
}
TypeNoreturn *Type::isTypeNoreturn()
{
return ty == Tnoreturn ? (TypeNoreturn *)this : NULL;
}
TypeFunction *Type::toTypeFunction()
{
if (ty != Tfunction)
@ -5175,16 +5193,47 @@ void TypeFunction::purityLevel()
tf->purity = purity;
}
// arguments get specially formatted
static const char *getParamError(TypeFunction *tf, Expression *arg, Parameter *par)
{
if (global.gag && !global.params.showGaggedErrors)
return NULL;
// show qualification when toChars() is the same but types are different
const char *at = arg->type->toChars();
bool qual = !arg->type->equals(par->type) && strcmp(at, par->type->toChars()) == 0;
if (qual)
at = arg->type->toPrettyChars(true);
OutBuffer buf;
// only mention rvalue if it's relevant
const bool rv = !arg->isLvalue() && (par->storageClass & (STCref | STCout)) != 0;
buf.printf("cannot pass %sargument `%s` of type `%s` to parameter `%s`",
rv ? "rvalue " : "", arg->toChars(), at,
parameterToChars(par, tf, qual));
return buf.extractChars();
}
static const char *getMatchError(const char *format, ...)
{
if (global.gag && !global.params.showGaggedErrors)
return NULL;
OutBuffer buf;
va_list ap;
va_start(ap, format);
buf.vprintf(format, ap);
return buf.extractChars();
}
/********************************
* 'args' are being matched to function 'this'
* Determine match level.
* Input:
* flag 1 performing a partial ordering match
* pMessage address to store error message, or null
* Returns:
* MATCHxxxx
*/
MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag)
MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag, const char **pMessage)
{
//printf("TypeFunction::callMatch() %s\n", toChars());
MATCH match = MATCHexact; // assume exact match
@ -5221,12 +5270,15 @@ MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag)
size_t nparams = parameterList.length();
size_t nargs = args ? args->length : 0;
if (nparams == nargs)
;
else if (nargs > nparams)
if (nargs > nparams)
{
if (parameterList.varargs == VARARGnone)
goto Nomatch; // too many args; no match
{
// suppress early exit if an error message is wanted,
// so we can check any matching args are valid
if (!pMessage)
goto Nomatch; // too many args; no match
}
match = MATCHconvert; // match ... with a "conversion" match level
}
@ -5309,7 +5361,10 @@ MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag)
if (m && !arg->isLvalue())
{
if (p->storageClass & STCout)
{
if (pMessage) *pMessage = getParamError(this, arg, p);
goto Nomatch;
}
if (arg->op == TOKstring && tp->ty == Tsarray)
{
@ -5331,7 +5386,10 @@ MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag)
}
}
else
{
if (pMessage) *pMessage = getParamError(this, arg, p);
goto Nomatch;
}
}
/* Find most derived alias this type being matched.
@ -5351,7 +5409,10 @@ MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag)
* ref T[dim] <- an lvalue of const(T[dim]) argument
*/
if (!ta->constConv(tp))
{
if (pMessage) *pMessage = getParamError(this, arg, p);
goto Nomatch;
}
}
}
@ -5377,7 +5438,11 @@ MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag)
tsa = (TypeSArray *)tb;
sz = tsa->dim->toInteger();
if (sz != nargs - u)
{
if (pMessage)
*pMessage = getMatchError("expected %llu variadic argument(s), not %zu", sz, nargs - u);
goto Nomatch;
}
/* fall through */
case Tarray:
{
@ -5408,7 +5473,10 @@ MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag)
m = arg->implicitConvTo(ta->next);
if (m == MATCHnomatch)
{
if (pMessage) *pMessage = getParamError(this, arg, p);
goto Nomatch;
}
if (m < match)
match = m;
}
@ -5420,9 +5488,14 @@ MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag)
goto Ldone;
default:
goto Nomatch;
break;
}
}
if (pMessage && u < nargs)
*pMessage = getParamError(this, (*args)[u], p);
else if (pMessage)
*pMessage = getMatchError("missing argument for parameter #%d: `%s`",
u + 1, parameterToChars(p, this, false));
goto Nomatch;
}
if (m < match)
@ -5430,6 +5503,12 @@ MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag)
}
Ldone:
if (pMessage && !parameterList.varargs && nargs > nparams)
{
// all parameters had a match, but there are surplus args
*pMessage = getMatchError("expected %d argument(s), not %d", nparams, nargs);
goto Nomatch;
}
//printf("match = %d\n", match);
return match;
@ -5797,6 +5876,20 @@ Type *TypeTraits::syntaxCopy()
return tt;
}
Dsymbol *TypeTraits::toDsymbol(Scope *sc)
{
Type *t = NULL;
Expression *e = NULL;
Dsymbol *s = NULL;
resolve(loc, sc, &e, &t, &s);
if (t && t->ty != Terror)
s = t->toDsymbol(sc);
else if (e)
s = getDsymbol(e);
return s;
}
void TypeTraits::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool)
{
*pt = NULL;
@ -5816,6 +5909,90 @@ d_uns64 TypeTraits::size(Loc)
return SIZE_INVALID;
}
/***************************** TypeMixin *****************************/
/******
* Implements mixin types.
*
* Semantic analysis will convert it to a real type.
*/
TypeMixin::TypeMixin(const Loc &loc, Expressions *exps)
: Type(Tmixin)
{
this->loc = loc;
this->exps = exps;
this->obj = NULL; // cached result of semantic analysis.
}
const char *TypeMixin::kind()
{
return "mixin";
}
Type *TypeMixin::syntaxCopy()
{
return new TypeMixin(loc, Expression::arraySyntaxCopy(exps));
}
Dsymbol *TypeMixin::toDsymbol(Scope *sc)
{
Type *t = NULL;
Expression *e = NULL;
Dsymbol *s = NULL;
resolve(loc, sc, &e, &t, &s);
if (t)
s = t->toDsymbol(sc);
else if (e)
s = getDsymbol(e);
return s;
}
void TypeMixin::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
{
// if already resolved just set pe/pt/ps and return.
if (obj)
{
*pe = isExpression(obj);
*pt = isType(obj);
*ps = isDsymbol(obj);
return;
}
RootObject *o = compileTypeMixin(this, loc, sc);
if (Type *t = isType(o))
{
t->resolve(loc, sc, pe, pt, ps, intypeid);
if (*pt)
(*pt) = (*pt)->addMod(mod);
}
else if (Expression *e = isExpression(o))
{
e = expressionSemantic(e, sc);
if (TypeExp *et = e->isTypeExp())
{
*pe = NULL;
*pt = et->type->addMod(mod);
*ps = NULL;
}
else
{
*pe = e;
*pt = NULL;
*ps = NULL;
}
}
else
{
*pe = NULL;
*pt = Type::terror;
*ps = NULL;
}
// save the result
obj = *pe ? (RootObject *)*pe : (*pt ? (RootObject *)*pt : (RootObject *)*ps);
}
/***************************** TypeQualified *****************************/
TypeQualified::TypeQualified(TY ty, Loc loc)
@ -6003,11 +6180,25 @@ void TypeQualified::resolveHelper(Loc loc, Scope *sc,
Type *t = s->getType(); // type symbol, type alias, or type tuple?
unsigned errorsave = global.errors;
Dsymbol *sm = s->searchX(loc, sc, id);
if (sm && !(sc->flags & SCOPEignoresymbolvisibility) && !symbolIsVisible(sc, sm))
int flags = t == NULL ? SearchLocalsOnly : IgnorePrivateImports;
Dsymbol *sm = s->searchX(loc, sc, id, flags);
if (sm)
{
::error(loc, "`%s` is not visible from module `%s`", sm->toPrettyChars(), sc->_module->toChars());
sm = NULL;
if (!(sc->flags & SCOPEignoresymbolvisibility) && !symbolIsVisible(sc, sm))
{
::error(loc, "`%s` is not visible from module `%s`", sm->toPrettyChars(), sc->_module->toChars());
sm = NULL;
}
// Same check as in Expression::semanticY(DotIdExp)
else if (sm->isPackage() && checkAccess(sc, (Package *)sm))
{
// @@@DEPRECATED_2.096@@@
// Should be an error in 2.106. Just remove the deprecation call
// and uncomment the null assignment
::deprecation(loc, "%s %s is not accessible here, perhaps add 'static import %s;'",
sm->kind(), sm->toPrettyChars(), sm->toPrettyChars());
//sm = null;
}
}
if (global.errors != errorsave)
{
@ -6052,7 +6243,7 @@ void TypeQualified::resolveHelper(Loc loc, Scope *sc,
sm = t->toDsymbol(sc);
if (sm && id->dyncast() == DYNCAST_IDENTIFIER)
{
sm = sm->search(loc, (Identifier *)id);
sm = sm->search(loc, (Identifier *)id, IgnorePrivateImports);
if (sm)
goto L2;
}
@ -8177,6 +8368,49 @@ Expression *TypeNull::defaultInit(Loc)
return new NullExp(Loc(), Type::tnull);
}
/***************************** TypeNoreturn *****************************/
TypeNoreturn::TypeNoreturn()
: Type(Tnoreturn)
{
//printf("TypeNoreturn %p\n", this);
}
const char *TypeNoreturn::kind()
{
return "noreturn";
}
Type *TypeNoreturn::syntaxCopy()
{
// No semantic analysis done, no need to copy
return this;
}
MATCH TypeNoreturn::implicitConvTo(Type *to)
{
//printf("TypeNoreturn::implicitConvTo(this=%p, to=%p)\n", this, to);
//printf("from: %s\n", toChars());
//printf("to : %s\n", to.toChars());
MATCH m = Type::implicitConvTo(to);
return (m == MATCHexact) ? MATCHexact : MATCHconvert;
}
bool TypeNoreturn::isBoolean()
{
return true; // bottom type can be implicitly converted to any other type
}
d_uns64 TypeNoreturn::size(Loc)
{
return 0;
}
unsigned TypeNoreturn::alignsize()
{
return 0;
}
/***********************************************************
* Encapsulate Parameters* so .length and [i] can be used on it.
* https://dlang.org/spec/function.html#ParameterList
@ -8472,3 +8706,25 @@ bool Parameter::isCovariantScope(bool returnByRef, StorageClass from, StorageCla
return covariant[SR::buildSR(returnByRef, from)][SR::buildSR(returnByRef, to)];
}
/**
* For printing two types with qualification when necessary.
* Params:
* t1 = The first type to receive the type name for
* t2 = The second type to receive the type name for
* Returns:
* The fully-qualified names of both types if the two type names are not the same,
* or the unqualified names of both types if the two type names are the same.
*/
void toAutoQualChars(const char **result, Type *t1, Type *t2)
{
const char *s1 = t1->toChars();
const char *s2 = t2->toChars();
if (strcmp(s1, s2) == 0)
{
s1 = t1->toPrettyChars(true);
s2 = t2->toPrettyChars(true);
}
result[0] = s1;
result[1] = s2;
}

View file

@ -96,6 +96,8 @@ enum ENUMTY
Tint128,
Tuns128,
Ttraits,
Tmixin,
Tnoreturn,
TMAX
};
typedef unsigned char TY; // ENUMTY
@ -201,6 +203,7 @@ public:
static Type *tdstring; // immutable(dchar)[]
static Type *terror; // for error recovery
static Type *tnull; // for null type
static Type *tnoreturn; // for bottom type typeof(*null)
static Type *tsize_t; // matches size_t alias
static Type *tptrdiff_t; // matches ptrdiff_t alias
@ -367,7 +370,9 @@ public:
TypeTuple *isTypeTuple();
TypeSlice *isTypeSlice();
TypeNull *isTypeNull();
TypeMixin *isTypeMixin();
TypeTraits *isTypeTraits();
TypeNoreturn *isTypeNoreturn();
void accept(Visitor *v) { v->visit(this); }
};
@ -686,7 +691,7 @@ public:
int attributesApply(void *param, int (*fp)(void *, const char *), TRUSTformat trustFormat = TRUSTformatDefault);
Type *substWildTo(unsigned mod);
MATCH callMatch(Type *tthis, Expressions *toargs, int flag = 0);
MATCH callMatch(Type *tthis, Expressions *toargs, int flag = 0, const char **pMessage = NULL);
bool checkRetType(Loc loc);
Expression *defaultInit(Loc loc) /*const*/;
@ -726,11 +731,27 @@ public:
TypeTraits(const Loc &loc, TraitsExp *exp);
Type *syntaxCopy();
Dsymbol *toDsymbol(Scope *sc);
void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
d_uns64 size(Loc loc);
void accept(Visitor *v) { v->visit(this); }
};
class TypeMixin : public Type
{
public:
Loc loc;
Expressions *exps;
RootObject *obj;
TypeMixin(const Loc &loc, Expressions *exps);
const char *kind();
Type *syntaxCopy();
Dsymbol *toDsymbol(Scope *sc);
void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
void accept(Visitor *v) { v->visit(this); }
};
class TypeQualified : public Type
{
public:
@ -966,6 +987,21 @@ public:
void accept(Visitor *v) { v->visit(this); }
};
class TypeNoreturn : public Type
{
public:
TypeNoreturn();
const char *kind();
Type *syntaxCopy();
MATCH implicitConvTo(Type *to);
bool isBoolean() /*const*/;
d_uns64 size(Loc loc) /*const*/;
unsigned alignsize();
void accept(Visitor *v) { v->visit(this); }
};
/**************************************************************/
bool arrayTypeCompatible(Loc loc, Type *t1, Type *t2);

View file

@ -328,11 +328,9 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl, PrefixAttributes
{
// mixin(string)
nextToken();
check(TOKlparen, "mixin");
Expression *e = parseAssignExp();
check(TOKrparen);
Expressions *exps = parseArguments();
check(TOKsemicolon);
s = new CompileDeclaration(loc, e);
s = new CompileDeclaration(loc, exps);
break;
}
case TOKtemplate:
@ -1336,7 +1334,7 @@ LINK Parser::parseLinkage(Identifiers **pidents, CPPMANGLE *pcppmangle, bool *pc
}
else if (!Identifier::isValidIdentifier(name))
{
error("expected valid identifer for C++ namespace but got `%s`", name);
error("expected valid identifier for C++ namespace but got `%s`", name);
idents = NULL;
break;
}
@ -2922,6 +2920,18 @@ Objects *Parser::parseTemplateArguments()
return tiargs;
}
/***************************************
* Parse a Type or an Expression
* Returns:
* RootObject representing the AST
*/
RootObject *Parser::parseTypeOrAssignExp(TOK endtoken)
{
return isDeclaration(&token, 0, endtoken, NULL)
? (RootObject *)parseType() // argument is a type
: (RootObject *)parseAssignExp(); // argument is an expression
}
/******************************************
* Parse template argument list.
* Input:
@ -2942,20 +2952,10 @@ Objects *Parser::parseTemplateArgumentList()
// Get TemplateArgumentList
while (token.value != endtok)
{
// See if it is an Expression or a Type
if (isDeclaration(&token, 0, TOKreserved, NULL))
{ // Template argument is a type
Type *ta = parseType();
tiargs->push(ta);
}
else
{ // Template argument is an expression
Expression *ea = parseAssignExp();
tiargs->push(ea);
}
if (token.value != TOKcomma)
break;
nextToken();
tiargs->push(parseTypeOrAssignExp());
if (token.value != TOKcomma)
break;
nextToken();
}
check(endtok, "template argument list");
return tiargs;
@ -3288,6 +3288,15 @@ Type *Parser::parseBasicType(bool dontLookDotIdents)
}
break;
case TOKmixin:
// https://dlang.org/spec/expression.html#mixin_types
loc = token.loc;
nextToken();
if (token.value != TOKlparen)
error("found `%s` when expecting `%s` following %s", token.toChars(), Token::toChars(TOKlparen), "`mixin`");
t = new TypeMixin(loc, parseArguments());
break;
case TOKdot:
// Leading . as in .foo
t = parseBasicTypeStartingAt(new TypeIdentifier(token.loc, Id::empty), dontLookDotIdents);
@ -3602,7 +3611,7 @@ Type *Parser::parseDeclarator(Type *t, int *palt, Identifier **pident,
if (pident)
*pident = token.ident;
else
error("unexpected identifer `%s` in declarator", token.ident->toChars());
error("unexpected identifier `%s` in declarator", token.ident->toChars());
ts = t;
nextToken();
break;
@ -3863,6 +3872,21 @@ void Parser::parseStorageClasses(StorageClass &storage_class, LINK &link,
}
}
static void parseAttributes(Parser *p, bool &hasParsedAttributes,
StorageClass &storage_class, LINK &link, bool &setAlignment,
Expression *&ealign, Expressions *&udas)
{
if (hasParsedAttributes) // only parse once
return;
hasParsedAttributes = true;
udas = NULL;
storage_class = STCundefined;
link = p->linkage;
setAlignment = false;
ealign = NULL;
p->parseStorageClasses(storage_class, link, setAlignment, ealign, udas);
}
/**********************************
* Parse Declarations.
* These can be:
@ -3936,26 +3960,48 @@ Dsymbols *Parser::parseDeclarations(bool autodecl, PrefixAttributes *pAttrs, con
bool hasParsedAttributes = false;
if (token.value == TOKat)
{
if (!hasParsedAttributes)
{
hasParsedAttributes = true;
storage_class = STCundefined;
link = linkage;
setAlignment = false;
ealign = NULL;
udas = NULL;
parseStorageClasses(storage_class, link, setAlignment, ealign, udas);
}
parseAttributes(this, hasParsedAttributes,
storage_class, link, setAlignment, ealign, udas);
}
Declaration *v;
if (token.value == TOKfunction ||
Dsymbol *s;
// try to parse function type:
// TypeCtors? BasicType ( Parameters ) MemberFunctionAttributes
bool attributesAppended = false;
const StorageClass funcStc = parseTypeCtor();
Token *tlu = &token;
if (token.value != TOKfunction &&
token.value != TOKdelegate &&
isBasicType(&tlu) && tlu &&
tlu->value == TOKlparen)
{
VarArg vargs;
Type *tret = parseBasicType();
Parameters *prms = parseParameters(&vargs);
ParameterList pl = ParameterList(prms, vargs);
parseAttributes(this, hasParsedAttributes,
storage_class, link, setAlignment, ealign, udas);
if (udas)
error("user-defined attributes not allowed for `alias` declarations");
attributesAppended = true;
storage_class = appendStorageClass(storage_class, funcStc);
Type *tf = new TypeFunction(pl, tret, link, storage_class);
v = new AliasDeclaration(loc, ident, tf);
}
else if (token.value == TOKfunction ||
token.value == TOKdelegate ||
(token.value == TOKlparen &&
skipAttributes(peekPastParen(&token), &tk) &&
(tk->value == TOKgoesto || tk->value == TOKlcurly)) ||
token.value == TOKlcurly ||
(token.value == TOKidentifier && peekNext() == TOKgoesto))
(token.value == TOKidentifier && peekNext() == TOKgoesto) ||
(token.value == TOKref && peekNext() == TOKlparen &&
skipAttributes(peekPastParen(peek(&token)), &tk) &&
(tk->value == TOKgoesto || tk->value == TOKlcurly)))
{
// function (parameters) { statements... }
// delegate (parameters) { statements... }
@ -3963,8 +4009,10 @@ Dsymbols *Parser::parseDeclarations(bool autodecl, PrefixAttributes *pAttrs, con
// (parameters) => expression
// { statements... }
// identifier => expression
// ref (parameters) { statements... }
// ref (parameters) => expression
Dsymbol *s = parseFunctionLiteral();
s = parseFunctionLiteral();
if (udas != NULL)
{
@ -3985,26 +4033,19 @@ Dsymbols *Parser::parseDeclarations(bool autodecl, PrefixAttributes *pAttrs, con
else
{
// StorageClasses type
if (!hasParsedAttributes)
{
hasParsedAttributes = true;
storage_class = STCundefined;
link = linkage;
setAlignment = false;
ealign = NULL;
udas = NULL;
parseStorageClasses(storage_class, link, setAlignment, ealign, udas);
}
parseAttributes(this, hasParsedAttributes,
storage_class, link, setAlignment, ealign, udas);
if (udas)
error("user-defined attributes not allowed for %s declarations", Token::toChars(tok));
t = parseType();
v = new AliasDeclaration(loc, ident, t);
}
if (!attributesAppended)
storage_class = appendStorageClass(storage_class, funcStc);
v->storage_class = storage_class;
Dsymbol *s = v;
s = v;
if (tpl)
{
Dsymbols *a2 = new Dsymbols();
@ -4358,6 +4399,13 @@ Dsymbol *Parser::parseFunctionLiteral()
case TOKdelegate:
save = token.value;
nextToken();
if (token.value == TOKref)
{
// function ref (parameters) { statements... }
// delegate ref (parameters) { statements... }
stc = STCref;
nextToken();
}
if (token.value != TOKlparen && token.value != TOKlcurly)
{
// function type (parameters) { statements... }
@ -4377,14 +4425,22 @@ Dsymbol *Parser::parseFunctionLiteral()
// delegate { statements... }
break;
}
/* fall through */
goto LTOKlparen;
case TOKref:
// ref (parameters) => expression
// ref (parameters) { statements... }
stc = STCref;
nextToken();
goto LTOKlparen;
case TOKlparen:
LTOKlparen:
{
// (parameters) => expression
// (parameters) { statements... }
parameters = parseParameters(&varargs, &tpl);
stc = parsePostfix(STCundefined, NULL);
stc = parsePostfix(stc, NULL);
if (StorageClass modStc = stc & STC_TYPECTOR)
{
if (save == TOKfunction)
@ -5093,7 +5149,7 @@ Statement *Parser::parseForeach(Loc loc, bool *isRange, bool isDecl)
check(TOKrparen);
Loc endloc;
Statement *body = (!isDecl) ? parseStatement(0, NULL, &endloc) : NULL;
if (isRange)
if (isRange)
*isRange = false;
return new ForeachStatement(loc, op, parameters, aggr, body, endloc);
}
@ -5378,15 +5434,19 @@ Statement *Parser::parseStatement(int flags, const utf8_t** endPtr, Loc *pEndloc
}
case TOKmixin:
{ Token *t = peek(&token);
{
if (isDeclaration(&token, 3, TOKreserved, NULL))
goto Ldeclaration;
Token *t = peek(&token);
if (t->value == TOKlparen)
{ // mixin(string)
{
// mixin(string)
Expression *e = parseAssignExp();
check(TOKsemicolon);
if (e->op == TOKmixin)
{
CompileExp *cpe = (CompileExp *)e;
s = new CompileStatement(loc, cpe->e1);
s = new CompileStatement(loc, cpe->exps);
}
else
{
@ -6332,6 +6392,7 @@ bool Parser::isBasicType(Token **pt)
case TOKtypeof:
case TOKvector:
case TOKmixin:
/* typeof(exp).identifier...
*/
t = peek(t);
@ -6592,9 +6653,11 @@ bool Parser::isDeclarator(Token **pt, int *haveId, int *haveTpl, TOK endtok, boo
case TOKin:
case TOKout:
case TOKdo:
LTOKdo:
// The !parens is to disallow unnecessary parentheses
if (!parens && (endtok == TOKreserved || endtok == t->value))
{ *pt = t;
{
*pt = t;
return true;
}
return false;
@ -6602,6 +6665,12 @@ bool Parser::isDeclarator(Token **pt, int *haveId, int *haveTpl, TOK endtok, boo
case TOKif:
return haveTpl ? true : false;
// Used for mixin type parsing
case TOKeof:
if (endtok == TOKeof)
goto LTOKdo;
return false;
default:
Ldefault:
return false;
@ -7229,15 +7298,7 @@ Expression *Parser::parsePrimaryExp()
{
nextToken();
check(TOKlparen, "typeid");
RootObject *o;
if (isDeclaration(&token, 0, TOKreserved, NULL))
{ // argument is a type
o = parseType();
}
else
{ // argument is an expression
o = parseAssignExp();
}
RootObject *o = parseTypeOrAssignExp();
check(TOKrparen);
e = new TypeidExp(loc, o);
break;
@ -7279,6 +7340,14 @@ Expression *Parser::parsePrimaryExp()
if (token.value == TOKlparen)
{
nextToken();
if (token.value == TOKidentifier && peekNext() == TOKlparen)
{
error(loc, "unexpected `(` after `%s`, inside `is` expression. Try enclosing the contents of `is` with a `typeof` expression", token.toChars());
nextToken();
Token *tempTok = peekPastParen(&token);
memcpy(&token, tempTok, sizeof(Token));
goto Lerr;
}
targ = parseType(&ident);
if (token.value == TOKcolon || token.value == TOKequal)
{
@ -7357,11 +7426,11 @@ Expression *Parser::parsePrimaryExp()
case TOKmixin:
{
// https://dlang.org/spec/expression.html#mixin_expressions
nextToken();
check(TOKlparen, "mixin");
e = parseAssignExp();
check(TOKrparen);
e = new CompileExp(loc, e);
if (token.value != TOKlparen)
error("found `%s` when expecting `%s` following %s", token.toChars(), Token::toChars(TOKlparen), "`mixin`");
e = new CompileExp(loc, parseArguments());
break;
}
@ -7379,6 +7448,24 @@ Expression *Parser::parsePrimaryExp()
e = parseNewExp(NULL);
break;
case TOKref:
{
if (peekNext() == TOKlparen)
{
Token *tk = peekPastParen(peek(&token));
if (skipAttributes(tk, &tk) &&
(tk->value == TOKgoesto || tk->value == TOKlcurly))
{
// ref (arguments) => expression
// ref (arguments) { statements... }
goto case_delegate;
}
}
nextToken();
error("found `%s` when expecting function literal following `ref`", token.toChars());
goto Lerr;
}
case TOKlparen:
{
Token *tk = peekPastParen(&token);

View file

@ -83,6 +83,7 @@ public:
TemplateParameters *parseTemplateParameterList(int flag = 0);
Dsymbol *parseMixin();
Objects *parseTemplateArguments();
RootObject *parseTypeOrAssignExp(TOK endtoken = TOKreserved);
Objects *parseTemplateArgumentList();
Objects *parseTemplateSingleArgument();
StaticAssert *parseStaticAssert();

View file

@ -66,6 +66,10 @@ enum PINLINE;
#define SCOPEfullinst 0x10000 // fully instantiate templates
#define SCOPEalias 0x20000 // inside alias declaration
// The following are mutually exclusive
#define SCOPEprintf 0x40000 // printf-style function
#define SCOPEscanf 0x80000 // scanf-style function
struct Scope
{
Scope *enclosing; // enclosing Scope

View file

@ -163,6 +163,15 @@ public:
if (vd->_init && !vd->toParent()->isFuncDeclaration())
{
vd->inuse++;
/* https://issues.dlang.org/show_bug.cgi?id=20280
*
* Template instances may import modules that have not
* finished semantic1.
*/
if (!vd->type)
dsymbolSemantic(vd, sc);
// Bugzilla 14166: Don't run CTFE for the temporary variables inside typeof
vd->_init = initializerSemantic(vd->_init, sc, vd->type, sc->intypeof == 1 ? INITnointerpret : INITinterpret);
vd->inuse--;
@ -265,6 +274,17 @@ public:
{
if (fd->semanticRun >= PASSsemantic2done)
return;
if (fd->semanticRun < PASSsemanticdone && !fd->errors)
{
/* https://issues.dlang.org/show_bug.cgi?id=21614
*
* Template instances may import modules that have not
* finished semantic1.
*/
dsymbolSemantic(fd, sc);
}
assert(fd->semanticRun <= PASSsemantic2);
fd->semanticRun = PASSsemantic2;

View file

@ -850,32 +850,18 @@ public:
}
assert(!funcdecl->returnLabel);
}
else if (f->next->ty == Tnoreturn)
{
}
else
{
const bool inlineAsm = (funcdecl->hasReturnExp & 8) != 0;
if ((blockexit & BEfallthru) && f->next->ty != Tvoid && !inlineAsm)
{
Expression *e;
if (!funcdecl->hasReturnExp)
funcdecl->error("has no return statement, but is expected to return a value of type %s", f->next->toChars());
funcdecl->error("has no `return` statement, but is expected to return a value of type `%s`", f->next->toChars());
else
funcdecl->error("no return exp; or assert(0); at end of function");
if (global.params.useAssert == CHECKENABLEon &&
!global.params.useInline)
{
/* Add an assert(0, msg); where the missing return
* should be.
*/
e = new AssertExp(funcdecl->endloc,
new IntegerExp(0),
new StringExp(funcdecl->loc, const_cast<char *>("missing return expression")));
}
else
e = new HaltExp(funcdecl->endloc);
e = new CommaExp(Loc(), e, f->next->defaultInit());
e = expressionSemantic(e, sc2);
Statement *s = new ExpStatement(Loc(), e);
funcdecl->fbody = new CompoundStatement(Loc(), funcdecl->fbody, s);
funcdecl->error("no `return exp;` or `assert(0);` at end of function");
}
}
@ -1162,15 +1148,7 @@ public:
if (cd)
{
if (!global.params.is64bit &&
global.params.isWindows &&
!funcdecl->isStatic() && !sbody->usesEH() && !global.params.trace)
{
/* The back end uses the "jmonitor" hack for syncing;
* no need to do the sync at this level.
*/
}
else
if (target.libraryObjectMonitors(funcdecl, sbody))
{
Expression *vsync;
if (funcdecl->isStatic())

View file

@ -31,6 +31,7 @@ StorageClass mergeFuncAttrs(StorageClass s1, FuncDeclaration *f);
bool checkEscapeRef(Scope *sc, Expression *e, bool gag);
VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e);
Statement *makeTupleForeachStatic(Scope *sc, ForeachStatement *fs, bool needExpansion);
bool expressionsToString(OutBuffer &buf, Scope *sc, Expressions *exps);
Identifier *fixupLabelName(Scope *sc, Identifier *ident)
{
@ -504,12 +505,19 @@ Statement *DtorExpStatement::syntaxCopy()
CompileStatement::CompileStatement(Loc loc, Expression *exp)
: Statement(loc)
{
this->exp = exp;
this->exps = new Expressions();
this->exps->push(exp);
}
CompileStatement::CompileStatement(Loc loc, Expressions *exps)
: Statement(loc)
{
this->exps = exps;
}
Statement *CompileStatement::syntaxCopy()
{
return new CompileStatement(loc, exp->syntaxCopy());
return new CompileStatement(loc, Expression::arraySyntaxCopy(exps));
}
static Statements *errorStatements()
@ -519,32 +527,36 @@ static Statements *errorStatements()
return a;
}
Statements *CompileStatement::flatten(Scope *sc)
static Statements *compileIt(CompileStatement *cs, Scope *sc)
{
//printf("CompileStatement::flatten() %s\n", exp->toChars());
StringExp *se = semanticString(sc, exp, "argument to mixin");
if (!se)
//printf("CompileStatement::compileIt() %s\n", exp->toChars());
OutBuffer buf;
if (expressionsToString(buf, sc, cs->exps))
return errorStatements();
se = se->toUTF8(sc);
unsigned errors = global.errors;
Parser p(loc, sc->_module, (utf8_t *)se->string, se->len, 0);
const size_t len = buf.length();
const char *str = buf.extractChars();
Parser p(cs->loc, sc->_module, (const utf8_t *)str, len, false);
p.nextToken();
Statements *a = new Statements();
while (p.token.value != TOKeof)
{
Statement *s = p.parseStatement(PSsemi | PScurlyscope);
if (!s || p.errors)
{
assert(!p.errors || global.errors != errors); // make sure we caught all the cases
if (!s || global.errors != errors)
return errorStatements();
}
a->push(s);
}
return a;
}
Statements *CompileStatement::flatten(Scope *sc)
{
//printf("CompileStatement::flatten() %s\n", exp->toChars());
return compileIt(this, sc);
}
/******************************** CompoundStatement ***************************/
CompoundStatement::CompoundStatement(Loc loc, Statements *s)

View file

@ -173,9 +173,10 @@ public:
class CompileStatement : public Statement
{
public:
Expression *exp;
Expressions *exps;
CompileStatement(Loc loc, Expression *exp);
CompileStatement(Loc loc, Expressions *exps);
Statement *syntaxCopy();
Statements *flatten(Scope *sc);
void accept(Visitor *v) { v->visit(this); }

View file

@ -581,7 +581,7 @@ public:
{
fs->error("constant value %s cannot be ref", ie->toChars());
}
else
else
{
fs->error("constant value %s cannot be ref", ident->toChars());
}

View file

@ -21,6 +21,7 @@ class Dsymbol;
class Expression;
class FuncDeclaration;
class Parameter;
class Statement;
class Type;
class TypeFunction;
class TypeTuple;
@ -30,6 +31,7 @@ struct TargetC
{
unsigned longsize; // size of a C 'long' or 'unsigned long' type
unsigned long_doublesize; // size of a C 'long double'
Type *twchar_t; // C 'wchar_t' type
};
struct TargetCPP
@ -44,6 +46,7 @@ struct TargetCPP
const char *typeMangle(Type *t);
Type *parameterType(Parameter *p);
bool fundamentalType(const Type *t, bool& isFundamental);
unsigned derivedClassOffset(ClassDeclaration *baseClass);
};
struct TargetObjC
@ -108,6 +111,7 @@ public:
TypeTuple *toArgTypes(Type *t);
bool isReturnOnStack(TypeFunction *tf, bool needsThis);
Expression *getTargetInfo(const char* name, const Loc& loc);
bool libraryObjectMonitors(FuncDeclaration *fd, Statement *fbody);
};
extern Target target;

View file

@ -78,6 +78,7 @@ public:
bool ismixin; // template declaration is only to be used as a mixin
bool isstatic; // this is static template declaration
Prot protection;
int inuse; // for recursive expansion detection
TemplatePrevious *previous; // threaded list of previous instantiation attempts on stack

View file

@ -25,7 +25,7 @@ public:
{
this->sc = sc;
this->parameters = parameters;
this->result = false;
this->result = false;
}
void visit(TemplateTypeParameter *ttp)

View file

@ -40,6 +40,8 @@ void freeFieldinit(Scope *sc);
Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
Package *resolveIsPackage(Dsymbol *sym);
Expression *typeToExpression(Type *t);
Type *decoToType(const char *deco);
bool expressionsToString(OutBuffer &buf, Scope *sc, Expressions *exps);
/************************************************
@ -442,7 +444,6 @@ TraitsInitializer::TraitsInitializer()
"derivedMembers",
"isSame",
"compiles",
"parameters",
"getAliasThis",
"getAttributes",
"getFunctionAttributes",
@ -1032,6 +1033,34 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc)
ex = expressionSemantic(ex, sc);
return ex;
}
else if (e->ident == Id::toType)
{
if (dim != 1)
return dimError(e, 1, dim);
Expression *ex = isExpression((*e->args)[0]);
if (!ex)
{
e->error("expression expected as second argument of __traits `%s`", e->ident->toChars());
return new ErrorExp();
}
ex = ex->ctfeInterpret();
StringExp *se = semanticString(sc, ex, "__traits(toType, string)");
if (!se)
{
return new ErrorExp();
}
Type *t = decoToType(se->toUTF8(sc)->toPtr());
if (!t)
{
e->error("cannot determine `%s`", e->toChars());
return new ErrorExp();
}
ex = new TypeExp(e->loc, t);
ex = expressionSemantic(ex, sc);
return ex;
}
else if (e->ident == Id::hasMember ||
e->ident == Id::getMember ||
e->ident == Id::getOverloads ||
@ -1674,33 +1703,67 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc)
RootObject *o = (*e->args)[i];
Type *t = isType(o);
Expression *ex = t ? typeToExpression(t) : isExpression(o);
if (!ex && t)
while (t)
{
Dsymbol *s;
t->resolve(e->loc, sc2, &ex, &t, &s);
if (t)
if (TypeMixin *tm = t->isTypeMixin())
{
typeSemantic(t, e->loc, sc2);
if (t->ty == Terror)
/* The mixin string could be a type or an expression.
* Have to try compiling it to see.
*/
OutBuffer buf;
if (expressionsToString(buf, sc, tm->exps))
{
err = true;
break;
}
const size_t len = buf.length();
const char *str = buf.extractChars();
Parser p(e->loc, sc->_module, (const utf8_t *)str, len, false);
p.nextToken();
//printf("p.loc.linnum = %d\n", p.loc.linnum);
o = p.parseTypeOrAssignExp(TOKeof);
if (p.errors || p.token.value != TOKeof)
{
err = true;
break;
}
t = isType(o);
}
else
break;
}
if (!err)
{
Expression *ex = t ? typeToExpression(t) : isExpression(o);
if (!ex && t)
{
Dsymbol *s;
t->resolve(e->loc, sc2, &ex, &t, &s);
if (t)
{
typeSemantic(t, e->loc, sc2);
if (t->ty == Terror)
err = true;
}
else if (s && s->errors)
err = true;
}
else if (s && s->errors)
err = true;
}
if (ex)
{
ex = expressionSemantic(ex, sc2);
ex = resolvePropertiesOnly(sc2, ex);
ex = ex->optimize(WANTvalue);
if (sc2->func && sc2->func->type->ty == Tfunction)
if (ex)
{
TypeFunction *tf = (TypeFunction *)sc2->func->type;
canThrow(ex, sc2->func, tf->isnothrow);
ex = expressionSemantic(ex, sc2);
ex = resolvePropertiesOnly(sc2, ex);
ex = ex->optimize(WANTvalue);
if (sc2->func && sc2->func->type->ty == Tfunction)
{
TypeFunction *tf = (TypeFunction *)sc2->func->type;
canThrow(ex, sc2->func, tf->isnothrow);
}
ex = checkGC(sc2, ex);
if (ex->op == TOKerror)
err = true;
}
ex = checkGC(sc2, ex);
if (ex->op == TOKerror)
err = true;
}
// Carefully detach the scope from the parent and throw it away as

View file

@ -18,6 +18,7 @@
#include "hdrgen.h"
#include "id.h"
#include "init.h"
#include "parse.h"
#include "scope.h"
#include "target.h"
#include "template.h"
@ -25,6 +26,7 @@
Expression *typeToExpression(Type *t);
Expression *typeToExpressionHelper(TypeQualified *t, Expression *e, size_t i = 0);
bool expressionsToString(OutBuffer &buf, Scope *sc, Expressions *exps);
char *MODtoChars(MOD mod);
class TypeToExpressionVisitor : public Visitor
@ -76,6 +78,11 @@ public:
{
result = typeToExpressionHelper(t, new ScopeExp(t->loc, t->tempinst));
}
void visit(TypeMixin *t)
{
result = new TypeExp(t->loc, t);
}
};
/* We've mistakenly parsed this as a type.
@ -84,6 +91,8 @@ public:
*/
Expression *typeToExpression(Type *t)
{
if (t->mod)
return NULL;
TypeToExpressionVisitor v = TypeToExpressionVisitor(t);
t->accept(&v);
return v.result;
@ -177,6 +186,48 @@ static Expression *semanticLength(Scope *sc, TupleDeclaration *s, Expression *ex
return exp;
}
/******************************************
* Compile the MixinType, returning the type or expression AST.
*
* Doesn't run semantic() on the returned object.
* Params:
* tm = mixin to compile as a type or expression
* loc = location for error messages
* sc = context
* Return:
* null if error, else RootObject AST as parsed
*/
RootObject *compileTypeMixin(TypeMixin *tm, Loc loc, Scope *sc)
{
OutBuffer buf;
if (expressionsToString(buf, sc, tm->exps))
return NULL;
const unsigned errors = global.errors;
const size_t len = buf.length();
const char *str = buf.extractChars();
Parser p(loc, sc->_module, (const utf8_t *)str, len, false);
p.nextToken();
//printf("p.loc.linnum = %d\n", p.loc.linnum);
RootObject *o = p.parseTypeOrAssignExp(TOKeof);
if (errors != global.errors)
{
assert(global.errors != errors); // should have caught all these cases
return NULL;
}
if (p.token.value != TOKeof)
{
::error(loc, "incomplete mixin type `%s`", str);
return NULL;
}
Type *t = isType(o);
Expression *e = t ? typeToExpression(t) : isExpression(o);
return (!e && t) ? (RootObject *)t : (RootObject *)e;
}
/******************************************
* Perform semantic analysis on a type.
* Params:
@ -440,7 +491,7 @@ Type *typeSemantic(Type *type, const Loc &loc, Scope *sc)
// Deal with the case where we thought the index was a type, but
// in reality it was an expression.
if (mtype->index->ty == Tident || mtype->index->ty == Tinstance || mtype->index->ty == Tsarray ||
mtype->index->ty == Ttypeof || mtype->index->ty == Treturn)
mtype->index->ty == Ttypeof || mtype->index->ty == Treturn || mtype->index->ty == Tmixin)
{
Expression *e;
Type *t;
@ -1072,6 +1123,7 @@ Type *typeSemantic(Type *type, const Loc &loc, Scope *sc)
mtype->exp->ident != Id::getMember &&
mtype->exp->ident != Id::parent &&
mtype->exp->ident != Id::child &&
mtype->exp->ident != Id::toType &&
mtype->exp->ident != Id::getOverloads &&
mtype->exp->ident != Id::getVirtualFunctions &&
mtype->exp->ident != Id::getVirtualMethods &&
@ -1275,7 +1327,7 @@ Type *typeSemantic(Type *type, const Loc &loc, Scope *sc)
void visit(TypeStruct *mtype)
{
//printf("TypeStruct::semantic('%s')\n", mtype->sym->toChars());
//printf("TypeStruct::semantic('%s')\n", mtype->toChars());
if (mtype->deco)
{
if (sc && sc->cppmangle != CPPMANGLEdefault)
@ -1304,7 +1356,7 @@ Type *typeSemantic(Type *type, const Loc &loc, Scope *sc)
void visit(TypeClass *mtype)
{
//printf("TypeClass::semantic(%s)\n", mtype->sym->toChars());
//printf("TypeClass::semantic(%s)\n", mtype->toChars());
if (mtype->deco)
{
if (sc && sc->cppmangle != CPPMANGLEdefault)
@ -1386,6 +1438,25 @@ Type *typeSemantic(Type *type, const Loc &loc, Scope *sc)
Type *t = new TypeTuple(args);
result = typeSemantic(t, loc, sc);
}
void visit(TypeMixin *mtype)
{
//printf("TypeMixin::semantic() %s\n", mtype->toChars());
Expression *e = NULL;
Type *t = NULL;
Dsymbol *s = NULL;
mtype->resolve(loc, sc, &e, &t, &s);
if (t && t->ty != Terror)
{
result = t;
return;
}
::error(mtype->loc, "`mixin(%s)` does not give a valid type", mtype->obj->toChars());
return error();
}
};
TypeSemanticVisitor v(loc, sc);
type->accept(&v);

View file

@ -81,7 +81,9 @@ class TypeClass;
class TypeTuple;
class TypeSlice;
class TypeNull;
class TypeNoreturn;
class TypeTraits;
class TypeMixin;
class Dsymbol;
@ -374,7 +376,9 @@ public:
virtual void visit(TypeTuple *t) { visit((Type *)t); }
virtual void visit(TypeSlice *t) { visit((TypeNext *)t); }
virtual void visit(TypeNull *t) { visit((Type *)t); }
virtual void visit(TypeNoreturn *t) { visit((Type *)t); }
virtual void visit(TypeTraits *t) { visit((Type *)t); }
virtual void visit(TypeMixin *t) { visit((Type *)t); }
virtual void visit(Dsymbol *) { assert(0); }

View file

@ -1068,6 +1068,13 @@ public:
add_stmt (return_expr (decl));
}
else if (tf->next->ty == Tnoreturn)
{
/* Returning an expression that has no value, but has a side effect
that should never return. */
add_stmt (build_expr_dtor (s->exp));
add_stmt (return_expr (NULL_TREE));
}
else
{
/* Convert for initializing the DECL_RESULT. */

View file

@ -603,6 +603,12 @@ public:
t->ctype = ptr_type_node;
}
/* Bottom type used for functions that never return. */
void visit (TypeNoreturn *t)
{
t->ctype = void_type_node;
}
/* Basic Data Types. */
@ -852,7 +858,46 @@ public:
tree basetype = (t->sym->memtype)
? build_ctype (t->sym->memtype) : void_type_node;
if (!INTEGRAL_TYPE_P (basetype) || TREE_CODE (basetype) == BOOLEAN_TYPE)
if (t->sym->isSpecial ())
{
/* Special enums are opaque types that bind to C types. */
const char *ident = t->toChars ();
Type *underlying = NULL;
/* Skip over the prefixing `__c_'. */
gcc_assert (strncmp (ident, "__c_", strlen ("__c_")) == 0);
ident = ident + strlen ("__c_");
/* To keep things compatible within the code generation we stick to
mapping to equivalent D types. However it should be OK to use the
GCC provided C types here as the front-end enforces that everything
must be explicitly cast from a D type to any of the opaque types. */
if (strcmp (ident, "long") == 0)
underlying = build_frontend_type (long_integer_type_node);
else if (strcmp (ident, "ulong") == 0)
underlying = build_frontend_type (long_unsigned_type_node);
else if (strcmp (ident, "wchar_t") == 0)
underlying = target.c.twchar_t;
else if (strcmp (ident, "longlong") == 0)
underlying = build_frontend_type (long_long_integer_type_node);
else if (strcmp (ident, "ulonglong") == 0)
underlying = build_frontend_type (long_long_unsigned_type_node);
else if (strcmp (ident, "long_double") == 0)
underlying = build_frontend_type (long_double_type_node);
else if (strcmp (ident, "complex_real") == 0)
underlying = build_frontend_type (complex_long_double_type_node);
else if (strcmp (ident, "complex_float") == 0)
underlying = build_frontend_type (complex_float_type_node);
else if (strcmp (ident, "complex_double") == 0)
underlying = build_frontend_type (complex_double_type_node);
/* Conversion failed or there's an unhandled special type. */
gcc_assert (underlying != NULL);
t->ctype = build_variant_type_copy (build_ctype (underlying));
build_type_decl (t->ctype, t->sym);
}
else if (!INTEGRAL_TYPE_P (basetype) || TREE_CODE (basetype) == BOOLEAN_TYPE)
{
/* Enums in D2 can have a base type that is not necessarily integral.
For these, we simplify this a little by using the base type directly

View file

@ -0,0 +1,2 @@
// EXTRA_SOURCES: protection/issue20796/package.d
// https://issues.dlang.org/show_bug.cgi?id=20796

View file

@ -372,3 +372,21 @@ version (Posix)
static assert(T.boo.mangleof == "_ZN1T3booE");
}
/*****************************************/
alias noreturn = typeof(*null);
extern (C++)
{
alias fpcpp = noreturn function();
int funccpp(fpcpp);
version (Posix)
static assert(funccpp.mangleof == "_Z7funccppPFvvE");
version (Win32)
static assert(funccpp.mangleof == "?funccpp@@YAHP6AXXZ@Z");
version (Win64)
static assert(funccpp.mangleof == "?funccpp@@YAHP6AXXZ@Z");
}

View file

@ -357,6 +357,7 @@ auto redBlackTree(bool allowDuplicates, E)(E[] elems...)
}
/// ditto
auto redBlackTree(alias less, E)(E[] elems...)
if (__traits(compiles, (E a, E b) => mixin(less)))
{
return 3;
}

View file

@ -3,6 +3,12 @@ class Controller {
enum _s_pkg = __traits(parent, __traits(parent, __traits(parent, T))).stringof["package ".length .. $];
enum _s_model = T.stringof[0 .. $-`Controller`.length] ~ `Model`;
import serenity7190.core.Model;
// expands to "import example7190.models.HomeModel;"
mixin(q{import } ~ _s_pkg ~ q{.models.} ~ _s_model ~ q{;});
// "enum _ = is(example7190.models.HomeModel.HomeModel : serenity7190.core.Model.Model);"
mixin(q{enum _ = is(} ~ _s_pkg ~ q{.models.} ~ _s_model ~ q{.} ~ _s_model ~ q{ : serenity7190.core.Model.Model);});
}
}
}

View file

@ -0,0 +1,12 @@
module test20280a;
struct Alpha(uint _)
{
import test20280a;
}
struct Foxtrot(uint _)
{
alias Attributes = Alpha!10;
enum A = 10;
}

View file

@ -0,0 +1,24 @@
/* TEST_OUTPUT:
---
i int
d double
Pi int*
---
*/
pragma(msg, 1.mangleof, " ", __traits(toType, 1.mangleof));
pragma(msg, (1.0).mangleof, " ", __traits(toType, (1.0).mangleof));
pragma(msg, (int*).mangleof, " ", __traits(toType, (int*).mangleof));
template Type(T) { alias Type = T; }
Type!(__traits(toType, 1.mangleof)) j = 3;
alias T = Type!(__traits(toType, 1.mangleof));
static assert(is(T == int));
__traits(toType, "i") x = 7;
static assert(is(Type!(__traits(toType, 1.mangleof)) == int));
static assert(is(Type!(__traits(toType, (1.0).mangleof)) == double));
static assert(is(Type!(__traits(toType, (int*).mangleof)) == int*));

View file

@ -0,0 +1,30 @@
/*
REQUIRED_ARGS:
TEST_OUTPUT:
---
cast(void)0
cast(void)0
void
cast(void)0
cast(void)0
cast(void)0
void
---
*/
// https://issues.dlang.org/show_bug.cgi?id=21647
void foo() { return cast(void)1; }
void main(){}
alias V = void;
void test1() { pragma(msg, foo()); }
void test2() { pragma(msg, main()); }
void test3() { pragma(msg, V); }
pragma(msg, foo());
pragma(msg, main());
pragma(msg, V);

View file

@ -1,3 +0,0 @@
// EXTRA_SOURCES: imports/ice10598a.d imports/ice10598b.d
void main() {}

View file

@ -0,0 +1,22 @@
module imports.issue21614a;
struct FormatSpec(Char)
{
import imports.issue21614a;
}
template Tuple(Specs...)
{
struct Tuple
{
alias spec = FormatSpec!char();
this(Specs)
{
}
}
}
auto findRoot(T)(T)
{
return Tuple!(T)();
}

View file

@ -0,0 +1,7 @@
module imports.test21501b;
import test21501a;
struct B
{
A data;
}

View file

@ -0,0 +1,4 @@
module imports.test21501c;
alias C = int;
const D = 1;

View file

@ -0,0 +1,39 @@
module issue16020;
alias F1 = const(int)(); const(int) f1(){return 42;}
static assert (is(F1 == typeof(f1)));
alias F2 = float(float); float f2(float p){return p;}
static assert (is(F2 == typeof(f2)));
alias F3 = void(); void f3(){}
static assert (is(F3 == typeof(f3)));
alias void F41() @safe;
alias F42 = void() @safe;
alias F43 = @safe void();
static assert (is(F41 == F42));
static assert (is(F43 == F42));
alias void F51() @system;
alias F52 = void() @safe;
static assert (!is(F51 == F52));
alias F61 = int() const shared;
alias int F62() const shared ;
alias F63 = const shared int();
static assert (is(F61 == F62));
static assert (is(F63 == F62));
alias F71 = int() immutable inout;
alias int F72() immutable inout;
alias F73 = immutable inout int();
static assert (is(F71 == F72));
static assert (is(F73 == F72));
alias FunTemplate(T) = void(T t);
alias Specialized = FunTemplate!int;
alias Compared = void(int);
static assert(is(Specialized == Compared));
void main() {}

View file

@ -0,0 +1,10 @@
// EXTRA_FILES: imports/issue21614a.d
// REQUIRED_ARGS: -i
// https://issues.dlang.org/show_bug.cgi?id=21614
void logmdigammaInverse(real y)
{
import imports.issue21614a;
findRoot(y);
}

View file

@ -0,0 +1,2 @@
// EXTRA_SOURCES: protection/issue21726/typecons.d
// https://issues.dlang.org/show_bug.cgi?id=21726

View file

@ -0,0 +1,55 @@
alias Int = mixin("int");
alias Lint = mixin("Int");
int test1(mixin("int")* p)
{
mixin("int")[] a;
mixin("int[]") b;
mixin("int[] c;");
mixin("*p = c[0];");
*p = mixin("c[0]");
return *p + a[0] + b[0] + c[0];
}
/******************************************/
void test2()
{
auto a = __traits(allMembers, mixin(__MODULE__));
}
/*****************************************/
void test3()
{
char val;
int mod;
enum b = __traits(compiles, mixin("*cast(int*)&val + mod"));
static assert(b == true);
}
/********************************************/
struct S
{
int fielda;
int fieldb;
}
template Foo4(alias T)
{
enum Foo4 = true;
}
void test4()
{
S sa;
auto a = Foo4!( __traits(getMember,sa,"fielda") );
S sb;
enum getStuff = q{ __traits(getMember,sb,"fieldb") };
auto b = Foo4!(mixin(getStuff));
}

View file

@ -0,0 +1,68 @@
alias fun = mixin("(){}");
void test1()
{
int x = 1;
static immutable c = 2;
fun();
foo!(mixin("int"))();
foo!(mixin("long*"))();
foo!(mixin("ST!(int, S.T)"))();
foo!(mixin(ST!(int, S.T)))();
int[mixin("string")] a1;
int[mixin("5")] a2;
int[mixin("c")] a3;
int[] v1 = new int[mixin("3")];
auto v2 = new int[mixin("x")];
mixin(q{__traits(getMember, S, "T")}) ftv;
alias T = int*;
static assert(__traits(compiles, mixin("int")));
static assert(__traits(compiles, mixin(q{int[mixin("string")]})));
static assert(__traits(compiles, mixin(q{int[mixin("2")]})));
static assert(__traits(compiles, mixin(T)));
static assert(__traits(compiles, mixin("int*")));
static assert(__traits(compiles, mixin(typeof(0))));
}
struct S { alias T = float*; }
struct ST(X,Y) {}
void foo(alias t)() {}
/**************************************************/
// https://issues.dlang.org/show_bug.cgi?id=21074
alias Byte = ubyte;
alias Byte2(A) = ubyte;
alias T0 = mixin(q{const(Byte)})*;
alias T1 = mixin(q{const(Byte[1])})*;
alias T2 = mixin(q{const(Byte2!int)})*;
alias T3 = mixin(q{const(mixin(Byte2!int))})*;
alias T4 = mixin(q{const(mixin("__traits(getMember, S, \"T\")"))})*;
alias T5 = const(mixin(q{Byte}))*;
alias T6 = const(mixin(q{immutable(Byte)}))*;
alias T7 = const(mixin(q{shared(Byte)}))*;
alias T8 = const(mixin(q{Byte*}));
// the following tests now work
static assert(is(T0 == const(ubyte)*));
static assert(is(T1 == const(ubyte[1])*));
static assert(is(T2 == const(ubyte)*));
static assert(is(T3 == const(ubyte)*));
static assert(is(T4 == const(float*)*));
static assert(is(T5 == const(ubyte)*));
static assert(is(T6 == immutable(ubyte)*));
static assert(is(T7 == const(shared(ubyte))*));
static assert(is(T8 == const(ubyte*)));
// this doesn't work but I'll file a new issue
/*
alias T8 = mixin(q{immutable(__traits(getMember, S, "T"))})*;
static assert(is(T8 == immutable(float*)*));
*/

View file

@ -0,0 +1,21 @@
/*
TEST_OUTPUT:
---
noreturn
---
*/
alias noreturn = typeof(*null);
pragma(msg, noreturn);
noreturn exits(int* p) { *p = 3; }
noreturn exit();
int test1(int i)
{
if (exit())
return i + 1;
return i - 1;
}

View file

@ -0,0 +1,5 @@
module issue20796;
package(issue20796) void foo()
{
}

View file

@ -0,0 +1,7 @@
module protection.issue21726.format;
package(protection.issue21726.format):
package(protection.issue21726) int issuePkgSym;
package(protection) int protectionPkgSym();
int formatPkgSym;

View file

@ -0,0 +1 @@
module protection.issue21726;

View file

@ -0,0 +1,6 @@
module protection.issue21726.typecons;
import protection.issue21726.format : issuePkgSym;
import protection.issue21726.format : protectionPkgSym;
static assert(!__traits(compiles,
{ import protection.issue21726.format : formatPkgSym; }));

View file

@ -22,3 +22,6 @@ 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));
static assert(!is(imports.nonexistent == package));
static assert(!is(imports.nonexistent == module));

View file

@ -0,0 +1,3 @@
// https://issues.dlang.org/show_bug.cgi?id=17991
// EXTRA_FILES: imports/test17991a/package.d imports/test17991a/a.d
import imports.test17991a, imports.test17991a.a;

View file

@ -0,0 +1,15 @@
// https://issues.dlang.org/show_bug.cgi?id=19292
mixin("enum a = ", 87, ";");
static assert(a == 87);
int test()
{
mixin("enum x = ", 7, ";");
return mixin("1", x, 2U);
}
void testit()
{
static assert(test() == 172);
}

View file

@ -0,0 +1,3 @@
// EXTRA_FILES: imports/test20151a/b/c/c.d
module imports.test20151a;
import imports.test20151a.b.c.c;

View file

@ -0,0 +1,8 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -Icompilable/extra-files
// EXTRA_FILES: extra-files/test20280a.d
module test20280;
import test20280a;
alias Charlie = Foxtrot!(0);

View file

@ -0,0 +1,46 @@
// EXTRA_FILES: imports/test20530a.d imports/plainpackage/plainmodule.d imports/pkgmodule/package.d imports/pkgmodule/plainmodule.d
module mod;
static assert(is(mod == module));
static assert(is(mixin("mod") == module));
static assert(!is(mod == package));
static assert(!is(mixin("mod") == package));
import imports.test20530a;
static assert(is(imports == package));
static assert(is(mixin("imports") == package));
static assert(!is(imports == module));
static assert(!is(mixin("imports") == module));
import imports.plainpackage.plainmodule;
import imports.pkgmodule.plainmodule;
struct MyStruct;
alias a = mixin("imports.plainpackage");
alias b = mixin("imports.pkgmodule.plainmodule");
static assert(is(mixin("imports.plainpackage") == package));
static assert(is(mixin("a") == package));
static assert(!is(mixin("imports.plainpackage.plainmodule") == package));
static assert(!is(mixin("b") == package));
static assert(is(mixin("imports.pkgmodule") == package));
mixin("static assert(is(imports.pkgmodule == package));");
static assert(!is(mixin("MyStruct") == package));
static assert(!is(mixin("imports.plainpackage") == module));
static assert(!is(mixin("a") == module));
static assert(is(mixin("imports.plainpackage.plainmodule") == module));
static assert(is(mixin("b") == module));
static assert(is(mixin("imports.pkgmodule") == module));
mixin("static assert(is(imports.pkgmodule == module));");
static assert(!is(mixin("MyStruct") == module));
static assert(!is(mixin("imports.nonexistent") == package));
static assert(!is(mixin("imports.nonexistent") == module));
// this won't work due to mixin argument .stringof expansion,
// it will expand to mixin(package imports.pkgmodule). Issue 20519.
//static assert(is(mixin(imports.pkgmodule) == package));
//static assert(is(mixin(imports.pkgmodule) == module));

View file

@ -0,0 +1,10 @@
// REQUIRED_ARGS: -Icompilable/imports
// EXTRA_FILES: imports/pkg20537/package.d
import pkg20537;
static assert(is(pkg20537 == module));
static assert(__traits(isModule, pkg20537));
static assert(is(mixin("pkg20537") == module));
static assert(is(pkg20537 == package));
static assert(__traits(isPackage, pkg20537));
static assert(is(mixin("pkg20537") == package));

View file

@ -0,0 +1,18 @@
// https://issues.dlang.org/show_bug.cgi?id=20692
struct S() {
void fun() {
gun("");
}
void gun(T)(T) {
alias buggy = bug;
}
}
alias X = S!();
void main() {
X().gun(0);
}
alias bug = __traits(getMember, X, "fun");

View file

@ -0,0 +1,19 @@
// EXTRA_SOURCES: imports/test21501b.d imports/test21501c.d
// https://issues.dlang.org/show_bug.cgi?id=21501
module test21501a;
import imports.test21501b;
import imports.test21501c;
alias Identity(alias T) = T;
struct A
{
alias a = imports.test21501c.C;
const int b = imports.test21501c.D; // fixed
alias c = Identity!(mixin(q{imports.test21501c.C})); // fixed
const int d = Identity!(mixin(q{imports.test21501c.D})); // fixed
static assert(is(a == c) && is(a == int));
static assert(b == d && b == 1);
}

View file

@ -0,0 +1,39 @@
// https://issues.dlang.org/show_bug.cgi?id=9029
enum NameOf(alias S) = S.stringof;
static assert(NameOf!int == "int");
enum BothMatch(alias S) = "alias";
enum BothMatch(T) = "type";
void foo9029() { }
struct Struct { }
static assert(BothMatch!int == "type");
static assert(BothMatch!(void function()) == "type");
static assert(BothMatch!BothMatch == "alias");
static assert(BothMatch!Struct == "type");
static assert(BothMatch!foo9029 == "alias");
static assert(BothMatch!5 == "alias");
// https://issues.dlang.org/show_bug.cgi?id=19884
mixin template genCtEvaluate()
{
void evaluate(alias op)() { }
}
struct S
{
mixin genCtEvaluate!() mixinEval;
alias evaluate = mixinEval.evaluate;
void evaluate() { }
}
alias List(Ops...) = Ops;
void main()
{
S g;
foreach (op; List!(0))
{
g.evaluate!op();
}
}

View file

@ -0,0 +1,18 @@
/*
TEST_OUTPUT:
---
fail_compilation/bug15613.d(16): Error: function `bug15613.f(int...)` is not callable using argument types `(typeof(null))`
fail_compilation/bug15613.d(16): cannot pass argument `null` of type `typeof(null)` to parameter `int...`
fail_compilation/bug15613.d(17): Error: function `bug15613.g(Object, ...)` is not callable using argument types `(int)`
fail_compilation/bug15613.d(17): cannot pass argument `8` of type `int` to parameter `Object`
---
*/
void f(int...);
void g(Object, ...);
void main()
{
f(null);
g(8);
}

View file

@ -0,0 +1,18 @@
void f(int x, Object y);
void g()
{
Object o;
f(o, o, 404);
f(5, 6, 404);
}
/*
TEST_OUTPUT:
---
fail_compilation/bug16165.d(6): Error: function `bug16165.f(int x, Object y)` is not callable using argument types `(Object, Object, int)`
fail_compilation/bug16165.d(6): cannot pass argument `o` of type `object.Object` to parameter `int x`
fail_compilation/bug16165.d(7): Error: function `bug16165.f(int x, Object y)` is not callable using argument types `(int, int, int)`
fail_compilation/bug16165.d(7): cannot pass argument `6` of type `int` to parameter `Object y`
---
*/

View file

@ -0,0 +1,100 @@
/*
TEST_OUTPUT:
---
fail_compilation/bug9631.d(20): Error: cannot implicitly convert expression `F()` of type `bug9631.T1!().F` to `bug9631.T2!().F`
---
*/
template T1()
{
struct F { }
}
template T2()
{
struct F { }
}
void main()
{
T2!().F x = T1!().F();
}
/*
TEST_OUTPUT:
---
fail_compilation/bug9631.d(41): Error: incompatible types for ((x) == (y)): 'bug9631.S' and 'bug9631.tem!
).S'
---
*/
struct S { char c; }
template tem()
{
struct S { int i; }
}
void equal()
{
S x;
auto y = tem!().S();
bool b = x == y;
}
/*
TEST_OUTPUT:
---
fail_compilation/bug9631.d(79): Error: function `bug9631.arg.f(int i, S s)` is not callable using argumen
types `(int, S)`
fail_compilation/bug9631.d(79): cannot pass argument `y` of type `bug9631.tem!().S` to parameter `
ug9631.S s`
fail_compilation/bug9631.d(80): Error: function literal `__lambda2(S s)` is not callable using argument t
pes `(S)`
fail_compilation/bug9631.d(80): cannot pass argument `x` of type `bug9631.S` to parameter `bug9631
tem!().S s`
fail_compilation/bug9631.d(86): Error: constructor `bug9631.arg.A.this(S _param_0)` is not callable using
argument types `(S)`
fail_compilation/bug9631.d(86): cannot pass argument `S(0)` of type `bug9631.tem!().S` to paramete
`bug9631.S _param_0`
---
*/
void arg()
{
S x;
tem!().S y;
void f(int i, S s);
f(4, y);
(tem!().S s){}(x);
struct A
{
this(S){}
}
A(tem!().S());
}
/*
TEST_OUTPUT:
---
fail_compilation/bug9631.d(106): Error: function `bug9631.targ.ft!().ft(S _param_0)` is not callable using argument types `(S)`
fail_compilation/bug9631.d(106): cannot pass argument `x` of type `bug9631.S` to parameter `bug9631.tem!().S _param_0`
fail_compilation/bug9631.d(107): Error: template `bug9631.targ.ft` cannot deduce function from argument types `!()(S)`, candidates are:
fail_compilation/bug9631.d(105): `bug9631.targ.ft()(tem!().S)`
fail_compilation/bug9631.d(109): Error: template `bug9631.targ.ft2` cannot deduce function from argument types `!()(S, int)`, candidates are:
fail_compilation/bug9631.d(108): `bug9631.targ.ft2(T)(S, T)`
---
*/
void targ()
{
S x;
tem!().S y;
void ft()(tem!().S){}
ft!()(x);
ft(x);
void ft2(T)(S, T){}
ft2(y, 1);
}

View file

@ -0,0 +1,139 @@
/*
REQUIRED_ARGS: -de
TEST_OUTPUT:
---
fail_compilation/chkformat.d(101): Deprecation: width argument `0L` for format specification `"%*.*d"` must be `int`, not `long`
fail_compilation/chkformat.d(101): Deprecation: precision argument `1L` for format specification `"%*.*d"` must be `int`, not `long`
fail_compilation/chkformat.d(101): Deprecation: argument `2L` for format specification `"%*.*d"` must be `int`, not `long`
fail_compilation/chkformat.d(104): Deprecation: argument `4` for format specification `"%lld"` must be `long`, not `int`
fail_compilation/chkformat.d(105): Deprecation: argument `5` for format specification `"%jd"` must be `core.stdc.stdint.intmax_t`, not `int`
fail_compilation/chkformat.d(106): Deprecation: argument `6.0` for format specification `"%zd"` must be `size_t`, not `double`
fail_compilation/chkformat.d(107): Deprecation: argument `7.0` for format specification `"%td"` must be `ptrdiff_t`, not `double`
fail_compilation/chkformat.d(108): Deprecation: argument `8.0L` for format specification `"%g"` must be `double`, not `real`
fail_compilation/chkformat.d(109): Deprecation: argument `9.0` for format specification `"%Lg"` must be `real`, not `double`
fail_compilation/chkformat.d(110): Deprecation: argument `10` for format specification `"%p"` must be `void*`, not `int`
fail_compilation/chkformat.d(111): Deprecation: argument `& u` for format specification `"%n"` must be `int*`, not `uint*`
fail_compilation/chkformat.d(113): Deprecation: argument `& u` for format specification `"%lln"` must be `long*`, not `int*`
fail_compilation/chkformat.d(114): Deprecation: argument `& u` for format specification `"%hn"` must be `short*`, not `int*`
fail_compilation/chkformat.d(115): Deprecation: argument `& u` for format specification `"%hhn"` must be `byte*`, not `int*`
fail_compilation/chkformat.d(116): Deprecation: argument `16L` for format specification `"%c"` must be `char`, not `long`
fail_compilation/chkformat.d(117): Deprecation: argument `17L` for format specification `"%c"` must be `char`, not `long`
fail_compilation/chkformat.d(118): Deprecation: argument `& u` for format specification `"%s"` must be `char*`, not `int*`
fail_compilation/chkformat.d(119): Deprecation: argument `& u` for format specification `"%ls"` must be `wchar_t*`, not `int*`
fail_compilation/chkformat.d(201): Deprecation: argument `0L` for format specification `"%d"` must be `int*`, not `long`
fail_compilation/chkformat.d(202): Deprecation: more format specifiers than 1 arguments
fail_compilation/chkformat.d(203): Deprecation: argument `0L` for format specification `"%d"` must be `int*`, not `long`
fail_compilation/chkformat.d(204): Deprecation: argument `0L` for format specification `"%3u"` must be `uint*`, not `long`
fail_compilation/chkformat.d(205): Deprecation: argument `u` for format specification `"%200u"` must be `uint*`, not `uint`
fail_compilation/chkformat.d(206): Deprecation: argument `3.0` for format specification `"%hhd"` must be `byte*`, not `double`
fail_compilation/chkformat.d(207): Deprecation: argument `4` for format specification `"%hd"` must be `short*`, not `int`
fail_compilation/chkformat.d(209): Deprecation: argument `4` for format specification `"%lld"` must be `long*`, not `int`
fail_compilation/chkformat.d(210): Deprecation: argument `5` for format specification `"%jd"` must be `core.stdc.stdint.intmax_t*`, not `int`
fail_compilation/chkformat.d(211): Deprecation: argument `6.0` for format specification `"%zd"` must be `size_t*`, not `double`
fail_compilation/chkformat.d(212): Deprecation: argument `7.0` for format specification `"%td"` must be `ptrdiff_t*`, not `double`
fail_compilation/chkformat.d(213): Deprecation: format specifier `"%Ld"` is invalid
fail_compilation/chkformat.d(214): Deprecation: argument `0` for format specification `"%u"` must be `uint*`, not `int`
fail_compilation/chkformat.d(215): Deprecation: argument `0` for format specification `"%hhu"` must be `ubyte*`, not `int`
fail_compilation/chkformat.d(216): Deprecation: argument `0` for format specification `"%hu"` must be `ushort*`, not `int`
fail_compilation/chkformat.d(218): Deprecation: argument `0` for format specification `"%llu"` must be `ulong*`, not `int`
fail_compilation/chkformat.d(219): Deprecation: argument `0` for format specification `"%ju"` must be `ulong*`, not `int`
fail_compilation/chkformat.d(220): Deprecation: argument `0` for format specification `"%zu"` must be `size_t*`, not `int`
fail_compilation/chkformat.d(221): Deprecation: argument `0` for format specification `"%tu"` must be `ptrdiff_t*`, not `int`
fail_compilation/chkformat.d(222): Deprecation: argument `8.0L` for format specification `"%g"` must be `float*`, not `real`
fail_compilation/chkformat.d(223): Deprecation: argument `8.0L` for format specification `"%lg"` must be `double*`, not `real`
fail_compilation/chkformat.d(224): Deprecation: argument `9.0` for format specification `"%Lg"` must be `real*`, not `double`
fail_compilation/chkformat.d(225): Deprecation: argument `& u` for format specification `"%s"` must be `char*`, not `int*`
fail_compilation/chkformat.d(226): Deprecation: argument `& u` for format specification `"%ls"` must be `wchar_t*`, not `int*`
fail_compilation/chkformat.d(227): Deprecation: argument `v` for format specification `"%p"` must be `void**`, not `void*`
fail_compilation/chkformat.d(228): Deprecation: argument `& u` for format specification `"%n"` must be `int*`, not `ushort*`
fail_compilation/chkformat.d(229): Deprecation: argument `& u` for format specification `"%hhn"` must be `byte*`, not `int*`
fail_compilation/chkformat.d(230): Deprecation: format specifier `"%[n"` is invalid
fail_compilation/chkformat.d(231): Deprecation: format specifier `"%]"` is invalid
fail_compilation/chkformat.d(232): Deprecation: argument `& u` for format specification `"%90s"` must be `char*`, not `int*`
fail_compilation/chkformat.d(233): Deprecation: argument `0L` for format specification `"%d"` must be `int*`, not `long`
fail_compilation/chkformat.d(234): Deprecation: argument `0L` for format specification `"%d"` must be `int*`, not `long`
---
*/
import core.stdc.stdio;
#line 100
void test1() { printf("%*.*d\n", 0L, 1L, 2L); }
//void test2() { }
//void test3() { printf("%ld\n", 3.0); }
void test4() { printf("%lld\n", 4); }
void test5() { printf("%jd\n", 5); }
void test6() { printf("%zd\n", 6.0); }
void test7() { printf("%td\n", 7.0); }
void test8() { printf("%g\n", 8.0L); }
void test9() { printf("%Lg\n", 9.0); }
void test10() { printf("%p\n", 10); }
void test11() { uint u; printf("%n\n", &u); }
//void test12() { ushort u; printf("%ln\n", &u); }
void test13() { int u; printf("%lln\n", &u); }
void test14() { int u; printf("%hn\n", &u); }
void test15() { int u; printf("%hhn\n", &u); }
void test16() { printf("%c\n", 16L); }
void test17() { printf("%c\n", 17L); }
void test18() { int u; printf("%s\n", &u); }
void test19() { int u; printf("%ls\n", &u); }
//void test20() { int u; char[] s; sprintf(&s[0], "%d\n", &u); }
//void test21() { int u; fprintf(null, "%d\n", &u); }
#line 200
void test31() { scanf("%d\n", 0L); }
void test32() { int i; scanf("%d %d\n", &i); }
void test33() { scanf("%d%*c\n", 0L); }
void test34() { scanf("%3u\n", 0L); }
void test35() { uint u; scanf("%200u%*s\n", u); }
void test36() { scanf("%hhd\n", 3.0); }
void test37() { scanf("%hd\n", 4); }
//void test38() { scanf("%ld\n", 3.0); }
void test39() { scanf("%lld\n", 4); }
void test40() { scanf("%jd\n", 5); }
void test41() { scanf("%zd\n", 6.0); }
void test42() { scanf("%td\n", 7.0); }
void test43() { scanf("%Ld\n", 0); }
void test44() { scanf("%u\n", 0); }
void test45() { scanf("%hhu\n", 0); }
void test46() { scanf("%hu\n", 0); }
//void test47() { scanf("%lu\n", 0); }
void test48() { scanf("%llu\n", 0); }
void test49() { scanf("%ju\n", 0); }
void test50() { scanf("%zu\n", 0); }
void test51() { scanf("%tu\n", 0); }
void test52() { scanf("%g\n", 8.0L); }
void test53() { scanf("%lg\n", 8.0L); }
void test54() { scanf("%Lg\n", 9.0); }
void test55() { int u; scanf("%s\n", &u); }
void test56() { int u; scanf("%ls\n", &u); }
void test57() { void* v; scanf("%p\n", v); }
void test58() { ushort u; scanf("%n\n", &u); }
void test59() { int u; scanf("%hhn\n", &u); }
void test60() { int u; scanf("%[n", &u); }
void test61() { int u; scanf("%]\n", &u); }
void test62() { int u; scanf("%90s\n", &u); }
void test63() { sscanf("1234", "%d\n", 0L); }
void test64() { fscanf(null, "%d\n", 0L); }
/* TEST_OUTPUT:
---
fail_compilation/chkformat.d(301): Deprecation: format specifier `"%K"` is invalid
fail_compilation/chkformat.d(302): Deprecation: format specifier `"%Q"` is invalid
---
*/
import core.stdc.stdarg;
#line 300
void test301() { va_list vargs; vprintf("%K", vargs); }
void test302() { va_list vargs; vscanf("%Q", vargs); }
// TODO - C++ 11 only:
//void test() { vscanf(); }
//void test() { vfscanf(); }
//void test() { vsscanf(); }

View file

@ -2,7 +2,7 @@
TEST_OUTPUT:
---
fail_compilation/cppmangle.d(10): Error: invalid zero length C++ namespace
fail_compilation/cppmangle.d(14): Error: expected valid identifer for C++ namespace but got `0num`
fail_compilation/cppmangle.d(14): Error: expected valid identifier for C++ namespace but got `0num`
fail_compilation/cppmangle.d(18): Error: string expected following `,` for C++ namespace, not `)`
---
*/

View file

@ -14,7 +14,7 @@ fail_compilation/diag11819b.d(37): Error: unrecognized trait `AllMembers`, did y
fail_compilation/diag11819b.d(38): Error: unrecognized trait `DerivedMembers`, did you mean `derivedMembers`?
fail_compilation/diag11819b.d(39): Error: unrecognized trait `IsSame`, did you mean `isSame`?
fail_compilation/diag11819b.d(40): Error: unrecognized trait `Compiles`, did you mean `compiles`?
fail_compilation/diag11819b.d(41): Error: unrecognized trait `Parameters`, did you mean `parameters`?
fail_compilation/diag11819b.d(41): Error: unrecognized trait `Parameters`
fail_compilation/diag11819b.d(42): Error: unrecognized trait `GetAliasThis`, did you mean `getAliasThis`?
fail_compilation/diag11819b.d(43): Error: unrecognized trait `GetAttributes`, did you mean `getAttributes`?
fail_compilation/diag11819b.d(44): Error: unrecognized trait `GetFunctionAttributes`, did you mean `getFunctionAttributes`?

View file

@ -1,8 +1,10 @@
/*
TEST_OUTPUT:
---
fail_compilation/diag13082.d(22): Error: constructor diag13082.C.this (int a) is not callable using argument types (string)
fail_compilation/diag13082.d(23): Error: constructor diag13082.S.this (int a) is not callable using argument types (string)
fail_compilation/diag13082.d(24): Error: constructor `diag13082.C.this(int a)` is not callable using argument types `(string)`
fail_compilation/diag13082.d(24): cannot pass argument `b` of type `string` to parameter `int a`
fail_compilation/diag13082.d(25): Error: constructor `diag13082.S.this(int a)` is not callable using argument types `(string)`
fail_compilation/diag13082.d(25): cannot pass argument `b` of type `string` to parameter `int a`
---
*/

View file

@ -0,0 +1,12 @@
/*
TEST_OUTPUT
---
fail_compilation/diag16271.d(10): Error: found `x` when expecting function literal following `ref`
---
*/
void main()
{
auto fun = ref x;
}

View file

@ -1,29 +1,30 @@
/*
TEST_OUTPUT:
---
fail_compilation/diag8101.d(56): Error: function diag8101.f_0 (int) is not callable using argument types ()
fail_compilation/diag8101.d(57): Error: none of the overloads of 'f_1' are callable using argument types (), candidates are:
fail_compilation/diag8101.d(32): diag8101.f_1(int)
fail_compilation/diag8101.d(33): diag8101.f_1(int, int)
fail_compilation/diag8101.d(58): Error: none of the overloads of 'f_2' are callable using argument types (), candidates are:
fail_compilation/diag8101.d(35): diag8101.f_2(int)
fail_compilation/diag8101.d(36): diag8101.f_2(int, int)
fail_compilation/diag8101.d(37): diag8101.f_2(int, int, int)
fail_compilation/diag8101.d(38): diag8101.f_2(int, int, int, int)
fail_compilation/diag8101.d(39): diag8101.f_2(int, int, int, int, int)
fail_compilation/diag8101.d(58): ... (1 more, -v to show) ...
fail_compilation/diag8101.d(60): Error: template diag8101.t_0 cannot deduce function from argument types !()(), candidates are:
fail_compilation/diag8101.d(42): diag8101.t_0(T1)()
fail_compilation/diag8101.d(61): Error: template diag8101.t_1 cannot deduce function from argument types !()(), candidates are:
fail_compilation/diag8101.d(44): diag8101.t_1(T1)()
fail_compilation/diag8101.d(45): diag8101.t_1(T1, T2)()
fail_compilation/diag8101.d(62): Error: template diag8101.t_2 cannot deduce function from argument types !()(), candidates are:
fail_compilation/diag8101.d(47): diag8101.t_2(T1)()
fail_compilation/diag8101.d(48): diag8101.t_2(T1, T2)()
fail_compilation/diag8101.d(49): diag8101.t_2(T1, T2, T3)()
fail_compilation/diag8101.d(50): diag8101.t_2(T1, T2, T3, T4)()
fail_compilation/diag8101.d(51): diag8101.t_2(T1, T2, T3, T4, T5)()
fail_compilation/diag8101.d(62): ... (1 more, -v to show) ...
fail_compilation/diag8101.d(57): Error: function `diag8101.f_0(int)` is not callable using argument types `()`
fail_compilation/diag8101.d(57): missing argument for parameter #1: `int`
fail_compilation/diag8101.d(58): Error: none of the overloads of `f_1` are callable using argument types `()`, candidates are:
fail_compilation/diag8101.d(33): `diag8101.f_1(int)`
fail_compilation/diag8101.d(34): `diag8101.f_1(int, int)`
fail_compilation/diag8101.d(59): Error: none of the overloads of `f_2` are callable using argument types `()`, candidates are:
fail_compilation/diag8101.d(36): `diag8101.f_2(int)`
fail_compilation/diag8101.d(37): `diag8101.f_2(int, int)`
fail_compilation/diag8101.d(38): `diag8101.f_2(int, int, int)`
fail_compilation/diag8101.d(39): `diag8101.f_2(int, int, int, int)`
fail_compilation/diag8101.d(40): `diag8101.f_2(int, int, int, int, int)`
fail_compilation/diag8101.d(59): ... (1 more, -v to show) ...
fail_compilation/diag8101.d(61): Error: template `diag8101.t_0` cannot deduce function from argument types `!()()`, candidates are:
fail_compilation/diag8101.d(43): `diag8101.t_0(T1)()`
fail_compilation/diag8101.d(62): Error: template `diag8101.t_1` cannot deduce function from argument types `!()()`, candidates are:
fail_compilation/diag8101.d(45): `diag8101.t_1(T1)()`
fail_compilation/diag8101.d(46): `diag8101.t_1(T1, T2)()`
fail_compilation/diag8101.d(63): Error: template `diag8101.t_2` cannot deduce function from argument types `!()()`, candidates are:
fail_compilation/diag8101.d(48): `diag8101.t_2(T1)()`
fail_compilation/diag8101.d(49): `diag8101.t_2(T1, T2)()`
fail_compilation/diag8101.d(50): `diag8101.t_2(T1, T2, T3)()`
fail_compilation/diag8101.d(51): `diag8101.t_2(T1, T2, T3, T4)()`
fail_compilation/diag8101.d(52): `diag8101.t_2(T1, T2, T3, T4, T5)()`
fail_compilation/diag8101.d(63): ... (1 more, -v to show) ...
---
*/

View file

@ -1,14 +1,15 @@
/*
TEST_OUTPUT:
---
fail_compilation/diag8101b.d(26): Error: none of the overloads of 'foo' are callable using argument types (double), candidates are:
fail_compilation/diag8101b.d(17): diag8101b.S.foo(int _param_0)
fail_compilation/diag8101b.d(18): diag8101b.S.foo(int _param_0, int _param_1)
fail_compilation/diag8101b.d(28): Error: function diag8101b.S.bar (int _param_0) is not callable using argument types (double)
fail_compilation/diag8101b.d(31): Error: none of the overloads of 'foo' are callable using a const object, candidates are:
fail_compilation/diag8101b.d(17): diag8101b.S.foo(int _param_0)
fail_compilation/diag8101b.d(18): diag8101b.S.foo(int _param_0, int _param_1)
fail_compilation/diag8101b.d(33): Error: mutable method diag8101b.S.bar is not callable using a const object
fail_compilation/diag8101b.d(27): Error: none of the overloads of `foo` are callable using argument types `(double)`, candidates are:
fail_compilation/diag8101b.d(18): `diag8101b.S.foo(int _param_0)`
fail_compilation/diag8101b.d(19): `diag8101b.S.foo(int _param_0, int _param_1)`
fail_compilation/diag8101b.d(29): Error: function `diag8101b.S.bar(int _param_0)` is not callable using argument types `(double)`
fail_compilation/diag8101b.d(29): cannot pass argument `1.00000` of type `double` to parameter `int _param_0`
fail_compilation/diag8101b.d(32): Error: none of the overloads of `foo` are callable using a `const` object, candidates are:
fail_compilation/diag8101b.d(18): `diag8101b.S.foo(int _param_0)`
fail_compilation/diag8101b.d(19): `diag8101b.S.foo(int _param_0, int _param_1)`
fail_compilation/diag8101b.d(34): Error: mutable method `diag8101b.S.bar` is not callable using a `const` object
---
*/

View file

@ -1,7 +1,8 @@
/*
TEST_OUTPUT
---
fail_compilation/diag9420.d(20): Error: function diag9420.S.t3!().tx () is not callable using argument types (int)
fail_compilation/diag9420.d(21): Error: function `diag9420.S.t3!().tx()` is not callable using argument types `(int)`
fail_compilation/diag9420.d(21): expected 0 argument(s), not 1
---
*/

View file

@ -0,0 +1,17 @@
// https://issues.dlang.org/show_bug.cgi?id=11038
/*
TEST_OUTPUT:
---
fail_compilation/fail11038.d(16): Error: `writeln` is not defined, perhaps `import std.stdio;` is needed?
---
*/
static
{
import std.stdio;
}
void main()
{
writeln("foo"); // compiles
}

View file

@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
fail_compilation/fail11445.d(11): Error: incompatible types for ((a) + (b)): 'double[string]' and 'double[string]'
fail_compilation/fail11445.d(11): Error: incompatible types for ((a) + (b)): both operands are of type 'double[string]'
---
*/

Some files were not shown because too many files have changed in this diff Show more