Auto merge of #70747 - Centril:rollup-2vx9bve, r=Centril
Rollup of 9 pull requests Successful merges: - #69860 (Use associated numeric consts in documentation) - #70576 (Update the description of the ticket to point at RFC 1721) - #70597 (Fix double-free and undefined behaviour in libstd::syn::unix::Thread::new) - #70640 (Hide `task_context` when lowering body) - #70641 (Remove duplicated code in trait selection) - #70707 (Remove unused graphviz emitter) - #70720 (Place TLS initializers with relocations in .tdata) - #70735 (Clean up E0502 explanation) - #70741 (Add test for #59023) Failed merges: r? @ghost
This commit is contained in:
commit
74bd074eef
@ -432,7 +432,7 @@ pub fn into_vec(self: Box<Self>) -> Vec<T> {
|
||||
///
|
||||
/// ```should_panic
|
||||
/// // this will panic at runtime
|
||||
/// b"0123456789abcdef".repeat(usize::max_value());
|
||||
/// b"0123456789abcdef".repeat(usize::MAX);
|
||||
/// ```
|
||||
#[stable(feature = "repeat_generic_slice", since = "1.40.0")]
|
||||
pub fn repeat(&self, n: usize) -> Vec<T>
|
||||
|
@ -499,7 +499,7 @@ pub fn into_string(self: Box<str>) -> String {
|
||||
///
|
||||
/// ```should_panic
|
||||
/// // this will panic at runtime
|
||||
/// "0123456789abcdef".repeat(usize::max_value());
|
||||
/// "0123456789abcdef".repeat(usize::MAX);
|
||||
/// ```
|
||||
#[stable(feature = "repeat_str", since = "1.16.0")]
|
||||
pub fn repeat(&self, n: usize) -> String {
|
||||
|
@ -817,7 +817,7 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
|
||||
/// When comparison is impossible:
|
||||
///
|
||||
/// ```
|
||||
/// let result = std::f64::NAN.partial_cmp(&1.0);
|
||||
/// let result = f64::NAN.partial_cmp(&1.0);
|
||||
/// assert_eq!(result, None);
|
||||
/// ```
|
||||
#[must_use]
|
||||
|
@ -852,7 +852,7 @@ pub trait LowerHex {
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// let l = Length(i32::max_value());
|
||||
/// let l = Length(i32::MAX);
|
||||
///
|
||||
/// assert_eq!(format!("l as hex is: {:X}", l), "l as hex is: 7FFFFFFF");
|
||||
///
|
||||
|
@ -43,7 +43,7 @@
|
||||
///
|
||||
/// assert_eq!(div_1(7, 0), 7);
|
||||
/// assert_eq!(div_1(9, 1), 4);
|
||||
/// assert_eq!(div_1(11, std::u32::MAX), 0);
|
||||
/// assert_eq!(div_1(11, u32::MAX), 0);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "unreachable", since = "1.27.0")]
|
||||
|
@ -1739,11 +1739,11 @@
|
||||
pub fn mul_with_overflow<T: Copy>(x: T, y: T) -> (T, bool);
|
||||
|
||||
/// Performs an exact division, resulting in undefined behavior where
|
||||
/// `x % y != 0` or `y == 0` or `x == T::min_value() && y == -1`
|
||||
/// `x % y != 0` or `y == 0` or `x == T::MIN && y == -1`
|
||||
pub fn exact_div<T: Copy>(x: T, y: T) -> T;
|
||||
|
||||
/// Performs an unchecked division, resulting in undefined behavior
|
||||
/// where y = 0 or x = `T::min_value()` and y = -1
|
||||
/// where y = 0 or x = `T::MIN` and y = -1
|
||||
///
|
||||
/// The stabilized versions of this intrinsic are available on the integer
|
||||
/// primitives via the `checked_div` method. For example,
|
||||
@ -1751,7 +1751,7 @@
|
||||
#[rustc_const_unstable(feature = "const_int_unchecked_arith", issue = "none")]
|
||||
pub fn unchecked_div<T: Copy>(x: T, y: T) -> T;
|
||||
/// Returns the remainder of an unchecked division, resulting in
|
||||
/// undefined behavior where y = 0 or x = `T::min_value()` and y = -1
|
||||
/// undefined behavior where y = 0 or x = `T::MIN` and y = -1
|
||||
///
|
||||
/// The stabilized versions of this intrinsic are available on the integer
|
||||
/// primitives via the `checked_rem` method. For example,
|
||||
@ -1777,17 +1777,17 @@
|
||||
pub fn unchecked_shr<T: Copy>(x: T, y: T) -> T;
|
||||
|
||||
/// Returns the result of an unchecked addition, resulting in
|
||||
/// undefined behavior when `x + y > T::max_value()` or `x + y < T::min_value()`.
|
||||
/// undefined behavior when `x + y > T::MAX` or `x + y < T::MIN`.
|
||||
#[rustc_const_unstable(feature = "const_int_unchecked_arith", issue = "none")]
|
||||
pub fn unchecked_add<T: Copy>(x: T, y: T) -> T;
|
||||
|
||||
/// Returns the result of an unchecked subtraction, resulting in
|
||||
/// undefined behavior when `x - y > T::max_value()` or `x - y < T::min_value()`.
|
||||
/// undefined behavior when `x - y > T::MAX` or `x - y < T::MIN`.
|
||||
#[rustc_const_unstable(feature = "const_int_unchecked_arith", issue = "none")]
|
||||
pub fn unchecked_sub<T: Copy>(x: T, y: T) -> T;
|
||||
|
||||
/// Returns the result of an unchecked multiplication, resulting in
|
||||
/// undefined behavior when `x * y > T::max_value()` or `x * y < T::min_value()`.
|
||||
/// undefined behavior when `x * y > T::MAX` or `x * y < T::MIN`.
|
||||
#[rustc_const_unstable(feature = "const_int_unchecked_arith", issue = "none")]
|
||||
pub fn unchecked_mul<T: Copy>(x: T, y: T) -> T;
|
||||
|
||||
|
@ -198,7 +198,7 @@ pub trait Iterator {
|
||||
/// // and the maximum possible lower bound
|
||||
/// let iter = 0..;
|
||||
///
|
||||
/// assert_eq!((usize::max_value(), None), iter.size_hint());
|
||||
/// assert_eq!((usize::MAX, None), iter.size_hint());
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -2920,7 +2920,7 @@ fn cmp_by<I, F>(mut self, other: I, mut cmp: F) -> Ordering
|
||||
/// assert_eq!([1.].iter().partial_cmp([1., 2.].iter()), Some(Ordering::Less));
|
||||
/// assert_eq!([1., 2.].iter().partial_cmp([1.].iter()), Some(Ordering::Greater));
|
||||
///
|
||||
/// assert_eq!([std::f64::NAN].iter().partial_cmp([1.].iter()), None);
|
||||
/// assert_eq!([f64::NAN].iter().partial_cmp([1.].iter()), None);
|
||||
/// ```
|
||||
#[stable(feature = "iter_order", since = "1.5.0")]
|
||||
fn partial_cmp<I>(self, other: I) -> Option<Ordering>
|
||||
@ -3170,7 +3170,7 @@ fn ge<I>(self, other: I) -> bool
|
||||
/// assert!(![1, 3, 2, 4].iter().is_sorted());
|
||||
/// assert!([0].iter().is_sorted());
|
||||
/// assert!(std::iter::empty::<i32>().is_sorted());
|
||||
/// assert!(![0.0, 1.0, std::f32::NAN].iter().is_sorted());
|
||||
/// assert!(![0.0, 1.0, f32::NAN].iter().is_sorted());
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "is_sorted", reason = "new API", issue = "53485")]
|
||||
@ -3197,7 +3197,7 @@ fn is_sorted(self) -> bool
|
||||
/// assert!(![1, 3, 2, 4].iter().is_sorted_by(|a, b| a.partial_cmp(b)));
|
||||
/// assert!([0].iter().is_sorted_by(|a, b| a.partial_cmp(b)));
|
||||
/// assert!(std::iter::empty::<i32>().is_sorted_by(|a, b| a.partial_cmp(b)));
|
||||
/// assert!(![0.0, 1.0, std::f32::NAN].iter().is_sorted_by(|a, b| a.partial_cmp(b)));
|
||||
/// assert!(![0.0, 1.0, f32::NAN].iter().is_sorted_by(|a, b| a.partial_cmp(b)));
|
||||
/// ```
|
||||
///
|
||||
/// [`is_sorted`]: trait.Iterator.html#method.is_sorted
|
||||
|
@ -470,7 +470,7 @@ pub fn min(self, other: f32) -> f32 {
|
||||
///
|
||||
/// let value = -128.9_f32;
|
||||
/// let rounded = unsafe { value.to_int_unchecked::<i8>() };
|
||||
/// assert_eq!(rounded, std::i8::MIN);
|
||||
/// assert_eq!(rounded, i8::MIN);
|
||||
/// ```
|
||||
///
|
||||
/// # Safety
|
||||
|
@ -484,7 +484,7 @@ pub fn min(self, other: f64) -> f64 {
|
||||
///
|
||||
/// let value = -128.9_f32;
|
||||
/// let rounded = unsafe { value.to_int_unchecked::<i8>() };
|
||||
/// assert_eq!(rounded, std::i8::MIN);
|
||||
/// assert_eq!(rounded, i8::MIN);
|
||||
/// ```
|
||||
///
|
||||
/// # Safety
|
||||
|
@ -174,7 +174,7 @@ fn from_str(src: &str) -> Result<Self, Self::Err> {
|
||||
/// let zero = Wrapping(0u32);
|
||||
/// let one = Wrapping(1u32);
|
||||
///
|
||||
/// assert_eq!(std::u32::MAX, (zero - one).0);
|
||||
/// assert_eq!(u32::MAX, (zero - one).0);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default, Hash)]
|
||||
|
@ -139,10 +139,9 @@ pub fn contains<U>(&self, item: &U) -> bool
|
||||
/// ```
|
||||
/// #![feature(range_is_empty)]
|
||||
///
|
||||
/// use std::f32::NAN;
|
||||
/// assert!(!(3.0..5.0).is_empty());
|
||||
/// assert!( (3.0..NAN).is_empty());
|
||||
/// assert!( (NAN..5.0).is_empty());
|
||||
/// assert!( (3.0..f32::NAN).is_empty());
|
||||
/// assert!( (f32::NAN..5.0).is_empty());
|
||||
/// ```
|
||||
#[unstable(feature = "range_is_empty", reason = "recently added", issue = "48111")]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
@ -496,10 +495,9 @@ pub fn contains<U>(&self, item: &U) -> bool
|
||||
/// ```
|
||||
/// #![feature(range_is_empty)]
|
||||
///
|
||||
/// use std::f32::NAN;
|
||||
/// assert!(!(3.0..=5.0).is_empty());
|
||||
/// assert!( (3.0..=NAN).is_empty());
|
||||
/// assert!( (NAN..=5.0).is_empty());
|
||||
/// assert!( (3.0..=f32::NAN).is_empty());
|
||||
/// assert!( (f32::NAN..=5.0).is_empty());
|
||||
/// ```
|
||||
///
|
||||
/// This method returns `true` after iteration has finished:
|
||||
|
@ -659,8 +659,8 @@ pub unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize)
|
||||
/// `align`.
|
||||
///
|
||||
/// If it is not possible to align the pointer, the implementation returns
|
||||
/// `usize::max_value()`. It is permissible for the implementation to *always*
|
||||
/// return `usize::max_value()`. Only your algorithm's performance can depend
|
||||
/// `usize::MAX`. It is permissible for the implementation to *always*
|
||||
/// return `usize::MAX`. Only your algorithm's performance can depend
|
||||
/// on getting a usable offset here, not its correctness.
|
||||
///
|
||||
/// The offset is expressed in number of `T` elements, and not bytes. The value returned can be
|
||||
|
@ -847,8 +847,8 @@ pub unsafe fn swap(self, with: *mut T)
|
||||
/// `align`.
|
||||
///
|
||||
/// If it is not possible to align the pointer, the implementation returns
|
||||
/// `usize::max_value()`. It is permissible for the implementation to *always*
|
||||
/// return `usize::max_value()`. Only your algorithm's performance can depend
|
||||
/// `usize::MAX`. It is permissible for the implementation to *always*
|
||||
/// return `usize::MAX`. Only your algorithm's performance can depend
|
||||
/// on getting a usable offset here, not its correctness.
|
||||
///
|
||||
/// The offset is expressed in number of `T` elements, and not bytes. The value returned can be
|
||||
|
@ -2588,7 +2588,7 @@ pub unsafe fn align_to_mut<U>(&mut self) -> (&mut [T], &mut [U], &mut [T]) {
|
||||
/// assert!(![1, 3, 2, 4].is_sorted());
|
||||
/// assert!([0].is_sorted());
|
||||
/// assert!(empty.is_sorted());
|
||||
/// assert!(![0.0, 1.0, std::f32::NAN].is_sorted());
|
||||
/// assert!(![0.0, 1.0, f32::NAN].is_sorted());
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "is_sorted", reason = "new API", issue = "53485")]
|
||||
|
@ -389,7 +389,7 @@ pub const fn as_nanos(&self) -> u128 {
|
||||
/// use std::time::Duration;
|
||||
///
|
||||
/// assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), Some(Duration::new(0, 1)));
|
||||
/// assert_eq!(Duration::new(1, 0).checked_add(Duration::new(std::u64::MAX, 0)), None);
|
||||
/// assert_eq!(Duration::new(1, 0).checked_add(Duration::new(u64::MAX, 0)), None);
|
||||
/// ```
|
||||
#[stable(feature = "duration_checked_ops", since = "1.16.0")]
|
||||
#[inline]
|
||||
@ -460,7 +460,7 @@ pub fn checked_sub(self, rhs: Duration) -> Option<Duration> {
|
||||
/// use std::time::Duration;
|
||||
///
|
||||
/// assert_eq!(Duration::new(0, 500_000_001).checked_mul(2), Some(Duration::new(1, 2)));
|
||||
/// assert_eq!(Duration::new(std::u64::MAX - 1, 0).checked_mul(2), None);
|
||||
/// assert_eq!(Duration::new(u64::MAX - 1, 0).checked_mul(2), None);
|
||||
/// ```
|
||||
#[stable(feature = "duration_checked_ops", since = "1.16.0")]
|
||||
#[inline]
|
||||
|
@ -972,8 +972,10 @@ pub(super) fn lower_body(
|
||||
f: impl FnOnce(&mut Self) -> (&'hir [hir::Param<'hir>], hir::Expr<'hir>),
|
||||
) -> hir::BodyId {
|
||||
let prev_gen_kind = self.generator_kind.take();
|
||||
let task_context = self.task_context.take();
|
||||
let (parameters, result) = f(self);
|
||||
let body_id = self.record_body(parameters, result);
|
||||
self.task_context = task_context;
|
||||
self.generator_kind = prev_gen_kind;
|
||||
body_id
|
||||
}
|
||||
|
@ -436,24 +436,21 @@ fn codegen_static(&self, def_id: DefId, is_mutable: bool) {
|
||||
//
|
||||
// We could remove this hack whenever we decide to drop macOS 10.10 support.
|
||||
if self.tcx.sess.target.target.options.is_like_osx {
|
||||
assert_eq!(alloc.relocations().len(), 0);
|
||||
|
||||
let is_zeroed = {
|
||||
// Treats undefined bytes as if they were defined with the byte value that
|
||||
// happens to be currently assigned in mir. This is valid since reading
|
||||
// undef bytes may yield arbitrary values.
|
||||
//
|
||||
// FIXME: ignore undef bytes even with representation `!= 0`.
|
||||
//
|
||||
// The `inspect` method is okay here because we checked relocations, and
|
||||
// because we are doing this access to inspect the final interpreter state
|
||||
// (not as part of the interpreter execution).
|
||||
alloc
|
||||
// The `inspect` method is okay here because we checked relocations, and
|
||||
// because we are doing this access to inspect the final interpreter state
|
||||
// (not as part of the interpreter execution).
|
||||
//
|
||||
// FIXME: This check requires that the (arbitrary) value of undefined bytes
|
||||
// happens to be zero. Instead, we should only check the value of defined bytes
|
||||
// and set all undefined bytes to zero if this allocation is headed for the
|
||||
// BSS.
|
||||
let all_bytes_are_zero = alloc.relocations().is_empty()
|
||||
&& alloc
|
||||
.inspect_with_undef_and_ptr_outside_interpreter(0..alloc.len())
|
||||
.iter()
|
||||
.all(|b| *b == 0)
|
||||
};
|
||||
let sect_name = if is_zeroed {
|
||||
.all(|&byte| byte == 0);
|
||||
|
||||
let sect_name = if all_bytes_are_zero {
|
||||
CStr::from_bytes_with_nul_unchecked(b"__DATA,__thread_bss\0")
|
||||
} else {
|
||||
CStr::from_bytes_with_nul_unchecked(b"__DATA,__thread_data\0")
|
||||
|
@ -1,5 +1,4 @@
|
||||
This error indicates that you are trying to borrow a variable as mutable when it
|
||||
has already been borrowed as immutable.
|
||||
A variable already borrowed as immutable was borrowed as mutable.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
pub mod error_reporting;
|
||||
mod project;
|
||||
mod structural_impls;
|
||||
mod util;
|
||||
pub mod util;
|
||||
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
|
@ -2,9 +2,12 @@
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_middle::ty::outlives::Component;
|
||||
use rustc_middle::ty::{self, ToPolyTraitRef, TyCtxt};
|
||||
use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, TyCtxt, WithConstness};
|
||||
|
||||
fn anonymize_predicate<'tcx>(tcx: TyCtxt<'tcx>, pred: &ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
|
||||
pub fn anonymize_predicate<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
pred: &ty::Predicate<'tcx>,
|
||||
) -> ty::Predicate<'tcx> {
|
||||
match *pred {
|
||||
ty::Predicate::Trait(ref data, constness) => {
|
||||
ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data), constness)
|
||||
@ -88,6 +91,21 @@ pub struct Elaborator<'tcx> {
|
||||
visited: PredicateSet<'tcx>,
|
||||
}
|
||||
|
||||
pub fn elaborate_trait_ref<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
) -> Elaborator<'tcx> {
|
||||
elaborate_predicates(tcx, vec![trait_ref.without_const().to_predicate()])
|
||||
}
|
||||
|
||||
pub fn elaborate_trait_refs<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
|
||||
) -> Elaborator<'tcx> {
|
||||
let predicates = trait_refs.map(|trait_ref| trait_ref.without_const().to_predicate()).collect();
|
||||
elaborate_predicates(tcx, predicates)
|
||||
}
|
||||
|
||||
pub fn elaborate_predicates<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
mut predicates: Vec<ty::Predicate<'tcx>>,
|
||||
@ -98,6 +116,10 @@ pub fn elaborate_predicates<'tcx>(
|
||||
}
|
||||
|
||||
impl Elaborator<'tcx> {
|
||||
pub fn filter_to_traits(self) -> FilterToTraits<Self> {
|
||||
FilterToTraits::new(self)
|
||||
}
|
||||
|
||||
fn elaborate(&mut self, predicate: &ty::Predicate<'tcx>) {
|
||||
let tcx = self.visited.tcx;
|
||||
match *predicate {
|
||||
@ -223,3 +245,57 @@ fn next(&mut self) -> Option<ty::Predicate<'tcx>> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Supertrait iterator
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
pub type Supertraits<'tcx> = FilterToTraits<Elaborator<'tcx>>;
|
||||
|
||||
pub fn supertraits<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
) -> Supertraits<'tcx> {
|
||||
elaborate_trait_ref(tcx, trait_ref).filter_to_traits()
|
||||
}
|
||||
|
||||
pub fn transitive_bounds<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
bounds: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
|
||||
) -> Supertraits<'tcx> {
|
||||
elaborate_trait_refs(tcx, bounds).filter_to_traits()
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Other
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// A filter around an iterator of predicates that makes it yield up
|
||||
/// just trait references.
|
||||
pub struct FilterToTraits<I> {
|
||||
base_iterator: I,
|
||||
}
|
||||
|
||||
impl<I> FilterToTraits<I> {
|
||||
fn new(base: I) -> FilterToTraits<I> {
|
||||
FilterToTraits { base_iterator: base }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, I: Iterator<Item = ty::Predicate<'tcx>>> Iterator for FilterToTraits<I> {
|
||||
type Item = ty::PolyTraitRef<'tcx>;
|
||||
|
||||
fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {
|
||||
while let Some(pred) = self.base_iterator.next() {
|
||||
if let ty::Predicate::Trait(data, _) = pred {
|
||||
return Some(data.to_poly_trait_ref());
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let (_, upper) = self.base_iterator.size_hint();
|
||||
(0, upper)
|
||||
}
|
||||
}
|
||||
|
@ -162,8 +162,13 @@ fn register_native_lib(&mut self, span: Option<Span>, lib: NativeLibrary) {
|
||||
}
|
||||
}
|
||||
if lib.cfg.is_some() && !self.tcx.features().link_cfg {
|
||||
feature_err(&self.tcx.sess.parse_sess, sym::link_cfg, span.unwrap(), "is unstable")
|
||||
.emit();
|
||||
feature_err(
|
||||
&self.tcx.sess.parse_sess,
|
||||
sym::link_cfg,
|
||||
span.unwrap(),
|
||||
"kind=\"link_cfg\" is unstable",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
if lib.kind == cstore::NativeStaticNobundle && !self.tcx.features().static_nobundle {
|
||||
feature_err(
|
||||
|
@ -1,277 +0,0 @@
|
||||
//! Hook into libgraphviz for rendering dataflow graphs for MIR.
|
||||
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::mir::{BasicBlock, Body};
|
||||
|
||||
use std::fs;
|
||||
use std::io;
|
||||
use std::marker::PhantomData;
|
||||
use std::path::Path;
|
||||
|
||||
use crate::util::graphviz_safe_def_name;
|
||||
|
||||
use super::DataflowBuilder;
|
||||
use super::DebugFormatted;
|
||||
use super::{BitDenotation, DataflowState};
|
||||
|
||||
pub trait MirWithFlowState<'tcx> {
|
||||
type BD: BitDenotation<'tcx>;
|
||||
fn def_id(&self) -> DefId;
|
||||
fn body(&self) -> &Body<'tcx>;
|
||||
fn flow_state(&self) -> &DataflowState<'tcx, Self::BD>;
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, BD> MirWithFlowState<'tcx> for DataflowBuilder<'a, 'tcx, BD>
|
||||
where
|
||||
BD: BitDenotation<'tcx>,
|
||||
{
|
||||
type BD = BD;
|
||||
fn def_id(&self) -> DefId {
|
||||
self.def_id
|
||||
}
|
||||
fn body(&self) -> &Body<'tcx> {
|
||||
self.flow_state.body()
|
||||
}
|
||||
fn flow_state(&self) -> &DataflowState<'tcx, Self::BD> {
|
||||
&self.flow_state.flow_state
|
||||
}
|
||||
}
|
||||
|
||||
struct Graph<'a, 'tcx, MWF, P>
|
||||
where
|
||||
MWF: MirWithFlowState<'tcx>,
|
||||
{
|
||||
mbcx: &'a MWF,
|
||||
phantom: PhantomData<&'tcx ()>,
|
||||
render_idx: P,
|
||||
}
|
||||
|
||||
pub(crate) fn print_borrowck_graph_to<'a, 'tcx, BD, P>(
|
||||
mbcx: &DataflowBuilder<'a, 'tcx, BD>,
|
||||
path: &Path,
|
||||
render_idx: P,
|
||||
) -> io::Result<()>
|
||||
where
|
||||
BD: BitDenotation<'tcx>,
|
||||
P: Fn(&BD, BD::Idx) -> DebugFormatted,
|
||||
{
|
||||
let g = Graph { mbcx, phantom: PhantomData, render_idx };
|
||||
let mut v = Vec::new();
|
||||
dot::render(&g, &mut v)?;
|
||||
debug!("print_borrowck_graph_to path: {} def_id: {:?}", path.display(), mbcx.def_id);
|
||||
fs::write(path, v)
|
||||
}
|
||||
|
||||
pub type Node = BasicBlock;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub struct Edge {
|
||||
source: BasicBlock,
|
||||
index: usize,
|
||||
}
|
||||
|
||||
fn outgoing(body: &Body<'_>, bb: BasicBlock) -> Vec<Edge> {
|
||||
(0..body[bb].terminator().successors().count())
|
||||
.map(|index| Edge { source: bb, index })
|
||||
.collect()
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P>
|
||||
where
|
||||
MWF: MirWithFlowState<'tcx>,
|
||||
P: Fn(&MWF::BD, <MWF::BD as BitDenotation<'tcx>>::Idx) -> DebugFormatted,
|
||||
{
|
||||
type Node = Node;
|
||||
type Edge = Edge;
|
||||
fn graph_id(&self) -> dot::Id<'_> {
|
||||
let name = graphviz_safe_def_name(self.mbcx.def_id());
|
||||
dot::Id::new(format!("graph_for_def_id_{}", name)).unwrap()
|
||||
}
|
||||
|
||||
fn node_id(&self, n: &Node) -> dot::Id<'_> {
|
||||
dot::Id::new(format!("bb_{}", n.index())).unwrap()
|
||||
}
|
||||
|
||||
fn node_label(&self, n: &Node) -> dot::LabelText<'_> {
|
||||
// Node label is something like this:
|
||||
// +---------+----------------------------------+------------------+------------------+
|
||||
// | ENTRY | MIR | GEN | KILL |
|
||||
// +---------+----------------------------------+------------------+------------------+
|
||||
// | | 0: StorageLive(_7) | bb3[2]: reserved | bb2[0]: reserved |
|
||||
// | | 1: StorageLive(_8) | bb3[2]: active | bb2[0]: active |
|
||||
// | | 2: _8 = &mut _1 | | bb4[2]: reserved |
|
||||
// | | | | bb4[2]: active |
|
||||
// | | | | bb9[0]: reserved |
|
||||
// | | | | bb9[0]: active |
|
||||
// | | | | bb10[0]: reserved|
|
||||
// | | | | bb10[0]: active |
|
||||
// | | | | bb11[0]: reserved|
|
||||
// | | | | bb11[0]: active |
|
||||
// +---------+----------------------------------+------------------+------------------+
|
||||
// | [00-00] | _7 = const Foo::twiddle(move _8) | [0c-00] | [f3-0f] |
|
||||
// +---------+----------------------------------+------------------+------------------+
|
||||
let mut v = Vec::new();
|
||||
self.node_label_internal(n, &mut v, *n, self.mbcx.body()).unwrap();
|
||||
dot::LabelText::html(String::from_utf8(v).unwrap())
|
||||
}
|
||||
|
||||
fn node_shape(&self, _n: &Node) -> Option<dot::LabelText<'_>> {
|
||||
Some(dot::LabelText::label("none"))
|
||||
}
|
||||
|
||||
fn edge_label(&'a self, e: &Edge) -> dot::LabelText<'a> {
|
||||
let term = self.mbcx.body()[e.source].terminator();
|
||||
let label = &term.kind.fmt_successor_labels()[e.index];
|
||||
dot::LabelText::label(label.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, MWF, P> Graph<'a, 'tcx, MWF, P>
|
||||
where
|
||||
MWF: MirWithFlowState<'tcx>,
|
||||
P: Fn(&MWF::BD, <MWF::BD as BitDenotation<'tcx>>::Idx) -> DebugFormatted,
|
||||
{
|
||||
/// Generate the node label
|
||||
fn node_label_internal<W: io::Write>(
|
||||
&self,
|
||||
n: &Node,
|
||||
w: &mut W,
|
||||
block: BasicBlock,
|
||||
body: &Body<'_>,
|
||||
) -> io::Result<()> {
|
||||
// Header rows
|
||||
const HDRS: [&str; 4] = ["ENTRY", "MIR", "BLOCK GENS", "BLOCK KILLS"];
|
||||
const HDR_FMT: &str = "bgcolor=\"grey\"";
|
||||
write!(w, "<table><tr><td rowspan=\"{}\">", HDRS.len())?;
|
||||
write!(w, "{:?}", block.index())?;
|
||||
write!(w, "</td></tr><tr>")?;
|
||||
for hdr in &HDRS {
|
||||
write!(w, "<td {}>{}</td>", HDR_FMT, hdr)?;
|
||||
}
|
||||
write!(w, "</tr>")?;
|
||||
|
||||
// Data row
|
||||
self.node_label_verbose_row(n, w, block, body)?;
|
||||
self.node_label_final_row(n, w, block, body)?;
|
||||
write!(w, "</table>")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Builds the verbose row: full MIR data, and detailed gen/kill/entry sets.
|
||||
fn node_label_verbose_row<W: io::Write>(
|
||||
&self,
|
||||
n: &Node,
|
||||
w: &mut W,
|
||||
block: BasicBlock,
|
||||
body: &Body<'_>,
|
||||
) -> io::Result<()> {
|
||||
let i = n.index();
|
||||
|
||||
macro_rules! dump_set_for {
|
||||
($set:ident, $interpret:ident) => {
|
||||
write!(w, "<td>")?;
|
||||
|
||||
let flow = self.mbcx.flow_state();
|
||||
let entry_interp =
|
||||
flow.$interpret(&flow.operator, flow.sets.$set(i), &self.render_idx);
|
||||
for e in &entry_interp {
|
||||
write!(w, "{:?}<br/>", e)?;
|
||||
}
|
||||
write!(w, "</td>")?;
|
||||
};
|
||||
}
|
||||
|
||||
write!(w, "<tr>")?;
|
||||
// Entry
|
||||
dump_set_for!(entry_set_for, interpret_set);
|
||||
|
||||
// MIR statements
|
||||
write!(w, "<td>")?;
|
||||
{
|
||||
let data = &body[block];
|
||||
for (i, statement) in data.statements.iter().enumerate() {
|
||||
write!(
|
||||
w,
|
||||
"{}<br align=\"left\"/>",
|
||||
dot::escape_html(&format!("{:3}: {:?}", i, statement))
|
||||
)?;
|
||||
}
|
||||
}
|
||||
write!(w, "</td>")?;
|
||||
|
||||
// Gen
|
||||
dump_set_for!(gen_set_for, interpret_hybrid_set);
|
||||
|
||||
// Kill
|
||||
dump_set_for!(kill_set_for, interpret_hybrid_set);
|
||||
|
||||
write!(w, "</tr>")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Builds the summary row: terminator, gen/kill/entry bit sets.
|
||||
fn node_label_final_row<W: io::Write>(
|
||||
&self,
|
||||
n: &Node,
|
||||
w: &mut W,
|
||||
block: BasicBlock,
|
||||
body: &Body<'_>,
|
||||
) -> io::Result<()> {
|
||||
let i = n.index();
|
||||
|
||||
let flow = self.mbcx.flow_state();
|
||||
|
||||
write!(w, "<tr>")?;
|
||||
|
||||
// Entry
|
||||
let set = flow.sets.entry_set_for(i);
|
||||
write!(w, "<td>{:?}</td>", dot::escape_html(&set.to_string()))?;
|
||||
|
||||
// Terminator
|
||||
write!(w, "<td>")?;
|
||||
{
|
||||
let data = &body[block];
|
||||
let mut terminator_head = String::new();
|
||||
data.terminator().kind.fmt_head(&mut terminator_head).unwrap();
|
||||
write!(w, "{}", dot::escape_html(&terminator_head))?;
|
||||
}
|
||||
write!(w, "</td>")?;
|
||||
|
||||
// Gen/Kill
|
||||
let trans = flow.sets.trans_for(i);
|
||||
write!(w, "<td>{:?}</td>", dot::escape_html(&format!("{:?}", trans.gen_set)))?;
|
||||
write!(w, "<td>{:?}</td>", dot::escape_html(&format!("{:?}", trans.kill_set)))?;
|
||||
|
||||
write!(w, "</tr>")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, MWF, P> dot::GraphWalk<'a> for Graph<'a, 'tcx, MWF, P>
|
||||
where
|
||||
MWF: MirWithFlowState<'tcx>,
|
||||
{
|
||||
type Node = Node;
|
||||
type Edge = Edge;
|
||||
fn nodes(&self) -> dot::Nodes<'_, Node> {
|
||||
self.mbcx.body().basic_blocks().indices().collect::<Vec<_>>().into()
|
||||
}
|
||||
|
||||
fn edges(&self) -> dot::Edges<'_, Edge> {
|
||||
let body = self.mbcx.body();
|
||||
|
||||
body.basic_blocks().indices().flat_map(|bb| outgoing(body, bb)).collect::<Vec<_>>().into()
|
||||
}
|
||||
|
||||
fn source(&self, edge: &Edge) -> Node {
|
||||
edge.source
|
||||
}
|
||||
|
||||
fn target(&self, edge: &Edge) -> Node {
|
||||
let body = self.mbcx.body();
|
||||
*body[edge.source].terminator().successors().nth(edge.index).unwrap()
|
||||
}
|
||||
}
|
@ -577,7 +577,7 @@ pub struct Scalar {
|
||||
pub value: Primitive,
|
||||
|
||||
/// Inclusive wrap-around range of valid values, that is, if
|
||||
/// start > end, it represents `start..=max_value()`,
|
||||
/// start > end, it represents `start..=MAX`,
|
||||
/// followed by `0..=end`.
|
||||
///
|
||||
/// That is, for an i8 primitive, a range of `254..=2` means following
|
||||
|
@ -5,270 +5,11 @@
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::ty::outlives::Component;
|
||||
use rustc_middle::ty::subst::{GenericArg, Subst, SubstsRef};
|
||||
use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness};
|
||||
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};
|
||||
|
||||
use super::{Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext};
|
||||
|
||||
fn anonymize_predicate<'tcx>(tcx: TyCtxt<'tcx>, pred: &ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
|
||||
match *pred {
|
||||
ty::Predicate::Trait(ref data, constness) => {
|
||||
ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data), constness)
|
||||
}
|
||||
|
||||
ty::Predicate::RegionOutlives(ref data) => {
|
||||
ty::Predicate::RegionOutlives(tcx.anonymize_late_bound_regions(data))
|
||||
}
|
||||
|
||||
ty::Predicate::TypeOutlives(ref data) => {
|
||||
ty::Predicate::TypeOutlives(tcx.anonymize_late_bound_regions(data))
|
||||
}
|
||||
|
||||
ty::Predicate::Projection(ref data) => {
|
||||
ty::Predicate::Projection(tcx.anonymize_late_bound_regions(data))
|
||||
}
|
||||
|
||||
ty::Predicate::WellFormed(data) => ty::Predicate::WellFormed(data),
|
||||
|
||||
ty::Predicate::ObjectSafe(data) => ty::Predicate::ObjectSafe(data),
|
||||
|
||||
ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
|
||||
ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind)
|
||||
}
|
||||
|
||||
ty::Predicate::Subtype(ref data) => {
|
||||
ty::Predicate::Subtype(tcx.anonymize_late_bound_regions(data))
|
||||
}
|
||||
|
||||
ty::Predicate::ConstEvaluatable(def_id, substs) => {
|
||||
ty::Predicate::ConstEvaluatable(def_id, substs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct PredicateSet<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
set: FxHashSet<ty::Predicate<'tcx>>,
|
||||
}
|
||||
|
||||
impl PredicateSet<'tcx> {
|
||||
fn new(tcx: TyCtxt<'tcx>) -> Self {
|
||||
Self { tcx, set: Default::default() }
|
||||
}
|
||||
|
||||
fn insert(&mut self, pred: &ty::Predicate<'tcx>) -> bool {
|
||||
// We have to be careful here because we want
|
||||
//
|
||||
// for<'a> Foo<&'a int>
|
||||
//
|
||||
// and
|
||||
//
|
||||
// for<'b> Foo<&'b int>
|
||||
//
|
||||
// to be considered equivalent. So normalize all late-bound
|
||||
// regions before we throw things into the underlying set.
|
||||
self.set.insert(anonymize_predicate(self.tcx, pred))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsRef<ty::Predicate<'tcx>>> Extend<T> for PredicateSet<'tcx> {
|
||||
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
|
||||
for pred in iter {
|
||||
self.insert(pred.as_ref());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// `Elaboration` iterator
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// "Elaboration" is the process of identifying all the predicates that
|
||||
/// are implied by a source predicate. Currently, this basically means
|
||||
/// walking the "supertraits" and other similar assumptions. For example,
|
||||
/// if we know that `T: Ord`, the elaborator would deduce that `T: PartialOrd`
|
||||
/// holds as well. Similarly, if we have `trait Foo: 'static`, and we know that
|
||||
/// `T: Foo`, then we know that `T: 'static`.
|
||||
pub struct Elaborator<'tcx> {
|
||||
stack: Vec<ty::Predicate<'tcx>>,
|
||||
visited: PredicateSet<'tcx>,
|
||||
}
|
||||
|
||||
pub fn elaborate_trait_ref<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
) -> Elaborator<'tcx> {
|
||||
elaborate_predicates(tcx, vec![trait_ref.without_const().to_predicate()])
|
||||
}
|
||||
|
||||
pub fn elaborate_trait_refs<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
|
||||
) -> Elaborator<'tcx> {
|
||||
let predicates = trait_refs.map(|trait_ref| trait_ref.without_const().to_predicate()).collect();
|
||||
elaborate_predicates(tcx, predicates)
|
||||
}
|
||||
|
||||
pub fn elaborate_predicates<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
mut predicates: Vec<ty::Predicate<'tcx>>,
|
||||
) -> Elaborator<'tcx> {
|
||||
let mut visited = PredicateSet::new(tcx);
|
||||
predicates.retain(|pred| visited.insert(pred));
|
||||
Elaborator { stack: predicates, visited }
|
||||
}
|
||||
|
||||
impl Elaborator<'tcx> {
|
||||
pub fn filter_to_traits(self) -> FilterToTraits<Self> {
|
||||
FilterToTraits::new(self)
|
||||
}
|
||||
|
||||
fn elaborate(&mut self, predicate: &ty::Predicate<'tcx>) {
|
||||
let tcx = self.visited.tcx;
|
||||
match *predicate {
|
||||
ty::Predicate::Trait(ref data, _) => {
|
||||
// Get predicates declared on the trait.
|
||||
let predicates = tcx.super_predicates_of(data.def_id());
|
||||
|
||||
let predicates = predicates
|
||||
.predicates
|
||||
.iter()
|
||||
.map(|(pred, _)| pred.subst_supertrait(tcx, &data.to_poly_trait_ref()));
|
||||
debug!("super_predicates: data={:?} predicates={:?}", data, predicates.clone());
|
||||
|
||||
// Only keep those bounds that we haven't already seen.
|
||||
// This is necessary to prevent infinite recursion in some
|
||||
// cases. One common case is when people define
|
||||
// `trait Sized: Sized { }` rather than `trait Sized { }`.
|
||||
let visited = &mut self.visited;
|
||||
let predicates = predicates.filter(|pred| visited.insert(pred));
|
||||
|
||||
self.stack.extend(predicates);
|
||||
}
|
||||
ty::Predicate::WellFormed(..) => {
|
||||
// Currently, we do not elaborate WF predicates,
|
||||
// although we easily could.
|
||||
}
|
||||
ty::Predicate::ObjectSafe(..) => {
|
||||
// Currently, we do not elaborate object-safe
|
||||
// predicates.
|
||||
}
|
||||
ty::Predicate::Subtype(..) => {
|
||||
// Currently, we do not "elaborate" predicates like `X <: Y`,
|
||||
// though conceivably we might.
|
||||
}
|
||||
ty::Predicate::Projection(..) => {
|
||||
// Nothing to elaborate in a projection predicate.
|
||||
}
|
||||
ty::Predicate::ClosureKind(..) => {
|
||||
// Nothing to elaborate when waiting for a closure's kind to be inferred.
|
||||
}
|
||||
ty::Predicate::ConstEvaluatable(..) => {
|
||||
// Currently, we do not elaborate const-evaluatable
|
||||
// predicates.
|
||||
}
|
||||
ty::Predicate::RegionOutlives(..) => {
|
||||
// Nothing to elaborate from `'a: 'b`.
|
||||
}
|
||||
ty::Predicate::TypeOutlives(ref data) => {
|
||||
// We know that `T: 'a` for some type `T`. We can
|
||||
// often elaborate this. For example, if we know that
|
||||
// `[U]: 'a`, that implies that `U: 'a`. Similarly, if
|
||||
// we know `&'a U: 'b`, then we know that `'a: 'b` and
|
||||
// `U: 'b`.
|
||||
//
|
||||
// We can basically ignore bound regions here. So for
|
||||
// example `for<'c> Foo<'a,'c>: 'b` can be elaborated to
|
||||
// `'a: 'b`.
|
||||
|
||||
// Ignore `for<'a> T: 'a` -- we might in the future
|
||||
// consider this as evidence that `T: 'static`, but
|
||||
// I'm a bit wary of such constructions and so for now
|
||||
// I want to be conservative. --nmatsakis
|
||||
let ty_max = data.skip_binder().0;
|
||||
let r_min = data.skip_binder().1;
|
||||
if r_min.is_late_bound() {
|
||||
return;
|
||||
}
|
||||
|
||||
let visited = &mut self.visited;
|
||||
let mut components = smallvec![];
|
||||
tcx.push_outlives_components(ty_max, &mut components);
|
||||
self.stack.extend(
|
||||
components
|
||||
.into_iter()
|
||||
.filter_map(|component| match component {
|
||||
Component::Region(r) => {
|
||||
if r.is_late_bound() {
|
||||
None
|
||||
} else {
|
||||
Some(ty::Predicate::RegionOutlives(ty::Binder::dummy(
|
||||
ty::OutlivesPredicate(r, r_min),
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
Component::Param(p) => {
|
||||
let ty = tcx.mk_ty_param(p.index, p.name);
|
||||
Some(ty::Predicate::TypeOutlives(ty::Binder::dummy(
|
||||
ty::OutlivesPredicate(ty, r_min),
|
||||
)))
|
||||
}
|
||||
|
||||
Component::UnresolvedInferenceVariable(_) => None,
|
||||
|
||||
Component::Projection(_) | Component::EscapingProjection(_) => {
|
||||
// We can probably do more here. This
|
||||
// corresponds to a case like `<T as
|
||||
// Foo<'a>>::U: 'b`.
|
||||
None
|
||||
}
|
||||
})
|
||||
.filter(|p| visited.insert(p)),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for Elaborator<'tcx> {
|
||||
type Item = ty::Predicate<'tcx>;
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(self.stack.len(), None)
|
||||
}
|
||||
|
||||
fn next(&mut self) -> Option<ty::Predicate<'tcx>> {
|
||||
// Extract next item from top-most stack frame, if any.
|
||||
if let Some(pred) = self.stack.pop() {
|
||||
self.elaborate(&pred);
|
||||
Some(pred)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Supertrait iterator
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
pub type Supertraits<'tcx> = FilterToTraits<Elaborator<'tcx>>;
|
||||
|
||||
pub fn supertraits<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
) -> Supertraits<'tcx> {
|
||||
elaborate_trait_ref(tcx, trait_ref).filter_to_traits()
|
||||
}
|
||||
|
||||
pub fn transitive_bounds<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
bounds: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
|
||||
) -> Supertraits<'tcx> {
|
||||
elaborate_trait_refs(tcx, bounds).filter_to_traits()
|
||||
}
|
||||
pub use rustc_infer::traits::util::*;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// `TraitAliasExpander` iterator
|
||||
@ -450,40 +191,6 @@ fn next(&mut self) -> Option<DefId> {
|
||||
// Other
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// A filter around an iterator of predicates that makes it yield up
|
||||
/// just trait references.
|
||||
pub struct FilterToTraits<I> {
|
||||
base_iterator: I,
|
||||
}
|
||||
|
||||
impl<I> FilterToTraits<I> {
|
||||
fn new(base: I) -> FilterToTraits<I> {
|
||||
FilterToTraits { base_iterator: base }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, I: Iterator<Item = ty::Predicate<'tcx>>> Iterator for FilterToTraits<I> {
|
||||
type Item = ty::PolyTraitRef<'tcx>;
|
||||
|
||||
fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {
|
||||
while let Some(pred) = self.base_iterator.next() {
|
||||
if let ty::Predicate::Trait(data, _) = pred {
|
||||
return Some(data.to_poly_trait_ref());
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let (_, upper) = self.base_iterator.size_hint();
|
||||
(0, upper)
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Other
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Instantiate all bound parameters of the impl with the given substs,
|
||||
/// returning the resulting trait ref and all obligations that arise.
|
||||
/// The obligations are closed under normalization.
|
||||
|
@ -284,7 +284,7 @@ pub fn div_euclid(self, rhs: f32) -> f32 {
|
||||
/// assert_eq!(a.rem_euclid(-b), 3.0);
|
||||
/// assert_eq!((-a).rem_euclid(-b), 1.0);
|
||||
/// // limitation due to round-off error
|
||||
/// assert!((-std::f32::EPSILON).rem_euclid(3.0) != 0.0);
|
||||
/// assert!((-f32::EPSILON).rem_euclid(3.0) != 0.0);
|
||||
/// ```
|
||||
#[must_use = "method returns a new number and does not mutate the original value"]
|
||||
#[inline]
|
||||
@ -962,7 +962,7 @@ pub fn atanh(self) -> f32 {
|
||||
/// assert!((-3.0f32).clamp(-2.0, 1.0) == -2.0);
|
||||
/// assert!((0.0f32).clamp(-2.0, 1.0) == 0.0);
|
||||
/// assert!((2.0f32).clamp(-2.0, 1.0) == 1.0);
|
||||
/// assert!((std::f32::NAN).clamp(-2.0, 1.0).is_nan());
|
||||
/// assert!((f32::NAN).clamp(-2.0, 1.0).is_nan());
|
||||
/// ```
|
||||
#[must_use = "method returns a new number and does not mutate the original value"]
|
||||
#[unstable(feature = "clamp", issue = "44095")]
|
||||
|
@ -280,7 +280,7 @@ pub fn div_euclid(self, rhs: f64) -> f64 {
|
||||
/// assert_eq!(a.rem_euclid(-b), 3.0);
|
||||
/// assert_eq!((-a).rem_euclid(-b), 1.0);
|
||||
/// // limitation due to round-off error
|
||||
/// assert!((-std::f64::EPSILON).rem_euclid(3.0) != 0.0);
|
||||
/// assert!((-f64::EPSILON).rem_euclid(3.0) != 0.0);
|
||||
/// ```
|
||||
#[must_use = "method returns a new number and does not mutate the original value"]
|
||||
#[inline]
|
||||
@ -928,7 +928,7 @@ pub fn atanh(self) -> f64 {
|
||||
/// assert!((-3.0f64).clamp(-2.0, 1.0) == -2.0);
|
||||
/// assert!((0.0f64).clamp(-2.0, 1.0) == 0.0);
|
||||
/// assert!((2.0f64).clamp(-2.0, 1.0) == 1.0);
|
||||
/// assert!((std::f64::NAN).clamp(-2.0, 1.0).is_nan());
|
||||
/// assert!((f64::NAN).clamp(-2.0, 1.0).is_nan());
|
||||
/// ```
|
||||
#[must_use = "method returns a new number and does not mutate the original value"]
|
||||
#[unstable(feature = "clamp", issue = "44095")]
|
||||
|
@ -1,13 +1,5 @@
|
||||
#![cfg_attr(test, allow(dead_code))]
|
||||
|
||||
pub struct Handler;
|
||||
|
||||
impl Handler {
|
||||
pub unsafe fn new() -> Handler {
|
||||
Handler
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn init() {}
|
||||
|
||||
pub unsafe fn cleanup() {}
|
||||
|
@ -5,7 +5,6 @@
|
||||
use crate::ptr;
|
||||
use crate::sys::cloudabi::abi;
|
||||
use crate::sys::time::checked_dur2intervals;
|
||||
use crate::sys_common::thread::*;
|
||||
use crate::time::Duration;
|
||||
|
||||
pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
|
||||
@ -22,7 +21,7 @@ unsafe impl Sync for Thread {}
|
||||
impl Thread {
|
||||
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
|
||||
pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
|
||||
let p = box p;
|
||||
let p = Box::into_raw(box p);
|
||||
let mut native: libc::pthread_t = mem::zeroed();
|
||||
let mut attr: libc::pthread_attr_t = mem::zeroed();
|
||||
assert_eq!(libc::pthread_attr_init(&mut attr), 0);
|
||||
@ -30,19 +29,25 @@ pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
|
||||
let stack_size = cmp::max(stack, min_stack_size(&attr));
|
||||
assert_eq!(libc::pthread_attr_setstacksize(&mut attr, stack_size), 0);
|
||||
|
||||
let ret = libc::pthread_create(&mut native, &attr, thread_start, &*p as *const _ as *mut _);
|
||||
let ret = libc::pthread_create(&mut native, &attr, thread_start, p as *mut _);
|
||||
// Note: if the thread creation fails and this assert fails, then p will
|
||||
// be leaked. However, an alternative design could cause double-free
|
||||
// which is clearly worse.
|
||||
assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
|
||||
|
||||
return if ret != 0 {
|
||||
// The thread failed to start and as a result p was not consumed. Therefore, it is
|
||||
// safe to reconstruct the box so that it gets deallocated.
|
||||
drop(Box::from_raw(p));
|
||||
Err(io::Error::from_raw_os_error(ret))
|
||||
} else {
|
||||
mem::forget(p); // ownership passed to pthread_create
|
||||
Ok(Thread { id: native })
|
||||
};
|
||||
|
||||
extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
|
||||
unsafe {
|
||||
start_thread(main as *mut u8);
|
||||
// Let's run some code.
|
||||
Box::from_raw(main as *mut Box<dyn FnOnce()>)();
|
||||
}
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
@ -1,11 +1,3 @@
|
||||
pub struct Handler;
|
||||
|
||||
impl Handler {
|
||||
pub unsafe fn new() -> Handler {
|
||||
Handler
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn init() {}
|
||||
|
||||
|
@ -8,8 +8,6 @@
|
||||
use crate::time::Duration;
|
||||
use core::u32;
|
||||
|
||||
use crate::sys_common::thread::*;
|
||||
|
||||
pub type Tid = abi::Tid;
|
||||
|
||||
/// Priority of a task
|
||||
@ -49,26 +47,29 @@ pub unsafe fn new_with_coreid(
|
||||
p: Box<dyn FnOnce()>,
|
||||
core_id: isize,
|
||||
) -> io::Result<Thread> {
|
||||
let p = box p;
|
||||
let p = Box::into_raw(box p);
|
||||
let mut tid: Tid = u32::MAX;
|
||||
let ret = abi::spawn(
|
||||
&mut tid as *mut Tid,
|
||||
thread_start,
|
||||
&*p as *const _ as *const u8 as usize,
|
||||
p as usize,
|
||||
Priority::into(NORMAL_PRIO),
|
||||
core_id,
|
||||
);
|
||||
|
||||
return if ret == 0 {
|
||||
mem::forget(p); // ownership passed to pthread_create
|
||||
Ok(Thread { tid: tid })
|
||||
} else {
|
||||
return if ret != 0 {
|
||||
// The thread failed to start and as a result p was not consumed. Therefore, it is
|
||||
// safe to reconstruct the box so that it gets deallocated.
|
||||
drop(Box::from_raw(p));
|
||||
Err(io::Error::new(io::ErrorKind::Other, "Unable to create thread!"))
|
||||
} else {
|
||||
Ok(Thread { tid: tid })
|
||||
};
|
||||
|
||||
extern "C" fn thread_start(main: usize) {
|
||||
unsafe {
|
||||
start_thread(main as *mut u8);
|
||||
// Finally, let's run some code.
|
||||
Box::from_raw(main as *mut Box<dyn FnOnce()>)();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,3 @@
|
||||
pub struct Handler;
|
||||
|
||||
impl Handler {
|
||||
pub unsafe fn new() -> Handler {
|
||||
Handler
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(test, allow(dead_code))]
|
||||
pub unsafe fn init() {}
|
||||
|
||||
|
@ -3,11 +3,9 @@
|
||||
use crate::io;
|
||||
use crate::mem;
|
||||
use crate::ptr;
|
||||
use crate::sys::os;
|
||||
use crate::sys::{os, stack_overflow};
|
||||
use crate::time::Duration;
|
||||
|
||||
use crate::sys_common::thread::*;
|
||||
|
||||
#[cfg(not(target_os = "l4re"))]
|
||||
pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
|
||||
#[cfg(target_os = "l4re")]
|
||||
@ -43,7 +41,7 @@ unsafe fn pthread_attr_setstacksize(
|
||||
impl Thread {
|
||||
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
|
||||
pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
|
||||
let p = box p;
|
||||
let p = Box::into_raw(box p);
|
||||
let mut native: libc::pthread_t = mem::zeroed();
|
||||
let mut attr: libc::pthread_attr_t = mem::zeroed();
|
||||
assert_eq!(libc::pthread_attr_init(&mut attr), 0);
|
||||
@ -65,19 +63,28 @@ pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
|
||||
}
|
||||
};
|
||||
|
||||
let ret = libc::pthread_create(&mut native, &attr, thread_start, &*p as *const _ as *mut _);
|
||||
let ret = libc::pthread_create(&mut native, &attr, thread_start, p as *mut _);
|
||||
// Note: if the thread creation fails and this assert fails, then p will
|
||||
// be leaked. However, an alternative design could cause double-free
|
||||
// which is clearly worse.
|
||||
assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
|
||||
|
||||
return if ret != 0 {
|
||||
// The thread failed to start and as a result p was not consumed. Therefore, it is
|
||||
// safe to reconstruct the box so that it gets deallocated.
|
||||
drop(Box::from_raw(p));
|
||||
Err(io::Error::from_raw_os_error(ret))
|
||||
} else {
|
||||
mem::forget(p); // ownership passed to pthread_create
|
||||
Ok(Thread { id: native })
|
||||
};
|
||||
|
||||
extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
|
||||
unsafe {
|
||||
start_thread(main as *mut u8);
|
||||
// Next, set up our stack overflow handler which may get triggered if we run
|
||||
// out of stack.
|
||||
let _handler = stack_overflow::Handler::new();
|
||||
// Finally, let's run some code.
|
||||
Box::from_raw(main as *mut Box<dyn FnOnce()>)();
|
||||
}
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
@ -3,11 +3,9 @@
|
||||
use crate::io;
|
||||
use crate::mem;
|
||||
use crate::ptr;
|
||||
use crate::sys::os;
|
||||
use crate::sys::{os, stack_overflow};
|
||||
use crate::time::Duration;
|
||||
|
||||
use crate::sys_common::thread::*;
|
||||
|
||||
pub const DEFAULT_MIN_STACK_SIZE: usize = 0x40000; // 256K
|
||||
|
||||
pub struct Thread {
|
||||
@ -31,7 +29,7 @@ unsafe fn pthread_attr_setstacksize(
|
||||
impl Thread {
|
||||
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
|
||||
pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
|
||||
let p = box p;
|
||||
let p = Box::into_raw(box p);
|
||||
let mut native: libc::pthread_t = mem::zeroed();
|
||||
let mut attr: libc::pthread_attr_t = mem::zeroed();
|
||||
assert_eq!(libc::pthread_attr_init(&mut attr), 0);
|
||||
@ -53,19 +51,28 @@ pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
|
||||
}
|
||||
};
|
||||
|
||||
let ret = libc::pthread_create(&mut native, &attr, thread_start, &*p as *const _ as *mut _);
|
||||
let ret = libc::pthread_create(&mut native, &attr, thread_start, p as *mut _);
|
||||
// Note: if the thread creation fails and this assert fails, then p will
|
||||
// be leaked. However, an alternative design could cause double-free
|
||||
// which is clearly worse.
|
||||
assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
|
||||
|
||||
return if ret != 0 {
|
||||
// The thread failed to start and as a result p was not consumed. Therefore, it is
|
||||
// safe to reconstruct the box so that it gets deallocated.
|
||||
drop(Box::from_raw(p));
|
||||
Err(io::Error::from_raw_os_error(ret))
|
||||
} else {
|
||||
mem::forget(p); // ownership passed to pthread_create
|
||||
Ok(Thread { id: native })
|
||||
};
|
||||
|
||||
extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
|
||||
unsafe {
|
||||
start_thread(main as *mut u8);
|
||||
// Next, set up our stack overflow handler which may get triggered if we run
|
||||
// out of stack.
|
||||
let _handler = stack_overflow::Handler::new();
|
||||
// Finally, let's run some code.
|
||||
Box::from_raw(main as *mut Box<dyn FnOnce()>)();
|
||||
}
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
@ -1,11 +1,3 @@
|
||||
pub struct Handler;
|
||||
|
||||
impl Handler {
|
||||
pub unsafe fn new() -> Handler {
|
||||
Handler
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn init() {}
|
||||
|
||||
pub unsafe fn cleanup() {}
|
||||
|
@ -1,10 +1,9 @@
|
||||
use crate::ffi::CStr;
|
||||
use crate::io;
|
||||
use crate::mem;
|
||||
use crate::ptr;
|
||||
use crate::sys::c;
|
||||
use crate::sys::handle::Handle;
|
||||
use crate::sys_common::thread::*;
|
||||
use crate::sys::stack_overflow;
|
||||
use crate::time::Duration;
|
||||
|
||||
use libc::c_void;
|
||||
@ -20,7 +19,7 @@ pub struct Thread {
|
||||
impl Thread {
|
||||
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
|
||||
pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
|
||||
let p = box p;
|
||||
let p = Box::into_raw(box p);
|
||||
|
||||
// FIXME On UNIX, we guard against stack sizes that are too small but
|
||||
// that's because pthreads enforces that stacks are at least
|
||||
@ -34,21 +33,27 @@ pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
|
||||
ptr::null_mut(),
|
||||
stack_size,
|
||||
thread_start,
|
||||
&*p as *const _ as *mut _,
|
||||
p as *mut _,
|
||||
c::STACK_SIZE_PARAM_IS_A_RESERVATION,
|
||||
ptr::null_mut(),
|
||||
);
|
||||
|
||||
return if ret as usize == 0 {
|
||||
// The thread failed to start and as a result p was not consumed. Therefore, it is
|
||||
// safe to reconstruct the box so that it gets deallocated.
|
||||
drop(Box::from_raw(p));
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
mem::forget(p); // ownership passed to CreateThread
|
||||
Ok(Thread { handle: Handle::new(ret) })
|
||||
};
|
||||
|
||||
extern "system" fn thread_start(main: *mut c_void) -> c::DWORD {
|
||||
unsafe {
|
||||
start_thread(main as *mut u8);
|
||||
// Next, set up our stack overflow handler which may get triggered if we run
|
||||
// out of stack.
|
||||
let _handler = stack_overflow::Handler::new();
|
||||
// Finally, let's run some code.
|
||||
Box::from_raw(main as *mut Box<dyn FnOnce()>)();
|
||||
}
|
||||
0
|
||||
}
|
||||
|
@ -1,18 +1,7 @@
|
||||
use crate::env;
|
||||
use crate::sync::atomic::{self, Ordering};
|
||||
use crate::sys::stack_overflow;
|
||||
use crate::sys::thread as imp;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub unsafe fn start_thread(main: *mut u8) {
|
||||
// Next, set up our stack overflow handler which may get triggered if we run
|
||||
// out of stack.
|
||||
let _handler = stack_overflow::Handler::new();
|
||||
|
||||
// Finally, let's run some code.
|
||||
Box::from_raw(main as *mut Box<dyn FnOnce()>)()
|
||||
}
|
||||
|
||||
pub fn min_stack() -> usize {
|
||||
static MIN: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
|
||||
match MIN.load(Ordering::SeqCst) {
|
||||
|
12
src/test/ui/async-await/issue-70594.rs
Normal file
12
src/test/ui/async-await/issue-70594.rs
Normal file
@ -0,0 +1,12 @@
|
||||
// edition:2018
|
||||
|
||||
async fn fun() {
|
||||
[1; ().await];
|
||||
//~^ error: `await` is only allowed inside `async` functions and blocks
|
||||
//~| error: `.await` is not allowed in a `const`
|
||||
//~| error: `loop` is not allowed in a `const`
|
||||
//~| error: `.await` is not allowed in a `const`
|
||||
//~| error: the trait bound `(): std::future::Future` is not satisfied
|
||||
}
|
||||
|
||||
fn main() {}
|
44
src/test/ui/async-await/issue-70594.stderr
Normal file
44
src/test/ui/async-await/issue-70594.stderr
Normal file
@ -0,0 +1,44 @@
|
||||
error[E0728]: `await` is only allowed inside `async` functions and blocks
|
||||
--> $DIR/issue-70594.rs:4:9
|
||||
|
|
||||
LL | async fn fun() {
|
||||
| --- this is not `async`
|
||||
LL | [1; ().await];
|
||||
| ^^^^^^^^ only allowed inside `async` functions and blocks
|
||||
|
||||
error[E0744]: `.await` is not allowed in a `const`
|
||||
--> $DIR/issue-70594.rs:4:9
|
||||
|
|
||||
LL | [1; ().await];
|
||||
| ^^^^^^^^
|
||||
|
||||
error[E0658]: `loop` is not allowed in a `const`
|
||||
--> $DIR/issue-70594.rs:4:9
|
||||
|
|
||||
LL | [1; ().await];
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
|
||||
= help: add `#![feature(const_loop)]` to the crate attributes to enable
|
||||
|
||||
error[E0744]: `.await` is not allowed in a `const`
|
||||
--> $DIR/issue-70594.rs:4:9
|
||||
|
|
||||
LL | [1; ().await];
|
||||
| ^^^^^^^^
|
||||
|
||||
error[E0277]: the trait bound `(): std::future::Future` is not satisfied
|
||||
--> $DIR/issue-70594.rs:4:9
|
||||
|
|
||||
LL | [1; ().await];
|
||||
| ^^^^^^^^ the trait `std::future::Future` is not implemented for `()`
|
||||
|
|
||||
::: $SRC_DIR/libcore/future/mod.rs:LL:COL
|
||||
|
|
||||
LL | F: Future,
|
||||
| ------ required by this bound in `std::future::poll_with_context`
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0277, E0658, E0728, E0744.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
@ -1,4 +1,4 @@
|
||||
error[E0658]: is unstable
|
||||
error[E0658]: kind="link_cfg" is unstable
|
||||
--> $DIR/feature-gate-link_cfg.rs:1:1
|
||||
|
|
||||
LL | #[link(name = "foo", cfg(foo))]
|
||||
|
12
src/test/ui/issues/issue-70673.rs
Normal file
12
src/test/ui/issues/issue-70673.rs
Normal file
@ -0,0 +1,12 @@
|
||||
// Regression test for https://github.com/rust-lang/rust/issues/70673.
|
||||
|
||||
// run-pass
|
||||
|
||||
#![feature(thread_local)]
|
||||
|
||||
#[thread_local]
|
||||
static A: &u8 = &42;
|
||||
|
||||
fn main() {
|
||||
dbg!(*A);
|
||||
}
|
17
src/test/ui/traits/impl_trait_as_trait_return_position.rs
Normal file
17
src/test/ui/traits/impl_trait_as_trait_return_position.rs
Normal file
@ -0,0 +1,17 @@
|
||||
// check-pass
|
||||
|
||||
trait A {
|
||||
type Foo;
|
||||
}
|
||||
|
||||
impl<T> A for T {
|
||||
type Foo = ();
|
||||
}
|
||||
|
||||
fn foo() -> impl std::borrow::Borrow<<u8 as A>::Foo> {
|
||||
()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
foo();
|
||||
}
|
Loading…
Reference in New Issue
Block a user