From a81c59f9b84b6519785a4e0ae9234107d149f454 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Thu, 30 Jan 2020 20:09:23 +0000 Subject: [PATCH 01/10] Remove some unsound specializations --- src/libcore/iter/range.rs | 4 + src/libcore/ops/range.rs | 38 ++++----- src/libcore/slice/mod.rs | 80 ++++++++++++------- src/libcore/str/mod.rs | 10 +-- src/libcore/tests/iter.rs | 16 ++++ .../soundness/partial_eq_range_inclusive.rs | 35 ++++++++ .../soundness/partial_ord_slice.rs | 42 ++++++++++ 7 files changed, 168 insertions(+), 57 deletions(-) create mode 100644 src/test/ui/specialization/soundness/partial_eq_range_inclusive.rs create mode 100644 src/test/ui/specialization/soundness/partial_ord_slice.rs diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index eac3c107d228..be9d832ed90f 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -385,12 +385,14 @@ impl Iterator for ops::RangeInclusive { } Some(Equal) => { self.is_empty = Some(true); + self.start = plus_n.clone(); return Some(plus_n); } _ => {} } } + self.start = self.end.clone(); self.is_empty = Some(true); None } @@ -477,12 +479,14 @@ impl DoubleEndedIterator for ops::RangeInclusive { } Some(Equal) => { self.is_empty = Some(true); + self.end = minus_n.clone(); return Some(minus_n); } _ => {} } } + self.end = self.start.clone(); self.is_empty = Some(true); None } diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index d38b35165695..6c0bc6bbbad2 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -343,38 +343,21 @@ pub struct RangeInclusive { pub(crate) is_empty: Option, // This field is: // - `None` when next() or next_back() was never called - // - `Some(false)` when `start <= end` assuming no overflow - // - `Some(true)` otherwise + // - `Some(false)` when `start < end` + // - `Some(true)` when `end < start` + // - `Some(false)` when `start == end` and the range hasn't yet completed iteration + // - `Some(true)` when `start == end` and the range has completed iteration // The field cannot be a simple `bool` because the `..=` constructor can // accept non-PartialOrd types, also we want the constructor to be const. } -trait RangeInclusiveEquality: Sized { - fn canonicalized_is_empty(range: &RangeInclusive) -> bool; -} - -impl RangeInclusiveEquality for T { - #[inline] - default fn canonicalized_is_empty(range: &RangeInclusive) -> bool { - range.is_empty.unwrap_or_default() - } -} - -impl RangeInclusiveEquality for T { - #[inline] - fn canonicalized_is_empty(range: &RangeInclusive) -> bool { - range.is_empty() - } -} - #[stable(feature = "inclusive_range", since = "1.26.0")] impl PartialEq for RangeInclusive { #[inline] fn eq(&self, other: &Self) -> bool { self.start == other.start && self.end == other.end - && RangeInclusiveEquality::canonicalized_is_empty(self) - == RangeInclusiveEquality::canonicalized_is_empty(other) + && self.is_exhausted() == other.is_exhausted() } } @@ -386,7 +369,8 @@ impl Hash for RangeInclusive { fn hash(&self, state: &mut H) { self.start.hash(state); self.end.hash(state); - RangeInclusiveEquality::canonicalized_is_empty(self).hash(state); + // Ideally we would hash `is_exhausted` here as well, but there's no + // way for us to call it. } } @@ -485,6 +469,14 @@ impl fmt::Debug for RangeInclusive { } } +impl> RangeInclusive { + // Returns true if this is a range that started non-empty, and was iterated + // to exhaustion. + fn is_exhausted(&self) -> bool { + Some(true) == self.is_empty && self.start == self.end + } +} + impl> RangeInclusive { /// Returns `true` if `item` is contained in the range. /// diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 9b4d20157323..e79a775325f4 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -5584,21 +5584,18 @@ where #[doc(hidden)] // intermediate trait for specialization of slice's PartialOrd -trait SlicePartialOrd { - fn partial_compare(&self, other: &[B]) -> Option; +trait SlicePartialOrd: Sized { + fn partial_compare(left: &[Self], right: &[Self]) -> Option; } -impl SlicePartialOrd for [A] -where - A: PartialOrd, -{ - default fn partial_compare(&self, other: &[A]) -> Option { - let l = cmp::min(self.len(), other.len()); +impl SlicePartialOrd for A { + default fn partial_compare(left: &[A], right: &[A]) -> Option { + let l = cmp::min(left.len(), right.len()); // Slice to the loop iteration range to enable bound check // elimination in the compiler - let lhs = &self[..l]; - let rhs = &other[..l]; + let lhs = &left[..l]; + let rhs = &right[..l]; for i in 0..l { match lhs[i].partial_cmp(&rhs[i]) { @@ -5607,36 +5604,61 @@ where } } - self.len().partial_cmp(&other.len()) + left.len().partial_cmp(&right.len()) } } -impl SlicePartialOrd for [A] +// This is the impl that we would like to have. Unfortunately it's not sound. +// See `partial_ord_slice.rs`. +/* +impl SlicePartialOrd for A where A: Ord, { - default fn partial_compare(&self, other: &[A]) -> Option { - Some(SliceOrd::compare(self, other)) + default fn partial_compare(left: &[A], right: &[A]) -> Option { + Some(SliceOrd::compare(left, right)) } } +*/ + +impl SlicePartialOrd for A { + fn partial_compare(left: &[A], right: &[A]) -> Option { + Some(SliceOrd::compare(left, right)) + } +} + +trait AlwaysApplicableOrd: SliceOrd + Ord {} + +macro_rules! always_applicable_ord { + ($([$($p:tt)*] $t:ty,)*) => { + $(impl<$($p)*> AlwaysApplicableOrd for $t {})* + } +} + +always_applicable_ord! { + [] u8, [] u16, [] u32, [] u64, [] u128, [] usize, + [] i8, [] i16, [] i32, [] i64, [] i128, [] isize, + [] bool, [] char, + [T: ?Sized] *const T, [T: ?Sized] *mut T, + [T: AlwaysApplicableOrd] &T, + [T: AlwaysApplicableOrd] &mut T, + [T: AlwaysApplicableOrd] Option, +} #[doc(hidden)] // intermediate trait for specialization of slice's Ord -trait SliceOrd { - fn compare(&self, other: &[B]) -> Ordering; +trait SliceOrd: Sized { + fn compare(left: &[Self], right: &[Self]) -> Ordering; } -impl SliceOrd for [A] -where - A: Ord, -{ - default fn compare(&self, other: &[A]) -> Ordering { - let l = cmp::min(self.len(), other.len()); +impl SliceOrd for A { + default fn compare(left: &[Self], right: &[Self]) -> Ordering { + let l = cmp::min(left.len(), right.len()); // Slice to the loop iteration range to enable bound check // elimination in the compiler - let lhs = &self[..l]; - let rhs = &other[..l]; + let lhs = &left[..l]; + let rhs = &right[..l]; for i in 0..l { match lhs[i].cmp(&rhs[i]) { @@ -5645,19 +5667,19 @@ where } } - self.len().cmp(&other.len()) + left.len().cmp(&right.len()) } } // memcmp compares a sequence of unsigned bytes lexicographically. // this matches the order we want for [u8], but no others (not even [i8]). -impl SliceOrd for [u8] { +impl SliceOrd for u8 { #[inline] - fn compare(&self, other: &[u8]) -> Ordering { + fn compare(left: &[Self], right: &[Self]) -> Ordering { let order = - unsafe { memcmp(self.as_ptr(), other.as_ptr(), cmp::min(self.len(), other.len())) }; + unsafe { memcmp(left.as_ptr(), right.as_ptr(), cmp::min(left.len(), right.len())) }; if order == 0 { - self.len().cmp(&other.len()) + left.len().cmp(&right.len()) } else if order < 0 { Less } else { diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 5a7cddd4041d..734b3ba7c6bb 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -12,7 +12,7 @@ use self::pattern::{DoubleEndedSearcher, ReverseSearcher, SearchStep, Searcher}; use crate::char; use crate::fmt::{self, Write}; use crate::iter::{Chain, FlatMap, Flatten}; -use crate::iter::{Cloned, Filter, FusedIterator, Map, TrustedLen, TrustedRandomAccess}; +use crate::iter::{Copied, Filter, FusedIterator, Map, TrustedLen, TrustedRandomAccess}; use crate::mem; use crate::ops::Try; use crate::option; @@ -750,7 +750,7 @@ impl<'a> CharIndices<'a> { /// [`str`]: ../../std/primitive.str.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone, Debug)] -pub struct Bytes<'a>(Cloned>); +pub struct Bytes<'a>(Copied>); #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for Bytes<'_> { @@ -2778,7 +2778,7 @@ impl str { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn bytes(&self) -> Bytes<'_> { - Bytes(self.as_bytes().iter().cloned()) + Bytes(self.as_bytes().iter().copied()) } /// Splits a string slice by whitespace. @@ -3895,7 +3895,7 @@ impl str { debug_assert_eq!( start, 0, "The first search step from Searcher \ - must include the first character" + must include the first character" ); // SAFETY: `Searcher` is known to return valid indices. unsafe { Some(self.get_unchecked(len..)) } @@ -3934,7 +3934,7 @@ impl str { end, self.len(), "The first search step from ReverseSearcher \ - must include the last character" + must include the last character" ); // SAFETY: `Searcher` is known to return valid indices. unsafe { Some(self.get_unchecked(..start)) } diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index 8b8dc941534e..e3fc2f54ecaa 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1954,11 +1954,19 @@ fn test_range_inclusive_exhaustion() { assert_eq!(r.next(), None); assert_eq!(r.next(), None); + assert_eq!(*r.start(), 10); + assert_eq!(*r.end(), 10); + assert_ne!(r, 10..=10); + let mut r = 10..=10; assert_eq!(r.next_back(), Some(10)); assert!(r.is_empty()); assert_eq!(r.next_back(), None); + assert_eq!(*r.start(), 10); + assert_eq!(*r.end(), 10); + assert_ne!(r, 10..=10); + let mut r = 10..=12; assert_eq!(r.next(), Some(10)); assert_eq!(r.next(), Some(11)); @@ -2076,6 +2084,9 @@ fn test_range_inclusive_nth() { assert_eq!((10..=15).nth(5), Some(15)); assert_eq!((10..=15).nth(6), None); + let mut exhausted_via_next = 10_u8..=20; + while exhausted_via_next.next().is_some() {} + let mut r = 10_u8..=20; assert_eq!(r.nth(2), Some(12)); assert_eq!(r, 13..=20); @@ -2085,6 +2096,7 @@ fn test_range_inclusive_nth() { assert_eq!(ExactSizeIterator::is_empty(&r), false); assert_eq!(r.nth(10), None); assert_eq!(r.is_empty(), true); + assert_eq!(r, exhausted_via_next); assert_eq!(ExactSizeIterator::is_empty(&r), true); } @@ -2096,6 +2108,9 @@ fn test_range_inclusive_nth_back() { assert_eq!((10..=15).nth_back(6), None); assert_eq!((-120..=80_i8).nth_back(200), Some(-120)); + let mut exhausted_via_next_back = 10_u8..=20; + while exhausted_via_next_back.next_back().is_some() {} + let mut r = 10_u8..=20; assert_eq!(r.nth_back(2), Some(18)); assert_eq!(r, 10..=17); @@ -2105,6 +2120,7 @@ fn test_range_inclusive_nth_back() { assert_eq!(ExactSizeIterator::is_empty(&r), false); assert_eq!(r.nth_back(10), None); assert_eq!(r.is_empty(), true); + assert_eq!(r, exhausted_via_next_back); assert_eq!(ExactSizeIterator::is_empty(&r), true); } diff --git a/src/test/ui/specialization/soundness/partial_eq_range_inclusive.rs b/src/test/ui/specialization/soundness/partial_eq_range_inclusive.rs new file mode 100644 index 000000000000..923dec892e08 --- /dev/null +++ b/src/test/ui/specialization/soundness/partial_eq_range_inclusive.rs @@ -0,0 +1,35 @@ +// run-pass + +use std::cell::RefCell; +use std::cmp::Ordering; + +struct Evil<'a, 'b> { + values: RefCell>, + to_insert: &'b String, +} + +impl<'a, 'b> PartialEq for Evil<'a, 'b> { + fn eq(&self, _other: &Self) -> bool { + true + } +} + +impl<'a> PartialOrd for Evil<'a, 'a> { + fn partial_cmp(&self, _other: &Self) -> Option { + self.values.borrow_mut().push(self.to_insert); + None + } +} + +fn main() { + let e; + let values; + { + let to_insert = String::from("Hello, world!"); + e = Evil { values: RefCell::new(Vec::new()), to_insert: &to_insert }; + let range = &e..=&e; + let _ = range == range; + values = e.values; + } + assert_eq!(*values.borrow(), Vec::<&str>::new()); +} diff --git a/src/test/ui/specialization/soundness/partial_ord_slice.rs b/src/test/ui/specialization/soundness/partial_ord_slice.rs new file mode 100644 index 000000000000..b9e80a48d33d --- /dev/null +++ b/src/test/ui/specialization/soundness/partial_ord_slice.rs @@ -0,0 +1,42 @@ +// Check that we aren't using unsound specialization in slice comparisons. + +// run-pass + +use std::cell::Cell; +use std::cmp::Ordering; + +struct Evil<'a, 'b>(Cell<(&'a [i32], &'b [i32])>); + +impl PartialEq for Evil<'_, '_> { + fn eq(&self, _other: &Self) -> bool { + true + } +} + +impl Eq for Evil<'_, '_> {} + +impl PartialOrd for Evil<'_, '_> { + fn partial_cmp(&self, _other: &Self) -> Option { + Some(Ordering::Equal) + } +} + +impl<'a> Ord for Evil<'a, 'a> { + fn cmp(&self, _other: &Self) -> Ordering { + let (a, b) = self.0.get(); + self.0.set((b, a)); + Ordering::Equal + } +} + +fn main() { + let x = &[1, 2, 3, 4]; + let u = { + let a = Box::new([7, 8, 9, 10]); + let y = [Evil(Cell::new((x, &*a)))]; + let _ = &y[..] <= &y[..]; + let [Evil(c)] = y; + c.get().0 + }; + assert_eq!(u, &[1, 2, 3, 4]); +} From cd5ad993d093f8ee5eedb63ed888a2ae2c35299f Mon Sep 17 00:00:00 2001 From: John VanEnk Date: Fri, 10 Jan 2020 17:16:04 -0800 Subject: [PATCH 02/10] Add a test that demonstrates a segfault when calling into rust with non-c-like-enum. --- .../return-non-c-like-enum/Makefile | 7 ++++ .../return-non-c-like-enum/nonclike.rs | 13 +++++++ .../return-non-c-like-enum/test.c | 35 +++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 src/test/run-make-fulldeps/return-non-c-like-enum/Makefile create mode 100644 src/test/run-make-fulldeps/return-non-c-like-enum/nonclike.rs create mode 100644 src/test/run-make-fulldeps/return-non-c-like-enum/test.c diff --git a/src/test/run-make-fulldeps/return-non-c-like-enum/Makefile b/src/test/run-make-fulldeps/return-non-c-like-enum/Makefile new file mode 100644 index 000000000000..5b5d620efe65 --- /dev/null +++ b/src/test/run-make-fulldeps/return-non-c-like-enum/Makefile @@ -0,0 +1,7 @@ +-include ../tools.mk + +all: + $(RUSTC) --crate-type=staticlib nonclike.rs + $(CC) test.c $(call STATICLIB,nonclike) $(call OUT_EXE,test) \ + $(EXTRACFLAGS) $(EXTRACXXFLAGS) + $(call RUN,test) diff --git a/src/test/run-make-fulldeps/return-non-c-like-enum/nonclike.rs b/src/test/run-make-fulldeps/return-non-c-like-enum/nonclike.rs new file mode 100644 index 000000000000..36f618b05e84 --- /dev/null +++ b/src/test/run-make-fulldeps/return-non-c-like-enum/nonclike.rs @@ -0,0 +1,13 @@ +#![crate_type = "lib"] +#![crate_name = "nonclike"] + +#[repr(C,u8)] +pub enum T { + A(u64), + B, +} + +#[no_mangle] +pub extern "C" fn t_new(a: u64) -> T { + T::A(a) +} diff --git a/src/test/run-make-fulldeps/return-non-c-like-enum/test.c b/src/test/run-make-fulldeps/return-non-c-like-enum/test.c new file mode 100644 index 000000000000..bcc17c0008d9 --- /dev/null +++ b/src/test/run-make-fulldeps/return-non-c-like-enum/test.c @@ -0,0 +1,35 @@ +#include +#include + +/* This is the code generated by cbindgen 0.12.1 for the `enum T` type + * in nonclike.rs . */ +enum T_Tag { + A, + B, +}; +typedef uint8_t T_Tag; + +typedef struct { + uint64_t _0; +} A_Body; + +typedef struct { + T_Tag tag; + union { + A_Body a; + }; +} T; + +/* This symbol is defined by the Rust staticlib built from + * nonclike.rs. */ +extern T t_new(uint64_t v); + +int main(int argc, char *argv[]) { + (void)argc; (void)argv; + + T t = t_new(10); + assert(A == t.tag); + assert(10 == t.a._0); + + return 0; +} From f1b52b34f201456d8a0e9da907e3e5619fa24ac7 Mon Sep 17 00:00:00 2001 From: John VanEnk Date: Fri, 10 Jan 2020 17:42:30 -0800 Subject: [PATCH 03/10] Add a test that demonstrates an incorrect return value when calling into rust with non-c-like-enums. --- .../arguments-non-c-like-enum/Makefile | 7 ++++ .../arguments-non-c-like-enum/nonclike.rs | 18 +++++++++ .../arguments-non-c-like-enum/test.c | 40 +++++++++++++++++++ 3 files changed, 65 insertions(+) create mode 100644 src/test/run-make-fulldeps/arguments-non-c-like-enum/Makefile create mode 100644 src/test/run-make-fulldeps/arguments-non-c-like-enum/nonclike.rs create mode 100644 src/test/run-make-fulldeps/arguments-non-c-like-enum/test.c diff --git a/src/test/run-make-fulldeps/arguments-non-c-like-enum/Makefile b/src/test/run-make-fulldeps/arguments-non-c-like-enum/Makefile new file mode 100644 index 000000000000..5b5d620efe65 --- /dev/null +++ b/src/test/run-make-fulldeps/arguments-non-c-like-enum/Makefile @@ -0,0 +1,7 @@ +-include ../tools.mk + +all: + $(RUSTC) --crate-type=staticlib nonclike.rs + $(CC) test.c $(call STATICLIB,nonclike) $(call OUT_EXE,test) \ + $(EXTRACFLAGS) $(EXTRACXXFLAGS) + $(call RUN,test) diff --git a/src/test/run-make-fulldeps/arguments-non-c-like-enum/nonclike.rs b/src/test/run-make-fulldeps/arguments-non-c-like-enum/nonclike.rs new file mode 100644 index 000000000000..563f907608bd --- /dev/null +++ b/src/test/run-make-fulldeps/arguments-non-c-like-enum/nonclike.rs @@ -0,0 +1,18 @@ +#![crate_type = "lib"] +#![crate_name = "nonclike"] + +#[repr(C,u8)] +pub enum T { + A(u64), + B, +} + +#[no_mangle] +pub extern "C" fn t_add(a: T, b: T) -> u64 { + match (a,b) { + (T::A(a), T::A(b)) => a + b, + (T::A(a), T::B) => a, + (T::B, T::A(b)) => b, + _ => 0, + } +} diff --git a/src/test/run-make-fulldeps/arguments-non-c-like-enum/test.c b/src/test/run-make-fulldeps/arguments-non-c-like-enum/test.c new file mode 100644 index 000000000000..f622471e7d1f --- /dev/null +++ b/src/test/run-make-fulldeps/arguments-non-c-like-enum/test.c @@ -0,0 +1,40 @@ +#include +#include + +#include + +/* This is the code generated by cbindgen 0.12.1 for the `enum T` type + * in nonclike.rs . */ +enum T_Tag { + A, + B, +}; +typedef uint8_t T_Tag; + +typedef struct { + uint64_t _0; +} A_Body; + +typedef struct { + T_Tag tag; + union { + A_Body a; + }; +} T; + +/* This symbol is defined by the Rust staticlib built from + * nonclike.rs. */ +extern uint64_t t_add(T a, T b); + +int main(int argc, char *argv[]) { + (void)argc; (void)argv; + + T x = { .tag = A, .a = { ._0 = 1 } }; + T y = { .tag = A, .a = { ._0 = 10 } }; + + uint64_t r = t_add(x, y); + + assert(11 == r); + + return 0; +} From 26bb0f15e7e97bc93385296c2932193fe6da6300 Mon Sep 17 00:00:00 2001 From: John VanEnk Date: Fri, 10 Jan 2020 17:59:18 -0800 Subject: [PATCH 04/10] Add similar examples that work to each test. --- .../arguments-non-c-like-enum/nonclike.rs | 20 ++++++++++-- .../arguments-non-c-like-enum/test.c | 32 +++++++++++++++++-- .../return-non-c-like-enum/nonclike.rs | 11 +++++++ .../return-non-c-like-enum/test.c | 30 ++++++++++++++++- 4 files changed, 87 insertions(+), 6 deletions(-) diff --git a/src/test/run-make-fulldeps/arguments-non-c-like-enum/nonclike.rs b/src/test/run-make-fulldeps/arguments-non-c-like-enum/nonclike.rs index 563f907608bd..8f75076a30e9 100644 --- a/src/test/run-make-fulldeps/arguments-non-c-like-enum/nonclike.rs +++ b/src/test/run-make-fulldeps/arguments-non-c-like-enum/nonclike.rs @@ -1,7 +1,23 @@ #![crate_type = "lib"] #![crate_name = "nonclike"] -#[repr(C,u8)] +#[repr(C, u8)] +pub enum TT { + AA(u64, u64), + BB, +} + +#[no_mangle] +pub extern "C" fn tt_add(a: TT, b: TT) -> u64 { + match (a, b) { + (TT::AA(a1, b1), TT::AA(a2, b2)) => a1 + a2 + b1 + b2, + (TT::AA(a1, b1), TT::BB) => a1 + b1, + (TT::BB, TT::AA(a1, b1)) => a1 + b1, + _ => 0, + } +} + +#[repr(C, u8)] pub enum T { A(u64), B, @@ -9,7 +25,7 @@ pub enum T { #[no_mangle] pub extern "C" fn t_add(a: T, b: T) -> u64 { - match (a,b) { + match (a, b) { (T::A(a), T::A(b)) => a + b, (T::A(a), T::B) => a, (T::B, T::A(b)) => b, diff --git a/src/test/run-make-fulldeps/arguments-non-c-like-enum/test.c b/src/test/run-make-fulldeps/arguments-non-c-like-enum/test.c index f622471e7d1f..d34babcf3d33 100644 --- a/src/test/run-make-fulldeps/arguments-non-c-like-enum/test.c +++ b/src/test/run-make-fulldeps/arguments-non-c-like-enum/test.c @@ -3,6 +3,26 @@ #include +/* This is the code generated by cbindgen 0.12.1 for the `enum TT` + * type in nonclike.rs . */ +enum TT_Tag { + AA, + BB, +}; +typedef uint8_t TT_Tag; + +typedef struct { + uint64_t _0; + uint64_t _1; +} AA_Body; + +typedef struct { + TT_Tag tag; + union { + AA_Body aa; + }; +} TT; + /* This is the code generated by cbindgen 0.12.1 for the `enum T` type * in nonclike.rs . */ enum T_Tag { @@ -22,18 +42,24 @@ typedef struct { }; } T; -/* This symbol is defined by the Rust staticlib built from +/* These symbols are defined by the Rust staticlib built from * nonclike.rs. */ extern uint64_t t_add(T a, T b); +extern uint64_t tt_add(TT a, TT b); int main(int argc, char *argv[]) { (void)argc; (void)argv; + /* This example works. */ + TT xx = { .tag = AA, .aa = { ._0 = 1, ._1 = 2 } }; + TT yy = { .tag = AA, .aa = { ._0 = 10, ._1 = 20 } }; + uint64_t rr = tt_add(xx, yy); + assert(33 == rr); + + /* This one returns an incorrect result. */ T x = { .tag = A, .a = { ._0 = 1 } }; T y = { .tag = A, .a = { ._0 = 10 } }; - uint64_t r = t_add(x, y); - assert(11 == r); return 0; diff --git a/src/test/run-make-fulldeps/return-non-c-like-enum/nonclike.rs b/src/test/run-make-fulldeps/return-non-c-like-enum/nonclike.rs index 36f618b05e84..700d2df1f381 100644 --- a/src/test/run-make-fulldeps/return-non-c-like-enum/nonclike.rs +++ b/src/test/run-make-fulldeps/return-non-c-like-enum/nonclike.rs @@ -1,6 +1,17 @@ #![crate_type = "lib"] #![crate_name = "nonclike"] +#[repr(C, u8)] +pub enum TT { + AA(u64, u64), + BB, +} + +#[no_mangle] +pub extern "C" fn tt_new(a: u64, b: u64) -> TT { + TT::AA(a, b) +} + #[repr(C,u8)] pub enum T { A(u64), diff --git a/src/test/run-make-fulldeps/return-non-c-like-enum/test.c b/src/test/run-make-fulldeps/return-non-c-like-enum/test.c index bcc17c0008d9..3cbd8e6a20cb 100644 --- a/src/test/run-make-fulldeps/return-non-c-like-enum/test.c +++ b/src/test/run-make-fulldeps/return-non-c-like-enum/test.c @@ -1,6 +1,26 @@ #include #include +/* This is the code generated by cbindgen 0.12.1 for the `enum TT` + * type in nonclike.rs . */ +enum TT_Tag { + AA, + BB, +}; +typedef uint8_t TT_Tag; + +typedef struct { + uint64_t _0; + uint64_t _1; +} AA_Body; + +typedef struct { + TT_Tag tag; + union { + AA_Body aa; + }; +} TT; + /* This is the code generated by cbindgen 0.12.1 for the `enum T` type * in nonclike.rs . */ enum T_Tag { @@ -20,13 +40,21 @@ typedef struct { }; } T; -/* This symbol is defined by the Rust staticlib built from +/* These symbols are defined by the Rust staticlib built from * nonclike.rs. */ +extern TT tt_new(uint64_t a, uint64_t b); extern T t_new(uint64_t v); int main(int argc, char *argv[]) { (void)argc; (void)argv; + /* This example works. */ + TT tt = tt_new(10, 20); + assert(AA == tt.tag); + assert(10 == tt.aa._0); + assert(20 == tt.aa._1); + + /* This one segfaults. */ T t = t_new(10); assert(A == t.tag); assert(10 == t.a._0); From 3b23b9864c07e47247c93d69e7ed8197c4cc9b37 Mon Sep 17 00:00:00 2001 From: John VanEnk Date: Tue, 21 Jan 2020 22:26:13 -0800 Subject: [PATCH 05/10] Two test cases where Rust calls C using enums by value One calls into C functions passing non-c-like enumerations by value. The other calls into C expecting non-C-like enumerations as returns. These test cases are based on the tests provided by @bitwalker on issue #68190. The original tests were provided at: https://github.com/bitwalker/rust_non_c_like_enums_issue/tree/2688d5c672bd4e289085fcdf1c6110e99e7e8ab1 --- .../pass-non-c-like-enum-to-c/Makefile | 6 ++ .../pass-non-c-like-enum-to-c/nonclike.rs | 24 ++++++ .../pass-non-c-like-enum-to-c/test.c | 85 +++++++++++++++++++ .../return-non-c-like-enum-from-c/Makefile | 6 ++ .../return-non-c-like-enum-from-c/nonclike.rs | 34 ++++++++ .../return-non-c-like-enum-from-c/test.c | 61 +++++++++++++ 6 files changed, 216 insertions(+) create mode 100644 src/test/run-make-fulldeps/pass-non-c-like-enum-to-c/Makefile create mode 100644 src/test/run-make-fulldeps/pass-non-c-like-enum-to-c/nonclike.rs create mode 100644 src/test/run-make-fulldeps/pass-non-c-like-enum-to-c/test.c create mode 100644 src/test/run-make-fulldeps/return-non-c-like-enum-from-c/Makefile create mode 100644 src/test/run-make-fulldeps/return-non-c-like-enum-from-c/nonclike.rs create mode 100644 src/test/run-make-fulldeps/return-non-c-like-enum-from-c/test.c diff --git a/src/test/run-make-fulldeps/pass-non-c-like-enum-to-c/Makefile b/src/test/run-make-fulldeps/pass-non-c-like-enum-to-c/Makefile new file mode 100644 index 000000000000..0b793b32aa1f --- /dev/null +++ b/src/test/run-make-fulldeps/pass-non-c-like-enum-to-c/Makefile @@ -0,0 +1,6 @@ +-include ../tools.mk + +all: + $(CC) -c test.c -o $(call STATICLIB,test) $(EXTRACFLAGS) $(EXTRACXXFLAGS) + $(RUSTC) nonclike.rs -L$(TMPDIR) -ltest + $(call RUN,nonclike) diff --git a/src/test/run-make-fulldeps/pass-non-c-like-enum-to-c/nonclike.rs b/src/test/run-make-fulldeps/pass-non-c-like-enum-to-c/nonclike.rs new file mode 100644 index 000000000000..22d6bdcb35bd --- /dev/null +++ b/src/test/run-make-fulldeps/pass-non-c-like-enum-to-c/nonclike.rs @@ -0,0 +1,24 @@ +#![crate_type = "bin"] +#![crate_name = "nonclike"] + +#[repr(C, u8)] +pub enum TT { + AA(u64, u64), + BB, +} + +#[repr(C,u8)] +pub enum T { + A(u64), + B, +} + +extern "C" { + pub fn t_add(a: T, b: T) -> u64; + pub fn tt_add(a: TT, b: TT) -> u64; +} + +fn main() { + assert_eq!(33, unsafe { tt_add(TT::AA(1,2), TT::AA(10,20)) }); + assert_eq!(11, unsafe { t_add(T::A(1), T::A(10)) }); +} diff --git a/src/test/run-make-fulldeps/pass-non-c-like-enum-to-c/test.c b/src/test/run-make-fulldeps/pass-non-c-like-enum-to-c/test.c new file mode 100644 index 000000000000..99511b2530f0 --- /dev/null +++ b/src/test/run-make-fulldeps/pass-non-c-like-enum-to-c/test.c @@ -0,0 +1,85 @@ +#include + +/* This is the code generated by cbindgen 0.12.1 for the `enum TT` + * type in nonclike.rs . */ +enum TT_Tag { + AA, + BB, +}; +typedef uint8_t TT_Tag; + +typedef struct { + uint64_t _0; + uint64_t _1; +} AA_Body; + +typedef struct { + TT_Tag tag; + union { + AA_Body aa; + }; +} TT; + +/* This is the code generated by cbindgen 0.12.1 for the `enum T` type + * in nonclike.rs . */ +enum T_Tag { + A, + B, +}; +typedef uint8_t T_Tag; + +typedef struct { + uint64_t _0; +} A_Body; + +typedef struct { + T_Tag tag; + union { + A_Body a; + }; +} T; + +uint64_t tt_add(TT a, TT b) { + if (a.tag == AA && b.tag == AA) { + return a.aa._0 + a.aa._1 + b.aa._0 + b.aa._1; + } else if (a.tag == AA) { + return a.aa._0 + a.aa._1; + } else if (b.tag == BB) { + return b.aa._0 + b.aa._1; + } else { + return 0; + } +} + +uint64_t t_add(T a, T b) { + if (a.tag == A && b.tag == A) { + return a.a._0 + b.a._0; + } else if (a.tag == AA) { + return a.a._0; + } else if (b.tag == BB) { + return b.a._0; + } else { + return 0; + } +} + +TT tt_new(uint64_t a, uint64_t b) { + TT tt = { + .tag = AA, + .aa = { + ._0 = a, + ._1 = b, + }, + }; + return tt; +} + +T t_new(uint64_t a) { + T t = { + .tag = A, + .a = { + ._0 = a, + }, + }; + return t; +} diff --git a/src/test/run-make-fulldeps/return-non-c-like-enum-from-c/Makefile b/src/test/run-make-fulldeps/return-non-c-like-enum-from-c/Makefile new file mode 100644 index 000000000000..0b793b32aa1f --- /dev/null +++ b/src/test/run-make-fulldeps/return-non-c-like-enum-from-c/Makefile @@ -0,0 +1,6 @@ +-include ../tools.mk + +all: + $(CC) -c test.c -o $(call STATICLIB,test) $(EXTRACFLAGS) $(EXTRACXXFLAGS) + $(RUSTC) nonclike.rs -L$(TMPDIR) -ltest + $(call RUN,nonclike) diff --git a/src/test/run-make-fulldeps/return-non-c-like-enum-from-c/nonclike.rs b/src/test/run-make-fulldeps/return-non-c-like-enum-from-c/nonclike.rs new file mode 100644 index 000000000000..1a2686cacd0b --- /dev/null +++ b/src/test/run-make-fulldeps/return-non-c-like-enum-from-c/nonclike.rs @@ -0,0 +1,34 @@ +#![crate_type = "bin"] +#![crate_name = "nonclike"] + +#[repr(C, u8)] +pub enum TT { + AA(u64, u64), + BB, +} + +#[repr(C,u8)] +pub enum T { + A(u64), + B, +} + +extern "C" { + pub fn t_new(a: u64) -> T; + pub fn tt_new(a: u64, b: u64) -> TT; +} + +fn main() { + if let TT::AA(a, b) = unsafe { tt_new(10, 11) } { + assert_eq!(10, a); + assert_eq!(11, b); + } else { + panic!("expected TT::AA"); + } + + if let T::A(a) = unsafe { t_new(10) } { + assert_eq!(10, a); + } else { + panic!("expected T::A"); + } +} diff --git a/src/test/run-make-fulldeps/return-non-c-like-enum-from-c/test.c b/src/test/run-make-fulldeps/return-non-c-like-enum-from-c/test.c new file mode 100644 index 000000000000..3ad135bab4a1 --- /dev/null +++ b/src/test/run-make-fulldeps/return-non-c-like-enum-from-c/test.c @@ -0,0 +1,61 @@ +#include + +/* This is the code generated by cbindgen 0.12.1 for the `enum TT` + * type in nonclike.rs . */ +enum TT_Tag { + AA, + BB, +}; +typedef uint8_t TT_Tag; + +typedef struct { + uint64_t _0; + uint64_t _1; +} AA_Body; + +typedef struct { + TT_Tag tag; + union { + AA_Body aa; + }; +} TT; + +/* This is the code generated by cbindgen 0.12.1 for the `enum T` type + * in nonclike.rs . */ +enum T_Tag { + A, + B, +}; +typedef uint8_t T_Tag; + +typedef struct { + uint64_t _0; +} A_Body; + +typedef struct { + T_Tag tag; + union { + A_Body a; + }; +} T; + +TT tt_new(uint64_t a, uint64_t b) { + TT tt = { + .tag = AA, + .aa = { + ._0 = a, + ._1 = b, + }, + }; + return tt; +} + +T t_new(uint64_t a) { + T t = { + .tag = A, + .a = { + ._0 = a, + }, + }; + return t; +} From 1d28952631b37f422a6c0bd9660c20b0b40f5bf9 Mon Sep 17 00:00:00 2001 From: John VanEnk Date: Wed, 22 Jan 2020 13:07:03 -0800 Subject: [PATCH 06/10] Add non-C-like enumeration tests on Rust->C calls to the abi-sysv64-arg-passing test. --- src/test/auxiliary/rust_test_helpers.c | 84 +++++++++++++++++++++++ src/test/ui/abi/abi-sysv64-arg-passing.rs | 73 ++++++++++++++++++++ 2 files changed, 157 insertions(+) diff --git a/src/test/auxiliary/rust_test_helpers.c b/src/test/auxiliary/rust_test_helpers.c index b95b0ca1a89c..a5299638e52f 100644 --- a/src/test/auxiliary/rust_test_helpers.c +++ b/src/test/auxiliary/rust_test_helpers.c @@ -300,3 +300,87 @@ __int128 sub(__int128 a, __int128 b) { } #endif + +#define OPTION_TAG_NONE (0) +#define OPTION_TAG_SOME (1) + +struct U8TaggedEnumOptionU64 { + uint8_t tag; + union { + uint64_t some; + }; +}; + +struct U8TaggedEnumOptionU64 +rust_dbg_new_some_u64(uint64_t some) { + struct U8TaggedEnumOptionU64 r = { + .tag = OPTION_TAG_SOME, + .some = some, + }; + return r; +} + +struct U8TaggedEnumOptionU64 +rust_dbg_new_none_u64(void) { + struct U8TaggedEnumOptionU64 r = { + .tag = OPTION_TAG_NONE, + }; + return r; +} + +int32_t +rust_dbg_unpack_option_u64(struct U8TaggedEnumOptionU64 o, uint64_t *into) { + assert(into); + switch (o.tag) { + case OPTION_TAG_SOME: + *into = o.some; + return 1; + case OPTION_TAG_NONE: + return 0; + default: + assert(0 && "unexpected tag"); + } +} + +struct U8TaggedEnumOptionU64U64 { + uint8_t tag; + union { + struct { + uint64_t a; + uint64_t b; + } some; + }; +}; + +struct U8TaggedEnumOptionU64U64 +rust_dbg_new_some_u64u64(uint64_t a, uint64_t b) { + struct U8TaggedEnumOptionU64U64 r = { + .tag = OPTION_TAG_SOME, + .some = { .a = a, .b = b }, + }; + return r; +} + +struct U8TaggedEnumOptionU64U64 +rust_dbg_new_none_u64u64(void) { + struct U8TaggedEnumOptionU64U64 r = { + .tag = OPTION_TAG_NONE, + }; + return r; +} + +int32_t +rust_dbg_unpack_option_u64u64(struct U8TaggedEnumOptionU64U64 o, uint64_t *a, uint64_t *b) { + assert(a); + assert(b); + switch (o.tag) { + case OPTION_TAG_SOME: + *a = o.some.a; + *b = o.some.b; + return 1; + case OPTION_TAG_NONE: + return 0; + default: + assert(0 && "unexpected tag"); + } +} diff --git a/src/test/ui/abi/abi-sysv64-arg-passing.rs b/src/test/ui/abi/abi-sysv64-arg-passing.rs index d40006eb9b68..adb62ab698eb 100644 --- a/src/test/ui/abi/abi-sysv64-arg-passing.rs +++ b/src/test/ui/abi/abi-sysv64-arg-passing.rs @@ -92,6 +92,18 @@ mod tests { #[derive(Copy, Clone)] pub struct Floats { a: f64, b: u8, c: f64 } + #[repr(C, u8)] + pub enum U8TaggedEnumOptionU64U64 { + None, + Some(u64,u64), + } + + #[repr(C, u8)] + pub enum U8TaggedEnumOptionU64 { + None, + Some(u64), + } + #[link(name = "rust_test_helpers", kind = "static")] extern "sysv64" { pub fn rust_int8_to_int32(_: i8) -> i32; @@ -125,6 +137,12 @@ mod tests { ) -> f32; pub fn rust_dbg_abi_1(q: Quad) -> Quad; pub fn rust_dbg_abi_2(f: Floats) -> Floats; + pub fn rust_dbg_new_some_u64u64(a: u64, b: u64) -> U8TaggedEnumOptionU64U64; + pub fn rust_dbg_new_none_u64u64() -> U8TaggedEnumOptionU64U64; + pub fn rust_dbg_unpack_option_u64u64(o: U8TaggedEnumOptionU64U64, a: *mut u64, b: *mut u64) -> i32; + pub fn rust_dbg_new_some_u64(some: u64) -> U8TaggedEnumOptionU64; + pub fn rust_dbg_new_none_u64() -> U8TaggedEnumOptionU64; + pub fn rust_dbg_unpack_option_u64(o: U8TaggedEnumOptionU64, v: *mut u64) -> i32; } pub fn cabi_int_widening() { @@ -336,6 +354,59 @@ mod tests { test1(); test2(); } + + pub fn enum_passing_and_return_pair() { + let some_u64u64 = unsafe { rust_dbg_new_some_u64u64(10, 20) }; + if let U8TaggedEnumOptionU64U64::Some(a, b) = some_u64u64 { + assert_eq!(10, a); + assert_eq!(20, b); + } else { + panic!("unexpected none"); + } + + let none_u64u64 = unsafe { rust_dbg_new_none_u64u64() }; + if let U8TaggedEnumOptionU64U64::Some(_,_) = none_u64u64 { + panic!("unexpected some"); + } + + let mut a: u64 = 0; + let mut b: u64 = 0; + let r = unsafe { rust_dbg_unpack_option_u64u64(some_u64u64, &mut a as *mut _, &mut b as *mut _) }; + assert_eq!(1, r); + assert_eq!(10, a); + assert_eq!(20, b); + + let mut a: u64 = 0; + let mut b: u64 = 0; + let r = unsafe { rust_dbg_unpack_option_u64u64(none_u64u64, &mut a as *mut _, &mut b as *mut _) }; + assert_eq!(0, r); + assert_eq!(0, a); + assert_eq!(0, b); + } + + pub fn enum_passing_and_return() { + let some_u64 = unsafe { rust_dbg_new_some_u64(10) }; + if let U8TaggedEnumOptionU64::Some(v) = some_u64 { + assert_eq!(10, v); + } else { + panic!("unexpected none"); + } + + let none_u64 = unsafe { rust_dbg_new_none_u64() }; + if let U8TaggedEnumOptionU64::Some(_) = none_u64 { + panic!("unexpected some"); + } + + let mut target: u64 = 0; + let r = unsafe { rust_dbg_unpack_option_u64(some_u64, &mut target as *mut _) }; + assert_eq!(1, r); + assert_eq!(10, target); + + let mut target: u64 = 0; + let r = unsafe { rust_dbg_unpack_option_u64(none_u64, &mut target as *mut _) }; + assert_eq!(0, r); + assert_eq!(0, target); + } } #[cfg(target_arch = "x86_64")] @@ -359,6 +430,8 @@ fn main() { issue_28676(); issue_62350(); struct_return(); + enum_passing_and_return_pair(); + enum_passing_and_return(); } #[cfg(not(target_arch = "x86_64"))] From 8f81593d6c9b731973c0f8e57548948101dda928 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 22 Jan 2020 02:52:14 +0200 Subject: [PATCH 07/10] 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 2dd41a0d80f9..c8bac5aebc63 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 eb9364091dc0..59ec87e3c9e0 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 af82f9e31837..748fd2b6579f 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 2db3954b481e..93c4e97de10b 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 8bcb02b87647..c80f8316feb7 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 852ead8c522c..9aab64ef272b 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 a7884849b824..e776a8b3fe4a 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 1c70624e4a22..7eecd99dc016 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 0d4426063518..cd3fb5ca5ea4 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 4b429412aebf..ec2c9b70224b 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 be04ba3e7f6c..ec2b08bf02d6 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 68b218249eb9..1a662ba44677 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 1bb31aaf7b7b..43b1588266bb 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; From da33935c260bf8859d20b83dec40be7fc3d82310 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 22 Jan 2020 02:52:54 +0200 Subject: [PATCH 08/10] rustc_target: treat enum variants like union members, in call ABIs. --- src/librustc_target/abi/call/mod.rs | 28 +++++++++++++++++++++++++- src/librustc_target/abi/call/x86_64.rs | 26 +++++++++++++++--------- 2 files changed, 44 insertions(+), 10 deletions(-) diff --git a/src/librustc_target/abi/call/mod.rs b/src/librustc_target/abi/call/mod.rs index 748fd2b6579f..e3cbf176c350 100644 --- a/src/librustc_target/abi/call/mod.rs +++ b/src/librustc_target/abi/call/mod.rs @@ -308,7 +308,7 @@ impl<'a, Ty> TyLayout<'a, Ty> { Abi::ScalarPair(..) | Abi::Aggregate { .. } => { // Helper for computing `homogenous_aggregate`, allowing a custom - // starting offset (TODO(eddyb): use this to handle variants). + // starting offset (used below for handling variants). let from_fields_at = |layout: Self, start: Size| @@ -354,6 +354,32 @@ impl<'a, Ty> TyLayout<'a, Ty> { let (mut result, mut total) = from_fields_at(*self, Size::ZERO)?; + match &self.variants { + abi::Variants::Single { .. } => {} + abi::Variants::Multiple { variants, .. } => { + // Treat enum variants like union members. + // HACK(eddyb) pretend the `enum` field (discriminant) + // is at the start of every variant (otherwise the gap + // at the start of all variants would disqualify them). + // + // NB: for all tagged `enum`s (which include all non-C-like + // `enum`s with defined FFI representation), this will + // match the homogenous computation on the equivalent + // `struct { tag; union { variant1; ... } }` and/or + // `union { struct { tag; variant1; } ... }` + // (the offsets of variant fields should be identical + // between the two for either to be a homogenous aggregate). + let variant_start = total; + for variant_idx in variants.indices() { + let (variant_result, variant_total) = + from_fields_at(self.for_variant(cx, variant_idx), variant_start)?; + + result = result.merge(variant_result)?; + total = total.max(variant_total); + } + } + } + // There needs to be no padding. if total != self.size { Err(Heterogeneous) diff --git a/src/librustc_target/abi/call/x86_64.rs b/src/librustc_target/abi/call/x86_64.rs index a547d7262e23..4c192c46786b 100644 --- a/src/librustc_target/abi/call/x86_64.rs +++ b/src/librustc_target/abi/call/x86_64.rs @@ -56,16 +56,24 @@ where Abi::Vector { .. } => Class::Sse, - Abi::ScalarPair(..) | Abi::Aggregate { .. } => match layout.variants { - abi::Variants::Single { .. } => { - for i in 0..layout.fields.count() { - let field_off = off + layout.fields.offset(i); - classify(cx, layout.field(cx, i), cls, field_off)?; - } - return Ok(()); + Abi::ScalarPair(..) | Abi::Aggregate { .. } => { + for i in 0..layout.fields.count() { + let field_off = off + layout.fields.offset(i); + classify(cx, layout.field(cx, i), cls, field_off)?; } - abi::Variants::Multiple { .. } => return Err(Memory), - }, + + match &layout.variants { + abi::Variants::Single { .. } => {} + abi::Variants::Multiple { variants, .. } => { + // Treat enum variants like union members. + for variant_idx in variants.indices() { + classify(cx, layout.for_variant(cx, variant_idx), cls, off)?; + } + } + } + + return Ok(()); + } }; // Fill in `cls` for scalars (Int/Sse) and vectors (Sse). From d69b3b16e500ea2116d41bc717cb8026a5873827 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sat, 8 Feb 2020 06:50:41 +0200 Subject: [PATCH 09/10] test: address comments and pacify the merciless tidy. --- src/test/auxiliary/rust_test_helpers.c | 6 +++--- .../arguments-non-c-like-enum/nonclike.rs | 3 --- .../arguments-non-c-like-enum/test.c | 2 +- .../pass-non-c-like-enum-to-c/nonclike.rs | 3 --- .../return-non-c-like-enum-from-c/nonclike.rs | 3 --- .../return-non-c-like-enum/nonclike.rs | 3 --- .../return-non-c-like-enum/test.c | 2 +- src/test/ui/abi/abi-sysv64-arg-passing.rs | 14 +++++++++++--- 8 files changed, 16 insertions(+), 20 deletions(-) diff --git a/src/test/auxiliary/rust_test_helpers.c b/src/test/auxiliary/rust_test_helpers.c index a5299638e52f..c1fe8b7743a8 100644 --- a/src/test/auxiliary/rust_test_helpers.c +++ b/src/test/auxiliary/rust_test_helpers.c @@ -346,9 +346,9 @@ struct U8TaggedEnumOptionU64U64 { uint8_t tag; union { struct { - uint64_t a; - uint64_t b; - } some; + uint64_t a; + uint64_t b; + } some; }; }; diff --git a/src/test/run-make-fulldeps/arguments-non-c-like-enum/nonclike.rs b/src/test/run-make-fulldeps/arguments-non-c-like-enum/nonclike.rs index 8f75076a30e9..57c2c6127ed9 100644 --- a/src/test/run-make-fulldeps/arguments-non-c-like-enum/nonclike.rs +++ b/src/test/run-make-fulldeps/arguments-non-c-like-enum/nonclike.rs @@ -1,6 +1,3 @@ -#![crate_type = "lib"] -#![crate_name = "nonclike"] - #[repr(C, u8)] pub enum TT { AA(u64, u64), diff --git a/src/test/run-make-fulldeps/arguments-non-c-like-enum/test.c b/src/test/run-make-fulldeps/arguments-non-c-like-enum/test.c index d34babcf3d33..0a1621e49f2e 100644 --- a/src/test/run-make-fulldeps/arguments-non-c-like-enum/test.c +++ b/src/test/run-make-fulldeps/arguments-non-c-like-enum/test.c @@ -56,7 +56,7 @@ int main(int argc, char *argv[]) { uint64_t rr = tt_add(xx, yy); assert(33 == rr); - /* This one returns an incorrect result. */ + /* This one used to return an incorrect result (see issue #68190). */ T x = { .tag = A, .a = { ._0 = 1 } }; T y = { .tag = A, .a = { ._0 = 10 } }; uint64_t r = t_add(x, y); diff --git a/src/test/run-make-fulldeps/pass-non-c-like-enum-to-c/nonclike.rs b/src/test/run-make-fulldeps/pass-non-c-like-enum-to-c/nonclike.rs index 22d6bdcb35bd..517286a868d8 100644 --- a/src/test/run-make-fulldeps/pass-non-c-like-enum-to-c/nonclike.rs +++ b/src/test/run-make-fulldeps/pass-non-c-like-enum-to-c/nonclike.rs @@ -1,6 +1,3 @@ -#![crate_type = "bin"] -#![crate_name = "nonclike"] - #[repr(C, u8)] pub enum TT { AA(u64, u64), diff --git a/src/test/run-make-fulldeps/return-non-c-like-enum-from-c/nonclike.rs b/src/test/run-make-fulldeps/return-non-c-like-enum-from-c/nonclike.rs index 1a2686cacd0b..ea22a2a56e09 100644 --- a/src/test/run-make-fulldeps/return-non-c-like-enum-from-c/nonclike.rs +++ b/src/test/run-make-fulldeps/return-non-c-like-enum-from-c/nonclike.rs @@ -1,6 +1,3 @@ -#![crate_type = "bin"] -#![crate_name = "nonclike"] - #[repr(C, u8)] pub enum TT { AA(u64, u64), diff --git a/src/test/run-make-fulldeps/return-non-c-like-enum/nonclike.rs b/src/test/run-make-fulldeps/return-non-c-like-enum/nonclike.rs index 700d2df1f381..de529cf641ab 100644 --- a/src/test/run-make-fulldeps/return-non-c-like-enum/nonclike.rs +++ b/src/test/run-make-fulldeps/return-non-c-like-enum/nonclike.rs @@ -1,6 +1,3 @@ -#![crate_type = "lib"] -#![crate_name = "nonclike"] - #[repr(C, u8)] pub enum TT { AA(u64, u64), diff --git a/src/test/run-make-fulldeps/return-non-c-like-enum/test.c b/src/test/run-make-fulldeps/return-non-c-like-enum/test.c index 3cbd8e6a20cb..afadd3c10c5c 100644 --- a/src/test/run-make-fulldeps/return-non-c-like-enum/test.c +++ b/src/test/run-make-fulldeps/return-non-c-like-enum/test.c @@ -54,7 +54,7 @@ int main(int argc, char *argv[]) { assert(10 == tt.aa._0); assert(20 == tt.aa._1); - /* This one segfaults. */ + /* This one used to segfault (see issue #68190). */ T t = t_new(10); assert(A == t.tag); assert(10 == t.a._0); diff --git a/src/test/ui/abi/abi-sysv64-arg-passing.rs b/src/test/ui/abi/abi-sysv64-arg-passing.rs index adb62ab698eb..c87353b93a7c 100644 --- a/src/test/ui/abi/abi-sysv64-arg-passing.rs +++ b/src/test/ui/abi/abi-sysv64-arg-passing.rs @@ -139,7 +139,11 @@ mod tests { pub fn rust_dbg_abi_2(f: Floats) -> Floats; pub fn rust_dbg_new_some_u64u64(a: u64, b: u64) -> U8TaggedEnumOptionU64U64; pub fn rust_dbg_new_none_u64u64() -> U8TaggedEnumOptionU64U64; - pub fn rust_dbg_unpack_option_u64u64(o: U8TaggedEnumOptionU64U64, a: *mut u64, b: *mut u64) -> i32; + pub fn rust_dbg_unpack_option_u64u64( + o: U8TaggedEnumOptionU64U64, + a: *mut u64, + b: *mut u64, + ) -> i32; pub fn rust_dbg_new_some_u64(some: u64) -> U8TaggedEnumOptionU64; pub fn rust_dbg_new_none_u64() -> U8TaggedEnumOptionU64; pub fn rust_dbg_unpack_option_u64(o: U8TaggedEnumOptionU64, v: *mut u64) -> i32; @@ -371,14 +375,18 @@ mod tests { let mut a: u64 = 0; let mut b: u64 = 0; - let r = unsafe { rust_dbg_unpack_option_u64u64(some_u64u64, &mut a as *mut _, &mut b as *mut _) }; + let r = unsafe { + rust_dbg_unpack_option_u64u64(some_u64u64, &mut a as *mut _, &mut b as *mut _) + }; assert_eq!(1, r); assert_eq!(10, a); assert_eq!(20, b); let mut a: u64 = 0; let mut b: u64 = 0; - let r = unsafe { rust_dbg_unpack_option_u64u64(none_u64u64, &mut a as *mut _, &mut b as *mut _) }; + let r = unsafe { + rust_dbg_unpack_option_u64u64(none_u64u64, &mut a as *mut _, &mut b as *mut _) + }; assert_eq!(0, r); assert_eq!(0, a); assert_eq!(0, b); From d20e4aa8e3d7b087b322be18df19811d9bca69f2 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sat, 8 Feb 2020 13:40:50 +0200 Subject: [PATCH 10/10] test: use `all: $(call NATIVE_STATICLIB,test)` to build a C lib. --- src/test/run-make-fulldeps/pass-non-c-like-enum-to-c/Makefile | 3 +-- .../run-make-fulldeps/return-non-c-like-enum-from-c/Makefile | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/test/run-make-fulldeps/pass-non-c-like-enum-to-c/Makefile b/src/test/run-make-fulldeps/pass-non-c-like-enum-to-c/Makefile index 0b793b32aa1f..f3d9357865c1 100644 --- a/src/test/run-make-fulldeps/pass-non-c-like-enum-to-c/Makefile +++ b/src/test/run-make-fulldeps/pass-non-c-like-enum-to-c/Makefile @@ -1,6 +1,5 @@ -include ../tools.mk -all: - $(CC) -c test.c -o $(call STATICLIB,test) $(EXTRACFLAGS) $(EXTRACXXFLAGS) +all: $(call NATIVE_STATICLIB,test) $(RUSTC) nonclike.rs -L$(TMPDIR) -ltest $(call RUN,nonclike) diff --git a/src/test/run-make-fulldeps/return-non-c-like-enum-from-c/Makefile b/src/test/run-make-fulldeps/return-non-c-like-enum-from-c/Makefile index 0b793b32aa1f..f3d9357865c1 100644 --- a/src/test/run-make-fulldeps/return-non-c-like-enum-from-c/Makefile +++ b/src/test/run-make-fulldeps/return-non-c-like-enum-from-c/Makefile @@ -1,6 +1,5 @@ -include ../tools.mk -all: - $(CC) -c test.c -o $(call STATICLIB,test) $(EXTRACFLAGS) $(EXTRACXXFLAGS) +all: $(call NATIVE_STATICLIB,test) $(RUSTC) nonclike.rs -L$(TMPDIR) -ltest $(call RUN,nonclike)