mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-19 07:45:09 +00:00
Estimated hours taken: 12 Fix a bug with the handling of commits in the high-level C back-end. It was implementing commits via calls to setjmp()/longjmp(), but ANSI/ISO C says that longjmp() is allowed to clobber the values of any non-volatile local variables in the function that called setjmp() which have been modified between the setjmp() and the longjmp(). The fix is that whenever we generate a commit, we put it in its own nested function, with the local variables (e.g. `succeeded', plus any outputs from the goal that we're committing over) remaining in the containing function. This ensures that none of the variables which get modified between the setjmp() and the longjmp() and which get referenced after the longjmp() are local variables in the function containing the setjmp(). [The obvious alternative of declaring the local variables in the function containing setjmp() as `volatile' doesn't work, since the assignments to those output variables may be deep in some function called indirectly from the goal that we're committing across, and assigning to a volatile-qualified variable via a non-volatile pointer is undefined behaviour. The only way to make it work would be to be to declare *every* output argument that we pass by reference as `volatile T *'. But that would impose distributed fat and would make interoperability difficult.] compiler/options.m: Add a new option `--put-commits-in-own-function'. compiler/handle_options.m: If the target is high-level C, set the `--put-commits-in-own-function' option. compiler/ml_code_util.m: Add a routine for accessing the new option. compiler/ml_code_gen.m: If the new option is set, generate each commit in its own nested function. tests/hard_coded/Mmakefile: tests/hard_coded/setjmp_test.m: tests/hard_coded/setjmp_test.exp: A regression test. Previous versions of the compiler generated code for this test case that did the wrong thing on *some* systems.
30 lines
626 B
Mathematica
30 lines
626 B
Mathematica
% This is a regression test:
|
|
% the compiler used to generate code for this in the hlc.gc grade
|
|
% which had undefined behaviour according to ANSI/ISO C,
|
|
% and which would in practice fail on some systems
|
|
% (e.g. alpha*-dec-osf3.2 with egcs-1.1.2).
|
|
|
|
:- module setjmp_test.
|
|
:- interface.
|
|
:- import_module io.
|
|
|
|
:- pred main(io__state::di, io__state::uo) is cc_multi.
|
|
|
|
:- implementation.
|
|
|
|
:- import_module std_util.
|
|
|
|
main -->
|
|
(if { p(X) } then
|
|
print("X = "), print(X), nl
|
|
;
|
|
print("no")
|
|
).
|
|
|
|
:- pragma inline(p/1).
|
|
:- pred p(int).
|
|
:- mode p(out) is nondet.
|
|
p(1) :- semidet_fail.
|
|
p(2) :- semidet_succeed.
|
|
p(3) :- semidet_fail.
|