Possible OCaml 4.04.2 compiler bug

compiler
bug

#1

I came across a weird error while building recently that seemed to result in a linker error (only using ocamlopt, of course). I’ve put the code here (reproduced inline).

module type Int = sig
  val one : int
  val (+) : int -> int -> int
end

module Make (Int : Int) = struct
  (* this assertion must fail in order to make the linker command fail *)
  let () = assert false

  (* this assertion doesn't matter *)
  let () =
    let falsy () = [1] == [1] in
    assert (falsy ())

  (* both the list and the + are needed to get the linker command to fail *)
  let two () = [ Int.(one + one) ]
end

module M = Make(struct
    let one = 1
    let (+) = (+)
  end)

(* This programs fails with a linker error on OCaml version 4.04.2 but not 4.05.0
   {[
      % jbuilder build @install
          ocamldep src/main.depends.ocamldep-output
            ocamlc src/main.{cmi,cmo,cmt}
          ocamlopt src/main.{cmx,o}
          ocamlopt src/main.exe (exit 2)
      (cd _build/default && ~/.opam/4.04.2/bin/ocamlopt.opt -w -40 -g -o src/main.exe src/main.cmx)
      src/main.o: In function `camlMain__entry':
      ~/.../_build/default/src/main.ml:24: undefined reference to `camlMain__two_1207'
      collect2: error: ld returned 1 exit status
      File "caml_startup", line 1:
      Error: Error during linking
   ]}
*)
let _ = M.two ()

(the bug manifests when building with, e.g., ocamlbuild, so jbuilder isn’t the culprit AFAICT)

Basically, under certain circumstances, a constant false assertion in the body of a functor seems to trigger “undefined reference” linker errors for values defined after that assertion.

Some weird things about this bug: I think the definition after the assertion needs to be sufficiently complex, or else it probably just gets inlined. Also, simply raising an exception without using assert doesn’t trigger the linker error.

It doesn’t really matter so much, since this is fixed in 4.05.0, but I read through the release notes and didn’t see anything obviously related to this. Thought somebody here might be more familiar with either what fixed it in 4.05.0 or what was causing this problem in the first place.


#2

I can reproduce this with 4.03.0. Please consider reporting it on the OCaml bug tracker.

Here is a shorter reproduction that does not require jbuilder:

module Make (Int : sig val one : int end) = struct
  let () = assert false
  let two () = [Int.one + 1]
end

module M = Make (struct let one = 1 end)

let _ = M.two ()

Compiling with ocamlopt test.ml should result in the same error.


#3

Thanks, @gsg. I’ve reported it here: https://caml.inria.fr/mantis/view.php?id=7654, looks like the problem was probably related to a known bug.


#4

The problem was fixed by Mark Shinwell in GPR#959 (December 2016).