From 3f52528e2dd40f116202dac1a8e4d34326c5bc3b Mon Sep 17 00:00:00 2001 From: RazvanN7 Date: Tue, 19 Mar 2019 15:07:00 +0200 Subject: [PATCH] Fix Issue 19731 - auto struct methods whose address is taken don't test invariants --- src/dmd/dsymbolsem.d | 40 +++++++++++++++++++++++++++++ test/runnable/test19731.d | 53 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 test/runnable/test19731.d diff --git a/src/dmd/dsymbolsem.d b/src/dmd/dsymbolsem.d index 78638ada3a4d..09ecf3bce059 100644 --- a/src/dmd/dsymbolsem.d +++ b/src/dmd/dsymbolsem.d @@ -4209,6 +4209,42 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor funcDeclarationSemantic(deld); } + /* https://issues.dlang.org/show_bug.cgi?id=19731 + * + * Some aggregate member functions might have had + * semantic 3 ran on them despite being in semantic1 + * (e.g. auto functions); if that is the case, then + * invariants will not be taken into account for them + * because at the time of the analysis it would appear + * as if the struct declaration does not have any + * invariants. To solve this issue, we need to redo + * semantic3 on the function declaration. + */ + private void reinforceInvariant(AggregateDeclaration ad, Scope* sc) + { + // for each member + for(int i = 0; i < ad.members.dim; i++) + { + if (!(*ad.members)[i]) + continue; + auto fd = (*ad.members)[i].isFuncDeclaration(); + if (!fd || fd.generated || fd.semanticRun != PASS.semantic3done) + continue; + + /* if it's a user defined function declaration and semantic3 + * was already performed on it, create a syntax copy and + * redo the first semantic step. + */ + auto err = global.startGagging(); + auto fd_temp = fd.syntaxCopy(null); + if (auto cd = ad.isClassDeclaration()) + cd.vtbl.remove(fd.vtblIndex); + fd_temp.dsymbolSemantic(sc); + global.endGagging(err); + (*ad.members)[i] = fd_temp; + } + } + override void visit(StructDeclaration sd) { //printf("StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", sd, sd.toPrettyChars(), sd.sizeok); @@ -4356,6 +4392,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } sd.inv = buildInv(sd, sc2); + if (sd.inv) + reinforceInvariant(sd, sc2); Module.dprogress++; sd.semanticRun = PASS.semanticdone; @@ -4980,6 +5018,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } cldec.inv = buildInv(cldec, sc2); + if (cldec.inv) + reinforceInvariant(cldec, sc2); Module.dprogress++; cldec.semanticRun = PASS.semanticdone; diff --git a/test/runnable/test19731.d b/test/runnable/test19731.d new file mode 100644 index 000000000000..55feb74b6337 --- /dev/null +++ b/test/runnable/test19731.d @@ -0,0 +1,53 @@ +// PERMUTE_ARGS: +struct Foo +{ + Object obj_; + + invariant (obj_ !is null); + + auto obj7() + { + return this.obj_; + } + + enum compiles = __traits(compiles, &Foo.init.obj7); +} + +class Foo2 +{ + Object obj_; + + invariant (obj_ !is null); + + final auto obj7() + { + return this.obj_; + } + + enum compiles = __traits(compiles, &Foo.init.obj7); +} + +void main() +{ + import core.exception : AssertError; + Foo foo = Foo(); + Foo2 foo2 = new Foo2(); + + try + { + foo.obj7.toString(); + } + catch(AssertError) + { + try + { + foo2.obj7.toString(); + } + catch(AssertError) + { + return; + } + assert(0); + } + assert(0); +}