From 8f81593d6c9b731973c0f8e57548948101dda928 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 22 Jan 2020 02:52:14 +0200 Subject: [PATCH] rustc_target: switch homogeneous_aggregate to returning Result. --- src/librustc_target/abi/call/aarch64.rs | 2 +- src/librustc_target/abi/call/arm.rs | 2 +- src/librustc_target/abi/call/mod.rs | 139 ++++++++++-------- src/librustc_target/abi/call/powerpc64.rs | 2 +- src/librustc_target/abi/call/sparc64.rs | 2 +- src/librustc_target/abi/call/wasm32.rs | 2 +- src/librustc_target/abi/call/x86.rs | 2 +- .../homogeneous-aggr-zero-sized-c-struct.rs | 4 +- ...omogeneous-aggr-zero-sized-c-struct.stderr | 4 +- .../homogeneous-aggr-zero-sized-repr-rust.rs | 10 +- ...mogeneous-aggr-zero-sized-repr-rust.stderr | 10 +- src/test/ui/layout/zero-sized-array-union.rs | 8 +- .../ui/layout/zero-sized-array-union.stderr | 8 +- 13 files changed, 107 insertions(+), 88 deletions(-) diff --git a/src/librustc_target/abi/call/aarch64.rs b/src/librustc_target/abi/call/aarch64.rs index 2dd41a0d80f..c8bac5aebc6 100644 --- a/src/librustc_target/abi/call/aarch64.rs +++ b/src/librustc_target/abi/call/aarch64.rs @@ -6,7 +6,7 @@ where Ty: TyLayoutMethods<'a, C> + Copy, C: LayoutOf> + HasDataLayout, { - arg.layout.homogeneous_aggregate(cx).unit().and_then(|unit| { + arg.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()).and_then(|unit| { let size = arg.layout.size; // Ensure we have at most four uniquely addressable members. diff --git a/src/librustc_target/abi/call/arm.rs b/src/librustc_target/abi/call/arm.rs index eb9364091dc..59ec87e3c9e 100644 --- a/src/librustc_target/abi/call/arm.rs +++ b/src/librustc_target/abi/call/arm.rs @@ -7,7 +7,7 @@ where Ty: TyLayoutMethods<'a, C> + Copy, C: LayoutOf> + HasDataLayout, { - arg.layout.homogeneous_aggregate(cx).unit().and_then(|unit| { + arg.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()).and_then(|unit| { let size = arg.layout.size; // Ensure we have at most four uniquely addressable members. diff --git a/src/librustc_target/abi/call/mod.rs b/src/librustc_target/abi/call/mod.rs index af82f9e3183..748fd2b6579 100644 --- a/src/librustc_target/abi/call/mod.rs +++ b/src/librustc_target/abi/call/mod.rs @@ -219,26 +219,47 @@ impl CastTarget { } } -/// Returns value from the `homogeneous_aggregate` test function. +/// Return value from the `homogeneous_aggregate` test function. #[derive(Copy, Clone, Debug)] pub enum HomogeneousAggregate { /// Yes, all the "leaf fields" of this struct are passed in the /// same way (specified in the `Reg` value). Homogeneous(Reg), - /// There are distinct leaf fields passed in different ways, - /// or this is uninhabited. - Heterogeneous, - /// There are no leaf fields at all. NoData, } +/// Error from the `homogeneous_aggregate` test function, indicating +/// there are distinct leaf fields passed in different ways, +/// or this is uninhabited. +#[derive(Copy, Clone, Debug)] +pub struct Heterogeneous; + impl HomogeneousAggregate { /// If this is a homogeneous aggregate, returns the homogeneous /// unit, else `None`. pub fn unit(self) -> Option { - if let HomogeneousAggregate::Homogeneous(r) = self { Some(r) } else { None } + match self { + HomogeneousAggregate::Homogeneous(reg) => Some(reg), + HomogeneousAggregate::NoData => None, + } + } + + /// Try to combine two `HomogeneousAggregate`s, e.g. from two fields in + /// the same `struct`. Only succeeds if only one of them has any data, + /// or both units are identical. + fn merge(self, other: HomogeneousAggregate) -> Result { + match (self, other) { + (x, HomogeneousAggregate::NoData) | (HomogeneousAggregate::NoData, x) => Ok(x), + + (HomogeneousAggregate::Homogeneous(a), HomogeneousAggregate::Homogeneous(b)) => { + if a != b { + return Err(Heterogeneous); + } + Ok(self) + } + } } } @@ -250,8 +271,8 @@ impl<'a, Ty> TyLayout<'a, Ty> { } } - /// Returns `true` if this layout is an aggregate containing fields of only - /// a single type (e.g., `(u32, u32)`). Such aggregates are often + /// Returns `Homogeneous` if this layout is an aggregate containing fields of + /// only a single type (e.g., `(u32, u32)`). Such aggregates are often /// special-cased in ABIs. /// /// Note: We generally ignore fields of zero-sized type when computing @@ -260,13 +281,13 @@ impl<'a, Ty> TyLayout<'a, Ty> { /// This is public so that it can be used in unit tests, but /// should generally only be relevant to the ABI details of /// specific targets. - pub fn homogeneous_aggregate(&self, cx: &C) -> HomogeneousAggregate + pub fn homogeneous_aggregate(&self, cx: &C) -> Result where Ty: TyLayoutMethods<'a, C> + Copy, C: LayoutOf, { match self.abi { - Abi::Uninhabited => HomogeneousAggregate::Heterogeneous, + Abi::Uninhabited => Err(Heterogeneous), // The primitive for this algorithm. Abi::Scalar(ref scalar) => { @@ -274,80 +295,78 @@ impl<'a, Ty> TyLayout<'a, Ty> { abi::Int(..) | abi::Pointer => RegKind::Integer, abi::F32 | abi::F64 => RegKind::Float, }; - HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size }) + Ok(HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size })) } Abi::Vector { .. } => { assert!(!self.is_zst()); - HomogeneousAggregate::Homogeneous(Reg { kind: RegKind::Vector, size: self.size }) + Ok(HomogeneousAggregate::Homogeneous(Reg { + kind: RegKind::Vector, + size: self.size, + })) } Abi::ScalarPair(..) | Abi::Aggregate { .. } => { - let mut total = Size::ZERO; - let mut result = None; + // Helper for computing `homogenous_aggregate`, allowing a custom + // starting offset (TODO(eddyb): use this to handle variants). + let from_fields_at = + |layout: Self, + start: Size| + -> Result<(HomogeneousAggregate, Size), Heterogeneous> { + let is_union = match layout.fields { + FieldPlacement::Array { count, .. } => { + assert_eq!(start, Size::ZERO); - let is_union = match self.fields { - FieldPlacement::Array { count, .. } => { - if count > 0 { - return self.field(cx, 0).homogeneous_aggregate(cx); - } else { - return HomogeneousAggregate::NoData; - } - } - FieldPlacement::Union(_) => true, - FieldPlacement::Arbitrary { .. } => false, - }; + let result = if count > 0 { + layout.field(cx, 0).homogeneous_aggregate(cx)? + } else { + HomogeneousAggregate::NoData + }; + return Ok((result, layout.size)); + } + FieldPlacement::Union(_) => true, + FieldPlacement::Arbitrary { .. } => false, + }; - for i in 0..self.fields.count() { - if !is_union && total != self.fields.offset(i) { - return HomogeneousAggregate::Heterogeneous; - } + let mut result = HomogeneousAggregate::NoData; + let mut total = start; - let field = self.field(cx, i); + for i in 0..layout.fields.count() { + if !is_union && total != layout.fields.offset(i) { + return Err(Heterogeneous); + } - match (result, field.homogeneous_aggregate(cx)) { - (_, HomogeneousAggregate::NoData) => { - // Ignore fields that have no data - } - (_, HomogeneousAggregate::Heterogeneous) => { - // The field itself must be a homogeneous aggregate. - return HomogeneousAggregate::Heterogeneous; - } - // If this is the first field, record the unit. - (None, HomogeneousAggregate::Homogeneous(unit)) => { - result = Some(unit); - } - // For all following fields, the unit must be the same. - (Some(prev_unit), HomogeneousAggregate::Homogeneous(unit)) => { - if prev_unit != unit { - return HomogeneousAggregate::Heterogeneous; + let field = layout.field(cx, i); + + result = result.merge(field.homogeneous_aggregate(cx)?)?; + + // Keep track of the offset (without padding). + let size = field.size; + if is_union { + total = total.max(size); + } else { + total += size; } } - } - // Keep track of the offset (without padding). - let size = field.size; - if is_union { - total = total.max(size); - } else { - total += size; - } - } + Ok((result, total)) + }; + + let (mut result, mut total) = from_fields_at(*self, Size::ZERO)?; // There needs to be no padding. if total != self.size { - HomogeneousAggregate::Heterogeneous + Err(Heterogeneous) } else { match result { - Some(reg) => { + HomogeneousAggregate::Homogeneous(_) => { assert_ne!(total, Size::ZERO); - HomogeneousAggregate::Homogeneous(reg) } - None => { + HomogeneousAggregate::NoData => { assert_eq!(total, Size::ZERO); - HomogeneousAggregate::NoData } } + Ok(result) } } } diff --git a/src/librustc_target/abi/call/powerpc64.rs b/src/librustc_target/abi/call/powerpc64.rs index 2db3954b481..93c4e97de10 100644 --- a/src/librustc_target/abi/call/powerpc64.rs +++ b/src/librustc_target/abi/call/powerpc64.rs @@ -22,7 +22,7 @@ where Ty: TyLayoutMethods<'a, C> + Copy, C: LayoutOf> + HasDataLayout, { - arg.layout.homogeneous_aggregate(cx).unit().and_then(|unit| { + arg.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()).and_then(|unit| { // ELFv1 only passes one-member aggregates transparently. // ELFv2 passes up to eight uniquely addressable members. if (abi == ELFv1 && arg.layout.size > unit.size) diff --git a/src/librustc_target/abi/call/sparc64.rs b/src/librustc_target/abi/call/sparc64.rs index 8bcb02b8764..c80f8316feb 100644 --- a/src/librustc_target/abi/call/sparc64.rs +++ b/src/librustc_target/abi/call/sparc64.rs @@ -8,7 +8,7 @@ where Ty: TyLayoutMethods<'a, C> + Copy, C: LayoutOf> + HasDataLayout, { - arg.layout.homogeneous_aggregate(cx).unit().and_then(|unit| { + arg.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()).and_then(|unit| { // Ensure we have at most eight uniquely addressable members. if arg.layout.size > unit.size.checked_mul(8, cx).unwrap() { return None; diff --git a/src/librustc_target/abi/call/wasm32.rs b/src/librustc_target/abi/call/wasm32.rs index 852ead8c522..9aab64ef272 100644 --- a/src/librustc_target/abi/call/wasm32.rs +++ b/src/librustc_target/abi/call/wasm32.rs @@ -7,7 +7,7 @@ where C: LayoutOf> + HasDataLayout, { if val.layout.is_aggregate() { - if let Some(unit) = val.layout.homogeneous_aggregate(cx).unit() { + if let Some(unit) = val.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()) { let size = val.layout.size; if unit.size == size { val.cast_to(Uniform { unit, total: size }); diff --git a/src/librustc_target/abi/call/x86.rs b/src/librustc_target/abi/call/x86.rs index a7884849b82..e776a8b3fe4 100644 --- a/src/librustc_target/abi/call/x86.rs +++ b/src/librustc_target/abi/call/x86.rs @@ -100,7 +100,7 @@ where }; // At this point we know this must be a primitive of sorts. - let unit = arg.layout.homogeneous_aggregate(cx).unit().unwrap(); + let unit = arg.layout.homogeneous_aggregate(cx).unwrap().unit().unwrap(); assert_eq!(unit.size, arg.layout.size); if unit.kind == RegKind::Float { continue; diff --git a/src/test/ui/layout/homogeneous-aggr-zero-sized-c-struct.rs b/src/test/ui/layout/homogeneous-aggr-zero-sized-c-struct.rs index 1c70624e4a2..7eecd99dc01 100644 --- a/src/test/ui/layout/homogeneous-aggr-zero-sized-c-struct.rs +++ b/src/test/ui/layout/homogeneous-aggr-zero-sized-c-struct.rs @@ -20,7 +20,7 @@ pub struct Middle { #[rustc_layout(homogeneous_aggregate)] pub type TestMiddle = Middle; -//~^ ERROR homogeneous_aggregate: Homogeneous +//~^ ERROR homogeneous_aggregate: Ok(Homogeneous #[repr(C)] pub struct Final { @@ -31,6 +31,6 @@ pub struct Final { #[rustc_layout(homogeneous_aggregate)] pub type TestFinal = Final; -//~^ ERROR homogeneous_aggregate: Homogeneous +//~^ ERROR homogeneous_aggregate: Ok(Homogeneous fn main() { } diff --git a/src/test/ui/layout/homogeneous-aggr-zero-sized-c-struct.stderr b/src/test/ui/layout/homogeneous-aggr-zero-sized-c-struct.stderr index 0d442606351..cd3fb5ca5ea 100644 --- a/src/test/ui/layout/homogeneous-aggr-zero-sized-c-struct.stderr +++ b/src/test/ui/layout/homogeneous-aggr-zero-sized-c-struct.stderr @@ -1,10 +1,10 @@ -error: homogeneous_aggregate: Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }) +error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size { raw: 4 } })) --> $DIR/homogeneous-aggr-zero-sized-c-struct.rs:22:1 | LL | pub type TestMiddle = Middle; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: homogeneous_aggregate: Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }) +error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size { raw: 4 } })) --> $DIR/homogeneous-aggr-zero-sized-c-struct.rs:33:1 | LL | pub type TestFinal = Final; diff --git a/src/test/ui/layout/homogeneous-aggr-zero-sized-repr-rust.rs b/src/test/ui/layout/homogeneous-aggr-zero-sized-repr-rust.rs index 4b429412aeb..ec2c9b70224 100644 --- a/src/test/ui/layout/homogeneous-aggr-zero-sized-repr-rust.rs +++ b/src/test/ui/layout/homogeneous-aggr-zero-sized-repr-rust.rs @@ -52,22 +52,22 @@ pub struct WithEmptyRustEnum { #[rustc_layout(homogeneous_aggregate)] pub type Test1 = BaseCase; -//~^ ERROR homogeneous_aggregate: Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }) +//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size { raw: 4 } })) #[rustc_layout(homogeneous_aggregate)] pub type Test2 = WithPhantomData; -//~^ ERROR homogeneous_aggregate: Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }) +//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size { raw: 4 } })) #[rustc_layout(homogeneous_aggregate)] pub type Test3 = WithEmptyRustStruct; -//~^ ERROR homogeneous_aggregate: Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }) +//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size { raw: 4 } })) #[rustc_layout(homogeneous_aggregate)] pub type Test4 = WithTransitivelyEmptyRustStruct; -//~^ ERROR homogeneous_aggregate: Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }) +//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size { raw: 4 } })) #[rustc_layout(homogeneous_aggregate)] pub type Test5 = WithEmptyRustEnum; -//~^ ERROR homogeneous_aggregate: Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }) +//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size { raw: 4 } })) fn main() { } diff --git a/src/test/ui/layout/homogeneous-aggr-zero-sized-repr-rust.stderr b/src/test/ui/layout/homogeneous-aggr-zero-sized-repr-rust.stderr index be04ba3e7f6..ec2b08bf02d 100644 --- a/src/test/ui/layout/homogeneous-aggr-zero-sized-repr-rust.stderr +++ b/src/test/ui/layout/homogeneous-aggr-zero-sized-repr-rust.stderr @@ -1,28 +1,28 @@ -error: homogeneous_aggregate: Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }) +error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size { raw: 4 } })) --> $DIR/homogeneous-aggr-zero-sized-repr-rust.rs:54:1 | LL | pub type Test1 = BaseCase; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: homogeneous_aggregate: Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }) +error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size { raw: 4 } })) --> $DIR/homogeneous-aggr-zero-sized-repr-rust.rs:58:1 | LL | pub type Test2 = WithPhantomData; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: homogeneous_aggregate: Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }) +error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size { raw: 4 } })) --> $DIR/homogeneous-aggr-zero-sized-repr-rust.rs:62:1 | LL | pub type Test3 = WithEmptyRustStruct; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: homogeneous_aggregate: Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }) +error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size { raw: 4 } })) --> $DIR/homogeneous-aggr-zero-sized-repr-rust.rs:66:1 | LL | pub type Test4 = WithTransitivelyEmptyRustStruct; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: homogeneous_aggregate: Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }) +error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size { raw: 4 } })) --> $DIR/homogeneous-aggr-zero-sized-repr-rust.rs:70:1 | LL | pub type Test5 = WithEmptyRustEnum; diff --git a/src/test/ui/layout/zero-sized-array-union.rs b/src/test/ui/layout/zero-sized-array-union.rs index 68b218249eb..1a662ba4467 100644 --- a/src/test/ui/layout/zero-sized-array-union.rs +++ b/src/test/ui/layout/zero-sized-array-union.rs @@ -57,7 +57,7 @@ struct Baz1 { #[rustc_layout(homogeneous_aggregate)] type TestBaz1 = Baz1; -//~^ ERROR homogeneous_aggregate: Homogeneous +//~^ ERROR homogeneous_aggregate: Ok(Homogeneous #[repr(C)] struct Baz2 { @@ -68,7 +68,7 @@ struct Baz2 { #[rustc_layout(homogeneous_aggregate)] type TestBaz2 = Baz2; -//~^ ERROR homogeneous_aggregate: Homogeneous +//~^ ERROR homogeneous_aggregate: Ok(Homogeneous #[repr(C)] struct Baz3 { @@ -79,7 +79,7 @@ struct Baz3 { #[rustc_layout(homogeneous_aggregate)] type TestBaz3 = Baz3; -//~^ ERROR homogeneous_aggregate: Homogeneous +//~^ ERROR homogeneous_aggregate: Ok(Homogeneous #[repr(C)] struct Baz4 { @@ -90,6 +90,6 @@ struct Baz4 { #[rustc_layout(homogeneous_aggregate)] type TestBaz4 = Baz4; -//~^ ERROR homogeneous_aggregate: Homogeneous +//~^ ERROR homogeneous_aggregate: Ok(Homogeneous fn main() { } diff --git a/src/test/ui/layout/zero-sized-array-union.stderr b/src/test/ui/layout/zero-sized-array-union.stderr index 1bb31aaf7b7..43b1588266b 100644 --- a/src/test/ui/layout/zero-sized-array-union.stderr +++ b/src/test/ui/layout/zero-sized-array-union.stderr @@ -1,22 +1,22 @@ -error: homogeneous_aggregate: Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }) +error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size { raw: 4 } })) --> $DIR/zero-sized-array-union.rs:59:1 | LL | type TestBaz1 = Baz1; | ^^^^^^^^^^^^^^^^^^^^^ -error: homogeneous_aggregate: Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }) +error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size { raw: 4 } })) --> $DIR/zero-sized-array-union.rs:70:1 | LL | type TestBaz2 = Baz2; | ^^^^^^^^^^^^^^^^^^^^^ -error: homogeneous_aggregate: Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }) +error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size { raw: 4 } })) --> $DIR/zero-sized-array-union.rs:81:1 | LL | type TestBaz3 = Baz3; | ^^^^^^^^^^^^^^^^^^^^^ -error: homogeneous_aggregate: Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }) +error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size { raw: 4 } })) --> $DIR/zero-sized-array-union.rs:92:1 | LL | type TestBaz4 = Baz4;