d/dversion.o \
d/entity.o \
d/errors.o \
+ d/errorsink.o \
d/escape.o \
d/expression.o \
d/expressionsem.o \
return r;
}
-/* Format the real_t value R to string BUFFER as a decimal or hexadecimal,
- converting the result to uppercase if FMT requests it. */
+/* Format the real_t value R to string BUFFER, bounded by BUF_SIZE, as a decimal
+ or hexadecimal, converting the result to uppercase if FMT requests it. */
int
-CTFloat::sprint (char *buffer, char fmt, real_t r)
+CTFloat::sprint (char *buffer, d_size_t buf_size, char fmt, real_t r)
{
if (fmt == 'a' || fmt == 'A')
{
/* Converting to a hexadecimal string. */
- real_to_hexadecimal (buffer, &r.rv (), 32, 0, 1);
+ real_to_hexadecimal (buffer, &r.rv (), buf_size, 0, 1);
int buflen;
switch (fmt)
/* Build and return typeinfo type for TYPE. */
Type *
-getTypeInfoType (const Loc &loc, Type *type, Scope *sc)
+getTypeInfoType (const Loc &loc, Type *type, Scope *sc, bool genObjCode)
{
gcc_assert (type->ty != TY::Terror);
check_typeinfo_type (loc, sc);
- create_typeinfo (type, sc ? sc->_module->importedFrom : NULL);
+ create_typeinfo (type, sc ? sc->_module->importedFrom : NULL, genObjCode);
return type->vtinfo->type;
}
case OPT_fpreview_all:
global.params.ehnogc = value;
- global.params.useDIP25 = FeatureState::enabled;
global.params.useDIP1000 = FeatureState::enabled;
global.params.useDIP1021 = value;
global.params.bitfields = value;
global.params.useDIP1021 = value;
break;
- case OPT_fpreview_dip25:
- global.params.useDIP25 = FeatureState::enabled;
- break;
-
case OPT_fpreview_dtorfields:
global.params.dtorFields = FeatureState::enabled;
break;
case OPT_frevert_all:
global.params.useDIP1000 = FeatureState::disabled;
- global.params.useDIP25 = FeatureState::disabled;
global.params.dtorFields = FeatureState::disabled;
global.params.fix16997 = !value;
break;
global.params.useDIP1000 = FeatureState::disabled;
break;
- case OPT_frevert_dip25:
- global.params.useDIP25 = FeatureState::disabled;
- break;
-
case OPT_frevert_dtorfields:
global.params.dtorFields = FeatureState::disabled;
break;
if (global.params.useDIP1021)
global.params.useDIP1000 = FeatureState::enabled;
- /* Enabling DIP1000 implies DIP25. */
- if (global.params.useDIP1000 == FeatureState::enabled)
- global.params.useDIP25 = FeatureState::enabled;
-
/* Keep in sync with existing -fbounds-check flag. */
flag_bounds_check = (global.params.useArrayBounds == CHECKENABLEon);
extern void check_typeinfo_type (const Loc &, Scope *, Expression * = NULL);
extern tree build_typeinfo (const Loc &, Type *, Expression * = NULL);
extern tree build_typeinfo (Expression *, Type *);
-extern void create_typeinfo (Type *, Module *);
+extern void create_typeinfo (Type *, Module *, bool = true);
extern void create_tinfo_types (Module *);
extern void layout_cpp_typeinfo (ClassDeclaration *);
extern tree get_cpp_typeinfo_decl (ClassDeclaration *);
if (fd2->isFuture ())
continue;
- if (fd->leastAsSpecialized (fd2) != MATCH::nomatch
- || fd2->leastAsSpecialized (fd) != MATCH::nomatch)
+ if (fd->leastAsSpecialized (fd2, NULL) != MATCH::nomatch
+ || fd2->leastAsSpecialized (fd, NULL) != MATCH::nomatch)
{
error_at (make_location_t (fd->loc), "use of %qs",
fd->toPrettyChars ());
return;
}
- if (d->aliassym)
+ if (d->aliasTuple)
{
this->build_dsymbol (d->toAlias ());
return;
DECL_INITIAL (decl) = build_expr (e, true);
}
}
- else
+ else if (!d->type->isZeroInit ())
{
/* Use default initializer for the type. */
if (TypeStruct *ts = d->type->isTypeStruct ())
if (gcc_attribute_p (d))
return;
+ /* Front-end decided this function doesn't require code generation. */
+ if (d->skipCodegen ())
+ return;
+
/* Not emitting unittest functions. */
if (!global.params.useUnitTests && d->isUnitTestDeclaration ())
return;
-09faa4eacd4fb147107e94eeebf56b3a73fdcc05
+4ca4140e584c055a8a9bc727e56a97ebcecd61e0
The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository.
| [dinifile.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dinifile.d) | Parse settings from .ini file (`sc.ini` / `dmd.conf`) |
| [vsoptions.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/vsoptions.d) | Detect the Microsoft Visual Studio toolchain for linking |
| [frontend.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/frontend.d) | An interface for using DMD as a library |
-| [errors.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/errors.d) | Error reporting functionality |
+| [errors.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/errors.d) | Error reporting implementation |
+| [errorsink.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/errorsink.d) | Error reporting interface |
| [target.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/target.d) | Manage target-specific parameters for cross-compiling (for LDC/GDC) |
| [compiler.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/compiler.d) | Describe a back-end compiler and implements compiler-specific actions |
-v2.102.0-beta.1
+v2.103.0-beta.1
virtual int vtblOffset() const;
const char *kind() const override;
- void addLocalClass(ClassDeclarations *) override final;
void addObjcSymbols(ClassDeclarations *classes, ClassDeclarations *categories) override final;
// Back end
public:
StoppableVisitor v;
- extern (D) this(StoppableVisitor v)
+ extern (D) this(StoppableVisitor v) scope
{
this.v = v;
}
ObjectNotFound(idArrayOp); // fatal error
}
- auto fd = resolveFuncCall(e.loc, sc, arrayOp, tiargs, null, args, FuncResolveFlag.standard);
+ auto fd = resolveFuncCall(e.loc, sc, arrayOp, tiargs, null, ArgumentList(args), FuncResolveFlag.standard);
if (!fd || fd.errors)
return ErrorExp.get();
return new CallExp(e.loc, new VarExp(e.loc, fd, false), args).expressionSemantic(sc);
Expressions* args;
public:
- extern (D) this(Scope* sc, Objects* tiargs)
+ extern (D) this(Scope* sc, Objects* tiargs) scope
{
this.sc = sc;
this.tiargs = tiargs;
/****************************************
*/
- override final void addLocalClass(ClassDeclarations* aclasses)
- {
- include(null).foreachDsymbol( s => s.addLocalClass(aclasses) );
- }
-
override final void addObjcSymbols(ClassDeclarations* classes, ClassDeclarations* categories)
{
objc.addSymbols(this, classes, categories);
}
- override final inout(AttribDeclaration) isAttribDeclaration() inout pure @safe
+ override inout(AttribDeclaration) isAttribDeclaration() inout pure @safe
{
return this;
}
return "static if";
}
+ override inout(StaticIfDeclaration) isStaticIfDeclaration() inout pure @safe
+ {
+ return this;
+ }
+
override void accept(Visitor v)
{
v.visit(this);
bool hasPointers() override final;
bool hasStaticCtorOrDtor() override final;
void checkCtorConstInit() override final;
- void addLocalClass(ClassDeclarations *) override final;
- AttribDeclaration *isAttribDeclaration() override final { return this; }
+ AttribDeclaration *isAttribDeclaration() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
void addMember(Scope *sc, ScopeDsymbol *sds) override;
void setScope(Scope *sc) override;
void importAll(Scope *sc) override;
+ StaticIfDeclaration *isStaticIfDeclaration() override { return this; }
const char *kind() const override;
void accept(Visitor *v) override { v->visit(this); }
};
bool mustNotThrow;
int result;
- extern (D) this(FuncDeclaration func, bool mustNotThrow)
+ extern (D) this(FuncDeclaration func, bool mustNotThrow) scope
{
this.func = func;
this.mustNotThrow = mustNotThrow;
CT result;
public:
- extern (D) this(FuncDeclaration func, bool mustNotThrow)
+ extern (D) this(FuncDeclaration func, bool mustNotThrow) scope
{
this.func = func;
this.mustNotThrow = mustNotThrow;
sc.minst = null;
a[0] = er;
- auto f = resolveFuncCall(ad.loc, sc, assign, null, ad.type, &a, FuncResolveFlag.quiet);
+ auto f = resolveFuncCall(ad.loc, sc, assign, null, ad.type, ArgumentList(&a), FuncResolveFlag.quiet);
if (!f)
{
a[0] = el;
- f = resolveFuncCall(ad.loc, sc, assign, null, ad.type, &a, FuncResolveFlag.quiet);
+ f = resolveFuncCall(ad.loc, sc, assign, null, ad.type, ArgumentList(&a), FuncResolveFlag.quiet);
}
sc = sc.pop();
{
a[0] = e;
a[0].type = tthis;
- return resolveFuncCall(ad.loc, sc, eq, null, tthis, &a, FuncResolveFlag.quiet);
+ return resolveFuncCall(ad.loc, sc, eq, null, tthis, ArgumentList(&a), FuncResolveFlag.quiet);
}
f = rfc(er);
{
auto cldec = ad.isClassDeclaration();
if (!cldec || cldec.cppDtorVtblIndex == -1) // scalar deleting dtor not built for non-virtual dtors
- return dtor;
+ return dtor; // perhaps also do this if STC.scope_ is set
// generate deleting C++ destructor corresponding to:
// void* C::~C(int del)
Parameter delparam = new Parameter(STC.undefined_, Type.tuns32, Identifier.idPool("del"), new IntegerExp(dtor.loc, 0, Type.tuns32), null);
Parameters* params = new Parameters;
params.push(delparam);
- auto ftype = new TypeFunction(ParameterList(params), Type.tvoidptr, LINK.cpp, dtor.storage_class);
- auto func = new DtorDeclaration(dtor.loc, dtor.loc, dtor.storage_class, Id.cppdtor);
+ const stc = dtor.storage_class & ~STC.scope_; // because we add the `return this;` later
+ auto ftype = new TypeFunction(ParameterList(params), Type.tvoidptr, LINK.cpp, stc);
+ auto func = new DtorDeclaration(dtor.loc, dtor.loc, stc, Id.cppdtor);
func.type = ftype;
// Always generate the function with body, because it is not exported from DLLs.
offset += len;
}
- /// write newline
+ /// strip trailing tabs or spaces, write newline
extern (C++) void writenl() pure nothrow @safe
{
+ while (offset > 0 && (data[offset - 1] == ' ' || data[offset - 1] == '\t'))
+ offset--;
+
version (Windows)
{
writeword(0x0A0D); // newline is CR,LF on Microsoft OS's
buf.setsize(4);
assert(buf.length == 4);
}
+
+unittest
+{
+ OutBuffer buf;
+
+ buf.writenl();
+ buf.writestring("abc \t ");
+ buf.writenl(); // strips trailing whitespace
+ buf.writenl(); // doesn't strip previous newline
+
+ version(Windows)
+ assert(buf[] == "\r\nabc\r\n\r\n");
+ else
+ assert(buf[] == "\nabc\n\n");
+}
}
else
{
- if (e1.type.isreal())
- {
- cmp = CTFloat.isIdentical(e1.toReal(), e2.toReal());
- }
- else if (e1.type.isimaginary())
- {
- cmp = RealIdentical(e1.toImaginary(), e2.toImaginary());
- }
- else if (e1.type.iscomplex())
- {
- complex_t v1 = e1.toComplex();
- complex_t v2 = e2.toComplex();
- cmp = RealIdentical(creall(v1), creall(v2)) && RealIdentical(cimagl(v1), cimagl(v1));
- }
+ if (e1.type.isfloating())
+ cmp = e1.isIdentical(e2);
else
{
ue = Equal((op == EXP.identity) ? EXP.equal : EXP.notEqual, loc, type, e1, e2);
import core.stdc.stdio;
import core.stdc.string;
import dmd.astenums;
+import dmd.errorsink;
import dmd.globals;
import dmd.id;
import dmd.identifier;
OutBuffer* defines;
extern (D) this(TARGET)(AST.Module _module, const(char)[] input, bool doDocComment,
- const ref TARGET target, OutBuffer* defines)
+ ErrorSink errorSink,
+ const ref TARGET target, OutBuffer* defines) scope
{
- super(_module, input, doDocComment);
+ super(_module, input, doDocComment, errorSink);
//printf("CParser.this()\n");
mod = _module;
case TOK.minusMinus:
case TOK.sizeof_:
case TOK._Generic:
+ case TOK._assert:
Lexp:
auto exp = cparseExpression();
if (token.value == TOK.identifier && exp.op == EXP.identifier)
{
- error("found `%s` when expecting `;` or `=`, did you mean `%s %s = %s`?", peek(&token).toChars(), exp.toChars(), token.toChars(), peek(peek(&token)).toChars());
+ error(token.loc, "found `%s` when expecting `;` or `=`, did you mean `%s %s = %s`?", peek(&token).toChars(), exp.toChars(), token.toChars(), peek(peek(&token)).toChars());
nextToken();
}
else
case TOK.int16:
case TOK.int32:
case TOK.int64:
+ case TOK.__int128:
case TOK.float32:
case TOK.float64:
case TOK.signed:
if (token.postfix)
{
if (token.postfix != postfix)
- error("mismatched string literal postfixes `'%c'` and `'%c'`", postfix, token.postfix);
+ error(token.loc, "mismatched string literal postfixes `'%c'` and `'%c'`", postfix, token.postfix);
postfix = token.postfix;
}
e = cparseGenericSelection();
break;
+ case TOK._assert: // __check(assign-exp) extension
+ nextToken();
+ check(TOK.leftParenthesis, "`__check`");
+ e = parseAssignExp();
+ check(TOK.rightParenthesis);
+ e = new AST.AssertExp(loc, e, null);
+ break;
+
default:
error("expression expected, not `%s`", token.toChars());
// Anything for e, as long as it's not NULL
specifier.packalign = this.packalign;
auto tspec = cparseDeclarationSpecifiers(level, specifier);
+ AST.Dsymbol declareTag(AST.TypeTag tt, ref Specifier specifier)
+ {
+ /* `struct tag;` and `struct tag { ... };`
+ * always result in a declaration in the current scope
+ */
+ auto stag = (tt.tok == TOK.struct_) ? new AST.StructDeclaration(tt.loc, tt.id, false) :
+ (tt.tok == TOK.union_) ? new AST.UnionDeclaration(tt.loc, tt.id) :
+ new AST.EnumDeclaration(tt.loc, tt.id, tt.base);
+ stag.members = tt.members;
+ tt.members = null;
+ if (!symbols)
+ symbols = new AST.Dsymbols();
+ auto stags = applySpecifier(stag, specifier);
+ symbols.push(stags);
+ return stags;
+ }
+
/* If a declarator does not follow, it is unnamed
*/
if (token.value == TOK.semicolon)
!tt.id && (tt.tok == TOK.struct_ || tt.tok == TOK.union_))
return; // legal but meaningless empty declaration, ignore it
- /* `struct tag;` and `struct tag { ... };`
- * always result in a declaration in the current scope
- */
- auto stag = (tt.tok == TOK.struct_) ? new AST.StructDeclaration(tt.loc, tt.id, false) :
- (tt.tok == TOK.union_) ? new AST.UnionDeclaration(tt.loc, tt.id) :
- new AST.EnumDeclaration(tt.loc, tt.id, tt.base);
- stag.members = tt.members;
- if (!symbols)
- symbols = new AST.Dsymbols();
- auto stags = applySpecifier(stag, specifier);
- symbols.push(stags);
+ auto stags = declareTag(tt, specifier);
if (0 && tt.tok == TOK.enum_) // C11 proscribes enums with no members, but we allow it
{
if (!tt.members)
- error(tt.loc, "`enum %s` has no members", stag.toChars());
+ error(tt.loc, "`enum %s` has no members", stags.toChars());
}
return;
}
{
if (tt.id || tt.tok == TOK.enum_)
{
- /* `struct tag;` and `struct tag { ... };`
- * always result in a declaration in the current scope
- */
- auto stag = (tt.tok == TOK.struct_) ? new AST.StructDeclaration(tt.loc, tt.id, false) :
- (tt.tok == TOK.union_) ? new AST.UnionDeclaration(tt.loc, tt.id) :
- new AST.EnumDeclaration(tt.loc, tt.id, tt.base);
- stag.members = tt.members;
- tt.members = null;
- if (!symbols)
- symbols = new AST.Dsymbols();
- symbols.push(stag);
+ if (!tt.id && id)
+ tt.id = id;
+ Specifier spec;
+ auto stag = declareTag(tt, spec);
if (tt.tok == TOK.enum_)
{
isalias = false;
}
else if (id)
{
+ if (auto tt = dt.isTypeTag())
+ {
+ if (tt.members && (tt.id || tt.tok == TOK.enum_))
+ {
+ Specifier spec;
+ declareTag(tt, spec);
+ }
+ }
+
if (level == LVL.prototype)
break; // declared later as Parameter, not VarDeclaration
case TOK.identifier:
if (s)
{
- error("missing comma or semicolon after declaration of `%s`, found `%s` instead", s.toChars(), token.toChars());
+ error(token.loc, "missing comma or semicolon after declaration of `%s`, found `%s` instead", s.toChars(), token.toChars());
goto Lend;
}
goto default;
importBuiltins = true; // will need __va_list_tag
auto plLength = pl.length;
if (symbols.length != plLength)
- error("%d identifiers does not match %d declarations", cast(int)plLength, cast(int)symbols.length);
+ error(token.loc, "%d identifiers does not match %d declarations", cast(int)plLength, cast(int)symbols.length);
/* Transfer the types and storage classes from symbols[] to pl[]
*/
ximaginary = 0x8000,
xcomplex = 0x10000,
x_Atomic = 0x20000,
+ xint128 = 0x40000,
}
AST.Type t;
case TOK.int16: tkwx = TKW.xshort; break;
case TOK.int32: tkwx = TKW.xint; break;
case TOK.int64: tkwx = TKW.xlong; break;
+ case TOK.__int128: tkwx = TKW.xint128; break;
case TOK.float32: tkwx = TKW.xfloat; break;
case TOK.float64: tkwx = TKW.xdouble; break;
case TOK.void_: tkwx = TKW.xvoid; break;
case TKW.xunsigned | TKW.xllong | TKW.xint:
case TKW.xunsigned | TKW.xllong: t = unsignedTypeForSize(long_longsize); break;
+ case TKW.xint128:
+ case TKW.xsigned | TKW.xint128: t = integerTypeForSize(16); break;
+
+ case TKW.xunsigned | TKW.xint128: t = unsignedTypeForSize(16); break;
+
case TKW.xvoid: t = AST.Type.tvoid; break;
case TKW.xbool: t = boolsize == 1 ? AST.Type.tbool : integerTypeForSize(boolsize); break;
auto param = new AST.Parameter(specifiersToSTC(LVL.parameter, specifier),
t, id, null, null);
parameters.push(param);
- if (token.value == TOK.rightParenthesis)
+ if (token.value == TOK.rightParenthesis || token.value == TOK.endOfFile)
break;
check(TOK.comma);
}
- nextToken();
+ check(TOK.rightParenthesis);
return finish();
}
case TOK._Complex:
case TOK._Thread_local:
case TOK.int32:
+ case TOK.__int128:
case TOK.char_:
case TOK.float32:
case TOK.float64:
case TOK.int16:
case TOK.int32:
case TOK.int64:
+ case TOK.__int128:
case TOK.float32:
case TOK.float64:
case TOK.signed:
case TOK.int16:
case TOK.int32:
case TOK.int64:
+ case TOK.__int128:
case TOK.float32:
case TOK.float64:
case TOK.void_:
return AST.Type.tint32;
if (size <= 8)
return AST.Type.tint64;
+ if (size == 16)
+ {
+ error("__int128 not supported");
+ return AST.Type.terror;
+ }
error("unsupported integer type");
return AST.Type.terror;
}
return AST.Type.tuns32;
if (size <= 8)
return AST.Type.tuns64;
+ if (size == 16)
+ {
+ error("unsigned __int128 not supported");
+ return AST.Type.terror;
+ }
error("unsupported integer type");
return AST.Type.terror;
}
if (n.value == TOK.identifier && n.ident == Id.show)
{
if (packalign.isDefault())
- warning(startloc, "current pack attribute is default");
+ eSink.warning(startloc, "current pack attribute is default");
else
- warning(startloc, "current pack attribute is %d", packalign.get());
+ eSink.warning(startloc, "current pack attribute is %d", packalign.get());
scan(&n);
return closingParen();
}
void addVar(AST.VarDeclaration v)
{
+ //printf("addVar() %s\n", v.toChars());
+ v.isCmacro(true); // mark it as coming from a C #define
/* If it's already defined, replace the earlier
* definition
*/
* buf = `OutBuffer` to write the mangling to
* loc = `Loc` of the symbol being mangled
*/
- this(OutBuffer* buf, Loc loc)
+ this(OutBuffer* buf, Loc loc) scope
{
this.buf = buf;
this.loc = loc;
{
return e1.toInteger() != e2.toInteger();
}
+ if (identity && e1.type.isfloating())
+ return !e1.isIdentical(e2);
if (e1.type.isreal() || e1.type.isimaginary())
{
real_t r1 = e1.type.isreal() ? e1.toReal() : e1.toImaginary();
real_t r2 = e1.type.isreal() ? e2.toReal() : e2.toImaginary();
- if (identity)
- return !CTFloat.isIdentical(r1, r2);
if (CTFloat.isNaN(r1) || CTFloat.isNaN(r2)) // if unordered
{
return 1; // they are not equal
}
else if (e1.type.iscomplex())
{
- auto c1 = e1.toComplex();
- auto c2 = e2.toComplex();
- if (identity)
- {
- return !RealIdentical(c1.re, c2.re) && !RealIdentical(c1.im, c2.im);
- }
- return c1 != c2;
+ return e1.toComplex() != e2.toComplex();
}
if (e1.op == EXP.structLiteral && e2.op == EXP.structLiteral)
{
SymOffExp es2 = e2.isSymOffExp();
cmp = (es1.var == es2.var && es1.offset == es2.offset);
}
- else if (e1.type.isreal())
- cmp = CTFloat.isIdentical(e1.toReal(), e2.toReal());
- else if (e1.type.isimaginary())
- cmp = RealIdentical(e1.toImaginary(), e2.toImaginary());
- else if (e1.type.iscomplex())
- {
- complex_t v1 = e1.toComplex();
- complex_t v2 = e2.toComplex();
- cmp = RealIdentical(creall(v1), creall(v2)) && RealIdentical(cimagl(v1), cimagl(v1));
- }
+ else if (e1.type.isfloating())
+ cmp = e1.isIdentical(e2);
else
{
cmp = !ctfeRawCmp(loc, e1, e2, true);
*/
Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
{
+ //printf("castTo(e: %s from: %s to: %s\n", e.toChars(), e.type.toChars(), t.toChars());
+
Expression visit(Expression e)
{
//printf("Expression::castTo(this=%s, t=%s)\n", e.toChars(), t.toChars());
/****************************************
*/
- override final void addLocalClass(ClassDeclarations* aclasses)
- {
- if (classKind != ClassKind.objc)
- aclasses.push(this);
- }
-
override final void addObjcSymbols(ClassDeclarations* classes, ClassDeclarations* categories)
{
.objc.addSymbols(this, classes, categories);
{
Initializer _init;
FuncDeclarations nestedrefs; // referenced by these lexically nested functions
- Dsymbol aliassym; // if redone as alias to another symbol
+ TupleDeclaration aliasTuple; // when `this` is really a tuple of declarations
VarDeclaration lastVar; // Linked list of variables for goto-skips-init detection
Expression edtor; // if !=null, does the destruction of the variable
IntRange* range; // if !=null, the variable is known to be within the range
bool doNotInferReturn; /// do not infer 'return' for this variable
bool isArgDtorVar; /// temporary created to handle scope destruction of a function argument
+ bool isCmacro; /// it is a C macro turned into a C declaration
+ version (MARS)
+ {
+ bool inClosure; /// is inserted into a GC allocated closure
+ bool inAlignSection; /// is inserted into an aligned section on stack
+ }
}
import dmd.common.bitfields : generateBitFields;
{
//printf("VarDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), toChars());
- if (aliassym)
+ if (aliasTuple)
{
// If this variable was really a tuple, set the offsets for the tuple fields
- TupleDeclaration v2 = aliassym.isTupleDeclaration();
- assert(v2);
- v2.foreachVar((s) { s.setFieldOffset(ad, fieldState, isunion); });
+ aliasTuple.foreachVar((s) { s.setFieldOffset(ad, fieldState, isunion); });
return;
}
override final bool isImportedSymbol() const
{
- if (visibility.kind == Visibility.Kind.export_ && !_init && (storage_class & STC.static_ || parent.isModule()))
- return true;
- return false;
+ /* If global variable has `export` and `extern` then it is imported
+ * export int sym1; // definition: exported
+ * export extern int sym2; // declaration: imported
+ * export extern int sym3 = 0; // error, extern cannot have initializer
+ */
+ bool result =
+ visibility.kind == Visibility.Kind.export_ &&
+ storage_class & STC.extern_ &&
+ (storage_class & STC.static_ || parent.isModule());
+ //printf("isImportedSymbol() %s %d\n", toChars(), result);
+ return result;
}
final bool isCtorinit() const pure nothrow @nogc @safe
// Add this VarDeclaration to fdv.closureVars[] if not already there
if (!sc.intypeof && !(sc.flags & SCOPE.compile) &&
// https://issues.dlang.org/show_bug.cgi?id=17605
- (fdv.isCompileTimeOnly || !fdthis.isCompileTimeOnly)
- )
+ (fdv.skipCodegen || !fdthis.skipCodegen))
{
if (!fdv.closureVars.contains(this))
fdv.closureVars.push(this);
if ((!type || !type.deco) && _scope)
dsymbolSemantic(this, _scope);
- assert(this != aliassym);
- Dsymbol s = aliassym ? aliassym.toAlias() : this;
+ assert(this != aliasTuple);
+ Dsymbol s = aliasTuple ? aliasTuple.toAlias() : this;
return s;
}
public:
Initializer *_init;
FuncDeclarations nestedrefs; // referenced by these lexically nested functions
- Dsymbol *aliassym; // if redone as alias to another symbol
+ TupleDeclaration *aliasTuple; // if `this` is really a tuple of declarations
VarDeclaration *lastVar; // Linked list of variables for goto-skips-init detection
Expression *edtor; // if !=NULL, does the destruction of the variable
IntRange *range; // if !NULL, the variable is known to be within the range
bool doNotInferReturn(bool v);
bool isArgDtorVar() const; // temporary created to handle scope destruction of a function argument
bool isArgDtorVar(bool v);
+ bool isCmacro() const; // if a C macro turned into a C variable
+ bool isCmacro(bool v);
+#if MARS
+ bool inClosure() const; // is inserted into a GC allocated closure
+ bool inClosure(bool v);
+ bool inAlignSection() const; // is inserted into aligned section on stack
+ bool inAlignSection(bool v);
+#endif
static VarDeclaration *create(const Loc &loc, Type *t, Identifier *id, Initializer *init, StorageClass storage_class = STCundefined);
VarDeclaration *syntaxCopy(Dsymbol *) override;
void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override final;
bool inferScope(bool v);
bool hasCatches() const;
bool hasCatches(bool v);
- bool isCompileTimeOnly() const;
- bool isCompileTimeOnly(bool v);
+ bool skipCodegen() const;
+ bool skipCodegen(bool v);
bool printf() const;
bool printf(bool v);
bool scanf() const;
BaseClass *overrideInterface();
bool overloadInsert(Dsymbol *s) override;
bool inUnittest();
- MATCH leastAsSpecialized(FuncDeclaration *g);
+ MATCH leastAsSpecialized(FuncDeclaration *g, Identifiers *names);
LabelDsymbol *searchLabel(Identifier *ident, const Loc &loc);
int getLevel(FuncDeclaration *fd, int intypeof); // lexical nesting level difference
int getLevelAndCheck(const Loc &loc, Scope *sc, FuncDeclaration *fd);
}
public:
- extern (D) this(FuncDeclaration fd)
+ extern (D) this(FuncDeclaration fd) scope
{
this.fd = fd;
}
Scope* sc;
bool result;
- extern (D) this(Scope* sc)
+ extern (D) this(Scope* sc) scope
{
this.sc = sc;
}
Expression result;
UnionExp* pue; // storage for `result`
- extern (D) this(UnionExp* pue, InterState* istate, CTFEGoal goal)
+ extern (D) this(UnionExp* pue, InterState* istate, CTFEGoal goal) scope
{
this.pue = pue;
this.istate = istate;
module dmd.dmangle;
-import dmd.astenums;
/******************************************************************************
* Returns exact mangled name of function.
*/
extern (C++) const(char)* mangleExact(FuncDeclaration fd)
{
+ //printf("mangleExact()\n");
if (!fd.mangleString)
{
OutBuffer buf;
- scope Mangler v = new Mangler(&buf);
+ auto backref = Backref(null);
+ scope Mangler v = new Mangler(&buf, &backref);
v.mangleExact(fd);
fd.mangleString = buf.extractChars();
}
extern (C++) void mangleToBuffer(Type t, OutBuffer* buf)
{
+ //printf("mangleToBuffer t()\n");
if (t.deco)
buf.writestring(t.deco);
else
{
- scope Mangler v = new Mangler(buf, t);
- v.visitWithMask(t, 0);
+ auto backref = Backref(t);
+ mangleType(t, 0, buf, backref);
+ //printf("%s\n", buf.peekChars());
}
}
extern (C++) void mangleToBuffer(Expression e, OutBuffer* buf)
{
- scope Mangler v = new Mangler(buf);
+ //printf("mangleToBuffer e()\n");
+ auto backref = Backref(null);
+ scope Mangler v = new Mangler(buf, &backref);
e.accept(v);
}
extern (C++) void mangleToBuffer(Dsymbol s, OutBuffer* buf)
{
- scope Mangler v = new Mangler(buf);
+ //printf("mangleToBuffer s(%s)\n", s.toChars());
+ auto backref = Backref(null);
+ scope Mangler v = new Mangler(buf, &backref);
s.accept(v);
}
extern (C++) void mangleToBuffer(TemplateInstance ti, OutBuffer* buf)
{
- scope Mangler v = new Mangler(buf);
+ //printf("mangleToBuffer ti()\n");
+ auto backref = Backref(null);
+ scope Mangler v = new Mangler(buf, &backref);
v.mangleTemplateInstance(ti);
}
import dmd.aggregate;
import dmd.arraytypes;
+import dmd.astenums;
import dmd.dclass;
import dmd.declaration;
import dmd.dmodule;
}
}
-private extern (C++) final class Mangler : Visitor
+/************************************************
+ * Append the mangling of type `t` to `buf`.
+ * Params:
+ * t = type to mangle
+ * modMask = mod bits currently applying to t
+ * buf = buffer to append mangling to
+ * backref = state of back references (updated)
+ */
+void mangleType(Type t, ubyte modMask, OutBuffer* buf, ref Backref backref)
{
- alias visit = Visitor.visit;
-public:
- static assert(Key.sizeof == size_t.sizeof);
-
- OutBuffer* buf;
- Backref backref;
-
- extern (D) this(OutBuffer* buf, Type rootType = null)
- {
- this.buf = buf;
- this.backref = Backref(rootType);
- }
-
- void mangleSymbol(Dsymbol s)
- {
- s.accept(this);
- }
-
- void mangleType(Type t)
+ void visitWithMask(Type t, ubyte modMask)
{
- if (!backref.addRefToType(buf, t))
- t.accept(this);
- }
+ void mangleSymbol(Dsymbol s)
+ {
+ scope Mangler v = new Mangler(buf, &backref);
+ v.mangleSymbol(s);
+ }
- void mangleIdentifier(Identifier id, Dsymbol s)
- {
- if (!backref.addRefToIdentifier(buf, id))
- toBuffer(buf, id.toString(), s);
- }
+ void visitType(Type t)
+ {
+ tyToDecoBuffer(buf, t.ty);
+ }
- ////////////////////////////////////////////////////////////////////////////
- /**************************************************
- * Type mangling
- */
- void visitWithMask(Type t, ubyte modMask)
- {
- if (modMask != t.mod)
+ void visitTypeNext(TypeNext t)
{
- MODtoDecoBuffer(buf, t.mod);
+ visitType(t);
+ visitWithMask(t.next, t.mod);
}
- mangleType(t);
- }
- override void visit(Type t)
- {
- tyToDecoBuffer(buf, t.ty);
- }
+ void visitTypeVector(TypeVector t)
+ {
+ buf.writestring("Nh");
+ visitWithMask(t.basetype, t.mod);
+ }
- override void visit(TypeNext t)
- {
- visit(cast(Type)t);
- visitWithMask(t.next, t.mod);
- }
+ void visitTypeSArray(TypeSArray t)
+ {
+ visitType(t);
+ if (t.dim)
+ buf.print(t.dim.toInteger());
+ if (t.next)
+ visitWithMask(t.next, t.mod);
+ }
- override void visit(TypeVector t)
- {
- buf.writestring("Nh");
- visitWithMask(t.basetype, t.mod);
- }
+ void visitTypeDArray(TypeDArray t)
+ {
+ visitType(t);
+ if (t.next)
+ visitWithMask(t.next, t.mod);
+ }
- override void visit(TypeSArray t)
- {
- visit(cast(Type)t);
- if (t.dim)
- buf.print(t.dim.toInteger());
- if (t.next)
+ void visitTypeAArray(TypeAArray t)
+ {
+ visitType(t);
+ visitWithMask(t.index, 0);
visitWithMask(t.next, t.mod);
- }
+ }
- override void visit(TypeDArray t)
- {
- visit(cast(Type)t);
- if (t.next)
- visitWithMask(t.next, t.mod);
- }
+ void visitTypeFunction(TypeFunction t)
+ {
+ //printf("TypeFunction.toDecoBuffer() t = %p %s\n", t, t.toChars());
+ //static int nest; if (++nest == 50) *(char*)0=0;
+ mangleFuncType(t, t, t.mod, t.next, buf, backref);
+ }
- override void visit(TypeAArray t)
- {
- visit(cast(Type)t);
- visitWithMask(t.index, 0);
- visitWithMask(t.next, t.mod);
- }
+ void visitTypeIdentifier(TypeIdentifier t)
+ {
+ visitType(t);
+ auto name = t.ident.toString();
+ buf.print(cast(int)name.length);
+ buf.writestring(name);
+ }
- override void visit(TypeFunction t)
- {
- //printf("TypeFunction.toDecoBuffer() t = %p %s\n", t, t.toChars());
- //static int nest; if (++nest == 50) *(char*)0=0;
- mangleFuncType(t, t, t.mod, t.next);
- }
+ void visitTypeEnum(TypeEnum t)
+ {
+ visitType(t);
+ mangleSymbol(t.sym);
+ }
- void mangleFuncType(TypeFunction t, TypeFunction ta, ubyte modMask, Type tret)
- {
- //printf("mangleFuncType() %s\n", t.toChars());
- if (t.inuse && tret)
+ void visitTypeStruct(TypeStruct t)
{
- // printf("TypeFunction.mangleFuncType() t = %s inuse\n", t.toChars());
- t.inuse = 2; // flag error to caller
- return;
+ //printf("TypeStruct.toDecoBuffer('%s') = '%s'\n", t.toChars(), name);
+ visitType(t);
+ mangleSymbol(t.sym);
}
- t.inuse++;
- if (modMask != t.mod)
- MODtoDecoBuffer(buf, t.mod);
- char mc;
- final switch (t.linkage)
+ void visitTypeClass(TypeClass t)
{
- case LINK.default_:
- case LINK.d:
- mc = 'F';
- break;
- case LINK.c:
- mc = 'U';
- break;
- case LINK.windows:
- mc = 'W';
- break;
- case LINK.cpp:
- mc = 'R';
- break;
- case LINK.objc:
- mc = 'Y';
- break;
- case LINK.system:
- assert(0);
+ //printf("TypeClass.toDecoBuffer('%s' mod=%x) = '%s'\n", t.toChars(), mod, name);
+ visitType(t);
+ mangleSymbol(t.sym);
}
- buf.writeByte(mc);
-
- if (ta.purity)
- buf.writestring("Na");
- if (ta.isnothrow)
- buf.writestring("Nb");
- if (ta.isref)
- buf.writestring("Nc");
- if (ta.isproperty)
- buf.writestring("Nd");
- if (ta.isnogc)
- buf.writestring("Ni");
-
- // `return scope` must be in that order
- if (ta.isreturnscope && !ta.isreturninferred)
+
+ void visitTypeTuple(TypeTuple t)
{
- buf.writestring("NjNl");
+ //printf("TypeTuple.toDecoBuffer() t = %p, %s\n", t, t.toChars());
+ visitType(t);
+ Parameter._foreach(t.arguments, (idx, param) {
+ mangleParameter(param, buf, backref);
+ return 0;
+ });
+ buf.writeByte('Z');
}
- else
+
+ void visitTypeNull(TypeNull t)
{
- // when return ref, the order is `scope return`
- if (ta.isScopeQual && !ta.isscopeinferred)
- buf.writestring("Nl");
+ visitType(t);
+ }
- if (ta.isreturn && !ta.isreturninferred)
- buf.writestring("Nj");
+ void visitTypeNoreturn(TypeNoreturn t)
+ {
+ buf.writestring("Nn");
}
- if (ta.islive)
- buf.writestring("Nm");
+ if (modMask != t.mod)
+ {
+ MODtoDecoBuffer(buf, t.mod);
+ }
+ if (backref.addRefToType(buf, t))
+ return;
- switch (ta.trust)
+ switch (t.ty)
{
- case TRUST.trusted:
- buf.writestring("Ne");
- break;
- case TRUST.safe:
- buf.writestring("Nf");
- break;
- default:
- break;
+ case Tpointer:
+ case Treference:
+ case Tdelegate:
+ case Tslice: visitTypeNext (cast(TypeNext)t); break;
+
+ case Tarray: visitTypeDArray (t.isTypeDArray()); break;
+ case Tsarray: visitTypeSArray (t.isTypeSArray()); break;
+ case Taarray: visitTypeAArray (t.isTypeAArray()); break;
+ case Tfunction: visitTypeFunction (t.isTypeFunction()); break;
+ case Tident: visitTypeIdentifier(t.isTypeIdentifier()); break;
+ case Tclass: visitTypeClass (t.isTypeClass()); break;
+ case Tstruct: visitTypeStruct (t.isTypeStruct()); break;
+ case Tenum: visitTypeEnum (t.isTypeEnum()); break;
+ case Ttuple: visitTypeTuple (t.isTypeTuple()); break;
+ case Tnull: visitTypeNull (t.isTypeNull()); break;
+ case Tvector: visitTypeVector (t.isTypeVector()); break;
+ case Tnoreturn: visitTypeNoreturn (t.isTypeNoreturn); break;
+
+ case Terror:
+ break; // ignore errors
+
+ default: visitType(t); break;
}
+ }
- // Write argument types
- foreach (idx, param; t.parameterList)
- mangleParameter(param);
- //if (buf.data[buf.length - 1] == '@') assert(0);
- buf.writeByte('Z' - t.parameterList.varargs); // mark end of arg list
- if (tret !is null)
- visitWithMask(tret, 0);
- t.inuse--;
+ visitWithMask(t, modMask);
+}
+
+
+/*************************************************************
+ */
+void mangleFuncType(TypeFunction t, TypeFunction ta, ubyte modMask, Type tret, OutBuffer* buf, ref Backref backref)
+{
+ //printf("mangleFuncType() %s\n", t.toChars());
+ if (t.inuse && tret)
+ {
+ // printf("TypeFunction.mangleFuncType() t = %s inuse\n", t.toChars());
+ t.inuse = 2; // flag error to caller
+ return;
}
+ t.inuse++;
+ if (modMask != t.mod)
+ MODtoDecoBuffer(buf, t.mod);
- override void visit(TypeIdentifier t)
+ char mc;
+ final switch (t.linkage)
+ {
+ case LINK.default_:
+ case LINK.d:
+ mc = 'F';
+ break;
+ case LINK.c:
+ mc = 'U';
+ break;
+ case LINK.windows:
+ mc = 'W';
+ break;
+ case LINK.cpp:
+ mc = 'R';
+ break;
+ case LINK.objc:
+ mc = 'Y';
+ break;
+ case LINK.system:
+ assert(0);
+ }
+ buf.writeByte(mc);
+
+ if (ta.purity)
+ buf.writestring("Na");
+ if (ta.isnothrow)
+ buf.writestring("Nb");
+ if (ta.isref)
+ buf.writestring("Nc");
+ if (ta.isproperty)
+ buf.writestring("Nd");
+ if (ta.isnogc)
+ buf.writestring("Ni");
+
+ // `return scope` must be in that order
+ if (ta.isreturnscope && !ta.isreturninferred)
+ {
+ buf.writestring("NjNl");
+ }
+ else
{
- visit(cast(Type)t);
- auto name = t.ident.toString();
- buf.print(cast(int)name.length);
- buf.writestring(name);
+ // when return ref, the order is `scope return`
+ if (ta.isScopeQual && !ta.isscopeinferred)
+ buf.writestring("Nl");
+
+ if (ta.isreturn && !ta.isreturninferred)
+ buf.writestring("Nj");
}
- override void visit(TypeEnum t)
+ if (ta.islive)
+ buf.writestring("Nm");
+
+ switch (ta.trust)
{
- visit(cast(Type)t);
- mangleSymbol(t.sym);
+ case TRUST.trusted:
+ buf.writestring("Ne");
+ break;
+ case TRUST.safe:
+ buf.writestring("Nf");
+ break;
+ default:
+ break;
}
- override void visit(TypeStruct t)
+ // Write argument types
+ foreach (idx, param; t.parameterList)
+ mangleParameter(param, buf, backref);
+ //if (buf.data[buf.length - 1] == '@') assert(0);
+ buf.writeByte('Z' - t.parameterList.varargs); // mark end of arg list
+ if (tret !is null)
+ mangleType(tret, 0, buf, backref);
+ t.inuse--;
+}
+
+/*************************************************************
+ */
+void mangleParameter(Parameter p, OutBuffer* buf, ref Backref backref)
+{
+ // https://dlang.org/spec/abi.html#Parameter
+
+ auto stc = p.storageClass;
+
+ // Inferred storage classes don't get mangled in
+ if (stc & STC.scopeinferred)
+ stc &= ~(STC.scope_ | STC.scopeinferred);
+ if (stc & STC.returninferred)
+ stc &= ~(STC.return_ | STC.returninferred);
+
+ // much like hdrgen.stcToBuffer()
+ string rrs;
+ const isout = (stc & STC.out_) != 0;
+ final switch (buildScopeRef(stc))
{
- //printf("TypeStruct.toDecoBuffer('%s') = '%s'\n", t.toChars(), name);
- visit(cast(Type)t);
- mangleSymbol(t.sym);
+ case ScopeRef.None:
+ case ScopeRef.Scope:
+ case ScopeRef.Ref:
+ case ScopeRef.Return:
+ case ScopeRef.RefScope:
+ break;
+
+ case ScopeRef.ReturnScope: rrs = "NkM"; goto L1; // return scope
+ case ScopeRef.ReturnRef: rrs = isout ? "NkJ" : "NkK"; goto L1; // return ref
+ case ScopeRef.ReturnRef_Scope: rrs = isout ? "MNkJ" : "MNkK"; goto L1; // scope return ref
+ case ScopeRef.Ref_ReturnScope: rrs = isout ? "NkMJ" : "NkMK"; goto L1; // return scope ref
+ L1:
+ buf.writestring(rrs);
+ stc &= ~(STC.out_ | STC.scope_ | STC.ref_ | STC.return_);
+ break;
}
- override void visit(TypeClass t)
+ if (stc & STC.scope_)
+ buf.writeByte('M'); // scope
+
+ if (stc & STC.return_)
+ buf.writestring("Nk"); // return
+
+ switch (stc & (STC.IOR | STC.lazy_))
{
- //printf("TypeClass.toDecoBuffer('%s' mod=%x) = '%s'\n", t.toChars(), mod, name);
- visit(cast(Type)t);
- mangleSymbol(t.sym);
+ case 0:
+ break;
+ case STC.in_:
+ buf.writeByte('I');
+ break;
+ case STC.in_ | STC.ref_:
+ buf.writestring("IK");
+ break;
+ case STC.out_:
+ buf.writeByte('J');
+ break;
+ case STC.ref_:
+ buf.writeByte('K');
+ break;
+ case STC.lazy_:
+ buf.writeByte('L');
+ break;
+ default:
+ debug
+ {
+ printf("storageClass = x%llx\n", stc & (STC.IOR | STC.lazy_));
+ }
+ assert(0);
}
+ mangleType(p.type, (stc & STC.in_) ? MODFlags.const_ : 0, buf, backref);
+}
+
+
+private extern (C++) final class Mangler : Visitor
+{
+ alias visit = Visitor.visit;
+public:
+ static assert(Key.sizeof == size_t.sizeof);
- override void visit(TypeTuple t)
+ OutBuffer* buf;
+ Backref* backref;
+
+ extern (D) this(OutBuffer* buf, Backref* backref)
{
- //printf("TypeTuple.toDecoBuffer() t = %p, %s\n", t, t.toChars());
- visit(cast(Type)t);
- Parameter._foreach(t.arguments, (idx, param) {
- mangleParameter(param);
- return 0;
- });
- buf.writeByte('Z');
+ this.buf = buf;
+ this.backref = backref;
}
- override void visit(TypeNull t)
+ void mangleSymbol(Dsymbol s)
{
- visit(cast(Type)t);
+ s.accept(this);
}
- override void visit(TypeNoreturn t)
+ void mangleIdentifier(Identifier id, Dsymbol s)
{
- buf.writestring("Nn");
+ if (!backref.addRefToIdentifier(buf, id))
+ toBuffer(buf, id.toString(), s);
}
////////////////////////////////////////////////////////////////////////////
}
else if (sthis.type)
{
- visitWithMask(sthis.type, 0);
+ mangleType(sthis.type, 0, buf, *backref);
}
else
assert(0);
{
TypeFunction tf = fd.type.isTypeFunction();
TypeFunction tfo = fd.originalType.isTypeFunction();
- mangleFuncType(tf, tfo, 0, null);
+ mangleFuncType(tf, tfo, 0, null, buf, *backref);
}
else
{
- visitWithMask(fd.type, 0);
+ mangleType(fd.type, 0, buf, *backref);
}
}
if (ta)
{
buf.writeByte('T');
- visitWithMask(ta, 0);
+ mangleType(ta, 0, buf, *backref);
}
else if (ea)
{
/* Use type mangling that matches what it would be for a function parameter
*/
- visitWithMask(ea.type, 0);
+ mangleType(ea.type, 0, buf, *backref);
ea.accept(this);
}
else if (sa)
else
mangleSymbol(e.fd);
}
-
- ////////////////////////////////////////////////////////////////////////////
-
- void mangleParameter(Parameter p)
- {
- // https://dlang.org/spec/abi.html#Parameter
-
- auto stc = p.storageClass;
-
- // Inferred storage classes don't get mangled in
- if (stc & STC.scopeinferred)
- stc &= ~(STC.scope_ | STC.scopeinferred);
- if (stc & STC.returninferred)
- stc &= ~(STC.return_ | STC.returninferred);
-
- // much like hdrgen.stcToBuffer()
- string rrs;
- const isout = (stc & STC.out_) != 0;
- final switch (buildScopeRef(stc))
- {
- case ScopeRef.None:
- case ScopeRef.Scope:
- case ScopeRef.Ref:
- case ScopeRef.Return:
- case ScopeRef.RefScope:
- break;
-
- case ScopeRef.ReturnScope: rrs = "NkM"; goto L1; // return scope
- case ScopeRef.ReturnRef: rrs = isout ? "NkJ" : "NkK"; goto L1; // return ref
- case ScopeRef.ReturnRef_Scope: rrs = isout ? "MNkJ" : "MNkK"; goto L1; // scope return ref
- case ScopeRef.Ref_ReturnScope: rrs = isout ? "NkMJ" : "NkMK"; goto L1; // return scope ref
- L1:
- buf.writestring(rrs);
- stc &= ~(STC.out_ | STC.scope_ | STC.ref_ | STC.return_);
- break;
- }
-
- if (stc & STC.scope_)
- buf.writeByte('M'); // scope
-
- if (stc & STC.return_)
- buf.writestring("Nk"); // return
-
- switch (stc & (STC.IOR | STC.lazy_))
- {
- case 0:
- break;
- case STC.in_:
- buf.writeByte('I');
- break;
- case STC.in_ | STC.ref_:
- buf.writestring("IK");
- break;
- case STC.out_:
- buf.writeByte('J');
- break;
- case STC.ref_:
- buf.writeByte('K');
- break;
- case STC.lazy_:
- buf.writeByte('L');
- break;
- default:
- debug
- {
- printf("storageClass = x%llx\n", stc & (STC.IOR | STC.lazy_));
- }
- assert(0);
- }
- visitWithMask(p.type, (stc & STC.in_) ? MODFlags.const_ : 0);
- }
}
/***************************************
char[36] buffer = void;
// 'A' format yields [-]0xh.hhhhp+-d
- const n = CTFloat.sprint(buffer.ptr, 'A', value);
+ const n = CTFloat.sprint(buffer.ptr, buffer.length, 'A', value);
assert(n < buffer.length);
foreach (const c; buffer[2 .. n])
{
import dmd.dsymbol;
import dmd.dsymbolsem;
import dmd.errors;
+import dmd.errorsink;
import dmd.expression;
import dmd.expressionsem;
import dmd.file_manager;
{
filetype = FileType.c;
- scope p = new CParser!AST(this, buf, cast(bool) docfile, target.c, &defines);
+ scope p = new CParser!AST(this, buf, cast(bool) docfile, global.errorSink, target.c, &defines);
p.nextToken();
checkCompiledImport();
members = p.parseModule();
}
else
{
- scope p = new Parser!AST(this, buf, cast(bool) docfile);
+ scope p = new Parser!AST(this, buf, cast(bool) docfile, global.errorSink);
p.nextToken();
p.parseModuleDeclaration();
md = p.md;
}
}
+/****************************************
+ * Create array of the local classes in the Module, suitable
+ * for inclusion in ModuleInfo
+ * Params:
+ * mod = the Module
+ * aclasses = array to fill in
+ * Returns: array of local classes
+ */
+extern (C++) void getLocalClasses(Module mod, ref ClassDeclarations aclasses)
+{
+ //printf("members.length = %d\n", mod.members.length);
+ int pushAddClassDg(size_t n, Dsymbol sm)
+ {
+ if (!sm)
+ return 0;
+
+ if (auto cd = sm.isClassDeclaration())
+ {
+ // compatibility with previous algorithm
+ if (cd.parent && cd.parent.isTemplateMixin())
+ return 0;
+
+ if (cd.classKind != ClassKind.objc)
+ aclasses.push(cd);
+ }
+ return 0;
+ }
+
+ ScopeDsymbol._foreach(null, mod.members, &pushAddClassDg);
+}
+
/**
* Process the content of a source file
*
OutBuffer* buf;
Scope* sc;
- extern (D) this(ref OutBuffer buf, Scope* sc)
+ extern (D) this(ref OutBuffer buf, Scope* sc) scope
{
this.buf = &buf;
this.sc = sc;
OutBuffer* buf;
Scope* sc;
- extern (D) this(ref OutBuffer buf, Scope* sc)
+ extern (D) this(ref OutBuffer buf, Scope* sc) scope
{
this.buf = &buf;
this.sc = sc;
uint errorsave = global.startGagging();
scope Lexer lex = new Lexer(null, cast(char*)buf[].ptr, 0, buf.length - 1, 0, 1,
+ global.errorSink,
global.vendor, global.versionNumber());
OutBuffer res;
const(char)* lastp = cast(char*)buf[].ptr;
free = 0x8000, /// is on free list
fullinst = 0x10000, /// fully instantiate templates
+ ctfeBlock = 0x20000, /// inside a `if (__ctfe)` block
}
/// Flags that are carried along with a scope push()
private enum PersistentFlags =
SCOPE.contract | SCOPE.debug_ | SCOPE.ctfe | SCOPE.compile | SCOPE.constraint |
SCOPE.noaccesscheck | SCOPE.ignoresymbolvisibility |
- SCOPE.Cfile;
+ SCOPE.Cfile | SCOPE.ctfeBlock;
extern (C++) struct Scope
{
* // To call x.toString in runtime, compiler should unspeculative S!int.
* assert(x.toString() == "instantiated");
* }
+ *
+ * This results in an undefined reference to `RTInfoImpl`:
+ * class C { int a,b,c; int* p,q; }
+ * void test() { C c = new C(); }
*/
// If a template is instantiated from CT evaluated expression,
// compiler can elide its code generation.
{
if (sc.intypeof)
return;
- if (sc.flags & (SCOPE.ctfe | SCOPE.compile))
+ if (sc.flags & (SCOPE.ctfe | SCOPE.compile | SCOPE.ctfeBlock))
return;
}
return (ispod == ThreeState.yes);
}
+ /***************************************
+ * Determine if struct has copy construction (copy constructor or postblit)
+ * Returns:
+ * true if struct has copy construction
+ */
+ final bool hasCopyConstruction()
+ {
+ return postblit || hasCopyCtor;
+ }
+
override final inout(StructDeclaration) isStructDeclaration() inout @nogc nothrow pure @safe
{
return this;
sm = sm.toAlias();
TemplateDeclaration td = sm.isTemplateDeclaration();
if (!td)
- {
- .error(loc, "`%s.%s` is not a template, it is a %s", s.toPrettyChars(), ti.name.toChars(), sm.kind());
- return null;
- }
+ return null; // error but handled later
ti.tempdecl = td;
if (!ti.semanticRun)
ti.dsymbolSemantic(sc);
return false;
}
- void addLocalClass(ClassDeclarations*)
- {
- }
-
void addObjcSymbols(ClassDeclarations* classes, ClassDeclarations* categories)
{
}
inout(OverloadSet) isOverloadSet() inout { return null; }
inout(CompileDeclaration) isCompileDeclaration() inout { return null; }
inout(StaticAssert) isStaticAssert() inout { return null; }
+ inout(StaticIfDeclaration) isStaticIfDeclaration() inout { return null; }
}
/***********************************************************
auto vd = s.isVarDeclaration(); // new declaration
auto vd2 = s2.isVarDeclaration(); // existing declaration
+
+ if (vd && vd.isCmacro())
+ return vd2;
+
+ assert(!(vd2 && vd2.isCmacro()));
+
if (vd && vd2)
{
/* if one is `static` and the other isn't, the result is undefined
class AliasAssign;
class OverloadSet;
class StaticAssert;
+class StaticIfDeclaration;
struct AA;
#ifdef IN_GCC
typedef union tree_node Symbol;
virtual void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion);
virtual bool hasPointers();
virtual bool hasStaticCtorOrDtor();
- virtual void addLocalClass(ClassDeclarations *) { }
virtual void addObjcSymbols(ClassDeclarations *, ClassDeclarations *) { }
virtual void checkCtorConstInit() { }
virtual OverloadSet *isOverloadSet() { return NULL; }
virtual CompileDeclaration *isCompileDeclaration() { return NULL; }
virtual StaticAssert *isStaticAssert() { return NULL; }
+ virtual StaticIfDeclaration *isStaticIfDeclaration() { return NULL; }
void accept(Visitor *v) override { v->visit(this); }
};
return true;
}
+/*
+Tests whether the `ctor` that is part of `ti` is an rvalue constructor
+(i.e. a constructor that receives a single parameter of the same type as
+`Unqual!typeof(this)`). If that is the case and `sd` contains a copy
+constructor, than an error is issued.
+
+Params:
+ sd = struct declaration that may contin both an rvalue and copy constructor
+ ctor = constructor that will be checked if it is an evalue constructor
+ ti = template instance the ctor is part of
+
+Return:
+ `false` if ctor is not an rvalue constructor or if `sd` does not contain a
+ copy constructor. `true` otherwise
+*/
+bool checkHasBothRvalueAndCpCtor(StructDeclaration sd, CtorDeclaration ctor, TemplateInstance ti)
+{
+ auto loc = ctor.loc;
+ auto tf = cast(TypeFunction)ctor.type;
+ auto dim = tf.parameterList.length;
+ if (sd && sd.hasCopyCtor && (dim == 1 || (dim > 1 && tf.parameterList[1].defaultArg)))
+ {
+ auto param = tf.parameterList[0];
+ if (!(param.storageClass & STC.ref_) && param.type.mutableOf().unSharedOf() == sd.type.mutableOf().unSharedOf())
+ {
+ .error(loc, "cannot define both an rvalue constructor and a copy constructor for `struct %s`", sd.toChars());
+ .errorSupplemental(ti.loc, "Template instance `%s` creates an rvalue constructor for `struct %s`",
+ ti.toPrettyChars(), sd.toChars());
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
private extern(C++) final class DsymbolSemanticVisitor : Visitor
{
alias visit = Visitor.visit;
Scope* sc;
- this(Scope* sc)
+ this(Scope* sc) scope
{
this.sc = sc;
}
return;
}
+ // @@@DEPRECATED_2.121@@@
+ // Deprecated in 2.101 - Can be removed in 2.121
+ if (ad.isClassDeclaration() || ad.isInterfaceDeclaration())
+ deprecation(dsym.loc, "alias this for classes/interfaces is deprecated");
+
assert(ad.members);
Dsymbol s = ad.search(dsym.loc, dsym.ident);
if (!s)
return;
assert(dsym.semanticRun <= PASS.semantic);
+ if (!sc)
+ return;
+
+ dsym.semanticRun = PASS.semantic;
+
dsym.storage_class |= sc.stc & STC.deprecated_;
dsym.visibility = sc.visibility;
dsym.userAttribDecl = sc.userAttribDecl;
{
if (inferred)
{
- dsym.error("type `%s` is inferred from initializer `%s`, and variables cannot be of type `void`", dsym.type.toChars(), dsym._init.toChars());
+ dsym.error("- type `%s` is inferred from initializer `%s`, and variables cannot be of type `void`", dsym.type.toChars(), dsym._init.toChars());
}
else
- dsym.error("variables cannot be of type `void`");
+ dsym.error("- variables cannot be of type `void`");
dsym.type = Type.terror;
tb = dsym.type;
}
// or when the variable is defined externally
if (!ts.sym.members && !(dsym.storage_class & (STC.ref_ | STC.extern_)))
{
- dsym.error("no definition of struct `%s`", ts.toChars());
+ dsym.error("- no definition of struct `%s`", ts.toChars());
// Explain why the definition is required when it's part of another type
if (!dsym.type.isTypeStruct())
}
}
if ((dsym.storage_class & STC.auto_) && !inferred)
- dsym.error("storage class `auto` has no effect if type is not inferred, did you mean `scope`?");
+ dsym.error("- storage class `auto` has no effect if type is not inferred, did you mean `scope`?");
if (auto tt = tb.isTypeTuple())
{
auto v2 = new TupleDeclaration(dsym.loc, dsym.ident, exps);
v2.parent = dsym.parent;
v2.isexp = true;
- dsym.aliassym = v2;
+ dsym.aliasTuple = v2;
dsym.semanticRun = PASS.semanticdone;
return;
}
}
else if (dsym.isMember())
{
- dsym.error("field cannot be `scope`");
+ error(dsym.loc, "field `%s` cannot be `scope`", dsym.toChars());
}
else if (!dsym.type.hasPointers())
{
InterfaceDeclaration id = parent.isInterfaceDeclaration();
if (id)
{
- dsym.error("field not allowed in interface");
+ error(dsym.loc, "field `%s` not allowed in interface", dsym.toChars());
}
else if (aad && aad.sizeok == Sizeok.done)
{
- dsym.error("cannot be further field because it will change the determined %s size", aad.toChars());
+ error(dsym.loc, "cannot declare field `%s` because it will change the determined size of `%s`", dsym.toChars(), aad.toChars());
}
/* Templates cannot add fields to aggregates
AggregateDeclaration ad2 = ti.tempdecl.isMember();
if (ad2 && dsym.storage_class != STC.undefined_)
{
- dsym.error("cannot use template to add field to aggregate `%s`", ad2.toChars());
+ dsym.error("- cannot use template to add field to aggregate `%s`", ad2.toChars());
}
}
}
+ /* If the alignment of a stack local is greater than the stack alignment,
+ * note it in the enclosing function's alignSectionVars
+ */
+ version (MARS)
+ {
+ if (!dsym.alignment.isDefault() && sc.func &&
+ dsym.alignment.get() > target.stackAlign() &&
+ sc.func && !dsym.isDataseg() && !dsym.isParameter() && !dsym.isField())
+ {
+ auto fd = sc.func;
+ if (!fd.alignSectionVars)
+ fd.alignSectionVars = new VarDeclarations();
+ fd.alignSectionVars.push(dsym);
+ }
+ }
+
if ((dsym.storage_class & (STC.ref_ | STC.parameter | STC.foreach_ | STC.temp | STC.result)) == STC.ref_ && dsym.ident != Id.This)
{
- dsym.error("only parameters or `foreach` declarations can be `ref`");
+ dsym.error("- only parameters, functions and `foreach` declarations can be `ref`");
}
if (dsym.type.hasWild())
{
if (dsym.storage_class & (STC.static_ | STC.extern_ | STC.gshared | STC.manifest | STC.field) || dsym.isDataseg())
{
- dsym.error("only parameters or stack based variables can be `inout`");
+ dsym.error("- only parameters or stack-based variables can be `inout`");
}
FuncDeclaration func = sc.func;
if (func)
}
if (!isWild)
{
- dsym.error("`inout` variables can only be declared inside `inout` functions");
+ dsym.error("- `inout` variables can only be declared inside `inout` functions");
}
}
}
{
}
else
- dsym.error("default construction is disabled for type `%s`", dsym.type.toChars());
+ dsym.error("- default construction is disabled for type `%s`", dsym.type.toChars());
}
}
if (dsym._init)
{ } // remember we had an explicit initializer
else if (dsym.storage_class & STC.manifest)
- dsym.error("manifest constants must have initializers");
+ dsym.error("- manifest constants must have initializers");
// Don't allow non-extern, non-__gshared variables to be interfaced with C++
if (dsym._linkage == LINK.cpp && !(dsym.storage_class & (STC.ctfe | STC.extern_ | STC.gshared)) && dsym.isDataseg())
//printf("Providing default initializer for '%s'\n", dsym.toChars());
if (sz == SIZE_INVALID && dsym.type.ty != Terror)
- dsym.error("size of type `%s` is invalid", dsym.type.toChars());
+ dsym.error("- size of type `%s` is invalid", dsym.type.toChars());
Type tv = dsym.type;
while (tv.ty == Tsarray) // Don't skip Tenum
}
if (dsym.type.baseElemOf().ty == Tvoid)
{
- dsym.error("`%s` does not have a default initializer", dsym.type.toChars());
+ dsym.error("of type `%s` does not have a default initializer", dsym.type.toChars());
}
else if (auto e = dsym.type.defaultInit(dsym.loc))
{
dsym._init.isVoidInitializer() &&
!(dsym.storage_class & STC.field))
{
- dsym.error("incomplete array type must have initializer");
+ dsym.error("- incomplete array type must have initializer");
}
ExpInitializer ei = dsym._init.isExpInitializer();
ex = (cast(AssignExp)ex).e2;
if (auto ne = ex.isNewExp())
{
- // See if initializer is a NewExp that can be allocated on the stack
+ /* See if initializer is a NewExp that can be allocated on the stack.
+ */
if (dsym.type.toBasetype().ty == Tclass)
{
+ /* Unsafe to allocate on stack if constructor is not `scope` because the `this` can leak.
+ * https://issues.dlang.org/show_bug.cgi?id=23145
+ */
+ if (ne.member && !(ne.member.storage_class & STC.scope_))
+ {
+ if (sc.func.isSafe())
+ {
+ // @@@DEPRECATED_2.112@@@
+ deprecation(dsym.loc,
+ "`scope` allocation of `%s` requires that constructor be annotated with `scope`",
+ dsym.toChars());
+ deprecationSupplemental(ne.member.loc, "is the location of the constructor");
+ }
+ else
+ sc.func.setUnsafe();
+ }
ne.onstack = 1;
dsym.onstack = true;
}
if (!dsym.parent.isStructDeclaration() && !dsym.parent.isClassDeclaration())
{
- dsym.error("bit-field must be member of struct, union, or class");
+ dsym.error("- bit-field must be member of struct, union, or class");
}
sc = sc.startCTFE();
e = se;
if (!se.len)
{
- pd.error("zero-length string not allowed for mangled name");
+ pd.error("- zero-length string not allowed for mangled name");
return null;
}
if (se.sz != 1)
{
- pd.error("mangled name characters can only be of type `char`");
+ pd.error("- mangled name characters can only be of type `char`");
return null;
}
version (all)
pd.args = new Expressions();
if (pd.args.length == 0 || pd.args.length > 2)
{
- pd.error(pd.args.length == 0 ? "string expected for mangled name"
+ pd.error(pd.args.length == 0 ? "- string expected for mangled name"
: "expected 1 or 2 arguments");
pd.args.setDim(1);
(*pd.args)[0] = ErrorExp.get(); // error recovery
const len = buf.length;
buf.writeByte(0);
const str = buf.extractSlice()[0 .. len];
- scope p = new Parser!ASTCodegen(cd.loc, sc._module, str, false);
+ scope p = new Parser!ASTCodegen(cd.loc, sc._module, str, false, global.errorSink);
p.nextToken();
auto d = p.parseDeclDefs(0);
override void visit(TemplateInstance ti)
{
- templateInstanceSemantic(ti, sc, null);
+ templateInstanceSemantic(ti, sc, ArgumentList());
}
override void visit(TemplateMixin tm)
/* Run semantic on each argument, place results in tiargs[],
* then find best match template with tiargs
*/
- if (!tm.findTempDecl(sc) || !tm.semanticTiargs(sc) || !tm.findBestMatch(sc, null))
+ if (!tm.findTempDecl(sc) || !tm.semanticTiargs(sc) || !tm.findBestMatch(sc, ArgumentList()))
{
if (tm.semanticRun == PASS.initial) // forward reference had occurred
{
//printf("function storage_class = x%llx, sc.stc = x%llx, %x\n", storage_class, sc.stc, Declaration.isFinal());
if (sc.flags & SCOPE.compile)
- funcdecl.isCompileTimeOnly = true; // don't emit code for this function
+ funcdecl.skipCodegen = true;
funcdecl._linkage = sc.linkage;
if (auto fld = funcdecl.isFuncLiteralDeclaration())
if (fd.ident == funcdecl.ident)
hgs.fullQual = true;
- functionToBufferFull(cast(TypeFunction)(fd.type), &buf1,
- new Identifier(fd.toPrettyChars()), &hgs, null);
- error(funcdecl.loc, "function `%s` does not override any function, did you mean to override `%s`?",
- funcdeclToChars, buf1.peekChars());
+ // https://issues.dlang.org/show_bug.cgi?id=23745
+ // If the potentially overriden function contains errors,
+ // inform the user to fix that one first
+ if (fd.errors)
+ {
+ error(funcdecl.loc, "function `%s` does not override any function, did you mean to override `%s`?",
+ funcdecl.toChars(), fd.toPrettyChars());
+ errorSupplemental(fd.loc, "Function `%s` contains errors in its declaration, therefore it cannot be correctly overriden",
+ fd.toPrettyChars());
+ }
+ else
+ {
+ functionToBufferFull(cast(TypeFunction)(fd.type), &buf1,
+ new Identifier(fd.toPrettyChars()), &hgs, null);
+
+ error(funcdecl.loc, "function `%s` does not override any function, did you mean to override `%s`?",
+ funcdeclToChars, buf1.peekChars());
+ }
}
else
{
else if (dim == 0 && tf.parameterList.varargs != VarArg.none) // allow varargs only ctor
{
}
- else if (dim && tf.parameterList[0].defaultArg)
+ else if (dim && !tf.parameterList.hasArgsWithoutDefault)
{
- // if the first parameter has a default argument, then the rest does as well
if (ctd.storage_class & STC.disable)
{
ctd.error("is marked `@disable`, so it cannot have default "~
// https://issues.dlang.org/show_bug.cgi?id=22593
else if (auto ti = ctd.parent.isTemplateInstance())
{
- if (!sd || !sd.hasCopyCtor || !(dim == 1 || (dim > 1 && tf.parameterList[1].defaultArg)))
- return;
-
- auto param = tf.parameterList[0];
-
- // if the template instance introduces an rvalue constructor
- // between the members of a struct declaration, we should check if a
- // copy constructor exists and issue an error in that case.
- if (!(param.storageClass & STC.ref_) && param.type.mutableOf().unSharedOf() == sd.type.mutableOf().unSharedOf())
- {
- .error(ctd.loc, "cannot define both an rvalue constructor and a copy constructor for `struct %s`", sd.toChars);
- .errorSupplemental(ti.loc, "Template instance `%s` creates a rvalue constructor for `struct %s`",
- ti.toChars(), sd.toChars());
- }
+ checkHasBothRvalueAndCpCtor(sd, ctd, ti);
}
}
override void visit(DtorDeclaration dd)
{
- //printf("DtorDeclaration::semantic() %s\n", toChars());
- //printf("ident: %s, %s, %p, %p\n", ident.toChars(), Id.dtor.toChars(), ident, Id.dtor);
+ //printf("DtorDeclaration::semantic() %s\n", dd.toChars());
+ //printf("ident: %s, %s, %p, %p\n", dd.ident.toChars(), Id.dtor.toChars(), dd.ident, Id.dtor);
if (dd.semanticRun >= PASS.semanticdone)
return;
if (dd._scope)
override void visit(StructDeclaration sd)
{
- //printf("StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", sd, sd.toPrettyChars(), sd.sizeok);
+ enum log = false;
+ if (log) printf("+StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", sd, sd.toPrettyChars(), sd.sizeok);
//static int count; if (++count == 20) assert(0);
if (!sd.members) // if opaque declaration
{
+ if (log) printf("\topaque declaration %s\n", sd.toChars());
sd.semanticRun = PASS.semanticdone;
return;
}
sc2.pop();
- //printf("\tdeferring %s\n", toChars());
+ if (log) printf("\tdeferring %s\n", sd.toChars());
return deferDsymbolSemantic(sd, scx);
}
sd.inv = buildInv(sd, sc2);
sd.semanticRun = PASS.semanticdone;
- //printf("-StructDeclaration::semantic(this=%p, '%s')\n", sd, sd.toChars());
+ if (log) printf("-StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", sd, sd.toPrettyChars(), sd.sizeok);
sc2.pop();
sc = sc.push();
sc.tinst = null;
sc.minst = null;
- auto fcall = resolveFuncCall(sd.loc, sc, scall, null, null, null, FuncResolveFlag.quiet);
+ auto fcall = resolveFuncCall(sd.loc, sc, scall, null, null, ArgumentList(), FuncResolveFlag.quiet);
sc = sc.pop();
global.endGagging(xerrors);
// Make an error in 2.110
if (sd.storage_class & STC.scope_)
deprecation(sd.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site.");
+ //printf("-StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", sd, sd.toPrettyChars(), sd.sizeok);
}
void interfaceSemantic(ClassDeclaration cd)
// this() { }
if (!cldec.ctor && cldec.baseClass && cldec.baseClass.ctor)
{
- auto fd = resolveFuncCall(cldec.loc, sc2, cldec.baseClass.ctor, null, cldec.type, null, FuncResolveFlag.quiet);
+ auto fd = resolveFuncCall(cldec.loc, sc2, cldec.baseClass.ctor, null, cldec.type, ArgumentList(), FuncResolveFlag.quiet);
if (!fd) // try shared base ctor instead
- fd = resolveFuncCall(cldec.loc, sc2, cldec.baseClass.ctor, null, cldec.type.sharedOf, null, FuncResolveFlag.quiet);
+ fd = resolveFuncCall(cldec.loc, sc2, cldec.baseClass.ctor, null, cldec.type.sharedOf, ArgumentList(), FuncResolveFlag.quiet);
if (fd && !fd.errors)
{
//printf("Creating default this(){} for class %s\n", toChars());
// is less strict (e.g. `preview=dtorfields` might introduce a call to a less qualified dtor)
auto ctor = new CtorDeclaration(cldec.loc, Loc.initial, 0, tf);
- ctor.storage_class |= STC.inference;
+ ctor.storage_class |= STC.inference | (fd.storage_class & STC.scope_);
ctor.isGenerated = true;
ctor.fbody = new CompoundStatement(Loc.initial, new Statements());
});
}
-void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions* fargs)
+void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList argumentList)
{
//printf("[%s] TemplateInstance.dsymbolSemantic('%s', this=%p, gag = %d, sc = %p)\n", tempinst.loc.toChars(), tempinst.toChars(), tempinst, global.gag, sc);
version (none)
* then run semantic on each argument (place results in tiargs[]),
* last find most specialized template from overload list/set.
*/
- if (!tempinst.findTempDecl(sc, null) || !tempinst.semanticTiargs(sc) || !tempinst.findBestMatch(sc, fargs))
+ if (!tempinst.findTempDecl(sc, null) || !tempinst.semanticTiargs(sc) || !tempinst.findBestMatch(sc, argumentList))
{
Lerror:
if (tempinst.gagged)
return aliasInstanceSemantic(tempinst, sc, tempdecl);
}
+ Expressions* fargs = argumentList.arguments; // TODO: resolve named args
+
/* See if there is an existing TemplateInstantiation that already
* implements the typeargs. If so, just refer to that one instead.
*/
alias visit = Visitor.visit;
TemplateInstance inst;
- extern (D) this(TemplateInstance inst)
+ extern (D) this(TemplateInstance inst) scope
{
this.inst = inst;
}
Dsymbol s;
if (Dsymbol.oneMembers(tempinst.members, &s, tempdecl.ident) && s)
{
- //printf("tempdecl.ident = %s, s = '%s'\n", tempdecl.ident.toChars(), s.kind(), s.toPrettyChars());
+ //printf("tempdecl.ident = %s, s = `%s %s`\n", tempdecl.ident.toChars(), s.kind(), s.toPrettyChars());
//printf("setting aliasdecl\n");
tempinst.aliasdecl = s;
}
{
if (!tempinst.aliasdecl || tempinst.aliasdecl != s)
{
- //printf("tempdecl.ident = %s, s = '%s'\n", tempdecl.ident.toChars(), s.kind(), s.toPrettyChars());
+ //printf("tempdecl.ident = %s, s = `%s %s`\n", tempdecl.ident.toChars(), s.kind(), s.toPrettyChars());
//printf("setting aliasdecl 2\n");
tempinst.aliasdecl = s;
}
if (ad.sizeok != Sizeok.none)
return 1;
- if (v.aliassym)
+ if (v.aliasTuple)
{
// If this variable was really a tuple, process each element.
- if (auto tup = v.aliassym.isTupleDeclaration())
- return tup.foreachVar(tv => tv.apply(&func, ad));
- return 0;
+ return v.aliasTuple.foreachVar(tv => tv.apply(&func, ad));
}
if (v.storage_class & (STC.static_ | STC.extern_ | STC.tls | STC.gshared | STC.manifest | STC.ctfe | STC.templateparameter))
import dmd.arraytypes;
import dmd.astenums;
import dmd.ast_node;
+import dmd.attrib;
import dmd.dcast;
import dmd.dclass;
import dmd.declaration;
* dedtypes deduced arguments
* Return match level.
*/
- extern (D) MATCH matchWithInstance(Scope* sc, TemplateInstance ti, Objects* dedtypes, Expressions* fargs, int flag)
+ extern (D) MATCH matchWithInstance(Scope* sc, TemplateInstance ti, Objects* dedtypes, ArgumentList argumentList, int flag)
{
enum LOGM = 0;
static if (LOGM)
if (fd)
{
TypeFunction tf = fd.type.isTypeFunction().syntaxCopy();
+ if (argumentList.hasNames)
+ return nomatch();
+ Expressions* fargs = argumentList.arguments;
+ // TODO: Expressions* fargs = tf.resolveNamedArgs(argumentList, null);
+ // if (!fargs)
+ // return nomatch();
fd = new FuncDeclaration(fd.loc, fd.endloc, fd.ident, fd.storage_class, tf);
fd.parent = ti;
paramscope.pop();
static if (LOGM)
{
- printf("-TemplateDeclaration.matchWithInstance(this = %p, ti = %p) = %d\n", this, ti, m);
+ printf("-TemplateDeclaration.matchWithInstance(this = %s, ti = %s) = %d\n", toChars(), ti.toChars(), m);
}
return m;
}
* match this is at least as specialized as td2
* 0 td2 is more specialized than this
*/
- MATCH leastAsSpecialized(Scope* sc, TemplateDeclaration td2, Expressions* fargs)
+ MATCH leastAsSpecialized(Scope* sc, TemplateDeclaration td2, ArgumentList argumentList)
{
enum LOG_LEASTAS = 0;
static if (LOG_LEASTAS)
Objects dedtypes = Objects(td2.parameters.length);
// Attempt a type deduction
- MATCH m = td2.matchWithInstance(sc, ti, &dedtypes, fargs, 1);
+ MATCH m = td2.matchWithInstance(sc, ti, &dedtypes, argumentList, 1);
if (m > MATCH.nomatch)
{
/* A non-variadic template is more specialized than a
* sc instantiation scope
* fd
* tthis 'this' argument if !NULL
- * fargs arguments to function
+ * argumentList arguments to function
* Output:
* fd Partially instantiated function declaration
* ti.tdtypes Expression/Type deduced template arguments
* Returns:
* match pair of initial and inferred template arguments
*/
- extern (D) MATCHpair deduceFunctionTemplateMatch(TemplateInstance ti, Scope* sc, ref FuncDeclaration fd, Type tthis, Expressions* fargs)
+ extern (D) MATCHpair deduceFunctionTemplateMatch(TemplateInstance ti, Scope* sc, ref FuncDeclaration fd, Type tthis, ArgumentList argumentList)
{
size_t nfparams;
size_t nfargs;
for (size_t i = 0; i < (fargs ? fargs.length : 0); i++)
{
Expression e = (*fargs)[i];
- printf("\tfarg[%d] is %s, type is %s\n", i, e.toChars(), e.type.toChars());
+ printf("\tfarg[%d] is %s, type is %s\n", cast(int) i, e.toChars(), e.type.toChars());
}
printf("fd = %s\n", fd.toChars());
printf("fd.type = %s\n", fd.type.toChars());
fparameters = fd.getParameterList();
nfparams = fparameters.length; // number of function parameters
- nfargs = fargs ? fargs.length : 0; // number of function arguments
+ nfargs = argumentList.length; // number of function arguments
+ if (argumentList.hasNames)
+ return matcherror(); // TODO: resolve named args
+ Expressions* fargs = argumentList.arguments; // TODO: resolve named args
/* Check for match of function arguments with variadic template
* parameter, such as:
* sc = instantiation scope
* tiargs = initial list of template arguments
* tthis = if !NULL, the 'this' pointer argument
- * fargs = arguments to function
+ * argumentList= arguments to function
* pMessage = address to store error message, or null
*/
void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, Objects* tiargs,
- Type tthis, Expressions* fargs, const(char)** pMessage = null)
+ Type tthis, ArgumentList argumentList, const(char)** pMessage = null)
{
- Expression[] fargs_ = fargs.peekSlice();
version (none)
{
printf("functionResolve() dstart = %s\n", dstart.toChars());
else if (shared_this && !shared_dtor && tthis_fd !is null)
tf.mod = tthis_fd.mod;
}
- MATCH mfa = tf.callMatch(tthis_fd, fargs_, 0, pMessage, sc);
+ MATCH mfa = tf.callMatch(tthis_fd, argumentList, 0, pMessage, sc);
//printf("test1: mfa = %d\n", mfa);
if (mfa == MATCH.nomatch)
return 0;
* This is because f() is "more specialized."
*/
{
- MATCH c1 = fd.leastAsSpecialized(m.lastf);
- MATCH c2 = m.lastf.leastAsSpecialized(fd);
+ MATCH c1 = fd.leastAsSpecialized(m.lastf, argumentList.names);
+ MATCH c2 = m.lastf.leastAsSpecialized(fd, argumentList.names);
//printf("c1 = %d, c2 = %d\n", c1, c2);
if (c1 > c2) return firstIsBetter();
if (c1 < c2) return 0;
int applyTemplate(TemplateDeclaration td)
{
- //printf("applyTemplate()\n");
+ //printf("applyTemplate(): td = %s\n", td.toChars());
if (td == td_best) // skip duplicates
return 0;
}
//printf("td = %s\n", td.toChars());
+ if (argumentList.hasNames)
+ {
+ .error(loc, "named arguments with Implicit Function Template Instantiation are not supported yet");
+ goto Lerror;
+ }
auto f = td.onemember ? td.onemember.isFuncDeclaration() : null;
if (!f)
{
auto ti = new TemplateInstance(loc, td, tiargs);
Objects dedtypes = Objects(td.parameters.length);
assert(td.semanticRun != PASS.initial);
- MATCH mta = td.matchWithInstance(sc, ti, &dedtypes, fargs, 0);
+ MATCH mta = td.matchWithInstance(sc, ti, &dedtypes, argumentList, 0);
//printf("matchWithInstance = %d\n", mta);
if (mta == MATCH.nomatch || mta < ta_last) // no match or less match
return 0;
- ti.templateInstanceSemantic(sc, fargs);
+ ti.templateInstanceSemantic(sc, argumentList);
if (!ti.inst) // if template failed to expand
return 0;
pr.dedargs = &dedtypesX;
tdx.previous = ≺ // add this to threaded list
- fd = resolveFuncCall(loc, sc, s, null, tthis, fargs, FuncResolveFlag.quiet);
+ fd = resolveFuncCall(loc, sc, s, null, tthis, argumentList, FuncResolveFlag.quiet);
tdx.previous = pr.prev; // unlink from threaded list
}
else if (s.isFuncDeclaration())
{
- fd = resolveFuncCall(loc, sc, s, null, tthis, fargs, FuncResolveFlag.quiet);
+ fd = resolveFuncCall(loc, sc, s, null, tthis, argumentList, FuncResolveFlag.quiet);
}
else
goto Lerror;
Type tthis_fd = fd.needThis() && !fd.isCtorDeclaration() ? tthis : null;
auto tf = cast(TypeFunction)fd.type;
- MATCH mfa = tf.callMatch(tthis_fd, fargs_, 0, null, sc);
+ MATCH mfa = tf.callMatch(tthis_fd, argumentList, 0, null, sc);
if (mfa < m.last)
return 0;
ti.parent = td.parent; // Maybe calculating valid 'enclosing' is unnecessary.
auto fd = f;
- MATCHpair x = td.deduceFunctionTemplateMatch(ti, sc, fd, tthis, fargs);
+ MATCHpair x = td.deduceFunctionTemplateMatch(ti, sc, fd, tthis, argumentList);
MATCH mta = x.mta;
MATCH mfa = x.mfa;
//printf("match:t/f = %d/%d\n", mta, mfa);
if (isCtorCall)
{
// Constructor call requires additional check.
-
auto tf = cast(TypeFunction)fd.type;
assert(tf.next);
if (MODimplicitConv(tf.mod, tthis_fd.mod) ||
}
else
continue; // MATCH.nomatch
+
+ // need to check here whether the constructor is the member of a struct
+ // declaration that defines a copy constructor. This is already checked
+ // in the semantic of CtorDeclaration, however, when matching functions,
+ // the template instance is not expanded.
+ // https://issues.dlang.org/show_bug.cgi?id=21613
+ auto ad = fd.isThis();
+ auto sd = ad.isStructDeclaration();
+ if (checkHasBothRvalueAndCpCtor(sd, fd.isCtorDeclaration(), ti))
+ continue;
}
if (mta < ta_last) goto Ltd_best;
if (td_best)
{
// Disambiguate by picking the most specialized TemplateDeclaration
- MATCH c1 = td.leastAsSpecialized(sc, td_best, fargs);
- MATCH c2 = td_best.leastAsSpecialized(sc, td, fargs);
+ MATCH c1 = td.leastAsSpecialized(sc, td_best, argumentList);
+ MATCH c2 = td_best.leastAsSpecialized(sc, td, argumentList);
//printf("1: c1 = %d, c2 = %d\n", c1, c2);
if (c1 > c2) goto Ltd;
if (c1 < c2) goto Ltd_best;
// Disambiguate by tf.callMatch
auto tf1 = fd.type.isTypeFunction();
auto tf2 = m.lastf.type.isTypeFunction();
- MATCH c1 = tf1.callMatch(tthis_fd, fargs_, 0, null, sc);
- MATCH c2 = tf2.callMatch(tthis_best, fargs_, 0, null, sc);
+ MATCH c1 = tf1.callMatch(tthis_fd, argumentList, 0, null, sc);
+ MATCH c2 = tf2.callMatch(tthis_best, argumentList, 0, null, sc);
//printf("2: c1 = %d, c2 = %d\n", c1, c2);
if (c1 > c2) goto Ltd;
if (c1 < c2) goto Ltd_best;
}
{
// Disambiguate by picking the most specialized FunctionDeclaration
- MATCH c1 = fd.leastAsSpecialized(m.lastf);
- MATCH c2 = m.lastf.leastAsSpecialized(fd);
+ MATCH c1 = fd.leastAsSpecialized(m.lastf, argumentList.names);
+ MATCH c2 = m.lastf.leastAsSpecialized(fd, argumentList.names);
//printf("3: c1 = %d, c2 = %d\n", c1, c2);
if (c1 > c2) goto Ltd;
if (c1 < c2) goto Ltd_best;
sc = td_best._scope; // workaround for Type.aliasthisOf
auto ti = new TemplateInstance(loc, td_best, ti_best.tiargs);
- ti.templateInstanceSemantic(sc, fargs);
+ ti.templateInstanceSemantic(sc, argumentList);
m.lastf = ti.toAlias().isFuncDeclaration();
if (!m.lastf)
if (m.lastf.type.ty == Terror)
goto Lerror;
auto tf = m.lastf.type.isTypeFunction();
- if (!tf.callMatch(tthis_best, fargs_, 0, null, sc))
+ if (!tf.callMatch(tthis_best, argumentList, 0, null, sc))
goto Lnomatch;
/* As https://issues.dlang.org/show_bug.cgi?id=3682 shows,
}
}
- extern (D) this(const ref Loc loc, Identifier ident, Objects* tiargs)
+ extern (D) this(const ref Loc loc, Identifier ident, Objects* tiargs) scope
{
super(loc, null);
static if (LOG)
* This constructor is only called when we figured out which function
* template to instantiate.
*/
- extern (D) this(const ref Loc loc, TemplateDeclaration td, Objects* tiargs)
+ extern (D) this(const ref Loc loc, TemplateDeclaration td, Objects* tiargs) scope
{
super(loc, null);
static if (LOG)
return;
// Print full trace for verbose mode, otherwise only short traces
- const(uint) max_shown = !global.params.verbose ? 6 : uint.max;
+ const(uint) max_shown = !global.params.verbose ?
+ (global.params.errorSupplementLimit ? global.params.errorSupplementLimit : uint.max)
+ : uint.max;
+
const(char)* format = "instantiated from here: `%s`";
// This returns a function pointer
*/
final bool needsCodegen()
{
+ //printf("needsCodegen() %s\n", toChars());
+
// minst is finalized after the 1st invocation.
- // tnext and tinst are only needed for the 1st invocation and
+ // tnext is only needed for the 1st invocation and
// cleared for further invocations.
TemplateInstance tnext = this.tnext;
TemplateInstance tinst = this.tinst;
this.tnext = null;
- this.tinst = null;
- if (errors || (inst && inst.isDiscardable()))
+ // Don't do codegen if the instance has errors,
+ // is a dummy instance (see evaluateConstraint),
+ // or is determined to be discardable.
+ if (errors || inst is null || inst.isDiscardable())
{
minst = null; // mark as speculative
return false;
}
+ // This should only be called on the primary instantiation.
+ assert(this is inst);
+
if (global.params.allInst)
{
// Do codegen if there is an instantiation from a root module, to maximize link-ability.
-
- // Do codegen if `this` is instantiated from a root module.
- if (minst && minst.isRoot())
- return true;
-
- // Do codegen if the ancestor needs it.
- if (tinst && tinst.needsCodegen())
+ static ThreeState needsCodegenAllInst(TemplateInstance tithis, TemplateInstance tinst)
{
- minst = tinst.minst; // cache result
- assert(minst);
- assert(minst.isRoot());
- return true;
+ // Do codegen if `this` is instantiated from a root module.
+ if (tithis.minst && tithis.minst.isRoot())
+ return ThreeState.yes;
+
+ // Do codegen if the ancestor needs it.
+ if (tinst && tinst.inst && tinst.inst.needsCodegen())
+ {
+ tithis.minst = tinst.inst.minst; // cache result
+ assert(tithis.minst);
+ assert(tithis.minst.isRoot());
+ return ThreeState.yes;
+ }
+ return ThreeState.none;
}
+ if (const needsCodegen = needsCodegenAllInst(this, tinst))
+ return needsCodegen == ThreeState.yes ? true : false;
+
// Do codegen if a sibling needs it.
- if (tnext)
+ for (; tnext; tnext = tnext.tnext)
{
- if (tnext.needsCodegen())
+ const needsCodegen = needsCodegenAllInst(tnext, tnext.tinst);
+ if (needsCodegen == ThreeState.yes)
{
minst = tnext.minst; // cache result
assert(minst);
else if (!minst && tnext.minst)
{
minst = tnext.minst; // cache result from non-speculative sibling
- return false;
+ // continue searching
}
+ else if (needsCodegen != ThreeState.none)
+ break;
}
// Elide codegen because there's no instantiation from any root modules.
* => Elide codegen if there is at least one instantiation from a non-root module
* which doesn't import any root modules.
*/
-
- // If the ancestor isn't speculative,
- // 1. do codegen if the ancestor needs it
- // 2. elide codegen if the ancestor doesn't need it (non-root instantiation of ancestor incl. subtree)
- if (tinst)
+ static ThreeState needsCodegenRootOnly(TemplateInstance tithis, TemplateInstance tinst)
{
- const needsCodegen = tinst.needsCodegen(); // sets tinst.minst
- if (tinst.minst) // not speculative
+ // If the ancestor isn't speculative,
+ // 1. do codegen if the ancestor needs it
+ // 2. elide codegen if the ancestor doesn't need it (non-root instantiation of ancestor incl. subtree)
+ if (tinst && tinst.inst)
{
- minst = tinst.minst; // cache result
- return needsCodegen;
+ tinst = tinst.inst;
+ const needsCodegen = tinst.needsCodegen(); // sets tinst.minst
+ if (tinst.minst) // not speculative
+ {
+ tithis.minst = tinst.minst; // cache result
+ return needsCodegen ? ThreeState.yes : ThreeState.no;
+ }
}
+
+ // Elide codegen if `this` doesn't need it.
+ if (tithis.minst && !tithis.minst.isRoot() && !tithis.minst.rootImports())
+ return ThreeState.no;
+
+ return ThreeState.none;
}
- // Elide codegen if `this` doesn't need it.
- if (minst && !minst.isRoot() && !minst.rootImports())
- return false;
+ if (const needsCodegen = needsCodegenRootOnly(this, tinst))
+ return needsCodegen == ThreeState.yes ? true : false;
// Elide codegen if a (non-speculative) sibling doesn't need it.
- if (tnext)
+ for (; tnext; tnext = tnext.tnext)
{
- const needsCodegen = tnext.needsCodegen(); // sets tnext.minst
+ const needsCodegen = needsCodegenRootOnly(tnext, tnext.tinst); // sets tnext.minst
if (tnext.minst) // not speculative
{
- if (!needsCodegen)
+ if (needsCodegen == ThreeState.no)
{
minst = tnext.minst; // cache result
assert(!minst.isRoot() && !minst.rootImports());
else if (!minst)
{
minst = tnext.minst; // cache result from non-speculative sibling
- return true;
+ // continue searching
}
+ else if (needsCodegen != ThreeState.none)
+ break;
}
}
}
TemplateInstance ti = s.parent ? s.parent.isTemplateInstance() : null;
- if (ti && (ti.name == s.ident || ti.toAlias().ident == s.ident) && ti.tempdecl)
+
+ /* This avoids the VarDeclaration.toAlias() which runs semantic() too soon
+ */
+ static bool matchId(TemplateInstance ti, Identifier id)
+ {
+ if (ti.aliasdecl && ti.aliasdecl.isVarDeclaration())
+ return ti.aliasdecl.isVarDeclaration().ident == id;
+ return ti.toAlias().ident == id;
+ }
+
+ if (ti && (ti.name == s.ident || matchId(ti, s.ident)) && ti.tempdecl)
{
/* This is so that one can refer to the enclosing
* template, even if it has the same name as a member
*
* Params:
* sc = the scope this TemplateInstance resides in
- * fargs = function arguments in case of a template function, null otherwise
+ * argumentList = function arguments in case of a template function
*
* Returns:
* `true` if a match was found, `false` otherwise
*/
- extern (D) final bool findBestMatch(Scope* sc, Expressions* fargs)
+ extern (D) final bool findBestMatch(Scope* sc, ArgumentList argumentList)
{
if (havetempdecl)
{
assert(tempdecl._scope);
// Deduce tdtypes
tdtypes.setDim(tempdecl.parameters.length);
- if (!tempdecl.matchWithInstance(sc, this, &tdtypes, fargs, 2))
+ if (!tempdecl.matchWithInstance(sc, this, &tdtypes, argumentList, 2))
{
error("incompatible arguments for template instantiation");
return false;
dedtypes.zero();
assert(td.semanticRun != PASS.initial);
- MATCH m = td.matchWithInstance(sc, this, &dedtypes, fargs, 0);
+ MATCH m = td.matchWithInstance(sc, this, &dedtypes, argumentList, 0);
//printf("matchWithInstance = %d\n", m);
if (m == MATCH.nomatch) // no match at all
return 0;
// Disambiguate by picking the most specialized TemplateDeclaration
{
- MATCH c1 = td.leastAsSpecialized(sc, td_best, fargs);
- MATCH c2 = td_best.leastAsSpecialized(sc, td, fargs);
+ MATCH c1 = td.leastAsSpecialized(sc, td_best, argumentList);
+ MATCH c2 = td_best.leastAsSpecialized(sc, td, argumentList);
//printf("c1 = %d, c2 = %d\n", c1, c2);
if (c1 > c2) goto Ltd;
if (c1 < c2) goto Ltd_best;
return 1;
}
}
- MATCH m = td.matchWithInstance(sc, this, &dedtypes, null, 0);
+ MATCH m = td.matchWithInstance(sc, this, &dedtypes, ArgumentList(), 0);
if (m == MATCH.nomatch)
return 0;
}
members.foreachDsymbol( (s) { s.importAll(sc2); } );
+ if (!aliasdecl)
+ {
+ /* static if's are crucial to evaluating aliasdecl correctly. But
+ * evaluating the if/else bodies may require aliasdecl.
+ * So, evaluate the condition for static if's, but not their if/else bodies.
+ * Then try to set aliasdecl.
+ * Later do the if/else bodies.
+ * https://issues.dlang.org/show_bug.cgi?id=23598
+ * It might be better to do this by attaching a lambda to the StaticIfDeclaration
+ * to do the oneMembers call after the sid.include(sc2) is run as part of dsymbolSemantic().
+ */
+ bool done;
+ void staticIfDg(Dsymbol s)
+ {
+ if (done || aliasdecl)
+ return;
+ //printf("\t staticIfDg on '%s %s' in '%s'\n", s.kind(), s.toChars(), this.toChars());
+ if (!s.isStaticIfDeclaration())
+ {
+ //s.dsymbolSemantic(sc2);
+ done = true;
+ return;
+ }
+ auto sid = s.isStaticIfDeclaration();
+ sid.include(sc2);
+ if (members.length)
+ {
+ Dsymbol sa;
+ if (Dsymbol.oneMembers(members, &sa, tempdecl.ident) && sa)
+ aliasdecl = sa;
+ }
+ done = true;
+ }
+
+ members.foreachDsymbol(&staticIfDg);
+ }
+
void symbolDg(Dsymbol s)
{
//printf("\t semantic on '%s' %p kind %s in '%s'\n", s.toChars(), s, s.kind(), this.toChars());
/// Informations about the current context in the AST
Context context;
- alias context this;
- this(OutBuffer* fwdbuf, OutBuffer* donebuf, OutBuffer* buf)
+ // Generates getter-setter methods to replace the use of alias this
+ // This should be replaced by a `static foreach` once the gdc tester
+ // gets upgraded to version 10 (to support `static foreach`).
+ private extern(D) static string generateMembers()
+ {
+ string result = "";
+ foreach(member; __traits(allMembers, Context))
+ {
+ result ~= "ref auto " ~ member ~ "() { return context." ~ member ~ "; }\n";
+ }
+ return result;
+ }
+
+ mixin(generateMembers());
+
+ this(OutBuffer* fwdbuf, OutBuffer* donebuf, OutBuffer* buf) scope
{
this.fwdbuf = fwdbuf;
this.donebuf = donebuf;
// (we'll visit them later)
if (vd.type && vd.type.isTypeTuple())
{
- assert(vd.aliassym);
+ assert(vd.aliasTuple);
vd.toAlias().accept(this);
return;
}
module dmd.errors;
import core.stdc.stdarg;
+import dmd.errorsink;
import dmd.globals;
import dmd.location;
nothrow:
+/***************************
+ * Error message sink for D compiler.
+ */
+class ErrorSinkCompiler : ErrorSink
+{
+ nothrow:
+ extern (C++):
+ override:
+
+ void error(const ref Loc loc, const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ verror(loc, format, ap);
+ va_end(ap);
+ }
+
+ void errorSupplemental(const ref Loc loc, const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ verrorSupplemental(loc, format, ap);
+ va_end(ap);
+ }
+
+ void warning(const ref Loc loc, const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ vwarning(loc, format, ap);
+ va_end(ap);
+ }
+
+ void deprecation(const ref Loc loc, const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ vdeprecation(loc, format, ap);
+ va_end(ap);
+ }
+
+ void deprecationSupplemental(const ref Loc loc, const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ vdeprecationSupplemental(loc, format, ap);
+ va_end(ap);
+ }
+}
+
+
/**
* Color highlighting to classify messages
*/
--- /dev/null
+/**
+ * Provides an abstraction for what to do with error messages.
+ *
+ * Copyright: Copyright (C) 2023 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/errorsink.d, _errorsink.d)
+ * Documentation: https://dlang.org/phobos/dmd_errorsink.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/errorsink.d
+ */
+
+module dmd.errorsink;
+
+import dmd.location;
+
+/***************************************
+ * Where error/warning/deprecation messages go.
+ */
+abstract class ErrorSink
+{
+ nothrow:
+ extern (C++):
+
+ void error(const ref Loc loc, const(char)* format, ...);
+
+ void errorSupplemental(const ref Loc loc, const(char)* format, ...);
+
+ void warning(const ref Loc loc, const(char)* format, ...);
+
+ void deprecation(const ref Loc loc, const(char)* format, ...);
+
+ void deprecationSupplemental(const ref Loc loc, const(char)* format, ...);
+}
+
+/*****************************************
+ * Just ignores the messages.
+ */
+class ErrorSinkNull : ErrorSink
+{
+ nothrow:
+ extern (C++):
+ override:
+
+ void error(const ref Loc loc, const(char)* format, ...) { }
+
+ void errorSupplemental(const ref Loc loc, const(char)* format, ...) { }
+
+ void warning(const ref Loc loc, const(char)* format, ...) { }
+
+ void deprecation(const ref Loc loc, const(char)* format, ...) { }
+
+ void deprecationSupplemental(const ref Loc loc, const(char)* format, ...) { }
+}
+
+/*****************************************
+ * Simplest implementation, just sends messages to stderr.
+ */
+class ErrorSinkStderr : ErrorSink
+{
+ import core.stdc.stdio;
+ import core.stdc.stdarg;
+
+ nothrow:
+ extern (C++):
+ override:
+
+ void error(const ref Loc loc, const(char)* format, ...)
+ {
+ fputs("Error: ", stderr);
+ const p = loc.toChars();
+ if (*p)
+ {
+ fprintf(stderr, "%s: ", p);
+ //mem.xfree(cast(void*)p); // loc should provide the free()
+ }
+
+ va_list ap;
+ va_start(ap, format);
+ vfprintf(stderr, format, ap);
+ fputc('\n', stderr);
+ va_end(ap);
+ }
+
+ void errorSupplemental(const ref Loc loc, const(char)* format, ...) { }
+
+ void warning(const ref Loc loc, const(char)* format, ...)
+ {
+ fputs("Warning: ", stderr);
+ const p = loc.toChars();
+ if (*p)
+ {
+ fprintf(stderr, "%s: ", p);
+ //mem.xfree(cast(void*)p); // loc should provide the free()
+ }
+
+ va_list ap;
+ va_start(ap, format);
+ vfprintf(stderr, format, ap);
+ fputc('\n', stderr);
+ va_end(ap);
+ }
+
+ void deprecation(const ref Loc loc, const(char)* format, ...)
+ {
+ fputs("Deprecation: ", stderr);
+ const p = loc.toChars();
+ if (*p)
+ {
+ fprintf(stderr, "%s: ", p);
+ //mem.xfree(cast(void*)p); // loc should provide the free()
+ }
+
+ va_list ap;
+ va_start(ap, format);
+ vfprintf(stderr, format, ap);
+ fputc('\n', stderr);
+ va_end(ap);
+ }
+
+ void deprecationSupplemental(const ref Loc loc, const(char)* format, ...) { }
+}
if (!(eb.isMutable || eb2.isMutable))
return;
- if (!(global.params.useDIP1000 == FeatureState.enabled && sc.setUnsafe()))
+ if (!tf.islive && !(global.params.useDIP1000 == FeatureState.enabled && sc.func.setUnsafe()))
return;
if (!gag)
return false;
}
+/// How a `return` parameter escapes its pointer value
+enum ReturnParamDest
+{
+ returnVal, /// through return statement: `return x`
+ this_, /// assigned to a struct instance: `this.x = x`
+ firstArg, /// assigned to first argument: `firstArg = x`
+}
+
+/****************************************
+ * Find out if instead of returning a `return` parameter via a return statement,
+ * it is returned via assignment to either `this` or the first parameter.
+ *
+ * This works the same as returning the value via a return statement.
+ * Although the first argument must be `ref`, it is not regarded as returning by `ref`.
+ *
+ * See_Also: https://dlang.org.spec/function.html#return-ref-parameters
+ *
+ * Params:
+ * tf = function type
+ * tthis = type of `this` parameter, or `null` if none
+ * Returns: What a `return` parameter should transfer the lifetime of the argument to
+ */
+ReturnParamDest returnParamDest(TypeFunction tf, Type tthis)
+{
+ assert(tf);
+ if (tf.isctor)
+ return ReturnParamDest.this_;
+
+ if (!tf.nextOf() || (tf.nextOf().ty != Tvoid))
+ return ReturnParamDest.returnVal;
+
+ if (tthis && tthis.toBasetype().ty == Tstruct) // class `this` is passed by value
+ return ReturnParamDest.this_;
+
+ if (tf.parameterList.length > 0 && tf.parameterList[0].isReference)
+ return ReturnParamDest.firstArg;
+
+ return ReturnParamDest.returnVal;
+}
+
/****************************************
* Given an `AssignExp`, determine if the lvalue will cause
* the contents of the rvalue to escape.
if (e1.isStructLiteralExp())
return false;
+ VarDeclaration va = expToVariable(e1);
EscapeByResults er;
if (byRef)
if (!er.byref.length && !er.byvalue.length && !er.byfunc.length && !er.byexp.length)
return false;
- VarDeclaration va = expToVariable(e1);
if (va && e.op == EXP.concatenateElemAssign)
{
const bool vaIsRef = va && va.isParameter() && va.isReference();
if (log && vaIsRef) printf("va is ref `%s`\n", va.toChars());
- /* Determine if va is the first parameter, through which other 'return' parameters
- * can be assigned.
- * This works the same as returning the value via a return statement.
- * Although va is marked as `ref`, it is not regarded as returning by `ref`.
- * https://dlang.org.spec/function.html#return-ref-parameters
- */
- bool isFirstRef()
+ // Determine if va is the first parameter, through which other 'return' parameters
+ // can be assigned.
+ bool vaIsFirstRef = false;
+ if (fd && fd.type)
{
- if (!vaIsRef)
- return false;
- Dsymbol p = va.toParent2();
- if (p == fd && fd.type && fd.type.isTypeFunction())
+ final switch (returnParamDest(fd.type.isTypeFunction(), fd.vthis ? fd.vthis.type : null))
{
- TypeFunction tf = fd.type.isTypeFunction();
- if (!tf.nextOf() || (tf.nextOf().ty != Tvoid && !fd.isCtorDeclaration()))
- return false;
- if (va == fd.vthis) // `this` of a non-static member function is considered to be the first parameter
- return true;
- if (!fd.vthis && fd.parameters && fd.parameters.length && (*fd.parameters)[0] == va) // va is first parameter
- return true;
+ case ReturnParamDest.this_:
+ vaIsFirstRef = va == fd.vthis;
+ break;
+ case ReturnParamDest.firstArg:
+ vaIsFirstRef = (*fd.parameters)[0] == va;
+ break;
+ case ReturnParamDest.returnVal:
+ break;
}
- return false;
}
- const bool vaIsFirstRef = isFirstRef();
if (log && vaIsFirstRef) printf("va is first ref `%s`\n", va.toChars());
bool result = false;
const stc = tf.parameterStorageClass(null, p);
ScopeRef psr = buildScopeRef(stc);
if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope)
- escapeByValue(arg, er, live, retRefTransition);
+ {
+ if (tf.isref)
+ {
+ /* ignore `ref` on struct constructor return because
+ * struct S { this(return scope int* q) { this.p = q; } int* p; }
+ * is different from:
+ * ref char* front(return scope char** q) { return *q; }
+ * https://github.com/dlang/dmd/pull/14869
+ */
+ if (auto dve = e.e1.isDotVarExp())
+ if (auto fd = dve.var.isFuncDeclaration())
+ if (fd.isCtorDeclaration() && tf.next.toBasetype().isTypeStruct())
+ {
+ escapeByValue(arg, er, live, retRefTransition);
+ }
+ }
+ else
+ escapeByValue(arg, er, live, retRefTransition);
+ }
else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope)
{
if (tf.isref)
{
DotVarExp dve = e.e1.isDotVarExp();
FuncDeclaration fd = dve.var.isFuncDeclaration();
- if (1)
+ if (fd && fd.isThis())
{
- if (fd && fd.isThis())
+ /* Calling a non-static member function dve.var, which is returning `this`, and with dve.e1 representing `this`
+ */
+
+ /*****************************
+ * Concoct storage class for member function's implicit `this` parameter.
+ * Params:
+ * fd = member function
+ * Returns:
+ * storage class for fd's `this`
+ */
+ StorageClass getThisStorageClass(FuncDeclaration fd)
{
- /* Calling a non-static member function dve.var, which is returning `this`, and with dve.e1 representing `this`
- */
-
- /*****************************
- * Concoct storage class for member function's implicit `this` parameter.
- * Params:
- * fd = member function
- * Returns:
- * storage class for fd's `this`
- */
- StorageClass getThisStorageClass(FuncDeclaration fd)
- {
- StorageClass stc;
- auto tf = fd.type.toBasetype().isTypeFunction();
- if (tf.isreturn)
- stc |= STC.return_;
- if (tf.isreturnscope)
- stc |= STC.returnScope | STC.scope_;
- auto ad = fd.isThis();
- if (ad.isClassDeclaration() || tf.isScopeQual)
- stc |= STC.scope_;
- if (ad.isStructDeclaration())
- stc |= STC.ref_; // `this` for a struct member function is passed by `ref`
- return stc;
- }
+ StorageClass stc;
+ auto tf = fd.type.toBasetype().isTypeFunction();
+ if (tf.isreturn)
+ stc |= STC.return_;
+ if (tf.isreturnscope)
+ stc |= STC.returnScope | STC.scope_;
+ auto ad = fd.isThis();
+ if (ad.isClassDeclaration() || tf.isScopeQual)
+ stc |= STC.scope_;
+ if (ad.isStructDeclaration())
+ stc |= STC.ref_; // `this` for a struct member function is passed by `ref`
+ return stc;
+ }
- const psr = buildScopeRef(getThisStorageClass(fd));
- if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope)
+ const psr = buildScopeRef(getThisStorageClass(fd));
+ if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope)
+ {
+ if (!tf.isref || tf.isctor)
escapeByValue(dve.e1, er, live, retRefTransition);
- else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope)
+ }
+ else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope)
+ {
+ if (tf.isref)
{
- if (tf.isref)
- {
- /* Treat calling:
- * struct S { ref S foo() return; }
- * as:
- * this;
- */
- escapeByValue(dve.e1, er, live, retRefTransition);
- }
- else
- escapeByRef(dve.e1, er, live, psr == ScopeRef.ReturnRef_Scope);
+ /* Treat calling:
+ * struct S { ref S foo() return; }
+ * as:
+ * this;
+ */
+ escapeByValue(dve.e1, er, live, retRefTransition);
}
+ else
+ escapeByRef(dve.e1, er, live, psr == ScopeRef.ReturnRef_Scope);
}
}
- else
- {
- // Calling member function before dip1000
- StorageClass stc = dve.var.storage_class & (STC.return_ | STC.scope_ | STC.ref_);
- if (tf.isreturn)
- stc |= STC.return_;
-
- const psr = buildScopeRef(stc);
- if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope)
- escapeByValue(dve.e1, er, live, retRefTransition);
- else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope)
- escapeByRef(dve.e1, er, live, retRefTransition);
- }
// If it's also a nested function that is 'return scope'
if (fd && fd.isNested())
}
/****************************************
- * Expand tuples.
- * Input:
- * exps aray of Expressions
- * Output:
- * exps rewritten in place
+ * Expand tuples in-place.
+ *
+ * Example:
+ * When there's a call `f(10, pair: AliasSeq!(20, 30), single: 40)`, the input is:
+ * `exps = [10, (20, 30), 40]`
+ * `names = [null, "pair", "single"]`
+ * The arrays will be modified to:
+ * `exps = [10, 20, 30, 40]`
+ * `names = [null, "pair", null, "single"]`
+ *
+ * Params:
+ * exps = array of Expressions
+ * names = optional array of names corresponding to Expressions
*/
-extern (C++) void expandTuples(Expressions* exps)
+extern (C++) void expandTuples(Expressions* exps, Identifiers* names = null)
{
//printf("expandTuples()\n");
if (exps is null)
return;
+ if (names)
+ {
+ if (exps.length != names.length)
+ {
+ printf("exps.length = %d, names.length = %d\n", cast(int) exps.length, cast(int) names.length);
+ printf("exps = %s, names = %s\n", exps.toChars(), names.toChars());
+ if (exps.length > 0)
+ printf("%s\n", (*exps)[0].loc.toChars());
+ assert(0);
+ }
+ }
+
+ // At `index`, a tuple of length `length` is expanded. Insert corresponding nulls in `names`.
+ void expandNames(size_t index, size_t length)
+ {
+ if (names)
+ {
+ if (length == 0)
+ {
+ names.remove(index);
+ return;
+ }
+ foreach (i; 1 .. length)
+ {
+ names.insert(index + i, cast(Identifier) null);
+ }
+ }
+ }
+
for (size_t i = 0; i < exps.length; i++)
{
Expression arg = (*exps)[i];
if (!tt.arguments || tt.arguments.length == 0)
{
exps.remove(i);
+ expandNames(i, 0);
if (i == exps.length)
return;
}
foreach (j, a; *tt.arguments)
(*texps)[j] = new TypeExp(e.loc, a.type);
exps.insert(i, texps);
+ expandNames(i, texps.length);
}
i--;
continue;
TupleExp te = cast(TupleExp)arg;
exps.remove(i); // remove arg
exps.insert(i, te.exps); // replace with tuple contents
+ expandNames(i, te.exps.length);
if (i == exps.length)
return; // empty tuple, no more arguments
(*exps)[i] = Expression.combine(te.e0, (*exps)[i]);
{
const EXP op; // to minimize use of dynamic_cast
ubyte size; // # of bytes in Expression so we can copy() it
- ubyte parens; // if this is a parenthesized expression
+ bool parens; // if this is a parenthesized expression
Type type; // !=null means that semantic() has been run
Loc loc; // file location
- extern (D) this(const ref Loc loc, EXP op, int size)
+ extern (D) this(const ref Loc loc, EXP op, int size) scope
{
//printf("Expression::Expression(op = %d) this = %p\n", op, this);
this.loc = loc;
*/
private static bool checkImpure(Scope* sc)
{
- return sc.func && (sc.flags & SCOPE.compile
+ return sc.func && (isRootTraitsCompilesScope(sc)
? sc.func.isPureBypassingInference() >= PURE.weak
: sc.func.setImpure());
}
if (!f.isSafe() && !f.isTrusted())
{
- if (sc.flags & SCOPE.compile ? sc.func.isSafeBypassingInference() : sc.func.setUnsafeCall(f))
+ if (isRootTraitsCompilesScope(sc) ? sc.func.isSafeBypassingInference() : sc.func.setUnsafeCall(f))
{
if (!loc.isValid()) // e.g. implicitly generated dtor
loc = sc.func.loc;
if (!f.isNogc())
{
- if (sc.flags & SCOPE.compile ? sc.func.isNogcBypassingInference() : sc.func.setGC())
+ if (isRootTraitsCompilesScope(sc) ? sc.func.isNogcBypassingInference() : sc.func.setGC())
{
if (loc.linnum == 0) // e.g. implicitly generated dtor
loc = sc.func.loc;
// Lowered non-@nogc'd hooks will print their own error message inside of nogc.d (NOGCVisitor.visit(CallExp e)),
// so don't print anything to avoid double error messages.
if (!(f.ident == Id._d_HookTraceImpl || f.ident == Id._d_arraysetlengthT
- || f.ident == Id._d_arrayappendT || f.ident == Id._d_arrayappendcTX))
+ || f.ident == Id._d_arrayappendT || f.ident == Id._d_arrayappendcTX
+ || f.ident == Id._d_newclassT))
error("`@nogc` %s `%s` cannot call non-@nogc %s `%s`",
sc.func.kind(), sc.func.toPrettyChars(), f.kind(), f.toPrettyChars());
return .isConst(this);
}
+ /******
+ * Identical, not just equal. I.e. NaNs with different bit patterns are not identical
+ */
+ bool isIdentical(const Expression e) const
+ {
+ return equals(e);
+ }
+
+
/// Statically evaluate this expression to a `bool` if possible
/// Returns: an optional thath either contains the value or is empty
Optional!bool toBool()
return false;
}
+ override bool isIdentical(const Expression e) const
+ {
+ if (!equals(e))
+ return false;
+ return CTFloat.isIdentical(value, e.isRealExp().value);
+ }
+
override dinteger_t toInteger()
{
return cast(sinteger_t)toReal();
return false;
}
+ override bool isIdentical(const Expression e) const
+ {
+ if (!equals(e))
+ return false;
+ // equals() regards different NaN values as 'equals'
+ auto c = e.isComplexExp();
+ return CTFloat.isIdentical(creall(value), creall(c.value)) &&
+ CTFloat.isIdentical(cimagl(value), cimagl(c.value));
+ }
+
override dinteger_t toInteger()
{
return cast(sinteger_t)toReal();
{
Identifier ident;
- extern (D) this(const ref Loc loc, Identifier ident)
+ extern (D) this(const ref Loc loc, Identifier ident) scope
{
super(loc, EXP.identifier, __traits(classInstanceSize, IdentifierExp));
this.ident = ident;
*/
extern (C++) final class NullExp : Expression
{
- extern (D) this(const ref Loc loc, Type type = null)
+ extern (D) this(const ref Loc loc, Type type = null) scope
{
super(loc, EXP.null_, __traits(classInstanceSize, NullExp));
this.type = type;
char postfix = NoPostfix; // 'c', 'w', 'd'
OwnedBy ownedByCtfe = OwnedBy.code;
- extern (D) this(const ref Loc loc, const(void)[] string)
+ extern (D) this(const ref Loc loc, const(void)[] string) scope
{
super(loc, EXP.string_, __traits(classInstanceSize, StringExp));
this.string = cast(char*)string.ptr; // note that this.string should be const
this.sz = 1; // work around LDC bug #1286
}
- extern (D) this(const ref Loc loc, const(void)[] string, size_t len, ubyte sz, char postfix = NoPostfix)
+ extern (D) this(const ref Loc loc, const(void)[] string, size_t len, ubyte sz, char postfix = NoPostfix) scope
{
super(loc, EXP.string_, __traits(classInstanceSize, StringExp));
this.string = cast(char*)string.ptr; // note that this.string should be const
Expression thisexp; // if !=null, 'this' for class being allocated
Type newtype;
Expressions* arguments; // Array of Expression's
+ Identifiers* names; // Array of names corresponding to expressions
Expression argprefix; // expression to be evaluated just before arguments[]
CtorDeclaration member; // constructor function
bool onstack; // allocate on stack
bool thrownew; // this NewExp is the expression of a ThrowStatement
- extern (D) this(const ref Loc loc, Expression thisexp, Type newtype, Expressions* arguments)
+ Expression lowering; // lowered druntime hook: `_d_newclass`
+
+ /// Puts the `arguments` and `names` into an `ArgumentList` for easily passing them around.
+ /// The fields are still separate for backwards compatibility
+ extern (D) ArgumentList argumentList() { return ArgumentList(arguments, names); }
+
+ extern (D) this(const ref Loc loc, Expression thisexp, Type newtype, Expressions* arguments, Identifiers* names = null)
{
super(loc, EXP.new_, __traits(classInstanceSize, NewExp));
this.thisexp = thisexp;
this.newtype = newtype;
this.arguments = arguments;
+ this.names = names;
}
static NewExp create(const ref Loc loc, Expression thisexp, Type newtype, Expressions* arguments)
return new NewExp(loc,
thisexp ? thisexp.syntaxCopy() : null,
newtype.syntaxCopy(),
- arraySyntaxCopy(arguments));
+ arraySyntaxCopy(arguments),
+ names ? names.copy() : null);
}
override void accept(Visitor v)
Type t = pto.type;
if (t.ty == Terror)
return cannotInfer(this, to, flag);
+ tf.parameterList[u].storageClass = tof.parameterList[u].storageClass;
tiargs.push(t);
}
TOK tok; // ':' or '=='
TOK tok2; // 'struct', 'union', etc.
- extern (D) this(const ref Loc loc, Type targ, Identifier id, TOK tok, Type tspec, TOK tok2, TemplateParameters* parameters)
+ extern (D) this(const ref Loc loc, Type targ, Identifier id, TOK tok, Type tspec, TOK tok2, TemplateParameters* parameters) scope
{
super(loc, EXP.is_, __traits(classInstanceSize, IsExp));
this.targ = targ;
Expression e1;
Type att1; // Save alias this type to detect recursion
- extern (D) this(const ref Loc loc, EXP op, int size, Expression e1)
+ extern (D) this(const ref Loc loc, EXP op, int size, Expression e1) scope
{
super(loc, op, size);
this.e1 = e1;
Type att1; // Save alias this type to detect recursion
Type att2; // Save alias this type to detect recursion
- extern (D) this(const ref Loc loc, EXP op, int size, Expression e1, Expression e2)
+ extern (D) this(const ref Loc loc, EXP op, int size, Expression e1, Expression e2) scope
{
super(loc, op, size);
this.e1 = e1;
*/
extern (C++) class BinAssignExp : BinExp
{
- extern (D) this(const ref Loc loc, EXP op, int size, Expression e1, Expression e2)
+ extern (D) this(const ref Loc loc, EXP op, int size, Expression e1, Expression e2) scope
{
super(loc, op, size, e1, e2);
}
}
}
+/**
+ * The arguments of a function call
+ *
+ * Contains a list of expressions. If it is a named argument, the `names`
+ * list has a non-null entry at the same index.
+ */
+struct ArgumentList
+{
+ Expressions* arguments; // function arguments
+ Identifiers* names; // named argument identifiers
+
+ size_t length() const @nogc nothrow pure @safe { return arguments ? arguments.length : 0; }
+
+ /// Returns: whether this argument list contains any named arguments
+ bool hasNames() const @nogc nothrow pure @safe
+ {
+ if (names is null)
+ return false;
+ foreach (name; *names)
+ if (name !is null)
+ return true;
+
+ return false;
+ }
+}
+
/***********************************************************
*/
extern (C++) final class CallExp : UnaExp
{
Expressions* arguments; // function arguments
+ Identifiers* names; // named argument identifiers
FuncDeclaration f; // symbol to call
bool directcall; // true if a virtual call is devirtualized
bool inDebugStatement; /// true if this was in a debug statement
bool ignoreAttributes; /// don't enforce attributes (e.g. call @gc function in @nogc code)
VarDeclaration vthis2; // container for multi-context
- extern (D) this(const ref Loc loc, Expression e, Expressions* exps)
+ /// Puts the `arguments` and `names` into an `ArgumentList` for easily passing them around.
+ /// The fields are still separate for backwards compatibility
+ extern (D) ArgumentList argumentList() { return ArgumentList(arguments, names); }
+
+ extern (D) this(const ref Loc loc, Expression e, Expressions* exps, Identifiers* names = null)
{
super(loc, EXP.call, __traits(classInstanceSize, CallExp), e);
this.arguments = exps;
+ this.names = names;
}
extern (D) this(const ref Loc loc, Expression e)
override CallExp syntaxCopy()
{
- return new CallExp(loc, e1.syntaxCopy(), arraySyntaxCopy(arguments));
+ return new CallExp(loc, e1.syntaxCopy(), arraySyntaxCopy(arguments), names ? names.copy() : null);
}
override bool isLvalue()
*/
extern (C++) final class UAddExp : UnaExp
{
- extern (D) this(const ref Loc loc, Expression e)
+ extern (D) this(const ref Loc loc, Expression e) scope
{
super(loc, EXP.uadd, __traits(classInstanceSize, UAddExp), e);
}
*/
extern (C++) final class CatExp : BinExp
{
- extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2) scope
{
super(loc, EXP.concatenate, __traits(classInstanceSize, CatExp), e1, e2);
}
{
Expression econd;
- extern (D) this(const ref Loc loc, Expression econd, Expression e1, Expression e2)
+ extern (D) this(const ref Loc loc, Expression econd, Expression e1, Expression e2) scope
{
super(loc, EXP.question, __traits(classInstanceSize, CondExp), e1, e2);
this.econd = econd;
struct Symbol; // back end symbol
#endif
-void expandTuples(Expressions *exps);
+void expandTuples(Expressions *exps, Identifiers *names = nullptr);
bool isTrivialExp(Expression *e);
bool hasSideEffect(Expression *e, bool assumeImpureCalls = false);
public:
EXP op; // to minimize use of dynamic_cast
unsigned char size; // # of bytes in Expression so we can copy() it
- unsigned char parens; // if this is a parenthesized expression
+ bool parens; // if this is a parenthesized expression
Type *type; // !=NULL means that semantic() has been run
Loc loc; // file location
// A compile-time result is required. Give an error if not possible
Expression *ctfeInterpret();
int isConst();
+ virtual bool isIdentical(const Expression *e) const;
virtual Optional<bool> toBool();
virtual bool hasCode()
{
static RealExp *create(const Loc &loc, real_t value, Type *type);
static void emplace(UnionExp *pue, const Loc &loc, real_t value, Type *type);
bool equals(const RootObject * const o) const override;
+ bool isIdentical(const Expression *e) const override;
dinteger_t toInteger() override;
uinteger_t toUInteger() override;
real_t toReal() override;
static ComplexExp *create(const Loc &loc, complex_t value, Type *type);
static void emplace(UnionExp *pue, const Loc &loc, complex_t value, Type *type);
bool equals(const RootObject * const o) const override;
+ bool isIdentical(const Expression *e) const override;
dinteger_t toInteger() override;
uinteger_t toUInteger() override;
real_t toReal() override;
Expression *thisexp; // if !NULL, 'this' for class being allocated
Type *newtype;
Expressions *arguments; // Array of Expression's
+ Identifiers *names; // Array of names corresponding to expressions
Expression *argprefix; // expression to be evaluated just before arguments[]
bool onstack; // allocate on stack
bool thrownew; // this NewExp is the expression of a ThrowStatement
+ Expression *lowering; // lowered druntime hook: `_d_newclass`
+
static NewExp *create(const Loc &loc, Expression *thisexp, Type *newtype, Expressions *arguments);
NewExp *syntaxCopy() override;
{
public:
Expressions *arguments; // function arguments
+ Identifiers *names;
FuncDeclaration *f; // symbol to call
bool directcall; // true if a virtual call is devirtualized
bool inDebugStatement; // true if this was in a debug statement
if (!ex)
continue;
auto sc2 = sc.startCTFE();
+ sc2.tinst = null;
+ sc2.minst = null; // prevents emission of any instantiated templates to object file
auto e2 = ex.expressionSemantic(sc2);
auto e3 = resolveProperties(sc2, e2);
sc2.endCTFE();
uint xerrors = global.startGagging();
sc = sc.push();
- FuncDeclaration fslice = resolveFuncCall(ae.loc, sc, slice, tiargs, ae.e1.type, fargs, FuncResolveFlag.quiet);
+ FuncDeclaration fslice = resolveFuncCall(ae.loc, sc, slice, tiargs, ae.e1.type, ArgumentList(fargs), FuncResolveFlag.quiet);
sc = sc.pop();
global.endGagging(xerrors);
if (!fslice)
if (!ce.arguments)
ce.arguments = new Expressions();
ce.arguments.shift(eleft);
+ if (!ce.names)
+ ce.names = new Identifiers();
+ ce.names.shift(null);
return null;
}
for (size_t i = 0; i < os.a.length; i++)
{
- if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, &a, FuncResolveFlag.quiet))
+ if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, ArgumentList(&a), FuncResolveFlag.quiet))
{
if (f.errors)
return ErrorExp.get();
{
for (size_t i = 0; i < os.a.length; i++)
{
- if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, null, FuncResolveFlag.quiet))
+ if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, ArgumentList(), FuncResolveFlag.quiet))
{
if (f.errors)
return ErrorExp.get();
Expressions a;
a.push(e2);
- FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, &a, FuncResolveFlag.quiet);
+ FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, ArgumentList(&a), FuncResolveFlag.quiet);
if (fd && fd.type)
{
if (fd.errors)
}
}
{
- FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, null, FuncResolveFlag.quiet);
+ FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, ArgumentList(), FuncResolveFlag.quiet);
if (fd && fd.type)
{
if (fd.errors)
/*********************
* Rewrite:
* array.length op= e2
- * as:
- * array.length = array.length op e2
- * or:
- * auto tmp = &array;
- * (*tmp).length = (*tmp).length op e2
*/
private Expression rewriteOpAssign(BinExp exp)
{
ArrayLengthExp ale = exp.e1.isArrayLengthExp();
if (ale.e1.isVarExp())
{
+ // array.length = array.length op e2
Expression e = opAssignToOp(exp.loc, exp.op, ale, exp.e2);
e = new AssignExp(exp.loc, ale.syntaxCopy(), e);
return e;
}
else
{
- /* auto tmp = &array;
- * (*tmp).length = (*tmp).length op e2
- */
- auto tmp = copyToTemp(0, "__arraylength", new AddrExp(ale.loc, ale.e1));
-
- Expression e1 = new ArrayLengthExp(ale.loc, new PtrExp(ale.loc, new VarExp(ale.loc, tmp)));
+ // (ref tmp = array;), tmp.length = tmp.length op e2
+ auto tmp = copyToTemp(STC.ref_, "__arraylength", ale.e1);
+ Expression e1 = new ArrayLengthExp(ale.loc, new VarExp(ale.loc, tmp));
Expression elvalue = e1.syntaxCopy();
Expression e = opAssignToOp(exp.loc, exp.op, e1, exp.e2);
e = new AssignExp(exp.loc, elvalue, e);
/****************************************
* Preprocess arguments to function.
- * Input:
- * reportErrors whether or not to report errors here. Some callers are not
+ *
+ * Tuples in argumentList get expanded, properties resolved, rewritten in place
+ *
+ * Params:
+ * sc = scope
+ * argumentList = arguments to function
+ * reportErrors = whether or not to report errors here. Some callers are not
* checking actual function params, so they'll do their own error reporting
- * Output:
- * exps[] tuples expanded, properties resolved, rewritten in place
* Returns:
- * true a semantic error occurred
+ * `true` when a semantic error occurred
*/
-private bool preFunctionParameters(Scope* sc, Expressions* exps, const bool reportErrors = true)
+private bool preFunctionParameters(Scope* sc, ArgumentList argumentList, const bool reportErrors = true)
{
+ Expressions* exps = argumentList.arguments;
bool err = false;
if (exps)
{
- expandTuples(exps);
+ expandTuples(exps, argumentList.names);
for (size_t i = 0; i < exps.length; i++)
{
* tf = type of the function
* ethis = `this` argument, `null` if none or not known
* tthis = type of `this` argument, `null` if no `this` argument
- * arguments = array of actual arguments to function call
+ * argumentsList = array of actual arguments to function call
* fd = the function being called, `null` if called indirectly
* prettype = set to return type of function
* peprefix = set to expression to execute before `arguments[]` are evaluated, `null` if none
* true errors happened
*/
private bool functionParameters(const ref Loc loc, Scope* sc,
- TypeFunction tf, Expression ethis, Type tthis, Expressions* arguments, FuncDeclaration fd,
+ TypeFunction tf, Expression ethis, Type tthis, ArgumentList argumentList, FuncDeclaration fd,
Type* prettype, Expression* peprefix)
{
+ Expressions* arguments = argumentList.arguments;
//printf("functionParameters() %s\n", fd ? fd.toChars() : "");
assert(arguments);
assert(fd || tf.next);
- size_t nargs = arguments ? arguments.length : 0;
const size_t nparams = tf.parameterList.length;
const olderrors = global.errors;
bool err = false;
- *prettype = Type.terror;
Expression eprefix = null;
*peprefix = null;
+ if (argumentList.names)
+ {
+ const(char)* msg = null;
+ auto resolvedArgs = tf.resolveNamedArgs(argumentList, &msg);
+ if (!resolvedArgs)
+ {
+ // while errors are usually already caught by `tf.callMatch`,
+ // this can happen when calling `typeof(freefunc)`
+ if (msg)
+ error(loc, "%s", msg);
+ return true;
+ }
+ // note: the argument list should be mutated with named arguments / default arguments,
+ // so we can't simply change the pointer like `arguments = resolvedArgs;`
+ arguments.setDim(0);
+ arguments.pushSlice((*resolvedArgs)[]);
+ }
+ size_t nargs = arguments ? arguments.length : 0;
+
if (nargs > nparams && tf.parameterList.varargs == VarArg.none)
{
error(loc, "expected %llu arguments, not %llu for non-variadic function type `%s`", cast(ulong)nparams, cast(ulong)nargs, tf.toChars());
return errorArgs();
}
arg = p.defaultArg;
+ if (!arg.type)
+ arg = arg.expressionSemantic(sc);
arg = inlineCopy(arg, sc);
// __FILE__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__
arg = arg.resolveLoc(loc, sc);
- arguments.push(arg);
- nargs++;
+ if (i >= nargs)
+ {
+ arguments.push(arg);
+ nargs++;
+ }
+ else
+ (*arguments)[i] = arg;
}
else
{
return errorInout(wildmatch);
}
- Expression firstArg = ((tf.next && tf.next.ty == Tvoid || isCtorCall) &&
- tthis &&
- tthis.isMutable() && tthis.toBasetype().ty == Tstruct &&
- tthis.hasPointers())
- ? ethis : null;
+ Expression firstArg = null;
+ final switch (returnParamDest(tf, tthis))
+ {
+ case ReturnParamDest.returnVal:
+ break;
+ case ReturnParamDest.firstArg:
+ firstArg = nargs > 0 ? (*arguments)[0] : null;
+ break;
+ case ReturnParamDest.this_:
+ firstArg = ethis;
+ break;
+ }
assert(nargs >= nparams);
foreach (const i, arg; (*arguments)[0 .. nargs])
err |= arg.checkSharedAccess(sc);
arg = arg.optimize(WANTvalue, p.isReference());
-
- /* Determine if this parameter is the "first reference" parameter through which
- * later "return" arguments can be stored.
- */
- if (i == 0 && !tthis && p.isReference() && p.type &&
- (tf.next && tf.next.ty == Tvoid || isCtorCall))
- {
- Type tb = p.type.baseElemOf();
- if (tb.isMutable() && tb.hasPointers())
- {
- firstArg = arg;
- }
- }
}
else
{
}
//if (eprefix) printf("eprefix: %s\n", eprefix.toChars());
- /* Test compliance with DIP1021
+ /* Test compliance with DIP1021 Argument Ownership and Function Calls
*/
- if (global.params.useDIP1021 &&
- tf.trust != TRUST.system && tf.trust != TRUST.trusted)
+ if (global.params.useDIP1021 && (tf.trust == TRUST.safe || tf.trust == TRUST.default_) ||
+ tf.islive)
err |= checkMutableArguments(sc, fd, tf, ethis, arguments, false);
// If D linkage and variadic, add _arguments[] as first argument
Scope* sc;
Expression result;
- this(Scope* sc)
+ this(Scope* sc) scope
{
this.sc = sc;
}
{
return setError();
}
- if (preFunctionParameters(sc, exp.arguments))
+ if (preFunctionParameters(sc, exp.argumentList))
{
return setError();
}
if (cd.ctor)
{
- FuncDeclaration f = resolveFuncCall(exp.loc, sc, cd.ctor, null, tb, exp.arguments, FuncResolveFlag.standard);
+ FuncDeclaration f = resolveFuncCall(exp.loc, sc, cd.ctor, null, tb, exp.argumentList, FuncResolveFlag.standard);
if (!f || f.errors)
return setError();
TypeFunction tf = f.type.isTypeFunction();
if (!exp.arguments)
exp.arguments = new Expressions();
- if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.arguments, f, &exp.type, &exp.argprefix))
+ if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.argumentList, f, &exp.type, &exp.argprefix))
return setError();
exp.member = f.isCtorDeclaration();
result = id.expressionSemantic(sc);
return;
}
+ else if (!exp.onstack && !exp.type.isscope())
+ {
+ auto hook = global.params.tracegc ? Id._d_newclassTTrace : Id._d_newclassT;
+ if (!verifyHookExist(exp.loc, *sc, hook, "new class"))
+ return setError();
+
+ Expression id = new IdentifierExp(exp.loc, Id.empty);
+ id = new DotIdExp(exp.loc, id, Id.object);
+
+ auto tiargs = new Objects();
+ auto t = exp.newtype.unqualify(MODFlags.wild); // remove `inout`
+ tiargs.push(t);
+ id = new DotTemplateInstanceExp(exp.loc, id, hook, tiargs);
+ auto arguments = new Expressions();
+ if (global.params.tracegc)
+ {
+ auto funcname = (sc.callsc && sc.callsc.func) ?
+ sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
+ arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
+ arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
+ arguments.push(new StringExp(exp.loc, funcname.toDString()));
+ }
+ id = new CallExp(exp.loc, id, arguments);
+
+ exp.lowering = id.expressionSemantic(sc);
+ }
}
else if (auto ts = tb.isTypeStruct())
{
// is the same type as the struct
if (nargs && (sd.hasRegularCtor() || (sd.ctor && (*exp.arguments)[0].type.mutableOf() == sd.type.mutableOf())))
{
- FuncDeclaration f = resolveFuncCall(exp.loc, sc, sd.ctor, null, tb, exp.arguments, FuncResolveFlag.standard);
+ FuncDeclaration f = resolveFuncCall(exp.loc, sc, sd.ctor, null, tb, exp.argumentList, FuncResolveFlag.standard);
if (!f || f.errors)
return setError();
TypeFunction tf = f.type.isTypeFunction();
if (!exp.arguments)
exp.arguments = new Expressions();
- if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.arguments, f, &exp.type, &exp.argprefix))
+ if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.argumentList, f, &exp.type, &exp.argprefix))
return setError();
exp.member = f.isCtorDeclaration();
}
else
{
- if (!exp.arguments)
+ if (exp.names)
+ {
+ exp.arguments = resolveStructLiteralNamedArgs(sd, exp.type, sc, exp.loc,
+ exp.names ? (*exp.names)[] : null,
+ (size_t i, Type t) => (*exp.arguments)[i],
+ i => (*exp.arguments)[i].loc
+ );
+ if (!exp.arguments)
+ return setError();
+ }
+ else if (!exp.arguments)
+ {
exp.arguments = new Expressions();
+ }
if (!sd.fit(exp.loc, sc, exp.arguments, tb))
return setError();
}
Expression arg = (*exp.arguments)[i];
+ if (exp.names && (*exp.names)[i])
+ {
+ exp.error("no named argument `%s` allowed for array dimension", (*exp.names)[i].toChars());
+ return setError();
+ }
+
arg = resolveProperties(sc, arg);
arg = arg.implicitCastTo(sc, Type.tsize_t);
if (arg.op == EXP.error)
}
else if (nargs == 1)
{
+ if (exp.names && (*exp.names)[0])
+ {
+ exp.error("no named argument `%s` allowed for scalar", (*exp.names)[0].toChars());
+ return setError();
+ }
Expression e = (*exp.arguments)[0];
e = e.implicitCastTo(sc, tb);
(*exp.arguments)[0] = e;
if (FuncExp fe = exp.e1.isFuncExp())
{
if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc) ||
- preFunctionParameters(sc, exp.arguments))
+ preFunctionParameters(sc, exp.argumentList))
return setError();
// Run e1 semantic even if arguments have any errors
return;
}
if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc) ||
- preFunctionParameters(sc, exp.arguments))
+ preFunctionParameters(sc, exp.argumentList))
return setError();
// Check for call operator overload
/* It's a struct literal
*/
Lx:
- Expression e = new StructLiteralExp(exp.loc, sd, exp.arguments, exp.e1.type);
+ Expressions* resolvedArgs = exp.arguments;
+ if (exp.names)
+ {
+ resolvedArgs = resolveStructLiteralNamedArgs(sd, exp.e1.type, sc, exp.loc,
+ (*exp.names)[],
+ (size_t i, Type t) => (*exp.arguments)[i],
+ i => (*exp.arguments)[i].loc
+ );
+ if (!resolvedArgs)
+ {
+ result = ErrorExp.get();
+ return;
+ }
+ }
+
+ Expression e = new StructLiteralExp(exp.loc, sd, resolvedArgs, exp.e1.type);
e = e.expressionSemantic(sc);
result = e;
return;
L1:
// Rewrite as e1.call(arguments)
Expression e = new DotIdExp(exp.loc, exp.e1, Id.call);
- e = new CallExp(exp.loc, e, exp.arguments);
+ e = new CallExp(exp.loc, e, exp.arguments, exp.names);
e = e.expressionSemantic(sc);
result = e;
return;
}
FuncDeclaration resolveOverloadSet(Loc loc, Scope* sc,
- OverloadSet os, Objects* tiargs, Type tthis, Expressions* arguments)
+ OverloadSet os, Objects* tiargs, Type tthis, ArgumentList argumentList)
{
FuncDeclaration f = null;
foreach (s; os.a)
{
if (tiargs && s.isFuncDeclaration())
continue;
- if (auto f2 = resolveFuncCall(loc, sc, s, tiargs, tthis, arguments, FuncResolveFlag.quiet))
+ if (auto f2 = resolveFuncCall(loc, sc, s, tiargs, tthis, argumentList, FuncResolveFlag.quiet))
{
if (f2.errors)
return null;
}
// Do overload resolution
- exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, ue.e1.type, exp.arguments, FuncResolveFlag.standard);
+ exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, ue.e1.type, exp.argumentList, FuncResolveFlag.standard);
if (!exp.f || exp.f.errors || exp.f.type.ty == Terror)
return setError();
tthis = ad.type.addMod(sc.func.type.mod);
auto ctor = isSuper ? cd.baseClass.ctor : ad.ctor;
if (auto os = ctor.isOverloadSet())
- exp.f = resolveOverloadSet(exp.loc, sc, os, null, tthis, exp.arguments);
+ exp.f = resolveOverloadSet(exp.loc, sc, os, null, tthis, exp.argumentList);
else
- exp.f = resolveFuncCall(exp.loc, sc, ctor, null, tthis, exp.arguments, FuncResolveFlag.standard);
+ exp.f = resolveFuncCall(exp.loc, sc, ctor, null, tthis, exp.argumentList, FuncResolveFlag.standard);
if (!exp.f || exp.f.errors)
return setError();
}
else if (auto oe = exp.e1.isOverExp())
{
- exp.f = resolveOverloadSet(exp.loc, sc, oe.vars, tiargs, tthis, exp.arguments);
+ exp.f = resolveOverloadSet(exp.loc, sc, oe.vars, tiargs, tthis, exp.argumentList);
if (!exp.f)
return setError();
if (ethis)
else if (exp.e1.op == EXP.dotVariable && (cast(DotVarExp)exp.e1).var.isOverDeclaration())
{
DotVarExp dve = cast(DotVarExp)exp.e1;
- exp.f = resolveFuncCall(exp.loc, sc, dve.var, tiargs, dve.e1.type, exp.arguments, FuncResolveFlag.overloadOnly);
+ exp.f = resolveFuncCall(exp.loc, sc, dve.var, tiargs, dve.e1.type, exp.argumentList, FuncResolveFlag.overloadOnly);
if (!exp.f)
return setError();
if (exp.f.needThis())
{
s = (cast(TemplateExp)exp.e1).td;
L2:
- exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, null, exp.arguments, FuncResolveFlag.standard);
+ exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, null, exp.argumentList, FuncResolveFlag.standard);
if (!exp.f || exp.f.errors)
return setError();
if (exp.f.needThis())
}
const(char)* failMessage;
- Expression[] fargs = exp.arguments ? (*exp.arguments)[] : null;
- if (!tf.callMatch(null, fargs, 0, &failMessage, sc))
+ if (!tf.callMatch(null, exp.argumentList, 0, &failMessage, sc))
{
OutBuffer buf;
buf.writeByte('(');
tiargs = null;
if (exp.f.overnext)
- exp.f = resolveFuncCall(exp.loc, sc, exp.f, tiargs, null, exp.arguments, FuncResolveFlag.overloadOnly);
+ exp.f = resolveFuncCall(exp.loc, sc, exp.f, tiargs, null, exp.argumentList, FuncResolveFlag.overloadOnly);
else
{
exp.f = exp.f.toAliasFunc();
TypeFunction tf = cast(TypeFunction)exp.f.type;
const(char)* failMessage;
- Expression[] fargs = exp.arguments ? (*exp.arguments)[] : null;
- if (!tf.callMatch(null, fargs, 0, &failMessage, sc))
+ if (!tf.callMatch(null, exp.argumentList, 0, &failMessage, sc))
{
OutBuffer buf;
buf.writeByte('(');
//
// https://issues.dlang.org/show_bug.cgi?id=22157
if (exp.f.overnext)
- exp.f = resolveFuncCall(exp.loc, sc, exp.f, tiargs, null, exp.arguments, FuncResolveFlag.standard);
+ exp.f = resolveFuncCall(exp.loc, sc, exp.f, tiargs, null, exp.argumentList, FuncResolveFlag.standard);
if (!exp.f || exp.f.errors)
return setError();
Expression argprefix;
if (!exp.arguments)
exp.arguments = new Expressions();
- if (functionParameters(exp.loc, sc, cast(TypeFunction)t1, ethis, tthis, exp.arguments, exp.f, &exp.type, &argprefix))
+ if (functionParameters(exp.loc, sc, cast(TypeFunction)t1, ethis, tthis, exp.argumentList, exp.f, &exp.type, &argprefix))
return setError();
if (!exp.type)
{
// Handle this in the glue layer
e = new TypeidExp(exp.loc, ta);
- e.type = getTypeInfoType(exp.loc, ta, sc);
+ bool genObjCode = true;
+
+ // https://issues.dlang.org/show_bug.cgi?id=23650
+ // We generate object code for typeinfo, required
+ // by typeid, only if in non-speculative context
+ if (sc.flags & SCOPE.compile)
+ {
+ genObjCode = false;
+ }
+
+ e.type = getTypeInfoType(exp.loc, ta, sc, genObjCode);
semanticTypeInfo(sc, ta);
if (ea)
uint errors = global.errors;
const len = buf.length;
const str = buf.extractChars()[0 .. len];
- scope p = new Parser!ASTCodegen(exp.loc, sc._module, str, false);
+ scope p = new Parser!ASTCodegen(exp.loc, sc._module, str, false, global.errorSink);
p.nextToken();
//printf("p.loc.linnum = %d\n", p.loc.linnum);
Type t1b = exp.e1.type.toBasetype();
- if (t1b.ty == Tvector)
+ if (TypeVector tv1 = t1b.isTypeVector())
{
// Convert e1 to corresponding static array
- TypeVector tv1 = cast(TypeVector)t1b;
t1b = tv1.basetype;
t1b = t1b.castMod(tv1.mod);
- exp.e1.type = t1b;
+ exp.e1 = exp.e1.castTo(sc, t1b);
}
if (t1b.ty == Tsarray || t1b.ty == Tarray)
{
__equals = new DotIdExp(exp.loc, __equals, Id.object);
__equals = new DotIdExp(exp.loc, __equals, id);
+ /* https://issues.dlang.org/show_bug.cgi?id=23674
+ *
+ * Optimize before creating the call expression to the
+ * druntime hook as the optimizer may output errors
+ * that will get swallowed otherwise.
+ */
+ exp.e1 = exp.e1.optimize(WANTvalue);
+ exp.e2 = exp.e2.optimize(WANTvalue);
+
auto arguments = new Expressions(2);
(*arguments)[0] = exp.e1;
(*arguments)[1] = exp.e2;
//printf("checkSharedAccess() `%s` returnRef: %d\n", e.toChars(), returnRef);
- /* In case we don't know which expression triggered it,
- * e.g. for `visit(Type)` overload
- */
- Expression original = e;
-
bool check(Expression e, bool allowRef)
{
bool sharedError(Expression e)
// Error by default
bool visit(Expression e)
{
- if (e.type.isShared())
+ // https://issues.dlang.org/show_bug.cgi?id=23639
+ // Should be able to cast(shared)
+ if (!e.isCastExp() && e.type.isShared())
return sharedError(e);
return false;
}
{
if (e.thisexp)
check(e.thisexp, false);
- // Note: This handles things like `new shared(Throwable).msg`,
- // where accessing `msg` would violate `shared`.
- if (e.newtype.isShared())
- return sharedError(original);
return false;
}
return check(e.e1, false);
}
- bool visitThis(ThisExp e)
+ bool visitDotVar(DotVarExp e)
{
- if (sc.func && sc.func.isSynchronized())
- return false;
+ //printf("dotvarexp = %s\n", e.toChars());
+ if (e.type.isShared())
+ {
+ // / https://issues.dlang.org/show_bug.cgi?id=22626
+ if (e.e1.isThisExp() && sc.func && sc.func.isSynchronized())
+ return false;
- if (!allowRef && e.type.isShared())
- return sharedError(e);
+ auto fd = e.var.isFuncDeclaration();
+ const sharedFunc = fd && fd.type.isShared;
+ if (!allowRef && !sharedFunc)
+ return sharedError(e);
- return false;
- }
+ // Allow using `DotVarExp` within value types
+ if (e.e1.type.isTypeSArray() || e.e1.type.isTypeStruct())
+ return check(e.e1, allowRef);
- bool visitDotVar(DotVarExp e)
- {
- //printf("dotvarexp = %s\n", e.toChars());
- auto fd = e.var.isFuncDeclaration();
- const sharedFunc = fd && fd.type.isShared;
- // Allow using `DotVarExp` within value types
- if (!allowRef && e.type.isShared() && !sharedFunc && !(sc.func && sc.func.isSynchronized()))
- return sharedError(e);
- if (e.e1.type.isTypeSArray() || e.e1.type.isTypeStruct())
- return check(e.e1, allowRef);
+ // If we end up with a single `VarExp`, it might be a `ref` param
+ // `shared ref T` param == `shared(T)*`.
+ if (auto ve = e.e1.isVarExp())
+ {
+ return check(e.e1, allowRef && (ve.var.storage_class & STC.ref_));
+ }
- // If we end up with a single `VarExp`, it might be a `ref` param
- // `shared ref T` param == `shared(T)*`.
- if (auto ve = e.e1.isVarExp())
- {
- return check(e.e1, allowRef && (ve.var.storage_class & STC.ref_));
+ return sharedError(e);
}
return check(e.e1, false);
case EXP.star: return visitPtr(e.isPtrExp());
case EXP.dotVariable: return visitDotVar(e.isDotVarExp());
case EXP.index: return visitIndex(e.isIndexExp());
- case EXP.this_: return visitThis(e.isThisExp());
}
}
alias visit = typeof(super).visit;
extern (D) void delegate(VarDeclaration) dgVar;
- extern (D) this(void delegate(VarDeclaration) dgVar)
+ extern (D) this(void delegate(VarDeclaration) dgVar) scope
{
this.dgVar = dgVar;
}
bool inlineScanned; /// function has been scanned for inline possibilities
bool inferScope; /// infer 'scope' for parameters
bool hasCatches; /// function has try-catch statements
- bool isCompileTimeOnly; /// is a compile time only function; no code will be generated for it
+ bool skipCodegen; /// do not generate code for this function.
bool printf; /// is a printf-like function
bool scanf; /// is a scanf-like function
bool noreturn; /// the function does not return
bool hasAlwaysInlines; /// Contains references to functions that must be inlined
bool isCrtCtor; /// Has attribute pragma(crt_constructor)
bool isCrtDtor; /// Has attribute pragma(crt_destructor)
+ bool hasEscapingSiblings;/// Has sibling functions that escape
+ bool computedEscapingSiblings; /// `hasEscapingSiblings` has been computed
}
/***********************************************************
GotoStatements* gotos; /// Gotos with forward references
+ version (MARS)
+ {
+ VarDeclarations* alignSectionVars; /// local variables with alignment needs larger than stackAlign
+ Symbol* salignSection; /// pointer to aligned section, if any
+ }
+
/// set if this is a known, builtin function we can evaluate at compile time
BUILTIN builtin = BUILTIN.unknown;
* match 'this' is at least as specialized as g
* 0 g is more specialized than 'this'
*/
- final MATCH leastAsSpecialized(FuncDeclaration g)
+ final MATCH leastAsSpecialized(FuncDeclaration g, Identifiers* names)
{
enum LOG_LEASTAS = 0;
static if (LOG_LEASTAS)
{
- printf("%s.leastAsSpecialized(%s)\n", toChars(), g.toChars());
+ import core.stdc.stdio : printf;
+ printf("%s.leastAsSpecialized(%s, %s)\n", toChars(), g.toChars(), names ? names.toChars() : "null");
printf("%s, %s\n", type.toChars(), g.type.toChars());
}
args.push(e);
}
- MATCH m = tg.callMatch(null, args[], 1);
+ MATCH m = tg.callMatch(null, ArgumentList(&args, names), 1);
if (m > MATCH.nomatch)
{
/* A variadic parameter list is less specialized than a
if (!sc.intypeof && !(sc.flags & SCOPE.compile))
{
siblingCallers.push(fdthis);
+ computedEscapingSiblings = false;
}
}
}
* is already set to `true` upon entering this function when the
* struct/class refers to a local variable and a closure is needed.
*/
-
- //printf("FuncDeclaration::needsClosure() %s\n", toChars());
+ //printf("FuncDeclaration::needsClosure() %s\n", toPrettyChars());
if (requiresClosure)
goto Lyes;
*/
extern (C++) final bool checkClosure()
{
- //printf("checkClosure() %s\n", toChars());
+ //printf("checkClosure() %s\n", toPrettyChars());
if (!needsClosure())
return false;
* base.in();
* assert(false, "Logic error: " ~ thr.msg);
* }
+ * }
*/
foreach (fdv; foverrides)
return false;
if (v.nestedrefs.length && needsClosure())
return false;
+ // don't know if the return storage is aligned
+ version (MARS)
+ {
+ if (alignSectionVars && (*alignSectionVars).contains(v))
+ return false;
+ }
// The variable type needs to be equivalent to the return type.
if (!v.type.equivalent(tf.next))
return false;
* s = instantiation symbol
* tiargs = initial list of template arguments
* tthis = if !NULL, the `this` argument type
- * fargs = arguments to function
+ * argumentList = arguments to function
* flags = see $(LREF FuncResolveFlag).
* Returns:
* if match is found, then function symbol, else null
*/
FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
- Objects* tiargs, Type tthis, Expressions* fargs, FuncResolveFlag flags)
+ Objects* tiargs, Type tthis, ArgumentList argumentList, FuncResolveFlag flags)
{
+ auto fargs = argumentList.arguments;
if (!s)
return null; // no match
printf("\t%s: %s\n", arg.toChars(), arg.type.toChars());
}
}
+ printf("\tfnames: %s\n", fnames ? fnames.toChars() : "null");
}
if (tiargs && arrayObjectIsError(tiargs))
return null;
MatchAccumulator m;
- functionResolve(m, s, loc, sc, tiargs, tthis, fargs, null);
+ functionResolve(m, s, loc, sc, tiargs, tthis, argumentList);
auto orig_s = s;
if (m.last > MATCH.nomatch && m.lastf)
}
const(char)* failMessage;
- functionResolve(m, orig_s, loc, sc, tiargs, tthis, fargs, &failMessage);
+ functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &failMessage);
if (failMessage)
{
.error(loc, "%s `%s%s%s` is not callable using argument types `%s`",
if (auto baseFunction = baseClass.search(baseClass.loc, fd.ident))
{
MatchAccumulator mErr;
- functionResolve(mErr, baseFunction, loc, sc, tiargs, baseClass.type, fargs, null);
+ functionResolve(mErr, baseFunction, loc, sc, tiargs, baseClass.type, argumentList);
if (mErr.last > MATCH.nomatch && mErr.lastf)
{
errorSupplemental(loc, "%s `%s` hides base class function `%s`",
}
}
const(char)* failMessage;
- functionResolve(m, orig_s, loc, sc, tiargs, tthis, fargs, &failMessage);
+ functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &failMessage);
if (failMessage)
errorSupplemental(loc, failMessage);
}
private void printCandidates(Decl)(const ref Loc loc, Decl declaration, bool showDeprecated)
if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration))
{
- // max num of overloads to print (-v overrides this).
- enum int DisplayLimit = 5;
+ // max num of overloads to print (-v or -verror-supplements overrides this).
+ const int DisplayLimit = !global.params.verbose ?
+ (global.params.errorSupplementLimit ? global.params.errorSupplementLimit : int.max)
+ : int.max;
const(char)* constraintsTip;
// determine if the first candidate was printed
int printed;
FuncDeclaration f;
}
+ if (f.computedEscapingSiblings)
+ return f.hasEscapingSiblings;
+
PrevSibling ps;
ps.p = cast(PrevSibling*)p;
ps.f = f;
prev = prev.p;
}
}
+ f.hasEscapingSiblings = bAnyClosures;
+ f.computedEscapingSiblings = true;
//printf("\t%d\n", bAnyClosures);
return bAnyClosures;
}
{
super(loc, endloc, Id.ctor, stc, type);
this.isCpCtor = isCpCtor;
- //printf("CtorDeclaration(loc = %s) %s\n", loc.toChars(), toChars());
+ //printf("CtorDeclaration(loc = %s) %s %p\n", loc.toChars(), toChars(), this);
}
override CtorDeclaration syntaxCopy(Dsymbol s)
}
}
+/**************************************
+ * When a traits(compiles) is used on a function literal call
+ * we need to take into account if the body of the function
+ * violates any attributes, however, we must not affect the
+ * attribute inference on the outer function. The attributes
+ * of the function literal still need to be inferred, therefore
+ * we need a way to check for the scope that the traits compiles
+ * introduces.
+ *
+ * Params:
+ * sc = scope to be checked for
+ *
+ * Returns: `true` if the provided scope is the root
+ * of the traits compiles list of scopes.
+ */
+bool isRootTraitsCompilesScope(Scope* sc)
+{
+ return (sc.flags & SCOPE.compile) && !(sc.func.flags & SCOPE.compile);
+}
+
/**************************************
* A statement / expression in this scope is not `@safe`,
* so mark the enclosing function as `@system`
}
- if (sc.flags & SCOPE.compile) // __traits(compiles, x)
+ if (isRootTraitsCompilesScope(sc)) // __traits(compiles, x)
{
if (sc.func.isSafeBypassingInference())
{
import dmd.root.array;
import dmd.root.filename;
import dmd.common.outbuffer;
+import dmd.errorsink;
+import dmd.errors;
import dmd.file_manager;
import dmd.identifier;
import dmd.location;
bool logo; // print compiler logo
// Options for `-preview=/-revert=`
- FeatureState useDIP25; // implement https://wiki.dlang.org/DIP25
+ FeatureState useDIP25 = FeatureState.enabled; // implement https://wiki.dlang.org/DIP25
FeatureState useDIP1000; // implement https://dlang.org/spec/memory-safe-d.html#scope-return-params
bool ehnogc; // use @nogc exception handling
bool useDIP1021; // implement https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1021.md
CHECKACTION checkAction = CHECKACTION.D; // action to take when bounds, asserts or switch defaults are violated
uint errorLimit = 20;
+ uint errorSupplementLimit = 6; // Limit the number of supplemental messages for each error (0 means unlimited)
const(char)[] argv0; // program name
Array!(const(char)*) modFileAliasStrings; // array of char*'s of -I module filename alias strings
enum recursionLimit = 500; /// number of recursive template expansions before abort
+ ErrorSink errorSink; /// where the error messages go
+
extern (C++) FileName function(FileName, ref const Loc, out bool, OutBuffer*) preprocess;
nothrow:
extern (C++) void _init()
{
+ global.errorSink = new ErrorSinkCompiler;
+
this.fileManager = new FileManager();
version (MARS)
{
// Can't include arraytypes.h here, need to declare these directly.
template <typename TYPE> struct Array;
+class ErrorSink;
class FileManager;
struct Loc;
CHECKACTION checkAction; // action to take when bounds, asserts or switch defaults are violated
unsigned errorLimit;
+ unsigned errorSupplementLimit; // Limit the number of supplemental messages for each error (0 means unlimited)
DString argv0; // program name
Array<const char *> modFileAliasStrings; // array of char*'s of -I module filename alias strings
unsigned varSequenceNumber;
FileManager* fileManager;
+ ErrorSink* errorSink; // where the error messages go
FileName (*preprocess)(FileName, const Loc&, bool&, OutBuffer&);
int autoMember;
int forStmtInit;
int insideFuncBody;
+ int insideAggregate;
bool declstring; // set while declaring alias for string,wstring or dstring
EnumDeclaration inEnumDecl;
OutBuffer* buf;
HdrGenState* hgs;
- extern (D) this(OutBuffer* buf, HdrGenState* hgs)
+ extern (D) this(OutBuffer* buf, HdrGenState* hgs) scope
{
this.buf = buf;
this.hgs = hgs;
OutBuffer* buf;
HdrGenState* hgs;
- extern (D) this(OutBuffer* buf, HdrGenState* hgs)
+ extern (D) this(OutBuffer* buf, HdrGenState* hgs) scope
{
this.buf = buf;
this.hgs = hgs;
buf.writeByte('{');
buf.writenl();
buf.level++;
+ hgs.insideAggregate++;
foreach (s; *d.members)
s.accept(this);
+ hgs.insideAggregate--;
buf.level--;
buf.writeByte('}');
buf.writenl();
buf.writeByte('{');
buf.writenl();
buf.level++;
+ hgs.insideAggregate++;
foreach (s; *d.members)
s.accept(this);
+ hgs.insideAggregate--;
buf.level--;
buf.writeByte('}');
}
void visitVarDecl(VarDeclaration v, bool anywritten)
{
+ const bool isextern = hgs.hdrgen &&
+ !hgs.insideFuncBody &&
+ !hgs.tpltMember &&
+ !hgs.insideAggregate &&
+ !(v.storage_class & STC.manifest);
+
+ void vinit(VarDeclaration v)
+ {
+ auto ie = v._init.isExpInitializer();
+ if (ie && (ie.exp.op == EXP.construct || ie.exp.op == EXP.blit))
+ (cast(AssignExp)ie.exp).e2.expressionToBuffer(buf, hgs);
+ else
+ v._init.initializerToBuffer(buf, hgs);
+ }
+
if (anywritten)
{
buf.writestring(", ");
}
else
{
- if (stcToBuffer(buf, v.storage_class))
+ const bool useTypeof = isextern && v._init && !v.type;
+ auto stc = v.storage_class;
+ if (isextern)
+ stc |= STC.extern_;
+ if (useTypeof)
+ stc &= ~STC.auto_;
+ if (stcToBuffer(buf, stc))
buf.writeByte(' ');
if (v.type)
typeToBuffer(v.type, v.ident, buf, hgs);
+ else if (useTypeof)
+ {
+ buf.writestring("typeof(");
+ vinit(v);
+ buf.writestring(") ");
+ buf.writestring(v.ident.toString());
+ }
else
buf.writestring(v.ident.toString());
}
- if (v._init)
+ if (v._init && !isextern)
{
buf.writestring(" = ");
- auto ie = v._init.isExpInitializer();
- if (ie && (ie.exp.op == EXP.construct || ie.exp.op == EXP.blit))
- (cast(AssignExp)ie.exp).e2.expressionToBuffer(buf, hgs);
- else
- v._init.initializerToBuffer(buf, hgs);
+ vinit(v);
}
}
if (e.arguments && e.arguments.length)
{
buf.writeByte('(');
- argsToBuffer(e.arguments, buf, hgs);
+ argsToBuffer(e.arguments, buf, hgs, null, e.names);
buf.writeByte(')');
}
}
else
expToBuffer(e.e1, precedence[e.op], buf, hgs);
buf.writeByte('(');
- argsToBuffer(e.arguments, buf, hgs);
+ argsToBuffer(e.arguments, buf, hgs, null, e.names);
buf.writeByte(')');
}
Plus one for rounding. */
const(size_t) BUFFER_LEN = value.sizeof * 3 + 8 + 1 + 1;
char[BUFFER_LEN] buffer = void;
- CTFloat.sprint(buffer.ptr, 'g', value);
+ CTFloat.sprint(buffer.ptr, BUFFER_LEN, 'g', value);
assert(strlen(buffer.ptr) < BUFFER_LEN);
if (allowHex)
{
real_t r = CTFloat.parse(buffer.ptr, isOutOfRange);
//assert(!isOutOfRange); // test/compilable/test22725.c asserts here
if (r != value) // if exact duplication
- CTFloat.sprint(buffer.ptr, 'a', value);
+ CTFloat.sprint(buffer.ptr, BUFFER_LEN, 'a', value);
}
buf.writestring(buffer.ptr);
if (buffer.ptr[strlen(buffer.ptr) - 1] == '.')
OutBuffer* buf;
HdrGenState* hgs;
- extern (D) this(OutBuffer* buf, HdrGenState* hgs)
+ extern (D) this(OutBuffer* buf, HdrGenState* hgs) scope
{
this.buf = buf;
this.hgs = hgs;
OutBuffer* buf;
HdrGenState* hgs;
- extern (D) this(OutBuffer* buf, HdrGenState* hgs)
+ extern (D) this(OutBuffer* buf, HdrGenState* hgs) scope
{
this.buf = buf;
this.hgs = hgs;
/**************************************************
* Write out argument list to buf.
+ * Params:
+ * expressions = argument list
+ * buf = buffer to write to
+ * hgs = context
+ * basis = replace `null`s in argument list with this expression (for sparse array literals)
+ * names = if non-null, use these as the names for the arguments
*/
-private void argsToBuffer(Expressions* expressions, OutBuffer* buf, HdrGenState* hgs, Expression basis = null)
+private void argsToBuffer(Expressions* expressions, OutBuffer* buf, HdrGenState* hgs, Expression basis = null, Identifiers* names = null)
{
if (!expressions || !expressions.length)
return;
{
if (i)
buf.writestring(", ");
+
+ if (names && i < names.length && (*names)[i])
+ {
+ buf.writestring((*names)[i].toString());
+ buf.writestring(": ");
+ }
if (!el)
el = basis;
if (el)
import dmd.astcodegen;
import dmd.dscope;
import dmd.errors;
+import dmd.errorsink;
import dmd.expression;
import dmd.expressionsem;
import dmd.identifier;
}
else
{
- p.error(s.loc, "expected identifier after `[`");
+ p.eSink.error(s.loc, "expected identifier after `[`");
goto Lerror;
}
// Look for closing `]`
break;
default:
- p.error("expected constant string constraint for operand, not `%s`",
+ p.eSink.error(p.token.loc, "expected constant string constraint for operand, not `%s`",
p.token.toChars());
goto Lerror;
}
break;
default:
- p.error("expected constant string constraint for clobber name, not `%s`",
+ p.eSink.error(p.token.loc, "expected constant string constraint for clobber name, not `%s`",
p.token.toChars());
goto Lerror;
}
break;
default:
- p.error("expected identifier for goto label name, not `%s`",
+ p.eSink.error(p.token.loc, "expected identifier for goto label name, not `%s`",
p.token.toChars());
goto Lerror;
}
extern (C++) public Statement gccAsmSemantic(GccAsmStatement s, Scope *sc)
{
//printf("GccAsmStatement.semantic()\n");
- scope p = new Parser!ASTCodegen(sc._module, ";", false);
+ scope p = new Parser!ASTCodegen(sc._module, ";", false, global.errorSink);
// Make a safe copy of the token list before parsing.
Token *toklist = null;
{
import dmd.mtype : TypeBasic;
+ if (!global.errorSink)
+ global.errorSink = new ErrorSinkCompiler;
+
uint errors = global.startGagging();
scope(exit) global.endGagging(errors);
{
const errors = global.errors;
scope gas = new GccAsmStatement(Loc.initial, tokens);
- scope p = new Parser!ASTCodegen(null, ";", false);
+ scope p = new Parser!ASTCodegen(null, ";", false, global.errorSink);
p.token = *tokens;
p.parseGccAsm(gas);
return global.errors - errors;
static void parseAsm(string input, bool expectError)
{
// Generate tokens from input test.
- scope p = new Parser!ASTCodegen(null, input, false);
+ scope p = new Parser!ASTCodegen(null, input, false, global.errorSink);
p.nextToken();
Token* toklist = null;
{ "__ArrayDtor" },
{ "_d_delThrowable" },
{ "_d_newThrowable" },
+ { "_d_newclassT" },
+ { "_d_newclassTTrace" },
{ "_d_assert_fail" },
{ "dup" },
{ "_aaApply" },
{ "isLazy" },
{ "hasMember" },
{ "identifier" },
+ { "fullyQualifiedName" },
{ "getProtection" },
{ "getVisibility" },
{ "parent" },
sd.size(i.loc);
if (sd.sizeok != Sizeok.done)
return err();
- const nfields = sd.nonHiddenFields();
- //expandTuples for non-identity arguments?
- auto elements = new Expressions(nfields);
- auto elems = (*elements)[];
- foreach (ref elem; elems)
- elem = null;
-
- // Run semantic for explicitly given initializers
- // TODO: this part is slightly different from StructLiteralExp::semantic.
- bool errors = false;
- size_t fieldi = 0;
- foreach (j, id; i.field[])
- {
- if (id)
- {
- /* Determine `fieldi` that `id` matches
- */
- Dsymbol s = sd.search(i.loc, id);
- if (!s)
- {
- s = sd.search_correct(id);
- const initLoc = i.value[j].loc;
- if (s)
- error(initLoc, "`%s` is not a member of `%s`, did you mean %s `%s`?", id.toChars(), sd.toChars(), s.kind(), s.toChars());
- else
- error(initLoc, "`%s` is not a member of `%s`", id.toChars(), sd.toChars());
- return err();
- }
- s.checkDeprecated(i.loc, sc);
- s = s.toAlias();
-
- // Find out which field index `s` is
- for (fieldi = 0; 1; fieldi++)
- {
- if (fieldi >= nfields)
- {
- error(i.loc, "`%s.%s` is not a per-instance initializable field", sd.toChars(), s.toChars());
- return err();
- }
- if (s == sd.fields[fieldi])
- break;
- }
- }
- if (j >= nfields)
- {
- error(i.value[j].loc, "too many initializers for `%s`", sd.toChars());
- return err();
- }
-
- VarDeclaration vd = sd.fields[fieldi];
- if (elems[fieldi])
- {
- error(i.value[j].loc, "duplicate initializer for field `%s`", vd.toChars());
- errors = true;
- elems[fieldi] = ErrorExp.get(); // for better diagnostics on multiple errors
- ++fieldi;
- continue;
- }
-
- // Check for @safe violations
- if (vd.type.hasPointers)
- {
- if ((!t.alignment.isDefault() && t.alignment.get() < target.ptrsize ||
- (vd.offset & (target.ptrsize - 1))))
- {
- if (sc.setUnsafe(false, i.value[j].loc,
- "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", sd, vd))
- {
- errors = true;
- elems[fieldi] = ErrorExp.get(); // for better diagnostics on multiple errors
- ++fieldi;
- continue;
- }
- }
- }
-
- // Check for overlapping initializations (can happen with unions)
- foreach (k, v2; sd.fields[0 .. nfields])
- {
- if (vd.isOverlappedWith(v2) && elems[k])
- {
- error(elems[k].loc, "overlapping initialization for field `%s` and `%s`", v2.toChars(), vd.toChars());
- errors = true;
- continue;
- }
- }
-
- // Convert initializer to Expression `ex`
- assert(sc);
- auto tm = vd.type.addMod(t.mod);
- auto iz = i.value[j].initializerSemantic(sc, tm, needInterpret);
- auto ex = iz.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0);
- if (ex.op == EXP.error)
- {
- errors = true;
- elems[fieldi] = ErrorExp.get(); // for better diagnostics on multiple errors
- ++fieldi;
- continue;
- }
+ Expression getExp(size_t j, Type fieldType)
+ {
+ // Convert initializer to Expression `ex`
+ auto tm = fieldType.addMod(t.mod);
+ auto iz = i.value[j].initializerSemantic(sc, tm, needInterpret);
+ auto ex = iz.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0);
+ if (ex.op != EXP.error)
i.value[j] = iz;
- elems[fieldi] = doCopyOrMove(sc, ex);
- ++fieldi;
- }
- if (errors)
+ return ex;
+ }
+ auto elements = resolveStructLiteralNamedArgs(sd, t, sc, i.loc, i.field[], &getExp, (size_t j) => i.value[j].loc);
+ if (!elements)
return err();
// Make a StructLiteralExp out of elements[]
}
return false;
}
+
+/**
+Given the names and values of a `StructInitializer` or `CallExp`,
+resolve it to a list of expressions to construct a `StructLiteralExp`.
+
+Params:
+ sd = struct
+ t = type of struct (potentially including qualifiers such as `const` or `immutable`)
+ sc = scope of the expression initializing the struct
+ iloc = location of expression initializing the struct
+ names = identifiers passed in argument list, `null` entries for positional arguments
+ getExp = function that, given an index into `names` and destination type, returns the initializing expression
+ getLoc = function that, given an index into `names`, returns a location for error messages
+
+Returns: list of expressions ordered to the struct's fields, or `null` on error
+*/
+Expressions* resolveStructLiteralNamedArgs(StructDeclaration sd, Type t, Scope* sc,
+ Loc iloc, Identifier[] names, scope Expression delegate(size_t i, Type fieldType) getExp,
+ scope Loc delegate(size_t i) getLoc
+)
+{
+ //expandTuples for non-identity arguments?
+ const nfields = sd.nonHiddenFields();
+ auto elements = new Expressions(nfields);
+ auto elems = (*elements)[];
+ foreach (ref elem; elems)
+ elem = null;
+
+ // Run semantic for explicitly given initializers
+ // TODO: this part is slightly different from StructLiteralExp::semantic.
+ bool errors = false;
+ size_t fieldi = 0;
+ foreach (j, id; names)
+ {
+ const argLoc = getLoc(j);
+ if (id)
+ {
+ // Determine `fieldi` that `id` matches
+ Dsymbol s = sd.search(iloc, id);
+ if (!s)
+ {
+ s = sd.search_correct(id);
+ if (s)
+ error(argLoc, "`%s` is not a member of `%s`, did you mean %s `%s`?", id.toChars(), sd.toChars(), s.kind(), s.toChars());
+ else
+ error(argLoc, "`%s` is not a member of `%s`", id.toChars(), sd.toChars());
+ return null;
+ }
+ s.checkDeprecated(iloc, sc);
+ s = s.toAlias();
+
+ // Find out which field index `s` is
+ for (fieldi = 0; 1; fieldi++)
+ {
+ if (fieldi >= nfields)
+ {
+ error(iloc, "`%s.%s` is not a per-instance initializable field", sd.toChars(), s.toChars());
+ return null;
+ }
+ if (s == sd.fields[fieldi])
+ break;
+ }
+ }
+ if (nfields == 0)
+ {
+ error(argLoc, "initializer provided for struct `%s` with no fields", sd.toChars());
+ return null;
+ }
+ if (j >= nfields)
+ {
+ error(argLoc, "too many initializers for `%s` with %d field%s", sd.toChars(),
+ cast(int) nfields, nfields != 1 ? "s".ptr : "".ptr);
+ return null;
+ }
+
+ VarDeclaration vd = sd.fields[fieldi];
+ if (elems[fieldi])
+ {
+ error(argLoc, "duplicate initializer for field `%s`", vd.toChars());
+ errors = true;
+ elems[fieldi] = ErrorExp.get(); // for better diagnostics on multiple errors
+ ++fieldi;
+ continue;
+ }
+
+ // Check for @safe violations
+ if (vd.type.hasPointers)
+ {
+ if ((!t.alignment.isDefault() && t.alignment.get() < target.ptrsize ||
+ (vd.offset & (target.ptrsize - 1))))
+ {
+ if (sc.setUnsafe(false, argLoc,
+ "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", sd, vd))
+ {
+ errors = true;
+ elems[fieldi] = ErrorExp.get(); // for better diagnostics on multiple errors
+ ++fieldi;
+ continue;
+ }
+ }
+ }
+
+ // Check for overlapping initializations (can happen with unions)
+ foreach (k, v2; sd.fields[0 .. nfields])
+ {
+ if (vd.isOverlappedWith(v2) && elems[k])
+ {
+ error(elems[k].loc, "overlapping initialization for field `%s` and `%s`", v2.toChars(), vd.toChars());
+ enum errorMsg = "`struct` initializers that contain anonymous unions" ~
+ " must initialize only the first member of a `union`. All subsequent" ~
+ " non-overlapping fields are default initialized";
+ if (!sd.isUnionDeclaration())
+ .errorSupplemental(elems[k].loc, errorMsg);
+ errors = true;
+ continue;
+ }
+ }
+
+ assert(sc);
+
+ auto ex = getExp(j, vd.type);
+
+ if (ex.op == EXP.error)
+ {
+ errors = true;
+ elems[fieldi] = ErrorExp.get(); // for better diagnostics on multiple errors
+ ++fieldi;
+ continue;
+ }
+
+ elems[fieldi] = doCopyOrMove(sc, ex);
+ ++fieldi;
+ }
+ if (errors)
+ return null;
+
+ return elements;
+}
int indentLevel;
const(char)[] filename;
- extern (D) this(OutBuffer* buf)
+ extern (D) this(OutBuffer* buf) scope
{
this.buf = buf;
}
OutBuffer buf;
alias visit = SemanticTimeTransitiveVisitor.visit;
- this(Scope* sc)
+ this(Scope* sc) scope
{
this.sc = sc;
}
import core.stdc.time;
import dmd.entity;
-import dmd.errors;
-import dmd.globals;
+import dmd.errorsink;
import dmd.id;
import dmd.identifier;
import dmd.location;
ubyte long_doublesize; /// size of C long double, 8 or D real.sizeof
ubyte wchar_tsize; /// size of C wchar_t, 2 or 4
+ ErrorSink eSink; /// send error messages through this interface
+
private
{
const(char)* base; // pointer to start of buffer
* endoffset = the last offset to read into base[]
* doDocComment = handle documentation comments
* commentToken = comments become TOK.comment's
+ * errorSink = where error messages go, must not be null
* vendor = name of the vendor
* versionNumber = version of the caller
*/
this(const(char)* filename, const(char)* base, size_t begoffset,
size_t endoffset, bool doDocComment, bool commentToken,
- const(char)[] vendor = "DLF", uint versionNumber = 1) pure
+ ErrorSink errorSink,
+ const(char)[] vendor = "DLF", uint versionNumber = 1) pure scope
{
scanloc = Loc(filename, 1, 1);
// debug printf("Lexer::Lexer(%p)\n", base);
this.tokenizeNewlines = false;
this.inTokenStringConstant = 0;
this.lastDocLine = 0;
+ this.eSink = errorSink;
+ assert(errorSink);
this.versionNumber = versionNumber;
this.vendor = vendor;
//initKeywords();
* Alternative entry point for DMDLIB, adds `whitespaceToken`
*/
this(const(char)* filename, const(char)* base, size_t begoffset, size_t endoffset,
- bool doDocComment, bool commentToken, bool whitespaceToken)
+ bool doDocComment, bool commentToken, bool whitespaceToken,
+ ErrorSink errorSink
+ )
{
- this(filename, base, begoffset, endoffset, doDocComment, commentToken);
+ this(filename, base, begoffset, endoffset, doDocComment, commentToken, errorSink);
this.whitespaceToken = whitespaceToken;
}
/******************
* Used for unittests for a mock Lexer
*/
- this() { }
+ this(ErrorSink errorSink) scope { assert(errorSink); this.eSink = errorSink; }
/**************************************
* Reset lexer to lex #define's
else if (*t.ptr == '_') // if special identifier token
{
// Lazy initialization
- TimeStampInfo.initialize(t.loc);
+ TimeStampInfo.initialize(t.loc, eSink);
if (id == Id.DATE)
{
else if (isspace(delimright))
error("delimited string must end in `\"`");
else
- error("delimited string must end in `%c\"`", delimright);
+ error(token.loc, "delimited string must end in `%c\"`", delimright);
result.setString(stringbuffer);
stringPostfix(result);
}
if (idx < n && !msg)
msg = utf_decodeChar(str, idx, d2);
if (msg)
- error(loc, "%s", msg);
+ error(loc, "%.*s", cast(int)msg.length, msg.ptr);
else if (idx < n)
error(loc, "max number of chars in 16 bit character literal is 2, had %d",
- (n + 1) >> 1);
+ cast(int)((n + 1) >> 1));
else if (d1 > 0x1_0000)
error(loc, "%d does not fit in 16 bits", d1);
else if (d2 > 0x1_0000)
size_t idx;
auto msg = utf_decodeChar(str, idx, d);
if (msg)
- error(loc, "%s", msg);
+ error(loc, "%.*s", cast(int)msg.length, msg.ptr);
else if (idx < n)
error(loc, "max number of chars in 32 bit character literal is 1, had %d",
- (n + 3) >> 2);
+ cast(int)((n + 3) >> 2));
u = d;
break;
Ldone:
if (errorDigit)
{
- error("%s digit expected, not `%c`", base == 2 ? "binary".ptr :
+ error(token.loc, "%s digit expected, not `%c`", base == 2 ? "binary".ptr :
base == 8 ? "octal".ptr :
"decimal".ptr, errorDigit);
err = true;
}
if ((base == 2 && !anyBinaryDigitsNoSingleUS) ||
(base == 16 && !anyHexDigitsNoSingleUS))
- error("`%.*s` isn't a valid integer literal, use `%.*s0` instead", cast(int)(p - start), start, 2, start);
+ error(token.loc, "`%.*s` isn't a valid integer literal, use `%.*s0` instead", cast(int)(p - start), start, 2, start);
t.unsvalue = n;
// can't translate invalid octal value, just show a generic message
error("octal literals larger than 7 are no longer supported");
else
- error("octal literals `0%llo%.*s` are no longer supported, use `std.conv.octal!\"%llo%.*s\"` instead",
+ error(token.loc, "octal literals `0%llo%.*s` are no longer supported, use `std.conv.octal!\"%llo%.*s\"` instead",
n, cast(int)(p - psuffix), psuffix, n, cast(int)(p - psuffix), psuffix);
}
TOK result;
TOK.float80Literal: "`real` for the current target".ptr][result];
error(scanloc, "number `%s%s` is not representable as a %s", sbufptr, suffix, type);
const char* extra = result == TOK.float64Literal ? "`real` literals can be written using the `L` suffix. " : "";
- errorSupplemental(scanloc, "%shttps://dlang.org/spec/lex.html#floatliteral", extra);
+ eSink.errorSupplemental(scanloc, "%shttps://dlang.org/spec/lex.html#floatliteral", extra);
}
debug
{
return scanloc;
}
- final void error(const(char)* format, ...)
+ void error(T...)(const(char)* format, T args)
+ {
+ eSink.error(token.loc, format, args);
+ }
+
+ void error(T...)(const ref Loc loc, const(char)* format, T args)
{
- va_list args;
- va_start(args, format);
- .verror(token.loc, format, args);
- va_end(args);
+ eSink.error(loc, format, args);
}
- final void error(const ref Loc loc, const(char)* format, ...)
+ final void deprecation(const(char)* format)
{
- va_list args;
- va_start(args, format);
- .verror(loc, format, args);
- va_end(args);
+ eSink.deprecation(token.loc, format);
}
- final void deprecation(const(char)* format, ...)
+ final void deprecationSupplemental(const(char)* format)
{
- va_list args;
- va_start(args, format);
- .vdeprecation(token.loc, format, args);
- va_end(args);
+ eSink.deprecationSupplemental(token.loc, format);
}
/***************************************
else
{
const locx = loc();
- warning(locx, "C preprocessor directive `#%s` is not supported", n.ident.toChars());
+ eSink.warning(locx, "C preprocessor directive `#%s` is not supported", n.ident.toChars());
}
}
else if (n.value == TOK.if_)
auto result = decodeUTFpure(msg);
if (msg)
- error("%.*s", cast(int)msg.length, msg.ptr);
+ error(token.loc, "%.*s", cast(int)msg.length, msg.ptr);
return result;
}
__gshared char[8 + 1] time;
__gshared char[24 + 1] timestamp;
- public static void initialize(const ref Loc loc) nothrow
+ public static void initialize(const ref Loc loc, ErrorSink eSink) nothrow
{
if (initdone)
return;
if (auto p = getenv("SOURCE_DATE_EPOCH"))
{
if (!ct.parseDigits(p.toDString()))
- error(loc, "value of environment variable `SOURCE_DATE_EPOCH` should be a valid UNIX timestamp, not: `%s`", p);
+ eSink.error(loc, "value of environment variable `SOURCE_DATE_EPOCH` should be a valid UNIX timestamp, not: `%s`", p);
}
else
.time(&ct);
const p = ctime(&ct);
assert(p);
- sprintf(&date[0], "%.6s %.4s", p + 4, p + 20);
- sprintf(&time[0], "%.8s", p + 11);
- sprintf(×tamp[0], "%.24s", p);
+ snprintf(&date[0], date.length, "%.6s %.4s", p + 4, p + 20);
+ snprintf(&time[0], time.length, "%.8s", p + 11);
+ snprintf(×tamp[0], timestamp.length, "%.24s", p);
}
}
unittest
{
- import dmd.console;
- nothrow bool assertDiagnosticHandler(const ref Loc loc, Color headerColor, const(char)* header,
- const(char)* format, va_list ap, const(char)* p1, const(char)* p2)
- {
- assert(0);
- }
- diagnosticHandler = &assertDiagnosticHandler;
+ fprintf(stderr, "Lexer.unittest %d\n", __LINE__);
+
+ ErrorSink errorSink = new ErrorSinkStderr;
- static void test(T)(string sequence, T expected, bool Ccompile = false)
+ void test(T)(string sequence, T expected, bool Ccompile = false)
{
auto p = cast(const(char)*)sequence.ptr;
dchar c2;
- Lexer lexer = new Lexer();
+ Lexer lexer = new Lexer(errorSink);
assert(expected == lexer.escapeSequence(Loc.initial, p, Ccompile, c2));
assert(p == sequence.ptr + sequence.length);
}
test(`"`, '"');
test(`<`, '<');
test(`>`, '>');
-
- diagnosticHandler = null;
}
unittest
{
- import dmd.console;
- string expected;
- bool gotError;
+ fprintf(stderr, "Lexer.unittest %d\n", __LINE__);
- nothrow bool expectDiagnosticHandler(const ref Loc loc, Color headerColor, const(char)* header,
- const(char)* format, va_list ap, const(char)* p1, const(char)* p2)
+ static class ErrorSinkTest : ErrorSinkNull
{
- assert(cast(Classification)headerColor == Classification.error);
+ nothrow:
+ extern (C++):
+ override:
+
+ import core.stdc.stdio;
+ import core.stdc.stdarg;
- gotError = true;
- char[100] buffer = void;
- auto actual = buffer[0 .. vsprintf(buffer.ptr, format, ap)];
- assert(expected == actual);
- return true;
+ string expected;
+ bool gotError;
+
+ void error(const ref Loc loc, const(char)* format, ...)
+ {
+ gotError = true;
+ char[100] buffer = void;
+ va_list ap;
+ va_start(ap, format);
+ auto actual = buffer[0 .. vsnprintf(buffer.ptr, buffer.length, format, ap)];
+ va_end(ap);
+ assert(expected == actual);
+ }
}
- diagnosticHandler = &expectDiagnosticHandler;
+ ErrorSinkTest errorSink = new ErrorSinkTest;
void test(string sequence, string expectedError, dchar expectedReturnValue, uint expectedScanLength, bool Ccompile = false)
{
- uint errors = global.errors;
- gotError = false;
- expected = expectedError;
+ errorSink.expected = expectedError;
+ errorSink.gotError = false;
auto p = cast(const(char)*)sequence.ptr;
- Lexer lexer = new Lexer();
+ Lexer lexer = new Lexer(errorSink);
dchar c2;
auto actualReturnValue = lexer.escapeSequence(Loc.initial, p, Ccompile, c2);
- assert(gotError);
+ assert(errorSink.gotError);
assert(expectedReturnValue == actualReturnValue);
auto actualScanLength = p - sequence.ptr;
assert(expectedScanLength == actualScanLength);
- global.errors = errors;
}
test("c", `undefined escape sequence \c`, 'c', 1);
test(""", `unterminated named entity "`, '?', 5);
test("400", `escape octal sequence \400 is larger than \377`, 0x100, 3);
-
- diagnosticHandler = null;
}
unittest
{
- //printf("lexer.unittest\n");
+ fprintf(stderr, "Lexer.unittest %d\n", __LINE__);
/* Not much here, just trying things out.
*/
string text = "int"; // We rely on the implicit null-terminator
- scope Lexer lex1 = new Lexer(null, text.ptr, 0, text.length, 0, 0);
+ ErrorSink errorSink = new ErrorSinkStderr;
+ scope Lexer lex1 = new Lexer(null, text.ptr, 0, text.length, false, false, errorSink);
TOK tok;
tok = lex1.nextToken();
//printf("tok == %s, %d, %d\n", Token::toChars(tok), tok, TOK.int32);
unittest
{
+ fprintf(stderr, "Lexer.unittest %d\n", __LINE__);
+
// We don't want to see Lexer error output during these tests.
- uint errors = global.startGagging();
- scope(exit) global.endGagging(errors);
+ ErrorSink errorSink = new ErrorSinkNull;
// Test malformed input: even malformed input should end in a TOK.endOfFile.
static immutable char[][] testcases =
foreach (testcase; testcases)
{
- scope Lexer lex2 = new Lexer(null, testcase.ptr, 0, testcase.length-1, 0, 0);
+ scope Lexer lex2 = new Lexer(null, testcase.ptr, 0, testcase.length-1, false, false, errorSink);
TOK tok = lex2.nextToken();
size_t iterations = 1;
while ((tok != TOK.endOfFile) && (iterations++ < testcase.length))
const char *toChars() const;
};
+
+extern void getLocalClasses(Module* mod, Array<ClassDeclaration* >& aclasses);
return sizeTy;
}();
- final extern (D) this(TY ty)
+ final extern (D) this(TY ty) scope
{
this.ty = ty;
}
}
if (auto fd = s.isFuncDeclaration())
{
- fd = resolveFuncCall(Loc.initial, null, fd, null, this, null, FuncResolveFlag.quiet);
+ fd = resolveFuncCall(Loc.initial, null, fd, null, this, ArgumentList(), FuncResolveFlag.quiet);
if (!fd || fd.errors || !fd.functionSemantic())
return Type.terror;
if (auto td = s.isTemplateDeclaration())
{
assert(td._scope);
- auto fd = resolveFuncCall(Loc.initial, null, td, null, this, null, FuncResolveFlag.quiet);
+ auto fd = resolveFuncCall(Loc.initial, null, td, null, this, ArgumentList(), FuncResolveFlag.quiet);
if (!fd || fd.errors || !fd.functionSemantic())
return Type.terror;
const namelen = 19 + size_t.sizeof * 3 + slice.length + 1;
auto name = namelen <= namebuf.length ? namebuf.ptr : cast(char*)Mem.check(malloc(namelen));
- const length = sprintf(name, "_D%lluTypeInfo_%.*s6__initZ",
+ const length = snprintf(name, namelen, "_D%lluTypeInfo_%.*s6__initZ",
cast(ulong)(9 + slice.length), cast(int)slice.length, slice.ptr);
//printf("%p %s, deco = %s, name = %s\n", this, toChars(), deco, name);
assert(0 < length && length < namelen); // don't overflow the buffer
const(char)* dstring;
uint flags;
- extern (D) this(TY ty)
+ extern (D) this(TY ty) scope
{
super(ty);
const(char)* d;
* Determine match level.
* Params:
* tthis = type of `this` pointer, null if not member function
- * args = array of function arguments
+ * argumentList = arguments to function call
* flag = 1: performing a partial ordering match
* pMessage = address to store error message, or null
* sc = context
* Returns:
* MATCHxxxx
*/
- extern (D) MATCH callMatch(Type tthis, Expression[] args, int flag = 0, const(char)** pMessage = null, Scope* sc = null)
+ extern (D) MATCH callMatch(Type tthis, ArgumentList argumentList, int flag = 0, const(char)** pMessage = null, Scope* sc = null)
{
//printf("TypeFunction::callMatch() %s\n", toChars());
MATCH match = MATCH.exact; // assume exact match
}
const nparams = parameterList.length;
- const nargs = args.length;
- if (nargs > nparams)
+ if (argumentList.length > nparams)
{
if (parameterList.varargs == VarArg.none)
{
}
// https://issues.dlang.org/show_bug.cgi?id=22997
- if (parameterList.varargs == VarArg.none && nparams > nargs && !parameterList[nargs].defaultArg)
+ if (parameterList.varargs == VarArg.none && nparams > argumentList.length && !parameterList.hasDefaultArgs)
{
OutBuffer buf;
- buf.printf("too few arguments, expected %d, got %d", cast(int)nparams, cast(int)nargs);
+ buf.printf("too few arguments, expected %d, got %d", cast(int)nparams, cast(int)argumentList.length);
if (pMessage)
*pMessage = buf.extractChars();
return MATCH.nomatch;
}
+ auto resolvedArgs = resolveNamedArgs(argumentList, pMessage);
+ Expression[] args;
+ if (!resolvedArgs)
+ {
+ if (!pMessage || *pMessage)
+ return MATCH.nomatch;
+
+ // if no message was provided, it was because of overflow which will be diagnosed below
+ match = MATCH.nomatch;
+ args = argumentList.arguments ? (*argumentList.arguments)[] : null;
+ }
+ else
+ {
+ args = (*resolvedArgs)[];
+ }
foreach (u, p; parameterList)
{
- if (u == nargs)
+ if (u >= args.length)
break;
Expression arg = args[u];
- assert(arg);
+ if (!arg)
+ continue; // default argument
+
Type tprm = p.type;
Type targ = arg.type;
assert(p);
// One or more arguments remain
- if (u < nargs)
+ if (u < args.length)
{
Expression arg = args[u];
- assert(arg);
+ if (!arg)
+ continue; // default argument
m = argumentMatchParameter(this, p, arg, wildmatch, flag, sc, pMessage);
}
else if (p.defaultArg)
/* prefer matching the element type rather than the array
* type when more arguments are present with T[]...
*/
- if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams && nargs > nparams)
+ if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams && args.length > nparams)
goto L1;
//printf("\tm = %d\n", m);
// Error message was already generated in `matchTypeSafeVarArgs`
return MATCH.nomatch;
}
- if (pMessage && u >= nargs)
+ if (pMessage && u >= args.length)
*pMessage = getMatchError("missing argument for parameter #%d: `%s`",
u + 1, parameterToChars(p, this, false));
// If an error happened previously, `pMessage` was already filled
match = m; // pick worst match
}
- if (pMessage && !parameterList.varargs && nargs > nparams)
+ if (pMessage && !parameterList.varargs && args.length > nparams)
{
// all parameters had a match, but there are surplus args
- *pMessage = getMatchError("expected %d argument(s), not %d", nparams, nargs);
+ *pMessage = getMatchError("expected %d argument(s), not %d", nparams, args.length);
return MATCH.nomatch;
}
//printf("match = %d\n", match);
return match;
}
+ /********************************
+ * Convert an `argumentList`, which may contain named arguments, into
+ * a list of arguments in the order of the parameter list.
+ *
+ * Params:
+ * argumentList = array of function arguments
+ * pMessage = address to store error message, or `null`
+ * Returns: re-ordered argument list, or `null` on error
+ */
+ extern(D) Expressions* resolveNamedArgs(ArgumentList argumentList, const(char)** pMessage)
+ {
+ Expression[] args = argumentList.arguments ? (*argumentList.arguments)[] : null;
+ Identifier[] names = argumentList.names ? (*argumentList.names)[] : null;
+ auto newArgs = new Expressions(parameterList.length);
+ newArgs.zero();
+ size_t ci = 0;
+ bool hasNamedArgs = false;
+ foreach (i, arg; args)
+ {
+ if (!arg)
+ {
+ ci++;
+ continue;
+ }
+ auto name = i < names.length ? names[i] : null;
+ if (name)
+ {
+ hasNamedArgs = true;
+ const pi = findParameterIndex(name);
+ if (pi == -1)
+ {
+ if (pMessage)
+ *pMessage = getMatchError("no parameter named `%s`", name.toChars());
+ return null;
+ }
+ ci = pi;
+ }
+ if (ci >= newArgs.length)
+ {
+ if (!parameterList.varargs)
+ {
+ // Without named args, let the caller diagnose argument overflow
+ if (hasNamedArgs && pMessage)
+ *pMessage = getMatchError("argument `%s` goes past end of parameter list", arg.toChars());
+ return null;
+ }
+ while (ci >= newArgs.length)
+ newArgs.push(null);
+ }
+
+ if ((*newArgs)[ci])
+ {
+ if (pMessage)
+ *pMessage = getMatchError("parameter `%s` assigned twice", parameterList[ci].toChars());
+ return null;
+ }
+ (*newArgs)[ci++] = arg;
+ }
+ foreach (i, arg; (*newArgs)[])
+ {
+ if (arg || parameterList[i].defaultArg)
+ continue;
+
+ if (parameterList.varargs != VarArg.none && i + 1 == newArgs.length)
+ continue;
+
+ if (pMessage)
+ *pMessage = getMatchError("missing argument for parameter #%d: `%s`",
+ i + 1, parameterToChars(parameterList[i], this, false));
+ return null;
+ }
+ // strip trailing nulls from default arguments
+ size_t e = newArgs.length;
+ while (e > 0 && (*newArgs)[e - 1] is null)
+ {
+ --e;
+ }
+ newArgs.setDim(e);
+ return newArgs;
+ }
+
/+
+ Checks whether this function type is convertible to ` to`
+ when used in a function pointer / delegate.
}
/// Returns: whether `this` function type has the same attributes (`@safe`,...) as `other`
- bool attributesEqual(const scope TypeFunction other) const pure nothrow @safe @nogc
- {
- return this.trust == other.trust &&
+ extern (D) bool attributesEqual(const scope TypeFunction other, bool trustSystemEqualsDefault = true) const pure nothrow @safe @nogc
+ {
+ // @@@DEPRECATED_2.112@@@
+ // See semantic2.d Semantic2Visitor.visit(FuncDeclaration):
+ // Two overloads that are identical except for one having an explicit `@system`
+ // attribute is currently in deprecation, and will become an error in 2.104 for
+ // `extern(C)`, and 2.112 for `extern(D)` code respectively. Once the deprecation
+ // period has passed, the trustSystemEqualsDefault=true behaviour should be made
+ // the default, then we can remove the `cannot overload extern(...) function`
+ // errors as they will become dead code as a result.
+ return (this.trust == other.trust ||
+ (trustSystemEqualsDefault && this.trust <= TRUST.system && other.trust <= TRUST.system)) &&
this.purity == other.purity &&
this.isnothrow == other.isnothrow &&
this.isnogc == other.isnogc &&
{
v.visit(this);
}
+
+ /**
+ * Look for the index of parameter `ident` in the parameter list
+ *
+ * Params:
+ * ident = identifier of parameter to search for
+ * Returns: index of parameter with name `ident` or -1 if not found
+ */
+ private extern(D) ptrdiff_t findParameterIndex(Identifier ident)
+ {
+ foreach (i, p; this.parameterList)
+ {
+ if (p.ident == ident)
+ return i;
+ }
+ return -1;
+ }
}
/***********************************************************
// Ensure no remaining parameters in `other`
return !diff && other[idx] is null;
}
+
+ /// Returns: `true` if any parameter has a default argument
+ extern(D) bool hasDefaultArgs()
+ {
+ foreach (oidx, oparam, eidx, eparam; this)
+ {
+ if (eparam.defaultArg)
+ return true;
+ }
+ return false;
+ }
+
+ // Returns: `true` if any parameter doesn't have a default argument
+ extern(D) bool hasArgsWithoutDefault()
+ {
+ foreach (oidx, oparam, eidx, eparam; this)
+ {
+ if (!eparam.defaultArg)
+ return true;
+ }
+ return false;
+ }
}
el.type = cast() ts;
Expressions args;
args.push(el);
- FuncDeclaration f = resolveFuncCall(Loc.initial, null, ctor, null, cast()ts, &args, FuncResolveFlag.quiet);
+ FuncDeclaration f = resolveFuncCall(Loc.initial, null, ctor, null, cast()ts, ArgumentList(&args), FuncResolveFlag.quiet);
if (!f || f.storage_class & STC.disable)
return false;
}
module dmd.nogc;
+import core.stdc.stdio;
+
import dmd.aggregate;
import dmd.apply;
import dmd.astenums;
import dmd.declaration;
import dmd.dscope;
+import dmd.errors;
import dmd.expression;
import dmd.func;
import dmd.globals;
alias visit = typeof(super).visit;
public:
FuncDeclaration f;
+ bool checkOnly; // don't print errors
bool err;
- extern (D) this(FuncDeclaration f)
+ extern (D) this(FuncDeclaration f) scope
{
this.f = f;
}
}
}
+ /**
+ * Register that expression `e` requires the GC
+ * Params:
+ * e = expression that uses GC
+ * format = error message when `e` is used in a `@nogc` function.
+ * Must contain format strings "`@nogc` %s `%s`" referring to the function.
+ * Returns: `true` if `err` was set, `false` if it's not in a `@nogc` and not checkonly (-betterC)
+ */
+ private bool setGC(Expression e, const(char)* format)
+ {
+ if (checkOnly)
+ {
+ err = true;
+ return true;
+ }
+ if (f.setGC())
+ {
+ e.error(format, f.kind(), f.toPrettyChars());
+ err = true;
+ return true;
+ }
+ return false;
+ }
+
override void visit(CallExp e)
{
import dmd.id : Id;
auto fd = stripHookTraceImpl(e.f);
if (fd.ident == Id._d_arraysetlengthT)
{
- if (f.setGC())
- {
- e.error("setting `length` in `@nogc` %s `%s` may cause a GC allocation",
- f.kind(), f.toPrettyChars());
- err = true;
+ if (setGC(e, "setting `length` in `@nogc` %s `%s` may cause a GC allocation"))
return;
- }
f.printGCUsage(e.loc, "setting `length` may cause a GC allocation");
}
else if (fd.ident == Id._d_arrayappendT || fd.ident == Id._d_arrayappendcTX)
{
- if (f.setGC())
- {
- e.error("cannot use operator `~=` in `@nogc` %s `%s`",
- f.kind(), f.toPrettyChars());
- err = true;
+ if (setGC(e, "cannot use operator `~=` in `@nogc` %s `%s`"))
return;
- }
f.printGCUsage(e.loc, "operator `~=` may cause a GC allocation");
}
}
{
if (e.type.ty != Tarray || !e.elements || !e.elements.length || e.onstack)
return;
- if (f.setGC())
- {
- e.error("array literal in `@nogc` %s `%s` may cause a GC allocation",
- f.kind(), f.toPrettyChars());
- err = true;
+ if (setGC(e, "array literal in `@nogc` %s `%s` may cause a GC allocation"))
return;
- }
f.printGCUsage(e.loc, "array literal may cause a GC allocation");
}
{
if (!e.keys.length)
return;
- if (f.setGC())
- {
- e.error("associative array literal in `@nogc` %s `%s` may cause a GC allocation",
- f.kind(), f.toPrettyChars());
- err = true;
+ if (setGC(e, "associative array literal in `@nogc` %s `%s` may cause a GC allocation"))
return;
- }
f.printGCUsage(e.loc, "associative array literal may cause a GC allocation");
}
return;
if (global.params.ehnogc && e.thrownew)
return; // separate allocator is called for this, not the GC
- if (f.setGC())
- {
- e.error("cannot use `new` in `@nogc` %s `%s`",
- f.kind(), f.toPrettyChars());
- err = true;
+
+ if (setGC(e, "cannot use `new` in `@nogc` %s `%s`"))
return;
- }
f.printGCUsage(e.loc, "`new` causes a GC allocation");
}
Type t1b = e.e1.type.toBasetype();
if (e.modifiable && t1b.ty == Taarray)
{
- if (f.setGC())
- {
- e.error("assigning an associative array element in `@nogc` %s `%s` may cause a GC allocation",
- f.kind(), f.toPrettyChars());
- err = true;
+ if (setGC(e, "assigning an associative array element in `@nogc` %s `%s` may cause a GC allocation"))
return;
- }
f.printGCUsage(e.loc, "assigning an associative array element may cause a GC allocation");
}
}
{
if (e.e1.op == EXP.arrayLength)
{
- if (f.setGC())
- {
- e.error("setting `length` in `@nogc` %s `%s` may cause a GC allocation",
- f.kind(), f.toPrettyChars());
- err = true;
+ if (setGC(e, "setting `length` in `@nogc` %s `%s` may cause a GC allocation"))
return;
- }
f.printGCUsage(e.loc, "setting `length` may cause a GC allocation");
}
}
* The other branch will be `_d_arrayappendcTX(e1, 1), e1[$-1]=e2` which will generate the warning about
* GC usage. See visit(CallExp).
*/
+ if (checkOnly)
+ {
+ err = true;
+ return;
+ }
if (f.setGC())
{
err = true;
override void visit(CatExp e)
{
- if (f.setGC())
- {
- e.error("cannot use operator `~` in `@nogc` %s `%s`",
- f.kind(), f.toPrettyChars());
- err = true;
+ if (setGC(e, "cannot use operator `~` in `@nogc` %s `%s`"))
return;
- }
f.printGCUsage(e.loc, "operator `~` may cause a GC allocation");
}
}
Expression checkGC(Scope* sc, Expression e)
{
+ if (sc.flags & SCOPE.ctfeBlock) // ignore GC in ctfe blocks
+ return e;
+
+ /* If betterC, allow GC to happen in non-CTFE code.
+ * Just don't generate code for it.
+ * Detect non-CTFE use of the GC in betterC code.
+ */
+ const betterC = global.params.betterC;
FuncDeclaration f = sc.func;
- if (e && e.op != EXP.error && f && sc.intypeof != 1 && !(sc.flags & SCOPE.ctfe) &&
+ if (e && e.op != EXP.error && f && sc.intypeof != 1 &&
+ (!(sc.flags & SCOPE.ctfe) || betterC) &&
(f.type.ty == Tfunction &&
(cast(TypeFunction)f.type).isnogc || f.nogcInprocess || global.params.vgc) &&
!(sc.flags & SCOPE.debug_))
{
scope NOGCVisitor gcv = new NOGCVisitor(f);
+ gcv.checkOnly = betterC;
walkPostorder(e, gcv);
if (gcv.err)
- return ErrorExp.get();
+ {
+ if (betterC)
+ {
+ /* Allow ctfe to use the gc code, but don't let it into the runtime
+ */
+ f.skipCodegen = true;
+ }
+ else
+ return ErrorExp.get();
+ }
}
return e;
}
PtrVarState[] input; /// variable states on entry to exp
PtrVarState[] output; /// variable states on exit to exp
- this(ObNode* tryBlock)
+ this(ObNode* tryBlock) scope
{
this.tryBlock = tryBlock;
}
extern (D) this(void delegate(ObNode*, VarDeclaration, Expression, bool) dgWriteVar,
void delegate(const ref Loc loc, ObNode* ob, VarDeclaration v, bool mutable) dgReadVar,
- ObNode* ob, ref ObState obstate)
+ ObNode* ob, ref ObState obstate) scope
{
this.dgWriteVar = dgWriteVar;
this.dgReadVar = dgReadVar;
extern (D) this(void delegate(const ref Loc loc, ObNode* ob, VarDeclaration v, bool mutable, PtrVarState[]) dgReadVar,
void delegate(ObNode*, PtrVarState[], VarDeclaration, Expression) dgWriteVar,
- PtrVarState[] cpvs, ObNode* ob, ref ObState obstate)
+ PtrVarState[] cpvs, ObNode* ob, ref ObState obstate) scope
{
this.dgReadVar = dgReadVar;
this.dgWriteVar = dgWriteVar;
{
auto v = obstate.vars[i];
if (v.type.hasPointers())
- v.error(v.loc, "is left dangling at return");
+ v.error(v.loc, "is not disposed of before return");
}
}
}
MatchAccumulator m;
if (s)
{
- functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, &args2);
+ functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, ArgumentList(&args2));
if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
{
return ErrorExp.get();
FuncDeclaration lastf = m.lastf;
if (s_r)
{
- functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, &args1);
+ functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, ArgumentList(&args1));
if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
{
return ErrorExp.get();
MatchAccumulator m;
if (s_r)
{
- functionResolve(m, s_r, e.loc, sc, tiargs, e.e1.type, &args2);
+ functionResolve(m, s_r, e.loc, sc, tiargs, e.e1.type, ArgumentList(&args2));
if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
{
return ErrorExp.get();
FuncDeclaration lastf = m.lastf;
if (s)
{
- functionResolve(m, s, e.loc, sc, tiargs, e.e2.type, &args1);
+ functionResolve(m, s, e.loc, sc, tiargs, e.e2.type, ArgumentList(&args1));
if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
{
return ErrorExp.get();
args2[0] = e.e2;
expandTuples(&args2);
MatchAccumulator m;
- functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, &args2);
+ functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, ArgumentList(&args2));
if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
{
return ErrorExp.get();
}
if (s)
{
- functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, &args2);
+ functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, ArgumentList(&args2));
if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
return ErrorExp.get();
}
int count = m.count;
if (s_r)
{
- functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, &args1);
+ functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, ArgumentList(&args1));
if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
return ErrorExp.get();
}
// Found another overload with different attributes?
// e.g. @system vs. @safe opApply
- bool ambig = tf.attributesEqual(bestTf);
+ // @@@DEPRECATED_2.112@@@
+ // See semantic2.d Semantic2Visitor.visit(FuncDeclaration):
+ // Remove `false` after deprecation period is over.
+ bool ambig = tf.attributesEqual(bestTf, false);
// opApplies with identical attributes could still accept
// different function bodies as delegate
import core.stdc.stdio;
import core.stdc.string;
import dmd.astenums;
+import dmd.errorsink;
import dmd.globals;
import dmd.id;
import dmd.identifier;
* Input:
* loc location in source file of mixin
*/
- extern (D) this(const ref Loc loc, AST.Module _module, const(char)[] input, bool doDocComment)
+ extern (D) this(const ref Loc loc, AST.Module _module, const(char)[] input, bool doDocComment,
+ ErrorSink errorSink) scope
{
super(_module ? _module.srcfile.toChars() : null, input.ptr, 0, input.length, doDocComment, false,
+ errorSink,
global.vendor, global.versionNumber());
//printf("Parser::Parser()\n");
/* Create a pseudo-filename for the mixin string, as it may not even exist
* in the source file.
*/
- char* filename = cast(char*)mem.xmalloc(strlen(loc.filename) + 7 + (loc.linnum).sizeof * 3 + 1);
- sprintf(filename, "%s-mixin-%d", loc.filename, cast(int)loc.linnum);
+ auto len = strlen(loc.filename) + 7 + (loc.linnum).sizeof * 3 + 1;
+ char* filename = cast(char*)mem.xmalloc(len);
+ snprintf(filename, len, "%s-mixin-%d", loc.filename, cast(int)loc.linnum);
scanloc.filename = filename;
}
//nextToken(); // start up the scanner
}
- extern (D) this(AST.Module _module, const(char)[] input, bool doDocComment)
+ extern (D) this(AST.Module _module, const(char)[] input, bool doDocComment, ErrorSink errorSink) scope
{
super(_module ? _module.srcfile.toChars() : null, input.ptr, 0, input.length, doDocComment, false,
+ errorSink,
global.vendor, global.versionNumber());
//printf("Parser::Parser()\n");
if (token.value == TOK.rightCurly)
{
- error(token.loc, "unmatched closing brace");
+ error("unmatched closing brace");
return errorReturn();
}
if (token.value != TOK.endOfFile)
{
- error(token.loc, "unrecognized declaration");
+ error("unrecognized declaration");
return errorReturn();
}
return decldefs;
check(TOK.rightParenthesis);
if (msg)
{
- error("conflicting storage class `deprecated(%s)` and `deprecated(%s)`", msg.toChars(), e.toChars());
+ error(token.loc, "conflicting storage class `deprecated(%s)` and `deprecated(%s)`", msg.toChars(), e.toChars());
}
msg = e;
return true;
{
if (pAttrs.link != res.link)
{
- error("conflicting linkage `extern (%s)` and `extern (%s)`", AST.linkageToChars(pAttrs.link), AST.linkageToChars(res.link));
+ error(token.loc, "conflicting linkage `extern (%s)` and `extern (%s)`", AST.linkageToChars(pAttrs.link), AST.linkageToChars(res.link));
}
else if (res.idents || res.identExps || res.cppmangle != CPPMANGLE.def)
{
if (pAttrs.visibility.kind != AST.Visibility.Kind.undefined)
{
if (pAttrs.visibility.kind != prot)
- error("conflicting visibility attribute `%s` and `%s`", AST.visibilityToChars(pAttrs.visibility.kind), AST.visibilityToChars(prot));
+ error(token.loc, "conflicting visibility attribute `%s` and `%s`", AST.visibilityToChars(pAttrs.visibility.kind), AST.visibilityToChars(prot));
else
error("redundant visibility attribute `%s`", AST.visibilityToChars(prot));
}
{
// Windows `printf` does not support `%1$s`
const(char*) stc_str = (orig & STC.scope_) ? "scope".ptr : "ref".ptr;
- error("attribute `in` cannot be added after `%s`: remove `%s`",
+ error(token.loc, "attribute `in` cannot be added after `%s`: remove `%s`",
stc_str, stc_str);
}
else
if (token.value == TOK.leftParenthesis)
{
const loc = token.loc;
- exp = new AST.CallExp(loc, exp, parseArguments());
+ AST.Expressions* args = new AST.Expressions();
+ AST.Identifiers* names = new AST.Identifiers();
+ parseNamedArguments(args, names);
+ exp = new AST.CallExp(loc, exp, args, names);
}
if (udas is null)
nextToken();
if (token.value != TOK.identifier)
{
- error("`%s` expected as dot-separated identifiers, got `%s`", entity, token.toChars());
+ error(token.loc, "`%s` expected as dot-separated identifiers, got `%s`", entity, token.toChars());
return qualified;
}
tf = tf.addSTC(stc);
auto f = new AST.CtorDeclaration(loc, Loc.initial, stc, tf);
- AST.Dsymbol s = parseContracts(f);
+ AST.Dsymbol s = parseContracts(f, !!tpl);
if (udas)
{
auto a = new AST.Dsymbols();
storageClass = appendStorageClass(storageClass, stc);
continue;
- version (none)
- {
- case TOK.static_:
- stc = STC.static_;
- goto L2;
-
- case TOK.auto_:
- storageClass = STC.auto_;
- goto L4;
-
- case TOK.alias_:
- storageClass = STC.alias_;
- goto L4;
- L4:
- nextToken();
- ai = null;
- if (token.value == TOK.identifier)
- {
- ai = token.ident;
- nextToken();
- }
-
- at = null; // no type
- ae = null; // no default argument
- if (token.value == TOK.assign) // = defaultArg
- {
- nextToken();
- ae = parseDefaultInitExp();
- hasdefault = 1;
- }
- else
- {
- if (hasdefault)
- error("default argument expected for `alias %s`", ai ? ai.toChars() : "");
- }
- goto L3;
- }
default:
{
stc = storageClass & (STC.IOR | STC.lazy_);
if (token.value != TOK.rightCurly)
{
/* { */
- error("`}` expected following members in `%s` declaration at %s",
+ error(token.loc, "`}` expected following members in `%s` declaration at %s",
Token.toChars(tok), loc.toChars());
}
nextToken();
}
else
{
- error("{ } expected following `%s` declaration", Token.toChars(tok));
+ error(token.loc, "{ } expected following `%s` declaration", Token.toChars(tok));
}
AST.AggregateDeclaration a;
loc = token.loc;
nextToken();
if (token.value != TOK.leftParenthesis)
- error("found `%s` when expecting `%s` following `mixin`", token.toChars(), Token.toChars(TOK.leftParenthesis));
+ error(token.loc, "found `%s` when expecting `%s` following `mixin`", token.toChars(), Token.toChars(TOK.leftParenthesis));
auto exps = parseArguments();
t = new AST.TypeMixin(loc, exps);
break;
default:
error("basic type expected, not `%s`", token.toChars());
if (token.value == TOK.else_)
- errorSupplemental(token.loc, "There's no `static else`, use `else` instead.");
+ eSink.errorSupplemental(token.loc, "There's no `static else`, use `else` instead.");
t = AST.Type.terror;
break;
}
if (!tfirst)
tfirst = t;
else if (t != tfirst)
- error("multiple declarations must have the same type, not `%s` and `%s`", tfirst.toChars(), t.toChars());
+ error(token.loc, "multiple declarations must have the same type, not `%s` and `%s`", tfirst.toChars(), t.toChars());
if (token.value == TOK.colon && !ident && t.ty != Tfunction)
{
if (_init)
{
if (isThis)
- error("cannot use syntax `alias this = %s`, use `alias %s this` instead", _init.toChars(), _init.toChars());
+ error(token.loc, "cannot use syntax `alias this = %s`, use `alias %s this` instead", _init.toChars(), _init.toChars());
else
error("alias cannot have initializer");
}
continue;
default:
- error("semicolon expected to close `alias` declaration");
+ error("semicolon expected to close `alias` declaration, not `%s`", token.toChars());
break;
}
}
pAttrs.storageClass = STC.undefined_;
if (tpl)
constraint = parseConstraint();
- AST.Dsymbol s = parseContracts(f);
+ AST.Dsymbol s = parseContracts(f, !!tpl);
auto tplIdent = s.ident;
if (link != linkage)
default:
if (loc.linnum != token.loc.linnum)
{
- error("semicolon needed to end declaration of `%s`, instead of `%s`", s.toChars(), token.toChars());
- errorSupplemental(loc, "`%s` declared here", s.toChars());
+ error(token.loc, "semicolon needed to end declaration of `%s`, instead of `%s`", s.toChars(), token.toChars());
+ eSink.errorSupplemental(loc, "`%s` declared here", s.toChars());
}
else
{
- error("semicolon needed to end declaration of `%s` instead of `%s`", s.toChars(), token.toChars());
+ error(token.loc, "semicolon needed to end declaration of `%s` instead of `%s`", s.toChars(), token.toChars());
}
break;
}
// A common mistake is to use a reserved keyword as an identifier, e.g. `in` or `out`
if (token.isKeyword)
{
- errorSupplemental(token.loc, "`%s` is a keyword, perhaps append `_` to make it an identifier", token.toChars());
+ eSink.errorSupplemental(token.loc, "`%s` is a keyword, perhaps append `_` to make it an identifier", token.toChars());
nextToken();
}
}
AST.stcToBuffer(&buf, remStc);
// @@@DEPRECATED_2.103@@@
// Deprecated in 2020-07, can be made an error in 2.103
- deprecation("storage class `%s` has no effect in type aliases", buf.peekChars());
+ eSink.deprecation(token.loc, "storage class `%s` has no effect in type aliases", buf.peekChars());
}
}
continue;
default:
- error("semicolon expected to close `alias` declaration");
+ error("semicolon expected to close `alias` declaration, not `%s`", token.toChars());
break;
}
break;
if (token.value == TOK.leftCurly)
{
deprecation("using `(args) => { ... }` to create a delegate that returns a delegate is error-prone.");
- deprecationSupplemental(token.loc, "Use `(args) { ... }` for a multi-statement function literal or use `(args) => () { }` if you intended for the lambda to return a delegate.");
+ deprecationSupplemental("Use `(args) { ... }` for a multi-statement function literal or use `(args) => () { }` if you intended for the lambda to return a delegate.");
}
const returnloc = token.loc;
AST.Expression ae = parseAssignExp();
/*****************************************
* Parse contracts following function declaration.
*/
- private AST.FuncDeclaration parseContracts(AST.FuncDeclaration f)
+ private AST.FuncDeclaration parseContracts(AST.FuncDeclaration f, bool isTemplateFunction = false)
{
LINK linksave = linkage;
else if (t == TOK.at)
error("attributes cannot be placed after a template constraint");
else if (t == TOK.if_)
- error("cannot use function constraints for non-template functions. Use `static if` instead");
+ {
+ if (isTemplateFunction)
+ error("template constraint must follow parameter lists and attributes");
+ else
+ error("cannot use function constraints for non-template functions. Use `static if` instead");
+ }
else
error("semicolon expected following function declaration");
}
{
if (token.value != TOK.else_ && token.value != TOK.catch_ && token.value != TOK.finally_ && lookingForElse.linnum != 0)
{
- warning(elseloc, "else is dangling, add { } after condition at %s", lookingForElse.toChars());
+ eSink.warning(elseloc, "else is dangling, add { } after condition at %s", lookingForElse.toChars());
}
}
nextToken();
}
if (format)
- error(format.ptr, start.ptr, param ? "declaration".ptr : condition.toChars());
+ error(token.loc, format.ptr, start.ptr, param ? "declaration".ptr : condition.toChars());
}
/*****************************************
stc = STC.out_;
goto Lagain;
+ case TOK.auto_:
+ error("cannot declare `auto` loop variable, omit `auto` to still get type inference");
+ stc = STC.auto_;
+ goto Lagain;
+
case TOK.enum_:
stc = STC.manifest;
goto Lagain;
nextToken();
if (lastai && parameters.length >= 2)
{
- errorSupplemental(loc, "perhaps the `;` goes before `%s`", lastai.toChars());
+ eSink.errorSupplemental(loc, "perhaps the `;` goes before `%s`", lastai.toChars());
}
return null;
}
*/
if (token.value == TOK.identifier && exp.op == EXP.identifier)
{
- error("found `%s` when expecting `;` or `=`, did you mean `%s %s = %s`?", peek(&token).toChars(), exp.toChars(), token.toChars(), peek(peek(&token)).toChars());
+ error(token.loc, "found `%s` when expecting `;` or `=`, did you mean `%s %s = %s`?", peek(&token).toChars(), exp.toChars(), token.toChars(), peek(peek(&token)).toChars());
nextToken();
}
else
if (token.value != TOK.leftParenthesis)
{
deprecation("`catch` statement without an exception specification is deprecated");
- deprecationSupplemental(token.loc, "use `catch(Throwable)` for old behavior");
+ deprecationSupplemental("use `catch(Throwable)` for old behavior");
t = null;
id = null;
}
void check(TOK value, const(char)* string)
{
if (token.value != value)
- error("found `%s` when expecting `%s` following %s", token.toChars(), Token.toChars(value), string);
+ error(token.loc, "found `%s` when expecting `%s` following %s", token.toChars(), Token.toChars(value), string);
nextToken();
}
{
// This code parallels parseDeclarator()
Token* t = *pt;
- int parens;
+ bool parens;
//printf("Parser::isDeclarator() %s\n", t.toChars());
if (t.value == TOK.assign)
}
goto L1;
- version (none)
- {
- case TOK.static_:
- continue;
- case TOK.auto_:
- case TOK.alias_:
- t = peek(t);
- if (t.value == TOK.identifier)
- t = peek(t);
- if (t.value == TOK.assign)
- {
- t = peek(t);
- if (!isExpression(&t))
- return false;
- }
- goto L3;
- }
-
default:
{
if (!isBasicType(&t))
if (token.postfix)
{
if (token.postfix != postfix)
- error("mismatched string literal postfixes `'%c'` and `'%c'`", postfix, token.postfix);
+ error(token.loc, "mismatched string literal postfixes `'%c'` and `'%c'`", postfix, token.postfix);
postfix = token.postfix;
}
error("implicit string concatenation is error-prone and disallowed in D");
- errorSupplemental(token.loc, "Use the explicit syntax instead " ~
+ eSink.errorSupplemental(token.loc, "Use the explicit syntax instead " ~
"(concatenating literals is `@nogc`): %s ~ %s",
prev.toChars(), token.toChars());
check(TOK.dot);
if (token.value != TOK.identifier)
{
- error("found `%s` when expecting identifier following `%s`.", token.toChars(), t.toChars());
+ error(token.loc, "found `%s` when expecting identifier following `%s`.", token.toChars(), t.toChars());
goto Lerr;
}
e = new AST.DotIdExp(loc, new AST.TypeExp(loc, t), token.ident);
// https://dlang.org/spec/expression.html#mixin_expressions
nextToken();
if (token.value != TOK.leftParenthesis)
- error("found `%s` when expecting `%s` following `mixin`", token.toChars(), Token.toChars(TOK.leftParenthesis));
+ error(token.loc, "found `%s` when expecting `%s` following `mixin`", token.toChars(), Token.toChars(TOK.leftParenthesis));
auto exps = parseArguments();
e = new AST.MixinExp(loc, exps);
break;
// ( expression )
nextToken();
e = parseExpression();
- e.parens = 1;
+ e.parens = true;
check(loc, TOK.rightParenthesis);
break;
}
case TOK.wcharLiteral:
case TOK.dcharLiteral:
case TOK.string_:
- version (none)
- {
- case TOK.tilde:
- case TOK.and:
- case TOK.mul:
- case TOK.min:
- case TOK.add:
- }
case TOK.function_:
case TOK.delegate_:
case TOK.typeof_:
break;
case TOK.leftParenthesis:
- e = new AST.CallExp(loc, e, parseArguments());
+ AST.Expressions* args = new AST.Expressions();
+ AST.Identifiers* names = new AST.Identifiers();
+ parseNamedArguments(args, names);
+ e = new AST.CallExp(loc, e, args, names);
continue;
case TOK.leftBracket:
private AST.Expressions* parseArguments()
{
// function call
- AST.Expressions* arguments;
+ AST.Expressions* arguments = new AST.Expressions();
+ parseNamedArguments(arguments, null);
+ return arguments;
+ }
+
+ /*************************
+ * Collect argument list.
+ * Assume current token is ',', '$(LPAREN)' or '['.
+ */
+ private void parseNamedArguments(AST.Expressions* arguments, AST.Identifiers* names)
+ {
+ assert(arguments);
- arguments = new AST.Expressions();
const endtok = token.value == TOK.leftBracket ? TOK.rightBracket : TOK.rightParenthesis;
nextToken();
while (token.value != endtok && token.value != TOK.endOfFile)
{
+ if (peekNext() == TOK.colon)
+ {
+ // Named argument `name: exp`
+ auto loc = token.loc;
+ auto ident = token.ident;
+ check(TOK.identifier);
+ check(TOK.colon);
+ if (names)
+ names.push(ident);
+ else
+ error(loc, "named arguments not allowed here");
+ }
+ else
+ {
+ if (names)
+ names.push(null);
+ }
+
auto arg = parseAssignExp();
arguments.push(arg);
+
if (token.value != TOK.comma)
break;
nextToken(); //comma
}
-
check(endtok);
-
- return arguments;
}
/*******************************************
nextToken();
AST.Expressions* arguments = null;
+ AST.Identifiers* names = null;
// An anonymous nested class starts with "class"
if (token.value == TOK.class_)
{
nextToken();
if (token.value == TOK.leftParenthesis)
- arguments = parseArguments();
+ {
+ arguments = new AST.Expressions();
+ names = new AST.Identifiers();
+ parseNamedArguments(arguments, names);
+ }
AST.BaseClasses* baseclasses = null;
if (token.value != TOK.leftCurly)
}
else if (token.value == TOK.leftParenthesis && t.ty != Tsarray)
{
- arguments = parseArguments();
+ arguments = new AST.Expressions();
+ names = new AST.Identifiers();
+ parseNamedArguments(arguments, names);
}
- auto e = new AST.NewExp(loc, thisexp, t, arguments);
+ auto e = new AST.NewExp(loc, thisexp, t, arguments, names);
return e;
}
import core.stdc.stdio;
import dmd.expression;
+import dmd.ctfeexpr;
import dmd.tokens;
import dmd.visitor;
import dmd.hdrgen;
int indent;
- extern (D) this(int indent)
+ extern (D) this(int indent) scope
{
this.indent = indent;
}
printf(".init: %s\n", e.initializer ? e.initializer.toChars() : "");
}
+ override void visit(ClassReferenceExp e)
+ {
+ visit(cast(Expression)e);
+ printIndent(indent + 2);
+ printf(".value: %s\n", e.value ? e.value.toChars() : "");
+ printAST(e.value, indent + 2);
+ }
+
static void printIndent(int indent)
{
foreach (i; 0 .. indent)
size_t bIndex;
aaA* current;
- this(AA* aa) pure nothrow @nogc
+ this(AA* aa) pure nothrow @nogc scope
{
if (aa)
{
* Params:
* dim = initial length of array
*/
- this(size_t dim) pure nothrow
+ this(size_t dim) pure nothrow scope
{
reserve(dim);
this.length = dim;
{
foreach (u; 0 .. a.length)
{
- buf[u] = toStringFunc(a.data[u]);
+ static if (is(typeof(a.data[u] is null)))
+ {
+ if (a.data[u] is null)
+ buf[u] = "null";
+ else
+ buf[u] = toStringFunc(a.data[u]);
+ }
+ else
+ {
+ buf[u] = toStringFunc(a.data[u]);
+ }
+
len += buf[u].length + seplen;
}
}
assert(str == `["hello","world"]`);
// Test presence of null terminator.
assert(str.ptr[str.length] == '\0');
+
+ // Test printing an array of classes, which can be null
+ static class C
+ {
+ override string toString() const
+ {
+ return "x";
+ }
+ }
+ auto nullarray = Array!C(2);
+ nullarray[0] = new C();
+ nullarray[1] = null;
+ assert(nullarray.toString() == `[x,null]`);
}
unittest
static real_t parse(const(char)* literal, out bool isOutOfRange);
@system
- static int sprint(char* str, char fmt, real_t x);
+ static int sprint(char* str, size_t size, char fmt, real_t x);
// Constant real values 0, 1, -1 and 0.5.
__gshared real_t zero;
#pragma once
+#include "dcompat.h"
#include "longdouble.h"
// Type used by the front-end for compile-time reals
static bool isInfinity(real_t r);
static real_t parse(const char *literal, bool& isOutOfRange);
- static int sprint(char *str, char fmt, real_t x);
+ static int sprint(char *str, d_size_t size, char fmt, real_t x);
static size_t hash(real_t a);
this.str = str.xarraydup;
}
+ ///
+ extern (C++) static FileName create(const(char)* name) pure
+ {
+ return FileName(name.toDString);
+ }
+
/// Compare two name according to the platform's rules (case sensitive or not)
extern (C++) static bool equals(const(char)* name1, const(char)* name2) pure @nogc
{
private:
DString str;
public:
+ static FileName create(const char *name);
static bool equals(const char *name1, const char *name2);
static bool absolute(const char *name);
static const char *toAbsolute(const char *name, const char *base = NULL);
extern (C++) class RootObject
{
- this() nothrow pure @nogc @safe
+ this() nothrow pure @nogc @safe scope
{
}
public:
StoppableVisitor v;
- extern (D) this(StoppableVisitor v)
+ extern (D) this(StoppableVisitor v) scope
{
this.v = v;
}
{
alias visit = Visitor.visit;
Scope* sc;
- this(Scope* sc)
+ this(Scope* sc) scope
{
this.sc = sc;
}
sc.varDecl = vd;
scope(exit) sc.varDecl = null;
- if (vd.aliassym) // if it's a tuple
+ if (vd.aliasTuple) // if it's a tuple
{
- vd.aliassym.accept(this);
+ vd.aliasTuple.accept(this);
vd.semanticRun = PASS.semantic2done;
return;
}
if (tf1.mod != tf2.mod || ((f1.storage_class ^ f2.storage_class) & STC.static_))
return 0;
- const sameAttr = tf1.attributesEqual(tf2);
+ // @@@DEPRECATED_2.112@@@
+ // This test doesn't catch identical functions that differ only
+ // in explicit/implicit `@system` - a deprecation has now been
+ // added below, remove `false` after deprecation period is over.
+ const sameAttr = tf1.attributesEqual(tf2, false);
const sameParams = tf1.parameterList == tf2.parameterList;
// Allow the hack to declare overloads with different parameters/STC's
// Different attributes don't conflict in extern(D)
if (!sameAttr && linkage1 == LINK.d)
+ {
+ // @@@DEPRECATED_2.112@@@
+ // Same as 2.104 deprecation, but also catching explicit/implicit `@system`
+ // At the end of deprecation period, fix Type.attributesEqual and remove
+ // this condition, as well as the error for extern(C) functions above.
+ if (sameAttr != tf1.attributesEqual(tf2))
+ {
+ f2.deprecation("cannot overload `extern(%s)` function at %s",
+ linkageToChars(f1._linkage),
+ f1.loc.toChars());
+ }
return 0;
+ }
error(f2.loc, "%s `%s%s` conflicts with previous declaration at %s",
f2.kind(),
alias visit = Visitor.visit;
Scope* sc;
- this(Scope* sc)
+ this(Scope* sc) scope
{
this.sc = sc;
}
sc2.aligndecl = null;
if (funcdecl.ident != Id.require && funcdecl.ident != Id.ensure)
sc2.flags = sc.flags & ~SCOPE.contract;
- sc2.flags &= ~SCOPE.compile;
sc2.tf = null;
sc2.os = null;
sc2.inLoop = false;
// Insert implicit super() at start of fbody
Type tthis = ad2.type.addMod(funcdecl.vthis.type.mod);
- FuncDeclaration fd = resolveFuncCall(Loc.initial, sc2, cd.baseClass.ctor, null, tthis, null, FuncResolveFlag.quiet);
+ FuncDeclaration fd = resolveFuncCall(Loc.initial, sc2, cd.baseClass.ctor, null, tthis, ArgumentList(), FuncResolveFlag.quiet);
if (!fd)
{
funcdecl.error("no match for implicit `super()` call in constructor");
// Scope of analysis
Scope* sc;
- this(FuncDeclaration fd,Scope* s)
+ this(FuncDeclaration fd,Scope* s) scope
{
funcdecl = fd;
sc = s;
{
alias visit = typeof(super).visit;
public:
- extern (D) this()
+ extern (D) this() scope
{
}
{
alias visit = typeof(super).visit;
public:
- extern (D) this()
+ extern (D) this() scope
{
}
{
v.visit(this);
}
+
+ /******
+ * Returns: true if `if (__ctfe)`
+ */
+ bool isIfCtfeBlock()
+ {
+ if (auto cv = condition.isVarExp())
+ return cv.var.ident == Id.ctfe;
+ return false;
+ }
}
/***********************************************************
TryFinallyStatement tf;
ScopeGuardStatement os;
VarDeclaration lastVar;
+ bool inCtfeBlock; /// set if goto is inside an `if (__ctfe)` block
extern (D) this(const ref Loc loc, Identifier ident)
{
return true;
}
+ if (label.statement.inCtfeBlock && !inCtfeBlock)
+ {
+ error("cannot `goto` into `if (__ctfe)` block");
+ return true;
+ }
+
Statement stbnext;
for (auto stb = tryBody; stb != label.statement.tryBody; stb = stbnext)
{
Statement gotoTarget; // interpret
void* extra; // used by Statement_toIR()
bool breaks; // someone did a 'break ident'
+ bool inCtfeBlock; // inside a block dominated by `if (__ctfe)`
extern (D) this(const ref Loc loc, Identifier ident, Statement statement)
{
IfStatement *syntaxCopy() override;
void accept(Visitor *v) override { v->visit(this); }
+ bool isIfCtfeBlock();
};
class ConditionalStatement final : public Statement
TryFinallyStatement *tf;
ScopeGuardStatement *os;
VarDeclaration *lastVar;
-
+ bool inCtfeBlock;
GotoStatement *syntaxCopy() override;
void accept(Visitor *v) override { v->visit(this); }
Statement *gotoTarget; // interpret
void* extra; // used by Statement_toIR()
bool breaks; // someone did a 'break ident'
-
+ bool inCtfeBlock;
LabelStatement *syntaxCopy() override;
void accept(Visitor *v) override { v->visit(this); }
import dmd.dsymbolsem;
import dmd.dtemplate;
import dmd.errors;
+import dmd.errorsink;
import dmd.escape;
import dmd.expression;
import dmd.expressionsem;
Statement result;
Scope* sc;
- this(Scope* sc)
+ this(Scope* sc) scope
{
this.sc = sc;
}
else if (auto td = sfront.isTemplateDeclaration())
{
Expressions a;
- if (auto f = resolveFuncCall(loc, sc, td, null, tab, &a, FuncResolveFlag.quiet))
+ if (auto f = resolveFuncCall(loc, sc, td, null, tab, ArgumentList(&a), FuncResolveFlag.quiet))
tfront = f.type;
}
else if (auto d = sfront.toAlias().isDeclaration())
assert(0);
}
const(char)* r = (fs.op == TOK.foreach_reverse_) ? "R" : "";
- int j = sprintf(fdname.ptr, "_aApply%s%.*s%llu", r, 2, fntab[flag].ptr, cast(ulong)dim);
+ int j = snprintf(fdname.ptr, BUFFER_LEN, "_aApply%s%.*s%llu", r, 2, fntab[flag].ptr, cast(ulong)dim);
assert(j < BUFFER_LEN);
FuncDeclaration fdapply;
// Save 'root' of two branches (then and else) at the point where it forks
CtorFlow ctorflow_root = scd.ctorflow.clone();
- ifs.ifbody = ifs.ifbody.semanticNoScope(scd);
+ /* Detect `if (__ctfe)`
+ */
+ if (ifs.isIfCtfeBlock())
+ {
+ Scope* scd2 = scd.push();
+ scd2.flags |= SCOPE.ctfeBlock;
+ ifs.ifbody = ifs.ifbody.semanticNoScope(scd2);
+ scd2.pop();
+ }
+ else
+ ifs.ifbody = ifs.ifbody.semanticNoScope(scd);
scd.pop();
CtorFlow ctorflow_then = sc.ctorflow; // move flow results
if (ed && ss.cases.length < ed.members.length)
{
int missingMembers = 0;
- const maxShown = !global.params.verbose ? 6 : int.max;
+ const maxShown = !global.params.verbose ?
+ (global.params.errorSupplementLimit ? global.params.errorSupplementLimit : int.max)
+ : int.max;
Lmembers:
foreach (es; *ed.members)
{
}
if (!sc.sw.sdefault &&
- (!ss.isFinal || needswitcherror || global.params.useAssert == CHECKENABLE.on))
+ (!ss.isFinal || needswitcherror || global.params.useAssert == CHECKENABLE.on || sc.func.isSafe))
{
ss.hasNoDefault = 1;
cs.exp = se;
else if (!cs.exp.isIntegerExp() && !cs.exp.isErrorExp())
{
- cs.error("`case` must be a `string` or an integral constant, not `%s`", cs.exp.toChars());
+ cs.error("`case` expression must be a compile-time `string` or an integral constant, not `%s`", cs.exp.toChars());
errors = true;
}
gs.tf = sc.tf;
gs.os = sc.os;
gs.lastVar = sc.lastVar;
+ gs.inCtfeBlock = (sc.flags & SCOPE.ctfeBlock) != 0;
if (!gs.label.statement && sc.fes)
{
ls.tf = sc.tf;
ls.os = sc.os;
ls.lastVar = sc.lastVar;
+ ls.inCtfeBlock = (sc.flags & SCOPE.ctfeBlock) != 0;
LabelDsymbol ls2 = fd.searchLabel(ls.ident, ls.loc);
if (ls2.statement)
const len = buf.length;
buf.writeByte(0);
const str = buf.extractSlice()[0 .. len];
- scope p = new Parser!ASTCodegen(cs.loc, sc._module, str, false);
+ scope p = new Parser!ASTCodegen(cs.loc, sc._module, str, false, global.errorSink);
p.nextToken();
auto a = new Statements();
Objects *dedargs;
};
+struct ArgumentList final
+{
+ Expressions* arguments;
+ Identifiers* names;
+ ArgumentList() :
+ arguments(),
+ names()
+ {
+ }
+ ArgumentList(Expressions* arguments, Identifiers* names = nullptr) :
+ arguments(arguments),
+ names(names)
+ {}
+};
+
class TemplateDeclaration final : public ScopeDsymbol
{
public:
Visibility visible() override;
- MATCH leastAsSpecialized(Scope *sc, TemplateDeclaration *td2, Expressions *fargs);
+ MATCH leastAsSpecialized(Scope* sc, TemplateDeclaration* td2, ArgumentList argumentList);
RootObject *declareParameter(Scope *sc, TemplateParameter *tp, RootObject *o);
TemplateDeclaration *isTemplateDeclaration() override { return this; }
TemplateParameters* parameters;
bool result;
- this(Scope* sc, TemplateParameters* parameters)
+ this(Scope* sc, TemplateParameters* parameters) scope
{
this.sc = sc;
this.parameters = parameters;
_Thread_local,
// C only extended keywords
+ _assert,
_import,
__cdecl,
__declspec,
__stdcall,
__pragma,
+ __int128,
__attribute__,
}
TOK._Thread_local,
// C only extended keywords
+ TOK._assert,
TOK._import,
TOK.__cdecl,
TOK.__declspec,
TOK.__stdcall,
TOK.__pragma,
+ TOK.__int128,
TOK.__attribute__,
];
restrict, return_, int16, signed, sizeof_, static_, struct_, switch_, typedef_,
union_, unsigned, void_, volatile, while_, asm_, typeof_,
_Alignas, _Alignof, _Atomic, _Bool, _Complex, _Generic, _Imaginary, _Noreturn,
- _Static_assert, _Thread_local, _import, __cdecl, __declspec, __stdcall, __pragma, __attribute__ ];
+ _Static_assert, _Thread_local,
+ _import, __cdecl, __declspec, __stdcall, __pragma, __int128, __attribute__,
+ _assert ];
foreach (kw; Ckwds)
tab[kw] = cast(TOK) kw;
TOK._Thread_local : "_Thread_local",
// C only extended keywords
+ TOK._assert : "__check",
TOK._import : "__import",
TOK.__cdecl : "__cdecl",
TOK.__declspec : "__declspec",
TOK.__stdcall : "__stdcall",
TOK.__pragma : "__pragma",
+ TOK.__int128 : "__int128",
TOK.__attribute__ : "__attribute__",
];
extern (C++) const(char)* toChars() const
{
- __gshared char[3 + 3 * floatvalue.sizeof + 1] buffer;
+ const bufflen = 3 + 3 * floatvalue.sizeof + 1;
+ __gshared char[bufflen] buffer;
const(char)* p = &buffer[0];
switch (value)
{
case TOK.int32Literal:
- sprintf(&buffer[0], "%d", cast(int)intvalue);
+ snprintf(&buffer[0], bufflen, "%d", cast(int)intvalue);
break;
case TOK.uns32Literal:
case TOK.wchar_tLiteral:
- sprintf(&buffer[0], "%uU", cast(uint)unsvalue);
+ snprintf(&buffer[0], bufflen, "%uU", cast(uint)unsvalue);
break;
case TOK.wcharLiteral:
case TOK.dcharLiteral:
OutBuffer buf;
buf.writeSingleCharLiteral(cast(dchar) intvalue);
buf.writeByte('\0');
- p = buf.extractSlice().ptr;
+ p = buf.extractChars();
}
break;
case TOK.int64Literal:
- sprintf(&buffer[0], "%lldL", cast(long)intvalue);
+ snprintf(&buffer[0], bufflen, "%lldL", cast(long)intvalue);
break;
case TOK.uns64Literal:
- sprintf(&buffer[0], "%lluUL", cast(ulong)unsvalue);
+ snprintf(&buffer[0], bufflen, "%lluUL", cast(ulong)unsvalue);
break;
case TOK.float32Literal:
- CTFloat.sprint(&buffer[0], 'g', floatvalue);
+ CTFloat.sprint(&buffer[0], bufflen, 'g', floatvalue);
strcat(&buffer[0], "f");
break;
case TOK.float64Literal:
- CTFloat.sprint(&buffer[0], 'g', floatvalue);
+ CTFloat.sprint(&buffer[0], bufflen, 'g', floatvalue);
break;
case TOK.float80Literal:
- CTFloat.sprint(&buffer[0], 'g', floatvalue);
+ CTFloat.sprint(&buffer[0], bufflen, 'g', floatvalue);
strcat(&buffer[0], "L");
break;
case TOK.imaginary32Literal:
- CTFloat.sprint(&buffer[0], 'g', floatvalue);
+ CTFloat.sprint(&buffer[0], bufflen, 'g', floatvalue);
strcat(&buffer[0], "fi");
break;
case TOK.imaginary64Literal:
- CTFloat.sprint(&buffer[0], 'g', floatvalue);
+ CTFloat.sprint(&buffer[0], bufflen, 'g', floatvalue);
strcat(&buffer[0], "i");
break;
case TOK.imaginary80Literal:
- CTFloat.sprint(&buffer[0], 'g', floatvalue);
+ CTFloat.sprint(&buffer[0], bufflen, 'g', floatvalue);
strcat(&buffer[0], "Li");
break;
case TOK.string_:
if (postfix)
buf.writeByte(postfix);
buf.writeByte(0);
- p = buf.extractSlice().ptr;
+ p = buf.extractChars();
}
break;
case TOK.identifier:
{
writeCharLiteral(buf, d);
}
- assert(buf.extractSlice() == `a\n\r\t\b\f\0\x11\u7233\U00017233`);
+ assert(buf[] == `a\n\r\t\b\f\0\x11\u7233\U00017233`);
}
/**
{
OutBuffer buf;
writeSingleCharLiteral(buf, '\'');
- assert(buf.extractSlice() == `'\''`);
+ assert(buf[] == `'\''`);
buf.reset();
writeSingleCharLiteral(buf, '"');
- assert(buf.extractSlice() == `'"'`);
+ assert(buf[] == `'"'`);
buf.reset();
writeSingleCharLiteral(buf, '\n');
- assert(buf.extractSlice() == `'\n'`);
+ assert(buf[] == `'\n'`);
}
_Thread_local_,
// C only extended keywords
+ _assert,
_import,
cdecl_,
declspec,
stdcall,
pragma,
+ int128_,
attribute__,
MAX,
{
alias visit = Visitor.visit;
public:
- extern (D) this(Array!(ulong)* _data, ulong _sz_size_t)
+ extern (D) this(Array!(ulong)* _data, ulong _sz_size_t) scope
{
this.data = _data;
this.sz_size_t = _sz_size_t;
}
if (e.ident == Id.isVirtualFunction)
{
+ // @@@DEPRECATED2.121@@@
+ // Deprecated in 2.101 - Can be removed from 2.121
+ e.deprecation("`traits(isVirtualFunction)` is deprecated. Use `traits(isVirtualMethod)` instead");
+
if (dim != 1)
return dimError(1);
auto se = new StringExp(e.loc, id.toString());
return se.expressionSemantic(sc);
}
+ if (e.ident == Id.fullyQualifiedName) // https://dlang.org/spec/traits.html#fullyQualifiedName
+ {
+ if (dim != 1)
+ return dimError(1);
+
+ Scope* sc2 = sc.push();
+ sc2.flags = sc.flags | SCOPE.noaccesscheck | SCOPE.ignoresymbolvisibility;
+ bool ok = TemplateInstance.semanticTiargs(e.loc, sc2, e.args, 1);
+ sc2.pop();
+ if (!ok)
+ return ErrorExp.get();
+
+ const(char)[] fqn;
+ auto o = (*e.args)[0];
+ if (auto s = getDsymbolWithoutExpCtx(o))
+ {
+ if (s.semanticRun == PASS.initial)
+ s.dsymbolSemantic(null);
+
+ fqn = s.toPrettyChars().toDString();
+ }
+ else if (auto t = getType(o))
+ {
+ fqn = t.toPrettyChars(true).toDString();
+ }
+ else
+ {
+ if (!isError(o))
+ e.error("argument `%s` has no identifier", o.toChars());
+ return ErrorExp.get();
+ }
+ assert(fqn);
+ auto se = new StringExp(e.loc, fqn);
+ return se.expressionSemantic(sc);
+
+ }
if (e.ident == Id.getProtection || e.ident == Id.getVisibility)
{
if (dim != 1)
if (errors < global.errors)
e.error("`%s` cannot be resolved", eorig.toChars());
+ if (e.ident == Id.getVirtualFunctions)
+ {
+ // @@@DEPRECATED2.121@@@
+ // Deprecated in 2.101 - Can be removed from 2.121
+ e.deprecation("`traits(getVirtualFunctions)` is deprecated. Use `traits(getVirtualMethods)` instead");
+ }
+
/* Create tuple of functions of ex
*/
auto exps = new Expressions();
uint errors = global.startGagging();
Scope* sc2 = sc.push();
sc2.tinst = null;
- sc2.minst = null;
+ sc2.minst = null; // this is why code for these are not emitted to object file
sc2.flags = (sc.flags & ~(SCOPE.ctfe | SCOPE.condition)) | SCOPE.compile | SCOPE.fullinst;
bool err = false;
initialized = true; // lazy initialization
// All possible traits
- __gshared Identifier*[58] idents =
+ __gshared Identifier*[59] idents =
[
&Id.isAbstractClass,
&Id.isArithmetic,
&Id.isReturnOnStack,
&Id.hasMember,
&Id.identifier,
+ &Id.fullyQualifiedName,
&Id.getProtection,
&Id.getVisibility,
&Id.parent,
import dmd.dsymbolsem;
import dmd.dtemplate;
import dmd.errors;
+import dmd.errorsink;
import dmd.expression;
import dmd.expressionsem;
import dmd.func;
return helper3();
}
}
+
if (!sm)
- {
- if (!t)
- {
- if (s.isDeclaration()) // var, func, or tuple declaration?
- {
- t = s.isDeclaration().type;
- if (!t && s.isTupleDeclaration()) // expression tuple?
- return helper3();
- }
- else if (s.isTemplateInstance() ||
- s.isImport() || s.isPackage() || s.isModule())
- {
- return helper3();
- }
- }
- if (t)
- {
- sm = t.toDsymbol(sc);
- if (sm && id.dyncast() == DYNCAST.identifier)
- {
- sm = sm.search(loc, cast(Identifier)id, IgnorePrivateImports);
- if (!sm)
- return helper3();
- }
- else
- return helper3();
- }
- else
- {
- if (id.dyncast() == DYNCAST.dsymbol)
- {
- // searchX already handles errors for template instances
- assert(global.errors);
- }
- else
- {
- assert(id.dyncast() == DYNCAST.identifier);
- sm = s.search_correct(cast(Identifier)id);
- if (sm)
- error(loc, "identifier `%s` of `%s` is not defined, did you mean %s `%s`?", id.toChars(), mt.toChars(), sm.kind(), sm.toChars());
- else
- error(loc, "identifier `%s` of `%s` is not defined", id.toChars(), mt.toChars());
- }
- pe = ErrorExp.get();
- return;
- }
- }
+ return helper3();
+
s = sm.toAlias();
}
{
auto errors = global.errors;
mtype.dim = semanticLength(sc, tbn, mtype.dim);
+ mtype.dim = mtype.dim.implicitCastTo(sc, Type.tsize_t);
if (errors != global.errors)
return error();
* run on them for the size, since they may be forward referenced.
*/
bool overflow = false;
- if (mulu(tbn.size(loc), d2, overflow) >= target.maxStaticDataSize || overflow)
+ if (mulu(tbn.size(loc), d2, overflow) > target.maxStaticDataSize || overflow)
return overflowError();
}
}
if (fparam.storageClass & STC.return_)
{
- if (fparam.isReference())
- {
- // Disabled for the moment awaiting improvement to allow return by ref
- // to be transformed into return by scope.
- if (0 && !tf.isref)
- {
- auto stc = fparam.storageClass & (STC.ref_ | STC.out_);
- .error(loc, "parameter `%s` is `return %s` but function does not return by `ref`",
- fparam.ident ? fparam.ident.toChars() : "",
- stcToString(stc).ptr);
- errors = true;
- }
- }
- else
+ if (!fparam.isReference())
{
if (!(fparam.storageClass & STC.scope_))
fparam.storageClass |= STC.scope_ | STC.scopeinferred; // 'return' implies 'scope'
// extended index), as we need to run semantic when `oidx` changes.
size_t tupleOrigIdx = size_t.max;
size_t tupleExtIdx = size_t.max;
- bool hasDefault;
foreach (oidx, oparam, eidx, eparam; tf.parameterList)
{
// oparam (original param) will always have the default arg
// position to get the offset in it later on.
if (oparam.defaultArg)
{
- hasDefault = true;
// Get the obvious case out of the way
if (oparam is eparam)
errors |= !defaultArgSemantic(eparam, argsc);
eparam.defaultArg = (*te.exps)[eidx - tupleExtIdx];
}
}
- else if (hasDefault)
- {
- .error(loc, "default argument expected for `%s`", oparam.toChars());
- errors = true;
- }
// We need to know the default argument to resolve `auto ref`,
// hence why this has to take place as the very last step.
{
/* Rewrite as:
* this.d
+ *
+ * only if the scope in which we are
+ * has a `this` that matches the type
+ * of the lhs of the dot expression.
+ *
+ * https://issues.dlang.org/show_bug.cgi?id=23617
*/
- if (hasThis(sc))
+ auto fd = hasThis(sc);
+ if (fd && fd.isThis() == mt.sym)
{
e = new DotVarExp(e.loc, new ThisExp(e.loc), d);
return e.expressionSemantic(sc);
const len = buf.length;
buf.writeByte(0);
const str = buf.extractSlice()[0 .. len];
- scope p = new Parser!ASTCodegen(loc, sc._module, str, false);
+ scope p = new Parser!ASTCodegen(loc, sc._module, str, false, global.errorSink);
p.nextToken();
//printf("p.loc.linnum = %d\n", p.loc.linnum);
* loc = the location for reporting line nunbers in errors
* t = the type to get the type of the `TypeInfo` object for
* sc = the scope
+ * genObjCode = if true, object code will be generated for the obtained TypeInfo
* Returns:
* The type of the `TypeInfo` object associated with `t`
*/
-extern (C++) Type getTypeInfoType(const ref Loc loc, Type t, Scope* sc);
+extern (C++) Type getTypeInfoType(const ref Loc loc, Type t, Scope* sc, bool genObjCode = true);
private TypeInfoDeclaration getTypeInfoDeclaration(Type t)
{
public:
bool stop;
- final extern (D) this()
+ final extern (D) this() scope
{
}
}
else
{
/* Generate: _d_newclass() */
- tree arg = build_address (get_classinfo_decl (cd));
- new_call = build_libcall (LIBCALL_NEWCLASS, tb, 1, arg);
+ new_call = build_expr (e->lowering);
}
/* Set the context pointer for nested classes. */
D RejectNegative
Implement DIP1021: Mutable function arguments.
-fpreview=dip25
-D RejectNegative
-Implement DIP25: Sealed references.
-
fpreview=dtorfields
D RejectNegative
Destruct fields of partially constructed objects.
D RejectNegative
Revert DIP1000: Scoped pointers.
-frevert=dip25
-D RejectNegative
-Revert DIP25: Sealed references.
-
frevert=dtorfields
D RejectNegative
Don't destruct fields of partially constructed objects.
/* Array of local ClassInfo decls are laid out in the same way. */
ClassDeclarations aclasses;
- for (size_t i = 0; i < decl->members->length; i++)
- {
- Dsymbol *member = (*decl->members)[i];
- member->addLocalClass (&aclasses);
- }
+ getLocalClasses (decl, aclasses);
if (aclasses.length)
{
ClassDeclarations aclasses;
FuncDeclaration *sgetmembers;
- for (size_t i = 0; i < decl->members->length; i++)
- {
- Dsymbol *member = (*decl->members)[i];
- member->addLocalClass (&aclasses);
- }
+ getLocalClasses (decl, aclasses);
size_t aimports_dim = decl->aimports.length;
for (size_t i = 0; i < decl->aimports.length; i++)
DEF_D_RUNTIME (ARRAYBOUNDS_INDEXP, "_d_arraybounds_indexp", RT(VOID),
P4(IMMUTABLE_CHARPTR, UINT, SIZE_T, SIZE_T), ECF_NORETURN)
-/* Used when calling new on a class. */
-DEF_D_RUNTIME (NEWCLASS, "_d_newclass", RT(OBJECT), P1(CONST_CLASSINFO), 0)
-
/* Used when calling delete on a stack-allocated class or interface. */
DEF_D_RUNTIME (CALLFINALIZER, "_d_callfinalizer", RT(VOID), P1(VOIDPTR), 0)
DEF_D_RUNTIME (CALLINTERFACEFINALIZER, "_d_callinterfacefinalizer", RT(VOID),
tree ifbody = void_node;
tree elsebody = void_node;
- /* Build the `then' branch. */
- if (s->ifbody)
+ /* Build the `then' branch, don't do code generation when the condition
+ is `if (__ctfe)', as that is always false at run-time. */
+ if (s->ifbody && !s->isIfCtfeBlock ())
{
push_stmt_list ();
this->build_stmt (s->ifbody);
return decl->cpp_type_info_ptr_sym;
}
-/* Get the exact TypeInfo for TYPE, if it doesn't exist, create it. */
+/* Get the exact TypeInfo for TYPE, if it doesn't exist, create it.
+ When GENERATE is true, push the TypeInfo as a member of MOD so that it will
+ get code generation. */
void
-create_typeinfo (Type *type, Module *mod)
+create_typeinfo (Type *type, Module *mod, bool generate)
{
if (!Type::dtypeinfo)
create_frontend_tinfo_types ();
/* If this has a custom implementation in rt/typeinfo, then
do not generate a COMDAT for it. */
- if (!builtin_typeinfo_p (t))
+ if (generate && !builtin_typeinfo_p (t))
{
/* Find module that will go all the way to an object file. */
if (mod)
continue;
/* If this variable was really a tuple, add all tuple fields. */
- if (var->aliassym)
+ if (var->aliasTuple)
{
- TupleDeclaration *td = var->aliassym->isTupleDeclaration ();
+ TupleDeclaration *td = var->aliasTuple;
Dsymbols tmembers;
/* No other way to coerce the underlying type out of the tuple.
Frontend should have already validated this. */
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=23084
+// { dg-additional-options "-mavx" { target avx_runtime } }
+// { dg-do compile { target { avx_runtime || vect_sizes_16B_8B } } }
+// { dg-skip-if "needs gcc/config.d" { ! d_runtime } }
+
+__vector(int[4]) test23084a(__vector(int[4]) a)
+{
+ __vector(short[8]) r = cast(short)(a.array[0]);
+ return cast(__vector(int[4]))r;
+}
+
+__vector(int[4]) test23084b(__vector(int[4]) a)
+{
+ __vector(byte[16]) r = cast(byte)(a.array[0]);
+ return cast(__vector(int[4]))r;
+}
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=23085
+// { dg-additional-options "-mavx" { target avx_runtime } }
+// { dg-do compile }
+// { dg-skip-if "needs gcc/config.d" { ! d_runtime } }
+
+float test23085(float x)
+{
+ byte i = *cast(byte*)&x;
+ ++i;
+ return *cast(float*)&i; // this cast is not allowed in @safe code
+}
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=23218
+// { dg-additional-options "-mavx" { target avx_runtime } }
+// { dg-do run { target { avx_runtime || vect_sizes_16B_8B } } }
+// { dg-skip-if "needs gcc/config.d" { ! d_runtime } }
+
+__vector(int[4]) convtest(int[4] a)
+{
+ return cast(__vector(int[4]))a;
+}
+
+void main()
+{
+ static assert(convtest([1,2,3,4])[0] == 1);
+ assert(convtest([1,2,3,4])[0] == 1);
+}
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=23620
+struct Index
+{
+ uint value;
+ alias value this;
+}
+
+enum i = Index();
+int[i] a;
+static assert(a.length == 0);
module foo.bar.ba;
-nothrow pure @nogc @safe package(foo)
+nothrow pure @nogc @safe package(foo)
{
void foo();
nothrow pure @nogc @safe package(foo.bar) void foo2();
struct BugInt
{
- uint[] data = ZEROX;
+ uint[] data = ZEROX;
}
enum uint [] ZEROX = [0];
--- /dev/null
+template fullyQualifiedName(T...)
+{
+ enum fullyQualifiedName = !T[0];
+}
+
+void __trace_maybeDumpTupleToFile(Args...)(auto ref const Args args) nothrow @nogc { }
+
+int getStructInfoEx(T)() {
+ enum Ctx = fullyQualifiedName!T;
+ return 0;
+}
+
+auto as(Func)(Func) {}
+
+@nogc void foo() { }
+
+void assertOp(string OPERATION, LHS, RHS)(LHS lhs, RHS) {
+ as({
+ try {
+ try as(lhs);
+ catch(Throwable) foo();
+ } catch(Throwable) assert(false);
+ });
+}
+
+struct FixedArray(T, size_t capacity_) {
+ int a = getStructInfoEx!FixedArray;
+
+ T* some_function() {
+ assertOp !""(1, 1);
+ return null;
+ }
+ alias some_function this;
+}
+
+struct ReclamationBatch {
+
+ FixedArray !(uint,1) dummy;
+
+ @nogc nothrow void some_inout_func() inout { }
+
+ void func_2(Dlg)(Dlg dlg) {
+ __trace_maybeDumpTupleToFile(dlg);
+ }
+
+ void _reclaimBatch() {
+ func_2({ some_inout_func; });
+ }
+}
--- /dev/null
+interface Timeline {
+}
+
+struct Policy {
+ alias OldTagCallback = void delegate() @nogc nothrow;
+ Timeline timeline;
+ OldTagCallback oldTagCB;
+}
+
+import test23626;
+
+struct Tiering {
+ StaticHashTable!(Policy) policies;
+}
{
auto dg = &f;
}
-
- foreach (f; __traits(getVirtualFunctions, typeof(this), "bar"))
- {
- auto dg = &f;
- }
}
uint bar() { return 0; }
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=23662
+typedef enum {A} E;
+
+E func(E v) {
+ return v;
+}
--- /dev/null
+/// Test storage class inference on delegate parameters
+
+alias FPT = void function (in string, ref string, out string, scope string);
+alias DGT = void delegate (in string, ref string, out string, scope string);
+
+void f1 (FPT func)
+{
+ string ro = "Hello World";
+ string ref_ = ro, out_ = ro;
+ func(ro, ref_, out_, ro);
+}
+
+void f2 (DGT func)
+{
+ string ro = "Hello World";
+ string ref_ = ro, out_ = ro;
+ func(ro, ref_, out_, ro);
+}
+
+void test ()
+{
+ f1((in_, ref_, out_, scope_) {
+ assert(in_ == "Hello World");
+ assert(in_ == scope_);
+ assert(in_ == ref_);
+ assert(out_ is null);
+ });
+
+ f2((in_, ref_, out_, scope_) {
+ assert(in_ == "Hello World");
+ assert(in_ == scope_);
+ assert(in_ == ref_);
+ assert(out_ is null);
+ });
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=11316
+void issue11316() {
+ void delegate(const int x) F0;
+ F0 = (const int x) {}; // OK
+ F0 = (x) {}; // OK
+ void delegate(in int x) F1;
+ F1 = (in int x) {}; // OK
+ F1 = (x) {}; // OK
+ void delegate(ref int x) F2;
+ F2 = (ref int x) {}; // OK
+ F2 = (x) {}; // Error
+ void delegate(out int x) F3;
+ F3 = (out int x) {}; // OK
+ F3 = (x) {}; // Error
+}
--- /dev/null
+
+struct S
+{
+ string name;
+ int x;
+ int y;
+}
+
+
+immutable S s = S(x: 2, 3, name: "boo");
+
+static assert(s.x == 2);
+static assert(s.y == 3);
+static assert(s.name == "boo");
+
+union U
+{
+ float f;
+ int i;
+}
+
+immutable U u = U(i: 2);
+
+static assert(u.i == 2);
--- /dev/null
+
+string fun(string x, string y, string z = "Z", string w = "W")
+{
+ return x ~ y ~ z ~ w;
+}
+
+static assert(fun( "x", "y") == "xyZW");
+static assert(fun( "x", "y", "z", "w") == "xyzw");
+static assert(fun(x: "x", y: "y", z: "z", w: "w") == "xyzw");
+static assert(fun(w: "w", z: "z", y: "y", x: "x") == "xyzw");
+static assert(fun(y: "y", "z", x: "x") == "xyzW");
+static assert(fun( "x", "y", w: "w") == "xyZw");
+static assert(fun(x: "x", "y", z: "z") == "xyzW");
+
+// Default arguments need not all be at the end anymore
+string fun2(string x = "x", string y, string z = "z")
+{
+ return x ~ y ~ z;
+}
+
+static assert(fun2(y: "y") == "xyz");
+
+// The assumption that first parameter having a default implies all parameters have a default is no longer valid,
+// so this struct constructor shouldn't be mistaken for a default constructor.
+struct SD { this(int x = 1, int y) { } }
+
+// UFCS
+static assert("x".fun("y", w: "w") == "xyZw");
+
+// tuples
+alias AliasSeq(T...) = T;
+
+static assert("x".fun(x: AliasSeq!(), "y", w: "w") == "xyZw");
+static assert(AliasSeq!("x", "y").fun(w: "w", z: AliasSeq!()) == "xyZw");
+static assert(fun(y: AliasSeq!("y", "z", "w"), x: "x") == "xyzw");
+
+// `new` expressions
+class C
+{
+ int x, y;
+
+ this(int x, int y)
+ {
+ this.x = x;
+ this.y = y;
+ }
+
+ static C opCall(int x, int y) { return new C(x, y); }
+}
+
+struct S
+{
+ int x, y;
+}
+
+static assert(new C(y: 3, x: 2).x == 2);
+static assert( C(y: 3, x: 2).x == 2);
+static assert(new S(y: 3, x: 2).x == 2);
+static assert( S(y: 3, x: 2).x == 2);
+
+// opCall
+struct Div
+{
+ static int opCall(int numer, int denom) { return numer / denom; }
+}
+static assert(Div(denom: 3, numer: 6) == 2);
+
+struct Concat
+{
+ string s = "s";
+ string opCall(string st0, string st1) { return s ~ st0 ~ st1; }
+}
+
+static assert(Concat.init("t0", "t1") == "st0t1");
testForeach(cs);
testForeach(fs);
}
+
+struct S23669
+{
+ string[] a;
+ @safe void reserve() scope
+ {
+ a.length += 1;
+ }
+}
ch = shared Child(i);
}
}
+
+// https://issues.dlang.org/show_bug.cgi?id=23732
+class Class {}
+void main()
+{
+ auto b = new shared Class();
+}
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=16495
+
+void types()
+{
+ static assert(__traits(fullyQualifiedName, string) == "string");
+ static assert(__traits(fullyQualifiedName, wstring) == "wstring");
+ static assert(__traits(fullyQualifiedName, dstring) == "dstring");
+ static assert(__traits(fullyQualifiedName, typeof(null)) == "typeof(null)");
+ static assert(__traits(fullyQualifiedName, void) == "void");
+ static assert(__traits(fullyQualifiedName, const(void)) == "const(void)");
+ static assert(__traits(fullyQualifiedName, shared(void)) == "shared(void)");
+ static assert(__traits(fullyQualifiedName, shared const(void)) == "shared(const(void))");
+ static assert(__traits(fullyQualifiedName, shared inout(void)) == "shared(inout(void))");
+ static assert(__traits(fullyQualifiedName, shared inout const(void)) == "shared(inout(const(void)))");
+ static assert(__traits(fullyQualifiedName, inout(void)) == "inout(void)");
+ static assert(__traits(fullyQualifiedName, inout const(void)) == "inout(const(void))");
+ static assert(__traits(fullyQualifiedName, immutable(void)) == "immutable(void)");
+}
+
+struct QualifiedNameTests
+{
+ struct Inner
+ {
+ bool value;
+ }
+
+ ref const(Inner[string]) func( ref Inner var1, lazy scope string var2 );
+ ref const(Inner[string]) retfunc( return ref Inner var1 );
+ Inner inoutFunc(inout Inner) inout;
+ shared(const(Inner[string])[]) data;
+ const Inner delegate(double, string) @safe nothrow deleg;
+ inout(int) delegate(inout int) inout inoutDeleg;
+ Inner function(out double, string) funcPtr;
+ extern(C) Inner function(double, string) cFuncPtr;
+
+ extern(C) void cVarArg(int, ...);
+ void dVarArg(...);
+ void dVarArg2(int, ...);
+ void typesafeVarArg(int[] ...);
+
+ Inner[] array;
+ Inner[16] sarray;
+ Inner[Inner] aarray;
+ const(Inner[const(Inner)]) qualAarray;
+
+ shared(immutable(Inner) delegate(ref double, scope string) const shared @trusted nothrow) attrDeleg;
+
+ struct Data(T) { int x; }
+ void tfunc(T...)(T args) {}
+
+ template Inst(alias A) { int x; }
+
+ class Test12309(T, int x, string s) {}
+}
+
+void symbols()
+{
+ alias qnTests = QualifiedNameTests;
+ enum prefix = "test16495.QualifiedNameTests.";
+ static assert(__traits(fullyQualifiedName, qnTests.Inner) == prefix ~ "Inner");
+ static assert(__traits(fullyQualifiedName, qnTests.func) == prefix ~ "func");
+
+ static assert(__traits(fullyQualifiedName, qnTests.Data!int) == prefix ~ "Data!int.Data");
+ static assert(__traits(fullyQualifiedName, qnTests.Data!int.x) == prefix ~ "Data!int.Data.x");
+ static assert(__traits(fullyQualifiedName, qnTests.tfunc!(int[])) == prefix ~ "tfunc!(int[]).tfunc");
+ static assert(__traits(fullyQualifiedName, qnTests.Inst!(Object)) == prefix ~ "Inst!(Object)");
+ static assert(__traits(fullyQualifiedName, qnTests.Inst!(Object).x) == prefix ~ "Inst!(Object).x");
+ static assert(__traits(fullyQualifiedName, qnTests.Test12309!(int, 10, "str"))
+ == prefix ~ "Test12309!(int, 10, \"str\").Test12309");
+}
+
+void names()
+{
+ enum prefix = "test16495.QualifiedNameTests";
+ enum xx = prefix ~ ".Inner";
+ with (QualifiedNameTests)
+ {
+ // Basic qualified name
+ static assert(__traits(fullyQualifiedName, Inner) == xx);
+
+ // Array types
+ static assert(__traits(fullyQualifiedName, typeof(array)) == xx ~ "[]");
+ static assert(__traits(fullyQualifiedName, typeof(sarray)) == xx ~ "[16]");
+ static assert(__traits(fullyQualifiedName, typeof(aarray)) == xx ~ "[" ~ xx ~ "]");
+
+ // qualified key for AA
+ static assert(__traits(fullyQualifiedName, typeof(qualAarray)) == "const(" ~ xx ~ "[const(" ~ xx ~ ")])");
+
+ // Qualified composed data types
+ static assert(__traits(fullyQualifiedName, typeof(data)) == "shared(const(" ~ xx ~ "[string])[])");
+
+ // Function types + function attributes
+ static assert(__traits(fullyQualifiedName, typeof(func)) == "ref const(" ~ xx ~ "[string])(ref " ~ xx ~ ", lazy scope string)");
+ static assert(__traits(fullyQualifiedName, typeof(retfunc)) == "ref const(" ~ xx ~ "[string])(return ref " ~ xx ~ ")");
+ static assert(__traits(fullyQualifiedName, typeof(inoutFunc)) == "inout "~xx~"(inout("~xx~"))");
+ static assert(__traits(fullyQualifiedName, typeof(deleg)) == "const(" ~ xx ~ " delegate(double, string) nothrow @safe)");
+ static assert(__traits(fullyQualifiedName, typeof(inoutDeleg)) == "inout(int) delegate(inout(int)) inout");
+ static assert(__traits(fullyQualifiedName, typeof(funcPtr)) == "" ~ xx ~ " function(out double, string)");
+ static assert(__traits(fullyQualifiedName, typeof(cFuncPtr)) == "extern (C) " ~ xx ~ " function(double, string)");
+
+ // Delegate type with qualified function type
+ static assert(__traits(fullyQualifiedName, typeof(attrDeleg)) == "shared(immutable(" ~ xx ~ ") "~
+ "delegate(ref double, scope string) shared const nothrow @trusted)");
+
+ // Variable argument function types
+ static assert(__traits(fullyQualifiedName, typeof(cVarArg)) == "extern (C) void(int, ...)");
+ static assert(__traits(fullyQualifiedName, typeof(dVarArg)) == "void(...)");
+ static assert(__traits(fullyQualifiedName, typeof(dVarArg2)) == "void(int, ...)");
+ static assert(__traits(fullyQualifiedName, typeof(typesafeVarArg)) == "void(int[]...)");
+
+ // SIMD vector
+ static if (is(__vector(float[4])))
+ {
+ static assert(__traits(fullyQualifiedName, __vector(float[4])) == "__vector(float[4])");
+ }
+ }
+}
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=18026
+bool f(T)(T x)
+{
+ return false;
+}
+
+static foreach(i; 0..60000)
+{
+ static if(f(i))
+ {
+ }
+}
--- /dev/null
+/* REQUIRED_ARGS: -betterC
+ */
+
+// https://issues.dlang.org/show_bug.cgi?id=19268
+
+mixin(`void foo(){}`.idup);
--- /dev/null
+/* REQUIRED_ARGS: -betterC
+ */
+
+// https://issues.dlang.org/show_bug.cgi?id=20101
+
+public string ctfeHelper()(string a)
+{
+ return "int " ~ a ~ " = 42;";
+}
+
+extern(C) int main()
+{
+ int b = __traits(compiles, ctfeHelper("a"));
+ mixin(ctfeHelper("a"));
+ return !(a + b);
+}
+++ /dev/null
-// https://issues.dlang.org/show_bug.cgi?id=21073
-
-class C
-{
- auto internal() const
- {
- return 5;
- }
- alias internal this;
-}
-
-void main() pure
-{
- const c = new C;
- auto r = cast(C)c;
-}
+++ /dev/null
-// https://issues.dlang.org/show_bug.cgi?id=21543
-
-class B
-{
- Nullable!B data;
- alias data this;
-}
-
-void test1()
-{
- B b;
- Nullable!B n;
-}
-
-struct Nullable(T)
-{
- T payload;
-
- void opAssign()(T)
- {
- move(payload);
- }
-
- inout(T) get_() inout
- {
- return payload;
- }
-
- alias get_ this;
-}
-
-// another version with chain of 3 alias this
-
-struct C
-{
- Nullable2 data;
- alias data this;
-}
-
-void test2()
-{
- C c;
- Nullable2 n2 = &c;
- Nullable3 n3 = &c;
-
- // these are to check a sane -vcg-ast output
- fn1(c);
- fn1(n2);
- fn1(n3);
- fn2(c);
- fn2(n2);
- fn2(n3);
- fn3(c);
- fn3(n2);
- fn3(n3);
-}
-
-void fn1(C x) {}
-
-void fn2(Nullable2 x) {}
-
-void fn3(Nullable3 x) {}
-
-struct Nullable2
-{
- Nullable3 payload;
-
- this(C* c)
- {
- payload = Nullable3(c);
- }
-
- void opAssign()(Nullable3)
- {
- move(payload);
- }
-
- inout(Nullable3) get_() inout
- {
- return payload;
- }
-
- alias get_ this;
-}
-
-struct Nullable3
-{
- C* payload;
-
- this(C* c)
- {
- payload = c;
- }
-
- void opAssign()(C)
- {
- move(payload);
- }
-
- inout(C) get_() inout
- {
- return *payload;
- }
-
- alias get_ this;
-}
-
-T move(T)(ref T source)
-{
- return source;
-}
-
-T move(T)(T source)
-{
- return source;
-}
--- /dev/null
+// REQUIRED_ARGS: -preview=dip1000
+
+// https://issues.dlang.org/show_bug.cgi?id=22916
+// Issue 22916 - [dip1000] copy of ref return still treated as scope variable (edit)
+
+@safe:
+struct Arr
+{
+ int** ptr;
+ ref int* index() return scope { return *ptr; }
+ void assign(int* p) scope { *ptr = p; }
+}
+
+void main0()
+{
+ scope Arr a;
+ a.assign(a.index());
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=23682
+ref char* front_p(ref return scope char** p) { return *p; }
+ref char* front_r( return scope char** p) { return *p; }
+
+char* g;
+
+void test23862()
+{
+ scope char** _errors;
+ g = front_p(_errors); // should pass
+ g = front_r(_errors); // should pass
+}
+
+// Test case reduced from druntime
+ref int* monitor(return scope Object h) pure nothrow @nogc @trusted
+{
+ return *cast(int**)&h.__monitor;
+}
+
+int* getMonitor(Object h) pure @nogc
+{
+ return monitor(h); // should pass
+}
--- /dev/null
+/* TEST_OUTPUT:
+---
+compilable/test23145.d(117): Deprecation: `scope` allocation of `c` requires that constructor be annotated with `scope`
+compilable/test23145.d(111): is the location of the constructor
+compilable/test23145.d(124): Deprecation: `scope` allocation of `c` requires that constructor be annotated with `scope`
+compilable/test23145.d(111): is the location of the constructor
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=23145
+
+#line 100
+
+class D
+{
+ C c;
+}
+
+class C
+{
+ D d;
+ int x=3;
+ this(int i) scope @safe @nogc;
+ this(D d) @safe @nogc;
+}
+
+C foo(D d)@nogc @safe
+{
+ scope e = new C(1); // ok
+ scope c = new C(d); // deprecation
+ return c.d.c;
+}
+
+C bax(D d) @safe
+{
+ scope e = new C(1); // ok
+ scope c = new C(d); // deprecation
+ return c.d.c;
+}
class Error { }
+// Needed to lower `new Exception("ice")` to it.
+T _d_newclassT(T)()
+if (is(T == class))
+{
+ return null;
+}
+
void test23431()
{
int a;
class Throwable { }
class Exception : Throwable { this(immutable(char)[]) { } }
+// Needed to lower `new Exception("ice")` to it.
+T _d_newclassT(T)()
+if (is(T == class))
+{
+ return null;
+}
+
void test23433()
{
try
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=23598
+
+alias AliasSeq(a...) = a;
+
+static if (1)
+{
+
+template sort(alias f, a...)
+{
+ static if (a.length > 0)
+ {
+ alias x = f!(a[0]);
+ alias sort = a;
+ }
+ else
+ alias sort = a;
+}
+
+alias SortedItems = sort!(isDependencyOf, String);
+
+enum isDependencyOf(Item) = Item.DirectDependencies.length == 0;
+
+struct String
+{
+ alias DirectDependencies = AliasSeq!();
+
+ enum l = SortedItems.length; // (3)
+}
+
+}
+
+/*****************************************************/
+
+static if (1)
+{
+enum x = 1;
+enum y = 2;
+
+template f(T)
+{
+ alias b = int;
+ static if (x)
+ {
+ alias c = x;
+ }
+ else
+ {
+ alias c = y;
+ }
+
+ static if (is(typeof(c)))
+ {
+ }
+ else
+ {
+ static assert(0);
+ }
+}
+
+void g()
+{
+ int x = f!int.c;
+}
+}
+
+/*****************************************************/
+
+template forward(args...)
+{
+ template fwd(alias arg)
+ {
+ alias fwd = arg;
+ }
+
+ alias Result = AliasSeq!();
+ static foreach (arg; args)
+ Result = AliasSeq!(Result, fwd!arg);
+ static if (Result.length == 1)
+ alias forward = Result[0];
+ else
+ alias forward = Result;
+}
+
+void func(int i, int j)
+{
+ func(forward!(i, j));
+}
--- /dev/null
+/* REQUIRED_ARGS: -betterC
+ */
+
+// https://issues.dlang.org/show_bug.cgi?id=23606
+
+string foo()()
+{
+ string a, b;
+ return a ~ b;
+}
+
+enum s = foo();
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=23617
+
+struct S
+{
+ void foo() {}
+}
+
+struct Wrapper
+{
+ size_t currentIndex;
+ S[] arrayOfS;
+
+ auto opDispatch(string name, T ...)(T t)
+ {
+ return __traits(child, arrayOfS[this.currentIndex], __traits(getMember, S, name))(t);
+ }
+}
+
+void main()
+{
+ Wrapper w;
+ w.opDispatch!"foo"();
+}
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=23626
+// EXTRA_SOURCES: extra-files/test23626a.d extra-files/test23626b.d
+module test23626;
+
+struct StaticHashTable(V)
+{
+ V v;
+}
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=23639
+
+// REQUIRED_ARGS: -preview=nosharedaccess
+
+class T {}
+
+shared(T) allocClassMem()
+{
+ void *p;
+ // assume p is allocated here
+ return cast(shared(T))p;
+}
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=23651
+
+template isCallable(alias callable)
+{
+ static if (is(typeof(&callable!())))
+ enum bool isCallable = isCallable!(typeof(&callable!()));
+ else
+ enum bool isCallable = true;
+}
+
+string foo();
+
+template FunctionTypeOf(alias func)
+if (isCallable!func)
+{
+ alias FunctionTypeOf = typeof(foo);
+}
+
+template ReturnType(alias func)
+{
+ static if (is(FunctionTypeOf!func R == return))
+ alias ReturnType = R;
+}
+
+template isAttrRange()
+{
+ alias NameType = ReturnType!((string r) => r);
+ //pragma(msg, "isAttrRange ", NameType, " ", string);
+ static assert(is(NameType == string));
+
+ enum isAttrRange = is(NameType == string);
+}
+
+static assert(isAttrRange!());
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=23662
+// EXTRA_FILES: imports/imp23662.c
+import imports.imp23662;
+
+void main(string[] args) {
+ auto r = func(A);
+ assert(r == A);
+}
--- /dev/null
+// Issue 23676 - Static foreach hangs compilation for some time
+// https://issues.dlang.org/show_bug.cgi?id=23676
+
+void f()
+{
+ int i;
+ void g(int I)()
+ {
+ static foreach(j; 0..11)
+ {
+ i++;
+ g!j();
+ }
+ }
+ g!0;
+}
--- /dev/null
+// DISABLED: win32
+// https://issues.dlang.org/show_bug.cgi?id=23679
+ubyte [0x7fff_ffffU] arr;
+++ /dev/null
-// https://issues.dlang.org/show_bug.cgi?id=5973
-
-class A { int a = 1; }
-class B { int b = 2; }
-class C : A
-{
- B obj;
- alias obj this;
- this(){ obj = new B(); }
-}
-class X : C {}
-
-class D
-{
- int i;
-}
-
-class E
-{
- D x;
- alias x this;
-}
-
-class F : E
-{
- void test()
- {
- i = 5;
- }
-}
-
-void main()
-{
- auto c = new C();
- assert(c.a == 1); // lookup C -> A, OK
- assert(c.b == 2); // lookup C => B, OK
-
- auto x = new X();
- assert(x.a == 1); // lookup X -> C -> A, OK
- assert(x.b == 2); // lookup X -> C => B, NG (Line 17)
-}
+++ /dev/null
-struct S {}
-
-class C {
- S s;
- alias s this;
-}
-
-void main() {
- auto c = new C;
- auto p = cast(void*) c;
-}
/* REQUIRED_ARGS: -preview=bitfields
* TEST_OUTPUT:
---
-fail_compilation/biterrors2.d(100): Error: variable `biterrors2.a` bit-field must be member of struct, union, or class
+fail_compilation/biterrors2.d(100): Error: variable `biterrors2.a` - bit-field must be member of struct, union, or class
fail_compilation/biterrors2.d(104): Error: bit-field `b` has zero width
fail_compilation/biterrors2.d(105): Error: bit-field type `float` is not an integer type
---
--- /dev/null
+/*
+TEST_OUTPUT:
+---
+fail_compilation/call_function_type.d(18): Error: missing argument for parameter #1: `int`
+fail_compilation/call_function_type.d(19): Error: cannot call `int(int)(3)` at compile time
+---
+*/
+
+// This is a rare case where `dmd.expressionsem.functionParameters` catches a missing argument error,
+// which is usually caught earlier by `TypeFunction.callMatch`, and had no test coverage yet.
+// This was found while implementing named arguments and reduced from `vibe.internal.meta.traits`.
+
+int f(int);
+
+void m()
+{
+ alias FT = typeof(f);
+ enum X0 = FT();
+ enum X1 = FT(3);
+}
--- /dev/null
+/* TEST_OUTPUT:
+---
+fail_compilation/ctfeblock.d(112): Error: cannot `goto` into `if (__ctfe)` block
+---
+*/
+
+/*******************************************/
+// https://issues.dlang.org/show_bug.cgi?id=18472
+// https://github.com/dlang/dmd/pull/14676
+
+#line 100
+
+struct T { }
+
+@nogc void test1()
+{
+ int a;
+ if (__ctfe)
+ {
+L1:
+ new T();
+ a = 3;
+ }
+ goto L1;
+}
+
+@nogc void test2()
+{
+ if (__ctfe)
+ {
+ new T();
+ }
+}
--- /dev/null
+// REQUIRED_ARGS: -de
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/deprecate_getVirtualFunctions.d(18): Deprecation: `traits(isVirtualFunction)` is deprecated. Use `traits(isVirtualMethod)` instead
+fail_compilation/deprecate_getVirtualFunctions.d(19): Deprecation: `traits(getVirtualFunctions)` is deprecated. Use `traits(getVirtualMethods)` instead
+---
+*/
+
+class A
+{
+ void fun() {}
+}
+
+void main()
+{
+ auto a = __traits(isVirtualFunction, A.fun);
+ foreach(f; __traits(getVirtualFunctions, A, "fun")) {}
+}
/*
TEST_OUTPUT:
---
-fail_compilation/diag10099.d(15): Error: variable `diag10099.main.s` default construction is disabled for type `S`
+fail_compilation/diag10099.d(15): Error: variable `diag10099.main.s` - default construction is disabled for type `S`
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/diag11132.d(22): Error: overlapping initialization for field `a` and `b`
+fail_compilation/diag11132.d(23): Error: overlapping initialization for field `a` and `b`
+fail_compilation/diag11132.d(23): `struct` initializers that contain anonymous unions must initialize only the first member of a `union`. All subsequent non-overlapping fields are default initialized
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/diag12312.d(10): Error: variable `diag12312.main.arr` `void[16]` does not have a default initializer
+fail_compilation/diag12312.d(10): Error: variable `diag12312.main.arr` of type `void[16]` does not have a default initializer
+fail_compilation/diag12312.d(15): Error: variable `diag12312.bug1176.v` of type `void[1]` does not have a default initializer
---
*/
-
void main()
{
void[16] arr;
}
+
+void bug1176()
+{
+ void[1] v;
+}
---
fail_compilation/diag14235.d(12): Error: undefined identifier `Undefined` in module `imports.a14235`
fail_compilation/diag14235.d(13): Error: undefined identifier `Something` in module `imports.a14235`, did you mean struct `SomeThing(T...)`?
-fail_compilation/diag14235.d(14): Error: `imports.a14235.SomeClass` is not a template, it is a class
+fail_compilation/diag14235.d(14): Error: `SomeClass` isn't a template
---
*/
fail_compilation/diag3438.d(20): Use `@disable this();` if you want to disable default initialization.
fail_compilation/diag3438.d(21): Error: constructor `diag3438.F6.this` is marked `@disable`, so it cannot have default arguments for all parameters.
fail_compilation/diag3438.d(21): Use `@disable this();` if you want to disable default initialization.
-fail_compilation/diag3438.d(24): Error: default argument expected for `y`
+fail_compilation/diag3438.d(22): Error: constructor `diag3438.F7.this` all parameters have default arguments, but structs cannot have default constructors.
---
*/
struct F4 { this(int[] x...) { } } // ok
struct F5 { @disable this(int x = 1); }
struct F6 { @disable this(int x = 1) { } }
-
-// Make sure the deprecation doesn't interfere w/ the check for default arguments
-struct S { this(int x = 1, int y) { } }
+struct F7 { this(int x = 1, int y = 2) { } }
/*
TEST_OUTPUT:
---
-fail_compilation/diag8101.d(57): Error: function `diag8101.f_0(int)` is not callable using argument types `()`
-fail_compilation/diag8101.d(57): too few arguments, expected 1, got 0
-fail_compilation/diag8101.d(58): Error: none of the overloads of `f_1` are callable using argument types `()`
-fail_compilation/diag8101.d(33): Candidates are: `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 `()`
-fail_compilation/diag8101.d(36): Candidates are: `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: none of the overloads of template `diag8101.t_0` are callable using argument types `!()()`
-fail_compilation/diag8101.d(43): Candidate is: `t_0(T1)()`
-fail_compilation/diag8101.d(62): Error: none of the overloads of template `diag8101.t_1` are callable using argument types `!()()`
-fail_compilation/diag8101.d(45): Candidates are: `t_1(T1)()`
-fail_compilation/diag8101.d(46): `t_1(T1, T2)()`
-fail_compilation/diag8101.d(63): Error: none of the overloads of template `diag8101.t_2` are callable using argument types `!()()`
-fail_compilation/diag8101.d(48): Candidates are: `t_2(T1)()`
-fail_compilation/diag8101.d(49): `t_2(T1, T2)()`
-fail_compilation/diag8101.d(50): `t_2(T1, T2, T3)()`
-fail_compilation/diag8101.d(51): `t_2(T1, T2, T3, T4)()`
-fail_compilation/diag8101.d(52): `t_2(T1, T2, T3, T4, T5)()`
+fail_compilation/diag8101.d(61): Error: function `diag8101.f_0(int)` is not callable using argument types `()`
+fail_compilation/diag8101.d(61): too few arguments, expected 1, got 0
+fail_compilation/diag8101.d(62): Error: none of the overloads of `f_1` are callable using argument types `()`
+fail_compilation/diag8101.d(35): Candidates are: `diag8101.f_1(int)`
+fail_compilation/diag8101.d(36): `diag8101.f_1(int, int)`
+fail_compilation/diag8101.d(63): Error: none of the overloads of `f_2` are callable using argument types `()`
+fail_compilation/diag8101.d(38): Candidates are: `diag8101.f_2(int)`
+fail_compilation/diag8101.d(39): `diag8101.f_2(int, int)`
+fail_compilation/diag8101.d(40): `diag8101.f_2(int, int, int)`
+fail_compilation/diag8101.d(41): `diag8101.f_2(int, int, int, int)`
+fail_compilation/diag8101.d(42): `diag8101.f_2(int, int, int, int, int)`
+fail_compilation/diag8101.d(43): `diag8101.f_2(int, int, int, int, int, int)`
fail_compilation/diag8101.d(63): ... (1 more, -v to show) ...
+fail_compilation/diag8101.d(65): Error: none of the overloads of template `diag8101.t_0` are callable using argument types `!()()`
+fail_compilation/diag8101.d(46): Candidate is: `t_0(T1)()`
+fail_compilation/diag8101.d(66): Error: none of the overloads of template `diag8101.t_1` are callable using argument types `!()()`
+fail_compilation/diag8101.d(48): Candidates are: `t_1(T1)()`
+fail_compilation/diag8101.d(49): `t_1(T1, T2)()`
+fail_compilation/diag8101.d(67): Error: none of the overloads of template `diag8101.t_2` are callable using argument types `!()()`
+fail_compilation/diag8101.d(51): Candidates are: `t_2(T1)()`
+fail_compilation/diag8101.d(52): `t_2(T1, T2)()`
+fail_compilation/diag8101.d(53): `t_2(T1, T2, T3)()`
+fail_compilation/diag8101.d(54): `t_2(T1, T2, T3, T4)()`
+fail_compilation/diag8101.d(55): `t_2(T1, T2, T3, T4, T5)()`
+fail_compilation/diag8101.d(56): `t_2(T1, T2, T3, T4, T5, T6)()`
+fail_compilation/diag8101.d(67): ... (1 more, -v to show) ...
---
*/
void f_2(int, int, int, int);
void f_2(int, int, int, int, int);
void f_2(int, int, int, int, int, int);
+void f_2(int, int, int, int, int, int, int);
void t_0(T1)();
void t_2(T1, T2, T3, T4)();
void t_2(T1, T2, T3, T4, T5)();
void t_2(T1, T2, T3, T4, T5, T6)();
+void t_2(T1, T2, T3, T4, T5, T6, T7)();
void main()
{
/*
TEST_OUTPUT:
---
-fail_compilation/diag9358.d(12): Error: `x` must be of integral or string type, it is a `double`
-fail_compilation/diag9358.d(14): Error: `case` must be a `string` or an integral constant, not `1.1`
-fail_compilation/diag9358.d(15): Error: `case` must be a `string` or an integral constant, not `2.1`
+fail_compilation/diag9358.d(13): Error: `x` must be of integral or string type, it is a `double`
+fail_compilation/diag9358.d(15): Error: `case` expression must be a compile-time `string` or an integral constant, not `1.1`
+fail_compilation/diag9358.d(16): Error: `case` expression must be a compile-time `string` or an integral constant, not `2.1`
+fail_compilation/diag9358.d(26): Error: `case` expression must be a compile-time `string` or an integral constant, not `z`
---
*/
void main()
default:
}
}
+
+void f(immutable string y)
+{
+ auto z = y[0..2];
+ switch (y)
+ {
+ case z: break;
+ default:
+ }
+}
/*
TEST_OUTPUT:
---
-fail_compilation/diag9679.d(11): Error: variable `diag9679.main.n` only parameters or `foreach` declarations can be `ref`
-fail_compilation/diag9679.d(12): Error: variable `diag9679.main.n` storage class `auto` has no effect if type is not inferred, did you mean `scope`?
+fail_compilation/diag9679.d(11): Error: variable `diag9679.main.n` - only parameters, functions and `foreach` declarations can be `ref`
+fail_compilation/diag9679.d(12): Error: variable `diag9679.main.n` - storage class `auto` has no effect if type is not inferred, did you mean `scope`?
---
*/
/*
-REQUIRED_ARGS: -de
+REQUIRED_ARGS:
TEST_OUTPUT:
---
-fail_compilation/dip25.d(17): Deprecation: returning `this.buffer[]` escapes a reference to parameter `this`
+fail_compilation/dip25.d(17): Error: returning `this.buffer[]` escapes a reference to parameter `this`
fail_compilation/dip25.d(15): perhaps annotate the function with `return`
fail_compilation/dip25.d(22): Error: returning `identity(x)` escapes a reference to parameter `x`
-fail_compilation/dip25.d(23): Deprecation: returning `identity(x)` escapes a reference to parameter `x`
+fail_compilation/dip25.d(23): Error: returning `identity(x)` escapes a reference to parameter `x`
fail_compilation/dip25.d(23): perhaps annotate the parameter with `return`
---
*/
--- /dev/null
+/*
+REQUIRED_ARGS: -de -dip25
+TEST_OUTPUT:
+---
+Deprecation: `-dip25` no longer has any effect
+---
+*/
TEST_OUTPUT:
---
fail_compilation/e15876_5.d(16): Error: basic type expected, not `End of File`
-fail_compilation/e15876_5.d(16): Error: semicolon expected to close `alias` declaration
+fail_compilation/e15876_5.d(16): Error: semicolon expected to close `alias` declaration, not `End of File`
fail_compilation/e15876_5.d(16): Error: found `End of File` when expecting `}` following compound statement
fail_compilation/e15876_5.d(16): Error: found `End of File` when expecting `]`
fail_compilation/e15876_5.d(16): Error: no identifier for declarator `p[()
---
fail_compilation/enum9921.d(9): Error: enum `enum9921.X` base type must not be `void`
fail_compilation/enum9921.d(11): Error: enum `enum9921.Z` base type must not be `void`
+fail_compilation/enum9921.d(13): Error: variable `enum9921.x` - manifest constants must have initializers
---
*/
-
enum X : void;
enum Z : void { Y };
+
+enum int x;
TEST_OUTPUT:
---
-fail_compilation/enum_init.d(306): Error: variable `enum_init.fooOB.ob` no definition of struct `S`
+fail_compilation/enum_init.d(306): Error: variable `enum_init.fooOB.ob` - no definition of struct `S`
fail_compilation/enum_init.d(302): required by type `OpaqueBase`
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/fail10102.d(48): Error: variable `fail10102.main.m` default construction is disabled for type `NotNull!(int*)`
-fail_compilation/fail10102.d(49): Error: variable `fail10102.main.a` default construction is disabled for type `NotNull!(int*)[3]`
+fail_compilation/fail10102.d(48): Error: variable `fail10102.main.m` - default construction is disabled for type `NotNull!(int*)`
+fail_compilation/fail10102.d(49): Error: variable `fail10102.main.a` - default construction is disabled for type `NotNull!(int*)[3]`
fail_compilation/fail10102.d(50): Error: default construction is disabled for type `NotNull!(int*)`
fail_compilation/fail10102.d(51): Error: field `S.m` must be initialized because it has no default constructor
---
/*
TEST_OUTPUT:
---
-fail_compilation/fail14406.d-mixin-20(20): Error: variable `fail14406.CFrop.bar_obj` cannot be further field because it will change the determined CFrop size
-fail_compilation/fail14406.d-mixin-25(25): Error: variable `fail14406.IFrop.bar_obj` field not allowed in interface
+fail_compilation/fail14406.d-mixin-20(20): Error: cannot declare field `bar_obj` because it will change the determined size of `CFrop`
+fail_compilation/fail14406.d-mixin-25(25): Error: field `bar_obj` not allowed in interface
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/fail155.d(20): Error: overlapping initialization for `y`
+fail_compilation/fail155.d(20): Error: overlapping initialization for field `x` and `y`
fail_compilation/fail155.d(20): `struct` initializers that contain anonymous unions must initialize only the first member of a `union`. All subsequent non-overlapping fields are default initialized
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/fail156.d(35): Error: overlapping initialization for `y`
+fail_compilation/fail156.d(35): Error: overlapping initialization for field `x` and `y`
fail_compilation/fail156.d(35): `struct` initializers that contain anonymous unions must initialize only the first member of a `union`. All subsequent non-overlapping fields are default initialized
-fail_compilation/fail156.d(42): Error: overlapping initialization for `y`
+fail_compilation/fail156.d(42): Error: overlapping initialization for field `x` and `y`
fail_compilation/fail156.d(42): `struct` initializers that contain anonymous unions must initialize only the first member of a `union`. All subsequent non-overlapping fields are default initialized
---
*/
fail_compilation/fail15616a.d(26): `fail15616a.foo(int a, int b, int c)`
fail_compilation/fail15616a.d(29): `fail15616a.foo(string a)`
fail_compilation/fail15616a.d(32): `fail15616a.foo(string a, string b)`
-fail_compilation/fail15616a.d(41): ... (3 more, -v to show) ...
+fail_compilation\fail15616a.d(35): `fail15616a.foo(string a, string b, string c)`
+fail_compilation/fail15616a.d(41): ... (2 more, -v to show) ...
---
*/
-
+#line 14
void foo(int a)
{}
--- /dev/null
+/*
+REQUIRED_ARGS: -verror-supplements=0
+TEST_OUTPUT:
+---
+fail_compilation/fail15616c.d(44): Error: none of the overloads of `foo` are callable using argument types `(double)`
+fail_compilation/fail15616c.d(17): Candidates are: `fail15616c.foo(int a)`
+fail_compilation/fail15616c.d(20): `fail15616c.foo(int a, int b)`
+fail_compilation/fail15616c.d(29): `fail15616c.foo(int a, int b, int c)`
+fail_compilation/fail15616c.d(32): `fail15616c.foo(string a)`
+fail_compilation/fail15616c.d(35): `fail15616c.foo(string a, string b)`
+fail_compilation/fail15616c.d(38): `fail15616c.foo(string a, string b, string c)`
+fail_compilation/fail15616c.d(23): `foo(T)(T a)`
+ with `T = double`
+ must satisfy the following constraint:
+` is(T == float)`
+fail_compilation/fail15616c.d(26): `foo(T)(T a)`
+ with `T = double`
+ must satisfy the following constraint:
+` is(T == char)`
+---
+*/
+
+#line 17
+void foo(int a)
+{}
+
+void foo(int a, int b)
+{}
+
+void foo(T)(T a) if (is(T == float))
+{}
+
+void foo(T)(T a) if (is(T == char))
+{}
+
+void foo(int a, int b, int c)
+{}
+
+void foo(string a)
+{}
+
+void foo(string a, string b)
+{}
+
+void foo(string a, string b, string c)
+{}
+
+
+void main()
+{
+ foo(3.14);
+}
--- /dev/null
+/*
+REQUIRED_ARGS: -verror-supplements=2
+TEST_OUTPUT:
+---
+fail_compilation/fail15616d.d(44): Error: none of the overloads of `foo` are callable using argument types `(double)`
+fail_compilation/fail15616d.d(17): Candidates are: `fail15616d.foo(int a)`
+fail_compilation/fail15616d.d(20): `fail15616d.foo(int a, int b)`
+fail_compilation/fail15616d.d(44): ... (6 more, -v to show) ...
+---
+*/
+
+#line 17
+void foo(int a)
+{}
+
+void foo(int a, int b)
+{}
+
+void foo(T)(T a) if (is(T == float))
+{}
+
+void foo(T)(T a) if (is(T == char))
+{}
+
+void foo(int a, int b, int c)
+{}
+
+void foo(string a)
+{}
+
+void foo(string a, string b)
+{}
+
+void foo(string a, string b, string c)
+{}
+
+
+void main()
+{
+ foo(3.14);
+}
/*
TEST_OUTPUT:
---
-fail_compilation/fail158.d(17): Error: more initializers than fields (2) of `S`
+fail_compilation/fail158.d(17): Error: too many initializers for `S` with 2 fields
---
*/
fail_compilation/fail17955.d(67): instantiated from here: `RedisStripped!(User, true)`
fail_compilation/fail17955.d(93): Error: need `this` for `fromISOExtString` of type `pure nothrow @nogc @safe immutable(SimpleTimeZone)(dstring _param_0)`
fail_compilation/fail17955.d(95): Error: undefined identifier `DateTimeException`
-fail_compilation/fail17955.d(25): Error: variable `fail17955.isISOExtStringSerializable!(SysTime).isISOExtStringSerializable` type `void` is inferred from initializer `fromISOExtString("")`, and variables cannot be of type `void`
+fail_compilation/fail17955.d(25): Error: variable `fail17955.isISOExtStringSerializable!(SysTime).isISOExtStringSerializable` - type `void` is inferred from initializer `fromISOExtString("")`, and variables cannot be of type `void`
fail_compilation/fail17955.d(54): Error: function `fail17955.toRedis!(SysTime).toRedis` has no `return` statement, but is expected to return a value of type `string`
---
*/
interface P { }
interface I : P { }
-auto F = __traits(getVirtualFunctions, I, "V");
+auto F = __traits(getVirtualMethods, I, "V");
fail_compilation/fail21243.d(18): Error: basic type expected, not `(`
fail_compilation/fail21243.d(18): Error: function declaration without return type. (Note that constructors are always named `this`)
fail_compilation/fail21243.d(18): Deprecation: storage class `auto` has no effect in type aliases
-fail_compilation/fail21243.d(18): Error: semicolon expected to close `alias` declaration
+fail_compilation/fail21243.d(18): Error: semicolon expected to close `alias` declaration, not `=>`
fail_compilation/fail21243.d(18): Error: declaration expected, not `=>`
fail_compilation/fail21243.d(19): Error: `auto` can only be used as part of `auto ref` for function literal return values
---
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=22039
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail22039.d(11): Error: recursive evaluation of `func()`
+fail_compilation/fail22039.d(14): Error: recursive evaluation of `gun(func2())`
+---
+*/
+
+int func(int x = func()) { return x; }
+
+int gun() { return 2; }
+int func2(int x = gun(func2())) { return x; }
/*
TEST_OUTPUT:
---
-fail_compilation/fail22570.d(19): Error: more initializers than fields (1) of `S`
-fail_compilation/fail22570.d(20): Error: more initializers than fields (1) of `S`
+fail_compilation/fail22570.d(19): Error: too many initializers for `S` with 1 field
+fail_compilation/fail22570.d(20): Error: too many initializers for `S` with 1 field
---
*/
+++ /dev/null
-// REQUIRED_ARGS: -o-
-/*
-TEST_OUTPUT:
----
-fail_compilation/fail233.d(11): Error: variable `fail233.bug1176.v` `void[1]` does not have a default initializer
----
-*/
-
-void bug1176()
-{
- void[1] v;
-}
--- /dev/null
+/* TEST_OUTPUT:
+---
+fail_compilation/fail23626a.d(10): Deprecation: function `fail23626a.ambig` cannot overload `extern(D)` function at fail_compilation/fail23626a.d(9)
+fail_compilation/fail23626a.d(13): Deprecation: function `fail23626a.ambigC` cannot overload `extern(C)` function at fail_compilation/fail23626a.d(12)
+fail_compilation/fail23626a.d(16): Error: function `fail23626a.ambigCxx(int a)` conflicts with previous declaration at fail_compilation/fail23626a.d(15)
+---
+*/
+
+extern(D) int ambig(int a) { return 0; }
+extern(D) int ambig(int a) @system { return 1; }
+
+extern(C) int ambigC(int a) { return 2; }
+extern(C) int ambigC(int a) @system { return 3; }
+
+extern(C++) int ambigCxx(int a) { return 4; }
+extern(C++) int ambigCxx(int a) @system { return 5; }
--- /dev/null
+/* TEST_OUTPUT:
+---
+fail_compilation/fail23626b.d(26): Error: `fail23626b.AmbigOpApply.opApply` called with argument types `(int delegate(int i) pure nothrow @nogc @system)` matches both:
+fail_compilation/fail23626b.d(12): `fail23626b.AmbigOpApply.opApply(int delegate(int) dg)`
+and:
+fail_compilation/fail23626b.d(17): `fail23626b.AmbigOpApply.opApply(int delegate(int) dg)`
+---
+*/
+
+struct AmbigOpApply
+{
+ int opApply(int delegate(int) dg)
+ {
+ return 0;
+ }
+
+ int opApply(int delegate(int) dg) @system
+ {
+ return 0;
+ }
+}
+
+void ambigOpApply() @system
+{
+ AmbigOpApply sa;
+ foreach (int i; sa) { }
+}
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=2374
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail23745.d(21): Error: undefined identifier `UndefinedType`
+fail_compilation/fail23745.d(14): Error: function `fun` does not override any function, did you mean to override `fail23745.A.fun`?
+fail_compilation/fail23745.d(21): Function `fail23745.A.fun` contains errors in its declaration, therefore it cannot be correctly overriden
+---
+*/
+
+class B : A
+{
+ override void fun()
+ {
+ }
+}
+
+class A
+{
+ void fun(UndefinedType);
+}
/*
TEST_OUTPUT:
---
-fail_compilation/fail253.d(13): Error: variable `fail253.main.x` `inout` variables can only be declared inside `inout` functions
+fail_compilation/fail253.d(13): Error: variable `fail253.main.x` - `inout` variables can only be declared inside `inout` functions
fail_compilation/fail253.d(16): Error: cannot modify `inout` expression `x`
+fail_compilation/fail253.d(19): Error: variable `fail253.main.err11` - `inout` variables can only be declared inside `inout` functions
---
*/
-
void main()
{
foreach (i; 0 .. 2)
x = '?';
}
}
+ inout(int)* err11;
}
/*
TEST_OUTPUT:
---
-fail_compilation/fail299.d(14): Error: more initializers than fields (0) of `Foo`
+fail_compilation/fail299.d(14): Error: initializer provided for struct `Foo` with no fields
---
*/
unittest
{
struct TestType {}
- MinHeap!(TestType) foo = new MinHeap!(TestType)();
+ MinHeap!(TestType) foo;
}
}
TEST_OUTPUT:
---
fail_compilation/fail346.d(15): Error: undefined identifier `P`
-fail_compilation/fail346.d(15): Error: variable `fail346.S.T!0.T` cannot use template to add field to aggregate `S`
+fail_compilation/fail346.d(15): Error: variable `fail346.S.T!0.T` - cannot use template to add field to aggregate `S`
fail_compilation/fail346.d(20): Error: template instance `fail346.S.T!0` error instantiating
fail_compilation/fail346.d(23): instantiated from here: `V!(S, 0)`
---
TEST_OUTPUT:
---
fail_compilation/fail4269a.d(12): Error: undefined identifier `B`
-fail_compilation/fail4269a.d(12): Error: variable `fail4269a.A.blah` field not allowed in interface
+fail_compilation/fail4269a.d(12): Error: field `blah` not allowed in interface
fail_compilation/fail4269a.d(13): Error: undefined identifier `B`
---
*/
+++ /dev/null
-/*
-TEST_OUTPUT:
----
-fail_compilation/fail5851.d(11): Error: alias this is not reachable as `Foo` already converts to `object.Object`
----
-*/
-
-class Foo
-{
- Object o;
- alias o this;
-}
-
-void main()
-{
-}
fail_compilation/fail_scope.d(82): Error: returning `& string` escapes a reference to local variable `string`
fail_compilation/fail_scope.d(92): Error: returning `cast(int[])a` escapes a reference to local variable `a`
fail_compilation/fail_scope.d(100): Error: returning `cast(int[])a` escapes a reference to local variable `a`
-fail_compilation/fail_scope.d(108): Deprecation: escaping reference to outer local variable `x`
+fail_compilation/fail_scope.d(108): Error: escaping reference to outer local variable `x`
fail_compilation/fail_scope.d(127): Deprecation: returning `s.bar()` escapes a reference to local variable `s`
fail_compilation/fail_scope.d(137): Error: returning `foo16226(i)` escapes a reference to local variable `i`
---
/*
TEST_OUTPUT:
---
-fail_compilation/failinout2.d(7): Error: variable `failinout2.x` only parameters or stack based variables can be `inout`
+fail_compilation/failinout2.d(8): Error: variable `failinout2.x` - only parameters or stack-based variables can be `inout`
+fail_compilation/failinout2.d(12): Error: variable `failinout2.S3748.err8` - only parameters or stack-based variables can be `inout`
---
*/
inout int x;
+
+struct S3748
+{
+ inout(int) err8;
+}
+++ /dev/null
-/*
-TEST_OUTPUT:
----
-fail_compilation/failinout3748a.d(9): Error: variable `failinout3748a.S3748.err8` only parameters or stack based variables can be `inout`
----
-*/
-struct S3748
-{
- inout(int) err8;
-}
+++ /dev/null
-/*
-TEST_OUTPUT:
----
-fail_compilation/failinout3748b.d(9): Error: variable `failinout3748b.main.err11` `inout` variables can only be declared inside `inout` functions
----
-*/
-void main()
-{
- inout(int)* err11;
-}
REQUIRED_ARGS:-preview=dip1021
TEST_OUTPUT:
---
-fail_compilation/failob1.d(104): Error: variable `failob1.test1.a1` is left dangling at return
-fail_compilation/failob1.d(105): Error: variable `failob1.test2.a2` is left dangling at return
-fail_compilation/failob1.d(107): Error: variable `failob1.test4.s4` is left dangling at return
-fail_compilation/failob1.d(108): Error: variable `failob1.test5.dg5` is left dangling at return
-fail_compilation/failob1.d(115): Error: variable `failob1.test12.p12` is left dangling at return
+fail_compilation/failob1.d(104): Error: variable `failob1.test1.a1` is not disposed of before return
+fail_compilation/failob1.d(105): Error: variable `failob1.test2.a2` is not disposed of before return
+fail_compilation/failob1.d(107): Error: variable `failob1.test4.s4` is not disposed of before return
+fail_compilation/failob1.d(108): Error: variable `failob1.test5.dg5` is not disposed of before return
+fail_compilation/failob1.d(115): Error: variable `failob1.test12.p12` is not disposed of before return
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/failob2.d(205): Error: variable `failob2.foo4!int.foo4.p` is left dangling at return
+fail_compilation/failob2.d(205): Error: variable `failob2.foo4!int.foo4.p` is not disposed of before return
fail_compilation/failob2.d(209): Error: template instance `failob2.foo4!int` error instantiating
---
*/
--- /dev/null
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fnconstraint.d(13): Error: template constraint must follow parameter lists and attributes
+fail_compilation/fnconstraint.d(13): Error: declaration expected, not `if`
+fail_compilation/fnconstraint.d(22): Error: template constraint must follow parameter lists and attributes
+fail_compilation/fnconstraint.d(22): Error: declaration expected, not `if`
+fail_compilation/fnconstraint.d(26): Error: `}` expected following members in `struct` declaration at fail_compilation/fnconstraint.d(18)
+---
+*/
+void foo()()
+in(true)
+if (true)
+{}
+
+alias f = foo!();
+
+struct S
+{
+ this()()
+ if (true)
+ if (true) {}
+}
+
+S s;
/* TEST_OUTPUT:
---
fail_compilation/fob1.d(204): Error: variable `fob1.foo2.p` assigning to Owner without disposing of owned value
-fail_compilation/fob1.d(203): Error: variable `fob1.foo2.p` is left dangling at return
+fail_compilation/fob1.d(203): Error: variable `fob1.foo2.p` is not disposed of before return
---
*/
---
fail_compilation/fob1.d(304): Error: variable `fob1.foo3.p` has undefined state and cannot be read
fail_compilation/fob1.d(304): Error: variable `fob1.foo3.p` is returned but is Undefined
-fail_compilation/fob1.d(303): Error: variable `fob1.foo3.q` is left dangling at return
+fail_compilation/fob1.d(303): Error: variable `fob1.foo3.q` is not disposed of before return
---
*/
*bq = 1;
return p;
}
+
+/* TEST_OUTPUT:
+---
+fail_compilation/fob1.d(503): Error: more than one mutable reference to `a` in arguments to `fob1.foo5()`
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=20781
+
+#line 500
+
+void test5() {
+ int a;
+ foo5(a, a);
+}
+
+@live void foo5(ref int, ref int);
/* TEST_OUTPUT:
---
fail_compilation/fob2.d(110): Error: variable `fob2.foo1.b1` has undefined state and cannot be read
-fail_compilation/fob2.d(103): Error: variable `fob2.foo1.p` is left dangling at return
+fail_compilation/fob2.d(103): Error: variable `fob2.foo1.p` is not disposed of before return
---
*/
/* TEST_OUTPUT:
---
-fail_compilation/fob2.d(203): Error: variable `fob2.zoo2.p` is passed as Owner more than once
-fail_compilation/fob2.d(202): Error: variable `fob2.zoo2.p` is left dangling at return
+fail_compilation/fob2.d(203): Error: more than one mutable reference of `p` in arguments to `fob2.foo2()`
---
*/
+//fail_compilation/fob2.d(203): Error: variable `fob2.zoo2.p` is passed as Owner more than once
+//fail_compilation/fob2.d(202): Error: variable `fob2.zoo2.p` is left dangling at return
+
#line 200
@live void zoo2() {
/* TEST_OUTPUT:
---
-fail_compilation/fob2.d(303): Error: variable `fob2.foo3.b` is left dangling at return
+fail_compilation/fob2.d(303): Error: variable `fob2.foo3.b` is not disposed of before return
---
*/
/* TEST_OUTPUT:
---
-fail_compilation/fob2.d(603): Error: variable `fob2.test6.p` is left dangling at return
+fail_compilation/fob2.d(603): Error: variable `fob2.test6.p` is not disposed of before return
+fail_compilation/fob2.d(612): Error: more than one mutable reference of `p` in arguments to `fob2.foo6b()`
---
*/
TEST_OUTPUT:
---
fail_compilation/gag4269f.d(11): Error: undefined identifier `Y9`, did you mean interface `X9`?
-fail_compilation/gag4269f.d(11): Error: variable `gag4269f.X9.y` field not allowed in interface
+fail_compilation/gag4269f.d(11): Error: field `y` not allowed in interface
---
*/
/*
TEST_OUTPUT:
----
+fail_compilation/ice12727.d(16): Error: template instance `IndexTuple!(1, 0)` recursive template expansion
fail_compilation/ice12727.d(16): Error: alias `ice12727.IndexTuple!(1, 0).IndexTuple` recursive alias declaration
fail_compilation/ice12727.d(23): Error: template instance `ice12727.IndexTuple!(1, 0)` error instantiating
fail_compilation/ice12727.d(27): instantiated from here: `Matrix!(float, 3)`
fail_compilation/ice12727.d(28): instantiated from here: `Vector!(float, 3)`
----
*/
-
template IndexTuple(int e, int s = 0, T...)
{
static if (s == e)
/*
TEST_OUTPUT:
---
-fail_compilation/ice12902.d(20): Error: variable `ice12902.main.__dollar` type `void` is inferred from initializer `s.opDollar()`, and variables cannot be of type `void`
+fail_compilation/ice12902.d(20): Error: variable `ice12902.main.__dollar` - type `void` is inferred from initializer `s.opDollar()`, and variables cannot be of type `void`
fail_compilation/ice12902.d(20): Error: expression `s.opDollar()` is `void` and has no value
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/ice13788.d(11): Error: pragma `mangle` string expected for mangled name
+fail_compilation/ice13788.d(11): Error: pragma `mangle` - string expected for mangled name
fail_compilation/ice13788.d(12): Error: `string` expected for mangled name, not `(1)` of type `int`
-fail_compilation/ice13788.d(13): Error: pragma `mangle` zero-length string not allowed for mangled name
-fail_compilation/ice13788.d(14): Error: pragma `mangle` mangled name characters can only be of type `char`
+fail_compilation/ice13788.d(13): Error: pragma `mangle` - zero-length string not allowed for mangled name
+fail_compilation/ice13788.d(14): Error: pragma `mangle` - mangled name characters can only be of type `char`
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/ice13816.d(15): Error: alias `ice13816.ItemProperty!().ItemProperty` recursive alias declaration
-fail_compilation/ice13816.d(20): Error: template instance `ice13816.ItemProperty!()` error instantiating
+fail_compilation/ice13816.d(17): Error: template instance `TypeTuple!(ItemProperty!())` recursive template expansion
+fail_compilation/ice13816.d(17): Error: alias `ice13816.ItemProperty!().ItemProperty` recursive alias declaration
+fail_compilation/ice13816.d(22): Error: template instance `ice13816.ItemProperty!()` error instantiating
---
*/
+
alias TypeTuple(T...) = T;
template ItemProperty()
/*
TEST_OUTPUT:
---
-fail_compilation/ice18753.d(21): Error: variable `ice18753.isInputRange!(Group).isInputRange` type `void` is inferred from initializer `ReturnType(func...)`, and variables cannot be of type `void`
+fail_compilation/ice18753.d(21): Error: variable `ice18753.isInputRange!(Group).isInputRange` - type `void` is inferred from initializer `ReturnType(func...)`, and variables cannot be of type `void`
fail_compilation/ice18753.d(23): Error: template instance `ice18753.isInputRange!(Group)` error instantiating
fail_compilation/ice18753.d(18): instantiated from here: `isForwardRange!(Group)`
fail_compilation/ice18753.d(18): while evaluating: `static assert(isForwardRange!(Group))`
/*
TEST_OUTPUT:
---
-fail_compilation/ice23569.d(18): Error: cannot compare classes for equality because `object.Object` was not declared
+fail_compilation/ice23569.d(24): Error: cannot compare classes for equality because `object.Object` was not declared
---
*/
module object;
+T _d_newclassT(T)()
+if (is(T == class))
+{
+ return null;
+}
+
@safe unittest1()
{
class F
TEST_OUTPUT:
---
fail_compilation/issue16020.d(12): Error: user-defined attributes not allowed for `alias` declarations
-fail_compilation/issue16020.d(13): Error: semicolon expected to close `alias` declaration
+fail_compilation/issue16020.d(13): Error: semicolon expected to close `alias` declaration, not `(`
fail_compilation/issue16020.d(13): Error: declaration expected, not `(`
---
*/
--- /dev/null
+/*
+TEST_OUTPUT:
+---
+fail_compilation/named_arguments_error.d(32): Error: function `named_arguments_error.f(int x, int y, int z)` is not callable using argument types `(int, int, int)`
+fail_compilation/named_arguments_error.d(32): parameter `x` assigned twice
+fail_compilation/named_arguments_error.d(33): Error: function `named_arguments_error.f(int x, int y, int z)` is not callable using argument types `(int, int, int)`
+fail_compilation/named_arguments_error.d(33): argument `4` goes past end of parameter list
+fail_compilation/named_arguments_error.d(34): Error: function `named_arguments_error.f(int x, int y, int z)` is not callable using argument types `(int, int, int)`
+fail_compilation/named_arguments_error.d(34): parameter `y` assigned twice
+fail_compilation/named_arguments_error.d(35): Error: function `named_arguments_error.f(int x, int y, int z)` is not callable using argument types `(int, int, int)`
+fail_compilation/named_arguments_error.d(35): no parameter named `a`
+fail_compilation/named_arguments_error.d(36): Error: function `named_arguments_error.g(int x, int y, int z = 3)` is not callable using argument types `(int, int)`
+fail_compilation/named_arguments_error.d(36): missing argument for parameter #1: `int x`
+fail_compilation/named_arguments_error.d(38): Error: no named argument `element` allowed for array dimension
+fail_compilation/named_arguments_error.d(39): Error: no named argument `number` allowed for scalar
+fail_compilation/named_arguments_error.d(40): Error: cannot implicitly convert expression `g(x: 3, y: 4, z: 5)` of type `int` to `string`
+fail_compilation/named_arguments_error.d(41): Error: named arguments with Implicit Function Template Instantiation are not supported yet
+fail_compilation/named_arguments_error.d(41): Error: none of the overloads of template `named_arguments_error.tempfun` are callable using argument types `!()(string, int)`
+fail_compilation/named_arguments_error.d(45): Candidate is: `tempfun(T, U)(T t, U u)`
+---
+*/
+
+
+
+
+void f(int x, int y, int z);
+
+int g(int x, int y, int z = 3);
+
+void main()
+{
+ f(x: 3, x: 3, 5);
+ f(z: 3, 4, 5);
+ f(y: 3, x: 4, 5);
+ f(a: 3, b: 4, 5);
+ g(y: 4, z: 3);
+
+ auto g0 = new int[](element: 3);
+ auto g1 = new int(number: 3);
+ string s = g(x: 3, y: 4, z: 5);
+ enum x = tempfun(u: "u", t: 0);
+}
+
+// template arguments
+int tempfun(T, U)(T t, U u)
+{
+ return 3;
+}
--- /dev/null
+/**
+TEST_OUTPUT:
+---
+fail_compilation/named_arguments_overload.d(33): Error: none of the overloads of `snoopy` are callable using argument types `(immutable(S), immutable(T))`
+fail_compilation/named_arguments_overload.d(17): Candidates are: `named_arguments_overload.snoopy(S s, int i = 0, T t = T())`
+fail_compilation/named_arguments_overload.d(18): `named_arguments_overload.snoopy(T t, int i, S s)`
+fail_compilation/named_arguments_overload.d(34): Error: none of the overloads of `snoopy` are callable using argument types `(immutable(T), immutable(S))`
+fail_compilation/named_arguments_overload.d(17): Candidates are: `named_arguments_overload.snoopy(S s, int i = 0, T t = T())`
+fail_compilation/named_arguments_overload.d(18): `named_arguments_overload.snoopy(T t, int i, S s)`
+fail_compilation/named_arguments_overload.d(35): Error: `named_arguments_overload.snoopy` called with argument types `(immutable(S), immutable(T), immutable(int))` matches both:
+fail_compilation/named_arguments_overload.d(17): `named_arguments_overload.snoopy(S s, int i = 0, T t = T())`
+and:
+fail_compilation/named_arguments_overload.d(18): `named_arguments_overload.snoopy(T t, int i, S s)`
+---
+*/
+
+char snoopy(S s, int i = 0, T t = T.init) { return 'B'; }
+char snoopy(T t, int i, S s) { return 'A'; }
+
+struct S { }
+struct T { }
+immutable S s = S.init;
+immutable T t = T.init;
+immutable int i = 0;
+
+static assert(snoopy(t, i, s ) == 'A');
+static assert(snoopy(s, i, t ) == 'B');
+static assert(snoopy(s:s, t:t ) == 'B');
+static assert(snoopy(t:t, s:s ) == 'B');
+static assert(snoopy(t:t, i, s:s) == 'A');
+static assert(snoopy(s:s, t:t, i ) == 'A');
+
+immutable err0 = snoopy(s, t); // error, neither A nor B match
+immutable err1 = snoopy(t, s); // error, neither A nor B match
+immutable err2 = snoopy(s:s, t:t, i:i); // error, ambiguous
--- /dev/null
+/**
+TEST_OUTPUT:
+---
+fail_compilation/named_arguments_parse.d(10): Error: named arguments not allowed here
+fail_compilation/named_arguments_parse.d(13): Error: named arguments not allowed here
+fail_compilation/named_arguments_parse.d(14): Error: named arguments not allowed here
+---
+*/
+
+@(attribute: 3)
+void main()
+{
+ mixin(thecode: "{}");
+ pragma(msg, themsg: "hello");
+}
/* TEST_OUTPUT:
---
-fail_compilation/retscope6.d(9022): Error: returning `fred(& i)` escapes a reference to local variable `i`
+fail_compilation/retscope6.d(9023): Error: returning `fred(& i)` escapes a reference to local variable `i`
---
*/
#line 9000
-@safe:
+@safe
+{
alias T9 = S9!(); struct S9()
{
ubyte[10] buffer;
secret = buffer[];
}
+}
/* TEST_OUTPUT:
---
// ensure we do not infer return ref
return infer23021(nonScopePtr); // no error
}
+
+/******************************/
fail_compilation/shared.d(2154): Error: direct access to shared `*c.c1` is not allowed, see `core.atomic`
fail_compilation/shared.d(2160): Error: direct access to shared `*c.c1.c1` is not allowed, see `core.atomic`
fail_compilation/shared.d(2181): Error: direct access to shared `k` is not allowed, see `core.atomic`
-fail_compilation/shared.d(2187): Error: direct access to shared `k.k2.k1` is not allowed, see `core.atomic`
+fail_compilation/shared.d(2187): Error: direct access to shared `k.k2.k1.value` is not allowed, see `core.atomic`
fail_compilation/shared.d(2194): Error: direct access to shared `(new shared(K2)).k1` is not allowed, see `core.atomic`
fail_compilation/shared.d(2202): Error: direct access to shared `c` is not allowed, see `core.atomic`
fail_compilation/shared.d(2206): Error: function `shared.test_inference_2` function returns `shared` but cannot be inferred `ref`
this.bits++;
}
}
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/shared.d(3004): Error: cast from `void*` to `shared(int*)` not allowed in safe code
+fail_compilation/shared.d(3005): Error: cast from `void*` to `shared(const(int*))` not allowed in safe code
+fail_compilation/shared.d(3008): Error: cast from `shared(void*)` to `int*` not allowed in safe code
+fail_compilation/shared.d(3009): Error: cast from `shared(void*)` to `shared(const(int*))` not allowed in safe code
+---
+*/
+
+#line 3000
+
+void test_casting_safe() @safe
+{
+ void *p;
+ auto t1 = cast(shared(int*))p;
+ auto t2 = cast(const(shared(int*)))p;
+
+ shared void* s;
+ auto x1 = cast(int*)s;
+ auto x2 = cast(const(shared(int*)))s;
+}
--- /dev/null
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test15368.d(13): Error: cannot declare `auto` loop variable, omit `auto` to still get type inference
+---
+*/
+
+// Issue 15368 - Improve error message for "auto" keyword inside "foreach"
+// https://issues.dlang.org/show_bug.cgi?id=15368
+
+void main()
+{
+ foreach (auto e; foo) { }
+}
--- /dev/null
+/* TEST_OUTPUT:
+---
+fail_compilation/test16495.d(12): Error: undefined identifier `q`
+fail_compilation/test16495.d(17): Error: expected 1 arguments for `fullyQualifiedName` but had 0
+---
+ */
+
+// https://issues.dlang.org/show_bug.cgi?id=16495
+
+void test1()
+{
+ auto m = __traits(fullyQualifiedName, q);
+}
+
+void test2()
+{
+ auto n = __traits(fullyQualifiedName);
+}
/* TEST_OUTPUT:
---
-fail_compilation/test17096.d(28): Error: expected 1 arguments for `isPOD` but had 2
-fail_compilation/test17096.d(29): Error: expected 1 arguments for `isNested` but had 2
-fail_compilation/test17096.d(30): Error: expected 1 arguments for `isVirtualFunction` but had 2
-fail_compilation/test17096.d(31): Error: expected 1 arguments for `isVirtualMethod` but had 2
-fail_compilation/test17096.d(32): Error: expected 1 arguments for `isAbstractFunction` but had 2
-fail_compilation/test17096.d(33): Error: expected 1 arguments for `isFinalFunction` but had 2
-fail_compilation/test17096.d(34): Error: expected 1 arguments for `isOverrideFunction` but had 2
-fail_compilation/test17096.d(35): Error: expected 1 arguments for `isStaticFunction` but had 2
-fail_compilation/test17096.d(36): Error: expected 1 arguments for `isRef` but had 2
-fail_compilation/test17096.d(37): Error: expected 1 arguments for `isOut` but had 2
-fail_compilation/test17096.d(38): Error: expected 1 arguments for `isLazy` but had 2
-fail_compilation/test17096.d(39): Error: expected 1 arguments for `identifier` but had 2
-fail_compilation/test17096.d(40): Error: expected 1 arguments for `getProtection` but had 2
-fail_compilation/test17096.d(41): Error: expected 1 arguments for `parent` but had 2
-fail_compilation/test17096.d(42): Error: expected 1 arguments for `classInstanceSize` but had 2
-fail_compilation/test17096.d(43): Error: expected 1 arguments for `allMembers` but had 2
-fail_compilation/test17096.d(44): Error: expected 1 arguments for `derivedMembers` but had 2
-fail_compilation/test17096.d(45): Error: expected 1 arguments for `getAliasThis` but had 2
-fail_compilation/test17096.d(46): Error: expected 1 arguments for `getAttributes` but had 2
-fail_compilation/test17096.d(47): Error: expected 1 arguments for `getFunctionAttributes` but had 2
-fail_compilation/test17096.d(48): Error: expected 1 arguments for `getUnitTests` but had 2
-fail_compilation/test17096.d(49): Error: expected 1 arguments for `getVirtualIndex` but had 2
-fail_compilation/test17096.d(50): Error: a single type expected for trait pointerBitmap
+fail_compilation/test17096.d(29): Error: expected 1 arguments for `isPOD` but had 2
+fail_compilation/test17096.d(30): Error: expected 1 arguments for `isNested` but had 2
+fail_compilation/test17096.d(31): Deprecation: `traits(isVirtualFunction)` is deprecated. Use `traits(isVirtualMethod)` instead
+fail_compilation/test17096.d(31): Error: expected 1 arguments for `isVirtualFunction` but had 2
+fail_compilation/test17096.d(32): Error: expected 1 arguments for `isVirtualMethod` but had 2
+fail_compilation/test17096.d(33): Error: expected 1 arguments for `isAbstractFunction` but had 2
+fail_compilation/test17096.d(34): Error: expected 1 arguments for `isFinalFunction` but had 2
+fail_compilation/test17096.d(35): Error: expected 1 arguments for `isOverrideFunction` but had 2
+fail_compilation/test17096.d(36): Error: expected 1 arguments for `isStaticFunction` but had 2
+fail_compilation/test17096.d(37): Error: expected 1 arguments for `isRef` but had 2
+fail_compilation/test17096.d(38): Error: expected 1 arguments for `isOut` but had 2
+fail_compilation/test17096.d(39): Error: expected 1 arguments for `isLazy` but had 2
+fail_compilation/test17096.d(40): Error: expected 1 arguments for `identifier` but had 2
+fail_compilation/test17096.d(41): Error: expected 1 arguments for `getProtection` but had 2
+fail_compilation/test17096.d(42): Error: expected 1 arguments for `parent` but had 2
+fail_compilation/test17096.d(43): Error: expected 1 arguments for `classInstanceSize` but had 2
+fail_compilation/test17096.d(44): Error: expected 1 arguments for `allMembers` but had 2
+fail_compilation/test17096.d(45): Error: expected 1 arguments for `derivedMembers` but had 2
+fail_compilation/test17096.d(46): Error: expected 1 arguments for `getAliasThis` but had 2
+fail_compilation/test17096.d(47): Error: expected 1 arguments for `getAttributes` but had 2
+fail_compilation/test17096.d(48): Error: expected 1 arguments for `getFunctionAttributes` but had 2
+fail_compilation/test17096.d(49): Error: expected 1 arguments for `getUnitTests` but had 2
+fail_compilation/test17096.d(50): Error: expected 1 arguments for `getVirtualIndex` but had 2
+fail_compilation/test17096.d(51): Error: a single type expected for trait pointerBitmap
---
*/
enum b03 = __traits(isPOD, 1, 2);
---
fail_compilation/test17451.d(22): Error: undefined identifier `allocator`
fail_compilation/test17451.d(23): Error: `false` has no effect
-fail_compilation/test17451.d(30): Error: variable `test17451.HashMap!(ThreadSlot).HashMap.__lambda2.v` size of type `ThreadSlot` is invalid
+fail_compilation/test17451.d(30): Error: variable `test17451.HashMap!(ThreadSlot).HashMap.__lambda2.v` - size of type `ThreadSlot` is invalid
fail_compilation/test17451.d(44): Error: template instance `test17451.HashMap!(ThreadSlot)` error instantiating
---
*/
/*
TEST_OUTPUT:
----
-fail_compilation/test20549.d(12): Error: variable `test.__a_field_0` variables cannot be of type `void`
+fail_compilation/test20549.d(12): Error: variable `test.__a_field_0` - variables cannot be of type `void`
----
*/
/* TEST_OUTPUT:
---
fail_compilation/test20719.d(13): Error: struct `test20719.SumType` no size because of forward reference
-fail_compilation/test20719.d(32): Error: variable `test20719.isCopyable!(SumType).__lambda2.foo` size of type `SumType` is invalid
+fail_compilation/test20719.d(32): Error: variable `test20719.isCopyable!(SumType).__lambda2.foo` - size of type `SumType` is invalid
fail_compilation/test20719.d(18): Error: template instance `test20719.isCopyable!(SumType)` error instantiating
---
*/
/*
-REQUIRED_ARGS: -de
+REQUIRED_ARGS:
TEST_OUTPUT:
---
-fail_compilation/test20809.d(114): Deprecation: returning `this.a` escapes a reference to parameter `this`
+fail_compilation/test20809.d(114): Error: returning `this.a` escapes a reference to parameter `this`
fail_compilation/test20809.d(112): perhaps annotate the function with `return`
---
*/
fail_compilation/test20998.d(76): Error: undefined identifier `invalid`
X x = { invalid, 2, "asd" };
^
-fail_compilation/test20998.d(76): Error: too many initializers for `X`
+fail_compilation/test20998.d(76): Error: too many initializers for `X` with 2 fields
X x = { invalid, 2, "asd" };
^
fail_compilation/test20998.d(83): Error: cannot implicitly convert expression `"a"` of type `string` to `int`
fail_compilation/test20998.d(83): Error: duplicate initializer for field `ptr`
X2 x2 = { ptr: null, "a", ptr: 2, 444 };
^
-fail_compilation/test20998.d(83): Error: too many initializers for `X2`
+fail_compilation/test20998.d(83): Error: too many initializers for `X2` with 3 fields
X2 x2 = { ptr: null, "a", ptr: 2, 444 };
^
fail_compilation/test20998.d(90): Error: overlapping initialization for field `ptr` and `x`
fail_compilation/test20998.d(90): Error: duplicate initializer for field `ptr`
X3 x3 = { ptr: null, "a", ptr: 2, 444 };
^
-fail_compilation/test20998.d(90): Error: too many initializers for `X3`
+fail_compilation/test20998.d(90): Error: too many initializers for `X3` with 3 fields
X3 x3 = { ptr: null, "a", ptr: 2, 444 };
^
fail_compilation/test20998.d(98): Error: field `X4.ptr` cannot assign to misaligned pointers in `@safe` code
fail_compilation/test20998.d(98): Error: cannot implicitly convert expression `"a"` of type `string` to `int`
X4 x4 = { ptr: null, "a", 444, ptr: 2, true };
^
-fail_compilation/test20998.d(98): Error: too many initializers for `X4`
+fail_compilation/test20998.d(98): Error: too many initializers for `X4` with 2 fields
X4 x4 = { ptr: null, "a", 444, ptr: 2, true };
^
fail_compilation/test20998.d(102): called from here: `test()`
fail_compilation/test20998.d(104): Error: duplicate initializer for field `ptr`
X2 a5 = { ptr: 1, ptr: 2, ptr: 444, ptr: 555 };
^
-fail_compilation/test20998.d(104): Error: too many initializers for `X2`
+fail_compilation/test20998.d(104): Error: too many initializers for `X2` with 3 fields
X2 a5 = { ptr: 1, ptr: 2, ptr: 444, ptr: 555 };
^
-fail_compilation/test20998.d(107): Error: too many initializers for `X2`
+fail_compilation/test20998.d(107): Error: too many initializers for `X2` with 3 fields
X2 c6 = { null, 2, true, null };
^
fail_compilation/test20998.d(116): Error: cannot implicitly convert expression `1` of type `int` to `immutable(char*)`
immutable Struct iStruct = {1, &ch};
^
-fail_compilation/test20998.d(116): Error: too many initializers for `Struct`
+fail_compilation/test20998.d(116): Error: too many initializers for `Struct` with 1 field
immutable Struct iStruct = {1, &ch};
^
fail_compilation/test20998.d(120): called from here: `test2()`
+++ /dev/null
-// https://issues.dlang.org/show_bug.cgi?id=22593
-
-/*
-TEST_OUTPUT:
----
-fail_compilation/test22593.d(14): Error: cannot define both an rvalue constructor and a copy constructor for `struct Foo`
-fail_compilation/test22593.d(22): Template instance `__ctor!(immutable(Foo!int), immutable(Foo!int))` creates a rvalue constructor for `struct Foo`
-fail_compilation/test22593.d(22): Error: template instance `test22593.Foo!int.Foo.__ctor!(immutable(Foo!int), immutable(Foo!int))` error instantiating
----
-*/
-
-struct Foo(T)
-{
- this(Rhs, this This)(scope Rhs rhs){}
-
- this(ref scope typeof(this) rhs){}
-}
-
-void main()
-{
- immutable Foo!int a;
- a.__ctor(a);
-}
--- /dev/null
+//https://issues.dlang.org/show_bug.cgi?id=23607
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test23607.d(15): Error: template `to(T)()` does not have property `bad`
+fail_compilation/test23607.d(16): Error: template `to(T)()` does not have property `bad`
+---
+*/
+
+template to(T)
+{
+ void to(T)(){}
+}
+
+alias comb = to!int.bad!0;
+auto combe = to!int.bad!0;
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=23674
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test23674.d(14): Error: array index 2 is out of bounds `arr[0 .. 2]`
+fail_compilation/test23674.d(14): Error: array index 3 is out of bounds `arr[0 .. 2]`
+---
+*/
+
+void main()
+{
+ string[2] arr;
+ assert(arr[2] == arr[3]);
+}
--- /dev/null
+/* REQUIRED_ARGS: -betterC
+TEST_OUTPUT:
+---
+fail_compilation/test23710.d(111): Error: array concatenation of expression `foo ~ [1, 2, 3]` requires the GC which is not available with -betterC
+---
+ */
+// https://issues.dlang.org/show_bug.cgi?id=23710
+
+#line 100
+
+int test(int i)
+{
+ int j;
+ int[] foo;
+ if (0)
+ {
+ for (;;)
+ {
+ import core.stdc.stdio;
+ printf("start body\n");
+ foo = foo ~ [1,2,3];
+L1:
+ printf("foo.length = %zu\n", foo.length);
+ j += foo.length;
+ i += 2;
+ if (i > 5)
+ return j;
+ printf("end body\n");
+ }
+ }
+ goto L1;
+}
TEST_OUTPUT:
---
fail_compilation/test_switch_error.d(513): Error: undefined identifier `undefinedFunc`
-fail_compilation/test_switch_error.d(517): Error: `case` must be a `string` or an integral constant, not `Strukt(1)`
+fail_compilation/test_switch_error.d(517): Error: `case` expression must be a compile-time `string` or an integral constant, not `Strukt(1)`
fail_compilation/test_switch_error.d(518): Error: `case` variables have to be `const` or `immutable`
fail_compilation/test_switch_error.d(518): Error: `case` variables not allowed in `final switch` statements
fail_compilation/test_switch_error.d(519): Error: `case` variables not allowed in `final switch` statements
TEST_OUTPUT:
---
fail_compilation/test_switch_error.d(622): Error: undefined identifier `undefinedFunc`
-fail_compilation/test_switch_error.d(624): Error: `case` must be a `string` or an integral constant, not `SubtypeOfInt(2)`
-fail_compilation/test_switch_error.d(625): Error: `case` must be a `string` or an integral constant, not `SubtypeOfIntMethod()`
+fail_compilation/test_switch_error.d(624): Error: `case` expression must be a compile-time `string` or an integral constant, not `SubtypeOfInt(2)`
+fail_compilation/test_switch_error.d(625): Error: `case` expression must be a compile-time `string` or an integral constant, not `SubtypeOfIntMethod()`
---
++/
#line 600
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=22593
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/testrvaluecpctor.d(16): Error: cannot define both an rvalue constructor and a copy constructor for `struct Foo`
+fail_compilation/testrvaluecpctor.d(24): Template instance `testrvaluecpctor.Foo!int.Foo.__ctor!(immutable(Foo!int), immutable(Foo!int))` creates an rvalue constructor for `struct Foo`
+fail_compilation/testrvaluecpctor.d(24): Error: none of the overloads of `__ctor` are callable using a `immutable` object
+fail_compilation/testrvaluecpctor.d(18): Candidates are: `testrvaluecpctor.Foo!int.Foo.this(ref Foo!int rhs)`
+fail_compilation/testrvaluecpctor.d(16): `__ctor(Rhs, this This)(scope Rhs rhs)`
+---
+*/
+
+struct Foo(T)
+{
+ this(Rhs, this This)(scope Rhs rhs){}
+
+ this(ref scope typeof(this) rhs){}
+}
+
+void fail22593()
+{
+ immutable Foo!int a;
+ a.__ctor(a);
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=21613
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/testrvaluecpctor.d(40): Error: cannot define both an rvalue constructor and a copy constructor for `struct Test`
+fail_compilation/testrvaluecpctor.d(46): Template instance `testrvaluecpctor.Test.__ctor!()` creates an rvalue constructor for `struct Test`
+---
+*/
+
+struct Test
+{
+ this(ref const typeof(this) rhs){}
+ this()(const typeof(this) rhs){} // rvalue ctor
+}
+
+void fail21613()
+{
+ const Test cb;
+ Test b = cb;
+}
fail_compilation/testscopestatic.d(15): Error: variable `testscopestatic.foo.p` cannot be `scope` and `static`
fail_compilation/testscopestatic.d(16): Error: variable `testscopestatic.foo.b` cannot be `scope` and `extern`
fail_compilation/testscopestatic.d(17): Error: variable `testscopestatic.foo.c` cannot be `scope` and `__gshared`
-fail_compilation/testscopestatic.d(21): Error: variable `testscopestatic.foo.S.x` field cannot be `scope`
+fail_compilation/testscopestatic.d(21): Error: field `x` cannot be `scope`
---
*/
fail_compilation/udaparams.d(45): Error: `@nogc` attribute for function parameter is not supported
fail_compilation/udaparams.d(51): Error: cannot put a storage-class in an `alias` declaration.
fail_compilation/udaparams.d(52): Error: cannot put a storage-class in an `alias` declaration.
-fail_compilation/udaparams.d(53): Error: semicolon expected to close `alias` declaration
+fail_compilation/udaparams.d(53): Error: semicolon expected to close `alias` declaration, not `=>`
fail_compilation/udaparams.d(53): Error: declaration expected, not `=>`
-fail_compilation/udaparams.d(54): Error: semicolon expected to close `alias` declaration
+fail_compilation/udaparams.d(54): Error: semicolon expected to close `alias` declaration, not `=>`
fail_compilation/udaparams.d(54): Error: declaration expected, not `=>`
fail_compilation/udaparams.d(57): Error: basic type expected, not `@`
fail_compilation/udaparams.d(57): Error: identifier expected for template value parameter
/*
TEST_OUTPUT:
---
+runnable/aliasthis.d(103): Deprecation: alias this for classes/interfaces is deprecated
+runnable/aliasthis.d(291): Deprecation: alias this for classes/interfaces is deprecated
+runnable/aliasthis.d(292): Deprecation: alias this for classes/interfaces is deprecated
+runnable/aliasthis.d(294): Deprecation: alias this for classes/interfaces is deprecated
+runnable/aliasthis.d(465): Deprecation: alias this for classes/interfaces is deprecated
+runnable/aliasthis.d(466): Deprecation: alias this for classes/interfaces is deprecated
+runnable/aliasthis.d(477): Deprecation: alias this for classes/interfaces is deprecated
+runnable/aliasthis.d(1013): Deprecation: alias this for classes/interfaces is deprecated
false
+runnable/aliasthis.d(2100): Deprecation: alias this for classes/interfaces is deprecated
[] = int
[] = string
[0] = int
[] = int
[1] = string
[0] = int
+runnable/aliasthis.d(741): Deprecation: alias this for classes/interfaces is deprecated
---
RUN_OUTPUT:
class A2
{
- this()
+ this() scope
{
printf("A2.this()\n");
ax += 1;
}
- ~this()
+ ~this() scope
{
printf("A2.~this()\n");
ax += 1000;
class Child3 : Parent3
{
- this(){
+ this() scope {
assert(status3==0);
status3=1;
}
- ~this(){
+ ~this() scope {
assert(status3==1);
status3=2;
}
extern (C++) class CppA
{
int num;
- this(int num)
+ this(int num) scope
{
this.num = num;
}
- ~this()
+ ~this() scope
{
printf("%d: CppA.~this\n", num);
}
extern (C++) class CppB : CppA
{
- this(int num)
+ this(int num) scope
{
super(num);
}
- ~this()
+ ~this() scope
{
printf("%d: CppB.~this\n", num);
}
extern (C++) class CppC : CppB
{
- this(int num)
+ this(int num) scope
{
super(num);
}
- ~this()
+ ~this() scope
{
printf("%d: CppC.~this\n", num);
}
extern (D) class DA
{
int num;
- this(int num)
+ this(int num) scope
{
this.num = num;
}
- ~this()
+ ~this() scope
{
printf("%d: DA.~this\n", num);
}
extern (D) class DB : DA
{
- this(int num)
+ this(int num) scope
{
super(num);
}
- ~this()
+ ~this() scope
{
printf("%d: DB.~this\n", num);
}
extern (D) class DC : DB
{
- this(int num)
+ this(int num) scope
{
super(num);
}
- ~this()
+ ~this() scope
{
printf("%d: DC.~this\n", num);
}
extern (C++) class CppNoDestruct
{
int num;
- this(int num)
+ this(int num) scope
{
this.num = num;
}
int virtual(int p){return p;}
void test(this T)()
{
- alias vf = __traits(getVirtualFunctions, Class, "virtual");
- assert(vf.length == 2);
alias vm = __traits(getVirtualMethods, Class, "virtual");
assert(vm.length == 1);
assert(vm[0](42) == 42);
--- /dev/null
+module test11051;
+
+version (Safe)
+{
+ void main() @safe
+ {
+ enum E { A, B }
+ E e = cast(E)-1;
+
+ final switch (e)
+ {
+ case E.A: break;
+ case E.B: break;
+ }
+ }
+}
+else
+{
+ void main()
+ {
+ enum E { A, B }
+ E e = cast(E)-1;
+
+ final switch (e)
+ {
+ case E.A: break;
+ case E.B: break;
+ }
+ }
+}
{
void foo1(void delegate(ref int ) dg){ int x=10; dg(x); }
foo1((ref x){ pragma(msg, typeof(x)); assert(x == 10); });
- static assert(!__traits(compiles, foo1((x){}) ));
void foo2(void delegate(int, ...) dg){ dg(20, 3.14); }
foo2((x,...){ pragma(msg, typeof(x)); assert(x == 20); });
--- /dev/null
+typedef struct Foo *FooRef;
+struct Foo {
+ int x;
+};
+void free_foo(FooRef foo) { }
--- /dev/null
+typedef struct Foo *FooRef;
+struct Foo {
+ int x;
+};
+FooRef make_foo(void) { return 0; }
true
g
&Test109S(&Test109S(<recursion>))
+runnable/interpret.d(3742): Deprecation: alias this for classes/interfaces is deprecated
tfoo
tfoo
Crash!
void main()
{
uint loops = 0;
- static foreach (i; 0 .. 50)
+ static foreach (i; 0 .. 5)
{
static foreach (ch; SomeContainer().range)
loops++;
}
- assert(loops == 50 * 50);
+ assert(loops == 5 * 5);
}
struct SomeContainer
struct SomeRange
{
- int count = 50;
+ int count = 5;
int front() { return count; }
bool empty() { return count <= 0; }
void popFront() { count--; }
assert(cond11565(true) == size_t.max);
}
+// https://issues.dlang.org/show_bug.cgi?id=23743
+void test23743()
+{
+ ubyte[] a = [1];
+ foreach (x; a)
+ {
+ ubyte v = x >= 1 ? 255 : 0;
+ assert(v == 255);
+ }
+}
+
///////////////////////
int[3] array1 = [1:1,2,0:3];
testdocond();
testnegcom();
test11565();
+ test23743();
testoror();
testbt();
test12095(0);
class Foo5
{
- this ()
+ this () scope
{
printf ("Constructor\n");
assert(x5 == 0);
x5++;
}
- ~this ()
+ ~this () scope
{
printf ("Destructor\n");
assert(x5 == 2);
--- /dev/null
+/* PERMUTE_ARGS: -allinst
+ */
+
+// https://issues.dlang.org/show_bug.cgi?id=15985
+
+void ff()()
+{
+ gg!()();
+ hh!()();
+}
+
+void gg()() { ff!()(); }
+void hh()() { ff!()(); }
+
+enum x = is(typeof(ff!()()));
+alias my_g = gg!();
+
+int main() { return 0; }
// https://issues.dlang.org/show_bug.cgi?id=16098
-void main() {
+/*********************************************/
+
+void testDynamicClosure()
+{
byte a;
align(128) byte b;
assert((cast(size_t) &b) % 128 == 0);
+ b = 37;
byte foo() { return b; }
dg = &foo;
- assert(dg() == false);
+ assert(dg() == 37);
}
__gshared byte delegate() dg;
+
+/*********************************************/
+
+void testStaticClosure()
+{
+ byte aa;
+ align(128) byte b;
+ assert((cast(size_t) &b) % 128 == 0);
+ b = 73;
+
+ byte foo() { return b; }
+ assert(foo() == 73);
+}
+
+/*********************************************/
+
+void test3()
+{
+ struct S
+ {
+ align(32) int b;
+ }
+}
+
+/*********************************************/
+
+align(16)
+struct Cent
+{
+ ulong lo; // low 64 bits
+ ulong hi; // high 64 bits
+}
+
+enum Cent One = { 1 };
+
+Cent inc(Cent c) { return add(c, One); }
+
+Cent add(Cent c1, Cent c2) { const Cent ret = { 3, 2 }; return ret; }
+
+void test4()
+{
+ const Cent C10_0 = { 0, 10 };
+ const Cent Cm10_0 = inc(C10_0);
+}
+
+/*********************************************/
+
+int main()
+{
+ testDynamicClosure();
+ testStaticClosure();
+ test3();
+ test4();
+ return 0;
+}
+/*
+TEST_OUTPUT:
+---
+runnable/test17684.d(37): Deprecation: alias this for classes/interfaces is deprecated
+runnable/test17684.d(54): Deprecation: alias this for classes/interfaces is deprecated
+runnable/test17684.d(54): Deprecation: alias this for classes/interfaces is deprecated
+runnable/test17684.d(37): Deprecation: alias this for classes/interfaces is deprecated
+---
+*/
+
struct StructField(T)
{
static T Field;
--- /dev/null
+/* REQUIRED_ARGS: -betterC
+*/
+
+/*******************************************/
+// https://issues.dlang.org/show_bug.cgi?id=18472
+// https://github.com/dlang/dmd/pull/14676
+
+@nogc nothrow pure:
+immutable(Char)[] format(Char, Args...)(in Char[] fmt, Args args)
+{
+
+ if (__ctfe)
+ {
+ auto data2 = new char[5];
+ auto data = new Data2;
+ {
+ auto data3 = new Data2;
+ }
+ data2 = cast(char[]) "test2";
+ return data2;
+ }
+ else
+ {
+ return "test";
+ }
+}
+
+extern(C) void main()
+{
+ static assert(getData() == "test");
+ static assert("%s %s".format("test", "test") == "test2", "Not working");
+ assert("%s %s".format("test", "test") == "test", "%s %s".format("test", "test"));
+ assert(getData() == "test2", getData());
+}
+
+string getData()
+{
+ if (__ctfe)
+ {
+ auto data2 = new ubyte[5];
+ auto data = new Data2;
+ return "test";
+ }
+ else
+ {
+ return "test2";
+ }
+}
+
+private struct Data2
+{
+ size_t capacity;
+}
// https://issues.dlang.org/show_bug.cgi?id=19782
+
+/*
+TEST_OUTPUT:
+---
+runnable/test19782.d(17): Deprecation: alias this for classes/interfaces is deprecated
+---
+*/
+
class Inner
{
int a;
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=19946
+
+import core.stdc.stdio;
+
+template Tests(TY)
+{
+ void test1()
+ {
+ TY[24] ba;
+ ba[0..23] = 0x40;
+ check1(ba[]);
+ }
+
+ void check1(TY[] ba)
+ {
+ foreach (i; 0 .. 23)
+ {
+ //printf("ba[%d] = 0x%02x\n", i, ba[i]);
+ assert(ba[i] == 0x40);
+ }
+ assert(ba[23] == 0);
+ }
+}
+
+int main()
+{
+ Tests!byte.test1();
+ Tests!short.test1();
+ Tests!int.test1();
+ Tests!long.test1();
+
+ Tests!ubyte.test1();
+ Tests!ushort.test1();
+ Tests!uint.test1();
+ Tests!ulong.test1();
+ return 0;
+}
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=20520
+
+class C {}
+
+enum Foo {
+ Bar = new C()
+}
+
+void main()
+{
+ //pragma(msg, typeid(Foo.Bar)); // Works fine: typeid(C())
+ auto t = typeid(Foo.Bar); // Segfault here
+}
string exp()
{
string s = "a = b + c * d + a;";
- foreach (i; 0 .. 9)
+ foreach (i; 0 .. 8)
s = s ~ s;
return s;
}
{
int a = test();
printf("a = %d\n", a);
- assert(test() == 7169);
+ assert(test() == 3585);
return 0;
}
// https://issues.dlang.org/show_bug.cgi?id=21039
+/*
+TEST_OUTPUT:
+---
+runnable/test21039.d(14): Deprecation: alias this for classes/interfaces is deprecated
+---
+*/
+
class Inner {}
class Outer {
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=21772
+
+import core.stdc.string;
+
+int main()
+{
+ //import std.stdio : writeln;
+
+ double[] a = [-double.nan, double.nan, double.nan,
+ 1.0, double.nan, -double.nan];
+ //writeln(a); // Writes "[-nan, -nan, -nan, 1, nan, nan]" (Uh-oh!)
+ assert(memcmp(&a[0], &a[1], double.sizeof) != 0);
+ return 0;
+}
--- /dev/null
+// REQUIRED_ARGS: -preview=fieldwise -O
+// https://issues.dlang.org/show_bug.cgi?id=21821
+
+// test case comes from unittests in core.lifetime
+
+void test()
+{
+ alias T = immutable(S);
+ T source;
+ T target;
+ copyEmplacex(source, target);
+ T expectedCopy = source;
+ assert(target == expectedCopy);
+}
+
+struct S
+{
+ int x = 42;
+ this(this) { x += 10; }
+}
+
+void copyEmplacex(ref immutable(S) source, ref immutable(S) target) @system
+{
+ import core.stdc.string : memcpy;
+ memcpy(cast(S*) &target, cast(S*) &source, S.sizeof);
+ (cast() target).__xpostblit(); // casting away immutable
+}
+
+void main()
+{
+ test();
+}
class C71
{
static int cnt;
- this() { printf("C()\n"); cnt++; }
- ~this() { printf("~C()\n"); cnt--; }
+ this() scope { printf("C()\n"); cnt++; }
+ ~this() scope { printf("~C()\n"); cnt--; }
}
class D71
{
static int cnt;
- this() { printf("D()\n"); cnt++; }
- ~this() { printf("~D()\n"); cnt--; }
+ this() scope { printf("D()\n"); cnt++; }
+ ~this() scope { printf("~D()\n"); cnt--; }
}
class E71
{
static int cnt;
- this() { printf("E()\n"); cnt++; }
- ~this() { printf("~E()\n"); cnt--; }
+ this() scope { printf("E()\n"); cnt++; }
+ ~this() scope { printf("~E()\n"); cnt--; }
}
void test71()
// https://issues.dlang.org/show_bug.cgi?id=23234
+/*
+TEST_OUTPUT:
+---
+runnable/test23234.d(17): Deprecation: alias this for classes/interfaces is deprecated
+---
+*/
+
class Bar
{
}
--- /dev/null
+/* COMPILE_SEPARATELY:
+ * EXTRA_SOURCES: imports/maker.i imports/freer.i
+ */
+
+// https://issues.dlang.org/show_bug.cgi?id=23387
+
+/+ maker.i
+typedef struct Foo *FooRef;
+struct Foo {
+ int x;
+};
+FooRef make_foo(void);
++/
+import imports.maker;
+
+
+/+ freer.i
+typedef struct Foo *FooRef;
+struct Foo {
+ int x;
+};
+void free_foo(FooRef foo);
++/
+import imports.freer;
+
+int main(){
+ FooRef f = make_foo();
+ free_foo(f);
+ return 0;
+}
--- /dev/null
+// DISABLED: win64
+// https://issues.dlang.org/show_bug.cgi?id=23514
+
+// Note: this test is disabled on Win64 because of an issue with the Windows
+// MS-COFF backend causing it to fail.
+
+enum ulong offset = 0xFFFF_FFFF_0000_0000UL;
+
+void main()
+{
+ ulong voffset = offset;
+ assert((cast(ulong)&main + voffset) == (cast(ulong)&main + offset));
+}
--- /dev/null
+
+// https://issues.dlang.org/show_bug.cgi?id=23618
+
+import core.stdc.stdio;
+
+uint test1()
+{
+ ushort ee = 1028;
+ ee <<= 5U;
+ ee >>= 5U;
+ assert(ee == 1028);
+ //printf("%x, %d\n", ee, ee);
+ return ee;
+}
+
+uint test2()
+{
+ ubyte ee = 4;
+ ee <<= 5U;
+ ee >>= 5U;
+ //printf("%x, %d\n", ee, ee);
+ assert(ee == 4);
+ return ee;
+}
+
+void main()
+{
+ test1();
+ test2();
+}
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=23650
+
+__gshared int x;
+
+void main()
+{
+
+ static assert(__traits(compiles,
+ {
+ struct S { int *p = &x; }
+ auto t = typeid(S);
+ }));
+}
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=23710
+
+int test(int i)
+{
+ int j;
+ int[] foo;
+ if (0)
+ {
+ for (;;)
+ {
+ import core.stdc.stdio;
+ printf("start body\n");
+ foo = foo ~ [1,2,3];
+L1:
+ printf("foo.length = %zu\n", foo.length);
+ j += foo.length;
+ i += 2;
+ if (i > 5)
+ return j;
+ printf("end body\n");
+ }
+ }
+ goto L1;
+}
+
+int main()
+{
+ assert(test(1) == 0 + 3 + 6);
+ return 0;
+}
-// REQUIRED_ARGS: -d
-
module test34;
import core.exception;
int x44;
class A44 {
- this() { printf("A44 ctor\n"); x44 += 1; }
- ~this() { printf("A44 dtor\n"); x44 += 0x100; }
+ this() scope { printf("A44 ctor\n"); x44 += 1; }
+ ~this() scope { printf("A44 dtor\n"); x44 += 0x100; }
}
class B44 : A44 { }
// https://issues.dlang.org/show_bug.cgi?id=11294
+/*
+TEST_OUTPUT:
+---
+runnable/testaliascast.d(29): Deprecation: alias this for classes/interfaces is deprecated
+runnable/testaliascast.d(58): Deprecation: alias this for classes/interfaces is deprecated
+---
+*/
+
string result;
extern(C) void rt_finalize(void *ptr, bool det=true);
REQUIRED_ARGS: -preview=rvaluerefparam
TEST_OUTPUT:
---
+runnable/testassign.d(802): Deprecation: alias this for classes/interfaces is deprecated
+runnable/testassign.d(808): Deprecation: alias this for classes/interfaces is deprecated
\ S1 S2a S2b S3a S3b S4a S4b
- true true true true true true true
Xa true true true true true true true
int status24;
class C24{
- this(){
+ this() scope {
assert(status24==0);
status24+=2;
}
/********************************************************/
-void test10()
-{
- assert(__traits(isVirtualFunction, C.bar) == true);
- assert(__traits(isVirtualFunction, S.bar) == false);
-}
-
-/********************************************************/
-
void test11()
{
assert(__traits(isAbstractFunction, C.bar) == false);
int foo(int) { return 2; }
}
-void test15()
-{
- D15 d = new D15();
-
- assert(__traits(getVirtualFunctions, D15, "foo").length == 2);
- assert(typeid(typeof(__traits(getVirtualFunctions, D15, "foo")[0])).toString()
- == "void function()");
- assert(typeid(typeof(__traits(getVirtualFunctions, D15, "foo")[1])).toString()
- == "int function(int)");
-
- alias typeof(__traits(getVirtualFunctions, D15, "foo")) b;
- assert(typeid(b[0]).toString() == "void function()");
- assert(typeid(b[1]).toString() == "int function(int)");
-
- auto i = __traits(getVirtualFunctions, d, "foo")[1](1);
- assert(i == 2);
-}
-
/********************************************************/
struct S16 { }
int YYY();
}
-class CC : AA
-{
- final int YYY() { return 4; }
-}
-
-static assert(__traits(isVirtualMethod, CC.YYY));
-static assert(__traits(getVirtualMethods, CC, "YYY").length == 1);
-
class DD
{
final int YYY() { return 4; }
static assert(__traits(isFinalFunction, C.ffunc) ==
__traits(isFinalFunction, __traits(getOverloads, C, "ffunc")[0])); // NG
- static assert(__traits(isVirtualFunction, C.vfunc) ==
- __traits(isVirtualFunction, __traits(getOverloads, C, "vfunc")[0])); // NG
static assert(__traits(isVirtualMethod, C.vfunc) ==
__traits(isVirtualMethod, __traits(getOverloads, C, "vfunc")[0])); // NG
static assert(__traits(isAbstractFunction, C.afunc) ==
test7();
test8();
test9();
- test10();
test11();
test12();
test13();
test7123();
test14();
- test15();
test16();
test17();
test18();
-
module traits_getPointerBitmap;
import core.stdc.stdio;
enum pOff = T.p.offsetof / bytesPerPtr;
}
-class C(T, aliasTo = void)
-{
- static if(!is(aliasTo == void))
- {
- aliasTo a;
- alias a this;
- }
-
- size_t x;
- T t = void;
- void* p;
-}
-
///////////////////////////////////////
void _testType(T)(size_t[] expected)
// prepend string
sexp[0] = (expected[0] << tOff!(S!(T, string))) | (1 << pOff!(S!(T, string))) | 2; // arr ptr
_testType!(S!(T, string))(sexp);
-
- // generate bit pattern for C!T
- C!T ct = null;
- size_t mutexBit = (RTInfoMark__Monitor ? 2 : 0);
- size_t ctpOff = ct.p.offsetof / bytesPerPtr;
- size_t cttOff = ct.t.offsetof / bytesPerPtr;
- sexp[0] = (expected[0] << cttOff) | (1 << ctpOff) | mutexBit;
- _testType!(C!(T))(sexp);
-
- C!(T, string) cts = null;
- size_t ctspOff = cts.p.offsetof / bytesPerPtr;
- size_t ctstOff = cts.t.offsetof / bytesPerPtr;
- // generate bit pattern for C!T
- sexp[0] = (expected[0] << ctstOff) | (1 << ctspOff) | mutexBit | 0b1000; // arr ptr
- _testType!(C!(T, string))(sexp);
}
///////////////////////////////////////
-// REQUIRED_ARGS: -d -preview=rvaluerefparam
+// REQUIRED_ARGS: -preview=rvaluerefparam
//
/* TEST_OUTPUT:
---
+runnable/xtest46.d(165): Deprecation: alias this for classes/interfaces is deprecated
Boo!double
Boo!int
true
int
!! immutable(int)[]
+runnable/xtest46.d(2932): Deprecation: alias this for classes/interfaces is deprecated
+runnable/xtest46.d(2964): Deprecation: alias this for classes/interfaces is deprecated
int(int i, long j = 7L)
long
C10390(C10390(C10390(<recursion>)))
double[]
double[]
{}
+runnable/xtest46.d(4670): Deprecation: alias this for classes/interfaces is deprecated
tuple("m")
true
TFunction1: extern (C) void function()
/*
-REQUIRED_ARGS: -d -lowmem -Jrunnable -preview=rvaluerefparam
+REQUIRED_ARGS: -lowmem -Jrunnable -preview=rvaluerefparam
EXTRA_FILES: xtest46.d
TEST_OUTPUT:
---
+runnable/xtest46_gc.d-mixin-33(197): Deprecation: alias this for classes/interfaces is deprecated
Boo!double
Boo!int
true
int
!! immutable(int)[]
+runnable/xtest46_gc.d-mixin-33(2964): Deprecation: alias this for classes/interfaces is deprecated
+runnable/xtest46_gc.d-mixin-33(2996): Deprecation: alias this for classes/interfaces is deprecated
int(int i, long j = 7L)
long
C10390(C10390(<recursion>))
double[]
double[]
{}
+runnable/xtest46_gc.d-mixin-33(4702): Deprecation: alias this for classes/interfaces is deprecated
tuple("m")
true
TFunction1: extern (C) void function()
extern(C++)
{
+ // https://issues.dlang.org/show_bug.cgi?id=19563
+
struct SmallStruct
{
int i;
}
}
+/*********************************************/
+// https://issues.dlang.org/show_bug.cgi?id=23195
+
+extern (C++)
+{
+ struct FF
+ {
+ float x, y;
+
+ ~this() { }
+ }
+
+ float draw(FF min, FF max);
+
+ void test23195()
+ {
+ FF a = { 1, 2 };
+ FF b = { 3, 4 };
+ float f = draw(a, b);
+ assert(f == 1234);
+ }
+
+ /*********************/
+
+ struct FF2
+ {
+ float x, y;
+
+ this(int i) { }
+ }
+
+ float draw2(FF2 min, FF2 max);
+
+ void test23195_2()
+ {
+ FF2 a; a.x = 1; a.y = 2;
+ FF2 b; b.x = 3; b.y = 4;
+ float f = draw2(a, b);
+ assert(f == 1234);
+ }
+}
+
+/*********************************************/
+
void main()
{
foreach(bool val; values!bool()) check(val);
doConsume2(sd);
assert(Sdtor.counter == 2);
}
+ test23195();
+ test23195_2();
}
// CXXFLAGS(linux freebsd osx netbsd dragonflybsd): -std=c++11
// druntime isn't linked, this prevents missing symbols '_d_arraybounds_slicep':
// REQUIRED_ARGS: -checkaction=C
-// Filter a spurious warning on Semaphore:
-// TRANSFORM_OUTPUT: remove_lines("warning: relocation refers to discarded section")
// N.B MSVC doesn't have a C++11 switch, but it defaults to the latest fully-supported standard
/****************************************/
-version (linux)
-{
- static if (__traits(getTargetInfo, "cppStd") < 201703)
- {
- // See note on std::allocator below.
- extern(C++, __gnu_cxx)
- {
- struct new_allocator(T)
- {
- alias size_type = size_t;
- static if (is(T : char))
- void deallocate(T*, size_type) { }
- else
- void deallocate(T*, size_type);
- }
- }
- }
-}
-
extern (C++, std)
{
- version (linux)
- {
- static if (__traits(getTargetInfo, "cppStd") >= 201703)
- {
- // std::allocator no longer derives from __gnu_cxx::new_allocator,
- // it derives from std::__new_allocator instead.
- struct __new_allocator(T)
- {
- alias size_type = size_t;
- static if (is(T : char))
- void deallocate(T*, size_type) { }
- else
- void deallocate(T*, size_type);
- }
- }
- }
-
extern (C++, class) struct allocator(T)
{
- version (linux)
- {
- alias size_type = size_t;
- void deallocate(T* p, size_type sz)
- {
- static if (__traits(getTargetInfo, "cppStd") >= 201703)
- (cast(std.__new_allocator!T*)&this).deallocate(p, sz);
- else
- (cast(__gnu_cxx.new_allocator!T*)&this).deallocate(p, sz);
- }
- }
}
class vector(T, A = allocator!T)
version (linux)
{
- void test14a(std.allocator!int * pa)
- {
- pa.deallocate(null, 0);
- }
-
void gun(std.vector!int pa)
{
int x = 42;
/****************************************/
// https://issues.dlang.org/show_bug.cgi?id=15579
-extern (C++)
+version (DigitalMars)
{
- class Base
- {
- //~this() {}
- void based() { }
- ubyte x = 4;
- }
-
- interface Interface
+ version (linux)
{
- int MethodCPP();
- int MethodD();
+ // Test removed for DMD/linux-only.
+ // https://issues.dlang.org/show_bug.cgi?id=23660
}
+ else
+ version = TEST15579;
+}
+else
+ version = TEST15579;
- class Derived : Base, Interface
+version (TEST15579)
+{
+ extern (C++)
{
- short y = 5;
- int MethodCPP();
- int MethodD() {
- printf("Derived.MethodD(): this = %p, x = %d, y = %d\n", this, x, y);
- Derived p = this;
- //p = cast(Derived)(cast(void*)p - 16);
- assert(p.x == 4 || p.x == 7);
- assert(p.y == 5 || p.y == 8);
- return 3;
+ class Base
+ {
+ //~this() {}
+ void based() { }
+ ubyte x = 4;
}
- int Method() { return 6; }
- }
-
- Derived cppfoo(Derived);
- Interface cppfooi(Interface);
-}
-void test15579()
-{
- Derived d = new Derived();
- printf("d = %p\n", d);
- assert(d.x == 4);
- assert(d.y == 5);
- assert((cast(Interface)d).MethodCPP() == 30);
- assert((cast(Interface)d).MethodD() == 3);
- assert(d.MethodCPP() == 30);
- assert(d.MethodD() == 3);
- assert(d.Method() == 6);
+ interface Interface
+ {
+ int MethodCPP();
+ int MethodD();
+ }
- d = cppfoo(d);
- assert(d.x == 7);
- assert(d.y == 8);
+ class Derived : Base, Interface
+ {
+ short y = 5;
+ int MethodCPP();
+ int MethodD() {
+ printf("Derived.MethodD(): this = %p, x = %d, y = %d\n", this, x, y);
+ Derived p = this;
+ //p = cast(Derived)(cast(void*)p - 16);
+ assert(p.x == 4 || p.x == 7);
+ assert(p.y == 5 || p.y == 8);
+ return 3;
+ }
+ int Method() { return 6; }
+ }
- printf("d2 = %p\n", d);
+ Derived cppfoo(Derived);
+ Interface cppfooi(Interface);
+ }
- /* Casting to an interface involves thunks in the vtbl[].
- * g++ puts the thunks for MethodD in the same COMDAT as MethodD.
- * But D doesn't, so when the linker "picks one" of the D generated MethodD
- * or the g++ generated MethodD, it may wind up with a messed up thunk,
- * resulting in a seg fault. The solution is to not expect objects of the same
- * type to be constructed on both sides of the D/C++ divide if the same member
- * function (in this case, MethodD) is also defined on both sides.
- */
- version (Windows)
+ void test15579()
{
+ Derived d = new Derived();
+ printf("d = %p\n", d);
+ assert(d.x == 4);
+ assert(d.y == 5);
+ assert((cast(Interface)d).MethodCPP() == 30);
assert((cast(Interface)d).MethodD() == 3);
- }
- assert((cast(Interface)d).MethodCPP() == 30);
+ assert(d.MethodCPP() == 30);
+ assert(d.MethodD() == 3);
+ assert(d.Method() == 6);
+
+ d = cppfoo(d);
+ assert(d.x == 7);
+ assert(d.y == 8);
+
+ printf("d2 = %p\n", d);
+
+ /* Casting to an interface involves thunks in the vtbl[].
+ * g++ puts the thunks for MethodD in the same COMDAT as MethodD.
+ * But D doesn't, so when the linker "picks one" of the D generated MethodD
+ * or the g++ generated MethodD, it may wind up with a messed up thunk,
+ * resulting in a seg fault. The solution is to not expect objects of the same
+ * type to be constructed on both sides of the D/C++ divide if the same member
+ * function (in this case, MethodD) is also defined on both sides.
+ */
+ version (Windows)
+ {
+ assert((cast(Interface)d).MethodD() == 3);
+ }
+ assert((cast(Interface)d).MethodCPP() == 30);
- assert(d.Method() == 6);
+ assert(d.Method() == 6);
- printf("d = %p, i = %p\n", d, cast(Interface)d);
- version (Windows)
- {
- Interface i = cppfooi(d);
- printf("i2: %p\n", i);
- assert(i.MethodD() == 3);
- assert(i.MethodCPP() == 30);
+ printf("d = %p, i = %p\n", d, cast(Interface)d);
+ version (Windows)
+ {
+ Interface i = cppfooi(d);
+ printf("i2: %p\n", i);
+ assert(i.MethodD() == 3);
+ assert(i.MethodCPP() == 30);
+ }
+ printf("test15579() done\n");
}
- printf("test15579() done\n");
}
/****************************************/
class Cpp15589Derived : Cpp15589Base
{
public:
- this();
+ this() scope;
final ~this();
int b;
}
public:
void beforeDtor();
- this();
+ this() scope;
~this();
void afterDtor();
class Cpp15589DerivedVirtual : Cpp15589BaseVirtual
{
public:
- this();
+ this() scope;
~this();
override void afterDtor();
class Cpp15589IntroducingVirtual : Cpp15589Base
{
public:
- this();
+ this() scope;
void beforeIntroducedVirtual();
~this();
void afterIntroducedVirtual(int);
testeh2();
testeh3();
test15576();
- test15579();
+ version (TEST15579) test15579();
test15610();
test15455();
test15372();
// fn0 passthrough_fn0 (fn0 value) { return value; }
// typedef int (*fn1)(int);
// fn1 passthrough_fn1 (fn1 value) { return value; }
+
+/******************************/
+
+struct FF
+{
+ float x, y;
+ ~FF();
+};
+
+float draw(FF min, FF max)
+{
+ return min.x * 1000 + min.y * 100 + max.x * 10 + max.y;
+}
+
+/******************************/
+
+struct FF2
+{
+ float x, y;
+ FF2(int i) { }
+};
+
+float draw2(FF2 min, FF2 max)
+{
+ return min.x * 1000 + min.y * 100 + max.x * 10 + max.y;
+}
extern(C++):
-version (AArch64) version = UnsignedChar;
-version (ARM) version = UnsignedChar;
-version (RISCV32) version = UnsignedChar;
-version (RISCV64) version = UnsignedChar;
-version (PPC) version = UnsignedChar;
-version (PPC64) version = UnsignedChar;
-version (S390) version = UnsignedChar;
-version (SystemZ) version = UnsignedChar;
+version (OSX)
+ version = Darwin;
+else version (iOS)
+ version = Darwin;
+else version (TVOS)
+ version = Darwin;
+else version (WatchOS)
+ version = Darwin;
+
+version (Darwin) { /* signed on ARM too */ } else
+{
+ version (AArch64) version = UnsignedChar;
+ version (ARM) version = UnsignedChar;
+ version (RISCV32) version = UnsignedChar;
+ version (RISCV64) version = UnsignedChar;
+ version (PPC) version = UnsignedChar;
+ version (PPC64) version = UnsignedChar;
+ version (S390) version = UnsignedChar;
+ version (SystemZ) version = UnsignedChar;
+}
version (UnsignedChar)
enum __c_char : ubyte;
-09faa4eacd4fb147107e94eeebf56b3a73fdcc05
+4ca4140e584c055a8a9bc727e56a97ebcecd61e0
The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository.
DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \
core/builtins.d core/checkedint.d core/cpuid.d core/demangle.d \
- core/exception.d core/gc/config.d core/gc/gcinterface.d \
+ core/exception.d core/factory.d core/gc/config.d core/gc/gcinterface.d \
core/gc/registry.d core/int128.d core/internal/abort.d \
core/internal/array/appending.d core/internal/array/arrayassign.d \
core/internal/array/capacity.d core/internal/array/casting.d \
am__dirstamp = $(am__leading_dot)dirstamp
am__objects_1 = core/atomic.lo core/attribute.lo core/bitop.lo \
core/builtins.lo core/checkedint.lo core/cpuid.lo \
- core/demangle.lo core/exception.lo core/gc/config.lo \
- core/gc/gcinterface.lo core/gc/registry.lo core/int128.lo \
- core/internal/abort.lo core/internal/array/appending.lo \
+ core/demangle.lo core/exception.lo core/factory.lo \
+ core/gc/config.lo core/gc/gcinterface.lo core/gc/registry.lo \
+ core/int128.lo core/internal/abort.lo \
+ core/internal/array/appending.lo \
core/internal/array/arrayassign.lo \
core/internal/array/capacity.lo core/internal/array/casting.lo \
core/internal/array/comparison.lo \
DRUNTIME_CSOURCES = core/stdc/errno_.c
DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \
core/builtins.d core/checkedint.d core/cpuid.d core/demangle.d \
- core/exception.d core/gc/config.d core/gc/gcinterface.d \
+ core/exception.d core/factory.d core/gc/config.d core/gc/gcinterface.d \
core/gc/registry.d core/int128.d core/internal/abort.d \
core/internal/array/appending.d core/internal/array/arrayassign.d \
core/internal/array/capacity.d core/internal/array/casting.d \
core/cpuid.lo: core/$(am__dirstamp)
core/demangle.lo: core/$(am__dirstamp)
core/exception.lo: core/$(am__dirstamp)
+core/factory.lo: core/$(am__dirstamp)
core/gc/$(am__dirstamp):
@$(MKDIR_P) core/gc
@: > core/gc/$(am__dirstamp)
{
string[] tags;
- this(string[] tags...)
+ this(string[] tags...) @safe pure nothrow
{
- this.tags = tags;
+ this.tags = tags.dup;
}
}
}
*/
-shared static this()
+pragma(crt_constructor) void cpuid_initialization()
{
auto cf = getCpuFeatures();
TypeTuple:
B Number Arguments
*/
- char[] parseType( char[] name = null ) return scope
+ char[] parseType() return scope
{
static immutable string[23] primitives = [
"char", // a
];
static if (__traits(hasMember, Hooks, "parseType"))
- if (auto n = hooks.parseType(this, name))
+ if (auto n = hooks.parseType(this, null))
return n;
debug(trace) printf( "parseType+\n" );
switch ( t )
{
case 'Q': // Type back reference
- return parseBackrefType( () => parseType( name ) );
+ return parseBackrefType(() => parseType());
case 'O': // Shared (O Type)
popFront();
put( "shared(" );
parseType();
put( ')' );
- pad( name );
return dst[beg .. len];
case 'x': // Const (x Type)
popFront();
put( "const(" );
parseType();
put( ')' );
- pad( name );
return dst[beg .. len];
case 'y': // Immutable (y Type)
popFront();
put( "immutable(" );
parseType();
put( ')' );
- pad( name );
return dst[beg .. len];
case 'N':
popFront();
popFront();
parseType();
put( "[]" );
- pad( name );
return dst[beg .. len];
case 'G': // TypeStaticArray (G Number Type)
popFront();
put( '[' );
put( num );
put( ']' );
- pad( name );
return dst[beg .. len];
case 'H': // TypeAssocArray (H Type Type)
popFront();
put( '[' );
put( tx );
put( ']' );
- pad( name );
return dst[beg .. len];
case 'P': // TypePointer (P Type)
popFront();
parseType();
put( '*' );
- pad( name );
return dst[beg .. len];
case 'F': case 'U': case 'W': case 'V': case 'R': // TypeFunction
- return parseTypeFunction( name );
+ return parseTypeFunction();
case 'C': // TypeClass (C LName)
case 'S': // TypeStruct (S LName)
case 'E': // TypeEnum (E LName)
case 'T': // TypeTypedef (T LName)
popFront();
parseQualifiedName();
- pad( name );
return dst[beg .. len];
case 'D': // TypeDelegate (D TypeFunction)
popFront();
auto modifiers = parseModifier();
if ( front == 'Q' )
- parseBackrefType( () => parseTypeFunction( name, IsDelegate.yes ) );
+ parseBackrefType(() => parseTypeFunction(IsDelegate.yes));
else
- parseTypeFunction( name, IsDelegate.yes );
+ parseTypeFunction(IsDelegate.yes);
if (modifiers)
{
// write modifiers behind the function arguments
{
popFront();
put( primitives[cast(size_t)(t - 'a')] );
- pad( name );
return dst[beg .. len];
}
else if (t == 'z')
case 'i':
popFront();
put( "cent" );
- pad( name );
return dst[beg .. len];
case 'k':
popFront();
put( "ucent" );
- pad( name );
return dst[beg .. len];
default:
error();
TypeFunction:
CallConvention FuncAttrs Arguments ArgClose Type
*/
- char[] parseTypeFunction( char[] name = null, IsDelegate isdg = IsDelegate.no ) return scope
+ char[] parseTypeFunction(IsDelegate isdg = IsDelegate.no) return scope
{
debug(trace) printf( "parseTypeFunction+\n" );
debug(trace) scope(success) printf( "parseTypeFunction-\n" );
auto retbeg = len;
parseType();
put( ' ' );
- // append name/delegate/function
- if ( name.length )
- {
- if ( !contains( dst[0 .. len], name ) )
- put( name );
- else if ( shift( name ).ptr != name.ptr )
- {
- argbeg -= name.length;
- retbeg -= name.length;
- }
- }
- else if ( IsDelegate.yes == isdg )
+ // append delegate/function
+ if (IsDelegate.yes == isdg)
put( "delegate" );
else
put( "function" );
version (linux) import core.sys.linux.dlfcn : RTLD_DEFAULT;
version (NetBSD) import core.sys.netbsd.dlfcn : RTLD_DEFAULT;
version (OpenBSD) import core.sys.openbsd.dlfcn : RTLD_DEFAULT;
- version (OSX) import core.sys.darwin.dlfcn : RTLD_DEFAULT;
+ version (Darwin) import core.sys.darwin.dlfcn : RTLD_DEFAULT;
version (Solaris) import core.sys.solaris.dlfcn : RTLD_DEFAULT;
if (auto found = cast(CXX_DEMANGLER) dlsym(RTLD_DEFAULT, "__cxa_demangle"))
--- /dev/null
+/* Create classes from their modules and names.
+ *
+ * Copyright: Copyright (C) D Language Foundation 2023
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Authors: Walter Bright, Steven Schveighoffer
+ * Source: $(DRUNTIMESRC core/_factory.d)
+ */
+
+module core.factory;
+
+/**
+ * Create instance of class specified by the module symbol and a string
+ * representing the name of the class.
+ * The class must either have no constructors or have
+ * a default constructor.
+ * Params:
+ * mod = symbol representing the module that the class is in
+ * classname = string representing the name of the class
+ * Returns:
+ * null if failed
+ * Example:
+ * ---
+ * module foo.bar;
+ *
+ * class C
+ * {
+ * this() { x = 10; }
+ * int x;
+ * }
+ *
+ * void main()
+ * {
+ * auto c = cast(C)factory!(foo.bar)("C");
+ * assert(c !is null && c.x == 10);
+ * }
+ * ---
+ */
+Object factory(alias mod)(string classname)
+{
+ foreach(cl; _getModuleClasses!mod)
+ {
+ if (cl.stringof == classname)
+ return cl.classinfo.create();
+ }
+ return null;
+}
+
+@system unittest
+{
+ Object valid_obj = factory!object("Object");
+ Object invalid_obj = factory!object("__this_class_doesnt_exist__");
+
+ assert(valid_obj !is null);
+ assert(invalid_obj is null);
+}
+
+/**************************************
+ * Retrieve as a tuple all the types of the top level classes in the module mod.
+ */
+private template _getModuleClasses(alias mod) {
+ alias result = _AliasSeq!();
+ static foreach(m; __traits(allMembers, mod))
+ static if(is(__traits(getMember, mod, m) == class))
+ result = _AliasSeq!(result, __traits(getMember, mod, m));
+ alias _getModuleClasses = result;
+}
+
+private template _AliasSeq(TList...) { alias _AliasSeq = TList; }
alias U = ulong;
enum Ubits = uint(U.sizeof * 8);
-version (X86_64) private enum Cent_alignment = 16;
-else private enum Cent_alignment = (size_t.sizeof * 2);
+version (DigitalMars)
+{
+ /* The alignment should follow target.stackAlign(),
+ * which is `isXmmSupported() ? 16 : (is64bit ? 8 : 4)
+ */
+ version (D_SIMD)
+ private enum Cent_alignment = 16;
+ else version (X86_64)
+ private enum Cent_alignment = 8;
+ else
+ private enum Cent_alignment = 4;
+}
+else
+{
+ version (X86_64) private enum Cent_alignment = 16;
+ else private enum Cent_alignment = (size_t.sizeof * 2);
+}
align(Cent_alignment) struct Cent
{
/// Implementation of `_d_arrayappendcTX` and `_d_arrayappendcTXTrace`
template _d_arrayappendcTXImpl(Tarr : T[], T)
{
- import core.internal.array.utils : _d_HookTraceImpl;
-
private enum errorMessage = "Cannot append to array if compiling without support for runtime type information!";
/**
return px;
}
else
- assert(0, "Cannot append arrays if compiling without support for runtime type information!");
+ assert(0, errorMessage);
}
- /**
- * TraceGC wrapper around $(REF _d_arrayappendcTX, rt,array,appending,_d_arrayappendcTXImpl).
- * Bugs:
- * This function template was ported from a much older runtime hook that bypassed safety,
- * purity, and throwabilty checks. To prevent breaking existing code, this function template
- * is temporarily declared `@trusted pure` until the implementation can be brought up to modern D expectations.
- */
- alias _d_arrayappendcTXTrace = _d_HookTraceImpl!(Tarr, _d_arrayappendcTX, errorMessage);
+ version (D_ProfileGC)
+ {
+ import core.internal.array.utils : _d_HookTraceImpl;
+
+ /**
+ * TraceGC wrapper around $(REF _d_arrayappendcTX, rt,array,appending,_d_arrayappendcTXImpl).
+ * Bugs:
+ * This function template was ported from a much older runtime hook that bypassed safety,
+ * purity, and throwabilty checks. To prevent breaking existing code, this function template
+ * is temporarily declared `@trusted pure` until the implementation can be brought up to modern D expectations.
+ */
+ alias _d_arrayappendcTXTrace = _d_HookTraceImpl!(Tarr, _d_arrayappendcTX, errorMessage);
+ }
}
/// Implementation of `_d_arrayappendT`
import core.stdc.string : memcpy;
import core.internal.traits : hasElaborateCopyConstructor, Unqual;
- import core.lifetime : copyEmplace;
enum hasPostblit = __traits(hasPostblit, T);
auto length = x.length;
// Only call `copyEmplace` if `T` has a copy ctor and no postblit.
static if (hasElaborateCopyConstructor!T && !hasPostblit)
{
+ import core.lifetime : copyEmplace;
+
foreach (i, ref elem; y)
copyEmplace(elem, x[length + i]);
}
return x;
}
-/**
- * TraceGC wrapper around $(REF _d_arrayappendT, core,internal,array,appending).
- */
-ref Tarr _d_arrayappendTTrace(Tarr : T[], T)(string file, int line, string funcname, return ref scope Tarr x, scope Tarr y) @trusted
+version (D_ProfileGC)
{
- version (D_TypeInfo)
+ /**
+ * TraceGC wrapper around $(REF _d_arrayappendT, core,internal,array,appending).
+ */
+ ref Tarr _d_arrayappendTTrace(Tarr : T[], T)(string file, int line, string funcname, return ref scope Tarr x, scope Tarr y) @trusted
{
- import core.internal.array.utils: TraceHook, gcStatsPure, accumulatePure;
- mixin(TraceHook!(Tarr.stringof, "_d_arrayappendT"));
+ version (D_TypeInfo)
+ {
+ import core.internal.array.utils: TraceHook, gcStatsPure, accumulatePure;
+ mixin(TraceHook!(Tarr.stringof, "_d_arrayappendT"));
- return _d_arrayappendT(x, y);
+ return _d_arrayappendT(x, y);
+ }
+ else
+ assert(0, "Cannot append to array if compiling without support for runtime type information!");
}
- else
- assert(0, "Cannot append to array if compiling without support for runtime type information!");
}
@safe unittest
/// Implementation of `_d_arraysetlengthT` and `_d_arraysetlengthTTrace`
template _d_arraysetlengthTImpl(Tarr : T[], T)
{
- import core.internal.array.utils : _d_HookTraceImpl;
-
private enum errorMessage = "Cannot resize arrays if compiling without support for runtime type information!";
/**
assert(0, errorMessage);
}
- /**
- * TraceGC wrapper around $(REF _d_arraysetlengthT, core,internal,array,core.internal.array.capacity).
- * Bugs:
- * This function template was ported from a much older runtime hook that bypassed safety,
- * purity, and throwabilty checks. To prevent breaking existing code, this function template
- * is temporarily declared `@trusted pure nothrow` until the implementation can be brought up to modern D expectations.
- */
- alias _d_arraysetlengthTTrace = _d_HookTraceImpl!(Tarr, _d_arraysetlengthT, errorMessage);
+ version (D_ProfileGC)
+ {
+ import core.internal.array.utils : _d_HookTraceImpl;
+
+ /**
+ * TraceGC wrapper around $(REF _d_arraysetlengthT, core,internal,array,core.internal.array.capacity).
+ * Bugs:
+ * This function template was ported from a much older runtime hook that bypassed safety,
+ * purity, and throwabilty checks. To prevent breaking existing code, this function template
+ * is temporarily declared `@trusted pure nothrow` until the implementation can be brought up to modern D expectations.
+ */
+ alias _d_arraysetlengthTTrace = _d_HookTraceImpl!(Tarr, _d_arraysetlengthT, errorMessage);
+ }
}
@safe unittest
/// Implementation of `_d_arraycatnTX` and `_d_arraycatnTXTrace`
template _d_arraycatnTXImpl(Tarr : ResultArrT[], ResultArrT : T[], T)
{
- import core.internal.array.utils : _d_HookTraceImpl;
-
private enum errorMessage = "Cannot concatenate arrays if compiling without support for runtime type information!";
/**
assert(0, errorMessage);
}
- /**
- * TraceGC wrapper around $(REF _d_arraycatnTX, core,internal,array,concat).
- * Bugs:
- * This function template was ported from a much older runtime hook that bypassed safety,
- * purity, and throwabilty checks. To prevent breaking existing code, this function template
- * is temporarily declared `@trusted pure nothrow` until the implementation can be brought up to modern D expectations.
- */
- alias _d_arraycatnTXTrace = _d_HookTraceImpl!(ResultArrT, _d_arraycatnTX, errorMessage);
+ version (D_ProfileGC)
+ {
+ import core.internal.array.utils : _d_HookTraceImpl;
+
+ /**
+ * TraceGC wrapper around $(REF _d_arraycatnTX, core,internal,array,concat).
+ * Bugs:
+ * This function template was ported from a much older runtime hook that bypassed safety,
+ * purity, and throwabilty checks. To prevent breaking existing code, this function template
+ * is temporarily declared `@trusted pure nothrow` until the implementation can be brought up to modern D expectations.
+ */
+ alias _d_arraycatnTXTrace = _d_HookTraceImpl!(ResultArrT, _d_arraycatnTX, errorMessage);
+ }
}
@safe unittest
if (__ctfe)
return _dupCtfe!(T, U)(a);
- import core.stdc.string : memcpy;
- auto arr = _d_newarrayU(typeid(T[]), a.length);
- memcpy(arr.ptr, cast(const(void)*) a.ptr, T.sizeof * a.length);
- return *cast(U[]*) &arr;
+ version (D_BetterC)
+ {
+ return _dupCtfe!(T, U)(a);
+ }
+ else
+ {
+ import core.stdc.string : memcpy;
+ auto arr = _d_newarrayU(typeid(T[]), a.length);
+ memcpy(arr.ptr, cast(const(void)*) a.ptr, T.sizeof * a.length);
+ return *cast(U[]*) &arr;
+ }
}
U[] _dupCtfe(T, U)(scope T[] a)
if (__ctfe)
return _dupCtfe!(T, U)(a);
- import core.lifetime: copyEmplace;
- U[] res = () @trusted {
- auto arr = cast(U*) _d_newarrayU(typeid(T[]), a.length);
- size_t i;
- scope (failure)
- {
- import core.internal.lifetime: emplaceInitializer;
- // Initialize all remaining elements to not destruct garbage
- foreach (j; i .. a.length)
- emplaceInitializer(cast() arr[j]);
- }
- for (; i < a.length; i++)
- {
- copyEmplace(a.ptr[i], arr[i]);
- }
- return cast(U[])(arr[0..a.length]);
- } ();
+ version (D_BetterC)
+ {
+ return _dupCtfe!(T, U)(a);
+ }
+ else
+ {
+ import core.lifetime: copyEmplace;
+ U[] res = () @trusted {
+ auto arr = cast(U*) _d_newarrayU(typeid(T[]), a.length);
+ size_t i;
+ scope (failure)
+ {
+ import core.internal.lifetime: emplaceInitializer;
+ // Initialize all remaining elements to not destruct garbage
+ foreach (j; i .. a.length)
+ emplaceInitializer(cast() arr[j]);
+ }
+ for (; i < a.length; i++)
+ {
+ copyEmplace(a.ptr[i], arr[i]);
+ }
+ return cast(U[])(arr[0..a.length]);
+ } ();
- return res;
+ return res;
+ }
}
// https://issues.dlang.org/show_bug.cgi?id=22107
return func(file, line, funcname, name, size);
}
-/**
- * TraceGC wrapper generator around the runtime hook `Hook`.
- * Params:
- * Type = The type of hook to report to accumulate
- * Hook = The name hook to wrap
- */
-template TraceHook(string Type, string Hook)
+version (D_ProfileGC)
{
- const char[] TraceHook = q{
- import core.internal.array.utils : gcStatsPure, accumulatePure;
-
- pragma(inline, false);
- string name = } ~ "`" ~ Type ~ "`;" ~ q{
-
- // FIXME: use rt.tracegc.accumulator when it is accessable in the future.
- version (tracegc)
- } ~ "{\n" ~ q{
- import core.stdc.stdio;
-
- printf("%sTrace file = '%.*s' line = %d function = '%.*s' type = %.*s\n",
- } ~ "\"" ~ Hook ~ "\".ptr," ~ q{
- file.length, file.ptr,
- line,
- funcname.length, funcname.ptr,
- name.length, name.ptr
- );
- } ~ "}\n" ~ q{
- ulong currentlyAllocated = gcStatsPure().allocatedInCurrentThread;
-
- scope(exit)
- {
- ulong size = gcStatsPure().allocatedInCurrentThread - currentlyAllocated;
- if (size > 0)
- if (!accumulatePure(file, line, funcname, name, size)) {
- // This 'if' and 'assert' is needed to force the compiler to not remove the call to
- // `accumulatePure`. It really want to do that while optimizing as the function is
- // `pure` and it does not influence the result of this hook.
-
- // `accumulatePure` returns the value of `size`, which can never be zero due to the
- // previous 'if'. So this assert will never be triggered.
- assert(0);
- }
- }
- };
-}
+ /**
+ * TraceGC wrapper generator around the runtime hook `Hook`.
+ * Params:
+ * Type = The type of hook to report to accumulate
+ * Hook = The name hook to wrap
+ */
+ template TraceHook(string Type, string Hook)
+ {
+ const char[] TraceHook = q{
+ import core.internal.array.utils : gcStatsPure, accumulatePure;
+
+ pragma(inline, false);
+ string name = } ~ "`" ~ Type ~ "`;" ~ q{
+
+ // FIXME: use rt.tracegc.accumulator when it is accessable in the future.
+ version (tracegc)
+ } ~ "{\n" ~ q{
+ import core.stdc.stdio;
+
+ printf("%sTrace file = '%.*s' line = %d function = '%.*s' type = %.*s\n",
+ } ~ "\"" ~ Hook ~ "\".ptr," ~ q{
+ file.length, file.ptr,
+ line,
+ funcname.length, funcname.ptr,
+ name.length, name.ptr
+ );
+ } ~ "}\n" ~ q{
+ ulong currentlyAllocated = gcStatsPure().allocatedInCurrentThread;
+
+ scope(exit)
+ {
+ ulong size = gcStatsPure().allocatedInCurrentThread - currentlyAllocated;
+ if (size > 0)
+ if (!accumulatePure(file, line, funcname, name, size)) {
+ // This 'if' and 'assert' is needed to force the compiler to not remove the call to
+ // `accumulatePure`. It really want to do that while optimizing as the function is
+ // `pure` and it does not influence the result of this hook.
+
+ // `accumulatePure` returns the value of `size`, which can never be zero due to the
+ // previous 'if'. So this assert will never be triggered.
+ assert(0);
+ }
+ }
+ };
+ }
-/**
- * TraceGC wrapper around runtime hook `Hook`.
- * Params:
- * T = Type of hook to report to accumulate
- * Hook = The hook to wrap
- * errorMessage = The error message incase `version != D_TypeInfo`
- * file = File that called `_d_HookTraceImpl`
- * line = Line inside of `file` that called `_d_HookTraceImpl`
- * funcname = Function that called `_d_HookTraceImpl`
- * parameters = Parameters that will be used to call `Hook`
- * Bugs:
- * This function template needs be between the compiler and a much older runtime hook that bypassed safety,
- * purity, and throwabilty checks. To prevent breaking existing code, this function template
- * is temporarily declared `@trusted pure` until the implementation can be brought up to modern D expectations.
-*/
-auto _d_HookTraceImpl(T, alias Hook, string errorMessage)(string file, int line, string funcname, Parameters!Hook parameters) @trusted pure
-{
- version (D_TypeInfo)
+ /**
+ * TraceGC wrapper around runtime hook `Hook`.
+ * Params:
+ * T = Type of hook to report to accumulate
+ * Hook = The hook to wrap
+ * errorMessage = The error message incase `version != D_TypeInfo`
+ * file = File that called `_d_HookTraceImpl`
+ * line = Line inside of `file` that called `_d_HookTraceImpl`
+ * funcname = Function that called `_d_HookTraceImpl`
+ * parameters = Parameters that will be used to call `Hook`
+ * Bugs:
+ * This function template needs be between the compiler and a much older runtime hook that bypassed safety,
+ * purity, and throwabilty checks. To prevent breaking existing code, this function template
+ * is temporarily declared `@trusted pure` until the implementation can be brought up to modern D expectations.
+ */
+ auto _d_HookTraceImpl(T, alias Hook, string errorMessage)(string file, int line, string funcname, Parameters!Hook parameters) @trusted pure
{
- mixin(TraceHook!(T.stringof, __traits(identifier, Hook)));
- return Hook(parameters);
+ version (D_TypeInfo)
+ {
+ mixin(TraceHook!(T.stringof, __traits(identifier, Hook)));
+ return Hook(parameters);
+ }
+ else
+ assert(0, errorMessage);
}
- else
- assert(0, errorMessage);
}
/**
int test(int);
int test() @property;
}
- alias ov = __traits(getVirtualFunctions, Overloads, "test");
+ alias ov = __traits(getVirtualMethods, Overloads, "test");
alias F_ov0 = FunctionTypeOf!(ov[0]);
alias F_ov1 = FunctionTypeOf!(ov[1]);
alias F_ov2 = FunctionTypeOf!(ov[2]);
}
}
- import core.internal.array.utils : _d_HookTraceImpl;
+ version (D_ProfileGC)
+ {
+ import core.internal.array.utils : _d_HookTraceImpl;
- private enum errorMessage = "Cannot delete struct if compiling without support for runtime type information!";
+ private enum errorMessage = "Cannot delete struct if compiling without support for runtime type information!";
- /**
- * TraceGC wrapper around $(REF _d_delstruct, core,lifetime,_d_delstructImpl).
- *
- * Bugs:
- * This function template was ported from a much older runtime hook that
- * bypassed safety, purity, and throwabilty checks. To prevent breaking
- * existing code, this function template is temporarily declared
- * `@trusted` until the implementation can be brought up to modern D
- * expectations.
- */
- alias _d_delstructTrace = _d_HookTraceImpl!(T, _d_delstruct, errorMessage);
+ /**
+ * TraceGC wrapper around $(REF _d_delstruct, core,lifetime,_d_delstructImpl).
+ *
+ * Bugs:
+ * This function template was ported from a much older runtime hook that
+ * bypassed safety, purity, and throwabilty checks. To prevent breaking
+ * existing code, this function template is temporarily declared
+ * `@trusted` until the implementation can be brought up to modern D
+ * expectations.
+ */
+ alias _d_delstructTrace = _d_HookTraceImpl!(T, _d_delstruct, errorMessage);
+ }
}
@system pure nothrow unittest
assert(exc.refcount() == 1);
assert(e.refcount() == 1);
}
+
+/**
+ * Create a new class instance.
+ * Allocates memory and sets fields to their initial value, but does not call a
+ * constructor.
+ * ---
+ * new C() // _d_newclass!(C)()
+ * ---
+ * Returns: newly created object
+ */
+T _d_newclassT(T)() @trusted
+if (is(T == class))
+{
+ import core.internal.traits : hasIndirections;
+ import core.exception : onOutOfMemoryError;
+ import core.memory : GC, pureMalloc;
+
+ alias BlkAttr = GC.BlkAttr;
+
+ auto init = __traits(initSymbol, T);
+ void* p;
+
+ static if (__traits(getLinkage, T) == "Windows")
+ {
+ p = pureMalloc(init.length);
+ if (!p)
+ onOutOfMemoryError();
+ }
+ else
+ {
+ BlkAttr attr = BlkAttr.NONE;
+
+ /* `extern(C++)`` classes don't have a classinfo pointer in their vtable,
+ * so the GC can't finalize them.
+ */
+ static if (__traits(hasMember, T, "__dtor") && __traits(getLinkage, T) != "C++")
+ attr |= BlkAttr.FINALIZE;
+ static if (!hasIndirections!T)
+ attr |= BlkAttr.NO_SCAN;
+
+ p = GC.malloc(init.length, attr, typeid(T));
+ debug(PRINTF) printf(" p = %p\n", p);
+ }
+
+ debug(PRINTF)
+ {
+ printf("p = %p\n", p);
+ printf("init.ptr = %p, len = %llu\n", init.ptr, cast(ulong)init.length);
+ printf("vptr = %p\n", *cast(void**) init);
+ printf("vtbl[0] = %p\n", (*cast(void***) init)[0]);
+ printf("vtbl[1] = %p\n", (*cast(void***) init)[1]);
+ printf("init[0] = %x\n", (cast(uint*) init)[0]);
+ printf("init[1] = %x\n", (cast(uint*) init)[1]);
+ printf("init[2] = %x\n", (cast(uint*) init)[2]);
+ printf("init[3] = %x\n", (cast(uint*) init)[3]);
+ printf("init[4] = %x\n", (cast(uint*) init)[4]);
+ }
+
+ // initialize it
+ p[0 .. init.length] = init[];
+
+ debug(PRINTF) printf("initialization done\n");
+ return cast(T) p;
+}
+
+// Test allocation
+@safe unittest
+{
+ class C { }
+ C c = _d_newclassT!C();
+
+ assert(c !is null);
+}
+
+// Test initializers
+@safe unittest
+{
+ {
+ class C { int x, y; }
+ C c = _d_newclassT!C();
+
+ assert(c.x == 0);
+ assert(c.y == 0);
+ }
+ {
+ class C { int x = 2, y = 3; }
+ C c = _d_newclassT!C();
+
+ assert(c.x == 2);
+ assert(c.y == 3);
+ }
+}
+
+T _d_newclassTTrace(T)(string file, int line, string funcname) @trusted
+{
+ version (D_TypeInfo)
+ {
+ import core.internal.array.utils: TraceHook, gcStatsPure, accumulatePure;
+ mixin(TraceHook!(T.stringof, "_d_newclassT"));
+
+ return _d_newclassT!T();
+ }
+ else
+ assert(0, "Cannot create new class if compiling without support for runtime type information!");
+}
// make it more difficult to call the function again, manually.
private void initialize();
pragma(crt_constructor)
-pragma(mangle, `_D` ~ initialize.mangleof)
-private extern (C) void initialize() @system
+pragma(mangle, initialize.mangleof)
+private extern (C) void _initialize() @system
{
version (Posix)
{
alias c_complex_double = __c_complex_double;
alias c_complex_real = __c_complex_real;
}
+
+
+// Returns the mangled name for the 64-bit time_t versions of
+// functions affected by musl's transition to 64-bit time_t.
+// https://musl.libc.org/time64.html
+version (CRuntime_Musl)
+{
+ version (CRuntime_Musl_Pre_Time64)
+ enum muslRedirTime64 = false;
+ else
+ {
+ // time_t was defined as a C long in older Musl versions.
+ enum muslRedirTime64 = (c_long.sizeof == 4);
+ }
+}
+else
+ enum muslRedirTime64 = false;
+
+package(core) template muslRedirTime64Mangle(string name, string redirectedName)
+{
+ static if (muslRedirTime64)
+ enum muslRedirTime64Mangle = redirectedName;
+ else
+ enum muslRedirTime64Mangle = name;
+}
@nogc:
///
+pragma(mangle, muslRedirTime64Mangle!("difftime", "__difftime64"))
pure double difftime(time_t time1, time_t time0); // MT-Safe
///
+pragma(mangle, muslRedirTime64Mangle!("mktime", "__mktime64"))
@system time_t mktime(scope tm* timeptr); // @system: MT-Safe env locale
///
+pragma(mangle, muslRedirTime64Mangle!("time", "__time64"))
time_t time(scope time_t* timer);
///
@system char* asctime(const scope tm* timeptr); // @system: MT-Unsafe race:asctime locale
///
+pragma(mangle, muslRedirTime64Mangle!("ctime", "__ctime64"))
@system char* ctime(const scope time_t* timer); // @system: MT-Unsafe race:tmbuf race:asctime env locale
///
+pragma(mangle, muslRedirTime64Mangle!("gmtime", "__gmtime64"))
@system tm* gmtime(const scope time_t* timer); // @system: MT-Unsafe race:tmbuf env locale
///
+pragma(mangle, muslRedirTime64Mangle!("localtime", "__localtime64"))
@system tm* localtime(const scope time_t* timer); // @system: MT-Unsafe race:tmbuf env locale
///
@system size_t strftime(scope char* s, size_t maxsize, const scope char* format, const scope tm* timeptr); // @system: MT-Safe env locale
EVFILT_EXCEPT = -15,
}
-extern(D) void EV_SET(kevent_t* kevp, typeof(kevent_t.tupleof) args)
+extern(D) void EV_SET()(kevent_t* kevp, typeof(kevent_t.tupleof) args)
{
*kevp = kevent_t(args);
}
-extern(D) void EV_SET64(kevent64_s* kevp, typeof(kevent64_s.tupleof) args)
+extern(D) void EV_SET64()(kevent64_s* kevp, typeof(kevent64_s.tupleof) args)
{
*kevp = kevent64_s(args);
}
*/
module core.sys.posix.aio;
+import core.stdc.config;
import core.sys.posix.signal;
import core.sys.posix.sys.types;
int aio_fsync(int op, aiocb* aiocbp);
int aio_error(const(aiocb)* aiocbp);
ssize_t aio_return(aiocb* aiocbp);
+ pragma(mangle, muslRedirTime64Mangle!("aio_suspend", "__aio_suspend_time64"))
int aio_suspend(const(aiocb*)* aiocb_list, int nitems, const(timespec)* timeout);
int aio_cancel(int fd, aiocb* aiocbp);
int lio_listio(int mode, const(aiocb*)* aiocb_list, int nitems, sigevent* sevp);
void* dli_saddr;
}
}
+else
+version (CRuntime_Musl)
+{
+ enum RTLD_LAZY = 1;
+ enum RTLD_NOW = 2;
+ enum RTLD_NOLOAD = 4;
+ enum RTLD_NODELETE = 4096;
+ enum RTLD_GLOBAL = 256;
+ enum RTLD_LOCAL = 0;
+
+ enum RTLD_NEXT = cast(void *)-1;
+ enum RTLD_DEFAULT = cast(void *)0;
+
+ enum RTLD_DI_LINKMAP = 2;
+
+ int dlclose(void *);
+ char *dlerror();
+ void *dlopen(const(char) *, int);
+
+ pragma(mangle, muslRedirTime64Mangle!("dlsym", "__dlsym_time64"))
+ void *dlsym(void *__restrict, const(char) *__restrict);
+
+ struct Dl_info
+ {
+ const(char)* dli_fname;
+ void* dli_fbase;
+ const(char)* dli_sname;
+ void* dli_saddr;
+ }
+ int dladdr(const(void) *, Dl_info *);
+ int dlinfo(void *, int, void *);
+}
else version (Darwin)
{
enum RTLD_LAZY = 0x00001;
* On success, mq_receive() returns the number of bytes in the received
* message; on error, -1 is returned, with errno set to indicate the error
*/
+pragma(mangle, muslRedirTime64Mangle!("mq_timedreceive", "__mq_timedreceive_time64"))
ssize_t mq_timedreceive (mqd_t mqdes, char* msg_ptr, size_t msg_len,
uint* msg_prio, const(timespec)* abs_timeout);
* with errno set to indicate the error.
*
*/
+pragma(mangle, muslRedirTime64Mangle!("mq_timedsend", "__mq_timedsend_time64"))
int mq_timedsend (mqd_t mqdes, const(char)* msg_ptr, size_t msg_len,
uint msg_prio, const(timespec)* abs_timeout);
}
// macros
- extern (D) int IN6_IS_ADDR_UNSPECIFIED( in6_addr* addr ) pure
+ extern (D) int IN6_IS_ADDR_UNSPECIFIED( const scope in6_addr* addr ) pure
{
return (cast(uint32_t*) addr)[0] == 0 &&
(cast(uint32_t*) addr)[1] == 0 &&
(cast(uint32_t*) addr)[3] == 0;
}
- extern (D) int IN6_IS_ADDR_LOOPBACK( in6_addr* addr ) pure
+ extern (D) int IN6_IS_ADDR_LOOPBACK( const scope in6_addr* addr ) pure
{
return (cast(uint32_t*) addr)[0] == 0 &&
(cast(uint32_t*) addr)[1] == 0 &&
(cast(uint32_t*) addr)[3] == htonl( 1 );
}
- extern (D) int IN6_IS_ADDR_MULTICAST( in6_addr* addr ) pure
+ extern (D) int IN6_IS_ADDR_MULTICAST( const scope in6_addr* addr ) pure
{
return (cast(uint8_t*) addr)[0] == 0xff;
}
- extern (D) int IN6_IS_ADDR_LINKLOCAL( in6_addr* addr ) pure
+ extern (D) int IN6_IS_ADDR_LINKLOCAL( const scope in6_addr* addr ) pure
{
return ((cast(uint32_t*) addr)[0] & htonl( 0xffc00000 )) == htonl( 0xfe800000 );
}
- extern (D) int IN6_IS_ADDR_SITELOCAL( in6_addr* addr ) pure
+ extern (D) int IN6_IS_ADDR_SITELOCAL( const scope in6_addr* addr ) pure
{
return ((cast(uint32_t*) addr)[0] & htonl( 0xffc00000 )) == htonl( 0xfec00000 );
}
- extern (D) int IN6_IS_ADDR_V4MAPPED( in6_addr* addr ) pure
+ extern (D) int IN6_IS_ADDR_V4MAPPED( const scope in6_addr* addr ) pure
{
return (cast(uint32_t*) addr)[0] == 0 &&
(cast(uint32_t*) addr)[1] == 0 &&
(cast(uint32_t*) addr)[2] == htonl( 0xffff );
}
- extern (D) int IN6_IS_ADDR_V4COMPAT( in6_addr* addr ) pure
+ extern (D) int IN6_IS_ADDR_V4COMPAT( const scope in6_addr* addr ) pure
{
return (cast(uint32_t*) addr)[0] == 0 &&
(cast(uint32_t*) addr)[1] == 0 &&
ntohl( (cast(uint32_t*) addr)[3] ) > 1;
}
- extern (D) int IN6_IS_ADDR_MC_NODELOCAL( in6_addr* addr ) pure
+ extern (D) int IN6_IS_ADDR_MC_NODELOCAL( const scope in6_addr* addr ) pure
{
return IN6_IS_ADDR_MULTICAST( addr ) &&
((cast(uint8_t*) addr)[1] & 0xf) == 0x1;
}
- extern (D) int IN6_IS_ADDR_MC_LINKLOCAL( in6_addr* addr ) pure
+ extern (D) int IN6_IS_ADDR_MC_LINKLOCAL( const scope in6_addr* addr ) pure
{
return IN6_IS_ADDR_MULTICAST( addr ) &&
((cast(uint8_t*) addr)[1] & 0xf) == 0x2;
}
- extern (D) int IN6_IS_ADDR_MC_SITELOCAL( in6_addr* addr ) pure
+ extern (D) int IN6_IS_ADDR_MC_SITELOCAL( const scope in6_addr* addr ) pure
{
return IN6_IS_ADDR_MULTICAST(addr) &&
((cast(uint8_t*) addr)[1] & 0xf) == 0x5;
}
- extern (D) int IN6_IS_ADDR_MC_ORGLOCAL( in6_addr* addr ) pure
+ extern (D) int IN6_IS_ADDR_MC_ORGLOCAL( const scope in6_addr* addr ) pure
{
return IN6_IS_ADDR_MULTICAST( addr) &&
((cast(uint8_t*) addr)[1] & 0xf) == 0x8;
}
- extern (D) int IN6_IS_ADDR_MC_GLOBAL( in6_addr* addr ) pure
+ extern (D) int IN6_IS_ADDR_MC_GLOBAL( const scope in6_addr* addr ) pure
{
return IN6_IS_ADDR_MULTICAST( addr ) &&
((cast(uint8_t*) addr)[1] & 0xf) == 0xe;
}
// macros
- extern (D) int IN6_IS_ADDR_UNSPECIFIED( in6_addr* addr ) pure
+ extern (D) int IN6_IS_ADDR_UNSPECIFIED( const scope in6_addr* addr ) pure
{
return (cast(uint32_t*) addr)[0] == 0 &&
(cast(uint32_t*) addr)[1] == 0 &&
(cast(uint32_t*) addr)[3] == 0;
}
- extern (D) int IN6_IS_ADDR_LOOPBACK( in6_addr* addr ) pure
+ extern (D) int IN6_IS_ADDR_LOOPBACK( const scope in6_addr* addr ) pure
{
return (cast(uint32_t*) addr)[0] == 0 &&
(cast(uint32_t*) addr)[1] == 0 &&
(cast(uint32_t*) addr)[3] == ntohl( 1 );
}
- extern (D) int IN6_IS_ADDR_MULTICAST( in6_addr* addr ) pure
+ extern (D) int IN6_IS_ADDR_MULTICAST( const scope in6_addr* addr ) pure
{
return addr.s6_addr[0] == 0xff;
}
- extern (D) int IN6_IS_ADDR_LINKLOCAL( in6_addr* addr ) pure
+ extern (D) int IN6_IS_ADDR_LINKLOCAL( const scope in6_addr* addr ) pure
{
return addr.s6_addr[0] == 0xfe && (addr.s6_addr[1] & 0xc0) == 0x80;
}
- extern (D) int IN6_IS_ADDR_SITELOCAL( in6_addr* addr ) pure
+ extern (D) int IN6_IS_ADDR_SITELOCAL( const scope in6_addr* addr ) pure
{
return addr.s6_addr[0] == 0xfe && (addr.s6_addr[1] & 0xc0) == 0xc0;
}
- extern (D) int IN6_IS_ADDR_V4MAPPED( in6_addr* addr ) pure
+ extern (D) int IN6_IS_ADDR_V4MAPPED( const scope in6_addr* addr ) pure
{
return (cast(uint32_t*) addr)[0] == 0 &&
(cast(uint32_t*) addr)[1] == 0 &&
(cast(uint32_t*) addr)[2] == ntohl( 0x0000ffff );
}
- extern (D) int IN6_IS_ADDR_V4COMPAT( in6_addr* addr ) pure
+ extern (D) int IN6_IS_ADDR_V4COMPAT( const scope in6_addr* addr ) pure
{
return (cast(uint32_t*) addr)[0] == 0 &&
(cast(uint32_t*) addr)[1] == 0 &&
(cast(uint32_t*) addr)[3] != ntohl( 1 );
}
- extern (D) int IN6_IS_ADDR_MC_NODELOCAL( in6_addr* addr ) pure
+ extern (D) int IN6_IS_ADDR_MC_NODELOCAL( const scope in6_addr* addr ) pure
{
return IN6_IS_ADDR_MULTICAST( addr ) &&
((cast(uint8_t*) addr)[1] & 0xf) == 0x1;
}
- extern (D) int IN6_IS_ADDR_MC_LINKLOCAL( in6_addr* addr ) pure
+ extern (D) int IN6_IS_ADDR_MC_LINKLOCAL( const scope in6_addr* addr ) pure
{
return IN6_IS_ADDR_MULTICAST( addr ) &&
((cast(uint8_t*) addr)[1] & 0xf) == 0x2;
}
- extern (D) int IN6_IS_ADDR_MC_SITELOCAL( in6_addr* addr ) pure
+ extern (D) int IN6_IS_ADDR_MC_SITELOCAL( const scope in6_addr* addr ) pure
{
return IN6_IS_ADDR_MULTICAST(addr) &&
((cast(uint8_t*) addr)[1] & 0xf) == 0x5;
}
- extern (D) int IN6_IS_ADDR_MC_ORGLOCAL( in6_addr* addr ) pure
+ extern (D) int IN6_IS_ADDR_MC_ORGLOCAL( const scope in6_addr* addr ) pure
{
return IN6_IS_ADDR_MULTICAST( addr) &&
((cast(uint8_t*) addr)[1] & 0xf) == 0x8;
}
- extern (D) int IN6_IS_ADDR_MC_GLOBAL( in6_addr* addr ) pure
+ extern (D) int IN6_IS_ADDR_MC_GLOBAL( const scope in6_addr* addr ) pure
{
return IN6_IS_ADDR_MULTICAST( addr ) &&
((cast(uint8_t*) addr)[1] & 0xf) == 0xe;
{
int sched_priority;
int __reserved1;
- timespec[2] __reserved2;
+ static if (muslRedirTime64)
+ c_long[2] __reserved2;
+ else
+ timespec[2] __reserved2;
int __reserved3;
}
}
{
int sched_get_priority_max(int);
int sched_get_priority_min(int);
+ pragma(mangle, muslRedirTime64Mangle!("sched_rr_get_interval", "__sched_rr_get_interval_time64"))
int sched_rr_get_interval(pid_t, timespec*);
}
else version (CRuntime_UClibc)
}
else version (CRuntime_Musl)
{
+ pragma(mangle, muslRedirTime64Mangle!("sem_timedwait", "__sem_timedwait_time64"))
int sem_timedwait(sem_t*, const scope timespec*);
}
else version (CRuntime_UClibc)
else version (CRuntime_Musl)
{
int sigqueue(pid_t, int, const sigval);
+ pragma(mangle, muslRedirTime64Mangle!("sigtimedwait", "__sigtimedwait_time64"))
int sigtimedwait(const scope sigset_t*, siginfo_t*, const scope timespec*);
int sigwaitinfo(const scope sigset_t*, siginfo_t*);
}
int setrlimit(int, const scope rlimit*);
alias getrlimit getrlimit64;
alias setrlimit setrlimit64;
+ pragma(mangle, muslRedirTime64Mangle!("getrusage", "__getrusage_time64"))
int getrusage(int, rusage*);
}
else version (Solaris)
{
fdset.fds_bits[0 .. $] = 0;
}
+ pragma(mangle, muslRedirTime64Mangle!("pselect", "__pselect_time64"))
int pselect(int, fd_set*, fd_set*, fd_set*, const scope timespec*, const scope sigset_t*);
+ pragma(mangle, muslRedirTime64Mangle!("select", "__select_time64"))
int select(int, fd_set*, fd_set*, fd_set*, timeval*);
}
else version (CRuntime_UClibc)
}
else version (CRuntime_Musl)
{
- alias __mode_t = uint;
enum {
S_IRUSR = 0x100, // octal 0400
S_IWUSR = 0x080, // octal 0200
}
else version (CRuntime_Musl)
{
+ pragma(mangle, muslRedirTime64Mangle!("stat", "__stat_time64"))
int stat(const scope char*, stat_t*);
+ pragma(mangle, muslRedirTime64Mangle!("fstat", "__fstat_time64"))
int fstat(int, stat_t*);
+ pragma(mangle, muslRedirTime64Mangle!("lstat", "__lstat_time64"))
int lstat(const scope char*, stat_t*);
alias fstat fstat64;
time_t tv_sec;
suseconds_t tv_usec;
}
+ pragma(mangle, muslRedirTime64Mangle!("gettimeofday", "__gettimeofday_time64"))
int gettimeofday(timeval*, void*);
+ pragma(mangle, muslRedirTime64Mangle!("utimes", "__utimes_time64"))
int utimes(const scope char*, ref const(timeval)[2]);
}
else version (Darwin)
}
else version (CRuntime_Musl)
{
+ pragma(mangle, muslRedirTime64Mangle!("timegm", "__timegm_time64"))
time_t timegm(tm*);
}
else version (CRuntime_UClibc)
int nanosleep(const scope timespec*, timespec*);
+ pragma(mangle, muslRedirTime64Mangle!("clock_getres", "__clock_getres_time64"))
int clock_getres(clockid_t, timespec*);
+ pragma(mangle, muslRedirTime64Mangle!("clock_gettime", "__clock_gettime64"))
int clock_gettime(clockid_t, timespec*);
+ pragma(mangle, muslRedirTime64Mangle!("clock_settime", "__clock_settime64"))
int clock_settime(clockid_t, const scope timespec*);
+ pragma(mangle, muslRedirTime64Mangle!("clock_nanosleep", "__clock_nanosleep_time64"))
int clock_nanosleep(clockid_t, int, const scope timespec*, timespec*);
int clock_getcpuclockid(pid_t, clockid_t *);
int timer_create(clockid_t, sigevent*, timer_t*);
int timer_delete(timer_t);
+ pragma(mangle, muslRedirTime64Mangle!("timer_gettime", "__timer_gettime64"))
int timer_gettime(timer_t, itimerspec*);
+ pragma(mangle, muslRedirTime64Mangle!("timer_settime", "__timer_settime64"))
int timer_settime(timer_t, int, const scope itimerspec*, itimerspec*);
int timer_getoverrun(timer_t);
}
else version (CRuntime_Musl)
{
char* asctime_r(const scope tm*, char*);
+ pragma(mangle, muslRedirTime64Mangle!("ctime_r", "__ctime64_r"))
char* ctime_r(const scope time_t*, char*);
+ pragma(mangle, muslRedirTime64Mangle!("gmtime_r", "__gmtime64_r"))
tm* gmtime_r(const scope time_t*, tm*);
+ pragma(mangle, muslRedirTime64Mangle!("localtime_r", "__localtime64_r"))
tm* localtime_r(const scope time_t*, tm*);
}
else version (CRuntime_UClibc)
time_t modtime;
}
+ pragma(mangle, muslRedirTime64Mangle!("utime", "__utime64"))
int utime(const scope char*, const scope utimbuf*);
}
else version (Darwin)
extern(Windows) alias USHORT function(ULONG FramesToSkip, ULONG FramesToCapture, PVOID *BackTrace, PULONG BackTraceHash) @nogc RtlCaptureStackBackTraceFunc;
private __gshared RtlCaptureStackBackTraceFunc RtlCaptureStackBackTrace;
+private __gshared CRITICAL_SECTION mutex; // cannot use core.sync.mutex.Mutex unfortunately (cyclic dependency...)
private __gshared immutable bool initialized;
skip += INTERNALFRAMES;
}
- if ( initialized )
+ if (initialized)
m_trace = trace(tracebuf[], skip, context);
}
- int opApply( scope int delegate(ref const(char[])) dg ) const
+ override int opApply( scope int delegate(ref const(char[])) dg ) const
{
return opApply( (ref size_t, ref const(char[]) buf)
{
}
- int opApply( scope int delegate(ref size_t, ref const(char[])) dg ) const
+ override int opApply( scope int delegate(ref size_t, ref const(char[])) dg ) const
{
int result;
foreach ( i, e; resolve(m_trace) )
/// ditto
static ulong[] trace(ulong[] buffer, size_t skip = 0, CONTEXT* context = null) @nogc
{
- synchronized( typeid(StackTrace) )
- {
- return traceNoSync(buffer, skip, context);
- }
+ EnterCriticalSection(&mutex);
+ scope(exit) LeaveCriticalSection(&mutex);
+
+ return traceNoSync(buffer, skip, context);
}
/**
*/
@trusted static char[][] resolve(const(ulong)[] addresses)
{
- synchronized( typeid(StackTrace) )
- {
- return resolveNoSync(addresses);
- }
+ // FIXME: make @nogc to avoid having to disable resolution within finalizers
+ import core.memory : GC;
+ if (GC.inFinalizer)
+ return null;
+
+ EnterCriticalSection(&mutex);
+ scope(exit) LeaveCriticalSection(&mutex);
+
+ return resolveNoSync(addresses);
}
private:
dbghelp.SymRegisterCallback64(hProcess, &FixupDebugHeader, 0);
+ InitializeCriticalSection(&mutex);
initialized = true;
}
// FIXME:
//alias void va_list;
import core.stdc.stdarg : va_list;
+import core.stdc.string : memset, memcpy, memmove;
// COMMPROP structure, used by GetCommProperties()
BOOL CopyFileExA(LPCSTR, LPCSTR, LPPROGRESS_ROUTINE, LPVOID, LPBOOL, DWORD);
BOOL CopyFileExW(LPCWSTR, LPCWSTR, LPPROGRESS_ROUTINE, LPVOID, LPBOOL, DWORD);
- /+ FIXME
- alias memmove RtlMoveMemory;
- alias memcpy RtlCopyMemory;
+ alias RtlMoveMemory = memmove;
+ alias RtlCopyMemory = memcpy;
+ pragma(inline, true) void RtlFillMemory(PVOID Destination, SIZE_T Length, BYTE Fill) { memset(Destination, Fill, Length); }
+ pragma(inline, true) void RtlZeroMemory(PVOID Destination, SIZE_T Length) { memset(Destination, 0, Length); }
+ alias MoveMemory = RtlMoveMemory;
+ alias CopyMemory = RtlCopyMemory;
+ alias FillMemory = RtlFillMemory;
+ alias ZeroMemory = RtlZeroMemory;
- void RtlFillMemory(PVOID dest, SIZE_T len, BYTE fill) {
- memset(dest, fill, len);
- }
-
- void RtlZeroMemory(PVOID dest, SIZE_T len) {
- RtlFillMemory(dest, len, 0);
- }
-
- alias RtlMoveMemory MoveMemory;
- alias RtlCopyMemory CopyMemory;
- alias RtlFillMemory FillMemory;
- alias RtlZeroMemory ZeroMemory;
- +/
BOOL CreateDirectoryA(LPCSTR, LPSECURITY_ATTRIBUTES);
BOOL CreateDirectoryW(LPCWSTR, LPSECURITY_ATTRIBUTES);
BOOL CreateDirectoryExA(LPCSTR, LPCSTR, LPSECURITY_ATTRIBUTES);
import core.thread.types;
import core.thread.context;
+import core.memory : pageSize;
+
///////////////////////////////////////////////////////////////////////////////
// Fiber Platform Detection
///////////////////////////////////////////////////////////////////////////////
version (X86_64)
// libunwind on macOS 11 now requires more stack space than 16k, so
// default to a larger stack size. This is only applied to X86 as
- // the PAGESIZE is still 4k, however on AArch64 it is 16k.
+ // the pageSize is still 4k, however on AArch64 it is 16k.
enum defaultStackPages = 8;
else
enum defaultStackPages = 4;
* In:
* fn must not be null.
*/
- this( void function() fn, size_t sz = PAGESIZE * defaultStackPages,
- size_t guardPageSize = PAGESIZE ) nothrow
+ this( void function() fn, size_t sz = pageSize * defaultStackPages,
+ size_t guardPageSize = pageSize ) nothrow
in
{
assert( fn );
* In:
* dg must not be null.
*/
- this( void delegate() dg, size_t sz = PAGESIZE * defaultStackPages,
- size_t guardPageSize = PAGESIZE ) nothrow
+ this( void delegate() dg, size_t sz = pageSize * defaultStackPages,
+ size_t guardPageSize = pageSize ) nothrow
{
allocStack( sz, guardPageSize );
reset( cast(void delegate() const) dg );
}
do
{
- // adjust alloc size to a multiple of PAGESIZE
- sz += PAGESIZE - 1;
- sz -= sz % PAGESIZE;
+ // adjust alloc size to a multiple of pageSize
+ sz += pageSize - 1;
+ sz -= sz % pageSize;
// NOTE: This instance of Thread.Context is dynamic so Fiber objects
// can be collected by the GC so long as no user level references
import core.thread.context;
import core.thread.types;
import core.atomic;
-import core.memory : GC;
+import core.memory : GC, pageSize;
import core.time;
import core.exception : onOutOfMemoryError;
import core.internal.traits : externDFunc;
unittest
{
- // use >PAGESIZE to avoid stack overflow (e.g. in an syscall)
+ // use >pageSize to avoid stack overflow (e.g. in an syscall)
auto thr = new Thread(function{}, 4096 + 1).start();
thr.join();
}
}
}
- // stack size must be a multiple of PAGESIZE
- sz = ((sz + PAGESIZE - 1) & ~(PAGESIZE - 1));
+ // stack size must be a multiple of pageSize
+ sz = ((sz + pageSize - 1) & ~(pageSize - 1));
return sz;
}
package
{
- static immutable size_t PAGESIZE;
version (Posix) static immutable size_t PTHREAD_STACK_MIN;
}
shared static this()
{
- version (Windows)
- {
- import core.sys.windows.winbase;
-
- SYSTEM_INFO info;
- GetSystemInfo(&info);
-
- PAGESIZE = info.dwPageSize;
- assert(PAGESIZE < int.max);
- }
- else version (Posix)
+ version (Posix)
{
import core.sys.posix.unistd;
- PAGESIZE = cast(size_t)sysconf(_SC_PAGESIZE);
PTHREAD_STACK_MIN = cast(size_t)sysconf(_SC_THREAD_STACK_MIN);
}
- else
- {
- static assert(0, "unimplemented");
- }
}
* }
* ---
*/
- deprecated static Object factory(string classname)
+ static Object factory(string classname)
{
auto ci = TypeInfo_Class.find(classname);
if (ci)
return null;
}
- deprecated @system unittest
+ @system unittest
{
Object valid_obj = Object.factory("object.Object");
Object invalid_obj = Object.factory("object.__this_class_doesnt_exist__");
int func(int a, int b);
}
- alias functionTypes = typeof(__traits(getVirtualFunctions, C, "func"));
+ alias functionTypes = typeof(__traits(getVirtualMethods, C, "func"));
assert(typeid(functionTypes[0]).toString() == "void function()");
assert(typeid(functionTypes[1]).toString() == "void function(int)");
assert(typeid(functionTypes[2]).toString() == "int function(int, int)");
void func(int a);
}
- alias functionTypes = typeof(__traits(getVirtualFunctions, C, "func"));
+ alias functionTypes = typeof(__traits(getVirtualMethods, C, "func"));
Object obj = typeid(functionTypes[0]);
assert(obj.opEquals(typeid(functionTypes[0])));
assert("k1" !in aa);
}
-// Issue 20559
-@system unittest
-{
- static class Foo
- {
- int[string] aa;
- alias aa this;
- }
-
- auto v = new Foo();
- v["Hello World"] = 42;
- v.clear;
- assert("Hello World" !in v);
-
- // Test for T*
- static assert(!__traits(compiles, (&v).clear));
- static assert( __traits(compiles, (*(&v)).clear));
-}
-
/***********************************
* Reorganizes the associative array in place so that lookups are more
* efficient.
destroy!true(new C());
}
-@system unittest
-{
- // class with an `alias this`
- class A
- {
- static int dtorCount;
- ~this()
- {
- dtorCount++;
- }
- }
-
- class B
- {
- A a;
- alias a this;
- this()
- {
- a = new A;
- }
- static int dtorCount;
- ~this()
- {
- dtorCount++;
- }
- }
- auto b = new B;
- assert(A.dtorCount == 0);
- assert(B.dtorCount == 0);
- destroy(b);
- assert(A.dtorCount == 0);
- assert(B.dtorCount == 1);
-
- auto a = new A;
- destroy(a);
- assert(A.dtorCount == 1);
-}
-
@system unittest
{
interface I { }
}
}
-// https://issues.dlang.org/show_bug.cgi?id=19218
-@system unittest
-{
- static struct S
- {
- static dtorCount = 0;
- ~this() { ++dtorCount; }
- }
-
- static interface I
- {
- ref S[3] getArray();
- alias getArray this;
- }
-
- static class C : I
- {
- static dtorCount = 0;
- ~this() { ++dtorCount; }
-
- S[3] a;
- alias a this;
-
- ref S[3] getArray() { return a; }
- }
-
- C c = new C();
- destroy(c);
- assert(S.dtorCount == 3);
- assert(C.dtorCount == 1);
-
- I i = new C();
- destroy(i);
- assert(S.dtorCount == 6);
- assert(C.dtorCount == 2);
-}
-
/// ditto
void destroy(bool initialize = true, T)(ref T obj)
if (!is(T == struct) && !is(T == interface) && !is(T == class) && !__traits(isStaticArray, T))
public import core.internal.entrypoint : _d_cmain;
public import core.internal.array.appending : _d_arrayappendT;
-public import core.internal.array.appending : _d_arrayappendTTrace;
+version (D_ProfileGC)
+ public import core.internal.array.appending : _d_arrayappendTTrace;
public import core.internal.array.appending : _d_arrayappendcTXImpl;
public import core.internal.array.comparison : __cmp;
public import core.internal.array.equality : __equals;
public import core.lifetime : _d_delstructImpl;
public import core.lifetime : _d_newThrowable;
+public import core.lifetime : _d_newclassT;
+public import core.lifetime : _d_newclassTTrace;
public @trusted @nogc nothrow pure extern (C) void _d_delThrowable(scope Throwable);
-e5a521ab2bddfa0a42ecf371910ffe6a2fe0a03a
+454dff14dcbd005f9550302c5836ef8e06ab663a
The first line of this file holds the git revision number of the last
merge done from the dlang/phobos repository.
front to back, even if it is a bidirectional range too.
*/
auto joiner(RoR, Separator)(RoR r, Separator sep)
-if (isInputRange!RoR && isInputRange!(ElementType!RoR)
- && isForwardRange!Separator
- && is(ElementType!Separator : ElementType!(ElementType!RoR)))
{
+ static assert(isInputRange!RoR, "The type of RoR '", RoR.stringof
+ , " must be an InputRange (isInputRange!", RoR.stringof, ").");
+ static assert(isInputRange!(ElementType!RoR), "The ElementyType of RoR '"
+ , ElementType!(RoR).stringof, "' must be an InputRange "
+ , "(isInputRange!(ElementType!(", RoR.stringof , "))).");
+ static assert(isForwardRange!Separator, "The type of the Seperator '"
+ , Seperator.stringof, "' must be a ForwardRange (isForwardRange!("
+ , Seperator.stringof, ")).");
+ static assert(is(ElementType!Separator : ElementType!(ElementType!RoR))
+ , "The type of the elements of the separator range does not match "
+ , "the type of the elements that are joined. Separator type '"
+ , ElementType!(Separator).stringof, "' is not implicitly"
+ , "convertible to range element type '"
+ , ElementType!(ElementType!RoR).stringof, "' (is(ElementType!"
+ , Separator.stringof, " : ElementType!(ElementType!", RoR.stringof
+ , "))).");
+
static struct Result
{
private RoR _items;
$(SUBREF sorting, multiSort)
$(SUBREF sorting, nextEvenPermutation)
$(SUBREF sorting, nextPermutation)
+ $(SUBREF sorting, nthPermutation)
$(SUBREF sorting, partialSort)
$(SUBREF sorting, partition)
$(SUBREF sorting, partition3)
$(REF binaryFun, std,functional)
*/
SortedRange!(Range, less)
-sort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable,
- Range)(Range r)
-if (((ss == SwapStrategy.unstable && (hasSwappableElements!Range ||
- hasAssignableElements!Range)) ||
- (ss != SwapStrategy.unstable && hasAssignableElements!Range)) &&
- isRandomAccessRange!Range &&
- hasSlicing!Range &&
- hasLength!Range)
+sort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range)
+(Range r)
/+ Unstable sorting uses the quicksort algorithm, which uses swapAt,
which either uses swap(...), requiring swappable elements, or just
swaps using assignment.
requiring assignable elements. +/
{
import std.range : assumeSorted;
- alias lessFun = binaryFun!(less);
- alias LessRet = typeof(lessFun(r.front, r.front)); // instantiate lessFun
- static if (is(LessRet == bool))
+ static if (ss == SwapStrategy.unstable)
{
- static if (ss == SwapStrategy.unstable)
- quickSortImpl!(lessFun)(r, r.length);
- else //use Tim Sort for semistable & stable
- TimSortImpl!(lessFun, Range).sort(r, null);
-
- assert(isSorted!lessFun(r), "Failed to sort range of type " ~ Range.stringof);
+ static assert(hasSwappableElements!Range || hasAssignableElements!Range,
+ "When using SwapStrategy.unstable, the passed Range '"
+ ~ Range.stringof ~ "' must"
+ ~ " either fulfill hasSwappableElements, or"
+ ~ " hasAssignableElements, both were not the case");
}
else
{
- static assert(false, "Invalid predicate passed to sort: " ~ less.stringof);
+ static assert(hasAssignableElements!Range, "When using a SwapStrategy"
+ ~ " != unstable, the"
+ ~ " passed Range '" ~ Range.stringof ~ "' must fulfill"
+ ~ " hasAssignableElements, which it did not");
}
+
+ static assert(isRandomAccessRange!Range, "The passed Range '"
+ ~ Range.stringof ~ "' must be a Random AccessRange "
+ ~ "(isRandomAccessRange)");
+
+ static assert(hasSlicing!Range, "The passed Range '"
+ ~ Range.stringof ~ "' must allow Slicing (hasSlicing)");
+
+ static assert(hasLength!Range, "The passed Range '"
+ ~ Range.stringof ~ "' must have a length (hasLength)");
+
+ alias lessFun = binaryFun!(less);
+ alias LessRet = typeof(lessFun(r.front, r.front)); // instantiate lessFun
+
+ static assert(is(LessRet == bool), "The return type of the template"
+ ~ " argument 'less' when used with the binaryFun!less template"
+ ~ " must be a bool. This is not the case, the returned type is '"
+ ~ LessRet.stringof ~ "'");
+
+ static if (ss == SwapStrategy.unstable)
+ quickSortImpl!(lessFun)(r, r.length);
+ else //use Tim Sort for semistable & stable
+ TimSortImpl!(lessFun, Range).sort(r, null);
+
+ assert(isSorted!lessFun(r), "Failed to sort range of type " ~ Range.stringof);
return assumeSorted!less(r);
}
//Test for overflow
if (newSize < minCapacity) newSize = minCapacity;
- if (__ctfe) temp.length = newSize;
- else temp = () @trusted { return uninitializedArray!(T[])(newSize); }();
+ // can't use `temp.length` if there's no default constructor
+ static if (__traits(compiles, { T defaultConstructed; cast(void) defaultConstructed; }))
+ {
+ if (__ctfe) temp.length = newSize;
+ else temp = () @trusted { return uninitializedArray!(T[])(newSize); }();
+ }
+ else
+ {
+ temp = () @trusted { return uninitializedArray!(T[])(newSize); }();
+ }
}
return temp;
}
sort!(cmp, SwapStrategy.stable)(makeArray(minMerge + 5));
}
+// https://issues.dlang.org/show_bug.cgi?id=23668
+@safe unittest
+{
+ static struct S
+ {
+ int opCmp(const S) const { return 1; }
+ @disable this();
+ }
+ S[] array;
+ array.sort!("a < b", SwapStrategy.stable);
+}
+
// schwartzSort
/**
Alternative sorting method that should be used when comparing keys involves an
/// ditto
ForeachType!(typeof((*Range).init))[] array(Range)(Range r)
-if (is(Range : U*, U) && isIterable!U && !isAutodecodableString!Range && !isInfinite!Range)
+if (is(Range == U*, U) && isIterable!U && !isAutodecodableString!Range && !isInfinite!Range)
{
return array(*r);
}
}
}
-// https://issues.dlang.org/show_bug.cgi?id=10895
-@safe unittest
-{
- static class A
- {
- string name;
- alias name this;
- this(string name) { this.name = name; }
- }
- auto a = [new A(`foo`)];
- assert(a[0].length == 3);
- auto temp = join(a, " ");
- assert(a[0].length == 3);
- assert(temp.length == 3);
-}
-
// https://issues.dlang.org/show_bug.cgi?id=14230
@safe unittest
{
}
else
{
- enum ulong
- maskAllElse = ((~0uL) >> (64 - len)) << offset,
- signBitCheck = 1uL << (len - 1);
+ enum ulong maskAllElse = ((~0uL) >> (64 - len)) << offset;
+ enum TSize = 8 * T.sizeof;
+ enum SignShift = TSize - len;
static if (T.min < 0)
{
enum long minVal = -(1uL << (len - 1));
enum ulong maxVal = (1uL << (len - 1)) - 1;
- alias UT = Unsigned!(T);
- enum UT extendSign = cast(UT)~((~0uL) >> (64 - len));
+ enum RightShiftOp = ">>=";
}
else
{
enum ulong minVal = 0;
enum ulong maxVal = (~0uL) >> (64 - len);
- enum extendSign = 0;
+ enum RightShiftOp = ">>>=";
}
static if (is(T == bool))
else
{
// getter
- enum createAccessors = "@property "~T.stringof~" "~name~"() @safe pure nothrow @nogc const { auto result = "
- ~"("~store~" & "
- ~ myToString(maskAllElse) ~ ") >>"
- ~ myToString(offset) ~ ";"
- ~ (T.min < 0
- ? "if (result >= " ~ myToString(signBitCheck)
- ~ ") result |= " ~ myToString(extendSign) ~ ";"
- : "")
- ~ " return cast("~T.stringof~") result;}\n"
+ enum createAccessors = "@property "~T.stringof~" "~name~"() @safe pure nothrow @nogc const {"
+ ~ "auto result = cast("~T.stringof~") (" ~ store ~ " >>" ~ myToString(offset) ~ ");"
+ ~ "result <<= " ~ myToString(SignShift) ~ ";"
+ ~ "result " ~ RightShiftOp ~ myToString(SignShift) ~ ";"
+ ~ " return result;}\n"
// setter
~"@property void "~name~"("~T.stringof~" v) @safe pure nothrow @nogc { "
~"assert(v >= "~name~`_min, "Value is smaller than the minimum value of bitfield '`~name~`'"); `
*
* This is a low-level messaging API upon which more structured or restrictive
* APIs may be built. The general idea is that every messageable entity is
- * represented by a common handle type called a Tid, which allows messages to
+ * represented by a common handle type called a `Tid`, which allows messages to
* be sent to logical threads that are executing in both the current process
* and in external processes using the same interface. This is an important
* aspect of scalability because it allows the components of a program to be
*
* A logical thread is an execution context that has its own stack and which
* runs asynchronously to other logical threads. These may be preemptively
- * scheduled kernel threads, fibers (cooperative user-space threads), or some
- * other concept with similar behavior.
+ * scheduled kernel threads, $(MREF_ALTTEXT fibers, core, thread, fiber)
+ * (cooperative user-space threads), or some other concept with similar behavior.
*
* The type of concurrency used when logical threads are created is determined
- * by the Scheduler selected at initialization time. The default behavior is
+ * by the $(LREF Scheduler) selected at initialization time. The default behavior is
* currently to create a new kernel thread per call to spawn, but other
* schedulers are available that multiplex fibers across the main thread or
* use some combination of the two approaches.
// Exceptions
/**
- * Thrown on calls to `receiveOnly` if a message other than the type
+ * Thrown on calls to $(LREF receiveOnly) if a message other than the type
* the receiving thread expected is sent.
*/
class MessageMismatch : Exception
}
/**
- * Thrown on calls to `receive` if the thread that spawned the receiving
+ * Thrown on calls to $(LREF receive) if the thread that spawned the receiving
* thread has terminated and no more messages exist.
*/
class OwnerTerminated : Exception
}
/**
- * Thrown when a Tid is missing, e.g. when `ownerTid` doesn't
+ * Thrown when a `Tid` is missing, e.g. when $(LREF ownerTid) doesn't
* find an owner thread.
*/
class TidMissingException : Exception
public:
/**
- * Generate a convenient string for identifying this Tid. This is only
- * useful to see if Tid's that are currently executing are the same or
+ * Generate a convenient string for identifying this `Tid`. This is only
+ * useful to see if `Tid`'s that are currently executing are the same or
* different, e.g. for logging and debugging. It is potentially possible
- * that a Tid executed in the future will have the same toString() output
- * as another Tid that has already terminated.
+ * that a `Tid` executed in the future will have the same `toString()` output
+ * as another `Tid` that has already terminated.
*/
void toString(W)(ref W w) const
{
}
/**
- * Returns: The $(LREF Tid) of the caller's thread.
+ * Returns: The `Tid` of the caller's thread.
*/
@property Tid thisTid() @safe
{
}
/**
- * Return the Tid of the thread which spawned the caller's thread.
+ * Return the `Tid` of the thread which spawned the caller's thread.
*
* Throws: A `TidMissingException` exception if
* there is no owner thread.
}
/**
- * Starts fn(args) in a new logical thread.
+ * Starts `fn(args)` in a new logical thread.
*
* Executes the supplied function in a new logical thread represented by
* `Tid`. The calling thread is designated as the owner of the new thread.
* args = Arguments to the function.
*
* Returns:
- * A Tid representing the new logical thread.
+ * A `Tid` representing the new logical thread.
*
* Notes:
* `args` must not have unshared aliasing. In other words, all arguments
}
/**
- * Starts fn(args) in a logical thread and will receive a LinkTerminated
+ * Starts `fn(args)` in a logical thread and will receive a `LinkTerminated`
* message when the operation terminates.
*
* Executes the supplied function in a new logical thread represented by
- * Tid. This new thread is linked to the calling thread so that if either
- * it or the calling thread terminates a LinkTerminated message will be sent
- * to the other, causing a LinkTerminated exception to be thrown on receive().
- * The owner relationship from spawn() is preserved as well, so if the link
+ * `Tid`. This new thread is linked to the calling thread so that if either
+ * it or the calling thread terminates a `LinkTerminated` message will be sent
+ * to the other, causing a `LinkTerminated` exception to be thrown on `receive()`.
+ * The owner relationship from `spawn()` is preserved as well, so if the link
* between threads is broken, owner termination will still result in an
- * OwnerTerminated exception to be thrown on receive().
+ * `OwnerTerminated` exception to be thrown on `receive()`.
*
* Params:
* fn = The function to execute.
enum OnCrowding
{
block, /// Wait until room is available.
- throwException, /// Throw a MailboxFull exception.
+ throwException, /// Throw a $(LREF MailboxFull) exception.
ignore /// Abort the send and return.
}
}
/**
- * Gets the Tid associated with name.
+ * Gets the `Tid` associated with name.
*
* Params:
* name = The name to locate within the registry.
*
* Returns:
- * The associated Tid or Tid.init if name is not registered.
+ * The associated `Tid` or `Tid.init` if name is not registered.
*/
Tid locate(string name)
{
/**
* Encapsulates all implementation-level data needed for scheduling.
*
- * When defining a Scheduler, an instance of this struct must be associated
+ * When defining a $(LREF Scheduler), an instance of this struct must be associated
* with each logical thread. It contains all implementation-level information
* needed by the internal API.
*/
Tid owner;
/**
- * Gets a thread-local instance of ThreadInfo.
+ * Gets a thread-local instance of `ThreadInfo`.
*
- * Gets a thread-local instance of ThreadInfo, which should be used as the
+ * Gets a thread-local instance of `ThreadInfo`, which should be used as the
* default instance when info is requested for a thread not created by the
- * Scheduler.
+ * `Scheduler`.
*/
static @property ref thisInfo() nothrow
{
}
/**
- * A Scheduler controls how threading is performed by spawn.
+ * A `Scheduler` controls how threading is performed by spawn.
*
- * Implementing a Scheduler allows the concurrency mechanism used by this
+ * Implementing a `Scheduler` allows the concurrency mechanism used by this
* module to be customized according to different needs. By default, a call
* to spawn will create a new kernel thread that executes the supplied routine
- * and terminates when finished. But it is possible to create Schedulers that
- * reuse threads, that multiplex Fibers (coroutines) across a single thread,
- * or any number of other approaches. By making the choice of Scheduler a
- * user-level option, std.concurrency may be used for far more types of
+ * and terminates when finished. But it is possible to create `Scheduler`s that
+ * reuse threads, that multiplex `Fiber`s (coroutines) across a single thread,
+ * or any number of other approaches. By making the choice of `Scheduler` a
+ * user-level option, `std.concurrency` may be used for far more types of
* application than if this behavior were predefined.
*
* Example:
* ---
*
* Some schedulers have a dispatching loop that must run if they are to work
- * properly, so for the sake of consistency, when using a scheduler, start()
- * must be called within main(). This yields control to the scheduler and
+ * properly, so for the sake of consistency, when using a scheduler, `start()`
+ * must be called within `main()`. This yields control to the scheduler and
* will ensure that any spawned threads are executed in an expected manner.
*/
interface Scheduler
{
/**
- * Spawns the supplied op and starts the Scheduler.
+ * Spawns the supplied op and starts the `Scheduler`.
*
* This is intended to be called at the start of the program to yield all
- * scheduling to the active Scheduler instance. This is necessary for
+ * scheduling to the active `Scheduler` instance. This is necessary for
* schedulers that explicitly dispatch threads rather than simply relying
* on the operating system to do so, and so start should always be called
- * within main() to begin normal program execution.
+ * within `main()` to begin normal program execution.
*
* Params:
* op = A wrapper for whatever the main thread would have done in the
* absence of a custom scheduler. It will be automatically executed
- * via a call to spawn by the Scheduler.
+ * via a call to spawn by the `Scheduler`.
*/
void start(void delegate() op);
*
* This routine is called by spawn. It is expected to instantiate a new
* logical thread and run the supplied operation. This thread must call
- * thisInfo.cleanup() when the thread terminates if the scheduled thread
- * is not a kernel thread--all kernel threads will have their ThreadInfo
+ * `thisInfo.cleanup()` when the thread terminates if the scheduled thread
+ * is not a kernel thread--all kernel threads will have their `ThreadInfo`
* cleaned up automatically by a thread-local destructor.
*
* Params:
void yield() nothrow;
/**
- * Returns an appropriate ThreadInfo instance.
+ * Returns an appropriate `ThreadInfo` instance.
*
- * Returns an instance of ThreadInfo specific to the logical thread that
+ * Returns an instance of `ThreadInfo` specific to the logical thread that
* is calling this routine or, if the calling thread was not create by
- * this scheduler, returns ThreadInfo.thisInfo instead.
+ * this scheduler, returns `ThreadInfo.thisInfo` instead.
*/
@property ref ThreadInfo thisInfo() nothrow;
/**
- * Creates a Condition variable analog for signaling.
+ * Creates a `Condition` variable analog for signaling.
*
- * Creates a new Condition variable analog which is used to check for and
+ * Creates a new `Condition` variable analog which is used to check for and
* to signal the addition of messages to a thread's message queue. Like
* yield, some schedulers may need to define custom behavior so that calls
- * to Condition.wait() yield to another thread when no new messages are
+ * to `Condition.wait()` yield to another thread when no new messages are
* available instead of blocking.
*
* Params:
- * m = The Mutex that will be associated with this condition. It will be
+ * m = The `Mutex` that will be associated with this condition. It will be
* locked prior to any operation on the condition, and so in some
- * cases a Scheduler may need to hold this reference and unlock the
+ * cases a `Scheduler` may need to hold this reference and unlock the
* mutex before yielding execution to another logical thread.
*/
Condition newCondition(Mutex m) nothrow;
}
/**
- * An example Scheduler using kernel threads.
+ * An example `Scheduler` using kernel threads.
*
- * This is an example Scheduler that mirrors the default scheduling behavior
+ * This is an example `Scheduler` that mirrors the default scheduling behavior
* of creating one kernel thread per call to spawn. It is fully functional
* and may be instantiated and used, but is not a necessary part of the
* default functioning of this module.
}
/**
- * Returns ThreadInfo.thisInfo, since it is a thread-local instance of
- * ThreadInfo, which is the correct behavior for this scheduler.
+ * Returns `ThreadInfo.thisInfo`, since it is a thread-local instance of
+ * `ThreadInfo`, which is the correct behavior for this scheduler.
*/
@property ref ThreadInfo thisInfo() nothrow
{
}
/**
- * Creates a new Condition variable. No custom behavior is needed here.
+ * Creates a new `Condition` variable. No custom behavior is needed here.
*/
Condition newCondition(Mutex m) nothrow
{
}
/**
- * An example Scheduler using Fibers.
+ * An example `Scheduler` using $(MREF_ALTTEXT `Fiber`s, core, thread, fiber).
*
- * This is an example scheduler that creates a new Fiber per call to spawn
+ * This is an example scheduler that creates a new `Fiber` per call to spawn
* and multiplexes the execution of all fibers within the main thread.
*/
class FiberScheduler : Scheduler
{
/**
- * This creates a new Fiber for the supplied op and then starts the
+ * This creates a new `Fiber` for the supplied op and then starts the
* dispatcher.
*/
void start(void delegate() op)
}
/**
- * This created a new Fiber for the supplied op and adds it to the
+ * This created a new `Fiber` for the supplied op and adds it to the
* dispatch list.
*/
void spawn(void delegate() op) nothrow
}
/**
- * If the caller is a scheduled Fiber, this yields execution to another
- * scheduled Fiber.
+ * If the caller is a scheduled `Fiber`, this yields execution to another
+ * scheduled `Fiber`.
*/
void yield() nothrow
{
}
/**
- * Returns an appropriate ThreadInfo instance.
+ * Returns an appropriate `ThreadInfo` instance.
*
- * Returns a ThreadInfo instance specific to the calling Fiber if the
- * Fiber was created by this dispatcher, otherwise it returns
- * ThreadInfo.thisInfo.
+ * Returns a `ThreadInfo` instance specific to the calling `Fiber` if the
+ * `Fiber` was created by this dispatcher, otherwise it returns
+ * `ThreadInfo.thisInfo`.
*/
@property ref ThreadInfo thisInfo() nothrow
{
}
/**
- * Returns a Condition analog that yields when wait or notify is called.
+ * Returns a `Condition` analog that yields when wait or notify is called.
*
* Bug:
- * For the default implementation, `notifyAll`will behave like `notify`.
+ * For the default implementation, `notifyAll` will behave like `notify`.
*
* Params:
* m = A `Mutex` to use for locking if the condition needs to be waited on
protected:
/**
- * Creates a new Fiber which calls the given delegate.
+ * Creates a new `Fiber` which calls the given delegate.
*
* Params:
* op = The delegate the fiber should call
}
/**
- * Fiber which embeds a ThreadInfo
+ * `Fiber` which embeds a `ThreadInfo`
*/
static class InfoFiber : Fiber
{
}
/**
- * Sets the Scheduler behavior within the program.
+ * Sets the `Scheduler` behavior within the program.
*
- * This variable sets the Scheduler behavior within this program. Typically,
- * when setting a Scheduler, scheduler.start() should be called in main. This
+ * This variable sets the `Scheduler` behavior within this program. Typically,
+ * when setting a `Scheduler`, `scheduler.start()` should be called in `main`. This
* routine will not return until program execution is complete.
*/
__gshared Scheduler scheduler;
// Generator
/**
- * If the caller is a Fiber and is not a Generator, this function will call
- * scheduler.yield() or Fiber.yield(), as appropriate.
+ * If the caller is a `Fiber` and is not a $(LREF Generator), this function will call
+ * `scheduler.yield()` or `Fiber.yield()`, as appropriate.
*/
void yield() nothrow
{
/**
- * A Generator is a Fiber that periodically returns values of type T to the
- * caller via yield. This is represented as an InputRange.
+ * A Generator is a $(MREF_ALTTEXT Fiber, core, thread, fiber)
+ * that periodically returns values of type `T` to the
+ * caller via `yield`. This is represented as an InputRange.
*/
class Generator(T) :
Fiber, IsGenerator, InputRange!T
/**
* Returns the most recently generated value without executing a
* copy contructor. Will not compile for element types defining a
- * postblit, because Generator does not return by reference.
+ * postblit, because `Generator` does not return by reference.
*/
final T moveFront()
{
heap.insert(6);
assert(equal(heap, [6, 5]));
}
+
+/**
+Example for unintuitive behaviour
+It is important not to use the Store after a Heap has been instantiated from
+it, at least in the cases of Dynamic Arrays. For example, inserting a new element
+in a Heap, which is using a Dyamic Array as a Store, will cause a reallocation of
+the Store, if the Store is already full. The Heap will not point anymore to the
+original Dyamic Array, but point to a new Dynamic Array.
+ */
+
+// https://issues.dlang.org/show_bug.cgi?id=18333
+@system unittest
+{
+ import std.stdio;
+ import std.algorithm.comparison : equal;
+ import std.container.binaryheap;
+
+ int[] a = [ 4, 1, 3, 2, 16, 9, 10, 14, 8, 7 ];
+ auto h = heapify(a);
+
+ // Internal representation of Binary Heap tree
+ assert(a.equal([16, 14, 10, 8, 7, 9, 3, 2, 4, 1]));
+
+ h.replaceFront(30);
+ // Value 16 was replaced by 30
+ assert(a.equal([30, 14, 10, 8, 7, 9, 3, 2, 4, 1]));
+
+ // Making changes to the Store will be seen in the Heap
+ a[0] = 40;
+ assert(h.front() == 40);
+
+ // Inserting a new element will reallocate the Store, leaving
+ // the original Store unchanged.
+ h.insert(20);
+ assert(a.equal([40, 14, 10, 8, 7, 9, 3, 2, 4, 1]));
+
+ // Making changes to the original Store will not affect the Heap anymore
+ a[0] = 60;
+ assert(h.front() == 40);
+}
*/
bool doesPointTo(S, T, Tdummy=void)(auto ref const S source, ref const T target) @nogc @trusted pure nothrow
if (__traits(isRef, source) || isDynamicArray!S ||
- is(S : U*, U) || is(S == class))
+ is(S == U*, U) || is(S == class))
{
- static if (is(S : U*, U) || is(S == class) || is(S == interface))
+ static if (is(S == U*, U) || is(S == class) || is(S == interface))
{
const m = *cast(void**) &source;
const b = cast(void*) ⌖
/// ditto
bool mayPointTo(S, T, Tdummy=void)(auto ref const S source, ref const T target) @trusted pure nothrow
if (__traits(isRef, source) || isDynamicArray!S ||
- is(S : U*, U) || is(S == class))
+ is(S == U*, U) || is(S == class))
{
- static if (is(S : U*, U) || is(S == class) || is(S == interface))
+ static if (is(S == U*, U) || is(S == class) || is(S == interface))
{
const m = *cast(void**) &source;
const b = cast(void*) ⌖
assert( doesPointTo(cast(int*) s, i));
assert(!doesPointTo(cast(int*) s, j));
}
-@safe unittest //more alias this opCast
-{
- void* p;
- class A
- {
- void* opCast(T)() if (is(T == void*))
- {
- return p;
- }
- alias foo = opCast!(void*);
- alias foo this;
- }
- assert(!doesPointTo(A.init, p));
- assert(!mayPointTo(A.init, p));
-}
/+
Returns true if the field at index `i` in ($D T) shares its address with another field.
const ta = SysTimeToFILETIME(accessTime);
const tm = SysTimeToFILETIME(modificationTime);
alias defaults =
- AliasSeq!(GENERIC_WRITE,
+ AliasSeq!(FILE_WRITE_ATTRIBUTES,
0,
null,
OPEN_EXISTING,
rmdirRecurse(newdir);
}
+// https://issues.dlang.org/show_bug.cgi?id=23683
+@safe unittest
+{
+ scope(exit) deleteme.remove;
+ import std.stdio : File;
+ auto f = File(deleteme, "wb");
+ SysTime time = SysTime(DateTime(2018, 10, 4, 0, 0, 30));
+ setTimes(deleteme, time, time);
+}
+
/++
Returns the time that the given file was last modified.
$(LREF DirEntry).
Throws:
- $(LREF FileException) if the directory does not exist.
+ $(UL
+ $(LI $(LREF FileException) if the $(B path) directory does not exist or read permission is denied.)
+ $(LI $(LREF FileException) if $(B mode) is not `shallow` and a subdirectory cannot be read.)
+ )
Example:
--------------------
foreach (d; dFiles)
writeln(d.name);
--------------------
- +/
+To handle subdirectories with denied read permission, use `SpanMode.shallow`:
+---
+void scan(string path)
+{
+ foreach (DirEntry entry; dirEntries(path, SpanMode.shallow))
+ {
+ try
+ {
+ writeln(entry.name);
+ if (entry.isDir)
+ scan(entry.name);
+ }
+ catch (FileException fe) { continue; } // ignore
+ }
+}
+
+scan("");
+---
++/
// For some reason, doing the same alias-to-a-template trick as with DirIterator
// does not work here.
@safe unittest
{
- class C1
- {
- bool val;
- alias val this;
- this(bool v){ val = v; }
- }
-
- class C2 {
- bool val;
- alias val this;
- this(bool v){ val = v; }
- override string toString() const { return "C"; }
- }
-
- () @trusted {
- formatTest(new C1(false), "false");
- formatTest(new C1(true), "true");
- formatTest(new C2(false), "C");
- formatTest(new C2(true), "C");
- } ();
-
struct S1
{
bool val;
@safe unittest
{
- class C1
- {
- long val;
- alias val this;
- this(long v){ val = v; }
- }
-
- class C2
- {
- long val;
- alias val this;
- this(long v){ val = v; }
- override string toString() const { return "C"; }
- }
-
- () @trusted {
- formatTest(new C1(10), "10");
- formatTest(new C2(10), "C");
- } ();
-
struct S1
{
long val;
{
formatTest(2.25, "2.25");
- class C1
- {
- double val;
- alias val this;
- this(double v){ val = v; }
- }
-
- class C2
- {
- double val;
- alias val this;
- this(double v){ val = v; }
- override string toString() const { return "C"; }
- }
-
- () @trusted {
- formatTest(new C1(2.25), "2.25");
- formatTest(new C2(2.25), "C");
- } ();
-
struct S1
{
double val;
@safe unittest
{
- class C1
- {
- char val;
- alias val this;
- this(char v){ val = v; }
- }
-
- class C2
- {
- char val;
- alias val this;
- this(char v){ val = v; }
- override string toString() const { return "C"; }
- }
-
- () @trusted {
- formatTest(new C1('c'), "c");
- formatTest(new C2('c'), "C");
- } ();
-
struct S1
{
char val;
@safe unittest
{
- // Test for bug 5371 for classes
- class C1
- {
- const string var;
- alias var this;
- this(string s){ var = s; }
- }
-
- class C2
- {
- string var;
- alias var this;
- this(string s){ var = s; }
- }
-
- () @trusted {
- formatTest(new C1("c1"), "c1");
- formatTest(new C2("c2"), "c2");
- } ();
-
// Test for bug 5371 for structs
struct S1
{
@safe unittest
{
- class C3
- {
- string val;
- alias val this;
- this(string s){ val = s; }
- override string toString() const { return "C"; }
- }
-
- () @trusted { formatTest(new C3("c3"), "C"); } ();
-
struct S3
{
string val; alias val this;
formatTest(S!0b101([0, 1, 2]), "S"); // Test for bug 7628
formatTest(S!0b110([0, 1, 2]), "S");
formatTest(S!0b111([0, 1, 2]), "S");
-
- class C(uint flags)
- {
- int[] arr;
- static if (flags & 1)
- alias arr this;
-
- this(int[] a) { arr = a; }
-
- static if (flags & 2)
- {
- @property bool empty() const { return arr.length == 0; }
- @property int front() const { return arr[0] * 2; }
- void popFront() { arr = arr[1 .. $]; }
- }
-
- static if (flags & 4)
- override string toString() const { return "C"; }
- }
-
- () @trusted {
- formatTest(new C!0b000([0, 1, 2]), (new C!0b000([])).toString());
- formatTest(new C!0b001([0, 1, 2]), "[0, 1, 2]"); // Test for bug 7628
- formatTest(new C!0b010([0, 1, 2]), "[0, 2, 4]");
- formatTest(new C!0b011([0, 1, 2]), "[0, 2, 4]");
- formatTest(new C!0b100([0, 1, 2]), "C");
- formatTest(new C!0b101([0, 1, 2]), "C"); // Test for bug 7628
- formatTest(new C!0b110([0, 1, 2]), "C");
- formatTest(new C!0b111([0, 1, 2]), "C");
- } ();
}
@safe unittest
@safe unittest
{
- class C1
- {
- int[char] val;
- alias val this;
- this(int[char] v){ val = v; }
- }
-
- class C2
- {
- int[char] val;
- alias val this;
- this(int[char] v){ val = v; }
- override string toString() const { return "C"; }
- }
-
- () @trusted {
- formatTest(new C1(['c':1, 'd':2]), [`['c':1, 'd':2]`, `['d':2, 'c':1]`]);
- formatTest(new C2(['c':1, 'd':2]), "C");
- } ();
-
struct S1
{
int[char] val;
customPutWriterFormatSpec,
}
-private enum hasPreviewIn = !is(typeof(mixin(q{(in ref int a) => a})));
+private alias DScannerBug895 = int[256];
+private immutable bool hasPreviewIn = ((in DScannerBug895 a) { return __traits(isRef, a); })(DScannerBug895.init);
template hasToString(T, Char)
{
formatTest(q, "FFEECCAA");
}
-// https://issues.dlang.org/show_bug.cgi?id=8186
-@system unittest
-{
- class B
- {
- int* a;
- this() { a = new int; }
- alias a this;
- }
- formatTest(B.init, "null");
-}
-
// https://issues.dlang.org/show_bug.cgi?id=9336
@system pure unittest
{
if (isSomeString!(typeof(fmt)))
{
import std.format : checkFormatException;
+ import std.meta : staticMap;
+ import std.typecons : Tuple;
+
- alias e = checkFormatException!(fmt, Args);
+ // formattedRead supports std.typecons.Tuple
+ // however, checkFormatException does not
+ // this means that all std.typecons.Tuple's types in Args must be unwrapped
+ // and passed to checkFormatException
+ template Flatten(T)
+ {
+ static if (is(T : Tuple!Args, Args...))
+ alias Flatten = Args;
+ else
+ alias Flatten = T;
+ }
+
+ alias e = checkFormatException!(fmt, staticMap!(Flatten, Args));
static assert(!e, e);
return .formattedRead(r, fmt, args);
}
assert(t[0] == 1 && t[1] == 2.125);
}
+// https://issues.dlang.org/show_bug.cgi?id=23600
+@safe pure unittest
+{
+ import std.typecons : Tuple, tuple;
+
+ string h, w;
+ Tuple!(int, float) t;
+
+ assert("hello 1 2.34 world".formattedRead!"%s %d %f %s"(h, t, w) == 3);
+ assert(h == "hello");
+ assert(t == tuple(1, 2.34f));
+ assert(w == "world");
+}
+
@safe unittest
{
import std.math.operations : isClose;
import std.format : format;
enum fmt = "getopt validator: %s (at position %d)";
- enum isReceiver(T) = is(T : U*, U) || (is(T == function)) || (is(T == delegate));
+ enum isReceiver(T) = is(T == U*, U) || (is(T == function)) || (is(T == delegate));
enum isOptionStr(T) = isSomeString!T || isSomeChar!T;
auto validator()
enum hangulLVTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x40, 0x80], [ 0x100, 0x80, 0xa00], [ 0x0, 0x20100, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20001, 0x40003, 0x60005, 0x10007, 0x30002, 0x50004, 0x70006, 0x20001, 0x40003, 0x60005, 0x10007, 0x30002, 0x50004, 0x70006, 0x20001, 0x40003, 0x60005, 0x10007, 0x30002, 0x50004, 0x70006, 0x80001, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000001, 0x1000000, 0x100000, 0x10000, 0x1000, 0x100, 0x10, 0x10000001, 0x1000000, 0x100000, 0x10000, 0x1000, 0x100, 0x10, 0x10000001, 0x1000000, 0x100000, 0x10000, 0x1000, 0x100, 0x10, 0x10000001, 0x1000000, 0x100000, 0x10000, 0x1000, 0x100, 0x10, 0x10000001, 0x1000000, 0x100000, 0x10000, 0x1000, 0x100, 0x10, 0x10000001, 0x1000000, 0x100000, 0x10000, 0x1000, 0x100, 0x10, 0x10000001, 0x1000000, 0x100000, 0x10000, 0x1000, 0x100, 0x10, 0x10000001, 0x1000000, 0x100000, 0x10000, 0x1000, 0x100, 0x10, 0x1000000, 0x100000, 0x10000, 0x1000, 0x100, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]);
//832 bytes
enum hangulLVTTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x40, 0x80], [ 0x100, 0x80, 0xa00], [ 0x0, 0x20100, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20001, 0x40003, 0x60005, 0x10007, 0x30002, 0x50004, 0x70006, 0x20001, 0x40003, 0x60005, 0x10007, 0x30002, 0x50004, 0x70006, 0x20001, 0x40003, 0x60005, 0x10007, 0x30002, 0x50004, 0x70006, 0x80001, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xeffffffe, 0xfeffffff, 0xffefffff, 0xfffeffff, 0xffffefff, 0xfffffeff, 0xffffffef, 0xeffffffe, 0xfeffffff, 0xffefffff, 0xfffeffff, 0xffffefff, 0xfffffeff, 0xffffffef, 0xeffffffe, 0xfeffffff, 0xffefffff, 0xfffeffff, 0xffffefff, 0xfffffeff, 0xffffffef, 0xeffffffe, 0xfeffffff, 0xffefffff, 0xfffeffff, 0xffffefff, 0xfffffeff, 0xffffffef, 0xeffffffe, 0xfeffffff, 0xffefffff, 0xfffeffff, 0xffffefff, 0xfffffeff, 0xffffffef, 0xeffffffe, 0xfeffffff, 0xffefffff, 0xfffeffff, 0xffffefff, 0xfffffeff, 0xffffffef, 0xeffffffe, 0xfeffffff, 0xffefffff, 0xfffeffff, 0xffffefff, 0xfffffeff, 0xffffffef, 0xeffffffe, 0xfeffffff, 0xffefffff, 0xfffeffff, 0xffffefff, 0xfffffeff, 0xffffffef, 0xfeffffff, 0xffefffff, 0xfffeffff, 0xffffefff, 0xfffffeff, 0xf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]);
-//1920 bytes
-enum mcTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x40, 0xc0], [ 0x100, 0x100, 0x2400], [ 0x2020100, 0x2020302, 0x5020204, 0x2060202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000, 0x30002, 0x50004, 0x60000, 0x7, 0x0, 0x0, 0x80000, 0x90000, 0xb000a, 0xc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf000e, 0x110010, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x130012, 0x150014, 0x170016, 0x190018, 0x1b001a, 0x1c, 0x1e001d, 0x20001f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x210000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x220000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0xc8000000, 0xde01, 0x0, 0xc, 0xc0000000, 0x801981, 0x0, 0x8, 0xc0000000, 0x1, 0x0, 0x8, 0xc0000000, 0x1a01, 0x0, 0xc, 0x40000000, 0x801981, 0x0, 0x0, 0xc0000000, 0x801dc6, 0x0, 0xe, 0x0, 0x1e, 0x0, 0xc, 0x40000000, 0x600d9f, 0x80000, 0xc, 0xc0000000, 0x801dc1, 0x0, 0xc, 0x0, 0xff038000, 0xc0000, 0x0, 0xc0000000, 0x0, 0x80000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x19021800, 0xc00000, 0x3f9c, 0x1c009f98, 0x0, 0x0, 0x0, 0x200000, 0x100000, 0x0, 0x0, 0x0, 0xc0400000, 0x1bf, 0x0, 0x0, 0x1fb0e78, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000000, 0x0, 0xa00000, 0x7e01a, 0x0, 0x0, 0x0, 0x0, 0x10, 0xe8200000, 0x1b, 0x0, 0x4, 0x4c2, 0x0, 0xc5c80, 0x0, 0x300ff0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x800002, 0x0, 0xc000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x98, 0x0, 0x0, 0x3, 0xfff00000, 0xf, 0x0, 0x0, 0x0, 0xc0000, 0x0, 0x8, 0xcc300000, 0x1, 0x0, 0x0, 0x198000, 0x2000, 0x28000000, 0x0, 0x0, 0x0, 0x20c800, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x16d8, 0x5, 0x0, 0x0, 0x0, 0x4, 0x1870000, 0x0, 0x0, 0x0, 0x1000, 0x60, 0x0, 0x4, 0x80380000, 0x4001, 0x0, 0x0, 0x2c7000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xc, 0xc0000000, 0x80399e, 0xc, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe00000, 0x23, 0x0, 0x0, 0x7a070000, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4f038000, 0x0, 0x0, 0x0, 0x58070000, 0x0, 0x0, 0x0, 0x40d000, 0x0, 0x0, 0x0, 0x43, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1007000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x21bf0000, 0x5, 0x0, 0x0, 0x0, 0xf00e0000, 0x10, 0x0, 0x2000000, 0x1800000, 0x0, 0x800000, 0x0, 0x0, 0x0, 0x0, 0x40008000, 0x0, 0x0, 0x0, 0x120200, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x587c00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x600000, 0x8, 0xc0300000, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfffe0000, 0xffffffff, 0xff, 0x0, 0x0, 0x30000, 0x0, 0x0, 0x0, 0x7e060, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]);
-//3456 bytes
-enum graphemeExtendTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x40, 0x110], [ 0x100, 0x1a0, 0x4a00], [ 0x2020100, 0x4020302, 0x7020605, 0xa090802, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x202020b, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000, 0x30002, 0x50004, 0x70006, 0x90008, 0xb000a, 0xd000c, 0xe, 0xf0000, 0x0, 0x100000, 0x120011, 0x140013, 0x160015, 0x0, 0x17, 0x0, 0x0, 0x0, 0x0, 0x0, 0x190018, 0x0, 0x1a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b, 0x1d001c, 0x1f001e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x200000, 0x0, 0x220021, 0x230000, 0x250024, 0x0, 0x0, 0x0, 0x26, 0x270000, 0x290028, 0x2b002a, 0x2d002c, 0x2f002e, 0x310030, 0x330032, 0x34, 0x360035, 0x380037, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3b003a, 0x0, 0x3c0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e0000, 0x3f0000, 0x40, 0x0, 0x0, 0x0, 0x41, 0x0, 0x0, 0x3b0042, 0x43, 0x44, 0x0, 0x460045, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x480047, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfffe0000, 0xbfffffff, 0xb6, 0x0, 0x7ff0000, 0x0, 0xfffff800, 0x10000, 0x0, 0x0, 0x9fc00000, 0x3d9f, 0x20000, 0xffff0000, 0x7ff, 0x0, 0x0, 0x1ffc0, 0x0, 0x200ff800, 0xfbc00000, 0x3eef, 0xe000000, 0x0, 0xff000000, 0x0, 0xfffffc00, 0xfffffffb, 0x7, 0x14000000, 0xfe21fe, 0xc, 0x2, 0x50000000, 0x80201e, 0x4000000c, 0x6, 0x10000000, 0x23986, 0x230000, 0x6, 0x10000000, 0x21be, 0xfc00000c, 0x2, 0xd0000000, 0xe0201e, 0xc, 0x4, 0x40000000, 0x802001, 0x0, 0x11, 0xd0000000, 0x603dc1, 0xc, 0x2, 0x90000000, 0x603044, 0xc, 0x3, 0x58000000, 0x80201e, 0xc, 0x2, 0x0, 0x805c8400, 0x0, 0x0, 0x7f20000, 0x7f80, 0x0, 0x0, 0x1ff20000, 0x7f00, 0x0, 0x3000000, 0x2a00000, 0x0, 0x7ffe0000, 0xfeffe0df, 0x1fffffff, 0x40, 0x0, 0x0, 0x66fde000, 0xc3000000, 0x1e0001, 0x20002064, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe0000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1c0000, 0xc0000, 0xc0000, 0xc0000, 0x0, 0x3fb00000, 0x200ffe40, 0x0, 0xb800, 0x0, 0x0, 0x0, 0x60, 0x200, 0x0, 0x0, 0x0, 0xe040187, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9800000, 0x0, 0x7f400000, 0x9ff81fe5, 0x0, 0xffff0000, 0x7fff, 0x0, 0xf, 0x17f00000, 0x4, 0xff800, 0x3, 0x3b3c, 0x0, 0x3a340, 0x0, 0xcff000, 0x0, 0x0, 0x0, 0x0, 0xfff70000, 0x31021fd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0x1000, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffff0000, 0x1ffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x38000, 0x0, 0x0, 0x0, 0x80000000, 0x0, 0x0, 0x0, 0xffffffff, 0x0, 0xfc00, 0x0, 0x0, 0x6000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff78000, 0xc0000000, 0x0, 0x0, 0x30000, 0x844, 0x1060, 0x0, 0x0, 0x0, 0x0, 0x30, 0x8003ffff, 0x0, 0x3fc0, 0x3ff80, 0x0, 0x7, 0x33c80000, 0x0, 0x20, 0x0, 0x667e00, 0x1008, 0x10000000, 0x0, 0xc19d0000, 0x2, 0x403000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2120, 0x40000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffff, 0xffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x7c00000, 0x0, 0x0, 0x0, 0x0, 0xf06e, 0x87000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x60, 0x0, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1800, 0x0, 0xe0000000, 0x0, 0x0, 0x1ffc0, 0x0, 0x3c, 0x0, 0x0, 0x0, 0x2, 0xff000000, 0x7f, 0x80190000, 0x3, 0x6780000, 0x4, 0x0, 0x7, 0x1fef80, 0x0, 0x80000, 0x3, 0x7fc00000, 0x9e00, 0x0, 0x0, 0x40d38000, 0x2, 0x0, 0x0, 0x0, 0x80000000, 0x7f8, 0x3, 0x58000000, 0x800001, 0x1f1fc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff000000, 0x4000005c, 0x0, 0x0, 0xa5f90000, 0xd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb03c8000, 0x30000001, 0x0, 0x0, 0xa7f80000, 0x1, 0x0, 0x0, 0xbf2800, 0x0, 0x0, 0xe0000000, 0xfbc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6ff8000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x58010000, 0x8, 0x0, 0x0, 0x0, 0xcf00000, 0x1, 0x7fe, 0x79f80000, 0xe7e0080, 0x0, 0x37ffc00, 0x0, 0x0, 0x0, 0x0, 0xbf7f0000, 0x0, 0x0, 0xfffc0000, 0x6dfcff, 0x0, 0x0, 0x0, 0xb47e0000, 0xbf, 0x0, 0xa30000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x180000, 0x3, 0x7c00000, 0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fff81, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f0000, 0x0, 0x7f0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8000, 0x0, 0x78000, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x60000000, 0x0, 0x0, 0x0, 0xffffffff, 0xffff3fff, 0x7f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf807c3a0, 0xfe7, 0x3c00, 0x0, 0x0, 0x0, 0x0, 0x1c, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xf87fffff, 0xffffffff, 0x201fff, 0xf8000010, 0xfffe, 0x0, 0x0, 0xf9ffff7f, 0x7db, 0x0, 0x0, 0x8000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4000, 0x0, 0xf000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f0000, 0x0, 0x0, 0x0, 0x7f0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]);
+//896 bytes
+enum prependTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x40, 0x80], [ 0x100, 0x80, 0xc00], [ 0x1010100, 0x1010101, 0x1010102, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20001, 0x3, 0x0, 0x40000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x60005, 0x0, 0x0, 0x0, 0x70000, 0x8, 0x90000, 0xa0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000000, 0x0, 0x8000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30000, 0x0, 0x0, 0x4, 0x0, 0x0, 0x4000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000000, 0x2000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x80000000, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4000000, 0x0, 0x0, 0x3f0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]);
+//1280 bytes
+enum controlTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x40, 0xd0], [ 0x100, 0x120, 0xe00], [ 0x2020100, 0x3020202, 0x2020402, 0x2060502, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020207, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000, 0x10001, 0x10001, 0x10002, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10003, 0x10001, 0x10001, 0x10001, 0x10004, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x60005, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10007, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10008, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x90001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0xb000a, 0xc000c, 0xc000c, 0xc000c, 0xc000c, 0xc000c, 0xc000c, 0xc000c, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0xffffdbff, 0x0, 0x0, 0x80000000, 0xffffffff, 0x2000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc800, 0x7f00, 0x0, 0xffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfff0000, 0x0, 0xffff0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f80000, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffff0000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]);
+//1856 bytes
+enum spacingMarkTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x40, 0xb0], [ 0x100, 0xe0, 0x2400], [ 0x1010100, 0x1010201, 0x4010103, 0x1050101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000, 0x30002, 0x50004, 0x70006, 0x8, 0x0, 0x0, 0x90000, 0xa0000, 0xc000b, 0xd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf000e, 0x110010, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x130012, 0x150014, 0x170016, 0x190018, 0x1b001a, 0x1c, 0x1e001d, 0x20001f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x210000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x220000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0xc8000000, 0xde01, 0x0, 0xc, 0x80000000, 0x1981, 0x0, 0x8, 0xc0000000, 0x1, 0x0, 0x8, 0xc0000000, 0x1a01, 0x0, 0xc, 0x0, 0x1981, 0x0, 0x0, 0x80000000, 0x1dc6, 0x0, 0xe, 0x0, 0x1e, 0x0, 0xc, 0x40000000, 0xd9b, 0x80000, 0xc, 0x80000000, 0x1dc1, 0x0, 0xc, 0x0, 0x7f030000, 0xc0000, 0x0, 0x80000, 0x0, 0x0, 0x0, 0x80000, 0x0, 0x0, 0x0, 0xc0000000, 0x0, 0x80000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18020000, 0xc00000, 0x0, 0x10, 0x0, 0x0, 0x0, 0x200000, 0x100000, 0x0, 0x0, 0x0, 0xc0400000, 0x1bf, 0x0, 0x0, 0x1fb0e78, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000000, 0x0, 0xa00000, 0x7e000, 0x0, 0x0, 0x0, 0x0, 0x10, 0xe8000000, 0x1b, 0x0, 0x4, 0x4c2, 0x0, 0xc5c80, 0x0, 0x300ff0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x800002, 0x0, 0x98, 0x0, 0x0, 0x3, 0xfff00000, 0xf, 0x0, 0x0, 0x0, 0xc0000, 0x0, 0x8, 0xcc300000, 0x1, 0x0, 0x0, 0x198000, 0x2000, 0x0, 0x0, 0x0, 0x0, 0x20c800, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x16d8, 0x5, 0x0, 0x0, 0x0, 0x4, 0x1870000, 0x0, 0x0, 0x0, 0x1000, 0x60, 0x0, 0x4, 0x80380000, 0x4001, 0x0, 0x0, 0x2c7000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xc, 0x80000000, 0x399e, 0xc, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe00000, 0x23, 0x0, 0x0, 0x5a060000, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4f030000, 0x0, 0x0, 0x0, 0x58070000, 0x0, 0x0, 0x0, 0x40d000, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1007000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x21be0000, 0x5, 0x0, 0x0, 0x0, 0xf00e0000, 0x10, 0x0, 0x2000000, 0x1800000, 0x0, 0x800000, 0x0, 0x0, 0x0, 0x0, 0x40008000, 0x0, 0x0, 0x0, 0x120200, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x587c00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x600000, 0x8, 0xc0300000, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfffe0000, 0xffffffff, 0xff, 0x0, 0x0, 0x30000, 0x0, 0x0, 0x0, 0x2040, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]);
+//3488 bytes
+enum graphemeExtendTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x40, 0x110], [ 0x100, 0x1a0, 0x4b00], [ 0x2020100, 0x4020302, 0x7020605, 0xa090802, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x202020b, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000, 0x30002, 0x50004, 0x70006, 0x90008, 0xb000a, 0xd000c, 0xe, 0xf0000, 0x0, 0x100000, 0x120011, 0x140013, 0x160015, 0x0, 0x17, 0x0, 0x0, 0x0, 0x0, 0x0, 0x190018, 0x0, 0x1a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b, 0x1d001c, 0x1f001e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x200000, 0x0, 0x220021, 0x230000, 0x250024, 0x0, 0x0, 0x0, 0x26, 0x270000, 0x290028, 0x2b002a, 0x2d002c, 0x2f002e, 0x310030, 0x330032, 0x34, 0x360035, 0x380037, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3b003a, 0x0, 0x3c0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e0000, 0x3f0000, 0x40, 0x0, 0x0, 0x0, 0x41, 0x0, 0x0, 0x3b0042, 0x43, 0x44, 0x0, 0x460045, 0x0, 0x0, 0x0, 0x0, 0x470000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x490048, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfffe0000, 0xbfffffff, 0xb6, 0x0, 0x7ff0000, 0x0, 0xfffff800, 0x10000, 0x0, 0x0, 0x9fc00000, 0x3d9f, 0x20000, 0xffff0000, 0x7ff, 0x0, 0x0, 0x1ffc0, 0x0, 0x200ff800, 0xfbc00000, 0x3eef, 0xe000000, 0x0, 0xff000000, 0x0, 0xfffffc00, 0xfffffffb, 0x7, 0x14000000, 0xfe21fe, 0xc, 0x2, 0x50000000, 0x80201e, 0x4000000c, 0x6, 0x10000000, 0x23986, 0x230000, 0x6, 0x10000000, 0x21be, 0xfc00000c, 0x2, 0xd0000000, 0xe0201e, 0xc, 0x4, 0x40000000, 0x802001, 0x0, 0x11, 0xd0000000, 0x603dc1, 0xc, 0x2, 0x90000000, 0x603044, 0xc, 0x3, 0x58000000, 0x80201e, 0xc, 0x2, 0x0, 0x805c8400, 0x0, 0x0, 0x7f20000, 0x7f80, 0x0, 0x0, 0x1ff20000, 0x7f00, 0x0, 0x3000000, 0x2a00000, 0x0, 0x7ffe0000, 0xfeffe0df, 0x1fffffff, 0x40, 0x0, 0x0, 0x66fde000, 0xc3000000, 0x1e0001, 0x20002064, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe0000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1c0000, 0xc0000, 0xc0000, 0xc0000, 0x0, 0x3fb00000, 0x200ffe40, 0x0, 0xb800, 0x0, 0x0, 0x0, 0x60, 0x200, 0x0, 0x0, 0x0, 0xe040187, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9800000, 0x0, 0x7f400000, 0x9ff81fe5, 0x0, 0xffff0000, 0x7fff, 0x0, 0xf, 0x17f00000, 0x4, 0xff800, 0x3, 0x3b3c, 0x0, 0x3a340, 0x0, 0xcff000, 0x0, 0x0, 0x0, 0x0, 0xfff70000, 0x31021fd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0x1000, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffff0000, 0x1ffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x38000, 0x0, 0x0, 0x0, 0x80000000, 0x0, 0x0, 0x0, 0xffffffff, 0x0, 0xfc00, 0x0, 0x0, 0x6000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff78000, 0xc0000000, 0x0, 0x0, 0x30000, 0x844, 0x1060, 0x0, 0x0, 0x0, 0x0, 0x30, 0x8003ffff, 0x0, 0x3fc0, 0x3ff80, 0x0, 0x7, 0x33c80000, 0x0, 0x20, 0x0, 0x667e00, 0x1008, 0x10000000, 0x0, 0xc19d0000, 0x2, 0x403000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2120, 0x40000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffff, 0xffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x7c00000, 0x0, 0x0, 0x0, 0x0, 0xf06e, 0x87000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x60, 0x0, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1800, 0x0, 0xe0000000, 0x0, 0x0, 0x1ffc0, 0x0, 0x3c, 0x0, 0x0, 0x0, 0x2, 0xff000000, 0x7f, 0x80190000, 0x3, 0x6780000, 0x4, 0x0, 0x7, 0x1fef80, 0x0, 0x80000, 0x3, 0x7fc00000, 0x9e00, 0x0, 0x0, 0x40d38000, 0x2, 0x0, 0x0, 0x0, 0x80000000, 0x7f8, 0x3, 0x58000000, 0x800001, 0x1f1fc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff000000, 0x4000005c, 0x0, 0x0, 0xa5f90000, 0xd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb03c8000, 0x30000001, 0x0, 0x0, 0xa7f80000, 0x1, 0x0, 0x0, 0xbf2800, 0x0, 0x0, 0xe0000000, 0xfbc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6ff8000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x58010000, 0x8, 0x0, 0x0, 0x0, 0xcf00000, 0x1, 0x7fe, 0x79f80000, 0xe7e0080, 0x0, 0x37ffc00, 0x0, 0x0, 0x0, 0x0, 0xbf7f0000, 0x0, 0x0, 0xfffc0000, 0x6dfcff, 0x0, 0x0, 0x0, 0xb47e0000, 0xbf, 0x0, 0xa30000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x180000, 0x3, 0x7c00000, 0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fff81, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f0000, 0x0, 0x7f0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8000, 0x0, 0x78000, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x60000000, 0x0, 0x0, 0x0, 0xffffffff, 0xffff3fff, 0x7f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf807c3a0, 0xfe7, 0x3c00, 0x0, 0x0, 0x0, 0x0, 0x1c, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xf87fffff, 0xffffffff, 0x201fff, 0xf8000010, 0xfffe, 0x0, 0x0, 0xf9ffff7f, 0x7db, 0x0, 0x0, 0x8000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4000, 0x0, 0xf000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f0000, 0x0, 0x0, 0x0, 0x7f0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf8000000, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]);
+//1344 bytes
+enum Extended_PictographicTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x40, 0x90], [ 0x100, 0xa0, 0x1800], [ 0x2020100, 0x2020202, 0x2020202, 0x3020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x30002, 0x40001, 0x60005, 0x80007, 0x90001, 0xa0001, 0x10001, 0x10001, 0x1000b, 0x1000c, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0xe000d, 0x10000f, 0x11000d, 0x130012, 0x150014, 0x1000d, 0xd000d, 0x16000d, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4200, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000000, 0x200, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2000004, 0x0, 0x0, 0x3f00000, 0x600, 0x0, 0x0, 0xc000000, 0x100, 0x0, 0x0, 0x100, 0x0, 0x8000, 0x70ffe00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x400c00, 0x1, 0x78000000, 0xfff7ffbf, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff003f, 0xffffffff, 0xffffffff, 0xffffffff, 0x2057ff3f, 0x180102, 0xb85090, 0xf8, 0xe00000, 0x80010002, 0x0, 0x0, 0x0, 0x300000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x180000e0, 0x0, 0x210000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20010000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2800000, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xe000, 0x8000, 0x0, 0xc003f000, 0x7fe4000, 0xffffe000, 0xffffffff, 0x3f, 0x400fffe, 0xf7fc8000, 0xfffffe00, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x7ffffff, 0xffffffff, 0x3fffffff, 0xffffffc0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x0, 0x0, 0x0, 0xfff00000, 0x0, 0x0, 0xffe00000, 0xffffffff, 0xf000, 0x0, 0xfc00ff00, 0x0, 0xff00, 0xffffc000, 0xffffffff, 0xffffffff, 0xfffff000, 0xf7ffffff, 0xffffffbf, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3fffffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]);
}
enum hangulLVTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x20, 0x40], [ 0x100, 0x80, 0xa00], [ 0x2010000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4000300020001, 0x1000700060005, 0x5000400030002, 0x2000100070006, 0x6000500040003, 0x3000200010007, 0x7000600050004, 0x4000300020001, 0x1000700060005, 0x5000400030002, 0x8000100070006, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x100000010000001, 0x1000000100000, 0x10000001000, 0x1000000100000010, 0x10000001000000, 0x100000010000, 0x1000000100, 0x100000010000001, 0x1000000100000, 0x10000001000, 0x1000000100000010, 0x10000001000000, 0x100000010000, 0x1000000100, 0x100000010000001, 0x1000000100000, 0x10000001000, 0x1000000100000010, 0x10000001000000, 0x100000010000, 0x1000000100, 0x100000010000001, 0x1000000100000, 0x10000001000, 0x1000000100000010, 0x10000001000000, 0x100000010000, 0x1000000100, 0x10000001000000, 0x100000010000, 0x100, 0x0, 0x0, 0x0, 0x0, 0x0]);
//832 bytes
enum hangulLVTTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x20, 0x40], [ 0x100, 0x80, 0xa00], [ 0x2010000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4000300020001, 0x1000700060005, 0x5000400030002, 0x2000100070006, 0x6000500040003, 0x3000200010007, 0x7000600050004, 0x4000300020001, 0x1000700060005, 0x5000400030002, 0x8000100070006, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfeffffffeffffffe, 0xfffeffffffefffff, 0xfffffeffffffefff, 0xeffffffeffffffef, 0xffeffffffeffffff, 0xffffeffffffeffff, 0xffffffeffffffeff, 0xfeffffffeffffffe, 0xfffeffffffefffff, 0xfffffeffffffefff, 0xeffffffeffffffef, 0xffeffffffeffffff, 0xffffeffffffeffff, 0xffffffeffffffeff, 0xfeffffffeffffffe, 0xfffeffffffefffff, 0xfffffeffffffefff, 0xeffffffeffffffef, 0xffeffffffeffffff, 0xffffeffffffeffff, 0xffffffeffffffeff, 0xfeffffffeffffffe, 0xfffeffffffefffff, 0xfffffeffffffefff, 0xeffffffeffffffef, 0xffeffffffeffffff, 0xffffeffffffeffff, 0xffffffeffffffeff, 0xffeffffffeffffff, 0xffffeffffffeffff, 0xffffffeff, 0x0, 0x0, 0x0, 0x0, 0x0]);
-//1920 bytes
-enum mcTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x20, 0x60], [ 0x100, 0x100, 0x2400], [ 0x202030202020100, 0x206020205020204, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3000200010000, 0x6000000050004, 0x7, 0x8000000000000, 0xb000a00090000, 0xc, 0x0, 0x0, 0x0, 0x0, 0xd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x110010000f000e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x15001400130012, 0x19001800170016, 0x1c001b001a, 0x20001f001e001d, 0x0, 0x0, 0x0, 0x21000000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x220000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc800000000000008, 0xde01, 0xc00000000000000c, 0x801981, 0xc000000000000008, 0x1, 0xc000000000000008, 0x1a01, 0x400000000000000c, 0x801981, 0xc000000000000000, 0x801dc6, 0xe, 0x1e, 0x400000000000000c, 0x8000000600d9f, 0xc00000000000000c, 0x801dc1, 0xc, 0xc0000ff038000, 0xc000000000000000, 0x8000000000000000, 0x0, 0x0, 0x1902180000000000, 0x3f9c00c00000, 0x1c009f98, 0x0, 0x10000000200000, 0x0, 0xc040000000000000, 0x1bf, 0x1fb0e7800000000, 0x0, 0x0, 0x0, 0x6000000, 0x7e01a00a00000, 0x0, 0x0, 0xe820000000000010, 0x1b, 0x4c200000004, 0xc5c8000000000, 0x300ff000000000, 0x0, 0x0, 0x80000200000000, 0xc00000000000, 0x0, 0x0, 0x0, 0x9800000000, 0x0, 0xfff0000000000003, 0xf, 0x0, 0xc0000, 0xcc30000000000008, 0x1, 0x19800000000000, 0x2800000000002000, 0x0, 0x20c80000000000, 0x0, 0x0, 0x0, 0x16d800000000, 0x5, 0x0, 0x187000000000004, 0x0, 0x100000000000, 0x60, 0x8038000000000004, 0x4001, 0x2c700000000000, 0x0, 0x0, 0x700000000, 0xc00000000000000c, 0xc0080399e, 0x0, 0x0, 0xe0000000000000, 0x23, 0x7a07000000000000, 0x2, 0x0, 0x0, 0x4f03800000000000, 0x0, 0x5807000000000000, 0x0, 0x40d00000000000, 0x0, 0x4300000000, 0x0, 0x0, 0x0, 0x100700000000000, 0x0, 0x0, 0x0, 0x21bf000000000000, 0x5, 0x0, 0x10f00e0000, 0x200000000000000, 0x1800000, 0x800000, 0x0, 0x4000800000000000, 0x0, 0x12020000000000, 0x0, 0x0, 0x0, 0x587c00, 0x0, 0x0, 0x0, 0x0, 0x60000000000000, 0xc030000000000008, 0x2, 0x0, 0x0, 0x0, 0xfffffffffffe0000, 0xff, 0x3000000000000, 0x0, 0x7e06000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]);
-//3456 bytes
-enum graphemeExtendTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x20, 0x88], [ 0x100, 0x1a0, 0x4a00], [ 0x402030202020100, 0xa09080207020605, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x20202020202020b, 0x202020202020202, 0x202020202020202, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1000000000000, 0x5000400030002, 0x9000800070006, 0xd000c000b000a, 0xf00000000000e, 0x10000000000000, 0x14001300120011, 0x160015, 0x17, 0x0, 0x0, 0x190018, 0x1a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b00000000, 0x1f001e001d001c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000000000000, 0x22002100000000, 0x25002400230000, 0x0, 0x2600000000, 0x29002800270000, 0x2d002c002b002a, 0x310030002f002e, 0x3400330032, 0x38003700360035, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x3b003a00000000, 0x3c000000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3d, 0x0, 0x0, 0x0, 0x3e000000000000, 0x40003f0000, 0x0, 0x4100000000, 0x0, 0x43003b0042, 0x44, 0x460045, 0x0, 0x0, 0x0, 0x0, 0x0, 0x480047, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffffffffffff, 0xffffffffffff, 0x0, 0x0, 0x0, 0x0, 0x3f8, 0x0, 0x0, 0x0, 0xbffffffffffe0000, 0xb6, 0x7ff0000, 0x10000fffff800, 0x0, 0x3d9f9fc00000, 0xffff000000020000, 0x7ff, 0x1ffc000000000, 0x200ff80000000000, 0x3eeffbc00000, 0xe000000, 0xff000000, 0xfffffffbfffffc00, 0x1400000000000007, 0xc00fe21fe, 0x5000000000000002, 0x4000000c0080201e, 0x1000000000000006, 0x23000000023986, 0x1000000000000006, 0xfc00000c000021be, 0xd000000000000002, 0xc00e0201e, 0x4000000000000004, 0x802001, 0xd000000000000011, 0xc00603dc1, 0x9000000000000002, 0xc00603044, 0x5800000000000003, 0xc0080201e, 0x2, 0x805c8400, 0x7f2000000000000, 0x7f80, 0x1ff2000000000000, 0x7f00, 0x2a0000003000000, 0x7ffe000000000000, 0x1ffffffffeffe0df, 0x40, 0x66fde00000000000, 0x1e0001c3000000, 0x20002064, 0x0, 0x0, 0xe0000000, 0x0, 0x0, 0xc0000001c0000, 0xc0000000c0000, 0x3fb0000000000000, 0x200ffe40, 0xb800, 0x0, 0x20000000060, 0x0, 0xe04018700000000, 0x0, 0x0, 0x0, 0x9800000, 0x9ff81fe57f400000, 0xffff000000000000, 0x7fff, 0x17f000000000000f, 0xff80000000004, 0x3b3c00000003, 0x3a34000000000, 0xcff00000000000, 0x0, 0x0, 0x31021fdfff70000, 0x0, 0x0, 0x0, 0xffffffffffffffff, 0x1000, 0x0, 0x0, 0x1ffffffff0000, 0x0, 0x0, 0x0, 0x3800000000000, 0x0, 0x8000000000000000, 0x0, 0xffffffff00000000, 0xfc0000000000, 0x0, 0x6000000, 0x0, 0x0, 0x3ff7800000000000, 0xc0000000, 0x3000000000000, 0x106000000844, 0x0, 0x0, 0x8003ffff00000030, 0x3fc000000000, 0x3ff80, 0x33c8000000000007, 0x2000000000, 0x667e0000000000, 0x1000000000001008, 0xc19d000000000000, 0x40300000000002, 0x0, 0x0, 0x0, 0x212000000000, 0x40000000, 0x0, 0x0, 0x0, 0xffff0000ffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0000000, 0x0, 0x0, 0x0, 0x0, 0x2000000000000000, 0x0, 0x0, 0x0, 0x100000000, 0x0, 0x7c0000000000000, 0x0, 0x0, 0x870000000000f06e, 0x0, 0x0, 0x6000000000, 0xf000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x180000000000, 0xe000000000000000, 0x0, 0x1ffc0, 0x3c, 0x0, 0xff00000000000002, 0x801900000000007f, 0x678000000000003, 0x4, 0x1fef8000000007, 0x8000000000000, 0x7fc0000000000003, 0x9e00, 0x40d3800000000000, 0x2, 0x0, 0x7f880000000, 0x5800000000000003, 0x1f1fc000800001, 0x0, 0x0, 0xff00000000000000, 0x4000005c, 0xa5f9000000000000, 0xd, 0x0, 0x0, 0xb03c800000000000, 0x30000001, 0xa7f8000000000000, 0x1, 0xbf280000000000, 0x0, 0xfbce0000000, 0x0, 0x0, 0x0, 0x6ff800000000000, 0x0, 0x0, 0x0, 0x5801000000000000, 0x8, 0x0, 0x10cf00000, 0x79f80000000007fe, 0xe7e0080, 0x37ffc00, 0x0, 0xbf7f000000000000, 0x0, 0x6dfcfffffc0000, 0x0, 0xb47e000000000000, 0xbf, 0xa30000, 0x0, 0x0, 0x0, 0x0, 0x18000000000000, 0x7c0000000000003, 0x5, 0x0, 0x0, 0x0, 0x3fff81, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f000000000000, 0x7f000000000000, 0x0, 0x0, 0x0, 0x0, 0x8000, 0x78000, 0x1000000000, 0x0, 0x0, 0x60000000, 0x0, 0xffff3fffffffffff, 0x7f, 0x0, 0x0, 0x0, 0xf807c3a000000000, 0x3c0000000fe7, 0x0, 0x0, 0x1c, 0x0, 0x0, 0xf87fffffffffffff, 0x201fffffffffff, 0xfffef8000010, 0x0, 0x7dbf9ffff7f, 0x0, 0x8000, 0x0, 0x0, 0x0, 0x400000000000, 0xf00000000000, 0x0, 0x0, 0x0, 0xf00000000000, 0x0, 0x0, 0x0, 0x7f0000, 0x0, 0x7f0, 0x0, 0x0, 0xffffffff00000000, 0xffffffffffffffff, 0x0, 0x0, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffff, 0x0, 0x0, 0x0, 0x0]);
+//896 bytes
+enum prependTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x20, 0x40], [ 0x100, 0x80, 0xc00], [ 0x101010101010100, 0x101010101010102, 0x101010101010101, 0x101010101010101, 0x101010101010101, 0x101010101010101, 0x101010101010101, 0x101010101010101, 0x101010101010101, 0x101010101010101, 0x101010101010101, 0x101010101010101, 0x101010101010101, 0x101010101010101, 0x101010101010101, 0x101010101010101, 0x101010101010101, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2000100000000, 0x3, 0x40000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x60005, 0x0, 0x800070000, 0xa000000090000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0x0, 0x0, 0x20000000, 0x8000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30000, 0x400000000, 0x0, 0x4000, 0x0, 0x0, 0x0, 0x0, 0x2000000000000000, 0x2000, 0x0, 0x0, 0x0, 0xc, 0x8000000000000000, 0x2, 0x0, 0x0, 0x400000000000000, 0x0, 0x3f0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]);
+//1280 bytes
+enum controlTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x20, 0x68], [ 0x100, 0x120, 0xe00], [ 0x302020202020100, 0x206050202020402, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020207, 0x202020202020202, 0x202020202020202, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1000100010000, 0x1000200010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010003, 0x1000100010001, 0x1000100010004, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x6000500010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010007, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010008, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100090001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0xc000c000b000a, 0xc000c000c000c, 0xc000c000c000c, 0xc000c000c000c, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0xffffdbff, 0x8000000000000000, 0x2000ffffffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000000, 0x0, 0x0, 0x0, 0x4000, 0x0, 0x0, 0x0, 0x7f000000c800, 0xffff00000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8000000000000000, 0x0, 0x0, 0x0, 0xfff000000000000, 0xffff000000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf00000000, 0x0, 0x0, 0x7f8000000000000, 0x0, 0x0, 0xffffffff, 0x0, 0xffffffffffffffff, 0xffffffffffffffff, 0x0, 0x0, 0x0, 0xffff000000000000, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x0, 0x0, 0x0, 0x0]);
+//1856 bytes
+enum spacingMarkTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x20, 0x58], [ 0x100, 0xe0, 0x2400], [ 0x101020101010100, 0x105010104010103, 0x101010101010101, 0x101010101010101, 0x101010101010101, 0x101010101010101, 0x101010101010101, 0x101010101010101, 0x101010101010101, 0x101010101010101, 0x101010101010101, 0x101010101010101, 0x101010101010101, 0x101010101010101, 0x101010101010101, 0x101010101010101, 0x101010101010101, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3000200010000, 0x7000600050004, 0x8, 0x9000000000000, 0xc000b000a0000, 0xd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x110010000f000e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x15001400130012, 0x19001800170016, 0x1c001b001a, 0x20001f001e001d, 0x0, 0x0, 0x0, 0x21000000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x220000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc800000000000008, 0xde01, 0x800000000000000c, 0x1981, 0xc000000000000008, 0x1, 0xc000000000000008, 0x1a01, 0xc, 0x1981, 0x8000000000000000, 0x1dc6, 0xe, 0x1e, 0x400000000000000c, 0x8000000000d9b, 0x800000000000000c, 0x1dc1, 0xc, 0xc00007f030000, 0x8000000000000, 0x0, 0x8000000000000, 0x0, 0xc000000000000000, 0x8000000000000000, 0x0, 0x0, 0x1802000000000000, 0xc00000, 0x10, 0x0, 0x10000000200000, 0x0, 0xc040000000000000, 0x1bf, 0x1fb0e7800000000, 0x0, 0x0, 0x0, 0x6000000, 0x7e00000a00000, 0x0, 0x0, 0xe800000000000010, 0x1b, 0x4c200000004, 0xc5c8000000000, 0x300ff000000000, 0x0, 0x0, 0x80000200000000, 0x9800000000, 0x0, 0xfff0000000000003, 0xf, 0x0, 0xc0000, 0xcc30000000000008, 0x1, 0x19800000000000, 0x2000, 0x0, 0x20c80000000000, 0x0, 0x0, 0x0, 0x16d800000000, 0x5, 0x0, 0x187000000000004, 0x0, 0x100000000000, 0x60, 0x8038000000000004, 0x4001, 0x2c700000000000, 0x0, 0x0, 0x700000000, 0x800000000000000c, 0xc0000399e, 0x0, 0x0, 0xe0000000000000, 0x23, 0x5a06000000000000, 0x2, 0x0, 0x0, 0x4f03000000000000, 0x0, 0x5807000000000000, 0x0, 0x40d00000000000, 0x0, 0x4000000000, 0x0, 0x0, 0x0, 0x100700000000000, 0x0, 0x0, 0x0, 0x21be000000000000, 0x5, 0x0, 0x10f00e0000, 0x200000000000000, 0x1800000, 0x800000, 0x0, 0x4000800000000000, 0x0, 0x12020000000000, 0x0, 0x0, 0x0, 0x587c00, 0x0, 0x0, 0x0, 0x0, 0x60000000000000, 0xc030000000000008, 0x2, 0x0, 0x0, 0x0, 0xfffffffffffe0000, 0xff, 0x3000000000000, 0x0, 0x204000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]);
+//3488 bytes
+enum graphemeExtendTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x20, 0x88], [ 0x100, 0x1a0, 0x4b00], [ 0x402030202020100, 0xa09080207020605, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x20202020202020b, 0x202020202020202, 0x202020202020202, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1000000000000, 0x5000400030002, 0x9000800070006, 0xd000c000b000a, 0xf00000000000e, 0x10000000000000, 0x14001300120011, 0x160015, 0x17, 0x0, 0x0, 0x190018, 0x1a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b00000000, 0x1f001e001d001c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000000000000, 0x22002100000000, 0x25002400230000, 0x0, 0x2600000000, 0x29002800270000, 0x2d002c002b002a, 0x310030002f002e, 0x3400330032, 0x38003700360035, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x3b003a00000000, 0x3c000000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3d, 0x0, 0x0, 0x0, 0x3e000000000000, 0x40003f0000, 0x0, 0x4100000000, 0x0, 0x43003b0042, 0x44, 0x460045, 0x0, 0x47000000000000, 0x0, 0x0, 0x0, 0x490048, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffffffffffff, 0xffffffffffff, 0x0, 0x0, 0x0, 0x0, 0x3f8, 0x0, 0x0, 0x0, 0xbffffffffffe0000, 0xb6, 0x7ff0000, 0x10000fffff800, 0x0, 0x3d9f9fc00000, 0xffff000000020000, 0x7ff, 0x1ffc000000000, 0x200ff80000000000, 0x3eeffbc00000, 0xe000000, 0xff000000, 0xfffffffbfffffc00, 0x1400000000000007, 0xc00fe21fe, 0x5000000000000002, 0x4000000c0080201e, 0x1000000000000006, 0x23000000023986, 0x1000000000000006, 0xfc00000c000021be, 0xd000000000000002, 0xc00e0201e, 0x4000000000000004, 0x802001, 0xd000000000000011, 0xc00603dc1, 0x9000000000000002, 0xc00603044, 0x5800000000000003, 0xc0080201e, 0x2, 0x805c8400, 0x7f2000000000000, 0x7f80, 0x1ff2000000000000, 0x7f00, 0x2a0000003000000, 0x7ffe000000000000, 0x1ffffffffeffe0df, 0x40, 0x66fde00000000000, 0x1e0001c3000000, 0x20002064, 0x0, 0x0, 0xe0000000, 0x0, 0x0, 0xc0000001c0000, 0xc0000000c0000, 0x3fb0000000000000, 0x200ffe40, 0xb800, 0x0, 0x20000000060, 0x0, 0xe04018700000000, 0x0, 0x0, 0x0, 0x9800000, 0x9ff81fe57f400000, 0xffff000000000000, 0x7fff, 0x17f000000000000f, 0xff80000000004, 0x3b3c00000003, 0x3a34000000000, 0xcff00000000000, 0x0, 0x0, 0x31021fdfff70000, 0x0, 0x0, 0x0, 0xffffffffffffffff, 0x1000, 0x0, 0x0, 0x1ffffffff0000, 0x0, 0x0, 0x0, 0x3800000000000, 0x0, 0x8000000000000000, 0x0, 0xffffffff00000000, 0xfc0000000000, 0x0, 0x6000000, 0x0, 0x0, 0x3ff7800000000000, 0xc0000000, 0x3000000000000, 0x106000000844, 0x0, 0x0, 0x8003ffff00000030, 0x3fc000000000, 0x3ff80, 0x33c8000000000007, 0x2000000000, 0x667e0000000000, 0x1000000000001008, 0xc19d000000000000, 0x40300000000002, 0x0, 0x0, 0x0, 0x212000000000, 0x40000000, 0x0, 0x0, 0x0, 0xffff0000ffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0000000, 0x0, 0x0, 0x0, 0x0, 0x2000000000000000, 0x0, 0x0, 0x0, 0x100000000, 0x0, 0x7c0000000000000, 0x0, 0x0, 0x870000000000f06e, 0x0, 0x0, 0x6000000000, 0xf000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x180000000000, 0xe000000000000000, 0x0, 0x1ffc0, 0x3c, 0x0, 0xff00000000000002, 0x801900000000007f, 0x678000000000003, 0x4, 0x1fef8000000007, 0x8000000000000, 0x7fc0000000000003, 0x9e00, 0x40d3800000000000, 0x2, 0x0, 0x7f880000000, 0x5800000000000003, 0x1f1fc000800001, 0x0, 0x0, 0xff00000000000000, 0x4000005c, 0xa5f9000000000000, 0xd, 0x0, 0x0, 0xb03c800000000000, 0x30000001, 0xa7f8000000000000, 0x1, 0xbf280000000000, 0x0, 0xfbce0000000, 0x0, 0x0, 0x0, 0x6ff800000000000, 0x0, 0x0, 0x0, 0x5801000000000000, 0x8, 0x0, 0x10cf00000, 0x79f80000000007fe, 0xe7e0080, 0x37ffc00, 0x0, 0xbf7f000000000000, 0x0, 0x6dfcfffffc0000, 0x0, 0xb47e000000000000, 0xbf, 0xa30000, 0x0, 0x0, 0x0, 0x0, 0x18000000000000, 0x7c0000000000003, 0x5, 0x0, 0x0, 0x0, 0x3fff81, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f000000000000, 0x7f000000000000, 0x0, 0x0, 0x0, 0x0, 0x8000, 0x78000, 0x1000000000, 0x0, 0x0, 0x60000000, 0x0, 0xffff3fffffffffff, 0x7f, 0x0, 0x0, 0x0, 0xf807c3a000000000, 0x3c0000000fe7, 0x0, 0x0, 0x1c, 0x0, 0x0, 0xf87fffffffffffff, 0x201fffffffffff, 0xfffef8000010, 0x0, 0x7dbf9ffff7f, 0x0, 0x8000, 0x0, 0x0, 0x0, 0x400000000000, 0xf00000000000, 0x0, 0x0, 0x0, 0xf00000000000, 0x0, 0x0, 0x0, 0x7f0000, 0x0, 0x7f0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf800000000000000, 0xffffffff00000000, 0xffffffffffffffff, 0x0, 0x0, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffff, 0x0, 0x0, 0x0, 0x0]);
+//1344 bytes
+enum Extended_PictographicTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x20, 0x48], [ 0x100, 0xa0, 0x1800], [ 0x202020202020100, 0x302020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1000100010000, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x4000100030002, 0x8000700060005, 0xa000100090001, 0x1000100010001, 0x1000c0001000b, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x10000f000e000d, 0x1300120011000d, 0x1000d00150014, 0x16000d000d000d, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x0, 0x0, 0x420000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1000000000000000, 0x200, 0x0, 0x0, 0x200000400000000, 0x0, 0x60003f00000, 0x0, 0x1000c000000, 0x0, 0x100, 0x70ffe0000008000, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x400c0000000000, 0x7800000000000001, 0xfffffffffff7ffbf, 0xffffffffffffffff, 0xffffffffffff003f, 0xffffffffffffffff, 0x1801022057ff3f, 0xf800b85090, 0x8001000200e00000, 0x0, 0x30000000000000, 0x0, 0x0, 0x0, 0x180000e0, 0x210000, 0x0, 0x0, 0x2001000000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2800000, 0x0, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x80000000e000, 0xc003f00000000000, 0xffffe00007fe4000, 0x3fffffffff, 0xf7fc80000400fffe, 0xfffffffffffffe00, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x7ffffffffffffff, 0x3fffffffffffffff, 0xffffffffffffffc0, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x0, 0xfff0000000000000, 0x0, 0xffffffffffe00000, 0xf000, 0xfc00ff00, 0xffffc0000000ff00, 0xffffffffffffffff, 0xf7fffffffffff000, 0xffffffffffffffbf, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x3fffffffffffffff, 0x0, 0x0, 0x0, 0x0]);
}
version (DigitalMars)
{
- version = INLINE_YL2X; // x87 has opcodes for these
+ version (OSX) { } // macOS 13 (M1) has issues emulating instruction
+ else version = INLINE_YL2X; // x87 has opcodes for these
}
version (D_InlineAsm_X86) version = InlineAsm_X86_Any;
private
{
- // Coefficients shared across log(), log2(), log10().
+ // Coefficients shared across log(), log2(), log10(), log1p().
template LogCoeffs(T)
{
import std.math : floatTraits, RealFormat;
alias log2Q = logQ;
// Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)/Q(x)
+ static immutable double[7] logp1P = [
+ 2.0039553499201281259648E1,
+ 5.7112963590585538103336E1,
+ 6.0949667980987787057556E1,
+ 2.9911919328553073277375E1,
+ 6.5787325942061044846969E0,
+ 4.9854102823193375972212E-1,
+ 4.5270000862445199635215E-5,
+ ];
+ static immutable double[7] logp1Q = [
+ 1.0000000000000000000000E0,
+ 6.0118660497603843919306E1,
+ 2.1642788614495947685003E2,
+ 3.0909872225312059774938E2,
+ 2.2176239823732856465394E2,
+ 8.3047565967967209469434E1,
+ 1.5062909083469192043167E1,
+ ];
+
static immutable double[7] log10P = [
1.98892446572874072159E1,
5.67349287391754285487E1,
7.0376836292E-2,
];
+ // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)/Q(x)
+ static immutable float[7] logp1P = [
+ 2.0039553499E1,
+ 5.7112963590E1,
+ 6.0949667980E1,
+ 2.9911919328E1,
+ 6.5787325942E0,
+ 4.9854102823E-1,
+ 4.5270000862E-5,
+ ];
+ static immutable float[7] logp1Q = [
+ 1.00000000000E0,
+ 6.01186604976E1,
+ 2.16427886144E2,
+ 3.09098722253E2,
+ 2.21762398237E2,
+ 8.30475659679E1,
+ 1.50629090834E1,
+ ];
+
// log2 and log10 uses the same coefficients as log.
alias log2P = logP;
alias log10P = logP;
assert(feqrel(log(E), 1) >= real.mant_dig - 1);
}
-private T logImpl(T)(T x) @safe pure nothrow @nogc
+private T logImpl(T, bool LOG1P = false)(T x) @safe pure nothrow @nogc
{
import std.math.constants : SQRT1_2;
import std.math.algebraic : poly;
alias coeffs = LogCoeffs!T;
alias F = floatTraits!T;
+ static if (LOG1P)
+ {
+ const T xm1 = x;
+ x = x + 1.0;
+ }
+
static if (F.realFormat == RealFormat.ieeeExtended ||
F.realFormat == RealFormat.ieeeExtended53 ||
F.realFormat == RealFormat.ieeeQuadruple)
if (x < SQRT1_2)
{
exp -= 1;
- x = 2.0 * x - 1.0;
+ static if (LOG1P)
+ {
+ if (exp != 0)
+ x = 2.0 * x - 1.0;
+ else
+ x = xm1;
+ }
+ else
+ x = 2.0 * x - 1.0;
+
}
else
{
- x = x - 1.0;
+ static if (LOG1P)
+ {
+ if (exp != 0)
+ x = x - 1.0;
+ else
+ x = xm1;
+ }
+ else
+ x = x - 1.0;
}
z = x * x;
static if (F.realFormat == RealFormat.ieeeSingle)
return z;
}
+@safe @nogc nothrow unittest
+{
+ import std.math : floatTraits, RealFormat;
+ import std.meta : AliasSeq;
+
+ static void testLog(T)(T[2][] vals)
+ {
+ import std.math.operations : isClose;
+ import std.math.traits : isNaN;
+ foreach (ref pair; vals)
+ {
+ if (isNaN(pair[1]))
+ assert(isNaN(log(pair[0])));
+ else
+ assert(isClose(log(pair[0]), pair[1]));
+ }
+ }
+ static foreach (F; AliasSeq!(float, double, real))
+ {{
+ F[2][24] vals = [
+ [F(1), F(0x0p+0)], [F(2), F(0x1.62e42fefa39ef358p-1)],
+ [F(4), F(0x1.62e42fefa39ef358p+0)], [F(8), F(0x1.0a2b23f3bab73682p+1)],
+ [F(16), F(0x1.62e42fefa39ef358p+1)], [F(32), F(0x1.bb9d3beb8c86b02ep+1)],
+ [F(64), F(0x1.0a2b23f3bab73682p+2)], [F(128), F(0x1.3687a9f1af2b14ecp+2)],
+ [F(256), F(0x1.62e42fefa39ef358p+2)], [F(512), F(0x1.8f40b5ed9812d1c2p+2)],
+ [F(1024), F(0x1.bb9d3beb8c86b02ep+2)], [F(2048), F(0x1.e7f9c1e980fa8e98p+2)],
+ [F(3), F(0x1.193ea7aad030a976p+0)], [F(5), F(0x1.9c041f7ed8d336bp+0)],
+ [F(7), F(0x1.f2272ae325a57546p+0)], [F(15), F(0x1.5aa16394d481f014p+1)],
+ [F(17), F(0x1.6aa6bc1fa7f79cfp+1)], [F(31), F(0x1.b78ce48912b59f12p+1)],
+ [F(33), F(0x1.bf8d8f4d5b8d1038p+1)], [F(63), F(0x1.09291e8e3181b20ep+2)],
+ [F(65), F(0x1.0b292939429755ap+2)], [F(-0), -F.infinity], [F(0), -F.infinity],
+ [F(10000), F(0x1.26bb1bbb5551582ep+3)],
+ ];
+ testLog(vals);
+ }}
+ {
+ float[2][16] vals = [
+ [float.nan, float.nan],[-float.nan, float.nan],
+ [float.infinity, float.infinity], [-float.infinity, float.nan],
+ [float.min_normal, -0x1.5d58ap+6f], [-float.min_normal, float.nan],
+ [float.max, 0x1.62e43p+6f], [-float.max, float.nan],
+ [float.min_normal / 2, -0x1.601e68p+6f], [-float.min_normal / 2, float.nan],
+ [float.max / 2, 0x1.601e68p+6f], [-float.max / 2, float.nan],
+ [float.min_normal / 3, -0x1.61bd9ap+6f], [-float.min_normal / 3, float.nan],
+ [float.max / 3, 0x1.5e7f36p+6f], [-float.max / 3, float.nan],
+ ];
+ testLog(vals);
+ }
+ {
+ double[2][16] vals = [
+ [double.nan, double.nan],[-double.nan, double.nan],
+ [double.infinity, double.infinity], [-double.infinity, double.nan],
+ [double.min_normal, -0x1.6232bdd7abcd2p+9], [-double.min_normal, double.nan],
+ [double.max, 0x1.62e42fefa39efp+9], [-double.max, double.nan],
+ [double.min_normal / 2, -0x1.628b76e3a7b61p+9], [-double.min_normal / 2, double.nan],
+ [double.max / 2, 0x1.628b76e3a7b61p+9], [-double.max / 2, double.nan],
+ [double.min_normal / 3, -0x1.62bf5d2b81354p+9], [-double.min_normal / 3, double.nan],
+ [double.max / 3, 0x1.6257909bce36ep+9], [-double.max / 3, double.nan],
+ ];
+ testLog(vals);
+ }
+ alias F = floatTraits!real;
+ static if (F.realFormat == RealFormat.ieeeExtended || F.realFormat == RealFormat.ieeeQuadruple)
+ {{
+ real[2][16] vals = [
+ [real.nan, real.nan],[-real.nan, real.nan],
+ [real.infinity, real.infinity], [-real.infinity, real.nan],
+ [real.min_normal, -0x1.62d918ce2421d66p+13L], [-real.min_normal, real.nan],
+ [real.max, 0x1.62e42fefa39ef358p+13L], [-real.max, real.nan],
+ [real.min_normal / 2, -0x1.62dea45ee3e064dcp+13L], [-real.min_normal / 2, real.nan],
+ [real.max / 2, 0x1.62dea45ee3e064dcp+13L], [-real.max / 2, real.nan],
+ [real.min_normal / 3, -0x1.62e1e2c3617857e6p+13L], [-real.min_normal / 3, real.nan],
+ [real.max / 3, 0x1.62db65fa664871d2p+13L], [-real.max / 3, real.nan],
+ ];
+ testLog(vals);
+ }}
+}
+
/**************************************
* Calculate the base-10 logarithm of x.
*
assert(fabs(log10(1000.0L) - 3) < .000001);
}
+@safe pure nothrow @nogc unittest
+{
+ import std.math.algebraic : fabs;
+
+ assert(fabs(log10(1000.0) - 3) < .000001);
+ assert(fabs(log10(1000.0f) - 3) < .000001);
+}
+
private T log10Impl(T)(T x) @safe pure nothrow @nogc
{
import std.math.constants : SQRT1_2;
return z;
}
+@safe @nogc nothrow unittest
+{
+ import std.math : floatTraits, RealFormat;
+ import std.meta : AliasSeq;
+
+ static void testLog10(T)(T[2][] vals)
+ {
+ import std.math.operations : isClose;
+ import std.math.traits : isNaN;
+ foreach (ref pair; vals)
+ {
+ if (isNaN(pair[1]))
+ assert(isNaN(log10(pair[0])));
+ else
+ assert(isClose(log10(pair[0]), pair[1]));
+ }
+ }
+ static foreach (F; AliasSeq!(float, double, real))
+ {{
+ F[2][24] vals = [
+ [F(1), F(0x0p+0)], [F(2), F(0x1.34413509f79fef32p-2)],
+ [F(4), F(0x1.34413509f79fef32p-1)], [F(8), F(0x1.ce61cf8ef36fe6cap-1)],
+ [F(16), F(0x1.34413509f79fef32p+0)], [F(32), F(0x1.8151824c7587eafep+0)],
+ [F(64), F(0x1.ce61cf8ef36fe6cap+0)], [F(128), F(0x1.0db90e68b8abf14cp+1)],
+ [F(256), F(0x1.34413509f79fef32p+1)], [F(512), F(0x1.5ac95bab3693ed18p+1)],
+ [F(1024), F(0x1.8151824c7587eafep+1)], [F(2048), F(0x1.a7d9a8edb47be8e4p+1)],
+ [F(3), F(0x1.e8927964fd5fd08cp-2)], [F(5), F(0x1.65df657b04300868p-1)],
+ [F(7), F(0x1.b0b0b0b78cc3f296p-1)], [F(15), F(0x1.2d145116c16ff856p+0)],
+ [F(17), F(0x1.3afeb354b7d9731ap+0)], [F(31), F(0x1.7dc9e145867e62eap+0)],
+ [F(33), F(0x1.84bd545e4baeddp+0)], [F(63), F(0x1.cca1950e4511e192p+0)],
+ [F(65), F(0x1.d01b16f9433cf7b8p+0)], [F(-0), -F.infinity], [F(0), -F.infinity],
+ [F(10000), F(0x1p+2)],
+ ];
+ testLog10(vals);
+ }}
+ {
+ float[2][16] vals = [
+ [float.nan, float.nan],[-float.nan, float.nan],
+ [float.infinity, float.infinity], [-float.infinity, float.nan],
+ [float.min_normal, -0x1.2f703p+5f], [-float.min_normal, float.nan],
+ [float.max, 0x1.344136p+5f], [-float.max, float.nan],
+ [float.min_normal / 2, -0x1.31d8b2p+5f], [-float.min_normal / 2, float.nan],
+ [float.max / 2, 0x1.31d8b2p+5f], [-float.max / 2, float.nan],
+ [float.min_normal / 3, -0x1.334156p+5f], [-float.min_normal / 3, float.nan],
+ [float.max / 3, 0x1.30701p+5f], [-float.max / 3, float.nan],
+ ];
+ testLog10(vals);
+ }
+ {
+ double[2][16] vals = [
+ [double.nan, double.nan],[-double.nan, double.nan],
+ [double.infinity, double.infinity], [-double.infinity, double.nan],
+ [double.min_normal, -0x1.33a7146f72a42p+8], [-double.min_normal, double.nan],
+ [double.max, 0x1.34413509f79ffp+8], [-double.max, double.nan],
+ [double.min_normal / 2, -0x1.33f424bcb522p+8], [-double.min_normal / 2, double.nan],
+ [double.max / 2, 0x1.33f424bcb522p+8], [-double.max / 2, double.nan],
+ [double.min_normal / 3, -0x1.3421390dcbe37p+8], [-double.min_normal / 3, double.nan],
+ [double.max / 3, 0x1.33c7106b9e609p+8], [-double.max / 3, double.nan],
+ ];
+ testLog10(vals);
+ }
+ alias F = floatTraits!real;
+ static if (F.realFormat == RealFormat.ieeeExtended || F.realFormat == RealFormat.ieeeQuadruple)
+ {{
+ real[2][16] vals = [
+ [real.nan, real.nan],[-real.nan, real.nan],
+ [real.infinity, real.infinity], [-real.infinity, real.nan],
+ [real.min_normal, -0x1.343793004f503232p+12L], [-real.min_normal, real.nan],
+ [real.max, 0x1.34413509f79fef32p+12L], [-real.max, real.nan],
+ [real.min_normal / 2, -0x1.343c6405237810b2p+12L], [-real.min_normal / 2, real.nan],
+ [real.max / 2, 0x1.343c6405237810b2p+12L], [-real.max / 2, real.nan],
+ [real.min_normal / 3, -0x1.343f354a34e427bp+12L], [-real.min_normal / 3, real.nan],
+ [real.max / 3, 0x1.343992c0120bf9b2p+12L], [-real.max / 3, real.nan],
+ ];
+ testLog10(vals);
+ }}
+}
+
/**
* Calculates the natural logarithm of 1 + x.
*
private T log1pImpl(T)(T x) @safe pure nothrow @nogc
{
import std.math.traits : isNaN, isInfinity, signbit;
+ import std.math.algebraic : poly;
+ import std.math.constants : SQRT1_2, SQRT2;
+ import std.math : floatTraits, RealFormat;
// Special cases.
if (isNaN(x) || x == 0.0)
if (x < -1.0)
return T.nan;
- return logImpl(x + 1.0);
+ alias F = floatTraits!T;
+ static if (F.realFormat == RealFormat.ieeeSingle ||
+ F.realFormat == RealFormat.ieeeDouble)
+ {
+ // When the input is within the range 1/sqrt(2) <= x+1 <= sqrt(2), compute
+ // log1p inline. Forwarding to log() would otherwise result in inaccuracies.
+ const T xp1 = x + 1.0;
+ if (xp1 >= SQRT1_2 && xp1 <= SQRT2)
+ {
+ alias coeffs = LogCoeffs!T;
+
+ T px = poly(x, coeffs.logp1P);
+ T qx = poly(x, coeffs.logp1Q);
+ const T xx = x * x;
+ qx = x + ((cast(T) -0.5) * xx + x * (xx * px / qx));
+ return qx;
+ }
+ }
+
+ return logImpl!(T, true)(x);
+}
+
+@safe @nogc nothrow unittest
+{
+ import std.math : floatTraits, RealFormat;
+ import std.meta : AliasSeq;
+
+ static void testLog1p(T)(T[2][] vals)
+ {
+ import std.math.operations : isClose;
+ import std.math.traits : isNaN;
+ foreach (ref pair; vals)
+ {
+ if (isNaN(pair[1]))
+ assert(isNaN(log1p(pair[0])));
+ else
+ assert(isClose(log1p(pair[0]), pair[1]));
+ }
+ }
+ static foreach (F; AliasSeq!(float, double, real))
+ {{
+ F[2][24] vals = [
+ [F(1), F(0x1.62e42fefa39ef358p-1)], [F(2), F(0x1.193ea7aad030a976p+0)],
+ [F(4), F(0x1.9c041f7ed8d336bp+0)], [F(8), F(0x1.193ea7aad030a976p+1)],
+ [F(16), F(0x1.6aa6bc1fa7f79cfp+1)], [F(32), F(0x1.bf8d8f4d5b8d1038p+1)],
+ [F(64), F(0x1.0b292939429755ap+2)], [F(128), F(0x1.37072a9b5b6cb31p+2)],
+ [F(256), F(0x1.63241004e9010ad8p+2)], [F(512), F(0x1.8f60adf041bde2a8p+2)],
+ [F(1024), F(0x1.bbad39ebe1cc08b6p+2)], [F(2048), F(0x1.e801c1698ba4395cp+2)],
+ [F(3), F(0x1.62e42fefa39ef358p+0)], [F(5), F(0x1.cab0bfa2a2002322p+0)],
+ [F(7), F(0x1.0a2b23f3bab73682p+1)], [F(15), F(0x1.62e42fefa39ef358p+1)],
+ [F(17), F(0x1.71f7b3a6b918664cp+1)], [F(31), F(0x1.bb9d3beb8c86b02ep+1)],
+ [F(33), F(0x1.c35fc81b90df59c6p+1)], [F(63), F(0x1.0a2b23f3bab73682p+2)],
+ [F(65), F(0x1.0c234da4a23a6686p+2)], [F(-0), F(-0x0p+0)], [F(0), F(0x0p+0)],
+ [F(10000), F(0x1.26bbed6fbd84182ep+3)],
+ ];
+ testLog1p(vals);
+ }}
+ {
+ float[2][16] vals = [
+ [float.nan, float.nan],[-float.nan, float.nan],
+ [float.infinity, float.infinity], [-float.infinity, float.nan],
+ [float.min_normal, 0x1p-126f], [-float.min_normal, -0x1p-126f],
+ [float.max, 0x1.62e43p+6f], [-float.max, float.nan],
+ [float.min_normal / 2, 0x0.8p-126f], [-float.min_normal / 2, -0x0.8p-126f],
+ [float.max / 2, 0x1.601e68p+6f], [-float.max / 2, float.nan],
+ [float.min_normal / 3, 0x0.555556p-126f], [-float.min_normal / 3, -0x0.555556p-126f],
+ [float.max / 3, 0x1.5e7f36p+6f], [-float.max / 3, float.nan],
+ ];
+ testLog1p(vals);
+ }
+ {
+ double[2][16] vals = [
+ [double.nan, double.nan],[-double.nan, double.nan],
+ [double.infinity, double.infinity], [-double.infinity, double.nan],
+ [double.min_normal, 0x1p-1022], [-double.min_normal, -0x1p-1022],
+ [double.max, 0x1.62e42fefa39efp+9], [-double.max, double.nan],
+ [double.min_normal / 2, 0x0.8p-1022], [-double.min_normal / 2, -0x0.8p-1022],
+ [double.max / 2, 0x1.628b76e3a7b61p+9], [-double.max / 2, double.nan],
+ [double.min_normal / 3, 0x0.5555555555555p-1022], [-double.min_normal / 3, -0x0.5555555555555p-1022],
+ [double.max / 3, 0x1.6257909bce36ep+9], [-double.max / 3, double.nan],
+ ];
+ testLog1p(vals);
+ }
+ alias F = floatTraits!real;
+ static if (F.realFormat == RealFormat.ieeeExtended || F.realFormat == RealFormat.ieeeQuadruple)
+ {{
+ real[2][16] vals = [
+ [real.nan, real.nan],[-real.nan, real.nan],
+ [real.infinity, real.infinity], [-real.infinity, real.nan],
+ [real.min_normal, 0x1p-16382L], [-real.min_normal, -0x1p-16382L],
+ [real.max, 0x1.62e42fefa39ef358p+13L], [-real.max, real.nan],
+ [real.min_normal / 2, 0x0.8p-16382L], [-real.min_normal / 2, -0x0.8p-16382L],
+ [real.max / 2, 0x1.62dea45ee3e064dcp+13L], [-real.max / 2, real.nan],
+ [real.min_normal / 3, 0x0.5555555555555556p-16382L], [-real.min_normal / 3, -0x0.5555555555555556p-16382L],
+ [real.max / 3, 0x1.62db65fa664871d2p+13L], [-real.max / 3, real.nan],
+ ];
+ testLog1p(vals);
+ }}
}
/***************************************
return z;
}
+@safe @nogc nothrow unittest
+{
+ import std.math : floatTraits, RealFormat;
+ import std.meta : AliasSeq;
+
+ static void testLog2(T)(T[2][] vals)
+ {
+ import std.math.operations : isClose;
+ import std.math.traits : isNaN;
+ foreach (ref pair; vals)
+ {
+ if (isNaN(pair[1]))
+ assert(isNaN(log2(pair[0])));
+ else
+ assert(isClose(log2(pair[0]), pair[1]));
+ }
+ }
+ static foreach (F; AliasSeq!(float, double, real))
+ {{
+ F[2][24] vals = [
+ [F(1), F(0x0p+0)], [F(2), F(0x1p+0)],
+ [F(4), F(0x1p+1)], [F(8), F(0x1.8p+1)],
+ [F(16), F(0x1p+2)], [F(32), F(0x1.4p+2)],
+ [F(64), F(0x1.8p+2)], [F(128), F(0x1.cp+2)],
+ [F(256), F(0x1p+3)], [F(512), F(0x1.2p+3)],
+ [F(1024), F(0x1.4p+3)], [F(2048), F(0x1.6p+3)],
+ [F(3), F(0x1.95c01a39fbd687ap+0)], [F(5), F(0x1.2934f0979a3715fcp+1)],
+ [F(7), F(0x1.675767f54042cd9ap+1)], [F(15), F(0x1.f414fdb4982259ccp+1)],
+ [F(17), F(0x1.0598fdbeb244c5ap+2)], [F(31), F(0x1.3d118d66c4d4e554p+2)],
+ [F(33), F(0x1.42d75a6eb1dfb0e6p+2)], [F(63), F(0x1.7e8bc1179e0caa9cp+2)],
+ [F(65), F(0x1.816e79685c2d2298p+2)], [F(-0), -F.infinity], [F(0), -F.infinity],
+ [F(10000), F(0x1.a934f0979a3715fcp+3)],
+ ];
+ testLog2(vals);
+ }}
+ {
+ float[2][16] vals = [
+ [float.nan, float.nan],[-float.nan, float.nan],
+ [float.infinity, float.infinity], [-float.infinity, float.nan],
+ [float.min_normal, -0x1.f8p+6f], [-float.min_normal, float.nan],
+ [float.max, 0x1p+7f], [-float.max, float.nan],
+ [float.min_normal / 2, -0x1.fcp+6f], [-float.min_normal / 2, float.nan],
+ [float.max / 2, 0x1.fcp+6f], [-float.max / 2, float.nan],
+ [float.min_normal / 3, -0x1.fe57p+6f], [-float.min_normal / 3, float.nan],
+ [float.max / 3, 0x1.f9a9p+6f], [-float.max / 3, float.nan],
+ ];
+ testLog2(vals);
+ }
+ {
+ double[2][16] vals = [
+ [double.nan, double.nan],[-double.nan, double.nan],
+ [double.infinity, double.infinity], [-double.infinity, double.nan],
+ [double.min_normal, -0x1.ffp+9], [-double.min_normal, double.nan],
+ [double.max, 0x1p+10], [-double.max, double.nan],
+ [double.min_normal / 2, -0x1.ff8p+9], [-double.min_normal / 2, double.nan],
+ [double.max / 2, 0x1.ff8p+9], [-double.max / 2, double.nan],
+ [double.min_normal / 3, -0x1.ffcae00d1cfdfp+9], [-double.min_normal / 3, double.nan],
+ [double.max / 3, 0x1.ff351ff2e3021p+9], [-double.max / 3, double.nan],
+ ];
+ testLog2(vals);
+ }
+ alias F = floatTraits!real;
+ static if (F.realFormat == RealFormat.ieeeExtended || F.realFormat == RealFormat.ieeeQuadruple)
+ {{
+ real[2][16] vals = [
+ [real.nan, real.nan],[-real.nan, real.nan],
+ [real.infinity, real.infinity], [-real.infinity, real.nan],
+ [real.min_normal, -0x1.fffp+13L], [-real.min_normal, real.nan],
+ [real.max, 0x1p+14L], [-real.max, real.nan],
+ [real.min_normal / 2, -0x1.fff8p+13L], [-real.min_normal / 2, real.nan],
+ [real.max / 2, 0x1.fff8p+13L], [-real.max / 2, real.nan],
+ [real.min_normal / 3, -0x1.fffcae00d1cfdeb4p+13L], [-real.min_normal / 3, real.nan],
+ [real.max / 3, 0x1.fff351ff2e30214cp+13L], [-real.max / 3, real.nan],
+ ];
+ testLog2(vals);
+ }}
+}
+
/*****************************************
* Extracts the exponent of x as a signed integral value.
*
return ilogb(x);
}
+@safe @nogc nothrow unittest
+{
+ import std.math : floatTraits, RealFormat;
+ import std.meta : AliasSeq;
+
+ static void testLogb(T)(T[2][] vals)
+ {
+ import std.math.operations : isClose;
+ import std.math.traits : isNaN;
+ foreach (ref pair; vals)
+ {
+ if (isNaN(pair[1]))
+ assert(isNaN(logb(pair[0])));
+ else
+ assert(isClose(logb(pair[0]), pair[1]));
+ }
+ }
+ static foreach (F; AliasSeq!(float, double, real))
+ {{
+ F[2][24] vals = [
+ [F(1), F(0x0p+0)], [F(2), F(0x1p+0)],
+ [F(4), F(0x1p+1)], [F(8), F(0x1.8p+1)],
+ [F(16), F(0x1p+2)], [F(32), F(0x1.4p+2)],
+ [F(64), F(0x1.8p+2)], [F(128), F(0x1.cp+2)],
+ [F(256), F(0x1p+3)], [F(512), F(0x1.2p+3)],
+ [F(1024), F(0x1.4p+3)], [F(2048), F(0x1.6p+3)],
+ [F(3), F(0x1p+0)], [F(5), F(0x1p+1)],
+ [F(7), F(0x1p+1)], [F(15), F(0x1.8p+1)],
+ [F(17), F(0x1p+2)], [F(31), F(0x1p+2)],
+ [F(33), F(0x1.4p+2)], [F(63), F(0x1.4p+2)],
+ [F(65), F(0x1.8p+2)], [F(-0), -F.infinity], [F(0), -F.infinity],
+ [F(10000), F(0x1.ap+3)],
+ ];
+ testLogb(vals);
+ }}
+ {
+ float[2][16] vals = [
+ [float.nan, float.nan],[-float.nan, float.nan],
+ [float.infinity, float.infinity], [-float.infinity, float.infinity],
+ [float.min_normal, -0x1.f8p+6f], [-float.min_normal, -0x1.f8p+6f],
+ [float.max, 0x1.fcp+6f], [-float.max, 0x1.fcp+6f],
+ [float.min_normal / 2, -0x1.fcp+6f], [-float.min_normal / 2, -0x1.fcp+6f],
+ [float.max / 2, 0x1.f8p+6f], [-float.max / 2, 0x1.f8p+6f],
+ [float.min_normal / 3, -0x1p+7f], [-float.min_normal / 3, -0x1p+7f],
+ [float.max / 3, 0x1.f8p+6f], [-float.max / 3, 0x1.f8p+6f],
+ ];
+ testLogb(vals);
+ }
+ {
+ double[2][16] vals = [
+ [double.nan, double.nan],[-double.nan, double.nan],
+ [double.infinity, double.infinity], [-double.infinity, double.infinity],
+ [double.min_normal, -0x1.ffp+9], [-double.min_normal, -0x1.ffp+9],
+ [double.max, 0x1.ff8p+9], [-double.max, 0x1.ff8p+9],
+ [double.min_normal / 2, -0x1.ff8p+9], [-double.min_normal / 2, -0x1.ff8p+9],
+ [double.max / 2, 0x1.ffp+9], [-double.max / 2, 0x1.ffp+9],
+ [double.min_normal / 3, -0x1p+10], [-double.min_normal / 3, -0x1p+10],
+ [double.max / 3, 0x1.ffp+9], [-double.max / 3, 0x1.ffp+9],
+ ];
+ testLogb(vals);
+ }
+ alias F = floatTraits!real;
+ static if (F.realFormat == RealFormat.ieeeExtended || F.realFormat == RealFormat.ieeeQuadruple)
+ {{
+ real[2][16] vals = [
+ [real.nan, real.nan],[-real.nan, real.nan],
+ [real.infinity, real.infinity], [-real.infinity, real.infinity],
+ [real.min_normal, -0x1.fffp+13L], [-real.min_normal, -0x1.fffp+13L],
+ [real.max, 0x1.fff8p+13L], [-real.max, 0x1.fff8p+13L],
+ [real.min_normal / 2, -0x1.fff8p+13L], [-real.min_normal / 2, -0x1.fff8p+13L],
+ [real.max / 2, 0x1.fffp+13L], [-real.max / 2, 0x1.fffp+13L],
+ [real.min_normal / 3, -0x1p+14L], [-real.min_normal / 3, -0x1p+14L],
+ [real.max / 3, 0x1.fffp+13L], [-real.max / 3, 0x1.fffp+13L],
+ ];
+ testLogb(vals);
+ }}
+}
+
/*************************************
* Efficiently calculates x * 2$(SUPERSCRIPT n).
*
*
* Example:
* ----
- * import std.net.curl, std.stdio;
+ * import std.net.curl, std.stdio, std.conv;
* auto client = HTTP("dlang.org");
* client.onReceive = (ubyte[] data)
* {
*
* Example:
* ----
- * import std.net.curl, std.stdio;
+ * import std.net.curl, std.stdio, std.conv;
* auto client = HTTP("dlang.org");
* client.onReceive = (ubyte[] data)
* {
*
* Example:
* ----
- * import std.net.curl, std.stdio;
+ * import std.net.curl, std.stdio, std.conv;
* auto http = HTTP("http://www.mydomain.com");
* http.onReceive = (ubyte[] data) { writeln(to!(const(char)[])(data)); return data.length; };
* http.postData = [1,2,3,4,5];
*
* Example:
* ----
- * import std.net.curl, std.stdio;
+ * import std.net.curl, std.stdio, std.conv;
* auto http = HTTP("http://www.mydomain.com");
* http.onReceive = (ubyte[] data) { writeln(to!(const(char)[])(data)); return data.length; };
* http.postData = "The quick....";
*
* Example:
* ----
- * import std.net.curl, std.stdio;
+ * import std.net.curl, std.stdio, std.conv;
* auto http = HTTP("dlang.org");
* http.onReceive = (ubyte[] data) { writeln(to!(const(char)[])(data)); return data.length; };
* http.onReceiveHeader = (in char[] key, in char[] value) { writeln(key, " = ", value); };
*
* Example:
* ----
- * import std.net.curl, std.stdio;
+ * import std.net.curl, std.stdio, std.conv;
* Curl curl;
* curl.initialize();
* curl.set(CurlOption.url, "http://dlang.org");
import std.exception : collectException;
import std.typecons : tuple;
- TestScript prog = ":Loop\ngoto Loop;";
+ TestScript prog = ":Loop\r\n" ~ "goto Loop";
auto pid = spawnProcess(prog.path);
// Doesn't block longer than one second
{
args : ["foo bar", "hello"],
windows : `"foo bar" hello`,
- posix : `'foo bar' 'hello'`
+ posix : `'foo bar' hello`
},
{
args : ["foo bar", "hello world"],
{
args : ["foo bar", "hello", "world"],
windows : `"foo bar" hello world`,
- posix : `'foo bar' 'hello' 'world'`
+ posix : `'foo bar' hello world`
},
{
args : ["foo bar", `'"^\`],
windows : `"foo bar" ^"'\^"^^\\^"`,
posix : `'foo bar' ''\''"^\'`
},
+ {
+ args : ["foo bar", ""],
+ windows : `"foo bar" ^"^"`,
+ posix : `'foo bar' ''`
+ },
+ {
+ args : ["foo bar", "2"],
+ windows : `"foo bar" ^"2^"`,
+ posix : `'foo bar' '2'`
+ },
];
foreach (test; tests)
+ {
+ auto actual = escapeShellCommand(test.args);
version (Windows)
- assert(escapeShellCommand(test.args) == test.windows);
+ string expected = test.windows;
else
- assert(escapeShellCommand(test.args) == test.posix );
+ string expected = test.posix;
+ assert(actual == expected, "\nExpected: " ~ expected ~ "\nGot: " ~ actual);
+ }
}
private string escapeShellCommandString(return scope string command) @safe pure
@safe nothrow
if (is(typeof(allocator(size_t.init)[0] = char.init)))
{
+ bool needQuoting = {
+ import std.ascii : isAlphaNum, isDigit;
+ import std.algorithm.comparison : among;
+
+ // Empty arguments need to be specified as ''
+ if (arg.length == 0)
+ return true;
+ // Arguments ending with digits need to be escaped,
+ // to disambiguate with 1>file redirection syntax
+ if (isDigit(arg[$-1]))
+ return true;
+
+ // Obtained using:
+ // for n in $(seq 1 255) ; do
+ // c=$(printf \\$(printf "%o" $n))
+ // q=$(/bin/printf '%q' "$c")
+ // if [[ "$q" == "$c" ]] ; then printf "%s, " "'$c'" ; fi
+ // done
+ // printf '\n'
+ foreach (char c; arg)
+ if (!isAlphaNum(c) && !c.among('%', '+', ',', '-', '.', '/', ':', '@', ']', '_'))
+ return true;
+ return false;
+ }();
+ if (!needQuoting)
+ {
+ auto buf = allocator(arg.length);
+ buf[] = arg;
+ return buf;
+ }
+
// '\'' means: close quoted part of argument, append an escaped
// single quote, and reopen quotes
// Then, test this module with:
// rdmd --main -unittest -version=unittest_burnin process.d
+ import std.file : readText, remove;
+ import std.format : format;
+ import std.path : absolutePath;
+ import std.random : uniform;
+
auto helper = absolutePath("std_process_unittest_helper");
assert(executeShell(helper ~ " hello").output.split("\0")[1..$] == ["hello"], "Helper malfunction");
*/
enum bool isInputRange(R) =
is(typeof(R.init) == R)
- && is(ReturnType!((R r) => r.empty) == bool)
+ && is(typeof((R r) { return r.empty; } (R.init)) == bool)
&& (is(typeof((return ref R r) => r.front)) || is(typeof(ref (return ref R r) => r.front)))
- && !is(ReturnType!((R r) => r.front) == void)
+ && !is(typeof((R r) { return r.front; } (R.init)) == void)
&& is(typeof((R r) => r.popFront));
///
The header of $(MREF std,range) for tutorials on ranges.
*/
enum bool isForwardRange(R) = isInputRange!R
- && is(ReturnType!((R r) => r.save) == R);
+ && is(typeof((R r) { return r.save; } (R.init)) == R);
///
@safe unittest
*/
enum bool isBidirectionalRange(R) = isForwardRange!R
&& is(typeof((R r) => r.popBack))
- && is(ReturnType!((R r) => r.back) == ElementType!R);
+ && is(typeof((R r) { return r.back; } (R.init)) == ElementType!R);
///
@safe unittest
----
isForwardRange!R
- && !isNarrowString!R
- && is(ReturnType!((R r) => r[1 .. 1].length) == size_t)
+ && !(isAutodecodableString!R && !isAggregateType!R)
+ && is(typeof((R r) { return r[1 .. 1].length; } (R.init)) == size_t)
&& (is(typeof(lvalueOf!R[1 .. 1]) == R) || isInfinite!R)
&& (!is(typeof(lvalueOf!R[0 .. $])) || is(typeof(lvalueOf!R[0 .. $]) == R))
&& (!is(typeof(lvalueOf!R[0 .. $])) || isInfinite!R
*/
enum bool hasSlicing(R) = isForwardRange!R
&& !(isAutodecodableString!R && !isAggregateType!R)
- && is(ReturnType!((R r) => r[1 .. 1].length) == size_t)
+ && is(typeof((R r) { return r[1 .. 1].length; } (R.init)) == size_t)
&& (is(typeof(lvalueOf!R[1 .. 1]) == R) || isInfinite!R)
&& (!is(typeof(lvalueOf!R[0 .. $])) || is(typeof(lvalueOf!R[0 .. $]) == R))
&& (!is(typeof(lvalueOf!R[0 .. $])) || isInfinite!R
//
@trusted void error(string msg)
{
- import std.array : appender;
- import std.format.write : formattedWrite;
- auto app = appender!string();
- formattedWrite(app, "%s\nPattern with error: `%s` <--HERE-- `%s`",
- msg, origin[0..$-pat.length], pat);
- throw new RegexException(app.data);
+ import std.conv : text;
+ string app = msg;
+ app ~= "\nPattern with error: `";
+ app ~= origin[0..$-pat.length].text;
+ app ~= "` <--HERE-- `";
+ app ~= pat.text;
+ app ~= "`";
+ throw new RegexException(app);
}
alias Char = BasicElementOf!R;
{
string getHostNameFromInt = ih.name.dup;
- assert(ih.getHostByAddr(ia.toAddrString()));
- string getHostNameFromStr = ih.name.dup;
+ // This randomly fails in the compiler test suite
+ //assert(ih.getHostByAddr(ia.toAddrString()));
- assert(getHostNameFromInt == getHostNameFromStr);
+ if (ih.getHostByAddr(ia.toAddrString()))
+ {
+ string getHostNameFromStr = ih.name.dup;
+ assert(getHostNameFromInt == getHostNameFromStr);
+ }
}
}
}
/**
-Calls $(HTTP cplusplus.com/reference/clibrary/cstdio/ftell.html, ftell) for the
-managed file handle.
+Calls $(HTTP cplusplus.com/reference/cstdio/ftell.html, ftell)
+for the managed file handle, which returns the current value of
+the position indicator of the file handle.
Throws: `Exception` if the file is not opened.
`ErrnoException` if the call to `ftell` fails.
* $(TR $(TH Category) $(TH Templates))
* $(TR $(TD Symbol Name traits) $(TD
* $(LREF fullyQualifiedName)
+ * $(LREF mangledName)
* $(LREF moduleName)
* $(LREF packageName)
* ))
* $(LREF isCovariantWith)
* $(LREF isImplicitlyConvertible)
* ))
- * $(TR $(TD SomethingTypeOf) $(TD
- * $(LREF rvalueOf)
- * $(LREF lvalueOf)
+ * $(TR $(TD Type Constructors) $(TD
* $(LREF InoutOf)
* $(LREF ConstOf)
* $(LREF SharedOf)
* $(LREF Promoted)
* ))
* $(TR $(TD Misc) $(TD
- * $(LREF mangledName)
+ * $(LREF lvalueOf)
+ * $(LREF rvalueOf)
* $(LREF Select)
* $(LREF select)
* ))
);
}
}
- else static if (is(T : U*, U))
+ else static if (is(T == U*, U))
{
enum fqnType = chain!(
fqnType!(U, qualifiers) ~ "*"
* or a class with an `opCall`. Please note that $(D_KEYWORD ref)
* is not part of a type, but the attribute of the function
* (see template $(LREF functionAttributes)).
+ *
+ * $(NOTE To reduce template instantiations, consider instead using
+ * $(D typeof(() { return func(args); } ())) if the argument types are known or
+ * $(D static if (is(typeof(func) Ret == return))) if only that basic test is needed.)
*/
template ReturnType(alias func)
if (isCallable!func)
int test(int);
int test() @property;
}
- alias ov = __traits(getVirtualFunctions, Overloads, "test");
+ alias ov = __traits(getVirtualMethods, Overloads, "test");
alias F_ov0 = FunctionTypeOf!(ov[0]);
alias F_ov1 = FunctionTypeOf!(ov[1]);
alias F_ov2 = FunctionTypeOf!(ov[2]);
{
static if (__traits(hasMember, T, member))
{
- static if (is(T : V*, V))
+ static if (is(T == V*, V))
alias U = V;
else
alias U = T;
static if (__traits(hasMember, Node, name) && __traits(compiles, __traits(getMember, Node, name)))
{
// Get all overloads in sight (not hidden).
- alias inSight = __traits(getVirtualFunctions, Node, name);
+ alias inSight = __traits(getVirtualMethods, Node, name);
// And collect all overloads in ancestor classes to reveal hidden
// methods. The result may contain duplicates.
static assert(!isAssignable!S5);
// `-preview=in` is enabled
- static if (!is(typeof(mixin(q{(in ref int a) => a}))))
+ alias DScannerBug895 = int[256];
+ static if (((in DScannerBug895 a) { return __traits(isRef, a); })(DScannerBug895.init))
{
struct S6 { void opAssign(in S5); }
static assert(is(Q!T[] == StringTypeOf!( SubTypeOf!(Q!T[]) )));
alias Str = Q!T[];
- class C(S) { S val; alias val this; }
+ struct C(S) { S val; alias val this; }
static assert(is(StringTypeOf!(C!Str) == Str));
}}
}
Returns:
A `bool`
*/
-template isSomeFunction(alias T)
-{
- static if (is(typeof(& T) U : U*) && is(U == function) || is(typeof(& T) U == delegate))
- {
- // T is a (nested) function symbol.
- enum bool isSomeFunction = true;
- }
- else static if (is(T W) || is(typeof(T) W))
- {
- // T is an expression or a type. Take the type of it and examine.
- static if (is(W F : F*) && is(F == function))
- enum bool isSomeFunction = true; // function pointer
- else
- enum bool isSomeFunction = is(W == function) || is(W == delegate);
- }
- else
- enum bool isSomeFunction = false;
-}
+enum bool isSomeFunction(alias T) =
+ is(T == return) ||
+ is(typeof(T) == return) ||
+ is(typeof(&T) == return); // @property
///
@safe unittest
auto c = new C;
auto fp = &func;
auto dg = &c.method;
- real val;
static assert( isSomeFunction!func);
static assert( isSomeFunction!prop);
static assert( isSomeFunction!(C.method));
static assert( isSomeFunction!(C.prop));
static assert( isSomeFunction!(c.prop));
- static assert( isSomeFunction!(c.prop));
static assert( isSomeFunction!fp);
static assert( isSomeFunction!dg);
+ real val;
static assert(!isSomeFunction!int);
static assert(!isSomeFunction!val);
}
*/
template ForeachType(T)
{
- alias ForeachType = ReturnType!(typeof(
+ alias ForeachType = typeof(
(inout int x = 0)
{
foreach (elem; T.init)
return elem;
}
assert(0);
- }));
+ }());
}
///
return this;
}
- /// ditto
- inout(typeof(this)) opIndex() inout
- {
- return this;
- }
-
/// ditto
inout(typeof(this)) opIndex(size_t[2] dim) inout
in (dim[0] <= length && dim[1] <= length && dim[1] >= dim[0])
{
return get();
}
+
+ /**
+ * Converts `Nullable` to a range. Works even when the contained type is `immutable`.
+ */
+ auto opSlice(this This)()
+ {
+ static struct NullableRange
+ {
+ private This value;
+
+ // starts out true if value is null
+ private bool empty_;
+
+ @property bool empty() const @safe pure nothrow
+ {
+ return empty_;
+ }
+
+ void popFront() @safe pure nothrow
+ {
+ empty_ = true;
+ }
+
+ alias popBack = popFront;
+
+ @property ref inout(typeof(value.get())) front() inout @safe pure nothrow
+ {
+ return value.get();
+ }
+
+ alias back = front;
+
+ @property inout(typeof(this)) save() inout
+ {
+ return this;
+ }
+
+ size_t[2] opSlice(size_t dim : 0)(size_t from, size_t to) const
+ {
+ return [from, to];
+ }
+
+ @property size_t length() const @safe pure nothrow
+ {
+ return !empty;
+ }
+
+ alias opDollar(size_t dim : 0) = length;
+
+ ref inout(typeof(value.get())) opIndex(size_t index) inout @safe pure nothrow
+ in (index < length)
+ {
+ return value.get();
+ }
+
+ inout(typeof(this)) opIndex(size_t[2] dim) inout
+ in (dim[0] <= length && dim[1] <= length && dim[1] >= dim[0])
+ {
+ return (dim[0] == 0 && dim[1] == 1) ? this : this.init;
+ }
+
+ auto opIndex() inout
+ {
+ return this;
+ }
+ }
+ return NullableRange(this, isNull);
+ }
}
/// ditto
assert(hasLvalueElements!(Nullable!int));
}
+// https://issues.dlang.org/show_bug.cgi?id=23640
+@safe pure nothrow unittest
+{
+ import std.algorithm.comparison : equal;
+ import std.range : only;
+ import std.range.primitives : hasLength, hasSlicing,
+ isRandomAccessRange;
+ static immutable struct S { int[] array; }
+ auto value = S([42]);
+ alias ImmutableNullable = immutable Nullable!S;
+ auto a = ImmutableNullable(value)[];
+ alias Range = typeof(a);
+ assert(isRandomAccessRange!Range);
+ assert(hasLength!Range);
+ assert(hasSlicing!Range);
+ assert(!a.empty);
+ assert(a.front == value);
+ assert(a.back == value);
+ assert(a[0] == value);
+ assert(a.equal(only(value)));
+ assert(a[0 .. $].equal(only(value)));
+ Range b = a.save();
+ assert(!b.empty);
+ b.popFront();
+ assert(!a.empty);
+ assert(b.empty);
+}
+
/**
Just like `Nullable!T`, except that the null state is defined as a
particular value. For example, $(D Nullable!(uint, uint.max)) is an
isSomeString, Unqual, isDynamicArray;
// debug = std_uni;
+import std.internal.unicode_tables; // generated file
+
debug(std_uni) import std.stdio; // writefln, writeln
private:
enum EMPTY_CASE_TRIE = ushort.max;// from what gen_uni uses internally
-// control - '\r'
-enum controlSwitch = `
- case '\u0000':..case '\u0008':case '\u000E':..case '\u001F':case '\u007F':..
- case '\u0084':case '\u0086':..case '\u009F': case '\u0009':..case '\u000C': case '\u0085':
-`;
// TODO: redo the most of hangul stuff algorithmically in case of Graphemes too
-// kill unrolled switches
+// Use combined trie instead of checking for '\r' | '\n' | ccTrie,
+// or extend | '\u200D' separately
private static bool isRegionalIndicator(dchar ch) @safe pure @nogc nothrow
{
return ch >= '\U0001F1E6' && ch <= '\U0001F1FF';
}
+// Our grapheme decoder is a state machine, this is list of all possible
+// states before each code point.
+private enum GraphemeState
+{
+ Start,
+ CR,
+ RI,
+ L,
+ V,
+ LVT,
+ Emoji,
+ EmojiZWJ,
+ Prepend,
+ End
+}
+
+// Message values whether end of grapheme is reached
+private enum TransformRes
+{
+ // No, unless the source range ends here
+ // (GB2 - break at end of text, unless text is empty)
+ goOn,
+ redo, // Run last character again with new state
+ retInclude, // Yes, after the just iterated character
+ retExclude // Yes, before the just iterated character
+}
+
+// The logic of the grapheme decoding is all here
+// GB# means Grapheme Breaking rule number # - see Unicode standard annex #29
+// Note, getting GB1 (break at start of text, unless text is empty) right
+// relies on the user starting grapheme walking from beginning of the text, and
+// not attempting to walk an empty text.
+private enum TransformRes
+ function(ref GraphemeState, dchar) @safe pure nothrow @nogc [] graphemeTransforms =
+[
+ GraphemeState.Start: (ref state, ch)
+ {
+ // GB4. Break after controls.
+ if (graphemeControlTrie[ch] || ch == '\n')
+ return TransformRes.retInclude;
+
+ with (GraphemeState) state =
+ ch == '\r' ? CR :
+ isRegionalIndicator(ch) ? RI :
+ isHangL(ch) ? L :
+ hangLV[ch] || isHangV(ch) ? V :
+ hangLVT[ch] || isHangT(ch) ? LVT :
+ prependTrie[ch] ? Prepend :
+ xpictoTrie[ch] ? Emoji :
+ End;
+
+ // No matter what we encountered, we always include the
+ // first code point in the grapheme.
+ return TransformRes.goOn;
+ },
+
+ // GB3, GB4. Do not break between a CR and LF.
+ // Otherwise, break after controls.
+ GraphemeState.CR: (ref state, ch) => ch == '\n' ?
+ TransformRes.retInclude :
+ TransformRes.retExclude,
+
+ // GB12 - GB13. Do not break within emoji flag sequences.
+ // That is, do not break between regional indicator (RI) symbols if
+ // there is an odd number of RI characters before the break point.
+ // This state applies if one and only one RI code point has been
+ // encountered.
+ GraphemeState.RI: (ref state, ch)
+ {
+ state = GraphemeState.End;
+
+ return isRegionalIndicator(ch) ?
+ TransformRes.goOn :
+ TransformRes.redo;
+ },
+
+ // GB6. Do not break Hangul syllable sequences.
+ GraphemeState.L: (ref state, ch)
+ {
+ if (isHangL(ch))
+ return TransformRes.goOn;
+ else if (isHangV(ch) || hangLV[ch])
+ {
+ state = GraphemeState.V;
+ return TransformRes.goOn;
+ }
+ else if (hangLVT[ch])
+ {
+ state = GraphemeState.LVT;
+ return TransformRes.goOn;
+ }
+
+ state = GraphemeState.End;
+ return TransformRes.redo;
+ },
+
+ // GB7. Do not break Hangul syllable sequences.
+ GraphemeState.V: (ref state, ch)
+ {
+ if (isHangV(ch))
+ return TransformRes.goOn;
+ else if (isHangT(ch))
+ {
+ state = GraphemeState.LVT;
+ return TransformRes.goOn;
+ }
+
+ state = GraphemeState.End;
+ return TransformRes.redo;
+ },
+
+ // GB8. Do not break Hangul syllable sequences.
+ GraphemeState.LVT: (ref state, ch)
+ {
+ if (isHangT(ch))
+ return TransformRes.goOn;
+
+ state = GraphemeState.End;
+ return TransformRes.redo;
+ },
+
+ // GB11. Do not break within emoji modifier sequences or emoji
+ // zwj sequences. This state applies when the last code point was
+ // NOT a ZWJ.
+ GraphemeState.Emoji: (ref state, ch)
+ {
+ if (graphemeExtendTrie[ch])
+ return TransformRes.goOn;
+
+ static assert(!graphemeExtendTrie['\u200D']);
+
+ if (ch == '\u200D')
+ {
+ state = GraphemeState.EmojiZWJ;
+ return TransformRes.goOn;
+ }
+
+ state = GraphemeState.End;
+ // There might still be spacing marks are
+ // at the end, which are not allowed in
+ // middle of emoji sequences
+ return TransformRes.redo;
+ },
+
+ // GB11. Do not break within emoji modifier sequences or emoji
+ // zwj sequences. This state applies when the last code point was
+ // a ZWJ.
+ GraphemeState.EmojiZWJ: (ref state, ch)
+ {
+ state = GraphemeState.Emoji;
+ if (xpictoTrie[ch])
+ return TransformRes.goOn;
+ return TransformRes.redo;
+ },
+
+ // GB9b. Do not break after Prepend characters.
+ GraphemeState.Prepend: (ref state, ch)
+ {
+ // GB5. Break before controls.
+ if (graphemeControlTrie[ch] || ch == '\r' || ch == '\n')
+ return TransformRes.retExclude;
+
+ state = GraphemeState.Start;
+ return TransformRes.redo;
+ },
+
+ // GB9, GB9a. Do not break before extending characters, ZWJ
+ // or SpacingMarks.
+ // GB999. Otherwise, break everywhere.
+ GraphemeState.End: (ref state, ch)
+ => !graphemeExtendTrie[ch] && !spacingMarkTrie[ch] && ch != '\u200D' ?
+ TransformRes.retExclude :
+ TransformRes.goOn
+];
+
template genericDecodeGrapheme(bool getValue)
{
- alias graphemeExtend = graphemeExtendTrie;
- alias spacingMark = mcTrie;
static if (getValue)
alias Value = Grapheme;
else
Value genericDecodeGrapheme(Input)(ref Input range)
{
- import std.internal.unicode_tables : isHangL, isHangT, isHangV; // generated file
- enum GraphemeState {
- Start,
- CR,
- RI,
- L,
- V,
- LVT
- }
static if (getValue)
Grapheme grapheme;
auto state = GraphemeState.Start;
- enum eat = q{
- static if (getValue)
- grapheme ~= ch;
- range.popFront();
- };
-
dchar ch;
+
assert(!range.empty, "Attempting to decode grapheme from an empty " ~ Input.stringof);
+ outer:
while (!range.empty)
{
ch = range.front;
- final switch (state) with(GraphemeState)
+
+ rerun:
+ final switch (graphemeTransforms[state](state, ch))
+ with(TransformRes)
{
- case Start:
- mixin(eat);
- if (ch == '\r')
- state = CR;
- else if (isRegionalIndicator(ch))
- state = RI;
- else if (isHangL(ch))
- state = L;
- else if (hangLV[ch] || isHangV(ch))
- state = V;
- else if (hangLVT[ch])
- state = LVT;
- else if (isHangT(ch))
- state = LVT;
- else
- {
- switch (ch)
- {
- mixin(controlSwitch);
- goto L_End;
- default:
- goto L_End_Extend;
- }
- }
- break;
- case CR:
- if (ch == '\n')
- mixin(eat);
- goto L_End_Extend;
- case RI:
- if (isRegionalIndicator(ch))
- mixin(eat);
- goto L_End_Extend;
- case L:
- if (isHangL(ch))
- mixin(eat);
- else if (isHangV(ch) || hangLV[ch])
- {
- state = V;
- mixin(eat);
- }
- else if (hangLVT[ch])
- {
- state = LVT;
- mixin(eat);
- }
- else
- goto L_End_Extend;
- break;
- case V:
- if (isHangV(ch))
- mixin(eat);
- else if (isHangT(ch))
- {
- state = LVT;
- mixin(eat);
- }
- else
- goto L_End_Extend;
- break;
- case LVT:
- if (isHangT(ch))
- {
- mixin(eat);
- }
- else
- goto L_End_Extend;
- break;
+ case goOn:
+ static if (getValue)
+ grapheme ~= ch;
+ range.popFront();
+ continue;
+
+ case redo:
+ goto rerun;
+
+ case retInclude:
+ static if (getValue)
+ grapheme ~= ch;
+ range.popFront();
+ break outer;
+
+ case retExclude:
+ break outer;
}
}
- L_End_Extend:
- while (!range.empty)
- {
- ch = range.front;
- // extend & spacing marks
- if (!graphemeExtend[ch] && !spacingMark[ch])
- break;
- mixin(eat);
- }
- L_End:
+
static if (getValue)
return grapheme;
}
-
}
public: // Public API continues
static assert(c2 == 3); // \u0301 has 2 UTF-8 code units
}
+// TODO: make this @nogc. Probably no big deal since the state machine is
+// already GC-free.
+@safe pure nothrow unittest
+{
+ // grinning face ~ emoji modifier fitzpatrick type-5 ~ grinning face
+ assert(graphemeStride("\U0001F600\U0001f3FE\U0001F600"d, 0) == 2);
+ // skier ~ female sign ~ '€'
+ assert(graphemeStride("\u26F7\u2640€"d, 0) == 1);
+ // skier ~ emoji modifier fitzpatrick type-5 ~ female sign ~ '€'
+ assert(graphemeStride("\u26F7\U0001f3FE\u2640€"d, 0) == 2);
+ // skier ~ zero-width joiner ~ female sign ~ '€'
+ assert(graphemeStride("\u26F7\u200D\u2640€"d, 0) == 3);
+ // skier ~ emoji modifier fitzpatrick type-5 ~ zero-width joiner
+ // ~ female sign ~ '€'
+ assert(graphemeStride("\u26F7\U0001f3FE\u200D\u2640€"d, 0) == 4);
+ // skier ~ zero-width joiner ~ '€'
+ assert(graphemeStride("\u26F7\u200D€"d, 0) == 2);
+ //'€' ~ zero-width joiner ~ skier
+ assert(graphemeStride("€\u200D\u26F7"d, 0) == 2);
+ // Kaithi number sign ~ Devanagari digit four ~ Devanagari digit two
+ assert(graphemeStride("\U000110BD\u096A\u0968"d, 0) == 2);
+ // Kaithi number sign ~ null
+ assert(graphemeStride("\U000110BD\0"d, 0) == 1);
+}
+
/++
Reads one full grapheme cluster from an
$(REF_ALTTEXT input range, isInputRange, std,range,primitives) of dchar `inp`.
assert(nonForwardRange.walkLength == 4);
}
+// Issue 23474
+@safe pure unittest
+{
+ import std.range.primitives : walkLength;
+ assert(byGrapheme("\r\u0308").walkLength == 2);
+}
+
/++
$(P Lazily transform a range of $(LREF Grapheme)s to a range of code points.)
@safe pure nothrow @nogc @property
{
- import std.internal.unicode_tables; // generated file
-
// It's important to use auto return here, so that the compiler
// only runs semantic on the return type if the function gets
// used. Also these are functions rather than templates to not
}
//grapheme breaking algorithm tables
- auto mcTrie()
+ auto spacingMarkTrie()
{
- import std.internal.unicode_grapheme : mcTrieEntries;
- static immutable res = asTrie(mcTrieEntries);
+ import std.internal.unicode_grapheme : spacingMarkTrieEntries;
+ static immutable res = asTrie(spacingMarkTrieEntries);
return res;
}
return res;
}
+ auto prependTrie()
+ {
+ import std.internal.unicode_grapheme : prependTrieEntries;
+ static immutable res = asTrie(prependTrieEntries);
+ return res;
+ }
+
+ auto graphemeControlTrie()
+ {
+ import std.internal.unicode_grapheme : controlTrieEntries;
+ static immutable res = asTrie(controlTrieEntries);
+ return res;
+ }
+
+ auto xpictoTrie()
+ {
+ import std.internal.unicode_grapheme : Extended_PictographicTrieEntries;
+ static immutable res = asTrie(Extended_PictographicTrieEntries);
+ return res;
+ }
+
// tables below are used for composition/decomposition
auto combiningClassTrie()
{
collection cycle and cause a nasty bug when the C code tries to use it.
+/
template toUTFz(P)
-if (is(P : C*, C) && isSomeChar!C)
+if (is(P == C*, C) && isSomeChar!C)
{
P toUTFz(S)(S str) @safe pure
if (isSomeString!S)
extern(C++) static class C0
{
int foo() { return 0; } // Need at least one function in vtable.
- S0 a; alias a this;
+ S0 a; alias a this; // { dg-warning "is deprecated" }
}
extern(C++) static class C1
{
S1 a;
inout(S1)* b() inout nothrow { return &a; }
- alias b this;
+ alias b this; // { dg-warning "is deprecated" }
}
cast(void) hashOf(S0.init);
void runTest()
{
Object obj;
- obj = Object.factory("lib.MyFinalizer"); // { dg-warning "is deprecated" }
+ obj = Object.factory("lib.MyFinalizer");
assert(obj.toString() == "lib.MyFinalizer");
- obj = Object.factory("lib.MyFinalizerBig"); // { dg-warning "is deprecated" }
+ obj = Object.factory("lib.MyFinalizerBig");
assert(obj.toString() == "lib.MyFinalizerBig");
}