Skip to content

Commit

Permalink
fix missing destruction when discarding complex expression (#1422)
Browse files Browse the repository at this point in the history
## Summary

Fix the result of `if`, `case`, `block`, and `try` expression not being
destroyed when `discard`ing the expression.

Fixes #1421.

## Details

* in `mirgen`, a value-like PMIR expression is now requested for the
  discarded expression
* `toValue` expects a properly value-like PMIR expression, which a
  complex expression is not, hence the missing destructor
* the expression is now properly materialized, which means that the a
  destructor call is registered for the temporary
  • Loading branch information
zerbina authored Aug 18, 2024
1 parent 43bd0e0 commit 3cab673
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 5 deletions.
9 changes: 4 additions & 5 deletions compiler/mir/mirgen.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2185,15 +2185,14 @@ proc gen(c: var TCtx, n: PNode) =
c.builder.pop(f)
of nkDiscardStmt:
if n[0].kind != nkEmpty:
let e = exprToPmir(c, n[0], false, false)
var e = exprToPmir(c, n[0], false, false)
case classify(e)
of Rvalue:
discard toValue(c, e, e.high, mnkDefCursor)
of OwnedRvalue:
of Rvalue, OwnedRvalue:
# extend the lifetime of the value
# XXX: while not possible at the moment, in the future, the
# discard statement could destroy the temporary right away
discard toValue(c, e, e.high, mnkDef)
wantValue(e) # forces materialization
discard toValue(c, e, e.high)
of Lvalue:
c.buildStmt mnkVoid:
genx(c, e, e.high)
Expand Down
49 changes: 49 additions & 0 deletions tests/lang_objects/destructor/tdestroy_discarded_complex.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
discard """
description: '''
Ensure that the result of complex expressions is properly destroyed when
the full expression is discarded
'''
targets: "c js vm"
"""

type Object = object
has: bool

var destroyed = 0

proc `=destroy`(x: var Object) =
if x.has:
inc destroyed

proc make(): Object = Object(has: true)

# ---------------
# test procedures

proc test_block() =
discard (block: make())

proc test_if(cond: bool) =
discard (if cond: make() else: make())

proc test_case(cond: bool) =
discard (
case cond
of true: make()
of false: make()
)

proc test_try() =
discard (
try: make()
except: make()
)

test_block()
doAssert destroyed == 1
test_if(true)
doAssert destroyed == 2
test_case(true)
doAssert destroyed == 3
test_try()
doAssert destroyed == 4

0 comments on commit 3cab673

Please sign in to comment.