From f7d745f33d950c050e0a5a2ee2ee9f0e1269e956 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 May 2020 13:22:45 +0200 Subject: [PATCH 01/42] tag/niche terminology cleanup --- .../debuginfo/metadata.rs | 105 +++++++++--------- src/librustc_codegen_ssa/mir/place.rs | 44 ++++---- src/librustc_lint/types.rs | 14 +-- src/librustc_middle/ty/layout.rs | 58 +++++----- src/librustc_mir/interpret/operand.rs | 27 ++--- src/librustc_mir/interpret/place.rs | 41 +++---- src/librustc_mir/interpret/step.rs | 4 +- src/librustc_mir/interpret/validity.rs | 4 +- src/librustc_target/abi/mod.rs | 27 +++-- src/test/ui/layout/debug.stderr | 12 +- 10 files changed, 167 insertions(+), 169 deletions(-) diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs index 0cce0b25e5893..01f630a31a18b 100644 --- a/src/librustc_codegen_llvm/debuginfo/metadata.rs +++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs @@ -1,4 +1,4 @@ -use self::EnumDiscriminantInfo::*; +use self::EnumTagInfo::*; use self::MemberDescriptionFactory::*; use self::RecursiveTypeDescription::*; @@ -40,7 +40,7 @@ use rustc_middle::{bug, span_bug}; use rustc_session::config::{self, DebugInfo}; use rustc_span::symbol::{Interner, Symbol}; use rustc_span::{self, SourceFile, SourceFileHash, Span}; -use rustc_target::abi::{Abi, Align, DiscriminantKind, HasDataLayout, Integer, LayoutOf}; +use rustc_target::abi::{Abi, Align, HasDataLayout, Integer, LayoutOf, TagEncoding}; use rustc_target::abi::{Int, Pointer, F32, F64}; use rustc_target::abi::{Primitive, Size, VariantIdx, Variants}; @@ -1335,7 +1335,7 @@ fn generator_layout_and_saved_local_names( struct EnumMemberDescriptionFactory<'ll, 'tcx> { enum_type: Ty<'tcx>, layout: TyAndLayout<'tcx>, - discriminant_type_metadata: Option<&'ll DIType>, + tag_type_metadata: Option<&'ll DIType>, containing_scope: &'ll DIScope, span: Span, } @@ -1385,7 +1385,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { cx, self.layout, variant_info, - NoDiscriminant, + NoTag, self_metadata, self.span, ); @@ -1409,19 +1409,19 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { }] } Variants::Multiple { - discr_kind: DiscriminantKind::Tag, - discr_index, + tag_encoding: TagEncoding::Direct, + tag_field, ref variants, .. } => { - let discriminant_info = if fallback { - RegularDiscriminant { - discr_field: Field::from(discr_index), - discr_type_metadata: self.discriminant_type_metadata.unwrap(), + let tag_info = if fallback { + RegularTag { + tag_field: Field::from(tag_field), + tag_type_metadata: self.tag_type_metadata.unwrap(), } } else { // This doesn't matter in this case. - NoDiscriminant + NoTag }; variants .iter_enumerated() @@ -1432,7 +1432,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { cx, variant, variant_info, - discriminant_info, + tag_info, self_metadata, self.span, ); @@ -1467,11 +1467,11 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { .collect() } Variants::Multiple { - discr_kind: - DiscriminantKind::Niche { ref niche_variants, niche_start, dataful_variant }, - ref discr, + tag_encoding: + TagEncoding::Niche { ref niche_variants, niche_start, dataful_variant }, + ref tag, ref variants, - discr_index, + tag_field, } => { if fallback { let variant = self.layout.for_variant(cx, dataful_variant); @@ -1480,7 +1480,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { cx, variant, variant_info_for(dataful_variant), - OptimizedDiscriminant, + OptimizedTag, self.containing_scope, self.span, ); @@ -1524,8 +1524,8 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { cx, &mut name, self.layout, - self.layout.fields.offset(discr_index), - self.layout.field(cx, discr_index).size, + self.layout.fields.offset(tag_field), + self.layout.field(cx, tag_field).size, ); variant_info_for(*niche_variants.start()).map_struct_name(|variant_name| { name.push_str(variant_name); @@ -1552,7 +1552,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { cx, variant, variant_info, - OptimizedDiscriminant, + OptimizedTag, self_metadata, self.span, ); @@ -1573,7 +1573,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { let value = (i.as_u32() as u128) .wrapping_sub(niche_variants.start().as_u32() as u128) .wrapping_add(niche_start); - let value = truncate(value, discr.value.size(cx)); + let value = truncate(value, tag.value.size(cx)); // NOTE(eddyb) do *NOT* remove this assert, until // we pass the full 128-bit value to LLVM, otherwise // truncation will be silent and remain undetected. @@ -1603,7 +1603,7 @@ struct VariantMemberDescriptionFactory<'ll, 'tcx> { /// Cloned from the `layout::Struct` describing the variant. offsets: Vec, args: Vec<(String, Ty<'tcx>)>, - discriminant_type_metadata: Option<&'ll DIType>, + tag_type_metadata: Option<&'ll DIType>, span: Span, } @@ -1617,7 +1617,7 @@ impl VariantMemberDescriptionFactory<'ll, 'tcx> { MemberDescription { name: name.to_string(), type_metadata: if use_enum_fallback(cx) { - match self.discriminant_type_metadata { + match self.tag_type_metadata { // Discriminant is always the first field of our variant // when using the enum fallback. Some(metadata) if i == 0 => metadata, @@ -1638,10 +1638,10 @@ impl VariantMemberDescriptionFactory<'ll, 'tcx> { } #[derive(Copy, Clone)] -enum EnumDiscriminantInfo<'ll> { - RegularDiscriminant { discr_field: Field, discr_type_metadata: &'ll DIType }, - OptimizedDiscriminant, - NoDiscriminant, +enum EnumTagInfo<'ll> { + RegularTag { tag_field: Field, tag_type_metadata: &'ll DIType }, + OptimizedTag, + NoTag, } #[derive(Copy, Clone)] @@ -1706,7 +1706,7 @@ fn describe_enum_variant( cx: &CodegenCx<'ll, 'tcx>, layout: layout::TyAndLayout<'tcx>, variant: VariantInfo<'_, 'tcx>, - discriminant_info: EnumDiscriminantInfo<'ll>, + discriminant_info: EnumTagInfo<'ll>, containing_scope: &'ll DIScope, span: Span, ) -> (&'ll DICompositeType, MemberDescriptionFactory<'ll, 'tcx>) { @@ -1722,12 +1722,12 @@ fn describe_enum_variant( let (offsets, args) = if use_enum_fallback(cx) { // If this is not a univariant enum, there is also the discriminant field. let (discr_offset, discr_arg) = match discriminant_info { - RegularDiscriminant { discr_field, .. } => { + RegularTag { tag_field, .. } => { // We have the layout of an enum variant, we need the layout of the outer enum let enum_layout = cx.layout_of(layout.ty); - let offset = enum_layout.fields.offset(discr_field.as_usize()); + let offset = enum_layout.fields.offset(tag_field.as_usize()); let args = - ("RUST$ENUM$DISR".to_owned(), enum_layout.field(cx, discr_field.as_usize()).ty); + ("RUST$ENUM$DISR".to_owned(), enum_layout.field(cx, tag_field.as_usize()).ty); (Some(offset), Some(args)) } _ => (None, None), @@ -1757,8 +1757,8 @@ fn describe_enum_variant( let member_description_factory = VariantMDF(VariantMemberDescriptionFactory { offsets, args, - discriminant_type_metadata: match discriminant_info { - RegularDiscriminant { discr_type_metadata, .. } => Some(discr_type_metadata), + tag_type_metadata: match discriminant_info { + RegularTag { tag_type_metadata, .. } => Some(tag_type_metadata), _ => None, }, span, @@ -1880,18 +1880,18 @@ fn prepare_enum_metadata( if let ( &Abi::Scalar(_), - &Variants::Multiple { discr_kind: DiscriminantKind::Tag, ref discr, .. }, + &Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. }, ) = (&layout.abi, &layout.variants) { - return FinalMetadata(discriminant_type_metadata(discr.value)); + return FinalMetadata(discriminant_type_metadata(tag.value)); } if use_enum_fallback(cx) { let discriminant_type_metadata = match layout.variants { Variants::Single { .. } - | Variants::Multiple { discr_kind: DiscriminantKind::Niche { .. }, .. } => None, - Variants::Multiple { discr_kind: DiscriminantKind::Tag, ref discr, .. } => { - Some(discriminant_type_metadata(discr.value)) + | Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, .. } => None, + Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. } => { + Some(discriminant_type_metadata(tag.value)) } }; @@ -1927,7 +1927,7 @@ fn prepare_enum_metadata( EnumMDF(EnumMemberDescriptionFactory { enum_type, layout, - discriminant_type_metadata, + tag_type_metadata: discriminant_type_metadata, containing_scope, span, }), @@ -1943,16 +1943,13 @@ fn prepare_enum_metadata( Variants::Single { .. } => None, Variants::Multiple { - discr_kind: DiscriminantKind::Niche { .. }, - ref discr, - discr_index, - .. + tag_encoding: TagEncoding::Niche { .. }, ref tag, tag_field, .. } => { // Find the integer type of the correct size. - let size = discr.value.size(cx); - let align = discr.value.align(cx); + let size = tag.value.size(cx); + let align = tag.value.align(cx); - let discr_type = match discr.value { + let tag_type = match tag.value { Int(t, _) => t, F32 => Integer::I32, F64 => Integer::I64, @@ -1960,7 +1957,7 @@ fn prepare_enum_metadata( } .to_ty(cx.tcx, false); - let discr_metadata = basic_type_metadata(cx, discr_type); + let tag_metadata = basic_type_metadata(cx, tag_type); unsafe { Some(llvm::LLVMRustDIBuilderCreateMemberType( DIB(cx), @@ -1971,17 +1968,15 @@ fn prepare_enum_metadata( UNKNOWN_LINE_NUMBER, size.bits(), align.abi.bits() as u32, - layout.fields.offset(discr_index).bits(), + layout.fields.offset(tag_field).bits(), DIFlags::FlagArtificial, - discr_metadata, + tag_metadata, )) } } - Variants::Multiple { - discr_kind: DiscriminantKind::Tag, ref discr, discr_index, .. - } => { - let discr_type = discr.value.to_ty(cx.tcx); + Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, tag_field, .. } => { + let discr_type = tag.value.to_ty(cx.tcx); let (size, align) = cx.size_and_align_of(discr_type); let discr_metadata = basic_type_metadata(cx, discr_type); @@ -1995,7 +1990,7 @@ fn prepare_enum_metadata( UNKNOWN_LINE_NUMBER, size.bits(), align.bits() as u32, - layout.fields.offset(discr_index).bits(), + layout.fields.offset(tag_field).bits(), DIFlags::FlagArtificial, discr_metadata, )) @@ -2081,7 +2076,7 @@ fn prepare_enum_metadata( EnumMDF(EnumMemberDescriptionFactory { enum_type, layout, - discriminant_type_metadata: None, + tag_type_metadata: None, containing_scope, span, }), diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs index 2be0679382900..0c8638b673d4f 100644 --- a/src/librustc_codegen_ssa/mir/place.rs +++ b/src/librustc_codegen_ssa/mir/place.rs @@ -10,7 +10,7 @@ use rustc_middle::mir; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::ty::layout::{HasTyCtxt, TyAndLayout}; use rustc_middle::ty::{self, Ty}; -use rustc_target::abi::{Abi, Align, DiscriminantKind, FieldsShape, Int}; +use rustc_target::abi::{Abi, Align, FieldsShape, Int, TagEncoding}; use rustc_target::abi::{LayoutOf, VariantIdx, Variants}; #[derive(Copy, Clone, Debug)] @@ -199,7 +199,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { if self.layout.abi.is_uninhabited() { return bx.cx().const_undef(cast_to); } - let (discr_scalar, discr_kind, discr_index) = match self.layout.variants { + let (tag_scalar, tag_encoding, tag_field) = match self.layout.variants { Variants::Single { index } => { let discr_val = self .layout @@ -208,33 +208,33 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { .map_or(index.as_u32() as u128, |discr| discr.val); return bx.cx().const_uint_big(cast_to, discr_val); } - Variants::Multiple { ref discr, ref discr_kind, discr_index, .. } => { - (discr, discr_kind, discr_index) + Variants::Multiple { ref tag, ref tag_encoding, tag_field, .. } => { + (tag, tag_encoding, tag_field) } }; // Read the tag/niche-encoded discriminant from memory. - let encoded_discr = self.project_field(bx, discr_index); - let encoded_discr = bx.load_operand(encoded_discr); + let tag = self.project_field(bx, tag_field); + let tag = bx.load_operand(tag); // Decode the discriminant (specifically if it's niche-encoded). - match *discr_kind { - DiscriminantKind::Tag => { - let signed = match discr_scalar.value { + match *tag_encoding { + TagEncoding::Direct => { + let signed = match tag_scalar.value { // We use `i1` for bytes that are always `0` or `1`, // e.g., `#[repr(i8)] enum E { A, B }`, but we can't // let LLVM interpret the `i1` as signed, because // then `i1 1` (i.e., `E::B`) is effectively `i8 -1`. - Int(_, signed) => !discr_scalar.is_bool() && signed, + Int(_, signed) => !tag_scalar.is_bool() && signed, _ => false, }; - bx.intcast(encoded_discr.immediate(), cast_to, signed) + bx.intcast(tag.immediate(), cast_to, signed) } - DiscriminantKind::Niche { dataful_variant, ref niche_variants, niche_start } => { + TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start } => { // Rebase from niche values to discriminants, and check // whether the result is in range for the niche variants. - let niche_llty = bx.cx().immediate_backend_type(encoded_discr.layout); - let encoded_discr = encoded_discr.immediate(); + let niche_llty = bx.cx().immediate_backend_type(tag.layout); + let tag = tag.immediate(); // We first compute the "relative discriminant" (wrt `niche_variants`), // that is, if `n = niche_variants.end() - niche_variants.start()`, @@ -248,9 +248,9 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { let relative_discr = if niche_start == 0 { // Avoid subtracting `0`, which wouldn't work for pointers. // FIXME(eddyb) check the actual primitive type here. - encoded_discr + tag } else { - bx.sub(encoded_discr, bx.cx().const_uint_big(niche_llty, niche_start)) + bx.sub(tag, bx.cx().const_uint_big(niche_llty, niche_start)) }; let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32(); let is_niche = { @@ -312,8 +312,8 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { Variants::Single { index } => { assert_eq!(index, variant_index); } - Variants::Multiple { discr_kind: DiscriminantKind::Tag, discr_index, .. } => { - let ptr = self.project_field(bx, discr_index); + Variants::Multiple { tag_encoding: TagEncoding::Direct, tag_field, .. } => { + let ptr = self.project_field(bx, tag_field); let to = self.layout.ty.discriminant_for_variant(bx.tcx(), variant_index).unwrap().val; bx.store( @@ -323,9 +323,9 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { ); } Variants::Multiple { - discr_kind: - DiscriminantKind::Niche { dataful_variant, ref niche_variants, niche_start }, - discr_index, + tag_encoding: + TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start }, + tag_field, .. } => { if variant_index != dataful_variant { @@ -339,7 +339,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { bx.memset(self.llval, fill_byte, size, self.align, MemFlags::empty()); } - let niche = self.project_field(bx, discr_index); + let niche = self.project_field(bx, tag_field); let niche_llty = bx.cx().immediate_backend_type(niche.layout); let niche_value = variant_index.as_u32() - niche_variants.start().as_u32(); let niche_value = (niche_value as u128).wrapping_add(niche_start); diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 703c2a7a443a9..6f4e2c69e339f 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -16,7 +16,7 @@ use rustc_middle::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt}; use rustc_span::source_map; use rustc_span::symbol::sym; use rustc_span::Span; -use rustc_target::abi::{DiscriminantKind, Integer, LayoutOf, VariantIdx, Variants}; +use rustc_target::abi::{Integer, LayoutOf, TagEncoding, VariantIdx, Variants}; use rustc_target::spec::abi::Abi; use log::debug; @@ -1036,15 +1036,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences { }; let (variants, tag) = match layout.variants { Variants::Multiple { - discr_kind: DiscriminantKind::Tag, - ref discr, + tag_encoding: TagEncoding::Direct, + ref tag, ref variants, .. - } => (variants, discr), + } => (variants, tag), _ => return, }; - let discr_size = tag.value.size(&cx.tcx).bytes(); + let tag_size = tag.value.size(&cx.tcx).bytes(); debug!( "enum `{}` is {} bytes large with layout:\n{:#?}", @@ -1058,8 +1058,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences { .iter() .zip(variants) .map(|(variant, variant_layout)| { - // Subtract the size of the enum discriminant. - let bytes = variant_layout.size.bytes().saturating_sub(discr_size); + // Subtract the size of the enum tag. + let bytes = variant_layout.size.bytes().saturating_sub(tag_size); debug!("- variant `{}` is {} bytes large", variant.ident, bytes); bytes diff --git a/src/librustc_middle/ty/layout.rs b/src/librustc_middle/ty/layout.rs index 5566e187c0c5c..fde2627e29dcb 100644 --- a/src/librustc_middle/ty/layout.rs +++ b/src/librustc_middle/ty/layout.rs @@ -975,13 +975,13 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { return Ok(tcx.intern_layout(Layout { variants: Variants::Multiple { - discr: niche_scalar, - discr_kind: DiscriminantKind::Niche { + tag: niche_scalar, + tag_encoding: TagEncoding::Niche { dataful_variant: i, niche_variants, niche_start, }, - discr_index: 0, + tag_field: 0, variants: st, }, fields: FieldsShape::Arbitrary { @@ -1217,9 +1217,9 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { tcx.intern_layout(Layout { variants: Variants::Multiple { - discr: tag, - discr_kind: DiscriminantKind::Tag, - discr_index: 0, + tag, + tag_encoding: TagEncoding::Direct, + tag_field: 0, variants: layout_variants, }, fields: FieldsShape::Arbitrary { @@ -1400,15 +1400,15 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // Build a prefix layout, including "promoting" all ineligible // locals as part of the prefix. We compute the layout of all of // these fields at once to get optimal packing. - let discr_index = substs.as_generator().prefix_tys().count(); + let tag_index = substs.as_generator().prefix_tys().count(); // `info.variant_fields` already accounts for the reserved variants, so no need to add them. let max_discr = (info.variant_fields.len() - 1) as u128; let discr_int = Integer::fit_unsigned(max_discr); let discr_int_ty = discr_int.to_ty(tcx, false); - let discr = Scalar { value: Primitive::Int(discr_int, false), valid_range: 0..=max_discr }; - let discr_layout = self.tcx.intern_layout(Layout::scalar(self, discr.clone())); - let discr_layout = TyAndLayout { ty: discr_int_ty, layout: discr_layout }; + let tag = Scalar { value: Primitive::Int(discr_int, false), valid_range: 0..=max_discr }; + let tag_layout = self.tcx.intern_layout(Layout::scalar(self, tag.clone())); + let tag_layout = TyAndLayout { ty: discr_int_ty, layout: tag_layout }; let promoted_layouts = ineligible_locals .iter() @@ -1419,7 +1419,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { .as_generator() .prefix_tys() .map(|ty| self.layout_of(ty)) - .chain(iter::once(Ok(discr_layout))) + .chain(iter::once(Ok(tag_layout))) .chain(promoted_layouts) .collect::, _>>()?; let prefix = self.univariant_uninterned( @@ -1442,7 +1442,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // "a" (`0..b_start`) and "b" (`b_start..`) correspond to // "outer" and "promoted" fields respectively. - let b_start = (discr_index + 1) as u32; + let b_start = (tag_index + 1) as u32; let offsets_b = offsets.split_off(b_start as usize); let offsets_a = offsets; @@ -1559,9 +1559,9 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { let layout = tcx.intern_layout(Layout { variants: Variants::Multiple { - discr, - discr_kind: DiscriminantKind::Tag, - discr_index, + tag: tag, + tag_encoding: TagEncoding::Direct, + tag_field: tag_index, variants, }, fields: outer_fields, @@ -1681,7 +1681,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { } } - Variants::Multiple { ref discr, ref discr_kind, .. } => { + Variants::Multiple { ref tag, ref tag_encoding, .. } => { debug!( "print-type-size `{:#?}` adt general variants def {}", layout.ty, @@ -1703,8 +1703,8 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { record( adt_kind.into(), adt_packed, - match discr_kind { - DiscriminantKind::Tag => Some(discr.value.size(self)), + match tag_encoding { + TagEncoding::Direct => Some(tag.value.size(self)), _ => None, }, variant_infos, @@ -2029,11 +2029,11 @@ where fn field(this: TyAndLayout<'tcx>, cx: &C, i: usize) -> C::TyAndLayout { let tcx = cx.tcx(); - let discr_layout = |discr: &Scalar| -> C::TyAndLayout { - let layout = Layout::scalar(cx, discr.clone()); + let tag_layout = |tag: &Scalar| -> C::TyAndLayout { + let layout = Layout::scalar(cx, tag.clone()); MaybeResult::from(Ok(TyAndLayout { layout: tcx.intern_layout(layout), - ty: discr.value.to_ty(tcx), + ty: tag.value.to_ty(tcx), })) }; @@ -2110,9 +2110,9 @@ where .unwrap() .nth(i) .unwrap(), - Variants::Multiple { ref discr, discr_index, .. } => { - if i == discr_index { - return discr_layout(discr); + Variants::Multiple { ref tag, tag_field, .. } => { + if i == tag_field { + return tag_layout(tag); } substs.as_generator().prefix_tys().nth(i).unwrap() } @@ -2129,9 +2129,9 @@ where Variants::Single { index } => def.variants[index].fields[i].ty(tcx, substs), // Discriminant field for enums (where applicable). - Variants::Multiple { ref discr, .. } => { + Variants::Multiple { ref tag, .. } => { assert_eq!(i, 0); - return discr_layout(discr); + return tag_layout(tag); } } } @@ -2208,10 +2208,10 @@ where // using more niches than just null (e.g., the first page of // the address space, or unaligned pointers). Variants::Multiple { - discr_kind: DiscriminantKind::Niche { dataful_variant, .. }, - discr_index, + tag_encoding: TagEncoding::Niche { dataful_variant, .. }, + tag_field, .. - } if this.fields.offset(discr_index) == offset => { + } if this.fields.offset(tag_field) == offset => { Some(this.for_variant(cx, dataful_variant)) } _ => Some(this), diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index db4473154c471..7da50eaa3e392 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -11,7 +11,7 @@ use rustc_middle::ty::layout::{PrimitiveExt, TyAndLayout}; use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Printer}; use rustc_middle::ty::Ty; use rustc_middle::{mir, ty}; -use rustc_target::abi::{Abi, DiscriminantKind, HasDataLayout, LayoutOf, Size}; +use rustc_target::abi::{Abi, TagEncoding, HasDataLayout, LayoutOf, Size}; use rustc_target::abi::{VariantIdx, Variants}; use super::{ @@ -587,7 +587,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { op: OpTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx, (Scalar, VariantIdx)> { trace!("read_discriminant_value {:#?}", op.layout); - // Get type and layout of the discriminant. let discr_layout = self.layout_of(op.layout.ty.discriminant_ty(*self.tcx))?; trace!("discriminant type: {:?}", discr_layout.ty); @@ -596,10 +595,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // This is not to be confused with its "variant index", which is just determining its position in the // declared list of variants -- they can differ with explicitly assigned discriminants. // We use "tag" to refer to how the discriminant is encoded in memory, which can be either - // straight-forward (`DiscriminantKind::Tag`) or with a niche (`DiscriminantKind::Niche`). - // Unfortunately, the rest of the compiler calls the latter "discriminant", too, which makes things - // rather confusing. - let (tag_scalar_layout, tag_kind, tag_index) = match op.layout.variants { + // straight-forward (`TagEncoding::Direct`) or with a niche (`TagEncoding::Niche`). + let (tag_scalar_layout, tag_encoding, tag_field) = match op.layout.variants { Variants::Single { index } => { let discr = match op.layout.ty.discriminant_for_variant(*self.tcx, index) { Some(discr) => { @@ -615,8 +612,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }; return Ok((discr, index)); } - Variants::Multiple { ref discr, ref discr_kind, discr_index, .. } => { - (discr, discr_kind, discr_index) + Variants::Multiple { ref tag, ref tag_encoding, tag_field, .. } => { + (tag, tag_encoding, tag_field) } }; @@ -633,21 +630,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let tag_layout = self.layout_of(tag_scalar_layout.value.to_int_ty(*self.tcx))?; // Read tag and sanity-check `tag_layout`. - let tag_val = self.read_immediate(self.operand_field(op, tag_index)?)?; + let tag_val = self.read_immediate(self.operand_field(op, tag_field)?)?; assert_eq!(tag_layout.size, tag_val.layout.size); assert_eq!(tag_layout.abi.is_signed(), tag_val.layout.abi.is_signed()); let tag_val = tag_val.to_scalar()?; trace!("tag value: {:?}", tag_val); // Figure out which discriminant and variant this corresponds to. - Ok(match *tag_kind { - DiscriminantKind::Tag => { + Ok(match *tag_encoding { + TagEncoding::Direct => { let tag_bits = self .force_bits(tag_val, tag_layout.size) .map_err(|_| err_ub!(InvalidDiscriminant(tag_val.erase_tag())))?; // Cast bits from tag layout to discriminant layout. - let discr_val_cast = self.cast_from_scalar(tag_bits, tag_layout, discr_layout.ty); - let discr_bits = discr_val_cast.assert_bits(discr_layout.size); + let discr_val = self.cast_from_scalar(tag_bits, tag_layout, discr_layout.ty); + let discr_bits = discr_val.assert_bits(discr_layout.size); // Convert discriminant to variant index, and catch invalid discriminants. let index = match op.layout.ty.kind { ty::Adt(adt, _) => { @@ -663,9 +660,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } .ok_or_else(|| err_ub!(InvalidDiscriminant(tag_val.erase_tag())))?; // Return the cast value, and the index. - (discr_val_cast, index.0) + (discr_val, index.0) } - DiscriminantKind::Niche { dataful_variant, ref niche_variants, niche_start } => { + TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start } => { // Compute the variant this niche value/"tag" corresponds to. With niche layout, // discriminant (encoded in niche/tag) and variant index are the same. let variants_start = niche_variants.start().as_u32(); diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 3f0800b12b549..1e6335c871e7c 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -9,7 +9,7 @@ use rustc_macros::HashStable; use rustc_middle::mir; use rustc_middle::ty::layout::{PrimitiveExt, TyAndLayout}; use rustc_middle::ty::{self, Ty}; -use rustc_target::abi::{Abi, Align, DiscriminantKind, FieldsShape}; +use rustc_target::abi::{Abi, Align, FieldsShape, TagEncoding}; use rustc_target::abi::{HasDataLayout, LayoutOf, Size, VariantIdx, Variants}; use super::{ @@ -1031,7 +1031,8 @@ where MPlaceTy { mplace, layout } } - pub fn write_discriminant_index( + /// Writes the discriminant of the given variant. + pub fn write_discriminant( &mut self, variant_index: VariantIdx, dest: PlaceTy<'tcx, M::PointerTag>, @@ -1047,9 +1048,9 @@ where assert_eq!(index, variant_index); } Variants::Multiple { - discr_kind: DiscriminantKind::Tag, - discr: ref discr_layout, - discr_index, + tag_encoding: TagEncoding::Direct, + tag: ref tag_layout, + tag_field, .. } => { // No need to validate that the discriminant here because the @@ -1061,17 +1062,17 @@ where // raw discriminants for enums are isize or bigger during // their computation, but the in-memory tag is the smallest possible // representation - let size = discr_layout.value.size(self); - let discr_val = truncate(discr_val, size); + let size = tag_layout.value.size(self); + let tag_val = truncate(discr_val, size); - let discr_dest = self.place_field(dest, discr_index)?; - self.write_scalar(Scalar::from_uint(discr_val, size), discr_dest)?; + let tag_dest = self.place_field(dest, tag_field)?; + self.write_scalar(Scalar::from_uint(tag_val, size), tag_dest)?; } Variants::Multiple { - discr_kind: - DiscriminantKind::Niche { dataful_variant, ref niche_variants, niche_start }, - discr: ref discr_layout, - discr_index, + tag_encoding: + TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start }, + tag: ref tag_layout, + tag_field, .. } => { // No need to validate that the discriminant here because the @@ -1084,19 +1085,19 @@ where .checked_sub(variants_start) .expect("overflow computing relative variant idx"); // We need to use machine arithmetic when taking into account `niche_start`: - // discr_val = variant_index_relative + niche_start_val - let discr_layout = self.layout_of(discr_layout.value.to_int_ty(*self.tcx))?; - let niche_start_val = ImmTy::from_uint(niche_start, discr_layout); + // tag_val = variant_index_relative + niche_start_val + let tag_layout = self.layout_of(tag_layout.value.to_int_ty(*self.tcx))?; + let niche_start_val = ImmTy::from_uint(niche_start, tag_layout); let variant_index_relative_val = - ImmTy::from_uint(variant_index_relative, discr_layout); - let discr_val = self.binary_op( + ImmTy::from_uint(variant_index_relative, tag_layout); + let tag_val = self.binary_op( mir::BinOp::Add, variant_index_relative_val, niche_start_val, )?; // Write result. - let niche_dest = self.place_field(dest, discr_index)?; - self.write_immediate(*discr_val, niche_dest)?; + let niche_dest = self.place_field(dest, tag_field)?; + self.write_immediate(*tag_val, niche_dest)?; } } } diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index bd4df788057e2..029b83492d593 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -89,7 +89,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { SetDiscriminant { place, variant_index } => { let dest = self.eval_place(**place)?; - self.write_discriminant_index(*variant_index, dest)?; + self.write_discriminant(*variant_index, dest)?; } // Mark locals as alive @@ -174,7 +174,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Aggregate(ref kind, ref operands) => { let (dest, active_field_index) = match **kind { mir::AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => { - self.write_discriminant_index(variant_index, dest)?; + self.write_discriminant(variant_index, dest)?; if adt_def.is_enum() { (self.place_downcast(dest, variant_index)?, active_field_index) } else { diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index e962dfb2b3e86..f21a96a979092 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -208,8 +208,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' fn aggregate_field_path_elem(&mut self, layout: TyAndLayout<'tcx>, field: usize) -> PathElem { // First, check if we are projecting to a variant. match layout.variants { - Variants::Multiple { discr_index, .. } => { - if discr_index == field { + Variants::Multiple { tag_field, .. } => { + if tag_field == field { return match layout.ty.kind { ty::Adt(def, ..) if def.is_enum() => PathElem::EnumTag, ty::Generator(..) => PathElem::GeneratorTag, diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index dcf181cb59f4a..c79e9bb289008 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -809,25 +809,30 @@ pub enum Variants { /// Single enum variants, structs/tuples, unions, and all non-ADTs. Single { index: VariantIdx }, - /// Enum-likes with more than one inhabited variant: for each case there is - /// a struct, and they all have space reserved for the discriminant. - /// For enums this is the sole field of the layout. + /// Enum-likes with more than one inhabited variant: each variant comes with + /// a *discriminant* (usually the same as the variant index but the user can + /// assign explicit discriminant values). That discriminant is encoded + /// as a *tag* on the machine. The layout of each variant is + /// a struct, and they all have space reserved for the tag. + /// For enums, the tag is the sole field of the layout. Multiple { - discr: Scalar, - discr_kind: DiscriminantKind, - discr_index: usize, + tag: Scalar, + tag_encoding: TagEncoding, + tag_field: usize, variants: IndexVec, }, } #[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)] -pub enum DiscriminantKind { - /// Integer tag holding the discriminant value itself. - Tag, +pub enum TagEncoding { + /// The tag directly stores the discriminant, but possibly with a smaller layout + /// (so converting the tag to the discriminant can require sign extension). + Direct, /// Niche (values invalid for a type) encoding the discriminant: - /// the variant `dataful_variant` contains a niche at an arbitrary - /// offset (field `discr_index` of the enum), which for a variant with + /// Discriminant and variant index coincide. + /// The variant `dataful_variant` contains a niche at an arbitrary + /// offset (field `tag_field` of the enum), which for a variant with /// discriminant `d` is set to /// `(d - niche_variants.start).wrapping_add(niche_start)`. /// diff --git a/src/test/ui/layout/debug.stderr b/src/test/ui/layout/debug.stderr index cd8ebdffb730b..1a371c6b17000 100644 --- a/src/test/ui/layout/debug.stderr +++ b/src/test/ui/layout/debug.stderr @@ -10,15 +10,15 @@ error: layout_of(E) = Layout { ], }, variants: Multiple { - discr: Scalar { + tag: Scalar { value: Int( I32, false, ), valid_range: 0..=0, }, - discr_kind: Tag, - discr_index: 0, + tag_encoding: Direct, + tag_field: 0, variants: [ Layout { fields: Arbitrary { @@ -202,15 +202,15 @@ error: layout_of(std::result::Result) = Layout { ], }, variants: Multiple { - discr: Scalar { + tag: Scalar { value: Int( I32, false, ), valid_range: 0..=1, }, - discr_kind: Tag, - discr_index: 0, + tag_encoding: Direct, + tag_field: 0, variants: [ Layout { fields: Arbitrary { From 7a6d03c2699787644b44f7bc3e8252d1508880b8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 May 2020 14:21:56 +0200 Subject: [PATCH 02/42] miri errors: rename InvalidDiscriminant -> InvalidTag --- src/librustc_middle/mir/interpret/error.rs | 6 +++--- src/librustc_mir/interpret/operand.rs | 8 ++++---- src/librustc_mir/interpret/validity.rs | 4 ++-- src/test/ui/consts/const-eval/double_check2.stderr | 2 +- src/test/ui/consts/const-eval/ub-enum.stderr | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/librustc_middle/mir/interpret/error.rs b/src/librustc_middle/mir/interpret/error.rs index fc588e049d7d8..6646aad6fc740 100644 --- a/src/librustc_middle/mir/interpret/error.rs +++ b/src/librustc_middle/mir/interpret/error.rs @@ -390,8 +390,8 @@ pub enum UndefinedBehaviorInfo<'tcx> { InvalidBool(u8), /// Using a non-character `u32` as character. InvalidChar(u32), - /// An enum discriminant was set to a value which was outside the range of valid values. - InvalidDiscriminant(Scalar), + /// The tag of an enum does not encode an actual discriminant. + InvalidTag(Scalar), /// Using a pointer-not-to-a-function as function pointer. InvalidFunctionPointer(Pointer), /// Using a string that is not valid UTF-8, @@ -463,7 +463,7 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> { InvalidChar(c) => { write!(f, "interpreting an invalid 32-bit value as a char: 0x{:08x}", c) } - InvalidDiscriminant(val) => write!(f, "enum value has invalid discriminant: {}", val), + InvalidTag(val) => write!(f, "enum value has invalid tag: {}", val), InvalidFunctionPointer(p) => { write!(f, "using {} as function pointer but it does not point to a function", p) } diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 7da50eaa3e392..fb08e83b76942 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -11,7 +11,7 @@ use rustc_middle::ty::layout::{PrimitiveExt, TyAndLayout}; use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Printer}; use rustc_middle::ty::Ty; use rustc_middle::{mir, ty}; -use rustc_target::abi::{Abi, TagEncoding, HasDataLayout, LayoutOf, Size}; +use rustc_target::abi::{Abi, HasDataLayout, LayoutOf, Size, TagEncoding}; use rustc_target::abi::{VariantIdx, Variants}; use super::{ @@ -641,7 +641,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { TagEncoding::Direct => { let tag_bits = self .force_bits(tag_val, tag_layout.size) - .map_err(|_| err_ub!(InvalidDiscriminant(tag_val.erase_tag())))?; + .map_err(|_| err_ub!(InvalidTag(tag_val.erase_tag())))?; // Cast bits from tag layout to discriminant layout. let discr_val = self.cast_from_scalar(tag_bits, tag_layout, discr_layout.ty); let discr_bits = discr_val.assert_bits(discr_layout.size); @@ -658,7 +658,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } _ => bug!("tagged layout for non-adt non-generator"), } - .ok_or_else(|| err_ub!(InvalidDiscriminant(tag_val.erase_tag())))?; + .ok_or_else(|| err_ub!(InvalidTag(tag_val.erase_tag())))?; // Return the cast value, and the index. (discr_val, index.0) } @@ -674,7 +674,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { && variants_start == variants_end && !self.memory.ptr_may_be_null(ptr); if !ptr_valid { - throw_ub!(InvalidDiscriminant(tag_val.erase_tag())) + throw_ub!(InvalidTag(tag_val.erase_tag())) } dataful_variant } diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index f21a96a979092..8dea811d8bcd4 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -696,8 +696,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> try_validation!( self.walk_value(op), self.path, - err_ub!(InvalidDiscriminant(val)) => - { "{}", val } expected { "a valid enum discriminant" }, + err_ub!(InvalidTag(val)) => + { "{}", val } expected { "a valid enum tag" }, err_unsup!(ReadPointerAsBytes) => { "a pointer" } expected { "plain (non-pointer) bytes" }, ); diff --git a/src/test/ui/consts/const-eval/double_check2.stderr b/src/test/ui/consts/const-eval/double_check2.stderr index 81fa5c0df13f6..93dd9a53ec99f 100644 --- a/src/test/ui/consts/const-eval/double_check2.stderr +++ b/src/test/ui/consts/const-eval/double_check2.stderr @@ -5,7 +5,7 @@ LL | / static FOO: (&Foo, &Bar) = unsafe {( LL | | Union { u8: &BAR }.foo, LL | | Union { u8: &BAR }.bar, LL | | )}; - | |___^ type validation failed: encountered 0x05 at .1., but expected a valid enum discriminant + | |___^ type validation failed: encountered 0x05 at .1., but expected a valid enum tag | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/src/test/ui/consts/const-eval/ub-enum.stderr b/src/test/ui/consts/const-eval/ub-enum.stderr index d8dafac3e70a1..d40073fb18fb0 100644 --- a/src/test/ui/consts/const-eval/ub-enum.stderr +++ b/src/test/ui/consts/const-eval/ub-enum.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:24:1 | LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x00000001, but expected a valid enum discriminant + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x00000001, but expected a valid enum tag | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -26,7 +26,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:42:1 | LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x00000000, but expected a valid enum discriminant + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x00000000, but expected a valid enum tag | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. From e9b67d281a3a1e740217ded7df9fc292f5ba6559 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 6 Jun 2020 18:26:15 +0100 Subject: [PATCH 03/42] Fix link error with #[thread_local] introduced by #71192 --- src/librustc_mir/monomorphize/collector.rs | 8 ++++++++ src/test/ui/tls.rs | 12 ++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 src/test/ui/tls.rs diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 297b899ef0bd6..e0e9bea5eb225 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -586,6 +586,14 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { self.output.push(create_fn_mono_item(instance)); } } + mir::Rvalue::ThreadLocalRef(def_id) => { + assert!(self.tcx.is_thread_local_static(def_id)); + let instance = Instance::mono(self.tcx, def_id); + if should_monomorphize_locally(self.tcx, &instance) { + trace!("collecting thread-local static {:?}", def_id); + self.output.push(MonoItem::Static(def_id)); + } + } _ => { /* not interesting */ } } diff --git a/src/test/ui/tls.rs b/src/test/ui/tls.rs new file mode 100644 index 0000000000000..cfc94c10c9e9b --- /dev/null +++ b/src/test/ui/tls.rs @@ -0,0 +1,12 @@ +// run-pass + +#![feature(thread_local)] + +#[thread_local] +static S: u32 = 222; + +fn main() { + let local = &S as *const u32 as usize; + let foreign = std::thread::spawn(|| &S as *const u32 as usize).join().unwrap(); + assert_ne!(local, foreign); +} From 5837518e78bf71172c4c86f14afd545fa38aa9e2 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sun, 7 Jun 2020 13:26:04 -0700 Subject: [PATCH 04/42] `-Zunpretty=everybody_loops` only works after expansion --- src/librustc_session/config.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc_session/config.rs b/src/librustc_session/config.rs index 5bdd7b67723b8..939d5e8ef8358 100644 --- a/src/librustc_session/config.rs +++ b/src/librustc_session/config.rs @@ -1954,9 +1954,11 @@ impl PpMode { use PpMode::*; use PpSourceMode::*; match *self { - PpmSource(PpmNormal | PpmEveryBodyLoops | PpmIdentified) => false, + PpmSource(PpmNormal | PpmIdentified) => false, - PpmSource(PpmExpanded | PpmExpandedIdentified | PpmExpandedHygiene) + PpmSource( + PpmExpanded | PpmEveryBodyLoops | PpmExpandedIdentified | PpmExpandedHygiene, + ) | PpmHir(_) | PpmHirTree(_) | PpmMir From d6848550393e9cebc734d5b8772b96c3a149a460 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sun, 7 Jun 2020 13:26:04 -0700 Subject: [PATCH 05/42] Helper method for whether `ast::Ty` contains `impl Trait` --- src/librustc_ast/ast.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/librustc_ast/ast.rs b/src/librustc_ast/ast.rs index efcf95ec706b8..8ae2e81fc5523 100644 --- a/src/librustc_ast/ast.rs +++ b/src/librustc_ast/ast.rs @@ -25,6 +25,7 @@ pub use UnsafeSource::*; use crate::ptr::P; use crate::token::{self, DelimToken}; use crate::tokenstream::{DelimSpan, TokenStream, TokenTree}; +use crate::visit::{walk_ty, Visitor}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::Lrc; @@ -1784,6 +1785,26 @@ pub struct Ty { pub span: Span, } +impl Ty { + /// Returns `true` if the kind of this type or any types contained within are `impl Trait`. + pub fn contains_impl_trait(&self) -> bool { + struct ContainsImplTrait(bool); + + impl<'ast> Visitor<'ast> for ContainsImplTrait { + fn visit_ty(&mut self, t: &'ast Ty) { + self.0 |= matches!(t.kind, TyKind::ImplTrait(..)); + if !self.0 { + walk_ty(self, t); + } + } + } + + let mut vis = ContainsImplTrait(false); + vis.visit_ty(self); + vis.0 + } +} + #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct BareFnTy { pub unsafety: Unsafe, From b5fdbbef4e03ab4fb88fcadbb8c370a1126419d9 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sun, 7 Jun 2020 13:26:04 -0700 Subject: [PATCH 06/42] Use correct names for things in `ReplaceBodyWithLoops` --- src/librustc_interface/util.rs | 130 +++++++++++---------------------- 1 file changed, 41 insertions(+), 89 deletions(-) diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs index 924908e572487..4d33383071e16 100644 --- a/src/librustc_interface/util.rs +++ b/src/librustc_interface/util.rs @@ -592,97 +592,48 @@ pub fn build_output_filenames( // // [#34511]: https://github.com/rust-lang/rust/issues/34511#issuecomment-322340401 pub struct ReplaceBodyWithLoop<'a, 'b> { - within_static_or_const: bool, + ignore_item: bool, nested_blocks: Option>, resolver: &'a mut Resolver<'b>, } impl<'a, 'b> ReplaceBodyWithLoop<'a, 'b> { pub fn new(resolver: &'a mut Resolver<'b>) -> ReplaceBodyWithLoop<'a, 'b> { - ReplaceBodyWithLoop { within_static_or_const: false, nested_blocks: None, resolver } + ReplaceBodyWithLoop { ignore_item: false, nested_blocks: None, resolver } } - fn run R>(&mut self, is_const: bool, action: F) -> R { - let old_const = mem::replace(&mut self.within_static_or_const, is_const); + fn run R>(&mut self, ignore_item: bool, action: F) -> R { + let old_ignore_item = mem::replace(&mut self.ignore_item, ignore_item); let old_blocks = self.nested_blocks.take(); let ret = action(self); - self.within_static_or_const = old_const; + self.ignore_item = old_ignore_item; self.nested_blocks = old_blocks; ret } - fn should_ignore_fn(ret_ty: &ast::FnRetTy) -> bool { - if let ast::FnRetTy::Ty(ref ty) = ret_ty { - fn involves_impl_trait(ty: &ast::Ty) -> bool { - match ty.kind { - ast::TyKind::ImplTrait(..) => true, - ast::TyKind::Slice(ref subty) - | ast::TyKind::Array(ref subty, _) - | ast::TyKind::Ptr(ast::MutTy { ty: ref subty, .. }) - | ast::TyKind::Rptr(_, ast::MutTy { ty: ref subty, .. }) - | ast::TyKind::Paren(ref subty) => involves_impl_trait(subty), - ast::TyKind::Tup(ref tys) => any_involves_impl_trait(tys.iter()), - ast::TyKind::Path(_, ref path) => { - path.segments.iter().any(|seg| match seg.args.as_deref() { - None => false, - Some(&ast::GenericArgs::AngleBracketed(ref data)) => { - data.args.iter().any(|arg| match arg { - ast::AngleBracketedArg::Arg(arg) => match arg { - ast::GenericArg::Type(ty) => involves_impl_trait(ty), - ast::GenericArg::Lifetime(_) - | ast::GenericArg::Const(_) => false, - }, - ast::AngleBracketedArg::Constraint(c) => match c.kind { - ast::AssocTyConstraintKind::Bound { .. } => true, - ast::AssocTyConstraintKind::Equality { ref ty } => { - involves_impl_trait(ty) - } - }, - }) - } - Some(&ast::GenericArgs::Parenthesized(ref data)) => { - any_involves_impl_trait(data.inputs.iter()) - || ReplaceBodyWithLoop::should_ignore_fn(&data.output) - } - }) - } - _ => false, - } - } - - fn any_involves_impl_trait<'a, I: Iterator>>(mut it: I) -> bool { - it.any(|subty| involves_impl_trait(subty)) - } - - involves_impl_trait(ty) - } else { - false - } - } - - fn is_sig_const(sig: &ast::FnSig) -> bool { + fn should_ignore_fn(sig: &ast::FnSig) -> bool { matches!(sig.header.constness, ast::Const::Yes(_)) - || ReplaceBodyWithLoop::should_ignore_fn(&sig.decl.output) + || matches!(&sig.decl.output, ast::FnRetTy::Ty(ty) if ty.contains_impl_trait()) } } impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> { fn visit_item_kind(&mut self, i: &mut ast::ItemKind) { - let is_const = match i { + let ignore_item = match i { ast::ItemKind::Static(..) | ast::ItemKind::Const(..) => true, - ast::ItemKind::Fn(_, ref sig, _, _) => Self::is_sig_const(sig), + ast::ItemKind::Fn(_, ref sig, _, _) => Self::should_ignore_fn(sig), _ => false, }; - self.run(is_const, |s| noop_visit_item_kind(i, s)) + self.run(ignore_item, |s| noop_visit_item_kind(i, s)) } fn flat_map_trait_item(&mut self, i: P) -> SmallVec<[P; 1]> { - let is_const = match i.kind { + let ignore_item = match i.kind { ast::AssocItemKind::Const(..) => true, - ast::AssocItemKind::Fn(_, ref sig, _, _) => Self::is_sig_const(sig), + ast::AssocItemKind::Fn(_, ref sig, _, _) => Self::should_ignore_fn(sig), _ => false, }; - self.run(is_const, |s| noop_flat_map_assoc_item(i, s)) + self.run(ignore_item, |s| noop_flat_map_assoc_item(i, s)) } fn flat_map_impl_item(&mut self, i: P) -> SmallVec<[P; 1]> { @@ -723,6 +674,11 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> { } } + if self.ignore_item { + noop_visit_block(b, self); + return; + } + let empty_block = stmt_to_block(BlockCheckMode::Default, None, self.resolver); let loop_expr = P(ast::Expr { kind: ast::ExprKind::Loop(P(empty_block), None), @@ -738,39 +694,35 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> { kind: ast::StmtKind::Expr(loop_expr), }; - if self.within_static_or_const { - noop_visit_block(b, self) - } else { - visit_clobber(b.deref_mut(), |b| { - let mut stmts = vec![]; - for s in b.stmts { - let old_blocks = self.nested_blocks.replace(vec![]); + visit_clobber(b.deref_mut(), |b| { + let mut stmts = vec![]; + for s in b.stmts { + let old_blocks = self.nested_blocks.replace(vec![]); - stmts.extend(self.flat_map_stmt(s).into_iter().filter(|s| s.is_item())); + stmts.extend(self.flat_map_stmt(s).into_iter().filter(|s| s.is_item())); - // we put a Some in there earlier with that replace(), so this is valid - let new_blocks = self.nested_blocks.take().unwrap(); - self.nested_blocks = old_blocks; - stmts.extend(new_blocks.into_iter().map(|b| block_to_stmt(b, self.resolver))); - } + // we put a Some in there earlier with that replace(), so this is valid + let new_blocks = self.nested_blocks.take().unwrap(); + self.nested_blocks = old_blocks; + stmts.extend(new_blocks.into_iter().map(|b| block_to_stmt(b, self.resolver))); + } - let mut new_block = ast::Block { stmts, ..b }; + let mut new_block = ast::Block { stmts, ..b }; - if let Some(old_blocks) = self.nested_blocks.as_mut() { - //push our fresh block onto the cache and yield an empty block with `loop {}` - if !new_block.stmts.is_empty() { - old_blocks.push(new_block); - } + if let Some(old_blocks) = self.nested_blocks.as_mut() { + //push our fresh block onto the cache and yield an empty block with `loop {}` + if !new_block.stmts.is_empty() { + old_blocks.push(new_block); + } - stmt_to_block(b.rules, Some(loop_stmt), &mut self.resolver) - } else { - //push `loop {}` onto the end of our fresh block and yield that - new_block.stmts.push(loop_stmt); + stmt_to_block(b.rules, Some(loop_stmt), &mut self.resolver) + } else { + //push `loop {}` onto the end of our fresh block and yield that + new_block.stmts.push(loop_stmt); - new_block - } - }) - } + new_block + } + }) } // in general the pretty printer processes unexpanded code, so From d8c99f3b1ab28ccadb3b56ba1fd506dce1385ee4 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sun, 7 Jun 2020 13:26:05 -0700 Subject: [PATCH 07/42] Preserve expressions that get a `DefId` Namely closures and `async` blocks. We have to make a few modifications to closures to make them compile. --- src/librustc_interface/util.rs | 83 +++++++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 1 deletion(-) diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs index 4d33383071e16..e446c8c0004c3 100644 --- a/src/librustc_interface/util.rs +++ b/src/librustc_interface/util.rs @@ -615,6 +615,12 @@ impl<'a, 'b> ReplaceBodyWithLoop<'a, 'b> { matches!(sig.header.constness, ast::Const::Yes(_)) || matches!(&sig.decl.output, ast::FnRetTy::Ty(ty) if ty.contains_impl_trait()) } + + /// Keep some `Expr`s that are ultimately assigned `DefId`s. This keeps the `HirId` parent + /// mappings correct even after this pass runs. + fn should_preserve_expr(e: &ast::Expr) -> bool { + matches!(&e.kind, ast::ExprKind::Closure(..) | ast::ExprKind::Async(..)) + } } impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> { @@ -644,6 +650,75 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> { self.run(true, |s| noop_visit_anon_const(c, s)) } + fn filter_map_expr(&mut self, mut e: P) -> Option> { + if self.ignore_item { + return noop_filter_map_expr(e, self); + } + + if let ast::ExprKind::Closure(.., decl, expr, _) = &mut e.kind { + // Replacing a closure body and removing its callsites will break inference. Give + // all closures the signature `|| -> !` to work around this. + decl.inputs = vec![]; + if let ast::FnRetTy::Default(_) = decl.output { + decl.output = ast::FnRetTy::Ty(P(ast::Ty { + id: self.resolver.next_node_id(), + span: rustc_span::DUMMY_SP, + kind: ast::TyKind::Never, + })); + } + + // Replace `|| expr` with `|| { expr }` so that `visit_block` gets called on the + // closure body. + if !matches!(expr.kind, ast::ExprKind::Block(..)) { + let new_stmt = ast::Stmt { + kind: ast::StmtKind::Expr(expr.clone()), + id: self.resolver.next_node_id(), + span: expr.span, + }; + + let new_block = ast::Block { + stmts: vec![new_stmt], + rules: BlockCheckMode::Default, + id: self.resolver.next_node_id(), + span: expr.span, + }; + + expr.kind = ast::ExprKind::Block(P(new_block), None); + } + } + + if Self::should_preserve_expr(&e) { + self.run(false, |s| noop_filter_map_expr(e, s)) + } else { + noop_filter_map_expr(e, self) + } + } + + fn flat_map_stmt(&mut self, s: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> { + if self.ignore_item { + return noop_flat_map_stmt(s, self); + } + + let ast::Stmt { id, span, .. } = s; + match s.kind { + // Replace `let x = || {};` with `|| {};` + ast::StmtKind::Local(mut local) if local.init.is_some() => self + .filter_map_expr(local.init.take().unwrap()) + .into_iter() + .map(|e| ast::Stmt { kind: ast::StmtKind::Semi(e), id, span }) + .collect(), + + // Replace `|| {}` with `|| {};` + ast::StmtKind::Expr(expr) => self + .filter_map_expr(expr) + .into_iter() + .map(|e| ast::Stmt { kind: ast::StmtKind::Semi(e), id, span }) + .collect(), + + _ => noop_flat_map_stmt(s, self), + } + } + fn visit_block(&mut self, b: &mut P) { fn stmt_to_block( rules: ast::BlockCheckMode, @@ -699,7 +774,13 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> { for s in b.stmts { let old_blocks = self.nested_blocks.replace(vec![]); - stmts.extend(self.flat_map_stmt(s).into_iter().filter(|s| s.is_item())); + stmts.extend(self.flat_map_stmt(s).into_iter().filter(|s| { + s.is_item() + || matches!( + &s.kind, + ast::StmtKind::Semi(expr) if Self::should_preserve_expr(expr) + ) + })); // we put a Some in there earlier with that replace(), so this is valid let new_blocks = self.nested_blocks.take().unwrap(); From 1a300427536883739ea30cc3e2c72409dadae4e1 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sun, 7 Jun 2020 15:03:24 -0700 Subject: [PATCH 08/42] Remove unnecessary `opt_local_def_id_to_hir_id` --- src/librustc_privacy/lib.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index cb896810951ba..87b15853a087c 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -943,11 +943,8 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> { let macro_module_def_id = ty::DefIdTree::parent(self.tcx, self.tcx.hir().local_def_id(md.hir_id).to_def_id()) .unwrap(); - // FIXME(#71104) Should really be using just `as_local_hir_id` but - // some `DefId` do not seem to have a corresponding HirId. - let hir_id = macro_module_def_id - .as_local() - .and_then(|def_id| self.tcx.hir().opt_local_def_id_to_hir_id(def_id)); + let hir_id = + macro_module_def_id.as_local().map(|def_id| self.tcx.hir().as_local_hir_id(def_id)); let mut module_id = match hir_id { Some(module_id) if self.tcx.hir().is_hir_id_module(module_id) => module_id, // `module_id` doesn't correspond to a `mod`, return early (#63164, #65252). From e319f203bd005282cf3eaefd577f35bd7cc1eecf Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sun, 7 Jun 2020 15:13:40 -0700 Subject: [PATCH 09/42] Add `rustdoc` tests from #72088 --- src/test/rustdoc/macro-in-async-block.rs | 9 +++++++++ src/test/rustdoc/macro-in-closure.rs | 7 +++++++ 2 files changed, 16 insertions(+) create mode 100644 src/test/rustdoc/macro-in-async-block.rs diff --git a/src/test/rustdoc/macro-in-async-block.rs b/src/test/rustdoc/macro-in-async-block.rs new file mode 100644 index 0000000000000..b4aaacf7b3d40 --- /dev/null +++ b/src/test/rustdoc/macro-in-async-block.rs @@ -0,0 +1,9 @@ +// Regression issue for rustdoc ICE encountered in PR #72088. +// edition:2018 +#![feature(decl_macro)] + +fn main() { + async { + macro m() {} + }; +} diff --git a/src/test/rustdoc/macro-in-closure.rs b/src/test/rustdoc/macro-in-closure.rs index 298ff601de89f..b4411d927e271 100644 --- a/src/test/rustdoc/macro-in-closure.rs +++ b/src/test/rustdoc/macro-in-closure.rs @@ -6,4 +6,11 @@ fn main() { || { macro m() {} }; + + let _ = || { + macro n() {} + }; + + let cond = true; + let _ = || if cond { macro n() {} } else { panic!() }; } From c920ae9e140b40280705baa70fa635929551c663 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 30 May 2020 17:03:32 +0100 Subject: [PATCH 10/42] Correctly handle binders inside trait predicates --- src/librustc_resolve/late/lifetimes.rs | 13 ++++++++----- .../ui/where-clauses/where-lifetime-resolution.rs | 1 - .../where-clauses/where-lifetime-resolution.stderr | 8 +------- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/librustc_resolve/late/lifetimes.rs b/src/librustc_resolve/late/lifetimes.rs index a3fbb28f22a56..0a39aa005bb97 100644 --- a/src/librustc_resolve/late/lifetimes.rs +++ b/src/librustc_resolve/late/lifetimes.rs @@ -908,7 +908,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { }) .collect(); if !lifetimes.is_empty() { - self.trait_ref_hack = true; let next_early_index = self.next_early_index(); let scope = Scope::Binder { lifetimes, @@ -920,9 +919,10 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { let result = self.with(scope, |old_scope, this| { this.check_lifetime_params(old_scope, &bound_generic_params); this.visit_ty(&bounded_ty); + this.trait_ref_hack = true; walk_list!(this, visit_param_bound, bounds); + this.trait_ref_hack = false; }); - self.trait_ref_hack = false; result } else { self.visit_ty(&bounded_ty); @@ -957,13 +957,15 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref); let should_pop_missing_lt = self.is_trait_ref_fn_scope(trait_ref); - if !self.trait_ref_hack + + let trait_ref_hack = take(&mut self.trait_ref_hack); + if !trait_ref_hack || trait_ref.bound_generic_params.iter().any(|param| match param.kind { GenericParamKind::Lifetime { .. } => true, _ => false, }) { - if self.trait_ref_hack { + if trait_ref_hack { struct_span_err!( self.tcx.sess, trait_ref.span, @@ -993,10 +995,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { this.check_lifetime_params(old_scope, &trait_ref.bound_generic_params); walk_list!(this, visit_generic_param, trait_ref.bound_generic_params); this.visit_trait_ref(&trait_ref.trait_ref); - }) + }); } else { self.visit_trait_ref(&trait_ref.trait_ref); } + self.trait_ref_hack = trait_ref_hack; if should_pop_missing_lt { self.missing_named_lifetime_spots.pop(); } diff --git a/src/test/ui/where-clauses/where-lifetime-resolution.rs b/src/test/ui/where-clauses/where-lifetime-resolution.rs index 0d426386768c8..d8677ee959abd 100644 --- a/src/test/ui/where-clauses/where-lifetime-resolution.rs +++ b/src/test/ui/where-clauses/where-lifetime-resolution.rs @@ -7,7 +7,6 @@ fn f() where //~^ ERROR use of undeclared lifetime name `'a` for<'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>, //~^ ERROR use of undeclared lifetime name `'b` - //~| ERROR nested quantification of lifetimes {} fn main() {} diff --git a/src/test/ui/where-clauses/where-lifetime-resolution.stderr b/src/test/ui/where-clauses/where-lifetime-resolution.stderr index 49799a93017eb..6c52664154bbf 100644 --- a/src/test/ui/where-clauses/where-lifetime-resolution.stderr +++ b/src/test/ui/where-clauses/where-lifetime-resolution.stderr @@ -7,12 +7,6 @@ LL | for<'a> dyn Trait1<'a>: Trait1<'a>, // OK LL | (dyn for<'a> Trait1<'a>): Trait1<'a>, | ^^ undeclared lifetime -error[E0316]: nested quantification of lifetimes - --> $DIR/where-lifetime-resolution.rs:8:17 - | -LL | for<'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>, - | ^^^^^^^^^^^^^^^^^^^^^^ - error[E0261]: use of undeclared lifetime name `'b` --> $DIR/where-lifetime-resolution.rs:8:52 | @@ -22,6 +16,6 @@ LL | fn f() where LL | for<'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>, | ^^ undeclared lifetime -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0261`. From d14ee0b5b921013b4516a55323d9b9ce655bf391 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 30 May 2020 17:19:31 +0100 Subject: [PATCH 11/42] Consider fewer predicates for projection candidates We now require that projection candidates are applicable with the idenitity substs of the trait, rather than allowing predicates that are only applicable for certain substs. --- src/librustc_middle/query/mod.rs | 7 ++ src/librustc_middle/ty/subst.rs | 11 ++ .../traits/project.rs | 21 ++-- .../traits/select/mod.rs | 50 ++++----- src/librustc_ty/ty.rs | 102 +++++++++++++++++- src/librustc_typeck/check/mod.rs | 2 +- .../hr-associated-type-bound-1.rs | 18 ++++ .../hr-associated-type-bound-1.stderr | 19 ++++ .../hr-associated-type-bound-2.rs | 21 ++++ .../hr-associated-type-bound-2.stderr | 13 +++ .../hr-associated-type-bound-object.rs | 14 +++ .../hr-associated-type-bound-object.stderr | 19 ++++ .../hr-associated-type-bound-param-1.rs | 20 ++++ .../hr-associated-type-bound-param-1.stderr | 19 ++++ .../hr-associated-type-bound-param-2.rs | 21 ++++ .../hr-associated-type-bound-param-2.stderr | 51 +++++++++ .../hr-associated-type-bound-param-3.rs | 21 ++++ .../hr-associated-type-bound-param-3.stderr | 19 ++++ .../hr-associated-type-bound-param-4.rs | 19 ++++ .../hr-associated-type-bound-param-4.stderr | 19 ++++ .../hr-associated-type-bound-param-5.rs | 41 +++++++ .../hr-associated-type-bound-param-5.stderr | 67 ++++++++++++ .../hr-associated-type-bound-param-6.rs | 20 ++++ .../hr-associated-type-bound-param-6.stderr | 36 +++++++ .../hr-associated-type-projection-1.rs | 21 ++++ .../hr-associated-type-projection-1.stderr | 30 ++++++ 26 files changed, 663 insertions(+), 38 deletions(-) create mode 100644 src/test/ui/associated-types/hr-associated-type-bound-1.rs create mode 100644 src/test/ui/associated-types/hr-associated-type-bound-1.stderr create mode 100644 src/test/ui/associated-types/hr-associated-type-bound-2.rs create mode 100644 src/test/ui/associated-types/hr-associated-type-bound-2.stderr create mode 100644 src/test/ui/associated-types/hr-associated-type-bound-object.rs create mode 100644 src/test/ui/associated-types/hr-associated-type-bound-object.stderr create mode 100644 src/test/ui/associated-types/hr-associated-type-bound-param-1.rs create mode 100644 src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr create mode 100644 src/test/ui/associated-types/hr-associated-type-bound-param-2.rs create mode 100644 src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr create mode 100644 src/test/ui/associated-types/hr-associated-type-bound-param-3.rs create mode 100644 src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr create mode 100644 src/test/ui/associated-types/hr-associated-type-bound-param-4.rs create mode 100644 src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr create mode 100644 src/test/ui/associated-types/hr-associated-type-bound-param-5.rs create mode 100644 src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr create mode 100644 src/test/ui/associated-types/hr-associated-type-bound-param-6.rs create mode 100644 src/test/ui/associated-types/hr-associated-type-bound-param-6.stderr create mode 100644 src/test/ui/associated-types/hr-associated-type-projection-1.rs create mode 100644 src/test/ui/associated-types/hr-associated-type-projection-1.stderr diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs index 4d7e7882e426c..e5f1a627bc48e 100644 --- a/src/librustc_middle/query/mod.rs +++ b/src/librustc_middle/query/mod.rs @@ -133,6 +133,13 @@ rustc_queries! { cache_on_disk_if { key.is_local() } } + /// Returns the list of predicates that can be used for + /// `SelectionCandidate::ProjectionCandidate` and + /// `ProjectionTyCandidate::TraitDef`. + query projection_predicates(key: DefId) -> &'tcx ty::List> { + desc { |tcx| "finding projection predicates for `{}`", tcx.def_path_str(key) } + } + query native_libraries(_: CrateNum) -> Lrc> { desc { "looking up the native libraries of a linked crate" } } diff --git a/src/librustc_middle/ty/subst.rs b/src/librustc_middle/ty/subst.rs index 1529f1173b391..0cbbb95fd6fef 100644 --- a/src/librustc_middle/ty/subst.rs +++ b/src/librustc_middle/ty/subst.rs @@ -333,6 +333,17 @@ impl<'a, 'tcx> InternalSubsts<'tcx> { /// in a different item, with `target_substs` as the base for /// the target impl/trait, with the source child-specific /// parameters (e.g., method parameters) on top of that base. + /// + /// For example given: + /// + /// trait X { fn f(); } + /// impl X for U { fn f() {} } + /// + /// * If `self` is `[Self, S, T]`: the identity substs of `f` in the trait. + /// * If `source_ancestor` is the def_id of the trait. + /// * If `target_substs` is `[U]`, the substs for the impl. + /// * Then we will return `[U, T]`, the subst for `f` in the impl that + /// are needed for it to match the trait. pub fn rebase_onto( &self, tcx: TyCtxt<'tcx>, diff --git a/src/librustc_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs index d6c79d1973a71..c55d7b5be2ded 100644 --- a/src/librustc_trait_selection/traits/project.rs +++ b/src/librustc_trait_selection/traits/project.rs @@ -895,9 +895,12 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( let tcx = selcx.tcx(); // Check whether the self-type is itself a projection. - let (def_id, substs) = match obligation_trait_ref.self_ty().kind { - ty::Projection(ref data) => (data.trait_ref(tcx).def_id, data.substs), - ty::Opaque(def_id, substs) => (def_id, substs), + // If so, extract what we know from the trait and try to come up with a good answer. + let bounds = match obligation_trait_ref.self_ty().kind { + ty::Projection(ref data) => { + tcx.projection_predicates(data.item_def_id).subst(tcx, data.substs) + } + ty::Opaque(def_id, substs) => tcx.projection_predicates(def_id).subst(tcx, substs), ty::Infer(ty::TyVar(_)) => { // If the self-type is an inference variable, then it MAY wind up // being a projected type, so induce an ambiguity. @@ -907,17 +910,13 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( _ => return, }; - // If so, extract what we know from the trait and try to come up with a good answer. - let trait_predicates = tcx.predicates_of(def_id); - let bounds = trait_predicates.instantiate(tcx, substs); - let bounds = elaborate_predicates(tcx, bounds.predicates.into_iter()).map(|o| o.predicate); assemble_candidates_from_predicates( selcx, obligation, obligation_trait_ref, candidate_set, ProjectionTyCandidate::TraitDef, - bounds, + bounds.iter(), ) } @@ -1474,6 +1473,12 @@ fn confirm_impl_candidate<'cx, 'tcx>( ); return Progress { ty: tcx.types.err, obligations: nested }; } + // If we're trying to normalize ` as X>::A` using + //`impl X for Vec { type A = Box; }`, then: + // + // * `obligation.predicate.substs` is `[Vec, S]` + // * `substs` is `[u32]` + // * `substs` ends up as `[u32, S]` let substs = obligation.predicate.substs.rebase_onto(tcx, trait_def_id, substs); let substs = translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.defining_node); diff --git a/src/librustc_trait_selection/traits/select/mod.rs b/src/librustc_trait_selection/traits/select/mod.rs index def99a7b5b528..da394ae528335 100644 --- a/src/librustc_trait_selection/traits/select/mod.rs +++ b/src/librustc_trait_selection/traits/select/mod.rs @@ -1265,9 +1265,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { placeholder_trait_predicate, ); - let (def_id, substs) = match placeholder_trait_predicate.trait_ref.self_ty().kind { - ty::Projection(ref data) => (data.trait_ref(self.tcx()).def_id, data.substs), - ty::Opaque(def_id, substs) => (def_id, substs), + let tcx = self.infcx.tcx; + let predicates = match placeholder_trait_predicate.trait_ref.self_ty().kind { + ty::Projection(ref data) => { + tcx.projection_predicates(data.item_def_id).subst(tcx, data.substs) + } + ty::Opaque(def_id, substs) => tcx.projection_predicates(def_id).subst(tcx, substs), _ => { span_bug!( obligation.cause.span, @@ -1277,32 +1280,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); } }; - debug!( - "match_projection_obligation_against_definition_bounds: \ - def_id={:?}, substs={:?}", - def_id, substs - ); - let predicates_of = self.tcx().predicates_of(def_id); - let bounds = predicates_of.instantiate(self.tcx(), substs); - debug!( - "match_projection_obligation_against_definition_bounds: \ - bounds={:?}", - bounds - ); - - let elaborated_predicates = - util::elaborate_predicates(self.tcx(), bounds.predicates.into_iter()); - let matching_bound = elaborated_predicates.filter_to_traits().find(|bound| { - self.infcx.probe(|_| { - self.match_projection( - obligation, - *bound, - placeholder_trait_predicate.trait_ref, - &placeholder_map, - snapshot, - ) - }) + let matching_bound = predicates.iter().find_map(|bound| { + if let ty::PredicateKind::Trait(bound, _) = bound.kind() { + let bound = bound.to_poly_trait_ref(); + if self.infcx.probe(|_| { + self.match_projection( + obligation, + bound, + placeholder_trait_predicate.trait_ref, + &placeholder_map, + snapshot, + ) + }) { + return Some(bound); + } + } + None }); debug!( diff --git a/src/librustc_ty/ty.rs b/src/librustc_ty/ty.rs index 3da5da2d9efb8..92d346054f5f4 100644 --- a/src/librustc_ty/ty.rs +++ b/src/librustc_ty/ty.rs @@ -1,8 +1,10 @@ use rustc_data_structures::svh::Svh; use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; +use rustc_infer::traits::util; use rustc_middle::hir::map as hir_map; -use rustc_middle::ty::subst::Subst; +use rustc_middle::ty::subst::{InternalSubsts, Subst}; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness}; use rustc_session::CrateDisambiguator; use rustc_span::symbol::Symbol; @@ -367,6 +369,103 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync { fn_like.asyncness() } +/// For associated types we allow bounds written on the associated type +/// (`type X: Trait`) to be used as candidates. We also allow the same bounds +/// when desugared as bounds on the trait `where Self::X: Trait`. +/// +/// Note that this filtering is done with the trait's identity substs to +/// simplify checking that these bounds are met in impls. This means that +/// a bound such as `for<'b> >::U: Clone` can't be used, as in +/// `hr-associated-type-bound-1.rs`. +fn associated_type_projection_predicates( + tcx: TyCtxt<'_>, + def_id: DefId, +) -> &'_ ty::List> { + let trait_id = tcx.associated_item(def_id).container.id(); + let trait_substs = InternalSubsts::identity_for_item(tcx, trait_id); + + let generic_trait_bounds = tcx.predicates_of(trait_id); + let trait_bounds = generic_trait_bounds.instantiate_identity(tcx); + let trait_predicates = util::elaborate_predicates(tcx, trait_bounds.predicates.into_iter()); + + let predicates = trait_predicates.filter_map(|obligation| { + let pred = obligation.predicate; + match pred.kind() { + ty::PredicateKind::Trait(tr, _) => { + if let ty::Projection(p) = tr.skip_binder().self_ty().kind { + if p.item_def_id == def_id && p.substs.starts_with(trait_substs) { + return Some(pred); + } + } + } + ty::PredicateKind::Projection(proj) => { + if let ty::Projection(p) = proj.skip_binder().projection_ty.self_ty().kind { + if p.item_def_id == def_id && p.substs.starts_with(trait_substs) { + return Some(pred); + } + } + } + _ => {} + } + None + }); + + let result = tcx.mk_predicates(predicates); + debug!("associated_type_projection_predicates({}) = {:?}", tcx.def_path_str(def_id), result); + result +} + +/// Opaque types might not have the same issues as associated types, but we use a +/// similar filtering for consistency. +fn opaque_type_projection_predicates( + tcx: TyCtxt<'_>, + def_id: DefId, +) -> &'_ ty::List> { + let substs = InternalSubsts::identity_for_item(tcx, def_id); + + let generics_bounds = tcx.predicates_of(def_id); + let bounds = generics_bounds.instantiate_identity(tcx); + let predicates = util::elaborate_predicates(tcx, bounds.predicates.into_iter()); + + let filtered_predicates = predicates.filter_map(|obligation| { + let pred = obligation.predicate; + match pred.kind() { + ty::PredicateKind::Trait(tr, _) => { + if let ty::Opaque(opaque_def_id, opaque_substs) = tr.skip_binder().self_ty().kind { + if opaque_def_id == def_id && opaque_substs == substs { + return Some(pred); + } + } + } + ty::PredicateKind::Projection(proj) => { + if let ty::Opaque(opaque_def_id, opaque_substs) = + proj.skip_binder().projection_ty.self_ty().kind + { + if opaque_def_id == def_id && opaque_substs == substs { + return Some(pred); + } + } + } + _ => {} + } + None + }); + + let result = tcx.mk_predicates(filtered_predicates); + debug!("opaque_type_projection_predicates({}) = {:?}", tcx.def_path_str(def_id), result); + result +} + +fn projection_predicates(tcx: TyCtxt<'_>, def_id: DefId) -> &'_ ty::List> { + match tcx.def_kind(def_id) { + DefKind::AssocTy => associated_type_projection_predicates(tcx, def_id), + DefKind::OpaqueTy | DefKind::AssocOpaqueTy => { + opaque_type_projection_predicates(tcx, def_id) + } + k => bug!("projection_predicates called on {}", k.descr(def_id)), + } +} + pub fn provide(providers: &mut ty::query::Providers<'_>) { *providers = ty::query::Providers { asyncness, @@ -383,6 +482,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) { instance_def_size_estimate, issue33140_self_ty, impl_defaultness, + projection_predicates, ..*providers }; } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index f2aeed4f1e465..0ed251a12ae4d 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2124,7 +2124,7 @@ fn check_impl_items_against_trait<'tcx>( &ty_trait_item, impl_trait_ref, opt_trait_span, - ) + ); } else { let mut err = struct_span_err!( tcx.sess, diff --git a/src/test/ui/associated-types/hr-associated-type-bound-1.rs b/src/test/ui/associated-types/hr-associated-type-bound-1.rs new file mode 100644 index 0000000000000..497b86eeab88d --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-1.rs @@ -0,0 +1,18 @@ +trait X<'a> +where + for<'b> >::U: Clone, +{ + type U: ?Sized; + fn f(&self, x: &Self::U) { + ::clone(x); + } +} + +impl X<'_> for i32 { + type U = str; + //~^ ERROR the trait bound `for<'b> >::U: std::clone::Clone` +} + +fn main() { + 1i32.f("abc"); +} diff --git a/src/test/ui/associated-types/hr-associated-type-bound-1.stderr b/src/test/ui/associated-types/hr-associated-type-bound-1.stderr new file mode 100644 index 0000000000000..7ef2faef9c6e7 --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-1.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `for<'b> >::U: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-1.rs:12:14 + | +LL | trait X<'a> + | - required by a bound in this +LL | where +LL | for<'b> >::U: Clone, + | ----- required by this bound in `X` +... +LL | type U = str; + | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `>::U` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/hr-associated-type-bound-2.rs b/src/test/ui/associated-types/hr-associated-type-bound-2.rs new file mode 100644 index 0000000000000..7ff0fede28cfe --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-2.rs @@ -0,0 +1,21 @@ +trait X<'a> +where + for<'b> >::U: Clone, +{ + type U: ?Sized; + fn f(&self, x: &Self::U) { + ::clone(x); + } +} + +impl X<'_> for u32 +where + for<'b> >::U: Clone, +{ + type U = str; +} + +fn main() { + 1u32.f("abc"); + //~^ ERROR no method named `f` found for type `u32` in the current scope +} diff --git a/src/test/ui/associated-types/hr-associated-type-bound-2.stderr b/src/test/ui/associated-types/hr-associated-type-bound-2.stderr new file mode 100644 index 0000000000000..2a364d349d77e --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-2.stderr @@ -0,0 +1,13 @@ +error[E0599]: no method named `f` found for type `u32` in the current scope + --> $DIR/hr-associated-type-bound-2.rs:19:10 + | +LL | 1u32.f("abc"); + | ^ method not found in `u32` + | + = note: the method `f` exists but the following trait bounds were not satisfied: + `>::U: std::clone::Clone` + which is required by `u32: X` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/associated-types/hr-associated-type-bound-object.rs b/src/test/ui/associated-types/hr-associated-type-bound-object.rs new file mode 100644 index 0000000000000..7c64ae38caf60 --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-object.rs @@ -0,0 +1,14 @@ +trait X<'a> +where + for<'b> >::U: Clone, +{ + type U: ?Sized; +} +fn f<'a, T: X<'a> + ?Sized>(x: &>::U) { + //~^ ERROR the trait bound `for<'b> >::U: std::clone::Clone` is not satisfied + <>::U>::clone(x); +} + +pub fn main() { + f::>("abc"); +} diff --git a/src/test/ui/associated-types/hr-associated-type-bound-object.stderr b/src/test/ui/associated-types/hr-associated-type-bound-object.stderr new file mode 100644 index 0000000000000..db966875c708f --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-object.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `for<'b> >::U: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-object.rs:7:13 + | +LL | trait X<'a> + | - required by a bound in this +LL | where +LL | for<'b> >::U: Clone, + | ----- required by this bound in `X` +... +LL | fn f<'a, T: X<'a> + ?Sized>(x: &>::U) { + | ^^^^^ the trait `for<'b> std::clone::Clone` is not implemented for `>::U` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-1.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-1.rs new file mode 100644 index 0000000000000..a65f8a8c498b7 --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-1.rs @@ -0,0 +1,20 @@ +trait Y<'a, T: ?Sized> +where + T: Y<'a, Self>, + for<'b> >::V: Clone, + for<'b> >::V: Clone, +{ + type V: ?Sized; + fn g(&self, x: &Self::V) { + ::clone(x); + } +} + +impl<'a> Y<'a, u8> for u8 { + type V = str; + //~^ ERROR the trait bound `for<'b> >::V: std::clone::Clone` is not satisfied +} + +fn main() { + 1u8.g("abc"); +} diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr new file mode 100644 index 0000000000000..347a5818dce31 --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `for<'b> >::V: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-1.rs:14:14 + | +LL | trait Y<'a, T: ?Sized> + | - required by a bound in this +... +LL | for<'b> >::V: Clone, + | ----- required by this bound in `Y` +... +LL | type V = str; + | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `>::V` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-2.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-2.rs new file mode 100644 index 0000000000000..9f849b0327669 --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-2.rs @@ -0,0 +1,21 @@ +trait Z<'a, T: ?Sized> +where + T: Z<'a, u16>, + //~^ the trait bound `for<'b> >::W: std::clone::Clone` is not satisfied + //~| the trait bound `for<'b> >::W: std::clone::Clone` is not satisfied + for<'b> >::W: Clone, +{ + type W: ?Sized; + fn h(&self, x: &T::W) { + ::clone(x); + } +} + +impl<'a> Z<'a, u16> for u16 { + type W = str; + //~^ ERROR the trait bound `for<'b> >::W: std::clone::Clone +} + +fn main() { + 1u16.h("abc"); +} diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr new file mode 100644 index 0000000000000..e06777e36a8c5 --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr @@ -0,0 +1,51 @@ +error[E0277]: the trait bound `for<'b> >::W: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-2.rs:3:8 + | +LL | trait Z<'a, T: ?Sized> + | - required by a bound in this +LL | where +LL | T: Z<'a, u16>, + | ^^^^^^^^^^ the trait `for<'b> std::clone::Clone` is not implemented for `>::W` +... +LL | for<'b> >::W: Clone, + | ----- required by this bound in `Z` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error[E0277]: the trait bound `for<'b> >::W: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-2.rs:15:14 + | +LL | trait Z<'a, T: ?Sized> + | - required by a bound in this +... +LL | for<'b> >::W: Clone, + | ----- required by this bound in `Z` +... +LL | type W = str; + | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `>::W` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error[E0277]: the trait bound `for<'b> >::W: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-2.rs:3:8 + | +LL | trait Z<'a, T: ?Sized> + | - required by a bound in this +LL | where +LL | T: Z<'a, u16>, + | ^^^^^^^^^^ the trait `for<'b> std::clone::Clone` is not implemented for `>::W` +... +LL | for<'b> >::W: Clone, + | ----- required by this bound in `Z` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-3.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-3.rs new file mode 100644 index 0000000000000..9aca59f8ce6d7 --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-3.rs @@ -0,0 +1,21 @@ +// ignore-tidy-linelength + +trait X<'a, T> +where + for<'b> T: X<'b, T>, + for<'b> >::U: Clone, +{ + type U: ?Sized; + fn f(x: &>::U) { + <>::U>::clone(x); + } +} + +impl X<'_, (T,)> for (S,) { + type U = str; + //~^ ERROR the trait bound `for<'b> <(T,) as X<'b, (T,)>>::U: std::clone::Clone` is not satisfied +} + +pub fn main() { + <(i32,) as X<(i32,)>>::f("abc"); +} diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr new file mode 100644 index 0000000000000..ff56f60e4c9e5 --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `for<'b> <(T,) as X<'b, (T,)>>::U: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-3.rs:15:14 + | +LL | trait X<'a, T> + | - required by a bound in this +... +LL | for<'b> >::U: Clone, + | ----- required by this bound in `X` +... +LL | type U = str; + | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<(T,) as X<'b, (T,)>>::U` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-4.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-4.rs new file mode 100644 index 0000000000000..ffe43c674c3dc --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-4.rs @@ -0,0 +1,19 @@ +trait X<'a, T> +where + for<'b> (T,): X<'b, T>, + for<'b> <(T,) as X<'b, T>>::U: Clone, +{ + type U: ?Sized; + fn f(x: &<(T,) as X<'_, T>>::U) { + <<(T,) as X<'_, T>>::U>::clone(x); + } +} + +impl X<'_, T> for (S,) { + type U = str; + //~^ ERROR the trait bound `for<'b> <(T,) as X<'b, T>>::U: std::clone::Clone` is not satisfied +} + +pub fn main() { + <(i32,) as X>::f("abc"); +} diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr new file mode 100644 index 0000000000000..c41efb8b6e1a2 --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `for<'b> <(T,) as X<'b, T>>::U: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-4.rs:13:14 + | +LL | trait X<'a, T> + | - required by a bound in this +... +LL | for<'b> <(T,) as X<'b, T>>::U: Clone, + | ----- required by this bound in `X` +... +LL | type U = str; + | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<(T,) as X<'b, T>>::U` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-5.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-5.rs new file mode 100644 index 0000000000000..dcca0b3ce92aa --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-5.rs @@ -0,0 +1,41 @@ +// ignore-tidy-linelength + +trait Cycle: Sized { + type Next: Cycle; +} + +impl Cycle for Box { + type Next = Vec; +} + +impl Cycle for Vec { + type Next = Box; +} + +trait X<'a, T: Cycle + for<'b> X<'b, T>> +where + for<'b> >::U: Clone, + for<'b> T::Next: X<'b, T::Next>, + for<'b> >::U: Clone, +{ + type U: ?Sized; + fn f(x: &>::U) { + <>::U>::clone(x); + } +} + +impl X<'_, Vec> for S { + type U = str; + //~^ ERROR the trait bound `for<'b> as X<'b, std::boxed::Box>>::U: std::clone::Clone` is not satisfied + //~| ERROR the trait bound `for<'b> as X<'b, std::vec::Vec>>::U: std::clone::Clone` is not satisfied +} + +impl X<'_, Box> for S { + type U = str; + //~^ ERROR the trait bound `for<'b> as X<'b, std::boxed::Box>>::U: std::clone::Clone` is not satisfied + //~| ERROR the trait bound `for<'b> as X<'b, std::vec::Vec>>::U: std::clone::Clone` is not satisfied +} + +pub fn main() { + >>::f("abc"); +} diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr new file mode 100644 index 0000000000000..39c191e974777 --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr @@ -0,0 +1,67 @@ +error[E0277]: the trait bound `for<'b> as X<'b, std::boxed::Box>>::U: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-5.rs:28:14 + | +LL | trait X<'a, T: Cycle + for<'b> X<'b, T>> + | - required by a bound in this +... +LL | for<'b> >::U: Clone, + | ----- required by this bound in `X` +... +LL | type U = str; + | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for ` as X<'b, std::boxed::Box>>::U` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error[E0277]: the trait bound `for<'b> as X<'b, std::vec::Vec>>::U: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-5.rs:28:14 + | +LL | trait X<'a, T: Cycle + for<'b> X<'b, T>> + | - required by a bound in this +LL | where +LL | for<'b> >::U: Clone, + | ----- required by this bound in `X` +... +LL | type U = str; + | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for ` as X<'b, std::vec::Vec>>::U` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error[E0277]: the trait bound `for<'b> as X<'b, std::vec::Vec>>::U: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-5.rs:34:14 + | +LL | trait X<'a, T: Cycle + for<'b> X<'b, T>> + | - required by a bound in this +... +LL | for<'b> >::U: Clone, + | ----- required by this bound in `X` +... +LL | type U = str; + | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for ` as X<'b, std::vec::Vec>>::U` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error[E0277]: the trait bound `for<'b> as X<'b, std::boxed::Box>>::U: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-5.rs:34:14 + | +LL | trait X<'a, T: Cycle + for<'b> X<'b, T>> + | - required by a bound in this +LL | where +LL | for<'b> >::U: Clone, + | ----- required by this bound in `X` +... +LL | type U = str; + | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for ` as X<'b, std::boxed::Box>>::U` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-6.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-6.rs new file mode 100644 index 0000000000000..4b8018cb43024 --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-6.rs @@ -0,0 +1,20 @@ +trait X<'a, T> +where + for<'b> T: X<'b, T>, + for<'b> >::U: Clone, +{ + type U: ?Sized; + fn f(x: &>::U) { + <>::U>::clone(x); + } +} + +impl X<'_, T> for (S,) { + //~^ ERROR the trait bound `for<'b> T: X<'b, T>` is not satisfied + type U = str; + //~^ ERROR the trait bound `for<'b> >::U: std::clone::Clone` is not satisfied +} + +pub fn main() { + <(i32,) as X>::f("abc"); +} diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-6.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-6.stderr new file mode 100644 index 0000000000000..83845d3a9410e --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-6.stderr @@ -0,0 +1,36 @@ +error[E0277]: the trait bound `for<'b> >::U: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-6.rs:14:14 + | +LL | trait X<'a, T> + | - required by a bound in this +... +LL | for<'b> >::U: Clone, + | ----- required by this bound in `X` +... +LL | type U = str; + | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `>::U` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error[E0277]: the trait bound `for<'b> T: X<'b, T>` is not satisfied + --> $DIR/hr-associated-type-bound-param-6.rs:12:12 + | +LL | trait X<'a, T> + | - required by a bound in this +LL | where +LL | for<'b> T: X<'b, T>, + | -------- required by this bound in `X` +... +LL | impl X<'_, T> for (S,) { + | ^^^^^^^^ the trait `for<'b> X<'b, T>` is not implemented for `T` + | +help: consider restricting type parameter `T` + | +LL | impl X<'b, T>> X<'_, T> for (S,) { + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/hr-associated-type-projection-1.rs b/src/test/ui/associated-types/hr-associated-type-projection-1.rs new file mode 100644 index 0000000000000..0d4567a55fc99 --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-projection-1.rs @@ -0,0 +1,21 @@ +trait UnsafeCopy<'a, T: Copy> +where + for<'b> >::Item: std::ops::Deref, +{ + type Item; + + fn bug(item: &Self::Item) -> () { + let x: T = **item; + &x as *const _; + } +} + +impl UnsafeCopy<'_, T> for T { + //~^ ERROR the trait bound `>::Item: std::ops::Deref` is not satisfied + type Item = T; + //~^ ERROR the trait bound `for<'b> >::Item: std::ops::Deref +} + +pub fn main() { + <&'static str>::bug(&""); +} diff --git a/src/test/ui/associated-types/hr-associated-type-projection-1.stderr b/src/test/ui/associated-types/hr-associated-type-projection-1.stderr new file mode 100644 index 0000000000000..5ab57410c441b --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-projection-1.stderr @@ -0,0 +1,30 @@ +error[E0277]: the trait bound `for<'b> >::Item: std::ops::Deref` is not satisfied + --> $DIR/hr-associated-type-projection-1.rs:15:17 + | +LL | trait UnsafeCopy<'a, T: Copy> + | ---------- required by a bound in this +LL | where +LL | for<'b> >::Item: std::ops::Deref, + | --------------------------- required by this bound in `UnsafeCopy` +... +LL | type Item = T; + | ^ the trait `for<'b> std::ops::Deref` is not implemented for `>::Item` + | + = help: the following implementations were found: + <&T as std::ops::Deref> + <&mut T as std::ops::Deref> + +error[E0277]: the trait bound `>::Item: std::ops::Deref` is not satisfied + --> $DIR/hr-associated-type-projection-1.rs:13:33 + | +LL | impl UnsafeCopy<'_, T> for T { + | ^^^^^^^^^^^^^^^^^ the trait `std::ops::Deref` is not implemented for `>::Item` + | +help: consider further restricting the associated type + | +LL | impl UnsafeCopy<'_, T> for T where >::Item: std::ops::Deref { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. From fb16ee78ae6fbe9be5bde77b1c8732b011afb7ac Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 30 May 2020 17:21:25 +0100 Subject: [PATCH 12/42] Check associated type satisfy their bounds This was currently only happening due to eager normalization, which isn't possible if there's specialization or bound variables. --- src/librustc_typeck/check/compare_method.rs | 158 +++++++++++++++++- .../issue-68641-check-gat-bounds.rs | 32 ++++ .../issue-68641-check-gat-bounds.stderr | 26 +++ .../issue-68642-broken-llvm-ir.rs | 21 +++ .../issue-68642-broken-llvm-ir.stderr | 28 ++++ .../issue-68643-broken-mir.rs | 21 +++ .../issue-68643-broken-mir.stderr | 28 ++++ .../issue-68644-codegen-selection.rs | 21 +++ .../issue-68644-codegen-selection.stderr | 28 ++++ .../issue-68645-codegen-fulfillment.rs | 21 +++ .../issue-68645-codegen-fulfillment.stderr | 28 ++++ .../issue-68656-unsized-values.rs | 22 +++ .../issue-68656-unsized-values.stderr | 30 ++++ src/test/ui/issues/issue-38091.rs | 2 +- src/test/ui/issues/issue-38091.stderr | 12 ++ .../deafult-associated-type-bound-1.rs | 23 +++ .../deafult-associated-type-bound-1.stderr | 12 ++ .../deafult-associated-type-bound-2.rs | 21 +++ .../deafult-associated-type-bound-2.stderr | 14 ++ .../deafult-generic-associated-type-bound.rs | 26 +++ ...afult-generic-associated-type-bound.stderr | 28 ++++ 21 files changed, 597 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.rs create mode 100644 src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr create mode 100644 src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.rs create mode 100644 src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr create mode 100644 src/test/ui/generic-associated-types/issue-68643-broken-mir.rs create mode 100644 src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr create mode 100644 src/test/ui/generic-associated-types/issue-68644-codegen-selection.rs create mode 100644 src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr create mode 100644 src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.rs create mode 100644 src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr create mode 100644 src/test/ui/generic-associated-types/issue-68656-unsized-values.rs create mode 100644 src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr create mode 100644 src/test/ui/issues/issue-38091.stderr create mode 100644 src/test/ui/specialization/deafult-associated-type-bound-1.rs create mode 100644 src/test/ui/specialization/deafult-associated-type-bound-1.stderr create mode 100644 src/test/ui/specialization/deafult-associated-type-bound-2.rs create mode 100644 src/test/ui/specialization/deafult-associated-type-bound-2.stderr create mode 100644 src/test/ui/specialization/deafult-generic-associated-type-bound.rs create mode 100644 src/test/ui/specialization/deafult-generic-associated-type-bound.stderr diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 29cd9681295be..2f3824c394bac 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -4,15 +4,17 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit; use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind}; use rustc_infer::infer::{self, InferOk, TyCtxtInferExt}; +use rustc_middle::ty; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::subst::{InternalSubsts, Subst}; +use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; use rustc_middle::ty::util::ExplicitSelf; -use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt}; +use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt, WithConstness}; use rustc_span::Span; use rustc_trait_selection::traits::error_reporting::InferCtxtExt; use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, Reveal}; use super::{potentially_plural_count, FnCtxt, Inherited}; +use std::iter; /// Checks that a method from an impl conforms to the signature of /// the same method as declared in the trait. @@ -1053,13 +1055,15 @@ crate fn compare_ty_impl<'tcx>( let _: Result<(), ErrorReported> = (|| { compare_number_of_generics(tcx, impl_ty, impl_ty_span, trait_ty, trait_item_span)?; - compare_type_predicate_entailment(tcx, impl_ty, impl_ty_span, trait_ty, impl_trait_ref) + compare_type_predicate_entailment(tcx, impl_ty, impl_ty_span, trait_ty, impl_trait_ref)?; + + compare_projection_bounds(tcx, trait_ty, impl_ty, impl_ty_span, impl_trait_ref) })(); } /// The equivalent of [compare_predicate_entailment], but for associated types /// instead of associated functions. -fn compare_type_predicate_entailment( +fn compare_type_predicate_entailment<'tcx>( tcx: TyCtxt<'tcx>, impl_ty: &ty::AssocItem, impl_ty_span: Span, @@ -1161,6 +1165,152 @@ fn compare_type_predicate_entailment( }) } +/// Validate that `ProjectionCandidate`s created for this associated type will +/// be valid. +/// +/// Usually given +/// +/// trait X { type Y: Copy } impl X for T { type Y = S; } +/// +/// We are able to normalize `::U` to `S`, and so when we check the +/// impl is well-formed we have to prove `S: Copy`. +/// +/// For default associated types the normalization is not possible (the value +/// from the impl could be overridden). We also can't normalize generic +/// associated types (yet) because they contain bound parameters. +fn compare_projection_bounds<'tcx>( + tcx: TyCtxt<'tcx>, + trait_ty: &ty::AssocItem, + impl_ty: &ty::AssocItem, + impl_ty_span: Span, + impl_trait_ref: ty::TraitRef<'tcx>, +) -> Result<(), ErrorReported> { + let is_gat = !tcx.generics_of(impl_ty.def_id).params.is_empty(); + if impl_ty.defaultness.is_final() && !is_gat { + // For "final", non-generic associate type implementations, we + // don't need this as described above. + return Ok(()); + } + + let param_env = tcx.param_env(impl_ty.def_id); + + let impl_substs = InternalSubsts::identity_for_item(tcx, impl_ty.container.id()); + let impl_ty_value = tcx.type_of(impl_ty.def_id); + + // Map the predicate from the trait to the corresponding one for the impl. + // For example: + // + // trait X { type Y<'a>: PartialEq } impl X for T { type Y<'a> = &'a S; } + // impl<'x> X<&'x u32> for () { type Y<'c> = &'c u32; } + // + // For the `for<'a> <>::Y<'a>: PartialEq` bound, this + // function would translate and partially normalize + // `[>::Y<'a>, A]` to `[&'a u32, &'x u32]`. + let translate_predicate_substs = move |predicate_substs: SubstsRef<'tcx>| { + let normalized_self = if !is_gat { + // projection_predicates only includes projections where the + // substs of the trait ref are exactly the trait's identity + // substs, so we can simply return the value from the impl. + impl_ty_value + } else { + let predicate_self_ty = predicate_substs.type_at(0); + let impl_ty_substs = if let ty::Projection(p) = predicate_self_ty.kind { + assert!( + p.item_def_id == trait_ty.def_id, + "projection_predicates returned predicate for the wrong type: {}", + predicate_self_ty, + ); + p.substs.rebase_onto(tcx, impl_trait_ref.def_id, impl_substs) + } else { + bug!( + "projection_predicates returned predicate for the wrong type `{}`", + predicate_self_ty, + ); + }; + impl_ty_value.subst(tcx, impl_ty_substs) + }; + + tcx.mk_substs( + iter::once(normalized_self.into()) + .chain(predicate_substs[1..].iter().map(|s| s.subst(tcx, impl_trait_ref.substs))), + ) + }; + + tcx.infer_ctxt().enter(move |infcx| { + let inh = Inherited::new(infcx, impl_ty.def_id.expect_local()); + let infcx = &inh.infcx; + let mut selcx = traits::SelectionContext::new(&infcx); + + let impl_ty_hir_id = tcx.hir().as_local_hir_id(impl_ty.def_id.expect_local()); + let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_hir_id); + let cause = ObligationCause { + span: impl_ty_span, + body_id: impl_ty_hir_id, + code: ObligationCauseCode::ItemObligation(impl_trait_ref.def_id), + }; + + let predicates = tcx.projection_predicates(trait_ty.def_id); + + debug!("compare_projection_bounds: projection_predicates={:?}", predicates); + + for predicate in predicates { + let concrete_ty_predicate = match predicate.kind() { + ty::PredicateKind::Trait(poly_tr, c) => poly_tr + .map_bound(|tr| { + let trait_substs = translate_predicate_substs(tr.trait_ref.substs); + ty::TraitRef { def_id: tr.def_id(), substs: trait_substs } + }) + .with_constness(*c) + .to_predicate(tcx), + ty::PredicateKind::Projection(poly_projection) => poly_projection + .map_bound(|projection| { + let projection_substs = + translate_predicate_substs(projection.projection_ty.substs); + ty::ProjectionPredicate { + projection_ty: ty::ProjectionTy { + substs: projection_substs, + item_def_id: projection.projection_ty.item_def_id, + }, + ty: projection.ty.subst(tcx, impl_trait_ref.substs), + } + }) + .to_predicate(tcx), + _ => bug!("unexepected projection predicate kind: `{:?}`", predicate), + }; + + let traits::Normalized { value: normalized_predicate, obligations } = traits::normalize( + &mut selcx, + param_env, + normalize_cause.clone(), + &concrete_ty_predicate, + ); + + debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate); + + inh.register_predicates(obligations); + inh.register_predicate(traits::Obligation::new( + cause.clone(), + param_env, + normalized_predicate, + )); + } + + // Check that all obligations are satisfied by the implementation's + // version. + if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) { + infcx.report_fulfillment_errors(errors, None, false); + return Err(ErrorReported); + } + + // Finally, resolve all regions. This catches wily misuses of + // lifetime parameters. + let fcx = FnCtxt::new(&inh, param_env, impl_ty_hir_id); + fcx.regionck_item(impl_ty_hir_id, impl_ty_span, &[]); + + Ok(()) + }) +} + fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str { match impl_item.kind { ty::AssocKind::Const => "const", diff --git a/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.rs b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.rs new file mode 100644 index 0000000000000..71f9b2967dc58 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.rs @@ -0,0 +1,32 @@ +// Regression test for #68641 + +#![feature(generic_associated_types)] +//~^ WARNING the feature `generic_associated_types` is incomplete and may not + +trait UnsafeCopy { + type Item<'a>: Copy; + + fn copy<'a>(item: &Self::Item<'a>) -> Self::Item<'a> { + *item + } +} + +impl UnsafeCopy for T { + type Item<'a> = T; + //~^ ERROR the trait bound `T: std::marker::Copy` is not satisfied +} + +fn main() { + let mut s = String::from("Hello world!"); + + let copy = String::copy(&s); + + // Do we indeed point to the samme memory? + assert!(s.as_ptr() == copy.as_ptr()); + + // Any use of `copy` is certeinly UB after this + drop(s); + + // UB UB UB UB UB!! + println!("{}", copy); +} diff --git a/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr new file mode 100644 index 0000000000000..eeff7c340ac96 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr @@ -0,0 +1,26 @@ +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-68641-check-gat-bounds.rs:3:12 + | +LL | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied + --> $DIR/issue-68641-check-gat-bounds.rs:15:5 + | +LL | trait UnsafeCopy { + | ---------------- required by `UnsafeCopy` +... +LL | type Item<'a> = T; + | ^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | +help: consider restricting type parameter `T` + | +LL | impl UnsafeCopy for T { + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.rs b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.rs new file mode 100644 index 0000000000000..c99073c13284d --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.rs @@ -0,0 +1,21 @@ +// Regression test for #68642 + +#![feature(generic_associated_types)] +//~^ WARNING the feature `generic_associated_types` is incomplete and may not + +trait Fun { + type F<'a>: Fn() -> u32; + + fn callme<'a>(f: Self::F<'a>) -> u32 { + f() + } +} + +impl Fun for T { + type F<'a> = Self; + //~^ ERROR expected a `std::ops::Fn<()>` closure, found `T` +} + +fn main() { + usize>::callme(|| 1); +} diff --git a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr new file mode 100644 index 0000000000000..b3d4b8d465180 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr @@ -0,0 +1,28 @@ +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-68642-broken-llvm-ir.rs:3:12 + | +LL | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error[E0277]: expected a `std::ops::Fn<()>` closure, found `T` + --> $DIR/issue-68642-broken-llvm-ir.rs:15:5 + | +LL | trait Fun { + | --------- required by `Fun` +... +LL | type F<'a> = Self; + | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T` + | + = help: the trait `std::ops::Fn<()>` is not implemented for `T` + = note: wrap the `T` in a closure with no arguments: `|| { /* code */ } +help: consider restricting type parameter `T` + | +LL | impl> Fun for T { + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/generic-associated-types/issue-68643-broken-mir.rs b/src/test/ui/generic-associated-types/issue-68643-broken-mir.rs new file mode 100644 index 0000000000000..24133e75cccee --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68643-broken-mir.rs @@ -0,0 +1,21 @@ +// Regression test for #68643 + +#![feature(generic_associated_types)] +//~^ WARNING the feature `generic_associated_types` is incomplete and may not + +trait Fun { + type F<'a>: Fn() -> u32; + + fn callme<'a>(f: Self::F<'a>) -> u32 { + f() + } +} + +impl Fun for T { + type F<'a> = Self; + //~^ ERROR expected a `std::ops::Fn<()>` closure, found `T` +} + +pub fn main() { + ::callme(|| {}); +} diff --git a/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr b/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr new file mode 100644 index 0000000000000..6e23fe02de8cd --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr @@ -0,0 +1,28 @@ +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-68643-broken-mir.rs:3:12 + | +LL | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error[E0277]: expected a `std::ops::Fn<()>` closure, found `T` + --> $DIR/issue-68643-broken-mir.rs:15:5 + | +LL | trait Fun { + | --------- required by `Fun` +... +LL | type F<'a> = Self; + | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T` + | + = help: the trait `std::ops::Fn<()>` is not implemented for `T` + = note: wrap the `T` in a closure with no arguments: `|| { /* code */ } +help: consider restricting type parameter `T` + | +LL | impl> Fun for T { + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.rs b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.rs new file mode 100644 index 0000000000000..22620c61b8390 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.rs @@ -0,0 +1,21 @@ +// Regression test for #68644 + +#![feature(generic_associated_types)] +//~^ WARNING the feature `generic_associated_types` is incomplete and may not + +trait Fun { + type F<'a>: Fn() -> u32; + + fn callme<'a>(f: Self::F<'a>) -> u32 { + f() + } +} + +impl Fun for T { + type F<'a> = Self; + //~^ ERROR expected a `std::ops::Fn<()>` closure, found `T` +} + +fn main() { + ::callme(0); +} diff --git a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr new file mode 100644 index 0000000000000..234f5c8a0cc02 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr @@ -0,0 +1,28 @@ +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-68644-codegen-selection.rs:3:12 + | +LL | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error[E0277]: expected a `std::ops::Fn<()>` closure, found `T` + --> $DIR/issue-68644-codegen-selection.rs:15:5 + | +LL | trait Fun { + | --------- required by `Fun` +... +LL | type F<'a> = Self; + | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T` + | + = help: the trait `std::ops::Fn<()>` is not implemented for `T` + = note: wrap the `T` in a closure with no arguments: `|| { /* code */ } +help: consider restricting type parameter `T` + | +LL | impl> Fun for T { + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.rs b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.rs new file mode 100644 index 0000000000000..423b80e8476f4 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.rs @@ -0,0 +1,21 @@ +// Regression test for #68645 + +#![feature(generic_associated_types)] +//~^ WARNING the feature `generic_associated_types` is incomplete and may not + +trait Fun { + type F<'a>: Fn() -> u32; + + fn callme<'a>(f: Self::F<'a>) -> u32 { + f() + } +} + +impl Fun for T { + type F<'a> = Self; + //~^ ERROR expected a `std::ops::Fn<()>` closure, found `T` +} + +fn main() { + <&dyn Iterator>::callme(&std::iter::once(1)); +} diff --git a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr new file mode 100644 index 0000000000000..ac2d5063fbb5d --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr @@ -0,0 +1,28 @@ +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-68645-codegen-fulfillment.rs:3:12 + | +LL | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error[E0277]: expected a `std::ops::Fn<()>` closure, found `T` + --> $DIR/issue-68645-codegen-fulfillment.rs:15:5 + | +LL | trait Fun { + | --------- required by `Fun` +... +LL | type F<'a> = Self; + | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T` + | + = help: the trait `std::ops::Fn<()>` is not implemented for `T` + = note: wrap the `T` in a closure with no arguments: `|| { /* code */ } +help: consider restricting type parameter `T` + | +LL | impl> Fun for T { + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/generic-associated-types/issue-68656-unsized-values.rs b/src/test/ui/generic-associated-types/issue-68656-unsized-values.rs new file mode 100644 index 0000000000000..4ccd42ba6432d --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68656-unsized-values.rs @@ -0,0 +1,22 @@ +// Regression test for #68656 + +#![feature(generic_associated_types)] +//~^ WARNING the feature `generic_associated_types` is incomplete and may not + +trait UnsafeCopy { + type Item<'a>: std::ops::Deref; + + fn bug<'a>(item: &Self::Item<'a>) -> () { + let x: T = **item; + &x as *const _; + } +} + +impl UnsafeCopy for T { + type Item<'a> = T; + //~^ ERROR type mismatch resolving `::Target == T` +} + +fn main() { + <&'static str>::bug(&""); +} diff --git a/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr b/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr new file mode 100644 index 0000000000000..e4eb7991f7637 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr @@ -0,0 +1,30 @@ +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-68656-unsized-values.rs:3:12 + | +LL | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error[E0271]: type mismatch resolving `::Target == T` + --> $DIR/issue-68656-unsized-values.rs:16:5 + | +LL | trait UnsafeCopy { + | ------------------------- required by `UnsafeCopy` +... +LL | impl UnsafeCopy for T { + | - this type parameter +LL | type Item<'a> = T; + | ^^^^^^^^^^^^^^^^^^ expected type parameter `T`, found associated type + | + = note: expected type parameter `T` + found associated type `::Target` +help: consider further restricting this bound + | +LL | impl> UnsafeCopy for T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/issues/issue-38091.rs b/src/test/ui/issues/issue-38091.rs index 00aa810f8308c..fcaf827ac63d4 100644 --- a/src/test/ui/issues/issue-38091.rs +++ b/src/test/ui/issues/issue-38091.rs @@ -1,4 +1,3 @@ -// run-pass #![feature(specialization)] trait Iterate<'a> { @@ -7,6 +6,7 @@ trait Iterate<'a> { } impl<'a, T> Iterate<'a> for T where T: Check { default type Ty = (); + //~^ ERROR the trait bound `(): Valid` is not satisfied default fn iterate(self) {} } diff --git a/src/test/ui/issues/issue-38091.stderr b/src/test/ui/issues/issue-38091.stderr new file mode 100644 index 0000000000000..55b74501ea184 --- /dev/null +++ b/src/test/ui/issues/issue-38091.stderr @@ -0,0 +1,12 @@ +error[E0277]: the trait bound `(): Valid` is not satisfied + --> $DIR/issue-38091.rs:8:5 + | +LL | trait Iterate<'a> { + | ----------------- required by `Iterate` +... +LL | default type Ty = (); + | ^^^^^^^^^^^^^^^^^^^^^ the trait `Valid` is not implemented for `()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/specialization/deafult-associated-type-bound-1.rs b/src/test/ui/specialization/deafult-associated-type-bound-1.rs new file mode 100644 index 0000000000000..5f7719c9e53e8 --- /dev/null +++ b/src/test/ui/specialization/deafult-associated-type-bound-1.rs @@ -0,0 +1,23 @@ +// Check that we check that default associated types satisfy the required +// bounds on them. + +#![feature(specialization)] + +trait X { + type U: Clone; + fn unsafe_clone(&self, x: Option<&Self::U>) { + x.cloned(); + } +} + +// We cannot normalize `::U` to `str` here, because the default could +// be overridden. The error here must therefore be found by a method other than +// normalization. +impl X for T { + default type U = str; + //~^ ERROR the trait bound `str: std::clone::Clone` is not satisfied +} + +pub fn main() { + 1.unsafe_clone(None); +} diff --git a/src/test/ui/specialization/deafult-associated-type-bound-1.stderr b/src/test/ui/specialization/deafult-associated-type-bound-1.stderr new file mode 100644 index 0000000000000..902ea81f3c9f1 --- /dev/null +++ b/src/test/ui/specialization/deafult-associated-type-bound-1.stderr @@ -0,0 +1,12 @@ +error[E0277]: the trait bound `str: std::clone::Clone` is not satisfied + --> $DIR/deafult-associated-type-bound-1.rs:17:5 + | +LL | trait X { + | ------- required by `X` +... +LL | default type U = str; + | ^^^^^^^^^^^^^^^^^^^^^ the trait `std::clone::Clone` is not implemented for `str` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/specialization/deafult-associated-type-bound-2.rs b/src/test/ui/specialization/deafult-associated-type-bound-2.rs new file mode 100644 index 0000000000000..9ea31f34c5cba --- /dev/null +++ b/src/test/ui/specialization/deafult-associated-type-bound-2.rs @@ -0,0 +1,21 @@ +// Check that generic predicates are also checked for default associated types. +#![feature(specialization)] + +trait X { + type U: PartialEq; + fn unsafe_compare(x: Option, y: Option) { + match (x, y) { + (Some(a), Some(b)) => a == b, + _ => false, + }; + } +} + +impl X for T { + default type U = &'static B; + //~^ ERROR can't compare `&'static B` with `B` +} + +pub fn main() { + >::unsafe_compare(None, None); +} diff --git a/src/test/ui/specialization/deafult-associated-type-bound-2.stderr b/src/test/ui/specialization/deafult-associated-type-bound-2.stderr new file mode 100644 index 0000000000000..3318e3b534141 --- /dev/null +++ b/src/test/ui/specialization/deafult-associated-type-bound-2.stderr @@ -0,0 +1,14 @@ +error[E0277]: can't compare `&'static B` with `B` + --> $DIR/deafult-associated-type-bound-2.rs:15:5 + | +LL | trait X { + | ---------- required by `X` +... +LL | default type U = &'static B; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `&'static B == B` + | + = help: the trait `std::cmp::PartialEq` is not implemented for `&'static B` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/specialization/deafult-generic-associated-type-bound.rs b/src/test/ui/specialization/deafult-generic-associated-type-bound.rs new file mode 100644 index 0000000000000..81ebfc4c9ca13 --- /dev/null +++ b/src/test/ui/specialization/deafult-generic-associated-type-bound.rs @@ -0,0 +1,26 @@ +// Check that default generics associated types are validated. + +#![feature(specialization)] +#![feature(generic_associated_types)] +//~^ WARNING the feature `generic_associated_types` is incomplete + +trait X { + type U<'a>: PartialEq<&'a Self>; + fn unsafe_compare<'b>(x: Option>, y: Option<&'b Self>) { + match (x, y) { + (Some(a), Some(b)) => a == b, + _ => false, + }; + } +} + +impl X for T { + default type U<'a> = &'a T; + //~^ ERROR can't compare `T` with `T` +} + +struct NotComparable; + +pub fn main() { + ::unsafe_compare(None, None); +} diff --git a/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr b/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr new file mode 100644 index 0000000000000..ccafa54d27776 --- /dev/null +++ b/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr @@ -0,0 +1,28 @@ +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/deafult-generic-associated-type-bound.rs:4:12 + | +LL | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error[E0277]: can't compare `T` with `T` + --> $DIR/deafult-generic-associated-type-bound.rs:18:5 + | +LL | trait X { + | ------- required by `X` +... +LL | default type U<'a> = &'a T; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `T == T` + | + = help: the trait `std::cmp::PartialEq` is not implemented for `T` + = note: required because of the requirements on the impl of `for<'a> std::cmp::PartialEq` for `&'a T` +help: consider further restricting this bound + | +LL | impl X for T { + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. From 373c7352c1a909cef56a15003428e0600e153599 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Wed, 10 Jun 2020 09:48:56 +0100 Subject: [PATCH 13/42] Don't set STILL_FURTHER_SPECIALIZABLE for regions/bound variables --- src/librustc_middle/ty/flags.rs | 2 -- src/librustc_middle/ty/sty.rs | 3 --- 2 files changed, 5 deletions(-) diff --git a/src/librustc_middle/ty/flags.rs b/src/librustc_middle/ty/flags.rs index edcb69c5e8cbd..994e824398c74 100644 --- a/src/librustc_middle/ty/flags.rs +++ b/src/librustc_middle/ty/flags.rs @@ -93,7 +93,6 @@ impl FlagComputation { &ty::Bound(debruijn, _) => { self.add_binder(debruijn); - self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE); } &ty::Placeholder(..) => { @@ -216,7 +215,6 @@ impl FlagComputation { } ty::ConstKind::Bound(debruijn, _) => { self.add_binder(debruijn); - self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE); } ty::ConstKind::Param(_) => { self.add_flags(TypeFlags::HAS_CT_PARAM); diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs index 5d4c2a54267c3..32713f487adc9 100644 --- a/src/librustc_middle/ty/sty.rs +++ b/src/librustc_middle/ty/sty.rs @@ -1583,19 +1583,16 @@ impl RegionKind { flags = flags | TypeFlags::HAS_FREE_REGIONS; flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; flags = flags | TypeFlags::HAS_RE_INFER; - flags = flags | TypeFlags::STILL_FURTHER_SPECIALIZABLE; } ty::RePlaceholder(..) => { flags = flags | TypeFlags::HAS_FREE_REGIONS; flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; flags = flags | TypeFlags::HAS_RE_PLACEHOLDER; - flags = flags | TypeFlags::STILL_FURTHER_SPECIALIZABLE; } ty::ReEarlyBound(..) => { flags = flags | TypeFlags::HAS_FREE_REGIONS; flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; flags = flags | TypeFlags::HAS_RE_PARAM; - flags = flags | TypeFlags::STILL_FURTHER_SPECIALIZABLE; } ty::ReFree { .. } => { flags = flags | TypeFlags::HAS_FREE_REGIONS; From 2af53e9a15aed1e9798867c9233a722530d03177 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 10 Jun 2020 22:11:17 +0100 Subject: [PATCH 14/42] Add -O compile flag to test --- src/test/ui/tls.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/ui/tls.rs b/src/test/ui/tls.rs index cfc94c10c9e9b..c696318e70f5f 100644 --- a/src/test/ui/tls.rs +++ b/src/test/ui/tls.rs @@ -1,4 +1,5 @@ // run-pass +// compile-flags: -O #![feature(thread_local)] From 83c5028301b3c28dd8a4db25a6a9b108680032bd Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Thu, 11 Jun 2020 16:50:34 +0100 Subject: [PATCH 15/42] Move bounds on associated types to the type Given `trait X { type U; }` the bound `::U` now lives on the type, rather than the trait. This is feature gated on `feature(generic_associated_types)` for now until more testing can be done. The also enabled type-generic associated types since we no longer need "implies bounds". --- src/librustc_infer/infer/outlives/verify.rs | 21 ++- src/librustc_infer/traits/mod.rs | 2 - src/librustc_middle/query/mod.rs | 10 ++ src/librustc_ty/ty.rs | 61 +++++--- src/librustc_typeck/check/compare_method.rs | 44 ++---- src/librustc_typeck/collect.rs | 130 +++++++----------- .../feature-gate-generic_associated_types.rs | 2 - ...ature-gate-generic_associated_types.stderr | 30 +--- .../collections-project-default.rs | 72 ++++++++++ .../collections-project-default.stderr | 15 ++ .../generic-associated-types/collections.rs | 33 ++--- .../collections.stderr | 19 --- .../construct_with_other_type.rs | 3 +- .../construct_with_other_type.stderr | 18 --- .../gat-dont-ice-on-absent-feature-2.rs | 1 - .../gat-dont-ice-on-absent-feature-2.stderr | 12 +- .../generic-associated-types-where.rs | 6 +- .../generic-associated-types-where.stderr | 30 ++-- .../issue-47206-where-clause.rs | 2 +- .../issue-47206-where-clause.stderr | 12 +- .../issue-62326-parameter-out-of-range.rs | 7 +- .../issue-62326-parameter-out-of-range.stderr | 10 -- .../generic-associated-types/issue-67424.rs | 1 - .../issue-67424.stderr | 10 +- .../issue-68641-check-gat-bounds.stderr | 4 +- .../issue-68642-broken-llvm-ir.stderr | 4 +- .../issue-68643-broken-mir.stderr | 4 +- .../issue-68644-codegen-selection.stderr | 4 +- .../issue-68645-codegen-fulfillment.stderr | 4 +- .../issue-68656-unsized-values.stderr | 4 +- .../ui/generic-associated-types/iterable.rs | 20 ++- .../generic-associated-types/iterable.stderr | 59 -------- .../missing-bounds.fixed | 5 +- .../missing-bounds.rs | 5 +- .../missing-bounds.stderr | 30 +--- .../parameter_number_and_kind.rs | 6 +- .../parameter_number_and_kind.stderr | 40 +----- .../pointer_family.rs | 3 +- .../pointer_family.stderr | 10 -- .../ui/generic-associated-types/shadowing.rs | 2 - .../generic-associated-types/shadowing.stderr | 20 +-- .../unsatisfied-outlives-bound.rs | 22 +++ .../unsatisfied-outlives-bound.stderr | 23 ++++ src/test/ui/issues/issue-38091.stderr | 4 +- .../deafult-associated-type-bound-1.stderr | 4 +- .../deafult-associated-type-bound-2.stderr | 4 +- ...afult-generic-associated-type-bound.stderr | 6 +- 47 files changed, 343 insertions(+), 495 deletions(-) create mode 100644 src/test/ui/generic-associated-types/collections-project-default.rs create mode 100644 src/test/ui/generic-associated-types/collections-project-default.stderr delete mode 100644 src/test/ui/generic-associated-types/collections.stderr delete mode 100644 src/test/ui/generic-associated-types/construct_with_other_type.stderr delete mode 100644 src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.stderr delete mode 100644 src/test/ui/generic-associated-types/iterable.stderr delete mode 100644 src/test/ui/generic-associated-types/pointer_family.stderr create mode 100644 src/test/ui/generic-associated-types/unsatisfied-outlives-bound.rs create mode 100644 src/test/ui/generic-associated-types/unsatisfied-outlives-bound.stderr diff --git a/src/librustc_infer/infer/outlives/verify.rs b/src/librustc_infer/infer/outlives/verify.rs index 82d32b008088d..383979f864075 100644 --- a/src/librustc_infer/infer/outlives/verify.rs +++ b/src/librustc_infer/infer/outlives/verify.rs @@ -1,9 +1,8 @@ use crate::infer::outlives::env::RegionBoundPairs; use crate::infer::{GenericKind, VerifyBound}; -use crate::traits; use rustc_data_structures::captures::Captures; use rustc_hir::def_id::DefId; -use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst}; +use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst}; use rustc_middle::ty::{self, Ty, TyCtxt}; /// The `TypeOutlives` struct has the job of "lowering" a `T: 'a` @@ -311,18 +310,14 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { fn region_bounds_declared_on_associated_item( &self, assoc_item_def_id: DefId, - ) -> impl Iterator> + 'cx + Captures<'tcx> { + ) -> impl Iterator> { let tcx = self.tcx; - let assoc_item = tcx.associated_item(assoc_item_def_id); - let trait_def_id = assoc_item.container.assert_trait(); - let trait_predicates = tcx.predicates_of(trait_def_id).predicates.iter().map(|(p, _)| *p); - let identity_substs = InternalSubsts::identity_for_item(tcx, assoc_item_def_id); - let identity_proj = tcx.mk_projection(assoc_item_def_id, identity_substs); - self.collect_outlives_from_predicate_list( - move |ty| ty == identity_proj, - traits::elaborate_predicates(tcx, trait_predicates).map(|o| o.predicate), - ) - .map(|b| b.1) + let predicates = tcx.projection_predicates(assoc_item_def_id); + predicates + .into_iter() + .filter_map(|p| p.to_opt_type_outlives()) + .filter_map(|p| p.no_bound_vars()) + .map(|b| b.1) } /// Searches through a predicate list for a predicate `T: 'a`. diff --git a/src/librustc_infer/traits/mod.rs b/src/librustc_infer/traits/mod.rs index c4f1fa2cb26b3..782b512da9724 100644 --- a/src/librustc_infer/traits/mod.rs +++ b/src/librustc_infer/traits/mod.rs @@ -25,8 +25,6 @@ pub use self::project::{ Normalized, NormalizedTy, ProjectionCache, ProjectionCacheEntry, ProjectionCacheKey, ProjectionCacheStorage, Reveal, }; -crate use self::util::elaborate_predicates; - pub use rustc_middle::traits::*; /// An `Obligation` represents some trait reference (e.g., `int: Eq`) for diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs index e5f1a627bc48e..a188fe0a728d7 100644 --- a/src/librustc_middle/query/mod.rs +++ b/src/librustc_middle/query/mod.rs @@ -136,6 +136,16 @@ rustc_queries! { /// Returns the list of predicates that can be used for /// `SelectionCandidate::ProjectionCandidate` and /// `ProjectionTyCandidate::TraitDef`. + /// Specifically this is the bounds (equivalent to) those + /// written on the trait's type definition, or those + /// after the `impl` keyword + /// + /// type X: Bound + 'lt + /// ^^^^^^^^^^^ + /// impl Debug + Display + /// ^^^^^^^^^^^^^^^ + /// + /// `key` is the `DefId` of the associated type or opaque type. query projection_predicates(key: DefId) -> &'tcx ty::List> { desc { |tcx| "finding projection predicates for `{}`", tcx.def_path_str(key) } } diff --git a/src/librustc_ty/ty.rs b/src/librustc_ty/ty.rs index 92d346054f5f4..31654bd90d4f2 100644 --- a/src/librustc_ty/ty.rs +++ b/src/librustc_ty/ty.rs @@ -373,34 +373,45 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync { /// (`type X: Trait`) to be used as candidates. We also allow the same bounds /// when desugared as bounds on the trait `where Self::X: Trait`. /// -/// Note that this filtering is done with the trait's identity substs to +/// Note that this filtering is done with the items identity substs to /// simplify checking that these bounds are met in impls. This means that /// a bound such as `for<'b> >::U: Clone` can't be used, as in /// `hr-associated-type-bound-1.rs`. fn associated_type_projection_predicates( tcx: TyCtxt<'_>, - def_id: DefId, + assoc_item_def_id: DefId, ) -> &'_ ty::List> { - let trait_id = tcx.associated_item(def_id).container.id(); - let trait_substs = InternalSubsts::identity_for_item(tcx, trait_id); - - let generic_trait_bounds = tcx.predicates_of(trait_id); - let trait_bounds = generic_trait_bounds.instantiate_identity(tcx); - let trait_predicates = util::elaborate_predicates(tcx, trait_bounds.predicates.into_iter()); + let generic_trait_bounds = tcx.predicates_of(assoc_item_def_id); + // We include predicates from the trait as well to handle + // `where Self::X: Trait`. + let item_bounds = generic_trait_bounds.instantiate_identity(tcx); + let item_predicates = util::elaborate_predicates(tcx, item_bounds.predicates.into_iter()); + + let assoc_item_ty = ty::ProjectionTy { + item_def_id: assoc_item_def_id, + substs: InternalSubsts::identity_for_item(tcx, assoc_item_def_id), + }; - let predicates = trait_predicates.filter_map(|obligation| { + let predicates = item_predicates.filter_map(|obligation| { let pred = obligation.predicate; match pred.kind() { ty::PredicateKind::Trait(tr, _) => { if let ty::Projection(p) = tr.skip_binder().self_ty().kind { - if p.item_def_id == def_id && p.substs.starts_with(trait_substs) { + if p == assoc_item_ty { return Some(pred); } } } ty::PredicateKind::Projection(proj) => { if let ty::Projection(p) = proj.skip_binder().projection_ty.self_ty().kind { - if p.item_def_id == def_id && p.substs.starts_with(trait_substs) { + if p == assoc_item_ty { + return Some(pred); + } + } + } + ty::PredicateKind::TypeOutlives(outlives) => { + if let ty::Projection(p) = outlives.skip_binder().0.kind { + if p == assoc_item_ty { return Some(pred); } } @@ -411,11 +422,15 @@ fn associated_type_projection_predicates( }); let result = tcx.mk_predicates(predicates); - debug!("associated_type_projection_predicates({}) = {:?}", tcx.def_path_str(def_id), result); + debug!( + "associated_type_projection_predicates({}) = {:?}", + tcx.def_path_str(assoc_item_def_id), + result + ); result } -/// Opaque types might not have the same issues as associated types, but we use a +/// Opaque types don't have the same issues as associated types, but we use a /// similar filtering for consistency. fn opaque_type_projection_predicates( tcx: TyCtxt<'_>, @@ -423,9 +438,9 @@ fn opaque_type_projection_predicates( ) -> &'_ ty::List> { let substs = InternalSubsts::identity_for_item(tcx, def_id); - let generics_bounds = tcx.predicates_of(def_id); - let bounds = generics_bounds.instantiate_identity(tcx); - let predicates = util::elaborate_predicates(tcx, bounds.predicates.into_iter()); + let bounds = tcx.predicates_of(def_id); + let predicates = + util::elaborate_predicates(tcx, bounds.predicates.into_iter().map(|&(pred, _)| pred)); let filtered_predicates = predicates.filter_map(|obligation| { let pred = obligation.predicate; @@ -446,8 +461,22 @@ fn opaque_type_projection_predicates( } } } + ty::PredicateKind::TypeOutlives(outlives) => { + if let ty::Opaque(opaque_def_id, opaque_substs) = outlives.skip_binder().0.kind { + if opaque_def_id == def_id && opaque_substs == substs { + return Some(pred); + } + } else { + // These can come from elaborating other predicates + return None; + } + } + // These can come from elaborating other predicates + ty::PredicateKind::RegionOutlives(_) => return None, _ => {} } + // Other predicates are currently only possible for type alias impl + // trait. After #72080 is merged this can be a (delayed?) bug. None }); diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 2f3824c394bac..368901ca09443 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -1185,8 +1185,8 @@ fn compare_projection_bounds<'tcx>( impl_ty_span: Span, impl_trait_ref: ty::TraitRef<'tcx>, ) -> Result<(), ErrorReported> { - let is_gat = !tcx.generics_of(impl_ty.def_id).params.is_empty(); - if impl_ty.defaultness.is_final() && !is_gat { + let have_gats = tcx.features().generic_associated_types; + if impl_ty.defaultness.is_final() && !have_gats { // For "final", non-generic associate type implementations, we // don't need this as described above. return Ok(()); @@ -1194,7 +1194,9 @@ fn compare_projection_bounds<'tcx>( let param_env = tcx.param_env(impl_ty.def_id); - let impl_substs = InternalSubsts::identity_for_item(tcx, impl_ty.container.id()); + let impl_ty_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id); + let rebased_substs = + impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs); let impl_ty_value = tcx.type_of(impl_ty.def_id); // Map the predicate from the trait to the corresponding one for the impl. @@ -1207,32 +1209,9 @@ fn compare_projection_bounds<'tcx>( // function would translate and partially normalize // `[>::Y<'a>, A]` to `[&'a u32, &'x u32]`. let translate_predicate_substs = move |predicate_substs: SubstsRef<'tcx>| { - let normalized_self = if !is_gat { - // projection_predicates only includes projections where the - // substs of the trait ref are exactly the trait's identity - // substs, so we can simply return the value from the impl. - impl_ty_value - } else { - let predicate_self_ty = predicate_substs.type_at(0); - let impl_ty_substs = if let ty::Projection(p) = predicate_self_ty.kind { - assert!( - p.item_def_id == trait_ty.def_id, - "projection_predicates returned predicate for the wrong type: {}", - predicate_self_ty, - ); - p.substs.rebase_onto(tcx, impl_trait_ref.def_id, impl_substs) - } else { - bug!( - "projection_predicates returned predicate for the wrong type `{}`", - predicate_self_ty, - ); - }; - impl_ty_value.subst(tcx, impl_ty_substs) - }; - tcx.mk_substs( - iter::once(normalized_self.into()) - .chain(predicate_substs[1..].iter().map(|s| s.subst(tcx, impl_trait_ref.substs))), + iter::once(impl_ty_value.into()) + .chain(predicate_substs[1..].iter().map(|s| s.subst(tcx, rebased_substs))), ) }; @@ -1246,7 +1225,7 @@ fn compare_projection_bounds<'tcx>( let cause = ObligationCause { span: impl_ty_span, body_id: impl_ty_hir_id, - code: ObligationCauseCode::ItemObligation(impl_trait_ref.def_id), + code: ObligationCauseCode::ItemObligation(trait_ty.def_id), }; let predicates = tcx.projection_predicates(trait_ty.def_id); @@ -1271,10 +1250,15 @@ fn compare_projection_bounds<'tcx>( substs: projection_substs, item_def_id: projection.projection_ty.item_def_id, }, - ty: projection.ty.subst(tcx, impl_trait_ref.substs), + ty: projection.ty.subst(tcx, rebased_substs), } }) .to_predicate(tcx), + ty::PredicateKind::TypeOutlives(poly_outlives) => poly_outlives + .map_bound(|outlives| { + ty::OutlivesPredicate(impl_ty_value, outlives.1.subst(tcx, rebased_substs)) + }) + .to_predicate(tcx), _ => bug!("unexepected projection predicate kind: `{:?}`", predicate), }; diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 355b4fc413f42..dd8116455f33b 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -35,7 +35,7 @@ use rustc_middle::hir::map::Map; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::mono::Linkage; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::subst::{InternalSubsts, Subst}; +use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::util::Discr; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, AdtKind, Const, ToPolyTraitRef, Ty, TyCtxt}; @@ -1704,6 +1704,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat let mut is_trait = None; let mut is_default_impl_trait = None; + let mut is_trait_associated_type = None; let icx = ItemCtxt::new(tcx, def_id); let constness = icx.default_constness_for_trait_bounds(); @@ -1713,7 +1714,12 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat let mut predicates = UniquePredicates::new(); let ast_generics = match node { - Node::TraitItem(item) => &item.generics, + Node::TraitItem(item) => { + if let hir::TraitItemKind::Type(bounds, _) = item.kind { + is_trait_associated_type = Some((bounds, item.span)); + } + &item.generics + } Node::ImplItem(item) => match item.kind { ImplItemKind::OpaqueTy(ref bounds) => { @@ -1961,10 +1967,21 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat } } - // Add predicates from associated type bounds. - if let Some((self_trait_ref, trait_items)) = is_trait { + // Add predicates from associated type bounds (`type X: Bound`) + if tcx.features().generic_associated_types { + // New behavior: bounds declared on associate type are predicates of that + // associated type. Not the default because it needs more testing. + if let Some((bounds, span)) = is_trait_associated_type { + let projection_ty = + tcx.mk_projection(def_id, InternalSubsts::identity_for_item(tcx, def_id)); + + predicates.extend(associated_item_predicates(tcx, def_id, bounds, projection_ty, span)) + } + } else if let Some((self_trait_ref, trait_items)) = is_trait { + // Current behavior: bounds declared on associate type are predicates + // of its parent trait. predicates.extend(trait_items.iter().flat_map(|trait_item_ref| { - associated_item_predicates(tcx, def_id, self_trait_ref, trait_item_ref) + trait_associated_item_predicates(tcx, def_id, self_trait_ref, trait_item_ref) })) } @@ -1994,7 +2011,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat result } -fn associated_item_predicates( +fn trait_associated_item_predicates( tcx: TyCtxt<'tcx>, def_id: DefId, self_trait_ref: ty::TraitRef<'tcx>, @@ -2007,93 +2024,40 @@ fn associated_item_predicates( _ => return Vec::new(), }; - let is_gat = !tcx.generics_of(item_def_id).params.is_empty(); - - let mut had_error = false; - - let mut unimplemented_error = |arg_kind: &str| { - if !had_error { - tcx.sess - .struct_span_err( - trait_item.span, - &format!("{}-generic associated types are not yet implemented", arg_kind), - ) - .note( - "for more information, see issue #44265 \ - for more information", - ) - .emit(); - had_error = true; - } - }; - - let mk_bound_param = |param: &ty::GenericParamDef, _: &_| { - match param.kind { - ty::GenericParamDefKind::Lifetime => tcx - .mk_region(ty::RegionKind::ReLateBound( - ty::INNERMOST, - ty::BoundRegion::BrNamed(param.def_id, param.name), - )) - .into(), - // FIXME(generic_associated_types): Use bound types and constants - // once they are handled by the trait system. - ty::GenericParamDefKind::Type { .. } => { - unimplemented_error("type"); - tcx.types.err.into() - } - ty::GenericParamDefKind::Const => { - unimplemented_error("const"); - tcx.mk_const(ty::Const { val: ty::ConstKind::Error, ty: tcx.type_of(param.def_id) }) - .into() - } - } - }; + if !tcx.generics_of(item_def_id).params.is_empty() { + // For GATs the substs provided to the mk_projection call below are + // wrong. We should emit a feature gate error if we get here so skip + // this type. + tcx.sess.delay_span_bug(trait_item.span, "gats used without feature gate"); + return Vec::new(); + } - let bound_substs = if is_gat { - // Given: - // - // trait X<'a, B, const C: usize> { - // type T<'d, E, const F: usize>: Default; - // } - // - // We need to create predicates on the trait: - // - // for<'d, E, const F: usize> - // >::T<'d, E, const F: usize>: Sized + Default - // - // We substitute escaping bound parameters for the generic - // arguments to the associated type which are then bound by - // the `Binder` around the the predicate. - // - // FIXME(generic_associated_types): Currently only lifetimes are handled. - self_trait_ref.substs.extend_to(tcx, item_def_id.to_def_id(), mk_bound_param) - } else { - self_trait_ref.substs - }; + let assoc_ty = tcx.mk_projection( + tcx.hir().local_def_id(trait_item.hir_id).to_def_id(), + self_trait_ref.substs, + ); - let assoc_ty = - tcx.mk_projection(tcx.hir().local_def_id(trait_item.hir_id).to_def_id(), bound_substs); + associated_item_predicates(tcx, def_id, bounds, assoc_ty, trait_item.span) +} +fn associated_item_predicates( + tcx: TyCtxt<'tcx>, + def_id: DefId, + bounds: &'tcx [hir::GenericBound<'tcx>], + projection_ty: Ty<'tcx>, + span: Span, +) -> Vec<(ty::Predicate<'tcx>, Span)> { let bounds = AstConv::compute_bounds( &ItemCtxt::new(tcx, def_id), - assoc_ty, + projection_ty, bounds, SizedByDefault::Yes, - trait_item.span, + span, ); - let predicates = bounds.predicates(tcx, assoc_ty); + let predicates = bounds.predicates(tcx, projection_ty); - if is_gat { - // We use shifts to get the regions that we're substituting to - // be bound by the binders in the `Predicate`s rather that - // escaping. - let shifted_in = ty::fold::shift_vars(tcx, &predicates, 1); - let substituted = shifted_in.subst(tcx, bound_substs); - ty::fold::shift_out_vars(tcx, &substituted, 1) - } else { - predicates - } + predicates } /// Converts a specific `GenericBound` from the AST into a set of diff --git a/src/test/ui/feature-gates/feature-gate-generic_associated_types.rs b/src/test/ui/feature-gates/feature-gate-generic_associated_types.rs index 7ff348aca7cc1..17548d7b9e88c 100644 --- a/src/test/ui/feature-gates/feature-gate-generic_associated_types.rs +++ b/src/test/ui/feature-gates/feature-gate-generic_associated_types.rs @@ -3,11 +3,9 @@ use std::ops::Deref; trait PointerFamily { type Pointer: Deref; //~^ ERROR generic associated types are unstable - //~| ERROR type-generic associated types are not yet implemented type Pointer2: Deref where T: Clone, U: Clone; //~^ ERROR generic associated types are unstable //~| ERROR where clauses on associated types are unstable - //~| ERROR type-generic associated types are not yet implemented } struct Foo; diff --git a/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr b/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr index a0e06cb2b6795..8499b1ab70f5d 100644 --- a/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr +++ b/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr @@ -8,7 +8,7 @@ LL | type Pointer: Deref; = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable error[E0658]: generic associated types are unstable - --> $DIR/feature-gate-generic_associated_types.rs:7:5 + --> $DIR/feature-gate-generic_associated_types.rs:6:5 | LL | type Pointer2: Deref where T: Clone, U: Clone; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | type Pointer2: Deref where T: Clone, U: Clone; = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable error[E0658]: where clauses on associated types are unstable - --> $DIR/feature-gate-generic_associated_types.rs:7:5 + --> $DIR/feature-gate-generic_associated_types.rs:6:5 | LL | type Pointer2: Deref where T: Clone, U: Clone; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -26,7 +26,7 @@ LL | type Pointer2: Deref where T: Clone, U: Clone; = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable error[E0658]: generic associated types are unstable - --> $DIR/feature-gate-generic_associated_types.rs:16:5 + --> $DIR/feature-gate-generic_associated_types.rs:14:5 | LL | type Pointer = Box; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -35,7 +35,7 @@ LL | type Pointer = Box; = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable error[E0658]: generic associated types are unstable - --> $DIR/feature-gate-generic_associated_types.rs:18:5 + --> $DIR/feature-gate-generic_associated_types.rs:16:5 | LL | type Pointer2 = Box; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -44,7 +44,7 @@ LL | type Pointer2 = Box; = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable error[E0658]: where clauses on associated types are unstable - --> $DIR/feature-gate-generic_associated_types.rs:23:5 + --> $DIR/feature-gate-generic_associated_types.rs:21:5 | LL | type Assoc where Self: Sized; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -53,7 +53,7 @@ LL | type Assoc where Self: Sized; = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable error[E0658]: where clauses on associated types are unstable - --> $DIR/feature-gate-generic_associated_types.rs:28:5 + --> $DIR/feature-gate-generic_associated_types.rs:26:5 | LL | type Assoc where Self: Sized = Foo; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,22 +61,6 @@ LL | type Assoc where Self: Sized = Foo; = note: see issue #44265 for more information = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable -error: type-generic associated types are not yet implemented - --> $DIR/feature-gate-generic_associated_types.rs:4:5 - | -LL | type Pointer: Deref; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: type-generic associated types are not yet implemented - --> $DIR/feature-gate-generic_associated_types.rs:7:5 - | -LL | type Pointer2: Deref where T: Clone, U: Clone; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: aborting due to 9 previous errors +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/generic-associated-types/collections-project-default.rs b/src/test/ui/generic-associated-types/collections-project-default.rs new file mode 100644 index 0000000000000..5fbae02573c62 --- /dev/null +++ b/src/test/ui/generic-associated-types/collections-project-default.rs @@ -0,0 +1,72 @@ +#![allow(incomplete_features)] +#![feature(generic_associated_types)] +#![feature(associated_type_defaults)] + +// A Collection trait and collection families. Based on +// http://smallcultfollowing.com/babysteps/blog/2016/11/03/ +// associated-type-constructors-part-2-family-traits/ + +// check that we don't normalize with trait defaults. + +trait Collection { + type Iter<'iter>: Iterator where T: 'iter; + type Family: CollectionFamily; + // Test associated type defaults with parameters + type Sibling: Collection = + <>::Family as CollectionFamily>::Member; + + fn empty() -> Self; + + fn add(&mut self, value: T); + + fn iterate<'iter>(&'iter self) -> Self::Iter<'iter>; +} + +trait CollectionFamily { + type Member: Collection; +} + +struct VecFamily; + +impl CollectionFamily for VecFamily { + type Member = Vec; +} + +impl Collection for Vec { + type Iter<'iter> where T: 'iter = std::slice::Iter<'iter, T>; + type Family = VecFamily; + + fn empty() -> Self { + Vec::new() + } + + fn add(&mut self, value: T) { + self.push(value) + } + + fn iterate<'iter>(&'iter self) -> Self::Iter<'iter> { + self.iter() + } +} + +fn floatify_sibling(ints: &C) -> >::Sibling +where + C: Collection, +{ + let mut res = ::Member::::empty(); + for &v in ints.iterate() { + res.add(v as f32); + } + res + //~^ ERROR mismatched types +} + +fn use_floatify() { + let a = vec![1i32, 2, 3]; + let c = floatify_sibling(&a); + assert_eq!(Some(&1.0), c.iterate().next()); +} + +fn main() { + use_floatify(); +} diff --git a/src/test/ui/generic-associated-types/collections-project-default.stderr b/src/test/ui/generic-associated-types/collections-project-default.stderr new file mode 100644 index 0000000000000..ca02b2603ba64 --- /dev/null +++ b/src/test/ui/generic-associated-types/collections-project-default.stderr @@ -0,0 +1,15 @@ +error[E0308]: mismatched types + --> $DIR/collections-project-default.rs:60:5 + | +LL | fn floatify_sibling(ints: &C) -> >::Sibling + | ------------------------------------ expected `>::Sibling` because of return type +... +LL | res + | ^^^ expected Collection::Sibling, found CollectionFamily::Member + | + = note: expected associated type `>::Sibling` + found associated type `<>::Family as CollectionFamily>::Member` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/generic-associated-types/collections.rs b/src/test/ui/generic-associated-types/collections.rs index 6f018f0401863..1b5b9c181fb61 100644 --- a/src/test/ui/generic-associated-types/collections.rs +++ b/src/test/ui/generic-associated-types/collections.rs @@ -6,13 +6,14 @@ // http://smallcultfollowing.com/babysteps/blog/2016/11/03/ // associated-type-constructors-part-2-family-traits/ +// run-pass + trait Collection { - type Iter<'iter>: Iterator; + type Iter<'iter>: Iterator where T: 'iter; type Family: CollectionFamily; // Test associated type defaults with parameters type Sibling: Collection = <>::Family as CollectionFamily>::Member; - //~^^ ERROR type-generic associated types are not yet implemented fn empty() -> Self; @@ -23,7 +24,6 @@ trait Collection { trait CollectionFamily { type Member: Collection; - //~^ ERROR type-generic associated types are not yet implemented } struct VecFamily; @@ -33,7 +33,7 @@ impl CollectionFamily for VecFamily { } impl Collection for Vec { - type Iter<'iter> = std::slice::Iter<'iter, T>; + type Iter<'iter> where T: 'iter = std::slice::Iter<'iter, T>; type Family = VecFamily; fn empty() -> Self { @@ -53,18 +53,7 @@ fn floatify(ints: &C) -> <>::Family as CollectionFamily> where C: Collection, { - let mut res = C::Family::Member::::empty(); - for &v in ints.iterate() { - res.add(v as f32); - } - res -} - -fn floatify_sibling(ints: &C) -> >::Sibling -where - C: Collection, -{ - let mut res = C::Family::Member::::empty(); + let mut res = ::Member::::empty(); for &v in ints.iterate() { res.add(v as f32); } @@ -72,11 +61,11 @@ where } fn use_floatify() { - let a = vec![1i32, 2, 3]; - let b = floatify(a); - println!("{}", b.iterate().next()); - let c = floatify_sibling(a); - println!("{}", c.iterate().next()); + let a = vec![1, 2, 3]; + let b = floatify(&a); + assert_eq!(Some(&1.0), b.iterate().next()); } -fn main() {} +fn main() { + use_floatify(); +} diff --git a/src/test/ui/generic-associated-types/collections.stderr b/src/test/ui/generic-associated-types/collections.stderr deleted file mode 100644 index fb06d5e49a391..0000000000000 --- a/src/test/ui/generic-associated-types/collections.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error: type-generic associated types are not yet implemented - --> $DIR/collections.rs:13:5 - | -LL | / type Sibling: Collection = -LL | | <>::Family as CollectionFamily>::Member; - | |_________________________________________________________________________^ - | - = note: for more information, see issue #44265 for more information - -error: type-generic associated types are not yet implemented - --> $DIR/collections.rs:25:5 - | -LL | type Member: Collection; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: aborting due to 2 previous errors - diff --git a/src/test/ui/generic-associated-types/construct_with_other_type.rs b/src/test/ui/generic-associated-types/construct_with_other_type.rs index 2198b99db25c1..ff9d61658f4eb 100644 --- a/src/test/ui/generic-associated-types/construct_with_other_type.rs +++ b/src/test/ui/generic-associated-types/construct_with_other_type.rs @@ -1,7 +1,7 @@ #![allow(incomplete_features)] #![feature(generic_associated_types)] -// FIXME(#30472) normalize enough to handle this. +// check-pass use std::ops::Deref; @@ -17,7 +17,6 @@ trait Baz { } impl Baz for T where T: Foo { -//~^ ERROR type mismatch resolving type Quux<'a> where T: 'a = T; type Baa<'a> where T: 'a = &'a ::Bar<'a, 'static>; diff --git a/src/test/ui/generic-associated-types/construct_with_other_type.stderr b/src/test/ui/generic-associated-types/construct_with_other_type.stderr deleted file mode 100644 index b9468b3330b44..0000000000000 --- a/src/test/ui/generic-associated-types/construct_with_other_type.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0271]: type mismatch resolving `for<'a> <::Baa<'a> as std::ops::Deref>::Target == <::Quux<'a> as Foo>::Bar<'a, 'static>` - --> $DIR/construct_with_other_type.rs:19:9 - | -LL | impl Baz for T where T: Foo { - | - ^^^ expected type parameter `T`, found associated type - | | - | this type parameter - | - = note: expected associated type `::Bar<'_, 'static>` - found associated type `<::Quux<'_> as Foo>::Bar<'_, 'static>` -help: consider further restricting this bound - | -LL | impl Baz for T where T: Foo + Baz { - | ^^^^^^^^^^^^^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.rs b/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.rs index f88df6a608aa3..c1d68812e9356 100644 --- a/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.rs +++ b/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.rs @@ -6,7 +6,6 @@ struct Foo; trait MyTrait { type Item; //~^ ERROR generic associated types are unstable [E0658] - //~| ERROR type-generic associated types are not yet implemented } impl MyTrait for Foo { diff --git a/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.stderr b/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.stderr index f3da27775adcf..34f536dbe8f64 100644 --- a/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.stderr +++ b/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.stderr @@ -8,7 +8,7 @@ LL | type Item; = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable error[E0658]: generic associated types are unstable - --> $DIR/gat-dont-ice-on-absent-feature-2.rs:13:5 + --> $DIR/gat-dont-ice-on-absent-feature-2.rs:12:5 | LL | type Item = T; | ^^^^^^^^^^^^^^^^^ @@ -16,14 +16,6 @@ LL | type Item = T; = note: see issue #44265 for more information = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable -error: type-generic associated types are not yet implemented - --> $DIR/gat-dont-ice-on-absent-feature-2.rs:7:5 - | -LL | type Item; - | ^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/generic-associated-types/generic-associated-types-where.rs b/src/test/ui/generic-associated-types/generic-associated-types-where.rs index 589024e162166..1a94796535c14 100644 --- a/src/test/ui/generic-associated-types/generic-associated-types-where.rs +++ b/src/test/ui/generic-associated-types/generic-associated-types-where.rs @@ -9,11 +9,8 @@ use std::fmt::{Display, Debug}; trait Foo { type Assoc where Self: Sized; type Assoc2 where T: Display; - //~^ ERROR type-generic associated types are not yet implemented type Assoc3; - //~^ ERROR type-generic associated types are not yet implemented - type WithDefault<'a, T: Debug + 'a> = dyn Iterator; - //~^ ERROR type-generic associated types are not yet implemented + type WithDefault<'a, T: Debug + 'a>: ?Sized = dyn Iterator; type NoGenerics; } @@ -23,6 +20,7 @@ impl Foo for Bar { type Assoc = usize; type Assoc2 = Vec; type Assoc3 where T: Iterator = Vec; + //~^ impl has stricter requirements than trait type WithDefault<'a, T: Debug + 'a> = &'a dyn Iterator; type NoGenerics = ::std::cell::Cell; } diff --git a/src/test/ui/generic-associated-types/generic-associated-types-where.stderr b/src/test/ui/generic-associated-types/generic-associated-types-where.stderr index fb29b377a16e3..4d02f2c46a6d0 100644 --- a/src/test/ui/generic-associated-types/generic-associated-types-where.stderr +++ b/src/test/ui/generic-associated-types/generic-associated-types-where.stderr @@ -1,26 +1,12 @@ -error: type-generic associated types are not yet implemented - --> $DIR/generic-associated-types-where.rs:11:5 - | -LL | type Assoc2 where T: Display; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: type-generic associated types are not yet implemented - --> $DIR/generic-associated-types-where.rs:13:5 +error[E0276]: impl has stricter requirements than trait + --> $DIR/generic-associated-types-where.rs:22:5 | LL | type Assoc3; - | ^^^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: type-generic associated types are not yet implemented - --> $DIR/generic-associated-types-where.rs:15:5 - | -LL | type WithDefault<'a, T: Debug + 'a> = dyn Iterator; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information + | --------------- definition of `Assoc3` from trait +... +LL | type Assoc3 where T: Iterator = Vec; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: std::iter::Iterator` -error: aborting due to 3 previous errors +error: aborting due to previous error +For more information about this error, try `rustc --explain E0276`. diff --git a/src/test/ui/generic-associated-types/issue-47206-where-clause.rs b/src/test/ui/generic-associated-types/issue-47206-where-clause.rs index 53e350aacf88e..de2b978460f7f 100644 --- a/src/test/ui/generic-associated-types/issue-47206-where-clause.rs +++ b/src/test/ui/generic-associated-types/issue-47206-where-clause.rs @@ -5,13 +5,13 @@ trait Foo { type Assoc3; - //~^ type-generic associated types are not yet implemented } struct Bar; impl Foo for Bar { type Assoc3 where T: Iterator = Vec; + //~^ ERROR impl has stricter requirements than trait } fn main() {} diff --git a/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr b/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr index c9c1a4753b0dd..bc5c40ff029f9 100644 --- a/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr +++ b/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr @@ -1,10 +1,12 @@ -error: type-generic associated types are not yet implemented - --> $DIR/issue-47206-where-clause.rs:7:5 +error[E0276]: impl has stricter requirements than trait + --> $DIR/issue-47206-where-clause.rs:13:5 | LL | type Assoc3; - | ^^^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information + | --------------- definition of `Assoc3` from trait +... +LL | type Assoc3 where T: Iterator = Vec; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: std::iter::Iterator` error: aborting due to previous error +For more information about this error, try `rustc --explain E0276`. diff --git a/src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.rs b/src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.rs index 1a79dbf2279a0..404be59a36d92 100644 --- a/src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.rs +++ b/src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.rs @@ -1,11 +1,14 @@ #![allow(incomplete_features)] #![feature(generic_associated_types)] -// FIXME(generic-associated-types) Investigate why this doesn't compile. +// check-pass trait Iterator { type Item<'a>: 'a; - //~^ ERROR the requirement `for<'a> ::Item<'a>: 'a` is not satisfied +} + +impl Iterator for () { + type Item<'a> = &'a (); } fn main() {} diff --git a/src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.stderr b/src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.stderr deleted file mode 100644 index 4b06baa09ffbf..0000000000000 --- a/src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error[E0280]: the requirement `for<'a> ::Item<'a>: 'a` is not satisfied - --> $DIR/issue-62326-parameter-out-of-range.rs:7:20 - | -LL | trait Iterator { - | -------- required by a bound in this -LL | type Item<'a>: 'a; - | ^^ required by this bound in `Iterator` - -error: aborting due to previous error - diff --git a/src/test/ui/generic-associated-types/issue-67424.rs b/src/test/ui/generic-associated-types/issue-67424.rs index 9b616b8abc2ee..fa35a3e8b04d1 100644 --- a/src/test/ui/generic-associated-types/issue-67424.rs +++ b/src/test/ui/generic-associated-types/issue-67424.rs @@ -7,7 +7,6 @@ trait Trait1 { trait Trait2 { type Type1: Trait1; //~^ ERROR: generic associated types are unstable - //~| ERROR: type-generic associated types are not yet implemented } fn main() {} diff --git a/src/test/ui/generic-associated-types/issue-67424.stderr b/src/test/ui/generic-associated-types/issue-67424.stderr index 8b08c71759bb9..bbb7d56f5928e 100644 --- a/src/test/ui/generic-associated-types/issue-67424.stderr +++ b/src/test/ui/generic-associated-types/issue-67424.stderr @@ -7,14 +7,6 @@ LL | type Type1: Trait1; = note: see issue #44265 for more information = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable -error: type-generic associated types are not yet implemented - --> $DIR/issue-67424.rs:8:5 - | -LL | type Type1: Trait1; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr index eeff7c340ac96..834bc3b7878f2 100644 --- a/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr +++ b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr @@ -10,8 +10,8 @@ LL | #![feature(generic_associated_types)] error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied --> $DIR/issue-68641-check-gat-bounds.rs:15:5 | -LL | trait UnsafeCopy { - | ---------------- required by `UnsafeCopy` +LL | type Item<'a>: Copy; + | -------------------- required by `UnsafeCopy::Item` ... LL | type Item<'a> = T; | ^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` diff --git a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr index b3d4b8d465180..89cc5dfd06018 100644 --- a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr +++ b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr @@ -10,8 +10,8 @@ LL | #![feature(generic_associated_types)] error[E0277]: expected a `std::ops::Fn<()>` closure, found `T` --> $DIR/issue-68642-broken-llvm-ir.rs:15:5 | -LL | trait Fun { - | --------- required by `Fun` +LL | type F<'a>: Fn() -> u32; + | ------------------------ required by `Fun::F` ... LL | type F<'a> = Self; | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T` diff --git a/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr b/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr index 6e23fe02de8cd..efd3287853f03 100644 --- a/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr +++ b/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr @@ -10,8 +10,8 @@ LL | #![feature(generic_associated_types)] error[E0277]: expected a `std::ops::Fn<()>` closure, found `T` --> $DIR/issue-68643-broken-mir.rs:15:5 | -LL | trait Fun { - | --------- required by `Fun` +LL | type F<'a>: Fn() -> u32; + | ------------------------ required by `Fun::F` ... LL | type F<'a> = Self; | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T` diff --git a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr index 234f5c8a0cc02..5da924a512f00 100644 --- a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr +++ b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr @@ -10,8 +10,8 @@ LL | #![feature(generic_associated_types)] error[E0277]: expected a `std::ops::Fn<()>` closure, found `T` --> $DIR/issue-68644-codegen-selection.rs:15:5 | -LL | trait Fun { - | --------- required by `Fun` +LL | type F<'a>: Fn() -> u32; + | ------------------------ required by `Fun::F` ... LL | type F<'a> = Self; | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T` diff --git a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr index ac2d5063fbb5d..12d84ab6a369b 100644 --- a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr +++ b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr @@ -10,8 +10,8 @@ LL | #![feature(generic_associated_types)] error[E0277]: expected a `std::ops::Fn<()>` closure, found `T` --> $DIR/issue-68645-codegen-fulfillment.rs:15:5 | -LL | trait Fun { - | --------- required by `Fun` +LL | type F<'a>: Fn() -> u32; + | ------------------------ required by `Fun::F` ... LL | type F<'a> = Self; | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T` diff --git a/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr b/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr index e4eb7991f7637..e1ceeac3196a8 100644 --- a/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr +++ b/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr @@ -10,8 +10,8 @@ LL | #![feature(generic_associated_types)] error[E0271]: type mismatch resolving `::Target == T` --> $DIR/issue-68656-unsized-values.rs:16:5 | -LL | trait UnsafeCopy { - | ------------------------- required by `UnsafeCopy` +LL | type Item<'a>: std::ops::Deref; + | ------------------------------------------- required by `UnsafeCopy::Item` ... LL | impl UnsafeCopy for T { | - this type parameter diff --git a/src/test/ui/generic-associated-types/iterable.rs b/src/test/ui/generic-associated-types/iterable.rs index 105ab4a8adc38..600a69006c1ea 100644 --- a/src/test/ui/generic-associated-types/iterable.rs +++ b/src/test/ui/generic-associated-types/iterable.rs @@ -1,7 +1,7 @@ #![allow(incomplete_features)] #![feature(generic_associated_types)] -// FIXME(#30472) normalize enough to handle this. +// run-pass trait Iterable { type Item<'a> where Self: 'a; @@ -13,39 +13,35 @@ trait Iterable { // Impl for struct type impl Iterable for Vec { type Item<'a> where T: 'a = as Iterator>::Item; - //~^ ERROR type mismatch resolving type Iter<'a> where T: 'a = std::slice::Iter<'a, T>; fn iter<'a>(&'a self) -> Self::Iter<'a> { - //~^ ERROR type mismatch resolving - self.iter() + self[..].iter() } } // Impl for a primitive type impl Iterable for [T] { type Item<'a> where T: 'a = as Iterator>::Item; - //~^ ERROR type mismatch resolving type Iter<'a> where T: 'a = std::slice::Iter<'a, T>; fn iter<'a>(&'a self) -> Self::Iter<'a> { - //~^ ERROR type mismatch resolving self.iter() } } -fn make_iter<'a, I: Iterable>(it: &'a I) -> I::Iter<'a> { +fn make_iter<'a, I: Iterable + ?Sized>(it: &'a I) -> I::Iter<'a> { it.iter() } -fn get_first<'a, I: Iterable>(it: &'a I) -> Option> { +fn get_first<'a, I: Iterable + ?Sized>(it: &'a I) -> Option> { it.iter().next() } fn main() { let v = vec![1, 2, 3]; - assert_eq!(v, make_iter(&v).copied().collect()); - assert_eq!(v, make_iter(&*v).copied().collect()); - assert_eq!(1, get_first(&v)); - assert_eq!(1, get_first(&*v)); + assert_eq!(v, make_iter(&v).copied().collect::>()); + assert_eq!(v, make_iter(&*v).copied().collect::>()); + assert_eq!(Some(&1), get_first(&v)); + assert_eq!(Some(&1), get_first(&*v)); } diff --git a/src/test/ui/generic-associated-types/iterable.stderr b/src/test/ui/generic-associated-types/iterable.stderr deleted file mode 100644 index 6e75462122513..0000000000000 --- a/src/test/ui/generic-associated-types/iterable.stderr +++ /dev/null @@ -1,59 +0,0 @@ -error[E0271]: type mismatch resolving `for<'a> < as Iterable>::Iter<'a> as std::iter::Iterator>::Item == as Iterable>::Item<'a>` - --> $DIR/iterable.rs:15:33 - | -LL | type Item<'a> where T: 'a = as Iterator>::Item; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found associated type - | - = note: expected reference `&T` - found associated type ` as Iterable>::Item<'_>` - = help: consider constraining the associated type ` as Iterable>::Item<'_>` to `&_` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html - -error[E0271]: type mismatch resolving `for<'a> <<[T] as Iterable>::Iter<'a> as std::iter::Iterator>::Item == <[T] as Iterable>::Item<'a>` - --> $DIR/iterable.rs:27:33 - | -LL | type Item<'a> where T: 'a = as Iterator>::Item; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found associated type - | - = note: expected reference `&T` - found associated type `<[T] as Iterable>::Item<'_>` - = help: consider constraining the associated type `<[T] as Iterable>::Item<'_>` to `&_` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html - -error[E0271]: type mismatch resolving `for<'a> < as Iterable>::Iter<'a> as std::iter::Iterator>::Item == as Iterable>::Item<'a>` - --> $DIR/iterable.rs:19:30 - | -LL | trait Iterable { - | -------- required by a bound in this -LL | type Item<'a> where Self: 'a; -LL | type Iter<'a>: Iterator> where Self: 'a; - | --------------------- required by this bound in `Iterable` -... -LL | fn iter<'a>(&'a self) -> Self::Iter<'a> { - | ^^^^^^^^^^^^^^ expected associated type, found reference - | - = note: expected associated type ` as Iterable>::Item<'_>` - found reference `&T` - = help: consider constraining the associated type ` as Iterable>::Item<'_>` to `&_` or calling a method that returns ` as Iterable>::Item<'_>` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html - -error[E0271]: type mismatch resolving `for<'a> <<[T] as Iterable>::Iter<'a> as std::iter::Iterator>::Item == <[T] as Iterable>::Item<'a>` - --> $DIR/iterable.rs:31:30 - | -LL | trait Iterable { - | -------- required by a bound in this -LL | type Item<'a> where Self: 'a; -LL | type Iter<'a>: Iterator> where Self: 'a; - | --------------------- required by this bound in `Iterable` -... -LL | fn iter<'a>(&'a self) -> Self::Iter<'a> { - | ^^^^^^^^^^^^^^ expected associated type, found reference - | - = note: expected associated type `<[T] as Iterable>::Item<'_>` - found reference `&T` - = help: consider constraining the associated type `<[T] as Iterable>::Item<'_>` to `&_` or calling a method that returns `<[T] as Iterable>::Item<'_>` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/generic-associated-types/missing-bounds.fixed b/src/test/ui/generic-associated-types/missing-bounds.fixed index 364d2388741b0..3ba7d043d0759 100644 --- a/src/test/ui/generic-associated-types/missing-bounds.fixed +++ b/src/test/ui/generic-associated-types/missing-bounds.fixed @@ -34,12 +34,11 @@ impl> Add for D { struct E(B); -impl Add for E where B: Add, B: std::ops::Add { - //~^ ERROR equality constraints are not yet supported in `where` clauses +impl Add for E where B: Add { type Output = Self; fn add(self, rhs: Self) -> Self { - Self(self.0 + rhs.0) //~ ERROR mismatched types + Self(self.0 + rhs.0) } } diff --git a/src/test/ui/generic-associated-types/missing-bounds.rs b/src/test/ui/generic-associated-types/missing-bounds.rs index ffafff5e9f586..962d2db9476bd 100644 --- a/src/test/ui/generic-associated-types/missing-bounds.rs +++ b/src/test/ui/generic-associated-types/missing-bounds.rs @@ -34,12 +34,11 @@ impl Add for D { struct E(B); -impl Add for E where ::Output = B { - //~^ ERROR equality constraints are not yet supported in `where` clauses +impl Add for E where B: Add { type Output = Self; fn add(self, rhs: Self) -> Self { - Self(self.0 + rhs.0) //~ ERROR mismatched types + Self(self.0 + rhs.0) } } diff --git a/src/test/ui/generic-associated-types/missing-bounds.stderr b/src/test/ui/generic-associated-types/missing-bounds.stderr index 50536fdaca96e..630ceac093ef2 100644 --- a/src/test/ui/generic-associated-types/missing-bounds.stderr +++ b/src/test/ui/generic-associated-types/missing-bounds.stderr @@ -1,15 +1,3 @@ -error: equality constraints are not yet supported in `where` clauses - --> $DIR/missing-bounds.rs:37:33 - | -LL | impl Add for E where ::Output = B { - | ^^^^^^^^^^^^^^^^^^^^^^ not supported - | - = note: see issue #20041 for more information -help: if `Output` is an associated type you're trying to set, use the associated type binding syntax - | -LL | impl Add for E where B: Add { - | ^^^^^^^^^^^^^^^^^^ - error[E0308]: mismatched types --> $DIR/missing-bounds.rs:11:11 | @@ -55,23 +43,7 @@ help: consider restricting type parameter `B` LL | impl> Add for D { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0308]: mismatched types - --> $DIR/missing-bounds.rs:42:14 - | -LL | impl Add for E where ::Output = B { - | - this type parameter -... -LL | Self(self.0 + rhs.0) - | ^^^^^^^^^^^^^^ expected type parameter `B`, found associated type - | - = note: expected type parameter `B` - found associated type `::Output` -help: consider further restricting type parameter `B` - | -LL | impl Add for E where ::Output = B, B: std::ops::Add { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0308, E0369. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/generic-associated-types/parameter_number_and_kind.rs b/src/test/ui/generic-associated-types/parameter_number_and_kind.rs index 0edc5c48c01af..f4d09fc1539da 100644 --- a/src/test/ui/generic-associated-types/parameter_number_and_kind.rs +++ b/src/test/ui/generic-associated-types/parameter_number_and_kind.rs @@ -7,18 +7,14 @@ trait Foo { type B<'a, 'b>; type C; type D; - //~^ ERROR type-generic associated types are not yet implemented type E<'a, T>; - //~^ ERROR type-generic associated types are not yet implemented // Test parameters in default values type FOk = Self::E<'static, T>; - //~^ ERROR type-generic associated types are not yet implemented type FErr1 = Self::E<'static, 'static>; //~^ ERROR wrong number of lifetime arguments: expected 1, found 2 //~| ERROR wrong number of type arguments: expected 1, found 0 type FErr2 = Self::E<'static, T, u32>; - //~^ ERROR type-generic associated types are not yet implemented - //~| ERROR wrong number of type arguments: expected 1, found 2 + //~^ ERROR wrong number of type arguments: expected 1, found 2 } fn main() {} diff --git a/src/test/ui/generic-associated-types/parameter_number_and_kind.stderr b/src/test/ui/generic-associated-types/parameter_number_and_kind.stderr index 028ab72f48812..ed090e302cefa 100644 --- a/src/test/ui/generic-associated-types/parameter_number_and_kind.stderr +++ b/src/test/ui/generic-associated-types/parameter_number_and_kind.stderr @@ -1,53 +1,21 @@ -error: type-generic associated types are not yet implemented - --> $DIR/parameter_number_and_kind.rs:9:5 - | -LL | type D; - | ^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: type-generic associated types are not yet implemented - --> $DIR/parameter_number_and_kind.rs:11:5 - | -LL | type E<'a, T>; - | ^^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: type-generic associated types are not yet implemented - --> $DIR/parameter_number_and_kind.rs:14:5 - | -LL | type FOk = Self::E<'static, T>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: type-generic associated types are not yet implemented - --> $DIR/parameter_number_and_kind.rs:19:5 - | -LL | type FErr2 = Self::E<'static, T, u32>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - error[E0107]: wrong number of lifetime arguments: expected 1, found 2 - --> $DIR/parameter_number_and_kind.rs:16:35 + --> $DIR/parameter_number_and_kind.rs:13:35 | LL | type FErr1 = Self::E<'static, 'static>; | ^^^^^^^ unexpected lifetime argument error[E0107]: wrong number of type arguments: expected 1, found 0 - --> $DIR/parameter_number_and_kind.rs:16:18 + --> $DIR/parameter_number_and_kind.rs:13:18 | LL | type FErr1 = Self::E<'static, 'static>; | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 type argument error[E0107]: wrong number of type arguments: expected 1, found 2 - --> $DIR/parameter_number_and_kind.rs:19:41 + --> $DIR/parameter_number_and_kind.rs:16:41 | LL | type FErr2 = Self::E<'static, T, u32>; | ^^^ unexpected type argument -error: aborting due to 7 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0107`. diff --git a/src/test/ui/generic-associated-types/pointer_family.rs b/src/test/ui/generic-associated-types/pointer_family.rs index 1668759b4e39c..b322b752a1567 100644 --- a/src/test/ui/generic-associated-types/pointer_family.rs +++ b/src/test/ui/generic-associated-types/pointer_family.rs @@ -1,7 +1,7 @@ #![allow(incomplete_features)] #![feature(generic_associated_types)] -// FIXME(#44265): allow type-generic associated types. +// check-pass use std::rc::Rc; use std::sync::Arc; @@ -9,7 +9,6 @@ use std::ops::Deref; trait PointerFamily { type Pointer: Deref; - //~^ ERROR type-generic associated types are not yet implemented fn new(value: T) -> Self::Pointer; } diff --git a/src/test/ui/generic-associated-types/pointer_family.stderr b/src/test/ui/generic-associated-types/pointer_family.stderr deleted file mode 100644 index 83fe992fcb571..0000000000000 --- a/src/test/ui/generic-associated-types/pointer_family.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: type-generic associated types are not yet implemented - --> $DIR/pointer_family.rs:11:5 - | -LL | type Pointer: Deref; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: aborting due to previous error - diff --git a/src/test/ui/generic-associated-types/shadowing.rs b/src/test/ui/generic-associated-types/shadowing.rs index 5c308948bd3f8..44528ca1da36e 100644 --- a/src/test/ui/generic-associated-types/shadowing.rs +++ b/src/test/ui/generic-associated-types/shadowing.rs @@ -18,12 +18,10 @@ impl<'a> NoShadow<'a> for &'a u32 { trait ShadowT { type Bar; //~^ ERROR the name `T` is already used - //~| ERROR type-generic associated types are not yet implemented } trait NoShadowT { type Bar; // OK - //~^ ERROR type-generic associated types are not yet implemented } impl NoShadowT for Option { diff --git a/src/test/ui/generic-associated-types/shadowing.stderr b/src/test/ui/generic-associated-types/shadowing.stderr index 2d9a0d6fceb2d..d51c29080a0c9 100644 --- a/src/test/ui/generic-associated-types/shadowing.stderr +++ b/src/test/ui/generic-associated-types/shadowing.stderr @@ -7,7 +7,7 @@ LL | type Bar; | ^ already used error[E0403]: the name `T` is already used for a generic parameter in this item's generic parameters - --> $DIR/shadowing.rs:30:14 + --> $DIR/shadowing.rs:28:14 | LL | impl NoShadowT for Option { | - first use of `T` @@ -30,23 +30,7 @@ LL | impl<'a> NoShadow<'a> for &'a u32 { LL | type Bar<'a> = i32; | ^^ lifetime 'a already in scope -error: type-generic associated types are not yet implemented - --> $DIR/shadowing.rs:19:5 - | -LL | type Bar; - | ^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: type-generic associated types are not yet implemented - --> $DIR/shadowing.rs:25:5 - | -LL | type Bar; // OK - | ^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: aborting due to 6 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0403, E0496. For more information about an error, try `rustc --explain E0403`. diff --git a/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.rs b/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.rs new file mode 100644 index 0000000000000..7510c58d57489 --- /dev/null +++ b/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.rs @@ -0,0 +1,22 @@ +#![allow(incomplete_features)] +#![feature(generic_associated_types)] + +trait ATy { + type Item<'a>: 'a; +} + +impl<'b> ATy for &'b () { + type Item<'a> = &'b (); + //~^ ERROR does not fulfill the required lifetime +} + +trait StaticTy { + type Item<'a>: 'static; +} + +impl StaticTy for () { + type Item<'a> = &'a (); + //~^ ERROR does not fulfill the required lifetime +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.stderr b/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.stderr new file mode 100644 index 0000000000000..5d612284a2187 --- /dev/null +++ b/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.stderr @@ -0,0 +1,23 @@ +error[E0477]: the type `&'b ()` does not fulfill the required lifetime + --> $DIR/unsatisfied-outlives-bound.rs:9:5 + | +LL | type Item<'a> = &'b (); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +note: type must outlive the lifetime `'a` as defined on the associated item at 9:15 + --> $DIR/unsatisfied-outlives-bound.rs:9:15 + | +LL | type Item<'a> = &'b (); + | ^^ + +error[E0477]: the type `&'a ()` does not fulfill the required lifetime + --> $DIR/unsatisfied-outlives-bound.rs:18:5 + | +LL | type Item<'a> = &'a (); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: type must satisfy the static lifetime + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0477`. diff --git a/src/test/ui/issues/issue-38091.stderr b/src/test/ui/issues/issue-38091.stderr index 55b74501ea184..fd5c31c311ccd 100644 --- a/src/test/ui/issues/issue-38091.stderr +++ b/src/test/ui/issues/issue-38091.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `(): Valid` is not satisfied --> $DIR/issue-38091.rs:8:5 | -LL | trait Iterate<'a> { - | ----------------- required by `Iterate` +LL | type Ty: Valid; + | --------------- required by `Iterate::Ty` ... LL | default type Ty = (); | ^^^^^^^^^^^^^^^^^^^^^ the trait `Valid` is not implemented for `()` diff --git a/src/test/ui/specialization/deafult-associated-type-bound-1.stderr b/src/test/ui/specialization/deafult-associated-type-bound-1.stderr index 902ea81f3c9f1..ae7a6bfe3a122 100644 --- a/src/test/ui/specialization/deafult-associated-type-bound-1.stderr +++ b/src/test/ui/specialization/deafult-associated-type-bound-1.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `str: std::clone::Clone` is not satisfied --> $DIR/deafult-associated-type-bound-1.rs:17:5 | -LL | trait X { - | ------- required by `X` +LL | type U: Clone; + | -------------- required by `X::U` ... LL | default type U = str; | ^^^^^^^^^^^^^^^^^^^^^ the trait `std::clone::Clone` is not implemented for `str` diff --git a/src/test/ui/specialization/deafult-associated-type-bound-2.stderr b/src/test/ui/specialization/deafult-associated-type-bound-2.stderr index 3318e3b534141..34bbd21ee5019 100644 --- a/src/test/ui/specialization/deafult-associated-type-bound-2.stderr +++ b/src/test/ui/specialization/deafult-associated-type-bound-2.stderr @@ -1,8 +1,8 @@ error[E0277]: can't compare `&'static B` with `B` --> $DIR/deafult-associated-type-bound-2.rs:15:5 | -LL | trait X { - | ---------- required by `X` +LL | type U: PartialEq; + | --------------------- required by `X::U` ... LL | default type U = &'static B; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `&'static B == B` diff --git a/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr b/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr index ccafa54d27776..e7cac5347d424 100644 --- a/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr +++ b/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr @@ -10,14 +10,14 @@ LL | #![feature(generic_associated_types)] error[E0277]: can't compare `T` with `T` --> $DIR/deafult-generic-associated-type-bound.rs:18:5 | -LL | trait X { - | ------- required by `X` +LL | type U<'a>: PartialEq<&'a Self>; + | -------------------------------- required by `X::U` ... LL | default type U<'a> = &'a T; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `T == T` | = help: the trait `std::cmp::PartialEq` is not implemented for `T` - = note: required because of the requirements on the impl of `for<'a> std::cmp::PartialEq` for `&'a T` + = note: required because of the requirements on the impl of `std::cmp::PartialEq` for `&'a T` help: consider further restricting this bound | LL | impl X for T { From f0d2e78d39d0efdb431af0b59c498d532d8146e2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 12 Jun 2020 18:17:30 +0200 Subject: [PATCH 16/42] add raw_ref macros --- src/libcore/ptr/mod.rs | 67 ++++++++++++++++++++++++++++++++++++++++++ src/libstd/lib.rs | 1 + 2 files changed, 68 insertions(+) diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs index 777284ca5c096..199f08c3d5058 100644 --- a/src/libcore/ptr/mod.rs +++ b/src/libcore/ptr/mod.rs @@ -1399,3 +1399,70 @@ fnptr_impls_args! { A, B, C, D, E, F, G, H, I } fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J } fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J, K } fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J, K, L } + +/// Create a `const` raw pointer to a place, without creating an intermediate reference. +/// +/// Creating a reference with `&`/`&mut` is only allowed if the pointer is properly aligned +/// and points to initialized data. For cases where those requirements do not hold, +/// raw pointers should be used instead. However, `&expr as *const _` creates a reference +/// before casting it to a raw pointer, and that reference is subject to the same rules +/// as all other references. This macro can create a raw pointer *without* creating +/// a reference first. +/// +/// # Example +/// +/// ``` +/// #![feature(raw_ref_macros)] +/// use std::ptr; +/// +/// #[repr(packed)] +/// struct Packed { +/// f1: u8, +/// f2: u16, +/// } +/// +/// let packed = Packed { f1: 1, f2: 2 }; +/// // `&packed.f2` would create an unaligned reference, and thus be Undefined Behavior! +/// let raw_f2 = ptr::raw_const!(packed.f2); +/// assert_eq!(unsafe { raw_f2.read_unaligned() }, 2); +/// ``` +#[unstable(feature = "raw_ref_macros", issue = "none")] +#[rustc_macro_transparency = "semitransparent"] +#[allow_internal_unstable(raw_ref_op)] +pub macro raw_const($e:expr) { + &raw const $e +} + +/// Create a `mut` raw pointer to a place, without creating an intermediate reference. +/// +/// Creating a reference with `&`/`&mut` is only allowed if the pointer is properly aligned +/// and points to initialized data. For cases where those requirements do not hold, +/// raw pointers should be used instead. However, `&mut expr as *mut _` creates a reference +/// before casting it to a raw pointer, and that reference is subject to the same rules +/// as all other references. This macro can create a raw pointer *without* creating +/// a reference first. +/// +/// # Example +/// +/// ``` +/// #![feature(raw_ref_macros)] +/// use std::ptr; +/// +/// #[repr(packed)] +/// struct Packed { +/// f1: u8, +/// f2: u16, +/// } +/// +/// let mut packed = Packed { f1: 1, f2: 2 }; +/// // `&mut packed.f2` would create an unaligned reference, and thus be Undefined Behavior! +/// let raw_f2 = ptr::raw_mut!(packed.f2); +/// unsafe { raw_f2.write_unaligned(42); } +/// assert_eq!({packed.f2}, 42); // `{...}` forces copying the field instead of creating a reference. +/// ``` +#[unstable(feature = "raw_ref_macros", issue = "none")] +#[rustc_macro_transparency = "semitransparent"] +#[allow_internal_unstable(raw_ref_op)] +pub macro raw_mut($e:expr) { + &raw mut $e +} diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index d6493454db591..ef699ede2a140 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -298,6 +298,7 @@ #![feature(prelude_import)] #![feature(ptr_internals)] #![feature(raw)] +#![feature(raw_ref_macros)] #![feature(renamed_spin_loop)] #![feature(rustc_attrs)] #![feature(rustc_private)] From 01e29c778c3749bca42e38adaad5a5ff58449031 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 13 Jun 2020 13:24:19 +0100 Subject: [PATCH 17/42] Don't run test on emscripten which doesn't have threads --- src/test/ui/tls.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/ui/tls.rs b/src/test/ui/tls.rs index c696318e70f5f..fbd3413885f8f 100644 --- a/src/test/ui/tls.rs +++ b/src/test/ui/tls.rs @@ -1,4 +1,5 @@ // run-pass +// ignore-emscripten no threads support // compile-flags: -O #![feature(thread_local)] From e785472781f160fb10d97aae05f0b3c53ed8b5cf Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 13 Jun 2020 17:31:48 +0100 Subject: [PATCH 18/42] Explain what the substs we're creating are --- src/librustc_typeck/check/compare_method.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 368901ca09443..92ffa0e0e6812 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -1194,6 +1194,15 @@ fn compare_projection_bounds<'tcx>( let param_env = tcx.param_env(impl_ty.def_id); + // Given + // + // impl Foo for (A, B) { + // type Bar =... + // } + // + // - `impl_substs` would be `[A, B, C]` + // - `rebased_substs` would be `[(A, B), u32, C]`, combining the substs from + // the *trait* with the generic associated type parameters. let impl_ty_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id); let rebased_substs = impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs); From 0687b78d56b93d28ceeaa05e794849757d7341a4 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 13 Jun 2020 10:29:56 -0700 Subject: [PATCH 19/42] Speed up bootstrap a little. --- src/bootstrap/flags.rs | 7 ++--- src/bootstrap/lib.rs | 2 +- src/bootstrap/metadata.rs | 65 +++++++++++++++++---------------------- src/bootstrap/test.rs | 4 +-- 4 files changed, 33 insertions(+), 45 deletions(-) diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index cfaa43f397095..03b7028b2fa55 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -10,12 +10,10 @@ use std::process; use getopts::Options; use crate::builder::Builder; +use crate::cache::{Interned, INTERNER}; use crate::config::Config; -use crate::metadata; use crate::{Build, DocTests}; -use crate::cache::{Interned, INTERNER}; - /// Deserialized version of all flags for this compile. pub struct Flags { pub verbose: usize, // number of -v args; each extra -v after the first is passed to Cargo @@ -444,8 +442,7 @@ Arguments: // All subcommands except `clean` can have an optional "Available paths" section if matches.opt_present("verbose") { let config = Config::parse(&["build".to_string()]); - let mut build = Build::new(config); - metadata::build(&mut build); + let build = Build::new(config); let maybe_rules_help = Builder::get_help(&build, subcommand.as_str()); extra_help.push_str(maybe_rules_help.unwrap_or_default().as_str()); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 8d8a036caef88..a125b49fc01e6 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -271,7 +271,7 @@ struct Crate { impl Crate { fn is_local(&self, build: &Build) -> bool { - self.path.starts_with(&build.config.src) && !self.path.to_string_lossy().ends_with("_shim") + self.path.starts_with(&build.config.src) } fn local_path(&self, build: &Build) -> PathBuf { diff --git a/src/bootstrap/metadata.rs b/src/bootstrap/metadata.rs index 292aa3b1e24a7..185f0ddb831e7 100644 --- a/src/bootstrap/metadata.rs +++ b/src/bootstrap/metadata.rs @@ -35,49 +35,24 @@ struct ResolveNode { } pub fn build(build: &mut Build) { - let mut resolves = Vec::new(); - build_krate(&build.std_features(), build, &mut resolves, "src/libstd"); - build_krate("", build, &mut resolves, "src/libtest"); - build_krate(&build.rustc_features(), build, &mut resolves, "src/rustc"); - - let mut id2name = HashMap::with_capacity(build.crates.len()); - for (name, krate) in build.crates.iter() { - id2name.insert(krate.id.clone(), name.clone()); - } - - for node in resolves { - let name = match id2name.get(&node.id) { - Some(name) => name, - None => continue, - }; - - let krate = build.crates.get_mut(name).unwrap(); - for dep in node.dependencies.iter() { - let dep = match id2name.get(dep) { - Some(dep) => dep, - None => continue, - }; - krate.deps.insert(*dep); - } - } -} - -fn build_krate(features: &str, build: &mut Build, resolves: &mut Vec, krate: &str) { // Run `cargo metadata` to figure out what crates we're testing. - // - // Down below we're going to call `cargo test`, but to test the right set - // of packages we're going to have to know what `-p` arguments to pass it - // to know what crates to test. Here we run `cargo metadata` to learn about - // the dependency graph and what `-p` arguments there are. + let features: Vec<_> = build + .std_features() + .split_whitespace() + .map(|f| format!("test/{}", f)) + .chain(build.rustc_features().split_whitespace().map(|f| format!("rustc-main/{}", f))) + .collect(); let mut cargo = Command::new(&build.initial_cargo); cargo .arg("metadata") .arg("--format-version") .arg("1") .arg("--features") - .arg(features) + .arg(features.join(",")) + .arg("-Zpackage-features") .arg("--manifest-path") - .arg(build.src.join(krate).join("Cargo.toml")); + .arg(build.src.join("Cargo.toml")) + .env("RUSTC_BOOTSTRAP", "1"); let output = output(&mut cargo); let output: Output = serde_json::from_str(&output).unwrap(); for package in output.packages { @@ -88,5 +63,23 @@ fn build_krate(features: &str, build: &mut Build, resolves: &mut Vec = + build.crates.iter().map(|(name, krate)| (krate.id.clone(), name.clone())).collect(); + + for node in output.resolve.nodes { + let name = match id2name.get(&node.id) { + Some(name) => name, + None => continue, + }; + + let krate = build.crates.get_mut(name).unwrap(); + for dep in node.dependencies.iter() { + let dep = match id2name.get(dep) { + Some(dep) => dep, + None => continue, + }; + krate.deps.insert(*dep); + } + } } diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 163132f563425..8659acf1cc5a5 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1654,9 +1654,7 @@ impl Step for Crate { fn should_run(mut run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; for krate in run.builder.in_tree_crates("test") { - if !(krate.name.starts_with("rustc_") && krate.name.ends_with("san")) { - run = run.path(krate.local_path(&builder).to_str().unwrap()); - } + run = run.path(krate.local_path(&builder).to_str().unwrap()); } run } From d5ea0e9f8def9a3ec0eb2dd88f0465d4d1a81c21 Mon Sep 17 00:00:00 2001 From: oddg Date: Thu, 14 May 2020 19:58:43 -0700 Subject: [PATCH 20/42] Report error when casting an C-like enum implementing Drop --- src/librustc_session/lint/builtin.rs | 11 ++++++++++ src/librustc_typeck/check/cast.rs | 30 +++++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/librustc_session/lint/builtin.rs b/src/librustc_session/lint/builtin.rs index 58388bafbeddf..5a8f5c1b9fbca 100644 --- a/src/librustc_session/lint/builtin.rs +++ b/src/librustc_session/lint/builtin.rs @@ -534,6 +534,16 @@ declare_lint! { @feature_gate = sym::unsafe_block_in_unsafe_fn; } +declare_lint! { + pub CENUM_IMPL_DROP_CAST, + Warn, + "a C-like enum implementing Drop is cast", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #73333 ", + edition: None, + }; +} + declare_lint_pass! { /// Does nothing as a lint pass, but registers some `Lint`s /// that are used by other parts of the compiler. @@ -607,6 +617,7 @@ declare_lint_pass! { ASM_SUB_REGISTER, UNSAFE_OP_IN_UNSAFE_FN, INCOMPLETE_INCLUDE, + CENUM_IMPL_DROP_CAST, ] } diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 46d6706cbf429..bea5e0e996658 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -609,7 +609,10 @@ impl<'a, 'tcx> CastCheck<'tcx> { (FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt), // prim -> prim - (Int(CEnum), Int(_)) => Ok(CastKind::EnumCast), + (Int(CEnum), Int(_)) => { + self.cenum_impl_drop_lint(fcx); + Ok(CastKind::EnumCast) + } (Int(Char) | Int(Bool), Int(_)) => Ok(CastKind::PrimIntCast), (Int(_) | Float, Int(_) | Float) => Ok(CastKind::NumericCast), @@ -706,11 +709,13 @@ impl<'a, 'tcx> CastCheck<'tcx> { // Coerce to a raw pointer so that we generate AddressOf in MIR. let array_ptr_type = fcx.tcx.mk_ptr(m_expr); fcx.try_coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No) - .unwrap_or_else(|_| bug!( + .unwrap_or_else(|_| { + bug!( "could not cast from reference to array to pointer to array ({:?} to {:?})", self.expr_ty, array_ptr_type, - )); + ) + }); // this will report a type mismatch if needed fcx.demand_eqtype(self.span, ety, m_cast.ty); @@ -740,6 +745,25 @@ impl<'a, 'tcx> CastCheck<'tcx> { Err(err) => Err(err), } } + + fn cenum_impl_drop_lint(&self, fcx: &FnCtxt<'a, 'tcx>) { + if let ty::Adt(d, _) = self.expr_ty.kind { + if d.has_dtor(fcx.tcx) { + fcx.tcx.struct_span_lint_hir( + lint::builtin::CENUM_IMPL_DROP_CAST, + self.expr.hir_id, + self.span, + |err| { + err.build(&format!( + "Cast `enum` implementing `Drop` `{}` to integer `{}`", + self.expr_ty, self.cast_ty + )) + .emit(); + }, + ); + } + } + } } impl<'a, 'tcx> FnCtxt<'a, 'tcx> { From a40156e5b7053dcc36ba1ad65fb567b183c4e1fb Mon Sep 17 00:00:00 2001 From: oddg Date: Sun, 14 Jun 2020 15:49:20 -0700 Subject: [PATCH 21/42] UI test for deprecation warning of casting enum implementing Drop --- src/test/ui/cenum_impl_drop_cast.rs | 18 ++++++++++++++++++ src/test/ui/cenum_impl_drop_cast.stderr | 16 ++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/test/ui/cenum_impl_drop_cast.rs create mode 100644 src/test/ui/cenum_impl_drop_cast.stderr diff --git a/src/test/ui/cenum_impl_drop_cast.rs b/src/test/ui/cenum_impl_drop_cast.rs new file mode 100644 index 0000000000000..623460673bfa2 --- /dev/null +++ b/src/test/ui/cenum_impl_drop_cast.rs @@ -0,0 +1,18 @@ +#![deny(cenum_impl_drop_cast)] + +enum E { + A = 0, +} + +impl Drop for E { + fn drop(&mut self) { + println!("Drop"); + } +} + +fn main() { + let e = E::A; + let i = e as u32; + //~^ ERROR Cast `enum` implementing `Drop` `E` to integer `u32` + //~| WARN this was previously accepted +} diff --git a/src/test/ui/cenum_impl_drop_cast.stderr b/src/test/ui/cenum_impl_drop_cast.stderr new file mode 100644 index 0000000000000..5c8f86ffd72ad --- /dev/null +++ b/src/test/ui/cenum_impl_drop_cast.stderr @@ -0,0 +1,16 @@ +error: Cast `enum` implementing `Drop` `E` to integer `u32` + --> $DIR/cenum_impl_drop_cast.rs:15:13 + | +LL | let i = e as u32; + | ^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/cenum_impl_drop_cast.rs:1:9 + | +LL | #![deny(cenum_impl_drop_cast)] + | ^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #73333 + +error: aborting due to previous error + From 607e85110ef9c79ce5a52286bb69d385471bc675 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sun, 14 Jun 2020 15:57:21 -0700 Subject: [PATCH 22/42] Switch bootstrap metadata to --no-deps. This should run much faster. There are also some drive-by cleanups here to try to simplify things. Also, the paths for in-tree crates are now displayed as relative in `x.py test -h -v`. --- src/bootstrap/builder.rs | 6 +++-- src/bootstrap/doc.rs | 20 ++------------ src/bootstrap/lib.rs | 25 +++++++++++------- src/bootstrap/metadata.rs | 55 +++++++++------------------------------ src/bootstrap/test.rs | 8 ++---- 5 files changed, 37 insertions(+), 77 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index ffdd8485181f4..345af600c2adb 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -255,7 +255,8 @@ impl<'a> ShouldRun<'a> { pub fn all_krates(mut self, name: &str) -> Self { let mut set = BTreeSet::new(); for krate in self.builder.in_tree_crates(name) { - set.insert(PathBuf::from(&krate.path)); + let path = krate.local_path(self.builder); + set.insert(path); } self.paths.insert(PathSet::Set(set)); self @@ -263,7 +264,8 @@ impl<'a> ShouldRun<'a> { pub fn krate(mut self, name: &str) -> Self { for krate in self.builder.in_tree_crates(name) { - self.paths.insert(PathSet::one(&krate.path)); + let path = krate.local_path(self.builder); + self.paths.insert(PathSet::one(path)); } self } diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 5c01c5e852c48..6d7fb7acfcb04 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -548,8 +548,8 @@ impl Step for Rustc { // Find dependencies for top level crates. let mut compiler_crates = HashSet::new(); for root_crate in &["rustc_driver", "rustc_codegen_llvm", "rustc_codegen_ssa"] { - let interned_root_crate = INTERNER.intern_str(root_crate); - find_compiler_crates(builder, &interned_root_crate, &mut compiler_crates); + compiler_crates + .extend(builder.in_tree_crates(root_crate).into_iter().map(|krate| krate.name)); } for krate in &compiler_crates { @@ -564,22 +564,6 @@ impl Step for Rustc { } } -fn find_compiler_crates( - builder: &Builder<'_>, - name: &Interned, - crates: &mut HashSet>, -) { - // Add current crate. - crates.insert(*name); - - // Look for dependencies. - for dep in builder.crates.get(name).unwrap().deps.iter() { - if builder.crates.get(dep).unwrap().is_local(builder) { - find_compiler_crates(builder, dep, crates); - } - } -} - #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct Rustdoc { stage: u32, diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index a125b49fc01e6..9d3830da39066 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -270,12 +270,7 @@ struct Crate { } impl Crate { - fn is_local(&self, build: &Build) -> bool { - self.path.starts_with(&build.config.src) - } - fn local_path(&self, build: &Build) -> PathBuf { - assert!(self.is_local(build)); self.path.strip_prefix(&build.config.src).unwrap().into() } } @@ -1079,17 +1074,29 @@ impl Build { } } + /// Returns a Vec of all the dependencies of the given root crate, + /// including transitive dependencies and the root itself. Only includes + /// "local" crates (those in the local source tree, not from a registry). fn in_tree_crates(&self, root: &str) -> Vec<&Crate> { let mut ret = Vec::new(); let mut list = vec![INTERNER.intern_str(root)]; let mut visited = HashSet::new(); while let Some(krate) = list.pop() { let krate = &self.crates[&krate]; - if krate.is_local(self) { - ret.push(krate); - } + ret.push(krate); for dep in &krate.deps { - if visited.insert(dep) && dep != "build_helper" { + // Don't include optional deps if their features are not + // enabled. Ideally this would be computed from `cargo + // metadata --features …`, but that is somewhat slow. Just + // skip `build_helper` since there aren't any operations we + // want to perform on it. In the future, we may want to + // consider just filtering all build and dev dependencies in + // metadata::build. + if visited.insert(dep) + && dep != "build_helper" + && (dep != "profiler_builtins" || self.config.profiler) + && (dep != "rustc_codegen_llvm" || self.config.llvm_enabled()) + { list.push(*dep); } } diff --git a/src/bootstrap/metadata.rs b/src/bootstrap/metadata.rs index 185f0ddb831e7..a38391c7b88f2 100644 --- a/src/bootstrap/metadata.rs +++ b/src/bootstrap/metadata.rs @@ -1,5 +1,3 @@ -use std::collections::HashMap; -use std::collections::HashSet; use std::path::PathBuf; use std::process::Command; @@ -12,7 +10,6 @@ use crate::{Build, Crate}; #[derive(Deserialize)] struct Output { packages: Vec, - resolve: Resolve, } #[derive(Deserialize)] @@ -21,38 +18,25 @@ struct Package { name: String, source: Option, manifest_path: String, + dependencies: Vec, } #[derive(Deserialize)] -struct Resolve { - nodes: Vec, -} - -#[derive(Deserialize)] -struct ResolveNode { - id: String, - dependencies: Vec, +struct Dependency { + name: String, + source: Option, } pub fn build(build: &mut Build) { // Run `cargo metadata` to figure out what crates we're testing. - let features: Vec<_> = build - .std_features() - .split_whitespace() - .map(|f| format!("test/{}", f)) - .chain(build.rustc_features().split_whitespace().map(|f| format!("rustc-main/{}", f))) - .collect(); let mut cargo = Command::new(&build.initial_cargo); cargo .arg("metadata") .arg("--format-version") .arg("1") - .arg("--features") - .arg(features.join(",")) - .arg("-Zpackage-features") + .arg("--no-deps") .arg("--manifest-path") - .arg(build.src.join("Cargo.toml")) - .env("RUSTC_BOOTSTRAP", "1"); + .arg(build.src.join("Cargo.toml")); let output = output(&mut cargo); let output: Output = serde_json::from_str(&output).unwrap(); for package in output.packages { @@ -60,26 +44,13 @@ pub fn build(build: &mut Build) { let name = INTERNER.intern_string(package.name); let mut path = PathBuf::from(package.manifest_path); path.pop(); - build.crates.insert(name, Crate { name, id: package.id, deps: HashSet::new(), path }); - } - } - - let id2name: HashMap<_, _> = - build.crates.iter().map(|(name, krate)| (krate.id.clone(), name.clone())).collect(); - - for node in output.resolve.nodes { - let name = match id2name.get(&node.id) { - Some(name) => name, - None => continue, - }; - - let krate = build.crates.get_mut(name).unwrap(); - for dep in node.dependencies.iter() { - let dep = match id2name.get(dep) { - Some(dep) => dep, - None => continue, - }; - krate.deps.insert(*dep); + let deps = package + .dependencies + .into_iter() + .filter(|dep| dep.source.is_none()) + .map(|dep| INTERNER.intern_string(dep.name)) + .collect(); + build.crates.insert(name, Crate { name, id: package.id, deps, path }); } } } diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 8659acf1cc5a5..c1d0316920be7 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1651,12 +1651,8 @@ impl Step for Crate { type Output = (); const DEFAULT: bool = true; - fn should_run(mut run: ShouldRun<'_>) -> ShouldRun<'_> { - let builder = run.builder; - for krate in run.builder.in_tree_crates("test") { - run = run.path(krate.local_path(&builder).to_str().unwrap()); - } - run + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.krate("test") } fn make_run(run: RunConfig<'_>) { From c2b920fab328201a2b5507b9a484c8c09752af93 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sun, 14 Jun 2020 16:58:45 -0700 Subject: [PATCH 23/42] Show suite paths (`src/test/ui/...`) in help output. --- src/bootstrap/builder.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 345af600c2adb..545ad64ba2cf6 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -489,13 +489,19 @@ impl<'a> Builder<'a> { should_run = (desc.should_run)(should_run); } let mut help = String::from("Available paths:\n"); + let mut add_path = |path: &Path| { + help.push_str(&format!(" ./x.py {} {}\n", subcommand, path.display())); + }; for pathset in should_run.paths { - if let PathSet::Set(set) = pathset { - set.iter().for_each(|path| { - help.push_str( - format!(" ./x.py {} {}\n", subcommand, path.display()).as_str(), - ) - }) + match pathset { + PathSet::Set(set) => { + for path in set { + add_path(&path); + } + } + PathSet::Suite(path) => { + add_path(&path.join("...")); + } } } Some(help) From f17fd7b0e692c59075db58ac2e7ca3ac2d5e19bd Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sun, 14 Jun 2020 17:00:34 -0700 Subject: [PATCH 24/42] Add some doc comments regarding PathSet. --- src/bootstrap/builder.rs | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 545ad64ba2cf6..c2f748f161f18 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -97,9 +97,21 @@ struct StepDescription { name: &'static str, } +/// Collection of paths used to match a task rule. #[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)] pub enum PathSet { + /// A collection of individual paths. + /// + /// These are generally matched as a path suffix. For example, a + /// command-line value of `libstd` will match if `src/libstd` is in the + /// set. Set(BTreeSet), + /// A "suite" of paths. + /// + /// These can match as a path suffix (like `Set`), or as a prefix. For + /// example, a command-line value of `src/test/ui/abi/variadic-ffi.rs` + /// will match `src/test/ui`. A command-line value of `ui` would also + /// match `src/test/ui`. Suite(PathBuf), } @@ -249,9 +261,15 @@ impl<'a> ShouldRun<'a> { self } - // Unlike `krate` this will create just one pathset. As such, it probably shouldn't actually - // ever be used, but as we transition to having all rules properly handle passing krate(...) by - // actually doing something different for every crate passed. + /// Indicates it should run if the command-line selects the given crate or + /// any of its (local) dependencies. + /// + /// Compared to `krate`, this treats the dependencies as aliases for the + /// same job. Generally it is preferred to use `krate`, and treat each + /// individual path separately. For example `./x.py test src/liballoc` + /// (which uses `krate`) will test just `liballoc`. However, `./x.py check + /// src/liballoc` (which uses `all_krates`) will check all of `libtest`. + /// `all_krates` should probably be removed at some point. pub fn all_krates(mut self, name: &str) -> Self { let mut set = BTreeSet::new(); for krate in self.builder.in_tree_crates(name) { @@ -262,6 +280,10 @@ impl<'a> ShouldRun<'a> { self } + /// Indicates it should run if the command-line selects the given crate or + /// any of its (local) dependencies. + /// + /// `make_run` will be called separately for each matching command-line path. pub fn krate(mut self, name: &str) -> Self { for krate in self.builder.in_tree_crates(name) { let path = krate.local_path(self.builder); From d6156e8fe5619143c687983d3ffa5b7ccc37c77e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 8 Jun 2020 09:02:57 -0700 Subject: [PATCH 25/42] Change how compiler-builtins gets many CGUs This commit intends to fix an accidental regression from #70846. The goal of #70846 was to build compiler-builtins with a maximal number of CGUs to ensure that each module in the source corresponds to an object file. This high degree of control for compiler-builtins is desirable to ensure that there's at most one exported symbol per CGU, ideally enabling compiler-builtins to not conflict with the system libgcc as often. In #70846, however, only part of the compiler understands that compiler-builtins is built with many CGUs. The rest of the compiler thinks it's building with `sess.codegen_units()`. Notably the calculation of `sess.lto()` consults `sess.codegen_units()`, which when there's only one CGU it disables ThinLTO. This means that compiler-builtins is built without ThinLTO, which is quite harmful to performance! This is the root of the cause from #73135 where intrinsics were found to not be inlining trivial functions. The fix applied in this commit is to remove the special-casing of compiler-builtins in the compiler. Instead the build system is now responsible for special-casing compiler-builtins. It doesn't know exactly how many CGUs will be needed but it passes a large number that is assumed to be much greater than the number of source-level modules needed. After reading the various locations in the compiler source, this seemed like the best solution rather than adding more and more special casing in the compiler for compiler-builtins. Closes #73135 --- Cargo.toml | 13 ++++++ src/librustc_mir/monomorphize/partitioning.rs | 9 +---- .../partitioning/compiler-builtins.rs | 40 ------------------- 3 files changed, 14 insertions(+), 48 deletions(-) delete mode 100644 src/test/codegen-units/partitioning/compiler-builtins.rs diff --git a/Cargo.toml b/Cargo.toml index f2177a99a9b88..f10d539d8296b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,19 @@ debug-assertions = false debug = false debug-assertions = false +[profile.release.package.compiler_builtins] +# For compiler-builtins we always use a high number of codegen units. +# The goal here is to place every single intrinsic into its own object +# file to avoid symbol clashes with the system libgcc if possible. Note +# that this number doesn't actually produce this many object files, we +# just don't create more than this number of object files. +# +# It's a bit of a bummer that we have to pass this here, unfortunately. +# Ideally this would be specified through an env var to Cargo so Cargo +# knows how many CGUs are for this specific crate, but for now +# per-crate configuration isn't specifiable in the environment. +codegen-units = 10000 + # We want the RLS to use the version of Cargo that we've got vendored in this # repository to ensure that the same exact version of Cargo is used by both the # RLS and the Cargo binary itself. The RLS depends on Cargo as a git repository diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs index db1ea72c0a531..a945c1d626a9a 100644 --- a/src/librustc_mir/monomorphize/partitioning.rs +++ b/src/librustc_mir/monomorphize/partitioning.rs @@ -454,18 +454,11 @@ fn default_visibility(tcx: TyCtxt<'_>, id: DefId, is_generic: bool) -> Visibilit fn merge_codegen_units<'tcx>( tcx: TyCtxt<'tcx>, initial_partitioning: &mut PreInliningPartitioning<'tcx>, - mut target_cgu_count: usize, + target_cgu_count: usize, ) { assert!(target_cgu_count >= 1); let codegen_units = &mut initial_partitioning.codegen_units; - if tcx.is_compiler_builtins(LOCAL_CRATE) { - // Compiler builtins require some degree of control over how mono items - // are partitioned into compilation units. Provide it by keeping the - // original partitioning when compiling the compiler builtins crate. - target_cgu_count = codegen_units.len(); - } - // Note that at this point in time the `codegen_units` here may not be in a // deterministic order (but we know they're deterministically the same set). // We want this merging to produce a deterministic ordering of codegen units diff --git a/src/test/codegen-units/partitioning/compiler-builtins.rs b/src/test/codegen-units/partitioning/compiler-builtins.rs deleted file mode 100644 index 25195743b0400..0000000000000 --- a/src/test/codegen-units/partitioning/compiler-builtins.rs +++ /dev/null @@ -1,40 +0,0 @@ -// Verifies that during compiler_builtins compilation the codegen units are kept -// unmerged. Even when only a single codegen unit is requested with -Ccodegen-units=1. -// -// compile-flags: -Zprint-mono-items=eager -Ccodegen-units=1 - -#![compiler_builtins] -#![crate_type="lib"] -#![feature(compiler_builtins)] - -mod atomics { - //~ MONO_ITEM fn compiler_builtins::atomics[0]::sync_1[0] @@ compiler_builtins-cgu.0[External] - #[no_mangle] - pub extern "C" fn sync_1() {} - - //~ MONO_ITEM fn compiler_builtins::atomics[0]::sync_2[0] @@ compiler_builtins-cgu.0[External] - #[no_mangle] - pub extern "C" fn sync_2() {} - - //~ MONO_ITEM fn compiler_builtins::atomics[0]::sync_3[0] @@ compiler_builtins-cgu.0[External] - #[no_mangle] - pub extern "C" fn sync_3() {} -} - -mod x { - //~ MONO_ITEM fn compiler_builtins::x[0]::x[0] @@ compiler_builtins-cgu.1[External] - #[no_mangle] - pub extern "C" fn x() {} -} - -mod y { - //~ MONO_ITEM fn compiler_builtins::y[0]::y[0] @@ compiler_builtins-cgu.2[External] - #[no_mangle] - pub extern "C" fn y() {} -} - -mod z { - //~ MONO_ITEM fn compiler_builtins::z[0]::z[0] @@ compiler_builtins-cgu.3[External] - #[no_mangle] - pub extern "C" fn z() {} -} From e857696cf8c3b4a4381d00424f165c10f93a9ebd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 14 Jun 2020 21:36:25 -0700 Subject: [PATCH 26/42] Tweak "non-primitive cast" error - Suggest borrowing expression if it would allow cast to work. - Suggest using `::from()` when appropriate. - Minor tweak to `;` typo suggestion. Partily address #47136. --- src/libcore/convert/mod.rs | 1 + src/librustc_parse/parser/diagnostics.rs | 2 +- src/librustc_span/symbol.rs | 1 + src/librustc_typeck/check/cast.rs | 107 ++++++++++++++---- src/test/ui/cast/cast-from-nil.stderr | 4 +- src/test/ui/cast/cast-to-bare-fn.stderr | 8 +- src/test/ui/cast/cast-to-nil.stderr | 4 +- ...-to-unsized-trait-object-suggestion.stderr | 2 +- src/test/ui/closures/closure-no-fn-3.stderr | 4 +- .../ui/coercion/coerce-to-bang-cast.stderr | 8 +- .../const-eval/const-eval-overflow-4b.stderr | 2 +- src/test/ui/error-codes/E0604.stderr | 2 +- src/test/ui/error-codes/E0605.stderr | 8 +- src/test/ui/error-festival.stderr | 6 +- src/test/ui/fat-ptr-cast.stderr | 4 +- src/test/ui/issues/issue-10991.stderr | 4 +- src/test/ui/issues/issue-16048.rs | 4 +- src/test/ui/issues/issue-16048.stderr | 8 +- src/test/ui/issues/issue-17441.stderr | 2 +- src/test/ui/issues/issue-22289.stderr | 7 +- src/test/ui/issues/issue-22312.rs | 2 +- src/test/ui/issues/issue-22312.stderr | 7 +- src/test/ui/issues/issue-2995.stderr | 4 +- src/test/ui/issues/issue-45730.stderr | 18 +-- .../ui/mismatched_types/cast-rfc0401.stderr | 22 +--- .../ui/mismatched_types/issue-26480.stderr | 3 +- src/test/ui/nonscalar-cast.fixed | 16 +++ src/test/ui/nonscalar-cast.rs | 8 ++ src/test/ui/nonscalar-cast.stderr | 6 +- .../ui/order-dependent-cast-inference.stderr | 6 +- .../ui/tag-variant-cast-non-nullary.fixed | 20 ++++ src/test/ui/tag-variant-cast-non-nullary.rs | 11 ++ .../ui/tag-variant-cast-non-nullary.stderr | 6 +- .../never_reveal_concrete_type.stderr | 4 +- .../uninhabited/uninhabited-enum-cast.stderr | 4 +- 35 files changed, 204 insertions(+), 121 deletions(-) create mode 100644 src/test/ui/nonscalar-cast.fixed create mode 100644 src/test/ui/tag-variant-cast-non-nullary.fixed diff --git a/src/libcore/convert/mod.rs b/src/libcore/convert/mod.rs index eef9ee7cb0093..8ff1ced53b071 100644 --- a/src/libcore/convert/mod.rs +++ b/src/libcore/convert/mod.rs @@ -374,6 +374,7 @@ pub trait Into: Sized { /// [`Into`]: trait.Into.html /// [`from`]: trait.From.html#tymethod.from /// [book]: ../../book/ch09-00-error-handling.html +#[rustc_diagnostic_item = "from_trait"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(on( all(_Self = "&str", T = "std::string::String"), diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs index 660a63841bcef..dafc0a9e048a4 100644 --- a/src/librustc_parse/parser/diagnostics.rs +++ b/src/librustc_parse/parser/diagnostics.rs @@ -961,7 +961,7 @@ impl<'a> Parser<'a> { self.bump(); let sp = self.prev_token.span; self.struct_span_err(sp, &msg) - .span_suggestion(sp, "change this to `;`", ";".to_string(), appl) + .span_suggestion_short(sp, "change this to `;`", ";".to_string(), appl) .emit(); return Ok(()); } else if self.look_ahead(0, |t| { diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index d165409696eca..9925e631c5c20 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -343,6 +343,7 @@ symbols! { from_method, from_ok, from_usize, + from_trait, fundamental, future, Future, diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 46d6706cbf429..bad009f4039af 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -43,6 +43,7 @@ use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, Ty, TypeAndMut, TypeFoldable}; use rustc_session::lint; use rustc_session::Session; +use rustc_span::symbol::sym; use rustc_span::Span; use rustc_trait_selection::traits; use rustc_trait_selection::traits::error_reporting::report_object_safety_error; @@ -333,10 +334,11 @@ impl<'a, 'tcx> CastCheck<'tcx> { "only `u8` can be cast as `char`, not `{}`", self.expr_ty ) + .span_label(self.span, "invalid cast") .emit(); } CastError::NonScalar => { - type_error_struct!( + let mut err = type_error_struct!( fcx.tcx.sess, self.span, self.expr_ty, @@ -344,12 +346,75 @@ impl<'a, 'tcx> CastCheck<'tcx> { "non-primitive cast: `{}` as `{}`", self.expr_ty, fcx.ty_to_string(self.cast_ty) - ) - .note( - "an `as` expression can only be used to convert between \ - primitive types. Consider using the `From` trait", - ) - .emit(); + ); + let mut sugg = None; + if let ty::Ref(reg, _, mutbl) = self.cast_ty.kind { + if fcx + .try_coerce( + self.expr, + fcx.tcx.mk_ref(reg, TypeAndMut { ty: self.expr_ty, mutbl }), + self.cast_ty, + AllowTwoPhase::No, + ) + .is_ok() + { + sugg = Some(format!("&{}", mutbl.prefix_str())); + } + } + if let Some(sugg) = sugg { + err.span_label(self.span, "invalid cast"); + err.span_suggestion_verbose( + self.expr.span.shrink_to_lo(), + "borrow the value for the cast to be valid", + sugg, + Applicability::MachineApplicable, + ); + } else if !matches!( + self.cast_ty.kind, + ty::FnDef(..) | ty::FnPtr(..) | ty::Closure(..) + ) { + let mut label = true; + // Check `impl From for self.cast_ty {}` for accurate suggestion: + if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) { + if let Some(from_trait) = fcx.tcx.get_diagnostic_item(sym::from_trait) { + let ty = fcx.resolve_vars_if_possible(&self.cast_ty); + // Erase regions to avoid panic in `prove_value` when calling + // `type_implements_trait`. + let ty = fcx.tcx.erase_regions(&ty); + let expr_ty = fcx.resolve_vars_if_possible(&self.expr_ty); + let expr_ty = fcx.tcx.erase_regions(&expr_ty); + let ty_params = fcx.tcx.mk_substs_trait(expr_ty, &[]); + // Check for infer types because cases like `Option<{integer}>` would + // panic otherwise. + if !expr_ty.has_infer_types() + && fcx.tcx.type_implements_trait(( + from_trait, + ty, + ty_params, + fcx.param_env, + )) + { + label = false; + err.span_suggestion( + self.span, + "consider using the `From` trait instead", + format!("{}::from({})", self.cast_ty, snippet), + Applicability::MaybeIncorrect, + ); + } + } + } + let msg = "an `as` expression can only be used to convert between primitive \ + types or to coerce to a specific trait object"; + if label { + err.span_label(self.span, msg); + } else { + err.note(msg); + } + } else { + err.span_label(self.span, "invalid cast"); + } + err.emit(); } CastError::SizedUnsizedCast => { use crate::structured_errors::{SizedUnsizedCastError, StructuredDiagnostic}; @@ -370,21 +435,22 @@ impl<'a, 'tcx> CastCheck<'tcx> { }; let mut err = struct_span_err!( fcx.tcx.sess, - self.span, + if unknown_cast_to { self.cast_span } else { self.span }, E0641, "cannot cast {} a pointer of an unknown kind", if unknown_cast_to { "to" } else { "from" } ); - err.note( - "the type information given here is insufficient to check whether \ - the pointer cast is valid", - ); if unknown_cast_to { - err.span_suggestion_short( - self.cast_span, - "consider giving more type information", - String::new(), - Applicability::Unspecified, + err.span_label(self.cast_span, "needs more type information"); + err.note( + "the type information given here is insufficient to check whether \ + the pointer cast is valid", + ); + } else { + err.span_label( + self.span, + "the type information given here is insufficient to check whether \ + the pointer cast is valid", ); } err.emit(); @@ -438,13 +504,16 @@ impl<'a, 'tcx> CastCheck<'tcx> { Ok(s) => { err.span_suggestion( self.cast_span, - "try casting to a `Box` instead", + "you can cast to a `Box` instead", format!("Box<{}>", s), Applicability::MachineApplicable, ); } Err(_) => { - err.span_help(self.cast_span, &format!("did you mean `Box<{}>`?", tstr)); + err.span_help( + self.cast_span, + &format!("you might have meant `Box<{}>`", tstr), + ); } } } diff --git a/src/test/ui/cast/cast-from-nil.stderr b/src/test/ui/cast/cast-from-nil.stderr index c8e3628a7ded8..dab133cfb4b67 100644 --- a/src/test/ui/cast/cast-from-nil.stderr +++ b/src/test/ui/cast/cast-from-nil.stderr @@ -2,9 +2,7 @@ error[E0605]: non-primitive cast: `()` as `u32` --> $DIR/cast-from-nil.rs:2:21 | LL | fn main() { let u = (assert!(true) as u32); } - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error: aborting due to previous error diff --git a/src/test/ui/cast/cast-to-bare-fn.stderr b/src/test/ui/cast/cast-to-bare-fn.stderr index 84933dca929a4..d97b0c5f8aadc 100644 --- a/src/test/ui/cast/cast-to-bare-fn.stderr +++ b/src/test/ui/cast/cast-to-bare-fn.stderr @@ -2,17 +2,13 @@ error[E0605]: non-primitive cast: `fn(isize) {foo}` as `extern "C" fn() -> isize --> $DIR/cast-to-bare-fn.rs:5:13 | LL | let x = foo as extern "C" fn() -> isize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast error[E0605]: non-primitive cast: `u64` as `fn(isize) -> (isize, isize)` --> $DIR/cast-to-bare-fn.rs:7:13 | LL | let y = v as extern "Rust" fn(isize) -> (isize, isize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast error: aborting due to 2 previous errors diff --git a/src/test/ui/cast/cast-to-nil.stderr b/src/test/ui/cast/cast-to-nil.stderr index 478f6b69dafc8..29a9baffd71d7 100644 --- a/src/test/ui/cast/cast-to-nil.stderr +++ b/src/test/ui/cast/cast-to-nil.stderr @@ -2,9 +2,7 @@ error[E0605]: non-primitive cast: `u32` as `()` --> $DIR/cast-to-nil.rs:2:21 | LL | fn main() { let u = 0u32 as (); } - | ^^^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error: aborting due to previous error diff --git a/src/test/ui/cast/cast-to-unsized-trait-object-suggestion.stderr b/src/test/ui/cast/cast-to-unsized-trait-object-suggestion.stderr index ffa02533d8b66..9b86f8d4def86 100644 --- a/src/test/ui/cast/cast-to-unsized-trait-object-suggestion.stderr +++ b/src/test/ui/cast/cast-to-unsized-trait-object-suggestion.stderr @@ -12,7 +12,7 @@ error[E0620]: cast to unsized type: `std::boxed::Box<{integer}>` as `dyn std::ma LL | Box::new(1) as dyn Send; | ^^^^^^^^^^^^^^^-------- | | - | help: try casting to a `Box` instead: `Box` + | help: you can cast to a `Box` instead: `Box` error: aborting due to 2 previous errors diff --git a/src/test/ui/closures/closure-no-fn-3.stderr b/src/test/ui/closures/closure-no-fn-3.stderr index ab6056b65473e..4b3b4be798fc1 100644 --- a/src/test/ui/closures/closure-no-fn-3.stderr +++ b/src/test/ui/closures/closure-no-fn-3.stderr @@ -2,9 +2,7 @@ error[E0605]: non-primitive cast: `[closure@$DIR/closure-no-fn-3.rs:6:27: 6:37 b --> $DIR/closure-no-fn-3.rs:6:27 | LL | let baz: fn() -> u8 = (|| { b }) as fn() -> u8; - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast error: aborting due to previous error diff --git a/src/test/ui/coercion/coerce-to-bang-cast.stderr b/src/test/ui/coercion/coerce-to-bang-cast.stderr index ff30ebc09c63a..d3adbd5158dbb 100644 --- a/src/test/ui/coercion/coerce-to-bang-cast.stderr +++ b/src/test/ui/coercion/coerce-to-bang-cast.stderr @@ -2,17 +2,13 @@ error[E0605]: non-primitive cast: `i32` as `!` --> $DIR/coerce-to-bang-cast.rs:6:13 | LL | let y = {return; 22} as !; - | ^^^^^^^^^^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error[E0605]: non-primitive cast: `i32` as `!` --> $DIR/coerce-to-bang-cast.rs:11:13 | LL | let y = 22 as !; - | ^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr b/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr index 5b2c4116c4b1d..e4d256c0ad192 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr @@ -16,7 +16,7 @@ error[E0604]: only `u8` can be cast as `char`, not `i8` --> $DIR/const-eval-overflow-4b.rs:25:13 | LL | : [u32; 5i8 as char as usize] - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ invalid cast error: aborting due to 3 previous errors diff --git a/src/test/ui/error-codes/E0604.stderr b/src/test/ui/error-codes/E0604.stderr index 5861bdcb7a953..18835310bd5e8 100644 --- a/src/test/ui/error-codes/E0604.stderr +++ b/src/test/ui/error-codes/E0604.stderr @@ -2,7 +2,7 @@ error[E0604]: only `u8` can be cast as `char`, not `u32` --> $DIR/E0604.rs:2:5 | LL | 1u32 as char; - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^ invalid cast error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0605.stderr b/src/test/ui/error-codes/E0605.stderr index 95e899db8b7e9..f23d2008e0b5f 100644 --- a/src/test/ui/error-codes/E0605.stderr +++ b/src/test/ui/error-codes/E0605.stderr @@ -2,17 +2,13 @@ error[E0605]: non-primitive cast: `u8` as `std::vec::Vec` --> $DIR/E0605.rs:3:5 | LL | x as Vec; - | ^^^^^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error[E0605]: non-primitive cast: `*const u8` as `&u8` --> $DIR/E0605.rs:6:5 | LL | v as &u8; - | ^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error: aborting due to 2 previous errors diff --git a/src/test/ui/error-festival.stderr b/src/test/ui/error-festival.stderr index 7f524230ef006..905195d4ad963 100644 --- a/src/test/ui/error-festival.stderr +++ b/src/test/ui/error-festival.stderr @@ -42,15 +42,13 @@ error[E0604]: only `u8` can be cast as `char`, not `u32` --> $DIR/error-festival.rs:25:5 | LL | 0u32 as char; - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^ invalid cast error[E0605]: non-primitive cast: `u8` as `std::vec::Vec` --> $DIR/error-festival.rs:29:5 | LL | x as Vec; - | ^^^^^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error[E0054]: cannot cast as `bool` --> $DIR/error-festival.rs:33:24 diff --git a/src/test/ui/fat-ptr-cast.stderr b/src/test/ui/fat-ptr-cast.stderr index 93e1471838f72..56d5a26beb04e 100644 --- a/src/test/ui/fat-ptr-cast.stderr +++ b/src/test/ui/fat-ptr-cast.stderr @@ -34,9 +34,7 @@ error[E0605]: non-primitive cast: `std::boxed::Box<[i32]>` as `usize` --> $DIR/fat-ptr-cast.rs:14:5 | LL | b as usize; - | ^^^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error[E0606]: casting `*const [i32]` as `usize` is invalid --> $DIR/fat-ptr-cast.rs:15:5 diff --git a/src/test/ui/issues/issue-10991.stderr b/src/test/ui/issues/issue-10991.stderr index f12539b47cf44..5b8a182338693 100644 --- a/src/test/ui/issues/issue-10991.stderr +++ b/src/test/ui/issues/issue-10991.stderr @@ -2,9 +2,7 @@ error[E0605]: non-primitive cast: `()` as `usize` --> $DIR/issue-10991.rs:3:14 | LL | let _t = nil as usize; - | ^^^^^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error: aborting due to previous error diff --git a/src/test/ui/issues/issue-16048.rs b/src/test/ui/issues/issue-16048.rs index 7d24f3a40a742..eaf6acff26bf3 100644 --- a/src/test/ui/issues/issue-16048.rs +++ b/src/test/ui/issues/issue-16048.rs @@ -18,12 +18,12 @@ impl<'a> Test<'a> for Foo<'a> { } impl<'a> NoLifetime for Foo<'a> { - fn get<'p, T : Test<'a>>(&self) -> T { + fn get<'p, T: Test<'a> + From>>(&self) -> T { //~^ ERROR E0195 //~| NOTE lifetimes do not match method in trait return *self as T; //~^ ERROR non-primitive cast: `Foo<'a>` as `T` - //~| NOTE an `as` expression can only be used to convert between primitive types. + //~| NOTE an `as` expression can only be used to convert between primitive types } } diff --git a/src/test/ui/issues/issue-16048.stderr b/src/test/ui/issues/issue-16048.stderr index a137bcdf1915e..73610942d7a7e 100644 --- a/src/test/ui/issues/issue-16048.stderr +++ b/src/test/ui/issues/issue-16048.stderr @@ -4,16 +4,16 @@ error[E0195]: lifetime parameters or bounds on method `get` do not match the tra LL | fn get<'p, T : Test<'p>>(&self) -> T; | ------------------ lifetimes in impl do not match this method in trait ... -LL | fn get<'p, T : Test<'a>>(&self) -> T { - | ^^^^^^^^^^^^^^^^^^ lifetimes do not match method in trait +LL | fn get<'p, T: Test<'a> + From>>(&self) -> T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetimes do not match method in trait error[E0605]: non-primitive cast: `Foo<'a>` as `T` --> $DIR/issue-16048.rs:24:16 | LL | return *self as T; - | ^^^^^^^^^^ + | ^^^^^^^^^^ help: consider using the `From` trait instead: `T::from(*self)` | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-17441.stderr b/src/test/ui/issues/issue-17441.stderr index 0ab035515a051..b63a3995d255d 100644 --- a/src/test/ui/issues/issue-17441.stderr +++ b/src/test/ui/issues/issue-17441.stderr @@ -16,7 +16,7 @@ error[E0620]: cast to unsized type: `std::boxed::Box` as `dyn std::fmt::D LL | let _bar = Box::new(1_usize) as dyn std::fmt::Debug; | ^^^^^^^^^^^^^^^^^^^^^------------------- | | - | help: try casting to a `Box` instead: `Box` + | help: you can cast to a `Box` instead: `Box` error[E0620]: cast to unsized type: `usize` as `dyn std::fmt::Debug` --> $DIR/issue-17441.rs:8:16 diff --git a/src/test/ui/issues/issue-22289.stderr b/src/test/ui/issues/issue-22289.stderr index cc7ace30cabef..4c35deb1fbe4e 100644 --- a/src/test/ui/issues/issue-22289.stderr +++ b/src/test/ui/issues/issue-22289.stderr @@ -2,9 +2,12 @@ error[E0605]: non-primitive cast: `i32` as `&(dyn std::any::Any + 'static)` --> $DIR/issue-22289.rs:2:5 | LL | 0 as &dyn std::any::Any; - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^ invalid cast | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait +help: borrow the value for the cast to be valid + | +LL | &0 as &dyn std::any::Any; + | ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-22312.rs b/src/test/ui/issues/issue-22312.rs index 250fec2588702..4e359b3412a71 100644 --- a/src/test/ui/issues/issue-22312.rs +++ b/src/test/ui/issues/issue-22312.rs @@ -1,6 +1,6 @@ use std::ops::Index; -pub trait Array2D: Index { +pub trait Array2D: Index + Sized { fn rows(&self) -> usize; fn columns(&self) -> usize; fn get<'a>(&'a self, y: usize, x: usize) -> Option<&'a >::Output> { diff --git a/src/test/ui/issues/issue-22312.stderr b/src/test/ui/issues/issue-22312.stderr index fc32fd376b75a..28564b074633b 100644 --- a/src/test/ui/issues/issue-22312.stderr +++ b/src/test/ui/issues/issue-22312.stderr @@ -2,9 +2,12 @@ error[E0605]: non-primitive cast: `Self` as `&dyn std::ops::Index $DIR/issue-22312.rs:11:24 | LL | let indexer = &(*self as &dyn Index>::Output>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait +help: borrow the value for the cast to be valid + | +LL | let indexer = &(&*self as &dyn Index>::Output>); + | ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-2995.stderr b/src/test/ui/issues/issue-2995.stderr index c316780d5f6a5..9f5968399a37d 100644 --- a/src/test/ui/issues/issue-2995.stderr +++ b/src/test/ui/issues/issue-2995.stderr @@ -2,9 +2,7 @@ error[E0605]: non-primitive cast: `*const isize` as `&isize` --> $DIR/issue-2995.rs:2:22 | LL | let _q: &isize = p as &isize; - | ^^^^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error: aborting due to previous error diff --git a/src/test/ui/issues/issue-45730.stderr b/src/test/ui/issues/issue-45730.stderr index d4ddba52df14a..d00f3d91b49da 100644 --- a/src/test/ui/issues/issue-45730.stderr +++ b/src/test/ui/issues/issue-45730.stderr @@ -1,30 +1,24 @@ error[E0641]: cannot cast to a pointer of an unknown kind - --> $DIR/issue-45730.rs:3:23 + --> $DIR/issue-45730.rs:3:28 | LL | let x: *const _ = 0 as _; - | ^^^^^- - | | - | help: consider giving more type information + | ^ needs more type information | = note: the type information given here is insufficient to check whether the pointer cast is valid error[E0641]: cannot cast to a pointer of an unknown kind - --> $DIR/issue-45730.rs:5:23 + --> $DIR/issue-45730.rs:5:28 | LL | let x: *const _ = 0 as *const _; - | ^^^^^-------- - | | - | help: consider giving more type information + | ^^^^^^^^ needs more type information | = note: the type information given here is insufficient to check whether the pointer cast is valid error[E0641]: cannot cast to a pointer of an unknown kind - --> $DIR/issue-45730.rs:8:13 + --> $DIR/issue-45730.rs:8:44 | LL | let x = 0 as *const i32 as *const _ as *mut _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------ - | | - | help: consider giving more type information + | ^^^^^^ needs more type information | = note: the type information given here is insufficient to check whether the pointer cast is valid diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr index f94dfd100a6f4..95936de218b8f 100644 --- a/src/test/ui/mismatched_types/cast-rfc0401.stderr +++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr @@ -24,41 +24,31 @@ error[E0605]: non-primitive cast: `*const u8` as `&u8` --> $DIR/cast-rfc0401.rs:29:13 | LL | let _ = v as &u8; - | ^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error[E0605]: non-primitive cast: `*const u8` as `E` --> $DIR/cast-rfc0401.rs:30:13 | LL | let _ = v as E; - | ^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error[E0605]: non-primitive cast: `*const u8` as `fn()` --> $DIR/cast-rfc0401.rs:31:13 | LL | let _ = v as fn(); - | ^^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^^^ invalid cast error[E0605]: non-primitive cast: `*const u8` as `(u32,)` --> $DIR/cast-rfc0401.rs:32:13 | LL | let _ = v as (u32,); - | ^^^^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error[E0605]: non-primitive cast: `std::option::Option<&*const u8>` as `*const u8` --> $DIR/cast-rfc0401.rs:33:13 | LL | let _ = Some(&v) as *const u8; - | ^^^^^^^^^^^^^^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error[E0606]: casting `*const u8` as `f32` is invalid --> $DIR/cast-rfc0401.rs:35:13 @@ -102,7 +92,7 @@ error[E0604]: only `u8` can be cast as `char`, not `u32` --> $DIR/cast-rfc0401.rs:41:13 | LL | let _ = 0x61u32 as char; - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ invalid cast error[E0606]: casting `bool` as `f32` is invalid --> $DIR/cast-rfc0401.rs:43:13 diff --git a/src/test/ui/mismatched_types/issue-26480.stderr b/src/test/ui/mismatched_types/issue-26480.stderr index 69a9d03e474ba..d39b0a3207763 100644 --- a/src/test/ui/mismatched_types/issue-26480.stderr +++ b/src/test/ui/mismatched_types/issue-26480.stderr @@ -17,12 +17,11 @@ error[E0605]: non-primitive cast: `{integer}` as `()` --> $DIR/issue-26480.rs:22:19 | LL | ($x:expr) => ($x as ()) - | ^^^^^^^^ + | ^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object ... LL | cast!(2); | --------- in this macro invocation | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors diff --git a/src/test/ui/nonscalar-cast.fixed b/src/test/ui/nonscalar-cast.fixed new file mode 100644 index 0000000000000..0a4b98469b2b6 --- /dev/null +++ b/src/test/ui/nonscalar-cast.fixed @@ -0,0 +1,16 @@ +// run-rustfix + +#[derive(Debug)] +struct Foo { + x: isize +} + +impl From for isize { + fn from(val: Foo) -> isize { + val.x + } +} + +fn main() { + println!("{}", isize::from(Foo { x: 1 })); //~ non-primitive cast: `Foo` as `isize` [E0605] +} diff --git a/src/test/ui/nonscalar-cast.rs b/src/test/ui/nonscalar-cast.rs index 7e6f1fd038fb7..59fcf09666b24 100644 --- a/src/test/ui/nonscalar-cast.rs +++ b/src/test/ui/nonscalar-cast.rs @@ -1,8 +1,16 @@ +// run-rustfix + #[derive(Debug)] struct Foo { x: isize } +impl From for isize { + fn from(val: Foo) -> isize { + val.x + } +} + fn main() { println!("{}", Foo { x: 1 } as isize); //~ non-primitive cast: `Foo` as `isize` [E0605] } diff --git a/src/test/ui/nonscalar-cast.stderr b/src/test/ui/nonscalar-cast.stderr index 9338688b037ff..2a7037121876d 100644 --- a/src/test/ui/nonscalar-cast.stderr +++ b/src/test/ui/nonscalar-cast.stderr @@ -1,10 +1,10 @@ error[E0605]: non-primitive cast: `Foo` as `isize` - --> $DIR/nonscalar-cast.rs:7:20 + --> $DIR/nonscalar-cast.rs:15:20 | LL | println!("{}", Foo { x: 1 } as isize); - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using the `From` trait instead: `isize::from(Foo { x: 1 })` | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error: aborting due to previous error diff --git a/src/test/ui/order-dependent-cast-inference.stderr b/src/test/ui/order-dependent-cast-inference.stderr index ad50b415869dd..9f4ac0fea36ef 100644 --- a/src/test/ui/order-dependent-cast-inference.stderr +++ b/src/test/ui/order-dependent-cast-inference.stderr @@ -1,10 +1,8 @@ error[E0641]: cannot cast to a pointer of an unknown kind - --> $DIR/order-dependent-cast-inference.rs:5:17 + --> $DIR/order-dependent-cast-inference.rs:5:22 | LL | let mut y = 0 as *const _; - | ^^^^^-------- - | | - | help: consider giving more type information + | ^^^^^^^^ needs more type information | = note: the type information given here is insufficient to check whether the pointer cast is valid diff --git a/src/test/ui/tag-variant-cast-non-nullary.fixed b/src/test/ui/tag-variant-cast-non-nullary.fixed new file mode 100644 index 0000000000000..53e68c2ac6af6 --- /dev/null +++ b/src/test/ui/tag-variant-cast-non-nullary.fixed @@ -0,0 +1,20 @@ +// run-rustfix +#![allow(dead_code, unused_variables)] +enum NonNullary { + Nullary, + Other(isize), +} + +impl From for isize { + fn from(val: NonNullary) -> isize { + match val { + NonNullary::Nullary => 0, + NonNullary::Other(i) => i, + } + } +} + +fn main() { + let v = NonNullary::Nullary; + let val = isize::from(v); //~ ERROR non-primitive cast: `NonNullary` as `isize` [E0605] +} diff --git a/src/test/ui/tag-variant-cast-non-nullary.rs b/src/test/ui/tag-variant-cast-non-nullary.rs index bb34e82cdca37..0d0c6188ad114 100644 --- a/src/test/ui/tag-variant-cast-non-nullary.rs +++ b/src/test/ui/tag-variant-cast-non-nullary.rs @@ -1,8 +1,19 @@ +// run-rustfix +#![allow(dead_code, unused_variables)] enum NonNullary { Nullary, Other(isize), } +impl From for isize { + fn from(val: NonNullary) -> isize { + match val { + NonNullary::Nullary => 0, + NonNullary::Other(i) => i, + } + } +} + fn main() { let v = NonNullary::Nullary; let val = v as isize; //~ ERROR non-primitive cast: `NonNullary` as `isize` [E0605] diff --git a/src/test/ui/tag-variant-cast-non-nullary.stderr b/src/test/ui/tag-variant-cast-non-nullary.stderr index 87ec20f20d789..ae2f5a7aead55 100644 --- a/src/test/ui/tag-variant-cast-non-nullary.stderr +++ b/src/test/ui/tag-variant-cast-non-nullary.stderr @@ -1,10 +1,10 @@ error[E0605]: non-primitive cast: `NonNullary` as `isize` - --> $DIR/tag-variant-cast-non-nullary.rs:8:15 + --> $DIR/tag-variant-cast-non-nullary.rs:19:15 | LL | let val = v as isize; - | ^^^^^^^^^^ + | ^^^^^^^^^^ help: consider using the `From` trait instead: `isize::from(v)` | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr b/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr index 70c99c944d654..360633bba622b 100644 --- a/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr +++ b/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr @@ -16,9 +16,7 @@ error[E0605]: non-primitive cast: `NoReveal` as `&'static str` --> $DIR/never_reveal_concrete_type.rs:14:13 | LL | let _ = x as &'static str; - | ^^^^^^^^^^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error: aborting due to 2 previous errors diff --git a/src/test/ui/uninhabited/uninhabited-enum-cast.stderr b/src/test/ui/uninhabited/uninhabited-enum-cast.stderr index a39af7832f8c9..a9f10dfec994a 100644 --- a/src/test/ui/uninhabited/uninhabited-enum-cast.stderr +++ b/src/test/ui/uninhabited/uninhabited-enum-cast.stderr @@ -2,9 +2,7 @@ error[E0605]: non-primitive cast: `E` as `isize` --> $DIR/uninhabited-enum-cast.rs:4:20 | LL | println!("{}", (e as isize).to_string()); - | ^^^^^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error: aborting due to previous error From 81c909488eebcba16610402349563380772e0d1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 29 May 2020 15:09:43 -0700 Subject: [PATCH 27/42] Suggest substituting `'static` lifetime in impl/dyn `Trait + 'static` return types --- .../nice_region_error/static_impl_trait.rs | 64 ++++++++-- src/librustc_middle/ty/context.rs | 13 +- src/librustc_middle/ty/diagnostics.rs | 8 +- ...t_outlive_least_region_or_bound.nll.stderr | 38 +++++- .../must_outlive_least_region_or_bound.rs | 21 ++++ .../must_outlive_least_region_or_bound.stderr | 117 ++++++++++++++++-- 6 files changed, 232 insertions(+), 29 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs index f4c86ddae604e..88d6c23d51441 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -4,6 +4,7 @@ use crate::infer::error_reporting::msg_span_from_free_region; use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; use rustc_errors::{Applicability, ErrorReported}; +use rustc_hir::{GenericBound, ItemKind, Lifetime, LifetimeName, TyKind}; use rustc_middle::ty::RegionKind; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { @@ -20,8 +21,9 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { ) = error.clone() { let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?; - let (fn_return_span, is_dyn) = - self.tcx().return_type_impl_or_dyn_trait(anon_reg_sup.def_id)?; + let fn_return = self.tcx().return_type_impl_or_dyn_trait(anon_reg_sup.def_id)?; + let is_dyn = matches!(fn_return.kind, TyKind::TraitObject(..)); + let fn_return_span = fn_return.span; if sub_r == &RegionKind::ReStatic { let sp = var_origin.span(); let return_sp = sub_origin.span(); @@ -67,12 +69,58 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { lifetime, ); // FIXME: account for the need of parens in `&(dyn Trait + '_)` - err.span_suggestion_verbose( - fn_return_span.shrink_to_hi(), - &msg, - format!(" + {}", lifetime_name), - Applicability::MaybeIncorrect, - ); + match fn_return.kind { + TyKind::Def(item_id, _) => { + let item = self.tcx().hir().item(item_id.id); + let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind { + opaque + } else { + err.emit(); + return Some(ErrorReported); + }; + let (span, sugg) = opaque + .bounds + .iter() + .filter_map(|arg| match arg { + GenericBound::Outlives(Lifetime { + name: LifetimeName::Static, + span, + .. + }) => Some((*span, lifetime_name.clone())), + _ => None, + }) + .next() + .unwrap_or_else(|| { + ( + fn_return_span.shrink_to_hi(), + format!(" + {}", lifetime_name), + ) + }); + + err.span_suggestion_verbose( + span, + &msg, + sugg, + Applicability::MaybeIncorrect, + ); + } + TyKind::TraitObject(_, lt) => { + let (span, sugg) = match lt.name { + LifetimeName::ImplicitObjectLifetimeDefault => ( + fn_return_span.shrink_to_hi(), + format!(" + {}", lifetime_name), + ), + _ => (lt.span, lifetime_name), + }; + err.span_suggestion_verbose( + span, + &msg, + sugg, + Applicability::MaybeIncorrect, + ); + } + _ => {} + } } err.emit(); return Some(ErrorReported); diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index d5be3508d2d80..4770993d9cb07 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -1383,7 +1383,10 @@ impl<'tcx> TyCtxt<'tcx> { }) } - pub fn return_type_impl_or_dyn_trait(&self, scope_def_id: DefId) -> Option<(Span, bool)> { + pub fn return_type_impl_or_dyn_trait( + &self, + scope_def_id: DefId, + ) -> Option<&'tcx hir::Ty<'tcx>> { let hir_id = self.hir().as_local_hir_id(scope_def_id.expect_local()); let hir_output = match self.hir().get(hir_id) { Node::Item(hir::Item { @@ -1429,15 +1432,17 @@ impl<'tcx> TyCtxt<'tcx> { let output = self.erase_late_bound_regions(&sig.output()); if output.is_impl_trait() { let fn_decl = self.hir().fn_decl_by_hir_id(hir_id).unwrap(); - Some((fn_decl.output.span(), false)) + if let hir::FnRetTy::Return(ty) = fn_decl.output { + return Some(ty); + } } else { let mut v = TraitObjectVisitor(vec![]); rustc_hir::intravisit::walk_ty(&mut v, hir_output); if v.0.len() == 1 { - return Some((v.0[0], true)); + return Some(v.0[0]); } - None } + None } _ => None, } diff --git a/src/librustc_middle/ty/diagnostics.rs b/src/librustc_middle/ty/diagnostics.rs index 2e9aa724ac5af..3ca506fe0d590 100644 --- a/src/librustc_middle/ty/diagnostics.rs +++ b/src/librustc_middle/ty/diagnostics.rs @@ -236,21 +236,21 @@ pub fn suggest_constraining_type_param( } } -pub struct TraitObjectVisitor(pub Vec); -impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor { +pub struct TraitObjectVisitor<'tcx>(pub Vec<&'tcx hir::Ty<'tcx>>); +impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> { type Map = rustc_hir::intravisit::ErasedMap<'v>; fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap { hir::intravisit::NestedVisitorMap::None } - fn visit_ty(&mut self, ty: &hir::Ty<'_>) { + fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) { if let hir::TyKind::TraitObject( _, hir::Lifetime { name: hir::LifetimeName::ImplicitObjectLifetimeDefault, .. }, ) = ty.kind { - self.0.push(ty.span); + self.0.push(ty); } } } diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr index 1806d2607a3ac..ca9ca8a9debe2 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr @@ -26,7 +26,34 @@ LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x } | ^^^^^^^^^^^^^^ error: lifetime may not live long enough - --> $DIR/must_outlive_least_region_or_bound.rs:12:69 + --> $DIR/must_outlive_least_region_or_bound.rs:9:46 + | +LL | fn elided2(x: &i32) -> impl Copy + 'static { x } + | - ^ returning this value requires that `'1` must outlive `'static` + | | + | let's call the lifetime of this reference `'1` + | + = help: consider replacing `'1` with `'static` + +error: lifetime may not live long enough + --> $DIR/must_outlive_least_region_or_bound.rs:12:55 + | +LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } + | -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static` + | + = help: consider replacing `'a` with `'static` + = help: consider replacing `'a` with `'static` + +error[E0621]: explicit lifetime required in the type of `x` + --> $DIR/must_outlive_least_region_or_bound.rs:15:41 + | +LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x } + | ---- ^ lifetime `'a` required + | | + | help: add explicit lifetime `'a` to the type of `x`: `&'a i32` + +error: lifetime may not live long enough + --> $DIR/must_outlive_least_region_or_bound.rs:33:69 | LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } | -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static` @@ -35,7 +62,7 @@ LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } = help: consider replacing `'a` with `'static` error: lifetime may not live long enough - --> $DIR/must_outlive_least_region_or_bound.rs:17:61 + --> $DIR/must_outlive_least_region_or_bound.rs:38:61 | LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) { | -- -- lifetime `'b` defined here ^^^^^^^^^^^^^^^^ opaque type requires that `'b` must outlive `'a` @@ -45,13 +72,14 @@ LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32 = help: consider adding the following bound: `'b: 'a` error[E0310]: the parameter type `T` may not live long enough - --> $DIR/must_outlive_least_region_or_bound.rs:22:51 + --> $DIR/must_outlive_least_region_or_bound.rs:43:51 | LL | fn ty_param_wont_outlive_static(x: T) -> impl Debug + 'static { | ^^^^^^^^^^^^^^^^^^^^ | = help: consider adding an explicit lifetime bound `T: 'static`... -error: aborting due to 5 previous errors +error: aborting due to 8 previous errors -For more information about this error, try `rustc --explain E0310`. +Some errors have detailed explanations: E0310, E0621. +For more information about an error, try `rustc --explain E0310`. diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs index 00f3490991b52..beafe9258209d 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs @@ -6,6 +6,27 @@ fn elided(x: &i32) -> impl Copy { x } fn explicit<'a>(x: &'a i32) -> impl Copy { x } //~^ ERROR cannot infer an appropriate lifetime +fn elided2(x: &i32) -> impl Copy + 'static { x } +//~^ ERROR cannot infer an appropriate lifetime + +fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } +//~^ ERROR cannot infer an appropriate lifetime + +fn foo<'a>(x: &i32) -> impl Copy + 'a { x } +//~^ ERROR explicit lifetime required in the type of `x` + +fn elided3(x: &i32) -> Box { Box::new(x) } +//~^ ERROR cannot infer an appropriate lifetime + +fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) } +//~^ ERROR cannot infer an appropriate lifetime + +fn elided4(x: &i32) -> Box { Box::new(x) } +//~^ ERROR explicit lifetime required in the type of `x` + +fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } +//~^ ERROR cannot infer an appropriate lifetime + trait LifetimeTrait<'a> {} impl<'a> LifetimeTrait<'a> for &'a i32 {} diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr index d7dae6a08a7b9..525e271bea9c3 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -27,7 +27,43 @@ LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x } | ^^^^ error: cannot infer an appropriate lifetime - --> $DIR/must_outlive_least_region_or_bound.rs:12:69 + --> $DIR/must_outlive_least_region_or_bound.rs:9:46 + | +LL | fn elided2(x: &i32) -> impl Copy + 'static { x } + | ---- ------------------- ^ ...and is captured here + | | | + | | ...is required to be `'static` by this... + | data with this lifetime... + | +help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 9:1 + | +LL | fn elided2(x: &i32) -> impl Copy + '_ { x } + | ^^ + +error: cannot infer an appropriate lifetime + --> $DIR/must_outlive_least_region_or_bound.rs:12:55 + | +LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } + | ------- ------------------- ^ ...and is captured here + | | | + | | ...is required to be `'static` by this... + | data with this lifetime... + | +help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the function body at 12:14 + | +LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'a { x } + | ^^ + +error[E0621]: explicit lifetime required in the type of `x` + --> $DIR/must_outlive_least_region_or_bound.rs:15:24 + | +LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x } + | ---- ^^^^^^^^^^^^^^ lifetime `'a` required + | | + | help: add explicit lifetime `'a` to the type of `x`: `&'a i32` + +error: cannot infer an appropriate lifetime + --> $DIR/must_outlive_least_region_or_bound.rs:33:69 | LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } | ------- -------------------------------- ^ ...and is captured here @@ -35,13 +71,13 @@ LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } | | ...is required to be `'static` by this... | data with this lifetime... | -help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the function body at 12:15 +help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the function body at 33:15 | -LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static + 'a { x } - | ^^^^ +LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'a { x } + | ^^ error[E0623]: lifetime mismatch - --> $DIR/must_outlive_least_region_or_bound.rs:17:61 + --> $DIR/must_outlive_least_region_or_bound.rs:38:61 | LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) { | ------- ^^^^^^^^^^^^^^^^ @@ -50,14 +86,79 @@ LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32 | this parameter and the return type are declared with different lifetimes... error[E0310]: the parameter type `T` may not live long enough - --> $DIR/must_outlive_least_region_or_bound.rs:22:51 + --> $DIR/must_outlive_least_region_or_bound.rs:43:51 | LL | fn ty_param_wont_outlive_static(x: T) -> impl Debug + 'static { | -- ^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds | | | help: consider adding an explicit lifetime bound...: `T: 'static +` -error: aborting due to 5 previous errors +error: cannot infer an appropriate lifetime + --> $DIR/must_outlive_least_region_or_bound.rs:18:50 + | +LL | fn elided3(x: &i32) -> Box { Box::new(x) } + | ---- ---------^- + | | | | + | | | ...and is captured here + | | ...is required to be `'static` by this... + | data with this lifetime... + | +help: to permit non-static references in a `dyn Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 18:1 + | +LL | fn elided3(x: &i32) -> Box { Box::new(x) } + | ^^^^ + +error: cannot infer an appropriate lifetime + --> $DIR/must_outlive_least_region_or_bound.rs:21:59 + | +LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) } + | ------- ---------^- + | | | | + | | | ...and is captured here + | | ...is required to be `'static` by this... + | data with this lifetime... + | +help: to permit non-static references in a `dyn Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the function body at 21:14 + | +LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) } + | ^^^^ + +error[E0621]: explicit lifetime required in the type of `x` + --> $DIR/must_outlive_least_region_or_bound.rs:24:51 + | +LL | fn elided4(x: &i32) -> Box { Box::new(x) } + | ---- ^^^^^^^^^^^ lifetime `'static` required + | | + | help: add explicit lifetime `'static` to the type of `x`: `&'static i32` + +error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements + --> $DIR/must_outlive_least_region_or_bound.rs:27:69 + | +LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } + | ^ + | +note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 27:14... + --> $DIR/must_outlive_least_region_or_bound.rs:27:14 + | +LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } + | ^^ +note: ...so that the expression is assignable + --> $DIR/must_outlive_least_region_or_bound.rs:27:69 + | +LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } + | ^ + = note: expected `&i32` + found `&'a i32` + = note: but, the lifetime must be valid for the static lifetime... +note: ...so that the expression is assignable + --> $DIR/must_outlive_least_region_or_bound.rs:27:60 + | +LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } + | ^^^^^^^^^^^ + = note: expected `std::boxed::Box<(dyn std::fmt::Debug + 'static)>` + found `std::boxed::Box` + +error: aborting due to 12 previous errors -Some errors have detailed explanations: E0310, E0623. +Some errors have detailed explanations: E0310, E0495, E0621, E0623. For more information about an error, try `rustc --explain E0310`. From 4e90f177cc530371a314f51f522a4c2e70885e03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 29 May 2020 18:05:20 -0700 Subject: [PATCH 28/42] When `'static` is explicit, suggest constraining argument with it --- .../infer/error_reporting/mod.rs | 3 +- .../nice_region_error/static_impl_trait.rs | 115 +++++++++++------- src/librustc_middle/ty/diagnostics.rs | 5 +- .../must_outlive_least_region_or_bound.rs | 2 +- .../must_outlive_least_region_or_bound.stderr | 75 +++++++----- src/test/ui/issues/issue-16922.stderr | 2 +- ...ect-lifetime-default-from-box-error.stderr | 2 +- ...ion-object-lifetime-in-coercion.nll.stderr | 19 ++- .../region-object-lifetime-in-coercion.rs | 5 +- .../region-object-lifetime-in-coercion.stderr | 61 +++++++--- .../regions-close-object-into-object-2.stderr | 32 ++--- .../regions-close-object-into-object-4.stderr | 32 ++--- .../regions-proc-bound-capture.nll.stderr | 11 ++ .../ui/regions/regions-proc-bound-capture.rs | 4 +- .../regions/regions-proc-bound-capture.stderr | 25 ++-- .../dyn-trait-underscore.stderr | 2 +- 16 files changed, 237 insertions(+), 158 deletions(-) create mode 100644 src/test/ui/regions/regions-proc-bound-capture.nll.stderr diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs index 12f7a9c0ca502..9cfa11dd7c813 100644 --- a/src/librustc_infer/infer/error_reporting/mod.rs +++ b/src/librustc_infer/infer/error_reporting/mod.rs @@ -2035,8 +2035,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.tcx.sess, var_origin.span(), E0495, - "cannot infer an appropriate lifetime{} \ - due to conflicting requirements", + "cannot infer an appropriate lifetime{} due to conflicting requirements", var_description ) } diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs index 88d6c23d51441..e24535bba5fdc 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -10,6 +10,7 @@ use rustc_middle::ty::RegionKind; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// Print the error message for lifetime errors when the return type is a static impl Trait. pub(super) fn try_report_static_impl_trait(&self) -> Option { + debug!("try_report_static_impl_trait(error={:?})", self.error); if let Some(ref error) = self.error { if let RegionResolutionError::SubSupConflict( _, @@ -18,19 +19,24 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { sub_r, sup_origin, sup_r, - ) = error.clone() + ) = error { + debug!( + "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})", + var_origin, sub_origin, sub_r, sup_origin, sup_r + ); let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?; + debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup); let fn_return = self.tcx().return_type_impl_or_dyn_trait(anon_reg_sup.def_id)?; - let is_dyn = matches!(fn_return.kind, TyKind::TraitObject(..)); - let fn_return_span = fn_return.span; - if sub_r == &RegionKind::ReStatic { + debug!("try_report_static_impl_trait: fn_return={:?}", fn_return); + if **sub_r == RegionKind::ReStatic { let sp = var_origin.span(); let return_sp = sub_origin.span(); + let param_info = self.find_param_with_region(sup_r, sub_r)?; let mut err = self.tcx().sess.struct_span_err(sp, "cannot infer an appropriate lifetime"); - let param_info = self.find_param_with_region(sup_r, sub_r)?; err.span_label(param_info.param_ty_span, "data with this lifetime..."); + debug!("try_report_static_impl_trait: param_info={:?}", param_info); // We try to make the output have fewer overlapping spans if possible. if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span())) @@ -60,14 +66,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { if sup_r.has_name() { sup_r.to_string() } else { "'_".to_owned() }; // only apply this suggestion onto functions with // explicit non-desugar'able return. - if fn_return_span.desugaring_kind().is_none() { - let msg = format!( - "to permit non-static references in {} `{} Trait` value, you can add \ - an explicit bound for {}", - if is_dyn { "a" } else { "an" }, - if is_dyn { "dyn" } else { "impl" }, - lifetime, - ); + if fn_return.span.desugaring_kind().is_none() { // FIXME: account for the need of parens in `&(dyn Trait + '_)` match fn_return.kind { TyKind::Def(item_id, _) => { @@ -78,7 +77,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { err.emit(); return Some(ErrorReported); }; - let (span, sugg) = opaque + + if let Some(span) = opaque .bounds .iter() .filter_map(|arg| match arg { @@ -86,38 +86,71 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { name: LifetimeName::Static, span, .. - }) => Some((*span, lifetime_name.clone())), + }) => Some(*span), _ => None, }) .next() - .unwrap_or_else(|| { - ( - fn_return_span.shrink_to_hi(), - format!(" + {}", lifetime_name), - ) - }); - - err.span_suggestion_verbose( - span, - &msg, - sugg, - Applicability::MaybeIncorrect, - ); - } - TyKind::TraitObject(_, lt) => { - let (span, sugg) = match lt.name { - LifetimeName::ImplicitObjectLifetimeDefault => ( - fn_return_span.shrink_to_hi(), + { + err.span_suggestion_verbose( + span, + "consider changing the `impl Trait`'s explicit \ + `'static` bound", + lifetime_name, + Applicability::MaybeIncorrect, + ); + err.span_suggestion_verbose( + param_info.param_ty_span, + "alternatively, set an explicit `'static` lifetime to \ + this parameter", + param_info.param_ty.to_string(), + Applicability::MaybeIncorrect, + ); + } else { + err.span_suggestion_verbose( + fn_return.span.shrink_to_hi(), + &format!( + "to permit non-static references in an `impl Trait` \ + value, you can add an explicit bound for {}", + lifetime, + ), format!(" + {}", lifetime_name), - ), - _ => (lt.span, lifetime_name), + Applicability::MaybeIncorrect, + ); }; - err.span_suggestion_verbose( - span, - &msg, - sugg, - Applicability::MaybeIncorrect, - ); + } + TyKind::TraitObject(_, lt) => { + match lt.name { + LifetimeName::ImplicitObjectLifetimeDefault => { + err.span_suggestion_verbose( + fn_return.span.shrink_to_hi(), + &format!( + "to permit non-static references in a trait object \ + value, you can add an explicit bound for {}", + lifetime, + ), + format!(" + {}", lifetime_name), + Applicability::MaybeIncorrect, + ); + } + _ => { + err.span_suggestion_verbose( + lt.span, + "consider changing the trait object's explicit \ + `'static` bound", + lifetime_name, + Applicability::MaybeIncorrect, + ); + err.span_suggestion_verbose( + param_info.param_ty_span, + &format!( + "alternatively, set an explicit `'static` lifetime \ + in this parameter", + ), + param_info.param_ty.to_string(), + Applicability::MaybeIncorrect, + ); + } + } } _ => {} } diff --git a/src/librustc_middle/ty/diagnostics.rs b/src/librustc_middle/ty/diagnostics.rs index 3ca506fe0d590..a2812e117ed39 100644 --- a/src/librustc_middle/ty/diagnostics.rs +++ b/src/librustc_middle/ty/diagnostics.rs @@ -247,7 +247,10 @@ impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> { fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) { if let hir::TyKind::TraitObject( _, - hir::Lifetime { name: hir::LifetimeName::ImplicitObjectLifetimeDefault, .. }, + hir::Lifetime { + name: hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static, + .. + }, ) = ty.kind { self.0.push(ty); diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs index beafe9258209d..837244b022721 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs @@ -22,7 +22,7 @@ fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) } //~^ ERROR cannot infer an appropriate lifetime fn elided4(x: &i32) -> Box { Box::new(x) } -//~^ ERROR explicit lifetime required in the type of `x` +//~^ ERROR cannot infer an appropriate lifetime fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } //~^ ERROR cannot infer an appropriate lifetime diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr index 525e271bea9c3..96d4a121c16af 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -35,10 +35,14 @@ LL | fn elided2(x: &i32) -> impl Copy + 'static { x } | | ...is required to be `'static` by this... | data with this lifetime... | -help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 9:1 +help: consider changing the `impl Trait`'s explicit `'static` bound | LL | fn elided2(x: &i32) -> impl Copy + '_ { x } | ^^ +help: alternatively, set an explicit `'static` lifetime to this parameter + | +LL | fn elided2(x: &'static i32) -> impl Copy + 'static { x } + | ^^^^^^^^^^^^ error: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:12:55 @@ -49,10 +53,14 @@ LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } | | ...is required to be `'static` by this... | data with this lifetime... | -help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the function body at 12:14 +help: consider changing the `impl Trait`'s explicit `'static` bound | LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'a { x } | ^^ +help: alternatively, set an explicit `'static` lifetime to this parameter + | +LL | fn explicit2<'a>(x: &'static i32) -> impl Copy + 'static { x } + | ^^^^^^^^^^^^ error[E0621]: explicit lifetime required in the type of `x` --> $DIR/must_outlive_least_region_or_bound.rs:15:24 @@ -71,10 +79,14 @@ LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } | | ...is required to be `'static` by this... | data with this lifetime... | -help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the function body at 33:15 +help: consider changing the `impl Trait`'s explicit `'static` bound | LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'a { x } | ^^ +help: alternatively, set an explicit `'static` lifetime to this parameter + | +LL | fn with_bound<'a>(x: &'static i32) -> impl LifetimeTrait<'a> + 'static { x } + | ^^^^^^^^^^^^ error[E0623]: lifetime mismatch --> $DIR/must_outlive_least_region_or_bound.rs:38:61 @@ -103,7 +115,7 @@ LL | fn elided3(x: &i32) -> Box { Box::new(x) } | | ...is required to be `'static` by this... | data with this lifetime... | -help: to permit non-static references in a `dyn Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 18:1 +help: to permit non-static references in a trait object value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 18:1 | LL | fn elided3(x: &i32) -> Box { Box::new(x) } | ^^^^ @@ -118,47 +130,48 @@ LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) } | | ...is required to be `'static` by this... | data with this lifetime... | -help: to permit non-static references in a `dyn Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the function body at 21:14 +help: to permit non-static references in a trait object value, you can add an explicit bound for the lifetime `'a` as defined on the function body at 21:14 | LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) } | ^^^^ -error[E0621]: explicit lifetime required in the type of `x` - --> $DIR/must_outlive_least_region_or_bound.rs:24:51 +error: cannot infer an appropriate lifetime + --> $DIR/must_outlive_least_region_or_bound.rs:24:60 | LL | fn elided4(x: &i32) -> Box { Box::new(x) } - | ---- ^^^^^^^^^^^ lifetime `'static` required - | | - | help: add explicit lifetime `'static` to the type of `x`: `&'static i32` - -error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements - --> $DIR/must_outlive_least_region_or_bound.rs:27:69 + | ---- ---------^- + | | | | + | | | ...and is captured here + | data with this lifetime... ...is required to be `'static` by this... | -LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } - | ^ +help: consider changing the trait object's explicit `'static` bound | -note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 27:14... - --> $DIR/must_outlive_least_region_or_bound.rs:27:14 +LL | fn elided4(x: &i32) -> Box { Box::new(x) } + | ^^ +help: alternatively, set an explicit `'static` lifetime in this parameter | -LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } - | ^^ -note: ...so that the expression is assignable +LL | fn elided4(x: &'static i32) -> Box { Box::new(x) } + | ^^^^^^^^^^^^ + +error: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:27:69 | LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } - | ^ - = note: expected `&i32` - found `&'a i32` - = note: but, the lifetime must be valid for the static lifetime... -note: ...so that the expression is assignable - --> $DIR/must_outlive_least_region_or_bound.rs:27:60 + | ------- ---------^- + | | | | + | | | ...and is captured here + | data with this lifetime... ...is required to be `'static` by this... | -LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } - | ^^^^^^^^^^^ - = note: expected `std::boxed::Box<(dyn std::fmt::Debug + 'static)>` - found `std::boxed::Box` +help: consider changing the trait object's explicit `'static` bound + | +LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } + | ^^ +help: alternatively, set an explicit `'static` lifetime in this parameter + | +LL | fn explicit4<'a>(x: &'static i32) -> Box { Box::new(x) } + | ^^^^^^^^^^^^ error: aborting due to 12 previous errors -Some errors have detailed explanations: E0310, E0495, E0621, E0623. +Some errors have detailed explanations: E0310, E0621, E0623. For more information about an error, try `rustc --explain E0310`. diff --git a/src/test/ui/issues/issue-16922.stderr b/src/test/ui/issues/issue-16922.stderr index 02d33aae023ff..038df47e1bd98 100644 --- a/src/test/ui/issues/issue-16922.stderr +++ b/src/test/ui/issues/issue-16922.stderr @@ -9,7 +9,7 @@ LL | Box::new(value) as Box | | ...and is captured here | ...is required to be `'static` by this... | -help: to permit non-static references in a `dyn Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 3:1 +help: to permit non-static references in a trait object value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 3:1 | LL | fn foo(value: &T) -> Box { | ^^^^ diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr index 70a9bf22b8db3..555622c9d13c1 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr @@ -7,7 +7,7 @@ LL | fn load(ss: &mut SomeStruct) -> Box { LL | ss.r | ^^^^ ...is captured and required to be `'static` here | -help: to permit non-static references in a `dyn Trait` value, you can add an explicit bound for the anonymous lifetime #2 defined on the function body at 14:1 +help: to permit non-static references in a trait object value, you can add an explicit bound for the anonymous lifetime #2 defined on the function body at 14:1 | LL | fn load(ss: &mut SomeStruct) -> Box { | ^^^^ diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr index bf02ba8eb9199..7e8f78067e08a 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr @@ -1,21 +1,21 @@ -error[E0621]: explicit lifetime required in the type of `v` +error: lifetime may not live long enough --> $DIR/region-object-lifetime-in-coercion.rs:8:12 | LL | fn a(v: &[u8]) -> Box { - | ----- help: add explicit lifetime `'static` to the type of `v`: `&'static [u8]` + | - let's call the lifetime of this reference `'1` LL | let x: Box = Box::new(v); - | ^^^^^^^^^^^^^^^^^^^^^^ lifetime `'static` required + | ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'1` must outlive `'static` -error[E0621]: explicit lifetime required in the type of `v` - --> $DIR/region-object-lifetime-in-coercion.rs:14:5 +error: lifetime may not live long enough + --> $DIR/region-object-lifetime-in-coercion.rs:13:5 | LL | fn b(v: &[u8]) -> Box { - | ----- help: add explicit lifetime `'static` to the type of `v`: `&'static [u8]` + | - let's call the lifetime of this reference `'1` LL | Box::new(v) - | ^^^^^^^^^^^ lifetime `'static` required + | ^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static` error: lifetime may not live long enough - --> $DIR/region-object-lifetime-in-coercion.rs:20:5 + --> $DIR/region-object-lifetime-in-coercion.rs:19:5 | LL | fn c(v: &[u8]) -> Box { | - let's call the lifetime of this reference `'1` @@ -24,7 +24,7 @@ LL | Box::new(v) | ^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static` error: lifetime may not live long enough - --> $DIR/region-object-lifetime-in-coercion.rs:24:5 + --> $DIR/region-object-lifetime-in-coercion.rs:23:5 | LL | fn d<'a,'b>(v: &'a [u8]) -> Box { | -- -- lifetime `'b` defined here @@ -37,4 +37,3 @@ LL | Box::new(v) error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.rs b/src/test/ui/regions/region-object-lifetime-in-coercion.rs index d56eaf77b6646..5d199149c39b8 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.rs +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.rs @@ -5,13 +5,12 @@ trait Foo {} impl<'a> Foo for &'a [u8] {} fn a(v: &[u8]) -> Box { - let x: Box = Box::new(v); - //~^ ERROR explicit lifetime required in the type of `v` [E0621] + let x: Box = Box::new(v); //~ ERROR cannot infer an appropriate lifetime x } fn b(v: &[u8]) -> Box { - Box::new(v) //~ ERROR explicit lifetime required in the type of `v` [E0621] + Box::new(v) //~ ERROR cannot infer an appropriate lifetime } fn c(v: &[u8]) -> Box { diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr index 1462af44cb15a..673300cebc26c 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr @@ -1,21 +1,45 @@ -error[E0621]: explicit lifetime required in the type of `v` - --> $DIR/region-object-lifetime-in-coercion.rs:8:37 +error: cannot infer an appropriate lifetime + --> $DIR/region-object-lifetime-in-coercion.rs:8:46 | LL | fn a(v: &[u8]) -> Box { - | ----- help: add explicit lifetime `'static` to the type of `v`: `&'static [u8]` + | ----- data with this lifetime... LL | let x: Box = Box::new(v); - | ^^^^^^^^^^^ lifetime `'static` required + | ---------^- + | | | + | | ...and is captured here + | ...is required to be `'static` by this... + | +help: consider changing the trait object's explicit `'static` bound + | +LL | fn a(v: &[u8]) -> Box { + | ^^ +help: alternatively, set an explicit `'static` lifetime in this parameter + | +LL | fn a(v: &'static [u8]) -> Box { + | ^^^^^^^^^^^^^ -error[E0621]: explicit lifetime required in the type of `v` - --> $DIR/region-object-lifetime-in-coercion.rs:14:5 +error: cannot infer an appropriate lifetime + --> $DIR/region-object-lifetime-in-coercion.rs:13:14 | LL | fn b(v: &[u8]) -> Box { - | ----- help: add explicit lifetime `'static` to the type of `v`: `&'static [u8]` + | ----- data with this lifetime... LL | Box::new(v) - | ^^^^^^^^^^^ lifetime `'static` required + | ---------^- + | | | + | | ...and is captured here + | ...is required to be `'static` by this... + | +help: consider changing the trait object's explicit `'static` bound + | +LL | fn b(v: &[u8]) -> Box { + | ^^ +help: alternatively, set an explicit `'static` lifetime in this parameter + | +LL | fn b(v: &'static [u8]) -> Box { + | ^^^^^^^^^^^^^ error: cannot infer an appropriate lifetime - --> $DIR/region-object-lifetime-in-coercion.rs:20:14 + --> $DIR/region-object-lifetime-in-coercion.rs:19:14 | LL | fn c(v: &[u8]) -> Box { | ----- data with this lifetime... @@ -26,36 +50,36 @@ LL | Box::new(v) | | ...and is captured here | ...is required to be `'static` by this... | -help: to permit non-static references in a `dyn Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 17:1 +help: to permit non-static references in a trait object value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 16:1 | LL | fn c(v: &[u8]) -> Box { | ^^^^ error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements - --> $DIR/region-object-lifetime-in-coercion.rs:24:14 + --> $DIR/region-object-lifetime-in-coercion.rs:23:14 | LL | Box::new(v) | ^ | -note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 23:6... - --> $DIR/region-object-lifetime-in-coercion.rs:23:6 +note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 22:6... + --> $DIR/region-object-lifetime-in-coercion.rs:22:6 | LL | fn d<'a,'b>(v: &'a [u8]) -> Box { | ^^ note: ...so that the expression is assignable - --> $DIR/region-object-lifetime-in-coercion.rs:24:14 + --> $DIR/region-object-lifetime-in-coercion.rs:23:14 | LL | Box::new(v) | ^ = note: expected `&[u8]` found `&'a [u8]` -note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 23:9... - --> $DIR/region-object-lifetime-in-coercion.rs:23:9 +note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 22:9... + --> $DIR/region-object-lifetime-in-coercion.rs:22:9 | LL | fn d<'a,'b>(v: &'a [u8]) -> Box { | ^^ note: ...so that the expression is assignable - --> $DIR/region-object-lifetime-in-coercion.rs:24:5 + --> $DIR/region-object-lifetime-in-coercion.rs:23:5 | LL | Box::new(v) | ^^^^^^^^^^^ @@ -64,5 +88,4 @@ LL | Box::new(v) error: aborting due to 4 previous errors -Some errors have detailed explanations: E0495, E0621. -For more information about an error, try `rustc --explain E0495`. +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-close-object-into-object-2.stderr b/src/test/ui/regions/regions-close-object-into-object-2.stderr index 147f7f3541816..982ed07232a80 100644 --- a/src/test/ui/regions/regions-close-object-into-object-2.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-2.stderr @@ -1,28 +1,22 @@ -error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements +error: cannot infer an appropriate lifetime --> $DIR/regions-close-object-into-object-2.rs:10:11 | +LL | fn g<'a, T: 'static>(v: Box + 'a>) -> Box { + | ------------------ data with this lifetime... LL | box B(&*v) as Box - | ^^^ - | -note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 9:6... - --> $DIR/regions-close-object-into-object-2.rs:9:6 + | ------^^^--------------- + | | | + | | ...and is captured here + | ...is required to be `'static` by this... | -LL | fn g<'a, T: 'static>(v: Box + 'a>) -> Box { - | ^^ -note: ...so that the type `(dyn A + 'a)` is not borrowed for too long - --> $DIR/regions-close-object-into-object-2.rs:10:11 +help: consider changing the trait object's explicit `'static` bound | -LL | box B(&*v) as Box - | ^^^ - = note: but, the lifetime must be valid for the static lifetime... -note: ...so that the expression is assignable - --> $DIR/regions-close-object-into-object-2.rs:10:5 +LL | fn g<'a, T: 'static>(v: Box + 'a>) -> Box { + | ^^ +help: alternatively, set an explicit `'static` lifetime in this parameter | -LL | box B(&*v) as Box - | ^^^^^^^^^^^^^^^^^^^^^^^^ - = note: expected `std::boxed::Box<(dyn X + 'static)>` - found `std::boxed::Box` +LL | fn g<'a, T: 'static>(v: std::boxed::Box<(dyn A + 'static)>) -> Box { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-close-object-into-object-4.stderr b/src/test/ui/regions/regions-close-object-into-object-4.stderr index 6e7d6152cd09a..1b82098ee13c2 100644 --- a/src/test/ui/regions/regions-close-object-into-object-4.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-4.stderr @@ -1,28 +1,22 @@ -error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements +error: cannot infer an appropriate lifetime --> $DIR/regions-close-object-into-object-4.rs:10:11 | +LL | fn i<'a, T, U>(v: Box+'a>) -> Box { + | ---------------- data with this lifetime... LL | box B(&*v) as Box - | ^^^ - | -note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 9:6... - --> $DIR/regions-close-object-into-object-4.rs:9:6 + | ------^^^--------------- + | | | + | | ...and is captured here + | ...is required to be `'static` by this... | -LL | fn i<'a, T, U>(v: Box+'a>) -> Box { - | ^^ -note: ...so that the type `(dyn A + 'a)` is not borrowed for too long - --> $DIR/regions-close-object-into-object-4.rs:10:11 +help: consider changing the trait object's explicit `'static` bound | -LL | box B(&*v) as Box - | ^^^ - = note: but, the lifetime must be valid for the static lifetime... -note: ...so that the expression is assignable - --> $DIR/regions-close-object-into-object-4.rs:10:5 +LL | fn i<'a, T, U>(v: Box+'a>) -> Box { + | ^^ +help: alternatively, set an explicit `'static` lifetime in this parameter | -LL | box B(&*v) as Box - | ^^^^^^^^^^^^^^^^^^^^^^^^ - = note: expected `std::boxed::Box<(dyn X + 'static)>` - found `std::boxed::Box` +LL | fn i<'a, T, U>(v: std::boxed::Box<(dyn A + 'static)>) -> Box { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-proc-bound-capture.nll.stderr b/src/test/ui/regions/regions-proc-bound-capture.nll.stderr new file mode 100644 index 0000000000000..75890b8581537 --- /dev/null +++ b/src/test/ui/regions/regions-proc-bound-capture.nll.stderr @@ -0,0 +1,11 @@ +error: lifetime may not live long enough + --> $DIR/regions-proc-bound-capture.rs:9:5 + | +LL | fn static_proc(x: &isize) -> Box (isize) + 'static> { + | - let's call the lifetime of this reference `'1` +LL | // This is illegal, because the region bound on `proc` is 'static. +LL | Box::new(move || { *x }) + | ^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-proc-bound-capture.rs b/src/test/ui/regions/regions-proc-bound-capture.rs index 0c903b7384992..8617c0e9da8f7 100644 --- a/src/test/ui/regions/regions-proc-bound-capture.rs +++ b/src/test/ui/regions/regions-proc-bound-capture.rs @@ -4,9 +4,9 @@ fn borrowed_proc<'a>(x: &'a isize) -> Box(isize) + 'a> { Box::new(move|| { *x }) } -fn static_proc(x: &isize) -> Box(isize) + 'static> { +fn static_proc(x: &isize) -> Box (isize) + 'static> { // This is illegal, because the region bound on `proc` is 'static. - Box::new(move|| { *x }) //~ ERROR explicit lifetime required in the type of `x` [E0621] + Box::new(move || { *x }) //~ ERROR cannot infer an appropriate lifetime } fn main() { } diff --git a/src/test/ui/regions/regions-proc-bound-capture.stderr b/src/test/ui/regions/regions-proc-bound-capture.stderr index c53af34456ef3..e7bbfaababe8a 100644 --- a/src/test/ui/regions/regions-proc-bound-capture.stderr +++ b/src/test/ui/regions/regions-proc-bound-capture.stderr @@ -1,12 +1,23 @@ -error[E0621]: explicit lifetime required in the type of `x` - --> $DIR/regions-proc-bound-capture.rs:9:5 +error: cannot infer an appropriate lifetime + --> $DIR/regions-proc-bound-capture.rs:9:14 | -LL | fn static_proc(x: &isize) -> Box(isize) + 'static> { - | ------ help: add explicit lifetime `'static` to the type of `x`: `&'static isize` +LL | fn static_proc(x: &isize) -> Box (isize) + 'static> { + | ------ data with this lifetime... LL | // This is illegal, because the region bound on `proc` is 'static. -LL | Box::new(move|| { *x }) - | ^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'static` required +LL | Box::new(move || { *x }) + | ---------^^^^^^^^^^^^^^- + | | | + | | ...and is captured here + | ...is required to be `'static` by this... + | +help: consider changing the trait object's explicit `'static` bound + | +LL | fn static_proc(x: &isize) -> Box (isize) + '_> { + | ^^ +help: alternatively, set an explicit `'static` lifetime in this parameter + | +LL | fn static_proc(x: &'static isize) -> Box (isize) + 'static> { + | ^^^^^^^^^^^^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr index 3577dd59289e5..4dc4aac6ceac4 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr @@ -7,7 +7,7 @@ LL | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to LL | Box::new(items.iter()) | ---------------^^^^--- ...is captured and required to be `'static` here | -help: to permit non-static references in a `dyn Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 6:1 +help: to permit non-static references in a trait object value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 6:1 | LL | fn a(items: &[T]) -> Box + '_> { | ^^^^ From 921f35fe73e8749dee8531f7fbaf2cb4958fa799 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 29 May 2020 18:59:42 -0700 Subject: [PATCH 29/42] Reduce verbosity of suggestion message and mention lifetime in label --- .../nice_region_error/static_impl_trait.rs | 87 ++++++++++--------- .../ui/async-await/issues/issue-62097.stderr | 2 +- .../must_outlive_least_region_or_bound.stderr | 38 ++++---- .../static-return-lifetime-infered.stderr | 8 +- src/test/ui/issues/issue-16922.stderr | 4 +- ...ect-lifetime-default-from-box-error.stderr | 4 +- .../region-object-lifetime-in-coercion.stderr | 12 +-- .../regions-close-object-into-object-2.stderr | 4 +- .../regions-close-object-into-object-4.stderr | 4 +- .../regions/regions-proc-bound-capture.stderr | 4 +- ...types_pin_lifetime_impl_trait-async.stderr | 2 +- ..._self_types_pin_lifetime_impl_trait.stderr | 4 +- .../missing-lifetimes-in-signature.stderr | 4 +- .../dyn-trait-underscore.stderr | 4 +- 14 files changed, 95 insertions(+), 86 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs index e24535bba5fdc..e9f165d309f8f 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -1,6 +1,5 @@ //! Error Reporting for static impl Traits. -use crate::infer::error_reporting::msg_span_from_free_region; use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; use rustc_errors::{Applicability, ErrorReported}; @@ -33,9 +32,17 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let sp = var_origin.span(); let return_sp = sub_origin.span(); let param_info = self.find_param_with_region(sup_r, sub_r)?; + let (lifetime_name, lifetime) = if sup_r.has_name() { + (sup_r.to_string(), format!("lifetime `{}`", sup_r)) + } else { + ("'_".to_owned(), "the anonymous lifetime `'_`".to_string()) + }; let mut err = self.tcx().sess.struct_span_err(sp, "cannot infer an appropriate lifetime"); - err.span_label(param_info.param_ty_span, "data with this lifetime..."); + err.span_label( + param_info.param_ty_span, + &format!("this data with {}...", lifetime), + ); debug!("try_report_static_impl_trait: param_info={:?}", param_info); // We try to make the output have fewer overlapping spans if possible. @@ -60,10 +67,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { ); } - let (lifetime, _) = msg_span_from_free_region(self.tcx(), sup_r); - - let lifetime_name = - if sup_r.has_name() { sup_r.to_string() } else { "'_".to_owned() }; // only apply this suggestion onto functions with // explicit non-desugar'able return. if fn_return.span.desugaring_kind().is_none() { @@ -93,8 +96,11 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { { err.span_suggestion_verbose( span, - "consider changing the `impl Trait`'s explicit \ - `'static` bound", + &format!( + "consider changing the `impl Trait`'s explicit \ + `'static` bound to {}", + lifetime, + ), lifetime_name, Applicability::MaybeIncorrect, ); @@ -118,40 +124,41 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { ); }; } - TyKind::TraitObject(_, lt) => { - match lt.name { - LifetimeName::ImplicitObjectLifetimeDefault => { - err.span_suggestion_verbose( - fn_return.span.shrink_to_hi(), - &format!( - "to permit non-static references in a trait object \ - value, you can add an explicit bound for {}", - lifetime, - ), - format!(" + {}", lifetime_name), - Applicability::MaybeIncorrect, - ); - } - _ => { - err.span_suggestion_verbose( - lt.span, + TyKind::TraitObject(_, lt) => match lt.name { + LifetimeName::ImplicitObjectLifetimeDefault => { + err.span_suggestion_verbose( + fn_return.span.shrink_to_hi(), + &format!( + "to permit non-static references in a trait object \ + value, you can add an explicit bound for {}", + lifetime, + ), + format!(" + {}", lifetime_name), + Applicability::MaybeIncorrect, + ); + } + _ => { + err.span_suggestion_verbose( + lt.span, + &format!( "consider changing the trait object's explicit \ - `'static` bound", - lifetime_name, - Applicability::MaybeIncorrect, - ); - err.span_suggestion_verbose( - param_info.param_ty_span, - &format!( - "alternatively, set an explicit `'static` lifetime \ - in this parameter", - ), - param_info.param_ty.to_string(), - Applicability::MaybeIncorrect, - ); - } + `'static` bound to {}", + lifetime, + ), + lifetime_name, + Applicability::MaybeIncorrect, + ); + err.span_suggestion_verbose( + param_info.param_ty_span, + &format!( + "alternatively, set an explicit `'static` lifetime \ + in this parameter", + ), + param_info.param_ty.to_string(), + Applicability::MaybeIncorrect, + ); } - } + }, _ => {} } } diff --git a/src/test/ui/async-await/issues/issue-62097.stderr b/src/test/ui/async-await/issues/issue-62097.stderr index af8fc2cd2ab45..fff43ae9f47bc 100644 --- a/src/test/ui/async-await/issues/issue-62097.stderr +++ b/src/test/ui/async-await/issues/issue-62097.stderr @@ -4,7 +4,7 @@ error: cannot infer an appropriate lifetime LL | pub async fn run_dummy_fn(&self) { | ^^^^^ | | - | data with this lifetime... + | this data with the anonymous lifetime `'_`... | ...is captured here... LL | foo(|| self.bar()).await; | --- ...and required to be `'static` by this diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr index 96d4a121c16af..00b6ec38323c3 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -5,9 +5,9 @@ LL | fn elided(x: &i32) -> impl Copy { x } | ---- --------- ^ ...and is captured here | | | | | ...is required to be `'static` by this... - | data with this lifetime... + | this data with the anonymous lifetime `'_`... | -help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 3:1 +help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the anonymous lifetime `'_` | LL | fn elided(x: &i32) -> impl Copy + '_ { x } | ^^^^ @@ -19,9 +19,9 @@ LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x } | ------- --------- ^ ...and is captured here | | | | | ...is required to be `'static` by this... - | data with this lifetime... + | this data with lifetime `'a`... | -help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the function body at 6:13 +help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for lifetime `'a` | LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x } | ^^^^ @@ -33,9 +33,9 @@ LL | fn elided2(x: &i32) -> impl Copy + 'static { x } | ---- ------------------- ^ ...and is captured here | | | | | ...is required to be `'static` by this... - | data with this lifetime... + | this data with the anonymous lifetime `'_`... | -help: consider changing the `impl Trait`'s explicit `'static` bound +help: consider changing the `impl Trait`'s explicit `'static` bound to the anonymous lifetime `'_` | LL | fn elided2(x: &i32) -> impl Copy + '_ { x } | ^^ @@ -51,9 +51,9 @@ LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } | ------- ------------------- ^ ...and is captured here | | | | | ...is required to be `'static` by this... - | data with this lifetime... + | this data with lifetime `'a`... | -help: consider changing the `impl Trait`'s explicit `'static` bound +help: consider changing the `impl Trait`'s explicit `'static` bound to lifetime `'a` | LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'a { x } | ^^ @@ -77,9 +77,9 @@ LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } | ------- -------------------------------- ^ ...and is captured here | | | | | ...is required to be `'static` by this... - | data with this lifetime... + | this data with lifetime `'a`... | -help: consider changing the `impl Trait`'s explicit `'static` bound +help: consider changing the `impl Trait`'s explicit `'static` bound to lifetime `'a` | LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'a { x } | ^^ @@ -113,9 +113,9 @@ LL | fn elided3(x: &i32) -> Box { Box::new(x) } | | | | | | | ...and is captured here | | ...is required to be `'static` by this... - | data with this lifetime... + | this data with the anonymous lifetime `'_`... | -help: to permit non-static references in a trait object value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 18:1 +help: to permit non-static references in a trait object value, you can add an explicit bound for the anonymous lifetime `'_` | LL | fn elided3(x: &i32) -> Box { Box::new(x) } | ^^^^ @@ -128,9 +128,9 @@ LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) } | | | | | | | ...and is captured here | | ...is required to be `'static` by this... - | data with this lifetime... + | this data with lifetime `'a`... | -help: to permit non-static references in a trait object value, you can add an explicit bound for the lifetime `'a` as defined on the function body at 21:14 +help: to permit non-static references in a trait object value, you can add an explicit bound for lifetime `'a` | LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) } | ^^^^ @@ -142,9 +142,10 @@ LL | fn elided4(x: &i32) -> Box { Box::new(x) } | ---- ---------^- | | | | | | | ...and is captured here - | data with this lifetime... ...is required to be `'static` by this... + | | ...is required to be `'static` by this... + | this data with the anonymous lifetime `'_`... | -help: consider changing the trait object's explicit `'static` bound +help: consider changing the trait object's explicit `'static` bound to the anonymous lifetime `'_` | LL | fn elided4(x: &i32) -> Box { Box::new(x) } | ^^ @@ -160,9 +161,10 @@ LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } | ------- ---------^- | | | | | | | ...and is captured here - | data with this lifetime... ...is required to be `'static` by this... + | | ...is required to be `'static` by this... + | this data with lifetime `'a`... | -help: consider changing the trait object's explicit `'static` bound +help: consider changing the trait object's explicit `'static` bound to lifetime `'a` | LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } | ^^ diff --git a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr index 1c3a5979ee55b..67d4f60dff6f1 100644 --- a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr +++ b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr @@ -4,13 +4,13 @@ error: cannot infer an appropriate lifetime LL | fn iter_values_anon(&self) -> impl Iterator { | ----- ----------------------- ...is required to be `'static` by this... | | - | data with this lifetime... + | this data with the anonymous lifetime `'_`... LL | self.x.iter().map(|a| a.0) | ------ ^^^^ | | | ...and is captured here | -help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the method body at 6:5 +help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the anonymous lifetime `'_` | LL | fn iter_values_anon(&self) -> impl Iterator + '_ { | ^^^^ @@ -21,13 +21,13 @@ error: cannot infer an appropriate lifetime LL | fn iter_values<'a>(&'a self) -> impl Iterator { | -------- ----------------------- ...is required to be `'static` by this... | | - | data with this lifetime... + | this data with lifetime `'a`... LL | self.x.iter().map(|a| a.0) | ------ ^^^^ | | | ...and is captured here | -help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the method body at 10:20 +help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for lifetime `'a` | LL | fn iter_values<'a>(&'a self) -> impl Iterator + 'a { | ^^^^ diff --git a/src/test/ui/issues/issue-16922.stderr b/src/test/ui/issues/issue-16922.stderr index 038df47e1bd98..c533a72dfc014 100644 --- a/src/test/ui/issues/issue-16922.stderr +++ b/src/test/ui/issues/issue-16922.stderr @@ -2,14 +2,14 @@ error: cannot infer an appropriate lifetime --> $DIR/issue-16922.rs:4:14 | LL | fn foo(value: &T) -> Box { - | -- data with this lifetime... + | -- this data with the anonymous lifetime `'_`... LL | Box::new(value) as Box | ---------^^^^^- | | | | | ...and is captured here | ...is required to be `'static` by this... | -help: to permit non-static references in a trait object value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 3:1 +help: to permit non-static references in a trait object value, you can add an explicit bound for the anonymous lifetime `'_` | LL | fn foo(value: &T) -> Box { | ^^^^ diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr index 555622c9d13c1..6edef8086b937 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr @@ -2,12 +2,12 @@ error: cannot infer an appropriate lifetime --> $DIR/object-lifetime-default-from-box-error.rs:18:5 | LL | fn load(ss: &mut SomeStruct) -> Box { - | --------------- data with this lifetime... + | --------------- this data with the anonymous lifetime `'_`... ... LL | ss.r | ^^^^ ...is captured and required to be `'static` here | -help: to permit non-static references in a trait object value, you can add an explicit bound for the anonymous lifetime #2 defined on the function body at 14:1 +help: to permit non-static references in a trait object value, you can add an explicit bound for the anonymous lifetime `'_` | LL | fn load(ss: &mut SomeStruct) -> Box { | ^^^^ diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr index 673300cebc26c..4b08c4bff2ebc 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr @@ -2,14 +2,14 @@ error: cannot infer an appropriate lifetime --> $DIR/region-object-lifetime-in-coercion.rs:8:46 | LL | fn a(v: &[u8]) -> Box { - | ----- data with this lifetime... + | ----- this data with the anonymous lifetime `'_`... LL | let x: Box = Box::new(v); | ---------^- | | | | | ...and is captured here | ...is required to be `'static` by this... | -help: consider changing the trait object's explicit `'static` bound +help: consider changing the trait object's explicit `'static` bound to the anonymous lifetime `'_` | LL | fn a(v: &[u8]) -> Box { | ^^ @@ -22,14 +22,14 @@ error: cannot infer an appropriate lifetime --> $DIR/region-object-lifetime-in-coercion.rs:13:14 | LL | fn b(v: &[u8]) -> Box { - | ----- data with this lifetime... + | ----- this data with the anonymous lifetime `'_`... LL | Box::new(v) | ---------^- | | | | | ...and is captured here | ...is required to be `'static` by this... | -help: consider changing the trait object's explicit `'static` bound +help: consider changing the trait object's explicit `'static` bound to the anonymous lifetime `'_` | LL | fn b(v: &[u8]) -> Box { | ^^ @@ -42,7 +42,7 @@ error: cannot infer an appropriate lifetime --> $DIR/region-object-lifetime-in-coercion.rs:19:14 | LL | fn c(v: &[u8]) -> Box { - | ----- data with this lifetime... + | ----- this data with the anonymous lifetime `'_`... ... LL | Box::new(v) | ---------^- @@ -50,7 +50,7 @@ LL | Box::new(v) | | ...and is captured here | ...is required to be `'static` by this... | -help: to permit non-static references in a trait object value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 16:1 +help: to permit non-static references in a trait object value, you can add an explicit bound for the anonymous lifetime `'_` | LL | fn c(v: &[u8]) -> Box { | ^^^^ diff --git a/src/test/ui/regions/regions-close-object-into-object-2.stderr b/src/test/ui/regions/regions-close-object-into-object-2.stderr index 982ed07232a80..894be310fd14b 100644 --- a/src/test/ui/regions/regions-close-object-into-object-2.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-2.stderr @@ -2,14 +2,14 @@ error: cannot infer an appropriate lifetime --> $DIR/regions-close-object-into-object-2.rs:10:11 | LL | fn g<'a, T: 'static>(v: Box + 'a>) -> Box { - | ------------------ data with this lifetime... + | ------------------ this data with lifetime `'a`... LL | box B(&*v) as Box | ------^^^--------------- | | | | | ...and is captured here | ...is required to be `'static` by this... | -help: consider changing the trait object's explicit `'static` bound +help: consider changing the trait object's explicit `'static` bound to lifetime `'a` | LL | fn g<'a, T: 'static>(v: Box + 'a>) -> Box { | ^^ diff --git a/src/test/ui/regions/regions-close-object-into-object-4.stderr b/src/test/ui/regions/regions-close-object-into-object-4.stderr index 1b82098ee13c2..ce261d78c2909 100644 --- a/src/test/ui/regions/regions-close-object-into-object-4.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-4.stderr @@ -2,14 +2,14 @@ error: cannot infer an appropriate lifetime --> $DIR/regions-close-object-into-object-4.rs:10:11 | LL | fn i<'a, T, U>(v: Box+'a>) -> Box { - | ---------------- data with this lifetime... + | ---------------- this data with lifetime `'a`... LL | box B(&*v) as Box | ------^^^--------------- | | | | | ...and is captured here | ...is required to be `'static` by this... | -help: consider changing the trait object's explicit `'static` bound +help: consider changing the trait object's explicit `'static` bound to lifetime `'a` | LL | fn i<'a, T, U>(v: Box+'a>) -> Box { | ^^ diff --git a/src/test/ui/regions/regions-proc-bound-capture.stderr b/src/test/ui/regions/regions-proc-bound-capture.stderr index e7bbfaababe8a..a0df1815247c3 100644 --- a/src/test/ui/regions/regions-proc-bound-capture.stderr +++ b/src/test/ui/regions/regions-proc-bound-capture.stderr @@ -2,7 +2,7 @@ error: cannot infer an appropriate lifetime --> $DIR/regions-proc-bound-capture.rs:9:14 | LL | fn static_proc(x: &isize) -> Box (isize) + 'static> { - | ------ data with this lifetime... + | ------ this data with the anonymous lifetime `'_`... LL | // This is illegal, because the region bound on `proc` is 'static. LL | Box::new(move || { *x }) | ---------^^^^^^^^^^^^^^- @@ -10,7 +10,7 @@ LL | Box::new(move || { *x }) | | ...and is captured here | ...is required to be `'static` by this... | -help: consider changing the trait object's explicit `'static` bound +help: consider changing the trait object's explicit `'static` bound to the anonymous lifetime `'_` | LL | fn static_proc(x: &isize) -> Box (isize) + '_> { | ^^ diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr index 1aeabce5e8aaf..5520341b5b1c3 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr @@ -4,7 +4,7 @@ error: cannot infer an appropriate lifetime LL | async fn f(self: Pin<&Self>) -> impl Clone { self } | ^^^^ ---------- ---------- ...and required to be `'static` by this | | | - | | data with this lifetime... + | | this data with the anonymous lifetime `'_`... | ...is captured here... error: aborting due to previous error diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr index 04c475be787b8..5374929f3a45f 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr @@ -5,9 +5,9 @@ LL | fn f(self: Pin<&Self>) -> impl Clone { self } | ---------- ---------- ^^^^ ...and is captured here | | | | | ...is required to be `'static` by this... - | data with this lifetime... + | this data with the anonymous lifetime `'_`... | -help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the method body at 6:5 +help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the anonymous lifetime `'_` | LL | fn f(self: Pin<&Self>) -> impl Clone + '_ { self } | ^^^^ diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr index 5cf170d566ca9..471f3cd14aa3e 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr @@ -12,14 +12,14 @@ error: cannot infer an appropriate lifetime LL | fn foo(g: G, dest: &mut T) -> impl FnOnce() | ------ ------------- ...is required to be `'static` by this... | | - | data with this lifetime... + | this data with the anonymous lifetime `'_`... ... LL | / move || { LL | | *dest = g.get(); LL | | } | |_____^ ...and is captured here | -help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 15:1 +help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the anonymous lifetime `'_` | LL | fn foo(g: G, dest: &mut T) -> impl FnOnce() + '_ | ^^^^ diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr index 4dc4aac6ceac4..5fd03f9770e5d 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr @@ -2,12 +2,12 @@ error: cannot infer an appropriate lifetime --> $DIR/dyn-trait-underscore.rs:8:20 | LL | fn a(items: &[T]) -> Box> { - | ---- data with this lifetime... + | ---- this data with the anonymous lifetime `'_`... LL | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static` LL | Box::new(items.iter()) | ---------------^^^^--- ...is captured and required to be `'static` here | -help: to permit non-static references in a trait object value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 6:1 +help: to permit non-static references in a trait object value, you can add an explicit bound for the anonymous lifetime `'_` | LL | fn a(items: &[T]) -> Box + '_> { | ^^^^ From e75588934c01d6bc9abb02979eb61168a7b5c598 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 29 May 2020 19:46:22 -0700 Subject: [PATCH 30/42] Move overlapping span to a note --- .../nice_region_error/static_impl_trait.rs | 31 ++++++++++++- .../must_outlive_least_region_or_bound.stderr | 44 ++++++++++++------- src/test/ui/issues/issue-16922.stderr | 10 +++-- .../region-object-lifetime-in-coercion.stderr | 30 ++++++++----- .../regions-close-object-into-object-2.stderr | 10 +++-- .../regions-close-object-into-object-4.stderr | 10 +++-- .../regions/regions-proc-bound-capture.stderr | 10 +++-- 7 files changed, 99 insertions(+), 46 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs index e9f165d309f8f..cc95441b68a03 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -53,7 +53,36 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // Customize the spans and labels depending on their relative order so // that split sentences flow correctly. - if sup_origin.span().shrink_to_hi() <= return_sp.shrink_to_lo() { + if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() { + // Avoid the following: + // + // error: cannot infer an appropriate lifetime + // --> $DIR/must_outlive_least_region_or_bound.rs:18:50 + // | + // LL | fn foo(x: &i32) -> Box { Box::new(x) } + // | ---- ---------^- + // | | | | + // | | | ...and is captured here + // | | ...is required to be `'static` by this... + // | this data with the anonymous lifetime `'_`... + // + // and instead show: + // + // error: cannot infer an appropriate lifetime + // --> $DIR/must_outlive_least_region_or_bound.rs:18:50 + // | + // LL | fn foo(x: &i32) -> Box { Box::new(x) } + // | ---- ^ ...is captured here with a `'static` requirement + // | | + // | this data with the anonymous lifetime `'_`... + // | + // note: ...is required to be `'static` by this + // | + // LL | fn elided3(x: &i32) -> Box { Box::new(x) } + // | ^^^^^^^^^^^ + err.span_label(sup_origin.span(), "...is captured here..."); + err.span_note(return_sp, "...and required to be `'static` by this"); + } else if sup_origin.span() <= return_sp { err.span_label(sup_origin.span(), "...is captured here..."); err.span_label(return_sp, "...and required to be `'static` by this"); } else { diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr index 00b6ec38323c3..2da49379ea8c2 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -109,12 +109,15 @@ error: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:18:50 | LL | fn elided3(x: &i32) -> Box { Box::new(x) } - | ---- ---------^- - | | | | - | | | ...and is captured here - | | ...is required to be `'static` by this... + | ---- ^ ...is captured here... + | | | this data with the anonymous lifetime `'_`... | +note: ...and required to be `'static` by this + --> $DIR/must_outlive_least_region_or_bound.rs:18:41 + | +LL | fn elided3(x: &i32) -> Box { Box::new(x) } + | ^^^^^^^^^^^ help: to permit non-static references in a trait object value, you can add an explicit bound for the anonymous lifetime `'_` | LL | fn elided3(x: &i32) -> Box { Box::new(x) } @@ -124,12 +127,15 @@ error: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:21:59 | LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) } - | ------- ---------^- - | | | | - | | | ...and is captured here - | | ...is required to be `'static` by this... + | ------- ^ ...is captured here... + | | | this data with lifetime `'a`... | +note: ...and required to be `'static` by this + --> $DIR/must_outlive_least_region_or_bound.rs:21:50 + | +LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) } + | ^^^^^^^^^^^ help: to permit non-static references in a trait object value, you can add an explicit bound for lifetime `'a` | LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) } @@ -139,12 +145,15 @@ error: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:24:60 | LL | fn elided4(x: &i32) -> Box { Box::new(x) } - | ---- ---------^- - | | | | - | | | ...and is captured here - | | ...is required to be `'static` by this... + | ---- ^ ...is captured here... + | | | this data with the anonymous lifetime `'_`... | +note: ...and required to be `'static` by this + --> $DIR/must_outlive_least_region_or_bound.rs:24:51 + | +LL | fn elided4(x: &i32) -> Box { Box::new(x) } + | ^^^^^^^^^^^ help: consider changing the trait object's explicit `'static` bound to the anonymous lifetime `'_` | LL | fn elided4(x: &i32) -> Box { Box::new(x) } @@ -158,12 +167,13 @@ error: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:27:69 | LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } - | ------- ---------^- - | | | | - | | | ...and is captured here - | | ...is required to be `'static` by this... - | this data with lifetime `'a`... + | ------- this data with lifetime `'a`... ^ ...is captured here... | +note: ...and required to be `'static` by this + --> $DIR/must_outlive_least_region_or_bound.rs:27:60 + | +LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } + | ^^^^^^^^^^^ help: consider changing the trait object's explicit `'static` bound to lifetime `'a` | LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } diff --git a/src/test/ui/issues/issue-16922.stderr b/src/test/ui/issues/issue-16922.stderr index c533a72dfc014..6c0b26a86b651 100644 --- a/src/test/ui/issues/issue-16922.stderr +++ b/src/test/ui/issues/issue-16922.stderr @@ -4,11 +4,13 @@ error: cannot infer an appropriate lifetime LL | fn foo(value: &T) -> Box { | -- this data with the anonymous lifetime `'_`... LL | Box::new(value) as Box - | ---------^^^^^- - | | | - | | ...and is captured here - | ...is required to be `'static` by this... + | ^^^^^ ...is captured here... | +note: ...and required to be `'static` by this + --> $DIR/issue-16922.rs:4:5 + | +LL | Box::new(value) as Box + | ^^^^^^^^^^^^^^^ help: to permit non-static references in a trait object value, you can add an explicit bound for the anonymous lifetime `'_` | LL | fn foo(value: &T) -> Box { diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr index 4b08c4bff2ebc..b333c314c57c9 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr @@ -4,11 +4,13 @@ error: cannot infer an appropriate lifetime LL | fn a(v: &[u8]) -> Box { | ----- this data with the anonymous lifetime `'_`... LL | let x: Box = Box::new(v); - | ---------^- - | | | - | | ...and is captured here - | ...is required to be `'static` by this... + | ^ ...is captured here... | +note: ...and required to be `'static` by this + --> $DIR/region-object-lifetime-in-coercion.rs:8:37 + | +LL | let x: Box = Box::new(v); + | ^^^^^^^^^^^ help: consider changing the trait object's explicit `'static` bound to the anonymous lifetime `'_` | LL | fn a(v: &[u8]) -> Box { @@ -24,11 +26,13 @@ error: cannot infer an appropriate lifetime LL | fn b(v: &[u8]) -> Box { | ----- this data with the anonymous lifetime `'_`... LL | Box::new(v) - | ---------^- - | | | - | | ...and is captured here - | ...is required to be `'static` by this... + | ^ ...is captured here... | +note: ...and required to be `'static` by this + --> $DIR/region-object-lifetime-in-coercion.rs:13:5 + | +LL | Box::new(v) + | ^^^^^^^^^^^ help: consider changing the trait object's explicit `'static` bound to the anonymous lifetime `'_` | LL | fn b(v: &[u8]) -> Box { @@ -45,11 +49,13 @@ LL | fn c(v: &[u8]) -> Box { | ----- this data with the anonymous lifetime `'_`... ... LL | Box::new(v) - | ---------^- - | | | - | | ...and is captured here - | ...is required to be `'static` by this... + | ^ ...is captured here... + | +note: ...and required to be `'static` by this + --> $DIR/region-object-lifetime-in-coercion.rs:19:5 | +LL | Box::new(v) + | ^^^^^^^^^^^ help: to permit non-static references in a trait object value, you can add an explicit bound for the anonymous lifetime `'_` | LL | fn c(v: &[u8]) -> Box { diff --git a/src/test/ui/regions/regions-close-object-into-object-2.stderr b/src/test/ui/regions/regions-close-object-into-object-2.stderr index 894be310fd14b..3127ae65ace7d 100644 --- a/src/test/ui/regions/regions-close-object-into-object-2.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-2.stderr @@ -4,11 +4,13 @@ error: cannot infer an appropriate lifetime LL | fn g<'a, T: 'static>(v: Box + 'a>) -> Box { | ------------------ this data with lifetime `'a`... LL | box B(&*v) as Box - | ------^^^--------------- - | | | - | | ...and is captured here - | ...is required to be `'static` by this... + | ^^^ ...is captured here... | +note: ...and required to be `'static` by this + --> $DIR/regions-close-object-into-object-2.rs:10:5 + | +LL | box B(&*v) as Box + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the trait object's explicit `'static` bound to lifetime `'a` | LL | fn g<'a, T: 'static>(v: Box + 'a>) -> Box { diff --git a/src/test/ui/regions/regions-close-object-into-object-4.stderr b/src/test/ui/regions/regions-close-object-into-object-4.stderr index ce261d78c2909..b18c61f137694 100644 --- a/src/test/ui/regions/regions-close-object-into-object-4.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-4.stderr @@ -4,11 +4,13 @@ error: cannot infer an appropriate lifetime LL | fn i<'a, T, U>(v: Box+'a>) -> Box { | ---------------- this data with lifetime `'a`... LL | box B(&*v) as Box - | ------^^^--------------- - | | | - | | ...and is captured here - | ...is required to be `'static` by this... + | ^^^ ...is captured here... | +note: ...and required to be `'static` by this + --> $DIR/regions-close-object-into-object-4.rs:10:5 + | +LL | box B(&*v) as Box + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the trait object's explicit `'static` bound to lifetime `'a` | LL | fn i<'a, T, U>(v: Box+'a>) -> Box { diff --git a/src/test/ui/regions/regions-proc-bound-capture.stderr b/src/test/ui/regions/regions-proc-bound-capture.stderr index a0df1815247c3..5cb9506afd351 100644 --- a/src/test/ui/regions/regions-proc-bound-capture.stderr +++ b/src/test/ui/regions/regions-proc-bound-capture.stderr @@ -5,11 +5,13 @@ LL | fn static_proc(x: &isize) -> Box (isize) + 'static> { | ------ this data with the anonymous lifetime `'_`... LL | // This is illegal, because the region bound on `proc` is 'static. LL | Box::new(move || { *x }) - | ---------^^^^^^^^^^^^^^- - | | | - | | ...and is captured here - | ...is required to be `'static` by this... + | ^^^^^^^^^^^^^^ ...is captured here... | +note: ...and required to be `'static` by this + --> $DIR/regions-proc-bound-capture.rs:9:5 + | +LL | Box::new(move || { *x }) + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the trait object's explicit `'static` bound to the anonymous lifetime `'_` | LL | fn static_proc(x: &isize) -> Box (isize) + '_> { From bc1579060981b5e95a18409e876c92bf0c9307e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 30 May 2020 09:54:05 -0700 Subject: [PATCH 31/42] Tweak output for overlapping required/captured spans --- .../nice_region_error/static_impl_trait.rs | 10 +++---- .../must_outlive_least_region_or_bound.stderr | 28 +++---------------- src/test/ui/issues/issue-16922.stderr | 7 +---- .../region-object-lifetime-in-coercion.stderr | 21 ++------------ .../regions-close-object-into-object-2.stderr | 7 +---- .../regions-close-object-into-object-4.stderr | 7 +---- .../regions/regions-proc-bound-capture.stderr | 7 +---- 7 files changed, 15 insertions(+), 72 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs index cc95441b68a03..253057536f133 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -76,12 +76,10 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // | | // | this data with the anonymous lifetime `'_`... // | - // note: ...is required to be `'static` by this - // | - // LL | fn elided3(x: &i32) -> Box { Box::new(x) } - // | ^^^^^^^^^^^ - err.span_label(sup_origin.span(), "...is captured here..."); - err.span_note(return_sp, "...and required to be `'static` by this"); + err.span_label( + sup_origin.span(), + "...is captured here with a `'static` requirement", + ); } else if sup_origin.span() <= return_sp { err.span_label(sup_origin.span(), "...is captured here..."); err.span_label(return_sp, "...and required to be `'static` by this"); diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr index 2da49379ea8c2..82e44cff9cc44 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -109,15 +109,10 @@ error: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:18:50 | LL | fn elided3(x: &i32) -> Box { Box::new(x) } - | ---- ^ ...is captured here... + | ---- ^ ...is captured here with a `'static` requirement | | | this data with the anonymous lifetime `'_`... | -note: ...and required to be `'static` by this - --> $DIR/must_outlive_least_region_or_bound.rs:18:41 - | -LL | fn elided3(x: &i32) -> Box { Box::new(x) } - | ^^^^^^^^^^^ help: to permit non-static references in a trait object value, you can add an explicit bound for the anonymous lifetime `'_` | LL | fn elided3(x: &i32) -> Box { Box::new(x) } @@ -127,15 +122,10 @@ error: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:21:59 | LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) } - | ------- ^ ...is captured here... + | ------- ^ ...is captured here with a `'static` requirement | | | this data with lifetime `'a`... | -note: ...and required to be `'static` by this - --> $DIR/must_outlive_least_region_or_bound.rs:21:50 - | -LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) } - | ^^^^^^^^^^^ help: to permit non-static references in a trait object value, you can add an explicit bound for lifetime `'a` | LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) } @@ -145,15 +135,10 @@ error: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:24:60 | LL | fn elided4(x: &i32) -> Box { Box::new(x) } - | ---- ^ ...is captured here... + | ---- ^ ...is captured here with a `'static` requirement | | | this data with the anonymous lifetime `'_`... | -note: ...and required to be `'static` by this - --> $DIR/must_outlive_least_region_or_bound.rs:24:51 - | -LL | fn elided4(x: &i32) -> Box { Box::new(x) } - | ^^^^^^^^^^^ help: consider changing the trait object's explicit `'static` bound to the anonymous lifetime `'_` | LL | fn elided4(x: &i32) -> Box { Box::new(x) } @@ -167,13 +152,8 @@ error: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:27:69 | LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } - | ------- this data with lifetime `'a`... ^ ...is captured here... + | ------- this data with lifetime `'a`... ^ ...is captured here with a `'static` requirement | -note: ...and required to be `'static` by this - --> $DIR/must_outlive_least_region_or_bound.rs:27:60 - | -LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } - | ^^^^^^^^^^^ help: consider changing the trait object's explicit `'static` bound to lifetime `'a` | LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } diff --git a/src/test/ui/issues/issue-16922.stderr b/src/test/ui/issues/issue-16922.stderr index 6c0b26a86b651..a254343cd1bb7 100644 --- a/src/test/ui/issues/issue-16922.stderr +++ b/src/test/ui/issues/issue-16922.stderr @@ -4,13 +4,8 @@ error: cannot infer an appropriate lifetime LL | fn foo(value: &T) -> Box { | -- this data with the anonymous lifetime `'_`... LL | Box::new(value) as Box - | ^^^^^ ...is captured here... + | ^^^^^ ...is captured here with a `'static` requirement | -note: ...and required to be `'static` by this - --> $DIR/issue-16922.rs:4:5 - | -LL | Box::new(value) as Box - | ^^^^^^^^^^^^^^^ help: to permit non-static references in a trait object value, you can add an explicit bound for the anonymous lifetime `'_` | LL | fn foo(value: &T) -> Box { diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr index b333c314c57c9..97d1f3579fcd8 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr @@ -4,13 +4,8 @@ error: cannot infer an appropriate lifetime LL | fn a(v: &[u8]) -> Box { | ----- this data with the anonymous lifetime `'_`... LL | let x: Box = Box::new(v); - | ^ ...is captured here... + | ^ ...is captured here with a `'static` requirement | -note: ...and required to be `'static` by this - --> $DIR/region-object-lifetime-in-coercion.rs:8:37 - | -LL | let x: Box = Box::new(v); - | ^^^^^^^^^^^ help: consider changing the trait object's explicit `'static` bound to the anonymous lifetime `'_` | LL | fn a(v: &[u8]) -> Box { @@ -26,13 +21,8 @@ error: cannot infer an appropriate lifetime LL | fn b(v: &[u8]) -> Box { | ----- this data with the anonymous lifetime `'_`... LL | Box::new(v) - | ^ ...is captured here... + | ^ ...is captured here with a `'static` requirement | -note: ...and required to be `'static` by this - --> $DIR/region-object-lifetime-in-coercion.rs:13:5 - | -LL | Box::new(v) - | ^^^^^^^^^^^ help: consider changing the trait object's explicit `'static` bound to the anonymous lifetime `'_` | LL | fn b(v: &[u8]) -> Box { @@ -49,13 +39,8 @@ LL | fn c(v: &[u8]) -> Box { | ----- this data with the anonymous lifetime `'_`... ... LL | Box::new(v) - | ^ ...is captured here... - | -note: ...and required to be `'static` by this - --> $DIR/region-object-lifetime-in-coercion.rs:19:5 + | ^ ...is captured here with a `'static` requirement | -LL | Box::new(v) - | ^^^^^^^^^^^ help: to permit non-static references in a trait object value, you can add an explicit bound for the anonymous lifetime `'_` | LL | fn c(v: &[u8]) -> Box { diff --git a/src/test/ui/regions/regions-close-object-into-object-2.stderr b/src/test/ui/regions/regions-close-object-into-object-2.stderr index 3127ae65ace7d..3d707f2d99941 100644 --- a/src/test/ui/regions/regions-close-object-into-object-2.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-2.stderr @@ -4,13 +4,8 @@ error: cannot infer an appropriate lifetime LL | fn g<'a, T: 'static>(v: Box + 'a>) -> Box { | ------------------ this data with lifetime `'a`... LL | box B(&*v) as Box - | ^^^ ...is captured here... + | ^^^ ...is captured here with a `'static` requirement | -note: ...and required to be `'static` by this - --> $DIR/regions-close-object-into-object-2.rs:10:5 - | -LL | box B(&*v) as Box - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the trait object's explicit `'static` bound to lifetime `'a` | LL | fn g<'a, T: 'static>(v: Box + 'a>) -> Box { diff --git a/src/test/ui/regions/regions-close-object-into-object-4.stderr b/src/test/ui/regions/regions-close-object-into-object-4.stderr index b18c61f137694..70282c8cbdb30 100644 --- a/src/test/ui/regions/regions-close-object-into-object-4.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-4.stderr @@ -4,13 +4,8 @@ error: cannot infer an appropriate lifetime LL | fn i<'a, T, U>(v: Box+'a>) -> Box { | ---------------- this data with lifetime `'a`... LL | box B(&*v) as Box - | ^^^ ...is captured here... + | ^^^ ...is captured here with a `'static` requirement | -note: ...and required to be `'static` by this - --> $DIR/regions-close-object-into-object-4.rs:10:5 - | -LL | box B(&*v) as Box - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the trait object's explicit `'static` bound to lifetime `'a` | LL | fn i<'a, T, U>(v: Box+'a>) -> Box { diff --git a/src/test/ui/regions/regions-proc-bound-capture.stderr b/src/test/ui/regions/regions-proc-bound-capture.stderr index 5cb9506afd351..8f93fad7fe9d8 100644 --- a/src/test/ui/regions/regions-proc-bound-capture.stderr +++ b/src/test/ui/regions/regions-proc-bound-capture.stderr @@ -5,13 +5,8 @@ LL | fn static_proc(x: &isize) -> Box (isize) + 'static> { | ------ this data with the anonymous lifetime `'_`... LL | // This is illegal, because the region bound on `proc` is 'static. LL | Box::new(move || { *x }) - | ^^^^^^^^^^^^^^ ...is captured here... + | ^^^^^^^^^^^^^^ ...is captured here with a `'static` requirement | -note: ...and required to be `'static` by this - --> $DIR/regions-proc-bound-capture.rs:9:5 - | -LL | Box::new(move || { *x }) - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the trait object's explicit `'static` bound to the anonymous lifetime `'_` | LL | fn static_proc(x: &isize) -> Box (isize) + '_> { From 539e9783dfb713b3af0a9967af8fd0639d700555 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 30 May 2020 10:15:58 -0700 Subject: [PATCH 32/42] Tweak wording and add error code --- .../nice_region_error/static_impl_trait.rs | 35 +++++++------ .../ui/async-await/issues/issue-62097.stderr | 6 +-- .../must_outlive_least_region_or_bound.stderr | 52 +++++++++---------- .../static-return-lifetime-infered.stderr | 12 ++--- src/test/ui/issues/issue-16922.stderr | 8 +-- ...ect-lifetime-default-from-box-error.stderr | 8 +-- .../region-object-lifetime-in-coercion.stderr | 24 ++++----- .../regions-close-object-into-object-2.stderr | 4 +- .../regions-close-object-into-object-4.stderr | 4 +- .../regions/regions-proc-bound-capture.stderr | 8 +-- ...types_pin_lifetime_impl_trait-async.stderr | 6 +-- ..._self_types_pin_lifetime_impl_trait.stderr | 8 +-- .../missing-lifetimes-in-signature.stderr | 8 +-- .../dyn-trait-underscore.stderr | 8 +-- 14 files changed, 97 insertions(+), 94 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs index 253057536f133..4e16e8c2c5717 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -2,7 +2,7 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; -use rustc_errors::{Applicability, ErrorReported}; +use rustc_errors::{struct_span_err, Applicability, ErrorReported}; use rustc_hir::{GenericBound, ItemKind, Lifetime, LifetimeName, TyKind}; use rustc_middle::ty::RegionKind; @@ -35,10 +35,14 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let (lifetime_name, lifetime) = if sup_r.has_name() { (sup_r.to_string(), format!("lifetime `{}`", sup_r)) } else { - ("'_".to_owned(), "the anonymous lifetime `'_`".to_string()) + ("'_".to_owned(), "an anonymous lifetime `'_`".to_string()) }; - let mut err = - self.tcx().sess.struct_span_err(sp, "cannot infer an appropriate lifetime"); + let mut err = struct_span_err!( + self.tcx().sess, + sp, + E0758, + "cannot infer an appropriate lifetime" + ); err.span_label( param_info.param_ty_span, &format!("this data with {}...", lifetime), @@ -61,10 +65,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // | // LL | fn foo(x: &i32) -> Box { Box::new(x) } // | ---- ---------^- - // | | | | - // | | | ...and is captured here - // | | ...is required to be `'static` by this... - // | this data with the anonymous lifetime `'_`... // // and instead show: // @@ -72,25 +72,28 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // --> $DIR/must_outlive_least_region_or_bound.rs:18:50 // | // LL | fn foo(x: &i32) -> Box { Box::new(x) } - // | ---- ^ ...is captured here with a `'static` requirement - // | | - // | this data with the anonymous lifetime `'_`... - // | + // | ---- ^ err.span_label( sup_origin.span(), - "...is captured here with a `'static` requirement", + "...is captured here requiring it to live as long as `'static`", ); } else if sup_origin.span() <= return_sp { err.span_label(sup_origin.span(), "...is captured here..."); - err.span_label(return_sp, "...and required to be `'static` by this"); + err.span_label( + return_sp, + "...and required to live as long as `'static` by this", + ); } else { - err.span_label(return_sp, "...is required to be `'static` by this..."); + err.span_label( + return_sp, + "...is required to live as long as `'static` by this...", + ); err.span_label(sup_origin.span(), "...and is captured here"); } } else { err.span_label( return_sp, - "...is captured and required to be `'static` here", + "...is captured and required live as long as `'static` here", ); } diff --git a/src/test/ui/async-await/issues/issue-62097.stderr b/src/test/ui/async-await/issues/issue-62097.stderr index fff43ae9f47bc..558d89f928945 100644 --- a/src/test/ui/async-await/issues/issue-62097.stderr +++ b/src/test/ui/async-await/issues/issue-62097.stderr @@ -1,13 +1,13 @@ -error: cannot infer an appropriate lifetime +error[E0758]: cannot infer an appropriate lifetime --> $DIR/issue-62097.rs:12:31 | LL | pub async fn run_dummy_fn(&self) { | ^^^^^ | | - | this data with the anonymous lifetime `'_`... + | this data with an anonymous lifetime `'_`... | ...is captured here... LL | foo(|| self.bar()).await; - | --- ...and required to be `'static` by this + | --- ...and required to live as long as `'static` by this error: aborting due to previous error diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr index 82e44cff9cc44..eff56ddc440d4 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -1,24 +1,24 @@ -error: cannot infer an appropriate lifetime +error[E0758]: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:3:35 | LL | fn elided(x: &i32) -> impl Copy { x } | ---- --------- ^ ...and is captured here | | | - | | ...is required to be `'static` by this... - | this data with the anonymous lifetime `'_`... + | | ...is required to live as long as `'static` by this... + | this data with an anonymous lifetime `'_`... | -help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the anonymous lifetime `'_` +help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for an anonymous lifetime `'_` | LL | fn elided(x: &i32) -> impl Copy + '_ { x } | ^^^^ -error: cannot infer an appropriate lifetime +error[E0758]: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:6:44 | LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x } | ------- --------- ^ ...and is captured here | | | - | | ...is required to be `'static` by this... + | | ...is required to live as long as `'static` by this... | this data with lifetime `'a`... | help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for lifetime `'a` @@ -26,16 +26,16 @@ help: to permit non-static references in an `impl Trait` value, you can add an e LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x } | ^^^^ -error: cannot infer an appropriate lifetime +error[E0758]: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:9:46 | LL | fn elided2(x: &i32) -> impl Copy + 'static { x } | ---- ------------------- ^ ...and is captured here | | | - | | ...is required to be `'static` by this... - | this data with the anonymous lifetime `'_`... + | | ...is required to live as long as `'static` by this... + | this data with an anonymous lifetime `'_`... | -help: consider changing the `impl Trait`'s explicit `'static` bound to the anonymous lifetime `'_` +help: consider changing the `impl Trait`'s explicit `'static` bound to an anonymous lifetime `'_` | LL | fn elided2(x: &i32) -> impl Copy + '_ { x } | ^^ @@ -44,13 +44,13 @@ help: alternatively, set an explicit `'static` lifetime to this parameter LL | fn elided2(x: &'static i32) -> impl Copy + 'static { x } | ^^^^^^^^^^^^ -error: cannot infer an appropriate lifetime +error[E0758]: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:12:55 | LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } | ------- ------------------- ^ ...and is captured here | | | - | | ...is required to be `'static` by this... + | | ...is required to live as long as `'static` by this... | this data with lifetime `'a`... | help: consider changing the `impl Trait`'s explicit `'static` bound to lifetime `'a` @@ -70,13 +70,13 @@ LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x } | | | help: add explicit lifetime `'a` to the type of `x`: `&'a i32` -error: cannot infer an appropriate lifetime +error[E0758]: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:33:69 | LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } | ------- -------------------------------- ^ ...and is captured here | | | - | | ...is required to be `'static` by this... + | | ...is required to live as long as `'static` by this... | this data with lifetime `'a`... | help: consider changing the `impl Trait`'s explicit `'static` bound to lifetime `'a` @@ -105,24 +105,24 @@ LL | fn ty_param_wont_outlive_static(x: T) -> impl Debug + 'static { | | | help: consider adding an explicit lifetime bound...: `T: 'static +` -error: cannot infer an appropriate lifetime +error[E0758]: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:18:50 | LL | fn elided3(x: &i32) -> Box { Box::new(x) } - | ---- ^ ...is captured here with a `'static` requirement + | ---- ^ ...is captured here requiring it to live as long as `'static` | | - | this data with the anonymous lifetime `'_`... + | this data with an anonymous lifetime `'_`... | -help: to permit non-static references in a trait object value, you can add an explicit bound for the anonymous lifetime `'_` +help: to permit non-static references in a trait object value, you can add an explicit bound for an anonymous lifetime `'_` | LL | fn elided3(x: &i32) -> Box { Box::new(x) } | ^^^^ -error: cannot infer an appropriate lifetime +error[E0758]: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:21:59 | LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) } - | ------- ^ ...is captured here with a `'static` requirement + | ------- ^ ...is captured here requiring it to live as long as `'static` | | | this data with lifetime `'a`... | @@ -131,15 +131,15 @@ help: to permit non-static references in a trait object value, you can add an ex LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) } | ^^^^ -error: cannot infer an appropriate lifetime +error[E0758]: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:24:60 | LL | fn elided4(x: &i32) -> Box { Box::new(x) } - | ---- ^ ...is captured here with a `'static` requirement + | ---- ^ ...is captured here requiring it to live as long as `'static` | | - | this data with the anonymous lifetime `'_`... + | this data with an anonymous lifetime `'_`... | -help: consider changing the trait object's explicit `'static` bound to the anonymous lifetime `'_` +help: consider changing the trait object's explicit `'static` bound to an anonymous lifetime `'_` | LL | fn elided4(x: &i32) -> Box { Box::new(x) } | ^^ @@ -148,11 +148,11 @@ help: alternatively, set an explicit `'static` lifetime in this parameter LL | fn elided4(x: &'static i32) -> Box { Box::new(x) } | ^^^^^^^^^^^^ -error: cannot infer an appropriate lifetime +error[E0758]: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:27:69 | LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } - | ------- this data with lifetime `'a`... ^ ...is captured here with a `'static` requirement + | ------- this data with lifetime `'a`... ^ ...is captured here requiring it to live as long as `'static` | help: consider changing the trait object's explicit `'static` bound to lifetime `'a` | diff --git a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr index 67d4f60dff6f1..a48580ee2d2fc 100644 --- a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr +++ b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr @@ -1,25 +1,25 @@ -error: cannot infer an appropriate lifetime +error[E0758]: cannot infer an appropriate lifetime --> $DIR/static-return-lifetime-infered.rs:7:16 | LL | fn iter_values_anon(&self) -> impl Iterator { - | ----- ----------------------- ...is required to be `'static` by this... + | ----- ----------------------- ...is required to live as long as `'static` by this... | | - | this data with the anonymous lifetime `'_`... + | this data with an anonymous lifetime `'_`... LL | self.x.iter().map(|a| a.0) | ------ ^^^^ | | | ...and is captured here | -help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the anonymous lifetime `'_` +help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for an anonymous lifetime `'_` | LL | fn iter_values_anon(&self) -> impl Iterator + '_ { | ^^^^ -error: cannot infer an appropriate lifetime +error[E0758]: cannot infer an appropriate lifetime --> $DIR/static-return-lifetime-infered.rs:11:16 | LL | fn iter_values<'a>(&'a self) -> impl Iterator { - | -------- ----------------------- ...is required to be `'static` by this... + | -------- ----------------------- ...is required to live as long as `'static` by this... | | | this data with lifetime `'a`... LL | self.x.iter().map(|a| a.0) diff --git a/src/test/ui/issues/issue-16922.stderr b/src/test/ui/issues/issue-16922.stderr index a254343cd1bb7..53fd658800a7a 100644 --- a/src/test/ui/issues/issue-16922.stderr +++ b/src/test/ui/issues/issue-16922.stderr @@ -1,12 +1,12 @@ -error: cannot infer an appropriate lifetime +error[E0758]: cannot infer an appropriate lifetime --> $DIR/issue-16922.rs:4:14 | LL | fn foo(value: &T) -> Box { - | -- this data with the anonymous lifetime `'_`... + | -- this data with an anonymous lifetime `'_`... LL | Box::new(value) as Box - | ^^^^^ ...is captured here with a `'static` requirement + | ^^^^^ ...is captured here requiring it to live as long as `'static` | -help: to permit non-static references in a trait object value, you can add an explicit bound for the anonymous lifetime `'_` +help: to permit non-static references in a trait object value, you can add an explicit bound for an anonymous lifetime `'_` | LL | fn foo(value: &T) -> Box { | ^^^^ diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr index 6edef8086b937..04a06104faf99 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr @@ -1,13 +1,13 @@ -error: cannot infer an appropriate lifetime +error[E0758]: cannot infer an appropriate lifetime --> $DIR/object-lifetime-default-from-box-error.rs:18:5 | LL | fn load(ss: &mut SomeStruct) -> Box { - | --------------- this data with the anonymous lifetime `'_`... + | --------------- this data with an anonymous lifetime `'_`... ... LL | ss.r - | ^^^^ ...is captured and required to be `'static` here + | ^^^^ ...is captured and required live as long as `'static` here | -help: to permit non-static references in a trait object value, you can add an explicit bound for the anonymous lifetime `'_` +help: to permit non-static references in a trait object value, you can add an explicit bound for an anonymous lifetime `'_` | LL | fn load(ss: &mut SomeStruct) -> Box { | ^^^^ diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr index 97d1f3579fcd8..34cf131319a1c 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr @@ -1,12 +1,12 @@ -error: cannot infer an appropriate lifetime +error[E0758]: cannot infer an appropriate lifetime --> $DIR/region-object-lifetime-in-coercion.rs:8:46 | LL | fn a(v: &[u8]) -> Box { - | ----- this data with the anonymous lifetime `'_`... + | ----- this data with an anonymous lifetime `'_`... LL | let x: Box = Box::new(v); - | ^ ...is captured here with a `'static` requirement + | ^ ...is captured here requiring it to live as long as `'static` | -help: consider changing the trait object's explicit `'static` bound to the anonymous lifetime `'_` +help: consider changing the trait object's explicit `'static` bound to an anonymous lifetime `'_` | LL | fn a(v: &[u8]) -> Box { | ^^ @@ -15,15 +15,15 @@ help: alternatively, set an explicit `'static` lifetime in this parameter LL | fn a(v: &'static [u8]) -> Box { | ^^^^^^^^^^^^^ -error: cannot infer an appropriate lifetime +error[E0758]: cannot infer an appropriate lifetime --> $DIR/region-object-lifetime-in-coercion.rs:13:14 | LL | fn b(v: &[u8]) -> Box { - | ----- this data with the anonymous lifetime `'_`... + | ----- this data with an anonymous lifetime `'_`... LL | Box::new(v) - | ^ ...is captured here with a `'static` requirement + | ^ ...is captured here requiring it to live as long as `'static` | -help: consider changing the trait object's explicit `'static` bound to the anonymous lifetime `'_` +help: consider changing the trait object's explicit `'static` bound to an anonymous lifetime `'_` | LL | fn b(v: &[u8]) -> Box { | ^^ @@ -32,16 +32,16 @@ help: alternatively, set an explicit `'static` lifetime in this parameter LL | fn b(v: &'static [u8]) -> Box { | ^^^^^^^^^^^^^ -error: cannot infer an appropriate lifetime +error[E0758]: cannot infer an appropriate lifetime --> $DIR/region-object-lifetime-in-coercion.rs:19:14 | LL | fn c(v: &[u8]) -> Box { - | ----- this data with the anonymous lifetime `'_`... + | ----- this data with an anonymous lifetime `'_`... ... LL | Box::new(v) - | ^ ...is captured here with a `'static` requirement + | ^ ...is captured here requiring it to live as long as `'static` | -help: to permit non-static references in a trait object value, you can add an explicit bound for the anonymous lifetime `'_` +help: to permit non-static references in a trait object value, you can add an explicit bound for an anonymous lifetime `'_` | LL | fn c(v: &[u8]) -> Box { | ^^^^ diff --git a/src/test/ui/regions/regions-close-object-into-object-2.stderr b/src/test/ui/regions/regions-close-object-into-object-2.stderr index 3d707f2d99941..be47ef589af8c 100644 --- a/src/test/ui/regions/regions-close-object-into-object-2.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-2.stderr @@ -1,10 +1,10 @@ -error: cannot infer an appropriate lifetime +error[E0758]: cannot infer an appropriate lifetime --> $DIR/regions-close-object-into-object-2.rs:10:11 | LL | fn g<'a, T: 'static>(v: Box + 'a>) -> Box { | ------------------ this data with lifetime `'a`... LL | box B(&*v) as Box - | ^^^ ...is captured here with a `'static` requirement + | ^^^ ...is captured here requiring it to live as long as `'static` | help: consider changing the trait object's explicit `'static` bound to lifetime `'a` | diff --git a/src/test/ui/regions/regions-close-object-into-object-4.stderr b/src/test/ui/regions/regions-close-object-into-object-4.stderr index 70282c8cbdb30..1b099c7d8bdf0 100644 --- a/src/test/ui/regions/regions-close-object-into-object-4.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-4.stderr @@ -1,10 +1,10 @@ -error: cannot infer an appropriate lifetime +error[E0758]: cannot infer an appropriate lifetime --> $DIR/regions-close-object-into-object-4.rs:10:11 | LL | fn i<'a, T, U>(v: Box+'a>) -> Box { | ---------------- this data with lifetime `'a`... LL | box B(&*v) as Box - | ^^^ ...is captured here with a `'static` requirement + | ^^^ ...is captured here requiring it to live as long as `'static` | help: consider changing the trait object's explicit `'static` bound to lifetime `'a` | diff --git a/src/test/ui/regions/regions-proc-bound-capture.stderr b/src/test/ui/regions/regions-proc-bound-capture.stderr index 8f93fad7fe9d8..e8baf44bd10aa 100644 --- a/src/test/ui/regions/regions-proc-bound-capture.stderr +++ b/src/test/ui/regions/regions-proc-bound-capture.stderr @@ -1,13 +1,13 @@ -error: cannot infer an appropriate lifetime +error[E0758]: cannot infer an appropriate lifetime --> $DIR/regions-proc-bound-capture.rs:9:14 | LL | fn static_proc(x: &isize) -> Box (isize) + 'static> { - | ------ this data with the anonymous lifetime `'_`... + | ------ this data with an anonymous lifetime `'_`... LL | // This is illegal, because the region bound on `proc` is 'static. LL | Box::new(move || { *x }) - | ^^^^^^^^^^^^^^ ...is captured here with a `'static` requirement + | ^^^^^^^^^^^^^^ ...is captured here requiring it to live as long as `'static` | -help: consider changing the trait object's explicit `'static` bound to the anonymous lifetime `'_` +help: consider changing the trait object's explicit `'static` bound to an anonymous lifetime `'_` | LL | fn static_proc(x: &isize) -> Box (isize) + '_> { | ^^ diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr index 5520341b5b1c3..92e1473a5da73 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr @@ -1,10 +1,10 @@ -error: cannot infer an appropriate lifetime +error[E0758]: cannot infer an appropriate lifetime --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:16 | LL | async fn f(self: Pin<&Self>) -> impl Clone { self } - | ^^^^ ---------- ---------- ...and required to be `'static` by this + | ^^^^ ---------- ---------- ...and required to live as long as `'static` by this | | | - | | this data with the anonymous lifetime `'_`... + | | this data with an anonymous lifetime `'_`... | ...is captured here... error: aborting due to previous error diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr index 5374929f3a45f..6721d41bb73c9 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr @@ -1,13 +1,13 @@ -error: cannot infer an appropriate lifetime +error[E0758]: cannot infer an appropriate lifetime --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:6:44 | LL | fn f(self: Pin<&Self>) -> impl Clone { self } | ---------- ---------- ^^^^ ...and is captured here | | | - | | ...is required to be `'static` by this... - | this data with the anonymous lifetime `'_`... + | | ...is required to live as long as `'static` by this... + | this data with an anonymous lifetime `'_`... | -help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the anonymous lifetime `'_` +help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for an anonymous lifetime `'_` | LL | fn f(self: Pin<&Self>) -> impl Clone + '_ { self } | ^^^^ diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr index 471f3cd14aa3e..ba56255af5b0c 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr @@ -6,20 +6,20 @@ LL | fn baz(g: G, dest: &mut T) -> impl FnOnce() + '_ | | | help: consider introducing lifetime `'a` here: `'a,` -error: cannot infer an appropriate lifetime +error[E0758]: cannot infer an appropriate lifetime --> $DIR/missing-lifetimes-in-signature.rs:19:5 | LL | fn foo(g: G, dest: &mut T) -> impl FnOnce() - | ------ ------------- ...is required to be `'static` by this... + | ------ ------------- ...is required to live as long as `'static` by this... | | - | this data with the anonymous lifetime `'_`... + | this data with an anonymous lifetime `'_`... ... LL | / move || { LL | | *dest = g.get(); LL | | } | |_____^ ...and is captured here | -help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the anonymous lifetime `'_` +help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for an anonymous lifetime `'_` | LL | fn foo(g: G, dest: &mut T) -> impl FnOnce() + '_ | ^^^^ diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr index 5fd03f9770e5d..20d3640d4118e 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr @@ -1,13 +1,13 @@ -error: cannot infer an appropriate lifetime +error[E0758]: cannot infer an appropriate lifetime --> $DIR/dyn-trait-underscore.rs:8:20 | LL | fn a(items: &[T]) -> Box> { - | ---- this data with the anonymous lifetime `'_`... + | ---- this data with an anonymous lifetime `'_`... LL | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static` LL | Box::new(items.iter()) - | ---------------^^^^--- ...is captured and required to be `'static` here + | ---------------^^^^--- ...is captured and required live as long as `'static` here | -help: to permit non-static references in a trait object value, you can add an explicit bound for the anonymous lifetime `'_` +help: to permit non-static references in a trait object value, you can add an explicit bound for an anonymous lifetime `'_` | LL | fn a(items: &[T]) -> Box + '_> { | ^^^^ From 31ea589a06e336a3d596e20e3a3f4327c8356aa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 1 Jun 2020 16:15:10 -0700 Subject: [PATCH 33/42] review comments: wording --- .../nice_region_error/static_impl_trait.rs | 58 ++++++++++--------- .../ui/async-await/issues/issue-62097.stderr | 2 +- .../must_outlive_least_region_or_bound.stderr | 46 +++++++-------- .../static-return-lifetime-infered.stderr | 8 +-- src/test/ui/issues/issue-16922.stderr | 4 +- ...ect-lifetime-default-from-box-error.stderr | 2 +- .../region-object-lifetime-in-coercion.stderr | 16 ++--- .../regions-close-object-into-object-2.stderr | 6 +- .../regions-close-object-into-object-4.stderr | 6 +- .../regions/regions-proc-bound-capture.stderr | 6 +- ...types_pin_lifetime_impl_trait-async.stderr | 2 +- ..._self_types_pin_lifetime_impl_trait.stderr | 4 +- .../missing-lifetimes-in-signature.stderr | 4 +- .../dyn-trait-underscore.stderr | 2 +- 14 files changed, 85 insertions(+), 81 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs index 4e16e8c2c5717..86f310eb71d76 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -75,18 +75,18 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // | ---- ^ err.span_label( sup_origin.span(), - "...is captured here requiring it to live as long as `'static`", + "...is captured here, requiring it to live as long as `'static`", ); } else if sup_origin.span() <= return_sp { err.span_label(sup_origin.span(), "...is captured here..."); err.span_label( return_sp, - "...and required to live as long as `'static` by this", + "...and is required to live as long as `'static` here", ); } else { err.span_label( return_sp, - "...is required to live as long as `'static` by this...", + "...is required to live as long as `'static` here...", ); err.span_label(sup_origin.span(), "...and is captured here"); } @@ -101,6 +101,20 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // explicit non-desugar'able return. if fn_return.span.desugaring_kind().is_none() { // FIXME: account for the need of parens in `&(dyn Trait + '_)` + + let consider = "consider changing the"; + let declare = "to declare that the"; + let arg = match param_info.param.pat.simple_ident() { + Some(simple_ident) => format!("argument `{}`", simple_ident), + None => "the argument".to_string(), + }; + let explicit = + format!("you can add an explicit `{}` lifetime bound", lifetime_name); + let explicit_static = format!("explicit `'static` bound to {}", arg); + let captures = format!("captures data from {}", arg); + let add_static_bound = + "alternatively, add an explicit `'static` bound to this reference"; + let plus_lt = format!(" + {}", lifetime_name); match fn_return.kind { TyKind::Def(item_id, _) => { let item = self.tcx().hir().item(item_id.id); @@ -126,18 +140,13 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { { err.span_suggestion_verbose( span, - &format!( - "consider changing the `impl Trait`'s explicit \ - `'static` bound to {}", - lifetime, - ), + &format!("{} `impl Trait`'s {}", consider, explicit_static), lifetime_name, Applicability::MaybeIncorrect, ); err.span_suggestion_verbose( param_info.param_ty_span, - "alternatively, set an explicit `'static` lifetime to \ - this parameter", + add_static_bound, param_info.param_ty.to_string(), Applicability::MaybeIncorrect, ); @@ -145,11 +154,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { err.span_suggestion_verbose( fn_return.span.shrink_to_hi(), &format!( - "to permit non-static references in an `impl Trait` \ - value, you can add an explicit bound for {}", - lifetime, + "{declare} `impl Trait` {captures}, {explicit}", + declare = declare, + captures = captures, + explicit = explicit, ), - format!(" + {}", lifetime_name), + plus_lt, Applicability::MaybeIncorrect, ); }; @@ -159,31 +169,25 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { err.span_suggestion_verbose( fn_return.span.shrink_to_hi(), &format!( - "to permit non-static references in a trait object \ - value, you can add an explicit bound for {}", - lifetime, + "{declare} trait object {captures}, {explicit}", + declare = declare, + captures = captures, + explicit = explicit, ), - format!(" + {}", lifetime_name), + plus_lt, Applicability::MaybeIncorrect, ); } _ => { err.span_suggestion_verbose( lt.span, - &format!( - "consider changing the trait object's explicit \ - `'static` bound to {}", - lifetime, - ), + &format!("{} trait object's {}", consider, explicit_static), lifetime_name, Applicability::MaybeIncorrect, ); err.span_suggestion_verbose( param_info.param_ty_span, - &format!( - "alternatively, set an explicit `'static` lifetime \ - in this parameter", - ), + add_static_bound, param_info.param_ty.to_string(), Applicability::MaybeIncorrect, ); diff --git a/src/test/ui/async-await/issues/issue-62097.stderr b/src/test/ui/async-await/issues/issue-62097.stderr index 558d89f928945..e9f155c6ced31 100644 --- a/src/test/ui/async-await/issues/issue-62097.stderr +++ b/src/test/ui/async-await/issues/issue-62097.stderr @@ -7,7 +7,7 @@ LL | pub async fn run_dummy_fn(&self) { | this data with an anonymous lifetime `'_`... | ...is captured here... LL | foo(|| self.bar()).await; - | --- ...and required to live as long as `'static` by this + | --- ...and is required to live as long as `'static` here error: aborting due to previous error diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr index eff56ddc440d4..a9fa0e93fed61 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -4,10 +4,10 @@ error[E0758]: cannot infer an appropriate lifetime LL | fn elided(x: &i32) -> impl Copy { x } | ---- --------- ^ ...and is captured here | | | - | | ...is required to live as long as `'static` by this... + | | ...is required to live as long as `'static` here... | this data with an anonymous lifetime `'_`... | -help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for an anonymous lifetime `'_` +help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'_` lifetime bound | LL | fn elided(x: &i32) -> impl Copy + '_ { x } | ^^^^ @@ -18,10 +18,10 @@ error[E0758]: cannot infer an appropriate lifetime LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x } | ------- --------- ^ ...and is captured here | | | - | | ...is required to live as long as `'static` by this... + | | ...is required to live as long as `'static` here... | this data with lifetime `'a`... | -help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for lifetime `'a` +help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'a` lifetime bound | LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x } | ^^^^ @@ -32,14 +32,14 @@ error[E0758]: cannot infer an appropriate lifetime LL | fn elided2(x: &i32) -> impl Copy + 'static { x } | ---- ------------------- ^ ...and is captured here | | | - | | ...is required to live as long as `'static` by this... + | | ...is required to live as long as `'static` here... | this data with an anonymous lifetime `'_`... | -help: consider changing the `impl Trait`'s explicit `'static` bound to an anonymous lifetime `'_` +help: consider changing the `impl Trait`'s explicit `'static` bound to argument `x` | LL | fn elided2(x: &i32) -> impl Copy + '_ { x } | ^^ -help: alternatively, set an explicit `'static` lifetime to this parameter +help: alternatively, add an explicit `'static` bound to this reference | LL | fn elided2(x: &'static i32) -> impl Copy + 'static { x } | ^^^^^^^^^^^^ @@ -50,14 +50,14 @@ error[E0758]: cannot infer an appropriate lifetime LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } | ------- ------------------- ^ ...and is captured here | | | - | | ...is required to live as long as `'static` by this... + | | ...is required to live as long as `'static` here... | this data with lifetime `'a`... | -help: consider changing the `impl Trait`'s explicit `'static` bound to lifetime `'a` +help: consider changing the `impl Trait`'s explicit `'static` bound to argument `x` | LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'a { x } | ^^ -help: alternatively, set an explicit `'static` lifetime to this parameter +help: alternatively, add an explicit `'static` bound to this reference | LL | fn explicit2<'a>(x: &'static i32) -> impl Copy + 'static { x } | ^^^^^^^^^^^^ @@ -76,14 +76,14 @@ error[E0758]: cannot infer an appropriate lifetime LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } | ------- -------------------------------- ^ ...and is captured here | | | - | | ...is required to live as long as `'static` by this... + | | ...is required to live as long as `'static` here... | this data with lifetime `'a`... | -help: consider changing the `impl Trait`'s explicit `'static` bound to lifetime `'a` +help: consider changing the `impl Trait`'s explicit `'static` bound to argument `x` | LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'a { x } | ^^ -help: alternatively, set an explicit `'static` lifetime to this parameter +help: alternatively, add an explicit `'static` bound to this reference | LL | fn with_bound<'a>(x: &'static i32) -> impl LifetimeTrait<'a> + 'static { x } | ^^^^^^^^^^^^ @@ -109,11 +109,11 @@ error[E0758]: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:18:50 | LL | fn elided3(x: &i32) -> Box { Box::new(x) } - | ---- ^ ...is captured here requiring it to live as long as `'static` + | ---- ^ ...is captured here, requiring it to live as long as `'static` | | | this data with an anonymous lifetime `'_`... | -help: to permit non-static references in a trait object value, you can add an explicit bound for an anonymous lifetime `'_` +help: to declare that the trait object captures data from argument `x`, you can add an explicit `'_` lifetime bound | LL | fn elided3(x: &i32) -> Box { Box::new(x) } | ^^^^ @@ -122,11 +122,11 @@ error[E0758]: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:21:59 | LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) } - | ------- ^ ...is captured here requiring it to live as long as `'static` + | ------- ^ ...is captured here, requiring it to live as long as `'static` | | | this data with lifetime `'a`... | -help: to permit non-static references in a trait object value, you can add an explicit bound for lifetime `'a` +help: to declare that the trait object captures data from argument `x`, you can add an explicit `'a` lifetime bound | LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) } | ^^^^ @@ -135,15 +135,15 @@ error[E0758]: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:24:60 | LL | fn elided4(x: &i32) -> Box { Box::new(x) } - | ---- ^ ...is captured here requiring it to live as long as `'static` + | ---- ^ ...is captured here, requiring it to live as long as `'static` | | | this data with an anonymous lifetime `'_`... | -help: consider changing the trait object's explicit `'static` bound to an anonymous lifetime `'_` +help: consider changing the trait object's explicit `'static` bound to argument `x` | LL | fn elided4(x: &i32) -> Box { Box::new(x) } | ^^ -help: alternatively, set an explicit `'static` lifetime in this parameter +help: alternatively, add an explicit `'static` bound to this reference | LL | fn elided4(x: &'static i32) -> Box { Box::new(x) } | ^^^^^^^^^^^^ @@ -152,13 +152,13 @@ error[E0758]: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:27:69 | LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } - | ------- this data with lifetime `'a`... ^ ...is captured here requiring it to live as long as `'static` + | ------- this data with lifetime `'a`... ^ ...is captured here, requiring it to live as long as `'static` | -help: consider changing the trait object's explicit `'static` bound to lifetime `'a` +help: consider changing the trait object's explicit `'static` bound to argument `x` | LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } | ^^ -help: alternatively, set an explicit `'static` lifetime in this parameter +help: alternatively, add an explicit `'static` bound to this reference | LL | fn explicit4<'a>(x: &'static i32) -> Box { Box::new(x) } | ^^^^^^^^^^^^ diff --git a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr index a48580ee2d2fc..6681eaa909ee0 100644 --- a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr +++ b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr @@ -2,7 +2,7 @@ error[E0758]: cannot infer an appropriate lifetime --> $DIR/static-return-lifetime-infered.rs:7:16 | LL | fn iter_values_anon(&self) -> impl Iterator { - | ----- ----------------------- ...is required to live as long as `'static` by this... + | ----- ----------------------- ...is required to live as long as `'static` here... | | | this data with an anonymous lifetime `'_`... LL | self.x.iter().map(|a| a.0) @@ -10,7 +10,7 @@ LL | self.x.iter().map(|a| a.0) | | | ...and is captured here | -help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for an anonymous lifetime `'_` +help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'_` lifetime bound | LL | fn iter_values_anon(&self) -> impl Iterator + '_ { | ^^^^ @@ -19,7 +19,7 @@ error[E0758]: cannot infer an appropriate lifetime --> $DIR/static-return-lifetime-infered.rs:11:16 | LL | fn iter_values<'a>(&'a self) -> impl Iterator { - | -------- ----------------------- ...is required to live as long as `'static` by this... + | -------- ----------------------- ...is required to live as long as `'static` here... | | | this data with lifetime `'a`... LL | self.x.iter().map(|a| a.0) @@ -27,7 +27,7 @@ LL | self.x.iter().map(|a| a.0) | | | ...and is captured here | -help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for lifetime `'a` +help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'a` lifetime bound | LL | fn iter_values<'a>(&'a self) -> impl Iterator + 'a { | ^^^^ diff --git a/src/test/ui/issues/issue-16922.stderr b/src/test/ui/issues/issue-16922.stderr index 53fd658800a7a..95f46bd7f3eb6 100644 --- a/src/test/ui/issues/issue-16922.stderr +++ b/src/test/ui/issues/issue-16922.stderr @@ -4,9 +4,9 @@ error[E0758]: cannot infer an appropriate lifetime LL | fn foo(value: &T) -> Box { | -- this data with an anonymous lifetime `'_`... LL | Box::new(value) as Box - | ^^^^^ ...is captured here requiring it to live as long as `'static` + | ^^^^^ ...is captured here, requiring it to live as long as `'static` | -help: to permit non-static references in a trait object value, you can add an explicit bound for an anonymous lifetime `'_` +help: to declare that the trait object captures data from argument `value`, you can add an explicit `'_` lifetime bound | LL | fn foo(value: &T) -> Box { | ^^^^ diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr index 04a06104faf99..e585db262f2d8 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr @@ -7,7 +7,7 @@ LL | fn load(ss: &mut SomeStruct) -> Box { LL | ss.r | ^^^^ ...is captured and required live as long as `'static` here | -help: to permit non-static references in a trait object value, you can add an explicit bound for an anonymous lifetime `'_` +help: to declare that the trait object captures data from argument `ss`, you can add an explicit `'_` lifetime bound | LL | fn load(ss: &mut SomeStruct) -> Box { | ^^^^ diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr index 34cf131319a1c..8d048d90cb345 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr @@ -4,13 +4,13 @@ error[E0758]: cannot infer an appropriate lifetime LL | fn a(v: &[u8]) -> Box { | ----- this data with an anonymous lifetime `'_`... LL | let x: Box = Box::new(v); - | ^ ...is captured here requiring it to live as long as `'static` + | ^ ...is captured here, requiring it to live as long as `'static` | -help: consider changing the trait object's explicit `'static` bound to an anonymous lifetime `'_` +help: consider changing the trait object's explicit `'static` bound to argument `v` | LL | fn a(v: &[u8]) -> Box { | ^^ -help: alternatively, set an explicit `'static` lifetime in this parameter +help: alternatively, add an explicit `'static` bound to this reference | LL | fn a(v: &'static [u8]) -> Box { | ^^^^^^^^^^^^^ @@ -21,13 +21,13 @@ error[E0758]: cannot infer an appropriate lifetime LL | fn b(v: &[u8]) -> Box { | ----- this data with an anonymous lifetime `'_`... LL | Box::new(v) - | ^ ...is captured here requiring it to live as long as `'static` + | ^ ...is captured here, requiring it to live as long as `'static` | -help: consider changing the trait object's explicit `'static` bound to an anonymous lifetime `'_` +help: consider changing the trait object's explicit `'static` bound to argument `v` | LL | fn b(v: &[u8]) -> Box { | ^^ -help: alternatively, set an explicit `'static` lifetime in this parameter +help: alternatively, add an explicit `'static` bound to this reference | LL | fn b(v: &'static [u8]) -> Box { | ^^^^^^^^^^^^^ @@ -39,9 +39,9 @@ LL | fn c(v: &[u8]) -> Box { | ----- this data with an anonymous lifetime `'_`... ... LL | Box::new(v) - | ^ ...is captured here requiring it to live as long as `'static` + | ^ ...is captured here, requiring it to live as long as `'static` | -help: to permit non-static references in a trait object value, you can add an explicit bound for an anonymous lifetime `'_` +help: to declare that the trait object captures data from argument `v`, you can add an explicit `'_` lifetime bound | LL | fn c(v: &[u8]) -> Box { | ^^^^ diff --git a/src/test/ui/regions/regions-close-object-into-object-2.stderr b/src/test/ui/regions/regions-close-object-into-object-2.stderr index be47ef589af8c..5dfe384112b2a 100644 --- a/src/test/ui/regions/regions-close-object-into-object-2.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-2.stderr @@ -4,13 +4,13 @@ error[E0758]: cannot infer an appropriate lifetime LL | fn g<'a, T: 'static>(v: Box + 'a>) -> Box { | ------------------ this data with lifetime `'a`... LL | box B(&*v) as Box - | ^^^ ...is captured here requiring it to live as long as `'static` + | ^^^ ...is captured here, requiring it to live as long as `'static` | -help: consider changing the trait object's explicit `'static` bound to lifetime `'a` +help: consider changing the trait object's explicit `'static` bound to argument `v` | LL | fn g<'a, T: 'static>(v: Box + 'a>) -> Box { | ^^ -help: alternatively, set an explicit `'static` lifetime in this parameter +help: alternatively, add an explicit `'static` bound to this reference | LL | fn g<'a, T: 'static>(v: std::boxed::Box<(dyn A + 'static)>) -> Box { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/regions/regions-close-object-into-object-4.stderr b/src/test/ui/regions/regions-close-object-into-object-4.stderr index 1b099c7d8bdf0..4d23118ba06f0 100644 --- a/src/test/ui/regions/regions-close-object-into-object-4.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-4.stderr @@ -4,13 +4,13 @@ error[E0758]: cannot infer an appropriate lifetime LL | fn i<'a, T, U>(v: Box+'a>) -> Box { | ---------------- this data with lifetime `'a`... LL | box B(&*v) as Box - | ^^^ ...is captured here requiring it to live as long as `'static` + | ^^^ ...is captured here, requiring it to live as long as `'static` | -help: consider changing the trait object's explicit `'static` bound to lifetime `'a` +help: consider changing the trait object's explicit `'static` bound to argument `v` | LL | fn i<'a, T, U>(v: Box+'a>) -> Box { | ^^ -help: alternatively, set an explicit `'static` lifetime in this parameter +help: alternatively, add an explicit `'static` bound to this reference | LL | fn i<'a, T, U>(v: std::boxed::Box<(dyn A + 'static)>) -> Box { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/regions/regions-proc-bound-capture.stderr b/src/test/ui/regions/regions-proc-bound-capture.stderr index e8baf44bd10aa..e36f77ec1da96 100644 --- a/src/test/ui/regions/regions-proc-bound-capture.stderr +++ b/src/test/ui/regions/regions-proc-bound-capture.stderr @@ -5,13 +5,13 @@ LL | fn static_proc(x: &isize) -> Box (isize) + 'static> { | ------ this data with an anonymous lifetime `'_`... LL | // This is illegal, because the region bound on `proc` is 'static. LL | Box::new(move || { *x }) - | ^^^^^^^^^^^^^^ ...is captured here requiring it to live as long as `'static` + | ^^^^^^^^^^^^^^ ...is captured here, requiring it to live as long as `'static` | -help: consider changing the trait object's explicit `'static` bound to an anonymous lifetime `'_` +help: consider changing the trait object's explicit `'static` bound to argument `x` | LL | fn static_proc(x: &isize) -> Box (isize) + '_> { | ^^ -help: alternatively, set an explicit `'static` lifetime in this parameter +help: alternatively, add an explicit `'static` bound to this reference | LL | fn static_proc(x: &'static isize) -> Box (isize) + 'static> { | ^^^^^^^^^^^^^^ diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr index 92e1473a5da73..365e38515b12c 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr @@ -2,7 +2,7 @@ error[E0758]: cannot infer an appropriate lifetime --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:16 | LL | async fn f(self: Pin<&Self>) -> impl Clone { self } - | ^^^^ ---------- ---------- ...and required to live as long as `'static` by this + | ^^^^ ---------- ---------- ...and is required to live as long as `'static` here | | | | | this data with an anonymous lifetime `'_`... | ...is captured here... diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr index 6721d41bb73c9..bd3f3efad82f2 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr @@ -4,10 +4,10 @@ error[E0758]: cannot infer an appropriate lifetime LL | fn f(self: Pin<&Self>) -> impl Clone { self } | ---------- ---------- ^^^^ ...and is captured here | | | - | | ...is required to live as long as `'static` by this... + | | ...is required to live as long as `'static` here... | this data with an anonymous lifetime `'_`... | -help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for an anonymous lifetime `'_` +help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'_` lifetime bound | LL | fn f(self: Pin<&Self>) -> impl Clone + '_ { self } | ^^^^ diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr index ba56255af5b0c..d96a5f961bdb8 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr @@ -10,7 +10,7 @@ error[E0758]: cannot infer an appropriate lifetime --> $DIR/missing-lifetimes-in-signature.rs:19:5 | LL | fn foo(g: G, dest: &mut T) -> impl FnOnce() - | ------ ------------- ...is required to live as long as `'static` by this... + | ------ ------------- ...is required to live as long as `'static` here... | | | this data with an anonymous lifetime `'_`... ... @@ -19,7 +19,7 @@ LL | | *dest = g.get(); LL | | } | |_____^ ...and is captured here | -help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for an anonymous lifetime `'_` +help: to declare that the `impl Trait` captures data from argument `dest`, you can add an explicit `'_` lifetime bound | LL | fn foo(g: G, dest: &mut T) -> impl FnOnce() + '_ | ^^^^ diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr index 20d3640d4118e..7c649f9c08d64 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr @@ -7,7 +7,7 @@ LL | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to LL | Box::new(items.iter()) | ---------------^^^^--- ...is captured and required live as long as `'static` here | -help: to permit non-static references in a trait object value, you can add an explicit bound for an anonymous lifetime `'_` +help: to declare that the trait object captures data from argument `items`, you can add an explicit `'_` lifetime bound | LL | fn a(items: &[T]) -> Box + '_> { | ^^^^ From 10d9bf17671ed1d3099f2b2e25b418931075cda7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 1 Jun 2020 17:51:12 -0700 Subject: [PATCH 34/42] Use note for requirement source span --- .../nice_region_error/static_impl_trait.rs | 10 +--- .../ui/async-await/issues/issue-62097.stderr | 6 ++- .../must_outlive_least_region_or_bound.stderr | 50 +++++++++++++------ .../static-return-lifetime-infered.stderr | 22 +++++--- ...types_pin_lifetime_impl_trait-async.stderr | 11 ++-- ..._self_types_pin_lifetime_impl_trait.stderr | 10 ++-- .../missing-lifetimes-in-signature.stderr | 11 ++-- 7 files changed, 77 insertions(+), 43 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs index 86f310eb71d76..74267a8dec059 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -77,18 +77,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { sup_origin.span(), "...is captured here, requiring it to live as long as `'static`", ); - } else if sup_origin.span() <= return_sp { + } else { err.span_label(sup_origin.span(), "...is captured here..."); - err.span_label( + err.span_note( return_sp, "...and is required to live as long as `'static` here", ); - } else { - err.span_label( - return_sp, - "...is required to live as long as `'static` here...", - ); - err.span_label(sup_origin.span(), "...and is captured here"); } } else { err.span_label( diff --git a/src/test/ui/async-await/issues/issue-62097.stderr b/src/test/ui/async-await/issues/issue-62097.stderr index e9f155c6ced31..ff7007dd30b1b 100644 --- a/src/test/ui/async-await/issues/issue-62097.stderr +++ b/src/test/ui/async-await/issues/issue-62097.stderr @@ -6,8 +6,12 @@ LL | pub async fn run_dummy_fn(&self) { | | | this data with an anonymous lifetime `'_`... | ...is captured here... + | +note: ...and is required to live as long as `'static` here + --> $DIR/issue-62097.rs:13:9 + | LL | foo(|| self.bar()).await; - | --- ...and is required to live as long as `'static` here + | ^^^ error: aborting due to previous error diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr index a9fa0e93fed61..698464b4971a7 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -2,11 +2,15 @@ error[E0758]: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:3:35 | LL | fn elided(x: &i32) -> impl Copy { x } - | ---- --------- ^ ...and is captured here - | | | - | | ...is required to live as long as `'static` here... + | ---- ^ ...is captured here... + | | | this data with an anonymous lifetime `'_`... | +note: ...and is required to live as long as `'static` here + --> $DIR/must_outlive_least_region_or_bound.rs:3:23 + | +LL | fn elided(x: &i32) -> impl Copy { x } + | ^^^^^^^^^ help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'_` lifetime bound | LL | fn elided(x: &i32) -> impl Copy + '_ { x } @@ -16,11 +20,15 @@ error[E0758]: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:6:44 | LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x } - | ------- --------- ^ ...and is captured here - | | | - | | ...is required to live as long as `'static` here... + | ------- ^ ...is captured here... + | | | this data with lifetime `'a`... | +note: ...and is required to live as long as `'static` here + --> $DIR/must_outlive_least_region_or_bound.rs:6:32 + | +LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x } + | ^^^^^^^^^ help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'a` lifetime bound | LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x } @@ -30,11 +38,15 @@ error[E0758]: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:9:46 | LL | fn elided2(x: &i32) -> impl Copy + 'static { x } - | ---- ------------------- ^ ...and is captured here - | | | - | | ...is required to live as long as `'static` here... + | ---- ^ ...is captured here... + | | | this data with an anonymous lifetime `'_`... | +note: ...and is required to live as long as `'static` here + --> $DIR/must_outlive_least_region_or_bound.rs:9:24 + | +LL | fn elided2(x: &i32) -> impl Copy + 'static { x } + | ^^^^^^^^^^^^^^^^^^^ help: consider changing the `impl Trait`'s explicit `'static` bound to argument `x` | LL | fn elided2(x: &i32) -> impl Copy + '_ { x } @@ -48,11 +60,15 @@ error[E0758]: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:12:55 | LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } - | ------- ------------------- ^ ...and is captured here - | | | - | | ...is required to live as long as `'static` here... + | ------- ^ ...is captured here... + | | | this data with lifetime `'a`... | +note: ...and is required to live as long as `'static` here + --> $DIR/must_outlive_least_region_or_bound.rs:12:33 + | +LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } + | ^^^^^^^^^^^^^^^^^^^ help: consider changing the `impl Trait`'s explicit `'static` bound to argument `x` | LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'a { x } @@ -74,11 +90,13 @@ error[E0758]: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:33:69 | LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } - | ------- -------------------------------- ^ ...and is captured here - | | | - | | ...is required to live as long as `'static` here... - | this data with lifetime `'a`... + | ------- this data with lifetime `'a`... ^ ...is captured here... + | +note: ...and is required to live as long as `'static` here + --> $DIR/must_outlive_least_region_or_bound.rs:33:34 | +LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the `impl Trait`'s explicit `'static` bound to argument `x` | LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'a { x } diff --git a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr index 6681eaa909ee0..bcc46785c5918 100644 --- a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr +++ b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr @@ -2,14 +2,17 @@ error[E0758]: cannot infer an appropriate lifetime --> $DIR/static-return-lifetime-infered.rs:7:16 | LL | fn iter_values_anon(&self) -> impl Iterator { - | ----- ----------------------- ...is required to live as long as `'static` here... - | | - | this data with an anonymous lifetime `'_`... + | ----- this data with an anonymous lifetime `'_`... LL | self.x.iter().map(|a| a.0) | ------ ^^^^ | | - | ...and is captured here + | ...is captured here... | +note: ...and is required to live as long as `'static` here + --> $DIR/static-return-lifetime-infered.rs:6:35 + | +LL | fn iter_values_anon(&self) -> impl Iterator { + | ^^^^^^^^^^^^^^^^^^^^^^^ help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'_` lifetime bound | LL | fn iter_values_anon(&self) -> impl Iterator + '_ { @@ -19,14 +22,17 @@ error[E0758]: cannot infer an appropriate lifetime --> $DIR/static-return-lifetime-infered.rs:11:16 | LL | fn iter_values<'a>(&'a self) -> impl Iterator { - | -------- ----------------------- ...is required to live as long as `'static` here... - | | - | this data with lifetime `'a`... + | -------- this data with lifetime `'a`... LL | self.x.iter().map(|a| a.0) | ------ ^^^^ | | - | ...and is captured here + | ...is captured here... | +note: ...and is required to live as long as `'static` here + --> $DIR/static-return-lifetime-infered.rs:10:37 + | +LL | fn iter_values<'a>(&'a self) -> impl Iterator { + | ^^^^^^^^^^^^^^^^^^^^^^^ help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'a` lifetime bound | LL | fn iter_values<'a>(&'a self) -> impl Iterator + 'a { diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr index 365e38515b12c..2ffbf6e08158e 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr @@ -2,10 +2,15 @@ error[E0758]: cannot infer an appropriate lifetime --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:16 | LL | async fn f(self: Pin<&Self>) -> impl Clone { self } - | ^^^^ ---------- ---------- ...and is required to live as long as `'static` here - | | | - | | this data with an anonymous lifetime `'_`... + | ^^^^ ---------- this data with an anonymous lifetime `'_`... + | | | ...is captured here... + | +note: ...and is required to live as long as `'static` here + --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:37 + | +LL | async fn f(self: Pin<&Self>) -> impl Clone { self } + | ^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr index bd3f3efad82f2..2da7bcf543d66 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr @@ -2,11 +2,15 @@ error[E0758]: cannot infer an appropriate lifetime --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:6:44 | LL | fn f(self: Pin<&Self>) -> impl Clone { self } - | ---------- ---------- ^^^^ ...and is captured here - | | | - | | ...is required to live as long as `'static` here... + | ---------- ^^^^ ...is captured here... + | | | this data with an anonymous lifetime `'_`... | +note: ...and is required to live as long as `'static` here + --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:6:31 + | +LL | fn f(self: Pin<&Self>) -> impl Clone { self } + | ^^^^^^^^^^ help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'_` lifetime bound | LL | fn f(self: Pin<&Self>) -> impl Clone + '_ { self } diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr index d96a5f961bdb8..95d905af05089 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr @@ -10,15 +10,18 @@ error[E0758]: cannot infer an appropriate lifetime --> $DIR/missing-lifetimes-in-signature.rs:19:5 | LL | fn foo(g: G, dest: &mut T) -> impl FnOnce() - | ------ ------------- ...is required to live as long as `'static` here... - | | - | this data with an anonymous lifetime `'_`... + | ------ this data with an anonymous lifetime `'_`... ... LL | / move || { LL | | *dest = g.get(); LL | | } - | |_____^ ...and is captured here + | |_____^ ...is captured here... | +note: ...and is required to live as long as `'static` here + --> $DIR/missing-lifetimes-in-signature.rs:15:37 + | +LL | fn foo(g: G, dest: &mut T) -> impl FnOnce() + | ^^^^^^^^^^^^^ help: to declare that the `impl Trait` captures data from argument `dest`, you can add an explicit `'_` lifetime bound | LL | fn foo(g: G, dest: &mut T) -> impl FnOnce() + '_ From 34d8692262a8299025379e5178041d0d52a0329e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 2 Jun 2020 10:47:58 -0700 Subject: [PATCH 35/42] Register new eror code --- src/test/ui/async-await/issues/issue-62097.stderr | 1 + .../ui/impl-trait/must_outlive_least_region_or_bound.stderr | 2 +- src/test/ui/impl-trait/static-return-lifetime-infered.stderr | 1 + src/test/ui/issues/issue-16922.stderr | 1 + .../object-lifetime-default-from-box-error.stderr | 3 ++- src/test/ui/regions/region-object-lifetime-in-coercion.stderr | 3 ++- src/test/ui/regions/regions-close-object-into-object-2.stderr | 1 + src/test/ui/regions/regions-close-object-into-object-4.stderr | 1 + src/test/ui/regions/regions-proc-bound-capture.stderr | 1 + .../arbitrary_self_types_pin_lifetime_impl_trait-async.stderr | 1 + .../self/arbitrary_self_types_pin_lifetime_impl_trait.stderr | 1 + .../lifetimes/missing-lifetimes-in-signature.stderr | 2 +- src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr | 1 + 13 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/test/ui/async-await/issues/issue-62097.stderr b/src/test/ui/async-await/issues/issue-62097.stderr index ff7007dd30b1b..b3754cce40833 100644 --- a/src/test/ui/async-await/issues/issue-62097.stderr +++ b/src/test/ui/async-await/issues/issue-62097.stderr @@ -15,3 +15,4 @@ LL | foo(|| self.bar()).await; error: aborting due to previous error +For more information about this error, try `rustc --explain E0758`. diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr index 698464b4971a7..5ab450a85d9e1 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -183,5 +183,5 @@ LL | fn explicit4<'a>(x: &'static i32) -> Box { Box::new(x) error: aborting due to 12 previous errors -Some errors have detailed explanations: E0310, E0621, E0623. +Some errors have detailed explanations: E0310, E0621, E0623, E0758. For more information about an error, try `rustc --explain E0310`. diff --git a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr index bcc46785c5918..90aada01d9917 100644 --- a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr +++ b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr @@ -40,3 +40,4 @@ LL | fn iter_values<'a>(&'a self) -> impl Iterator + 'a { error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0758`. diff --git a/src/test/ui/issues/issue-16922.stderr b/src/test/ui/issues/issue-16922.stderr index 95f46bd7f3eb6..ec80f6569f5ac 100644 --- a/src/test/ui/issues/issue-16922.stderr +++ b/src/test/ui/issues/issue-16922.stderr @@ -13,3 +13,4 @@ LL | fn foo(value: &T) -> Box { error: aborting due to previous error +For more information about this error, try `rustc --explain E0758`. diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr index e585db262f2d8..ac7502e004c44 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr @@ -23,4 +23,5 @@ LL | ss.r = b; error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0621`. +Some errors have detailed explanations: E0621, E0758. +For more information about an error, try `rustc --explain E0621`. diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr index 8d048d90cb345..fe191e9b69565 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr @@ -79,4 +79,5 @@ LL | Box::new(v) error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0495`. +Some errors have detailed explanations: E0495, E0758. +For more information about an error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-close-object-into-object-2.stderr b/src/test/ui/regions/regions-close-object-into-object-2.stderr index 5dfe384112b2a..2ea970afcede2 100644 --- a/src/test/ui/regions/regions-close-object-into-object-2.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-2.stderr @@ -17,3 +17,4 @@ LL | fn g<'a, T: 'static>(v: std::boxed::Box<(dyn A + 'static)>) -> Box(v: std::boxed::Box<(dyn A + 'static)>) -> Box Box (isize) + 'static> error: aborting due to previous error +For more information about this error, try `rustc --explain E0758`. diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr index 2ffbf6e08158e..69022607bd19e 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr @@ -14,3 +14,4 @@ LL | async fn f(self: Pin<&Self>) -> impl Clone { self } error: aborting due to previous error +For more information about this error, try `rustc --explain E0758`. diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr index 2da7bcf543d66..c37eb2d136ef1 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr @@ -18,3 +18,4 @@ LL | fn f(self: Pin<&Self>) -> impl Clone + '_ { self } error: aborting due to previous error +For more information about this error, try `rustc --explain E0758`. diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr index 95d905af05089..7e8ab1bfe1633 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr @@ -125,5 +125,5 @@ LL | fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a error: aborting due to 7 previous errors -Some errors have detailed explanations: E0261, E0309, E0621. +Some errors have detailed explanations: E0261, E0309, E0621, E0758. For more information about an error, try `rustc --explain E0261`. diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr index 7c649f9c08d64..e768d7c8ab99f 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr @@ -14,3 +14,4 @@ LL | fn a(items: &[T]) -> Box + '_> { error: aborting due to previous error +For more information about this error, try `rustc --explain E0758`. From e31367de6b5ed3878711cdd1761828587b9639fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 2 Jun 2020 16:05:48 -0700 Subject: [PATCH 36/42] small tweaks --- .../nice_region_error/static_impl_trait.rs | 20 +++++++++++++------ .../ui/async-await/issues/issue-62097.stderr | 6 +----- .../must_outlive_least_region_or_bound.stderr | 10 +++++----- ...ect-lifetime-default-from-box-error.stderr | 2 +- .../region-object-lifetime-in-coercion.stderr | 4 ++-- .../regions-close-object-into-object-2.stderr | 2 +- .../regions-close-object-into-object-4.stderr | 2 +- .../regions/regions-proc-bound-capture.stderr | 2 +- ...types_pin_lifetime_impl_trait-async.stderr | 11 +++------- .../dyn-trait-underscore.stderr | 2 +- 10 files changed, 30 insertions(+), 31 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs index 74267a8dec059..5ad76e3964038 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -79,15 +79,22 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { ); } else { err.span_label(sup_origin.span(), "...is captured here..."); - err.span_note( - return_sp, - "...and is required to live as long as `'static` here", - ); + if return_sp < sup_origin.span() { + err.span_note( + return_sp, + "...and is required to live as long as `'static` here", + ); + } else { + err.span_label( + return_sp, + "...and is required to live as long as `'static` here", + ); + } } } else { err.span_label( return_sp, - "...is captured and required live as long as `'static` here", + "...is captured and required to live as long as `'static` here", ); } @@ -104,7 +111,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { }; let explicit = format!("you can add an explicit `{}` lifetime bound", lifetime_name); - let explicit_static = format!("explicit `'static` bound to {}", arg); + let explicit_static = + format!("explicit `'static` bound to the lifetime of {}", arg); let captures = format!("captures data from {}", arg); let add_static_bound = "alternatively, add an explicit `'static` bound to this reference"; diff --git a/src/test/ui/async-await/issues/issue-62097.stderr b/src/test/ui/async-await/issues/issue-62097.stderr index b3754cce40833..aa443b9d2fc16 100644 --- a/src/test/ui/async-await/issues/issue-62097.stderr +++ b/src/test/ui/async-await/issues/issue-62097.stderr @@ -6,12 +6,8 @@ LL | pub async fn run_dummy_fn(&self) { | | | this data with an anonymous lifetime `'_`... | ...is captured here... - | -note: ...and is required to live as long as `'static` here - --> $DIR/issue-62097.rs:13:9 - | LL | foo(|| self.bar()).await; - | ^^^ + | --- ...and is required to live as long as `'static` here error: aborting due to previous error diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr index 5ab450a85d9e1..baed43783a13c 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -47,7 +47,7 @@ note: ...and is required to live as long as `'static` here | LL | fn elided2(x: &i32) -> impl Copy + 'static { x } | ^^^^^^^^^^^^^^^^^^^ -help: consider changing the `impl Trait`'s explicit `'static` bound to argument `x` +help: consider changing the `impl Trait`'s explicit `'static` bound to the lifetime of argument `x` | LL | fn elided2(x: &i32) -> impl Copy + '_ { x } | ^^ @@ -69,7 +69,7 @@ note: ...and is required to live as long as `'static` here | LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } | ^^^^^^^^^^^^^^^^^^^ -help: consider changing the `impl Trait`'s explicit `'static` bound to argument `x` +help: consider changing the `impl Trait`'s explicit `'static` bound to the lifetime of argument `x` | LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'a { x } | ^^ @@ -97,7 +97,7 @@ note: ...and is required to live as long as `'static` here | LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: consider changing the `impl Trait`'s explicit `'static` bound to argument `x` +help: consider changing the `impl Trait`'s explicit `'static` bound to the lifetime of argument `x` | LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'a { x } | ^^ @@ -157,7 +157,7 @@ LL | fn elided4(x: &i32) -> Box { Box::new(x) } | | | this data with an anonymous lifetime `'_`... | -help: consider changing the trait object's explicit `'static` bound to argument `x` +help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x` | LL | fn elided4(x: &i32) -> Box { Box::new(x) } | ^^ @@ -172,7 +172,7 @@ error[E0758]: cannot infer an appropriate lifetime LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } | ------- this data with lifetime `'a`... ^ ...is captured here, requiring it to live as long as `'static` | -help: consider changing the trait object's explicit `'static` bound to argument `x` +help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x` | LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } | ^^ diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr index ac7502e004c44..d461001adead9 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr @@ -5,7 +5,7 @@ LL | fn load(ss: &mut SomeStruct) -> Box { | --------------- this data with an anonymous lifetime `'_`... ... LL | ss.r - | ^^^^ ...is captured and required live as long as `'static` here + | ^^^^ ...is captured and required to live as long as `'static` here | help: to declare that the trait object captures data from argument `ss`, you can add an explicit `'_` lifetime bound | diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr index fe191e9b69565..c684373c67e9d 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr @@ -6,7 +6,7 @@ LL | fn a(v: &[u8]) -> Box { LL | let x: Box = Box::new(v); | ^ ...is captured here, requiring it to live as long as `'static` | -help: consider changing the trait object's explicit `'static` bound to argument `v` +help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v` | LL | fn a(v: &[u8]) -> Box { | ^^ @@ -23,7 +23,7 @@ LL | fn b(v: &[u8]) -> Box { LL | Box::new(v) | ^ ...is captured here, requiring it to live as long as `'static` | -help: consider changing the trait object's explicit `'static` bound to argument `v` +help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v` | LL | fn b(v: &[u8]) -> Box { | ^^ diff --git a/src/test/ui/regions/regions-close-object-into-object-2.stderr b/src/test/ui/regions/regions-close-object-into-object-2.stderr index 2ea970afcede2..c4ba395179831 100644 --- a/src/test/ui/regions/regions-close-object-into-object-2.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-2.stderr @@ -6,7 +6,7 @@ LL | fn g<'a, T: 'static>(v: Box + 'a>) -> Box { LL | box B(&*v) as Box | ^^^ ...is captured here, requiring it to live as long as `'static` | -help: consider changing the trait object's explicit `'static` bound to argument `v` +help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v` | LL | fn g<'a, T: 'static>(v: Box + 'a>) -> Box { | ^^ diff --git a/src/test/ui/regions/regions-close-object-into-object-4.stderr b/src/test/ui/regions/regions-close-object-into-object-4.stderr index 493b7a1df9920..e45930bd95710 100644 --- a/src/test/ui/regions/regions-close-object-into-object-4.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-4.stderr @@ -6,7 +6,7 @@ LL | fn i<'a, T, U>(v: Box+'a>) -> Box { LL | box B(&*v) as Box | ^^^ ...is captured here, requiring it to live as long as `'static` | -help: consider changing the trait object's explicit `'static` bound to argument `v` +help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v` | LL | fn i<'a, T, U>(v: Box+'a>) -> Box { | ^^ diff --git a/src/test/ui/regions/regions-proc-bound-capture.stderr b/src/test/ui/regions/regions-proc-bound-capture.stderr index c10b9850a4e99..69c7256364d70 100644 --- a/src/test/ui/regions/regions-proc-bound-capture.stderr +++ b/src/test/ui/regions/regions-proc-bound-capture.stderr @@ -7,7 +7,7 @@ LL | // This is illegal, because the region bound on `proc` is 'static. LL | Box::new(move || { *x }) | ^^^^^^^^^^^^^^ ...is captured here, requiring it to live as long as `'static` | -help: consider changing the trait object's explicit `'static` bound to argument `x` +help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x` | LL | fn static_proc(x: &isize) -> Box (isize) + '_> { | ^^ diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr index 69022607bd19e..9b04069136be2 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr @@ -2,15 +2,10 @@ error[E0758]: cannot infer an appropriate lifetime --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:16 | LL | async fn f(self: Pin<&Self>) -> impl Clone { self } - | ^^^^ ---------- this data with an anonymous lifetime `'_`... - | | + | ^^^^ ---------- ---------- ...and is required to live as long as `'static` here + | | | + | | this data with an anonymous lifetime `'_`... | ...is captured here... - | -note: ...and is required to live as long as `'static` here - --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:37 - | -LL | async fn f(self: Pin<&Self>) -> impl Clone { self } - | ^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr index e768d7c8ab99f..fc4c801949512 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr @@ -5,7 +5,7 @@ LL | fn a(items: &[T]) -> Box> { | ---- this data with an anonymous lifetime `'_`... LL | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static` LL | Box::new(items.iter()) - | ---------------^^^^--- ...is captured and required live as long as `'static` here + | ---------------^^^^--- ...is captured and required to live as long as `'static` here | help: to declare that the trait object captures data from argument `items`, you can add an explicit `'_` lifetime bound | From f7a1f97307e2f878297c6096f3afcc6fc2a31f22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 3 Jun 2020 11:34:04 -0700 Subject: [PATCH 37/42] Change E0758 to E0759 to avoid conflict with #72912 --- src/librustc_error_codes/error_codes.rs | 1 + src/librustc_error_codes/error_codes/E0759.md | 67 +++++++++++++++++++ .../nice_region_error/static_impl_trait.rs | 2 +- .../ui/async-await/issues/issue-62097.stderr | 4 +- .../must_outlive_least_region_or_bound.stderr | 20 +++--- .../static-return-lifetime-infered.stderr | 6 +- src/test/ui/issues/issue-16922.stderr | 4 +- ...ect-lifetime-default-from-box-error.stderr | 4 +- .../region-object-lifetime-in-coercion.stderr | 8 +-- .../regions-close-object-into-object-2.stderr | 4 +- .../regions-close-object-into-object-4.stderr | 4 +- .../regions/regions-proc-bound-capture.stderr | 4 +- ...types_pin_lifetime_impl_trait-async.stderr | 4 +- ..._self_types_pin_lifetime_impl_trait.stderr | 4 +- .../missing-lifetimes-in-signature.stderr | 4 +- .../dyn-trait-underscore.stderr | 4 +- 16 files changed, 106 insertions(+), 38 deletions(-) create mode 100644 src/librustc_error_codes/error_codes/E0759.md diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs index 3fb5e04efc922..99ef226f94aae 100644 --- a/src/librustc_error_codes/error_codes.rs +++ b/src/librustc_error_codes/error_codes.rs @@ -439,6 +439,7 @@ E0752: include_str!("./error_codes/E0752.md"), E0753: include_str!("./error_codes/E0753.md"), E0754: include_str!("./error_codes/E0754.md"), E0758: include_str!("./error_codes/E0758.md"), +E0759: include_str!("./error_codes/E0759.md"), E0760: include_str!("./error_codes/E0760.md"), E0761: include_str!("./error_codes/E0761.md"), E0762: include_str!("./error_codes/E0762.md"), diff --git a/src/librustc_error_codes/error_codes/E0759.md b/src/librustc_error_codes/error_codes/E0759.md new file mode 100644 index 0000000000000..a74759bdf634b --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0759.md @@ -0,0 +1,67 @@ +A `'static` requirement in a return type involving a trait is not fulfilled. + +Erroneous code examples: + +```compile_fail,E0759 +use std::fmt::Debug; + +fn foo(x: &i32) -> impl Debug { + x +} +``` + +```compile_fail,E0759 +# use std::fmt::Debug; +fn bar(x: &i32) -> Box { + Box::new(x) +} +``` + +These examples have the same semantics as the following: + +```compile_fail,E0759 +# use std::fmt::Debug; +fn foo(x: &i32) -> impl Debug + 'static { + x +} +``` + +```compile_fail,E0759 +# use std::fmt::Debug; +fn bar(x: &i32) -> Box { + Box::new(x) +} +``` + +Both [`dyn Trait`] and [`impl Trait`] in return types have a an implicit +`'static` requirement, meaning that the value implementing them that is being +returned has to be either a `'static` borrow or an owned value. + +In order to change the requirement from `'static` to be a lifetime derived from +its arguments, you can add an explicit bound, either to an anonymous lifetime +`'_` or some appropriate named lifetime. + +``` +# use std::fmt::Debug; +fn foo(x: &i32) -> impl Debug + '_ { + x +} +fn bar(x: &i32) -> Box { + Box::new(x) +} +``` + +These are equivalent to the following explicit lifetime annotations: + +``` +# use std::fmt::Debug; +fn foo<'a>(x: &'a i32) -> impl Debug + 'a { + x +} +fn bar<'a>(x: &'a i32) -> Box { + Box::new(x) +} +``` + +[`dyn Trait`]: https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types +[`impl Trait`]: https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs index 5ad76e3964038..853a414290704 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -40,7 +40,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let mut err = struct_span_err!( self.tcx().sess, sp, - E0758, + E0759, "cannot infer an appropriate lifetime" ); err.span_label( diff --git a/src/test/ui/async-await/issues/issue-62097.stderr b/src/test/ui/async-await/issues/issue-62097.stderr index aa443b9d2fc16..0f58b158904db 100644 --- a/src/test/ui/async-await/issues/issue-62097.stderr +++ b/src/test/ui/async-await/issues/issue-62097.stderr @@ -1,4 +1,4 @@ -error[E0758]: cannot infer an appropriate lifetime +error[E0759]: cannot infer an appropriate lifetime --> $DIR/issue-62097.rs:12:31 | LL | pub async fn run_dummy_fn(&self) { @@ -11,4 +11,4 @@ LL | foo(|| self.bar()).await; error: aborting due to previous error -For more information about this error, try `rustc --explain E0758`. +For more information about this error, try `rustc --explain E0759`. diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr index baed43783a13c..e1fa4f02b6fcf 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -1,4 +1,4 @@ -error[E0758]: cannot infer an appropriate lifetime +error[E0759]: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:3:35 | LL | fn elided(x: &i32) -> impl Copy { x } @@ -16,7 +16,7 @@ help: to declare that the `impl Trait` captures data from argument `x`, you can LL | fn elided(x: &i32) -> impl Copy + '_ { x } | ^^^^ -error[E0758]: cannot infer an appropriate lifetime +error[E0759]: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:6:44 | LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x } @@ -34,7 +34,7 @@ help: to declare that the `impl Trait` captures data from argument `x`, you can LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x } | ^^^^ -error[E0758]: cannot infer an appropriate lifetime +error[E0759]: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:9:46 | LL | fn elided2(x: &i32) -> impl Copy + 'static { x } @@ -56,7 +56,7 @@ help: alternatively, add an explicit `'static` bound to this reference LL | fn elided2(x: &'static i32) -> impl Copy + 'static { x } | ^^^^^^^^^^^^ -error[E0758]: cannot infer an appropriate lifetime +error[E0759]: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:12:55 | LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } @@ -86,7 +86,7 @@ LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x } | | | help: add explicit lifetime `'a` to the type of `x`: `&'a i32` -error[E0758]: cannot infer an appropriate lifetime +error[E0759]: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:33:69 | LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } @@ -123,7 +123,7 @@ LL | fn ty_param_wont_outlive_static(x: T) -> impl Debug + 'static { | | | help: consider adding an explicit lifetime bound...: `T: 'static +` -error[E0758]: cannot infer an appropriate lifetime +error[E0759]: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:18:50 | LL | fn elided3(x: &i32) -> Box { Box::new(x) } @@ -136,7 +136,7 @@ help: to declare that the trait object captures data from argument `x`, you can LL | fn elided3(x: &i32) -> Box { Box::new(x) } | ^^^^ -error[E0758]: cannot infer an appropriate lifetime +error[E0759]: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:21:59 | LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) } @@ -149,7 +149,7 @@ help: to declare that the trait object captures data from argument `x`, you can LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) } | ^^^^ -error[E0758]: cannot infer an appropriate lifetime +error[E0759]: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:24:60 | LL | fn elided4(x: &i32) -> Box { Box::new(x) } @@ -166,7 +166,7 @@ help: alternatively, add an explicit `'static` bound to this reference LL | fn elided4(x: &'static i32) -> Box { Box::new(x) } | ^^^^^^^^^^^^ -error[E0758]: cannot infer an appropriate lifetime +error[E0759]: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:27:69 | LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } @@ -183,5 +183,5 @@ LL | fn explicit4<'a>(x: &'static i32) -> Box { Box::new(x) error: aborting due to 12 previous errors -Some errors have detailed explanations: E0310, E0621, E0623, E0758. +Some errors have detailed explanations: E0310, E0621, E0623, E0759. For more information about an error, try `rustc --explain E0310`. diff --git a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr index 90aada01d9917..df0db6e4fc6df 100644 --- a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr +++ b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr @@ -1,4 +1,4 @@ -error[E0758]: cannot infer an appropriate lifetime +error[E0759]: cannot infer an appropriate lifetime --> $DIR/static-return-lifetime-infered.rs:7:16 | LL | fn iter_values_anon(&self) -> impl Iterator { @@ -18,7 +18,7 @@ help: to declare that the `impl Trait` captures data from argument `self`, you c LL | fn iter_values_anon(&self) -> impl Iterator + '_ { | ^^^^ -error[E0758]: cannot infer an appropriate lifetime +error[E0759]: cannot infer an appropriate lifetime --> $DIR/static-return-lifetime-infered.rs:11:16 | LL | fn iter_values<'a>(&'a self) -> impl Iterator { @@ -40,4 +40,4 @@ LL | fn iter_values<'a>(&'a self) -> impl Iterator + 'a { error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0758`. +For more information about this error, try `rustc --explain E0759`. diff --git a/src/test/ui/issues/issue-16922.stderr b/src/test/ui/issues/issue-16922.stderr index ec80f6569f5ac..919594fc9af4b 100644 --- a/src/test/ui/issues/issue-16922.stderr +++ b/src/test/ui/issues/issue-16922.stderr @@ -1,4 +1,4 @@ -error[E0758]: cannot infer an appropriate lifetime +error[E0759]: cannot infer an appropriate lifetime --> $DIR/issue-16922.rs:4:14 | LL | fn foo(value: &T) -> Box { @@ -13,4 +13,4 @@ LL | fn foo(value: &T) -> Box { error: aborting due to previous error -For more information about this error, try `rustc --explain E0758`. +For more information about this error, try `rustc --explain E0759`. diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr index d461001adead9..1b1e0d9610724 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr @@ -1,4 +1,4 @@ -error[E0758]: cannot infer an appropriate lifetime +error[E0759]: cannot infer an appropriate lifetime --> $DIR/object-lifetime-default-from-box-error.rs:18:5 | LL | fn load(ss: &mut SomeStruct) -> Box { @@ -23,5 +23,5 @@ LL | ss.r = b; error: aborting due to 2 previous errors -Some errors have detailed explanations: E0621, E0758. +Some errors have detailed explanations: E0621, E0759. For more information about an error, try `rustc --explain E0621`. diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr index c684373c67e9d..7f5a3a47976c7 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr @@ -1,4 +1,4 @@ -error[E0758]: cannot infer an appropriate lifetime +error[E0759]: cannot infer an appropriate lifetime --> $DIR/region-object-lifetime-in-coercion.rs:8:46 | LL | fn a(v: &[u8]) -> Box { @@ -15,7 +15,7 @@ help: alternatively, add an explicit `'static` bound to this reference LL | fn a(v: &'static [u8]) -> Box { | ^^^^^^^^^^^^^ -error[E0758]: cannot infer an appropriate lifetime +error[E0759]: cannot infer an appropriate lifetime --> $DIR/region-object-lifetime-in-coercion.rs:13:14 | LL | fn b(v: &[u8]) -> Box { @@ -32,7 +32,7 @@ help: alternatively, add an explicit `'static` bound to this reference LL | fn b(v: &'static [u8]) -> Box { | ^^^^^^^^^^^^^ -error[E0758]: cannot infer an appropriate lifetime +error[E0759]: cannot infer an appropriate lifetime --> $DIR/region-object-lifetime-in-coercion.rs:19:14 | LL | fn c(v: &[u8]) -> Box { @@ -79,5 +79,5 @@ LL | Box::new(v) error: aborting due to 4 previous errors -Some errors have detailed explanations: E0495, E0758. +Some errors have detailed explanations: E0495, E0759. For more information about an error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-close-object-into-object-2.stderr b/src/test/ui/regions/regions-close-object-into-object-2.stderr index c4ba395179831..114e4052aae09 100644 --- a/src/test/ui/regions/regions-close-object-into-object-2.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-2.stderr @@ -1,4 +1,4 @@ -error[E0758]: cannot infer an appropriate lifetime +error[E0759]: cannot infer an appropriate lifetime --> $DIR/regions-close-object-into-object-2.rs:10:11 | LL | fn g<'a, T: 'static>(v: Box + 'a>) -> Box { @@ -17,4 +17,4 @@ LL | fn g<'a, T: 'static>(v: std::boxed::Box<(dyn A + 'static)>) -> Box $DIR/regions-close-object-into-object-4.rs:10:11 | LL | fn i<'a, T, U>(v: Box+'a>) -> Box { @@ -17,4 +17,4 @@ LL | fn i<'a, T, U>(v: std::boxed::Box<(dyn A + 'static)>) -> Box $DIR/regions-proc-bound-capture.rs:9:14 | LL | fn static_proc(x: &isize) -> Box (isize) + 'static> { @@ -18,4 +18,4 @@ LL | fn static_proc(x: &'static isize) -> Box (isize) + 'static> error: aborting due to previous error -For more information about this error, try `rustc --explain E0758`. +For more information about this error, try `rustc --explain E0759`. diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr index 9b04069136be2..88bd990b1e81b 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr @@ -1,4 +1,4 @@ -error[E0758]: cannot infer an appropriate lifetime +error[E0759]: cannot infer an appropriate lifetime --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:16 | LL | async fn f(self: Pin<&Self>) -> impl Clone { self } @@ -9,4 +9,4 @@ LL | async fn f(self: Pin<&Self>) -> impl Clone { self } error: aborting due to previous error -For more information about this error, try `rustc --explain E0758`. +For more information about this error, try `rustc --explain E0759`. diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr index c37eb2d136ef1..2e10ab3d3f9b8 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr @@ -1,4 +1,4 @@ -error[E0758]: cannot infer an appropriate lifetime +error[E0759]: cannot infer an appropriate lifetime --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:6:44 | LL | fn f(self: Pin<&Self>) -> impl Clone { self } @@ -18,4 +18,4 @@ LL | fn f(self: Pin<&Self>) -> impl Clone + '_ { self } error: aborting due to previous error -For more information about this error, try `rustc --explain E0758`. +For more information about this error, try `rustc --explain E0759`. diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr index 7e8ab1bfe1633..9ab060328537b 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr @@ -6,7 +6,7 @@ LL | fn baz(g: G, dest: &mut T) -> impl FnOnce() + '_ | | | help: consider introducing lifetime `'a` here: `'a,` -error[E0758]: cannot infer an appropriate lifetime +error[E0759]: cannot infer an appropriate lifetime --> $DIR/missing-lifetimes-in-signature.rs:19:5 | LL | fn foo(g: G, dest: &mut T) -> impl FnOnce() @@ -125,5 +125,5 @@ LL | fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a error: aborting due to 7 previous errors -Some errors have detailed explanations: E0261, E0309, E0621, E0758. +Some errors have detailed explanations: E0261, E0309, E0621, E0759. For more information about an error, try `rustc --explain E0261`. diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr index fc4c801949512..dda5de431d309 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr @@ -1,4 +1,4 @@ -error[E0758]: cannot infer an appropriate lifetime +error[E0759]: cannot infer an appropriate lifetime --> $DIR/dyn-trait-underscore.rs:8:20 | LL | fn a(items: &[T]) -> Box> { @@ -14,4 +14,4 @@ LL | fn a(items: &[T]) -> Box + '_> { error: aborting due to previous error -For more information about this error, try `rustc --explain E0758`. +For more information about this error, try `rustc --explain E0759`. From bfe1434d3bb849d3eb993c42fb57aa0819f9be65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 15 Jun 2020 09:09:20 -0700 Subject: [PATCH 38/42] fix rebase --- .../error_reporting/nice_region_error/static_impl_trait.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs index 853a414290704..82feebc80292a 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -118,7 +118,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { "alternatively, add an explicit `'static` bound to this reference"; let plus_lt = format!(" + {}", lifetime_name); match fn_return.kind { - TyKind::Def(item_id, _) => { + TyKind::OpaqueDef(item_id, _) => { let item = self.tcx().hir().item(item_id.id); let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind { opaque From b5809b027262cb9404519862ccbe06a13cae408b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 15 Jun 2020 12:12:22 -0400 Subject: [PATCH 39/42] Update src/librustc_typeck/check/cast.rs Co-authored-by: lzutao --- src/librustc_typeck/check/cast.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index bea5e0e996658..fa10851abd4f6 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -755,7 +755,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { self.span, |err| { err.build(&format!( - "Cast `enum` implementing `Drop` `{}` to integer `{}`", + "cannot cast enum `{}` into integer `{}` because it implements `Drop`", self.expr_ty, self.cast_ty )) .emit(); From 10c8d2afb8b90e03e2d1563df021146150338c45 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 15 Jun 2020 19:12:14 +0200 Subject: [PATCH 40/42] add FIXME to EnumTagInfo --- src/librustc_codegen_llvm/debuginfo/metadata.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs index 01f630a31a18b..b7e7489cba0ab 100644 --- a/src/librustc_codegen_llvm/debuginfo/metadata.rs +++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs @@ -1637,6 +1637,9 @@ impl VariantMemberDescriptionFactory<'ll, 'tcx> { } } +// FIXME: terminology here should be aligned with `abi::TagEncoding`. +// `OptimizedTag` is `TagEncoding::Niche`, `RegularTag` is `TagEncoding::Direct`. +// `NoTag` should be removed; users should use `Option` instead. #[derive(Copy, Clone)] enum EnumTagInfo<'ll> { RegularTag { tag_field: Field, tag_type_metadata: &'ll DIType }, From f3dfe80ee1d13ec923082487e73c6d5d5833eef0 Mon Sep 17 00:00:00 2001 From: oddg Date: Mon, 15 Jun 2020 21:28:50 -0700 Subject: [PATCH 41/42] Adjust error message --- src/test/ui/cenum_impl_drop_cast.rs | 2 +- src/test/ui/cenum_impl_drop_cast.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/ui/cenum_impl_drop_cast.rs b/src/test/ui/cenum_impl_drop_cast.rs index 623460673bfa2..96e3d967e2c61 100644 --- a/src/test/ui/cenum_impl_drop_cast.rs +++ b/src/test/ui/cenum_impl_drop_cast.rs @@ -13,6 +13,6 @@ impl Drop for E { fn main() { let e = E::A; let i = e as u32; - //~^ ERROR Cast `enum` implementing `Drop` `E` to integer `u32` + //~^ ERROR cannot cast enum `E` into integer `u32` because it implements `Drop` //~| WARN this was previously accepted } diff --git a/src/test/ui/cenum_impl_drop_cast.stderr b/src/test/ui/cenum_impl_drop_cast.stderr index 5c8f86ffd72ad..8d847a0c80b16 100644 --- a/src/test/ui/cenum_impl_drop_cast.stderr +++ b/src/test/ui/cenum_impl_drop_cast.stderr @@ -1,4 +1,4 @@ -error: Cast `enum` implementing `Drop` `E` to integer `u32` +error: cannot cast enum `E` into integer `u32` because it implements `Drop` --> $DIR/cenum_impl_drop_cast.rs:15:13 | LL | let i = e as u32; From 0265e4e61bcd51b11f0b13b712245feb9c59ab50 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Jun 2020 09:25:29 +0200 Subject: [PATCH 42/42] add tracking issue --- src/libcore/ptr/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs index 199f08c3d5058..30c0f9a375714 100644 --- a/src/libcore/ptr/mod.rs +++ b/src/libcore/ptr/mod.rs @@ -1426,7 +1426,7 @@ fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J, K, L } /// let raw_f2 = ptr::raw_const!(packed.f2); /// assert_eq!(unsafe { raw_f2.read_unaligned() }, 2); /// ``` -#[unstable(feature = "raw_ref_macros", issue = "none")] +#[unstable(feature = "raw_ref_macros", issue = "73394")] #[rustc_macro_transparency = "semitransparent"] #[allow_internal_unstable(raw_ref_op)] pub macro raw_const($e:expr) { @@ -1460,7 +1460,7 @@ pub macro raw_const($e:expr) { /// unsafe { raw_f2.write_unaligned(42); } /// assert_eq!({packed.f2}, 42); // `{...}` forces copying the field instead of creating a reference. /// ``` -#[unstable(feature = "raw_ref_macros", issue = "none")] +#[unstable(feature = "raw_ref_macros", issue = "73394")] #[rustc_macro_transparency = "semitransparent"] #[allow_internal_unstable(raw_ref_op)] pub macro raw_mut($e:expr) {