From df7789c902eb198a107422dd8e4e4c81ec3cb6ad Mon Sep 17 00:00:00 2001 From: Tomas Tauber <2410580+tomtau@users.noreply.github.com> Date: Sat, 14 Sep 2019 10:06:05 +0800 Subject: [PATCH 01/17] Made a thread local storage panic message more explanatory (TLS is usually understood as Transport Layer Security outside rust-std internals) --- src/libstd/thread/local.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index f85b5d632f16b..a2bbe371de788 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -236,8 +236,8 @@ impl LocalKey { #[stable(feature = "rust1", since = "1.0.0")] pub fn with(&'static self, f: F) -> R where F: FnOnce(&T) -> R { - self.try_with(f).expect("cannot access a TLS value during or \ - after it is destroyed") + self.try_with(f).expect("cannot access a Thread Local Storage value \ + during or after it is destroyed") } /// Acquires a reference to the value in this TLS key. From 68c3739f1268e496c096d89ab9e556f196e35974 Mon Sep 17 00:00:00 2001 From: Tomas Tauber <2410580+tomtau@users.noreply.github.com> Date: Mon, 16 Sep 2019 12:13:02 +0800 Subject: [PATCH 02/17] updated the panic message wording --- src/libstd/thread/local.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index a2bbe371de788..e92c0d1c58e41 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -237,7 +237,7 @@ impl LocalKey { pub fn with(&'static self, f: F) -> R where F: FnOnce(&T) -> R { self.try_with(f).expect("cannot access a Thread Local Storage value \ - during or after it is destroyed") + during or after destruction") } /// Acquires a reference to the value in this TLS key. From 2fd4c27c329d85a69a6b585d217e48b4d500477e Mon Sep 17 00:00:00 2001 From: csmoe Date: Thu, 19 Sep 2019 03:02:08 +0000 Subject: [PATCH 03/17] add is_async_fn query --- src/librustc/query/mod.rs | 4 ++++ src/librustc_metadata/cstore_impl.rs | 1 + src/librustc_metadata/decoder.rs | 9 +++++++++ src/librustc_metadata/encoder.rs | 4 ++++ src/librustc_metadata/schema.rs | 1 + 5 files changed, 19 insertions(+) diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index c7260945295a6..c4f62df12b766 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -244,6 +244,10 @@ rustc_queries! { desc { |tcx| "checking if item is const fn: `{}`", tcx.def_path_str(key) } } + query is_async_fn(key: DefId) -> hir::IsAsync { + desc { |tcx| "checking if the function is async: `{}`", tcx.def_path_str(key) } + } + /// Returns `true` if calls to the function may be promoted. /// /// This is either because the function is e.g., a tuple-struct or tuple-variant diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index a1e3bbcbf8ea9..6db3bfd8880ff 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -133,6 +133,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, fn_sig => { cdata.fn_sig(def_id.index, tcx) } inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) } is_const_fn_raw => { cdata.is_const_fn_raw(def_id.index) } + is_async_fn { cdata.fn_asyncness(def_id.index) } is_foreign_item => { cdata.is_foreign_item(def_id.index) } static_mutability => { cdata.static_mutability(def_id.index) } def_kind => { cdata.def_kind(def_id.index) } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 75d7261704722..6cc5c409e1331 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1208,6 +1208,15 @@ impl<'a, 'tcx> CrateMetadata { constness == hir::Constness::Const } + pub fn is_async_fn(&self, id: DefIndex) -> bool { + let asyncness = match self.entry(id).kind { + EntryKind::Fn(data) => data.decode(self).asyncness, + EntryKind::Method(data) => data.decode(self).fn_data.asyncness, + _ => hir::IsAsync::NotAsync, + }; + asyncness == hir::IsAsync::Async + } + pub fn is_foreign_item(&self, id: DefIndex) -> bool { match self.entry(id).kind { EntryKind::ForeignImmStatic | diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index f430f01542efe..439763810ec0e 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -885,6 +885,7 @@ impl EncodeContext<'tcx> { } }; FnData { + asyncness: hir::IsAsync::NotAsync, constness: hir::Constness::NotConst, param_names, sig: self.lazy(&tcx.fn_sig(def_id)), @@ -982,6 +983,7 @@ impl EncodeContext<'tcx> { ty::AssocKind::Method => { let fn_data = if let hir::ImplItemKind::Method(ref sig, body) = ast_item.node { FnData { + asyncness: sig.header.asyncness, constness: sig.header.constness, param_names: self.encode_fn_param_names_for_body(body), sig: self.lazy(&tcx.fn_sig(def_id)), @@ -1128,6 +1130,7 @@ impl EncodeContext<'tcx> { } hir::ItemKind::Fn(_, header, .., body) => { let data = FnData { + asyncness: header.asyncness, constness: header.constness, param_names: self.encode_fn_param_names_for_body(body), sig: self.lazy(tcx.fn_sig(def_id)), @@ -1675,6 +1678,7 @@ impl EncodeContext<'tcx> { let kind = match nitem.node { hir::ForeignItemKind::Fn(_, ref names, _) => { let data = FnData { + asyncness: hir::IsAsync::NotAsync, constness: hir::Constness::NotConst, param_names: self.encode_fn_param_names(names), sig: self.lazy(tcx.fn_sig(def_id)), diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 1a5f0e17ba7ce..92534ab056a8b 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -295,6 +295,7 @@ pub struct MacroDef { #[derive(RustcEncodable, RustcDecodable)] pub struct FnData<'tcx> { + pub asyncness: hir::IsAsync, pub constness: hir::Constness, pub param_names: Lazy<[ast::Name]>, pub sig: Lazy>, From 9ffb1ce28cb1656d6142f1f9f6f882eb187fac25 Mon Sep 17 00:00:00 2001 From: csmoe Date: Thu, 19 Sep 2019 03:21:11 +0000 Subject: [PATCH 04/17] append asyncness info to functions --- src/librustc/query/mod.rs | 2 +- src/librustc/ty/mod.rs | 15 +++++++++++++++ src/librustc_metadata/cstore_impl.rs | 2 +- src/librustc_metadata/encoder.rs | 4 ++-- src/librustdoc/clean/inline.rs | 8 ++++++-- src/librustdoc/clean/mod.rs | 7 ++++++- 6 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index c4f62df12b766..5e1db92b55580 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -244,7 +244,7 @@ rustc_queries! { desc { |tcx| "checking if item is const fn: `{}`", tcx.def_path_str(key) } } - query is_async_fn(key: DefId) -> hir::IsAsync { + query is_async_fn(key: DefId) -> bool { desc { |tcx| "checking if the function is async: `{}`", tcx.def_path_str(key) } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 5ca819e12f232..97981f4782003 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -3349,6 +3349,20 @@ fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option> { } } +fn is_async_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool { + if let Some(hir_id) = tcx.hir().as_local_hir_id(def_id) { + let node = tcx.hir().get(hir_id); + if let Some(fn_like) = hir::map::blocks::FnLikeNode::from_node(node) { + fn_like.asyncness() == hir::IsAsync::Async + } else { + false + } + } else { + false + } +} + + pub fn provide(providers: &mut ty::query::Providers<'_>) { context::provide(providers); erase_regions::provide(providers); @@ -3356,6 +3370,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) { util::provide(providers); constness::provide(providers); *providers = ty::query::Providers { + is_async_fn, associated_item, associated_item_def_ids, adt_sized_constraint, diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 6db3bfd8880ff..c46e2a901f88d 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -133,7 +133,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, fn_sig => { cdata.fn_sig(def_id.index, tcx) } inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) } is_const_fn_raw => { cdata.is_const_fn_raw(def_id.index) } - is_async_fn { cdata.fn_asyncness(def_id.index) } + is_async_fn => { cdata.is_async_fn(def_id.index) } is_foreign_item => { cdata.is_foreign_item(def_id.index) } static_mutability => { cdata.static_mutability(def_id.index) } def_kind => { cdata.def_kind(def_id.index) } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 439763810ec0e..1e7c0829a26a9 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -875,7 +875,7 @@ impl EncodeContext<'tcx> { EntryKind::AssocConst(container, const_qualif, rendered_const) } ty::AssocKind::Method => { - let fn_data = if let hir::TraitItemKind::Method(_, ref m) = ast_item.node { + let fn_data = if let hir::TraitItemKind::Method(method_sig, m) = &ast_item.node { let param_names = match *m { hir::TraitMethod::Required(ref names) => { self.encode_fn_param_names(names) @@ -885,7 +885,7 @@ impl EncodeContext<'tcx> { } }; FnData { - asyncness: hir::IsAsync::NotAsync, + asyncness: method_sig.header.asyncness, constness: hir::Constness::NotConst, param_names, sig: self.lazy(&tcx.fn_sig(def_id)), diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index cb42ff1c8052f..0752934c8c1de 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -217,7 +217,11 @@ fn build_external_function(cx: &DocContext<'_>, did: DefId) -> clean::Function { } else { hir::Constness::NotConst }; - + let asyncness = if cx.tcx.is_async_fn(did) { + hir::IsAsync::Async + } else { + hir::IsAsync::NotAsync + }; let predicates = cx.tcx.predicates_of(did); let (generics, decl) = clean::enter_impl_trait(cx, || { ((cx.tcx.generics_of(did), &predicates).clean(cx), (did, sig).clean(cx)) @@ -230,7 +234,7 @@ fn build_external_function(cx: &DocContext<'_>, did: DefId) -> clean::Function { unsafety: sig.unsafety(), abi: sig.abi(), constness, - asyncness: hir::IsAsync::NotAsync, + asyncness, }, all_types, ret_types, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index ae70fdc530be6..7bd54c64cf6f5 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2403,6 +2403,11 @@ impl Clean for ty::AssocItem { } else { hir::Constness::NotConst }; + let asyncness = if cx.tcx.is_async_fn(self.def_id) { + hir::IsAsync::Async + } else { + hir::IsAsync::NotAsync + }; let defaultness = match self.container { ty::ImplContainer(_) => Some(self.defaultness), ty::TraitContainer(_) => None, @@ -2414,7 +2419,7 @@ impl Clean for ty::AssocItem { unsafety: sig.unsafety(), abi: sig.abi(), constness, - asyncness: hir::IsAsync::NotAsync, + asyncness, }, defaultness, all_types, From a813cc1bf190f9cdcd7dce2eba287c637ce4048f Mon Sep 17 00:00:00 2001 From: csmoe Date: Sat, 21 Sep 2019 03:17:57 +0000 Subject: [PATCH 05/17] rename is_async_fn to asyncness --- src/librustc/query/mod.rs | 2 +- src/librustc/ty/mod.rs | 11 ++++++----- src/librustc_metadata/cstore_impl.rs | 2 +- src/librustc_metadata/decoder.rs | 7 +++---- src/librustdoc/clean/inline.rs | 6 +----- src/librustdoc/clean/mod.rs | 6 +----- 6 files changed, 13 insertions(+), 21 deletions(-) diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index 5e1db92b55580..252e49d5d15f6 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -244,7 +244,7 @@ rustc_queries! { desc { |tcx| "checking if item is const fn: `{}`", tcx.def_path_str(key) } } - query is_async_fn(key: DefId) -> bool { + query asyncness(key: DefId) -> hir::IsAsync { desc { |tcx| "checking if the function is async: `{}`", tcx.def_path_str(key) } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 97981f4782003..dd36a4520929a 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -3349,16 +3349,17 @@ fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option> { } } -fn is_async_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool { +/// Check if a function is async. +fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync { if let Some(hir_id) = tcx.hir().as_local_hir_id(def_id) { let node = tcx.hir().get(hir_id); if let Some(fn_like) = hir::map::blocks::FnLikeNode::from_node(node) { - fn_like.asyncness() == hir::IsAsync::Async + fn_like.asyncness() } else { - false + hir::IsAsync::NotAsync } } else { - false + hir::IsAsync::NotAsync } } @@ -3370,7 +3371,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) { util::provide(providers); constness::provide(providers); *providers = ty::query::Providers { - is_async_fn, + asyncness, associated_item, associated_item_def_ids, adt_sized_constraint, diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index c46e2a901f88d..55cf3965aa85a 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -133,7 +133,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, fn_sig => { cdata.fn_sig(def_id.index, tcx) } inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) } is_const_fn_raw => { cdata.is_const_fn_raw(def_id.index) } - is_async_fn => { cdata.is_async_fn(def_id.index) } + asyncness => { cdata.asyncness(def_id.index) } is_foreign_item => { cdata.is_foreign_item(def_id.index) } static_mutability => { cdata.static_mutability(def_id.index) } def_kind => { cdata.def_kind(def_id.index) } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 6cc5c409e1331..5153564fc8255 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1208,13 +1208,12 @@ impl<'a, 'tcx> CrateMetadata { constness == hir::Constness::Const } - pub fn is_async_fn(&self, id: DefIndex) -> bool { - let asyncness = match self.entry(id).kind { + pub fn asyncness(&self, id: DefIndex) -> hir::IsAsync { + match self.entry(id).kind { EntryKind::Fn(data) => data.decode(self).asyncness, EntryKind::Method(data) => data.decode(self).fn_data.asyncness, _ => hir::IsAsync::NotAsync, - }; - asyncness == hir::IsAsync::Async + } } pub fn is_foreign_item(&self, id: DefIndex) -> bool { diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 0752934c8c1de..d71acb4fa7b31 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -217,11 +217,7 @@ fn build_external_function(cx: &DocContext<'_>, did: DefId) -> clean::Function { } else { hir::Constness::NotConst }; - let asyncness = if cx.tcx.is_async_fn(did) { - hir::IsAsync::Async - } else { - hir::IsAsync::NotAsync - }; + let asyncness = cx.tcx.asyncness(did); let predicates = cx.tcx.predicates_of(did); let (generics, decl) = clean::enter_impl_trait(cx, || { ((cx.tcx.generics_of(did), &predicates).clean(cx), (did, sig).clean(cx)) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 7bd54c64cf6f5..95a5869e84510 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2403,11 +2403,7 @@ impl Clean for ty::AssocItem { } else { hir::Constness::NotConst }; - let asyncness = if cx.tcx.is_async_fn(self.def_id) { - hir::IsAsync::Async - } else { - hir::IsAsync::NotAsync - }; + let asyncness = cx.tcx.asyncness(self.def_id); let defaultness = match self.container { ty::ImplContainer(_) => Some(self.defaultness), ty::TraitContainer(_) => None, From 726fe3b25573c8406a74e751d54f0bd3c663ea03 Mon Sep 17 00:00:00 2001 From: csmoe Date: Sat, 21 Sep 2019 08:14:41 +0000 Subject: [PATCH 06/17] add rustdoc test for async fn reexport --- .../rustdoc/inline_cross/auxiliary/impl_trait_aux.rs | 10 ++++++++++ src/test/rustdoc/inline_cross/impl_trait.rs | 10 +++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs b/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs index 21c733a9bc98e..913ba8f2a1649 100644 --- a/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs +++ b/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs @@ -1,3 +1,5 @@ +// edition:2018 + use std::ops::Deref; pub fn func<'a>(_x: impl Clone + Into> + 'a) {} @@ -11,8 +13,16 @@ pub fn func3(_x: impl Iterator> + Clone) {} pub fn func4>(_x: T) {} +pub async fn async_fn() {} + pub struct Foo; impl Foo { pub fn method<'a>(_x: impl Clone + Into> + 'a) {} } + +pub struct Bar; + +impl Bar { + pub async fn async_foo(&self) {} +} diff --git a/src/test/rustdoc/inline_cross/impl_trait.rs b/src/test/rustdoc/inline_cross/impl_trait.rs index b1e3f8d145b5f..6f4a48c83c05b 100644 --- a/src/test/rustdoc/inline_cross/impl_trait.rs +++ b/src/test/rustdoc/inline_cross/impl_trait.rs @@ -1,4 +1,5 @@ // aux-build:impl_trait_aux.rs +// edition:2018 extern crate impl_trait_aux; @@ -20,13 +21,20 @@ pub use impl_trait_aux::func2; // @!has - '//pre[@class="rust fn"]' 'where' pub use impl_trait_aux::func3; - // @has impl_trait/fn.func4.html // @has - '//pre[@class="rust fn"]' "func4(" // @has - '//pre[@class="rust fn"]' "T: Iterator," pub use impl_trait_aux::func4; +// @has impl_trait/fn.async_fn.html +// @has - '//pre[@class="rust fn"]' "pub async fn async_fn()" +pub use impl_trait_aux::async_fn; + // @has impl_trait/struct.Foo.html // @has - '//code[@id="method.v"]' "pub fn method<'a>(_x: impl Clone + Into> + 'a)" // @!has - '//code[@id="method.v"]' 'where' pub use impl_trait_aux::Foo; + +// @has impl_trait/struct.Bar.html +// @has - '//*[@id="method.async_foo"]' "pub async fn async_foo(" +pub use impl_trait_aux::Bar; From 983e035b11d90787fe27c5c31203b4e03ea0266a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 13 Sep 2019 15:14:28 +0200 Subject: [PATCH 07/17] add long error explanation for E0524 --- src/librustc_mir/error_codes.rs | 64 ++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/error_codes.rs b/src/librustc_mir/error_codes.rs index ba299e9463b8d..196bcf147f8f8 100644 --- a/src/librustc_mir/error_codes.rs +++ b/src/librustc_mir/error_codes.rs @@ -1993,6 +1993,69 @@ fn get_owned_iterator() -> IntoIter { ``` "##, +E0524: r##" +A variable which requires unique access is being used in more than one closure +at the same time. + +Erroneous code example: + +```compile_fail,E0524 +fn set(x: &mut isize) { + *x += 4; +} + +fn dragoooon(x: &mut isize) { + let mut c1 = || set(x); + let mut c2 = || set(x); // error! + + c2(); + c1(); +} +``` + +To solve this issue, multiple solutions are available. First, is it required +for this variable to be used in more than one closure at a time? If it is the +case, use reference counted types such as `Rc` (or `Arc` if it runs +concurrently): + +``` +use std::rc::Rc; +use std::cell::RefCell; + +fn set(x: &mut isize) { + *x += 4; +} + +fn dragoooon(x: &mut isize) { + let x = Rc::new(RefCell::new(x)); + let y = Rc::clone(&x); + let mut c1 = || { let mut x2 = x.borrow_mut(); set(&mut x2); }; + let mut c2 = || { let mut x2 = y.borrow_mut(); set(&mut x2); }; // ok! + + c2(); + c1(); +} +``` + +If not, just run closures one at a time: + +``` +fn set(x: &mut isize) { + *x += 4; +} + +fn dragoooon(x: &mut isize) { + { // This block isn't necessary since non-lexical lifetimes, it's just to + // make it more clear. + let mut c1 = || set(&mut *x); + c1(); + } // `c1` has been dropped here so we're free to use `x` again! + let mut c2 = || set(&mut *x); + c2(); +} +``` +"##, + E0595: r##" #### Note: this error code is no longer emitted by the compiler. @@ -2393,7 +2456,6 @@ There are some known bugs that trigger this message. // E0385, // {} in an aliasable location E0493, // destructors cannot be evaluated at compile-time E0521, // borrowed data escapes outside of closure - E0524, // two closures require unique access to `..` at the same time E0526, // shuffle indices are not constant E0594, // cannot assign to {} // E0598, // lifetime of {} is too short to guarantee its contents can be... From d2b873b06706e97dc54317b8c0ad8f9efa1c3b70 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 13 Sep 2019 15:14:53 +0200 Subject: [PATCH 08/17] update ui tests --- src/test/ui/borrowck/borrowck-closures-mut-of-imm.rs | 4 ---- src/test/ui/borrowck/borrowck-closures-mut-of-imm.stderr | 9 +++++---- src/test/ui/borrowck/borrowck-closures-mut-of-mut.stderr | 1 + src/test/ui/borrowck/borrowck-closures-unique.stderr | 3 ++- src/test/ui/nll/closures-in-loops.stderr | 2 +- 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/test/ui/borrowck/borrowck-closures-mut-of-imm.rs b/src/test/ui/borrowck/borrowck-closures-mut-of-imm.rs index 24e06e3c4e666..d7e187a2b3958 100644 --- a/src/test/ui/borrowck/borrowck-closures-mut-of-imm.rs +++ b/src/test/ui/borrowck/borrowck-closures-mut-of-imm.rs @@ -1,10 +1,6 @@ // Tests that two closures cannot simultaneously have mutable // and immutable access to the variable. Issue #6801. -fn get(x: &isize) -> isize { - *x -} - fn set(x: &mut isize) { *x = 4; } diff --git a/src/test/ui/borrowck/borrowck-closures-mut-of-imm.stderr b/src/test/ui/borrowck/borrowck-closures-mut-of-imm.stderr index 3be7d725eda3a..784b903a5896a 100644 --- a/src/test/ui/borrowck/borrowck-closures-mut-of-imm.stderr +++ b/src/test/ui/borrowck/borrowck-closures-mut-of-imm.stderr @@ -1,17 +1,17 @@ error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference - --> $DIR/borrowck-closures-mut-of-imm.rs:13:25 + --> $DIR/borrowck-closures-mut-of-imm.rs:9:25 | LL | let mut c1 = || set(&mut *x); | ^^^^^^^ cannot borrow as mutable error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference - --> $DIR/borrowck-closures-mut-of-imm.rs:15:25 + --> $DIR/borrowck-closures-mut-of-imm.rs:11:25 | LL | let mut c2 = || set(&mut *x); | ^^^^^^^ cannot borrow as mutable error[E0524]: two closures require unique access to `x` at the same time - --> $DIR/borrowck-closures-mut-of-imm.rs:15:18 + --> $DIR/borrowck-closures-mut-of-imm.rs:11:18 | LL | let mut c1 = || set(&mut *x); | -- - first borrow occurs due to use of `x` in closure @@ -28,4 +28,5 @@ LL | c2(); c1(); error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0596`. +Some errors have detailed explanations: E0524, E0596. +For more information about an error, try `rustc --explain E0524`. diff --git a/src/test/ui/borrowck/borrowck-closures-mut-of-mut.stderr b/src/test/ui/borrowck/borrowck-closures-mut-of-mut.stderr index a174388712158..471173e595f47 100644 --- a/src/test/ui/borrowck/borrowck-closures-mut-of-mut.stderr +++ b/src/test/ui/borrowck/borrowck-closures-mut-of-mut.stderr @@ -15,3 +15,4 @@ LL | c2(); c1(); error: aborting due to previous error +For more information about this error, try `rustc --explain E0524`. diff --git a/src/test/ui/borrowck/borrowck-closures-unique.stderr b/src/test/ui/borrowck/borrowck-closures-unique.stderr index 9b53af4c01f59..2ed08b83c58b9 100644 --- a/src/test/ui/borrowck/borrowck-closures-unique.stderr +++ b/src/test/ui/borrowck/borrowck-closures-unique.stderr @@ -50,4 +50,5 @@ LL | let c1 = |y: &'static mut isize| x = y; error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0500`. +Some errors have detailed explanations: E0500, E0524. +For more information about an error, try `rustc --explain E0500`. diff --git a/src/test/ui/nll/closures-in-loops.stderr b/src/test/ui/nll/closures-in-loops.stderr index 7603f9650b54a..0b15d9bcfe68c 100644 --- a/src/test/ui/nll/closures-in-loops.stderr +++ b/src/test/ui/nll/closures-in-loops.stderr @@ -27,5 +27,5 @@ LL | v.push(|| *x = String::new()); error: aborting due to 3 previous errors -Some errors have detailed explanations: E0382, E0499. +Some errors have detailed explanations: E0382, E0499, E0524. For more information about an error, try `rustc --explain E0382`. From 5d531aeaf46451f999aea0f7c9ba08016b9ee3eb Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 16 Sep 2019 13:34:57 -0700 Subject: [PATCH 09/17] rustc: Convert `dependency_formats` to a query This commit converts a field of `Session`, `dependency_formats`, into a query of `TyCtxt`. This information then also needed to be threaded through to other remaining portions of the linker, but it's relatively straightforward. The only change here is that instead of `HashMap` the data structure changed to `Vec<(CrateType, T)>` to make it easier to deal with in queries. --- src/librustc/middle/dependency_format.rs | 378 +-------------------- src/librustc/query/mod.rs | 4 + src/librustc/session/config.rs | 2 +- src/librustc/session/mod.rs | 3 - src/librustc_codegen_ssa/back/link.rs | 61 ++-- src/librustc_codegen_ssa/back/linker.rs | 12 +- src/librustc_codegen_ssa/back/write.rs | 2 +- src/librustc_codegen_ssa/base.rs | 3 +- src/librustc_codegen_ssa/lib.rs | 2 + src/librustc_interface/passes.rs | 4 - src/librustc_metadata/cstore_impl.rs | 5 + src/librustc_metadata/dependency_format.rs | 371 ++++++++++++++++++++ src/librustc_metadata/encoder.rs | 26 +- src/librustc_metadata/lib.rs | 1 + 14 files changed, 455 insertions(+), 419 deletions(-) create mode 100644 src/librustc_metadata/dependency_format.rs diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs index 96b99fe4cdce2..8b2bf55ccc120 100644 --- a/src/librustc/middle/dependency_format.rs +++ b/src/librustc/middle/dependency_format.rs @@ -1,64 +1,10 @@ -//! Resolution of mixing rlibs and dylibs +//! Type definitions for learning about the dependency formats of all upstream +//! crates (rlibs/dylibs/oh my). //! -//! When producing a final artifact, such as a dynamic library, the compiler has -//! a choice between linking an rlib or linking a dylib of all upstream -//! dependencies. The linking phase must guarantee, however, that a library only -//! show up once in the object file. For example, it is illegal for library A to -//! be statically linked to B and C in separate dylibs, and then link B and C -//! into a crate D (because library A appears twice). -//! -//! The job of this module is to calculate what format each upstream crate -//! should be used when linking each output type requested in this session. This -//! generally follows this set of rules: -//! -//! 1. Each library must appear exactly once in the output. -//! 2. Each rlib contains only one library (it's just an object file) -//! 3. Each dylib can contain more than one library (due to static linking), -//! and can also bring in many dynamic dependencies. -//! -//! With these constraints in mind, it's generally a very difficult problem to -//! find a solution that's not "all rlibs" or "all dylibs". I have suspicions -//! that NP-ness may come into the picture here... -//! -//! The current selection algorithm below looks mostly similar to: -//! -//! 1. If static linking is required, then require all upstream dependencies -//! to be available as rlibs. If not, generate an error. -//! 2. If static linking is requested (generating an executable), then -//! attempt to use all upstream dependencies as rlibs. If any are not -//! found, bail out and continue to step 3. -//! 3. Static linking has failed, at least one library must be dynamically -//! linked. Apply a heuristic by greedily maximizing the number of -//! dynamically linked libraries. -//! 4. Each upstream dependency available as a dynamic library is -//! registered. The dependencies all propagate, adding to a map. It is -//! possible for a dylib to add a static library as a dependency, but it -//! is illegal for two dylibs to add the same static library as a -//! dependency. The same dylib can be added twice. Additionally, it is -//! illegal to add a static dependency when it was previously found as a -//! dylib (and vice versa) -//! 5. After all dynamic dependencies have been traversed, re-traverse the -//! remaining dependencies and add them statically (if they haven't been -//! added already). -//! -//! While not perfect, this algorithm should help support use-cases such as leaf -//! dependencies being static while the larger tree of inner dependencies are -//! all dynamic. This isn't currently very well battle tested, so it will likely -//! fall short in some use cases. -//! -//! Currently, there is no way to specify the preference of linkage with a -//! particular library (other than a global dynamic/static switch). -//! Additionally, the algorithm is geared towards finding *any* solution rather -//! than finding a number of solutions (there are normally quite a few). - -use crate::hir::def_id::CrateNum; +//! For all the gory details, see the provider of the `dependency_formats` +//! query. use crate::session::config; -use crate::ty::TyCtxt; -use crate::middle::cstore::{self, DepKind}; -use crate::middle::cstore::LinkagePreference::{self, RequireStatic, RequireDynamic}; -use crate::util::nodemap::FxHashMap; -use rustc_target::spec::PanicStrategy; /// A list of dependencies for a certain crate type. /// @@ -71,324 +17,12 @@ pub type DependencyList = Vec; /// A mapping of all required dependencies for a particular flavor of output. /// /// This is local to the tcx, and is generally relevant to one session. -pub type Dependencies = FxHashMap; +pub type Dependencies = Vec<(config::CrateType, DependencyList)>; -#[derive(Copy, Clone, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug, HashStable)] pub enum Linkage { NotLinked, IncludedFromDylib, Static, Dynamic, } - -pub fn calculate(tcx: TyCtxt<'_>) { - let sess = &tcx.sess; - let fmts = sess.crate_types.borrow().iter().map(|&ty| { - let linkage = calculate_type(tcx, ty); - verify_ok(tcx, &linkage); - (ty, linkage) - }).collect::>(); - sess.abort_if_errors(); - sess.dependency_formats.set(fmts); -} - -fn calculate_type(tcx: TyCtxt<'_>, ty: config::CrateType) -> DependencyList { - let sess = &tcx.sess; - - if !sess.opts.output_types.should_codegen() { - return Vec::new(); - } - - let preferred_linkage = match ty { - // cdylibs must have all static dependencies. - config::CrateType::Cdylib => Linkage::Static, - - // Generating a dylib without `-C prefer-dynamic` means that we're going - // to try to eagerly statically link all dependencies. This is normally - // done for end-product dylibs, not intermediate products. - config::CrateType::Dylib if !sess.opts.cg.prefer_dynamic => Linkage::Static, - config::CrateType::Dylib => Linkage::Dynamic, - - // If the global prefer_dynamic switch is turned off, or the final - // executable will be statically linked, prefer static crate linkage. - config::CrateType::Executable if !sess.opts.cg.prefer_dynamic || - sess.crt_static() => Linkage::Static, - config::CrateType::Executable => Linkage::Dynamic, - - // proc-macro crates are mostly cdylibs, but we also need metadata. - config::CrateType::ProcMacro => Linkage::Static, - - // No linkage happens with rlibs, we just needed the metadata (which we - // got long ago), so don't bother with anything. - config::CrateType::Rlib => Linkage::NotLinked, - - // staticlibs must have all static dependencies. - config::CrateType::Staticlib => Linkage::Static, - }; - - if preferred_linkage == Linkage::NotLinked { - // If the crate is not linked, there are no link-time dependencies. - return Vec::new(); - } - - if preferred_linkage == Linkage::Static { - // Attempt static linkage first. For dylibs and executables, we may be - // able to retry below with dynamic linkage. - if let Some(v) = attempt_static(tcx) { - return v; - } - - // Staticlibs, cdylibs, and static executables must have all static - // dependencies. If any are not found, generate some nice pretty errors. - if ty == config::CrateType::Cdylib || ty == config::CrateType::Staticlib || - (ty == config::CrateType::Executable && sess.crt_static() && - !sess.target.target.options.crt_static_allows_dylibs) { - for &cnum in tcx.crates().iter() { - if tcx.dep_kind(cnum).macros_only() { continue } - let src = tcx.used_crate_source(cnum); - if src.rlib.is_some() { continue } - sess.err(&format!("crate `{}` required to be available in rlib format, \ - but was not found in this form", - tcx.crate_name(cnum))); - } - return Vec::new(); - } - } - - let mut formats = FxHashMap::default(); - - // Sweep all crates for found dylibs. Add all dylibs, as well as their - // dependencies, ensuring there are no conflicts. The only valid case for a - // dependency to be relied upon twice is for both cases to rely on a dylib. - for &cnum in tcx.crates().iter() { - if tcx.dep_kind(cnum).macros_only() { continue } - let name = tcx.crate_name(cnum); - let src = tcx.used_crate_source(cnum); - if src.dylib.is_some() { - info!("adding dylib: {}", name); - add_library(tcx, cnum, RequireDynamic, &mut formats); - let deps = tcx.dylib_dependency_formats(cnum); - for &(depnum, style) in deps.iter() { - info!("adding {:?}: {}", style, tcx.crate_name(depnum)); - add_library(tcx, depnum, style, &mut formats); - } - } - } - - // Collect what we've got so far in the return vector. - let last_crate = tcx.crates().len(); - let mut ret = (1..last_crate+1).map(|cnum| { - match formats.get(&CrateNum::new(cnum)) { - Some(&RequireDynamic) => Linkage::Dynamic, - Some(&RequireStatic) => Linkage::IncludedFromDylib, - None => Linkage::NotLinked, - } - }).collect::>(); - - // Run through the dependency list again, and add any missing libraries as - // static libraries. - // - // If the crate hasn't been included yet and it's not actually required - // (e.g., it's an allocator) then we skip it here as well. - for &cnum in tcx.crates().iter() { - let src = tcx.used_crate_source(cnum); - if src.dylib.is_none() && - !formats.contains_key(&cnum) && - tcx.dep_kind(cnum) == DepKind::Explicit { - assert!(src.rlib.is_some() || src.rmeta.is_some()); - info!("adding staticlib: {}", tcx.crate_name(cnum)); - add_library(tcx, cnum, RequireStatic, &mut formats); - ret[cnum.as_usize() - 1] = Linkage::Static; - } - } - - // We've gotten this far because we're emitting some form of a final - // artifact which means that we may need to inject dependencies of some - // form. - // - // Things like allocators and panic runtimes may not have been activated - // quite yet, so do so here. - activate_injected_dep(*sess.injected_panic_runtime.get(), &mut ret, - &|cnum| tcx.is_panic_runtime(cnum)); - - // When dylib B links to dylib A, then when using B we must also link to A. - // It could be the case, however, that the rlib for A is present (hence we - // found metadata), but the dylib for A has since been removed. - // - // For situations like this, we perform one last pass over the dependencies, - // making sure that everything is available in the requested format. - for (cnum, kind) in ret.iter().enumerate() { - let cnum = CrateNum::new(cnum + 1); - let src = tcx.used_crate_source(cnum); - match *kind { - Linkage::NotLinked | - Linkage::IncludedFromDylib => {} - Linkage::Static if src.rlib.is_some() => continue, - Linkage::Dynamic if src.dylib.is_some() => continue, - kind => { - let kind = match kind { - Linkage::Static => "rlib", - _ => "dylib", - }; - sess.err(&format!("crate `{}` required to be available in {} format, \ - but was not found in this form", - tcx.crate_name(cnum), kind)); - } - } - } - - ret -} - -fn add_library( - tcx: TyCtxt<'_>, - cnum: CrateNum, - link: LinkagePreference, - m: &mut FxHashMap, -) { - match m.get(&cnum) { - Some(&link2) => { - // If the linkages differ, then we'd have two copies of the library - // if we continued linking. If the linkages are both static, then we - // would also have two copies of the library (static from two - // different locations). - // - // This error is probably a little obscure, but I imagine that it - // can be refined over time. - if link2 != link || link == RequireStatic { - tcx.sess.struct_err(&format!("cannot satisfy dependencies so `{}` only \ - shows up once", tcx.crate_name(cnum))) - .help("having upstream crates all available in one format \ - will likely make this go away") - .emit(); - } - } - None => { m.insert(cnum, link); } - } -} - -fn attempt_static(tcx: TyCtxt<'_>) -> Option { - let sess = &tcx.sess; - let crates = cstore::used_crates(tcx, RequireStatic); - if !crates.iter().by_ref().all(|&(_, ref p)| p.is_some()) { - return None - } - - // All crates are available in an rlib format, so we're just going to link - // everything in explicitly so long as it's actually required. - let last_crate = tcx.crates().len(); - let mut ret = (1..last_crate+1).map(|cnum| { - if tcx.dep_kind(CrateNum::new(cnum)) == DepKind::Explicit { - Linkage::Static - } else { - Linkage::NotLinked - } - }).collect::>(); - - // Our allocator/panic runtime may not have been linked above if it wasn't - // explicitly linked, which is the case for any injected dependency. Handle - // that here and activate them. - activate_injected_dep(*sess.injected_panic_runtime.get(), &mut ret, - &|cnum| tcx.is_panic_runtime(cnum)); - - Some(ret) -} - -// Given a list of how to link upstream dependencies so far, ensure that an -// injected dependency is activated. This will not do anything if one was -// transitively included already (e.g., via a dylib or explicitly so). -// -// If an injected dependency was not found then we're guaranteed the -// metadata::creader module has injected that dependency (not listed as -// a required dependency) in one of the session's field. If this field is not -// set then this compilation doesn't actually need the dependency and we can -// also skip this step entirely. -fn activate_injected_dep(injected: Option, - list: &mut DependencyList, - replaces_injected: &dyn Fn(CrateNum) -> bool) { - for (i, slot) in list.iter().enumerate() { - let cnum = CrateNum::new(i + 1); - if !replaces_injected(cnum) { - continue - } - if *slot != Linkage::NotLinked { - return - } - } - if let Some(injected) = injected { - let idx = injected.as_usize() - 1; - assert_eq!(list[idx], Linkage::NotLinked); - list[idx] = Linkage::Static; - } -} - -// After the linkage for a crate has been determined we need to verify that -// there's only going to be one allocator in the output. -fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) { - let sess = &tcx.sess; - if list.len() == 0 { - return - } - let mut panic_runtime = None; - for (i, linkage) in list.iter().enumerate() { - if let Linkage::NotLinked = *linkage { - continue - } - let cnum = CrateNum::new(i + 1); - - if tcx.is_panic_runtime(cnum) { - if let Some((prev, _)) = panic_runtime { - let prev_name = tcx.crate_name(prev); - let cur_name = tcx.crate_name(cnum); - sess.err(&format!("cannot link together two \ - panic runtimes: {} and {}", - prev_name, cur_name)); - } - panic_runtime = Some((cnum, tcx.panic_strategy(cnum))); - } - } - - // If we found a panic runtime, then we know by this point that it's the - // only one, but we perform validation here that all the panic strategy - // compilation modes for the whole DAG are valid. - if let Some((cnum, found_strategy)) = panic_runtime { - let desired_strategy = sess.panic_strategy(); - - // First up, validate that our selected panic runtime is indeed exactly - // our same strategy. - if found_strategy != desired_strategy { - sess.err(&format!("the linked panic runtime `{}` is \ - not compiled with this crate's \ - panic strategy `{}`", - tcx.crate_name(cnum), - desired_strategy.desc())); - } - - // Next up, verify that all other crates are compatible with this panic - // strategy. If the dep isn't linked, we ignore it, and if our strategy - // is abort then it's compatible with everything. Otherwise all crates' - // panic strategy must match our own. - for (i, linkage) in list.iter().enumerate() { - if let Linkage::NotLinked = *linkage { - continue - } - if desired_strategy == PanicStrategy::Abort { - continue - } - let cnum = CrateNum::new(i + 1); - let found_strategy = tcx.panic_strategy(cnum); - let is_compiler_builtins = tcx.is_compiler_builtins(cnum); - if is_compiler_builtins || desired_strategy == found_strategy { - continue - } - - sess.err(&format!("the crate `{}` is compiled with the \ - panic strategy `{}` which is \ - incompatible with this crate's \ - strategy of `{}`", - tcx.crate_name(cnum), - found_strategy.desc(), - desired_strategy.desc())); - } - } -} diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index c7260945295a6..4a9fa57f34525 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -630,6 +630,10 @@ rustc_queries! { -> &'tcx [(CrateNum, LinkagePreference)] { desc { "dylib dependency formats of crate" } } + + query dependency_formats(_: CrateNum) -> Lrc { + desc { "get the linkage format of all dependencies" } + } } Codegen { diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 5eda3df378126..a9a20a924347c 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -687,7 +687,7 @@ pub enum EntryFnType { impl_stable_hash_via_hash!(EntryFnType); -#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug)] +#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, HashStable)] pub enum CrateType { Executable, Dylib, diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index a24fed8f21c5a..8aca861d1f64d 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -7,7 +7,6 @@ use rustc_data_structures::fingerprint::Fingerprint; use crate::lint; use crate::lint::builtin::BuiltinLintDiagnostics; -use crate::middle::dependency_format; use crate::session::config::{OutputType, PrintRequest, SwitchWithOptPath}; use crate::session::search_paths::{PathKind, SearchPath}; use crate::util::nodemap::{FxHashMap, FxHashSet}; @@ -91,7 +90,6 @@ pub struct Session { pub plugin_llvm_passes: OneThread>>, pub plugin_attributes: Lock>, pub crate_types: Once>, - pub dependency_formats: Once, /// The `crate_disambiguator` is constructed out of all the `-C metadata` /// arguments passed to the compiler. Its value together with the crate-name /// forms a unique global identifier for the crate. It is used to allow @@ -1247,7 +1245,6 @@ fn build_session_( plugin_llvm_passes: OneThread::new(RefCell::new(Vec::new())), plugin_attributes: Lock::new(Vec::new()), crate_types: Once::new(), - dependency_formats: Once::new(), crate_disambiguator: Once::new(), features: Once::new(), recursion_limit: Once::new(), diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs index 9b044d9b45377..3b7ae5e33d5e7 100644 --- a/src/librustc_codegen_ssa/back/link.rs +++ b/src/librustc_codegen_ssa/back/link.rs @@ -219,15 +219,24 @@ pub fn get_linker(sess: &Session, linker: &Path, flavor: LinkerFlavor) -> (PathB (linker.to_path_buf(), cmd) } -pub fn each_linked_rlib(sess: &Session, - info: &CrateInfo, - f: &mut dyn FnMut(CrateNum, &Path)) -> Result<(), String> { +pub fn each_linked_rlib( + info: &CrateInfo, + f: &mut dyn FnMut(CrateNum, &Path), +) -> Result<(), String> { let crates = info.used_crates_static.iter(); - let fmts = sess.dependency_formats.borrow(); - let fmts = fmts.get(&config::CrateType::Executable) - .or_else(|| fmts.get(&config::CrateType::Staticlib)) - .or_else(|| fmts.get(&config::CrateType::Cdylib)) - .or_else(|| fmts.get(&config::CrateType::ProcMacro)); + let mut fmts = None; + for (ty, list) in info.dependency_formats.iter() { + match ty { + config::CrateType::Executable | + config::CrateType::Staticlib | + config::CrateType::Cdylib | + config::CrateType::ProcMacro => { + fmts = Some(list); + break; + } + _ => {} + } + } let fmts = match fmts { Some(f) => f, None => return Err("could not find formats for rlibs".to_string()) @@ -406,7 +415,7 @@ fn link_staticlib<'a, B: ArchiveBuilder<'a>>(sess: &'a Session, tempdir); let mut all_native_libs = vec![]; - let res = each_linked_rlib(sess, &codegen_results.crate_info, &mut |cnum, path| { + let res = each_linked_rlib(&codegen_results.crate_info, &mut |cnum, path| { let name = &codegen_results.crate_info.crate_name[&cnum]; let native_libs = &codegen_results.crate_info.native_libraries[&cnum]; @@ -1294,11 +1303,13 @@ pub fn add_local_native_libraries(cmd: &mut dyn Linker, // Rust crates are not considered at all when creating an rlib output. All // dependencies will be linked when producing the final output (instead of // the intermediate rlib version) -fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(cmd: &mut dyn Linker, - sess: &'a Session, - codegen_results: &CodegenResults, - crate_type: config::CrateType, - tmpdir: &Path) { +fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( + cmd: &mut dyn Linker, + sess: &'a Session, + codegen_results: &CodegenResults, + crate_type: config::CrateType, + tmpdir: &Path, +) { // All of the heavy lifting has previously been accomplished by the // dependency_format module of the compiler. This is just crawling the // output of that module, adding crates as necessary. @@ -1307,8 +1318,10 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(cmd: &mut dyn Linker, // will slurp up the object files inside), and linking to a dynamic library // involves just passing the right -l flag. - let formats = sess.dependency_formats.borrow(); - let data = formats.get(&crate_type).unwrap(); + let (_, data) = codegen_results.crate_info.dependency_formats + .iter() + .find(|(ty, _)| *ty == crate_type) + .expect("failed to find crate type in dependency format list"); // Invoke get_used_crates to ensure that we get a topological sorting of // crates. @@ -1620,10 +1633,12 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(cmd: &mut dyn Linker, // generic function calls a native function, then the generic function must // be instantiated in the target crate, meaning that the native symbol must // also be resolved in the target crate. -pub fn add_upstream_native_libraries(cmd: &mut dyn Linker, - sess: &Session, - codegen_results: &CodegenResults, - crate_type: config::CrateType) { +pub fn add_upstream_native_libraries( + cmd: &mut dyn Linker, + sess: &Session, + codegen_results: &CodegenResults, + crate_type: config::CrateType, +) { // Be sure to use a topological sorting of crates because there may be // interdependencies between native libraries. When passing -nodefaultlibs, // for example, almost all native libraries depend on libc, so we have to @@ -1633,8 +1648,10 @@ pub fn add_upstream_native_libraries(cmd: &mut dyn Linker, // This passes RequireStatic, but the actual requirement doesn't matter, // we're just getting an ordering of crate numbers, we're not worried about // the paths. - let formats = sess.dependency_formats.borrow(); - let data = formats.get(&crate_type).unwrap(); + let (_, data) = codegen_results.crate_info.dependency_formats + .iter() + .find(|(ty, _)| *ty == crate_type) + .expect("failed to find crate type in dependency format list"); let crates = &codegen_results.crate_info.used_crates_static; for &(cnum, _) in crates { diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs index c42cd024926dc..940a9a72bf6d4 100644 --- a/src/librustc_codegen_ssa/back/linker.rs +++ b/src/librustc_codegen_ssa/back/linker.rs @@ -1092,10 +1092,16 @@ fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec { } } - let formats = tcx.sess.dependency_formats.borrow(); - let deps = formats[&crate_type].iter(); + let formats = tcx.dependency_formats(LOCAL_CRATE); + let deps = formats.iter().filter_map(|(t, list)| { + if *t == crate_type { + Some(list) + } else { + None + } + }).next().unwrap(); - for (index, dep_format) in deps.enumerate() { + for (index, dep_format) in deps.iter().enumerate() { let cnum = CrateNum::new(index + 1); // For each dependency that we are linking to statically ... if *dep_format == Linkage::Static { diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index 1bba479c1fd5d..1a2c23ae0d4f7 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/src/librustc_codegen_ssa/back/write.rs @@ -1048,7 +1048,7 @@ fn start_executing_work( }).expect("failed to spawn helper thread"); let mut each_linked_rlib_for_lto = Vec::new(); - drop(link::each_linked_rlib(sess, crate_info, &mut |cnum, path| { + drop(link::each_linked_rlib(crate_info, &mut |cnum, path| { if link::ignored_for_lto(sess, crate_info, cnum) { return } diff --git a/src/librustc_codegen_ssa/base.rs b/src/librustc_codegen_ssa/base.rs index 4acbe0356b47c..98d3022a4185d 100644 --- a/src/librustc_codegen_ssa/base.rs +++ b/src/librustc_codegen_ssa/base.rs @@ -539,7 +539,7 @@ pub fn codegen_crate( // linkage, then it's already got an allocator shim and we'll be using that // one instead. If nothing exists then it's our job to generate the // allocator! - let any_dynamic_crate = tcx.sess.dependency_formats.borrow() + let any_dynamic_crate = tcx.dependency_formats(LOCAL_CRATE) .iter() .any(|(_, list)| { use rustc::middle::dependency_format::Linkage; @@ -731,6 +731,7 @@ impl CrateInfo { used_crate_source: Default::default(), lang_item_to_crate: Default::default(), missing_lang_items: Default::default(), + dependency_formats: tcx.dependency_formats(LOCAL_CRATE), }; let lang_items = tcx.lang_items(); diff --git a/src/librustc_codegen_ssa/lib.rs b/src/librustc_codegen_ssa/lib.rs index 1708d7235b45b..161d3ce61f0a6 100644 --- a/src/librustc_codegen_ssa/lib.rs +++ b/src/librustc_codegen_ssa/lib.rs @@ -33,6 +33,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; use rustc_data_structures::svh::Svh; use rustc::middle::cstore::{LibSource, CrateSource, NativeLibrary}; +use rustc::middle::dependency_format::Dependencies; use syntax_pos::symbol::Symbol; mod error_codes; @@ -142,6 +143,7 @@ pub struct CrateInfo { pub used_crates_dynamic: Vec<(CrateNum, LibSource)>, pub lang_item_to_crate: FxHashMap, pub missing_lang_items: FxHashMap>, + pub dependency_formats: Lrc, } diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index e8e8da6733471..102ea690f5ac9 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -1079,10 +1079,6 @@ pub fn start_codegen<'tcx>( tcx.print_debug_stats(); } - time(tcx.sess, "resolving dependency formats", || { - middle::dependency_format::calculate(tcx) - }); - let (metadata, need_metadata_module) = time(tcx.sess, "metadata encoding and writing", || { encode_and_write_metadata(tcx, outputs) }); diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index a1e3bbcbf8ea9..4a81fd3b32084 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -370,6 +370,11 @@ pub fn provide(providers: &mut Providers<'_>) { tcx.arena.alloc(visible_parent_map) }, + dependency_formats: |tcx, cnum| { + assert_eq!(cnum, LOCAL_CRATE); + Lrc::new(crate::dependency_format::calculate(tcx)) + }, + ..*providers }; } diff --git a/src/librustc_metadata/dependency_format.rs b/src/librustc_metadata/dependency_format.rs new file mode 100644 index 0000000000000..9de326a67b423 --- /dev/null +++ b/src/librustc_metadata/dependency_format.rs @@ -0,0 +1,371 @@ +//! Resolution of mixing rlibs and dylibs +//! +//! When producing a final artifact, such as a dynamic library, the compiler has +//! a choice between linking an rlib or linking a dylib of all upstream +//! dependencies. The linking phase must guarantee, however, that a library only +//! show up once in the object file. For example, it is illegal for library A to +//! be statically linked to B and C in separate dylibs, and then link B and C +//! into a crate D (because library A appears twice). +//! +//! The job of this module is to calculate what format each upstream crate +//! should be used when linking each output type requested in this session. This +//! generally follows this set of rules: +//! +//! 1. Each library must appear exactly once in the output. +//! 2. Each rlib contains only one library (it's just an object file) +//! 3. Each dylib can contain more than one library (due to static linking), +//! and can also bring in many dynamic dependencies. +//! +//! With these constraints in mind, it's generally a very difficult problem to +//! find a solution that's not "all rlibs" or "all dylibs". I have suspicions +//! that NP-ness may come into the picture here... +//! +//! The current selection algorithm below looks mostly similar to: +//! +//! 1. If static linking is required, then require all upstream dependencies +//! to be available as rlibs. If not, generate an error. +//! 2. If static linking is requested (generating an executable), then +//! attempt to use all upstream dependencies as rlibs. If any are not +//! found, bail out and continue to step 3. +//! 3. Static linking has failed, at least one library must be dynamically +//! linked. Apply a heuristic by greedily maximizing the number of +//! dynamically linked libraries. +//! 4. Each upstream dependency available as a dynamic library is +//! registered. The dependencies all propagate, adding to a map. It is +//! possible for a dylib to add a static library as a dependency, but it +//! is illegal for two dylibs to add the same static library as a +//! dependency. The same dylib can be added twice. Additionally, it is +//! illegal to add a static dependency when it was previously found as a +//! dylib (and vice versa) +//! 5. After all dynamic dependencies have been traversed, re-traverse the +//! remaining dependencies and add them statically (if they haven't been +//! added already). +//! +//! While not perfect, this algorithm should help support use-cases such as leaf +//! dependencies being static while the larger tree of inner dependencies are +//! all dynamic. This isn't currently very well battle tested, so it will likely +//! fall short in some use cases. +//! +//! Currently, there is no way to specify the preference of linkage with a +//! particular library (other than a global dynamic/static switch). +//! Additionally, the algorithm is geared towards finding *any* solution rather +//! than finding a number of solutions (there are normally quite a few). + +use rustc::hir::def_id::CrateNum; +use rustc::middle::cstore::LinkagePreference::{self, RequireStatic, RequireDynamic}; +use rustc::middle::cstore::{self, DepKind}; +use rustc::middle::dependency_format::{DependencyList, Dependencies, Linkage}; +use rustc::session::config; +use rustc::ty::TyCtxt; +use rustc::util::nodemap::FxHashMap; +use rustc_target::spec::PanicStrategy; + +pub fn calculate(tcx: TyCtxt<'_>) -> Dependencies { + tcx.sess.crate_types.borrow().iter().map(|&ty| { + let linkage = calculate_type(tcx, ty); + verify_ok(tcx, &linkage); + (ty, linkage) + }).collect::>() +} + +fn calculate_type(tcx: TyCtxt<'_>, ty: config::CrateType) -> DependencyList { + let sess = &tcx.sess; + + if !sess.opts.output_types.should_codegen() { + return Vec::new(); + } + + let preferred_linkage = match ty { + // cdylibs must have all static dependencies. + config::CrateType::Cdylib => Linkage::Static, + + // Generating a dylib without `-C prefer-dynamic` means that we're going + // to try to eagerly statically link all dependencies. This is normally + // done for end-product dylibs, not intermediate products. + config::CrateType::Dylib if !sess.opts.cg.prefer_dynamic => Linkage::Static, + config::CrateType::Dylib => Linkage::Dynamic, + + // If the global prefer_dynamic switch is turned off, or the final + // executable will be statically linked, prefer static crate linkage. + config::CrateType::Executable if !sess.opts.cg.prefer_dynamic || + sess.crt_static() => Linkage::Static, + config::CrateType::Executable => Linkage::Dynamic, + + // proc-macro crates are mostly cdylibs, but we also need metadata. + config::CrateType::ProcMacro => Linkage::Static, + + // No linkage happens with rlibs, we just needed the metadata (which we + // got long ago), so don't bother with anything. + config::CrateType::Rlib => Linkage::NotLinked, + + // staticlibs must have all static dependencies. + config::CrateType::Staticlib => Linkage::Static, + }; + + if preferred_linkage == Linkage::NotLinked { + // If the crate is not linked, there are no link-time dependencies. + return Vec::new(); + } + + if preferred_linkage == Linkage::Static { + // Attempt static linkage first. For dylibs and executables, we may be + // able to retry below with dynamic linkage. + if let Some(v) = attempt_static(tcx) { + return v; + } + + // Staticlibs, cdylibs, and static executables must have all static + // dependencies. If any are not found, generate some nice pretty errors. + if ty == config::CrateType::Cdylib || ty == config::CrateType::Staticlib || + (ty == config::CrateType::Executable && sess.crt_static() && + !sess.target.target.options.crt_static_allows_dylibs) { + for &cnum in tcx.crates().iter() { + if tcx.dep_kind(cnum).macros_only() { continue } + let src = tcx.used_crate_source(cnum); + if src.rlib.is_some() { continue } + sess.err(&format!("crate `{}` required to be available in rlib format, \ + but was not found in this form", + tcx.crate_name(cnum))); + } + return Vec::new(); + } + } + + let mut formats = FxHashMap::default(); + + // Sweep all crates for found dylibs. Add all dylibs, as well as their + // dependencies, ensuring there are no conflicts. The only valid case for a + // dependency to be relied upon twice is for both cases to rely on a dylib. + for &cnum in tcx.crates().iter() { + if tcx.dep_kind(cnum).macros_only() { continue } + let name = tcx.crate_name(cnum); + let src = tcx.used_crate_source(cnum); + if src.dylib.is_some() { + log::info!("adding dylib: {}", name); + add_library(tcx, cnum, RequireDynamic, &mut formats); + let deps = tcx.dylib_dependency_formats(cnum); + for &(depnum, style) in deps.iter() { + log::info!("adding {:?}: {}", style, tcx.crate_name(depnum)); + add_library(tcx, depnum, style, &mut formats); + } + } + } + + // Collect what we've got so far in the return vector. + let last_crate = tcx.crates().len(); + let mut ret = (1..last_crate+1).map(|cnum| { + match formats.get(&CrateNum::new(cnum)) { + Some(&RequireDynamic) => Linkage::Dynamic, + Some(&RequireStatic) => Linkage::IncludedFromDylib, + None => Linkage::NotLinked, + } + }).collect::>(); + + // Run through the dependency list again, and add any missing libraries as + // static libraries. + // + // If the crate hasn't been included yet and it's not actually required + // (e.g., it's an allocator) then we skip it here as well. + for &cnum in tcx.crates().iter() { + let src = tcx.used_crate_source(cnum); + if src.dylib.is_none() && + !formats.contains_key(&cnum) && + tcx.dep_kind(cnum) == DepKind::Explicit { + assert!(src.rlib.is_some() || src.rmeta.is_some()); + log::info!("adding staticlib: {}", tcx.crate_name(cnum)); + add_library(tcx, cnum, RequireStatic, &mut formats); + ret[cnum.as_usize() - 1] = Linkage::Static; + } + } + + // We've gotten this far because we're emitting some form of a final + // artifact which means that we may need to inject dependencies of some + // form. + // + // Things like allocators and panic runtimes may not have been activated + // quite yet, so do so here. + activate_injected_dep(*sess.injected_panic_runtime.get(), &mut ret, + &|cnum| tcx.is_panic_runtime(cnum)); + + // When dylib B links to dylib A, then when using B we must also link to A. + // It could be the case, however, that the rlib for A is present (hence we + // found metadata), but the dylib for A has since been removed. + // + // For situations like this, we perform one last pass over the dependencies, + // making sure that everything is available in the requested format. + for (cnum, kind) in ret.iter().enumerate() { + let cnum = CrateNum::new(cnum + 1); + let src = tcx.used_crate_source(cnum); + match *kind { + Linkage::NotLinked | + Linkage::IncludedFromDylib => {} + Linkage::Static if src.rlib.is_some() => continue, + Linkage::Dynamic if src.dylib.is_some() => continue, + kind => { + let kind = match kind { + Linkage::Static => "rlib", + _ => "dylib", + }; + sess.err(&format!("crate `{}` required to be available in {} format, \ + but was not found in this form", + tcx.crate_name(cnum), kind)); + } + } + } + + ret +} + +fn add_library( + tcx: TyCtxt<'_>, + cnum: CrateNum, + link: LinkagePreference, + m: &mut FxHashMap, +) { + match m.get(&cnum) { + Some(&link2) => { + // If the linkages differ, then we'd have two copies of the library + // if we continued linking. If the linkages are both static, then we + // would also have two copies of the library (static from two + // different locations). + // + // This error is probably a little obscure, but I imagine that it + // can be refined over time. + if link2 != link || link == RequireStatic { + tcx.sess.struct_err(&format!("cannot satisfy dependencies so `{}` only \ + shows up once", tcx.crate_name(cnum))) + .help("having upstream crates all available in one format \ + will likely make this go away") + .emit(); + } + } + None => { m.insert(cnum, link); } + } +} + +fn attempt_static(tcx: TyCtxt<'_>) -> Option { + let sess = &tcx.sess; + let crates = cstore::used_crates(tcx, RequireStatic); + if !crates.iter().by_ref().all(|&(_, ref p)| p.is_some()) { + return None + } + + // All crates are available in an rlib format, so we're just going to link + // everything in explicitly so long as it's actually required. + let last_crate = tcx.crates().len(); + let mut ret = (1..last_crate+1).map(|cnum| { + if tcx.dep_kind(CrateNum::new(cnum)) == DepKind::Explicit { + Linkage::Static + } else { + Linkage::NotLinked + } + }).collect::>(); + + // Our allocator/panic runtime may not have been linked above if it wasn't + // explicitly linked, which is the case for any injected dependency. Handle + // that here and activate them. + activate_injected_dep(*sess.injected_panic_runtime.get(), &mut ret, + &|cnum| tcx.is_panic_runtime(cnum)); + + Some(ret) +} + +// Given a list of how to link upstream dependencies so far, ensure that an +// injected dependency is activated. This will not do anything if one was +// transitively included already (e.g., via a dylib or explicitly so). +// +// If an injected dependency was not found then we're guaranteed the +// metadata::creader module has injected that dependency (not listed as +// a required dependency) in one of the session's field. If this field is not +// set then this compilation doesn't actually need the dependency and we can +// also skip this step entirely. +fn activate_injected_dep(injected: Option, + list: &mut DependencyList, + replaces_injected: &dyn Fn(CrateNum) -> bool) { + for (i, slot) in list.iter().enumerate() { + let cnum = CrateNum::new(i + 1); + if !replaces_injected(cnum) { + continue + } + if *slot != Linkage::NotLinked { + return + } + } + if let Some(injected) = injected { + let idx = injected.as_usize() - 1; + assert_eq!(list[idx], Linkage::NotLinked); + list[idx] = Linkage::Static; + } +} + +// After the linkage for a crate has been determined we need to verify that +// there's only going to be one allocator in the output. +fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) { + let sess = &tcx.sess; + if list.len() == 0 { + return + } + let mut panic_runtime = None; + for (i, linkage) in list.iter().enumerate() { + if let Linkage::NotLinked = *linkage { + continue + } + let cnum = CrateNum::new(i + 1); + + if tcx.is_panic_runtime(cnum) { + if let Some((prev, _)) = panic_runtime { + let prev_name = tcx.crate_name(prev); + let cur_name = tcx.crate_name(cnum); + sess.err(&format!("cannot link together two \ + panic runtimes: {} and {}", + prev_name, cur_name)); + } + panic_runtime = Some((cnum, tcx.panic_strategy(cnum))); + } + } + + // If we found a panic runtime, then we know by this point that it's the + // only one, but we perform validation here that all the panic strategy + // compilation modes for the whole DAG are valid. + if let Some((cnum, found_strategy)) = panic_runtime { + let desired_strategy = sess.panic_strategy(); + + // First up, validate that our selected panic runtime is indeed exactly + // our same strategy. + if found_strategy != desired_strategy { + sess.err(&format!("the linked panic runtime `{}` is \ + not compiled with this crate's \ + panic strategy `{}`", + tcx.crate_name(cnum), + desired_strategy.desc())); + } + + // Next up, verify that all other crates are compatible with this panic + // strategy. If the dep isn't linked, we ignore it, and if our strategy + // is abort then it's compatible with everything. Otherwise all crates' + // panic strategy must match our own. + for (i, linkage) in list.iter().enumerate() { + if let Linkage::NotLinked = *linkage { + continue + } + if desired_strategy == PanicStrategy::Abort { + continue + } + let cnum = CrateNum::new(i + 1); + let found_strategy = tcx.panic_strategy(cnum); + let is_compiler_builtins = tcx.is_compiler_builtins(cnum); + if is_compiler_builtins || desired_strategy == found_strategy { + continue + } + + sess.err(&format!("the crate `{}` is compiled with the \ + panic strategy `{}` which is \ + incompatible with this crate's \ + strategy of `{}`", + tcx.crate_name(cnum), + found_strategy.desc(), + desired_strategy.desc())); + } + } +} + diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index f430f01542efe..be083cf6020ea 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1649,20 +1649,22 @@ impl EncodeContext<'tcx> { } fn encode_dylib_dependency_formats(&mut self) -> Lazy<[Option]> { - match self.tcx.sess.dependency_formats.borrow().get(&config::CrateType::Dylib) { - Some(arr) => { - self.lazy(arr.iter().map(|slot| { - match *slot { - Linkage::NotLinked | - Linkage::IncludedFromDylib => None, - - Linkage::Dynamic => Some(LinkagePreference::RequireDynamic), - Linkage::Static => Some(LinkagePreference::RequireStatic), - } - })) + let formats = self.tcx.dependency_formats(LOCAL_CRATE); + for (ty, arr) in formats.iter() { + if *ty != config::CrateType::Dylib { + continue; } - None => Lazy::empty(), + return self.lazy(arr.iter().map(|slot| { + match *slot { + Linkage::NotLinked | + Linkage::IncludedFromDylib => None, + + Linkage::Dynamic => Some(LinkagePreference::RequireDynamic), + Linkage::Static => Some(LinkagePreference::RequireStatic), + } + })); } + Lazy::empty() } fn encode_info_for_foreign_item(&mut self, diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index e6104e629e9fb..9273b064ba9ce 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -32,6 +32,7 @@ mod schema; mod native_libs; mod link_args; mod foreign_modules; +mod dependency_format; pub mod creader; pub mod cstore; From 50c57d8c80b1fab4c1e9087756fb9fae396d5218 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 11 Sep 2019 08:08:04 -0700 Subject: [PATCH 10/17] rustc: Fix mixing crates with different `share_generics` This commit addresses #64319 by removing the `dylib` crate type from the list of crate type that exports generic symbols. The bug in #64319 arises because a `dylib` crate type was trying to export a symbol in an uptream crate but it miscalculated the symbol name of the uptream symbol. This isn't really necessary, though, since `dylib` crates aren't that heavily used, so we can just conservatively say that the `dylib` crate type never exports generic symbols, forcibly removing them from the exported symbol lists if were to otherwise find them. The fix here happens in two places: * First is in the `local_crate_exports_generics` method, indicating that it's now `false` for the `Dylib` crate type. Only rlibs actually export generics at this point. * Next is when we load exported symbols from upstream crate. If, for our compilation session, the crate may be included from a dynamic library, then its generic symbols are removed. When the crate was linked into a dynamic library its symbols weren't exported, so we can't consider them a candidate to link against. Overally this should avoid situations where we incorrectly calculate the upstream symbol names in the face of differnet `share_generics` options, ultimately... Closes #64319 --- src/librustc/query/mod.rs | 4 +- src/librustc/ty/context.rs | 4 +- .../back/symbol_export.rs | 2 +- src/librustc_metadata/cstore_impl.rs | 27 ++++++++++++- src/librustc_metadata/dependency_format.rs | 1 - .../auxiliary/shared_generics_aux.rs | 1 + .../partitioning/shared-generics.rs | 1 + src/test/compile-fail/two-panic-runtimes.rs | 1 + .../run-make-fulldeps/issue-64319/Makefile | 39 +++++++++++++++++++ src/test/run-make-fulldeps/issue-64319/bar.rs | 5 +++ src/test/run-make-fulldeps/issue-64319/foo.rs | 9 +++++ .../symbol-visibility/Makefile | 4 +- .../panic-runtime/transitive-link-a-bunch.rs | 3 +- .../ui/panic-runtime/want-unwind-got-abort.rs | 3 +- .../panic-runtime/want-unwind-got-abort2.rs | 3 +- 15 files changed, 93 insertions(+), 14 deletions(-) create mode 100644 src/test/run-make-fulldeps/issue-64319/Makefile create mode 100644 src/test/run-make-fulldeps/issue-64319/bar.rs create mode 100644 src/test/run-make-fulldeps/issue-64319/foo.rs diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index 4a9fa57f34525..fd99995480a9e 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -631,7 +631,9 @@ rustc_queries! { desc { "dylib dependency formats of crate" } } - query dependency_formats(_: CrateNum) -> Lrc { + query dependency_formats(_: CrateNum) + -> Lrc + { desc { "get the linkage format of all dependencies" } } } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 0155803e30580..c03dbb2b1ed0e 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1510,9 +1510,9 @@ impl<'tcx> TyCtxt<'tcx> { CrateType::Executable | CrateType::Staticlib | CrateType::ProcMacro | + CrateType::Dylib | CrateType::Cdylib => false, - CrateType::Rlib | - CrateType::Dylib => true, + CrateType::Rlib => true, } }) } diff --git a/src/librustc_codegen_ssa/back/symbol_export.rs b/src/librustc_codegen_ssa/back/symbol_export.rs index 7e700e6819426..3e4b7695447c8 100644 --- a/src/librustc_codegen_ssa/back/symbol_export.rs +++ b/src/librustc_codegen_ssa/back/symbol_export.rs @@ -298,7 +298,7 @@ fn upstream_monomorphizations_provider( }; for &cnum in cnums.iter() { - for &(ref exported_symbol, _) in tcx.exported_symbols(cnum).iter() { + for (exported_symbol, _) in tcx.exported_symbols(cnum).iter() { if let &ExportedSymbol::Generic(def_id, substs) = exported_symbol { let substs_map = instances.entry(def_id).or_default(); diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 4a81fd3b32084..f18a98ffea7cd 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -10,6 +10,8 @@ use rustc::middle::cstore::{CrateStore, DepKind, EncodedMetadata, NativeLibraryKind}; use rustc::middle::exported_symbols::ExportedSymbol; use rustc::middle::stability::DeprecationEntry; +use rustc::middle::dependency_format::Linkage; +use rustc::session::config::CrateType; use rustc::hir::def; use rustc::hir; use rustc::session::{CrateDisambiguator, Session}; @@ -239,7 +241,30 @@ provide! { <'tcx> tcx, def_id, other, cdata, used_crate_source => { Lrc::new(cdata.source.clone()) } - exported_symbols => { Arc::new(cdata.exported_symbols(tcx)) } + exported_symbols => { + let mut syms = cdata.exported_symbols(tcx); + + // When linked into a dylib crates don't export their generic symbols, + // so if that's happening then we can't load upstream monomorphizations + // from this crate. As a result, if we're creating a dylib or this crate + // is being included from a different dynamic library, then we filter + // out all `Generic` symbols here. + let formats = tcx.dependency_formats(LOCAL_CRATE); + let remove_generics = formats.iter().any(|(ty, list)| { + *ty == CrateType::Dylib || + list.get(def_id.krate.as_usize() - 1) == Some(&Linkage::IncludedFromDylib) + }); + if remove_generics { + syms.retain(|(sym, _threshold)| { + match sym { + ExportedSymbol::Generic(..) => false, + _ => return true, + } + }); + } + + Arc::new(syms) + } } pub fn provide(providers: &mut Providers<'_>) { diff --git a/src/librustc_metadata/dependency_format.rs b/src/librustc_metadata/dependency_format.rs index 9de326a67b423..9a30623b33d62 100644 --- a/src/librustc_metadata/dependency_format.rs +++ b/src/librustc_metadata/dependency_format.rs @@ -368,4 +368,3 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) { } } } - diff --git a/src/test/codegen-units/partitioning/auxiliary/shared_generics_aux.rs b/src/test/codegen-units/partitioning/auxiliary/shared_generics_aux.rs index d50a7910fe0b3..9050e8f1671d9 100644 --- a/src/test/codegen-units/partitioning/auxiliary/shared_generics_aux.rs +++ b/src/test/codegen-units/partitioning/auxiliary/shared_generics_aux.rs @@ -1,4 +1,5 @@ // compile-flags:-Zshare-generics=yes +// no-prefer-dynamic #![crate_type="rlib"] diff --git a/src/test/codegen-units/partitioning/shared-generics.rs b/src/test/codegen-units/partitioning/shared-generics.rs index 010412b8baeb3..58e485be00321 100644 --- a/src/test/codegen-units/partitioning/shared-generics.rs +++ b/src/test/codegen-units/partitioning/shared-generics.rs @@ -1,4 +1,5 @@ // ignore-tidy-linelength +// no-prefer-dynamic // compile-flags:-Zprint-mono-items=eager -Zshare-generics=yes -Zincremental=tmp/partitioning-tests/shared-generics-exe #![crate_type="rlib"] diff --git a/src/test/compile-fail/two-panic-runtimes.rs b/src/test/compile-fail/two-panic-runtimes.rs index 66b184e521abc..671d44564e66f 100644 --- a/src/test/compile-fail/two-panic-runtimes.rs +++ b/src/test/compile-fail/two-panic-runtimes.rs @@ -5,6 +5,7 @@ // aux-build:panic-runtime-lang-items.rs #![no_std] +#![no_main] extern crate panic_runtime_unwind; extern crate panic_runtime_unwind2; diff --git a/src/test/run-make-fulldeps/issue-64319/Makefile b/src/test/run-make-fulldeps/issue-64319/Makefile new file mode 100644 index 0000000000000..b2c6b8b3cbbf2 --- /dev/null +++ b/src/test/run-make-fulldeps/issue-64319/Makefile @@ -0,0 +1,39 @@ +-include ../tools.mk + +# Different optimization levels imply different values for `-Zshare-generics`, +# so try out a whole bunch of combinations to make sure everything is compatible +all: + # First up, try some defaults + $(RUSTC) --crate-type rlib foo.rs + $(RUSTC) --crate-type dylib bar.rs -C opt-level=3 + + # Next try mixing up some things explicitly + $(RUSTC) --crate-type rlib foo.rs -Z share-generics=no + $(RUSTC) --crate-type dylib bar.rs -Z share-generics=no + $(RUSTC) --crate-type rlib foo.rs -Z share-generics=no + $(RUSTC) --crate-type dylib bar.rs -Z share-generics=yes + $(RUSTC) --crate-type rlib foo.rs -Z share-generics=yes + $(RUSTC) --crate-type dylib bar.rs -Z share-generics=no + $(RUSTC) --crate-type rlib foo.rs -Z share-generics=yes + $(RUSTC) --crate-type dylib bar.rs -Z share-generics=yes + + # Now combine a whole bunch of options together + $(RUSTC) --crate-type rlib foo.rs + $(RUSTC) --crate-type dylib bar.rs + $(RUSTC) --crate-type dylib bar.rs -Z share-generics=no + $(RUSTC) --crate-type dylib bar.rs -Z share-generics=yes + $(RUSTC) --crate-type dylib bar.rs -C opt-level=1 + $(RUSTC) --crate-type dylib bar.rs -C opt-level=1 -Z share-generics=no + $(RUSTC) --crate-type dylib bar.rs -C opt-level=1 -Z share-generics=yes + $(RUSTC) --crate-type dylib bar.rs -C opt-level=2 + $(RUSTC) --crate-type dylib bar.rs -C opt-level=2 -Z share-generics=no + $(RUSTC) --crate-type dylib bar.rs -C opt-level=2 -Z share-generics=yes + $(RUSTC) --crate-type dylib bar.rs -C opt-level=3 + $(RUSTC) --crate-type dylib bar.rs -C opt-level=3 -Z share-generics=no + $(RUSTC) --crate-type dylib bar.rs -C opt-level=3 -Z share-generics=yes + $(RUSTC) --crate-type dylib bar.rs -C opt-level=s + $(RUSTC) --crate-type dylib bar.rs -C opt-level=s -Z share-generics=no + $(RUSTC) --crate-type dylib bar.rs -C opt-level=s -Z share-generics=yes + $(RUSTC) --crate-type dylib bar.rs -C opt-level=z + $(RUSTC) --crate-type dylib bar.rs -C opt-level=z -Z share-generics=no + $(RUSTC) --crate-type dylib bar.rs -C opt-level=z -Z share-generics=yes diff --git a/src/test/run-make-fulldeps/issue-64319/bar.rs b/src/test/run-make-fulldeps/issue-64319/bar.rs new file mode 100644 index 0000000000000..3895c0b6cdbb3 --- /dev/null +++ b/src/test/run-make-fulldeps/issue-64319/bar.rs @@ -0,0 +1,5 @@ +extern crate foo; + +pub fn bar() { + foo::foo(); +} diff --git a/src/test/run-make-fulldeps/issue-64319/foo.rs b/src/test/run-make-fulldeps/issue-64319/foo.rs new file mode 100644 index 0000000000000..c54a238e9add7 --- /dev/null +++ b/src/test/run-make-fulldeps/issue-64319/foo.rs @@ -0,0 +1,9 @@ +pub fn foo() { + bar::(); +} + +pub fn bar() { + baz(); +} + +fn baz() {} diff --git a/src/test/run-make-fulldeps/symbol-visibility/Makefile b/src/test/run-make-fulldeps/symbol-visibility/Makefile index 7901866015bf2..840fe801a953c 100644 --- a/src/test/run-make-fulldeps/symbol-visibility/Makefile +++ b/src/test/run-make-fulldeps/symbol-visibility/Makefile @@ -79,12 +79,12 @@ all: # Check that a Rust dylib exports its monomorphic functions, including generics this time [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_c_function_from_rust_dylib)" -eq "1" ] [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_rust_function_from_rust_dylib)" -eq "1" ] - [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_generic_function_from_rust_dylib)" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_generic_function_from_rust_dylib)" -eq "0" ] # Check that a Rust dylib exports the monomorphic functions from its dependencies [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ] [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_rust_function_from_rlib)" -eq "1" ] - [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_generic_function_from_rlib)" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_generic_function_from_rlib)" -eq "0" ] # Check that an executable does not export any dynamic symbols [ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -c public_c_function_from_rlib)" -eq "0" ] diff --git a/src/test/ui/panic-runtime/transitive-link-a-bunch.rs b/src/test/ui/panic-runtime/transitive-link-a-bunch.rs index 9b083a640a6d3..5d72771c2dcff 100644 --- a/src/test/ui/panic-runtime/transitive-link-a-bunch.rs +++ b/src/test/ui/panic-runtime/transitive-link-a-bunch.rs @@ -7,9 +7,8 @@ // ignore-wasm32-bare compiled with panic=abort by default #![no_std] +#![no_main] extern crate wants_panic_runtime_unwind; extern crate wants_panic_runtime_abort; extern crate panic_runtime_lang_items; - -fn main() {} diff --git a/src/test/ui/panic-runtime/want-unwind-got-abort.rs b/src/test/ui/panic-runtime/want-unwind-got-abort.rs index c9ee8a032a3d3..4c25c09d6438f 100644 --- a/src/test/ui/panic-runtime/want-unwind-got-abort.rs +++ b/src/test/ui/panic-runtime/want-unwind-got-abort.rs @@ -4,8 +4,7 @@ // ignore-wasm32-bare compiled with panic=abort by default #![no_std] +#![no_main] extern crate panic_runtime_abort; extern crate panic_runtime_lang_items; - -fn main() {} diff --git a/src/test/ui/panic-runtime/want-unwind-got-abort2.rs b/src/test/ui/panic-runtime/want-unwind-got-abort2.rs index 5219826eec62f..478af451e7f65 100644 --- a/src/test/ui/panic-runtime/want-unwind-got-abort2.rs +++ b/src/test/ui/panic-runtime/want-unwind-got-abort2.rs @@ -5,8 +5,7 @@ // ignore-wasm32-bare compiled with panic=abort by default #![no_std] +#![no_main] extern crate wants_panic_runtime_abort; extern crate panic_runtime_lang_items; - -fn main() {} From f00c6346b42d2a3091752166cd86aa2d69112dcc Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 23 Sep 2019 14:01:06 -0700 Subject: [PATCH 11/17] Allow using upstream generics in a dylib crate type ... just don't export them! --- src/librustc_codegen_ssa/back/linker.rs | 22 ++++++++++++++++++++-- src/librustc_metadata/cstore_impl.rs | 13 ++++++------- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs index 940a9a72bf6d4..ff87f0b1547ce 100644 --- a/src/librustc_codegen_ssa/back/linker.rs +++ b/src/librustc_codegen_ssa/back/linker.rs @@ -14,6 +14,7 @@ use rustc::middle::dependency_format::Linkage; use rustc::session::Session; use rustc::session::config::{self, CrateType, OptLevel, DebugInfo, LinkerPluginLto, Lto}; +use rustc::middle::exported_symbols::ExportedSymbol; use rustc::ty::TyCtxt; use rustc_target::spec::{LinkerFlavor, LldFlavor}; use rustc_serialize::{json, Encoder}; @@ -1107,9 +1108,26 @@ fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec { if *dep_format == Linkage::Static { // ... we add its symbol list to our export list. for &(symbol, level) in tcx.exported_symbols(cnum).iter() { - if level.is_below_threshold(export_threshold) { - symbols.push(symbol.symbol_name(tcx).to_string()); + if !level.is_below_threshold(export_threshold) { + continue; } + + // Do not export generic symbols from upstream crates in linked + // artifact (notably the `dylib` crate type). The main reason + // for this is that `symbol_name` is actually wrong for generic + // symbols because it guesses the name we'd give them locally + // rather than the name it has upstream (depending on + // `share_generics` settings and such). + // + // To fix that issue we just say that linked artifacts, aka + // `dylib`s, never export generic symbols and they aren't + // available to downstream crates. (the not available part is + // handled elsewhere). + if let ExportedSymbol::Generic(..) = symbol { + continue; + } + + symbols.push(symbol.symbol_name(tcx).to_string()); } } } diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index f18a98ffea7cd..0bc53dbde5f8a 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -11,7 +11,6 @@ use rustc::middle::cstore::{CrateStore, DepKind, use rustc::middle::exported_symbols::ExportedSymbol; use rustc::middle::stability::DeprecationEntry; use rustc::middle::dependency_format::Linkage; -use rustc::session::config::CrateType; use rustc::hir::def; use rustc::hir; use rustc::session::{CrateDisambiguator, Session}; @@ -246,13 +245,13 @@ provide! { <'tcx> tcx, def_id, other, cdata, // When linked into a dylib crates don't export their generic symbols, // so if that's happening then we can't load upstream monomorphizations - // from this crate. As a result, if we're creating a dylib or this crate - // is being included from a different dynamic library, then we filter - // out all `Generic` symbols here. + // from this crate. let formats = tcx.dependency_formats(LOCAL_CRATE); - let remove_generics = formats.iter().any(|(ty, list)| { - *ty == CrateType::Dylib || - list.get(def_id.krate.as_usize() - 1) == Some(&Linkage::IncludedFromDylib) + let remove_generics = formats.iter().any(|(_ty, list)| { + match list.get(def_id.krate.as_usize() - 1) { + Some(Linkage::IncludedFromDylib) | Some(Linkage::Dynamic) => true, + _ => false, + } }); if remove_generics { syms.retain(|(sym, _threshold)| { From a744fd04321f6307303a22ecc8880cbc7b6bcbda Mon Sep 17 00:00:00 2001 From: csmoe Date: Mon, 23 Sep 2019 17:13:11 +0000 Subject: [PATCH 12/17] bug-out asyncness query on non-local funtions --- src/librustc/ty/mod.rs | 21 +++++++++++---------- src/librustc_metadata/decoder.rs | 3 ++- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index dd36a4520929a..98fa64c265cb2 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -3351,16 +3351,17 @@ fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option> { /// Check if a function is async. fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync { - if let Some(hir_id) = tcx.hir().as_local_hir_id(def_id) { - let node = tcx.hir().get(hir_id); - if let Some(fn_like) = hir::map::blocks::FnLikeNode::from_node(node) { - fn_like.asyncness() - } else { - hir::IsAsync::NotAsync - } - } else { - hir::IsAsync::NotAsync - } + let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap_or_else(|| { + bug!("asyncness: expected local `DefId`, got `{:?}`", def_id) + }); + + let node = tcx.hir().get(hir_id); + + let fn_like = hir::map::blocks::FnLikeNode::from_node(node).unwrap_or_else(|| { + bug!("asyncness: expected fn-like node but got `{:?}`", def_id); + }); + + fn_like.asyncness() } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 5153564fc8255..6698c7cb17036 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1212,7 +1212,8 @@ impl<'a, 'tcx> CrateMetadata { match self.entry(id).kind { EntryKind::Fn(data) => data.decode(self).asyncness, EntryKind::Method(data) => data.decode(self).fn_data.asyncness, - _ => hir::IsAsync::NotAsync, + EntryKind::ForeignFn(data) => data.decode(self).asyncness, + _ => bug!("asyncness: expect functions entry."), } } From 5c5e3facabbeb84ef0e5de0ccbfcfa973927f8d1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 24 Sep 2019 11:06:56 -0700 Subject: [PATCH 13/17] Update cargo 11 commits in b6c6f685b38d523580813b0031677c2298f458ea..aa6b7e01abce30091cc594cb23a15c46cead6e24 2019-09-19 21:10:09 +0000 to 2019-09-24 17:19:12 +0000 - Fix interpretation of `--features a b` on the CLI (rust-lang/cargo#7419) - Update env_logger requirement from 0.6.0 to 0.7.0 (rust-lang/cargo#7422) - Update some unstable docs (rust-lang/cargo#7407) - Fix xcompile tests. (rust-lang/cargo#7408) - -Ztimings: Fix more scale problems. (rust-lang/cargo#7403) - Fix some rendering issues with -Ztimings. (rust-lang/cargo#7397) - -Ztimings: show max jobs/cpus (rust-lang/cargo#7398) - Fix -Ztimings with doc tests. (rust-lang/cargo#7395) - Add documentation for the -Zdoctest-xcompile feature (rust-lang/cargo#7391) - Fix integration tests waiting for binaries to finish. (rust-lang/cargo#7394) - Extract Platform to a separate crate. (rust-lang/cargo#7375) --- Cargo.lock | 47 ++++++++++++++++++++++++++++++++++------------- src/tools/cargo | 2 +- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5bc1938fee260..2f998c5d012d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -269,6 +269,7 @@ version = "0.40.0" dependencies = [ "atty", "bytesize", + "cargo-platform", "cargo-test-macro", "cargo-test-support", "clap", @@ -278,7 +279,7 @@ dependencies = [ "crypto-hash", "curl", "curl-sys", - "env_logger", + "env_logger 0.7.0", "failure", "filetime", "flate2", @@ -325,6 +326,13 @@ dependencies = [ "winapi 0.3.6", ] +[[package]] +name = "cargo-platform" +version = "0.1.0" +dependencies = [ + "serde", +] + [[package]] name = "cargo-test-macro" version = "0.1.0" @@ -526,7 +534,7 @@ name = "compiletest" version = "0.0.0" dependencies = [ "diff", - "env_logger", + "env_logger 0.6.2", "getopts", "lazy_static 1.3.0", "libc", @@ -938,6 +946,19 @@ dependencies = [ "termcolor", ] +[[package]] +name = "env_logger" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ecdb7dd54465526f0a56d666e3b2dd5f3a218665a030b6e4ad9e70fa95d8fa" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + [[package]] name = "error-chain" version = "0.12.0" @@ -1339,9 +1360,9 @@ checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" [[package]] name = "humantime" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" dependencies = [ "quick-error", ] @@ -1866,7 +1887,7 @@ dependencies = [ "chrono", "clap", "elasticlunr-rs", - "env_logger", + "env_logger 0.6.2", "error-chain", "handlebars", "itertools 0.8.0", @@ -1891,7 +1912,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77d1f0ba4d1e6b86fa18e8853d026d7d76a97eb7eb5eb052ed80901e43b7fc10" dependencies = [ - "env_logger", + "env_logger 0.6.2", "failure", "log", "mdbook", @@ -2084,7 +2105,7 @@ dependencies = [ "colored", "compiletest_rs", "directories", - "env_logger", + "env_logger 0.6.2", "getrandom", "hex 0.3.2", "log", @@ -2493,7 +2514,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df8b3f4e0475def7d9c2e5de8e5a1306949849761e107b360d03e98eafaffd61" dependencies = [ "chrono", - "env_logger", + "env_logger 0.6.2", "log", ] @@ -2620,7 +2641,7 @@ dependencies = [ "bitflags", "clap", "derive_more", - "env_logger", + "env_logger 0.6.2", "humantime", "lazy_static 1.3.0", "log", @@ -2914,7 +2935,7 @@ dependencies = [ "clippy_lints", "crossbeam-channel", "difference", - "env_logger", + "env_logger 0.6.2", "failure", "futures", "heck", @@ -2998,7 +3019,7 @@ name = "rls-rustc" version = "0.6.0" dependencies = [ "clippy_lints", - "env_logger", + "env_logger 0.6.2", "failure", "futures", "log", @@ -3403,7 +3424,7 @@ dependencies = [ name = "rustc_driver" version = "0.0.0" dependencies = [ - "env_logger", + "env_logger 0.6.2", "graphviz", "lazy_static 1.3.0", "log", @@ -3791,7 +3812,7 @@ dependencies = [ "derive-new", "diff", "dirs", - "env_logger", + "env_logger 0.6.2", "failure", "getopts", "ignore", diff --git a/src/tools/cargo b/src/tools/cargo index b6c6f685b38d5..aa6b7e01abce3 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit b6c6f685b38d523580813b0031677c2298f458ea +Subproject commit aa6b7e01abce30091cc594cb23a15c46cead6e24 From d9ab4ff9a3746c8663278f7338cfb4aabf96a9bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 24 Sep 2019 11:05:49 -0700 Subject: [PATCH 14/17] Remove blanket silencing of "type annotation needed" errors Remove blanket check for existence of other errors before emitting "type annotation needed" errors, and add some eager checks to avoid adding obligations when they refer to types that reference `[type error]` in order to reduce unneded errors. --- src/librustc/hir/lowering.rs | 4 +- src/librustc/infer/opaque_types/mod.rs | 13 ++- src/librustc/traits/error_reporting.rs | 71 ++++++++----- src/librustc/traits/mod.rs | 13 ++- src/librustc/traits/select.rs | 2 +- src/librustc/traits/structural_impls.rs | 3 +- src/librustc/ty/mod.rs | 6 +- src/librustc_typeck/check/coercion.rs | 2 +- src/librustc_typeck/check/expr.rs | 16 +-- src/librustc_typeck/check/mod.rs | 4 +- src/librustc_typeck/check/wfcheck.rs | 2 +- .../associated-types-overridden-binding.rs | 4 +- ...associated-types-overridden-binding.stderr | 13 ++- .../associated-types-unconstrained.rs | 2 +- .../associated-types-unconstrained.stderr | 2 +- src/test/ui/error-codes/E0283.stderr | 2 +- src/test/ui/error-codes/E0401.rs | 2 +- src/test/ui/error-codes/E0401.stderr | 11 +- src/test/ui/error-codes/E0661.rs | 2 +- src/test/ui/error-codes/E0661.stderr | 9 +- src/test/ui/impl-trait/where-allowed.rs | 6 +- src/test/ui/impl-trait/where-allowed.stderr | 100 ++++++++++-------- src/test/ui/issues/issue-12028.rs | 2 +- src/test/ui/issues/issue-12028.stderr | 2 +- src/test/ui/issues/issue-21974.rs | 2 +- src/test/ui/issues/issue-21974.stderr | 2 +- src/test/ui/issues/issue-24424.rs | 2 +- src/test/ui/issues/issue-24424.stderr | 2 +- src/test/ui/issues/issue-29147.stderr | 2 +- src/test/ui/issues/issue-54954.rs | 4 +- src/test/ui/issues/issue-54954.stderr | 25 ++++- ...method-ambig-one-trait-unknown-int-type.rs | 2 +- src/test/ui/parser/raw/raw-literal-self.rs | 2 +- .../ui/parser/raw/raw-literal-self.stderr | 2 +- .../ui/parser/raw/raw-literal-underscore.rs | 2 +- .../parser/raw/raw-literal-underscore.stderr | 2 +- .../pattern/rest-pat-semantic-disallowed.rs | 1 + .../rest-pat-semantic-disallowed.stderr | 37 ++++--- src/test/ui/question-mark-type-infer.rs | 2 +- src/test/ui/question-mark-type-infer.stderr | 2 +- .../proc-macro-cannot-be-used.rs | 2 +- .../proc-macro-cannot-be-used.stderr | 4 +- .../trait-static-method-generic-inference.rs | 2 +- ...ait-static-method-generic-inference.stderr | 2 +- src/test/ui/type/type-annotation-needed.rs | 2 +- .../ui/type/type-annotation-needed.stderr | 2 +- src/test/ui/type/type-check/issue-40294.rs | 2 +- .../ui/type/type-check/issue-40294.stderr | 2 +- src/test/ui/type/type-path-err-node-types.rs | 2 +- .../ui/type/type-path-err-node-types.stderr | 12 ++- 50 files changed, 256 insertions(+), 160 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index f6b872623d789..1e05018007a8d 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2184,9 +2184,7 @@ impl<'a> LoweringContext<'a> { match decl.output { FunctionRetTy::Ty(ref ty) => match in_band_ty_params { Some((def_id, _)) if impl_trait_return_allow => { - hir::Return(self.lower_ty(ty, - ImplTraitContext::OpaqueTy(Some(def_id)) - )) + hir::Return(self.lower_ty(ty, ImplTraitContext::OpaqueTy(Some(def_id)))) } _ => { hir::Return(self.lower_ty(ty, ImplTraitContext::disallowed())) diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs index c9fd3392a962d..129cfc8bcb23f 100644 --- a/src/librustc/infer/opaque_types/mod.rs +++ b/src/librustc/infer/opaque_types/mod.rs @@ -988,7 +988,9 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { value.fold_with(&mut BottomUpFolder { tcx, ty_op: |ty| { - if let ty::Opaque(def_id, substs) = ty.sty { + if ty.references_error() { + return tcx.types.err; + } else if let ty::Opaque(def_id, substs) = ty.sty { // Check that this is `impl Trait` type is // declared by `parent_def_id` -- i.e., one whose // value we are inferring. At present, this is @@ -1155,6 +1157,15 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { ); debug!("instantiate_opaque_types: ty_var={:?}", ty_var); + for predicate in &bounds.predicates { + if let ty::Predicate::Projection(projection) = &predicate { + if projection.skip_binder().ty.references_error() { + // No point on adding these obligations since there's a type error involved. + return ty_var; + } + } + } + self.obligations.reserve(bounds.predicates.len()); for predicate in bounds.predicates { // Change the predicate to refer to the type variable, diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index aff866fa76d5f..08fea75739978 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -1432,8 +1432,11 @@ impl<'tcx> TyCtxt<'tcx> { } impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>, - body_id: Option) { + fn maybe_report_ambiguity( + &self, + obligation: &PredicateObligation<'tcx>, + body_id: Option, + ) { // Unable to successfully determine, probably means // insufficient type information, but could mean // ambiguous impls. The latter *ought* to be a @@ -1442,9 +1445,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let predicate = self.resolve_vars_if_possible(&obligation.predicate); let span = obligation.cause.span; - debug!("maybe_report_ambiguity(predicate={:?}, obligation={:?})", - predicate, - obligation); + debug!( + "maybe_report_ambiguity(predicate={:?}, obligation={:?} body_id={:?}, code={:?})", + predicate, + obligation, + body_id, + obligation.cause.code, + ); // Ambiguity errors are often caused as fallout from earlier // errors. So just ignore them if this infcx is tainted. @@ -1456,6 +1463,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ty::Predicate::Trait(ref data) => { let trait_ref = data.to_poly_trait_ref(); let self_ty = trait_ref.self_ty(); + debug!("self_ty {:?} {:?} trait_ref {:?}", self_ty, self_ty.sty, trait_ref); + if predicate.references_error() { return; } @@ -1480,24 +1489,25 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // be ignoring the fact that we don't KNOW the type works // out. Though even that would probably be harmless, given that // we're only talking about builtin traits, which are known to be - // inhabited. But in any case I just threw in this check for - // has_errors() to be sure that compilation isn't happening - // anyway. In that case, why inundate the user. - if !self.tcx.sess.has_errors() { - if - self.tcx.lang_items().sized_trait() - .map_or(false, |sized_id| sized_id == trait_ref.def_id()) - { - self.need_type_info_err(body_id, span, self_ty).emit(); - } else { - let mut err = struct_span_err!(self.tcx.sess, - span, E0283, - "type annotations required: \ - cannot resolve `{}`", - predicate); - self.note_obligation_cause(&mut err, obligation); - err.emit(); - } + // inhabited. We used to check for `self.tcx.sess.has_errors()` to + // avoid inundating the user with unnecessary errors, but we now + // check upstream for type errors and dont add the obligations to + // begin with in those cases. + if + self.tcx.lang_items().sized_trait() + .map_or(false, |sized_id| sized_id == trait_ref.def_id()) + { + self.need_type_info_err(body_id, span, self_ty).emit(); + } else { + let mut err = struct_span_err!( + self.tcx.sess, + span, + E0283, + "type annotations needed: cannot resolve `{}`", + predicate, + ); + self.note_obligation_cause(&mut err, obligation); + err.emit(); } } @@ -1524,11 +1534,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { _ => { if !self.tcx.sess.has_errors() { - let mut err = struct_span_err!(self.tcx.sess, - obligation.cause.span, E0284, - "type annotations required: \ - cannot resolve `{}`", - predicate); + let mut err = struct_span_err!( + self.tcx.sess, + obligation.cause.span, + E0284, + "type annotations needed: cannot resolve `{}`", + predicate, + ); self.note_obligation_cause(&mut err, obligation); err.emit(); } @@ -1766,7 +1778,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { but not on the corresponding trait method", predicate)); } - ObligationCauseCode::ReturnType(_) | + ObligationCauseCode::ReturnType | + ObligationCauseCode::ReturnValue(_) | ObligationCauseCode::BlockTailExpression(_) => (), ObligationCauseCode::TrivialBound => { err.help("see issue #48214"); diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 1123422ad6008..accbbe3643ea1 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -212,14 +212,14 @@ pub enum ObligationCauseCode<'tcx> { /// Constant expressions must be sized. ConstSized, - /// static items must have `Sync` type + /// Static items must have `Sync` type SharedStatic, BuiltinDerivedObligation(DerivedObligationCause<'tcx>), ImplDerivedObligation(DerivedObligationCause<'tcx>), - /// error derived when matching traits/impls; see ObligationCause for more details + /// Error derived when matching traits/impls; see ObligationCause for more details CompareImplMethodObligation { item_name: ast::Name, impl_item_def_id: DefId, @@ -248,17 +248,20 @@ pub enum ObligationCauseCode<'tcx> { /// `start` has wrong type StartFunctionType, - /// intrinsic has wrong type + /// Intrinsic has wrong type IntrinsicType, - /// method receiver + /// Method receiver MethodReceiver, /// `return` with no expression ReturnNoExpression, /// `return` with an expression - ReturnType(hir::HirId), + ReturnValue(hir::HirId), + + /// Return type of this function + ReturnType, /// Block implicit return BlockTailExpression(hir::HirId), diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index a54bc05f16961..386a5677f5f17 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -214,7 +214,7 @@ pub struct SelectionCache<'tcx> { /// of type variables - it just means the obligation isn't sufficiently /// elaborated. In that case we report an ambiguity, and the caller can /// try again after more type information has been gathered or report a -/// "type annotations required" error. +/// "type annotations needed" error. /// /// However, with type parameters, this can be a real problem - type /// parameters don't unify with regular types, but they *can* unify diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 68c97226f89cf..c0d8230999dd8 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -485,7 +485,8 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { super::TupleInitializerSized => Some(super::TupleInitializerSized), super::StructInitializerSized => Some(super::StructInitializerSized), super::VariableType(id) => Some(super::VariableType(id)), - super::ReturnType(id) => Some(super::ReturnType(id)), + super::ReturnValue(id) => Some(super::ReturnValue(id)), + super::ReturnType => Some(super::ReturnType), super::SizedArgumentType => Some(super::SizedArgumentType), super::SizedReturnType => Some(super::SizedReturnType), super::SizedYieldType => Some(super::SizedYieldType), diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 8bb9648e031ef..525b551b3f2d3 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -438,7 +438,7 @@ bitflags! { /// `true` if there are "names" of types and regions and so forth /// that are local to a particular fn - const HAS_FREE_LOCAL_NAMES = 1 << 9; + const HAS_FREE_LOCAL_NAMES = 1 << 9; /// Present if the type belongs in a local type context. /// Only set for Infer other than Fresh. @@ -446,11 +446,11 @@ bitflags! { /// Does this have any `ReLateBound` regions? Used to check /// if a global bound is safe to evaluate. - const HAS_RE_LATE_BOUND = 1 << 11; + const HAS_RE_LATE_BOUND = 1 << 11; const HAS_TY_PLACEHOLDER = 1 << 12; - const HAS_CT_INFER = 1 << 13; + const HAS_CT_INFER = 1 << 13; const HAS_CT_PLACEHOLDER = 1 << 14; const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits | diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index d98e1f3e1283f..dc536329251ca 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -1253,7 +1253,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { expression.map(|expr| (expr, blk_id)), ); } - ObligationCauseCode::ReturnType(id) => { + ObligationCauseCode::ReturnValue(id) => { db = self.report_return_mismatched_types( cause, expected, found, err, fcx, id, None); } diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index e34a2c6f61c24..550b0f81d2103 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -498,7 +498,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr.span, infer::LateBoundRegionConversionTime::FnCall, &fn_sig.output()).0; - self.require_type_is_sized_deferred(output, expr.span, traits::SizedReturnType); + if !fn_sig.output().references_error() { + self.require_type_is_sized_deferred(output, expr.span, traits::SizedReturnType); + } } // We always require that the type provided as the value for @@ -664,12 +666,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ret_ty = ret_coercion.borrow().expected_ty(); let return_expr_ty = self.check_expr_with_hint(return_expr, ret_ty.clone()); - ret_coercion.borrow_mut() - .coerce(self, - &self.cause(return_expr.span, - ObligationCauseCode::ReturnType(return_expr.hir_id)), - return_expr, - return_expr_ty); + ret_coercion.borrow_mut().coerce( + self, + &self.cause(return_expr.span, ObligationCauseCode::ReturnValue(return_expr.hir_id)), + return_expr, + return_expr_ty, + ); } /// Type check assignment expression `expr` of form `lhs = rhs`. diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 6c8c5ae512358..b07579327472f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1097,7 +1097,9 @@ fn check_fn<'a, 'tcx>( *fcx.ps.borrow_mut() = UnsafetyState::function(fn_sig.unsafety, fn_id); let declared_ret_ty = fn_sig.output(); - fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); + if !declared_ret_ty.references_error() { + fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); + } let revealed_ret_ty = fcx.instantiate_opaque_types_from_value( fn_id, &declared_ret_ty, diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index b0e886a2aa2eb..46b3a3f658927 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -596,7 +596,7 @@ fn check_fn_or_method<'fcx, 'tcx>( } implied_bounds.extend(sig.inputs()); - fcx.register_wf_obligation(sig.output(), span, ObligationCauseCode::MiscObligation); + fcx.register_wf_obligation(sig.output(), span, ObligationCauseCode::ReturnType); // FIXME(#25759) return types should not be implied bounds implied_bounds.push(sig.output()); diff --git a/src/test/ui/associated-types/associated-types-overridden-binding.rs b/src/test/ui/associated-types/associated-types-overridden-binding.rs index fa1889389fd5c..9a64a06c31bad 100644 --- a/src/test/ui/associated-types/associated-types-overridden-binding.rs +++ b/src/test/ui/associated-types/associated-types-overridden-binding.rs @@ -1,10 +1,10 @@ #![feature(trait_alias)] trait Foo: Iterator {} -trait Bar: Foo {} //~ ERROR type annotations required +trait Bar: Foo {} //~ ERROR type annotations needed trait I32Iterator = Iterator; -trait U32Iterator = I32Iterator; +trait U32Iterator = I32Iterator; //~ ERROR type annotations needed fn main() { let _: &dyn I32Iterator; diff --git a/src/test/ui/associated-types/associated-types-overridden-binding.stderr b/src/test/ui/associated-types/associated-types-overridden-binding.stderr index a7238541cd96e..5ef1b23cbcd21 100644 --- a/src/test/ui/associated-types/associated-types-overridden-binding.stderr +++ b/src/test/ui/associated-types/associated-types-overridden-binding.stderr @@ -1,4 +1,4 @@ -error[E0284]: type annotations required: cannot resolve `::Item == i32` +error[E0284]: type annotations needed: cannot resolve `::Item == i32` --> $DIR/associated-types-overridden-binding.rs:4:1 | LL | trait Foo: Iterator {} @@ -6,6 +6,13 @@ LL | trait Foo: Iterator {} LL | trait Bar: Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error[E0282]: type annotations needed + --> $DIR/associated-types-overridden-binding.rs:7:1 + | +LL | trait U32Iterator = I32Iterator; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0284`. +Some errors have detailed explanations: E0282, E0284. +For more information about an error, try `rustc --explain E0282`. diff --git a/src/test/ui/associated-types/associated-types-unconstrained.rs b/src/test/ui/associated-types/associated-types-unconstrained.rs index 99424836ece2f..b97d4af184f92 100644 --- a/src/test/ui/associated-types/associated-types-unconstrained.rs +++ b/src/test/ui/associated-types/associated-types-unconstrained.rs @@ -12,5 +12,5 @@ impl Foo for isize { pub fn main() { let x: isize = Foo::bar(); - //~^ ERROR type annotations required + //~^ ERROR type annotations needed } diff --git a/src/test/ui/associated-types/associated-types-unconstrained.stderr b/src/test/ui/associated-types/associated-types-unconstrained.stderr index da14a69ae306a..4e9e54d368805 100644 --- a/src/test/ui/associated-types/associated-types-unconstrained.stderr +++ b/src/test/ui/associated-types/associated-types-unconstrained.stderr @@ -1,4 +1,4 @@ -error[E0284]: type annotations required: cannot resolve `<_ as Foo>::A == _` +error[E0284]: type annotations needed: cannot resolve `<_ as Foo>::A == _` --> $DIR/associated-types-unconstrained.rs:14:20 | LL | let x: isize = Foo::bar(); diff --git a/src/test/ui/error-codes/E0283.stderr b/src/test/ui/error-codes/E0283.stderr index 1d99f99c62383..aba649d83ec01 100644 --- a/src/test/ui/error-codes/E0283.stderr +++ b/src/test/ui/error-codes/E0283.stderr @@ -1,4 +1,4 @@ -error[E0283]: type annotations required: cannot resolve `_: Generator` +error[E0283]: type annotations needed: cannot resolve `_: Generator` --> $DIR/E0283.rs:18:21 | LL | fn create() -> u32; diff --git a/src/test/ui/error-codes/E0401.rs b/src/test/ui/error-codes/E0401.rs index a120198b7284d..c30e5f4718871 100644 --- a/src/test/ui/error-codes/E0401.rs +++ b/src/test/ui/error-codes/E0401.rs @@ -8,7 +8,7 @@ fn foo(x: T) { W: Fn()> (y: T) { //~ ERROR E0401 } - bfnr(x); + bfnr(x); //~ ERROR type annotations needed } diff --git a/src/test/ui/error-codes/E0401.stderr b/src/test/ui/error-codes/E0401.stderr index 1d9dfe46722ec..485b76a09a3c4 100644 --- a/src/test/ui/error-codes/E0401.stderr +++ b/src/test/ui/error-codes/E0401.stderr @@ -32,6 +32,13 @@ LL | fn helper(sel: &Self) -> u8 { | use of generic parameter from outer function | use a type here instead -error: aborting due to 3 previous errors +error[E0282]: type annotations needed + --> $DIR/E0401.rs:11:5 + | +LL | bfnr(x); + | ^^^^ cannot infer type for `U` + +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0401`. +Some errors have detailed explanations: E0282, E0401. +For more information about an error, try `rustc --explain E0282`. diff --git a/src/test/ui/error-codes/E0661.rs b/src/test/ui/error-codes/E0661.rs index 2440e3a446eb4..5ac0c415ae1b2 100644 --- a/src/test/ui/error-codes/E0661.rs +++ b/src/test/ui/error-codes/E0661.rs @@ -3,7 +3,7 @@ #![feature(asm)] fn main() { - let a; + let a; //~ ERROR type annotations needed asm!("nop" : "r"(a)); //~^ ERROR E0661 } diff --git a/src/test/ui/error-codes/E0661.stderr b/src/test/ui/error-codes/E0661.stderr index 58f7e7fa0f919..3537e0bc3a4c6 100644 --- a/src/test/ui/error-codes/E0661.stderr +++ b/src/test/ui/error-codes/E0661.stderr @@ -4,5 +4,12 @@ error[E0661]: output operand constraint lacks '=' or '+' LL | asm!("nop" : "r"(a)); | ^^^ -error: aborting due to previous error +error[E0282]: type annotations needed + --> $DIR/E0661.rs:6:9 + | +LL | let a; + | ^ consider giving `a` a type + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/impl-trait/where-allowed.rs b/src/test/ui/impl-trait/where-allowed.rs index 9eac6b714de37..65c4b78bf6a40 100644 --- a/src/test/ui/impl-trait/where-allowed.rs +++ b/src/test/ui/impl-trait/where-allowed.rs @@ -11,8 +11,9 @@ fn in_return() -> impl Debug { panic!() } // Allowed fn in_adt_in_parameters(_: Vec) { panic!() } -// Allowed +// Disallowed fn in_adt_in_return() -> Vec { panic!() } +//~^ ERROR type annotations needed // Disallowed fn in_fn_parameter_in_parameters(_: fn(impl Debug)) { panic!() } @@ -58,7 +59,8 @@ fn in_impl_Fn_return_in_parameters(_: &impl Fn() -> impl Debug) { panic!() } // Disallowed fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types -//~^^ ERROR nested `impl Trait` is not allowed +//~| ERROR nested `impl Trait` is not allowed +//~| ERROR type annotations needed // Disallowed fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() } diff --git a/src/test/ui/impl-trait/where-allowed.stderr b/src/test/ui/impl-trait/where-allowed.stderr index 1332fff84f50a..dfb6e6524d9a5 100644 --- a/src/test/ui/impl-trait/where-allowed.stderr +++ b/src/test/ui/impl-trait/where-allowed.stderr @@ -1,5 +1,5 @@ error[E0666]: nested `impl Trait` is not allowed - --> $DIR/where-allowed.rs:50:51 + --> $DIR/where-allowed.rs:51:51 | LL | fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() } | --------^^^^^^^^^^- @@ -8,7 +8,7 @@ LL | fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() } | outer `impl Trait` error[E0666]: nested `impl Trait` is not allowed - --> $DIR/where-allowed.rs:59:57 + --> $DIR/where-allowed.rs:60:57 | LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } | --------^^^^^^^^^^- @@ -17,7 +17,7 @@ LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic | outer `impl Trait` error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/where-allowed.rs:122:5 + --> $DIR/where-allowed.rs:124:5 | LL | type Out = impl Debug; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -26,7 +26,7 @@ LL | type Out = impl Debug; = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/where-allowed.rs:158:1 + --> $DIR/where-allowed.rs:160:1 | LL | type InTypeAlias = impl Debug; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -35,205 +35,205 @@ LL | type InTypeAlias = impl Debug; = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:18:40 + --> $DIR/where-allowed.rs:19:40 | LL | fn in_fn_parameter_in_parameters(_: fn(impl Debug)) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:22:42 + --> $DIR/where-allowed.rs:23:42 | LL | fn in_fn_return_in_parameters(_: fn() -> impl Debug) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:26:38 + --> $DIR/where-allowed.rs:27:38 | LL | fn in_fn_parameter_in_return() -> fn(impl Debug) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:30:40 + --> $DIR/where-allowed.rs:31:40 | LL | fn in_fn_return_in_return() -> fn() -> impl Debug { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:34:49 + --> $DIR/where-allowed.rs:35:49 | LL | fn in_dyn_Fn_parameter_in_parameters(_: &dyn Fn(impl Debug)) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:38:51 + --> $DIR/where-allowed.rs:39:51 | LL | fn in_dyn_Fn_return_in_parameters(_: &dyn Fn() -> impl Debug) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:42:55 + --> $DIR/where-allowed.rs:43:55 | LL | fn in_dyn_Fn_parameter_in_return() -> &'static dyn Fn(impl Debug) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:46:57 + --> $DIR/where-allowed.rs:47:57 | LL | fn in_dyn_Fn_return_in_return() -> &'static dyn Fn() -> impl Debug { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:50:51 + --> $DIR/where-allowed.rs:51:51 | LL | fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:55:53 + --> $DIR/where-allowed.rs:56:53 | LL | fn in_impl_Fn_return_in_parameters(_: &impl Fn() -> impl Debug) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:59:57 + --> $DIR/where-allowed.rs:60:57 | LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:64:59 + --> $DIR/where-allowed.rs:66:59 | LL | fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:68:38 + --> $DIR/where-allowed.rs:70:38 | LL | fn in_Fn_parameter_in_generics (_: F) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:72:40 + --> $DIR/where-allowed.rs:74:40 | LL | fn in_Fn_return_in_generics impl Debug> (_: F) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:85:32 + --> $DIR/where-allowed.rs:87:32 | LL | struct InBraceStructField { x: impl Debug } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:89:41 + --> $DIR/where-allowed.rs:91:41 | LL | struct InAdtInBraceStructField { x: Vec } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:93:27 + --> $DIR/where-allowed.rs:95:27 | LL | struct InTupleStructField(impl Debug); | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:98:25 + --> $DIR/where-allowed.rs:100:25 | LL | InBraceVariant { x: impl Debug }, | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:100:20 + --> $DIR/where-allowed.rs:102:20 | LL | InTupleVariant(impl Debug), | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:111:23 + --> $DIR/where-allowed.rs:113:23 | LL | fn in_return() -> impl Debug; | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:129:34 + --> $DIR/where-allowed.rs:131:34 | LL | fn in_trait_impl_return() -> impl Debug { () } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:142:33 + --> $DIR/where-allowed.rs:144:33 | LL | fn in_foreign_parameters(_: impl Debug); | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:145:31 + --> $DIR/where-allowed.rs:147:31 | LL | fn in_foreign_return() -> impl Debug; | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:162:39 + --> $DIR/where-allowed.rs:164:39 | LL | type InReturnInTypeAlias = fn() -> impl Debug; | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:166:16 + --> $DIR/where-allowed.rs:168:16 | LL | impl PartialEq for () { | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:171:24 + --> $DIR/where-allowed.rs:173:24 | LL | impl PartialEq<()> for impl Debug { | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:176:6 + --> $DIR/where-allowed.rs:178:6 | LL | impl impl Debug { | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:182:24 + --> $DIR/where-allowed.rs:184:24 | LL | impl InInherentImplAdt { | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:188:11 + --> $DIR/where-allowed.rs:190:11 | LL | where impl Debug: Debug | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:195:15 + --> $DIR/where-allowed.rs:197:15 | LL | where Vec: Debug | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:202:24 + --> $DIR/where-allowed.rs:204:24 | LL | where T: PartialEq | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:209:17 + --> $DIR/where-allowed.rs:211:17 | LL | where T: Fn(impl Debug) | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:216:22 + --> $DIR/where-allowed.rs:218:22 | LL | where T: Fn() -> impl Debug | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:222:29 + --> $DIR/where-allowed.rs:224:29 | LL | let _in_local_variable: impl Fn() = || {}; | ^^^^^^^^^ @@ -241,24 +241,36 @@ LL | let _in_local_variable: impl Fn() = || {}; = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:224:46 + --> $DIR/where-allowed.rs:226:46 | LL | let _in_return_in_local_variable = || -> impl Fn() { || {} }; | ^^^^^^^^^ +error[E0282]: type annotations needed + --> $DIR/where-allowed.rs:15:30 + | +LL | fn in_adt_in_return() -> Vec { panic!() } + | ^^^^^^^^^^ cannot infer type + +error[E0282]: type annotations needed + --> $DIR/where-allowed.rs:60:49 + | +LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } + | ^^^^^^^^^^^^^^^^^^^ cannot infer type + error: could not find defining uses - --> $DIR/where-allowed.rs:158:1 + --> $DIR/where-allowed.rs:160:1 | LL | type InTypeAlias = impl Debug; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: could not find defining uses - --> $DIR/where-allowed.rs:122:5 + --> $DIR/where-allowed.rs:124:5 | LL | type Out = impl Debug; | ^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 41 previous errors +error: aborting due to 43 previous errors -Some errors have detailed explanations: E0562, E0658. -For more information about an error, try `rustc --explain E0562`. +Some errors have detailed explanations: E0282, E0562, E0658. +For more information about an error, try `rustc --explain E0282`. diff --git a/src/test/ui/issues/issue-12028.rs b/src/test/ui/issues/issue-12028.rs index 7c2b0d69c8b25..7503766ff2084 100644 --- a/src/test/ui/issues/issue-12028.rs +++ b/src/test/ui/issues/issue-12028.rs @@ -24,7 +24,7 @@ trait StreamHash: Hash { impl Hash for u8 { fn hash2(&self, hasher: &H) -> u64 { let mut stream = hasher.stream(); - self.input_stream(&mut stream); //~ ERROR type annotations required + self.input_stream(&mut stream); //~ ERROR type annotations needed Stream::result(&stream) } } diff --git a/src/test/ui/issues/issue-12028.stderr b/src/test/ui/issues/issue-12028.stderr index 24aa88c3fa379..ff92d01a69ed2 100644 --- a/src/test/ui/issues/issue-12028.stderr +++ b/src/test/ui/issues/issue-12028.stderr @@ -1,4 +1,4 @@ -error[E0284]: type annotations required: cannot resolve `<_ as StreamHasher>::S == ::S` +error[E0284]: type annotations needed: cannot resolve `<_ as StreamHasher>::S == ::S` --> $DIR/issue-12028.rs:27:14 | LL | self.input_stream(&mut stream); diff --git a/src/test/ui/issues/issue-21974.rs b/src/test/ui/issues/issue-21974.rs index f49eb230b4083..0cbe38d6ec0b6 100644 --- a/src/test/ui/issues/issue-21974.rs +++ b/src/test/ui/issues/issue-21974.rs @@ -7,7 +7,7 @@ trait Foo { fn foo(self); } -fn foo<'a,'b,T>(x: &'a T, y: &'b T) //~ ERROR type annotations required +fn foo<'a,'b,T>(x: &'a T, y: &'b T) //~ ERROR type annotations needed where &'a T : Foo, &'b T : Foo { diff --git a/src/test/ui/issues/issue-21974.stderr b/src/test/ui/issues/issue-21974.stderr index a6cce7846e81d..7ceb2bd23f6cd 100644 --- a/src/test/ui/issues/issue-21974.stderr +++ b/src/test/ui/issues/issue-21974.stderr @@ -1,4 +1,4 @@ -error[E0283]: type annotations required: cannot resolve `&'a T: Foo` +error[E0283]: type annotations needed: cannot resolve `&'a T: Foo` --> $DIR/issue-21974.rs:10:1 | LL | trait Foo { diff --git a/src/test/ui/issues/issue-24424.rs b/src/test/ui/issues/issue-24424.rs index 8b8c5bc23e48b..9b74cd1230e8a 100644 --- a/src/test/ui/issues/issue-24424.rs +++ b/src/test/ui/issues/issue-24424.rs @@ -2,6 +2,6 @@ trait Trait1<'l0, T0> {} trait Trait0<'l0> {} impl <'l0, 'l1, T0> Trait1<'l0, T0> for bool where T0 : Trait0<'l0>, T0 : Trait0<'l1> {} -//~^ ERROR type annotations required: cannot resolve `T0: Trait0<'l0>` +//~^ ERROR type annotations needed: cannot resolve `T0: Trait0<'l0>` fn main() {} diff --git a/src/test/ui/issues/issue-24424.stderr b/src/test/ui/issues/issue-24424.stderr index 7ff019a30a864..8c539f7cedd19 100644 --- a/src/test/ui/issues/issue-24424.stderr +++ b/src/test/ui/issues/issue-24424.stderr @@ -1,4 +1,4 @@ -error[E0283]: type annotations required: cannot resolve `T0: Trait0<'l0>` +error[E0283]: type annotations needed: cannot resolve `T0: Trait0<'l0>` --> $DIR/issue-24424.rs:4:1 | LL | trait Trait0<'l0> {} diff --git a/src/test/ui/issues/issue-29147.stderr b/src/test/ui/issues/issue-29147.stderr index 0dc9b0c9e10cd..c9dd92fca7dc8 100644 --- a/src/test/ui/issues/issue-29147.stderr +++ b/src/test/ui/issues/issue-29147.stderr @@ -1,4 +1,4 @@ -error[E0283]: type annotations required: cannot resolve `S5<_>: Foo` +error[E0283]: type annotations needed: cannot resolve `S5<_>: Foo` --> $DIR/issue-29147.rs:21:13 | LL | trait Foo { fn xxx(&self); } diff --git a/src/test/ui/issues/issue-54954.rs b/src/test/ui/issues/issue-54954.rs index 40045bc758cff..9e9f92ed9ace5 100644 --- a/src/test/ui/issues/issue-54954.rs +++ b/src/test/ui/issues/issue-54954.rs @@ -1,7 +1,7 @@ #![feature(const_fn)] const ARR_LEN: usize = Tt::const_val::<[i8; 123]>(); -//~^ ERROR constant contains unimplemented expression type +//~^ ERROR type annotations needed trait Tt { const fn const_val() -> usize { @@ -11,6 +11,8 @@ trait Tt { } fn f(z: [f32; ARR_LEN]) -> [f32; ARR_LEN] { + //~^ ERROR evaluation of constant value failed + //~| ERROR evaluation of constant value failed z } diff --git a/src/test/ui/issues/issue-54954.stderr b/src/test/ui/issues/issue-54954.stderr index 29edb506c4b1c..82315c125798f 100644 --- a/src/test/ui/issues/issue-54954.stderr +++ b/src/test/ui/issues/issue-54954.stderr @@ -4,13 +4,28 @@ error[E0379]: trait fns cannot be declared const LL | const fn const_val() -> usize { | ^^^^^ trait fns cannot be const -error[E0019]: constant contains unimplemented expression type +error[E0283]: type annotations needed: cannot resolve `_: Tt` --> $DIR/issue-54954.rs:3:24 | LL | const ARR_LEN: usize = Tt::const_val::<[i8; 123]>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | const fn const_val() -> usize { + | --------------------------------------- required by `Tt::const_val` + +error[E0080]: evaluation of constant value failed + --> $DIR/issue-54954.rs:13:15 + | +LL | fn f(z: [f32; ARR_LEN]) -> [f32; ARR_LEN] { + | ^^^^^^^ referenced constant has errors + +error[E0080]: evaluation of constant value failed + --> $DIR/issue-54954.rs:13:34 + | +LL | fn f(z: [f32; ARR_LEN]) -> [f32; ARR_LEN] { + | ^^^^^^^ referenced constant has errors -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0019, E0379. -For more information about an error, try `rustc --explain E0019`. +Some errors have detailed explanations: E0080, E0283, E0379. +For more information about an error, try `rustc --explain E0080`. diff --git a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.rs b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.rs index e33f23c64dbe1..49fe7d1324ca8 100644 --- a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.rs +++ b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.rs @@ -15,7 +15,7 @@ impl Foo for Vec { } // This is very hokey: we have heuristics to suppress messages about -// type annotations required. But placing these two bits of code into +// type annotations needed. But placing these two bits of code into // distinct functions, in this order, causes us to print out both // errors I'd like to see. diff --git a/src/test/ui/parser/raw/raw-literal-self.rs b/src/test/ui/parser/raw/raw-literal-self.rs index 123a11b6f8543..a0c9e24c235d6 100644 --- a/src/test/ui/parser/raw/raw-literal-self.rs +++ b/src/test/ui/parser/raw/raw-literal-self.rs @@ -1,4 +1,4 @@ fn main() { - let r#self; + let r#self: (); //~^ ERROR `self` cannot be a raw identifier } diff --git a/src/test/ui/parser/raw/raw-literal-self.stderr b/src/test/ui/parser/raw/raw-literal-self.stderr index 9a330fcdf2aae..2a40dfe200cde 100644 --- a/src/test/ui/parser/raw/raw-literal-self.stderr +++ b/src/test/ui/parser/raw/raw-literal-self.stderr @@ -1,7 +1,7 @@ error: `self` cannot be a raw identifier --> $DIR/raw-literal-self.rs:2:9 | -LL | let r#self; +LL | let r#self: (); | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/raw/raw-literal-underscore.rs b/src/test/ui/parser/raw/raw-literal-underscore.rs index 6d15f1e7f0afd..a9d9e13a9d9ec 100644 --- a/src/test/ui/parser/raw/raw-literal-underscore.rs +++ b/src/test/ui/parser/raw/raw-literal-underscore.rs @@ -1,4 +1,4 @@ fn main() { - let r#_; + let r#_: (); //~^ ERROR `_` cannot be a raw identifier } diff --git a/src/test/ui/parser/raw/raw-literal-underscore.stderr b/src/test/ui/parser/raw/raw-literal-underscore.stderr index d96b14f55a39b..d7a364d8579ef 100644 --- a/src/test/ui/parser/raw/raw-literal-underscore.stderr +++ b/src/test/ui/parser/raw/raw-literal-underscore.stderr @@ -1,7 +1,7 @@ error: `_` cannot be a raw identifier --> $DIR/raw-literal-underscore.rs:2:9 | -LL | let r#_; +LL | let r#_: (); | ^^^ error: aborting due to previous error diff --git a/src/test/ui/pattern/rest-pat-semantic-disallowed.rs b/src/test/ui/pattern/rest-pat-semantic-disallowed.rs index 36a45a3ccdc4b..31620216e82e1 100644 --- a/src/test/ui/pattern/rest-pat-semantic-disallowed.rs +++ b/src/test/ui/pattern/rest-pat-semantic-disallowed.rs @@ -31,6 +31,7 @@ fn rest_patterns() { // Ident patterns: let x @ ..; //~ ERROR `..` patterns are not allowed here + //~^ ERROR type annotations needed let ref x @ ..; //~ ERROR `..` patterns are not allowed here let ref mut x @ ..; //~ ERROR `..` patterns are not allowed here diff --git a/src/test/ui/pattern/rest-pat-semantic-disallowed.stderr b/src/test/ui/pattern/rest-pat-semantic-disallowed.stderr index 826f76b356cf1..be484e3a4d417 100644 --- a/src/test/ui/pattern/rest-pat-semantic-disallowed.stderr +++ b/src/test/ui/pattern/rest-pat-semantic-disallowed.stderr @@ -58,7 +58,7 @@ LL | let x @ ..; = note: only allowed in tuple, tuple struct, and slice patterns error: `..` patterns are not allowed here - --> $DIR/rest-pat-semantic-disallowed.rs:34:17 + --> $DIR/rest-pat-semantic-disallowed.rs:35:17 | LL | let ref x @ ..; | ^^ @@ -66,7 +66,7 @@ LL | let ref x @ ..; = note: only allowed in tuple, tuple struct, and slice patterns error: `..` patterns are not allowed here - --> $DIR/rest-pat-semantic-disallowed.rs:35:21 + --> $DIR/rest-pat-semantic-disallowed.rs:36:21 | LL | let ref mut x @ ..; | ^^ @@ -74,7 +74,7 @@ LL | let ref mut x @ ..; = note: only allowed in tuple, tuple struct, and slice patterns error: `..` can only be used once per tuple pattern - --> $DIR/rest-pat-semantic-disallowed.rs:42:9 + --> $DIR/rest-pat-semantic-disallowed.rs:43:9 | LL | .., | -- previously used here @@ -82,7 +82,7 @@ LL | .., | ^^ can only be used once per tuple pattern error: `..` can only be used once per tuple pattern - --> $DIR/rest-pat-semantic-disallowed.rs:43:9 + --> $DIR/rest-pat-semantic-disallowed.rs:44:9 | LL | .., | -- previously used here @@ -91,7 +91,7 @@ LL | .. | ^^ can only be used once per tuple pattern error: `..` can only be used once per tuple pattern - --> $DIR/rest-pat-semantic-disallowed.rs:48:9 + --> $DIR/rest-pat-semantic-disallowed.rs:49:9 | LL | .., | -- previously used here @@ -100,7 +100,7 @@ LL | .. | ^^ can only be used once per tuple pattern error: `..` can only be used once per tuple struct pattern - --> $DIR/rest-pat-semantic-disallowed.rs:58:9 + --> $DIR/rest-pat-semantic-disallowed.rs:59:9 | LL | .., | -- previously used here @@ -108,7 +108,7 @@ LL | .., | ^^ can only be used once per tuple struct pattern error: `..` can only be used once per tuple struct pattern - --> $DIR/rest-pat-semantic-disallowed.rs:59:9 + --> $DIR/rest-pat-semantic-disallowed.rs:60:9 | LL | .., | -- previously used here @@ -117,7 +117,7 @@ LL | .. | ^^ can only be used once per tuple struct pattern error: `..` can only be used once per tuple struct pattern - --> $DIR/rest-pat-semantic-disallowed.rs:64:9 + --> $DIR/rest-pat-semantic-disallowed.rs:65:9 | LL | .., | -- previously used here @@ -126,7 +126,7 @@ LL | .. | ^^ can only be used once per tuple struct pattern error: `..` can only be used once per slice pattern - --> $DIR/rest-pat-semantic-disallowed.rs:72:9 + --> $DIR/rest-pat-semantic-disallowed.rs:73:9 | LL | .., | -- previously used here @@ -134,7 +134,7 @@ LL | .., | ^^ can only be used once per slice pattern error: `..` can only be used once per slice pattern - --> $DIR/rest-pat-semantic-disallowed.rs:73:9 + --> $DIR/rest-pat-semantic-disallowed.rs:74:9 | LL | .., | -- previously used here @@ -143,7 +143,7 @@ LL | .. | ^^ can only be used once per slice pattern error: `..` can only be used once per slice pattern - --> $DIR/rest-pat-semantic-disallowed.rs:77:17 + --> $DIR/rest-pat-semantic-disallowed.rs:78:17 | LL | .., | -- previously used here @@ -151,7 +151,7 @@ LL | ref x @ .., | ^^ can only be used once per slice pattern error: `..` can only be used once per slice pattern - --> $DIR/rest-pat-semantic-disallowed.rs:78:21 + --> $DIR/rest-pat-semantic-disallowed.rs:79:21 | LL | .., | -- previously used here @@ -160,7 +160,7 @@ LL | ref mut y @ .., | ^^ can only be used once per slice pattern error: `..` patterns are not allowed here - --> $DIR/rest-pat-semantic-disallowed.rs:79:18 + --> $DIR/rest-pat-semantic-disallowed.rs:80:18 | LL | (ref z @ ..), | ^^ @@ -168,7 +168,7 @@ LL | (ref z @ ..), = note: only allowed in tuple, tuple struct, and slice patterns error: `..` can only be used once per slice pattern - --> $DIR/rest-pat-semantic-disallowed.rs:80:9 + --> $DIR/rest-pat-semantic-disallowed.rs:81:9 | LL | .., | -- previously used here @@ -184,5 +184,12 @@ LL | fn foo(..: u8) {} | = note: only allowed in tuple, tuple struct, and slice patterns -error: aborting due to 22 previous errors +error[E0282]: type annotations needed + --> $DIR/rest-pat-semantic-disallowed.rs:33:9 + | +LL | let x @ ..; + | ^^^^^^ consider giving this pattern a type + +error: aborting due to 23 previous errors +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/question-mark-type-infer.rs b/src/test/ui/question-mark-type-infer.rs index 2e7a342b95e17..95ee01a70cead 100644 --- a/src/test/ui/question-mark-type-infer.rs +++ b/src/test/ui/question-mark-type-infer.rs @@ -9,7 +9,7 @@ fn f(x: &i32) -> Result { fn g() -> Result, ()> { let l = [1, 2, 3, 4]; - l.iter().map(f).collect()? //~ ERROR type annotations required: cannot resolve + l.iter().map(f).collect()? //~ ERROR type annotations needed: cannot resolve } fn main() { diff --git a/src/test/ui/question-mark-type-infer.stderr b/src/test/ui/question-mark-type-infer.stderr index f62a540572c93..53a170e7d431c 100644 --- a/src/test/ui/question-mark-type-infer.stderr +++ b/src/test/ui/question-mark-type-infer.stderr @@ -1,4 +1,4 @@ -error[E0284]: type annotations required: cannot resolve `<_ as std::ops::Try>::Ok == _` +error[E0284]: type annotations needed: cannot resolve `<_ as std::ops::Try>::Ok == _` --> $DIR/question-mark-type-infer.rs:12:5 | LL | l.iter().map(f).collect()? diff --git a/src/test/ui/rfc-2565-param-attrs/proc-macro-cannot-be-used.rs b/src/test/ui/rfc-2565-param-attrs/proc-macro-cannot-be-used.rs index 9f4e2710dc420..e2680446f851a 100644 --- a/src/test/ui/rfc-2565-param-attrs/proc-macro-cannot-be-used.rs +++ b/src/test/ui/rfc-2565-param-attrs/proc-macro-cannot-be-used.rs @@ -20,7 +20,7 @@ type Alias = extern "C" fn(#[id] u8, #[id] ...); fn free(#[id] arg1: u8) { //~^ ERROR expected an inert attribute, found an attribute macro - let lam = |#[id] W(x), #[id] y| (); + let lam = |#[id] W(x), #[id] y: usize| (); //~^ ERROR expected an inert attribute, found an attribute macro //~| ERROR expected an inert attribute, found an attribute macro } diff --git a/src/test/ui/rfc-2565-param-attrs/proc-macro-cannot-be-used.stderr b/src/test/ui/rfc-2565-param-attrs/proc-macro-cannot-be-used.stderr index b4946fa74943f..4654dc1b496f2 100644 --- a/src/test/ui/rfc-2565-param-attrs/proc-macro-cannot-be-used.stderr +++ b/src/test/ui/rfc-2565-param-attrs/proc-macro-cannot-be-used.stderr @@ -37,13 +37,13 @@ LL | fn free(#[id] arg1: u8) { error: expected an inert attribute, found an attribute macro --> $DIR/proc-macro-cannot-be-used.rs:23:16 | -LL | let lam = |#[id] W(x), #[id] y| (); +LL | let lam = |#[id] W(x), #[id] y: usize| (); | ^^^^^ error: expected an inert attribute, found an attribute macro --> $DIR/proc-macro-cannot-be-used.rs:23:28 | -LL | let lam = |#[id] W(x), #[id] y| (); +LL | let lam = |#[id] W(x), #[id] y: usize| (); | ^^^^^ error: expected an inert attribute, found an attribute macro diff --git a/src/test/ui/traits/trait-static-method-generic-inference.rs b/src/test/ui/traits/trait-static-method-generic-inference.rs index c08bd5cb13566..759416d1901db 100644 --- a/src/test/ui/traits/trait-static-method-generic-inference.rs +++ b/src/test/ui/traits/trait-static-method-generic-inference.rs @@ -22,7 +22,7 @@ mod base { pub fn foo() { let _f: base::Foo = base::HasNew::new(); - //~^ ERROR type annotations required + //~^ ERROR type annotations needed } fn main() { } diff --git a/src/test/ui/traits/trait-static-method-generic-inference.stderr b/src/test/ui/traits/trait-static-method-generic-inference.stderr index a99536d31ef84..22931c5ba32e9 100644 --- a/src/test/ui/traits/trait-static-method-generic-inference.stderr +++ b/src/test/ui/traits/trait-static-method-generic-inference.stderr @@ -1,4 +1,4 @@ -error[E0283]: type annotations required: cannot resolve `_: base::HasNew` +error[E0283]: type annotations needed: cannot resolve `_: base::HasNew` --> $DIR/trait-static-method-generic-inference.rs:24:25 | LL | fn new() -> T; diff --git a/src/test/ui/type/type-annotation-needed.rs b/src/test/ui/type/type-annotation-needed.rs index ddf16f7699517..3b1521d5c028b 100644 --- a/src/test/ui/type/type-annotation-needed.rs +++ b/src/test/ui/type/type-annotation-needed.rs @@ -4,5 +4,5 @@ fn foo>(x: i32) {} fn main() { foo(42); - //~^ ERROR type annotations required + //~^ ERROR type annotations needed } diff --git a/src/test/ui/type/type-annotation-needed.stderr b/src/test/ui/type/type-annotation-needed.stderr index 01287b727d2f8..460bbe9dbc4f9 100644 --- a/src/test/ui/type/type-annotation-needed.stderr +++ b/src/test/ui/type/type-annotation-needed.stderr @@ -1,4 +1,4 @@ -error[E0283]: type annotations required: cannot resolve `_: std::convert::Into` +error[E0283]: type annotations needed: cannot resolve `_: std::convert::Into` --> $DIR/type-annotation-needed.rs:6:5 | LL | fn foo>(x: i32) {} diff --git a/src/test/ui/type/type-check/issue-40294.rs b/src/test/ui/type/type-check/issue-40294.rs index c73acdc467ee2..7e6429ccfbe30 100644 --- a/src/test/ui/type/type-check/issue-40294.rs +++ b/src/test/ui/type/type-check/issue-40294.rs @@ -2,7 +2,7 @@ trait Foo: Sized { fn foo(self); } -fn foo<'a,'b,T>(x: &'a T, y: &'b T) //~ ERROR type annotations required +fn foo<'a,'b,T>(x: &'a T, y: &'b T) //~ ERROR type annotations needed where &'a T : Foo, &'b T : Foo { diff --git a/src/test/ui/type/type-check/issue-40294.stderr b/src/test/ui/type/type-check/issue-40294.stderr index 732a81c8a244a..508783aaf2b0e 100644 --- a/src/test/ui/type/type-check/issue-40294.stderr +++ b/src/test/ui/type/type-check/issue-40294.stderr @@ -1,4 +1,4 @@ -error[E0283]: type annotations required: cannot resolve `&'a T: Foo` +error[E0283]: type annotations needed: cannot resolve `&'a T: Foo` --> $DIR/issue-40294.rs:5:1 | LL | trait Foo: Sized { diff --git a/src/test/ui/type/type-path-err-node-types.rs b/src/test/ui/type/type-path-err-node-types.rs index a2cc5070db482..15adfebb33400 100644 --- a/src/test/ui/type/type-path-err-node-types.rs +++ b/src/test/ui/type/type-path-err-node-types.rs @@ -20,7 +20,7 @@ fn method() { } fn closure() { - let _ = |a, b: _| -> _ { 0 }; // OK + let _ = |a, b: _| -> _ { 0 }; //~ ERROR type annotations needed } fn main() {} diff --git a/src/test/ui/type/type-path-err-node-types.stderr b/src/test/ui/type/type-path-err-node-types.stderr index ed744478f26f8..cd93525c76219 100644 --- a/src/test/ui/type/type-path-err-node-types.stderr +++ b/src/test/ui/type/type-path-err-node-types.stderr @@ -22,7 +22,13 @@ error[E0425]: cannot find value `nonexistent` in this scope LL | nonexistent.nonexistent::(); | ^^^^^^^^^^^ not found in this scope -error: aborting due to 4 previous errors +error[E0282]: type annotations needed + --> $DIR/type-path-err-node-types.rs:23:14 + | +LL | let _ = |a, b: _| -> _ { 0 }; + | ^ consider giving this closure parameter a type + +error: aborting due to 5 previous errors -Some errors have detailed explanations: E0412, E0425, E0433. -For more information about an error, try `rustc --explain E0412`. +Some errors have detailed explanations: E0282, E0412, E0425, E0433. +For more information about an error, try `rustc --explain E0282`. From affa038c293a1b2b38cc8d323a652c1c279b9391 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 24 Sep 2019 11:28:30 -0700 Subject: [PATCH 15/17] clean up, push silencing logic to more relevant places --- src/librustc_typeck/check/expr.rs | 4 +- src/librustc_typeck/check/mod.rs | 86 +++++++++++++++++-------------- 2 files changed, 49 insertions(+), 41 deletions(-) diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 550b0f81d2103..6b694bfc8da25 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -498,9 +498,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr.span, infer::LateBoundRegionConversionTime::FnCall, &fn_sig.output()).0; - if !fn_sig.output().references_error() { - self.require_type_is_sized_deferred(output, expr.span, traits::SizedReturnType); - } + self.require_type_is_sized_deferred(output, expr.span, traits::SizedReturnType); } // We always require that the type provided as the value for diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index b07579327472f..02f4f2a3744c6 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1097,9 +1097,7 @@ fn check_fn<'a, 'tcx>( *fcx.ps.borrow_mut() = UnsafetyState::function(fn_sig.unsafety, fn_id); let declared_ret_ty = fn_sig.output(); - if !declared_ret_ty.references_error() { - fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); - } + fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); let revealed_ret_ty = fcx.instantiate_opaque_types_from_value( fn_id, &declared_ret_ty, @@ -2700,30 +2698,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { traits::ObligationCause::new(span, self.body_id, code)); } - pub fn require_type_is_sized(&self, - ty: Ty<'tcx>, - span: Span, - code: traits::ObligationCauseCode<'tcx>) - { - let lang_item = self.tcx.require_lang_item(lang_items::SizedTraitLangItem, None); - self.require_type_meets(ty, span, code, lang_item); + pub fn require_type_is_sized( + &self, + ty: Ty<'tcx>, + span: Span, + code: traits::ObligationCauseCode<'tcx>, + ) { + if !ty.references_error() { + let lang_item = self.tcx.require_lang_item(lang_items::SizedTraitLangItem, None); + self.require_type_meets(ty, span, code, lang_item); + } } - pub fn require_type_is_sized_deferred(&self, - ty: Ty<'tcx>, - span: Span, - code: traits::ObligationCauseCode<'tcx>) - { - self.deferred_sized_obligations.borrow_mut().push((ty, span, code)); + pub fn require_type_is_sized_deferred( + &self, + ty: Ty<'tcx>, + span: Span, + code: traits::ObligationCauseCode<'tcx>, + ) { + if !ty.references_error() { + self.deferred_sized_obligations.borrow_mut().push((ty, span, code)); + } } - pub fn register_bound(&self, - ty: Ty<'tcx>, - def_id: DefId, - cause: traits::ObligationCause<'tcx>) - { - self.fulfillment_cx.borrow_mut() - .register_bound(self, self.param_env, ty, def_id, cause); + pub fn register_bound( + &self, + ty: Ty<'tcx>, + def_id: DefId, + cause: traits::ObligationCause<'tcx>, + ) { + if !ty.references_error() { + self.fulfillment_cx.borrow_mut() + .register_bound(self, self.param_env, ty, def_id, cause); + } } pub fn to_ty(&self, ast_t: &hir::Ty) -> Ty<'tcx> { @@ -2782,22 +2789,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Registers an obligation for checking later, during regionck, that the type `ty` must /// outlive the region `r`. - pub fn register_wf_obligation(&self, - ty: Ty<'tcx>, - span: Span, - code: traits::ObligationCauseCode<'tcx>) - { + pub fn register_wf_obligation( + &self, + ty: Ty<'tcx>, + span: Span, + code: traits::ObligationCauseCode<'tcx>, + ) { // WF obligations never themselves fail, so no real need to give a detailed cause: let cause = traits::ObligationCause::new(span, self.body_id, code); - self.register_predicate(traits::Obligation::new(cause, - self.param_env, - ty::Predicate::WellFormed(ty))); + self.register_predicate( + traits::Obligation::new(cause, self.param_env, ty::Predicate::WellFormed(ty)), + ); } /// Registers obligations that all types appearing in `substs` are well-formed. pub fn add_wf_bounds(&self, substs: SubstsRef<'tcx>, expr: &hir::Expr) { for ty in substs.types() { - self.register_wf_obligation(ty, expr.span, traits::MiscObligation); + if !ty.references_error() { + self.register_wf_obligation(ty, expr.span, traits::MiscObligation); + } } } @@ -2836,12 +2846,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // FIXME(arielb1): use this instead of field.ty everywhere // Only for fields! Returns for methods> // Indifferent to privacy flags - pub fn field_ty(&self, - span: Span, - field: &'tcx ty::FieldDef, - substs: SubstsRef<'tcx>) - -> Ty<'tcx> - { + pub fn field_ty( + &self, + span: Span, + field: &'tcx ty::FieldDef, + substs: SubstsRef<'tcx>, + ) -> Ty<'tcx> { self.normalize_associated_types_in(span, &field.ty(self.tcx, substs)) } From b7ca1c5a1e349edebae2ca4a2525dc6ecf04f17d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 24 Sep 2019 11:55:53 -0700 Subject: [PATCH 16/17] fix rebase --- src/test/ui/issues/issue-54954.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/issues/issue-54954.stderr b/src/test/ui/issues/issue-54954.stderr index 82315c125798f..56ccdaf7aac40 100644 --- a/src/test/ui/issues/issue-54954.stderr +++ b/src/test/ui/issues/issue-54954.stderr @@ -11,7 +11,7 @@ LL | const ARR_LEN: usize = Tt::const_val::<[i8; 123]>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | const fn const_val() -> usize { - | --------------------------------------- required by `Tt::const_val` + | --------- - required by this bound in `Tt::const_val` error[E0080]: evaluation of constant value failed --> $DIR/issue-54954.rs:13:15 From 6d07874e883ae4334b42ef3ab04cc3f52ee711ee Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 24 Sep 2019 16:53:33 -0700 Subject: [PATCH 17/17] Don't emit explain with json short messages. --- src/libsyntax/json.rs | 7 +++++++ src/test/ui/json-short.stderr | 2 -- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs index 5cdea3aabbe11..2423e1070fc3e 100644 --- a/src/libsyntax/json.rs +++ b/src/libsyntax/json.rs @@ -112,6 +112,13 @@ impl Emitter for JsonEmitter { panic!("failed to print notification: {:?}", e); } } + + fn should_show_explain(&self) -> bool { + match self.json_rendered { + HumanReadableErrorType::Short(_) => false, + _ => true, + } + } } // The following data types are provided just for serialisation. diff --git a/src/test/ui/json-short.stderr b/src/test/ui/json-short.stderr index 0a1fb567714fb..d9f68023ce76d 100644 --- a/src/test/ui/json-short.stderr +++ b/src/test/ui/json-short.stderr @@ -15,5 +15,3 @@ started: https://doc.rust-lang.org/book/ "} {"message":"aborting due to previous error","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to previous error "} -{"message":"For more information about this error, try `rustc --explain E0601`.","code":null,"level":"failure-note","spans":[],"children":[],"rendered":"For more information about this error, try `rustc --explain E0601`. -"}