diff options
author | Björn Gustavsson <[email protected]> | 2015-01-14 07:05:21 +0100 |
---|---|---|
committer | Björn Gustavsson <[email protected]> | 2015-01-14 14:44:22 +0100 |
commit | 85701edb6bdfe7c616a8486542dc2ca4bd787113 (patch) | |
tree | 15c6a1a0e1612c1dd51852dd2a15b68e942f1460 /bootstrap/lib/compiler | |
parent | a4449c481a6c887166097fd28f545876f6791625 (diff) | |
download | otp-85701edb6bdfe7c616a8486542dc2ca4bd787113.tar.gz otp-85701edb6bdfe7c616a8486542dc2ca4bd787113.tar.bz2 otp-85701edb6bdfe7c616a8486542dc2ca4bd787113.zip |
sys_core_fold: Correct optimization of 'case'
The optimization of a 'case' statement could lead to incorrect
code that would cause an exception at run-time.
Here is an example to show how the optimization went wrong. Start
with the following code:
f({r,#{key:=Val},X}=S) ->
case S of
{r,_,_} ->
setelement(3, Val, S)
end.
(The record operations have already been translated to the
corresponding tuple operations.) The first step in case_opt/3 is
to substitute S to obtain:
f({r,#{key:=Val},X}=S) ->
case {r,#{key:=Val},X} of
{r,_,_} ->
setelement(3, Val, S)
end.
After that substitution the 'case' can be simplified to:
f({r,#{key:=Val},_}=S) ->
case #{key:=Val} of
NewVar ->
setelement(3, Val, S)
end.
That is the result from case_opt/3. Now eval_case/2 notices
that since there is only one clause left in the 'case', the
'case' can eliminated:
f({r,#{key:=Val},_}=S) ->
NewVar = #{key:=Val},
setelement(3, Val, S).
Since the map construction may have a side effect, it was not
eliminated, but assigned to a variable that is never used.
The problem is that '#{key:=Val}' is fine as a pattern, but in a
construction of a new map, the '=>' operator must be used. So the
map construction will fail, generating an exception.
As a conservative correction for a maintenance release, we will
abort the 'case' optimization if the substitution into the 'case'
expression is anything but data items (tuples, conses, or
literals) or variables.
Reported-by: Dmitry Aleksandrov
Diffstat (limited to 'bootstrap/lib/compiler')
0 files changed, 0 insertions, 0 deletions