fix Issue 23598 - Circular reference bug with static if and eponymous templates (#14838)

This commit is contained in:
Walter Bright 2023-01-26 01:28:50 -08:00 committed by GitHub
parent fbf8061eec
commit 4791e9e7fa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 154 additions and 12 deletions

View file

@ -207,7 +207,7 @@ extern (C++) abstract class AttribDeclaration : Dsymbol
objc.addSymbols(this, classes, categories);
}
override final inout(AttribDeclaration) isAttribDeclaration() inout pure @safe
override inout(AttribDeclaration) isAttribDeclaration() inout pure @safe
{
return this;
}
@ -1080,6 +1080,11 @@ extern (C++) final class StaticIfDeclaration : ConditionalDeclaration
return "static if";
}
override inout(StaticIfDeclaration) isStaticIfDeclaration() inout pure @safe
{
return this;
}
override void accept(Visitor v)
{
v.visit(this);

View file

@ -37,7 +37,7 @@ public:
bool hasStaticCtorOrDtor() override final;
void checkCtorConstInit() override final;
void addLocalClass(ClassDeclarations *) override final;
AttribDeclaration *isAttribDeclaration() override final { return this; }
AttribDeclaration *isAttribDeclaration() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
@ -184,6 +184,7 @@ public:
void addMember(Scope *sc, ScopeDsymbol *sds) override;
void setScope(Scope *sc) override;
void importAll(Scope *sc) override;
StaticIfDeclaration *isStaticIfDeclaration() override { return this; }
const char *kind() const override;
void accept(Visitor *v) override { v->visit(this); }
};

View file

@ -1413,6 +1413,7 @@ extern (C++) class Dsymbol : ASTNode
inout(OverloadSet) isOverloadSet() inout { return null; }
inout(CompileDeclaration) isCompileDeclaration() inout { return null; }
inout(StaticAssert) isStaticAssert() inout { return null; }
inout(StaticIfDeclaration) isStaticIfDeclaration() inout { return null; }
}
/***********************************************************

View file

@ -72,6 +72,7 @@ class ExpressionDsymbol;
class AliasAssign;
class OverloadSet;
class StaticAssert;
class StaticIfDeclaration;
struct AA;
#ifdef IN_GCC
typedef union tree_node Symbol;
@ -323,6 +324,7 @@ public:
virtual OverloadSet *isOverloadSet() { return NULL; }
virtual CompileDeclaration *isCompileDeclaration() { return NULL; }
virtual StaticAssert *isStaticAssert() { return NULL; }
virtual StaticIfDeclaration *isStaticIfDeclaration() { return NULL; }
void accept(Visitor *v) override { v->visit(this); }
};

View file

@ -4539,7 +4539,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
override void visit(StructDeclaration sd)
{
//printf("StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", sd, sd.toPrettyChars(), sd.sizeok);
enum log = false;
if (log) printf("+StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", sd, sd.toPrettyChars(), sd.sizeok);
//static int count; if (++count == 20) assert(0);
@ -4609,6 +4610,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
if (!sd.members) // if opaque declaration
{
if (log) printf("\topaque declaration %s\n", sd.toChars());
sd.semanticRun = PASS.semanticdone;
return;
}
@ -4660,7 +4662,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
sc2.pop();
//printf("\tdeferring %s\n", toChars());
if (log) printf("\tdeferring %s\n", sd.toChars());
return deferDsymbolSemantic(sd, scx);
}
@ -4690,7 +4692,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
sd.inv = buildInv(sd, sc2);
sd.semanticRun = PASS.semanticdone;
//printf("-StructDeclaration::semantic(this=%p, '%s')\n", sd, sd.toChars());
if (log) printf("-StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", sd, sd.toPrettyChars(), sd.sizeok);
sc2.pop();
@ -4757,6 +4759,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
// Make an error in 2.110
if (sd.storage_class & STC.scope_)
deprecation(sd.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site.");
//printf("-StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", sd, sd.toPrettyChars(), sd.sizeok);
}
void interfaceSemantic(ClassDeclaration cd)
@ -6147,7 +6150,7 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions*
Dsymbol s;
if (Dsymbol.oneMembers(tempinst.members, &s, tempdecl.ident) && s)
{
//printf("tempdecl.ident = %s, s = '%s'\n", tempdecl.ident.toChars(), s.kind(), s.toPrettyChars());
//printf("tempdecl.ident = %s, s = `%s %s`\n", tempdecl.ident.toChars(), s.kind(), s.toPrettyChars());
//printf("setting aliasdecl\n");
tempinst.aliasdecl = s;
}
@ -6194,7 +6197,7 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions*
{
if (!tempinst.aliasdecl || tempinst.aliasdecl != s)
{
//printf("tempdecl.ident = %s, s = '%s'\n", tempdecl.ident.toChars(), s.kind(), s.toPrettyChars());
//printf("tempdecl.ident = %s, s = `%s %s`\n", tempdecl.ident.toChars(), s.kind(), s.toPrettyChars());
//printf("setting aliasdecl 2\n");
tempinst.aliasdecl = s;
}

View file

@ -45,6 +45,7 @@ import dmd.aliasthis;
import dmd.arraytypes;
import dmd.astenums;
import dmd.ast_node;
import dmd.attrib;
import dmd.dcast;
import dmd.dclass;
import dmd.declaration;
@ -1226,7 +1227,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
paramscope.pop();
static if (LOGM)
{
printf("-TemplateDeclaration.matchWithInstance(this = %p, ti = %p) = %d\n", this, ti, m);
printf("-TemplateDeclaration.matchWithInstance(this = %s, ti = %s) = %d\n", toChars(), ti.toChars(), m);
}
return m;
}
@ -7520,6 +7521,43 @@ extern (C++) class TemplateInstance : ScopeDsymbol
members.foreachDsymbol( (s) { s.importAll(sc2); } );
if (!aliasdecl)
{
/* static if's are crucial to evaluating aliasdecl correctly. But
* evaluating the if/else bodies may require aliasdecl.
* So, evaluate the condition for static if's, but not their if/else bodies.
* Then try to set aliasdecl.
* Later do the if/else bodies.
* https://issues.dlang.org/show_bug.cgi?id=23598
* It might be better to do this by attaching a lambda to the StaticIfDeclaration
* to do the oneMembers call after the sid.include(sc2) is run as part of dsymbolSemantic().
*/
bool done;
void staticIfDg(Dsymbol s)
{
if (done || aliasdecl)
return;
//printf("\t staticIfDg on '%s %s' in '%s'\n", s.kind(), s.toChars(), this.toChars());
if (!s.isStaticIfDeclaration())
{
//s.dsymbolSemantic(sc2);
done = true;
return;
}
auto sid = s.isStaticIfDeclaration();
sid.include(sc2);
if (members.length)
{
Dsymbol sa;
if (Dsymbol.oneMembers(members, &sa, tempdecl.ident) && sa)
aliasdecl = sa;
}
done = true;
}
members.foreachDsymbol(&staticIfDg);
}
void symbolDg(Dsymbol s)
{
//printf("\t semantic on '%s' %p kind %s in '%s'\n", s.toChars(), s, s.kind(), this.toChars());

View file

@ -102,6 +102,7 @@ class VisibilityDeclaration;
class OverloadSet;
class CompileDeclaration;
class StaticAssert;
class StaticIfDeclaration;
class DsymbolTable;
struct MangleOverride;
class AliasThis;
@ -571,6 +572,7 @@ public:
virtual OverloadSet* isOverloadSet();
virtual CompileDeclaration* isCompileDeclaration();
virtual StaticAssert* isStaticAssert();
virtual StaticIfDeclaration* isStaticIfDeclaration();
};
typedef uint64_t size_t;
@ -5387,7 +5389,7 @@ public:
void checkCtorConstInit() final override;
void addLocalClass(Array<ClassDeclaration* >* aclasses) final override;
void addObjcSymbols(Array<ClassDeclaration* >* classes, Array<ClassDeclaration* >* categories) final override;
AttribDeclaration* isAttribDeclaration() final override;
AttribDeclaration* isAttribDeclaration() override;
void accept(Visitor* v) override;
};
@ -5524,6 +5526,7 @@ public:
void setScope(Scope* sc) override;
void importAll(Scope* sc) override;
const char* kind() const override;
StaticIfDeclaration* isStaticIfDeclaration() override;
void accept(Visitor* v) override;
};

