crystal-lang / crystal

The Crystal Programming Language
https://crystal-lang.org
Apache License 2.0
19.32k stars 1.61k forks source link

"Module validation failed: GEP base pointer is not a vector or a vector of pointers" #13890

Open wolfgang371 opened 10 months ago

wolfgang371 commented 10 months ago
ERROR_CODE_PROPERTIES = {
    file_name: "generated-errorcodes.txt",
    current_code: 0
}
{% system("rm #{ERROR_CODE_PROPERTIES[:file_name]}; true") %}
macro assert(invariant, f=__FILE__, l=__LINE__)
    {%
        ERROR_CODE_PROPERTIES[:current_code] += 1
        system("echo \"#{ERROR_CODE_PROPERTIES[:current_code]}; #{f}; #{l}\" >> #{ERROR_CODE_PROPERTIES[:file_name]}")
    %}
    {% if invariant %}
        if {{invariant}} # see https://github.com/crystal-lang/crystal/issues/13209
        else
            raise("error code #{ERROR_CODE_PROPERTIES[:current_code]}")
        end
    {% else %}
        raise("error code #{ERROR_CODE_PROPERTIES[:current_code]}")
    {% end %}
end

class X
    def initialize
    end
    def do(&block)
        assert(false)
    end
end

x = X.new
x.do {}
x.do {}

... gives...

Module validation failed: GEP base pointer is not a vector or a vector of pointers
  %42 = getelementptr inbounds %"NamedTuple(file_name: String, current_code: Int32)", i8 %41, i32 0, i32 1, !dbg !97
 (Exception)
  from /crystal/src/llvm/module.cr:73:9 in 'codegen'
  from /crystal/src/compiler/crystal/compiler.cr:172:16 in 'compile:combine_rpath'
  from /crystal/src/compiler/crystal/compiler.cr:165:56 in 'compile:combine_rpath'
  from /crystal/src/compiler/crystal/command.cr:227:5 in 'run_command'
  from /crystal/src/compiler/crystal/command.cr:125:10 in 'run'
  from /crystal/src/compiler/crystal.cr:11:1 in '__crystal_main'
  from /crystal/src/crystal/main.cr:129:5 in 'main'
  from src/env/__libc_start_main.c:95:2 in 'libc_start_main_stage2'
Error: you've found a bug in the Crystal compiler. Please open an issue, including source code that will allow us to reproduce the bug: https://github.com/crystal-lang/crystal/issues

(showing up on both 1.9.2 and 1.10.1, Ubuntu 18.04)

wolfgang371 commented 10 months ago

this is a slightly smaller version

ERROR_CODE_PROPERTIES = {current_code: 0}
macro assert(invariant)
    {% ERROR_CODE_PROPERTIES[:current_code] = 1 %}
    raise("error code #{ERROR_CODE_PROPERTIES[:current_code]}")
end

class X
    def initialize
    end
    def do(&)
        assert(false)
    end
end

x = X.new
x.do {}
x.do {}

(the original issue comes from https://forum.crystal-lang.org/t/compiler-support-on-production-ready-error-codes/6087)

HertzDevil commented 10 months ago

In:

def raise(x)
  while true; end
end

FOO = {x: 0}

def foo(&)
  {% FOO[:x] = 1 %}
  FOO[:x]
end

foo {}
foo {}

The LLVM IR for the code that initializes FOO is:

define void @"~FOO:init"() !dbg !18 {
entry:
  call void @"*raise<String>:NoReturn"(ptr @"'can't execute `{x: ...'")
  unreachable
}

And indeed running the snippet with DUMP=1 prints FOO = ::raise("can't execute `{x: 1}` at /home/quinton/crystal/crystal/usr/test.cr:5:7"). This only happens if #foo takes a block and is called more than once. So it looks like the constant initializer is not typed after it is modified (this explains why we need a definition for ::raise in order for the snippet to compile using the empty prelude).