diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs index 350f7be5a9d8d..6501ba031e445 100644 --- a/src/librustc_codegen_llvm/type_of.rs +++ b/src/librustc_codegen_llvm/type_of.rs @@ -79,7 +79,7 @@ fn uncached_llvm_type<'a, 'tcx>( }; match layout.fields { - layout::FieldPlacement::Union(_) => { + layout::FieldsShape::Union(_) => { let fill = cx.type_padding_filler(layout.size, layout.align.abi); let packed = false; match name { @@ -91,10 +91,10 @@ fn uncached_llvm_type<'a, 'tcx>( } } } - layout::FieldPlacement::Array { count, .. } => { + layout::FieldsShape::Array { count, .. } => { cx.type_array(layout.field(cx, 0).llvm_type(cx), count) } - layout::FieldPlacement::Arbitrary { .. } => match name { + layout::FieldsShape::Arbitrary { .. } => match name { None => { let (llfields, packed) = struct_llfields(cx, layout); cx.type_struct(&llfields, packed) @@ -371,13 +371,13 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { _ => {} } match self.fields { - layout::FieldPlacement::Union(_) => { + layout::FieldsShape::Union(_) => { bug!("TyAndLayout::llvm_field_index({:?}): not applicable", self) } - layout::FieldPlacement::Array { .. } => index as u64, + layout::FieldsShape::Array { .. } => index as u64, - layout::FieldPlacement::Arbitrary { .. } => { + layout::FieldsShape::Arbitrary { .. } => { 1 + (self.fields.memory_index(index) as u64) * 2 } } diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs index 1237e70aa36f1..eca66a5704db9 100644 --- a/src/librustc_codegen_ssa/mir/place.rs +++ b/src/librustc_codegen_ssa/mir/place.rs @@ -66,7 +66,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { } pub fn len>(&self, cx: &Cx) -> V { - if let layout::FieldPlacement::Array { count, .. } = self.layout.fields { + if let layout::FieldsShape::Array { count, .. } = self.layout.fields { if self.layout.is_unsized() { assert_eq!(count, 0); self.llextra.unwrap() diff --git a/src/librustc_error_codes/error_codes/E0468.md b/src/librustc_error_codes/error_codes/E0468.md index 73e3ebb949ac0..cf8664718fa63 100644 --- a/src/librustc_error_codes/error_codes/E0468.md +++ b/src/librustc_error_codes/error_codes/E0468.md @@ -1,4 +1,4 @@ -A non-root module attempts to import macros from another crate. +A non-root module tried to import macros from another crate. Example of erroneous code: @@ -17,7 +17,7 @@ Either move the macro import to crate root or do without the foreign macros. This will work: ``` -#[macro_use(debug_assert)] +#[macro_use(debug_assert)] // ok! extern crate core; mod foo { diff --git a/src/librustc_middle/traits/specialization_graph.rs b/src/librustc_middle/traits/specialization_graph.rs index 1847326a742eb..a2793f9805004 100644 --- a/src/librustc_middle/traits/specialization_graph.rs +++ b/src/librustc_middle/traits/specialization_graph.rs @@ -154,14 +154,44 @@ impl Iterator for Ancestors<'_> { } } -pub struct NodeItem { - pub node: Node, - pub item: T, +/// Information about the most specialized definition of an associated item. +pub struct LeafDef { + /// The associated item described by this `LeafDef`. + pub item: ty::AssocItem, + + /// The node in the specialization graph containing the definition of `item`. + pub defining_node: Node, + + /// The "top-most" (ie. least specialized) specialization graph node that finalized the + /// definition of `item`. + /// + /// Example: + /// + /// ``` + /// trait Tr { + /// fn assoc(&self); + /// } + /// + /// impl Tr for T { + /// default fn assoc(&self) {} + /// } + /// + /// impl Tr for u8 {} + /// ``` + /// + /// If we start the leaf definition search at `impl Tr for u8`, that impl will be the + /// `finalizing_node`, while `defining_node` will be the generic impl. + /// + /// If the leaf definition search is started at the generic impl, `finalizing_node` will be + /// `None`, since the most specialized impl we found still allows overriding the method + /// (doesn't finalize it). + pub finalizing_node: Option, } -impl NodeItem { - pub fn map U>(self, f: F) -> NodeItem { - NodeItem { node: self.node, item: f(self.item) } +impl LeafDef { + /// Returns whether this definition is known to not be further specializable. + pub fn is_final(&self) -> bool { + self.finalizing_node.is_some() } } @@ -173,18 +203,36 @@ impl<'tcx> Ancestors<'tcx> { tcx: TyCtxt<'tcx>, trait_item_name: Ident, trait_item_kind: ty::AssocKind, - ) -> Option> { + ) -> Option { let trait_def_id = self.trait_def_id; + let mut finalizing_node = None; + self.find_map(|node| { - node.item(tcx, trait_item_name, trait_item_kind, trait_def_id) - .map(|item| NodeItem { node, item }) + if let Some(item) = node.item(tcx, trait_item_name, trait_item_kind, trait_def_id) { + if finalizing_node.is_none() { + let is_specializable = item.defaultness.is_default() + || tcx.impl_defaultness(node.def_id()).is_default(); + + if !is_specializable { + finalizing_node = Some(node); + } + } + + Some(LeafDef { item, defining_node: node, finalizing_node }) + } else { + // Item not mentioned. This "finalizes" any defaulted item provided by an ancestor. + finalizing_node = Some(node); + None + } }) } } /// Walk up the specialization ancestors of a given impl, starting with that -/// impl itself. Returns `None` if an error was reported while building the -/// specialization graph. +/// impl itself. +/// +/// Returns `Err` if an error was reported while building the specialization +/// graph. pub fn ancestors( tcx: TyCtxt<'tcx>, trait_def_id: DefId, diff --git a/src/librustc_middle/ty/layout.rs b/src/librustc_middle/ty/layout.rs index 17c93922b0023..727d302d53f08 100644 --- a/src/librustc_middle/ty/layout.rs +++ b/src/librustc_middle/ty/layout.rs @@ -230,7 +230,7 @@ enum StructKind { // Invert a bijective mapping, i.e. `invert(map)[y] = x` if `map[x] = y`. // This is used to go between `memory_index` (source field order to memory order) // and `inverse_memory_index` (memory order to source field order). -// See also `FieldPlacement::Arbitrary::memory_index` for more details. +// See also `FieldsShape::Arbitrary::memory_index` for more details. // FIXME(eddyb) build a better abstraction for permutations, if possible. fn invert_mapping(map: &[u32]) -> Vec { let mut inverse = vec![0; map.len()]; @@ -257,7 +257,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { Layout { variants: Variants::Single { index: VariantIdx::new(0) }, - fields: FieldPlacement::Arbitrary { + fields: FieldsShape::Arbitrary { offsets: vec![Size::ZERO, b_offset], memory_index: vec![0, 1], }, @@ -443,7 +443,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { }; let pair = self.scalar_pair(a.clone(), b.clone()); let pair_offsets = match pair.fields { - FieldPlacement::Arbitrary { ref offsets, ref memory_index } => { + FieldsShape::Arbitrary { ref offsets, ref memory_index } => { assert_eq!(memory_index, &[0, 1]); offsets } @@ -471,7 +471,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { Ok(Layout { variants: Variants::Single { index: VariantIdx::new(0) }, - fields: FieldPlacement::Arbitrary { offsets, memory_index }, + fields: FieldsShape::Arbitrary { offsets, memory_index }, abi, largest_niche, align, @@ -520,7 +520,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // The never type. ty::Never => tcx.intern_layout(Layout { variants: Variants::Single { index: VariantIdx::new(0) }, - fields: FieldPlacement::Union(0), + fields: FieldsShape::Union(0), abi: Abi::Uninhabited, largest_niche: None, align: dl.i8_align, @@ -581,7 +581,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { tcx.intern_layout(Layout { variants: Variants::Single { index: VariantIdx::new(0) }, - fields: FieldPlacement::Array { stride: element.size, count }, + fields: FieldsShape::Array { stride: element.size, count }, abi, largest_niche, align: element.align, @@ -592,7 +592,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { let element = self.layout_of(element)?; tcx.intern_layout(Layout { variants: Variants::Single { index: VariantIdx::new(0) }, - fields: FieldPlacement::Array { stride: element.size, count: 0 }, + fields: FieldsShape::Array { stride: element.size, count: 0 }, abi: Abi::Aggregate { sized: false }, largest_niche: None, align: element.align, @@ -601,7 +601,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { } ty::Str => tcx.intern_layout(Layout { variants: Variants::Single { index: VariantIdx::new(0) }, - fields: FieldPlacement::Array { stride: Size::from_bytes(1), count: 0 }, + fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 }, abi: Abi::Aggregate { sized: false }, largest_niche: None, align: dl.i8_align, @@ -670,7 +670,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { tcx.intern_layout(Layout { variants: Variants::Single { index: VariantIdx::new(0) }, - fields: FieldPlacement::Array { stride: element.size, count }, + fields: FieldsShape::Array { stride: element.size, count }, abi: Abi::Vector { element: scalar, count }, largest_niche: element.largest_niche.clone(), size, @@ -746,7 +746,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { return Ok(tcx.intern_layout(Layout { variants: Variants::Single { index }, - fields: FieldPlacement::Union(variants[index].len()), + fields: FieldsShape::Union(variants[index].len()), abi, largest_niche: None, align, @@ -980,7 +980,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { discr_index: 0, variants: st, }, - fields: FieldPlacement::Arbitrary { + fields: FieldsShape::Arbitrary { offsets: vec![offset], memory_index: vec![0], }, @@ -1121,7 +1121,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { let new_ity_size = ity.size(); for variant in &mut layout_variants { match variant.fields { - FieldPlacement::Arbitrary { ref mut offsets, .. } => { + FieldsShape::Arbitrary { ref mut offsets, .. } => { for i in offsets { if *i <= old_ity_size { assert_eq!(*i, old_ity_size); @@ -1151,7 +1151,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { let mut common_prim = None; for (field_layouts, layout_variant) in variants.iter().zip(&layout_variants) { let offsets = match layout_variant.fields { - FieldPlacement::Arbitrary { ref offsets, .. } => offsets, + FieldsShape::Arbitrary { ref offsets, .. } => offsets, _ => bug!(), }; let mut fields = @@ -1187,7 +1187,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { if let Some((prim, offset)) = common_prim { let pair = self.scalar_pair(tag.clone(), scalar_unit(prim)); let pair_offsets = match pair.fields { - FieldPlacement::Arbitrary { ref offsets, ref memory_index } => { + FieldsShape::Arbitrary { ref offsets, ref memory_index } => { assert_eq!(memory_index, &[0, 1]); offsets } @@ -1218,7 +1218,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { discr_index: 0, variants: layout_variants, }, - fields: FieldPlacement::Arbitrary { + fields: FieldsShape::Arbitrary { offsets: vec![Size::ZERO], memory_index: vec![0], }, @@ -1435,7 +1435,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // GeneratorLayout. debug!("prefix = {:#?}", prefix); let (outer_fields, promoted_offsets, promoted_memory_index) = match prefix.fields { - FieldPlacement::Arbitrary { mut offsets, memory_index } => { + FieldsShape::Arbitrary { mut offsets, memory_index } => { let mut inverse_memory_index = invert_mapping(&memory_index); // "a" (`0..b_start`) and "b" (`b_start..`) correspond to @@ -1458,7 +1458,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { let memory_index_b = invert_mapping(&inverse_memory_index_b); let outer_fields = - FieldPlacement::Arbitrary { offsets: offsets_a, memory_index: memory_index_a }; + FieldsShape::Arbitrary { offsets: offsets_a, memory_index: memory_index_a }; (outer_fields, offsets_b, memory_index_b) } _ => bug!(), @@ -1492,7 +1492,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { variant.variants = Variants::Single { index }; let (offsets, memory_index) = match variant.fields { - FieldPlacement::Arbitrary { offsets, memory_index } => (offsets, memory_index), + FieldsShape::Arbitrary { offsets, memory_index } => (offsets, memory_index), _ => bug!(), }; @@ -1535,7 +1535,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { combined_inverse_memory_index.retain(|&i| i != INVALID_FIELD_IDX); let combined_memory_index = invert_mapping(&combined_inverse_memory_index); - variant.fields = FieldPlacement::Arbitrary { + variant.fields = FieldsShape::Arbitrary { offsets: combined_offsets, memory_index: combined_memory_index, }; @@ -1990,7 +1990,7 @@ where if index == variant_index && // Don't confuse variants of uninhabited enums with the enum itself. // For more details see https://github.com/rust-lang/rust/issues/69763. - this.fields != FieldPlacement::Union(0) => + this.fields != FieldsShape::Union(0) => { this.layout } @@ -2008,7 +2008,7 @@ where let tcx = cx.tcx(); tcx.intern_layout(Layout { variants: Variants::Single { index: variant_index }, - fields: FieldPlacement::Union(fields), + fields: FieldsShape::Union(fields), abi: Abi::Uninhabited, largest_niche: None, align: tcx.data_layout.i8_align, @@ -2054,7 +2054,7 @@ where // Reuse the fat `*T` type as its own thin pointer data field. // This provides information about, e.g., DST struct pointees // (which may have no non-DST form), and will work as long - // as the `Abi` or `FieldPlacement` is checked by users. + // as the `Abi` or `FieldsShape` is checked by users. if i == 0 { let nil = tcx.mk_unit(); let ptr_ty = if this.ty.is_unsafe_ptr() { @@ -2219,7 +2219,7 @@ where if let Some(variant) = data_variant { // We're not interested in any unions. - if let FieldPlacement::Union(_) = variant.fields { + if let FieldsShape::Union(_) = variant.fields { data_variant = None; } } diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 5c4915d54b037..a8e65a7e7f5a9 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -219,7 +219,7 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { // Go through the layout. There are lots of types that support a length, // e.g., SIMD types. match self.layout.fields { - layout::FieldPlacement::Array { count, .. } => Ok(count), + layout::FieldsShape::Array { count, .. } => Ok(count), _ => bug!("len not supported on sized type {:?}", self.layout.ty), } } @@ -437,7 +437,7 @@ where ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { // Not using the layout method because we want to compute on u64 match base.layout.fields { - layout::FieldPlacement::Array { stride, .. } => { + layout::FieldsShape::Array { stride, .. } => { let len = base.len(self)?; if index >= len { // This can only be reached in ConstProp and non-rustc-MIR. @@ -463,7 +463,7 @@ where { let len = base.len(self)?; // also asserts that we have a type where this makes sense let stride = match base.layout.fields { - layout::FieldPlacement::Array { stride, .. } => stride, + layout::FieldsShape::Array { stride, .. } => stride, _ => bug!("mplace_array_fields: expected an array layout"), }; let layout = base.layout.field(self, 0)?; @@ -493,7 +493,7 @@ where // Not using layout method because that works with usize, and does not work with slices // (that have count 0 in their layout). let from_offset = match base.layout.fields { - layout::FieldPlacement::Array { stride, .. } => stride * from, // `Size` multiplication is checked + layout::FieldsShape::Array { stride, .. } => stride * from, // `Size` multiplication is checked _ => bug!("Unexpected layout of index access: {:#?}", base.layout), }; diff --git a/src/librustc_mir/interpret/visitor.rs b/src/librustc_mir/interpret/visitor.rs index 11170164cf35b..66a46c12c062f 100644 --- a/src/librustc_mir/interpret/visitor.rs +++ b/src/librustc_mir/interpret/visitor.rs @@ -207,10 +207,10 @@ macro_rules! make_value_visitor { // Visit the fields of this value. match v.layout().fields { - layout::FieldPlacement::Union(fields) => { + layout::FieldsShape::Union(fields) => { self.visit_union(v, fields)?; }, - layout::FieldPlacement::Arbitrary { ref offsets, .. } => { + layout::FieldsShape::Arbitrary { ref offsets, .. } => { // FIXME: We collect in a vec because otherwise there are lifetime // errors: Projecting to a field needs access to `ecx`. let fields: Vec> = @@ -220,7 +220,7 @@ macro_rules! make_value_visitor { .collect(); self.visit_aggregate(v, fields.into_iter())?; }, - layout::FieldPlacement::Array { .. } => { + layout::FieldsShape::Array { .. } => { // Let's get an mplace first. let mplace = v.to_op(self.ecx())?.assert_mem_place(self.ecx()); // Now we can go over all the fields. diff --git a/src/librustc_target/abi/call/mips64.rs b/src/librustc_target/abi/call/mips64.rs index 285cb5ff6433f..81de630678890 100644 --- a/src/librustc_target/abi/call/mips64.rs +++ b/src/librustc_target/abi/call/mips64.rs @@ -49,7 +49,7 @@ where // use of float registers to structures (not unions) containing exactly one or two // float fields. - if let abi::FieldPlacement::Arbitrary { .. } = ret.layout.fields { + if let abi::FieldsShape::Arbitrary { .. } = ret.layout.fields { if ret.layout.fields.count() == 1 { if let Some(reg) = float_reg(cx, ret, 0) { ret.cast_to(reg); @@ -88,15 +88,15 @@ where let mut prefix_index = 0; match arg.layout.fields { - abi::FieldPlacement::Array { .. } => { + abi::FieldsShape::Array { .. } => { // Arrays are passed indirectly arg.make_indirect(); return; } - abi::FieldPlacement::Union(_) => { + abi::FieldsShape::Union(_) => { // Unions and are always treated as a series of 64-bit integer chunks } - abi::FieldPlacement::Arbitrary { .. } => { + abi::FieldsShape::Arbitrary { .. } => { // Structures are split up into a series of 64-bit integer chunks, but any aligned // doubles not part of another aggregate are passed as floats. let mut last_offset = Size::ZERO; diff --git a/src/librustc_target/abi/call/mod.rs b/src/librustc_target/abi/call/mod.rs index 72768c31e3077..b6bfa70005b5e 100644 --- a/src/librustc_target/abi/call/mod.rs +++ b/src/librustc_target/abi/call/mod.rs @@ -1,4 +1,4 @@ -use crate::abi::{self, Abi, Align, FieldPlacement, Size}; +use crate::abi::{self, Abi, Align, FieldsShape, Size}; use crate::abi::{HasDataLayout, LayoutOf, TyAndLayout, TyAndLayoutMethods}; use crate::spec::{self, HasTargetSpec}; @@ -315,7 +315,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { start: Size| -> Result<(HomogeneousAggregate, Size), Heterogeneous> { let is_union = match layout.fields { - FieldPlacement::Array { count, .. } => { + FieldsShape::Array { count, .. } => { assert_eq!(start, Size::ZERO); let result = if count > 0 { @@ -325,8 +325,8 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { }; return Ok((result, layout.size)); } - FieldPlacement::Union(_) => true, - FieldPlacement::Arbitrary { .. } => false, + FieldsShape::Union(_) => true, + FieldsShape::Arbitrary { .. } => false, }; let mut result = HomogeneousAggregate::NoData; diff --git a/src/librustc_target/abi/call/riscv.rs b/src/librustc_target/abi/call/riscv.rs index a916a53f0cbf7..0eb8816e43461 100644 --- a/src/librustc_target/abi/call/riscv.rs +++ b/src/librustc_target/abi/call/riscv.rs @@ -6,7 +6,7 @@ use crate::abi::call::{ArgAbi, ArgAttribute, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform}; use crate::abi::{ - self, Abi, FieldPlacement, HasDataLayout, LayoutOf, Size, TyAndLayout, TyAndLayoutMethods, + self, Abi, FieldsShape, HasDataLayout, LayoutOf, Size, TyAndLayout, TyAndLayoutMethods, }; use crate::spec::HasTargetSpec; @@ -87,12 +87,12 @@ where }, Abi::Vector { .. } | Abi::Uninhabited => return Err(CannotUseFpConv), Abi::ScalarPair(..) | Abi::Aggregate { .. } => match arg_layout.fields { - FieldPlacement::Union(_) => { + FieldsShape::Union(_) => { if !arg_layout.is_zst() { return Err(CannotUseFpConv); } } - FieldPlacement::Array { count, .. } => { + FieldsShape::Array { count, .. } => { for _ in 0..count { let elem_layout = arg_layout.field(cx, 0); should_use_fp_conv_helper( @@ -105,7 +105,7 @@ where )?; } } - FieldPlacement::Arbitrary { .. } => { + FieldsShape::Arbitrary { .. } => { match arg_layout.variants { abi::Variants::Multiple { .. } => return Err(CannotUseFpConv), abi::Variants::Single { .. } => (), diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index 3cc7292bbdfd5..f382ef984be24 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -618,7 +618,7 @@ impl Scalar { /// Describes how the fields of a type are located in memory. #[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)] -pub enum FieldPlacement { +pub enum FieldsShape { /// All fields start at no offset. The `usize` is the field count. /// /// In the case of primitives the number of fields is `0`. @@ -657,38 +657,38 @@ pub enum FieldPlacement { }, } -impl FieldPlacement { +impl FieldsShape { pub fn count(&self) -> usize { match *self { - FieldPlacement::Union(count) => count, - FieldPlacement::Array { count, .. } => { + FieldsShape::Union(count) => count, + FieldsShape::Array { count, .. } => { let usize_count = count as usize; assert_eq!(usize_count as u64, count); usize_count } - FieldPlacement::Arbitrary { ref offsets, .. } => offsets.len(), + FieldsShape::Arbitrary { ref offsets, .. } => offsets.len(), } } pub fn offset(&self, i: usize) -> Size { match *self { - FieldPlacement::Union(count) => { + FieldsShape::Union(count) => { assert!(i < count, "tried to access field {} of union with {} fields", i, count); Size::ZERO } - FieldPlacement::Array { stride, count } => { + FieldsShape::Array { stride, count } => { let i = u64::try_from(i).unwrap(); assert!(i < count); stride * i } - FieldPlacement::Arbitrary { ref offsets, .. } => offsets[i], + FieldsShape::Arbitrary { ref offsets, .. } => offsets[i], } } pub fn memory_index(&self, i: usize) -> usize { match *self { - FieldPlacement::Union(_) | FieldPlacement::Array { .. } => i, - FieldPlacement::Arbitrary { ref memory_index, .. } => { + FieldsShape::Union(_) | FieldsShape::Array { .. } => i, + FieldsShape::Arbitrary { ref memory_index, .. } => { let r = memory_index[i]; assert_eq!(r as usize as u32, r); r as usize @@ -704,7 +704,7 @@ impl FieldPlacement { let use_small = self.count() <= inverse_small.len(); // We have to write this logic twice in order to keep the array small. - if let FieldPlacement::Arbitrary { ref memory_index, .. } = *self { + if let FieldsShape::Arbitrary { ref memory_index, .. } = *self { if use_small { for i in 0..self.count() { inverse_small[memory_index[i] as usize] = i as u8; @@ -718,8 +718,8 @@ impl FieldPlacement { } (0..self.count()).map(move |i| match *self { - FieldPlacement::Union(_) | FieldPlacement::Array { .. } => i, - FieldPlacement::Arbitrary { .. } => { + FieldsShape::Union(_) | FieldsShape::Array { .. } => i, + FieldsShape::Arbitrary { .. } => { if use_small { inverse_small[i] as usize } else { @@ -888,7 +888,7 @@ impl Niche { pub struct Layout { /// Says where the fields are located within the layout. /// Primitives and uninhabited enums appear as unions without fields. - pub fields: FieldPlacement, + pub fields: FieldsShape, /// Encodes information about multi-variant layouts. /// Even with `Multiple` variants, a layout still has its own fields! Those are then @@ -923,7 +923,7 @@ impl Layout { let align = scalar.value.align(cx); Layout { variants: Variants::Single { index: VariantIdx::new(0) }, - fields: FieldPlacement::Union(0), + fields: FieldsShape::Union(0), abi: Abi::Scalar(scalar), largest_niche, size, diff --git a/src/librustc_trait_selection/traits/mod.rs b/src/librustc_trait_selection/traits/mod.rs index 3ef44a198417a..5f98850633075 100644 --- a/src/librustc_trait_selection/traits/mod.rs +++ b/src/librustc_trait_selection/traits/mod.rs @@ -54,7 +54,6 @@ pub use self::project::{ }; pub use self::select::{EvaluationCache, SelectionCache, SelectionContext}; pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError}; -pub use self::specialize::find_associated_item; pub use self::specialize::specialization_graph::FutureCompatOverlapError; pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind; pub use self::specialize::{specialization_graph, translate_substs, OverlapError}; @@ -64,8 +63,7 @@ pub use self::structural_match::NonStructuralMatchTy; pub use self::util::{elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs}; pub use self::util::{expand_trait_aliases, TraitAliasExpander}; pub use self::util::{ - get_vtable_index_of_object_method, impl_is_default, impl_item_is_final, - predicate_for_trait_def, upcast_choices, + get_vtable_index_of_object_method, impl_item_is_final, predicate_for_trait_def, upcast_choices, }; pub use self::util::{ supertrait_def_ids, supertraits, transitive_bounds, SupertraitDefIds, Supertraits, diff --git a/src/librustc_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs index 2eb63b8f59030..aae0d46756331 100644 --- a/src/librustc_trait_selection/traits/project.rs +++ b/src/librustc_trait_selection/traits/project.rs @@ -1015,49 +1015,21 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( assoc_ty_def(selcx, impl_data.impl_def_id, obligation.predicate.item_def_id) .map_err(|ErrorReported| ())?; - let is_default = if node_item.node.is_from_trait() { - // If true, the impl inherited a `type Foo = Bar` - // given in the trait, which is implicitly default. - // Otherwise, the impl did not specify `type` and - // neither did the trait: - // - // ```rust - // trait Foo { type T; } - // impl Foo for Bar { } - // ``` - // - // This is an error, but it will be - // reported in `check_impl_items_against_trait`. - // We accept it here but will flag it as - // an error when we confirm the candidate - // (which will ultimately lead to `normalize_to_error` - // being invoked). - false + if node_item.is_final() { + // Non-specializable items are always projectable. + true } else { - // If we're looking at a trait *impl*, the item is - // specializable if the impl or the item are marked - // `default`. - node_item.item.defaultness.is_default() - || super::util::impl_is_default(selcx.tcx(), node_item.node.def_id()) - }; - - match is_default { - // Non-specializable items are always projectable - false => true, - // Only reveal a specializable default if we're past type-checking // and the obligation is monomorphic, otherwise passes such as // transmute checking and polymorphic MIR optimizations could // get a result which isn't correct for all monomorphizations. - true if obligation.param_env.reveal == Reveal::All => { + if obligation.param_env.reveal == Reveal::All { // NOTE(eddyb) inference variables can resolve to parameters, so // assume `poly_trait_ref` isn't monomorphic, if it contains any. let poly_trait_ref = selcx.infcx().resolve_vars_if_possible(&poly_trait_ref); !poly_trait_ref.needs_infer() && !poly_trait_ref.needs_subst() - } - - true => { + } else { debug!( "assemble_candidates_from_impls: not eligible due to default: \ assoc_ty={} predicate={}", @@ -1422,7 +1394,8 @@ fn confirm_impl_candidate<'cx, 'tcx>( return Progress { ty: tcx.types.err, obligations: nested }; } 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.node); + let substs = + translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.defining_node); let ty = if let ty::AssocKind::OpaqueTy = assoc_ty.item.kind { let item_substs = InternalSubsts::identity_for_item(tcx, assoc_ty.item.def_id); tcx.mk_opaque(assoc_ty.item.def_id, item_substs) @@ -1447,7 +1420,7 @@ fn assoc_ty_def( selcx: &SelectionContext<'_, '_>, impl_def_id: DefId, assoc_ty_def_id: DefId, -) -> Result, ErrorReported> { +) -> Result { let tcx = selcx.tcx(); let assoc_ty_name = tcx.associated_item(assoc_ty_def_id).ident; let trait_def_id = tcx.impl_trait_ref(impl_def_id).unwrap().def_id; @@ -1464,9 +1437,10 @@ fn assoc_ty_def( if matches!(item.kind, ty::AssocKind::Type | ty::AssocKind::OpaqueTy) && tcx.hygienic_eq(item.ident, assoc_ty_name, trait_def_id) { - return Ok(specialization_graph::NodeItem { - node: specialization_graph::Node::Impl(impl_def_id), + return Ok(specialization_graph::LeafDef { item: *item, + defining_node: impl_node, + finalizing_node: if item.defaultness.is_default() { None } else { Some(impl_node) }, }); } } diff --git a/src/librustc_trait_selection/traits/specialize/mod.rs b/src/librustc_trait_selection/traits/specialize/mod.rs index edf02d75ee60f..fabd8c89b72af 100644 --- a/src/librustc_trait_selection/traits/specialize/mod.rs +++ b/src/librustc_trait_selection/traits/specialize/mod.rs @@ -20,7 +20,7 @@ use rustc_errors::struct_span_err; use rustc_hir::def_id::DefId; use rustc_middle::lint::LintDiagnosticBuilder; use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; -use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK; use rustc_session::lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS; use rustc_span::DUMMY_SP; @@ -112,48 +112,6 @@ pub fn translate_substs<'a, 'tcx>( source_substs.rebase_onto(infcx.tcx, source_impl, target_substs) } -/// Given a selected impl described by `impl_data`, returns the -/// definition and substitutions for the method with the name `name` -/// the kind `kind`, and trait method substitutions `substs`, in -/// that impl, a less specialized impl, or the trait default, -/// whichever applies. -pub fn find_associated_item<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - item: &ty::AssocItem, - substs: SubstsRef<'tcx>, - impl_data: &super::VtableImplData<'tcx, ()>, -) -> (DefId, SubstsRef<'tcx>) { - debug!("find_associated_item({:?}, {:?}, {:?}, {:?})", param_env, item, substs, impl_data); - assert!(!substs.needs_infer()); - - let trait_def_id = tcx.trait_id_of_impl(impl_data.impl_def_id).unwrap(); - let trait_def = tcx.trait_def(trait_def_id); - - if let Ok(ancestors) = trait_def.ancestors(tcx, impl_data.impl_def_id) { - match ancestors.leaf_def(tcx, item.ident, item.kind) { - Some(node_item) => { - let substs = tcx.infer_ctxt().enter(|infcx| { - let param_env = param_env.with_reveal_all(); - let substs = substs.rebase_onto(tcx, trait_def_id, impl_data.substs); - let substs = translate_substs( - &infcx, - param_env, - impl_data.impl_def_id, - substs, - node_item.node, - ); - infcx.tcx.erase_regions(&substs) - }); - (node_item.item.def_id, substs) - } - None => bug!("{:?} not found in {:?}", item, impl_data.impl_def_id), - } - } else { - (item.def_id, substs) - } -} - /// Is `impl1` a specialization of `impl2`? /// /// Specialization is determined by the sets of types to which the impls apply; diff --git a/src/librustc_trait_selection/traits/util.rs b/src/librustc_trait_selection/traits/util.rs index 6eeac2f676c09..6348673dab8b5 100644 --- a/src/librustc_trait_selection/traits/util.rs +++ b/src/librustc_trait_selection/traits/util.rs @@ -4,7 +4,6 @@ use smallvec::smallvec; use smallvec::SmallVec; use rustc_data_structures::fx::FxHashSet; -use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::ty::outlives::Component; use rustc_middle::ty::subst::{GenericArg, Subst, SubstsRef}; @@ -651,22 +650,8 @@ pub fn generator_trait_ref_and_outputs( ty::Binder::bind((trait_ref, sig.skip_binder().yield_ty, sig.skip_binder().return_ty)) } -pub fn impl_is_default(tcx: TyCtxt<'_>, node_item_def_id: DefId) -> bool { - match tcx.hir().as_local_hir_id(node_item_def_id) { - Some(hir_id) => { - let item = tcx.hir().expect_item(hir_id); - if let hir::ItemKind::Impl { defaultness, .. } = item.kind { - defaultness.is_default() - } else { - false - } - } - None => tcx.impl_defaultness(node_item_def_id).is_default(), - } -} - pub fn impl_item_is_final(tcx: TyCtxt<'_>, assoc_item: &ty::AssocItem) -> bool { - assoc_item.defaultness.is_final() && !impl_is_default(tcx, assoc_item.container.id()) + assoc_item.defaultness.is_final() && tcx.impl_defaultness(assoc_item.container.id()).is_final() } pub enum TupleArgumentsFlag { diff --git a/src/librustc_ty/instance.rs b/src/librustc_ty/instance.rs index 447c49e40fb5a..47c4b1c41cdbd 100644 --- a/src/librustc_ty/instance.rs +++ b/src/librustc_ty/instance.rs @@ -1,9 +1,11 @@ use rustc_hir::def_id::DefId; +use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, Instance, TyCtxt, TypeFoldable}; use rustc_span::sym; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits; +use traits::{translate_substs, Reveal}; use log::debug; @@ -82,21 +84,50 @@ fn resolve_associated_item<'tcx>( // the actual function: match vtbl { traits::VtableImpl(impl_data) => { - let (def_id, substs) = - traits::find_associated_item(tcx, param_env, trait_item, rcvr_substs, &impl_data); - - let resolved_item = tcx.associated_item(def_id); + debug!( + "resolving VtableImpl: {:?}, {:?}, {:?}, {:?}", + param_env, trait_item, rcvr_substs, impl_data + ); + assert!(!rcvr_substs.needs_infer()); + assert!(!trait_ref.needs_infer()); + + let trait_def_id = tcx.trait_id_of_impl(impl_data.impl_def_id).unwrap(); + let trait_def = tcx.trait_def(trait_def_id); + let leaf_def = trait_def + .ancestors(tcx, impl_data.impl_def_id) + .ok()? + .leaf_def(tcx, trait_item.ident, trait_item.kind) + .unwrap_or_else(|| { + bug!("{:?} not found in {:?}", trait_item, impl_data.impl_def_id); + }); + let def_id = leaf_def.item.def_id; + + let substs = tcx.infer_ctxt().enter(|infcx| { + let param_env = param_env.with_reveal_all(); + let substs = rcvr_substs.rebase_onto(tcx, trait_def_id, impl_data.substs); + let substs = translate_substs( + &infcx, + param_env, + impl_data.impl_def_id, + substs, + leaf_def.defining_node, + ); + infcx.tcx.erase_regions(&substs) + }); // Since this is a trait item, we need to see if the item is either a trait default item // or a specialization because we can't resolve those unless we can `Reveal::All`. // NOTE: This should be kept in sync with the similar code in // `rustc_middle::traits::project::assemble_candidates_from_impls()`. - let eligible = if !resolved_item.defaultness.is_default() { + let eligible = if leaf_def.is_final() { + // Non-specializable items are always projectable. true - } else if param_env.reveal == traits::Reveal::All { - !trait_ref.needs_subst() } else { - false + // Only reveal a specializable default if we're past type-checking + // and the obligation is monomorphic, otherwise passes such as + // transmute checking and polymorphic MIR optimizations could + // get a result which isn't correct for all monomorphizations. + if param_env.reveal == Reveal::All { !trait_ref.needs_subst() } else { false } }; if !eligible { diff --git a/src/librustc_ty/ty.rs b/src/librustc_ty/ty.rs index 9d28447e212a6..aefe61f60b87a 100644 --- a/src/librustc_ty/ty.rs +++ b/src/librustc_ty/ty.rs @@ -165,6 +165,16 @@ fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem { ) } +fn impl_defaultness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Defaultness { + let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); + let item = tcx.hir().expect_item(hir_id); + if let hir::ItemKind::Impl { defaultness, .. } = item.kind { + defaultness + } else { + bug!("`impl_defaultness` called on {:?}", item); + } +} + /// Calculates the `Sized` constraint. /// /// In fact, there are only a few options for the types in the constraint: @@ -371,6 +381,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) { crate_hash, instance_def_size_estimate, issue33140_self_ty, + impl_defaultness, ..*providers }; } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 6249e1d49779e..3823efe9d927e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1942,7 +1942,7 @@ fn check_specialization_validity<'tcx>( // grandparent. In that case, if parent is a `default impl`, inherited items use the // "defaultness" from the grandparent, else they are final. None => { - if traits::impl_is_default(tcx, parent_impl.def_id()) { + if tcx.impl_defaultness(parent_impl.def_id()).is_default() { None } else { Some(Err(parent_impl.def_id())) @@ -2114,10 +2114,10 @@ fn check_impl_items_against_trait<'tcx>( for trait_item in tcx.associated_items(impl_trait_ref.def_id).in_definition_order() { let is_implemented = ancestors .leaf_def(tcx, trait_item.ident, trait_item.kind) - .map(|node_item| !node_item.node.is_from_trait()) + .map(|node_item| !node_item.defining_node.is_from_trait()) .unwrap_or(false); - if !is_implemented && !traits::impl_is_default(tcx, impl_id) { + if !is_implemented && tcx.impl_defaultness(impl_id).is_final() { if !trait_item.defaultness.has_value() { missing_items.push(*trait_item); } diff --git a/src/test/ui/specialization/issue-70442.rs b/src/test/ui/specialization/issue-70442.rs new file mode 100644 index 0000000000000..4371dd2e16747 --- /dev/null +++ b/src/test/ui/specialization/issue-70442.rs @@ -0,0 +1,23 @@ +#![feature(specialization)] + +// check-pass + +trait Trait { + type Assoc; +} + +impl Trait for T { + default type Assoc = bool; +} + +// This impl inherits the `Assoc` definition from above and "locks it in", or finalizes it, making +// child impls unable to further specialize it. However, since the specialization graph didn't +// correctly track this, we would refuse to project `Assoc` from this impl, even though that should +// happen for items that are final. +impl Trait for () {} + +fn foo>() {} + +fn main() { + foo::<()>(); // `<() as Trait>::Assoc` is normalized to `bool` correctly +} diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 0ee016f33dd88..8a291a3611efd 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -180,29 +180,25 @@ pub fn make_diff(expected: &str, actual: &str, context_size: usize) -> Vec { - writeln!(dest, "-\t{}", e).unwrap(); + println!("-\t{}", e); line_number += 1; } DiffLine::Context(c) => { - writeln!(dest, "{}\t{}", line_number, c).unwrap(); + println!("{}\t{}", line_number, c); line_number += 1; } DiffLine::Resulting(r) => { - writeln!(dest, "+\t{}", r).unwrap(); + println!("+\t{}", r); } } } - writeln!(dest).unwrap(); + println!(); } }