Skip to content

Commit f27aaa5

Browse files
committed
[c] Destroy temporaries from "return".
fusionlanguage#26
1 parent d6fe4e2 commit f27aaa5

File tree

6 files changed

+108
-219
lines changed

6 files changed

+108
-219
lines changed

GenC.fu

Lines changed: 23 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,33 +1080,7 @@ public class GenC : GenCCpp
10801080
WriteOwningTemporary(arg);
10811081
}
10821082

1083-
static bool HasTemporariesToDestruct(FuExpr expr) => ContainsTemporariesToDestruct(expr) || expr.IsNewString(false);
1084-
1085-
static bool ContainsTemporariesToDestruct(FuExpr expr)
1086-
{
1087-
switch (expr) {
1088-
case FuAggregateInitializer init:
1089-
return init.Items.Any(field => HasTemporariesToDestruct(field));
1090-
case FuLiteral:
1091-
case FuLambdaExpr:
1092-
return false;
1093-
case FuInterpolatedString interp:
1094-
return interp.Parts.Any(part => HasTemporariesToDestruct(part.Argument));
1095-
case FuSymbolReference symbol:
1096-
return symbol.Left != null && HasTemporariesToDestruct(symbol.Left);
1097-
case FuUnaryExpr unary:
1098-
return unary.Inner != null && ContainsTemporariesToDestruct(unary.Inner);
1099-
case FuBinaryExpr binary:
1100-
return HasTemporariesToDestruct(binary.Left) || (binary.Op != FuToken.Is && HasTemporariesToDestruct(binary.Right));
1101-
case FuSelectExpr select:
1102-
return ContainsTemporariesToDestruct(select.Cond);
1103-
case FuCallExpr call:
1104-
return (call.Method.Left != null && HasTemporariesToDestruct(call.Method.Left))
1105-
|| call.Arguments.Any(arg => HasTemporariesToDestruct(arg));
1106-
default:
1107-
assert false;
1108-
}
1109-
}
1083+
bool HasTemporariesToDestruct() => this.CurrentTemporaries.Any(temp => !(temp is FuType));
11101084

