Skip to content

Commit

Permalink
Compiler: correctly copy anonymous struct types from other contexts. F…
Browse files Browse the repository at this point in the history
…ixes #4078 . Fixes #4082
  • Loading branch information
asterite committed Mar 1, 2017
1 parent 2e61cca commit e586dd2
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 6 deletions.
24 changes: 24 additions & 0 deletions spec/compiler/codegen/c_abi/c_abi_x86_64_spec.cr
Expand Up @@ -85,6 +85,30 @@ require "../../../spec_helper"
str.should contain("declare void @foo({ i64, i64 })")
end

it "passes struct between 64 and 128 bits as { i64, i64 } (with multiple modules/contexts)" do
codegen(%(
require "prelude"
lib LibFoo
struct Struct
x : Int64
y : Int16
end
fun foo(s : Struct)
end
module Moo
def self.moo
s = LibFoo::Struct.new
LibFoo.foo(s)
end
end
Moo.moo
))
end

it "passes struct between 64 and 128 bits (for real)" do
test_c(
%(
Expand Down
14 changes: 10 additions & 4 deletions src/compiler/crystal/codegen/llvm_typer.cr
Expand Up @@ -523,11 +523,17 @@ module Crystal
LLVM::Type.function(params_types, ret_type, type.varargs?)
when .struct?
llvm_name = type.struct_name
@structs[llvm_name] ||= begin
@llvm_context.struct(llvm_name, type.packed_struct?) do |the_struct|
@structs[llvm_name] = the_struct
copy_types(type.struct_element_types)
if llvm_name
@structs[llvm_name] ||= begin
@llvm_context.struct(llvm_name, type.packed_struct?) do |the_struct|
@structs[llvm_name] = the_struct
copy_types(type.struct_element_types)
end
end
else
# The case of an anonymous struct (only happens with C bindings and C ABI,
# where structs like `{ double, double }` are generated)
@llvm_context.struct(copy_types(type.struct_element_types), packed: type.packed_struct?)
end
else
raise "don't know how to copy type: #{type} (#{type.kind})"
Expand Down
8 changes: 6 additions & 2 deletions src/llvm/type.cr
Expand Up @@ -63,10 +63,14 @@ struct LLVM::Type
LibLLVM.is_packed_struct(self) != 0
end

def struct_name
# Assuming this type is a struct, returns its name.
# The name can be `nil` if the struct is anynomous.
# Raises if this type is not a struct.
def struct_name : String?
raise "not a Struct" unless kind == Kind::Struct

String.new(LibLLVM.get_struct_name(self))
name = LibLLVM.get_struct_name(self)
name ? String.new(name) : nil
end

def struct_element_types
Expand Down

0 comments on commit e586dd2

Please sign in to comment.