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:
parent
ba0f690266
commit
5a0aa603b2
191 changed files with 7471 additions and 3914 deletions
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
975
gcc/d/dmd/chkformat.c
Normal 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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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>";
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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())
|
||||
{
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
@ -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
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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); }
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ public:
|
|||
{
|
||||
this->sc = sc;
|
||||
this->parameters = parameters;
|
||||
this->result = false;
|
||||
this->result = false;
|
||||
}
|
||||
|
||||
void visit(TemplateTypeParameter *ttp)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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); }
|
||||
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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
|
||||
|
|
2
gcc/testsuite/gdc.test/compilable/bug20796.d
Normal file
2
gcc/testsuite/gdc.test/compilable/bug20796.d
Normal file
|
@ -0,0 +1,2 @@
|
|||
// EXTRA_SOURCES: protection/issue20796/package.d
|
||||
// https://issues.dlang.org/show_bug.cgi?id=20796
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
12
gcc/testsuite/gdc.test/compilable/extra-files/test20280a.d
Normal file
12
gcc/testsuite/gdc.test/compilable/extra-files/test20280a.d
Normal file
|
@ -0,0 +1,12 @@
|
|||
module test20280a;
|
||||
|
||||
struct Alpha(uint _)
|
||||
{
|
||||
import test20280a;
|
||||
}
|
||||
|
||||
struct Foxtrot(uint _)
|
||||
{
|
||||
alias Attributes = Alpha!10;
|
||||
enum A = 10;
|
||||
}
|
24
gcc/testsuite/gdc.test/compilable/fix21585.d
Normal file
24
gcc/testsuite/gdc.test/compilable/fix21585.d
Normal 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*));
|
30
gcc/testsuite/gdc.test/compilable/fix21647.d
Normal file
30
gcc/testsuite/gdc.test/compilable/fix21647.d
Normal 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);
|
|
@ -1,3 +0,0 @@
|
|||
// EXTRA_SOURCES: imports/ice10598a.d imports/ice10598b.d
|
||||
|
||||
void main() {}
|
22
gcc/testsuite/gdc.test/compilable/imports/issue21614a.d
Normal file
22
gcc/testsuite/gdc.test/compilable/imports/issue21614a.d
Normal 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)();
|
||||
}
|
0
gcc/testsuite/gdc.test/compilable/imports/test17991a/a.d
Normal file
0
gcc/testsuite/gdc.test/compilable/imports/test17991a/a.d
Normal file
0
gcc/testsuite/gdc.test/compilable/imports/test20530a.d
Normal file
0
gcc/testsuite/gdc.test/compilable/imports/test20530a.d
Normal file
7
gcc/testsuite/gdc.test/compilable/imports/test21501b.d
Normal file
7
gcc/testsuite/gdc.test/compilable/imports/test21501b.d
Normal file
|
@ -0,0 +1,7 @@
|
|||
module imports.test21501b;
|
||||
import test21501a;
|
||||
|
||||
struct B
|
||||
{
|
||||
A data;
|
||||
}
|
4
gcc/testsuite/gdc.test/compilable/imports/test21501c.d
Normal file
4
gcc/testsuite/gdc.test/compilable/imports/test21501c.d
Normal file
|
@ -0,0 +1,4 @@
|
|||
module imports.test21501c;
|
||||
|
||||
alias C = int;
|
||||
const D = 1;
|
39
gcc/testsuite/gdc.test/compilable/issue16020.d
Normal file
39
gcc/testsuite/gdc.test/compilable/issue16020.d
Normal 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() {}
|
10
gcc/testsuite/gdc.test/compilable/issue21614.d
Normal file
10
gcc/testsuite/gdc.test/compilable/issue21614.d
Normal 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);
|
||||
}
|
2
gcc/testsuite/gdc.test/compilable/issue21726.d
Normal file
2
gcc/testsuite/gdc.test/compilable/issue21726.d
Normal file
|
@ -0,0 +1,2 @@
|
|||
// EXTRA_SOURCES: protection/issue21726/typecons.d
|
||||
// https://issues.dlang.org/show_bug.cgi?id=21726
|
55
gcc/testsuite/gdc.test/compilable/mixintype.d
Normal file
55
gcc/testsuite/gdc.test/compilable/mixintype.d
Normal 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));
|
||||
}
|
||||
|
68
gcc/testsuite/gdc.test/compilable/mixintype2.d
Normal file
68
gcc/testsuite/gdc.test/compilable/mixintype2.d
Normal 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*)*));
|
||||
*/
|
21
gcc/testsuite/gdc.test/compilable/noreturn1.d
Normal file
21
gcc/testsuite/gdc.test/compilable/noreturn1.d
Normal 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;
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
module issue20796;
|
||||
|
||||
package(issue20796) void foo()
|
||||
{
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
module protection.issue21726.format;
|
||||
|
||||
package(protection.issue21726.format):
|
||||
|
||||
package(protection.issue21726) int issuePkgSym;
|
||||
package(protection) int protectionPkgSym();
|
||||
int formatPkgSym;
|
|
@ -0,0 +1 @@
|
|||
module protection.issue21726;
|
|
@ -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; }));
|
|
@ -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));
|
||||
|
|
3
gcc/testsuite/gdc.test/compilable/test17991.d
Normal file
3
gcc/testsuite/gdc.test/compilable/test17991.d
Normal 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;
|
15
gcc/testsuite/gdc.test/compilable/test19292.d
Normal file
15
gcc/testsuite/gdc.test/compilable/test19292.d
Normal 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);
|
||||
}
|
3
gcc/testsuite/gdc.test/compilable/test20151a.d
Normal file
3
gcc/testsuite/gdc.test/compilable/test20151a.d
Normal file
|
@ -0,0 +1,3 @@
|
|||
// EXTRA_FILES: imports/test20151a/b/c/c.d
|
||||
module imports.test20151a;
|
||||
import imports.test20151a.b.c.c;
|
8
gcc/testsuite/gdc.test/compilable/test20280.d
Normal file
8
gcc/testsuite/gdc.test/compilable/test20280.d
Normal 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);
|
46
gcc/testsuite/gdc.test/compilable/test20530.d
Normal file
46
gcc/testsuite/gdc.test/compilable/test20530.d
Normal 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));
|
10
gcc/testsuite/gdc.test/compilable/test20537.d
Normal file
10
gcc/testsuite/gdc.test/compilable/test20537.d
Normal 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));
|
18
gcc/testsuite/gdc.test/compilable/test20692.d
Normal file
18
gcc/testsuite/gdc.test/compilable/test20692.d
Normal 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");
|
19
gcc/testsuite/gdc.test/compilable/test21501a.d
Normal file
19
gcc/testsuite/gdc.test/compilable/test21501a.d
Normal 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);
|
||||
}
|
39
gcc/testsuite/gdc.test/compilable/test9029.d
Normal file
39
gcc/testsuite/gdc.test/compilable/test9029.d
Normal 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();
|
||||
}
|
||||
}
|
18
gcc/testsuite/gdc.test/fail_compilation/bug15613.d
Normal file
18
gcc/testsuite/gdc.test/fail_compilation/bug15613.d
Normal 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);
|
||||
}
|
18
gcc/testsuite/gdc.test/fail_compilation/bug16165.d
Normal file
18
gcc/testsuite/gdc.test/fail_compilation/bug16165.d
Normal 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`
|
||||
---
|
||||
*/
|
100
gcc/testsuite/gdc.test/fail_compilation/bug9631.d
Normal file
100
gcc/testsuite/gdc.test/fail_compilation/bug9631.d
Normal 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);
|
||||
}
|
||||
|
139
gcc/testsuite/gdc.test/fail_compilation/chkformat.d
Normal file
139
gcc/testsuite/gdc.test/fail_compilation/chkformat.d
Normal 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(); }
|
|
@ -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 `)`
|
||||
---
|
||||
*/
|
||||
|
|
|
@ -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`?
|
||||
|
|
|
@ -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`
|
||||
---
|
||||
*/
|
||||
|
||||
|
|
12
gcc/testsuite/gdc.test/fail_compilation/diag16271.d
Normal file
12
gcc/testsuite/gdc.test/fail_compilation/diag16271.d
Normal 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;
|
||||
}
|
||||
|
|
@ -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) ...
|
||||
---
|
||||
*/
|
||||
|
||||
|
|
|
@ -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
|
||||
---
|
||||
*/
|
||||
|
||||
|
|
|
@ -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
|
||||
---
|
||||
*/
|
||||
|
||||
|
|
17
gcc/testsuite/gdc.test/fail_compilation/fail11038.d
Normal file
17
gcc/testsuite/gdc.test/fail_compilation/fail11038.d
Normal 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
|
||||
}
|
|
@ -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
Loading…
Add table
Reference in a new issue