d: Merge upstream dmd cb49e99f8, druntime 55528bd1, phobos 1a3e80ec2.

D front-end changes:

    - Import dmd v2.099.0-beta.1.
    - It's now an error to use `alias this' for partial assignment.
    - The `delete' keyword has been removed from the language.
    - Using `this' and `super' as types has been removed from the
      language, the parser no longer specially handles this wrong code
      with an informative error.

D Runtime changes:

    - Import druntime v2.099.0-beta.1.

Phobos changes:

    - Import phobos v2.099.0-beta.1.

gcc/d/ChangeLog:

	* dmd/MERGE: Merge upstream dmd cb49e99f8.
	* dmd/VERSION: Update version to v2.099.0-beta.1.
	* decl.cc (layout_class_initializer): Update call to NewExp::create.
	* expr.cc (ExprVisitor::visit (DeleteExp *)): Remove handling of
	deleting arrays and pointers.
	(ExprVisitor::visit (DotVarExp *)): Convert complex types to the
	front-end library type representing them.
	(ExprVisitor::visit (StringExp *)): Use getCodeUnit instead of charAt
	to get the value of each index in a string expression.
	* runtime.def (DELMEMORY): Remove.
	(DELARRAYT): Remove.
	* types.cc (TypeVisitor::visit (TypeEnum *)): Handle anonymous enums.

libphobos/ChangeLog:

	* libdruntime/MERGE: Merge upstream druntime 55528bd1.
	* src/MERGE: Merge upstream phobos 1a3e80ec2.
	* testsuite/libphobos.hash/test_hash.d: Update.
	* testsuite/libphobos.betterc/test19933.d: New test.
This commit is contained in:
Iain Buclaw 2022-02-20 20:02:23 +01:00
parent e49508ac6b
commit 6384eff56d
245 changed files with 5807 additions and 5205 deletions

View File

@ -2235,7 +2235,7 @@ aggregate_initializer_decl (AggregateDeclaration *decl)
tree
layout_class_initializer (ClassDeclaration *cd)
{
NewExp *ne = NewExp::create (cd->loc, NULL, NULL, cd->type, NULL);
NewExp *ne = NewExp::create (cd->loc, NULL, cd->type, NULL);
ne->type = cd->type;
Expression *e = ne->ctfeInterpret ();

View File

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

View File

@ -1 +1 @@
v2.098.1
v2.099.0-beta.1

View File

@ -110,13 +110,13 @@ public:
override void visit(NewExp e)
{
//printf("NewExp::apply(): %s\n", toChars());
doCond(e.thisexp) || doCond(e.newargs) || doCond(e.arguments) || applyTo(e);
doCond(e.thisexp) || doCond(e.arguments) || applyTo(e);
}
override void visit(NewAnonClassExp e)
{
//printf("NewAnonClassExp::apply(): %s\n", toChars());
doCond(e.thisexp) || doCond(e.newargs) || doCond(e.arguments) || applyTo(e);
doCond(e.thisexp) || doCond(e.arguments) || applyTo(e);
}
override void visit(TypeidExp e)

View File

@ -114,9 +114,7 @@ extern (C++) /* CT */ BE canThrow(Expression e, FuncDeclaration func, bool mustN
import dmd.id : Id;
auto sd = ts.sym;
if (sd.dtor && ce.f.ident == Id._d_delstruct)
checkFuncThrows(ce, sd.dtor);
else if (sd.postblit &&
if (sd.postblit &&
(ce.f.ident == Id._d_arrayctor || ce.f.ident == Id._d_arraysetctor))
{
checkFuncThrows(ce, sd.postblit);
@ -175,14 +173,6 @@ extern (C++) /* CT */ BE canThrow(Expression e, FuncDeclaration func, bool mustN
ad = tb.isTypeClass().sym;
break;
case Tpointer:
case Tarray:
auto ts = tb.nextOf().baseElemOf().isTypeStruct();
if (!ts)
return;
ad = ts.sym;
break;
default:
assert(0); // error should have been detected by semantic()
}

View File

@ -521,9 +521,9 @@ FuncDeclaration buildOpEquals(StructDeclaration sd, Scope* sc)
/******************************************
* Build __xopEquals for TypeInfo_Struct
* static bool __xopEquals(ref const S p, ref const S q)
* bool __xopEquals(ref const S p) const
* {
* return p == q;
* return this == p;
* }
*
* This is called by TypeInfo.equals(p1, p2). If the struct does not support
@ -570,14 +570,15 @@ FuncDeclaration buildXopEquals(StructDeclaration sd, Scope* sc)
Loc declLoc; // loc is unnecessary so __xopEquals is never called directly
Loc loc; // loc is unnecessary so errors are gagged
auto parameters = new Parameters();
parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.p, null, null))
.push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.q, null, null));
auto tf = new TypeFunction(ParameterList(parameters), Type.tbool, LINK.d);
parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.p, null, null));
auto tf = new TypeFunction(ParameterList(parameters), Type.tbool, LINK.d, STC.const_);
tf = tf.addSTC(STC.const_).toTypeFunction();
Identifier id = Id.xopEquals;
auto fop = new FuncDeclaration(declLoc, Loc.initial, id, STC.static_, tf);
auto fop = new FuncDeclaration(declLoc, Loc.initial, id, 0, tf);
fop.generated = true;
Expression e1 = new IdentifierExp(loc, Id.p);
Expression e2 = new IdentifierExp(loc, Id.q);
fop.parent = sd;
Expression e1 = new IdentifierExp(loc, Id.This);
Expression e2 = new IdentifierExp(loc, Id.p);
Expression e = new EqualExp(EXP.equal, loc, e1, e2);
fop.fbody = new ReturnStatement(loc, e);
uint errors = global.startGagging(); // Do not report errors
@ -594,9 +595,9 @@ FuncDeclaration buildXopEquals(StructDeclaration sd, Scope* sc)
/******************************************
* Build __xopCmp for TypeInfo_Struct
* static bool __xopCmp(ref const S p, ref const S q)
* int __xopCmp(ref const S p) const
* {
* return p.opCmp(q);
* return this.opCmp(p);
* }
*
* This is called by TypeInfo.compare(p1, p2). If the struct does not support
@ -691,17 +692,15 @@ FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc)
Loc loc; // loc is unnecessary so errors are gagged
auto parameters = new Parameters();
parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.p, null, null));
parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.q, null, null));
auto tf = new TypeFunction(ParameterList(parameters), Type.tint32, LINK.d);
auto tf = new TypeFunction(ParameterList(parameters), Type.tint32, LINK.d, STC.const_);
tf = tf.addSTC(STC.const_).toTypeFunction();
Identifier id = Id.xopCmp;
auto fop = new FuncDeclaration(declLoc, Loc.initial, id, STC.static_, tf);
auto fop = new FuncDeclaration(declLoc, Loc.initial, id, 0, tf);
fop.generated = true;
Expression e1 = new IdentifierExp(loc, Id.p);
Expression e2 = new IdentifierExp(loc, Id.q);
version (IN_GCC)
Expression e = new CallExp(loc, new DotIdExp(loc, e1, Id.cmp), e2);
else
Expression e = new CallExp(loc, new DotIdExp(loc, e2, Id.cmp), e1);
fop.parent = sd;
Expression e1 = new IdentifierExp(loc, Id.This);
Expression e2 = new IdentifierExp(loc, Id.p);
Expression e = new CallExp(loc, new DotIdExp(loc, e1, Id.cmp), e2);
fop.fbody = new ReturnStatement(loc, e);
uint errors = global.startGagging(); // Do not report errors
Scope* sc2 = sc.push();

View File

@ -827,9 +827,9 @@ UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e
else
{
cmp = 1; // if dim1 winds up being 0
for (size_t i = 0; i < dim1; i++)
foreach (i; 0 .. dim1)
{
uinteger_t c = es1.charAt(i);
uinteger_t c = es1.getCodeUnit(i);
auto ee2 = es2[i];
if (ee2.isConst() != 1)
{
@ -1247,7 +1247,7 @@ UnionExp Index(Type type, Expression e1, Expression e2)
}
else
{
emplaceExp!(IntegerExp)(&ue, loc, es1.charAt(i), type);
emplaceExp!(IntegerExp)(&ue, loc, es1.getCodeUnit(cast(size_t) i), type);
}
}
else if (e1.type.toBasetype().ty == Tsarray && e2.op == EXP.int64)

View File

@ -197,6 +197,7 @@ final class CParser(AST) : Parser!AST
}
break;
case TOK.charLiteral:
case TOK.int32Literal:
case TOK.uns32Literal:
case TOK.int64Literal:
@ -264,6 +265,7 @@ final class CParser(AST) : Parser!AST
case TOK.const_:
case TOK.volatile:
case TOK.restrict:
case TOK.__stdcall:
// alignment-specifier
case TOK._Alignas:
@ -635,6 +637,7 @@ final class CParser(AST) : Parser!AST
nextToken();
break;
case TOK.charLiteral:
case TOK.int32Literal:
e = new AST.IntegerExp(loc, token.intvalue, AST.Type.tint32);
nextToken();
@ -1585,7 +1588,7 @@ final class CParser(AST) : Parser!AST
if (tspec && specifier.mod & MOD.xconst)
{
tspec = toConst(tspec);
specifier.mod = MOD.xnone; // 'used' it
specifier.mod &= ~MOD.xnone; // 'used' it
}
bool first = true;
@ -1708,7 +1711,7 @@ final class CParser(AST) : Parser!AST
symbols.push(stag);
if (tt.tok == TOK.enum_)
{
if (!tt.members)
if (!stag.members)
error(tt.loc, "`enum %s` has no members", stag.toChars());
isalias = false;
s = new AST.AliasDeclaration(token.loc, id, stag);
@ -1842,8 +1845,8 @@ final class CParser(AST) : Parser!AST
/* Since there were declarations, the parameter-list must have been
* an identifier-list.
*/
ft.parameterList.hasIdentifierList = true; // semantic needs to know to adjust parameter types
auto pl = ft.parameterList;
pl.hasIdentifierList = true; // semantic needs to know to adjust parameter types
if (pl.varargs != AST.VarArg.none && pl.length)
error("function identifier-list cannot end with `...`");
ft.parameterList.varargs = AST.VarArg.variadic; // but C11 allows extra arguments
@ -2071,6 +2074,7 @@ final class CParser(AST) : Parser!AST
case TOK.const_: modx = MOD.xconst; break;
case TOK.volatile: modx = MOD.xvolatile; break;
case TOK.restrict: modx = MOD.xrestrict; break;
case TOK.__stdcall: modx = MOD.x__stdcall; break;
// Type specifiers
case TOK.char_: tkwx = TKW.xchar; break;
@ -2409,6 +2413,13 @@ final class CParser(AST) : Parser!AST
* T ((*fp))();
*/
nextToken();
if (token.value == TOK.__stdcall) // T (__stdcall*fp)();
{
specifier.mod |= MOD.x__stdcall;
nextToken();
}
ts = parseDecl(t);
check(TOK.rightParenthesis);
break;
@ -2544,7 +2555,8 @@ final class CParser(AST) : Parser!AST
this.symbols = null;
auto parameterList = cparseParameterList();
AST.Type tf = new AST.TypeFunction(parameterList, t, linkage, 0);
const lkg = specifier.mod & MOD.x__stdcall ? LINK.windows : linkage;
AST.Type tf = new AST.TypeFunction(parameterList, t, lkg, 0);
// tf = tf.addSTC(storageClass); // TODO
insertTx(ts, tf, t); // ts -> ... -> tf -> t
@ -2612,6 +2624,7 @@ final class CParser(AST) : Parser!AST
* restrict
* volatile
* _Atomic
* __stdcall
*/
MOD cparseTypeQualifierList()
{
@ -2624,6 +2637,7 @@ final class CParser(AST) : Parser!AST
case TOK.volatile: mod |= MOD.xvolatile; break;
case TOK.restrict: mod |= MOD.xrestrict; break;
case TOK._Atomic: mod |= MOD.x_Atomic; break;
case TOK.__stdcall: mod |= MOD.x__stdcall; break;
default:
return mod;
@ -3708,6 +3722,7 @@ final class CParser(AST) : Parser!AST
case TOK.const_:
case TOK.volatile:
case TOK.restrict:
case TOK.__stdcall:
t = peek(t);
any = true;
continue;
@ -3948,6 +3963,7 @@ final class CParser(AST) : Parser!AST
case TOK.restrict:
case TOK.volatile:
case TOK._Atomic:
case TOK.__stdcall:
t = peek(t);
continue;
@ -4000,6 +4016,7 @@ final class CParser(AST) : Parser!AST
case TOK.const_:
case TOK.restrict:
case TOK.volatile:
case TOK.__stdcall:
// Type Specifiers
case TOK.char_:
@ -4202,6 +4219,7 @@ final class CParser(AST) : Parser!AST
switch (t.value)
{
case TOK.identifier:
case TOK.charLiteral:
case TOK.int32Literal:
case TOK.uns32Literal:
case TOK.int64Literal:
@ -4283,6 +4301,7 @@ final class CParser(AST) : Parser!AST
xvolatile = 2,
xrestrict = 4,
x_Atomic = 8,
x__stdcall = 0x10, // Windows linkage extension
}
/**********************************

View File

@ -1565,7 +1565,7 @@ Expression ctfeIndex(UnionExp* pue, const ref Loc loc, Type type, Expression e1,
error(loc, "string index %llu is out of bounds `[0 .. %llu]`", indx, cast(ulong)es1.len);
return CTFEExp.cantexp;
}
emplaceExp!IntegerExp(pue, loc, es1.charAt(indx), type);
emplaceExp!IntegerExp(pue, loc, es1.getCodeUnit(cast(size_t) indx), type);
return pue.exp();
}

File diff suppressed because it is too large Load Diff

View File

@ -1064,9 +1064,8 @@ extern (C++) class VarDeclaration : Declaration
// Both these mean the var is not rebindable once assigned,
// and the destructor gets run when it goes out of scope
bool onstack; // it is a class that was allocated on the stack
bool mynew; // it is a class new'd with custom operator new
byte canassign; // it can be assigned to
byte canassign; // it can be assigned to
bool overlapped; // if it is a field and has overlapping
bool overlapUnsafe; // if it is an overlapping field and the overlaps are unsafe
bool doNotInferScope; // do not infer 'scope' for this variable
@ -1452,7 +1451,7 @@ extern (C++) class VarDeclaration : Declaration
//if (cd.isInterfaceDeclaration())
// error("interface `%s` cannot be scope", cd.toChars());
if (mynew || onstack) // if any destructors
if (onstack) // if any destructors
{
// delete'ing C++ classes crashes (and delete is deprecated anyway)
if (cd.classKind == ClassKind.cpp)

View File

@ -248,7 +248,6 @@ public:
bool isowner; // this is an Owner, despite it being `scope`
bool setInCtorOnly; // field can only be set in a constructor, as it is const or immutable
bool onstack; // it is a class that was allocated on the stack
bool mynew; // it is a class new'd with custom operator new
char canassign; // it can be assigned to
bool overlapped; // if it is a field and has overlapping
bool overlapUnsafe; // if it is an overlapping field and the overlaps are unsafe

View File

@ -3820,6 +3820,21 @@ public:
payload = &(*sle.elements)[fieldi];
oldval = *payload;
if (auto ival = newval.isIntegerExp())
{
if (auto bf = v.isBitFieldDeclaration())
{
sinteger_t value = ival.toInteger();
if (bf.type.isunsigned())
value &= (1L << bf.fieldWidth) - 1; // zero extra bits
else
{ // sign extend extra bits
value = value << (64 - bf.fieldWidth);
value = value >> (64 - bf.fieldWidth);
}
ival.setInteger(value);
}
}
}
else if (auto ie = e1.isIndexExp())
{
@ -4851,47 +4866,6 @@ public:
result = interpret(ce, istate);
return;
}
else if (fd.ident == Id._d_delstruct)
{
// Only interpret the dtor and the argument.
assert(e.arguments.dim == 1);
Type tb = (*e.arguments)[0].type.toBasetype();
auto ts = tb.nextOf().baseElemOf().isTypeStruct();
if (ts)
{
result = interpretRegion((*e.arguments)[0], istate);
if (exceptionOrCant(result))
return;
if (result.op == EXP.null_)
{
result = CTFEExp.voidexp;
return;
}
if (result.op != EXP.address ||
(cast(AddrExp)result).e1.op != EXP.structLiteral)
{
e.error("`delete` on invalid struct pointer `%s`", result.toChars());
result = CTFEExp.cantexp;
return;
}
auto sd = ts.sym;
if (sd.dtor)
{
auto sle = cast(StructLiteralExp)(cast(AddrExp)result).e1;
result = interpretFunction(pue, sd.dtor, istate, null, sle);
if (exceptionOrCant(result))
return;
result = CTFEExp.voidexp;
}
}
return;
}
}
else if (auto soe = ecall.isSymOffExp())
{
@ -5835,56 +5809,6 @@ public:
break;
case Tpointer:
tb = (cast(TypePointer)tb).next.toBasetype();
if (tb.ty == Tstruct)
{
if (result.op != EXP.address ||
(cast(AddrExp)result).e1.op != EXP.structLiteral)
{
e.error("`delete` on invalid struct pointer `%s`", result.toChars());
result = CTFEExp.cantexp;
return;
}
auto sd = (cast(TypeStruct)tb).sym;
auto sle = cast(StructLiteralExp)(cast(AddrExp)result).e1;
if (sd.dtor)
{
result = interpretFunction(pue, sd.dtor, istate, null, sle);
if (exceptionOrCant(result))
return;
}
}
break;
case Tarray:
auto tv = tb.nextOf().baseElemOf();
if (tv.ty == Tstruct)
{
if (result.op != EXP.arrayLiteral)
{
e.error("`delete` on invalid struct array `%s`", result.toChars());
result = CTFEExp.cantexp;
return;
}
auto sd = (cast(TypeStruct)tv).sym;
if (sd.dtor)
{
auto ale = cast(ArrayLiteralExp)result;
foreach (el; *ale.elements)
{
result = interpretFunction(pue, sd.dtor, istate, null, el);
if (exceptionOrCant(result))
return;
}
}
}
break;
default:
assert(0);
}

View File

@ -726,7 +726,8 @@ public:
extern (D) static const(char)[] externallyMangledIdentifier(Declaration d)
{
const par = d.toParent(); //toParent() skips over mixin templates
if (!par || par.isModule() || d.linkage == LINK.cpp)
if (!par || par.isModule() || d.linkage == LINK.cpp ||
(d.linkage == LINK.c && d.isCsymbol() && d.isFuncDeclaration()))
{
if (d.linkage != LINK.d && d.localNum)
d.error("the same declaration cannot be in multiple scopes with non-D linkage");

View File

@ -524,17 +524,8 @@ extern (C++) final class Module : Package
buf.printf("%s\t(%s)", ident.toChars(), m.srcfile.toChars());
message("import %s", buf.peekChars());
}
m = m.parse();
if((m = m.parse()) is null) return null;
// Call onImport here because if the module is going to be compiled then we
// need to determine it early because it affects semantic analysis. This is
// being done after parsing the module so the full module name can be taken
// from whatever was declared in the file.
if (!m.isRoot() && Compiler.onImport(m))
{
m.importedFrom = m;
assert(m.isRoot());
}
return m;
}
@ -727,7 +718,7 @@ extern (C++) final class Module : Package
if (buf.length & 3)
{
error("odd length of UTF-32 char source %llu", cast(ulong) buf.length);
fatal();
return null;
}
const (uint)[] eBuf = cast(const(uint)[])buf;
@ -743,7 +734,7 @@ extern (C++) final class Module : Package
if (u > 0x10FFFF)
{
error("UTF-32 value %08x greater than 0x10FFFF", u);
fatal();
return null;
}
dbuf.writeUTF8(u);
}
@ -773,7 +764,7 @@ extern (C++) final class Module : Package
if (buf.length & 1)
{
error("odd length of UTF-16 char source %llu", cast(ulong) buf.length);
fatal();
return null;
}
const (ushort)[] eBuf = cast(const(ushort)[])buf;
@ -793,13 +784,13 @@ extern (C++) final class Module : Package
if (i >= eBuf.length)
{
error("surrogate UTF-16 high value %04x at end of file", u);
fatal();
return null;
}
const u2 = readNext(&eBuf[i]);
if (u2 < 0xDC00 || 0xE000 <= u2)
{
error("surrogate UTF-16 low value %04x out of range", u2);
fatal();
return null;
}
u = (u - 0xD7C0) << 10;
u |= (u2 - 0xDC00);
@ -807,12 +798,12 @@ extern (C++) final class Module : Package
else if (u >= 0xDC00 && u <= 0xDFFF)
{
error("unpaired surrogate UTF-16 value %04x", u);
fatal();
return null;
}
else if (u == 0xFFFE || u == 0xFFFF)
{
error("illegal UTF-16 value %04x", u);
fatal();
return null;
}
dbuf.writeUTF8(u);
}
@ -899,7 +890,7 @@ extern (C++) final class Module : Package
if (buf[0] >= 0x80)
{
error("source file must start with BOM or ASCII character, not \\x%02X", buf[0]);
fatal();
return null;
}
}
}
@ -929,6 +920,8 @@ extern (C++) final class Module : Package
? UTF32ToUTF8!(Endian.little)(buf)
: UTF32ToUTF8!(Endian.big)(buf);
}
// an error happened on UTF conversion
if (buf is null) return null;
}
/* If it starts with the string "Ddoc", then it's a documentation
@ -962,6 +955,16 @@ extern (C++) final class Module : Package
isHdrFile = true;
}
/// Promote `this` to a root module if requested via `-i`
void checkCompiledImport()
{
if (!this.isRoot() && Compiler.onImport(this))
this.importedFrom = this;
}
DsymbolTable dst;
Package ppack = null;
/* If it has the extension ".c", it is a "C" file.
* If it has the extension ".i", it is a preprocessed "C" file.
*/
@ -971,33 +974,41 @@ extern (C++) final class Module : Package
scope p = new CParser!AST(this, buf, cast(bool) docfile, target.c);
p.nextToken();
checkCompiledImport();
members = p.parseModule();
md = p.md;
assert(!p.md); // C doesn't have module declarations
numlines = p.scanloc.linnum;
}
else
{
scope p = new Parser!AST(this, buf, cast(bool) docfile);
p.nextToken();
members = p.parseModule();
p.parseModuleDeclaration();
md = p.md;
if (md)
{
/* A ModuleDeclaration, md, was provided.
* The ModuleDeclaration sets the packages this module appears in, and
* the name of this module.
*/
this.ident = md.id;
dst = Package.resolve(md.packages, &this.parent, &ppack);
}
// Done after parsing the module header because `module x.y.z` may override the file name
checkCompiledImport();
members = p.parseModuleContent();
numlines = p.scanloc.linnum;
}
srcBuffer.destroy();
srcBuffer = null;
/* The symbol table into which the module is to be inserted.
*/
DsymbolTable dst;
if (md)
{
/* A ModuleDeclaration, md, was provided.
* The ModuleDeclaration sets the packages this module appears in, and
* the name of this module.
*/
this.ident = md.id;
Package ppack = null;
dst = Package.resolve(md.packages, &this.parent, &ppack);
// Mark the package path as accessible from the current module
// https://issues.dlang.org/show_bug.cgi?id=21661
// Code taken from Import.addPackageAccess()
@ -1201,10 +1212,13 @@ extern (C++) final class Module : Package
if (StringExp se = msg ? msg.toStringExp() : null)
{
const slice = se.peekString();
deprecation(loc, "is deprecated - %.*s", cast(int)slice.length, slice.ptr);
if (slice.length)
{
deprecation(loc, "is deprecated - %.*s", cast(int)slice.length, slice.ptr);
return;
}
}
else
deprecation(loc, "is deprecated");
deprecation(loc, "is deprecated");
}
}

View File

@ -692,7 +692,7 @@ struct Scope
}
/********************************************
* Search enclosing scopes for ClassDeclaration.
* Search enclosing scopes for ClassDeclaration or StructDeclaration.
*/
extern (C++) AggregateDeclaration getStructClassScope()
{

View File

@ -51,6 +51,7 @@ import dmd.root.rootobject;
import dmd.root.speller;
import dmd.root.string;
import dmd.statement;
import dmd.staticassert;
import dmd.tokens;
import dmd.visitor;
@ -1305,9 +1306,10 @@ extern (C++) class Dsymbol : ASTNode
inout(AttribDeclaration) isAttribDeclaration() inout { return null; }
inout(AnonDeclaration) isAnonDeclaration() inout { return null; }
inout(CPPNamespaceDeclaration) isCPPNamespaceDeclaration() inout { return null; }
inout(VisibilityDeclaration) isVisibilityDeclaration() inout { return null; }
inout(VisibilityDeclaration) isVisibilityDeclaration() inout { return null; }
inout(OverloadSet) isOverloadSet() inout { return null; }
inout(CompileDeclaration) isCompileDeclaration() inout { return null; }
inout(StaticAssert) isStaticAssert() inout { return null; }
}
/***********************************************************
@ -2500,12 +2502,15 @@ Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsy
if (fd.fbody) // fd is the definition
{
sds.symtab.update(fd); // replace fd2 in symbol table with fd
fd.overnext = fd2;
return fd;
}
/* BUG: just like with VarDeclaration, the types should match, which needs semantic() to be run on it.
* FuncDeclaration::semantic2() can detect this, but it relies overnext being set.
/* Just like with VarDeclaration, the types should match, which needs semantic() to be run on it.
* FuncDeclaration::semantic() detects this, but it relies on .overnext being set.
*/
fd2.overloadInsert(fd);
return fd2;
}

View File

@ -71,6 +71,7 @@ class Expression;
class ExpressionDsymbol;
class AliasAssign;
class OverloadSet;
class StaticAssert;
struct AA;
#ifdef IN_GCC
typedef union tree_node Symbol;
@ -307,6 +308,7 @@ public:
virtual VisibilityDeclaration *isVisibilityDeclaration() { return NULL; }
virtual OverloadSet *isOverloadSet() { return NULL; }
virtual CompileDeclaration *isCompileDeclaration() { return NULL; }
virtual StaticAssert *isStaticAssert() { return NULL; }
void accept(Visitor *v) { v->visit(this); }
};

View File

