mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-29 02:03:53 +00:00
Auto merge of #108709 - matthiaskrgr:rollup-j2tjbyx, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - #104549 (add -Zexport-executable-symbols to unstable book) - #108292 (Label opaque type for 'captures lifetime' error message) - #108540 (Add `Atomic*::from_ptr`) - #108634 (Add link to component dashboard) - #108647 (Remove dead pgo.sh file) - #108678 (Use `Option::as_slice` where applicable) - #108681 (Improve comments in `needs_process_obligation`.) - #108688 (Match unmatched backticks in library/) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
70adb4e5b4
@ -426,6 +426,7 @@ impl<O: ForestObligation> ObligationForest<O> {
|
|||||||
// nodes. Therefore we use a `while` loop.
|
// nodes. Therefore we use a `while` loop.
|
||||||
let mut index = 0;
|
let mut index = 0;
|
||||||
while let Some(node) = self.nodes.get_mut(index) {
|
while let Some(node) = self.nodes.get_mut(index) {
|
||||||
|
// This test is extremely hot.
|
||||||
if node.state.get() != NodeState::Pending
|
if node.state.get() != NodeState::Pending
|
||||||
|| !processor.needs_process_obligation(&node.obligation)
|
|| !processor.needs_process_obligation(&node.obligation)
|
||||||
{
|
{
|
||||||
@ -439,6 +440,7 @@ impl<O: ForestObligation> ObligationForest<O> {
|
|||||||
// out of sync with `nodes`. It's not very common, but it does
|
// out of sync with `nodes`. It's not very common, but it does
|
||||||
// happen, and code in `compress` has to allow for it.
|
// happen, and code in `compress` has to allow for it.
|
||||||
|
|
||||||
|
// This code is much less hot.
|
||||||
match processor.process_obligation(&mut node.obligation) {
|
match processor.process_obligation(&mut node.obligation) {
|
||||||
ProcessResult::Unchanged => {
|
ProcessResult::Unchanged => {
|
||||||
// No change in state.
|
// No change in state.
|
||||||
|
@ -36,7 +36,6 @@ use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext}
|
|||||||
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::slice;
|
|
||||||
|
|
||||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
pub(in super::super) fn check_casts(&mut self) {
|
pub(in super::super) fn check_casts(&mut self) {
|
||||||
@ -1507,11 +1506,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
let coerce = if blk.targeted_by_break {
|
let coerce = if blk.targeted_by_break {
|
||||||
CoerceMany::new(coerce_to_ty)
|
CoerceMany::new(coerce_to_ty)
|
||||||
} else {
|
} else {
|
||||||
let tail_expr: &[&hir::Expr<'_>] = match tail_expr {
|
CoerceMany::with_coercion_sites(coerce_to_ty, blk.expr.as_slice())
|
||||||
Some(e) => slice::from_ref(e),
|
|
||||||
None => &[],
|
|
||||||
};
|
|
||||||
CoerceMany::with_coercion_sites(coerce_to_ty, tail_expr)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let prev_diverges = self.diverges.get();
|
let prev_diverges = self.diverges.get();
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#![feature(min_specialization)]
|
#![feature(min_specialization)]
|
||||||
#![feature(control_flow_enum)]
|
#![feature(control_flow_enum)]
|
||||||
#![feature(drain_filter)]
|
#![feature(drain_filter)]
|
||||||
|
#![feature(option_as_slice)]
|
||||||
#![allow(rustc::potential_query_instability)]
|
#![allow(rustc::potential_query_instability)]
|
||||||
#![recursion_limit = "256"]
|
#![recursion_limit = "256"]
|
||||||
|
|
||||||
|
@ -749,14 +749,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let opname = Ident::with_dummy_span(opname);
|
let opname = Ident::with_dummy_span(opname);
|
||||||
let input_types =
|
let (opt_rhs_expr, opt_rhs_ty) = opt_rhs.unzip();
|
||||||
opt_rhs.as_ref().map(|(_, ty)| std::slice::from_ref(ty)).unwrap_or_default();
|
let input_types = opt_rhs_ty.as_slice();
|
||||||
let cause = self.cause(
|
let cause = self.cause(
|
||||||
span,
|
span,
|
||||||
traits::BinOp {
|
traits::BinOp {
|
||||||
rhs_span: opt_rhs.map(|(expr, _)| expr.span),
|
rhs_span: opt_rhs_expr.map(|expr| expr.span),
|
||||||
is_lit: opt_rhs
|
is_lit: opt_rhs_expr
|
||||||
.map_or(false, |(expr, _)| matches!(expr.kind, hir::ExprKind::Lit(_))),
|
.map_or(false, |expr| matches!(expr.kind, hir::ExprKind::Lit(_))),
|
||||||
output_ty: expected.only_has_type(self),
|
output_ty: expected.only_has_type(self),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -11,7 +11,6 @@ use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutabili
|
|||||||
use rustc_middle::ty::{self, Ty};
|
use rustc_middle::ty::{self, Ty};
|
||||||
use rustc_span::symbol::{sym, Ident};
|
use rustc_span::symbol::{sym, Ident};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use std::slice;
|
|
||||||
|
|
||||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
/// Type-check `*oprnd_expr` with `oprnd_expr` type-checked already.
|
/// Type-check `*oprnd_expr` with `oprnd_expr` type-checked already.
|
||||||
@ -393,11 +392,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
Some(self.typeck_results.borrow().node_substs(expr.hir_id).type_at(1))
|
Some(self.typeck_results.borrow().node_substs(expr.hir_id).type_at(1))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let arg_tys = match arg_ty {
|
let arg_tys = arg_ty.as_slice();
|
||||||
None => &[],
|
|
||||||
Some(ref ty) => slice::from_ref(ty),
|
|
||||||
};
|
|
||||||
|
|
||||||
let method = self.try_mutable_overloaded_place_op(expr.span, base_ty, arg_tys, op);
|
let method = self.try_mutable_overloaded_place_op(expr.span, base_ty, arg_tys, op);
|
||||||
let method = match method {
|
let method = match method {
|
||||||
Some(ok) => self.register_infer_ok_obligations(ok),
|
Some(ok) => self.register_infer_ok_obligations(ok),
|
||||||
|
@ -345,3 +345,6 @@ infer_prlf_defined_without_sub = the lifetime defined here...
|
|||||||
infer_prlf_must_oultive_with_sup = ...must outlive the lifetime `{$sup_symbol}` defined here
|
infer_prlf_must_oultive_with_sup = ...must outlive the lifetime `{$sup_symbol}` defined here
|
||||||
infer_prlf_must_oultive_without_sup = ...must outlive the lifetime defined here
|
infer_prlf_must_oultive_without_sup = ...must outlive the lifetime defined here
|
||||||
infer_prlf_known_limitation = this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
|
infer_prlf_known_limitation = this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
|
||||||
|
|
||||||
|
infer_opaque_captures_lifetime = hidden type for `{$opaque_ty}` captures lifetime that does not appear in bounds
|
||||||
|
.label = opaque type defined here
|
||||||
|
@ -1147,3 +1147,13 @@ pub enum PlaceholderRelationLfNotSatisfied {
|
|||||||
note: (),
|
note: (),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(infer_opaque_captures_lifetime, code = "E0700")]
|
||||||
|
pub struct OpaqueCapturesLifetime<'tcx> {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
#[label]
|
||||||
|
pub opaque_ty_span: Span,
|
||||||
|
pub opaque_ty: Ty<'tcx>,
|
||||||
|
}
|
||||||
|
@ -49,6 +49,7 @@ use super::lexical_region_resolve::RegionResolutionError;
|
|||||||
use super::region_constraints::GenericKind;
|
use super::region_constraints::GenericKind;
|
||||||
use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs};
|
use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs};
|
||||||
|
|
||||||
|
use crate::errors;
|
||||||
use crate::infer;
|
use crate::infer;
|
||||||
use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type;
|
use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type;
|
||||||
use crate::infer::ExpectedFound;
|
use crate::infer::ExpectedFound;
|
||||||
@ -281,15 +282,13 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
|
|||||||
span: Span,
|
span: Span,
|
||||||
hidden_ty: Ty<'tcx>,
|
hidden_ty: Ty<'tcx>,
|
||||||
hidden_region: ty::Region<'tcx>,
|
hidden_region: ty::Region<'tcx>,
|
||||||
opaque_ty: ty::OpaqueTypeKey<'tcx>,
|
opaque_ty_key: ty::OpaqueTypeKey<'tcx>,
|
||||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||||
let opaque_ty = tcx.mk_opaque(opaque_ty.def_id.to_def_id(), opaque_ty.substs);
|
let mut err = tcx.sess.create_err(errors::OpaqueCapturesLifetime {
|
||||||
let mut err = struct_span_err!(
|
|
||||||
tcx.sess,
|
|
||||||
span,
|
span,
|
||||||
E0700,
|
opaque_ty: tcx.mk_opaque(opaque_ty_key.def_id.to_def_id(), opaque_ty_key.substs),
|
||||||
"hidden type for `{opaque_ty}` captures lifetime that does not appear in bounds",
|
opaque_ty_span: tcx.def_span(opaque_ty_key.def_id),
|
||||||
);
|
});
|
||||||
|
|
||||||
// Explain the region we are capturing.
|
// Explain the region we are capturing.
|
||||||
match *hidden_region {
|
match *hidden_region {
|
||||||
|
@ -212,36 +212,44 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
|
|||||||
|
|
||||||
/// Identifies whether a predicate obligation needs processing.
|
/// Identifies whether a predicate obligation needs processing.
|
||||||
///
|
///
|
||||||
/// This is always inlined, despite its size, because it has a single
|
/// This is always inlined because it has a single callsite and it is
|
||||||
/// callsite and it is called *very* frequently.
|
/// called *very* frequently. Be careful modifying this code! Several
|
||||||
|
/// compile-time benchmarks are very sensitive to even small changes.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn needs_process_obligation(&self, pending_obligation: &Self::Obligation) -> bool {
|
fn needs_process_obligation(&self, pending_obligation: &Self::Obligation) -> bool {
|
||||||
// If we were stalled on some unresolved variables, first check whether
|
// If we were stalled on some unresolved variables, first check whether
|
||||||
// any of them have been resolved; if not, don't bother doing more work
|
// any of them have been resolved; if not, don't bother doing more work
|
||||||
// yet.
|
// yet.
|
||||||
match pending_obligation.stalled_on.len() {
|
let stalled_on = &pending_obligation.stalled_on;
|
||||||
// Match arms are in order of frequency, which matters because this
|
match stalled_on.len() {
|
||||||
// code is so hot. 1 and 0 dominate; 2+ is fairly rare.
|
// This case is the hottest most of the time, being hit up to 99%
|
||||||
1 => {
|
// of the time. `keccak` and `cranelift-codegen-0.82.1` are
|
||||||
let infer_var = pending_obligation.stalled_on[0];
|
// benchmarks that particularly stress this path.
|
||||||
self.selcx.infcx.ty_or_const_infer_var_changed(infer_var)
|
1 => self.selcx.infcx.ty_or_const_infer_var_changed(stalled_on[0]),
|
||||||
}
|
|
||||||
0 => {
|
// In this case we haven't changed, but wish to make a change. Note
|
||||||
// In this case we haven't changed, but wish to make a change.
|
// that this is a special case, and is not equivalent to the `_`
|
||||||
true
|
// case below, which would return `false` for an empty `stalled_on`
|
||||||
}
|
// vector.
|
||||||
_ => {
|
//
|
||||||
// This `for` loop was once a call to `all()`, but this lower-level
|
// This case is usually hit only 1% of the time or less, though it
|
||||||
// form was a perf win. See #64545 for details.
|
// reaches 20% in `wasmparser-0.101.0`.
|
||||||
(|| {
|
0 => true,
|
||||||
for &infer_var in &pending_obligation.stalled_on {
|
|
||||||
|
// This case is usually hit only 1% of the time or less, though it
|
||||||
|
// reaches 95% in `mime-0.3.16`, 64% in `wast-54.0.0`, and 12% in
|
||||||
|
// `inflate-0.4.5`.
|
||||||
|
//
|
||||||
|
// The obvious way of writing this, with a call to `any()` and no
|
||||||
|
// closure, is currently slower than this version.
|
||||||
|
_ => (|| {
|
||||||
|
for &infer_var in stalled_on {
|
||||||
if self.selcx.infcx.ty_or_const_infer_var_changed(infer_var) {
|
if self.selcx.infcx.ty_or_const_infer_var_changed(infer_var) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
})()
|
})(),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2145,7 +2145,7 @@ impl<T, I: iter::TrustedLen<Item = T>> ToRcSlice<T> for I {
|
|||||||
Rc::from_iter_exact(self, low)
|
Rc::from_iter_exact(self, low)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// TrustedLen contract guarantees that `upper_bound == `None` implies an iterator
|
// TrustedLen contract guarantees that `upper_bound == None` implies an iterator
|
||||||
// length exceeding `usize::MAX`.
|
// length exceeding `usize::MAX`.
|
||||||
// The default implementation would collect into a vec which would panic.
|
// The default implementation would collect into a vec which would panic.
|
||||||
// Thus we panic here immediately without invoking `Vec` code.
|
// Thus we panic here immediately without invoking `Vec` code.
|
||||||
|
@ -2895,7 +2895,7 @@ impl<T, I: iter::TrustedLen<Item = T>> ToArcSlice<T> for I {
|
|||||||
Arc::from_iter_exact(self, low)
|
Arc::from_iter_exact(self, low)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// TrustedLen contract guarantees that `upper_bound == `None` implies an iterator
|
// TrustedLen contract guarantees that `upper_bound == None` implies an iterator
|
||||||
// length exceeding `usize::MAX`.
|
// length exceeding `usize::MAX`.
|
||||||
// The default implementation would collect into a vec which would panic.
|
// The default implementation would collect into a vec which would panic.
|
||||||
// Thus we panic here immediately without invoking `Vec` code.
|
// Thus we panic here immediately without invoking `Vec` code.
|
||||||
|
@ -56,7 +56,7 @@
|
|||||||
//! let value_any = value as &dyn Any;
|
//! let value_any = value as &dyn Any;
|
||||||
//!
|
//!
|
||||||
//! // Try to convert our value to a `String`. If successful, we want to
|
//! // Try to convert our value to a `String`. If successful, we want to
|
||||||
//! // output the String`'s length as well as its value. If not, it's a
|
//! // output the `String`'s length as well as its value. If not, it's a
|
||||||
//! // different type: just print it out unadorned.
|
//! // different type: just print it out unadorned.
|
||||||
//! match value_any.downcast_ref::<String>() {
|
//! match value_any.downcast_ref::<String>() {
|
||||||
//! Some(as_string) => {
|
//! Some(as_string) => {
|
||||||
|
@ -632,7 +632,7 @@ pub struct RefCell<T: ?Sized> {
|
|||||||
// Stores the location of the earliest currently active borrow.
|
// Stores the location of the earliest currently active borrow.
|
||||||
// This gets updated whenever we go from having zero borrows
|
// This gets updated whenever we go from having zero borrows
|
||||||
// to having a single borrow. When a borrow occurs, this gets included
|
// to having a single borrow. When a borrow occurs, this gets included
|
||||||
// in the generated `BorrowError/`BorrowMutError`
|
// in the generated `BorrowError`/`BorrowMutError`
|
||||||
#[cfg(feature = "debug_refcell")]
|
#[cfg(feature = "debug_refcell")]
|
||||||
borrowed_at: Cell<Option<&'static crate::panic::Location<'static>>>,
|
borrowed_at: Cell<Option<&'static crate::panic::Location<'static>>>,
|
||||||
value: UnsafeCell<T>,
|
value: UnsafeCell<T>,
|
||||||
|
@ -42,7 +42,7 @@
|
|||||||
//! another function. The `dialect` and `phase` parameters indicate which [version of MIR][dialect
|
//! another function. The `dialect` and `phase` parameters indicate which [version of MIR][dialect
|
||||||
//! docs] you are inserting here. Generally you'll want to use `#![custom_mir(dialect = "built")]`
|
//! docs] you are inserting here. Generally you'll want to use `#![custom_mir(dialect = "built")]`
|
||||||
//! if you want your MIR to be modified by the full MIR pipeline, or `#![custom_mir(dialect =
|
//! if you want your MIR to be modified by the full MIR pipeline, or `#![custom_mir(dialect =
|
||||||
//! "runtime", phase = "optimized")] if you don't.
|
//! "runtime", phase = "optimized")]` if you don't.
|
||||||
//!
|
//!
|
||||||
//! [dialect docs]:
|
//! [dialect docs]:
|
||||||
//! https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/enum.MirPhase.html
|
//! https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/enum.MirPhase.html
|
||||||
|
@ -41,7 +41,7 @@ impl Alignment {
|
|||||||
/// Returns the alignment for a type.
|
/// Returns the alignment for a type.
|
||||||
///
|
///
|
||||||
/// This provides the same numerical value as [`mem::align_of`],
|
/// This provides the same numerical value as [`mem::align_of`],
|
||||||
/// but in an `Alignment` instead of a `usize.
|
/// but in an `Alignment` instead of a `usize`.
|
||||||
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
|
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn of<T>() -> Self {
|
pub const fn of<T>() -> Self {
|
||||||
|
@ -2955,7 +2955,7 @@ impl<T> [T] {
|
|||||||
// This operation is still `O(n)`.
|
// This operation is still `O(n)`.
|
||||||
//
|
//
|
||||||
// Example: We start in this state, where `r` represents "next
|
// Example: We start in this state, where `r` represents "next
|
||||||
// read" and `w` represents "next_write`.
|
// read" and `w` represents "next_write".
|
||||||
//
|
//
|
||||||
// r
|
// r
|
||||||
// +---+---+---+---+---+---+
|
// +---+---+---+---+---+---+
|
||||||
|
@ -317,7 +317,7 @@ where
|
|||||||
// 1. `block` - Number of elements in the block.
|
// 1. `block` - Number of elements in the block.
|
||||||
// 2. `start` - Start pointer into the `offsets` array.
|
// 2. `start` - Start pointer into the `offsets` array.
|
||||||
// 3. `end` - End pointer into the `offsets` array.
|
// 3. `end` - End pointer into the `offsets` array.
|
||||||
// 4. `offsets - Indices of out-of-order elements within the block.
|
// 4. `offsets` - Indices of out-of-order elements within the block.
|
||||||
|
|
||||||
// The current block on the left side (from `l` to `l.add(block_l)`).
|
// The current block on the left side (from `l` to `l.add(block_l)`).
|
||||||
let mut l = v.as_mut_ptr();
|
let mut l = v.as_mut_ptr();
|
||||||
@ -327,7 +327,7 @@ where
|
|||||||
let mut offsets_l = [MaybeUninit::<u8>::uninit(); BLOCK];
|
let mut offsets_l = [MaybeUninit::<u8>::uninit(); BLOCK];
|
||||||
|
|
||||||
// The current block on the right side (from `r.sub(block_r)` to `r`).
|
// The current block on the right side (from `r.sub(block_r)` to `r`).
|
||||||
// SAFETY: The documentation for .add() specifically mention that `vec.as_ptr().add(vec.len())` is always safe`
|
// SAFETY: The documentation for .add() specifically mention that `vec.as_ptr().add(vec.len())` is always safe
|
||||||
let mut r = unsafe { l.add(v.len()) };
|
let mut r = unsafe { l.add(v.len()) };
|
||||||
let mut block_r = BLOCK;
|
let mut block_r = BLOCK;
|
||||||
let mut start_r = ptr::null_mut();
|
let mut start_r = ptr::null_mut();
|
||||||
|
@ -305,6 +305,50 @@ impl AtomicBool {
|
|||||||
AtomicBool { v: UnsafeCell::new(v as u8) }
|
AtomicBool { v: UnsafeCell::new(v as u8) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new `AtomicBool` from a pointer.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(atomic_from_ptr, pointer_is_aligned)]
|
||||||
|
/// use std::sync::atomic::{self, AtomicBool};
|
||||||
|
/// use std::mem::align_of;
|
||||||
|
///
|
||||||
|
/// // Get a pointer to an allocated value
|
||||||
|
/// let ptr: *mut bool = Box::into_raw(Box::new(false));
|
||||||
|
///
|
||||||
|
/// assert!(ptr.is_aligned_to(align_of::<AtomicBool>()));
|
||||||
|
///
|
||||||
|
/// {
|
||||||
|
/// // Create an atomic view of the allocated value
|
||||||
|
/// let atomic = unsafe { AtomicBool::from_ptr(ptr) };
|
||||||
|
///
|
||||||
|
/// // Use `atomic` for atomic operations, possibly share it with other threads
|
||||||
|
/// atomic.store(true, atomic::Ordering::Relaxed);
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // It's ok to non-atomically access the value behind `ptr`,
|
||||||
|
/// // since the reference to the atomic ended its lifetime in the block above
|
||||||
|
/// assert_eq!(unsafe { *ptr }, true);
|
||||||
|
///
|
||||||
|
/// // Deallocate the value
|
||||||
|
/// unsafe { drop(Box::from_raw(ptr)) }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// * `ptr` must be aligned to `align_of::<AtomicBool>()` (note that on some platforms this can be bigger than `align_of::<bool>()`).
|
||||||
|
/// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
|
||||||
|
/// * The value behind `ptr` must not be accessed through non-atomic operations for the whole lifetime `'a`.
|
||||||
|
///
|
||||||
|
/// [valid]: crate::ptr#safety
|
||||||
|
#[unstable(feature = "atomic_from_ptr", issue = "108652")]
|
||||||
|
#[rustc_const_unstable(feature = "atomic_from_ptr", issue = "108652")]
|
||||||
|
pub const unsafe fn from_ptr<'a>(ptr: *mut bool) -> &'a AtomicBool {
|
||||||
|
// SAFETY: guaranteed by the caller
|
||||||
|
unsafe { &*ptr.cast() }
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a mutable reference to the underlying [`bool`].
|
/// Returns a mutable reference to the underlying [`bool`].
|
||||||
///
|
///
|
||||||
/// This is safe because the mutable reference guarantees that no other threads are
|
/// This is safe because the mutable reference guarantees that no other threads are
|
||||||
@ -1017,6 +1061,50 @@ impl<T> AtomicPtr<T> {
|
|||||||
AtomicPtr { p: UnsafeCell::new(p) }
|
AtomicPtr { p: UnsafeCell::new(p) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new `AtomicPtr` from a pointer.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(atomic_from_ptr, pointer_is_aligned)]
|
||||||
|
/// use std::sync::atomic::{self, AtomicPtr};
|
||||||
|
/// use std::mem::align_of;
|
||||||
|
///
|
||||||
|
/// // Get a pointer to an allocated value
|
||||||
|
/// let ptr: *mut *mut u8 = Box::into_raw(Box::new(std::ptr::null_mut()));
|
||||||
|
///
|
||||||
|
/// assert!(ptr.is_aligned_to(align_of::<AtomicPtr<u8>>()));
|
||||||
|
///
|
||||||
|
/// {
|
||||||
|
/// // Create an atomic view of the allocated value
|
||||||
|
/// let atomic = unsafe { AtomicPtr::from_ptr(ptr) };
|
||||||
|
///
|
||||||
|
/// // Use `atomic` for atomic operations, possibly share it with other threads
|
||||||
|
/// atomic.store(std::ptr::NonNull::dangling().as_ptr(), atomic::Ordering::Relaxed);
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // It's ok to non-atomically access the value behind `ptr`,
|
||||||
|
/// // since the reference to the atomic ended its lifetime in the block above
|
||||||
|
/// assert!(!unsafe { *ptr }.is_null());
|
||||||
|
///
|
||||||
|
/// // Deallocate the value
|
||||||
|
/// unsafe { drop(Box::from_raw(ptr)) }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// * `ptr` must be aligned to `align_of::<AtomicPtr<T>>()` (note that on some platforms this can be bigger than `align_of::<*mut T>()`).
|
||||||
|
/// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
|
||||||
|
/// * The value behind `ptr` must not be accessed through non-atomic operations for the whole lifetime `'a`.
|
||||||
|
///
|
||||||
|
/// [valid]: crate::ptr#safety
|
||||||
|
#[unstable(feature = "atomic_from_ptr", issue = "108652")]
|
||||||
|
#[rustc_const_unstable(feature = "atomic_from_ptr", issue = "108652")]
|
||||||
|
pub const unsafe fn from_ptr<'a>(ptr: *mut *mut T) -> &'a AtomicPtr<T> {
|
||||||
|
// SAFETY: guaranteed by the caller
|
||||||
|
unsafe { &*ptr.cast() }
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a mutable reference to the underlying pointer.
|
/// Returns a mutable reference to the underlying pointer.
|
||||||
///
|
///
|
||||||
/// This is safe because the mutable reference guarantees that no other threads are
|
/// This is safe because the mutable reference guarantees that no other threads are
|
||||||
@ -1958,6 +2046,53 @@ macro_rules! atomic_int {
|
|||||||
Self {v: UnsafeCell::new(v)}
|
Self {v: UnsafeCell::new(v)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new reference to an atomic integer from a pointer.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(atomic_from_ptr, pointer_is_aligned)]
|
||||||
|
#[doc = concat!($extra_feature, "use std::sync::atomic::{self, ", stringify!($atomic_type), "};")]
|
||||||
|
/// use std::mem::align_of;
|
||||||
|
///
|
||||||
|
/// // Get a pointer to an allocated value
|
||||||
|
#[doc = concat!("let ptr: *mut ", stringify!($int_type), " = Box::into_raw(Box::new(0));")]
|
||||||
|
///
|
||||||
|
#[doc = concat!("assert!(ptr.is_aligned_to(align_of::<", stringify!($atomic_type), ">()));")]
|
||||||
|
///
|
||||||
|
/// {
|
||||||
|
/// // Create an atomic view of the allocated value
|
||||||
|
// SAFETY: this is a doc comment, tidy, it can't hurt you (also guaranteed by the construction of `ptr` and the assert above)
|
||||||
|
#[doc = concat!(" let atomic = unsafe {", stringify!($atomic_type), "::from_ptr(ptr) };")]
|
||||||
|
///
|
||||||
|
/// // Use `atomic` for atomic operations, possibly share it with other threads
|
||||||
|
/// atomic.store(1, atomic::Ordering::Relaxed);
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // It's ok to non-atomically access the value behind `ptr`,
|
||||||
|
/// // since the reference to the atomic ended its lifetime in the block above
|
||||||
|
/// assert_eq!(unsafe { *ptr }, 1);
|
||||||
|
///
|
||||||
|
/// // Deallocate the value
|
||||||
|
/// unsafe { drop(Box::from_raw(ptr)) }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// * `ptr` must be aligned to `align_of::<AtomicBool>()` (note that on some platforms this can be bigger than `align_of::<bool>()`).
|
||||||
|
#[doc = concat!(" * `ptr` must be aligned to `align_of::<", stringify!($atomic_type), ">()` (note that on some platforms this can be bigger than `align_of::<", stringify!($int_type), ">()`).")]
|
||||||
|
/// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
|
||||||
|
/// * The value behind `ptr` must not be accessed through non-atomic operations for the whole lifetime `'a`.
|
||||||
|
///
|
||||||
|
/// [valid]: crate::ptr#safety
|
||||||
|
#[unstable(feature = "atomic_from_ptr", issue = "108652")]
|
||||||
|
#[rustc_const_unstable(feature = "atomic_from_ptr", issue = "108652")]
|
||||||
|
pub const unsafe fn from_ptr<'a>(ptr: *mut $int_type) -> &'a $atomic_type {
|
||||||
|
// SAFETY: guaranteed by the caller
|
||||||
|
unsafe { &*ptr.cast() }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Returns a mutable reference to the underlying integer.
|
/// Returns a mutable reference to the underlying integer.
|
||||||
///
|
///
|
||||||
/// This is safe because the mutable reference guarantees that no other threads are
|
/// This is safe because the mutable reference guarantees that no other threads are
|
||||||
|
@ -24,7 +24,7 @@ mod zip;
|
|||||||
|
|
||||||
use core::cell::Cell;
|
use core::cell::Cell;
|
||||||
|
|
||||||
/// An iterator that panics whenever `next` or next_back` is called
|
/// An iterator that panics whenever `next` or `next_back` is called
|
||||||
/// after `None` has already been returned. This does not violate
|
/// after `None` has already been returned. This does not violate
|
||||||
/// `Iterator`'s contract. Used to test that iterator adapters don't
|
/// `Iterator`'s contract. Used to test that iterator adapters don't
|
||||||
/// poll their inner iterators after exhausting them.
|
/// poll their inner iterators after exhausting them.
|
||||||
|
@ -28,7 +28,7 @@ use crate::simd::{
|
|||||||
/// let zm_add = a0.zip(a1).map(|(lhs, rhs)| lhs + rhs);
|
/// let zm_add = a0.zip(a1).map(|(lhs, rhs)| lhs + rhs);
|
||||||
/// let zm_mul = a0.zip(a1).map(|(lhs, rhs)| lhs * rhs);
|
/// let zm_mul = a0.zip(a1).map(|(lhs, rhs)| lhs * rhs);
|
||||||
///
|
///
|
||||||
/// // `Simd<T, N>` implements `From<[T; N]>
|
/// // `Simd<T, N>` implements `From<[T; N]>`
|
||||||
/// let (v0, v1) = (Simd::from(a0), Simd::from(a1));
|
/// let (v0, v1) = (Simd::from(a0), Simd::from(a1));
|
||||||
/// // Which means arrays implement `Into<Simd<T, N>>`.
|
/// // Which means arrays implement `Into<Simd<T, N>>`.
|
||||||
/// assert_eq!(v0 + v1, zm_add.into());
|
/// assert_eq!(v0 + v1, zm_add.into());
|
||||||
|
@ -1416,7 +1416,7 @@ impl From<fs::File> for Stdio {
|
|||||||
/// use std::fs::File;
|
/// use std::fs::File;
|
||||||
/// use std::process::Command;
|
/// use std::process::Command;
|
||||||
///
|
///
|
||||||
/// // With the `foo.txt` file containing `Hello, world!"
|
/// // With the `foo.txt` file containing "Hello, world!"
|
||||||
/// let file = File::open("foo.txt").unwrap();
|
/// let file = File::open("foo.txt").unwrap();
|
||||||
///
|
///
|
||||||
/// let reverse = Command::new("rev")
|
/// let reverse = Command::new("rev")
|
||||||
|
@ -247,7 +247,7 @@ impl Thread {
|
|||||||
// [FINISHED → JOINED]
|
// [FINISHED → JOINED]
|
||||||
// To synchronize with the child task's memory accesses to
|
// To synchronize with the child task's memory accesses to
|
||||||
// `inner` up to the point of the assignment of `FINISHED`,
|
// `inner` up to the point of the assignment of `FINISHED`,
|
||||||
// `Ordering::Acquire` must be used for the above `swap` call`.
|
// `Ordering::Acquire` must be used for the above `swap` call.
|
||||||
}
|
}
|
||||||
_ => unsafe { hint::unreachable_unchecked() },
|
_ => unsafe { hint::unreachable_unchecked() },
|
||||||
}
|
}
|
||||||
|
@ -329,7 +329,7 @@ pub fn cvt_nz(error: libc::c_int) -> crate::io::Result<()> {
|
|||||||
// do so. In 1003.1-2004 this was fixed.
|
// do so. In 1003.1-2004 this was fixed.
|
||||||
//
|
//
|
||||||
// glibc's implementation did the flush, unsafely, before glibc commit
|
// glibc's implementation did the flush, unsafely, before glibc commit
|
||||||
// 91e7cf982d01 `abort: Do not flush stdio streams [BZ #15436]' by Florian
|
// 91e7cf982d01 `abort: Do not flush stdio streams [BZ #15436]` by Florian
|
||||||
// Weimer. According to glibc's NEWS:
|
// Weimer. According to glibc's NEWS:
|
||||||
//
|
//
|
||||||
// The abort function terminates the process immediately, without flushing
|
// The abort function terminates the process immediately, without flushing
|
||||||
|
@ -6,7 +6,7 @@ fn no_lookup_host_duplicates() {
|
|||||||
let mut addrs = HashMap::new();
|
let mut addrs = HashMap::new();
|
||||||
let lh = match LookupHost::try_from(("localhost", 0)) {
|
let lh = match LookupHost::try_from(("localhost", 0)) {
|
||||||
Ok(lh) => lh,
|
Ok(lh) => lh,
|
||||||
Err(e) => panic!("couldn't resolve `localhost': {e}"),
|
Err(e) => panic!("couldn't resolve `localhost`: {e}"),
|
||||||
};
|
};
|
||||||
for sa in lh {
|
for sa in lh {
|
||||||
*addrs.entry(sa).or_insert(0) += 1;
|
*addrs.entry(sa).or_insert(0) += 1;
|
||||||
|
@ -594,7 +594,7 @@ impl Wtf8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the code point at `position` if it is in the ASCII range,
|
/// Returns the code point at `position` if it is in the ASCII range,
|
||||||
/// or `b'\xFF' otherwise.
|
/// or `b'\xFF'` otherwise.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
|
@ -204,7 +204,7 @@ fn make_owned_test(test: &&TestDescAndFn) -> TestDescAndFn {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Invoked when unit tests terminate. Returns `Result::Err` if the test is
|
/// Invoked when unit tests terminate. Returns `Result::Err` if the test is
|
||||||
/// considered a failure. By default, invokes `report() and checks for a `0`
|
/// considered a failure. By default, invokes `report()` and checks for a `0`
|
||||||
/// result.
|
/// result.
|
||||||
pub fn assert_test_result<T: Termination>(result: T) -> Result<(), String> {
|
pub fn assert_test_result<T: Termination>(result: T) -> Result<(), String> {
|
||||||
let code = result.report().to_i32();
|
let code = result.report().to_i32();
|
||||||
|
@ -89,7 +89,7 @@ pub type _Unwind_Exception_Cleanup_Fn =
|
|||||||
|
|
||||||
// FIXME: The `#[link]` attributes on `extern "C"` block marks those symbols declared in
|
// FIXME: The `#[link]` attributes on `extern "C"` block marks those symbols declared in
|
||||||
// the block are reexported in dylib build of std. This is needed when build rustc with
|
// the block are reexported in dylib build of std. This is needed when build rustc with
|
||||||
// feature `llvm-libunwind', as no other cdylib will provided those _Unwind_* symbols.
|
// feature `llvm-libunwind`, as no other cdylib will provided those _Unwind_* symbols.
|
||||||
// However the `link` attribute is duplicated multiple times and does not just export symbol,
|
// However the `link` attribute is duplicated multiple times and does not just export symbol,
|
||||||
// a better way to manually export symbol would be another attribute like `#[export]`.
|
// a better way to manually export symbol would be another attribute like `#[export]`.
|
||||||
// See the logic in function rustc_codegen_ssa::src::back::exported_symbols, module
|
// See the logic in function rustc_codegen_ssa::src::back::exported_symbols, module
|
||||||
|
230
src/ci/pgo.sh
230
src/ci/pgo.sh
@ -1,230 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# ignore-tidy-linelength
|
|
||||||
|
|
||||||
set -euxo pipefail
|
|
||||||
|
|
||||||
ci_dir=`cd $(dirname $0) && pwd`
|
|
||||||
source "$ci_dir/shared.sh"
|
|
||||||
|
|
||||||
# The root checkout, where the source is located
|
|
||||||
CHECKOUT=/checkout
|
|
||||||
|
|
||||||
DOWNLOADED_LLVM=/rustroot
|
|
||||||
|
|
||||||
# The main directory where the build occurs, which can be different between linux and windows
|
|
||||||
BUILD_ROOT=$CHECKOUT/obj
|
|
||||||
|
|
||||||
if isWindows; then
|
|
||||||
CHECKOUT=$(pwd)
|
|
||||||
DOWNLOADED_LLVM=$CHECKOUT/citools/clang-rust
|
|
||||||
BUILD_ROOT=$CHECKOUT
|
|
||||||
fi
|
|
||||||
|
|
||||||
# The various build artifacts used in other commands: to launch rustc builds, build the perf
|
|
||||||
# collector, and run benchmarks to gather profiling data
|
|
||||||
BUILD_ARTIFACTS=$BUILD_ROOT/build/$PGO_HOST
|
|
||||||
RUSTC_STAGE_0=$BUILD_ARTIFACTS/stage0/bin/rustc
|
|
||||||
CARGO_STAGE_0=$BUILD_ARTIFACTS/stage0/bin/cargo
|
|
||||||
RUSTC_STAGE_2=$BUILD_ARTIFACTS/stage2/bin/rustc
|
|
||||||
|
|
||||||
# Windows needs these to have the .exe extension
|
|
||||||
if isWindows; then
|
|
||||||
RUSTC_STAGE_0="${RUSTC_STAGE_0}.exe"
|
|
||||||
CARGO_STAGE_0="${CARGO_STAGE_0}.exe"
|
|
||||||
RUSTC_STAGE_2="${RUSTC_STAGE_2}.exe"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Make sure we have a temporary PGO work folder
|
|
||||||
PGO_TMP=/tmp/tmp-pgo
|
|
||||||
mkdir -p $PGO_TMP
|
|
||||||
rm -rf $PGO_TMP/*
|
|
||||||
|
|
||||||
RUSTC_PERF=$PGO_TMP/rustc-perf
|
|
||||||
|
|
||||||
# Compile several crates to gather execution PGO profiles.
|
|
||||||
# Arg0 => profiles (Debug, Opt)
|
|
||||||
# Arg1 => scenarios (Full, IncrFull, All)
|
|
||||||
# Arg2 => crates (syn, cargo, ...)
|
|
||||||
gather_profiles () {
|
|
||||||
cd $BUILD_ROOT
|
|
||||||
|
|
||||||
# Compile libcore, both in opt-level=0 and opt-level=3
|
|
||||||
RUSTC_BOOTSTRAP=1 $RUSTC_STAGE_2 \
|
|
||||||
--edition=2021 --crate-type=lib $CHECKOUT/library/core/src/lib.rs \
|
|
||||||
--out-dir $PGO_TMP
|
|
||||||
RUSTC_BOOTSTRAP=1 $RUSTC_STAGE_2 \
|
|
||||||
--edition=2021 --crate-type=lib -Copt-level=3 $CHECKOUT/library/core/src/lib.rs \
|
|
||||||
--out-dir $PGO_TMP
|
|
||||||
|
|
||||||
cd $RUSTC_PERF
|
|
||||||
|
|
||||||
# Run rustc-perf benchmarks
|
|
||||||
# Benchmark using profile_local with eprintln, which essentially just means
|
|
||||||
# don't actually benchmark -- just make sure we run rustc a bunch of times.
|
|
||||||
RUST_LOG=collector=debug \
|
|
||||||
RUSTC=$RUSTC_STAGE_0 \
|
|
||||||
RUSTC_BOOTSTRAP=1 \
|
|
||||||
$CARGO_STAGE_0 run -p collector --bin collector -- \
|
|
||||||
profile_local \
|
|
||||||
eprintln \
|
|
||||||
$RUSTC_STAGE_2 \
|
|
||||||
--id Test \
|
|
||||||
--profiles $1 \
|
|
||||||
--cargo $CARGO_STAGE_0 \
|
|
||||||
--scenarios $2 \
|
|
||||||
--include $3
|
|
||||||
|
|
||||||
cd $BUILD_ROOT
|
|
||||||
}
|
|
||||||
|
|
||||||
# This path has to be absolute
|
|
||||||
LLVM_PROFILE_DIRECTORY_ROOT=$PGO_TMP/llvm-pgo
|
|
||||||
|
|
||||||
# We collect LLVM profiling information and rustc profiling information in
|
|
||||||
# separate phases. This increases build time -- though not by a huge amount --
|
|
||||||
# but prevents any problems from arising due to different profiling runtimes
|
|
||||||
# being simultaneously linked in.
|
|
||||||
# LLVM IR PGO does not respect LLVM_PROFILE_FILE, so we have to set the profiling file
|
|
||||||
# path through our custom environment variable. We include the PID in the directory path
|
|
||||||
# to avoid updates to profile files being lost because of race conditions.
|
|
||||||
LLVM_PROFILE_DIR=${LLVM_PROFILE_DIRECTORY_ROOT}/prof-%p python3 $CHECKOUT/x.py build \
|
|
||||||
--target=$PGO_HOST \
|
|
||||||
--host=$PGO_HOST \
|
|
||||||
--stage 2 library/std \
|
|
||||||
--llvm-profile-generate
|
|
||||||
|
|
||||||
# Compile rustc-perf:
|
|
||||||
# - get the expected commit source code: on linux, the Dockerfile downloads a source archive before
|
|
||||||
# running this script. On Windows, we do that here.
|
|
||||||
if isLinux; then
|
|
||||||
cp -r /tmp/rustc-perf $RUSTC_PERF
|
|
||||||
chown -R $(whoami): $RUSTC_PERF
|
|
||||||
else
|
|
||||||
# rustc-perf version from 2022-07-22
|
|
||||||
PERF_COMMIT=3c253134664fdcba862c539d37f0de18557a9a4c
|
|
||||||
retry curl -LS -o $PGO_TMP/perf.zip \
|
|
||||||
https://github.com/rust-lang/rustc-perf/archive/$PERF_COMMIT.zip && \
|
|
||||||
cd $PGO_TMP && unzip -q perf.zip && \
|
|
||||||
mv rustc-perf-$PERF_COMMIT $RUSTC_PERF && \
|
|
||||||
rm perf.zip
|
|
||||||
fi
|
|
||||||
|
|
||||||
# - build rustc-perf's collector ahead of time, which is needed to make sure the rustc-fake binary
|
|
||||||
# used by the collector is present.
|
|
||||||
cd $RUSTC_PERF
|
|
||||||
|
|
||||||
RUSTC=$RUSTC_STAGE_0 \
|
|
||||||
RUSTC_BOOTSTRAP=1 \
|
|
||||||
$CARGO_STAGE_0 build -p collector
|
|
||||||
|
|
||||||
# Here we're profiling LLVM, so we only care about `Debug` and `Opt`, because we want to stress
|
|
||||||
# codegen. We also profile some of the most prolific crates.
|
|
||||||
gather_profiles "Debug,Opt" "Full" \
|
|
||||||
"syn-1.0.89,cargo-0.60.0,serde-1.0.136,ripgrep-13.0.0,regex-1.5.5,clap-3.1.6,hyper-0.14.18"
|
|
||||||
|
|
||||||
LLVM_PROFILE_MERGED_FILE=$PGO_TMP/llvm-pgo.profdata
|
|
||||||
|
|
||||||
# Merge the profile data we gathered for LLVM
|
|
||||||
# Note that this uses the profdata from the clang we used to build LLVM,
|
|
||||||
# which likely has a different version than our in-tree clang.
|
|
||||||
$DOWNLOADED_LLVM/bin/llvm-profdata merge -o ${LLVM_PROFILE_MERGED_FILE} ${LLVM_PROFILE_DIRECTORY_ROOT}
|
|
||||||
|
|
||||||
echo "LLVM PGO statistics"
|
|
||||||
du -sh ${LLVM_PROFILE_MERGED_FILE}
|
|
||||||
du -sh ${LLVM_PROFILE_DIRECTORY_ROOT}
|
|
||||||
echo "Profile file count"
|
|
||||||
find ${LLVM_PROFILE_DIRECTORY_ROOT} -type f | wc -l
|
|
||||||
|
|
||||||
# We don't need the individual .profraw files now that they have been merged into a final .profdata
|
|
||||||
rm -r $LLVM_PROFILE_DIRECTORY_ROOT
|
|
||||||
|
|
||||||
# Rustbuild currently doesn't support rebuilding LLVM when PGO options
|
|
||||||
# change (or any other llvm-related options); so just clear out the relevant
|
|
||||||
# directories ourselves.
|
|
||||||
rm -r $BUILD_ARTIFACTS/llvm $BUILD_ARTIFACTS/lld
|
|
||||||
|
|
||||||
# Okay, LLVM profiling is done, switch to rustc PGO.
|
|
||||||
|
|
||||||
# The path has to be absolute
|
|
||||||
RUSTC_PROFILE_DIRECTORY_ROOT=$PGO_TMP/rustc-pgo
|
|
||||||
|
|
||||||
python3 $CHECKOUT/x.py build --target=$PGO_HOST --host=$PGO_HOST \
|
|
||||||
--stage 2 library/std \
|
|
||||||
--rust-profile-generate=${RUSTC_PROFILE_DIRECTORY_ROOT}
|
|
||||||
|
|
||||||
# Here we're profiling the `rustc` frontend, so we also include `Check`.
|
|
||||||
# The benchmark set includes various stress tests that put the frontend under pressure.
|
|
||||||
if isLinux; then
|
|
||||||
# The profile data is written into a single filepath that is being repeatedly merged when each
|
|
||||||
# rustc invocation ends. Empirically, this can result in some profiling data being lost. That's
|
|
||||||
# why we override the profile path to include the PID. This will produce many more profiling
|
|
||||||
# files, but the resulting profile will produce a slightly faster rustc binary.
|
|
||||||
LLVM_PROFILE_FILE=${RUSTC_PROFILE_DIRECTORY_ROOT}/default_%m_%p.profraw gather_profiles \
|
|
||||||
"Check,Debug,Opt" "All" \
|
|
||||||
"externs,ctfe-stress-5,cargo-0.60.0,token-stream-stress,match-stress,tuple-stress,diesel-1.4.8,bitmaps-3.1.0"
|
|
||||||
else
|
|
||||||
# On windows, we don't do that yet (because it generates a lot of data, hitting disk space
|
|
||||||
# limits on the builder), and use the default profraw merging behavior.
|
|
||||||
gather_profiles \
|
|
||||||
"Check,Debug,Opt" "All" \
|
|
||||||
"externs,ctfe-stress-5,cargo-0.60.0,token-stream-stress,match-stress,tuple-stress,diesel-1.4.8,bitmaps-3.1.0"
|
|
||||||
fi
|
|
||||||
|
|
||||||
RUSTC_PROFILE_MERGED_FILE=$PGO_TMP/rustc-pgo.profdata
|
|
||||||
|
|
||||||
# Merge the profile data we gathered
|
|
||||||
$BUILD_ARTIFACTS/llvm/bin/llvm-profdata \
|
|
||||||
merge -o ${RUSTC_PROFILE_MERGED_FILE} ${RUSTC_PROFILE_DIRECTORY_ROOT}
|
|
||||||
|
|
||||||
echo "Rustc PGO statistics"
|
|
||||||
du -sh ${RUSTC_PROFILE_MERGED_FILE}
|
|
||||||
du -sh ${RUSTC_PROFILE_DIRECTORY_ROOT}
|
|
||||||
echo "Profile file count"
|
|
||||||
find ${RUSTC_PROFILE_DIRECTORY_ROOT} -type f | wc -l
|
|
||||||
|
|
||||||
# We don't need the individual .profraw files now that they have been merged into a final .profdata
|
|
||||||
rm -r $RUSTC_PROFILE_DIRECTORY_ROOT
|
|
||||||
|
|
||||||
# Rustbuild currently doesn't support rebuilding LLVM when PGO options
|
|
||||||
# change (or any other llvm-related options); so just clear out the relevant
|
|
||||||
# directories ourselves.
|
|
||||||
rm -r $BUILD_ARTIFACTS/llvm $BUILD_ARTIFACTS/lld
|
|
||||||
|
|
||||||
if isLinux; then
|
|
||||||
# Gather BOLT profile (BOLT is currently only available on Linux)
|
|
||||||
python3 ../x.py build --target=$PGO_HOST --host=$PGO_HOST \
|
|
||||||
--stage 2 library/std \
|
|
||||||
--llvm-profile-use=${LLVM_PROFILE_MERGED_FILE} \
|
|
||||||
--llvm-bolt-profile-generate
|
|
||||||
|
|
||||||
BOLT_PROFILE_MERGED_FILE=/tmp/bolt.profdata
|
|
||||||
|
|
||||||
# Here we're profiling Bolt.
|
|
||||||
gather_profiles "Check,Debug,Opt" "Full" \
|
|
||||||
"syn-1.0.89,serde-1.0.136,ripgrep-13.0.0,regex-1.5.5,clap-3.1.6,hyper-0.14.18"
|
|
||||||
|
|
||||||
merge-fdata /tmp/prof.fdata* > ${BOLT_PROFILE_MERGED_FILE}
|
|
||||||
|
|
||||||
echo "BOLT statistics"
|
|
||||||
du -sh /tmp/prof.fdata*
|
|
||||||
du -sh ${BOLT_PROFILE_MERGED_FILE}
|
|
||||||
echo "Profile file count"
|
|
||||||
find /tmp/prof.fdata* -type f | wc -l
|
|
||||||
|
|
||||||
rm -r $BUILD_ARTIFACTS/llvm $BUILD_ARTIFACTS/lld
|
|
||||||
|
|
||||||
# This produces the actual final set of artifacts, using both the LLVM and rustc
|
|
||||||
# collected profiling data.
|
|
||||||
$@ \
|
|
||||||
--rust-profile-use=${RUSTC_PROFILE_MERGED_FILE} \
|
|
||||||
--llvm-profile-use=${LLVM_PROFILE_MERGED_FILE} \
|
|
||||||
--llvm-bolt-profile-use=${BOLT_PROFILE_MERGED_FILE}
|
|
||||||
else
|
|
||||||
$@ \
|
|
||||||
--rust-profile-use=${RUSTC_PROFILE_MERGED_FILE} \
|
|
||||||
--llvm-profile-use=${LLVM_PROFILE_MERGED_FILE}
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Rustc binary size"
|
|
||||||
ls -la ./build/$PGO_HOST/stage2/bin
|
|
||||||
ls -la ./build/$PGO_HOST/stage2/lib
|
|
@ -13,6 +13,8 @@ for targets at each tier, see the [Target Tier Policy](target-tier-policy.md).
|
|||||||
Targets are identified by their "target triple" which is the string to inform
|
Targets are identified by their "target triple" which is the string to inform
|
||||||
the compiler what kind of output should be produced.
|
the compiler what kind of output should be produced.
|
||||||
|
|
||||||
|
Component availability is tracked [here](https://rust-lang.github.io/rustup-components-history/).
|
||||||
|
|
||||||
## Tier 1 with Host Tools
|
## Tier 1 with Host Tools
|
||||||
|
|
||||||
Tier 1 targets can be thought of as "guaranteed to work". The Rust project
|
Tier 1 targets can be thought of as "guaranteed to work". The Rust project
|
||||||
|
@ -0,0 +1,43 @@
|
|||||||
|
# `export-executable-symbols`
|
||||||
|
|
||||||
|
The tracking issue for this feature is: [#84161](https://github.com/rust-lang/rust/issues/84161).
|
||||||
|
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
The `-Zexport-executable-symbols` compiler flag makes `rustc` export symbols from executables. The resulting binary is runnable, but can also be used as a dynamic library. This is useful for interoperating with programs written in other languages, in particular languages with a runtime like Java or Lua.
|
||||||
|
|
||||||
|
For example on windows:
|
||||||
|
```rust
|
||||||
|
#[no_mangle]
|
||||||
|
fn my_function() -> usize {
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("Hello, world!");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
A standard `cargo build` will produce a `.exe` without an export directory. When the `export-executable-symbols` flag is added
|
||||||
|
|
||||||
|
```Bash
|
||||||
|
export RUSTFLAGS="-Zexport-executable-symbols"
|
||||||
|
cargo build
|
||||||
|
```
|
||||||
|
|
||||||
|
the binary has an export directory with the functions:
|
||||||
|
|
||||||
|
```plain
|
||||||
|
The Export Tables (interpreted .edata section contents)
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
[Ordinal/Name Pointer] Table
|
||||||
|
[ 0] my_function
|
||||||
|
[ 1] main
|
||||||
|
```
|
||||||
|
(the output of `objdump -x` on the binary)
|
||||||
|
|
||||||
|
Please note that the `#[no_mangle]` attribute is required. Without it, the symbol is not exported.
|
||||||
|
|
||||||
|
The equivalent of this flag in C and C++ compilers is the `__declspec(dllexport)` annotation or the `-rdynamic` linker flag.
|
@ -17,8 +17,9 @@ error[E0700]: hidden type for `impl Trait<'a>` captures lifetime that does not a
|
|||||||
--> $DIR/ret-impl-trait-one.rs:16:80
|
--> $DIR/ret-impl-trait-one.rs:16:80
|
||||||
|
|
|
|
||||||
LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
|
LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
|
||||||
| ____________________________________--__________________________________________^
|
| ____________________________________--___________________________--------------_^
|
||||||
| | |
|
| | | |
|
||||||
|
| | | opaque type defined here
|
||||||
| | hidden type `(&'a u8, &'b u8)` captures the lifetime `'b` as defined here
|
| | hidden type `(&'a u8, &'b u8)` captures the lifetime `'b` as defined here
|
||||||
LL | |
|
LL | |
|
||||||
LL | | (a, b)
|
LL | | (a, b)
|
||||||
|
@ -2,7 +2,9 @@ error[E0700]: hidden type for `impl Swap + 'a` captures lifetime that does not a
|
|||||||
--> $DIR/hidden-lifetimes.rs:29:5
|
--> $DIR/hidden-lifetimes.rs:29:5
|
||||||
|
|
|
|
||||||
LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a {
|
LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a {
|
||||||
| -- hidden type `&'a mut &'b T` captures the lifetime `'b` as defined here
|
| -- -------------- opaque type defined here
|
||||||
|
| |
|
||||||
|
| hidden type `&'a mut &'b T` captures the lifetime `'b` as defined here
|
||||||
LL | x
|
LL | x
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
@ -15,7 +17,9 @@ error[E0700]: hidden type for `impl Swap + 'a` captures lifetime that does not a
|
|||||||
--> $DIR/hidden-lifetimes.rs:46:5
|
--> $DIR/hidden-lifetimes.rs:46:5
|
||||||
|
|
|
|
||||||
LL | fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a {
|
LL | fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a {
|
||||||
| -- hidden type `Rc<RefCell<&'b T>>` captures the lifetime `'b` as defined here
|
| -- -------------- opaque type defined here
|
||||||
|
| |
|
||||||
|
| hidden type `Rc<RefCell<&'b T>>` captures the lifetime `'b` as defined here
|
||||||
LL | x
|
LL | x
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
error[E0700]: hidden type for `impl Debug` captures lifetime that does not appear in bounds
|
error[E0700]: hidden type for `impl Debug` captures lifetime that does not appear in bounds
|
||||||
--> $DIR/impl-fn-hrtb-bounds-2.rs:5:9
|
--> $DIR/impl-fn-hrtb-bounds-2.rs:5:9
|
||||||
|
|
|
|
||||||
|
LL | fn a() -> impl Fn(&u8) -> impl Debug {
|
||||||
|
| ---------- opaque type defined here
|
||||||
LL | |x| x
|
LL | |x| x
|
||||||
| --- ^
|
| --- ^
|
||||||
| |
|
| |
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
error[E0700]: hidden type for `E<'b, 'c>` captures lifetime that does not appear in bounds
|
error[E0700]: hidden type for `E<'b, 'c>` captures lifetime that does not appear in bounds
|
||||||
--> $DIR/error-handling-2.rs:22:5
|
--> $DIR/error-handling-2.rs:22:5
|
||||||
|
|
|
|
||||||
|
LL | type E<'a, 'b> = impl Sized;
|
||||||
|
| ---------- opaque type defined here
|
||||||
|
LL |
|
||||||
LL | fn foo<'a: 'b, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> {
|
LL | fn foo<'a: 'b, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> {
|
||||||
| -- hidden type `*mut &'a i32` captures the lifetime `'a` as defined here
|
| -- hidden type `*mut &'a i32` captures the lifetime `'a` as defined here
|
||||||
...
|
...
|
||||||
|
@ -2,7 +2,9 @@ error[E0700]: hidden type for `impl Trait<'d, 'e>` captures lifetime that does n
|
|||||||
--> $DIR/ordinary-bounds-unrelated.rs:28:33
|
--> $DIR/ordinary-bounds-unrelated.rs:28:33
|
||||||
|
|
|
|
||||||
LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e>
|
LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e>
|
||||||
| -- hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here
|
| -- ------------------ opaque type defined here
|
||||||
|
| |
|
||||||
|
| hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here
|
||||||
...
|
...
|
||||||
LL | if condition() { a } else { b }
|
LL | if condition() { a } else { b }
|
||||||
| ^
|
| ^
|
||||||
|
@ -2,7 +2,9 @@ error[E0700]: hidden type for `impl Trait<'a, 'b>` captures lifetime that does n
|
|||||||
--> $DIR/ordinary-bounds-unsuited.rs:31:33
|
--> $DIR/ordinary-bounds-unsuited.rs:31:33
|
||||||
|
|
|
|
||||||
LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
|
LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
|
||||||
| -- hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here
|
| -- ------------------ opaque type defined here
|
||||||
|
| |
|
||||||
|
| hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here
|
||||||
...
|
...
|
||||||
LL | if condition() { a } else { b }
|
LL | if condition() { a } else { b }
|
||||||
| ^
|
| ^
|
||||||
|
@ -2,8 +2,9 @@ error[E0700]: hidden type for `impl Copy` captures lifetime that does not appear
|
|||||||
--> $DIR/must_outlive_least_region_or_bound.rs:3:35
|
--> $DIR/must_outlive_least_region_or_bound.rs:3:35
|
||||||
|
|
|
|
||||||
LL | fn elided(x: &i32) -> impl Copy { x }
|
LL | fn elided(x: &i32) -> impl Copy { x }
|
||||||
| ---- ^
|
| ---- --------- ^
|
||||||
| |
|
| | |
|
||||||
|
| | opaque type defined here
|
||||||
| hidden type `&i32` captures the anonymous lifetime defined here
|
| hidden type `&i32` captures the anonymous lifetime defined here
|
||||||
|
|
|
|
||||||
help: to declare that `impl Copy` captures `'_`, you can add an explicit `'_` lifetime bound
|
help: to declare that `impl Copy` captures `'_`, you can add an explicit `'_` lifetime bound
|
||||||
@ -15,8 +16,9 @@ error[E0700]: hidden type for `impl Copy` captures lifetime that does not appear
|
|||||||
--> $DIR/must_outlive_least_region_or_bound.rs:6:44
|
--> $DIR/must_outlive_least_region_or_bound.rs:6:44
|
||||||
|
|
|
|
||||||
LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
|
LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
|
||||||
| -- ^
|
| -- --------- ^
|
||||||
| |
|
| | |
|
||||||
|
| | opaque type defined here
|
||||||
| hidden type `&'a i32` captures the lifetime `'a` as defined here
|
| hidden type `&'a i32` captures the lifetime `'a` as defined here
|
||||||
|
|
|
|
||||||
help: to declare that `impl Copy` captures `'a`, you can add an explicit `'a` lifetime bound
|
help: to declare that `impl Copy` captures `'a`, you can add an explicit `'a` lifetime bound
|
||||||
@ -100,7 +102,9 @@ error[E0700]: hidden type for `impl Fn(&'a u32)` captures lifetime that does not
|
|||||||
--> $DIR/must_outlive_least_region_or_bound.rs:38:5
|
--> $DIR/must_outlive_least_region_or_bound.rs:38:5
|
||||||
|
|
|
|
||||||
LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
|
LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
|
||||||
| -- hidden type `[closure@$DIR/must_outlive_least_region_or_bound.rs:38:5: 38:13]` captures the lifetime `'b` as defined here
|
| -- ---------------- opaque type defined here
|
||||||
|
| |
|
||||||
|
| hidden type `[closure@$DIR/must_outlive_least_region_or_bound.rs:38:5: 38:13]` captures the lifetime `'b` as defined here
|
||||||
LL | move |_| println!("{}", y)
|
LL | move |_| println!("{}", y)
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
|
@ -2,7 +2,9 @@ error[E0700]: hidden type for `impl Future<Output = impl Sized>` captures lifeti
|
|||||||
--> $DIR/nested-return-type4.rs:4:5
|
--> $DIR/nested-return-type4.rs:4:5
|
||||||
|
|
|
|
||||||
LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized> {
|
LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized> {
|
||||||
| -- hidden type `[async block@$DIR/nested-return-type4.rs:4:5: 4:31]` captures the lifetime `'s` as defined here
|
| -- --------------------------------------------- opaque type defined here
|
||||||
|
| |
|
||||||
|
| hidden type `[async block@$DIR/nested-return-type4.rs:4:5: 4:31]` captures the lifetime `'s` as defined here
|
||||||
LL | async move { let _s = s; }
|
LL | async move { let _s = s; }
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
|
@ -2,7 +2,9 @@ error[E0700]: hidden type for `impl Trait<'y>` captures lifetime that does not a
|
|||||||
--> $DIR/region-escape-via-bound.rs:17:5
|
--> $DIR/region-escape-via-bound.rs:17:5
|
||||||
|
|
|
|
||||||
LL | fn foo<'x, 'y>(x: Cell<&'x u32>) -> impl Trait<'y>
|
LL | fn foo<'x, 'y>(x: Cell<&'x u32>) -> impl Trait<'y>
|
||||||
| -- hidden type `Cell<&'x u32>` captures the lifetime `'x` as defined here
|
| -- -------------- opaque type defined here
|
||||||
|
| |
|
||||||
|
| hidden type `Cell<&'x u32>` captures the lifetime `'x` as defined here
|
||||||
...
|
...
|
||||||
LL | x
|
LL | x
|
||||||
| ^
|
| ^
|
||||||
|
@ -2,7 +2,9 @@ error[E0700]: hidden type for `impl Iterator<Item = u32>` captures lifetime that
|
|||||||
--> $DIR/static-return-lifetime-infered.rs:7:9
|
--> $DIR/static-return-lifetime-infered.rs:7:9
|
||||||
|
|
|
|
||||||
LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
|
LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
|
||||||
| ----- hidden type `Map<std::slice::Iter<'_, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:7:27: 7:30]>` captures the anonymous lifetime defined here
|
| ----- ----------------------- opaque type defined here
|
||||||
|
| |
|
||||||
|
| hidden type `Map<std::slice::Iter<'_, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:7:27: 7:30]>` captures the anonymous lifetime defined here
|
||||||
LL | self.x.iter().map(|a| a.0)
|
LL | self.x.iter().map(|a| a.0)
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
@ -15,7 +17,9 @@ error[E0700]: hidden type for `impl Iterator<Item = u32>` captures lifetime that
|
|||||||
--> $DIR/static-return-lifetime-infered.rs:11:9
|
--> $DIR/static-return-lifetime-infered.rs:11:9
|
||||||
|
|
|
|
||||||
LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
|
LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
|
||||||
| -- hidden type `Map<std::slice::Iter<'a, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:11:27: 11:30]>` captures the lifetime `'a` as defined here
|
| -- ----------------------- opaque type defined here
|
||||||
|
| |
|
||||||
|
| hidden type `Map<std::slice::Iter<'a, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:11:27: 11:30]>` captures the lifetime `'a` as defined here
|
||||||
LL | self.x.iter().map(|a| a.0)
|
LL | self.x.iter().map(|a| a.0)
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
|
@ -2,7 +2,9 @@ error[E0700]: hidden type for `impl Iterator<Item = char>` captures lifetime tha
|
|||||||
--> $DIR/issue-105227.rs:7:5
|
--> $DIR/issue-105227.rs:7:5
|
||||||
|
|
|
|
||||||
LL | fn chars0(v :(& str, &str)) -> impl Iterator<Item = char> {
|
LL | fn chars0(v :(& str, &str)) -> impl Iterator<Item = char> {
|
||||||
| ----- hidden type `std::iter::Chain<Chars<'_>, Chars<'_>>` captures the anonymous lifetime defined here
|
| ----- -------------------------- opaque type defined here
|
||||||
|
| |
|
||||||
|
| hidden type `std::iter::Chain<Chars<'_>, Chars<'_>>` captures the anonymous lifetime defined here
|
||||||
LL |
|
LL |
|
||||||
LL | v.0.chars().chain(v.1.chars())
|
LL | v.0.chars().chain(v.1.chars())
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
@ -16,7 +18,9 @@ error[E0700]: hidden type for `impl Iterator<Item = char>` captures lifetime tha
|
|||||||
--> $DIR/issue-105227.rs:13:5
|
--> $DIR/issue-105227.rs:13:5
|
||||||
|
|
|
|
||||||
LL | fn chars1(v0 : & str, v1 : &str) -> impl Iterator<Item = char> {
|
LL | fn chars1(v0 : & str, v1 : &str) -> impl Iterator<Item = char> {
|
||||||
| ----- hidden type `std::iter::Chain<Chars<'_>, Chars<'_>>` captures the anonymous lifetime defined here
|
| ----- -------------------------- opaque type defined here
|
||||||
|
| |
|
||||||
|
| hidden type `std::iter::Chain<Chars<'_>, Chars<'_>>` captures the anonymous lifetime defined here
|
||||||
LL |
|
LL |
|
||||||
LL | v0.chars().chain(v1.chars())
|
LL | v0.chars().chain(v1.chars())
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
@ -31,7 +35,10 @@ error[E0700]: hidden type for `impl Iterator<Item = char>` captures lifetime tha
|
|||||||
|
|
|
|
||||||
LL | fn chars2<'b>(v0 : &str, v1 : &'_ str, v2 : &'b str) ->
|
LL | fn chars2<'b>(v0 : &str, v1 : &'_ str, v2 : &'b str) ->
|
||||||
| ---- hidden type `std::iter::Chain<Chars<'_>, Chars<'_>>` captures the anonymous lifetime defined here
|
| ---- hidden type `std::iter::Chain<Chars<'_>, Chars<'_>>` captures the anonymous lifetime defined here
|
||||||
...
|
LL |
|
||||||
|
LL | (impl Iterator<Item = char>, &'b str)
|
||||||
|
| -------------------------- opaque type defined here
|
||||||
|
LL | {
|
||||||
LL | (v0.chars().chain(v1.chars()), v2)
|
LL | (v0.chars().chain(v1.chars()), v2)
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
|
@ -4,6 +4,7 @@ error[E0700]: hidden type for `impl Iterator<Item = u8>` captures lifetime that
|
|||||||
LL | impl<'a> Foo<'a> {
|
LL | impl<'a> Foo<'a> {
|
||||||
| -- hidden type `Copied<std::slice::Iter<'a, u8>>` captures the lifetime `'a` as defined here
|
| -- hidden type `Copied<std::slice::Iter<'a, u8>>` captures the lifetime `'a` as defined here
|
||||||
LL | fn make_it(&self) -> impl Iterator<Item = u8> {
|
LL | fn make_it(&self) -> impl Iterator<Item = u8> {
|
||||||
|
| ------------------------ opaque type defined here
|
||||||
LL | self.0.iter().copied()
|
LL | self.0.iter().copied()
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
@ -24,7 +24,9 @@ error[E0700]: hidden type for `impl Cap<'b> + Cap<'c>` captures lifetime that do
|
|||||||
--> $DIR/min-choice-reject-ambiguous.rs:39:5
|
--> $DIR/min-choice-reject-ambiguous.rs:39:5
|
||||||
|
|
|
|
||||||
LL | fn test_ambiguous<'a, 'b, 'c>(s: &'a u8) -> impl Cap<'b> + Cap<'c>
|
LL | fn test_ambiguous<'a, 'b, 'c>(s: &'a u8) -> impl Cap<'b> + Cap<'c>
|
||||||
| -- hidden type `&'a u8` captures the lifetime `'a` as defined here
|
| -- ---------------------- opaque type defined here
|
||||||
|
| |
|
||||||
|
| hidden type `&'a u8` captures the lifetime `'a` as defined here
|
||||||
...
|
...
|
||||||
LL | s
|
LL | s
|
||||||
| ^
|
| ^
|
||||||
|
@ -2,7 +2,9 @@ error[E0700]: hidden type for `impl IntoIterator<Item = impl Cap<'a> + Cap<'b>>`
|
|||||||
--> $DIR/nested-impl-trait-fail.rs:17:5
|
--> $DIR/nested-impl-trait-fail.rs:17:5
|
||||||
|
|
|
|
||||||
LL | fn fail_early_bound<'s, 'a, 'b>(a: &'s u8) -> impl IntoIterator<Item = impl Cap<'a> + Cap<'b>>
|
LL | fn fail_early_bound<'s, 'a, 'b>(a: &'s u8) -> impl IntoIterator<Item = impl Cap<'a> + Cap<'b>>
|
||||||
| -- hidden type `[&'s u8; 1]` captures the lifetime `'s` as defined here
|
| -- ------------------------------------------------ opaque type defined here
|
||||||
|
| |
|
||||||
|
| hidden type `[&'s u8; 1]` captures the lifetime `'s` as defined here
|
||||||
...
|
...
|
||||||
LL | [a]
|
LL | [a]
|
||||||
| ^^^
|
| ^^^
|
||||||
@ -20,7 +22,9 @@ error[E0700]: hidden type for `impl Cap<'a> + Cap<'b>` captures lifetime that do
|
|||||||
--> $DIR/nested-impl-trait-fail.rs:17:5
|
--> $DIR/nested-impl-trait-fail.rs:17:5
|
||||||
|
|
|
|
||||||
LL | fn fail_early_bound<'s, 'a, 'b>(a: &'s u8) -> impl IntoIterator<Item = impl Cap<'a> + Cap<'b>>
|
LL | fn fail_early_bound<'s, 'a, 'b>(a: &'s u8) -> impl IntoIterator<Item = impl Cap<'a> + Cap<'b>>
|
||||||
| -- hidden type `&'s u8` captures the lifetime `'s` as defined here
|
| -- ---------------------- opaque type defined here
|
||||||
|
| |
|
||||||
|
| hidden type `&'s u8` captures the lifetime `'s` as defined here
|
||||||
...
|
...
|
||||||
LL | [a]
|
LL | [a]
|
||||||
| ^^^
|
| ^^^
|
||||||
@ -40,6 +44,8 @@ error[E0700]: hidden type for `impl IntoIterator<Item = impl Cap<'a> + Cap<'b>>`
|
|||||||
LL | fn fail_late_bound<'s, 'a, 'b>(
|
LL | fn fail_late_bound<'s, 'a, 'b>(
|
||||||
| -- hidden type `[&'s u8; 1]` captures the lifetime `'s` as defined here
|
| -- hidden type `[&'s u8; 1]` captures the lifetime `'s` as defined here
|
||||||
...
|
...
|
||||||
|
LL | ) -> impl IntoIterator<Item = impl Cap<'a> + Cap<'b>> {
|
||||||
|
| ------------------------------------------------ opaque type defined here
|
||||||
LL | [a]
|
LL | [a]
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
|
|
||||||
@ -58,6 +64,8 @@ error[E0700]: hidden type for `impl Cap<'a> + Cap<'b>` captures lifetime that do
|
|||||||
LL | fn fail_late_bound<'s, 'a, 'b>(
|
LL | fn fail_late_bound<'s, 'a, 'b>(
|
||||||
| -- hidden type `&'s u8` captures the lifetime `'s` as defined here
|
| -- hidden type `&'s u8` captures the lifetime `'s` as defined here
|
||||||
...
|
...
|
||||||
|
LL | ) -> impl IntoIterator<Item = impl Cap<'a> + Cap<'b>> {
|
||||||
|
| ---------------------- opaque type defined here
|
||||||
LL | [a]
|
LL | [a]
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
|
|
||||||
|
@ -2,7 +2,9 @@ error[E0700]: hidden type for `Opaque(DefId(0:13 ~ impl_trait_captures[1afc]::fo
|
|||||||
--> $DIR/impl-trait-captures.rs:11:5
|
--> $DIR/impl-trait-captures.rs:11:5
|
||||||
|
|
|
|
||||||
LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> {
|
LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> {
|
||||||
| -- hidden type `&ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[1afc]::foo::'_), '_)) T` captures the anonymous lifetime defined here
|
| -- ------------ opaque type defined here
|
||||||
|
| |
|
||||||
|
| hidden type `&ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[1afc]::foo::'_), '_)) T` captures the anonymous lifetime defined here
|
||||||
LL | x
|
LL | x
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
|
@ -2,8 +2,9 @@ error[E0700]: hidden type for `impl Clone` captures lifetime that does not appea
|
|||||||
--> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:48
|
--> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:48
|
||||||
|
|
|
|
||||||
LL | async fn f(self: Pin<&Self>) -> impl Clone { self }
|
LL | async fn f(self: Pin<&Self>) -> impl Clone { self }
|
||||||
| ----- ^^^^^^^^
|
| ----- ---------- ^^^^^^^^
|
||||||
| |
|
| | |
|
||||||
|
| | opaque type defined here
|
||||||
| hidden type `Pin<&Foo>` captures the anonymous lifetime defined here
|
| hidden type `Pin<&Foo>` captures the anonymous lifetime defined here
|
||||||
|
|
|
|
||||||
help: to declare that `impl Clone` captures `'_`, you can add an explicit `'_` lifetime bound
|
help: to declare that `impl Clone` captures `'_`, you can add an explicit `'_` lifetime bound
|
||||||
|
@ -2,8 +2,9 @@ error[E0700]: hidden type for `impl Clone` captures lifetime that does not appea
|
|||||||
--> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:6:44
|
--> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:6:44
|
||||||
|
|
|
|
||||||
LL | fn f(self: Pin<&Self>) -> impl Clone { self }
|
LL | fn f(self: Pin<&Self>) -> impl Clone { self }
|
||||||
| ----- ^^^^
|
| ----- ---------- ^^^^
|
||||||
| |
|
| | |
|
||||||
|
| | opaque type defined here
|
||||||
| hidden type `Pin<&Foo>` captures the anonymous lifetime defined here
|
| hidden type `Pin<&Foo>` captures the anonymous lifetime defined here
|
||||||
|
|
|
|
||||||
help: to declare that `impl Clone` captures `'_`, you can add an explicit `'_` lifetime bound
|
help: to declare that `impl Clone` captures `'_`, you can add an explicit `'_` lifetime bound
|
||||||
|
@ -10,7 +10,9 @@ error[E0700]: hidden type for `impl FnOnce()` captures lifetime that does not ap
|
|||||||
--> $DIR/missing-lifetimes-in-signature.rs:19:5
|
--> $DIR/missing-lifetimes-in-signature.rs:19:5
|
||||||
|
|
|
|
||||||
LL | fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce()
|
LL | fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce()
|
||||||
| ------ hidden type `[closure@$DIR/missing-lifetimes-in-signature.rs:19:5: 19:12]` captures the anonymous lifetime defined here
|
| ------ ------------- opaque type defined here
|
||||||
|
| |
|
||||||
|
| hidden type `[closure@$DIR/missing-lifetimes-in-signature.rs:19:5: 19:12]` captures the anonymous lifetime defined here
|
||||||
...
|
...
|
||||||
LL | / move || {
|
LL | / move || {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -2,7 +2,9 @@ error[E0700]: hidden type for `impl PlusOne` captures lifetime that does not app
|
|||||||
--> $DIR/imply_bounds_from_bounds_param.rs:24:5
|
--> $DIR/imply_bounds_from_bounds_param.rs:24:5
|
||||||
|
|
|
|
||||||
LL | fn test<'a>(y: &'a mut i32) -> impl PlusOne {
|
LL | fn test<'a>(y: &'a mut i32) -> impl PlusOne {
|
||||||
| -- hidden type `<&'a mut i32 as Callable>::Output` captures the lifetime `'a` as defined here
|
| -- ------------ opaque type defined here
|
||||||
|
| |
|
||||||
|
| hidden type `<&'a mut i32 as Callable>::Output` captures the lifetime `'a` as defined here
|
||||||
LL | <&'a mut i32 as Callable>::call(y)
|
LL | <&'a mut i32 as Callable>::call(y)
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
error[E0700]: hidden type for `Opaque<'a, T>` captures lifetime that does not appear in bounds
|
error[E0700]: hidden type for `Opaque<'a, T>` captures lifetime that does not appear in bounds
|
||||||
--> $DIR/missing_lifetime_bound.rs:4:47
|
--> $DIR/missing_lifetime_bound.rs:4:47
|
||||||
|
|
|
|
||||||
|
LL | type Opaque<'a, T> = impl Sized;
|
||||||
|
| ---------- opaque type defined here
|
||||||
LL | fn defining<'a, T>(x: &'a i32) -> Opaque<T> { x }
|
LL | fn defining<'a, T>(x: &'a i32) -> Opaque<T> { x }
|
||||||
| -- ^
|
| -- ^
|
||||||
| |
|
| |
|
||||||
|
Loading…
Reference in New Issue
Block a user