From e5901641755dfd2e758c7e855b82ee0bcd8b29c0 Mon Sep 17 00:00:00 2001 From: msizanoen1 Date: Tue, 21 Jan 2020 21:52:19 +0700 Subject: [PATCH 01/17] Implement proper C ABI lowering for RISC-V --- src/librustc/ty/layout.rs | 1 + src/librustc_target/abi/call/mod.rs | 10 +- src/librustc_target/abi/call/riscv.rs | 335 +++++++++++++++++++++++++- 3 files changed, 331 insertions(+), 15 deletions(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index bda42db40b0ae..c70473b667ea9 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -2650,6 +2650,7 @@ where .map(|(i, ty)| arg_of(ty, Some(i))) .collect(), c_variadic: sig.c_variadic, + fixed_count: inputs.len(), conv, }; fn_abi.adjust_for_abi(cx, sig.abi); diff --git a/src/librustc_target/abi/call/mod.rs b/src/librustc_target/abi/call/mod.rs index af82f9e318371..175eb93e4e55f 100644 --- a/src/librustc_target/abi/call/mod.rs +++ b/src/librustc_target/abi/call/mod.rs @@ -120,6 +120,7 @@ impl Reg { reg_ctor!(i16, Integer, 16); reg_ctor!(i32, Integer, 32); reg_ctor!(i64, Integer, 64); + reg_ctor!(i128, Integer, 128); reg_ctor!(f32, Float, 32); reg_ctor!(f64, Float, 64); @@ -493,6 +494,12 @@ pub struct FnAbi<'a, Ty> { pub c_variadic: bool, + /// The count of non-variadic arguments. + /// + /// Should only be different from args.len() when c_variadic is true. + /// This can be used to know wether an argument is variadic or not. + pub fixed_count: usize, + pub conv: Conv, } @@ -534,8 +541,7 @@ impl<'a, Ty> FnAbi<'a, Ty> { "nvptx" => nvptx::compute_abi_info(self), "nvptx64" => nvptx64::compute_abi_info(self), "hexagon" => hexagon::compute_abi_info(self), - "riscv32" => riscv::compute_abi_info(self, 32), - "riscv64" => riscv::compute_abi_info(self, 64), + "riscv32" | "riscv64" => riscv::compute_abi_info(cx, self), "wasm32" if cx.target_spec().target_os != "emscripten" => { wasm32_bindgen_compat::compute_abi_info(self) } diff --git a/src/librustc_target/abi/call/riscv.rs b/src/librustc_target/abi/call/riscv.rs index 095e5aff74422..11d6c4d819107 100644 --- a/src/librustc_target/abi/call/riscv.rs +++ b/src/librustc_target/abi/call/riscv.rs @@ -1,49 +1,358 @@ // Reference: RISC-V ELF psABI specification // https://github.com/riscv/riscv-elf-psabi-doc +// +// Reference: Clang RISC-V ELF psABI lowering code +// https://github.com/llvm/llvm-project/blob/8e780252a7284be45cf1ba224cabd884847e8e92/clang/lib/CodeGen/TargetInfo.cpp#L9311-L9773 -use crate::abi::call::{ArgAbi, FnAbi}; +use crate::abi::call::{ArgAbi, ArgAttribute, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform}; +use crate::abi::{ + self, Abi, FieldPlacement, HasDataLayout, LayoutOf, Size, TyLayout, TyLayoutMethods, +}; +use crate::spec::HasTargetSpec; + +#[derive(Copy, Clone)] +enum RegPassKind { + Float(Reg), + Integer(Reg), + Unknown, +} + +#[derive(Copy, Clone)] +enum FloatConv { + FloatPair(Reg, Reg), + Float(Reg), + MixedPair(Reg, Reg), +} + +#[derive(Copy, Clone)] +struct CannotUseFpConv; + +fn is_riscv_aggregate<'a, Ty>(arg: &ArgAbi<'a, Ty>) -> bool { + match arg.layout.abi { + Abi::Vector { .. } => true, + _ => arg.layout.is_aggregate(), + } +} + +fn should_use_fp_conv_helper<'a, Ty, C>( + cx: &C, + arg_layout: &TyLayout<'a, Ty>, + xlen: u64, + flen: u64, + field1_kind: &mut RegPassKind, + field2_kind: &mut RegPassKind, +) -> Result<(), CannotUseFpConv> +where + Ty: TyLayoutMethods<'a, C> + Copy, + C: LayoutOf>, +{ + match arg_layout.abi { + Abi::Scalar(ref scalar) => match scalar.value { + abi::Int(..) | abi::Pointer => { + if arg_layout.size.bits() > xlen { + return Err(CannotUseFpConv); + } + match (*field1_kind, *field2_kind) { + (RegPassKind::Unknown, _) => { + *field1_kind = RegPassKind::Integer(Reg { + kind: RegKind::Integer, + size: arg_layout.size, + }); + } + (RegPassKind::Float(_), RegPassKind::Unknown) => { + *field2_kind = RegPassKind::Integer(Reg { + kind: RegKind::Integer, + size: arg_layout.size, + }); + } + _ => return Err(CannotUseFpConv), + } + } + abi::F32 | abi::F64 => { + if arg_layout.size.bits() > flen { + return Err(CannotUseFpConv); + } + match (*field1_kind, *field2_kind) { + (RegPassKind::Unknown, _) => { + *field1_kind = + RegPassKind::Float(Reg { kind: RegKind::Float, size: arg_layout.size }); + } + (_, RegPassKind::Unknown) => { + *field2_kind = + RegPassKind::Float(Reg { kind: RegKind::Float, size: arg_layout.size }); + } + _ => return Err(CannotUseFpConv), + } + } + }, + Abi::Vector { .. } | Abi::Uninhabited => return Err(CannotUseFpConv), + Abi::ScalarPair(..) | Abi::Aggregate { .. } => match arg_layout.fields { + FieldPlacement::Union(_) => { + if !arg_layout.is_zst() { + return Err(CannotUseFpConv); + } + } + FieldPlacement::Array { count, .. } => { + for _ in 0..count { + let elem_layout = arg_layout.field(cx, 0); + should_use_fp_conv_helper( + cx, + &elem_layout, + xlen, + flen, + field1_kind, + field2_kind, + )?; + } + } + FieldPlacement::Arbitrary { .. } => { + match arg_layout.variants { + abi::Variants::Multiple { .. } => return Err(CannotUseFpConv), + abi::Variants::Single { .. } => (), + } + for i in arg_layout.fields.index_by_increasing_offset() { + let field = arg_layout.field(cx, i); + should_use_fp_conv_helper(cx, &field, xlen, flen, field1_kind, field2_kind)?; + } + } + }, + } + Ok(()) +} + +fn should_use_fp_conv<'a, Ty, C>( + cx: &C, + arg: &TyLayout<'a, Ty>, + xlen: u64, + flen: u64, +) -> Option +where + Ty: TyLayoutMethods<'a, C> + Copy, + C: LayoutOf>, +{ + let mut field1_kind = RegPassKind::Unknown; + let mut field2_kind = RegPassKind::Unknown; + if should_use_fp_conv_helper(cx, arg, xlen, flen, &mut field1_kind, &mut field2_kind).is_err() { + return None; + } + match (field1_kind, field2_kind) { + (RegPassKind::Integer(l), RegPassKind::Float(r)) => Some(FloatConv::MixedPair(l, r)), + (RegPassKind::Float(l), RegPassKind::Integer(r)) => Some(FloatConv::MixedPair(l, r)), + (RegPassKind::Float(l), RegPassKind::Float(r)) => Some(FloatConv::FloatPair(l, r)), + (RegPassKind::Float(f), RegPassKind::Unknown) => Some(FloatConv::Float(f)), + _ => None, + } +} + +fn classify_ret<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, xlen: u64, flen: u64) -> bool +where + Ty: TyLayoutMethods<'a, C> + Copy, + C: LayoutOf>, +{ + if let Some(conv) = should_use_fp_conv(cx, &arg.layout, xlen, flen) { + match conv { + FloatConv::Float(f) => { + arg.cast_to(f); + } + FloatConv::FloatPair(l, r) => { + arg.cast_to(CastTarget::pair(l, r)); + } + FloatConv::MixedPair(l, r) => { + arg.cast_to(CastTarget::pair(l, r)); + } + } + return false; + } + + let total = arg.layout.size; -fn classify_ret(arg: &mut ArgAbi<'_, Ty>, xlen: u64) { // "Scalars wider than 2✕XLEN are passed by reference and are replaced in // the argument list with the address." // "Aggregates larger than 2✕XLEN bits are passed by reference and are // replaced in the argument list with the address, as are C++ aggregates // with nontrivial copy constructors, destructors, or vtables." - if arg.layout.size.bits() > 2 * xlen { - arg.make_indirect(); + if total.bits() > 2 * xlen { + // We rely on the LLVM backend lowering code to lower passing a scalar larger than 2*XLEN. + if is_riscv_aggregate(arg) { + arg.make_indirect(); + } + return true; + } + + let xlen_reg = match xlen { + 32 => Reg::i32(), + 64 => Reg::i64(), + _ => unreachable!("Unsupported XLEN: {}", xlen), + }; + if is_riscv_aggregate(arg) { + if total.bits() <= xlen { + arg.cast_to(xlen_reg); + } else { + arg.cast_to(Uniform { unit: xlen_reg, total: Size::from_bits(xlen * 2) }); + } + return false; } // "When passed in registers, scalars narrower than XLEN bits are widened // according to the sign of their type up to 32 bits, then sign-extended to // XLEN bits." - arg.extend_integer_width_to(xlen); // this method only affects integer scalars + extend_integer_width(arg, xlen); + false } -fn classify_arg(arg: &mut ArgAbi<'_, Ty>, xlen: u64) { +fn classify_arg<'a, Ty, C>( + cx: &C, + arg: &mut ArgAbi<'a, Ty>, + xlen: u64, + flen: u64, + is_vararg: bool, + avail_gprs: &mut u64, + avail_fprs: &mut u64, +) where + Ty: TyLayoutMethods<'a, C> + Copy, + C: LayoutOf>, +{ + if !is_vararg { + match should_use_fp_conv(cx, &arg.layout, xlen, flen) { + Some(FloatConv::Float(f)) if *avail_fprs >= 1 => { + *avail_fprs -= 1; + arg.cast_to(f); + return; + } + Some(FloatConv::FloatPair(l, r)) if *avail_fprs >= 2 => { + *avail_fprs -= 2; + arg.cast_to(CastTarget::pair(l, r)); + return; + } + Some(FloatConv::MixedPair(l, r)) if *avail_fprs >= 1 && *avail_gprs >= 1 => { + *avail_gprs -= 1; + *avail_fprs -= 1; + arg.cast_to(CastTarget::pair(l, r)); + return; + } + _ => (), + } + } + + let total = arg.layout.size; + let align = arg.layout.align.abi.bits(); + // "Scalars wider than 2✕XLEN are passed by reference and are replaced in // the argument list with the address." // "Aggregates larger than 2✕XLEN bits are passed by reference and are // replaced in the argument list with the address, as are C++ aggregates // with nontrivial copy constructors, destructors, or vtables." - if arg.layout.size.bits() > 2 * xlen { - arg.make_indirect(); + if total.bits() > 2 * xlen { + // We rely on the LLVM backend lowering code to lower passing a scalar larger than 2*XLEN. + if is_riscv_aggregate(arg) { + arg.make_indirect(); + } + if *avail_gprs >= 1 { + *avail_gprs -= 1; + } + return; + } + + let double_xlen_reg = match xlen { + 32 => Reg::i64(), + 64 => Reg::i128(), + _ => unreachable!("Unsupported XLEN: {}", xlen), + }; + + let xlen_reg = match xlen { + 32 => Reg::i32(), + 64 => Reg::i64(), + _ => unreachable!("Unsupported XLEN: {}", xlen), + }; + + if total.bits() > xlen { + let align_regs = align > xlen; + if is_riscv_aggregate(arg) { + arg.cast_to(Uniform { + unit: if align_regs { double_xlen_reg } else { xlen_reg }, + total: Size::from_bits(xlen * 2), + }); + } + if align_regs && is_vararg { + *avail_gprs -= *avail_gprs % 2; + } + if *avail_gprs >= 2 { + *avail_gprs -= 2; + } else { + *avail_gprs = 0; + } + return; + } else if is_riscv_aggregate(arg) { + arg.cast_to(xlen_reg); + if *avail_gprs >= 1 { + *avail_gprs -= 1; + } + return; } // "When passed in registers, scalars narrower than XLEN bits are widened // according to the sign of their type up to 32 bits, then sign-extended to // XLEN bits." - arg.extend_integer_width_to(xlen); // this method only affects integer scalars + if *avail_gprs >= 1 { + extend_integer_width(arg, xlen); + *avail_gprs -= 1; + } } -pub fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>, xlen: u64) { +fn extend_integer_width<'a, Ty>(arg: &mut ArgAbi<'a, Ty>, xlen: u64) { + match arg.layout.abi { + Abi::Scalar(ref scalar) => { + match scalar.value { + abi::Int(i, _) => { + // 32-bit integers are always sign-extended + if i.size().bits() == 32 && xlen > 32 { + if let PassMode::Direct(ref mut attrs) = arg.mode { + attrs.set(ArgAttribute::SExt); + return; + } + } + } + _ => (), + } + } + _ => (), + } + arg.extend_integer_width_to(xlen); +} + +pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) +where + Ty: TyLayoutMethods<'a, C> + Copy, + C: LayoutOf> + HasDataLayout + HasTargetSpec, +{ + let flen = match &cx.target_spec().options.llvm_abiname[..] { + "ilp32f" | "lp64f" => 32, + "ilp32d" | "lp64d" => 64, + _ => 0, + }; + let xlen = cx.data_layout().pointer_size.bits(); + + let mut avail_gprs = 8; + let mut avail_fprs = 8; + if !fn_abi.ret.is_ignore() { - classify_ret(&mut fn_abi.ret, xlen); + if classify_ret(cx, &mut fn_abi.ret, xlen, flen) { + avail_gprs -= 1; + } } - for arg in &mut fn_abi.args { + for (i, arg) in fn_abi.args.iter_mut().enumerate() { if arg.is_ignore() { continue; } - classify_arg(arg, xlen); + classify_arg( + cx, + arg, + xlen, + flen, + i >= fn_abi.fixed_count, + &mut avail_gprs, + &mut avail_fprs, + ); } } From 39633874ae7d0150669004a80740ff3b0708d08d Mon Sep 17 00:00:00 2001 From: msizanoen1 Date: Mon, 3 Feb 2020 22:04:44 +0700 Subject: [PATCH 02/17] Add tests for RISC-V C ABI --- src/test/auxiliary/rust_test_helpers.c | 29 ++ .../riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs | 181 +++++++++++ .../codegen/riscv-abi/riscv64-lp64d-abi.rs | 293 ++++++++++++++++++ .../riscv-abi/riscv64-lp64f-lp64d-abi.rs | 277 +++++++++++++++++ src/test/ui/abi/struct-enums/struct-return.rs | 52 +++- 5 files changed, 831 insertions(+), 1 deletion(-) create mode 100644 src/test/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs create mode 100644 src/test/codegen/riscv-abi/riscv64-lp64d-abi.rs create mode 100644 src/test/codegen/riscv-abi/riscv64-lp64f-lp64d-abi.rs diff --git a/src/test/auxiliary/rust_test_helpers.c b/src/test/auxiliary/rust_test_helpers.c index b95b0ca1a89c0..22bb54988365c 100644 --- a/src/test/auxiliary/rust_test_helpers.c +++ b/src/test/auxiliary/rust_test_helpers.c @@ -168,6 +168,18 @@ struct floats { double c; }; +struct char_char_double { + uint8_t a; + uint8_t b; + double c; +}; + +struct char_char_float { + uint8_t a; + uint8_t b; + float c; +}; + struct quad rust_dbg_abi_1(struct quad q) { struct quad qq = { q.c + 1, @@ -185,6 +197,23 @@ rust_dbg_abi_2(struct floats f) { return ff; } +struct char_char_double +rust_dbg_abi_3(struct char_char_double a) { + struct char_char_double ccd = { a.a + 1, + a.b - 1, + a.c + 1.0 }; + return ccd; +} + +struct char_char_float +rust_dbg_abi_4(struct char_char_float a) { + struct char_char_float ccd = { a.a + 1, + a.b - 1, + a.c + 1.0 }; + return ccd; +} + + int rust_dbg_static_mut = 3; diff --git a/src/test/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs b/src/test/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs new file mode 100644 index 0000000000000..f0f052fe5c557 --- /dev/null +++ b/src/test/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs @@ -0,0 +1,181 @@ +// ignore-tidy-linelength +// compile-flags: -C no-prepopulate-passes +// only-riscv64 +// only-linux +#![crate_type = "lib"] +#![allow(improper_ctypes)] + +// CHECK: define void @f_void() +#[no_mangle] +pub extern "C" fn f_void() {} + +// CHECK: define zeroext i1 @f_scalar_0(i1 zeroext %a) +#[no_mangle] +pub extern "C" fn f_scalar_0(a: bool) -> bool { + a +} + +// CHECK: define signext i8 @f_scalar_1(i8 signext %x) +#[no_mangle] +pub extern "C" fn f_scalar_1(x: i8) -> i8 { + x +} + +// CHECK: define zeroext i8 @f_scalar_2(i8 zeroext %x) +#[no_mangle] +pub extern "C" fn f_scalar_2(x: u8) -> u8 { + x +} + +// CHECK: define signext i32 @f_scalar_3(i32 signext %x) +#[no_mangle] +pub extern "C" fn f_scalar_3(x: i32) -> u32 { + x as u32 +} + +// CHECK: define i64 @f_scalar_4(i64 %x) +#[no_mangle] +pub extern "C" fn f_scalar_4(x: i64) -> i64 { + x +} + +// CHECK: define float @f_fp_scalar_1(float) +#[no_mangle] +pub extern "C" fn f_fp_scalar_1(x: f32) -> f32 { + x +} +// CHECK: define double @f_fp_scalar_2(double) +#[no_mangle] +pub extern "C" fn f_fp_scalar_2(x: f64) -> f64 { + x +} + +#[repr(C)] +pub struct Empty {} + +// CHECK: define void @f_agg_empty_struct() +#[no_mangle] +pub extern "C" fn f_agg_empty_struct(e: Empty) -> Empty { + e +} + +#[repr(C)] +pub struct Tiny { + a: u16, + b: u16, + c: u16, + d: u16, +} + +// CHECK: define void @f_agg_tiny(i64) +#[no_mangle] +pub extern "C" fn f_agg_tiny(mut e: Tiny) { + e.a += e.b; + e.c += e.d; +} + +// CHECK: define i64 @f_agg_tiny_ret() +#[no_mangle] +pub extern "C" fn f_agg_tiny_ret() -> Tiny { + Tiny { a: 1, b: 2, c: 3, d: 4 } +} + +#[repr(C)] +pub struct Small { + a: i64, + b: *mut i64, +} + +// CHECK: define void @f_agg_small([2 x i64]) +#[no_mangle] +pub extern "C" fn f_agg_small(mut x: Small) { + x.a += unsafe { *x.b }; + x.b = &mut x.a; +} + +// CHECK: define [2 x i64] @f_agg_small_ret() +#[no_mangle] +pub extern "C" fn f_agg_small_ret() -> Small { + Small { a: 1, b: core::ptr::null_mut() } +} + +#[repr(C)] +pub struct SmallAligned { + a: i128, +} + +// CHECK: define void @f_agg_small_aligned(i128) +#[no_mangle] +pub extern "C" fn f_agg_small_aligned(mut x: SmallAligned) { + x.a += x.a; +} + +#[repr(C)] +pub struct Large { + a: i64, + b: i64, + c: i64, + d: i64, +} + +// CHECK: define void @f_agg_large(%Large* {{.*}}%x) +#[no_mangle] +pub extern "C" fn f_agg_large(mut x: Large) { + x.a = x.b + x.c + x.d; +} + +// CHECK: define void @f_agg_large_ret(%Large* {{.*}}sret{{.*}}, i32 signext %i, i8 signext %j) +#[no_mangle] +pub extern "C" fn f_agg_large_ret(i: i32, j: i8) -> Large { + Large { a: 1, b: 2, c: 3, d: 4 } +} + +// CHECK: define void @f_scalar_stack_1(i64, [2 x i64], i128, %Large* {{.*}}%d, i8 zeroext %e, i8 signext %f, i8 %g, i8 %h) +#[no_mangle] +pub extern "C" fn f_scalar_stack_1( + a: Tiny, + b: Small, + c: SmallAligned, + d: Large, + e: u8, + f: i8, + g: u8, + h: i8, +) { +} + +// CHECK: define void @f_scalar_stack_2(%Large* {{.*}}sret{{.*}}, i64 %a, i128, i128, i64 %d, i8 zeroext %e, i8 %f, i8 %g) +#[no_mangle] +pub extern "C" fn f_scalar_stack_2( + a: u64, + b: SmallAligned, + c: SmallAligned, + d: u64, + e: u8, + f: i8, + g: u8, +) -> Large { + Large { a: a as i64, b: e as i64, c: f as i64, d: g as i64 } +} + +extern "C" { + fn f_va_callee(_: i32, ...) -> i32; +} + +#[no_mangle] +pub unsafe extern "C" fn f_va_caller() { + // CHECK: call signext i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i64 3, double {{.*}}, double {{.*}}, i64 {{.*}}, [2 x i64] {{.*}}, i128 {{.*}}, %Large* {{.*}}) + f_va_callee( + 1, + 2i32, + 3i64, + 4.0f64, + 5.0f64, + Tiny { a: 1, b: 2, c: 3, d: 4 }, + Small { a: 10, b: core::ptr::null_mut() }, + SmallAligned { a: 11 }, + Large { a: 12, b: 13, c: 14, d: 15 }, + ); + // CHECK: call signext i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i128 {{.*}}, i32 signext 6, i32 signext 7, i32 8, i32 9) + f_va_callee(1, 2i32, 3i32, 4i32, SmallAligned { a: 5 }, 6i32, 7i32, 8i32, 9i32); +} diff --git a/src/test/codegen/riscv-abi/riscv64-lp64d-abi.rs b/src/test/codegen/riscv-abi/riscv64-lp64d-abi.rs new file mode 100644 index 0000000000000..66a3b9e4952a9 --- /dev/null +++ b/src/test/codegen/riscv-abi/riscv64-lp64d-abi.rs @@ -0,0 +1,293 @@ +// ignore-tidy-linelength +// compile-flags: -C no-prepopulate-passes +// only-riscv64 +// only-linux +#![crate_type = "lib"] + +// CHECK: define void @f_fpr_tracking(double, double, double, double, double, double, double, double, i8 zeroext %i) +#[no_mangle] +pub extern "C" fn f_fpr_tracking( + a: f64, + b: f64, + c: f64, + d: f64, + e: f64, + f: f64, + g: f64, + h: f64, + i: u8, +) { +} + +#[repr(C)] +pub struct Double { + f: f64, +} + +#[repr(C)] +pub struct DoubleDouble { + f: f64, + g: f64, +} + +#[repr(C)] +pub struct DoubleFloat { + f: f64, + g: f32, +} + +// CHECK: define void @f_double_s_arg(double) +#[no_mangle] +pub extern "C" fn f_double_s_arg(a: Double) {} + +// CHECK: define double @f_ret_double_s() +#[no_mangle] +pub extern "C" fn f_ret_double_s() -> Double { + Double { f: 1. } +} + +// CHECK: define void @f_double_double_s_arg({ double, double }) +#[no_mangle] +pub extern "C" fn f_double_double_s_arg(a: DoubleDouble) {} + +// CHECK: define { double, double } @f_ret_double_double_s() +#[no_mangle] +pub extern "C" fn f_ret_double_double_s() -> DoubleDouble { + DoubleDouble { f: 1., g: 2. } +} + +// CHECK: define void @f_double_float_s_arg({ double, float }) +#[no_mangle] +pub extern "C" fn f_double_float_s_arg(a: DoubleFloat) {} + +// CHECK: define { double, float } @f_ret_double_float_s() +#[no_mangle] +pub extern "C" fn f_ret_double_float_s() -> DoubleFloat { + DoubleFloat { f: 1., g: 2. } +} + +// CHECK: define void @f_double_double_s_arg_insufficient_fprs(double, double, double, double, double, double, double, [2 x i64]) +#[no_mangle] +pub extern "C" fn f_double_double_s_arg_insufficient_fprs( + a: f64, + b: f64, + c: f64, + d: f64, + e: f64, + f: f64, + g: f64, + h: DoubleDouble, +) { +} + +#[repr(C)] +pub struct DoubleInt8 { + f: f64, + i: i8, +} + +#[repr(C)] +pub struct DoubleUInt8 { + f: f64, + i: u8, +} + +#[repr(C)] +pub struct DoubleInt32 { + f: f64, + i: i32, +} + +#[repr(C)] +pub struct DoubleInt64 { + f: f64, + i: i64, +} + +// CHECK: define void @f_double_int8_s_arg({ double, i8 }) +#[no_mangle] +pub extern "C" fn f_double_int8_s_arg(a: DoubleInt8) {} + +// CHECK: define { double, i8 } @f_ret_double_int8_s() +#[no_mangle] +pub extern "C" fn f_ret_double_int8_s() -> DoubleInt8 { + DoubleInt8 { f: 1., i: 2 } +} + +// CHECK: define void @f_double_int32_s_arg({ double, i32 }) +#[no_mangle] +pub extern "C" fn f_double_int32_s_arg(a: DoubleInt32) {} + +// CHECK: define { double, i32 } @f_ret_double_int32_s() +#[no_mangle] +pub extern "C" fn f_ret_double_int32_s() -> DoubleInt32 { + DoubleInt32 { f: 1., i: 2 } +} + +// CHECK: define void @f_double_uint8_s_arg({ double, i8 }) +#[no_mangle] +pub extern "C" fn f_double_uint8_s_arg(a: DoubleUInt8) {} + +// CHECK: define { double, i8 } @f_ret_double_uint8_s() +#[no_mangle] +pub extern "C" fn f_ret_double_uint8_s() -> DoubleUInt8 { + DoubleUInt8 { f: 1., i: 2 } +} + +// CHECK: define void @f_double_int64_s_arg({ double, i64 }) +#[no_mangle] +pub extern "C" fn f_double_int64_s_arg(a: DoubleInt64) {} + +// CHECK: define { double, i64 } @f_ret_double_int64_s() +#[no_mangle] +pub extern "C" fn f_ret_double_int64_s() -> DoubleInt64 { + DoubleInt64 { f: 1., i: 2 } +} + +// CHECK: define void @f_double_int8_s_arg_insufficient_gprs(i32 signext %a, i32 signext %b, i32 signext %c, i32 signext %d, i32 signext %e, i32 signext %f, i32 signext %g, i32 signext %h, [2 x i64]) +#[no_mangle] +pub extern "C" fn f_double_int8_s_arg_insufficient_gprs( + a: i32, + b: i32, + c: i32, + d: i32, + e: i32, + f: i32, + g: i32, + h: i32, + i: DoubleInt8, +) { +} + +// CHECK: define void @f_struct_double_int8_insufficient_fprs(float, double, double, double, double, double, double, double, [2 x i64]) +#[no_mangle] +pub extern "C" fn f_struct_double_int8_insufficient_fprs( + a: f32, + b: f64, + c: f64, + d: f64, + e: f64, + f: f64, + g: f64, + h: f64, + i: DoubleInt8, +) { +} + +#[repr(C)] +pub struct DoubleArr1 { + a: [f64; 1], +} + +// CHECK: define void @f_doublearr1_s_arg(double) +#[no_mangle] +pub extern "C" fn f_doublearr1_s_arg(a: DoubleArr1) {} + +// CHECK: define double @f_ret_doublearr1_s() +#[no_mangle] +pub extern "C" fn f_ret_doublearr1_s() -> DoubleArr1 { + DoubleArr1 { a: [1.] } +} + +#[repr(C)] +pub struct DoubleArr2 { + a: [f64; 2], +} + +// CHECK: define void @f_doublearr2_s_arg({ double, double }) +#[no_mangle] +pub extern "C" fn f_doublearr2_s_arg(a: DoubleArr2) {} + +// CHECK: define { double, double } @f_ret_doublearr2_s() +#[no_mangle] +pub extern "C" fn f_ret_doublearr2_s() -> DoubleArr2 { + DoubleArr2 { a: [1., 2.] } +} + +#[repr(C)] +pub struct Tricky1 { + f: [f64; 1], +} + +#[repr(C)] +pub struct DoubleArr2Tricky1 { + g: [Tricky1; 2], +} + +// CHECK: define void @f_doublearr2_tricky1_s_arg({ double, double }) +#[no_mangle] +pub extern "C" fn f_doublearr2_tricky1_s_arg(a: DoubleArr2Tricky1) {} + +// CHECK: define { double, double } @f_ret_doublearr2_tricky1_s() +#[no_mangle] +pub extern "C" fn f_ret_doublearr2_tricky1_s() -> DoubleArr2Tricky1 { + DoubleArr2Tricky1 { g: [Tricky1 { f: [1.] }, Tricky1 { f: [2.] }] } +} + +#[repr(C)] +pub struct EmptyStruct {} + +#[repr(C)] +pub struct DoubleArr2Tricky2 { + s: EmptyStruct, + g: [Tricky1; 2], +} + +// CHECK: define void @f_doublearr2_tricky2_s_arg({ double, double }) +#[no_mangle] +pub extern "C" fn f_doublearr2_tricky2_s_arg(a: DoubleArr2Tricky2) {} + +// CHECK: define { double, double } @f_ret_doublearr2_tricky2_s() +#[no_mangle] +pub extern "C" fn f_ret_doublearr2_tricky2_s() -> DoubleArr2Tricky2 { + DoubleArr2Tricky2 { s: EmptyStruct {}, g: [Tricky1 { f: [1.] }, Tricky1 { f: [2.] }] } +} + +#[repr(C)] +pub struct IntDoubleInt { + a: i32, + b: f64, + c: i32, +} + +// CHECK: define void @f_int_double_int_s_arg(%IntDoubleInt* {{.*}}%a) +#[no_mangle] +pub extern "C" fn f_int_double_int_s_arg(a: IntDoubleInt) {} + +// CHECK: define void @f_ret_int_double_int_s(%IntDoubleInt* {{.*}}sret +#[no_mangle] +pub extern "C" fn f_ret_int_double_int_s() -> IntDoubleInt { + IntDoubleInt { a: 1, b: 2., c: 3 } +} + +#[repr(C)] +pub struct CharCharDouble { + a: u8, + b: u8, + c: f64, +} + +// CHECK: define void @f_char_char_double_s_arg([2 x i64]) +#[no_mangle] +pub extern "C" fn f_char_char_double_s_arg(a: CharCharDouble) {} + +// CHECK: define [2 x i64] @f_ret_char_char_double_s() +#[no_mangle] +pub extern "C" fn f_ret_char_char_double_s() -> CharCharDouble { + CharCharDouble { a: 1, b: 2, c: 3. } +} + +#[repr(C)] +pub union DoubleU { + a: f64, +} + +// CHECK: define void @f_double_u_arg(i64) +#[no_mangle] +pub extern "C" fn f_double_u_arg(a: DoubleU) {} + +// CHECK: define i64 @f_ret_double_u() +#[no_mangle] +pub extern "C" fn f_ret_double_u() -> DoubleU { + unsafe { DoubleU { a: 1. } } +} diff --git a/src/test/codegen/riscv-abi/riscv64-lp64f-lp64d-abi.rs b/src/test/codegen/riscv-abi/riscv64-lp64f-lp64d-abi.rs new file mode 100644 index 0000000000000..d843331f425de --- /dev/null +++ b/src/test/codegen/riscv-abi/riscv64-lp64f-lp64d-abi.rs @@ -0,0 +1,277 @@ +// ignore-tidy-linelength +// compile-flags: -C no-prepopulate-passes +// only-riscv64 +// only-linux +#![crate_type = "lib"] + +// CHECK: define void @f_fpr_tracking(float, float, float, float, float, float, float, float, i8 zeroext %i) +#[no_mangle] +pub extern "C" fn f_fpr_tracking( + a: f32, + b: f32, + c: f32, + d: f32, + e: f32, + f: f32, + g: f32, + h: f32, + i: u8, +) { +} + +#[repr(C)] +pub struct Float { + f: f32, +} + +#[repr(C)] +pub struct FloatFloat { + f: f32, + g: f32, +} + +// CHECK: define void @f_float_s_arg(float) +#[no_mangle] +pub extern "C" fn f_float_s_arg(a: Float) {} + +// CHECK: define float @f_ret_float_s() +#[no_mangle] +pub extern "C" fn f_ret_float_s() -> Float { + Float { f: 1. } +} + +// CHECK: define void @f_float_float_s_arg({ float, float }) +#[no_mangle] +pub extern "C" fn f_float_float_s_arg(a: FloatFloat) {} + +// CHECK: define { float, float } @f_ret_float_float_s() +#[no_mangle] +pub extern "C" fn f_ret_float_float_s() -> FloatFloat { + FloatFloat { f: 1., g: 2. } +} + +// CHECK: define void @f_float_float_s_arg_insufficient_fprs(float, float, float, float, float, float, float, i64) +#[no_mangle] +pub extern "C" fn f_float_float_s_arg_insufficient_fprs( + a: f32, + b: f32, + c: f32, + d: f32, + e: f32, + f: f32, + g: f32, + h: FloatFloat, +) { +} + +#[repr(C)] +pub struct FloatInt8 { + f: f32, + i: i8, +} + +#[repr(C)] +pub struct FloatUInt8 { + f: f32, + i: u8, +} + +#[repr(C)] +pub struct FloatInt32 { + f: f32, + i: i32, +} + +#[repr(C)] +pub struct FloatInt64 { + f: f32, + i: i64, +} + +// CHECK: define void @f_float_int8_s_arg({ float, i8 }) +#[no_mangle] +pub extern "C" fn f_float_int8_s_arg(a: FloatInt8) {} + +// CHECK: define { float, i8 } @f_ret_float_int8_s() +#[no_mangle] +pub extern "C" fn f_ret_float_int8_s() -> FloatInt8 { + FloatInt8 { f: 1., i: 2 } +} + +// CHECK: define void @f_float_int32_s_arg({ float, i32 }) +#[no_mangle] +pub extern "C" fn f_float_int32_s_arg(a: FloatInt32) {} + +// CHECK: define { float, i32 } @f_ret_float_int32_s() +#[no_mangle] +pub extern "C" fn f_ret_float_int32_s() -> FloatInt32 { + FloatInt32 { f: 1., i: 2 } +} + +// CHECK: define void @f_float_uint8_s_arg({ float, i8 }) +#[no_mangle] +pub extern "C" fn f_float_uint8_s_arg(a: FloatUInt8) {} + +// CHECK: define { float, i8 } @f_ret_float_uint8_s() +#[no_mangle] +pub extern "C" fn f_ret_float_uint8_s() -> FloatUInt8 { + FloatUInt8 { f: 1., i: 2 } +} + +// CHECK: define void @f_float_int64_s_arg({ float, i64 }) +#[no_mangle] +pub extern "C" fn f_float_int64_s_arg(a: FloatInt64) {} + +// CHECK: define { float, i64 } @f_ret_float_int64_s() +#[no_mangle] +pub extern "C" fn f_ret_float_int64_s() -> FloatInt64 { + FloatInt64 { f: 1., i: 2 } +} + +// CHECK: define void @f_float_int8_s_arg_insufficient_gprs(i32 signext %a, i32 signext %b, i32 signext %c, i32 signext %d, i32 signext %e, i32 signext %f, i32 signext %g, i32 signext %h, i64) +#[no_mangle] +pub extern "C" fn f_float_int8_s_arg_insufficient_gprs( + a: i32, + b: i32, + c: i32, + d: i32, + e: i32, + f: i32, + g: i32, + h: i32, + i: FloatInt8, +) { +} + +// CHECK: define void @f_struct_float_int8_insufficient_fprs(float, float, float, float, float, float, float, float, i64) +#[no_mangle] +pub extern "C" fn f_struct_float_int8_insufficient_fprs( + a: f32, + b: f32, + c: f32, + d: f32, + e: f32, + f: f32, + g: f32, + h: f32, + i: FloatInt8, +) { +} + +#[repr(C)] +pub struct FloatArr1 { + a: [f32; 1], +} + +// CHECK: define void @f_floatarr1_s_arg(float) +#[no_mangle] +pub extern "C" fn f_floatarr1_s_arg(a: FloatArr1) {} + +// CHECK: define float @f_ret_floatarr1_s() +#[no_mangle] +pub extern "C" fn f_ret_floatarr1_s() -> FloatArr1 { + FloatArr1 { a: [1.] } +} + +#[repr(C)] +pub struct FloatArr2 { + a: [f32; 2], +} + +// CHECK: define void @f_floatarr2_s_arg({ float, float }) +#[no_mangle] +pub extern "C" fn f_floatarr2_s_arg(a: FloatArr2) {} + +// CHECK: define { float, float } @f_ret_floatarr2_s() +#[no_mangle] +pub extern "C" fn f_ret_floatarr2_s() -> FloatArr2 { + FloatArr2 { a: [1., 2.] } +} + +#[repr(C)] +pub struct Tricky1 { + f: [f32; 1], +} + +#[repr(C)] +pub struct FloatArr2Tricky1 { + g: [Tricky1; 2], +} + +// CHECK: define void @f_floatarr2_tricky1_s_arg({ float, float }) +#[no_mangle] +pub extern "C" fn f_floatarr2_tricky1_s_arg(a: FloatArr2Tricky1) {} + +// CHECK: define { float, float } @f_ret_floatarr2_tricky1_s() +#[no_mangle] +pub extern "C" fn f_ret_floatarr2_tricky1_s() -> FloatArr2Tricky1 { + FloatArr2Tricky1 { g: [Tricky1 { f: [1.] }, Tricky1 { f: [2.] }] } +} + +#[repr(C)] +pub struct EmptyStruct {} + +#[repr(C)] +pub struct FloatArr2Tricky2 { + s: EmptyStruct, + g: [Tricky1; 2], +} + +// CHECK: define void @f_floatarr2_tricky2_s_arg({ float, float }) +#[no_mangle] +pub extern "C" fn f_floatarr2_tricky2_s_arg(a: FloatArr2Tricky2) {} + +// CHECK: define { float, float } @f_ret_floatarr2_tricky2_s() +#[no_mangle] +pub extern "C" fn f_ret_floatarr2_tricky2_s() -> FloatArr2Tricky2 { + FloatArr2Tricky2 { s: EmptyStruct {}, g: [Tricky1 { f: [1.] }, Tricky1 { f: [2.] }] } +} + +#[repr(C)] +pub struct IntFloatInt { + a: i32, + b: f32, + c: i32, +} + +// CHECK: define void @f_int_float_int_s_arg([2 x i64]) +#[no_mangle] +pub extern "C" fn f_int_float_int_s_arg(a: IntFloatInt) {} + +// CHECK: define [2 x i64] @f_ret_int_float_int_s() +#[no_mangle] +pub extern "C" fn f_ret_int_float_int_s() -> IntFloatInt { + IntFloatInt { a: 1, b: 2., c: 3 } +} + +#[repr(C)] +pub struct CharCharFloat { + a: u8, + b: u8, + c: f32, +} + +// CHECK: define void @f_char_char_float_s_arg(i64) +#[no_mangle] +pub extern "C" fn f_char_char_float_s_arg(a: CharCharFloat) {} + +// CHECK: define i64 @f_ret_char_char_float_s() +#[no_mangle] +pub extern "C" fn f_ret_char_char_float_s() -> CharCharFloat { + CharCharFloat { a: 1, b: 2, c: 3. } +} + +#[repr(C)] +pub union FloatU { + a: f32, +} + +// CHECK: define void @f_float_u_arg(i64) +#[no_mangle] +pub extern "C" fn f_float_u_arg(a: FloatU) {} + +// CHECK: define i64 @f_ret_float_u() +#[no_mangle] +pub extern "C" fn f_ret_float_u() -> FloatU { + unsafe { FloatU { a: 1. } } +} diff --git a/src/test/ui/abi/struct-enums/struct-return.rs b/src/test/ui/abi/struct-enums/struct-return.rs index 5930fc4acbbe3..a3e70bbdb0809 100644 --- a/src/test/ui/abi/struct-enums/struct-return.rs +++ b/src/test/ui/abi/struct-enums/struct-return.rs @@ -10,13 +10,23 @@ pub struct Quad { a: u64, b: u64, c: u64, d: u64 } #[derive(Copy, Clone)] pub struct Floats { a: f64, b: u8, c: f64 } +#[repr(C)] +#[derive(Copy, Clone)] +pub struct CharCharDouble { a: u8, b: u8, c: f64 } + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct CharCharFloat { a: u8, b: u8, c: f32 } + mod rustrt { - use super::{Floats, Quad}; + use super::{Floats, Quad, CharCharDouble, CharCharFloat}; #[link(name = "rust_test_helpers", kind = "static")] extern { pub fn rust_dbg_abi_1(q: Quad) -> Quad; pub fn rust_dbg_abi_2(f: Floats) -> Floats; + pub fn rust_dbg_abi_3(a: CharCharDouble) -> CharCharDouble; + pub fn rust_dbg_abi_4(a: CharCharFloat) -> CharCharFloat; } } @@ -58,7 +68,47 @@ fn test2() { fn test2() { } +#[cfg(target_pointer_width = "64")] +fn test3() { + unsafe { + let a = CharCharDouble { + a: 1, + b: 2, + c: 3., + }; + let b = rustrt::rust_dbg_abi_3(a); + println!("a: {}", b.a); + println!("b: {}", b.b); + println!("c: {}", b.c); + assert_eq!(b.a, a.a + 1); + assert_eq!(b.b, a.b - 1); + assert_eq!(b.c, a.c + 1.0); + } +} + +#[cfg(target_pointer_width = "32")] +fn test3() {} + +fn test4() { + unsafe { + let a = CharCharFloat { + a: 1, + b: 2, + c: 3., + }; + let b = rustrt::rust_dbg_abi_4(a); + println!("a: {}", b.a); + println!("b: {}", b.b); + println!("c: {}", b.c); + assert_eq!(b.a, a.a + 1); + assert_eq!(b.b, a.b - 1); + assert_eq!(b.c, a.c + 1.0); + } +} + pub fn main() { test1(); test2(); + test3(); + test4(); } From fa9bfebfc9256369c03cbe8bba2e737de3cb38fc Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Tue, 4 Feb 2020 22:19:05 +0100 Subject: [PATCH 03/17] Fix and test implementation of BTreeMap's first_entry, last_entry, pop_first, pop_last --- src/liballoc/collections/btree/map.rs | 24 ++++++++++++++---------- src/liballoc/tests/btree/map.rs | 5 +++++ src/liballoc/tests/btree/set.rs | 27 ++++++++++++++++----------- 3 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index 8eabc1773042f..c1778f2065d40 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -675,13 +675,15 @@ impl BTreeMap { T: Ord, K: Borrow, { - match self.length { - 0 => None, - _ => Some(OccupiedEntry { - handle: self.root.as_mut().first_kv(), + let front = self.root.as_mut().first_leaf_edge(); + if let Ok(kv) = front.right_kv() { + Some(OccupiedEntry { + handle: kv.forget_node_type(), length: &mut self.length, _marker: PhantomData, - }), + }) + } else { + None } } @@ -736,13 +738,15 @@ impl BTreeMap { T: Ord, K: Borrow, { - match self.length { - 0 => None, - _ => Some(OccupiedEntry { - handle: self.root.as_mut().last_kv(), + let back = self.root.as_mut().last_leaf_edge(); + if let Ok(kv) = back.left_kv() { + Some(OccupiedEntry { + handle: kv.forget_node_type(), length: &mut self.length, _marker: PhantomData, - }), + }) + } else { + None } } diff --git a/src/liballoc/tests/btree/map.rs b/src/liballoc/tests/btree/map.rs index 0d009507fc7aa..0a26d7bf427ab 100644 --- a/src/liballoc/tests/btree/map.rs +++ b/src/liballoc/tests/btree/map.rs @@ -23,6 +23,11 @@ fn test_basic_large() { assert_eq!(map.len(), i + 1); } + assert_eq!(map.first_key_value(), Some((&0, &0))); + assert_eq!(map.last_key_value(), Some((&(size - 1), &(10 * (size - 1))))); + assert_eq!(map.first_entry().unwrap().key(), &0); + assert_eq!(map.last_entry().unwrap().key(), &(size - 1)); + for i in 0..size { assert_eq!(map.get(&i).unwrap(), &(i * 10)); } diff --git a/src/liballoc/tests/btree/set.rs b/src/liballoc/tests/btree/set.rs index 265ef758cc5bc..1a2b62d026b2e 100644 --- a/src/liballoc/tests/btree/set.rs +++ b/src/liballoc/tests/btree/set.rs @@ -487,21 +487,26 @@ fn test_first_last() { a.insert(2); assert_eq!(a.first(), Some(&1)); assert_eq!(a.last(), Some(&2)); - a.insert(3); + for i in 3..=12 { + a.insert(i); + } assert_eq!(a.first(), Some(&1)); - assert_eq!(a.last(), Some(&3)); - - assert_eq!(a.len(), 3); + assert_eq!(a.last(), Some(&12)); assert_eq!(a.pop_first(), Some(1)); - assert_eq!(a.len(), 2); - assert_eq!(a.pop_last(), Some(3)); - assert_eq!(a.len(), 1); + assert_eq!(a.pop_last(), Some(12)); assert_eq!(a.pop_first(), Some(2)); - assert_eq!(a.len(), 0); - assert_eq!(a.pop_last(), None); - assert_eq!(a.len(), 0); + assert_eq!(a.pop_last(), Some(11)); + assert_eq!(a.pop_first(), Some(3)); + assert_eq!(a.pop_last(), Some(10)); + assert_eq!(a.pop_first(), Some(4)); + assert_eq!(a.pop_first(), Some(5)); + assert_eq!(a.pop_first(), Some(6)); + assert_eq!(a.pop_first(), Some(7)); + assert_eq!(a.pop_first(), Some(8)); + assert_eq!(a.clone().pop_last(), Some(9)); + assert_eq!(a.pop_first(), Some(9)); assert_eq!(a.pop_first(), None); - assert_eq!(a.len(), 0); + assert_eq!(a.pop_last(), None); } fn rand_data(len: usize) -> Vec { From c00d8aa5179ef38f7d83067a8d010bcc26fa0cc3 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 5 Feb 2020 16:28:13 +0800 Subject: [PATCH 04/17] Reorder declarations of Result::export/unwrap to match Option --- src/libcore/result.rs | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/libcore/result.rs b/src/libcore/result.rs index bc70dbd62eb52..3361ab6c97d80 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -935,8 +935,8 @@ impl Result { /// /// # Panics /// - /// Panics if the value is an [`Err`], with a panic message provided by the - /// [`Err`]'s value. + /// Panics if the value is an [`Err`], with a panic message including the + /// passed message, and the content of the [`Err`]. /// /// [`Ok`]: enum.Result.html#variant.Ok /// [`Err`]: enum.Result.html#variant.Err @@ -945,22 +945,17 @@ impl Result { /// /// Basic usage: /// - /// ``` - /// let x: Result = Ok(2); - /// assert_eq!(x.unwrap(), 2); - /// ``` - /// /// ```{.should_panic} /// let x: Result = Err("emergency failure"); - /// x.unwrap(); // panics with `emergency failure` + /// x.expect("Testing expect"); // panics with `Testing expect: emergency failure` /// ``` #[inline] #[track_caller] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn unwrap(self) -> T { + #[stable(feature = "result_expect", since = "1.4.0")] + pub fn expect(self, msg: &str) -> T { match self { Ok(t) => t, - Err(e) => unwrap_failed("called `Result::unwrap()` on an `Err` value", &e), + Err(e) => unwrap_failed(msg, &e), } } @@ -968,8 +963,8 @@ impl Result { /// /// # Panics /// - /// Panics if the value is an [`Err`], with a panic message including the - /// passed message, and the content of the [`Err`]. + /// Panics if the value is an [`Err`], with a panic message provided by the + /// [`Err`]'s value. /// /// [`Ok`]: enum.Result.html#variant.Ok /// [`Err`]: enum.Result.html#variant.Err @@ -978,17 +973,22 @@ impl Result { /// /// Basic usage: /// + /// ``` + /// let x: Result = Ok(2); + /// assert_eq!(x.unwrap(), 2); + /// ``` + /// /// ```{.should_panic} /// let x: Result = Err("emergency failure"); - /// x.expect("Testing expect"); // panics with `Testing expect: emergency failure` + /// x.unwrap(); // panics with `emergency failure` /// ``` #[inline] #[track_caller] - #[stable(feature = "result_expect", since = "1.4.0")] - pub fn expect(self, msg: &str) -> T { + #[stable(feature = "rust1", since = "1.0.0")] + pub fn unwrap(self) -> T { match self { Ok(t) => t, - Err(e) => unwrap_failed(msg, &e), + Err(e) => unwrap_failed("called `Result::unwrap()` on an `Err` value", &e), } } } From db9b578b71190540cfd84f16f5d310d6ce4cb659 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 5 Feb 2020 16:31:12 +0800 Subject: [PATCH 05/17] Reorder declarations of Result::expect_err/unwrap_err to match Option --- src/libcore/result.rs | 44 +++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 3361ab6c97d80..ee28946f0da7a 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -998,30 +998,26 @@ impl Result { /// /// # Panics /// - /// Panics if the value is an [`Ok`], with a custom panic message provided - /// by the [`Ok`]'s value. + /// Panics if the value is an [`Ok`], with a panic message including the + /// passed message, and the content of the [`Ok`]. /// /// [`Ok`]: enum.Result.html#variant.Ok /// [`Err`]: enum.Result.html#variant.Err /// - /// /// # Examples /// - /// ```{.should_panic} - /// let x: Result = Ok(2); - /// x.unwrap_err(); // panics with `2` - /// ``` + /// Basic usage: /// - /// ``` - /// let x: Result = Err("emergency failure"); - /// assert_eq!(x.unwrap_err(), "emergency failure"); + /// ```{.should_panic} + /// let x: Result = Ok(10); + /// x.expect_err("Testing expect_err"); // panics with `Testing expect_err: 10` /// ``` #[inline] #[track_caller] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn unwrap_err(self) -> E { + #[stable(feature = "result_expect_err", since = "1.17.0")] + pub fn expect_err(self, msg: &str) -> E { match self { - Ok(t) => unwrap_failed("called `Result::unwrap_err()` on an `Ok` value", &t), + Ok(t) => unwrap_failed(msg, &t), Err(e) => e, } } @@ -1030,26 +1026,30 @@ impl Result { /// /// # Panics /// - /// Panics if the value is an [`Ok`], with a panic message including the - /// passed message, and the content of the [`Ok`]. + /// Panics if the value is an [`Ok`], with a custom panic message provided + /// by the [`Ok`]'s value. /// /// [`Ok`]: enum.Result.html#variant.Ok /// [`Err`]: enum.Result.html#variant.Err /// - /// # Examples /// - /// Basic usage: + /// # Examples /// /// ```{.should_panic} - /// let x: Result = Ok(10); - /// x.expect_err("Testing expect_err"); // panics with `Testing expect_err: 10` + /// let x: Result = Ok(2); + /// x.unwrap_err(); // panics with `2` + /// ``` + /// + /// ``` + /// let x: Result = Err("emergency failure"); + /// assert_eq!(x.unwrap_err(), "emergency failure"); /// ``` #[inline] #[track_caller] - #[stable(feature = "result_expect_err", since = "1.17.0")] - pub fn expect_err(self, msg: &str) -> E { + #[stable(feature = "rust1", since = "1.0.0")] + pub fn unwrap_err(self) -> E { match self { - Ok(t) => unwrap_failed(msg, &t), + Ok(t) => unwrap_failed("called `Result::unwrap_err()` on an `Ok` value", &t), Err(e) => e, } } From b82f6c575e53f06c3645f66a9d480b4f025ee39e Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Thu, 6 Feb 2020 11:04:46 +0200 Subject: [PATCH 06/17] rustc_codegen_llvm: always set AlwaysPreserve on all debuginfo variables. --- src/librustc_codegen_llvm/debuginfo/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs index c4a52a73e25d9..eb22d74ba3e47 100644 --- a/src/librustc_codegen_llvm/debuginfo/mod.rs +++ b/src/librustc_codegen_llvm/debuginfo/mod.rs @@ -569,7 +569,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { file_metadata, loc.line as c_uint, type_metadata, - self.sess().opts.optimize != config::OptLevel::No, + true, DIFlags::FlagZero, argument_index, align.bytes() as u32, From 8251e12950159c5802dd3995b14be7cf4fa99acd Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Fri, 7 Feb 2020 13:59:43 +0800 Subject: [PATCH 07/17] Don't use the word 'unwrap' to describe core unwrapping functions It's tautological, and Rust-specific Jargon. This changes various Option/Result methods to consistently describe unwrapping behavior using the words "return", "contain", "consume". It also renames the closure argument of `Return::unwrap_or_else` to `default` to be consistent with `Option`. --- src/libcore/option.rs | 26 ++++++++++++++++---------- src/libcore/result.rs | 38 ++++++++++++++++++++++---------------- 2 files changed, 38 insertions(+), 26 deletions(-) diff --git a/src/libcore/option.rs b/src/libcore/option.rs index ad0491f888cc7..c7b36d8ad6362 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -317,7 +317,7 @@ impl Option { // Getting to contained values ///////////////////////////////////////////////////////////////////////// - /// Unwraps an option, yielding the content of a [`Some`]. + /// Returns the contained [`Some`] value, consuming the `self` value. /// /// # Panics /// @@ -348,17 +348,22 @@ impl Option { } } - /// Moves the value `v` out of the `Option` if it is [`Some(v)`]. + /// Returns the contained [`Some`] value, consuming the `self` value. /// - /// In general, because this function may panic, its use is discouraged. + /// Because this function may panic, its use is generally discouraged. /// Instead, prefer to use pattern matching and handle the [`None`] - /// case explicitly. + /// case explicitly, or call [`unwrap_or`], [`unwrap_or_else`], or + /// [`unwrap_or_default`]. + /// + /// [`unwrap_or`]: #method.unwrap_or + /// [`unwrap_or_else`]: #method.unwrap_or_else + /// [`unwrap_or_default`]: #method.unwrap_or_default /// /// # Panics /// /// Panics if the self value equals [`None`]. /// - /// [`Some(v)`]: #variant.Some + /// [`Some`]: #variant.Some /// [`None`]: #variant.None /// /// # Examples @@ -382,12 +387,13 @@ impl Option { } } - /// Returns the contained value or a default. + /// Returns the contained [`Some`] value or a provided default. /// /// Arguments passed to `unwrap_or` are eagerly evaluated; if you are passing /// the result of a function call, it is recommended to use [`unwrap_or_else`], /// which is lazily evaluated. /// + /// [`Some`]: #variant.Some /// [`unwrap_or_else`]: #method.unwrap_or_else /// /// # Examples @@ -405,7 +411,7 @@ impl Option { } } - /// Returns the contained value or computes it from a closure. + /// Returns the contained [`Some`] value or computes it from a closure. /// /// # Examples /// @@ -980,7 +986,7 @@ impl Option<&mut T> { } impl Option { - /// Unwraps an option, expecting [`None`] and returning nothing. + /// Consumes `self` while expecting [`None`] and returning nothing. /// /// # Panics /// @@ -1023,7 +1029,7 @@ impl Option { } } - /// Unwraps an option, expecting [`None`] and returning nothing. + /// Consumes `self` while expecting [`None`] and returning nothing. /// /// # Panics /// @@ -1068,7 +1074,7 @@ impl Option { } impl Option { - /// Returns the contained value or a default + /// Returns the contained [`Some`] value or a default /// /// Consumes the `self` argument then, if [`Some`], returns the contained /// value, otherwise if [`None`], returns the [default value] for that diff --git a/src/libcore/result.rs b/src/libcore/result.rs index ee28946f0da7a..022701c949815 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -792,8 +792,7 @@ impl Result { } } - /// Unwraps a result, yielding the content of an [`Ok`]. - /// Else, it returns `optb`. + /// Returns the contained [`Ok`] value or a provided default. /// /// Arguments passed to `unwrap_or` are eagerly evaluated; if you are passing /// the result of a function call, it is recommended to use [`unwrap_or_else`], @@ -808,27 +807,25 @@ impl Result { /// Basic usage: /// /// ``` - /// let optb = 2; + /// let default = 2; /// let x: Result = Ok(9); - /// assert_eq!(x.unwrap_or(optb), 9); + /// assert_eq!(x.unwrap_or(default), 9); /// /// let x: Result = Err("error"); - /// assert_eq!(x.unwrap_or(optb), optb); + /// assert_eq!(x.unwrap_or(default), default); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn unwrap_or(self, optb: T) -> T { + pub fn unwrap_or(self, default: T) -> T { match self { Ok(t) => t, - Err(_) => optb, + Err(_) => default, } } - /// Unwraps a result, yielding the content of an [`Ok`]. - /// If the value is an [`Err`] then it calls `op` with its value. + /// Returns the contained [`Ok`] value or computes it from a closure. /// /// [`Ok`]: enum.Result.html#variant.Ok - /// [`Err`]: enum.Result.html#variant.Err /// /// # Examples /// @@ -931,7 +928,7 @@ impl Result<&mut T, E> { } impl Result { - /// Unwraps a result, yielding the content of an [`Ok`]. + /// Returns the contained [`Ok`] value, consuming the `self` value. /// /// # Panics /// @@ -959,7 +956,16 @@ impl Result { } } - /// Unwraps a result, yielding the content of an [`Ok`]. + /// Returns the contained [`Ok`] value, consuming the `self` value. + /// + /// Because this function may panic, its use is generally discouraged. + /// Instead, prefer to use pattern matching and handle the [`Err`] + /// case explicitly, or call [`unwrap_or`], [`unwrap_or_else`], or + /// [`unwrap_or_default`]. + /// + /// [`unwrap_or`]: #method.unwrap_or + /// [`unwrap_or_else`]: #method.unwrap_or_else + /// [`unwrap_or_default`]: #method.unwrap_or_default /// /// # Panics /// @@ -994,7 +1000,7 @@ impl Result { } impl Result { - /// Unwraps a result, yielding the content of an [`Err`]. + /// Returns the contained [`Err`] value, consuming the `self` value. /// /// # Panics /// @@ -1022,7 +1028,7 @@ impl Result { } } - /// Unwraps a result, yielding the content of an [`Err`]. + /// Returns the contained [`Err`] value, consuming the `self` value. /// /// # Panics /// @@ -1056,7 +1062,7 @@ impl Result { } impl Result { - /// Returns the contained value or a default + /// Returns the contained [`Ok`] value or a default /// /// Consumes the `self` argument then, if [`Ok`], returns the contained /// value, otherwise if [`Err`], returns the default value for that @@ -1095,7 +1101,7 @@ impl Result { #[unstable(feature = "unwrap_infallible", reason = "newly added", issue = "61695")] impl> Result { - /// Unwraps a result that can never be an [`Err`], yielding the content of the [`Ok`]. + /// Returns the contained [`Ok`] value, but never panics. /// /// Unlike [`unwrap`], this method is known to never panic on the /// result types it is implemented for. Therefore, it can be used From 73936ab57ad567802a613157ae9db0cccf31eda3 Mon Sep 17 00:00:00 2001 From: Mikhail Babenko Date: Fri, 7 Feb 2020 04:03:54 +0300 Subject: [PATCH 08/17] print generic bounds on associated types --- src/librustc_ast_pretty/pprust.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs index d9077d1606f3a..78bf149f0e01a 100644 --- a/src/librustc_ast_pretty/pprust.rs +++ b/src/librustc_ast_pretty/pprust.rs @@ -1074,12 +1074,15 @@ impl<'a> State<'a> { fn print_associated_type( &mut self, ident: ast::Ident, + generics: &ast::Generics, bounds: &ast::GenericBounds, ty: Option<&ast::Ty>, ) { self.word_space("type"); self.print_ident(ident); + self.print_generic_params(&generics.params); self.print_type_bounds(":", bounds); + self.print_where_clause(&generics.where_clause); if let Some(ty) = ty { self.s.space(); self.word_space("="); @@ -1474,7 +1477,7 @@ impl<'a> State<'a> { self.print_fn_full(sig, item.ident, &item.generics, &item.vis, body, &item.attrs); } ast::AssocItemKind::TyAlias(bounds, ty) => { - self.print_associated_type(item.ident, bounds, ty.as_deref()); + self.print_associated_type(item.ident, &item.generics, bounds, ty.as_deref()); } ast::AssocItemKind::Macro(mac) => { self.print_mac(mac); From ab6ea2bba771836ebbf8759e718fedd2c6d229d2 Mon Sep 17 00:00:00 2001 From: Mikhail Babenko Date: Fri, 7 Feb 2020 05:17:38 +0300 Subject: [PATCH 09/17] add regression test --- src/test/pretty/gat-bounds.pp | 25 +++++++++++++++++++++++++ src/test/pretty/gat-bounds.rs | 17 +++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 src/test/pretty/gat-bounds.pp create mode 100644 src/test/pretty/gat-bounds.rs diff --git a/src/test/pretty/gat-bounds.pp b/src/test/pretty/gat-bounds.pp new file mode 100644 index 0000000000000..0c95add490110 --- /dev/null +++ b/src/test/pretty/gat-bounds.pp @@ -0,0 +1,25 @@ +// Check that associated types print generic parameters and where clauses. +// See issue #67509. + +// pretty-compare-only +// pp-exact:gat-bounds.pp + +#![feature(generic_associated_types)] + +trait X { + type + Y: Trait + where + Self: Sized; +} + +impl X for () { + type + Y + where + Self: Sized + = + u32; +} + +fn main() { } diff --git a/src/test/pretty/gat-bounds.rs b/src/test/pretty/gat-bounds.rs new file mode 100644 index 0000000000000..1275f432a3c50 --- /dev/null +++ b/src/test/pretty/gat-bounds.rs @@ -0,0 +1,17 @@ +// Check that associated types print generic parameters and where clauses. +// See issue #67509. + +// pretty-compare-only +// pp-exact:gat-bounds.pp + +#![feature(generic_associated_types)] + +trait X { + type Y: Trait where Self: Sized; +} + +impl X for () { + type Y where Self: Sized = u32; +} + +fn main() { } From bf82582d6f8de744df5c34e80a04ad72f40afed7 Mon Sep 17 00:00:00 2001 From: Mikhail Babenko Date: Fri, 7 Feb 2020 18:27:12 +0300 Subject: [PATCH 10/17] add hir printing --- src/librustc_hir/print.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/librustc_hir/print.rs b/src/librustc_hir/print.rs index b0d2f96c71a03..071c3de4b1c2c 100644 --- a/src/librustc_hir/print.rs +++ b/src/librustc_hir/print.rs @@ -454,14 +454,17 @@ impl<'a> State<'a> { fn print_associated_type( &mut self, ident: ast::Ident, + generics: &hir::Generics<'_>, bounds: Option>, ty: Option<&hir::Ty<'_>>, ) { self.word_space("type"); self.print_ident(ident); + self.print_generic_params(&generics.params); if let Some(bounds) = bounds { self.print_bounds(":", bounds); } + self.print_where_clause(&generics.where_clause); if let Some(ty) = ty { self.s.space(); self.word_space("="); @@ -902,6 +905,7 @@ impl<'a> State<'a> { hir::TraitItemKind::Type(ref bounds, ref default) => { self.print_associated_type( ti.ident, + &ti.generics, Some(bounds), default.as_ref().map(|ty| &**ty), ); @@ -930,7 +934,7 @@ impl<'a> State<'a> { self.ann.nested(self, Nested::Body(body)); } hir::ImplItemKind::TyAlias(ref ty) => { - self.print_associated_type(ii.ident, None, Some(ty)); + self.print_associated_type(ii.ident, &ii.generics, None, Some(ty)); } hir::ImplItemKind::OpaqueTy(bounds) => { self.word_space("type"); From 0df21b2301149924f9c6842fb0ec0282b330409c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Tue, 14 Jan 2020 02:54:55 +0100 Subject: [PATCH 11/17] Make the `type_of` return a generic type for generators --- src/librustc_mir_build/build/mod.rs | 3 ++- src/librustc_typeck/collect.rs | 10 +++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/librustc_mir_build/build/mod.rs b/src/librustc_mir_build/build/mod.rs index 32b1f2b6e1368..67a8ef788672c 100644 --- a/src/librustc_mir_build/build/mod.rs +++ b/src/librustc_mir_build/build/mod.rs @@ -143,7 +143,8 @@ fn mir_build(tcx: TyCtxt<'_>, def_id: DefId) -> BodyAndCache<'_> { let arguments = implicit_argument.into_iter().chain(explicit_arguments); let (yield_ty, return_ty) = if body.generator_kind.is_some() { - let gen_sig = match ty.kind { + let gen_ty = tcx.body_tables(body_id).node_type(id); + let gen_sig = match gen_ty.kind { ty::Generator(gen_def_id, gen_substs, ..) => { gen_substs.as_generator().sig(gen_def_id, tcx) } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 2a450f4b4e8b1..5982ac60d9903 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1428,12 +1428,12 @@ fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { Node::Field(field) => icx.to_ty(&field.ty), Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(.., gen), .. }) => { - if gen.is_some() { - return tcx.typeck_tables_of(def_id).node_type(hir_id); - } - let substs = InternalSubsts::identity_for_item(tcx, def_id); - tcx.mk_closure(def_id, substs) + if let Some(movability) = gen { + tcx.mk_generator(def_id, substs, movability) + } else { + tcx.mk_closure(def_id, substs) + } } Node::AnonConst(_) => { From 1ae614f27a0d354107cfce3b6578bae7b72906fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Thu, 6 Feb 2020 10:33:05 +0100 Subject: [PATCH 12/17] Update tests --- ...block-control-flow-static-semantics.stderr | 32 ++++++------ src/test/ui/async-await/async-error-span.rs | 1 + .../ui/async-await/async-error-span.stderr | 20 ++++++-- .../incorrect-syntax-suggestions.rs | 1 + .../incorrect-syntax-suggestions.stderr | 49 +++++++++++-------- src/test/ui/async-await/issue-67651.rs | 20 ++++++++ src/test/ui/async-await/issue-67651.stderr | 12 +++++ .../issues/issue-63388-2.nll.stderr | 13 ----- .../ui/async-await/issues/issue-63388-2.rs | 2 +- .../async-await/issues/issue-63388-2.stderr | 17 +------ src/test/ui/async-await/issues/issue-65159.rs | 1 + .../ui/async-await/issues/issue-65159.stderr | 11 ++++- .../ui/self/elision/ref-self-async.nll.stderr | 13 ----- src/test/ui/self/elision/ref-self-async.rs | 1 + .../ui/self/elision/ref-self-async.stderr | 14 +++--- 15 files changed, 115 insertions(+), 92 deletions(-) create mode 100644 src/test/ui/async-await/issue-67651.rs create mode 100644 src/test/ui/async-await/issue-67651.stderr delete mode 100644 src/test/ui/async-await/issues/issue-63388-2.nll.stderr delete mode 100644 src/test/ui/self/elision/ref-self-async.nll.stderr diff --git a/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr b/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr index afb8f146192cc..46a132da309bb 100644 --- a/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr +++ b/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr @@ -18,22 +18,6 @@ LL | | break 0u8; LL | | }; | |_________- enclosing `async` block -error[E0308]: mismatched types - --> $DIR/async-block-control-flow-static-semantics.rs:13:43 - | -LL | fn return_targets_async_block_not_fn() -> u8 { - | --------------------------------- ^^ expected `u8`, found `()` - | | - | implicitly returns `()` as its body has no tail or `return` expression - -error[E0271]: type mismatch resolving `::Output == ()` - --> $DIR/async-block-control-flow-static-semantics.rs:18:39 - | -LL | let _: &dyn Future = █ - | ^^^^^^ expected `()`, found `u8` - | - = note: required for the cast to the object type `dyn std::future::Future` - error[E0308]: mismatched types --> $DIR/async-block-control-flow-static-semantics.rs:22:58 | @@ -55,6 +39,22 @@ LL | let _: &dyn Future = █ | = note: required for the cast to the object type `dyn std::future::Future` +error[E0308]: mismatched types + --> $DIR/async-block-control-flow-static-semantics.rs:13:43 + | +LL | fn return_targets_async_block_not_fn() -> u8 { + | --------------------------------- ^^ expected `u8`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression + +error[E0271]: type mismatch resolving `::Output == ()` + --> $DIR/async-block-control-flow-static-semantics.rs:18:39 + | +LL | let _: &dyn Future = █ + | ^^^^^^ expected `()`, found `u8` + | + = note: required for the cast to the object type `dyn std::future::Future` + error[E0308]: mismatched types --> $DIR/async-block-control-flow-static-semantics.rs:48:44 | diff --git a/src/test/ui/async-await/async-error-span.rs b/src/test/ui/async-await/async-error-span.rs index 28132c9789c67..cf10ebfeca939 100644 --- a/src/test/ui/async-await/async-error-span.rs +++ b/src/test/ui/async-await/async-error-span.rs @@ -5,6 +5,7 @@ use std::future::Future; fn get_future() -> impl Future { +//~^ ERROR the trait bound `(): std::future::Future` is not satisfied panic!() } diff --git a/src/test/ui/async-await/async-error-span.stderr b/src/test/ui/async-await/async-error-span.stderr index b551b99587dd9..4054e739c483d 100644 --- a/src/test/ui/async-await/async-error-span.stderr +++ b/src/test/ui/async-await/async-error-span.stderr @@ -1,15 +1,27 @@ +error[E0277]: the trait bound `(): std::future::Future` is not satisfied + --> $DIR/async-error-span.rs:7:20 + | +LL | fn get_future() -> impl Future { + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::future::Future` is not implemented for `()` +LL | +LL | panic!() + | -------- this returned value is of type `!` + | + = note: the return type of a function must have a statically known size + error[E0698]: type inside `async fn` body must be known in this context - --> $DIR/async-error-span.rs:12:9 + --> $DIR/async-error-span.rs:13:9 | LL | let a; | ^ cannot infer type | note: the type is part of the `async fn` body because of this `await` - --> $DIR/async-error-span.rs:13:5 + --> $DIR/async-error-span.rs:14:5 | LL | get_future().await; | ^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0698`. +Some errors have detailed explanations: E0277, E0698. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.rs b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.rs index 22bcbb1064dd7..cebff3be6b059 100644 --- a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.rs +++ b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.rs @@ -62,6 +62,7 @@ fn foo10() -> Result<(), ()> { fn foo11() -> Result<(), ()> { let _ = await bar()?; //~ ERROR `await` is only allowed inside `async` functions and blocks //~^ ERROR incorrect use of `await` + //~| ERROR the `?` operator can only be applied to values that implement `std::ops::Try` Ok(()) } fn foo12() -> Result<(), ()> { diff --git a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr index 92cef80c19360..61f2570b2ff93 100644 --- a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr +++ b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr @@ -71,49 +71,49 @@ LL | let _ = await bar()?; | ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar()?.await` error: incorrect use of `await` - --> $DIR/incorrect-syntax-suggestions.rs:68:14 + --> $DIR/incorrect-syntax-suggestions.rs:69:14 | LL | let _ = (await bar())?; | ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` error: incorrect use of `await` - --> $DIR/incorrect-syntax-suggestions.rs:73:24 + --> $DIR/incorrect-syntax-suggestions.rs:74:24 | LL | let _ = bar().await(); | ^^ help: `await` is not a method call, remove the parentheses error: incorrect use of `await` - --> $DIR/incorrect-syntax-suggestions.rs:78:24 + --> $DIR/incorrect-syntax-suggestions.rs:79:24 | LL | let _ = bar().await()?; | ^^ help: `await` is not a method call, remove the parentheses error: incorrect use of `await` - --> $DIR/incorrect-syntax-suggestions.rs:106:13 + --> $DIR/incorrect-syntax-suggestions.rs:107:13 | LL | let _ = await!(bar()); | ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` error: incorrect use of `await` - --> $DIR/incorrect-syntax-suggestions.rs:110:13 + --> $DIR/incorrect-syntax-suggestions.rs:111:13 | LL | let _ = await!(bar())?; | ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` error: incorrect use of `await` - --> $DIR/incorrect-syntax-suggestions.rs:115:17 + --> $DIR/incorrect-syntax-suggestions.rs:116:17 | LL | let _ = await!(bar())?; | ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` error: incorrect use of `await` - --> $DIR/incorrect-syntax-suggestions.rs:123:17 + --> $DIR/incorrect-syntax-suggestions.rs:124:17 | LL | let _ = await!(bar())?; | ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` error: expected expression, found `=>` - --> $DIR/incorrect-syntax-suggestions.rs:131:25 + --> $DIR/incorrect-syntax-suggestions.rs:132:25 | LL | match await { await => () } | ----- ^^ expected expression @@ -121,13 +121,13 @@ LL | match await { await => () } | while parsing this incorrect await expression error: incorrect use of `await` - --> $DIR/incorrect-syntax-suggestions.rs:131:11 + --> $DIR/incorrect-syntax-suggestions.rs:132:11 | LL | match await { await => () } | ^^^^^^^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ await => () }.await` error: expected one of `.`, `?`, `{`, or an operator, found `}` - --> $DIR/incorrect-syntax-suggestions.rs:134:1 + --> $DIR/incorrect-syntax-suggestions.rs:135:1 | LL | match await { await => () } | ----- - expected one of `.`, `?`, `{`, or an operator @@ -162,7 +162,7 @@ LL | let _ = await bar()?; | ^^^^^^^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/incorrect-syntax-suggestions.rs:68:14 + --> $DIR/incorrect-syntax-suggestions.rs:69:14 | LL | fn foo12() -> Result<(), ()> { | ----- this is not `async` @@ -170,7 +170,7 @@ LL | let _ = (await bar())?; | ^^^^^^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/incorrect-syntax-suggestions.rs:73:13 + --> $DIR/incorrect-syntax-suggestions.rs:74:13 | LL | fn foo13() -> Result<(), ()> { | ----- this is not `async` @@ -178,7 +178,7 @@ LL | let _ = bar().await(); | ^^^^^^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/incorrect-syntax-suggestions.rs:78:13 + --> $DIR/incorrect-syntax-suggestions.rs:79:13 | LL | fn foo14() -> Result<(), ()> { | ----- this is not `async` @@ -186,7 +186,7 @@ LL | let _ = bar().await()?; | ^^^^^^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/incorrect-syntax-suggestions.rs:83:13 + --> $DIR/incorrect-syntax-suggestions.rs:84:13 | LL | fn foo15() -> Result<(), ()> { | ----- this is not `async` @@ -194,7 +194,7 @@ LL | let _ = bar().await; | ^^^^^^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/incorrect-syntax-suggestions.rs:87:13 + --> $DIR/incorrect-syntax-suggestions.rs:88:13 | LL | fn foo16() -> Result<(), ()> { | ----- this is not `async` @@ -202,7 +202,7 @@ LL | let _ = bar().await?; | ^^^^^^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/incorrect-syntax-suggestions.rs:92:17 + --> $DIR/incorrect-syntax-suggestions.rs:93:17 | LL | fn foo() -> Result<(), ()> { | --- this is not `async` @@ -210,7 +210,7 @@ LL | let _ = bar().await?; | ^^^^^^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/incorrect-syntax-suggestions.rs:99:17 + --> $DIR/incorrect-syntax-suggestions.rs:100:17 | LL | let foo = || { | -- this is not `async` @@ -218,7 +218,7 @@ LL | let _ = bar().await?; | ^^^^^^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/incorrect-syntax-suggestions.rs:115:17 + --> $DIR/incorrect-syntax-suggestions.rs:116:17 | LL | fn foo() -> Result<(), ()> { | --- this is not `async` @@ -226,7 +226,7 @@ LL | let _ = await!(bar())?; | ^^^^^^^^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/incorrect-syntax-suggestions.rs:123:17 + --> $DIR/incorrect-syntax-suggestions.rs:124:17 | LL | let foo = || { | -- this is not `async` @@ -242,7 +242,16 @@ LL | let _ = await bar()?; = help: the trait `std::ops::Try` is not implemented for `impl std::future::Future` = note: required by `std::ops::Try::into_result` -error: aborting due to 35 previous errors +error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` + --> $DIR/incorrect-syntax-suggestions.rs:63:19 + | +LL | let _ = await bar()?; + | ^^^^^^ the `?` operator cannot be applied to type `impl std::future::Future` + | + = help: the trait `std::ops::Try` is not implemented for `impl std::future::Future` + = note: required by `std::ops::Try::into_result` + +error: aborting due to 36 previous errors Some errors have detailed explanations: E0277, E0728. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/issue-67651.rs b/src/test/ui/async-await/issue-67651.rs new file mode 100644 index 0000000000000..bd96a3b709bae --- /dev/null +++ b/src/test/ui/async-await/issue-67651.rs @@ -0,0 +1,20 @@ +// edition:2018 + +trait From { + fn from(); +} + +impl From for () { + fn from() {} +} + +impl From for () { +//~^ ERROR conflicting implementations of trait + fn from() {} +} + +fn bar() -> impl core::future::Future { + async move { From::from() } +} + +fn main() {} diff --git a/src/test/ui/async-await/issue-67651.stderr b/src/test/ui/async-await/issue-67651.stderr new file mode 100644 index 0000000000000..99857c215eb8f --- /dev/null +++ b/src/test/ui/async-await/issue-67651.stderr @@ -0,0 +1,12 @@ +error[E0119]: conflicting implementations of trait `From` for type `()`: + --> $DIR/issue-67651.rs:11:1 + | +LL | impl From for () { + | ---------------- first implementation here +... +LL | impl From for () { + | ^^^^^^^^^^^^^^^^ conflicting implementation for `()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/async-await/issues/issue-63388-2.nll.stderr b/src/test/ui/async-await/issues/issue-63388-2.nll.stderr deleted file mode 100644 index 6edb9e63d480a..0000000000000 --- a/src/test/ui/async-await/issues/issue-63388-2.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0106]: missing lifetime specifier - --> $DIR/issue-63388-2.rs:12:10 - | -LL | foo: &dyn Foo, bar: &'a dyn Foo - | -------- ----------- -LL | ) -> &dyn Foo - | ^ help: consider using the named lifetime: `&'a` - | - = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `foo` or `bar` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/async-await/issues/issue-63388-2.rs b/src/test/ui/async-await/issues/issue-63388-2.rs index 73e7f25f97d0d..458bc9faeaf27 100644 --- a/src/test/ui/async-await/issues/issue-63388-2.rs +++ b/src/test/ui/async-await/issues/issue-63388-2.rs @@ -8,7 +8,7 @@ trait Foo {} impl Xyz { async fn do_sth<'a>( - foo: &dyn Foo, bar: &'a dyn Foo //~ ERROR cannot infer + foo: &dyn Foo, bar: &'a dyn Foo ) -> &dyn Foo //~ ERROR missing lifetime specifier { foo diff --git a/src/test/ui/async-await/issues/issue-63388-2.stderr b/src/test/ui/async-await/issues/issue-63388-2.stderr index 9f51ced9c3f49..6edb9e63d480a 100644 --- a/src/test/ui/async-await/issues/issue-63388-2.stderr +++ b/src/test/ui/async-await/issues/issue-63388-2.stderr @@ -8,21 +8,6 @@ LL | ) -> &dyn Foo | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `foo` or `bar` -error: cannot infer an appropriate lifetime - --> $DIR/issue-63388-2.rs:11:9 - | -LL | foo: &dyn Foo, bar: &'a dyn Foo - | ^^^ ...but this borrow... -... -LL | foo - | --- this return type evaluates to the `'static` lifetime... - | -note: ...can't outlive the lifetime `'_` as defined on the method body at 11:14 - --> $DIR/issue-63388-2.rs:11:14 - | -LL | foo: &dyn Foo, bar: &'a dyn Foo - | ^ - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/async-await/issues/issue-65159.rs b/src/test/ui/async-await/issues/issue-65159.rs index b5fee061f277e..2f80435046bdf 100644 --- a/src/test/ui/async-await/issues/issue-65159.rs +++ b/src/test/ui/async-await/issues/issue-65159.rs @@ -5,6 +5,7 @@ async fn copy() -> Result<()> //~ ERROR wrong number of type arguments { Ok(()) + //~^ type annotations needed } fn main() { } diff --git a/src/test/ui/async-await/issues/issue-65159.stderr b/src/test/ui/async-await/issues/issue-65159.stderr index 56d2c38b302e9..04cfa5249982e 100644 --- a/src/test/ui/async-await/issues/issue-65159.stderr +++ b/src/test/ui/async-await/issues/issue-65159.stderr @@ -4,6 +4,13 @@ error[E0107]: wrong number of type arguments: expected 2, found 1 LL | async fn copy() -> Result<()> | ^^^^^^^^^^ expected 2 type arguments -error: aborting due to previous error +error[E0282]: type annotations needed + --> $DIR/issue-65159.rs:7:5 + | +LL | Ok(()) + | ^^ cannot infer type for type parameter `E` declared on the enum `Result` + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0107`. +Some errors have detailed explanations: E0107, E0282. +For more information about an error, try `rustc --explain E0107`. diff --git a/src/test/ui/self/elision/ref-self-async.nll.stderr b/src/test/ui/self/elision/ref-self-async.nll.stderr deleted file mode 100644 index 46468b693ee98..0000000000000 --- a/src/test/ui/self/elision/ref-self-async.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0658]: `Wrap<&Struct, Struct>` cannot be used as the type of `self` without the `arbitrary_self_types` feature - --> $DIR/ref-self-async.rs:47:39 - | -LL | async fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 { - | ^^^^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/44874 - = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable - = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/self/elision/ref-self-async.rs b/src/test/ui/self/elision/ref-self-async.rs index 6a98b79cb3bba..0fbbd95c975d6 100644 --- a/src/test/ui/self/elision/ref-self-async.rs +++ b/src/test/ui/self/elision/ref-self-async.rs @@ -1,6 +1,7 @@ // edition:2018 #![allow(non_snake_case)] +#![feature(arbitrary_self_types)] use std::marker::PhantomData; use std::ops::Deref; diff --git a/src/test/ui/self/elision/ref-self-async.stderr b/src/test/ui/self/elision/ref-self-async.stderr index b73290b024f8f..bda958241b67b 100644 --- a/src/test/ui/self/elision/ref-self-async.stderr +++ b/src/test/ui/self/elision/ref-self-async.stderr @@ -1,5 +1,5 @@ error[E0623]: lifetime mismatch - --> $DIR/ref-self-async.rs:22:9 + --> $DIR/ref-self-async.rs:23:9 | LL | async fn ref_self(&self, f: &u32) -> &u32 { | ----- ---- @@ -9,7 +9,7 @@ LL | f | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch - --> $DIR/ref-self-async.rs:28:9 + --> $DIR/ref-self-async.rs:29:9 | LL | async fn ref_Self(self: &Self, f: &u32) -> &u32 { | ----- ---- @@ -19,7 +19,7 @@ LL | f | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch - --> $DIR/ref-self-async.rs:32:9 + --> $DIR/ref-self-async.rs:33:9 | LL | async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 { | ----- ---- @@ -29,7 +29,7 @@ LL | f | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch - --> $DIR/ref-self-async.rs:36:9 + --> $DIR/ref-self-async.rs:37:9 | LL | async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 { | ----- ---- @@ -39,7 +39,7 @@ LL | f | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch - --> $DIR/ref-self-async.rs:40:9 + --> $DIR/ref-self-async.rs:41:9 | LL | async fn box_box_ref_Self(self: Box>, f: &u32) -> &u32 { | ----- ---- @@ -49,7 +49,7 @@ LL | f | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch - --> $DIR/ref-self-async.rs:44:9 + --> $DIR/ref-self-async.rs:45:9 | LL | async fn box_pin_ref_Self(self: Box>, f: &u32) -> &u32 { | ----- ---- @@ -59,7 +59,7 @@ LL | f | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch - --> $DIR/ref-self-async.rs:48:9 + --> $DIR/ref-self-async.rs:49:9 | LL | async fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 { | ----- --- From 66fd4e6ed8fbc00feeccfe0fe9d25e1c1346807d Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Thu, 6 Feb 2020 23:21:44 +0100 Subject: [PATCH 13/17] Make `associated_items` query return a slice --- src/librustc/query/mod.rs | 2 +- src/librustc/traits/mod.rs | 1 + src/librustc/traits/object_safety.rs | 6 ++++- src/librustc/traits/project.rs | 2 +- .../traits/types/specialization_graph.rs | 11 +++++---- src/librustc/traits/wf.rs | 5 ++-- src/librustc/ty/adjustment.rs | 1 + src/librustc/ty/instance.rs | 1 + src/librustc/ty/mod.rs | 24 +++---------------- src/librustc/ty/sty.rs | 1 + src/librustc/ty/util.rs | 2 +- src/librustc_mir/shim.rs | 1 + src/librustc_mir/util/elaborate_drops.rs | 2 +- src/librustc_passes/stability.rs | 1 + src/librustc_save_analysis/lib.rs | 2 ++ src/librustc_ty/ty.rs | 10 ++++---- src/librustc_typeck/astconv.rs | 6 ++++- src/librustc_typeck/check/closure.rs | 4 ++-- src/librustc_typeck/check/demand.rs | 1 + src/librustc_typeck/check/method/mod.rs | 11 ++++++--- src/librustc_typeck/check/method/probe.rs | 4 +++- src/librustc_typeck/check/mod.rs | 6 +++-- src/librustdoc/clean/blanket_impl.rs | 2 ++ src/librustdoc/clean/inline.rs | 3 ++- .../passes/collect_intra_doc_links.rs | 1 + 25 files changed, 62 insertions(+), 48 deletions(-) diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index d1bccb961c48b..7cb1f3aa0e851 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -323,7 +323,7 @@ rustc_queries! { query associated_item(_: DefId) -> ty::AssocItem {} /// Collects the associated items defined on a trait or impl. - query associated_items(key: DefId) -> ty::AssocItemsIterator<'tcx> { + query associated_items(key: DefId) -> &'tcx [ty::AssocItem] { desc { |tcx| "collecting associated items of {}", tcx.def_path_str(key) } } diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 50068b89687ba..9e6e6047b35d2 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -539,6 +539,7 @@ fn vtable_methods<'tcx>( tcx.arena.alloc_from_iter(supertraits(tcx, trait_ref).flat_map(move |trait_ref| { let trait_methods = tcx .associated_items(trait_ref.def_id()) + .iter() .filter(|item| item.kind == ty::AssocKind::Method); // Now list each method's DefId and InternalSubsts (for within its trait). diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index d0dbfe73c91d5..3c886ce7f3eb7 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -212,6 +212,7 @@ fn object_safety_violations_for_trait( // Check methods for violations. let mut violations: Vec<_> = tcx .associated_items(trait_def_id) + .iter() .filter(|item| item.kind == ty::AssocKind::Method) .filter_map(|item| { object_safety_violation_for_method(tcx, trait_def_id, &item) @@ -277,6 +278,7 @@ fn object_safety_violations_for_trait( violations.extend( tcx.associated_items(trait_def_id) + .iter() .filter(|item| item.kind == ty::AssocKind::Const) .map(|item| ObjectSafetyViolation::AssocConst(item.ident.name, item.ident.span)), ); @@ -632,7 +634,9 @@ fn object_ty_for_trait<'tcx>( let mut associated_types = traits::supertraits(tcx, ty::Binder::dummy(trait_ref)) .flat_map(|super_trait_ref| { - tcx.associated_items(super_trait_ref.def_id()).map(move |item| (super_trait_ref, item)) + tcx.associated_items(super_trait_ref.def_id()) + .iter() + .map(move |item| (super_trait_ref, item)) }) .filter(|(_, item)| item.kind == ty::AssocKind::Type) .collect::>(); diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index fffcf66075f93..8ea990d1e937e 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -1436,7 +1436,7 @@ fn assoc_ty_def( { return specialization_graph::NodeItem { node: specialization_graph::Node::Impl(impl_def_id), - item, + item: *item, }; } } diff --git a/src/librustc/traits/types/specialization_graph.rs b/src/librustc/traits/types/specialization_graph.rs index 3086850db6d9c..36a84369d4a3a 100644 --- a/src/librustc/traits/types/specialization_graph.rs +++ b/src/librustc/traits/types/specialization_graph.rs @@ -81,7 +81,7 @@ impl<'tcx> Node { } /// Iterate over the items defined directly by the given (impl or trait) node. - pub fn items(&self, tcx: TyCtxt<'tcx>) -> ty::AssocItemsIterator<'tcx> { + pub fn items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [ty::AssocItem] { tcx.associated_items(self.def_id()) } @@ -98,8 +98,10 @@ impl<'tcx> Node { ) -> Option { use crate::ty::AssocKind::*; - tcx.associated_items(self.def_id()).find(move |impl_item| { - match (trait_item_kind, impl_item.kind) { + tcx.associated_items(self.def_id()) + .iter() + .find(move |impl_item| { + match (trait_item_kind, impl_item.kind) { | (Const, Const) | (Method, Method) | (Type, Type) @@ -112,7 +114,8 @@ impl<'tcx> Node { | (OpaqueTy, _) => false, } - }) + }) + .copied() } pub fn def_id(&self) -> DefId { diff --git a/src/librustc/traits/wf.rs b/src/librustc/traits/wf.rs index 9fa3c87477951..c44d45e75807e 100644 --- a/src/librustc/traits/wf.rs +++ b/src/librustc/traits/wf.rs @@ -166,7 +166,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { let extend_cause_with_original_assoc_item_obligation = |cause: &mut traits::ObligationCause<'_>, pred: &ty::Predicate<'_>, - trait_assoc_items: ty::AssocItemsIterator<'_>| { + trait_assoc_items: &[ty::AssocItem]| { let trait_item = tcx .hir() .as_local_hir_id(trait_ref.def_id) @@ -283,6 +283,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { ) = (&proj.skip_binder().self_ty().kind, item.map(|i| &i.kind)) { if let Some((impl_item, trait_assoc_item)) = trait_assoc_items + .iter() .filter(|i| i.def_id == *item_def_id) .next() .and_then(|trait_assoc_item| { @@ -325,7 +326,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { extend_cause_with_original_assoc_item_obligation( &mut cause, &pred, - trait_assoc_items.clone(), + trait_assoc_items, ); traits::Obligation::new(cause, param_env, pred) }); diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs index db034d1618cea..f4006a1cd40c1 100644 --- a/src/librustc/ty/adjustment.rs +++ b/src/librustc/ty/adjustment.rs @@ -122,6 +122,7 @@ impl<'tcx> OverloadedDeref<'tcx> { }; let method_def_id = tcx .associated_items(trait_def_id.unwrap()) + .iter() .find(|m| m.kind == ty::AssocKind::Method) .unwrap() .def_id; diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 51a18f8eae274..c7f19513f666e 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -376,6 +376,7 @@ impl<'tcx> Instance<'tcx> { let fn_once = tcx.lang_items().fn_once_trait().unwrap(); let call_once = tcx .associated_items(fn_once) + .iter() .find(|it| it.kind == ty::AssocKind::Method) .unwrap() .def_id; diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 2538322431ec9..62dc02eaa03ae 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2705,14 +2705,15 @@ impl<'tcx> TyCtxt<'tcx> { .for_each(|&body_id| f(self.hir().body_owner_def_id(body_id))); } - pub fn provided_trait_methods(self, id: DefId) -> Vec { + pub fn provided_trait_methods(self, id: DefId) -> Vec<&'tcx AssocItem> { self.associated_items(id) + .iter() .filter(|item| item.kind == AssocKind::Method && item.defaultness.has_value()) .collect() } pub fn trait_relevant_for_never(self, did: DefId) -> bool { - self.associated_items(did).any(|item| item.relevant_for_never()) + self.associated_items(did).iter().any(|item| item.relevant_for_never()) } pub fn opt_item_name(self, def_id: DefId) -> Option { @@ -2974,25 +2975,6 @@ impl<'tcx> TyCtxt<'tcx> { } } -#[derive(Copy, Clone, HashStable)] -pub struct AssocItemsIterator<'tcx> { - pub items: &'tcx [AssocItem], -} - -impl<'tcx> Iterator for AssocItemsIterator<'tcx> { - type Item = AssocItem; - - #[inline] - fn next(&mut self) -> Option { - if let Some((first, rest)) = self.items.split_first() { - self.items = rest; - Some(*first) - } else { - None - } - } -} - #[derive(Clone, HashStable)] pub struct AdtSizedConstraint<'tcx>(pub &'tcx [Ty<'tcx>]); diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 4c5bc3debde54..0718853b1df59 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -1066,6 +1066,7 @@ impl<'tcx> ProjectionTy<'tcx> { ) -> ProjectionTy<'tcx> { let item_def_id = tcx .associated_items(trait_ref.def_id) + .iter() .find(|item| { item.kind == ty::AssocKind::Type && tcx.hygienic_eq(item_name, item.ident, trait_ref.def_id) diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 4dfff85d53147..5d5fa4090c800 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -355,7 +355,7 @@ impl<'tcx> TyCtxt<'tcx> { let mut dtor_did = None; let ty = self.type_of(adt_did); self.for_each_relevant_impl(drop_trait, ty, |impl_did| { - if let Some(item) = self.associated_items(impl_did).next() { + if let Some(item) = self.associated_items(impl_did).first() { if validate(self, impl_did).is_ok() { dtor_did = Some(item.def_id); } diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 94a5f2b3bf86d..a8c66be359c4a 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -68,6 +68,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx let fn_mut = tcx.lang_items().fn_mut_trait().unwrap(); let call_mut = tcx .associated_items(fn_mut) + .iter() .find(|it| it.kind == ty::AssocKind::Method) .unwrap() .def_id; diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index 1be3da4b3d85a..091ae1bbb799d 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -539,7 +539,7 @@ where debug!("destructor_call_block({:?}, {:?})", self, succ); let tcx = self.tcx(); let drop_trait = tcx.lang_items().drop_trait().unwrap(); - let drop_fn = tcx.associated_items(drop_trait).next().unwrap(); + let drop_fn = tcx.associated_items(drop_trait)[0]; let ty = self.place_ty(self.place); let substs = tcx.mk_substs_trait(ty, &[]); diff --git a/src/librustc_passes/stability.rs b/src/librustc_passes/stability.rs index 4009cc6d725ab..12debfb66a431 100644 --- a/src/librustc_passes/stability.rs +++ b/src/librustc_passes/stability.rs @@ -468,6 +468,7 @@ impl Visitor<'tcx> for Checker<'tcx> { let trait_item_def_id = self .tcx .associated_items(trait_did) + .iter() .find(|item| item.ident.name == impl_item.ident.name) .map(|item| item.def_id); if let Some(def_id) = trait_item_def_id { diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index e32f47443667b..401e172275113 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -423,6 +423,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { qualname.push_str(&self.tcx.def_path_str(def_id)); self.tcx .associated_items(def_id) + .iter() .find(|item| item.ident.name == ident.name) .map(|item| decl_id = Some(item.def_id)); } @@ -717,6 +718,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { let ti = self.tcx.associated_item(decl_id); self.tcx .associated_items(ti.container.id()) + .iter() .find(|item| { item.ident.name == ti.ident.name && item.defaultness.has_value() }) diff --git a/src/librustc_ty/ty.rs b/src/librustc_ty/ty.rs index aa05165e3de32..b032acf82f582 100644 --- a/src/librustc_ty/ty.rs +++ b/src/librustc_ty/ty.rs @@ -206,12 +206,10 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] { } } -fn associated_items<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::AssocItemsIterator<'tcx> { - ty::AssocItemsIterator { - items: tcx.arena.alloc_from_iter( - tcx.associated_item_def_ids(def_id).iter().map(|did| tcx.associated_item(*did)), - ), - } +fn associated_items<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx [ty::AssocItem] { + tcx.arena.alloc_from_iter( + tcx.associated_item_def_ids(def_id).iter().map(|did| tcx.associated_item(*did)), + ) } fn def_span(tcx: TyCtxt<'_>, def_id: DefId) -> Span { diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 6bd120d818d09..2909d0f8c54e7 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1109,7 +1109,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { trait_def_id: DefId, assoc_name: ast::Ident, ) -> bool { - self.tcx().associated_items(trait_def_id).any(|item| { + self.tcx().associated_items(trait_def_id).iter().any(|item| { item.kind == ty::AssocKind::Type && self.tcx().hygienic_eq(assoc_name, item.ident, trait_def_id) }) @@ -1347,6 +1347,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { tcx.adjust_ident_and_get_scope(binding.item_name, candidate.def_id(), hir_ref_id); let assoc_ty = tcx .associated_items(candidate.def_id()) + .iter() .find(|i| i.kind == ty::AssocKind::Type && i.ident.modern() == assoc_ident) .expect("missing associated type"); @@ -1512,6 +1513,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ty::Predicate::Trait(pred, _) => { associated_types.entry(span).or_default().extend( tcx.associated_items(pred.def_id()) + .iter() .filter(|item| item.kind == ty::AssocKind::Type) .map(|item| item.def_id), ); @@ -1969,6 +1971,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let bound_span = self .tcx() .associated_items(bound.def_id()) + .iter() .find(|item| { item.kind == ty::AssocKind::Type && self.tcx().hygienic_eq(assoc_name, item.ident, bound.def_id()) @@ -2198,6 +2201,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { tcx.adjust_ident_and_get_scope(assoc_ident, trait_did, hir_ref_id); let item = tcx .associated_items(trait_did) + .iter() .find(|i| Namespace::from(i.kind) == Namespace::Type && i.ident.modern() == assoc_ident) .expect("missing associated type"); diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 26777b3b01048..707125b3fd522 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -248,7 +248,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if is_gen { // Check that we deduce the signature from the `<_ as std::ops::Generator>::Return` // associated item and not yield. - let return_assoc_item = self.tcx.associated_items(gen_trait).nth(1).unwrap().def_id; + let return_assoc_item = self.tcx.associated_items(gen_trait)[1].def_id; if return_assoc_item != projection.projection_def_id() { debug!("deduce_sig_from_projection: not return assoc item of generator"); return None; @@ -673,7 +673,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // The `Future` trait has only one associted item, `Output`, // so check that this is what we see. - let output_assoc_item = self.tcx.associated_items(future_trait).nth(0).unwrap().def_id; + let output_assoc_item = self.tcx.associated_items(future_trait)[0].def_id; if output_assoc_item != predicate.projection_ty.item_def_id { span_bug!( cause_span, diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index e0f9fcc69325c..8c7f1330820e3 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -536,6 +536,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let item_def_id = self .tcx .associated_items(deref_trait) + .iter() .find(|item| item.kind == ty::AssocKind::Type) .unwrap() .def_id; diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index e90c2ef5e4361..67d8030a9d69b 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -474,8 +474,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { item_name: ast::Ident, ns: Namespace, ) -> Option { - self.tcx.associated_items(def_id).find(|item| { - Namespace::from(item.kind) == ns && self.tcx.hygienic_eq(item_name, item.ident, def_id) - }) + self.tcx + .associated_items(def_id) + .iter() + .find(|item| { + Namespace::from(item.kind) == ns + && self.tcx.hygienic_eq(item_name, item.ident, def_id) + }) + .copied() } } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 2444fc60f77ba..497a401a031e5 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -1696,10 +1696,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let max_dist = max(name.as_str().len(), 3) / 3; self.tcx .associated_items(def_id) + .iter() .filter(|x| { let dist = lev_distance(&*name.as_str(), &x.ident.as_str()); Namespace::from(x.kind) == Namespace::Value && dist > 0 && dist <= max_dist }) + .copied() .collect() } else { self.fcx @@ -1707,7 +1709,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { .map_or(Vec::new(), |x| vec![x]) } } else { - self.tcx.associated_items(def_id).collect() + self.tcx.associated_items(def_id).to_vec() } } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 7e5d27d93b3cb..54a5330df399d 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1976,6 +1976,7 @@ fn check_impl_items_against_trait<'tcx>( let ty_impl_item = tcx.associated_item(tcx.hir().local_def_id(impl_item.hir_id)); let ty_trait_item = tcx .associated_items(impl_trait_ref.def_id) + .iter() .find(|ac| { Namespace::from(&impl_item.kind) == Namespace::from(ac.kind) && tcx.hygienic_eq(ty_impl_item.ident, ac.ident, impl_trait_ref.def_id) @@ -1983,6 +1984,7 @@ fn check_impl_items_against_trait<'tcx>( .or_else(|| { // Not compatible, but needed for the error message tcx.associated_items(impl_trait_ref.def_id) + .iter() .find(|ac| tcx.hygienic_eq(ty_impl_item.ident, ac.ident, impl_trait_ref.def_id)) }); @@ -2096,7 +2098,7 @@ fn check_impl_items_against_trait<'tcx>( if !is_implemented && !traits::impl_is_default(tcx, impl_id) { if !trait_item.defaultness.has_value() { - missing_items.push(trait_item); + missing_items.push(*trait_item); } else if associated_type_overridden { invalidated_items.push(trait_item.ident); } @@ -5096,7 +5098,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Check for `Future` implementations by constructing a predicate to // prove: `::Output == U` let future_trait = self.tcx.lang_items().future_trait().unwrap(); - let item_def_id = self.tcx.associated_items(future_trait).next().unwrap().def_id; + let item_def_id = self.tcx.associated_items(future_trait)[0].def_id; let predicate = ty::Predicate::Projection(ty::Binder::bind(ty::ProjectionPredicate { // `::Output` diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 18ebd254507ea..818e0a0f93a01 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -115,6 +115,8 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { .cx .tcx .associated_items(impl_def_id) + .iter() + .copied() .collect::>() .clean(self.cx), polarity: None, diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index df72bf0b56e61..90eb557d5e125 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -191,7 +191,7 @@ pub fn record_extern_fqn(cx: &DocContext<'_>, did: DefId, kind: clean::TypeKind) pub fn build_external_trait(cx: &DocContext<'_>, did: DefId) -> clean::Trait { let auto_trait = cx.tcx.trait_def(did).has_auto_impl; - let trait_items = cx.tcx.associated_items(did).map(|item| item.clean(cx)).collect(); + let trait_items = cx.tcx.associated_items(did).iter().map(|item| item.clean(cx)).collect(); let predicates = cx.tcx.predicates_of(did); let generics = (cx.tcx.generics_of(did), predicates).clean(cx); let generics = filter_non_trait_generics(did, generics); @@ -376,6 +376,7 @@ pub fn build_impl( } else { ( tcx.associated_items(did) + .iter() .filter_map(|item| { if associated_trait.is_some() || item.vis == ty::Visibility::Public { Some(item.clean(cx)) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 332d19fbfaeca..9ecf6d531299f 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -206,6 +206,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { return cx .tcx .associated_items(did) + .iter() .find(|item| item.ident.name == item_name) .and_then(|item| match item.kind { ty::AssocKind::Method => Some("method"), From f4165731ad0445dc801b43b6b125c7178d5c70ff Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Thu, 6 Feb 2020 23:50:08 +0100 Subject: [PATCH 14/17] Use `associated_items` query in impl overlap check This reduces the number of `associated_item` queries done here. --- .../coherence/inherent_impls_overlap.rs | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/librustc_typeck/coherence/inherent_impls_overlap.rs b/src/librustc_typeck/coherence/inherent_impls_overlap.rs index 3e17b661cf4ce..8234801ff8077 100644 --- a/src/librustc_typeck/coherence/inherent_impls_overlap.rs +++ b/src/librustc_typeck/coherence/inherent_impls_overlap.rs @@ -23,32 +23,30 @@ impl InherentOverlapChecker<'tcx> { impl2: DefId, overlap: traits::OverlapResult<'_>, ) { - let name_and_namespace = |def_id| { - let item = self.tcx.associated_item(def_id); - (item.ident.modern(), Namespace::from(item.kind)) - }; + let name_and_namespace = + |assoc: &AssocItem| (assoc.ident.modern(), Namespace::from(assoc.kind)); - let impl_items1 = self.tcx.associated_item_def_ids(impl1); - let impl_items2 = self.tcx.associated_item_def_ids(impl2); + let impl_items1 = self.tcx.associated_items(impl1); + let impl_items2 = self.tcx.associated_items(impl2); - for &item1 in &impl_items1[..] { + for item1 in &impl_items1[..] { let (name, namespace) = name_and_namespace(item1); - for &item2 in &impl_items2[..] { + for item2 in &impl_items2[..] { if (name, namespace) == name_and_namespace(item2) { let mut err = struct_span_err!( self.tcx.sess, - self.tcx.span_of_impl(item1).unwrap(), + self.tcx.span_of_impl(item1.def_id).unwrap(), E0592, "duplicate definitions with name `{}`", name ); err.span_label( - self.tcx.span_of_impl(item1).unwrap(), + self.tcx.span_of_impl(item1.def_id).unwrap(), format!("duplicate definitions for `{}`", name), ); err.span_label( - self.tcx.span_of_impl(item2).unwrap(), + self.tcx.span_of_impl(item2.def_id).unwrap(), format!("other definition for `{}`", name), ); From 52f77110d455b6b946ae0ca36a4671bdd9b7e145 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Fri, 7 Feb 2020 00:52:35 +0100 Subject: [PATCH 15/17] Add a fast path to inherent impl overlap check Quickly skip impls that do not define any items with the same name --- .../coherence/inherent_impls_overlap.rs | 72 +++++++++++++------ 1 file changed, 49 insertions(+), 23 deletions(-) diff --git a/src/librustc_typeck/coherence/inherent_impls_overlap.rs b/src/librustc_typeck/coherence/inherent_impls_overlap.rs index 8234801ff8077..97aa77c6516f3 100644 --- a/src/librustc_typeck/coherence/inherent_impls_overlap.rs +++ b/src/librustc_typeck/coherence/inherent_impls_overlap.rs @@ -17,6 +17,30 @@ struct InherentOverlapChecker<'tcx> { } impl InherentOverlapChecker<'tcx> { + /// Checks whether any associated items in impls 1 and 2 share the same identifier and + /// namespace. + fn impls_have_common_items(&self, impl1: DefId, impl2: DefId) -> bool { + let impl_items1 = self.tcx.associated_items(impl1); + let impl_items2 = self.tcx.associated_items(impl2); + + for item1 in &impl_items1[..] { + for item2 in &impl_items2[..] { + // Avoid costly `.modern()` calls as much as possible by doing them as late as we + // can. Compare raw symbols first. + if item1.ident.name == item2.ident.name + && Namespace::from(item1.kind) == Namespace::from(item2.kind) + { + // Symbols and namespace match, compare hygienically. + if item1.ident.modern() == item2.ident.modern() { + return true; + } + } + } + } + + false + } + fn check_for_common_items_in_impls( &self, impl1: DefId, @@ -64,27 +88,21 @@ impl InherentOverlapChecker<'tcx> { } } - fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) { - let impls = self.tcx.inherent_impls(ty_def_id); - - for (i, &impl1_def_id) in impls.iter().enumerate() { - for &impl2_def_id in &impls[(i + 1)..] { - traits::overlapping_impls( - self.tcx, - impl1_def_id, - impl2_def_id, - IntercrateMode::Issue43355, - // We go ahead and just skip the leak check for - // inherent impls without warning. - SkipLeakCheck::Yes, - |overlap| { - self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id, overlap); - false - }, - || true, - ); - } - } + fn check_for_overlapping_inherent_impls(&self, impl1_def_id: DefId, impl2_def_id: DefId) { + traits::overlapping_impls( + self.tcx, + impl1_def_id, + impl2_def_id, + IntercrateMode::Issue43355, + // We go ahead and just skip the leak check for + // inherent impls without warning. + SkipLeakCheck::Yes, + |overlap| { + self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id, overlap); + false + }, + || true, + ); } } @@ -95,8 +113,16 @@ impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> { | hir::ItemKind::Struct(..) | hir::ItemKind::Trait(..) | hir::ItemKind::Union(..) => { - let type_def_id = self.tcx.hir().local_def_id(item.hir_id); - self.check_for_overlapping_inherent_impls(type_def_id); + let ty_def_id = self.tcx.hir().local_def_id(item.hir_id); + let impls = self.tcx.inherent_impls(ty_def_id); + + for (i, &impl1_def_id) in impls.iter().enumerate() { + for &impl2_def_id in &impls[(i + 1)..] { + if self.impls_have_common_items(impl1_def_id, impl2_def_id) { + self.check_for_overlapping_inherent_impls(impl1_def_id, impl2_def_id); + } + } + } } _ => {} } From e0cb1ae24abb9242263d0bbf40f631bd95512406 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Fri, 7 Feb 2020 21:33:23 +0100 Subject: [PATCH 16/17] Make `provided_trait_methods` use `impl Iterator` --- src/librustc/ty/mod.rs | 3 +-- src/librustc_passes/reachable.rs | 12 ++++++------ src/librustdoc/clean/blanket_impl.rs | 1 - src/librustdoc/clean/inline.rs | 4 +--- src/librustdoc/clean/mod.rs | 6 +----- 5 files changed, 9 insertions(+), 17 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 62dc02eaa03ae..0118fc4c8ac84 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2705,11 +2705,10 @@ impl<'tcx> TyCtxt<'tcx> { .for_each(|&body_id| f(self.hir().body_owner_def_id(body_id))); } - pub fn provided_trait_methods(self, id: DefId) -> Vec<&'tcx AssocItem> { + pub fn provided_trait_methods(self, id: DefId) -> impl Iterator { self.associated_items(id) .iter() .filter(|item| item.kind == AssocKind::Method && item.defaultness.has_value()) - .collect() } pub fn trait_relevant_for_never(self, did: DefId) -> bool { diff --git a/src/librustc_passes/reachable.rs b/src/librustc_passes/reachable.rs index 667898046ac36..888f4370dd5e8 100644 --- a/src/librustc_passes/reachable.rs +++ b/src/librustc_passes/reachable.rs @@ -362,12 +362,12 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, 'tcx return; } - let provided_trait_methods = self.tcx.provided_trait_methods(trait_def_id); - self.worklist.reserve(provided_trait_methods.len()); - for default_method in provided_trait_methods { - let hir_id = self.tcx.hir().as_local_hir_id(default_method.def_id).unwrap(); - self.worklist.push(hir_id); - } + // FIXME(#53488) remove `let` + let tcx = self.tcx; + self.worklist.extend( + tcx.provided_trait_methods(trait_def_id) + .map(|assoc| tcx.hir().as_local_hir_id(assoc.def_id).unwrap()), + ); } } } diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 818e0a0f93a01..288446b6219ce 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -87,7 +87,6 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { .cx .tcx .provided_trait_methods(trait_def_id) - .into_iter() .map(|meth| meth.ident.to_string()) .collect(); diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 90eb557d5e125..90ce8802f6584 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -402,9 +402,7 @@ pub fn build_impl( let provided = trait_ .def_id() - .map(|did| { - tcx.provided_trait_methods(did).into_iter().map(|meth| meth.ident.to_string()).collect() - }) + .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.ident.to_string()).collect()) .unwrap_or_default(); debug!("build_impl: impl {:?} for {:?}", trait_.def_id(), for_.def_id()); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index f140f11b09098..87edc88611f3a 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2108,11 +2108,7 @@ impl Clean> for doctree::Impl<'_> { let provided: FxHashSet = trait_ .def_id() .map(|did| { - cx.tcx - .provided_trait_methods(did) - .into_iter() - .map(|meth| meth.ident.to_string()) - .collect() + cx.tcx.provided_trait_methods(did).map(|meth| meth.ident.to_string()).collect() }) .unwrap_or_default(); From 58a9284bff045ef81f38b730043b5acb00485d0e Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sat, 8 Feb 2020 14:44:32 +0100 Subject: [PATCH 17/17] Add missing import --- src/librustc_typeck/coherence/inherent_impls_overlap.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_typeck/coherence/inherent_impls_overlap.rs b/src/librustc_typeck/coherence/inherent_impls_overlap.rs index 97aa77c6516f3..fb9c173f52000 100644 --- a/src/librustc_typeck/coherence/inherent_impls_overlap.rs +++ b/src/librustc_typeck/coherence/inherent_impls_overlap.rs @@ -1,6 +1,6 @@ use crate::namespace::Namespace; use rustc::traits::{self, IntercrateMode, SkipLeakCheck}; -use rustc::ty::TyCtxt; +use rustc::ty::{AssocItem, TyCtxt}; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};