Moved VarDeclaration.checkNestedReference to funcsem (#21237)

This commit is contained in:
Matthew Qiu 2025-04-15 07:46:48 -04:00 committed by GitHub
parent c296cb1ec2
commit 1fe1cac81b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 79 additions and 78 deletions

View file

@ -27,7 +27,6 @@ import dmd.dtemplate;
import dmd.errors;
import dmd.expression;
import dmd.func;
import dmd.funcsem : getLevelAndCheck;
import dmd.globals;
import dmd.gluelayer;
import dmd.hdrgen;
@ -1084,83 +1083,6 @@ extern (C++) class VarDeclaration : Declaration
return e;
}
/************************************
* Check to see if this variable is actually in an enclosing function
* rather than the current one.
* Update nestedrefs[], closureVars[] and outerVars[].
* Returns: true if error occurs.
*/
extern (D) final bool checkNestedReference(Scope* sc, Loc loc)
{
//printf("VarDeclaration::checkNestedReference() %s\n", toChars());
if (sc.intypeof == 1 || sc.ctfe)
return false;
if (!parent || parent == sc.parent)
return false;
if (isDataseg() || (storage_class & STC.manifest))
return false;
// The current function
FuncDeclaration fdthis = sc.parent.isFuncDeclaration();
if (!fdthis)
return false; // out of function scope
Dsymbol p = toParent2();
// Function literals from fdthis to p must be delegates
ensureStaticLinkTo(fdthis, p);
// The function that this variable is in
FuncDeclaration fdv = p.isFuncDeclaration();
if (!fdv || fdv == fdthis)
return false;
// Add fdthis to nestedrefs[] if not already there
if (!nestedrefs.contains(fdthis))
nestedrefs.push(fdthis);
//printf("\tfdv = %s\n", fdv.toChars());
//printf("\tfdthis = %s\n", fdthis.toChars());
if (loc.isValid())
{
if (fdthis.getLevelAndCheck(loc, sc, fdv, this) == fdthis.LevelError)
return true;
}
// Add this VarDeclaration to fdv.closureVars[] if not already there
if (!sc.intypeof && !sc.traitsCompiles &&
// https://issues.dlang.org/show_bug.cgi?id=17605
(fdv.skipCodegen || !fdthis.skipCodegen))
{
if (!fdv.closureVars.contains(this))
fdv.closureVars.push(this);
}
if (!fdthis.outerVars.contains(this))
fdthis.outerVars.push(this);
//printf("fdthis is %s\n", fdthis.toChars());
//printf("var %s in function %s is nested ref\n", toChars(), fdv.toChars());
// __dollar creates problems because it isn't a real variable
// https://issues.dlang.org/show_bug.cgi?id=3326
if (ident == Id.dollar)
{
.error(loc, "cannnot use `$` inside a function literal");
return true;
}
if (ident == Id.withSym) // https://issues.dlang.org/show_bug.cgi?id=1759
{
ExpInitializer ez = _init.isExpInitializer();
assert(ez);
Expression e = ez.exp;
if (e.op == EXP.construct || e.op == EXP.blit)
e = (cast(AssignExp)e).e2;
return lambdaCheckForNestedRef(e, sc);
}
return false;
}
override final Dsymbol toAlias()
{
//printf("VarDeclaration::toAlias('%s', this = %p, aliassym = %p)\n", toChars(), this, aliassym);

View file

@ -21,6 +21,7 @@ import dmd.dsymbol;
import dmd.expression;
import dmd.expressionsem;
import dmd.func;
import dmd.funcsem : checkNestedReference;
import dmd.init;
import dmd.initsem;
import dmd.location;

View file

@ -3702,3 +3702,80 @@ Dsymbol isUnique(OverDeclaration od)
});
return result;
}
/************************************
* Check to see if this variable is actually in an enclosing function
* rather than the current one.
* Update nestedrefs[], closureVars[] and outerVars[].
* Returns: true if error occurs.
*/
extern (D) bool checkNestedReference(VarDeclaration vd, Scope* sc, Loc loc)
{
//printf("VarDeclaration::checkNestedReference() %s\n", toChars());
if (sc.intypeof == 1 || sc.ctfe)
return false;
if (!vd.parent || vd.parent == sc.parent)
return false;
if (vd.isDataseg() || (vd.storage_class & STC.manifest))
return false;
// The current function
FuncDeclaration fdthis = sc.parent.isFuncDeclaration();
if (!fdthis)
return false; // out of function scope
Dsymbol p = vd.toParent2();
// Function literals from fdthis to p must be delegates
ensureStaticLinkTo(fdthis, p);
// The function that this variable is in
FuncDeclaration fdv = p.isFuncDeclaration();
if (!fdv || fdv == fdthis)
return false;
// Add fdthis to nestedrefs[] if not already there
if (!vd.nestedrefs.contains(fdthis))
vd.nestedrefs.push(fdthis);
//printf("\tfdv = %s\n", fdv.toChars());
//printf("\tfdthis = %s\n", fdthis.toChars());
if (loc.isValid())
{
if (fdthis.getLevelAndCheck(loc, sc, fdv, vd) == fdthis.LevelError)
return true;
}
// Add this VarDeclaration to fdv.closureVars[] if not already there
if (!sc.intypeof && !sc.traitsCompiles &&
// https://issues.dlang.org/show_bug.cgi?id=17605
(fdv.skipCodegen || !fdthis.skipCodegen))
{
if (!fdv.closureVars.contains(vd))
fdv.closureVars.push(vd);
}
if (!fdthis.outerVars.contains(vd))
fdthis.outerVars.push(vd);
//printf("fdthis is %s\n", fdthis.toChars());
//printf("var %s in function %s is nested ref\n", toChars(), fdv.toChars());
// __dollar creates problems because it isn't a real variable
// https://issues.dlang.org/show_bug.cgi?id=3326
if (vd.ident == Id.dollar)
{
.error(loc, "cannnot use `$` inside a function literal");
return true;
}
if (vd.ident == Id.withSym) // https://issues.dlang.org/show_bug.cgi?id=1759
{
ExpInitializer ez = vd._init.isExpInitializer();
assert(ez);
Expression e = ez.exp;
if (e.op == EXP.construct || e.op == EXP.blit)
e = (cast(AssignExp)e).e2;
return lambdaCheckForNestedRef(e, sc);
}
return false;
}

View file

@ -28,6 +28,7 @@ import dmd.dsymbol;
import dmd.errors;
import dmd.expression;
import dmd.expressionsem;
import dmd.funcsem : checkNestedReference;
import dmd.globals;
import dmd.id;
import dmd.identifier;