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:
bors 2020-04-03 20:56:05 +00:00
commit 74bd074eef
41 changed files with 283 additions and 709 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,11 +1,3 @@
pub struct Handler;
impl Handler {
pub unsafe fn new() -> Handler {
Handler
}
}
#[inline]
pub unsafe fn init() {}

View File

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

View File

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

View File

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

View File

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

View File

@ -1,11 +1,3 @@
pub struct Handler;
impl Handler {
pub unsafe fn new() -> Handler {
Handler
}
}
pub unsafe fn init() {}
pub unsafe fn cleanup() {}

View File

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

View File

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

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

View 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`.

View File

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

View 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);
}

View 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();
}