diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 049bf4470cbc6..d98a43c3f5b2e 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -12,7 +12,7 @@ //! the parent links in the region hierarchy. //! //! Most of the documentation on regions can be found in -//! `middle/infer/region_constraints/README.md` +//! `librustc/infer/region_constraints/README.md` use ich::{StableHashingContext, NodeIdHashingMode}; use util::nodemap::{FxHashMap, FxHashSet}; diff --git a/src/librustc_trans/cabi_x86_64.rs b/src/librustc_trans/cabi_x86_64.rs index 7c9f257469370..2785a6b0bf45d 100644 --- a/src/librustc_trans/cabi_x86_64.rs +++ b/src/librustc_trans/cabi_x86_64.rs @@ -14,7 +14,7 @@ use abi::{ArgType, CastTarget, FnType, LayoutExt, Reg, RegKind}; use context::CrateContext; -use rustc::ty::layout::{self, TyLayout, Size}; +use rustc::ty::layout::{self, Integer, Primitive, TyLayout, Size}; #[derive(Clone, Copy, PartialEq, Debug)] enum Class { @@ -24,6 +24,25 @@ enum Class { SseUp } +impl Class { + pub fn from_layout<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, layout: TyLayout<'tcx>) -> Self { + match layout.abi { + layout::Abi::Scalar(ref scalar) => match scalar.value { + layout::Int(..) | + layout::Pointer => Class::Int, + layout::F32 | + layout::F64 => Class::Sse, + }, + layout::Abi::ScalarPair(..) | layout::Abi::Aggregate { .. } => { + let last_idx = layout.fields.count().checked_sub(1).unwrap_or(0); + Class::from_layout(ccx, layout.field(ccx, last_idx)) + } + layout::Abi::Vector{ .. } => Class::SseUp, + layout::Abi::Uninhabited => unreachable!(), + } + } +} + #[derive(Clone, Copy, Debug)] struct Memory; @@ -64,17 +83,17 @@ fn classify_arg<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &ArgType<'tcx>) return Ok(()); } - match layout.abi { - layout::Abi::Uninhabited => {} + let mut offset = match layout.abi { + layout::Abi::Uninhabited => return Ok(()), layout::Abi::Scalar(ref scalar) => { - let reg = match scalar.value { - layout::Int(..) | - layout::Pointer => Class::Int, - layout::F32 | - layout::F64 => Class::Sse - }; - unify(cls, off, reg); + if let Primitive::Int(Integer::I128, _) = scalar.value { + unify(cls, off, Class::Int); + unify(cls, off + Size::from_bytes(8), Class::Int); + } else { + unify(cls, off, Class::from_layout(ccx, layout)); + } + off + scalar.value.size(ccx) } layout::Abi::Vector { ref element, count } => { @@ -83,26 +102,39 @@ fn classify_arg<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &ArgType<'tcx>) // everything after the first one is the upper // half of a register. let stride = element.value.size(ccx); + let mut field_off = off; for i in 1..count { - let field_off = off + stride * i; + field_off = off + stride * i; unify(cls, field_off, Class::SseUp); } + field_off + stride } layout::Abi::ScalarPair(..) | layout::Abi::Aggregate { .. } => { match layout.variants { layout::Variants::Single { .. } => { + let mut field_off = off; + let mut last_size = Size::from_bytes(0); for i in 0..layout.fields.count() { - let field_off = off + layout.fields.offset(i); + field_off = off + layout.fields.offset(i); classify(ccx, layout.field(ccx, i), cls, field_off)?; + last_size = layout.field(ccx, i).size; } + field_off + last_size } layout::Variants::Tagged { .. } | layout::Variants::NicheFilling { .. } => return Err(Memory), } } + }; + + // Add registers for padding. + let reg = Class::from_layout(ccx, layout); + while offset < layout.size { + unify(cls, offset, reg); + offset = offset + Size::from_bytes(8); } Ok(()) @@ -175,18 +207,18 @@ fn reg_component(cls: &[Class], i: &mut usize, size: Size) -> Option { } } -fn cast_target(cls: &[Class], size: Size) -> CastTarget { +fn cast_target(cls: &[Class], size: Size) -> Option { let mut i = 0; - let lo = reg_component(cls, &mut i, size).unwrap(); + let lo = reg_component(cls, &mut i, size)?; let offset = Size::from_bytes(8) * (i as u64); let target = if size <= offset { CastTarget::from(lo) } else { - let hi = reg_component(cls, &mut i, size - offset).unwrap(); + let hi = reg_component(cls, &mut i, size - offset)?; CastTarget::Pair(lo, hi) }; assert_eq!(reg_component(cls, &mut i, Size::from_bytes(0)), None); - target + Some(target) } pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) { @@ -229,7 +261,12 @@ pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType if arg.layout.is_aggregate() { let size = arg.layout.size; - arg.cast_to(cast_target(cls.as_ref().unwrap(), size)) + let cls = cls.as_ref().unwrap(); // This cannot fail when `in_mem` is false. + if let Some(target) = cast_target(cls, size) { + arg.cast_to(target); + } else { + bug!("cast_target() failed: cls {:?} size {:?} arg {:?}", cls, size, arg); + } } else { arg.extend_integer_width_to(32); } diff --git a/src/test/run-pass/align-with-extern-c-fn.rs b/src/test/run-pass/align-with-extern-c-fn.rs index db25960df4c87..4ace08e590151 100644 --- a/src/test/run-pass/align-with-extern-c-fn.rs +++ b/src/test/run-pass/align-with-extern-c-fn.rs @@ -18,6 +18,7 @@ pub struct A { y: i64, } +#[no_mangle] pub extern "C" fn foo(x: A) {} fn main() {} diff --git a/src/test/run-pass/issue-38763.rs b/src/test/run-pass/issue-38763.rs new file mode 100644 index 0000000000000..4bf9513d64f92 --- /dev/null +++ b/src/test/run-pass/issue-38763.rs @@ -0,0 +1,21 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(i128_type)] + +#[repr(C)] +pub struct Foo(i128); + +#[no_mangle] +pub extern "C" fn foo(x: Foo) -> Foo { x } + +fn main() { + foo(Foo(1)); +}