d: Merge upstream dmd, druntime 4ca4140e58, phobos 454dff14d.
D front-end changes: - Import dmd v2.103.0-beta.1. - Using `alias this' for classes has been deprecated. - The feature `-fpreview=dip25` is now enabled by default. - The compile-time traits `isVirtualFunction' and `getVirtualFunctions' have been deprecated. D runtime changes: - Import druntime v2.103.0-beta.1. Phobos changes: - Import phobos v2.103.0-beta.1. - Updated unicode grapheme walking updated to conform to Unicode version 15. - Improved friendliness of error messages when instantiating `std.algorithm.iteration.joiner' and `std.algorithm.sorting.sort' with wrong inputs. gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd 4ca4140e58. * dmd/VERSION: Bump version to v2.103.0-beta.1. * Make-lang.in (D_FRONTEND_OBJS): Add d/errorsink.o. * d-ctfloat.cc (CTFloat::sprint): Update signature for new front-end interface. * d-frontend.cc (getTypeInfoType): Likewise. * d-lang.cc (d_handle_option): Remove handling of -fpreview=dip25 and -frevert=dip25. (d_post_options): Remove enabling of sealed references language feature when scoped pointers is enabled. * d-tree.h (create_typeinfo): Update signature. * decl.cc (DeclVisitor::finish_vtable): Update for new front-end interface. (DeclVisitor::visit (VarDeclaration *)): Likewise. (DeclVisitor::visit (FuncDeclaration *)): Check skipCodegen to see if front-end explicitly requested not to generate code. * expr.cc (ExprVisitor::visit (NewExp *)): Update for new front-end interface. * lang.opt (fpreview=dip25): Remove. (frevert=dip25): Remove. * modules.cc (layout_moduleinfo_fields): Update for new front-end interface. (layout_moduleinfo): Likewise. * runtime.def (NEWCLASS): Remove. * toir.cc (IRVisitor::visit (IfStatement *)): Don't generate IR for if statement list when condition is `__ctfe'. * typeinfo.cc (create_typeinfo): Add generate parameter. * types.cc (layout_aggregate_members): Update for new front-end interface. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime 4ca4140e58. * libdruntime/Makefile.am (DRUNTIME_DSOURCES): Add core/factory.d. * libdruntime/Makefile.in: Regenerate. * src/MERGE: Merge upstream phobos 454dff14d. * testsuite/libphobos.hash/test_hash.d: Update test. * testsuite/libphobos.shared/finalize.d: Update test. * libdruntime/core/factory.d: New file. gcc/testsuite/ChangeLog: * gdc.dg/torture/simd23084.d: New test. * gdc.dg/torture/simd23085.d: New test. * gdc.dg/torture/simd23218.d: New test.
This commit is contained in:
@@ -124,6 +124,7 @@ D_FRONTEND_OBJS = \
|
||||
d/dversion.o \
|
||||
d/entity.o \
|
||||
d/errors.o \
|
||||
d/errorsink.o \
|
||||
d/escape.o \
|
||||
d/expression.o \
|
||||
d/expressionsem.o \
|
||||
|
||||
+4
-4
@@ -96,16 +96,16 @@ CTFloat::parse (const char *buffer, bool &overflow)
|
||||
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)
|
||||
|
||||
+2
-2
@@ -79,11 +79,11 @@ eval_builtin (const Loc &loc, FuncDeclaration *fd, Expressions *arguments)
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -558,7 +558,6 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
|
||||
|
||||
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;
|
||||
@@ -590,10 +589,6 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT 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;
|
||||
@@ -636,7 +631,6 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
|
||||
|
||||
case OPT_frevert_all:
|
||||
global.params.useDIP1000 = FeatureState::disabled;
|
||||
global.params.useDIP25 = FeatureState::disabled;
|
||||
global.params.dtorFields = FeatureState::disabled;
|
||||
global.params.fix16997 = !value;
|
||||
break;
|
||||
@@ -645,10 +639,6 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
|
||||
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;
|
||||
@@ -911,10 +901,6 @@ d_post_options (const char ** fn)
|
||||
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);
|
||||
|
||||
|
||||
+1
-1
@@ -689,7 +689,7 @@ extern tree get_classinfo_decl (ClassDeclaration *);
|
||||
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 *);
|
||||
|
||||
+8
-4
@@ -563,8 +563,8 @@ public:
|
||||
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 ());
|
||||
@@ -772,7 +772,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
if (d->aliassym)
|
||||
if (d->aliasTuple)
|
||||
{
|
||||
this->build_dsymbol (d->toAlias ());
|
||||
return;
|
||||
@@ -821,7 +821,7 @@ public:
|
||||
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 ())
|
||||
@@ -903,6 +903,10 @@ public:
|
||||
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;
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
09faa4eacd4fb147107e94eeebf56b3a73fdcc05
|
||||
4ca4140e584c055a8a9bc727e56a97ebcecd61e0
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the dlang/dmd repository.
|
||||
|
||||
+2
-1
@@ -38,7 +38,8 @@ Note that these groups have no strict meaning, the category assignments are a bi
|
||||
| [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 |
|
||||
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
v2.102.0-beta.1
|
||||
v2.103.0-beta.1
|
||||
|
||||
@@ -304,7 +304,6 @@ public:
|
||||
virtual int vtblOffset() const;
|
||||
const char *kind() const override;
|
||||
|
||||
void addLocalClass(ClassDeclarations *) override final;
|
||||
void addObjcSymbols(ClassDeclarations *classes, ClassDeclarations *categories) override final;
|
||||
|
||||
// Back end
|
||||
|
||||
+1
-1
@@ -75,7 +75,7 @@ private extern (C++) final class PostorderExpressionVisitor : StoppableVisitor
|
||||
public:
|
||||
StoppableVisitor v;
|
||||
|
||||
extern (D) this(StoppableVisitor v)
|
||||
extern (D) this(StoppableVisitor v) scope
|
||||
{
|
||||
this.v = v;
|
||||
}
|
||||
|
||||
+2
-2
@@ -149,7 +149,7 @@ Expression arrayOp(BinExp e, Scope* sc)
|
||||
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);
|
||||
@@ -194,7 +194,7 @@ private Expressions* buildArrayOp(Scope* sc, Expression e, Objects* tiargs)
|
||||
Expressions* args;
|
||||
|
||||
public:
|
||||
extern (D) this(Scope* sc, Objects* tiargs)
|
||||
extern (D) this(Scope* sc, Objects* tiargs) scope
|
||||
{
|
||||
this.sc = sc;
|
||||
this.tiargs = tiargs;
|
||||
|
||||
+6
-6
@@ -197,17 +197,12 @@ extern (C++) abstract class AttribDeclaration : Dsymbol
|
||||
|
||||
/****************************************
|
||||
*/
|
||||
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;
|
||||
}
|
||||
@@ -1080,6 +1075,11 @@ extern (C++) final class StaticIfDeclaration : ConditionalDeclaration
|
||||
return "static if";
|
||||
}
|
||||
|
||||
override inout(StaticIfDeclaration) isStaticIfDeclaration() inout pure @safe
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
override void accept(Visitor v)
|
||||
{
|
||||
v.visit(this);
|
||||
|
||||
+2
-2
@@ -36,8 +36,7 @@ public:
|
||||
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); }
|
||||
};
|
||||
@@ -184,6 +183,7 @@ public:
|
||||
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); }
|
||||
};
|
||||
|
||||
@@ -71,7 +71,7 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
|
||||
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;
|
||||
|
||||
@@ -63,7 +63,7 @@ extern (C++) /* CT */ BE canThrow(Expression e, FuncDeclaration func, bool mustN
|
||||
CT result;
|
||||
|
||||
public:
|
||||
extern (D) this(FuncDeclaration func, bool mustNotThrow)
|
||||
extern (D) this(FuncDeclaration func, bool mustNotThrow) scope
|
||||
{
|
||||
this.func = func;
|
||||
this.mustNotThrow = mustNotThrow;
|
||||
|
||||
+7
-6
@@ -113,11 +113,11 @@ FuncDeclaration hasIdentityOpAssign(AggregateDeclaration ad, Scope* sc)
|
||||
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();
|
||||
@@ -478,7 +478,7 @@ private FuncDeclaration hasIdentityOpEquals(AggregateDeclaration ad, Scope* sc)
|
||||
{
|
||||
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);
|
||||
@@ -1065,7 +1065,7 @@ private DtorDeclaration buildWindowsCppDtor(AggregateDeclaration ad, DtorDeclara
|
||||
{
|
||||
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)
|
||||
@@ -1077,8 +1077,9 @@ private DtorDeclaration buildWindowsCppDtor(AggregateDeclaration ad, DtorDeclara
|
||||
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.
|
||||
|
||||
@@ -338,9 +338,12 @@ struct OutBuffer
|
||||
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
|
||||
@@ -919,3 +922,18 @@ unittest
|
||||
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");
|
||||
}
|
||||
|
||||
+2
-14
@@ -845,20 +845,8 @@ UnionExp Identity(EXP op, const ref Loc loc, Type type, Expression e1, Expressio
|
||||
}
|
||||
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);
|
||||
|
||||
+76
-33
@@ -16,6 +16,7 @@ module dmd.cparse;
|
||||
import core.stdc.stdio;
|
||||
import core.stdc.string;
|
||||
import dmd.astenums;
|
||||
import dmd.errorsink;
|
||||
import dmd.globals;
|
||||
import dmd.id;
|
||||
import dmd.identifier;
|
||||
@@ -69,9 +70,10 @@ final class CParser(AST) : Parser!AST
|
||||
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;
|
||||
@@ -268,11 +270,12 @@ final class CParser(AST) : Parser!AST
|
||||
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
|
||||
@@ -286,6 +289,7 @@ final class CParser(AST) : Parser!AST
|
||||
case TOK.int16:
|
||||
case TOK.int32:
|
||||
case TOK.int64:
|
||||
case TOK.__int128:
|
||||
case TOK.float32:
|
||||
case TOK.float64:
|
||||
case TOK.signed:
|
||||
@@ -752,7 +756,7 @@ final class CParser(AST) : Parser!AST
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -781,6 +785,14 @@ final class CParser(AST) : Parser!AST
|
||||
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
|
||||
@@ -1640,6 +1652,23 @@ final class CParser(AST) : Parser!AST
|
||||
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)
|
||||
@@ -1664,22 +1693,12 @@ final class CParser(AST) : Parser!AST
|
||||
!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;
|
||||
}
|
||||
@@ -1823,17 +1842,10 @@ final class CParser(AST) : Parser!AST
|
||||
{
|
||||
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;
|
||||
@@ -1847,6 +1859,15 @@ final class CParser(AST) : Parser!AST
|
||||
}
|
||||
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
|
||||
|
||||
@@ -1929,7 +1950,7 @@ final class CParser(AST) : Parser!AST
|
||||
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;
|
||||
@@ -1995,7 +2016,7 @@ final class CParser(AST) : Parser!AST
|
||||
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[]
|
||||
*/
|
||||
@@ -2183,6 +2204,7 @@ final class CParser(AST) : Parser!AST
|
||||
ximaginary = 0x8000,
|
||||
xcomplex = 0x10000,
|
||||
x_Atomic = 0x20000,
|
||||
xint128 = 0x40000,
|
||||
}
|
||||
|
||||
AST.Type t;
|
||||
@@ -2227,6 +2249,7 @@ final class CParser(AST) : Parser!AST
|
||||
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;
|
||||
@@ -2505,6 +2528,11 @@ final class CParser(AST) : Parser!AST
|
||||
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;
|
||||
|
||||
@@ -2991,11 +3019,11 @@ final class CParser(AST) : Parser!AST
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -3270,6 +3298,7 @@ final class CParser(AST) : Parser!AST
|
||||
case TOK._Complex:
|
||||
case TOK._Thread_local:
|
||||
case TOK.int32:
|
||||
case TOK.__int128:
|
||||
case TOK.char_:
|
||||
case TOK.float32:
|
||||
case TOK.float64:
|
||||
@@ -3940,6 +3969,7 @@ final class CParser(AST) : Parser!AST
|
||||
case TOK.int16:
|
||||
case TOK.int32:
|
||||
case TOK.int64:
|
||||
case TOK.__int128:
|
||||
case TOK.float32:
|
||||
case TOK.float64:
|
||||
case TOK.signed:
|
||||
@@ -4304,6 +4334,7 @@ final class CParser(AST) : Parser!AST
|
||||
case TOK.int16:
|
||||
case TOK.int32:
|
||||
case TOK.int64:
|
||||
case TOK.__int128:
|
||||
case TOK.float32:
|
||||
case TOK.float64:
|
||||
case TOK.void_:
|
||||
@@ -4702,6 +4733,11 @@ final class CParser(AST) : Parser!AST
|
||||
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;
|
||||
}
|
||||
@@ -4723,6 +4759,11 @@ final class CParser(AST) : Parser!AST
|
||||
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;
|
||||
}
|
||||
@@ -5115,9 +5156,9 @@ final class CParser(AST) : Parser!AST
|
||||
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();
|
||||
}
|
||||
@@ -5278,6 +5319,8 @@ final class CParser(AST) : Parser!AST
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
@@ -173,7 +173,7 @@ private final class CppMangleVisitor : Visitor
|
||||
* 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;
|
||||
|
||||
+5
-19
@@ -1281,12 +1281,12 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide
|
||||
{
|
||||
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
|
||||
@@ -1298,13 +1298,7 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide
|
||||
}
|
||||
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)
|
||||
{
|
||||
@@ -1415,16 +1409,8 @@ bool ctfeIdentity(const ref Loc loc, EXP op, Expression e1, Expression e2)
|
||||
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);
|
||||
|
||||
@@ -1520,6 +1520,8 @@ Type toStaticArrayType(SliceExp e)
|
||||
*/
|
||||
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());
|
||||
|
||||
@@ -963,12 +963,6 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
|
||||
|
||||
/****************************************
|
||||
*/
|
||||
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);
|
||||
|
||||
+23
-12
@@ -1111,7 +1111,7 @@ extern (C++) class VarDeclaration : Declaration
|
||||
{
|
||||
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
|
||||
@@ -1148,6 +1148,12 @@ extern (C++) class VarDeclaration : Declaration
|
||||
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;
|
||||
@@ -1199,12 +1205,10 @@ extern (C++) class VarDeclaration : Declaration
|
||||
{
|
||||
//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;
|
||||
}
|
||||
|
||||
@@ -1315,9 +1319,17 @@ extern (C++) class VarDeclaration : Declaration
|
||||
|
||||
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
|
||||
@@ -1659,8 +1671,7 @@ extern (C++) class VarDeclaration : Declaration
|
||||
// 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);
|
||||
@@ -1697,8 +1708,8 @@ extern (C++) class VarDeclaration : Declaration
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
+12
-4
@@ -229,7 +229,7 @@ class VarDeclaration : public Declaration
|
||||
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
|
||||
@@ -270,6 +270,14 @@ public:
|
||||
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;
|
||||
@@ -634,8 +642,8 @@ public:
|
||||
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;
|
||||
@@ -680,7 +688,7 @@ public:
|
||||
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);
|
||||
|
||||
@@ -109,7 +109,7 @@ private void lambdaSetParent(Expression e, FuncDeclaration fd)
|
||||
}
|
||||
|
||||
public:
|
||||
extern (D) this(FuncDeclaration fd)
|
||||
extern (D) this(FuncDeclaration fd) scope
|
||||
{
|
||||
this.fd = fd;
|
||||
}
|
||||
@@ -205,7 +205,7 @@ bool lambdaCheckForNestedRef(Expression e, Scope* sc)
|
||||
Scope* sc;
|
||||
bool result;
|
||||
|
||||
extern (D) this(Scope* sc)
|
||||
extern (D) this(Scope* sc) scope
|
||||
{
|
||||
this.sc = sc;
|
||||
}
|
||||
|
||||
@@ -747,7 +747,7 @@ public:
|
||||
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;
|
||||
|
||||
+340
-290
@@ -14,17 +14,18 @@
|
||||
|
||||
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();
|
||||
}
|
||||
@@ -33,30 +34,38 @@ extern (C++) const(char)* mangleExact(FuncDeclaration fd)
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -127,6 +136,7 @@ import core.stdc.string;
|
||||
|
||||
import dmd.aggregate;
|
||||
import dmd.arraytypes;
|
||||
import dmd.astenums;
|
||||
import dmd.dclass;
|
||||
import dmd.declaration;
|
||||
import dmd.dmodule;
|
||||
@@ -231,6 +241,320 @@ unittest
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************
|
||||
* 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)
|
||||
{
|
||||
void visitWithMask(Type t, ubyte modMask)
|
||||
{
|
||||
void mangleSymbol(Dsymbol s)
|
||||
{
|
||||
scope Mangler v = new Mangler(buf, &backref);
|
||||
v.mangleSymbol(s);
|
||||
}
|
||||
|
||||
void visitType(Type t)
|
||||
{
|
||||
tyToDecoBuffer(buf, t.ty);
|
||||
}
|
||||
|
||||
void visitTypeNext(TypeNext t)
|
||||
{
|
||||
visitType(t);
|
||||
visitWithMask(t.next, t.mod);
|
||||
}
|
||||
|
||||
void visitTypeVector(TypeVector t)
|
||||
{
|
||||
buf.writestring("Nh");
|
||||
visitWithMask(t.basetype, t.mod);
|
||||
}
|
||||
|
||||
void visitTypeSArray(TypeSArray t)
|
||||
{
|
||||
visitType(t);
|
||||
if (t.dim)
|
||||
buf.print(t.dim.toInteger());
|
||||
if (t.next)
|
||||
visitWithMask(t.next, t.mod);
|
||||
}
|
||||
|
||||
void visitTypeDArray(TypeDArray t)
|
||||
{
|
||||
visitType(t);
|
||||
if (t.next)
|
||||
visitWithMask(t.next, t.mod);
|
||||
}
|
||||
|
||||
void visitTypeAArray(TypeAArray t)
|
||||
{
|
||||
visitType(t);
|
||||
visitWithMask(t.index, 0);
|
||||
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);
|
||||
}
|
||||
|
||||
void visitTypeIdentifier(TypeIdentifier t)
|
||||
{
|
||||
visitType(t);
|
||||
auto name = t.ident.toString();
|
||||
buf.print(cast(int)name.length);
|
||||
buf.writestring(name);
|
||||
}
|
||||
|
||||
void visitTypeEnum(TypeEnum t)
|
||||
{
|
||||
visitType(t);
|
||||
mangleSymbol(t.sym);
|
||||
}
|
||||
|
||||
void visitTypeStruct(TypeStruct t)
|
||||
{
|
||||
//printf("TypeStruct.toDecoBuffer('%s') = '%s'\n", t.toChars(), name);
|
||||
visitType(t);
|
||||
mangleSymbol(t.sym);
|
||||
}
|
||||
|
||||
void visitTypeClass(TypeClass t)
|
||||
{
|
||||
//printf("TypeClass.toDecoBuffer('%s' mod=%x) = '%s'\n", t.toChars(), mod, name);
|
||||
visitType(t);
|
||||
mangleSymbol(t.sym);
|
||||
}
|
||||
|
||||
void visitTypeTuple(TypeTuple t)
|
||||
{
|
||||
//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');
|
||||
}
|
||||
|
||||
void visitTypeNull(TypeNull t)
|
||||
{
|
||||
visitType(t);
|
||||
}
|
||||
|
||||
void visitTypeNoreturn(TypeNoreturn t)
|
||||
{
|
||||
buf.writestring("Nn");
|
||||
}
|
||||
|
||||
if (modMask != t.mod)
|
||||
{
|
||||
MODtoDecoBuffer(buf, t.mod);
|
||||
}
|
||||
if (backref.addRefToType(buf, t))
|
||||
return;
|
||||
|
||||
switch (t.ty)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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
|
||||
{
|
||||
// when return ref, the order is `scope return`
|
||||
if (ta.isScopeQual && !ta.isscopeinferred)
|
||||
buf.writestring("Nl");
|
||||
|
||||
if (ta.isreturn && !ta.isreturninferred)
|
||||
buf.writestring("Nj");
|
||||
}
|
||||
|
||||
if (ta.islive)
|
||||
buf.writestring("Nm");
|
||||
|
||||
switch (ta.trust)
|
||||
{
|
||||
case TRUST.trusted:
|
||||
buf.writestring("Ne");
|
||||
break;
|
||||
case TRUST.safe:
|
||||
buf.writestring("Nf");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// 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))
|
||||
{
|
||||
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);
|
||||
}
|
||||
mangleType(p.type, (stc & STC.in_) ? MODFlags.const_ : 0, buf, backref);
|
||||
}
|
||||
|
||||
|
||||
private extern (C++) final class Mangler : Visitor
|
||||
{
|
||||
alias visit = Visitor.visit;
|
||||
@@ -238,12 +562,12 @@ public:
|
||||
static assert(Key.sizeof == size_t.sizeof);
|
||||
|
||||
OutBuffer* buf;
|
||||
Backref backref;
|
||||
Backref* backref;
|
||||
|
||||
extern (D) this(OutBuffer* buf, Type rootType = null)
|
||||
extern (D) this(OutBuffer* buf, Backref* backref)
|
||||
{
|
||||
this.buf = buf;
|
||||
this.backref = Backref(rootType);
|
||||
this.backref = backref;
|
||||
}
|
||||
|
||||
void mangleSymbol(Dsymbol s)
|
||||
@@ -251,215 +575,12 @@ public:
|
||||
s.accept(this);
|
||||
}
|
||||
|
||||
void mangleType(Type t)
|
||||
{
|
||||
if (!backref.addRefToType(buf, t))
|
||||
t.accept(this);
|
||||
}
|
||||
|
||||
void mangleIdentifier(Identifier id, Dsymbol s)
|
||||
{
|
||||
if (!backref.addRefToIdentifier(buf, id))
|
||||
toBuffer(buf, id.toString(), s);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
/**************************************************
|
||||
* Type mangling
|
||||
*/
|
||||
void visitWithMask(Type t, ubyte modMask)
|
||||
{
|
||||
if (modMask != t.mod)
|
||||
{
|
||||
MODtoDecoBuffer(buf, t.mod);
|
||||
}
|
||||
mangleType(t);
|
||||
}
|
||||
|
||||
override void visit(Type t)
|
||||
{
|
||||
tyToDecoBuffer(buf, t.ty);
|
||||
}
|
||||
|
||||
override void visit(TypeNext t)
|
||||
{
|
||||
visit(cast(Type)t);
|
||||
visitWithMask(t.next, t.mod);
|
||||
}
|
||||
|
||||
override void visit(TypeVector t)
|
||||
{
|
||||
buf.writestring("Nh");
|
||||
visitWithMask(t.basetype, t.mod);
|
||||
}
|
||||
|
||||
override void visit(TypeSArray t)
|
||||
{
|
||||
visit(cast(Type)t);
|
||||
if (t.dim)
|
||||
buf.print(t.dim.toInteger());
|
||||
if (t.next)
|
||||
visitWithMask(t.next, t.mod);
|
||||
}
|
||||
|
||||
override void visit(TypeDArray t)
|
||||
{
|
||||
visit(cast(Type)t);
|
||||
if (t.next)
|
||||
visitWithMask(t.next, t.mod);
|
||||
}
|
||||
|
||||
override void visit(TypeAArray t)
|
||||
{
|
||||
visit(cast(Type)t);
|
||||
visitWithMask(t.index, 0);
|
||||
visitWithMask(t.next, t.mod);
|
||||
}
|
||||
|
||||
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 mangleFuncType(TypeFunction t, TypeFunction ta, ubyte modMask, Type tret)
|
||||
{
|
||||
//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);
|
||||
|
||||
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
|
||||
{
|
||||
// when return ref, the order is `scope return`
|
||||
if (ta.isScopeQual && !ta.isscopeinferred)
|
||||
buf.writestring("Nl");
|
||||
|
||||
if (ta.isreturn && !ta.isreturninferred)
|
||||
buf.writestring("Nj");
|
||||
}
|
||||
|
||||
if (ta.islive)
|
||||
buf.writestring("Nm");
|
||||
|
||||
switch (ta.trust)
|
||||
{
|
||||
case TRUST.trusted:
|
||||
buf.writestring("Ne");
|
||||
break;
|
||||
case TRUST.safe:
|
||||
buf.writestring("Nf");
|
||||
break;
|
||||
default:
|
||||
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--;
|
||||
}
|
||||
|
||||
override void visit(TypeIdentifier t)
|
||||
{
|
||||
visit(cast(Type)t);
|
||||
auto name = t.ident.toString();
|
||||
buf.print(cast(int)name.length);
|
||||
buf.writestring(name);
|
||||
}
|
||||
|
||||
override void visit(TypeEnum t)
|
||||
{
|
||||
visit(cast(Type)t);
|
||||
mangleSymbol(t.sym);
|
||||
}
|
||||
|
||||
override void visit(TypeStruct t)
|
||||
{
|
||||
//printf("TypeStruct.toDecoBuffer('%s') = '%s'\n", t.toChars(), name);
|
||||
visit(cast(Type)t);
|
||||
mangleSymbol(t.sym);
|
||||
}
|
||||
|
||||
override void visit(TypeClass t)
|
||||
{
|
||||
//printf("TypeClass.toDecoBuffer('%s' mod=%x) = '%s'\n", t.toChars(), mod, name);
|
||||
visit(cast(Type)t);
|
||||
mangleSymbol(t.sym);
|
||||
}
|
||||
|
||||
override void visit(TypeTuple t)
|
||||
{
|
||||
//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');
|
||||
}
|
||||
|
||||
override void visit(TypeNull t)
|
||||
{
|
||||
visit(cast(Type)t);
|
||||
}
|
||||
|
||||
override void visit(TypeNoreturn t)
|
||||
{
|
||||
buf.writestring("Nn");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
void mangleDecl(Declaration sthis)
|
||||
{
|
||||
@@ -472,7 +593,7 @@ public:
|
||||
}
|
||||
else if (sthis.type)
|
||||
{
|
||||
visitWithMask(sthis.type, 0);
|
||||
mangleType(sthis.type, 0, buf, *backref);
|
||||
}
|
||||
else
|
||||
assert(0);
|
||||
@@ -530,11 +651,11 @@ public:
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -735,7 +856,7 @@ public:
|
||||
if (ta)
|
||||
{
|
||||
buf.writeByte('T');
|
||||
visitWithMask(ta, 0);
|
||||
mangleType(ta, 0, buf, *backref);
|
||||
}
|
||||
else if (ea)
|
||||
{
|
||||
@@ -778,7 +899,7 @@ public:
|
||||
|
||||
/* 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)
|
||||
@@ -1004,77 +1125,6 @@ public:
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************
|
||||
@@ -1322,7 +1372,7 @@ void realToMangleBuffer(OutBuffer* buf, real_t value)
|
||||
|
||||
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])
|
||||
{
|
||||
|
||||
+34
-2
@@ -29,6 +29,7 @@ import dmd.dscope;
|
||||
import dmd.dsymbol;
|
||||
import dmd.dsymbolsem;
|
||||
import dmd.errors;
|
||||
import dmd.errorsink;
|
||||
import dmd.expression;
|
||||
import dmd.expressionsem;
|
||||
import dmd.file_manager;
|
||||
@@ -766,7 +767,7 @@ extern (C++) final class Module : Package
|
||||
{
|
||||
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();
|
||||
@@ -775,7 +776,7 @@ extern (C++) final class Module : Package
|
||||
}
|
||||
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;
|
||||
@@ -1377,6 +1378,37 @@ extern (C++) struct ModuleDeclaration
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************
|
||||
* 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
|
||||
*
|
||||
|
||||
+3
-2
@@ -951,7 +951,7 @@ private void emitComment(Dsymbol s, ref OutBuffer buf, Scope* 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;
|
||||
@@ -1235,7 +1235,7 @@ private void toDocBuffer(Dsymbol s, ref OutBuffer buf, Scope* 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;
|
||||
@@ -5183,6 +5183,7 @@ private void highlightCode2(Scope* sc, Dsymbols* a, ref OutBuffer buf, size_t of
|
||||
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;
|
||||
|
||||
+6
-1
@@ -64,13 +64,14 @@ enum SCOPE
|
||||
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
|
||||
{
|
||||
@@ -272,6 +273,10 @@ 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.
|
||||
|
||||
+11
-1
@@ -75,7 +75,7 @@ extern (C++) void semanticTypeInfo(Scope* sc, Type t)
|
||||
{
|
||||
if (sc.intypeof)
|
||||
return;
|
||||
if (sc.flags & (SCOPE.ctfe | SCOPE.compile))
|
||||
if (sc.flags & (SCOPE.ctfe | SCOPE.compile | SCOPE.ctfeBlock))
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -480,6 +480,16 @@ extern (C++) class StructDeclaration : AggregateDeclaration
|
||||
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;
|
||||
|
||||
+8
-8
@@ -999,10 +999,7 @@ extern (C++) class Dsymbol : ASTNode
|
||||
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);
|
||||
@@ -1242,10 +1239,6 @@ extern (C++) class Dsymbol : ASTNode
|
||||
return false;
|
||||
}
|
||||
|
||||
void addLocalClass(ClassDeclarations*)
|
||||
{
|
||||
}
|
||||
|
||||
void addObjcSymbols(ClassDeclarations* classes, ClassDeclarations* categories)
|
||||
{
|
||||
}
|
||||
@@ -1416,6 +1409,7 @@ extern (C++) class Dsymbol : ASTNode
|
||||
inout(OverloadSet) isOverloadSet() inout { return null; }
|
||||
inout(CompileDeclaration) isCompileDeclaration() inout { return null; }
|
||||
inout(StaticAssert) isStaticAssert() inout { return null; }
|
||||
inout(StaticIfDeclaration) isStaticIfDeclaration() inout { return null; }
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
@@ -2620,6 +2614,12 @@ Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsy
|
||||
|
||||
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
|
||||
|
||||
+2
-1
@@ -72,6 +72,7 @@ class ExpressionDsymbol;
|
||||
class AliasAssign;
|
||||
class OverloadSet;
|
||||
class StaticAssert;
|
||||
class StaticIfDeclaration;
|
||||
struct AA;
|
||||
#ifdef IN_GCC
|
||||
typedef union tree_node Symbol;
|
||||
@@ -257,7 +258,6 @@ public:
|
||||
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() { }
|
||||
|
||||
@@ -323,6 +323,7 @@ public:
|
||||
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); }
|
||||
};
|
||||
|
||||
|
||||
+147
-65
@@ -230,12 +230,48 @@ package bool allowsContractWithoutBody(FuncDeclaration funcdecl)
|
||||
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;
|
||||
}
|
||||
@@ -281,6 +317,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
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)
|
||||
@@ -338,6 +379,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
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;
|
||||
@@ -509,10 +555,10 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
{
|
||||
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;
|
||||
}
|
||||
@@ -528,7 +574,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
// 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())
|
||||
@@ -544,7 +590,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
}
|
||||
}
|
||||
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())
|
||||
{
|
||||
@@ -689,7 +735,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
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;
|
||||
}
|
||||
@@ -742,7 +788,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
}
|
||||
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())
|
||||
{
|
||||
@@ -780,11 +826,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
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
|
||||
@@ -804,21 +850,37 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
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)
|
||||
@@ -836,7 +898,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
}
|
||||
if (!isWild)
|
||||
{
|
||||
dsym.error("`inout` variables can only be declared inside `inout` functions");
|
||||
dsym.error("- `inout` variables can only be declared inside `inout` functions");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -856,7 +918,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
{
|
||||
}
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -911,7 +973,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
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())
|
||||
@@ -939,7 +1001,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
|
||||
//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
|
||||
@@ -974,7 +1036,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
}
|
||||
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))
|
||||
{
|
||||
@@ -995,7 +1057,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
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();
|
||||
@@ -1049,9 +1111,26 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
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;
|
||||
}
|
||||
@@ -1244,7 +1323,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
|
||||
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();
|
||||
@@ -1534,12 +1613,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
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)
|
||||
@@ -1742,7 +1821,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
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
|
||||
@@ -1854,7 +1933,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
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);
|
||||
@@ -2656,7 +2735,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
|
||||
override void visit(TemplateInstance ti)
|
||||
{
|
||||
templateInstanceSemantic(ti, sc, null);
|
||||
templateInstanceSemantic(ti, sc, ArgumentList());
|
||||
}
|
||||
|
||||
override void visit(TemplateMixin tm)
|
||||
@@ -2694,7 +2773,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
/* 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
|
||||
{
|
||||
@@ -3054,7 +3133,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
//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())
|
||||
@@ -3844,11 +3923,25 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
|
||||
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
|
||||
{
|
||||
@@ -4088,9 +4181,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
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 "~
|
||||
@@ -4115,20 +4207,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4171,8 +4250,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
|
||||
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)
|
||||
@@ -4534,7 +4613,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
|
||||
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);
|
||||
|
||||
@@ -4604,6 +4684,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
|
||||
if (!sd.members) // if opaque declaration
|
||||
{
|
||||
if (log) printf("\topaque declaration %s\n", sd.toChars());
|
||||
sd.semanticRun = PASS.semanticdone;
|
||||
return;
|
||||
}
|
||||
@@ -4655,7 +4736,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
|
||||
sc2.pop();
|
||||
|
||||
//printf("\tdeferring %s\n", toChars());
|
||||
if (log) printf("\tdeferring %s\n", sd.toChars());
|
||||
return deferDsymbolSemantic(sd, scx);
|
||||
}
|
||||
|
||||
@@ -4685,7 +4766,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
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();
|
||||
|
||||
@@ -4698,7 +4779,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
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);
|
||||
|
||||
@@ -4752,6 +4833,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
// 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)
|
||||
@@ -5297,9 +5379,9 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
// 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());
|
||||
@@ -5311,7 +5393,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
// 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());
|
||||
|
||||
@@ -5776,7 +5858,7 @@ void addEnumMembers(EnumDeclaration ed, Scope* sc, ScopeDsymbol sds)
|
||||
});
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -5848,7 +5930,7 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions*
|
||||
* 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)
|
||||
@@ -5901,6 +5983,8 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions*
|
||||
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.
|
||||
*/
|
||||
@@ -5986,7 +6070,7 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions*
|
||||
alias visit = Visitor.visit;
|
||||
TemplateInstance inst;
|
||||
|
||||
extern (D) this(TemplateInstance inst)
|
||||
extern (D) this(TemplateInstance inst) scope
|
||||
{
|
||||
this.inst = inst;
|
||||
}
|
||||
@@ -6142,7 +6226,7 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions*
|
||||
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;
|
||||
}
|
||||
@@ -6189,7 +6273,7 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions*
|
||||
{
|
||||
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;
|
||||
}
|
||||
@@ -7022,12 +7106,10 @@ bool determineFields(AggregateDeclaration ad)
|
||||
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))
|
||||
|
||||
+173
-74
@@ -45,6 +45,7 @@ import dmd.aliasthis;
|
||||
import dmd.arraytypes;
|
||||
import dmd.astenums;
|
||||
import dmd.ast_node;
|
||||
import dmd.attrib;
|
||||
import dmd.dcast;
|
||||
import dmd.dclass;
|
||||
import dmd.declaration;
|
||||
@@ -1050,7 +1051,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
|
||||
* 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)
|
||||
@@ -1168,6 +1169,12 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
|
||||
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;
|
||||
@@ -1226,7 +1233,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
|
||||
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;
|
||||
}
|
||||
@@ -1237,7 +1244,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
|
||||
* 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)
|
||||
@@ -1272,7 +1279,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
|
||||
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
|
||||
@@ -1303,14 +1310,14 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
|
||||
* 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;
|
||||
@@ -1334,7 +1341,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
|
||||
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());
|
||||
@@ -1458,7 +1465,10 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
|
||||
|
||||
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:
|
||||
@@ -2593,13 +2603,12 @@ extern (C++) final class TypeDeduced : Type
|
||||
* 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());
|
||||
@@ -2704,7 +2713,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
|
||||
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;
|
||||
@@ -2737,8 +2746,8 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
|
||||
* 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;
|
||||
@@ -2806,7 +2815,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
|
||||
|
||||
int applyTemplate(TemplateDeclaration td)
|
||||
{
|
||||
//printf("applyTemplate()\n");
|
||||
//printf("applyTemplate(): td = %s\n", td.toChars());
|
||||
if (td == td_best) // skip duplicates
|
||||
return 0;
|
||||
|
||||
@@ -2830,6 +2839,11 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
|
||||
}
|
||||
//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)
|
||||
{
|
||||
@@ -2838,12 +2852,12 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
|
||||
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;
|
||||
|
||||
@@ -2882,13 +2896,13 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
|
||||
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;
|
||||
@@ -2907,7 +2921,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
|
||||
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;
|
||||
|
||||
@@ -2954,7 +2968,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
|
||||
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);
|
||||
@@ -2967,7 +2981,6 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
|
||||
if (isCtorCall)
|
||||
{
|
||||
// Constructor call requires additional check.
|
||||
|
||||
auto tf = cast(TypeFunction)fd.type;
|
||||
assert(tf.next);
|
||||
if (MODimplicitConv(tf.mod, tthis_fd.mod) ||
|
||||
@@ -2978,6 +2991,16 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
|
||||
}
|
||||
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;
|
||||
@@ -2989,8 +3012,8 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
|
||||
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;
|
||||
@@ -3000,16 +3023,16 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
|
||||
// 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;
|
||||
@@ -3076,7 +3099,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
|
||||
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)
|
||||
@@ -3104,7 +3127,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
|
||||
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,
|
||||
@@ -5887,7 +5910,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -5902,7 +5925,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
|
||||
* 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)
|
||||
@@ -6010,7 +6033,10 @@ extern (C++) class TemplateInstance : ScopeDsymbol
|
||||
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
|
||||
@@ -6247,41 +6273,55 @@ extern (C++) class TemplateInstance : ScopeDsymbol
|
||||
*/
|
||||
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);
|
||||
@@ -6291,8 +6331,10 @@ extern (C++) class TemplateInstance : ScopeDsymbol
|
||||
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.
|
||||
@@ -6317,31 +6359,39 @@ extern (C++) class TemplateInstance : ScopeDsymbol
|
||||
* => 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());
|
||||
@@ -6350,8 +6400,10 @@ extern (C++) class TemplateInstance : ScopeDsymbol
|
||||
else if (!minst)
|
||||
{
|
||||
minst = tnext.minst; // cache result from non-speculative sibling
|
||||
return true;
|
||||
// continue searching
|
||||
}
|
||||
else if (needsCodegen != ThreeState.none)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6564,7 +6616,17 @@ extern (C++) class TemplateInstance : ScopeDsymbol
|
||||
}
|
||||
|
||||
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
|
||||
@@ -6883,12 +6945,12 @@ extern (C++) class TemplateInstance : ScopeDsymbol
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
@@ -6897,7 +6959,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
|
||||
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;
|
||||
@@ -6947,7 +7009,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
|
||||
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;
|
||||
@@ -6956,8 +7018,8 @@ extern (C++) class TemplateInstance : ScopeDsymbol
|
||||
|
||||
// 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;
|
||||
@@ -7223,7 +7285,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
|
||||
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;
|
||||
}
|
||||
@@ -7480,6 +7542,43 @@ extern (C++) class TemplateInstance : ScopeDsymbol
|
||||
|
||||
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());
|
||||
|
||||
+17
-3
@@ -291,9 +291,23 @@ public:
|
||||
|
||||
/// 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;
|
||||
@@ -875,7 +889,7 @@ public:
|
||||
// (we'll visit them later)
|
||||
if (vd.type && vd.type.isTypeTuple())
|
||||
{
|
||||
assert(vd.aliassym);
|
||||
assert(vd.aliasTuple);
|
||||
vd.toAlias().accept(this);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -12,11 +12,63 @@
|
||||
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
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* 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, ...) { }
|
||||
}
|
||||
+116
-78
@@ -181,7 +181,7 @@ bool checkMutableArguments(Scope* sc, FuncDeclaration fd, TypeFunction tf,
|
||||
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)
|
||||
@@ -558,6 +558,46 @@ bool checkConstructorEscape(Scope* sc, CallExp ce, bool 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.
|
||||
@@ -608,6 +648,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
|
||||
if (e1.isStructLiteralExp())
|
||||
return false;
|
||||
|
||||
VarDeclaration va = expToVariable(e1);
|
||||
EscapeByResults er;
|
||||
|
||||
if (byRef)
|
||||
@@ -618,7 +659,6 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool 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)
|
||||
{
|
||||
@@ -653,30 +693,23 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
|
||||
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;
|
||||
@@ -1745,7 +1778,25 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re
|
||||
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)
|
||||
@@ -1768,67 +1819,54 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
const psr = buildScopeRef(getThisStorageClass(fd));
|
||||
if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope)
|
||||
escapeByValue(dve.e1, er, live, retRefTransition);
|
||||
else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope)
|
||||
{
|
||||
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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
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);
|
||||
const psr = buildScopeRef(getThisStorageClass(fd));
|
||||
if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope)
|
||||
escapeByValue(dve.e1, er, live, retRefTransition);
|
||||
{
|
||||
if (!tf.isref || tf.isctor)
|
||||
escapeByValue(dve.e1, er, live, retRefTransition);
|
||||
}
|
||||
else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope)
|
||||
escapeByRef(dve.e1, er, live, retRefTransition);
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// If it's also a nested function that is 'return scope'
|
||||
|
||||
+136
-27
@@ -249,18 +249,55 @@ bool isDotOpDispatch(Expression e)
|
||||
}
|
||||
|
||||
/****************************************
|
||||
* 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];
|
||||
@@ -275,6 +312,7 @@ extern (C++) void expandTuples(Expressions* exps)
|
||||
if (!tt.arguments || tt.arguments.length == 0)
|
||||
{
|
||||
exps.remove(i);
|
||||
expandNames(i, 0);
|
||||
if (i == exps.length)
|
||||
return;
|
||||
}
|
||||
@@ -285,6 +323,7 @@ extern (C++) void expandTuples(Expressions* exps)
|
||||
foreach (j, a; *tt.arguments)
|
||||
(*texps)[j] = new TypeExp(e.loc, a.type);
|
||||
exps.insert(i, texps);
|
||||
expandNames(i, texps.length);
|
||||
}
|
||||
i--;
|
||||
continue;
|
||||
@@ -297,6 +336,7 @@ extern (C++) void expandTuples(Expressions* exps)
|
||||
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]);
|
||||
@@ -682,11 +722,11 @@ extern (C++) abstract class Expression : ASTNode
|
||||
{
|
||||
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;
|
||||
@@ -1393,7 +1433,7 @@ extern (C++) abstract class Expression : ASTNode
|
||||
*/
|
||||
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());
|
||||
}
|
||||
@@ -1435,7 +1475,7 @@ extern (C++) abstract class Expression : ASTNode
|
||||
|
||||
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;
|
||||
@@ -1488,7 +1528,7 @@ extern (C++) abstract class Expression : ASTNode
|
||||
|
||||
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;
|
||||
@@ -1496,7 +1536,8 @@ extern (C++) abstract class Expression : ASTNode
|
||||
// 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());
|
||||
|
||||
@@ -1647,6 +1688,15 @@ extern (C++) abstract class Expression : ASTNode
|
||||
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()
|
||||
@@ -2137,6 +2187,13 @@ extern (C++) final class RealExp : Expression
|
||||
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();
|
||||
@@ -2213,6 +2270,16 @@ extern (C++) final class ComplexExp : Expression
|
||||
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();
|
||||
@@ -2261,7 +2328,7 @@ extern (C++) class IdentifierExp : Expression
|
||||
{
|
||||
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;
|
||||
@@ -2416,7 +2483,7 @@ extern (C++) final class SuperExp : ThisExp
|
||||
*/
|
||||
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;
|
||||
@@ -2475,7 +2542,7 @@ extern (C++) final class StringExp : Expression
|
||||
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
|
||||
@@ -2483,7 +2550,7 @@ extern (C++) final class StringExp : Expression
|
||||
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
|
||||
@@ -3570,18 +3637,26 @@ extern (C++) final class NewExp : Expression
|
||||
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)
|
||||
@@ -3594,7 +3669,8 @@ extern (C++) final class NewExp : Expression
|
||||
return new NewExp(loc,
|
||||
thisexp ? thisexp.syntaxCopy() : null,
|
||||
newtype.syntaxCopy(),
|
||||
arraySyntaxCopy(arguments));
|
||||
arraySyntaxCopy(arguments),
|
||||
names ? names.copy() : null);
|
||||
}
|
||||
|
||||
override void accept(Visitor v)
|
||||
@@ -3969,6 +4045,7 @@ extern (C++) final class FuncExp : Expression
|
||||
Type t = pto.type;
|
||||
if (t.ty == Terror)
|
||||
return cannotInfer(this, to, flag);
|
||||
tf.parameterList[u].storageClass = tof.parameterList[u].storageClass;
|
||||
tiargs.push(t);
|
||||
}
|
||||
|
||||
@@ -4217,7 +4294,7 @@ extern (C++) final class IsExp : Expression
|
||||
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;
|
||||
@@ -4257,7 +4334,7 @@ extern (C++) abstract class UnaExp : Expression
|
||||
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;
|
||||
@@ -4330,7 +4407,7 @@ extern (C++) abstract class BinExp : Expression
|
||||
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;
|
||||
@@ -4621,7 +4698,7 @@ extern (C++) abstract class BinExp : Expression
|
||||
*/
|
||||
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);
|
||||
}
|
||||
@@ -5048,21 +5125,53 @@ extern (C++) final class DotTypeExp : UnaExp
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
@@ -5129,7 +5238,7 @@ extern (C++) final class CallExp : UnaExp
|
||||
|
||||
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()
|
||||
@@ -5325,7 +5434,7 @@ extern (C++) final class NegExp : UnaExp
|
||||
*/
|
||||
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);
|
||||
}
|
||||
@@ -6387,7 +6496,7 @@ extern (C++) final class MinExp : BinExp
|
||||
*/
|
||||
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);
|
||||
}
|
||||
@@ -6717,7 +6826,7 @@ extern (C++) final class CondExp : BinExp
|
||||
{
|
||||
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;
|
||||
|
||||
@@ -45,7 +45,7 @@ typedef union tree_node Symbol;
|
||||
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);
|
||||
|
||||
@@ -81,7 +81,7 @@ class Expression : public ASTNode
|
||||
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
|
||||
|
||||
@@ -123,6 +123,7 @@ public:
|
||||
// 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()
|
||||
{
|
||||
@@ -281,6 +282,7 @@ public:
|
||||
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;
|
||||
@@ -298,6 +300,7 @@ public:
|
||||
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;
|
||||
@@ -529,6 +532,7 @@ public:
|
||||
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[]
|
||||
|
||||
@@ -536,6 +540,8 @@ public:
|
||||
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;
|
||||
|
||||
@@ -823,6 +829,7 @@ class CallExp final : public UnaExp
|
||||
{
|
||||
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
|
||||
|
||||
+207
-115
@@ -105,6 +105,8 @@ bool expressionsToString(ref OutBuffer buf, Scope* sc, Expressions* exps)
|
||||
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();
|
||||
@@ -260,7 +262,7 @@ Expression resolveOpDollar(Scope* sc, ArrayExp ae, Expression* pe0)
|
||||
|
||||
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)
|
||||
@@ -649,6 +651,9 @@ private Expression resolveUFCS(Scope* sc, CallExp ce)
|
||||
if (!ce.arguments)
|
||||
ce.arguments = new Expressions();
|
||||
ce.arguments.shift(eleft);
|
||||
if (!ce.names)
|
||||
ce.names = new Identifiers();
|
||||
ce.names.shift(null);
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -1192,7 +1197,7 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
|
||||
|
||||
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();
|
||||
@@ -1209,7 +1214,7 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
|
||||
{
|
||||
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();
|
||||
@@ -1307,7 +1312,7 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
|
||||
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)
|
||||
@@ -1327,7 +1332,7 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
|
||||
}
|
||||
}
|
||||
{
|
||||
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)
|
||||
@@ -1586,29 +1591,22 @@ private Expression opAssignToOp(const ref Loc loc, EXP op, Expression e1, Expres
|
||||
/*********************
|
||||
* 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);
|
||||
@@ -1619,20 +1617,24 @@ private Expression rewriteOpAssign(BinExp exp)
|
||||
|
||||
/****************************************
|
||||
* 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++)
|
||||
{
|
||||
@@ -1708,7 +1710,7 @@ private bool checkDefCtor(Loc loc, Type t)
|
||||
* 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
|
||||
@@ -1716,20 +1718,38 @@ private bool checkDefCtor(Loc loc, Type t)
|
||||
* 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());
|
||||
@@ -1796,11 +1816,18 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
|
||||
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
|
||||
{
|
||||
@@ -1978,11 +2005,18 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
|
||||
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])
|
||||
@@ -2145,19 +2179,6 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
|
||||
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
|
||||
{
|
||||
@@ -2443,10 +2464,10 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
|
||||
}
|
||||
//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
|
||||
@@ -2545,7 +2566,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
Scope* sc;
|
||||
Expression result;
|
||||
|
||||
this(Scope* sc)
|
||||
this(Scope* sc) scope
|
||||
{
|
||||
this.sc = sc;
|
||||
}
|
||||
@@ -3547,7 +3568,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
{
|
||||
return setError();
|
||||
}
|
||||
if (preFunctionParameters(sc, exp.arguments))
|
||||
if (preFunctionParameters(sc, exp.argumentList))
|
||||
{
|
||||
return setError();
|
||||
}
|
||||
@@ -3706,7 +3727,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
|
||||
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();
|
||||
|
||||
@@ -3716,7 +3737,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
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();
|
||||
@@ -3776,6 +3797,32 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
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())
|
||||
{
|
||||
@@ -3805,7 +3852,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
// 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();
|
||||
|
||||
@@ -3815,7 +3862,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
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();
|
||||
@@ -3826,8 +3873,20 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
}
|
||||
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();
|
||||
@@ -3876,6 +3935,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -3897,6 +3962,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
}
|
||||
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;
|
||||
@@ -4285,7 +4355,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
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
|
||||
@@ -4524,7 +4594,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
return;
|
||||
}
|
||||
if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc) ||
|
||||
preFunctionParameters(sc, exp.arguments))
|
||||
preFunctionParameters(sc, exp.argumentList))
|
||||
return setError();
|
||||
|
||||
// Check for call operator overload
|
||||
@@ -4622,7 +4692,22 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
/* 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;
|
||||
@@ -4632,7 +4717,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
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;
|
||||
@@ -4671,14 +4756,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -4738,7 +4823,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
}
|
||||
|
||||
// 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();
|
||||
|
||||
@@ -4901,9 +4986,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
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();
|
||||
@@ -4928,7 +5013,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
}
|
||||
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)
|
||||
@@ -4975,7 +5060,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
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())
|
||||
@@ -4999,7 +5084,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
{
|
||||
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())
|
||||
@@ -5027,8 +5112,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
}
|
||||
|
||||
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('(');
|
||||
@@ -5095,14 +5179,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
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('(');
|
||||
@@ -5144,7 +5227,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
//
|
||||
// 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();
|
||||
@@ -5176,7 +5259,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
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)
|
||||
@@ -5499,8 +5582,18 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
{
|
||||
// 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)
|
||||
@@ -6009,7 +6102,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
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);
|
||||
|
||||
@@ -8342,13 +8435,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -12043,6 +12135,15 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
__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;
|
||||
@@ -13149,11 +13250,6 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)
|
||||
|
||||
//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)
|
||||
@@ -13166,7 +13262,9 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)
|
||||
// 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;
|
||||
}
|
||||
@@ -13175,10 +13273,6 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = 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;
|
||||
}
|
||||
|
||||
@@ -13216,33 +13310,32 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)
|
||||
return check(e.e1, false);
|
||||
}
|
||||
|
||||
bool visitThis(ThisExp e)
|
||||
{
|
||||
if (sc.func && sc.func.isSynchronized())
|
||||
return false;
|
||||
|
||||
if (!allowRef && e.type.isShared())
|
||||
return sharedError(e);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
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())
|
||||
if (e.type.isShared())
|
||||
{
|
||||
return check(e.e1, allowRef && (ve.var.storage_class & STC.ref_));
|
||||
// / https://issues.dlang.org/show_bug.cgi?id=22626
|
||||
if (e.e1.isThisExp() && sc.func && sc.func.isSynchronized())
|
||||
return false;
|
||||
|
||||
auto fd = e.var.isFuncDeclaration();
|
||||
const sharedFunc = fd && fd.type.isShared;
|
||||
if (!allowRef && !sharedFunc)
|
||||
return sharedError(e);
|
||||
|
||||
// Allow using `DotVarExp` within value types
|
||||
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_));
|
||||
}
|
||||
|
||||
return sharedError(e);
|
||||
}
|
||||
|
||||
return check(e.e1, false);
|
||||
@@ -13283,7 +13376,6 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = 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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ void foreachVar(Expression e, void delegate(VarDeclaration) dgVar)
|
||||
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;
|
||||
}
|
||||
|
||||
+62
-17
@@ -202,7 +202,7 @@ private struct FUNCFLAG
|
||||
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
|
||||
@@ -217,6 +217,8 @@ private struct FUNCFLAG
|
||||
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
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
@@ -322,6 +324,12 @@ extern (C++) class FuncDeclaration : Declaration
|
||||
|
||||
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;
|
||||
|
||||
@@ -1039,12 +1047,13 @@ extern (C++) class FuncDeclaration : Declaration
|
||||
* 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());
|
||||
}
|
||||
|
||||
@@ -1089,7 +1098,7 @@ extern (C++) class FuncDeclaration : Declaration
|
||||
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
|
||||
@@ -1979,6 +1988,7 @@ extern (C++) class FuncDeclaration : Declaration
|
||||
if (!sc.intypeof && !(sc.flags & SCOPE.compile))
|
||||
{
|
||||
siblingCallers.push(fdthis);
|
||||
computedEscapingSiblings = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2028,8 +2038,7 @@ extern (C++) class FuncDeclaration : Declaration
|
||||
* 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;
|
||||
@@ -2106,7 +2115,7 @@ extern (C++) class FuncDeclaration : Declaration
|
||||
*/
|
||||
extern (C++) final bool checkClosure()
|
||||
{
|
||||
//printf("checkClosure() %s\n", toChars());
|
||||
//printf("checkClosure() %s\n", toPrettyChars());
|
||||
if (!needsClosure())
|
||||
return false;
|
||||
|
||||
@@ -2320,6 +2329,7 @@ extern (C++) class FuncDeclaration : Declaration
|
||||
* base.in();
|
||||
* assert(false, "Logic error: " ~ thr.msg);
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
|
||||
foreach (fdv; foverrides)
|
||||
@@ -2827,6 +2837,12 @@ extern (C++) class FuncDeclaration : Declaration
|
||||
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;
|
||||
@@ -3127,14 +3143,15 @@ enum FuncResolveFlag : ubyte
|
||||
* 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
|
||||
|
||||
@@ -3152,6 +3169,7 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
|
||||
printf("\t%s: %s\n", arg.toChars(), arg.type.toChars());
|
||||
}
|
||||
}
|
||||
printf("\tfnames: %s\n", fnames ? fnames.toChars() : "null");
|
||||
}
|
||||
|
||||
if (tiargs && arrayObjectIsError(tiargs))
|
||||
@@ -3162,7 +3180,7 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
|
||||
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)
|
||||
@@ -3285,7 +3303,7 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol 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)
|
||||
{
|
||||
.error(loc, "%s `%s%s%s` is not callable using argument types `%s`",
|
||||
@@ -3331,7 +3349,7 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol 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`",
|
||||
@@ -3345,7 +3363,7 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol 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);
|
||||
}
|
||||
@@ -3362,8 +3380,10 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
|
||||
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;
|
||||
@@ -3619,6 +3639,9 @@ private bool checkEscapingSiblings(FuncDeclaration f, FuncDeclaration outerFunc,
|
||||
FuncDeclaration f;
|
||||
}
|
||||
|
||||
if (f.computedEscapingSiblings)
|
||||
return f.hasEscapingSiblings;
|
||||
|
||||
PrevSibling ps;
|
||||
ps.p = cast(PrevSibling*)p;
|
||||
ps.f = f;
|
||||
@@ -3660,6 +3683,8 @@ private bool checkEscapingSiblings(FuncDeclaration f, FuncDeclaration outerFunc,
|
||||
prev = prev.p;
|
||||
}
|
||||
}
|
||||
f.hasEscapingSiblings = bAnyClosures;
|
||||
f.computedEscapingSiblings = true;
|
||||
//printf("\t%d\n", bAnyClosures);
|
||||
return bAnyClosures;
|
||||
}
|
||||
@@ -3859,7 +3884,7 @@ extern (C++) final class CtorDeclaration : FuncDeclaration
|
||||
{
|
||||
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)
|
||||
@@ -4350,6 +4375,26 @@ extern (C++) final class NewDeclaration : FuncDeclaration
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************
|
||||
* 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`
|
||||
@@ -4392,7 +4437,7 @@ bool setUnsafe(Scope* sc,
|
||||
}
|
||||
|
||||
|
||||
if (sc.flags & SCOPE.compile) // __traits(compiles, x)
|
||||
if (isRootTraitsCompilesScope(sc)) // __traits(compiles, x)
|
||||
{
|
||||
if (sc.func.isSafeBypassingInference())
|
||||
{
|
||||
|
||||
+8
-1
@@ -15,6 +15,8 @@ import core.stdc.stdint;
|
||||
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;
|
||||
@@ -143,7 +145,7 @@ extern (C++) struct Param
|
||||
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
|
||||
@@ -176,6 +178,7 @@ extern (C++) struct Param
|
||||
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
|
||||
@@ -291,6 +294,8 @@ extern (C++) struct Global
|
||||
|
||||
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:
|
||||
@@ -345,6 +350,8 @@ extern (C++) struct Global
|
||||
|
||||
extern (C++) void _init()
|
||||
{
|
||||
global.errorSink = new ErrorSinkCompiler;
|
||||
|
||||
this.fileManager = new FileManager();
|
||||
version (MARS)
|
||||
{
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
// Can't include arraytypes.h here, need to declare these directly.
|
||||
template <typename TYPE> struct Array;
|
||||
|
||||
class ErrorSink;
|
||||
class FileManager;
|
||||
struct Loc;
|
||||
|
||||
@@ -179,6 +180,7 @@ struct Param
|
||||
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
|
||||
@@ -277,6 +279,7 @@ struct Global
|
||||
unsigned varSequenceNumber;
|
||||
|
||||
FileManager* fileManager;
|
||||
ErrorSink* errorSink; // where the error messages go
|
||||
|
||||
FileName (*preprocess)(FileName, const Loc&, bool&, OutBuffer&);
|
||||
|
||||
|
||||
+57
-16
@@ -65,6 +65,7 @@ struct HdrGenState
|
||||
int autoMember;
|
||||
int forStmtInit;
|
||||
int insideFuncBody;
|
||||
int insideAggregate;
|
||||
|
||||
bool declstring; // set while declaring alias for string,wstring or dstring
|
||||
EnumDeclaration inEnumDecl;
|
||||
@@ -144,7 +145,7 @@ public:
|
||||
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;
|
||||
@@ -805,7 +806,7 @@ public:
|
||||
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;
|
||||
@@ -1406,8 +1407,10 @@ public:
|
||||
buf.writeByte('{');
|
||||
buf.writenl();
|
||||
buf.level++;
|
||||
hgs.insideAggregate++;
|
||||
foreach (s; *d.members)
|
||||
s.accept(this);
|
||||
hgs.insideAggregate--;
|
||||
buf.level--;
|
||||
buf.writeByte('}');
|
||||
buf.writenl();
|
||||
@@ -1428,8 +1431,10 @@ public:
|
||||
buf.writeByte('{');
|
||||
buf.writenl();
|
||||
buf.level++;
|
||||
hgs.insideAggregate++;
|
||||
foreach (s; *d.members)
|
||||
s.accept(this);
|
||||
hgs.insideAggregate--;
|
||||
buf.level--;
|
||||
buf.writeByte('}');
|
||||
}
|
||||
@@ -1521,6 +1526,21 @@ public:
|
||||
|
||||
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(", ");
|
||||
@@ -1528,21 +1548,30 @@ public:
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2136,7 +2165,7 @@ private void expressionPrettyPrint(Expression e, OutBuffer* buf, HdrGenState* hg
|
||||
if (e.arguments && e.arguments.length)
|
||||
{
|
||||
buf.writeByte('(');
|
||||
argsToBuffer(e.arguments, buf, hgs);
|
||||
argsToBuffer(e.arguments, buf, hgs, null, e.names);
|
||||
buf.writeByte(')');
|
||||
}
|
||||
}
|
||||
@@ -2440,7 +2469,7 @@ private void expressionPrettyPrint(Expression e, OutBuffer* buf, HdrGenState* hg
|
||||
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(')');
|
||||
}
|
||||
|
||||
@@ -2683,7 +2712,7 @@ void floatToBuffer(Type type, const real_t value, OutBuffer* buf, const bool all
|
||||
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)
|
||||
{
|
||||
@@ -2691,7 +2720,7 @@ void floatToBuffer(Type type, const real_t value, OutBuffer* buf, const bool all
|
||||
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] == '.')
|
||||
@@ -2733,7 +2762,7 @@ public:
|
||||
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;
|
||||
@@ -2814,7 +2843,7 @@ public:
|
||||
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;
|
||||
@@ -3281,8 +3310,14 @@ private void parameterToBuffer(Parameter p, OutBuffer* buf, HdrGenState* 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;
|
||||
@@ -3292,6 +3327,12 @@ private void argsToBuffer(Expressions* expressions, OutBuffer* buf, HdrGenState*
|
||||
{
|
||||
if (i)
|
||||
buf.writestring(", ");
|
||||
|
||||
if (names && i < names.length && (*names)[i])
|
||||
{
|
||||
buf.writestring((*names)[i].toString());
|
||||
buf.writestring(": ");
|
||||
}
|
||||
if (!el)
|
||||
el = basis;
|
||||
if (el)
|
||||
|
||||
+11
-7
@@ -17,6 +17,7 @@ import dmd.arraytypes;
|
||||
import dmd.astcodegen;
|
||||
import dmd.dscope;
|
||||
import dmd.errors;
|
||||
import dmd.errorsink;
|
||||
import dmd.expression;
|
||||
import dmd.expressionsem;
|
||||
import dmd.identifier;
|
||||
@@ -72,7 +73,7 @@ int parseExtAsmOperands(Parser)(Parser p, GccAsmStatement s)
|
||||
}
|
||||
else
|
||||
{
|
||||
p.error(s.loc, "expected identifier after `[`");
|
||||
p.eSink.error(s.loc, "expected identifier after `[`");
|
||||
goto Lerror;
|
||||
}
|
||||
// Look for closing `]`
|
||||
@@ -116,7 +117,7 @@ int parseExtAsmOperands(Parser)(Parser p, GccAsmStatement s)
|
||||
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;
|
||||
}
|
||||
@@ -167,7 +168,7 @@ Expressions *parseExtAsmClobbers(Parser)(Parser p)
|
||||
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;
|
||||
}
|
||||
@@ -214,7 +215,7 @@ Identifiers *parseExtAsmGotoLabels(Parser)(Parser p)
|
||||
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;
|
||||
}
|
||||
@@ -301,7 +302,7 @@ Ldone:
|
||||
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;
|
||||
@@ -384,6 +385,9 @@ unittest
|
||||
{
|
||||
import dmd.mtype : TypeBasic;
|
||||
|
||||
if (!global.errorSink)
|
||||
global.errorSink = new ErrorSinkCompiler;
|
||||
|
||||
uint errors = global.startGagging();
|
||||
scope(exit) global.endGagging(errors);
|
||||
|
||||
@@ -406,7 +410,7 @@ unittest
|
||||
{
|
||||
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;
|
||||
@@ -416,7 +420,7 @@ unittest
|
||||
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;
|
||||
|
||||
@@ -313,6 +313,8 @@ immutable Msgtable[] msgtable =
|
||||
{ "__ArrayDtor" },
|
||||
{ "_d_delThrowable" },
|
||||
{ "_d_newThrowable" },
|
||||
{ "_d_newclassT" },
|
||||
{ "_d_newclassTTrace" },
|
||||
{ "_d_assert_fail" },
|
||||
{ "dup" },
|
||||
{ "_aaApply" },
|
||||
@@ -455,6 +457,7 @@ immutable Msgtable[] msgtable =
|
||||
{ "isLazy" },
|
||||
{ "hasMember" },
|
||||
{ "identifier" },
|
||||
{ "fullyQualifiedName" },
|
||||
{ "getProtection" },
|
||||
{ "getVisibility" },
|
||||
{ "parent" },
|
||||
|
||||
+149
-103
@@ -135,111 +135,19 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
|
||||
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[]
|
||||
@@ -1514,3 +1422,141 @@ private bool hasNonConstPointers(Expression e)
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
+1
-1
@@ -54,7 +54,7 @@ public:
|
||||
int indentLevel;
|
||||
const(char)[] filename;
|
||||
|
||||
extern (D) this(OutBuffer* buf)
|
||||
extern (D) this(OutBuffer* buf) scope
|
||||
{
|
||||
this.buf = buf;
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ public:
|
||||
OutBuffer buf;
|
||||
alias visit = SemanticTimeTransitiveVisitor.visit;
|
||||
|
||||
this(Scope* sc)
|
||||
this(Scope* sc) scope
|
||||
{
|
||||
this.sc = sc;
|
||||
}
|
||||
|
||||
+79
-74
@@ -22,8 +22,7 @@ import core.stdc.string;
|
||||
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;
|
||||
@@ -69,6 +68,8 @@ class Lexer
|
||||
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
|
||||
@@ -103,12 +104,14 @@ class Lexer
|
||||
* 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);
|
||||
@@ -123,6 +126,8 @@ class Lexer
|
||||
this.tokenizeNewlines = false;
|
||||
this.inTokenStringConstant = 0;
|
||||
this.lastDocLine = 0;
|
||||
this.eSink = errorSink;
|
||||
assert(errorSink);
|
||||
this.versionNumber = versionNumber;
|
||||
this.vendor = vendor;
|
||||
//initKeywords();
|
||||
@@ -163,16 +168,18 @@ class Lexer
|
||||
* 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
|
||||
@@ -565,7 +572,7 @@ class Lexer
|
||||
else if (*t.ptr == '_') // if special identifier token
|
||||
{
|
||||
// Lazy initialization
|
||||
TimeStampInfo.initialize(t.loc);
|
||||
TimeStampInfo.initialize(t.loc, eSink);
|
||||
|
||||
if (id == Id.DATE)
|
||||
{
|
||||
@@ -1616,7 +1623,7 @@ class Lexer
|
||||
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);
|
||||
}
|
||||
@@ -1909,10 +1916,10 @@ class Lexer
|
||||
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)
|
||||
@@ -1927,10 +1934,10 @@ class Lexer
|
||||
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;
|
||||
|
||||
@@ -2137,7 +2144,7 @@ class Lexer
|
||||
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;
|
||||
@@ -2149,7 +2156,7 @@ class Lexer
|
||||
}
|
||||
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;
|
||||
|
||||
@@ -2202,7 +2209,7 @@ class Lexer
|
||||
// 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;
|
||||
@@ -2619,7 +2626,7 @@ class Lexer
|
||||
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
|
||||
{
|
||||
@@ -2647,28 +2654,24 @@ class Lexer
|
||||
return scanloc;
|
||||
}
|
||||
|
||||
final void error(const(char)* format, ...)
|
||||
void error(T...)(const(char)* format, T args)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
.verror(token.loc, format, args);
|
||||
va_end(args);
|
||||
eSink.error(token.loc, format, args);
|
||||
}
|
||||
|
||||
final void error(const ref Loc loc, const(char)* format, ...)
|
||||
void error(T...)(const ref Loc loc, const(char)* format, T args)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
.verror(loc, format, args);
|
||||
va_end(args);
|
||||
eSink.error(loc, format, args);
|
||||
}
|
||||
|
||||
final void deprecation(const(char)* format, ...)
|
||||
final void deprecation(const(char)* format)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
.vdeprecation(token.loc, format, args);
|
||||
va_end(args);
|
||||
eSink.deprecation(token.loc, format);
|
||||
}
|
||||
|
||||
final void deprecationSupplemental(const(char)* format)
|
||||
{
|
||||
eSink.deprecationSupplemental(token.loc, format);
|
||||
}
|
||||
|
||||
/***************************************
|
||||
@@ -2692,7 +2695,7 @@ class Lexer
|
||||
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_)
|
||||
@@ -2853,7 +2856,7 @@ class Lexer
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -3077,7 +3080,7 @@ private struct TimeStampInfo
|
||||
__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;
|
||||
@@ -3088,15 +3091,15 @@ private struct TimeStampInfo
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3217,19 +3220,15 @@ private bool c_isalnum(const int c) pure @nogc @safe
|
||||
|
||||
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__);
|
||||
|
||||
static void test(T)(string sequence, T expected, bool Ccompile = false)
|
||||
ErrorSink errorSink = new ErrorSinkStderr;
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -3266,45 +3265,51 @@ unittest
|
||||
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:
|
||||
|
||||
gotError = true;
|
||||
char[100] buffer = void;
|
||||
auto actual = buffer[0 .. vsprintf(buffer.ptr, format, ap)];
|
||||
assert(expected == actual);
|
||||
return true;
|
||||
import core.stdc.stdio;
|
||||
import core.stdc.stdarg;
|
||||
|
||||
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);
|
||||
@@ -3338,17 +3343,16 @@ unittest
|
||||
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);
|
||||
@@ -3363,9 +3367,10 @@ unittest
|
||||
|
||||
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 =
|
||||
@@ -3383,7 +3388,7 @@ unittest
|
||||
|
||||
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))
|
||||
|
||||
@@ -170,3 +170,5 @@ struct ModuleDeclaration
|
||||
|
||||
const char *toChars() const;
|
||||
};
|
||||
|
||||
extern void getLocalClasses(Module* mod, Array<ClassDeclaration* >& aclasses);
|
||||
|
||||
+168
-22
@@ -456,7 +456,7 @@ extern (C++) abstract class Type : ASTNode
|
||||
return sizeTy;
|
||||
}();
|
||||
|
||||
final extern (D) this(TY ty)
|
||||
final extern (D) this(TY ty) scope
|
||||
{
|
||||
this.ty = ty;
|
||||
}
|
||||
@@ -2046,7 +2046,7 @@ extern (C++) abstract class Type : ASTNode
|
||||
}
|
||||
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;
|
||||
|
||||
@@ -2068,7 +2068,7 @@ extern (C++) abstract class Type : ASTNode
|
||||
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;
|
||||
|
||||
@@ -2447,7 +2447,7 @@ extern (C++) abstract class Type : ASTNode
|
||||
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
|
||||
@@ -3120,7 +3120,7 @@ extern (C++) final class TypeBasic : Type
|
||||
const(char)* dstring;
|
||||
uint flags;
|
||||
|
||||
extern (D) this(TY ty)
|
||||
extern (D) this(TY ty) scope
|
||||
{
|
||||
super(ty);
|
||||
const(char)* d;
|
||||
@@ -4626,14 +4626,14 @@ extern (C++) final class TypeFunction : TypeNext
|
||||
* 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
|
||||
@@ -4669,8 +4669,7 @@ extern (C++) final class TypeFunction : TypeNext
|
||||
}
|
||||
|
||||
const nparams = parameterList.length;
|
||||
const nargs = args.length;
|
||||
if (nargs > nparams)
|
||||
if (argumentList.length > nparams)
|
||||
{
|
||||
if (parameterList.varargs == VarArg.none)
|
||||
{
|
||||
@@ -4684,22 +4683,39 @@ extern (C++) final class TypeFunction : TypeNext
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
@@ -4733,10 +4749,11 @@ extern (C++) final class TypeFunction : TypeNext
|
||||
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)
|
||||
@@ -4745,7 +4762,7 @@ extern (C++) final class TypeFunction : TypeNext
|
||||
/* 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);
|
||||
@@ -4760,7 +4777,7 @@ extern (C++) final class TypeFunction : TypeNext
|
||||
// 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
|
||||
@@ -4773,16 +4790,97 @@ extern (C++) final class TypeFunction : TypeNext
|
||||
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.
|
||||
@@ -4871,9 +4969,18 @@ extern (C++) final class TypeFunction : TypeNext
|
||||
}
|
||||
|
||||
/// Returns: whether `this` function type has the same attributes (`@safe`,...) as `other`
|
||||
bool attributesEqual(const scope TypeFunction other) const pure nothrow @safe @nogc
|
||||
extern (D) bool attributesEqual(const scope TypeFunction other, bool trustSystemEqualsDefault = true) const pure nothrow @safe @nogc
|
||||
{
|
||||
return this.trust == other.trust &&
|
||||
// @@@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 &&
|
||||
@@ -4884,6 +4991,23 @@ extern (C++) final class TypeFunction : TypeNext
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
@@ -6507,6 +6631,28 @@ extern (C++) struct ParameterList
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6975,7 +7121,7 @@ bool isCopyable(Type t)
|
||||
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;
|
||||
}
|
||||
|
||||
+64
-51
@@ -13,11 +13,14 @@
|
||||
|
||||
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;
|
||||
@@ -34,9 +37,10 @@ extern (C++) final class NOGCVisitor : StoppableVisitor
|
||||
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;
|
||||
}
|
||||
@@ -64,6 +68,30 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
@@ -75,24 +103,14 @@ public:
|
||||
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");
|
||||
}
|
||||
}
|
||||
@@ -101,13 +119,8 @@ public:
|
||||
{
|
||||
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");
|
||||
}
|
||||
|
||||
@@ -115,13 +128,8 @@ public:
|
||||
{
|
||||
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");
|
||||
}
|
||||
|
||||
@@ -136,13 +144,9 @@ public:
|
||||
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");
|
||||
}
|
||||
|
||||
@@ -164,13 +168,8 @@ public:
|
||||
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");
|
||||
}
|
||||
}
|
||||
@@ -179,13 +178,8 @@ public:
|
||||
{
|
||||
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");
|
||||
}
|
||||
}
|
||||
@@ -196,6 +190,11 @@ public:
|
||||
* 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;
|
||||
@@ -205,29 +204,43 @@ public:
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
+4
-4
@@ -115,7 +115,7 @@ struct ObNode
|
||||
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;
|
||||
}
|
||||
@@ -1353,7 +1353,7 @@ void genKill(ref ObState obstate, ObNode* ob)
|
||||
|
||||
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;
|
||||
@@ -2058,7 +2058,7 @@ void checkObErrors(ref ObState obstate)
|
||||
|
||||
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;
|
||||
@@ -2569,7 +2569,7 @@ void checkObErrors(ref ObState obstate)
|
||||
{
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+11
-8
@@ -711,7 +711,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
|
||||
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();
|
||||
@@ -720,7 +720,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
|
||||
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();
|
||||
@@ -793,7 +793,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
|
||||
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();
|
||||
@@ -802,7 +802,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
|
||||
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();
|
||||
@@ -1254,7 +1254,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
|
||||
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();
|
||||
@@ -1347,7 +1347,7 @@ private Expression compare_overload(BinExp e, Scope* sc, Identifier id, EXP* pop
|
||||
}
|
||||
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();
|
||||
}
|
||||
@@ -1355,7 +1355,7 @@ private Expression compare_overload(BinExp e, Scope* sc, Identifier id, EXP* pop
|
||||
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();
|
||||
}
|
||||
@@ -1746,7 +1746,10 @@ private FuncDeclaration findBestOpApplyMatch(Expression ethis, FuncDeclaration f
|
||||
|
||||
// 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
|
||||
|
||||
+105
-114
@@ -16,6 +16,7 @@ module dmd.parse;
|
||||
import core.stdc.stdio;
|
||||
import core.stdc.string;
|
||||
import dmd.astenums;
|
||||
import dmd.errorsink;
|
||||
import dmd.globals;
|
||||
import dmd.id;
|
||||
import dmd.identifier;
|
||||
@@ -51,9 +52,11 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
||||
* 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");
|
||||
@@ -64,8 +67,9 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
||||
/* 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;
|
||||
}
|
||||
|
||||
@@ -74,9 +78,10 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
||||
//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");
|
||||
@@ -167,13 +172,13 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
||||
|
||||
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;
|
||||
@@ -286,7 +291,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
||||
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;
|
||||
@@ -799,7 +804,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
||||
{
|
||||
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)
|
||||
{
|
||||
@@ -887,7 +892,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
||||
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));
|
||||
}
|
||||
@@ -1240,7 +1245,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
||||
{
|
||||
// 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
|
||||
@@ -1285,7 +1290,10 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
||||
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)
|
||||
@@ -2170,7 +2178,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -2420,7 +2428,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
||||
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();
|
||||
@@ -2879,43 +2887,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
||||
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_);
|
||||
@@ -3270,7 +3241,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
||||
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();
|
||||
@@ -3283,7 +3254,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
||||
}
|
||||
else
|
||||
{
|
||||
error("{ } expected following `%s` declaration", Token.toChars(tok));
|
||||
error(token.loc, "{ } expected following `%s` declaration", Token.toChars(tok));
|
||||
}
|
||||
|
||||
AST.AggregateDeclaration a;
|
||||
@@ -3670,7 +3641,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
||||
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;
|
||||
@@ -3734,7 +3705,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
||||
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;
|
||||
}
|
||||
@@ -4482,7 +4453,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
||||
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)
|
||||
{
|
||||
@@ -4519,7 +4490,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
||||
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");
|
||||
}
|
||||
@@ -4558,7 +4529,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
||||
continue;
|
||||
|
||||
default:
|
||||
error("semicolon expected to close `alias` declaration");
|
||||
error("semicolon expected to close `alias` declaration, not `%s`", token.toChars());
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -4571,7 +4542,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
||||
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)
|
||||
@@ -4697,12 +4668,12 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
||||
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;
|
||||
}
|
||||
@@ -4720,7 +4691,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
@@ -4940,7 +4911,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4990,7 +4961,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
||||
continue;
|
||||
|
||||
default:
|
||||
error("semicolon expected to close `alias` declaration");
|
||||
error("semicolon expected to close `alias` declaration, not `%s`", token.toChars());
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -5132,7 +5103,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
||||
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();
|
||||
@@ -5157,7 +5128,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
||||
/*****************************************
|
||||
* 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;
|
||||
|
||||
@@ -5329,7 +5300,12 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
||||
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");
|
||||
}
|
||||
@@ -5352,7 +5328,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
||||
{
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5395,7 +5371,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
||||
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());
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
@@ -5450,6 +5426,11 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
||||
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;
|
||||
@@ -5525,7 +5506,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
||||
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;
|
||||
}
|
||||
@@ -5798,7 +5779,7 @@ LagainStc:
|
||||
*/
|
||||
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
|
||||
@@ -6501,7 +6482,7 @@ LagainStc:
|
||||
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;
|
||||
}
|
||||
@@ -7060,7 +7041,7 @@ LagainStc:
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -7330,7 +7311,7 @@ LagainStc:
|
||||
{
|
||||
// This code parallels parseDeclarator()
|
||||
Token* t = *pt;
|
||||
int parens;
|
||||
bool parens;
|
||||
|
||||
//printf("Parser::isDeclarator() %s\n", t.toChars());
|
||||
if (t.value == TOK.assign)
|
||||
@@ -7625,24 +7606,6 @@ LagainStc:
|
||||
}
|
||||
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))
|
||||
@@ -8144,12 +8107,12 @@ LagainStc:
|
||||
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());
|
||||
|
||||
@@ -8280,7 +8243,7 @@ LagainStc:
|
||||
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);
|
||||
@@ -8425,7 +8388,7 @@ LagainStc:
|
||||
// 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;
|
||||
@@ -8488,7 +8451,7 @@ LagainStc:
|
||||
// ( expression )
|
||||
nextToken();
|
||||
e = parseExpression();
|
||||
e.parens = 1;
|
||||
e.parens = true;
|
||||
check(loc, TOK.rightParenthesis);
|
||||
break;
|
||||
}
|
||||
@@ -8758,14 +8721,6 @@ LagainStc:
|
||||
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_:
|
||||
@@ -8907,7 +8862,10 @@ LagainStc:
|
||||
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:
|
||||
@@ -9342,26 +9300,52 @@ LagainStc:
|
||||
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;
|
||||
}
|
||||
|
||||
/*******************************************
|
||||
@@ -9372,13 +9356,18 @@ LagainStc:
|
||||
|
||||
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)
|
||||
@@ -9420,10 +9409,12 @@ LagainStc:
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
+10
-1
@@ -14,6 +14,7 @@ module dmd.printast;
|
||||
import core.stdc.stdio;
|
||||
|
||||
import dmd.expression;
|
||||
import dmd.ctfeexpr;
|
||||
import dmd.tokens;
|
||||
import dmd.visitor;
|
||||
import dmd.hdrgen;
|
||||
@@ -38,7 +39,7 @@ extern (C++) final class PrintASTVisitor : Visitor
|
||||
|
||||
int indent;
|
||||
|
||||
extern (D) this(int indent)
|
||||
extern (D) this(int indent) scope
|
||||
{
|
||||
this.indent = indent;
|
||||
}
|
||||
@@ -210,6 +211,14 @@ extern (C++) final class PrintASTVisitor : Visitor
|
||||
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)
|
||||
|
||||
@@ -149,7 +149,7 @@ private struct AARange(K,V)
|
||||
size_t bIndex;
|
||||
aaA* current;
|
||||
|
||||
this(AA* aa) pure nothrow @nogc
|
||||
this(AA* aa) pure nothrow @nogc scope
|
||||
{
|
||||
if (aa)
|
||||
{
|
||||
|
||||
+26
-2
@@ -41,7 +41,7 @@ public:
|
||||
* Params:
|
||||
* dim = initial length of array
|
||||
*/
|
||||
this(size_t dim) pure nothrow
|
||||
this(size_t dim) pure nothrow scope
|
||||
{
|
||||
reserve(dim);
|
||||
this.length = dim;
|
||||
@@ -69,7 +69,18 @@ public:
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -381,6 +392,19 @@ unittest
|
||||
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
|
||||
|
||||
@@ -50,7 +50,7 @@ extern (C++) struct CTFloat
|
||||
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;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "dcompat.h"
|
||||
#include "longdouble.h"
|
||||
|
||||
// Type used by the front-end for compile-time reals
|
||||
@@ -51,7 +52,7 @@ struct CTFloat
|
||||
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);
|
||||
|
||||
|
||||
@@ -85,6 +85,12 @@ nothrow:
|
||||
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
|
||||
{
|
||||
|
||||
@@ -19,6 +19,7 @@ struct FileName
|
||||
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);
|
||||
|
||||
@@ -38,7 +38,7 @@ enum DYNCAST : int
|
||||
|
||||
extern (C++) class RootObject
|
||||
{
|
||||
this() nothrow pure @nogc @safe
|
||||
this() nothrow pure @nogc @safe scope
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ private extern (C++) final class PostorderStatementVisitor : StoppableVisitor
|
||||
public:
|
||||
StoppableVisitor v;
|
||||
|
||||
extern (D) this(StoppableVisitor v)
|
||||
extern (D) this(StoppableVisitor v) scope
|
||||
{
|
||||
this.v = v;
|
||||
}
|
||||
|
||||
+20
-4
@@ -83,7 +83,7 @@ private extern(C++) final class Semantic2Visitor : Visitor
|
||||
{
|
||||
alias visit = Visitor.visit;
|
||||
Scope* sc;
|
||||
this(Scope* sc)
|
||||
this(Scope* sc) scope
|
||||
{
|
||||
this.sc = sc;
|
||||
}
|
||||
@@ -248,9 +248,9 @@ private extern(C++) final class Semantic2Visitor : Visitor
|
||||
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;
|
||||
}
|
||||
@@ -439,7 +439,11 @@ private extern(C++) final class Semantic2Visitor : Visitor
|
||||
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
|
||||
@@ -462,7 +466,19 @@ private extern(C++) final class Semantic2Visitor : Visitor
|
||||
|
||||
// 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(),
|
||||
|
||||
@@ -88,7 +88,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
|
||||
alias visit = Visitor.visit;
|
||||
|
||||
Scope* sc;
|
||||
this(Scope* sc)
|
||||
this(Scope* sc) scope
|
||||
{
|
||||
this.sc = sc;
|
||||
}
|
||||
@@ -342,7 +342,6 @@ private extern(C++) final class Semantic3Visitor : Visitor
|
||||
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;
|
||||
@@ -712,7 +711,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
|
||||
|
||||
// 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");
|
||||
@@ -1600,7 +1599,7 @@ private struct FuncDeclSem3
|
||||
|
||||
// Scope of analysis
|
||||
Scope* sc;
|
||||
this(FuncDeclaration fd,Scope* s)
|
||||
this(FuncDeclaration fd,Scope* s) scope
|
||||
{
|
||||
funcdecl = fd;
|
||||
sc = s;
|
||||
|
||||
@@ -37,7 +37,7 @@ extern (C++) bool isTrivialExp(Expression e)
|
||||
{
|
||||
alias visit = typeof(super).visit;
|
||||
public:
|
||||
extern (D) this()
|
||||
extern (D) this() scope
|
||||
{
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ extern (C++) bool hasSideEffect(Expression e, bool assumeImpureCalls = false)
|
||||
{
|
||||
alias visit = typeof(super).visit;
|
||||
public:
|
||||
extern (D) this()
|
||||
extern (D) this() scope
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -1061,6 +1061,16 @@ extern (C++) final class IfStatement : Statement
|
||||
{
|
||||
v.visit(this);
|
||||
}
|
||||
|
||||
/******
|
||||
* Returns: true if `if (__ctfe)`
|
||||
*/
|
||||
bool isIfCtfeBlock()
|
||||
{
|
||||
if (auto cv = condition.isVarExp())
|
||||
return cv.var.ident == Id.ctfe;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
@@ -1762,6 +1772,7 @@ extern (C++) final class GotoStatement : Statement
|
||||
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)
|
||||
{
|
||||
@@ -1804,6 +1815,12 @@ extern (C++) final class GotoStatement : Statement
|
||||
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)
|
||||
{
|
||||
@@ -1870,6 +1887,7 @@ extern (C++) final class LabelStatement : Statement
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -381,6 +381,7 @@ public:
|
||||
IfStatement *syntaxCopy() override;
|
||||
|
||||
void accept(Visitor *v) override { v->visit(this); }
|
||||
bool isIfCtfeBlock();
|
||||
};
|
||||
|
||||
class ConditionalStatement final : public Statement
|
||||
@@ -667,7 +668,7 @@ public:
|
||||
TryFinallyStatement *tf;
|
||||
ScopeGuardStatement *os;
|
||||
VarDeclaration *lastVar;
|
||||
|
||||
bool inCtfeBlock;
|
||||
GotoStatement *syntaxCopy() override;
|
||||
|
||||
void accept(Visitor *v) override { v->visit(this); }
|
||||
@@ -685,7 +686,7 @@ public:
|
||||
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); }
|
||||
|
||||
@@ -39,6 +39,7 @@ import dmd.dsymbol;
|
||||
import dmd.dsymbolsem;
|
||||
import dmd.dtemplate;
|
||||
import dmd.errors;
|
||||
import dmd.errorsink;
|
||||
import dmd.escape;
|
||||
import dmd.expression;
|
||||
import dmd.expressionsem;
|
||||
@@ -160,7 +161,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
|
||||
Statement result;
|
||||
Scope* sc;
|
||||
|
||||
this(Scope* sc)
|
||||
this(Scope* sc) scope
|
||||
{
|
||||
this.sc = sc;
|
||||
}
|
||||
@@ -1276,7 +1277,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
|
||||
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())
|
||||
@@ -1491,7 +1492,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
|
||||
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;
|
||||
@@ -1955,7 +1956,17 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
|
||||
// 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
|
||||
@@ -2222,7 +2233,9 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
|
||||
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)
|
||||
{
|
||||
@@ -2256,7 +2269,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@@ -2485,7 +2498,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -3798,6 +3811,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
|
||||
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)
|
||||
{
|
||||
@@ -3837,6 +3851,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
|
||||
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)
|
||||
@@ -4730,7 +4745,7 @@ private Statements* flatten(Statement statement, Scope* sc)
|
||||
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();
|
||||
|
||||
+16
-1
@@ -46,6 +46,21 @@ struct TemplatePrevious
|
||||
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:
|
||||
@@ -81,7 +96,7 @@ 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; }
|
||||
|
||||
@@ -50,7 +50,7 @@ private extern (C++) final class TemplateParameterSemanticVisitor : Visitor
|
||||
TemplateParameters* parameters;
|
||||
bool result;
|
||||
|
||||
this(Scope* sc, TemplateParameters* parameters)
|
||||
this(Scope* sc, TemplateParameters* parameters) scope
|
||||
{
|
||||
this.sc = sc;
|
||||
this.parameters = parameters;
|
||||
|
||||
+27
-18
@@ -269,11 +269,13 @@ enum TOK : ubyte
|
||||
_Thread_local,
|
||||
|
||||
// C only extended keywords
|
||||
_assert,
|
||||
_import,
|
||||
__cdecl,
|
||||
__declspec,
|
||||
__stdcall,
|
||||
__pragma,
|
||||
__int128,
|
||||
__attribute__,
|
||||
}
|
||||
|
||||
@@ -579,11 +581,13 @@ private immutable TOK[] keywords =
|
||||
TOK._Thread_local,
|
||||
|
||||
// C only extended keywords
|
||||
TOK._assert,
|
||||
TOK._import,
|
||||
TOK.__cdecl,
|
||||
TOK.__declspec,
|
||||
TOK.__stdcall,
|
||||
TOK.__pragma,
|
||||
TOK.__int128,
|
||||
TOK.__attribute__,
|
||||
];
|
||||
|
||||
@@ -612,7 +616,9 @@ static immutable TOK[TOK.max + 1] Ckeywords =
|
||||
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;
|
||||
@@ -878,11 +884,13 @@ extern (C++) struct Token
|
||||
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__",
|
||||
];
|
||||
|
||||
@@ -942,16 +950,17 @@ nothrow:
|
||||
|
||||
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:
|
||||
@@ -960,36 +969,36 @@ nothrow:
|
||||
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_:
|
||||
@@ -1006,7 +1015,7 @@ nothrow:
|
||||
if (postfix)
|
||||
buf.writeByte(postfix);
|
||||
buf.writeByte(0);
|
||||
p = buf.extractSlice().ptr;
|
||||
p = buf.extractChars();
|
||||
}
|
||||
break;
|
||||
case TOK.identifier:
|
||||
@@ -1116,7 +1125,7 @@ unittest
|
||||
{
|
||||
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`);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1147,11 +1156,11 @@ unittest
|
||||
{
|
||||
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'`);
|
||||
}
|
||||
|
||||
@@ -278,11 +278,13 @@ enum class TOK : unsigned char
|
||||
_Thread_local_,
|
||||
|
||||
// C only extended keywords
|
||||
_assert,
|
||||
_import,
|
||||
cdecl_,
|
||||
declspec,
|
||||
stdcall,
|
||||
pragma,
|
||||
int128_,
|
||||
attribute__,
|
||||
|
||||
MAX,
|
||||
|
||||
+51
-3
@@ -122,7 +122,7 @@ ulong getTypePointerBitmap(Loc loc, Type t, Array!(ulong)* data)
|
||||
{
|
||||
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;
|
||||
@@ -634,6 +634,10 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
|
||||
}
|
||||
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);
|
||||
|
||||
@@ -739,6 +743,42 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
|
||||
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)
|
||||
@@ -995,6 +1035,13 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
|
||||
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();
|
||||
@@ -1676,7 +1723,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
|
||||
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;
|
||||
@@ -2197,7 +2244,7 @@ private void traitNotFound(TraitsExp e)
|
||||
initialized = true; // lazy initialization
|
||||
|
||||
// All possible traits
|
||||
__gshared Identifier*[58] idents =
|
||||
__gshared Identifier*[59] idents =
|
||||
[
|
||||
&Id.isAbstractClass,
|
||||
&Id.isArithmetic,
|
||||
@@ -2227,6 +2274,7 @@ private void traitNotFound(TraitsExp e)
|
||||
&Id.isReturnOnStack,
|
||||
&Id.hasMember,
|
||||
&Id.identifier,
|
||||
&Id.fullyQualifiedName,
|
||||
&Id.getProtection,
|
||||
&Id.getVisibility,
|
||||
&Id.parent,
|
||||
|
||||
+16
-71
@@ -35,6 +35,7 @@ import dmd.dsymbol;
|
||||
import dmd.dsymbolsem;
|
||||
import dmd.dtemplate;
|
||||
import dmd.errors;
|
||||
import dmd.errorsink;
|
||||
import dmd.expression;
|
||||
import dmd.expressionsem;
|
||||
import dmd.func;
|
||||
@@ -285,54 +286,10 @@ private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -580,6 +537,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
|
||||
{
|
||||
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();
|
||||
|
||||
@@ -636,7 +594,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
@@ -1285,20 +1243,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
|
||||
|
||||
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'
|
||||
@@ -1389,7 +1334,6 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
|
||||
// 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
|
||||
@@ -1398,7 +1342,6 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
|
||||
// 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);
|
||||
@@ -1425,11 +1368,6 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
|
||||
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.
|
||||
@@ -3912,8 +3850,15 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
|
||||
{
|
||||
/* 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);
|
||||
@@ -4973,7 +4918,7 @@ RootObject compileTypeMixin(TypeMixin tm, Loc loc, Scope* 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);
|
||||
|
||||
|
||||
+2
-1
@@ -105,10 +105,11 @@ extern (C++) void genTypeInfo(Expression e, const ref Loc loc, Type torig, Scope
|
||||
* 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)
|
||||
{
|
||||
|
||||
+1
-1
@@ -248,7 +248,7 @@ extern (C++) class StoppableVisitor : Visitor
|
||||
public:
|
||||
bool stop;
|
||||
|
||||
final extern (D) this()
|
||||
final extern (D) this() scope
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -2277,8 +2277,7 @@ public:
|
||||
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. */
|
||||
|
||||
@@ -360,10 +360,6 @@ fpreview=dip1021
|
||||
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.
|
||||
@@ -412,10 +408,6 @@ frevert=dip1000
|
||||
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.
|
||||
|
||||
+2
-10
@@ -530,11 +530,7 @@ layout_moduleinfo_fields (Module *decl, tree type)
|
||||
|
||||
/* 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)
|
||||
{
|
||||
@@ -564,11 +560,7 @@ layout_moduleinfo (Module *decl)
|
||||
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++)
|
||||
|
||||
@@ -59,9 +59,6 @@ DEF_D_RUNTIME (ARRAYBOUNDS_SLICEP, "_d_arraybounds_slicep", RT(VOID),
|
||||
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),
|
||||
|
||||
+3
-2
@@ -582,8 +582,9 @@ public:
|
||||
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);
|
||||
|
||||
+5
-3
@@ -1524,10 +1524,12 @@ get_cpp_typeinfo_decl (ClassDeclaration *decl)
|
||||
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 ();
|
||||
@@ -1685,7 +1687,7 @@ create_typeinfo (Type *type, Module *mod)
|
||||
|
||||
/* 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)
|
||||
|
||||
+2
-2
@@ -381,9 +381,9 @@ layout_aggregate_members (Dsymbols *members, tree context, bool inherited_p)
|
||||
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. */
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
// 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;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// 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
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// 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);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// 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);
|
||||
@@ -1,5 +1,5 @@
|
||||
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();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
struct BugInt
|
||||
{
|
||||
uint[] data = ZEROX;
|
||||
uint[] data = ZEROX;
|
||||
}
|
||||
enum uint [] ZEROX = [0];
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
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; });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
interface Timeline {
|
||||
}
|
||||
|
||||
struct Policy {
|
||||
alias OldTagCallback = void delegate() @nogc nothrow;
|
||||
Timeline timeline;
|
||||
OldTagCallback oldTagCB;
|
||||
}
|
||||
|
||||
import test23626;
|
||||
|
||||
struct Tiering {
|
||||
StaticHashTable!(Policy) policies;
|
||||
}
|
||||
@@ -14,11 +14,6 @@ class Foo
|
||||
{
|
||||
auto dg = &f;
|
||||
}
|
||||
|
||||
foreach (f; __traits(getVirtualFunctions, typeof(this), "bar"))
|
||||
{
|
||||
auto dg = &f;
|
||||
}
|
||||
}
|
||||
|
||||
uint bar() { return 0; }
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user