diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs index 1cf2b40e93068..dac9ee6a5d91e 100644 --- a/src/libcore/mem/mod.rs +++ b/src/libcore/mem/mod.rs @@ -58,7 +58,9 @@ pub use crate::intrinsics::transmute; /// /// # Examples /// -/// Leak an I/O object, never closing the file: +/// The canonical safe use of `mem::forget` is to circumvent a value's destructor +/// implemented by the `Drop` trait. For example, this will leak a `File`, i.e. reclaim +/// the space taken by the variable but never close the underlying system resource: /// /// ```no_run /// use std::mem; @@ -68,9 +70,40 @@ pub use crate::intrinsics::transmute; /// mem::forget(file); /// ``` /// -/// The practical use cases for `forget` are rather specialized and mainly come -/// up in unsafe or FFI code. However, [`ManuallyDrop`] is usually preferred -/// for such cases, e.g.: +/// This is useful when the ownership of the underlying resource was previously +/// transferred to code outside of Rust, for example by transmitting the raw +/// file descriptor to C code. +/// +/// # Relationship with `ManuallyDrop` +/// +/// While `mem::forget` can also be used to transfer *memory* ownership, doing so is error-prone. +/// [`ManuallyDrop`] should be used instead. Consider, for example, this code: +/// +/// ``` +/// use std::mem; +/// +/// let mut v = vec![65, 122]; +/// // Build a `String` using the contents of `v` +/// let s = unsafe { String::from_raw_parts(v.as_mut_ptr(), v.len(), v.capacity()) }; +/// // leak `v` because its memory is now managed by `s` +/// mem::forget(v); // ERROR - v is invalid and must not be passed to a function +/// assert_eq!(s, "Az"); +/// // `s` is implicitly dropped and its memory deallocated. +/// ``` +/// +/// There are two issues with the above example: +/// +/// * If more code were added between the construction of `String` and the invocation of +/// `mem::forget()`, a panic within it would cause a double free because the same memory +/// is handled by both `v` and `s`. +/// * After calling `v.as_mut_ptr()` and transmitting the ownership of the data to `s`, +/// the `v` value is invalid. Even when a value is just moved to `mem::forget` (which won't +/// inspect it), some types have strict requirements on their values that +/// make them invalid when dangling or no longer owned. Using invalid values in any +/// way, including passing them to or returning them from functions, constitutes +/// undefined behavior and may break the assumptions made by the compiler. +/// +/// Switching to `ManuallyDrop` avoids both issues: /// /// ``` /// use std::mem::ManuallyDrop; @@ -80,24 +113,24 @@ pub use crate::intrinsics::transmute; /// // does not get dropped! /// let mut v = ManuallyDrop::new(v); /// // Now disassemble `v`. These operations cannot panic, so there cannot be a leak. -/// let ptr = v.as_mut_ptr(); -/// let cap = v.capacity(); +/// let (ptr, len, cap) = (v.as_mut_ptr(), v.len(), v.capacity()); /// // Finally, build a `String`. -/// let s = unsafe { String::from_raw_parts(ptr, 2, cap) }; +/// let s = unsafe { String::from_raw_parts(ptr, len, cap) }; /// assert_eq!(s, "Az"); /// // `s` is implicitly dropped and its memory deallocated. /// ``` /// -/// Using `ManuallyDrop` here has two advantages: +/// `ManuallyDrop` robustly prevents double-free because we disable `v`'s destructor +/// before doing anything else. `mem::forget()` doesn't allow this because it consumes its +/// argument, forcing us to call it only after extracting anything we need from `v`. Even +/// if a panic were introduced between construction of `ManuallyDrop` and building the +/// string (which cannot happen in the code as shown), it would result in a leak and not a +/// double free. In other words, `ManuallyDrop` errs on the side of leaking instead of +/// erring on the side of (double-)dropping. /// -/// * We do not "touch" `v` after disassembling it. For some types, operations -/// such as passing ownership (to a function like `mem::forget`) requires them to actually -/// be fully owned right now; that is a promise we do not want to make here as we are -/// in the process of transferring ownership to the new `String` we are building. -/// * In case of an unexpected panic, `ManuallyDrop` is not dropped, but if the panic -/// occurs before `mem::forget` was called we might end up dropping invalid data, -/// or double-dropping. In other words, `ManuallyDrop` errs on the side of leaking -/// instead of erring on the side of dropping. +/// Also, `ManuallyDrop` prevents us from having to "touch" `v` after transferring the +/// ownership to `s` - the final step of interacting with `v` to dispoe of it without +/// running its destructor is entirely avoided. /// /// [drop]: fn.drop.html /// [uninit]: fn.uninitialized.html diff --git a/src/libpanic_unwind/hermit.rs b/src/libpanic_unwind/hermit.rs index 6bded4dd499bd..69b9edb77c564 100644 --- a/src/libpanic_unwind/hermit.rs +++ b/src/libpanic_unwind/hermit.rs @@ -4,7 +4,6 @@ use alloc::boxed::Box; use core::any::Any; -use core::ptr; pub unsafe fn cleanup(_ptr: *mut u8) -> Box { extern "C" { diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index c9ad8707a7454..13d58ea73ac6b 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -381,6 +381,32 @@ impl<'tcx> Instance<'tcx> { Instance { def, substs } } + /// FIXME(#69925) Depending on the kind of `InstanceDef`, the MIR body associated with an + /// instance is expressed in terms of the generic parameters of `self.def_id()`, and in other + /// cases the MIR body is expressed in terms of the types found in the substitution array. + /// In the former case, we want to substitute those generic types and replace them with the + /// values from the substs when monomorphizing the function body. But in the latter case, we + /// don't want to do that substitution, since it has already been done effectively. + /// + /// This function returns `Some(substs)` in the former case and None otherwise -- i.e., if + /// this function returns `None`, then the MIR body does not require substitution during + /// monomorphization. + pub fn substs_for_mir_body(&self) -> Option> { + match self.def { + InstanceDef::CloneShim(..) + | InstanceDef::DropGlue(_, Some(_)) => None, + InstanceDef::ClosureOnceShim { .. } + | InstanceDef::DropGlue(..) + // FIXME(#69925): `FnPtrShim` should be in the other branch. + | InstanceDef::FnPtrShim(..) + | InstanceDef::Item(_) + | InstanceDef::Intrinsic(..) + | InstanceDef::ReifyShim(..) + | InstanceDef::Virtual(..) + | InstanceDef::VtableShim(..) => Some(self.substs), + } + } + pub fn is_vtable_shim(&self) -> bool { if let InstanceDef::VtableShim(..) = self.def { true } else { false } } diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 041dfc7d169a4..6d28796b34847 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -780,8 +780,8 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { present_first @ Some(_) => present_first, // Uninhabited because it has no variants, or only absent ones. None if def.is_enum() => return tcx.layout_raw(param_env.and(tcx.types.never)), - // if it's a struct, still compute a layout so that we can still compute the - // field offsets + // If it's a struct, still compute a layout so that we can still compute the + // field offsets. None => Some(VariantIdx::new(0)), }; @@ -1987,7 +1987,15 @@ where { fn for_variant(this: TyLayout<'tcx>, cx: &C, variant_index: VariantIdx) -> TyLayout<'tcx> { let details = match this.variants { - Variants::Single { index } if index == variant_index => this.details, + Variants::Single { index } + // If all variants but one are uninhabited, the variant layout is the enum layout. + if index == variant_index && + // Don't confuse variants of uninhabited enums with the enum itself. + // For more details see https://github.com/rust-lang/rust/issues/69763. + this.fields != FieldPlacement::Union(0) => + { + this.details + } Variants::Single { index } => { // Deny calling for_variant more than once for non-Single enums. diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs index 64ead19b35869..000db0155ada3 100644 --- a/src/librustc_codegen_ssa/mir/mod.rs +++ b/src/librustc_codegen_ssa/mir/mod.rs @@ -86,13 +86,18 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn monomorphize(&self, value: &T) -> T where - T: TypeFoldable<'tcx>, + T: Copy + TypeFoldable<'tcx>, { - self.cx.tcx().subst_and_normalize_erasing_regions( - self.instance.substs, - ty::ParamEnv::reveal_all(), - value, - ) + debug!("monomorphize: self.instance={:?}", self.instance); + if let Some(substs) = self.instance.substs_for_mir_body() { + self.cx.tcx().subst_and_normalize_erasing_regions( + substs, + ty::ParamEnv::reveal_all(), + &value, + ) + } else { + self.cx.tcx().normalize_erasing_regions(ty::ParamEnv::reveal_all(), *value) + } } } diff --git a/src/librustc_error_codes/error_codes/E0437.md b/src/librustc_error_codes/error_codes/E0437.md index 834cf33dbc7f0..0f924ba692064 100644 --- a/src/librustc_error_codes/error_codes/E0437.md +++ b/src/librustc_error_codes/error_codes/E0437.md @@ -1,7 +1,5 @@ -Trait implementations can only implement associated types that are members of -the trait in question. This error indicates that you attempted to implement -an associated type whose name does not match the name of any associated type -in the trait. +An associated type whose name does not match any of the associated types +in the trait was used when implementing the trait. Erroneous code example: @@ -13,6 +11,9 @@ impl Foo for i32 { } ``` +Trait implementations can only implement associated types that are members of +the trait in question. + The solution to this problem is to remove the extraneous associated type: ``` diff --git a/src/librustc_error_codes/error_codes/E0438.md b/src/librustc_error_codes/error_codes/E0438.md index cb141a5d24aed..13723bc30090e 100644 --- a/src/librustc_error_codes/error_codes/E0438.md +++ b/src/librustc_error_codes/error_codes/E0438.md @@ -1,7 +1,5 @@ -Trait implementations can only implement associated constants that are -members of the trait in question. This error indicates that you -attempted to implement an associated constant whose name does not -match the name of any associated constant in the trait. +An associated constant whose name does not match any of the associated constants +in the trait was used when implementing the trait. Erroneous code example: @@ -13,6 +11,9 @@ impl Foo for i32 { } ``` +Trait implementations can only implement associated constants that are +members of the trait in question. + The solution to this problem is to remove the extraneous associated constant: ``` diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 481719bfa8e63..68a893dc4be5d 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -335,15 +335,25 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Call this on things you got out of the MIR (so it is as generic as the current /// stack frame), to bring it into the proper environment for this interpreter. + pub(super) fn subst_from_current_frame_and_normalize_erasing_regions>( + &self, + value: T, + ) -> T { + self.subst_from_frame_and_normalize_erasing_regions(self.frame(), value) + } + + /// Call this on things you got out of the MIR (so it is as generic as the provided + /// stack frame), to bring it into the proper environment for this interpreter. pub(super) fn subst_from_frame_and_normalize_erasing_regions>( &self, + frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>, value: T, ) -> T { - self.tcx.subst_and_normalize_erasing_regions( - self.frame().instance.substs, - self.param_env, - &value, - ) + if let Some(substs) = frame.instance.substs_for_mir_body() { + self.tcx.subst_and_normalize_erasing_regions(substs, self.param_env, &value) + } else { + self.tcx.normalize_erasing_regions(self.param_env, value) + } } /// The `substs` are assumed to already be in our interpreter "universe" (param_env). @@ -371,11 +381,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { None => { let layout = crate::interpret::operand::from_known_layout(layout, || { let local_ty = frame.body.local_decls[local].ty; - let local_ty = self.tcx.subst_and_normalize_erasing_regions( - frame.instance.substs, - self.param_env, - &local_ty, - ); + let local_ty = + self.subst_from_frame_and_normalize_erasing_regions(frame, local_ty); self.layout_of(local_ty) })?; if let Some(state) = frame.locals.get(local) { diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 316cf2ee41918..b39058405f5cb 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -355,7 +355,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { let base = match op.try_as_mplace(self) { Ok(mplace) => { - // The easy case + // We can reuse the mplace field computation logic for indirect operands. let field = self.mplace_field(mplace, field)?; return Ok(field.into()); } @@ -490,7 +490,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Copy(ref place) | Move(ref place) => self.eval_place_to_op(place, layout)?, Constant(ref constant) => { - let val = self.subst_from_frame_and_normalize_erasing_regions(constant.literal); + let val = + self.subst_from_current_frame_and_normalize_erasing_regions(constant.literal); self.eval_const_to_op(val, layout)? } }; diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 107cfee5aceb5..5313446c253c8 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -410,14 +410,6 @@ where stride * field } layout::FieldPlacement::Union(count) => { - // This is a narrow bug-fix for rust-lang/rust#69191: if we are - // trying to access absent field of uninhabited variant, then - // signal UB (but don't ICE the compiler). - // FIXME temporary hack to work around incoherence between - // layout computation and MIR building - if field >= count as u64 && base.layout.abi == layout::Abi::Uninhabited { - throw_ub!(Unreachable); - } assert!( field < count as u64, "Tried to access field {} of union {:#?} with {} fields", @@ -648,9 +640,11 @@ where // bail out. None => Place::null(&*self), }, - layout: self.layout_of(self.subst_from_frame_and_normalize_erasing_regions( - self.frame().body.return_ty(), - ))?, + layout: self.layout_of( + self.subst_from_current_frame_and_normalize_erasing_regions( + self.frame().body.return_ty(), + ), + )?, } } local => PlaceTy { diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index f298a6677d6dc..cb11df18378d9 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -248,7 +248,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } NullaryOp(mir::NullOp::SizeOf, ty) => { - let ty = self.subst_from_frame_and_normalize_erasing_regions(ty); + let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty); let layout = self.layout_of(ty)?; assert!( !layout.is_unsized(), diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 51760500b03c9..4dd037d93ce9b 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -185,7 +185,7 @@ use rustc::mir::visit::Visitor as MirVisitor; use rustc::mir::{self, Local, Location}; use rustc::ty::adjustment::{CustomCoerceUnsized, PointerCast}; use rustc::ty::print::obsolete::DefPathBasedNames; -use rustc::ty::subst::{InternalSubsts, SubstsRef}; +use rustc::ty::subst::InternalSubsts; use rustc::ty::{self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::{par_iter, MTLock, MTRef, ParallelIterator}; @@ -493,7 +493,21 @@ struct MirNeighborCollector<'a, 'tcx> { tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, output: &'a mut Vec>, - param_substs: SubstsRef<'tcx>, + instance: Instance<'tcx>, +} + +impl<'a, 'tcx> MirNeighborCollector<'a, 'tcx> { + pub fn monomorphize(&self, value: T) -> T + where + T: TypeFoldable<'tcx>, + { + debug!("monomorphize: self.instance={:?}", self.instance); + if let Some(substs) = self.instance.substs_for_mir_body() { + self.tcx.subst_and_normalize_erasing_regions(substs, ty::ParamEnv::reveal_all(), &value) + } else { + self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), value) + } + } } impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { @@ -509,17 +523,9 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { ref operand, target_ty, ) => { - let target_ty = self.tcx.subst_and_normalize_erasing_regions( - self.param_substs, - ty::ParamEnv::reveal_all(), - &target_ty, - ); + let target_ty = self.monomorphize(target_ty); let source_ty = operand.ty(self.body, self.tcx); - let source_ty = self.tcx.subst_and_normalize_erasing_regions( - self.param_substs, - ty::ParamEnv::reveal_all(), - &source_ty, - ); + let source_ty = self.monomorphize(source_ty); let (source_ty, target_ty) = find_vtable_types_for_unsizing(self.tcx, source_ty, target_ty); // This could also be a different Unsize instruction, like @@ -540,11 +546,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { _, ) => { let fn_ty = operand.ty(self.body, self.tcx); - let fn_ty = self.tcx.subst_and_normalize_erasing_regions( - self.param_substs, - ty::ParamEnv::reveal_all(), - &fn_ty, - ); + let fn_ty = self.monomorphize(fn_ty); visit_fn_use(self.tcx, fn_ty, false, &mut self.output); } mir::Rvalue::Cast( @@ -553,11 +555,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { _, ) => { let source_ty = operand.ty(self.body, self.tcx); - let source_ty = self.tcx.subst_and_normalize_erasing_regions( - self.param_substs, - ty::ParamEnv::reveal_all(), - &source_ty, - ); + let source_ty = self.monomorphize(source_ty); match source_ty.kind { ty::Closure(def_id, substs) => { let instance = Instance::resolve_closure( @@ -593,7 +591,23 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, location: Location) { debug!("visiting const {:?} @ {:?}", *constant, location); - collect_const(self.tcx, *constant, self.param_substs, self.output); + let substituted_constant = self.monomorphize(*constant); + let param_env = ty::ParamEnv::reveal_all(); + + match substituted_constant.val { + ty::ConstKind::Value(val) => collect_const_value(self.tcx, val, self.output), + ty::ConstKind::Unevaluated(def_id, substs, promoted) => { + match self.tcx.const_eval_resolve(param_env, def_id, substs, promoted, None) { + Ok(val) => collect_const_value(self.tcx, val, self.output), + Err(ErrorHandled::Reported) => {} + Err(ErrorHandled::TooGeneric) => span_bug!( + self.tcx.def_span(def_id), + "collection encountered polymorphic constant", + ), + } + } + _ => {} + } self.super_const(constant); } @@ -605,21 +619,13 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { match *kind { mir::TerminatorKind::Call { ref func, .. } => { let callee_ty = func.ty(self.body, tcx); - let callee_ty = tcx.subst_and_normalize_erasing_regions( - self.param_substs, - ty::ParamEnv::reveal_all(), - &callee_ty, - ); + let callee_ty = self.monomorphize(callee_ty); visit_fn_use(self.tcx, callee_ty, true, &mut self.output); } mir::TerminatorKind::Drop { ref location, .. } | mir::TerminatorKind::DropAndReplace { ref location, .. } => { let ty = location.ty(self.body, self.tcx).ty; - let ty = tcx.subst_and_normalize_erasing_regions( - self.param_substs, - ty::ParamEnv::reveal_all(), - &ty, - ); + let ty = self.monomorphize(ty); visit_drop_use(self.tcx, ty, true, self.output); } mir::TerminatorKind::Goto { .. } @@ -1156,8 +1162,7 @@ fn collect_neighbours<'tcx>( debug!("collect_neighbours: {:?}", instance.def_id()); let body = tcx.instance_mir(instance.def); - MirNeighborCollector { tcx, body: &body, output, param_substs: instance.substs } - .visit_body(body); + MirNeighborCollector { tcx, body: &body, output, instance }.visit_body(body); } fn def_id_to_string(tcx: TyCtxt<'_>, def_id: DefId) -> String { @@ -1167,33 +1172,6 @@ fn def_id_to_string(tcx: TyCtxt<'_>, def_id: DefId) -> String { output } -fn collect_const<'tcx>( - tcx: TyCtxt<'tcx>, - constant: &'tcx ty::Const<'tcx>, - param_substs: SubstsRef<'tcx>, - output: &mut Vec>, -) { - debug!("visiting const {:?}", constant); - - let param_env = ty::ParamEnv::reveal_all(); - let substituted_constant = - tcx.subst_and_normalize_erasing_regions(param_substs, param_env, &constant); - - match substituted_constant.val { - ty::ConstKind::Value(val) => collect_const_value(tcx, val, output), - ty::ConstKind::Unevaluated(def_id, substs, promoted) => { - match tcx.const_eval_resolve(param_env, def_id, substs, promoted, None) { - Ok(val) => collect_const_value(tcx, val, output), - Err(ErrorHandled::Reported) => {} - Err(ErrorHandled::TooGeneric) => { - span_bug!(tcx.def_span(def_id), "collection encountered polymorphic constant",) - } - } - } - _ => {} - } -} - fn collect_const_value<'tcx>( tcx: TyCtxt<'tcx>, value: ConstValue<'tcx>, diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index 2f8bbd66c322b..afa30e7e632a7 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -660,7 +660,10 @@ impl FieldPlacement { pub fn offset(&self, i: usize) -> Size { match *self { - FieldPlacement::Union(_) => Size::ZERO, + FieldPlacement::Union(count) => { + assert!(i < count, "tried to access field {} of union with {} fields", i, count); + Size::ZERO + } FieldPlacement::Array { stride, count } => { let i = i as u64; assert!(i < count); diff --git a/src/libstd/env.rs b/src/libstd/env.rs index af35a5d9b7c47..6aad082a97f9a 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -723,8 +723,8 @@ pub struct ArgsOs { /// (such as `*` and `?`). On Windows this is not done, and such arguments are /// passed as-is. /// -/// On glibc Linux, arguments are retrieved by placing a function in .init_array. -/// glibc passes argc, argv, and envp to functions in .init_array, as a non-standard extension. +/// On glibc Linux systems, arguments are retrieved by placing a function in ".init_array". +/// Glibc passes argc, argv, and envp to functions in ".init_array", as a non-standard extension. /// This allows `std::env::args` to work even in a `cdylib` or `staticlib`, as it does on macOS /// and Windows. /// @@ -758,8 +758,8 @@ pub fn args() -> Args { /// set to arbitrary text, and it may not even exist, so this property should /// not be relied upon for security purposes. /// -/// On glibc Linux, arguments are retrieved by placing a function in .init_array. -/// glibc passes argc, argv, and envp to functions in .init_array, as a non-standard extension. +/// On glibc Linux systems, arguments are retrieved by placing a function in ".init_array". +/// Glibc passes argc, argv, and envp to functions in ".init_array", as a non-standard extension. /// This allows `std::env::args` to work even in a `cdylib` or `staticlib`, as it does on macOS /// and Windows. /// diff --git a/src/test/ui/type-alias-impl-trait/issue-55099-lifetime-inference.rs b/src/test/ui/type-alias-impl-trait/issue-55099-lifetime-inference.rs new file mode 100644 index 0000000000000..8e8508cdd6f30 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-55099-lifetime-inference.rs @@ -0,0 +1,28 @@ +// check-pass +// Regression test for issue #55099 +// Tests that we don't incorrectly consider a lifetime to part +// of the concrete type + +#![feature(type_alias_impl_trait)] + +trait Future { +} + +struct AndThen(F); + +impl Future for AndThen { +} + +struct Foo<'a> { + x: &'a mut (), +} + +type F = impl Future; + +impl<'a> Foo<'a> { + fn reply(&mut self) -> F { + AndThen(|| ()) + } +} + +fn main() {} diff --git a/triagebot.toml b/triagebot.toml index ec32771583334..2476f414e0e03 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -23,7 +23,7 @@ Thanks! <3 label = "ICEBreaker-LLVM" [ping.icebreakers-cleanup-crew] -alias = ["cleanup", "cleanups", "shrink", "reduce", "bisect"] +alias = ["cleanup", "cleanups", "cleanup-crew", "shrink", "reduce", "bisect"] message = """\ Hey Cleanup Crew ICE-breakers! This bug has been identified as a good "Cleanup ICE-breaking candidate". In case it's useful, here are some