Skip to content

Commit 2067dd2

Browse files
committed
Auto merge of #22160 - dotdash:extern_rust, r=brson
As the function comment already says, the types generated in the foreign_signture function don't necessarily match the types used for a corresponding rust function. Therefore we can't just use these types to guide the translation of the wrapper function that bridges between the external ABI and the rust ABI. Instead, we can query LLVM about the types used in the rust function and use those to generate an appropriate wrapper. Fixes #21454
2 parents a954663 + 61db692 commit 2067dd2

File tree

2 files changed

+34
-5
lines changed

2 files changed

+34
-5
lines changed

src/librustc_trans/trans/foreign.rs

+15-5
Original file line numberDiff line numberDiff line change
@@ -670,14 +670,19 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
670670
}
671671
};
672672

673+
let rustfn_ty = Type::from_ref(llvm::LLVMTypeOf(llrustfn)).element_type();
674+
let mut rust_param_tys = rustfn_ty.func_params().into_iter();
673675
// Push Rust return pointer, using null if it will be unused.
674676
let rust_uses_outptr = match tys.fn_sig.output {
675677
ty::FnConverging(ret_ty) => type_of::return_uses_outptr(ccx, ret_ty),
676678
ty::FnDiverging => false
677679
};
678680
let return_alloca: Option<ValueRef>;
679-
let llrust_ret_ty = tys.llsig.llret_ty;
680-
let llrust_retptr_ty = llrust_ret_ty.ptr_to();
681+
let llrust_ret_ty = if rust_uses_outptr {
682+
rust_param_tys.next().expect("Missing return type!").element_type()
683+
} else {
684+
rustfn_ty.return_type()
685+
};
681686
if rust_uses_outptr {
682687
// Rust expects to use an outpointer. If the foreign fn
683688
// also uses an outpointer, we can reuse it, but the types
@@ -689,7 +694,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
689694
debug!("out pointer, foreign={}",
690695
ccx.tn().val_to_string(llforeign_outptr));
691696
let llrust_retptr =
692-
builder.bitcast(llforeign_outptr, llrust_retptr_ty);
697+
builder.bitcast(llforeign_outptr, llrust_ret_ty.ptr_to());
693698
debug!("out pointer, foreign={} (casted)",
694699
ccx.tn().val_to_string(llrust_retptr));
695700
llrust_args.push(llrust_retptr);
@@ -721,8 +726,13 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
721726
// a pointer and Rust does not or vice versa.
722727
for i in 0..tys.fn_sig.inputs.len() {
723728
let rust_ty = tys.fn_sig.inputs[i];
724-
let llrust_ty = tys.llsig.llarg_tys[i];
725729
let rust_indirect = type_of::arg_is_indirect(ccx, rust_ty);
730+
let llty = rust_param_tys.next().expect("Not enough parameter types!");
731+
let llrust_ty = if rust_indirect {
732+
llty.element_type()
733+
} else {
734+
llty
735+
};
726736
let llforeign_arg_ty = tys.fn_ty.arg_tys[i];
727737
let foreign_indirect = llforeign_arg_ty.is_indirect();
728738

@@ -838,7 +848,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
838848
// Foreign ABI requires an out pointer, but Rust doesn't.
839849
// Store Rust return value.
840850
let llforeign_outptr_casted =
841-
builder.bitcast(llforeign_outptr, llrust_retptr_ty);
851+
builder.bitcast(llforeign_outptr, llrust_ret_ty.ptr_to());
842852
builder.store(llrust_ret_val, llforeign_outptr_casted);
843853
builder.ret_void();
844854
}

src/test/run-pass/extern-rust.rs

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#[repr(C)]
12+
pub struct Foo(u32);
13+
14+
// ICE trigger, bad handling of differing types between rust and external ABIs
15+
pub extern fn bar() -> Foo {
16+
Foo(0)
17+
}
18+
19+
fn main() {}

0 commit comments

Comments
 (0)