11111085
protected override void CleanupTemporary!(int i, FuExpr temp)
11121086
{
@@ -2827,7 +2801,7 @@ public class GenC : GenCCpp
28272801

28282802
protected override void StartIf!(FuExpr expr)
28292803
{
2830-
if (this.CurrentTemporaries.Any(temp => !(temp is FuType))) {
2804+
if (HasTemporariesToDestruct()) {
28312805
if (!this.ConditionVarInScope) {
28322806
this.ConditionVarInScope = true;
28332807
Write("bool ");
@@ -2856,44 +2830,43 @@ public class GenC : GenCCpp
28562830

28572831
internal override void VisitReturn!(FuReturn statement)
28582832
{
2859-
if (statement.Value == null) {
2833+
if (statement.Value == null || statement.Value is FuLiteral) {
28602834
WriteDestructAll();
2861-
if (this.CurrentMethod.Throws.Count > 0)
2835+
if (statement.Value == null && this.CurrentMethod.Throws.Count > 0)
28622836
WriteLine("return true;");
28632837
else
28642838
base.VisitReturn(statement);
28652839
}
2840+
else if (statement.Value is FuSymbolReference symbol && symbol.Symbol is FuVar local) {
2841+
if (this.VarsToDestruct.Contains(local)) {
2842+
// Optimization: avoid copy
2843+
WriteDestructAll(local);
2844+
Write("return ");
2845+
if (this.CurrentMethod.Type is FuClassType resultPtr && !(resultPtr is FuStorageType))
2846+
WriteClassPtr(resultPtr.Class, symbol, FuPriority.Argument); // upcast, but don't AddRef
2847+
else
2848+
symbol.Accept(this, FuPriority.Argument);
2849+
WriteCharLine(';');
2850+
}
2851+
else {
2852+
// Local variable value doesn't depend on destructed variables
2853+
WriteDestructAll();
2854+
base.VisitReturn(statement);
2855+
}
2856+
}
28662857
else {
2858+
WriteTemporaries(statement.Value);
28672859
FuMethod? throwingMethod = this.CurrentMethod.Type is FuNumericType ? GetThrowingMethod(statement.Value) : null;
28682860
if (throwingMethod != null
28692861
&& (this.CurrentMethod.Type is FuRangeType methodRange
28702862
? throwingMethod.Type is FuRangeType throwingRange && methodRange.Min == throwingRange.Min // (int) ThrowingSameValue()
28712863
: throwingMethod.Type is FuFloatingType)) // (float) ThrowingNaN()
28722864
throwingMethod = null;
2873-
if (statement.Value is FuLiteral
2874-
|| (throwingMethod == null && this.VarsToDestruct.Count == 0 && !ContainsTemporariesToDestruct(statement.Value))) {
2865+
if (throwingMethod == null && this.VarsToDestruct.Count == 0 && !HasTemporariesToDestruct()) {
28752866
WriteDestructAll();
28762867
base.VisitReturn(statement);
28772868
}
2878-
else if (statement.Value is FuSymbolReference symbol && symbol.Symbol is FuVar local) {
2879-
if (this.VarsToDestruct.Contains(local)) {
2880-
// Optimization: avoid copy
2881-
WriteDestructAll(local);
2882-
Write("return ");
2883-
if (this.CurrentMethod.Type is FuClassType resultPtr && !(resultPtr is FuStorageType))
2884-
WriteClassPtr(resultPtr.Class, symbol, FuPriority.Argument); // upcast, but don't AddRef
2885-
else
2886-
symbol.Accept(this, FuPriority.Argument);
2887-
WriteCharLine(';');
2888-
}
2889-
else {
2890-
// Local variable value doesn't depend on destructed variables
2891-
WriteDestructAll();
2892-
base.VisitReturn(statement);
2893-
}
2894-
}
28952869
else {
2896-
WriteTemporaries(statement.Value);
28972870
EnsureChildBlock();
28982871
StartDefinition(this.CurrentMethod.Type, true, true);
28992872
Write("returnValue = ");

libfut.cpp

Lines changed: 31 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -10019,31 +10019,9 @@ void GenC::writeArgTemporary(const FuMethod * method, const FuVar * param, const
1001910019
writeOwningTemporary(arg);
1002010020
}
1002110021

10022-
bool GenC::hasTemporariesToDestruct(const FuExpr * expr)
10022+
bool GenC::hasTemporariesToDestruct() const
1002310023
{
10024-
return containsTemporariesToDestruct(expr) || expr->isNewString(false);
10025-
}
10026-
10027-
bool GenC::containsTemporariesToDestruct(const FuExpr * expr)
10028-
{
10029-
if (const FuAggregateInitializer *init = dynamic_cast<const FuAggregateInitializer *>(expr))
10030-
return std::any_of(init->items.begin(), init->items.end(), [](const std::shared_ptr<FuExpr> &field) { return hasTemporariesToDestruct(field.get()); });
10031-
else if (dynamic_cast<const FuLiteral *>(expr) || dynamic_cast<const FuLambdaExpr *>(expr))
10032-
return false;
10033-
else if (const FuInterpolatedString *interp = dynamic_cast<const FuInterpolatedString *>(expr))
10034-
return std::any_of(interp->parts.begin(), interp->parts.end(), [](const FuInterpolatedPart &part) { return hasTemporariesToDestruct(part.argument.get()); });
10035-
else if (const FuSymbolReference *symbol = dynamic_cast<const FuSymbolReference *>(expr))
10036-
return symbol->left != nullptr && hasTemporariesToDestruct(symbol->left.get());
10037-
else if (const FuUnaryExpr *unary = dynamic_cast<const FuUnaryExpr *>(expr))
10038-
return unary->inner != nullptr && containsTemporariesToDestruct(unary->inner.get());
10039-
else if (const FuBinaryExpr *binary = dynamic_cast<const FuBinaryExpr *>(expr))
10040-
return hasTemporariesToDestruct(binary->left.get()) || (binary->op != FuToken::is && hasTemporariesToDestruct(binary->right.get()));
10041-
else if (const FuSelectExpr *select = dynamic_cast<const FuSelectExpr *>(expr))
10042-
return containsTemporariesToDestruct(select->cond.get());
10043-
else if (const FuCallExpr *call = dynamic_cast<const FuCallExpr *>(expr))
10044-
return (call->method->left != nullptr && hasTemporariesToDestruct(call->method->left.get())) || std::any_of(call->arguments.begin(), call->arguments.end(), [](const std::shared_ptr<FuExpr> &arg) { return hasTemporariesToDestruct(arg.get()); });
10045-
else
10046-
std::abort();
10024+
return std::any_of(this->currentTemporaries.begin(), this->currentTemporaries.end(), [](const FuExpr * temp) { return !dynamic_cast<const FuType *>(temp); });
1004710025
}
1004810026

1004910027
void GenC::cleanupTemporary(int i, const FuExpr * temp)
@@ -11779,7 +11757,7 @@ void GenC::visitForeach(const FuForeach * statement)
1177911757

1178011758
void GenC::startIf(const FuExpr * expr)
1178111759
{
11782-
if (std::any_of(this->currentTemporaries.begin(), this->currentTemporaries.end(), [](const FuExpr * temp) { return !dynamic_cast<const FuType *>(temp); })) {
11760+
if (hasTemporariesToDestruct()) {
1178311761
if (!this->conditionVarInScope) {
1178411762
this->conditionVarInScope = true;
1178511763
write("bool ");
@@ -11807,44 +11785,44 @@ void GenC::visitLock(const FuLock * statement)
1180711785

1180811786
void GenC::visitReturn(const FuReturn * statement)
1180911787
{
11810-
if (statement->value == nullptr) {
11788+
if (statement->value == nullptr || dynamic_cast<const FuLiteral *>(statement->value.get())) {
1181111789
writeDestructAll();
11812-
if (std::ssize(this->currentMethod->throws) > 0)
11790+
if (statement->value == nullptr && std::ssize(this->currentMethod->throws) > 0)
1181311791
writeLine("return true;");
1181411792
else
1181511793
GenCCpp::visitReturn(statement);
1181611794
}
1181711795
else {
11818-
const FuMethod * throwingMethod = dynamic_cast<const FuNumericType *>(this->currentMethod->type.get()) ? getThrowingMethod(statement->value.get()) : nullptr;
11819-
const FuRangeType * methodRange;
11820-
const FuRangeType * throwingRange;
11821-
if (throwingMethod != nullptr && ((methodRange = dynamic_cast<const FuRangeType *>(this->currentMethod->type.get())) ? (throwingRange = dynamic_cast<const FuRangeType *>(throwingMethod->type.get())) && methodRange->min == throwingRange->min : !!dynamic_cast<const FuFloatingType *>(throwingMethod->type.get())))
11822-
throwingMethod = nullptr;
11823-
if (dynamic_cast<const FuLiteral *>(statement->value.get()) || (throwingMethod == nullptr && std::ssize(this->varsToDestruct) == 0 && !containsTemporariesToDestruct(statement->value.get()))) {
11824-
writeDestructAll();
11825-
GenCCpp::visitReturn(statement);
11796+
const FuSymbolReference * symbol;
11797+
const FuVar * local;
11798+
if ((symbol = dynamic_cast<const FuSymbolReference *>(statement->value.get())) && (local = dynamic_cast<const FuVar *>(symbol->symbol))) {
11799+
if (std::find(this->varsToDestruct.begin(), this->varsToDestruct.end(), local) != this->varsToDestruct.end()) {
11800+
writeDestructAll(local);
11801+
write("return ");
11802+
const FuClassType * resultPtr;
11803+
if ((resultPtr = dynamic_cast<const FuClassType *>(this->currentMethod->type.get())) && !dynamic_cast<const FuStorageType *>(resultPtr))
11804+
writeClassPtr(resultPtr->class_, symbol, FuPriority::argument);
11805+
else
11806+
symbol->accept(this, FuPriority::argument);
11807+
writeCharLine(';');
11808+
}
11809+
else {
11810+
writeDestructAll();
11811+
GenCCpp::visitReturn(statement);
11812+
}
1182611813
}
1182711814
else {
11828-
const FuSymbolReference * symbol;
11829-
const FuVar * local;
11830-
if ((symbol = dynamic_cast<const FuSymbolReference *>(statement->value.get())) && (local = dynamic_cast<const FuVar *>(symbol->symbol))) {
11831-
if (std::find(this->varsToDestruct.begin(), this->varsToDestruct.end(), local) != this->varsToDestruct.end()) {
11832-
writeDestructAll(local);
11833-
write("return ");
11834-
const FuClassType * resultPtr;
11835-
if ((resultPtr = dynamic_cast<const FuClassType *>(this->currentMethod->type.get())) && !dynamic_cast<const FuStorageType *>(resultPtr))
11836-
writeClassPtr(resultPtr->class_, symbol, FuPriority::argument);
11837-
else
11838-
symbol->accept(this, FuPriority::argument);
11839-
writeCharLine(';');
11840-
}
11841-
else {
11842-
writeDestructAll();
11843-
GenCCpp::visitReturn(statement);
11844-
}
11815+
writeTemporaries(statement->value.get());
11816+
const FuMethod * throwingMethod = dynamic_cast<const FuNumericType *>(this->currentMethod->type.get()) ? getThrowingMethod(statement->value.get()) : nullptr;
11817+
const FuRangeType * methodRange;
11818+
const FuRangeType * throwingRange;
11819+
if (throwingMethod != nullptr && ((methodRange = dynamic_cast<const FuRangeType *>(this->currentMethod->type.get())) ? (throwingRange = dynamic_cast<const FuRangeType *>(throwingMethod->type.get())) && methodRange->min == throwingRange->min : !!dynamic_cast<const FuFloatingType *>(throwingMethod->type.get())))
11820+
throwingMethod = nullptr;
11821+
if (throwingMethod == nullptr && std::ssize(this->varsToDestruct) == 0 && !hasTemporariesToDestruct()) {
11822+
writeDestructAll();
11823+
GenCCpp::visitReturn(statement);
1184511824
}
1184611825
else {
11847-
writeTemporaries(statement->value.get());
1184811826
ensureChildBlock();
1184911827
startDefinition(this->currentMethod->type.get(), true, true);
1185011828
write("returnValue = ");

libfut.cs

Lines changed: 21 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -10320,32 +10320,7 @@ protected override void WriteArgTemporary(FuMethod method, FuVar param, FuExpr a
1032010320
WriteOwningTemporary(arg);
1032110321
}
1032210322

10323-
static bool HasTemporariesToDestruct(FuExpr expr) => ContainsTemporariesToDestruct(expr) || expr.IsNewString(false);
10324-
10325-
static bool ContainsTemporariesToDestruct(FuExpr expr)
10326-
{
10327-
switch (expr) {
10328-
case FuAggregateInitializer init:
10329-
return init.Items.Exists(field => HasTemporariesToDestruct(field));
10330-
case FuLiteral:
10331-
case FuLambdaExpr:
10332-
return false;
10333-
case FuInterpolatedString interp:
10334-
return interp.Parts.Exists(part => HasTemporariesToDestruct(part.Argument));
10335-
case FuSymbolReference symbol:
10336-
return symbol.Left != null && HasTemporariesToDestruct(symbol.Left);
10337-
case FuUnaryExpr unary:
10338-
return unary.Inner != null && ContainsTemporariesToDestruct(unary.Inner);
10339-
case FuBinaryExpr binary:
10340-
return HasTemporariesToDestruct(binary.Left) || (binary.Op != FuToken.Is && HasTemporariesToDestruct(binary.Right));
10341-
case FuSelectExpr select:
10342-
return ContainsTemporariesToDestruct(select.Cond);
10343-
case FuCallExpr call:
10344-
return (call.Method.Left != null && HasTemporariesToDestruct(call.Method.Left)) || call.Arguments.Exists(arg => HasTemporariesToDestruct(arg));
10345-
default:
10346-
throw new NotImplementedException();
10347-
}
10348-
}
10323+
bool HasTemporariesToDestruct() => this.CurrentTemporaries.Exists(temp => !(temp is FuType));
1034910324

1035010325
protected override void CleanupTemporary(int i, FuExpr temp)
1035110326
{
@@ -12047,7 +12022,7 @@ internal override void VisitForeach(FuForeach statement)
1204712022

1204812023
protected override void StartIf(FuExpr expr)
1204912024
{
12050-
if (this.CurrentTemporaries.Exists(temp => !(temp is FuType))) {
12025+
if (HasTemporariesToDestruct()) {
1205112026
if (!this.ConditionVarInScope) {
1205212027
this.ConditionVarInScope = true;
1205312028
Write("bool ");
@@ -12075,38 +12050,38 @@ internal override void VisitLock(FuLock statement)
1207512050

1207612051
internal override void VisitReturn(FuReturn statement)
1207712052
{
12078-
if (statement.Value == null) {
12053+
if (statement.Value == null || statement.Value is FuLiteral) {
1207912054
WriteDestructAll();
12080-
if (this.CurrentMethod.Throws.Count > 0)
12055+
if (statement.Value == null && this.CurrentMethod.Throws.Count > 0)
1208112056
WriteLine("return true;");
1208212057
else
1208312058
base.VisitReturn(statement);
1208412059
}
12060+
else if (statement.Value is FuSymbolReference symbol && symbol.Symbol is FuVar local) {
12061+
if (this.VarsToDestruct.Contains(local)) {
12062+
WriteDestructAll(local);
12063+
Write("return ");
12064+
if (this.CurrentMethod.Type is FuClassType resultPtr && !(resultPtr is FuStorageType))
12065+
WriteClassPtr(resultPtr.Class, symbol, FuPriority.Argument);
12066+
else
12067+
symbol.Accept(this, FuPriority.Argument);
12068+
WriteCharLine(';');
12069+
}
12070+
else {
12071+
WriteDestructAll();
12072+
base.VisitReturn(statement);
12073+
}
12074+
}
1208512075
else {
12076+
WriteTemporaries(statement.Value);
1208612077
FuMethod throwingMethod = this.CurrentMethod.Type is FuNumericType ? GetThrowingMethod(statement.Value) : null;
1208712078
if (throwingMethod != null && (this.CurrentMethod.Type is FuRangeType methodRange ? throwingMethod.Type is FuRangeType throwingRange && methodRange.Min == throwingRange.Min : throwingMethod.Type is FuFloatingType))
1208812079
throwingMethod = null;
12089-
if (statement.Value is FuLiteral || (throwingMethod == null && this.VarsToDestruct.Count == 0 && !ContainsTemporariesToDestruct(statement.Value))) {
12080+
if (throwingMethod == null && this.VarsToDestruct.Count == 0 && !HasTemporariesToDestruct()) {
1209012081
WriteDestructAll();
1209112082
base.VisitReturn(statement);
1209212083
}
12093-
else if (statement.Value is FuSymbolReference symbol && symbol.Symbol is FuVar local) {
12094-
if (this.VarsToDestruct.Contains(local)) {
12095-
WriteDestructAll(local);
12096-
Write("return ");
12097-
if (this.CurrentMethod.Type is FuClassType resultPtr && !(resultPtr is FuStorageType))
12098-
WriteClassPtr(resultPtr.Class, symbol, FuPriority.Argument);
12099-
else
12100-
symbol.Accept(this, FuPriority.Argument);
12101-
WriteCharLine(';');
12102-
}
12103-
else {
12104-
WriteDestructAll();
12105-
base.VisitReturn(statement);
12106-
}
12107-
}
1210812084
else {
12109-
WriteTemporaries(statement.Value);
1211012085
EnsureChildBlock();
1211112086
StartDefinition(this.CurrentMethod.Type, true, true);
1211212087
Write("returnValue = ");

libfut.hpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2179,8 +2179,7 @@ class GenC : public GenCCpp
21792179
void writeAssignTemporary(const FuType * type, const FuExpr * expr);
21802180
int writeCTemporary(const FuType * type, const FuExpr * expr);
21812181
static bool needsOwningTemporary(const FuExpr * expr);
2182-
static bool hasTemporariesToDestruct(const FuExpr * expr);
2183-
static bool containsTemporariesToDestruct(const FuExpr * expr);
2182+
bool hasTemporariesToDestruct() const;
21842183
void writeGPointerCast(const FuType * type, const FuExpr * expr);
21852184
void writeAddressOf(const FuExpr * expr);
21862185
void writeGConstPointerCast(const FuExpr * expr);

0 commit comments

Comments
 (0)