Merge branch 'master' of https://github.com/jwhite927/rust into E0637

This commit is contained in:
Josh White 2020-02-08 16:30:40 -05:00
commit d705ad28a0
35 changed files with 884 additions and 152 deletions

View file

@ -385,12 +385,14 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
}
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<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> {
}
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
}

View file

@ -343,38 +343,21 @@ pub struct RangeInclusive<Idx> {
pub(crate) is_empty: Option<bool>,
// 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<Self>) -> bool;
}
impl<T> RangeInclusiveEquality for T {
#[inline]
default fn canonicalized_is_empty(range: &RangeInclusive<Self>) -> bool {
range.is_empty.unwrap_or_default()
}
}
impl<T: PartialOrd> RangeInclusiveEquality for T {
#[inline]
fn canonicalized_is_empty(range: &RangeInclusive<Self>) -> bool {
range.is_empty()
}
}
#[stable(feature = "inclusive_range", since = "1.26.0")]
impl<Idx: PartialEq> PartialEq for RangeInclusive<Idx> {
#[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<Idx: Hash> Hash for RangeInclusive<Idx> {
fn hash<H: Hasher>(&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<Idx: fmt::Debug> fmt::Debug for RangeInclusive<Idx> {
}
}
impl<Idx: PartialEq<Idx>> RangeInclusive<Idx> {
// 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<Idx: PartialOrd<Idx>> RangeInclusive<Idx> {
/// Returns `true` if `item` is contained in the range.
///

View file

@ -5584,21 +5584,18 @@ where
#[doc(hidden)]
// intermediate trait for specialization of slice's PartialOrd
trait SlicePartialOrd<B> {
fn partial_compare(&self, other: &[B]) -> Option<Ordering>;
trait SlicePartialOrd: Sized {
fn partial_compare(left: &[Self], right: &[Self]) -> Option<Ordering>;
}
impl<A> SlicePartialOrd<A> for [A]
where
A: PartialOrd,
{
default fn partial_compare(&self, other: &[A]) -> Option<Ordering> {
let l = cmp::min(self.len(), other.len());
impl<A: PartialOrd> SlicePartialOrd for A {
default fn partial_compare(left: &[A], right: &[A]) -> Option<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].partial_cmp(&rhs[i]) {
@ -5607,36 +5604,61 @@ where
}
}
self.len().partial_cmp(&other.len())
left.len().partial_cmp(&right.len())
}
}
impl<A> SlicePartialOrd<A> for [A]
// This is the impl that we would like to have. Unfortunately it's not sound.
// See `partial_ord_slice.rs`.
/*
impl<A> SlicePartialOrd for A
where
A: Ord,
{
default fn partial_compare(&self, other: &[A]) -> Option<Ordering> {
Some(SliceOrd::compare(self, other))
default fn partial_compare(left: &[A], right: &[A]) -> Option<Ordering> {
Some(SliceOrd::compare(left, right))
}
}
*/
impl<A: AlwaysApplicableOrd> SlicePartialOrd for A {
fn partial_compare(left: &[A], right: &[A]) -> Option<Ordering> {
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<T>,
}
#[doc(hidden)]
// intermediate trait for specialization of slice's Ord
trait SliceOrd<B> {
fn compare(&self, other: &[B]) -> Ordering;
trait SliceOrd: Sized {
fn compare(left: &[Self], right: &[Self]) -> Ordering;
}
impl<A> SliceOrd<A> for [A]
where
A: Ord,
{
default fn compare(&self, other: &[A]) -> Ordering {
let l = cmp::min(self.len(), other.len());
impl<A: Ord> 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<u8> 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 {

View file

@ -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<slice::Iter<'a, u8>>);
pub struct Bytes<'a>(Copied<slice::Iter<'a, u8>>);
#[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)) }

View file

@ -1956,11 +1956,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));
@ -2078,6 +2086,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);
@ -2087,6 +2098,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);
}
@ -2098,6 +2110,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);
@ -2107,6 +2122,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);
}

View file

@ -6,7 +6,7 @@ where
Ty: TyLayoutMethods<'a, C> + Copy,
C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + 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.

View file

@ -7,7 +7,7 @@ where
Ty: TyLayoutMethods<'a, C> + Copy,
C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + 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.

View file

@ -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<Reg> {
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<HomogeneousAggregate, Heterogeneous> {
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<C>(&self, cx: &C) -> HomogeneousAggregate
pub fn homogeneous_aggregate<C>(&self, cx: &C) -> Result<HomogeneousAggregate, Heterogeneous>
where
Ty: TyLayoutMethods<'a, C> + Copy,
C: LayoutOf<Ty = Ty, TyLayout = Self>,
{
match self.abi {
Abi::Uninhabited => HomogeneousAggregate::Heterogeneous,
Abi::Uninhabited => Err(Heterogeneous),
// The primitive for this algorithm.
Abi::Scalar(ref scalar) => {
@ -274,80 +295,104 @@ 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 (used below for handling 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)?;
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 {
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)
}
}
}

View file

@ -22,7 +22,7 @@ where
Ty: TyLayoutMethods<'a, C> + Copy,
C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + 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)

View file

@ -8,7 +8,7 @@ where
Ty: TyLayoutMethods<'a, C> + Copy,
C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + 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;

View file

@ -7,7 +7,7 @@ where
C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + 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 });

View file

@ -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;

View file

@ -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).

View file

@ -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");
}
}

View file

@ -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)

View file

@ -0,0 +1,31 @@
#[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,
}
#[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,
}
}

View file

@ -0,0 +1,66 @@
#include <stdint.h>
#include <assert.h>
#include <stdio.h>
/* 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;
/* 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 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);
assert(11 == r);
return 0;
}

View file

@ -0,0 +1,5 @@
-include ../tools.mk
all: $(call NATIVE_STATICLIB,test)
$(RUSTC) nonclike.rs -L$(TMPDIR) -ltest
$(call RUN,nonclike)

View file

@ -0,0 +1,21 @@
#[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)) });
}

View file

@ -0,0 +1,85 @@
#include <stdint.h>
/* 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;
}

View file

@ -0,0 +1,5 @@
-include ../tools.mk
all: $(call NATIVE_STATICLIB,test)
$(RUSTC) nonclike.rs -L$(TMPDIR) -ltest
$(call RUN,nonclike)

View file

@ -0,0 +1,31 @@
#[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");
}
}

View file

@ -0,0 +1,61 @@
#include <stdint.h>
/* 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;
}

View file

@ -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)

View file

@ -0,0 +1,21 @@
#[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),
B,
}
#[no_mangle]
pub extern "C" fn t_new(a: u64) -> T {
T::A(a)
}

View file

@ -0,0 +1,63 @@
#include <stdint.h>
#include <assert.h>
/* 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;
/* 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 used to segfault (see issue #68190). */
T t = t_new(10);
assert(A == t.tag);
assert(10 == t.a._0);
return 0;
}

View file

@ -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,16 @@ 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 +358,63 @@ 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 +438,8 @@ fn main() {
issue_28676();
issue_62350();
struct_return();
enum_passing_and_return_pair();
enum_passing_and_return();
}
#[cfg(not(target_arch = "x86_64"))]

View file

@ -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() { }

View file

@ -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;

View file

@ -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() { }

View file

@ -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;

View file

@ -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() { }

View file

@ -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;

View file

@ -0,0 +1,35 @@
// run-pass
use std::cell::RefCell;
use std::cmp::Ordering;
struct Evil<'a, 'b> {
values: RefCell<Vec<&'a str>>,
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<Ordering> {
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());
}

View file

@ -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<Ordering> {
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]);
}