diff options
78 files changed, 695 insertions, 791 deletions
diff --git a/.gitignore b/.gitignore index 3f77e6884b9..0cd6b9f648d 100644 --- a/.gitignore +++ b/.gitignore @@ -5,53 +5,71 @@ # created during manual debugging and many people like to clean up instead of # having git ignore such leftovers. You can use `.git/info/exclude` to # configure your local ignore list. -# FIXME: This needs cleanup. -*~ + +## File system +.DS_Store +desktop.ini + +## Editor *.swp *.swo -.#* -.DS_Store +Session.vim .cproject -.hg/ -.hgignore .idea *.iml -__pycache__/ -*.py[cod] -*$py.class +.vscode .project +.favorites.json .settings/ + +## Tool .valgrindrc -.vscode -.favorites.json -/Makefile -/build/ +.cargo +# Included because it is part of the test case +!/src/test/run-make/thumb-none-qemu/example/.cargo + +## Configuration /config.toml -/dist/ +/Makefile +config.mk +config.stamp +no_llvm_build + +## Build /dl/ /doc/ /inst/ /llvm/ /mingw-build/ -/src/tools/x/target -# Created by default with `src/ci/docker/run.sh`: -/obj/ +/build/ +/dist/ /unicode-downloads /target -# Generated by compiletest for incremental: +/src/tools/x/target +# Generated by compiletest for incremental /tmp/ +# Created by default with `src/ci/docker/run.sh` +/obj/ + +## Temporary files +*~ +\#* +\#*\# +.#* + +## Tags tags tags.* TAGS TAGS.* -\#* -\#*\# -config.mk -config.stamp -Session.vim -.cargo -!/src/test/run-make/thumb-none-qemu/example/.cargo -no_llvm_build + +## Python +__pycache__/ +*.py[cod] +*$py.class + +## Node **node_modules **package-lock.json + # Before adding new lines, see the comment at the top. diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index f823792fabe..053cda1e7cc 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -2,6 +2,7 @@ use crate::common::Funclet; use crate::context::CodegenCx; use crate::llvm::{self, BasicBlock, False}; use crate::llvm::{AtomicOrdering, AtomicRmwBinOp, SynchronizationScope}; +use crate::llvm_util; use crate::type_::Type; use crate::type_of::LayoutLlvmExt; use crate::value::Value; @@ -16,7 +17,7 @@ use rustc_data_structures::small_c_str::SmallCStr; use rustc_hir::def_id::DefId; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::{sym, Span}; +use rustc_span::Span; use rustc_target::abi::{self, Align, Size}; use rustc_target::spec::{HasTargetSpec, Target}; use std::borrow::Cow; @@ -669,81 +670,47 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } fn fptoui_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> Option<&'ll Value> { - // WebAssembly has saturating floating point to integer casts if the - // `nontrapping-fptoint` target feature is activated. We'll use those if - // they are available. - if self.sess().target.arch == "wasm32" - && self.sess().target_features.contains(&sym::nontrapping_dash_fptoint) - { + if llvm_util::get_version() >= (12, 0, 0) && !self.fptoint_sat_broken_in_llvm() { let src_ty = self.cx.val_ty(val); let float_width = self.cx.float_width(src_ty); let int_width = self.cx.int_width(dest_ty); - let name = match (int_width, float_width) { - (32, 32) => Some("llvm.wasm.trunc.saturate.unsigned.i32.f32"), - (32, 64) => Some("llvm.wasm.trunc.saturate.unsigned.i32.f64"), - (64, 32) => Some("llvm.wasm.trunc.saturate.unsigned.i64.f32"), - (64, 64) => Some("llvm.wasm.trunc.saturate.unsigned.i64.f64"), - _ => None, - }; - if let Some(name) = name { - let intrinsic = self.get_intrinsic(name); - return Some(self.call(intrinsic, &[val], None)); - } + let name = format!("llvm.fptoui.sat.i{}.f{}", int_width, float_width); + let intrinsic = self.get_intrinsic(&name); + return Some(self.call(intrinsic, &[val], None)); } + None } fn fptosi_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> Option<&'ll Value> { - // WebAssembly has saturating floating point to integer casts if the - // `nontrapping-fptoint` target feature is activated. We'll use those if - // they are available. - if self.sess().target.arch == "wasm32" - && self.sess().target_features.contains(&sym::nontrapping_dash_fptoint) - { + if llvm_util::get_version() >= (12, 0, 0) && !self.fptoint_sat_broken_in_llvm() { let src_ty = self.cx.val_ty(val); let float_width = self.cx.float_width(src_ty); let int_width = self.cx.int_width(dest_ty); - let name = match (int_width, float_width) { - (32, 32) => Some("llvm.wasm.trunc.saturate.signed.i32.f32"), - (32, 64) => Some("llvm.wasm.trunc.saturate.signed.i32.f64"), - (64, 32) => Some("llvm.wasm.trunc.saturate.signed.i64.f32"), - (64, 64) => Some("llvm.wasm.trunc.saturate.signed.i64.f64"), - _ => None, - }; - if let Some(name) = name { - let intrinsic = self.get_intrinsic(name); - return Some(self.call(intrinsic, &[val], None)); - } + let name = format!("llvm.fptosi.sat.i{}.f{}", int_width, float_width); + let intrinsic = self.get_intrinsic(&name); + return Some(self.call(intrinsic, &[val], None)); } - None - } - fn fptosui_may_trap(&self, val: &'ll Value, dest_ty: &'ll Type) -> bool { - // Most of the time we'll be generating the `fptosi` or `fptoui` - // instruction for floating-point-to-integer conversions. These - // instructions by definition in LLVM do not trap. For the WebAssembly - // target, however, we'll lower in some cases to intrinsic calls instead - // which may trap. If we detect that this is a situation where we'll be - // using the intrinsics then we report that the call map trap, which - // callers might need to handle. - if !self.wasm_and_missing_nontrapping_fptoint() { - return false; - } - let src_ty = self.cx.val_ty(val); - let float_width = self.cx.float_width(src_ty); - let int_width = self.cx.int_width(dest_ty); - matches!((int_width, float_width), (32, 32) | (32, 64) | (64, 32) | (64, 64)) + None } fn fptoui(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { - // When we can, use the native wasm intrinsics which have tighter - // codegen. Note that this has a semantic difference in that the - // intrinsic can trap whereas `fptoui` never traps. That difference, - // however, is handled by `fptosui_may_trap` above. + // On WebAssembly the `fptoui` and `fptosi` instructions currently have + // poor codegen. The reason for this is that the corresponding wasm + // instructions, `i32.trunc_f32_s` for example, will trap when the float + // is out-of-bounds, infinity, or nan. This means that LLVM + // automatically inserts control flow around `fptoui` and `fptosi` + // because the LLVM instruction `fptoui` is defined as producing a + // poison value, not having UB on out-of-bounds values. // - // Note that we skip the wasm intrinsics for vector types where `fptoui` - // must be used instead. - if self.wasm_and_missing_nontrapping_fptoint() { + // This method, however, is only used with non-saturating casts that + // have UB on out-of-bounds values. This means that it's ok if we use + // the raw wasm instruction since out-of-bounds values can do whatever + // we like. To ensure that LLVM picks the right instruction we choose + // the raw wasm intrinsic functions which avoid LLVM inserting all the + // other control flow automatically. + if self.sess().target.arch == "wasm32" { let src_ty = self.cx.val_ty(val); if self.cx.type_kind(src_ty) != TypeKind::Vector { let float_width = self.cx.float_width(src_ty); @@ -765,7 +732,8 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } fn fptosi(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { - if self.wasm_and_missing_nontrapping_fptoint() { + // see `fptoui` above for why wasm is different here + if self.sess().target.arch == "wasm32" { let src_ty = self.cx.val_ty(val); if self.cx.type_kind(src_ty) != TypeKind::Vector { let float_width = self.cx.float_width(src_ty); @@ -1420,8 +1388,11 @@ impl Builder<'a, 'll, 'tcx> { } } - fn wasm_and_missing_nontrapping_fptoint(&self) -> bool { - self.sess().target.arch == "wasm32" - && !self.sess().target_features.contains(&sym::nontrapping_dash_fptoint) + fn fptoint_sat_broken_in_llvm(&self) -> bool { + match self.tcx.sess.target.arch.as_str() { + // FIXME - https://bugs.llvm.org/show_bug.cgi?id=50083 + "riscv64" => llvm_util::get_version() < (13, 0, 0), + _ => false, + } } } diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 773c0c16328..f5c54b11c08 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -503,14 +503,6 @@ impl CodegenCx<'b, 'tcx> { let t_f32 = self.type_f32(); let t_f64 = self.type_f64(); - ifn!("llvm.wasm.trunc.saturate.unsigned.i32.f32", fn(t_f32) -> t_i32); - ifn!("llvm.wasm.trunc.saturate.unsigned.i32.f64", fn(t_f64) -> t_i32); - ifn!("llvm.wasm.trunc.saturate.unsigned.i64.f32", fn(t_f32) -> t_i64); - ifn!("llvm.wasm.trunc.saturate.unsigned.i64.f64", fn(t_f64) -> t_i64); - ifn!("llvm.wasm.trunc.saturate.signed.i32.f32", fn(t_f32) -> t_i32); - ifn!("llvm.wasm.trunc.saturate.signed.i32.f64", fn(t_f64) -> t_i32); - ifn!("llvm.wasm.trunc.saturate.signed.i64.f32", fn(t_f32) -> t_i64); - ifn!("llvm.wasm.trunc.saturate.signed.i64.f64", fn(t_f64) -> t_i64); ifn!("llvm.wasm.trunc.unsigned.i32.f32", fn(t_f32) -> t_i32); ifn!("llvm.wasm.trunc.unsigned.i32.f64", fn(t_f64) -> t_i32); ifn!("llvm.wasm.trunc.unsigned.i64.f32", fn(t_f32) -> t_i64); @@ -520,6 +512,28 @@ impl CodegenCx<'b, 'tcx> { ifn!("llvm.wasm.trunc.signed.i64.f32", fn(t_f32) -> t_i64); ifn!("llvm.wasm.trunc.signed.i64.f64", fn(t_f64) -> t_i64); + ifn!("llvm.fptosi.sat.i8.f32", fn(t_f32) -> t_i8); + ifn!("llvm.fptosi.sat.i16.f32", fn(t_f32) -> t_i16); + ifn!("llvm.fptosi.sat.i32.f32", fn(t_f32) -> t_i32); + ifn!("llvm.fptosi.sat.i64.f32", fn(t_f32) -> t_i64); + ifn!("llvm.fptosi.sat.i128.f32", fn(t_f32) -> t_i128); + ifn!("llvm.fptosi.sat.i8.f64", fn(t_f64) -> t_i8); + ifn!("llvm.fptosi.sat.i16.f64", fn(t_f64) -> t_i16); + ifn!("llvm.fptosi.sat.i32.f64", fn(t_f64) -> t_i32); + ifn!("llvm.fptosi.sat.i64.f64", fn(t_f64) -> t_i64); + ifn!("llvm.fptosi.sat.i128.f64", fn(t_f64) -> t_i128); + + ifn!("llvm.fptoui.sat.i8.f32", fn(t_f32) -> t_i8); + ifn!("llvm.fptoui.sat.i16.f32", fn(t_f32) -> t_i16); + ifn!("llvm.fptoui.sat.i32.f32", fn(t_f32) -> t_i32); + ifn!("llvm.fptoui.sat.i64.f32", fn(t_f32) -> t_i64); + ifn!("llvm.fptoui.sat.i128.f32", fn(t_f32) -> t_i128); + ifn!("llvm.fptoui.sat.i8.f64", fn(t_f64) -> t_i8); + ifn!("llvm.fptoui.sat.i16.f64", fn(t_f64) -> t_i16); + ifn!("llvm.fptoui.sat.i32.f64", fn(t_f64) -> t_i32); + ifn!("llvm.fptoui.sat.i64.f64", fn(t_f64) -> t_i64); + ifn!("llvm.fptoui.sat.i128.f64", fn(t_f64) -> t_i128); + ifn!("llvm.trap", fn() -> void); ifn!("llvm.debugtrap", fn() -> void); ifn!("llvm.frameaddress", fn(t_i32) -> i8p); diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 629cb64d43e..9917c23f121 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -11,7 +11,7 @@ use rustc_apfloat::{ieee, Float, Round, Status}; use rustc_hir::lang_items::LangItem; use rustc_middle::mir; use rustc_middle::ty::cast::{CastTy, IntTy}; -use rustc_middle::ty::layout::{HasTyCtxt, TyAndLayout}; +use rustc_middle::ty::layout::HasTyCtxt; use rustc_middle::ty::{self, adjustment::PointerCast, Instance, Ty, TyCtxt}; use rustc_span::source_map::{Span, DUMMY_SP}; use rustc_span::symbol::sym; @@ -385,10 +385,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.inttoptr(usize_llval, ll_t_out) } (CastTy::Float, CastTy::Int(IntTy::I)) => { - cast_float_to_int(&mut bx, true, llval, ll_t_in, ll_t_out, cast) + cast_float_to_int(&mut bx, true, llval, ll_t_in, ll_t_out) } (CastTy::Float, CastTy::Int(_)) => { - cast_float_to_int(&mut bx, false, llval, ll_t_in, ll_t_out, cast) + cast_float_to_int(&mut bx, false, llval, ll_t_in, ll_t_out) } _ => bug!("unsupported cast: {:?} to {:?}", operand.layout.ty, cast.ty), }; @@ -790,7 +790,6 @@ fn cast_float_to_int<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( x: Bx::Value, float_ty: Bx::Type, int_ty: Bx::Type, - int_layout: TyAndLayout<'tcx>, ) -> Bx::Value { if let Some(false) = bx.cx().sess().opts.debugging_opts.saturating_float_casts { return if signed { bx.fptosi(x, int_ty) } else { bx.fptoui(x, int_ty) }; @@ -891,134 +890,39 @@ fn cast_float_to_int<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let int_min = bx.cx().const_uint_big(int_ty, int_min(signed, int_width) as u128); let zero = bx.cx().const_uint(int_ty, 0); - // The codegen here differs quite a bit depending on whether our builder's - // `fptosi` and `fptoui` instructions may trap for out-of-bounds values. If - // they don't trap then we can start doing everything inline with a - // `select` instruction because it's ok to execute `fptosi` and `fptoui` - // even if we don't use the results. - if !bx.fptosui_may_trap(x, int_ty) { - // Step 1 ... - let fptosui_result = if signed { bx.fptosi(x, int_ty) } else { bx.fptoui(x, int_ty) }; - let less_or_nan = bx.fcmp(RealPredicate::RealULT, x, f_min); - let greater = bx.fcmp(RealPredicate::RealOGT, x, f_max); - - // Step 2: We use two comparisons and two selects, with %s1 being the - // result: - // %less_or_nan = fcmp ult %x, %f_min - // %greater = fcmp olt %x, %f_max - // %s0 = select %less_or_nan, int_ty::MIN, %fptosi_result - // %s1 = select %greater, int_ty::MAX, %s0 - // Note that %less_or_nan uses an *unordered* comparison. This - // comparison is true if the operands are not comparable (i.e., if x is - // NaN). The unordered comparison ensures that s1 becomes int_ty::MIN if - // x is NaN. - // - // Performance note: Unordered comparison can be lowered to a "flipped" - // comparison and a negation, and the negation can be merged into the - // select. Therefore, it not necessarily any more expensive than a - // ordered ("normal") comparison. Whether these optimizations will be - // performed is ultimately up to the backend, but at least x86 does - // perform them. - let s0 = bx.select(less_or_nan, int_min, fptosui_result); - let s1 = bx.select(greater, int_max, s0); - - // Step 3: NaN replacement. - // For unsigned types, the above step already yielded int_ty::MIN == 0 if x is NaN. - // Therefore we only need to execute this step for signed integer types. - if signed { - // LLVM has no isNaN predicate, so we use (x == x) instead - let cmp = bx.fcmp(RealPredicate::RealOEQ, x, x); - bx.select(cmp, s1, zero) - } else { - s1 - } + // Step 1 ... + let fptosui_result = if signed { bx.fptosi(x, int_ty) } else { bx.fptoui(x, int_ty) }; + let less_or_nan = bx.fcmp(RealPredicate::RealULT, x, f_min); + let greater = bx.fcmp(RealPredicate::RealOGT, x, f_max); + + // Step 2: We use two comparisons and two selects, with %s1 being the + // result: + // %less_or_nan = fcmp ult %x, %f_min + // %greater = fcmp olt %x, %f_max + // %s0 = select %less_or_nan, int_ty::MIN, %fptosi_result + // %s1 = select %greater, int_ty::MAX, %s0 + // Note that %less_or_nan uses an *unordered* comparison. This + // comparison is true if the operands are not comparable (i.e., if x is + // NaN). The unordered comparison ensures that s1 becomes int_ty::MIN if + // x is NaN. + // + // Performance note: Unordered comparison can be lowered to a "flipped" + // comparison and a negation, and the negation can be merged into the + // select. Therefore, it not necessarily any more expensive than a + // ordered ("normal") comparison. Whether these optimizations will be + // performed is ultimately up to the backend, but at least x86 does + // perform them. + let s0 = bx.select(less_or_nan, int_min, fptosui_result); + let s1 = bx.select(greater, int_max, s0); + + // Step 3: NaN replacement. + // For unsigned types, the above step already yielded int_ty::MIN == 0 if x is NaN. + // Therefore we only need to execute this step for signed integer types. + if signed { + // LLVM has no isNaN predicate, so we use (x == x) instead + let cmp = bx.fcmp(RealPredicate::RealOEQ, x, x); + bx.select(cmp, s1, zero) } else { - // In this case we cannot execute `fptosi` or `fptoui` and then later - // discard the result. The builder is telling us that these instructions - // will trap on out-of-bounds values, so we need to use basic blocks and - // control flow to avoid executing the `fptosi` and `fptoui` - // instructions. - // - // The general idea of what we're constructing here is, for f64 -> i32: - // - // ;; block so far... %0 is the argument - // %result = alloca i32, align 4 - // %inbound_lower = fcmp oge double %0, 0xC1E0000000000000 - // %inbound_upper = fcmp ole double %0, 0x41DFFFFFFFC00000 - // ;; match (inbound_lower, inbound_upper) { - // ;; (true, true) => %0 can be converted without trapping - // ;; (false, false) => %0 is a NaN - // ;; (true, false) => %0 is too large - // ;; (false, true) => %0 is too small - // ;; } - // ;; - // ;; The (true, true) check, go to %convert if so. - // %inbounds = and i1 %inbound_lower, %inbound_upper - // br i1 %inbounds, label %convert, label %specialcase - // - // convert: - // %cvt = call i32 @llvm.wasm.trunc.signed.i32.f64(double %0) - // store i32 %cvt, i32* %result, align 4 - // br label %done - // - // specialcase: - // ;; Handle the cases where the number is NaN, too large or too small - // - // ;; Either (true, false) or (false, true) - // %is_not_nan = or i1 %inbound_lower, %inbound_upper - // ;; Figure out which saturated value we are interested in if not `NaN` - // %saturated = select i1 %inbound_lower, i32 2147483647, i32 -2147483648 - // ;; Figure out between saturated and NaN representations - // %result_nan = select i1 %is_not_nan, i32 %saturated, i32 0 - // store i32 %result_nan, i32* %result, align 4 - // br label %done - // - // done: - // %r = load i32, i32* %result, align 4 - // ;; ... - let done = bx.build_sibling_block("float_cast_done"); - let mut convert = bx.build_sibling_block("float_cast_convert"); - let mut specialcase = bx.build_sibling_block("float_cast_specialcase"); - - let result = PlaceRef::alloca(bx, int_layout); - result.storage_live(bx); - - // Use control flow to figure out whether we can execute `fptosi` in a - // basic block, or whether we go to a different basic block to implement - // the saturating logic. - let inbound_lower = bx.fcmp(RealPredicate::RealOGE, x, f_min); - let inbound_upper = bx.fcmp(RealPredicate::RealOLE, x, f_max); - let inbounds = bx.and(inbound_lower, inbound_upper); - bx.cond_br(inbounds, convert.llbb(), specialcase.llbb()); - - // Translation of the `convert` basic block - let cvt = if signed { convert.fptosi(x, int_ty) } else { convert.fptoui(x, int_ty) }; - convert.store(cvt, result.llval, result.align); - convert.br(done.llbb()); - - // Translation of the `specialcase` basic block. Note that like above - // we try to be a bit clever here for unsigned conversions. In those - // cases the `int_min` is zero so we don't need two select instructions, - // just one to choose whether we need `int_max` or not. If - // `inbound_lower` is true then we're guaranteed to not be `NaN` and - // since we're greater than zero we must be saturating to `int_max`. If - // `inbound_lower` is false then we're either NaN or less than zero, so - // we saturate to zero. - let result_nan = if signed { - let is_not_nan = specialcase.or(inbound_lower, inbound_upper); - let saturated = specialcase.select(inbound_lower, int_max, int_min); - specialcase.select(is_not_nan, saturated, zero) - } else { - specialcase.select(inbound_lower, int_max, int_min) - }; - specialcase.store(result_nan, result.llval, result.align); - specialcase.br(done.llbb()); - - // Translation of the `done` basic block, positioning ourselves to - // continue from that point as well. - *bx = done; - let ret = bx.load(result.llval, result.align); - result.storage_dead(bx); - ret + s1 } } diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index d5bd2780388..1bc05f30e5c 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -171,7 +171,6 @@ pub trait BuilderMethods<'a, 'tcx>: fn sext(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value; fn fptoui_sat(&mut self, val: Self::Value, dest_ty: Self::Type) -> Option<Self::Value>; fn fptosi_sat(&mut self, val: Self::Value, dest_ty: Self::Type) -> Option<Self::Value>; - fn fptosui_may_trap(&self, val: Self::Value, dest_ty: Self::Type) -> bool; fn fptoui(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value; fn fptosi(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value; fn uitofp(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value; diff --git a/compiler/rustc_error_codes/src/error_codes/E0404.md b/compiler/rustc_error_codes/src/error_codes/E0404.md index 1360cc99afc..d6fa51e618c 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0404.md +++ b/compiler/rustc_error_codes/src/error_codes/E0404.md @@ -8,14 +8,15 @@ struct Foo; struct Bar; impl Foo for Bar {} // error: `Foo` is not a trait +fn baz<T: Foo>(t: T) {} // error: `Foo` is not a trait ``` Another erroneous code example: ```compile_fail,E0404 -struct Foo; +type Foo = Iterator<Item=String>; -fn bar<T: Foo>(t: T) {} // error: `Foo` is not a trait +fn bar<T: Foo>(t: T) {} // error: `Foo` is a type alias ``` Please verify that the trait's name was not misspelled or that the right @@ -30,14 +31,27 @@ struct Bar; impl Foo for Bar { // ok! // functions implementation } + +fn baz<T: Foo>(t: T) {} // ok! ``` -or: +Alternatively, you could introduce a new trait with your desired restrictions +as a super trait: ``` -trait Foo { - // some functions -} +# trait Foo {} +# struct Bar; +# impl Foo for Bar {} +trait Qux: Foo {} // Anything that implements Qux also needs to implement Foo +fn baz<T: Qux>(t: T) {} // also ok! +``` + +Finally, if you are on nightly and want to use a trait alias +instead of a type alias, you should use `#![feature(trait_alias)]`: + +``` +#![feature(trait_alias)] +trait Foo = Iterator<Item=String>; fn bar<T: Foo>(t: T) {} // ok! ``` diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 1051fb8cea2..685429863fa 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2201,7 +2201,7 @@ impl PrimTy { /// Like [`PrimTy::name`], but returns a &str instead of a symbol. /// - /// Used by rustdoc. + /// Used by clippy. pub fn name_str(self) -> &'static str { match self { PrimTy::Int(i) => i.name_str(), diff --git a/compiler/rustc_mir/src/transform/coverage/mod.rs b/compiler/rustc_mir/src/transform/coverage/mod.rs index 93133e9b7f0..60757178bec 100644 --- a/compiler/rustc_mir/src/transform/coverage/mod.rs +++ b/compiler/rustc_mir/src/transform/coverage/mod.rs @@ -111,7 +111,8 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { let body_span = hir_body.value.span; let source_file = source_map.lookup_source_file(body_span.lo()); let fn_sig_span = match some_fn_sig.filter(|fn_sig| { - Lrc::ptr_eq(&source_file, &source_map.lookup_source_file(fn_sig.span.hi())) + fn_sig.span.ctxt() == body_span.ctxt() + && Lrc::ptr_eq(&source_file, &source_map.lookup_source_file(fn_sig.span.hi())) }) { Some(fn_sig) => fn_sig.span.with_hi(body_span.lo()), None => body_span.shrink_to_lo(), diff --git a/compiler/rustc_mir/src/transform/coverage/spans.rs b/compiler/rustc_mir/src/transform/coverage/spans.rs index 067e1001def..249f5e835cd 100644 --- a/compiler/rustc_mir/src/transform/coverage/spans.rs +++ b/compiler/rustc_mir/src/transform/coverage/spans.rs @@ -240,13 +240,13 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { /// to be). pub(super) fn generate_coverage_spans( mir_body: &'a mir::Body<'tcx>, - fn_sig_span: Span, + fn_sig_span: Span, // Ensured to be same SourceFile and SyntaxContext as `body_span` body_span: Span, basic_coverage_blocks: &'a CoverageGraph, ) -> Vec<CoverageSpan> { let mut coverage_spans = CoverageSpans { mir_body, - fn_sig_span: fn_sig_source_span(fn_sig_span, body_span), + fn_sig_span, body_span, basic_coverage_blocks, sorted_spans_iter: None, @@ -732,11 +732,6 @@ pub(super) fn filtered_terminator_span( } #[inline] -fn fn_sig_source_span(fn_sig_span: Span, body_span: Span) -> Span { - original_sp(fn_sig_span, body_span).with_ctxt(body_span.ctxt()) -} - -#[inline] fn function_source_span(span: Span, body_span: Span) -> Span { let span = original_sp(span, body_span).with_ctxt(body_span.ctxt()); if body_span.contains(span) { span } else { body_span } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 6fae6921fc9..e33c374f562 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -930,7 +930,14 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { let msg = "you might have meant to use `#![feature(trait_alias)]` instead of a \ `type` alias"; if let Some(span) = self.def_span(def_id) { - err.span_help(span, msg); + if let Ok(snip) = self.r.session.source_map().span_to_snippet(span) { + // The span contains a type alias so we should be able to + // replace `type` with `trait`. + let snip = snip.replacen("type", "trait", 1); + err.span_suggestion(span, msg, snip, Applicability::MaybeIncorrect); + } else { + err.span_help(span, msg); + } } else { err.help(msg); } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index b683626bbd6..52a6e4ff924 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -797,7 +797,7 @@ pub const fn default_lib_output() -> CrateType { CrateType::Rlib } -pub fn default_configuration(sess: &Session) -> CrateConfig { +fn default_configuration(sess: &Session) -> CrateConfig { let end = &sess.target.endian; let arch = &sess.target.arch; let wordsz = sess.target.pointer_width.to_string(); @@ -892,7 +892,7 @@ pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateCo user_cfg } -pub fn build_target_config(opts: &Options, target_override: Option<Target>) -> Target { +pub(super) fn build_target_config(opts: &Options, target_override: Option<Target>) -> Target { let target_result = target_override.map_or_else(|| Target::search(&opts.target_triple), Ok); let target = target_result.unwrap_or_else(|e| { early_error( diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 52270f0e627..1d1471fdeca 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -796,7 +796,6 @@ symbols! { non_modrs_mods, none_error, nontemporal_store, - nontrapping_dash_fptoint: "nontrapping-fptoint", noop_method_borrow, noop_method_clone, noop_method_deref, diff --git a/library/alloc/src/task.rs b/library/alloc/src/task.rs index 58a9ae77244..528ee4ff154 100644 --- a/library/alloc/src/task.rs +++ b/library/alloc/src/task.rs @@ -87,6 +87,9 @@ pub trait Wake { #[stable(feature = "wake_trait", since = "1.51.0")] impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for Waker { + /// Use a `Wake`-able type as a `Waker`. + /// + /// No heap allocations or atomic operations are used for this conversion. fn from(waker: Arc<W>) -> Waker { // SAFETY: This is safe because raw_waker safely constructs // a RawWaker from Arc<W>. @@ -96,6 +99,9 @@ impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for Waker { #[stable(feature = "wake_trait", since = "1.51.0")] impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for RawWaker { + /// Use a `Wake`-able type as a `RawWaker`. + /// + /// No heap allocations or atomic operations are used for this conversion. fn from(waker: Arc<W>) -> RawWaker { raw_waker(waker) } diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 1b78356fde5..e459442dfcf 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2810,8 +2810,7 @@ impl<T, A: Allocator> From<Box<[T], A>> for Vec<T, A> { /// assert_eq!(Vec::from(b), vec![1, 2, 3]); /// ``` fn from(s: Box<[T], A>) -> Self { - let len = s.len(); - Self { buf: RawVec::from_box(s), len } + s.into_vec() } } diff --git a/library/core/src/convert/num.rs b/library/core/src/convert/num.rs index 5b113610a5d..a522b7da3bd 100644 --- a/library/core/src/convert/num.rs +++ b/library/core/src/convert/num.rs @@ -45,8 +45,10 @@ impl_float_to_int!(f64 => u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize); macro_rules! impl_from { ($Small: ty, $Large: ty, #[$attr:meta], $doc: expr) => { #[$attr] - #[doc = $doc] impl From<$Small> for $Large { + // Rustdocs on the impl block show a "[+] show undocumented items" toggle. + // Rustdocs on functions do not. + #[doc = $doc] #[inline] fn from(small: $Small) -> Self { small as Self @@ -383,8 +385,10 @@ use crate::num::NonZeroUsize; macro_rules! nzint_impl_from { ($Small: ty, $Large: ty, #[$attr:meta], $doc: expr) => { #[$attr] - #[doc = $doc] impl From<$Small> for $Large { + // Rustdocs on the impl block show a "[+] show undocumented items" toggle. + // Rustdocs on functions do not. + #[doc = $doc] #[inline] fn from(small: $Small) -> Self { // SAFETY: input type guarantees the value is non-zero @@ -450,10 +454,12 @@ nzint_impl_from! { NonZeroU64, NonZeroI128, #[stable(feature = "nz_int_conv", si macro_rules! nzint_impl_try_from_int { ($Int: ty, $NonZeroInt: ty, #[$attr:meta], $doc: expr) => { #[$attr] - #[doc = $doc] impl TryFrom<$Int> for $NonZeroInt { type Error = TryFromIntError; + // Rustdocs on the impl block show a "[+] show undocumented items" toggle. + // Rustdocs on functions do not. + #[doc = $doc] #[inline] fn try_from(value: $Int) -> Result<Self, Self::Error> { Self::new(value).ok_or(TryFromIntError(())) @@ -489,10 +495,12 @@ nzint_impl_try_from_int! { isize, NonZeroIsize, #[stable(feature = "nzint_try_fr macro_rules! nzint_impl_try_from_nzint { ($From:ty => $To:ty, $doc: expr) => { #[stable(feature = "nzint_try_from_nzint_conv", since = "1.49.0")] - #[doc = $doc] impl TryFrom<$From> for $To { type Error = TryFromIntError; + // Rustdocs on the impl block show a "[+] show undocumented items" toggle. + // Rustdocs on functions do not. + #[doc = $doc] #[inline] fn try_from(value: $From) -> Result<Self, Self::Error> { TryFrom::try_from(value.get()).map(|v| { diff --git a/library/core/src/iter/adapters/take.rs b/library/core/src/iter/adapters/take.rs index 9efc7a480ae..54a47f1323e 100644 --- a/library/core/src/iter/adapters/take.rs +++ b/library/core/src/iter/adapters/take.rs @@ -1,5 +1,8 @@ use crate::cmp; -use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen}; +use crate::iter::{ + adapters::zip::try_get_unchecked, adapters::SourceIter, FusedIterator, InPlaceIterable, + TrustedLen, TrustedRandomAccess, +}; use crate::ops::{ControlFlow, Try}; /// An iterator that only iterates over the first `n` iterations of `iter`. @@ -111,6 +114,15 @@ where self.try_fold(init, ok(fold)).unwrap() } + + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> <I as Iterator>::Item + where + Self: TrustedRandomAccess, + { + // SAFETY: the caller must uphold the contract for + // `Iterator::__iterator_get_unchecked`. + unsafe { try_get_unchecked(&mut self.iter, idx) } + } } #[unstable(issue = "none", feature = "inplace_iteration")] @@ -207,3 +219,12 @@ impl<I> FusedIterator for Take<I> where I: FusedIterator {} #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl<I: TrustedLen> TrustedLen for Take<I> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<I> TrustedRandomAccess for Take<I> +where + I: TrustedRandomAccess, +{ + const MAY_HAVE_SIDE_EFFECT: bool = I::MAY_HAVE_SIDE_EFFECT; +} diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index c0cab86cf62..7977d599ae7 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1651,31 +1651,16 @@ pub trait Iterator { /// Basic usage: /// /// ``` - /// let a = [1, 2, 3]; - /// - /// let iter = a.iter(); - /// - /// let sum: i32 = iter.take(5).fold(0, |acc, i| acc + i); - /// - /// assert_eq!(sum, 6); - /// - /// // if we try to use iter again, it won't work. The following line - /// // gives "error: use of moved value: `iter` - /// // assert_eq!(iter.next(), None); + /// let mut words = vec!["hello", "world", "of", "Rust"].into_iter(); /// - /// // let's try that again - /// let a = [1, 2, 3]; - /// - /// let mut iter = a.iter(); - /// - /// // instead, we add in a .by_ref() - /// let sum: i32 = iter.by_ref().take(2).fold(0, |acc, i| acc + i); + /// // Take the first two words. + /// let hello_world: Vec<_> = words.by_ref().take(2).collect(); + /// assert_eq!(hello_world, vec!["hello", "world"]); /// - /// assert_eq!(sum, 3); - /// - /// // now this is just fine: - /// assert_eq!(iter.next(), Some(&3)); - /// assert_eq!(iter.next(), None); + /// // Collect the rest of the words. + /// // We can only do this because we used `by_ref` earlier. + /// let of_rust: Vec<_> = words.collect(); + /// assert_eq!(of_rust, vec!["of", "Rust"]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn by_ref(&mut self) -> &mut Self diff --git a/library/std/src/sync/condvar.rs b/library/std/src/sync/condvar.rs index 60be63c9543..2f0b32c90d0 100644 --- a/library/std/src/sync/condvar.rs +++ b/library/std/src/sync/condvar.rs @@ -2,9 +2,8 @@ mod tests; use crate::fmt; -use crate::sync::{mutex, MutexGuard, PoisonError}; +use crate::sync::{mutex, poison, LockResult, MutexGuard, PoisonError}; use crate::sys_common::condvar as sys; -use crate::sys_common::poison::{self, LockResult}; use crate::time::{Duration, Instant}; /// A type indicating whether a timed wait on a condition variable returned diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs index b6699910b07..ee35598bab5 100644 --- a/library/std/src/sync/mod.rs +++ b/library/std/src/sync/mod.rs @@ -166,9 +166,9 @@ pub use self::mutex::{Mutex, MutexGuard}; #[allow(deprecated)] pub use self::once::{Once, OnceState, ONCE_INIT}; #[stable(feature = "rust1", since = "1.0.0")] -pub use self::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}; +pub use self::poison::{LockResult, PoisonError, TryLockError, TryLockResult}; #[stable(feature = "rust1", since = "1.0.0")] -pub use crate::sys_common::poison::{LockResult, PoisonError, TryLockError, TryLockResult}; +pub use self::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}; pub mod mpsc; @@ -176,4 +176,5 @@ mod barrier; mod condvar; mod mutex; mod once; +mod poison; mod rwlock; diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs index 98c34282e0c..2615bea6592 100644 --- a/library/std/src/sync/mutex.rs +++ b/library/std/src/sync/mutex.rs @@ -6,8 +6,8 @@ use crate::fmt; use crate::mem; use crate::ops::{Deref, DerefMut}; use crate::ptr; +use crate::sync::{poison, LockResult, TryLockError, TryLockResult}; use crate::sys_common::mutex as sys; -use crate::sys_common::poison::{self, LockResult, TryLockError, TryLockResult}; /// A mutual exclusion primitive useful for protecting shared data /// diff --git a/library/std/src/sys_common/poison.rs b/library/std/src/sync/poison.rs index 1f71187f1b4..05e1833c3e5 100644 --- a/library/std/src/sys_common/poison.rs +++ b/library/std/src/sync/poison.rs @@ -3,9 +3,6 @@ use crate::fmt; use crate::sync::atomic::{AtomicBool, Ordering}; use crate::thread; -#[allow(unused_imports)] // for intra-doc links -use crate::sync::{Mutex, RwLock}; - pub struct Flag { failed: AtomicBool, } @@ -80,6 +77,8 @@ pub struct Guard { /// } /// }; /// ``` +/// [`Mutex`]: crate::sync::Mutex +/// [`RwLock`]: crate::sync::RwLock #[stable(feature = "rust1", since = "1.0.0")] pub struct PoisonError<T> { guard: T, @@ -89,9 +88,11 @@ pub struct PoisonError<T> { /// can occur while trying to acquire a lock, from the [`try_lock`] method on a /// [`Mutex`] or the [`try_read`] and [`try_write`] methods on an [`RwLock`]. /// -/// [`try_lock`]: Mutex::try_lock -/// [`try_read`]: RwLock::try_read -/// [`try_write`]: RwLock::try_write +/// [`try_lock`]: crate::sync::Mutex::try_lock +/// [`try_read`]: crate::sync::RwLock::try_read +/// [`try_write`]: crate::sync::RwLock::try_write +/// [`Mutex`]: crate::sync::Mutex +/// [`RwLock`]: crate::sync::RwLock #[stable(feature = "rust1", since = "1.0.0")] pub enum TryLockError<T> { /// The lock could not be acquired because another thread failed while holding @@ -149,7 +150,8 @@ impl<T> Error for PoisonError<T> { impl<T> PoisonError<T> { /// Creates a `PoisonError`. /// - /// This is generally created by methods like [`Mutex::lock`] or [`RwLock::read`]. + /// This is generally created by methods like [`Mutex::lock`](crate::sync::Mutex::lock) + /// or [`RwLock::read`](crate::sync::RwLock::read). #[stable(feature = "sync_poison", since = "1.2.0")] pub fn new(guard: T) -> PoisonError<T> { PoisonError { guard } diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs index 351804ec979..b01bcec1361 100644 --- a/library/std/src/sync/rwlock.rs +++ b/library/std/src/sync/rwlock.rs @@ -6,7 +6,7 @@ use crate::fmt; use crate::mem; use crate::ops::{Deref, DerefMut}; use crate::ptr; -use crate::sys_common::poison::{self, LockResult, TryLockError, TryLockResult}; +use crate::sync::{poison, LockResult, TryLockError, TryLockResult}; use crate::sys_common::rwlock as sys; /// A reader-writer lock diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs index 23a3a0e907d..4979bc0b5af 100644 --- a/library/std/src/sys_common/mod.rs +++ b/library/std/src/sys_common/mod.rs @@ -59,7 +59,6 @@ pub mod mutex; // when generating documentation. #[cfg(any(doc, not(windows)))] pub mod os_str_bytes; -pub mod poison; pub mod process; pub mod remutex; pub mod rwlock; diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index 68e7dc80067..13ee909afd5 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -17,6 +17,11 @@ use crate::Compiler; use crate::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::config::{Config, TargetSelection}; +#[cfg(target_os = "illumos")] +const SHELL: &str = "bash"; +#[cfg(not(target_os = "illumos"))] +const SHELL: &str = "sh"; + fn install_sh( builder: &Builder<'_>, package: &str, @@ -37,7 +42,7 @@ fn install_sh( let empty_dir = builder.out.join("tmp/empty_dir"); t!(fs::create_dir_all(&empty_dir)); - let mut cmd = Command::new("sh"); + let mut cmd = Command::new(SHELL); cmd.current_dir(&empty_dir) .arg(sanitize_sh(&tarball.decompressed_output().join("install.sh"))) .arg(format!("--prefix={}", prepare_dir(prefix))) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index f352746d3fb..25b56b96ed2 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -179,7 +179,7 @@ target | std | host | notes `i386-apple-ios` | ✓ | | 32-bit x86 iOS `i686-apple-darwin` | ✓ | ✓ | 32-bit macOS (10.7+, Lion+) `i686-pc-windows-msvc` | ✓ | | 32-bit Windows XP support -`i686-unknown-uefi` | ? | | 32-bit UEFI +`i686-unknown-uefi` | * | | 32-bit UEFI `i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku `i686-unknown-netbsd` | ✓ | ✓ | NetBSD/i386 with SSE2 `i686-unknown-openbsd` | ✓ | ✓ | 32-bit OpenBSD @@ -228,7 +228,7 @@ target | std | host | notes `x86_64-unknown-none-hermitkernel` | ? | | HermitCore kernel `x86_64-unknown-l4re-uclibc` | ? | | `x86_64-unknown-openbsd` | ✓ | ✓ | 64-bit OpenBSD -`x86_64-unknown-uefi` | ? | | +`x86_64-unknown-uefi` | * | | 64-bit UEFI `x86_64-uwp-windows-gnu` | ✓ | | `x86_64-uwp-windows-msvc` | ✓ | | `x86_64-wrs-vxworks` | ? | | diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 7d33cf21013..72046645e3a 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -84,123 +84,8 @@ impl<T: Clean<U>, U> Clean<Option<U>> for Option<T> { impl Clean<ExternalCrate> for CrateNum { fn clean(&self, cx: &mut DocContext<'_>) -> ExternalCrate { - let tcx = cx.tcx; let root = DefId { krate: *self, index: CRATE_DEF_INDEX }; - let krate_span = tcx.def_span(root); - let krate_src = cx.sess().source_map().span_to_filename(krate_span); - - // Collect all inner modules which are tagged as implementations of - // primitives. - // - // Note that this loop only searches the top-level items of the crate, - // and this is intentional. If we were to search the entire crate for an - // item tagged with `#[doc(primitive)]` then we would also have to - // search the entirety of external modules for items tagged - // `#[doc(primitive)]`, which is a pretty inefficient process (decoding - // all that metadata unconditionally). - // - // In order to keep the metadata load under control, the - // `#[doc(primitive)]` feature is explicitly designed to only allow the - // primitive tags to show up as the top level items in a crate. - // - // Also note that this does not attempt to deal with modules tagged - // duplicately for the same primitive. This is handled later on when - // rendering by delegating everything to a hash map. - let mut as_primitive = |res: Res| { - if let Res::Def(DefKind::Mod, def_id) = res { - let attrs = cx.tcx.get_attrs(def_id).clean(cx); - let mut prim = None; - for attr in attrs.lists(sym::doc) { - if let Some(v) = attr.value_str() { - if attr.has_name(sym::primitive) { - prim = PrimitiveType::from_symbol(v); - if prim.is_some() { - break; - } - // FIXME: should warn on unknown primitives? - } - } - } - return prim.map(|p| (def_id, p)); - } - None - }; - let primitives = if root.is_local() { - tcx.hir() - .krate() - .item - .item_ids - .iter() - .filter_map(|&id| { - let item = tcx.hir().item(id); - match item.kind { - hir::ItemKind::Mod(_) => { - as_primitive(Res::Def(DefKind::Mod, id.def_id.to_def_id())) - } - hir::ItemKind::Use(ref path, hir::UseKind::Single) - if item.vis.node.is_pub() => - { - as_primitive(path.res).map(|(_, prim)| { - // Pretend the primitive is local. - (id.def_id.to_def_id(), prim) - }) - } - _ => None, - } - }) - .collect() - } else { - tcx.item_children(root).iter().map(|item| item.res).filter_map(as_primitive).collect() - }; - - let mut as_keyword = |res: Res| { - if let Res::Def(DefKind::Mod, def_id) = res { - let attrs = tcx.get_attrs(def_id).clean(cx); - let mut keyword = None; - for attr in attrs.lists(sym::doc) { - if attr.has_name(sym::keyword) { - if let Some(v) = attr.value_str() { - keyword = Some(v); - break; - } - } - } - return keyword.map(|p| (def_id, p)); - } - None - }; - let keywords = if root.is_local() { - tcx.hir() - .krate() - .item - .item_ids - .iter() - .filter_map(|&id| { - let item = tcx.hir().item(id); - match item.kind { - hir::ItemKind::Mod(_) => { - as_keyword(Res::Def(DefKind::Mod, id.def_id.to_def_id())) - } - hir::ItemKind::Use(ref path, hir::UseKind::Single) - if item.vis.node.is_pub() => - { - as_keyword(path.res).map(|(_, prim)| (id.def_id.to_def_id(), prim)) - } - _ => None, - } - }) - .collect() - } else { - tcx.item_children(root).iter().map(|item| item.res).filter_map(as_keyword).collect() - }; - - ExternalCrate { - name: tcx.crate_name(*self), - src: krate_src, - attrs: tcx.get_attrs(root).clean(cx), - primitives, - keywords, - } + ExternalCrate { crate_num: *self, attrs: cx.tcx.get_attrs(root).clean(cx) } } } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 675de640c70..1acde8401b2 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -17,8 +17,8 @@ use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::thin_vec::ThinVec; use rustc_hir as hir; -use rustc_hir::def::{CtorKind, Res}; -use rustc_hir::def_id::{CrateNum, DefId, DefIndex}; +use rustc_hir::def::{CtorKind, DefKind, Res}; +use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX}; use rustc_hir::lang_items::LangItem; use rustc_hir::{BodyId, Mutability}; use rustc_index::vec::IndexVec; @@ -72,11 +72,138 @@ crate struct TraitWithExtraInfo { #[derive(Clone, Debug)] crate struct ExternalCrate { - crate name: Symbol, - crate src: FileName, + crate crate_num: CrateNum, crate attrs: Attributes, - crate primitives: ThinVec<(DefId, PrimitiveType)>, - crate keywords: ThinVec<(DefId, Symbol)>, +} + +impl ExternalCrate { + #[inline] + fn def_id(&self) -> DefId { + DefId { krate: self.crate_num, index: CRATE_DEF_INDEX } + } + + crate fn src(&self, tcx: TyCtxt<'_>) -> FileName { + let krate_span = tcx.def_span(self.def_id()); + tcx.sess.source_map().span_to_filename(krate_span) + } + + crate fn name(&self, tcx: TyCtxt<'_>) -> Symbol { + tcx.crate_name(self.crate_num) + } + + crate fn keywords(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, Symbol)> { + let root = self.def_id(); + + let as_keyword = |res: Res| { + if let Res::Def(DefKind::Mod, def_id) = res { + let attrs = tcx.get_attrs(def_id); + let mut keyword = None; + for attr in attrs.lists(sym::doc) { + if attr.has_name(sym::keyword) { + if let Some(v) = attr.value_str() { + keyword = Some(v); + break; + } + } + } + return keyword.map(|p| (def_id, p)); + } + None + }; + if root.is_local() { + tcx.hir() + .krate() + .item + .item_ids + .iter() + .filter_map(|&id| { + let item = tcx.hir().item(id); + match item.kind { + hir::ItemKind::Mod(_) => { + as_keyword(Res::Def(DefKind::Mod, id.def_id.to_def_id())) + } + hir::ItemKind::Use(ref path, hir::UseKind::Single) + if item.vis.node.is_pub() => + { + as_keyword(path.res).map(|(_, prim)| (id.def_id.to_def_id(), prim)) + } + _ => None, + } + }) + .collect() + } else { + tcx.item_children(root).iter().map(|item| item.res).filter_map(as_keyword).collect() + } + } + + crate fn primitives(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, PrimitiveType)> { + let root = self.def_id(); + + // Collect all inner modules which are tagged as implementations of + // primitives. + // + // Note that this loop only searches the top-level items of the crate, + // and this is intentional. If we were to search the entire crate for an + // item tagged with `#[doc(primitive)]` then we would also have to + // search the entirety of external modules for items tagged + // `#[doc(primitive)]`, which is a pretty inefficient process (decoding + // all that metadata unconditionally). + // + // In order to keep the metadata load under control, the + // `#[doc(primitive)]` feature is explicitly designed to only allow the + // primitive tags to show up as the top level items in a crate. + // + // Also note that this does not attempt to deal with modules tagged + // duplicately for the same primitive. This is handled later on when + // rendering by delegating everything to a hash map. + let as_primitive = |res: Res| { + if let Res::Def(DefKind::Mod, def_id) = res { + let attrs = tcx.get_attrs(def_id); + let mut prim = None; + for attr in attrs.lists(sym::doc) { + if let Some(v) = attr.value_str() { + if attr.has_name(sym::primitive) { + prim = PrimitiveType::from_symbol(v); + if prim.is_some() { + break; + } + // FIXME: should warn on unknown primitives? + } + } + } + return prim.map(|p| (def_id, p)); + } + None + }; + + if root.is_local() { + tcx.hir() + .krate() + .item + .item_ids + .iter() + .filter_map(|&id| { + let item = tcx.hir().item(id); + match item.kind { + hir::ItemKind::Mod(_) => { + as_primitive(Res::Def(DefKind::Mod, id.def_id.to_def_id())) + } + hir::ItemKind::Use(ref path, hir::UseKind::Single) + if item.vis.node.is_pub() => + { + as_primitive(path.res).map(|(_, prim)| { + // Pretend the primitive is local. + (id.def_id.to_def_id(), prim) + }) + } + _ => None, + } + }) + .collect() + } else { + tcx.item_children(root).iter().map(|item| item.res).filter_map(as_primitive).collect() + } + } } /// Anything with a source location and set of attributes and, optionally, a diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index c2a971d6375..55a0cb42a20 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -1,9 +1,9 @@ use crate::clean::auto_trait::AutoTraitFinder; use crate::clean::blanket_impl::BlanketImplFinder; use crate::clean::{ - inline, Clean, Crate, ExternalCrate, Generic, GenericArg, GenericArgs, ImportSource, Item, - ItemKind, Lifetime, MacroKind, Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Type, - TypeBinding, TypeKind, + inline, Clean, Crate, Generic, GenericArg, GenericArgs, ImportSource, Item, ItemKind, Lifetime, + MacroKind, Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Type, TypeBinding, + TypeKind, }; use crate::core::DocContext; @@ -54,7 +54,11 @@ crate fn krate(cx: &mut DocContext<'_>) -> Crate { _ => unreachable!(), } - let ExternalCrate { name, src, primitives, keywords, .. } = LOCAL_CRATE.clean(cx); + let local_crate = LOCAL_CRATE.clean(cx); + let src = local_crate.src(cx.tcx); + let name = local_crate.name(cx.tcx); + let primitives = local_crate.primitives(cx.tcx); + let keywords = local_crate.keywords(cx.tcx); { let m = match *module.kind { ItemKind::ModuleItem(ref mut m) => m, diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index b2b895cc672..9a61f963a3e 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -155,19 +155,20 @@ impl Cache { // Cache where all our extern crates are located // FIXME: this part is specific to HTML so it'd be nice to remove it from the common code for &(n, ref e) in &krate.externs { - let src_root = match e.src { + let src_root = match e.src(tcx) { FileName::Real(ref p) => match p.local_path().parent() { Some(p) => p.to_path_buf(), None => PathBuf::new(), }, _ => PathBuf::new(), }; - let extern_url = extern_html_root_urls.get(&*e.name.as_str()).map(|u| &**u); + let name = e.name(tcx); + let extern_url = extern_html_root_urls.get(&*name.as_str()).map(|u| &**u); self.extern_locations - .insert(n, (e.name, src_root, extern_location(e, extern_url, &dst))); + .insert(n, (name, src_root, extern_location(e, extern_url, &dst, tcx))); let did = DefId { krate: n, index: CRATE_DEF_INDEX }; - self.external_paths.insert(did, (vec![e.name.to_string()], ItemType::Module)); + self.external_paths.insert(did, (vec![name.to_string()], ItemType::Module)); } // Cache where all known primitives have their documentation located. @@ -175,7 +176,7 @@ impl Cache { // Favor linking to as local extern as possible, so iterate all crates in // reverse topological order. for &(_, ref e) in krate.externs.iter().rev() { - for &(def_id, prim) in &e.primitives { + for &(def_id, prim) in &e.primitives(tcx) { self.primitive_locations.insert(prim, def_id); } } diff --git a/src/librustdoc/formats/renderer.rs b/src/librustdoc/formats/renderer.rs index ae97cd64fb5..b8ef3384c59 100644 --- a/src/librustdoc/formats/renderer.rs +++ b/src/librustdoc/formats/renderer.rs @@ -1,5 +1,5 @@ use rustc_middle::ty::TyCtxt; -use rustc_span::{edition::Edition, Symbol}; +use rustc_span::Symbol; use crate::clean; use crate::config::RenderOptions; @@ -23,7 +23,6 @@ crate trait FormatRenderer<'tcx>: Sized { fn init( krate: clean::Crate, options: RenderOptions, - edition: Edition, cache: Cache, tcx: TyCtxt<'tcx>, ) -> Result<(Self, clean::Crate), Error>; @@ -35,19 +34,15 @@ crate trait FormatRenderer<'tcx>: Sized { fn item(&mut self, item: clean::Item) -> Result<(), Error>; /// Renders a module (should not handle recursing into children). - fn mod_item_in(&mut self, item: &clean::Item, item_name: &str) -> Result<(), Error>; + fn mod_item_in(&mut self, item: &clean::Item) -> Result<(), Error>; /// Runs after recursively rendering all sub-items of a module. - fn mod_item_out(&mut self, item_name: &str) -> Result<(), Error>; + fn mod_item_out(&mut self) -> Result<(), Error> { + Ok(()) + } /// Post processing hook for cleanup and dumping output to files. - /// - /// A handler is available if the renderer wants to report errors. - fn after_krate( - &mut self, - crate_name: Symbol, - diag: &rustc_errors::Handler, - ) -> Result<(), Error>; + fn after_krate(&mut self) -> Result<(), Error>; fn cache(&self) -> &Cache; } @@ -57,8 +52,6 @@ crate fn run_format<'tcx, T: FormatRenderer<'tcx>>( krate: clean::Crate, options: RenderOptions, cache: Cache, - diag: &rustc_errors::Handler, - edition: Edition, tcx: TyCtxt<'tcx>, ) -> Result<(), Error> { let prof = &tcx.sess.prof; @@ -66,14 +59,13 @@ crate fn run_format<'tcx, T: FormatRenderer<'tcx>>( let emit_crate = options.should_emit_crate(); let (mut format_renderer, krate) = prof .extra_verbose_generic_activity("create_renderer", T::descr()) - .run(|| T::init(krate, options, edition, cache, tcx))?; + .run(|| T::init(krate, options, cache, tcx))?; if !emit_crate { return Ok(()); } // Render the crate documentation - let crate_name = krate.name; let mut work = vec![(format_renderer.make_child_renderer(), krate.module)]; let unknown = Symbol::intern("<unknown item>"); @@ -81,13 +73,10 @@ crate fn run_format<'tcx, T: FormatRenderer<'tcx>>( if item.is_mod() && T::RUN_ON_MODULE { // modules are special because they add a namespace. We also need to // recurse into the items of the module as well. - let name = item.name.as_ref().unwrap().to_string(); - if name.is_empty() { - panic!("Unexpected module with empty name"); - } - let _timer = prof.generic_activity_with_arg("render_mod_item", name.as_str()); + let _timer = + prof.generic_activity_with_arg("render_mod_item", item.name.unwrap().to_string()); - cx.mod_item_in(&item, &name)?; + cx.mod_item_in(&item)?; let module = match *item.kind { clean::StrippedItem(box clean::ModuleItem(m)) | clean::ModuleItem(m) => m, _ => unreachable!(), @@ -97,7 +86,7 @@ crate fn run_format<'tcx, T: FormatRenderer<'tcx>>( work.push((cx.make_child_renderer(), it)); } - cx.mod_item_out(&name)?; + cx.mod_item_out()?; // FIXME: checking `item.name.is_some()` is very implicit and leads to lots of special // cases. Use an explicit match instead. } else if item.name.is_some() && !item.is_extern_crate() { @@ -106,5 +95,5 @@ crate fn run_format<'tcx, T: FormatRenderer<'tcx>>( } } prof.extra_verbose_generic_activity("renderer_after_krate", T::descr()) - .run(|| format_renderer.after_krate(crate_name, diag)) + .run(|| format_renderer.after_krate()) } diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs index 2265905dcba..b8544a0f439 100644 --- a/src/librustdoc/html/render/cache.rs +++ b/src/librustdoc/html/render/cache.rs @@ -31,10 +31,11 @@ crate fn extern_location( e: &clean::ExternalCrate, extern_url: Option<&str>, dst: &Path, + tcx: TyCtxt<'_>, ) -> ExternalLocation { use ExternalLocation::*; // See if there's documentation generated into the local directory - let local_location = dst.join(&*e.name.as_str()); + let local_location = dst.join(&*e.name(tcx).as_str()); if local_location.is_dir() { return Local; } diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 0aa7aa763c2..9cffcef9749 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -11,7 +11,7 @@ use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_span::edition::Edition; use rustc_span::source_map::FileName; -use rustc_span::{symbol::sym, Symbol}; +use rustc_span::symbol::sym; use super::cache::{build_index, ExternalLocation}; use super::print_item::{full_path, item_path, print_item}; @@ -111,8 +111,6 @@ crate struct SharedContext<'tcx> { crate static_root_path: Option<String>, /// The fs handle we are working with. crate fs: DocFS, - /// The default edition used to parse doctests. - crate edition: Edition, pub(super) codes: ErrorCodes, pub(super) playground: Option<markdown::Playground>, all: RefCell<AllTypes>, @@ -141,6 +139,10 @@ impl SharedContext<'_> { crate fn maybe_collapsed_doc_value<'a>(&self, item: &'a clean::Item) -> Option<String> { if self.collapsed { item.collapsed_doc_value() } else { item.doc_value() } } + + crate fn edition(&self) -> Edition { + self.tcx.sess.edition() + } } impl<'tcx> Context<'tcx> { @@ -346,7 +348,6 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { fn init( mut krate: clean::Crate, options: RenderOptions, - edition: Edition, mut cache: Cache, tcx: TyCtxt<'tcx>, ) -> Result<(Self, clean::Crate), Error> { @@ -435,7 +436,6 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { resource_suffix, static_root_path, fs: DocFS::new(sender), - edition, codes: ErrorCodes::from(unstable_features.is_nightly_build()), playground, all: RefCell::new(AllTypes::new()), @@ -494,11 +494,8 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { } } - fn after_krate( - &mut self, - crate_name: Symbol, - diag: &rustc_errors::Handler, - ) -> Result<(), Error> { + fn after_krate(&mut self) -> Result<(), Error> { + let crate_name = self.tcx().crate_name(LOCAL_CRATE); let final_file = self.dst.join(&*crate_name.as_str()).join("all.html"); let settings_file = self.dst.join("settings.html"); @@ -572,7 +569,8 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { // Flush pending errors. Rc::get_mut(&mut self.shared).unwrap().fs.close(); - let nb_errors = self.shared.errors.iter().map(|err| diag.struct_err(&err).emit()).count(); + let nb_errors = + self.shared.errors.iter().map(|err| self.tcx().sess.struct_err(&err).emit()).count(); if nb_errors > 0 { Err(Error::new(io::Error::new(io::ErrorKind::Other, "I/O error"), "")) } else { @@ -580,7 +578,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { } } - fn mod_item_in(&mut self, item: &clean::Item, item_name: &str) -> Result<(), Error> { + fn mod_item_in(&mut self, item: &clean::Item) -> Result<(), Error> { // Stripped modules survive the rustdoc passes (i.e., `strip-private`) // if they contain impls for public types. These modules can also // contain items such as publicly re-exported structures. @@ -592,8 +590,9 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { self.render_redirect_pages = item.is_stripped(); } let scx = &self.shared; - self.dst.push(item_name); - self.current.push(item_name.to_owned()); + let item_name = item.name.as_ref().unwrap().to_string(); + self.dst.push(&item_name); + self.current.push(item_name); info!("Recursing into {}", self.dst.display()); @@ -619,7 +618,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { Ok(()) } - fn mod_item_out(&mut self, _item_name: &str) -> Result<(), Error> { + fn mod_item_out(&mut self) -> Result<(), Error> { info!("Recursed; leaving {}", self.dst.display()); // Go back to where we were at diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index d773f37ad90..f6d6b34f8be 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -530,7 +530,7 @@ fn render_markdown( &links, &mut ids, cx.shared.codes, - cx.shared.edition, + cx.shared.edition(), &cx.shared.playground ) .into_string() @@ -660,7 +660,7 @@ fn short_item_info( ¬e, &mut ids, error_codes, - cx.shared.edition, + cx.shared.edition(), &cx.shared.playground, ); message.push_str(&format!(": {}", html.into_string())); @@ -702,7 +702,7 @@ fn short_item_info( &unstable_reason.as_str(), &mut ids, error_codes, - cx.shared.edition, + cx.shared.edition(), &cx.shared.playground, ) .into_string() @@ -1284,6 +1284,7 @@ fn render_impl( let cache = cx.cache(); let traits = &cache.traits; let trait_ = i.trait_did_full(cache).map(|did| &traits[&did]); + let mut close_tags = String::new(); if render_mode == RenderMode::Normal { let id = cx.derive_id(match i.inner_impl().trait_ { @@ -1302,7 +1303,12 @@ fn render_impl( format!(" aliases=\"{}\"", aliases.join(",")) }; if let Some(use_absolute) = use_absolute { - write!(w, "<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">", id, aliases); + write!( + w, + "<details class=\"rustdoc-toggle implementors-toggle\"><summary><h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">", + id, aliases + ); + close_tags.insert_str(0, "</details>"); write!(w, "{}", i.inner_impl().print(use_absolute, cx)); if show_def_docs { for it in &i.inner_impl().items { @@ -1325,11 +1331,12 @@ fn render_impl( } else { write!( w, - "<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">{}</code>", + "<details class=\"rustdoc-toggle implementors-toggle\"><summary><h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">{}</code>", id, aliases, i.inner_impl().print(false, cx) ); + close_tags.insert_str(0, "</details>"); } write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id); render_stability_since_raw( @@ -1341,6 +1348,7 @@ fn render_impl( ); write_srclink(cx, &i.impl_item, w); w.write_str("</h3>"); + w.write_str("</summary>"); if trait_.is_some() { if let Some(portability) = portability(&i.impl_item, Some(parent)) { @@ -1358,7 +1366,7 @@ fn render_impl( &i.impl_item.links(cx), &mut ids, cx.shared.codes, - cx.shared.edition, + cx.shared.edition(), &cx.shared.playground ) .into_string() @@ -1542,6 +1550,7 @@ fn render_impl( } w.write_str("<div class=\"impl-items\">"); + close_tags.insert_str(0, "</div>"); for trait_item in &i.inner_impl().items { doc_impl_item( w, @@ -1612,7 +1621,7 @@ fn render_impl( ); } } - w.write_str("</div>"); + w.write_str(&close_tags); } fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) { diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index a303ca956d8..9d7d8a7cb8a 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -963,6 +963,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum use crate::clean::Variant; if let clean::VariantItem(Variant::Struct(ref s)) = *variant.kind { + toggle_open(w, "fields"); let variant_id = cx.derive_id(format!( "{}.{}.fields", ItemType::Variant, @@ -996,6 +997,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum } } w.write_str("</div></div>"); + toggle_close(w); } render_stability_since(w, variant, it, cx.tcx()); } diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 78bcd40af75..8e10c696df0 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -425,7 +425,7 @@ pub(super) fn write_shared( md_opts.output = cx.dst.clone(); md_opts.external_html = (*cx.shared).layout.external_html.clone(); - crate::markdown::render(&index_page, md_opts, cx.shared.edition) + crate::markdown::render(&index_page, md_opts, cx.shared.edition()) .map_err(|e| Error::new(e, &index_page))?; } else { let dst = cx.dst.join("index.html"); diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 001c8b09044..5a2a165191a 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -129,7 +129,7 @@ impl SourceCollector<'_, 'tcx> { &self.scx.layout, &page, "", - |buf: &mut _| print_src(buf, contents, self.scx.edition), + |buf: &mut _| print_src(buf, contents, self.scx.edition()), &self.scx.style_files, ); self.scx.fs.write(&cur, v.as_bytes())?; diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index be8d0a5996f..2e3e148eaf6 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -455,6 +455,15 @@ function hideThemeButtonState() { handleHashes(ev); } + function openParentDetails(elem) { + while (elem) { + if (elem.tagName === "DETAILS") { + elem.open = true; + } + elem = elem.parentNode; + } + } + function expandSection(id) { var elem = document.getElementById(id); if (elem && isHidden(elem)) { @@ -469,6 +478,8 @@ function hideThemeButtonState() { // The element is not visible, we need to make it appear! collapseDocs(collapses[0], "show"); } + // Open all ancestor <details> to make this element visible. + openParentDetails(h3.parentNode); } } } @@ -1009,7 +1020,7 @@ function hideThemeButtonState() { if (hasClass(relatedDoc, "item-info")) { relatedDoc = relatedDoc.nextElementSibling; } - if (hasClass(relatedDoc, "docblock") || hasClass(relatedDoc, "sub-variant")) { + if (hasClass(relatedDoc, "docblock")) { if (mode === "toggle") { if (hasClass(relatedDoc, "hidden-by-usual-hider")) { action = "show"; @@ -1196,31 +1207,18 @@ function hideThemeButtonState() { if (!next) { return; } - if (hasClass(e, "impl") && - (next.getElementsByClassName("method").length > 0 || - next.getElementsByClassName("associatedconstant").length > 0)) { - var newToggle = toggle.cloneNode(true); - insertAfter(newToggle, e.childNodes[e.childNodes.length - 1]); - // In case the option "auto-collapse implementors" is not set to false, we collapse - // all implementors. - if (hideImplementors === true && e.parentNode.id === "implementors-list") { - collapseDocs(newToggle, "hide"); - } - } }; onEachLazy(document.getElementsByClassName("method"), func); onEachLazy(document.getElementsByClassName("associatedconstant"), func); - onEachLazy(document.getElementsByClassName("impl"), funcImpl); var impl_call = function() {}; - // Large items are hidden by default in the HTML. If the setting overrides that, show 'em. - if (!hideLargeItemContents) { - onEachLazy(document.getElementsByTagName("details"), function (e) { - if (hasClass(e, "type-contents-toggle")) { - e.open = true; - } - }); - } + onEachLazy(document.getElementsByTagName("details"), function (e) { + var showLargeItem = !hideLargeItemContents && hasClass(e, "type-contents-toggle"); + var showImplementor = !hideImplementors && hasClass(e, "implementors-toggle"); + if (showLargeItem || showImplementor) { + e.open = true; + } + }); if (hideMethodDocs === true) { impl_call = function(e, newToggle) { if (e.id.match(/^impl(?:-\d+)?$/) === null) { @@ -1318,8 +1316,6 @@ function hideThemeButtonState() { if (hasClass(e, "type-decl")) { // We do something special for these return; - } else if (hasClass(e, "sub-variant")) { - otherMessage = " Show fields"; } else if (hasClass(e, "non-exhaustive")) { otherMessage = " This "; if (hasClass(e, "non-exhaustive-struct")) { @@ -1351,7 +1347,6 @@ function hideThemeButtonState() { } onEachLazy(document.getElementsByClassName("docblock"), buildToggleWrapper); - onEachLazy(document.getElementsByClassName("sub-variant"), buildToggleWrapper); autoCollapse(getSettingValue("collapse") === "true"); diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 213ca9ec9e3..a024fa49b0e 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -1046,10 +1046,11 @@ h3 > .collapse-toggle, h4 > .collapse-toggle { } .sub-variant, .sub-variant > h3 { - margin-top: 1px !important; + margin-top: 0px !important; + padding-top: 1px; } -#main > .sub-variant > h3 { +#main > details > .sub-variant > h3 { font-size: 15px; margin-left: 25px; margin-bottom: 5px; @@ -1572,6 +1573,10 @@ h4 > .notable-traits { left: -10px; } + .item-list > details.rustdoc-toggle > summary:not(.hideme)::before { + left: -10px; + } + #all-types { margin: 10px; } @@ -1786,6 +1791,7 @@ details.rustdoc-toggle > summary::before { font-weight: 300; font-size: 0.8em; letter-spacing: 1px; + cursor: pointer; } details.rustdoc-toggle > summary.hideme::before { @@ -1793,7 +1799,8 @@ details.rustdoc-toggle > summary.hideme::before { } details.rustdoc-toggle > summary:not(.hideme)::before { - float: left; + position: absolute; + left: -23px; } /* When a "hideme" summary is open and the "Expand description" or "Show diff --git a/src/librustdoc/html/static/search.js b/src/librustdoc/html/static/search.js index eb232a96081..9fab435de49 100644 --- a/src/librustdoc/html/static/search.js +++ b/src/librustdoc/html/static/search.js @@ -935,6 +935,9 @@ window.initSearch = function(rawSearchIndex) { }); current += 1; }); + var SHIFT = 16; + var CTRL = 17; + var ALT = 18; var currentTab = searchState.currentTab; if (e.which === 38) { // up @@ -967,10 +970,10 @@ window.initSearch = function(rawSearchIndex) { e.preventDefault(); } else if (e.which === 13) { // return if (actives[currentTab].length) { - document.location.href = - actives[currentTab][0].getElementsByTagName("a")[0].href; + var elem = actives[currentTab][0].getElementsByTagName("a")[0]; + document.location.href = elem.href; } - } else if (e.which === 16) { // shift + } else if ([SHIFT, CTRL, ALT].indexOf(e.which) !== -1) { // Does nothing, it's just to avoid losing "focus" on the highlighted element. } else if (actives[currentTab].length > 0) { removeClass(actives[currentTab][0], "highlighted"); diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index db3a0c5ceb1..b048e7f919f 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -14,7 +14,6 @@ use std::rc::Rc; use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty::TyCtxt; use rustc_session::Session; -use rustc_span::{edition::Edition, Symbol}; use rustdoc_json_types as types; @@ -134,7 +133,6 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { fn init( krate: clean::Crate, options: RenderOptions, - _edition: Edition, cache: Cache, tcx: TyCtxt<'tcx>, ) -> Result<(Self, clean::Crate), Error> { @@ -183,7 +181,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { Ok(()) } - fn mod_item_in(&mut self, item: &clean::Item, _module_name: &str) -> Result<(), Error> { + fn mod_item_in(&mut self, item: &clean::Item) -> Result<(), Error> { use clean::types::ItemKind::*; if let ModuleItem(m) = &*item.kind { for item in &m.items { @@ -200,15 +198,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { Ok(()) } - fn mod_item_out(&mut self, _item_name: &str) -> Result<(), Error> { - Ok(()) - } - - fn after_krate( - &mut self, - _crate_name: Symbol, - _diag: &rustc_errors::Handler, - ) -> Result<(), Error> { + fn after_krate(&mut self) -> Result<(), Error> { debug!("Done with crate"); let mut index = (*self.index).clone().into_inner(); index.extend(self.get_trait_items()); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 2a51d78f64a..26aaf0db6f6 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -656,14 +656,13 @@ fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>( krate: clean::Crate, renderopts: config::RenderOptions, cache: formats::cache::Cache, - diag: &rustc_errors::Handler, - edition: rustc_span::edition::Edition, tcx: TyCtxt<'tcx>, ) -> MainResult { - match formats::run_format::<T>(krate, renderopts, cache, &diag, edition, tcx) { + match formats::run_format::<T>(krate, renderopts, cache, tcx) { Ok(_) => Ok(()), Err(e) => { - let mut msg = diag.struct_err(&format!("couldn't generate documentation: {}", e.error)); + let mut msg = + tcx.sess.struct_err(&format!("couldn't generate documentation: {}", e.error)); let file = e.file.display().to_string(); if file.is_empty() { msg.emit() @@ -692,7 +691,6 @@ fn main_options(options: config::Options) -> MainResult { // need to move these items separately because we lose them by the time the closure is called, // but we can't create the Handler ahead of time because it's not Send - let diag_opts = (options.error_format, options.edition, options.debugging_opts.clone()); let show_coverage = options.show_coverage; let run_check = options.run_check; @@ -758,28 +756,12 @@ fn main_options(options: config::Options) -> MainResult { } info!("going to format"); - let (error_format, edition, debugging_options) = diag_opts; - let diag = core::new_handler(error_format, None, &debugging_options); match output_format { config::OutputFormat::Html => sess.time("render_html", || { - run_renderer::<html::render::Context<'_>>( - krate, - render_opts, - cache, - &diag, - edition, - tcx, - ) + run_renderer::<html::render::Context<'_>>(krate, render_opts, cache, tcx) }), config::OutputFormat::Json => sess.time("render_json", || { - run_renderer::<json::JsonRenderer<'_>>( - krate, - render_opts, - cache, - &diag, - edition, - tcx, - ) + run_renderer::<json::JsonRenderer<'_>>(krate, render_opts, cache, tcx) }), } }) diff --git a/src/test/codegen/wasm_casts_nontrapping.rs b/src/test/codegen/wasm_casts_nontrapping.rs deleted file mode 100644 index bd6073d8c20..00000000000 --- a/src/test/codegen/wasm_casts_nontrapping.rs +++ /dev/null @@ -1,162 +0,0 @@ -// only-wasm32 -// compile-flags: -C target-feature=+nontrapping-fptoint -#![crate_type = "lib"] - -// CHECK-LABEL: @cast_f64_i64 -#[no_mangle] -pub fn cast_f64_i64(a: f64) -> i64 { - // CHECK: tail call i64 @llvm.wasm.trunc.saturate.signed.i64.f64(double {{.*}}) - // CHECK-NEXT: ret i64 {{.*}} - a as _ -} - -// CHECK-LABEL: @cast_f64_i32 -#[no_mangle] -pub fn cast_f64_i32(a: f64) -> i32 { - // CHECK: tail call i32 @llvm.wasm.trunc.saturate.signed.i32.f64(double {{.*}}) - // CHECK-NEXT: ret i32 {{.*}} - a as _ -} - -// CHECK-LABEL: @cast_f32_i64 -#[no_mangle] -pub fn cast_f32_i64(a: f32) -> i64 { - // CHECK: tail call i64 @llvm.wasm.trunc.saturate.signed.i64.f32(float {{.*}}) - // CHECK-NEXT: ret i64 {{.*}} - a as _ -} - -// CHECK-LABEL: @cast_f32_i32 -#[no_mangle] -pub fn cast_f32_i32(a: f32) -> i32 { - // CHECK: tail call i32 @llvm.wasm.trunc.saturate.signed.i32.f32(float {{.*}}) - // CHECK-NEXT: ret i32 {{.*}} - a as _ -} - - -// CHECK-LABEL: @cast_f64_u64 -#[no_mangle] -pub fn cast_f64_u64(a: f64) -> u64 { - // CHECK: tail call i64 @llvm.wasm.trunc.saturate.unsigned.i64.f64(double {{.*}}) - // CHECK-NEXT: ret i64 {{.*}} - a as _ -} - -// CHECK-LABEL: @cast_f64_u32 -#[no_mangle] -pub fn cast_f64_u32(a: f64) -> u32 { - // CHECK: tail call i32 @llvm.wasm.trunc.saturate.unsigned.i32.f64(double {{.*}}) - // CHECK-NEXT: ret i32 {{.*}} - a as _ -} - -// CHECK-LABEL: @cast_f32_u64 -#[no_mangle] -pub fn cast_f32_u64(a: f32) -> u64 { - // CHECK: tail call i64 @llvm.wasm.trunc.saturate.unsigned.i64.f32(float {{.*}}) - // CHECK-NEXT: ret i64 {{.*}} - a as _ -} - -// CHECK-LABEL: @cast_f32_u32 -#[no_mangle] -pub fn cast_f32_u32(a: f32) -> u32 { - // CHECK: tail call i32 @llvm.wasm.trunc.saturate.unsigned.i32.f32(float {{.*}}) - // CHECK-NEXT: ret i32 {{.*}} - a as _ -} - -// CHECK-LABEL: @cast_f32_u8 -#[no_mangle] -pub fn cast_f32_u8(a: f32) -> u8 { - // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}} - // CHECK: fptoui float {{.*}} to i8 - // CHECK-NEXT: select i1 {{.*}}, i8 {{.*}}, i8 {{.*}} - // CHECK-NEXT: ret i8 {{.*}} - a as _ -} - - - -// CHECK-LABEL: @cast_unchecked_f64_i64 -#[no_mangle] -pub unsafe fn cast_unchecked_f64_i64(a: f64) -> i64 { - // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}} - // CHECK: fptosi double {{.*}} to i64 - // CHECK-NEXT: ret i64 {{.*}} - a.to_int_unchecked() -} - -// CHECK-LABEL: @cast_unchecked_f64_i32 -#[no_mangle] -pub unsafe fn cast_unchecked_f64_i32(a: f64) -> i32 { - // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}} - // CHECK: fptosi double {{.*}} to i32 - // CHECK-NEXT: ret i32 {{.*}} - a.to_int_unchecked() -} - -// CHECK-LABEL: @cast_unchecked_f32_i64 -#[no_mangle] -pub unsafe fn cast_unchecked_f32_i64(a: f32) -> i64 { - // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}} - // CHECK: fptosi float {{.*}} to i64 - // CHECK-NEXT: ret i64 {{.*}} - a.to_int_unchecked() -} - -// CHECK-LABEL: @cast_unchecked_f32_i32 -#[no_mangle] -pub unsafe fn cast_unchecked_f32_i32(a: f32) -> i32 { - // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}} - // CHECK: fptosi float {{.*}} to i32 - // CHECK-NEXT: ret i32 {{.*}} - a.to_int_unchecked() -} - - -// CHECK-LABEL: @cast_unchecked_f64_u64 -#[no_mangle] -pub unsafe fn cast_unchecked_f64_u64(a: f64) -> u64 { - // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}} - // CHECK: fptoui double {{.*}} to i64 - // CHECK-NEXT: ret i64 {{.*}} - a.to_int_unchecked() -} - -// CHECK-LABEL: @cast_unchecked_f64_u32 -#[no_mangle] -pub unsafe fn cast_unchecked_f64_u32(a: f64) -> u32 { - // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}} - // CHECK: fptoui double {{.*}} to i32 - // CHECK-NEXT: ret i32 {{.*}} - a.to_int_unchecked() -} - -// CHECK-LABEL: @cast_unchecked_f32_u64 -#[no_mangle] -pub unsafe fn cast_unchecked_f32_u64(a: f32) -> u64 { - // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}} - // CHECK: fptoui float {{.*}} to i64 - // CHECK-NEXT: ret i64 {{.*}} - a.to_int_unchecked() -} - -// CHECK-LABEL: @cast_unchecked_f32_u32 -#[no_mangle] -pub unsafe fn cast_unchecked_f32_u32(a: f32) -> u32 { - // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}} - // CHECK: fptoui float {{.*}} to i32 - // CHECK-NEXT: ret i32 {{.*}} - a.to_int_unchecked() -} - -// CHECK-LABEL: @cast_unchecked_f32_u8 -#[no_mangle] -pub unsafe fn cast_unchecked_f32_u8(a: f32) -> u8 { - // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}} - // CHECK: fptoui float {{.*}} to i8 - // CHECK-NEXT: ret i8 {{.*}} - a.to_int_unchecked() -} diff --git a/src/test/codegen/wasm_casts_trapping.rs b/src/test/codegen/wasm_casts_trapping.rs index ed51faa7be1..baf130a8791 100644 --- a/src/test/codegen/wasm_casts_trapping.rs +++ b/src/test/codegen/wasm_casts_trapping.rs @@ -1,5 +1,6 @@ // only-wasm32 // compile-flags: -C target-feature=-nontrapping-fptoint +// min-llvm-version: 12.0 #![crate_type = "lib"] // CHECK-LABEL: @cast_f64_i64 @@ -7,7 +8,7 @@ pub fn cast_f64_i64(a: f64) -> i64 { // CHECK-NOT: fptosi double {{.*}} to i64 // CHECK-NOT: select i1 {{.*}}, i64 {{.*}}, i64 {{.*}} - // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}} + // CHECK: {{.*}} call {{.*}} @llvm.fptosi.sat.i64.f64{{.*}} a as _ } @@ -16,7 +17,7 @@ pub fn cast_f64_i64(a: f64) -> i64 { pub fn cast_f64_i32(a: f64) -> i32 { // CHECK-NOT: fptosi double {{.*}} to i32 // CHECK-NOT: select i1 {{.*}}, i32 {{.*}}, i32 {{.*}} - // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}} + // CHECK: {{.*}} call {{.*}} @llvm.fptosi.sat.i32.f64{{.*}} a as _ } @@ -25,7 +26,7 @@ pub fn cast_f64_i32(a: f64) -> i32 { pub fn cast_f32_i64(a: f32) -> i64 { // CHECK-NOT: fptosi float {{.*}} to i64 // CHECK-NOT: select i1 {{.*}}, i64 {{.*}}, i64 {{.*}} - // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}} + // CHECK: {{.*}} call {{.*}} @llvm.fptosi.sat.i64.f32{{.*}} a as _ } @@ -34,7 +35,7 @@ pub fn cast_f32_i64(a: f32) -> i64 { pub fn cast_f32_i32(a: f32) -> i32 { // CHECK-NOT: fptosi float {{.*}} to i32 // CHECK-NOT: select i1 {{.*}}, i32 {{.*}}, i32 {{.*}} - // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}} + // CHECK: {{.*}} call {{.*}} @llvm.fptosi.sat.i32.f32{{.*}} a as _ } @@ -43,7 +44,7 @@ pub fn cast_f32_i32(a: f32) -> i32 { pub fn cast_f64_u64(a: f64) -> u64 { // CHECK-NOT: fptoui double {{.*}} to i64 // CHECK-NOT: select i1 {{.*}}, i64 {{.*}}, i64 {{.*}} - // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}} + // CHECK: {{.*}} call {{.*}} @llvm.fptoui.sat.i64.f64{{.*}} a as _ } @@ -52,7 +53,7 @@ pub fn cast_f64_u64(a: f64) -> u64 { pub fn cast_f64_u32(a: f64) -> u32 { // CHECK-NOT: fptoui double {{.*}} to i32 // CHECK-NOT: select i1 {{.*}}, i32 {{.*}}, i32 {{.*}} - // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}} + // CHECK: {{.*}} call {{.*}} @llvm.fptoui.sat.i32.f64{{.*}} a as _ } @@ -61,7 +62,7 @@ pub fn cast_f64_u32(a: f64) -> u32 { pub fn cast_f32_u64(a: f32) -> u64 { // CHECK-NOT: fptoui float {{.*}} to i64 // CHECK-NOT: select i1 {{.*}}, i64 {{.*}}, i64 {{.*}} - // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}} + // CHECK: {{.*}} call {{.*}} @llvm.fptoui.sat.i64.f32{{.*}} a as _ } @@ -70,16 +71,16 @@ pub fn cast_f32_u64(a: f32) -> u64 { pub fn cast_f32_u32(a: f32) -> u32 { // CHECK-NOT: fptoui float {{.*}} to i32 // CHECK-NOT: select i1 {{.*}}, i32 {{.*}}, i32 {{.*}} - // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}} + // CHECK: {{.*}} call {{.*}} @llvm.fptoui.sat.i32.f32{{.*}} a as _ } // CHECK-LABEL: @cast_f32_u8 #[no_mangle] pub fn cast_f32_u8(a: f32) -> u8 { - // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}} - // CHECK: fptoui float {{.*}} to i8 - // CHECK-NEXT: select i1 {{.*}}, i8 {{.*}}, i8 {{.*}} + // CHECK-NOT: fptoui float {{.*}} to i8 + // CHECK-NOT: select i1 {{.*}}, i8 {{.*}}, i8 {{.*}} + // CHECK: {{.*}} call {{.*}} @llvm.fptoui.sat.i8.f32{{.*}} a as _ } diff --git a/src/test/rustdoc-gui/lib.rs b/src/test/rustdoc-gui/lib.rs index c1e161e1235..eeba3e3f907 100644 --- a/src/test/rustdoc-gui/lib.rs +++ b/src/test/rustdoc-gui/lib.rs @@ -29,7 +29,9 @@ pub struct Foo; impl Foo { #[must_use] - pub fn must_use(&self) -> bool { true } + pub fn must_use(&self) -> bool { + true + } } /// Just a normal enum. @@ -85,3 +87,7 @@ pub trait AnotherOne { /// let x = 12; /// ``` pub fn check_list_code_block() {} + +pub enum AnEnum { + WithVariants { and: usize, sub: usize, variants: usize }, +} diff --git a/src/test/rustdoc/const-generics/add-impl.rs b/src/test/rustdoc/const-generics/add-impl.rs index db4be82e6bf..77432ba1539 100644 --- a/src/test/rustdoc/const-generics/add-impl.rs +++ b/src/test/rustdoc/const-generics/add-impl.rs @@ -8,7 +8,7 @@ pub struct Simd<T, const WIDTH: usize> { inner: T, } -// @has foo/struct.Simd.html '//div[@id="trait-implementations-list"]/h3/code' 'impl Add<Simd<u8, 16_usize>> for Simd<u8, 16>' +// @has foo/struct.Simd.html '//div[@id="trait-implementations-list"]//h3/code' 'impl Add<Simd<u8, 16_usize>> for Simd<u8, 16>' impl Add for Simd<u8, 16> { type Output = Self; diff --git a/src/test/rustdoc/duplicate_impls/issue-33054.rs b/src/test/rustdoc/duplicate_impls/issue-33054.rs index 112d632971a..1e644bb9739 100644 --- a/src/test/rustdoc/duplicate_impls/issue-33054.rs +++ b/src/test/rustdoc/duplicate_impls/issue-33054.rs @@ -1,8 +1,8 @@ // @has issue_33054/impls/struct.Foo.html // @has - '//code' 'impl Foo' // @has - '//code' 'impl Bar for Foo' -// @count - '//*[@id="trait-implementations-list"]/*[@class="impl"]' 1 -// @count - '//*[@id="main"]/*[@class="impl"]' 1 +// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1 +// @count - '//*[@id="main"]/details/summary/*[@class="impl"]' 1 // @has issue_33054/impls/bar/trait.Bar.html // @has - '//code' 'impl Bar for Foo' // @count - '//*[@class="struct"]' 1 diff --git a/src/test/rustdoc/issue-21474.rs b/src/test/rustdoc/issue-21474.rs index 896fc1a78f1..5de26abace6 100644 --- a/src/test/rustdoc/issue-21474.rs +++ b/src/test/rustdoc/issue-21474.rs @@ -7,5 +7,5 @@ mod inner { pub trait Blah { } // @count issue_21474/struct.What.html \ -// '//*[@id="trait-implementations-list"]/*[@class="impl"]' 1 +// '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1 pub struct What; diff --git a/src/test/rustdoc/issue-29503.rs b/src/test/rustdoc/issue-29503.rs index 19bab394dcf..2b25da77d7e 100644 --- a/src/test/rustdoc/issue-29503.rs +++ b/src/test/rustdoc/issue-29503.rs @@ -5,7 +5,7 @@ pub trait MyTrait { fn my_string(&self) -> String; } -// @has - "//div[@id='implementors-list']/h3[@id='impl-MyTrait']//code" "impl<T> MyTrait for T where T: Debug" +// @has - "//div[@id='implementors-list']//h3[@id='impl-MyTrait']//code" "impl<T> MyTrait for T where T: Debug" impl<T> MyTrait for T where T: fmt::Debug { fn my_string(&self) -> String { format!("{:?}", self) diff --git a/src/test/rustdoc/issue-45584.rs b/src/test/rustdoc/issue-45584.rs index 0225c0c5c2f..8a5f0413826 100644 --- a/src/test/rustdoc/issue-45584.rs +++ b/src/test/rustdoc/issue-45584.rs @@ -4,12 +4,12 @@ pub trait Bar<T, U> {} // @has 'foo/struct.Foo1.html' pub struct Foo1; -// @count - '//*[@id="trait-implementations-list"]/*[@class="impl"]' 1 +// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1 // @has - '//*[@class="impl"]' "impl Bar<Foo1, &'static Foo1> for Foo1" impl Bar<Foo1, &'static Foo1> for Foo1 {} // @has 'foo/struct.Foo2.html' pub struct Foo2; -// @count - '//*[@id="trait-implementations-list"]/*[@class="impl"]' 1 +// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1 // @has - '//*[@class="impl"]' "impl Bar<&'static Foo2, Foo2> for u8" impl Bar<&'static Foo2, Foo2> for u8 {} diff --git a/src/test/rustdoc/issue-50159.rs b/src/test/rustdoc/issue-50159.rs index 74502be622a..0820512e521 100644 --- a/src/test/rustdoc/issue-50159.rs +++ b/src/test/rustdoc/issue-50159.rs @@ -13,8 +13,8 @@ impl<B, C> Signal2 for B where B: Signal<Item = C> { // @has issue_50159/struct.Switch.html // @has - '//code' 'impl<B> Send for Switch<B> where <B as Signal>::Item: Send' // @has - '//code' 'impl<B> Sync for Switch<B> where <B as Signal>::Item: Sync' -// @count - '//*[@id="implementations-list"]/*[@class="impl"]' 0 -// @count - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]' 5 +// @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0 +// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 5 pub struct Switch<B: Signal> { pub inner: <B as Signal2>::Item2, } diff --git a/src/test/rustdoc/issue-51236.rs b/src/test/rustdoc/issue-51236.rs index d9accf9c599..d018c948162 100644 --- a/src/test/rustdoc/issue-51236.rs +++ b/src/test/rustdoc/issue-51236.rs @@ -7,7 +7,7 @@ pub mod traits { } // @has issue_51236/struct.Owned.html -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<T> Send for \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> Send for \ // Owned<T> where <T as Owned<'static>>::Reader: Send" pub struct Owned<T> where T: for<'a> ::traits::Owned<'a> { marker: PhantomData<<T as ::traits::Owned<'static>>::Reader>, diff --git a/src/test/rustdoc/issue-53812.rs b/src/test/rustdoc/issue-53812.rs index 3ebf154077f..daebe059f8e 100644 --- a/src/test/rustdoc/issue-53812.rs +++ b/src/test/rustdoc/issue-53812.rs @@ -12,9 +12,9 @@ macro_rules! array_impls { } } -// @has issue_53812/trait.MyIterator.html '//*[@id="implementors-list"]//h3[1]' 'MyStruct<[T; 0]>' -// @has - '//*[@id="implementors-list"]//h3[2]' 'MyStruct<[T; 1]>' -// @has - '//*[@id="implementors-list"]//h3[3]' 'MyStruct<[T; 2]>' -// @has - '//*[@id="implementors-list"]//h3[4]' 'MyStruct<[T; 3]>' -// @has - '//*[@id="implementors-list"]//h3[5]' 'MyStruct<[T; 10]>' +// @has issue_53812/trait.MyIterator.html '//*[@id="implementors-list"]/details[1]/summary/h3' 'MyStruct<[T; 0]>' +// @has - '//*[@id="implementors-list"]/details[2]/summary/h3' 'MyStruct<[T; 1]>' +// @has - '//*[@id="implementors-list"]/details[3]/summary/h3' 'MyStruct<[T; 2]>' +// @has - '//*[@id="implementors-list"]/details[4]/summary/h3' 'MyStruct<[T; 3]>' +// @has - '//*[@id="implementors-list"]/details[5]/summary/h3' 'MyStruct<[T; 10]>' array_impls! { 10 3 2 1 0 } diff --git a/src/test/rustdoc/issue-54705.rs b/src/test/rustdoc/issue-54705.rs index 263b1eb0bd6..47da94a4ccf 100644 --- a/src/test/rustdoc/issue-54705.rs +++ b/src/test/rustdoc/issue-54705.rs @@ -3,10 +3,10 @@ pub trait ScopeHandle<'scope> {} // @has issue_54705/struct.ScopeFutureContents.html -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<'scope, S> \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'scope, S> \ // Send for ScopeFutureContents<'scope, S> where S: Sync" // -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<'scope, S> \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'scope, S> \ // Sync for ScopeFutureContents<'scope, S> where S: Sync" pub struct ScopeFutureContents<'scope, S> where S: ScopeHandle<'scope>, diff --git a/src/test/rustdoc/issue-55321.rs b/src/test/rustdoc/issue-55321.rs index d312a511459..d1877f39ba7 100644 --- a/src/test/rustdoc/issue-55321.rs +++ b/src/test/rustdoc/issue-55321.rs @@ -1,16 +1,16 @@ #![feature(negative_impls)] // @has issue_55321/struct.A.html -// @has - '//*[@id="trait-implementations-list"]/*[@class="impl"]//code' "impl !Send for A" -// @has - '//*[@id="trait-implementations-list"]/*[@class="impl"]//code' "impl !Sync for A" +// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//code' "impl !Send for A" +// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//code' "impl !Sync for A" pub struct A(); impl !Send for A {} impl !Sync for A {} // @has issue_55321/struct.B.html -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<T> !Send for \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> !Send for \ // B<T>" -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<T> !Sync for \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> !Sync for \ // B<T>" pub struct B<T: ?Sized>(A, Box<T>); diff --git a/src/test/rustdoc/issue-56822.rs b/src/test/rustdoc/issue-56822.rs index 5b67817fa4c..b932a3d3474 100644 --- a/src/test/rustdoc/issue-56822.rs +++ b/src/test/rustdoc/issue-56822.rs @@ -17,7 +17,7 @@ impl<'a, T> MyTrait for Inner<'a, T> { } // @has issue_56822/struct.Parser.html -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<'a> Send for \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'a> Send for \ // Parser<'a>" pub struct Parser<'a> { field: <Wrapper<Inner<'a, u8>> as MyTrait>::Output diff --git a/src/test/rustdoc/issue-60726.rs b/src/test/rustdoc/issue-60726.rs index 6acc8627738..79b8b70c545 100644 --- a/src/test/rustdoc/issue-60726.rs +++ b/src/test/rustdoc/issue-60726.rs @@ -26,9 +26,9 @@ where {} // @has issue_60726/struct.IntoIter.html -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<T> !Send for \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> !Send for \ // IntoIter<T>" -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<T> !Sync for \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> !Sync for \ // IntoIter<T>" pub struct IntoIter<T>{ hello:DynTrait<FooInterface<T>>, diff --git a/src/test/rustdoc/item-hide-threshold.rs b/src/test/rustdoc/item-hide-threshold.rs index 616eef95662..8986f72636a 100644 --- a/src/test/rustdoc/item-hide-threshold.rs +++ b/src/test/rustdoc/item-hide-threshold.rs @@ -62,7 +62,8 @@ pub struct PrivStruct { } // @has 'item_hide_threshold/enum.Enum.html' -// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0 +// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1 +// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show fields' pub enum Enum { A, B, C, D { diff --git a/src/test/rustdoc/synthetic_auto/basic.rs b/src/test/rustdoc/synthetic_auto/basic.rs index 38de5316b6c..0dd3a3f7a86 100644 --- a/src/test/rustdoc/synthetic_auto/basic.rs +++ b/src/test/rustdoc/synthetic_auto/basic.rs @@ -1,8 +1,8 @@ // @has basic/struct.Foo.html // @has - '//code' 'impl<T> Send for Foo<T> where T: Send' // @has - '//code' 'impl<T> Sync for Foo<T> where T: Sync' -// @count - '//*[@id="implementations-list"]/*[@class="impl"]' 0 -// @count - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]' 5 +// @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0 +// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 5 pub struct Foo<T> { field: T, } diff --git a/src/test/rustdoc/synthetic_auto/complex.rs b/src/test/rustdoc/synthetic_auto/complex.rs index 80a717718c2..d951a20e2de 100644 --- a/src/test/rustdoc/synthetic_auto/complex.rs +++ b/src/test/rustdoc/synthetic_auto/complex.rs @@ -20,7 +20,7 @@ mod foo { } // @has complex/struct.NotOuter.html -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<'a, T, K: \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'a, T, K: \ // ?Sized> Send for Outer<'a, T, K> where K: for<'b> Fn((&'b bool, &'a u8)) \ // -> &'b i8, T: MyTrait<'a>, <T as MyTrait<'a>>::MyItem: Copy, 'a: 'static" diff --git a/src/test/rustdoc/synthetic_auto/lifetimes.rs b/src/test/rustdoc/synthetic_auto/lifetimes.rs index 6d0a68f9b07..05c88f10822 100644 --- a/src/test/rustdoc/synthetic_auto/lifetimes.rs +++ b/src/test/rustdoc/synthetic_auto/lifetimes.rs @@ -9,10 +9,10 @@ where {} // @has lifetimes/struct.Foo.html -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<'c, K> Send \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'c, K> Send \ // for Foo<'c, K> where K: for<'b> Fn(&'b bool) -> &'c u8, 'c: 'static" // -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<'c, K> Sync \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'c, K> Sync \ // for Foo<'c, K> where K: Sync" pub struct Foo<'c, K: 'c> { inner_field: Inner<'c, K>, diff --git a/src/test/rustdoc/synthetic_auto/manual.rs b/src/test/rustdoc/synthetic_auto/manual.rs index d20b4744af1..88ddd57349a 100644 --- a/src/test/rustdoc/synthetic_auto/manual.rs +++ b/src/test/rustdoc/synthetic_auto/manual.rs @@ -1,12 +1,12 @@ // @has manual/struct.Foo.html -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' 'impl<T> Sync for \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' 'impl<T> Sync for \ // Foo<T> where T: Sync' // -// @has - '//*[@id="trait-implementations-list"]/*[@class="impl"]//code' \ +// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//code' \ // 'impl<T> Send for Foo<T>' // -// @count - '//*[@id="trait-implementations-list"]/*[@class="impl"]' 1 -// @count - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]' 4 +// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1 +// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 4 pub struct Foo<T> { field: T, } diff --git a/src/test/rustdoc/synthetic_auto/negative.rs b/src/test/rustdoc/synthetic_auto/negative.rs index 30713849da2..53801542c95 100644 --- a/src/test/rustdoc/synthetic_auto/negative.rs +++ b/src/test/rustdoc/synthetic_auto/negative.rs @@ -3,10 +3,10 @@ pub struct Inner<T: Copy> { } // @has negative/struct.Outer.html -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<T> !Send for \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> !Send for \ // Outer<T>" // -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<T> \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> \ // !Sync for Outer<T>" pub struct Outer<T: Copy> { inner_field: Inner<T>, diff --git a/src/test/rustdoc/synthetic_auto/nested.rs b/src/test/rustdoc/synthetic_auto/nested.rs index e710ce1c2ed..d4d93a87ffc 100644 --- a/src/test/rustdoc/synthetic_auto/nested.rs +++ b/src/test/rustdoc/synthetic_auto/nested.rs @@ -9,10 +9,10 @@ where } // @has nested/struct.Foo.html -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' 'impl<T> Send for \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' 'impl<T> Send for \ // Foo<T> where T: Copy' // -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' \ // 'impl<T> Sync for Foo<T> where T: Sync' pub struct Foo<T> { inner_field: Inner<T>, diff --git a/src/test/rustdoc/synthetic_auto/no-redundancy.rs b/src/test/rustdoc/synthetic_auto/no-redundancy.rs index cf173111ec1..3a23dc2cf95 100644 --- a/src/test/rustdoc/synthetic_auto/no-redundancy.rs +++ b/src/test/rustdoc/synthetic_auto/no-redundancy.rs @@ -9,7 +9,7 @@ where } // @has no_redundancy/struct.Outer.html -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<T> Send for \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> Send for \ // Outer<T> where T: Copy + Send" pub struct Outer<T> { inner_field: Inner<T>, diff --git a/src/test/rustdoc/synthetic_auto/project.rs b/src/test/rustdoc/synthetic_auto/project.rs index 5346521f8d2..060491e3cf1 100644 --- a/src/test/rustdoc/synthetic_auto/project.rs +++ b/src/test/rustdoc/synthetic_auto/project.rs @@ -23,10 +23,10 @@ where } // @has project/struct.Foo.html -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<'c, K> Send \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'c, K> Send \ // for Foo<'c, K> where K: MyTrait<MyItem = bool>, 'c: 'static" // -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<'c, K> Sync \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'c, K> Sync \ // for Foo<'c, K> where K: MyTrait, <K as MyTrait>::MyItem: OtherTrait, 'c: 'static," pub struct Foo<'c, K: 'c> { inner_field: Inner<'c, K>, diff --git a/src/test/rustdoc/synthetic_auto/self-referential.rs b/src/test/rustdoc/synthetic_auto/self-referential.rs index 905aa20918b..ecdbdf41b20 100644 --- a/src/test/rustdoc/synthetic_auto/self-referential.rs +++ b/src/test/rustdoc/synthetic_auto/self-referential.rs @@ -23,7 +23,7 @@ impl<T> Pattern for Wrapper<T> { // @has self_referential/struct.WriteAndThen.html -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<P1> Send for \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<P1> Send for \ // WriteAndThen<P1> where <P1 as Pattern>::Value: Send" pub struct WriteAndThen<P1>(pub P1::Value,pub <Constrain<P1, Wrapper<P1::Value>> as Pattern>::Value) where P1: Pattern; diff --git a/src/test/rustdoc/synthetic_auto/static-region.rs b/src/test/rustdoc/synthetic_auto/static-region.rs index 59493744b62..a10e694c1b2 100644 --- a/src/test/rustdoc/synthetic_auto/static-region.rs +++ b/src/test/rustdoc/synthetic_auto/static-region.rs @@ -3,7 +3,7 @@ pub trait OwnedTrait<'a> { } // @has static_region/struct.Owned.html -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<T> Send for \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> Send for \ // Owned<T> where <T as OwnedTrait<'static>>::Reader: Send" pub struct Owned<T> where T: OwnedTrait<'static> { marker: <T as OwnedTrait<'static>>::Reader, diff --git a/src/test/ui/associated-type-bounds/issue-81193.rs b/src/test/ui/associated-type-bounds/issue-81193.rs new file mode 100644 index 00000000000..d2aa54ab951 --- /dev/null +++ b/src/test/ui/associated-type-bounds/issue-81193.rs @@ -0,0 +1,15 @@ +// check-pass + +#![feature(associated_type_bounds)] + +trait A<'a, 'b> {} + +trait B<'a, 'b, 'c> {} + +fn err<'u, 'a, F>() +where + for<'b> F: Iterator<Item: for<'c> B<'a, 'b, 'c> + for<'c> A<'a, 'c>>, +{ +} + +fn main() {} diff --git a/src/test/ui/associated-type-bounds/issue-83017.rs b/src/test/ui/associated-type-bounds/issue-83017.rs new file mode 100644 index 00000000000..8f0a9ea3566 --- /dev/null +++ b/src/test/ui/associated-type-bounds/issue-83017.rs @@ -0,0 +1,39 @@ +#![feature(associated_type_bounds)] + +trait TraitA<'a> { + type AsA; +} + +trait TraitB<'a, 'b> { + type AsB; +} + +trait TraitC<'a, 'b, 'c> {} + +struct X; + +impl<'a, 'b, 'c> TraitC<'a, 'b, 'c> for X {} + +struct Y; + +impl<'a, 'b> TraitB<'a, 'b> for Y { + type AsB = X; +} + +struct Z; + +impl<'a> TraitA<'a> for Z { + type AsA = Y; +} + +fn foo<T>() +where + for<'a> T: TraitA<'a, AsA: for<'b> TraitB<'a, 'b, AsB: for<'c> TraitC<'a, 'b, 'c>>>, +{ +} + +fn main() { + foo::<Z>(); + //~^ ERROR: the trait bound `for<'a, 'b> <Z as TraitA<'a>>::AsA: TraitB<'a, 'b>` is not satisfied + //~| ERROR: the trait bound `for<'a, 'b, 'c> <<Z as TraitA<'a>>::AsA as TraitB<'a, 'b>>::AsB: TraitC<'a, 'b, 'c>` is not satisfied +} diff --git a/src/test/ui/associated-type-bounds/issue-83017.stderr b/src/test/ui/associated-type-bounds/issue-83017.stderr new file mode 100644 index 00000000000..4eb71fd0287 --- /dev/null +++ b/src/test/ui/associated-type-bounds/issue-83017.stderr @@ -0,0 +1,27 @@ +error[E0277]: the trait bound `for<'a, 'b> <Z as TraitA<'a>>::AsA: TraitB<'a, 'b>` is not satisfied + --> $DIR/issue-83017.rs:36:5 + | +LL | fn foo<T>() + | --- required by a bound in this +LL | where +LL | for<'a> T: TraitA<'a, AsA: for<'b> TraitB<'a, 'b, AsB: for<'c> TraitC<'a, 'b, 'c>>>, + | ------------------------------------------------------- required by this bound in `foo` +... +LL | foo::<Z>(); + | ^^^^^^^^ the trait `for<'a, 'b> TraitB<'a, 'b>` is not implemented for `<Z as TraitA<'a>>::AsA` + +error[E0277]: the trait bound `for<'a, 'b, 'c> <<Z as TraitA<'a>>::AsA as TraitB<'a, 'b>>::AsB: TraitC<'a, 'b, 'c>` is not satisfied + --> $DIR/issue-83017.rs:36:5 + | +LL | fn foo<T>() + | --- required by a bound in this +LL | where +LL | for<'a> T: TraitA<'a, AsA: for<'b> TraitB<'a, 'b, AsB: for<'c> TraitC<'a, 'b, 'c>>>, + | -------------------------- required by this bound in `foo` +... +LL | foo::<Z>(); + | ^^^^^^^^ the trait `for<'a, 'b, 'c> TraitC<'a, 'b, 'c>` is not implemented for `<<Z as TraitA<'a>>::AsA as TraitB<'a, 'b>>::AsB` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/codemap_tests/two_files.stderr b/src/test/ui/codemap_tests/two_files.stderr index de2ffc2e5dc..aff51ee9e2f 100644 --- a/src/test/ui/codemap_tests/two_files.stderr +++ b/src/test/ui/codemap_tests/two_files.stderr @@ -5,10 +5,9 @@ LL | impl Bar for Baz { } | ^^^ type aliases cannot be used as traits | help: you might have meant to use `#![feature(trait_alias)]` instead of a `type` alias - --> $DIR/two_files_data.rs:5:1 | -LL | type Bar = dyn Foo; - | ^^^^^^^^^^^^^^^^^^^ +LL | trait Bar = dyn Foo; + | error: aborting due to previous error diff --git a/src/test/ui/resolve/issue-3907.stderr b/src/test/ui/resolve/issue-3907.stderr index 4d0b0af58a3..6fc61cae843 100644 --- a/src/test/ui/resolve/issue-3907.stderr +++ b/src/test/ui/resolve/issue-3907.stderr @@ -5,10 +5,9 @@ LL | impl Foo for S { | ^^^ type aliases cannot be used as traits | help: you might have meant to use `#![feature(trait_alias)]` instead of a `type` alias - --> $DIR/issue-3907.rs:5:1 | -LL | type Foo = dyn issue_3907::Foo; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | trait Foo = dyn issue_3907::Foo; + | help: consider importing this trait instead | LL | use issue_3907::Foo; diff --git a/src/test/ui/resolve/issue-5035.stderr b/src/test/ui/resolve/issue-5035.stderr index 41dff2fe542..a8aa50b7c3a 100644 --- a/src/test/ui/resolve/issue-5035.stderr +++ b/src/test/ui/resolve/issue-5035.stderr @@ -11,16 +11,16 @@ LL | trait I {} | ------- similarly named trait `I` defined here LL | type K = dyn I; LL | impl K for isize {} - | ^ - | | - | type aliases cannot be used as traits - | help: a trait with a similar name exists: `I` + | ^ type aliases cannot be used as traits | help: you might have meant to use `#![feature(trait_alias)]` instead of a `type` alias - --> $DIR/issue-5035.rs:2:1 | -LL | type K = dyn I; - | ^^^^^^^^^^^^^^^ +LL | trait K = dyn I; + | +help: a trait with a similar name exists + | +LL | impl I for isize {} + | ^ error: aborting due to 2 previous errors diff --git a/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr b/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr index 2974d08eb23..8addc0303fb 100644 --- a/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr +++ b/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr @@ -11,10 +11,9 @@ LL | fn g<F:Typedef(isize) -> isize>(x: F) {} | ^^^^^^^^^^^^^^^^^^^^^^^ type aliases cannot be used as traits | help: you might have meant to use `#![feature(trait_alias)]` instead of a `type` alias - --> $DIR/unboxed-closure-sugar-nonexistent-trait.rs:4:1 | -LL | type Typedef = isize; - | ^^^^^^^^^^^^^^^^^^^^^ +LL | trait Typedef = isize; + | error: aborting due to 2 previous errors diff --git a/src/test/ui/traits/alias/suggest-trait-alias-instead-of-type.fixed b/src/test/ui/traits/alias/suggest-trait-alias-instead-of-type.fixed new file mode 100644 index 00000000000..8a94abaeb07 --- /dev/null +++ b/src/test/ui/traits/alias/suggest-trait-alias-instead-of-type.fixed @@ -0,0 +1,13 @@ +// Regression test of #43913. + +// run-rustfix + +#![feature(trait_alias)] +#![allow(bare_trait_objects, dead_code)] + +trait Strings = Iterator<Item=String>; + +struct Struct<S: Strings>(S); +//~^ ERROR: expected trait, found type alias `Strings` + +fn main() {} diff --git a/src/test/ui/traits/alias/suggest-trait-alias-instead-of-type.rs b/src/test/ui/traits/alias/suggest-trait-alias-instead-of-type.rs new file mode 100644 index 00000000000..40c678c281f --- /dev/null +++ b/src/test/ui/traits/alias/suggest-trait-alias-instead-of-type.rs @@ -0,0 +1,13 @@ +// Regression test of #43913. + +// run-rustfix + +#![feature(trait_alias)] +#![allow(bare_trait_objects, dead_code)] + +type Strings = Iterator<Item=String>; + +struct Struct<S: Strings>(S); +//~^ ERROR: expected trait, found type alias `Strings` + +fn main() {} diff --git a/src/test/ui/traits/alias/suggest-trait-alias-instead-of-type.stderr b/src/test/ui/traits/alias/suggest-trait-alias-instead-of-type.stderr new file mode 100644 index 00000000000..6e03eeada49 --- /dev/null +++ b/src/test/ui/traits/alias/suggest-trait-alias-instead-of-type.stderr @@ -0,0 +1,14 @@ +error[E0404]: expected trait, found type alias `Strings` + --> $DIR/suggest-trait-alias-instead-of-type.rs:10:18 + | +LL | struct Struct<S: Strings>(S); + | ^^^^^^^ type aliases cannot be used as traits + | +help: you might have meant to use `#![feature(trait_alias)]` instead of a `type` alias + | +LL | trait Strings = Iterator<Item=String>; + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0404`. diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer -Subproject 7be06139b632ee615fc18af04dd67947e2c794b +Subproject 7570212a544b8e973a7d57be3657aae6465028a |
