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:
Iain Buclaw
2023-03-05 01:47:19 +01:00
parent c5e2c3dd6a
commit 8da8c7d337
313 changed files with 6503 additions and 2920 deletions
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
-14
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -1 +1 @@
v2.102.0-beta.1
v2.103.0-beta.1
-1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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); }
};
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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
View File
@@ -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.
+19 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
*/
+1 -1
View File
@@ -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
View File
@@ -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);
+2
View File
@@ -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());
-6
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+2 -2
View File
@@ -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;
}
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 = &pr; // 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
View File
@@ -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;
}
+52
View File
@@ -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
*/
+121
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+9 -2
View File
@@ -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
View File
@@ -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());
}
}
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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)
{
+3
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+3
View File
@@ -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
View File
@@ -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
View File
@@ -54,7 +54,7 @@ public:
int indentLevel;
const(char)[] filename;
extern (D) this(OutBuffer* buf)
extern (D) this(OutBuffer* buf) scope
{
this.buf = buf;
}
+1 -1
View File
@@ -120,7 +120,7 @@ public:
OutBuffer buf;
alias visit = SemanticTimeTransitiveVisitor.visit;
this(Scope* sc)
this(Scope* sc) scope
{
this.sc = sc;
}
+79 -74
View File
@@ -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(&timestamp[0], "%.24s", p);
snprintf(&date[0], date.length, "%.6s %.4s", p + 4, p + 20);
snprintf(&time[0], time.length, "%.8s", p + 11);
snprintf(&timestamp[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(`&quot;`, '"');
test(`&lt;`, '<');
test(`&gt;`, '>');
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("&quot", `unterminated named entity &quot;`, '?', 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))
+2
View File
@@ -170,3 +170,5 @@ struct ModuleDeclaration
const char *toChars() const;
};
extern void getLocalClasses(Module* mod, Array<ClassDeclaration* >& aclasses);
+168 -22
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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)
+1 -1
View File
@@ -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
View File
@@ -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
+1 -1
View File
@@ -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;
+2 -1
View File
@@ -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);
+6
View File
@@ -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
{
+1
View File
@@ -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);
+1 -1
View File
@@ -38,7 +38,7 @@ enum DYNCAST : int
extern (C++) class RootObject
{
this() nothrow pure @nogc @safe
this() nothrow pure @nogc @safe scope
{
}
+1 -1
View File
@@ -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
View File
@@ -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(),
+3 -4
View File
@@ -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;
+2 -2
View File
@@ -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
{
}
+18
View File
@@ -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)
{
+3 -2
View File
@@ -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); }
+23 -8
View File
@@ -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
View File
@@ -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; }
+1 -1
View File
@@ -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
View File
@@ -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'`);
}
+2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -248,7 +248,7 @@ extern (C++) class StoppableVisitor : Visitor
public:
bool stop;
final extern (D) this()
final extern (D) this() scope
{
}
}
+1 -2
View File
@@ -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. */
-8
View File
@@ -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
View File
@@ -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++)
-3
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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. */
+16
View File
@@ -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;
}
+11
View File
@@ -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
}
+15
View File
@@ -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