From fc52b47e8013da325fc0a0f5d3897143243ba206 Mon Sep 17 00:00:00 2001 From: Jamie Cunliffe Date: Tue, 30 Jun 2020 09:57:59 +0100 Subject: [PATCH 01/30] va_args implementation for AAPCS. Implement the va args in codegen for AAPCS, this will be used as the default va_args implementation for AArch64 rather than the va_args llvm-ir as it currently is. Copyright (c) 2020, Arm Limited. --- src/librustc_codegen_llvm/builder.rs | 7 +- src/librustc_codegen_llvm/va_arg.rs | 82 ++++++++++++++++++- .../c-link-to-rust-va-list-fn/checkrust.rs | 55 +++++++++++++ .../c-link-to-rust-va-list-fn/test.c | 10 +++ 4 files changed, 151 insertions(+), 3 deletions(-) diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs index ba285b5ef38d1..01c2ab32d6ada 100644 --- a/src/librustc_codegen_llvm/builder.rs +++ b/src/librustc_codegen_llvm/builder.rs @@ -1279,7 +1279,12 @@ impl Builder<'a, 'll, 'tcx> { self.call(lifetime_intrinsic, &[self.cx.const_u64(size), ptr], None); } - fn phi(&mut self, ty: &'ll Type, vals: &[&'ll Value], bbs: &[&'ll BasicBlock]) -> &'ll Value { + pub(crate) fn phi( + &mut self, + ty: &'ll Type, + vals: &[&'ll Value], + bbs: &[&'ll BasicBlock], + ) -> &'ll Value { assert_eq!(vals.len(), bbs.len()); let phi = unsafe { llvm::LLVMBuildPhi(self.llbuilder, ty, UNNAMED) }; unsafe { diff --git a/src/librustc_codegen_llvm/va_arg.rs b/src/librustc_codegen_llvm/va_arg.rs index 8bc3579800ea8..8c0d256df2357 100644 --- a/src/librustc_codegen_llvm/va_arg.rs +++ b/src/librustc_codegen_llvm/va_arg.rs @@ -3,8 +3,9 @@ use crate::type_::Type; use crate::type_of::LayoutLlvmExt; use crate::value::Value; use rustc_codegen_ssa::mir::operand::OperandRef; -use rustc_codegen_ssa::traits::{ - BaseTypeMethods, BuilderMethods, ConstMethods, DerivedTypeMethods, +use rustc_codegen_ssa::{ + common::IntPredicate, + traits::{BaseTypeMethods, BuilderMethods, ConstMethods, DerivedTypeMethods}, }; use rustc_middle::ty::layout::HasTyCtxt; use rustc_middle::ty::Ty; @@ -89,6 +90,82 @@ fn emit_ptr_va_arg( } } +fn emit_aapcs_va_arg( + bx: &mut Builder<'a, 'll, 'tcx>, + list: OperandRef<'tcx, &'ll Value>, + target_ty: Ty<'tcx>, +) -> &'ll Value { + // Implementation of the AAPCS64 calling convention for va_args see + // https://github.com/ARM-software/abi-aa/blob/master/aapcs64/aapcs64.rst + let va_list_addr = list.immediate(); + let layout = bx.cx.layout_of(target_ty); + + let mut maybe_reg = bx.build_sibling_block("va_arg.maybe_reg"); + let mut in_reg = bx.build_sibling_block("va_arg.in_reg"); + let mut on_stack = bx.build_sibling_block("va_arg.on_stack"); + let mut end = bx.build_sibling_block("va_arg.end"); + let zero = bx.const_i32(0); + let offset_align = Align::from_bytes(4).unwrap(); + assert!(&*bx.tcx().sess.target.target.target_endian == "little"); + + let gr_type = target_ty.is_any_ptr() || target_ty.is_integral(); + let (reg_off, reg_top_index, slot_size) = if gr_type { + let gr_offs = bx.struct_gep(va_list_addr, 7); + let nreg = (layout.size.bytes() + 7) / 8; + (gr_offs, 3, nreg * 8) + } else { + let vr_off = bx.struct_gep(va_list_addr, 9); + let nreg = (layout.size.bytes() + 15) / 16; + (vr_off, 5, nreg * 16) + }; + + // if the offset >= 0 then the value will be on the stack + let mut reg_off_v = bx.load(reg_off, offset_align); + let use_stack = bx.icmp(IntPredicate::IntSGE, reg_off_v, zero); + bx.cond_br(use_stack, &on_stack.llbb(), &maybe_reg.llbb()); + + // The value at this point might be in a register, but there is a chance that + // it could be on the stack so we have to update the offset and then check + // the offset again. + + if layout.align.abi.bytes() > 8 { + assert!(layout.align.abi.bytes() <= 16); + reg_off_v = maybe_reg.add(reg_off_v, bx.const_i32(15)); + reg_off_v = maybe_reg.and(reg_off_v, bx.const_i32(-16)); + } + let new_reg_off_v = maybe_reg.add(reg_off_v, bx.const_i32(slot_size as i32)); + + maybe_reg.store(new_reg_off_v, reg_off, offset_align); + + // Check to see if we have overflowed the registers as a result of this. + // If we have then we need to use the stack for this value + let use_stack = maybe_reg.icmp(IntPredicate::IntSGT, new_reg_off_v, zero); + maybe_reg.cond_br(use_stack, &on_stack.llbb(), &in_reg.llbb()); + + let top = in_reg.struct_gep(va_list_addr, reg_top_index); + let top = in_reg.load(top, bx.tcx().data_layout.pointer_align.abi); + + // reg_value = *(@top + reg_off_v); + let top = in_reg.gep(top, &[reg_off_v]); + let top = in_reg.bitcast(top, bx.cx.type_ptr_to(layout.llvm_type(bx))); + let reg_value = in_reg.load(top, layout.align.abi); + in_reg.br(&end.llbb()); + + // On Stack block + let stack_value = + emit_ptr_va_arg(&mut on_stack, list, target_ty, false, Align::from_bytes(8).unwrap(), true); + on_stack.br(&end.llbb()); + + let val = end.phi( + layout.immediate_llvm_type(bx), + &[reg_value, stack_value], + &[&in_reg.llbb(), &on_stack.llbb()], + ); + + *bx = end; + val +} + pub(super) fn emit_va_arg( bx: &mut Builder<'a, 'll, 'tcx>, addr: OperandRef<'tcx, &'ll Value>, @@ -115,6 +192,7 @@ pub(super) fn emit_va_arg( ("aarch64", _) if target.target_os == "ios" => { emit_ptr_va_arg(bx, addr, target_ty, false, Align::from_bytes(8).unwrap(), true) } + ("aarch64", _) => emit_aapcs_va_arg(bx, addr, target_ty), // Windows x86_64 ("x86_64", true) => { let target_ty_size = bx.cx.size_of(target_ty).bytes(); diff --git a/src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/checkrust.rs b/src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/checkrust.rs index a0a5b141ec0e1..5830ef033d389 100644 --- a/src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/checkrust.rs +++ b/src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/checkrust.rs @@ -91,3 +91,58 @@ pub unsafe extern "C" fn check_varargs_1(_: c_int, mut ap: ...) -> usize { pub unsafe extern "C" fn check_varargs_2(_: c_int, _ap: ...) -> usize { 0 } + +#[no_mangle] +pub unsafe extern "C" fn check_varargs_3(_: c_int, mut ap: ...) -> usize { + continue_if!(ap.arg::() == 1); + continue_if!(ap.arg::() == 2); + continue_if!(ap.arg::() == 3); + continue_if!(ap.arg::() == 4); + continue_if!(ap.arg::() == 5); + continue_if!(ap.arg::() == 6); + continue_if!(ap.arg::() == 7); + continue_if!(ap.arg::() == 8); + continue_if!(ap.arg::() == 9); + continue_if!(ap.arg::() == 10); + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn check_varargs_4(_: c_double, mut ap: ...) -> usize { + continue_if!(ap.arg::() == 1.0); + continue_if!(ap.arg::() == 2.0); + continue_if!(ap.arg::() == 3.0); + continue_if!(ap.arg::() == 4.0); + continue_if!(ap.arg::() == 5.0); + continue_if!(ap.arg::() == 6.0); + continue_if!(ap.arg::() == 7.0); + continue_if!(ap.arg::() == 8.0); + continue_if!(ap.arg::() == 9.0); + continue_if!(ap.arg::() == 10.0); + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn check_varargs_5(_: c_int, mut ap: ...) -> usize { + continue_if!(ap.arg::() == 1.0); + continue_if!(ap.arg::() == 1); + continue_if!(ap.arg::() == 2.0); + continue_if!(ap.arg::() == 2); + continue_if!(ap.arg::() == 3.0); + continue_if!(ap.arg::() == 3); + continue_if!(ap.arg::() == 4.0); + continue_if!(ap.arg::() == 4); + continue_if!(ap.arg::() == 5); + continue_if!(ap.arg::() == 5.0); + continue_if!(ap.arg::() == 6); + continue_if!(ap.arg::() == 6.0); + continue_if!(ap.arg::() == 7); + continue_if!(ap.arg::() == 7.0); + continue_if!(ap.arg::() == 8); + continue_if!(ap.arg::() == 8.0); + continue_if!(ap.arg::() == 9); + continue_if!(ap.arg::() == 9.0); + continue_if!(ap.arg::() == 10); + continue_if!(ap.arg::() == 10.0); + 0 +} diff --git a/src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/test.c b/src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/test.c index 91b060dce26f4..5bdb51680a656 100644 --- a/src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/test.c +++ b/src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/test.c @@ -11,6 +11,9 @@ extern size_t check_list_copy_0(va_list ap); extern size_t check_varargs_0(int fixed, ...); extern size_t check_varargs_1(int fixed, ...); extern size_t check_varargs_2(int fixed, ...); +extern size_t check_varargs_3(int fixed, ...); +extern size_t check_varargs_4(double fixed, ...); +extern size_t check_varargs_5(int fixed, ...); int test_rust(size_t (*fn)(va_list), ...) { size_t ret = 0; @@ -36,5 +39,12 @@ int main(int argc, char* argv[]) { assert(check_varargs_2(0, "All", "of", "these", "are", "ignored", ".") == 0); + assert(check_varargs_3(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10) == 0); + + assert(check_varargs_4(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0) == 0); + + assert(check_varargs_5(0, 1.0, 1, 2.0, 2, 3.0, 3, 4.0, 4, 5, 5.0, 6, 6.0, 7, 7.0, 8, 8.0, + 9, 9.0, 10, 10.0) == 0); + return 0; } From 31c7aae1136b4d80f0256e269ca8086fd3fbdddd Mon Sep 17 00:00:00 2001 From: Andrew Paverd Date: Tue, 14 Jul 2020 15:27:42 +0100 Subject: [PATCH 02/30] Stabilize control-flow-guard codegen option --- src/bootstrap/builder.rs | 2 +- src/doc/rustc/src/codegen-options/index.md | 12 ++++++++++++ src/librustc_codegen_llvm/context.rs | 2 +- src/librustc_codegen_ssa/back/link.rs | 2 +- src/librustc_interface/tests.rs | 2 +- src/librustc_session/config.rs | 2 +- src/librustc_session/options.rs | 4 ++-- src/test/codegen/cfguard-checks.rs | 2 +- src/test/codegen/cfguard-disabled.rs | 2 +- src/test/codegen/cfguard-nochecks.rs | 2 +- src/test/codegen/cfguard-non-msvc.rs | 2 +- src/test/ui/cfguard-run.rs | 2 +- 12 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 557fb1aa550a5..276e7ac558e31 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -1231,7 +1231,7 @@ impl<'a> Builder<'a> { && self.config.control_flow_guard && compiler.stage >= 1 { - rustflags.arg("-Zcontrol-flow-guard"); + rustflags.arg("-Ccontrol-flow-guard"); } // For `cargo doc` invocations, make rustdoc print the Rust version into the docs diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index 0b4bb05c1db23..35904e15d3fee 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -42,6 +42,18 @@ generated code, but may be slower to compile. The default value, if not specified, is 16 for non-incremental builds. For incremental builds the default is 256 which allows caching to be more granular. +## control-flow-guard + +This flag controls whether LLVM enables the Windows [Control Flow +Guard](https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard) +platform security feature. This flag is currently ignored for non-Windows targets. +It takes one of the following values: + +* `y`, `yes`, `on`, `checks`, or no value: enable Control Flow Guard. +* `nochecks`: emit Control Flow Guard metadata without runtime enforcement checks (this +should only be used for testing purposes as it does not provide security enforcement). +* `n`, `no`, `off`: do not enable Control Flow Guard (the default). + ## debug-assertions This flag lets you turn `cfg(debug_assertions)` [conditional diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs index 21ba97d15a485..a07f6c64edcb1 100644 --- a/src/librustc_codegen_llvm/context.rs +++ b/src/librustc_codegen_llvm/context.rs @@ -190,7 +190,7 @@ pub unsafe fn create_module( // Control Flow Guard is currently only supported by the MSVC linker on Windows. if sess.target.target.options.is_like_msvc { - match sess.opts.debugging_opts.control_flow_guard { + match sess.opts.cg.control_flow_guard { CFGuard::Disabled => {} CFGuard::NoChecks => { // Set `cfguard=1` module flag to emit metadata only. diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs index 3adaa07db91b0..7f3aa4be9fdb6 100644 --- a/src/librustc_codegen_ssa/back/link.rs +++ b/src/librustc_codegen_ssa/back/link.rs @@ -1700,7 +1700,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( } // OBJECT-FILES-NO, AUDIT-ORDER - if sess.opts.debugging_opts.control_flow_guard != CFGuard::Disabled { + if sess.opts.cg.control_flow_guard != CFGuard::Disabled { cmd.control_flow_guard(); } diff --git a/src/librustc_interface/tests.rs b/src/librustc_interface/tests.rs index 651a77912c6d0..dd09ce9e3dddf 100644 --- a/src/librustc_interface/tests.rs +++ b/src/librustc_interface/tests.rs @@ -420,6 +420,7 @@ fn test_codegen_options_tracking_hash() { // Make sure that changing a [TRACKED] option changes the hash. // This list is in alphabetical order. tracked!(code_model, Some(CodeModel::Large)); + tracked!(control_flow_guard, CFGuard::Checks); tracked!(debug_assertions, Some(true)); tracked!(debuginfo, 0xdeadbeef); tracked!(embed_bitcode, false); @@ -537,7 +538,6 @@ fn test_debugging_options_tracking_hash() { tracked!(binary_dep_depinfo, true); tracked!(chalk, true); tracked!(codegen_backend, Some("abc".to_string())); - tracked!(control_flow_guard, CFGuard::Checks); tracked!(crate_attr, vec!["abc".to_string()]); tracked!(debug_macros, true); tracked!(dep_info_omit_d_target, true); diff --git a/src/librustc_session/config.rs b/src/librustc_session/config.rs index c5a866817cb4a..dbf5b7ece08fe 100644 --- a/src/librustc_session/config.rs +++ b/src/librustc_session/config.rs @@ -103,7 +103,7 @@ pub enum Strip { Symbols, } -/// The different settings that the `-Z control-flow-guard` flag can have. +/// The different settings that the `-C control-flow-guard` flag can have. #[derive(Clone, Copy, PartialEq, Hash, Debug)] pub enum CFGuard { /// Do not emit Control Flow Guard metadata or checks. diff --git a/src/librustc_session/options.rs b/src/librustc_session/options.rs index 2ad7d09cbf415..62f6fca97466d 100644 --- a/src/librustc_session/options.rs +++ b/src/librustc_session/options.rs @@ -692,6 +692,8 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options, "choose the code model to use (`rustc --print code-models` for details)"), codegen_units: Option = (None, parse_opt_uint, [UNTRACKED], "divide crate into N units to optimize in parallel"), + control_flow_guard: CFGuard = (CFGuard::Disabled, parse_cfguard, [TRACKED], + "use Windows Control Flow Guard (default: no)"), debug_assertions: Option = (None, parse_opt_bool, [TRACKED], "explicitly enable the `cfg(debug_assertions)` directive"), debuginfo: usize = (0, parse_uint, [TRACKED], @@ -809,8 +811,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "enable the experimental Chalk-based trait solving engine"), codegen_backend: Option = (None, parse_opt_string, [TRACKED], "the backend to use"), - control_flow_guard: CFGuard = (CFGuard::Disabled, parse_cfguard, [TRACKED], - "use Windows Control Flow Guard (default: no)"), crate_attr: Vec = (Vec::new(), parse_string_push, [TRACKED], "inject the given attribute in the crate"), debug_macros: bool = (false, parse_bool, [TRACKED], diff --git a/src/test/codegen/cfguard-checks.rs b/src/test/codegen/cfguard-checks.rs index 96a0a321199a3..571a2654bcbfd 100644 --- a/src/test/codegen/cfguard-checks.rs +++ b/src/test/codegen/cfguard-checks.rs @@ -1,4 +1,4 @@ -// compile-flags: -Z control-flow-guard=checks +// compile-flags: -C control-flow-guard=checks // only-msvc #![crate_type = "lib"] diff --git a/src/test/codegen/cfguard-disabled.rs b/src/test/codegen/cfguard-disabled.rs index 925e4e8e2d155..c3f8f4116819c 100644 --- a/src/test/codegen/cfguard-disabled.rs +++ b/src/test/codegen/cfguard-disabled.rs @@ -1,4 +1,4 @@ -// compile-flags: -Z control-flow-guard=no +// compile-flags: -C control-flow-guard=no // only-msvc #![crate_type = "lib"] diff --git a/src/test/codegen/cfguard-nochecks.rs b/src/test/codegen/cfguard-nochecks.rs index d7dc3d7e89eea..3847c3e81ed7a 100644 --- a/src/test/codegen/cfguard-nochecks.rs +++ b/src/test/codegen/cfguard-nochecks.rs @@ -1,4 +1,4 @@ -// compile-flags: -Z control-flow-guard=nochecks +// compile-flags: -C control-flow-guard=nochecks // only-msvc #![crate_type = "lib"] diff --git a/src/test/codegen/cfguard-non-msvc.rs b/src/test/codegen/cfguard-non-msvc.rs index 4008f0187a0b0..6278a951e35f1 100644 --- a/src/test/codegen/cfguard-non-msvc.rs +++ b/src/test/codegen/cfguard-non-msvc.rs @@ -1,4 +1,4 @@ -// compile-flags: -Z control-flow-guard +// compile-flags: -C control-flow-guard // ignore-msvc #![crate_type = "lib"] diff --git a/src/test/ui/cfguard-run.rs b/src/test/ui/cfguard-run.rs index 21368fad3b058..3c4f9a1f5ee2c 100644 --- a/src/test/ui/cfguard-run.rs +++ b/src/test/ui/cfguard-run.rs @@ -1,5 +1,5 @@ // run-pass -// compile-flags: -Z control-flow-guard +// compile-flags: -C control-flow-guard pub fn main() { println!("hello, world"); From cfa3a330149b78c4d827b10d9ac4ff8d381e7342 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sat, 11 Jul 2020 08:45:26 +0000 Subject: [PATCH 03/30] compiletest: Rewrite extract_lldb_version function This makes extract_lldb_version has the same version type like extract_gdb_version. This is technically a breaking change for rustc-dev users. But note that rustc-dev is a nightly component. --- src/tools/compiletest/src/common.rs | 2 +- src/tools/compiletest/src/header.rs | 23 +++----- src/tools/compiletest/src/main.rs | 90 ++++++++++------------------- src/tools/compiletest/src/tests.rs | 11 ++++ 4 files changed, 50 insertions(+), 76 deletions(-) diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 703b87634cec3..4abb1db35a02f 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -268,7 +268,7 @@ pub struct Config { pub gdb_native_rust: bool, /// Version of LLDB - pub lldb_version: Option, + pub lldb_version: Option, /// Whether LLDB has native rust support pub lldb_native_rust: bool, diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index d6e28e93c9667..0ee11608dc5b3 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -188,16 +188,17 @@ impl EarlyProps { } fn ignore_lldb(config: &Config, line: &str) -> bool { - if let Some(ref actual_version) = config.lldb_version { - if line.starts_with("min-lldb-version") { - let min_version = line - .trim_end() - .rsplit(' ') - .next() - .expect("Malformed lldb version directive"); + if let Some(actual_version) = config.lldb_version { + if let Some(min_version) = line.strip_prefix("min-lldb-version:").map(str::trim) { + let min_version = min_version.parse().unwrap_or_else(|e| { + panic!( + "Unexpected format of LLDB version string: {}\n{:?}", + min_version, e + ); + }); // Ignore if actual version is smaller the minimum required // version - lldb_version_to_int(actual_version) < lldb_version_to_int(min_version) + actual_version < min_version } else if line.starts_with("rust-lldb") && !config.lldb_native_rust { true } else { @@ -944,12 +945,6 @@ impl Config { } } -pub fn lldb_version_to_int(version_string: &str) -> isize { - let error_string = - format!("Encountered LLDB version string with unexpected format: {}", version_string); - version_string.parse().expect(&error_string) -} - fn expand_variables(mut value: String, config: &Config) -> String { const CWD: &'static str = "{{cwd}}"; const SRC_BASE: &'static str = "{{src-base}}"; diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 97272f1a9c1b6..2b0ff0da9f5c5 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -165,8 +165,12 @@ pub fn parse_config(args: Vec) -> Config { let cdb = analyze_cdb(matches.opt_str("cdb"), &target); let (gdb, gdb_version, gdb_native_rust) = analyze_gdb(matches.opt_str("gdb"), &target, &android_cross_path); - let (lldb_version, lldb_native_rust) = extract_lldb_version(matches.opt_str("lldb-version")); - + let (lldb_version, lldb_native_rust) = matches + .opt_str("lldb-version") + .as_deref() + .and_then(extract_lldb_version) + .map(|(v, b)| (Some(v), b)) + .unwrap_or((None, false)); let color = match matches.opt_str("color").as_ref().map(|x| &**x) { Some("auto") | None => ColorConfig::AutoColor, Some("always") => ColorConfig::AlwaysColor, @@ -400,17 +404,14 @@ fn configure_lldb(config: &Config) -> Option { return None; } - if let Some(lldb_version) = config.lldb_version.as_ref() { - if lldb_version == "350" { - println!( - "WARNING: The used version of LLDB ({}) has a \ - known issue that breaks debuginfo tests. See \ - issue #32520 for more information. Skipping all \ - LLDB-based tests!", - lldb_version - ); - return None; - } + if let Some(350) = config.lldb_version { + println!( + "WARNING: The used version of LLDB (350) has a \ + known issue that breaks debuginfo tests. See \ + issue #32520 for more information. Skipping all \ + LLDB-based tests!", + ); + return None; } // Some older versions of LLDB seem to have problems with multiple @@ -908,7 +909,7 @@ fn extract_gdb_version(full_version_line: &str) -> Option { } /// Returns (LLDB version, LLDB is rust-enabled) -fn extract_lldb_version(full_version_line: Option) -> (Option, bool) { +fn extract_lldb_version(full_version_line: &str) -> Option<(u32, bool)> { // Extract the major LLDB version from the given version string. // LLDB version strings are different for Apple and non-Apple platforms. // The Apple variant looks like this: @@ -917,7 +918,7 @@ fn extract_lldb_version(full_version_line: Option) -> (Option, b // lldb-300.2.51 (new versions) // // We are only interested in the major version number, so this function - // will return `Some("179")` and `Some("300")` respectively. + // will return `Some(179)` and `Some(300)` respectively. // // Upstream versions look like: // lldb version 6.0.1 @@ -929,53 +930,20 @@ fn extract_lldb_version(full_version_line: Option) -> (Option, b // normally fine because the only non-Apple version we test is // rust-enabled. - if let Some(ref full_version_line) = full_version_line { - if !full_version_line.trim().is_empty() { - let full_version_line = full_version_line.trim(); - - for (pos, l) in full_version_line.char_indices() { - if l != 'l' && l != 'L' { - continue; - } - if pos + 5 >= full_version_line.len() { - continue; - } - let l = full_version_line[pos + 1..].chars().next().unwrap(); - if l != 'l' && l != 'L' { - continue; - } - let d = full_version_line[pos + 2..].chars().next().unwrap(); - if d != 'd' && d != 'D' { - continue; - } - let b = full_version_line[pos + 3..].chars().next().unwrap(); - if b != 'b' && b != 'B' { - continue; - } - let dash = full_version_line[pos + 4..].chars().next().unwrap(); - if dash != '-' { - continue; - } - - let vers = full_version_line[pos + 5..] - .chars() - .take_while(|c| c.is_digit(10)) - .collect::(); - if !vers.is_empty() { - return (Some(vers), full_version_line.contains("rust-enabled")); - } - } + let full_version_line = full_version_line.trim(); - if full_version_line.starts_with("lldb version ") { - let vers = full_version_line[13..] - .chars() - .take_while(|c| c.is_digit(10)) - .collect::(); - if !vers.is_empty() { - return (Some(vers + "00"), full_version_line.contains("rust-enabled")); - } - } + if let Some(apple_ver) = + full_version_line.strip_prefix("LLDB-").or_else(|| full_version_line.strip_prefix("lldb-")) + { + if let Some(idx) = apple_ver.find(|c: char| !c.is_digit(10)) { + let version: u32 = apple_ver[..idx].parse().unwrap(); + return Some((version, full_version_line.contains("rust-enabled"))); + } + } else if let Some(lldb_ver) = full_version_line.strip_prefix("lldb version ") { + if let Some(idx) = lldb_ver.find(|c: char| !c.is_digit(10)) { + let version: u32 = lldb_ver[..idx].parse().unwrap(); + return Some((version * 100, full_version_line.contains("rust-enabled"))); } } - (None, false) + None } diff --git a/src/tools/compiletest/src/tests.rs b/src/tools/compiletest/src/tests.rs index 31c151d29e916..7669ec53bf72f 100644 --- a/src/tools/compiletest/src/tests.rs +++ b/src/tools/compiletest/src/tests.rs @@ -41,6 +41,17 @@ fn test_extract_gdb_version() { } } +#[test] +fn test_extract_lldb_version() { + // Apple variants + assert_eq!(extract_lldb_version("LLDB-179.5"), Some((179, false))); + assert_eq!(extract_lldb_version("lldb-300.2.51"), Some((300, false))); + + // Upstream versions + assert_eq!(extract_lldb_version("lldb version 6.0.1"), Some((600, false))); + assert_eq!(extract_lldb_version("lldb version 9.0.0"), Some((900, false))); +} + #[test] fn is_test_test() { assert_eq!(true, is_test(&OsString::from("a_test.rs"))); From d778f326c385b2df7053b84fb5e3f89361b5fc3a Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sat, 11 Jul 2020 08:45:26 +0000 Subject: [PATCH 04/30] compiletest: Rewrite extract_gdb_version function --- src/tools/compiletest/src/main.rs | 89 +++++++++--------------------- src/tools/compiletest/src/tests.rs | 2 +- 2 files changed, 28 insertions(+), 63 deletions(-) diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 2b0ff0da9f5c5..80f611d2ad6a4 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -841,71 +841,36 @@ fn extract_gdb_version(full_version_line: &str) -> Option { // This particular form is documented in the GNU coding standards: // https://www.gnu.org/prep/standards/html_node/_002d_002dversion.html#g_t_002d_002dversion - // don't start parsing in the middle of a number - let mut prev_was_digit = false; - let mut in_parens = false; - for (pos, c) in full_version_line.char_indices() { - if in_parens { - if c == ')' { - in_parens = false; - } - continue; - } else if c == '(' { - in_parens = true; - continue; - } - - if prev_was_digit || !c.is_digit(10) { - prev_was_digit = c.is_digit(10); - continue; + let mut splits = full_version_line.rsplit(' '); + let version_string = splits.next().unwrap(); + + let mut splits = version_string.split('.'); + let major = splits.next().unwrap(); + let minor = splits.next().unwrap(); + let patch = splits.next(); + + let major: u32 = major.parse().unwrap(); + let (minor, patch): (u32, u32) = match minor.find(|c: char| !c.is_digit(10)) { + None => { + let minor = minor.parse().unwrap(); + let patch: u32 = match patch { + Some(patch) => match patch.find(|c: char| !c.is_digit(10)) { + None => patch.parse().unwrap(), + Some(idx) if idx > 3 => 0, + Some(idx) => patch[..idx].parse().unwrap(), + }, + None => 0, + }; + (minor, patch) } - - prev_was_digit = true; - - let line = &full_version_line[pos..]; - - let next_split = match line.find(|c: char| !c.is_digit(10)) { - Some(idx) => idx, - None => continue, // no minor version - }; - - if line.as_bytes()[next_split] != b'.' { - continue; // no minor version + // There is no patch version after minor-date (e.g. "4-2012"). + Some(idx) => { + let minor = minor[..idx].parse().unwrap(); + (minor, 0) } + }; - let major = &line[..next_split]; - let line = &line[next_split + 1..]; - - let (minor, patch) = match line.find(|c: char| !c.is_digit(10)) { - Some(idx) => { - if line.as_bytes()[idx] == b'.' { - let patch = &line[idx + 1..]; - - let patch_len = - patch.find(|c: char| !c.is_digit(10)).unwrap_or_else(|| patch.len()); - let patch = &patch[..patch_len]; - let patch = if patch_len > 3 || patch_len == 0 { None } else { Some(patch) }; - - (&line[..idx], patch) - } else { - (&line[..idx], None) - } - } - None => (line, None), - }; - - if minor.is_empty() { - continue; - } - - let major: u32 = major.parse().unwrap(); - let minor: u32 = minor.parse().unwrap(); - let patch: u32 = patch.unwrap_or("0").parse().unwrap(); - - return Some(((major * 1000) + minor) * 1000 + patch); - } - - None + Some(((major * 1000) + minor) * 1000 + patch) } /// Returns (LLDB version, LLDB is rust-enabled) diff --git a/src/tools/compiletest/src/tests.rs b/src/tools/compiletest/src/tests.rs index 7669ec53bf72f..237bb756597a3 100644 --- a/src/tools/compiletest/src/tests.rs +++ b/src/tools/compiletest/src/tests.rs @@ -2,7 +2,7 @@ use super::*; #[test] fn test_extract_gdb_version() { - macro_rules! test { ($($expectation:tt: $input:tt,)*) => {{$( + macro_rules! test { ($($expectation:literal: $input:literal,)*) => {{$( assert_eq!(extract_gdb_version($input), Some($expectation)); )*}}} From 07d56cba8ffd854f1c8b91bb1372130e5abe6169 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sat, 11 Jul 2020 13:48:21 +0000 Subject: [PATCH 05/30] Fix panic as passing wrong format to `extract_gdb_version` --- src/tools/compiletest/src/header.rs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 0ee11608dc5b3..dc561352642b3 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -132,32 +132,29 @@ impl EarlyProps { fn ignore_gdb(config: &Config, line: &str) -> bool { if let Some(actual_version) = config.gdb_version { - if line.starts_with("min-gdb-version") { - let (start_ver, end_ver) = extract_gdb_version_range(line); + if let Some(rest) = line.strip_prefix("min-gdb-version:").map(str::trim) { + let (start_ver, end_ver) = extract_gdb_version_range(rest); if start_ver != end_ver { panic!("Expected single GDB version") } // Ignore if actual version is smaller the minimum required // version - actual_version < start_ver - } else if line.starts_with("ignore-gdb-version") { - let (min_version, max_version) = extract_gdb_version_range(line); + return actual_version < start_ver; + } else if let Some(rest) = line.strip_prefix("ignore-gdb-version:").map(str::trim) { + let (min_version, max_version) = extract_gdb_version_range(rest); if max_version < min_version { panic!("Malformed GDB version range: max < min") } - actual_version >= min_version && actual_version <= max_version - } else { - false + return actual_version >= min_version && actual_version <= max_version; } - } else { - false } + false } - // Takes a directive of the form "ignore-gdb-version [- ]", + // Takes a directive of the form " [- ]", // returns the numeric representation of and as // tuple: ( as u32, as u32) // If the part is omitted, the second component of the tuple From 79d5cbbf867a888000b8bbd47194bc57b343b72a Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sat, 11 Jul 2020 08:45:26 +0000 Subject: [PATCH 06/30] Use Option::as_deref --- src/tools/compiletest/src/main.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 80f611d2ad6a4..3929ce28ab0a6 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -171,7 +171,7 @@ pub fn parse_config(args: Vec) -> Config { .and_then(extract_lldb_version) .map(|(v, b)| (Some(v), b)) .unwrap_or((None, false)); - let color = match matches.opt_str("color").as_ref().map(|x| &**x) { + let color = match matches.opt_str("color").as_deref() { Some("auto") | None => ColorConfig::AutoColor, Some("always") => ColorConfig::AlwaysColor, Some("never") => ColorConfig::NeverColor, @@ -255,7 +255,7 @@ pub fn log_config(config: &Config) { logv(c, format!("stage_id: {}", config.stage_id)); logv(c, format!("mode: {}", config.mode)); logv(c, format!("run_ignored: {}", config.run_ignored)); - logv(c, format!("filter: {}", opt_str(&config.filter.as_ref().map(|re| re.to_owned())))); + logv(c, format!("filter: {}", opt_str(&config.filter))); logv(c, format!("filter_exact: {}", config.filter_exact)); logv( c, @@ -723,9 +723,7 @@ fn make_test_closure( let config = config.clone(); let testpaths = testpaths.clone(); let revision = revision.cloned(); - test::DynTestFn(Box::new(move || { - runtest::run(config, &testpaths, revision.as_ref().map(|s| s.as_str())) - })) + test::DynTestFn(Box::new(move || runtest::run(config, &testpaths, revision.as_deref()))) } /// Returns `true` if the given target is an Android target for the From 75caee076d41eca5163a4094e44ce6d48f6b4f1b Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sat, 11 Jul 2020 09:06:59 +0000 Subject: [PATCH 07/30] Extract closure to function --- src/tools/compiletest/src/main.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 3929ce28ab0a6..049bf44d6fd96 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -848,11 +848,11 @@ fn extract_gdb_version(full_version_line: &str) -> Option { let patch = splits.next(); let major: u32 = major.parse().unwrap(); - let (minor, patch): (u32, u32) = match minor.find(|c: char| !c.is_digit(10)) { + let (minor, patch): (u32, u32) = match minor.find(not_a_digit) { None => { let minor = minor.parse().unwrap(); let patch: u32 = match patch { - Some(patch) => match patch.find(|c: char| !c.is_digit(10)) { + Some(patch) => match patch.find(not_a_digit) { None => patch.parse().unwrap(), Some(idx) if idx > 3 => 0, Some(idx) => patch[..idx].parse().unwrap(), @@ -898,15 +898,19 @@ fn extract_lldb_version(full_version_line: &str) -> Option<(u32, bool)> { if let Some(apple_ver) = full_version_line.strip_prefix("LLDB-").or_else(|| full_version_line.strip_prefix("lldb-")) { - if let Some(idx) = apple_ver.find(|c: char| !c.is_digit(10)) { + if let Some(idx) = apple_ver.find(not_a_digit) { let version: u32 = apple_ver[..idx].parse().unwrap(); return Some((version, full_version_line.contains("rust-enabled"))); } } else if let Some(lldb_ver) = full_version_line.strip_prefix("lldb version ") { - if let Some(idx) = lldb_ver.find(|c: char| !c.is_digit(10)) { + if let Some(idx) = lldb_ver.find(not_a_digit) { let version: u32 = lldb_ver[..idx].parse().unwrap(); return Some((version * 100, full_version_line.contains("rust-enabled"))); } } None } + +fn not_a_digit(c: char) -> bool { + !c.is_digit(10) +} From 5aa33b11fc88d0f81c7b2dc586db1439fcf2b664 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sat, 11 Jul 2020 13:50:46 +0000 Subject: [PATCH 08/30] Use subslice pattern --- src/tools/compiletest/src/header.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index dc561352642b3..e155a9249902f 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -170,14 +170,14 @@ impl EarlyProps { .take(3) // 3 or more = invalid, so take at most 3. .collect::>>(); - match range_components.len() { - 1 => { - let v = range_components[0].unwrap(); + match *range_components { + [v] => { + let v = v.unwrap(); (v, v) } - 2 => { - let v_min = range_components[0].unwrap(); - let v_max = range_components[1].expect(ERROR_MESSAGE); + [min, max] => { + let v_min = min.unwrap(); + let v_max = max.expect(ERROR_MESSAGE); (v_min, v_max) } _ => panic!(ERROR_MESSAGE), From 5e5d8163233df1421925c7351377ade2306742de Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sat, 18 Jul 2020 03:17:30 +0000 Subject: [PATCH 09/30] Add missing : after min-gdb-version --- src/test/debuginfo/function-call.rs | 2 +- src/test/debuginfo/pretty-huge-vec.rs | 2 +- src/test/debuginfo/pretty-std-collections.rs | 2 +- src/test/debuginfo/pretty-std.rs | 2 +- src/test/debuginfo/pretty-uninitialized-vec.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/debuginfo/function-call.rs b/src/test/debuginfo/function-call.rs index 98ad8983a60a0..a5d5942b53953 100644 --- a/src/test/debuginfo/function-call.rs +++ b/src/test/debuginfo/function-call.rs @@ -1,5 +1,5 @@ // This test does not passed with gdb < 8.0. See #53497. -// min-gdb-version 8.0 +// min-gdb-version: 8.0 // compile-flags:-g diff --git a/src/test/debuginfo/pretty-huge-vec.rs b/src/test/debuginfo/pretty-huge-vec.rs index 2616c9465246e..cbd2278f7e27c 100644 --- a/src/test/debuginfo/pretty-huge-vec.rs +++ b/src/test/debuginfo/pretty-huge-vec.rs @@ -2,7 +2,7 @@ // ignore-freebsd: gdb package too new // ignore-android: FIXME(#10381) // compile-flags:-g -// min-gdb-version 8.1 +// min-gdb-version: 8.1 // min-lldb-version: 310 // === GDB TESTS =================================================================================== diff --git a/src/test/debuginfo/pretty-std-collections.rs b/src/test/debuginfo/pretty-std-collections.rs index 4e95a028e0749..a4fbff5725c97 100644 --- a/src/test/debuginfo/pretty-std-collections.rs +++ b/src/test/debuginfo/pretty-std-collections.rs @@ -6,7 +6,7 @@ // The pretty printers being tested here require the patch from // https://sourceware.org/bugzilla/show_bug.cgi?id=21763 -// min-gdb-version 8.1 +// min-gdb-version: 8.1 // min-lldb-version: 310 diff --git a/src/test/debuginfo/pretty-std.rs b/src/test/debuginfo/pretty-std.rs index 57721ce103c39..7ae82d522b09d 100644 --- a/src/test/debuginfo/pretty-std.rs +++ b/src/test/debuginfo/pretty-std.rs @@ -2,7 +2,7 @@ // only-cdb // "Temporarily" ignored on GDB/LLDB due to debuginfo tests being disabled, see PR 47155 // ignore-android: FIXME(#10381) // compile-flags:-g -// min-gdb-version 7.7 +// min-gdb-version: 7.7 // min-lldb-version: 310 // === GDB TESTS =================================================================================== diff --git a/src/test/debuginfo/pretty-uninitialized-vec.rs b/src/test/debuginfo/pretty-uninitialized-vec.rs index 7ce004681e100..61791f48f4db7 100644 --- a/src/test/debuginfo/pretty-uninitialized-vec.rs +++ b/src/test/debuginfo/pretty-uninitialized-vec.rs @@ -2,7 +2,7 @@ // ignore-freebsd: gdb package too new // ignore-android: FIXME(#10381) // compile-flags:-g -// min-gdb-version 8.1 +// min-gdb-version: 8.1 // min-lldb-version: 310 // === GDB TESTS =================================================================================== From 2bcefa8d81fdf46f8ad9d893d271788477ccf95b Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sun, 19 Jul 2020 10:45:31 +0000 Subject: [PATCH 10/30] Add missing : after *llvm-version --- src/test/codegen/abi-efiapi.rs | 2 +- src/test/codegen/force-unwind-tables.rs | 2 +- src/test/ui/sanitize/new-llvm-pass-manager-thin-lto.rs | 2 +- src/tools/compiletest/src/header/tests.rs | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/test/codegen/abi-efiapi.rs b/src/test/codegen/abi-efiapi.rs index 8aeee5859d0ad..7c61b7809901f 100644 --- a/src/test/codegen/abi-efiapi.rs +++ b/src/test/codegen/abi-efiapi.rs @@ -2,7 +2,7 @@ // revisions:x86_64 i686 arm -// min-llvm-version 9.0 +// min-llvm-version: 9.0 //[x86_64] compile-flags: --target x86_64-unknown-uefi //[i686] compile-flags: --target i686-unknown-linux-musl diff --git a/src/test/codegen/force-unwind-tables.rs b/src/test/codegen/force-unwind-tables.rs index fbaf38d69df7f..eba4a7469f930 100644 --- a/src/test/codegen/force-unwind-tables.rs +++ b/src/test/codegen/force-unwind-tables.rs @@ -1,4 +1,4 @@ -// min-llvm-version 8.0 +// min-llvm-version: 8.0 // compile-flags: -C no-prepopulate-passes -C force-unwind-tables=y #![crate_type="lib"] diff --git a/src/test/ui/sanitize/new-llvm-pass-manager-thin-lto.rs b/src/test/ui/sanitize/new-llvm-pass-manager-thin-lto.rs index 64d6ccf340916..9439df266d59b 100644 --- a/src/test/ui/sanitize/new-llvm-pass-manager-thin-lto.rs +++ b/src/test/ui/sanitize/new-llvm-pass-manager-thin-lto.rs @@ -2,7 +2,7 @@ // being run when compiling with new LLVM pass manager and ThinLTO. // Note: The issue occurred only on non-zero opt-level. // -// min-llvm-version 9.0 +// min-llvm-version: 9.0 // needs-sanitizer-support // needs-sanitizer-address // diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index 72af34d78260b..58f73a4d7e060 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -120,16 +120,16 @@ fn llvm_version() { let mut config = config(); config.llvm_version = Some("8.1.2-rust".to_owned()); - assert!(parse_rs(&config, "// min-llvm-version 9.0").ignore); + assert!(parse_rs(&config, "// min-llvm-version: 9.0").ignore); config.llvm_version = Some("9.0.1-rust-1.43.0-dev".to_owned()); - assert!(parse_rs(&config, "// min-llvm-version 9.2").ignore); + assert!(parse_rs(&config, "// min-llvm-version: 9.2").ignore); config.llvm_version = Some("9.3.1-rust-1.43.0-dev".to_owned()); - assert!(!parse_rs(&config, "// min-llvm-version 9.2").ignore); + assert!(!parse_rs(&config, "// min-llvm-version: 9.2").ignore); config.llvm_version = Some("10.0.0-rust".to_owned()); - assert!(!parse_rs(&config, "// min-llvm-version 9.0").ignore); + assert!(!parse_rs(&config, "// min-llvm-version: 9.0").ignore); } #[test] From 99e3a3cdeaf9d6b42d329254b5d2752833c0c562 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sun, 19 Jul 2020 10:58:06 +0000 Subject: [PATCH 11/30] Extract extract_version_range --- src/tools/compiletest/src/header.rs | 66 +++++++++++++++-------------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index e155a9249902f..3d9c875499136 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -133,7 +133,7 @@ impl EarlyProps { fn ignore_gdb(config: &Config, line: &str) -> bool { if let Some(actual_version) = config.gdb_version { if let Some(rest) = line.strip_prefix("min-gdb-version:").map(str::trim) { - let (start_ver, end_ver) = extract_gdb_version_range(rest); + let (start_ver, end_ver) = extract_version_range(rest, extract_gdb_version); if start_ver != end_ver { panic!("Expected single GDB version") @@ -142,7 +142,8 @@ impl EarlyProps { // version return actual_version < start_ver; } else if let Some(rest) = line.strip_prefix("ignore-gdb-version:").map(str::trim) { - let (min_version, max_version) = extract_gdb_version_range(rest); + let (min_version, max_version) = + extract_version_range(rest, extract_gdb_version); if max_version < min_version { panic!("Malformed GDB version range: max < min") @@ -154,36 +155,6 @@ impl EarlyProps { false } - // Takes a directive of the form " [- ]", - // returns the numeric representation of and as - // tuple: ( as u32, as u32) - // If the part is omitted, the second component of the tuple - // is the same as . - fn extract_gdb_version_range(line: &str) -> (u32, u32) { - const ERROR_MESSAGE: &'static str = "Malformed GDB version directive"; - - let range_components = line - .split(&[' ', '-'][..]) - .filter(|word| !word.is_empty()) - .map(extract_gdb_version) - .skip_while(Option::is_none) - .take(3) // 3 or more = invalid, so take at most 3. - .collect::>>(); - - match *range_components { - [v] => { - let v = v.unwrap(); - (v, v) - } - [min, max] => { - let v_min = min.unwrap(); - let v_max = max.expect(ERROR_MESSAGE); - (v_min, v_max) - } - _ => panic!(ERROR_MESSAGE), - } - } - fn ignore_lldb(config: &Config, line: &str) -> bool { if let Some(actual_version) = config.lldb_version { if let Some(min_version) = line.strip_prefix("min-lldb-version:").map(str::trim) { @@ -982,3 +953,34 @@ fn parse_normalization_string(line: &mut &str) -> Option { *line = &line[end + 1..]; Some(result) } + +// Takes a directive of the form " [- ]", +// returns the numeric representation of and as +// tuple: ( as u32, as u32) +// If the part is omitted, the second component of the tuple +// is the same as . +fn extract_version_range(line: &str, parse: F) -> (u32, u32) +where + F: Fn(&str) -> Option, +{ + let range_components = line + .split(&[' ', '-'][..]) + .filter(|word| !word.is_empty()) + .map(parse) + .skip_while(Option::is_none) + .take(3) // 3 or more = invalid, so take at most 3. + .collect::>>(); + + match *range_components { + [v] => { + let v = v.unwrap(); + (v, v) + } + [min, max] => { + let v_min = min.unwrap(); + let v_max = max.expect("Malformed version directive"); + (v_min, v_max) + } + _ => panic!("Malformed version directive"), + } +} From 60fac34c2048fe5e4fdb5c4516987b948d9f5192 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sun, 19 Jul 2020 11:10:38 +0000 Subject: [PATCH 12/30] Rewrite extract_llvm_version --- src/tools/compiletest/src/common.rs | 2 +- src/tools/compiletest/src/header.rs | 83 +++++++++-------------- src/tools/compiletest/src/header/tests.rs | 8 +-- src/tools/compiletest/src/main.rs | 4 +- src/tools/compiletest/src/tests.rs | 9 +++ 5 files changed, 49 insertions(+), 57 deletions(-) diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 4abb1db35a02f..c1c07e0bc00a0 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -274,7 +274,7 @@ pub struct Config { pub lldb_native_rust: bool, /// Version of LLVM - pub llvm_version: Option, + pub llvm_version: Option, /// Is LLVM a system LLVM pub system_llvm: bool, diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 3d9c875499136..4b5c44bca875b 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -181,48 +181,28 @@ impl EarlyProps { if config.system_llvm && line.starts_with("no-system-llvm") { return true; } - if let Some(ref actual_version) = config.llvm_version { - let actual_version = version_to_int(actual_version); - if line.starts_with("min-llvm-version") { - let min_version = line - .trim_end() - .rsplit(' ') - .next() - .expect("Malformed llvm version directive"); + if let Some(actual_version) = config.llvm_version { + if let Some(rest) = line.strip_prefix("min-llvm-version:").map(str::trim) { + let min_version = extract_llvm_version(rest).unwrap(); // Ignore if actual version is smaller the minimum required // version - actual_version < version_to_int(min_version) - } else if line.starts_with("min-system-llvm-version") { - let min_version = line - .trim_end() - .rsplit(' ') - .next() - .expect("Malformed llvm version directive"); + actual_version < min_version + } else if let Some(rest) = + line.strip_prefix("min-system-llvm-version:").map(str::trim) + { + let min_version = extract_llvm_version(rest).unwrap(); // Ignore if using system LLVM and actual version // is smaller the minimum required version - config.system_llvm && actual_version < version_to_int(min_version) - } else if line.starts_with("ignore-llvm-version") { - // Syntax is: "ignore-llvm-version [- ]" - let range_components = line - .split(' ') - .skip(1) // Skip the directive. - .map(|s| s.trim()) - .filter(|word| !word.is_empty() && word != &"-") - .take(3) // 3 or more = invalid, so take at most 3. - .collect::>(); - match range_components.len() { - 1 => actual_version == version_to_int(range_components[0]), - 2 => { - let v_min = version_to_int(range_components[0]); - let v_max = version_to_int(range_components[1]); - if v_max < v_min { - panic!("Malformed LLVM version range: max < min") - } - // Ignore if version lies inside of range. - actual_version >= v_min && actual_version <= v_max - } - _ => panic!("Malformed LLVM version directive"), + config.system_llvm && actual_version < min_version + } else if let Some(rest) = line.strip_prefix("ignore-llvm-version:").map(str::trim) + { + // Syntax is: "ignore-llvm-version: [- ]" + let (v_min, v_max) = extract_version_range(rest, extract_llvm_version); + if v_max < v_min { + panic!("Malformed LLVM version range: max < min") } + // Ignore if version lies inside of range. + actual_version >= v_min && actual_version <= v_max } else { false } @@ -230,20 +210,6 @@ impl EarlyProps { false } } - - fn version_to_int(version: &str) -> u32 { - let version_without_suffix = version.trim_end_matches("git").split('-').next().unwrap(); - let components: Vec = version_without_suffix - .split('.') - .map(|s| s.parse().expect("Malformed version component")) - .collect(); - match components.len() { - 1 => components[0] * 10000, - 2 => components[0] * 10000 + components[1] * 100, - 3 => components[0] * 10000 + components[1] * 100 + components[2], - _ => panic!("Malformed version"), - } - } } } @@ -954,6 +920,21 @@ fn parse_normalization_string(line: &mut &str) -> Option { Some(result) } +pub fn extract_llvm_version(version: &str) -> Option { + let version_without_suffix = version.trim_end_matches("git").split('-').next().unwrap(); + let components: Vec = version_without_suffix + .split('.') + .map(|s| s.parse().expect("Malformed version component")) + .collect(); + let version = match *components { + [a] => a * 10_000, + [a, b] => a * 10_000 + b * 100, + [a, b, c] => a * 10_000 + b * 100 + c, + _ => panic!("Malformed version"), + }; + Some(version) +} + // Takes a directive of the form " [- ]", // returns the numeric representation of and as // tuple: ( as u32, as u32) diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index 58f73a4d7e060..adcd8691d0f58 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -119,16 +119,16 @@ fn no_system_llvm() { fn llvm_version() { let mut config = config(); - config.llvm_version = Some("8.1.2-rust".to_owned()); + config.llvm_version = Some(80102); assert!(parse_rs(&config, "// min-llvm-version: 9.0").ignore); - config.llvm_version = Some("9.0.1-rust-1.43.0-dev".to_owned()); + config.llvm_version = Some(90001); assert!(parse_rs(&config, "// min-llvm-version: 9.2").ignore); - config.llvm_version = Some("9.3.1-rust-1.43.0-dev".to_owned()); + config.llvm_version = Some(90301); assert!(!parse_rs(&config, "// min-llvm-version: 9.2").ignore); - config.llvm_version = Some("10.0.0-rust".to_owned()); + config.llvm_version = Some(100000); assert!(!parse_rs(&config, "// min-llvm-version: 9.0").ignore); } diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 049bf44d6fd96..0b46aace49944 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -177,6 +177,8 @@ pub fn parse_config(args: Vec) -> Config { Some("never") => ColorConfig::NeverColor, Some(x) => panic!("argument for --color must be auto, always, or never, but found `{}`", x), }; + let llvm_version = + matches.opt_str("llvm-version").as_deref().and_then(header::extract_llvm_version); let src_base = opt_path(matches, "src-base"); let run_ignored = matches.opt_present("ignored"); @@ -217,7 +219,7 @@ pub fn parse_config(args: Vec) -> Config { gdb_native_rust, lldb_version, lldb_native_rust, - llvm_version: matches.opt_str("llvm-version"), + llvm_version, system_llvm: matches.opt_present("system-llvm"), android_cross_path, adb_path: opt_str2(matches.opt_str("adb-path")), diff --git a/src/tools/compiletest/src/tests.rs b/src/tools/compiletest/src/tests.rs index 237bb756597a3..ea9bc1c1a5b7f 100644 --- a/src/tools/compiletest/src/tests.rs +++ b/src/tools/compiletest/src/tests.rs @@ -1,3 +1,4 @@ +use super::header::extract_llvm_version; use super::*; #[test] @@ -60,3 +61,11 @@ fn is_test_test() { assert_eq!(false, is_test(&OsString::from("#a_dog_gif"))); assert_eq!(false, is_test(&OsString::from("~a_temp_file"))); } + +#[test] +fn test_extract_llvm_version() { + assert_eq!(extract_llvm_version("8.1.2-rust"), Some(80102)); + assert_eq!(extract_llvm_version("9.0.1-rust-1.43.0-dev"), Some(90001)); + assert_eq!(extract_llvm_version("9.3.1-rust-1.43.0-dev"), Some(90301)); + assert_eq!(extract_llvm_version("10.0.0-rust"), Some(100000)); +} From 1314d31fb5974e8c32aa8d695a02d37c4ab4bd7e Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sun, 19 Jul 2020 15:08:35 +0000 Subject: [PATCH 13/30] Rewrite extract_version_range --- src/tools/compiletest/src/header.rs | 54 +++++++++++++---------- src/tools/compiletest/src/header/tests.rs | 15 +++++++ 2 files changed, 46 insertions(+), 23 deletions(-) diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 4b5c44bca875b..2ab764eb9207c 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -133,7 +133,10 @@ impl EarlyProps { fn ignore_gdb(config: &Config, line: &str) -> bool { if let Some(actual_version) = config.gdb_version { if let Some(rest) = line.strip_prefix("min-gdb-version:").map(str::trim) { - let (start_ver, end_ver) = extract_version_range(rest, extract_gdb_version); + let (start_ver, end_ver) = extract_version_range(rest, extract_gdb_version) + .unwrap_or_else(|| { + panic!("couldn't parse version range: {:?}", rest); + }); if start_ver != end_ver { panic!("Expected single GDB version") @@ -143,7 +146,9 @@ impl EarlyProps { return actual_version < start_ver; } else if let Some(rest) = line.strip_prefix("ignore-gdb-version:").map(str::trim) { let (min_version, max_version) = - extract_version_range(rest, extract_gdb_version); + extract_version_range(rest, extract_gdb_version).unwrap_or_else(|| { + panic!("couldn't parse version range: {:?}", rest); + }); if max_version < min_version { panic!("Malformed GDB version range: max < min") @@ -197,7 +202,10 @@ impl EarlyProps { } else if let Some(rest) = line.strip_prefix("ignore-llvm-version:").map(str::trim) { // Syntax is: "ignore-llvm-version: [- ]" - let (v_min, v_max) = extract_version_range(rest, extract_llvm_version); + let (v_min, v_max) = extract_version_range(rest, extract_llvm_version) + .unwrap_or_else(|| { + panic!("couldn't parse version range: {:?}", rest); + }); if v_max < v_min { panic!("Malformed LLVM version range: max < min") } @@ -940,28 +948,28 @@ pub fn extract_llvm_version(version: &str) -> Option { // tuple: ( as u32, as u32) // If the part is omitted, the second component of the tuple // is the same as . -fn extract_version_range(line: &str, parse: F) -> (u32, u32) +fn extract_version_range(line: &str, parse: F) -> Option<(u32, u32)> where F: Fn(&str) -> Option, { - let range_components = line - .split(&[' ', '-'][..]) - .filter(|word| !word.is_empty()) - .map(parse) - .skip_while(Option::is_none) - .take(3) // 3 or more = invalid, so take at most 3. - .collect::>>(); - - match *range_components { - [v] => { - let v = v.unwrap(); - (v, v) - } - [min, max] => { - let v_min = min.unwrap(); - let v_max = max.expect("Malformed version directive"); - (v_min, v_max) - } - _ => panic!("Malformed version directive"), + let mut splits = line.splitn(2, "- ").map(str::trim); + let min = splits.next().unwrap(); + if min.ends_with('-') { + return None; + } + + let max = splits.next(); + + if min.is_empty() { + return None; } + + let min = parse(min)?; + let max = match max { + Some(max) if max.is_empty() => return None, + Some(max) => parse(max)?, + _ => min, + }; + + Some((min, max)) } diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index adcd8691d0f58..1f82b137ee6cf 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -220,3 +220,18 @@ fn sanitizers() { assert!(parse_rs(&config, "// needs-sanitizer-memory").ignore); assert!(parse_rs(&config, "// needs-sanitizer-thread").ignore); } + +#[test] +fn test_extract_version_range() { + use super::{extract_llvm_version, extract_version_range}; + + assert_eq!(extract_version_range("1.2.3 - 4.5.6", extract_llvm_version), Some((10203, 40506))); + assert_eq!(extract_version_range("0 - 4.5.6", extract_llvm_version), Some((0, 40506))); + assert_eq!(extract_version_range("1.2.3 -", extract_llvm_version), None); + assert_eq!(extract_version_range("1.2.3 - ", extract_llvm_version), None); + assert_eq!(extract_version_range("- 4.5.6", extract_llvm_version), None); + assert_eq!(extract_version_range("-", extract_llvm_version), None); + assert_eq!(extract_version_range(" - 4.5.6", extract_llvm_version), None); + assert_eq!(extract_version_range(" - 4.5.6", extract_llvm_version), None); + assert_eq!(extract_version_range("0 -", extract_llvm_version), None); +} From 4fb260bb32a2da7d7ea63b759eef77072a95614b Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sat, 4 Jul 2020 18:41:30 +0100 Subject: [PATCH 14/30] Guard against non-monomorphized type_id intrinsic call --- src/librustc_mir/interpret/intrinsics.rs | 12 +++++++++-- src/test/ui/consts/issue-73976.rs | 26 ++++++++++++++++++++++++ src/test/ui/consts/issue-73976.stderr | 14 +++++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/consts/issue-73976.rs create mode 100644 src/test/ui/consts/issue-73976.stderr diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 5836fc9c95a80..29549041d258c 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -12,7 +12,7 @@ use rustc_middle::mir::{ }; use rustc_middle::ty; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{Ty, TyCtxt}; +use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable}; use rustc_span::symbol::{sym, Symbol}; use rustc_target::abi::{Abi, LayoutOf as _, Primitive, Size}; @@ -54,6 +54,9 @@ crate fn eval_nullary_intrinsic<'tcx>( let name = tcx.item_name(def_id); Ok(match name { sym::type_name => { + if tp_ty.needs_subst() { + throw_inval!(TooGeneric); + } let alloc = type_name::alloc_type_name(tcx, tp_ty); ConstValue::Slice { data: alloc, start: 0, end: alloc.len() } } @@ -68,7 +71,12 @@ crate fn eval_nullary_intrinsic<'tcx>( }; ConstValue::from_machine_usize(n, &tcx) } - sym::type_id => ConstValue::from_u64(tcx.type_id_hash(tp_ty)), + sym::type_id => { + if tp_ty.needs_subst() { + throw_inval!(TooGeneric); + } + ConstValue::from_u64(tcx.type_id_hash(tp_ty)) + } sym::variant_count => { if let ty::Adt(ref adt, _) = tp_ty.kind { ConstValue::from_machine_usize(adt.variants.len() as u64, &tcx) diff --git a/src/test/ui/consts/issue-73976.rs b/src/test/ui/consts/issue-73976.rs new file mode 100644 index 0000000000000..ef141791c2cc8 --- /dev/null +++ b/src/test/ui/consts/issue-73976.rs @@ -0,0 +1,26 @@ +// This test is from #73976. We previously did not check if a type is monomorphized +// before calculating its type id, which leads to the bizzare behaviour below that +// TypeId of a generic type does not match itself. +// +// This test case should either run-pass or be rejected at compile time. +// Currently we just disallow this usage and require pattern is monomorphic. + +#![feature(const_type_id)] + +use std::any::TypeId; + +pub struct GetTypeId(T); + +impl GetTypeId { + pub const VALUE: TypeId = TypeId::of::(); +} + +const fn check_type_id() -> bool { + matches!(GetTypeId::::VALUE, GetTypeId::::VALUE) + //~^ ERROR could not evaluate constant pattern + //~| ERROR could not evaluate constant pattern +} + +fn main() { + assert!(check_type_id::()); +} diff --git a/src/test/ui/consts/issue-73976.stderr b/src/test/ui/consts/issue-73976.stderr new file mode 100644 index 0000000000000..dbb7690b849c8 --- /dev/null +++ b/src/test/ui/consts/issue-73976.stderr @@ -0,0 +1,14 @@ +error: could not evaluate constant pattern + --> $DIR/issue-73976.rs:19:37 + | +LL | matches!(GetTypeId::::VALUE, GetTypeId::::VALUE) + | ^^^^^^^^^^^^^^^^^^^^^ + +error: could not evaluate constant pattern + --> $DIR/issue-73976.rs:19:37 + | +LL | matches!(GetTypeId::::VALUE, GetTypeId::::VALUE) + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + From 0ced817ed373cdc83cd2cc9dea75f9dc76436a07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 26 Jun 2020 18:52:00 -0700 Subject: [PATCH 15/30] Detect when `'static` obligation might come from an `impl` Address #71341. --- .../nice_region_error/static_impl_trait.rs | 465 ++++++++++-------- .../cache/project-fn-ret-contravariant.rs | 2 +- ...ject-fn-ret-contravariant.transmute.stderr | 23 +- .../cache/project-fn-ret-invariant.rs | 2 +- .../project-fn-ret-invariant.transmute.stderr | 28 +- .../dyn-trait.stderr | 25 +- .../constant-in-expr-inherent-1.stderr | 25 +- .../ui/regions/regions-addr-of-self.stderr | 28 +- ...mplicit-static-bound-without-suggestion.rs | 14 + ...cit-static-bound-without-suggestion.stderr | 18 + ...dyn-trait-with-implicit-static-bound.fixed | 37 ++ ...on-dyn-trait-with-implicit-static-bound.rs | 37 ++ ...yn-trait-with-implicit-static-bound.stderr | 29 ++ 13 files changed, 431 insertions(+), 302 deletions(-) create mode 100644 src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-without-suggestion.rs create mode 100644 src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-without-suggestion.stderr create mode 100644 src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.fixed create mode 100644 src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.rs create mode 100644 src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs index b6e971feb0e5f..da776f269d510 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -2,227 +2,302 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; -use rustc_errors::{struct_span_err, Applicability, ErrorReported}; -use rustc_hir::{GenericBound, ItemKind, Lifetime, LifetimeName, TyKind}; -use rustc_middle::ty::RegionKind; +use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported}; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def_id::{DefId, LOCAL_CRATE}; +use rustc_hir::{ + GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, Path, PolyTraitRef, TraitRef, + TyKind, +}; +use rustc_middle::ty::{self, RegionKind, Ty, TypeFoldable, TypeVisitor}; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// Print the error message for lifetime errors when the return type is a static impl Trait. pub(super) fn try_report_static_impl_trait(&self) -> Option { debug!("try_report_static_impl_trait(error={:?})", self.error); - if let Some(RegionResolutionError::SubSupConflict( - _, - var_origin, - ref sub_origin, - sub_r, - ref sup_origin, - sup_r, - )) = self.error - { - debug!( - "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})", - var_origin, sub_origin, sub_r, sup_origin, sup_r - ); - let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?; - debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup); - let fn_returns = self.tcx().return_type_impl_or_dyn_traits(anon_reg_sup.def_id); - if fn_returns.is_empty() { - return None; + let tcx = self.tcx(); + let (var_origin, sub_origin, sub_r, sup_origin, sup_r) = match self.error.as_ref()? { + RegionResolutionError::SubSupConflict( + _, + var_origin, + sub_origin, + sub_r, + sup_origin, + sup_r, + ) if **sub_r == RegionKind::ReStatic => { + (var_origin, sub_origin, sub_r, sup_origin, sup_r) } - debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns); - if *sub_r == RegionKind::ReStatic { - let sp = var_origin.span(); - let return_sp = sub_origin.span(); - let param_info = self.find_param_with_region(sup_r, sub_r)?; - let (lifetime_name, lifetime) = if sup_r.has_name() { - (sup_r.to_string(), format!("lifetime `{}`", sup_r)) - } else { - ("'_".to_owned(), "an anonymous lifetime `'_`".to_string()) - }; - let mut err = struct_span_err!( - self.tcx().sess, - sp, - E0759, - "cannot infer an appropriate lifetime" - ); - err.span_label( - param_info.param_ty_span, - &format!("this data with {}...", lifetime), - ); - debug!("try_report_static_impl_trait: param_info={:?}", param_info); + _ => return None, + }; + debug!( + "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})", + var_origin, sub_origin, sub_r, sup_origin, sup_r + ); + let anon_reg_sup = tcx.is_suitable_region(sup_r)?; + debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup); + let sp = var_origin.span(); + let return_sp = sub_origin.span(); + let param = self.find_param_with_region(sup_r, sub_r)?; + let (lifetime_name, lifetime) = if sup_r.has_name() { + (sup_r.to_string(), format!("lifetime `{}`", sup_r)) + } else { + ("'_".to_owned(), "an anonymous lifetime `'_`".to_string()) + }; + let mut err = struct_span_err!(tcx.sess, sp, E0759, "cannot infer an appropriate lifetime"); + err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime)); + debug!("try_report_static_impl_trait: param_info={:?}", param); - // We try to make the output have fewer overlapping spans if possible. - if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span())) - && sup_origin.span() != return_sp - { - // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs` + // We try to make the output have fewer overlapping spans if possible. + if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span())) + && sup_origin.span() != return_sp + { + // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs` - // Customize the spans and labels depending on their relative order so - // that split sentences flow correctly. - if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() { - // Avoid the following: - // - // error: cannot infer an appropriate lifetime - // --> $DIR/must_outlive_least_region_or_bound.rs:18:50 - // | - // LL | fn foo(x: &i32) -> Box { Box::new(x) } - // | ---- ---------^- - // - // and instead show: - // - // error: cannot infer an appropriate lifetime - // --> $DIR/must_outlive_least_region_or_bound.rs:18:50 - // | - // LL | fn foo(x: &i32) -> Box { Box::new(x) } - // | ---- ^ - err.span_label( - sup_origin.span(), - "...is captured here, requiring it to live as long as `'static`", - ); - } else { - err.span_label(sup_origin.span(), "...is captured here..."); - if return_sp < sup_origin.span() { - err.span_note( - return_sp, - "...and is required to live as long as `'static` here", - ); - } else { - err.span_label( - return_sp, - "...and is required to live as long as `'static` here", - ); - } - } + // Customize the spans and labels depending on their relative order so + // that split sentences flow correctly. + if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() { + // Avoid the following: + // + // error: cannot infer an appropriate lifetime + // --> $DIR/must_outlive_least_region_or_bound.rs:18:50 + // | + // LL | fn foo(x: &i32) -> Box { Box::new(x) } + // | ---- ---------^- + // + // and instead show: + // + // error: cannot infer an appropriate lifetime + // --> $DIR/must_outlive_least_region_or_bound.rs:18:50 + // | + // LL | fn foo(x: &i32) -> Box { Box::new(x) } + // | ---- ^ + err.span_label( + sup_origin.span(), + "...is captured here, requiring it to live as long as `'static`", + ); + } else { + err.span_label(sup_origin.span(), "...is captured here..."); + if return_sp < sup_origin.span() { + err.span_note( + return_sp, + "...and is required to live as long as `'static` here", + ); } else { err.span_label( return_sp, - "...is captured and required to live as long as `'static` here", + "...and is required to live as long as `'static` here", ); } + } + } else { + err.span_label( + return_sp, + "...is captured and required to live as long as `'static` here", + ); + } - // FIXME: account for the need of parens in `&(dyn Trait + '_)` - let consider = "consider changing the"; - let declare = "to declare that the"; - let arg = match param_info.param.pat.simple_ident() { - Some(simple_ident) => format!("argument `{}`", simple_ident), - None => "the argument".to_string(), - }; - let explicit = - format!("you can add an explicit `{}` lifetime bound", lifetime_name); - let explicit_static = - format!("explicit `'static` bound to the lifetime of {}", arg); - let captures = format!("captures data from {}", arg); - let add_static_bound = - "alternatively, add an explicit `'static` bound to this reference"; - let plus_lt = format!(" + {}", lifetime_name); - for fn_return in fn_returns { - if fn_return.span.desugaring_kind().is_some() { - // Skip `async` desugaring `impl Future`. - continue; - } - match fn_return.kind { - TyKind::OpaqueDef(item_id, _) => { - let item = self.tcx().hir().item(item_id.id); - let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind { - opaque - } else { - err.emit(); - return Some(ErrorReported); - }; + self.find_impl_on_dyn_trait(&mut err, param.param_ty); - if let Some(span) = opaque - .bounds - .iter() - .filter_map(|arg| match arg { - GenericBound::Outlives(Lifetime { - name: LifetimeName::Static, - span, - .. - }) => Some(*span), - _ => None, - }) - .next() - { - err.span_suggestion_verbose( - span, - &format!("{} `impl Trait`'s {}", consider, explicit_static), - lifetime_name.clone(), - Applicability::MaybeIncorrect, - ); - err.span_suggestion_verbose( - param_info.param_ty_span, - add_static_bound, - param_info.param_ty.to_string(), - Applicability::MaybeIncorrect, - ); - } else if let Some(_) = opaque - .bounds - .iter() - .filter_map(|arg| match arg { - GenericBound::Outlives(Lifetime { name, span, .. }) - if name.ident().to_string() == lifetime_name => - { - Some(*span) - } - _ => None, - }) - .next() + let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id); + debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns); + // FIXME: account for the need of parens in `&(dyn Trait + '_)` + let consider = "consider changing the"; + let declare = "to declare that the"; + let arg = match param.param.pat.simple_ident() { + Some(simple_ident) => format!("argument `{}`", simple_ident), + None => "the argument".to_string(), + }; + let explicit = format!("you can add an explicit `{}` lifetime bound", lifetime_name); + let explicit_static = format!("explicit `'static` bound to the lifetime of {}", arg); + let captures = format!("captures data from {}", arg); + let add_static_bound = "alternatively, add an explicit `'static` bound to this reference"; + let plus_lt = format!(" + {}", lifetime_name); + for fn_return in fn_returns { + if fn_return.span.desugaring_kind().is_some() { + // Skip `async` desugaring `impl Future`. + continue; + } + match fn_return.kind { + TyKind::OpaqueDef(item_id, _) => { + let item = tcx.hir().item(item_id.id); + let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind { + opaque + } else { + err.emit(); + return Some(ErrorReported); + }; + + if let Some(span) = opaque + .bounds + .iter() + .filter_map(|arg| match arg { + GenericBound::Outlives(Lifetime { + name: LifetimeName::Static, + span, + .. + }) => Some(*span), + _ => None, + }) + .next() + { + err.span_suggestion_verbose( + span, + &format!("{} `impl Trait`'s {}", consider, explicit_static), + lifetime_name.clone(), + Applicability::MaybeIncorrect, + ); + err.span_suggestion_verbose( + param.param_ty_span, + add_static_bound, + param.param_ty.to_string(), + Applicability::MaybeIncorrect, + ); + } else if let Some(_) = opaque + .bounds + .iter() + .filter_map(|arg| match arg { + GenericBound::Outlives(Lifetime { name, span, .. }) + if name.ident().to_string() == lifetime_name => { - } else { - err.span_suggestion_verbose( - fn_return.span.shrink_to_hi(), - &format!( - "{declare} `impl Trait` {captures}, {explicit}", - declare = declare, - captures = captures, - explicit = explicit, - ), - plus_lt.clone(), - Applicability::MaybeIncorrect, - ); + Some(*span) } - } - TyKind::TraitObject(_, lt) => match lt.name { - LifetimeName::ImplicitObjectLifetimeDefault => { - err.span_suggestion_verbose( - fn_return.span.shrink_to_hi(), - &format!( - "{declare} trait object {captures}, {explicit}", - declare = declare, - captures = captures, - explicit = explicit, - ), - plus_lt.clone(), - Applicability::MaybeIncorrect, - ); - } - name if name.ident().to_string() != lifetime_name => { - // With this check we avoid suggesting redundant bounds. This - // would happen if there are nested impl/dyn traits and only - // one of them has the bound we'd suggest already there, like - // in `impl Foo + '_`. - err.span_suggestion_verbose( - lt.span, - &format!("{} trait object's {}", consider, explicit_static), - lifetime_name.clone(), - Applicability::MaybeIncorrect, - ); + _ => None, + }) + .next() + { + } else { + err.span_suggestion_verbose( + fn_return.span.shrink_to_hi(), + &format!( + "{declare} `impl Trait` {captures}, {explicit}", + declare = declare, + captures = captures, + explicit = explicit, + ), + plus_lt.clone(), + Applicability::MaybeIncorrect, + ); + } + } + TyKind::TraitObject(_, lt) => match lt.name { + LifetimeName::ImplicitObjectLifetimeDefault => { + err.span_suggestion_verbose( + fn_return.span.shrink_to_hi(), + &format!( + "{declare} trait object {captures}, {explicit}", + declare = declare, + captures = captures, + explicit = explicit, + ), + plus_lt.clone(), + Applicability::MaybeIncorrect, + ); + } + name if name.ident().to_string() != lifetime_name => { + // With this check we avoid suggesting redundant bounds. This + // would happen if there are nested impl/dyn traits and only + // one of them has the bound we'd suggest already there, like + // in `impl Foo + '_`. + err.span_suggestion_verbose( + lt.span, + &format!("{} trait object's {}", consider, explicit_static), + lifetime_name.clone(), + Applicability::MaybeIncorrect, + ); + err.span_suggestion_verbose( + param.param_ty_span, + add_static_bound, + param.param_ty.to_string(), + Applicability::MaybeIncorrect, + ); + } + _ => {} + }, + _ => {} + } + } + err.emit(); + Some(ErrorReported) + } + + /// When we call a method coming from an `impl Foo for dyn Bar`, `dyn Bar` introduces a default + /// `'static` obligation. Find `impl` blocks that are implemented + fn find_impl_on_dyn_trait(&self, err: &mut DiagnosticBuilder<'_>, ty: Ty<'_>) -> bool { + let tcx = self.tcx(); + + // Find the trait object types in the argument. + let mut v = TraitObjectVisitor(vec![]); + v.visit_ty(ty); + debug!("TraitObjectVisitor {:?}", v.0); + + // Find all the `impl`s in the local scope that can be called on the type parameter. + // FIXME: this doesn't find `impl dyn Trait { /**/ }`. + let impl_self_tys = tcx + .all_traits(LOCAL_CRATE) + .iter() + .flat_map(|trait_did| tcx.hir().trait_impls(*trait_did)) + .filter_map(|impl_node| { + let impl_did = tcx.hir().local_def_id(*impl_node); + if let Some(Node::Item(Item { kind: ItemKind::Impl { self_ty, .. }, .. })) = + tcx.hir().get_if_local(impl_did.to_def_id()) + { + Some(self_ty) + } else { + None + } + }); + let mut suggested = false; + for self_ty in impl_self_tys { + if let TyKind::TraitObject( + poly_trait_refs, + Lifetime { name: LifetimeName::ImplicitObjectLifetimeDefault, .. }, + ) = self_ty.kind + { + for p in poly_trait_refs { + if let PolyTraitRef { + trait_ref: + TraitRef { path: Path { res: Res::Def(DefKind::Trait, did), .. }, .. }, + .. + } = p + { + for found_did in &v.0 { + if did == found_did { + // We've found an `impl Foo for dyn Bar {}`. + // FIXME: we should change this so it also works for + // `impl Foo for Box {}`. err.span_suggestion_verbose( - param_info.param_ty_span, - add_static_bound, - param_info.param_ty.to_string(), + self_ty.span.shrink_to_hi(), + "this `impl` introduces an implicit `'static` requirement, \ + consider changing it", + " + '_".to_string(), Applicability::MaybeIncorrect, ); + suggested = true; } - _ => {} - }, - _ => {} + } } } err.emit(); return Some(ErrorReported); } } - None + suggested + } +} + +/// Collect all the trait objects in a type that could have received an implicit `'static` lifetime. +struct TraitObjectVisitor(Vec); + +impl TypeVisitor<'_> for TraitObjectVisitor { + fn visit_ty(&mut self, t: Ty<'_>) -> bool { + match t.kind { + ty::Dynamic(preds, RegionKind::ReStatic) => { + if let Some(def_id) = preds.principal_def_id() { + self.0.push(def_id); + } + false + } + _ => t.super_visit_with(self), + } } } diff --git a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.rs b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.rs index 8c6073e2f7a49..1eeb01ccc846e 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.rs +++ b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.rs @@ -35,7 +35,7 @@ fn baz<'a,'b>(x: &'a u32, y: &'b u32) -> (&'a u32, &'b u32) { #[cfg(transmute)] // one instantiations: BAD fn baz<'a,'b>(x: &'a u32) -> &'static u32 { - bar(foo, x) //[transmute]~ ERROR E0495 + bar(foo, x) //[transmute]~ ERROR E0759 } #[cfg(krisskross)] // two instantiations, mixing and matching: BAD diff --git a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr index 5ea98dcd4a972..36812d3c0441e 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr @@ -1,26 +1,11 @@ -error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements +error[E0759]: cannot infer an appropriate lifetime --> $DIR/project-fn-ret-contravariant.rs:38:8 | -LL | bar(foo, x) - | ^^^ - | -note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 37:8... - --> $DIR/project-fn-ret-contravariant.rs:37:8 - | LL | fn baz<'a,'b>(x: &'a u32) -> &'static u32 { - | ^^ -note: ...so that reference does not outlive borrowed content - --> $DIR/project-fn-ret-contravariant.rs:38:13 - | -LL | bar(foo, x) - | ^ - = note: but, the lifetime must be valid for the static lifetime... -note: ...so that reference does not outlive borrowed content - --> $DIR/project-fn-ret-contravariant.rs:38:4 - | + | ------- this data with lifetime `'a`... LL | bar(foo, x) - | ^^^^^^^^^^^ + | ----^^^---- ...is captured and required to live as long as `'static` here error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. +For more information about this error, try `rustc --explain E0759`. diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.rs b/src/test/ui/associated-types/cache/project-fn-ret-invariant.rs index 0034d796826de..08d864f7836d2 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.rs +++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.rs @@ -46,7 +46,7 @@ fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> { // Cannot instantiate `foo` with any lifetime other than `'a`, // since it is provided as input. - bar(foo, x) //[transmute]~ ERROR E0495 + bar(foo, x) //[transmute]~ ERROR E0759 } #[cfg(krisskross)] // two instantiations, mixing and matching: BAD diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr index ef57f9e0bc480..9cec0780b3ca8 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr @@ -1,30 +1,12 @@ -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements +error[E0759]: cannot infer an appropriate lifetime --> $DIR/project-fn-ret-invariant.rs:49:9 | -LL | bar(foo, x) - | ^^^ - | -note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 45:8... - --> $DIR/project-fn-ret-invariant.rs:45:8 - | LL | fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> { - | ^^ -note: ...so that the expression is assignable - --> $DIR/project-fn-ret-invariant.rs:49:14 - | -LL | bar(foo, x) - | ^ - = note: expected `Type<'_>` - found `Type<'a>` - = note: but, the lifetime must be valid for the static lifetime... -note: ...so that the expression is assignable - --> $DIR/project-fn-ret-invariant.rs:49:5 - | + | -------- this data with lifetime `'a`... +... LL | bar(foo, x) - | ^^^^^^^^^^^ - = note: expected `Type<'static>` - found `Type<'_>` + | ----^^^---- ...is captured and required to live as long as `'static` here error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. +For more information about this error, try `rustc --explain E0759`. diff --git a/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr b/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr index 268008c211129..397cb3750c266 100644 --- a/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr +++ b/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr @@ -1,30 +1,17 @@ -error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements +error[E0759]: cannot infer an appropriate lifetime --> $DIR/dyn-trait.rs:20:16 | -LL | static_val(x); - | ^ - | -note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 19:26... - --> $DIR/dyn-trait.rs:19:26 - | LL | fn with_dyn_debug_static<'a>(x: Box) { - | ^^ -note: ...so that the expression is assignable - --> $DIR/dyn-trait.rs:20:16 - | + | ------------------- this data with lifetime `'a`... LL | static_val(x); - | ^ - = note: expected `std::boxed::Box` - found `std::boxed::Box<(dyn std::fmt::Debug + 'a)>` - = note: but, the lifetime must be valid for the static lifetime... -note: ...so that the types are compatible + | ^ ...is captured here... + | +note: ...and is required to live as long as `'static` here --> $DIR/dyn-trait.rs:20:5 | LL | static_val(x); | ^^^^^^^^^^ - = note: expected `StaticTrait` - found `StaticTrait` error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. +For more information about this error, try `rustc --explain E0759`. diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr index 8421dc1d0c130..f823f69c76f67 100644 --- a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr +++ b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr @@ -1,28 +1,11 @@ -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements +error[E0759]: cannot infer an appropriate lifetime --> $DIR/constant-in-expr-inherent-1.rs:8:5 | -LL | >::C - | ^^^^^^^^^^^^ - | -note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 7:8... - --> $DIR/constant-in-expr-inherent-1.rs:7:8 - | LL | fn foo<'a>(_: &'a u32) -> &'static u32 { - | ^^ -note: ...so that the types are compatible - --> $DIR/constant-in-expr-inherent-1.rs:8:5 - | -LL | >::C - | ^^^^^^^^^^^^ - = note: expected `Foo<'_>` - found `Foo<'a>` - = note: but, the lifetime must be valid for the static lifetime... -note: ...so that reference does not outlive borrowed content - --> $DIR/constant-in-expr-inherent-1.rs:8:5 - | + | ------- this data with lifetime `'a`... LL | >::C - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^ ...is captured and required to live as long as `'static` here error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. +For more information about this error, try `rustc --explain E0759`. diff --git a/src/test/ui/regions/regions-addr-of-self.stderr b/src/test/ui/regions/regions-addr-of-self.stderr index a0b8b6b51e5a1..c15a933379c85 100644 --- a/src/test/ui/regions/regions-addr-of-self.stderr +++ b/src/test/ui/regions/regions-addr-of-self.stderr @@ -1,29 +1,11 @@ -error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements +error[E0759]: cannot infer an appropriate lifetime --> $DIR/regions-addr-of-self.rs:7:37 | +LL | pub fn chase_cat(&mut self) { + | --------- this data with an anonymous lifetime `'_`... LL | let p: &'static mut usize = &mut self.cats_chased; - | ^^^^^^^^^^^^^^^^^^^^^ - | -note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 6:5... - --> $DIR/regions-addr-of-self.rs:6:5 - | -LL | / pub fn chase_cat(&mut self) { -LL | | let p: &'static mut usize = &mut self.cats_chased; -LL | | *p += 1; -LL | | } - | |_____^ -note: ...so that reference does not outlive borrowed content - --> $DIR/regions-addr-of-self.rs:7:37 - | -LL | let p: &'static mut usize = &mut self.cats_chased; - | ^^^^^^^^^^^^^^^^^^^^^ - = note: but, the lifetime must be valid for the static lifetime... -note: ...so that reference does not outlive borrowed content - --> $DIR/regions-addr-of-self.rs:7:37 - | -LL | let p: &'static mut usize = &mut self.cats_chased; - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ ...is captured and required to live as long as `'static` here error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. +For more information about this error, try `rustc --explain E0759`. diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-without-suggestion.rs b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-without-suggestion.rs new file mode 100644 index 0000000000000..dd53ee06ff5ee --- /dev/null +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-without-suggestion.rs @@ -0,0 +1,14 @@ +trait OtherTrait<'a> {} +impl<'a> OtherTrait<'a> for &'a () {} + +trait ObjectTrait {} + +impl dyn ObjectTrait { + fn use_self(&self) -> &() { panic!() } +} + +fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { + val.use_self() //~ ERROR mismatched types +} + +fn main() {} diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-without-suggestion.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-without-suggestion.stderr new file mode 100644 index 0000000000000..4618b540c70ee --- /dev/null +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-without-suggestion.stderr @@ -0,0 +1,18 @@ +error[E0308]: mismatched types + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-without-suggestion.rs:11:9 + | +LL | val.use_self() + | ^^^^^^^^ lifetime mismatch + | + = note: expected reference `&(dyn ObjectTrait + 'static)` + found reference `&(dyn ObjectTrait + 'a)` +note: the lifetime `'a` as defined on the function body at 10:11... + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-without-suggestion.rs:10:11 + | +LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { + | ^^ + = note: ...does not necessarily outlive the static lifetime + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.fixed b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.fixed new file mode 100644 index 0000000000000..dfe475d3c0694 --- /dev/null +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.fixed @@ -0,0 +1,37 @@ +// run-rustfix +#![allow(dead_code)] + +mod foo { + trait OtherTrait<'a> {} + impl<'a> OtherTrait<'a> for &'a () {} + + trait ObjectTrait {} + trait MyTrait { + fn use_self(&self) -> &(); + } + + impl MyTrait for dyn ObjectTrait + '_ { + fn use_self(&self) -> &() { panic!() } + } + + fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { + val.use_self() //~ ERROR cannot infer an appropriate lifetime + } +} + +mod bar { + trait ObjectTrait {} + trait MyTrait { + fn use_self(&self) -> &(); + } + + impl MyTrait for dyn ObjectTrait + '_ { + fn use_self(&self) -> &() { panic!() } + } + + fn use_it<'a>(val: &'a dyn ObjectTrait) -> &'a () { + val.use_self() //~ ERROR cannot infer an appropriate lifetime + } +} + +fn main() {} diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.rs b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.rs new file mode 100644 index 0000000000000..85e6c2993b9b1 --- /dev/null +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.rs @@ -0,0 +1,37 @@ +// run-rustfix +#![allow(dead_code)] + +mod foo { + trait OtherTrait<'a> {} + impl<'a> OtherTrait<'a> for &'a () {} + + trait ObjectTrait {} + trait MyTrait { + fn use_self(&self) -> &(); + } + + impl MyTrait for dyn ObjectTrait { + fn use_self(&self) -> &() { panic!() } + } + + fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { + val.use_self() //~ ERROR cannot infer an appropriate lifetime + } +} + +mod bar { + trait ObjectTrait {} + trait MyTrait { + fn use_self(&self) -> &(); + } + + impl MyTrait for dyn ObjectTrait { + fn use_self(&self) -> &() { panic!() } + } + + fn use_it<'a>(val: &'a dyn ObjectTrait) -> &'a () { + val.use_self() //~ ERROR cannot infer an appropriate lifetime + } +} + +fn main() {} diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr new file mode 100644 index 0000000000000..6780459adbeac --- /dev/null +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr @@ -0,0 +1,29 @@ +error[E0759]: cannot infer an appropriate lifetime + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:18:13 + | +LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { + | ------------------- this data with lifetime `'a`... +LL | val.use_self() + | ^^^^^^^^ ...is captured and required to live as long as `'static` here + | +help: this `impl` introduces an implicit `'static` requirement, consider changing it + | +LL | impl MyTrait for dyn ObjectTrait + '_ { + | ^^^^ + +error[E0759]: cannot infer an appropriate lifetime + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:33:13 + | +LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> &'a () { + | ------------------- this data with lifetime `'a`... +LL | val.use_self() + | ^^^^^^^^ ...is captured and required to live as long as `'static` here + | +help: this `impl` introduces an implicit `'static` requirement, consider changing it + | +LL | impl MyTrait for dyn ObjectTrait + '_ { + | ^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0759`. From bc528ebc5158486252d8609d266c0a924244fd4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 28 Jun 2020 15:26:12 -0700 Subject: [PATCH 16/30] Increase accuracy of lifetime bound on trait object impl suggestion --- src/librustc_hir/hir.rs | 12 +- src/librustc_infer/infer/combine.rs | 10 +- .../infer/error_reporting/mod.rs | 2 +- .../nice_region_error/static_impl_trait.rs | 184 +++++++++++++----- .../error_reporting/nice_region_error/util.rs | 14 +- src/librustc_infer/infer/mod.rs | 18 +- src/librustc_infer/lib.rs | 1 + src/librustc_middle/traits/mod.rs | 2 + .../traits/structural_impls.rs | 1 + src/librustc_middle/ty/mod.rs | 8 +- .../traits/error_reporting/suggestions.rs | 1 + src/librustc_typeck/check/method/confirm.rs | 24 ++- ...mplicit-static-bound-without-suggestion.rs | 14 -- ...cit-static-bound-without-suggestion.stderr | 18 -- ...dyn-trait-with-implicit-static-bound.fixed | 36 ++++ ...rait-with-implicit-static-bound.nll.stderr | 22 +++ ...on-dyn-trait-with-implicit-static-bound.rs | 36 ++++ ...yn-trait-with-implicit-static-bound.stderr | 32 ++- 18 files changed, 321 insertions(+), 114 deletions(-) delete mode 100644 src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-without-suggestion.rs delete mode 100644 src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-without-suggestion.stderr create mode 100644 src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index f56522406b0a7..6474dc318d329 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -2198,7 +2198,17 @@ pub enum IsAsync { NotAsync, } -#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] +#[derive( + Copy, + Clone, + PartialEq, + RustcEncodable, + RustcDecodable, + Debug, + HashStable_Generic, + Eq, + Hash +)] pub enum Defaultness { Default { has_value: bool }, Final, diff --git a/src/librustc_infer/infer/combine.rs b/src/librustc_infer/infer/combine.rs index 3b564e03d9a94..c63464e5baec9 100644 --- a/src/librustc_infer/infer/combine.rs +++ b/src/librustc_infer/infer/combine.rs @@ -36,12 +36,13 @@ use crate::traits::{Obligation, PredicateObligations}; use rustc_ast::ast; use rustc_hir::def_id::DefId; +use rustc_middle::traits::ObligationCause; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, InferConst, ToPredicate, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{IntType, UintType}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::DUMMY_SP; #[derive(Clone)] pub struct CombineFields<'infcx, 'tcx> { @@ -367,10 +368,11 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { }; debug!("generalize: for_universe = {:?}", for_universe); + debug!("generalize: trace = {:?}", self.trace); let mut generalize = Generalizer { infcx: self.infcx, - span: self.trace.cause.span, + cause: &self.trace.cause, for_vid_sub_root: self.infcx.inner.borrow_mut().type_variables().sub_root_var(for_vid), for_universe, ambient_variance, @@ -414,7 +416,7 @@ struct Generalizer<'cx, 'tcx> { infcx: &'cx InferCtxt<'cx, 'tcx>, /// The span, used when creating new type variables and things. - span: Span, + cause: &'cx ObligationCause<'tcx>, /// The vid of the type variable that is in the process of being /// instantiated; if we find this within the type we are folding, @@ -639,7 +641,7 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { // FIXME: This is non-ideal because we don't give a // very descriptive origin for this region variable. - Ok(self.infcx.next_region_var_in_universe(MiscVariable(self.span), self.for_universe)) + Ok(self.infcx.next_region_var_in_universe(MiscVariable(self.cause.span), self.for_universe)) } fn consts( diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs index 633589db2704c..ff905faa95a9f 100644 --- a/src/librustc_infer/infer/error_reporting/mod.rs +++ b/src/librustc_infer/infer/error_reporting/mod.rs @@ -2010,7 +2010,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { infer::MiscVariable(_) => String::new(), infer::PatternRegion(_) => " for pattern".to_string(), infer::AddrOfRegion(_) => " for borrow expression".to_string(), - infer::Autoref(_) => " for autoref".to_string(), + infer::Autoref(_, _) => " for autoref".to_string(), infer::Coercion(_) => " for automatic coercion".to_string(), infer::LateBoundRegion(_, br, infer::FnCall) => { format!(" for lifetime parameter {}in function call", br_string(br)) diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs index da776f269d510..0aa1d65612ee6 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -2,14 +2,14 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; +use crate::infer::{SubregionOrigin, TypeTrace}; +use crate::traits::ObligationCauseCode; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported}; -use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; -use rustc_hir::{ - GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, Path, PolyTraitRef, TraitRef, - TyKind, -}; -use rustc_middle::ty::{self, RegionKind, Ty, TypeFoldable, TypeVisitor}; +use rustc_hir::intravisit::{walk_ty, ErasedMap, NestedVisitorMap, Visitor}; +use rustc_hir::{self as hir, GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, TyKind}; +use rustc_middle::ty::{self, AssocItemContainer, RegionKind, Ty, TypeFoldable, TypeVisitor}; +use rustc_span::Span; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// Print the error message for lifetime errors when the return type is a static impl Trait. @@ -27,6 +27,39 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { ) if **sub_r == RegionKind::ReStatic => { (var_origin, sub_origin, sub_r, sup_origin, sup_r) } + RegionResolutionError::ConcreteFailure( + SubregionOrigin::Subtype(box TypeTrace { cause, .. }), + sub_r, + sup_r, + ) if **sub_r == RegionKind::ReStatic => { + // This is for the implicit `'static` requirement coming from `impl dyn Trait {}`. + if let ObligationCauseCode::UnifyReceiver(assoc) = &cause.code { + let param = self.find_param_with_region(sup_r, sub_r)?; + let lifetime = if sup_r.has_name() { + format!("lifetime `{}`", sup_r) + } else { + "an anonymous lifetime `'_`".to_string() + }; + let mut err = struct_span_err!( + tcx.sess, + cause.span, + E0759, + "cannot infer an appropriate lifetime" + ); + err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime)); + err.span_label( + cause.span, + "...is captured and required to live as long as `'static` here", + ); + if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &assoc.container) { + err.emit(); + return Some(ErrorReported); + } else { + err.cancel(); + } + } + return None; + } _ => return None, }; debug!( @@ -96,7 +129,11 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { ); } - self.find_impl_on_dyn_trait(&mut err, param.param_ty); + if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sup_origin { + if let ObligationCauseCode::UnifyReceiver(assoc) = &cause.code { + self.find_impl_on_dyn_trait(&mut err, param.param_ty, &assoc.container); + } + } let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id); debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns); @@ -222,63 +259,86 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// When we call a method coming from an `impl Foo for dyn Bar`, `dyn Bar` introduces a default /// `'static` obligation. Find `impl` blocks that are implemented - fn find_impl_on_dyn_trait(&self, err: &mut DiagnosticBuilder<'_>, ty: Ty<'_>) -> bool { + fn find_impl_on_dyn_trait( + &self, + err: &mut DiagnosticBuilder<'_>, + ty: Ty<'_>, + container: &AssocItemContainer, + ) -> bool { let tcx = self.tcx(); + let mut suggested = false; // Find the trait object types in the argument. let mut v = TraitObjectVisitor(vec![]); v.visit_ty(ty); - debug!("TraitObjectVisitor {:?}", v.0); - // Find all the `impl`s in the local scope that can be called on the type parameter. - // FIXME: this doesn't find `impl dyn Trait { /**/ }`. + let container_id = match container { + // When the obligation comes from an `impl Foo for dyn Bar {}`, we + // have the `DefId` of the `trait` itself, not the relevant `impl` + // block. Because of this, we have to look at all the `trait`s + // available, and filter out all that are not of `Foo` (this `def_id`) + // and not of `Bar` (the `filter_map` later in this method). + AssocItemContainer::TraitContainer(def_id) => def_id, + + // When the obligation comes from an `impl dyn Trait {}`, we already + // have the `DefId` of the relevant `Item`, so we use it directly. + AssocItemContainer::ImplContainer(def_id) => { + if let Some(Node::Item(Item { kind: ItemKind::Impl { self_ty, .. }, .. })) = + tcx.hir().get_if_local(*def_id) + { + for found_did in &v.0 { + let mut hir_v = HirTraitObjectVisitor(vec![], *found_did); + hir_v.visit_ty(self_ty); + if let [span] = &hir_v.0[..] { + err.span_suggestion_verbose( + span.shrink_to_hi(), + "this `impl` introduces an implicit `'static` requirement, \ + consider changing it", + " + '_".to_string(), + Applicability::MaybeIncorrect, + ); + suggested = true; + } + } + } + return suggested; + } + }; + + // Find all the `impl`s in the local scope that can be called on the type parameter. And + // retain all that are `impl`s of the trait that originated the `'static` obligation. + // This doesn't find `impl dyn Trait { /**/ }`, but that case is handled above. let impl_self_tys = tcx .all_traits(LOCAL_CRATE) .iter() .flat_map(|trait_did| tcx.hir().trait_impls(*trait_did)) .filter_map(|impl_node| { let impl_did = tcx.hir().local_def_id(*impl_node); - if let Some(Node::Item(Item { kind: ItemKind::Impl { self_ty, .. }, .. })) = - tcx.hir().get_if_local(impl_did.to_def_id()) - { - Some(self_ty) - } else { - None + match tcx.hir().get_if_local(impl_did.to_def_id()) { + Some(Node::Item(Item { + kind: ItemKind::Impl { self_ty, of_trait: Some(of_trait), .. }, + .. + })) if of_trait.trait_def_id() == Some(*container_id) => Some(self_ty), + _ => None, } }); - let mut suggested = false; + + // Given all the `impl`s of the relevant `trait`, look for those that are implemented for + // the trait object in the `fn` parameter type. for self_ty in impl_self_tys { - if let TyKind::TraitObject( - poly_trait_refs, - Lifetime { name: LifetimeName::ImplicitObjectLifetimeDefault, .. }, - ) = self_ty.kind - { - for p in poly_trait_refs { - if let PolyTraitRef { - trait_ref: - TraitRef { path: Path { res: Res::Def(DefKind::Trait, did), .. }, .. }, - .. - } = p - { - for found_did in &v.0 { - if did == found_did { - // We've found an `impl Foo for dyn Bar {}`. - // FIXME: we should change this so it also works for - // `impl Foo for Box {}`. - err.span_suggestion_verbose( - self_ty.span.shrink_to_hi(), - "this `impl` introduces an implicit `'static` requirement, \ - consider changing it", - " + '_".to_string(), - Applicability::MaybeIncorrect, - ); - suggested = true; - } - } - } + for found_did in &v.0 { + let mut hir_v = HirTraitObjectVisitor(vec![], *found_did); + hir_v.visit_ty(self_ty); + if let [span] = &hir_v.0[..] { + err.span_suggestion_verbose( + span.shrink_to_hi(), + "this `impl` introduces an implicit `'static` requirement, \ + consider changing it", + " + '_".to_string(), + Applicability::MaybeIncorrect, + ); + suggested = true; } - err.emit(); - return Some(ErrorReported); } } suggested @@ -301,3 +361,31 @@ impl TypeVisitor<'_> for TraitObjectVisitor { } } } + +/// Collect all `hir::Ty<'_>` `Span`s for trait objects with an implicit lifetime. +struct HirTraitObjectVisitor(Vec, DefId); + +impl<'tcx> Visitor<'tcx> for HirTraitObjectVisitor { + type Map = ErasedMap<'tcx>; + + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::None + } + + fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) { + match t.kind { + TyKind::TraitObject( + poly_trait_refs, + Lifetime { name: LifetimeName::ImplicitObjectLifetimeDefault, .. }, + ) => { + for ptr in poly_trait_refs { + if Some(self.1) == ptr.trait_ref.trait_def_id() { + self.0.push(ptr.span); + } + } + } + _ => {} + } + walk_ty(self, t); + } +} diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/util.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/util.rs index fa999abb1a86c..28e9dd90cfd67 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/util.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/util.rs @@ -7,20 +7,18 @@ use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::{self, DefIdTree, Region, Ty}; use rustc_span::Span; -// The struct contains the information about the anonymous region -// we are searching for. +/// Information about the anonymous region we are searching for. #[derive(Debug)] pub(super) struct AnonymousParamInfo<'tcx> { - // the parameter corresponding to the anonymous region + /// The parameter corresponding to the anonymous region. pub param: &'tcx hir::Param<'tcx>, - // the type corresponding to the anonymopus region parameter + /// The type corresponding to the anonymous region parameter. pub param_ty: Ty<'tcx>, - // the ty::BoundRegion corresponding to the anonymous region + /// The ty::BoundRegion corresponding to the anonymous region. pub bound_region: ty::BoundRegion, - // param_ty_span contains span of parameter type + /// The `Span` of the parameter type. pub param_ty_span: Span, - // corresponds to id the argument is the first parameter - // in the declaration + /// Signals that the argument is the first parameter in the declaration. pub is_first: bool, } diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index 37883fcb07468..3744ad5d0324a 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -463,7 +463,7 @@ pub enum RegionVariableOrigin { AddrOfRegion(Span), /// Regions created as part of an autoref of a method receiver - Autoref(Span), + Autoref(Span, ty::AssocItem), /// Regions created as part of an automatic coercion Coercion(Span), @@ -1800,15 +1800,15 @@ impl<'tcx> SubregionOrigin<'tcx> { impl RegionVariableOrigin { pub fn span(&self) -> Span { match *self { - MiscVariable(a) => a, - PatternRegion(a) => a, - AddrOfRegion(a) => a, - Autoref(a) => a, - Coercion(a) => a, - EarlyBoundRegion(a, ..) => a, - LateBoundRegion(a, ..) => a, + MiscVariable(a) + | PatternRegion(a) + | AddrOfRegion(a) + | Autoref(a, _) + | Coercion(a) + | EarlyBoundRegion(a, ..) + | LateBoundRegion(a, ..) + | UpvarRegion(_, a) => a, BoundRegionInCoherence(_) => rustc_span::DUMMY_SP, - UpvarRegion(_, a) => a, NLL(..) => bug!("NLL variable used with `span`"), } } diff --git a/src/librustc_infer/lib.rs b/src/librustc_infer/lib.rs index 0cd6585163c4e..bacb7fa153e43 100644 --- a/src/librustc_infer/lib.rs +++ b/src/librustc_infer/lib.rs @@ -13,6 +13,7 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![feature(bindings_after_at)] #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(box_syntax)] diff --git a/src/librustc_middle/traits/mod.rs b/src/librustc_middle/traits/mod.rs index c15c31a53f0c9..c066ea831b298 100644 --- a/src/librustc_middle/traits/mod.rs +++ b/src/librustc_middle/traits/mod.rs @@ -300,6 +300,8 @@ pub enum ObligationCauseCode<'tcx> { /// Method receiver MethodReceiver, + UnifyReceiver(Rc), + /// `return` with no expression ReturnNoExpression, diff --git a/src/librustc_middle/traits/structural_impls.rs b/src/librustc_middle/traits/structural_impls.rs index 334462790edbc..61ef0821733e8 100644 --- a/src/librustc_middle/traits/structural_impls.rs +++ b/src/librustc_middle/traits/structural_impls.rs @@ -213,6 +213,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { super::StartFunctionType => Some(super::StartFunctionType), super::IntrinsicType => Some(super::IntrinsicType), super::MethodReceiver => Some(super::MethodReceiver), + super::UnifyReceiver(ref assoc) => Some(super::UnifyReceiver(assoc.clone())), super::BlockTailExpression(id) => Some(super::BlockTailExpression(id)), super::TrivialBound => Some(super::TrivialBound), } diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 21745977b04b1..3b83ba8a4a71b 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -136,7 +136,7 @@ pub struct ResolverOutputs { pub extern_prelude: FxHashMap, } -#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable)] +#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable, Hash)] pub enum AssocItemContainer { TraitContainer(DefId), ImplContainer(DefId), @@ -184,7 +184,7 @@ pub enum ImplPolarity { Reservation, } -#[derive(Copy, Clone, Debug, PartialEq, HashStable)] +#[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash)] pub struct AssocItem { pub def_id: DefId, #[stable_hasher(project(name))] @@ -199,7 +199,7 @@ pub struct AssocItem { pub fn_has_self_parameter: bool, } -#[derive(Copy, Clone, PartialEq, Debug, HashStable)] +#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash)] pub enum AssocKind { Const, Fn, @@ -316,7 +316,7 @@ impl<'tcx> AssociatedItems<'tcx> { } } -#[derive(Clone, Debug, PartialEq, Eq, Copy, RustcEncodable, RustcDecodable, HashStable)] +#[derive(Clone, Debug, PartialEq, Eq, Copy, RustcEncodable, RustcDecodable, HashStable, Hash)] pub enum Visibility { /// Visible everywhere (including in other crates). Public, diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index 0a6fb72ca51ea..e94b44d879533 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -1706,6 +1706,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { | ObligationCauseCode::IntrinsicType | ObligationCauseCode::MethodReceiver | ObligationCauseCode::ReturnNoExpression + | ObligationCauseCode::UnifyReceiver(_) | ObligationCauseCode::MiscObligation => {} ObligationCauseCode::SliceOrArrayElem => { err.note("slice and array elements must have `Sized` type"); diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 96248e18aaf87..58cbe8b2479d6 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -6,6 +6,7 @@ use crate::hir::def_id::DefId; use crate::hir::GenericArg; use rustc_hir as hir; use rustc_infer::infer::{self, InferOk}; +use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast}; use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::fold::TypeFoldable; @@ -15,6 +16,7 @@ use rustc_span::Span; use rustc_trait_selection::traits; use std::ops::Deref; +use std::rc::Rc; struct ConfirmContext<'a, 'tcx> { fcx: &'a FnCtxt<'a, 'tcx>, @@ -91,7 +93,11 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // signature (which is also done during probing). let method_sig_rcvr = self.normalize_associated_types_in(self.span, &method_sig.inputs()[0]); - self.unify_receivers(self_ty, method_sig_rcvr); + debug!( + "confirm: self_ty={:?} method_sig_rcvr={:?} method_sig={:?} method_predicates={:?}", + self_ty, method_sig_rcvr, method_sig, method_predicates + ); + self.unify_receivers(self_ty, method_sig_rcvr, &pick); let (method_sig, method_predicates) = self.normalize_associated_types_in(self.span, &(method_sig, method_predicates)); @@ -150,7 +156,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false)); if let Some(mutbl) = pick.autoref { - let region = self.next_region_var(infer::Autoref(self.span)); + let region = self.next_region_var(infer::Autoref(self.span, pick.item)); target = self.tcx.mk_ref(region, ty::TypeAndMut { mutbl, ty: target }); let mutbl = match mutbl { hir::Mutability::Not => AutoBorrowMutability::Not, @@ -334,8 +340,18 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { ) } - fn unify_receivers(&mut self, self_ty: Ty<'tcx>, method_self_ty: Ty<'tcx>) { - match self.at(&self.misc(self.span), self.param_env).sup(method_self_ty, self_ty) { + fn unify_receivers( + &mut self, + self_ty: Ty<'tcx>, + method_self_ty: Ty<'tcx>, + pick: &probe::Pick<'tcx>, + ) { + debug!( + "unify_receivers: self_ty={:?} method_self_ty={:?} span={:?} pick={:?}", + self_ty, method_self_ty, self.span, pick + ); + let cause = self.cause(self.span, ObligationCauseCode::UnifyReceiver(Rc::new(pick.item))); + match self.at(&cause, self.param_env).sup(method_self_ty, self_ty) { Ok(InferOk { obligations, value: () }) => { self.register_predicates(obligations); } diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-without-suggestion.rs b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-without-suggestion.rs deleted file mode 100644 index dd53ee06ff5ee..0000000000000 --- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-without-suggestion.rs +++ /dev/null @@ -1,14 +0,0 @@ -trait OtherTrait<'a> {} -impl<'a> OtherTrait<'a> for &'a () {} - -trait ObjectTrait {} - -impl dyn ObjectTrait { - fn use_self(&self) -> &() { panic!() } -} - -fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { - val.use_self() //~ ERROR mismatched types -} - -fn main() {} diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-without-suggestion.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-without-suggestion.stderr deleted file mode 100644 index 4618b540c70ee..0000000000000 --- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-without-suggestion.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-without-suggestion.rs:11:9 - | -LL | val.use_self() - | ^^^^^^^^ lifetime mismatch - | - = note: expected reference `&(dyn ObjectTrait + 'static)` - found reference `&(dyn ObjectTrait + 'a)` -note: the lifetime `'a` as defined on the function body at 10:11... - --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-without-suggestion.rs:10:11 - | -LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { - | ^^ - = note: ...does not necessarily outlive the static lifetime - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.fixed b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.fixed index dfe475d3c0694..62cf9b989bb4d 100644 --- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.fixed +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.fixed @@ -9,10 +9,12 @@ mod foo { trait MyTrait { fn use_self(&self) -> &(); } + trait Irrelevant {} impl MyTrait for dyn ObjectTrait + '_ { fn use_self(&self) -> &() { panic!() } } + impl Irrelevant for dyn ObjectTrait {} fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { val.use_self() //~ ERROR cannot infer an appropriate lifetime @@ -24,14 +26,48 @@ mod bar { trait MyTrait { fn use_self(&self) -> &(); } + trait Irrelevant {} impl MyTrait for dyn ObjectTrait + '_ { fn use_self(&self) -> &() { panic!() } } + impl Irrelevant for dyn ObjectTrait {} fn use_it<'a>(val: &'a dyn ObjectTrait) -> &'a () { val.use_self() //~ ERROR cannot infer an appropriate lifetime } } +mod baz { + trait ObjectTrait {} + trait MyTrait { + fn use_self(&self) -> &(); + } + trait Irrelevant {} + + impl MyTrait for Box { + fn use_self(&self) -> &() { panic!() } + } + impl Irrelevant for Box {} + + fn use_it<'a>(val: &'a Box) -> &'a () { + val.use_self() //~ ERROR cannot infer an appropriate lifetime + } +} + +mod bat { + trait OtherTrait<'a> {} + impl<'a> OtherTrait<'a> for &'a () {} + + trait ObjectTrait {} + + impl dyn ObjectTrait + '_ { + fn use_self(&self) -> &() { panic!() } + } + + fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { + val.use_self() //~ ERROR cannot infer an appropriate lifetime + } +} + fn main() {} diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr new file mode 100644 index 0000000000000..00f65a2348935 --- /dev/null +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr @@ -0,0 +1,22 @@ +error[E0521]: borrowed data escapes outside of function + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:20:9 + | +LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { + | --- `val` is a reference that is only valid in the function body +LL | val.use_self() + | ^^^^^^^^^^^^^^ `val` escapes the function body here + | + = help: consider replacing `'a` with `'static` + +error[E0521]: borrowed data escapes outside of function + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:69:9 + | +LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { + | --- `val` is a reference that is only valid in the function body +LL | val.use_self() + | ^^^^^^^^^^^^^^ `val` escapes the function body here + | + = help: consider replacing `'a` with `'static` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.rs b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.rs index 85e6c2993b9b1..28a599d12bfd1 100644 --- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.rs +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.rs @@ -9,10 +9,12 @@ mod foo { trait MyTrait { fn use_self(&self) -> &(); } + trait Irrelevant {} impl MyTrait for dyn ObjectTrait { fn use_self(&self) -> &() { panic!() } } + impl Irrelevant for dyn ObjectTrait {} fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { val.use_self() //~ ERROR cannot infer an appropriate lifetime @@ -24,14 +26,48 @@ mod bar { trait MyTrait { fn use_self(&self) -> &(); } + trait Irrelevant {} impl MyTrait for dyn ObjectTrait { fn use_self(&self) -> &() { panic!() } } + impl Irrelevant for dyn ObjectTrait {} fn use_it<'a>(val: &'a dyn ObjectTrait) -> &'a () { val.use_self() //~ ERROR cannot infer an appropriate lifetime } } +mod baz { + trait ObjectTrait {} + trait MyTrait { + fn use_self(&self) -> &(); + } + trait Irrelevant {} + + impl MyTrait for Box { + fn use_self(&self) -> &() { panic!() } + } + impl Irrelevant for Box {} + + fn use_it<'a>(val: &'a Box) -> &'a () { + val.use_self() //~ ERROR cannot infer an appropriate lifetime + } +} + +mod bat { + trait OtherTrait<'a> {} + impl<'a> OtherTrait<'a> for &'a () {} + + trait ObjectTrait {} + + impl dyn ObjectTrait { + fn use_self(&self) -> &() { panic!() } + } + + fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { + val.use_self() //~ ERROR cannot infer an appropriate lifetime + } +} + fn main() {} diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr index 6780459adbeac..1a03590febe46 100644 --- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr @@ -1,5 +1,5 @@ error[E0759]: cannot infer an appropriate lifetime - --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:18:13 + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:20:13 | LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { | ------------------- this data with lifetime `'a`... @@ -12,7 +12,20 @@ LL | impl MyTrait for dyn ObjectTrait + '_ { | ^^^^ error[E0759]: cannot infer an appropriate lifetime - --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:33:13 + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:69:13 + | +LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { + | ------------------- this data with lifetime `'a`... +LL | val.use_self() + | ^^^^^^^^ ...is captured and required to live as long as `'static` here + | +help: this `impl` introduces an implicit `'static` requirement, consider changing it + | +LL | impl dyn ObjectTrait + '_ { + | ^^^^ + +error[E0759]: cannot infer an appropriate lifetime + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:37:13 | LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> &'a () { | ------------------- this data with lifetime `'a`... @@ -24,6 +37,19 @@ help: this `impl` introduces an implicit `'static` requirement, consider changin LL | impl MyTrait for dyn ObjectTrait + '_ { | ^^^^ -error: aborting due to 2 previous errors +error[E0759]: cannot infer an appropriate lifetime + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:54:13 + | +LL | fn use_it<'a>(val: &'a Box) -> &'a () { + | ----------------------------- this data with lifetime `'a`... +LL | val.use_self() + | ^^^^^^^^ ...is captured and required to live as long as `'static` here + | +help: this `impl` introduces an implicit `'static` requirement, consider changing it + | +LL | impl MyTrait for Box { + | ^^^^ + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0759`. From 3f5c7f2e5ef86164a3b768338d429aa73387efa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 28 Jun 2020 18:07:26 -0700 Subject: [PATCH 17/30] Add more context to diagnostic --- .../nice_region_error/static_impl_trait.rs | 78 +++++++++++++++---- ...yn-trait-with-implicit-static-bound.stderr | 36 ++++++++- 2 files changed, 96 insertions(+), 18 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs index 0aa1d65612ee6..36d354ea777a4 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -8,8 +8,10 @@ use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorRepor use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::intravisit::{walk_ty, ErasedMap, NestedVisitorMap, Visitor}; use rustc_hir::{self as hir, GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, TyKind}; -use rustc_middle::ty::{self, AssocItemContainer, RegionKind, Ty, TypeFoldable, TypeVisitor}; -use rustc_span::Span; +use rustc_middle::ty::{ + self, AssocItem, AssocItemContainer, RegionKind, Ty, TypeFoldable, TypeVisitor, +}; +use rustc_span::{MultiSpan, Span}; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// Print the error message for lifetime errors when the return type is a static impl Trait. @@ -51,7 +53,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { cause.span, "...is captured and required to live as long as `'static` here", ); - if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &assoc.container) { + if self.find_impl_on_dyn_trait(&mut err, param.param_ty, assoc) { err.emit(); return Some(ErrorReported); } else { @@ -131,7 +133,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sup_origin { if let ObligationCauseCode::UnifyReceiver(assoc) = &cause.code { - self.find_impl_on_dyn_trait(&mut err, param.param_ty, &assoc.container); + self.find_impl_on_dyn_trait(&mut err, param.param_ty, assoc); } } @@ -263,7 +265,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { &self, err: &mut DiagnosticBuilder<'_>, ty: Ty<'_>, - container: &AssocItemContainer, + assoc: &AssocItem, ) -> bool { let tcx = self.tcx(); let mut suggested = false; @@ -272,7 +274,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let mut v = TraitObjectVisitor(vec![]); v.visit_ty(ty); - let container_id = match container { + let container_id = match assoc.container { // When the obligation comes from an `impl Foo for dyn Bar {}`, we // have the `DefId` of the `trait` itself, not the relevant `impl` // block. Because of this, we have to look at all the `trait`s @@ -284,16 +286,35 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // have the `DefId` of the relevant `Item`, so we use it directly. AssocItemContainer::ImplContainer(def_id) => { if let Some(Node::Item(Item { kind: ItemKind::Impl { self_ty, .. }, .. })) = - tcx.hir().get_if_local(*def_id) + tcx.hir().get_if_local(def_id) { for found_did in &v.0 { let mut hir_v = HirTraitObjectVisitor(vec![], *found_did); hir_v.visit_ty(self_ty); if let [span] = &hir_v.0[..] { + let mut multi_span: MultiSpan = vec![*span].into(); + multi_span.push_span_label( + *span, + "this trait object has an implicit `'static` lifetime requirement" + .to_string(), + ); + multi_span.push_span_label( + assoc.ident.span, + "the `'static` requirement is introduced when calling this method" + .to_string(), + ); + err.span_note( + multi_span, + &format!( + "when using method `{}` on `{}`, an implicit `'static` \ + requirement is introduced", + assoc.ident, + tcx.def_path_str(*found_did), + ), + ); err.span_suggestion_verbose( span.shrink_to_hi(), - "this `impl` introduces an implicit `'static` requirement, \ - consider changing it", + "consider relaxing the implicit `'static` requirement", " + '_".to_string(), Applicability::MaybeIncorrect, ); @@ -316,24 +337,53 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let impl_did = tcx.hir().local_def_id(*impl_node); match tcx.hir().get_if_local(impl_did.to_def_id()) { Some(Node::Item(Item { - kind: ItemKind::Impl { self_ty, of_trait: Some(of_trait), .. }, + kind: ItemKind::Impl { self_ty, of_trait: Some(of_trait), items, .. }, .. - })) if of_trait.trait_def_id() == Some(*container_id) => Some(self_ty), + })) if of_trait.trait_def_id() == Some(container_id) => Some(( + self_ty, + // Get the ident of the method, in order to use its `Span`. + items + .iter() + .filter(|item| item.ident == assoc.ident) + .map(|item| item.ident) + .next() + .unwrap_or(assoc.ident), + )), _ => None, } }); // Given all the `impl`s of the relevant `trait`, look for those that are implemented for // the trait object in the `fn` parameter type. - for self_ty in impl_self_tys { + for (self_ty, method) in impl_self_tys { for found_did in &v.0 { let mut hir_v = HirTraitObjectVisitor(vec![], *found_did); hir_v.visit_ty(self_ty); if let [span] = &hir_v.0[..] { + let mut multi_span: MultiSpan = vec![*span].into(); + multi_span.push_span_label( + *span, + "this trait object has an implicit `'static` lifetime requirement" + .to_string(), + ); + multi_span.push_span_label( + method.span, + "the `'static` requirement is introduced when calling this method" + .to_string(), + ); + err.span_note( + multi_span, + &format!( + "when using method `{}` of trait `{}` on `{}`, an implicit `'static` \ + requirement is introduced", + method, + tcx.def_path_str(container_id), + tcx.def_path_str(*found_did), + ), + ); err.span_suggestion_verbose( span.shrink_to_hi(), - "this `impl` introduces an implicit `'static` requirement, \ - consider changing it", + "consider relaxing the implicit `'static` requirement", " + '_".to_string(), Applicability::MaybeIncorrect, ); diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr index 1a03590febe46..8f8fd9dc32402 100644 --- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr @@ -6,7 +6,14 @@ LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { LL | val.use_self() | ^^^^^^^^ ...is captured and required to live as long as `'static` here | -help: this `impl` introduces an implicit `'static` requirement, consider changing it +note: when using method `use_self` of trait `foo::MyTrait` on `foo::ObjectTrait`, an implicit `'static` requirement is introduced + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:14:26 + | +LL | impl MyTrait for dyn ObjectTrait { + | ^^^^^^^^^^^ this trait object has an implicit `'static` lifetime requirement +LL | fn use_self(&self) -> &() { panic!() } + | -------- the `'static` requirement is introduced when calling this method +help: consider relaxing the implicit `'static` requirement | LL | impl MyTrait for dyn ObjectTrait + '_ { | ^^^^ @@ -19,7 +26,14 @@ LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { LL | val.use_self() | ^^^^^^^^ ...is captured and required to live as long as `'static` here | -help: this `impl` introduces an implicit `'static` requirement, consider changing it +note: when using method `use_self` on `bat::ObjectTrait`, an implicit `'static` requirement is introduced + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:64:14 + | +LL | impl dyn ObjectTrait { + | ^^^^^^^^^^^ this trait object has an implicit `'static` lifetime requirement +LL | fn use_self(&self) -> &() { panic!() } + | -------- the `'static` requirement is introduced when calling this method +help: consider relaxing the implicit `'static` requirement | LL | impl dyn ObjectTrait + '_ { | ^^^^ @@ -32,7 +46,14 @@ LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> &'a () { LL | val.use_self() | ^^^^^^^^ ...is captured and required to live as long as `'static` here | -help: this `impl` introduces an implicit `'static` requirement, consider changing it +note: when using method `use_self` of trait `bar::MyTrait` on `bar::ObjectTrait`, an implicit `'static` requirement is introduced + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:31:26 + | +LL | impl MyTrait for dyn ObjectTrait { + | ^^^^^^^^^^^ this trait object has an implicit `'static` lifetime requirement +LL | fn use_self(&self) -> &() { panic!() } + | -------- the `'static` requirement is introduced when calling this method +help: consider relaxing the implicit `'static` requirement | LL | impl MyTrait for dyn ObjectTrait + '_ { | ^^^^ @@ -45,7 +66,14 @@ LL | fn use_it<'a>(val: &'a Box) -> &'a () { LL | val.use_self() | ^^^^^^^^ ...is captured and required to live as long as `'static` here | -help: this `impl` introduces an implicit `'static` requirement, consider changing it +note: when using method `use_self` of trait `baz::MyTrait` on `baz::ObjectTrait`, an implicit `'static` requirement is introduced + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:48:30 + | +LL | impl MyTrait for Box { + | ^^^^^^^^^^^ this trait object has an implicit `'static` lifetime requirement +LL | fn use_self(&self) -> &() { panic!() } + | -------- the `'static` requirement is introduced when calling this method +help: consider relaxing the implicit `'static` requirement | LL | impl MyTrait for Box { | ^^^^ From 8f749710b4477f2d93c89b67c012d87d56de1bc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 29 Jun 2020 11:14:42 -0700 Subject: [PATCH 18/30] Further tweak wording of E0759 and introduce E0767 --- src/librustc_error_codes/error_codes.rs | 1 + .../nice_region_error/static_impl_trait.rs | 107 +++++++++++++----- ...ject-fn-ret-contravariant.transmute.stderr | 2 +- .../project-fn-ret-invariant.transmute.stderr | 2 +- src/test/ui/async-await/issues/issue-62097.rs | 2 +- .../ui/async-await/issues/issue-62097.stderr | 2 +- .../impl-header-lifetime-elision/dyn-trait.rs | 2 +- .../dyn-trait.stderr | 2 +- ...t_outlive_least_region_or_bound.nll.stderr | 16 +-- .../must_outlive_least_region_or_bound.rs | 32 ++---- .../must_outlive_least_region_or_bound.stderr | 58 +++++----- .../static-return-lifetime-infered.nll.stderr | 2 +- .../static-return-lifetime-infered.rs | 6 +- .../static-return-lifetime-infered.stderr | 8 +- src/test/ui/issues/issue-16922.rs | 3 +- src/test/ui/issues/issue-16922.stderr | 2 +- .../constant-in-expr-inherent-1.stderr | 2 +- .../object-lifetime-default-from-box-error.rs | 2 +- ...ect-lifetime-default-from-box-error.stderr | 2 +- .../region-object-lifetime-in-coercion.rs | 6 +- .../region-object-lifetime-in-coercion.stderr | 6 +- src/test/ui/regions/regions-addr-of-self.rs | 2 +- .../ui/regions/regions-addr-of-self.stderr | 2 +- .../regions-close-object-into-object-2.rs | 2 +- .../regions-close-object-into-object-2.stderr | 2 +- .../regions-close-object-into-object-4.rs | 2 +- .../regions-close-object-into-object-4.stderr | 2 +- .../ui/regions/regions-proc-bound-capture.rs | 2 +- .../regions/regions-proc-bound-capture.stderr | 2 +- ...elf_types_pin_lifetime_impl_trait-async.rs | 2 +- ...types_pin_lifetime_impl_trait-async.stderr | 2 +- ...rary_self_types_pin_lifetime_impl_trait.rs | 2 +- ..._self_types_pin_lifetime_impl_trait.stderr | 2 +- ...dyn-trait-with-implicit-static-bound.fixed | 29 ++++- ...rait-with-implicit-static-bound.nll.stderr | 12 +- ...on-dyn-trait-with-implicit-static-bound.rs | 29 ++++- ...yn-trait-with-implicit-static-bound.stderr | 64 +++++++---- .../missing-lifetimes-in-signature.rs | 2 +- .../missing-lifetimes-in-signature.stderr | 2 +- .../trait-object-nested-in-impl-trait.rs | 8 +- .../trait-object-nested-in-impl-trait.stderr | 8 +- .../dyn-trait-underscore.rs | 2 +- .../dyn-trait-underscore.stderr | 2 +- 43 files changed, 280 insertions(+), 167 deletions(-) diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs index bbbd8359f0126..a5d4adae8dba4 100644 --- a/src/librustc_error_codes/error_codes.rs +++ b/src/librustc_error_codes/error_codes.rs @@ -632,4 +632,5 @@ E0770: include_str!("./error_codes/E0770.md"), E0755, // `#[ffi_pure]` is only allowed on foreign functions E0756, // `#[ffi_const]` is only allowed on foreign functions E0757, // `#[ffi_const]` functions cannot be `#[ffi_pure]` + E0767, // `'static' obligation coming from `impl dyn Trait {}` or `impl Foo for dyn Bar {}`. } diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs index 36d354ea777a4..9fa905cb5abe9 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -45,13 +45,31 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let mut err = struct_span_err!( tcx.sess, cause.span, - E0759, - "cannot infer an appropriate lifetime" + E0767, + "{} has {} but calling `{}` introduces an implicit `'static` lifetime \ + requirement", + param + .param + .pat + .simple_ident() + .map(|s| format!("`{}`", s)) + .unwrap_or_else(|| "`fn` parameter".to_string()), + lifetime, + assoc.ident, ); err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime)); err.span_label( cause.span, - "...is captured and required to live as long as `'static` here", + &format!( + "...is captured and required to live as long as `'static` here \ + because of an implicit lifetime bound on the {}", + match assoc.container { + AssocItemContainer::TraitContainer(id) => + format!("`impl` of `{}`", tcx.def_path_str(id)), + AssocItemContainer::ImplContainer(_) => + "inherent `impl`".to_string(), + }, + ), ); if self.find_impl_on_dyn_trait(&mut err, param.param_ty, assoc) { err.emit(); @@ -78,10 +96,49 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } else { ("'_".to_owned(), "an anonymous lifetime `'_`".to_string()) }; - let mut err = struct_span_err!(tcx.sess, sp, E0759, "cannot infer an appropriate lifetime"); + let param_name = param + .param + .pat + .simple_ident() + .map(|s| format!("`{}`", s)) + .unwrap_or_else(|| "`fn` parameter".to_string()); + let mut err = struct_span_err!( + tcx.sess, + sp, + E0759, + "{} has {} but it needs to satisfy a `'static` lifetime requirement", + param_name, + lifetime, + ); err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime)); debug!("try_report_static_impl_trait: param_info={:?}", param); + let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id); + + let mut postfix = String::new(); + if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sup_origin { + if let ObligationCauseCode::UnifyReceiver(assoc) = &cause.code { + if self.find_impl_on_dyn_trait(&mut err, param.param_ty, assoc) + && fn_returns.is_empty() + { + err.code(rustc_errors::error_code!(E0767)); + err.set_primary_message(&format!( + "{} has {} but calling `{}` introduces an implicit `'static` lifetime \ + requirement", + param_name, lifetime, assoc.ident, + )); + postfix = format!( + " because of an implicit lifetime on the {}", + match assoc.container { + AssocItemContainer::TraitContainer(id) => + format!("`impl` of `{}`", tcx.def_path_str(id)), + AssocItemContainer::ImplContainer(_) => "inherent `impl`".to_string(), + }, + ); + } + } + } + // We try to make the output have fewer overlapping spans if possible. if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span())) && sup_origin.span() != return_sp @@ -108,36 +165,35 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // | ---- ^ err.span_label( sup_origin.span(), - "...is captured here, requiring it to live as long as `'static`", + &format!( + "...is captured here, requiring it to live as long as `'static`{}", + postfix + ), ); } else { err.span_label(sup_origin.span(), "...is captured here..."); if return_sp < sup_origin.span() { err.span_note( return_sp, - "...and is required to live as long as `'static` here", + &format!("...and is required to live as long as `'static` here{}", postfix), ); } else { err.span_label( return_sp, - "...and is required to live as long as `'static` here", + &format!("...and is required to live as long as `'static` here{}", postfix), ); } } } else { err.span_label( return_sp, - "...is captured and required to live as long as `'static` here", + &format!( + "...is captured and required to live as long as `'static` here{}", + postfix + ), ); } - if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sup_origin { - if let ObligationCauseCode::UnifyReceiver(assoc) = &cause.code { - self.find_impl_on_dyn_trait(&mut err, param.param_ty, assoc); - } - } - - let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id); debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns); // FIXME: account for the need of parens in `&(dyn Trait + '_)` let consider = "consider changing the"; @@ -295,20 +351,17 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let mut multi_span: MultiSpan = vec![*span].into(); multi_span.push_span_label( *span, - "this trait object has an implicit `'static` lifetime requirement" - .to_string(), + "this has an implicit `'static` lifetime requirement".to_string(), ); multi_span.push_span_label( assoc.ident.span, - "the `'static` requirement is introduced when calling this method" + "`'static` requirement is introduced when calling this method" .to_string(), ); err.span_note( multi_span, &format!( - "when using method `{}` on `{}`, an implicit `'static` \ - requirement is introduced", - assoc.ident, + "`{}`'s inherent `impl` has a `'static` requirement", tcx.def_path_str(*found_did), ), ); @@ -363,22 +416,18 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let mut multi_span: MultiSpan = vec![*span].into(); multi_span.push_span_label( *span, - "this trait object has an implicit `'static` lifetime requirement" - .to_string(), + "this has an implicit `'static` lifetime requirement".to_string(), ); multi_span.push_span_label( method.span, - "the `'static` requirement is introduced when calling this method" - .to_string(), + "`'static` requirement is introduced when calling this method".to_string(), ); err.span_note( multi_span, &format!( - "when using method `{}` of trait `{}` on `{}`, an implicit `'static` \ - requirement is introduced", - method, - tcx.def_path_str(container_id), + "`{}`'s `impl` of `{}` has an implicit `'static` requirement", tcx.def_path_str(*found_did), + tcx.def_path_str(container_id), ), ); err.span_suggestion_verbose( diff --git a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr index 36812d3c0441e..0be9b37263a48 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr @@ -1,4 +1,4 @@ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement --> $DIR/project-fn-ret-contravariant.rs:38:8 | LL | fn baz<'a,'b>(x: &'a u32) -> &'static u32 { diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr index 9cec0780b3ca8..0a44864b24955 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr @@ -1,4 +1,4 @@ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement --> $DIR/project-fn-ret-invariant.rs:49:9 | LL | fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> { diff --git a/src/test/ui/async-await/issues/issue-62097.rs b/src/test/ui/async-await/issues/issue-62097.rs index ea482d3667e2b..66ebbd83ffa9e 100644 --- a/src/test/ui/async-await/issues/issue-62097.rs +++ b/src/test/ui/async-await/issues/issue-62097.rs @@ -9,7 +9,7 @@ where struct Struct; impl Struct { - pub async fn run_dummy_fn(&self) { //~ ERROR cannot infer + pub async fn run_dummy_fn(&self) { //~ ERROR E0759 foo(|| self.bar()).await; } diff --git a/src/test/ui/async-await/issues/issue-62097.stderr b/src/test/ui/async-await/issues/issue-62097.stderr index 0f58b158904db..56a28d904b91d 100644 --- a/src/test/ui/async-await/issues/issue-62097.stderr +++ b/src/test/ui/async-await/issues/issue-62097.stderr @@ -1,4 +1,4 @@ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/issue-62097.rs:12:31 | LL | pub async fn run_dummy_fn(&self) { diff --git a/src/test/ui/impl-header-lifetime-elision/dyn-trait.rs b/src/test/ui/impl-header-lifetime-elision/dyn-trait.rs index d4ad706d01bc2..89210fdf137e0 100644 --- a/src/test/ui/impl-header-lifetime-elision/dyn-trait.rs +++ b/src/test/ui/impl-header-lifetime-elision/dyn-trait.rs @@ -17,7 +17,7 @@ fn static_val(_: T) { } fn with_dyn_debug_static<'a>(x: Box) { - static_val(x); //~ ERROR cannot infer + static_val(x); //~ ERROR E0759 } fn not_static_val(_: T) { diff --git a/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr b/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr index 397cb3750c266..b3bef677d19c1 100644 --- a/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr +++ b/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr @@ -1,4 +1,4 @@ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement --> $DIR/dyn-trait.rs:20:16 | LL | fn with_dyn_debug_static<'a>(x: Box) { diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr index 3b339c5c3d7fc..4372de245078f 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr @@ -12,7 +12,7 @@ LL | fn elided(x: &i32) -> impl Copy + '_ { x } | ^^^^^^^^^^^^^^ error: lifetime may not live long enough - --> $DIR/must_outlive_least_region_or_bound.rs:6:32 + --> $DIR/must_outlive_least_region_or_bound.rs:5:32 | LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x } | -- ^^^^^^^^^ opaque type requires that `'a` must outlive `'static` @@ -26,7 +26,7 @@ LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x } | ^^^^^^^^^^^^^^ error: lifetime may not live long enough - --> $DIR/must_outlive_least_region_or_bound.rs:9:46 + --> $DIR/must_outlive_least_region_or_bound.rs:7:46 | LL | fn elided2(x: &i32) -> impl Copy + 'static { x } | - ^ returning this value requires that `'1` must outlive `'static` @@ -36,7 +36,7 @@ LL | fn elided2(x: &i32) -> impl Copy + 'static { x } = help: consider replacing `'1` with `'static` error: lifetime may not live long enough - --> $DIR/must_outlive_least_region_or_bound.rs:12:55 + --> $DIR/must_outlive_least_region_or_bound.rs:9:55 | LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } | -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static` @@ -45,7 +45,7 @@ LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } = help: consider replacing `'a` with `'static` error[E0621]: explicit lifetime required in the type of `x` - --> $DIR/must_outlive_least_region_or_bound.rs:15:41 + --> $DIR/must_outlive_least_region_or_bound.rs:11:41 | LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x } | ---- ^ lifetime `'a` required @@ -53,7 +53,7 @@ LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x } | help: add explicit lifetime `'a` to the type of `x`: `&'a i32` error: lifetime may not live long enough - --> $DIR/must_outlive_least_region_or_bound.rs:30:24 + --> $DIR/must_outlive_least_region_or_bound.rs:22:24 | LL | fn elided5(x: &i32) -> (Box, impl Debug) { (Box::new(x), x) } | - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'1` must outlive `'static` @@ -61,7 +61,7 @@ LL | fn elided5(x: &i32) -> (Box, impl Debug) { (Box::new(x), x) } | let's call the lifetime of this reference `'1` error: lifetime may not live long enough - --> $DIR/must_outlive_least_region_or_bound.rs:37:69 + --> $DIR/must_outlive_least_region_or_bound.rs:28:69 | LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } | -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static` @@ -70,7 +70,7 @@ LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } = help: consider replacing `'a` with `'static` error: lifetime may not live long enough - --> $DIR/must_outlive_least_region_or_bound.rs:42:61 + --> $DIR/must_outlive_least_region_or_bound.rs:32:61 | LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) { | -- -- lifetime `'b` defined here ^^^^^^^^^^^^^^^^ opaque type requires that `'b` must outlive `'a` @@ -80,7 +80,7 @@ LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32 = help: consider adding the following bound: `'b: 'a` error[E0310]: the parameter type `T` may not live long enough - --> $DIR/must_outlive_least_region_or_bound.rs:47:51 + --> $DIR/must_outlive_least_region_or_bound.rs:37:51 | LL | fn ty_param_wont_outlive_static(x: T) -> impl Debug + 'static { | ^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs index 9bf86fa66cded..51f488e45a6f3 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs @@ -1,41 +1,31 @@ use std::fmt::Debug; -fn elided(x: &i32) -> impl Copy { x } -//~^ ERROR cannot infer an appropriate lifetime +fn elided(x: &i32) -> impl Copy { x } //~ ERROR E0759 -fn explicit<'a>(x: &'a i32) -> impl Copy { x } -//~^ ERROR cannot infer an appropriate lifetime +fn explicit<'a>(x: &'a i32) -> impl Copy { x } //~ ERROR E0759 -fn elided2(x: &i32) -> impl Copy + 'static { x } -//~^ ERROR cannot infer an appropriate lifetime +fn elided2(x: &i32) -> impl Copy + 'static { x } //~ ERROR E0759 -fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } -//~^ ERROR cannot infer an appropriate lifetime +fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } //~ ERROR E0759 fn foo<'a>(x: &i32) -> impl Copy + 'a { x } //~^ ERROR explicit lifetime required in the type of `x` -fn elided3(x: &i32) -> Box { Box::new(x) } -//~^ ERROR cannot infer an appropriate lifetime +fn elided3(x: &i32) -> Box { Box::new(x) } //~ ERROR E0759 -fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) } -//~^ ERROR cannot infer an appropriate lifetime +fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) } //~ ERROR E0759 -fn elided4(x: &i32) -> Box { Box::new(x) } -//~^ ERROR cannot infer an appropriate lifetime +fn elided4(x: &i32) -> Box { Box::new(x) } //~ ERROR E0759 -fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } -//~^ ERROR cannot infer an appropriate lifetime +fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } //~ ERROR E0759 -fn elided5(x: &i32) -> (Box, impl Debug) { (Box::new(x), x) } -//~^ ERROR cannot infer an appropriate lifetime -//~| ERROR cannot infer an appropriate lifetime +fn elided5(x: &i32) -> (Box, impl Debug) { (Box::new(x), x) } //~ ERROR E0759 +//~^ ERROR E0759 trait LifetimeTrait<'a> {} impl<'a> LifetimeTrait<'a> for &'a i32 {} -fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } -//~^ ERROR cannot infer an appropriate lifetime +fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } //~ ERROR E0759 // Tests that a closure type containing 'b cannot be returned from a type where // only 'a was expected. diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr index ffadcaae08e05..b040889217e47 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -1,4 +1,4 @@ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/must_outlive_least_region_or_bound.rs:3:35 | LL | fn elided(x: &i32) -> impl Copy { x } @@ -16,8 +16,8 @@ help: to declare that the `impl Trait` captures data from argument `x`, you can LL | fn elided(x: &i32) -> impl Copy + '_ { x } | ^^^^ -error[E0759]: cannot infer an appropriate lifetime - --> $DIR/must_outlive_least_region_or_bound.rs:6:44 +error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement + --> $DIR/must_outlive_least_region_or_bound.rs:5:44 | LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x } | ------- ^ ...is captured here... @@ -25,7 +25,7 @@ LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x } | this data with lifetime `'a`... | note: ...and is required to live as long as `'static` here - --> $DIR/must_outlive_least_region_or_bound.rs:6:32 + --> $DIR/must_outlive_least_region_or_bound.rs:5:32 | LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x } | ^^^^^^^^^ @@ -34,8 +34,8 @@ help: to declare that the `impl Trait` captures data from argument `x`, you can LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x } | ^^^^ -error[E0759]: cannot infer an appropriate lifetime - --> $DIR/must_outlive_least_region_or_bound.rs:9:46 +error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement + --> $DIR/must_outlive_least_region_or_bound.rs:7:46 | LL | fn elided2(x: &i32) -> impl Copy + 'static { x } | ---- ^ ...is captured here... @@ -43,7 +43,7 @@ LL | fn elided2(x: &i32) -> impl Copy + 'static { x } | this data with an anonymous lifetime `'_`... | note: ...and is required to live as long as `'static` here - --> $DIR/must_outlive_least_region_or_bound.rs:9:24 + --> $DIR/must_outlive_least_region_or_bound.rs:7:24 | LL | fn elided2(x: &i32) -> impl Copy + 'static { x } | ^^^^^^^^^^^^^^^^^^^ @@ -56,8 +56,8 @@ help: alternatively, add an explicit `'static` bound to this reference LL | fn elided2(x: &'static i32) -> impl Copy + 'static { x } | ^^^^^^^^^^^^ -error[E0759]: cannot infer an appropriate lifetime - --> $DIR/must_outlive_least_region_or_bound.rs:12:55 +error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement + --> $DIR/must_outlive_least_region_or_bound.rs:9:55 | LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } | ------- ^ ...is captured here... @@ -65,7 +65,7 @@ LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } | this data with lifetime `'a`... | note: ...and is required to live as long as `'static` here - --> $DIR/must_outlive_least_region_or_bound.rs:12:33 + --> $DIR/must_outlive_least_region_or_bound.rs:9:33 | LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } | ^^^^^^^^^^^^^^^^^^^ @@ -79,15 +79,15 @@ LL | fn explicit2<'a>(x: &'static i32) -> impl Copy + 'static { x } | ^^^^^^^^^^^^ error[E0621]: explicit lifetime required in the type of `x` - --> $DIR/must_outlive_least_region_or_bound.rs:15:24 + --> $DIR/must_outlive_least_region_or_bound.rs:11:24 | LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x } | ---- ^^^^^^^^^^^^^^ lifetime `'a` required | | | help: add explicit lifetime `'a` to the type of `x`: `&'a i32` -error[E0759]: cannot infer an appropriate lifetime - --> $DIR/must_outlive_least_region_or_bound.rs:30:65 +error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement + --> $DIR/must_outlive_least_region_or_bound.rs:22:65 | LL | fn elided5(x: &i32) -> (Box, impl Debug) { (Box::new(x), x) } | ---- this data with an anonymous lifetime `'_`... ^ ...is captured here, requiring it to live as long as `'static` @@ -101,14 +101,14 @@ help: to declare that the `impl Trait` captures data from argument `x`, you can LL | fn elided5(x: &i32) -> (Box, impl Debug + '_) { (Box::new(x), x) } | ^^^^ -error[E0759]: cannot infer an appropriate lifetime - --> $DIR/must_outlive_least_region_or_bound.rs:30:69 +error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement + --> $DIR/must_outlive_least_region_or_bound.rs:22:69 | LL | fn elided5(x: &i32) -> (Box, impl Debug) { (Box::new(x), x) } | ---- this data with an anonymous lifetime `'_`... ^ ...is captured here... | note: ...and is required to live as long as `'static` here - --> $DIR/must_outlive_least_region_or_bound.rs:30:41 + --> $DIR/must_outlive_least_region_or_bound.rs:22:41 | LL | fn elided5(x: &i32) -> (Box, impl Debug) { (Box::new(x), x) } | ^^^^^^^^^^ @@ -121,14 +121,14 @@ help: to declare that the `impl Trait` captures data from argument `x`, you can LL | fn elided5(x: &i32) -> (Box, impl Debug + '_) { (Box::new(x), x) } | ^^^^ -error[E0759]: cannot infer an appropriate lifetime - --> $DIR/must_outlive_least_region_or_bound.rs:37:69 +error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement + --> $DIR/must_outlive_least_region_or_bound.rs:28:69 | LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } | ------- this data with lifetime `'a`... ^ ...is captured here... | note: ...and is required to live as long as `'static` here - --> $DIR/must_outlive_least_region_or_bound.rs:37:34 + --> $DIR/must_outlive_least_region_or_bound.rs:28:34 | LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -142,7 +142,7 @@ LL | fn with_bound<'a>(x: &'static i32) -> impl LifetimeTrait<'a> + 'static { x | ^^^^^^^^^^^^ error[E0623]: lifetime mismatch - --> $DIR/must_outlive_least_region_or_bound.rs:42:61 + --> $DIR/must_outlive_least_region_or_bound.rs:32:61 | LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) { | ------- ^^^^^^^^^^^^^^^^ @@ -151,15 +151,15 @@ LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32 | this parameter and the return type are declared with different lifetimes... error[E0310]: the parameter type `T` may not live long enough - --> $DIR/must_outlive_least_region_or_bound.rs:47:51 + --> $DIR/must_outlive_least_region_or_bound.rs:37:51 | LL | fn ty_param_wont_outlive_static(x: T) -> impl Debug + 'static { | -- ^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds | | | help: consider adding an explicit lifetime bound...: `T: 'static +` -error[E0759]: cannot infer an appropriate lifetime - --> $DIR/must_outlive_least_region_or_bound.rs:18:50 +error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement + --> $DIR/must_outlive_least_region_or_bound.rs:14:50 | LL | fn elided3(x: &i32) -> Box { Box::new(x) } | ---- ^ ...is captured here, requiring it to live as long as `'static` @@ -171,8 +171,8 @@ help: to declare that the trait object captures data from argument `x`, you can LL | fn elided3(x: &i32) -> Box { Box::new(x) } | ^^^^ -error[E0759]: cannot infer an appropriate lifetime - --> $DIR/must_outlive_least_region_or_bound.rs:21:59 +error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement + --> $DIR/must_outlive_least_region_or_bound.rs:16:59 | LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) } | ------- ^ ...is captured here, requiring it to live as long as `'static` @@ -184,8 +184,8 @@ help: to declare that the trait object captures data from argument `x`, you can LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) } | ^^^^ -error[E0759]: cannot infer an appropriate lifetime - --> $DIR/must_outlive_least_region_or_bound.rs:24:60 +error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement + --> $DIR/must_outlive_least_region_or_bound.rs:18:60 | LL | fn elided4(x: &i32) -> Box { Box::new(x) } | ---- ^ ...is captured here, requiring it to live as long as `'static` @@ -201,8 +201,8 @@ help: alternatively, add an explicit `'static` bound to this reference LL | fn elided4(x: &'static i32) -> Box { Box::new(x) } | ^^^^^^^^^^^^ -error[E0759]: cannot infer an appropriate lifetime - --> $DIR/must_outlive_least_region_or_bound.rs:27:69 +error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement + --> $DIR/must_outlive_least_region_or_bound.rs:20:69 | LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } | ------- this data with lifetime `'a`... ^ ...is captured here, requiring it to live as long as `'static` diff --git a/src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr b/src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr index 123ea6af6b019..65178cc9d24c2 100644 --- a/src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr +++ b/src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr @@ -12,7 +12,7 @@ LL | fn iter_values_anon(&self) -> impl Iterator + '_ { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: lifetime may not live long enough - --> $DIR/static-return-lifetime-infered.rs:10:37 + --> $DIR/static-return-lifetime-infered.rs:9:37 | LL | fn iter_values<'a>(&'a self) -> impl Iterator { | -- ^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'a` must outlive `'static` diff --git a/src/test/ui/impl-trait/static-return-lifetime-infered.rs b/src/test/ui/impl-trait/static-return-lifetime-infered.rs index 96f3652c226ea..518c52f5de4d7 100644 --- a/src/test/ui/impl-trait/static-return-lifetime-infered.rs +++ b/src/test/ui/impl-trait/static-return-lifetime-infered.rs @@ -4,13 +4,11 @@ struct A { impl A { fn iter_values_anon(&self) -> impl Iterator { - self.x.iter().map(|a| a.0) + self.x.iter().map(|a| a.0) //~ ERROR E0759 } - //~^^ ERROR cannot infer an appropriate lifetime fn iter_values<'a>(&'a self) -> impl Iterator { - self.x.iter().map(|a| a.0) + self.x.iter().map(|a| a.0) //~ ERROR E0759 } - //~^^ ERROR cannot infer an appropriate lifetime } fn main() {} diff --git a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr index df0db6e4fc6df..7c289b388223a 100644 --- a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr +++ b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr @@ -1,4 +1,4 @@ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/static-return-lifetime-infered.rs:7:16 | LL | fn iter_values_anon(&self) -> impl Iterator { @@ -18,8 +18,8 @@ help: to declare that the `impl Trait` captures data from argument `self`, you c LL | fn iter_values_anon(&self) -> impl Iterator + '_ { | ^^^^ -error[E0759]: cannot infer an appropriate lifetime - --> $DIR/static-return-lifetime-infered.rs:11:16 +error[E0759]: `self` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement + --> $DIR/static-return-lifetime-infered.rs:10:16 | LL | fn iter_values<'a>(&'a self) -> impl Iterator { | -------- this data with lifetime `'a`... @@ -29,7 +29,7 @@ LL | self.x.iter().map(|a| a.0) | ...is captured here... | note: ...and is required to live as long as `'static` here - --> $DIR/static-return-lifetime-infered.rs:10:37 + --> $DIR/static-return-lifetime-infered.rs:9:37 | LL | fn iter_values<'a>(&'a self) -> impl Iterator { | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/issues/issue-16922.rs b/src/test/ui/issues/issue-16922.rs index 827163ef83cf7..f048ccd2427cb 100644 --- a/src/test/ui/issues/issue-16922.rs +++ b/src/test/ui/issues/issue-16922.rs @@ -1,8 +1,7 @@ use std::any::Any; fn foo(value: &T) -> Box { - Box::new(value) as Box - //~^ ERROR cannot infer an appropriate lifetime + Box::new(value) as Box //~ ERROR E0759 } fn main() { diff --git a/src/test/ui/issues/issue-16922.stderr b/src/test/ui/issues/issue-16922.stderr index 919594fc9af4b..6decc751321f9 100644 --- a/src/test/ui/issues/issue-16922.stderr +++ b/src/test/ui/issues/issue-16922.stderr @@ -1,4 +1,4 @@ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `value` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/issue-16922.rs:4:14 | LL | fn foo(value: &T) -> Box { diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr index f823f69c76f67..1931934a2112a 100644 --- a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr +++ b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr @@ -1,4 +1,4 @@ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `fn` parameter has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement --> $DIR/constant-in-expr-inherent-1.rs:8:5 | LL | fn foo<'a>(_: &'a u32) -> &'static u32 { diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.rs b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.rs index 708ab1cf38297..4a2665d8e1694 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.rs +++ b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.rs @@ -15,7 +15,7 @@ fn load(ss: &mut SomeStruct) -> Box { // `Box` defaults to a `'static` bound, so this return // is illegal. - ss.r //~ ERROR cannot infer an appropriate lifetime + ss.r //~ ERROR E0759 } fn store(ss: &mut SomeStruct, b: Box) { diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr index 1b1e0d9610724..70b99ef7869ca 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr @@ -1,4 +1,4 @@ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `ss` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/object-lifetime-default-from-box-error.rs:18:5 | LL | fn load(ss: &mut SomeStruct) -> Box { diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.rs b/src/test/ui/regions/region-object-lifetime-in-coercion.rs index 5d199149c39b8..9d3f485e31438 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.rs +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.rs @@ -5,18 +5,18 @@ trait Foo {} impl<'a> Foo for &'a [u8] {} fn a(v: &[u8]) -> Box { - let x: Box = Box::new(v); //~ ERROR cannot infer an appropriate lifetime + let x: Box = Box::new(v); //~ ERROR E0759 x } fn b(v: &[u8]) -> Box { - Box::new(v) //~ ERROR cannot infer an appropriate lifetime + Box::new(v) //~ ERROR E0759 } fn c(v: &[u8]) -> Box { // same as previous case due to RFC 599 - Box::new(v) //~ ERROR cannot infer an appropriate lifetime + Box::new(v) //~ ERROR E0759 } fn d<'a,'b>(v: &'a [u8]) -> Box { diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr index 7f5a3a47976c7..63fea1f41626d 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr @@ -1,4 +1,4 @@ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/region-object-lifetime-in-coercion.rs:8:46 | LL | fn a(v: &[u8]) -> Box { @@ -15,7 +15,7 @@ help: alternatively, add an explicit `'static` bound to this reference LL | fn a(v: &'static [u8]) -> Box { | ^^^^^^^^^^^^^ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/region-object-lifetime-in-coercion.rs:13:14 | LL | fn b(v: &[u8]) -> Box { @@ -32,7 +32,7 @@ help: alternatively, add an explicit `'static` bound to this reference LL | fn b(v: &'static [u8]) -> Box { | ^^^^^^^^^^^^^ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/region-object-lifetime-in-coercion.rs:19:14 | LL | fn c(v: &[u8]) -> Box { diff --git a/src/test/ui/regions/regions-addr-of-self.rs b/src/test/ui/regions/regions-addr-of-self.rs index 647212407fc8a..4eb1b275f163e 100644 --- a/src/test/ui/regions/regions-addr-of-self.rs +++ b/src/test/ui/regions/regions-addr-of-self.rs @@ -4,7 +4,7 @@ struct Dog { impl Dog { pub fn chase_cat(&mut self) { - let p: &'static mut usize = &mut self.cats_chased; //~ ERROR cannot infer + let p: &'static mut usize = &mut self.cats_chased; //~ ERROR E0759 *p += 1; } diff --git a/src/test/ui/regions/regions-addr-of-self.stderr b/src/test/ui/regions/regions-addr-of-self.stderr index c15a933379c85..738691fd695eb 100644 --- a/src/test/ui/regions/regions-addr-of-self.stderr +++ b/src/test/ui/regions/regions-addr-of-self.stderr @@ -1,4 +1,4 @@ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/regions-addr-of-self.rs:7:37 | LL | pub fn chase_cat(&mut self) { diff --git a/src/test/ui/regions/regions-close-object-into-object-2.rs b/src/test/ui/regions/regions-close-object-into-object-2.rs index 2364ba2728600..7144ab5a24c51 100644 --- a/src/test/ui/regions/regions-close-object-into-object-2.rs +++ b/src/test/ui/regions/regions-close-object-into-object-2.rs @@ -7,7 +7,7 @@ trait X { } impl<'a, T> X for B<'a, T> {} fn g<'a, T: 'static>(v: Box + 'a>) -> Box { - box B(&*v) as Box //~ ERROR cannot infer + box B(&*v) as Box //~ ERROR E0759 } fn main() { } diff --git a/src/test/ui/regions/regions-close-object-into-object-2.stderr b/src/test/ui/regions/regions-close-object-into-object-2.stderr index 114e4052aae09..aab7ce993aa3c 100644 --- a/src/test/ui/regions/regions-close-object-into-object-2.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-2.stderr @@ -1,4 +1,4 @@ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `v` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement --> $DIR/regions-close-object-into-object-2.rs:10:11 | LL | fn g<'a, T: 'static>(v: Box + 'a>) -> Box { diff --git a/src/test/ui/regions/regions-close-object-into-object-4.rs b/src/test/ui/regions/regions-close-object-into-object-4.rs index d531077043686..4c087f264f92b 100644 --- a/src/test/ui/regions/regions-close-object-into-object-4.rs +++ b/src/test/ui/regions/regions-close-object-into-object-4.rs @@ -7,7 +7,7 @@ trait X { } impl<'a, T> X for B<'a, T> {} fn i<'a, T, U>(v: Box+'a>) -> Box { - box B(&*v) as Box //~ ERROR cannot infer + box B(&*v) as Box //~ ERROR E0759 } fn main() {} diff --git a/src/test/ui/regions/regions-close-object-into-object-4.stderr b/src/test/ui/regions/regions-close-object-into-object-4.stderr index 850d81940791f..90f807a41c562 100644 --- a/src/test/ui/regions/regions-close-object-into-object-4.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-4.stderr @@ -1,4 +1,4 @@ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `v` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement --> $DIR/regions-close-object-into-object-4.rs:10:11 | LL | fn i<'a, T, U>(v: Box+'a>) -> Box { diff --git a/src/test/ui/regions/regions-proc-bound-capture.rs b/src/test/ui/regions/regions-proc-bound-capture.rs index 8617c0e9da8f7..55d964ac53405 100644 --- a/src/test/ui/regions/regions-proc-bound-capture.rs +++ b/src/test/ui/regions/regions-proc-bound-capture.rs @@ -6,7 +6,7 @@ fn borrowed_proc<'a>(x: &'a isize) -> Box(isize) + 'a> { fn static_proc(x: &isize) -> Box (isize) + 'static> { // This is illegal, because the region bound on `proc` is 'static. - Box::new(move || { *x }) //~ ERROR cannot infer an appropriate lifetime + Box::new(move || { *x }) //~ ERROR E0759 } fn main() { } diff --git a/src/test/ui/regions/regions-proc-bound-capture.stderr b/src/test/ui/regions/regions-proc-bound-capture.stderr index 67eee3bb6e281..e76073f4f6b13 100644 --- a/src/test/ui/regions/regions-proc-bound-capture.stderr +++ b/src/test/ui/regions/regions-proc-bound-capture.stderr @@ -1,4 +1,4 @@ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/regions-proc-bound-capture.rs:9:14 | LL | fn static_proc(x: &isize) -> Box (isize) + 'static> { diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.rs b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.rs index 0afe631f1e3fc..43998ca8c5784 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.rs +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.rs @@ -6,7 +6,7 @@ struct Foo; impl Foo { async fn f(self: Pin<&Self>) -> impl Clone { self } - //~^ ERROR cannot infer an appropriate lifetime + //~^ ERROR E0759 } fn main() { diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr index f2fbb0ba7d755..9cd0fd328ffa0 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr @@ -1,4 +1,4 @@ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:16 | LL | async fn f(self: Pin<&Self>) -> impl Clone { self } diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.rs b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.rs index 5054568b18970..04935fc52ab9e 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.rs +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.rs @@ -3,7 +3,7 @@ use std::pin::Pin; struct Foo; impl Foo { - fn f(self: Pin<&Self>) -> impl Clone { self } //~ ERROR cannot infer an appropriate lifetime + fn f(self: Pin<&Self>) -> impl Clone { self } //~ ERROR E0759 } fn main() { diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr index 2e10ab3d3f9b8..cb9d5b56dbc5c 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr @@ -1,4 +1,4 @@ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:6:44 | LL | fn f(self: Pin<&Self>) -> impl Clone { self } diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.fixed b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.fixed index 62cf9b989bb4d..832b185e619fa 100644 --- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.fixed +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.fixed @@ -17,7 +17,7 @@ mod foo { impl Irrelevant for dyn ObjectTrait {} fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { - val.use_self() //~ ERROR cannot infer an appropriate lifetime + val.use_self() //~ ERROR E0759 } } @@ -34,7 +34,7 @@ mod bar { impl Irrelevant for dyn ObjectTrait {} fn use_it<'a>(val: &'a dyn ObjectTrait) -> &'a () { - val.use_self() //~ ERROR cannot infer an appropriate lifetime + val.use_self() //~ ERROR E0767 } } @@ -51,7 +51,7 @@ mod baz { impl Irrelevant for Box {} fn use_it<'a>(val: &'a Box) -> &'a () { - val.use_self() //~ ERROR cannot infer an appropriate lifetime + val.use_self() //~ ERROR E0767 } } @@ -66,8 +66,29 @@ mod bat { } fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { - val.use_self() //~ ERROR cannot infer an appropriate lifetime + val.use_self() //~ ERROR E0767 } } +mod ban { + trait OtherTrait<'a> {} + impl<'a> OtherTrait<'a> for &'a () {} + + trait ObjectTrait {} + trait MyTrait { + fn use_self(&self) -> &(); + } + trait Irrelevant {} + + impl MyTrait for dyn ObjectTrait + '_ { + fn use_self(&self) -> &() { panic!() } + } + impl Irrelevant for dyn ObjectTrait {} + + fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { + val.use_self() //~ ERROR E0759 + } +} + + fn main() {} diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr index 00f65a2348935..8765591c4a114 100644 --- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr @@ -18,5 +18,15 @@ LL | val.use_self() | = help: consider replacing `'a` with `'static` -error: aborting due to 2 previous errors +error[E0521]: borrowed data escapes outside of function + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:89:9 + | +LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> { + | --- `val` is a reference that is only valid in the function body +LL | val.use_self() + | ^^^^^^^^^^^^^^ `val` escapes the function body here + | + = help: consider replacing `'a` with `'static` + +error: aborting due to 3 previous errors diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.rs b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.rs index 28a599d12bfd1..ba26c2d67dfa8 100644 --- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.rs +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.rs @@ -17,7 +17,7 @@ mod foo { impl Irrelevant for dyn ObjectTrait {} fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { - val.use_self() //~ ERROR cannot infer an appropriate lifetime + val.use_self() //~ ERROR E0759 } } @@ -34,7 +34,7 @@ mod bar { impl Irrelevant for dyn ObjectTrait {} fn use_it<'a>(val: &'a dyn ObjectTrait) -> &'a () { - val.use_self() //~ ERROR cannot infer an appropriate lifetime + val.use_self() //~ ERROR E0767 } } @@ -51,7 +51,7 @@ mod baz { impl Irrelevant for Box {} fn use_it<'a>(val: &'a Box) -> &'a () { - val.use_self() //~ ERROR cannot infer an appropriate lifetime + val.use_self() //~ ERROR E0767 } } @@ -66,8 +66,29 @@ mod bat { } fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { - val.use_self() //~ ERROR cannot infer an appropriate lifetime + val.use_self() //~ ERROR E0767 } } +mod ban { + trait OtherTrait<'a> {} + impl<'a> OtherTrait<'a> for &'a () {} + + trait ObjectTrait {} + trait MyTrait { + fn use_self(&self) -> &(); + } + trait Irrelevant {} + + impl MyTrait for dyn ObjectTrait { + fn use_self(&self) -> &() { panic!() } + } + impl Irrelevant for dyn ObjectTrait {} + + fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> { + val.use_self() //~ ERROR E0759 + } +} + + fn main() {} diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr index 8f8fd9dc32402..425159edbcd4a 100644 --- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr @@ -1,4 +1,4 @@ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `val` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:20:13 | LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { @@ -6,78 +6,102 @@ LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { LL | val.use_self() | ^^^^^^^^ ...is captured and required to live as long as `'static` here | -note: when using method `use_self` of trait `foo::MyTrait` on `foo::ObjectTrait`, an implicit `'static` requirement is introduced +note: `foo::ObjectTrait`'s `impl` of `foo::MyTrait` has an implicit `'static` requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:14:26 | LL | impl MyTrait for dyn ObjectTrait { - | ^^^^^^^^^^^ this trait object has an implicit `'static` lifetime requirement + | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement LL | fn use_self(&self) -> &() { panic!() } - | -------- the `'static` requirement is introduced when calling this method + | -------- `'static` requirement is introduced when calling this method help: consider relaxing the implicit `'static` requirement | LL | impl MyTrait for dyn ObjectTrait + '_ { | ^^^^ -error[E0759]: cannot infer an appropriate lifetime +error[E0767]: `val` has lifetime `'a` but calling `use_self` introduces an implicit `'static` lifetime requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:69:13 | LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { | ------------------- this data with lifetime `'a`... LL | val.use_self() - | ^^^^^^^^ ...is captured and required to live as long as `'static` here + | ^^^^^^^^ ...is captured and required to live as long as `'static` here because of an implicit lifetime bound on the inherent `impl` | -note: when using method `use_self` on `bat::ObjectTrait`, an implicit `'static` requirement is introduced +note: `bat::ObjectTrait`'s inherent `impl` has a `'static` requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:64:14 | LL | impl dyn ObjectTrait { - | ^^^^^^^^^^^ this trait object has an implicit `'static` lifetime requirement + | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement LL | fn use_self(&self) -> &() { panic!() } - | -------- the `'static` requirement is introduced when calling this method + | -------- `'static` requirement is introduced when calling this method help: consider relaxing the implicit `'static` requirement | LL | impl dyn ObjectTrait + '_ { | ^^^^ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `val` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:89:13 + | +LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> { + | ------------------- this data with lifetime `'a`... +LL | val.use_self() + | ^^^^^^^^ ...is captured and required to live as long as `'static` here + | +note: `ban::ObjectTrait`'s `impl` of `ban::MyTrait` has an implicit `'static` requirement + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:83:26 + | +LL | impl MyTrait for dyn ObjectTrait { + | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement +LL | fn use_self(&self) -> &() { panic!() } + | -------- `'static` requirement is introduced when calling this method +help: consider relaxing the implicit `'static` requirement + | +LL | impl MyTrait for dyn ObjectTrait + '_ { + | ^^^^ +help: to declare that the `impl Trait` captures data from argument `val`, you can add an explicit `'a` lifetime bound + | +LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { + | ^^^^ + +error[E0767]: `val` has lifetime `'a` but calling `use_self` introduces an implicit `'static` lifetime requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:37:13 | LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> &'a () { | ------------------- this data with lifetime `'a`... LL | val.use_self() - | ^^^^^^^^ ...is captured and required to live as long as `'static` here + | ^^^^^^^^ ...is captured and required to live as long as `'static` here because of an implicit lifetime on the `impl` of `bar::MyTrait` | -note: when using method `use_self` of trait `bar::MyTrait` on `bar::ObjectTrait`, an implicit `'static` requirement is introduced +note: `bar::ObjectTrait`'s `impl` of `bar::MyTrait` has an implicit `'static` requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:31:26 | LL | impl MyTrait for dyn ObjectTrait { - | ^^^^^^^^^^^ this trait object has an implicit `'static` lifetime requirement + | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement LL | fn use_self(&self) -> &() { panic!() } - | -------- the `'static` requirement is introduced when calling this method + | -------- `'static` requirement is introduced when calling this method help: consider relaxing the implicit `'static` requirement | LL | impl MyTrait for dyn ObjectTrait + '_ { | ^^^^ -error[E0759]: cannot infer an appropriate lifetime +error[E0767]: `val` has lifetime `'a` but calling `use_self` introduces an implicit `'static` lifetime requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:54:13 | LL | fn use_it<'a>(val: &'a Box) -> &'a () { | ----------------------------- this data with lifetime `'a`... LL | val.use_self() - | ^^^^^^^^ ...is captured and required to live as long as `'static` here + | ^^^^^^^^ ...is captured and required to live as long as `'static` here because of an implicit lifetime on the `impl` of `baz::MyTrait` | -note: when using method `use_self` of trait `baz::MyTrait` on `baz::ObjectTrait`, an implicit `'static` requirement is introduced +note: `baz::ObjectTrait`'s `impl` of `baz::MyTrait` has an implicit `'static` requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:48:30 | LL | impl MyTrait for Box { - | ^^^^^^^^^^^ this trait object has an implicit `'static` lifetime requirement + | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement LL | fn use_self(&self) -> &() { panic!() } - | -------- the `'static` requirement is introduced when calling this method + | -------- `'static` requirement is introduced when calling this method help: consider relaxing the implicit `'static` requirement | LL | impl MyTrait for Box { | ^^^^ -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0759`. diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs index d3853445dfdfe..94dd826a15cae 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs @@ -16,7 +16,7 @@ fn foo(g: G, dest: &mut T) -> impl FnOnce() where G: Get { - move || { //~ ERROR cannot infer an appropriate lifetime + move || { //~ ERROR `dest` *dest = g.get(); } } diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr index 9ab060328537b..d7051515f1102 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr @@ -6,7 +6,7 @@ LL | fn baz(g: G, dest: &mut T) -> impl FnOnce() + '_ | | | help: consider introducing lifetime `'a` here: `'a,` -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `dest` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/missing-lifetimes-in-signature.rs:19:5 | LL | fn foo(g: G, dest: &mut T) -> impl FnOnce() diff --git a/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.rs b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.rs index f78edb1c83a4c..d8446e58dbb63 100644 --- a/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.rs +++ b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.rs @@ -27,7 +27,7 @@ impl Bar { fn iter(&self) -> impl Iterator> { Iter { current: None, - remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime + remaining: self.0.iter(), //~ ERROR E0759 } } } @@ -38,7 +38,7 @@ impl Baz { fn iter(&self) -> impl Iterator> + '_ { Iter { current: None, - remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime + remaining: self.0.iter(), //~ ERROR E0759 } } } @@ -49,7 +49,7 @@ impl Bat { fn iter<'a>(&'a self) -> impl Iterator> + 'a { Iter { current: None, - remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime + remaining: self.0.iter(), //~ ERROR E0759 } } } @@ -60,7 +60,7 @@ impl Ban { fn iter<'a>(&'a self) -> impl Iterator> { Iter { current: None, - remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime + remaining: self.0.iter(), //~ ERROR E0759 } } } diff --git a/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr index 1257e9b172cf7..9f30787f07cc6 100644 --- a/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr +++ b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr @@ -1,4 +1,4 @@ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/trait-object-nested-in-impl-trait.rs:30:31 | LL | fn iter(&self) -> impl Iterator> { @@ -23,7 +23,7 @@ help: to declare that the trait object captures data from argument `self`, you c LL | fn iter(&self) -> impl Iterator> { | ^^^^ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/trait-object-nested-in-impl-trait.rs:41:31 | LL | fn iter(&self) -> impl Iterator> + '_ { @@ -44,7 +44,7 @@ help: to declare that the trait object captures data from argument `self`, you c LL | fn iter(&self) -> impl Iterator> + '_ { | ^^^^ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `self` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement --> $DIR/trait-object-nested-in-impl-trait.rs:52:31 | LL | fn iter<'a>(&'a self) -> impl Iterator> + 'a { @@ -65,7 +65,7 @@ help: to declare that the trait object captures data from argument `self`, you c LL | fn iter<'a>(&'a self) -> impl Iterator> + 'a { | ^^^^ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `self` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement --> $DIR/trait-object-nested-in-impl-trait.rs:63:31 | LL | fn iter<'a>(&'a self) -> impl Iterator> { diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.rs b/src/test/ui/underscore-lifetime/dyn-trait-underscore.rs index d5aa18eb0f4e7..e951adf030f5c 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.rs +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.rs @@ -5,7 +5,7 @@ fn a(items: &[T]) -> Box> { // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static` - Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime + Box::new(items.iter()) //~ ERROR E0759 } fn b(items: &[T]) -> Box + '_> { diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr index dda5de431d309..dd804864dab4f 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr @@ -1,4 +1,4 @@ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `items` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/dyn-trait-underscore.rs:8:20 | LL | fn a(items: &[T]) -> Box> { From b795cf1f8b7afefbbf1121a04786068dd3efb17c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 30 Jun 2020 17:41:15 -0700 Subject: [PATCH 19/30] Use `ty::Instance::resolve` to identify `'static` bound source --- .../nice_region_error/static_impl_trait.rs | 221 ++++++++---------- src/librustc_middle/traits/mod.rs | 9 +- .../traits/structural_impls.rs | 15 +- .../traits/codegen/mod.rs | 13 ++ .../traits/error_reporting/suggestions.rs | 2 +- src/librustc_typeck/check/method/confirm.rs | 15 +- ...dyn-trait-with-implicit-static-bound.fixed | 23 +- ...rait-with-implicit-static-bound.nll.stderr | 10 +- ...on-dyn-trait-with-implicit-static-bound.rs | 23 +- ...yn-trait-with-implicit-static-bound.stderr | 47 ++-- 10 files changed, 196 insertions(+), 182 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs index 9fa905cb5abe9..9c2e02968f607 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -3,18 +3,20 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::{SubregionOrigin, TypeTrace}; -use crate::traits::ObligationCauseCode; +use crate::traits::{ObligationCauseCode, UnifyReceiverContext}; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported}; -use rustc_hir::def_id::{DefId, LOCAL_CRATE}; +use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{walk_ty, ErasedMap, NestedVisitorMap, Visitor}; -use rustc_hir::{self as hir, GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, TyKind}; -use rustc_middle::ty::{ - self, AssocItem, AssocItemContainer, RegionKind, Ty, TypeFoldable, TypeVisitor, +use rustc_hir::{ + self as hir, GenericBound, ImplItem, Item, ItemKind, Lifetime, LifetimeName, Node, TraitItem, + TyKind, }; +use rustc_middle::ty::{self, AssocItemContainer, RegionKind, Ty, TypeFoldable, TypeVisitor}; use rustc_span::{MultiSpan, Span}; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { - /// Print the error message for lifetime errors when the return type is a static impl Trait. + /// Print the error message for lifetime errors when the return type is a static `impl Trait`, + /// `dyn Trait` or if a method call on a trait object introduces a static requirement. pub(super) fn try_report_static_impl_trait(&self) -> Option { debug!("try_report_static_impl_trait(error={:?})", self.error); let tcx = self.tcx(); @@ -34,8 +36,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { sub_r, sup_r, ) if **sub_r == RegionKind::ReStatic => { - // This is for the implicit `'static` requirement coming from `impl dyn Trait {}`. - if let ObligationCauseCode::UnifyReceiver(assoc) = &cause.code { + // This is for an implicit `'static` requirement coming from `impl dyn Trait {}`. + if let ObligationCauseCode::UnifyReceiver(ctxt) = &cause.code { let param = self.find_param_with_region(sup_r, sub_r)?; let lifetime = if sup_r.has_name() { format!("lifetime `{}`", sup_r) @@ -55,7 +57,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { .map(|s| format!("`{}`", s)) .unwrap_or_else(|| "`fn` parameter".to_string()), lifetime, - assoc.ident, + ctxt.assoc_item.ident, ); err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime)); err.span_label( @@ -63,7 +65,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { &format!( "...is captured and required to live as long as `'static` here \ because of an implicit lifetime bound on the {}", - match assoc.container { + match ctxt.assoc_item.container { AssocItemContainer::TraitContainer(id) => format!("`impl` of `{}`", tcx.def_path_str(id)), AssocItemContainer::ImplContainer(_) => @@ -71,7 +73,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { }, ), ); - if self.find_impl_on_dyn_trait(&mut err, param.param_ty, assoc) { + if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) { err.emit(); return Some(ErrorReported); } else { @@ -117,25 +119,26 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let mut postfix = String::new(); if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sup_origin { - if let ObligationCauseCode::UnifyReceiver(assoc) = &cause.code { - if self.find_impl_on_dyn_trait(&mut err, param.param_ty, assoc) + if let ObligationCauseCode::UnifyReceiver(ctxt) = &cause.code { + if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) && fn_returns.is_empty() { err.code(rustc_errors::error_code!(E0767)); err.set_primary_message(&format!( "{} has {} but calling `{}` introduces an implicit `'static` lifetime \ requirement", - param_name, lifetime, assoc.ident, + param_name, lifetime, ctxt.assoc_item.ident, )); postfix = format!( " because of an implicit lifetime on the {}", - match assoc.container { + match ctxt.assoc_item.container { AssocItemContainer::TraitContainer(id) => format!("`impl` of `{}`", tcx.def_path_str(id)), AssocItemContainer::ImplContainer(_) => "inherent `impl`".to_string(), }, ); } + // } } } @@ -316,128 +319,104 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } /// When we call a method coming from an `impl Foo for dyn Bar`, `dyn Bar` introduces a default - /// `'static` obligation. Find `impl` blocks that are implemented + /// `'static` obligation. Suggest relaxing that implicit bound. fn find_impl_on_dyn_trait( &self, err: &mut DiagnosticBuilder<'_>, ty: Ty<'_>, - assoc: &AssocItem, + ctxt: &UnifyReceiverContext<'tcx>, ) -> bool { let tcx = self.tcx(); let mut suggested = false; - // Find the trait object types in the argument. - let mut v = TraitObjectVisitor(vec![]); - v.visit_ty(ty); - - let container_id = match assoc.container { - // When the obligation comes from an `impl Foo for dyn Bar {}`, we - // have the `DefId` of the `trait` itself, not the relevant `impl` - // block. Because of this, we have to look at all the `trait`s - // available, and filter out all that are not of `Foo` (this `def_id`) - // and not of `Bar` (the `filter_map` later in this method). - AssocItemContainer::TraitContainer(def_id) => def_id, + // Find the method being called. + let instance = match ty::Instance::resolve( + tcx, + ctxt.param_env, + ctxt.assoc_item.def_id, + self.infcx.resolve_vars_if_possible(&ctxt.substs), + ) { + Ok(Some(instance)) => instance, + _ => return false, + }; - // When the obligation comes from an `impl dyn Trait {}`, we already - // have the `DefId` of the relevant `Item`, so we use it directly. - AssocItemContainer::ImplContainer(def_id) => { - if let Some(Node::Item(Item { kind: ItemKind::Impl { self_ty, .. }, .. })) = - tcx.hir().get_if_local(def_id) - { - for found_did in &v.0 { - let mut hir_v = HirTraitObjectVisitor(vec![], *found_did); - hir_v.visit_ty(self_ty); - if let [span] = &hir_v.0[..] { - let mut multi_span: MultiSpan = vec![*span].into(); - multi_span.push_span_label( - *span, - "this has an implicit `'static` lifetime requirement".to_string(), - ); - multi_span.push_span_label( - assoc.ident.span, - "`'static` requirement is introduced when calling this method" - .to_string(), - ); - err.span_note( - multi_span, - &format!( - "`{}`'s inherent `impl` has a `'static` requirement", - tcx.def_path_str(*found_did), - ), - ); - err.span_suggestion_verbose( - span.shrink_to_hi(), - "consider relaxing the implicit `'static` requirement", - " + '_".to_string(), - Applicability::MaybeIncorrect, - ); - suggested = true; - } + // Get the `Ident` of the method being called and the corresponding `impl` (to point at + // `Bar` in `impl Foo for dyn Bar {}` and the definition of the method being called). + let (ident, self_ty) = match tcx.hir().get_if_local(instance.def_id()) { + Some(Node::ImplItem(ImplItem { ident, hir_id, .. })) => { + match tcx.hir().find(tcx.hir().get_parent_item(*hir_id)) { + Some(Node::Item(Item { kind: ItemKind::Impl { self_ty, .. }, .. })) => { + (ident, self_ty) } + _ => return false, } - return suggested; } - }; - - // Find all the `impl`s in the local scope that can be called on the type parameter. And - // retain all that are `impl`s of the trait that originated the `'static` obligation. - // This doesn't find `impl dyn Trait { /**/ }`, but that case is handled above. - let impl_self_tys = tcx - .all_traits(LOCAL_CRATE) - .iter() - .flat_map(|trait_did| tcx.hir().trait_impls(*trait_did)) - .filter_map(|impl_node| { - let impl_did = tcx.hir().local_def_id(*impl_node); - match tcx.hir().get_if_local(impl_did.to_def_id()) { - Some(Node::Item(Item { - kind: ItemKind::Impl { self_ty, of_trait: Some(of_trait), items, .. }, - .. - })) if of_trait.trait_def_id() == Some(container_id) => Some(( - self_ty, - // Get the ident of the method, in order to use its `Span`. - items + Some(Node::TraitItem(TraitItem { ident, hir_id, .. })) => { + let parent_id = tcx.hir().get_parent_item(*hir_id); + match tcx.hir().find(parent_id) { + Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => { + // The method being called is defined in the `trait`, but the `'static` + // obligation comes from the `impl`. Find that `impl` so that we can point + // at it in the suggestion. + let trait_did = tcx.hir().local_def_id(parent_id).to_def_id(); + match tcx.hir().trait_impls(trait_did) .iter() - .filter(|item| item.ident == assoc.ident) - .map(|item| item.ident) + .filter_map(|impl_node| { + let impl_did = tcx.hir().local_def_id(*impl_node); + match tcx.hir().get_if_local(impl_did.to_def_id()) { + Some(Node::Item(Item { + kind: ItemKind::Impl { self_ty, of_trait: Some(of_trait), .. }, + .. + })) if of_trait.trait_def_id() == Some(trait_did) => Some(self_ty), + _ => None, + } + }) .next() - .unwrap_or(assoc.ident), - )), - _ => None, + { + Some(self_ty) => (ident, self_ty), + _ => return false, + } + } + _ => return false, } - }); + } + _ => return false, + }; - // Given all the `impl`s of the relevant `trait`, look for those that are implemented for - // the trait object in the `fn` parameter type. - for (self_ty, method) in impl_self_tys { - for found_did in &v.0 { - let mut hir_v = HirTraitObjectVisitor(vec![], *found_did); - hir_v.visit_ty(self_ty); - if let [span] = &hir_v.0[..] { - let mut multi_span: MultiSpan = vec![*span].into(); - multi_span.push_span_label( - *span, - "this has an implicit `'static` lifetime requirement".to_string(), - ); - multi_span.push_span_label( - method.span, - "`'static` requirement is introduced when calling this method".to_string(), - ); - err.span_note( - multi_span, - &format!( - "`{}`'s `impl` of `{}` has an implicit `'static` requirement", - tcx.def_path_str(*found_did), - tcx.def_path_str(container_id), - ), - ); - err.span_suggestion_verbose( - span.shrink_to_hi(), - "consider relaxing the implicit `'static` requirement", - " + '_".to_string(), - Applicability::MaybeIncorrect, - ); - suggested = true; - } + // Find the trait object types in the argument, so we point at *only* the trait object. + let mut v = TraitObjectVisitor(vec![]); + v.visit_ty(ty); + for found_did in &v.0 { + let mut hir_v = HirTraitObjectVisitor(vec![], *found_did); + hir_v.visit_ty(self_ty); + for span in &hir_v.0 { + let mut multi_span: MultiSpan = vec![*span].into(); + multi_span.push_span_label( + *span, + "this has an implicit `'static` lifetime requirement".to_string(), + ); + multi_span.push_span_label( + ident.span, + "calling this method introduces the `impl`'s 'static` requirement".to_string(), + ); + err.span_note( + multi_span, + &format!( + "{} has a `'static` requirement", + match ctxt.assoc_item.container { + AssocItemContainer::TraitContainer(id) => + format!("`impl` of `{}`", tcx.def_path_str(id)), + AssocItemContainer::ImplContainer(_) => "inherent `impl`".to_string(), + }, + ), + ); + err.span_suggestion_verbose( + span.shrink_to_hi(), + "consider relaxing the implicit `'static` requirement", + " + '_".to_string(), + Applicability::MaybeIncorrect, + ); + suggested = true; } } suggested diff --git a/src/librustc_middle/traits/mod.rs b/src/librustc_middle/traits/mod.rs index c066ea831b298..d2747e5fc659b 100644 --- a/src/librustc_middle/traits/mod.rs +++ b/src/librustc_middle/traits/mod.rs @@ -169,6 +169,13 @@ impl<'tcx> ObligationCause<'tcx> { } } +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct UnifyReceiverContext<'tcx> { + pub assoc_item: ty::AssocItem, + pub param_env: ty::ParamEnv<'tcx>, + pub substs: SubstsRef<'tcx>, +} + #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum ObligationCauseCode<'tcx> { /// Not well classified or should be obvious from the span. @@ -300,7 +307,7 @@ pub enum ObligationCauseCode<'tcx> { /// Method receiver MethodReceiver, - UnifyReceiver(Rc), + UnifyReceiver(Box>), /// `return` with no expression ReturnNoExpression, diff --git a/src/librustc_middle/traits/structural_impls.rs b/src/librustc_middle/traits/structural_impls.rs index 61ef0821733e8..18b4371053a89 100644 --- a/src/librustc_middle/traits/structural_impls.rs +++ b/src/librustc_middle/traits/structural_impls.rs @@ -213,13 +213,26 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { super::StartFunctionType => Some(super::StartFunctionType), super::IntrinsicType => Some(super::IntrinsicType), super::MethodReceiver => Some(super::MethodReceiver), - super::UnifyReceiver(ref assoc) => Some(super::UnifyReceiver(assoc.clone())), + super::UnifyReceiver(ref ctxt) => tcx.lift(ctxt).map(|ctxt| super::UnifyReceiver(ctxt)), super::BlockTailExpression(id) => Some(super::BlockTailExpression(id)), super::TrivialBound => Some(super::TrivialBound), } } } +impl<'a, 'tcx> Lift<'tcx> for traits::UnifyReceiverContext<'a> { + type Lifted = traits::UnifyReceiverContext<'tcx>; + fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option { + tcx.lift(&self.param_env).and_then(|param_env| { + tcx.lift(&self.substs).map(|substs| traits::UnifyReceiverContext { + assoc_item: self.assoc_item, + param_env, + substs, + }) + }) + } +} + impl<'a, 'tcx> Lift<'tcx> for traits::DerivedObligationCause<'a> { type Lifted = traits::DerivedObligationCause<'tcx>; fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option { diff --git a/src/librustc_trait_selection/traits/codegen/mod.rs b/src/librustc_trait_selection/traits/codegen/mod.rs index cf575d3eca9c2..dd7ea55cc1043 100644 --- a/src/librustc_trait_selection/traits/codegen/mod.rs +++ b/src/librustc_trait_selection/traits/codegen/mod.rs @@ -6,6 +6,7 @@ use crate::infer::{InferCtxt, TyCtxtInferExt}; use crate::traits::{ FulfillmentContext, ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine, + Unimplemented, }; use rustc_errors::ErrorReported; use rustc_middle::ty::fold::TypeFoldable; @@ -58,6 +59,18 @@ pub fn codegen_fulfill_obligation<'tcx>( ); return Err(ErrorReported); } + Err(Unimplemented) => { + // This can trigger when we probe for the source of a `'static` lifetime requirement + // on a trait object: `impl Foo for dyn Trait {}` has an implicit `'static` bound. + infcx.tcx.sess.delay_span_bug( + rustc_span::DUMMY_SP, + &format!( + "Encountered error `Unimplemented` selecting `{:?}` during codegen", + trait_ref + ), + ); + return Err(ErrorReported); + } Err(e) => { bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref) } diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index e94b44d879533..0632ce2319aee 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -1706,7 +1706,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { | ObligationCauseCode::IntrinsicType | ObligationCauseCode::MethodReceiver | ObligationCauseCode::ReturnNoExpression - | ObligationCauseCode::UnifyReceiver(_) + | ObligationCauseCode::UnifyReceiver(..) | ObligationCauseCode::MiscObligation => {} ObligationCauseCode::SliceOrArrayElem => { err.note("slice and array elements must have `Sized` type"); diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 58cbe8b2479d6..ed84095ae6b0c 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -6,7 +6,7 @@ use crate::hir::def_id::DefId; use crate::hir::GenericArg; use rustc_hir as hir; use rustc_infer::infer::{self, InferOk}; -use rustc_middle::traits::ObligationCauseCode; +use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast}; use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::fold::TypeFoldable; @@ -16,7 +16,6 @@ use rustc_span::Span; use rustc_trait_selection::traits; use std::ops::Deref; -use std::rc::Rc; struct ConfirmContext<'a, 'tcx> { fcx: &'a FnCtxt<'a, 'tcx>, @@ -97,7 +96,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { "confirm: self_ty={:?} method_sig_rcvr={:?} method_sig={:?} method_predicates={:?}", self_ty, method_sig_rcvr, method_sig, method_predicates ); - self.unify_receivers(self_ty, method_sig_rcvr, &pick); + self.unify_receivers(self_ty, method_sig_rcvr, &pick, all_substs); let (method_sig, method_predicates) = self.normalize_associated_types_in(self.span, &(method_sig, method_predicates)); @@ -345,12 +344,20 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { self_ty: Ty<'tcx>, method_self_ty: Ty<'tcx>, pick: &probe::Pick<'tcx>, + substs: SubstsRef<'tcx>, ) { debug!( "unify_receivers: self_ty={:?} method_self_ty={:?} span={:?} pick={:?}", self_ty, method_self_ty, self.span, pick ); - let cause = self.cause(self.span, ObligationCauseCode::UnifyReceiver(Rc::new(pick.item))); + let cause = self.cause( + self.span, + ObligationCauseCode::UnifyReceiver(Box::new(UnifyReceiverContext { + assoc_item: pick.item, + param_env: self.param_env, + substs, + })), + ); match self.at(&cause, self.param_env).sup(method_self_ty, self_ty) { Ok(InferOk { obligations, value: () }) => { self.register_predicates(obligations); diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.fixed b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.fixed index 832b185e619fa..45e6cfdb82131 100644 --- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.fixed +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.fixed @@ -5,19 +5,19 @@ mod foo { trait OtherTrait<'a> {} impl<'a> OtherTrait<'a> for &'a () {} - trait ObjectTrait {} - trait MyTrait { - fn use_self(&self) -> &(); + trait ObjectTrait {} + trait MyTrait { + fn use_self(&self) -> &(); } trait Irrelevant {} - impl MyTrait for dyn ObjectTrait + '_ { - fn use_self(&self) -> &() { panic!() } + impl MyTrait for dyn ObjectTrait + '_ { + fn use_self(&self) -> &() { panic!() } } - impl Irrelevant for dyn ObjectTrait {} + impl Irrelevant for dyn ObjectTrait {} - fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { - val.use_self() //~ ERROR E0759 + fn use_it<'a, T>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { + val.use_self::() //~ ERROR E0759 } } @@ -76,13 +76,11 @@ mod ban { trait ObjectTrait {} trait MyTrait { - fn use_self(&self) -> &(); + fn use_self(&self) -> &() { panic!() } } trait Irrelevant {} - impl MyTrait for dyn ObjectTrait + '_ { - fn use_self(&self) -> &() { panic!() } - } + impl MyTrait for dyn ObjectTrait + '_ {} impl Irrelevant for dyn ObjectTrait {} fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { @@ -90,5 +88,4 @@ mod ban { } } - fn main() {} diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr index 8765591c4a114..fb6e62e76da88 100644 --- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr @@ -1,10 +1,10 @@ error[E0521]: borrowed data escapes outside of function --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:20:9 | -LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { - | --- `val` is a reference that is only valid in the function body -LL | val.use_self() - | ^^^^^^^^^^^^^^ `val` escapes the function body here +LL | fn use_it<'a, T>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { + | --- `val` is a reference that is only valid in the function body +LL | val.use_self::() + | ^^^^^^^^^^^^^^^^^^^ `val` escapes the function body here | = help: consider replacing `'a` with `'static` @@ -19,7 +19,7 @@ LL | val.use_self() = help: consider replacing `'a` with `'static` error[E0521]: borrowed data escapes outside of function - --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:89:9 + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:87:9 | LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> { | --- `val` is a reference that is only valid in the function body diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.rs b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.rs index ba26c2d67dfa8..7de11f4f8fc51 100644 --- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.rs +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.rs @@ -5,19 +5,19 @@ mod foo { trait OtherTrait<'a> {} impl<'a> OtherTrait<'a> for &'a () {} - trait ObjectTrait {} - trait MyTrait { - fn use_self(&self) -> &(); + trait ObjectTrait {} + trait MyTrait { + fn use_self(&self) -> &(); } trait Irrelevant {} - impl MyTrait for dyn ObjectTrait { - fn use_self(&self) -> &() { panic!() } + impl MyTrait for dyn ObjectTrait { + fn use_self(&self) -> &() { panic!() } } - impl Irrelevant for dyn ObjectTrait {} + impl Irrelevant for dyn ObjectTrait {} - fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { - val.use_self() //~ ERROR E0759 + fn use_it<'a, T>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { + val.use_self::() //~ ERROR E0759 } } @@ -76,13 +76,11 @@ mod ban { trait ObjectTrait {} trait MyTrait { - fn use_self(&self) -> &(); + fn use_self(&self) -> &() { panic!() } } trait Irrelevant {} - impl MyTrait for dyn ObjectTrait { - fn use_self(&self) -> &() { panic!() } - } + impl MyTrait for dyn ObjectTrait {} impl Irrelevant for dyn ObjectTrait {} fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> { @@ -90,5 +88,4 @@ mod ban { } } - fn main() {} diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr index 425159edbcd4a..1375ac8db8ded 100644 --- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr @@ -1,22 +1,22 @@ error[E0759]: `val` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:20:13 | -LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { - | ------------------- this data with lifetime `'a`... -LL | val.use_self() +LL | fn use_it<'a, T>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { + | ---------------------- this data with lifetime `'a`... +LL | val.use_self::() | ^^^^^^^^ ...is captured and required to live as long as `'static` here | -note: `foo::ObjectTrait`'s `impl` of `foo::MyTrait` has an implicit `'static` requirement - --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:14:26 +note: `impl` of `foo::MyTrait` has a `'static` requirement + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:14:32 | -LL | impl MyTrait for dyn ObjectTrait { - | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement -LL | fn use_self(&self) -> &() { panic!() } - | -------- `'static` requirement is introduced when calling this method +LL | impl MyTrait for dyn ObjectTrait { + | ^^^^^^^^^^^^^^ this has an implicit `'static` lifetime requirement +LL | fn use_self(&self) -> &() { panic!() } + | -------- calling this method introduces the `impl`'s 'static` requirement help: consider relaxing the implicit `'static` requirement | -LL | impl MyTrait for dyn ObjectTrait + '_ { - | ^^^^ +LL | impl MyTrait for dyn ObjectTrait + '_ { + | ^^^^ error[E0767]: `val` has lifetime `'a` but calling `use_self` introduces an implicit `'static` lifetime requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:69:13 @@ -26,36 +26,37 @@ LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { LL | val.use_self() | ^^^^^^^^ ...is captured and required to live as long as `'static` here because of an implicit lifetime bound on the inherent `impl` | -note: `bat::ObjectTrait`'s inherent `impl` has a `'static` requirement +note: inherent `impl` has a `'static` requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:64:14 | LL | impl dyn ObjectTrait { | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement LL | fn use_self(&self) -> &() { panic!() } - | -------- `'static` requirement is introduced when calling this method + | -------- calling this method introduces the `impl`'s 'static` requirement help: consider relaxing the implicit `'static` requirement | LL | impl dyn ObjectTrait + '_ { | ^^^^ error[E0759]: `val` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement - --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:89:13 + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:87:13 | LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> { | ------------------- this data with lifetime `'a`... LL | val.use_self() | ^^^^^^^^ ...is captured and required to live as long as `'static` here | -note: `ban::ObjectTrait`'s `impl` of `ban::MyTrait` has an implicit `'static` requirement +note: `impl` of `ban::MyTrait` has a `'static` requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:83:26 | -LL | impl MyTrait for dyn ObjectTrait { - | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement LL | fn use_self(&self) -> &() { panic!() } - | -------- `'static` requirement is introduced when calling this method + | -------- calling this method introduces the `impl`'s 'static` requirement +... +LL | impl MyTrait for dyn ObjectTrait {} + | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement help: consider relaxing the implicit `'static` requirement | -LL | impl MyTrait for dyn ObjectTrait + '_ { +LL | impl MyTrait for dyn ObjectTrait + '_ {} | ^^^^ help: to declare that the `impl Trait` captures data from argument `val`, you can add an explicit `'a` lifetime bound | @@ -70,13 +71,13 @@ LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> &'a () { LL | val.use_self() | ^^^^^^^^ ...is captured and required to live as long as `'static` here because of an implicit lifetime on the `impl` of `bar::MyTrait` | -note: `bar::ObjectTrait`'s `impl` of `bar::MyTrait` has an implicit `'static` requirement +note: `impl` of `bar::MyTrait` has a `'static` requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:31:26 | LL | impl MyTrait for dyn ObjectTrait { | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement LL | fn use_self(&self) -> &() { panic!() } - | -------- `'static` requirement is introduced when calling this method + | -------- calling this method introduces the `impl`'s 'static` requirement help: consider relaxing the implicit `'static` requirement | LL | impl MyTrait for dyn ObjectTrait + '_ { @@ -90,13 +91,13 @@ LL | fn use_it<'a>(val: &'a Box) -> &'a () { LL | val.use_self() | ^^^^^^^^ ...is captured and required to live as long as `'static` here because of an implicit lifetime on the `impl` of `baz::MyTrait` | -note: `baz::ObjectTrait`'s `impl` of `baz::MyTrait` has an implicit `'static` requirement +note: `impl` of `baz::MyTrait` has a `'static` requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:48:30 | LL | impl MyTrait for Box { | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement LL | fn use_self(&self) -> &() { panic!() } - | -------- `'static` requirement is introduced when calling this method + | -------- calling this method introduces the `impl`'s 'static` requirement help: consider relaxing the implicit `'static` requirement | LL | impl MyTrait for Box { From 0c5891b3e7a0764960c2fdc12c67b938fa995945 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 1 Jul 2020 00:24:55 -0700 Subject: [PATCH 20/30] Partially account for case where used method is from trait --- .../nice_region_error/static_impl_trait.rs | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs index 9c2e02968f607..18466b00da971 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -340,6 +340,9 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { _ => return false, }; + let mut v = TraitObjectVisitor(vec![]); + v.visit_ty(ty); + // Get the `Ident` of the method being called and the corresponding `impl` (to point at // `Bar` in `impl Foo for dyn Bar {}` and the definition of the method being called). let (ident, self_ty) = match tcx.hir().get_if_local(instance.def_id()) { @@ -359,15 +362,30 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // obligation comes from the `impl`. Find that `impl` so that we can point // at it in the suggestion. let trait_did = tcx.hir().local_def_id(parent_id).to_def_id(); - match tcx.hir().trait_impls(trait_did) + match tcx + .hir() + .trait_impls(trait_did) .iter() .filter_map(|impl_node| { let impl_did = tcx.hir().local_def_id(*impl_node); match tcx.hir().get_if_local(impl_did.to_def_id()) { Some(Node::Item(Item { - kind: ItemKind::Impl { self_ty, of_trait: Some(of_trait), .. }, + kind: ItemKind::Impl { self_ty, .. }, .. - })) if of_trait.trait_def_id() == Some(trait_did) => Some(self_ty), + })) if v.0.iter().all(|did| { + // FIXME: we should check `self_ty` against the receiver + // type in the `UnifyReceiver` context, but for now, use + // this imperfect proxy. This will fail if there are + // multiple `impl`s for the same trait like + // `impl Foo for Box` and `impl Foo for dyn Bar`. + // In that case, only the first one will get suggestions. + let mut hir_v = HirTraitObjectVisitor(vec![], *did); + hir_v.visit_ty(self_ty); + !hir_v.0.is_empty() + }) => + { + Some(self_ty) + } _ => None, } }) @@ -384,8 +402,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { }; // Find the trait object types in the argument, so we point at *only* the trait object. - let mut v = TraitObjectVisitor(vec![]); - v.visit_ty(ty); for found_did in &v.0 { let mut hir_v = HirTraitObjectVisitor(vec![], *found_did); hir_v.visit_ty(self_ty); From 4344265df9cc1989ff65a8e960266c01a3bc43c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 1 Jul 2020 14:02:57 -0700 Subject: [PATCH 21/30] Handle fully-qualified paths and add test cases --- .../nice_region_error/static_impl_trait.rs | 184 ++++++++++-------- ...-bound-needing-more-suggestions.nll.stderr | 37 ++++ ...t-static-bound-needing-more-suggestions.rs | 114 +++++++++++ ...atic-bound-needing-more-suggestions.stderr | 57 ++++++ ...dyn-trait-with-implicit-static-bound.fixed | 25 ++- ...rait-with-implicit-static-bound.nll.stderr | 14 +- ...on-dyn-trait-with-implicit-static-bound.rs | 25 ++- ...yn-trait-with-implicit-static-bound.stderr | 46 ++++- 8 files changed, 404 insertions(+), 98 deletions(-) create mode 100644 src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.nll.stderr create mode 100644 src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs create mode 100644 src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs index 18466b00da971..9581ee611fce8 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -12,6 +12,7 @@ use rustc_hir::{ TyKind, }; use rustc_middle::ty::{self, AssocItemContainer, RegionKind, Ty, TypeFoldable, TypeVisitor}; +use rustc_span::symbol::Ident; use rustc_span::{MultiSpan, Span}; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { @@ -115,33 +116,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime)); debug!("try_report_static_impl_trait: param_info={:?}", param); - let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id); - - let mut postfix = String::new(); - if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sup_origin { - if let ObligationCauseCode::UnifyReceiver(ctxt) = &cause.code { - if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) - && fn_returns.is_empty() - { - err.code(rustc_errors::error_code!(E0767)); - err.set_primary_message(&format!( - "{} has {} but calling `{}` introduces an implicit `'static` lifetime \ - requirement", - param_name, lifetime, ctxt.assoc_item.ident, - )); - postfix = format!( - " because of an implicit lifetime on the {}", - match ctxt.assoc_item.container { - AssocItemContainer::TraitContainer(id) => - format!("`impl` of `{}`", tcx.def_path_str(id)), - AssocItemContainer::ImplContainer(_) => "inherent `impl`".to_string(), - }, - ); - } - // } - } - } - // We try to make the output have fewer overlapping spans if possible. if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span())) && sup_origin.span() != return_sp @@ -168,35 +142,68 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // | ---- ^ err.span_label( sup_origin.span(), - &format!( - "...is captured here, requiring it to live as long as `'static`{}", - postfix - ), + "...is captured here, requiring it to live as long as `'static`", ); } else { err.span_label(sup_origin.span(), "...is captured here..."); if return_sp < sup_origin.span() { err.span_note( return_sp, - &format!("...and is required to live as long as `'static` here{}", postfix), + "...and is required to live as long as `'static` here", ); } else { err.span_label( return_sp, - &format!("...and is required to live as long as `'static` here{}", postfix), + "...and is required to live as long as `'static` here", ); } } } else { err.span_label( return_sp, - &format!( - "...is captured and required to live as long as `'static` here{}", - postfix - ), + "...is captured and required to live as long as `'static` here", ); } + let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id); + + let mut override_error_code = None; + if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sup_origin { + if let ObligationCauseCode::UnifyReceiver(ctxt) = &cause.code { + // Handle case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a + // `'static` lifetime when called as a method on a binding: `bar.qux()`. + if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) { + override_error_code = Some(ctxt.assoc_item.ident); + } + } + } + if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sub_origin { + if let ObligationCauseCode::ItemObligation(item_def_id) = cause.code { + // Same case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a `'static` + // lifetime as above, but called using a fully-qualified path to the method: + // `Foo::qux(bar)`. + let mut v = TraitObjectVisitor(vec![]); + v.visit_ty(param.param_ty); + if let Some((ident, self_ty)) = + self.get_impl_ident_and_self_ty_from_trait(item_def_id, &v.0[..]) + { + if self.suggest_constrain_dyn_trait_in_impl(&mut err, &v.0[..], ident, self_ty) + { + override_error_code = Some(ident); + } + } + } + } + if let (Some(ident), true) = (override_error_code, fn_returns.is_empty()) { + // Provide a more targetted error code and description. + err.code(rustc_errors::error_code!(E0767)); + err.set_primary_message(&format!( + "{} has {} but calling `{}` introduces an implicit `'static` lifetime \ + requirement", + param_name, lifetime, ident, + )); + } + debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns); // FIXME: account for the need of parens in `&(dyn Trait + '_)` let consider = "consider changing the"; @@ -318,40 +325,19 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { Some(ErrorReported) } - /// When we call a method coming from an `impl Foo for dyn Bar`, `dyn Bar` introduces a default - /// `'static` obligation. Suggest relaxing that implicit bound. - fn find_impl_on_dyn_trait( + fn get_impl_ident_and_self_ty_from_trait( &self, - err: &mut DiagnosticBuilder<'_>, - ty: Ty<'_>, - ctxt: &UnifyReceiverContext<'tcx>, - ) -> bool { + def_id: DefId, + trait_objects: &[DefId], + ) -> Option<(Ident, &'tcx hir::Ty<'tcx>)> { let tcx = self.tcx(); - let mut suggested = false; - - // Find the method being called. - let instance = match ty::Instance::resolve( - tcx, - ctxt.param_env, - ctxt.assoc_item.def_id, - self.infcx.resolve_vars_if_possible(&ctxt.substs), - ) { - Ok(Some(instance)) => instance, - _ => return false, - }; - - let mut v = TraitObjectVisitor(vec![]); - v.visit_ty(ty); - - // Get the `Ident` of the method being called and the corresponding `impl` (to point at - // `Bar` in `impl Foo for dyn Bar {}` and the definition of the method being called). - let (ident, self_ty) = match tcx.hir().get_if_local(instance.def_id()) { + match tcx.hir().get_if_local(def_id) { Some(Node::ImplItem(ImplItem { ident, hir_id, .. })) => { match tcx.hir().find(tcx.hir().get_parent_item(*hir_id)) { Some(Node::Item(Item { kind: ItemKind::Impl { self_ty, .. }, .. })) => { - (ident, self_ty) + Some((*ident, self_ty)) } - _ => return false, + _ => None, } } Some(Node::TraitItem(TraitItem { ident, hir_id, .. })) => { @@ -372,7 +358,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { Some(Node::Item(Item { kind: ItemKind::Impl { self_ty, .. }, .. - })) if v.0.iter().all(|did| { + })) if trait_objects.iter().all(|did| { // FIXME: we should check `self_ty` against the receiver // type in the `UnifyReceiver` context, but for now, use // this imperfect proxy. This will fail if there are @@ -391,20 +377,64 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { }) .next() { - Some(self_ty) => (ident, self_ty), - _ => return false, + Some(self_ty) => Some((*ident, self_ty)), + _ => None, } } - _ => return false, + _ => None, } } + _ => None, + } + } + + /// When we call a method coming from an `impl Foo for dyn Bar`, `dyn Bar` introduces a default + /// `'static` obligation. Suggest relaxing that implicit bound. + fn find_impl_on_dyn_trait( + &self, + err: &mut DiagnosticBuilder<'_>, + ty: Ty<'_>, + ctxt: &UnifyReceiverContext<'tcx>, + ) -> bool { + let tcx = self.tcx(); + + // Find the method being called. + let instance = match ty::Instance::resolve( + tcx, + ctxt.param_env, + ctxt.assoc_item.def_id, + self.infcx.resolve_vars_if_possible(&ctxt.substs), + ) { + Ok(Some(instance)) => instance, _ => return false, }; + let mut v = TraitObjectVisitor(vec![]); + v.visit_ty(ty); + + // Get the `Ident` of the method being called and the corresponding `impl` (to point at + // `Bar` in `impl Foo for dyn Bar {}` and the definition of the method being called). + let (ident, self_ty) = + match self.get_impl_ident_and_self_ty_from_trait(instance.def_id(), &v.0[..]) { + Some((ident, self_ty)) => (ident, self_ty), + None => return false, + }; + // Find the trait object types in the argument, so we point at *only* the trait object. - for found_did in &v.0 { + self.suggest_constrain_dyn_trait_in_impl(err, &v.0[..], ident, self_ty) + } + + fn suggest_constrain_dyn_trait_in_impl( + &self, + err: &mut DiagnosticBuilder<'_>, + found_dids: &[DefId], + ident: Ident, + self_ty: &hir::Ty<'_>, + ) -> bool { + let mut suggested = false; + for found_did in found_dids { let mut hir_v = HirTraitObjectVisitor(vec![], *found_did); - hir_v.visit_ty(self_ty); + hir_v.visit_ty(&self_ty); for span in &hir_v.0 { let mut multi_span: MultiSpan = vec![*span].into(); multi_span.push_span_label( @@ -415,17 +445,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { ident.span, "calling this method introduces the `impl`'s 'static` requirement".to_string(), ); - err.span_note( - multi_span, - &format!( - "{} has a `'static` requirement", - match ctxt.assoc_item.container { - AssocItemContainer::TraitContainer(id) => - format!("`impl` of `{}`", tcx.def_path_str(id)), - AssocItemContainer::ImplContainer(_) => "inherent `impl`".to_string(), - }, - ), - ); + err.span_note(multi_span, "the used `impl` has a `'static` requirement"); err.span_suggestion_verbose( span.shrink_to_hi(), "consider relaxing the implicit `'static` requirement", diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.nll.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.nll.stderr new file mode 100644 index 0000000000000..6921926590a69 --- /dev/null +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.nll.stderr @@ -0,0 +1,37 @@ +error[E0597]: `val` does not live long enough + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:22:9 + | +LL | fn use_it<'a>(val: Box>) -> impl OtherTrait<'a> { + | -- lifetime `'a` defined here ------------------- opaque type requires that `val` is borrowed for `'a` +LL | val.use_self() + | ^^^ borrowed value does not live long enough +LL | } + | - `val` dropped here while still borrowed + | +help: you can add a bound to the opaque type to make it last less than `'static` and match `'a` + | +LL | fn use_it<'a>(val: Box>) -> impl OtherTrait<'a> + 'a { + | ^^^^ + +error[E0515]: cannot return value referencing function parameter `val` + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:44:9 + | +LL | val.use_self() + | ---^^^^^^^^^^^ + | | + | returns a value referencing data owned by the current function + | `val` is borrowed here + +error[E0515]: cannot return value referencing function parameter `val` + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:110:9 + | +LL | val.use_self() + | ---^^^^^^^^^^^ + | | + | returns a value referencing data owned by the current function + | `val` is borrowed here + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0515, E0597. +For more information about an error, try `rustc --explain E0515`. diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs new file mode 100644 index 0000000000000..ae6ffa8d93e01 --- /dev/null +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs @@ -0,0 +1,114 @@ + +// FIXME: the following cases need to suggest more things to make users reach a working end state. + +mod bav { + trait OtherTrait<'a> {} + impl<'a> OtherTrait<'a> for &'a () {} + + trait ObjectTrait { + type Assoc: Bar; + } + trait MyTrait { + fn use_self(&self) -> &() { panic!() } + } + trait Bar {} + + impl MyTrait for Box> { + fn use_self(&self) -> &() { panic!() } + } + impl Bar for i32 {} + + fn use_it<'a>(val: Box>) -> impl OtherTrait<'a> { + val.use_self() //~ ERROR E0597 + } +} + +mod bap { + trait OtherTrait<'a> {} + impl<'a> OtherTrait<'a> for &'a () {} + + trait ObjectTrait { + type Assoc: Bar; + } + trait MyTrait { + fn use_self(&self) -> &() { panic!() } + } + trait Bar {} + + impl MyTrait for Box> { + fn use_self(&self) -> &() { panic!() } + } + impl Bar for i32 {} + + fn use_it<'a>(val: Box>) -> impl OtherTrait<'a> + 'a { + val.use_self() //~ ERROR E0515 + } +} + +// This case in particular requires the user to write all of the bounds we have in `mod bax`. +mod bay { + trait OtherTrait<'a> {} + impl<'a> OtherTrait<'a> for &'a () {} + + trait ObjectTrait { + type Assoc: Bar; + } + trait MyTrait { + fn use_self(&self) -> &() { panic!() } + } + trait Bar {} + + impl MyTrait for Box> { + fn use_self(&self) -> &() { panic!() } + } + impl Bar for i32 {} + + fn use_it<'a>(val: Box + 'a>) -> &'a () { + val.use_self() //~ ERROR E0767 + } +} + +mod bax { + trait OtherTrait<'a> {} + impl<'a> OtherTrait<'a> for &'a () {} + + trait ObjectTrait { + type Assoc: Bar; + } + trait MyTrait<'a> { + fn use_self(&'a self) -> &'a () { panic!() } + } + trait Bar {} + + impl<'a> MyTrait<'a> for Box + 'a> { + fn use_self(&'a self) -> &'a () { panic!() } + } + impl Bar for i32 {} + + fn use_it<'a>(val: Box + 'a>) -> &'a () { + val.use_self() + } +} + +mod baw { + trait OtherTrait<'a> {} + impl<'a> OtherTrait<'a> for &'a () {} + + trait ObjectTrait { + type Assoc: Bar; + } + trait MyTrait { + fn use_self(&self) -> &() { panic!() } + } + trait Bar {} + + impl<'a> MyTrait for Box>> { + fn use_self(&self) -> &() { panic!() } + } + + fn use_it<'a>(val: Box>>) -> impl OtherTrait<'a> + 'a{ + val.use_self() //~ ERROR E0515 + } +} + +fn main() {} diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr new file mode 100644 index 0000000000000..2fab02fd1be45 --- /dev/null +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr @@ -0,0 +1,57 @@ +error[E0597]: `val` does not live long enough + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:22:9 + | +LL | fn use_it<'a>(val: Box>) -> impl OtherTrait<'a> { + | -- lifetime `'a` defined here ------------------- opaque type requires that `val` is borrowed for `'a` +LL | val.use_self() + | ^^^ borrowed value does not live long enough +LL | } + | - `val` dropped here while still borrowed + | +help: you can add a bound to the opaque type to make it last less than `'static` and match `'a` + | +LL | fn use_it<'a>(val: Box>) -> impl OtherTrait<'a> + 'a { + | ^^^^ + +error[E0515]: cannot return value referencing function parameter `val` + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:44:9 + | +LL | val.use_self() + | ---^^^^^^^^^^^ + | | + | returns a value referencing data owned by the current function + | `val` is borrowed here + +error[E0515]: cannot return value referencing function parameter `val` + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:110:9 + | +LL | val.use_self() + | ---^^^^^^^^^^^ + | | + | returns a value referencing data owned by the current function + | `val` is borrowed here + +error[E0767]: `val` has lifetime `'a` but calling `use_self` introduces an implicit `'static` lifetime requirement + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:67:13 + | +LL | fn use_it<'a>(val: Box + 'a>) -> &'a () { + | -------------------------------------- this data with lifetime `'a`... +LL | val.use_self() + | ^^^^^^^^ ...is captured and required to live as long as `'static` here + | +note: the used `impl` has a `'static` requirement + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:61:30 + | +LL | impl MyTrait for Box> { + | ^^^^^^^^^^^^^^^^^^^^^^^^ this has an implicit `'static` lifetime requirement +LL | fn use_self(&self) -> &() { panic!() } + | -------- calling this method introduces the `impl`'s 'static` requirement +help: consider relaxing the implicit `'static` requirement + | +LL | impl MyTrait for Box + '_> { + | ^^^^ + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0515, E0597. +For more information about an error, try `rustc --explain E0515`. diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.fixed b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.fixed index 45e6cfdb82131..c568738d94b45 100644 --- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.fixed +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.fixed @@ -78,14 +78,35 @@ mod ban { trait MyTrait { fn use_self(&self) -> &() { panic!() } } - trait Irrelevant {} + trait Irrelevant { + fn use_self(&self) -> &() { panic!() } + } impl MyTrait for dyn ObjectTrait + '_ {} - impl Irrelevant for dyn ObjectTrait {} fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { val.use_self() //~ ERROR E0759 } } +mod bal { + trait OtherTrait<'a> {} + impl<'a> OtherTrait<'a> for &'a () {} + + trait ObjectTrait {} + trait MyTrait { + fn use_self(&self) -> &() { panic!() } + } + trait Irrelevant { + fn use_self(&self) -> &() { panic!() } + } + + impl MyTrait for dyn ObjectTrait + '_ {} + impl Irrelevant for dyn ObjectTrait {} + + fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { + MyTrait::use_self(val) //~ ERROR E0759 + } +} + fn main() {} diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr index fb6e62e76da88..697467dc3a630 100644 --- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr @@ -19,7 +19,7 @@ LL | val.use_self() = help: consider replacing `'a` with `'static` error[E0521]: borrowed data escapes outside of function - --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:87:9 + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:88:9 | LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> { | --- `val` is a reference that is only valid in the function body @@ -28,5 +28,15 @@ LL | val.use_self() | = help: consider replacing `'a` with `'static` -error: aborting due to 3 previous errors +error[E0521]: borrowed data escapes outside of function + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:108:9 + | +LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { + | --- `val` is a reference that is only valid in the function body +LL | MyTrait::use_self(val) + | ^^^^^^^^^^^^^^^^^^^^^^ `val` escapes the function body here + | + = help: consider replacing `'a` with `'static` + +error: aborting due to 4 previous errors diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.rs b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.rs index 7de11f4f8fc51..8dd1e5d78de09 100644 --- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.rs +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.rs @@ -78,14 +78,35 @@ mod ban { trait MyTrait { fn use_self(&self) -> &() { panic!() } } - trait Irrelevant {} + trait Irrelevant { + fn use_self(&self) -> &() { panic!() } + } impl MyTrait for dyn ObjectTrait {} - impl Irrelevant for dyn ObjectTrait {} fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> { val.use_self() //~ ERROR E0759 } } +mod bal { + trait OtherTrait<'a> {} + impl<'a> OtherTrait<'a> for &'a () {} + + trait ObjectTrait {} + trait MyTrait { + fn use_self(&self) -> &() { panic!() } + } + trait Irrelevant { + fn use_self(&self) -> &() { panic!() } + } + + impl MyTrait for dyn ObjectTrait {} + impl Irrelevant for dyn ObjectTrait {} + + fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { + MyTrait::use_self(val) //~ ERROR E0759 + } +} + fn main() {} diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr index 1375ac8db8ded..7e814fc664625 100644 --- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr @@ -6,7 +6,7 @@ LL | fn use_it<'a, T>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + LL | val.use_self::() | ^^^^^^^^ ...is captured and required to live as long as `'static` here | -note: `impl` of `foo::MyTrait` has a `'static` requirement +note: the used `impl` has a `'static` requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:14:32 | LL | impl MyTrait for dyn ObjectTrait { @@ -26,7 +26,7 @@ LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { LL | val.use_self() | ^^^^^^^^ ...is captured and required to live as long as `'static` here because of an implicit lifetime bound on the inherent `impl` | -note: inherent `impl` has a `'static` requirement +note: the used `impl` has a `'static` requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:64:14 | LL | impl dyn ObjectTrait { @@ -39,15 +39,15 @@ LL | impl dyn ObjectTrait + '_ { | ^^^^ error[E0759]: `val` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement - --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:87:13 + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:88:13 | LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> { | ------------------- this data with lifetime `'a`... LL | val.use_self() | ^^^^^^^^ ...is captured and required to live as long as `'static` here | -note: `impl` of `ban::MyTrait` has a `'static` requirement - --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:83:26 +note: the used `impl` has a `'static` requirement + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:85:26 | LL | fn use_self(&self) -> &() { panic!() } | -------- calling this method introduces the `impl`'s 'static` requirement @@ -63,15 +63,41 @@ help: to declare that the `impl Trait` captures data from argument `val`, you ca LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { | ^^^^ +error[E0759]: `val` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:108:27 + | +LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { + | ------------------- this data with lifetime `'a`... +LL | MyTrait::use_self(val) + | ^^^ ...is captured here... + | +note: ...and is required to live as long as `'static` here + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:108:9 + | +LL | MyTrait::use_self(val) + | ^^^^^^^^^^^^^^^^^ +note: the used `impl` has a `'static` requirement + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:104:26 + | +LL | fn use_self(&self) -> &() { panic!() } + | -------- calling this method introduces the `impl`'s 'static` requirement +... +LL | impl MyTrait for dyn ObjectTrait {} + | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement +help: consider relaxing the implicit `'static` requirement + | +LL | impl MyTrait for dyn ObjectTrait + '_ {} + | ^^^^ + error[E0767]: `val` has lifetime `'a` but calling `use_self` introduces an implicit `'static` lifetime requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:37:13 | LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> &'a () { | ------------------- this data with lifetime `'a`... LL | val.use_self() - | ^^^^^^^^ ...is captured and required to live as long as `'static` here because of an implicit lifetime on the `impl` of `bar::MyTrait` + | ^^^^^^^^ ...is captured and required to live as long as `'static` here | -note: `impl` of `bar::MyTrait` has a `'static` requirement +note: the used `impl` has a `'static` requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:31:26 | LL | impl MyTrait for dyn ObjectTrait { @@ -89,9 +115,9 @@ error[E0767]: `val` has lifetime `'a` but calling `use_self` introduces an impli LL | fn use_it<'a>(val: &'a Box) -> &'a () { | ----------------------------- this data with lifetime `'a`... LL | val.use_self() - | ^^^^^^^^ ...is captured and required to live as long as `'static` here because of an implicit lifetime on the `impl` of `baz::MyTrait` + | ^^^^^^^^ ...is captured and required to live as long as `'static` here | -note: `impl` of `baz::MyTrait` has a `'static` requirement +note: the used `impl` has a `'static` requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:48:30 | LL | impl MyTrait for Box { @@ -103,6 +129,6 @@ help: consider relaxing the implicit `'static` requirement LL | impl MyTrait for Box { | ^^^^ -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0759`. From cf52d5fb87dc53b69f04416cc4080de807b7fd76 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Mon, 20 Jul 2020 16:29:58 -0300 Subject: [PATCH 22/30] Use forge links for prioritization procedure --- triagebot.toml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/triagebot.toml b/triagebot.toml index 51a29553fdb3d..ce4ea895400ac 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -81,7 +81,7 @@ topic = "I-prioritize #{number} {title}" message_on_add = """\ @*WG-prioritization/alerts* issue #{number} has been requested for prioritization. -# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#Unprioritized-I-prioritize) +# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#assign-priority-to-unprioritized-issues-with-i-prioritize-label) - Priority? - Regression? - Notify people/groups? @@ -96,7 +96,7 @@ topic = "I-nominated #{number} {title}" message_on_add = """\ @*WG-prioritization/alerts* #{number} has been nominated for discussion in `T-compiler` meeting. -# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#I-nominated) +# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#summarize-i-nominated-issues) - Already discussed? - Worth the meeting time? - Add agenda entry: @@ -113,7 +113,7 @@ topic = "Backport #{number} {title}" message_on_add = """\ @*WG-prioritization/alerts* PR #{number} has been requested for beta backport. -# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#StableBeta-nominations) +# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#summarize-stablebeta-nominations) Prepare agenda entry: - Why nominated? - Author, assignee? @@ -127,7 +127,7 @@ topic = "Backport #{number} {title}" message_on_add = """\ @*WG-prioritization/alerts* PR #{number} has been requested for stable backport. -# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#StableBeta-nominations) +# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#summarize-stablebeta-nominations) Prepare agenda entry: - Why nominated? - Author, assignee? @@ -142,7 +142,7 @@ topic = "S-waiting-on-team #{number} {title}" message_on_add = """\ @*WG-prioritization/alerts* PR #{number} is waiting on `T-compiler`. -# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#PR%E2%80%99s-waiting-on-team) +# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#summarize-prs-waiting-on-team) - Prepare agenda entry: - What is it waiting for? - Important details? @@ -156,7 +156,7 @@ topic = "P-critical #{number} {title}" message_on_add = """\ @*WG-prioritization/alerts* issue #{number} has been assigned `P-critical`. -# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#P-critical-and-Unassigned-P-high-regressions) +# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#summarize-p-critical-and-unassigned-p-high-regressions) - Notify people/groups? - Assign if possible? - Add to agenda: @@ -172,7 +172,7 @@ topic = "P-high regression #{number} {title}" message_on_add = """\ @*WG-prioritization/alerts* issue #{number} has been assigned `P-high` and is a regression. -# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#P-critical-and-Unassigned-P-high-regressions) +# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#summarize-p-critical-and-unassigned-p-high-regressions) Is issue assigned? If not: - Try to find an assignee? - Otherwise add to agenda: From 7f3e2c0d374ba7982ef09499c7de6bb53866abf4 Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Sun, 19 Jul 2020 13:03:35 -0400 Subject: [PATCH 23/30] refactor and reword intra-doc link errors This commit refactors intra-doc link error reporting to deduplicate code and decouple error construction from the type of error. This greatly improves flexibility at each error construction site, while reducing the complexity of the diagnostic creation. This commit also rewords the diagnostics for clarity and style: - Diagnostics should not end in periods. - It's unnecessary to say "ignoring it". Since this is a warning by default, it's already clear that the link is ignored. --- .../passes/collect_intra_doc_links.rs | 354 +++++++++--------- .../deny-intra-link-resolution-failure.stderr | 6 +- .../rustdoc-ui/intra-doc-alias-ice.stderr | 6 +- .../rustdoc-ui/intra-link-span-ice-55723.rs | 2 +- .../intra-link-span-ice-55723.stderr | 6 +- src/test/rustdoc-ui/intra-links-anchors.rs | 8 +- .../rustdoc-ui/intra-links-anchors.stderr | 16 +- .../intra-links-private.public.stderr | 2 +- src/test/rustdoc-ui/intra-links-private.rs | 2 +- .../rustdoc-ui/intra-links-warning-crlf.rs | 8 +- .../intra-links-warning-crlf.stderr | 24 +- src/test/rustdoc-ui/intra-links-warning.rs | 38 +- .../rustdoc-ui/intra-links-warning.stderr | 104 ++--- src/test/rustdoc-ui/issue-74134.public.stderr | 2 +- src/test/rustdoc-ui/issue-74134.rs | 2 +- src/test/rustdoc-ui/lint-group.rs | 2 +- src/test/rustdoc-ui/lint-group.stderr | 6 +- 17 files changed, 290 insertions(+), 298 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index e187b9251f71e..6f221da1168c6 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1,5 +1,5 @@ use rustc_ast::ast; -use rustc_errors::Applicability; +use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_expand::base::SyntaxExtensionKind; use rustc_feature::UnstableFeatures; use rustc_hir as hir; @@ -45,7 +45,17 @@ pub fn collect_intra_doc_links(krate: Crate, cx: &DocContext<'_>) -> Crate { enum ErrorKind { ResolutionFailure, - AnchorFailure(&'static str), + AnchorFailure(AnchorFailure), +} + +enum AnchorFailure { + MultipleAnchors, + Primitive, + Variant, + AssocConstant, + AssocType, + Field, + Method, } struct LinkCollector<'a, 'tcx> { @@ -197,9 +207,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // Not a trait item; just return what we found. Res::PrimTy(..) => { if extra_fragment.is_some() { - return Err(ErrorKind::AnchorFailure( - "primitive types cannot be followed by anchors", - )); + return Err(ErrorKind::AnchorFailure(AnchorFailure::Primitive)); } return Ok((res, Some(path_str.to_owned()))); } @@ -209,9 +217,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { if disambiguator == Some("type") { if let Some(prim) = is_primitive(path_str, ns) { if extra_fragment.is_some() { - return Err(ErrorKind::AnchorFailure( - "primitive types cannot be followed by anchors", - )); + return Err(ErrorKind::AnchorFailure(AnchorFailure::Primitive)); } return Ok((prim, Some(path_str.to_owned()))); } @@ -228,9 +234,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } } else if let Some(prim) = is_primitive(path_str, ns) { if extra_fragment.is_some() { - return Err(ErrorKind::AnchorFailure( - "primitive types cannot be followed by anchors", - )); + return Err(ErrorKind::AnchorFailure(AnchorFailure::Primitive)); } return Ok((prim, Some(path_str.to_owned()))); } else { @@ -338,9 +342,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { }; if extra_fragment.is_some() { Err(ErrorKind::AnchorFailure(if item.kind == ty::AssocKind::Fn { - "methods cannot be followed by anchors" + AnchorFailure::Method } else { - "associated constants cannot be followed by anchors" + AnchorFailure::AssocConstant })) } else { Ok((ty_res, Some(format!("{}.{}", out, item_name)))) @@ -358,9 +362,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } { if extra_fragment.is_some() { Err(ErrorKind::AnchorFailure(if def.is_enum() { - "enum variants cannot be followed by anchors" + AnchorFailure::Variant } else { - "struct fields cannot be followed by anchors" + AnchorFailure::Field })) } else { Ok(( @@ -404,11 +408,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { if extra_fragment.is_some() { Err(ErrorKind::AnchorFailure(if item.kind == ty::AssocKind::Const { - "associated constants cannot be followed by anchors" + AnchorFailure::AssocConstant } else if item.kind == ty::AssocKind::Type { - "associated types cannot be followed by anchors" + AnchorFailure::AssocType } else { - "methods cannot be followed by anchors" + AnchorFailure::Method })) } else { Ok((ty_res, Some(format!("{}.{}", kind, item_name)))) @@ -559,16 +563,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { let link = ori_link.replace("`", ""); let parts = link.split('#').collect::>(); let (link, extra_fragment) = if parts.len() > 2 { - build_diagnostic( - cx, - &item, - &link, - &dox, - link_range, - "has an issue with the link anchor.", - "only one `#` is allowed in a link", - None, - ); + anchor_failure(cx, &item, &link, &dox, link_range, AnchorFailure::MultipleAnchors); continue; } else if parts.len() == 2 { if parts[0].trim().is_empty() { @@ -803,21 +798,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { && (item.visibility == Visibility::Public) && !self.cx.render_options.document_private { - let item_name = item.name.as_deref().unwrap_or(""); - let err_msg = format!( - "public documentation for `{}` links to a private item", - item_name - ); - build_diagnostic( - cx, - &item, - path_str, - &dox, - link_range, - &err_msg, - "this item is private", - None, - ); + privacy_error(cx, &item, &path_str, &dox, link_range); continue; } } @@ -851,24 +832,33 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } } -fn build_diagnostic( +/// Reports a diagnostic for an intra-doc link. +/// +/// If no link range is provided, or the source span of the link cannot be determined, the span of +/// the entire documentation block is used for the lint. If a range is provided but the span +/// calculation fails, a note is added to the diagnostic pointing to the link in the markdown. +/// +/// The `decorate` callback is invoked in all cases to allow further customization of the +/// diagnostic before emission. If the span of the link was able to be determined, the second +/// parameter of the callback will contain it, and the primary span of the diagnostic will be set +/// to it. +fn report_diagnostic( cx: &DocContext<'_>, + msg: &str, item: &Item, - path_str: &str, dox: &str, link_range: Option>, - err_msg: &str, - short_err_msg: &str, - help_msg: Option<&str>, + decorate: impl FnOnce(&mut DiagnosticBuilder<'_>, Option), ) { let hir_id = match cx.as_local_hir_id(item.def_id) { Some(hir_id) => hir_id, None => { // If non-local, no need to check anything. - info!("ignoring warning from parent crate: {}", err_msg); + info!("ignoring warning from parent crate: {}", msg); return; } }; + let attrs = &item.attrs; let sp = span_of_attrs(attrs).unwrap_or(item.source.span()); @@ -877,12 +867,15 @@ fn build_diagnostic( hir_id, sp, |lint| { - let mut diag = lint.build(&format!("`[{}]` {}", path_str, err_msg)); + let mut diag = lint.build(msg); + + let span = link_range + .as_ref() + .and_then(|range| super::source_span_for_markdown_range(cx, dox, range, attrs)); + if let Some(link_range) = link_range { - if let Some(sp) = super::source_span_for_markdown_range(cx, dox, &link_range, attrs) - { + if let Some(sp) = span { diag.set_span(sp); - diag.span_label(sp, short_err_msg); } else { // blah blah blah\nblah\nblah [blah] blah blah\nblah blah // ^ ~~~~ @@ -902,20 +895,15 @@ fn build_diagnostic( found = link_range.len(), )); } - }; - if let Some(help_msg) = help_msg { - diag.help(help_msg); } + + decorate(&mut diag, span); + diag.emit(); }, ); } -/// Reports a resolution failure diagnostic. -/// -/// If we cannot find the exact source span of the resolution failure, we use the span of the -/// documentation attributes themselves. This is a little heavy-handed, so we display the markdown -/// line containing the failure as a note as well. fn resolution_failure( cx: &DocContext<'_>, item: &Item, @@ -923,15 +911,19 @@ fn resolution_failure( dox: &str, link_range: Option>, ) { - build_diagnostic( + report_diagnostic( cx, + &format!("unresolved link to `{}`", path_str), item, - path_str, dox, link_range, - "cannot be resolved, ignoring it.", - "cannot be resolved, ignoring", - Some("to escape `[` and `]` characters, just add '\\' before them like `\\[` or `\\]`"), + |diag, sp| { + if let Some(sp) = sp { + diag.span_label(sp, "unresolved link"); + } + + diag.help(r#"to escape `[` and `]` characters, add '\' before them like `\[` or `\]`"#); + }, ); } @@ -941,18 +933,39 @@ fn anchor_failure( path_str: &str, dox: &str, link_range: Option>, - msg: &str, + failure: AnchorFailure, ) { - build_diagnostic( - cx, - item, - path_str, - dox, - link_range, - "has an issue with the link anchor.", - msg, - None, - ); + let msg = match failure { + AnchorFailure::MultipleAnchors => format!("`{}` contains multiple anchors", path_str), + AnchorFailure::Primitive + | AnchorFailure::Variant + | AnchorFailure::AssocConstant + | AnchorFailure::AssocType + | AnchorFailure::Field + | AnchorFailure::Method => { + let kind = match failure { + AnchorFailure::Primitive => "primitive type", + AnchorFailure::Variant => "enum variant", + AnchorFailure::AssocConstant => "associated constant", + AnchorFailure::AssocType => "associated type", + AnchorFailure::Field => "struct field", + AnchorFailure::Method => "method", + AnchorFailure::MultipleAnchors => unreachable!("should be handled already"), + }; + + format!( + "`{}` contains an anchor, but links to {kind}s are already anchored", + path_str, + kind = kind + ) + } + }; + + report_diagnostic(cx, &msg, item, dox, link_range, |diag, sp| { + if let Some(sp) = sp { + diag.span_label(sp, "contains invalid anchor"); + } + }); } fn ambiguity_error( @@ -963,121 +976,100 @@ fn ambiguity_error( link_range: Option>, candidates: PerNS>, ) { - let hir_id = match cx.as_local_hir_id(item.def_id) { - Some(hir_id) => hir_id, - None => { - // If non-local, no need to check anything. - return; + let mut msg = format!("`{}` is ", path_str); + + let candidates = [TypeNS, ValueNS, MacroNS] + .iter() + .filter_map(|&ns| candidates[ns].map(|res| (res, ns))) + .collect::>(); + match candidates.as_slice() { + [(first_def, _), (second_def, _)] => { + msg += &format!( + "both {} {} and {} {}", + first_def.article(), + first_def.descr(), + second_def.article(), + second_def.descr(), + ); } - }; - let attrs = &item.attrs; - let sp = span_of_attrs(attrs).unwrap_or(item.source.span()); - - cx.tcx.struct_span_lint_hir( - lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE, - hir_id, - sp, - |lint| { - let mut msg = format!("`{}` is ", path_str); - - let candidates = [TypeNS, ValueNS, MacroNS] - .iter() - .filter_map(|&ns| candidates[ns].map(|res| (res, ns))) - .collect::>(); - match candidates.as_slice() { - [(first_def, _), (second_def, _)] => { - msg += &format!( - "both {} {} and {} {}", - first_def.article(), - first_def.descr(), - second_def.article(), - second_def.descr(), - ); - } - _ => { - let mut candidates = candidates.iter().peekable(); - while let Some((res, _)) = candidates.next() { - if candidates.peek().is_some() { - msg += &format!("{} {}, ", res.article(), res.descr()); - } else { - msg += &format!("and {} {}", res.article(), res.descr()); - } - } + _ => { + let mut candidates = candidates.iter().peekable(); + while let Some((res, _)) = candidates.next() { + if candidates.peek().is_some() { + msg += &format!("{} {}, ", res.article(), res.descr()); + } else { + msg += &format!("and {} {}", res.article(), res.descr()); } } + } + } - let mut diag = lint.build(&msg); + report_diagnostic(cx, &msg, item, dox, link_range.clone(), |diag, sp| { + if let Some(sp) = sp { + diag.span_label(sp, "ambiguous link"); - if let Some(link_range) = link_range { - if let Some(sp) = super::source_span_for_markdown_range(cx, dox, &link_range, attrs) - { - diag.set_span(sp); - diag.span_label(sp, "ambiguous link"); + let link_range = link_range.expect("must have a link range if we have a span"); - for (res, ns) in candidates { - let (action, mut suggestion) = match res { - Res::Def(DefKind::AssocFn | DefKind::Fn, _) => { - ("add parentheses", format!("{}()", path_str)) - } - Res::Def(DefKind::Macro(MacroKind::Bang), _) => { - ("add an exclamation mark", format!("{}!", path_str)) - } - _ => { - let type_ = match (res, ns) { - (Res::Def(DefKind::Const, _), _) => "const", - (Res::Def(DefKind::Static, _), _) => "static", - (Res::Def(DefKind::Struct, _), _) => "struct", - (Res::Def(DefKind::Enum, _), _) => "enum", - (Res::Def(DefKind::Union, _), _) => "union", - (Res::Def(DefKind::Trait, _), _) => "trait", - (Res::Def(DefKind::Mod, _), _) => "module", - (_, TypeNS) => "type", - (_, ValueNS) => "value", - (Res::Def(DefKind::Macro(MacroKind::Derive), _), MacroNS) => { - "derive" - } - (_, MacroNS) => "macro", - }; - - // FIXME: if this is an implied shortcut link, it's bad style to suggest `@` - ("prefix with the item type", format!("{}@{}", type_, path_str)) - } + for (res, ns) in candidates { + let (action, mut suggestion) = match res { + Res::Def(DefKind::AssocFn | DefKind::Fn, _) => { + ("add parentheses", format!("{}()", path_str)) + } + Res::Def(DefKind::Macro(MacroKind::Bang), _) => { + ("add an exclamation mark", format!("{}!", path_str)) + } + _ => { + let type_ = match (res, ns) { + (Res::Def(DefKind::Const, _), _) => "const", + (Res::Def(DefKind::Static, _), _) => "static", + (Res::Def(DefKind::Struct, _), _) => "struct", + (Res::Def(DefKind::Enum, _), _) => "enum", + (Res::Def(DefKind::Union, _), _) => "union", + (Res::Def(DefKind::Trait, _), _) => "trait", + (Res::Def(DefKind::Mod, _), _) => "module", + (_, TypeNS) => "type", + (_, ValueNS) => "value", + (Res::Def(DefKind::Macro(MacroKind::Derive), _), MacroNS) => "derive", + (_, MacroNS) => "macro", }; - if dox.bytes().nth(link_range.start) == Some(b'`') { - suggestion = format!("`{}`", suggestion); - } - - diag.span_suggestion( - sp, - &format!("to link to the {}, {}", res.descr(), action), - suggestion, - Applicability::MaybeIncorrect, - ); + // FIXME: if this is an implied shortcut link, it's bad style to suggest `@` + ("prefix with the item type", format!("{}@{}", type_, path_str)) } - } else { - // blah blah blah\nblah\nblah [blah] blah blah\nblah blah - // ^ ~~~~ - // | link_range - // last_new_line_offset - let last_new_line_offset = - dox[..link_range.start].rfind('\n').map_or(0, |n| n + 1); - let line = dox[last_new_line_offset..].lines().next().unwrap_or(""); + }; - // Print the line containing the `link_range` and manually mark it with '^'s. - diag.note(&format!( - "the link appears in this line:\n\n{line}\n\ - {indicator: , + item: &Item, + path_str: &str, + dox: &str, + link_range: Option>, +) { + let item_name = item.name.as_deref().unwrap_or(""); + let msg = + format!("public documentation for `{}` links to private item `{}`", item_name, path_str); + + report_diagnostic(cx, &msg, item, dox, link_range, |diag, sp| { + if let Some(sp) = sp { + diag.span_label(sp, "this item is private"); + } + }); } /// Given an enum variant's res, return the res of its enum and the associated fragment. @@ -1089,7 +1081,7 @@ fn handle_variant( use rustc_middle::ty::DefIdTree; if extra_fragment.is_some() { - return Err(ErrorKind::AnchorFailure("variants cannot be followed by anchors")); + return Err(ErrorKind::AnchorFailure(AnchorFailure::Variant)); } let parent = if let Some(parent) = cx.tcx.parent(res.def_id()) { parent diff --git a/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr index bc21cfd47c5d1..894518faa3168 100644 --- a/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr +++ b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr @@ -1,15 +1,15 @@ -error: `[v2]` cannot be resolved, ignoring it. +error: unresolved link to `v2` --> $DIR/deny-intra-link-resolution-failure.rs:3:6 | LL | /// [v2] - | ^^ cannot be resolved, ignoring + | ^^ unresolved link | note: the lint level is defined here --> $DIR/deny-intra-link-resolution-failure.rs:1:9 | LL | #![deny(intra_doc_link_resolution_failure)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: aborting due to previous error diff --git a/src/test/rustdoc-ui/intra-doc-alias-ice.stderr b/src/test/rustdoc-ui/intra-doc-alias-ice.stderr index cf26675163054..d2b2b90a4e50d 100644 --- a/src/test/rustdoc-ui/intra-doc-alias-ice.stderr +++ b/src/test/rustdoc-ui/intra-doc-alias-ice.stderr @@ -1,15 +1,15 @@ -error: `[TypeAlias::hoge]` cannot be resolved, ignoring it. +error: unresolved link to `TypeAlias::hoge` --> $DIR/intra-doc-alias-ice.rs:5:30 | LL | /// [broken cross-reference](TypeAlias::hoge) - | ^^^^^^^^^^^^^^^ cannot be resolved, ignoring + | ^^^^^^^^^^^^^^^ unresolved link | note: the lint level is defined here --> $DIR/intra-doc-alias-ice.rs:1:9 | LL | #![deny(intra_doc_link_resolution_failure)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: aborting due to previous error diff --git a/src/test/rustdoc-ui/intra-link-span-ice-55723.rs b/src/test/rustdoc-ui/intra-link-span-ice-55723.rs index 44997c90f5932..95388003f8470 100644 --- a/src/test/rustdoc-ui/intra-link-span-ice-55723.rs +++ b/src/test/rustdoc-ui/intra-link-span-ice-55723.rs @@ -7,7 +7,7 @@ /// ## For example: /// /// (arr[i]) -//~^ ERROR `[i]` cannot be resolved, ignoring it. +//~^ ERROR `i` pub fn test_ice() { unimplemented!(); } diff --git a/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr b/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr index ce31eb3a8a378..156e214a79ff0 100644 --- a/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr +++ b/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr @@ -1,15 +1,15 @@ -error: `[i]` cannot be resolved, ignoring it. +error: unresolved link to `i` --> $DIR/intra-link-span-ice-55723.rs:9:10 | LL | /// (arr[i]) - | ^ cannot be resolved, ignoring + | ^ unresolved link | note: the lint level is defined here --> $DIR/intra-link-span-ice-55723.rs:1:9 | LL | #![deny(intra_doc_link_resolution_failure)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: aborting due to previous error diff --git a/src/test/rustdoc-ui/intra-links-anchors.rs b/src/test/rustdoc-ui/intra-links-anchors.rs index 7f8a8dd3c45e0..7e61bd725359a 100644 --- a/src/test/rustdoc-ui/intra-links-anchors.rs +++ b/src/test/rustdoc-ui/intra-links-anchors.rs @@ -23,23 +23,23 @@ pub enum Enum { /// Like [Foo#hola]. /// /// Or maybe [Foo::f#hola]. -//~^ ERROR `[Foo::f#hola]` has an issue with the link anchor. +//~^ ERROR `Foo::f#hola` contains an anchor pub fn foo() {} /// Empty. /// /// Another anchor error: [hello#people#!]. -//~^ ERROR `[hello#people#!]` has an issue with the link anchor. +//~^ ERROR `hello#people#!` contains multiple anchors pub fn bar() {} /// Empty? /// /// Damn enum's variants: [Enum::A#whatever]. -//~^ ERROR `[Enum::A#whatever]` has an issue with the link anchor. +//~^ ERROR `Enum::A#whatever` contains an anchor pub fn enum_link() {} /// Primitives? /// /// [u32#hello] -//~^ ERROR `[u32#hello]` has an issue with the link anchor. +//~^ ERROR `u32#hello` contains an anchor pub fn x() {} diff --git a/src/test/rustdoc-ui/intra-links-anchors.stderr b/src/test/rustdoc-ui/intra-links-anchors.stderr index 11dee5547db4f..ef33d8f3e06fe 100644 --- a/src/test/rustdoc-ui/intra-links-anchors.stderr +++ b/src/test/rustdoc-ui/intra-links-anchors.stderr @@ -1,8 +1,8 @@ -error: `[Foo::f#hola]` has an issue with the link anchor. +error: `Foo::f#hola` contains an anchor, but links to struct fields are already anchored --> $DIR/intra-links-anchors.rs:25:15 | LL | /// Or maybe [Foo::f#hola]. - | ^^^^^^^^^^^ struct fields cannot be followed by anchors + | ^^^^^^^^^^^ contains invalid anchor | note: the lint level is defined here --> $DIR/intra-links-anchors.rs:1:9 @@ -10,23 +10,23 @@ note: the lint level is defined here LL | #![deny(intra_doc_link_resolution_failure)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `[hello#people#!]` has an issue with the link anchor. +error: `hello#people#!` contains multiple anchors --> $DIR/intra-links-anchors.rs:31:28 | LL | /// Another anchor error: [hello#people#!]. - | ^^^^^^^^^^^^^^ only one `#` is allowed in a link + | ^^^^^^^^^^^^^^ contains invalid anchor -error: `[Enum::A#whatever]` has an issue with the link anchor. +error: `Enum::A#whatever` contains an anchor, but links to enum variants are already anchored --> $DIR/intra-links-anchors.rs:37:28 | LL | /// Damn enum's variants: [Enum::A#whatever]. - | ^^^^^^^^^^^^^^^^ variants cannot be followed by anchors + | ^^^^^^^^^^^^^^^^ contains invalid anchor -error: `[u32#hello]` has an issue with the link anchor. +error: `u32#hello` contains an anchor, but links to primitive types are already anchored --> $DIR/intra-links-anchors.rs:43:6 | LL | /// [u32#hello] - | ^^^^^^^^^ primitive types cannot be followed by anchors + | ^^^^^^^^^ contains invalid anchor error: aborting due to 4 previous errors diff --git a/src/test/rustdoc-ui/intra-links-private.public.stderr b/src/test/rustdoc-ui/intra-links-private.public.stderr index 0a8dafdaf9466..a124435b08a99 100644 --- a/src/test/rustdoc-ui/intra-links-private.public.stderr +++ b/src/test/rustdoc-ui/intra-links-private.public.stderr @@ -1,4 +1,4 @@ -warning: `[DontDocMe]` public documentation for `DocMe` links to a private item +warning: public documentation for `DocMe` links to private item `DontDocMe` --> $DIR/intra-links-private.rs:6:11 | LL | /// docs [DontDocMe] diff --git a/src/test/rustdoc-ui/intra-links-private.rs b/src/test/rustdoc-ui/intra-links-private.rs index 86cf9fed3dab4..1b97f6e61bd23 100644 --- a/src/test/rustdoc-ui/intra-links-private.rs +++ b/src/test/rustdoc-ui/intra-links-private.rs @@ -4,7 +4,7 @@ #![cfg_attr(private, deny(intra_doc_link_resolution_failure))] /// docs [DontDocMe] -//[public]~^ WARNING `[DontDocMe]` public documentation for `DocMe` links to a private item +//[public]~^ WARNING public documentation for `DocMe` links to private item `DontDocMe` // FIXME: for [private] we should also make sure the link was actually generated pub struct DocMe; struct DontDocMe; diff --git a/src/test/rustdoc-ui/intra-links-warning-crlf.rs b/src/test/rustdoc-ui/intra-links-warning-crlf.rs index 18c9837b0bb45..a19c33b53be09 100644 --- a/src/test/rustdoc-ui/intra-links-warning-crlf.rs +++ b/src/test/rustdoc-ui/intra-links-warning-crlf.rs @@ -6,16 +6,16 @@ /// [error] pub struct A; -//~^^ WARNING `[error]` cannot be resolved +//~^^ WARNING `error` /// /// docs [error1] -//~^ WARNING `[error1]` cannot be resolved +//~^ WARNING `error1` /// docs [error2] /// pub struct B; -//~^^^ WARNING `[error2]` cannot be resolved +//~^^^ WARNING `error2` /** * This is a multi-line comment. @@ -23,4 +23,4 @@ pub struct B; * It also has an [error]. */ pub struct C; -//~^^^ WARNING `[error]` cannot be resolved +//~^^^ WARNING `error` diff --git a/src/test/rustdoc-ui/intra-links-warning-crlf.stderr b/src/test/rustdoc-ui/intra-links-warning-crlf.stderr index ac8691a8743ba..bc31264c170ea 100644 --- a/src/test/rustdoc-ui/intra-links-warning-crlf.stderr +++ b/src/test/rustdoc-ui/intra-links-warning-crlf.stderr @@ -1,35 +1,35 @@ -warning: `[error]` cannot be resolved, ignoring it. +warning: unresolved link to `error` --> $DIR/intra-links-warning-crlf.rs:7:6 | LL | /// [error] - | ^^^^^ cannot be resolved, ignoring + | ^^^^^ unresolved link | = note: `#[warn(intra_doc_link_resolution_failure)]` on by default - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[error1]` cannot be resolved, ignoring it. +warning: unresolved link to `error1` --> $DIR/intra-links-warning-crlf.rs:12:11 | LL | /// docs [error1] - | ^^^^^^ cannot be resolved, ignoring + | ^^^^^^ unresolved link | - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[error2]` cannot be resolved, ignoring it. +warning: unresolved link to `error2` --> $DIR/intra-links-warning-crlf.rs:15:11 | LL | /// docs [error2] - | ^^^^^^ cannot be resolved, ignoring + | ^^^^^^ unresolved link | - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[error]` cannot be resolved, ignoring it. +warning: unresolved link to `error` --> $DIR/intra-links-warning-crlf.rs:23:20 | LL | * It also has an [error]. - | ^^^^^ cannot be resolved, ignoring + | ^^^^^ unresolved link | - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: 4 warnings emitted diff --git a/src/test/rustdoc-ui/intra-links-warning.rs b/src/test/rustdoc-ui/intra-links-warning.rs index 623dcc320bb8d..eab1f03480460 100644 --- a/src/test/rustdoc-ui/intra-links-warning.rs +++ b/src/test/rustdoc-ui/intra-links-warning.rs @@ -1,37 +1,37 @@ // check-pass //! Test with [Foo::baz], [Bar::foo], ... -//~^ WARNING `[Foo::baz]` cannot be resolved -//~| WARNING `[Bar::foo]` cannot be resolved +//~^ WARNING `Foo::baz` +//~| WARNING `Bar::foo` //! , [Uniooon::X] and [Qux::Z]. -//~^ WARNING `[Uniooon::X]` cannot be resolved -//~| WARNING `[Qux::Z]` cannot be resolved +//~^ WARNING `Uniooon::X` +//~| WARNING `Qux::Z` //! //! , [Uniooon::X] and [Qux::Z]. -//~^ WARNING `[Uniooon::X]` cannot be resolved -//~| WARNING `[Qux::Z]` cannot be resolved +//~^ WARNING `Uniooon::X` +//~| WARNING `Qux::Z` /// [Qux:Y] -//~^ WARNING `[Qux:Y]` cannot be resolved +//~^ WARNING `Qux:Y` pub struct Foo { pub bar: usize, } /// Foo -/// bar [BarA] bar //~ WARNING `[BarA]` cannot be resolved +/// bar [BarA] bar //~ WARNING `BarA` /// baz pub fn a() {} /** * Foo - * bar [BarB] bar //~ WARNING `[BarB]` cannot be resolved + * bar [BarB] bar //~ WARNING `BarB` * baz */ pub fn b() {} /** Foo -bar [BarC] bar //~ WARNING `[BarC]` cannot be resolved +bar [BarC] bar //~ WARNING `BarC` baz let bar_c_1 = 0; @@ -42,12 +42,12 @@ baz */ pub fn c() {} -#[doc = "Foo\nbar [BarD] bar\nbaz"] //~ WARNING `[BarD]` cannot be resolved +#[doc = "Foo\nbar [BarD] bar\nbaz"] //~ WARNING `BarD` pub fn d() {} macro_rules! f { ($f:expr) => { - #[doc = $f] //~ WARNING `[BarF]` cannot be resolved + #[doc = $f] //~ WARNING `BarF` pub fn f() {} } } @@ -55,30 +55,30 @@ f!("Foo\nbar [BarF] bar\nbaz"); /** # for example, * - * time to introduce a link [error]*/ //~ WARNING `[error]` cannot be resolved + * time to introduce a link [error]*/ //~ WARNING `error` pub struct A; /** * # for example, * - * time to introduce a link [error] //~ WARNING `[error]` cannot be resolved + * time to introduce a link [error] //~ WARNING `error` */ pub struct B; -#[doc = "single line [error]"] //~ WARNING `[error]` cannot be resolved +#[doc = "single line [error]"] //~ WARNING `error` pub struct C; -#[doc = "single line with \"escaping\" [error]"] //~ WARNING `[error]` cannot be resolved +#[doc = "single line with \"escaping\" [error]"] //~ WARNING `error` pub struct D; -/// Item docs. //~ WARNING `[error]` cannot be resolved +/// Item docs. //~ WARNING `error` #[doc="Hello there!"] /// [error] pub struct E; /// -/// docs [error1] //~ WARNING `[error1]` cannot be resolved +/// docs [error1] //~ WARNING `error1` -/// docs [error2] //~ WARNING `[error2]` cannot be resolved +/// docs [error2] //~ WARNING `error2` /// pub struct F; diff --git a/src/test/rustdoc-ui/intra-links-warning.stderr b/src/test/rustdoc-ui/intra-links-warning.stderr index 914a19fc536c7..81931399c240a 100644 --- a/src/test/rustdoc-ui/intra-links-warning.stderr +++ b/src/test/rustdoc-ui/intra-links-warning.stderr @@ -1,77 +1,77 @@ -warning: `[Foo::baz]` cannot be resolved, ignoring it. +warning: unresolved link to `Foo::baz` --> $DIR/intra-links-warning.rs:3:23 | LL | //! Test with [Foo::baz], [Bar::foo], ... - | ^^^^^^^^ cannot be resolved, ignoring + | ^^^^^^^^ unresolved link | = note: `#[warn(intra_doc_link_resolution_failure)]` on by default - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[Bar::foo]` cannot be resolved, ignoring it. +warning: unresolved link to `Bar::foo` --> $DIR/intra-links-warning.rs:3:35 | LL | //! Test with [Foo::baz], [Bar::foo], ... - | ^^^^^^^^ cannot be resolved, ignoring + | ^^^^^^^^ unresolved link | - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[Uniooon::X]` cannot be resolved, ignoring it. +warning: unresolved link to `Uniooon::X` --> $DIR/intra-links-warning.rs:6:13 | LL | //! , [Uniooon::X] and [Qux::Z]. - | ^^^^^^^^^^ cannot be resolved, ignoring + | ^^^^^^^^^^ unresolved link | - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[Qux::Z]` cannot be resolved, ignoring it. +warning: unresolved link to `Qux::Z` --> $DIR/intra-links-warning.rs:6:30 | LL | //! , [Uniooon::X] and [Qux::Z]. - | ^^^^^^ cannot be resolved, ignoring + | ^^^^^^ unresolved link | - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[Uniooon::X]` cannot be resolved, ignoring it. +warning: unresolved link to `Uniooon::X` --> $DIR/intra-links-warning.rs:10:14 | LL | //! , [Uniooon::X] and [Qux::Z]. - | ^^^^^^^^^^ cannot be resolved, ignoring + | ^^^^^^^^^^ unresolved link | - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[Qux::Z]` cannot be resolved, ignoring it. +warning: unresolved link to `Qux::Z` --> $DIR/intra-links-warning.rs:10:31 | LL | //! , [Uniooon::X] and [Qux::Z]. - | ^^^^^^ cannot be resolved, ignoring + | ^^^^^^ unresolved link | - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[Qux:Y]` cannot be resolved, ignoring it. +warning: unresolved link to `Qux:Y` --> $DIR/intra-links-warning.rs:14:13 | LL | /// [Qux:Y] - | ^^^^^ cannot be resolved, ignoring + | ^^^^^ unresolved link | - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[error]` cannot be resolved, ignoring it. +warning: unresolved link to `error` --> $DIR/intra-links-warning.rs:58:30 | LL | * time to introduce a link [error]*/ - | ^^^^^ cannot be resolved, ignoring + | ^^^^^ unresolved link | - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[error]` cannot be resolved, ignoring it. +warning: unresolved link to `error` --> $DIR/intra-links-warning.rs:64:30 | LL | * time to introduce a link [error] - | ^^^^^ cannot be resolved, ignoring + | ^^^^^ unresolved link | - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[error]` cannot be resolved, ignoring it. +warning: unresolved link to `error` --> $DIR/intra-links-warning.rs:68:1 | LL | #[doc = "single line [error]"] @@ -81,9 +81,9 @@ LL | #[doc = "single line [error]"] single line [error] ^^^^^ - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[error]` cannot be resolved, ignoring it. +warning: unresolved link to `error` --> $DIR/intra-links-warning.rs:71:1 | LL | #[doc = "single line with \"escaping\" [error]"] @@ -93,9 +93,9 @@ LL | #[doc = "single line with \"escaping\" [error]"] single line with "escaping" [error] ^^^^^ - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[error]` cannot be resolved, ignoring it. +warning: unresolved link to `error` --> $DIR/intra-links-warning.rs:74:1 | LL | / /// Item docs. @@ -107,49 +107,49 @@ LL | | /// [error] [error] ^^^^^ - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[error1]` cannot be resolved, ignoring it. +warning: unresolved link to `error1` --> $DIR/intra-links-warning.rs:80:11 | LL | /// docs [error1] - | ^^^^^^ cannot be resolved, ignoring + | ^^^^^^ unresolved link | - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[error2]` cannot be resolved, ignoring it. +warning: unresolved link to `error2` --> $DIR/intra-links-warning.rs:82:11 | LL | /// docs [error2] - | ^^^^^^ cannot be resolved, ignoring + | ^^^^^^ unresolved link | - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[BarA]` cannot be resolved, ignoring it. +warning: unresolved link to `BarA` --> $DIR/intra-links-warning.rs:21:10 | LL | /// bar [BarA] bar - | ^^^^ cannot be resolved, ignoring + | ^^^^ unresolved link | - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[BarB]` cannot be resolved, ignoring it. +warning: unresolved link to `BarB` --> $DIR/intra-links-warning.rs:27:9 | LL | * bar [BarB] bar - | ^^^^ cannot be resolved, ignoring + | ^^^^ unresolved link | - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[BarC]` cannot be resolved, ignoring it. +warning: unresolved link to `BarC` --> $DIR/intra-links-warning.rs:34:6 | LL | bar [BarC] bar - | ^^^^ cannot be resolved, ignoring + | ^^^^ unresolved link | - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[BarD]` cannot be resolved, ignoring it. +warning: unresolved link to `BarD` --> $DIR/intra-links-warning.rs:45:1 | LL | #[doc = "Foo\nbar [BarD] bar\nbaz"] @@ -159,9 +159,9 @@ LL | #[doc = "Foo\nbar [BarD] bar\nbaz"] bar [BarD] bar ^^^^ - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[BarF]` cannot be resolved, ignoring it. +warning: unresolved link to `BarF` --> $DIR/intra-links-warning.rs:50:9 | LL | #[doc = $f] @@ -174,7 +174,7 @@ LL | f!("Foo\nbar [BarF] bar\nbaz"); bar [BarF] bar ^^^^ - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) warning: 19 warnings emitted diff --git a/src/test/rustdoc-ui/issue-74134.public.stderr b/src/test/rustdoc-ui/issue-74134.public.stderr index 03f95f19d326e..3c41f7e63e637 100644 --- a/src/test/rustdoc-ui/issue-74134.public.stderr +++ b/src/test/rustdoc-ui/issue-74134.public.stderr @@ -1,4 +1,4 @@ -warning: `[PrivateType]` public documentation for `public_item` links to a private item +warning: public documentation for `public_item` links to private item `PrivateType` --> $DIR/issue-74134.rs:19:10 | LL | /// [`PrivateType`] diff --git a/src/test/rustdoc-ui/issue-74134.rs b/src/test/rustdoc-ui/issue-74134.rs index d561c2dd89015..fe484b43fb6fc 100644 --- a/src/test/rustdoc-ui/issue-74134.rs +++ b/src/test/rustdoc-ui/issue-74134.rs @@ -17,7 +17,7 @@ pub struct PublicType; pub struct Public { /// [`PublicType`] /// [`PrivateType`] - //[public]~^ WARNING public documentation for `public_item` links to a private + //[public]~^ WARNING public documentation for `public_item` links to private item `PrivateType` pub public_item: u32, /// [`PublicType`] diff --git a/src/test/rustdoc-ui/lint-group.rs b/src/test/rustdoc-ui/lint-group.rs index 06766db5335a1..e58c8b12f68cb 100644 --- a/src/test/rustdoc-ui/lint-group.rs +++ b/src/test/rustdoc-ui/lint-group.rs @@ -11,7 +11,7 @@ /// ``` /// println!("sup"); /// ``` -pub fn link_error() {} //~^^^^^ ERROR cannot be resolved, ignoring it +pub fn link_error() {} //~^^^^^ ERROR unresolved link to `error` /// wait, this doesn't have a doctest? pub fn no_doctest() {} //~^ ERROR missing code example in this documentation diff --git a/src/test/rustdoc-ui/lint-group.stderr b/src/test/rustdoc-ui/lint-group.stderr index 852c9120e0bf9..14d72e9aad3ba 100644 --- a/src/test/rustdoc-ui/lint-group.stderr +++ b/src/test/rustdoc-ui/lint-group.stderr @@ -15,11 +15,11 @@ LL | #![deny(rustdoc)] | ^^^^^^^ = note: `#[deny(private_doc_tests)]` implied by `#[deny(rustdoc)]` -error: `[error]` cannot be resolved, ignoring it. +error: unresolved link to `error` --> $DIR/lint-group.rs:9:29 | LL | /// what up, let's make an [error] - | ^^^^^ cannot be resolved, ignoring + | ^^^^^ unresolved link | note: the lint level is defined here --> $DIR/lint-group.rs:7:9 @@ -27,7 +27,7 @@ note: the lint level is defined here LL | #![deny(rustdoc)] | ^^^^^^^ = note: `#[deny(intra_doc_link_resolution_failure)]` implied by `#[deny(rustdoc)]` - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: missing code example in this documentation --> $DIR/lint-group.rs:16:1 From 4c69d4bc05f43d801390c8498eea6e317e9d4b12 Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Sat, 11 Jul 2020 14:50:03 -0400 Subject: [PATCH 24/30] Add the aarch64-apple-darwin target This is a basic copy-paste-modify from the existing x86_64-apple-darwin target. --- .../spec/aarch64_apple_darwin.rs | 30 +++++++++++++++++++ src/librustc_target/spec/mod.rs | 1 + .../spec/x86_64_apple_darwin.rs | 5 +++- 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 src/librustc_target/spec/aarch64_apple_darwin.rs diff --git a/src/librustc_target/spec/aarch64_apple_darwin.rs b/src/librustc_target/spec/aarch64_apple_darwin.rs new file mode 100644 index 0000000000000..60daf10b36afe --- /dev/null +++ b/src/librustc_target/spec/aarch64_apple_darwin.rs @@ -0,0 +1,30 @@ +use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; + +pub fn target() -> TargetResult { + let mut base = super::apple_base::opts(); + base.cpu = "apple-a12".to_string(); + base.max_atomic_width = Some(128); + base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-arch".to_string(), "arm64".to_string()]); + + base.link_env_remove.extend(super::apple_base::macos_link_env_remove()); + + // Clang automatically chooses a more specific target based on + // MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work + // correctly, we do too. + let arch = "aarch64"; + let llvm_target = super::apple_base::macos_llvm_target(&arch); + + Ok(Target { + llvm_target, + target_endian: "little".to_string(), + target_pointer_width: "64".to_string(), + target_c_int_width: "32".to_string(), + data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".to_string(), + arch: arch.to_string(), + target_os: "macos".to_string(), + target_env: String::new(), + target_vendor: "apple".to_string(), + linker_flavor: LinkerFlavor::Gcc, + options: TargetOptions { target_mcount: "\u{1}mcount".to_string(), ..base }, + }) +} diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index d53033ba3ba20..5a97ef441c203 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -574,6 +574,7 @@ supported_targets! { ("i686-unknown-haiku", i686_unknown_haiku), ("x86_64-unknown-haiku", x86_64_unknown_haiku), + ("aarch64-apple-darwin", aarch64_apple_darwin), ("x86_64-apple-darwin", x86_64_apple_darwin), ("i686-apple-darwin", i686_apple_darwin), diff --git a/src/librustc_target/spec/x86_64_apple_darwin.rs b/src/librustc_target/spec/x86_64_apple_darwin.rs index 31011e8474958..909aebec70b58 100644 --- a/src/librustc_target/spec/x86_64_apple_darwin.rs +++ b/src/librustc_target/spec/x86_64_apple_darwin.rs @@ -5,7 +5,10 @@ pub fn target() -> TargetResult { base.cpu = "core2".to_string(); base.max_atomic_width = Some(128); // core2 support cmpxchg16b base.eliminate_frame_pointer = false; - base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]); + base.pre_link_args.insert( + LinkerFlavor::Gcc, + vec!["-m64".to_string(), "-arch".to_string(), "x86_64".to_string()], + ); base.link_env_remove.extend(super::apple_base::macos_link_env_remove()); base.stack_probes = true; From 804241ea06f20acc9bfd83c229507e726609f927 Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Sat, 11 Jul 2020 14:52:30 -0400 Subject: [PATCH 25/30] Update dependencies that have knowledge about aarch64-apple-darwin --- Cargo.lock | 8 ++++---- src/librustc_llvm/Cargo.toml | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 34a33eca3f40b..8391cba278631 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -412,9 +412,9 @@ version = "0.1.0" [[package]] name = "cc" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fde55d2a2bfaa4c9668bbc63f531fbdeee3ffe188f4662511ce2c22b3eedebe" +checksum = "f9a06fb2e53271d7c279ec1efea6ab691c35a2ae67ec0d91d7acec0caf13b518" dependencies = [ "jobserver", ] @@ -1576,9 +1576,9 @@ checksum = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" [[package]] name = "libc" -version = "0.2.71" +version = "0.2.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" +checksum = "bd7d4bd64732af4bf3a67f367c27df8520ad7e230c5817b8ff485864d80242b9" dependencies = [ "rustc-std-workspace-core", ] diff --git a/src/librustc_llvm/Cargo.toml b/src/librustc_llvm/Cargo.toml index 4fc02e348f646..1a034294cd8eb 100644 --- a/src/librustc_llvm/Cargo.toml +++ b/src/librustc_llvm/Cargo.toml @@ -14,8 +14,8 @@ static-libstdcpp = [] emscripten = [] [dependencies] -libc = "0.2" +libc = "0.2.73" [build-dependencies] build_helper = { path = "../build_helper" } -cc = "1.0.1" +cc = "1.0.58" From b3340b5cea5fdaefa4cbc7eec8ceb0592ebe2255 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Tue, 21 Jul 2020 02:28:51 +0100 Subject: [PATCH 26/30] Expand test to cover type_name and monomorphic use --- src/test/ui/consts/issue-73976-monomorphic.rs | 36 +++++++++++++++++++ ...ue-73976.rs => issue-73976-polymorphic.rs} | 16 ++++++++- .../ui/consts/issue-73976-polymorphic.stderr | 26 ++++++++++++++ src/test/ui/consts/issue-73976.stderr | 14 -------- 4 files changed, 77 insertions(+), 15 deletions(-) create mode 100644 src/test/ui/consts/issue-73976-monomorphic.rs rename src/test/ui/consts/{issue-73976.rs => issue-73976-polymorphic.rs} (62%) create mode 100644 src/test/ui/consts/issue-73976-polymorphic.stderr delete mode 100644 src/test/ui/consts/issue-73976.stderr diff --git a/src/test/ui/consts/issue-73976-monomorphic.rs b/src/test/ui/consts/issue-73976-monomorphic.rs new file mode 100644 index 0000000000000..7706a97f23b48 --- /dev/null +++ b/src/test/ui/consts/issue-73976-monomorphic.rs @@ -0,0 +1,36 @@ +// check-pass +// +// This test is complement to the test in issue-73976-polymorphic.rs. +// In that test we ensure that polymorphic use of type_id and type_name in patterns +// will be properly rejected. This test will ensure that monomorphic use of these +// would not be wrongly rejected in patterns. + +#![feature(const_type_id)] +#![feature(const_type_name)] + +use std::any::{self, TypeId}; + +pub struct GetTypeId(T); + +impl GetTypeId { + pub const VALUE: TypeId = TypeId::of::(); +} + +const fn check_type_id() -> bool { + matches!(GetTypeId::::VALUE, GetTypeId::::VALUE) +} + +pub struct GetTypeNameLen(T); + +impl GetTypeNameLen { + pub const VALUE: usize = any::type_name::().len(); +} + +const fn check_type_name_len() -> bool { + matches!(GetTypeNameLen::::VALUE, GetTypeNameLen::::VALUE) +} + +fn main() { + assert!(check_type_id::()); + assert!(check_type_name_len::()); +} diff --git a/src/test/ui/consts/issue-73976.rs b/src/test/ui/consts/issue-73976-polymorphic.rs similarity index 62% rename from src/test/ui/consts/issue-73976.rs rename to src/test/ui/consts/issue-73976-polymorphic.rs index ef141791c2cc8..28b84518719a1 100644 --- a/src/test/ui/consts/issue-73976.rs +++ b/src/test/ui/consts/issue-73976-polymorphic.rs @@ -6,8 +6,9 @@ // Currently we just disallow this usage and require pattern is monomorphic. #![feature(const_type_id)] +#![feature(const_type_name)] -use std::any::TypeId; +use std::any::{self, TypeId}; pub struct GetTypeId(T); @@ -21,6 +22,19 @@ const fn check_type_id() -> bool { //~| ERROR could not evaluate constant pattern } +pub struct GetTypeNameLen(T); + +impl GetTypeNameLen { + pub const VALUE: usize = any::type_name::().len(); +} + +const fn check_type_name_len() -> bool { + matches!(GetTypeNameLen::::VALUE, GetTypeNameLen::::VALUE) + //~^ ERROR could not evaluate constant pattern + //~| ERROR could not evaluate constant pattern +} + fn main() { assert!(check_type_id::()); + assert!(check_type_name_len::()); } diff --git a/src/test/ui/consts/issue-73976-polymorphic.stderr b/src/test/ui/consts/issue-73976-polymorphic.stderr new file mode 100644 index 0000000000000..c90ce2bd06a67 --- /dev/null +++ b/src/test/ui/consts/issue-73976-polymorphic.stderr @@ -0,0 +1,26 @@ +error: could not evaluate constant pattern + --> $DIR/issue-73976-polymorphic.rs:20:37 + | +LL | matches!(GetTypeId::::VALUE, GetTypeId::::VALUE) + | ^^^^^^^^^^^^^^^^^^^^^ + +error: could not evaluate constant pattern + --> $DIR/issue-73976-polymorphic.rs:32:42 + | +LL | matches!(GetTypeNameLen::::VALUE, GetTypeNameLen::::VALUE) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: could not evaluate constant pattern + --> $DIR/issue-73976-polymorphic.rs:20:37 + | +LL | matches!(GetTypeId::::VALUE, GetTypeId::::VALUE) + | ^^^^^^^^^^^^^^^^^^^^^ + +error: could not evaluate constant pattern + --> $DIR/issue-73976-polymorphic.rs:32:42 + | +LL | matches!(GetTypeNameLen::::VALUE, GetTypeNameLen::::VALUE) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/consts/issue-73976.stderr b/src/test/ui/consts/issue-73976.stderr deleted file mode 100644 index dbb7690b849c8..0000000000000 --- a/src/test/ui/consts/issue-73976.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: could not evaluate constant pattern - --> $DIR/issue-73976.rs:19:37 - | -LL | matches!(GetTypeId::::VALUE, GetTypeId::::VALUE) - | ^^^^^^^^^^^^^^^^^^^^^ - -error: could not evaluate constant pattern - --> $DIR/issue-73976.rs:19:37 - | -LL | matches!(GetTypeId::::VALUE, GetTypeId::::VALUE) - | ^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors - From 8b58eb9dc49254926c91690380c065403b10fbb8 Mon Sep 17 00:00:00 2001 From: Jamie Cunliffe Date: Tue, 21 Jul 2020 13:46:22 +0100 Subject: [PATCH 27/30] Remove the assert on alignment check. Also the alignment should only be done on general register types as per the AAPCS so fixed that issue. Copyright (c) 2020, Arm Limited. --- src/librustc_codegen_llvm/va_arg.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustc_codegen_llvm/va_arg.rs b/src/librustc_codegen_llvm/va_arg.rs index 8c0d256df2357..54efa05aee81e 100644 --- a/src/librustc_codegen_llvm/va_arg.rs +++ b/src/librustc_codegen_llvm/va_arg.rs @@ -128,8 +128,7 @@ fn emit_aapcs_va_arg( // it could be on the stack so we have to update the offset and then check // the offset again. - if layout.align.abi.bytes() > 8 { - assert!(layout.align.abi.bytes() <= 16); + if gr_type && layout.align.abi.bytes() > 8 { reg_off_v = maybe_reg.add(reg_off_v, bx.const_i32(15)); reg_off_v = maybe_reg.and(reg_off_v, bx.const_i32(-16)); } From 3eed7da1f93960871f16f8d6558a7b4356267f57 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 21 Jul 2020 07:58:59 -0700 Subject: [PATCH 28/30] Update books --- src/doc/book | 2 +- src/doc/edition-guide | 2 +- src/doc/reference | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/book b/src/doc/book index 84a31397b34f9..a914f2c7e5cdb 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 84a31397b34f9d405df44f2899ff17a4828dba18 +Subproject commit a914f2c7e5cdb771fa465de142381a51c53b580e diff --git a/src/doc/edition-guide b/src/doc/edition-guide index 82bec5877c77c..bd6e4a9f59c5c 160000 --- a/src/doc/edition-guide +++ b/src/doc/edition-guide @@ -1 +1 @@ -Subproject commit 82bec5877c77cfad530ca11095db4456d757f668 +Subproject commit bd6e4a9f59c5c1545f572266af77f5c7a5bad6d1 diff --git a/src/doc/reference b/src/doc/reference index 0ea7bc494f128..b329ce3742487 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 0ea7bc494f1289234d8800bb9185021e0ad946f0 +Subproject commit b329ce37424874ad4db94f829a55807c6e21d2cb From 7b05fb504194652b1d550babfce403fa11454233 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 20 Jul 2020 13:56:50 -0700 Subject: [PATCH 29/30] Change error code number --- src/librustc_error_codes/error_codes.rs | 2 +- .../nice_region_error/static_impl_trait.rs | 4 ++-- ...implicit-static-bound-needing-more-suggestions.rs | 3 +-- ...icit-static-bound-needing-more-suggestions.stderr | 12 ++++++------ ...mpl-on-dyn-trait-with-implicit-static-bound.fixed | 6 +++--- .../impl-on-dyn-trait-with-implicit-static-bound.rs | 6 +++--- ...pl-on-dyn-trait-with-implicit-static-bound.stderr | 6 +++--- 7 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs index a5d4adae8dba4..9d16b968286a7 100644 --- a/src/librustc_error_codes/error_codes.rs +++ b/src/librustc_error_codes/error_codes.rs @@ -632,5 +632,5 @@ E0770: include_str!("./error_codes/E0770.md"), E0755, // `#[ffi_pure]` is only allowed on foreign functions E0756, // `#[ffi_const]` is only allowed on foreign functions E0757, // `#[ffi_const]` functions cannot be `#[ffi_pure]` - E0767, // `'static' obligation coming from `impl dyn Trait {}` or `impl Foo for dyn Bar {}`. + E0772, // `'static' obligation coming from `impl dyn Trait {}` or `impl Foo for dyn Bar {}`. } diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs index 9581ee611fce8..4fa6d9d239424 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -48,7 +48,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let mut err = struct_span_err!( tcx.sess, cause.span, - E0767, + E0772, "{} has {} but calling `{}` introduces an implicit `'static` lifetime \ requirement", param @@ -196,7 +196,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } if let (Some(ident), true) = (override_error_code, fn_returns.is_empty()) { // Provide a more targetted error code and description. - err.code(rustc_errors::error_code!(E0767)); + err.code(rustc_errors::error_code!(E0772)); err.set_primary_message(&format!( "{} has {} but calling `{}` introduces an implicit `'static` lifetime \ requirement", diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs index ae6ffa8d93e01..b2dc16a27e310 100644 --- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs @@ -1,4 +1,3 @@ - // FIXME: the following cases need to suggest more things to make users reach a working end state. mod bav { @@ -64,7 +63,7 @@ mod bay { impl Bar for i32 {} fn use_it<'a>(val: Box + 'a>) -> &'a () { - val.use_self() //~ ERROR E0767 + val.use_self() //~ ERROR E0772 } } diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr index 2fab02fd1be45..00971b41c7ce6 100644 --- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr @@ -1,5 +1,5 @@ error[E0597]: `val` does not live long enough - --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:22:9 + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:21:9 | LL | fn use_it<'a>(val: Box>) -> impl OtherTrait<'a> { | -- lifetime `'a` defined here ------------------- opaque type requires that `val` is borrowed for `'a` @@ -14,7 +14,7 @@ LL | fn use_it<'a>(val: Box>) -> impl OtherTrai | ^^^^ error[E0515]: cannot return value referencing function parameter `val` - --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:44:9 + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:43:9 | LL | val.use_self() | ---^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | val.use_self() | `val` is borrowed here error[E0515]: cannot return value referencing function parameter `val` - --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:110:9 + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:109:9 | LL | val.use_self() | ---^^^^^^^^^^^ @@ -31,8 +31,8 @@ LL | val.use_self() | returns a value referencing data owned by the current function | `val` is borrowed here -error[E0767]: `val` has lifetime `'a` but calling `use_self` introduces an implicit `'static` lifetime requirement - --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:67:13 +error[E0772]: `val` has lifetime `'a` but calling `use_self` introduces an implicit `'static` lifetime requirement + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:66:13 | LL | fn use_it<'a>(val: Box + 'a>) -> &'a () { | -------------------------------------- this data with lifetime `'a`... @@ -40,7 +40,7 @@ LL | val.use_self() | ^^^^^^^^ ...is captured and required to live as long as `'static` here | note: the used `impl` has a `'static` requirement - --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:61:30 + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:60:30 | LL | impl MyTrait for Box> { | ^^^^^^^^^^^^^^^^^^^^^^^^ this has an implicit `'static` lifetime requirement diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.fixed b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.fixed index c568738d94b45..3c10f85d9423a 100644 --- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.fixed +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.fixed @@ -34,7 +34,7 @@ mod bar { impl Irrelevant for dyn ObjectTrait {} fn use_it<'a>(val: &'a dyn ObjectTrait) -> &'a () { - val.use_self() //~ ERROR E0767 + val.use_self() //~ ERROR E0772 } } @@ -51,7 +51,7 @@ mod baz { impl Irrelevant for Box {} fn use_it<'a>(val: &'a Box) -> &'a () { - val.use_self() //~ ERROR E0767 + val.use_self() //~ ERROR E0772 } } @@ -66,7 +66,7 @@ mod bat { } fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { - val.use_self() //~ ERROR E0767 + val.use_self() //~ ERROR E0772 } } diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.rs b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.rs index 8dd1e5d78de09..88ab03dfc1ef1 100644 --- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.rs +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.rs @@ -34,7 +34,7 @@ mod bar { impl Irrelevant for dyn ObjectTrait {} fn use_it<'a>(val: &'a dyn ObjectTrait) -> &'a () { - val.use_self() //~ ERROR E0767 + val.use_self() //~ ERROR E0772 } } @@ -51,7 +51,7 @@ mod baz { impl Irrelevant for Box {} fn use_it<'a>(val: &'a Box) -> &'a () { - val.use_self() //~ ERROR E0767 + val.use_self() //~ ERROR E0772 } } @@ -66,7 +66,7 @@ mod bat { } fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { - val.use_self() //~ ERROR E0767 + val.use_self() //~ ERROR E0772 } } diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr index 7e814fc664625..2fb6c25fd1702 100644 --- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr @@ -18,7 +18,7 @@ help: consider relaxing the implicit `'static` requirement LL | impl MyTrait for dyn ObjectTrait + '_ { | ^^^^ -error[E0767]: `val` has lifetime `'a` but calling `use_self` introduces an implicit `'static` lifetime requirement +error[E0772]: `val` has lifetime `'a` but calling `use_self` introduces an implicit `'static` lifetime requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:69:13 | LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { @@ -89,7 +89,7 @@ help: consider relaxing the implicit `'static` requirement LL | impl MyTrait for dyn ObjectTrait + '_ {} | ^^^^ -error[E0767]: `val` has lifetime `'a` but calling `use_self` introduces an implicit `'static` lifetime requirement +error[E0772]: `val` has lifetime `'a` but calling `use_self` introduces an implicit `'static` lifetime requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:37:13 | LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> &'a () { @@ -109,7 +109,7 @@ help: consider relaxing the implicit `'static` requirement LL | impl MyTrait for dyn ObjectTrait + '_ { | ^^^^ -error[E0767]: `val` has lifetime `'a` but calling `use_self` introduces an implicit `'static` lifetime requirement +error[E0772]: `val` has lifetime `'a` but calling `use_self` introduces an implicit `'static` lifetime requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:54:13 | LL | fn use_it<'a>(val: &'a Box) -> &'a () { From 96225b15e5480dae3c7e0f3df044553502c82d66 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 22 Jul 2020 16:28:47 +0200 Subject: [PATCH 30/30] Fix tooltip position if the documentation starts with a code block --- src/librustdoc/html/static/rustdoc.css | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 38709b445efae..85c125e5efdd4 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -1291,6 +1291,16 @@ h4 > .important-traits { /* Media Queries */ +@media (min-width: 701px) { + /* In case there is no documentation before a code block, we need to add some margin at the top + to prevent an overlay between the "collapse toggle" and the information tooltip. + However, it's needed needed with smaller screen width because the doc/code block is always put + "one line" below. */ + .information:first-child > .tooltip { + margin-top: 16px; + } +} + @media (max-width: 700px) { body { padding-top: 0px;