From 8462a378f313f7f279fb8f98a7dad703ef9ef897 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 17 Jul 2021 01:20:10 +0200 Subject: [PATCH 01/22] avoid temporary vectors Avoid collecting an interator just to re-iterate immediately. Rather reuse the previous iterator. (clippy::needless_collect) --- .../rustc_builtin_macros/src/deriving/generic/ty.rs | 10 +++------- compiler/rustc_infer/src/infer/error_reporting/mod.rs | 4 ++-- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs index 6b7d0e1f204b5..00d75be439964 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs @@ -72,13 +72,9 @@ impl Path { ) -> ast::Path { let mut idents = self.path.iter().map(|s| Ident::new(*s, span)).collect(); let lt = mk_lifetimes(cx, span, &self.lifetime); - let tys: Vec> = - self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics)).collect(); - let params = lt - .into_iter() - .map(GenericArg::Lifetime) - .chain(tys.into_iter().map(GenericArg::Type)) - .collect(); + let tys = self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics)); + let params = + lt.into_iter().map(GenericArg::Lifetime).chain(tys.map(GenericArg::Type)).collect(); match self.kind { PathKind::Global => cx.path_all(span, true, idents, params), diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index e3a79fe265330..a5a804a291643 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2134,7 +2134,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let new_lt = generics .as_ref() .and_then(|(parent_g, g)| { - let possible: Vec<_> = (b'a'..=b'z').map(|c| format!("'{}", c as char)).collect(); + let mut possible = (b'a'..=b'z').map(|c| format!("'{}", c as char)); let mut lts_names = g .params .iter() @@ -2150,7 +2150,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ); } let lts = lts_names.iter().map(|s| -> &str { &*s }).collect::>(); - possible.into_iter().find(|candidate| !lts.contains(&candidate.as_str())) + possible.find(|candidate| !lts.contains(&candidate.as_str())) }) .unwrap_or("'lt".to_string()); let add_lt_sugg = generics From d05a286449809cba5043bdac39074198a63cda6d Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Mon, 19 Jul 2021 18:50:06 +0800 Subject: [PATCH 02/22] Iterate through impls only when permitted --- .../src/transform/check_consts/validation.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index 646ae8ced7eb4..cfc538ef500a1 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -897,16 +897,19 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { permitted = true; } } - let mut const_impls = true; - tcx.for_each_relevant_impl(trait_id, substs.type_at(0), |imp| { - if const_impls { - if let hir::Constness::NotConst = tcx.impl_constness(imp) { - const_impls = false; + if !permitted { + // if trait's impls are all const, permit the call. + let mut const_impls = true; + tcx.for_each_relevant_impl(trait_id, substs.type_at(0), |imp| { + if const_impls { + if let hir::Constness::NotConst = tcx.impl_constness(imp) { + const_impls = false; + } } + }); + if const_impls { + permitted = true; } - }); - if const_impls { - permitted = true; } } From 4b82bbeac009c09c55e4a5458ee7338bddb14a44 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Mon, 19 Jul 2021 18:50:47 +0800 Subject: [PATCH 03/22] Recognize bounds on impls as const bounds --- compiler/rustc_hir/src/hir.rs | 21 +++++++++++++++++++ .../rustc_typeck/src/check/fn_ctxt/mod.rs | 9 +------- compiler/rustc_typeck/src/collect.rs | 7 +------ .../call-generic-in-impl.rs | 15 +++++++++++++ 4 files changed, 38 insertions(+), 14 deletions(-) create mode 100644 src/test/ui/rfc-2632-const-trait-impl/call-generic-in-impl.rs diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 4b2679e164aac..213887e26179c 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3064,6 +3064,27 @@ impl<'hir> Node<'hir> { Node::Crate(_) | Node::Visibility(_) => None, } } + + /// Returns `Constness::Const` when this node is a const fn/impl. + pub fn constness(&self) -> Constness { + match self { + Node::Item(Item { + kind: ItemKind::Fn(FnSig { header: FnHeader { constness, .. }, .. }, ..), + .. + }) + | Node::TraitItem(TraitItem { + kind: TraitItemKind::Fn(FnSig { header: FnHeader { constness, .. }, .. }, ..), + .. + }) + | Node::ImplItem(ImplItem { + kind: ImplItemKind::Fn(FnSig { header: FnHeader { constness, .. }, .. }, ..), + .. + }) + | Node::Item(Item { kind: ItemKind::Impl(Impl { constness, .. }), .. }) => *constness, + + _ => Constness::NotConst, + } + } } // Some nodes are used a lot. Make sure they don't unintentionally get bigger. diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs index 4da4835f7cfbb..13686cfec809a 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs @@ -15,7 +15,6 @@ use rustc_hir::def_id::DefId; use rustc_infer::infer; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; -use rustc_middle::hir::map::blocks::FnLikeNode; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, Const, Ty, TyCtxt}; @@ -175,13 +174,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { } fn default_constness_for_trait_bounds(&self) -> hir::Constness { - // FIXME: refactor this into a method - let node = self.tcx.hir().get(self.body_id); - if let Some(fn_like) = FnLikeNode::from_node(node) { - fn_like.constness() - } else { - hir::Constness::NotConst - } + self.tcx.hir().get(self.body_id).constness() } fn get_type_parameter_bounds( diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 506ca98b96026..1a4c2eb515584 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -35,7 +35,6 @@ use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::weak_lang_items; use rustc_hir::{GenericParamKind, HirId, Node}; -use rustc_middle::hir::map::blocks::FnLikeNode; use rustc_middle::hir::map::Map; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::mono::Linkage; @@ -358,11 +357,7 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> { } fn default_constness_for_trait_bounds(&self) -> hir::Constness { - if let Some(fn_like) = FnLikeNode::from_node(self.node()) { - fn_like.constness() - } else { - hir::Constness::NotConst - } + self.node().constness() } fn get_type_parameter_bounds( diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-in-impl.rs b/src/test/ui/rfc-2632-const-trait-impl/call-generic-in-impl.rs new file mode 100644 index 0000000000000..536c1d7374023 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-in-impl.rs @@ -0,0 +1,15 @@ +// check-pass +#![feature(const_fn_trait_bound)] +#![feature(const_trait_impl)] + +trait MyPartialEq { + fn eq(&self, other: &Self) -> bool; +} + +impl const MyPartialEq for T { + fn eq(&self, other: &Self) -> bool { + PartialEq::eq(self, other) + } +} + +fn main() {} From 7066398ec5cd67b1e0359d271022694cda23961a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 19 Jul 2021 11:50:14 +0200 Subject: [PATCH 04/22] Don't render in items' summary --- src/librustdoc/html/markdown.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index e21469dc9c343..908e292d968ef 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -57,7 +57,7 @@ pub(crate) fn opts() -> Options { /// A subset of [`opts()`] used for rendering summaries. pub(crate) fn summary_opts() -> Options { - Options::ENABLE_STRIKETHROUGH | Options::ENABLE_SMART_PUNCTUATION + Options::ENABLE_STRIKETHROUGH | Options::ENABLE_SMART_PUNCTUATION | Options::ENABLE_TABLES } /// When `to_string` is called, this struct will emit the HTML corresponding to @@ -522,6 +522,10 @@ fn check_if_allowed_tag(t: &Tag<'_>) -> bool { ) } +fn is_forbidden_tag(t: &Tag<'_>) -> bool { + matches!(t, Tag::CodeBlock(_) | Tag::Table(_) | Tag::TableHead | Tag::TableRow | Tag::TableCell) +} + impl<'a, I: Iterator>> Iterator for SummaryLine<'a, I> { type Item = Event<'a>; @@ -535,14 +539,17 @@ impl<'a, I: Iterator>> Iterator for SummaryLine<'a, I> { if let Some(event) = self.inner.next() { let mut is_start = true; let is_allowed_tag = match event { - Event::Start(Tag::CodeBlock(_)) | Event::End(Tag::CodeBlock(_)) => { - return None; - } Event::Start(ref c) => { + if is_forbidden_tag(c) { + return None; + } self.depth += 1; check_if_allowed_tag(c) } Event::End(ref c) => { + if is_forbidden_tag(c) { + return None; + } self.depth -= 1; is_start = false; check_if_allowed_tag(c) From d6dc840cf7b29ea2be93a4c443b38234f34d9902 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 19 Jul 2021 12:02:41 +0200 Subject: [PATCH 05/22] Add test to ensure tables are not inside items summary --- src/test/rustdoc-gui/item-summary-table.goml | 6 ++++++ src/test/rustdoc-gui/src/lib2/lib.rs | 7 +++++++ 2 files changed, 13 insertions(+) create mode 100644 src/test/rustdoc-gui/item-summary-table.goml diff --git a/src/test/rustdoc-gui/item-summary-table.goml b/src/test/rustdoc-gui/item-summary-table.goml new file mode 100644 index 0000000000000..6bf4e288c4377 --- /dev/null +++ b/src/test/rustdoc-gui/item-summary-table.goml @@ -0,0 +1,6 @@ +// This test ensures that
elements aren't display in items summary. +goto: file://|DOC_PATH|/lib2/summary_table/index.html +// We check that we picked the right item first. +assert-text: (".item-table .item-left", "Foo") +// Then we check that its summary is empty. +assert-text: (".item-table .item-right", "") diff --git a/src/test/rustdoc-gui/src/lib2/lib.rs b/src/test/rustdoc-gui/src/lib2/lib.rs index 0466909479b67..84091ad968f20 100644 --- a/src/test/rustdoc-gui/src/lib2/lib.rs +++ b/src/test/rustdoc-gui/src/lib2/lib.rs @@ -54,3 +54,10 @@ pub mod long_trait { pub trait ALongNameBecauseItHelpsTestingTheCurrentProblem: DerefMut + From + Send + Sync + AsRef + 'static {} } + +pub mod summary_table { + /// | header 1 | header 2 | + /// | -------- | -------- | + /// | content | content | + pub struct Foo; +} From 76ab8a6b107060aa09ec5dc0901d29502bda8497 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Mon, 19 Jul 2021 17:07:21 +0300 Subject: [PATCH 06/22] :arrow_up: rust-analyzer --- src/tools/rust-analyzer | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer index fe00358888a24..ea105f9396a9d 160000 --- a/src/tools/rust-analyzer +++ b/src/tools/rust-analyzer @@ -1 +1 @@ -Subproject commit fe00358888a24c64878abc15f09b0e60e16db9d6 +Subproject commit ea105f9396a9dab68e71efb06016b7c76c83ba7c From 2a56a681c4cfd56822e447a66adccdc32580b46a Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 19 Jul 2021 07:06:42 -0700 Subject: [PATCH 07/22] Add comments explaining the unix command-line argument support. Following up on #87236, add comments to the unix command-line argument support explaining that the code doesn't mutate the system-provided argc/argv, and that this is why the code doesn't need a lock or special memory ordering. --- library/std/src/sys/unix/args.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/unix/args.rs b/library/std/src/sys/unix/args.rs index ad93fa610c481..0bd1ea645779f 100644 --- a/library/std/src/sys/unix/args.rs +++ b/library/std/src/sys/unix/args.rs @@ -77,10 +77,18 @@ mod imp { use crate::ptr; use crate::sync::atomic::{AtomicIsize, AtomicPtr, Ordering}; + // The system-provided argc and argv, which we store in static memory + // here so that we can defer the work of parsing them until its actually + // needed. + // + // Note that we never mutate argv/argc, the argv array, or the argv + // strings, which allows the code in this file to be very simple. static ARGC: AtomicIsize = AtomicIsize::new(0); static ARGV: AtomicPtr<*const u8> = AtomicPtr::new(ptr::null_mut()); unsafe fn really_init(argc: isize, argv: *const *const u8) { + // These don't need to be ordered with each other or other stores, + // because they only hold the unmodified system-provide argv/argc. ARGC.store(argc, Ordering::Relaxed); ARGV.store(argv as *mut _, Ordering::Relaxed); } @@ -122,8 +130,14 @@ mod imp { fn clone() -> Vec { unsafe { - // Load ARGC and ARGV without a lock. If the store to either ARGV or - // ARGC isn't visible yet, we'll return an empty argument list. + // Load ARGC and ARGV, which hold the unmodified system-provided + // argc/argv, so we can read the pointed-to memory without atomics + // or synchronization. + // + // If either ARGC or ARGV is still zero or null, then either there + // really are no arguments, or someone is asking for `args()` + // before initialization has completed, and we return an empty + // list. let argv = ARGV.load(Ordering::Relaxed); let argc = if argv.is_null() { 0 } else { ARGC.load(Ordering::Relaxed) }; (0..argc) From 64f4e34d69a99b00e635a572a0643dd008bb5a3a Mon Sep 17 00:00:00 2001 From: Chinmay Deshpande Date: Mon, 19 Jul 2021 20:03:03 -0700 Subject: [PATCH 08/22] Fix typo in compile.rs --- src/bootstrap/compile.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 1fae4bee732c0..5b9ea97dea59d 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -2,7 +2,7 @@ //! library. //! //! This module contains some of the real meat in the rustbuild build system -//! which is where Cargo is used to compiler the standard library, libtest, and +//! which is where Cargo is used to compile the standard library, libtest, and //! compiler. This module is also responsible for assembling the sysroot as it //! goes along from the output of the previous stage. From d56c02d7e9d2ad9b563ad3695c65b976f1099ec7 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 19 Jul 2021 17:14:58 +0200 Subject: [PATCH 09/22] Allow combining -Cprofile-generate and -Cpanic=unwind when targeting MSVC. The LLVM limitation that previously prevented this has been fixed in LLVM 9 which is older than the oldest LLVM version we currently support. See https://github.com/rust-lang/rust/issues/61002. --- compiler/rustc_session/src/session.rs | 21 +------------------ src/test/codegen/pgo-instrumentation.rs | 3 +-- .../pgo-branch-weights/Makefile | 13 ------------ .../run-make-fulldeps/pgo-gen-lto/Makefile | 8 ------- .../pgo-gen-no-imp-symbols/Makefile | 8 ------- src/test/run-make-fulldeps/pgo-gen/Makefile | 8 ------- .../pgo-indirect-call-promotion/Makefile | 14 ------------- src/test/run-make-fulldeps/pgo-use/Makefile | 8 ------- 8 files changed, 2 insertions(+), 81 deletions(-) diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index f3ce78d2d78f8..86d495c3353b3 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1,7 +1,7 @@ use crate::cgu_reuse_tracker::CguReuseTracker; use crate::code_stats::CodeStats; pub use crate::code_stats::{DataTypeKind, FieldInfo, SizeKind, VariantInfo}; -use crate::config::{self, CrateType, OutputType, PrintRequest, SwitchWithOptPath}; +use crate::config::{self, CrateType, OutputType, SwitchWithOptPath}; use crate::filesearch; use crate::lint::{self, LintId}; use crate::parse::ParseSess; @@ -1440,25 +1440,6 @@ fn validate_commandline_args_with_session_available(sess: &Session) { } } - // PGO does not work reliably with panic=unwind on Windows. Let's make it - // an error to combine the two for now. It always runs into an assertions - // if LLVM is built with assertions, but without assertions it sometimes - // does not crash and will probably generate a corrupted binary. - // We should only display this error if we're actually going to run PGO. - // If we're just supposed to print out some data, don't show the error (#61002). - if sess.opts.cg.profile_generate.enabled() - && sess.target.is_like_msvc - && sess.panic_strategy() == PanicStrategy::Unwind - && sess.opts.prints.iter().all(|&p| p == PrintRequest::NativeStaticLibs) - { - sess.err( - "Profile-guided optimization does not yet work in conjunction \ - with `-Cpanic=unwind` on Windows when targeting MSVC. \ - See issue #61002 \ - for more information.", - ); - } - // Sanitizers can only be used on platforms that we know have working sanitizer codegen. let supported_sanitizers = sess.target.options.supported_sanitizers; let unsupported_sanitizers = sess.opts.debugging_opts.sanitizer - supported_sanitizers; diff --git a/src/test/codegen/pgo-instrumentation.rs b/src/test/codegen/pgo-instrumentation.rs index c085f3c829ea4..05c2d2fc0d8c1 100644 --- a/src/test/codegen/pgo-instrumentation.rs +++ b/src/test/codegen/pgo-instrumentation.rs @@ -1,8 +1,7 @@ // Test that `-Cprofile-generate` creates expected instrumentation artifacts in LLVM IR. -// Compiling with `-Cpanic=abort` because PGO+unwinding isn't supported on all platforms. // needs-profiler-support -// compile-flags: -Cprofile-generate -Ccodegen-units=1 -Cpanic=abort +// compile-flags: -Cprofile-generate -Ccodegen-units=1 // CHECK: @__llvm_profile_raw_version = // CHECK-DAG: @__profc_{{.*}}pgo_instrumentation{{.*}}some_function{{.*}} = {{.*}}global diff --git a/src/test/run-make-fulldeps/pgo-branch-weights/Makefile b/src/test/run-make-fulldeps/pgo-branch-weights/Makefile index 18828b66ce874..9773e3f1fdfc4 100644 --- a/src/test/run-make-fulldeps/pgo-branch-weights/Makefile +++ b/src/test/run-make-fulldeps/pgo-branch-weights/Makefile @@ -6,19 +6,6 @@ -include ../tools.mk -# This test makes sure that instrumented binaries record the right counts for -# functions being called and branches being taken. We run an instrumented binary -# with an argument that causes a know path through the program and then check -# that the expected counts get added to the use-phase LLVM IR. - -# LLVM doesn't support instrumenting binaries that use SEH: -# https://github.com/rust-lang/rust/issues/61002 -# -# Things work fine with -Cpanic=abort though. -ifdef IS_MSVC -COMMON_FLAGS=-Cpanic=abort -endif - # For some very small programs GNU ld seems to not properly handle # instrumentation sections correctly. Neither Gold nor LLD have that problem. ifeq ($(UNAME),Linux) diff --git a/src/test/run-make-fulldeps/pgo-gen-lto/Makefile b/src/test/run-make-fulldeps/pgo-gen-lto/Makefile index f1ac39aa0ea8a..a7d5c56163257 100644 --- a/src/test/run-make-fulldeps/pgo-gen-lto/Makefile +++ b/src/test/run-make-fulldeps/pgo-gen-lto/Makefile @@ -8,14 +8,6 @@ COMPILE_FLAGS=-Copt-level=3 -Clto=fat -Cprofile-generate="$(TMPDIR)" -# LLVM doesn't yet support instrumenting binaries that use unwinding on MSVC: -# https://github.com/rust-lang/rust/issues/61002 -# -# Things work fine with -Cpanic=abort though. -ifdef IS_MSVC -COMPILE_FLAGS+= -Cpanic=abort -endif - all: $(RUSTC) $(COMPILE_FLAGS) test.rs $(call RUN,test) || exit 1 diff --git a/src/test/run-make-fulldeps/pgo-gen-no-imp-symbols/Makefile b/src/test/run-make-fulldeps/pgo-gen-no-imp-symbols/Makefile index 3fbfeb09eb373..425bfc28a9766 100644 --- a/src/test/run-make-fulldeps/pgo-gen-no-imp-symbols/Makefile +++ b/src/test/run-make-fulldeps/pgo-gen-no-imp-symbols/Makefile @@ -4,14 +4,6 @@ COMPILE_FLAGS=-O -Ccodegen-units=1 -Cprofile-generate="$(TMPDIR)" -# LLVM doesn't yet support instrumenting binaries that use unwinding on MSVC: -# https://github.com/rust-lang/rust/issues/61002 -# -# Things work fine with -Cpanic=abort though. -ifdef IS_MSVC -COMPILE_FLAGS+= -Cpanic=abort -endif - all: $(RUSTC) $(COMPILE_FLAGS) --emit=llvm-ir test.rs # We expect symbols starting with "__llvm_profile_". diff --git a/src/test/run-make-fulldeps/pgo-gen/Makefile b/src/test/run-make-fulldeps/pgo-gen/Makefile index 69b19801bf091..6533355be3418 100644 --- a/src/test/run-make-fulldeps/pgo-gen/Makefile +++ b/src/test/run-make-fulldeps/pgo-gen/Makefile @@ -8,14 +8,6 @@ COMPILE_FLAGS=-g -Cprofile-generate="$(TMPDIR)" -# LLVM doesn't yet support instrumenting binaries that use unwinding on MSVC: -# https://github.com/rust-lang/rust/issues/61002 -# -# Things work fine with -Cpanic=abort though. -ifdef IS_MSVC -COMPILE_FLAGS+= -Cpanic=abort -endif - all: $(RUSTC) $(COMPILE_FLAGS) test.rs $(call RUN,test) || exit 1 diff --git a/src/test/run-make-fulldeps/pgo-indirect-call-promotion/Makefile b/src/test/run-make-fulldeps/pgo-indirect-call-promotion/Makefile index 876a9b2c43991..c0195dcbb31be 100644 --- a/src/test/run-make-fulldeps/pgo-indirect-call-promotion/Makefile +++ b/src/test/run-make-fulldeps/pgo-indirect-call-promotion/Makefile @@ -6,20 +6,6 @@ -include ../tools.mk -# This test makes sure that indirect call promotion is performed. The test -# programs calls the same function a thousand times through a function pointer. -# Only PGO data provides the information that it actually always is the same -# function. We verify that the indirect call promotion pass inserts a check -# whether it can make a direct call instead of the indirect call. - -# LLVM doesn't support instrumenting binaries that use SEH: -# https://github.com/rust-lang/rust/issues/61002 -# -# Things work fine with -Cpanic=abort though. -ifdef IS_MSVC -COMMON_FLAGS=-Cpanic=abort -endif - all: # We don't compile `opaque` with either optimizations or instrumentation. # We don't compile `opaque` with either optimizations or instrumentation. diff --git a/src/test/run-make-fulldeps/pgo-use/Makefile b/src/test/run-make-fulldeps/pgo-use/Makefile index 01bc211df1616..d7863c9c587a5 100644 --- a/src/test/run-make-fulldeps/pgo-use/Makefile +++ b/src/test/run-make-fulldeps/pgo-use/Makefile @@ -18,14 +18,6 @@ COMMON_FLAGS=-Copt-level=2 -Ccodegen-units=1 -Cllvm-args=-disable-preinline -# LLVM doesn't support instrumenting binaries that use SEH: -# https://github.com/rust-lang/rust/issues/61002 -# -# Things work fine with -Cpanic=abort though. -ifdef IS_MSVC -COMMON_FLAGS+= -Cpanic=abort -endif - ifeq ($(UNAME),Darwin) # macOS does not have the `tac` command, but `tail -r` does the same thing TAC := tail -r From b9b0a5e05400d61df0f0f8745a9d9e7bf8a85e3e Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 19 Jul 2021 16:38:14 +0000 Subject: [PATCH 10/22] Fix VecMap::iter_mut It used to allow you to mutate the key, even though that can invalidate the map by creating duplicate keys. --- compiler/rustc_data_structures/src/lib.rs | 1 + compiler/rustc_data_structures/src/vec_map.rs | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 16151e9dca5e0..4467980054f54 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -24,6 +24,7 @@ #![feature(new_uninit)] #![feature(once_cell)] #![feature(maybe_uninit_uninit_array)] +#![feature(min_type_alias_impl_trait)] #![allow(rustc::default_hash_types)] #![deny(unaligned_references)] diff --git a/compiler/rustc_data_structures/src/vec_map.rs b/compiler/rustc_data_structures/src/vec_map.rs index 1786fa340cc8b..96e33184658a3 100644 --- a/compiler/rustc_data_structures/src/vec_map.rs +++ b/compiler/rustc_data_structures/src/vec_map.rs @@ -1,6 +1,6 @@ use std::borrow::Borrow; use std::iter::FromIterator; -use std::slice::{Iter, IterMut}; +use std::slice::Iter; use std::vec::IntoIter; use crate::stable_hasher::{HashStable, StableHasher}; @@ -67,7 +67,7 @@ where self.into_iter() } - pub fn iter_mut(&mut self) -> IterMut<'_, (K, V)> { + pub fn iter_mut(&mut self) -> impl Iterator { self.into_iter() } } @@ -108,12 +108,12 @@ impl<'a, K, V> IntoIterator for &'a VecMap { } impl<'a, K, V> IntoIterator for &'a mut VecMap { - type Item = &'a mut (K, V); - type IntoIter = IterMut<'a, (K, V)>; + type Item = (&'a K, &'a mut V); + type IntoIter = impl Iterator; #[inline] fn into_iter(self) -> Self::IntoIter { - self.0.iter_mut() + self.0.iter_mut().map(|(k, v)| (&*k, v)) } } From 75d9ed7b024aefa9e48b17f7f49b351b056b83ed Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 19 Jul 2021 16:50:43 +0000 Subject: [PATCH 11/22] Make mir borrowck's use of opaque types independent of the typeck query's result --- compiler/rustc_data_structures/src/vec_map.rs | 4 + .../src/borrow_check/type_check/mod.rs | 149 ++++++++---------- .../assoc-type-eq-with-dyn-atb-fail.rs | 1 - .../assoc-type-eq-with-dyn-atb-fail.stderr | 8 +- src/test/ui/impl-trait/auto-trait-leak.rs | 1 - src/test/ui/impl-trait/auto-trait-leak.stderr | 34 ++-- ...does_not_live_long_enough.full_tait.stderr | 11 +- ..._does_not_live_long_enough.min_tait.stderr | 11 +- .../generic_type_does_not_live_long_enough.rs | 1 - .../issue-57611-trait-alias.full_tait.stderr | 49 +----- .../issue-57611-trait-alias.min_tait.stderr | 49 +----- .../issue-57611-trait-alias.rs | 4 - .../ui/type-alias-impl-trait/issue-60371.rs | 1 - .../type-alias-impl-trait/issue-60371.stderr | 13 +- .../ui/type-alias-impl-trait/issue-74761-2.rs | 19 +++ .../issue-74761-2.stderr | 34 ++++ .../multiple-def-uses-in-one-fn2.rs | 2 +- .../multiple-def-uses-in-one-fn2.stderr | 14 +- .../multiple-def-uses-in-one-fn3.rs | 1 + .../multiple-def-uses-in-one-fn3.stderr | 17 +- 20 files changed, 162 insertions(+), 261 deletions(-) create mode 100644 src/test/ui/type-alias-impl-trait/issue-74761-2.rs create mode 100644 src/test/ui/type-alias-impl-trait/issue-74761-2.stderr diff --git a/compiler/rustc_data_structures/src/vec_map.rs b/compiler/rustc_data_structures/src/vec_map.rs index 96e33184658a3..e3fa587985df0 100644 --- a/compiler/rustc_data_structures/src/vec_map.rs +++ b/compiler/rustc_data_structures/src/vec_map.rs @@ -70,6 +70,10 @@ where pub fn iter_mut(&mut self) -> impl Iterator { self.into_iter() } + + pub fn retain(&mut self, f: impl Fn(&(K, V)) -> bool) { + self.0.retain(f) + } } impl Default for VecMap { diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs index aa3ff98f7ff9f..de327047a872a 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -26,7 +26,7 @@ use rustc_middle::mir::*; use rustc_middle::ty::adjustment::PointerCast; use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef, UserSubsts}; +use rustc_middle::ty::subst::{GenericArgKind, SubstsRef, UserSubsts}; use rustc_middle::ty::{ self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueTypeKey, RegionVid, ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, WithConstness, @@ -60,7 +60,6 @@ use crate::borrow_check::{ LivenessValues, PlaceholderIndex, PlaceholderIndices, RegionValueElements, }, region_infer::{ClosureRegionRequirementsExt, TypeTest}, - renumber, type_check::free_region_relations::{CreateResult, UniversalRegionRelations}, universal_regions::{DefiningTy, UniversalRegions}, Upvar, @@ -180,7 +179,66 @@ pub(crate) fn type_check<'mir, 'tcx>( liveness::generate(&mut cx, body, elements, flow_inits, move_data, location_table); translate_outlives_facts(&mut cx); - cx.opaque_type_values + let mut opaque_type_values = cx.opaque_type_values; + + for (_, revealed_ty) in &mut opaque_type_values { + // FIXME(oli-obk): Instead of looping, implement a visitor like + // FullTypeResolver. We can't use FullTypeResolver here, as that will + // resolve lifetimes lexically, which it can't because we didn't do old + // borrowck stuff. We want to use MIR borrowck information instead. + + while revealed_ty.has_infer_types_or_consts() { + let prev = *revealed_ty; + trace!(prev=?prev.kind()); + let type_resolved = infcx.shallow_resolve(prev); + trace!(type_resolved=?type_resolved.kind()); + if prev == type_resolved { + infcx.tcx.sess.delay_span_bug( + body.span, + &format!("could not resolve {:#?}", type_resolved.kind()), + ); + *revealed_ty = infcx.tcx.ty_error(); + break; + } + *revealed_ty = type_resolved; + } + } + + opaque_type_values.retain(|(opaque_type_key, resolved_ty)| { + let concrete_is_opaque = if let ty::Opaque(def_id, _) = resolved_ty.kind() { + *def_id == opaque_type_key.def_id + } else { + false + }; + + if concrete_is_opaque { + // We're using an opaque `impl Trait` type without + // 'revealing' it. For example, code like this: + // + // type Foo = impl Debug; + // fn foo1() -> Foo { ... } + // fn foo2() -> Foo { foo1() } + // + // In `foo2`, we're not revealing the type of `Foo` - we're + // just treating it as the opaque type. + // + // When this occurs, we do *not* want to try to equate + // the concrete type with the underlying defining type + // of the opaque type - this will always fail, since + // the defining type of an opaque type is always + // some other type (e.g. not itself) + // Essentially, none of the normal obligations apply here - + // we're just passing around some unknown opaque type, + // without actually looking at the underlying type it + // gets 'revealed' into + debug!( + "eq_opaque_type_and_type: non-defining use of {:?}", + opaque_type_key.def_id, + ); + } + !concrete_is_opaque + }); + opaque_type_values }, ); @@ -1240,13 +1298,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } let infcx = self.infcx; - let tcx = infcx.tcx; let param_env = self.param_env; let body = self.body; let mir_def_id = body.source.def_id().expect_local(); - // the "concrete opaque types" maps - let concrete_opaque_types = &tcx.typeck(mir_def_id).concrete_opaque_types; let mut opaque_type_values = VecMap::new(); debug!("eq_opaque_type_and_type: mir_def_id={:?}", mir_def_id); @@ -1296,88 +1351,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { .eq(output_ty, revealed_ty)?, ); - // For each opaque type `Foo` inferred by this value, we want to equate - // the inference variable `?T` with the revealed type that was computed - // earlier by type check. for &(opaque_type_key, opaque_decl) in &opaque_type_map { - let resolved_ty = infcx.resolve_vars_if_possible(opaque_decl.concrete_ty); - let concrete_is_opaque = if let ty::Opaque(def_id, _) = resolved_ty.kind() { - *def_id == opaque_type_key.def_id - } else { - false - }; - - // The revealed type computed by the earlier phase of type check. - // In our example, this would be `(U, u32)`. Note that this references - // the type parameter `U` from the definition of `Foo`. - let concrete_ty = match concrete_opaque_types - .get_by(|(key, _)| key.def_id == opaque_type_key.def_id) - { - None => { - if !concrete_is_opaque { - tcx.sess.delay_span_bug( - body.span, - &format!( - "Non-defining use of {:?} with revealed type", - opaque_type_key.def_id, - ), - ); - } - continue; - } - Some(concrete_ty) => concrete_ty, - }; - debug!("concrete_ty = {:?}", concrete_ty); - - // Apply the substitution, in this case `[U -> T]`, so that the - // concrete type becomes `Foo<(T, u32)>` - let subst_opaque_defn_ty = concrete_ty.subst(tcx, opaque_type_key.substs); - - // "Renumber" this, meaning that we replace all the regions - // with fresh inference variables. Not relevant to our example. - let renumbered_opaque_defn_ty = - renumber::renumber_regions(infcx, subst_opaque_defn_ty); - - debug!( - "eq_opaque_type_and_type: concrete_ty={:?}={:?} opaque_defn_ty={:?}", - concrete_ty, resolved_ty, renumbered_opaque_defn_ty, - ); - - if !concrete_is_opaque { - // Equate the instantiated opaque type `opaque_decl.concrete_ty` (`?T`, - // in our example) with the renumbered version that we took from - // the type check results (`Foo<(T, u32)>`). - obligations.add( - infcx - .at(&ObligationCause::dummy(), param_env) - .eq(opaque_decl.concrete_ty, renumbered_opaque_defn_ty)?, - ); - opaque_type_values.insert(opaque_type_key, renumbered_opaque_defn_ty); - } else { - // We're using an opaque `impl Trait` type without - // 'revealing' it. For example, code like this: - // - // type Foo = impl Debug; - // fn foo1() -> Foo { ... } - // fn foo2() -> Foo { foo1() } - // - // In `foo2`, we're not revealing the type of `Foo` - we're - // just treating it as the opaque type. - // - // When this occurs, we do *not* want to try to equate - // the concrete type with the underlying defining type - // of the opaque type - this will always fail, since - // the defining type of an opaque type is always - // some other type (e.g. not itself) - // Essentially, none of the normal obligations apply here - - // we're just passing around some unknown opaque type, - // without actually looking at the underlying type it - // gets 'revealed' into - debug!( - "eq_opaque_type_and_type: non-defining use of {:?}", - opaque_type_key.def_id, - ); - } + opaque_type_values.insert(opaque_type_key, opaque_decl.concrete_ty); } debug!("eq_opaque_type_and_type: equated"); diff --git a/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.rs b/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.rs index 73b23da5bcb66..7950dd3e99e29 100644 --- a/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.rs +++ b/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.rs @@ -29,7 +29,6 @@ impl Bar for AssocNoCopy { impl Thing for AssocNoCopy { type Out = Box>; //~^ ERROR the trait bound `String: Copy` is not satisfied - //~| ERROR the trait bound `String: Copy` is not satisfied fn func() -> Self::Out { Box::new(AssocNoCopy) diff --git a/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr b/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr index 414d74d4786d9..0f1d35be0eb7a 100644 --- a/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr +++ b/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr @@ -4,12 +4,6 @@ error[E0277]: the trait bound `String: Copy` is not satisfied LL | type Out = Box>; | ^^^^^^^^^^^ the trait `Copy` is not implemented for `String` -error[E0277]: the trait bound `String: Copy` is not satisfied - --> $DIR/assoc-type-eq-with-dyn-atb-fail.rs:30:28 - | -LL | type Out = Box>; - | ^^^^^^^^^^^ the trait `Copy` is not implemented for `String` - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/impl-trait/auto-trait-leak.rs b/src/test/ui/impl-trait/auto-trait-leak.rs index 087f4582b21c3..c2fbbf94fd666 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.rs +++ b/src/test/ui/impl-trait/auto-trait-leak.rs @@ -12,7 +12,6 @@ fn main() { fn cycle1() -> impl Clone { //~^ ERROR cycle detected send(cycle2().clone()); - //~^ ERROR cannot be sent between threads safely Rc::new(Cell::new(5)) } diff --git a/src/test/ui/impl-trait/auto-trait-leak.stderr b/src/test/ui/impl-trait/auto-trait-leak.stderr index e578c4b4f819e..3eb141cc2bb55 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak.stderr @@ -36,37 +36,37 @@ LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... note: ...which requires computing type of `cycle2::{opaque#0}`... - --> $DIR/auto-trait-leak.rs:20:16 + --> $DIR/auto-trait-leak.rs:19:16 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^ note: ...which requires borrow-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:20:1 + --> $DIR/auto-trait-leak.rs:19:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires processing `cycle2`... - --> $DIR/auto-trait-leak.rs:20:1 + --> $DIR/auto-trait-leak.rs:19:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires processing MIR for `cycle2`... - --> $DIR/auto-trait-leak.rs:20:1 + --> $DIR/auto-trait-leak.rs:19:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires unsafety-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:20:1 + --> $DIR/auto-trait-leak.rs:19:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires building MIR for `cycle2`... - --> $DIR/auto-trait-leak.rs:20:1 + --> $DIR/auto-trait-leak.rs:19:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires type-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:20:1 + --> $DIR/auto-trait-leak.rs:19:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -84,22 +84,6 @@ LL | | Rc::new(String::from("foo")) LL | | } | |_^ -error[E0277]: `Rc` cannot be sent between threads safely - --> $DIR/auto-trait-leak.rs:14:5 - | -LL | fn send(_: T) {} - | ---- required by this bound in `send` -... -LL | send(cycle2().clone()); - | ^^^^ `Rc` cannot be sent between threads safely -... -LL | fn cycle2() -> impl Clone { - | ---------- within this `impl Clone` - | - = help: within `impl Clone`, the trait `Send` is not implemented for `Rc` - = note: required because it appears within the type `impl Clone` - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0277, E0391. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.full_tait.stderr b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.full_tait.stderr index 6394a1f8e8509..90a753b5a6de1 100644 --- a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.full_tait.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.full_tait.stderr @@ -36,16 +36,7 @@ LL | type WrongGeneric = impl 'static; LL | fn wrong_generic(t: T) -> WrongGeneric { | - help: consider adding an explicit lifetime bound...: `T: 'static` -error[E0310]: the parameter type `T` may not live long enough - --> $DIR/generic_type_does_not_live_long_enough.rs:12:24 - | -LL | type WrongGeneric = impl 'static; - | ^^^^^^^^^^^^ - | - = help: consider adding an explicit lifetime bound `T: 'static`... - = note: ...so that the type `T` will meet its required lifetime bounds - -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 3 previous errors; 1 warning emitted Some errors have detailed explanations: E0308, E0310. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.min_tait.stderr b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.min_tait.stderr index 49ead8b094c19..e50282201074e 100644 --- a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.min_tait.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.min_tait.stderr @@ -27,16 +27,7 @@ LL | type WrongGeneric = impl 'static; LL | fn wrong_generic(t: T) -> WrongGeneric { | - help: consider adding an explicit lifetime bound...: `T: 'static` -error[E0310]: the parameter type `T` may not live long enough - --> $DIR/generic_type_does_not_live_long_enough.rs:12:24 - | -LL | type WrongGeneric = impl 'static; - | ^^^^^^^^^^^^ - | - = help: consider adding an explicit lifetime bound `T: 'static`... - = note: ...so that the type `T` will meet its required lifetime bounds - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0308, E0310. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs index 3dda34ff668ce..9f647d9e737fe 100644 --- a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs +++ b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs @@ -11,7 +11,6 @@ fn main() { type WrongGeneric = impl 'static; //~^ ERROR the parameter type `T` may not live long enough -//~| ERROR the parameter type `T` may not live long enough //~| ERROR: at least one trait must be specified fn wrong_generic(t: T) -> WrongGeneric { diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.full_tait.stderr b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.full_tait.stderr index d90f328708a7b..61e8da91bbaa9 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.full_tait.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.full_tait.stderr @@ -16,52 +16,5 @@ LL | type Bar = impl Baz; = note: closure with signature `fn(&'2 X) -> &X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2` -error[E0308]: mismatched types - --> $DIR/issue-57611-trait-alias.rs:20:16 - | -LL | type Bar = impl Baz; - | ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other - | - = note: expected type `for<'r> Fn<(&'r X,)>` - found type `Fn<(&' X,)>` -note: this closure does not fulfill the lifetime requirements - --> $DIR/issue-57611-trait-alias.rs:28:9 - | -LL | |x| x - | ^^^^^ - -error: implementation of `FnOnce` is not general enough - --> $DIR/issue-57611-trait-alias.rs:20:16 - | -LL | type Bar = impl Baz; - | ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough - | - = note: closure with signature `fn(&'2 X) -> &'2 X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`... - = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2` - -error[E0308]: mismatched types - --> $DIR/issue-57611-trait-alias.rs:20:16 - | -LL | type Bar = impl Baz; - | ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other - | - = note: expected type `for<'r> Fn<(&'r X,)>` - found type `Fn<(&' X,)>` -note: this closure does not fulfill the lifetime requirements - --> $DIR/issue-57611-trait-alias.rs:28:9 - | -LL | |x| x - | ^^^^^ - -error: implementation of `FnOnce` is not general enough - --> $DIR/issue-57611-trait-alias.rs:20:16 - | -LL | type Bar = impl Baz; - | ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough - | - = note: closure with signature `fn(&'2 X) -> &'2 X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`... - = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2` - -error: aborting due to 5 previous errors; 1 warning emitted +error: aborting due to previous error; 1 warning emitted -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.min_tait.stderr b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.min_tait.stderr index d019f40757eed..f65e91e52c713 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.min_tait.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.min_tait.stderr @@ -7,52 +7,5 @@ LL | type Bar = impl Baz; = note: closure with signature `fn(&'2 X) -> &X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2` -error[E0308]: mismatched types - --> $DIR/issue-57611-trait-alias.rs:20:16 - | -LL | type Bar = impl Baz; - | ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other - | - = note: expected type `for<'r> Fn<(&'r X,)>` - found type `Fn<(&' X,)>` -note: this closure does not fulfill the lifetime requirements - --> $DIR/issue-57611-trait-alias.rs:28:9 - | -LL | |x| x - | ^^^^^ - -error: implementation of `FnOnce` is not general enough - --> $DIR/issue-57611-trait-alias.rs:20:16 - | -LL | type Bar = impl Baz; - | ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough - | - = note: closure with signature `fn(&'2 X) -> &'2 X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`... - = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2` - -error[E0308]: mismatched types - --> $DIR/issue-57611-trait-alias.rs:20:16 - | -LL | type Bar = impl Baz; - | ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other - | - = note: expected type `for<'r> Fn<(&'r X,)>` - found type `Fn<(&' X,)>` -note: this closure does not fulfill the lifetime requirements - --> $DIR/issue-57611-trait-alias.rs:28:9 - | -LL | |x| x - | ^^^^^ - -error: implementation of `FnOnce` is not general enough - --> $DIR/issue-57611-trait-alias.rs:20:16 - | -LL | type Bar = impl Baz; - | ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough - | - = note: closure with signature `fn(&'2 X) -> &'2 X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`... - = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2` - -error: aborting due to 5 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs index ccc727e0bf01b..508ecdd88a482 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs +++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs @@ -19,10 +19,6 @@ struct X; impl Foo for X { type Bar = impl Baz; //~^ ERROR implementation of `FnOnce` is not general enough - //~| ERROR implementation of `FnOnce` is not general enough - //~| ERROR implementation of `FnOnce` is not general enough - //~| ERROR mismatched types - //~| ERROR mismatched types fn bar(&self) -> Self::Bar { |x| x diff --git a/src/test/ui/type-alias-impl-trait/issue-60371.rs b/src/test/ui/type-alias-impl-trait/issue-60371.rs index b7c8a58a65629..cee5e5a01cc2a 100644 --- a/src/test/ui/type-alias-impl-trait/issue-60371.rs +++ b/src/test/ui/type-alias-impl-trait/issue-60371.rs @@ -9,7 +9,6 @@ trait Bug { impl Bug for &() { type Item = impl Bug; //~ ERROR `impl Trait` in type aliases is unstable //~^ ERROR the trait bound `(): Bug` is not satisfied - //~^^ ERROR the trait bound `(): Bug` is not satisfied const FUN: fn() -> Self::Item = || (); //~^ ERROR type alias impl trait is not permitted here diff --git a/src/test/ui/type-alias-impl-trait/issue-60371.stderr b/src/test/ui/type-alias-impl-trait/issue-60371.stderr index 4906ea9c2e261..a9df74689df29 100644 --- a/src/test/ui/type-alias-impl-trait/issue-60371.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-60371.stderr @@ -8,7 +8,7 @@ LL | type Item = impl Bug; = help: add `#![feature(min_type_alias_impl_trait)]` to the crate attributes to enable error[E0658]: type alias impl trait is not permitted here - --> $DIR/issue-60371.rs:14:40 + --> $DIR/issue-60371.rs:13:40 | LL | const FUN: fn() -> Self::Item = || (); | ^ @@ -25,16 +25,7 @@ LL | type Item = impl Bug; = help: the following implementations were found: <&() as Bug> -error[E0277]: the trait bound `(): Bug` is not satisfied - --> $DIR/issue-60371.rs:10:17 - | -LL | type Item = impl Bug; - | ^^^^^^^^ the trait `Bug` is not implemented for `()` - | - = help: the following implementations were found: - <&() as Bug> - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0277, E0658. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/type-alias-impl-trait/issue-74761-2.rs b/src/test/ui/type-alias-impl-trait/issue-74761-2.rs new file mode 100644 index 0000000000000..4b0f2afee5484 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-74761-2.rs @@ -0,0 +1,19 @@ +#![feature(member_constraints)] +#![feature(type_alias_impl_trait)] +//~^ WARN incomplete + +pub trait A { + type B; + fn f(&self) -> Self::B; +} +impl<'a, 'b> A for () { + //~^ ERROR the lifetime parameter `'a` is not constrained + //~| ERROR the lifetime parameter `'b` is not constrained + type B = impl core::fmt::Debug; + //~^ ERROR is unstable + + + fn f(&self) -> Self::B {} +} + +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/issue-74761-2.stderr b/src/test/ui/type-alias-impl-trait/issue-74761-2.stderr new file mode 100644 index 0000000000000..4506a6e23d5c0 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-74761-2.stderr @@ -0,0 +1,34 @@ +error[E0658]: `impl Trait` in type aliases is unstable + --> $DIR/issue-74761-2.rs:12:14 + | +LL | type B = impl core::fmt::Debug; + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #63063 for more information + = help: add `#![feature(min_type_alias_impl_trait)]` to the crate attributes to enable + +warning: the feature `type_alias_impl_trait` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-74761-2.rs:2:12 + | +LL | #![feature(type_alias_impl_trait)] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #63063 for more information + +error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates + --> $DIR/issue-74761-2.rs:9:6 + | +LL | impl<'a, 'b> A for () { + | ^^ unconstrained lifetime parameter + +error[E0207]: the lifetime parameter `'b` is not constrained by the impl trait, self type, or predicates + --> $DIR/issue-74761-2.rs:9:10 + | +LL | impl<'a, 'b> A for () { + | ^^ unconstrained lifetime parameter + +error: aborting due to 3 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0207, E0658. +For more information about an error, try `rustc --explain E0207`. diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.rs b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.rs index 38aa18fe40ee7..11756017ad846 100644 --- a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.rs +++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.rs @@ -5,9 +5,9 @@ #![feature(min_type_alias_impl_trait)] type X = impl ToString; -//~^ ERROR could not find defining uses fn f(a: A, b: B) -> (X, X) { + //~^ ERROR concrete type differs from previous defining opaque type (a.clone(), a) } diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.stderr b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.stderr index c00973c0761b0..52b0462de988c 100644 --- a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.stderr +++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.stderr @@ -1,8 +1,14 @@ -error: could not find defining uses - --> $DIR/multiple-def-uses-in-one-fn2.rs:7:52 +error: concrete type differs from previous defining opaque type use + --> $DIR/multiple-def-uses-in-one-fn2.rs:9:1 | -LL | type X = impl ToString; - | ^^^^^^^^^^^^^ +LL | fn f(a: A, b: B) -> (X, X) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `A`, got `B` + | +note: previous use here + --> $DIR/multiple-def-uses-in-one-fn2.rs:9:1 + | +LL | fn f(a: A, b: B) -> (X, X) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.rs b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.rs index 17e900058113d..5f25365666c7f 100644 --- a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.rs +++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.rs @@ -11,6 +11,7 @@ fn f(a: A, b: B) -> (X, X) } fn g(a: A, b: B) -> (X, X) { + //~^ ERROR concrete type differs from previous defining opaque type (a, b) //~^ ERROR mismatched types } diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.stderr b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.stderr index bbe709dccab4e..3d943b77af57d 100644 --- a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.stderr +++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.stderr @@ -1,10 +1,11 @@ error[E0308]: mismatched types - --> $DIR/multiple-def-uses-in-one-fn3.rs:14:9 + --> $DIR/multiple-def-uses-in-one-fn3.rs:15:9 | LL | fn g(a: A, b: B) -> (X, X) { | - - found type parameter | | | expected type parameter +LL | LL | (a, b) | ^ expected type parameter `A`, found type parameter `B` | @@ -13,6 +14,18 @@ LL | (a, b) = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters -error: aborting due to previous error +error: concrete type differs from previous defining opaque type use + --> $DIR/multiple-def-uses-in-one-fn3.rs:13:1 + | +LL | fn g(a: A, b: B) -> (X, X) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `A`, got `[type error]` + | +note: previous use here + --> $DIR/multiple-def-uses-in-one-fn3.rs:9:1 + | +LL | fn f(a: A, b: B) -> (X, X) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. From df04b98bcc543b89eb54a5ce34a0f0f68e444905 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 20 Jul 2021 10:48:56 +0000 Subject: [PATCH 12/22] Use instrument debugging for more readable logs --- .../rustc_trait_selection/src/opaque_types.rs | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index 39013a317fd9c..95c81c5c729be 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -83,6 +83,7 @@ pub struct OpaqueTypeDecl<'tcx> { } /// Whether member constraints should be generated for all opaque types +#[derive(Debug)] pub enum GenerateMemberConstraints { /// The default, used by typeck WhenRequired, @@ -354,8 +355,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { opaque_types: &OpaqueTypeMap<'tcx>, free_region_relations: &FRR, ) { - debug!("constrain_opaque_types()"); - for &(opaque_type_key, opaque_defn) in opaque_types { self.constrain_opaque_type( opaque_type_key, @@ -367,6 +366,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } /// See `constrain_opaque_types` for documentation. + #[instrument(level = "debug", skip(self, free_region_relations))] fn constrain_opaque_type>( &self, opaque_type_key: OpaqueTypeKey<'tcx>, @@ -376,15 +376,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ) { let def_id = opaque_type_key.def_id; - debug!("constrain_opaque_type()"); - debug!("constrain_opaque_type: def_id={:?}", def_id); - debug!("constrain_opaque_type: opaque_defn={:#?}", opaque_defn); - let tcx = self.tcx; let concrete_ty = self.resolve_vars_if_possible(opaque_defn.concrete_ty); - debug!("constrain_opaque_type: concrete_ty={:?}", concrete_ty); + debug!(?concrete_ty); let first_own_region = match opaque_defn.origin { hir::OpaqueTyOrigin::FnReturn | hir::OpaqueTyOrigin::AsyncFn => { @@ -397,7 +393,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // type foo::<'p0..'pn>::Foo<'q0..'qm> // fn foo() -> foo::<'static..'static>::Foo<'l0..'lm>. // - // For these types we onlt iterate over `'l0..lm` below. + // For these types we only iterate over `'l0..lm` below. tcx.generics_of(def_id).parent_count } // These opaque type inherit all lifetime parameters from their @@ -410,10 +406,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // If there are required region bounds, we can use them. if opaque_defn.has_required_region_bounds { let bounds = tcx.explicit_item_bounds(def_id); - debug!("constrain_opaque_type: predicates: {:#?}", bounds); + debug!("{:#?}", bounds); let bounds: Vec<_> = bounds.iter().map(|(bound, _)| bound.subst(tcx, opaque_type_key.substs)).collect(); - debug!("constrain_opaque_type: bounds={:#?}", bounds); + debug!("{:#?}", bounds); let opaque_type = tcx.mk_opaque(def_id, opaque_type_key.substs); let required_region_bounds = @@ -452,8 +448,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }; // Compute the least upper bound of it with the other regions. - debug!("constrain_opaque_types: least_region={:?}", least_region); - debug!("constrain_opaque_types: subst_region={:?}", subst_region); + debug!(?least_region); + debug!(?subst_region); match least_region { None => least_region = Some(subst_region), Some(lr) => { @@ -484,7 +480,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } let least_region = least_region.unwrap_or(tcx.lifetimes.re_static); - debug!("constrain_opaque_types: least_region={:?}", least_region); + debug!(?least_region); if let GenerateMemberConstraints::IfNoStaticBound = mode { if least_region != tcx.lifetimes.re_static { From 1ad1b94de73741ebc38bee22a299c11c7bede5a0 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 20 Jul 2021 10:53:23 +0000 Subject: [PATCH 13/22] Remove an unnecessary variable --- compiler/rustc_mir/src/borrow_check/type_check/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs index de327047a872a..03ffad4a814cb 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -1297,7 +1297,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { return Ok(()); } - let infcx = self.infcx; let param_env = self.param_env; let body = self.body; let mir_def_id = body.source.def_id().expect_local(); @@ -1380,7 +1379,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { locations, ConstraintCategory::OpaqueType, CustomTypeOp::new( - |_cx| { + |infcx| { infcx.constrain_opaque_type( opaque_type_key, &opaque_decl, From b3594f0d1d8190387d37b0f5b30b9688f857b1dd Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 20 Jul 2021 11:36:31 +0000 Subject: [PATCH 14/22] Get back the more precise suggestion spans of old regionck --- .../src/borrow_check/diagnostics/region_errors.rs | 10 ++++++---- .../must_outlive_least_region_or_bound.nll.stderr | 4 ++-- .../static-return-lifetime-infered.nll.stderr | 4 ++-- ...self_types_pin_lifetime_impl_trait-async.nll.stderr | 2 +- ...trary_self_types_pin_lifetime_impl_trait.nll.stderr | 2 +- .../trait-object-nested-in-impl-trait.nll.stderr | 4 ++-- 6 files changed, 14 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs index feb7672f650ec..1460c2378d1c9 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs @@ -9,7 +9,7 @@ use rustc_middle::mir::{ConstraintCategory, ReturnConstraint}; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{self, RegionVid, Ty}; use rustc_span::symbol::{kw, sym}; -use rustc_span::Span; +use rustc_span::{BytePos, Span}; use crate::util::borrowck_errors; @@ -641,12 +641,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } else { "'_".to_string() }; - let suggestion = if snippet.ends_with(';') { + let span = if snippet.ends_with(';') { // `type X = impl Trait;` - format!("{} + {};", &snippet[..snippet.len() - 1], suggestable_fr_name) + span.with_hi(span.hi() - BytePos(1)) } else { - format!("{} + {}", snippet, suggestable_fr_name) + span }; + let suggestion = format!(" + {}", suggestable_fr_name); + let span = span.shrink_to_hi(); diag.span_suggestion( span, &format!( 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 4372de245078f..e9d6208773454 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 @@ -9,7 +9,7 @@ LL | fn elided(x: &i32) -> impl Copy { x } help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a bound | LL | fn elided(x: &i32) -> impl Copy + '_ { x } - | ^^^^^^^^^^^^^^ + | ^^^^ error: lifetime may not live long enough --> $DIR/must_outlive_least_region_or_bound.rs:5:32 @@ -23,7 +23,7 @@ LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x } help: to allow this `impl Trait` to capture borrowed data with lifetime `'a`, add `'a` as a bound | 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:7:46 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 65178cc9d24c2..6c5264671a912 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 @@ -9,7 +9,7 @@ LL | fn iter_values_anon(&self) -> impl Iterator { help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a bound | LL | fn iter_values_anon(&self) -> impl Iterator + '_ { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^ error: lifetime may not live long enough --> $DIR/static-return-lifetime-infered.rs:9:37 @@ -23,7 +23,7 @@ LL | fn iter_values<'a>(&'a self) -> impl Iterator { help: to allow this `impl Trait` to capture borrowed data with lifetime `'a`, add `'a` as a bound | LL | fn iter_values<'a>(&'a self) -> impl Iterator + 'a { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.nll.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.nll.stderr index f2e556c63cbf3..a678731934f6e 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.nll.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.nll.stderr @@ -9,7 +9,7 @@ LL | async fn f(self: Pin<&Self>) -> impl Clone { self } help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a bound | LL | async fn f(self: Pin<&Self>) -> impl Clone + '_ { self } - | ^^^^^^^^^^^^^^^ + | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.nll.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.nll.stderr index 73766c31b93b6..962593e411e92 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.nll.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.nll.stderr @@ -9,7 +9,7 @@ LL | fn f(self: Pin<&Self>) -> impl Clone { self } help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a bound | LL | fn f(self: Pin<&Self>) -> impl Clone + '_ { self } - | ^^^^^^^^^^^^^^^ + | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.nll.stderr b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.nll.stderr index 2407d13714a2a..05ba7808600b0 100644 --- a/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.nll.stderr +++ b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.nll.stderr @@ -9,7 +9,7 @@ LL | fn iter(&self) -> impl Iterator> { help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a bound | LL | fn iter(&self) -> impl Iterator> + '_ { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^ error: lifetime may not live long enough --> $DIR/trait-object-nested-in-impl-trait.rs:39:9 @@ -47,7 +47,7 @@ LL | fn iter<'a>(&'a self) -> impl Iterator> { help: to allow this `impl Trait` to capture borrowed data with lifetime `'a`, add `'a` as a bound | LL | fn iter<'a>(&'a self) -> impl Iterator> + 'a { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^ error: aborting due to 4 previous errors From b3aca4765327b69fb12f87456a63d450fdefbdc4 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 20 Jul 2021 15:10:55 +0000 Subject: [PATCH 15/22] Resolve nested inference variables. I attempted that with the previous code, but I misunderstdood how `shallow_resolve` works. --- .../src/borrow_check/type_check/mod.rs | 26 +++++-------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs index 03ffad4a814cb..3fb06cd2f5f44 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -182,25 +182,13 @@ pub(crate) fn type_check<'mir, 'tcx>( let mut opaque_type_values = cx.opaque_type_values; for (_, revealed_ty) in &mut opaque_type_values { - // FIXME(oli-obk): Instead of looping, implement a visitor like - // FullTypeResolver. We can't use FullTypeResolver here, as that will - // resolve lifetimes lexically, which it can't because we didn't do old - // borrowck stuff. We want to use MIR borrowck information instead. - - while revealed_ty.has_infer_types_or_consts() { - let prev = *revealed_ty; - trace!(prev=?prev.kind()); - let type_resolved = infcx.shallow_resolve(prev); - trace!(type_resolved=?type_resolved.kind()); - if prev == type_resolved { - infcx.tcx.sess.delay_span_bug( - body.span, - &format!("could not resolve {:#?}", type_resolved.kind()), - ); - *revealed_ty = infcx.tcx.ty_error(); - break; - } - *revealed_ty = type_resolved; + *revealed_ty = infcx.resolve_vars_if_possible(*revealed_ty); + if revealed_ty.has_infer_types_or_consts() { + infcx.tcx.sess.delay_span_bug( + body.span, + &format!("could not resolve {:#?}", revealed_ty.kind()), + ); + *revealed_ty = infcx.tcx.ty_error(); } } From db0324ebb2961bbeb1a75641fd1ca38d6462b721 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 18 Jul 2021 11:33:49 -0500 Subject: [PATCH 16/22] Support HIR wf checking for function signatures During function type-checking, we normalize any associated types in the function signature (argument types + return type), and then create WF obligations for each of the normalized types. The HIR wf code does not currently support this case, so any errors that we get have imprecise spans. This commit extends `ObligationCauseCode::WellFormed` to support recording a function parameter, allowing us to get the corresponding HIR type if an error occurs. Function typechecking is modified to pass this information during signature normalization and WF checking. The resulting code is fairly verbose, due to the fact that we can no longer normalize the entire signature with a single function call. As part of the refactoring, we now perform HIR-based WF checking for several other 'typed items' (statics, consts, and inherent impls). As a result, WF and projection errors in a function signature now have a precise span, which points directly at the responsible type. If a function signature is constructed via a macro, this will allow the error message to point at the code 'most responsible' for the error (e.g. a user-supplied macro argument). --- compiler/rustc_middle/src/hir/map/mod.rs | 5 +- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/traits/mod.rs | 34 +++++-- compiler/rustc_middle/src/ty/context.rs | 2 +- compiler/rustc_query_impl/src/keys.rs | 4 +- .../src/traits/error_reporting/mod.rs | 4 +- .../rustc_typeck/src/check/fn_ctxt/_impl.rs | 5 +- compiler/rustc_typeck/src/check/wfcheck.rs | 72 +++++++++++++-- compiler/rustc_typeck/src/hir_wf_check.rs | 91 ++++++++++++++----- .../associated-types-for-unimpl-trait.stderr | 7 +- .../associated-types-no-suitable-bound.stderr | 7 +- ...ated-types-no-suitable-supertrait-2.stderr | 7 +- ...ciated-types-no-suitable-supertrait.stderr | 14 ++- ...ted-trait-in-method-without-default.stderr | 7 +- .../object-safety-err-ret.stderr | 4 +- src/test/ui/error-codes/E0038.stderr | 4 +- ...ature-gate-object_safe_for_dispatch.stderr | 8 +- .../gat-in-trait-path.stderr | 4 +- .../issue-67510-pass.stderr | 4 +- .../trait-objects.stderr | 4 +- src/test/ui/issues/issue-18611.stderr | 7 +- src/test/ui/issues/issue-18959.stderr | 4 +- ...object-unsafe-trait-references-self.stderr | 8 +- ...unsafe-trait-should-use-where-sized.stderr | 4 +- src/test/ui/wf/wf-foreign-fn-decl-ret.stderr | 7 +- src/test/ui/wf/wf-in-fn-arg.stderr | 4 +- src/test/ui/wf/wf-trait-default-fn-arg.stderr | 4 +- src/test/ui/wf/wf-trait-fn-arg.stderr | 4 +- 28 files changed, 240 insertions(+), 91 deletions(-) diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index ae53f1ac3bb49..392372fad531e 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -29,7 +29,10 @@ fn fn_decl<'hir>(node: Node<'hir>) -> Option<&'hir FnDecl<'hir>> { Node::Item(Item { kind: ItemKind::Fn(sig, _, _), .. }) | Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(sig, _), .. }) | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(sig, _), .. }) => Some(&sig.decl), - Node::Expr(Expr { kind: ExprKind::Closure(_, fn_decl, ..), .. }) => Some(fn_decl), + Node::Expr(Expr { kind: ExprKind::Closure(_, fn_decl, ..), .. }) + | Node::ForeignItem(ForeignItem { kind: ForeignItemKind::Fn(fn_decl, ..), .. }) => { + Some(fn_decl) + } _ => None, } } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index cb99ae19ee72e..0908b6a1763d5 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1722,7 +1722,7 @@ rustc_queries! { /// span) for an *existing* error. Therefore, it is best-effort, and may never handle /// all of the cases that the normal `ty::Ty`-based wfcheck does. This is fine, /// because the `ty::Ty`-based wfcheck is always run. - query diagnostic_hir_wf_check(key: (ty::Predicate<'tcx>, hir::HirId)) -> Option> { + query diagnostic_hir_wf_check(key: (ty::Predicate<'tcx>, traits::WellFormedLoc)) -> Option> { eval_always no_hash desc { "performing HIR wf-checking for predicate {:?} at item {:?}", key.0, key.1 } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index f951e43fbfa35..a4a2e82463757 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -16,7 +16,7 @@ use crate::ty::{self, AdtKind, Ty, TyCtxt}; use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::Constness; use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; @@ -327,17 +327,39 @@ pub enum ObligationCauseCode<'tcx> { /// If `X` is the concrete type of an opaque type `impl Y`, then `X` must implement `Y` OpaqueType, - /// Well-formed checking. If a `HirId` is provided, - /// it is used to perform HIR-based wf checking if an error - /// occurs, in order to generate a more precise error message. + /// Well-formed checking. If a `WellFormedLoc` is provided, + /// then it will be used to eprform HIR-based wf checking + /// after an error occurs, in order to generate a more precise error span. /// This is purely for diagnostic purposes - it is always - /// correct to use `MiscObligation` instead - WellFormed(Option), + /// correct to use `MiscObligation` instead, or to specify + /// `WellFormed(None)` + WellFormed(Option), /// From `match_impl`. The cause for us having to match an impl, and the DefId we are matching against. MatchImpl(Lrc>, DefId), } +/// The 'location' at which we try to perform HIR-based wf checking. +/// This information is used to obtain an `hir::Ty`, which +/// we can walk in order to obtain precise spans for any +/// 'nested' types (e.g. `Foo` in `Option`). +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)] +pub enum WellFormedLoc { + /// Use the type of the provided definition. + Ty(LocalDefId), + /// Use the type of the parameter of the provided function. + /// We cannot use `hir::Param`, since the function may + /// not have a body (e.g. a trait method definition) + Param { + /// The function to lookup the parameter in + function: LocalDefId, + /// The index of the parameter to use. + /// Parameters are indexed from 0, with the return type + /// being the last 'parameter' + param_idx: u16, + }, +} + impl ObligationCauseCode<'_> { // Return the base obligation, ignoring derived obligations. pub fn peel_derives(&self) -> &Self { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index b84058011066f..4ce49032398bc 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1682,7 +1682,7 @@ nop_list_lift! {bound_variable_kinds; ty::BoundVariableKind => ty::BoundVariable // This is the impl for `&'a InternalSubsts<'a>`. nop_list_lift! {substs; GenericArg<'a> => GenericArg<'tcx>} -CloneLiftImpls! { for<'tcx> { Constness, } } +CloneLiftImpls! { for<'tcx> { Constness, traits::WellFormedLoc, } } pub mod tls { use super::{ptr_eq, GlobalCtxt, TyCtxt}; diff --git a/compiler/rustc_query_impl/src/keys.rs b/compiler/rustc_query_impl/src/keys.rs index 1993e0a602fa5..0ad360c7d89c3 100644 --- a/compiler/rustc_query_impl/src/keys.rs +++ b/compiler/rustc_query_impl/src/keys.rs @@ -1,9 +1,9 @@ //! Defines the set of legal keys that can be used in queries. use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; -use rustc_hir::HirId; use rustc_middle::infer::canonical::Canonical; use rustc_middle::mir; +use rustc_middle::traits; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::subst::{GenericArg, SubstsRef}; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -397,7 +397,7 @@ impl<'tcx> Key for (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>) { } } -impl<'tcx> Key for (ty::Predicate<'tcx>, HirId) { +impl<'tcx> Key for (ty::Predicate<'tcx>, traits::WellFormedLoc) { #[inline(always)] fn query_crate_is_local(&self) -> bool { true diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 5c4aef529e5ac..13a6733fb478a 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -242,11 +242,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { SelectionError::Unimplemented => { // If this obligation was generated as a result of well-formed checking, see if we // can get a better error message by performing HIR-based well formed checking. - if let ObligationCauseCode::WellFormed(Some(wf_hir_id)) = + if let ObligationCauseCode::WellFormed(Some(wf_loc)) = root_obligation.cause.code.peel_derives() { if let Some(cause) = - self.tcx.diagnostic_hir_wf_check((obligation.predicate, *wf_hir_id)) + self.tcx.diagnostic_hir_wf_check((obligation.predicate, wf_loc.clone())) { obligation.cause = cause; span = obligation.cause.span; diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 4ed07ba358de3..865e4ccc0b63f 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -40,6 +40,7 @@ use rustc_trait_selection::opaque_types::InferCtxtExt as _; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; use rustc_trait_selection::traits::{ self, ObligationCause, ObligationCauseCode, StatementAsExpression, TraitEngine, TraitEngineExt, + WellFormedLoc, }; use std::collections::hash_map::Entry; @@ -419,13 +420,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, span: Span, value: T, - hir_id: hir::HirId, + loc: WellFormedLoc, ) -> T where T: TypeFoldable<'tcx>, { self.inh.normalize_associated_types_in_with_cause( - ObligationCause::new(span, self.body_id, ObligationCauseCode::WellFormed(Some(hir_id))), + ObligationCause::new(span, self.body_id, ObligationCauseCode::WellFormed(Some(loc))), self.param_env, value, ) diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index b24d63917c1cf..98980c65bc815 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -22,8 +22,9 @@ use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; use rustc_trait_selection::opaque_types::may_define_opaque_type; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; -use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; +use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, WellFormedLoc}; +use std::convert::TryInto; use std::iter; use std::ops::ControlFlow; @@ -386,7 +387,7 @@ fn check_associated_item( span: Span, sig_if_method: Option<&hir::FnSig<'_>>, ) { - let code = ObligationCauseCode::WellFormed(Some(item_id)); + let code = ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(item_id.expect_owner()))); for_id(tcx, item_id, span).with_fcx(|fcx| { let item = fcx.tcx.associated_item(fcx.tcx.hir().local_def_id(item_id)); @@ -400,7 +401,11 @@ fn check_associated_item( match item.kind { ty::AssocKind::Const => { let ty = fcx.tcx.type_of(item.def_id); - let ty = fcx.normalize_associated_types_in_wf(span, ty, item_id); + let ty = fcx.normalize_associated_types_in_wf( + span, + ty, + WellFormedLoc::Ty(item_id.expect_owner()), + ); fcx.register_wf_obligation(ty.into(), span, code.clone()); } ty::AssocKind::Fn => { @@ -422,7 +427,11 @@ fn check_associated_item( } if item.defaultness.has_value() { let ty = fcx.tcx.type_of(item.def_id); - let ty = fcx.normalize_associated_types_in_wf(span, ty, item_id); + let ty = fcx.normalize_associated_types_in_wf( + span, + ty, + WellFormedLoc::Ty(item_id.expect_owner()), + ); fcx.register_wf_obligation(ty.into(), span, code.clone()); } } @@ -621,7 +630,11 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: hir::HirId, ty_span: Span, allow_fo for_id(tcx, item_id, ty_span).with_fcx(|fcx| { let ty = tcx.type_of(tcx.hir().local_def_id(item_id)); - let item_ty = fcx.normalize_associated_types_in_wf(ty_span, ty, item_id); + let item_ty = fcx.normalize_associated_types_in_wf( + ty_span, + ty, + WellFormedLoc::Ty(item_id.expect_owner()), + ); let mut forbid_unsized = true; if allow_foreign_ty { @@ -634,7 +647,7 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: hir::HirId, ty_span: Span, allow_fo fcx.register_wf_obligation( item_ty.into(), ty_span, - ObligationCauseCode::WellFormed(Some(item_id)), + ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(item_id.expect_owner()))), ); if forbid_unsized { fcx.register_bound( @@ -684,7 +697,9 @@ fn check_impl<'tcx>( fcx.register_wf_obligation( self_ty.into(), ast_self_ty.span, - ObligationCauseCode::WellFormed(Some(item.hir_id())), + ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty( + item.hir_id().expect_owner(), + ))), ); } } @@ -901,11 +916,48 @@ fn check_fn_or_method<'fcx, 'tcx>( implied_bounds: &mut Vec>, ) { let sig = fcx.tcx.liberate_late_bound_regions(def_id, sig); - let sig = fcx.normalize_associated_types_in(span, sig); - for (&input_ty, ty) in iter::zip(sig.inputs(), hir_decl.inputs) { - fcx.register_wf_obligation(input_ty.into(), ty.span, ObligationCauseCode::WellFormed(None)); + // Normalize the input and output types one at a time, using a different + // `WellFormedLoc` for each. We cannot call `normalize_associated_types` + // on the entire `FnSig`, since this would use the same `WellFormedLoc` + // for each type, preventing the HIR wf check from generating + // a nice error message. + let ty::FnSig { mut inputs_and_output, c_variadic, unsafety, abi } = sig; + inputs_and_output = + fcx.tcx.mk_type_list(inputs_and_output.iter().enumerate().map(|(i, ty)| { + fcx.normalize_associated_types_in_wf( + span, + ty, + WellFormedLoc::Param { + function: def_id.expect_local(), + // Note that the `param_idx` of the output type is + // one greater than the index of the last input type. + param_idx: i.try_into().unwrap(), + }, + ) + })); + // Manually call `normalize_assocaited_types_in` on the other types + // in `FnSig`. This ensures that if the types of these fields + // ever change to include projections, we will start normalizing + // them automatically. + let sig = ty::FnSig { + inputs_and_output, + c_variadic: fcx.normalize_associated_types_in(span, c_variadic), + unsafety: fcx.normalize_associated_types_in(span, unsafety), + abi: fcx.normalize_associated_types_in(span, abi), + }; + + for (i, (&input_ty, ty)) in iter::zip(sig.inputs(), hir_decl.inputs).enumerate() { + fcx.register_wf_obligation( + input_ty.into(), + ty.span, + ObligationCauseCode::WellFormed(Some(WellFormedLoc::Param { + function: def_id.expect_local(), + param_idx: i.try_into().unwrap(), + })), + ); } + implied_bounds.extend(sig.inputs()); fcx.register_wf_obligation( diff --git a/compiler/rustc_typeck/src/hir_wf_check.rs b/compiler/rustc_typeck/src/hir_wf_check.rs index a8ec7b79e571f..c1af10f5ce451 100644 --- a/compiler/rustc_typeck/src/hir_wf_check.rs +++ b/compiler/rustc_typeck/src/hir_wf_check.rs @@ -3,10 +3,10 @@ use rustc_hir as hir; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::HirId; use rustc_infer::infer::TyCtxtInferExt; -use rustc_infer::traits::ObligationCause; use rustc_infer::traits::TraitEngine; +use rustc_infer::traits::{ObligationCause, WellFormedLoc}; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{self, ToPredicate, TyCtxt}; +use rustc_middle::ty::{self, Region, ToPredicate, TyCtxt, TypeFoldable, TypeFolder}; use rustc_trait_selection::traits; pub fn provide(providers: &mut Providers) { @@ -17,21 +17,20 @@ pub fn provide(providers: &mut Providers) { // need access to `ItemCtxt` fn diagnostic_hir_wf_check<'tcx>( tcx: TyCtxt<'tcx>, - (predicate, hir_id): (ty::Predicate<'tcx>, HirId), + (predicate, loc): (ty::Predicate<'tcx>, WellFormedLoc), ) -> Option> { let hir = tcx.hir(); - // HIR wfcheck should only ever happen as part of improving an existing error - tcx.sess.delay_span_bug(hir.span(hir_id), "Performed HIR wfcheck without an existing error!"); - // Currently, we only handle WF checking for items (e.g. associated items). - // It would be nice to extend this to handle wf checks inside functions. - let def_id = match tcx.hir().opt_local_def_id(hir_id) { - Some(def_id) => def_id, - None => return None, + let def_id = match loc { + WellFormedLoc::Ty(def_id) => def_id, + WellFormedLoc::Param { function, param_idx: _ } => function, }; + let hir_id = HirId::make_owner(def_id); + + // HIR wfcheck should only ever happen as part of improving an existing error + tcx.sess + .delay_span_bug(tcx.def_span(def_id), "Performed HIR wfcheck without an existing error!"); - // FIXME - figure out how we want to handle wf-checking for - // things inside a function body. let icx = ItemCtxt::new(tcx, def_id.to_def_id()); // To perform HIR-based WF checking, we iterate over all HIR types @@ -72,7 +71,8 @@ fn diagnostic_hir_wf_check<'tcx>( fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { self.tcx.infer_ctxt().enter(|infcx| { let mut fulfill = traits::FulfillmentContext::new(); - let tcx_ty = self.icx.to_ty(ty); + let tcx_ty = + self.icx.to_ty(ty).fold_with(&mut EraseAllBoundRegions { tcx: self.tcx }); let cause = traits::ObligationCause::new( ty.span, self.hir_id, @@ -119,19 +119,66 @@ fn diagnostic_hir_wf_check<'tcx>( depth: 0, }; - let ty = match tcx.hir().get(hir_id) { - hir::Node::ImplItem(item) => match item.kind { - hir::ImplItemKind::TyAlias(ty) => Some(ty), - _ => None, - }, - hir::Node::TraitItem(item) => match item.kind { - hir::TraitItemKind::Type(_, ty) => ty, - _ => None, + // Get the starting `hir::Ty` using our `WellFormedLoc`. + // We will walk 'into' this type to try to find + // a more precise span for our predicate. + let ty = match loc { + WellFormedLoc::Ty(_) => match hir.get(hir_id) { + hir::Node::ImplItem(item) => match item.kind { + hir::ImplItemKind::TyAlias(ty) => Some(ty), + ref item => bug!("Unexpected ImplItem {:?}", item), + }, + hir::Node::TraitItem(item) => match item.kind { + hir::TraitItemKind::Type(_, ty) => ty, + ref item => bug!("Unexpected TraitItem {:?}", item), + }, + hir::Node::Item(item) => match item.kind { + hir::ItemKind::Static(ty, _, _) | hir::ItemKind::Const(ty, _) => Some(ty), + hir::ItemKind::Impl(ref impl_) => { + assert!(impl_.of_trait.is_none(), "Unexpected trait impl: {:?}", impl_); + Some(impl_.self_ty) + } + ref item => bug!("Unexpected item {:?}", item), + }, + ref node => bug!("Unexpected node {:?}", node), }, - _ => None, + WellFormedLoc::Param { function: _, param_idx } => { + let fn_decl = hir.fn_decl_by_hir_id(hir_id).unwrap(); + // Get return type + if param_idx as usize == fn_decl.inputs.len() { + match fn_decl.output { + hir::FnRetTy::Return(ty) => Some(ty), + // The unit type `()` is always well-formed + hir::FnRetTy::DefaultReturn(_span) => None, + } + } else { + Some(&fn_decl.inputs[param_idx as usize]) + } + } }; if let Some(ty) = ty { visitor.visit_ty(ty); } visitor.cause } + +struct EraseAllBoundRegions<'tcx> { + tcx: TyCtxt<'tcx>, +} + +// Higher ranked regions are complicated. +// To make matters worse, the HIR WF check can instantiate them +// outside of a `Binder`, due to the way we (ab)use +// `ItemCtxt::to_ty`. To make things simpler, we just erase all +// of them, regardless of depth. At worse, this will give +// us an inaccurate span for an error message, but cannot +// lead to unsoundess (we call `delay_span_bug` at the start +// of `diagnostic_hir_wf_check`). +impl<'tcx> TypeFolder<'tcx> for EraseAllBoundRegions<'tcx> { + fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { + self.tcx + } + fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> { + if let ty::ReLateBound(..) = r { &ty::ReErased } else { r } + } +} diff --git a/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr b/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr index e8c11a32bf7fd..25e80159b0b18 100644 --- a/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr +++ b/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr @@ -1,8 +1,11 @@ error[E0277]: the trait bound `Self: Get` is not satisfied - --> $DIR/associated-types-for-unimpl-trait.rs:10:8 + --> $DIR/associated-types-for-unimpl-trait.rs:10:40 | +LL | trait Get { + | --------- required by this bound in `Get` +... LL | fn uhoh(&self, foo: U, bar: ::Value) {} - | ^^^^ the trait `Get` is not implemented for `Self` + | ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self` | help: consider further restricting `Self` | diff --git a/src/test/ui/associated-types/associated-types-no-suitable-bound.stderr b/src/test/ui/associated-types/associated-types-no-suitable-bound.stderr index e3be434698ab9..19500f58aa688 100644 --- a/src/test/ui/associated-types/associated-types-no-suitable-bound.stderr +++ b/src/test/ui/associated-types/associated-types-no-suitable-bound.stderr @@ -1,8 +1,11 @@ error[E0277]: the trait bound `T: Get` is not satisfied - --> $DIR/associated-types-no-suitable-bound.rs:11:8 + --> $DIR/associated-types-no-suitable-bound.rs:11:21 | +LL | trait Get { + | --------- required by this bound in `Get` +... LL | fn uhoh(foo: ::Value) {} - | ^^^^ the trait `Get` is not implemented for `T` + | ^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `T` | help: consider restricting type parameter `T` | diff --git a/src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr b/src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr index 9dc3414e9edf0..0e978f20a6634 100644 --- a/src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr +++ b/src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr @@ -1,8 +1,11 @@ error[E0277]: the trait bound `Self: Get` is not satisfied - --> $DIR/associated-types-no-suitable-supertrait-2.rs:17:8 + --> $DIR/associated-types-no-suitable-supertrait-2.rs:17:40 | +LL | trait Get { + | --------- required by this bound in `Get` +... LL | fn uhoh(&self, foo: U, bar: ::Value) {} - | ^^^^ the trait `Get` is not implemented for `Self` + | ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self` | help: consider further restricting `Self` | diff --git a/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr b/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr index c2aed3f9de548..1ec3c05983aef 100644 --- a/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr +++ b/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr @@ -1,8 +1,11 @@ error[E0277]: the trait bound `Self: Get` is not satisfied - --> $DIR/associated-types-no-suitable-supertrait.rs:17:8 + --> $DIR/associated-types-no-suitable-supertrait.rs:17:40 | +LL | trait Get { + | --------- required by this bound in `Get` +... LL | fn uhoh(&self, foo: U, bar: ::Value) {} - | ^^^^ the trait `Get` is not implemented for `Self` + | ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self` | help: consider further restricting `Self` | @@ -10,10 +13,13 @@ LL | fn uhoh(&self, foo: U, bar: ::Value) where Self: Ge | ^^^^^^^^^^^^^^^ error[E0277]: the trait bound `(T, U): Get` is not satisfied - --> $DIR/associated-types-no-suitable-supertrait.rs:22:8 + --> $DIR/associated-types-no-suitable-supertrait.rs:22:40 | +LL | trait Get { + | --------- required by this bound in `Get` +... LL | fn uhoh(&self, foo: U, bar: <(T, U) as Get>::Value) {} - | ^^^^ the trait `Get` is not implemented for `(T, U)` + | ^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `(T, U)` error: aborting due to 2 previous errors diff --git a/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr b/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr index fb842d968676d..b6ee1ed733c3e 100644 --- a/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr +++ b/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr @@ -1,8 +1,11 @@ error[E0277]: the trait bound `Self: Get` is not satisfied - --> $DIR/associated-types-projection-to-unrelated-trait-in-method-without-default.rs:10:8 + --> $DIR/associated-types-projection-to-unrelated-trait-in-method-without-default.rs:10:40 | +LL | trait Get { + | --------- required by this bound in `Get` +... LL | fn okay(&self, foo: U, bar: ::Value); - | ^^^^ the trait `Get` is not implemented for `Self` + | ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self` | help: consider further restricting `Self` | diff --git a/src/test/ui/const-generics/const_evaluatable_checked/object-safety-err-ret.stderr b/src/test/ui/const-generics/const_evaluatable_checked/object-safety-err-ret.stderr index e0e6029252c00..319e6c2c032a0 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/object-safety-err-ret.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/object-safety-err-ret.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/object-safety-err-ret.rs:17:15 + --> $DIR/object-safety-err-ret.rs:17:16 | LL | fn use_dyn(v: &dyn Foo) { - | ^^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^ `Foo` cannot be made into an object | = help: consider moving `test` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit diff --git a/src/test/ui/error-codes/E0038.stderr b/src/test/ui/error-codes/E0038.stderr index eb68a6298d1ac..cead9776e4abb 100644 --- a/src/test/ui/error-codes/E0038.stderr +++ b/src/test/ui/error-codes/E0038.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Trait` cannot be made into an object - --> $DIR/E0038.rs:5:16 + --> $DIR/E0038.rs:5:20 | LL | fn call_foo(x: Box) { - | ^^^^^^^^^^^^^^ `Trait` cannot be made into an object + | ^^^^^^^^^ `Trait` cannot be made into an object | = help: consider moving `foo` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit diff --git a/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr b/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr index 12195bc1071a0..c13c05f146a7e 100644 --- a/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr +++ b/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `NonObjectSafe1` cannot be made into an object - --> $DIR/feature-gate-object_safe_for_dispatch.rs:18:38 + --> $DIR/feature-gate-object_safe_for_dispatch.rs:18:39 | LL | fn takes_non_object_safe_ref(obj: &dyn NonObjectSafe1) { - | ^^^^^^^^^^^^^^^^^^^ `NonObjectSafe1` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^ `NonObjectSafe1` cannot be made into an object | note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/feature-gate-object_safe_for_dispatch.rs:4:23 @@ -35,10 +35,10 @@ LL | fn static_fn() where Self: Sized {} | ^^^^^^^^^^^^^^^^^ error[E0038]: the trait `NonObjectSafe3` cannot be made into an object - --> $DIR/feature-gate-object_safe_for_dispatch.rs:27:35 + --> $DIR/feature-gate-object_safe_for_dispatch.rs:27:39 | LL | fn takes_non_object_safe_box(obj: Box) { - | ^^^^^^^^^^^^^^^^^^^^^^^ `NonObjectSafe3` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^ `NonObjectSafe3` cannot be made into an object | = help: consider moving `foo` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit diff --git a/src/test/ui/generic-associated-types/gat-in-trait-path.stderr b/src/test/ui/generic-associated-types/gat-in-trait-path.stderr index eb8e101a83d79..8651789688eaa 100644 --- a/src/test/ui/generic-associated-types/gat-in-trait-path.stderr +++ b/src/test/ui/generic-associated-types/gat-in-trait-path.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/gat-in-trait-path.rs:21:13 + --> $DIR/gat-in-trait-path.rs:21:17 | LL | fn f(_arg : Box Foo = &'a ()>>) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object | = help: consider moving `A` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit diff --git a/src/test/ui/generic-associated-types/issue-67510-pass.stderr b/src/test/ui/generic-associated-types/issue-67510-pass.stderr index 8cc9f2816a166..b4b89ab047363 100644 --- a/src/test/ui/generic-associated-types/issue-67510-pass.stderr +++ b/src/test/ui/generic-associated-types/issue-67510-pass.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `X` cannot be made into an object - --> $DIR/issue-67510-pass.rs:7:19 + --> $DIR/issue-67510-pass.rs:7:23 | LL | fn _func1<'a>(_x: Box=&'a ()>>) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object | = help: consider moving `Y` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit diff --git a/src/test/ui/generic-associated-types/trait-objects.stderr b/src/test/ui/generic-associated-types/trait-objects.stderr index a121566bbd884..6429bb8159e1f 100644 --- a/src/test/ui/generic-associated-types/trait-objects.stderr +++ b/src/test/ui/generic-associated-types/trait-objects.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `StreamingIterator` cannot be made into an object - --> $DIR/trait-objects.rs:10:16 + --> $DIR/trait-objects.rs:10:21 | LL | fn min_size(x: &mut dyn for<'a> StreamingIterator = &'a i32>) -> usize { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `StreamingIterator` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `StreamingIterator` cannot be made into an object | = help: consider moving `Item` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit diff --git a/src/test/ui/issues/issue-18611.stderr b/src/test/ui/issues/issue-18611.stderr index 8872f51753c94..0e942e80e2544 100644 --- a/src/test/ui/issues/issue-18611.stderr +++ b/src/test/ui/issues/issue-18611.stderr @@ -1,8 +1,11 @@ error[E0277]: the trait bound `isize: HasState` is not satisfied - --> $DIR/issue-18611.rs:1:4 + --> $DIR/issue-18611.rs:1:18 | LL | fn add_state(op: ::State) { - | ^^^^^^^^^ the trait `HasState` is not implemented for `isize` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasState` is not implemented for `isize` +... +LL | trait HasState { + | -------------- required by this bound in `HasState` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-18959.stderr b/src/test/ui/issues/issue-18959.stderr index 86b530e85a80a..2a5416ce85ba6 100644 --- a/src/test/ui/issues/issue-18959.stderr +++ b/src/test/ui/issues/issue-18959.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/issue-18959.rs:11:11 + --> $DIR/issue-18959.rs:11:12 | LL | fn foo(b: &dyn Bar) { - | ^^^^^^^^ `Bar` cannot be made into an object + | ^^^^^^^ `Bar` cannot be made into an object | = help: consider moving `foo` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit diff --git a/src/test/ui/suggestions/object-unsafe-trait-references-self.stderr b/src/test/ui/suggestions/object-unsafe-trait-references-self.stderr index 797406f869fe6..f332b7213d8bc 100644 --- a/src/test/ui/suggestions/object-unsafe-trait-references-self.stderr +++ b/src/test/ui/suggestions/object-unsafe-trait-references-self.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Trait` cannot be made into an object - --> $DIR/object-unsafe-trait-references-self.rs:6:11 + --> $DIR/object-unsafe-trait-references-self.rs:6:12 | LL | fn bar(x: &dyn Trait) {} - | ^^^^^^^^^^ `Trait` cannot be made into an object + | ^^^^^^^^^ `Trait` cannot be made into an object | = help: consider moving `baz` to another trait = help: consider moving `bat` to another trait @@ -17,10 +17,10 @@ LL | fn bat(&self) -> Self {} | ^^^^ ...because method `bat` references the `Self` type in its return type error[E0038]: the trait `Other` cannot be made into an object - --> $DIR/object-unsafe-trait-references-self.rs:10:11 + --> $DIR/object-unsafe-trait-references-self.rs:10:12 | LL | fn foo(x: &dyn Other) {} - | ^^^^^^^^^^ `Other` cannot be made into an object + | ^^^^^^^^^ `Other` cannot be made into an object | note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-unsafe-trait-references-self.rs:8:14 diff --git a/src/test/ui/suggestions/object-unsafe-trait-should-use-where-sized.stderr b/src/test/ui/suggestions/object-unsafe-trait-should-use-where-sized.stderr index a2caf846cc5fe..4c18f6d79d077 100644 --- a/src/test/ui/suggestions/object-unsafe-trait-should-use-where-sized.stderr +++ b/src/test/ui/suggestions/object-unsafe-trait-should-use-where-sized.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Trait` cannot be made into an object - --> $DIR/object-unsafe-trait-should-use-where-sized.rs:9:11 + --> $DIR/object-unsafe-trait-should-use-where-sized.rs:9:12 | LL | fn bar(x: &dyn Trait) {} - | ^^^^^^^^^^ `Trait` cannot be made into an object + | ^^^^^^^^^ `Trait` cannot be made into an object | note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-unsafe-trait-should-use-where-sized.rs:5:8 diff --git a/src/test/ui/wf/wf-foreign-fn-decl-ret.stderr b/src/test/ui/wf/wf-foreign-fn-decl-ret.stderr index a0eb7d10bd94a..f6b48938f9b04 100644 --- a/src/test/ui/wf/wf-foreign-fn-decl-ret.stderr +++ b/src/test/ui/wf/wf-foreign-fn-decl-ret.stderr @@ -1,8 +1,11 @@ error[E0277]: the trait bound `(): Foo` is not satisfied - --> $DIR/wf-foreign-fn-decl-ret.rs:11:12 + --> $DIR/wf-foreign-fn-decl-ret.rs:11:25 | +LL | pub trait Foo { + | ------------- required by this bound in `Foo` +... LL | pub fn lint_me() -> <() as Foo>::Assoc; - | ^^^^^^^ the trait `Foo` is not implemented for `()` + | ^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()` error[E0277]: the trait bound `u32: Unsatisfied` is not satisfied --> $DIR/wf-foreign-fn-decl-ret.rs:14:32 diff --git a/src/test/ui/wf/wf-in-fn-arg.stderr b/src/test/ui/wf/wf-in-fn-arg.stderr index 9687658feba43..ca90e9222dea9 100644 --- a/src/test/ui/wf/wf-in-fn-arg.stderr +++ b/src/test/ui/wf/wf-in-fn-arg.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `T: Copy` is not satisfied - --> $DIR/wf-in-fn-arg.rs:10:14 + --> $DIR/wf-in-fn-arg.rs:10:15 | LL | struct MustBeCopy { | ---- required by this bound in `MustBeCopy` ... LL | fn bar(_: &MustBeCopy) - | ^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` + | ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` | help: consider restricting type parameter `T` | diff --git a/src/test/ui/wf/wf-trait-default-fn-arg.stderr b/src/test/ui/wf/wf-trait-default-fn-arg.stderr index c3d5d2b9669b8..2a129538f7633 100644 --- a/src/test/ui/wf/wf-trait-default-fn-arg.stderr +++ b/src/test/ui/wf/wf-trait-default-fn-arg.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `Self: Eq` is not satisfied - --> $DIR/wf-trait-default-fn-arg.rs:11:22 + --> $DIR/wf-trait-default-fn-arg.rs:11:23 | LL | struct Bar { value: Box } | -- required by this bound in `Bar` ... LL | fn bar(&self, x: &Bar) { - | ^^^^^^^^^^ the trait `Eq` is not implemented for `Self` + | ^^^^^^^^^ the trait `Eq` is not implemented for `Self` | help: consider further restricting `Self` | diff --git a/src/test/ui/wf/wf-trait-fn-arg.stderr b/src/test/ui/wf/wf-trait-fn-arg.stderr index 4510f50feea58..7693aa6d2d583 100644 --- a/src/test/ui/wf/wf-trait-fn-arg.stderr +++ b/src/test/ui/wf/wf-trait-fn-arg.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `Self: Eq` is not satisfied - --> $DIR/wf-trait-fn-arg.rs:10:22 + --> $DIR/wf-trait-fn-arg.rs:10:23 | LL | struct Bar { value: Box } | -- required by this bound in `Bar` ... LL | fn bar(&self, x: &Bar); - | ^^^^^^^^^^ the trait `Eq` is not implemented for `Self` + | ^^^^^^^^^ the trait `Eq` is not implemented for `Self` | help: consider further restricting `Self` | From 713044c652a8dc9815df97e1f7a6d167bd22d88c Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 20 Jul 2021 15:16:41 +0000 Subject: [PATCH 17/22] Add a regression test --- src/test/ui/impl-trait/issue-86465.rs | 10 ++++++++++ src/test/ui/impl-trait/issue-86465.stderr | 14 ++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/test/ui/impl-trait/issue-86465.rs create mode 100644 src/test/ui/impl-trait/issue-86465.stderr diff --git a/src/test/ui/impl-trait/issue-86465.rs b/src/test/ui/impl-trait/issue-86465.rs new file mode 100644 index 0000000000000..23a3748c12c6a --- /dev/null +++ b/src/test/ui/impl-trait/issue-86465.rs @@ -0,0 +1,10 @@ +#![feature(min_type_alias_impl_trait)] + +type X<'a, 'b> = impl std::fmt::Debug; + +fn f<'t, 'u>(a: &'t u32, b: &'u u32) -> (X<'t, 'u>, X<'u, 't>) { + //~^ ERROR concrete type differs from previous defining opaque type use + (a, a) +} + +fn main() {} diff --git a/src/test/ui/impl-trait/issue-86465.stderr b/src/test/ui/impl-trait/issue-86465.stderr new file mode 100644 index 0000000000000..595b16aa68554 --- /dev/null +++ b/src/test/ui/impl-trait/issue-86465.stderr @@ -0,0 +1,14 @@ +error: concrete type differs from previous defining opaque type use + --> $DIR/issue-86465.rs:5:1 + | +LL | fn f<'t, 'u>(a: &'t u32, b: &'u u32) -> (X<'t, 'u>, X<'u, 't>) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&'a u32`, got `&'b u32` + | +note: previous use here + --> $DIR/issue-86465.rs:5:1 + | +LL | fn f<'t, 'u>(a: &'t u32, b: &'u u32) -> (X<'t, 'u>, X<'u, 't>) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + From 320d049e876579cd5c57be17e791a519f9b852a0 Mon Sep 17 00:00:00 2001 From: Chris Midgley Date: Tue, 20 Jul 2021 20:13:08 +0100 Subject: [PATCH 18/22] Add long explanation for E0722 --- compiler/rustc_error_codes/src/error_codes.rs | 2 +- .../src/error_codes/E0722.md | 24 +++++++++++++++++++ .../feature-gate-optimize_attribute.stderr | 3 ++- 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0722.md diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index df162f8dce026..902c7c4787323 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -418,6 +418,7 @@ E0716: include_str!("./error_codes/E0716.md"), E0718: include_str!("./error_codes/E0718.md"), E0719: include_str!("./error_codes/E0719.md"), E0720: include_str!("./error_codes/E0720.md"), +E0722: include_str!("./error_codes/E0722.md"), E0724: include_str!("./error_codes/E0724.md"), E0725: include_str!("./error_codes/E0725.md"), E0727: include_str!("./error_codes/E0727.md"), @@ -634,7 +635,6 @@ E0783: include_str!("./error_codes/E0783.md"), E0711, // a feature has been declared with conflicting stability attributes E0717, // rustc_promotable without stability attribute // E0721, // `await` keyword - E0722, // Malformed `#[optimize]` attribute // E0723, unstable feature in `const` context E0726, // non-explicit (not `'_`) elided lifetime in unsupported position // E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`. diff --git a/compiler/rustc_error_codes/src/error_codes/E0722.md b/compiler/rustc_error_codes/src/error_codes/E0722.md new file mode 100644 index 0000000000000..4a687d7428805 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0722.md @@ -0,0 +1,24 @@ +The `optimize` attribute was malformed. + +Erroneous code example: + +```compile_fail,E0722 +#![feature(optimize_attribute)] + +#[optimize(something)] // error: invalid argument +pub fn something() {} + +fn main() {} +``` + +The `#[optimize]` attribute should be used as follows: + +- `#[optimize(size)]` -- instructs the optimization pipeline to generate code + that's smaller rather than faster + +- `#[optimize(speed)]` -- instructs the optimization pipeline to generate code + that's faster rather than smaller + +See [RFC 2412] for more details. + +[RFC 2412]: https://rust-lang.github.io/rfcs/2412-optimize-attr.html diff --git a/src/test/ui/feature-gates/feature-gate-optimize_attribute.stderr b/src/test/ui/feature-gates/feature-gate-optimize_attribute.stderr index 50ce6427e8b58..a3ced35155f37 100644 --- a/src/test/ui/feature-gates/feature-gate-optimize_attribute.stderr +++ b/src/test/ui/feature-gates/feature-gate-optimize_attribute.stderr @@ -51,4 +51,5 @@ LL | #[optimize(banana)] error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0658`. +Some errors have detailed explanations: E0658, E0722. +For more information about an error, try `rustc --explain E0658`. From f4981b4aedac1d9f750dc28bd7524b3ac4bb9b25 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 20 Jul 2021 16:08:41 -0700 Subject: [PATCH 19/22] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 27277d966b3cf..4e143fd131e0c 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 27277d966b3cfa454d6dea7f724cb961c036251c +Subproject commit 4e143fd131e0c16cefd008456e974236ca54e62e From e09d78260908436e6bc1691f23cda2ee8382545a Mon Sep 17 00:00:00 2001 From: Chris Midgley Date: Wed, 21 Jul 2021 10:29:20 +0100 Subject: [PATCH 20/22] add working code example --- compiler/rustc_error_codes/src/error_codes/E0722.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/compiler/rustc_error_codes/src/error_codes/E0722.md b/compiler/rustc_error_codes/src/error_codes/E0722.md index 4a687d7428805..1513c4ce0594d 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0722.md +++ b/compiler/rustc_error_codes/src/error_codes/E0722.md @@ -19,6 +19,16 @@ The `#[optimize]` attribute should be used as follows: - `#[optimize(speed)]` -- instructs the optimization pipeline to generate code that's faster rather than smaller +For example: +``` +#![feature(optimize_attribute)] + +#[optimize(size)] +pub fn something() {} + +fn main() {} +``` + See [RFC 2412] for more details. [RFC 2412]: https://rust-lang.github.io/rfcs/2412-optimize-attr.html From adc5de601f9e860f00638f078f3a4d4e6ae4c73d Mon Sep 17 00:00:00 2001 From: Chris Midgley Date: Wed, 21 Jul 2021 10:57:27 +0100 Subject: [PATCH 21/22] docs: remove spurious main functions --- compiler/rustc_error_codes/src/error_codes/E0722.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0722.md b/compiler/rustc_error_codes/src/error_codes/E0722.md index 1513c4ce0594d..fe2b6d27457f5 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0722.md +++ b/compiler/rustc_error_codes/src/error_codes/E0722.md @@ -7,8 +7,6 @@ Erroneous code example: #[optimize(something)] // error: invalid argument pub fn something() {} - -fn main() {} ``` The `#[optimize]` attribute should be used as follows: @@ -25,8 +23,6 @@ For example: #[optimize(size)] pub fn something() {} - -fn main() {} ``` See [RFC 2412] for more details. From b24d4915b895fab1528ee5081edaa94e951b523e Mon Sep 17 00:00:00 2001 From: Chris Midgley Date: Wed, 21 Jul 2021 10:58:35 +0100 Subject: [PATCH 22/22] docs: add newline before example --- compiler/rustc_error_codes/src/error_codes/E0722.md | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_error_codes/src/error_codes/E0722.md b/compiler/rustc_error_codes/src/error_codes/E0722.md index fe2b6d27457f5..570717a92bd79 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0722.md +++ b/compiler/rustc_error_codes/src/error_codes/E0722.md @@ -18,6 +18,7 @@ The `#[optimize]` attribute should be used as follows: that's faster rather than smaller For example: + ``` #![feature(optimize_attribute)]