diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index 0b501da7cd975..100824f4b9448 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -707,6 +707,18 @@ impl GrowableBitSet { self.bit_set.insert(elem) } + /// Returns `true` if the set has changed. + #[inline] + pub fn remove(&mut self, elem: T) -> bool { + self.ensure(elem.index() + 1); + self.bit_set.remove(elem) + } + + #[inline] + pub fn is_empty(&self) -> bool { + self.bit_set.is_empty() + } + #[inline] pub fn contains(&self, elem: T) -> bool { let (word_index, mask) = word_index_and_mask(elem); diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 3015188fd447a..3e3e945f654b7 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -829,16 +829,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let tail_field_ty = tcx.type_of(tail_field.did); let mut unsizing_params = GrowableBitSet::new_empty(); - let mut found = false; for arg in tail_field_ty.walk() { if let Some(i) = maybe_unsizing_param_idx(arg) { unsizing_params.insert(i); - found = true; } } - if !found { - return Err(Unimplemented); - } // Ensure none of the other fields mention the parameters used // in unsizing. @@ -848,13 +843,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { for field in prefix_fields { for arg in tcx.type_of(field.did).walk() { if let Some(i) = maybe_unsizing_param_idx(arg) { - if unsizing_params.contains(i) { - return Err(Unimplemented); - } + unsizing_params.remove(i); } } } + if unsizing_params.is_empty() { + return Err(Unimplemented); + } + // Extract `TailField` and `TailField` from `Struct` and `Struct`. let source_tail = tail_field_ty.subst(tcx, substs_a); let target_tail = tail_field_ty.subst(tcx, substs_b); diff --git a/src/test/ui/unsized/unchanged-param.rs b/src/test/ui/unsized/unchanged-param.rs new file mode 100644 index 0000000000000..93c7af68ac388 --- /dev/null +++ b/src/test/ui/unsized/unchanged-param.rs @@ -0,0 +1,11 @@ +// run-pass +// Test that we allow unsizing even if there is an unchanged param in the +// field getting unsized. +struct A(T, B); +struct B(T, U); + +fn main() { + let x: A<[u32; 1], [u32; 1]> = A([0; 1], B([0; 1], [0; 1])); + let y: &A<[u32; 1], [u32]> = &x; + assert_eq!(y.1.1.len(), 1); +}