From 6e88e96ccf1ca7621e6177d729a69625838db1c8 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Sat, 13 Jul 2019 17:16:57 +0200 Subject: [PATCH 01/27] Support repr(simd) on ADTs containing a single array field This PR allows using `#[repr(simd)]` on ADTs containing a single array field: ```rust #[repr(simd)] struct S0([f32; 4]); #[repr(simd)] struct S1([f32; N]); #[repr(simd)] struct S2([T; N]); ``` This should allow experimenting with portable packed SIMD abstractions on nightly that make use of const generics. --- compiler/rustc_codegen_llvm/src/intrinsic.rs | 122 +++++++++++------- compiler/rustc_middle/src/ty/layout.rs | 109 +++++++++++++--- compiler/rustc_middle/src/ty/sty.rs | 16 --- compiler/rustc_typeck/src/check/check.rs | 4 +- .../simd-intrinsic-generic-extract-insert.rs | 47 +++++++ .../simd-intrinsic-transmute-array.rs | 44 +++++++ src/test/ui/error-codes/E0077.stderr | 2 +- .../ui/simd-type-generic-monomorphisation.rs | 4 +- .../simd-type-generic-monomorphisation.stderr | 2 +- src/test/ui/simd-type.rs | 10 ++ src/test/ui/simd-type.stderr | 20 ++- src/test/ui/simd/simd-array-type.rs | 44 +++++++ src/test/ui/simd/simd-generics.rs | 32 ++++- ...intrinsic-generic-arithmetic-saturating.rs | 68 +++++----- .../simd/simd-intrinsic-generic-arithmetic.rs | 63 +++++---- 15 files changed, 427 insertions(+), 160 deletions(-) create mode 100644 src/test/codegen/simd-intrinsic/simd-intrinsic-generic-extract-insert.rs create mode 100644 src/test/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs create mode 100644 src/test/ui/simd/simd-array-type.rs diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index e9900e8bc108a..2ea7d7ac2d822 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -740,6 +740,23 @@ fn generic_simd_intrinsic( llret_ty: &'ll Type, span: Span, ) -> Result<&'ll Value, ()> { + // Given a SIMD vector type `x` return the element type and the number of + // elements in the vector. + fn simd_ty_and_len(bx: &Builder<'a, 'll, 'tcx>, simd_ty: Ty<'tcx>) -> (Ty<'tcx>, u64) { + let ty = if let ty::Adt(_def, _substs) = simd_ty.kind() { + let f0_ty = bx.layout_of(simd_ty).field(bx, 0).ty; + if let ty::Array(element_ty, _) = f0_ty.kind() { element_ty } else { f0_ty } + } else { + bug!("should only be called with a SIMD type") + }; + let count = if let abi::Abi::Vector { count, .. } = bx.layout_of(simd_ty).abi { + count + } else { + bug!("should only be called with a SIMD type") + }; + (ty, count) + } + // macros for error handling: macro_rules! emit_error { ($msg: tt) => { @@ -792,7 +809,7 @@ fn generic_simd_intrinsic( _ => return_error!("`{}` is not an integral type", in_ty), }; require_simd!(arg_tys[1], "argument"); - let v_len = arg_tys[1].simd_size(tcx); + let (_, v_len) = simd_ty_and_len(bx, arg_tys[1]); require!( // Allow masks for vectors with fewer than 8 elements to be // represented with a u8 or i8. @@ -812,8 +829,6 @@ fn generic_simd_intrinsic( // every intrinsic below takes a SIMD vector as its first argument require_simd!(arg_tys[0], "input"); let in_ty = arg_tys[0]; - let in_elem = arg_tys[0].simd_type(tcx); - let in_len = arg_tys[0].simd_size(tcx); let comparison = match name { sym::simd_eq => Some(hir::BinOpKind::Eq), @@ -825,14 +840,15 @@ fn generic_simd_intrinsic( _ => None, }; + let (in_elem, in_len) = simd_ty_and_len(bx, arg_tys[0]); if let Some(cmp_op) = comparison { require_simd!(ret_ty, "return"); - let out_len = ret_ty.simd_size(tcx); + let (out_ty, out_len) = simd_ty_and_len(bx, ret_ty); require!( in_len == out_len, "expected return type with length {} (same as input type `{}`), \ - found `{}` with length {}", + found `{}` with length {}", in_len, in_ty, ret_ty, @@ -842,7 +858,7 @@ fn generic_simd_intrinsic( bx.type_kind(bx.element_type(llret_ty)) == TypeKind::Integer, "expected return type with integer elements, found `{}` with non-integer `{}`", ret_ty, - ret_ty.simd_type(tcx) + out_ty ); return Ok(compare_simd_types( @@ -862,7 +878,7 @@ fn generic_simd_intrinsic( require_simd!(ret_ty, "return"); - let out_len = ret_ty.simd_size(tcx); + let (out_ty, out_len) = simd_ty_and_len(bx, ret_ty); require!( out_len == n, "expected return type of length {}, found `{}` with length {}", @@ -871,13 +887,13 @@ fn generic_simd_intrinsic( out_len ); require!( - in_elem == ret_ty.simd_type(tcx), + in_elem == out_ty, "expected return element type `{}` (element of input `{}`), \ - found `{}` with element type `{}`", + found `{}` with element type `{}`", in_elem, in_ty, ret_ty, - ret_ty.simd_type(tcx) + out_ty ); let total_len = u128::from(in_len) * 2; @@ -946,7 +962,7 @@ fn generic_simd_intrinsic( let m_elem_ty = in_elem; let m_len = in_len; require_simd!(arg_tys[1], "argument"); - let v_len = arg_tys[1].simd_size(tcx); + let (_, v_len) = simd_ty_and_len(bx, arg_tys[1]); require!( m_len == v_len, "mismatched lengths: mask length `{}` != other vector length `{}`", @@ -1171,25 +1187,27 @@ fn generic_simd_intrinsic( require_simd!(ret_ty, "return"); // Of the same length: + let (_, out_len) = simd_ty_and_len(bx, arg_tys[1]); + let (_, out_len2) = simd_ty_and_len(bx, arg_tys[2]); require!( - in_len == arg_tys[1].simd_size(tcx), + in_len == out_len, "expected {} argument with length {} (same as input type `{}`), \ - found `{}` with length {}", + found `{}` with length {}", "second", in_len, in_ty, arg_tys[1], - arg_tys[1].simd_size(tcx) + out_len ); require!( - in_len == arg_tys[2].simd_size(tcx), + in_len == out_len2, "expected {} argument with length {} (same as input type `{}`), \ - found `{}` with length {}", + found `{}` with length {}", "third", in_len, in_ty, arg_tys[2], - arg_tys[2].simd_size(tcx) + out_len2 ); // The return type must match the first argument type @@ -1213,39 +1231,40 @@ fn generic_simd_intrinsic( // The second argument must be a simd vector with an element type that's a pointer // to the element type of the first argument - let (pointer_count, underlying_ty) = match arg_tys[1].simd_type(tcx).kind() { - ty::RawPtr(p) if p.ty == in_elem => { - (ptr_count(arg_tys[1].simd_type(tcx)), non_ptr(arg_tys[1].simd_type(tcx))) - } + let (element_ty0, _) = simd_ty_and_len(bx, arg_tys[0]); + let (element_ty1, _) = simd_ty_and_len(bx, arg_tys[1]); + let (pointer_count, underlying_ty) = match element_ty1.kind() { + ty::RawPtr(p) if p.ty == in_elem => (ptr_count(element_ty1), non_ptr(element_ty1)), _ => { require!( false, "expected element type `{}` of second argument `{}` \ - to be a pointer to the element type `{}` of the first \ - argument `{}`, found `{}` != `*_ {}`", - arg_tys[1].simd_type(tcx), + to be a pointer to the element type `{}` of the first \ + argument `{}`, found `{}` != `*_ {}`", + element_ty1, arg_tys[1], in_elem, in_ty, - arg_tys[1].simd_type(tcx), + element_ty1, in_elem ); unreachable!(); } }; assert!(pointer_count > 0); - assert_eq!(pointer_count - 1, ptr_count(arg_tys[0].simd_type(tcx))); - assert_eq!(underlying_ty, non_ptr(arg_tys[0].simd_type(tcx))); + assert_eq!(pointer_count - 1, ptr_count(element_ty0)); + assert_eq!(underlying_ty, non_ptr(element_ty0)); // The element type of the third argument must be a signed integer type of any width: - match arg_tys[2].simd_type(tcx).kind() { + let (element_ty2, _) = simd_ty_and_len(bx, arg_tys[2]); + match element_ty2.kind() { ty::Int(_) => (), _ => { require!( false, "expected element type `{}` of third argument `{}` \ to be a signed integer type", - arg_tys[2].simd_type(tcx), + element_ty2, arg_tys[2] ); } @@ -1297,25 +1316,27 @@ fn generic_simd_intrinsic( require_simd!(arg_tys[2], "third"); // Of the same length: + let (_, element_len1) = simd_ty_and_len(bx, arg_tys[1]); + let (_, element_len2) = simd_ty_and_len(bx, arg_tys[2]); require!( - in_len == arg_tys[1].simd_size(tcx), + in_len == element_len1, "expected {} argument with length {} (same as input type `{}`), \ - found `{}` with length {}", + found `{}` with length {}", "second", in_len, in_ty, arg_tys[1], - arg_tys[1].simd_size(tcx) + element_len1 ); require!( - in_len == arg_tys[2].simd_size(tcx), + in_len == element_len2, "expected {} argument with length {} (same as input type `{}`), \ - found `{}` with length {}", + found `{}` with length {}", "third", in_len, in_ty, arg_tys[2], - arg_tys[2].simd_size(tcx) + element_len2 ); // This counts how many pointers @@ -1336,39 +1357,42 @@ fn generic_simd_intrinsic( // The second argument must be a simd vector with an element type that's a pointer // to the element type of the first argument - let (pointer_count, underlying_ty) = match arg_tys[1].simd_type(tcx).kind() { + let (element_ty0, _element_len0) = simd_ty_and_len(bx, arg_tys[0]); + let (element_ty1, _element_len1) = simd_ty_and_len(bx, arg_tys[1]); + let (element_ty2, _element_len2) = simd_ty_and_len(bx, arg_tys[2]); + let (pointer_count, underlying_ty) = match element_ty1.kind() { ty::RawPtr(p) if p.ty == in_elem && p.mutbl == hir::Mutability::Mut => { - (ptr_count(arg_tys[1].simd_type(tcx)), non_ptr(arg_tys[1].simd_type(tcx))) + (ptr_count(element_ty1), non_ptr(element_ty1)) } _ => { require!( false, "expected element type `{}` of second argument `{}` \ - to be a pointer to the element type `{}` of the first \ - argument `{}`, found `{}` != `*mut {}`", - arg_tys[1].simd_type(tcx), + to be a pointer to the element type `{}` of the first \ + argument `{}`, found `{}` != `*mut {}`", + element_ty1, arg_tys[1], in_elem, in_ty, - arg_tys[1].simd_type(tcx), + element_ty1, in_elem ); unreachable!(); } }; assert!(pointer_count > 0); - assert_eq!(pointer_count - 1, ptr_count(arg_tys[0].simd_type(tcx))); - assert_eq!(underlying_ty, non_ptr(arg_tys[0].simd_type(tcx))); + assert_eq!(pointer_count - 1, ptr_count(element_ty0)); + assert_eq!(underlying_ty, non_ptr(element_ty0)); // The element type of the third argument must be a signed integer type of any width: - match arg_tys[2].simd_type(tcx).kind() { + match element_ty2.kind() { ty::Int(_) => (), _ => { require!( false, "expected element type `{}` of third argument `{}` \ - to be a signed integer type", - arg_tys[2].simd_type(tcx), + be a signed integer type", + element_ty2, arg_tys[2] ); } @@ -1565,7 +1589,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, if name == sym::simd_cast { require_simd!(ret_ty, "return"); - let out_len = ret_ty.simd_size(tcx); + let (out_elem, out_len) = simd_ty_and_len(bx, ret_ty); require!( in_len == out_len, "expected return type with length {} (same as input type `{}`), \ @@ -1576,8 +1600,6 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, out_len ); // casting cares about nominal type, not just structural type - let out_elem = ret_ty.simd_type(tcx); - if in_elem == out_elem { return Ok(args[0].immediate()); } @@ -1693,7 +1715,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, return_error!( "expected element type `{}` of vector type `{}` \ to be a signed or unsigned integer type", - arg_tys[0].simd_type(tcx), + simd_ty_and_len(bx, arg_tys[0]).0, arg_tys[0] ); } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 91c3dcbfa81cf..b0e2469019ab6 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -631,30 +631,106 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { } // SIMD vector types. - ty::Adt(def, ..) if def.repr.simd() => { - let element = self.layout_of(ty.simd_type(tcx))?; - let count = ty.simd_size(tcx); - assert!(count > 0); - let scalar = match element.abi { - Abi::Scalar(ref scalar) => scalar.clone(), - _ => { + ty::Adt(def, substs) if def.repr.simd() => { + // Supported SIMD vectors are homogeneous ADTs with at least one field: + // + // * #[repr(simd)] struct S(T, T, T, T); + // * #[repr(simd)] struct S { x: T, y: T, z: T, w: T } + // * #[repr(simd)] struct S([T; 4]) + // + // where T is a primitive scalar (integer/float/pointer). + + // SIMD vectors with zero fields are not supported. + // (should be caught by typeck) + if def.non_enum_variant().fields.is_empty() { + tcx.sess.fatal(&format!("monomorphising SIMD type `{}` of zero length", ty)); + } + + // Type of the first ADT field: + let f0_ty = def.non_enum_variant().fields[0].ty(tcx, substs); + + // Heterogeneous SIMD vectors are not supported: + // (should be caught by typeck) + for fi in &def.non_enum_variant().fields { + if fi.ty(tcx, substs) != f0_ty { + tcx.sess.fatal(&format!("monomorphising heterogeneous SIMD type `{}`", ty)); + } + } + + // The element type and number of elements of the SIMD vector + // are obtained from: + // + // * the element type and length of the single array field, if + // the first field is of array type, or + // + // * the homogenous field type and the number of fields. + let (e_ty, e_len, is_array) = if let ty::Array(e_ty, _) = f0_ty.kind() { + // First ADT field is an array: + + // SIMD vectors with multiple array fields are not supported: + // (should be caught by typeck) + if def.non_enum_variant().fields.len() != 1 { tcx.sess.fatal(&format!( - "monomorphising SIMD type `{}` with \ - a non-machine element type `{}`", - ty, element.ty + "monomorphising SIMD type `{}` with more than one array field", + ty )); } + + // Extract the number of elements from the layout of the array field: + let len = if let Ok(TyAndLayout { + layout: Layout { fields: FieldsShape::Array { count, .. }, .. }, + .. + }) = self.layout_of(f0_ty) + { + count + } else { + return Err(LayoutError::Unknown(ty)); + }; + + (*e_ty, *len, true) + } else { + // First ADT field is not an array: + (f0_ty, def.non_enum_variant().fields.len() as _, false) }; - let size = - element.size.checked_mul(count, dl).ok_or(LayoutError::SizeOverflow(ty))?; + + // SIMD vectors of zero length are not supported. + // + // Can't be caught in typeck if the array length is generic. + if e_len == 0 { + tcx.sess.fatal(&format!("monomorphising SIMD type `{}` of zero length", ty)); + } + + // Compute the ABI of the element type: + let e_ly = self.layout_of(e_ty)?; + let e_abi = if let Abi::Scalar(ref scalar) = e_ly.abi { + scalar.clone() + } else { + // This error isn't caught in typeck, e.g., if + // the element type of the vector is generic. + tcx.sess.fatal(&format!( + "monomorphising SIMD type `{}` with a non-primitive-scalar \ + (integer/float/pointer) element type `{}`", + ty, e_ty + )) + }; + + // Compute the size and alignment of the vector: + let size = e_ly.size.checked_mul(e_len, dl).ok_or(LayoutError::SizeOverflow(ty))?; let align = dl.vector_align(size); let size = size.align_to(align.abi); + // Compute the placement of the vector fields: + let fields = if is_array { + FieldsShape::Arbitrary { offsets: vec![Size::ZERO], memory_index: vec![0] } + } else { + FieldsShape::Array { stride: e_ly.size, count: e_len } + }; + tcx.intern_layout(Layout { variants: Variants::Single { index: VariantIdx::new(0) }, - fields: FieldsShape::Array { stride: element.size, count }, - abi: Abi::Vector { element: scalar, count }, - largest_niche: element.largest_niche.clone(), + fields, + abi: Abi::Vector { element: e_abi, count: e_len }, + largest_niche: e_ly.largest_niche.clone(), size, align, }) @@ -2121,9 +2197,6 @@ where ty::Tuple(tys) => tys[i].expect_ty(), - // SIMD vector types. - ty::Adt(def, ..) if def.repr.simd() => this.ty.simd_type(tcx), - // ADTs. ty::Adt(def, substs) => { match this.variants { diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 384d08f83485c..8202d0f0ef169 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1959,22 +1959,6 @@ impl<'tcx> TyS<'tcx> { } } - pub fn simd_type(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - match self.kind() { - Adt(def, substs) => def.non_enum_variant().fields[0].ty(tcx, substs), - _ => bug!("`simd_type` called on invalid type"), - } - } - - pub fn simd_size(&self, _tcx: TyCtxt<'tcx>) -> u64 { - // Parameter currently unused, but probably needed in the future to - // allow `#[repr(simd)] struct Simd([T; N]);`. - match self.kind() { - Adt(def, _) => def.non_enum_variant().fields.len() as u64, - _ => bug!("`simd_size` called on invalid type"), - } - } - pub fn simd_size_and_type(&self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) { match self.kind() { Adt(def, substs) => { diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 70d94ef869d05..4605238b0a1f1 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -1065,12 +1065,14 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { match e.kind() { ty::Param(_) => { /* struct(T, T, T, T) is ok */ } _ if e.is_machine() => { /* struct(u8, u8, u8, u8) is ok */ } + ty::Array(ty, _c) if ty.is_machine() => { /* struct([f32; 4]) */ } _ => { struct_span_err!( tcx.sess, sp, E0077, - "SIMD vector element type should be machine type" + "SIMD vector element type should be a \ + primitive scalar (integer/float/pointer) type" ) .emit(); return; diff --git a/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-extract-insert.rs b/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-extract-insert.rs new file mode 100644 index 0000000000000..3dba044d376e8 --- /dev/null +++ b/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-extract-insert.rs @@ -0,0 +1,47 @@ +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +#![feature(repr_simd, platform_intrinsics, const_generics)] +#![allow(non_camel_case_types, incomplete_features)] + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct M(pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct S([f32; N]); + +extern "platform-intrinsic" { + fn simd_extract(x: T, idx: u32) -> U; + fn simd_insert(x: T, idx: u32, b: U) -> T; +} + +// CHECK-LABEL: @extract_m +#[no_mangle] +pub unsafe fn extract_m(v: M, i: u32) -> f32 { + // CHECK: extractelement <4 x float> %0, i32 %i + simd_extract(v, i) +} + +// CHECK-LABEL: @extract_s +#[no_mangle] +pub unsafe fn extract_s(v: S<4>, i: u32) -> f32 { + // CHECK: extractelement <4 x float> %0, i32 %i + simd_extract(v, i) +} + +// CHECK-LABEL: @insert_m +#[no_mangle] +pub unsafe fn insert_m(v: M, i: u32, j: f32) -> M { + // CHECK: insertelement <4 x float> %1, float %j, i32 %i + simd_insert(v, i, j) +} + +// CHECK-LABEL: @insert_s +#[no_mangle] +pub unsafe fn insert_s(v: S<4>, i: u32, j: f32) -> S<4> { + // CHECK: insertelement <4 x float> %1, float %j, i32 %i + simd_insert(v, i, j) +} diff --git a/src/test/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs b/src/test/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs new file mode 100644 index 0000000000000..23098e7f64945 --- /dev/null +++ b/src/test/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs @@ -0,0 +1,44 @@ +// ignore-tidy-linelength +// compile-flags: -C no-prepopulate-passes +// min-llvm-version 8.0 + +#![crate_type = "lib"] + +#![allow(non_camel_case_types, incomplete_features)] +#![feature(repr_simd, platform_intrinsics, const_generics)] + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct S([f32; N]); + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct T([f32; 4]); + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct U(f32, f32, f32, f32); + +// CHECK-LABEL: @build_array_s +#[no_mangle] +pub fn build_array_s(x: [f32; 4]) -> S<4> { + // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* {{.*}} %{{[0-9]+}}, i8* {{.*}} %3, i64 16, i1 false) + // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* {{.*}} %{{[0-9]+}}, i8* {{.*}} %6, i64 16, i1 false) + S::<4>(x) +} + +// CHECK-LABEL: @build_array_t +#[no_mangle] +pub fn build_array_t(x: [f32; 4]) -> T { + // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* {{.*}} %{{[0-9]+}}, i8* {{.*}} %3, i64 16, i1 false) + // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* {{.*}} %{{[0-9]+}}, i8* {{.*}} %6, i64 16, i1 false) + T(x) +} + +// CHECK-LABEL: @build_array_u +#[no_mangle] +pub fn build_array_u(x: [f32; 4]) -> U { + // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* {{.*}} %{{[0-9]+}}, i8* {{.*}} %3, i64 16, i1 false) + // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* {{.*}} %{{[0-9]+}}, i8* {{.*}} %6, i64 16, i1 false) + unsafe { std::mem::transmute(x) } +} diff --git a/src/test/ui/error-codes/E0077.stderr b/src/test/ui/error-codes/E0077.stderr index 4f85d175ce65d..1938a9a272a16 100644 --- a/src/test/ui/error-codes/E0077.stderr +++ b/src/test/ui/error-codes/E0077.stderr @@ -1,4 +1,4 @@ -error[E0077]: SIMD vector element type should be machine type +error[E0077]: SIMD vector element type should be a primitive scalar (integer/float/pointer) type --> $DIR/E0077.rs:4:1 | LL | struct Bad(String); diff --git a/src/test/ui/simd-type-generic-monomorphisation.rs b/src/test/ui/simd-type-generic-monomorphisation.rs index fc5e23f49869a..0275f0ce4c159 100644 --- a/src/test/ui/simd-type-generic-monomorphisation.rs +++ b/src/test/ui/simd-type-generic-monomorphisation.rs @@ -2,7 +2,9 @@ #![feature(repr_simd, platform_intrinsics)] -// error-pattern:monomorphising SIMD type `Simd2` with a non-machine element type `X` +// ignore-tidy-linelength + +// error-pattern:monomorphising SIMD type `Simd2` with a non-primitive-scalar (integer/float/pointer) element type `X` struct X(Vec); #[repr(simd)] diff --git a/src/test/ui/simd-type-generic-monomorphisation.stderr b/src/test/ui/simd-type-generic-monomorphisation.stderr index 2a74506e80ea5..7f23893ac8536 100644 --- a/src/test/ui/simd-type-generic-monomorphisation.stderr +++ b/src/test/ui/simd-type-generic-monomorphisation.stderr @@ -1,4 +1,4 @@ -error: monomorphising SIMD type `Simd2` with a non-machine element type `X` +error: monomorphising SIMD type `Simd2` with a non-primitive-scalar (integer/float/pointer) element type `X` error: aborting due to previous error diff --git a/src/test/ui/simd-type.rs b/src/test/ui/simd-type.rs index 9e4b7e7656055..a320df85138e5 100644 --- a/src/test/ui/simd-type.rs +++ b/src/test/ui/simd-type.rs @@ -1,10 +1,20 @@ #![feature(repr_simd)] #![allow(non_camel_case_types)] +// ignore-tidy-linelength + #[repr(simd)] struct empty; //~ ERROR SIMD vector cannot be empty #[repr(simd)] struct i64f64(i64, f64); //~ ERROR SIMD vector should be homogeneous +struct Foo; + +#[repr(simd)] +struct FooV(Foo, Foo); //~ ERROR SIMD vector element type should be a primitive scalar (integer/float/pointer) type + +#[repr(simd)] +struct FooV2([Foo; 2]); //~ ERROR SIMD vector element type should be a primitive scalar (integer/float/pointer) type + fn main() {} diff --git a/src/test/ui/simd-type.stderr b/src/test/ui/simd-type.stderr index 0c4242f46b786..23004c785918c 100644 --- a/src/test/ui/simd-type.stderr +++ b/src/test/ui/simd-type.stderr @@ -1,16 +1,28 @@ error[E0075]: SIMD vector cannot be empty - --> $DIR/simd-type.rs:5:1 + --> $DIR/simd-type.rs:7:1 | LL | struct empty; | ^^^^^^^^^^^^^ error[E0076]: SIMD vector should be homogeneous - --> $DIR/simd-type.rs:8:1 + --> $DIR/simd-type.rs:10:1 | LL | struct i64f64(i64, f64); | ^^^^^^^^^^^^^^^^^^^^^^^^ SIMD elements must have the same type -error: aborting due to 2 previous errors +error[E0077]: SIMD vector element type should be a primitive scalar (integer/float/pointer) type + --> $DIR/simd-type.rs:15:1 + | +LL | struct FooV(Foo, Foo); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error[E0077]: SIMD vector element type should be a primitive scalar (integer/float/pointer) type + --> $DIR/simd-type.rs:18:1 + | +LL | struct FooV2([Foo; 2]); + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0075, E0076. +Some errors have detailed explanations: E0075, E0076, E0077. For more information about an error, try `rustc --explain E0075`. diff --git a/src/test/ui/simd/simd-array-type.rs b/src/test/ui/simd/simd-array-type.rs new file mode 100644 index 0000000000000..c84988cffb423 --- /dev/null +++ b/src/test/ui/simd/simd-array-type.rs @@ -0,0 +1,44 @@ +// run-pass +#![allow(dead_code, incomplete_features)] + +// pretty-expanded FIXME #23616 + +#![feature(repr_simd)] +#![feature(platform_intrinsics)] +#![feature(const_generics)] + +#[repr(simd)] +#[derive(Copy, Clone)] +struct S([i32; 4]); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct T([i32; N]); + +extern "platform-intrinsic" { + fn simd_insert(x: T, idx: u32, y: E) -> T; + fn simd_extract(x: T, idx: u32) -> E; +} + +pub fn main() { + let mut s = S([0; 4]); + + unsafe { + for i in 0_i32..4 { + s = simd_insert(s, i as u32, i); + } + for i in 0_i32..4 { + assert_eq!(i, simd_extract(s, i as u32)); + } + } + + let mut t = T::<4>([0; 4]); + unsafe { + for i in 0_i32..4 { + t = simd_insert(t, i as u32, i); + } + for i in 0_i32..4 { + assert_eq!(i, simd_extract(t, i as u32)); + } + } +} diff --git a/src/test/ui/simd/simd-generics.rs b/src/test/ui/simd/simd-generics.rs index ab6caee9d7bce..9877e37dfb2ec 100644 --- a/src/test/ui/simd/simd-generics.rs +++ b/src/test/ui/simd/simd-generics.rs @@ -1,9 +1,6 @@ // run-pass -#![allow(non_camel_case_types)] - - - -#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types, incomplete_features)] +#![feature(repr_simd, platform_intrinsics, const_generics)] use std::ops; @@ -11,6 +8,11 @@ use std::ops; #[derive(Copy, Clone)] struct f32x4(f32, f32, f32, f32); +#[repr(simd)] +#[derive(Copy, Clone)] +struct S([f32; N]); + + extern "platform-intrinsic" { fn simd_add(x: T, y: T) -> T; } @@ -27,7 +29,16 @@ impl ops::Add for f32x4 { } } -pub fn main() { +impl ops::Add for S<4> { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + unsafe {simd_add(self, rhs)} + } +} + + +pub fn main() { unsafe { let lr = f32x4(1.0f32, 2.0f32, 3.0f32, 4.0f32); // lame-o @@ -36,4 +47,11 @@ pub fn main() { assert_eq!(y, 4.0f32); assert_eq!(z, 6.0f32); assert_eq!(w, 8.0f32); -} + + let lr2 = S::<4>([1.0f32, 2.0f32, 3.0f32, 4.0f32]); + let [x, y, z, w] = add(lr2, lr2).0; + assert_eq!(x, 2.0f32); + assert_eq!(y, 4.0f32); + assert_eq!(z, 6.0f32); + assert_eq!(w, 8.0f32); +}} diff --git a/src/test/ui/simd/simd-intrinsic-generic-arithmetic-saturating.rs b/src/test/ui/simd/simd-intrinsic-generic-arithmetic-saturating.rs index b7b3ec997810e..30a4fc11368d6 100644 --- a/src/test/ui/simd/simd-intrinsic-generic-arithmetic-saturating.rs +++ b/src/test/ui/simd/simd-intrinsic-generic-arithmetic-saturating.rs @@ -1,16 +1,16 @@ // run-pass // ignore-emscripten -#![allow(non_camel_case_types)] -#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types, incomplete_features)] +#![feature(repr_simd, platform_intrinsics, const_generics)] #[repr(simd)] #[derive(Copy, Clone, PartialEq, Debug)] struct u32x4(pub u32, pub u32, pub u32, pub u32); #[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct i32x4(pub i32, pub i32, pub i32, pub i32); +#[derive(Copy, Clone)] +struct I32([i32; N]); extern "platform-intrinsic" { fn simd_saturating_add(x: T, y: T) -> T; @@ -51,41 +51,41 @@ fn main() { const MIN: i32 = i32::MIN; const MAX: i32 = i32::MAX; - let a = i32x4(1, 2, 3, 4); - let b = i32x4(2, 4, 6, 8); - let c = i32x4(-1, -2, -3, -4); - let d = i32x4(-2, -4, -6, -8); + let a = I32::<4>([1, 2, 3, 4]); + let b = I32::<4>([2, 4, 6, 8]); + let c = I32::<4>([-1, -2, -3, -4]); + let d = I32::<4>([-2, -4, -6, -8]); - let max = i32x4(MAX, MAX, MAX, MAX); - let max1 = i32x4(MAX - 1, MAX - 1, MAX - 1, MAX - 1); - let min = i32x4(MIN, MIN, MIN, MIN); - let min1 = i32x4(MIN + 1, MIN + 1, MIN + 1, MIN + 1); + let max = I32::<4>([MAX, MAX, MAX, MAX]); + let max1 = I32::<4>([MAX - 1, MAX - 1, MAX - 1, MAX - 1]); + let min = I32::<4>([MIN, MIN, MIN, MIN]); + let min1 = I32::<4>([MIN + 1, MIN + 1, MIN + 1, MIN + 1]); - let z = i32x4(0, 0, 0, 0); + let z = I32::<4>([0, 0, 0, 0]); unsafe { - assert_eq!(simd_saturating_add(z, z), z); - assert_eq!(simd_saturating_add(z, a), a); - assert_eq!(simd_saturating_add(b, z), b); - assert_eq!(simd_saturating_add(a, a), b); - assert_eq!(simd_saturating_add(a, max), max); - assert_eq!(simd_saturating_add(max, b), max); - assert_eq!(simd_saturating_add(max1, a), max); - assert_eq!(simd_saturating_add(min1, z), min1); - assert_eq!(simd_saturating_add(min, z), min); - assert_eq!(simd_saturating_add(min1, c), min); - assert_eq!(simd_saturating_add(min, c), min); - assert_eq!(simd_saturating_add(min1, d), min); - assert_eq!(simd_saturating_add(min, d), min); + assert_eq!(simd_saturating_add(z, z).0, z.0); + assert_eq!(simd_saturating_add(z, a).0, a.0); + assert_eq!(simd_saturating_add(b, z).0, b.0); + assert_eq!(simd_saturating_add(a, a).0, b.0); + assert_eq!(simd_saturating_add(a, max).0, max.0); + assert_eq!(simd_saturating_add(max, b).0, max.0); + assert_eq!(simd_saturating_add(max1, a).0, max.0); + assert_eq!(simd_saturating_add(min1, z).0, min1.0); + assert_eq!(simd_saturating_add(min, z).0, min.0); + assert_eq!(simd_saturating_add(min1, c).0, min.0); + assert_eq!(simd_saturating_add(min, c).0, min.0); + assert_eq!(simd_saturating_add(min1, d).0, min.0); + assert_eq!(simd_saturating_add(min, d).0, min.0); - assert_eq!(simd_saturating_sub(b, z), b); - assert_eq!(simd_saturating_sub(b, a), a); - assert_eq!(simd_saturating_sub(a, a), z); - assert_eq!(simd_saturating_sub(a, b), c); - assert_eq!(simd_saturating_sub(z, max), min1); - assert_eq!(simd_saturating_sub(min1, z), min1); - assert_eq!(simd_saturating_sub(min1, a), min); - assert_eq!(simd_saturating_sub(min1, b), min); + assert_eq!(simd_saturating_sub(b, z).0, b.0); + assert_eq!(simd_saturating_sub(b, a).0, a.0); + assert_eq!(simd_saturating_sub(a, a).0, z.0); + assert_eq!(simd_saturating_sub(a, b).0, c.0); + assert_eq!(simd_saturating_sub(z, max).0, min1.0); + assert_eq!(simd_saturating_sub(min1, z).0, min1.0); + assert_eq!(simd_saturating_sub(min1, a).0, min.0); + assert_eq!(simd_saturating_sub(min1, b).0, min.0); } } } diff --git a/src/test/ui/simd/simd-intrinsic-generic-arithmetic.rs b/src/test/ui/simd/simd-intrinsic-generic-arithmetic.rs index b67c0ad1eb2f1..83f11c6abdbf0 100644 --- a/src/test/ui/simd/simd-intrinsic-generic-arithmetic.rs +++ b/src/test/ui/simd/simd-intrinsic-generic-arithmetic.rs @@ -1,9 +1,9 @@ // run-pass -#![allow(non_camel_case_types)] +#![allow(non_camel_case_types, incomplete_features)] // ignore-emscripten FIXME(#45351) hits an LLVM assert -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, platform_intrinsics, const_generics)] #[repr(simd)] #[derive(Copy, Clone)] @@ -11,7 +11,7 @@ struct i32x4(pub i32, pub i32, pub i32, pub i32); #[repr(simd)] #[derive(Copy, Clone)] -struct u32x4(pub u32, pub u32, pub u32, pub u32); +struct U32([u32; N]); #[repr(simd)] #[derive(Copy, Clone)] @@ -25,6 +25,15 @@ macro_rules! all_eq { }} } +macro_rules! all_eq_ { + ($a: expr, $b: expr) => {{ + let a = $a; + let b = $b; + assert!(a.0 == b.0); + }} +} + + extern "platform-intrinsic" { fn simd_add(x: T, y: T) -> T; fn simd_sub(x: T, y: T) -> T; @@ -40,81 +49,81 @@ extern "platform-intrinsic" { fn main() { let x1 = i32x4(1, 2, 3, 4); - let y1 = u32x4(1, 2, 3, 4); + let y1 = U32::<4>([1, 2, 3, 4]); let z1 = f32x4(1.0, 2.0, 3.0, 4.0); let x2 = i32x4(2, 3, 4, 5); - let y2 = u32x4(2, 3, 4, 5); + let y2 = U32::<4>([2, 3, 4, 5]); let z2 = f32x4(2.0, 3.0, 4.0, 5.0); unsafe { all_eq!(simd_add(x1, x2), i32x4(3, 5, 7, 9)); all_eq!(simd_add(x2, x1), i32x4(3, 5, 7, 9)); - all_eq!(simd_add(y1, y2), u32x4(3, 5, 7, 9)); - all_eq!(simd_add(y2, y1), u32x4(3, 5, 7, 9)); + all_eq_!(simd_add(y1, y2), U32::<4>([3, 5, 7, 9])); + all_eq_!(simd_add(y2, y1), U32::<4>([3, 5, 7, 9])); all_eq!(simd_add(z1, z2), f32x4(3.0, 5.0, 7.0, 9.0)); all_eq!(simd_add(z2, z1), f32x4(3.0, 5.0, 7.0, 9.0)); all_eq!(simd_mul(x1, x2), i32x4(2, 6, 12, 20)); all_eq!(simd_mul(x2, x1), i32x4(2, 6, 12, 20)); - all_eq!(simd_mul(y1, y2), u32x4(2, 6, 12, 20)); - all_eq!(simd_mul(y2, y1), u32x4(2, 6, 12, 20)); + all_eq_!(simd_mul(y1, y2), U32::<4>([2, 6, 12, 20])); + all_eq_!(simd_mul(y2, y1), U32::<4>([2, 6, 12, 20])); all_eq!(simd_mul(z1, z2), f32x4(2.0, 6.0, 12.0, 20.0)); all_eq!(simd_mul(z2, z1), f32x4(2.0, 6.0, 12.0, 20.0)); all_eq!(simd_sub(x2, x1), i32x4(1, 1, 1, 1)); all_eq!(simd_sub(x1, x2), i32x4(-1, -1, -1, -1)); - all_eq!(simd_sub(y2, y1), u32x4(1, 1, 1, 1)); - all_eq!(simd_sub(y1, y2), u32x4(!0, !0, !0, !0)); + all_eq_!(simd_sub(y2, y1), U32::<4>([1, 1, 1, 1])); + all_eq_!(simd_sub(y1, y2), U32::<4>([!0, !0, !0, !0])); all_eq!(simd_sub(z2, z1), f32x4(1.0, 1.0, 1.0, 1.0)); all_eq!(simd_sub(z1, z2), f32x4(-1.0, -1.0, -1.0, -1.0)); all_eq!(simd_div(x1, x1), i32x4(1, 1, 1, 1)); all_eq!(simd_div(i32x4(2, 4, 6, 8), i32x4(2, 2, 2, 2)), x1); - all_eq!(simd_div(y1, y1), u32x4(1, 1, 1, 1)); - all_eq!(simd_div(u32x4(2, 4, 6, 8), u32x4(2, 2, 2, 2)), y1); + all_eq_!(simd_div(y1, y1), U32::<4>([1, 1, 1, 1])); + all_eq_!(simd_div(U32::<4>([2, 4, 6, 8]), U32::<4>([2, 2, 2, 2])), y1); all_eq!(simd_div(z1, z1), f32x4(1.0, 1.0, 1.0, 1.0)); all_eq!(simd_div(z1, z2), f32x4(1.0/2.0, 2.0/3.0, 3.0/4.0, 4.0/5.0)); all_eq!(simd_div(z2, z1), f32x4(2.0/1.0, 3.0/2.0, 4.0/3.0, 5.0/4.0)); all_eq!(simd_rem(x1, x1), i32x4(0, 0, 0, 0)); all_eq!(simd_rem(x2, x1), i32x4(0, 1, 1, 1)); - all_eq!(simd_rem(y1, y1), u32x4(0, 0, 0, 0)); - all_eq!(simd_rem(y2, y1), u32x4(0, 1, 1, 1)); + all_eq_!(simd_rem(y1, y1), U32::<4>([0, 0, 0, 0])); + all_eq_!(simd_rem(y2, y1), U32::<4>([0, 1, 1, 1])); all_eq!(simd_rem(z1, z1), f32x4(0.0, 0.0, 0.0, 0.0)); all_eq!(simd_rem(z1, z2), z1); all_eq!(simd_rem(z2, z1), f32x4(0.0, 1.0, 1.0, 1.0)); all_eq!(simd_shl(x1, x2), i32x4(1 << 2, 2 << 3, 3 << 4, 4 << 5)); all_eq!(simd_shl(x2, x1), i32x4(2 << 1, 3 << 2, 4 << 3, 5 << 4)); - all_eq!(simd_shl(y1, y2), u32x4(1 << 2, 2 << 3, 3 << 4, 4 << 5)); - all_eq!(simd_shl(y2, y1), u32x4(2 << 1, 3 << 2, 4 << 3, 5 << 4)); + all_eq_!(simd_shl(y1, y2), U32::<4>([1 << 2, 2 << 3, 3 << 4, 4 << 5])); + all_eq_!(simd_shl(y2, y1), U32::<4>([2 << 1, 3 << 2, 4 << 3, 5 << 4])); // test right-shift by assuming left-shift is correct all_eq!(simd_shr(simd_shl(x1, x2), x2), x1); all_eq!(simd_shr(simd_shl(x2, x1), x1), x2); - all_eq!(simd_shr(simd_shl(y1, y2), y2), y1); - all_eq!(simd_shr(simd_shl(y2, y1), y1), y2); + all_eq_!(simd_shr(simd_shl(y1, y2), y2), y1); + all_eq_!(simd_shr(simd_shl(y2, y1), y1), y2); // ensure we get logical vs. arithmetic shifts correct let (a, b, c, d) = (-12, -123, -1234, -12345); all_eq!(simd_shr(i32x4(a, b, c, d), x1), i32x4(a >> 1, b >> 2, c >> 3, d >> 4)); - all_eq!(simd_shr(u32x4(a as u32, b as u32, c as u32, d as u32), y1), - u32x4((a as u32) >> 1, (b as u32) >> 2, (c as u32) >> 3, (d as u32) >> 4)); + all_eq_!(simd_shr(U32::<4>([a as u32, b as u32, c as u32, d as u32]), y1), + U32::<4>([(a as u32) >> 1, (b as u32) >> 2, (c as u32) >> 3, (d as u32) >> 4])); all_eq!(simd_and(x1, x2), i32x4(0, 2, 0, 4)); all_eq!(simd_and(x2, x1), i32x4(0, 2, 0, 4)); - all_eq!(simd_and(y1, y2), u32x4(0, 2, 0, 4)); - all_eq!(simd_and(y2, y1), u32x4(0, 2, 0, 4)); + all_eq_!(simd_and(y1, y2), U32::<4>([0, 2, 0, 4])); + all_eq_!(simd_and(y2, y1), U32::<4>([0, 2, 0, 4])); all_eq!(simd_or(x1, x2), i32x4(3, 3, 7, 5)); all_eq!(simd_or(x2, x1), i32x4(3, 3, 7, 5)); - all_eq!(simd_or(y1, y2), u32x4(3, 3, 7, 5)); - all_eq!(simd_or(y2, y1), u32x4(3, 3, 7, 5)); + all_eq_!(simd_or(y1, y2), U32::<4>([3, 3, 7, 5])); + all_eq_!(simd_or(y2, y1), U32::<4>([3, 3, 7, 5])); all_eq!(simd_xor(x1, x2), i32x4(3, 1, 7, 1)); all_eq!(simd_xor(x2, x1), i32x4(3, 1, 7, 1)); - all_eq!(simd_xor(y1, y2), u32x4(3, 1, 7, 1)); - all_eq!(simd_xor(y2, y1), u32x4(3, 1, 7, 1)); + all_eq_!(simd_xor(y1, y2), U32::<4>([3, 1, 7, 1])); + all_eq_!(simd_xor(y2, y1), U32::<4>([3, 1, 7, 1])); } } From 9bb42021962c93b35592a0b1c29f282d3b5506c4 Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Sun, 8 Nov 2020 20:21:28 +1000 Subject: [PATCH 02/27] update ui tests --- src/test/ui/simd/simd-array-type.rs | 6 ++---- src/test/ui/simd/simd-generics.rs | 12 ++++++------ .../simd-intrinsic-generic-arithmetic-saturating.rs | 4 ++-- .../ui/simd/simd-intrinsic-generic-arithmetic.rs | 4 ++-- 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/test/ui/simd/simd-array-type.rs b/src/test/ui/simd/simd-array-type.rs index c84988cffb423..e84186a42adff 100644 --- a/src/test/ui/simd/simd-array-type.rs +++ b/src/test/ui/simd/simd-array-type.rs @@ -1,11 +1,9 @@ // run-pass -#![allow(dead_code, incomplete_features)] +#![allow(dead_code)] // pretty-expanded FIXME #23616 -#![feature(repr_simd)] -#![feature(platform_intrinsics)] -#![feature(const_generics)] +#![feature(repr_simd, platform_intrinsics, min_const_generics)] #[repr(simd)] #[derive(Copy, Clone)] diff --git a/src/test/ui/simd/simd-generics.rs b/src/test/ui/simd/simd-generics.rs index 9877e37dfb2ec..dedca6276cda9 100644 --- a/src/test/ui/simd/simd-generics.rs +++ b/src/test/ui/simd/simd-generics.rs @@ -1,6 +1,6 @@ // run-pass -#![allow(non_camel_case_types, incomplete_features)] -#![feature(repr_simd, platform_intrinsics, const_generics)] +#![allow(non_camel_case_types)] +#![feature(repr_simd, platform_intrinsics, min_const_generics)] use std::ops; @@ -25,7 +25,7 @@ impl ops::Add for f32x4 { type Output = f32x4; fn add(self, rhs: f32x4) -> f32x4 { - unsafe {simd_add(self, rhs)} + unsafe { simd_add(self, rhs) } } } @@ -33,12 +33,12 @@ impl ops::Add for S<4> { type Output = Self; fn add(self, rhs: Self) -> Self { - unsafe {simd_add(self, rhs)} + unsafe { simd_add(self, rhs) } } } -pub fn main() { unsafe { +pub fn main() { let lr = f32x4(1.0f32, 2.0f32, 3.0f32, 4.0f32); // lame-o @@ -54,4 +54,4 @@ pub fn main() { unsafe { assert_eq!(y, 4.0f32); assert_eq!(z, 6.0f32); assert_eq!(w, 8.0f32); -}} +} diff --git a/src/test/ui/simd/simd-intrinsic-generic-arithmetic-saturating.rs b/src/test/ui/simd/simd-intrinsic-generic-arithmetic-saturating.rs index 30a4fc11368d6..4c459fa4bc801 100644 --- a/src/test/ui/simd/simd-intrinsic-generic-arithmetic-saturating.rs +++ b/src/test/ui/simd/simd-intrinsic-generic-arithmetic-saturating.rs @@ -1,8 +1,8 @@ // run-pass // ignore-emscripten -#![allow(non_camel_case_types, incomplete_features)] -#![feature(repr_simd, platform_intrinsics, const_generics)] +#![allow(non_camel_case_types)] +#![feature(repr_simd, platform_intrinsics, min_const_generics)] #[repr(simd)] #[derive(Copy, Clone, PartialEq, Debug)] diff --git a/src/test/ui/simd/simd-intrinsic-generic-arithmetic.rs b/src/test/ui/simd/simd-intrinsic-generic-arithmetic.rs index 83f11c6abdbf0..5b0ff88432ed9 100644 --- a/src/test/ui/simd/simd-intrinsic-generic-arithmetic.rs +++ b/src/test/ui/simd/simd-intrinsic-generic-arithmetic.rs @@ -1,9 +1,9 @@ // run-pass -#![allow(non_camel_case_types, incomplete_features)] +#![allow(non_camel_case_types)] // ignore-emscripten FIXME(#45351) hits an LLVM assert -#![feature(repr_simd, platform_intrinsics, const_generics)] +#![feature(repr_simd, platform_intrinsics, min_const_generics)] #[repr(simd)] #[derive(Copy, Clone)] From 899d9b9bd505d5dbd39e22f1c6d04d516e75c769 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Thu, 12 Nov 2020 00:00:00 +0000 Subject: [PATCH 03/27] Fix test checking that into_boxed_slice does not panic The memory allocation in vec might panic in the case of capacity overflow. Move the allocation outside the function to fix the test. --- src/test/codegen/vec-shrink-panic.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/codegen/vec-shrink-panic.rs b/src/test/codegen/vec-shrink-panic.rs index 690c7e6d6ced2..cee4128c65040 100644 --- a/src/test/codegen/vec-shrink-panic.rs +++ b/src/test/codegen/vec-shrink-panic.rs @@ -15,9 +15,9 @@ pub fn shrink_to_fit(vec: &mut Vec) { // CHECK-LABEL: @issue71861 #[no_mangle] -pub fn issue71861(n: usize) -> Box<[u32]> { +pub fn issue71861(vec: Vec) -> Box<[u32]> { // CHECK-NOT: panic - vec![0; n].into_boxed_slice() + vec.into_boxed_slice() } // CHECK-LABEL: @issue75636 From 28463aac9621fdfc9fb1bcca2c5d611e0b7d3837 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Thu, 12 Nov 2020 00:00:00 +0000 Subject: [PATCH 04/27] Ensure that closure call is not removed by MIR optimizations in a test --- src/test/codegen/internalize-closures.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/codegen/internalize-closures.rs b/src/test/codegen/internalize-closures.rs index 8d9192c6fa0c1..ab3dc3fba5ef6 100644 --- a/src/test/codegen/internalize-closures.rs +++ b/src/test/codegen/internalize-closures.rs @@ -1,4 +1,4 @@ -// compile-flags: -C no-prepopulate-passes +// compile-flags: -C no-prepopulate-passes -Zmir-opt-level=0 pub fn main() { From d54ea4f622a788b75d6576281081c4252b1ec05e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Thu, 12 Nov 2020 00:00:00 +0000 Subject: [PATCH 05/27] Fix codegen test for issue 37945 --- src/test/codegen/issue-37945.rs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/test/codegen/issue-37945.rs b/src/test/codegen/issue-37945.rs index 0ca42b7ec83b1..a91e8e817e403 100644 --- a/src/test/codegen/issue-37945.rs +++ b/src/test/codegen/issue-37945.rs @@ -1,26 +1,34 @@ -// compile-flags: -O +// compile-flags: -O -Zmerge-functions=disabled // ignore-x86 // ignore-arm // ignore-emscripten // ignore-gnux32 // ignore 32-bit platforms (LLVM has a bug with them) -// See issue #37945. +// Check that LLVM understands that `Iter` pointer is not null. Issue #37945. #![crate_type = "lib"] use std::slice::Iter; -// CHECK-LABEL: @is_empty_1 #[no_mangle] pub fn is_empty_1(xs: Iter) -> bool { -// CHECK-NOT: icmp eq float* {{.*}}, null +// CHECK-LABEL: @is_empty_1( +// CHECK-NEXT: start: +// CHECK-NEXT: [[A:%.*]] = icmp ne i32* %xs.1, null +// CHECK-NEXT: tail call void @llvm.assume(i1 [[A]]) +// CHECK-NEXT: [[B:%.*]] = icmp eq i32* %xs.0, %xs.1 +// CHECK-NEXT: ret i1 [[B:%.*]] {xs}.next().is_none() } -// CHECK-LABEL: @is_empty_2 #[no_mangle] pub fn is_empty_2(xs: Iter) -> bool { -// CHECK-NOT: icmp eq float* {{.*}}, null +// CHECK-LABEL: @is_empty_2 +// CHECK-NEXT: start: +// CHECK-NEXT: [[C:%.*]] = icmp ne i32* %xs.1, null +// CHECK-NEXT: tail call void @llvm.assume(i1 [[C]]) +// CHECK-NEXT: [[D:%.*]] = icmp eq i32* %xs.0, %xs.1 +// CHECK-NEXT: ret i1 [[D:%.*]] xs.map(|&x| x).next().is_none() } From 540b5db6306e0e7e96fb9d8dfda94cc82f6ba3bb Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Fri, 13 Nov 2020 14:31:12 +1000 Subject: [PATCH 06/27] remove const_generics from codegen tests --- .../simd-intrinsic/simd-intrinsic-generic-extract-insert.rs | 4 ++-- .../codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-extract-insert.rs b/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-extract-insert.rs index 3dba044d376e8..5f976b642eae9 100644 --- a/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-extract-insert.rs +++ b/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-extract-insert.rs @@ -2,8 +2,8 @@ #![crate_type = "lib"] -#![feature(repr_simd, platform_intrinsics, const_generics)] -#![allow(non_camel_case_types, incomplete_features)] +#![feature(repr_simd, platform_intrinsics, min_const_generics)] +#![allow(non_camel_case_types)] #[repr(simd)] #[derive(Copy, Clone)] diff --git a/src/test/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs b/src/test/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs index 23098e7f64945..76f2644dbc9f5 100644 --- a/src/test/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs +++ b/src/test/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs @@ -4,8 +4,8 @@ #![crate_type = "lib"] -#![allow(non_camel_case_types, incomplete_features)] -#![feature(repr_simd, platform_intrinsics, const_generics)] +#![allow(non_camel_case_types)] +#![feature(repr_simd, platform_intrinsics, min_const_generics)] #[repr(simd)] #[derive(Copy, Clone)] From 045105b1a2ed4d93d5e72bc34fdce55e0b3e6dad Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Fri, 13 Nov 2020 14:32:03 +1000 Subject: [PATCH 07/27] remove internal simd_size_and_ty from llvm backend --- compiler/rustc_codegen_llvm/src/intrinsic.rs | 51 +++++++------------- compiler/rustc_middle/src/ty/sty.rs | 7 ++- 2 files changed, 23 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 2ea7d7ac2d822..3df0ab5d36ca0 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -740,23 +740,6 @@ fn generic_simd_intrinsic( llret_ty: &'ll Type, span: Span, ) -> Result<&'ll Value, ()> { - // Given a SIMD vector type `x` return the element type and the number of - // elements in the vector. - fn simd_ty_and_len(bx: &Builder<'a, 'll, 'tcx>, simd_ty: Ty<'tcx>) -> (Ty<'tcx>, u64) { - let ty = if let ty::Adt(_def, _substs) = simd_ty.kind() { - let f0_ty = bx.layout_of(simd_ty).field(bx, 0).ty; - if let ty::Array(element_ty, _) = f0_ty.kind() { element_ty } else { f0_ty } - } else { - bug!("should only be called with a SIMD type") - }; - let count = if let abi::Abi::Vector { count, .. } = bx.layout_of(simd_ty).abi { - count - } else { - bug!("should only be called with a SIMD type") - }; - (ty, count) - } - // macros for error handling: macro_rules! emit_error { ($msg: tt) => { @@ -809,7 +792,7 @@ fn generic_simd_intrinsic( _ => return_error!("`{}` is not an integral type", in_ty), }; require_simd!(arg_tys[1], "argument"); - let (_, v_len) = simd_ty_and_len(bx, arg_tys[1]); + let (v_len, _) = arg_tys[1].simd_size_and_type(bx.tcx()); require!( // Allow masks for vectors with fewer than 8 elements to be // represented with a u8 or i8. @@ -840,11 +823,11 @@ fn generic_simd_intrinsic( _ => None, }; - let (in_elem, in_len) = simd_ty_and_len(bx, arg_tys[0]); + let (in_len, in_elem) = arg_tys[0].simd_size_and_type(bx.tcx()); if let Some(cmp_op) = comparison { require_simd!(ret_ty, "return"); - let (out_ty, out_len) = simd_ty_and_len(bx, ret_ty); + let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx()); require!( in_len == out_len, "expected return type with length {} (same as input type `{}`), \ @@ -878,7 +861,7 @@ fn generic_simd_intrinsic( require_simd!(ret_ty, "return"); - let (out_ty, out_len) = simd_ty_and_len(bx, ret_ty); + let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx()); require!( out_len == n, "expected return type of length {}, found `{}` with length {}", @@ -962,7 +945,7 @@ fn generic_simd_intrinsic( let m_elem_ty = in_elem; let m_len = in_len; require_simd!(arg_tys[1], "argument"); - let (_, v_len) = simd_ty_and_len(bx, arg_tys[1]); + let (v_len, _) = arg_tys[1].simd_size_and_type(bx.tcx()); require!( m_len == v_len, "mismatched lengths: mask length `{}` != other vector length `{}`", @@ -1187,8 +1170,8 @@ fn generic_simd_intrinsic( require_simd!(ret_ty, "return"); // Of the same length: - let (_, out_len) = simd_ty_and_len(bx, arg_tys[1]); - let (_, out_len2) = simd_ty_and_len(bx, arg_tys[2]); + let (out_len, _) = arg_tys[1].simd_size_and_type(bx.tcx()); + let (out_len2, _) = arg_tys[2].simd_size_and_type(bx.tcx()); require!( in_len == out_len, "expected {} argument with length {} (same as input type `{}`), \ @@ -1231,8 +1214,8 @@ fn generic_simd_intrinsic( // The second argument must be a simd vector with an element type that's a pointer // to the element type of the first argument - let (element_ty0, _) = simd_ty_and_len(bx, arg_tys[0]); - let (element_ty1, _) = simd_ty_and_len(bx, arg_tys[1]); + let (_, element_ty0) = arg_tys[0].simd_size_and_type(bx.tcx()); + let (_, element_ty1) = arg_tys[1].simd_size_and_type(bx.tcx()); let (pointer_count, underlying_ty) = match element_ty1.kind() { ty::RawPtr(p) if p.ty == in_elem => (ptr_count(element_ty1), non_ptr(element_ty1)), _ => { @@ -1256,7 +1239,7 @@ fn generic_simd_intrinsic( assert_eq!(underlying_ty, non_ptr(element_ty0)); // The element type of the third argument must be a signed integer type of any width: - let (element_ty2, _) = simd_ty_and_len(bx, arg_tys[2]); + let (_, element_ty2) = arg_tys[2].simd_size_and_type(bx.tcx()); match element_ty2.kind() { ty::Int(_) => (), _ => { @@ -1316,8 +1299,8 @@ fn generic_simd_intrinsic( require_simd!(arg_tys[2], "third"); // Of the same length: - let (_, element_len1) = simd_ty_and_len(bx, arg_tys[1]); - let (_, element_len2) = simd_ty_and_len(bx, arg_tys[2]); + let (element_len1, _) = arg_tys[1].simd_size_and_type(bx.tcx()); + let (element_len2, _) = arg_tys[2].simd_size_and_type(bx.tcx()); require!( in_len == element_len1, "expected {} argument with length {} (same as input type `{}`), \ @@ -1357,9 +1340,9 @@ fn generic_simd_intrinsic( // The second argument must be a simd vector with an element type that's a pointer // to the element type of the first argument - let (element_ty0, _element_len0) = simd_ty_and_len(bx, arg_tys[0]); - let (element_ty1, _element_len1) = simd_ty_and_len(bx, arg_tys[1]); - let (element_ty2, _element_len2) = simd_ty_and_len(bx, arg_tys[2]); + let (_, element_ty0) = arg_tys[0].simd_size_and_type(bx.tcx()); + let (_, element_ty1) = arg_tys[1].simd_size_and_type(bx.tcx()); + let (_, element_ty2) = arg_tys[2].simd_size_and_type(bx.tcx()); let (pointer_count, underlying_ty) = match element_ty1.kind() { ty::RawPtr(p) if p.ty == in_elem && p.mutbl == hir::Mutability::Mut => { (ptr_count(element_ty1), non_ptr(element_ty1)) @@ -1589,7 +1572,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, if name == sym::simd_cast { require_simd!(ret_ty, "return"); - let (out_elem, out_len) = simd_ty_and_len(bx, ret_ty); + let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx()); require!( in_len == out_len, "expected return type with length {} (same as input type `{}`), \ @@ -1715,7 +1698,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, return_error!( "expected element type `{}` of vector type `{}` \ to be a signed or unsigned integer type", - simd_ty_and_len(bx, arg_tys[0]).0, + arg_tys[0].simd_size_and_type(bx.tcx()).1, arg_tys[0] ); } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 8202d0f0ef169..d1f83d0a83e0e 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1963,7 +1963,12 @@ impl<'tcx> TyS<'tcx> { match self.kind() { Adt(def, substs) => { let variant = def.non_enum_variant(); - (variant.fields.len() as u64, variant.fields[0].ty(tcx, substs)) + let f0_ty = variant.fields[0].ty(tcx, substs); + + match f0_ty.kind() { + Array(f0_elem_ty, f0_len) => (f0_len.eval_usize(tcx, ParamEnv::empty()) as u64, f0_elem_ty), + _ => (variant.fields.len() as u64, f0_ty), + } } _ => bug!("`simd_size_and_type` called on invalid type"), } From 74f2941a8ebf32a6864ea4596c755a9f65e14f42 Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Sat, 14 Nov 2020 21:12:15 +1000 Subject: [PATCH 08/27] tweak new codegen test to work on local --- .../simd-intrinsic-generic-extract-insert.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-extract-insert.rs b/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-extract-insert.rs index 5f976b642eae9..1ab3292378558 100644 --- a/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-extract-insert.rs +++ b/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-extract-insert.rs @@ -21,27 +21,27 @@ extern "platform-intrinsic" { // CHECK-LABEL: @extract_m #[no_mangle] pub unsafe fn extract_m(v: M, i: u32) -> f32 { - // CHECK: extractelement <4 x float> %0, i32 %i + // CHECK: extractelement <4 x float> %_3, i32 %i simd_extract(v, i) } // CHECK-LABEL: @extract_s #[no_mangle] pub unsafe fn extract_s(v: S<4>, i: u32) -> f32 { - // CHECK: extractelement <4 x float> %0, i32 %i + // CHECK: extractelement <4 x float> %_3, i32 %i simd_extract(v, i) } // CHECK-LABEL: @insert_m #[no_mangle] pub unsafe fn insert_m(v: M, i: u32, j: f32) -> M { - // CHECK: insertelement <4 x float> %1, float %j, i32 %i + // CHECK: insertelement <4 x float> %_4, float %j, i32 %i simd_insert(v, i, j) } // CHECK-LABEL: @insert_s #[no_mangle] pub unsafe fn insert_s(v: S<4>, i: u32, j: f32) -> S<4> { - // CHECK: insertelement <4 x float> %1, float %j, i32 %i + // CHECK: insertelement <4 x float> %_4, float %j, i32 %i simd_insert(v, i, j) } From e0f3119103b79df190324e8d72a5827e4d0cd52d Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Thu, 5 Nov 2020 17:30:39 +0100 Subject: [PATCH 09/27] Introduce `TypeVisitor::BreakTy` --- .../src/infer/error_reporting/mod.rs | 2 +- .../nice_region_error/static_impl_trait.rs | 2 +- .../rustc_infer/src/infer/nll_relate/mod.rs | 7 ++- compiler/rustc_infer/src/infer/resolve.rs | 2 +- .../src/traits/structural_impls.rs | 2 +- compiler/rustc_lint/src/types.rs | 2 +- compiler/rustc_macros/src/type_foldable.rs | 2 +- compiler/rustc_middle/src/lib.rs | 1 + compiler/rustc_middle/src/macros.rs | 4 +- compiler/rustc_middle/src/mir/mod.rs | 5 +- .../rustc_middle/src/mir/type_foldable.rs | 25 +++++---- compiler/rustc_middle/src/ty/fold.rs | 53 +++++++++--------- compiler/rustc_middle/src/ty/mod.rs | 2 +- compiler/rustc_middle/src/ty/print/pretty.rs | 2 +- .../rustc_middle/src/ty/structural_impls.rs | 54 +++++++++---------- compiler/rustc_middle/src/ty/subst.rs | 4 +- compiler/rustc_mir/src/interpret/util.rs | 4 +- .../src/monomorphize/polymorphize.rs | 8 +-- compiler/rustc_mir/src/util/pretty.rs | 2 +- compiler/rustc_privacy/src/lib.rs | 35 +++++++----- .../rustc_trait_selection/src/opaque_types.rs | 9 ++-- .../src/traits/const_evaluatable.rs | 14 ++--- .../src/traits/object_safety.rs | 6 +-- .../src/traits/structural_match.rs | 2 +- compiler/rustc_traits/src/chalk/lowering.rs | 10 ++-- compiler/rustc_typeck/src/check/check.rs | 8 +-- compiler/rustc_typeck/src/check/op.rs | 2 +- compiler/rustc_typeck/src/check/wfcheck.rs | 6 +-- compiler/rustc_typeck/src/collect.rs | 2 +- .../src/constrained_generic_params.rs | 6 +-- .../clippy_lints/src/redundant_clone.rs | 2 +- 31 files changed, 157 insertions(+), 128 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 524efd04cfce9..b0d9daf3927c1 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1498,7 +1498,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> { - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { if let Some((kind, def_id)) = TyCategory::from_ty(t) { let span = self.tcx.def_span(def_id); // Avoid cluttering the output when the "found" and error span overlap: diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index df3dbfca01d7a..7b0deb45f8684 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -474,7 +474,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { struct TraitObjectVisitor(Vec); impl TypeVisitor<'_> for TraitObjectVisitor { - fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow<()> { + fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow { match t.kind() { ty::Dynamic(preds, RegionKind::ReStatic) => { if let Some(def_id) = preds.principal_def_id() { diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 9b2ffc7a920b0..0b2847658f71e 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -741,7 +741,10 @@ struct ScopeInstantiator<'me, 'tcx> { } impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> { - fn visit_binder>(&mut self, t: &ty::Binder) -> ControlFlow<()> { + fn visit_binder>( + &mut self, + t: &ty::Binder, + ) -> ControlFlow { self.target_index.shift_in(1); t.super_visit_with(self); self.target_index.shift_out(1); @@ -749,7 +752,7 @@ impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> { ControlFlow::CONTINUE } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { let ScopeInstantiator { bound_region_scope, next_region, .. } = self; match r { diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index fe4ba5aa4e820..e2531dc7ad9d6 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -123,7 +123,7 @@ impl<'a, 'tcx> UnresolvedTypeFinder<'a, 'tcx> { } impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> { - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { let t = self.infcx.shallow_resolve(t); if t.has_infer_types() { if let ty::Infer(infer_ty) = *t.kind() { diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs index 1a1c2637a6fa6..d6500f62e7851 100644 --- a/compiler/rustc_infer/src/traits/structural_impls.rs +++ b/compiler/rustc_infer/src/traits/structural_impls.rs @@ -69,7 +69,7 @@ impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx } } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.predicate.visit_with(visitor) } } diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 467a3a425906f..802fb1970cd7e 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1135,7 +1135,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { }; impl<'a, 'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> { - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { match ty.kind() { ty::Opaque(..) => { self.ty = Some(ty); diff --git a/compiler/rustc_macros/src/type_foldable.rs b/compiler/rustc_macros/src/type_foldable.rs index 8fa6e6a710108..18d7affa75dea 100644 --- a/compiler/rustc_macros/src/type_foldable.rs +++ b/compiler/rustc_macros/src/type_foldable.rs @@ -35,7 +35,7 @@ pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2:: fn super_visit_with<__F: ::rustc_middle::ty::fold::TypeVisitor<'tcx>>( &self, __folder: &mut __F - ) -> ::std::ops::ControlFlow<()> { + ) -> ::std::ops::ControlFlow<__F::BreakTy> { match *self { #body_visit } ::std::ops::ControlFlow::CONTINUE } diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 4a1d5459d1eec..cdc5940d9baed 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -51,6 +51,7 @@ #![feature(half_open_range_patterns)] #![feature(exclusive_range_pattern)] #![feature(control_flow_enum)] +#![feature(associated_type_defaults)] #![recursion_limit = "512"] #[macro_use] diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs index 921086366bea2..057f2615a44c6 100644 --- a/compiler/rustc_middle/src/macros.rs +++ b/compiler/rustc_middle/src/macros.rs @@ -62,7 +62,7 @@ macro_rules! CloneTypeFoldableImpls { fn super_visit_with>( &self, _: &mut F) - -> ::std::ops::ControlFlow<()> + -> ::std::ops::ControlFlow { ::std::ops::ControlFlow::CONTINUE } @@ -105,7 +105,7 @@ macro_rules! EnumTypeFoldableImpl { fn super_visit_with>( &self, visitor: &mut V, - ) -> ::std::ops::ControlFlow<()> { + ) -> ::std::ops::ControlFlow { EnumTypeFoldableImpl!(@VisitVariants(self, visitor) input($($variants)*) output()) } } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 5fe7b0f647dcd..15783cfd00c5c 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2477,7 +2477,10 @@ impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection { UserTypeProjection { base, projs } } - fn super_visit_with>(&self, visitor: &mut Vs) -> ControlFlow<()> { + fn super_visit_with>( + &self, + visitor: &mut Vs, + ) -> ControlFlow { self.base.visit_with(visitor) // Note: there's nothing in `self.proj` to visit. } diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs index 0801188b27881..0e6bf0fd02971 100644 --- a/compiler/rustc_middle/src/mir/type_foldable.rs +++ b/compiler/rustc_middle/src/mir/type_foldable.rs @@ -87,7 +87,7 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { Terminator { source_info: self.source_info, kind } } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { use crate::mir::TerminatorKind::*; match self.kind { @@ -144,7 +144,7 @@ impl<'tcx> TypeFoldable<'tcx> for GeneratorKind { *self } - fn super_visit_with>(&self, _: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, _: &mut V) -> ControlFlow { ControlFlow::CONTINUE } } @@ -154,7 +154,7 @@ impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> { Place { local: self.local.fold_with(folder), projection: self.projection.fold_with(folder) } } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.local.visit_with(visitor)?; self.projection.visit_with(visitor) } @@ -166,7 +166,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { folder.tcx().intern_place_elems(&v) } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.iter().try_for_each(|t| t.visit_with(visitor)) } } @@ -216,7 +216,7 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { } } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { use crate::mir::Rvalue::*; match *self { Use(ref op) => op.visit_with(visitor), @@ -271,7 +271,7 @@ impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> { } } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { match *self { Operand::Copy(ref place) | Operand::Move(ref place) => place.visit_with(visitor), Operand::Constant(ref c) => c.visit_with(visitor), @@ -295,7 +295,10 @@ impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> { } } - fn super_visit_with>(&self, visitor: &mut Vs) -> ControlFlow<()> { + fn super_visit_with>( + &self, + visitor: &mut Vs, + ) -> ControlFlow { use crate::mir::ProjectionElem::*; match self { @@ -310,7 +313,7 @@ impl<'tcx> TypeFoldable<'tcx> for Field { fn super_fold_with>(&self, _: &mut F) -> Self { *self } - fn super_visit_with>(&self, _: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, _: &mut V) -> ControlFlow { ControlFlow::CONTINUE } } @@ -319,7 +322,7 @@ impl<'tcx> TypeFoldable<'tcx> for GeneratorSavedLocal { fn super_fold_with>(&self, _: &mut F) -> Self { *self } - fn super_visit_with>(&self, _: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, _: &mut V) -> ControlFlow { ControlFlow::CONTINUE } } @@ -328,7 +331,7 @@ impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix { fn super_fold_with>(&self, _: &mut F) -> Self { self.clone() } - fn super_visit_with>(&self, _: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, _: &mut V) -> ControlFlow { ControlFlow::CONTINUE } } @@ -341,7 +344,7 @@ impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> { literal: self.literal.fold_with(folder), } } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.literal.visit_with(visitor) } } diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 70a8157c04ac7..c24cb9b4c0f2d 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -49,8 +49,8 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { self.super_fold_with(folder) } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()>; - fn visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow; + fn visit_with>(&self, visitor: &mut V) -> ControlFlow { self.super_visit_with(visitor) } @@ -161,7 +161,7 @@ impl TypeFoldable<'tcx> for hir::Constness { fn super_fold_with>(&self, _: &mut F) -> Self { *self } - fn super_visit_with>(&self, _: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, _: &mut V) -> ControlFlow { ControlFlow::CONTINUE } } @@ -195,23 +195,25 @@ pub trait TypeFolder<'tcx>: Sized { } pub trait TypeVisitor<'tcx>: Sized { - fn visit_binder>(&mut self, t: &Binder) -> ControlFlow<()> { + type BreakTy = (); + + fn visit_binder>(&mut self, t: &Binder) -> ControlFlow { t.super_visit_with(self) } - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { t.super_visit_with(self) } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { r.super_visit_with(self) } - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> { + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { c.super_visit_with(self) } - fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow<()> { + fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow { p.super_visit_with(self) } } @@ -329,14 +331,17 @@ impl<'tcx> TyCtxt<'tcx> { where F: FnMut(ty::Region<'tcx>) -> bool, { - fn visit_binder>(&mut self, t: &Binder) -> ControlFlow<()> { + fn visit_binder>( + &mut self, + t: &Binder, + ) -> ControlFlow { self.outer_index.shift_in(1); let result = t.as_ref().skip_binder().visit_with(self); self.outer_index.shift_out(1); result } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { match *r { ty::ReLateBound(debruijn, _) if debruijn < self.outer_index => { ControlFlow::CONTINUE @@ -351,7 +356,7 @@ impl<'tcx> TyCtxt<'tcx> { } } - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { // We're only interested in types involving regions if ty.flags().intersects(TypeFlags::HAS_FREE_REGIONS) { ty.super_visit_with(self) @@ -844,14 +849,14 @@ struct HasEscapingVarsVisitor { } impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { - fn visit_binder>(&mut self, t: &Binder) -> ControlFlow<()> { + fn visit_binder>(&mut self, t: &Binder) -> ControlFlow { self.outer_index.shift_in(1); let result = t.super_visit_with(self); self.outer_index.shift_out(1); result } - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { // If the outer-exclusive-binder is *strictly greater* than // `outer_index`, that means that `t` contains some content // bound at `outer_index` or above (because @@ -864,7 +869,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { } } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { // If the region is bound by `outer_index` or anything outside // of outer index, then it escapes the binders we have // visited. @@ -875,7 +880,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { } } - fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> ControlFlow<()> { + fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> ControlFlow { // we don't have a `visit_infer_const` callback, so we have to // hook in here to catch this case (annoying...), but // otherwise we do want to remember to visit the rest of the @@ -887,7 +892,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { } } - fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<()> { + fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow { if predicate.inner.outer_exclusive_binder > self.outer_index { ControlFlow::BREAK } else { @@ -902,7 +907,7 @@ struct HasTypeFlagsVisitor { } impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { - fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow<()> { + fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow { debug!( "HasTypeFlagsVisitor: t={:?} t.flags={:?} self.flags={:?}", t, @@ -912,19 +917,19 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { if t.flags().intersects(self.flags) { ControlFlow::BREAK } else { ControlFlow::CONTINUE } } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { let flags = r.type_flags(); debug!("HasTypeFlagsVisitor: r={:?} r.flags={:?} self.flags={:?}", r, flags, self.flags); if flags.intersects(self.flags) { ControlFlow::BREAK } else { ControlFlow::CONTINUE } } - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> { + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { let flags = FlagComputation::for_const(c); debug!("HasTypeFlagsVisitor: c={:?} c.flags={:?} self.flags={:?}", c, flags, self.flags); if flags.intersects(self.flags) { ControlFlow::BREAK } else { ControlFlow::CONTINUE } } - fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<()> { + fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow { debug!( "HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}", predicate, predicate.inner.flags, self.flags @@ -964,14 +969,14 @@ impl LateBoundRegionsCollector { } impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { - fn visit_binder>(&mut self, t: &Binder) -> ControlFlow<()> { + fn visit_binder>(&mut self, t: &Binder) -> ControlFlow { self.current_index.shift_in(1); let result = t.super_visit_with(self); self.current_index.shift_out(1); result } - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { // if we are only looking for "constrained" region, we have to // ignore the inputs to a projection, as they may not appear // in the normalized form @@ -984,7 +989,7 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { t.super_visit_with(self) } - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> { + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { // if we are only looking for "constrained" region, we have to // ignore the inputs of an unevaluated const, as they may not appear // in the normalized form @@ -997,7 +1002,7 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { c.super_visit_with(self) } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { if let ty::ReLateBound(debruijn, br) = *r { if debruijn == self.current_index { self.regions.insert(br); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 06e69a0009b1f..dee0abb868e39 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1781,7 +1781,7 @@ impl<'tcx> TypeFoldable<'tcx> for ParamEnv<'tcx> { ParamEnv::new(self.caller_bounds().fold_with(folder), self.reveal().fold_with(folder)) } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.caller_bounds().visit_with(visitor)?; self.reveal().visit_with(visitor) } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 1e4fd0921ee0f..d4fad188e215d 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1796,7 +1796,7 @@ impl FmtPrinter<'_, 'tcx, F> { { struct LateBoundRegionNameCollector<'a>(&'a mut FxHashSet); impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector<'_> { - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { if let ty::ReLateBound(_, ty::BrNamed(_, name)) = *r { self.0.insert(name); } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 89fd803fe5140..d42a1b772a039 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -729,7 +729,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::AdtDef { *self } - fn super_visit_with>(&self, _visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, _visitor: &mut V) -> ControlFlow { ControlFlow::CONTINUE } } @@ -739,7 +739,7 @@ impl<'tcx, T: TypeFoldable<'tcx>, U: TypeFoldable<'tcx>> TypeFoldable<'tcx> for (self.0.fold_with(folder), self.1.fold_with(folder)) } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.0.visit_with(visitor)?; self.1.visit_with(visitor) } @@ -752,7 +752,7 @@ impl<'tcx, A: TypeFoldable<'tcx>, B: TypeFoldable<'tcx>, C: TypeFoldable<'tcx>> (self.0.fold_with(folder), self.1.fold_with(folder), self.2.fold_with(folder)) } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.0.visit_with(visitor)?; self.1.visit_with(visitor)?; self.2.visit_with(visitor) @@ -778,7 +778,7 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc { Rc::new((**self).fold_with(folder)) } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { (**self).visit_with(visitor) } } @@ -788,7 +788,7 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Arc { Arc::new((**self).fold_with(folder)) } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { (**self).visit_with(visitor) } } @@ -799,7 +799,7 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box { box content } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { (**self).visit_with(visitor) } } @@ -809,7 +809,7 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec { self.iter().map(|t| t.fold_with(folder)).collect() } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.iter().try_for_each(|t| t.visit_with(visitor)) } } @@ -819,7 +819,7 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<[T]> { self.iter().map(|t| t.fold_with(folder)).collect::>().into_boxed_slice() } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.iter().try_for_each(|t| t.visit_with(visitor)) } } @@ -833,11 +833,11 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder { folder.fold_binder(self) } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.as_ref().skip_binder().visit_with(visitor) } - fn visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn visit_with>(&self, visitor: &mut V) -> ControlFlow { visitor.visit_binder(self) } } @@ -847,7 +847,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> fold_list(*self, folder, |tcx, v| tcx.intern_existential_predicates(v)) } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.iter().try_for_each(|p| p.visit_with(visitor)) } } @@ -857,7 +857,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { fold_list(*self, folder, |tcx, v| tcx.intern_type_list(v)) } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.iter().try_for_each(|t| t.visit_with(visitor)) } } @@ -867,7 +867,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List { fold_list(*self, folder, |tcx, v| tcx.intern_projs(v)) } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.iter().try_for_each(|t| t.visit_with(visitor)) } } @@ -893,7 +893,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> { } } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { use crate::ty::InstanceDef::*; self.substs.visit_with(visitor)?; match self.def { @@ -919,7 +919,7 @@ impl<'tcx> TypeFoldable<'tcx> for interpret::GlobalId<'tcx> { Self { instance: self.instance.fold_with(folder), promoted: self.promoted } } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.instance.visit_with(visitor) } } @@ -968,7 +968,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { folder.fold_ty(*self) } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { match self.kind() { ty::RawPtr(ref tm) => tm.visit_with(visitor), ty::Array(typ, sz) => { @@ -1010,7 +1010,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { } } - fn visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn visit_with>(&self, visitor: &mut V) -> ControlFlow { visitor.visit_ty(self) } } @@ -1024,11 +1024,11 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Region<'tcx> { folder.fold_region(*self) } - fn super_visit_with>(&self, _visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, _visitor: &mut V) -> ControlFlow { ControlFlow::CONTINUE } - fn visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn visit_with>(&self, visitor: &mut V) -> ControlFlow { visitor.visit_region(*self) } } @@ -1039,11 +1039,11 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { folder.tcx().reuse_or_mk_predicate(*self, new) } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { ty::PredicateKind::super_visit_with(&self.inner.kind, visitor) } - fn visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn visit_with>(&self, visitor: &mut V) -> ControlFlow { visitor.visit_predicate(*self) } @@ -1061,7 +1061,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { fold_list(*self, folder, |tcx, v| tcx.intern_predicates(v)) } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.iter().try_for_each(|p| p.visit_with(visitor)) } } @@ -1071,7 +1071,7 @@ impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec self.iter().map(|x| x.fold_with(folder)).collect() } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.iter().try_for_each(|t| t.visit_with(visitor)) } } @@ -1091,12 +1091,12 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Const<'tcx> { folder.fold_const(*self) } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.ty.visit_with(visitor)?; self.val.visit_with(visitor) } - fn visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn visit_with>(&self, visitor: &mut V) -> ControlFlow { visitor.visit_const(self) } } @@ -1116,7 +1116,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> { } } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { match *self { ty::ConstKind::Infer(ic) => ic.visit_with(visitor), ty::ConstKind::Param(p) => p.visit_with(visitor), @@ -1134,7 +1134,7 @@ impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> { *self } - fn super_visit_with>(&self, _visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, _visitor: &mut V) -> ControlFlow { ControlFlow::CONTINUE } } diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 07f775cf8b1e5..343322cfe5830 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -160,7 +160,7 @@ impl<'tcx> TypeFoldable<'tcx> for GenericArg<'tcx> { } } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { match self.unpack() { GenericArgKind::Lifetime(lt) => lt.visit_with(visitor), GenericArgKind::Type(ty) => ty.visit_with(visitor), @@ -392,7 +392,7 @@ impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> { } } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.iter().try_for_each(|t| t.visit_with(visitor)) } } diff --git a/compiler/rustc_mir/src/interpret/util.rs b/compiler/rustc_mir/src/interpret/util.rs index fce5553c99314..f7fca4822ef54 100644 --- a/compiler/rustc_mir/src/interpret/util.rs +++ b/compiler/rustc_mir/src/interpret/util.rs @@ -18,7 +18,7 @@ where }; impl<'tcx> TypeVisitor<'tcx> for UsedParamsNeedSubstVisitor<'tcx> { - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> { + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { if !c.needs_subst() { return ControlFlow::CONTINUE; } @@ -29,7 +29,7 @@ where } } - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { if !ty.needs_subst() { return ControlFlow::CONTINUE; } diff --git a/compiler/rustc_mir/src/monomorphize/polymorphize.rs b/compiler/rustc_mir/src/monomorphize/polymorphize.rs index c2ebc954a22c0..6a50a9243781e 100644 --- a/compiler/rustc_mir/src/monomorphize/polymorphize.rs +++ b/compiler/rustc_mir/src/monomorphize/polymorphize.rs @@ -250,7 +250,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { } impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { - fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<()> { + fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow { debug!("visit_const: c={:?}", c); if !c.has_param_types_or_consts() { return ControlFlow::CONTINUE; @@ -283,7 +283,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { } } - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { debug!("visit_ty: ty={:?}", ty); if !ty.has_param_types_or_consts() { return ControlFlow::CONTINUE; @@ -318,7 +318,7 @@ struct HasUsedGenericParams<'a> { } impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> { - fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<()> { + fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow { debug!("visit_const: c={:?}", c); if !c.has_param_types_or_consts() { return ControlFlow::CONTINUE; @@ -336,7 +336,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> { } } - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { debug!("visit_ty: ty={:?}", ty); if !ty.has_param_types_or_consts() { return ControlFlow::CONTINUE; diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs index 8bee8417c51fa..cd60602b088f2 100644 --- a/compiler/rustc_mir/src/util/pretty.rs +++ b/compiler/rustc_mir/src/util/pretty.rs @@ -640,7 +640,7 @@ pub fn write_allocations<'tcx>( } struct CollectAllocIds(BTreeSet); impl<'tcx> TypeVisitor<'tcx> for CollectAllocIds { - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> { + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { if let ty::ConstKind::Value(val) = c.val { self.0.extend(alloc_ids_from_const(val)); } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 75d75433f1bf1..4a0d356d3377b 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -4,6 +4,7 @@ #![feature(or_patterns)] #![feature(control_flow_enum)] #![feature(try_blocks)] +#![feature(associated_type_defaults)] #![recursion_limit = "256"] use rustc_attr as attr; @@ -44,6 +45,8 @@ use std::{cmp, fmt, mem}; /// manually. Second, it doesn't visit some type components like signatures of fn types, or traits /// in `impl Trait`, see individual comments in `DefIdVisitorSkeleton::visit_ty`. trait DefIdVisitor<'tcx> { + type BreakTy = (); + fn tcx(&self) -> TyCtxt<'tcx>; fn shallow(&self) -> bool { false @@ -56,7 +59,7 @@ trait DefIdVisitor<'tcx> { def_id: DefId, kind: &str, descr: &dyn fmt::Display, - ) -> ControlFlow<()>; + ) -> ControlFlow; /// Not overridden, but used to actually visit types and traits. fn skeleton(&mut self) -> DefIdVisitorSkeleton<'_, 'tcx, Self> { @@ -66,13 +69,16 @@ trait DefIdVisitor<'tcx> { dummy: Default::default(), } } - fn visit(&mut self, ty_fragment: impl TypeFoldable<'tcx>) -> ControlFlow<()> { + fn visit(&mut self, ty_fragment: impl TypeFoldable<'tcx>) -> ControlFlow { ty_fragment.visit_with(&mut self.skeleton()) } - fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<()> { + fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow { self.skeleton().visit_trait(trait_ref) } - fn visit_predicates(&mut self, predicates: ty::GenericPredicates<'tcx>) -> ControlFlow<()> { + fn visit_predicates( + &mut self, + predicates: ty::GenericPredicates<'tcx>, + ) -> ControlFlow { self.skeleton().visit_predicates(predicates) } } @@ -87,13 +93,13 @@ impl<'tcx, V> DefIdVisitorSkeleton<'_, 'tcx, V> where V: DefIdVisitor<'tcx> + ?Sized, { - fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<()> { + fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow { let TraitRef { def_id, substs } = trait_ref; self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref.print_only_trait_path())?; if self.def_id_visitor.shallow() { ControlFlow::CONTINUE } else { substs.visit_with(self) } } - fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<()> { + fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow { match predicate.skip_binders() { ty::PredicateAtom::Trait(ty::TraitPredicate { trait_ref }, _) => { self.visit_trait(trait_ref) @@ -119,7 +125,10 @@ where } } - fn visit_predicates(&mut self, predicates: ty::GenericPredicates<'tcx>) -> ControlFlow<()> { + fn visit_predicates( + &mut self, + predicates: ty::GenericPredicates<'tcx>, + ) -> ControlFlow { let ty::GenericPredicates { parent: _, predicates } = predicates; predicates.iter().try_for_each(|&(predicate, _span)| self.visit_predicate(predicate)) } @@ -129,7 +138,9 @@ impl<'tcx, V> TypeVisitor<'tcx> for DefIdVisitorSkeleton<'_, 'tcx, V> where V: DefIdVisitor<'tcx> + ?Sized, { - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { + type BreakTy = V::BreakTy; + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { let tcx = self.def_id_visitor.tcx(); // InternalSubsts are not visited here because they are visited below in `super_visit_with`. match *ty.kind() { @@ -283,7 +294,7 @@ impl<'a, 'tcx, VL: VisibilityLike> DefIdVisitor<'tcx> for FindMin<'a, 'tcx, VL> def_id: DefId, _kind: &str, _descr: &dyn fmt::Display, - ) -> ControlFlow<()> { + ) -> ControlFlow { self.min = VL::new_min(self, def_id); ControlFlow::CONTINUE } @@ -902,7 +913,7 @@ impl DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> { def_id: DefId, _kind: &str, _descr: &dyn fmt::Display, - ) -> ControlFlow<()> { + ) -> ControlFlow { if let Some(def_id) = def_id.as_local() { if let (ty::Visibility::Public, _) | (_, Some(AccessLevel::ReachableFromImplTrait)) = (self.tcx().visibility(def_id.to_def_id()), self.access_level) @@ -1299,7 +1310,7 @@ impl DefIdVisitor<'tcx> for TypePrivacyVisitor<'tcx> { def_id: DefId, kind: &str, descr: &dyn fmt::Display, - ) -> ControlFlow<()> { + ) -> ControlFlow { if self.check_def_id(def_id, kind, descr) { ControlFlow::BREAK } else { @@ -1799,7 +1810,7 @@ impl DefIdVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'tcx> { def_id: DefId, kind: &str, descr: &dyn fmt::Display, - ) -> ControlFlow<()> { + ) -> ControlFlow { if self.check_def_id(def_id, kind, descr) { ControlFlow::BREAK } else { diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index 914fa1e52c269..c3b2d72fb734b 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -693,12 +693,15 @@ impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor where OP: FnMut(ty::Region<'tcx>), { - fn visit_binder>(&mut self, t: &ty::Binder) -> ControlFlow<()> { + fn visit_binder>( + &mut self, + t: &ty::Binder, + ) -> ControlFlow { t.as_ref().skip_binder().visit_with(self); ControlFlow::CONTINUE } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { match *r { // ignore bound regions, keep visiting ty::ReLateBound(_, _) => ControlFlow::CONTINUE, @@ -709,7 +712,7 @@ where } } - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { // We're only interested in types involving regions if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) { return ControlFlow::CONTINUE; diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index e1721a5a88a76..fdb2361ba0360 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -78,7 +78,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>( Concrete, } let mut failure_kind = FailureKind::Concrete; - walk_abstract_const(tcx, ct, |node| match node { + walk_abstract_const::(tcx, ct, |node| match node { Node::Leaf(leaf) => { let leaf = leaf.subst(tcx, ct.substs); if leaf.has_infer_types_or_consts() { @@ -574,19 +574,19 @@ pub(super) fn try_unify_abstract_consts<'tcx>( // on `ErrorReported`. } -pub fn walk_abstract_const<'tcx, F>( +pub fn walk_abstract_const<'tcx, R, F>( tcx: TyCtxt<'tcx>, ct: AbstractConst<'tcx>, mut f: F, -) -> ControlFlow<()> +) -> ControlFlow where - F: FnMut(Node<'tcx>) -> ControlFlow<()>, + F: FnMut(Node<'tcx>) -> ControlFlow, { - fn recurse<'tcx>( + fn recurse<'tcx, R>( tcx: TyCtxt<'tcx>, ct: AbstractConst<'tcx>, - f: &mut dyn FnMut(Node<'tcx>) -> ControlFlow<()>, - ) -> ControlFlow<()> { + f: &mut dyn FnMut(Node<'tcx>) -> ControlFlow, + ) -> ControlFlow { let root = ct.root(); f(root)?; match root { diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 32e0991733bd9..7da5ec051cb6a 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -771,7 +771,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( } impl<'tcx> TypeVisitor<'tcx> for IllegalSelfTypeVisitor<'tcx> { - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { match t.kind() { ty::Param(_) => { if t == self.tcx.types.self_param { @@ -812,7 +812,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( } } - fn visit_const(&mut self, ct: &ty::Const<'tcx>) -> ControlFlow<()> { + fn visit_const(&mut self, ct: &ty::Const<'tcx>) -> ControlFlow { // First check if the type of this constant references `Self`. self.visit_ty(ct.ty)?; @@ -844,7 +844,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( } } - fn visit_predicate(&mut self, pred: ty::Predicate<'tcx>) -> ControlFlow<()> { + fn visit_predicate(&mut self, pred: ty::Predicate<'tcx>) -> ControlFlow { if let ty::PredicateAtom::ConstEvaluatable(def, substs) = pred.skip_binders() { // FIXME(const_evaluatable_checked): We should probably deduplicate the logic for // `AbstractConst`s here, it might make sense to change `ConstEvaluatable` to diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs index ce0d3ef8a6a58..edab1e031ccab 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -135,7 +135,7 @@ impl Search<'a, 'tcx> { } impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { debug!("Search visiting ty: {:?}", ty); let (adt_def, substs) = match *ty.kind() { diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index c4e2c7f839d70..4c616ccc08676 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -859,14 +859,14 @@ impl<'tcx> BoundVarsCollector<'tcx> { } impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> { - fn visit_binder>(&mut self, t: &Binder) -> ControlFlow<()> { + fn visit_binder>(&mut self, t: &Binder) -> ControlFlow { self.binder_index.shift_in(1); let result = t.super_visit_with(self); self.binder_index.shift_out(1); result } - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { match *t.kind() { ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => { match self.parameters.entry(bound_ty.var.as_u32()) { @@ -886,7 +886,7 @@ impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> { t.super_visit_with(self) } - fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow { match r { ty::ReLateBound(index, br) if *index == self.binder_index => match br { ty::BoundRegion::BrNamed(def_id, _name) => { @@ -1076,7 +1076,7 @@ impl PlaceholdersCollector { } impl<'tcx> TypeVisitor<'tcx> for PlaceholdersCollector { - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { match t.kind() { ty::Placeholder(p) if p.universe == self.universe_index => { self.next_ty_placeholder = self.next_ty_placeholder.max(p.name.as_usize() + 1); @@ -1088,7 +1088,7 @@ impl<'tcx> TypeVisitor<'tcx> for PlaceholdersCollector { t.super_visit_with(self) } - fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow { match r { ty::RePlaceholder(p) if p.universe == self.universe_index => { if let ty::BoundRegion::BrAnon(anon) = p.name { diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 70d94ef869d05..0e6e289c9fb90 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -450,7 +450,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( }; impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> { - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t); if t != self.opaque_identity_ty && t.super_visit_with(self).is_break() { self.ty = Some(t); @@ -459,7 +459,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( ControlFlow::CONTINUE } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { debug!("check_opaque_for_inheriting_lifetimes: (visit_region) r={:?}", r); if let RegionKind::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = r { if *index < self.generics.parent_count as u32 { @@ -472,7 +472,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( r.super_visit_with(self) } - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> { + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { if let ty::ConstKind::Unevaluated(..) = c.val { // FIXME(#72219) We currenctly don't detect lifetimes within substs // which would violate this check. Even though the particular substitution is not used @@ -1455,7 +1455,7 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) { { struct VisitTypes(Vec); impl<'tcx> ty::fold::TypeVisitor<'tcx> for VisitTypes { - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { match *t.kind() { ty::Opaque(def, _) => { self.0.push(def); diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index 247b525672603..8e69df734e6f8 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -983,7 +983,7 @@ fn suggest_constraining_param( struct TypeParamVisitor<'tcx>(Vec>); impl<'tcx> TypeVisitor<'tcx> for TypeParamVisitor<'tcx> { - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { if let ty::Param(_) = ty.kind() { self.0.push(ty); } diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 1e27357ce4414..95ad977abd1ef 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -800,18 +800,18 @@ fn check_where_clauses<'tcx, 'fcx>( params: FxHashSet, } impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams { - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { if let ty::Param(param) = t.kind() { self.params.insert(param.index); } t.super_visit_with(self) } - fn visit_region(&mut self, _: ty::Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, _: ty::Region<'tcx>) -> ControlFlow { ControlFlow::BREAK } - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> { + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { if let ty::ConstKind::Param(param) = c.val { self.params.insert(param.index); } diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index b431de9036944..7779794b9db7d 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -2062,7 +2062,7 @@ fn const_evaluatable_predicates_of<'tcx>( } impl<'a, 'tcx> TypeVisitor<'tcx> for TyAliasVisitor<'a, 'tcx> { - fn visit_const(&mut self, ct: &'tcx Const<'tcx>) -> ControlFlow<()> { + fn visit_const(&mut self, ct: &'tcx Const<'tcx>) -> ControlFlow { if let ty::ConstKind::Unevaluated(def, substs, None) = ct.val { self.preds.insert(( ty::PredicateAtom::ConstEvaluatable(def, substs).to_predicate(self.tcx), diff --git a/compiler/rustc_typeck/src/constrained_generic_params.rs b/compiler/rustc_typeck/src/constrained_generic_params.rs index bae5bde70026f..e389fd4d9f00f 100644 --- a/compiler/rustc_typeck/src/constrained_generic_params.rs +++ b/compiler/rustc_typeck/src/constrained_generic_params.rs @@ -57,7 +57,7 @@ struct ParameterCollector { } impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { match *t.kind() { ty::Projection(..) | ty::Opaque(..) if !self.include_nonconstraining => { // projections are not injective @@ -72,14 +72,14 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { t.super_visit_with(self) } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { if let ty::ReEarlyBound(data) = *r { self.parameters.push(Parameter::from(data)); } ControlFlow::CONTINUE } - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> { + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { match c.val { ty::ConstKind::Unevaluated(..) if !self.include_nonconstraining => { // Constant expressions are not injective diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs index b4a9804fb25a5..64b12980af66b 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs @@ -563,7 +563,7 @@ impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'tcx> { struct ContainsRegion; impl TypeVisitor<'_> for ContainsRegion { - fn visit_region(&mut self, _: ty::Region<'_>) -> ControlFlow<()> { + fn visit_region(&mut self, _: ty::Region<'_>) -> ControlFlow { ControlFlow::BREAK } } From 17b395d29609e9a52aeddec658ae6d57f62260cc Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Thu, 5 Nov 2020 19:11:42 +0100 Subject: [PATCH 10/27] Use `TypeVisitor::BreakTy` in `structural_match::Search` --- .../src/traits/structural_match.rs | 51 ++++++------------- 1 file changed, 15 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs index edab1e031ccab..3d20a8d5cf336 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -55,9 +55,7 @@ pub fn search_for_structural_match_violation<'tcx>( ) -> Option> { // FIXME: we should instead pass in an `infcx` from the outside. tcx.infer_ctxt().enter(|infcx| { - let mut search = Search { infcx, span, found: None, seen: FxHashSet::default() }; - ty.visit_with(&mut search); - search.found + ty.visit_with(&mut Search { infcx, span, seen: FxHashSet::default() }).break_value() }) } @@ -116,9 +114,6 @@ struct Search<'a, 'tcx> { infcx: InferCtxt<'a, 'tcx>, - /// Records first ADT that does not implement a structural-match trait. - found: Option>, - /// Tracks ADTs previously encountered during search, so that /// we will not recur on them again. seen: FxHashSet, @@ -135,38 +130,33 @@ impl Search<'a, 'tcx> { } impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { + type BreakTy = NonStructuralMatchTy<'tcx>; + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { debug!("Search visiting ty: {:?}", ty); let (adt_def, substs) = match *ty.kind() { ty::Adt(adt_def, substs) => (adt_def, substs), ty::Param(_) => { - self.found = Some(NonStructuralMatchTy::Param); - return ControlFlow::BREAK; + return ControlFlow::Break(NonStructuralMatchTy::Param); } ty::Dynamic(..) => { - self.found = Some(NonStructuralMatchTy::Dynamic); - return ControlFlow::BREAK; + return ControlFlow::Break(NonStructuralMatchTy::Dynamic); } ty::Foreign(_) => { - self.found = Some(NonStructuralMatchTy::Foreign); - return ControlFlow::BREAK; + return ControlFlow::Break(NonStructuralMatchTy::Foreign); } ty::Opaque(..) => { - self.found = Some(NonStructuralMatchTy::Opaque); - return ControlFlow::BREAK; + return ControlFlow::Break(NonStructuralMatchTy::Opaque); } ty::Projection(..) => { - self.found = Some(NonStructuralMatchTy::Projection); - return ControlFlow::BREAK; + return ControlFlow::Break(NonStructuralMatchTy::Projection); } ty::Generator(..) | ty::GeneratorWitness(..) => { - self.found = Some(NonStructuralMatchTy::Generator); - return ControlFlow::BREAK; + return ControlFlow::Break(NonStructuralMatchTy::Generator); } ty::Closure(..) => { - self.found = Some(NonStructuralMatchTy::Closure); - return ControlFlow::BREAK; + return ControlFlow::Break(NonStructuralMatchTy::Closure); } ty::RawPtr(..) => { // structural-match ignores substructure of @@ -206,8 +196,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => { // First check all contained types and then tell the caller to continue searching. - ty.super_visit_with(self); - return ControlFlow::CONTINUE; + return ty.super_visit_with(self); } ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => { bug!("unexpected type during structural-match checking: {:?}", ty); @@ -227,8 +216,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { if !self.type_marked_structural(ty) { debug!("Search found ty: {:?}", ty); - self.found = Some(NonStructuralMatchTy::Adt(&adt_def)); - return ControlFlow::BREAK; + return ControlFlow::Break(NonStructuralMatchTy::Adt(&adt_def)); } // structural-match does not care about the @@ -244,20 +232,11 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { // even though we skip super_visit_with, we must recur on // fields of ADT. let tcx = self.tcx(); - for field_ty in adt_def.all_fields().map(|field| field.ty(tcx, substs)) { + adt_def.all_fields().map(|field| field.ty(tcx, substs)).try_for_each(|field_ty| { let ty = self.tcx().normalize_erasing_regions(ty::ParamEnv::empty(), field_ty); debug!("structural-match ADT: field_ty={:?}, ty={:?}", field_ty, ty); - - if ty.visit_with(self).is_break() { - // found an ADT without structural-match; halt visiting! - assert!(self.found.is_some()); - return ControlFlow::BREAK; - } - } - - // Even though we do not want to recur on substs, we do - // want our caller to continue its own search. - ControlFlow::CONTINUE + ty.visit_with(self) + }) } } From 23feec397713918c7cd960d52348d088a32837a5 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Thu, 5 Nov 2020 19:17:30 +0100 Subject: [PATCH 11/27] Use `TypeVisitor::BreakTy` in `ProhibitOpaqueVisitor` --- compiler/rustc_typeck/src/check/check.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 0e6e289c9fb90..9755e499e29c9 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -446,15 +446,15 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( struct ProhibitOpaqueVisitor<'tcx> { opaque_identity_ty: Ty<'tcx>, generics: &'tcx ty::Generics, - ty: Option>, }; impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> { + type BreakTy = Option>; + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t); if t != self.opaque_identity_ty && t.super_visit_with(self).is_break() { - self.ty = Some(t); - return ControlFlow::BREAK; + return ControlFlow::Break(Some(t)); } ControlFlow::CONTINUE } @@ -463,7 +463,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( debug!("check_opaque_for_inheriting_lifetimes: (visit_region) r={:?}", r); if let RegionKind::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = r { if *index < self.generics.parent_count as u32 { - return ControlFlow::BREAK; + return ControlFlow::Break(None); } else { return ControlFlow::CONTINUE; } @@ -494,18 +494,17 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( InternalSubsts::identity_for_item(tcx, def_id.to_def_id()), ), generics: tcx.generics_of(def_id), - ty: None, }; let prohibit_opaque = tcx .explicit_item_bounds(def_id) .iter() - .any(|(predicate, _)| predicate.visit_with(&mut visitor).is_break()); + .try_for_each(|(predicate, _)| predicate.visit_with(&mut visitor)); debug!( "check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor={:?}", prohibit_opaque, visitor ); - if prohibit_opaque { + if let Some(ty) = prohibit_opaque.break_value() { let is_async = match item.kind { ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => match origin { hir::OpaqueTyOrigin::AsyncFn => true, @@ -525,7 +524,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) { if snippet == "Self" { - if let Some(ty) = visitor.ty { + if let Some(ty) = ty { err.span_suggestion( span, "consider spelling out the type instead", From 29b140a1c38aab78ecc1bbdd824e7117e3b81f56 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Thu, 5 Nov 2020 19:30:42 +0100 Subject: [PATCH 12/27] Use `TypeVisitor::BreakTy` in `HasTypeFlagsVisitor` --- compiler/rustc_middle/src/ty/fold.rs | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index c24cb9b4c0f2d..027d43d186a65 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -73,7 +73,7 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { } fn has_type_flags(&self, flags: TypeFlags) -> bool { - self.visit_with(&mut HasTypeFlagsVisitor { flags }).is_break() + self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags) } fn has_projections(&self) -> bool { self.has_type_flags(TypeFlags::HAS_PROJECTION) @@ -901,12 +901,17 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { } } +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +struct FoundFlags; + // FIXME: Optimize for checking for infer flags struct HasTypeFlagsVisitor { flags: ty::TypeFlags, } impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { + type BreakTy = FoundFlags; + fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow { debug!( "HasTypeFlagsVisitor: t={:?} t.flags={:?} self.flags={:?}", @@ -914,19 +919,31 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { t.flags(), self.flags ); - if t.flags().intersects(self.flags) { ControlFlow::BREAK } else { ControlFlow::CONTINUE } + if t.flags().intersects(self.flags) { + ControlFlow::Break(FoundFlags) + } else { + ControlFlow::CONTINUE + } } fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { let flags = r.type_flags(); debug!("HasTypeFlagsVisitor: r={:?} r.flags={:?} self.flags={:?}", r, flags, self.flags); - if flags.intersects(self.flags) { ControlFlow::BREAK } else { ControlFlow::CONTINUE } + if flags.intersects(self.flags) { + ControlFlow::Break(FoundFlags) + } else { + ControlFlow::CONTINUE + } } fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { let flags = FlagComputation::for_const(c); debug!("HasTypeFlagsVisitor: c={:?} c.flags={:?} self.flags={:?}", c, flags, self.flags); - if flags.intersects(self.flags) { ControlFlow::BREAK } else { ControlFlow::CONTINUE } + if flags.intersects(self.flags) { + ControlFlow::Break(FoundFlags) + } else { + ControlFlow::CONTINUE + } } fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow { @@ -935,7 +952,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { predicate, predicate.inner.flags, self.flags ); if predicate.inner.flags.intersects(self.flags) { - ControlFlow::BREAK + ControlFlow::Break(FoundFlags) } else { ControlFlow::CONTINUE } From 44f7d8fcf624b0e8aee130527092c03b4e0ba5ba Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Thu, 5 Nov 2020 19:39:48 +0100 Subject: [PATCH 13/27] Use `TypeVisitor::BreakTy` in `HasEscapingVarsVisitor` --- compiler/rustc_middle/src/ty/fold.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 027d43d186a65..57aa15f69a952 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -818,6 +818,9 @@ where value.fold_with(&mut Shifter::new(tcx, amount)) } +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +struct FoundEscapingVars; + /// An "escaping var" is a bound var whose binder is not part of `t`. A bound var can be a /// bound region or a bound type. /// @@ -849,6 +852,8 @@ struct HasEscapingVarsVisitor { } impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { + type BreakTy = FoundEscapingVars; + fn visit_binder>(&mut self, t: &Binder) -> ControlFlow { self.outer_index.shift_in(1); let result = t.super_visit_with(self); @@ -863,7 +868,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { // `outer_exclusive_binder` is always 1 higher than the // content in `t`). Therefore, `t` has some escaping vars. if t.outer_exclusive_binder > self.outer_index { - ControlFlow::BREAK + ControlFlow::Break(FoundEscapingVars) } else { ControlFlow::CONTINUE } @@ -874,7 +879,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { // of outer index, then it escapes the binders we have // visited. if r.bound_at_or_above_binder(self.outer_index) { - ControlFlow::BREAK + ControlFlow::Break(FoundEscapingVars) } else { ControlFlow::CONTINUE } @@ -887,14 +892,16 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { // const, as it has types/regions embedded in a lot of other // places. match ct.val { - ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => ControlFlow::BREAK, + ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => { + ControlFlow::Break(FoundEscapingVars) + } _ => ct.super_visit_with(self), } } fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow { if predicate.inner.outer_exclusive_binder > self.outer_index { - ControlFlow::BREAK + ControlFlow::Break(FoundEscapingVars) } else { ControlFlow::CONTINUE } From df6e87cc850a2d3a7510f1e89335dc73d34abc26 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Fri, 6 Nov 2020 18:28:41 +0100 Subject: [PATCH 14/27] Use `TypeVisitor::BreakTy` in `UnresolvedTypeFinder` --- compiler/rustc_infer/src/infer/mod.rs | 6 +----- compiler/rustc_infer/src/infer/resolve.rs | 9 +++------ 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index acded5351f80a..225582a2db6a5 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1,5 +1,3 @@ -//! See the Book for more information. - pub use self::freshen::TypeFreshener; pub use self::LateBoundRegionConversionTime::*; pub use self::RegionVariableOrigin::*; @@ -1334,9 +1332,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { where T: TypeFoldable<'tcx>, { - let mut r = resolve::UnresolvedTypeFinder::new(self); - value.visit_with(&mut r); - r.first_unresolved + value.visit_with(&mut resolve::UnresolvedTypeFinder::new(self)).break_value() } pub fn probe_const_var( diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index e2531dc7ad9d6..822fa77aa0ed0 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -111,18 +111,16 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticRegionResolver<'a, 'tcx> { /// involve some hashing and so forth). pub struct UnresolvedTypeFinder<'a, 'tcx> { infcx: &'a InferCtxt<'a, 'tcx>, - - /// Used to find the type parameter name and location for error reporting. - pub first_unresolved: Option<(Ty<'tcx>, Option)>, } impl<'a, 'tcx> UnresolvedTypeFinder<'a, 'tcx> { pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self { - UnresolvedTypeFinder { infcx, first_unresolved: None } + UnresolvedTypeFinder { infcx } } } impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> { + type BreakTy = (Ty<'tcx>, Option); fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { let t = self.infcx.shallow_resolve(t); if t.has_infer_types() { @@ -144,8 +142,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> { } else { None }; - self.first_unresolved = Some((t, ty_var_span)); - ControlFlow::BREAK + ControlFlow::Break((t, ty_var_span)) } else { // Otherwise, visit its contents. t.super_visit_with(self) From 65cdc21f06fba564d161db9d49f07dfe867f741e Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Sat, 14 Nov 2020 21:46:39 +0100 Subject: [PATCH 15/27] Set the default `BreakTy` to `!` --- compiler/rustc_lint/src/types.rs | 2 ++ compiler/rustc_middle/src/ty/fold.rs | 5 ++++- compiler/rustc_mir/src/interpret/util.rs | 2 ++ compiler/rustc_mir/src/monomorphize/polymorphize.rs | 2 ++ compiler/rustc_trait_selection/src/traits/object_safety.rs | 2 ++ compiler/rustc_typeck/src/check/wfcheck.rs | 2 ++ src/tools/clippy/clippy_lints/src/redundant_clone.rs | 2 ++ 7 files changed, 16 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 802fb1970cd7e..1607b53d10cbe 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1135,6 +1135,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { }; impl<'a, 'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> { + type BreakTy = (); + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { match ty.kind() { ty::Opaque(..) => { diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 57aa15f69a952..605bdbcc0d2fc 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -148,6 +148,7 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { pub struct Visitor(F); impl<'tcx, F: FnMut(Ty<'tcx>) -> ControlFlow<()>> TypeVisitor<'tcx> for Visitor { + type BreakTy = (); fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { self.0(ty) } @@ -195,7 +196,7 @@ pub trait TypeFolder<'tcx>: Sized { } pub trait TypeVisitor<'tcx>: Sized { - type BreakTy = (); + type BreakTy = !; fn visit_binder>(&mut self, t: &Binder) -> ControlFlow { t.super_visit_with(self) @@ -331,6 +332,8 @@ impl<'tcx> TyCtxt<'tcx> { where F: FnMut(ty::Region<'tcx>) -> bool, { + type BreakTy = (); + fn visit_binder>( &mut self, t: &Binder, diff --git a/compiler/rustc_mir/src/interpret/util.rs b/compiler/rustc_mir/src/interpret/util.rs index f7fca4822ef54..e49b1c9f64d44 100644 --- a/compiler/rustc_mir/src/interpret/util.rs +++ b/compiler/rustc_mir/src/interpret/util.rs @@ -18,6 +18,8 @@ where }; impl<'tcx> TypeVisitor<'tcx> for UsedParamsNeedSubstVisitor<'tcx> { + type BreakTy = (); + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { if !c.needs_subst() { return ControlFlow::CONTINUE; diff --git a/compiler/rustc_mir/src/monomorphize/polymorphize.rs b/compiler/rustc_mir/src/monomorphize/polymorphize.rs index 6a50a9243781e..0ce1c5a04893b 100644 --- a/compiler/rustc_mir/src/monomorphize/polymorphize.rs +++ b/compiler/rustc_mir/src/monomorphize/polymorphize.rs @@ -318,6 +318,8 @@ struct HasUsedGenericParams<'a> { } impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> { + type BreakTy = (); + fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow { debug!("visit_const: c={:?}", c); if !c.has_param_types_or_consts() { diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 7da5ec051cb6a..97253da051c41 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -771,6 +771,8 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( } impl<'tcx> TypeVisitor<'tcx> for IllegalSelfTypeVisitor<'tcx> { + type BreakTy = (); + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { match t.kind() { ty::Param(_) => { diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 95ad977abd1ef..7d58f2cf34c0d 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -800,6 +800,8 @@ fn check_where_clauses<'tcx, 'fcx>( params: FxHashSet, } impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams { + type BreakTy = (); + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { if let ty::Param(param) = t.kind() { self.params.insert(param.index); diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs index 64b12980af66b..602facbe062ac 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs @@ -563,6 +563,8 @@ impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'tcx> { struct ContainsRegion; impl TypeVisitor<'_> for ContainsRegion { + type BreakTy = (); + fn visit_region(&mut self, _: ty::Region<'_>) -> ControlFlow { ControlFlow::BREAK } From 07b37cf791c69c5359a058402495fe45d4657f66 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Sat, 14 Nov 2020 22:16:16 +0100 Subject: [PATCH 16/27] Use `TypeVisitor::BreakTy` in `ProhibitOpaqueTypes` --- compiler/rustc_lint/src/types.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 1607b53d10cbe..aaedd53c0f611 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1131,18 +1131,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool { struct ProhibitOpaqueTypes<'a, 'tcx> { cx: &'a LateContext<'tcx>, - ty: Option>, }; impl<'a, 'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> { - type BreakTy = (); + type BreakTy = Ty<'tcx>; fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { match ty.kind() { - ty::Opaque(..) => { - self.ty = Some(ty); - ControlFlow::BREAK - } + ty::Opaque(..) => ControlFlow::Break(ty), // Consider opaque types within projections FFI-safe if they do not normalize // to more opaque types. ty::Projection(..) => { @@ -1161,9 +1157,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } } - let mut visitor = ProhibitOpaqueTypes { cx: self.cx, ty: None }; - ty.visit_with(&mut visitor); - if let Some(ty) = visitor.ty { + if let Some(ty) = ty.visit_with(&mut ProhibitOpaqueTypes { cx: self.cx }).break_value() { self.emit_ffi_unsafe_type_lint(ty, sp, "opaque types have no C equivalent", None); true } else { From 75658091631afe5a8b805a340a43bef4c00def11 Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Sun, 15 Nov 2020 09:35:04 +1000 Subject: [PATCH 17/27] add a canary test for complex repr(simd) --- compiler/rustc_middle/src/ty/sty.rs | 8 ++++- src/test/ui/simd/simd-array-trait.rs | 40 ++++++++++++++++++++++++ src/test/ui/simd/simd-array-trait.stderr | 10 ++++++ 3 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/simd/simd-array-trait.rs create mode 100644 src/test/ui/simd/simd-array-trait.stderr diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index d1f83d0a83e0e..5d57ed9e2f832 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1966,7 +1966,13 @@ impl<'tcx> TyS<'tcx> { let f0_ty = variant.fields[0].ty(tcx, substs); match f0_ty.kind() { - Array(f0_elem_ty, f0_len) => (f0_len.eval_usize(tcx, ParamEnv::empty()) as u64, f0_elem_ty), + Array(f0_elem_ty, f0_len) => { + // FIXME(repr_simd): https://github.com/rust-lang/rust/pull/78863#discussion_r522784112 + // The way we evaluate the `N` in `[T; N]` here only works since we use + // `simd_size_and_type` post-monomorphization. It will probably start to ICE + // if we use it in generic code. See the `simd-array-trait` ui test. + (f0_len.eval_usize(tcx, ParamEnv::empty()) as u64, f0_elem_ty) + } _ => (variant.fields.len() as u64, f0_ty), } } diff --git a/src/test/ui/simd/simd-array-trait.rs b/src/test/ui/simd/simd-array-trait.rs new file mode 100644 index 0000000000000..6219e7ca83b16 --- /dev/null +++ b/src/test/ui/simd/simd-array-trait.rs @@ -0,0 +1,40 @@ +// Figuring out the size of a vector type that depends on traits doesn't ICE + +#![allow(dead_code)] + +// pretty-expanded FIXME #23616 + +#![feature(repr_simd, platform_intrinsics, const_generics)] +#![allow(non_camel_case_types, incomplete_features)] + +pub trait Simd { + type Lane: Clone + Copy; + const SIZE: usize; +} + +pub struct i32x4; +impl Simd for i32x4 { + type Lane = i32; + const SIZE: usize = 4; +} + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct T([S::Lane; S::SIZE]); //~ ERROR constant expression depends on a generic parameter + +extern "platform-intrinsic" { + fn simd_insert(x: T, idx: u32, y: E) -> T; + fn simd_extract(x: T, idx: u32) -> E; +} + +pub fn main() { + let mut t = T::([0; 4]); + unsafe { + for i in 0_i32..4 { + t = simd_insert(t, i as u32, i); + } + for i in 0_i32..4 { + assert_eq!(i, simd_extract(t, i as u32)); + } + } +} diff --git a/src/test/ui/simd/simd-array-trait.stderr b/src/test/ui/simd/simd-array-trait.stderr new file mode 100644 index 0000000000000..c100e020c5490 --- /dev/null +++ b/src/test/ui/simd/simd-array-trait.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/simd-array-trait.rs:23:23 + | +LL | pub struct T([S::Lane; S::SIZE]); + | ^^^^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + From f27d56d1ff2fdbb86cb1fc86fb06bf32f009ada0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Sun, 15 Nov 2020 00:00:00 +0000 Subject: [PATCH 18/27] Limit storage duration of inlined always live locals --- compiler/rustc_middle/src/mir/mod.rs | 4 +- compiler/rustc_mir/src/transform/inline.rs | 39 +++++++++++++++++++ .../inline/inline_diverging.h.Inline.diff | 1 + .../inline/inline_generator.main.Inline.diff | 4 ++ .../inline/inline_shims.drop.Inline.diff | 4 ++ src/test/ui/mir/auxiliary/issue_76375_aux.rs | 10 ++++- src/test/ui/mir/issue-76375.rs | 16 +++++++- 7 files changed, 73 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 5fe7b0f647dcd..454cdad2e6a78 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -420,7 +420,9 @@ impl<'tcx> Body<'tcx> { /// Returns an iterator over all user-defined variables and compiler-generated temporaries (all /// locals that are neither arguments nor the return place). #[inline] - pub fn vars_and_temps_iter(&self) -> impl Iterator + ExactSizeIterator { + pub fn vars_and_temps_iter( + &self, + ) -> impl DoubleEndedIterator + ExactSizeIterator { let arg_count = self.arg_count; let local_count = self.local_decls.len(); (arg_count + 1..local_count).map(Local::new) diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs index aae98f5b6d8d6..220fc06da8610 100644 --- a/compiler/rustc_mir/src/transform/inline.rs +++ b/compiler/rustc_mir/src/transform/inline.rs @@ -459,6 +459,7 @@ impl Inliner<'tcx> { tcx: self.tcx, callsite_span: callsite.source_info.span, body_span: callee_body.span, + always_live_locals: BitSet::new_filled(callee_body.local_decls.len()), }; // Map all `Local`s, `SourceScope`s and `BasicBlock`s to new ones @@ -490,6 +491,34 @@ impl Inliner<'tcx> { } } + // If there are any locals without storage markers, give them storage only for the + // duration of the call. + for local in callee_body.vars_and_temps_iter() { + if integrator.always_live_locals.contains(local) { + let new_local = integrator.map_local(local); + caller_body[callsite.block].statements.push(Statement { + source_info: callsite.source_info, + kind: StatementKind::StorageLive(new_local), + }); + } + } + if let Some(block) = callsite.target { + // To avoid repeated O(n) insert, push any new statements to the end and rotate + // the slice once. + let mut n = 0; + for local in callee_body.vars_and_temps_iter().rev() { + if integrator.always_live_locals.contains(local) { + let new_local = integrator.map_local(local); + caller_body[block].statements.push(Statement { + source_info: callsite.source_info, + kind: StatementKind::StorageDead(new_local), + }); + n += 1; + } + } + caller_body[block].statements.rotate_right(n); + } + // Insert all of the (mapped) parts of the callee body into the caller. caller_body.local_decls.extend( // FIXME(eddyb) make `Range` iterable so that we can use @@ -670,6 +699,7 @@ struct Integrator<'a, 'tcx> { tcx: TyCtxt<'tcx>, callsite_span: Span, body_span: Span, + always_live_locals: BitSet, } impl<'a, 'tcx> Integrator<'a, 'tcx> { @@ -759,6 +789,15 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { } } + fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) { + if let StatementKind::StorageLive(local) | StatementKind::StorageDead(local) = + statement.kind + { + self.always_live_locals.remove(local); + } + self.super_statement(statement, location); + } + fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, loc: Location) { // Don't try to modify the implicit `_0` access on return (`return` terminators are // replaced down below anyways). diff --git a/src/test/mir-opt/inline/inline_diverging.h.Inline.diff b/src/test/mir-opt/inline/inline_diverging.h.Inline.diff index b728ad4b42899..07994eb3c1661 100644 --- a/src/test/mir-opt/inline/inline_diverging.h.Inline.diff +++ b/src/test/mir-opt/inline/inline_diverging.h.Inline.diff @@ -40,6 +40,7 @@ - // mir::Constant // + span: $DIR/inline-diverging.rs:22:16: 22:21 // + literal: Const { ty: fn() -> ! {sleep}, val: Value(Scalar()) } ++ StorageLive(_6); // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 + StorageLive(_3); // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 + StorageLive(_4); // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 + _4 = &_2; // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 diff --git a/src/test/mir-opt/inline/inline_generator.main.Inline.diff b/src/test/mir-opt/inline/inline_generator.main.Inline.diff index aa32daa82dd51..99497a6fc791c 100644 --- a/src/test/mir-opt/inline/inline_generator.main.Inline.diff +++ b/src/test/mir-opt/inline/inline_generator.main.Inline.diff @@ -65,12 +65,16 @@ - // + literal: Const { ty: for<'r> fn(std::pin::Pin<&'r mut impl std::ops::Generator>, bool) -> std::ops::GeneratorState< as std::ops::Generator>::Yield, as std::ops::Generator>::Return> { as std::ops::Generator>::resume}, val: Value(Scalar()) } + StorageLive(_7); // scope 0 at $DIR/inline-generator.rs:9:14: 9:46 + _7 = const false; // scope 0 at $DIR/inline-generator.rs:9:14: 9:46 ++ StorageLive(_8); // scope 0 at $DIR/inline-generator.rs:9:14: 9:46 ++ StorageLive(_9); // scope 0 at $DIR/inline-generator.rs:9:14: 9:46 + _9 = discriminant((*(_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41 {bool, i32}]))); // scope 6 at $DIR/inline-generator.rs:9:14: 9:46 + switchInt(move _9) -> [0_u32: bb3, 1_u32: bb8, 3_u32: bb7, otherwise: bb9]; // scope 6 at $DIR/inline-generator.rs:9:14: 9:46 } - bb3: { + bb1: { ++ StorageDead(_9); // scope 0 at $DIR/inline-generator.rs:9:14: 9:46 ++ StorageDead(_8); // scope 0 at $DIR/inline-generator.rs:9:14: 9:46 + StorageDead(_7); // scope 0 at $DIR/inline-generator.rs:9:14: 9:46 StorageDead(_2); // scope 0 at $DIR/inline-generator.rs:9:45: 9:46 StorageDead(_4); // scope 0 at $DIR/inline-generator.rs:9:46: 9:47 diff --git a/src/test/mir-opt/inline/inline_shims.drop.Inline.diff b/src/test/mir-opt/inline/inline_shims.drop.Inline.diff index 503d8bc6b7a68..092ff42c3b66d 100644 --- a/src/test/mir-opt/inline/inline_shims.drop.Inline.diff +++ b/src/test/mir-opt/inline/inline_shims.drop.Inline.diff @@ -36,11 +36,15 @@ - // mir::Constant - // + span: $DIR/inline-shims.rs:12:14: 12:37 - // + literal: Const { ty: unsafe fn(*mut std::option::Option) {std::intrinsics::drop_in_place::>}, val: Value(Scalar()) } ++ StorageLive(_6); // scope 2 at $DIR/inline-shims.rs:12:14: 12:40 ++ StorageLive(_7); // scope 2 at $DIR/inline-shims.rs:12:14: 12:40 + _6 = discriminant((*_5)); // scope 3 at $DIR/inline-shims.rs:12:14: 12:40 + switchInt(move _6) -> [0_isize: bb2, otherwise: bb3]; // scope 3 at $DIR/inline-shims.rs:12:14: 12:40 } bb2: { ++ StorageDead(_7); // scope 2 at $DIR/inline-shims.rs:12:14: 12:40 ++ StorageDead(_6); // scope 2 at $DIR/inline-shims.rs:12:14: 12:40 StorageDead(_5); // scope 2 at $DIR/inline-shims.rs:12:39: 12:40 return; // scope 0 at $DIR/inline-shims.rs:13:2: 13:2 + } diff --git a/src/test/ui/mir/auxiliary/issue_76375_aux.rs b/src/test/ui/mir/auxiliary/issue_76375_aux.rs index f8b318d58ba2a..72f32ecf7ea22 100644 --- a/src/test/ui/mir/auxiliary/issue_76375_aux.rs +++ b/src/test/ui/mir/auxiliary/issue_76375_aux.rs @@ -1,8 +1,8 @@ // edition:2018 -// compile-flags: -Z mir-opt-level=2 -Z unsound-mir-opts +// compile-flags: -Z mir-opt-level=2 #[inline(always)] -pub fn f(s: bool) -> String { +pub fn copy_prop(s: bool) -> String { let a = "Hello world!".to_string(); let b = a; let c = b; @@ -12,3 +12,9 @@ pub fn f(s: bool) -> String { String::new() } } + +#[inline(always)] +pub fn dest_prop(x: &[u8]) -> &[u8] { + let y = &x[..x.len()]; + y +} diff --git a/src/test/ui/mir/issue-76375.rs b/src/test/ui/mir/issue-76375.rs index ef459f6a28ec8..a7772cb1fe68d 100644 --- a/src/test/ui/mir/issue-76375.rs +++ b/src/test/ui/mir/issue-76375.rs @@ -1,6 +1,8 @@ +// Regression test for issue #76375. +// // edition:2018 // build-pass -// compile-flags: -Z mir-opt-level=2 -L. +// compile-flags: -Z mir-opt-level=2 // aux-build:issue_76375_aux.rs #![crate_type = "lib"] @@ -8,8 +10,18 @@ extern crate issue_76375_aux; pub async fn g() { - issue_76375_aux::f(true); + issue_76375_aux::copy_prop(true); h().await; } +pub async fn u() { + let b = [0u8; 32]; + let mut i = 0; + while i != 10 { + issue_76375_aux::dest_prop(&b); + h().await; + i += 1; + } +} + pub async fn h() {} From e217fc4a06ad7b5cb39877c0dae028f9f01839e3 Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Sun, 15 Nov 2020 18:03:42 +1000 Subject: [PATCH 19/27] fix up tidy --- src/test/ui/simd/simd-array-trait.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/ui/simd/simd-array-trait.rs b/src/test/ui/simd/simd-array-trait.rs index 6219e7ca83b16..d6ed5f61a000e 100644 --- a/src/test/ui/simd/simd-array-trait.rs +++ b/src/test/ui/simd/simd-array-trait.rs @@ -20,7 +20,8 @@ impl Simd for i32x4 { #[repr(simd)] #[derive(Copy, Clone)] -pub struct T([S::Lane; S::SIZE]); //~ ERROR constant expression depends on a generic parameter +pub struct T([S::Lane; S::SIZE]); +//~^ ERROR constant expression depends on a generic parameter extern "platform-intrinsic" { fn simd_insert(x: T, idx: u32, y: E) -> T; From 43bfbb10bf52d1cf6bd90ae2e19bcd357d38be4d Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 12 Nov 2020 21:46:54 +0100 Subject: [PATCH 20/27] Add column number support to Backtrace Backtrace frames might include column numbers. Print them if they are included. --- library/std/src/backtrace.rs | 11 +++++++++-- library/std/src/backtrace/tests.rs | 4 ++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs index a9d8a4e2a81c1..7e8e0a621e31c 100644 --- a/library/std/src/backtrace.rs +++ b/library/std/src/backtrace.rs @@ -161,6 +161,7 @@ struct BacktraceSymbol { name: Option>, filename: Option, lineno: Option, + colno: Option, } enum BytesOrWide { @@ -197,6 +198,10 @@ impl fmt::Debug for Backtrace { impl fmt::Debug for BacktraceSymbol { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + // FIXME: improve formatting: https://github.com/rust-lang/rust/issues/65280 + // FIXME: Also, include column numbers into the debug format as Display already has them. + // Until there are stable per-frame accessors, the format shouldn't be changed: + // https://github.com/rust-lang/rust/issues/65280#issuecomment-638966585 write!(fmt, "{{ ")?; if let Some(fn_name) = self.name.as_ref().map(|b| backtrace_rs::SymbolName::new(b)) { @@ -209,7 +214,7 @@ impl fmt::Debug for BacktraceSymbol { write!(fmt, ", file: \"{:?}\"", fname)?; } - if let Some(line) = self.lineno.as_ref() { + if let Some(line) = self.lineno { write!(fmt, ", line: {:?}", line)?; } @@ -381,7 +386,7 @@ impl fmt::Display for Backtrace { f.print_raw(frame.frame.ip(), None, None, None)?; } else { for symbol in frame.symbols.iter() { - f.print_raw( + f.print_raw_with_column( frame.frame.ip(), symbol.name.as_ref().map(|b| backtrace_rs::SymbolName::new(b)), symbol.filename.as_ref().map(|b| match b { @@ -389,6 +394,7 @@ impl fmt::Display for Backtrace { BytesOrWide::Wide(w) => BytesOrWideString::Wide(w), }), symbol.lineno, + symbol.colno, )?; } } @@ -427,6 +433,7 @@ impl Capture { BytesOrWideString::Wide(b) => BytesOrWide::Wide(b.to_owned()), }), lineno: symbol.lineno(), + colno: symbol.colno(), }); }); } diff --git a/library/std/src/backtrace/tests.rs b/library/std/src/backtrace/tests.rs index 287359cd545e3..f5f74d1eb9ae6 100644 --- a/library/std/src/backtrace/tests.rs +++ b/library/std/src/backtrace/tests.rs @@ -13,6 +13,7 @@ fn test_debug() { name: Some(b"std::backtrace::Backtrace::create".to_vec()), filename: Some(BytesOrWide::Bytes(b"rust/backtrace.rs".to_vec())), lineno: Some(100), + colno: None, }], }, BacktraceFrame { @@ -21,6 +22,7 @@ fn test_debug() { name: Some(b"__rust_maybe_catch_panic".to_vec()), filename: None, lineno: None, + colno: None, }], }, BacktraceFrame { @@ -30,11 +32,13 @@ fn test_debug() { name: Some(b"std::rt::lang_start_internal".to_vec()), filename: Some(BytesOrWide::Bytes(b"rust/rt.rs".to_vec())), lineno: Some(300), + colno: Some(5), }, BacktraceSymbol { name: Some(b"std::rt::lang_start".to_vec()), filename: Some(BytesOrWide::Bytes(b"rust/rt.rs".to_vec())), lineno: Some(400), + colno: None, }, ], }, From f6e6a15f076360e70b6dafa3414d62374c372ad7 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Sun, 15 Nov 2020 14:45:41 +0100 Subject: [PATCH 21/27] Remove dead `TypeFoldable::visit_tys_shallow` method --- compiler/rustc_middle/src/ty/fold.rs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 605bdbcc0d2fc..b1bfcf4491ad8 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -142,20 +142,6 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { fn still_further_specializable(&self) -> bool { self.has_type_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE) } - - /// A visitor that does not recurse into types, works like `fn walk_shallow` in `Ty`. - fn visit_tys_shallow(&self, visit: impl FnMut(Ty<'tcx>) -> ControlFlow<()>) -> ControlFlow<()> { - pub struct Visitor(F); - - impl<'tcx, F: FnMut(Ty<'tcx>) -> ControlFlow<()>> TypeVisitor<'tcx> for Visitor { - type BreakTy = (); - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { - self.0(ty) - } - } - - self.visit_with(&mut Visitor(visit)) - } } impl TypeFoldable<'tcx> for hir::Constness { From 1861a38ca9040c36741fb51f9b22f65228722b13 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 14 Oct 2020 17:02:04 +0200 Subject: [PATCH 22/27] Ensure that the source code display is working with DOS backline --- src/librustdoc/html/highlight.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 4769edc50ff07..986337336540a 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -21,6 +21,8 @@ pub fn render_with_highlighting( playground_button: Option<&str>, tooltip: Option<(&str, &str)>, ) -> String { + // This replace allows to fix how the code source with DOS backline characters is displayed. + let src = src.replace("\r\n", "\n"); debug!("highlighting: ================\n{}\n==============", src); let mut out = String::with_capacity(src.len()); if let Some((tooltip, class)) = tooltip { From af869c2f8dea8efb2a2d10a44d200cb769b4956c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 15 Nov 2020 18:40:49 +0100 Subject: [PATCH 23/27] document that __rust_alloc is also magic to our LLVM fork --- library/alloc/src/alloc.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 0a4f88dedbb07..3427c83a18f2a 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -23,6 +23,8 @@ extern "Rust" { // (the code expanding that attribute macro generates those functions), or to call // the default implementations in libstd (`__rdl_alloc` etc. in `library/std/src/alloc.rs`) // otherwise. + // The rustc fork of LLVM also special-cases these function names to be able to optimize them + // like `malloc`, `realloc`, and `free`, respectively. #[rustc_allocator] #[rustc_allocator_nounwind] fn __rust_alloc(size: usize, align: usize) -> *mut u8; From 0c52044528580fb5b02eb0dca7bbbe3e584d6b13 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 15 Nov 2020 20:51:25 +0100 Subject: [PATCH 24/27] Add test to ensure that no DOS backline (\r\n) doesn't create extra backline in source rendering --- src/librustdoc/html/highlight.rs | 6 ++-- .../html/highlight/fixtures/dos_line.html | 3 ++ src/librustdoc/html/highlight/tests.rs | 32 ++++++++++++------- 3 files changed, 27 insertions(+), 14 deletions(-) create mode 100644 src/librustdoc/html/highlight/fixtures/dos_line.html diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 986337336540a..b5fe593dc0105 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -21,8 +21,6 @@ pub fn render_with_highlighting( playground_button: Option<&str>, tooltip: Option<(&str, &str)>, ) -> String { - // This replace allows to fix how the code source with DOS backline characters is displayed. - let src = src.replace("\r\n", "\n"); debug!("highlighting: ================\n{}\n==============", src); let mut out = String::with_capacity(src.len()); if let Some((tooltip, class)) = tooltip { @@ -48,7 +46,9 @@ fn write_header(out: &mut String, class: Option<&str>) { } fn write_code(out: &mut String, src: &str) { - Classifier::new(src).highlight(&mut |highlight| { + // This replace allows to fix how the code source with DOS backline characters is displayed. + let src = src.replace("\r\n", "\n"); + Classifier::new(&src).highlight(&mut |highlight| { match highlight { Highlight::Token { text, class } => string(out, Escape(text), class), Highlight::EnterSpan { class } => enter_span(out, class), diff --git a/src/librustdoc/html/highlight/fixtures/dos_line.html b/src/librustdoc/html/highlight/fixtures/dos_line.html new file mode 100644 index 0000000000000..4400f85681d8a --- /dev/null +++ b/src/librustdoc/html/highlight/fixtures/dos_line.html @@ -0,0 +1,3 @@ +pub fn foo() { +println!("foo"); +} diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs index c79471b1fae6b..f57f52d6f0875 100644 --- a/src/librustdoc/html/highlight/tests.rs +++ b/src/librustdoc/html/highlight/tests.rs @@ -1,17 +1,6 @@ use super::write_code; use expect_test::expect_file; -#[test] -fn test_html_highlighting() { - let src = include_str!("fixtures/sample.rs"); - let html = { - let mut out = String::new(); - write_code(&mut out, src); - format!("{}
{}
\n", STYLE, out) - }; - expect_file!["fixtures/sample.html"].assert_eq(&html); -} - const STYLE: &str = r#" "#; + +#[test] +fn test_html_highlighting() { + let src = include_str!("fixtures/sample.rs"); + let html = { + let mut out = String::new(); + write_code(&mut out, src); + format!("{}
{}
\n", STYLE, out) + }; + expect_file!["fixtures/sample.html"].assert_eq(&html); +} + +#[test] +fn test_dos_backline() { + let src = "pub fn foo() {\r\n\ + println!(\"foo\");\r\n\ +}\r\n"; + let mut html = String::new(); + write_code(&mut html, src); + expect_file!["fixtures/dos_line.html"].assert_eq(&html); +} From 7986bb8c463ea6c61788983e4016243bef97acdc Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 16 Nov 2020 15:31:35 +0100 Subject: [PATCH 25/27] Don't warn about invalid HTML tags in code blocks --- src/librustdoc/passes/html_tags.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/passes/html_tags.rs b/src/librustdoc/passes/html_tags.rs index 26b64b4905ea7..bfe53d63960b1 100644 --- a/src/librustdoc/passes/html_tags.rs +++ b/src/librustdoc/passes/html_tags.rs @@ -4,7 +4,7 @@ use crate::core::DocContext; use crate::fold::DocFolder; use crate::html::markdown::opts; use core::ops::Range; -use pulldown_cmark::{Event, Parser}; +use pulldown_cmark::{Event, Parser, Tag}; use rustc_session::lint; use std::iter::Peekable; use std::str::CharIndices; @@ -196,14 +196,17 @@ impl<'a, 'tcx> DocFolder for InvalidHtmlTagsLinter<'a, 'tcx> { let mut tags = Vec::new(); let mut is_in_comment = None; + let mut in_code_block = false; let p = Parser::new_ext(&dox, opts()).into_offset_iter(); for (event, range) in p { match event { - Event::Html(text) | Event::Text(text) => { + Event::Start(Tag::CodeBlock(_)) => in_code_block = true, + Event::Html(text) | Event::Text(text) if !in_code_block => { extract_tags(&mut tags, &text, range, &mut is_in_comment, &report_diag) } + Event::End(Tag::CodeBlock(_)) => in_code_block = false, _ => {} } } From bbd302bab469a1da3804a4b998817ccbf15c874e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 16 Nov 2020 15:32:26 +0100 Subject: [PATCH 26/27] Add test to ensure that "invalid HTML tag" lint isn't fired in code blocks --- src/test/rustdoc-ui/invalid-html-tags.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/test/rustdoc-ui/invalid-html-tags.rs b/src/test/rustdoc-ui/invalid-html-tags.rs index 56ca7e79d4358..9c2fc4beb5eb1 100644 --- a/src/test/rustdoc-ui/invalid-html-tags.rs +++ b/src/test/rustdoc-ui/invalid-html-tags.rs @@ -87,3 +87,24 @@ pub fn h() {} ///