@ -847,11 +847,10 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
dsym.error("globals, statics, fields, manifest constants, ref and out parameters cannot be `scope`");
}
// @@@DEPRECATED@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint
// @@@DEPRECATED_2.097@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint
// Deprecated in 2.087
// Remove this when the feature is removed from the language
if (0 && // deprecation disabled for now to accommodate existing extensive use
!(dsym.storage_class & STC.scope_))
if (!(dsym.storage_class & STC.scope_))
{
if (!(dsym.storage_class & STC.parameter) && dsym.ident != Id.withSym)
dsym.error("reference to `scope class` must be `scope`");
@ -1040,15 +1039,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
// See if initializer is a NewExp that can be allocated on the stack
if (dsym.type.toBasetype().ty == Tclass)
{
if (ne.newargs && ne.newargs.dim > 1)
{
dsym.mynew = true;
}
else
{
ne.onstack = 1;
dsym.onstack = true;
}
ne.onstack = 1;
dsym.onstack = true;
}
}
else if (auto fe = ex.isFuncExp())
@ -2438,8 +2430,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
Type tprev = eprev.type.toHeadMutable().equals(em.ed.type.toHeadMutable())
? em.ed.memtype
: eprev.type;
Expression emax = tprev.getProperty(sc, em.ed.loc, Id.max, 0);
/*
https://issues.dlang.org/show_bug.cgi?id=20777
Previously this used getProperty, which doesn't consider anything user defined,
this construct does do that and thus fixes the bug.
*/
Expression emax = DotIdExp.create(em.ed.loc, new TypeExp(em.ed.loc, tprev), Id.max);
emax = emax.expressionSemantic(sc);
emax = emax.ctfeInterpret();
@ -2979,10 +2975,6 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
void funcDeclarationSemantic(FuncDeclaration funcdecl)
{
TypeFunction f;
AggregateDeclaration ad;
InterfaceDeclaration id;
version (none)
{
printf("FuncDeclaration::semantic(sc = %p, this = %p, '%s', linkage = %d)\n", sc, funcdecl, funcdecl.toPrettyChars(), sc.linkage);
@ -3023,7 +3015,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
funcdecl.foverrides.setDim(0); // reset in case semantic() is being retried for this function
funcdecl.storage_class |= sc.stc & ~STC.ref_;
ad = funcdecl.isThis();
AggregateDeclaration ad = funcdecl.isThis();
// Don't nest structs b/c of generated methods which should not access the outer scopes.
// https://issues.dlang.org/show_bug.cgi?id=16627
if (ad && !funcdecl.generated)
@ -3042,21 +3034,22 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
if (sc.flags & SCOPE.compile)
funcdecl.flags |= FUNCFLAG.compileTimeOnly; // don't emit code for this function
FuncLiteralDeclaration fld = funcdecl.isFuncLiteralDeclaration();
if (fld && fld.treq)
funcdecl.linkage = sc.linkage;
if (auto fld = funcdecl.isFuncLiteralDeclaration())
{
Type treq = fld.treq;
assert(treq.nextOf().ty == Tfunction);
if (treq.ty == Tdelegate)
fld.tok = TOK.delegate_;
else if (treq.isPtrToFunction())
fld.tok = TOK.function_;
else
assert(0);
funcdecl.linkage = treq.nextOf().toTypeFunction().linkage;
if (fld.treq)
{
Type treq = fld.treq;
assert(treq.nextOf().ty == Tfunction);
if (treq.ty == Tdelegate)
fld.tok = TOK.delegate_;
else if (treq.isPtrToFunction())
fld.tok = TOK.function_;
else
assert(0);
funcdecl.linkage = treq.nextOf().toTypeFunction().linkage;
}
}
else
funcdecl.linkage = sc.linkage;
// evaluate pragma(inline)
if (auto pragmadecl = sc.inlining)
@ -3078,16 +3071,24 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
if (!funcdecl.originalType)
funcdecl.originalType = funcdecl.type.syntaxCopy();
if (funcdecl.type.ty != Tfunction)
static TypeFunction getFunctionType(FuncDeclaration fd)
{
if (funcdecl.type.ty != Terror)
if (auto tf = fd.type.isTypeFunction())
return tf;
if (!fd.type.isTypeError())
{
funcdecl.error("`%s` must be a function instead of `%s`", funcdecl.toChars(), funcdecl.type.toChars());
funcdecl.type = Type.terror;
fd.error("`%s` must be a function instead of `%s`", fd.toChars(), fd.type.toChars());
fd.type = Type.terror;
}
funcdecl.errors = true;
return;
fd.errors = true;
return null;
}
if (!getFunctionType(funcdecl))
return;
if (!funcdecl.type.deco)
{
sc = sc.push();
@ -3147,14 +3148,17 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
sc.stc |= STC.property;
if (tf.purity == PURE.fwdref)
sc.stc |= STC.pure_;
if (tf.trust != TRUST.default_)
{
sc.stc &= ~STC.safeGroup;
if (tf.trust == TRUST.safe)
sc.stc |= STC.safe;
if (tf.trust == TRUST.system)
sc.stc |= STC.system;
if (tf.trust == TRUST.trusted)
sc.stc |= STC.trusted;
if (tf.trust == TRUST.safe)
sc.stc |= STC.safe;
else if (tf.trust == TRUST.system)
sc.stc |= STC.system;
else if (tf.trust == TRUST.trusted)
sc.stc |= STC.trusted;
}
if (funcdecl.isCtorDeclaration())
{
@ -3206,37 +3210,46 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
funcdecl.type = funcdecl.type.typeSemantic(funcdecl.loc, sc);
sc = sc.pop();
}
if (funcdecl.type.ty != Tfunction)
{
if (funcdecl.type.ty != Terror)
{
funcdecl.error("`%s` must be a function instead of `%s`", funcdecl.toChars(), funcdecl.type.toChars());
funcdecl.type = Type.terror;
}
funcdecl.errors = true;
return;
}
else
auto f = getFunctionType(funcdecl);
if (!f)
return; // funcdecl's type is not a function
{
// Merge back function attributes into 'originalType'.
// It's used for mangling, ddoc, and json output.
TypeFunction tfo = funcdecl.originalType.toTypeFunction();
TypeFunction tfx = funcdecl.type.toTypeFunction();
tfo.mod = tfx.mod;
tfo.isScopeQual = tfx.isScopeQual;
tfo.isreturninferred = tfx.isreturninferred;
tfo.isscopeinferred = tfx.isscopeinferred;
tfo.isref = tfx.isref;
tfo.isnothrow = tfx.isnothrow;
tfo.isnogc = tfx.isnogc;
tfo.isproperty = tfx.isproperty;
tfo.purity = tfx.purity;
tfo.trust = tfx.trust;
tfo.mod = f.mod;
tfo.isScopeQual = f.isScopeQual;
tfo.isreturninferred = f.isreturninferred;
tfo.isscopeinferred = f.isscopeinferred;
tfo.isref = f.isref;
tfo.isnothrow = f.isnothrow;
tfo.isnogc = f.isnogc;
tfo.isproperty = f.isproperty;
tfo.purity = f.purity;
tfo.trust = f.trust;
funcdecl.storage_class &= ~(STC.TYPECTOR | STC.FUNCATTR);
}
f = cast(TypeFunction)funcdecl.type;
if (funcdecl.overnext && funcdecl.isCsymbol())
{
/* C does not allow function overloading, but it does allow
* redeclarations of the same function. If .overnext points
* to a redeclaration, ok. Error if it is an overload.
*/
auto fnext = funcdecl.overnext.isFuncDeclaration();
funcDeclarationSemantic(fnext);
auto fn = fnext.type.isTypeFunction();
if (!fn || !cFuncEquivalence(f, fn))
{
funcdecl.error("redeclaration with different type");
//printf("t1: %s\n", f.toChars());
//printf("t2: %s\n", fn.toChars());
}
funcdecl.overnext = null; // don't overload the redeclarations
}
if ((funcdecl.storage_class & STC.auto_) && !f.isref && !funcdecl.inferRetType)
funcdecl.error("storage class `auto` has no effect if return type is not inferred");
@ -3355,8 +3368,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
}
}
id = parent.isInterfaceDeclaration();
if (id)
if (auto id = parent.isInterfaceDeclaration())
{
funcdecl.storage_class |= STC.abstract_;
if (funcdecl.isCtorDeclaration() || funcdecl.isPostBlitDeclaration() || funcdecl.isDtorDeclaration() || funcdecl.isInvariantDeclaration() || funcdecl.isNewDeclaration() || funcdecl.isDelete())
@ -3364,6 +3376,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
if (funcdecl.fbody && funcdecl.isVirtual())
funcdecl.error("function body only allowed in `final` functions in interface `%s`", id.toChars());
}
if (UnionDeclaration ud = parent.isUnionDeclaration())
{
if (funcdecl.isPostBlitDeclaration() || funcdecl.isDtorDeclaration() || funcdecl.isInvariantDeclaration())
@ -3449,8 +3462,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
Dsymbol s = cd.baseClass.search(funcdecl.loc, funcdecl.ident);
if (s)
{
FuncDeclaration f2 = s.isFuncDeclaration();
if (f2)
if (auto f2 = s.isFuncDeclaration())
{
f2 = f2.overloadExactMatch(funcdecl.type);
if (f2 && f2.isFinalFunc() && f2.visible().kind != Visibility.Kind.private_)
@ -3802,11 +3814,9 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
{
if (b.sym)
{
Dsymbol s = search_function(b.sym, funcdecl.ident);
if (s)
if (auto s = search_function(b.sym, funcdecl.ident))
{
FuncDeclaration f2 = s.isFuncDeclaration();
if (f2)
if (auto f2 = s.isFuncDeclaration())
{
f2 = f2.overloadExactMatch(funcdecl.type);
if (f2 && f2.isFinalFunc() && f2.visible().kind != Visibility.Kind.private_)
@ -3853,8 +3863,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
*/
if (funcdecl.isVirtual())
{
TemplateInstance ti = parent.isTemplateInstance();
if (ti)
if (auto ti = parent.isTemplateInstance())
{
// Take care of nested templates
while (1)
@ -4426,7 +4435,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
return;
int errors = global.errors;
//printf("+StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", this, sd.toPrettyChars(), sd.sizeok);
//printf("+StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", sd, sd.toPrettyChars(), sd.sizeok);
Scope* scx = null;
if (sd._scope)
{
@ -5275,7 +5284,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
}
//printf("-ClassDeclaration.dsymbolSemantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this);
// @@@DEPRECATED@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint
// @@@DEPRECATED_2.097@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint
// Deprecated in 2.087
// Make an error in 2.091
// Don't forget to remove code at https://github.com/dlang/dmd/blob/b2f8274ba76358607fc3297a1e9f361480f9bcf9/src/dmd/dsymbolsem.d#L1032-L1036
@ -5582,12 +5591,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
}
assert(idec.type.ty != Tclass || (cast(TypeClass)idec.type).sym == idec);
// @@@DEPRECATED@@@https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint
// @@@DEPRECATED_2.120@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint
// Deprecated in 2.087
// Remove in 2.091
// Made an error in 2.100, but removal depends on `scope class` being removed too
// Don't forget to remove code at https://github.com/dlang/dmd/blob/b2f8274ba76358607fc3297a1e9f361480f9bcf9/src/dmd/dsymbolsem.d#L1032-L1036
if (idec.storage_class & STC.scope_)
deprecation(idec.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site.");
error(idec.loc, "`scope` as a type constraint is obsolete. Use `scope` at the usage site.");
}
}
@ -5879,13 +5888,16 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions*
scope v = new InstMemberWalker(tempinst.inst);
tempinst.inst.accept(v);
if (tempinst.minst) // if inst was not speculative
if (!global.params.allInst &&
tempinst.minst) // if inst was not speculative...
{
/* Add 'inst' once again to the root module members[], then the
* instance members will get codegen chances.
*/
assert(!tempinst.minst.isRoot()); // ... it was previously appended to a non-root module
// Append again to the root module members[], so that the instance will
// get codegen chances (depending on `tempinst.inst.needsCodegen()`).
tempinst.inst.appendToModuleMember();
}
assert(tempinst.inst.memberOf && tempinst.inst.memberOf.isRoot(), "no codegen chances");
}
// modules imported by an existing instance should be added to the module

View File

@ -5125,15 +5125,6 @@ private bool reliesOnTemplateParameters(Expression e, TemplateParameter[] tparam
//printf("NewExp.reliesOnTemplateParameters('%s')\n", e.toChars());
if (e.thisexp)
e.thisexp.accept(this);
if (!result && e.newargs)
{
foreach (ea; *e.newargs)
{
ea.accept(this);
if (result)
return;
}
}
result = e.newtype.reliesOnTemplateParameters(tparams);
if (!result && e.arguments)
{
@ -7351,12 +7342,12 @@ extern (C++) class TemplateInstance : ScopeDsymbol
// toPrettyChars(),
// enclosing ? enclosing.toPrettyChars() : null,
// mi ? mi.toPrettyChars() : null);
if (!mi || mi.isRoot())
if (global.params.allInst || !mi || mi.isRoot())
{
/* If the instantiated module is speculative or root, insert to the
* member of a root module. Then:
* - semantic3 pass will get called on the instance members.
* - codegen pass will get a selection chance to do/skip it.
* - codegen pass will get a selection chance to do/skip it (needsCodegen()).
*/
static Dsymbol getStrictEnclosing(TemplateInstance ti)
{
@ -7374,8 +7365,18 @@ extern (C++) class TemplateInstance : ScopeDsymbol
// where tempdecl is declared.
mi = (enc ? enc : tempdecl).getModule();
if (!mi.isRoot())
mi = mi.importedFrom;
assert(mi.isRoot());
{
if (mi.importedFrom)
{
mi = mi.importedFrom;
assert(mi.isRoot());
}
else
{
// This can happen when using the frontend as a library.
// Append it to the non-root module.
}
}
}
else
{
@ -7383,24 +7384,12 @@ extern (C++) class TemplateInstance : ScopeDsymbol
* non-root module. Then:
* - semantic3 pass won't be called on the instance.
* - codegen pass won't reach to the instance.
* Unless it is re-appended to a root module later (with changed minst).
*/
}
//printf("\t-. mi = %s\n", mi.toPrettyChars());
if (memberOf is mi) // already a member
{
debug // make sure it really is a member
{
auto a = mi.members;
for (size_t i = 0; 1; ++i)
{
assert(i != a.dim);
if (this == (*a)[i])
break;
}
}
return null;
}
assert(!memberOf || (!memberOf.isRoot() && mi.isRoot()), "can only re-append from non-root to root module");
Dsymbols* a = mi.members;
a.push(this);
@ -7801,15 +7790,22 @@ struct TemplateInstanceBox
{
bool res = void;
if (ti.inst && s.ti.inst)
{
/* This clause is only used when an instance with errors
* is replaced with a correct instance.
*/
res = ti is s.ti;
}
else
{
/* Used when a proposed instance is used to see if there's
* an existing instance.
*/
res = (cast()s.ti).equalsx(cast()ti);
static if (__VERSION__ >= 2099)
res = (cast()ti).equalsx(cast()s.ti);
else // https://issues.dlang.org/show_bug.cgi?id=22717
res = (cast()s.ti).equalsx(cast()ti);
}
debug (FindExistingInstance) ++(res ? nHits : nCollisions);
return res;

View File

@ -2545,29 +2545,9 @@ public:
buf.writeByte('U');
buf.writeByte('"');
for (size_t i = 0; i < e.len; i++)
foreach (i; 0 .. e.len)
{
uint c = e.charAt(i);
switch (c)
{
case '"':
case '\\':
buf.writeByte('\\');
goto default;
default:
if (c <= 0xFF)
{
if (c >= 0x20 && c < 0x80)
buf.writeByte(c);
else
buf.printf("\\x%02x", c);
}
else if (c <= 0xFFFF)
buf.printf("\\u%04x", c);
else
buf.printf("\\U%08x", c);
break;
}
writeCharLiteral(*buf, e.getCodeUnit(i));
}
buf.writeByte('"');
}

View File

@ -380,7 +380,7 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Parameter par, Exp
notMaybeScope(v);
if (!v.isReference() && p == sc.func)
if (p == sc.func)
{
if (psr == ScopeRef.Scope ||
psr == ScopeRef.RefScope ||

View File

@ -1742,11 +1742,21 @@ extern (C++) abstract class Expression : ASTNode
inout(PrettyFuncInitExp) isPrettyFuncInitExp() { return op == EXP.prettyFunction ? cast(typeof(return))this : null; }
inout(ClassReferenceExp) isClassReferenceExp() { return op == EXP.classReference ? cast(typeof(return))this : null; }
inout(ThrownExceptionExp) isThrownExceptionExp() { return op == EXP.thrownException ? cast(typeof(return))this : null; }
}
inout(BinAssignExp) isBinAssignExp() pure inout nothrow @nogc
{
return null;
inout(UnaExp) isUnaExp() pure inout nothrow @nogc
{
return exptab[op] & EXPFLAGS.unary ? cast(typeof(return))this : null;
}
inout(BinExp) isBinExp() pure inout nothrow @nogc
{
return exptab[op] & EXPFLAGS.binary ? cast(typeof(return))this : null;
}
inout(BinAssignExp) isBinAssignExp() pure inout nothrow @nogc
{
return exptab[op] & EXPFLAGS.binaryAssign ? cast(typeof(return))this : null;
}
}
override void accept(Visitor v)
@ -2716,29 +2726,6 @@ extern (C++) final class StringExp : Expression
return ErrorExp.get();
}
uint charAt(uinteger_t i) const
{
uint value;
switch (sz)
{
case 1:
value = (cast(char*)string)[cast(size_t)i];
break;
case 2:
value = (cast(ushort*)string)[cast(size_t)i];
break;
case 4:
value = (cast(uint*)string)[cast(size_t)i];
break;
default:
assert(0);
}
return value;
}
/********************************
* Convert string contents to a 0 terminated string,
* allocated by mem.xmalloc().
@ -3516,12 +3503,11 @@ extern (C++) final class TemplateExp : Expression
}
/***********************************************************
* thisexp.new(newargs) newtype(arguments)
* newtype(arguments)
*/
extern (C++) final class NewExp : Expression
{
Expression thisexp; // if !=null, 'this' for class being allocated
Expressions* newargs; // Array of Expression's to call new operator
Type newtype;
Expressions* arguments; // Array of Expression's
@ -3530,25 +3516,23 @@ extern (C++) final class NewExp : Expression
bool onstack; // allocate on stack
bool thrownew; // this NewExp is the expression of a ThrowStatement
extern (D) this(const ref Loc loc, Expression thisexp, Expressions* newargs, Type newtype, Expressions* arguments)
extern (D) this(const ref Loc loc, Expression thisexp, Type newtype, Expressions* arguments)
{
super(loc, EXP.new_, __traits(classInstanceSize, NewExp));
this.thisexp = thisexp;
this.newargs = newargs;
this.newtype = newtype;
this.arguments = arguments;
}
static NewExp create(const ref Loc loc, Expression thisexp, Expressions* newargs, Type newtype, Expressions* arguments)
static NewExp create(const ref Loc loc, Expression thisexp, Type newtype, Expressions* arguments)
{
return new NewExp(loc, thisexp, newargs, newtype, arguments);
return new NewExp(loc, thisexp, newtype, arguments);
}
override NewExp syntaxCopy()
{
return new NewExp(loc,
thisexp ? thisexp.syntaxCopy() : null,
arraySyntaxCopy(newargs),
newtype.syntaxCopy(),
arraySyntaxCopy(arguments));
}
@ -3560,27 +3544,25 @@ extern (C++) final class NewExp : Expression
}
/***********************************************************
* thisexp.new(newargs) class baseclasses { } (arguments)
* class baseclasses { } (arguments)
*/
extern (C++) final class NewAnonClassExp : Expression
{
Expression thisexp; // if !=null, 'this' for class being allocated
Expressions* newargs; // Array of Expression's to call new operator
ClassDeclaration cd; // class being instantiated
Expressions* arguments; // Array of Expression's to call class constructor
extern (D) this(const ref Loc loc, Expression thisexp, Expressions* newargs, ClassDeclaration cd, Expressions* arguments)
extern (D) this(const ref Loc loc, Expression thisexp, ClassDeclaration cd, Expressions* arguments)
{
super(loc, EXP.newAnonymousClass, __traits(classInstanceSize, NewAnonClassExp));
this.thisexp = thisexp;
this.newargs = newargs;
this.cd = cd;
this.arguments = arguments;
}
override NewAnonClassExp syntaxCopy()
{
return new NewAnonClassExp(loc, thisexp ? thisexp.syntaxCopy() : null, arraySyntaxCopy(newargs), cd.syntaxCopy(null), arraySyntaxCopy(arguments));
return new NewAnonClassExp(loc, thisexp ? thisexp.syntaxCopy() : null, cd.syntaxCopy(null), arraySyntaxCopy(arguments));
}
override void accept(Visitor v)
@ -4593,11 +4575,6 @@ extern (C++) class BinAssignExp : BinExp
return toLvalue(sc, this);
}
override inout(BinAssignExp) isBinAssignExp() pure inout nothrow @nogc @safe
{
return this;
}
override void accept(Visitor v)
{
v.visit(this);
@ -7055,3 +7032,53 @@ extern(D) Modifiable checkModifiable(Expression exp, Scope* sc, ModifyFlags flag
return exp.type ? Modifiable.yes : Modifiable.no; // default modifiable
}
}
/******************************
* Provide efficient way to implement isUnaExp(), isBinExp(), isBinAssignExp()
*/
private immutable ubyte[EXP.max + 1] exptab =
() {
ubyte[EXP.max + 1] tab;
with (EXPFLAGS)
{
foreach (i; Eunary) { tab[i] |= unary; }
foreach (i; Ebinary) { tab[i] |= unary | binary; }
foreach (i; EbinaryAssign) { tab[i] |= unary | binary | binaryAssign; }
}
return tab;
} ();
private enum EXPFLAGS : ubyte
{
unary = 1,
binary = 2,
binaryAssign = 4,
}
private enum Eunary =
[
EXP.import_, EXP.assert_, EXP.throw_, EXP.dotIdentifier, EXP.dotTemplateDeclaration,
EXP.dotVariable, EXP.dotTemplateInstance, EXP.delegate_, EXP.dotType, EXP.call,
EXP.address, EXP.star, EXP.negate, EXP.uadd, EXP.tilde, EXP.not, EXP.delete_, EXP.cast_,
EXP.vector, EXP.vectorArray, EXP.slice, EXP.arrayLength, EXP.array, EXP.delegatePointer,
EXP.delegateFunctionPointer, EXP.preMinusMinus, EXP.prePlusPlus,
];
private enum Ebinary =
[
EXP.dot, EXP.comma, EXP.index, EXP.minusMinus, EXP.plusPlus, EXP.assign,
EXP.add, EXP.min, EXP.concatenate, EXP.mul, EXP.div, EXP.mod, EXP.pow, EXP.leftShift,
EXP.rightShift, EXP.unsignedRightShift, EXP.and, EXP.or, EXP.xor, EXP.andAnd, EXP.orOr,
EXP.lessThan, EXP.lessOrEqual, EXP.greaterThan, EXP.greaterOrEqual,
EXP.in_, EXP.remove, EXP.equal, EXP.notEqual, EXP.identity, EXP.notIdentity,
EXP.question,
EXP.construct, EXP.blit,
];
private enum EbinaryAssign =
[
EXP.addAssign, EXP.minAssign, EXP.mulAssign, EXP.divAssign, EXP.modAssign,
EXP.andAssign, EXP.orAssign, EXP.xorAssign, EXP.powAssign,
EXP.leftShiftAssign, EXP.rightShiftAssign, EXP.unsignedRightShiftAssign,
EXP.concatenateAssign, EXP.concatenateElemAssign, EXP.concatenateDcharAssign,
];

View File

@ -234,7 +234,10 @@ public:
FuncInitExp* isFuncInitExp();
PrettyFuncInitExp* isPrettyFuncInitExp();
ClassReferenceExp* isClassReferenceExp();
virtual BinAssignExp* isBinAssignExp();
ThrownExceptionExp* isThrownExceptionExp();
UnaExp* isUnaExp();
BinExp* isBinExp();
BinAssignExp* isBinAssignExp();
void accept(Visitor *v) { v->visit(this); }
};
@ -374,13 +377,14 @@ public:
static StringExp *create(const Loc &loc, const void *s, size_t len);
static void emplace(UnionExp *pue, const Loc &loc, const char *s);
bool equals(const RootObject *o) const;
char32_t getCodeUnit(size_t i) const;
void setCodeUnit(size_t i, char32_t c);
StringExp *toStringExp();
StringExp *toUTF8(Scope *sc);
Optional<bool> toBool();
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
Expression *modifiableLvalue(Scope *sc, Expression *e);
unsigned charAt(uinteger_t i) const;
void accept(Visitor *v) { v->visit(this); }
size_t numberOfCodeUnits(int tynto = 0) const;
void writeTo(void* dest, bool zero, int tyto = 0) const;
@ -519,10 +523,9 @@ public:
class NewExp : public Expression
{
public:
/* thisexp.new(newargs) newtype(arguments)
/* newtype(arguments)
*/
Expression *thisexp; // if !NULL, 'this' for class being allocated
Expressions *newargs; // Array of Expression's to call new operator
Type *newtype;
Expressions *arguments; // Array of Expression's
@ -532,7 +535,7 @@ public:
bool onstack; // allocate on stack
bool thrownew; // this NewExp is the expression of a ThrowStatement
static NewExp *create(const Loc &loc, Expression *thisexp, Expressions *newargs, Type *newtype, Expressions *arguments);
static NewExp *create(const Loc &loc, Expression *thisexp, Type *newtype, Expressions *arguments);
NewExp *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
@ -541,10 +544,9 @@ public:
class NewAnonClassExp : public Expression
{
public:
/* thisexp.new(newargs) class baseclasses { } (arguments)
/* class baseclasses { } (arguments)
*/
Expression *thisexp; // if !NULL, 'this' for class being allocated
Expressions *newargs; // Array of Expression's to call new operator
ClassDeclaration *cd; // class being instantiated
Expressions *arguments; // Array of Expression's to call class constructor
@ -716,7 +718,6 @@ public:
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *ex);
Expression *modifiableLvalue(Scope *sc, Expression *e);
BinAssignExp* isBinAssignExp();
void accept(Visitor *v) { v->visit(this); }
};

View File

@ -1236,21 +1236,21 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
tthis = null;
goto Lfd;
}
else if (e1.op == EXP.dotVariable && e1.type && (e1.type.toBasetype().ty == Tfunction || (cast(DotVarExp)e1).var.isOverDeclaration()))
else if (e1.isDotVarExp() && e1.type && (e1.type.toBasetype().isTypeFunction() || e1.isDotVarExp().var.isOverDeclaration()))
{
DotVarExp dve = cast(DotVarExp)e1;
DotVarExp dve = e1.isDotVarExp();
s = dve.var;
tiargs = null;
tthis = dve.e1.type;
goto Lfd;
}
else if (sc && sc.flags & SCOPE.Cfile && e1.op == EXP.variable && !e2)
else if (sc && sc.flags & SCOPE.Cfile && e1.isVarExp() && !e2)
{
// ImportC: do not implicitly call function if no ( ) are present
}
else if (e1.op == EXP.variable && e1.type && (e1.type.toBasetype().ty == Tfunction || (cast(VarExp)e1).var.isOverDeclaration()))
else if (e1.isVarExp() && e1.type && (e1.type.toBasetype().isTypeFunction() || e1.isVarExp().var.isOverDeclaration()))
{
s = (cast(VarExp)e1).var;
s = e1.isVarExp().var;
tiargs = null;
tthis = null;
Lfd:
@ -1272,9 +1272,9 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
return ErrorExp.get();
if (!checkSymbolAccess(sc, fd))
{
// @@@DEPRECATED_2020-10@@@
// @@@DEPRECATED_2.105@@@
// When turning into error, uncomment the return statement
TypeFunction tf = cast(TypeFunction)fd.type;
TypeFunction tf = fd.type.isTypeFunction();
deprecation(loc, "Function `%s` of type `%s` is not accessible from module `%s`",
fd.toPrettyChars(), tf.toChars, sc._module.toChars);
//return ErrorExp.get();
@ -1290,13 +1290,12 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
{
if (fd.errors)
return ErrorExp.get();
assert(fd.type.ty == Tfunction);
TypeFunction tf = cast(TypeFunction)fd.type;
TypeFunction tf = fd.type.isTypeFunction();
if (!e2 || tf.isref)
{
if (!checkSymbolAccess(sc, fd))
{
// @@@DEPRECATED_2020-10@@@
// @@@DEPRECATED_2.105@@@
// When turning into error, uncomment the return statement
deprecation(loc, "Function `%s` of type `%s` is not accessible from module `%s`",
fd.toPrettyChars(), tf.toChars, sc._module.toChars);
@ -1319,17 +1318,18 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
if (e2)
goto Leprop;
}
if (e1.op == EXP.variable)
if (auto ve = e1.isVarExp())
{
VarExp ve = cast(VarExp)e1;
VarDeclaration v = ve.var.isVarDeclaration();
if (v && ve.checkPurity(sc, v))
return ErrorExp.get();
if (auto v = ve.var.isVarDeclaration())
{
if (ve.checkPurity(sc, v))
return ErrorExp.get();
}
}
if (e2)
return null;
if (e1.type && e1.op != EXP.type) // function type is not a property
if (e1.type && !e1.isTypeExp()) // function type is not a property
{
/* Look for e1 being a lazy parameter; rewrite as delegate call
* only if the symbol wasn't already treated as a delegate
@ -1340,15 +1340,14 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
Expression e = new CallExp(loc, e1);
return e.expressionSemantic(sc);
}
else if (e1.op == EXP.dotVariable)
else if (e1.isDotVarExp())
{
// Check for reading overlapped pointer field in @safe code.
if (checkUnsafeAccess(sc, e1, true, true))
return ErrorExp.get();
}
else if (e1.op == EXP.call)
else if (auto ce = e1.isCallExp())
{
CallExp ce = cast(CallExp)e1;
// Check for reading overlapped pointer field in @safe code.
if (checkUnsafeAccess(sc, ce.e1, true, true))
return ErrorExp.get();
@ -1560,14 +1559,12 @@ private Expression opAssignToOp(const ref Loc loc, EXP op, Expression e1, Expres
*/
private Expression rewriteOpAssign(BinExp exp)
{
Expression e;
assert(exp.e1.op == EXP.arrayLength);
ArrayLengthExp ale = cast(ArrayLengthExp)exp.e1;
if (ale.e1.op == EXP.variable)
ArrayLengthExp ale = exp.e1.isArrayLengthExp();
if (ale.e1.isVarExp())
{
e = opAssignToOp(exp.loc, exp.op, ale, exp.e2);
Expression e = opAssignToOp(exp.loc, exp.op, ale, exp.e2);
e = new AssignExp(exp.loc, ale.syntaxCopy(), e);
return e;
}
else
{
@ -1578,11 +1575,11 @@ private Expression rewriteOpAssign(BinExp exp)
Expression e1 = new ArrayLengthExp(ale.loc, new PtrExp(ale.loc, new VarExp(ale.loc, tmp)));
Expression elvalue = e1.syntaxCopy();
e = opAssignToOp(exp.loc, exp.op, e1, exp.e2);
Expression e = opAssignToOp(exp.loc, exp.op, e1, exp.e2);
e = new AssignExp(exp.loc, elvalue, e);
e = new CommaExp(exp.loc, new DeclarationExp(ale.loc, tmp), e);
return e;
}
return e;
}
/****************************************
@ -1650,10 +1647,9 @@ private bool preFunctionParameters(Scope* sc, Expressions* exps, const bool repo
*/
private bool checkDefCtor(Loc loc, Type t)
{
t = t.baseElemOf();
if (t.ty == Tstruct)
if (auto ts = t.baseElemOf().isTypeStruct())
{
StructDeclaration sd = (cast(TypeStruct)t).sym;
StructDeclaration sd = ts.sym;
if (sd.noDefaultCtor)
{
sd.error(loc, "default construction is disabled");
@ -1846,7 +1842,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
auto args = new Expressions(nargs - i);
foreach (u; i .. nargs)
(*args)[u - i] = (*arguments)[u];
arg = new NewExp(loc, null, null, p.type, args);
arg = new NewExp(loc, null, p.type, args);
break;
}
default:
@ -1923,7 +1919,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
}
else if (auto ff = s.isFuncDeclaration())
{
if ((cast(TypeFunction)ff.type).iswild)
if (ff.type.isTypeFunction().iswild)
return errorInout(wildmatch);
if (ff.isNested() || ff.isThis())
@ -1969,7 +1965,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
? p.type.substWildTo(wildmatch)
: p.type;
const hasCopyCtor = (arg.type.ty == Tstruct) && (cast(TypeStruct)arg.type).sym.hasCopyCtor;
const hasCopyCtor = arg.type.isTypeStruct() && arg.type.isTypeStruct().sym.hasCopyCtor;
const typesMatch = arg.type.mutableOf().unSharedOf().equals(tprm.mutableOf().unSharedOf());
if (!((hasCopyCtor && typesMatch) || tprm.equals(arg.type)))
{
@ -2059,8 +2055,8 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
/* Argument value cannot escape from the called function.
*/
Expression a = arg;
if (a.op == EXP.cast_)
a = (cast(CastExp)a).e1;
if (auto ce = a.isCastExp())
a = ce.e1;
ArrayLiteralExp ale;
if (p.type.toBasetype().ty == Tarray &&
@ -2074,26 +2070,22 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
arg = CommaExp.combine(declareTmp, castToSlice);
arg = arg.expressionSemantic(sc);
}
else if (a.op == EXP.function_)
else if (auto fe = a.isFuncExp())
{
/* Function literals can only appear once, so if this
* appearance was scoped, there cannot be any others.
*/
FuncExp fe = cast(FuncExp)a;
fe.fd.tookAddressOf = 0;
}
else if (a.op == EXP.delegate_)
else if (auto de = a.isDelegateExp())
{
/* For passing a delegate to a scoped parameter,
* this doesn't count as taking the address of it.
* We only worry about 'escaping' references to the function.
*/
DelegateExp de = cast(DelegateExp)a;
if (de.e1.op == EXP.variable)
if (auto ve = de.e1.isVarExp())
{
VarExp ve = cast(VarExp)de.e1;
FuncDeclaration f = ve.var.isFuncDeclaration();
if (f)
if (auto f = ve.var.isFuncDeclaration())
{
if (f.tookAddressOf)
--f.tookAddressOf;
@ -2174,9 +2166,8 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
// Convert static arrays to dynamic arrays
// BUG: I don't think this is right for D2
Type tb = arg.type.toBasetype();
if (tb.ty == Tsarray)
if (auto ts = tb.isTypeSArray())
{
TypeSArray ts = cast(TypeSArray)tb;
Type ta = ts.next.arrayOf();
if (ts.size(arg.loc) == 0)
arg = new NullExp(arg.loc, ta);
@ -2188,9 +2179,8 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
//arg = callCpCtor(sc, arg);
}
// Give error for overloaded function addresses
if (arg.op == EXP.symbolOffset)
if (auto se = arg.isSymOffExp())
{
SymOffExp se = cast(SymOffExp)arg;
if (se.hasOverloads && !se.var.isFuncDeclaration().isUnique())
{
arg.error("function `%s` is overloaded", arg.toChars());
@ -3469,10 +3459,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
// T should be analyzed first and edim should go into arguments iff it's
// not a tuple.
Expression edim = null;
if (!exp.arguments && exp.newtype.ty == Tsarray)
if (!exp.arguments && exp.newtype.isTypeSArray())
{
edim = (cast(TypeSArray)exp.newtype).dim;
exp.newtype = (cast(TypeNext)exp.newtype).next;
auto ts = exp.newtype.isTypeSArray();
edim = ts.dim;
exp.newtype = ts.next;
}
ClassDeclaration cdthis = null;
@ -3522,11 +3513,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
exp.newtype = exp.type; // in case type gets cast to something else
Type tb = exp.type.toBasetype();
//printf("tb: %s, deco = %s\n", tb.toChars(), tb.deco);
if (arrayExpressionSemantic(exp.newargs, sc) ||
preFunctionParameters(sc, exp.newargs))
{
return setError();
}
if (arrayExpressionSemantic(exp.arguments, sc))
{
return setError();
@ -3556,9 +3542,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
const size_t nargs = exp.arguments ? exp.arguments.dim : 0;
Expression newprefix = null;
if (tb.ty == Tclass)
if (auto tc = tb.isTypeClass())
{
auto cd = (cast(TypeClass)tb).sym;
auto cd = tc.sym;
cd.size(exp.loc);
if (cd.sizeok != Sizeok.done)
return setError();
@ -3692,14 +3678,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
originalNewtype.toChars());
return setError();
}
else
{
if (exp.newargs && exp.newargs.dim)
{
exp.error("no allocator for `%s`", cd.toChars());
return setError();
}
}
if (cd.ctor)
{
@ -3710,7 +3688,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
checkFunctionAttributes(exp, sc, f);
checkAccess(cd, exp.loc, sc, f);
TypeFunction tf = cast(TypeFunction)f.type;
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))
@ -3744,9 +3722,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
}
}
else if (tb.ty == Tstruct)
else if (auto ts = tb.isTypeStruct())
{
auto sd = (cast(TypeStruct)tb).sym;
auto sd = ts.sym;
sd.size(exp.loc);
if (sd.sizeok != Sizeok.done)
return setError();
@ -3765,14 +3743,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
originalNewtype.toChars());
return setError();
}
else
{
if (exp.newargs && exp.newargs.dim)
{
exp.error("no allocator for `%s`", sd.toChars());
return setError();
}
}
if (sd.hasRegularCtor() && nargs)
{
@ -3783,7 +3753,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
checkFunctionAttributes(exp, sc, f);
checkAccess(sd, exp.loc, sc, f);
TypeFunction tf = cast(TypeFunction)f.type;
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))
@ -3861,7 +3831,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return setError();
}
(*exp.arguments)[i] = arg;
tb = (cast(TypeDArray)tb).next.toBasetype();
tb = tb.isTypeDArray().next.toBasetype();
}
}
else if (tb.isscalar())
@ -3924,7 +3894,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
sds.members.push(e.cd);
}
Expression n = new NewExp(e.loc, e.thisexp, e.newargs, e.cd.type, e.arguments);
Expression n = new NewExp(e.loc, e.thisexp, e.cd.type, e.arguments);
Expression c = new CommaExp(e.loc, d, n);
result = c.expressionSemantic(sc);
@ -4097,6 +4067,15 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
// Type is a "delegate to" or "pointer to" the function literal
if ((exp.fd.isNested() && exp.fd.tok == TOK.delegate_) || (exp.tok == TOK.reserved && exp.fd.treq && exp.fd.treq.ty == Tdelegate))
{
// https://issues.dlang.org/show_bug.cgi?id=22686
// if the delegate return type is an error
// abort semantic of the FuncExp and propagate
// the error
if (exp.fd.type.isTypeError())
{
e = ErrorExp.get();
goto Ldone;
}
exp.type = new TypeDelegate(exp.fd.type.isTypeFunction());
exp.type = exp.type.typeSemantic(exp.loc, sc);
@ -5239,21 +5218,21 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
break;
}
VarDeclaration v = s.isVarDeclaration();
if (v)
{
// Do semantic() on initializer first, so:
// int a = a;
// will be illegal.
e.declaration.dsymbolSemantic(sc);
s.parent = sc.parent;
}
//printf("inserting '%s' %p into sc = %p\n", s.toChars(), s, sc);
// Insert into both local scope and function scope.
// Must be unique in both.
if (s.ident)
{
VarDeclaration v = s.isVarDeclaration();
if (v && !(sc.flags & SCOPE.Cfile))
{
/* Do semantic() on initializer first so this will be illegal:
* int a = a;
*/
e.declaration.dsymbolSemantic(sc);
s.parent = sc.parent;
}
if (!sc.insert(s))
{
auto conflict = sc.search(Loc.initial, s.ident, null);
@ -5262,7 +5241,17 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
conflict.kind(), conflict.toChars());
return setError();
}
else if (sc.func)
if (v && (sc.flags & SCOPE.Cfile))
{
/* Do semantic() on initializer last so this will be legal:
* int a = a;
*/
e.declaration.dsymbolSemantic(sc);
s.parent = sc.parent;
}
if (sc.func)
{
// https://issues.dlang.org/show_bug.cgi?id=11720
if ((s.isFuncDeclaration() ||
@ -5278,14 +5267,19 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
// Perturb the name mangling so that the symbols can co-exist
// instead of colliding
s.localNum = cast(ushort)(originalSymbol.localNum + 1);
assert(s.localNum); // 65535 should be enough for anyone
// 65535 should be enough for anyone
if (!s.localNum)
{
e.error("more than 65535 symbols with name `%s` generated", s.ident.toChars());
return setError();
}
// Replace originalSymbol with s, which updates the localCount
sc.func.localsymtab.update(s);
// The mangling change only works for D mangling
}
// else
{
/* https://issues.dlang.org/show_bug.cgi?id=21272
* If we are in a foreach body we need to extract the
@ -6943,15 +6937,19 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
else if (!exp.e1.type.deco)
{
if (exp.e1.op == EXP.variable)
// try to resolve the type
exp.e1.type = exp.e1.type.typeSemantic(exp.e1.loc, null);
if (!exp.e1.type.deco) // still couldn't resolve it
{
VarExp ve = cast(VarExp)exp.e1;
Declaration d = ve.var;
exp.error("forward reference to %s `%s`", d.kind(), d.toChars());
if (auto ve = exp.e1.isVarExp())
{
Declaration d = ve.var;
exp.error("forward reference to %s `%s`", d.kind(), d.toChars());
}
else
exp.error("forward reference to type `%s` of expression `%s`", exp.e1.type.toChars(), exp.e1.toChars());
return setError();
}
else
exp.error("forward reference to `%s`", exp.e1.toChars());
return setError();
}
exp.type = exp.e1.type.pointerTo();
@ -7327,14 +7325,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
override void visit(DeleteExp exp)
{
if (!sc.isDeprecated)
// @@@DEPRECATED_2.109@@@
// 1. Deprecated since 2.079
// 2. Error since 2.099
// 3. Removal of keyword, "delete" can be used for other identities
if (!exp.isRAII)
{
// @@@DEPRECATED_2019-02@@@
// 1. Deprecation for 1 year
// 2. Error for 1 year
// 3. Removal of keyword, "delete" can be used for other identities
if (!exp.isRAII)
deprecation(exp.loc, "The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.");
error(exp.loc, "The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.");
return setError();
}
Expression e = exp;
@ -7353,89 +7351,32 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
exp.type = Type.tvoid;
AggregateDeclaration ad = null;
Type tb = exp.e1.type.toBasetype();
switch (tb.ty)
/* Now that `delete` in user code is an error, we only get here when
* `isRAII` has been set to true for the deletion of a `scope class`. */
if (tb.ty != Tclass)
{
case Tclass:
{
auto cd = (cast(TypeClass)tb).sym;
if (cd.isCOMinterface())
{
/* Because COM classes are deleted by IUnknown.Release()
*/
exp.error("cannot `delete` instance of COM interface `%s`", cd.toChars());
return setError();
}
ad = cd;
break;
}
case Tpointer:
tb = (cast(TypePointer)tb).next.toBasetype();
if (tb.ty == Tstruct)
{
ad = (cast(TypeStruct)tb).sym;
Identifier hook = global.params.tracegc ? Id._d_delstructTrace : Id._d_delstruct;
if (!verifyHookExist(exp.loc, *sc, Id._d_delstructImpl, "deleting struct with dtor", Id.object))
return setError();
// Lower to .object._d_delstruct{,Trace}(exp.e1)
Expression id = new IdentifierExp(exp.loc, Id.empty);
id = new DotIdExp(exp.loc, id, Id.object);
auto tiargs = new Objects();
tiargs.push(exp.e1.type);
id = new DotTemplateInstanceExp(exp.loc, id, Id._d_delstructImpl, tiargs);
id = new DotIdExp(exp.loc, id, hook);
e = new CallExp(exp.loc, id, exp.e1);
/* Gag errors generated by calls to `_d_delstruct`, because they display
* internal compiler information, which is unnecessary to the user.
*/
uint errors = global.startGagging();
e = e.expressionSemantic(sc);
global.endGagging(errors);
}
break;
case Tarray:
{
Type tv = tb.nextOf().baseElemOf();
if (tv.ty == Tstruct)
{
ad = (cast(TypeStruct)tv).sym;
if (ad.dtor)
semanticTypeInfo(sc, ad.type);
}
break;
}
default:
exp.error("cannot delete type `%s`", exp.e1.type.toChars());
return setError();
}
bool err = false;
if (ad)
ClassDeclaration cd = (cast(TypeClass)tb).sym;
if (cd.isCOMinterface())
{
if (ad.dtor)
{
err |= !ad.dtor.functionSemantic();
err |= exp.checkPurity(sc, ad.dtor);
err |= exp.checkSafety(sc, ad.dtor);
err |= exp.checkNogc(sc, ad.dtor);
}
if (err)
return setError();
/* Because COM classes are deleted by IUnknown.Release()
*/
exp.error("cannot `delete` instance of COM interface `%s`", cd.toChars());
return setError();
}
if (!sc.intypeof && sc.func &&
!exp.isRAII &&
!(sc.flags & SCOPE.debug_) &&
sc.func.setUnsafe())
bool err = false;
if (cd.dtor)
{
exp.error("`%s` is not `@safe` but is used in `@safe` function `%s`", exp.toChars(), sc.func.toChars());
err = true;
err |= !cd.dtor.functionSemantic();
err |= exp.checkPurity(sc, cd.dtor);
err |= exp.checkSafety(sc, cd.dtor);
err |= exp.checkNogc(sc, cd.dtor);
}
if (err)
return setError();
@ -7457,12 +7398,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
if ((sc && sc.flags & SCOPE.Cfile) &&
exp.to && exp.to.ty == Tident &&
exp.to && (exp.to.ty == Tident || exp.to.ty == Tsarray) &&
(exp.e1.op == EXP.address || exp.e1.op == EXP.star ||
exp.e1.op == EXP.uadd || exp.e1.op == EXP.negate))
{
/* Ambiguous cases arise from CParser if type-name is just an identifier.
* ( identifier ) cast-expression
* ( identifier [expression]) cast-expression
* If we determine that `identifier` is a variable, and cast-expression
* is one of the unary operators (& * + -), then rewrite this cast
* as a binary expression.
@ -9858,7 +9800,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
VarExp ve = cast(VarExp)exp.e1;
VarDeclaration vd = ve.var.isVarDeclaration();
if (vd && (vd.onstack || vd.mynew))
if (vd && vd.onstack)
{
assert(t1.ty == Tclass);
exp.error("cannot rebind scope variables");

View File

@ -567,7 +567,8 @@ extern (C++) class FuncDeclaration : Declaration
* do existing practice. But we should examine how TypeFunction does
* it, for consistency.
*/
if (!tf.isref && isRefReturnScope(vthis.storage_class))
if (global.params.useDIP1000 != FeatureState.enabled &&
!tf.isref && isRefReturnScope(vthis.storage_class))
{
/* if `ref return scope`, evaluate to `ref` `return scope`
*/

View File

@ -991,8 +991,9 @@ public:
override void visit(VisibilityDeclaration d)
{
visibilityToBuffer(buf, d.visibility);
buf.writeByte(' ');
AttribDeclaration ad = cast(AttribDeclaration)d;
if (ad.decl.dim <= 1)
buf.writeByte(' ');
if (ad.decl.dim == 1 && (*ad.decl)[0].isVisibilityDeclaration)
visit(cast(AttribDeclaration)(*ad.decl)[0]);
else
@ -1693,17 +1694,8 @@ public:
override void visit(DtorDeclaration d)
{
if (d.storage_class & STC.trusted)
buf.writestring("@trusted ");
if (d.storage_class & STC.safe)
buf.writestring("@safe ");
if (d.storage_class & STC.nogc)
buf.writestring("@nogc ");
if (d.storage_class & STC.live)
buf.writestring("@live ");
if (d.storage_class & STC.disable)
buf.writestring("@disable ");
if (stcToBuffer(buf, d.storage_class))
buf.writeByte(' ');
buf.writestring("~this()");
bodyToBuffer(d);
}
@ -1992,29 +1984,9 @@ public:
{
buf.writeByte('"');
const o = buf.length;
for (size_t i = 0; i < e.len; i++)
foreach (i; 0 .. e.len)
{
const c = e.charAt(i);
switch (c)
{
case '"':
case '\\':
buf.writeByte('\\');
goto default;
default:
if (c <= 0xFF)
{
if (c <= 0x7F && isprint(c))
buf.writeByte(c);
else
buf.printf("\\x%02x", c);
}
else if (c <= 0xFFFF)
buf.printf("\\x%02x\\x%02x", c & 0xFF, c >> 8);
else
buf.printf("\\x%02x\\x%02x\\x%02x\\x%02x", c & 0xFF, (c >> 8) & 0xFF, (c >> 16) & 0xFF, c >> 24);
break;
}
writeCharLiteral(*buf, e.getCodeUnit(i));
}
if (hgs.ddoc)
escapeDdocString(buf, o);
@ -2113,12 +2085,6 @@ public:
buf.writeByte('.');
}
buf.writestring("new ");
if (e.newargs && e.newargs.dim)
{
buf.writeByte('(');
argsToBuffer(e.newargs, buf, hgs);
buf.writeByte(')');
}
typeToBuffer(e.newtype, null, buf, hgs);
if (e.arguments && e.arguments.dim)
{
@ -2136,12 +2102,6 @@ public:
buf.writeByte('.');
}
buf.writestring("new");
if (e.newargs && e.newargs.dim)
{
buf.writeByte('(');
argsToBuffer(e.newargs, buf, hgs);
buf.writeByte(')');
}
buf.writestring(" class ");
if (e.arguments && e.arguments.dim)
{
@ -2909,22 +2869,6 @@ string stcToString(ref StorageClass stc)
return null;
}
/// Ditto
extern (D) string trustToString(TRUST trust) pure nothrow
{
final switch (trust)
{
case TRUST.default_:
return null;
case TRUST.system:
return "@system";
case TRUST.trusted:
return "@trusted";
case TRUST.safe:
return "@safe";
}
}
private void linkageToBuffer(OutBuffer* buf, LINK linkage)
{
const s = linkageToString(linkage);
@ -3902,7 +3846,7 @@ private void typeToBufferx(Type t, OutBuffer* buf, HdrGenState* hgs)
buf.writeByte(' ');
if (t.id)
buf.writestring(t.id.toChars());
if (t.base.ty != TY.Tint32)
if (t.tok == TOK.enum_ && t.base.ty != TY.Tint32)
{
buf.writestring(" : ");
visitWithMask(t.base, t.mod, buf, hgs);

View File

@ -84,7 +84,7 @@ int parseExtAsmOperands(Parser)(Parser p, GccAsmStatement s)
case TOK.string_:
constraint = p.parsePrimaryExp();
// @@@DEPRECATED@@@
// @@@DEPRECATED_2.101@@@
// Old parser allowed omitting parentheses around the expression.
// Deprecated in 2.091. Can be made permanent error after 2.100
if (p.token.value != TOK.leftParenthesis)

View File

@ -115,7 +115,6 @@ immutable Msgtable[] msgtable =
{ "line" },
{ "empty", "" },
{ "p" },
{ "q" },
{ "__vptr" },
{ "__monitor" },
{ "gate", "__gate" },
@ -311,9 +310,6 @@ immutable Msgtable[] msgtable =
{ "__ArrayPostblit" },
{ "__ArrayDtor" },
{ "_d_delThrowable" },
{ "_d_delstructImpl" },
{ "_d_delstruct" },
{ "_d_delstructTrace" },
{ "_d_assert_fail" },
{ "dup" },
{ "_aaApply" },

View File

@ -260,3 +260,50 @@ Expression castCallAmbiguity(Expression e, Scope* sc)
}
}
/********************************************
* Implement the C11 notion of function equivalence,
* which allows prototyped functions to match K+R functions,
* even though they are different.
* Params:
* tf1 = type of first function
* tf2 = type of second function
* Returns:
* true if C11 considers them equivalent
*/
bool cFuncEquivalence(TypeFunction tf1, TypeFunction tf2)
{
if (tf1.equals(tf2))
return true;
if (tf1.linkage != tf2.linkage)
return false;
// Allow func(void) to match func()
if (tf1.parameterList.length == 0 && tf2.parameterList.length == 0)
return true;
if (!tf1.parameterList.hasIdentifierList &&
!tf2.parameterList.hasIdentifierList)
return false; // both functions are prototyped
// Otherwise ignore variadicness, as K+R functions are all variadic
if (!tf1.nextOf().equals(tf2.nextOf()))
return false; // function return types don't match
if (tf1.parameterList.length != tf2.parameterList.length)
return false;
foreach (i, fparam ; tf1.parameterList)
{
Type t1 = fparam.type;
Type t2 = tf2.parameterList[i].type;
if (!t1.equals(t2))
return false;
}
//printf("t1: %s\n", tf1.toChars());
//printf("t2: %s\n", tf2.toChars());
return true;
}

View File

@ -590,7 +590,11 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
i.exp = ErrorExp.get();
}
}
Type et = i.exp.type;
const errors = global.startGagging();
i.exp = i.exp.implicitCastTo(sc, t);
if (global.endGagging(errors))
currExp.error("cannot implicitly convert expression `%s` of type `%s` to `%s`", currExp.toChars(), et.toChars(), t.toChars());
}
L1:
if (i.exp.op == EXP.error)

View File

@ -38,172 +38,6 @@ import dmd.utils;
nothrow:
private enum LS = 0x2028; // UTF line separator
private enum PS = 0x2029; // UTF paragraph separator
/********************************************
* Do our own char maps
*/
private static immutable cmtable = () {
ubyte[256] table;
foreach (const c; 0 .. table.length)
{
if ('0' <= c && c <= '7')
table[c] |= CMoctal;
if (c_isxdigit(c))
table[c] |= CMhex;
if (c_isalnum(c) || c == '_')
table[c] |= CMidchar;
switch (c)
{
case 'x': case 'X':
case 'b': case 'B':
table[c] |= CMzerosecond;
break;
case '0': .. case '9':
case 'e': case 'E':
case 'f': case 'F':
case 'l': case 'L':
case 'p': case 'P':
case 'u': case 'U':
case 'i':
case '.':
case '_':
table[c] |= CMzerosecond | CMdigitsecond;
break;
default:
break;
}
switch (c)
{
case '\\':
case '\n':
case '\r':
case 0:
case 0x1A:
case '\'':
break;
default:
if (!(c & 0x80))
table[c] |= CMsinglechar;
break;
}
}
return table;
}();
private
{
enum CMoctal = 0x1;
enum CMhex = 0x2;
enum CMidchar = 0x4;
enum CMzerosecond = 0x8;
enum CMdigitsecond = 0x10;
enum CMsinglechar = 0x20;
}
private bool isoctal(const char c) pure @nogc @safe
{
return (cmtable[c] & CMoctal) != 0;
}
private bool ishex(const char c) pure @nogc @safe
{
return (cmtable[c] & CMhex) != 0;
}
private bool isidchar(const char c) pure @nogc @safe
{
return (cmtable[c] & CMidchar) != 0;
}
private bool isZeroSecond(const char c) pure @nogc @safe
{
return (cmtable[c] & CMzerosecond) != 0;
}
private bool isDigitSecond(const char c) pure @nogc @safe
{
return (cmtable[c] & CMdigitsecond) != 0;
}
private bool issinglechar(const char c) pure @nogc @safe
{
return (cmtable[c] & CMsinglechar) != 0;
}
private bool c_isxdigit(const int c) pure @nogc @safe
{
return (( c >= '0' && c <= '9') ||
( c >= 'a' && c <= 'f') ||
( c >= 'A' && c <= 'F'));
}
private bool c_isalnum(const int c) pure @nogc @safe
{
return (( c >= '0' && c <= '9') ||
( c >= 'a' && c <= 'z') ||
( c >= 'A' && c <= 'Z'));
}
unittest
{
//printf("lexer.unittest\n");
/* 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);
TOK tok;
tok = lex1.nextToken();
//printf("tok == %s, %d, %d\n", Token::toChars(tok), tok, TOK.int32);
assert(tok == TOK.int32);
tok = lex1.nextToken();
assert(tok == TOK.endOfFile);
tok = lex1.nextToken();
assert(tok == TOK.endOfFile);
tok = lex1.nextToken();
assert(tok == TOK.endOfFile);
}
unittest
{
// We don't want to see Lexer error output during these tests.
uint errors = global.startGagging();
scope(exit) global.endGagging(errors);
// Test malformed input: even malformed input should end in a TOK.endOfFile.
static immutable char[][] testcases =
[ // Testcase must end with 0 or 0x1A.
[0], // not malformed, but pathological
['\'', 0],
['\'', 0x1A],
['{', '{', 'q', '{', 0],
[0xFF, 0],
[0xFF, 0x80, 0],
[0xFF, 0xFF, 0],
[0xFF, 0xFF, 0],
['x', '"', 0x1A],
];
foreach (testcase; testcases)
{
scope Lexer lex2 = new Lexer(null, testcase.ptr, 0, testcase.length-1, 0, 0);
TOK tok = lex2.nextToken();
size_t iterations = 1;
while ((tok != TOK.endOfFile) && (iterations++ < testcase.length))
{
tok = lex2.nextToken();
}
assert(tok == TOK.endOfFile);
tok = lex2.nextToken();
assert(tok == TOK.endOfFile);
}
}
version (DMDLIB)
{
version = LocOffset;
@ -440,7 +274,7 @@ class Lexer
if (issinglechar(p[1]) && p[2] == '\'')
{
t.unsvalue = p[1]; // simple one character literal
t.value = Ccompile ? TOK.int32Literal : TOK.charLiteral;
t.value = TOK.charLiteral;
p += 3;
}
else if (Ccompile)
@ -1716,9 +1550,11 @@ class Lexer
if (*p == '"')
p++;
else if (hereid)
error("delimited string must end in %s\"", hereid.toChars());
error("delimited string must end in `%s\"`", hereid.toChars());
else if (isspace(delimright))
error("delimited string must end in `\"`");
else
error("delimited string must end in %c\"", delimright);
error("delimited string must end in `%c\"`", delimright);
result.setString(stringbuffer);
stringPostfix(result);
}
@ -2030,7 +1866,7 @@ class Lexer
default:
assert(0);
}
t.value = TOK.int32Literal;
t.value = n == 1 ? TOK.charLiteral : TOK.int32Literal;
t.unsvalue = u;
}
@ -2113,7 +1949,11 @@ class Lexer
if (p[1] == '.')
goto Ldone; // if ".."
if (isalpha(p[1]) || p[1] == '_' || p[1] & 0x80)
{
if (Ccompile && (p[1] == 'f' || p[1] == 'F' || p[1] == 'l' || p[1] == 'L'))
goto Lreal; // if `0.f` or `0.L`
goto Ldone; // if ".identifier" or ".unicode"
}
goto Lreal; // '.' is part of current token
case 'i':
case 'f':
@ -2182,7 +2022,12 @@ class Lexer
if (p[1] == '.')
goto Ldone; // if ".."
if (base <= 10 && n > 0 && (isalpha(p[1]) || p[1] == '_' || p[1] & 0x80))
{
if (Ccompile && base == 10 &&
(p[1] == 'f' || p[1] == 'F' || p[1] == 'l' || p[1] == 'L'))
goto Lreal; // if `1.f` or `1.L`
goto Ldone; // if ".identifier" or ".unicode"
}
if (base == 16 && (!ishex(p[1]) || p[1] == '_' || p[1] & 0x80))
goto Ldone; // if ".identifier" or ".unicode"
if (base == 2)
@ -2421,11 +2266,6 @@ class Lexer
flags = cast(FLAGS)(flags | f);
}
void overflow()
{
error("integer overflow");
}
TOK result = TOK.int32Literal; // default
switch (flags)
{
@ -2438,71 +2278,35 @@ class Lexer
* First that fits: int, unsigned, long, unsigned long,
* long long, unsigned long long
*/
if (longsize == 4)
{
if (n & 0x8000000000000000L)
result = TOK.uns64Literal;
else if (n & 0xFFFFFFFF00000000L)
result = TOK.int64Literal;
else if (n & 0x80000000)
result = TOK.uns32Literal;
else
result = TOK.int32Literal;
}
if (n & 0x8000000000000000L)
result = TOK.uns64Literal; // unsigned long
else if (n & 0xFFFFFFFF00000000L)
result = TOK.int64Literal; // long
else if (n & 0x80000000)
result = TOK.uns32Literal;
else
{
if (n & 0x8000000000000000L)
result = TOK.uns64Literal; // unsigned long
else if (n & 0xFFFFFFFF00000000L)
result = TOK.int64Literal; // long
else if (n & 0x80000000)
result = TOK.uns32Literal;
else
result = TOK.int32Literal;
}
result = TOK.int32Literal;
break;
case FLAGS.decimal:
/* First that fits: int, long, long long
*/
if (longsize == 4)
{
if (n & 0x8000000000000000L)
result = TOK.uns64Literal;
else if (n & 0xFFFFFFFF80000000L)
result = TOK.int64Literal;
else
result = TOK.int32Literal;
}
if (n & 0x8000000000000000L)
result = TOK.uns64Literal; // unsigned long
else if (n & 0xFFFFFFFF80000000L)
result = TOK.int64Literal; // long
else
{
if (n & 0x8000000000000000L)
result = TOK.uns64Literal; // unsigned long
else if (n & 0xFFFFFFFF80000000L)
result = TOK.int64Literal; // long
else
result = TOK.int32Literal;
}
result = TOK.int32Literal;
break;
case FLAGS.octalhex | FLAGS.unsigned:
case FLAGS.decimal | FLAGS.unsigned:
/* First that fits: unsigned, unsigned long, unsigned long long
*/
if (longsize == 4)
{
if (n & 0xFFFFFFFF00000000L)
result = TOK.uns64Literal;
else
result = TOK.uns32Literal;
}
if (n & 0xFFFFFFFF00000000L)
result = TOK.uns64Literal; // unsigned long
else
{
if (n & 0xFFFFFFFF00000000L)
result = TOK.uns64Literal; // unsigned long
else
result = TOK.uns32Literal;
}
result = TOK.uns32Literal;
break;
case FLAGS.decimal | FLAGS.long_:
@ -2510,19 +2314,14 @@ class Lexer
*/
if (longsize == 4)
{
if (n & 0x8000000000000000L)
overflow();
else if (n & 0xFFFFFFFF_80000000L)
if (n & 0xFFFFFFFF_80000000L)
result = TOK.int64Literal;
else
result = TOK.int32Literal; // long
result = TOK.int32Literal; // long
}
else
{
if (n & 0x8000000000000000L)
overflow();
else
result = TOK.int64Literal; // long
result = TOK.int64Literal; // long
}
break;
@ -3353,6 +3152,11 @@ class Lexer
}
}
/******************************* Private *****************************************/
private:
/// Support for `__DATE__`, `__TIME__`, and `__TIMESTAMP__`
private struct TimeStampInfo
{
@ -3389,6 +3193,121 @@ private struct TimeStampInfo
}
}
private enum LS = 0x2028; // UTF line separator
private enum PS = 0x2029; // UTF paragraph separator
/********************************************
* Do our own char maps
*/
private static immutable cmtable = ()
{
ubyte[256] table;
foreach (const c; 0 .. table.length)
{
if ('0' <= c && c <= '7')
table[c] |= CMoctal;
if (c_isxdigit(c))
table[c] |= CMhex;
if (c_isalnum(c) || c == '_')
table[c] |= CMidchar;
switch (c)
{
case 'x': case 'X':
case 'b': case 'B':
table[c] |= CMzerosecond;
break;
case '0': .. case '9':
case 'e': case 'E':
case 'f': case 'F':
case 'l': case 'L':
case 'p': case 'P':
case 'u': case 'U':
case 'i':
case '.':
case '_':
table[c] |= CMzerosecond | CMdigitsecond;
break;
default:
break;
}
switch (c)
{
case '\\':
case '\n':
case '\r':
case 0:
case 0x1A:
case '\'':
break;
default:
if (!(c & 0x80))
table[c] |= CMsinglechar;
break;
}
}
return table;
}();
private
{
enum CMoctal = 0x1;
enum CMhex = 0x2;
enum CMidchar = 0x4;
enum CMzerosecond = 0x8;
enum CMdigitsecond = 0x10;
enum CMsinglechar = 0x20;
}
private bool isoctal(const char c) pure @nogc @safe
{
return (cmtable[c] & CMoctal) != 0;
}
private bool ishex(const char c) pure @nogc @safe
{
return (cmtable[c] & CMhex) != 0;
}
private bool isidchar(const char c) pure @nogc @safe
{
return (cmtable[c] & CMidchar) != 0;
}
private bool isZeroSecond(const char c) pure @nogc @safe
{
return (cmtable[c] & CMzerosecond) != 0;
}
private bool isDigitSecond(const char c) pure @nogc @safe
{
return (cmtable[c] & CMdigitsecond) != 0;
}
private bool issinglechar(const char c) pure @nogc @safe
{
return (cmtable[c] & CMsinglechar) != 0;
}
private bool c_isxdigit(const int c) pure @nogc @safe
{
return (( c >= '0' && c <= '9') ||
( c >= 'a' && c <= 'f') ||
( c >= 'A' && c <= 'F'));
}
private bool c_isalnum(const int c) pure @nogc @safe
{
return (( c >= '0' && c <= '9') ||
( c >= 'a' && c <= 'z') ||
( c >= 'A' && c <= 'Z'));
}
/******************************* Unittest *****************************************/
unittest
{
import dmd.console;
@ -3441,6 +3360,7 @@ unittest
diagnosticHandler = null;
}
unittest
{
import dmd.console;
@ -3510,3 +3430,59 @@ unittest
diagnosticHandler = null;
}
unittest
{
//printf("lexer.unittest\n");
/* 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);
TOK tok;
tok = lex1.nextToken();
//printf("tok == %s, %d, %d\n", Token::toChars(tok), tok, TOK.int32);
assert(tok == TOK.int32);
tok = lex1.nextToken();
assert(tok == TOK.endOfFile);
tok = lex1.nextToken();
assert(tok == TOK.endOfFile);
tok = lex1.nextToken();
assert(tok == TOK.endOfFile);
}
unittest
{
// We don't want to see Lexer error output during these tests.
uint errors = global.startGagging();
scope(exit) global.endGagging(errors);
// Test malformed input: even malformed input should end in a TOK.endOfFile.
static immutable char[][] testcases =
[ // Testcase must end with 0 or 0x1A.
[0], // not malformed, but pathological
['\'', 0],
['\'', 0x1A],
['{', '{', 'q', '{', 0],
[0xFF, 0],
[0xFF, 0x80, 0],
[0xFF, 0xFF, 0],
[0xFF, 0xFF, 0],
['x', '"', 0x1A],
];
foreach (testcase; testcases)
{
scope Lexer lex2 = new Lexer(null, testcase.ptr, 0, testcase.length-1, 0, 0);
TOK tok = lex2.nextToken();
size_t iterations = 1;
while ((tok != TOK.endOfFile) && (iterations++ < testcase.length))
{
tok = lex2.nextToken();
}
assert(tok == TOK.endOfFile);
tok = lex2.nextToken();
assert(tok == TOK.endOfFile);
}
}

View File

@ -206,6 +206,32 @@ string MODtoString(MOD mod) nothrow pure
}
}
/*************************************************
* Pick off one of the trust flags from trust,
* and return a string representation of it.
*/
string trustToString(TRUST trust) pure nothrow @nogc @safe
{
final switch (trust)
{
case TRUST.default_:
return null;
case TRUST.system:
return "@system";
case TRUST.trusted:
return "@trusted";
case TRUST.safe:
return "@safe";
}
}
unittest
{
assert(trustToString(TRUST.default_) == "");
assert(trustToString(TRUST.system) == "@system");
assert(trustToString(TRUST.trusted) == "@trusted");
assert(trustToString(TRUST.safe) == "@safe");
}
/************************************
* Convert MODxxxx to STCxxx
@ -400,7 +426,7 @@ extern (C++) abstract class Type : ASTNode
extern (C++) __gshared Type[TMAX] basic;
extern (D) __gshared StringTable!Type stringtable;
extern (D) private __gshared ubyte[TMAX] sizeTy = ()
extern (D) private static immutable ubyte[TMAX] sizeTy = ()
{
ubyte[TMAX] sizeTy = __traits(classInstanceSize, TypeBasic);
sizeTy[Tsarray] = __traits(classInstanceSize, TypeSArray);
@ -2604,6 +2630,10 @@ extern (C++) abstract class Type : ASTNode
default:
assert(0);
}
// @@@DEPRECATED_2.117@@@
// Deprecated in 2.097 - Can be made an error from 2.117.
// The deprecation period is longer than usual as `cfloat`,
// `cdouble`, and `creal` were quite widely used.
if (t.iscomplex())
{
deprecation(loc, "use of complex type `%s` is deprecated, use `std.complex.Complex!(%s)` instead",
@ -4219,9 +4249,9 @@ extern (C++) final class TypeFunction : TypeNext
this.trust = TRUST.default_;
if (stc & STC.safe)
this.trust = TRUST.safe;
if (stc & STC.system)
else if (stc & STC.system)
this.trust = TRUST.system;
if (stc & STC.trusted)
else if (stc & STC.trusted)
this.trust = TRUST.trusted;
}
@ -6346,7 +6376,7 @@ extern (C++) final class TypeClass : Type
/* Conversion derived to const(base)
*/
int offset = 0;
if (to.isBaseOf(this, &offset) && offset == 0 && MODimplicitConv(mod, to.mod))
if (to.isBaseOf(this, &offset) && MODimplicitConv(mod, to.mod))
{
// Disallow:
// derived to base
@ -7253,10 +7283,9 @@ void attributesApply(const TypeFunction tf, void delegate(string) dg, TRUSTforma
if (trustAttrib == TRUST.default_)
{
if (trustFormat == TRUSTformatSystem)
trustAttrib = TRUST.system;
else
return; // avoid calling with an empty string
if (trustFormat != TRUSTformatSystem)
return;
trustAttrib = TRUST.system; // avoid calling with an empty string
}
dg(trustToString(trustAttrib));

View File

@ -84,20 +84,6 @@ public:
}
f.printGCUsage(e.loc, "setting `length` may cause a GC allocation");
}
else if (fd.ident == Id._d_delstruct)
{
// In expressionsem.d, `delete s` was lowererd to `_d_delstruct(s)`.
// The following code handles the call like the original expression,
// so the error is menaningful to the user.
if (f.setGC())
{
e.error("cannot use `delete` in `@nogc` %s `%s`", f.kind(),
f.toPrettyChars());
err = true;
return;
}
f.printGCUsage(e.loc, "`delete` requires the GC");
}
}
override void visit(ArrayLiteralExp e)
@ -158,32 +144,8 @@ public:
return; // delete for scope allocated class object
}
Type tb = e.e1.type.toBasetype();
AggregateDeclaration ad = null;
switch (tb.ty)
{
case Tclass:
ad = (cast(TypeClass)tb).sym;
break;
case Tpointer:
tb = (cast(TypePointer)tb).next.toBasetype();
if (tb.ty == Tstruct)
ad = (cast(TypeStruct)tb).sym;
break;
default:
break;
}
if (f.setGC())
{
e.error("cannot use `delete` in `@nogc` %s `%s`",
f.kind(), f.toPrettyChars());
err = true;
return;
}
f.printGCUsage(e.loc, "`delete` requires the GC");
// Semantic should have already handled this case.
assert(0);
}
override void visit(IndexExp e)

View File

@ -272,31 +272,17 @@ private Expression checkAliasThisForRhs(AggregateDeclaration ad, Scope* sc, BinE
*/
Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
{
extern (C++) final class OpOverload : Visitor
{
alias visit = Visitor.visit;
public:
Scope* sc;
EXP* pop;
Expression result;
extern (D) this(Scope* sc, EXP* pop)
{
this.sc = sc;
this.pop = pop;
}
override void visit(Expression e)
Expression visit(Expression e)
{
assert(0);
}
override void visit(UnaExp e)
Expression visitUna(UnaExp e)
{
//printf("UnaExp::op_overload() (%s)\n", e.toChars());
if (e.e1.op == EXP.array)
Expression result;
if (auto ae = e.e1.isArrayExp())
{
ArrayExp ae = cast(ArrayExp)e.e1;
ae.e1 = ae.e1.expressionSemantic(sc);
ae.e1 = resolveProperties(sc, ae.e1);
Expression ae1old = ae.e1;
@ -304,15 +290,13 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
IntervalExp ie = null;
if (maybeSlice && ae.arguments.dim)
{
assert((*ae.arguments)[0].op == EXP.interval);
ie = cast(IntervalExp)(*ae.arguments)[0];
ie = (*ae.arguments)[0].isIntervalExp();
}
while (true)
{
if (ae.e1.op == EXP.error)
{
result = ae.e1;
return;
return ae.e1;
}
Expression e0 = null;
Expression ae1save = ae.e1;
@ -328,7 +312,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
if (!result) // op(a[i..j]) might be: a.opSliceUnary!(op)(i, j)
goto Lfallback;
if (result.op == EXP.error)
return;
return result;
/* Rewrite op(a[arguments]) as:
* a.opIndexUnary!(op)(arguments)
*/
@ -342,8 +326,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
result = result.expressionSemantic(sc);
if (result)
{
result = Expression.combine(e0, result);
return;
return Expression.combine(e0, result);
}
}
Lfallback:
@ -352,7 +335,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
// Deal with $
result = resolveOpDollar(sc, ae, ie, &e0);
if (result.op == EXP.error)
return;
return result;
/* Rewrite op(a[i..j]) as:
* a.opSliceUnary!(op)(i, j)
*/
@ -367,7 +350,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
result = new CallExp(e.loc, result, a);
result = result.expressionSemantic(sc);
result = Expression.combine(e0, result);
return;
return result;
}
// Didn't find it. Forward to aliasthis
if (ad.aliasthis && !isRecursiveAliasThis(ae.att1, ae.e1.type))
@ -388,8 +371,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
e.e1 = resolveProperties(sc, e.e1);
if (e.e1.op == EXP.error)
{
result = e.e1;
return;
return e.e1;
}
AggregateDeclaration ad = isAggregate(e.e1.type);
if (ad)
@ -405,7 +387,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
result = new DotTemplateInstanceExp(e.loc, e.e1, fd.ident, tiargs);
result = new CallExp(e.loc, result);
result = result.expressionSemantic(sc);
return;
return result;
}
// D1-style operator overloads, deprecated
if (e.op != EXP.prePlusPlus && e.op != EXP.preMinusMinus)
@ -420,7 +402,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
e.deprecation("`%s` is deprecated. Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr);
// Rewrite +e1 as e1.add()
result = build_overload(e.loc, sc, e.e1, null, fd);
return;
return result;
}
}
// Didn't find it. Forward to aliasthis
@ -434,12 +416,13 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
UnaExp ue = cast(UnaExp)e.copy();
ue.e1 = e1;
result = ue.trySemantic(sc);
return;
return result;
}
}
return result;
}
override void visit(ArrayExp ae)
Expression visitArray(ArrayExp ae)
{
//printf("ArrayExp::op_overload() (%s)\n", ae.toChars());
ae.e1 = ae.e1.expressionSemantic(sc);
@ -449,15 +432,14 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
IntervalExp ie = null;
if (maybeSlice && ae.arguments.dim)
{
assert((*ae.arguments)[0].op == EXP.interval);
ie = cast(IntervalExp)(*ae.arguments)[0];
ie = (*ae.arguments)[0].isIntervalExp();
}
Expression result;
while (true)
{
if (ae.e1.op == EXP.error)
{
result = ae.e1;
return;
return ae.e1;
}
Expression e0 = null;
Expression ae1save = ae.e1;
@ -475,14 +457,14 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
{
result = new SliceExp(ae.loc, ae.e1, ie);
result = result.expressionSemantic(sc);
return;
return result;
}
// Convert to IndexExp
if (ae.arguments.dim == 1)
{
result = new IndexExp(ae.loc, ae.e1, (*ae.arguments)[0]);
result = result.expressionSemantic(sc);
return;
return result;
}
}
break;
@ -494,7 +476,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
if (!result) // a[i..j] might be: a.opSlice(i, j)
goto Lfallback;
if (result.op == EXP.error)
return;
return result;
/* Rewrite e1[arguments] as:
* e1.opIndex(arguments)
*/
@ -507,8 +489,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
result = result.expressionSemantic(sc);
if (result)
{
result = Expression.combine(e0, result);
return;
return Expression.combine(e0, result);
}
}
Lfallback:
@ -517,7 +498,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
result = new SliceExp(ae.loc, ae.e1, ie);
result = result.expressionSemantic(sc);
result = Expression.combine(e0, result);
return;
return result;
}
if (maybeSlice && search_function(ad, Id.slice))
{
@ -529,7 +510,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
if (!e0 && !search_function(ad, Id.dollar)) {
ae.loc.errorSupplemental("Aggregate declaration '%s' does not define 'opDollar'", ae.e1.toChars());
}
return;
return result;
}
/* Rewrite a[i..j] as:
* a.opSlice(i, j)
@ -544,7 +525,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
result = new CallExp(ae.loc, result, a);
result = result.expressionSemantic(sc);
result = Expression.combine(e0, result);
return;
return result;
}
// Didn't find it. Forward to aliasthis
if (ad.aliasthis && !isRecursiveAliasThis(ae.att1, ae.e1.type))
@ -561,15 +542,17 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
}
ae.e1 = ae1old; // recovery
ae.lengthVar = null;
return result;
}
/***********************************************
* This is mostly the same as UnaryExp::op_overload(), but has
* a different rewrite.
*/
override void visit(CastExp e)
Expression visitCast(CastExp e)
{
//printf("CastExp::op_overload() (%s)\n", e.toChars());
Expression result;
AggregateDeclaration ad = isAggregate(e.e1.type);
if (ad)
{
@ -586,8 +569,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
if (fd.isFuncDeclaration())
{
// Rewrite as: e1.opCast()
result = build_overload(e.loc, sc, e.e1, null, fd);
return;
return build_overload(e.loc, sc, e.e1, null, fd);
}
}
auto tiargs = new Objects();
@ -595,7 +577,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
result = new DotTemplateInstanceExp(e.loc, e.e1, fd.ident, tiargs);
result = new CallExp(e.loc, result);
result = result.expressionSemantic(sc);
return;
return result;
}
// Didn't find it. Forward to aliasthis
if (ad.aliasthis && !isRecursiveAliasThis(e.att1, e.e1.type))
@ -608,13 +590,14 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
result = e.copy();
(cast(UnaExp)result).e1 = e1;
result = result.op_overload(sc);
return;
return result;
}
}
}
return result;
}
override void visit(BinExp e)
Expression visitBin(BinExp e)
{
//printf("BinExp::op_overload() (%s)\n", e.toChars());
Identifier id = opId(e);
@ -635,7 +618,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
(sd.hasBlitAssign && !e.e2.isLvalue())))
{
/* This is bitwise struct assignment. */
return;
return null;
}
}
Dsymbol s = null;
@ -645,7 +628,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
{
// Bug4099 fix
if (ad1 && search_function(ad1, Id.opUnary))
return;
return null;
}
if (e.op != EXP.equal && e.op != EXP.notEqual && e.op != EXP.assign && e.op != EXP.plusPlus && e.op != EXP.minusMinus)
{
@ -657,8 +640,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
if (s && !s.isTemplateDeclaration())
{
e.e1.error("`%s.opBinary` isn't a template", e.e1.toChars());
result = ErrorExp.get();
return;
return ErrorExp.get();
}
}
if (ad2)
@ -667,8 +649,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
if (s_r && !s_r.isTemplateDeclaration())
{
e.e2.error("`%s.opBinaryRight` isn't a template", e.e2.toChars());
result = ErrorExp.get();
return;
return ErrorExp.get();
}
if (s_r && s_r == s) // https://issues.dlang.org/show_bug.cgi?id=12778
s_r = null;
@ -735,8 +716,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, &args2);
if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
{
result = ErrorExp.get();
return;
return ErrorExp.get();
}
}
FuncDeclaration lastf = m.lastf;
@ -745,8 +725,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, &args1);
if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
{
result = ErrorExp.get();
return;
return ErrorExp.get();
}
}
if (m.count > 1)
@ -766,19 +745,18 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
// as unary, but it's implemented as a binary.
// Rewrite (e1 ++ e2) as e1.postinc()
// Rewrite (e1 -- e2) as e1.postdec()
result = build_overload(e.loc, sc, e.e1, null, m.lastf ? m.lastf : s);
return build_overload(e.loc, sc, e.e1, null, m.lastf ? m.lastf : s);
}
else if (lastf && m.lastf == lastf || !s_r && m.last == MATCH.nomatch)
{
// Rewrite (e1 op e2) as e1.opfunc(e2)
result = build_overload(e.loc, sc, e.e1, e.e2, m.lastf ? m.lastf : s);
return build_overload(e.loc, sc, e.e1, e.e2, m.lastf ? m.lastf : s);
}
else
{
// Rewrite (e1 op e2) as e2.opfunc_r(e1)
result = build_overload(e.loc, sc, e.e2, e.e1, m.lastf ? m.lastf : s_r);
return build_overload(e.loc, sc, e.e2, e.e1, m.lastf ? m.lastf : s_r);
}
return;
}
L1:
version (all)
@ -820,8 +798,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
functionResolve(m, s_r, e.loc, sc, tiargs, e.e1.type, &args2);
if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
{
result = ErrorExp.get();
return;
return ErrorExp.get();
}
}
FuncDeclaration lastf = m.lastf;
@ -830,8 +807,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
functionResolve(m, s, e.loc, sc, tiargs, e.e2.type, &args1);
if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
{
result = ErrorExp.get();
return;
return ErrorExp.get();
}
}
if (m.count > 1)
@ -847,27 +823,26 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
if (lastf && m.lastf == lastf || !s && m.last == MATCH.nomatch)
{
// Rewrite (e1 op e2) as e1.opfunc_r(e2)
result = build_overload(e.loc, sc, e.e1, e.e2, m.lastf ? m.lastf : s_r);
return build_overload(e.loc, sc, e.e1, e.e2, m.lastf ? m.lastf : s_r);
}
else
{
// Rewrite (e1 op e2) as e2.opfunc(e1)
result = build_overload(e.loc, sc, e.e2, e.e1, m.lastf ? m.lastf : s);
Expression result = build_overload(e.loc, sc, e.e2, e.e1, m.lastf ? m.lastf : s);
// When reversing operands of comparison operators,
// need to reverse the sense of the op
if (pop)
*pop = reverseRelation(e.op);
return result;
}
return;
}
}
}
Expression tempResult;
Expression rewrittenLhs;
if (!(e.op == EXP.assign && ad2 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943
{
result = checkAliasThisForLhs(ad1, sc, e);
if (result)
if (Expression result = checkAliasThisForLhs(ad1, sc, e))
{
/* https://issues.dlang.org/show_bug.cgi?id=19441
*
@ -880,43 +855,42 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
* one of the members, hence the `ad1.fields.dim == 2 && ad1.vthis`
* condition.
*/
if (e.op != EXP.assign || e.e1.op == EXP.type)
return;
if (result.op != EXP.assign)
return result; // i.e: Rewrote `e1 = e2` -> `e1(e2)`
if (ad1.fields.dim == 1 || (ad1.fields.dim == 2 && ad1.vthis))
auto ae = result.isAssignExp();
if (ae.e1.op != EXP.dotVariable)
return result; // i.e: Rewrote `e1 = e2` -> `e1() = e2`
auto dve = ae.e1.isDotVarExp();
if (auto ad = dve.var.isMember2())
{
auto var = ad1.aliasthis.sym.isVarDeclaration();
if (var && var.type == ad1.fields[0].type)
return;
auto func = ad1.aliasthis.sym.isFuncDeclaration();
auto tf = cast(TypeFunction)(func.type);
if (tf.isref && ad1.fields[0].type == tf.next)
return;
// i.e: Rewrote `e1 = e2` -> `e1.some.var = e2`
// Ensure that `var` is the only field member in `ad`
if (ad.fields.dim == 1 || (ad.fields.dim == 2 && ad.vthis))
{
if (dve.var == ad.aliasthis.sym)
return result;
}
}
tempResult = result;
rewrittenLhs = ae.e1;
}
}
if (!(e.op == EXP.assign && ad1 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943
{
result = checkAliasThisForRhs(ad2, sc, e);
if (result)
return;
if (Expression result = checkAliasThisForRhs(ad2, sc, e))
return result;
}
// @@@DEPRECATED_2019-02@@@
// 1. Deprecation for 1 year
// 2. Turn to error after
if (tempResult)
if (rewrittenLhs)
{
// move this line where tempResult is assigned to result and turn to error when derecation period is over
e.deprecation("Cannot use `alias this` to partially initialize variable `%s` of type `%s`. Use `%s`", e.e1.toChars(), ad1.toChars(), (cast(BinExp)tempResult).e1.toChars());
// delete this line when deprecation period is over
result = tempResult;
e.error("cannot use `alias this` to partially initialize variable `%s` of type `%s`. Use `%s`",
e.e1.toChars(), ad1.toChars(), rewrittenLhs.toChars());
return ErrorExp.get();
}
return null;
}
override void visit(EqualExp e)
Expression visitEqual(EqualExp e)
{
//printf("EqualExp::op_overload() (%s)\n", e.toChars());
Type t1 = e.e1.type.toBasetype();
@ -929,7 +903,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
if ((t1.ty == Tarray || t1.ty == Tsarray) &&
(t2.ty == Tarray || t2.ty == Tsarray))
{
return;
return null;
}
/* Check for class equality with null literal or typeof(null).
@ -940,14 +914,13 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
e.error("use `%s` instead of `%s` when comparing with `null`",
EXPtoString(e.op == EXP.equal ? EXP.identity : EXP.notIdentity).ptr,
EXPtoString(e.op).ptr);
result = ErrorExp.get();
return;
return ErrorExp.get();
}
if (t1.ty == Tclass && t2.ty == Tnull ||
t1.ty == Tnull && t2.ty == Tclass)
{
// Comparing a class with typeof(null) should not call opEquals
return;
return null;
}
/* Check for class equality.
@ -973,26 +946,25 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
if (cd2.isInterfaceDeclaration())
e2x = new CastExp(e.loc, e.e2, t2.isMutable() ? to : to.constOf());
result = new IdentifierExp(e.loc, Id.empty);
Expression result = new IdentifierExp(e.loc, Id.empty);
result = new DotIdExp(e.loc, result, Id.object);
result = new DotIdExp(e.loc, result, Id.eq);
result = new CallExp(e.loc, result, e1x, e2x);
if (e.op == EXP.notEqual)
result = new NotExp(e.loc, result);
result = result.expressionSemantic(sc);
return;
return result;
}
}
result = compare_overload(e, sc, Id.eq, null);
if (result)
if (Expression result = compare_overload(e, sc, Id.eq, null))
{
if (lastComma(result).op == EXP.call && e.op == EXP.notEqual)
{
result = new NotExp(result.loc, result);
result = result.expressionSemantic(sc);
}
return;
return result;
}
/* Check for pointer equality.
@ -1008,27 +980,25 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
* as the backend input.
*/
auto op2 = e.op == EXP.equal ? EXP.identity : EXP.notIdentity;
result = new IdentityExp(op2, e.loc, e.e1, e.e2);
result = result.expressionSemantic(sc);
return;
Expression r = new IdentityExp(op2, e.loc, e.e1, e.e2);
return r.expressionSemantic(sc);
}
/* Check for struct equality without opEquals.
*/
if (t1.ty == Tstruct && t2.ty == Tstruct)
{
auto sd = (cast(TypeStruct)t1).sym;
if (sd != (cast(TypeStruct)t2).sym)
return;
auto sd = t1.isTypeStruct().sym;
if (sd != t2.isTypeStruct().sym)
return null;
import dmd.clone : needOpEquals;
if (!global.params.fieldwise && !needOpEquals(sd))
{
// Use bitwise equality.
auto op2 = e.op == EXP.equal ? EXP.identity : EXP.notIdentity;
result = new IdentityExp(op2, e.loc, e.e1, e.e2);
result = result.expressionSemantic(sc);
return;
Expression r = new IdentityExp(op2, e.loc, e.e1, e.e2);
return r.expressionSemantic(sc);
}
/* Do memberwise equality.
@ -1042,10 +1012,10 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
* also compare the parent class's equality. Otherwise, compares
* the identity of parent context through void*.
*/
if (e.att1 && t1.equivalent(e.att1)) return;
if (e.att2 && t2.equivalent(e.att2)) return;
if (e.att1 && t1.equivalent(e.att1)) return null;
if (e.att2 && t2.equivalent(e.att2)) return null;
e = cast(EqualExp)e.copy();
e = e.copy().isEqualExp();
if (!e.att1) e.att1 = t1;
if (!e.att2) e.att2 = t2;
e.e1 = new DotIdExp(e.loc, e.e1, Id._tupleof);
@ -1053,38 +1023,38 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
auto sc2 = sc.push();
sc2.flags |= SCOPE.noaccesscheck;
result = e.expressionSemantic(sc2);
Expression r = e.expressionSemantic(sc2);
sc2.pop();
/* https://issues.dlang.org/show_bug.cgi?id=15292
* if the rewrite result is same with the original,
* the equality is unresolvable because it has recursive definition.
*/
if (result.op == e.op &&
(cast(EqualExp)result).e1.type.toBasetype() == t1)
if (r.op == e.op &&
r.isEqualExp().e1.type.toBasetype() == t1)
{
e.error("cannot compare `%s` because its auto generated member-wise equality has recursive definition",
t1.toChars());
result = ErrorExp.get();
return ErrorExp.get();
}
return;
return r;
}
/* Check for tuple equality.
*/
if (e.e1.op == EXP.tuple && e.e2.op == EXP.tuple)
{
auto tup1 = cast(TupleExp)e.e1;
auto tup2 = cast(TupleExp)e.e2;
auto tup1 = e.e1.isTupleExp();
auto tup2 = e.e2.isTupleExp();
size_t dim = tup1.exps.dim;
if (dim != tup2.exps.dim)
{
e.error("mismatched tuple lengths, `%d` and `%d`",
cast(int)dim, cast(int)tup2.exps.dim);
result = ErrorExp.get();
return;
return ErrorExp.get();
}
Expression result;
if (dim == 0)
{
// zero-length tuple comparison should always return true or false.
@ -1112,25 +1082,25 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
result = Expression.combine(tup1.e0, tup2.e0, result);
result = result.expressionSemantic(sc);
return;
return result;
}
return null;
}
override void visit(CmpExp e)
Expression visitCmp(CmpExp e)
{
//printf("CmpExp:: () (%s)\n", e.toChars());
result = compare_overload(e, sc, Id.cmp, pop);
return compare_overload(e, sc, Id.cmp, pop);
}
/*********************************
* Operator overloading for op=
*/
override void visit(BinAssignExp e)
Expression visitBinAssign(BinAssignExp e)
{
//printf("BinAssignExp::op_overload() (%s)\n", e.toChars());
if (e.e1.op == EXP.array)
if (auto ae = e.e1.isArrayExp())
{
ArrayExp ae = cast(ArrayExp)e.e1;
ae.e1 = ae.e1.expressionSemantic(sc);
ae.e1 = resolveProperties(sc, ae.e1);
Expression ae1old = ae.e1;
@ -1138,15 +1108,13 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
IntervalExp ie = null;
if (maybeSlice && ae.arguments.dim)
{
assert((*ae.arguments)[0].op == EXP.interval);
ie = cast(IntervalExp)(*ae.arguments)[0];
ie = (*ae.arguments)[0].isIntervalExp();
}
while (true)
{
if (ae.e1.op == EXP.error)
{
result = ae.e1;
return;
return ae.e1;
}
Expression e0 = null;
Expression ae1save = ae.e1;
@ -1158,14 +1126,14 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
if (search_function(ad, Id.opIndexOpAssign))
{
// Deal with $
result = resolveOpDollar(sc, ae, &e0);
Expression result = resolveOpDollar(sc, ae, &e0);
if (!result) // (a[i..j] op= e2) might be: a.opSliceOpAssign!(op)(e2, i, j)
goto Lfallback;
if (result.op == EXP.error)
return;
return result;
result = e.e2.expressionSemantic(sc);
if (result.op == EXP.error)
return;
return result;
e.e2 = result;
/* Rewrite a[arguments] op= e2 as:
* a.opIndexOpAssign!(op)(e2, arguments)
@ -1181,20 +1149,19 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
result = result.expressionSemantic(sc);
if (result)
{
result = Expression.combine(e0, result);
return;
return Expression.combine(e0, result);
}
}
Lfallback:
if (maybeSlice && search_function(ad, Id.opSliceOpAssign))
{
// Deal with $
result = resolveOpDollar(sc, ae, ie, &e0);
Expression result = resolveOpDollar(sc, ae, ie, &e0);
if (result.op == EXP.error)
return;
return result;
result = e.e2.expressionSemantic(sc);
if (result.op == EXP.error)
return;
return result;
e.e2 = result;
/* Rewrite (a[i..j] op= e2) as:
* a.opSliceOpAssign!(op)(e2, i, j)
@ -1211,7 +1178,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
result = new CallExp(e.loc, result, a);
result = result.expressionSemantic(sc);
result = Expression.combine(e0, result);
return;
return result;
}
// Didn't find it. Forward to aliasthis
if (ad.aliasthis && !isRecursiveAliasThis(ae.att1, ae.e1.type))
@ -1228,14 +1195,13 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
ae.e1 = ae1old; // recovery
ae.lengthVar = null;
}
result = e.binSemanticProp(sc);
Expression result = e.binSemanticProp(sc);
if (result)
return;
return result;
// Don't attempt 'alias this' if an error occurred
if (e.e1.type.ty == Terror || e.e2.type.ty == Terror)
{
result = ErrorExp.get();
return;
return ErrorExp.get();
}
Identifier id = opId(e);
Expressions args2;
@ -1250,8 +1216,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
if (s && !s.isTemplateDeclaration())
{
e.error("`%s.opOpAssign` isn't a template", e.e1.toChars());
result = ErrorExp.get();
return;
return ErrorExp.get();
}
}
// Set tiargs, the template argument list, which will be the operator string
@ -1290,8 +1255,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, &args2);
if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
{
result = ErrorExp.get();
return;
return ErrorExp.get();
}
}
if (m.count > 1)
@ -1306,23 +1270,38 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
m.lastf = null;
}
// Rewrite (e1 op e2) as e1.opOpAssign(e2)
result = build_overload(e.loc, sc, e.e1, e.e2, m.lastf ? m.lastf : s);
return;
return build_overload(e.loc, sc, e.e1, e.e2, m.lastf ? m.lastf : s);
}
L1:
result = checkAliasThisForLhs(ad1, sc, e);
if (result || !s) // no point in trying Rhs alias-this if there's no overload of any kind in lhs
return;
return result;
result = checkAliasThisForRhs(isAggregate(e.e2.type), sc, e);
return checkAliasThisForRhs(isAggregate(e.e2.type), sc, e);
}
}
if (pop)
*pop = e.op;
scope OpOverload v = new OpOverload(sc, pop);
e.accept(v);
return v.result;
switch (e.op)
{
case EXP.cast_ : return visitCast(e.isCastExp());
case EXP.array : return visitArray(e.isArrayExp());
case EXP.notEqual :
case EXP.equal : return visitEqual(e.isEqualExp());
case EXP.lessOrEqual :
case EXP.greaterThan :
case EXP.greaterOrEqual:
case EXP.lessThan : return visitCmp(cast(CmpExp)e);
default:
if (auto ex = e.isBinAssignExp()) return visitBinAssign(ex);
if (auto ex = e.isBinExp()) return visitBin(ex);
if (auto ex = e.isUnaExp()) return visitUna(ex);
return visit(e);
}
}
/******************************************
@ -1505,8 +1484,8 @@ bool inferForeachAggregate(Scope* sc, bool isForeach, ref Expression feaggr, out
case Tclass:
case Tstruct:
{
AggregateDeclaration ad = (tab.ty == Tclass) ? (cast(TypeClass)tab).sym
: (cast(TypeStruct)tab).sym;
AggregateDeclaration ad = (tab.ty == Tclass) ? tab.isTypeClass().sym
: tab.isTypeStruct().sym;
if (!sliced)
{
sapply = search_function(ad, isForeach ? Id.apply : Id.applyReverse);
@ -1547,9 +1526,9 @@ bool inferForeachAggregate(Scope* sc, bool isForeach, ref Expression feaggr, out
}
case Tdelegate: // https://dlang.org/spec/statement.html#foreach_over_delegates
if (aggr.op == EXP.delegate_)
if (auto de = aggr.isDelegateExp())
{
sapply = (cast(DelegateExp)aggr).func;
sapply = de.func;
}
break;
@ -1600,7 +1579,7 @@ bool inferApplyArgTypes(ForeachStatement fes, Scope* sc, ref Dsymbol sapply)
else
{
assert(tab.ty == Tdelegate && fes.aggr.op == EXP.delegate_);
ethis = (cast(DelegateExp)fes.aggr).e1;
ethis = fes.aggr.isDelegateExp().e1;
}
/* Look for like an
@ -1613,7 +1592,7 @@ bool inferApplyArgTypes(ForeachStatement fes, Scope* sc, ref Dsymbol sapply)
if (fdapply)
{
// Fill in any missing types on foreach parameters[]
matchParamsToOpApply(cast(TypeFunction)fdapply.type, fes.parameters, true);
matchParamsToOpApply(fdapply.type.isTypeFunction(), fes.parameters, true);
sapply = fdapply;
return true;
}
@ -1649,7 +1628,7 @@ bool inferApplyArgTypes(ForeachStatement fes, Scope* sc, ref Dsymbol sapply)
case Taarray:
{
TypeAArray taa = cast(TypeAArray)tab;
TypeAArray taa = tab.isTypeAArray();
if (fes.parameters.dim == 2)
{
if (!p.type)
@ -1672,8 +1651,8 @@ bool inferApplyArgTypes(ForeachStatement fes, Scope* sc, ref Dsymbol sapply)
case Tclass:
case Tstruct:
{
AggregateDeclaration ad = (tab.ty == Tclass) ? (cast(TypeClass)tab).sym
: (cast(TypeStruct)tab).sym;
AggregateDeclaration ad = (tab.ty == Tclass) ? tab.isTypeClass().sym
: tab.isTypeStruct().sym;
if (fes.parameters.dim == 1)
{
if (!p.type)
@ -1697,7 +1676,7 @@ bool inferApplyArgTypes(ForeachStatement fes, Scope* sc, ref Dsymbol sapply)
{
}
else if (s && s.isDeclaration())
p.type = (cast(Declaration)s).type;
p.type = s.isDeclaration().type;
else
break;
}
@ -1707,9 +1686,12 @@ bool inferApplyArgTypes(ForeachStatement fes, Scope* sc, ref Dsymbol sapply)
}
case Tdelegate:
if (!matchParamsToOpApply(cast(TypeFunction)tab.nextOf(), fes.parameters, true))
{
auto td = tab.isTypeDelegate();
if (!matchParamsToOpApply(td.next.isTypeFunction(), fes.parameters, true))
return false;
break;
}
default:
break; // ignore error, caught later
@ -1738,7 +1720,7 @@ private FuncDeclaration findBestOpApplyMatch(Expression ethis, FuncDeclaration f
auto f = s.isFuncDeclaration();
if (!f)
return 0; // continue
auto tf = cast(TypeFunction)f.type;
auto tf = f.type.isTypeFunction();
MATCH m = MATCH.exact;
if (f.isThis())
{
@ -1825,10 +1807,10 @@ private bool matchParamsToOpApply(TypeFunction tf, Parameters* parameters, bool
/* Get the type of opApply's dg parameter
*/
Parameter p0 = tf.parameterList[0];
if (p0.type.ty != Tdelegate)
auto de = p0.type.isTypeDelegate();
if (!de)
return nomatch;
TypeFunction tdg = cast(TypeFunction)p0.type.nextOf();
assert(tdg.ty == Tfunction);
TypeFunction tdg = de.next.isTypeFunction();
/* We now have tdg, the type of the delegate.
* tdg's parameters must match that of the foreach arglist (i.e. parameters).

View File

@ -631,13 +631,6 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
{
expOptimize(e.thisexp, WANTvalue);
// Optimize parameters
if (e.newargs)
{
for (size_t i = 0; i < e.newargs.dim; i++)
{
expOptimize((*e.newargs)[i], WANTvalue);
}
}
if (e.arguments)
{
for (size_t i = 0; i < e.arguments.dim; i++)

View File

@ -28,268 +28,6 @@ import dmd.root.rootobject;
import dmd.root.string;
import dmd.tokens;
// How multiple declarations are parsed.
// If 1, treat as C.
// If 0, treat:
// int *p, i;
// as:
// int* p;
// int* i;
private enum CDECLSYNTAX = 0;
// Support C cast syntax:
// (type)(expression)
private enum CCASTSYNTAX = 1;
// Support postfix C array declarations, such as
// int a[3][4];
private enum CARRAYDECL = 1;
/**********************************
* Set operator precedence for each operator.
*
* Used by hdrgen
*/
immutable PREC[EXP.max + 1] precedence =
[
EXP.type : PREC.expr,
EXP.error : PREC.expr,
EXP.objcClassReference : PREC.expr, // Objective-C class reference, same as EXP.type
EXP.typeof_ : PREC.primary,
EXP.mixin_ : PREC.primary,
EXP.import_ : PREC.primary,
EXP.dotVariable : PREC.primary,
EXP.scope_ : PREC.primary,
EXP.identifier : PREC.primary,
EXP.this_ : PREC.primary,
EXP.super_ : PREC.primary,
EXP.int64 : PREC.primary,
EXP.float64 : PREC.primary,
EXP.complex80 : PREC.primary,
EXP.null_ : PREC.primary,
EXP.string_ : PREC.primary,
EXP.arrayLiteral : PREC.primary,
EXP.assocArrayLiteral : PREC.primary,
EXP.classReference : PREC.primary,
EXP.file : PREC.primary,
EXP.fileFullPath : PREC.primary,
EXP.line : PREC.primary,
EXP.moduleString : PREC.primary,
EXP.functionString : PREC.primary,
EXP.prettyFunction : PREC.primary,
EXP.typeid_ : PREC.primary,
EXP.is_ : PREC.primary,
EXP.assert_ : PREC.primary,
EXP.halt : PREC.primary,
EXP.template_ : PREC.primary,
EXP.dSymbol : PREC.primary,
EXP.function_ : PREC.primary,
EXP.variable : PREC.primary,
EXP.symbolOffset : PREC.primary,
EXP.structLiteral : PREC.primary,
EXP.compoundLiteral : PREC.primary,
EXP.arrayLength : PREC.primary,
EXP.delegatePointer : PREC.primary,
EXP.delegateFunctionPointer : PREC.primary,
EXP.remove : PREC.primary,
EXP.tuple : PREC.primary,
EXP.traits : PREC.primary,
EXP.default_ : PREC.primary,
EXP.overloadSet : PREC.primary,
EXP.void_ : PREC.primary,
EXP.vectorArray : PREC.primary,
EXP._Generic : PREC.primary,
// post
EXP.dotTemplateInstance : PREC.primary,
EXP.dotIdentifier : PREC.primary,
EXP.dotTemplateDeclaration : PREC.primary,
EXP.dot : PREC.primary,
EXP.dotType : PREC.primary,
EXP.plusPlus : PREC.primary,
EXP.minusMinus : PREC.primary,
EXP.prePlusPlus : PREC.primary,
EXP.preMinusMinus : PREC.primary,
EXP.call : PREC.primary,
EXP.slice : PREC.primary,
EXP.array : PREC.primary,
EXP.index : PREC.primary,
EXP.delegate_ : PREC.unary,
EXP.address : PREC.unary,
EXP.star : PREC.unary,
EXP.negate : PREC.unary,
EXP.uadd : PREC.unary,
EXP.not : PREC.unary,
EXP.tilde : PREC.unary,
EXP.delete_ : PREC.unary,
EXP.new_ : PREC.unary,
EXP.newAnonymousClass : PREC.unary,
EXP.cast_ : PREC.unary,
EXP.throw_ : PREC.unary,
EXP.vector : PREC.unary,
EXP.pow : PREC.pow,
EXP.mul : PREC.mul,
EXP.div : PREC.mul,
EXP.mod : PREC.mul,
EXP.add : PREC.add,
EXP.min : PREC.add,
EXP.concatenate : PREC.add,
EXP.leftShift : PREC.shift,
EXP.rightShift : PREC.shift,
EXP.unsignedRightShift : PREC.shift,
EXP.lessThan : PREC.rel,
EXP.lessOrEqual : PREC.rel,
EXP.greaterThan : PREC.rel,
EXP.greaterOrEqual : PREC.rel,
EXP.in_ : PREC.rel,
/* Note that we changed precedence, so that < and != have the same
* precedence. This change is in the parser, too.
*/
EXP.equal : PREC.rel,
EXP.notEqual : PREC.rel,
EXP.identity : PREC.rel,
EXP.notIdentity : PREC.rel,
EXP.and : PREC.and,
EXP.xor : PREC.xor,
EXP.or : PREC.or,
EXP.andAnd : PREC.andand,
EXP.orOr : PREC.oror,
EXP.question : PREC.cond,
EXP.assign : PREC.assign,
EXP.construct : PREC.assign,
EXP.blit : PREC.assign,
EXP.addAssign : PREC.assign,
EXP.minAssign : PREC.assign,
EXP.concatenateAssign : PREC.assign,
EXP.concatenateElemAssign : PREC.assign,
EXP.concatenateDcharAssign : PREC.assign,
EXP.mulAssign : PREC.assign,
EXP.divAssign : PREC.assign,
EXP.modAssign : PREC.assign,
EXP.powAssign : PREC.assign,
EXP.leftShiftAssign : PREC.assign,
EXP.rightShiftAssign : PREC.assign,
EXP.unsignedRightShiftAssign : PREC.assign,
EXP.andAssign : PREC.assign,
EXP.orAssign : PREC.assign,
EXP.xorAssign : PREC.assign,
EXP.comma : PREC.expr,
EXP.declaration : PREC.expr,
EXP.interval : PREC.assign,
];
enum ParseStatementFlags : int
{
semi = 1, // empty ';' statements are allowed, but deprecated
scope_ = 2, // start a new scope
curly = 4, // { } statement is required
curlyScope = 8, // { } starts a new scope
semiOk = 0x10, // empty ';' are really ok
}
struct PrefixAttributes(AST)
{
StorageClass storageClass;
AST.Expression depmsg;
LINK link;
AST.Visibility visibility;
bool setAlignment;
AST.Expression ealign;
AST.Expressions* udas;
const(char)* comment;
}
/// The result of the `ParseLinkage` function
struct ParsedLinkage(AST)
{
/// What linkage was specified
LINK link;
/// If `extern(C++, class|struct)`, contains the `class|struct`
CPPMANGLE cppmangle;
/// If `extern(C++, some.identifier)`, will be the identifiers
AST.Identifiers* idents;
/// If `extern(C++, (some_tuple_expression)|"string"), will be the expressions
AST.Expressions* identExps;
}
/*****************************
* Destructively extract storage class from pAttrs.
*/
private StorageClass getStorageClass(AST)(PrefixAttributes!(AST)* pAttrs)
{
StorageClass stc = STC.undefined_;
if (pAttrs)
{
stc = pAttrs.storageClass;
pAttrs.storageClass = STC.undefined_;
}
return stc;
}
/**************************************
* dump mixin expansion to file for better debugging
*/
private bool writeMixin(const(char)[] s, ref Loc loc)
{
if (!global.params.mixinOut)
return false;
OutBuffer* ob = global.params.mixinOut;
ob.writestring("// expansion at ");
ob.writestring(loc.toChars());
ob.writenl();
global.params.mixinLines++;
loc = Loc(global.params.mixinFile, global.params.mixinLines + 1, loc.charnum);
// write by line to create consistent line endings
size_t lastpos = 0;
for (size_t i = 0; i < s.length; ++i)
{
// detect LF and CRLF
const c = s[i];
if (c == '\n' || (c == '\r' && i+1 < s.length && s[i+1] == '\n'))
{
ob.writestring(s[lastpos .. i]);
ob.writenl();
global.params.mixinLines++;
if (c == '\r')
++i;
lastpos = i + 1;
}
}
if(lastpos < s.length)
ob.writestring(s[lastpos .. $]);
if (s.length == 0 || s[$-1] != '\n')
{
ob.writenl(); // ensure empty line after expansion
global.params.mixinLines++;
}
ob.writenl();
global.params.mixinLines++;
return true;
}
/***********************************************************
*/
class Parser(AST) : Lexer
@ -344,80 +82,49 @@ class Parser(AST) : Lexer
//nextToken(); // start up the scanner
}
/++
+ Parse a module, i.e. the optional `module x.y.z` declaration and all declarations
+ found in the current file.
+
+ Returns: the list of declarations or an empty list in case of malformed declarations,
+ the module declaration will be stored as `this.md` if found
+/
AST.Dsymbols* parseModule()
{
if (!parseModuleDeclaration())
return errorReturn();
return parseModuleContent();
}
/++
+ Parse the optional module declaration
+
+ Returns: false if a malformed module declaration was found
+/
final bool parseModuleDeclaration()
{
const comment = token.blockComment;
bool isdeprecated = false;
AST.Expression msg = null;
AST.Expressions* udas = null;
AST.Dsymbols* decldefs;
AST.Dsymbol lastDecl = mod; // for attaching ddoc unittests to module decl
Token* tk;
if (skipAttributes(&token, &tk) && tk.value == TOK.module_)
{
while (token.value != TOK.module_)
{
switch (token.value)
{
case TOK.deprecated_:
{
// deprecated (...) module ...
if (isdeprecated)
error("there is only one deprecation attribute allowed for module declaration");
isdeprecated = true;
nextToken();
if (token.value == TOK.leftParenthesis)
{
check(TOK.leftParenthesis);
msg = parseAssignExp();
check(TOK.rightParenthesis);
}
break;
}
case TOK.at:
{
AST.Expressions* exps = null;
const stc = parseAttribute(exps);
if (stc & atAttrGroup)
{
error("`@%s` attribute for module declaration is not supported", token.toChars());
}
else
{
udas = AST.UserAttributeDeclaration.concat(udas, exps);
}
if (stc)
nextToken();
break;
}
default:
{
error("`module` expected instead of `%s`", token.toChars());
nextToken();
break;
}
}
}
}
// Parse optional module attributes
parseModuleAttributes(msg, isdeprecated);
if (udas)
{
auto a = new AST.Dsymbols();
auto udad = new AST.UserAttributeDeclaration(udas, a);
mod.userAttribDecl = udad;
}
// ModuleDeclation leads off
// ModuleDeclaration leads off
if (token.value == TOK.module_)
{
const loc = token.loc;
nextToken();
/* parse ModuleFullyQualifiedName
* https://dlang.org/spec/module.html#ModuleFullyQualifiedName
*/
if (token.value != TOK.identifier)
{
error("identifier expected following `module`");
goto Lerr;
return false;
}
Identifier[] a;
@ -430,7 +137,7 @@ class Parser(AST) : Lexer
if (token.value != TOK.identifier)
{
error("identifier expected following `package`");
goto Lerr;
return false;
}
id = token.ident;
}
@ -442,29 +149,115 @@ class Parser(AST) : Lexer
nextToken();
addComment(mod, comment);
}
return true;
}
decldefs = parseDeclDefs(0, &lastDecl);
/++
+ Parse the content of a module, i.e. all declarations found until the end of file.
+
+ Returns: the list of declarations or an empty list in case of malformed declarations
+/
final AST.Dsymbols* parseModuleContent()
{
AST.Dsymbol lastDecl = mod;
AST.Dsymbols* decldefs = parseDeclDefs(0, &lastDecl);
if (token.value == TOK.rightCurly)
{
error(token.loc, "unmatched closing brace");
goto Lerr;
return errorReturn();
}
if (token.value != TOK.endOfFile)
{
error(token.loc, "unrecognized declaration");
goto Lerr;
return errorReturn();
}
return decldefs;
}
Lerr:
/++
+ Skips to the end of the current declaration - denoted by either `;` or EOF
+
+ Returns: An empty list of Dsymbols
+/
private AST.Dsymbols* errorReturn()
{
while (token.value != TOK.semicolon && token.value != TOK.endOfFile)
nextToken();
nextToken();
return new AST.Dsymbols();
}
/**********************************
* Parse the ModuleAttributes preceding a module declaration.
* ModuleDeclaration:
* ModuleAttributes(opt) module ModuleFullyQualifiedName ;
* https://dlang.org/spec/module.html#ModuleAttributes
* Params:
* msg = set to the AssignExpression from DeprecatedAttribute https://dlang.org/spec/module.html#DeprecatedAttribute
* isdeprecated = set to true if a DeprecatedAttribute is seen
*/
private
void parseModuleAttributes(out AST.Expression msg, out bool isdeprecated)
{
Token* tk;
if (!(skipAttributes(&token, &tk) && tk.value == TOK.module_))
return; // no module attributes
AST.Expressions* udas = null;
while (token.value != TOK.module_)
{
switch (token.value)
{
case TOK.deprecated_:
{
// deprecated (...) module ...
if (isdeprecated)
error("there is only one deprecation attribute allowed for module declaration");
isdeprecated = true;
nextToken();
if (token.value == TOK.leftParenthesis)
{
check(TOK.leftParenthesis);
msg = parseAssignExp();
check(TOK.rightParenthesis);
}
break;
}
case TOK.at:
{
AST.Expressions* exps = null;
const stc = parseAttribute(exps);
if (stc & atAttrGroup)
{
error("`@%s` attribute for module declaration is not supported", token.toChars());
}
else
{
udas = AST.UserAttributeDeclaration.concat(udas, exps);
}
if (stc)
nextToken();
break;
}
default:
{
error("`module` expected instead of `%s`", token.toChars());
nextToken();
break;
}
}
}
if (udas)
{
auto a = new AST.Dsymbols();
auto udad = new AST.UserAttributeDeclaration(udas, a);
mod.userAttribDecl = udad;
}
}
final:
/**
@ -914,7 +707,7 @@ class Parser(AST) : Lexer
tk.value == TOK.out_ || tk.value == TOK.do_ || tk.value == TOK.goesTo ||
tk.value == TOK.identifier && tk.ident == Id._body))
{
// @@@DEPRECATED@@@
// @@@DEPRECATED_2.117@@@
// https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md
// Deprecated in 2.097 - Can be removed from 2.117
// The deprecation period is longer than usual as `body`
@ -1418,6 +1211,15 @@ class Parser(AST) : Lexer
*/
private StorageClass appendStorageClass(StorageClass orig, StorageClass added)
{
void checkConflictSTCGroup(bool at = false)(StorageClass group)
{
if (added & group && orig & group & ((orig & group) - 1))
error(
at ? "conflicting attribute `@%s`"
: "conflicting attribute `%s`",
token.toChars());
}
if (orig & added)
{
OutBuffer buf;
@ -1460,24 +1262,9 @@ class Parser(AST) : Lexer
return orig;
}
if (added & (STC.const_ | STC.immutable_ | STC.manifest))
{
StorageClass u = orig & (STC.const_ | STC.immutable_ | STC.manifest);
if (u & (u - 1))
error("conflicting attribute `%s`", Token.toChars(token.value));
}
if (added & (STC.gshared | STC.shared_ | STC.tls))
{
StorageClass u = orig & (STC.gshared | STC.shared_ | STC.tls);
if (u & (u - 1))
error("conflicting attribute `%s`", Token.toChars(token.value));
}
if (added & STC.safeGroup)
{
StorageClass u = orig & STC.safeGroup;
if (u & (u - 1))
error("conflicting attribute `@%s`", token.toChars());
}
checkConflictSTCGroup(STC.const_ | STC.immutable_ | STC.manifest);
checkConflictSTCGroup(STC.gshared | STC.shared_ | STC.tls);
checkConflictSTCGroup!true(STC.safeGroup);
return orig;
}
@ -2885,7 +2672,7 @@ class Parser(AST) : Lexer
}
nextToken();
/* @@@DEPRECATED_2.098@@@
/* @@@DEPRECATED_2.108@@@
* After deprecation period (2.108), remove all code in the version(all) block.
*/
version (all)
@ -4614,7 +4401,7 @@ class Parser(AST) : Lexer
(tk.value == TOK.leftParenthesis || tk.value == TOK.leftCurly || tk.value == TOK.in_ || tk.value == TOK.out_ || tk.value == TOK.goesTo ||
tk.value == TOK.do_ || tk.value == TOK.identifier && tk.ident == Id._body))
{
// @@@DEPRECATED@@@
// @@@DEPRECATED_2.117@@@
// https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md
// Deprecated in 2.097 - Can be removed from 2.117
// The deprecation period is longer than usual as `body`
@ -5028,12 +4815,18 @@ class Parser(AST) : Lexer
// parseAttributes shouldn't have set these variables
assert(link == linkage && !setAlignment && ealign is null);
auto tpl_ = cast(AST.TemplateDeclaration) s;
assert(tpl_ !is null && tpl_.members.dim == 1);
auto fd = cast(AST.FuncLiteralDeclaration) (*tpl_.members)[0];
auto tf = cast(AST.TypeFunction) fd.type;
assert(tf.parameterList.parameters.dim > 0);
auto as = new AST.Dsymbols();
(*tf.parameterList.parameters)[0].userAttribDecl = new AST.UserAttributeDeclaration(udas, as);
if (tpl_ is null || tpl_.members.dim != 1)
{
error("user-defined attributes are not allowed on `alias` declarations");
}
else
{
auto fd = cast(AST.FuncLiteralDeclaration) (*tpl_.members)[0];
auto tf = cast(AST.TypeFunction) fd.type;
assert(tf.parameterList.parameters.dim > 0);
auto as = new AST.Dsymbols();
(*tf.parameterList.parameters)[0].userAttribDecl = new AST.UserAttributeDeclaration(udas, as);
}
}
v = new AST.AliasDeclaration(loc, ident, s);
@ -5060,7 +4853,7 @@ class Parser(AST) : Lexer
{
OutBuffer buf;
AST.stcToBuffer(&buf, remStc);
// @@@DEPRECATED_2.093@@@
// @@@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());
}
@ -5287,7 +5080,7 @@ class Parser(AST) : Lexer
case TOK.identifier:
if (token.ident == Id._body)
{
// @@@DEPRECATED@@@
// @@@DEPRECATED_2.117@@@
// https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md
// Deprecated in 2.097 - Can be removed from 2.117
// The deprecation period is longer than usual as `body`
@ -7607,7 +7400,7 @@ LagainStc:
case TOK.identifier:
if (t.ident == Id._body)
{
// @@@DEPRECATED@@@
// @@@DEPRECATED_2.117@@@
// https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md
// Deprecated in 2.097 - Can be removed from 2.117
// The deprecation period is longer than usual as `body`
@ -8652,6 +8445,9 @@ LagainStc:
break;
case TOK.delete_:
// @@@DEPRECATED_2.109@@@
// Use of `delete` keyword has been an error since 2.099.
// Remove from the parser after 2.109.
nextToken();
e = parseUnaryExp();
e = new AST.DeleteExp(loc, e, false);
@ -9409,12 +9205,7 @@ LagainStc:
const loc = token.loc;
nextToken();
AST.Expressions* newargs = null;
AST.Expressions* arguments = null;
if (token.value == TOK.leftParenthesis)
{
newargs = parseArguments();
}
// An anonymous nested class starts with "class"
if (token.value == TOK.class_)
@ -9444,7 +9235,7 @@ LagainStc:
}
auto cd = new AST.ClassDeclaration(loc, id, baseclasses, members, false);
auto e = new AST.NewAnonClassExp(loc, thisexp, newargs, cd, arguments);
auto e = new AST.NewAnonClassExp(loc, thisexp, cd, arguments);
return e;
}
@ -9469,7 +9260,7 @@ LagainStc:
arguments = parseArguments();
}
auto e = new AST.NewExp(loc, thisexp, newargs, t, arguments);
auto e = new AST.NewExp(loc, thisexp, t, arguments);
return e;
}
@ -9519,7 +9310,7 @@ LagainStc:
STC.live |
/*STC.future |*/ // probably should be included
STC.disable;
}
}
enum PREC : int
{
@ -9541,3 +9332,276 @@ enum PREC : int
unary,
primary,
}
/**********************************
* Set operator precedence for each operator.
*
* Used by hdrgen
*/
immutable PREC[EXP.max + 1] precedence =
[
EXP.type : PREC.expr,
EXP.error : PREC.expr,
EXP.objcClassReference : PREC.expr, // Objective-C class reference, same as EXP.type
EXP.typeof_ : PREC.primary,
EXP.mixin_ : PREC.primary,
EXP.import_ : PREC.primary,
EXP.dotVariable : PREC.primary,
EXP.scope_ : PREC.primary,
EXP.identifier : PREC.primary,
EXP.this_ : PREC.primary,
EXP.super_ : PREC.primary,
EXP.int64 : PREC.primary,
EXP.float64 : PREC.primary,
EXP.complex80 : PREC.primary,
EXP.null_ : PREC.primary,
EXP.string_ : PREC.primary,
EXP.arrayLiteral : PREC.primary,
EXP.assocArrayLiteral : PREC.primary,
EXP.classReference : PREC.primary,
EXP.file : PREC.primary,
EXP.fileFullPath : PREC.primary,
EXP.line : PREC.primary,
EXP.moduleString : PREC.primary,
EXP.functionString : PREC.primary,
EXP.prettyFunction : PREC.primary,
EXP.typeid_ : PREC.primary,
EXP.is_ : PREC.primary,
EXP.assert_ : PREC.primary,
EXP.halt : PREC.primary,
EXP.template_ : PREC.primary,
EXP.dSymbol : PREC.primary,
EXP.function_ : PREC.primary,
EXP.variable : PREC.primary,
EXP.symbolOffset : PREC.primary,
EXP.structLiteral : PREC.primary,
EXP.compoundLiteral : PREC.primary,
EXP.arrayLength : PREC.primary,
EXP.delegatePointer : PREC.primary,
EXP.delegateFunctionPointer : PREC.primary,
EXP.remove : PREC.primary,
EXP.tuple : PREC.primary,
EXP.traits : PREC.primary,
EXP.default_ : PREC.primary,
EXP.overloadSet : PREC.primary,
EXP.void_ : PREC.primary,
EXP.vectorArray : PREC.primary,
EXP._Generic : PREC.primary,
// post
EXP.dotTemplateInstance : PREC.primary,
EXP.dotIdentifier : PREC.primary,
EXP.dotTemplateDeclaration : PREC.primary,
EXP.dot : PREC.primary,
EXP.dotType : PREC.primary,
EXP.plusPlus : PREC.primary,
EXP.minusMinus : PREC.primary,
EXP.prePlusPlus : PREC.primary,
EXP.preMinusMinus : PREC.primary,
EXP.call : PREC.primary,
EXP.slice : PREC.primary,
EXP.array : PREC.primary,
EXP.index : PREC.primary,
EXP.delegate_ : PREC.unary,
EXP.address : PREC.unary,
EXP.star : PREC.unary,
EXP.negate : PREC.unary,
EXP.uadd : PREC.unary,
EXP.not : PREC.unary,
EXP.tilde : PREC.unary,
EXP.delete_ : PREC.unary,
EXP.new_ : PREC.unary,
EXP.newAnonymousClass : PREC.unary,
EXP.cast_ : PREC.unary,
EXP.throw_ : PREC.unary,
EXP.vector : PREC.unary,
EXP.pow : PREC.pow,
EXP.mul : PREC.mul,
EXP.div : PREC.mul,
EXP.mod : PREC.mul,
EXP.add : PREC.add,
EXP.min : PREC.add,
EXP.concatenate : PREC.add,
EXP.leftShift : PREC.shift,
EXP.rightShift : PREC.shift,
EXP.unsignedRightShift : PREC.shift,
EXP.lessThan : PREC.rel,
EXP.lessOrEqual : PREC.rel,
EXP.greaterThan : PREC.rel,
EXP.greaterOrEqual : PREC.rel,
EXP.in_ : PREC.rel,
/* Note that we changed precedence, so that < and != have the same
* precedence. This change is in the parser, too.
*/
EXP.equal : PREC.rel,
EXP.notEqual : PREC.rel,
EXP.identity : PREC.rel,
EXP.notIdentity : PREC.rel,
EXP.and : PREC.and,
EXP.xor : PREC.xor,
EXP.or : PREC.or,
EXP.andAnd : PREC.andand,
EXP.orOr : PREC.oror,
EXP.question : PREC.cond,
EXP.assign : PREC.assign,
EXP.construct : PREC.assign,
EXP.blit : PREC.assign,
EXP.addAssign : PREC.assign,
EXP.minAssign : PREC.assign,
EXP.concatenateAssign : PREC.assign,
EXP.concatenateElemAssign : PREC.assign,
EXP.concatenateDcharAssign : PREC.assign,
EXP.mulAssign : PREC.assign,
EXP.divAssign : PREC.assign,
EXP.modAssign : PREC.assign,
EXP.powAssign : PREC.assign,
EXP.leftShiftAssign : PREC.assign,
EXP.rightShiftAssign : PREC.assign,
EXP.unsignedRightShiftAssign : PREC.assign,
EXP.andAssign : PREC.assign,
EXP.orAssign : PREC.assign,
EXP.xorAssign : PREC.assign,
EXP.comma : PREC.expr,
EXP.declaration : PREC.expr,
EXP.interval : PREC.assign,
];
enum ParseStatementFlags : int
{
semi = 1, // empty ';' statements are allowed, but deprecated
scope_ = 2, // start a new scope
curly = 4, // { } statement is required
curlyScope = 8, // { } starts a new scope
semiOk = 0x10, // empty ';' are really ok
}
struct PrefixAttributes(AST)
{
StorageClass storageClass;
AST.Expression depmsg;
LINK link;
AST.Visibility visibility;
bool setAlignment;
AST.Expression ealign;
AST.Expressions* udas;
const(char)* comment;
}
/// The result of the `ParseLinkage` function
struct ParsedLinkage(AST)
{
/// What linkage was specified
LINK link;
/// If `extern(C++, class|struct)`, contains the `class|struct`
CPPMANGLE cppmangle;
/// If `extern(C++, some.identifier)`, will be the identifiers
AST.Identifiers* idents;
/// If `extern(C++, (some_tuple_expression)|"string"), will be the expressions
AST.Expressions* identExps;
}
/*********************************** Private *************************************/
/***********************
* How multiple declarations are parsed.
* If 1, treat as C.
* If 0, treat:
* int *p, i;
* as:
* int* p;
* int* i;
*/
private enum CDECLSYNTAX = 0;
/*****
* Support C cast syntax:
* (type)(expression)
*/
private enum CCASTSYNTAX = 1;
/*****
* Support postfix C array declarations, such as
* int a[3][4];
*/
private enum CARRAYDECL = 1;
/*****************************
* Destructively extract storage class from pAttrs.
*/
private StorageClass getStorageClass(AST)(PrefixAttributes!(AST)* pAttrs)
{
StorageClass stc = STC.undefined_;
if (pAttrs)
{
stc = pAttrs.storageClass;
pAttrs.storageClass = STC.undefined_;
}
return stc;
}
/**************************************
* dump mixin expansion to file for better debugging
*/
private bool writeMixin(const(char)[] s, ref Loc loc)
{
if (!global.params.mixinOut)
return false;
OutBuffer* ob = global.params.mixinOut;
ob.writestring("// expansion at ");
ob.writestring(loc.toChars());
ob.writenl();
global.params.mixinLines++;
loc = Loc(global.params.mixinFile, global.params.mixinLines + 1, loc.charnum);
// write by line to create consistent line endings
size_t lastpos = 0;
for (size_t i = 0; i < s.length; ++i)
{
// detect LF and CRLF
const c = s[i];
if (c == '\n' || (c == '\r' && i+1 < s.length && s[i+1] == '\n'))
{
ob.writestring(s[lastpos .. i]);
ob.writenl();
global.params.mixinLines++;
if (c == '\r')
++i;
lastpos = i + 1;
}
}
if(lastpos < s.length)
ob.writestring(s[lastpos .. $]);
if (s.length == 0 || s[$-1] != '\n')
{
ob.writenl(); // ensure empty line after expansion
global.params.mixinLines++;
}
ob.writenl();
global.params.mixinLines++;
return true;
}

