mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-12 13:55:57 +03:00

Notably, the glue layer side of the changed multiple interface inheritance layout (DMD a54e89d) has not been implemented yet. This corresponds to DMD commit 3f6a763c0589dd03c1c206eafd434b593702564e.
194 lines
5.1 KiB
D
194 lines
5.1 KiB
D
// Compiler implementation of the D programming language
|
|
// Copyright (c) 1999-2015 by Digital Mars
|
|
// All Rights Reserved
|
|
// written by Walter Bright
|
|
// http://www.digitalmars.com
|
|
// Distributed under the Boost Software License, Version 1.0.
|
|
// http://www.boost.org/LICENSE_1_0.txt
|
|
|
|
module ddmd.delegatize;
|
|
|
|
import ddmd.apply;
|
|
import ddmd.declaration;
|
|
import ddmd.dscope;
|
|
import ddmd.dsymbol;
|
|
import ddmd.expression;
|
|
import ddmd.func;
|
|
import ddmd.globals;
|
|
import ddmd.mtype;
|
|
import ddmd.statement;
|
|
import ddmd.tokens;
|
|
import ddmd.visitor;
|
|
|
|
extern (C++) Expression toDelegate(Expression e, Type t, Scope* sc)
|
|
{
|
|
//printf("Expression::toDelegate(t = %s) %s\n", t->toChars(), e->toChars());
|
|
Loc loc = e.loc;
|
|
auto tf = new TypeFunction(null, t, 0, LINKd);
|
|
if (t.hasWild())
|
|
tf.mod = MODwild;
|
|
auto fld = new FuncLiteralDeclaration(loc, loc, tf, TOKdelegate, null);
|
|
sc = sc.push();
|
|
sc.parent = fld; // set current function to be the delegate
|
|
lambdaSetParent(e, sc);
|
|
bool r = lambdaCheckForNestedRef(e, sc);
|
|
sc = sc.pop();
|
|
if (r)
|
|
return new ErrorExp();
|
|
Statement s;
|
|
if (t.ty == Tvoid)
|
|
s = new ExpStatement(loc, e);
|
|
else
|
|
s = new ReturnStatement(loc, e);
|
|
fld.fbody = s;
|
|
e = new FuncExp(loc, fld);
|
|
e = e.semantic(sc);
|
|
return e;
|
|
}
|
|
|
|
/******************************************
|
|
* Patch the parent of declarations to be the new function literal.
|
|
*/
|
|
extern (C++) void lambdaSetParent(Expression e, Scope* sc)
|
|
{
|
|
extern (C++) final class LambdaSetParent : StoppableVisitor
|
|
{
|
|
alias visit = super.visit;
|
|
Scope* sc;
|
|
|
|
public:
|
|
extern (D) this(Scope* sc)
|
|
{
|
|
this.sc = sc;
|
|
}
|
|
|
|
override void visit(Expression)
|
|
{
|
|
}
|
|
|
|
override void visit(DeclarationExp e)
|
|
{
|
|
e.declaration.parent = sc.parent;
|
|
}
|
|
|
|
override void visit(IndexExp e)
|
|
{
|
|
if (e.lengthVar)
|
|
{
|
|
//printf("lengthVar\n");
|
|
e.lengthVar.parent = sc.parent;
|
|
}
|
|
}
|
|
|
|
override void visit(SliceExp e)
|
|
{
|
|
if (e.lengthVar)
|
|
{
|
|
//printf("lengthVar\n");
|
|
e.lengthVar.parent = sc.parent;
|
|
}
|
|
}
|
|
}
|
|
|
|
scope LambdaSetParent lsp = new LambdaSetParent(sc);
|
|
walkPostorder(e, lsp);
|
|
}
|
|
|
|
/*******************************************
|
|
* Look for references to variables in a scope enclosing the new function literal.
|
|
* Returns true if error occurs.
|
|
*/
|
|
extern (C++) bool lambdaCheckForNestedRef(Expression e, Scope* sc)
|
|
{
|
|
extern (C++) final class LambdaCheckForNestedRef : StoppableVisitor
|
|
{
|
|
alias visit = super.visit;
|
|
public:
|
|
Scope* sc;
|
|
bool result;
|
|
|
|
extern (D) this(Scope* sc)
|
|
{
|
|
this.sc = sc;
|
|
}
|
|
|
|
override void visit(Expression)
|
|
{
|
|
}
|
|
|
|
override void visit(SymOffExp e)
|
|
{
|
|
VarDeclaration v = e.var.isVarDeclaration();
|
|
if (v)
|
|
result = v.checkNestedReference(sc, Loc());
|
|
}
|
|
|
|
override void visit(VarExp e)
|
|
{
|
|
VarDeclaration v = e.var.isVarDeclaration();
|
|
if (v)
|
|
result = v.checkNestedReference(sc, Loc());
|
|
}
|
|
|
|
override void visit(ThisExp e)
|
|
{
|
|
if (e.var)
|
|
result = e.var.checkNestedReference(sc, Loc());
|
|
}
|
|
|
|
override void visit(DeclarationExp e)
|
|
{
|
|
VarDeclaration v = e.declaration.isVarDeclaration();
|
|
if (v)
|
|
{
|
|
result = v.checkNestedReference(sc, Loc());
|
|
if (result)
|
|
return;
|
|
/* Some expressions cause the frontend to create a temporary.
|
|
* For example, structs with cpctors replace the original
|
|
* expression e with:
|
|
* __cpcttmp = __cpcttmp.cpctor(e);
|
|
*
|
|
* In this instance, we need to ensure that the original
|
|
* expression e does not have any nested references by
|
|
* checking the declaration initializer too.
|
|
*/
|
|
if (v._init && v._init.isExpInitializer())
|
|
{
|
|
Expression ie = v._init.toExpression();
|
|
result = lambdaCheckForNestedRef(ie, sc);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
scope LambdaCheckForNestedRef v = new LambdaCheckForNestedRef(sc);
|
|
walkPostorder(e, v);
|
|
return v.result;
|
|
}
|
|
|
|
bool checkNestedRef(Dsymbol s, Dsymbol p)
|
|
{
|
|
while (s)
|
|
{
|
|
if (s == p) // hit!
|
|
return false;
|
|
|
|
if (auto fd = s.isFuncDeclaration())
|
|
{
|
|
if (!fd.isThis() && !fd.isNested())
|
|
break;
|
|
|
|
// Bugzilla 15332: change to delegate if fd is actually nested.
|
|
if (auto fld = fd.isFuncLiteralDeclaration())
|
|
fld.tok = TOKdelegate;
|
|
}
|
|
if (auto ad = s.isAggregateDeclaration())
|
|
{
|
|
if (ad.storage_class & STCstatic)
|
|
break;
|
|
}
|
|
s = s.toParent2();
|
|
}
|
|
return true;
|
|
}
|