Skip to content

Commit

Permalink
Fix: calling twice proc with extern didn't work. Fixes #4982
Browse files Browse the repository at this point in the history
  • Loading branch information
asterite authored and Martin Verzilli committed Sep 16, 2017
1 parent 611b5eb commit 7f4ccff
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 5 deletions.
21 changes: 21 additions & 0 deletions spec/compiler/codegen/extern_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,27 @@ describe "Codegen: extern struct" do
)).to_i.should eq(42)
end

it "codegens extern proc call twice (#4982)" do
run(%(
@[Extern]
struct Data
def initialize(@foo : Int32)
end
def foo
@foo
end
end
f = ->(data : Data) { data.foo }
x = f.call(Data.new(1))
y = f.call(Data.new(2))
x + y
)).to_i.should eq(3)
end

# These specs *should* also work for 32 bits, but for now we'll
# make sure they work in 64 bits (they probably work in 32 bits too,
# it's just that the specs need to be a bit different)
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/crystal/codegen/ast.cr
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ module Crystal
end

@c_calling_convention : Bool? = nil
setter c_calling_convention
property c_calling_convention

# Returns `self` as an `External` if this Def is an External
# that must respect the C calling convention.
Expand Down
9 changes: 5 additions & 4 deletions src/compiler/crystal/codegen/primitives.cr
Original file line number Diff line number Diff line change
Expand Up @@ -651,7 +651,7 @@ class Crystal::CodeGenVisitor
c_calling_convention = target_def.proc_c_calling_convention?

proc_type = context.type.as(ProcInstanceType)
0.upto(target_def.args.size - 1) do |i|
target_def.args.size.times do |i|
arg = args[i]
proc_arg_type = proc_type.arg_types[i]
target_def_arg_type = target_def.args[i].type
Expand Down Expand Up @@ -685,6 +685,9 @@ class Crystal::CodeGenVisitor
# arguments according to the ABI.
# For this we temporarily set the target_def's `abi_info` and `c_calling_convention`
# properties for the non-closure branch, and then reset it.
old_abi_info = target_def.abi_info?
old_c_calling_convention = target_def.c_calling_convention

if c_calling_convention
null_fun_ptr, null_args = codegen_extern_primitive_proc_call(target_def, args, fun_ptr)
else
Expand All @@ -695,8 +698,6 @@ class Crystal::CodeGenVisitor
phi.add value, node.type

# Reset abi_info + c_calling_convention so the closure part is generated as usual
old_abi_info = target_def.abi_info?
old_c_calling_convention = target_def.c_calling_convention?
target_def.abi_info = false
target_def.c_calling_convention = nil

Expand All @@ -707,7 +708,7 @@ class Crystal::CodeGenVisitor
phi.add value, node.type, true

target_def.abi_info = old_abi_info
target_def.c_calling_convention = !!old_c_calling_convention
target_def.c_calling_convention = old_c_calling_convention
end

old_needs_value = @needs_value
Expand Down

0 comments on commit 7f4ccff

Please sign in to comment.