@@ -1,4 +1,4 @@
-9038e64c5b67a10763d32893f53bb6c610df3595
+e598f69c0726ad1bf6b2e15e0b60d7cead737fad
The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository.
@@ -61,3 +61,5 @@ typedef Array<class ReturnStatement *> ReturnStatements;
typedef Array<class GotoStatement *> GotoStatements;
typedef Array<class TemplateInstance *> TemplateInstances;
+
+typedef Array<struct Ensure> Ensures;
@@ -20,6 +20,16 @@ class LabelDsymbol;
class Initializer;
class Module;
class ForeachStatement;
+struct Ensure
+{
+ Identifier *id;
+ Statement *ensure;
+
+ Ensure();
+ Ensure(Identifier *id, Statement *ensure);
+ Ensure syntaxCopy();
+ static Ensures *arraySyntaxCopy(Ensures *a);
+};
class FuncDeclaration;
class ExpInitializer;
class StructDeclaration;
@@ -516,8 +526,10 @@ class FuncDeclaration : public Declaration
{
public:
Types *fthrows; // Array of Type's of exceptions (not used)
- Statement *frequire;
- Statement *fensure;
+ Statements *frequires; // in contracts
+ Ensures *fensures; // out contracts
+ Statement *frequire; // lowered in contract
+ Statement *fensure; // lowered out contract
Statement *fbody;
FuncDeclarations foverrides; // functions this function overrides
@@ -526,8 +538,7 @@ public:
const char *mangleString; // mangled symbol created from mangleExact()
- Identifier *outId; // identifier for out statement
- VarDeclaration *vresult; // variable corresponding to outId
+ VarDeclaration *vresult; // result variable for out contracts
LabelDsymbol *returnLabel; // where the return goes
// used to prevent symbols in different
@@ -292,6 +292,42 @@ public:
}
};
+/***********************************************************
+ * Tuple of result identifier (possibly null) and statement.
+ * This is used to store out contracts: out(id){ ensure }
+ */
+Ensure::Ensure()
+{
+ this->id = NULL;
+ this->ensure = NULL;
+}
+
+Ensure::Ensure(Identifier *id, Statement *ensure)
+{
+ this->id = id;
+ this->ensure = ensure;
+}
+
+Ensure Ensure::syntaxCopy()
+{
+ return Ensure(id, ensure->syntaxCopy());
+}
+
+/*****************************************
+ * Do syntax copy of an array of Ensure's.
+ */
+Ensures *Ensure::arraySyntaxCopy(Ensures *a)
+{
+ Ensures *b = NULL;
+ if (a)
+ {
+ b = a->copy();
+ for (size_t i = 0; i < a->length; i++)
+ (*b)[i] = (*a)[i].syntaxCopy();
+ }
+ return b;
+}
+
/********************************* FuncDeclaration ****************************/
FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, StorageClass storage_class, Type *type)
@@ -314,10 +350,11 @@ FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, StorageCla
fdrequire = NULL;
fdensure = NULL;
mangleString = NULL;
- outId = NULL;
vresult = NULL;
returnLabel = NULL;
fensure = NULL;
+ frequires = NULL;
+ fensures = NULL;
fbody = NULL;
localsymtab = NULL;
vthis = NULL;
@@ -372,10 +409,9 @@ Dsymbol *FuncDeclaration::syntaxCopy(Dsymbol *s)
FuncDeclaration *f =
s ? (FuncDeclaration *)s
: new FuncDeclaration(loc, endloc, ident, storage_class, type->syntaxCopy());
- f->outId = outId;
- f->frequire = frequire ? frequire->syntaxCopy() : NULL;
- f->fensure = fensure ? fensure->syntaxCopy() : NULL;
- f->fbody = fbody ? fbody->syntaxCopy() : NULL;
+ f->frequires = frequires ? Statement::arraySyntaxCopy(frequires) : NULL;
+ f->fensures = fensures ? Ensure::arraySyntaxCopy(fensures) : NULL;
+ f->fbody = fbody ? fbody->syntaxCopy() : NULL;
assert(!fthrows); // deprecated
return f;
}
@@ -441,6 +477,28 @@ static void initInferAttributes(FuncDeclaration *fd)
fd->flags |= FUNCFLAGinferScope;
}
+// Returns true if a contract can appear without a function body.
+static bool allowsContractWithoutBody(FuncDeclaration *funcdecl)
+{
+ assert(!funcdecl->fbody);
+
+ /* Contracts can only appear without a body when they are virtual
+ * interface functions or abstract.
+ */
+ Dsymbol *parent = funcdecl->toParent();
+ InterfaceDeclaration *id = parent->isInterfaceDeclaration();
+
+ if (!funcdecl->isAbstract() &&
+ (funcdecl->fensures || funcdecl->frequires) &&
+ !(id && funcdecl->isVirtual()))
+ {
+ ClassDeclaration *cd = parent->isClassDeclaration();
+ if (!(cd && cd->isAbstract()))
+ return false;
+ }
+ return true;
+}
+
// Do the semantic analysis on the external interface to the function.
void FuncDeclaration::semantic(Scope *sc)
@@ -780,11 +838,6 @@ void FuncDeclaration::semantic(Scope *sc)
error("destructors, postblits and invariants are not allowed in union %s", ud->toChars());
}
- /* Contracts can only appear without a body when they are virtual interface functions
- */
- if (!fbody && (fensure || frequire) && !(id && isVirtual()))
- error("in and out contracts require function body");
-
if (parent->isStructDeclaration())
{
if (isCtorDeclaration())
@@ -1157,6 +1210,12 @@ void FuncDeclaration::semantic(Scope *sc)
// Reflect this->type to f because it could be changed by findVtblIndex
f = type->toTypeFunction();
+Ldone:
+ /* Contracts can only appear without a body when they are virtual interface functions
+ */
+ if (!fbody && !allowsContractWithoutBody(this))
+ error("in and out contracts can only appear without a body when they are virtual interface functions or abstract");
+
/* Do not allow template instances to add virtual functions
* to a class.
*/
@@ -1186,7 +1245,6 @@ void FuncDeclaration::semantic(Scope *sc)
if (isMain())
checkDmain(); // Check main() parameters and return type
-Ldone:
/* Purity and safety can be inferred for some functions by examining
* the function body.
*/
@@ -1270,7 +1328,7 @@ void FuncDeclaration::semantic2(Scope *sc)
*/
static bool needsFensure(FuncDeclaration *fd)
{
- if (fd->fensure)
+ if (fd->fensures)
return true;
for (size_t i = 0; i < fd->foverrides.length; i++)
@@ -1287,16 +1345,83 @@ static bool needsFensure(FuncDeclaration *fd)
}
/****************************************************
- * Rewrite contracts as nested functions, then call them. Doing it as nested
- * functions means that overriding functions can call them.
+ * Check whether result variable can be built.
+ * Returns:
+ * `true` if the function has a return type that
+ * is different from `void`.
+ */
+static bool canBuildResultVar(FuncDeclaration *fd)
+{
+ TypeFunction *f = (TypeFunction *)fd->type;
+ return f && f->nextOf() && f->nextOf()->toBasetype()->ty != Tvoid;
+}
+
+/****************************************************
+ * Rewrite contracts as statements.
* Params:
- * fd = the function to rewrite contracts for
+ * fdx = the function to rewrite contracts for
*/
static void buildEnsureRequire(FuncDeclaration *fdx)
{
+ if (fdx->frequires)
+ {
+ /* in { statements1... }
+ * in { statements2... }
+ * ...
+ * becomes:
+ * in { { statements1... } { statements2... } ... }
+ */
+ assert(fdx->frequires->length);
+ Loc loc = (*fdx->frequires)[0]->loc;
+ Statements *s = new Statements;
+ for (size_t i = 0; i < fdx->frequires->length; i++)
+ {
+ Statement *r = (*fdx->frequires)[i];
+ s->push(new ScopeStatement(r->loc, r, r->loc));
+ }
+ fdx->frequire = new CompoundStatement(loc, s);
+ }
+
+ if (fdx->fensures)
+ {
+ /* out(id1) { statements1... }
+ * out(id2) { statements2... }
+ * ...
+ * becomes:
+ * out(__result) { { ref id1 = __result; { statements1... } }
+ * { ref id2 = __result; { statements2... } } ... }
+ */
+ assert(fdx->fensures->length);
+ Loc loc = (*fdx->fensures)[0].ensure->loc;
+ Statements *s = new Statements;
+ for (size_t i = 0; i < fdx->fensures->length; i++)
+ {
+ Ensure r = (*fdx->fensures)[i];
+ if (r.id && canBuildResultVar(fdx))
+ {
+ Loc rloc = r.ensure->loc;
+ IdentifierExp *resultId = new IdentifierExp(rloc, Id::result);
+ ExpInitializer *init = new ExpInitializer(rloc, resultId);
+ StorageClass stc = STCref | STCtemp | STCresult;
+ VarDeclaration *decl = new VarDeclaration(rloc, NULL, r.id, init);
+ decl->storage_class = stc;
+ ExpStatement *sdecl = new ExpStatement(rloc, decl);
+ s->push(new ScopeStatement(rloc, new CompoundStatement(rloc, sdecl, r.ensure), rloc));
+ }
+ else
+ {
+ s->push(r.ensure);
+ }
+ }
+ fdx->fensure = new CompoundStatement(loc, s);
+ }
+
if (!fdx->isVirtual())
return;
+ /* Rewrite contracts as nested functions, then call them. Doing it as nested
+ * functions means that overriding functions can call them.
+ */
TypeFunction *f = (TypeFunction *)fdx->type;
if (fdx->frequire)
@@ -1322,9 +1447,6 @@ static void buildEnsureRequire(FuncDeclaration *fdx)
fdx->fdrequire = fd;
}
- if (!fdx->outId && f->nextOf() && f->nextOf()->toBasetype()->ty != Tvoid)
- fdx->outId = Id::result; // provide a default
-
if (fdx->fensure)
{
/* out (result) { ... }
@@ -1335,9 +1457,9 @@ static void buildEnsureRequire(FuncDeclaration *fdx)
Loc loc = fdx->fensure->loc;
Parameters *fparams = new Parameters();
Parameter *p = NULL;
- if (fdx->outId)
+ if (canBuildResultVar(fdx))
{
- p = new Parameter(STCref | STCconst, f->nextOf(), fdx->outId, NULL, NULL);
+ p = new Parameter(STCref | STCconst, f->nextOf(), Id::result, NULL, NULL);
fparams->push(p);
}
TypeFunction *tf = new TypeFunction(ParameterList(fparams), Type::tvoid, LINKd);
@@ -1350,8 +1472,8 @@ static void buildEnsureRequire(FuncDeclaration *fdx)
fd->fbody = fdx->fensure;
Statement *s1 = new ExpStatement(loc, fd);
Expression *eresult = NULL;
- if (fdx->outId)
- eresult = new IdentifierExp(loc, fdx->outId);
+ if (canBuildResultVar(fdx))
+ eresult = new IdentifierExp(loc, Id::result);
Expression *e = new CallExp(loc, new VarExp(loc, fd, false), eresult);
Statement *s2 = new ExpStatement(loc, e);
fdx->fensure = new CompoundStatement(loc, s1, s2);
@@ -1435,13 +1557,13 @@ void FuncDeclaration::semantic3(Scope *sc)
unsigned oldErrors = global.errors;
- if (frequire)
+ if (frequires)
{
for (size_t i = 0; i < foverrides.length; i++)
{
FuncDeclaration *fdv = foverrides[i];
- if (fdv->fbody && !fdv->frequire)
+ if (fdv->fbody && !fdv->frequires)
{
error("cannot have an in contract when overriden function %s does not have an in contract", fdv->toPrettyChars());
break;
@@ -1450,9 +1572,9 @@ void FuncDeclaration::semantic3(Scope *sc)
}
// Remember whether we need to generate an 'out' contract.
- bool needEnsure = needsFensure(this);
+ const bool needEnsure = needsFensure(this);
- if (fbody || frequire || needEnsure)
+ if (fbody || frequires || needEnsure)
{
/* Symbol table into which we place parameters and nested functions,
* solely to diagnose name collisions.
@@ -2039,7 +2161,7 @@ void FuncDeclaration::semantic3(Scope *sc)
}
frequire = mergeFrequire(frequire);
- fensure = mergeFensure(fensure, outId);
+ fensure = mergeFensure(fensure, Id::result);
Statement *freq = frequire;
Statement *fens = fensure;
@@ -2075,8 +2197,18 @@ void FuncDeclaration::semantic3(Scope *sc)
{
/* fensure is composed of the [out] contracts
*/
- if (f->next->ty == Tvoid && outId)
- error("void functions have no result");
+ if (f->next->ty == Tvoid && fensures)
+ {
+ for (size_t i = 0; i < fensures->length; i++)
+ {
+ Ensure e = (*fensures)[i];
+ if (e.id)
+ {
+ error(e.ensure->loc, "`void` functions have no result");
+ //fens = NULL;
+ }
+ }
+ }
sc2 = scout; //push
sc2->flags = (sc2->flags & ~SCOPEcontract) | SCOPEensure;
@@ -2263,8 +2395,7 @@ void FuncDeclaration::semantic3(Scope *sc)
}
// If declaration has no body, don't set sbody to prevent incorrect codegen.
- InterfaceDeclaration *id = parent->isInterfaceDeclaration();
- if (fbody || (id && (fdensure || fdrequire) && isVirtual()))
+ if (fbody || allowsContractWithoutBody(this))
fbody = sbody;
}
@@ -2277,7 +2408,7 @@ void FuncDeclaration::semantic3(Scope *sc)
}
}
- if (naked && (fensure || frequire))
+ if (naked && (fensures || frequires))
error("naked assembly functions with contracts are not supported");
sc2->callSuper = 0;
@@ -2610,11 +2741,8 @@ void FuncDeclaration::buildResultVar(Scope *sc, Type *tret)
* So, in here it may be a temporary type for vresult, and after
* fbody->semantic() running, vresult->type might be modified.
*/
- vresult = new VarDeclaration(loc, tret, outId ? outId : Id::result, NULL);
- vresult->storage_class |= STCnodtor;
-
- if (outId == Id::result)
- vresult->storage_class |= STCtemp;
+ vresult = new VarDeclaration(loc, tret, Id::result, NULL);
+ vresult->storage_class |= STCnodtor | STCtemp;
if (!isVirtual())
vresult->storage_class |= STCconst;
vresult->storage_class |= STCresult;
@@ -2685,7 +2813,7 @@ Statement *FuncDeclaration::mergeFrequire(Statement *sf)
* be completed before code generation occurs.
* https://issues.dlang.org/show_bug.cgi?id=3602
*/
- if (fdv->frequire && fdv->semanticRun != PASSsemantic3done)
+ if (fdv->frequires && fdv->semanticRun != PASSsemantic3done)
{
assert(fdv->_scope);
Scope *sc = fdv->_scope->push();
@@ -2758,7 +2886,7 @@ Statement *FuncDeclaration::mergeFensure(Statement *sf, Identifier *oid)
//printf("fdv->fensure: %s\n", fdv->fensure->toChars());
// Make the call: __ensure(result)
Expression *eresult = NULL;
- if (outId)
+ if (canBuildResultVar(this))
{
eresult = new IdentifierExp(loc, oid);
@@ -1950,32 +1950,70 @@ public:
int saveauto = hgs->autoMember;
hgs->tpltMember = 0;
hgs->autoMember = 0;
-
buf->writenl();
-
+ bool requireDo = false;
// in{}
- if (f->frequire)
+ if (f->frequires)
{
- buf->writestring("in");
- buf->writenl();
- f->frequire->accept(this);
+ for (size_t i = 0; i < f->frequires->length; i++)
+ {
+ Statement *frequire = (*f->frequires)[i];
+ buf->writestring("in");
+ if (ExpStatement *es = frequire->isExpStatement())
+ {
+ assert(es->exp && es->exp->op == TOKassert);
+ buf->writestring(" (");
+ ((AssertExp *)es->exp)->e1->accept(this);
+ buf->writeByte(')');
+ buf->writenl();
+ requireDo = false;
+ }
+ else
+ {
+ buf->writenl();
+ frequire->accept(this);
+ requireDo = true;
+ }
+ }
}
// out{}
- if (f->fensure)
+ if (f->fensures)
{
- buf->writestring("out");
- if (f->outId)
+ for (size_t i = 0; i < f->fensures->length; i++)
{
- buf->writeByte('(');
- buf->writestring(f->outId->toChars());
- buf->writeByte(')');
+ Ensure fensure = (*f->fensures)[i];
+ buf->writestring("out");
+ if (ExpStatement *es = fensure.ensure->isExpStatement())
+ {
+ assert(es->exp && es->exp->op == TOKassert);
+ buf->writestring(" (");
+ if (fensure.id)
+ {
+ buf->writestring(fensure.id->toChars());
+ }
+ buf->writestring("; ");
+ ((AssertExp *)es->exp)->e1->accept(this);
+ buf->writeByte(')');
+ buf->writenl();
+ requireDo = false;
+ }
+ else
+ {
+ if (fensure.id)
+ {
+ buf->writeByte('(');
+ buf->writestring(fensure.id->toChars());
+ buf->writeByte(')');
+ }
+ buf->writenl();
+ fensure.ensure->accept(this);
+ requireDo = true;
+ }
}
- buf->writenl();
- f->fensure->accept(this);
}
- if (f->frequire || f->fensure)
+ if (requireDo)
{
buf->writestring("body");
buf->writenl();
@@ -2093,7 +2131,18 @@ public:
if (stcToBuffer(buf, d->storage_class))
buf->writeByte(' ');
buf->writestring("invariant");
- bodyToBuffer(d);
+ if (ExpStatement *es = d->fbody->isExpStatement())
+ {
+ assert(es->exp && es->exp->op == TOKassert);
+ buf->writestring(" (");
+ ((AssertExp *)es->exp)->e1->accept(this);
+ buf->writestring(");");
+ buf->writenl();
+ }
+ else
+ {
+ bodyToBuffer(d);
+ }
}
void visit(UnitTestDeclaration *d)
@@ -372,11 +372,11 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl, PrefixAttributes
case TOKinvariant:
{
Token *t = peek(&token);
- if ((t->value == TOKlparen && peek(t)->value == TOKrparen) ||
- t->value == TOKlcurly)
+ if (t->value == TOKlparen || t->value == TOKlcurly)
{
- // invariant {}
- // invariant() {}
+ // invariant { statements... }
+ // invariant() { statements... }
+ // invariant (expression);
s = parseInvariant(pAttrs);
}
else
@@ -1846,7 +1846,9 @@ Dsymbol *Parser::parseSharedStaticDtor(PrefixAttributes *pAttrs)
/*****************************************
* Parse an invariant definition:
- * invariant() { body }
+ * invariant { statements... }
+ * invariant() { statements... }
+ * invariant (expression);
* Current token is 'invariant'.
*/
@@ -1856,10 +1858,35 @@ Dsymbol *Parser::parseInvariant(PrefixAttributes *pAttrs)
StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
nextToken();
- if (token.value == TOKlparen) // optional ()
+ if (token.value == TOKlparen) // optional () or invariant (expression);
{
nextToken();
- check(TOKrparen);
+ if (token.value != TOKrparen) // invariant (expression);
+ {
+ Expression *e = parseAssignExp();
+ Expression *msg = NULL;
+ if (token.value == TOKcomma)
+ {
+ nextToken();
+ if (token.value != TOKrparen)
+ {
+ msg = parseAssignExp();
+ if (token.value == TOKcomma)
+ nextToken();
+ }
+ }
+ check(TOKrparen);
+ check(TOKsemicolon);
+ e = new AssertExp(loc, e, msg);
+ ExpStatement *fbody = new ExpStatement(loc, e);
+ InvariantDeclaration *f = new InvariantDeclaration(loc, token.loc, stc);
+ f->fbody = fbody;
+ return f;
+ }
+ else
+ {
+ nextToken();
+ }
}
InvariantDeclaration *f = new InvariantDeclaration(loc, Loc(), stc);
@@ -4426,11 +4453,12 @@ FuncDeclaration *Parser::parseContracts(FuncDeclaration *f)
// The following is irrelevant, as it is overridden by sc->linkage in
// TypeFunction::semantic
linkage = LINKd; // nested functions have D linkage
+ bool requireDo = false;
L1:
switch (token.value)
{
case TOKlcurly:
- if (f->frequire || f->fensure)
+ if (requireDo)
error("missing body { ... } after in or out");
f->fbody = parseStatement(PSsemi);
f->endloc = endloc;
@@ -4448,35 +4476,100 @@ L1:
break;
case TOKin:
+ {
+ // in { statements... }
+ // in (expression)
+ Loc loc = token.loc;
nextToken();
- if (f->frequire)
- error("redundant 'in' statement");
- f->frequire = parseStatement(PScurly | PSscope);
+ if (!f->frequires)
+ {
+ f->frequires = new Statements();
+ }
+ if (token.value == TOKlparen)
+ {
+ nextToken();
+ Expression *e = parseAssignExp();
+ Expression *msg = NULL;
+ if (token.value == TOKcomma)
+ {
+ nextToken();
+ if (token.value != TOKrparen)
+ {
+ msg = parseAssignExp();
+ if (token.value == TOKcomma)
+ nextToken();
+ }
+ }
+ check(TOKrparen);
+ e = new AssertExp(loc, e, msg);
+ f->frequires->push(new ExpStatement(loc, e));
+ requireDo = false;
+ }
+ else
+ {
+ f->frequires->push(parseStatement(PScurly | PSscope));
+ requireDo = true;
+ }
goto L1;
+ }
case TOKout:
- // parse: out (identifier) { statement }
+ {
+ // out { statements... }
+ // out (; expression)
+ // out (identifier) { statements... }
+ // out (identifier; expression)
+ Loc loc = token.loc;
nextToken();
+ if (!f->fensures)
+ {
+ f->fensures = new Ensures();
+ }
+ Identifier *id = NULL;
if (token.value != TOKlcurly)
{
check(TOKlparen);
- if (token.value != TOKidentifier)
- error("(identifier) following 'out' expected, not %s", token.toChars());
- f->outId = token.ident;
- nextToken();
+ if (token.value != TOKidentifier && token.value != TOKsemicolon)
+ error("`(identifier) { ... }` or `(identifier; expression)` following `out` expected, not `%s`", token.toChars());
+ if (token.value != TOKsemicolon)
+ {
+ id = token.ident;
+ nextToken();
+ }
+ if (token.value == TOKsemicolon)
+ {
+ nextToken();
+ Expression *e = parseAssignExp();
+ Expression *msg = NULL;
+ if (token.value == TOKcomma)
+ {
+ nextToken();
+ if (token.value != TOKrparen)
+ {
+ msg = parseAssignExp();
+ if (token.value == TOKcomma)
+ nextToken();
+ }
+ }
+ check(TOKrparen);
+ e = new AssertExp(loc, e, msg);
+ f->fensures->push(Ensure(id, new ExpStatement(loc, e)));
+ requireDo = false;
+ goto L1;
+ }
check(TOKrparen);
}
- if (f->fensure)
- error("redundant 'out' statement");
- f->fensure = parseStatement(PScurly | PSscope);
+ f->fensures->push(Ensure(id, parseStatement(PScurly | PSscope)));
+ requireDo = true;
goto L1;
+ }
case TOKsemicolon:
if (!literal)
{
// Bugzilla 15799: Semicolon becomes a part of function declaration
- // only when neither of contracts exists.
- if (!f->frequire && !f->fensure)
+ // only when 'do' is not required
+ if (!requireDo)
nextToken();
break;
}
@@ -4486,10 +4579,10 @@ L1:
Ldefault:
if (literal)
{
- const char *sbody = (f->frequire || f->fensure) ? "body " : "";
+ const char *sbody = requireDo ? "do " : "";
error("missing %s{ ... } for function literal", sbody);
}
- else if (!f->frequire && !f->fensure) // allow these even with no body
+ else if (!requireDo) // allow these even with no body
{
error("semicolon expected following function declaration");
}
@@ -109,6 +109,24 @@ Statement *Statement::syntaxCopy()
return NULL;
}
+/*************************************
+ * Do syntax copy of an array of Statement's.
+ */
+Statements *Statement::arraySyntaxCopy(Statements *a)
+{
+ Statements *b = NULL;
+ if (a)
+ {
+ b = a->copy();
+ for (size_t i = 0; i < a->length; i++)
+ {
+ Statement *s = (*a)[i];
+ (*b)[i] = s ? s->syntaxCopy() : NULL;
+ }
+ }
+ return b;
+}
+
void Statement::print()
{
fprintf(stderr, "%s\n", toChars());
@@ -560,14 +578,7 @@ CompoundStatement *CompoundStatement::create(Loc loc, Statement *s1, Statement *
Statement *CompoundStatement::syntaxCopy()
{
- Statements *a = new Statements();
- a->setDim(statements->length);
- for (size_t i = 0; i < statements->length; i++)
- {
- Statement *s = (*statements)[i];
- (*a)[i] = s ? s->syntaxCopy() : NULL;
- }
- return new CompoundStatement(loc, a);
+ return new CompoundStatement(loc, Statement::arraySyntaxCopy(statements));
}
Statements *CompoundStatement::flatten(Scope *)
@@ -74,6 +74,7 @@ public:
Statement(Loc loc);
virtual Statement *syntaxCopy();
+ static Statements *arraySyntaxCopy(Statements *a);
void print();
const char *toChars();
@@ -10,6 +10,30 @@ static assert(true, "message");
alias double mydbl;
+alias fl1 = function ()
+ in {}
+ in (true)
+ out (; true)
+ out (r; true)
+ out
+ {
+ }
+ out (r)
+ {
+ }
+ do
+ {
+ return 2;
+ };
+
+alias fl2 = function ()
+ in (true)
+ out(; true)
+ out(r; true)
+ {
+ return 2;
+ };
+
int testmain()
in
{
@@ -133,11 +157,11 @@ template Foo(T, int V)
}
try
- bar(1, 2);
+ bar(1, 2);
catch(Object o)
- x++;
+ x++;
finally
- x--;
+ x--;
Object o;
synchronized (o)
@@ -244,6 +268,7 @@ class Test
pure nothrow @safe @nogc unittest {}
pure nothrow @safe @nogc invariant {}
+ pure nothrow @safe @nogc invariant (true);
pure nothrow @safe @nogc new (size_t sz) { return null; }
pure nothrow @safe @nogc delete (void* p) { }
@@ -1,10 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail17502.d(12): Error: function fail17502.Foo.foo void functions have no result
-fail_compilation/fail17502.d(13): Error: cannot have parameter of type const(void)
-fail_compilation/fail17502.d(16): Error: function fail17502.Foo.bar void functions have no result
-fail_compilation/fail17502.d(17): Error: cannot have parameter of type const(void)
+fail_compilation/fail17502.d(13): Error: function `fail17502.Foo.foo` `void` functions have no result
+fail_compilation/fail17502.d(13): Error: undefined identifier `res`
+fail_compilation/fail17502.d(17): Error: function `fail17502.Foo.bar` `void` functions have no result
+fail_compilation/fail17502.d(17): Error: undefined identifier `res`
---
*/
class Foo
@@ -421,6 +421,56 @@ void test6417()
(new Bug6417).bar();
}
+/*******************************************/
+// 6549
+
+class C6549
+{
+ static int ocount = 0;
+ static int icount = 0;
+
+ abstract int foo(int)
+ in { ++icount; }
+ out { ++ocount; }
+}
+
+class CD6549 : C6549
+{
+ override int foo(int)
+ in { assert(false); }
+ do { return 10; }
+}
+
+abstract class D6549
+{
+ static int icount = 0;
+ static int ocount = 0;
+
+ int foo(int)
+ in { ++icount; }
+ out { ++ocount; }
+}
+
+class DD6549 : D6549
+{
+ override int foo(int)
+ in { assert(false); }
+ do { return 10; }
+}
+
+void test6549()
+{
+ auto c = new CD6549;
+ c.foo(10);
+ assert(C6549.icount == 1);
+ assert(C6549.ocount == 1);
+
+ auto d = new DD6549;
+ d.foo(10);
+ assert(D6549.icount == 1);
+ assert(D6549.ocount == 1);
+}
+
/*******************************************/
// 7218
@@ -1030,6 +1080,81 @@ void test14779()
/*******************************************/
+//******************************************/
+// DIP 1009
+
+int dip1009_1(int x)
+ in (x > 0, "x must be positive!")
+ out (r; r < 0, "r must be negative!")
+ in (true, "cover trailing comma case",)
+ out (; true, "cover trailing comma case",)
+{
+ return -x;
+}
+
+int dip1009_2(int x)
+ in (x > 0)
+ out (r; r < 0)
+{
+ return -x;
+}
+
+int dip1009_3(int x)
+in (x > 0,)
+out (r; r < 0,)
+do
+{
+ return -x;
+}
+
+void dip1009_4(int x)
+ in (x > 0)
+ out (; x > 1)
+{
+ x += 1;
+}
+
+interface DIP1009_5
+{
+ void dip1009_5(int x)
+ in (x > 0)
+ out (; x > 1);
+}
+
+int dip1009_6(int x, int y)
+ in (x > 0)
+ out (r; r > 1)
+ out (; x > 0)
+ in (y > 0)
+ in (x + y > 1)
+ out (r; r > 1)
+{
+ return x+y;
+}
+
+int dip1009_7(int x)
+ in (x > 0)
+ in { assert(x > 1); }
+ out { assert(x > 2); }
+ out (; x > 3)
+ out (r; r > 3)
+{
+ x += 2;
+ return x;
+}
+
+class DIP1009_8
+{
+ private int x = 4;
+ invariant (x > 0, "x must stay positive");
+ invariant (x > 1, "x must be greater than one",);
+ invariant (x > 2);
+ invariant (x > 3,);
+ void foo(){ x = 5; }
+}
+
+/*******************************************/
+
int main()
{
test1();
@@ -1043,6 +1168,7 @@ int main()
test9();
test4785();
test6417();
+ test6549();
test7218();
test7517();
test8073();
@@ -1051,6 +1177,13 @@ int main()
test15524();
test15524a();
test14779();
+ dip1009_1(1);
+ dip1009_2(1);
+ dip1009_3(1);
+ dip1009_4(1);
+ dip1009_6(1, 1);
+ dip1009_7(3);
+ new DIP1009_8().foo();
printf("Success\n");
return 0;