Skip to content

Commit 8760a5e

Browse files
committed
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 <[email protected]>
1 parent 2819eca commit 8760a5e

File tree

1 file changed

+9
-0
lines changed

1 file changed

+9
-0
lines changed

src/librustc_trans/abi.rs

+9
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use cabi_asmjs;
2626
use machine::{llalign_of_min, llsize_of, llsize_of_real, llsize_of_store};
2727
use type_::Type;
2828
use type_of;
29+
use adt;
2930

3031
use rustc::hir;
3132
use rustc::ty::{self, Ty};
@@ -317,6 +318,14 @@ impl FnType {
317318
if ty.is_integral() {
318319
arg.signedness = Some(ty.is_signed());
319320
}
321+
// Rust enum types that map onto C enums (LLVM integers) also
322+
// need to follow the target ABI zero-/sign-extension rules.
323+
if let ty::TyEnum(..) = ty.sty {
324+
if arg.ty.kind() == llvm::Integer {
325+
let repr = adt::represent_type(ccx, ty);
326+
arg.signedness = Some(adt::is_discr_signed(&repr));
327+
}
328+
}
320329
if llsize_of_real(ccx, arg.ty) == 0 {
321330
// For some forsaken reason, x86_64-pc-windows-gnu
322331
// doesn't ignore zero-sized struct arguments.

0 commit comments

Comments
 (0)