From c1e9b0a951ee5298244c6456af3641ee966e101b Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Wed, 9 Nov 2016 14:10:59 +0100 Subject: Fix returns from within finalizers When a return in a finalizer was reached through a return within the try block, the backend ignored the return in the finalizer: try { try { return 1 } finally { return 2 } } finally { println() } This expression should evaluate to 2 (it does in 2.11.8), but in 2.12.0 it the result is 1. The Scala spec is currently incomplete, it does not say that a finalizer should be exectuted if a return occurs within a try block, and it does not specify what happens if also the finally block has a return. So we follow the Java spec, which basically says: if the finally blocks completes abruptly for reason S, then the entire try statement completes abruptly with reason S. An abrupt termination of the try block for a different reason R is discarded. Abrupt completion is basically returning or throwing. --- .../scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala | 13 ++++--------- .../scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala | 1 - .../scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala | 3 --- 3 files changed, 4 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala index 0b07e12917..b0815b0008 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala @@ -488,16 +488,11 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { bc emitRETURN returnType case nextCleanup :: rest => if (saveReturnValue) { - if (insideCleanupBlock) { - reporter.warning(r.pos, "Return statement found in finally-clause, discarding its return-value in favor of that of a more deeply nested return.") - bc drop returnType - } else { - // regarding return value, the protocol is: in place of a `return-stmt`, a sequence of `adapt, store, jump` are inserted. - if (earlyReturnVar == null) { - earlyReturnVar = locals.makeLocal(returnType, "earlyReturnVar") - } - locals.store(earlyReturnVar) + // regarding return value, the protocol is: in place of a `return-stmt`, a sequence of `adapt, store, jump` are inserted. + if (earlyReturnVar == null) { + earlyReturnVar = locals.makeLocal(returnType, "earlyReturnVar") } + locals.store(earlyReturnVar) } bc goTo nextCleanup shouldEmitCleanup = true diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala index dbad37cd5b..fdb5687311 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala @@ -255,7 +255,6 @@ abstract class BCodeSkelBuilder extends BCodeHelpers { // used by genLoadTry() and genSynchronized() var earlyReturnVar: Symbol = null var shouldEmitCleanup = false - var insideCleanupBlock = false // line numbers var lastEmittedLineNr = -1 diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala index 9d4ef44546..add2c5ffe6 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala @@ -348,13 +348,10 @@ abstract class BCodeSyncAndTry extends BCodeBodyBuilder { // `shouldEmitCleanup` can be set, and at the same time this try expression may lack a finally-clause. // In other words, all combinations of (hasFinally, shouldEmitCleanup) are valid. if (hasFinally && currentFinallyBlockNeedsCleanup) { - val savedInsideCleanup = insideCleanupBlock - insideCleanupBlock = true markProgramPoint(finCleanup) // regarding return value, the protocol is: in place of a `return-stmt`, a sequence of `adapt, store, jump` are inserted. emitFinalizer(finalizer, null, isDuplicate = true) pendingCleanups() - insideCleanupBlock = savedInsideCleanup } /* ------ (4) finally-clause-for-normal-nonEarlyReturn-exit -- cgit v1.2.3