View file

@ -0,0 +1,87 @@
// https://issues.dlang.org/show_bug.cgi?id=23598
alias AliasSeq(a...) = a;
static if (1)
{
template sort(alias f, a...)
{
static if (a.length > 0)
{
alias x = f!(a[0]);
alias sort = a;
}
else
alias sort = a;
}
alias SortedItems = sort!(isDependencyOf, String);
enum isDependencyOf(Item) = Item.DirectDependencies.length == 0;
struct String
{
alias DirectDependencies = AliasSeq!();
enum l = SortedItems.length; // (3)
}
}
/*****************************************************/
static if (1)
{
enum x = 1;
enum y = 2;
template f(T)
{
alias b = int;
static if (x)
{
alias c = x;
}
else
{
alias c = y;
}
static if (is(typeof(c)))
{
}
else
{
static assert(0);
}
}
void g()
{
int x = f!int.c;
}
}
/*****************************************************/
template forward(args...)
{
template fwd(alias arg)
{
alias fwd = arg;
}
alias Result = AliasSeq!();
static foreach (arg; args)
Result = AliasSeq!(Result, fwd!arg);
static if (Result.length == 1)
alias forward = Result[0];
else
alias forward = Result;
}
void func(int i, int j)
{
func(forward!(i, j));
}

View file

@ -1,13 +1,13 @@
/*
TEST_OUTPUT:
----
fail_compilation/ice12727.d(16): Error: template instance `IndexTuple!(1, 0)` recursive template expansion
fail_compilation/ice12727.d(16): Error: alias `ice12727.IndexTuple!(1, 0).IndexTuple` recursive alias declaration
fail_compilation/ice12727.d(23): Error: template instance `ice12727.IndexTuple!(1, 0)` error instantiating
fail_compilation/ice12727.d(27): instantiated from here: `Matrix!(float, 3)`
fail_compilation/ice12727.d(28): instantiated from here: `Vector!(float, 3)`
----
*/
template IndexTuple(int e, int s = 0, T...)
{
static if (s == e)

View file

@ -1,11 +1,13 @@
/*
TEST_OUTPUT:
---
fail_compilation/ice13816.d(15): Error: alias `ice13816.ItemProperty!().ItemProperty` recursive alias declaration
fail_compilation/ice13816.d(20): Error: template instance `ice13816.ItemProperty!()` error instantiating
fail_compilation/ice13816.d(17): Error: template instance `TypeTuple!(ItemProperty!())` recursive template expansion
fail_compilation/ice13816.d(17): Error: alias `ice13816.ItemProperty!().ItemProperty` recursive alias declaration
fail_compilation/ice13816.d(22): Error: template instance `ice13816.ItemProperty!()` error instantiating
---
*/
alias TypeTuple(T...) = T;
template ItemProperty()