Skip to content

Commit

Permalink
fix Issue 23598 - Circular reference bug with static if and eponymous…
Browse files Browse the repository at this point in the history
… templates (#14838)
  • Loading branch information
WalterBright committed Jan 26, 2023
1 parent fbf8061 commit 4791e9e
Show file tree
Hide file tree
Showing 10 changed files with 154 additions and 12 deletions.
7 changes: 6 additions & 1 deletion compiler/src/dmd/attrib.d
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion compiler/src/dmd/attrib.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class AttribDeclaration : public Dsymbol
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); }
};
Expand Down Expand Up @@ -184,6 +184,7 @@ class StaticIfDeclaration final : public ConditionalDeclaration
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); }
};
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dmd/dsymbol.d
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
}

/***********************************************************
Expand Down
2 changes: 2 additions & 0 deletions compiler/src/dmd/dsymbol.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class ExpressionDsymbol;
class AliasAssign;
class OverloadSet;
class StaticAssert;
class StaticIfDeclaration;
struct AA;
#ifdef IN_GCC
typedef union tree_node Symbol;
Expand Down Expand Up @@ -323,6 +324,7 @@ class Dsymbol : public ASTNode
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); }
};

Expand Down
13 changes: 8 additions & 5 deletions compiler/src/dmd/dsymbolsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand Down
40 changes: 39 additions & 1 deletion compiler/src/dmd/dtemplate.d
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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());
Expand Down
5 changes: 4 additions & 1 deletion compiler/src/dmd/frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ class VisibilityDeclaration;
class OverloadSet;
class CompileDeclaration;
class StaticAssert;
class StaticIfDeclaration;
class DsymbolTable;
struct MangleOverride;
class AliasThis;
Expand Down Expand Up @@ -571,6 +572,7 @@ class Dsymbol : public ASTNode
virtual OverloadSet* isOverloadSet();
virtual CompileDeclaration* isCompileDeclaration();
virtual StaticAssert* isStaticAssert();
virtual StaticIfDeclaration* isStaticIfDeclaration();
};

typedef uint64_t size_t;
Expand Down Expand Up @@ -5387,7 +5389,7 @@ class AttribDeclaration : public Dsymbol
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;
};

Expand Down Expand Up @@ -5524,6 +5526,7 @@ class StaticIfDeclaration final : public ConditionalDeclaration
void setScope(Scope* sc) override;
void importAll(Scope* sc) override;
const char* kind() const override;
StaticIfDeclaration* isStaticIfDeclaration() override;
void accept(Visitor* v) override;
};

Expand Down
87 changes: 87 additions & 0 deletions compiler/test/compilable/test23598.d
Original file line number Diff line number Diff line change
@@ -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));
}
2 changes: 1 addition & 1 deletion compiler/test/fail_compilation/ice12727.d
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
6 changes: 4 additions & 2 deletions compiler/test/fail_compilation/ice13816.d
Original file line number Diff line number Diff line change
@@ -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()
Expand Down

0 comments on commit 4791e9e

Please sign in to comment.