From 8760a5e3cc8bab89053ef9cee9757160e76f517d Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Wed, 7 Sep 2016 17:09:24 +0200 Subject: [PATCH 1/2] Follow target ABI sign-/zero-extension rules for enum types While attempting to port Rust to s390x, I ran into an ABI violation (that caused rust_eh_personality to be miscompiled, breaking unwinding). The problem is that this function returns an enum type, which is supposed to be sign-extended according to the s390x ABI. However, common code would ignore target sign-/zero-extension rules for any types that do not satisfy is_integral(), which includes enums. For the general case of Rust enum types, which map to structure types with a discriminant, that seems correct. However, in the special case of simple enums that map directly to C enum types (i.e. LLVM integers), this is incorrect; we must follow the target extension rules for those. Signed-off-by: Ulrich Weigand --- src/librustc_trans/abi.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index c2b040c32f6a3..ab0fd0c92edd4 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -26,6 +26,7 @@ use cabi_asmjs; use machine::{llalign_of_min, llsize_of, llsize_of_real, llsize_of_store}; use type_::Type; use type_of; +use adt; use rustc::hir; use rustc::ty::{self, Ty}; @@ -317,6 +318,14 @@ impl FnType { if ty.is_integral() { arg.signedness = Some(ty.is_signed()); } + // Rust enum types that map onto C enums (LLVM integers) also + // need to follow the target ABI zero-/sign-extension rules. + if let ty::TyEnum(..) = ty.sty { + if arg.ty.kind() == llvm::Integer { + let repr = adt::represent_type(ccx, ty); + arg.signedness = Some(adt::is_discr_signed(&repr)); + } + } if llsize_of_real(ccx, arg.ty) == 0 { // For some forsaken reason, x86_64-pc-windows-gnu // doesn't ignore zero-sized struct arguments. From ce3cecf116a2d691c53f37c1d257a416ecfd381b Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Wed, 7 Sep 2016 21:03:21 +0200 Subject: [PATCH 2/2] Use layout_of to detect C enums --- src/librustc_trans/abi.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index ab0fd0c92edd4..42289ec094f32 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -26,7 +26,6 @@ use cabi_asmjs; use machine::{llalign_of_min, llsize_of, llsize_of_real, llsize_of_store}; use type_::Type; use type_of; -use adt; use rustc::hir; use rustc::ty::{self, Ty}; @@ -36,6 +35,7 @@ use std::cmp; pub use syntax::abi::Abi; pub use rustc::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA}; +use rustc::ty::layout::Layout; #[derive(Clone, Copy, PartialEq, Debug)] enum ArgKind { @@ -318,13 +318,10 @@ impl FnType { if ty.is_integral() { arg.signedness = Some(ty.is_signed()); } - // Rust enum types that map onto C enums (LLVM integers) also - // need to follow the target ABI zero-/sign-extension rules. - if let ty::TyEnum(..) = ty.sty { - if arg.ty.kind() == llvm::Integer { - let repr = adt::represent_type(ccx, ty); - arg.signedness = Some(adt::is_discr_signed(&repr)); - } + // Rust enum types that map onto C enums also need to follow + // the target ABI zero-/sign-extension rules. + if let Layout::CEnum { signed, .. } = *ccx.layout_of(ty) { + arg.signedness = Some(signed); } if llsize_of_real(ccx, arg.ty) == 0 { // For some forsaken reason, x86_64-pc-windows-gnu