From 763703cb7696d51b83bb8507e5a74a31144ac782 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Mon, 11 Oct 2021 00:00:00 +0000 Subject: [PATCH 01/27] Remove redundant check for promoteds For some time CTFE has been using a dedicated MIR which is never optimized, so the check for promoted became redundant. --- .../rustc_mir_transform/src/uninhabited_enum_branching.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs index 2aa506112909d..961c5009ac541 100644 --- a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs +++ b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs @@ -71,10 +71,6 @@ fn variant_discriminants<'tcx>( impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - if body.source.promoted.is_some() { - return; - } - trace!("UninhabitedEnumBranching starting for {:?}", body.source); let basic_block_count = body.basic_blocks().len(); From d5a91f3114dde5a32dc69f9114fca0d9b0fd2abc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Mon, 11 Oct 2021 00:00:00 +0000 Subject: [PATCH 02/27] Use `IndexVec::indices` instead of reimplementing it The change is limited to the iteration over indices instead of using `basic_blocks_mut()` directly, in the case the previous implementation intentionally avoided invalidating the caches stored in MIR body. --- .../rustc_mir_transform/src/uninhabited_enum_branching.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs index 961c5009ac541..5a6f83652b4d2 100644 --- a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs +++ b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs @@ -3,8 +3,7 @@ use crate::MirPass; use rustc_data_structures::stable_set::FxHashSet; use rustc_middle::mir::{ - BasicBlock, BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, SwitchTargets, - TerminatorKind, + BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, SwitchTargets, TerminatorKind, }; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{Ty, TyCtxt}; @@ -73,10 +72,7 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { trace!("UninhabitedEnumBranching starting for {:?}", body.source); - let basic_block_count = body.basic_blocks().len(); - - for bb in 0..basic_block_count { - let bb = BasicBlock::from_usize(bb); + for bb in body.basic_blocks().indices() { trace!("processing block {:?}", bb); let Some(discriminant_ty) = get_switched_on_type(&body.basic_blocks()[bb], tcx, body) else { From c3e71d83cdeb0ccaf6584255313380fd166b1096 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Mon, 11 Oct 2021 00:00:00 +0000 Subject: [PATCH 03/27] Fix a variant index and variant discriminant confusion Previously for enums using the `Variants::Single` layout, the variant index was being confused with its discriminant. For example, in the case of `enum E { A = 1 }`. Use `discriminant_for_variant` to avoid the issue. --- .../rustc_mir_transform/src/uninhabited_enum_branching.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs index 5a6f83652b4d2..263ffb17d47d4 100644 --- a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs +++ b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs @@ -55,7 +55,10 @@ fn variant_discriminants<'tcx>( match &layout.variants { Variants::Single { index } => { let mut res = FxHashSet::default(); - res.insert(index.as_u32() as u128); + res.insert( + ty.discriminant_for_variant(tcx, *index) + .map_or(index.as_u32() as u128, |discr| discr.val), + ); res } Variants::Multiple { variants, .. } => variants From cd626fec2bcfa6b78d34a1ae023943c8a15a6641 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Mon, 6 Dec 2021 14:09:24 -0800 Subject: [PATCH 04/27] Stabilize -Z print-link-args as --print link-args We have stable options for adding linker arguments; we should have a stable option to help debug linker arguments. --- compiler/rustc_codegen_ssa/src/back/link.rs | 2 +- compiler/rustc_driver/src/lib.rs | 7 ++++--- compiler/rustc_interface/src/tests.rs | 1 - compiler/rustc_session/src/config.rs | 5 ++++- compiler/rustc_session/src/options.rs | 2 -- .../run-make-fulldeps/codegen-options-parsing/Makefile | 4 ++-- .../run-make-fulldeps/interdependent-c-libraries/Makefile | 2 +- src/test/run-make-fulldeps/link-arg/Makefile | 2 +- .../run-make-fulldeps/metadata-flag-frobs-symbols/Makefile | 2 +- src/test/run-make-fulldeps/no-builtins-lto/Makefile | 2 +- src/test/run-make-fulldeps/redundant-libs/Makefile | 2 +- src/test/run-make-fulldeps/static-nobundle/Makefile | 4 ++-- 12 files changed, 18 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 638b2a7b5a9f2..5397547670931 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -722,7 +722,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( cmd.env_remove(k); } - if sess.opts.debugging_opts.print_link_args { + if sess.opts.prints.contains(&PrintRequest::LinkArgs) { println!("{:?}", &cmd); } diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 6ff94341142fd..19f4c22d4bba3 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -652,9 +652,9 @@ impl RustcDefaultCalls { temps_dir: &Option, ) -> Compilation { use rustc_session::config::PrintRequest::*; - // PrintRequest::NativeStaticLibs is special - printed during linking + // NativeStaticLibs and LinkArgs are special - printed during linking // (empty iterator returns true) - if sess.opts.prints.iter().all(|&p| p == PrintRequest::NativeStaticLibs) { + if sess.opts.prints.iter().all(|&p| p == NativeStaticLibs || p == LinkArgs) { return Compilation::Continue; } @@ -745,7 +745,8 @@ impl RustcDefaultCalls { codegen_backend.print(*req, sess); } // Any output here interferes with Cargo's parsing of other printed output - PrintRequest::NativeStaticLibs => {} + NativeStaticLibs => {} + LinkArgs => {} } } Compilation::Stop diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index c651feaaa66f6..760187f04151c 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -675,7 +675,6 @@ fn test_debugging_options_tracking_hash() { // `pre_link_arg` is omitted because it just forwards to `pre_link_args`. untracked!(pre_link_args, vec![String::from("abc"), String::from("def")]); untracked!(profile_closures, true); - untracked!(print_link_args, true); untracked!(print_llvm_passes, true); untracked!(print_mono_items, Some(String::from("abc"))); untracked!(print_type_sizes, true); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 87e8e57611765..ec32201c26317 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -534,6 +534,7 @@ pub enum PrintRequest { TargetSpec, NativeStaticLibs, StackProtectorStrategies, + LinkArgs, } #[derive(Copy, Clone)] @@ -1115,7 +1116,8 @@ pub fn rustc_short_optgroups() -> Vec { "Compiler information to print on stdout", "[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\ target-cpus|target-features|relocation-models|code-models|\ - tls-models|target-spec-json|native-static-libs|stack-protector-strategies]", + tls-models|target-spec-json|native-static-libs|stack-protector-strategies\ + link-args]", ), opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"), opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"), @@ -1547,6 +1549,7 @@ fn collect_print_requests( ); } } + "link-args" => PrintRequest::LinkArgs, req => early_error(error_format, &format!("unknown print request `{}`", req)), })); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index bd7b1639613eb..7114b11703140 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1294,8 +1294,6 @@ options! { See #77382 and #74551."), print_fuel: Option = (None, parse_opt_string, [TRACKED], "make rustc print the total optimization fuel used by a crate"), - print_link_args: bool = (false, parse_bool, [UNTRACKED], - "print the arguments passed to the linker (default: no)"), print_llvm_passes: bool = (false, parse_bool, [UNTRACKED], "print the LLVM optimization passes being run (default: no)"), print_mono_items: Option = (None, parse_opt_string, [UNTRACKED], diff --git a/src/test/run-make-fulldeps/codegen-options-parsing/Makefile b/src/test/run-make-fulldeps/codegen-options-parsing/Makefile index 39e9a9bdd6b68..f1410b69b3fce 100644 --- a/src/test/run-make-fulldeps/codegen-options-parsing/Makefile +++ b/src/test/run-make-fulldeps/codegen-options-parsing/Makefile @@ -24,8 +24,8 @@ all: $(RUSTC) -C lto dummy.rs # Should not link dead code... - $(RUSTC) -Z print-link-args dummy.rs 2>&1 | \ + $(RUSTC) --print link-args dummy.rs 2>&1 | \ $(CGREP) -e '--gc-sections|-z[^ ]* [^ ]*|-dead_strip|/OPT:REF' # ... unless you specifically ask to keep it - $(RUSTC) -Z print-link-args -C link-dead-code dummy.rs 2>&1 | \ + $(RUSTC) --print link-args -C link-dead-code dummy.rs 2>&1 | \ $(CGREP) -ve '--gc-sections|-z[^ ]* [^ ]*|-dead_strip|/OPT:REF' diff --git a/src/test/run-make-fulldeps/interdependent-c-libraries/Makefile b/src/test/run-make-fulldeps/interdependent-c-libraries/Makefile index 1268022e37b74..0a50859cdaa4d 100644 --- a/src/test/run-make-fulldeps/interdependent-c-libraries/Makefile +++ b/src/test/run-make-fulldeps/interdependent-c-libraries/Makefile @@ -11,4 +11,4 @@ all: $(call NATIVE_STATICLIB,foo) $(call NATIVE_STATICLIB,bar) $(RUSTC) foo.rs $(RUSTC) bar.rs - $(RUSTC) main.rs -Z print-link-args + $(RUSTC) main.rs --print link-args diff --git a/src/test/run-make-fulldeps/link-arg/Makefile b/src/test/run-make-fulldeps/link-arg/Makefile index d7c9fd2711285..0360ede762551 100644 --- a/src/test/run-make-fulldeps/link-arg/Makefile +++ b/src/test/run-make-fulldeps/link-arg/Makefile @@ -1,5 +1,5 @@ -include ../tools.mk -RUSTC_FLAGS = -C link-arg="-lfoo" -C link-arg="-lbar" -Z print-link-args +RUSTC_FLAGS = -C link-arg="-lfoo" -C link-arg="-lbar" --print link-args all: $(RUSTC) $(RUSTC_FLAGS) empty.rs | $(CGREP) lfoo lbar diff --git a/src/test/run-make-fulldeps/metadata-flag-frobs-symbols/Makefile b/src/test/run-make-fulldeps/metadata-flag-frobs-symbols/Makefile index 09e6ae0bbf7cd..3ffbba9444bc2 100644 --- a/src/test/run-make-fulldeps/metadata-flag-frobs-symbols/Makefile +++ b/src/test/run-make-fulldeps/metadata-flag-frobs-symbols/Makefile @@ -6,5 +6,5 @@ all: $(RUSTC) bar.rs \ --extern foo1=$(TMPDIR)/libfoo-a.rlib \ --extern foo2=$(TMPDIR)/libfoo-b.rlib \ - -Z print-link-args + --print link-args $(call RUN,bar) diff --git a/src/test/run-make-fulldeps/no-builtins-lto/Makefile b/src/test/run-make-fulldeps/no-builtins-lto/Makefile index b9688f16c6464..2e41be39d5d00 100644 --- a/src/test/run-make-fulldeps/no-builtins-lto/Makefile +++ b/src/test/run-make-fulldeps/no-builtins-lto/Makefile @@ -6,4 +6,4 @@ all: # Build an executable that depends on that crate using LTO. The no_builtins crate doesn't # participate in LTO, so its rlib must be explicitly linked into the final binary. Verify this by # grepping the linker arguments. - $(RUSTC) main.rs -C lto -Z print-link-args | $(CGREP) 'libno_builtins.rlib' + $(RUSTC) main.rs -C lto --print link-args | $(CGREP) 'libno_builtins.rlib' diff --git a/src/test/run-make-fulldeps/redundant-libs/Makefile b/src/test/run-make-fulldeps/redundant-libs/Makefile index 8468d102bec83..e09841fb42e18 100644 --- a/src/test/run-make-fulldeps/redundant-libs/Makefile +++ b/src/test/run-make-fulldeps/redundant-libs/Makefile @@ -16,7 +16,7 @@ RUSTC_FLAGS = \ -l foo \ -l static=baz \ -l foo \ - -Z print-link-args + --print link-args all: $(call DYLIB,foo) $(call STATICLIB,bar) $(call STATICLIB,baz) $(RUSTC) $(RUSTC_FLAGS) main.rs diff --git a/src/test/run-make-fulldeps/static-nobundle/Makefile b/src/test/run-make-fulldeps/static-nobundle/Makefile index abc32d4423b05..8f78c401a1141 100644 --- a/src/test/run-make-fulldeps/static-nobundle/Makefile +++ b/src/test/run-make-fulldeps/static-nobundle/Makefile @@ -13,9 +13,9 @@ all: $(call NATIVE_STATICLIB,aaa) nm $(TMPDIR)/libbbb.rlib | $(CGREP) -e "U _*native_func" # Check that aaa gets linked (either as `-l aaa` or `aaa.lib`) when building ccc. - $(RUSTC) ccc.rs -C prefer-dynamic --crate-type=dylib -Z print-link-args | $(CGREP) -e '-l[" ]*aaa|aaa\.lib' + $(RUSTC) ccc.rs -C prefer-dynamic --crate-type=dylib --print link-args | $(CGREP) -e '-l[" ]*aaa|aaa\.lib' # Check that aaa does NOT get linked when building ddd. - $(RUSTC) ddd.rs -Z print-link-args | $(CGREP) -ve '-l[" ]*aaa|aaa\.lib' + $(RUSTC) ddd.rs --print link-args | $(CGREP) -ve '-l[" ]*aaa|aaa\.lib' $(call RUN,ddd) From 371bd4643587da89ce1bbe7e577f49d9b8acb990 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Mon, 6 Dec 2021 14:10:25 -0800 Subject: [PATCH 05/27] Document `--print link-args` The documentation makes it clear that the *exact* format of the output is not a stable guarantee. --- src/doc/rustc/src/command-line-arguments.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md index 7f482f0f2b1a0..11925ab978588 100644 --- a/src/doc/rustc/src/command-line-arguments.md +++ b/src/doc/rustc/src/command-line-arguments.md @@ -170,6 +170,12 @@ The valid types of print values are: include a diagnostic note that indicates the linker flags to use when linking the resulting static library. The note starts with the text `native-static-libs:` to make it easier to fetch the output. +- `link-args` — This flag does not disable the `--emit` step. When linking, + this flag causes `rustc` to print the full linker invocation in a + human-readable form. This can be useful when debugging linker options. The + exact format of this debugging output is not a stable guarantee, other than + that it will include the linker executable and the text of each command-line + argument passed to the linker. [conditional compilation]: ../reference/conditional-compilation.html From 36a11417fafcbfae0500884df2d4b6dd2c5e5a0f Mon Sep 17 00:00:00 2001 From: 5225225 <5225225@mailbox.org> Date: Sun, 9 Jan 2022 22:15:23 +0000 Subject: [PATCH 06/27] Make message for &T -> &mut T transmute more accurate --- compiler/rustc_lint/src/builtin.rs | 6 +++--- src/test/ui/transmute/transmute-imut-to-mut.rs | 2 +- src/test/ui/transmute/transmute-imut-to-mut.stderr | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index c0384875a47c9..2b373a53b635d 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1248,7 +1248,7 @@ declare_lint! { /// [`UnsafeCell`]: https://doc.rust-lang.org/std/cell/struct.UnsafeCell.html MUTABLE_TRANSMUTES, Deny, - "mutating transmuted &mut T from &T may cause undefined behavior" + "transmuting &T to &mut T is undefined behavior, even if the reference is unused" } declare_lint_pass!(MutableTransmutes => [MUTABLE_TRANSMUTES]); @@ -1260,8 +1260,8 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes { get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (ty1.kind(), ty2.kind())) { if to_mt == hir::Mutability::Mut && from_mt == hir::Mutability::Not { - let msg = "mutating transmuted &mut T from &T may cause undefined behavior, \ - consider instead using an UnsafeCell"; + let msg = "transmuting &T to &mut T is undefined behavior, \ + even if the reference is unused, consider instead using an UnsafeCell"; cx.struct_span_lint(MUTABLE_TRANSMUTES, expr.span, |lint| lint.build(msg).emit()); } } diff --git a/src/test/ui/transmute/transmute-imut-to-mut.rs b/src/test/ui/transmute/transmute-imut-to-mut.rs index 8e34e0ae8c74d..9f3f76c1ef3e0 100644 --- a/src/test/ui/transmute/transmute-imut-to-mut.rs +++ b/src/test/ui/transmute/transmute-imut-to-mut.rs @@ -4,5 +4,5 @@ use std::mem::transmute; fn main() { let _a: &mut u8 = unsafe { transmute(&1u8) }; - //~^ ERROR mutating transmuted &mut T from &T may cause undefined behavior + //~^ ERROR transmuting &T to &mut T is undefined behavior, even if the reference is unused, consider instead using an UnsafeCell } diff --git a/src/test/ui/transmute/transmute-imut-to-mut.stderr b/src/test/ui/transmute/transmute-imut-to-mut.stderr index d323c1a73b772..1e9dff3ce89b2 100644 --- a/src/test/ui/transmute/transmute-imut-to-mut.stderr +++ b/src/test/ui/transmute/transmute-imut-to-mut.stderr @@ -1,4 +1,4 @@ -error: mutating transmuted &mut T from &T may cause undefined behavior, consider instead using an UnsafeCell +error: transmuting &T to &mut T is undefined behavior, even if the reference is unused, consider instead using an UnsafeCell --> $DIR/transmute-imut-to-mut.rs:6:32 | LL | let _a: &mut u8 = unsafe { transmute(&1u8) }; From dc1c39b10ed4650de784e860e2778c3e246f585e Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Thu, 9 Dec 2021 00:21:36 -0500 Subject: [PATCH 07/27] rustdoc: decouple stability and const-stability --- src/librustdoc/html/render/mod.rs | 91 ++++++++++++++++++------------ src/test/rustdoc/const-display.rs | 17 ++++++ src/test/rustdoc/deref-const-fn.rs | 2 +- 3 files changed, 73 insertions(+), 37 deletions(-) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index dda7490493197..3dfe03b54e9f2 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -792,6 +792,20 @@ fn assoc_type( } } +/// Writes a span containing the versions at which an item became stable and/or const-stable. For +/// example, if the item became stable at 1.0.0, and const-stable at 1.45.0, this function would +/// write a span containing "1.0.0 (const: 1.45.0)". +/// +/// Returns `true` if a stability annotation was rendered. +/// +/// Stability and const-stability are considered separately. If the item is unstable, no version +/// will be written. If the item is const-unstable, "const: unstable" will be appended to the +/// span, with a link to the tracking issue if present. If an item's stability or const-stability +/// version matches the version of its enclosing item, that version will be omitted. +/// +/// Note that it is possible for an unstable function to be const-stable. In that case, the span +/// will include the const-stable version, but no stable version will be emitted, as a natural +/// consequence of the above rules. fn render_stability_since_raw( w: &mut Buffer, ver: Option, @@ -799,51 +813,56 @@ fn render_stability_since_raw( containing_ver: Option, containing_const_ver: Option, ) -> bool { - let ver = ver.filter(|inner| !inner.is_empty()); + let stable_version = ver.filter(|inner| !inner.is_empty() && Some(*inner) != containing_ver); - match (ver, const_stability) { - // stable and const stable - (Some(v), Some(ConstStability { level: StabilityLevel::Stable { since }, .. })) + let mut title = String::new(); + let mut stability = String::new(); + + if let Some(ver) = stable_version { + stability.push_str(&ver.as_str()); + title.push_str(&format!("Stable since Rust version {}", ver)); + } + + let const_title_and_stability = match const_stability { + Some(ConstStability { level: StabilityLevel::Stable { since }, .. }) if Some(since) != containing_const_ver => { - write!( - w, - "{0} (const: {1})", - v, since - ); + Some((format!("const since {}", since), format!("const: {}", since))) } - // stable and const unstable - ( - Some(v), - Some(ConstStability { level: StabilityLevel::Unstable { issue, .. }, feature, .. }), - ) => { - write!( - w, - "{0} (const: ", - v - ); - if let Some(n) = issue { - write!( - w, - "unstable", + Some(ConstStability { level: StabilityLevel::Unstable { issue, .. }, feature, .. }) => { + let unstable = if let Some(n) = issue { + format!( + r#"unstable"#, n, feature - ); + ) } else { - write!(w, "unstable"); - } - write!(w, ")"); + String::from("unstable") + }; + + Some((String::from("const unstable"), format!("const: {}", unstable))) } - // stable - (Some(v), _) if ver != containing_ver => { - write!( - w, - "{0}", - v - ); + _ => None, + }; + + if let Some((const_title, const_stability)) = const_title_and_stability { + if !title.is_empty() { + title.push_str(&format!(", {}", const_title)); + } else { + title.push_str(&const_title); + } + + if !stability.is_empty() { + stability.push_str(&format!(" ({})", const_stability)); + } else { + stability.push_str(&const_stability); } - _ => return false, } - true + + if !stability.is_empty() { + write!(w, r#"{}"#, title, stability); + } + + !stability.is_empty() } fn render_assoc_item( diff --git a/src/test/rustdoc/const-display.rs b/src/test/rustdoc/const-display.rs index fb8ea7e33c28c..b8e101038f8f1 100644 --- a/src/test/rustdoc/const-display.rs +++ b/src/test/rustdoc/const-display.rs @@ -67,3 +67,20 @@ impl Foo { #[rustc_const_stable(feature = "rust1", since = "1.2.0")] pub const fn stable_impl() -> u32 { 42 } } + +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Bar; + +impl Bar { + // Do not show non-const stabilities that are the same as the enclosing item. + // @matches 'foo/struct.Bar.html' '//span[@class="since"]' '^const: 1.2.0$' + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "rust1", since = "1.2.0")] + pub const fn stable_impl() -> u32 { 42 } + + // Show const-stability even for unstable functions. + // @matches 'foo/struct.Bar.html' '//span[@class="since"]' '^const: 1.3.0$' + #[unstable(feature = "foo2", issue = "none")] + #[rustc_const_stable(feature = "rust1", since = "1.3.0")] + pub const fn const_stable_unstable() -> u32 { 42 } +} diff --git a/src/test/rustdoc/deref-const-fn.rs b/src/test/rustdoc/deref-const-fn.rs index ca51f3c7b5af0..8ecca6d12d24a 100644 --- a/src/test/rustdoc/deref-const-fn.rs +++ b/src/test/rustdoc/deref-const-fn.rs @@ -13,7 +13,7 @@ pub struct Bar; impl Bar { // @has - '//*[@id="method.len"]' 'pub const fn len(&self) -> usize' - // @has - '//*[@id="method.len"]//span[@class="since"]' '1.0.0 (const: 1.0.0)' + // @has - '//*[@id="method.len"]//span[@class="since"]' 'const: 1.0.0' #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] pub const fn len(&self) -> usize { 0 } From c2807525a5d7adff0e340007f73b9558f45e38b5 Mon Sep 17 00:00:00 2001 From: Kornel Date: Mon, 17 Jan 2022 02:17:25 +0000 Subject: [PATCH 08/27] Help optimize out backtraces when disabled --- library/std/src/panicking.rs | 2 +- library/std/src/sys_common/backtrace.rs | 25 ++++++++++++++++++------- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 44f573297eed1..d0f332fe5e810 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -263,7 +263,7 @@ fn default_hook(info: &PanicInfo<'_>) { // If this is a double panic, make sure that we print a backtrace // for this panic. Otherwise only print it if logging is enabled. let backtrace_env = if panic_count::get_count() >= 2 { - RustBacktrace::Print(crate::backtrace_rs::PrintFmt::Full) + backtrace::rust_backtrace_print_full() } else { backtrace::rust_backtrace_env() }; diff --git a/library/std/src/sys_common/backtrace.rs b/library/std/src/sys_common/backtrace.rs index d5e8f12414ff2..dc581a0675b38 100644 --- a/library/std/src/sys_common/backtrace.rs +++ b/library/std/src/sys_common/backtrace.rs @@ -150,16 +150,18 @@ pub enum RustBacktrace { RuntimeDisabled, } +// If the `backtrace` feature of this crate isn't enabled quickly return +// `Disabled` so this can be constant propagated all over the place to +// optimize away callers. +#[cfg(not(feature = "backtrace"))] +pub fn rust_backtrace_env() -> RustBacktrace { + RustBacktrace::Disabled +} + // For now logging is turned off by default, and this function checks to see // whether the magical environment variable is present to see if it's turned on. +#[cfg(feature = "backtrace")] pub fn rust_backtrace_env() -> RustBacktrace { - // If the `backtrace` feature of this crate isn't enabled quickly return - // `None` so this can be constant propagated all over the place to turn - // optimize away callers. - if !cfg!(feature = "backtrace") { - return RustBacktrace::Disabled; - } - // Setting environment variables for Fuchsia components isn't a standard // or easily supported workflow. For now, always display backtraces. if cfg!(target_os = "fuchsia") { @@ -189,6 +191,15 @@ pub fn rust_backtrace_env() -> RustBacktrace { format } +/// Setting for printing the full backtrace, unless backtraces are completely disabled +pub(crate) fn rust_backtrace_print_full() -> RustBacktrace { + if cfg!(feature = "backtrace") { + RustBacktrace::Print(PrintFmt::Full) + } else { + RustBacktrace::Disabled + } +} + /// Prints the filename of the backtrace frame. /// /// See also `output`. From a8b71164af36a5a9584c1a2205a1e8216d27cdc7 Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 5 Jan 2022 11:42:08 +0100 Subject: [PATCH 09/27] change `ct_infer` to a delay_span_bug --- compiler/rustc_middle/src/ty/context.rs | 20 +++++++++++++++++--- compiler/rustc_typeck/src/collect.rs | 6 ++---- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index e7b99995ca4ae..6eb3653dd7baa 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1210,11 +1210,25 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_ty(Error(DelaySpanBugEmitted(()))) } - /// Like `err` but for constants. + /// Like [`ty_error`] but for constants. #[track_caller] pub fn const_error(self, ty: Ty<'tcx>) -> &'tcx Const<'tcx> { - self.sess - .delay_span_bug(DUMMY_SP, "ty::ConstKind::Error constructed but no error reported."); + self.const_error_with_message( + ty, + DUMMY_SP, + "ty::ConstKind::Error constructed but no error reported", + ) + } + + /// Like [`ty_error_with_message`] but for constants. + #[track_caller] + pub fn const_error_with_message>( + self, + ty: Ty<'tcx>, + span: S, + msg: &str, + ) -> &'tcx Const<'tcx> { + self.sess.delay_span_bug(span, msg); self.mk_const(ty::Const { val: ty::ConstKind::Error(DelaySpanBugEmitted(())), ty }) } diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 314174e0f8501..8204b5cc36182 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -381,7 +381,7 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { } fn ty_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> { - self.tcx().ty_error_with_message(span, "bad_placeholder_type") + self.tcx().ty_error_with_message(span, "bad placeholder type") } fn ct_infer( @@ -390,13 +390,11 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { _: Option<&ty::GenericParamDef>, span: Span, ) -> &'tcx Const<'tcx> { - bad_placeholder(self.tcx(), "const", vec![span], "generic").emit(); - // Typeck doesn't expect erased regions to be returned from `type_of`. let ty = self.tcx.fold_regions(ty, &mut false, |r, _| match r { ty::ReErased => self.tcx.lifetimes.re_static, _ => r, }); - self.tcx().const_error(ty) + self.tcx().const_error_with_message(ty, span, "bad placeholder constant") } fn projected_ty_from_poly_trait_ref( From 621e60a54fc1b0b06517b354edd4fda006723f8f Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 5 Jan 2022 11:42:45 +0100 Subject: [PATCH 10/27] remove unnecessary fixme --- compiler/rustc_typeck/src/collect/type_of.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index bc7507bcc500f..a6e8b36f78b3e 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -20,9 +20,6 @@ use super::{bad_placeholder, is_suggestable_infer_ty}; /// This should be called using the query `tcx.opt_const_param_of`. #[instrument(level = "debug", skip(tcx))] pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { - // FIXME(generic_arg_infer): allow for returning DefIds of inference of - // GenericArg::Infer below. This may require a change where GenericArg::Infer has some flag - // for const or type. use hir::*; let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); From b2d8f0c77db87cc84551598ceba3f4e8615eb66c Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 5 Jan 2022 11:43:21 +0100 Subject: [PATCH 11/27] generic_arg_infer: placeholder in signature err --- compiler/rustc_typeck/src/astconv/mod.rs | 4 +- compiler/rustc_typeck/src/collect.rs | 40 +++--- compiler/rustc_typeck/src/collect/type_of.rs | 2 +- .../generic_arg_infer/array-in-sig.rs | 12 -- .../generic_arg_infer/array-in-sig.stderr | 9 -- .../generic_arg_infer/in-signature.rs | 61 +++++++++ .../generic_arg_infer/in-signature.stderr | 119 +++++++++++++++++ src/test/ui/did_you_mean/bad-assoc-ty.rs | 20 +-- src/test/ui/did_you_mean/bad-assoc-ty.stderr | 20 +-- src/test/ui/error-codes/E0121.stderr | 4 +- src/test/ui/fn/issue-80179.rs | 4 +- src/test/ui/fn/issue-80179.stderr | 4 +- .../issue-69396-const-no-type-in-macro.rs | 2 +- .../issue-69396-const-no-type-in-macro.stderr | 2 +- src/test/ui/self/self-infer.rs | 4 +- src/test/ui/self/self-infer.stderr | 4 +- src/test/ui/suggestions/unnamable-types.rs | 4 +- .../ui/suggestions/unnamable-types.stderr | 4 +- .../ui/type-alias-impl-trait/issue-77179.rs | 2 +- .../type-alias-impl-trait/issue-77179.stderr | 2 +- src/test/ui/typeck/issue-74086.rs | 2 +- src/test/ui/typeck/issue-74086.stderr | 2 +- src/test/ui/typeck/issue-75883.rs | 4 +- src/test/ui/typeck/issue-75883.stderr | 4 +- src/test/ui/typeck/issue-75889.stderr | 4 +- src/test/ui/typeck/issue-80779.rs | 4 +- src/test/ui/typeck/issue-80779.stderr | 4 +- src/test/ui/typeck/issue-81885.rs | 4 +- src/test/ui/typeck/issue-81885.stderr | 4 +- ...-83621-placeholder-static-in-extern.stderr | 2 +- .../ui/typeck/issue-91450-inner-ty-error.rs | 2 +- .../typeck/issue-91450-inner-ty-error.stderr | 2 +- .../ui/typeck/type-placeholder-fn-in-const.rs | 6 +- .../type-placeholder-fn-in-const.stderr | 6 +- .../ui/typeck/typeck_type_placeholder_item.rs | 120 +++++++++--------- .../typeck_type_placeholder_item.stderr | 120 +++++++++--------- .../typeck_type_placeholder_item_help.rs | 12 +- .../typeck_type_placeholder_item_help.stderr | 12 +- 38 files changed, 402 insertions(+), 235 deletions(-) delete mode 100644 src/test/ui/const-generics/generic_arg_infer/array-in-sig.rs delete mode 100644 src/test/ui/const-generics/generic_arg_infer/array-in-sig.stderr create mode 100644 src/test/ui/const-generics/generic_arg_infer/in-signature.rs create mode 100644 src/test/ui/const-generics/generic_arg_infer/in-signature.stderr diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 2ada1c0ddf4fa..fca72837d12b5 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -6,7 +6,7 @@ mod errors; mod generics; use crate::bounds::Bounds; -use crate::collect::PlaceholderHirTyCollector; +use crate::collect::HirPlaceholderCollector; use crate::errors::{ AmbiguousLifetimeBound, MultipleRelaxedDefaultBounds, TraitObjectDeclaredWithNoTraits, TypeofReservedKeywordUsed, ValueOfAssociatedStructAlreadySpecified, @@ -2478,7 +2478,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { debug!(?bound_vars); // We proactively collect all the inferred type params to emit a single error per fn def. - let mut visitor = PlaceholderHirTyCollector::default(); + let mut visitor = HirPlaceholderCollector::default(); for ty in decl.inputs { visitor.visit_ty(ty); } diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 8204b5cc36182..97a21de5d3a1e 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -112,9 +112,9 @@ pub struct ItemCtxt<'tcx> { /////////////////////////////////////////////////////////////////////////// #[derive(Default)] -crate struct PlaceholderHirTyCollector(crate Vec); +crate struct HirPlaceholderCollector(crate Vec); -impl<'v> Visitor<'v> for PlaceholderHirTyCollector { +impl<'v> Visitor<'v> for HirPlaceholderCollector { fn visit_ty(&mut self, t: &'v hir::Ty<'v>) { if let hir::TyKind::Infer = t.kind { self.0.push(t.span); @@ -131,6 +131,12 @@ impl<'v> Visitor<'v> for PlaceholderHirTyCollector { _ => {} } } + fn visit_array_length(&mut self, length: &'v hir::ArrayLen) { + if let &hir::ArrayLen::Infer(_, span) = length { + self.0.push(span); + } + intravisit::walk_array_len(self, length) + } } struct CollectItemTypesVisitor<'tcx> { @@ -175,7 +181,7 @@ crate fn placeholder_type_error<'tcx>( sugg.push((span, format!(", {}", type_name))); } - let mut err = bad_placeholder(tcx, "type", placeholder_types, kind); + let mut err = bad_placeholder(tcx, placeholder_types, kind); // Suggest, but only if it is not a function in const or static if suggest { @@ -233,7 +239,7 @@ fn reject_placeholder_type_signatures_in_item<'tcx>( _ => return, }; - let mut visitor = PlaceholderHirTyCollector::default(); + let mut visitor = HirPlaceholderCollector::default(); visitor.visit_item(item); placeholder_type_error( @@ -311,7 +317,6 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { fn bad_placeholder<'tcx>( tcx: TyCtxt<'tcx>, - placeholder_kind: &'static str, mut spans: Vec, kind: &'static str, ) -> rustc_errors::DiagnosticBuilder<'tcx> { @@ -322,8 +327,7 @@ fn bad_placeholder<'tcx>( tcx.sess, spans.clone(), E0121, - "the {} placeholder `_` is not allowed within types on item signatures for {}", - placeholder_kind, + "the placeholder `_` is not allowed within types on item signatures for {}", kind ); for span in spans { @@ -737,7 +741,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { match item.kind { hir::ForeignItemKind::Fn(..) => tcx.ensure().fn_sig(item.def_id), hir::ForeignItemKind::Static(..) => { - let mut visitor = PlaceholderHirTyCollector::default(); + let mut visitor = HirPlaceholderCollector::default(); visitor.visit_foreign_item(item); placeholder_type_error( tcx, @@ -820,7 +824,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { hir::ItemKind::Const(ty, ..) | hir::ItemKind::Static(ty, ..) => { // (#75889): Account for `const C: dyn Fn() -> _ = "";` if let hir::TyKind::TraitObject(..) = ty.kind { - let mut visitor = PlaceholderHirTyCollector::default(); + let mut visitor = HirPlaceholderCollector::default(); visitor.visit_item(it); placeholder_type_error( tcx, @@ -856,7 +860,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { hir::TraitItemKind::Const(..) => { tcx.ensure().type_of(trait_item_id.def_id); // Account for `const C: _;`. - let mut visitor = PlaceholderHirTyCollector::default(); + let mut visitor = HirPlaceholderCollector::default(); visitor.visit_trait_item(trait_item); placeholder_type_error(tcx, None, &[], visitor.0, false, None, "constant"); } @@ -865,7 +869,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { tcx.ensure().item_bounds(trait_item_id.def_id); tcx.ensure().type_of(trait_item_id.def_id); // Account for `type T = _;`. - let mut visitor = PlaceholderHirTyCollector::default(); + let mut visitor = HirPlaceholderCollector::default(); visitor.visit_trait_item(trait_item); placeholder_type_error(tcx, None, &[], visitor.0, false, None, "associated type"); } @@ -874,7 +878,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { tcx.ensure().item_bounds(trait_item_id.def_id); // #74612: Visit and try to find bad placeholders // even if there is no concrete type. - let mut visitor = PlaceholderHirTyCollector::default(); + let mut visitor = HirPlaceholderCollector::default(); visitor.visit_trait_item(trait_item); placeholder_type_error(tcx, None, &[], visitor.0, false, None, "associated type"); @@ -896,7 +900,7 @@ fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) { } hir::ImplItemKind::TyAlias(_) => { // Account for `type T = _;` - let mut visitor = PlaceholderHirTyCollector::default(); + let mut visitor = HirPlaceholderCollector::default(); visitor.visit_impl_item(impl_item); placeholder_type_error(tcx, None, &[], visitor.0, false, None, "associated type"); @@ -1816,10 +1820,14 @@ fn are_suggestable_generic_args(generic_args: &[hir::GenericArg<'_>]) -> bool { /// Whether `ty` is a type with `_` placeholders that can be inferred. Used in diagnostics only to /// use inference to provide suggestions for the appropriate type if possible. fn is_suggestable_infer_ty(ty: &hir::Ty<'_>) -> bool { + debug!(?ty); use hir::TyKind::*; match &ty.kind { Infer => true, - Slice(ty) | Array(ty, _) => is_suggestable_infer_ty(ty), + Slice(ty) => is_suggestable_infer_ty(ty), + Array(ty, length) => { + is_suggestable_infer_ty(ty) || matches!(length, hir::ArrayLen::Infer(_, _)) + } Tup(tys) => tys.iter().any(is_suggestable_infer_ty), Ptr(mut_ty) | Rptr(_, mut_ty) => is_suggestable_infer_ty(mut_ty.ty), OpaqueDef(_, generic_args) => are_suggestable_generic_args(generic_args), @@ -1871,9 +1879,9 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { }); let fn_sig = ty::Binder::dummy(fn_sig); - let mut visitor = PlaceholderHirTyCollector::default(); + let mut visitor = HirPlaceholderCollector::default(); visitor.visit_ty(ty); - let mut diag = bad_placeholder(tcx, "type", visitor.0, "return type"); + let mut diag = bad_placeholder(tcx, visitor.0, "return type"); let ret_ty = fn_sig.skip_binder().output(); if !ret_ty.references_error() { if !ret_ty.is_closure() { diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index a6e8b36f78b3e..63020b7f90f0a 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -750,7 +750,7 @@ fn infer_placeholder_type<'a>( err.emit(); } None => { - let mut diag = bad_placeholder(tcx, "type", vec![span], kind); + let mut diag = bad_placeholder(tcx, vec![span], kind); if !ty.references_error() { let mut mk_nameable = MakeNameable::new(tcx); diff --git a/src/test/ui/const-generics/generic_arg_infer/array-in-sig.rs b/src/test/ui/const-generics/generic_arg_infer/array-in-sig.rs deleted file mode 100644 index 56b88a426a1a8..0000000000000 --- a/src/test/ui/const-generics/generic_arg_infer/array-in-sig.rs +++ /dev/null @@ -1,12 +0,0 @@ -// To avoid having to `or` gate `_` as an expr. -#![feature(generic_arg_infer)] - -fn foo() -> [u8; _] { - //~^ ERROR the const placeholder `_` is not allowed within types on item signatures for generics - // FIXME(generic_arg_infer): this error message should say in the return type or sth like that. - [0; 3] -} - -fn main() { - foo(); -} diff --git a/src/test/ui/const-generics/generic_arg_infer/array-in-sig.stderr b/src/test/ui/const-generics/generic_arg_infer/array-in-sig.stderr deleted file mode 100644 index eaa12b4192dc6..0000000000000 --- a/src/test/ui/const-generics/generic_arg_infer/array-in-sig.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0121]: the const placeholder `_` is not allowed within types on item signatures for generics - --> $DIR/array-in-sig.rs:4:18 - | -LL | fn foo() -> [u8; _] { - | ^ not allowed in type signatures - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0121`. diff --git a/src/test/ui/const-generics/generic_arg_infer/in-signature.rs b/src/test/ui/const-generics/generic_arg_infer/in-signature.rs new file mode 100644 index 0000000000000..1f60b2242411d --- /dev/null +++ b/src/test/ui/const-generics/generic_arg_infer/in-signature.rs @@ -0,0 +1,61 @@ +#![crate_type = "rlib"] +#![feature(generic_arg_infer)] + +struct Foo; +struct Bar(T); + +fn arr_fn() -> [u8; _] { + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types + [0; 3] +} + +fn ty_fn() -> Bar { + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types + Bar::(0) +} + +fn ty_fn_mixed() -> Bar<_, _> { + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types + Bar::(0) +} + +const ARR_CT: [u8; _] = [0; 3]; +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants +static ARR_STATIC: [u8; _] = [0; 3]; +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for static variables +const TY_CT: Bar = Bar::(0); +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants +static TY_STATIC: Bar = Bar::(0); +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for static variables +const TY_CT_MIXED: Bar<_, _> = Bar::(0); +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants +static TY_STATIC_MIXED: Bar<_, _> = Bar::(0); +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for static variables +trait ArrAssocConst { + const ARR: [u8; _]; + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants +} +trait TyAssocConst { + const ARR: Bar; + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants +} +trait TyAssocConstMixed { + const ARR: Bar<_, _>; + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants +} + +trait AssocTy { + type Assoc; +} +impl AssocTy for i8 { + type Assoc = [u8; _]; + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated types +} +impl AssocTy for i16 { + type Assoc = Bar; + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated types +} +impl AssocTy for i32 { + type Assoc = Bar<_, _>; + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated types +} diff --git a/src/test/ui/const-generics/generic_arg_infer/in-signature.stderr b/src/test/ui/const-generics/generic_arg_infer/in-signature.stderr new file mode 100644 index 0000000000000..7581cf4120ecf --- /dev/null +++ b/src/test/ui/const-generics/generic_arg_infer/in-signature.stderr @@ -0,0 +1,119 @@ +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types + --> $DIR/in-signature.rs:7:21 + | +LL | fn arr_fn() -> [u8; _] { + | -----^- + | | | + | | not allowed in type signatures + | help: replace with the correct return type: `[u8; 3]` + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types + --> $DIR/in-signature.rs:12:24 + | +LL | fn ty_fn() -> Bar { + | ---------^- + | | | + | | not allowed in type signatures + | help: replace with the correct return type: `Bar` + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types + --> $DIR/in-signature.rs:17:25 + | +LL | fn ty_fn_mixed() -> Bar<_, _> { + | ----^--^- + | | | | + | | | not allowed in type signatures + | | not allowed in type signatures + | help: replace with the correct return type: `Bar` + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants + --> $DIR/in-signature.rs:22:15 + | +LL | const ARR_CT: [u8; _] = [0; 3]; + | ^^^^^^^ not allowed in type signatures + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables + --> $DIR/in-signature.rs:24:20 + | +LL | static ARR_STATIC: [u8; _] = [0; 3]; + | ^^^^^^^ not allowed in type signatures + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants + --> $DIR/in-signature.rs:26:14 + | +LL | const TY_CT: Bar = Bar::(0); + | ^^^^^^^^^^^ + | | + | not allowed in type signatures + | help: replace with the correct type: `Bar` + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables + --> $DIR/in-signature.rs:28:19 + | +LL | static TY_STATIC: Bar = Bar::(0); + | ^^^^^^^^^^^ + | | + | not allowed in type signatures + | help: replace with the correct type: `Bar` + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants + --> $DIR/in-signature.rs:30:20 + | +LL | const TY_CT_MIXED: Bar<_, _> = Bar::(0); + | ^^^^^^^^^ + | | + | not allowed in type signatures + | help: replace with the correct type: `Bar` + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables + --> $DIR/in-signature.rs:32:25 + | +LL | static TY_STATIC_MIXED: Bar<_, _> = Bar::(0); + | ^^^^^^^^^ + | | + | not allowed in type signatures + | help: replace with the correct type: `Bar` + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants + --> $DIR/in-signature.rs:35:21 + | +LL | const ARR: [u8; _]; + | ^ not allowed in type signatures + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants + --> $DIR/in-signature.rs:39:25 + | +LL | const ARR: Bar; + | ^ not allowed in type signatures + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants + --> $DIR/in-signature.rs:43:20 + | +LL | const ARR: Bar<_, _>; + | ^ ^ not allowed in type signatures + | | + | not allowed in type signatures + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types + --> $DIR/in-signature.rs:51:23 + | +LL | type Assoc = [u8; _]; + | ^ not allowed in type signatures + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types + --> $DIR/in-signature.rs:55:27 + | +LL | type Assoc = Bar; + | ^ not allowed in type signatures + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types + --> $DIR/in-signature.rs:59:22 + | +LL | type Assoc = Bar<_, _>; + | ^ ^ not allowed in type signatures + | | + | not allowed in type signatures + +error: aborting due to 15 previous errors + +For more information about this error, try `rustc --explain E0121`. diff --git a/src/test/ui/did_you_mean/bad-assoc-ty.rs b/src/test/ui/did_you_mean/bad-assoc-ty.rs index 609a5b0de6b7e..f787c416c2d63 100644 --- a/src/test/ui/did_you_mean/bad-assoc-ty.rs +++ b/src/test/ui/did_you_mean/bad-assoc-ty.rs @@ -16,7 +16,7 @@ type D = (u8, u8)::AssocTy; type E = _::AssocTy; //~^ ERROR missing angle brackets in associated item path -//~| ERROR the type placeholder `_` is not allowed within types on item signatures for type aliases +//~| ERROR the placeholder `_` is not allowed within types on item signatures for type aliases type F = &'static (u8)::AssocTy; //~^ ERROR missing angle brackets in associated item path @@ -49,37 +49,37 @@ type I = ty!()::AssocTy; trait K {} fn foo>(x: X) {} -//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions fn bar(_: F) where F: Fn() -> _ {} -//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions fn baz _>(_: F) {} -//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions struct L(F) where F: Fn() -> _; -//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for structs +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for structs struct M where F: Fn() -> _ { -//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for structs +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for structs a: F, } enum N where F: Fn() -> _ { -//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for enums +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for enums Foo(F), } union O where F: Fn() -> _ { -//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for unions +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for unions foo: F, } trait P where F: Fn() -> _ { -//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for traits +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for traits } trait Q { fn foo(_: F) where F: Fn() -> _ {} - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions } fn main() {} diff --git a/src/test/ui/did_you_mean/bad-assoc-ty.stderr b/src/test/ui/did_you_mean/bad-assoc-ty.stderr index 11514a28b2ca5..2326af934d014 100644 --- a/src/test/ui/did_you_mean/bad-assoc-ty.stderr +++ b/src/test/ui/did_you_mean/bad-assoc-ty.stderr @@ -81,7 +81,7 @@ error[E0223]: ambiguous associated type LL | type D = (u8, u8)::AssocTy; | ^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(u8, u8) as Trait>::AssocTy` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for type aliases +error[E0121]: the placeholder `_` is not allowed within types on item signatures for type aliases --> $DIR/bad-assoc-ty.rs:17:10 | LL | type E = _::AssocTy; @@ -136,7 +136,7 @@ error[E0223]: ambiguous associated type LL | type I = ty!()::AssocTy; | ^^^^^^^^^^^^^^ help: use fully-qualified syntax: `::AssocTy` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/bad-assoc-ty.rs:51:13 | LL | fn foo>(x: X) {} @@ -149,7 +149,7 @@ help: use type parameters instead LL | fn foo, T>(x: X) {} | ~ ~ +++ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/bad-assoc-ty.rs:54:34 | LL | fn bar(_: F) where F: Fn() -> _ {} @@ -160,7 +160,7 @@ help: use type parameters instead LL | fn bar(_: F) where F: Fn() -> T {} | +++ ~ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/bad-assoc-ty.rs:57:19 | LL | fn baz _>(_: F) {} @@ -171,7 +171,7 @@ help: use type parameters instead LL | fn baz T, T>(_: F) {} | ~+++ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for structs +error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs --> $DIR/bad-assoc-ty.rs:60:33 | LL | struct L(F) where F: Fn() -> _; @@ -182,7 +182,7 @@ help: use type parameters instead LL | struct L(F) where F: Fn() -> T; | +++ ~ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for structs +error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs --> $DIR/bad-assoc-ty.rs:62:30 | LL | struct M where F: Fn() -> _ { @@ -193,7 +193,7 @@ help: use type parameters instead LL | struct M where F: Fn() -> T { | +++ ~ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for enums +error[E0121]: the placeholder `_` is not allowed within types on item signatures for enums --> $DIR/bad-assoc-ty.rs:66:28 | LL | enum N where F: Fn() -> _ { @@ -204,7 +204,7 @@ help: use type parameters instead LL | enum N where F: Fn() -> T { | +++ ~ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for unions +error[E0121]: the placeholder `_` is not allowed within types on item signatures for unions --> $DIR/bad-assoc-ty.rs:71:29 | LL | union O where F: Fn() -> _ { @@ -215,7 +215,7 @@ help: use type parameters instead LL | union O where F: Fn() -> T { | +++ ~ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for traits +error[E0121]: the placeholder `_` is not allowed within types on item signatures for traits --> $DIR/bad-assoc-ty.rs:76:29 | LL | trait P where F: Fn() -> _ { @@ -226,7 +226,7 @@ help: use type parameters instead LL | trait P where F: Fn() -> T { | +++ ~ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/bad-assoc-ty.rs:81:38 | LL | fn foo(_: F) where F: Fn() -> _ {} diff --git a/src/test/ui/error-codes/E0121.stderr b/src/test/ui/error-codes/E0121.stderr index cc0c2df72ea7c..023d7e011bf3a 100644 --- a/src/test/ui/error-codes/E0121.stderr +++ b/src/test/ui/error-codes/E0121.stderr @@ -1,4 +1,4 @@ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/E0121.rs:1:13 | LL | fn foo() -> _ { 5 } @@ -7,7 +7,7 @@ LL | fn foo() -> _ { 5 } | not allowed in type signatures | help: replace with the correct return type: `i32` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for static variables +error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables --> $DIR/E0121.rs:3:13 | LL | static BAR: _ = "test"; diff --git a/src/test/ui/fn/issue-80179.rs b/src/test/ui/fn/issue-80179.rs index 550974bf77881..fcef6f1b60ecf 100644 --- a/src/test/ui/fn/issue-80179.rs +++ b/src/test/ui/fn/issue-80179.rs @@ -8,7 +8,7 @@ fn returns_i32() -> i32 { } fn returns_fn_ptr() -> _ { -//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types [E0121] +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types [E0121] //~| NOTE not allowed in type signatures //~| HELP replace with the correct return type //~| SUGGESTION fn() -> i32 @@ -16,7 +16,7 @@ fn returns_fn_ptr() -> _ { } fn returns_closure() -> _ { -//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types [E0121] +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types [E0121] //~| NOTE not allowed in type signatures //~| HELP consider using an `Fn`, `FnMut`, or `FnOnce` trait bound //~| NOTE for more information on `Fn` traits and closure types, see diff --git a/src/test/ui/fn/issue-80179.stderr b/src/test/ui/fn/issue-80179.stderr index 96d0f02b01af4..2ca4ae982d96f 100644 --- a/src/test/ui/fn/issue-80179.stderr +++ b/src/test/ui/fn/issue-80179.stderr @@ -1,4 +1,4 @@ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/issue-80179.rs:10:24 | LL | fn returns_fn_ptr() -> _ { @@ -7,7 +7,7 @@ LL | fn returns_fn_ptr() -> _ { | not allowed in type signatures | help: replace with the correct return type: `fn() -> i32` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/issue-80179.rs:18:25 | LL | fn returns_closure() -> _ { diff --git a/src/test/ui/issues/issue-69396-const-no-type-in-macro.rs b/src/test/ui/issues/issue-69396-const-no-type-in-macro.rs index 6880e1a46293f..45a30857413b9 100644 --- a/src/test/ui/issues/issue-69396-const-no-type-in-macro.rs +++ b/src/test/ui/issues/issue-69396-const-no-type-in-macro.rs @@ -4,7 +4,7 @@ macro_rules! suite { const A = "A".$fn(); //~^ ERROR the name `A` is defined multiple times //~| ERROR missing type for `const` item - //~| ERROR the type placeholder `_` is not allowed within types on item signatures for constants + //~| ERROR the placeholder `_` is not allowed within types on item signatures for constants )* } } diff --git a/src/test/ui/issues/issue-69396-const-no-type-in-macro.stderr b/src/test/ui/issues/issue-69396-const-no-type-in-macro.stderr index 34c2073db0485..e5ab65169ce3b 100644 --- a/src/test/ui/issues/issue-69396-const-no-type-in-macro.stderr +++ b/src/test/ui/issues/issue-69396-const-no-type-in-macro.stderr @@ -30,7 +30,7 @@ LL | | } | = note: this error originates in the macro `suite` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constants +error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants --> $DIR/issue-69396-const-no-type-in-macro.rs:4:19 | LL | const A = "A".$fn(); diff --git a/src/test/ui/self/self-infer.rs b/src/test/ui/self/self-infer.rs index cc17d8f8e3962..9839b8880e9e1 100644 --- a/src/test/ui/self/self-infer.rs +++ b/src/test/ui/self/self-infer.rs @@ -1,8 +1,8 @@ struct S; impl S { - fn f(self: _) {} //~ERROR the type placeholder `_` is not allowed within types on item signatures for functions - fn g(self: &_) {} //~ERROR the type placeholder `_` is not allowed within types on item signatures for functions + fn f(self: _) {} //~ERROR the placeholder `_` is not allowed within types on item signatures for functions + fn g(self: &_) {} //~ERROR the placeholder `_` is not allowed within types on item signatures for functions } fn main() {} diff --git a/src/test/ui/self/self-infer.stderr b/src/test/ui/self/self-infer.stderr index d3bf63efa40d8..4f9e3f21dca52 100644 --- a/src/test/ui/self/self-infer.stderr +++ b/src/test/ui/self/self-infer.stderr @@ -1,4 +1,4 @@ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/self-infer.rs:4:16 | LL | fn f(self: _) {} @@ -9,7 +9,7 @@ help: use type parameters instead LL | fn f(self: T) {} | +++ ~ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/self-infer.rs:5:17 | LL | fn g(self: &_) {} diff --git a/src/test/ui/suggestions/unnamable-types.rs b/src/test/ui/suggestions/unnamable-types.rs index 483f9bbb48cc6..f2485041d9ba2 100644 --- a/src/test/ui/suggestions/unnamable-types.rs +++ b/src/test/ui/suggestions/unnamable-types.rs @@ -8,14 +8,14 @@ const A = 5; //~| HELP: provide a type for the constant static B: _ = "abc"; -//~^ ERROR: the type placeholder `_` is not allowed within types on item signatures for static variables +//~^ ERROR: the placeholder `_` is not allowed within types on item signatures for static variables //~| NOTE: not allowed in type signatures //~| HELP: replace with the correct type // FIXME: this should also suggest a function pointer, as the closure is non-capturing const C: _ = || 42; -//~^ ERROR: the type placeholder `_` is not allowed within types on item signatures for constants +//~^ ERROR: the placeholder `_` is not allowed within types on item signatures for constants //~| NOTE: not allowed in type signatures //~| NOTE: however, the inferred type diff --git a/src/test/ui/suggestions/unnamable-types.stderr b/src/test/ui/suggestions/unnamable-types.stderr index 3a489a6e94313..6127446c83e3b 100644 --- a/src/test/ui/suggestions/unnamable-types.stderr +++ b/src/test/ui/suggestions/unnamable-types.stderr @@ -4,7 +4,7 @@ error: missing type for `const` item LL | const A = 5; | ^ help: provide a type for the constant: `A: i32` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for static variables +error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables --> $DIR/unnamable-types.rs:10:11 | LL | static B: _ = "abc"; @@ -13,7 +13,7 @@ LL | static B: _ = "abc"; | not allowed in type signatures | help: replace with the correct type: `&str` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constants +error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants --> $DIR/unnamable-types.rs:17:10 | LL | const C: _ = || 42; diff --git a/src/test/ui/type-alias-impl-trait/issue-77179.rs b/src/test/ui/type-alias-impl-trait/issue-77179.rs index 31c45a2093a04..8d818d4a387a6 100644 --- a/src/test/ui/type-alias-impl-trait/issue-77179.rs +++ b/src/test/ui/type-alias-impl-trait/issue-77179.rs @@ -5,7 +5,7 @@ type Pointer = impl std::ops::Deref; fn test() -> Pointer<_> { - //~^ ERROR: the type placeholder `_` is not allowed within types + //~^ ERROR: the placeholder `_` is not allowed within types Box::new(1) } diff --git a/src/test/ui/type-alias-impl-trait/issue-77179.stderr b/src/test/ui/type-alias-impl-trait/issue-77179.stderr index 593aeeacb83aa..15205ba9b419e 100644 --- a/src/test/ui/type-alias-impl-trait/issue-77179.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-77179.stderr @@ -1,4 +1,4 @@ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/issue-77179.rs:7:22 | LL | fn test() -> Pointer<_> { diff --git a/src/test/ui/typeck/issue-74086.rs b/src/test/ui/typeck/issue-74086.rs index 1de9cd8007cff..44ca256b05163 100644 --- a/src/test/ui/typeck/issue-74086.rs +++ b/src/test/ui/typeck/issue-74086.rs @@ -1,4 +1,4 @@ fn main() { static BUG: fn(_) -> u8 = |_| 8; - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions [E0121] + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions [E0121] } diff --git a/src/test/ui/typeck/issue-74086.stderr b/src/test/ui/typeck/issue-74086.stderr index ac1752e17dfb9..e7aea33758cb2 100644 --- a/src/test/ui/typeck/issue-74086.stderr +++ b/src/test/ui/typeck/issue-74086.stderr @@ -1,4 +1,4 @@ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/issue-74086.rs:2:20 | LL | static BUG: fn(_) -> u8 = |_| 8; diff --git a/src/test/ui/typeck/issue-75883.rs b/src/test/ui/typeck/issue-75883.rs index 0d1534df091fa..885acc48231b2 100644 --- a/src/test/ui/typeck/issue-75883.rs +++ b/src/test/ui/typeck/issue-75883.rs @@ -5,7 +5,7 @@ pub struct UI {} impl UI { pub fn run() -> Result<_> { //~^ ERROR: this enum takes 2 generic arguments but 1 generic argument was supplied - //~| ERROR: the type placeholder `_` is not allowed within types on item signatures for return types + //~| ERROR: the placeholder `_` is not allowed within types on item signatures for return types let mut ui = UI {}; ui.interact(); @@ -14,7 +14,7 @@ impl UI { pub fn interact(&mut self) -> Result<_> { //~^ ERROR: this enum takes 2 generic arguments but 1 generic argument was supplied - //~| ERROR: the type placeholder `_` is not allowed within types on item signatures for return types + //~| ERROR: the placeholder `_` is not allowed within types on item signatures for return types unimplemented!(); } } diff --git a/src/test/ui/typeck/issue-75883.stderr b/src/test/ui/typeck/issue-75883.stderr index 5e42c817e030b..3861e0507f6dd 100644 --- a/src/test/ui/typeck/issue-75883.stderr +++ b/src/test/ui/typeck/issue-75883.stderr @@ -34,13 +34,13 @@ help: add missing generic argument LL | pub fn interact(&mut self) -> Result<_, E> { | +++ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/issue-75883.rs:15:42 | LL | pub fn interact(&mut self) -> Result<_> { | ^ not allowed in type signatures -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/issue-75883.rs:6:28 | LL | pub fn run() -> Result<_> { diff --git a/src/test/ui/typeck/issue-75889.stderr b/src/test/ui/typeck/issue-75889.stderr index de4bdf4e6d9de..1438f481ec7e1 100644 --- a/src/test/ui/typeck/issue-75889.stderr +++ b/src/test/ui/typeck/issue-75889.stderr @@ -1,10 +1,10 @@ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constant items +error[E0121]: the placeholder `_` is not allowed within types on item signatures for constant items --> $DIR/issue-75889.rs:3:24 | LL | const FOO: dyn Fn() -> _ = ""; | ^ not allowed in type signatures -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for static items +error[E0121]: the placeholder `_` is not allowed within types on item signatures for static items --> $DIR/issue-75889.rs:4:25 | LL | static BOO: dyn Fn() -> _ = ""; diff --git a/src/test/ui/typeck/issue-80779.rs b/src/test/ui/typeck/issue-80779.rs index 99a93b1863d6e..1624f6b7742b0 100644 --- a/src/test/ui/typeck/issue-80779.rs +++ b/src/test/ui/typeck/issue-80779.rs @@ -3,11 +3,11 @@ pub struct T<'a>(&'a str); pub fn f<'a>(val: T<'a>) -> _ { - //~^ ERROR: the type placeholder `_` is not allowed within types on item signatures for return types + //~^ ERROR: the placeholder `_` is not allowed within types on item signatures for return types g(val) } pub fn g(_: T<'static>) -> _ {} -//~^ ERROR: the type placeholder `_` is not allowed within types on item signatures for return types +//~^ ERROR: the placeholder `_` is not allowed within types on item signatures for return types fn main() {} diff --git a/src/test/ui/typeck/issue-80779.stderr b/src/test/ui/typeck/issue-80779.stderr index 5a695fecc29dc..2261ba616545f 100644 --- a/src/test/ui/typeck/issue-80779.stderr +++ b/src/test/ui/typeck/issue-80779.stderr @@ -1,4 +1,4 @@ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/issue-80779.rs:10:28 | LL | pub fn g(_: T<'static>) -> _ {} @@ -7,7 +7,7 @@ LL | pub fn g(_: T<'static>) -> _ {} | not allowed in type signatures | help: replace with the correct return type: `()` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/issue-80779.rs:5:29 | LL | pub fn f<'a>(val: T<'a>) -> _ { diff --git a/src/test/ui/typeck/issue-81885.rs b/src/test/ui/typeck/issue-81885.rs index 5117f250fe5ea..8935535fb7eb8 100644 --- a/src/test/ui/typeck/issue-81885.rs +++ b/src/test/ui/typeck/issue-81885.rs @@ -1,8 +1,8 @@ const TEST4: fn() -> _ = 42; - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions fn main() { const TEST5: fn() -> _ = 42; - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions } diff --git a/src/test/ui/typeck/issue-81885.stderr b/src/test/ui/typeck/issue-81885.stderr index 8206156a6180a..3ff4375cd8d3f 100644 --- a/src/test/ui/typeck/issue-81885.stderr +++ b/src/test/ui/typeck/issue-81885.stderr @@ -1,10 +1,10 @@ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/issue-81885.rs:1:22 | LL | const TEST4: fn() -> _ = 42; | ^ not allowed in type signatures -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/issue-81885.rs:5:26 | LL | const TEST5: fn() -> _ = 42; diff --git a/src/test/ui/typeck/issue-83621-placeholder-static-in-extern.stderr b/src/test/ui/typeck/issue-83621-placeholder-static-in-extern.stderr index 7c5cf1082be09..9376e8bcf80bc 100644 --- a/src/test/ui/typeck/issue-83621-placeholder-static-in-extern.stderr +++ b/src/test/ui/typeck/issue-83621-placeholder-static-in-extern.stderr @@ -1,4 +1,4 @@ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for static variables +error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables --> $DIR/issue-83621-placeholder-static-in-extern.rs:4:15 | LL | static x: _; diff --git a/src/test/ui/typeck/issue-91450-inner-ty-error.rs b/src/test/ui/typeck/issue-91450-inner-ty-error.rs index 0b942d6d94f84..3c7c990d4e27c 100644 --- a/src/test/ui/typeck/issue-91450-inner-ty-error.rs +++ b/src/test/ui/typeck/issue-91450-inner-ty-error.rs @@ -2,6 +2,6 @@ // This test ensures that the compiler does not suggest `Foo<[type error]>` in diagnostic messages. fn foo() -> Option<_> {} //~ ERROR: [E0308] -//~^ ERROR: the type placeholder `_` is not allowed +//~^ ERROR: the placeholder `_` is not allowed fn main() {} diff --git a/src/test/ui/typeck/issue-91450-inner-ty-error.stderr b/src/test/ui/typeck/issue-91450-inner-ty-error.stderr index 314fe56180368..32f4c8f6fdf82 100644 --- a/src/test/ui/typeck/issue-91450-inner-ty-error.stderr +++ b/src/test/ui/typeck/issue-91450-inner-ty-error.stderr @@ -9,7 +9,7 @@ LL | fn foo() -> Option<_> {} = note: expected enum `Option<_>` found unit type `()` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/issue-91450-inner-ty-error.rs:4:20 | LL | fn foo() -> Option<_> {} diff --git a/src/test/ui/typeck/type-placeholder-fn-in-const.rs b/src/test/ui/typeck/type-placeholder-fn-in-const.rs index f657bea164872..ab2e2d8c53aa3 100644 --- a/src/test/ui/typeck/type-placeholder-fn-in-const.rs +++ b/src/test/ui/typeck/type-placeholder-fn-in-const.rs @@ -2,13 +2,13 @@ struct MyStruct; trait Test { const TEST: fn() -> _; - //~^ ERROR: the type placeholder `_` is not allowed within types on item signatures for functions [E0121] - //~| ERROR: the type placeholder `_` is not allowed within types on item signatures for constants [E0121] + //~^ ERROR: the placeholder `_` is not allowed within types on item signatures for functions [E0121] + //~| ERROR: the placeholder `_` is not allowed within types on item signatures for constants [E0121] } impl Test for MyStruct { const TEST: fn() -> _ = 42; - //~^ ERROR: the type placeholder `_` is not allowed within types on item signatures for functions [E0121] + //~^ ERROR: the placeholder `_` is not allowed within types on item signatures for functions [E0121] } fn main() {} diff --git a/src/test/ui/typeck/type-placeholder-fn-in-const.stderr b/src/test/ui/typeck/type-placeholder-fn-in-const.stderr index 62f4db8638f3c..e7b2e554a8d42 100644 --- a/src/test/ui/typeck/type-placeholder-fn-in-const.stderr +++ b/src/test/ui/typeck/type-placeholder-fn-in-const.stderr @@ -1,16 +1,16 @@ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/type-placeholder-fn-in-const.rs:4:25 | LL | const TEST: fn() -> _; | ^ not allowed in type signatures -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constants +error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants --> $DIR/type-placeholder-fn-in-const.rs:4:25 | LL | const TEST: fn() -> _; | ^ not allowed in type signatures -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/type-placeholder-fn-in-const.rs:10:25 | LL | const TEST: fn() -> _ = 42; diff --git a/src/test/ui/typeck/typeck_type_placeholder_item.rs b/src/test/ui/typeck/typeck_type_placeholder_item.rs index a3b75543510ae..ca0876be58df9 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_item.rs +++ b/src/test/ui/typeck/typeck_type_placeholder_item.rs @@ -5,67 +5,67 @@ // inference by using the `_` type placeholder. fn test() -> _ { 5 } -//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types fn test2() -> (_, _) { (5, 5) } -//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types static TEST3: _ = "test"; -//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for static variables +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for static variables static TEST4: _ = 145; -//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for static variables +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for static variables static TEST5: (_, _) = (1, 2); -//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for static variables +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for static variables fn test6(_: _) { } -//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions fn test6_b(_: _, _: T) { } -//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions fn test6_c(_: _, _: (T, K, L, A, B)) { } -//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions fn test7(x: _) { let _x: usize = x; } -//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions fn test8(_f: fn() -> _) { } -//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions -//~^^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions +//~^^ ERROR the placeholder `_` is not allowed within types on item signatures for functions struct Test9; impl Test9 { fn test9(&self) -> _ { () } - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types fn test10(&self, _x : _) { } - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions } fn test11(x: &usize) -> &_ { -//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types &x } unsafe fn test12(x: *const usize) -> *const *const _ { -//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types &x } impl Clone for Test9 { fn clone(&self) -> _ { Test9 } - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types fn clone_from(&mut self, other: _) { *self = Test9; } - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions } struct Test10 { a: _, - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for structs + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for structs b: (_, _), } @@ -73,94 +73,94 @@ pub fn main() { static A = 42; //~^ ERROR missing type for `static` item static B: _ = 42; - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for static variables + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for static variables static C: Option<_> = Some(42); - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for static variables + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for static variables fn fn_test() -> _ { 5 } - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types fn fn_test2() -> (_, _) { (5, 5) } - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types static FN_TEST3: _ = "test"; - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for static variables + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for static variables static FN_TEST4: _ = 145; - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for static variables + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for static variables static FN_TEST5: (_, _) = (1, 2); - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for static variables + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for static variables fn fn_test6(_: _) { } - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions fn fn_test7(x: _) { let _x: usize = x; } - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions fn fn_test8(_f: fn() -> _) { } - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions - //~^^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions + //~^^ ERROR the placeholder `_` is not allowed within types on item signatures for functions struct FnTest9; impl FnTest9 { fn fn_test9(&self) -> _ { () } - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types fn fn_test10(&self, _x : _) { } - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions } impl Clone for FnTest9 { fn clone(&self) -> _ { FnTest9 } - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types fn clone_from(&mut self, other: _) { *self = FnTest9; } - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions } struct FnTest10 { a: _, - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for structs + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for structs b: (_, _), } fn fn_test11(_: _) -> (_, _) { panic!() } - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types //~| ERROR type annotations needed fn fn_test12(x: i32) -> (_, _) { (x, x) } - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types fn fn_test13(x: _) -> (i32, _) { (x, x) } - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types } trait T { fn method_test1(&self, x: _); - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions fn method_test2(&self, x: _) -> _; - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions fn method_test3(&self) -> _; - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions fn assoc_fn_test1(x: _); - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions fn assoc_fn_test2(x: _) -> _; - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions fn assoc_fn_test3() -> _; - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions } struct BadStruct<_>(_); //~^ ERROR expected identifier, found reserved identifier `_` -//~| ERROR the type placeholder `_` is not allowed within types on item signatures for structs +//~| ERROR the placeholder `_` is not allowed within types on item signatures for structs trait BadTrait<_> {} //~^ ERROR expected identifier, found reserved identifier `_` impl BadTrait<_> for BadStruct<_> {} -//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for implementations +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for implementations fn impl_trait() -> impl BadTrait<_> { -//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for opaque types +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for opaque types unimplemented!() } @@ -168,19 +168,19 @@ struct BadStruct1<_, _>(_); //~^ ERROR expected identifier, found reserved identifier `_` //~| ERROR expected identifier, found reserved identifier `_` //~| ERROR the name `_` is already used -//~| ERROR the type placeholder `_` is not allowed within types on item signatures for structs +//~| ERROR the placeholder `_` is not allowed within types on item signatures for structs struct BadStruct2<_, T>(_, T); //~^ ERROR expected identifier, found reserved identifier `_` -//~| ERROR the type placeholder `_` is not allowed within types on item signatures for structs +//~| ERROR the placeholder `_` is not allowed within types on item signatures for structs type X = Box<_>; -//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for type aliases +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for type aliases struct Struct; trait Trait {} impl Trait for Struct {} type Y = impl Trait<_>; -//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for opaque types +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for opaque types fn foo() -> Y { Struct } @@ -188,25 +188,25 @@ fn foo() -> Y { trait Qux { type A; type B = _; - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for associated types + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated types const C: _; - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for constants + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants const D: _ = 42; - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for constants + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants // type E: _; // FIXME: make the parser propagate the existence of `B` type F: std::ops::Fn(_); - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for associated types + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated types } impl Qux for Struct { type A = _; - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for associated types + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated types type B = _; - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for associated types + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated types const C: _; - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for constants + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants //~| ERROR associated constant in `impl` without body const D: _ = 42; - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for constants + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants } fn map(_: fn() -> Option<&'static T>) -> Option { @@ -214,9 +214,9 @@ fn map(_: fn() -> Option<&'static T>) -> Option { } fn value() -> Option<&'static _> { -//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types Option::<&'static u8>::None } const _: Option<_> = map(value); -//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for constants +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants diff --git a/src/test/ui/typeck/typeck_type_placeholder_item.stderr b/src/test/ui/typeck/typeck_type_placeholder_item.stderr index e1f66afdacc11..c07b96f9a977a 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_item.stderr +++ b/src/test/ui/typeck/typeck_type_placeholder_item.stderr @@ -44,7 +44,7 @@ LL | struct BadStruct1<_, _>(_); | | | first use of `_` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/typeck_type_placeholder_item.rs:7:14 | LL | fn test() -> _ { 5 } @@ -53,7 +53,7 @@ LL | fn test() -> _ { 5 } | not allowed in type signatures | help: replace with the correct return type: `i32` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/typeck_type_placeholder_item.rs:10:16 | LL | fn test2() -> (_, _) { (5, 5) } @@ -63,7 +63,7 @@ LL | fn test2() -> (_, _) { (5, 5) } | |not allowed in type signatures | help: replace with the correct return type: `(i32, i32)` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for static variables +error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables --> $DIR/typeck_type_placeholder_item.rs:13:15 | LL | static TEST3: _ = "test"; @@ -72,7 +72,7 @@ LL | static TEST3: _ = "test"; | not allowed in type signatures | help: replace with the correct type: `&str` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for static variables +error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables --> $DIR/typeck_type_placeholder_item.rs:16:15 | LL | static TEST4: _ = 145; @@ -81,13 +81,13 @@ LL | static TEST4: _ = 145; | not allowed in type signatures | help: replace with the correct type: `i32` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for static variables +error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables --> $DIR/typeck_type_placeholder_item.rs:19:15 | LL | static TEST5: (_, _) = (1, 2); | ^^^^^^ not allowed in type signatures -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/typeck_type_placeholder_item.rs:22:13 | LL | fn test6(_: _) { } @@ -98,7 +98,7 @@ help: use type parameters instead LL | fn test6(_: T) { } | +++ ~ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/typeck_type_placeholder_item.rs:25:18 | LL | fn test6_b(_: _, _: T) { } @@ -109,7 +109,7 @@ help: use type parameters instead LL | fn test6_b(_: U, _: T) { } | +++ ~ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/typeck_type_placeholder_item.rs:28:30 | LL | fn test6_c(_: _, _: (T, K, L, A, B)) { } @@ -120,7 +120,7 @@ help: use type parameters instead LL | fn test6_c(_: U, _: (T, K, L, A, B)) { } | +++ ~ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/typeck_type_placeholder_item.rs:31:13 | LL | fn test7(x: _) { let _x: usize = x; } @@ -131,7 +131,7 @@ help: use type parameters instead LL | fn test7(x: T) { let _x: usize = x; } | +++ ~ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/typeck_type_placeholder_item.rs:34:22 | LL | fn test8(_f: fn() -> _) { } @@ -140,7 +140,7 @@ LL | fn test8(_f: fn() -> _) { } | not allowed in type signatures | help: use type parameters instead: `T` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/typeck_type_placeholder_item.rs:34:22 | LL | fn test8(_f: fn() -> _) { } @@ -151,7 +151,7 @@ help: use type parameters instead LL | fn test8(_f: fn() -> T) { } | +++ ~ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/typeck_type_placeholder_item.rs:48:26 | LL | fn test11(x: &usize) -> &_ { @@ -160,7 +160,7 @@ LL | fn test11(x: &usize) -> &_ { | |not allowed in type signatures | help: replace with the correct return type: `&'static &'static usize` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/typeck_type_placeholder_item.rs:53:52 | LL | unsafe fn test12(x: *const usize) -> *const *const _ { @@ -169,7 +169,7 @@ LL | unsafe fn test12(x: *const usize) -> *const *const _ { | | not allowed in type signatures | help: replace with the correct return type: `*const *const usize` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for structs +error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs --> $DIR/typeck_type_placeholder_item.rs:67:8 | LL | a: _, @@ -194,7 +194,7 @@ error: missing type for `static` item LL | static A = 42; | ^ help: provide a type for the static variable: `A: i32` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for static variables +error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables --> $DIR/typeck_type_placeholder_item.rs:75:15 | LL | static B: _ = 42; @@ -203,13 +203,13 @@ LL | static B: _ = 42; | not allowed in type signatures | help: replace with the correct type: `i32` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for static variables +error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables --> $DIR/typeck_type_placeholder_item.rs:77:15 | LL | static C: Option<_> = Some(42); | ^^^^^^^^^ not allowed in type signatures -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/typeck_type_placeholder_item.rs:79:21 | LL | fn fn_test() -> _ { 5 } @@ -218,7 +218,7 @@ LL | fn fn_test() -> _ { 5 } | not allowed in type signatures | help: replace with the correct return type: `i32` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/typeck_type_placeholder_item.rs:82:23 | LL | fn fn_test2() -> (_, _) { (5, 5) } @@ -228,7 +228,7 @@ LL | fn fn_test2() -> (_, _) { (5, 5) } | |not allowed in type signatures | help: replace with the correct return type: `(i32, i32)` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for static variables +error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables --> $DIR/typeck_type_placeholder_item.rs:85:22 | LL | static FN_TEST3: _ = "test"; @@ -237,7 +237,7 @@ LL | static FN_TEST3: _ = "test"; | not allowed in type signatures | help: replace with the correct type: `&str` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for static variables +error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables --> $DIR/typeck_type_placeholder_item.rs:88:22 | LL | static FN_TEST4: _ = 145; @@ -246,13 +246,13 @@ LL | static FN_TEST4: _ = 145; | not allowed in type signatures | help: replace with the correct type: `i32` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for static variables +error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables --> $DIR/typeck_type_placeholder_item.rs:91:22 | LL | static FN_TEST5: (_, _) = (1, 2); | ^^^^^^ not allowed in type signatures -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/typeck_type_placeholder_item.rs:94:20 | LL | fn fn_test6(_: _) { } @@ -263,7 +263,7 @@ help: use type parameters instead LL | fn fn_test6(_: T) { } | +++ ~ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/typeck_type_placeholder_item.rs:97:20 | LL | fn fn_test7(x: _) { let _x: usize = x; } @@ -274,7 +274,7 @@ help: use type parameters instead LL | fn fn_test7(x: T) { let _x: usize = x; } | +++ ~ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/typeck_type_placeholder_item.rs:100:29 | LL | fn fn_test8(_f: fn() -> _) { } @@ -283,7 +283,7 @@ LL | fn fn_test8(_f: fn() -> _) { } | not allowed in type signatures | help: use type parameters instead: `T` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/typeck_type_placeholder_item.rs:100:29 | LL | fn fn_test8(_f: fn() -> _) { } @@ -294,7 +294,7 @@ help: use type parameters instead LL | fn fn_test8(_f: fn() -> T) { } | +++ ~ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for structs +error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs --> $DIR/typeck_type_placeholder_item.rs:123:12 | LL | a: _, @@ -319,7 +319,7 @@ error[E0282]: type annotations needed LL | fn fn_test11(_: _) -> (_, _) { panic!() } | ^ cannot infer type -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/typeck_type_placeholder_item.rs:128:28 | LL | fn fn_test11(_: _) -> (_, _) { panic!() } @@ -327,7 +327,7 @@ LL | fn fn_test11(_: _) -> (_, _) { panic!() } | | | not allowed in type signatures -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/typeck_type_placeholder_item.rs:132:30 | LL | fn fn_test12(x: i32) -> (_, _) { (x, x) } @@ -337,7 +337,7 @@ LL | fn fn_test12(x: i32) -> (_, _) { (x, x) } | |not allowed in type signatures | help: replace with the correct return type: `(i32, i32)` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/typeck_type_placeholder_item.rs:135:33 | LL | fn fn_test13(x: _) -> (i32, _) { (x, x) } @@ -346,7 +346,7 @@ LL | fn fn_test13(x: _) -> (i32, _) { (x, x) } | | not allowed in type signatures | help: replace with the correct return type: `(i32, i32)` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for structs +error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs --> $DIR/typeck_type_placeholder_item.rs:154:21 | LL | struct BadStruct<_>(_); @@ -357,7 +357,7 @@ help: use type parameters instead LL | struct BadStruct(T); | ~ ~ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for implementations +error[E0121]: the placeholder `_` is not allowed within types on item signatures for implementations --> $DIR/typeck_type_placeholder_item.rs:159:15 | LL | impl BadTrait<_> for BadStruct<_> {} @@ -370,13 +370,13 @@ help: use type parameters instead LL | impl BadTrait for BadStruct {} | +++ ~ ~ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for opaque types +error[E0121]: the placeholder `_` is not allowed within types on item signatures for opaque types --> $DIR/typeck_type_placeholder_item.rs:162:34 | LL | fn impl_trait() -> impl BadTrait<_> { | ^ not allowed in type signatures -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for structs +error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs --> $DIR/typeck_type_placeholder_item.rs:167:25 | LL | struct BadStruct1<_, _>(_); @@ -387,7 +387,7 @@ help: use type parameters instead LL | struct BadStruct1(T); | ~ ~ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for structs +error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs --> $DIR/typeck_type_placeholder_item.rs:172:25 | LL | struct BadStruct2<_, T>(_, T); @@ -398,19 +398,19 @@ help: use type parameters instead LL | struct BadStruct2(U, T); | ~ ~ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for type aliases +error[E0121]: the placeholder `_` is not allowed within types on item signatures for type aliases --> $DIR/typeck_type_placeholder_item.rs:176:14 | LL | type X = Box<_>; | ^ not allowed in type signatures -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for opaque types +error[E0121]: the placeholder `_` is not allowed within types on item signatures for opaque types --> $DIR/typeck_type_placeholder_item.rs:182:21 | LL | type Y = impl Trait<_>; | ^ not allowed in type signatures -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/typeck_type_placeholder_item.rs:216:31 | LL | fn value() -> Option<&'static _> { @@ -419,7 +419,7 @@ LL | fn value() -> Option<&'static _> { | | not allowed in type signatures | help: replace with the correct return type: `Option<&'static u8>` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constants +error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants --> $DIR/typeck_type_placeholder_item.rs:221:10 | LL | const _: Option<_> = map(value); @@ -428,7 +428,7 @@ LL | const _: Option<_> = map(value); | not allowed in type signatures | help: replace with the correct type: `Option` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/typeck_type_placeholder_item.rs:140:31 | LL | fn method_test1(&self, x: _); @@ -439,7 +439,7 @@ help: use type parameters instead LL | fn method_test1(&self, x: T); | +++ ~ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/typeck_type_placeholder_item.rs:142:31 | LL | fn method_test2(&self, x: _) -> _; @@ -452,7 +452,7 @@ help: use type parameters instead LL | fn method_test2(&self, x: T) -> T; | +++ ~ ~ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/typeck_type_placeholder_item.rs:144:31 | LL | fn method_test3(&self) -> _; @@ -463,7 +463,7 @@ help: use type parameters instead LL | fn method_test3(&self) -> T; | +++ ~ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/typeck_type_placeholder_item.rs:146:26 | LL | fn assoc_fn_test1(x: _); @@ -474,7 +474,7 @@ help: use type parameters instead LL | fn assoc_fn_test1(x: T); | +++ ~ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/typeck_type_placeholder_item.rs:148:26 | LL | fn assoc_fn_test2(x: _) -> _; @@ -487,7 +487,7 @@ help: use type parameters instead LL | fn assoc_fn_test2(x: T) -> T; | +++ ~ ~ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/typeck_type_placeholder_item.rs:150:28 | LL | fn assoc_fn_test3() -> _; @@ -498,19 +498,19 @@ help: use type parameters instead LL | fn assoc_fn_test3() -> T; | +++ ~ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for associated types +error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types --> $DIR/typeck_type_placeholder_item.rs:190:14 | LL | type B = _; | ^ not allowed in type signatures -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constants +error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants --> $DIR/typeck_type_placeholder_item.rs:192:14 | LL | const C: _; | ^ not allowed in type signatures -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constants +error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants --> $DIR/typeck_type_placeholder_item.rs:194:14 | LL | const D: _ = 42; @@ -519,13 +519,13 @@ LL | const D: _ = 42; | not allowed in type signatures | help: replace with the correct type: `i32` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for associated types +error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types --> $DIR/typeck_type_placeholder_item.rs:197:26 | LL | type F: std::ops::Fn(_); | ^ not allowed in type signatures -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/typeck_type_placeholder_item.rs:41:24 | LL | fn test9(&self) -> _ { () } @@ -534,7 +534,7 @@ LL | fn test9(&self) -> _ { () } | not allowed in type signatures | help: replace with the correct return type: `()` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/typeck_type_placeholder_item.rs:44:27 | LL | fn test10(&self, _x : _) { } @@ -545,7 +545,7 @@ help: use type parameters instead LL | fn test10(&self, _x : T) { } | +++ ~ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/typeck_type_placeholder_item.rs:59:24 | LL | fn clone(&self) -> _ { Test9 } @@ -554,7 +554,7 @@ LL | fn clone(&self) -> _ { Test9 } | not allowed in type signatures | help: replace with the correct return type: `Test9` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/typeck_type_placeholder_item.rs:62:37 | LL | fn clone_from(&mut self, other: _) { *self = Test9; } @@ -565,7 +565,7 @@ help: use type parameters instead LL | fn clone_from(&mut self, other: T) { *self = Test9; } | +++ ~ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/typeck_type_placeholder_item.rs:107:31 | LL | fn fn_test9(&self) -> _ { () } @@ -574,7 +574,7 @@ LL | fn fn_test9(&self) -> _ { () } | not allowed in type signatures | help: replace with the correct return type: `()` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/typeck_type_placeholder_item.rs:110:34 | LL | fn fn_test10(&self, _x : _) { } @@ -585,7 +585,7 @@ help: use type parameters instead LL | fn fn_test10(&self, _x : T) { } | +++ ~ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/typeck_type_placeholder_item.rs:115:28 | LL | fn clone(&self) -> _ { FnTest9 } @@ -594,7 +594,7 @@ LL | fn clone(&self) -> _ { FnTest9 } | not allowed in type signatures | help: replace with the correct return type: `FnTest9` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/typeck_type_placeholder_item.rs:118:41 | LL | fn clone_from(&mut self, other: _) { *self = FnTest9; } @@ -605,25 +605,25 @@ help: use type parameters instead LL | fn clone_from(&mut self, other: T) { *self = FnTest9; } | +++ ~ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for associated types +error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types --> $DIR/typeck_type_placeholder_item.rs:201:14 | LL | type A = _; | ^ not allowed in type signatures -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for associated types +error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types --> $DIR/typeck_type_placeholder_item.rs:203:14 | LL | type B = _; | ^ not allowed in type signatures -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constants +error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants --> $DIR/typeck_type_placeholder_item.rs:205:14 | LL | const C: _; | ^ not allowed in type signatures -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constants +error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants --> $DIR/typeck_type_placeholder_item.rs:208:14 | LL | const D: _ = 42; diff --git a/src/test/ui/typeck/typeck_type_placeholder_item_help.rs b/src/test/ui/typeck/typeck_type_placeholder_item_help.rs index 3af5cf926abf0..53f31b683c1a4 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_item_help.rs +++ b/src/test/ui/typeck/typeck_type_placeholder_item_help.rs @@ -2,27 +2,27 @@ // using the `_` type placeholder. fn test1() -> _ { Some(42) } -//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types const TEST2: _ = 42u32; -//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for constants +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants const TEST3: _ = Some(42); -//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for constants +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants const TEST4: fn() -> _ = 42; -//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions trait Test5 { const TEST5: _ = 42; - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for constants + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants } struct Test6; impl Test6 { const TEST6: _ = 13; - //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for constants + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants } pub fn main() { diff --git a/src/test/ui/typeck/typeck_type_placeholder_item_help.stderr b/src/test/ui/typeck/typeck_type_placeholder_item_help.stderr index 1b56b1033a8c1..e8191832318e5 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_item_help.stderr +++ b/src/test/ui/typeck/typeck_type_placeholder_item_help.stderr @@ -1,4 +1,4 @@ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/typeck_type_placeholder_item_help.rs:4:15 | LL | fn test1() -> _ { Some(42) } @@ -7,7 +7,7 @@ LL | fn test1() -> _ { Some(42) } | not allowed in type signatures | help: replace with the correct return type: `Option` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constants +error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants --> $DIR/typeck_type_placeholder_item_help.rs:7:14 | LL | const TEST2: _ = 42u32; @@ -16,7 +16,7 @@ LL | const TEST2: _ = 42u32; | not allowed in type signatures | help: replace with the correct type: `u32` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constants +error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants --> $DIR/typeck_type_placeholder_item_help.rs:10:14 | LL | const TEST3: _ = Some(42); @@ -25,13 +25,13 @@ LL | const TEST3: _ = Some(42); | not allowed in type signatures | help: replace with the correct type: `Option` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/typeck_type_placeholder_item_help.rs:13:22 | LL | const TEST4: fn() -> _ = 42; | ^ not allowed in type signatures -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constants +error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants --> $DIR/typeck_type_placeholder_item_help.rs:17:18 | LL | const TEST5: _ = 42; @@ -40,7 +40,7 @@ LL | const TEST5: _ = 42; | not allowed in type signatures | help: replace with the correct type: `i32` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constants +error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants --> $DIR/typeck_type_placeholder_item_help.rs:24:18 | LL | const TEST6: _ = 13; From cbc6d35a5745f56c69c11dd4125906e08826c959 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 10 Jan 2022 10:59:26 +0100 Subject: [PATCH 12/27] privacy: update `visit_infer` --- compiler/rustc_privacy/src/lib.rs | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 7bee2ebf2f977..d10f85b1bed54 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1148,19 +1148,11 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { if self.visit(ty).is_break() { return; } + } else { + // We don't do anything for const infers here. } } else { - let local_id = self.tcx.hir().local_def_id(inf.hir_id); - if let Some(did) = self.tcx.opt_const_param_of(local_id) { - if self.visit_def_id(did, "inferred", &"").is_break() { - return; - } - } - - // FIXME see above note for same issue. - if self.visit(rustc_typeck::hir_ty_to_ty(self.tcx, &inf.to_ty())).is_break() { - return; - } + bug!("visit_infer without typeck_results"); } intravisit::walk_inf(self, inf); } From 217458b9dab4578147090203a21acde9423785e7 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 17 Jan 2022 07:54:56 +0100 Subject: [PATCH 13/27] intra-doc links --- compiler/rustc_middle/src/ty/context.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 6eb3653dd7baa..8d591d6781235 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1210,7 +1210,7 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_ty(Error(DelaySpanBugEmitted(()))) } - /// Like [`ty_error`] but for constants. + /// Like [TyCtxt::ty_error] but for constants. #[track_caller] pub fn const_error(self, ty: Ty<'tcx>) -> &'tcx Const<'tcx> { self.const_error_with_message( @@ -1220,7 +1220,7 @@ impl<'tcx> TyCtxt<'tcx> { ) } - /// Like [`ty_error_with_message`] but for constants. + /// Like [TyCtxt::ty_error_with_message] but for constants. #[track_caller] pub fn const_error_with_message>( self, From 29a2d6b50536cee777ca5454b5f9bd1a58b5fc17 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Sat, 8 Jan 2022 14:48:25 -0800 Subject: [PATCH 14/27] intra-doc: Use the impl's assoc item where possible Before, the trait's associated item would be used. Now, the impl's associated item is used. The only exception is for impls that use default values for associated items set by the trait. In that case, the trait's associated item is still used. As an example of the old and new behavior, take this code: trait MyTrait { type AssocTy; } impl MyTrait for String { type AssocTy = u8; } Before, when resolving a link to `String::AssocTy`, `resolve_associated_trait_item` would return the associated item for `MyTrait::AssocTy`. Now, it would return the associated item for `::AssocTy`, as it claims in its docs. --- .../passes/collect_intra_doc_links.rs | 88 +++++++++++-------- 1 file changed, 53 insertions(+), 35 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 1a9794e75bc06..7dbf00420de12 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -305,16 +305,15 @@ crate enum FragmentKind { impl ItemFragment { /// Create a fragment for an associated item. - /// - /// `is_prototype` is whether this associated item is a trait method - /// without a default definition. - fn from_assoc_item(def_id: DefId, kind: ty::AssocKind, is_prototype: bool) -> Self { - match kind { + #[instrument(level = "debug")] + fn from_assoc_item(item: &ty::AssocItem) -> Self { + let def_id = item.def_id; + match item.kind { ty::AssocKind::Fn => { - if is_prototype { - ItemFragment(FragmentKind::TyMethod, def_id) - } else { + if item.defaultness.has_value() { ItemFragment(FragmentKind::Method, def_id) + } else { + ItemFragment(FragmentKind::TyMethod, def_id) } } ty::AssocKind::Const => ItemFragment(FragmentKind::AssociatedConstant, def_id), @@ -473,8 +472,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { tcx.associated_items(impl_) .find_by_name_and_namespace(tcx, Ident::with_dummy_span(item_name), ns, impl_) .map(|item| { - let kind = item.kind; - let fragment = ItemFragment::from_assoc_item(item.def_id, kind, false); + let fragment = ItemFragment::from_assoc_item(item); (Res::Primitive(prim_ty), fragment) }) }) @@ -726,8 +724,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { .flatten(); assoc_item.map(|item| { - let kind = item.kind; - let fragment = ItemFragment::from_assoc_item(item.def_id, kind, false); + let fragment = ItemFragment::from_assoc_item(&item); (root_res, fragment) }) }) @@ -765,20 +762,19 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // To handle that properly resolve() would have to support // something like [`ambi_fn`](::ambi_fn) .or_else(|| { - let item = resolve_associated_trait_item( + resolve_associated_trait_item( tcx.type_of(did), module_id, item_name, ns, self.cx, - ); - debug!("got associated item {:?}", item); - item + ) }); + debug!("got associated item {:?}", assoc_item); + if let Some(item) = assoc_item { - let kind = item.kind; - let fragment = ItemFragment::from_assoc_item(item.def_id, kind, false); + let fragment = ItemFragment::from_assoc_item(&item); return Some((root_res, fragment)); } @@ -813,11 +809,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { .associated_items(did) .find_by_name_and_namespace(tcx, Ident::with_dummy_span(item_name), ns, did) .map(|item| { - let fragment = ItemFragment::from_assoc_item( - item.def_id, - item.kind, - !item.defaultness.has_value(), - ); + let fragment = ItemFragment::from_assoc_item(item); let res = Res::Def(item.kind.as_def_kind(), item.def_id); (res, fragment) }), @@ -883,30 +875,56 @@ fn resolve_associated_trait_item<'a>( // Next consider explicit impls: `impl MyTrait for MyType` // Give precedence to inherent impls. - let traits = traits_implemented_by(cx, ty, module); + let traits = trait_impls_for(cx, ty, module); debug!("considering traits {:?}", traits); - let mut candidates = traits.iter().filter_map(|&trait_| { - cx.tcx.associated_items(trait_).find_by_name_and_namespace( - cx.tcx, - Ident::with_dummy_span(item_name), - ns, - trait_, - ) + let mut candidates = traits.iter().filter_map(|&(impl_, trait_)| { + cx.tcx + .associated_items(trait_) + .find_by_name_and_namespace(cx.tcx, Ident::with_dummy_span(item_name), ns, trait_) + .map(|trait_assoc| { + trait_assoc_to_impl_assoc_item(cx.tcx, impl_, trait_assoc.def_id) + .unwrap_or(trait_assoc) + }) }); // FIXME(#74563): warn about ambiguity debug!("the candidates were {:?}", candidates.clone().collect::>()); candidates.next().copied() } -/// Given a type, return all traits in scope in `module` implemented by that type. +/// Find the associated item in the impl `impl_id` that corresponds to the +/// trait associated item `trait_assoc_id`. +/// +/// This function returns `None` if no associated item was found in the impl. +/// This can occur when the trait associated item has a default value that is +/// not overriden in the impl. +/// +/// This is just a wrapper around [`TyCtxt::impl_item_implementor_ids()`] and +/// [`TyCtxt::associated_item()`] (with some helpful logging added). +#[instrument(level = "debug", skip(tcx))] +fn trait_assoc_to_impl_assoc_item<'tcx>( + tcx: TyCtxt<'tcx>, + impl_id: DefId, + trait_assoc_id: DefId, +) -> Option<&'tcx ty::AssocItem> { + let trait_to_impl_assoc_map = tcx.impl_item_implementor_ids(impl_id); + debug!(?trait_to_impl_assoc_map); + let impl_assoc_id = *trait_to_impl_assoc_map.get(&trait_assoc_id)?; + debug!(?impl_assoc_id); + let impl_assoc = tcx.associated_item(impl_assoc_id); + debug!(?impl_assoc); + Some(impl_assoc) +} + +/// Given a type, return all trait impls in scope in `module` for that type. +/// Returns a set of pairs of `(impl_id, trait_id)`. /// /// NOTE: this cannot be a query because more traits could be available when more crates are compiled! /// So it is not stable to serialize cross-crate. -fn traits_implemented_by<'a>( +fn trait_impls_for<'a>( cx: &mut DocContext<'a>, ty: Ty<'a>, module: DefId, -) -> FxHashSet { +) -> FxHashSet<(DefId, DefId)> { let mut resolver = cx.resolver.borrow_mut(); let in_scope_traits = cx.module_trait_cache.entry(module).or_insert_with(|| { resolver.access(|resolver| { @@ -948,7 +966,7 @@ fn traits_implemented_by<'a>( _ => false, }; - if saw_impl { Some(trait_) } else { None } + if saw_impl { Some((impl_, trait_)) } else { None } }) }); iter.collect() From 2938be612dce1d2976bebf80812d713257a3b501 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 18 Jan 2022 16:56:16 +0100 Subject: [PATCH 15/27] Correctly handle starts in block doc comments --- compiler/rustc_ast/src/attr/mod.rs | 11 +++++++ compiler/rustc_ast/src/util/comments.rs | 29 ++++++++++++++++--- compiler/rustc_ast/src/util/comments/tests.rs | 14 ++++----- compiler/rustc_save_analysis/src/lib.rs | 4 +-- src/librustdoc/clean/types.rs | 4 +-- 5 files changed, 47 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index d66774040f782..6a0ace04d4b61 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -242,6 +242,17 @@ impl Attribute { } } + pub fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> { + match self.kind { + AttrKind::DocComment(kind, data) => Some((data, kind)), + AttrKind::Normal(ref item, _) if item.path == sym::doc => item + .meta_kind() + .and_then(|kind| kind.value_str()) + .map(|data| (data, CommentKind::Line)), + _ => None, + } + } + pub fn doc_str(&self) -> Option { match self.kind { AttrKind::DocComment(.., data) => Some(data), diff --git a/compiler/rustc_ast/src/util/comments.rs b/compiler/rustc_ast/src/util/comments.rs index 0a391123dd381..612ee71f350f1 100644 --- a/compiler/rustc_ast/src/util/comments.rs +++ b/compiler/rustc_ast/src/util/comments.rs @@ -1,3 +1,4 @@ +use crate::token::CommentKind; use rustc_span::source_map::SourceMap; use rustc_span::{BytePos, CharPos, FileName, Pos, Symbol}; @@ -25,7 +26,7 @@ pub struct Comment { /// Makes a doc string more presentable to users. /// Used by rustdoc and perhaps other tools, but not by rustc. -pub fn beautify_doc_string(data: Symbol) -> Symbol { +pub fn beautify_doc_string(data: Symbol, kind: CommentKind) -> Symbol { fn get_vertical_trim(lines: &[&str]) -> Option<(usize, usize)> { let mut i = 0; let mut j = lines.len(); @@ -42,10 +43,28 @@ pub fn beautify_doc_string(data: Symbol) -> Symbol { if i != 0 || j != lines.len() { Some((i, j)) } else { None } } - fn get_horizontal_trim(lines: &[&str]) -> Option { + fn get_horizontal_trim(lines: &[&str], kind: CommentKind) -> Option { let mut i = usize::MAX; let mut first = true; + // In case we have doc comments like `/**` or `/*!`, we want to remove stars if they are + // present. However, we first need to strip the empty lines so they don't get in the middle + // when we try to compute the "horizontal trim". + let lines = if kind == CommentKind::Block { + let mut i = 0; + let mut j = lines.len(); + + while i < j && lines[i].trim().is_empty() { + i += 1; + } + while j > i && lines[j - 1].trim().is_empty() { + j -= 1; + } + &lines[i..j] + } else { + lines + }; + for line in lines { for (j, c) in line.chars().enumerate() { if j > i || !"* \t".contains(c) { @@ -79,11 +98,13 @@ pub fn beautify_doc_string(data: Symbol) -> Symbol { } else { &mut lines }; - if let Some(horizontal) = get_horizontal_trim(&lines) { + if let Some(horizontal) = get_horizontal_trim(&lines, kind) { changes = true; // remove a "[ \t]*\*" block from each line, if possible for line in lines.iter_mut() { - *line = &line[horizontal + 1..]; + if horizontal + 1 < line.len() { + *line = &line[horizontal + 1..]; + } } } if changes { diff --git a/compiler/rustc_ast/src/util/comments/tests.rs b/compiler/rustc_ast/src/util/comments/tests.rs index 6d137f3774fe7..98f692a7724e2 100644 --- a/compiler/rustc_ast/src/util/comments/tests.rs +++ b/compiler/rustc_ast/src/util/comments/tests.rs @@ -5,7 +5,7 @@ use rustc_span::create_default_session_globals_then; fn test_block_doc_comment_1() { create_default_session_globals_then(|| { let comment = "\n * Test \n ** Test\n * Test\n"; - let stripped = beautify_doc_string(Symbol::intern(comment)); + let stripped = beautify_doc_string(Symbol::intern(comment), CommentKind::Block); assert_eq!(stripped.as_str(), " Test \n* Test\n Test"); }) } @@ -14,7 +14,7 @@ fn test_block_doc_comment_1() { fn test_block_doc_comment_2() { create_default_session_globals_then(|| { let comment = "\n * Test\n * Test\n"; - let stripped = beautify_doc_string(Symbol::intern(comment)); + let stripped = beautify_doc_string(Symbol::intern(comment), CommentKind::Block); assert_eq!(stripped.as_str(), " Test\n Test"); }) } @@ -23,7 +23,7 @@ fn test_block_doc_comment_2() { fn test_block_doc_comment_3() { create_default_session_globals_then(|| { let comment = "\n let a: *i32;\n *a = 5;\n"; - let stripped = beautify_doc_string(Symbol::intern(comment)); + let stripped = beautify_doc_string(Symbol::intern(comment), CommentKind::Block); assert_eq!(stripped.as_str(), " let a: *i32;\n *a = 5;"); }) } @@ -31,13 +31,13 @@ fn test_block_doc_comment_3() { #[test] fn test_line_doc_comment() { create_default_session_globals_then(|| { - let stripped = beautify_doc_string(Symbol::intern(" test")); + let stripped = beautify_doc_string(Symbol::intern(" test"), CommentKind::Line); assert_eq!(stripped.as_str(), " test"); - let stripped = beautify_doc_string(Symbol::intern("! test")); + let stripped = beautify_doc_string(Symbol::intern("! test"), CommentKind::Line); assert_eq!(stripped.as_str(), "! test"); - let stripped = beautify_doc_string(Symbol::intern("test")); + let stripped = beautify_doc_string(Symbol::intern("test"), CommentKind::Line); assert_eq!(stripped.as_str(), "test"); - let stripped = beautify_doc_string(Symbol::intern("!test")); + let stripped = beautify_doc_string(Symbol::intern("!test"), CommentKind::Line); assert_eq!(stripped.as_str(), "!test"); }) } diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs index 21cb93cc5f48b..b95fe1b0549bd 100644 --- a/compiler/rustc_save_analysis/src/lib.rs +++ b/compiler/rustc_save_analysis/src/lib.rs @@ -821,9 +821,9 @@ impl<'tcx> SaveContext<'tcx> { let mut result = String::new(); for attr in attrs { - if let Some(val) = attr.doc_str() { + if let Some((val, kind)) = attr.doc_str_and_comment_kind() { // FIXME: Should save-analysis beautify doc strings itself or leave it to users? - result.push_str(beautify_doc_string(val).as_str()); + result.push_str(beautify_doc_string(val, kind).as_str()); result.push('\n'); } } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 00c6e38839f54..8e60473140a57 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1040,9 +1040,9 @@ impl Attributes { ) -> Attributes { let mut doc_strings: Vec = vec![]; let clean_attr = |(attr, parent_module): (&ast::Attribute, Option)| { - if let Some(value) = attr.doc_str() { + if let Some((value, kind)) = attr.doc_str_and_comment_kind() { trace!("got doc_str={:?}", value); - let value = beautify_doc_string(value); + let value = beautify_doc_string(value, kind); let kind = if attr.is_doc_comment() { DocFragmentKind::SugaredDoc } else { From 06b00ad19972c18150fe25a9b3716ffdf5300a83 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 18 Jan 2022 16:56:37 +0100 Subject: [PATCH 16/27] Add test for block doc comments --- .../strip-block-doc-comments-stars.docblock.html | 2 ++ src/test/rustdoc/strip-block-doc-comments-stars.rs | 11 +++++++++++ 2 files changed, 13 insertions(+) create mode 100644 src/test/rustdoc/strip-block-doc-comments-stars.docblock.html create mode 100644 src/test/rustdoc/strip-block-doc-comments-stars.rs diff --git a/src/test/rustdoc/strip-block-doc-comments-stars.docblock.html b/src/test/rustdoc/strip-block-doc-comments-stars.docblock.html new file mode 100644 index 0000000000000..22b0b5dc47e28 --- /dev/null +++ b/src/test/rustdoc/strip-block-doc-comments-stars.docblock.html @@ -0,0 +1,2 @@ +

a

+
\ No newline at end of file diff --git a/src/test/rustdoc/strip-block-doc-comments-stars.rs b/src/test/rustdoc/strip-block-doc-comments-stars.rs new file mode 100644 index 0000000000000..ed2297b4fac5d --- /dev/null +++ b/src/test/rustdoc/strip-block-doc-comments-stars.rs @@ -0,0 +1,11 @@ +#![crate_name = "foo"] + +// The goal of this test is to answer that it won't be generated as a list because +// block doc comments can have their lines starting with a star. + +// @has foo/fn.foo.html +// @snapshot docblock - '//*[@class="rustdoc-toggle top-doc"]//*[@class="docblock"]' +/** + * a + */ +pub fn foo() {} From 5ab67bff1e2230217ce133165605f8dc0d588178 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Thu, 6 Jan 2022 02:47:36 +0000 Subject: [PATCH 17/27] Fix CVE-2022-21658 for Windows --- library/std/src/sys/windows/c.rs | 124 +++++++++++- library/std/src/sys/windows/fs.rs | 322 ++++++++++++++++++++++++++++-- 2 files changed, 419 insertions(+), 27 deletions(-) diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index b87b6b5d88e4a..09d3661e4fd52 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -4,6 +4,7 @@ #![cfg_attr(test, allow(dead_code))] #![unstable(issue = "none", feature = "windows_c")] +use crate::mem; use crate::os::raw::NonZero_c_ulong; use crate::os::raw::{c_char, c_int, c_long, c_longlong, c_uint, c_ulong, c_ushort}; use crate::ptr; @@ -36,6 +37,7 @@ pub type USHORT = c_ushort; pub type SIZE_T = usize; pub type WORD = u16; pub type CHAR = c_char; +pub type CCHAR = c_char; pub type ULONG_PTR = usize; pub type ULONG = c_ulong; pub type NTSTATUS = LONG; @@ -86,16 +88,21 @@ pub const FILE_SHARE_DELETE: DWORD = 0x4; pub const FILE_SHARE_READ: DWORD = 0x1; pub const FILE_SHARE_WRITE: DWORD = 0x2; +pub const FILE_OPEN_REPARSE_POINT: ULONG = 0x200000; +pub const OBJ_DONT_REPARSE: ULONG = 0x1000; + pub const CREATE_ALWAYS: DWORD = 2; pub const CREATE_NEW: DWORD = 1; pub const OPEN_ALWAYS: DWORD = 4; pub const OPEN_EXISTING: DWORD = 3; pub const TRUNCATE_EXISTING: DWORD = 5; +pub const FILE_LIST_DIRECTORY: DWORD = 0x1; pub const FILE_WRITE_DATA: DWORD = 0x00000002; pub const FILE_APPEND_DATA: DWORD = 0x00000004; pub const FILE_WRITE_EA: DWORD = 0x00000010; pub const FILE_WRITE_ATTRIBUTES: DWORD = 0x00000100; +pub const DELETE: DWORD = 0x10000; pub const READ_CONTROL: DWORD = 0x00020000; pub const SYNCHRONIZE: DWORD = 0x00100000; pub const GENERIC_READ: DWORD = 0x80000000; @@ -261,9 +268,61 @@ pub const FD_SETSIZE: usize = 64; pub const STACK_SIZE_PARAM_IS_A_RESERVATION: DWORD = 0x00010000; pub const STATUS_SUCCESS: NTSTATUS = 0x00000000; +pub const STATUS_DELETE_PENDING: NTSTATUS = 0xc0000056_u32 as _; +pub const STATUS_INVALID_PARAMETER: NTSTATUS = 0xc000000d_u32 as _; + +// Equivalent to the `NT_SUCCESS` C preprocessor macro. +// See: https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/using-ntstatus-values +pub fn nt_success(status: NTSTATUS) -> bool { + status >= 0 +} pub const BCRYPT_USE_SYSTEM_PREFERRED_RNG: DWORD = 0x00000002; +#[repr(C)] +pub struct UNICODE_STRING { + pub Length: u16, + pub MaximumLength: u16, + pub Buffer: *mut u16, +} +impl UNICODE_STRING { + pub fn from_ref(slice: &[u16]) -> Self { + let len = slice.len() * mem::size_of::(); + Self { Length: len as _, MaximumLength: len as _, Buffer: slice.as_ptr() as _ } + } +} +#[repr(C)] +pub struct OBJECT_ATTRIBUTES { + pub Length: ULONG, + pub RootDirectory: HANDLE, + pub ObjectName: *const UNICODE_STRING, + pub Attributes: ULONG, + pub SecurityDescriptor: *mut c_void, + pub SecurityQualityOfService: *mut c_void, +} +impl Default for OBJECT_ATTRIBUTES { + fn default() -> Self { + Self { + Length: mem::size_of::() as _, + RootDirectory: ptr::null_mut(), + ObjectName: ptr::null_mut(), + Attributes: 0, + SecurityDescriptor: ptr::null_mut(), + SecurityQualityOfService: ptr::null_mut(), + } + } +} +#[repr(C)] +pub struct IO_STATUS_BLOCK { + pub Pointer: *mut c_void, + pub Information: usize, +} +impl Default for IO_STATUS_BLOCK { + fn default() -> Self { + Self { Pointer: ptr::null_mut(), Information: 0 } + } +} + #[repr(C)] #[cfg(not(target_pointer_width = "64"))] pub struct WSADATA { @@ -353,9 +412,43 @@ pub enum FILE_INFO_BY_HANDLE_CLASS { FileIdInfo = 18, // 0x12 FileIdExtdDirectoryInfo = 19, // 0x13 FileIdExtdDirectoryRestartInfo = 20, // 0x14 + FileDispositionInfoEx = 21, // 0x15, Windows 10 version 1607 MaximumFileInfoByHandlesClass, } +#[repr(C)] +pub struct FILE_DISPOSITION_INFO { + pub DeleteFile: BOOLEAN, +} + +pub const FILE_DISPOSITION_DELETE: DWORD = 0x1; +pub const FILE_DISPOSITION_POSIX_SEMANTICS: DWORD = 0x2; +pub const FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE: DWORD = 0x10; + +#[repr(C)] +pub struct FILE_DISPOSITION_INFO_EX { + pub Flags: DWORD, +} + +#[repr(C)] +#[derive(Default)] +pub struct FILE_ID_BOTH_DIR_INFO { + pub NextEntryOffset: DWORD, + pub FileIndex: DWORD, + pub CreationTime: LARGE_INTEGER, + pub LastAccessTime: LARGE_INTEGER, + pub LastWriteTime: LARGE_INTEGER, + pub ChangeTime: LARGE_INTEGER, + pub EndOfFile: LARGE_INTEGER, + pub AllocationSize: LARGE_INTEGER, + pub FileAttributes: DWORD, + pub FileNameLength: DWORD, + pub EaSize: DWORD, + pub ShortNameLength: CCHAR, + pub ShortName: [WCHAR; 12], + pub FileId: LARGE_INTEGER, + pub FileName: [WCHAR; 1], +} #[repr(C)] pub struct FILE_BASIC_INFO { pub CreationTime: LARGE_INTEGER, @@ -750,16 +843,6 @@ if #[cfg(target_vendor = "uwp")] { pub DeletePending: BOOLEAN, pub Directory: BOOLEAN, } - - #[link(name = "kernel32")] - extern "system" { - pub fn GetFileInformationByHandleEx( - hFile: HANDLE, - fileInfoClass: FILE_INFO_BY_HANDLE_CLASS, - lpFileInformation: LPVOID, - dwBufferSize: DWORD, - ) -> BOOL; - } } } @@ -949,6 +1032,12 @@ extern "system" { cchFilePath: DWORD, dwFlags: DWORD, ) -> DWORD; + pub fn GetFileInformationByHandleEx( + hFile: HANDLE, + fileInfoClass: FILE_INFO_BY_HANDLE_CLASS, + lpFileInformation: LPVOID, + dwBufferSize: DWORD, + ) -> BOOL; pub fn SetFileInformationByHandle( hFile: HANDLE, FileInformationClass: FILE_INFO_BY_HANDLE_CLASS, @@ -1139,6 +1228,21 @@ compat_fn! { compat_fn! { "ntdll": + pub fn NtOpenFile( + FileHandle: *mut HANDLE, + DesiredAccess: ACCESS_MASK, + ObjectAttributes: *const OBJECT_ATTRIBUTES, + IoStatusBlock: *mut IO_STATUS_BLOCK, + ShareAccess: ULONG, + OpenOptions: ULONG + ) -> NTSTATUS { + panic!("`NtOpenFile` not available"); + } + pub fn RtlNtStatusToDosError( + Status: NTSTATUS + ) -> ULONG { + panic!("`RtlNtStatusToDosError` not available"); + } pub fn NtCreateKeyedEvent( KeyedEventHandle: LPHANDLE, DesiredAccess: ACCESS_MASK, diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index b258fc0478bdc..dd21c6b43891f 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -547,6 +547,218 @@ impl File { })?; Ok(()) } + /// Get only basic file information such as attributes and file times. + fn basic_info(&self) -> io::Result { + unsafe { + let mut info: c::FILE_BASIC_INFO = mem::zeroed(); + let size = mem::size_of_val(&info); + cvt(c::GetFileInformationByHandleEx( + self.handle.as_raw_handle(), + c::FileBasicInfo, + &mut info as *mut _ as *mut libc::c_void, + size as c::DWORD, + ))?; + Ok(info) + } + } + /// Delete using POSIX semantics. + /// + /// Files will be deleted as soon as the handle is closed. This is supported + /// for Windows 10 1607 (aka RS1) and later. However some filesystem + /// drivers will not support it even then, e.g. FAT32. + /// + /// If the operation is not supported for this filesystem or OS version + /// then errors will be `ERROR_NOT_SUPPORTED` or `ERROR_INVALID_PARAMETER`. + fn posix_delete(&self) -> io::Result<()> { + let mut info = c::FILE_DISPOSITION_INFO_EX { + Flags: c::FILE_DISPOSITION_DELETE + | c::FILE_DISPOSITION_POSIX_SEMANTICS + | c::FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE, + }; + let size = mem::size_of_val(&info); + cvt(unsafe { + c::SetFileInformationByHandle( + self.handle.as_raw_handle(), + c::FileDispositionInfoEx, + &mut info as *mut _ as *mut _, + size as c::DWORD, + ) + })?; + Ok(()) + } + + /// Delete a file using win32 semantics. The file won't actually be deleted + /// until all file handles are closed. However, marking a file for deletion + /// will prevent anyone from opening a new handle to the file. + fn win32_delete(&self) -> io::Result<()> { + let mut info = c::FILE_DISPOSITION_INFO { DeleteFile: c::TRUE as _ }; + let size = mem::size_of_val(&info); + cvt(unsafe { + c::SetFileInformationByHandle( + self.handle.as_raw_handle(), + c::FileDispositionInfo, + &mut info as *mut _ as *mut _, + size as c::DWORD, + ) + })?; + Ok(()) + } + + /// Fill the given buffer with as many directory entries as will fit. + /// This will remember its position and continue from the last call unless + /// `restart` is set to `true`. + /// + /// The returned bool indicates if there are more entries or not. + /// It is an error if `self` is not a directory. + /// + /// # Symlinks and other reparse points + /// + /// On Windows a file is either a directory or a non-directory. + /// A symlink directory is simply an empty directory with some "reparse" metadata attached. + /// So if you open a link (not its target) and iterate the directory, + /// you will always iterate an empty directory regardless of the target. + fn fill_dir_buff(&self, buffer: &mut DirBuff, restart: bool) -> io::Result { + let class = + if restart { c::FileIdBothDirectoryRestartInfo } else { c::FileIdBothDirectoryInfo }; + + unsafe { + let result = cvt(c::GetFileInformationByHandleEx( + self.handle.as_raw_handle(), + class, + buffer.as_mut_ptr().cast(), + buffer.capacity() as _, + )); + match result { + Ok(_) => Ok(true), + Err(e) if e.raw_os_error() == Some(c::ERROR_NO_MORE_FILES as _) => Ok(false), + Err(e) => Err(e), + } + } + } +} + +/// A buffer for holding directory entries. +struct DirBuff { + buffer: Vec, +} +impl DirBuff { + fn new() -> Self { + const BUFFER_SIZE: usize = 1024; + Self { buffer: vec![0_u8; BUFFER_SIZE] } + } + fn capacity(&self) -> usize { + self.buffer.len() + } + fn as_mut_ptr(&mut self) -> *mut u8 { + self.buffer.as_mut_ptr().cast() + } + /// Returns a `DirBuffIter`. + fn iter(&self) -> DirBuffIter<'_> { + DirBuffIter::new(self) + } +} +impl AsRef<[u8]> for DirBuff { + fn as_ref(&self) -> &[u8] { + &self.buffer + } +} + +/// An iterator over entries stored in a `DirBuff`. +/// +/// Currently only returns file names (UTF-16 encoded). +struct DirBuffIter<'a> { + buffer: Option<&'a [u8]>, + cursor: usize, +} +impl<'a> DirBuffIter<'a> { + fn new(buffer: &'a DirBuff) -> Self { + Self { buffer: Some(buffer.as_ref()), cursor: 0 } + } +} +impl<'a> Iterator for DirBuffIter<'a> { + type Item = &'a [u16]; + fn next(&mut self) -> Option { + use crate::mem::size_of; + let buffer = &self.buffer?[self.cursor..]; + + // Get the name and next entry from the buffer. + // SAFETY: The buffer contains a `FILE_ID_BOTH_DIR_INFO` struct but the + // last field (the file name) is unsized. So an offset has to be + // used to get the file name slice. + let (name, next_entry) = unsafe { + let info = buffer.as_ptr().cast::(); + let next_entry = (*info).NextEntryOffset as usize; + let name = crate::slice::from_raw_parts( + (*info).FileName.as_ptr().cast::(), + (*info).FileNameLength as usize / size_of::(), + ); + (name, next_entry) + }; + + if next_entry == 0 { + self.buffer = None + } else { + self.cursor += next_entry + } + + // Skip `.` and `..` pseudo entries. + const DOT: u16 = b'.' as u16; + match name { + [DOT] | [DOT, DOT] => self.next(), + _ => Some(name), + } + } +} + +/// Open a link relative to the parent directory, ensure no symlinks are followed. +fn open_link_no_reparse(parent: &File, name: &[u16], access: u32) -> io::Result { + // This is implemented using the lower level `NtOpenFile` function as + // unfortunately opening a file relative to a parent is not supported by + // win32 functions. It is however a fundamental feature of the NT kernel. + // + // See https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntopenfile + unsafe { + let mut handle = ptr::null_mut(); + let mut io_status = c::IO_STATUS_BLOCK::default(); + let name_str = c::UNICODE_STRING::from_ref(name); + use crate::sync::atomic::{AtomicU32, Ordering}; + // The `OBJ_DONT_REPARSE` attribute ensures that we haven't been + // tricked into following a symlink. However, it may not be available in + // earlier versions of Windows. + static ATTRIBUTES: AtomicU32 = AtomicU32::new(c::OBJ_DONT_REPARSE); + let object = c::OBJECT_ATTRIBUTES { + ObjectName: &name_str, + RootDirectory: parent.as_raw_handle(), + Attributes: ATTRIBUTES.load(Ordering::Relaxed), + ..c::OBJECT_ATTRIBUTES::default() + }; + let status = c::NtOpenFile( + &mut handle, + access, + &object, + &mut io_status, + c::FILE_SHARE_DELETE | c::FILE_SHARE_READ | c::FILE_SHARE_WRITE, + // If `name` is a symlink then open the link rather than the target. + c::FILE_OPEN_REPARSE_POINT, + ); + // Convert an NTSTATUS to the more familiar Win32 error codes (aka "DosError") + if c::nt_success(status) { + Ok(File::from_raw_handle(handle)) + } else if status == c::STATUS_DELETE_PENDING { + // We make a special exception for `STATUS_DELETE_PENDING` because + // otherwise this will be mapped to `ERROR_ACCESS_DENIED` which is + // very unhelpful. + Err(io::Error::from_raw_os_error(c::ERROR_DELETE_PENDING as _)) + } else if status == c::STATUS_INVALID_PARAMETER + && ATTRIBUTES.load(Ordering::Relaxed) == c::OBJ_DONT_REPARSE + { + // Try without `OBJ_DONT_REPARSE`. See above. + ATTRIBUTES.store(0, Ordering::Relaxed); + open_link_no_reparse(parent, name, access) + } else { + Err(io::Error::from_raw_os_error(c::RtlNtStatusToDosError(status) as _)) + } + } } impl AsInner for File { @@ -756,30 +968,106 @@ pub fn rmdir(p: &Path) -> io::Result<()> { Ok(()) } +/// Open a file or directory without following symlinks. +fn open_link(path: &Path, access_mode: u32) -> io::Result { + let mut opts = OpenOptions::new(); + opts.access_mode(access_mode); + // `FILE_FLAG_BACKUP_SEMANTICS` allows opening directories. + // `FILE_FLAG_OPEN_REPARSE_POINT` opens a link instead of its target. + opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS | c::FILE_FLAG_OPEN_REPARSE_POINT); + File::open(path, &opts) +} + pub fn remove_dir_all(path: &Path) -> io::Result<()> { - let filetype = lstat(path)?.file_type(); - if filetype.is_symlink() { - // On Windows symlinks to files and directories are removed differently. - // rmdir only deletes dir symlinks and junctions, not file symlinks. - rmdir(path) + let file = open_link(path, c::DELETE | c::FILE_LIST_DIRECTORY)?; + + // Test if the file is not a directory or a symlink to a directory. + if (file.basic_info()?.FileAttributes & c::FILE_ATTRIBUTE_DIRECTORY) == 0 { + return Err(io::Error::from_raw_os_error(c::ERROR_DIRECTORY as _)); + } + let mut delete: fn(&File) -> io::Result<()> = File::posix_delete; + let result = match delete(&file) { + Err(e) if e.kind() == io::ErrorKind::DirectoryNotEmpty => { + match remove_dir_all_recursive(&file, delete) { + // Return unexpected errors. + Err(e) if e.kind() != io::ErrorKind::DirectoryNotEmpty => return Err(e), + result => result, + } + } + // If POSIX delete is not supported for this filesystem then fallback to win32 delete. + Err(e) + if e.raw_os_error() == Some(c::ERROR_NOT_SUPPORTED as i32) + || e.raw_os_error() == Some(c::ERROR_INVALID_PARAMETER as i32) => + { + delete = File::win32_delete; + Err(e) + } + result => result, + }; + if result.is_ok() { + Ok(()) } else { - remove_dir_all_recursive(path) + // This is a fallback to make sure the directory is actually deleted. + // Otherwise this function is prone to failing with `DirectoryNotEmpty` + // due to possible delays between marking a file for deletion and the + // file actually being deleted from the filesystem. + // + // So we retry a few times before giving up. + for _ in 0..5 { + match remove_dir_all_recursive(&file, delete) { + Err(e) if e.kind() == io::ErrorKind::DirectoryNotEmpty => {} + result => return result, + } + } + // Try one last time. + delete(&file) } } -fn remove_dir_all_recursive(path: &Path) -> io::Result<()> { - for child in readdir(path)? { - let child = child?; - let child_type = child.file_type()?; - if child_type.is_dir() { - remove_dir_all_recursive(&child.path())?; - } else if child_type.is_symlink_dir() { - rmdir(&child.path())?; - } else { - unlink(&child.path())?; +fn remove_dir_all_recursive(f: &File, delete: fn(&File) -> io::Result<()>) -> io::Result<()> { + let mut buffer = DirBuff::new(); + let mut restart = true; + // Fill the buffer and iterate the entries. + while f.fill_dir_buff(&mut buffer, restart)? { + for name in buffer.iter() { + // Open the file without following symlinks and try deleting it. + // We try opening will all needed permissions and if that is denied + // fallback to opening without `FILE_LIST_DIRECTORY` permission. + // Note `SYNCHRONIZE` permission is needed for synchronous access. + let mut result = + open_link_no_reparse(&f, name, c::SYNCHRONIZE | c::DELETE | c::FILE_LIST_DIRECTORY); + if matches!(&result, Err(e) if e.kind() == io::ErrorKind::PermissionDenied) { + result = open_link_no_reparse(&f, name, c::SYNCHRONIZE | c::DELETE); + } + match result { + Ok(file) => match delete(&file) { + Err(e) if e.kind() == io::ErrorKind::DirectoryNotEmpty => { + // Iterate the directory's files. + // Ignore `DirectoryNotEmpty` errors here. They will be + // caught when `remove_dir_all` tries to delete the top + // level directory. It can then decide if to retry or not. + match remove_dir_all_recursive(&file, delete) { + Err(e) if e.kind() == io::ErrorKind::DirectoryNotEmpty => {} + result => result?, + } + } + result => result?, + }, + // Ignore error if a delete is already in progress or the file + // has already been deleted. It also ignores sharing violations + // (where a file is locked by another process) as these are + // usually temporary. + Err(e) + if e.raw_os_error() == Some(c::ERROR_DELETE_PENDING as _) + || e.kind() == io::ErrorKind::NotFound + || e.raw_os_error() == Some(c::ERROR_SHARING_VIOLATION as _) => {} + Err(e) => return Err(e), + } } + // Continue reading directory entries without restarting from the beginning, + restart = false; } - rmdir(path) + delete(&f) } pub fn readlink(path: &Path) -> io::Result { From 54e22eb7dbb615bd44355028d3fd867aa93c0972 Mon Sep 17 00:00:00 2001 From: Hans Kratz Date: Sat, 18 Dec 2021 15:30:30 +0100 Subject: [PATCH 18/27] Fix CVE-2022-21658 for UNIX-like --- library/std/src/fs/tests.rs | 70 ++++++++ library/std/src/sys/unix/fs.rs | 288 +++++++++++++++++++++++++++++-- library/std/src/sys/unix/weak.rs | 6 +- 3 files changed, 351 insertions(+), 13 deletions(-) diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 749d51d4981c3..a62c01ef29b27 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -4,8 +4,10 @@ use crate::fs::{self, File, OpenOptions}; use crate::io::{ErrorKind, SeekFrom}; use crate::path::Path; use crate::str; +use crate::sync::Arc; use crate::sys_common::io::test::{tmpdir, TempDir}; use crate::thread; +use crate::time::{Duration, Instant}; use rand::{rngs::StdRng, RngCore, SeedableRng}; @@ -601,6 +603,21 @@ fn recursive_rmdir_of_symlink() { assert!(canary.exists()); } +#[test] +fn recursive_rmdir_of_file_fails() { + // test we do not delete a directly specified file. + let tmpdir = tmpdir(); + let canary = tmpdir.join("do_not_delete"); + check!(check!(File::create(&canary)).write(b"foo")); + let result = fs::remove_dir_all(&canary); + #[cfg(unix)] + error!(result, "Not a directory"); + #[cfg(windows)] + error!(result, 267); // ERROR_DIRECTORY - The directory name is invalid. + assert!(result.is_err()); + assert!(canary.exists()); +} + #[test] // only Windows makes a distinction between file and directory symlinks. #[cfg(windows)] @@ -620,6 +637,59 @@ fn recursive_rmdir_of_file_symlink() { } } +#[test] +#[ignore] // takes too much time +fn recursive_rmdir_toctou() { + // Test for time-of-check to time-of-use issues. + // + // Scenario: + // The attacker wants to get directory contents deleted, to which he does not have access. + // He has a way to get a privileged Rust binary call `std::fs::remove_dir_all()` on a + // directory he controls, e.g. in his home directory. + // + // The POC sets up the `attack_dest/attack_file` which the attacker wants to have deleted. + // The attacker repeatedly creates a directory and replaces it with a symlink from + // `victim_del` to `attack_dest` while the victim code calls `std::fs::remove_dir_all()` + // on `victim_del`. After a few seconds the attack has succeeded and + // `attack_dest/attack_file` is deleted. + let tmpdir = tmpdir(); + let victim_del_path = tmpdir.join("victim_del"); + let victim_del_path_clone = victim_del_path.clone(); + + // setup dest + let attack_dest_dir = tmpdir.join("attack_dest"); + let attack_dest_dir = attack_dest_dir.as_path(); + fs::create_dir(attack_dest_dir).unwrap(); + let attack_dest_file = tmpdir.join("attack_dest/attack_file"); + File::create(&attack_dest_file).unwrap(); + + let drop_canary_arc = Arc::new(()); + let drop_canary_weak = Arc::downgrade(&drop_canary_arc); + + eprintln!("x: {:?}", &victim_del_path); + + // victim just continuously removes `victim_del` + thread::spawn(move || { + while drop_canary_weak.upgrade().is_some() { + let _ = fs::remove_dir_all(&victim_del_path_clone); + } + }); + + // attacker (could of course be in a separate process) + let start_time = Instant::now(); + while Instant::now().duration_since(start_time) < Duration::from_secs(1000) { + if !attack_dest_file.exists() { + panic!( + "Victim deleted symlinked file outside of victim_del. Attack succeeded in {:?}.", + Instant::now().duration_since(start_time) + ); + } + let _ = fs::create_dir(&victim_del_path); + let _ = fs::remove_dir(&victim_del_path); + let _ = symlink_dir(attack_dest_dir, &victim_del_path); + } +} + #[test] fn unicode_path_is_dir() { assert!(Path::new(".").is_dir()); diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index bcf2be0e95fb7..16460bee66ff2 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -64,7 +64,7 @@ use libc::{ dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, readdir64_r, stat64, }; -pub use crate::sys_common::fs::{remove_dir_all, try_exists}; +pub use crate::sys_common::fs::try_exists; pub struct File(FileDesc); @@ -228,7 +228,7 @@ pub struct DirEntry { target_os = "fuchsia", target_os = "redox" ))] - name: Box<[u8]>, + name: CString, } #[derive(Clone, Debug)] @@ -455,8 +455,6 @@ impl Iterator for ReadDir { target_os = "illumos" ))] fn next(&mut self) -> Option> { - use crate::slice; - unsafe { loop { // Although readdir_r(3) would be a correct function to use here because @@ -474,14 +472,10 @@ impl Iterator for ReadDir { }; } - let name = (*entry_ptr).d_name.as_ptr(); - let namelen = libc::strlen(name) as usize; - let ret = DirEntry { entry: *entry_ptr, - name: slice::from_raw_parts(name as *const u8, namelen as usize) - .to_owned() - .into_boxed_slice(), + // d_name is guaranteed to be null-terminated. + name: CStr::from_ptr((*entry_ptr).d_name.as_ptr()).to_owned(), dir: Arc::clone(&self.inner), }; if ret.name_bytes() != b"." && ret.name_bytes() != b".." { @@ -664,7 +658,26 @@ impl DirEntry { target_os = "redox" ))] fn name_bytes(&self) -> &[u8] { - &*self.name + self.name.as_bytes() + } + + #[cfg(not(any( + target_os = "solaris", + target_os = "illumos", + target_os = "fuchsia", + target_os = "redox" + )))] + fn name_cstr(&self) -> &CStr { + unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) } + } + #[cfg(any( + target_os = "solaris", + target_os = "illumos", + target_os = "fuchsia", + target_os = "redox" + ))] + fn name_cstr(&self) -> &CStr { + &self.name } pub fn file_name_os_str(&self) -> &OsStr { @@ -1437,3 +1450,256 @@ pub fn chroot(dir: &Path) -> io::Result<()> { cvt(unsafe { libc::chroot(dir.as_ptr()) })?; Ok(()) } + +pub use remove_dir_impl::remove_dir_all; + +// Fallback for REDOX +#[cfg(target_os = "redox")] +mod remove_dir_impl { + pub use crate::sys_common::fs::remove_dir_all; +} + +// Dynamically choose implementation Macos x86-64: modern for 10.10+, fallback for older versions +#[cfg(all(target_os = "macos", target_arch = "x86_64"))] +mod remove_dir_impl { + use super::{cstr, lstat, Dir, InnerReadDir, ReadDir}; + use crate::ffi::CStr; + use crate::io; + use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd}; + use crate::os::unix::prelude::{OwnedFd, RawFd}; + use crate::path::{Path, PathBuf}; + use crate::sync::Arc; + use crate::sys::weak::weak; + use crate::sys::{cvt, cvt_r}; + use libc::{c_char, c_int, DIR}; + + pub fn openat_nofollow_dironly(parent_fd: Option, p: &CStr) -> io::Result { + weak!(fn openat(c_int, *const c_char, c_int) -> c_int); + let fd = cvt_r(|| unsafe { + openat.get().unwrap()( + parent_fd.unwrap_or(libc::AT_FDCWD), + p.as_ptr(), + libc::O_CLOEXEC | libc::O_RDONLY | libc::O_NOFOLLOW | libc::O_DIRECTORY, + ) + })?; + Ok(unsafe { OwnedFd::from_raw_fd(fd) }) + } + + fn fdreaddir(dir_fd: OwnedFd) -> io::Result<(ReadDir, RawFd)> { + weak!(fn fdopendir(c_int) -> *mut DIR, "fdopendir$INODE64"); + let ptr = unsafe { fdopendir.get().unwrap()(dir_fd.as_raw_fd()) }; + if ptr.is_null() { + return Err(io::Error::last_os_error()); + } + let dirp = Dir(ptr); + // file descriptor is automatically closed by libc::closedir() now, so give up ownership + let new_parent_fd = dir_fd.into_raw_fd(); + // a valid root is not needed because we do not call any functions involving the full path + // of the DirEntrys. + let dummy_root = PathBuf::new(); + Ok(( + ReadDir { + inner: Arc::new(InnerReadDir { dirp, root: dummy_root }), + end_of_stream: false, + }, + new_parent_fd, + )) + } + + fn remove_dir_all_recursive(parent_fd: Option, p: &Path) -> io::Result<()> { + weak!(fn unlinkat(c_int, *const c_char, c_int) -> c_int); + + let pcstr = cstr(p)?; + + // entry is expected to be a directory, open as such + let fd = openat_nofollow_dironly(parent_fd, &pcstr)?; + + // open the directory passing ownership of the fd + let (dir, fd) = fdreaddir(fd)?; + for child in dir { + let child = child?; + match child.entry.d_type { + libc::DT_DIR => { + remove_dir_all_recursive(Some(fd), Path::new(&child.file_name()))?; + } + libc::DT_UNKNOWN => { + match cvt(unsafe { unlinkat.get().unwrap()(fd, child.name_cstr().as_ptr(), 0) }) + { + // type unknown - try to unlink + Err(err) if err.raw_os_error() == Some(libc::EPERM) => { + // if the file is a directory unlink fails with EPERM + remove_dir_all_recursive(Some(fd), Path::new(&child.file_name()))?; + } + result => { + result?; + } + } + } + _ => { + // not a directory -> unlink + cvt(unsafe { unlinkat.get().unwrap()(fd, child.name_cstr().as_ptr(), 0) })?; + } + } + } + + // unlink the directory after removing its contents + cvt(unsafe { + unlinkat.get().unwrap()( + parent_fd.unwrap_or(libc::AT_FDCWD), + pcstr.as_ptr(), + libc::AT_REMOVEDIR, + ) + })?; + Ok(()) + } + + fn remove_dir_all_modern(p: &Path) -> io::Result<()> { + // We cannot just call remove_dir_all_recursive() here because that would not delete a passed + // symlink. No need to worry about races, because remove_dir_all_recursive() does not recurse + // into symlinks. + let attr = lstat(p)?; + if attr.file_type().is_symlink() { + crate::fs::remove_file(p) + } else { + remove_dir_all_recursive(None, p) + } + } + + pub fn remove_dir_all(p: &Path) -> io::Result<()> { + weak!(fn openat(c_int, *const c_char, c_int) -> c_int); + if openat.get().is_some() { + // openat() is available with macOS 10.10+, just like unlinkat() and fdopendir() + remove_dir_all_modern(p) + } else { + // fall back to classic implementation + crate::sys_common::fs::remove_dir_all(p) + } + } +} + +// Modern implementation using openat(), unlinkat() and fdopendir() +#[cfg(not(any(all(target_os = "macos", target_arch = "x86_64"), target_os = "redox")))] +mod remove_dir_impl { + use super::{cstr, lstat, Dir, DirEntry, InnerReadDir, ReadDir}; + use crate::ffi::CStr; + use crate::io; + use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd}; + use crate::os::unix::prelude::{OwnedFd, RawFd}; + use crate::path::{Path, PathBuf}; + use crate::sync::Arc; + use crate::sys::{cvt, cvt_r}; + use libc::{fdopendir, openat, unlinkat}; + + pub fn openat_nofollow_dironly(parent_fd: Option, p: &CStr) -> io::Result { + let fd = cvt_r(|| unsafe { + openat( + parent_fd.unwrap_or(libc::AT_FDCWD), + p.as_ptr(), + libc::O_CLOEXEC | libc::O_RDONLY | libc::O_NOFOLLOW | libc::O_DIRECTORY, + ) + })?; + Ok(unsafe { OwnedFd::from_raw_fd(fd) }) + } + + fn fdreaddir(dir_fd: OwnedFd) -> io::Result<(ReadDir, RawFd)> { + let ptr = unsafe { fdopendir(dir_fd.as_raw_fd()) }; + if ptr.is_null() { + return Err(io::Error::last_os_error()); + } + let dirp = Dir(ptr); + // file descriptor is automatically closed by libc::closedir() now, so give up ownership + let new_parent_fd = dir_fd.into_raw_fd(); + // a valid root is not needed because we do not call any functions involving the full path + // of the DirEntrys. + let dummy_root = PathBuf::new(); + Ok(( + ReadDir { + inner: Arc::new(InnerReadDir { dirp, root: dummy_root }), + #[cfg(not(any( + target_os = "solaris", + target_os = "illumos", + target_os = "fuchsia", + target_os = "redox", + )))] + end_of_stream: false, + }, + new_parent_fd, + )) + } + + #[cfg(any( + target_os = "solaris", + target_os = "illumos", + target_os = "haiku", + target_os = "vxworks" + ))] + fn is_dir(_ent: &DirEntry) -> Option { + None + } + + #[cfg(not(any( + target_os = "solaris", + target_os = "illumos", + target_os = "haiku", + target_os = "vxworks" + )))] + fn is_dir(ent: &DirEntry) -> Option { + match ent.entry.d_type { + libc::DT_UNKNOWN => None, + libc::DT_DIR => Some(true), + _ => Some(false), + } + } + + fn remove_dir_all_recursive(parent_fd: Option, p: &Path) -> io::Result<()> { + let pcstr = cstr(p)?; + + // entry is expected to be a directory, open as such + let fd = openat_nofollow_dironly(parent_fd, &pcstr)?; + + // open the directory passing ownership of the fd + let (dir, fd) = fdreaddir(fd)?; + for child in dir { + let child = child?; + match is_dir(&child) { + Some(true) => { + remove_dir_all_recursive(Some(fd), Path::new(&child.file_name()))?; + } + Some(false) => { + cvt(unsafe { unlinkat(fd, child.name_cstr().as_ptr(), 0) })?; + } + None => match cvt(unsafe { unlinkat(fd, child.name_cstr().as_ptr(), 0) }) { + // type unknown - try to unlink + Err(err) + if err.raw_os_error() == Some(libc::EISDIR) + || err.raw_os_error() == Some(libc::EPERM) => + { + // if the file is a directory unlink fails with EISDIR on Linux and EPERM everyhwere else + remove_dir_all_recursive(Some(fd), Path::new(&child.file_name()))?; + } + result => { + result?; + } + }, + } + } + + // unlink the directory after removing its contents + cvt(unsafe { + unlinkat(parent_fd.unwrap_or(libc::AT_FDCWD), pcstr.as_ptr(), libc::AT_REMOVEDIR) + })?; + Ok(()) + } + + pub fn remove_dir_all(p: &Path) -> io::Result<()> { + // We cannot just call remove_dir_all_recursive() here because that would not delete a passed + // symlink. No need to worry about races, because remove_dir_all_recursive() does not recurse + // into symlinks. + let attr = lstat(p)?; + if attr.file_type().is_symlink() { + crate::fs::remove_file(p) + } else { + remove_dir_all_recursive(None, p) + } + } +} diff --git a/library/std/src/sys/unix/weak.rs b/library/std/src/sys/unix/weak.rs index 55719b87c7e06..da63c068384a2 100644 --- a/library/std/src/sys/unix/weak.rs +++ b/library/std/src/sys/unix/weak.rs @@ -73,12 +73,14 @@ impl ExternWeak { pub(crate) macro dlsym { (fn $name:ident($($t:ty),*) -> $ret:ty) => ( + dlsym!(fn $name($($t),*) -> $ret, stringify!($name)); + ), + (fn $name:ident($($t:ty),*) -> $ret:ty, $sym:expr) => ( static DLSYM: DlsymWeak $ret> = - DlsymWeak::new(concat!(stringify!($name), '\0')); + DlsymWeak::new(concat!($sym, '\0')); let $name = &DLSYM; ) } - pub(crate) struct DlsymWeak { name: &'static str, addr: AtomicUsize, From cb748a27d28df86cfe036709dc8092896abde31a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 4 Jan 2022 08:44:15 -0800 Subject: [PATCH 19/27] Fix CVE-2022-21658 for WASI --- library/std/src/sys/wasi/fs.rs | 71 ++++++++++++++++++++++++++++++---- 1 file changed, 63 insertions(+), 8 deletions(-) diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs index 1a3da3746ac61..5924789d12ba4 100644 --- a/library/std/src/sys/wasi/fs.rs +++ b/library/std/src/sys/wasi/fs.rs @@ -16,7 +16,7 @@ use crate::sys::time::SystemTime; use crate::sys::unsupported; use crate::sys_common::{AsInner, FromInner, IntoInner}; -pub use crate::sys_common::fs::{remove_dir_all, try_exists}; +pub use crate::sys_common::fs::try_exists; pub struct File { fd: WasiFd, @@ -130,6 +130,18 @@ impl FileType { } } +impl ReadDir { + fn new(dir: File, root: PathBuf) -> ReadDir { + ReadDir { + cookie: Some(0), + buf: vec![0; 128], + offset: 0, + cap: 0, + inner: Arc::new(ReadDirInner { dir, root }), + } + } +} + impl fmt::Debug for ReadDir { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ReadDir").finish_non_exhaustive() @@ -516,13 +528,7 @@ pub fn readdir(p: &Path) -> io::Result { opts.directory(true); opts.read(true); let dir = File::open(p, &opts)?; - Ok(ReadDir { - cookie: Some(0), - buf: vec![0; 128], - offset: 0, - cap: 0, - inner: Arc::new(ReadDirInner { dir, root: p.to_path_buf() }), - }) + Ok(ReadDir::new(dir, p.to_path_buf())) } pub fn unlink(p: &Path) -> io::Result<()> { @@ -716,3 +722,52 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { io::copy(&mut reader, &mut writer) } + +pub fn remove_dir_all(path: &Path) -> io::Result<()> { + let (parent, path) = open_parent(path)?; + remove_dir_all_recursive(&parent, &path) +} + +fn remove_dir_all_recursive(parent: &WasiFd, path: &Path) -> io::Result<()> { + // Open up a file descriptor for the directory itself. Note that we don't + // follow symlinks here and we specifically open directories. + // + // At the root invocation of this function this will correctly handle + // symlinks passed to the top-level `remove_dir_all`. At the recursive + // level this will double-check that after the `readdir` call deduced this + // was a directory it's still a directory by the time we open it up. + // + // If the opened file was actually a symlink then the symlink is deleted, + // not the directory recursively. + let mut opts = OpenOptions::new(); + opts.lookup_flags(0); + opts.directory(true); + opts.read(true); + let fd = open_at(parent, path, &opts)?; + if fd.file_attr()?.file_type().is_symlink() { + return parent.unlink_file(osstr2str(path.as_ref())?); + } + + // this "root" is only used by `DirEntry::path` which we don't use below so + // it's ok for this to be a bogus value + let dummy_root = PathBuf::new(); + + // Iterate over all the entries in this directory, and travel recursively if + // necessary + for entry in ReadDir::new(fd, dummy_root) { + let entry = entry?; + let path = crate::str::from_utf8(&entry.name).map_err(|_| { + io::Error::new_const(io::ErrorKind::Uncategorized, &"invalid utf-8 file name found") + })?; + + if entry.file_type()?.is_dir() { + remove_dir_all_recursive(&entry.inner.dir.fd, path.as_ref())?; + } else { + entry.inner.dir.fd.unlink_file(path)?; + } + } + + // Once all this directory's contents are deleted it should be safe to + // delete the directory tiself. + parent.remove_directory(osstr2str(path.as_ref())?) +} From 32080ad6d0ecdc50c22d214cb64c07874e5ff3c8 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 19 Jan 2022 13:14:24 +0100 Subject: [PATCH 20/27] Update std::fs::remove_dir_all documentation --- library/std/src/fs.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index a00b5e1232369..c0b0d2389894e 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -2042,13 +2042,17 @@ pub fn remove_dir>(path: P) -> io::Result<()> { /// /// # Platform-specific behavior /// -/// This function currently corresponds to `opendir`, `lstat`, `rm` and `rmdir` functions on Unix -/// and the `FindFirstFile`, `GetFileAttributesEx`, `DeleteFile`, and `RemoveDirectory` functions -/// on Windows. -/// Note that, this [may change in the future][changes]. +/// This function currently corresponds to `openat`, `fdopendir`, `unlinkat` and `lstat` functions +/// on Unix (except for macOS before version 10.10 and REDOX) and the `CreateFileW`, +/// `GetFileInformationByHandleEx`, `SetFileInformationByHandle`, and `NtOpenFile` functions on +/// Windows. Note that, this [may change in the future][changes]. /// /// [changes]: io#platform-specific-behavior /// +/// On macOS before version 10.10 and REDOX this function is not protected against time-of-check to +/// time-of-use (TOCTOU) race conditions, and should not be used in security-sensitive code on +/// those platforms. All other platforms are protected. +/// /// # Errors /// /// See [`fs::remove_file`] and [`fs::remove_dir`]. From 5c96dcf96100d67370e794d3ffd59762dbc102ed Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 10 Oct 2021 19:19:52 +0100 Subject: [PATCH 21/27] Add MaybeUninit::as_bytes --- library/core/src/mem/maybe_uninit.rs | 125 ++++++++++++++++++++++++++- 1 file changed, 124 insertions(+), 1 deletion(-) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 56bdc6beb902d..e38c0412a0afe 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -1,8 +1,9 @@ use crate::any::type_name; use crate::fmt; use crate::intrinsics; -use crate::mem::ManuallyDrop; +use crate::mem::{self, ManuallyDrop}; use crate::ptr; +use crate::slice; /// A wrapper type to construct uninitialized instances of `T`. /// @@ -1160,4 +1161,126 @@ impl MaybeUninit { // SAFETY: Valid elements have just been written into `this` so it is initialized unsafe { MaybeUninit::slice_assume_init_mut(this) } } + + /// Returns the contents of this `MaybeUninit` as a slice of potentially uninitialized bytes. + /// + /// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still + /// contain padding bytes which are left uninitialized. + /// + /// # Examples + /// + /// ``` + /// #![feature(maybe_uninit_as_bytes, maybe_uninit_slice)] + /// use std::mem::MaybeUninit; + /// + /// let val = 0x12345678i32; + /// let uninit = MaybeUninit::new(val); + /// let uninit_bytes = uninit.as_bytes(); + /// let bytes = unsafe { MaybeUninit::slice_assume_init_ref(uninit_bytes) }; + /// assert_eq!(bytes, val.to_ne_bytes()); + /// ``` + #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")] + pub fn as_bytes(&self) -> &[MaybeUninit] { + // SAFETY: MaybeUninit is always valid, even for padding bytes + unsafe { + slice::from_raw_parts(self.as_ptr() as *const MaybeUninit, mem::size_of::()) + } + } + + /// Returns the contents of this `MaybeUninit` as a mutable slice of potentially uninitialized + /// bytes. + /// + /// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still + /// contain padding bytes which are left uninitialized. + /// + /// # Examples + /// + /// ``` + /// #![feature(maybe_uninit_as_bytes)] + /// use std::mem::MaybeUninit; + /// + /// let val = 0x12345678i32; + /// let mut uninit = MaybeUninit::new(val); + /// let uninit_bytes = uninit.as_bytes_mut(); + /// if cfg!(target_endian = "little") { + /// uninit_bytes[0].write(0xcd); + /// } else { + /// uninit_bytes[3].write(0xcd); + /// } + /// let val2 = unsafe { uninit.assume_init() }; + /// assert_eq!(val2, 0x123456cd); + /// ``` + #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")] + pub fn as_bytes_mut(&mut self) -> &mut [MaybeUninit] { + // SAFETY: MaybeUninit is always valid, even for padding bytes + unsafe { + slice::from_raw_parts_mut( + self.as_mut_ptr() as *mut MaybeUninit, + mem::size_of::(), + ) + } + } + + /// Returns the contents of this slice of `MaybeUninit` as a slice of potentially uninitialized + /// bytes. + /// + /// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still + /// contain padding bytes which are left uninitialized. + /// + /// # Examples + /// + /// ``` + /// #![feature(maybe_uninit_as_bytes, maybe_uninit_write_slice, maybe_uninit_slice)] + /// use std::mem::MaybeUninit; + /// + /// let uninit = [MaybeUninit::new(0x1234u16), MaybeUninit::new(0x5678u16)]; + /// let uninit_bytes = MaybeUninit::slice_as_bytes(&uninit); + /// let bytes = unsafe { MaybeUninit::slice_assume_init_ref(&uninit_bytes) }; + /// let val1 = u16::from_ne_bytes(bytes[0..2].try_into().unwrap()); + /// let val2 = u16::from_ne_bytes(bytes[2..4].try_into().unwrap()); + /// assert_eq!(&[val1, val2], &[0x1234u16, 0x5678u16]); + /// ``` + #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")] + pub fn slice_as_bytes(this: &[MaybeUninit]) -> &[MaybeUninit] { + // SAFETY: MaybeUninit is always valid, even for padding bytes + unsafe { + slice::from_raw_parts( + this.as_ptr() as *const MaybeUninit, + this.len() * mem::size_of::(), + ) + } + } + + /// Returns the contents of this mutable slice of `MaybeUninit` as a mutable slice of + /// potentially uninitialized bytes. + /// + /// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still + /// contain padding bytes which are left uninitialized. + /// + /// # Examples + /// + /// ``` + /// #![feature(maybe_uninit_as_bytes, maybe_uninit_write_slice, maybe_uninit_slice)] + /// use std::mem::MaybeUninit; + /// + /// let mut uninit = [MaybeUninit::::uninit(), MaybeUninit::::uninit()]; + /// let uninit_bytes = MaybeUninit::slice_as_bytes_mut(&mut uninit); + /// MaybeUninit::write_slice(uninit_bytes, &[0x12, 0x34, 0x56, 0x78]); + /// let vals = unsafe { MaybeUninit::slice_assume_init_ref(&uninit) }; + /// if cfg!(target_endian = "little") { + /// assert_eq!(vals, &[0x3412u16, 0x7856u16]); + /// } else { + /// assert_eq!(vals, &[0x1234u16, 0x5678u16]); + /// } + /// ``` + #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")] + pub fn slice_as_bytes_mut(this: &mut [MaybeUninit]) -> &mut [MaybeUninit] { + // SAFETY: MaybeUninit is always valid, even for padding bytes + unsafe { + slice::from_raw_parts_mut( + this.as_mut_ptr() as *mut MaybeUninit, + this.len() * mem::size_of::(), + ) + } + } } From 64878458841d00882d1673a0b4579b4babaab91f Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Tue, 21 Dec 2021 22:08:47 +0000 Subject: [PATCH 22/27] Properly account for binders in get_impl_future_output_ty --- .../src/infer/error_reporting/mod.rs | 29 ++++++++++++------- compiler/rustc_typeck/src/check/expr.rs | 2 +- .../src/check/fn_ctxt/suggestions.rs | 18 +++++++----- .../rustc_typeck/src/check/method/suggest.rs | 2 +- 4 files changed, 31 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index e98b9c3b03c5a..75472faeebafa 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -69,7 +69,7 @@ use rustc_middle::ty::error::TypeError; use rustc_middle::ty::{ self, subst::{GenericArgKind, Subst, SubstsRef}, - Region, Ty, TyCtxt, TypeFoldable, + Binder, Region, Ty, TyCtxt, TypeFoldable, }; use rustc_span::{sym, BytePos, DesugaringKind, MultiSpan, Pos, Span}; use rustc_target::spec::abi; @@ -1765,7 +1765,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.note_error_origin(diag, cause, exp_found, terr); } - pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option> { + pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option>> { if let ty::Opaque(def_id, substs) = ty.kind() { let future_trait = self.tcx.require_lang_item(LangItem::Future, None); // Future::Output @@ -1775,13 +1775,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { for (predicate, _) in bounds { let predicate = predicate.subst(self.tcx, substs); - if let ty::PredicateKind::Projection(projection_predicate) = - predicate.kind().skip_binder() - { - if projection_predicate.projection_ty.item_def_id == item_def_id { - // We don't account for multiple `Future::Output = Ty` contraints. - return projection_predicate.term.ty(); - } + let output = predicate + .kind() + .map_bound(|kind| match kind { + ty::PredicateKind::Projection(projection_predicate) + if projection_predicate.projection_ty.item_def_id == item_def_id => + { + projection_predicate.term.ty() + } + _ => None, + }) + .transpose(); + if output.is_some() { + // We don't account for multiple `Future::Output = Ty` contraints. + return output; } } } @@ -1823,8 +1830,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } match ( - self.get_impl_future_output_ty(exp_found.expected), - self.get_impl_future_output_ty(exp_found.found), + self.get_impl_future_output_ty(exp_found.expected).map(Binder::skip_binder), + self.get_impl_future_output_ty(exp_found.found).map(Binder::skip_binder), ) { (Some(exp), Some(found)) if same_type_modulo_infer(exp, found) => match cause.code() { ObligationCauseCode::IfExpression(box IfExpressionCause { then, .. }) => { diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 3e73cc659ec46..f6abeff60cd94 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -1909,7 +1909,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => return, }; let mut add_label = true; - if let ty::Adt(def, _) = output_ty.kind() { + if let ty::Adt(def, _) = output_ty.skip_binder().kind() { // no field access on enum type if !def.is_enum() { if def diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index 473c848ad8f13..be4c9ec99b9c6 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -609,14 +609,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = self.tcx.erase_late_bound_regions(Binder::bind_with_vars(ty, bound_vars)); let ty = self.normalize_associated_types_in(expr.span, ty); let ty = match self.tcx.asyncness(fn_id.owner) { - hir::IsAsync::Async => self.tcx.infer_ctxt().enter(|infcx| { - infcx.get_impl_future_output_ty(ty).unwrap_or_else(|| { - span_bug!( - fn_decl.output.span(), - "failed to get output type of async function" - ) + hir::IsAsync::Async => self + .tcx + .infer_ctxt() + .enter(|infcx| { + infcx.get_impl_future_output_ty(ty).unwrap_or_else(|| { + span_bug!( + fn_decl.output.span(), + "failed to get output type of async function" + ) + }) }) - }), + .skip_binder(), hir::IsAsync::NotAsync => ty, }; if self.can_coerce(found, ty) { diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 56f4d5afe400d..96ab800afaffe 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -1274,7 +1274,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, ) { let output_ty = match self.infcx.get_impl_future_output_ty(ty) { - Some(output_ty) => self.resolve_vars_if_possible(output_ty), + Some(output_ty) => self.resolve_vars_if_possible(output_ty).skip_binder(), _ => return, }; let method_exists = self.method_exists(item_name, output_ty, call.hir_id, true); From 5c15ad7fca5140362fe459d7c72661ea59a66b10 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Sat, 20 Nov 2021 02:48:29 +0000 Subject: [PATCH 23/27] NiceRegionError: Use written return type for async fn --- compiler/rustc_hir/src/hir.rs | 15 ++++- .../src/infer/error_reporting/mod.rs | 2 +- .../nice_region_error/different_lifetimes.rs | 1 + .../nice_region_error/find_anon_type.rs | 19 ++----- .../error_reporting/nice_region_error/util.rs | 37 ++++++++---- src/test/ui/async-await/issue-76547.stderr | 14 ++--- .../async-await/issues/issue-63388-1.stderr | 2 +- ...f_types_pin_lifetime_mismatch-async.stderr | 24 ++++---- .../ui/self/elision/lt-ref-self-async.stderr | 48 ++++++++-------- .../ui/self/elision/ref-mut-self-async.stderr | 48 ++++++++-------- .../self/elision/ref-mut-struct-async.stderr | 40 ++++++------- .../ui/self/elision/ref-self-async.stderr | 56 +++++++++---------- .../ui/self/elision/ref-struct-async.stderr | 40 ++++++------- 13 files changed, 181 insertions(+), 165 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 43aa0ae265a09..a9dbdd483fe6f 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2726,6 +2726,10 @@ pub struct FnHeader { } impl FnHeader { + pub fn is_async(&self) -> bool { + matches!(&self.asyncness, IsAsync::Async) + } + pub fn is_const(&self) -> bool { matches!(&self.constness, Constness::Const) } @@ -3169,7 +3173,7 @@ impl<'hir> Node<'hir> { } } - pub fn fn_decl(&self) -> Option<&FnDecl<'hir>> { + pub fn fn_decl(&self) -> Option<&'hir FnDecl<'hir>> { match self { Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig, _), .. }) | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. }) @@ -3181,6 +3185,15 @@ impl<'hir> Node<'hir> { } } + pub fn fn_sig(&self) -> Option<&'hir FnSig<'hir>> { + match self { + Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig, _), .. }) + | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. }) + | Node::Item(Item { kind: ItemKind::Fn(fn_sig, _, _), .. }) => Some(fn_sig), + _ => None, + } + } + pub fn body_id(&self) -> Option { match self { Node::TraitItem(TraitItem { diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 75472faeebafa..14ab635a2ae2b 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -65,9 +65,9 @@ use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_hir::{Item, ItemKind, Node}; use rustc_middle::dep_graph::DepContext; -use rustc_middle::ty::error::TypeError; use rustc_middle::ty::{ self, + error::TypeError, subst::{GenericArgKind, Subst, SubstsRef}, Binder, Region, Ty, TyCtxt, TypeFoldable, }; diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs index ac57796763fb3..5d33d2b4f9b06 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs @@ -171,6 +171,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { self.suggest_adding_lifetime_params(sub, ty_sup, ty_sub, &mut err); + // TODO: This is only helpful if the lifetime more visible in the impl Future type than in the signature. if let Some(t) = future_return_type { let snip = self .tcx() diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs index 07bba00056630..b1535701bb399 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs @@ -1,6 +1,5 @@ use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::Node; use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_lifetime as rl; @@ -25,25 +24,19 @@ pub(crate) fn find_anon_type<'tcx>( tcx: TyCtxt<'tcx>, region: Region<'tcx>, br: &ty::BoundRegionKind, -) -> Option<(&'tcx hir::Ty<'tcx>, &'tcx hir::FnDecl<'tcx>)> { +) -> Option<(&'tcx hir::Ty<'tcx>, &'tcx hir::FnSig<'tcx>)> { if let Some(anon_reg) = tcx.is_suitable_region(region) { let hir_id = tcx.hir().local_def_id_to_hir_id(anon_reg.def_id); - let fndecl = match tcx.hir().get(hir_id) { - Node::Item(&hir::Item { kind: hir::ItemKind::Fn(ref m, ..), .. }) - | Node::TraitItem(&hir::TraitItem { - kind: hir::TraitItemKind::Fn(ref m, ..), .. - }) - | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(ref m, ..), .. }) => { - &m.decl - } - _ => return None, + let Some(fn_sig) = tcx.hir().get(hir_id).fn_sig() else { + return None }; - fndecl + fn_sig + .decl .inputs .iter() .find_map(|arg| find_component_for_bound_region(tcx, arg, br)) - .map(|ty| (ty, &**fndecl)) + .map(|ty| (ty, fn_sig)) } else { None } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs index 3fa71d1a3d817..3e87f97f496b8 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs @@ -4,7 +4,7 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; -use rustc_middle::ty::{self, DefIdTree, Region, Ty}; +use rustc_middle::ty::{self, Binder, DefIdTree, Region, Ty, TypeFoldable}; use rustc_span::Span; /// Information about the anonymous region we are searching for. @@ -149,26 +149,41 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } // Here, we check for the case where the anonymous region - // is in the return type. + // is in the return type as written by the user. // FIXME(#42703) - Need to handle certain cases here. pub(super) fn is_return_type_anon( &self, scope_def_id: LocalDefId, br: ty::BoundRegionKind, - decl: &hir::FnDecl<'_>, + hir_sig: &hir::FnSig<'_>, ) -> Option { - let ret_ty = self.tcx().type_of(scope_def_id); - if let ty::FnDef(_, _) = ret_ty.kind() { - let sig = ret_ty.fn_sig(self.tcx()); - let late_bound_regions = - self.tcx().collect_referenced_late_bound_regions(&sig.output()); - if late_bound_regions.iter().any(|r| *r == br) { - return Some(decl.output.span()); - } + let fn_ty = self.tcx().type_of(scope_def_id); + if let ty::FnDef(_, _) = fn_ty.kind() { + let ret_ty = fn_ty.fn_sig(self.tcx()).output(); + let span = hir_sig.decl.output.span(); + let future_output = if hir_sig.header.is_async() { + ret_ty.map_bound(|ty| self.infcx.get_impl_future_output_ty(ty)).transpose() + } else { + None + }; + return match future_output { + Some(output) if self.includes_region(output, br) => Some(span), + None if self.includes_region(ret_ty, br) => Some(span), + _ => None, + }; } None } + fn includes_region( + &self, + ty: Binder<'tcx, impl TypeFoldable<'tcx>>, + region: ty::BoundRegionKind, + ) -> bool { + let late_bound_regions = self.tcx().collect_referenced_late_bound_regions(&ty); + late_bound_regions.iter().any(|r| *r == region) + } + // Here we check for the case where anonymous region // corresponds to self and if yes, we display E0312. // FIXME(#42700) - Need to format self properly to diff --git a/src/test/ui/async-await/issue-76547.stderr b/src/test/ui/async-await/issue-76547.stderr index 9bfb0f28028cb..ac5f99970c814 100644 --- a/src/test/ui/async-await/issue-76547.stderr +++ b/src/test/ui/async-await/issue-76547.stderr @@ -2,23 +2,17 @@ error[E0623]: lifetime mismatch --> $DIR/issue-76547.rs:20:13 | LL | async fn fut(bufs: &mut [&mut [u8]]) { - | --------- - - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | ---------------- these two types are declared with different lifetimes... LL | ListFut(bufs).await - | ^^^^ ...but data from `bufs` is held across an await point here + | ^^^^ ...but data from `bufs` flows into `bufs` here error[E0623]: lifetime mismatch --> $DIR/issue-76547.rs:34:14 | LL | async fn fut2(bufs: &mut [&mut [u8]]) -> i32 { - | --------- --- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | ---------------- these two types are declared with different lifetimes... LL | ListFut2(bufs).await - | ^^^^ ...but data from `bufs` is held across an await point here + | ^^^^ ...but data from `bufs` flows into `bufs` here error: aborting due to 2 previous errors diff --git a/src/test/ui/async-await/issues/issue-63388-1.stderr b/src/test/ui/async-await/issues/issue-63388-1.stderr index ac29cca9d3f60..32ca7afd82d8b 100644 --- a/src/test/ui/async-await/issues/issue-63388-1.stderr +++ b/src/test/ui/async-await/issues/issue-63388-1.stderr @@ -2,7 +2,7 @@ error[E0623]: lifetime mismatch --> $DIR/issue-63388-1.rs:14:9 | LL | &'a self, foo: &dyn Foo - | -------- this parameter and the returned future are declared with different lifetimes... + | -------- this parameter and the returned future are declared with different lifetimes... LL | ) -> &dyn Foo | -------- | | diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr index e6846fb40494f..6986cd1a5fdac 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr @@ -2,28 +2,28 @@ error[E0623]: lifetime mismatch --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:8:52 | LL | async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f } - | ---- ---- ^ ...but data from `f` is held across an await point here - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | ---- ---- ^ ...but data from `f` is held across an await point here + | | | + | | this `async fn` implicitly returns an `impl Future` + | this parameter and the returned future are declared with different lifetimes... error[E0623]: lifetime mismatch --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:11:82 | LL | async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) } - | ----- ----------------- ^ ...but data from `f` is held across an await point here - | | | - | | this `async fn` implicitly returns an `impl Future, &Foo)>` - | this parameter and the returned future are declared with different lifetimes... + | ---- ----------------- ^ ...but data from `f` is held across an await point here + | | | + | | this `async fn` implicitly returns an `impl Future, &Foo)>` + | this parameter and the returned future are declared with different lifetimes... error[E0623]: lifetime mismatch --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:17:64 | LL | async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg } - | ----- --- ^^^ ...but data from `arg` is held across an await point here - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | ------ --- ^^^ ...but data from `arg` is held across an await point here + | | | + | | this `async fn` implicitly returns an `impl Future` + | this parameter and the returned future are declared with different lifetimes... error: aborting due to 3 previous errors diff --git a/src/test/ui/self/elision/lt-ref-self-async.stderr b/src/test/ui/self/elision/lt-ref-self-async.stderr index 3221d27085096..d65a6ade03733 100644 --- a/src/test/ui/self/elision/lt-ref-self-async.stderr +++ b/src/test/ui/self/elision/lt-ref-self-async.stderr @@ -2,10 +2,10 @@ error[E0623]: lifetime mismatch --> $DIR/lt-ref-self-async.rs:13:9 | LL | async fn ref_self(&self, f: &u32) -> &u32 { - | ----- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | ---- ---- + | | | + | | this `async fn` implicitly returns an `impl Future` + | this parameter and the returned future are declared with different lifetimes... LL | f | ^ ...but data from `f` is held across an await point here @@ -13,10 +13,10 @@ error[E0623]: lifetime mismatch --> $DIR/lt-ref-self-async.rs:19:9 | LL | async fn ref_Self(self: &Self, f: &u32) -> &u32 { - | ----- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | ---- ---- + | | | + | | this `async fn` implicitly returns an `impl Future` + | this parameter and the returned future are declared with different lifetimes... LL | f | ^ ...but data from `f` is held across an await point here @@ -24,10 +24,10 @@ error[E0623]: lifetime mismatch --> $DIR/lt-ref-self-async.rs:23:9 | LL | async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 { - | ----- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | ---- ---- + | | | + | | this `async fn` implicitly returns an `impl Future` + | this parameter and the returned future are declared with different lifetimes... LL | f | ^ ...but data from `f` is held across an await point here @@ -35,10 +35,10 @@ error[E0623]: lifetime mismatch --> $DIR/lt-ref-self-async.rs:27:9 | LL | async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 { - | ----- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | ---- ---- + | | | + | | this `async fn` implicitly returns an `impl Future` + | this parameter and the returned future are declared with different lifetimes... LL | f | ^ ...but data from `f` is held across an await point here @@ -46,10 +46,10 @@ error[E0623]: lifetime mismatch --> $DIR/lt-ref-self-async.rs:31:9 | LL | async fn box_box_ref_Self(self: Box>, f: &u32) -> &u32 { - | ----- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | ---- ---- + | | | + | | this `async fn` implicitly returns an `impl Future` + | this parameter and the returned future are declared with different lifetimes... LL | f | ^ ...but data from `f` is held across an await point here @@ -57,10 +57,10 @@ error[E0623]: lifetime mismatch --> $DIR/lt-ref-self-async.rs:35:9 | LL | async fn box_pin_Self(self: Box>, f: &u32) -> &u32 { - | ----- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | ---- ---- + | | | + | | this `async fn` implicitly returns an `impl Future` + | this parameter and the returned future are declared with different lifetimes... LL | f | ^ ...but data from `f` is held across an await point here diff --git a/src/test/ui/self/elision/ref-mut-self-async.stderr b/src/test/ui/self/elision/ref-mut-self-async.stderr index b6ca986923d2e..c4f7b7eb625ea 100644 --- a/src/test/ui/self/elision/ref-mut-self-async.stderr +++ b/src/test/ui/self/elision/ref-mut-self-async.stderr @@ -2,10 +2,10 @@ error[E0623]: lifetime mismatch --> $DIR/ref-mut-self-async.rs:13:9 | LL | async fn ref_self(&mut self, f: &u32) -> &u32 { - | --------- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | ---- ---- + | | | + | | this `async fn` implicitly returns an `impl Future` + | this parameter and the returned future are declared with different lifetimes... LL | f | ^ ...but data from `f` is held across an await point here @@ -13,10 +13,10 @@ error[E0623]: lifetime mismatch --> $DIR/ref-mut-self-async.rs:19:9 | LL | async fn ref_Self(self: &mut Self, f: &u32) -> &u32 { - | --------- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | ---- ---- + | | | + | | this `async fn` implicitly returns an `impl Future` + | this parameter and the returned future are declared with different lifetimes... LL | f | ^ ...but data from `f` is held across an await point here @@ -24,10 +24,10 @@ error[E0623]: lifetime mismatch --> $DIR/ref-mut-self-async.rs:23:9 | LL | async fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 { - | --------- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | ---- ---- + | | | + | | this `async fn` implicitly returns an `impl Future` + | this parameter and the returned future are declared with different lifetimes... LL | f | ^ ...but data from `f` is held across an await point here @@ -35,10 +35,10 @@ error[E0623]: lifetime mismatch --> $DIR/ref-mut-self-async.rs:27:9 | LL | async fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 { - | --------- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | ---- ---- + | | | + | | this `async fn` implicitly returns an `impl Future` + | this parameter and the returned future are declared with different lifetimes... LL | f | ^ ...but data from `f` is held across an await point here @@ -46,10 +46,10 @@ error[E0623]: lifetime mismatch --> $DIR/ref-mut-self-async.rs:31:9 | LL | async fn box_box_ref_Self(self: Box>, f: &u32) -> &u32 { - | --------- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | ---- ---- + | | | + | | this `async fn` implicitly returns an `impl Future` + | this parameter and the returned future are declared with different lifetimes... LL | f | ^ ...but data from `f` is held across an await point here @@ -57,10 +57,10 @@ error[E0623]: lifetime mismatch --> $DIR/ref-mut-self-async.rs:35:9 | LL | async fn box_pin_ref_Self(self: Box>, f: &u32) -> &u32 { - | --------- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | ---- ---- + | | | + | | this `async fn` implicitly returns an `impl Future` + | this parameter and the returned future are declared with different lifetimes... LL | f | ^ ...but data from `f` is held across an await point here diff --git a/src/test/ui/self/elision/ref-mut-struct-async.stderr b/src/test/ui/self/elision/ref-mut-struct-async.stderr index eda15d76390b6..6c5edcb2b366e 100644 --- a/src/test/ui/self/elision/ref-mut-struct-async.stderr +++ b/src/test/ui/self/elision/ref-mut-struct-async.stderr @@ -2,10 +2,10 @@ error[E0623]: lifetime mismatch --> $DIR/ref-mut-struct-async.rs:13:9 | LL | async fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 { - | ----------- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | ---- ---- + | | | + | | this `async fn` implicitly returns an `impl Future` + | this parameter and the returned future are declared with different lifetimes... LL | f | ^ ...but data from `f` is held across an await point here @@ -13,10 +13,10 @@ error[E0623]: lifetime mismatch --> $DIR/ref-mut-struct-async.rs:17:9 | LL | async fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 { - | ----------- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | ---- ---- + | | | + | | this `async fn` implicitly returns an `impl Future` + | this parameter and the returned future are declared with different lifetimes... LL | f | ^ ...but data from `f` is held across an await point here @@ -24,10 +24,10 @@ error[E0623]: lifetime mismatch --> $DIR/ref-mut-struct-async.rs:21:9 | LL | async fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 { - | ----------- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | ---- ---- + | | | + | | this `async fn` implicitly returns an `impl Future` + | this parameter and the returned future are declared with different lifetimes... LL | f | ^ ...but data from `f` is held across an await point here @@ -35,10 +35,10 @@ error[E0623]: lifetime mismatch --> $DIR/ref-mut-struct-async.rs:25:9 | LL | async fn box_box_ref_Struct(self: Box>, f: &u32) -> &u32 { - | ----------- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | ---- ---- + | | | + | | this `async fn` implicitly returns an `impl Future` + | this parameter and the returned future are declared with different lifetimes... LL | f | ^ ...but data from `f` is held across an await point here @@ -46,10 +46,10 @@ error[E0623]: lifetime mismatch --> $DIR/ref-mut-struct-async.rs:29:9 | LL | async fn box_pin_ref_Struct(self: Box>, f: &u32) -> &u32 { - | ----------- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | ---- ---- + | | | + | | this `async fn` implicitly returns an `impl Future` + | this parameter and the returned future are declared with different lifetimes... LL | f | ^ ...but data from `f` is held across an await point here diff --git a/src/test/ui/self/elision/ref-self-async.stderr b/src/test/ui/self/elision/ref-self-async.stderr index b42caa88c6fef..fef346b4d2a6e 100644 --- a/src/test/ui/self/elision/ref-self-async.stderr +++ b/src/test/ui/self/elision/ref-self-async.stderr @@ -2,10 +2,10 @@ error[E0623]: lifetime mismatch --> $DIR/ref-self-async.rs:23:9 | LL | async fn ref_self(&self, f: &u32) -> &u32 { - | ----- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | ---- ---- + | | | + | | this `async fn` implicitly returns an `impl Future` + | this parameter and the returned future are declared with different lifetimes... LL | f | ^ ...but data from `f` is held across an await point here @@ -13,10 +13,10 @@ error[E0623]: lifetime mismatch --> $DIR/ref-self-async.rs:29:9 | LL | async fn ref_Self(self: &Self, f: &u32) -> &u32 { - | ----- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | ---- ---- + | | | + | | this `async fn` implicitly returns an `impl Future` + | this parameter and the returned future are declared with different lifetimes... LL | f | ^ ...but data from `f` is held across an await point here @@ -24,10 +24,10 @@ error[E0623]: lifetime mismatch --> $DIR/ref-self-async.rs:33:9 | LL | async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 { - | ----- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | ---- ---- + | | | + | | this `async fn` implicitly returns an `impl Future` + | this parameter and the returned future are declared with different lifetimes... LL | f | ^ ...but data from `f` is held across an await point here @@ -35,10 +35,10 @@ error[E0623]: lifetime mismatch --> $DIR/ref-self-async.rs:37:9 | LL | async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 { - | ----- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | ---- ---- + | | | + | | this `async fn` implicitly returns an `impl Future` + | this parameter and the returned future are declared with different lifetimes... LL | f | ^ ...but data from `f` is held across an await point here @@ -46,10 +46,10 @@ error[E0623]: lifetime mismatch --> $DIR/ref-self-async.rs:41:9 | LL | async fn box_box_ref_Self(self: Box>, f: &u32) -> &u32 { - | ----- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | ---- ---- + | | | + | | this `async fn` implicitly returns an `impl Future` + | this parameter and the returned future are declared with different lifetimes... LL | f | ^ ...but data from `f` is held across an await point here @@ -57,10 +57,10 @@ error[E0623]: lifetime mismatch --> $DIR/ref-self-async.rs:45:9 | LL | async fn box_pin_ref_Self(self: Box>, f: &u32) -> &u32 { - | ----- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | ---- ---- + | | | + | | this `async fn` implicitly returns an `impl Future` + | this parameter and the returned future are declared with different lifetimes... LL | f | ^ ...but data from `f` is held across an await point here @@ -68,10 +68,10 @@ error[E0623]: lifetime mismatch --> $DIR/ref-self-async.rs:49:9 | LL | async fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 { - | ----- --- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | --- --- + | | | + | | this `async fn` implicitly returns an `impl Future` + | this parameter and the returned future are declared with different lifetimes... LL | f | ^ ...but data from `f` is held across an await point here diff --git a/src/test/ui/self/elision/ref-struct-async.stderr b/src/test/ui/self/elision/ref-struct-async.stderr index 599becd308062..cc269c0e7aad5 100644 --- a/src/test/ui/self/elision/ref-struct-async.stderr +++ b/src/test/ui/self/elision/ref-struct-async.stderr @@ -2,10 +2,10 @@ error[E0623]: lifetime mismatch --> $DIR/ref-struct-async.rs:13:9 | LL | async fn ref_Struct(self: &Struct, f: &u32) -> &u32 { - | ------- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | ---- ---- + | | | + | | this `async fn` implicitly returns an `impl Future` + | this parameter and the returned future are declared with different lifetimes... LL | f | ^ ...but data from `f` is held across an await point here @@ -13,10 +13,10 @@ error[E0623]: lifetime mismatch --> $DIR/ref-struct-async.rs:17:9 | LL | async fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 { - | ------- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | ---- ---- + | | | + | | this `async fn` implicitly returns an `impl Future` + | this parameter and the returned future are declared with different lifetimes... LL | f | ^ ...but data from `f` is held across an await point here @@ -24,10 +24,10 @@ error[E0623]: lifetime mismatch --> $DIR/ref-struct-async.rs:21:9 | LL | async fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 { - | ------- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | ---- ---- + | | | + | | this `async fn` implicitly returns an `impl Future` + | this parameter and the returned future are declared with different lifetimes... LL | f | ^ ...but data from `f` is held across an await point here @@ -35,10 +35,10 @@ error[E0623]: lifetime mismatch --> $DIR/ref-struct-async.rs:25:9 | LL | async fn box_box_ref_Struct(self: Box>, f: &u32) -> &u32 { - | ------- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | ---- ---- + | | | + | | this `async fn` implicitly returns an `impl Future` + | this parameter and the returned future are declared with different lifetimes... LL | f | ^ ...but data from `f` is held across an await point here @@ -46,10 +46,10 @@ error[E0623]: lifetime mismatch --> $DIR/ref-struct-async.rs:29:9 | LL | async fn box_pin_Struct(self: Box>, f: &u32) -> &u32 { - | ------- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | ---- ---- + | | | + | | this `async fn` implicitly returns an `impl Future` + | this parameter and the returned future are declared with different lifetimes... LL | f | ^ ...but data from `f` is held across an await point here From 698631e16c390c29bacc778e35aba1dc27bed57f Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Fri, 10 Dec 2021 00:01:05 +0000 Subject: [PATCH 24/27] Simplify error reporting code, remove await point wording --- .../nice_region_error/different_lifetimes.rs | 110 ++++++------------ .../error_reporting/nice_region_error/util.rs | 54 --------- .../async-await/issues/issue-63388-1.stderr | 6 +- .../ret-impl-trait-one.stderr | 5 +- ...f_types_pin_lifetime_mismatch-async.stderr | 21 ++-- .../ui/self/elision/lt-ref-self-async.stderr | 42 +++---- .../ui/self/elision/ref-mut-self-async.stderr | 42 +++---- .../self/elision/ref-mut-struct-async.stderr | 35 +++--- .../ui/self/elision/ref-self-async.stderr | 49 ++++---- .../ui/self/elision/ref-struct-async.stderr | 35 +++--- 10 files changed, 133 insertions(+), 266 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs index 5d33d2b4f9b06..4eec492b3aeb9 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs @@ -106,91 +106,47 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { None => String::new(), }; - let (span_1, span_2, main_label, span_label, future_return_type) = - match (sup_is_ret_type, sub_is_ret_type) { - (None, None) => { - let (main_label_1, span_label_1) = if ty_sup.hir_id == ty_sub.hir_id { - ( - "this type is declared with multiple lifetimes...".to_owned(), - "...but data with one lifetime flows into the other here".to_owned(), - ) - } else { - ( - "these two types are declared with different lifetimes...".to_owned(), - format!("...but data{} flows{} here", span_label_var1, span_label_var2), - ) - }; - (ty_sup.span, ty_sub.span, main_label_1, span_label_1, None) - } + debug!( + "try_report_anon_anon_conflict: sub_is_ret_type={:?} sup_is_ret_type={:?}", + sub_is_ret_type, sup_is_ret_type + ); - (Some(ret_span), _) => { - let sup_future = self.future_return_type(scope_def_id_sup); - let (return_type, action) = if sup_future.is_some() { - ("returned future", "held across an await point") - } else { - ("return type", "returned") - }; + let mut err = struct_span_err!(self.tcx().sess, span, E0623, "lifetime mismatch"); - ( - ty_sub.span, - ret_span, - format!( - "this parameter and the {} are declared with different lifetimes...", - return_type - ), - format!("...but data{} is {} here", span_label_var1, action), - sup_future, - ) - } - (_, Some(ret_span)) => { - let sub_future = self.future_return_type(scope_def_id_sub); - let (return_type, action) = if sub_future.is_some() { - ("returned future", "held across an await point") - } else { - ("return type", "returned") - }; + match (sup_is_ret_type, sub_is_ret_type) { + (ret_capture @ Some(ret_span), _) | (_, ret_capture @ Some(ret_span)) => { + let param_span = + if sup_is_ret_type == ret_capture { ty_sub.span } else { ty_sup.span }; + + err.span_label( + param_span, + "this parameter and the return type are declared with different lifetimes...", + ); + err.span_label(ret_span, ""); + err.span_label(span, format!("...but data{} is returned here", span_label_var1)); + } - ( + (None, None) => { + if ty_sup.hir_id == ty_sub.hir_id { + err.span_label(ty_sup.span, "this type is declared with multiple lifetimes..."); + err.span_label(ty_sub.span, ""); + err.span_label(span, "...but data with one lifetime flows into the other here"); + } else { + err.span_label( ty_sup.span, - ret_span, - format!( - "this parameter and the {} are declared with different lifetimes...", - return_type - ), - format!("...but data{} is {} here", span_label_var1, action), - sub_future, - ) + "these two types are declared with different lifetimes...", + ); + err.span_label(ty_sub.span, ""); + err.span_label( + span, + format!("...but data{} flows{} here", span_label_var1, span_label_var2), + ); } - }; - - let mut err = struct_span_err!(self.tcx().sess, span, E0623, "lifetime mismatch"); - - err.span_label(span_1, main_label); - err.span_label(span_2, String::new()); - err.span_label(span, span_label); + } + } self.suggest_adding_lifetime_params(sub, ty_sup, ty_sub, &mut err); - // TODO: This is only helpful if the lifetime more visible in the impl Future type than in the signature. - if let Some(t) = future_return_type { - let snip = self - .tcx() - .sess - .source_map() - .span_to_snippet(t.span) - .ok() - .and_then(|s| match (&t.kind, s.as_str()) { - (rustc_hir::TyKind::Tup(&[]), "") => Some("()".to_string()), - (_, "") => None, - _ => Some(s), - }) - .unwrap_or_else(|| "{unnamed_type}".to_string()); - - err.span_label( - t.span, - &format!("this `async fn` implicitly returns an `impl Future`", snip), - ); - } err.emit(); Some(ErrorReported) } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs index 3e87f97f496b8..6d71d702cc89b 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs @@ -94,60 +94,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { }) } - pub(super) fn future_return_type( - &self, - local_def_id: LocalDefId, - ) -> Option<&rustc_hir::Ty<'_>> { - if let Some(hir::IsAsync::Async) = self.asyncness(local_def_id) { - if let rustc_middle::ty::Opaque(def_id, _) = - self.tcx().type_of(local_def_id).fn_sig(self.tcx()).output().skip_binder().kind() - { - match self.tcx().hir().get_if_local(*def_id) { - Some(hir::Node::Item(hir::Item { - kind: - hir::ItemKind::OpaqueTy(hir::OpaqueTy { - bounds, - origin: hir::OpaqueTyOrigin::AsyncFn(..), - .. - }), - .. - })) => { - for b in bounds.iter() { - if let hir::GenericBound::LangItemTrait( - hir::LangItem::Future, - _span, - _hir_id, - generic_args, - ) = b - { - for type_binding in generic_args.bindings.iter() { - if type_binding.ident.name == rustc_span::sym::Output { - if let hir::TypeBindingKind::Equality { - term: hir::Term::Ty(ty), - } = type_binding.kind - { - return Some(ty); - } - } - } - } - } - } - _ => {} - } - } - } - None - } - - pub(super) fn asyncness(&self, local_def_id: LocalDefId) -> Option { - // similar to the asyncness fn in rustc_ty_utils::ty - let hir_id = self.tcx().hir().local_def_id_to_hir_id(local_def_id); - let node = self.tcx().hir().get(hir_id); - let fn_kind = node.fn_kind()?; - Some(fn_kind.asyncness()) - } - // Here, we check for the case where the anonymous region // is in the return type as written by the user. // FIXME(#42703) - Need to handle certain cases here. diff --git a/src/test/ui/async-await/issues/issue-63388-1.stderr b/src/test/ui/async-await/issues/issue-63388-1.stderr index 32ca7afd82d8b..8f602a1492ad2 100644 --- a/src/test/ui/async-await/issues/issue-63388-1.stderr +++ b/src/test/ui/async-await/issues/issue-63388-1.stderr @@ -2,14 +2,12 @@ error[E0623]: lifetime mismatch --> $DIR/issue-63388-1.rs:14:9 | LL | &'a self, foo: &dyn Foo - | -------- this parameter and the returned future are declared with different lifetimes... + | -------- this parameter and the return type are declared with different lifetimes... LL | ) -> &dyn Foo | -------- - | | - | this `async fn` implicitly returns an `impl Future` LL | { LL | foo - | ^^^ ...but data from `foo` is held across an await point here + | ^^^ ...but data from `foo` is returned here error: aborting due to previous error diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr index 464f283095dad..149692a2c6998 100644 --- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr +++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr @@ -4,9 +4,8 @@ error[E0623]: lifetime mismatch LL | async fn async_ret_impl_trait3<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b { | ------ ^^^^^^^^^^^^^^^^^^^ | | | - | | ...but data from `a` is held across an await point here - | | this `async fn` implicitly returns an `impl Future + 'b>` - | this parameter and the returned future are declared with different lifetimes... + | | ...but data from `a` is returned here + | this parameter and the return type are declared with different lifetimes... error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds --> $DIR/ret-impl-trait-one.rs:16:65 diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr index 6986cd1a5fdac..299a2d2f2d3de 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr @@ -2,28 +2,25 @@ error[E0623]: lifetime mismatch --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:8:52 | LL | async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f } - | ---- ---- ^ ...but data from `f` is held across an await point here - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | ---- ---- ^ ...but data from `f` is returned here + | | + | this parameter and the return type are declared with different lifetimes... error[E0623]: lifetime mismatch --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:11:82 | LL | async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) } - | ---- ----------------- ^ ...but data from `f` is held across an await point here - | | | - | | this `async fn` implicitly returns an `impl Future, &Foo)>` - | this parameter and the returned future are declared with different lifetimes... + | ---- ----------------- ^ ...but data from `f` is returned here + | | + | this parameter and the return type are declared with different lifetimes... error[E0623]: lifetime mismatch --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:17:64 | LL | async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg } - | ------ --- ^^^ ...but data from `arg` is held across an await point here - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | ------ --- ^^^ ...but data from `arg` is returned here + | | + | this parameter and the return type are declared with different lifetimes... error: aborting due to 3 previous errors diff --git a/src/test/ui/self/elision/lt-ref-self-async.stderr b/src/test/ui/self/elision/lt-ref-self-async.stderr index d65a6ade03733..7448e8484b47a 100644 --- a/src/test/ui/self/elision/lt-ref-self-async.stderr +++ b/src/test/ui/self/elision/lt-ref-self-async.stderr @@ -3,66 +3,60 @@ error[E0623]: lifetime mismatch | LL | async fn ref_self(&self, f: &u32) -> &u32 { | ---- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` is held across an await point here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/lt-ref-self-async.rs:19:9 | LL | async fn ref_Self(self: &Self, f: &u32) -> &u32 { | ---- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` is held across an await point here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/lt-ref-self-async.rs:23:9 | LL | async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 { | ---- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` is held across an await point here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/lt-ref-self-async.rs:27:9 | LL | async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 { | ---- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` is held across an await point here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/lt-ref-self-async.rs:31:9 | LL | async fn box_box_ref_Self(self: Box>, f: &u32) -> &u32 { | ---- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` is held across an await point here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/lt-ref-self-async.rs:35:9 | LL | async fn box_pin_Self(self: Box>, f: &u32) -> &u32 { | ---- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` is held across an await point here + | ^ ...but data from `f` is returned here error: aborting due to 6 previous errors diff --git a/src/test/ui/self/elision/ref-mut-self-async.stderr b/src/test/ui/self/elision/ref-mut-self-async.stderr index c4f7b7eb625ea..6056cc46d3d8a 100644 --- a/src/test/ui/self/elision/ref-mut-self-async.stderr +++ b/src/test/ui/self/elision/ref-mut-self-async.stderr @@ -3,66 +3,60 @@ error[E0623]: lifetime mismatch | LL | async fn ref_self(&mut self, f: &u32) -> &u32 { | ---- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` is held across an await point here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-mut-self-async.rs:19:9 | LL | async fn ref_Self(self: &mut Self, f: &u32) -> &u32 { | ---- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` is held across an await point here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-mut-self-async.rs:23:9 | LL | async fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 { | ---- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` is held across an await point here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-mut-self-async.rs:27:9 | LL | async fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 { | ---- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` is held across an await point here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-mut-self-async.rs:31:9 | LL | async fn box_box_ref_Self(self: Box>, f: &u32) -> &u32 { | ---- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` is held across an await point here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-mut-self-async.rs:35:9 | LL | async fn box_pin_ref_Self(self: Box>, f: &u32) -> &u32 { | ---- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` is held across an await point here + | ^ ...but data from `f` is returned here error: aborting due to 6 previous errors diff --git a/src/test/ui/self/elision/ref-mut-struct-async.stderr b/src/test/ui/self/elision/ref-mut-struct-async.stderr index 6c5edcb2b366e..61034ae4d47b6 100644 --- a/src/test/ui/self/elision/ref-mut-struct-async.stderr +++ b/src/test/ui/self/elision/ref-mut-struct-async.stderr @@ -3,55 +3,50 @@ error[E0623]: lifetime mismatch | LL | async fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 { | ---- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` is held across an await point here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-mut-struct-async.rs:17:9 | LL | async fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 { | ---- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` is held across an await point here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-mut-struct-async.rs:21:9 | LL | async fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 { | ---- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` is held across an await point here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-mut-struct-async.rs:25:9 | LL | async fn box_box_ref_Struct(self: Box>, f: &u32) -> &u32 { | ---- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` is held across an await point here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-mut-struct-async.rs:29:9 | LL | async fn box_pin_ref_Struct(self: Box>, f: &u32) -> &u32 { | ---- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` is held across an await point here + | ^ ...but data from `f` is returned here error: aborting due to 5 previous errors diff --git a/src/test/ui/self/elision/ref-self-async.stderr b/src/test/ui/self/elision/ref-self-async.stderr index fef346b4d2a6e..0eab16e685d4c 100644 --- a/src/test/ui/self/elision/ref-self-async.stderr +++ b/src/test/ui/self/elision/ref-self-async.stderr @@ -3,77 +3,70 @@ error[E0623]: lifetime mismatch | LL | async fn ref_self(&self, f: &u32) -> &u32 { | ---- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` is held across an await point here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-self-async.rs:29:9 | LL | async fn ref_Self(self: &Self, f: &u32) -> &u32 { | ---- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` is held across an await point here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-self-async.rs:33:9 | LL | async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 { | ---- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` is held across an await point here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-self-async.rs:37:9 | LL | async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 { | ---- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` is held across an await point here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-self-async.rs:41:9 | LL | async fn box_box_ref_Self(self: Box>, f: &u32) -> &u32 { | ---- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` is held across an await point here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-self-async.rs:45:9 | LL | async fn box_pin_ref_Self(self: Box>, f: &u32) -> &u32 { | ---- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` is held across an await point here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-self-async.rs:49:9 | LL | async fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 { | --- --- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` is held across an await point here + | ^ ...but data from `f` is returned here error: aborting due to 7 previous errors diff --git a/src/test/ui/self/elision/ref-struct-async.stderr b/src/test/ui/self/elision/ref-struct-async.stderr index cc269c0e7aad5..aa1d7453e83e1 100644 --- a/src/test/ui/self/elision/ref-struct-async.stderr +++ b/src/test/ui/self/elision/ref-struct-async.stderr @@ -3,55 +3,50 @@ error[E0623]: lifetime mismatch | LL | async fn ref_Struct(self: &Struct, f: &u32) -> &u32 { | ---- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` is held across an await point here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-struct-async.rs:17:9 | LL | async fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 { | ---- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` is held across an await point here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-struct-async.rs:21:9 | LL | async fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 { | ---- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` is held across an await point here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-struct-async.rs:25:9 | LL | async fn box_box_ref_Struct(self: Box>, f: &u32) -> &u32 { | ---- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` is held across an await point here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-struct-async.rs:29:9 | LL | async fn box_pin_Struct(self: Box>, f: &u32) -> &u32 { | ---- ---- - | | | - | | this `async fn` implicitly returns an `impl Future` - | this parameter and the returned future are declared with different lifetimes... + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` is held across an await point here + | ^ ...but data from `f` is returned here error: aborting due to 5 previous errors From 152e8889052adaaa6c12652486292be34059713c Mon Sep 17 00:00:00 2001 From: Jacob Hoffman-Andrews Date: Thu, 13 Jan 2022 09:54:44 -0800 Subject: [PATCH 25/27] Rustdoc mobile: put out-of-band on its own line Before this, the item name and the stability, source link, and "collapse all docs" would compete for room on a single line, resulting in awkward wrapping behavior on mobile. This gives a separate line for that out-of-band information. It also removes the "copy path" icon on mobile to make a little more room. Also, switch to flex-wrap: wrap, so anytime there's not enough room for `source`, it gets bumped to the next line. --- src/librustdoc/html/static/css/rustdoc.css | 29 ++++++++++++++------ src/test/rustdoc-gui/mobile.goml | 17 ++++++++++++ src/test/rustdoc-gui/toggle-docs-mobile.goml | 12 ++++---- 3 files changed, 43 insertions(+), 15 deletions(-) create mode 100644 src/test/rustdoc-gui/mobile.goml diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 44a9a571fa1f8..d0244351b5973 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -148,11 +148,11 @@ h1.fqn { } .main-heading { display: flex; + flex-wrap: wrap; + justify-content: space-between; + border-bottom: 1px dashed #DDDDDD; + padding-bottom: 6px; margin-bottom: 15px; - - /* workaround to keep flex from breaking below 700 px width due to the float: right on the nav - above the h1 */ - padding-left: 1px; } .main-heading a:hover { text-decoration: underline; @@ -623,11 +623,7 @@ nav.sub { .content .out-of-band { flex-grow: 0; - text-align: right; - margin-left: auto; - margin-right: 0; font-size: 1.15rem; - padding: 0 0 0 12px; font-weight: normal; float: right; } @@ -1748,10 +1744,25 @@ details.rustdoc-toggle[open] > summary.hideme::after { padding-top: 0px; } - .rustdoc { + .rustdoc, + .main-heading { flex-direction: column; } + .content .out-of-band { + text-align: left; + margin-left: initial; + padding: initial; + } + + .content .out-of-band .since::before { + content: "Since "; + } + + #copy-path { + display: none; + } + /* Hide the logo and item name from the sidebar. Those are displayed in the mobile-topbar instead. */ .sidebar .sidebar-logo, diff --git a/src/test/rustdoc-gui/mobile.goml b/src/test/rustdoc-gui/mobile.goml new file mode 100644 index 0000000000000..acde112392521 --- /dev/null +++ b/src/test/rustdoc-gui/mobile.goml @@ -0,0 +1,17 @@ +// Test various properties of the mobile UI +goto: file://|DOC_PATH|/staged_api/struct.Foo.html +size: (400, 600) + +// The out-of-band info (source, stable version, collapse) should be below the +// h1 when the screen gets narrow enough. +assert-css: (".main-heading", { + "display": "flex", + "flex-direction": "column" +}) + +// Note: We can't use assert-text here because the 'Since' is set by CSS and +// is therefore not part of the DOM. +assert-css: (".content .out-of-band .since::before", { "content": "\"Since \"" }) + +size: (1000, 1000) +assert-css-false: (".content .out-of-band .since::before", { "content": "\"Since \"" }) diff --git a/src/test/rustdoc-gui/toggle-docs-mobile.goml b/src/test/rustdoc-gui/toggle-docs-mobile.goml index 4c83fd6c0e31c..e7a75b43c5a02 100644 --- a/src/test/rustdoc-gui/toggle-docs-mobile.goml +++ b/src/test/rustdoc-gui/toggle-docs-mobile.goml @@ -1,12 +1,12 @@ goto: file://|DOC_PATH|/test_docs/struct.Foo.html size: (433, 600) assert-attribute: (".top-doc", {"open": ""}) -click: (4, 250) // This is the position of the top doc comment toggle +click: (4, 270) // This is the position of the top doc comment toggle assert-attribute-false: (".top-doc", {"open": ""}) -click: (4, 250) +click: (4, 270) assert-attribute: (".top-doc", {"open": ""}) // To ensure that the toggle isn't over the text, we check that the toggle isn't clicked. -click: (3, 250) +click: (3, 270) assert-attribute: (".top-doc", {"open": ""}) // Assert the position of the toggle on the top doc block. @@ -22,10 +22,10 @@ assert-position: ( // Now we do the same but with a little bigger width size: (600, 600) assert-attribute: (".top-doc", {"open": ""}) -click: (4, 250) // New Y position since all search elements are back on one line. +click: (4, 270) // New Y position since all search elements are back on one line. assert-attribute-false: (".top-doc", {"open": ""}) -click: (4, 250) +click: (4, 270) assert-attribute: (".top-doc", {"open": ""}) // To ensure that the toggle isn't over the text, we check that the toggle isn't clicked. -click: (3, 250) +click: (3, 270) assert-attribute: (".top-doc", {"open": ""}) From 3b100458c137e2394c0a73f66d37a4ec373d6469 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Thu, 20 Jan 2022 12:14:08 +0200 Subject: [PATCH 26/27] :arrow_up: rust-analyzer --- src/tools/rust-analyzer | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer index 8e9ccbf97a702..9700addc82111 160000 --- a/src/tools/rust-analyzer +++ b/src/tools/rust-analyzer @@ -1 +1 @@ -Subproject commit 8e9ccbf97a70259b6c6576e8fd7d77d28238737e +Subproject commit 9700addc82111200a2150b9a796f62dd8e600ddf From 0a6c9adc4a09d6c34437a57e83adf78b2ad1e7db Mon Sep 17 00:00:00 2001 From: Hans Kratz Date: Thu, 20 Jan 2022 12:43:54 +0100 Subject: [PATCH 27/27] Fix compilation for a few tier 2 targets --- library/std/src/sys/unix/fs.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 16460bee66ff2..f8deda93fe2a7 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -670,12 +670,7 @@ impl DirEntry { fn name_cstr(&self) -> &CStr { unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) } } - #[cfg(any( - target_os = "solaris", - target_os = "illumos", - target_os = "fuchsia", - target_os = "redox" - ))] + #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "fuchsia"))] fn name_cstr(&self) -> &CStr { &self.name } @@ -1631,7 +1626,8 @@ mod remove_dir_impl { target_os = "solaris", target_os = "illumos", target_os = "haiku", - target_os = "vxworks" + target_os = "vxworks", + target_os = "fuchsia" ))] fn is_dir(_ent: &DirEntry) -> Option { None @@ -1641,7 +1637,8 @@ mod remove_dir_impl { target_os = "solaris", target_os = "illumos", target_os = "haiku", - target_os = "vxworks" + target_os = "vxworks", + target_os = "fuchsia" )))] fn is_dir(ent: &DirEntry) -> Option { match ent.entry.d_type {