From a3f30bbc2d28572f9fa429cf3b31d7f95d3b0dda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 12 May 2020 10:56:26 -0700 Subject: [PATCH 1/7] Don't `type_of` on trait assoc ty without default Fix #72076. --- src/librustc_middle/ty/error.rs | 13 +++---- src/test/ui/issues/issue-72076.rs | 6 +++ src/test/ui/issues/issue-72076.stderr | 14 +++++++ ...ith-missing-associated-type-restriction.rs | 1 + ...missing-associated-type-restriction.stderr | 37 ++++++++++++++----- 5 files changed, 54 insertions(+), 17 deletions(-) create mode 100644 src/test/ui/issues/issue-72076.rs create mode 100644 src/test/ui/issues/issue-72076.stderr diff --git a/src/librustc_middle/ty/error.rs b/src/librustc_middle/ty/error.rs index f3b6a53dfeb82..00be12f46fe21 100644 --- a/src/librustc_middle/ty/error.rs +++ b/src/librustc_middle/ty/error.rs @@ -817,19 +817,18 @@ fn foo(&self) -> Self::T { String::new() } for item in &items[..] { match item.kind { hir::AssocItemKind::Type | hir::AssocItemKind::OpaqueTy => { - if self.type_of(self.hir().local_def_id(item.id.hir_id)) == found { - if let hir::Defaultness::Default { has_value: true } = - item.defaultness - { + // FIXME: account for returning some type in a trait fn impl that has + // an assoc type as a return type (#72076). + if let hir::Defaultness::Default { has_value: true } = item.defaultness + { + if self.type_of(self.hir().local_def_id(item.id.hir_id)) == found { db.span_label( item.span, "associated type defaults can't be assumed inside the \ trait defining them", ); - } else { - db.span_label(item.span, "expected this associated type"); + return true; } - return true; } } _ => {} diff --git a/src/test/ui/issues/issue-72076.rs b/src/test/ui/issues/issue-72076.rs new file mode 100644 index 0000000000000..1659044a64fe1 --- /dev/null +++ b/src/test/ui/issues/issue-72076.rs @@ -0,0 +1,6 @@ +trait X { + type S; + fn f() -> Self::S {} //~ ERROR mismatched types +} + +fn main() {} diff --git a/src/test/ui/issues/issue-72076.stderr b/src/test/ui/issues/issue-72076.stderr new file mode 100644 index 0000000000000..b942cf75b06a7 --- /dev/null +++ b/src/test/ui/issues/issue-72076.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/issue-72076.rs:3:23 + | +LL | fn f() -> Self::S {} + | ^^ expected associated type, found `()` + | + = note: expected associated type `::S` + found unit type `()` + = help: consider constraining the associated type `::S` to `()` or calling a method that returns `::S` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.rs b/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.rs index 7465049787f59..0d90e449523a3 100644 --- a/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.rs +++ b/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.rs @@ -7,6 +7,7 @@ trait Trait { fn func(&self) -> Self::A; fn funk(&self, _: Self::A); + fn funq(&self) -> Self::A {} //~ ERROR mismatched types } fn foo(_: impl Trait, x: impl Trait) { diff --git a/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.stderr b/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.stderr index 5ae1d45c6b703..e629f8f970d32 100644 --- a/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.stderr +++ b/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.stderr @@ -1,5 +1,19 @@ error[E0308]: mismatched types - --> $DIR/trait-with-missing-associated-type-restriction.rs:13:9 + --> $DIR/trait-with-missing-associated-type-restriction.rs:10:31 + | +LL | fn funq(&self) -> Self::A {} + | ^^ expected associated type, found `()` + | + = note: expected associated type `>::A` + found unit type `()` +help: a method is available that returns `>::A` + --> $DIR/trait-with-missing-associated-type-restriction.rs:8:5 + | +LL | fn func(&self) -> Self::A; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ consider calling `Trait::func` + +error[E0308]: mismatched types + --> $DIR/trait-with-missing-associated-type-restriction.rs:14:9 | LL | qux(x.func()) | ^^^^^^^^ expected `usize`, found associated type @@ -12,7 +26,7 @@ LL | fn foo(_: impl Trait, x: impl Trait) { | ^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/trait-with-missing-associated-type-restriction.rs:17:9 + --> $DIR/trait-with-missing-associated-type-restriction.rs:18:9 | LL | qux(x.func()) | ^^^^^^^^ expected `usize`, found associated type @@ -25,7 +39,7 @@ LL | fn bar>(x: T) { | ^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/trait-with-missing-associated-type-restriction.rs:21:9 + --> $DIR/trait-with-missing-associated-type-restriction.rs:22:9 | LL | qux(x.func()) | ^^^^^^^^ expected `usize`, found associated type @@ -38,25 +52,28 @@ LL | fn foo2(x: impl Trait) { | ^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/trait-with-missing-associated-type-restriction.rs:25:12 + --> $DIR/trait-with-missing-associated-type-restriction.rs:26:12 | LL | x.funk(3); | ^ expected associated type, found integer | = note: expected associated type `>::A` found type `{integer}` -help: a method is available that returns `>::A` +help: some methods are available that return `>::A` --> $DIR/trait-with-missing-associated-type-restriction.rs:8:5 | LL | fn func(&self) -> Self::A; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ consider calling `Trait::func` +LL | fn funk(&self, _: Self::A); +LL | fn funq(&self) -> Self::A {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ consider calling `Trait::funq` help: consider constraining the associated type `>::A` to `{integer}` | LL | fn bar2>(x: T) { | ^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/trait-with-missing-associated-type-restriction.rs:26:9 + --> $DIR/trait-with-missing-associated-type-restriction.rs:27:9 | LL | qux(x.func()) | ^^^^^^^^ expected `usize`, found associated type @@ -69,7 +86,7 @@ LL | fn bar2>(x: T) { | ^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/trait-with-missing-associated-type-restriction.rs:30:9 + --> $DIR/trait-with-missing-associated-type-restriction.rs:31:9 | LL | fn baz>(x: T) { | - this type parameter @@ -80,13 +97,13 @@ LL | qux(x.func()) found type parameter `D` error[E0308]: mismatched types - --> $DIR/trait-with-missing-associated-type-restriction.rs:34:9 + --> $DIR/trait-with-missing-associated-type-restriction.rs:35:9 | LL | qux(x.func()) | ^^^^^^^^ expected `usize`, found `()` error[E0308]: mismatched types - --> $DIR/trait-with-missing-associated-type-restriction.rs:38:9 + --> $DIR/trait-with-missing-associated-type-restriction.rs:39:9 | LL | qux(x.func()) | ^^^^^^^^ expected `usize`, found associated type @@ -98,6 +115,6 @@ help: consider constraining the associated type `::A` to `usize` LL | fn ban(x: T) where T: Trait { | ^^^^^^^^^^^ -error: aborting due to 8 previous errors +error: aborting due to 9 previous errors For more information about this error, try `rustc --explain E0308`. From fc4c9a6c7f27dc4cc68d8b2afe77e88a29ff8a31 Mon Sep 17 00:00:00 2001 From: Tymoteusz Jankowski Date: Tue, 19 May 2020 13:54:22 +0200 Subject: [PATCH 2/7] Make intra-link resolve links for both trait and impl items --- .../passes/collect_intra_doc_links.rs | 61 +++++++++++-------- src/test/rustdoc/issue-72340.rs | 19 ++++++ 2 files changed, 54 insertions(+), 26 deletions(-) create mode 100644 src/test/rustdoc/issue-72340.rs diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index a3ef350a0487e..05f3b598ecdf4 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -232,37 +232,46 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::TyAlias, did, ) => { - // We need item's parent to know if it's - // trait impl or struct/enum/etc impl - let item_parent = item_opt + // Checks if item_name belongs to `impl SomeItem` + let impl_item = cx + .tcx + .inherent_impls(did) + .iter() + .flat_map(|imp| cx.tcx.associated_items(*imp).in_definition_order()) + .find(|item| item.ident.name == item_name); + let trait_item = item_opt .and_then(|item| self.cx.as_local_hir_id(item.def_id)) .and_then(|item_hir| { + // Checks if item_name belongs to `impl SomeTrait for SomeItem` let parent_hir = self.cx.tcx.hir().get_parent_item(item_hir); - self.cx.tcx.hir().find(parent_hir) + let item_parent = self.cx.tcx.hir().find(parent_hir); + match item_parent { + Some(hir::Node::Item(hir::Item { + kind: hir::ItemKind::Impl { of_trait: Some(_), self_ty, .. }, + .. + })) => cx + .tcx + .associated_item_def_ids(self_ty.hir_id.owner) + .iter() + .map(|child| { + let associated_item = cx.tcx.associated_item(*child); + associated_item + }) + .find(|child| child.ident.name == item_name), + _ => None, + } }); - let item = match item_parent { - Some(hir::Node::Item(hir::Item { - kind: hir::ItemKind::Impl { of_trait: Some(_), self_ty, .. }, - .. - })) => { - // trait impl - cx.tcx - .associated_item_def_ids(self_ty.hir_id.owner) - .iter() - .map(|child| { - let associated_item = cx.tcx.associated_item(*child); - associated_item - }) - .find(|child| child.ident.name == item_name) - } - _ => { - // struct/enum/etc. impl - cx.tcx - .inherent_impls(did) - .iter() - .flat_map(|imp| cx.tcx.associated_items(*imp).in_definition_order()) - .find(|item| item.ident.name == item_name) + let item = match (impl_item, trait_item) { + (Some(from_impl), Some(_)) => { + // Although it's ambiguous, return impl version for compat. sake. + // To handle that properly resolve() would have to support + // something like + // [`ambi_fn`](::ambi_fn) + Some(from_impl) } + (None, Some(from_trait)) => Some(from_trait), + (Some(from_impl), None) => Some(from_impl), + _ => None, }; if let Some(item) = item { diff --git a/src/test/rustdoc/issue-72340.rs b/src/test/rustdoc/issue-72340.rs new file mode 100644 index 0000000000000..6ed3bfbe3e54b --- /dev/null +++ b/src/test/rustdoc/issue-72340.rs @@ -0,0 +1,19 @@ +#![crate_name = "foo"] + +pub struct Body; + +impl Body { + pub fn empty() -> Self { + Body + } + +} + +impl Default for Body { + // @has foo/struct.Body.html '//a/@href' '../foo/struct.Body.html#method.empty' + + /// Returns [`Body::empty()`](Body::empty). + fn default() -> Body { + Body::empty() + } +} From 6778c7a7c147385fc8a95ead842844b005409301 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Wed, 20 May 2020 00:00:00 +0000 Subject: [PATCH 3/7] Show default values for debug-assertions & debug-assertions-std --- config.toml.example | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.toml.example b/config.toml.example index ffe907c9da97c..cf8fe4e082ac3 100644 --- a/config.toml.example +++ b/config.toml.example @@ -312,11 +312,11 @@ # Whether or not debug assertions are enabled for the compiler and standard # library. -#debug-assertions = false +#debug-assertions = debug # Whether or not debug assertions are enabled for the standard library. # Overrides the `debug-assertions` option, if defined. -#debug-assertions-std = false +#debug-assertions-std = debug-assertions # Debuginfo level for most of Rust code, corresponds to the `-C debuginfo=N` option of `rustc`. # `0` - no debug info From 20b499c60a5778b9ad00c807fe33d225c36c095e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 21 May 2020 12:22:03 +0200 Subject: [PATCH 4/7] Fix anchor display when hovering impl --- src/librustdoc/html/static/rustdoc.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index ab52475172333..2cb3347135c1b 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -625,7 +625,7 @@ a { display: initial; } -.in-band:hover > .anchor { +.in-band:hover > .anchor, .impl:hover > .anchor { display: inline-block; position: absolute; } From 94aa02855defad20fe63d46a5df9506e82b78ff3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 May 2020 16:30:27 +0200 Subject: [PATCH 5/7] fix discriminant sign extension --- src/librustc_mir/interpret/intrinsics.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 42b969c99917f..fc4be82ad90ad 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -219,7 +219,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let place = self.deref_operand(args[0])?; let discr_val = self.read_discriminant(place.into())?.0; let scalar = match dest.layout.ty.kind { - ty::Int(_) => Scalar::from_int(discr_val as i128, dest.layout.size), + ty::Int(_) => Scalar::from_int( + self.sign_extend(discr_val, dest.layout) as i128, + dest.layout.size, + ), ty::Uint(_) => Scalar::from_uint(discr_val, dest.layout.size), _ => bug!("invalid `discriminant_value` return layout: {:?}", dest.layout), }; From a81e9a781b19153d19898c421c80d713dc739d8e Mon Sep 17 00:00:00 2001 From: Daniel Henry-Mantilla Date: Tue, 19 May 2020 15:37:06 +0200 Subject: [PATCH 6/7] Improve documentation of `slice::from_raw_parts` This is to provide a more explicit statement against a code pattern that many people end up coming with, since the reason of it being unsound comes from the badly known single-allocation validity rule. Providing that very pattern as a counter-example could help mitigate that. Co-authored-by: Ralf Jung --- src/libcore/slice/mod.rs | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 9582ac33ff6b7..2e1dd89433d9e 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -5740,7 +5740,8 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> { /// and it must be properly aligned. This means in particular: /// /// * The entire memory range of this slice must be contained within a single allocated object! -/// Slices can never span across multiple allocated objects. +/// Slices can never span across multiple allocated objects. See [below](#incorrect-usage) +/// for an example incorrectly not taking this into account. /// * `data` must be non-null and aligned even for zero-length slices. One /// reason for this is that enum layout optimizations may rely on references /// (including slices of any length) being aligned and non-null to distinguish @@ -5773,6 +5774,34 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> { /// assert_eq!(slice[0], 42); /// ``` /// +/// ### Incorrect usage +/// +/// The following `join_slices` function is **unsound** ⚠️ +/// +/// ```rust,no_run +/// use std::slice; +/// +/// fn join_slices<'a, T>(fst: &'a [T], snd: &'a [T]) -> &'a [T] { +/// let fst_end = fst.as_ptr().wrapping_add(fst.len()); +/// let snd_start = snd.as_ptr(); +/// assert_eq!(fst_end, snd_start, "Slices must be contiguous!"); +/// unsafe { +/// // The assertion above ensures `fst` and `snd` are contiguous, but they might +/// // still be contained within _different allocated objects_, in which case +/// // creating this slice is undefined behavior. +/// slice::from_raw_parts(fst.as_ptr(), fst.len() + snd.len()) +/// } +/// } +/// +/// fn main() { +/// // `a` and `b` are different allocated objects... +/// let a = 42; +/// let b = 27; +/// // ... which may nevertheless be laid out contiguous in memory: | a | b | +/// let _ = join_slices(slice::from_ref(&a), slice::from_ref(&b)); // UB +/// } +/// ``` +/// /// [valid]: ../../std/ptr/index.html#safety /// [`NonNull::dangling()`]: ../../std/ptr/struct.NonNull.html#method.dangling /// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset From 67e075589b7e19a87130a700b7e59015a1b80f11 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 May 2020 19:07:59 +0200 Subject: [PATCH 7/7] Typo --- src/libcore/slice/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 2e1dd89433d9e..b5ce165cb43db 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -5797,7 +5797,7 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> { /// // `a` and `b` are different allocated objects... /// let a = 42; /// let b = 27; -/// // ... which may nevertheless be laid out contiguous in memory: | a | b | +/// // ... which may nevertheless be laid out contiguously in memory: | a | b | /// let _ = join_slices(slice::from_ref(&a), slice::from_ref(&b)); // UB /// } /// ```