From fb14d425fa4ef60f7be9be7be305b72590f631c7 Mon Sep 17 00:00:00 2001 From: Etienne Cimon Date: Wed, 7 Dec 2022 02:30:19 -0500 Subject: [PATCH] Fix 18472: betterC cannot use format at compile time. --- compiler/src/dmd/backend/util2.d | 2 +- compiler/src/dmd/dinterpret.d | 9 +++++++ compiler/src/dmd/s2ir.d | 2 +- compiler/src/dmd/statementsem.d | 7 ++++-- compiler/src/dmd/toobj.d | 3 ++- compiler/src/dmd/typinf.d | 3 ++- druntime/test/betterc/Makefile | 2 +- druntime/test/betterc/src/test18472.d | 36 +++++++++++++++++++++++++++ 8 files changed, 57 insertions(+), 7 deletions(-) create mode 100644 druntime/test/betterc/src/test18472.d diff --git a/compiler/src/dmd/backend/util2.d b/compiler/src/dmd/backend/util2.d index 9079ad46cfc4..4bc1a6e1b737 100644 --- a/compiler/src/dmd/backend/util2.d +++ b/compiler/src/dmd/backend/util2.d @@ -41,7 +41,7 @@ void file_progress() /**************************** * Clean up and exit program. */ - +@trusted void err_exit() { util_exit(EXIT_FAILURE); diff --git a/compiler/src/dmd/dinterpret.d b/compiler/src/dmd/dinterpret.d index e504cb4879fd..de1bc3389ac6 100644 --- a/compiler/src/dmd/dinterpret.d +++ b/compiler/src/dmd/dinterpret.d @@ -97,8 +97,12 @@ public Expression ctfeInterpret(Expression e) auto rgnpos = ctfeGlobals.region.savePos(); + ctfeGlobals.active = true; + Expression result = interpret(e, null); + ctfeGlobals.active = false; + // Report an error if the expression contained a `ThrowException` and // hence generated an uncaught exception if (auto tee = result.isThrownExceptionExp()) @@ -206,6 +210,10 @@ void incArrayAllocs() ++ctfeGlobals.numArrayAllocs; } +bool isInterpreting() { + return ctfeGlobals.active; +} + /* ================================================ Implementation ======================================= */ private: @@ -227,6 +235,7 @@ struct CtfeGlobals int maxCallDepth = 0; // highest number of recursive calls int numArrayAllocs = 0; // Number of allocated arrays int numAssignments = 0; // total number of assignments executed + bool active; // whether we are interpreting a ctfe function } __gshared CtfeGlobals ctfeGlobals; diff --git a/compiler/src/dmd/s2ir.d b/compiler/src/dmd/s2ir.d index 2c2c6d05dc9c..9c67c938a141 100644 --- a/compiler/src/dmd/s2ir.d +++ b/compiler/src/dmd/s2ir.d @@ -191,7 +191,7 @@ private extern (C++) class S2irVisitor : Visitor block_next(blx, BCiftrue, null); bcond.appendSucc(blx.curblock); - if (s.ifbody) + if (s.ifbody && !(s.condition.isVarExp() && s.condition.isVarExp().var.ident == Id.ctfe)) Statement_toIR(s.ifbody, irs, &mystate); blx.curblock.appendSucc(bexit); diff --git a/compiler/src/dmd/statementsem.d b/compiler/src/dmd/statementsem.d index b372fc2f5a96..6edea880d9e6 100644 --- a/compiler/src/dmd/statementsem.d +++ b/compiler/src/dmd/statementsem.d @@ -1888,7 +1888,6 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor { /* https://dlang.org/spec/statement.html#IfStatement */ - // check in syntax level ifs.condition = checkAssignmentAsCondition(ifs.condition, sc); @@ -1953,8 +1952,12 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor // Save 'root' of two branches (then and else) at the point where it forks CtorFlow ctorflow_root = scd.ctorflow.clone(); - + bool needsCtfe = !global.params.useTypeInfo && !isInterpreting() && ifs.condition.isVarExp() && ifs.condition.isVarExp().var.ident == Id.ctfe; + if (needsCtfe) + scd = scd.startCTFE(); ifs.ifbody = ifs.ifbody.semanticNoScope(scd); + if (needsCtfe) + scd = scd.endCTFE(); scd.pop(); CtorFlow ctorflow_then = sc.ctorflow; // move flow results diff --git a/compiler/src/dmd/toobj.d b/compiler/src/dmd/toobj.d index 33968790e447..9ceee43effbe 100644 --- a/compiler/src/dmd/toobj.d +++ b/compiler/src/dmd/toobj.d @@ -715,7 +715,8 @@ void toObjFile(Dsymbol ds, bool multiobj) override void visit(TypeInfoDeclaration tid) { - if (isSpeculativeType(tid.tinfo)) + import dmd.globals : global; + if (isSpeculativeType(tid.tinfo) || global.params.betterC) { //printf("-speculative '%s'\n", tid.toPrettyChars()); return; diff --git a/compiler/src/dmd/typinf.d b/compiler/src/dmd/typinf.d index 047e6cfbcd09..60263557206b 100644 --- a/compiler/src/dmd/typinf.d +++ b/compiler/src/dmd/typinf.d @@ -16,6 +16,7 @@ import dmd.declaration; import dmd.dmodule; import dmd.dscope; import dmd.dclass; +import dmd.dinterpret; import dmd.dstruct; import dmd.errors; import dmd.expression; @@ -41,7 +42,7 @@ extern (C++) void genTypeInfo(Expression e, const ref Loc loc, Type torig, Scope // Even when compiling without `useTypeInfo` (e.g. -betterC) we should // still be able to evaluate `TypeInfo` at compile-time, just not at runtime. // https://issues.dlang.org/show_bug.cgi?id=18472 - if (!sc || !(sc.flags & SCOPE.ctfe)) + if (!sc || (!(sc.flags & SCOPE.ctfe) && !isInterpreting())) { if (!global.params.useTypeInfo) { diff --git a/druntime/test/betterc/Makefile b/druntime/test/betterc/Makefile index 53d90c1fa081..b0b451c983e9 100644 --- a/druntime/test/betterc/Makefile +++ b/druntime/test/betterc/Makefile @@ -1,6 +1,6 @@ include ../common.mak -TESTS:=test18828 test19416 test19421 test19561 test20088 test20613 test19924 test22336 test19933 +TESTS:=test18472 test18828 test19416 test19421 test19561 test20088 test20613 test19924 test22336 test19933 .PHONY: all clean all: $(addprefix $(ROOT)/,$(addsuffix ,$(TESTS))) $(addprefix $(ROOT)/,test19924.done) diff --git a/druntime/test/betterc/src/test18472.d b/druntime/test/betterc/src/test18472.d new file mode 100644 index 000000000000..3e9166baaa0b --- /dev/null +++ b/druntime/test/betterc/src/test18472.d @@ -0,0 +1,36 @@ +/*******************************************/ +// https://issues.dlang.org/show_bug.cgi?id=18472 +@nogc nothrow pure: +immutable(Char)[] format(Char, Args...)(in Char[] fmt, Args args) +{ + if (__ctfe) { + auto data2 = new char[5]; + auto data = new Data2; + data2 = cast(char[]) "test2"; + return data2; + } else { + return "test"; + } +} + +extern(C) void main() +{ + static assert("%s %s".format("test", "test") == "test2", "Not working"); + assert("%s %s".format("test", "test") == "test", "%s %s".format("test", "test")); + assert(getData() == "test2", getData()); +} + +string getData() { + if (__ctfe) { + auto data2 = new ubyte[5]; + auto data = new Data2; + return "test"; + } else { + return "test2"; + } +} + +private struct Data2 +{ + size_t capacity; +}