View File

@ -122,6 +122,16 @@ extern (C++) final class PrintASTVisitor : Visitor
printAST(e.e1, indent + 2);
}
override void visit(CastExp e)
{
printIndent(indent);
auto s = EXPtoString(e.op);
printf("%.*s %s\n", cast(int)s.length, s.ptr, e.type ? e.type.toChars() : "");
printIndent(indent + 2);
printf(".to: %s\n", e.to.toChars());
printAST(e.e1, indent + 2);
}
override void visit(VectorExp e)
{
printIndent(indent);

View File

@ -422,7 +422,7 @@ private extern(C++) final class Semantic2Visitor : Visitor
const sameParams = tf1.parameterList == tf2.parameterList;
// Allow the hack to declare overloads with different parameters/STC's
// @@@DEPRECATED_2.094@@@
// @@@DEPRECATED_2.104@@@
// Deprecated in 2020-08, make this an error in 2.104
if (parent1.isModule() &&
f1.linkage != LINK.d && f1.linkage != LINK.cpp &&

View File

@ -377,6 +377,12 @@ private extern(C++) final class Semantic3Visitor : Visitor
// Reverts: https://issues.dlang.org/show_bug.cgi?id=5710
// No compiler supports this, and there was never any spec for it.
// @@@DEPRECATED_2.116@@@
// Deprecated in 2.096, can be made an error in 2.116.
// The deprecation period is longer than usual as dual-context
// functions may be widely used by dmd-compiled projects.
// It also gives more time for the implementation of dual-context
// functions to be reworked as a frontend-only feature.
if (funcdecl.isThis2)
{
funcdecl.deprecation("function requires a dual-context, which is deprecated");
@ -746,7 +752,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
// Check for errors related to 'nothrow'.
const blockexit = funcdecl.fbody.blockExit(funcdecl, f.isnothrow);
if (f.isnothrow && blockexit & BE.throw_)
error(funcdecl.loc, "`nothrow` %s `%s` may throw", funcdecl.kind(), funcdecl.toPrettyChars());
error(funcdecl.loc, "%s `%s` may throw but is marked as `nothrow`", funcdecl.kind(), funcdecl.toPrettyChars());
if (!(blockexit & (BE.throw_ | BE.halt) || funcdecl.flags & FUNCFLAG.hasCatches))
{
@ -1146,14 +1152,16 @@ private extern(C++) final class Semantic3Visitor : Visitor
s = s.statementSemantic(sc2);
bool isnothrow = f.isnothrow & !(funcdecl.flags & FUNCFLAG.nothrowInprocess);
immutable bool isnothrow = f.isnothrow && !(funcdecl.flags & FUNCFLAG.nothrowInprocess);
const blockexit = s.blockExit(funcdecl, isnothrow);
if (blockexit & BE.throw_)
{
funcdecl.eh_none = false;
if (f.isnothrow && isnothrow && blockexit & BE.throw_)
error(funcdecl.loc, "`nothrow` %s `%s` may throw", funcdecl.kind(), funcdecl.toPrettyChars());
if (funcdecl.flags & FUNCFLAG.nothrowInprocess && blockexit & BE.throw_)
f.isnothrow = false;
if (isnothrow)
error(funcdecl.loc, "%s `%s` may throw but is marked as `nothrow`", funcdecl.kind(), funcdecl.toPrettyChars());
else if (funcdecl.flags & FUNCFLAG.nothrowInprocess)
f.isnothrow = false;
}
if (sbody.blockExit(funcdecl, f.isnothrow) == BE.fallthru)
sbody = new CompoundStatement(Loc.initial, sbody, s);
@ -1402,7 +1410,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
auto sexp = new ExpStatement(ctor.loc, ce);
auto ss = new ScopeStatement(ctor.loc, sexp, ctor.loc);
// @@@DEPRECATED_2096@@@
// @@@DEPRECATED_2.106@@@
// Allow negligible attribute violations to allow for a smooth
// transition. Remove this after the usual deprecation period
// after 2.106.

View File

@ -1608,7 +1608,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
* Params:
* sc = context
* fs = ForeachStatement
* tfld = type of function literal to be created, can be null
* tfld = type of function literal to be created (type of opApply() function if any), can be null
* Returns:
* Function literal created, as an expression
* null if error.
@ -1619,7 +1619,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
foreach (i; 0 .. fs.parameters.dim)
{
Parameter p = (*fs.parameters)[i];
StorageClass stc = STC.ref_;
StorageClass stc = STC.ref_ | (p.storageClass & STC.scope_);
Identifier id;
p.type = p.type.typeSemantic(fs.loc, sc);
@ -1628,17 +1628,17 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
{
Parameter prm = tfld.parameterList[i];
//printf("\tprm = %s%s\n", (prm.storageClass&STC.ref_?"ref ":"").ptr, prm.ident.toChars());
stc = prm.storageClass & STC.ref_;
id = p.ident; // argument copy is not need.
if ((p.storageClass & STC.ref_) != stc)
stc = (prm.storageClass & STC.ref_) | (p.storageClass & STC.scope_);
if ((p.storageClass & STC.ref_) != (prm.storageClass & STC.ref_))
{
if (!stc)
if (!(prm.storageClass & STC.ref_))
{
fs.error("`foreach`: cannot make `%s` `ref`", p.ident.toChars());
return null;
}
goto LcopyArg;
}
id = p.ident; // argument copy is not need.
}
else if (p.storageClass & STC.ref_)
{
@ -1655,7 +1655,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
Initializer ie = new ExpInitializer(fs.loc, new IdentifierExp(fs.loc, id));
auto v = new VarDeclaration(fs.loc, p.type, p.ident, ie);
v.storage_class |= STC.temp;
v.storage_class |= STC.temp | (stc & STC.scope_);
Statement s = new ExpStatement(fs.loc, v);
fs._body = new CompoundStatement(fs.loc, s, fs._body);
}
@ -3567,7 +3567,6 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
tcs.tryBody = sc.tryBody; // chain on the in-flight tryBody
tcs._body = tcs._body.semanticScope(sc, null, null, tcs);
assert(tcs._body);
/* Even if body is empty, still do semantic analysis on catches
*/
@ -3610,6 +3609,11 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
if (catchErrors)
return setError();
// No actual code in the try (i.e. omitted any conditionally compiled code)
// Could also be extended to check for hasCode
if (!tcs._body)
return;
if (tcs._body.isErrorStatement())
{
result = tcs._body;
@ -4764,161 +4768,71 @@ private Statements* flatten(Statement statement, Scope* sc)
}
/***********************************************************
* Convert TemplateMixin members (== Dsymbols) to Statements.
* Convert TemplateMixin members (which are Dsymbols) to Statements.
* Params:
* s = the symbol to convert to a Statement
* Returns:
* s redone as a Statement
*/
private Statement toStatement(Dsymbol s)
{
extern (C++) final class ToStmt : Visitor
Statement result;
if (auto tm = s.isTemplateMixin())
{
alias visit = Visitor.visit;
public:
Statement result;
Statement visitMembers(Loc loc, Dsymbols* a)
auto a = new Statements();
foreach (m; *tm.members)
{
if (!a)
return null;
auto statements = new Statements();
foreach (s; *a)
{
statements.push(toStatement(s));
}
return new CompoundStatement(loc, statements);
if (Statement sx = toStatement(m))
a.push(sx);
}
override void visit(Dsymbol s)
{
.error(Loc.initial, "Internal Compiler Error: cannot mixin %s `%s`\n", s.kind(), s.toChars());
result = new ErrorStatement();
}
override void visit(TemplateMixin tm)
{
auto a = new Statements();
foreach (m; *tm.members)
{
Statement s = toStatement(m);
if (s)
a.push(s);
}
result = new CompoundStatement(tm.loc, a);
}
result = new CompoundStatement(tm.loc, a);
}
else if (s.isVarDeclaration() ||
s.isAggregateDeclaration() ||
s.isFuncDeclaration() ||
s.isEnumDeclaration() ||
s.isAliasDeclaration() ||
s.isTemplateDeclaration())
{
/* Perhaps replace the above with isScopeDsymbol() || isDeclaration()
*/
/* An actual declaration symbol will be converted to DeclarationExp
* with ExpStatement.
*/
Statement declStmt(Dsymbol s)
{
auto de = new DeclarationExp(s.loc, s);
de.type = Type.tvoid; // avoid repeated semantic
return new ExpStatement(s.loc, de);
}
override void visit(VarDeclaration d)
{
result = declStmt(d);
}
override void visit(AggregateDeclaration d)
{
result = declStmt(d);
}
override void visit(FuncDeclaration d)
{
result = declStmt(d);
}
override void visit(EnumDeclaration d)
{
result = declStmt(d);
}
override void visit(AliasDeclaration d)
{
result = declStmt(d);
}
override void visit(TemplateDeclaration d)
{
result = declStmt(d);
}
auto de = new DeclarationExp(s.loc, s);
de.type = Type.tvoid; // avoid repeated semantic
result = new ExpStatement(s.loc, de);
}
else if (auto d = s.isAttribDeclaration())
{
/* All attributes have been already picked by the semantic analysis of
* 'bottom' declarations (function, struct, class, etc).
* So we don't have to copy them.
*/
override void visit(StorageClassDeclaration d)
if (Dsymbols* a = d.include(null))
{
result = visitMembers(d.loc, d.decl);
}
override void visit(DeprecatedDeclaration d)
{
result = visitMembers(d.loc, d.decl);
}
override void visit(LinkDeclaration d)
{
result = visitMembers(d.loc, d.decl);
}
override void visit(VisibilityDeclaration d)
{
result = visitMembers(d.loc, d.decl);
}
override void visit(AlignDeclaration d)
{
result = visitMembers(d.loc, d.decl);
}
override void visit(UserAttributeDeclaration d)
{
result = visitMembers(d.loc, d.decl);
}
override void visit(ForwardingAttribDeclaration d)
{
result = visitMembers(d.loc, d.decl);
}
override void visit(StaticAssert s)
{
}
override void visit(Import s)
{
}
override void visit(PragmaDeclaration d)
{
}
override void visit(ConditionalDeclaration d)
{
result = visitMembers(d.loc, d.include(null));
}
override void visit(StaticForeachDeclaration d)
{
assert(d.sfe && !!d.sfe.aggrfe ^ !!d.sfe.rangefe);
result = visitMembers(d.loc, d.include(null));
}
override void visit(CompileDeclaration d)
{
result = visitMembers(d.loc, d.include(null));
auto statements = new Statements();
foreach (sx; *a)
{
statements.push(toStatement(sx));
}
result = new CompoundStatement(d.loc, statements);
}
}
else if (s.isStaticAssert() ||
s.isImport())
{
/* Ignore as they are not Statements
*/
}
else
{
.error(Loc.initial, "Internal Compiler Error: cannot mixin %s `%s`\n", s.kind(), s.toChars());
result = new ErrorStatement();
}
if (!s)
return null;
scope ToStmt v = new ToStmt();
s.accept(v);
return v.result;
return result;
}
/**

View File

@ -59,6 +59,11 @@ extern (C++) final class StaticAssert : Dsymbol
return "static assert";
}
override inout(StaticAssert) isStaticAssert() inout
{
return this;
}
override void accept(Visitor v)
{
v.visit(this);

View File

@ -24,5 +24,6 @@ public:
void addMember(Scope *sc, ScopeDsymbol *sds);
bool oneMember(Dsymbol **ps, Identifier *ident);
const char *kind() const;
StaticAssert *isStaticAssert() { return this; }
void accept(Visitor *v) { v->visit(this); }
};

View File

@ -35,7 +35,6 @@ enum TOK : ubyte
leftCurly,
rightCurly,
colon,
negate,
semicolon,
dotDotDot,
endOfFile,
@ -44,26 +43,18 @@ enum TOK : ubyte
assert_,
true_,
false_,
array,
call,
address,
type,
throw_,
new_,
delete_,
star,
variable,
slice,
version_,
module_,
dollar,
template_,
declaration,
typeof_,
pragma_,
typeid_,
uadd,
remove,
comment,
// Operators
@ -75,7 +66,6 @@ enum TOK : ubyte
notEqual,
identity,
notIdentity,
index,
is_,
leftShift,
@ -281,6 +271,7 @@ enum TOK : ubyte
_import,
__cdecl,
__declspec,
__stdcall,
__attribute__,
}
@ -589,6 +580,7 @@ private immutable TOK[] keywords =
TOK._import,
TOK.__cdecl,
TOK.__declspec,
TOK.__stdcall,
TOK.__attribute__,
];
@ -617,7 +609,7 @@ static immutable TOK[TOK.max + 1] Ckeywords =
restrict, return_, int16, signed, sizeof_, static_, struct_, switch_, typedef_,
union_, unsigned, void_, volatile, while_, asm_,
_Alignas, _Alignof, _Atomic, _Bool, _Complex, _Generic, _Imaginary, _Noreturn,
_Static_assert, _Thread_local, _import, __cdecl, __declspec, __attribute__ ];
_Static_assert, _Thread_local, _import, __cdecl, __declspec, __stdcall, __attribute__ ];
foreach (kw; Ckwds)
tab[kw] = cast(TOK) kw;
@ -805,18 +797,11 @@ extern (C++) struct Token
TOK.andAnd: "&&",
TOK.or: "|",
TOK.orOr: "||",
TOK.array: "[]",
TOK.index: "[i]",
TOK.address: "&",
TOK.star: "*",
TOK.tilde: "~",
TOK.dollar: "$",
TOK.plusPlus: "++",
TOK.minusMinus: "--",
TOK.type: "type",
TOK.question: "?",
TOK.negate: "-",
TOK.uadd: "+",
TOK.variable: "var",
TOK.addAssign: "+=",
TOK.minAssign: "-=",
@ -829,7 +814,6 @@ extern (C++) struct Token
TOK.andAssign: "&=",
TOK.orAssign: "|=",
TOK.concatenateAssign: "~=",
TOK.call: "call",
TOK.identity: "is",
TOK.notIdentity: "!is",
TOK.identifier: "identifier",
@ -844,14 +828,12 @@ extern (C++) struct Token
// For debugging
TOK.error: "error",
TOK.string_: "string",
TOK.declaration: "declaration",
TOK.onScopeExit: "scope(exit)",
TOK.onScopeSuccess: "scope(success)",
TOK.onScopeFailure: "scope(failure)",
// Finish up
TOK.reserved: "reserved",
TOK.remove: "remove",
TOK.comment: "comment",
TOK.int32Literal: "int32v",
TOK.uns32Literal: "uns32v",
@ -896,6 +878,7 @@ extern (C++) struct Token
TOK._import : "__import",
TOK.__cdecl : "__cdecl",
TOK.__declspec : "__declspec",
TOK.__stdcall : "__stdcall",
TOK.__attribute__ : "__attribute__",
];
@ -963,12 +946,20 @@ nothrow:
sprintf(&buffer[0], "%d", cast(d_int32)intvalue);
break;
case TOK.uns32Literal:
case TOK.charLiteral:
case TOK.wcharLiteral:
case TOK.dcharLiteral:
case TOK.wchar_tLiteral:
sprintf(&buffer[0], "%uU", cast(d_uns32)unsvalue);
break;
case TOK.charLiteral:
{
const v = cast(d_int32)intvalue;
if (v >= ' ' && v <= '~')
sprintf(&buffer[0], "'%c'", v);
else
sprintf(&buffer[0], "'\\x%02x'", v);
break;
}
case TOK.int64Literal:
sprintf(&buffer[0], "%lldL", cast(long)intvalue);
break;
@ -1006,29 +997,7 @@ nothrow:
{
dchar c;
utf_decodeChar(ustring[0 .. len], i, c);
switch (c)
{
case 0:
break;
case '"':
case '\\':
buf.writeByte('\\');
goto default;
default:
if (c <= 0x7F)
{
if (isprint(c))
buf.writeByte(c);
else
buf.printf("\\x%02x", c);
}
else if (c <= 0xFFFF)
buf.printf("\\u%04x", c);
else
buf.printf("\\U%08x", c);
continue;
}
break;
writeCharLiteral(buf, c);
}
buf.writeByte('"');
if (postfix)
@ -1103,3 +1072,64 @@ nothrow:
}
}
/**
* Write a character, using a readable escape sequence if needed
*
* Useful for printing "" string literals in e.g. error messages, ddoc, or the `.stringof` property
*
* Params:
* buf = buffer to append character in
* c = code point to write
*/
nothrow
void writeCharLiteral(ref OutBuffer buf, dchar c)
{
switch (c)
{
case '\0':
buf.writestring("\\0");
break;
case '\n':
buf.writestring("\\n");
break;
case '\r':
buf.writestring("\\r");
break;
case '\t':
buf.writestring("\\t");
break;
case '\b':
buf.writestring("\\b");
break;
case '\f':
buf.writestring("\\f");
break;
case '"':
case '\\':
buf.writeByte('\\');
goto default;
default:
if (c <= 0x7F)
{
if (isprint(c))
buf.writeByte(c);
else
buf.printf("\\x%02x", c);
}
else if (c <= 0xFFFF)
buf.printf("\\u%04x", c);
else
buf.printf("\\U%08x", c);
break;
}
}
unittest
{
OutBuffer buf;
foreach(dchar d; "a\n\r\t\b\f\0\x11\u7233\U00017233"d)
{
writeCharLiteral(buf, d);
}
assert(buf.extractSlice() == `a\n\r\t\b\f\0\x11\u7233\U00017233`);
}

View File

@ -44,7 +44,6 @@ enum class TOK : unsigned char
leftCurly,
rightCurly,
colon,
negate,
semicolon,
dotDotDot,
endOfFile,
@ -53,26 +52,18 @@ enum class TOK : unsigned char
assert_,
true_,
false_,
array,
call,
address,
type,
throw_,
new_,
delete_,
star,
variable,
slice,
version_,
module_,
dollar,
template_,
declaration,
typeof_,
pragma_,
typeid_,
uadd,
remove,
comment,
// Operators
@ -84,7 +75,6 @@ enum class TOK : unsigned char
notEqual,
identity,
notIdentity,
index,
is_,
leftShift, // 64
@ -288,8 +278,9 @@ enum class TOK : unsigned char
// C only extended keywords
_import,
cdecl,
cdecl_,
declspec,
stdcall,
attribute__,
MAX,

View File

@ -961,8 +961,6 @@ package mixin template ParseVisitMethods(AST)
//printf("Visiting NewExp\n");
if (e.thisexp)
e.thisexp.accept(this);
if (e.newargs && e.newargs.dim)
visitArgs(e.newargs);
visitType(e.newtype);
if (e.arguments && e.arguments.dim)
visitArgs(e.arguments);
@ -973,8 +971,6 @@ package mixin template ParseVisitMethods(AST)
//printf("Visiting NewAnonClassExp\n");
if (e.thisexp)
e.thisexp.accept(this);
if (e.newargs && e.newargs.dim)
visitArgs(e.newargs);
if (e.arguments && e.arguments.dim)
visitArgs(e.arguments);
if (e.cd)

View File

@ -210,6 +210,9 @@ private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb
error(loc, "undefined identifier `%s`, did you mean %s `%s`?", p, s2.kind(), s2.toChars());
else if (const q = Scope.search_correct_C(id))
error(loc, "undefined identifier `%s`, did you mean `%s`?", p, q);
else if ((id == Id.This && sc.getStructClassScope()) ||
(id == Id._super && sc.getClassScope()))
error(loc, "undefined identifier `%s`, did you mean `typeof(%s)`?", p, p);
else
error(loc, "undefined identifier `%s`", p);
@ -273,7 +276,7 @@ private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb
// Same check as in Expression.semanticY(DotIdExp)
else if (sm.isPackage() && checkAccess(sc, sm.isPackage()))
{
// @@@DEPRECATED_2.096@@@
// @@@DEPRECATED_2.106@@@
// Should be an error in 2.106. Just remove the deprecation call
// and uncomment the null assignment
deprecation(loc, "%s %s is not accessible here, perhaps add 'static import %s;'", sm.kind(), sm.toPrettyChars(), sm.toPrettyChars());
@ -2040,6 +2043,22 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
return mtype.resolved;
}
/* Find the current scope by skipping tag scopes.
* In C, tag scopes aren't considered scopes.
*/
Scope* sc2 = sc;
while (1)
{
sc2 = sc2.inner();
auto scopesym = sc2.scopesym;
if (scopesym.isStructDeclaration())
{
sc2 = sc2.enclosing;
continue;
}
break;
}
/* Declare mtype as a struct/union/enum declaration
*/
void declareTag()
@ -2047,16 +2066,16 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
void declare(ScopeDsymbol sd)
{
sd.members = mtype.members;
auto scopesym = sc.inner().scopesym;
auto scopesym = sc2.inner().scopesym;
if (scopesym.members)
scopesym.members.push(sd);
if (scopesym.symtab && !scopesym.symtabInsert(sd))
{
Dsymbol s2 = scopesym.symtabLookup(sd, mtype.id);
handleTagSymbols(*sc, sd, s2, scopesym);
handleTagSymbols(*sc2, sd, s2, scopesym);
}
sd.parent = sc.parent;
sd.dsymbolSemantic(sc);
sd.parent = sc2.parent;
sd.dsymbolSemantic(sc2);
}
switch (mtype.tok)
@ -2098,7 +2117,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
/* look for pre-existing declaration
*/
Dsymbol scopesym;
auto s = sc.search(mtype.loc, mtype.id, &scopesym, IgnoreErrors | TagNameSpace);
auto s = sc2.search(mtype.loc, mtype.id, &scopesym, IgnoreErrors | TagNameSpace);
if (!s || s.isModule())
{
// no pre-existing declaration, so declare it
@ -2111,7 +2130,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
/* A redeclaration only happens if both declarations are in
* the same scope
*/
const bool redeclar = (scopesym == sc.inner().scopesym);
const bool redeclar = (scopesym == sc2.inner().scopesym);
if (redeclar)
{
@ -2154,7 +2173,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
* picked up and added to the symtab.
*/
sd.semanticRun = PASS.semantic;
sd.dsymbolSemantic(sc);
sd.dsymbolSemantic(sc2);
}
}
else
@ -2985,44 +3004,21 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type
void visitIdentifier(TypeIdentifier mt)
{
//printf("TypeIdentifier::resolve(sc = %p, idents = '%s')\n", sc, mt.toChars());
if ((mt.ident.equals(Id._super) || mt.ident.equals(Id.This)) && !hasThis(sc))
{
// @@@DEPRECATED_v2.091@@@.
// Made an error in 2.086.
// Eligible for removal in 2.091.
if (mt.ident.equals(Id._super))
{
error(mt.loc, "Using `super` as a type is obsolete. Use `typeof(super)` instead");
}
// @@@DEPRECATED_v2.091@@@.
// Made an error in 2.086.
// Eligible for removal in 2.091.
if (mt.ident.equals(Id.This))
{
error(mt.loc, "Using `this` as a type is obsolete. Use `typeof(this)` instead");
}
if (AggregateDeclaration ad = sc.getStructClassScope())
{
if (ClassDeclaration cd = ad.isClassDeclaration())
{
if (mt.ident.equals(Id.This))
mt.ident = cd.ident;
else if (cd.baseClass && mt.ident.equals(Id._super))
mt.ident = cd.baseClass.ident;
}
else
{
StructDeclaration sd = ad.isStructDeclaration();
if (sd && mt.ident.equals(Id.This))
mt.ident = sd.ident;
}
}
}
if (mt.ident == Id.ctfe)
{
error(loc, "variable `__ctfe` cannot be read at compile time");
return returnError();
}
if (mt.ident == Id.builtin_va_list) // gcc has __builtin_va_xxxx for stdarg.h
{
/* Since we don't support __builtin_va_start, -arg, -end, we don't
* have to actually care what -list is. A void* will do.
* If we ever do care, import core.stdc.stdarg and pull
* the definition out of that, similarly to how std.math is handled for PowExp
*/
pt = target.va_listType(loc, sc);
return;
}
Dsymbol scopesym;
Dsymbol s = sc.search(loc, mt.ident, &scopesym);
@ -3821,7 +3817,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
* e.opDot().ident
*/
e = build_overload(e.loc, sc, e, null, fd);
// @@@DEPRECATED_2.087@@@.
// @@@DEPRECATED_2.092@@@.
e.deprecation("`opDot` is deprecated. Use `alias this`");
e = new DotIdExp(e.loc, e, ident);
return returnExp(e.expressionSemantic(sc));

View File

@ -22,6 +22,7 @@ along with GCC; see the file COPYING3. If not see
#include "dmd/aggregate.h"
#include "dmd/ctfe.h"
#include "dmd/declaration.h"
#include "dmd/enum.h"
#include "dmd/expression.h"
#include "dmd/identifier.h"
#include "dmd/init.h"
@ -1460,40 +1461,6 @@ public:
t1 = build_address (t1);
this->result_ = build_libcall (libcall, Type::tvoid, 1, t1);
}
else if (tb1->ty == TY::Tarray)
{
/* For dynamic arrays, the garbage collector is called to immediately
release the memory. */
Type *telem = tb1->nextOf ()->baseElemOf ();
tree ti = null_pointer_node;
if (TypeStruct *ts = telem->isTypeStruct ())
{
/* Might need to run destructor on array contents. */
if (ts->sym->dtor)
ti = build_typeinfo (e->loc, tb1->nextOf ());
}
/* Generate: _delarray_t (&t1, ti); */
this->result_ = build_libcall (LIBCALL_DELARRAYT, Type::tvoid, 2,
build_address (t1), ti);
}
else if (tb1->ty == TY::Tpointer)
{
/* For pointers to a struct instance, if the struct has overloaded
operator delete, then that operator is called. */
t1 = build_address (t1);
Type *tnext = tb1->isTypePointer ()->next->toBasetype ();
/* This case should have been rewritten to `_d_delstruct` in the
semantic phase. */
if (TypeStruct *ts = tnext->isTypeStruct ())
gcc_assert (!ts->sym->dtor);
/* Otherwise, the garbage collector is called to immediately free the
memory allocated for the pointer. */
this->result_ = build_libcall (LIBCALL_DELMEMORY, Type::tvoid, 1, t1);
}
else
{
error ("don%'t know how to delete %qs", e->e1->toChars ());
@ -1936,10 +1903,17 @@ public:
else
{
tree object = build_expr (e->e1);
Type *tb = e->e1->type->toBasetype ();
if (e->e1->type->toBasetype ()->ty != TY::Tstruct)
if (tb->ty != TY::Tstruct)
object = build_deref (object);
/* __complex is represented as a struct in the front-end, but
underlying is really a complex type. */
if (e->e1->type->ty == TY::Tenum
&& e->e1->type->isTypeEnum ()->sym->isSpecial ())
object = build_vconvert (build_ctype (tb), object);
this->result_ = component_ref (object, get_symbol_decl (vd));
}
}
@ -2604,7 +2578,7 @@ public:
for (size_t i = 0; i < e->len; i++)
{
tree value = build_integer_cst (e->charAt (i), etype);
tree value = build_integer_cst (e->getCodeUnit (i), etype);
CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value);
}

View File

@ -83,9 +83,6 @@ DEF_D_RUNTIME (INTERFACE_CAST, "_d_interface_cast", RT(OBJECT),
DEF_D_RUNTIME (NEWITEMT, "_d_newitemT", RT(VOIDPTR), P1(CONST_TYPEINFO), 0)
DEF_D_RUNTIME (NEWITEMIT, "_d_newitemiT", RT(VOIDPTR), P1(CONST_TYPEINFO), 0)
/* Used when calling delete on a pointer. */
DEF_D_RUNTIME (DELMEMORY, "_d_delmemory", RT(VOID), P1(POINTER_VOIDPTR), 0)
/* Used when calling new on an array. The `i' variant is for when the
initializer is nonzero, and the `m' variant is when initializing a
multi-dimensional array. */
@ -102,10 +99,6 @@ DEF_D_RUNTIME (NEWARRAYMITX, "_d_newarraymiTX", RT(ARRAY_VOID),
DEF_D_RUNTIME (ARRAYLITERALTX, "_d_arrayliteralTX", RT(VOIDPTR),
P2(CONST_TYPEINFO, SIZE_T), 0)
/* Used when calling delete on an array. */
DEF_D_RUNTIME (DELARRAYT, "_d_delarray_t", RT(VOID),
P2(ARRAYPTR_VOID, CONST_TYPEINFO), 0)
/* Used for value equality (x == y) and comparisons (x < y) of non-trivial
arrays. Such as an array of structs or classes. */
DEF_D_RUNTIME (ADEQ2, "_adEq2", RT(INT),

View File

@ -993,13 +993,17 @@ public:
t->ctype = build_variant_type_copy (build_ctype (underlying));
build_type_decl (t->ctype, t->sym);
}
else if (!INTEGRAL_TYPE_P (basetype) || TREE_CODE (basetype) == BOOLEAN_TYPE)
else if (t->sym->ident == NULL
|| !INTEGRAL_TYPE_P (basetype)
|| TREE_CODE (basetype) == BOOLEAN_TYPE)
{
/* Enums in D2 can have a base type that is not necessarily integral.
For these, we simplify this a little by using the base type directly
instead of building an ENUMERAL_TYPE. */
/* Enums in D2 can either be anonymous, or have a base type that is not
necessarily integral. For these, we simplify this a little by using
the base type directly instead of building an ENUMERAL_TYPE. */
t->ctype = build_variant_type_copy (basetype);
build_type_decl (t->ctype, t->sym);
if (t->sym->ident != NULL)
build_type_decl (t->ctype, t->sym);
}
else
{

View File

@ -0,0 +1,12 @@
// { dg-do compile }
struct _Complex(T) { T re; T im; }
enum __c_complex_float : _Complex!float;
bool equals(__c_complex_float[] lhs, __c_complex_float[] rhs)
{
foreach (i; 0 .. lhs.length)
if (lhs.ptr[i] != rhs.ptr[i])
return false;
return true;
}

View File

@ -3,7 +3,7 @@
// http://www.99-bottles-of-beer.net/language-d-1212.html
// Generates the "99 bottles of beer" song at compile time,
// using the template metaprograming facilities of D.
// using the template metaprograming facilities of D.
// No executable is generated. No libraries are used.
// Illustrates template default values, template string value parameters,
// compile-time concatenation of constant strings, static if.
@ -24,13 +24,13 @@ template itoa(ulong n)
template showHowMany(int n, string where, bool needcapital = false)
{
static if ( n > 1 )
static if ( n > 1 )
const string showHowMany = itoa!(n) ~ " bottles of beer" ~ where ~ "\n";
else static if ( n == 1 )
const string showHowMany = "1 bottle of beer" ~ where ~ "\n";
else static if ( needcapital )
const string showHowMany = "No more bottles of beer" ~ where ~ "\n";
else
else
const string showHowMany = "no more bottles of beer" ~ where ~ "\n";
}
@ -39,514 +39,514 @@ template beer(int maxbeers, int n = maxbeers)
static if ( n > 0 )
const string beer = showHowMany!(n, " on the wall,", true)
~ showHowMany!(n, ".")
~ "Take one down and pass it around, " ~ "\n"
~ showHowMany!( n - 1 , " on the wall.")
~ "Take one down and pass it around," ~ "\n"
~ showHowMany!( n - 1 , " on the wall.")
~ "\n" ~ beer!(maxbeers, n - 1); // recurse for subsequent verses.
else
const string beer = showHowMany!(n, " on the wall,", true)
~ showHowMany!(n, ".")
~ "Go to the store and buy some more, " ~ "\n"
~ "Go to the store and buy some more," ~ "\n"
~ showHowMany!( maxbeers, " on the wall.");
}
enum expected = `99 bottles of beer on the wall,
99 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
98 bottles of beer on the wall.
98 bottles of beer on the wall,
98 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
97 bottles of beer on the wall.
97 bottles of beer on the wall,
97 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
96 bottles of beer on the wall.
96 bottles of beer on the wall,
96 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
95 bottles of beer on the wall.
95 bottles of beer on the wall,
95 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
94 bottles of beer on the wall.
94 bottles of beer on the wall,
94 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
93 bottles of beer on the wall.
93 bottles of beer on the wall,
93 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
92 bottles of beer on the wall.
92 bottles of beer on the wall,
92 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
91 bottles of beer on the wall.
91 bottles of beer on the wall,
91 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
90 bottles of beer on the wall.
90 bottles of beer on the wall,
90 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
89 bottles of beer on the wall.
89 bottles of beer on the wall,
89 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
88 bottles of beer on the wall.
88 bottles of beer on the wall,
88 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
87 bottles of beer on the wall.
87 bottles of beer on the wall,
87 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
86 bottles of beer on the wall.
86 bottles of beer on the wall,
86 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
85 bottles of beer on the wall.
85 bottles of beer on the wall,
85 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
84 bottles of beer on the wall.
84 bottles of beer on the wall,
84 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
83 bottles of beer on the wall.
83 bottles of beer on the wall,
83 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
82 bottles of beer on the wall.
82 bottles of beer on the wall,
82 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
81 bottles of beer on the wall.
81 bottles of beer on the wall,
81 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
80 bottles of beer on the wall.
80 bottles of beer on the wall,
80 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
79 bottles of beer on the wall.
79 bottles of beer on the wall,
79 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
78 bottles of beer on the wall.
78 bottles of beer on the wall,
78 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
77 bottles of beer on the wall.
77 bottles of beer on the wall,
77 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
76 bottles of beer on the wall.
76 bottles of beer on the wall,
76 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
75 bottles of beer on the wall.
75 bottles of beer on the wall,
75 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
74 bottles of beer on the wall.
74 bottles of beer on the wall,
74 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
73 bottles of beer on the wall.
73 bottles of beer on the wall,
73 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
72 bottles of beer on the wall.
72 bottles of beer on the wall,
72 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
71 bottles of beer on the wall.
71 bottles of beer on the wall,
71 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
70 bottles of beer on the wall.
70 bottles of beer on the wall,
70 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
69 bottles of beer on the wall.
69 bottles of beer on the wall,
69 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
68 bottles of beer on the wall.
68 bottles of beer on the wall,
68 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
67 bottles of beer on the wall.
67 bottles of beer on the wall,
67 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
66 bottles of beer on the wall.
66 bottles of beer on the wall,
66 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
65 bottles of beer on the wall.
65 bottles of beer on the wall,
65 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
64 bottles of beer on the wall.
64 bottles of beer on the wall,
64 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
63 bottles of beer on the wall.
63 bottles of beer on the wall,
63 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
62 bottles of beer on the wall.
62 bottles of beer on the wall,
62 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
61 bottles of beer on the wall.
61 bottles of beer on the wall,
61 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
60 bottles of beer on the wall.
60 bottles of beer on the wall,
60 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
59 bottles of beer on the wall.
59 bottles of beer on the wall,
59 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
58 bottles of beer on the wall.
58 bottles of beer on the wall,
58 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
57 bottles of beer on the wall.
57 bottles of beer on the wall,
57 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
56 bottles of beer on the wall.
56 bottles of beer on the wall,
56 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
55 bottles of beer on the wall.
55 bottles of beer on the wall,
55 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
54 bottles of beer on the wall.
54 bottles of beer on the wall,
54 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
53 bottles of beer on the wall.
53 bottles of beer on the wall,
53 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
52 bottles of beer on the wall.
52 bottles of beer on the wall,
52 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
51 bottles of beer on the wall.
51 bottles of beer on the wall,
51 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
50 bottles of beer on the wall.
50 bottles of beer on the wall,
50 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
49 bottles of beer on the wall.
49 bottles of beer on the wall,
49 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
48 bottles of beer on the wall.
48 bottles of beer on the wall,
48 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
47 bottles of beer on the wall.
47 bottles of beer on the wall,
47 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
46 bottles of beer on the wall.
46 bottles of beer on the wall,
46 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
45 bottles of beer on the wall.
45 bottles of beer on the wall,
45 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
44 bottles of beer on the wall.
44 bottles of beer on the wall,
44 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
43 bottles of beer on the wall.
43 bottles of beer on the wall,
43 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
42 bottles of beer on the wall.
42 bottles of beer on the wall,
42 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
41 bottles of beer on the wall.
41 bottles of beer on the wall,
41 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
40 bottles of beer on the wall.
40 bottles of beer on the wall,
40 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
39 bottles of beer on the wall.
39 bottles of beer on the wall,
39 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
38 bottles of beer on the wall.
38 bottles of beer on the wall,
38 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
37 bottles of beer on the wall.
37 bottles of beer on the wall,
37 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
36 bottles of beer on the wall.
36 bottles of beer on the wall,
36 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
35 bottles of beer on the wall.
35 bottles of beer on the wall,
35 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
34 bottles of beer on the wall.
34 bottles of beer on the wall,
34 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
33 bottles of beer on the wall.
33 bottles of beer on the wall,
33 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
32 bottles of beer on the wall.
32 bottles of beer on the wall,
32 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
31 bottles of beer on the wall.
31 bottles of beer on the wall,
31 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
30 bottles of beer on the wall.
30 bottles of beer on the wall,
30 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
29 bottles of beer on the wall.
29 bottles of beer on the wall,
29 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
28 bottles of beer on the wall.
28 bottles of beer on the wall,
28 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
27 bottles of beer on the wall.
27 bottles of beer on the wall,
27 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
26 bottles of beer on the wall.
26 bottles of beer on the wall,
26 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
25 bottles of beer on the wall.
25 bottles of beer on the wall,
25 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
24 bottles of beer on the wall.
24 bottles of beer on the wall,
24 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
23 bottles of beer on the wall.
23 bottles of beer on the wall,
23 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
22 bottles of beer on the wall.
22 bottles of beer on the wall,
22 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
21 bottles of beer on the wall.
21 bottles of beer on the wall,
21 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
20 bottles of beer on the wall.
20 bottles of beer on the wall,
20 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
19 bottles of beer on the wall.
19 bottles of beer on the wall,
19 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
18 bottles of beer on the wall.
18 bottles of beer on the wall,
18 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
17 bottles of beer on the wall.
17 bottles of beer on the wall,
17 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
16 bottles of beer on the wall.
16 bottles of beer on the wall,
16 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
15 bottles of beer on the wall.
15 bottles of beer on the wall,
15 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
14 bottles of beer on the wall.
14 bottles of beer on the wall,
14 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
13 bottles of beer on the wall.
13 bottles of beer on the wall,
13 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
12 bottles of beer on the wall.
12 bottles of beer on the wall,
12 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
11 bottles of beer on the wall.
11 bottles of beer on the wall,
11 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
10 bottles of beer on the wall.
10 bottles of beer on the wall,
10 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
9 bottles of beer on the wall.
9 bottles of beer on the wall,
9 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
8 bottles of beer on the wall.
8 bottles of beer on the wall,
8 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
7 bottles of beer on the wall.
7 bottles of beer on the wall,
7 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
6 bottles of beer on the wall.
6 bottles of beer on the wall,
6 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
5 bottles of beer on the wall.
5 bottles of beer on the wall,
5 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
4 bottles of beer on the wall.
4 bottles of beer on the wall,
4 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
3 bottles of beer on the wall.
3 bottles of beer on the wall,
3 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
2 bottles of beer on the wall.
2 bottles of beer on the wall,
2 bottles of beer.
Take one down and pass it around,
Take one down and pass it around,
1 bottle of beer on the wall.
1 bottle of beer on the wall,
1 bottle of beer.
Take one down and pass it around,
Take one down and pass it around,
no more bottles of beer on the wall.
No more bottles of beer on the wall,
no more bottles of beer.
Go to the store and buy some more,
Go to the store and buy some more,
99 bottles of beer on the wall.
`;

View File

@ -5,14 +5,14 @@ module object;
class Object { }
class TypeInfo { }
class TypeInfo_Class : TypeInfo
{
class TypeInfo_Class : TypeInfo
{
version(D_LP64) { ubyte[136] _x; } else { ubyte[68] _x; }
}
class Throwable { }
int _d_run_main()
int _d_run_main()
{
try { } catch(Throwable e) { return 1; }
return 0;

View File

@ -51,19 +51,19 @@ void test()
MT s = MyStruct!int(1);
MT[] arr = [s, 2 * s, 3 * s, 4 * s, 5 * s, 6 * s];
MT[] result = new MT[arr.length];
result[] = arr[] + s;
result[] = s + arr[];
result[] = arr[] - s;
result[] = s - arr[];
result[] = arr[] * s;
result[] = s * arr[];
result[] = arr[] / s;
result[] = s / arr[];
result[] = arr[] ^^ s;
result[] = s ^^ arr[];
}

View File

@ -12,11 +12,11 @@ void fun() {
immutable S _is;
Object o;
immutable Object io;
auto a = [pi, ipi];
auto b = [ai, iai];
auto b = [ai, iai];
auto c = [s, _is];
auto d = [o, io];
auto e = [A.a, B.b];
}

View File

@ -1,27 +1,27 @@
// REQUIRED_ARGS: -unittest
// Issue 21285 - Delegate covariance broken between 2.092 and 2.094 (git master).
// Issue 21285 - Delegate covariance broken between 2.092 and 2.094 (git master).
unittest
{
string path;
int bank;
static string path2;
static int bank2;
// delegates
auto a = [
(string arg) { path = arg; },
(string arg) { bank = 1; throw new Exception(""); }
];
// functions
auto ab = [
(string arg) { path2 = arg; },
(string arg) { bank2 = 1; throw new Exception(""); }
];
alias dg = void delegate(string) pure @safe;
alias fn = void function(string) @safe;
static assert(is(typeof(a[0]) == dg));
static assert(is(typeof(ab[0]) == fn));
}

View File

@ -196,7 +196,8 @@ static assert(is( X!( C***, B*** ) == const(B**)* )); // `B***`
static assert(is( X!( C*, I* ) == I* ));
static assert(is( X!( I*, C* ) == I* ));
static assert(Error!( C**, I** ));
//static assert(Error!( C**, I** ));
static assert(is( X!( C**, I** ) == const(I*)* ));
static assert(Error!( C*, D* )); // should work
@ -303,13 +304,15 @@ static assert(is( X!(C[4], B[4]) ));
static assert(Error!( C[4], I[4] ));
static assert(Error!( C[4], D[4] ));
static assert(is( X!( C[4], const(B)[4] ) == const(B)[4] ));
static assert(Error!( C[4], const(I)[4] ));
//static assert(Error!( C[4], const(I)[4] ));
static assert(is( X!( C[4], const(I)[4] ) == const(I)[] ));
static assert(Error!( C[4], const(D)[4] ));
static assert(Error!( C*[4], B*[4] ));
static assert(Error!( C*[4], I*[4] ));
static assert(Error!( C*[4], D*[4] ));
static assert(is( X!( C*[4], const(B*)[4] ) == const(B*)[] )); // !?
static assert(Error!( C*[4], const(I*)[4] ));
//static assert(Error!( C*[4], const(I*)[4] ));
static assert(is( X!( C*[4], const(I*)[4] ) == const(I*)[] ));
static assert(Error!( C*[4], const(D*)[4] ));
static assert(Error!( C*[4], B**[4] ));
static assert(Error!( C*[4], const(B*)*[4] ));

View File

@ -171,7 +171,7 @@ struct T
/****
*/
this(A...)(A args) { }
///
this(int){}
}

View File

@ -49,7 +49,7 @@ struct lldiv_t { long quot,rem; }
void *calloc(size_t, size_t); ///
void *calloc(size_t, size_t); ///
void *malloc(size_t); /// dittx
/**

View File

@ -77,7 +77,7 @@ interface Interface {
V mColon(lazy P p) ; /// 10
}
+/
public P variable; /// 0
V mNone(lazy P p) {} /// 1
pure nothrow V mPrefix(lazy P p) {} /// 2

View File

@ -42,7 +42,7 @@
* $(TROW 4, 5, 6)
* )
*
* $(D_CODE
* $(D_CODE
$(B pragma)( $(I name) );
$(B pragma)( $(I name) , $(I option) [ $(I option) ] );
$(U $(LPAREN))

View File

@ -15,10 +15,10 @@ class TestMembers(TemplateArg)
public:
/**
a static method
a static method
Params: idx = index
*/
static void PublicStaticMethod(int idx)
{

View File

@ -30,41 +30,41 @@ struct Bar
{
/** */
alias A_Foo Bar_A_Foo;
/** */
alias A_Foo_Alias Bar_A_Foo_Alias;
/** */
alias A_Int Bar_A_Int;
/** */
alias This_Foo Bar_This_Foo;
/** */
alias This_Foo_Alias Bar_This_Foo_Alias;
/** */
alias This_Int Bar_This_Int;
/** */
alias Nested Nested_Alias;
/** */
alias .Nested Fake_Nested;
/** */
struct Nested
{
/** */
alias Bar Bar_Nested_Bar_Alias;
/** */
alias .Bar Bar_Alias;
/** */
struct Bar
{
}
}
}

View File

@ -12,12 +12,12 @@ module ddoc9155;
+ ---
+ import std.stdio; //&
+ writeln("Hello world!");
+ if (test) {
+ if (test) {
+ writefln("D programming language");
+ }
+
+ algorithm;
+
+
+ xxx; //comment
+ yyy;
+ /* test
@ -28,7 +28,7 @@ module ddoc9155;
+File f = File("./text.txt", "r");
+uint line = 0;
+ // The ElementType of data is not aggregation type
+foreach (encoded; Base64.encoder(data))
+foreach (encoded; Base64.encoder(data))
+ ---
+/
@ -45,12 +45,12 @@ module ddoc9155;
* ---
* import std.stdio; //&
* writeln("Hello world!");
* if (test) {
* if (test) {
* writefln("D programming language");
* }
*
* algorithm;
*
*
* xxx; //comment
* yyy;
* /+ test

View File

@ -1,9 +1,5 @@
/*
REQUIRED_ARGS: -debug
TEST_OUTPUT:
---
compilable/debugInference.d(35): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
---
https://issues.dlang.org/show_bug.cgi?id=20507
*/
@ -32,7 +28,7 @@ void bar()()
auto f2Ptr = &f2;
S s;
delete s;
destroy(s);
int* ptr = cast(int*) 0;
int[] slice = ptr[0 .. 4];

View File

@ -3,7 +3,7 @@
module defa;
private import imports.defaa;
public abstract class A
{
Display d;

View File

@ -0,0 +1,34 @@
// https://issues.dlang.org/show_bug.cgi?id=22365
class DrawableCache
{
Ref _nullDrawable;
this()
{
debug Log;
}
}
class DrawableCacheEmpty
{
Ref _nullDrawable;
this() {}
}
struct Ref
{
~this()
{
}
}
void foo()
{
try
debug Log;
catch (Exception)
assert(false);
}

View File

@ -0,0 +1,20 @@
//https://issues.dlang.org/show_bug.cgi?id=20777
struct FooInt
{
int i;
auto opBinary(string op : "+")(int j)
{
return typeof(this)(i + j);
}
static @property FooInt max()
{
return typeof(this)(int.max);
}
}
enum foolist
{
hi = FooInt(0),
bye
}

View File

@ -8,7 +8,7 @@ TEST_OUTPUT:
=== ${RESULTS_DIR}/compilable/header18364.di
// D import file generated from 'compilable/header18364.d'
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();

View File

@ -6,10 +6,10 @@ struct IsEqual( T )
{
return p1 == p2;
}
}
}
template find_( Elem, Pred = IsEqual!(Elem) )
{
{
size_t fn( char[] buf, Pred pred = Pred.init )
{
return 3;

View File

@ -0,0 +1,3 @@
typedef enum { C } E;
int a = C;

View File

@ -0,0 +1,3 @@
module imports.test22714a;
import imports.test22714b;
class Statement {}

View File

@ -0,0 +1,12 @@
module imports.test22714b;
import imports.test22714a;
struct Array(T)
{
T[] data;
T[1] smallarray;
}
struct Ensure
{
Statement ensure;
Array!Ensure* arraySyntaxCopy;
}

View File

@ -0,0 +1,42 @@
// https://issues.dlang.org/show_bug.cgi?id=16472
enum e() = 0;
template t(alias v = e!()) {} //Error
alias dummy = t!(e!());
template E(F){
enum E {
K = F(1)
}
}
struct S(F = float, alias e_ = E!double.K) {}
S!float x; // Error: E!double.K is used as a type
alias T = E!double.K;
struct S2(F = float, alias e_ = T) {}
S2!float y; // alias makes it okay...
struct S3(F = float, alias e_ = (E!double.K)) {}
S3!float z; // just putting parens make it okay as well... wat!?
// for coverage
template G(T)
{
struct G
{
alias I = int;
static int i;
}
}
struct H(F = float, alias e_ = G!double) {}
H!float a;
struct H1(F = float, alias e_ = G!double.I) {}
H1!float b;
// https://issues.dlang.org/show_bug.cgi?id=21795
// struct H2(F = float, alias e_ = G!double.i) {}
// H2!float c;

View File

@ -5,7 +5,7 @@ version (CppRuntime_Sun) version = CppMangle_Itanium;
template ScopeClass(C)
if (is(C == class) && __traits(getLinkage, C) == "C++")
{
extern(C++, class)
extern(C++, __traits(getCppNamespaces,C))
extern(C++, (ns))
@ -35,4 +35,4 @@ alias ns = AliasSeq!();
immutable ns2 = AliasSeq!();
extern(C++,(ns)) class Bar {}
extern(C++,) class Baz {}
extern(C++, (ns2)) class Quux {}
extern(C++, (ns2)) class Quux {}

View File

@ -4,7 +4,7 @@ Target.OS defaultTargetOS()
return Target.OS.linux;
}
struct Target
struct Target
{
enum OS { linux }
OS os = defaultTargetOS();

View File

@ -10,7 +10,7 @@
struct S { }
enum E
enum E
{
e0 = 0,
e1 = 1

View File

@ -19,7 +19,7 @@ auto fun()
{
auto x = foo!()(test!(a=>a)());
// pragma(msg, "fun: " ~ typeof(x).mangleof);
return x;
}

View File

@ -3,12 +3,12 @@
bool check()
{
bool result = false;
result |= false;
if (result) goto ret;
result |= false;
if (result) {}
ret: return true;
}

View File

@ -12,5 +12,5 @@ struct Attrib {}
@Attrib enum TEST = 123;
pragma(msg, __traits(getAttributes,
pragma(msg, __traits(getAttributes,
__traits(getMember, example, "TEST")));

View File

@ -1,7 +0,0 @@
// REQUIRED_ARGS: -de
// https://issues.dlang.org/show_bug.cgi?id=18647
deprecated void main ()
{
Object o = new Object;
delete o;
}

View File

@ -9,6 +9,6 @@ struct S(T)
class C
{
alias Al = S!C;
static void func(U)(U var) { }
}

View File

@ -8,5 +8,5 @@ void main()
{
static import core.stdc.math;
}
static assert(!__traits(compiles, core.stdc.math.cos(0)));
static assert(!__traits(compiles, core.stdc.math.cos(0)));
}

View File

@ -1,5 +1,5 @@
//https://issues.dlang.org/show_bug.cgi?id=19315
void main()
void main()
{
#line 100 "file.d"
enum code = q{

View File

@ -1,6 +1,6 @@
// https://issues.dlang.org/show_bug.cgi?id=19557
// Error: redundant linkage `extern (C++)`
extern(C++, "ns")
extern(C++, class)
struct test {}

View File

@ -3,9 +3,9 @@
/*
TEST_OUTPUT:
---
compilable/test19609.d(11): Deprecation: module `imports.test19609a` is deprecated -
compilable/test19609.d(11): Deprecation: module `imports.test19609a` is deprecated
compilable/test19609.d(12): Deprecation: module `imports.test19609b` is deprecated - hello
compilable/test19609.d(13): Deprecation: module `imports.test19609c` is deprecated -
compilable/test19609.d(13): Deprecation: module `imports.test19609c` is deprecated
---
*/
import imports.test19609a;

View File

@ -0,0 +1,76 @@
// https://issues.dlang.org/show_bug.cgi?id=21177
/*
DISABLED: win
TEST_OUTPUT:
---
compilable/test21177.d(103): Deprecation: more format specifiers than 0 arguments
compilable/test21177.d(150): Deprecation: more format specifiers than 0 arguments
compilable/test21177.d(151): Deprecation: more format specifiers than 0 arguments
compilable/test21177.d(152): Deprecation: more format specifiers than 0 arguments
compilable/test21177.d(153): Deprecation: more format specifiers than 0 arguments
compilable/test21177.d(200): Deprecation: more format specifiers than 0 arguments
compilable/test21177.d(203): Deprecation: format specifier `"%m"` is invalid
compilable/test21177.d(204): Deprecation: format specifier `"%m"` is invalid
compilable/test21177.d(205): Deprecation: argument `c` for format specification `"%a"` must be `float*`, not `char*`
compilable/test21177.d(206): Deprecation: argument `c` for format specification `"%a"` must be `float*`, not `char*`
---
*/
import core.stdc.stdio;
import core.stdc.string;
import core.stdc.stdlib;
void main()
{
version (CRuntime_Glibc)
{
#line 100
printf("%m this is a string in errno");
printf("%s %m", "str".ptr, 2);
printf("%a", 2.);
printf("%m %m %s");
printf("%*m");
char* a, b;
sscanf("salut poilu", "%a %m", a, b);
assert(!strcmp(a, b));
free(a);
free(b);
char* t, p;
sscanf("Tomate Patate", "%ms %as", t, p);
free(t);
free(p);
#line 150
sscanf("150", "%m");
sscanf("151", "%ms");
sscanf("152", "%a");
sscanf("153", "%as");
pragma(msg, "compilable/test21177.d(200): Deprecation: more format specifiers than 0 arguments");
pragma(msg, "compilable/test21177.d(203): Deprecation: format specifier `\"%m\"` is invalid");
pragma(msg, "compilable/test21177.d(204): Deprecation: format specifier `\"%m\"` is invalid");
pragma(msg, "compilable/test21177.d(205): Deprecation: argument `c` for format specification `\"%a\"` must be `float*`, not `char*`");
pragma(msg, "compilable/test21177.d(206): Deprecation: argument `c` for format specification `\"%a\"` must be `float*`, not `char*`");
}
else
{
// fake it
pragma(msg, "compilable/test21177.d(103): Deprecation: more format specifiers than 0 arguments");
pragma(msg, "compilable/test21177.d(150): Deprecation: more format specifiers than 0 arguments");
pragma(msg, "compilable/test21177.d(151): Deprecation: more format specifiers than 0 arguments");
pragma(msg, "compilable/test21177.d(152): Deprecation: more format specifiers than 0 arguments");
pragma(msg, "compilable/test21177.d(153): Deprecation: more format specifiers than 0 arguments");
#line 200
printf("%m");
char* c;
sscanf("204", "%m", c);
sscanf("205", "%ms", c);
sscanf("206", "%a", c);
sscanf("207", "%as", c);
}
}

View File

@ -0,0 +1,71 @@
// https://issues.dlang.org/show_bug.cgi?id=21674
// REQUIRED_ARGS: -de
struct Module
{
CachedString data;
}
struct CachedString
{
private size_t len;
this (string data) { this.len = data.length; }
public string str () const { return null; }
public void str (string value) { this.len = value.length; }
alias str this;
}
void test21674a()
{
Module m;
m.data = "Hello World";
}
//////////////////////////////////////////
struct StaticGetter(T)
{
private static T _impl;
static ref T value() { return _impl; }
alias value this;
}
struct StaticWrapper
{
StaticGetter!int get;
alias get this;
}
void test21674b()
{
StaticGetter!float sg;
sg = 4.2;
StaticWrapper sw;
sw = 42;
}
//////////////////////////////////////////
EntryType arr;
auto getPtr() { return &arr; }
struct EntryType
{
bool _state;
alias _state this;
}
struct S19441
{
@property auto ref entry() { return *getPtr(); }
alias entry this;
}
void test19441()
{
S19441 s19441;
s19441 = true;
}

View File

@ -1,4 +1,4 @@
// REQUIRED_ARGS: -profile -c
import core.stdc.stdarg;
import core.stdc.stdarg;
void error(...) { }

View File

@ -0,0 +1,4 @@
// https://issues.dlang.org/show_bug.cgi?id=22632
static assert(["one": 1] != null);
static assert(null != ["one": 1]);

View File

@ -0,0 +1,3 @@
// EXTRA_FILES: imports/test22714a.d imports/test22714b.d
// https://issues.dlang.org/show_bug.cgi?id=22714
import imports.test22714a;

View File

@ -0,0 +1,6 @@
// https://issues.dlang.org/show_bug.cgi?id=22734
// EXTRA_FILES: imports/imp22734.c
import imports.imp22734;
auto dc = C;

View File

@ -256,7 +256,7 @@ label1:
else
assert(89);
else
assert(12);
assert(12);
with (x)
@ -299,7 +299,7 @@ label1:
if (true)
assert(110);
else
assert(112);
assert(112);
finally
assert(111);
@ -316,7 +316,7 @@ label1:
int w;
static if (true)
int t;
int t;
else static if (false)
int u;
else

View File

@ -7,7 +7,7 @@ void main()
static assert(!__traits(compiles, { class D : FinalC{} }));
scope class ScopeC{}
// static assert(!__traits(compiles, { auto sc = new ScopeC(); }));
static assert(!__traits(compiles, { auto sc = new ScopeC(); }));
static assert( __traits(compiles, { scope sc = new ScopeC(); }));
synchronized class SyncC{ void f(){} }

View File

@ -10,7 +10,7 @@ struct bar2
class InnerBar {
bar2 b;
this()
{
b = bar2(0);
@ -21,7 +21,7 @@ struct bar1
{
InnerBar b;
}
class Foo
{
bar1 m_bar1;

View File

@ -5,25 +5,25 @@ class Bar
{
interface I_Foo { void i_inner(); }
class C_Foo { void c_inner() { } }
class Impl1 : C_Foo, I_Foo
{
override void i_inner() { }
override void c_inner() { }
}
class Impl2 : C_Foo, .I_Foo
{
override void i_outer() { }
override void c_inner() { }
}
class Impl3 : .C_Foo, I_Foo
{
override void i_inner() { }
override void c_outer() { }
}
class Impl4 : .C_Foo, .I_Foo
{
override void i_outer() { }

View File

@ -14,4 +14,4 @@ struct Test1c
{
const Test1b b;
@disable this(this);
}
}

View File

@ -17,3 +17,19 @@ void test()
size_t* p;
const ppi = const(PackedPtrImpl!(3))(p);
}
/************************************************/
// issues.dlang.org/show_bug.cgi?id=22541
struct S
{
int i;
int* ptr;
int* wannabeReturnRef() scope return
{
return &i;
}
}

View File

@ -9,6 +9,6 @@ class Panzer {}
class Tiger : Panzer {}
static assert (() {
Panzer p = new Tiger(); return classname(p);
Panzer p = new Tiger(); return classname(p);
} () == "Tiger");

View File

@ -65,20 +65,9 @@ void testNewScope()
/***************** DeleteExp *******************/
/*
TEST_OUTPUT:
---
compilable/vgc1.d(81): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
compilable/vgc1.d(81): vgc: `delete` requires the GC
compilable/vgc1.d(82): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
compilable/vgc1.d(82): vgc: `delete` requires the GC
compilable/vgc1.d(83): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
compilable/vgc1.d(83): vgc: `delete` requires the GC
---
*/
void testDelete(int* p, Object o, S1* s)
{
delete p;
delete o;
delete s;
destroy(p);
destroy(o);
destroy(s);
}

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