Merge from rustc
This commit is contained in:
commit
8652177c63
350 changed files with 3530 additions and 1199 deletions
6
.gitattributes
vendored
6
.gitattributes
vendored
|
|
@ -4,10 +4,8 @@
|
|||
*.cpp rust
|
||||
*.h rust
|
||||
*.rs rust diff=rust
|
||||
*.fixed linguist-language=Rust -merge
|
||||
*.mir linguist-language=Rust -merge
|
||||
*.stderr -merge
|
||||
*.stdout -merge
|
||||
*.fixed linguist-language=Rust
|
||||
*.mir linguist-language=Rust
|
||||
src/etc/installer/gfx/* binary
|
||||
src/vendor/** -text
|
||||
Cargo.lock linguist-generated=false
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
#![cfg_attr(not(bootstrap), allow(rustc::symbol_intern_string_literal))]
|
||||
|
||||
use rustc_span::create_default_session_globals_then;
|
||||
|
||||
use super::*;
|
||||
|
|
|
|||
|
|
@ -511,11 +511,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
|||
"you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`"
|
||||
);
|
||||
gate_all!(let_chains, "`let` expressions in this position are unstable");
|
||||
gate_all!(
|
||||
async_closure,
|
||||
"async closures are unstable",
|
||||
"to use an async block, remove the `||`: `async {`"
|
||||
);
|
||||
gate_all!(
|
||||
async_trait_bounds,
|
||||
"`async` trait bounds are unstable",
|
||||
|
|
|
|||
|
|
@ -17,7 +17,9 @@ use super::debuginfo::{
|
|||
DebugEmissionKind, DebugNameTableKind,
|
||||
};
|
||||
|
||||
pub type Bool = c_uint;
|
||||
/// In the LLVM-C API, boolean values are passed as `typedef int LLVMBool`,
|
||||
/// which has a different ABI from Rust or C++ `bool`.
|
||||
pub type Bool = c_int;
|
||||
|
||||
pub const True: Bool = 1 as Bool;
|
||||
pub const False: Bool = 0 as Bool;
|
||||
|
|
|
|||
|
|
@ -65,8 +65,10 @@ impl Trait for Foo {
|
|||
```
|
||||
|
||||
The nightly feature [Arbitrary self types][AST] extends the accepted
|
||||
set of receiver types to also include any type that can dereference to
|
||||
`Self`:
|
||||
set of receiver types to also include any type that implements the
|
||||
`Receiver` trait and can follow its chain of `Target` types to `Self`.
|
||||
There's a blanket implementation of `Receiver` for `T: Deref`, so any
|
||||
type which dereferences to `Self` can be used.
|
||||
|
||||
```
|
||||
#![feature(arbitrary_self_types)]
|
||||
|
|
|
|||
|
|
@ -5,8 +5,6 @@
|
|||
Erroneous code example:
|
||||
|
||||
```edition2018
|
||||
#![feature(async_closure)]
|
||||
|
||||
fn main() {
|
||||
let add_one = async |num: u8| {
|
||||
num + 1
|
||||
|
|
@ -18,8 +16,6 @@ fn main() {
|
|||
version, you can use successfully by using move:
|
||||
|
||||
```edition2018
|
||||
#![feature(async_closure)]
|
||||
|
||||
fn main() {
|
||||
let add_one = async move |num: u8| { // ok!
|
||||
num + 1
|
||||
|
|
|
|||
|
|
@ -94,8 +94,7 @@ mod styled_buffer;
|
|||
mod tests;
|
||||
pub mod translation;
|
||||
|
||||
pub type PErr<'a> = Diag<'a>;
|
||||
pub type PResult<'a, T> = Result<T, PErr<'a>>;
|
||||
pub type PResult<'a, T> = Result<T, Diag<'a>>;
|
||||
|
||||
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||
|
||||
|
|
@ -576,6 +575,10 @@ pub enum StashKey {
|
|||
UndeterminedMacroResolution,
|
||||
/// Used by `Parser::maybe_recover_trailing_expr`
|
||||
ExprInPat,
|
||||
/// If in the parser we detect a field expr with turbofish generic params it's possible that
|
||||
/// it's a method call without parens. If later on in `hir_typeck` we find out that this is
|
||||
/// the case we suppress this message and we give a better suggestion.
|
||||
GenericInFieldExpr,
|
||||
}
|
||||
|
||||
fn default_track_diagnostic<R>(diag: DiagInner, f: &mut dyn FnMut(DiagInner) -> R) -> R {
|
||||
|
|
|
|||
|
|
@ -72,6 +72,8 @@ declare_features! (
|
|||
(accepted, associated_types, "1.0.0", None),
|
||||
/// Allows free and inherent `async fn`s, `async` blocks, and `<expr>.await` expressions.
|
||||
(accepted, async_await, "1.39.0", Some(50547)),
|
||||
/// Allows `async || body` closures.
|
||||
(accepted, async_closure, "CURRENT_RUSTC_VERSION", Some(62290)),
|
||||
/// Allows async functions to be declared, implemented, and used in traits.
|
||||
(accepted, async_fn_in_trait, "1.75.0", Some(91611)),
|
||||
/// Allows all literals in attribute lists and values of key-value pairs.
|
||||
|
|
|
|||
|
|
@ -388,8 +388,8 @@ declare_features! (
|
|||
(unstable, associated_const_equality, "1.58.0", Some(92827)),
|
||||
/// Allows associated type defaults.
|
||||
(unstable, associated_type_defaults, "1.2.0", Some(29661)),
|
||||
/// Allows `async || body` closures.
|
||||
(unstable, async_closure, "1.37.0", Some(62290)),
|
||||
/// Allows async functions to be called from `dyn Trait`.
|
||||
(incomplete, async_fn_in_dyn_trait, "CURRENT_RUSTC_VERSION", Some(133119)),
|
||||
/// Allows `#[track_caller]` on async functions.
|
||||
(unstable, async_fn_track_caller, "1.73.0", Some(110011)),
|
||||
/// Allows `for await` loops.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
#![cfg_attr(not(bootstrap), allow(rustc::symbol_intern_string_literal))]
|
||||
|
||||
use rustc_data_structures::stable_hasher::Hash64;
|
||||
use rustc_span::def_id::{DefPathHash, StableCrateId};
|
||||
use rustc_span::edition::Edition;
|
||||
|
|
|
|||
|
|
@ -241,10 +241,10 @@ hir_analysis_invalid_generic_receiver_ty_help =
|
|||
use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
|
||||
|
||||
hir_analysis_invalid_receiver_ty = invalid `self` parameter type: `{$receiver_ty}`
|
||||
.note = type of `self` must be `Self` or a type that dereferences to it
|
||||
.note = type of `self` must be `Self` or some type implementing `Receiver`
|
||||
|
||||
hir_analysis_invalid_receiver_ty_help =
|
||||
consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
|
||||
consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
|
||||
|
||||
hir_analysis_invalid_union_field =
|
||||
field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ pub enum AutoderefKind {
|
|||
/// A type which must dispatch to a `Deref` implementation.
|
||||
Overloaded,
|
||||
}
|
||||
|
||||
struct AutoderefSnapshot<'tcx> {
|
||||
at_start: bool,
|
||||
reached_recursion_limit: bool,
|
||||
|
|
@ -27,6 +26,10 @@ struct AutoderefSnapshot<'tcx> {
|
|||
obligations: PredicateObligations<'tcx>,
|
||||
}
|
||||
|
||||
/// Recursively dereference a type, considering both built-in
|
||||
/// dereferences (`*`) and the `Deref` trait.
|
||||
/// Although called `Autoderef` it can be configured to use the
|
||||
/// `Receiver` trait instead of the `Deref` trait.
|
||||
pub struct Autoderef<'a, 'tcx> {
|
||||
// Meta infos:
|
||||
infcx: &'a InferCtxt<'tcx>,
|
||||
|
|
@ -39,6 +42,7 @@ pub struct Autoderef<'a, 'tcx> {
|
|||
|
||||
// Configurations:
|
||||
include_raw_pointers: bool,
|
||||
use_receiver_trait: bool,
|
||||
silence_errors: bool,
|
||||
}
|
||||
|
||||
|
|
@ -69,6 +73,10 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> {
|
|||
}
|
||||
|
||||
// Otherwise, deref if type is derefable:
|
||||
// NOTE: in the case of self.use_receiver_trait = true, you might think it would
|
||||
// be better to skip this clause and use the Overloaded case only, since &T
|
||||
// and &mut T implement Receiver. But built-in derefs apply equally to Receiver
|
||||
// and Deref, and this has benefits for const and the emitted MIR.
|
||||
let (kind, new_ty) =
|
||||
if let Some(ty) = self.state.cur_ty.builtin_deref(self.include_raw_pointers) {
|
||||
debug_assert_eq!(ty, self.infcx.resolve_vars_if_possible(ty));
|
||||
|
|
@ -111,7 +119,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
|
|||
body_def_id: LocalDefId,
|
||||
span: Span,
|
||||
base_ty: Ty<'tcx>,
|
||||
) -> Autoderef<'a, 'tcx> {
|
||||
) -> Self {
|
||||
Autoderef {
|
||||
infcx,
|
||||
span,
|
||||
|
|
@ -125,6 +133,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
|
|||
reached_recursion_limit: false,
|
||||
},
|
||||
include_raw_pointers: false,
|
||||
use_receiver_trait: false,
|
||||
silence_errors: false,
|
||||
}
|
||||
}
|
||||
|
|
@ -137,8 +146,13 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
|
|||
return None;
|
||||
}
|
||||
|
||||
// <ty as Deref>
|
||||
let trait_ref = ty::TraitRef::new(tcx, tcx.lang_items().deref_trait()?, [ty]);
|
||||
// <ty as Deref>, or whatever the equivalent trait is that we've been asked to walk.
|
||||
let (trait_def_id, trait_target_def_id) = if self.use_receiver_trait {
|
||||
(tcx.lang_items().receiver_trait()?, tcx.lang_items().receiver_target()?)
|
||||
} else {
|
||||
(tcx.lang_items().deref_trait()?, tcx.lang_items().deref_target()?)
|
||||
};
|
||||
let trait_ref = ty::TraitRef::new(tcx, trait_def_id, [ty]);
|
||||
let cause = traits::ObligationCause::misc(self.span, self.body_id);
|
||||
let obligation = traits::Obligation::new(
|
||||
tcx,
|
||||
|
|
@ -151,11 +165,8 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
|
|||
return None;
|
||||
}
|
||||
|
||||
let (normalized_ty, obligations) = self.structurally_normalize(Ty::new_projection(
|
||||
tcx,
|
||||
tcx.lang_items().deref_target()?,
|
||||
[ty],
|
||||
))?;
|
||||
let (normalized_ty, obligations) =
|
||||
self.structurally_normalize(Ty::new_projection(tcx, trait_target_def_id, [ty]))?;
|
||||
debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations);
|
||||
self.state.obligations.extend(obligations);
|
||||
|
||||
|
|
@ -234,6 +245,14 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
|
|||
self
|
||||
}
|
||||
|
||||
/// Use `core::ops::Receiver` and `core::ops::Receiver::Target` as
|
||||
/// the trait and associated type to iterate, instead of
|
||||
/// `core::ops::Deref` and `core::ops::Deref::Target`
|
||||
pub fn use_receiver_trait(mut self) -> Self {
|
||||
self.use_receiver_trait = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn silence_errors(mut self) -> Self {
|
||||
self.silence_errors = true;
|
||||
self
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use std::assert_matches::debug_assert_matches;
|
|||
use rustc_abi::FieldIdx;
|
||||
use rustc_ast::InlineAsmTemplatePiece;
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{self as hir, LangItem};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::{self, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, UintTy};
|
||||
|
|
@ -21,6 +22,12 @@ pub struct InlineAsmCtxt<'a, 'tcx> {
|
|||
get_operand_ty: Box<dyn Fn(&'tcx hir::Expr<'tcx>) -> Ty<'tcx> + 'a>,
|
||||
}
|
||||
|
||||
enum NonAsmTypeReason<'tcx> {
|
||||
UnevaluatedSIMDArrayLength(DefId, ty::Const<'tcx>),
|
||||
Invalid(Ty<'tcx>),
|
||||
InvalidElement(DefId, Ty<'tcx>),
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
||||
pub fn new_global_asm(tcx: TyCtxt<'tcx>) -> Self {
|
||||
InlineAsmCtxt {
|
||||
|
|
@ -56,7 +63,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
false
|
||||
}
|
||||
|
||||
fn get_asm_ty(&self, ty: Ty<'tcx>) -> Option<InlineAsmType> {
|
||||
fn get_asm_ty(&self, ty: Ty<'tcx>) -> Result<InlineAsmType, NonAsmTypeReason<'tcx>> {
|
||||
let asm_ty_isize = match self.tcx.sess.target.pointer_width {
|
||||
16 => InlineAsmType::I16,
|
||||
32 => InlineAsmType::I32,
|
||||
|
|
@ -65,64 +72,62 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
};
|
||||
|
||||
match *ty.kind() {
|
||||
ty::Int(IntTy::I8) | ty::Uint(UintTy::U8) => Some(InlineAsmType::I8),
|
||||
ty::Int(IntTy::I16) | ty::Uint(UintTy::U16) => Some(InlineAsmType::I16),
|
||||
ty::Int(IntTy::I32) | ty::Uint(UintTy::U32) => Some(InlineAsmType::I32),
|
||||
ty::Int(IntTy::I64) | ty::Uint(UintTy::U64) => Some(InlineAsmType::I64),
|
||||
ty::Int(IntTy::I128) | ty::Uint(UintTy::U128) => Some(InlineAsmType::I128),
|
||||
ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => Some(asm_ty_isize),
|
||||
ty::Float(FloatTy::F16) => Some(InlineAsmType::F16),
|
||||
ty::Float(FloatTy::F32) => Some(InlineAsmType::F32),
|
||||
ty::Float(FloatTy::F64) => Some(InlineAsmType::F64),
|
||||
ty::Float(FloatTy::F128) => Some(InlineAsmType::F128),
|
||||
ty::FnPtr(..) => Some(asm_ty_isize),
|
||||
ty::RawPtr(ty, _) if self.is_thin_ptr_ty(ty) => Some(asm_ty_isize),
|
||||
ty::Int(IntTy::I8) | ty::Uint(UintTy::U8) => Ok(InlineAsmType::I8),
|
||||
ty::Int(IntTy::I16) | ty::Uint(UintTy::U16) => Ok(InlineAsmType::I16),
|
||||
ty::Int(IntTy::I32) | ty::Uint(UintTy::U32) => Ok(InlineAsmType::I32),
|
||||
ty::Int(IntTy::I64) | ty::Uint(UintTy::U64) => Ok(InlineAsmType::I64),
|
||||
ty::Int(IntTy::I128) | ty::Uint(UintTy::U128) => Ok(InlineAsmType::I128),
|
||||
ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => Ok(asm_ty_isize),
|
||||
ty::Float(FloatTy::F16) => Ok(InlineAsmType::F16),
|
||||
ty::Float(FloatTy::F32) => Ok(InlineAsmType::F32),
|
||||
ty::Float(FloatTy::F64) => Ok(InlineAsmType::F64),
|
||||
ty::Float(FloatTy::F128) => Ok(InlineAsmType::F128),
|
||||
ty::FnPtr(..) => Ok(asm_ty_isize),
|
||||
ty::RawPtr(ty, _) if self.is_thin_ptr_ty(ty) => Ok(asm_ty_isize),
|
||||
ty::Adt(adt, args) if adt.repr().simd() => {
|
||||
let fields = &adt.non_enum_variant().fields;
|
||||
let elem_ty = fields[FieldIdx::ZERO].ty(self.tcx, args);
|
||||
let field = &fields[FieldIdx::ZERO];
|
||||
let elem_ty = field.ty(self.tcx, args);
|
||||
|
||||
let (size, ty) = match elem_ty.kind() {
|
||||
ty::Array(ty, len) => {
|
||||
let len = self.tcx.normalize_erasing_regions(self.typing_env, *len);
|
||||
if let Some(len) = len.try_to_target_usize(self.tcx) {
|
||||
(len, *ty)
|
||||
} else {
|
||||
return None;
|
||||
return Err(NonAsmTypeReason::UnevaluatedSIMDArrayLength(
|
||||
field.did, len,
|
||||
));
|
||||
}
|
||||
}
|
||||
_ => (fields.len() as u64, elem_ty),
|
||||
};
|
||||
|
||||
match ty.kind() {
|
||||
ty::Int(IntTy::I8) | ty::Uint(UintTy::U8) => Some(InlineAsmType::VecI8(size)),
|
||||
ty::Int(IntTy::I16) | ty::Uint(UintTy::U16) => {
|
||||
Some(InlineAsmType::VecI16(size))
|
||||
}
|
||||
ty::Int(IntTy::I32) | ty::Uint(UintTy::U32) => {
|
||||
Some(InlineAsmType::VecI32(size))
|
||||
}
|
||||
ty::Int(IntTy::I64) | ty::Uint(UintTy::U64) => {
|
||||
Some(InlineAsmType::VecI64(size))
|
||||
}
|
||||
ty::Int(IntTy::I8) | ty::Uint(UintTy::U8) => Ok(InlineAsmType::VecI8(size)),
|
||||
ty::Int(IntTy::I16) | ty::Uint(UintTy::U16) => Ok(InlineAsmType::VecI16(size)),
|
||||
ty::Int(IntTy::I32) | ty::Uint(UintTy::U32) => Ok(InlineAsmType::VecI32(size)),
|
||||
ty::Int(IntTy::I64) | ty::Uint(UintTy::U64) => Ok(InlineAsmType::VecI64(size)),
|
||||
ty::Int(IntTy::I128) | ty::Uint(UintTy::U128) => {
|
||||
Some(InlineAsmType::VecI128(size))
|
||||
Ok(InlineAsmType::VecI128(size))
|
||||
}
|
||||
ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => {
|
||||
Some(match self.tcx.sess.target.pointer_width {
|
||||
Ok(match self.tcx.sess.target.pointer_width {
|
||||
16 => InlineAsmType::VecI16(size),
|
||||
32 => InlineAsmType::VecI32(size),
|
||||
64 => InlineAsmType::VecI64(size),
|
||||
width => bug!("unsupported pointer width: {width}"),
|
||||
})
|
||||
}
|
||||
ty::Float(FloatTy::F16) => Some(InlineAsmType::VecF16(size)),
|
||||
ty::Float(FloatTy::F32) => Some(InlineAsmType::VecF32(size)),
|
||||
ty::Float(FloatTy::F64) => Some(InlineAsmType::VecF64(size)),
|
||||
ty::Float(FloatTy::F128) => Some(InlineAsmType::VecF128(size)),
|
||||
_ => None,
|
||||
ty::Float(FloatTy::F16) => Ok(InlineAsmType::VecF16(size)),
|
||||
ty::Float(FloatTy::F32) => Ok(InlineAsmType::VecF32(size)),
|
||||
ty::Float(FloatTy::F64) => Ok(InlineAsmType::VecF64(size)),
|
||||
ty::Float(FloatTy::F128) => Ok(InlineAsmType::VecF128(size)),
|
||||
_ => Err(NonAsmTypeReason::InvalidElement(field.did, ty)),
|
||||
}
|
||||
}
|
||||
ty::Infer(_) => bug!("unexpected infer ty in asm operand"),
|
||||
_ => None,
|
||||
_ => Err(NonAsmTypeReason::Invalid(ty)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -163,17 +168,42 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
}
|
||||
_ => self.get_asm_ty(ty),
|
||||
};
|
||||
let Some(asm_ty) = asm_ty else {
|
||||
let msg = format!("cannot use value of type `{ty}` for inline assembly");
|
||||
self.tcx
|
||||
.dcx()
|
||||
.struct_span_err(expr.span, msg)
|
||||
.with_note(
|
||||
"only integers, floats, SIMD vectors, pointers and function pointers \
|
||||
can be used as arguments for inline assembly",
|
||||
)
|
||||
.emit();
|
||||
return None;
|
||||
let asm_ty = match asm_ty {
|
||||
Ok(asm_ty) => asm_ty,
|
||||
Err(reason) => {
|
||||
match reason {
|
||||
NonAsmTypeReason::UnevaluatedSIMDArrayLength(did, len) => {
|
||||
let msg = format!("cannot evaluate SIMD vector length `{len}`");
|
||||
self.tcx
|
||||
.dcx()
|
||||
.struct_span_err(self.tcx.def_span(did), msg)
|
||||
.with_span_note(
|
||||
expr.span,
|
||||
"SIMD vector length needs to be known statically for use in `asm!`",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
NonAsmTypeReason::Invalid(ty) => {
|
||||
let msg = format!("cannot use value of type `{ty}` for inline assembly");
|
||||
self.tcx.dcx().struct_span_err(expr.span, msg).with_note(
|
||||
"only integers, floats, SIMD vectors, pointers and function pointers \
|
||||
can be used as arguments for inline assembly",
|
||||
).emit();
|
||||
}
|
||||
NonAsmTypeReason::InvalidElement(did, ty) => {
|
||||
let msg = format!(
|
||||
"cannot use SIMD vector with element type `{ty}` for inline assembly"
|
||||
);
|
||||
self.tcx.dcx()
|
||||
.struct_span_err(self.tcx.def_span(did), msg).with_span_note(
|
||||
expr.span,
|
||||
"only integers, floats, SIMD vectors, pointers and function pointers \
|
||||
can be used as arguments for inline assembly",
|
||||
).emit();
|
||||
}
|
||||
}
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
// Check that the type implements Copy. The only case where this can
|
||||
|
|
|
|||
|
|
@ -1821,13 +1821,18 @@ fn receiver_is_valid<'tcx>(
|
|||
|
||||
let mut autoderef = Autoderef::new(infcx, wfcx.param_env, wfcx.body_def_id, span, receiver_ty);
|
||||
|
||||
// The `arbitrary_self_types` feature allows custom smart pointer
|
||||
// types to be method receivers, as identified by following the Receiver<Target=T>
|
||||
// chain.
|
||||
if arbitrary_self_types_enabled.is_some() {
|
||||
autoderef = autoderef.use_receiver_trait();
|
||||
}
|
||||
|
||||
// The `arbitrary_self_types_pointers` feature allows raw pointer receivers like `self: *const Self`.
|
||||
if arbitrary_self_types_enabled == Some(ArbitrarySelfTypesLevel::WithPointers) {
|
||||
autoderef = autoderef.include_raw_pointers();
|
||||
}
|
||||
|
||||
let receiver_trait_def_id = tcx.require_lang_item(LangItem::LegacyReceiver, Some(span));
|
||||
|
||||
// Keep dereferencing `receiver_ty` until we get to `self_ty`.
|
||||
while let Some((potential_self_ty, _)) = autoderef.next() {
|
||||
debug!(
|
||||
|
|
@ -1849,11 +1854,13 @@ fn receiver_is_valid<'tcx>(
|
|||
}
|
||||
|
||||
// Without `feature(arbitrary_self_types)`, we require that each step in the
|
||||
// deref chain implement `receiver`.
|
||||
// deref chain implement `LegacyReceiver`.
|
||||
if arbitrary_self_types_enabled.is_none() {
|
||||
if !receiver_is_implemented(
|
||||
let legacy_receiver_trait_def_id =
|
||||
tcx.require_lang_item(LangItem::LegacyReceiver, Some(span));
|
||||
if !legacy_receiver_is_implemented(
|
||||
wfcx,
|
||||
receiver_trait_def_id,
|
||||
legacy_receiver_trait_def_id,
|
||||
cause.clone(),
|
||||
potential_self_ty,
|
||||
) {
|
||||
|
|
@ -1866,7 +1873,7 @@ fn receiver_is_valid<'tcx>(
|
|||
cause.clone(),
|
||||
wfcx.param_env,
|
||||
potential_self_ty,
|
||||
receiver_trait_def_id,
|
||||
legacy_receiver_trait_def_id,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1875,14 +1882,14 @@ fn receiver_is_valid<'tcx>(
|
|||
Err(ReceiverValidityError::DoesNotDeref)
|
||||
}
|
||||
|
||||
fn receiver_is_implemented<'tcx>(
|
||||
fn legacy_receiver_is_implemented<'tcx>(
|
||||
wfcx: &WfCheckingCtxt<'_, 'tcx>,
|
||||
receiver_trait_def_id: DefId,
|
||||
legacy_receiver_trait_def_id: DefId,
|
||||
cause: ObligationCause<'tcx>,
|
||||
receiver_ty: Ty<'tcx>,
|
||||
) -> bool {
|
||||
let tcx = wfcx.tcx();
|
||||
let trait_ref = ty::TraitRef::new(tcx, receiver_trait_def_id, [receiver_ty]);
|
||||
let trait_ref = ty::TraitRef::new(tcx, legacy_receiver_trait_def_id, [receiver_ty]);
|
||||
|
||||
let obligation = Obligation::new(tcx, cause, wfcx.param_env, trait_ref);
|
||||
|
||||
|
|
@ -1890,7 +1897,7 @@ fn receiver_is_implemented<'tcx>(
|
|||
true
|
||||
} else {
|
||||
debug!(
|
||||
"receiver_is_implemented: type `{:?}` does not implement `Receiver` trait",
|
||||
"receiver_is_implemented: type `{:?}` does not implement `LegacyReceiver` trait",
|
||||
receiver_ty
|
||||
);
|
||||
false
|
||||
|
|
|
|||
|
|
@ -917,7 +917,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
[candidate] => format!(
|
||||
"the method of the same name on {} `{}`",
|
||||
match candidate.kind {
|
||||
probe::CandidateKind::InherentImplCandidate(_) => "the inherent impl for",
|
||||
probe::CandidateKind::InherentImplCandidate { .. } => "the inherent impl for",
|
||||
_ => "trait",
|
||||
},
|
||||
self.tcx.def_path_str(candidate.item.container_id(self.tcx))
|
||||
|
|
|
|||
|
|
@ -3076,7 +3076,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
err.help("methods are immutable and cannot be assigned to");
|
||||
}
|
||||
|
||||
err.emit()
|
||||
// See `StashKey::GenericInFieldExpr` for more info
|
||||
self.dcx().try_steal_replace_and_emit_err(field.span, StashKey::GenericInFieldExpr, err)
|
||||
}
|
||||
|
||||
fn point_at_param_definition(&self, err: &mut Diag<'_>, param: ty::ParamTy) {
|
||||
|
|
|
|||
|
|
@ -613,19 +613,16 @@ impl<'tcx> AnnotateUnitFallbackVisitor<'_, 'tcx> {
|
|||
if arg_segment.args.is_none()
|
||||
&& let Some(all_args) = self.fcx.typeck_results.borrow().node_args_opt(id)
|
||||
&& let generics = self.fcx.tcx.generics_of(def_id)
|
||||
&& let args = &all_args[generics.parent_count..]
|
||||
&& let args = all_args[generics.parent_count..].iter().zip(&generics.own_params)
|
||||
// We can't turbofish consts :(
|
||||
&& args.iter().all(|arg| matches!(arg.unpack(), ty::GenericArgKind::Type(_) | ty::GenericArgKind::Lifetime(_)))
|
||||
&& args.clone().all(|(_, param)| matches!(param.kind, ty::GenericParamDefKind::Type { .. } | ty::GenericParamDefKind::Lifetime))
|
||||
{
|
||||
let n_tys = args
|
||||
.iter()
|
||||
.filter(|arg| matches!(arg.unpack(), ty::GenericArgKind::Type(_)))
|
||||
.count();
|
||||
for (idx, arg) in args
|
||||
.iter()
|
||||
.filter(|arg| matches!(arg.unpack(), ty::GenericArgKind::Type(_)))
|
||||
.enumerate()
|
||||
{
|
||||
// We filter out APITs, which are not turbofished.
|
||||
let non_apit_type_args = args.filter(|(_, param)| {
|
||||
matches!(param.kind, ty::GenericParamDefKind::Type { synthetic: false, .. })
|
||||
});
|
||||
let n_tys = non_apit_type_args.clone().count();
|
||||
for (idx, (arg, _)) in non_apit_type_args.enumerate() {
|
||||
if let Some(ty) = arg.as_type()
|
||||
&& let Some(vid) = self.fcx.root_vid(ty)
|
||||
&& self.reachable_vids.contains(&vid)
|
||||
|
|
|
|||
|
|
@ -79,12 +79,6 @@ pub(crate) struct ProbeContext<'a, 'tcx> {
|
|||
/// used for error reporting
|
||||
static_candidates: RefCell<Vec<CandidateSource>>,
|
||||
|
||||
/// Collects near misses when trait bounds for type parameters are unsatisfied and is only used
|
||||
/// for error reporting
|
||||
unsatisfied_predicates: RefCell<
|
||||
Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>, Option<ObligationCause<'tcx>>)>,
|
||||
>,
|
||||
|
||||
scope_expr_id: HirId,
|
||||
|
||||
/// Is this probe being done for a diagnostic? This will skip some error reporting
|
||||
|
|
@ -109,7 +103,7 @@ pub(crate) struct Candidate<'tcx> {
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum CandidateKind<'tcx> {
|
||||
InherentImplCandidate(DefId),
|
||||
InherentImplCandidate { impl_def_id: DefId, receiver_steps: usize },
|
||||
ObjectCandidate(ty::PolyTraitRef<'tcx>),
|
||||
TraitCandidate(ty::PolyTraitRef<'tcx>),
|
||||
WhereClauseCandidate(ty::PolyTraitRef<'tcx>),
|
||||
|
|
@ -162,6 +156,52 @@ impl AutorefOrPtrAdjustment {
|
|||
}
|
||||
}
|
||||
|
||||
/// Extra information required only for error reporting.
|
||||
#[derive(Debug)]
|
||||
struct PickDiagHints<'a, 'tcx> {
|
||||
/// Unstable candidates alongside the stable ones.
|
||||
unstable_candidates: Option<Vec<(Candidate<'tcx>, Symbol)>>,
|
||||
|
||||
/// Collects near misses when trait bounds for type parameters are unsatisfied and is only used
|
||||
/// for error reporting
|
||||
unsatisfied_predicates: &'a mut Vec<(
|
||||
ty::Predicate<'tcx>,
|
||||
Option<ty::Predicate<'tcx>>,
|
||||
Option<ObligationCause<'tcx>>,
|
||||
)>,
|
||||
}
|
||||
|
||||
/// Criteria to apply when searching for a given Pick. This is used during
|
||||
/// the search for potentially shadowed methods to ensure we don't search
|
||||
/// more candidates than strictly necessary.
|
||||
#[derive(Debug)]
|
||||
struct PickConstraintsForShadowed {
|
||||
autoderefs: usize,
|
||||
receiver_steps: Option<usize>,
|
||||
def_id: DefId,
|
||||
}
|
||||
|
||||
impl PickConstraintsForShadowed {
|
||||
fn may_shadow_based_on_autoderefs(&self, autoderefs: usize) -> bool {
|
||||
autoderefs == self.autoderefs
|
||||
}
|
||||
|
||||
fn candidate_may_shadow(&self, candidate: &Candidate<'_>) -> bool {
|
||||
// An item never shadows itself
|
||||
candidate.item.def_id != self.def_id
|
||||
// and we're only concerned about inherent impls doing the shadowing.
|
||||
// Shadowing can only occur if the shadowed is further along
|
||||
// the Receiver dereferencing chain than the shadowed.
|
||||
&& match candidate.kind {
|
||||
CandidateKind::InherentImplCandidate { receiver_steps, .. } => match self.receiver_steps {
|
||||
Some(shadowed_receiver_steps) => receiver_steps > shadowed_receiver_steps,
|
||||
_ => false
|
||||
},
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct Pick<'tcx> {
|
||||
pub item: ty::AssocItem,
|
||||
|
|
@ -181,6 +221,11 @@ pub(crate) struct Pick<'tcx> {
|
|||
|
||||
/// Unstable candidates alongside the stable ones.
|
||||
unstable_candidates: Vec<(Candidate<'tcx>, Symbol)>,
|
||||
|
||||
/// Number of jumps along the `Receiver::Target` chain we followed
|
||||
/// to identify this method. Used only for deshadowing errors.
|
||||
/// Only applies for inherent impls.
|
||||
pub receiver_steps: Option<usize>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
|
|
@ -366,6 +411,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
autoderefs: 0,
|
||||
from_unsafe_deref: false,
|
||||
unsize: false,
|
||||
reachable_via_deref: true,
|
||||
}]),
|
||||
opt_bad_ty: None,
|
||||
reached_recursion_limit: false,
|
||||
|
|
@ -516,47 +562,93 @@ fn method_autoderef_steps<'tcx>(
|
|||
let (ref infcx, goal, inference_vars) = tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &goal);
|
||||
let ParamEnvAnd { param_env, value: self_ty } = goal;
|
||||
|
||||
let mut autoderef =
|
||||
// If arbitrary self types is not enabled, we follow the chain of
|
||||
// `Deref<Target=T>`. If arbitrary self types is enabled, we instead
|
||||
// follow the chain of `Receiver<Target=T>`, but we also record whether
|
||||
// such types are reachable by following the (potentially shorter)
|
||||
// chain of `Deref<Target=T>`. We will use the first list when finding
|
||||
// potentially relevant function implementations (e.g. relevant impl blocks)
|
||||
// but the second list when determining types that the receiver may be
|
||||
// converted to, in order to find out which of those methods might actually
|
||||
// be callable.
|
||||
let mut autoderef_via_deref =
|
||||
Autoderef::new(infcx, param_env, hir::def_id::CRATE_DEF_ID, DUMMY_SP, self_ty)
|
||||
.include_raw_pointers()
|
||||
.silence_errors();
|
||||
let mut reached_raw_pointer = false;
|
||||
let mut steps: Vec<_> = autoderef
|
||||
.by_ref()
|
||||
.map(|(ty, d)| {
|
||||
let step = CandidateStep {
|
||||
self_ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, ty),
|
||||
autoderefs: d,
|
||||
from_unsafe_deref: reached_raw_pointer,
|
||||
unsize: false,
|
||||
};
|
||||
if let ty::RawPtr(_, _) = ty.kind() {
|
||||
// all the subsequent steps will be from_unsafe_deref
|
||||
reached_raw_pointer = true;
|
||||
}
|
||||
step
|
||||
})
|
||||
.collect();
|
||||
|
||||
let final_ty = autoderef.final_ty(true);
|
||||
let mut reached_raw_pointer = false;
|
||||
let arbitrary_self_types_enabled =
|
||||
tcx.features().arbitrary_self_types() || tcx.features().arbitrary_self_types_pointers();
|
||||
let (mut steps, reached_recursion_limit): (Vec<_>, bool) = if arbitrary_self_types_enabled {
|
||||
let reachable_via_deref =
|
||||
autoderef_via_deref.by_ref().map(|_| true).chain(std::iter::repeat(false));
|
||||
|
||||
let mut autoderef_via_receiver =
|
||||
Autoderef::new(infcx, param_env, hir::def_id::CRATE_DEF_ID, DUMMY_SP, self_ty)
|
||||
.include_raw_pointers()
|
||||
.use_receiver_trait()
|
||||
.silence_errors();
|
||||
let steps = autoderef_via_receiver
|
||||
.by_ref()
|
||||
.zip(reachable_via_deref)
|
||||
.map(|((ty, d), reachable_via_deref)| {
|
||||
let step = CandidateStep {
|
||||
self_ty: infcx
|
||||
.make_query_response_ignoring_pending_obligations(inference_vars, ty),
|
||||
autoderefs: d,
|
||||
from_unsafe_deref: reached_raw_pointer,
|
||||
unsize: false,
|
||||
reachable_via_deref,
|
||||
};
|
||||
if ty.is_unsafe_ptr() {
|
||||
// all the subsequent steps will be from_unsafe_deref
|
||||
reached_raw_pointer = true;
|
||||
}
|
||||
step
|
||||
})
|
||||
.collect();
|
||||
(steps, autoderef_via_receiver.reached_recursion_limit())
|
||||
} else {
|
||||
let steps = autoderef_via_deref
|
||||
.by_ref()
|
||||
.map(|(ty, d)| {
|
||||
let step = CandidateStep {
|
||||
self_ty: infcx
|
||||
.make_query_response_ignoring_pending_obligations(inference_vars, ty),
|
||||
autoderefs: d,
|
||||
from_unsafe_deref: reached_raw_pointer,
|
||||
unsize: false,
|
||||
reachable_via_deref: true,
|
||||
};
|
||||
if ty.is_unsafe_ptr() {
|
||||
// all the subsequent steps will be from_unsafe_deref
|
||||
reached_raw_pointer = true;
|
||||
}
|
||||
step
|
||||
})
|
||||
.collect();
|
||||
(steps, autoderef_via_deref.reached_recursion_limit())
|
||||
};
|
||||
let final_ty = autoderef_via_deref.final_ty(true);
|
||||
let opt_bad_ty = match final_ty.kind() {
|
||||
ty::Infer(ty::TyVar(_)) | ty::Error(_) => Some(MethodAutoderefBadTy {
|
||||
reached_raw_pointer,
|
||||
ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, final_ty),
|
||||
}),
|
||||
ty::Array(elem_ty, _) => {
|
||||
let dereferences = steps.len() - 1;
|
||||
|
||||
let autoderefs = steps.iter().filter(|s| s.reachable_via_deref).count() - 1;
|
||||
steps.push(CandidateStep {
|
||||
self_ty: infcx.make_query_response_ignoring_pending_obligations(
|
||||
inference_vars,
|
||||
Ty::new_slice(infcx.tcx, *elem_ty),
|
||||
),
|
||||
autoderefs: dereferences,
|
||||
autoderefs,
|
||||
// this could be from an unsafe deref if we had
|
||||
// a *mut/const [T; N]
|
||||
from_unsafe_deref: reached_raw_pointer,
|
||||
unsize: true,
|
||||
reachable_via_deref: true, // this is always the final type from
|
||||
// autoderef_via_deref
|
||||
});
|
||||
|
||||
None
|
||||
|
|
@ -569,7 +661,7 @@ fn method_autoderef_steps<'tcx>(
|
|||
MethodAutoderefStepsResult {
|
||||
steps: tcx.arena.alloc_from_iter(steps),
|
||||
opt_bad_ty: opt_bad_ty.map(|ty| &*tcx.arena.alloc(ty)),
|
||||
reached_recursion_limit: autoderef.reached_recursion_limit(),
|
||||
reached_recursion_limit,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -600,7 +692,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
private_candidates: Vec::new(),
|
||||
private_candidate: Cell::new(None),
|
||||
static_candidates: RefCell::new(Vec::new()),
|
||||
unsatisfied_predicates: RefCell::new(Vec::new()),
|
||||
scope_expr_id,
|
||||
is_suggestion,
|
||||
}
|
||||
|
|
@ -613,7 +704,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
self.private_candidates.clear();
|
||||
self.private_candidate.set(None);
|
||||
self.static_candidates.borrow_mut().clear();
|
||||
self.unsatisfied_predicates.borrow_mut().clear();
|
||||
}
|
||||
|
||||
/// When we're looking up a method by path (UFCS), we relate the receiver
|
||||
|
|
@ -652,12 +742,16 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
|
||||
fn assemble_inherent_candidates(&mut self) {
|
||||
for step in self.steps.iter() {
|
||||
self.assemble_probe(&step.self_ty);
|
||||
self.assemble_probe(&step.self_ty, step.autoderefs);
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn assemble_probe(&mut self, self_ty: &Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>) {
|
||||
fn assemble_probe(
|
||||
&mut self,
|
||||
self_ty: &Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
|
||||
receiver_steps: usize,
|
||||
) {
|
||||
let raw_self_ty = self_ty.value.value;
|
||||
match *raw_self_ty.kind() {
|
||||
ty::Dynamic(data, ..) if let Some(p) = data.principal() => {
|
||||
|
|
@ -682,22 +776,31 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
self.fcx.instantiate_canonical(self.span, self_ty);
|
||||
|
||||
self.assemble_inherent_candidates_from_object(generalized_self_ty);
|
||||
self.assemble_inherent_impl_candidates_for_type(p.def_id());
|
||||
self.assemble_inherent_impl_candidates_for_type(p.def_id(), receiver_steps);
|
||||
if self.tcx.has_attr(p.def_id(), sym::rustc_has_incoherent_inherent_impls) {
|
||||
self.assemble_inherent_candidates_for_incoherent_ty(raw_self_ty);
|
||||
self.assemble_inherent_candidates_for_incoherent_ty(
|
||||
raw_self_ty,
|
||||
receiver_steps,
|
||||
);
|
||||
}
|
||||
}
|
||||
ty::Adt(def, _) => {
|
||||
let def_id = def.did();
|
||||
self.assemble_inherent_impl_candidates_for_type(def_id);
|
||||
self.assemble_inherent_impl_candidates_for_type(def_id, receiver_steps);
|
||||
if self.tcx.has_attr(def_id, sym::rustc_has_incoherent_inherent_impls) {
|
||||
self.assemble_inherent_candidates_for_incoherent_ty(raw_self_ty);
|
||||
self.assemble_inherent_candidates_for_incoherent_ty(
|
||||
raw_self_ty,
|
||||
receiver_steps,
|
||||
);
|
||||
}
|
||||
}
|
||||
ty::Foreign(did) => {
|
||||
self.assemble_inherent_impl_candidates_for_type(did);
|
||||
self.assemble_inherent_impl_candidates_for_type(did, receiver_steps);
|
||||
if self.tcx.has_attr(did, sym::rustc_has_incoherent_inherent_impls) {
|
||||
self.assemble_inherent_candidates_for_incoherent_ty(raw_self_ty);
|
||||
self.assemble_inherent_candidates_for_incoherent_ty(
|
||||
raw_self_ty,
|
||||
receiver_steps,
|
||||
);
|
||||
}
|
||||
}
|
||||
ty::Param(p) => {
|
||||
|
|
@ -714,29 +817,35 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
| ty::RawPtr(_, _)
|
||||
| ty::Ref(..)
|
||||
| ty::Never
|
||||
| ty::Tuple(..) => self.assemble_inherent_candidates_for_incoherent_ty(raw_self_ty),
|
||||
| ty::Tuple(..) => {
|
||||
self.assemble_inherent_candidates_for_incoherent_ty(raw_self_ty, receiver_steps)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn assemble_inherent_candidates_for_incoherent_ty(&mut self, self_ty: Ty<'tcx>) {
|
||||
fn assemble_inherent_candidates_for_incoherent_ty(
|
||||
&mut self,
|
||||
self_ty: Ty<'tcx>,
|
||||
receiver_steps: usize,
|
||||
) {
|
||||
let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::InstantiateWithInfer) else {
|
||||
bug!("unexpected incoherent type: {:?}", self_ty)
|
||||
};
|
||||
for &impl_def_id in self.tcx.incoherent_impls(simp).into_iter() {
|
||||
self.assemble_inherent_impl_probe(impl_def_id);
|
||||
self.assemble_inherent_impl_probe(impl_def_id, receiver_steps);
|
||||
}
|
||||
}
|
||||
|
||||
fn assemble_inherent_impl_candidates_for_type(&mut self, def_id: DefId) {
|
||||
fn assemble_inherent_impl_candidates_for_type(&mut self, def_id: DefId, receiver_steps: usize) {
|
||||
let impl_def_ids = self.tcx.at(self.span).inherent_impls(def_id).into_iter();
|
||||
for &impl_def_id in impl_def_ids {
|
||||
self.assemble_inherent_impl_probe(impl_def_id);
|
||||
self.assemble_inherent_impl_probe(impl_def_id, receiver_steps);
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn assemble_inherent_impl_probe(&mut self, impl_def_id: DefId) {
|
||||
fn assemble_inherent_impl_probe(&mut self, impl_def_id: DefId, receiver_steps: usize) {
|
||||
if !self.impl_dups.insert(impl_def_id) {
|
||||
return; // already visited
|
||||
}
|
||||
|
|
@ -750,7 +859,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
self.push_candidate(
|
||||
Candidate {
|
||||
item,
|
||||
kind: InherentImplCandidate(impl_def_id),
|
||||
kind: InherentImplCandidate { impl_def_id, receiver_steps },
|
||||
import_ids: smallvec![],
|
||||
},
|
||||
true,
|
||||
|
|
@ -989,7 +1098,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
fn pick(mut self) -> PickResult<'tcx> {
|
||||
assert!(self.method_name.is_some());
|
||||
|
||||
if let Some(r) = self.pick_core() {
|
||||
let mut unsatisfied_predicates = Vec::new();
|
||||
|
||||
if let Some(r) = self.pick_core(&mut unsatisfied_predicates) {
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
@ -1009,7 +1120,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
|
||||
let static_candidates = std::mem::take(self.static_candidates.get_mut());
|
||||
let private_candidate = self.private_candidate.take();
|
||||
let unsatisfied_predicates = std::mem::take(self.unsatisfied_predicates.get_mut());
|
||||
|
||||
// things failed, so lets look at all traits, for diagnostic purposes now:
|
||||
self.reset();
|
||||
|
|
@ -1019,7 +1129,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
|
||||
self.assemble_extension_candidates_for_all_traits();
|
||||
|
||||
let out_of_scope_traits = match self.pick_core() {
|
||||
let out_of_scope_traits = match self.pick_core(&mut Vec::new()) {
|
||||
Some(Ok(p)) => vec![p.item.container_id(self.tcx)],
|
||||
Some(Err(MethodError::Ambiguity(v))) => v
|
||||
.into_iter()
|
||||
|
|
@ -1054,17 +1164,48 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
}))
|
||||
}
|
||||
|
||||
fn pick_core(&self) -> Option<PickResult<'tcx>> {
|
||||
fn pick_core(
|
||||
&self,
|
||||
unsatisfied_predicates: &mut Vec<(
|
||||
ty::Predicate<'tcx>,
|
||||
Option<ty::Predicate<'tcx>>,
|
||||
Option<ObligationCause<'tcx>>,
|
||||
)>,
|
||||
) -> Option<PickResult<'tcx>> {
|
||||
// Pick stable methods only first, and consider unstable candidates if not found.
|
||||
self.pick_all_method(Some(&mut vec![])).or_else(|| self.pick_all_method(None))
|
||||
self.pick_all_method(&mut PickDiagHints {
|
||||
// This first cycle, maintain a list of unstable candidates which
|
||||
// we encounter. This will end up in the Pick for diagnostics.
|
||||
unstable_candidates: Some(Vec::new()),
|
||||
// Contribute to the list of unsatisfied predicates which may
|
||||
// also be used for diagnostics.
|
||||
unsatisfied_predicates,
|
||||
})
|
||||
.or_else(|| {
|
||||
self.pick_all_method(&mut PickDiagHints {
|
||||
// On the second search, don't provide a special list of unstable
|
||||
// candidates. This indicates to the picking code that it should
|
||||
// in fact include such unstable candidates in the actual
|
||||
// search.
|
||||
unstable_candidates: None,
|
||||
// And there's no need to duplicate ourselves in the
|
||||
// unsatisifed predicates list. Provide a throwaway list.
|
||||
unsatisfied_predicates: &mut Vec::new(),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn pick_all_method(
|
||||
fn pick_all_method<'b>(
|
||||
&self,
|
||||
mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
|
||||
pick_diag_hints: &mut PickDiagHints<'b, 'tcx>,
|
||||
) -> Option<PickResult<'tcx>> {
|
||||
let track_unstable_candidates = pick_diag_hints.unstable_candidates.is_some();
|
||||
self.steps
|
||||
.iter()
|
||||
// At this point we're considering the types to which the receiver can be converted,
|
||||
// so we want to follow the `Deref` chain not the `Receiver` chain. Filter out
|
||||
// steps which can only be reached by following the (longer) `Receiver` chain.
|
||||
.filter(|step| step.reachable_via_deref)
|
||||
.filter(|step| {
|
||||
debug!("pick_all_method: step={:?}", step);
|
||||
// skip types that are from a type error or that would require dereferencing
|
||||
|
|
@ -1082,40 +1223,188 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
.unwrap_or_else(|_| {
|
||||
span_bug!(self.span, "{:?} was applicable but now isn't?", step.self_ty)
|
||||
});
|
||||
self.pick_by_value_method(step, self_ty, unstable_candidates.as_deref_mut())
|
||||
.or_else(|| {
|
||||
self.pick_autorefd_method(
|
||||
step,
|
||||
self_ty,
|
||||
hir::Mutability::Not,
|
||||
unstable_candidates.as_deref_mut(),
|
||||
)
|
||||
.or_else(|| {
|
||||
self.pick_autorefd_method(
|
||||
|
||||
let by_value_pick = self.pick_by_value_method(step, self_ty, pick_diag_hints);
|
||||
|
||||
// Check for shadowing of a by-reference method by a by-value method (see comments on check_for_shadowing)
|
||||
if let Some(by_value_pick) = by_value_pick {
|
||||
if let Ok(by_value_pick) = by_value_pick.as_ref() {
|
||||
if by_value_pick.kind == PickKind::InherentImplPick {
|
||||
if let Err(e) = self.check_for_shadowed_autorefd_method(
|
||||
by_value_pick,
|
||||
step,
|
||||
self_ty,
|
||||
hir::Mutability::Not,
|
||||
track_unstable_candidates,
|
||||
) {
|
||||
return Some(Err(e));
|
||||
}
|
||||
if let Err(e) = self.check_for_shadowed_autorefd_method(
|
||||
by_value_pick,
|
||||
step,
|
||||
self_ty,
|
||||
hir::Mutability::Mut,
|
||||
unstable_candidates.as_deref_mut(),
|
||||
)
|
||||
})
|
||||
.or_else(|| {
|
||||
self.pick_const_ptr_method(
|
||||
track_unstable_candidates,
|
||||
) {
|
||||
return Some(Err(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
return Some(by_value_pick);
|
||||
}
|
||||
|
||||
let autoref_pick = self.pick_autorefd_method(
|
||||
step,
|
||||
self_ty,
|
||||
hir::Mutability::Not,
|
||||
pick_diag_hints,
|
||||
None,
|
||||
);
|
||||
// Check for shadowing of a by-mut-ref method by a by-reference method (see comments on check_for_shadowing)
|
||||
if let Some(autoref_pick) = autoref_pick {
|
||||
if let Ok(autoref_pick) = autoref_pick.as_ref() {
|
||||
// Check we're not shadowing others
|
||||
if autoref_pick.kind == PickKind::InherentImplPick {
|
||||
if let Err(e) = self.check_for_shadowed_autorefd_method(
|
||||
autoref_pick,
|
||||
step,
|
||||
self_ty,
|
||||
unstable_candidates.as_deref_mut(),
|
||||
)
|
||||
})
|
||||
.or_else(|| {
|
||||
self.pick_reborrow_pin_method(
|
||||
step,
|
||||
self_ty,
|
||||
unstable_candidates.as_deref_mut(),
|
||||
)
|
||||
})
|
||||
})
|
||||
hir::Mutability::Mut,
|
||||
track_unstable_candidates,
|
||||
) {
|
||||
return Some(Err(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
return Some(autoref_pick);
|
||||
}
|
||||
|
||||
// Note that no shadowing errors are produced from here on,
|
||||
// as we consider const ptr methods.
|
||||
// We allow new methods that take *mut T to shadow
|
||||
// methods which took *const T, so there is no entry in
|
||||
// this list for the results of `pick_const_ptr_method`.
|
||||
// The reason is that the standard pointer cast method
|
||||
// (on a mutable pointer) always already shadows the
|
||||
// cast method (on a const pointer). So, if we added
|
||||
// `pick_const_ptr_method` to this method, the anti-
|
||||
// shadowing algorithm would always complain about
|
||||
// the conflict between *const::cast and *mut::cast.
|
||||
// In practice therefore this does constrain us:
|
||||
// we cannot add new
|
||||
// self: *mut Self
|
||||
// methods to types such as NonNull or anything else
|
||||
// which implements Receiver, because this might in future
|
||||
// shadow existing methods taking
|
||||
// self: *const NonNull<Self>
|
||||
// in the pointee. In practice, methods taking raw pointers
|
||||
// are rare, and it seems that it should be easily possible
|
||||
// to avoid such compatibility breaks.
|
||||
// We also don't check for reborrowed pin methods which
|
||||
// may be shadowed; these also seem unlikely to occur.
|
||||
self.pick_autorefd_method(
|
||||
step,
|
||||
self_ty,
|
||||
hir::Mutability::Mut,
|
||||
pick_diag_hints,
|
||||
None,
|
||||
)
|
||||
.or_else(|| self.pick_const_ptr_method(step, self_ty, pick_diag_hints))
|
||||
.or_else(|| self.pick_reborrow_pin_method(step, self_ty, pick_diag_hints))
|
||||
})
|
||||
}
|
||||
|
||||
/// Check for cases where arbitrary self types allows shadowing
|
||||
/// of methods that might be a compatibility break. Specifically,
|
||||
/// we have something like:
|
||||
/// ```ignore (illustrative)
|
||||
/// struct A;
|
||||
/// impl A {
|
||||
/// fn foo(self: &NonNull<A>) {}
|
||||
/// // note this is by reference
|
||||
/// }
|
||||
/// ```
|
||||
/// then we've come along and added this method to `NonNull`:
|
||||
/// ```ignore (illustrative)
|
||||
/// fn foo(self) // note this is by value
|
||||
/// ```
|
||||
/// Report an error in this case.
|
||||
fn check_for_shadowed_autorefd_method(
|
||||
&self,
|
||||
possible_shadower: &Pick<'tcx>,
|
||||
step: &CandidateStep<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
mutbl: hir::Mutability,
|
||||
track_unstable_candidates: bool,
|
||||
) -> Result<(), MethodError<'tcx>> {
|
||||
// We don't want to remember any of the diagnostic hints from this
|
||||
// shadow search, but we do need to provide Some/None for the
|
||||
// unstable_candidates in order to reflect the behavior of the
|
||||
// main search.
|
||||
let mut pick_diag_hints = PickDiagHints {
|
||||
unstable_candidates: if track_unstable_candidates { Some(Vec::new()) } else { None },
|
||||
unsatisfied_predicates: &mut Vec::new(),
|
||||
};
|
||||
// Set criteria for how we find methods possibly shadowed by 'possible_shadower'
|
||||
let pick_constraints = PickConstraintsForShadowed {
|
||||
// It's the same `self` type...
|
||||
autoderefs: possible_shadower.autoderefs,
|
||||
// ... but the method was found in an impl block determined
|
||||
// by searching further along the Receiver chain than the other,
|
||||
// showing that it's a smart pointer type causing the problem...
|
||||
receiver_steps: possible_shadower.receiver_steps,
|
||||
// ... and they don't end up pointing to the same item in the
|
||||
// first place (could happen with things like blanket impls for T)
|
||||
def_id: possible_shadower.item.def_id,
|
||||
};
|
||||
// A note on the autoderefs above. Within pick_by_value_method, an extra
|
||||
// autoderef may be applied in order to reborrow a reference with
|
||||
// a different lifetime. That seems as though it would break the
|
||||
// logic of these constraints, since the number of autoderefs could
|
||||
// no longer be used to identify the fundamental type of the receiver.
|
||||
// However, this extra autoderef is applied only to by-value calls
|
||||
// where the receiver is already a reference. So this situation would
|
||||
// only occur in cases where the shadowing looks like this:
|
||||
// ```
|
||||
// struct A;
|
||||
// impl A {
|
||||
// fn foo(self: &&NonNull<A>) {}
|
||||
// // note this is by DOUBLE reference
|
||||
// }
|
||||
// ```
|
||||
// then we've come along and added this method to `NonNull`:
|
||||
// ```
|
||||
// fn foo(&self) // note this is by single reference
|
||||
// ```
|
||||
// and the call is:
|
||||
// ```
|
||||
// let bar = NonNull<Foo>;
|
||||
// let bar = &foo;
|
||||
// bar.foo();
|
||||
// ```
|
||||
// In these circumstances, the logic is wrong, and we wouldn't spot
|
||||
// the shadowing, because the autoderef-based maths wouldn't line up.
|
||||
// This is a niche case and we can live without generating an error
|
||||
// in the case of such shadowing.
|
||||
let potentially_shadowed_pick = self.pick_autorefd_method(
|
||||
step,
|
||||
self_ty,
|
||||
mutbl,
|
||||
&mut pick_diag_hints,
|
||||
Some(&pick_constraints),
|
||||
);
|
||||
// Look for actual pairs of shadower/shadowed which are
|
||||
// the sort of shadowing case we want to avoid. Specifically...
|
||||
if let Some(Ok(possible_shadowed)) = potentially_shadowed_pick.as_ref() {
|
||||
let sources = [possible_shadower, possible_shadowed]
|
||||
.into_iter()
|
||||
.map(|p| self.candidate_source_from_pick(p))
|
||||
.collect();
|
||||
return Err(MethodError::Ambiguity(sources));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// For each type `T` in the step list, this attempts to find a method where
|
||||
/// the (transformed) self type is exactly `T`. We do however do one
|
||||
/// transformation on the adjustment: if we are passing a region pointer in,
|
||||
|
|
@ -1126,13 +1415,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
&self,
|
||||
step: &CandidateStep<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
|
||||
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
|
||||
) -> Option<PickResult<'tcx>> {
|
||||
if step.unsize {
|
||||
return None;
|
||||
}
|
||||
|
||||
self.pick_method(self_ty, unstable_candidates).map(|r| {
|
||||
self.pick_method(self_ty, pick_diag_hints, None).map(|r| {
|
||||
r.map(|mut pick| {
|
||||
pick.autoderefs = step.autoderefs;
|
||||
|
||||
|
|
@ -1170,15 +1459,22 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
step: &CandidateStep<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
mutbl: hir::Mutability,
|
||||
unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
|
||||
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
|
||||
pick_constraints: Option<&PickConstraintsForShadowed>,
|
||||
) -> Option<PickResult<'tcx>> {
|
||||
let tcx = self.tcx;
|
||||
|
||||
if let Some(pick_constraints) = pick_constraints {
|
||||
if !pick_constraints.may_shadow_based_on_autoderefs(step.autoderefs) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
// In general, during probing we erase regions.
|
||||
let region = tcx.lifetimes.re_erased;
|
||||
|
||||
let autoref_ty = Ty::new_ref(tcx, region, self_ty, mutbl);
|
||||
self.pick_method(autoref_ty, unstable_candidates).map(|r| {
|
||||
self.pick_method(autoref_ty, pick_diag_hints, pick_constraints).map(|r| {
|
||||
r.map(|mut pick| {
|
||||
pick.autoderefs = step.autoderefs;
|
||||
pick.autoref_or_ptr_adjustment =
|
||||
|
|
@ -1189,12 +1485,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
/// Looks for applicable methods if we reborrow a `Pin<&mut T>` as a `Pin<&T>`.
|
||||
#[instrument(level = "debug", skip(self, step, unstable_candidates))]
|
||||
#[instrument(level = "debug", skip(self, step, pick_diag_hints))]
|
||||
fn pick_reborrow_pin_method(
|
||||
&self,
|
||||
step: &CandidateStep<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
|
||||
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
|
||||
) -> Option<PickResult<'tcx>> {
|
||||
if !self.tcx.features().pin_ergonomics() {
|
||||
return None;
|
||||
|
|
@ -1215,7 +1511,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
|
||||
let region = self.tcx.lifetimes.re_erased;
|
||||
let autopin_ty = Ty::new_pinned_ref(self.tcx, region, inner_ty, hir::Mutability::Not);
|
||||
self.pick_method(autopin_ty, unstable_candidates).map(|r| {
|
||||
self.pick_method(autopin_ty, pick_diag_hints, None).map(|r| {
|
||||
r.map(|mut pick| {
|
||||
pick.autoderefs = step.autoderefs;
|
||||
pick.autoref_or_ptr_adjustment =
|
||||
|
|
@ -1232,7 +1528,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
&self,
|
||||
step: &CandidateStep<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
|
||||
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
|
||||
) -> Option<PickResult<'tcx>> {
|
||||
// Don't convert an unsized reference to ptr
|
||||
if step.unsize {
|
||||
|
|
@ -1244,7 +1540,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
};
|
||||
|
||||
let const_ptr_ty = Ty::new_imm_ptr(self.tcx, ty);
|
||||
self.pick_method(const_ptr_ty, unstable_candidates).map(|r| {
|
||||
self.pick_method(const_ptr_ty, pick_diag_hints, None).map(|r| {
|
||||
r.map(|mut pick| {
|
||||
pick.autoderefs = step.autoderefs;
|
||||
pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::ToConstPtr);
|
||||
|
|
@ -1256,40 +1552,35 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
fn pick_method(
|
||||
&self,
|
||||
self_ty: Ty<'tcx>,
|
||||
mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
|
||||
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
|
||||
pick_constraints: Option<&PickConstraintsForShadowed>,
|
||||
) -> Option<PickResult<'tcx>> {
|
||||
debug!("pick_method(self_ty={})", self.ty_to_string(self_ty));
|
||||
|
||||
let mut possibly_unsatisfied_predicates = Vec::new();
|
||||
|
||||
for (kind, candidates) in
|
||||
[("inherent", &self.inherent_candidates), ("extension", &self.extension_candidates)]
|
||||
{
|
||||
debug!("searching {} candidates", kind);
|
||||
let res = self.consider_candidates(
|
||||
self_ty,
|
||||
candidates,
|
||||
&mut possibly_unsatisfied_predicates,
|
||||
unstable_candidates.as_deref_mut(),
|
||||
);
|
||||
let res =
|
||||
self.consider_candidates(self_ty, candidates, pick_diag_hints, pick_constraints);
|
||||
if let Some(pick) = res {
|
||||
return Some(pick);
|
||||
}
|
||||
}
|
||||
|
||||
if self.private_candidate.get().is_none() {
|
||||
if let Some(Ok(pick)) =
|
||||
self.consider_candidates(self_ty, &self.private_candidates, &mut vec![], None)
|
||||
{
|
||||
if let Some(Ok(pick)) = self.consider_candidates(
|
||||
self_ty,
|
||||
&self.private_candidates,
|
||||
&mut PickDiagHints {
|
||||
unstable_candidates: None,
|
||||
unsatisfied_predicates: &mut vec![],
|
||||
},
|
||||
None,
|
||||
) {
|
||||
self.private_candidate.set(Some((pick.item.kind.as_def_kind(), pick.item.def_id)));
|
||||
}
|
||||
}
|
||||
|
||||
// `pick_method` may be called twice for the same self_ty if no stable methods
|
||||
// match. Only extend once.
|
||||
if unstable_candidates.is_some() {
|
||||
self.unsatisfied_predicates.borrow_mut().extend(possibly_unsatisfied_predicates);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
|
|
@ -1297,17 +1588,25 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
&self,
|
||||
self_ty: Ty<'tcx>,
|
||||
candidates: &[Candidate<'tcx>],
|
||||
possibly_unsatisfied_predicates: &mut Vec<(
|
||||
ty::Predicate<'tcx>,
|
||||
Option<ty::Predicate<'tcx>>,
|
||||
Option<ObligationCause<'tcx>>,
|
||||
)>,
|
||||
mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
|
||||
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
|
||||
pick_constraints: Option<&PickConstraintsForShadowed>,
|
||||
) -> Option<PickResult<'tcx>> {
|
||||
let mut applicable_candidates: Vec<_> = candidates
|
||||
.iter()
|
||||
.filter(|candidate| {
|
||||
pick_constraints
|
||||
.map(|pick_constraints| pick_constraints.candidate_may_shadow(&candidate))
|
||||
.unwrap_or(true)
|
||||
})
|
||||
.map(|probe| {
|
||||
(probe, self.consider_probe(self_ty, probe, possibly_unsatisfied_predicates))
|
||||
(
|
||||
probe,
|
||||
self.consider_probe(
|
||||
self_ty,
|
||||
probe,
|
||||
&mut pick_diag_hints.unsatisfied_predicates,
|
||||
),
|
||||
)
|
||||
})
|
||||
.filter(|&(_, status)| status != ProbeResult::NoMatch)
|
||||
.collect();
|
||||
|
|
@ -1322,7 +1621,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
if let Some(uc) = &mut unstable_candidates {
|
||||
if let Some(uc) = &mut pick_diag_hints.unstable_candidates {
|
||||
applicable_candidates.retain(|&(candidate, _)| {
|
||||
if let stability::EvalResult::Deny { feature, .. } =
|
||||
self.tcx.eval_stability(candidate.item.def_id, None, self.span, None)
|
||||
|
|
@ -1340,10 +1639,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
applicable_candidates.pop().map(|(probe, status)| match status {
|
||||
ProbeResult::Match => {
|
||||
Ok(probe
|
||||
.to_unadjusted_pick(self_ty, unstable_candidates.cloned().unwrap_or_default()))
|
||||
}
|
||||
ProbeResult::Match => Ok(probe.to_unadjusted_pick(
|
||||
self_ty,
|
||||
pick_diag_hints.unstable_candidates.clone().unwrap_or_default(),
|
||||
)),
|
||||
ProbeResult::NoMatch | ProbeResult::BadReturnType => Err(MethodError::BadReturnType),
|
||||
})
|
||||
}
|
||||
|
|
@ -1372,6 +1671,7 @@ impl<'tcx> Pick<'tcx> {
|
|||
autoref_or_ptr_adjustment: _,
|
||||
self_ty,
|
||||
unstable_candidates: _,
|
||||
receiver_steps: _,
|
||||
} = *self;
|
||||
self_ty != other.self_ty || def_id != other.item.def_id
|
||||
}
|
||||
|
|
@ -1447,7 +1747,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
/// so do not use to make a decision that may lead to a successful compilation.
|
||||
fn candidate_source(&self, candidate: &Candidate<'tcx>, self_ty: Ty<'tcx>) -> CandidateSource {
|
||||
match candidate.kind {
|
||||
InherentImplCandidate(_) => {
|
||||
InherentImplCandidate { .. } => {
|
||||
CandidateSource::Impl(candidate.item.container_id(self.tcx))
|
||||
}
|
||||
ObjectCandidate(_) | WhereClauseCandidate(_) => {
|
||||
|
|
@ -1477,6 +1777,15 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn candidate_source_from_pick(&self, pick: &Pick<'tcx>) -> CandidateSource {
|
||||
match pick.kind {
|
||||
InherentImplPick => CandidateSource::Impl(pick.item.container_id(self.tcx)),
|
||||
ObjectPick | WhereClausePick(_) | TraitPick => {
|
||||
CandidateSource::Trait(pick.item.container_id(self.tcx))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(self, possibly_unsatisfied_predicates), ret)]
|
||||
fn consider_probe(
|
||||
&self,
|
||||
|
|
@ -1501,7 +1810,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
let (mut xform_self_ty, mut xform_ret_ty);
|
||||
|
||||
match probe.kind {
|
||||
InherentImplCandidate(impl_def_id) => {
|
||||
InherentImplCandidate { impl_def_id, .. } => {
|
||||
let impl_args = self.fresh_args_for_item(self.span, impl_def_id);
|
||||
let impl_ty = self.tcx.type_of(impl_def_id).instantiate(self.tcx, impl_args);
|
||||
(xform_self_ty, xform_ret_ty) =
|
||||
|
|
@ -1693,7 +2002,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
// We don't normalize the other candidates for perf/backwards-compat reasons...
|
||||
// but `self.return_type` is only set on the diagnostic-path, so we
|
||||
// should be okay doing it here.
|
||||
if !matches!(probe.kind, InherentImplCandidate(_)) {
|
||||
if !matches!(probe.kind, InherentImplCandidate { .. }) {
|
||||
xform_ret_ty = ocx.normalize(&cause, self.param_env, xform_ret_ty);
|
||||
}
|
||||
|
||||
|
|
@ -1771,6 +2080,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
autoref_or_ptr_adjustment: None,
|
||||
self_ty,
|
||||
unstable_candidates: vec![],
|
||||
receiver_steps: None,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -1808,7 +2118,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
pcx.method_name = Some(method_name);
|
||||
pcx.assemble_inherent_candidates();
|
||||
pcx.assemble_extension_candidates_for_all_traits();
|
||||
pcx.pick_core().and_then(|pick| pick.ok()).map(|pick| pick.item)
|
||||
pcx.pick_core(&mut Vec::new()).and_then(|pick| pick.ok()).map(|pick| pick.item)
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
|
@ -2042,7 +2352,7 @@ impl<'tcx> Candidate<'tcx> {
|
|||
Pick {
|
||||
item: self.item,
|
||||
kind: match self.kind {
|
||||
InherentImplCandidate(_) => InherentImplPick,
|
||||
InherentImplCandidate { .. } => InherentImplPick,
|
||||
ObjectCandidate(_) => ObjectPick,
|
||||
TraitCandidate(_) => TraitPick,
|
||||
WhereClauseCandidate(trait_ref) => {
|
||||
|
|
@ -2064,6 +2374,10 @@ impl<'tcx> Candidate<'tcx> {
|
|||
autoref_or_ptr_adjustment: None,
|
||||
self_ty,
|
||||
unstable_candidates,
|
||||
receiver_steps: match self.kind {
|
||||
InherentImplCandidate { receiver_steps, .. } => Some(receiver_steps),
|
||||
_ => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1840,7 +1840,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
/// captured by move.
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(async_closure)]
|
||||
/// let x = &1i32; // Let's call this lifetime `'1`.
|
||||
/// let c = async move || {
|
||||
/// println!("{:?}", *x);
|
||||
|
|
@ -1855,7 +1854,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
/// child capture with the lifetime of the parent coroutine-closure's env.
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(async_closure)]
|
||||
/// let mut x = 1i32;
|
||||
/// let c = async || {
|
||||
/// x = 1;
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ declare_lint! {
|
|||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(async_closure)]
|
||||
/// #![warn(closure_returning_async_block)]
|
||||
/// let c = |x: &str| async {};
|
||||
/// ```
|
||||
|
|
@ -40,8 +39,6 @@ declare_lint! {
|
|||
/// But it does work with async closures:
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(async_closure)]
|
||||
///
|
||||
/// async fn callback(x: &str) {}
|
||||
///
|
||||
/// let captured_str = String::new();
|
||||
|
|
@ -52,7 +49,6 @@ declare_lint! {
|
|||
pub CLOSURE_RETURNING_ASYNC_BLOCK,
|
||||
Allow,
|
||||
"closure that returns `async {}` could be rewritten as an async closure",
|
||||
@feature_gate = async_closure;
|
||||
}
|
||||
|
||||
declare_lint_pass!(
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
#![cfg_attr(not(bootstrap), allow(rustc::symbol_intern_string_literal))]
|
||||
|
||||
use rustc_span::{Symbol, create_default_session_globals_then};
|
||||
|
||||
use crate::levels::parse_lint_and_tool_name;
|
||||
|
|
|
|||
|
|
@ -149,11 +149,21 @@ pub struct CandidateStep<'tcx> {
|
|||
/// `foo.by_raw_ptr()` will work and `foo.by_ref()` won't.
|
||||
pub from_unsafe_deref: bool,
|
||||
pub unsize: bool,
|
||||
/// We will generate CandidateSteps which are reachable via a chain
|
||||
/// of following `Receiver`. The first 'n' of those will be reachable
|
||||
/// by following a chain of 'Deref' instead (since there's a blanket
|
||||
/// implementation of Receiver for Deref).
|
||||
/// We use the entire set of steps when identifying method candidates
|
||||
/// (e.g. identifying relevant `impl` blocks) but only those that are
|
||||
/// reachable via Deref when examining what the receiver type can
|
||||
/// be converted into by autodereffing.
|
||||
pub reachable_via_deref: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, HashStable)]
|
||||
pub struct MethodAutoderefStepsResult<'tcx> {
|
||||
/// The valid autoderef steps that could be found.
|
||||
/// The valid autoderef steps that could be found by following a chain
|
||||
/// of `Receiver<Target=T>` or `Deref<Target=T>` trait implementations.
|
||||
pub steps: &'tcx [CandidateStep<'tcx>],
|
||||
/// If Some(T), a type autoderef reported an error on.
|
||||
pub opt_bad_ty: Option<&'tcx MethodAutoderefBadTy<'tcx>>,
|
||||
|
|
|
|||
|
|
@ -677,23 +677,26 @@ impl<'tcx> Instance<'tcx> {
|
|||
//
|
||||
// 1) The underlying method expects a caller location parameter
|
||||
// in the ABI
|
||||
if resolved.def.requires_caller_location(tcx)
|
||||
// 2) The caller location parameter comes from having `#[track_caller]`
|
||||
// on the implementation, and *not* on the trait method.
|
||||
&& !tcx.should_inherit_track_caller(def)
|
||||
// If the method implementation comes from the trait definition itself
|
||||
// (e.g. `trait Foo { #[track_caller] my_fn() { /* impl */ } }`),
|
||||
// then we don't need to generate a shim. This check is needed because
|
||||
// `should_inherit_track_caller` returns `false` if our method
|
||||
// implementation comes from the trait block, and not an impl block
|
||||
&& !matches!(
|
||||
tcx.opt_associated_item(def),
|
||||
Some(ty::AssocItem {
|
||||
container: ty::AssocItemContainer::Trait,
|
||||
..
|
||||
})
|
||||
)
|
||||
{
|
||||
let needs_track_caller_shim = resolved.def.requires_caller_location(tcx)
|
||||
// 2) The caller location parameter comes from having `#[track_caller]`
|
||||
// on the implementation, and *not* on the trait method.
|
||||
&& !tcx.should_inherit_track_caller(def)
|
||||
// If the method implementation comes from the trait definition itself
|
||||
// (e.g. `trait Foo { #[track_caller] my_fn() { /* impl */ } }`),
|
||||
// then we don't need to generate a shim. This check is needed because
|
||||
// `should_inherit_track_caller` returns `false` if our method
|
||||
// implementation comes from the trait block, and not an impl block
|
||||
&& !matches!(
|
||||
tcx.opt_associated_item(def),
|
||||
Some(ty::AssocItem {
|
||||
container: ty::AssocItemContainer::Trait,
|
||||
..
|
||||
})
|
||||
);
|
||||
// We also need to generate a shim if this is an AFIT.
|
||||
let needs_rpitit_shim =
|
||||
tcx.return_position_impl_trait_in_trait_shim_data(def).is_some();
|
||||
if needs_track_caller_shim || needs_rpitit_shim {
|
||||
if tcx.is_closure_like(def) {
|
||||
debug!(
|
||||
" => vtable fn pointer created for closure with #[track_caller]: {:?} for method {:?} {:?}",
|
||||
|
|
|
|||
|
|
@ -146,6 +146,7 @@ mod opaque_types;
|
|||
mod parameterized;
|
||||
mod predicate;
|
||||
mod region;
|
||||
mod return_position_impl_trait_in_trait;
|
||||
mod rvalue_scopes;
|
||||
mod structural_impls;
|
||||
#[allow(hidden_glob_reexports)]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,95 @@
|
|||
use rustc_hir::def_id::DefId;
|
||||
|
||||
use crate::ty::{self, ExistentialPredicateStableCmpExt, TyCtxt};
|
||||
|
||||
impl<'tcx> TyCtxt<'tcx> {
|
||||
/// Given a `def_id` of a trait or impl method, compute whether that method needs to
|
||||
/// have an RPITIT shim applied to it for it to be object safe. If so, return the
|
||||
/// `def_id` of the RPITIT, and also the args of trait method that returns the RPITIT.
|
||||
///
|
||||
/// NOTE that these args are not, in general, the same as than the RPITIT's args. They
|
||||
/// are a subset of those args, since they do not include the late-bound lifetimes of
|
||||
/// the RPITIT. Depending on the context, these will need to be dealt with in different
|
||||
/// ways -- in codegen, it's okay to fill them with ReErased.
|
||||
pub fn return_position_impl_trait_in_trait_shim_data(
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> Option<(DefId, ty::EarlyBinder<'tcx, ty::GenericArgsRef<'tcx>>)> {
|
||||
let assoc_item = self.opt_associated_item(def_id)?;
|
||||
|
||||
let (trait_item_def_id, opt_impl_def_id) = match assoc_item.container {
|
||||
ty::AssocItemContainer::Impl => {
|
||||
(assoc_item.trait_item_def_id?, Some(self.parent(def_id)))
|
||||
}
|
||||
ty::AssocItemContainer::Trait => (def_id, None),
|
||||
};
|
||||
|
||||
let sig = self.fn_sig(trait_item_def_id);
|
||||
|
||||
// Check if the trait returns an RPITIT.
|
||||
let ty::Alias(ty::Projection, ty::AliasTy { def_id, .. }) =
|
||||
*sig.skip_binder().skip_binder().output().kind()
|
||||
else {
|
||||
return None;
|
||||
};
|
||||
if !self.is_impl_trait_in_trait(def_id) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let args = if let Some(impl_def_id) = opt_impl_def_id {
|
||||
// Rebase the args from the RPITIT onto the impl trait ref, so we can later
|
||||
// substitute them with the method args of the *impl* method, since that's
|
||||
// the instance we're building a vtable shim for.
|
||||
ty::GenericArgs::identity_for_item(self, trait_item_def_id).rebase_onto(
|
||||
self,
|
||||
self.parent(trait_item_def_id),
|
||||
self.impl_trait_ref(impl_def_id)
|
||||
.expect("expected impl trait ref from parent of impl item")
|
||||
.instantiate_identity()
|
||||
.args,
|
||||
)
|
||||
} else {
|
||||
// This is when we have a default trait implementation.
|
||||
ty::GenericArgs::identity_for_item(self, trait_item_def_id)
|
||||
};
|
||||
|
||||
Some((def_id, ty::EarlyBinder::bind(args)))
|
||||
}
|
||||
|
||||
/// Given a `DefId` of an RPITIT and its args, return the existential predicates
|
||||
/// that corresponds to the RPITIT's bounds with the self type erased.
|
||||
pub fn item_bounds_to_existential_predicates(
|
||||
self,
|
||||
def_id: DefId,
|
||||
args: ty::GenericArgsRef<'tcx>,
|
||||
) -> &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> {
|
||||
let mut bounds: Vec<_> = self
|
||||
.item_super_predicates(def_id)
|
||||
.iter_instantiated(self, args)
|
||||
.filter_map(|clause| {
|
||||
clause
|
||||
.kind()
|
||||
.map_bound(|clause| match clause {
|
||||
ty::ClauseKind::Trait(trait_pred) => Some(ty::ExistentialPredicate::Trait(
|
||||
ty::ExistentialTraitRef::erase_self_ty(self, trait_pred.trait_ref),
|
||||
)),
|
||||
ty::ClauseKind::Projection(projection_pred) => {
|
||||
Some(ty::ExistentialPredicate::Projection(
|
||||
ty::ExistentialProjection::erase_self_ty(self, projection_pred),
|
||||
))
|
||||
}
|
||||
ty::ClauseKind::TypeOutlives(_) => {
|
||||
// Type outlives bounds don't really turn into anything,
|
||||
// since we must use an intersection region for the `dyn*`'s
|
||||
// region anyways.
|
||||
None
|
||||
}
|
||||
_ => unreachable!("unexpected clause in item bounds: {clause:?}"),
|
||||
})
|
||||
.transpose()
|
||||
})
|
||||
.collect();
|
||||
bounds.sort_by(|a, b| a.skip_binder().stable_cmp(self, &b.skip_binder()));
|
||||
self.mk_poly_existential_predicates(&bounds)
|
||||
}
|
||||
}
|
||||
|
|
@ -4,52 +4,26 @@
|
|||
//! field-deref on a local variable, `x.field`, has the same meaning
|
||||
//! in both domains). Indexed projections are the exception: `a[x]`
|
||||
//! needs to be treated as mapping to the same move path as `a[y]` as
|
||||
//! well as `a[13]`, etc.
|
||||
//! well as `a[13]`, etc. So we map these `x`/`y` values to `()`.
|
||||
//!
|
||||
//! (In theory, the analysis could be extended to work with sets of
|
||||
//! paths, so that `a[0]` and `a[13]` could be kept distinct, while
|
||||
//! `a[x]` would still overlap them both. But that is not this
|
||||
//! representation does today.)
|
||||
|
||||
use rustc_middle::mir::{Local, Operand, PlaceElem, ProjectionElem};
|
||||
use rustc_middle::ty::Ty;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub(crate) struct AbstractOperand;
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub(crate) struct AbstractType;
|
||||
pub(crate) type AbstractElem = ProjectionElem<AbstractOperand, AbstractType>;
|
||||
use rustc_middle::mir::{PlaceElem, ProjectionElem, ProjectionKind};
|
||||
|
||||
pub(crate) trait Lift {
|
||||
type Abstract;
|
||||
fn lift(&self) -> Self::Abstract;
|
||||
}
|
||||
impl<'tcx> Lift for Operand<'tcx> {
|
||||
type Abstract = AbstractOperand;
|
||||
fn lift(&self) -> Self::Abstract {
|
||||
AbstractOperand
|
||||
}
|
||||
}
|
||||
impl Lift for Local {
|
||||
type Abstract = AbstractOperand;
|
||||
fn lift(&self) -> Self::Abstract {
|
||||
AbstractOperand
|
||||
}
|
||||
}
|
||||
impl<'tcx> Lift for Ty<'tcx> {
|
||||
type Abstract = AbstractType;
|
||||
fn lift(&self) -> Self::Abstract {
|
||||
AbstractType
|
||||
}
|
||||
fn lift(&self) -> ProjectionKind;
|
||||
}
|
||||
|
||||
impl<'tcx> Lift for PlaceElem<'tcx> {
|
||||
type Abstract = AbstractElem;
|
||||
fn lift(&self) -> Self::Abstract {
|
||||
fn lift(&self) -> ProjectionKind {
|
||||
match *self {
|
||||
ProjectionElem::Deref => ProjectionElem::Deref,
|
||||
ProjectionElem::Field(f, ty) => ProjectionElem::Field(f, ty.lift()),
|
||||
ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty.lift()),
|
||||
ProjectionElem::Index(ref i) => ProjectionElem::Index(i.lift()),
|
||||
ProjectionElem::Field(f, _ty) => ProjectionElem::Field(f, ()),
|
||||
ProjectionElem::OpaqueCast(_ty) => ProjectionElem::OpaqueCast(()),
|
||||
ProjectionElem::Index(_i) => ProjectionElem::Index(()),
|
||||
ProjectionElem::Subslice { from, to, from_end } => {
|
||||
ProjectionElem::Subslice { from, to, from_end }
|
||||
}
|
||||
|
|
@ -57,7 +31,7 @@ impl<'tcx> Lift for PlaceElem<'tcx> {
|
|||
ProjectionElem::ConstantIndex { offset, min_length, from_end }
|
||||
}
|
||||
ProjectionElem::Downcast(a, u) => ProjectionElem::Downcast(a, u),
|
||||
ProjectionElem::Subtype(ty) => ProjectionElem::Subtype(ty.lift()),
|
||||
ProjectionElem::Subtype(_ty) => ProjectionElem::Subtype(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use rustc_middle::ty::{Ty, TyCtxt};
|
|||
use rustc_span::Span;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use self::abs_domain::{AbstractElem, Lift};
|
||||
use self::abs_domain::Lift;
|
||||
use crate::un_derefer::UnDerefer;
|
||||
|
||||
mod abs_domain;
|
||||
|
|
@ -300,7 +300,7 @@ pub struct MovePathLookup<'tcx> {
|
|||
/// subsequent search so that it is solely relative to that
|
||||
/// base-place). For the remaining lookup, we map the projection
|
||||
/// elem to the associated MovePathIndex.
|
||||
projections: FxHashMap<(MovePathIndex, AbstractElem), MovePathIndex>,
|
||||
projections: FxHashMap<(MovePathIndex, ProjectionKind), MovePathIndex>,
|
||||
|
||||
un_derefer: UnDerefer<'tcx>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,6 @@
|
|||
//!
|
||||
//! Consider an async closure like:
|
||||
//! ```rust
|
||||
//! #![feature(async_closure)]
|
||||
//!
|
||||
//! let x = vec![1, 2, 3];
|
||||
//!
|
||||
//! let closure = async move || {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ use rustc_index::{Idx, IndexVec};
|
|||
use rustc_middle::mir::patch::MirPatch;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::adjustment::PointerCoercion;
|
||||
use rustc_middle::ty::{
|
||||
self, CoroutineArgs, CoroutineArgsExt, EarlyBinder, GenericArgs, Ty, TyCtxt,
|
||||
};
|
||||
|
|
@ -710,6 +711,13 @@ fn build_call_shim<'tcx>(
|
|||
};
|
||||
|
||||
let def_id = instance.def_id();
|
||||
|
||||
let rpitit_shim = if let ty::InstanceKind::ReifyShim(..) = instance {
|
||||
tcx.return_position_impl_trait_in_trait_shim_data(def_id)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let sig = tcx.fn_sig(def_id);
|
||||
let sig = sig.map_bound(|sig| tcx.instantiate_bound_regions_with_erased(sig));
|
||||
|
||||
|
|
@ -765,9 +773,34 @@ fn build_call_shim<'tcx>(
|
|||
let mut local_decls = local_decls_for_sig(&sig, span);
|
||||
let source_info = SourceInfo::outermost(span);
|
||||
|
||||
let mut destination = Place::return_place();
|
||||
if let Some((rpitit_def_id, fn_args)) = rpitit_shim {
|
||||
let rpitit_args =
|
||||
fn_args.instantiate_identity().extend_to(tcx, rpitit_def_id, |param, _| {
|
||||
match param.kind {
|
||||
ty::GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
|
||||
ty::GenericParamDefKind::Type { .. }
|
||||
| ty::GenericParamDefKind::Const { .. } => {
|
||||
unreachable!("rpitit should have no addition ty/ct")
|
||||
}
|
||||
}
|
||||
});
|
||||
let dyn_star_ty = Ty::new_dynamic(
|
||||
tcx,
|
||||
tcx.item_bounds_to_existential_predicates(rpitit_def_id, rpitit_args),
|
||||
tcx.lifetimes.re_erased,
|
||||
ty::DynStar,
|
||||
);
|
||||
destination = local_decls.push(local_decls[RETURN_PLACE].clone()).into();
|
||||
local_decls[RETURN_PLACE].ty = dyn_star_ty;
|
||||
let mut inputs_and_output = sig.inputs_and_output.to_vec();
|
||||
*inputs_and_output.last_mut().unwrap() = dyn_star_ty;
|
||||
sig.inputs_and_output = tcx.mk_type_list(&inputs_and_output);
|
||||
}
|
||||
|
||||
let rcvr_place = || {
|
||||
assert!(rcvr_adjustment.is_some());
|
||||
Place::from(Local::new(1 + 0))
|
||||
Place::from(Local::new(1))
|
||||
};
|
||||
let mut statements = vec![];
|
||||
|
||||
|
|
@ -854,7 +887,7 @@ fn build_call_shim<'tcx>(
|
|||
TerminatorKind::Call {
|
||||
func: callee,
|
||||
args,
|
||||
destination: Place::return_place(),
|
||||
destination,
|
||||
target: Some(BasicBlock::new(1)),
|
||||
unwind: if let Some(Adjustment::RefMut) = rcvr_adjustment {
|
||||
UnwindAction::Cleanup(BasicBlock::new(3))
|
||||
|
|
@ -882,7 +915,24 @@ fn build_call_shim<'tcx>(
|
|||
);
|
||||
}
|
||||
// BB #1/#2 - return
|
||||
block(&mut blocks, vec![], TerminatorKind::Return, false);
|
||||
// NOTE: If this is an RPITIT in dyn, we also want to coerce
|
||||
// the return type of the function into a `dyn*`.
|
||||
let stmts = if rpitit_shim.is_some() {
|
||||
vec![Statement {
|
||||
source_info,
|
||||
kind: StatementKind::Assign(Box::new((
|
||||
Place::return_place(),
|
||||
Rvalue::Cast(
|
||||
CastKind::PointerCoercion(PointerCoercion::DynStar, CoercionSource::Implicit),
|
||||
Operand::Move(destination),
|
||||
sig.output(),
|
||||
),
|
||||
))),
|
||||
}]
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
block(&mut blocks, stmts, TerminatorKind::Return, false);
|
||||
if let Some(Adjustment::RefMut) = rcvr_adjustment {
|
||||
// BB #3 - drop if closure panics
|
||||
block(
|
||||
|
|
|
|||
|
|
@ -42,7 +42,10 @@ fn custom_coerce_unsize_info<'tcx>(
|
|||
..
|
||||
})) => Ok(tcx.coerce_unsized_info(impl_def_id)?.custom_kind.unwrap()),
|
||||
impl_source => {
|
||||
bug!("invalid `CoerceUnsized` impl_source: {:?}", impl_source);
|
||||
bug!(
|
||||
"invalid `CoerceUnsized` from {source_ty} to {target_ty}: impl_source: {:?}",
|
||||
impl_source
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use rustc_ast::token::{self, Delimiter, Token};
|
||||
use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
|
||||
use rustc_ast_pretty::pprust::token_to_string;
|
||||
use rustc_errors::{Applicability, PErr};
|
||||
use rustc_errors::{Applicability, Diag};
|
||||
use rustc_span::symbol::kw;
|
||||
|
||||
use super::diagnostics::{report_suspicious_mismatch_block, same_indentation_level};
|
||||
|
|
@ -14,7 +14,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> {
|
|||
pub(super) fn lex_token_trees(
|
||||
&mut self,
|
||||
is_delimited: bool,
|
||||
) -> (Spacing, TokenStream, Result<(), Vec<PErr<'psess>>>) {
|
||||
) -> (Spacing, TokenStream, Result<(), Vec<Diag<'psess>>>) {
|
||||
// Move past the opening delimiter.
|
||||
let open_spacing = self.bump_minimal();
|
||||
|
||||
|
|
@ -56,7 +56,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> {
|
|||
}
|
||||
}
|
||||
|
||||
fn eof_err(&mut self) -> PErr<'psess> {
|
||||
fn eof_err(&mut self) -> Diag<'psess> {
|
||||
let msg = "this file contains an unclosed delimiter";
|
||||
let mut err = self.dcx().struct_span_err(self.token.span, msg);
|
||||
|
||||
|
|
@ -98,7 +98,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> {
|
|||
fn lex_token_tree_open_delim(
|
||||
&mut self,
|
||||
open_delim: Delimiter,
|
||||
) -> Result<TokenTree, Vec<PErr<'psess>>> {
|
||||
) -> Result<TokenTree, Vec<Diag<'psess>>> {
|
||||
// The span for beginning of the delimited section.
|
||||
let pre_span = self.token.span;
|
||||
|
||||
|
|
@ -250,8 +250,8 @@ impl<'psess, 'src> Lexer<'psess, 'src> {
|
|||
fn unclosed_delim_err(
|
||||
&mut self,
|
||||
tts: TokenStream,
|
||||
mut errs: Vec<PErr<'psess>>,
|
||||
) -> Vec<PErr<'psess>> {
|
||||
mut errs: Vec<Diag<'psess>>,
|
||||
) -> Vec<Diag<'psess>> {
|
||||
// If there are unclosed delims, see if there are diff markers and if so, point them
|
||||
// out instead of complaining about the unclosed delims.
|
||||
let mut parser = Parser::new(self.psess, tts, None);
|
||||
|
|
@ -308,7 +308,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> {
|
|||
errs
|
||||
}
|
||||
|
||||
fn close_delim_err(&mut self, delim: Delimiter) -> PErr<'psess> {
|
||||
fn close_delim_err(&mut self, delim: Delimiter) -> Diag<'psess> {
|
||||
// An unexpected closing delimiter (i.e., there is no matching opening delimiter).
|
||||
let token_str = token_to_string(&self.token);
|
||||
let msg = format!("unexpected closing delimiter: `{token_str}`");
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use rustc_ast_pretty::pprust;
|
|||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::{
|
||||
Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, FatalError, PErr, PResult, Subdiagnostic,
|
||||
Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, FatalError, PResult, Subdiagnostic,
|
||||
Suggestions, pluralize,
|
||||
};
|
||||
use rustc_session::errors::ExprParenthesesNeeded;
|
||||
|
|
@ -2132,7 +2132,7 @@ impl<'a> Parser<'a> {
|
|||
&mut self,
|
||||
delim: Delimiter,
|
||||
lo: Span,
|
||||
err: PErr<'a>,
|
||||
err: Diag<'a>,
|
||||
) -> P<Expr> {
|
||||
let guar = err.emit();
|
||||
// Recover from parse error, callers expect the closing delim to be consumed.
|
||||
|
|
@ -3014,7 +3014,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
/// Check for exclusive ranges written as `..<`
|
||||
pub(crate) fn maybe_err_dotdotlt_syntax(&self, maybe_lt: Token, mut err: PErr<'a>) -> PErr<'a> {
|
||||
pub(crate) fn maybe_err_dotdotlt_syntax(&self, maybe_lt: Token, mut err: Diag<'a>) -> Diag<'a> {
|
||||
if maybe_lt == token::Lt
|
||||
&& (self.expected_tokens.contains(&TokenType::Token(token::Gt))
|
||||
|| matches!(self.token.kind, token::Literal(..)))
|
||||
|
|
|
|||
|
|
@ -1369,11 +1369,14 @@ impl<'a> Parser<'a> {
|
|||
))
|
||||
} else {
|
||||
// Field access `expr.f`
|
||||
let span = lo.to(self.prev_token.span);
|
||||
if let Some(args) = seg.args {
|
||||
self.dcx().emit_err(errors::FieldExpressionWithGeneric(args.span()));
|
||||
// See `StashKey::GenericInFieldExpr` for more info on why we stash this.
|
||||
self.dcx()
|
||||
.create_err(errors::FieldExpressionWithGeneric(args.span()))
|
||||
.stash(seg.ident.span, StashKey::GenericInFieldExpr);
|
||||
}
|
||||
|
||||
let span = lo.to(self.prev_token.span);
|
||||
Ok(self.mk_expr(span, ExprKind::Field(self_arg, seg.ident)))
|
||||
}
|
||||
}
|
||||
|
|
@ -2363,10 +2366,7 @@ impl<'a> Parser<'a> {
|
|||
};
|
||||
|
||||
match coroutine_kind {
|
||||
Some(CoroutineKind::Async { span, .. }) => {
|
||||
// Feature-gate `async ||` closures.
|
||||
self.psess.gated_spans.gate(sym::async_closure, span);
|
||||
}
|
||||
Some(CoroutineKind::Async { .. }) => {}
|
||||
Some(CoroutineKind::Gen { span, .. }) | Some(CoroutineKind::AsyncGen { span, .. }) => {
|
||||
// Feature-gate `gen ||` and `async gen ||` closures.
|
||||
// FIXME(gen_blocks): This perhaps should be a different gate.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
#![cfg_attr(not(bootstrap), allow(rustc::symbol_intern_string_literal))]
|
||||
|
||||
use std::assert_matches::assert_matches;
|
||||
use std::io::prelude::*;
|
||||
use std::iter::Peekable;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
#![cfg_attr(not(bootstrap), allow(rustc::symbol_intern_string_literal))]
|
||||
|
||||
use rustc_ast::token::{self, IdentIsRaw};
|
||||
use rustc_ast::tokenstream::{TokenStream, TokenTree};
|
||||
use rustc_span::{BytePos, Span, Symbol, create_default_session_globals_then};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
#![cfg_attr(not(bootstrap), allow(rustc::symbol_intern_string_literal))]
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -461,6 +461,7 @@ symbols! {
|
|||
async_drop_slice,
|
||||
async_drop_surface_drop_in_place,
|
||||
async_fn,
|
||||
async_fn_in_dyn_trait,
|
||||
async_fn_in_trait,
|
||||
async_fn_kind_helper,
|
||||
async_fn_kind_upvars,
|
||||
|
|
|
|||
|
|
@ -42,6 +42,8 @@ pub(crate) fn opts() -> TargetOptions {
|
|||
eh_frame_header: false,
|
||||
no_default_libraries: false,
|
||||
has_thread_local: true,
|
||||
crt_static_allows_dylibs: true,
|
||||
crt_static_respected: true,
|
||||
// FIXME(davidtwco): Support Split DWARF on Windows GNU - may require LLVM changes to
|
||||
// output DWO, despite using DWARF, doesn't use ELF..
|
||||
debuginfo_kind: DebuginfoKind::Pdb,
|
||||
|
|
|
|||
|
|
@ -611,6 +611,8 @@ const HEXAGON_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
|
|||
&[/*(512, "hvx-length64b"),*/ (1024, "hvx-length128b")];
|
||||
const MIPS_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "msa")];
|
||||
const CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "vdspv1")];
|
||||
const LOONGARCH_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
|
||||
&[(128, "lsx"), (256, "lasx")];
|
||||
|
||||
impl super::spec::Target {
|
||||
pub fn rust_target_features(&self) -> &'static [(&'static str, Stability, ImpliedFeatures)] {
|
||||
|
|
@ -638,7 +640,7 @@ impl super::spec::Target {
|
|||
"aarch64" | "arm64ec" => AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI,
|
||||
"arm" => ARM_FEATURES_FOR_CORRECT_VECTOR_ABI,
|
||||
"powerpc" | "powerpc64" => POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI,
|
||||
"loongarch64" => &[], // on-stack ABI, so we complain about all by-val vectors
|
||||
"loongarch64" => LOONGARCH_FEATURES_FOR_CORRECT_VECTOR_ABI,
|
||||
"riscv32" | "riscv64" => RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI,
|
||||
"wasm32" | "wasm64" => WASM_FEATURES_FOR_CORRECT_VECTOR_ABI,
|
||||
"s390x" => S390X_FEATURES_FOR_CORRECT_VECTOR_ABI,
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ use rustc_abi::BackendRepr;
|
|||
use rustc_errors::FatalError;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::{
|
||||
self, EarlyBinder, ExistentialPredicateStableCmpExt as _, GenericArgs, Ty, TyCtxt,
|
||||
|
|
@ -901,23 +902,59 @@ fn contains_illegal_impl_trait_in_trait<'tcx>(
|
|||
fn_def_id: DefId,
|
||||
ty: ty::Binder<'tcx, Ty<'tcx>>,
|
||||
) -> Option<MethodViolationCode> {
|
||||
// This would be caught below, but rendering the error as a separate
|
||||
// `async-specific` message is better.
|
||||
if tcx.asyncness(fn_def_id).is_async() {
|
||||
return Some(MethodViolationCode::AsyncFn);
|
||||
}
|
||||
let ty = tcx.liberate_late_bound_regions(fn_def_id, ty);
|
||||
|
||||
if tcx.asyncness(fn_def_id).is_async() {
|
||||
// FIXME(async_fn_in_dyn_trait): Think of a better way to unify these code paths
|
||||
// to issue an appropriate feature suggestion when users try to use AFIDT.
|
||||
// Obviously we must only do this once AFIDT is finished enough to actually be usable.
|
||||
if tcx.features().async_fn_in_dyn_trait() {
|
||||
let ty::Alias(ty::Projection, proj) = *ty.kind() else {
|
||||
bug!("expected async fn in trait to return an RPITIT");
|
||||
};
|
||||
assert!(tcx.is_impl_trait_in_trait(proj.def_id));
|
||||
|
||||
// FIXME(async_fn_in_dyn_trait): We should check that this bound is legal too,
|
||||
// and stop relying on `async fn` in the definition.
|
||||
for bound in tcx.item_bounds(proj.def_id).instantiate(tcx, proj.args) {
|
||||
if let Some(violation) = bound
|
||||
.visit_with(&mut IllegalRpititVisitor { tcx, allowed: Some(proj) })
|
||||
.break_value()
|
||||
{
|
||||
return Some(violation);
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(RPITIT): Perhaps we should use a visitor here?
|
||||
ty.skip_binder().walk().find_map(|arg| {
|
||||
if let ty::GenericArgKind::Type(ty) = arg.unpack()
|
||||
&& let ty::Alias(ty::Projection, proj) = ty.kind()
|
||||
&& tcx.is_impl_trait_in_trait(proj.def_id)
|
||||
{
|
||||
Some(MethodViolationCode::ReferencesImplTraitInTrait(tcx.def_span(proj.def_id)))
|
||||
} else {
|
||||
None
|
||||
} else {
|
||||
// Rendering the error as a separate `async-specific` message is better.
|
||||
Some(MethodViolationCode::AsyncFn)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
ty.visit_with(&mut IllegalRpititVisitor { tcx, allowed: None }).break_value()
|
||||
}
|
||||
}
|
||||
|
||||
struct IllegalRpititVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
allowed: Option<ty::AliasTy<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IllegalRpititVisitor<'tcx> {
|
||||
type Result = ControlFlow<MethodViolationCode>;
|
||||
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
|
||||
if let ty::Alias(ty::Projection, proj) = *ty.kind()
|
||||
&& Some(proj) != self.allowed
|
||||
&& self.tcx.is_impl_trait_in_trait(proj.def_id)
|
||||
{
|
||||
ControlFlow::Break(MethodViolationCode::ReferencesImplTraitInTrait(
|
||||
self.tcx.def_span(proj.def_id),
|
||||
))
|
||||
} else {
|
||||
ty.super_visit_with(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
|
|||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_infer::infer::DefineOpaqueTypes;
|
||||
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
|
||||
use rustc_infer::infer::{DefineOpaqueTypes, RegionVariableOrigin};
|
||||
use rustc_infer::traits::{ObligationCauseCode, PredicateObligations};
|
||||
use rustc_middle::traits::select::OverflowError;
|
||||
use rustc_middle::traits::{BuiltinImplSource, ImplSource, ImplSourceUserDefinedData};
|
||||
|
|
@ -18,6 +18,7 @@ use rustc_middle::ty::visit::TypeVisitableExt;
|
|||
use rustc_middle::ty::{self, Term, Ty, TyCtxt, TypingMode, Upcast};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::symbol::sym;
|
||||
use thin_vec::thin_vec;
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use super::{
|
||||
|
|
@ -61,6 +62,9 @@ enum ProjectionCandidate<'tcx> {
|
|||
/// Bounds specified on an object type
|
||||
Object(ty::PolyProjectionPredicate<'tcx>),
|
||||
|
||||
/// Built-in bound for a dyn async fn in trait
|
||||
ObjectRpitit,
|
||||
|
||||
/// From an "impl" (or a "pseudo-impl" returned by select)
|
||||
Select(Selection<'tcx>),
|
||||
}
|
||||
|
|
@ -827,6 +831,17 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>(
|
|||
env_predicates,
|
||||
false,
|
||||
);
|
||||
|
||||
// `dyn Trait` automagically project their AFITs to `dyn* Future`.
|
||||
if tcx.is_impl_trait_in_trait(obligation.predicate.def_id)
|
||||
&& let Some(out_trait_def_id) = data.principal_def_id()
|
||||
&& let rpitit_trait_def_id = tcx.parent(obligation.predicate.def_id)
|
||||
&& tcx
|
||||
.supertrait_def_ids(out_trait_def_id)
|
||||
.any(|trait_def_id| trait_def_id == rpitit_trait_def_id)
|
||||
{
|
||||
candidate_set.push_candidate(ProjectionCandidate::ObjectRpitit);
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(
|
||||
|
|
@ -1247,6 +1262,8 @@ fn confirm_candidate<'cx, 'tcx>(
|
|||
ProjectionCandidate::Select(impl_source) => {
|
||||
confirm_select_candidate(selcx, obligation, impl_source)
|
||||
}
|
||||
|
||||
ProjectionCandidate::ObjectRpitit => confirm_object_rpitit_candidate(selcx, obligation),
|
||||
};
|
||||
|
||||
// When checking for cycle during evaluation, we compare predicates with
|
||||
|
|
@ -2034,6 +2051,45 @@ fn confirm_impl_candidate<'cx, 'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
fn confirm_object_rpitit_candidate<'cx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||
obligation: &ProjectionTermObligation<'tcx>,
|
||||
) -> Progress<'tcx> {
|
||||
let tcx = selcx.tcx();
|
||||
let mut obligations = thin_vec![];
|
||||
|
||||
// Compute an intersection lifetime for all the input components of this GAT.
|
||||
let intersection =
|
||||
selcx.infcx.next_region_var(RegionVariableOrigin::MiscVariable(obligation.cause.span));
|
||||
for component in obligation.predicate.args {
|
||||
match component.unpack() {
|
||||
ty::GenericArgKind::Lifetime(lt) => {
|
||||
obligations.push(obligation.with(tcx, ty::OutlivesPredicate(lt, intersection)));
|
||||
}
|
||||
ty::GenericArgKind::Type(ty) => {
|
||||
obligations.push(obligation.with(tcx, ty::OutlivesPredicate(ty, intersection)));
|
||||
}
|
||||
ty::GenericArgKind::Const(_ct) => {
|
||||
// Consts have no outlives...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Progress {
|
||||
term: Ty::new_dynamic(
|
||||
tcx,
|
||||
tcx.item_bounds_to_existential_predicates(
|
||||
obligation.predicate.def_id,
|
||||
obligation.predicate.args,
|
||||
),
|
||||
intersection,
|
||||
ty::DynStar,
|
||||
)
|
||||
.into(),
|
||||
obligations,
|
||||
}
|
||||
}
|
||||
|
||||
// Get obligations corresponding to the predicates from the where-clause of the
|
||||
// associated type itself.
|
||||
fn assoc_ty_own_obligations<'cx, 'tcx>(
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData};
|
|||
use rustc_middle::ty::{self, GenericArgsRef, ToPolyTraitRef, Ty, TyCtxt, Upcast};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_type_ir::elaborate;
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use super::SelectionCandidate::{self, *};
|
||||
|
|
@ -624,6 +625,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
for assoc_type in assoc_types {
|
||||
let defs: &ty::Generics = tcx.generics_of(assoc_type);
|
||||
|
||||
// When `async_fn_in_dyn_trait` is enabled, we don't need to check the
|
||||
// RPITIT for compatibility, since it's not provided by the user.
|
||||
if tcx.features().async_fn_in_dyn_trait() && tcx.is_impl_trait_in_trait(assoc_type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if !defs.own_params.is_empty() {
|
||||
tcx.dcx().span_delayed_bug(
|
||||
obligation.cause.span,
|
||||
|
|
@ -1175,6 +1182,38 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
ty::ClauseKind::TypeOutlives(outlives).upcast(tcx),
|
||||
));
|
||||
|
||||
// Require that all AFIT will return something that can be coerced into `dyn*`
|
||||
// -- a shim will be responsible for doing the actual coercion to `dyn*`.
|
||||
if let Some(principal) = data.principal() {
|
||||
for supertrait in
|
||||
elaborate::supertraits(tcx, principal.with_self_ty(tcx, source))
|
||||
{
|
||||
if tcx.is_trait_alias(supertrait.def_id()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for &assoc_item in tcx.associated_item_def_ids(supertrait.def_id()) {
|
||||
if !tcx.is_impl_trait_in_trait(assoc_item) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// RPITITs with `Self: Sized` don't need to be checked.
|
||||
if tcx.generics_require_sized_self(assoc_item) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let pointer_like_goal = pointer_like_goal_for_rpitit(
|
||||
tcx,
|
||||
supertrait,
|
||||
assoc_item,
|
||||
&obligation.cause,
|
||||
);
|
||||
|
||||
nested.push(predicate_to_obligation(pointer_like_goal.upcast(tcx)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImplSource::Builtin(BuiltinImplSource::Misc, nested)
|
||||
}
|
||||
|
||||
|
|
@ -1280,3 +1319,43 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute a goal that some RPITIT (right now, only RPITITs corresponding to Futures)
|
||||
/// implements the `PointerLike` trait, which is a requirement for the RPITIT to be
|
||||
/// coercible to `dyn* Future`, which is itself a requirement for the RPITIT's parent
|
||||
/// trait to be coercible to `dyn Trait`.
|
||||
///
|
||||
/// We do this given a supertrait's substitutions, and then augment the substitutions
|
||||
/// with bound variables to compute the goal universally. Given that `PointerLike` has
|
||||
/// no region requirements (at least for the built-in pointer types), this shouldn't
|
||||
/// *really* matter, but it is the best choice for soundness.
|
||||
fn pointer_like_goal_for_rpitit<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
supertrait: ty::PolyTraitRef<'tcx>,
|
||||
rpitit_item: DefId,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
) -> ty::PolyTraitRef<'tcx> {
|
||||
let mut bound_vars = supertrait.bound_vars().to_vec();
|
||||
|
||||
let args = supertrait.skip_binder().args.extend_to(tcx, rpitit_item, |arg, _| match arg.kind {
|
||||
ty::GenericParamDefKind::Lifetime => {
|
||||
let kind = ty::BoundRegionKind::Named(arg.def_id, tcx.item_name(arg.def_id));
|
||||
bound_vars.push(ty::BoundVariableKind::Region(kind));
|
||||
ty::Region::new_bound(tcx, ty::INNERMOST, ty::BoundRegion {
|
||||
var: ty::BoundVar::from_usize(bound_vars.len() - 1),
|
||||
kind,
|
||||
})
|
||||
.into()
|
||||
}
|
||||
ty::GenericParamDefKind::Type { .. } | ty::GenericParamDefKind::Const { .. } => {
|
||||
unreachable!()
|
||||
}
|
||||
});
|
||||
|
||||
ty::Binder::bind_with_vars(
|
||||
ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::PointerLike, Some(cause.span)), [
|
||||
Ty::new_projection_from_args(tcx, rpitit_item, args),
|
||||
]),
|
||||
tcx.mk_bound_variable_kinds(&bound_vars),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,12 +48,38 @@ fn fn_sig_for_fn_abi<'tcx>(
|
|||
let mut sig = tcx
|
||||
.instantiate_bound_regions_with_erased(tcx.fn_sig(def_id).instantiate(tcx, args));
|
||||
|
||||
// Modify `fn(self, ...)` to `fn(self: *mut Self, ...)`.
|
||||
if let ty::InstanceKind::VTableShim(..) = instance.def {
|
||||
let mut inputs_and_output = sig.inputs_and_output.to_vec();
|
||||
inputs_and_output[0] = Ty::new_mut_ptr(tcx, inputs_and_output[0]);
|
||||
sig.inputs_and_output = tcx.mk_type_list(&inputs_and_output);
|
||||
}
|
||||
|
||||
// Modify `fn() -> impl Future` to `fn() -> dyn* Future`.
|
||||
if let ty::InstanceKind::ReifyShim(def_id, _) = instance.def
|
||||
&& let Some((rpitit_def_id, fn_args)) =
|
||||
tcx.return_position_impl_trait_in_trait_shim_data(def_id)
|
||||
{
|
||||
let fn_args = fn_args.instantiate(tcx, args);
|
||||
let rpitit_args =
|
||||
fn_args.extend_to(tcx, rpitit_def_id, |param, _| match param.kind {
|
||||
ty::GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
|
||||
ty::GenericParamDefKind::Type { .. }
|
||||
| ty::GenericParamDefKind::Const { .. } => {
|
||||
unreachable!("rpitit should have no addition ty/ct")
|
||||
}
|
||||
});
|
||||
let dyn_star_ty = Ty::new_dynamic(
|
||||
tcx,
|
||||
tcx.item_bounds_to_existential_predicates(rpitit_def_id, rpitit_args),
|
||||
tcx.lifetimes.re_erased,
|
||||
ty::DynStar,
|
||||
);
|
||||
let mut inputs_and_output = sig.inputs_and_output.to_vec();
|
||||
*inputs_and_output.last_mut().unwrap() = dyn_star_ty;
|
||||
sig.inputs_and_output = tcx.mk_type_list(&inputs_and_output);
|
||||
}
|
||||
|
||||
sig
|
||||
}
|
||||
ty::Closure(def_id, args) => {
|
||||
|
|
|
|||
|
|
@ -10,9 +10,6 @@ use core::hint;
|
|||
#[cfg(not(test))]
|
||||
use core::ptr::{self, NonNull};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
extern "Rust" {
|
||||
// These are the magic symbols to call the global allocator. rustc generates
|
||||
// them to call `__rg_alloc` etc. if there is a `#[global_allocator]` attribute
|
||||
|
|
|
|||
|
|
@ -1985,7 +1985,8 @@ impl<Args: Tuple, F: Fn<Args> + ?Sized, A: Allocator> Fn<Args> for Box<F, A> {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "async_fn_traits", issue = "none")]
|
||||
#[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))]
|
||||
#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))]
|
||||
impl<Args: Tuple, F: AsyncFnOnce<Args> + ?Sized, A: Allocator> AsyncFnOnce<Args> for Box<F, A> {
|
||||
type Output = F::Output;
|
||||
type CallOnceFuture = F::CallOnceFuture;
|
||||
|
|
@ -1995,7 +1996,8 @@ impl<Args: Tuple, F: AsyncFnOnce<Args> + ?Sized, A: Allocator> AsyncFnOnce<Args>
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "async_fn_traits", issue = "none")]
|
||||
#[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))]
|
||||
#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))]
|
||||
impl<Args: Tuple, F: AsyncFnMut<Args> + ?Sized, A: Allocator> AsyncFnMut<Args> for Box<F, A> {
|
||||
type CallRefFuture<'a>
|
||||
= F::CallRefFuture<'a>
|
||||
|
|
@ -2007,7 +2009,8 @@ impl<Args: Tuple, F: AsyncFnMut<Args> + ?Sized, A: Allocator> AsyncFnMut<Args> f
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "async_fn_traits", issue = "none")]
|
||||
#[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))]
|
||||
#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))]
|
||||
impl<Args: Tuple, F: AsyncFn<Args> + ?Sized, A: Allocator> AsyncFn<Args> for Box<F, A> {
|
||||
extern "rust-call" fn async_call(&self, args: Args) -> Self::CallRefFuture<'_> {
|
||||
F::async_call(self, args)
|
||||
|
|
|
|||
|
|
@ -155,9 +155,6 @@ use crate::collections::TryReserveError;
|
|||
use crate::slice;
|
||||
use crate::vec::{self, AsVecIntoIter, Vec};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
/// A priority queue implemented with a binary heap.
|
||||
///
|
||||
/// This will be a max-heap.
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
//! [`CString`] and its related types.
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use core::borrow::Borrow;
|
||||
use core::ffi::{CStr, c_char};
|
||||
use core::num::NonZero;
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@
|
|||
//
|
||||
// Library features:
|
||||
// tidy-alphabetical-start
|
||||
#![cfg_attr(bootstrap, feature(async_closure))]
|
||||
#![cfg_attr(test, feature(str_as_str))]
|
||||
#![feature(alloc_layout_extra)]
|
||||
#![feature(allocator_api)]
|
||||
|
|
@ -99,7 +100,6 @@
|
|||
#![feature(array_windows)]
|
||||
#![feature(ascii_char)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(async_closure)]
|
||||
#![feature(async_fn_traits)]
|
||||
#![feature(async_iterator)]
|
||||
#![feature(box_uninit_write)]
|
||||
|
|
@ -239,8 +239,6 @@ pub mod string;
|
|||
pub mod sync;
|
||||
#[cfg(all(not(no_global_oom_handling), not(no_rc), not(no_sync)))]
|
||||
pub mod task;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
pub mod vec;
|
||||
|
||||
#[doc(hidden)]
|
||||
|
|
|
|||
|
|
@ -39,9 +39,6 @@ use crate::string::String;
|
|||
#[cfg(not(no_global_oom_handling))]
|
||||
use crate::vec::Vec;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
/// A soft limit on the amount of references that may be made to an `Arc`.
|
||||
///
|
||||
/// Going above this limit will abort your program (although not
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
use super::*;
|
||||
use alloc::alloc::*;
|
||||
use alloc::boxed::Box;
|
||||
|
||||
extern crate test;
|
||||
use test::Bencher;
|
||||
|
||||
use crate::boxed::Box;
|
||||
|
||||
#[test]
|
||||
fn allocate_zeroed() {
|
||||
unsafe {
|
||||
|
|
@ -1,11 +1,12 @@
|
|||
use alloc::ffi::CString;
|
||||
use alloc::rc::Rc;
|
||||
use alloc::sync::Arc;
|
||||
use core::assert_matches::assert_matches;
|
||||
use core::ffi::FromBytesUntilNulError;
|
||||
use core::ffi::{CStr, FromBytesUntilNulError, c_char};
|
||||
#[allow(deprecated)]
|
||||
use core::hash::SipHasher13 as DefaultHasher;
|
||||
use core::hash::{Hash, Hasher};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn c_to_rust() {
|
||||
let data = b"123\0";
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
use alloc::boxed::Box;
|
||||
use alloc::collections::binary_heap::*;
|
||||
use std::iter::TrustedLen;
|
||||
use std::mem;
|
||||
use std::panic::{AssertUnwindSafe, catch_unwind};
|
||||
|
||||
use super::*;
|
||||
use crate::boxed::Box;
|
||||
use crate::testing::crash_test::{CrashTestDummy, Panic};
|
||||
|
||||
#[test]
|
||||
|
|
@ -531,7 +533,7 @@ fn panic_safe() {
|
|||
self.0.partial_cmp(&other.0)
|
||||
}
|
||||
}
|
||||
let mut rng = crate::test_helpers::test_rng();
|
||||
let mut rng = crate::test_rng();
|
||||
const DATASZ: usize = 32;
|
||||
// Miri is too slow
|
||||
let ntest = if cfg!(miri) { 1 } else { 10 };
|
||||
1
library/alloc/tests/collections/mod.rs
Normal file
1
library/alloc/tests/collections/mod.rs
Normal file
|
|
@ -0,0 +1 @@
|
|||
mod binary_heap;
|
||||
|
|
@ -5,8 +5,10 @@
|
|||
#![feature(btree_extract_if)]
|
||||
#![feature(cow_is_borrowed)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(downcast_unchecked)]
|
||||
#![feature(extract_if)]
|
||||
#![feature(exact_size_is_empty)]
|
||||
#![feature(hashmap_internals)]
|
||||
#![feature(linked_list_cursors)]
|
||||
#![feature(map_try_insert)]
|
||||
#![feature(pattern)]
|
||||
|
|
@ -29,9 +31,11 @@
|
|||
#![feature(const_str_from_utf8)]
|
||||
#![feature(panic_update_hook)]
|
||||
#![feature(pointer_is_aligned_to)]
|
||||
#![feature(test)]
|
||||
#![feature(thin_box)]
|
||||
#![feature(drain_keep_rest)]
|
||||
#![feature(local_waker)]
|
||||
#![feature(str_as_str)]
|
||||
#![feature(strict_provenance_lints)]
|
||||
#![feature(vec_pop_if)]
|
||||
#![feature(unique_rc_arc)]
|
||||
|
|
@ -40,25 +44,33 @@
|
|||
#![deny(fuzzy_provenance_casts)]
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
|
||||
extern crate test;
|
||||
|
||||
use std::hash::{DefaultHasher, Hash, Hasher};
|
||||
|
||||
mod alloc;
|
||||
mod arc;
|
||||
mod autotraits;
|
||||
mod borrow;
|
||||
mod boxed;
|
||||
mod btree_set_hash;
|
||||
mod c_str;
|
||||
mod c_str2;
|
||||
mod collections;
|
||||
mod const_fns;
|
||||
mod cow_str;
|
||||
mod fmt;
|
||||
mod heap;
|
||||
mod linked_list;
|
||||
mod misc_tests;
|
||||
mod rc;
|
||||
mod slice;
|
||||
mod sort;
|
||||
mod str;
|
||||
mod string;
|
||||
mod sync;
|
||||
mod task;
|
||||
mod testing;
|
||||
mod thin_box;
|
||||
mod vec;
|
||||
mod vec_deque;
|
||||
|
|
@ -69,6 +81,18 @@ fn hash<T: Hash>(t: &T) -> u64 {
|
|||
s.finish()
|
||||
}
|
||||
|
||||
/// Copied from `std::test_helpers::test_rng`, since these tests rely on the
|
||||
/// seed not being the same for every RNG invocation too.
|
||||
fn test_rng() -> rand_xorshift::XorShiftRng {
|
||||
use std::hash::{BuildHasher, Hash, Hasher};
|
||||
let mut hasher = std::hash::RandomState::new().build_hasher();
|
||||
std::panic::Location::caller().hash(&mut hasher);
|
||||
let hc64 = hasher.finish();
|
||||
let seed_vec = hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<Vec<u8>>();
|
||||
let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap();
|
||||
rand::SeedableRng::from_seed(seed)
|
||||
}
|
||||
|
||||
// FIXME: Instantiated functions with i128 in the signature is not supported in Emscripten.
|
||||
// See https://github.com/kripken/emscripten-fastcomp/issues/169
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
use alloc::sync::*;
|
||||
use std::alloc::{AllocError, Allocator, Layout};
|
||||
use std::any::Any;
|
||||
use std::clone::Clone;
|
||||
use std::mem::MaybeUninit;
|
||||
use std::option::Option::None;
|
||||
use std::ptr::NonNull;
|
||||
use std::sync::Mutex;
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
use std::sync::atomic::Ordering::SeqCst;
|
||||
use std::sync::atomic::Ordering::*;
|
||||
use std::sync::atomic::{self, AtomicUsize};
|
||||
use std::sync::mpsc::channel;
|
||||
use std::thread;
|
||||
|
||||
use super::*;
|
||||
|
||||
struct Canary(*mut AtomicUsize);
|
||||
|
||||
impl Drop for Canary {
|
||||
80
library/alloc/tests/testing/crash_test.rs
Normal file
80
library/alloc/tests/testing/crash_test.rs
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
use std::cmp::Ordering;
|
||||
use std::fmt::Debug;
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
use std::sync::atomic::Ordering::SeqCst;
|
||||
|
||||
/// A blueprint for crash test dummy instances that monitor drops.
|
||||
/// Some instances may be configured to panic at some point.
|
||||
///
|
||||
/// Crash test dummies are identified and ordered by an id, so they can be used
|
||||
/// as keys in a BTreeMap.
|
||||
#[derive(Debug)]
|
||||
pub struct CrashTestDummy {
|
||||
pub id: usize,
|
||||
dropped: AtomicUsize,
|
||||
}
|
||||
|
||||
impl CrashTestDummy {
|
||||
/// Creates a crash test dummy design. The `id` determines order and equality of instances.
|
||||
pub fn new(id: usize) -> CrashTestDummy {
|
||||
CrashTestDummy { id, dropped: AtomicUsize::new(0) }
|
||||
}
|
||||
|
||||
/// Creates an instance of a crash test dummy that records what events it experiences
|
||||
/// and optionally panics.
|
||||
pub fn spawn(&self, panic: Panic) -> Instance<'_> {
|
||||
Instance { origin: self, panic }
|
||||
}
|
||||
|
||||
/// Returns how many times instances of the dummy have been dropped.
|
||||
pub fn dropped(&self) -> usize {
|
||||
self.dropped.load(SeqCst)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Instance<'a> {
|
||||
origin: &'a CrashTestDummy,
|
||||
panic: Panic,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Panic {
|
||||
Never,
|
||||
InDrop,
|
||||
}
|
||||
|
||||
impl Instance<'_> {
|
||||
pub fn id(&self) -> usize {
|
||||
self.origin.id
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Instance<'_> {
|
||||
fn drop(&mut self) {
|
||||
self.origin.dropped.fetch_add(1, SeqCst);
|
||||
if self.panic == Panic::InDrop {
|
||||
panic!("panic in `drop`");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Instance<'_> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
self.id().partial_cmp(&other.id())
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Instance<'_> {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.id().cmp(&other.id())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Instance<'_> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.id().eq(&other.id())
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Instance<'_> {}
|
||||
1
library/alloc/tests/testing/mod.rs
Normal file
1
library/alloc/tests/testing/mod.rs
Normal file
|
|
@ -0,0 +1 @@
|
|||
pub mod crash_test;
|
||||
|
|
@ -4,7 +4,8 @@ use crate::marker::Tuple;
|
|||
/// An async-aware version of the [`Fn`](crate::ops::Fn) trait.
|
||||
///
|
||||
/// All `async fn` and functions returning futures implement this trait.
|
||||
#[unstable(feature = "async_closure", issue = "62290")]
|
||||
#[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))]
|
||||
#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))]
|
||||
#[rustc_paren_sugar]
|
||||
#[fundamental]
|
||||
#[must_use = "async closures are lazy and do nothing unless called"]
|
||||
|
|
@ -18,7 +19,8 @@ pub trait AsyncFn<Args: Tuple>: AsyncFnMut<Args> {
|
|||
/// An async-aware version of the [`FnMut`](crate::ops::FnMut) trait.
|
||||
///
|
||||
/// All `async fn` and functions returning futures implement this trait.
|
||||
#[unstable(feature = "async_closure", issue = "62290")]
|
||||
#[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))]
|
||||
#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))]
|
||||
#[rustc_paren_sugar]
|
||||
#[fundamental]
|
||||
#[must_use = "async closures are lazy and do nothing unless called"]
|
||||
|
|
@ -39,7 +41,8 @@ pub trait AsyncFnMut<Args: Tuple>: AsyncFnOnce<Args> {
|
|||
/// An async-aware version of the [`FnOnce`](crate::ops::FnOnce) trait.
|
||||
///
|
||||
/// All `async fn` and functions returning futures implement this trait.
|
||||
#[unstable(feature = "async_closure", issue = "62290")]
|
||||
#[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))]
|
||||
#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))]
|
||||
#[rustc_paren_sugar]
|
||||
#[fundamental]
|
||||
#[must_use = "async closures are lazy and do nothing unless called"]
|
||||
|
|
@ -64,7 +67,8 @@ mod impls {
|
|||
use super::{AsyncFn, AsyncFnMut, AsyncFnOnce};
|
||||
use crate::marker::Tuple;
|
||||
|
||||
#[unstable(feature = "async_fn_traits", issue = "none")]
|
||||
#[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))]
|
||||
#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))]
|
||||
impl<A: Tuple, F: ?Sized> AsyncFn<A> for &F
|
||||
where
|
||||
F: AsyncFn<A>,
|
||||
|
|
@ -74,7 +78,8 @@ mod impls {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "async_fn_traits", issue = "none")]
|
||||
#[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))]
|
||||
#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))]
|
||||
impl<A: Tuple, F: ?Sized> AsyncFnMut<A> for &F
|
||||
where
|
||||
F: AsyncFn<A>,
|
||||
|
|
@ -89,7 +94,8 @@ mod impls {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "async_fn_traits", issue = "none")]
|
||||
#[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))]
|
||||
#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))]
|
||||
impl<'a, A: Tuple, F: ?Sized> AsyncFnOnce<A> for &'a F
|
||||
where
|
||||
F: AsyncFn<A>,
|
||||
|
|
@ -102,7 +108,8 @@ mod impls {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "async_fn_traits", issue = "none")]
|
||||
#[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))]
|
||||
#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))]
|
||||
impl<A: Tuple, F: ?Sized> AsyncFnMut<A> for &mut F
|
||||
where
|
||||
F: AsyncFnMut<A>,
|
||||
|
|
@ -117,7 +124,8 @@ mod impls {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "async_fn_traits", issue = "none")]
|
||||
#[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))]
|
||||
#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))]
|
||||
impl<'a, A: Tuple, F: ?Sized> AsyncFnOnce<A> for &'a mut F
|
||||
where
|
||||
F: AsyncFnMut<A>,
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ pub mod rust_2021 {
|
|||
/// The 2024 version of the core prelude.
|
||||
///
|
||||
/// See the [module-level documentation](self) for more.
|
||||
#[unstable(feature = "prelude_2024", issue = "121042")]
|
||||
#[stable(feature = "prelude_2024", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub mod rust_2024 {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use super::common::*;
|
||||
|
|
@ -84,7 +84,7 @@ pub mod rust_2024 {
|
|||
#[doc(no_inline)]
|
||||
pub use crate::convert::{TryFrom, TryInto};
|
||||
|
||||
#[unstable(feature = "prelude_2024", issue = "121042")]
|
||||
#[stable(feature = "prelude_2024", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[doc(no_inline)]
|
||||
pub use crate::future::{Future, IntoFuture};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1587,15 +1587,6 @@ impl<T: ?Sized> *mut T {
|
|||
/// beyond the allocation that the pointer points into. It is up to the caller to ensure that
|
||||
/// the returned offset is correct in all terms other than alignment.
|
||||
///
|
||||
/// When this is called during compile-time evaluation (which is unstable), the implementation
|
||||
/// may return `usize::MAX` in cases where that can never happen at runtime. This is because the
|
||||
/// actual alignment of pointers is not known yet during compile-time, so an offset with
|
||||
/// guaranteed alignment can sometimes not be computed. For example, a buffer declared as `[u8;
|
||||
/// N]` might be allocated at an odd or an even address, but at compile-time this is not yet
|
||||
/// known, so the execution has to be correct for either choice. It is therefore impossible to
|
||||
/// find an offset that is guaranteed to be 2-aligned. (This behavior is subject to change, as usual
|
||||
/// for unstable APIs.)
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// The function panics if `align` is not a power-of-two.
|
||||
|
|
|
|||
|
|
@ -348,7 +348,6 @@
|
|||
#![feature(pin_coerce_unsized_trait)]
|
||||
#![feature(pointer_is_aligned_to)]
|
||||
#![feature(portable_simd)]
|
||||
#![feature(prelude_2024)]
|
||||
#![feature(ptr_as_uninit)]
|
||||
#![feature(ptr_mask)]
|
||||
#![feature(random)]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
//! Hurd-specific definitions
|
||||
|
||||
#![stable(feature = "raw_ext", since = "1.1.0")]
|
||||
#![forbid(unsafe_op_in_unsafe_fn)]
|
||||
|
||||
pub mod fs;
|
||||
pub mod raw;
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@ pub use crate::marker::{Send, Sized, Sync, Unpin};
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[doc(no_inline)]
|
||||
pub use crate::ops::{Drop, Fn, FnMut, FnOnce};
|
||||
#[unstable(feature = "async_closure", issue = "62290")]
|
||||
#[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))]
|
||||
#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))]
|
||||
#[doc(no_inline)]
|
||||
pub use crate::ops::{AsyncFn, AsyncFnMut, AsyncFnOnce};
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
//!
|
||||
//! # Prelude contents
|
||||
//!
|
||||
//! The items included in the prelude depend on the edition of the crate.
|
||||
//! The first version of the prelude is used in Rust 2015 and Rust 2018,
|
||||
//! and lives in [`std::prelude::v1`].
|
||||
//! [`std::prelude::rust_2015`] and [`std::prelude::rust_2018`] re-export this prelude.
|
||||
|
|
@ -32,8 +33,9 @@
|
|||
//!
|
||||
//! * <code>[std::marker]::{[Copy], [Send], [Sized], [Sync], [Unpin]}</code>,
|
||||
//! marker traits that indicate fundamental properties of types.
|
||||
//! * <code>[std::ops]::{[Drop], [Fn], [FnMut], [FnOnce]}</code>, various
|
||||
//! operations for both destructors and overloading `()`.
|
||||
//! * <code>[std::ops]::{[Fn], [FnMut], [FnOnce]}</code>, and their analogous
|
||||
//! async traits, <code>[std::ops]::{[AsyncFn], [AsyncFnMut], [AsyncFnOnce]}</code>.
|
||||
//! * <code>[std::ops]::[Drop]</code>, for implementing destructors.
|
||||
//! * <code>[std::mem]::[drop]</code>, a convenience function for explicitly
|
||||
//! dropping a value.
|
||||
//! * <code>[std::mem]::{[size_of], [size_of_val]}</code>, to get the size of
|
||||
|
|
@ -67,15 +69,21 @@
|
|||
//! The prelude used in Rust 2021, [`std::prelude::rust_2021`], includes all of the above,
|
||||
//! and in addition re-exports:
|
||||
//!
|
||||
//! * <code>[std::convert]::{[TryFrom], [TryInto]}</code>,
|
||||
//! * <code>[std::convert]::{[TryFrom], [TryInto]}</code>.
|
||||
//! * <code>[std::iter]::[FromIterator]</code>.
|
||||
//!
|
||||
//! The prelude used in Rust 2024, [`std::prelude::rust_2024`], includes all of the above,
|
||||
//! and in addition re-exports:
|
||||
//!
|
||||
//! * <code>[std::future]::{[Future], [IntoFuture]}</code>.
|
||||
//!
|
||||
//! [std::borrow]: crate::borrow
|
||||
//! [std::boxed]: crate::boxed
|
||||
//! [std::clone]: crate::clone
|
||||
//! [std::cmp]: crate::cmp
|
||||
//! [std::convert]: crate::convert
|
||||
//! [std::default]: crate::default
|
||||
//! [std::future]: crate::future
|
||||
//! [std::iter]: crate::iter
|
||||
//! [std::marker]: crate::marker
|
||||
//! [std::mem]: crate::mem
|
||||
|
|
@ -85,6 +93,7 @@
|
|||
//! [`std::prelude::rust_2015`]: rust_2015
|
||||
//! [`std::prelude::rust_2018`]: rust_2018
|
||||
//! [`std::prelude::rust_2021`]: rust_2021
|
||||
//! [`std::prelude::rust_2024`]: rust_2024
|
||||
//! [std::result]: crate::result
|
||||
//! [std::slice]: crate::slice
|
||||
//! [std::string]: crate::string
|
||||
|
|
@ -94,6 +103,8 @@
|
|||
//! [book-dtor]: ../../book/ch15-03-drop.html
|
||||
//! [book-enums]: ../../book/ch06-01-defining-an-enum.html
|
||||
//! [book-iter]: ../../book/ch13-02-iterators.html
|
||||
//! [Future]: crate::future::Future
|
||||
//! [IntoFuture]: crate::future::IntoFuture
|
||||
|
||||
// No formatting: this file is nothing but re-exports, and their order is worth preserving.
|
||||
#![cfg_attr(rustfmt, rustfmt::skip)]
|
||||
|
|
@ -158,12 +169,12 @@ pub mod rust_2021 {
|
|||
/// The 2024 version of the prelude of The Rust Standard Library.
|
||||
///
|
||||
/// See the [module-level documentation](self) for more.
|
||||
#[unstable(feature = "prelude_2024", issue = "121042")]
|
||||
#[stable(feature = "prelude_2024", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub mod rust_2024 {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use super::common::*;
|
||||
|
||||
#[unstable(feature = "prelude_2024", issue = "121042")]
|
||||
#[stable(feature = "prelude_2024", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[doc(no_inline)]
|
||||
pub use core::prelude::rust_2024::*;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -178,3 +178,8 @@ cfg_if::cfg_if! {
|
|||
#[cfg(target_os = "hurd")]
|
||||
#[link(name = "gcc_s")]
|
||||
extern "C" {}
|
||||
|
||||
#[cfg(all(target_os = "windows", target_env = "gnu", target_abi = "llvm"))]
|
||||
#[link(name = "unwind", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))]
|
||||
#[link(name = "unwind", cfg(not(target_feature = "crt-static")))]
|
||||
extern "C" {}
|
||||
|
|
|
|||
|
|
@ -102,12 +102,9 @@ pub type _Unwind_Exception_Cleanup_Fn =
|
|||
// rustc_codegen_ssa::src::back::symbol_export, rustc_middle::middle::exported_symbols
|
||||
// and RFC 2841
|
||||
#[cfg_attr(
|
||||
any(
|
||||
all(
|
||||
feature = "llvm-libunwind",
|
||||
any(target_os = "fuchsia", target_os = "linux", target_os = "xous")
|
||||
),
|
||||
all(target_os = "windows", target_env = "gnu", target_abi = "llvm")
|
||||
all(
|
||||
feature = "llvm-libunwind",
|
||||
any(target_os = "fuchsia", target_os = "linux", target_os = "xous")
|
||||
),
|
||||
link(name = "unwind", kind = "static", modifiers = "-bundle")
|
||||
)]
|
||||
|
|
|
|||
|
|
@ -48,9 +48,9 @@ fn main() {
|
|||
err => {
|
||||
drop(err);
|
||||
if let Ok(pid) = pid {
|
||||
eprintln!("WARNING: build directory locked by process {pid}, waiting for lock");
|
||||
println!("WARNING: build directory locked by process {pid}, waiting for lock");
|
||||
} else {
|
||||
eprintln!("WARNING: build directory locked, waiting for lock");
|
||||
println!("WARNING: build directory locked, waiting for lock");
|
||||
}
|
||||
let mut lock = t!(build_lock.write());
|
||||
t!(lock.write(process::id().to_string().as_ref()));
|
||||
|
|
@ -70,13 +70,13 @@ fn main() {
|
|||
// changelog warning, not the `x.py setup` message.
|
||||
let suggest_setup = config.config.is_none() && !matches!(config.cmd, Subcommand::Setup { .. });
|
||||
if suggest_setup {
|
||||
eprintln!("WARNING: you have not made a `config.toml`");
|
||||
eprintln!(
|
||||
println!("WARNING: you have not made a `config.toml`");
|
||||
println!(
|
||||
"HELP: consider running `./x.py setup` or copying `config.example.toml` by running \
|
||||
`cp config.example.toml config.toml`"
|
||||
);
|
||||
} else if let Some(suggestion) = &changelog_suggestion {
|
||||
eprintln!("{suggestion}");
|
||||
println!("{suggestion}");
|
||||
}
|
||||
|
||||
let pre_commit = config.src.join(".git").join("hooks").join("pre-commit");
|
||||
|
|
@ -86,13 +86,13 @@ fn main() {
|
|||
Build::new(config).build();
|
||||
|
||||
if suggest_setup {
|
||||
eprintln!("WARNING: you have not made a `config.toml`");
|
||||
eprintln!(
|
||||
println!("WARNING: you have not made a `config.toml`");
|
||||
println!(
|
||||
"HELP: consider running `./x.py setup` or copying `config.example.toml` by running \
|
||||
`cp config.example.toml config.toml`"
|
||||
);
|
||||
} else if let Some(suggestion) = &changelog_suggestion {
|
||||
eprintln!("{suggestion}");
|
||||
println!("{suggestion}");
|
||||
}
|
||||
|
||||
// Give a warning if the pre-commit script is in pre-commit and not pre-push.
|
||||
|
|
@ -102,14 +102,14 @@ fn main() {
|
|||
if fs::read_to_string(pre_commit).is_ok_and(|contents| {
|
||||
contents.contains("https://github.com/rust-lang/rust/issues/77620#issuecomment-705144570")
|
||||
}) {
|
||||
eprintln!(
|
||||
println!(
|
||||
"WARNING: You have the pre-push script installed to .git/hooks/pre-commit. \
|
||||
Consider moving it to .git/hooks/pre-push instead, which runs less often."
|
||||
);
|
||||
}
|
||||
|
||||
if suggest_setup || changelog_suggestion.is_some() {
|
||||
eprintln!("NOTE: this message was printed twice to make it more likely to be seen");
|
||||
println!("NOTE: this message was printed twice to make it more likely to be seen");
|
||||
}
|
||||
|
||||
if dump_bootstrap_shims {
|
||||
|
|
|
|||
|
|
@ -306,7 +306,7 @@ fn main() {
|
|||
// should run on success, after this block.
|
||||
}
|
||||
if verbose > 0 {
|
||||
eprintln!("\nDid not run successfully: {status}\n{cmd:?}\n-------------");
|
||||
println!("\nDid not run successfully: {status}\n{cmd:?}\n-------------");
|
||||
}
|
||||
|
||||
if let Some(mut on_fail) = on_fail {
|
||||
|
|
|
|||
|
|
@ -287,7 +287,7 @@ impl Step for CodegenBackend {
|
|||
fn run(self, builder: &Builder<'_>) {
|
||||
// FIXME: remove once https://github.com/rust-lang/rust/issues/112393 is resolved
|
||||
if builder.build.config.vendor && self.backend == "gcc" {
|
||||
eprintln!("Skipping checking of `rustc_codegen_gcc` with vendoring enabled.");
|
||||
println!("Skipping checking of `rustc_codegen_gcc` with vendoring enabled.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1611,7 +1611,7 @@ impl Step for Sysroot {
|
|||
let sysroot = sysroot_dir(compiler.stage);
|
||||
|
||||
builder
|
||||
.verbose(|| eprintln!("Removing sysroot {} to avoid caching bugs", sysroot.display()));
|
||||
.verbose(|| println!("Removing sysroot {} to avoid caching bugs", sysroot.display()));
|
||||
let _ = fs::remove_dir_all(&sysroot);
|
||||
t!(fs::create_dir_all(&sysroot));
|
||||
|
||||
|
|
@ -1681,7 +1681,7 @@ impl Step for Sysroot {
|
|||
return true;
|
||||
}
|
||||
if !filtered_files.iter().all(|f| f != path.file_name().unwrap()) {
|
||||
builder.verbose_than(1, || eprintln!("ignoring {}", path.display()));
|
||||
builder.verbose_than(1, || println!("ignoring {}", path.display()));
|
||||
false
|
||||
} else {
|
||||
true
|
||||
|
|
@ -2240,7 +2240,7 @@ pub fn stream_cargo(
|
|||
cargo.arg(arg);
|
||||
}
|
||||
|
||||
builder.verbose(|| eprintln!("running: {cargo:?}"));
|
||||
builder.verbose(|| println!("running: {cargo:?}"));
|
||||
|
||||
if builder.config.dry_run() {
|
||||
return true;
|
||||
|
|
@ -2266,7 +2266,7 @@ pub fn stream_cargo(
|
|||
cb(msg)
|
||||
}
|
||||
// If this was informational, just print it out and continue
|
||||
Err(_) => eprintln!("{line}"),
|
||||
Err(_) => println!("{line}"),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2080,7 +2080,7 @@ fn maybe_install_llvm(
|
|||
{
|
||||
let mut cmd = command(llvm_config);
|
||||
cmd.arg("--libfiles");
|
||||
builder.verbose(|| eprintln!("running {cmd:?}"));
|
||||
builder.verbose(|| println!("running {cmd:?}"));
|
||||
let files = cmd.run_capture_stdout(builder).stdout();
|
||||
let build_llvm_out = &builder.llvm_out(builder.config.build);
|
||||
let target_llvm_out = &builder.llvm_out(target);
|
||||
|
|
|
|||
|
|
@ -107,10 +107,10 @@ fn print_paths(verb: &str, adjective: Option<&str>, paths: &[String]) {
|
|||
if let Some(adjective) = adjective { format!("{adjective} ") } else { String::new() };
|
||||
if len <= 10 {
|
||||
for path in paths {
|
||||
eprintln!("fmt: {verb} {adjective}file {path}");
|
||||
println!("fmt: {verb} {adjective}file {path}");
|
||||
}
|
||||
} else {
|
||||
eprintln!("fmt: {verb} {len} {adjective}files");
|
||||
println!("fmt: {verb} {len} {adjective}files");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -199,7 +199,7 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) {
|
|||
match get_modified_rs_files(build) {
|
||||
Ok(Some(files)) => {
|
||||
if files.is_empty() {
|
||||
eprintln!("fmt info: No modified files detected for formatting.");
|
||||
println!("fmt info: No modified files detected for formatting.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ impl Step for Profile {
|
|||
t!(fs::remove_file(path));
|
||||
}
|
||||
_ => {
|
||||
eprintln!("Exiting.");
|
||||
println!("Exiting.");
|
||||
crate::exit!(1);
|
||||
}
|
||||
}
|
||||
|
|
@ -184,15 +184,15 @@ pub fn setup(config: &Config, profile: Profile) {
|
|||
Profile::Dist => &["dist", "build"],
|
||||
};
|
||||
|
||||
eprintln!();
|
||||
println!();
|
||||
|
||||
eprintln!("To get started, try one of the following commands:");
|
||||
println!("To get started, try one of the following commands:");
|
||||
for cmd in suggestions {
|
||||
eprintln!("- `x.py {cmd}`");
|
||||
println!("- `x.py {cmd}`");
|
||||
}
|
||||
|
||||
if profile != Profile::Dist {
|
||||
eprintln!(
|
||||
println!(
|
||||
"For more suggestions, see https://rustc-dev-guide.rust-lang.org/building/suggested.html"
|
||||
);
|
||||
}
|
||||
|
|
@ -224,7 +224,7 @@ fn setup_config_toml(path: &PathBuf, profile: Profile, config: &Config) {
|
|||
t!(fs::write(path, settings));
|
||||
|
||||
let include_path = profile.include_path(&config.src);
|
||||
eprintln!("`x.py` will now use the configuration at {}", include_path.display());
|
||||
println!("`x.py` will now use the configuration at {}", include_path.display());
|
||||
}
|
||||
|
||||
/// Creates a toolchain link for stage1 using `rustup`
|
||||
|
|
@ -256,7 +256,7 @@ impl Step for Link {
|
|||
}
|
||||
|
||||
if !rustup_installed(builder) {
|
||||
eprintln!("WARNING: `rustup` is not installed; Skipping `stage1` toolchain linking.");
|
||||
println!("WARNING: `rustup` is not installed; Skipping `stage1` toolchain linking.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -296,7 +296,7 @@ fn attempt_toolchain_link(builder: &Builder<'_>, stage_path: &str) {
|
|||
}
|
||||
|
||||
if try_link_toolchain(builder, stage_path) {
|
||||
eprintln!(
|
||||
println!(
|
||||
"Added `stage1` rustup toolchain; try `cargo +stage1 build` on a separate rust project to run a newly-built toolchain"
|
||||
);
|
||||
} else {
|
||||
|
|
@ -321,14 +321,14 @@ fn toolchain_is_linked(builder: &Builder<'_>) -> bool {
|
|||
return false;
|
||||
}
|
||||
// The toolchain has already been linked.
|
||||
eprintln!(
|
||||
println!(
|
||||
"`stage1` toolchain already linked; not attempting to link `stage1` toolchain"
|
||||
);
|
||||
}
|
||||
None => {
|
||||
// In this case, we don't know if the `stage1` toolchain has been linked;
|
||||
// but `rustup` failed, so let's not go any further.
|
||||
eprintln!(
|
||||
println!(
|
||||
"`rustup` failed to list current toolchains; not attempting to link `stage1` toolchain"
|
||||
);
|
||||
}
|
||||
|
|
@ -389,12 +389,12 @@ pub fn interactive_path() -> io::Result<Profile> {
|
|||
input.parse()
|
||||
}
|
||||
|
||||
eprintln!("Welcome to the Rust project! What do you want to do with x.py?");
|
||||
println!("Welcome to the Rust project! What do you want to do with x.py?");
|
||||
for ((letter, _), profile) in abbrev_all() {
|
||||
eprintln!("{}) {}: {}", letter, profile, profile.purpose());
|
||||
println!("{}) {}: {}", letter, profile, profile.purpose());
|
||||
}
|
||||
let template = loop {
|
||||
eprint!(
|
||||
print!(
|
||||
"Please choose one ({}): ",
|
||||
abbrev_all().map(|((l, _), _)| l).collect::<Vec<_>>().join("/")
|
||||
);
|
||||
|
|
@ -428,7 +428,7 @@ enum PromptResult {
|
|||
fn prompt_user(prompt: &str) -> io::Result<Option<PromptResult>> {
|
||||
let mut input = String::new();
|
||||
loop {
|
||||
eprint!("{prompt} ");
|
||||
print!("{prompt} ");
|
||||
io::stdout().flush()?;
|
||||
input.clear();
|
||||
io::stdin().read_line(&mut input)?;
|
||||
|
|
@ -490,7 +490,7 @@ fn install_git_hook_maybe(builder: &Builder<'_>, config: &Config) -> io::Result<
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
eprintln!(
|
||||
println!(
|
||||
"\nRust's CI will automatically fail if it doesn't pass `tidy`, the internal tool for ensuring code quality.
|
||||
If you'd like, x.py can install a git hook for you that will automatically run `test tidy` before
|
||||
pushing your code to ensure your code is up to par. If you decide later that this behavior is
|
||||
|
|
@ -498,7 +498,7 @@ undesirable, simply delete the `pre-push` file from .git/hooks."
|
|||
);
|
||||
|
||||
if prompt_user("Would you like to install the git hook?: [y/N]")? != Some(PromptResult::Yes) {
|
||||
eprintln!("Ok, skipping installation!");
|
||||
println!("Ok, skipping installation!");
|
||||
return Ok(());
|
||||
}
|
||||
if !hooks_dir.exists() {
|
||||
|
|
@ -515,7 +515,7 @@ undesirable, simply delete the `pre-push` file from .git/hooks."
|
|||
);
|
||||
return Err(e);
|
||||
}
|
||||
Ok(_) => eprintln!("Linked `src/etc/pre-push.sh` to `.git/hooks/pre-push`"),
|
||||
Ok(_) => println!("Linked `src/etc/pre-push.sh` to `.git/hooks/pre-push`"),
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -541,7 +541,7 @@ Select which editor you would like to set up [default: None]: ";
|
|||
|
||||
let mut input = String::new();
|
||||
loop {
|
||||
eprint!("{}", prompt_str);
|
||||
print!("{}", prompt_str);
|
||||
io::stdout().flush()?;
|
||||
input.clear();
|
||||
io::stdin().read_line(&mut input)?;
|
||||
|
|
@ -656,7 +656,7 @@ impl Step for Editor {
|
|||
if let Some(editor_kind) = editor_kind {
|
||||
while !t!(create_editor_settings_maybe(config, editor_kind.clone())) {}
|
||||
} else {
|
||||
eprintln!("Ok, skipping editor setup!");
|
||||
println!("Ok, skipping editor setup!");
|
||||
}
|
||||
}
|
||||
Err(e) => eprintln!("Could not determine the editor: {e}"),
|
||||
|
|
@ -689,7 +689,7 @@ fn create_editor_settings_maybe(config: &Config, editor: EditorKind) -> io::Resu
|
|||
mismatched_settings = Some(false);
|
||||
}
|
||||
}
|
||||
eprintln!(
|
||||
println!(
|
||||
"\nx.py can automatically install the recommended `{settings_filename}` file for rustc development"
|
||||
);
|
||||
|
||||
|
|
@ -708,7 +708,7 @@ fn create_editor_settings_maybe(config: &Config, editor: EditorKind) -> io::Resu
|
|||
Some(PromptResult::Yes) => true,
|
||||
Some(PromptResult::Print) => false,
|
||||
_ => {
|
||||
eprintln!("Ok, skipping settings!");
|
||||
println!("Ok, skipping settings!");
|
||||
return Ok(true);
|
||||
}
|
||||
};
|
||||
|
|
@ -735,9 +735,9 @@ fn create_editor_settings_maybe(config: &Config, editor: EditorKind) -> io::Resu
|
|||
_ => "Created",
|
||||
};
|
||||
fs::write(&settings_path, editor.settings_template())?;
|
||||
eprintln!("{verb} `{}`", settings_filename);
|
||||
println!("{verb} `{}`", settings_filename);
|
||||
} else {
|
||||
eprintln!("\n{}", editor.settings_template());
|
||||
println!("\n{}", editor.settings_template());
|
||||
}
|
||||
Ok(should_create)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,6 +66,6 @@ pub fn suggest(builder: &Builder<'_>, run: bool) {
|
|||
build.build();
|
||||
}
|
||||
} else {
|
||||
eprintln!("HELP: consider using the `--run` flag to automatically run suggested tests");
|
||||
println!("HELP: consider using the `--run` flag to automatically run suggested tests");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -471,11 +471,11 @@ impl Miri {
|
|||
// We re-use the `cargo` from above.
|
||||
cargo.arg("--print-sysroot");
|
||||
|
||||
builder.verbose(|| eprintln!("running: {cargo:?}"));
|
||||
builder.verbose(|| println!("running: {cargo:?}"));
|
||||
let stdout = cargo.run_capture_stdout(builder).stdout();
|
||||
// Output is "<sysroot>\n".
|
||||
let sysroot = stdout.trim_end();
|
||||
builder.verbose(|| eprintln!("`cargo miri setup --print-sysroot` said: {sysroot:?}"));
|
||||
builder.verbose(|| println!("`cargo miri setup --print-sysroot` said: {sysroot:?}"));
|
||||
PathBuf::from(sysroot)
|
||||
}
|
||||
}
|
||||
|
|
@ -2488,7 +2488,7 @@ fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) ->
|
|||
}
|
||||
}
|
||||
|
||||
builder.verbose(|| eprintln!("doc tests for: {}", markdown.display()));
|
||||
builder.verbose(|| println!("doc tests for: {}", markdown.display()));
|
||||
let mut cmd = builder.rustdoc_cmd(compiler);
|
||||
builder.add_rust_test_threads(&mut cmd);
|
||||
// allow for unstable options such as new editions
|
||||
|
|
|
|||
|
|
@ -523,7 +523,7 @@ impl Builder<'_> {
|
|||
|
||||
let sysroot_str = sysroot.as_os_str().to_str().expect("sysroot should be UTF-8");
|
||||
if self.is_verbose() && !matches!(self.config.dry_run, DryRun::SelfCheck) {
|
||||
eprintln!("using sysroot {sysroot_str}");
|
||||
println!("using sysroot {sysroot_str}");
|
||||
}
|
||||
|
||||
let mut rustflags = Rustflags::new(target);
|
||||
|
|
@ -1035,12 +1035,7 @@ impl Builder<'_> {
|
|||
rustflags.arg("-Wrustc::internal");
|
||||
// cfg(bootstrap) - remove this check when lint is in bootstrap compiler
|
||||
if stage != 0 {
|
||||
// Lint is allow by default so downstream tools don't get a lit
|
||||
// they can do nothing about
|
||||
// We shouldn't be preinterning symbols used by tests
|
||||
if cmd_kind != Kind::Test {
|
||||
rustflags.arg("-Drustc::symbol_intern_string_literal");
|
||||
}
|
||||
rustflags.arg("-Drustc::symbol_intern_string_literal");
|
||||
}
|
||||
// FIXME(edition_2024): Change this to `-Wrust_2024_idioms` when all
|
||||
// of the individual lints are satisfied.
|
||||
|
|
|
|||
|
|
@ -392,14 +392,14 @@ impl StepDescription {
|
|||
fn is_excluded(&self, builder: &Builder<'_>, pathset: &PathSet) -> bool {
|
||||
if builder.config.skip.iter().any(|e| pathset.has(e, builder.kind)) {
|
||||
if !matches!(builder.config.dry_run, DryRun::SelfCheck) {
|
||||
eprintln!("Skipping {pathset:?} because it is excluded");
|
||||
println!("Skipping {pathset:?} because it is excluded");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if !builder.config.skip.is_empty() && !matches!(builder.config.dry_run, DryRun::SelfCheck) {
|
||||
builder.verbose(|| {
|
||||
eprintln!(
|
||||
println!(
|
||||
"{:?} not skipped for {:?} -- not in {:?}",
|
||||
pathset, self.name, builder.config.skip
|
||||
)
|
||||
|
|
@ -1437,11 +1437,11 @@ impl<'a> Builder<'a> {
|
|||
panic!("{}", out);
|
||||
}
|
||||
if let Some(out) = self.cache.get(&step) {
|
||||
self.verbose_than(1, || eprintln!("{}c {:?}", " ".repeat(stack.len()), step));
|
||||
self.verbose_than(1, || println!("{}c {:?}", " ".repeat(stack.len()), step));
|
||||
|
||||
return out;
|
||||
}
|
||||
self.verbose_than(1, || eprintln!("{}> {:?}", " ".repeat(stack.len()), step));
|
||||
self.verbose_than(1, || println!("{}> {:?}", " ".repeat(stack.len()), step));
|
||||
stack.push(Box::new(step.clone()));
|
||||
}
|
||||
|
||||
|
|
@ -1462,7 +1462,7 @@ impl<'a> Builder<'a> {
|
|||
let step_string = format!("{step:?}");
|
||||
let brace_index = step_string.find('{').unwrap_or(0);
|
||||
let type_string = type_name::<S>();
|
||||
eprintln!(
|
||||
println!(
|
||||
"[TIMING] {} {} -- {}.{:03}",
|
||||
&type_string.strip_prefix("bootstrap::").unwrap_or(type_string),
|
||||
&step_string[brace_index..],
|
||||
|
|
@ -1479,9 +1479,7 @@ impl<'a> Builder<'a> {
|
|||
let cur_step = stack.pop().expect("step stack empty");
|
||||
assert_eq!(cur_step.downcast_ref(), Some(&step));
|
||||
}
|
||||
self.verbose_than(1, || {
|
||||
eprintln!("{}< {:?}", " ".repeat(self.stack.borrow().len()), step)
|
||||
});
|
||||
self.verbose_than(1, || println!("{}< {:?}", " ".repeat(self.stack.borrow().len()), step));
|
||||
self.cache.put(step, out.clone());
|
||||
out
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1299,7 +1299,7 @@ impl Config {
|
|||
.map(|change_id| change_id.inner.map(crate::find_recent_config_change_ids))
|
||||
{
|
||||
if !changes.is_empty() {
|
||||
eprintln!(
|
||||
println!(
|
||||
"WARNING: There have been changes to x.py since you last updated:\n{}",
|
||||
crate::human_readable_changes(&changes)
|
||||
);
|
||||
|
|
@ -1565,7 +1565,7 @@ impl Config {
|
|||
}
|
||||
|
||||
if cargo_clippy.is_some() && rustc.is_none() {
|
||||
eprintln!(
|
||||
println!(
|
||||
"WARNING: Using `build.cargo-clippy` without `build.rustc` usually fails due to toolchain conflict."
|
||||
);
|
||||
}
|
||||
|
|
@ -1852,7 +1852,7 @@ impl Config {
|
|||
|
||||
// FIXME: Remove this option at the end of 2024.
|
||||
if parallel_compiler.is_some() {
|
||||
eprintln!(
|
||||
println!(
|
||||
"WARNING: The `rust.parallel-compiler` option is deprecated and does nothing. The parallel compiler (with one thread) is now the default"
|
||||
);
|
||||
}
|
||||
|
|
@ -1884,7 +1884,7 @@ impl Config {
|
|||
if available_backends.contains(&backend) {
|
||||
panic!("Invalid value '{s}' for 'rust.codegen-backends'. Instead, please use '{backend}'.");
|
||||
} else {
|
||||
eprintln!("HELP: '{s}' for 'rust.codegen-backends' might fail. \
|
||||
println!("HELP: '{s}' for 'rust.codegen-backends' might fail. \
|
||||
Codegen backends are mostly defined without the '{CODEGEN_BACKEND_PREFIX}' prefix. \
|
||||
In this case, it would be referred to as '{backend}'.");
|
||||
}
|
||||
|
|
@ -1913,7 +1913,7 @@ impl Config {
|
|||
// tests may fail due to using a different channel than the one used by the compiler during tests.
|
||||
if let Some(commit) = &config.download_rustc_commit {
|
||||
if is_user_configured_rust_channel {
|
||||
eprintln!(
|
||||
println!(
|
||||
"WARNING: `rust.download-rustc` is enabled. The `rust.channel` option will be overridden by the CI rustc's channel."
|
||||
);
|
||||
|
||||
|
|
@ -2003,10 +2003,10 @@ impl Config {
|
|||
|
||||
if config.llvm_from_ci {
|
||||
let warn = |option: &str| {
|
||||
eprintln!(
|
||||
println!(
|
||||
"WARNING: `{option}` will only be used on `compiler/rustc_llvm` build, not for the LLVM build."
|
||||
);
|
||||
eprintln!(
|
||||
println!(
|
||||
"HELP: To use `{option}` for LLVM builds, set `download-ci-llvm` option to false."
|
||||
);
|
||||
};
|
||||
|
|
@ -2025,12 +2025,12 @@ impl Config {
|
|||
// if they've chosen a different value.
|
||||
|
||||
if libzstd.is_some() {
|
||||
eprintln!(
|
||||
println!(
|
||||
"WARNING: when using `download-ci-llvm`, the local `llvm.libzstd` option, \
|
||||
like almost all `llvm.*` options, will be ignored and set by the LLVM CI \
|
||||
artifacts builder config."
|
||||
);
|
||||
eprintln!(
|
||||
println!(
|
||||
"HELP: To use `llvm.libzstd` for LLVM/LLD builds, set `download-ci-llvm` option to false."
|
||||
);
|
||||
}
|
||||
|
|
@ -2099,7 +2099,7 @@ impl Config {
|
|||
if available_backends.contains(&backend) {
|
||||
panic!("Invalid value '{s}' for 'target.{triple}.codegen-backends'. Instead, please use '{backend}'.");
|
||||
} else {
|
||||
eprintln!("HELP: '{s}' for 'target.{triple}.codegen-backends' might fail. \
|
||||
println!("HELP: '{s}' for 'target.{triple}.codegen-backends' might fail. \
|
||||
Codegen backends are mostly defined without the '{CODEGEN_BACKEND_PREFIX}' prefix. \
|
||||
In this case, it would be referred to as '{backend}'.");
|
||||
}
|
||||
|
|
@ -2315,7 +2315,7 @@ impl Config {
|
|||
if self.dry_run() {
|
||||
return Ok(());
|
||||
}
|
||||
self.verbose(|| eprintln!("running: {cmd:?}"));
|
||||
self.verbose(|| println!("running: {cmd:?}"));
|
||||
build_helper::util::try_run(cmd, self.is_verbose())
|
||||
}
|
||||
|
||||
|
|
@ -2490,7 +2490,7 @@ impl Config {
|
|||
// This happens when LLVM submodule is updated in CI, we should disable ci-rustc without an error
|
||||
// to not break CI. For non-CI environments, we should return an error.
|
||||
if CiEnv::is_ci() {
|
||||
eprintln!("WARNING: LLVM submodule has changes, `download-rustc` will be disabled.");
|
||||
println!("WARNING: LLVM submodule has changes, `download-rustc` will be disabled.");
|
||||
return None;
|
||||
} else {
|
||||
panic!("ERROR: LLVM submodule has changes, `download-rustc` can't be used.");
|
||||
|
|
@ -2501,8 +2501,8 @@ impl Config {
|
|||
let ci_config_toml = match self.get_builder_toml("ci-rustc") {
|
||||
Ok(ci_config_toml) => ci_config_toml,
|
||||
Err(e) if e.to_string().contains("unknown field") => {
|
||||
eprintln!("WARNING: CI rustc has some fields that are no longer supported in bootstrap; download-rustc will be disabled.");
|
||||
eprintln!("HELP: Consider rebasing to a newer commit if available.");
|
||||
println!("WARNING: CI rustc has some fields that are no longer supported in bootstrap; download-rustc will be disabled.");
|
||||
println!("HELP: Consider rebasing to a newer commit if available.");
|
||||
return None;
|
||||
},
|
||||
Err(e) => {
|
||||
|
|
@ -2527,7 +2527,7 @@ impl Config {
|
|||
.is_some_and(|s| s == "1" || s == "true");
|
||||
|
||||
if disable_ci_rustc_if_incompatible && res.is_err() {
|
||||
eprintln!("WARNING: download-rustc is disabled with `DISABLE_CI_RUSTC_IF_INCOMPATIBLE` env.");
|
||||
println!("WARNING: download-rustc is disabled with `DISABLE_CI_RUSTC_IF_INCOMPATIBLE` env.");
|
||||
return None;
|
||||
}
|
||||
|
||||
|
|
@ -2712,7 +2712,7 @@ impl Config {
|
|||
return;
|
||||
}
|
||||
|
||||
eprintln!("Updating submodule {relative_path}");
|
||||
println!("Updating submodule {relative_path}");
|
||||
self.check_run(
|
||||
helpers::git(Some(&self.src))
|
||||
.run_always()
|
||||
|
|
@ -2835,7 +2835,7 @@ impl Config {
|
|||
Some(StringOrBool::Bool(true)) => false,
|
||||
Some(StringOrBool::String(s)) if s == "if-unchanged" => {
|
||||
if !self.rust_info.is_managed_git_subrepository() {
|
||||
eprintln!(
|
||||
println!(
|
||||
"ERROR: `download-rustc=if-unchanged` is only compatible with Git managed sources."
|
||||
);
|
||||
crate::exit!(1);
|
||||
|
|
@ -2868,10 +2868,10 @@ impl Config {
|
|||
if if_unchanged {
|
||||
return None;
|
||||
}
|
||||
eprintln!("ERROR: could not find commit hash for downloading rustc");
|
||||
eprintln!("HELP: maybe your repository history is too shallow?");
|
||||
eprintln!("HELP: consider setting `rust.download-rustc=false` in config.toml");
|
||||
eprintln!("HELP: or fetch enough history to include one upstream commit");
|
||||
println!("ERROR: could not find commit hash for downloading rustc");
|
||||
println!("HELP: maybe your repository history is too shallow?");
|
||||
println!("HELP: consider setting `rust.download-rustc=false` in config.toml");
|
||||
println!("HELP: or fetch enough history to include one upstream commit");
|
||||
crate::exit!(1);
|
||||
}
|
||||
};
|
||||
|
|
@ -2910,7 +2910,7 @@ impl Config {
|
|||
let if_unchanged = || {
|
||||
if self.rust_info.is_from_tarball() {
|
||||
// Git is needed for running "if-unchanged" logic.
|
||||
eprintln!(
|
||||
println!(
|
||||
"WARNING: 'if-unchanged' has no effect on tarball sources; ignoring `download-ci-llvm`."
|
||||
);
|
||||
return false;
|
||||
|
|
@ -2959,10 +2959,10 @@ impl Config {
|
|||
// Only commits merged by bors will have CI artifacts.
|
||||
let commit = get_closest_merge_commit(Some(&self.src), &self.git_config(), &[]).unwrap();
|
||||
if commit.is_empty() {
|
||||
eprintln!("error: could not find commit hash for downloading components from CI");
|
||||
eprintln!("help: maybe your repository history is too shallow?");
|
||||
eprintln!("help: consider disabling `{option_name}`");
|
||||
eprintln!("help: or fetch enough history to include one upstream commit");
|
||||
println!("error: could not find commit hash for downloading components from CI");
|
||||
println!("help: maybe your repository history is too shallow?");
|
||||
println!("help: consider disabling `{option_name}`");
|
||||
println!("help: or fetch enough history to include one upstream commit");
|
||||
crate::exit!(1);
|
||||
}
|
||||
|
||||
|
|
@ -2974,14 +2974,14 @@ impl Config {
|
|||
if has_changes {
|
||||
if if_unchanged {
|
||||
if self.is_verbose() {
|
||||
eprintln!(
|
||||
println!(
|
||||
"warning: saw changes to one of {modified_paths:?} since {commit}; \
|
||||
ignoring `{option_name}`"
|
||||
);
|
||||
}
|
||||
return None;
|
||||
}
|
||||
eprintln!(
|
||||
println!(
|
||||
"warning: `{option_name}` is enabled, but there are changes to one of {modified_paths:?}"
|
||||
);
|
||||
}
|
||||
|
|
@ -3018,7 +3018,7 @@ pub(crate) fn check_incompatible_options_for_ci_llvm(
|
|||
($current:expr, $expected:expr) => {
|
||||
if let Some(current) = &$current {
|
||||
if Some(current) != $expected.as_ref() {
|
||||
eprintln!(
|
||||
println!(
|
||||
"WARNING: `llvm.{}` has no effect with `llvm.download-ci-llvm`. \
|
||||
Current value: {:?}, Expected value(s): {}{:?}",
|
||||
stringify!($expected).replace("_", "-"),
|
||||
|
|
@ -3123,7 +3123,7 @@ fn check_incompatible_options_for_ci_rustc(
|
|||
($current:expr, $expected:expr, $config_section:expr) => {
|
||||
if let Some(current) = &$current {
|
||||
if Some(current) != $expected.as_ref() {
|
||||
eprintln!(
|
||||
println!(
|
||||
"WARNING: `{}` has no effect with `rust.download-rustc`. \
|
||||
Current value: {:?}, Expected value(s): {}{:?}",
|
||||
format!("{}.{}", $config_section, stringify!($expected).replace("_", "-")),
|
||||
|
|
|
|||
|
|
@ -196,12 +196,12 @@ impl Flags {
|
|||
if let Ok(HelpVerboseOnly { help: true, verbose: 1.., cmd: subcommand }) =
|
||||
HelpVerboseOnly::try_parse_from(normalize_args(args))
|
||||
{
|
||||
eprintln!("NOTE: updating submodules before printing available paths");
|
||||
println!("NOTE: updating submodules before printing available paths");
|
||||
let config = Config::parse(Self::parse(&[String::from("build")]));
|
||||
let build = Build::new(config);
|
||||
let paths = Builder::get_help(&build, subcommand);
|
||||
if let Some(s) = paths {
|
||||
eprintln!("{s}");
|
||||
println!("{s}");
|
||||
} else {
|
||||
panic!("No paths available for subcommand `{}`", subcommand.as_str());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ impl Config {
|
|||
if self.dry_run() && !cmd.run_always {
|
||||
return true;
|
||||
}
|
||||
self.verbose(|| eprintln!("running: {cmd:?}"));
|
||||
self.verbose(|| println!("running: {cmd:?}"));
|
||||
check_run(cmd, self.is_verbose())
|
||||
}
|
||||
|
||||
|
|
@ -144,7 +144,7 @@ impl Config {
|
|||
/// Please see <https://nixos.org/patchelf.html> for more information
|
||||
fn fix_bin_or_dylib(&self, fname: &Path) {
|
||||
assert_eq!(SHOULD_FIX_BINS_AND_DYLIBS.get(), Some(&true));
|
||||
eprintln!("attempting to patch {}", fname.display());
|
||||
println!("attempting to patch {}", fname.display());
|
||||
|
||||
// Only build `.nix-deps` once.
|
||||
static NIX_DEPS_DIR: OnceLock<PathBuf> = OnceLock::new();
|
||||
|
|
@ -206,7 +206,7 @@ impl Config {
|
|||
}
|
||||
|
||||
fn download_file(&self, url: &str, dest_path: &Path, help_on_error: &str) {
|
||||
self.verbose(|| eprintln!("download {url}"));
|
||||
self.verbose(|| println!("download {url}"));
|
||||
// Use a temporary file in case we crash while downloading, to avoid a corrupt download in cache/.
|
||||
let tempfile = self.tempdir().join(dest_path.file_name().unwrap());
|
||||
// While bootstrap itself only supports http and https downloads, downstream forks might
|
||||
|
|
@ -226,7 +226,7 @@ impl Config {
|
|||
}
|
||||
|
||||
fn download_http_with_retries(&self, tempfile: &Path, url: &str, help_on_error: &str) {
|
||||
eprintln!("downloading {url}");
|
||||
println!("downloading {url}");
|
||||
// Try curl. If that fails and we are on windows, fallback to PowerShell.
|
||||
// options should be kept in sync with
|
||||
// src/bootstrap/src/core/download.rs
|
||||
|
|
@ -341,7 +341,7 @@ impl Config {
|
|||
short_path = short_path.strip_prefix(pattern).unwrap_or(short_path);
|
||||
let dst_path = dst.join(short_path);
|
||||
self.verbose(|| {
|
||||
eprintln!("extracting {} to {}", original_path.display(), dst.display())
|
||||
println!("extracting {} to {}", original_path.display(), dst.display())
|
||||
});
|
||||
if !t!(member.unpack_in(dst)) {
|
||||
panic!("path traversal attack ??");
|
||||
|
|
@ -365,7 +365,7 @@ impl Config {
|
|||
pub(crate) fn verify(&self, path: &Path, expected: &str) -> bool {
|
||||
use sha2::Digest;
|
||||
|
||||
self.verbose(|| eprintln!("verifying {}", path.display()));
|
||||
self.verbose(|| println!("verifying {}", path.display()));
|
||||
|
||||
if self.dry_run() {
|
||||
return false;
|
||||
|
|
@ -391,7 +391,7 @@ impl Config {
|
|||
let verified = checksum == expected;
|
||||
|
||||
if !verified {
|
||||
eprintln!(
|
||||
println!(
|
||||
"invalid checksum: \n\
|
||||
found: {checksum}\n\
|
||||
expected: {expected}",
|
||||
|
|
@ -421,7 +421,7 @@ enum DownloadSource {
|
|||
/// Functions that are only ever called once, but named for clarify and to avoid thousand-line functions.
|
||||
impl Config {
|
||||
pub(crate) fn download_clippy(&self) -> PathBuf {
|
||||
self.verbose(|| eprintln!("downloading stage0 clippy artifacts"));
|
||||
self.verbose(|| println!("downloading stage0 clippy artifacts"));
|
||||
|
||||
let date = &self.stage0_metadata.compiler.date;
|
||||
let version = &self.stage0_metadata.compiler.version;
|
||||
|
|
@ -518,7 +518,7 @@ impl Config {
|
|||
}
|
||||
|
||||
pub(crate) fn download_ci_rustc(&self, commit: &str) {
|
||||
self.verbose(|| eprintln!("using downloaded stage2 artifacts from CI (commit {commit})"));
|
||||
self.verbose(|| println!("using downloaded stage2 artifacts from CI (commit {commit})"));
|
||||
|
||||
let version = self.artifact_version_part(commit);
|
||||
// download-rustc doesn't need its own cargo, it can just use beta's. But it does need the
|
||||
|
|
@ -539,7 +539,7 @@ impl Config {
|
|||
|
||||
#[cfg(not(feature = "bootstrap-self-test"))]
|
||||
pub(crate) fn download_beta_toolchain(&self) {
|
||||
self.verbose(|| eprintln!("downloading stage0 beta artifacts"));
|
||||
self.verbose(|| println!("downloading stage0 beta artifacts"));
|
||||
|
||||
let date = &self.stage0_metadata.compiler.date;
|
||||
let version = &self.stage0_metadata.compiler.version;
|
||||
|
|
@ -677,7 +677,7 @@ impl Config {
|
|||
return;
|
||||
} else {
|
||||
self.verbose(|| {
|
||||
eprintln!(
|
||||
println!(
|
||||
"ignoring cached file {} due to failed verification",
|
||||
tarball.display()
|
||||
)
|
||||
|
|
@ -776,10 +776,10 @@ download-rustc = false
|
|||
t!(check_incompatible_options_for_ci_llvm(current_config_toml, ci_config_toml));
|
||||
}
|
||||
Err(e) if e.to_string().contains("unknown field") => {
|
||||
eprintln!(
|
||||
println!(
|
||||
"WARNING: CI LLVM has some fields that are no longer supported in bootstrap; download-ci-llvm will be disabled."
|
||||
);
|
||||
eprintln!("HELP: Consider rebasing to a newer commit if available.");
|
||||
println!("HELP: Consider rebasing to a newer commit if available.");
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("ERROR: Failed to parse CI LLVM config.toml: {e}");
|
||||
|
|
|
|||
|
|
@ -237,11 +237,11 @@ than building it.
|
|||
stage0_supported_target_list.intersection(&missing_targets_hashset).collect();
|
||||
|
||||
if !duplicated_targets.is_empty() {
|
||||
eprintln!(
|
||||
println!(
|
||||
"Following targets supported from the stage0 compiler, please remove them from STAGE0_MISSING_TARGETS list."
|
||||
);
|
||||
for duplicated_target in duplicated_targets {
|
||||
eprintln!(" {duplicated_target}");
|
||||
println!(" {duplicated_target}");
|
||||
}
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -406,11 +406,11 @@ impl Build {
|
|||
.unwrap()
|
||||
.trim();
|
||||
if local_release.split('.').take(2).eq(version.split('.').take(2)) {
|
||||
build.verbose(|| eprintln!("auto-detected local-rebuild {local_release}"));
|
||||
build.verbose(|| println!("auto-detected local-rebuild {local_release}"));
|
||||
build.local_rebuild = true;
|
||||
}
|
||||
|
||||
build.verbose(|| eprintln!("finding compilers"));
|
||||
build.verbose(|| println!("finding compilers"));
|
||||
utils::cc_detect::find(&build);
|
||||
// When running `setup`, the profile is about to change, so any requirements we have now may
|
||||
// be different on the next invocation. Don't check for them until the next time x.py is
|
||||
|
|
@ -418,7 +418,7 @@ impl Build {
|
|||
//
|
||||
// Similarly, for `setup` we don't actually need submodules or cargo metadata.
|
||||
if !matches!(build.config.cmd, Subcommand::Setup { .. }) {
|
||||
build.verbose(|| eprintln!("running sanity check"));
|
||||
build.verbose(|| println!("running sanity check"));
|
||||
crate::core::sanity::check(&mut build);
|
||||
|
||||
// Make sure we update these before gathering metadata so we don't get an error about missing
|
||||
|
|
@ -436,7 +436,7 @@ impl Build {
|
|||
// Now, update all existing submodules.
|
||||
build.update_existing_submodules();
|
||||
|
||||
build.verbose(|| eprintln!("learning about cargo"));
|
||||
build.verbose(|| println!("learning about cargo"));
|
||||
crate::core::metadata::build(&mut build);
|
||||
}
|
||||
|
||||
|
|
@ -605,7 +605,7 @@ impl Build {
|
|||
let stamp = dir.join(".stamp");
|
||||
let mut cleared = false;
|
||||
if mtime(&stamp) < mtime(input) {
|
||||
self.verbose(|| eprintln!("Dirty - {}", dir.display()));
|
||||
self.verbose(|| println!("Dirty - {}", dir.display()));
|
||||
let _ = fs::remove_dir_all(dir);
|
||||
cleared = true;
|
||||
} else if stamp.exists() {
|
||||
|
|
@ -890,7 +890,7 @@ impl Build {
|
|||
let executed_at = std::panic::Location::caller();
|
||||
|
||||
self.verbose(|| {
|
||||
eprintln!("running: {command:?} (created at {created_at}, executed at {executed_at})")
|
||||
println!("running: {command:?} (created at {created_at}, executed at {executed_at})")
|
||||
});
|
||||
|
||||
let cmd = command.as_command_mut();
|
||||
|
|
@ -947,7 +947,7 @@ Executed at: {executed_at}"#,
|
|||
|
||||
let fail = |message: &str, output: CommandOutput| -> ! {
|
||||
if self.is_verbose() {
|
||||
eprintln!("{message}");
|
||||
println!("{message}");
|
||||
} else {
|
||||
let (stdout, stderr) = (output.stdout_if_present(), output.stderr_if_present());
|
||||
// If the command captures output, the user would not see any indication that
|
||||
|
|
@ -957,16 +957,16 @@ Executed at: {executed_at}"#,
|
|||
if let Some(stdout) =
|
||||
output.stdout_if_present().take_if(|s| !s.trim().is_empty())
|
||||
{
|
||||
eprintln!("STDOUT:\n{stdout}\n");
|
||||
println!("STDOUT:\n{stdout}\n");
|
||||
}
|
||||
if let Some(stderr) =
|
||||
output.stderr_if_present().take_if(|s| !s.trim().is_empty())
|
||||
{
|
||||
eprintln!("STDERR:\n{stderr}\n");
|
||||
println!("STDERR:\n{stderr}\n");
|
||||
}
|
||||
eprintln!("Command {command:?} has failed. Rerun with -v to see more details.");
|
||||
println!("Command {command:?} has failed. Rerun with -v to see more details.");
|
||||
} else {
|
||||
eprintln!("Command has failed. Rerun with -v to see more details.");
|
||||
println!("Command has failed. Rerun with -v to see more details.");
|
||||
}
|
||||
}
|
||||
exit!(1);
|
||||
|
|
@ -1011,7 +1011,7 @@ Executed at: {executed_at}"#,
|
|||
match self.config.dry_run {
|
||||
DryRun::SelfCheck => (),
|
||||
DryRun::Disabled | DryRun::UserSelected => {
|
||||
eprintln!("{msg}");
|
||||
println!("{msg}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1666,7 +1666,7 @@ Executed at: {executed_at}"#,
|
|||
if self.config.dry_run() {
|
||||
return;
|
||||
}
|
||||
self.verbose_than(1, || eprintln!("Copy/Link {src:?} to {dst:?}"));
|
||||
self.verbose_than(1, || println!("Copy/Link {src:?} to {dst:?}"));
|
||||
if src == dst {
|
||||
return;
|
||||
}
|
||||
|
|
@ -1775,7 +1775,7 @@ Executed at: {executed_at}"#,
|
|||
return;
|
||||
}
|
||||
let dst = dstdir.join(src.file_name().unwrap());
|
||||
self.verbose_than(1, || eprintln!("Install {src:?} to {dst:?}"));
|
||||
self.verbose_than(1, || println!("Install {src:?} to {dst:?}"));
|
||||
t!(fs::create_dir_all(dstdir));
|
||||
if !src.exists() {
|
||||
panic!("ERROR: File \"{}\" not found!", src.display());
|
||||
|
|
|
|||
|
|
@ -155,15 +155,15 @@ pub fn find_target(build: &Build, target: TargetSelection) {
|
|||
build.cxx.borrow_mut().insert(target, compiler);
|
||||
}
|
||||
|
||||
build.verbose(|| eprintln!("CC_{} = {:?}", target.triple, build.cc(target)));
|
||||
build.verbose(|| eprintln!("CFLAGS_{} = {cflags:?}", target.triple));
|
||||
build.verbose(|| println!("CC_{} = {:?}", target.triple, build.cc(target)));
|
||||
build.verbose(|| println!("CFLAGS_{} = {cflags:?}", target.triple));
|
||||
if let Ok(cxx) = build.cxx(target) {
|
||||
let cxxflags = build.cflags(target, GitRepo::Rustc, CLang::Cxx);
|
||||
build.verbose(|| eprintln!("CXX_{} = {cxx:?}", target.triple));
|
||||
build.verbose(|| eprintln!("CXXFLAGS_{} = {cxxflags:?}", target.triple));
|
||||
build.verbose(|| println!("CXX_{} = {cxx:?}", target.triple));
|
||||
build.verbose(|| println!("CXXFLAGS_{} = {cxxflags:?}", target.triple));
|
||||
}
|
||||
if let Some(ar) = ar {
|
||||
build.verbose(|| eprintln!("AR_{} = {ar:?}", target.triple));
|
||||
build.verbose(|| println!("AR_{} = {ar:?}", target.triple));
|
||||
build.ar.borrow_mut().insert(target, ar);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ impl Drop for TimeIt {
|
|||
fn drop(&mut self) {
|
||||
let time = self.1.elapsed();
|
||||
if !self.0 {
|
||||
eprintln!("\tfinished in {}.{:03} seconds", time.as_secs(), time.subsec_millis());
|
||||
println!("\tfinished in {}.{:03} seconds", time.as_secs(), time.subsec_millis());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -267,12 +267,12 @@ pub fn check_run(cmd: &mut BootstrapCommand, print_cmd_on_fail: bool) -> bool {
|
|||
let status = match cmd.as_command_mut().status() {
|
||||
Ok(status) => status,
|
||||
Err(e) => {
|
||||
eprintln!("failed to execute command: {cmd:?}\nERROR: {e}");
|
||||
println!("failed to execute command: {cmd:?}\nERROR: {e}");
|
||||
return false;
|
||||
}
|
||||
};
|
||||
if !status.success() && print_cmd_on_fail {
|
||||
eprintln!(
|
||||
println!(
|
||||
"\n\ncommand did not execute successfully: {cmd:?}\n\
|
||||
expected success, got: {status}\n\n"
|
||||
);
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ impl BuildMetrics {
|
|||
if version.format_version == CURRENT_FORMAT_VERSION {
|
||||
t!(serde_json::from_slice::<JsonRoot>(&contents)).invocations
|
||||
} else {
|
||||
eprintln!(
|
||||
println!(
|
||||
"WARNING: overriding existing build/metrics.json, as it's not \
|
||||
compatible with build metrics format version {CURRENT_FORMAT_VERSION}."
|
||||
);
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ fn run_tests(builder: &Builder<'_>, cmd: &mut BootstrapCommand, stream: bool) ->
|
|||
let cmd = cmd.as_command_mut();
|
||||
cmd.stdout(Stdio::piped());
|
||||
|
||||
builder.verbose(|| eprintln!("running: {cmd:?}"));
|
||||
builder.verbose(|| println!("running: {cmd:?}"));
|
||||
|
||||
let mut process = cmd.spawn().unwrap();
|
||||
|
||||
|
|
@ -71,7 +71,7 @@ fn run_tests(builder: &Builder<'_>, cmd: &mut BootstrapCommand, stream: bool) ->
|
|||
|
||||
let result = process.wait_with_output().unwrap();
|
||||
if !result.status.success() && builder.is_verbose() {
|
||||
eprintln!(
|
||||
println!(
|
||||
"\n\ncommand did not execute successfully: {cmd:?}\n\
|
||||
expected success, got: {}",
|
||||
result.status
|
||||
|
|
@ -135,9 +135,7 @@ impl<'a> Renderer<'a> {
|
|||
if self.up_to_date_tests > 0 {
|
||||
let n = self.up_to_date_tests;
|
||||
let s = if n > 1 { "s" } else { "" };
|
||||
eprintln!(
|
||||
"help: ignored {n} up-to-date test{s}; use `--force-rerun` to prevent this\n"
|
||||
);
|
||||
println!("help: ignored {n} up-to-date test{s}; use `--force-rerun` to prevent this\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -187,12 +185,12 @@ impl<'a> Renderer<'a> {
|
|||
}
|
||||
|
||||
fn render_test_outcome_verbose(&self, outcome: Outcome<'_>, test: &TestOutcome) {
|
||||
eprint!("test {} ... ", test.name);
|
||||
self.builder.colored_stderr(|stdout| outcome.write_long(stdout)).unwrap();
|
||||
print!("test {} ... ", test.name);
|
||||
self.builder.colored_stdout(|stdout| outcome.write_long(stdout)).unwrap();
|
||||
if let Some(exec_time) = test.exec_time {
|
||||
eprint!(" ({exec_time:.2?})");
|
||||
print!(" ({exec_time:.2?})");
|
||||
}
|
||||
eprintln!();
|
||||
println!();
|
||||
}
|
||||
|
||||
fn render_test_outcome_terse(&mut self, outcome: Outcome<'_>, test: &TestOutcome) {
|
||||
|
|
@ -200,45 +198,45 @@ impl<'a> Renderer<'a> {
|
|||
if let Some(total) = self.tests_count {
|
||||
let total = total.to_string();
|
||||
let executed = format!("{:>width$}", self.executed_tests - 1, width = total.len());
|
||||
eprint!(" {executed}/{total}");
|
||||
print!(" {executed}/{total}");
|
||||
}
|
||||
eprintln!();
|
||||
println!();
|
||||
self.terse_tests_in_line = 0;
|
||||
}
|
||||
|
||||
self.terse_tests_in_line += 1;
|
||||
self.builder.colored_stderr(|stdout| outcome.write_short(stdout, &test.name)).unwrap();
|
||||
self.builder.colored_stdout(|stdout| outcome.write_short(stdout, &test.name)).unwrap();
|
||||
let _ = std::io::stdout().flush();
|
||||
}
|
||||
|
||||
fn render_suite_outcome(&self, outcome: Outcome<'_>, suite: &SuiteOutcome) {
|
||||
// The terse output doesn't end with a newline, so we need to add it ourselves.
|
||||
if !self.builder.config.verbose_tests {
|
||||
eprintln!();
|
||||
println!();
|
||||
}
|
||||
|
||||
if !self.failures.is_empty() {
|
||||
eprintln!("\nfailures:\n");
|
||||
println!("\nfailures:\n");
|
||||
for failure in &self.failures {
|
||||
if failure.stdout.is_some() || failure.message.is_some() {
|
||||
eprintln!("---- {} stdout ----", failure.name);
|
||||
println!("---- {} stdout ----", failure.name);
|
||||
if let Some(stdout) = &failure.stdout {
|
||||
eprintln!("{stdout}");
|
||||
println!("{stdout}");
|
||||
}
|
||||
if let Some(message) = &failure.message {
|
||||
eprintln!("NOTE: {message}");
|
||||
println!("NOTE: {message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eprintln!("\nfailures:");
|
||||
println!("\nfailures:");
|
||||
for failure in &self.failures {
|
||||
eprintln!(" {}", failure.name);
|
||||
println!(" {}", failure.name);
|
||||
}
|
||||
}
|
||||
|
||||
if !self.benches.is_empty() {
|
||||
eprintln!("\nbenchmarks:");
|
||||
println!("\nbenchmarks:");
|
||||
|
||||
let mut rows = Vec::new();
|
||||
for bench in &self.benches {
|
||||
|
|
@ -253,13 +251,13 @@ impl<'a> Renderer<'a> {
|
|||
let max_1 = rows.iter().map(|r| r.1.len()).max().unwrap_or(0);
|
||||
let max_2 = rows.iter().map(|r| r.2.len()).max().unwrap_or(0);
|
||||
for row in &rows {
|
||||
eprintln!(" {:<max_0$} {:>max_1$} {:>max_2$}", row.0, row.1, row.2);
|
||||
println!(" {:<max_0$} {:>max_1$} {:>max_2$}", row.0, row.1, row.2);
|
||||
}
|
||||
}
|
||||
|
||||
eprint!("\ntest result: ");
|
||||
self.builder.colored_stderr(|stdout| outcome.write_long(stdout)).unwrap();
|
||||
eprintln!(
|
||||
print!("\ntest result: ");
|
||||
self.builder.colored_stdout(|stdout| outcome.write_long(stdout)).unwrap();
|
||||
println!(
|
||||
". {} passed; {} failed; {} ignored; {} measured; {} filtered out{time}\n",
|
||||
suite.passed,
|
||||
suite.failed,
|
||||
|
|
@ -276,7 +274,7 @@ impl<'a> Renderer<'a> {
|
|||
fn render_message(&mut self, message: Message) {
|
||||
match message {
|
||||
Message::Suite(SuiteMessage::Started { test_count }) => {
|
||||
eprintln!("\nrunning {test_count} tests");
|
||||
println!("\nrunning {test_count} tests");
|
||||
self.executed_tests = 0;
|
||||
self.terse_tests_in_line = 0;
|
||||
self.tests_count = Some(test_count);
|
||||
|
|
@ -316,7 +314,7 @@ impl<'a> Renderer<'a> {
|
|||
self.failures.push(outcome);
|
||||
}
|
||||
Message::Test(TestMessage::Timeout { name }) => {
|
||||
eprintln!("test {name} has been running for a long time");
|
||||
println!("test {name} has been running for a long time");
|
||||
}
|
||||
Message::Test(TestMessage::Started) => {} // Not useful
|
||||
}
|
||||
|
|
|
|||
|
|
@ -344,7 +344,7 @@ impl<'a> Tarball<'a> {
|
|||
// For `x install` tarball files aren't needed, so we can speed up the process by not producing them.
|
||||
let compression_profile = if self.builder.kind == Kind::Install {
|
||||
self.builder.verbose(|| {
|
||||
eprintln!("Forcing dist.compression-profile = 'no-op' for `x install`.")
|
||||
println!("Forcing dist.compression-profile = 'no-op' for `x install`.")
|
||||
});
|
||||
// "no-op" indicates that the rust-installer won't produce compressed tarball sources.
|
||||
"no-op"
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ PICK_REFS=()
|
|||
# commit hash of fuchsia.git and some other repos in the "monorepo" checkout, in
|
||||
# addition to versions of prebuilts. It should be bumped regularly by the
|
||||
# Fuchsia team – we aim for every 1-2 months.
|
||||
INTEGRATION_SHA=9f632bb7446d5a6af2998f1a0ebdb4b8ea2f4511
|
||||
INTEGRATION_SHA=bb38af4e3d45e490531b71fc52a460003141d032
|
||||
|
||||
checkout=fuchsia
|
||||
jiri=.jiri_root/bin/jiri
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ pub(crate) fn build_index(
|
|||
// exported from this same module). It's also likely to Do
|
||||
// What I Mean, since if a re-export changes the name, it might
|
||||
// also be a change in semantic meaning.
|
||||
.filter(|fqp| fqp.last() == fqp.last());
|
||||
.filter(|this_fqp| this_fqp.last() == fqp.last());
|
||||
Some(insert_into_map(
|
||||
itemid_to_pathid,
|
||||
ItemId::DefId(defid),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
#![feature(async_closure)]
|
||||
#![warn(clippy::async_yields_async)]
|
||||
#![allow(clippy::redundant_async_block)]
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
#![feature(async_closure)]
|
||||
#![warn(clippy::async_yields_async)]
|
||||
#![allow(clippy::redundant_async_block)]
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error: an async construct yields a type which is itself awaitable
|
||||
--> tests/ui/async_yields_async.rs:38:9
|
||||
--> tests/ui/async_yields_async.rs:37:9
|
||||
|
|
||||
LL | let _h = async {
|
||||
| _____________________-
|
||||
|
|
@ -20,7 +20,7 @@ LL + }.await
|
|||
|
|
||||
|
||||
error: an async construct yields a type which is itself awaitable
|
||||
--> tests/ui/async_yields_async.rs:43:9
|
||||
--> tests/ui/async_yields_async.rs:42:9
|
||||
|
|
||||
LL | let _i = async {
|
||||
| ____________________-
|
||||
|
|
@ -33,7 +33,7 @@ LL | | };
|
|||
| |_____- outer async construct
|
||||
|
||||
error: an async construct yields a type which is itself awaitable
|
||||
--> tests/ui/async_yields_async.rs:49:9
|
||||
--> tests/ui/async_yields_async.rs:48:9
|
||||
|
|
||||
LL | let _j = async || {
|
||||
| ________________________-
|
||||
|
|
@ -52,7 +52,7 @@ LL + }.await
|
|||
|
|
||||
|
||||
error: an async construct yields a type which is itself awaitable
|
||||
--> tests/ui/async_yields_async.rs:54:9
|
||||
--> tests/ui/async_yields_async.rs:53:9
|
||||
|
|
||||
LL | let _k = async || {
|
||||
| _______________________-
|
||||
|
|
@ -65,7 +65,7 @@ LL | | };
|
|||
| |_____- outer async construct
|
||||
|
||||
error: an async construct yields a type which is itself awaitable
|
||||
--> tests/ui/async_yields_async.rs:56:23
|
||||
--> tests/ui/async_yields_async.rs:55:23
|
||||
|
|
||||
LL | let _l = async || CustomFutureType;
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
@ -75,7 +75,7 @@ LL | let _l = async || CustomFutureType;
|
|||
| help: consider awaiting this value: `CustomFutureType.await`
|
||||
|
||||
error: an async construct yields a type which is itself awaitable
|
||||
--> tests/ui/async_yields_async.rs:62:9
|
||||
--> tests/ui/async_yields_async.rs:61:9
|
||||
|
|
||||
LL | let _m = async || {
|
||||
| _______________________-
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
#![allow(redundant_semicolons, clippy::no_effect)]
|
||||
#![feature(stmt_expr_attributes)]
|
||||
#![feature(async_closure)]
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn main() {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
#![allow(clippy::never_loop)]
|
||||
#![warn(clippy::infinite_loop)]
|
||||
#![feature(async_closure)]
|
||||
|
||||
extern crate proc_macros;
|
||||
use proc_macros::{external, with_span};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error: infinite loop detected
|
||||
--> tests/ui/infinite_loops.rs:14:5
|
||||
--> tests/ui/infinite_loops.rs:13:5
|
||||
|
|
||||
LL | / loop {
|
||||
LL | |
|
||||
|
|
@ -15,7 +15,7 @@ LL | fn no_break() -> ! {
|
|||
| ++++
|
||||
|
||||
error: infinite loop detected
|
||||
--> tests/ui/infinite_loops.rs:21:5
|
||||
--> tests/ui/infinite_loops.rs:20:5
|
||||
|
|
||||
LL | / loop {
|
||||
LL | |
|
||||
|
|
@ -32,7 +32,7 @@ LL | fn all_inf() -> ! {
|
|||
| ++++
|
||||
|
||||
error: infinite loop detected
|
||||
--> tests/ui/infinite_loops.rs:23:9
|
||||
--> tests/ui/infinite_loops.rs:22:9
|
||||
|
|
||||
LL | / loop {
|
||||
LL | |
|
||||
|
|
@ -49,7 +49,7 @@ LL | fn all_inf() -> ! {
|
|||
| ++++
|
||||
|
||||
error: infinite loop detected
|
||||
--> tests/ui/infinite_loops.rs:25:13
|
||||
--> tests/ui/infinite_loops.rs:24:13
|
||||
|
|
||||
LL | / loop {
|
||||
LL | |
|
||||
|
|
@ -63,7 +63,7 @@ LL | fn all_inf() -> ! {
|
|||
| ++++
|
||||
|
||||
error: infinite loop detected
|
||||
--> tests/ui/infinite_loops.rs:39:5
|
||||
--> tests/ui/infinite_loops.rs:38:5
|
||||
|
|
||||
LL | / loop {
|
||||
LL | |
|
||||
|
|
@ -74,7 +74,7 @@ LL | | }
|
|||
= help: if this is not intended, try adding a `break` or `return` condition in the loop
|
||||
|
||||
error: infinite loop detected
|
||||
--> tests/ui/infinite_loops.rs:52:5
|
||||
--> tests/ui/infinite_loops.rs:51:5
|
||||
|
|
||||
LL | / loop {
|
||||
LL | | fn inner_fn() -> ! {
|
||||
|
|
@ -90,7 +90,7 @@ LL | fn no_break_never_ret_noise() -> ! {
|
|||
| ++++
|
||||
|
||||
error: infinite loop detected
|
||||
--> tests/ui/infinite_loops.rs:95:5
|
||||
--> tests/ui/infinite_loops.rs:94:5
|
||||
|
|
||||
LL | / loop {
|
||||
LL | |
|
||||
|
|
@ -107,7 +107,7 @@ LL | fn break_inner_but_not_outer_1(cond: bool) -> ! {
|
|||
| ++++
|
||||
|
||||
error: infinite loop detected
|
||||
--> tests/ui/infinite_loops.rs:106:5
|
||||
--> tests/ui/infinite_loops.rs:105:5
|
||||
|
|
||||
LL | / loop {
|
||||
LL | |
|
||||
|
|
@ -124,7 +124,7 @@ LL | fn break_inner_but_not_outer_2(cond: bool) -> ! {
|
|||
| ++++
|
||||
|
||||
error: infinite loop detected
|
||||
--> tests/ui/infinite_loops.rs:120:9
|
||||
--> tests/ui/infinite_loops.rs:119:9
|
||||
|
|
||||
LL | / loop {
|
||||
LL | |
|
||||
|
|
@ -138,7 +138,7 @@ LL | fn break_outer_but_not_inner() -> ! {
|
|||
| ++++
|
||||
|
||||
error: infinite loop detected
|
||||
--> tests/ui/infinite_loops.rs:143:9
|
||||
--> tests/ui/infinite_loops.rs:142:9
|
||||
|
|
||||
LL | / loop {
|
||||
LL | |
|
||||
|
|
@ -155,7 +155,7 @@ LL | fn break_wrong_loop(cond: bool) -> ! {
|
|||
| ++++
|
||||
|
||||
error: infinite loop detected
|
||||
--> tests/ui/infinite_loops.rs:183:5
|
||||
--> tests/ui/infinite_loops.rs:182:5
|
||||
|
|
||||
LL | / loop {
|
||||
LL | |
|
||||
|
|
@ -172,7 +172,7 @@ LL | fn match_like() -> ! {
|
|||
| ++++
|
||||
|
||||
error: infinite loop detected
|
||||
--> tests/ui/infinite_loops.rs:224:5
|
||||
--> tests/ui/infinite_loops.rs:223:5
|
||||
|
|
||||
LL | / loop {
|
||||
LL | |
|
||||
|
|
@ -186,7 +186,7 @@ LL | fn match_like() -> ! {
|
|||
| ++++
|
||||
|
||||
error: infinite loop detected
|
||||
--> tests/ui/infinite_loops.rs:229:5
|
||||
--> tests/ui/infinite_loops.rs:228:5
|
||||
|
|
||||
LL | / loop {
|
||||
LL | |
|
||||
|
|
@ -203,7 +203,7 @@ LL | fn match_like() -> ! {
|
|||
| ++++
|
||||
|
||||
error: infinite loop detected
|
||||
--> tests/ui/infinite_loops.rs:334:9
|
||||
--> tests/ui/infinite_loops.rs:333:9
|
||||
|
|
||||
LL | / loop {
|
||||
LL | |
|
||||
|
|
@ -217,7 +217,7 @@ LL | fn problematic_trait_method() -> ! {
|
|||
| ++++
|
||||
|
||||
error: infinite loop detected
|
||||
--> tests/ui/infinite_loops.rs:344:9
|
||||
--> tests/ui/infinite_loops.rs:343:9
|
||||
|
|
||||
LL | / loop {
|
||||
LL | |
|
||||
|
|
@ -231,7 +231,7 @@ LL | fn could_be_problematic() -> ! {
|
|||
| ++++
|
||||
|
||||
error: infinite loop detected
|
||||
--> tests/ui/infinite_loops.rs:353:9
|
||||
--> tests/ui/infinite_loops.rs:352:9
|
||||
|
|
||||
LL | / loop {
|
||||
LL | |
|
||||
|
|
@ -245,7 +245,7 @@ LL | let _loop_forever = || -> ! {
|
|||
| ++++
|
||||
|
||||
error: infinite loop detected
|
||||
--> tests/ui/infinite_loops.rs:367:8
|
||||
--> tests/ui/infinite_loops.rs:366:8
|
||||
|
|
||||
LL | Ok(loop {
|
||||
| ________^
|
||||
|
|
@ -256,7 +256,7 @@ LL | | })
|
|||
= help: if this is not intended, try adding a `break` or `return` condition in the loop
|
||||
|
||||
error: infinite loop detected
|
||||
--> tests/ui/infinite_loops.rs:409:5
|
||||
--> tests/ui/infinite_loops.rs:408:5
|
||||
|
|
||||
LL | / 'infinite: loop {
|
||||
LL | |
|
||||
|
|
@ -272,7 +272,7 @@ LL | fn continue_outer() -> ! {
|
|||
| ++++
|
||||
|
||||
error: infinite loop detected
|
||||
--> tests/ui/infinite_loops.rs:416:5
|
||||
--> tests/ui/infinite_loops.rs:415:5
|
||||
|
|
||||
LL | / loop {
|
||||
LL | |
|
||||
|
|
@ -289,7 +289,7 @@ LL | fn continue_outer() -> ! {
|
|||
| ++++
|
||||
|
||||
error: infinite loop detected
|
||||
--> tests/ui/infinite_loops.rs:418:9
|
||||
--> tests/ui/infinite_loops.rs:417:9
|
||||
|
|
||||
LL | / 'inner: loop {
|
||||
LL | | loop {
|
||||
|
|
@ -304,7 +304,7 @@ LL | fn continue_outer() -> ! {
|
|||
| ++++
|
||||
|
||||
error: infinite loop detected
|
||||
--> tests/ui/infinite_loops.rs:426:5
|
||||
--> tests/ui/infinite_loops.rs:425:5
|
||||
|
|
||||
LL | / loop {
|
||||
LL | |
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
#![feature(async_closure)]
|
||||
#![warn(clippy::redundant_closure_call)]
|
||||
#![allow(clippy::redundant_async_block)]
|
||||
#![allow(clippy::type_complexity)]
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
#![feature(async_closure)]
|
||||
#![warn(clippy::redundant_closure_call)]
|
||||
#![allow(clippy::redundant_async_block)]
|
||||
#![allow(clippy::type_complexity)]
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error: try not to call a closure in the expression where it is declared
|
||||
--> tests/ui/redundant_closure_call_fixable.rs:16:13
|
||||
--> tests/ui/redundant_closure_call_fixable.rs:15:13
|
||||
|
|
||||
LL | let a = (|| 42)();
|
||||
| ^^^^^^^^^ help: try doing something like: `42`
|
||||
|
|
@ -8,7 +8,7 @@ LL | let a = (|| 42)();
|
|||
= help: to override `-D warnings` add `#[allow(clippy::redundant_closure_call)]`
|
||||
|
||||
error: try not to call a closure in the expression where it is declared
|
||||
--> tests/ui/redundant_closure_call_fixable.rs:17:13
|
||||
--> tests/ui/redundant_closure_call_fixable.rs:16:13
|
||||
|
|
||||
LL | let b = (async || {
|
||||
| _____________^
|
||||
|
|
@ -28,7 +28,7 @@ LL ~ };
|
|||
|
|
||||
|
||||
error: try not to call a closure in the expression where it is declared
|
||||
--> tests/ui/redundant_closure_call_fixable.rs:22:13
|
||||
--> tests/ui/redundant_closure_call_fixable.rs:21:13
|
||||
|
|
||||
LL | let c = (|| {
|
||||
| _____________^
|
||||
|
|
@ -48,13 +48,13 @@ LL ~ };
|
|||
|
|
||||
|
||||
error: try not to call a closure in the expression where it is declared
|
||||
--> tests/ui/redundant_closure_call_fixable.rs:27:13
|
||||
--> tests/ui/redundant_closure_call_fixable.rs:26:13
|
||||
|
|
||||
LL | let d = (async || something().await)();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `async { something().await }`
|
||||
|
||||
error: try not to call a closure in the expression where it is declared
|
||||
--> tests/ui/redundant_closure_call_fixable.rs:36:13
|
||||
--> tests/ui/redundant_closure_call_fixable.rs:35:13
|
||||
|
|
||||
LL | (|| m!())()
|
||||
| ^^^^^^^^^^^ help: try doing something like: `m!()`
|
||||
|
|
@ -65,7 +65,7 @@ LL | m2!();
|
|||
= note: this error originates in the macro `m2` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: try not to call a closure in the expression where it is declared
|
||||
--> tests/ui/redundant_closure_call_fixable.rs:31:13
|
||||
--> tests/ui/redundant_closure_call_fixable.rs:30:13
|
||||
|
|
||||
LL | (|| 0)()
|
||||
| ^^^^^^^^ help: try doing something like: `0`
|
||||
|
|
@ -76,67 +76,67 @@ LL | m2!();
|
|||
= note: this error originates in the macro `m` which comes from the expansion of the macro `m2` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: try not to call a closure in the expression where it is declared
|
||||
--> tests/ui/redundant_closure_call_fixable.rs:44:16
|
||||
--> tests/ui/redundant_closure_call_fixable.rs:43:16
|
||||
|
|
||||
LL | assert_eq!((|| || 43)()(), 42);
|
||||
| ^^^^^^^^^^^^^^ help: try doing something like: `43`
|
||||
|
||||
error: try not to call a closure in the expression where it is declared
|
||||
--> tests/ui/redundant_closure_call_fixable.rs:53:10
|
||||
--> tests/ui/redundant_closure_call_fixable.rs:52:10
|
||||
|
|
||||
LL | dbg!((|| 42)());
|
||||
| ^^^^^^^^^ help: try doing something like: `42`
|
||||
|
||||
error: try not to call a closure in the expression where it is declared
|
||||
--> tests/ui/redundant_closure_call_fixable.rs:56:13
|
||||
--> tests/ui/redundant_closure_call_fixable.rs:55:13
|
||||
|
|
||||
LL | let a = (|| || || 123)();
|
||||
| ^^^^^^^^^^^^^^^^ help: try doing something like: `(|| || 123)`
|
||||
|
||||
error: try not to call a closure in the expression where it is declared
|
||||
--> tests/ui/redundant_closure_call_fixable.rs:60:13
|
||||
--> tests/ui/redundant_closure_call_fixable.rs:59:13
|
||||
|
|
||||
LL | let a = (|| || || || async || 1)()()()()();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `async { 1 }`
|
||||
|
||||
error: try not to call a closure in the expression where it is declared
|
||||
--> tests/ui/redundant_closure_call_fixable.rs:69:13
|
||||
--> tests/ui/redundant_closure_call_fixable.rs:68:13
|
||||
|
|
||||
LL | let a = (|| echo!(|| echo!(|| 1)))()()();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `1`
|
||||
|
||||
error: try not to call a closure in the expression where it is declared
|
||||
--> tests/ui/redundant_closure_call_fixable.rs:71:13
|
||||
--> tests/ui/redundant_closure_call_fixable.rs:70:13
|
||||
|
|
||||
LL | let a = (|| echo!((|| 123)))()();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `123`
|
||||
|
||||
error: try not to call a closure in the expression where it is declared
|
||||
--> tests/ui/redundant_closure_call_fixable.rs:84:11
|
||||
--> tests/ui/redundant_closure_call_fixable.rs:83:11
|
||||
|
|
||||
LL | bar()((|| || 42)()(), 5);
|
||||
| ^^^^^^^^^^^^^^ help: try doing something like: `42`
|
||||
|
||||
error: try not to call a closure in the expression where it is declared
|
||||
--> tests/ui/redundant_closure_call_fixable.rs:85:9
|
||||
--> tests/ui/redundant_closure_call_fixable.rs:84:9
|
||||
|
|
||||
LL | foo((|| || 42)()(), 5);
|
||||
| ^^^^^^^^^^^^^^ help: try doing something like: `42`
|
||||
|
||||
error: try not to call a closure in the expression where it is declared
|
||||
--> tests/ui/redundant_closure_call_fixable.rs:89:5
|
||||
--> tests/ui/redundant_closure_call_fixable.rs:88:5
|
||||
|
|
||||
LL | (|| async {})().await;
|
||||
| ^^^^^^^^^^^^^^^ help: try doing something like: `async {}`
|
||||
|
||||
error: try not to call a closure in the expression where it is declared
|
||||
--> tests/ui/redundant_closure_call_fixable.rs:98:18
|
||||
--> tests/ui/redundant_closure_call_fixable.rs:97:18
|
||||
|
|
||||
LL | spawn_on((|| async move {})());
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `async move {}`
|
||||
|
||||
error: try not to call a closure in the expression where it is declared
|
||||
--> tests/ui/redundant_closure_call_fixable.rs:103:28
|
||||
--> tests/ui/redundant_closure_call_fixable.rs:102:28
|
||||
|
|
||||
LL | std::convert::identity((|| 13_i32 + 36_i32)()).leading_zeros();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `13_i32 + 36_i32`
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
//@aux-build:proc_macros.rs
|
||||
#![allow(unused, clippy::no_effect, clippy::needless_pass_by_ref_mut)]
|
||||
#![warn(clippy::redundant_locals)]
|
||||
#![feature(async_closure, coroutines, stmt_expr_attributes)]
|
||||
#![feature(coroutines, stmt_expr_attributes)]
|
||||
|
||||
extern crate proc_macros;
|
||||
use proc_macros::{external, with_span};
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue