From 6ce64ccc27f51b60561fb93f3cdc31c46f57a77b Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 2 Jan 2019 15:49:33 -0800 Subject: [PATCH 01/13] [BETA] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 1b6702f22a0dd..8610973aaf486 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 1b6702f22a0dd54847684f29acd6617dd31a8479 +Subproject commit 8610973aaf48615ba7dc9a38a9a2795ba6f36a31 From 6cd7fb70ba682137a2ed7c139cd68d7a9fa6c43e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Thu, 3 Jan 2019 09:13:16 +0100 Subject: [PATCH 02/13] beta: bootstrap from latest stable (1.31.1) --- src/stage0.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/stage0.txt b/src/stage0.txt index b0ef7b6d0446d..2b089c0ddf15d 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -12,8 +12,8 @@ # source tarball for a stable release you'll likely see `1.x.0` for rustc and # `0.x.0` for Cargo where they were released on `date`. -date: 2018-12-06 -rustc: 1.31.0 +date: 2018-12-20 +rustc: 1.31.1 cargo: 0.32.0 # When making a stable release the process currently looks like: From 4c4ea590d0885be5ceeba574b01139616c84f7f8 Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Thu, 3 Jan 2019 11:26:17 +0100 Subject: [PATCH 03/13] [beta] Update RLS to include 100% CPU on hover bugfix Beta backport of a fix that already was backported to stable, see https://github.com/rust-lang/rust/issues/56726 and https://github.com/rust-lang/rls/pull/1170 for the underlying RLS issue. Also includes the fix for https://github.com/rust-lang/rls/issues/1154 (respecting target-dir specified in .cargo/config for RLS artifacts). --- src/tools/rls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rls b/src/tools/rls index cfd8449bd6fcf..bfa1371f5ccea 160000 --- a/src/tools/rls +++ b/src/tools/rls @@ -1 +1 @@ -Subproject commit cfd8449bd6fcfc6a0b53889c616faa4de4513636 +Subproject commit bfa1371f5cceacebe307d9ee70760296eb0ec489 From f493744339a6914a3e11a17f712ef05fcb82fa84 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 21 Dec 2018 23:12:15 +0100 Subject: [PATCH 04/13] Fix alignment for array indexing We need to reduce the alignment with the used offset. If the offset isn't known, we need to reduce with the element size to support arbitrary offsets. --- src/librustc_codegen_ssa/mir/place.rs | 13 ++++++-- src/librustc_codegen_ssa/mir/rvalue.rs | 3 +- src/test/codegen/issue-56927.rs | 44 ++++++++++++++++++++++++++ src/test/codegen/packed.rs | 36 +++++++++++++++++++++ 4 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 src/test/codegen/issue-56927.rs diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs index 1aba53255e7a7..0a9fbcbfdd29a 100644 --- a/src/librustc_codegen_ssa/mir/place.rs +++ b/src/librustc_codegen_ssa/mir/place.rs @@ -335,11 +335,20 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> { bx: &mut Bx, llindex: V ) -> Self { + // Statically compute the offset if we can, otherwise just use the element size, + // as this will yield the lowest alignment. + let layout = self.layout.field(bx, 0); + let offset = if bx.is_const_integral(llindex) { + layout.size.checked_mul(bx.const_to_uint(llindex), bx).unwrap_or(layout.size) + } else { + layout.size + }; + PlaceRef { llval: bx.inbounds_gep(self.llval, &[bx.cx().const_usize(0), llindex]), llextra: None, - layout: self.layout.field(bx.cx(), 0), - align: self.align + layout, + align: self.align.restrict_for_offset(offset), } } diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs index dc7b1ec37b23a..a94ee27b7e65d 100644 --- a/src/librustc_codegen_ssa/mir/rvalue.rs +++ b/src/librustc_codegen_ssa/mir/rvalue.rs @@ -131,8 +131,9 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let keep_going = header_bx.icmp(IntPredicate::IntNE, current, end); header_bx.cond_br(keep_going, body_bx.llbb(), next_bx.llbb()); + let align = dest.align.restrict_for_offset(dest.layout.field(bx.cx(), 0).size); cg_elem.val.store(&mut body_bx, - PlaceRef::new_sized(current, cg_elem.layout, dest.align)); + PlaceRef::new_sized(current, cg_elem.layout, align)); let next = body_bx.inbounds_gep(current, &[bx.cx().const_usize(1)]); body_bx.br(header_bx.llbb()); diff --git a/src/test/codegen/issue-56927.rs b/src/test/codegen/issue-56927.rs new file mode 100644 index 0000000000000..0544ff86aacfa --- /dev/null +++ b/src/test/codegen/issue-56927.rs @@ -0,0 +1,44 @@ +// compile-flags: -C no-prepopulate-passes + +#![crate_type="rlib"] +use std::usize; + +#[repr(align(16))] +pub struct S { + arr: [u32; 4], +} + +// CHECK-LABEL: @test1 +// CHECK: store i32 0, i32* %{{.+}}, align 16 +// CHECK: store i32 1, i32* %{{.+}}, align 4 +// CHECK: store i32 2, i32* %{{.+}}, align 8 +// CHECK: store i32 3, i32* %{{.+}}, align 4 +#[no_mangle] +pub fn test1(s: &mut S) { + s.arr[0] = 0; + s.arr[1] = 1; + s.arr[2] = 2; + s.arr[3] = 3; +} + +// CHECK-LABEL: @test2 +// CHECK: store i32 4, i32* %{{.+}}, align 4 +#[allow(const_err)] +#[no_mangle] +pub fn test2(s: &mut S) { + s.arr[usize::MAX / 4 + 1] = 4; +} + +// CHECK-LABEL: @test3 +// CHECK: store i32 5, i32* %{{.+}}, align 4 +#[no_mangle] +pub fn test3(s: &mut S, i: usize) { + s.arr[i] = 5; +} + +// CHECK-LABEL: @test4 +// CHECK: store i32 6, i32* %{{.+}}, align 4 +#[no_mangle] +pub fn test4(s: &mut S) { + s.arr = [6; 4]; +} diff --git a/src/test/codegen/packed.rs b/src/test/codegen/packed.rs index b50f5b6f16fed..e60051de559b5 100644 --- a/src/test/codegen/packed.rs +++ b/src/test/codegen/packed.rs @@ -84,6 +84,42 @@ pub fn call_pkd2(f: fn() -> Array) -> BigPacked2 { BigPacked2 { dealign: 0, data: f() } } +// CHECK-LABEL: @write_packed_array1 +// CHECK: store i32 0, i32* %{{.+}}, align 1 +// CHECK: store i32 1, i32* %{{.+}}, align 1 +// CHECK: store i32 2, i32* %{{.+}}, align 1 +#[no_mangle] +pub fn write_packed_array1(p: &mut BigPacked1) { + p.data.0[0] = 0; + p.data.0[1] = 1; + p.data.0[2] = 2; +} + +// CHECK-LABEL: @write_packed_array2 +// CHECK: store i32 0, i32* %{{.+}}, align 2 +// CHECK: store i32 1, i32* %{{.+}}, align 2 +// CHECK: store i32 2, i32* %{{.+}}, align 2 +#[no_mangle] +pub fn write_packed_array2(p: &mut BigPacked2) { + p.data.0[0] = 0; + p.data.0[1] = 1; + p.data.0[2] = 2; +} + +// CHECK-LABEL: @repeat_packed_array1 +// CHECK: store i32 42, i32* %{{.+}}, align 1 +#[no_mangle] +pub fn repeat_packed_array1(p: &mut BigPacked1) { + p.data.0 = [42; 8]; +} + +// CHECK-LABEL: @repeat_packed_array2 +// CHECK: store i32 42, i32* %{{.+}}, align 2 +#[no_mangle] +pub fn repeat_packed_array2(p: &mut BigPacked2) { + p.data.0 = [42; 8]; +} + #[repr(packed)] #[derive(Copy, Clone)] pub struct Packed1Pair(u8, u32); From 57009e7216eef995b0200bd1da3ee7af9593c326 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 29 Dec 2018 00:15:19 +0300 Subject: [PATCH 05/13] resolve: Fix another ICE in import validation --- src/librustc_resolve/lib.rs | 8 ++++---- src/librustc_resolve/resolve_imports.rs | 4 +++- .../uniform-paths/auxiliary/issue-56596-2.rs | 1 + src/test/ui/rust-2018/uniform-paths/issue-56596-2.rs | 11 +++++++++++ 4 files changed, 19 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/rust-2018/uniform-paths/auxiliary/issue-56596-2.rs create mode 100644 src/test/ui/rust-2018/uniform-paths/issue-56596-2.rs diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index fdac1e3b81652..e39c764e089c0 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1022,11 +1022,11 @@ enum ModuleOrUniformRoot<'a> { CurrentScope, } -impl<'a> PartialEq for ModuleOrUniformRoot<'a> { - fn eq(&self, other: &Self) -> bool { - match (*self, *other) { +impl ModuleOrUniformRoot<'_> { + fn same_def(lhs: Self, rhs: Self) -> bool { + match (lhs, rhs) { (ModuleOrUniformRoot::Module(lhs), - ModuleOrUniformRoot::Module(rhs)) => ptr::eq(lhs, rhs), + ModuleOrUniformRoot::Module(rhs)) => lhs.def() == rhs.def(), (ModuleOrUniformRoot::CrateRootAndExternPrelude, ModuleOrUniformRoot::CrateRootAndExternPrelude) | (ModuleOrUniformRoot::ExternPrelude, ModuleOrUniformRoot::ExternPrelude) | diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index e7cd32f4e810f..16cacceb97189 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -836,7 +836,9 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { PathResult::Module(module) => { // Consistency checks, analogous to `finalize_current_module_macro_resolutions`. if let Some(initial_module) = directive.imported_module.get() { - if module != initial_module && self.ambiguity_errors.is_empty() { + if !ModuleOrUniformRoot::same_def(module, initial_module) + && self.ambiguity_errors.is_empty() + { span_bug!(directive.span, "inconsistent resolution for an import"); } } else { diff --git a/src/test/ui/rust-2018/uniform-paths/auxiliary/issue-56596-2.rs b/src/test/ui/rust-2018/uniform-paths/auxiliary/issue-56596-2.rs new file mode 100644 index 0000000000000..db723075f93c0 --- /dev/null +++ b/src/test/ui/rust-2018/uniform-paths/auxiliary/issue-56596-2.rs @@ -0,0 +1 @@ +pub extern crate core; diff --git a/src/test/ui/rust-2018/uniform-paths/issue-56596-2.rs b/src/test/ui/rust-2018/uniform-paths/issue-56596-2.rs new file mode 100644 index 0000000000000..9ec3a64113116 --- /dev/null +++ b/src/test/ui/rust-2018/uniform-paths/issue-56596-2.rs @@ -0,0 +1,11 @@ +// compile-pass +// edition:2018 +// compile-flags: --extern issue_56596_2 +// aux-build:issue-56596-2.rs + +mod m { + use core::any; + pub use issue_56596_2::*; +} + +fn main() {} From 073aa85f1d1a1987e5670a363a90a3a1e45e3f95 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 29 Dec 2018 02:48:38 +0300 Subject: [PATCH 06/13] resolve: Never override real bindings with `Def::Err`s from error recovery --- src/librustc_resolve/resolve_imports.rs | 4 ++++ src/test/ui/imports/duplicate.rs | 2 +- src/test/ui/imports/duplicate.stderr | 21 +-------------------- src/test/ui/imports/issue-56125.stderr | 10 +++++----- src/test/ui/imports/issue-57015.rs | 13 +++++++++++++ src/test/ui/imports/issue-57015.stderr | 9 +++++++++ 6 files changed, 33 insertions(+), 26 deletions(-) create mode 100644 src/test/ui/imports/issue-57015.rs create mode 100644 src/test/ui/imports/issue-57015.stderr diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 16cacceb97189..ddcaf54f2a556 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -465,6 +465,10 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> { self.set_binding_parent_module(binding, module); self.update_resolution(module, ident, ns, |this, resolution| { if let Some(old_binding) = resolution.binding { + if binding.def() == Def::Err { + // Do not override real bindings with `Def::Err`s from error recovery. + return Ok(()); + } match (old_binding.is_glob_import(), binding.is_glob_import()) { (true, true) => { if binding.def() != old_binding.def() { diff --git a/src/test/ui/imports/duplicate.rs b/src/test/ui/imports/duplicate.rs index dd2dcbe2e6808..aad5529851a79 100644 --- a/src/test/ui/imports/duplicate.rs +++ b/src/test/ui/imports/duplicate.rs @@ -43,7 +43,7 @@ mod g { fn main() { e::foo(); f::foo(); //~ ERROR `foo` is ambiguous - g::foo(); //~ ERROR `foo` is ambiguous + g::foo(); } mod ambiguous_module_errors { diff --git a/src/test/ui/imports/duplicate.stderr b/src/test/ui/imports/duplicate.stderr index f53ba9cd5de8e..b4b3fc2ecae3b 100644 --- a/src/test/ui/imports/duplicate.stderr +++ b/src/test/ui/imports/duplicate.stderr @@ -50,25 +50,6 @@ LL | pub use b::*; | ^^^^ = help: consider adding an explicit import of `foo` to disambiguate -error[E0659]: `foo` is ambiguous (glob import vs glob import in the same module) - --> $DIR/duplicate.rs:46:8 - | -LL | g::foo(); //~ ERROR `foo` is ambiguous - | ^^^ ambiguous name - | -note: `foo` could refer to the function imported here - --> $DIR/duplicate.rs:39:13 - | -LL | pub use a::*; - | ^^^^ - = help: consider adding an explicit import of `foo` to disambiguate -note: `foo` could also refer to the unresolved item imported here - --> $DIR/duplicate.rs:40:13 - | -LL | pub use f::*; - | ^^^^ - = help: consider adding an explicit import of `foo` to disambiguate - error[E0659]: `foo` is ambiguous (glob import vs glob import in the same module) --> $DIR/duplicate.rs:59:9 | @@ -88,7 +69,7 @@ LL | use self::m2::*; | ^^^^^^^^^^^ = help: consider adding an explicit import of `foo` to disambiguate -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors Some errors occurred: E0252, E0659. For more information about an error, try `rustc --explain E0252`. diff --git a/src/test/ui/imports/issue-56125.stderr b/src/test/ui/imports/issue-56125.stderr index b1292ef8f783e..72d6041765e99 100644 --- a/src/test/ui/imports/issue-56125.stderr +++ b/src/test/ui/imports/issue-56125.stderr @@ -54,12 +54,12 @@ LL | use issue_56125::*; //~ ERROR `issue_56125` is ambiguous | = note: `issue_56125` could refer to an extern crate passed with `--extern` = help: use `::issue_56125` to refer to this extern crate unambiguously -note: `issue_56125` could also refer to the unresolved item imported here - --> $DIR/issue-56125.rs:21:9 +note: `issue_56125` could also refer to the module imported here + --> $DIR/issue-56125.rs:22:9 | -LL | use empty::issue_56125; //~ ERROR unresolved import `empty::issue_56125` - | ^^^^^^^^^^^^^^^^^^ - = help: use `self::issue_56125` to refer to this unresolved item unambiguously +LL | use issue_56125::*; //~ ERROR `issue_56125` is ambiguous + | ^^^^^^^^^^^^^^ + = help: use `self::issue_56125` to refer to this module unambiguously error: aborting due to 6 previous errors diff --git a/src/test/ui/imports/issue-57015.rs b/src/test/ui/imports/issue-57015.rs new file mode 100644 index 0000000000000..27688fd34f62f --- /dev/null +++ b/src/test/ui/imports/issue-57015.rs @@ -0,0 +1,13 @@ +mod glob_ok { + pub mod something { + pub mod something_else {} + } +} + +mod single_err {} + +use glob_ok::*; // glob_ok::something +use single_err::something; //~ ERROR unresolved import `single_err::something` +use something::something_else; + +fn main() {} diff --git a/src/test/ui/imports/issue-57015.stderr b/src/test/ui/imports/issue-57015.stderr new file mode 100644 index 0000000000000..b0fcf5bec6a77 --- /dev/null +++ b/src/test/ui/imports/issue-57015.stderr @@ -0,0 +1,9 @@ +error[E0432]: unresolved import `single_err::something` + --> $DIR/issue-57015.rs:10:5 + | +LL | use single_err::something; //~ ERROR unresolved import `single_err::something` + | ^^^^^^^^^^^^^^^^^^^^^ no `something` in `single_err` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0432`. From e6823339b454e800d34932bedf9052a1d592cf44 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Wed, 2 Jan 2019 20:00:56 +0000 Subject: [PATCH 07/13] Wf-check the output type of a function in MIR-typeck --- .../borrow_check/nll/type_check/mod.rs | 2 +- .../nll/issue-57265-return-type-wf-check.rs | 26 +++++++++++++++++++ .../issue-57265-return-type-wf-check.stderr | 12 +++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/nll/issue-57265-return-type-wf-check.rs create mode 100644 src/test/ui/nll/issue-57265-return-type-wf-check.stderr diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 5f64dfd931c89..2dec217becf4d 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -1415,7 +1415,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { self.check_call_dest(mir, term, &sig, destination, term_location); self.prove_predicates( - sig.inputs().iter().map(|ty| ty::Predicate::WellFormed(ty)), + sig.inputs_and_output.iter().map(|ty| ty::Predicate::WellFormed(ty)), term_location.to_locations(), ConstraintCategory::Boring, ); diff --git a/src/test/ui/nll/issue-57265-return-type-wf-check.rs b/src/test/ui/nll/issue-57265-return-type-wf-check.rs new file mode 100644 index 0000000000000..24c61a4926f0c --- /dev/null +++ b/src/test/ui/nll/issue-57265-return-type-wf-check.rs @@ -0,0 +1,26 @@ +#![feature(nll)] + +use std::any::Any; + +#[derive(Debug, Clone)] +struct S(T); + +// S<&'a T> is in the return type, so we get an implied bound +// &'a T: 'static +fn foo<'a, T>(x: &'a T) -> (S<&'a T>, Box) { + let y = S(x); + + let z = Box::new(y.clone()) as Box; + (y, z) +} + +fn main() { + let x = 5; + + // Check that we require that the argument is of type `&'static String`, + // so that the return type is well-formed. + let (_, z) = foo(&"hello".to_string()); + //~^ ERROR temporary value dropped while borrowed + + println!("{:?}", z.downcast_ref::>()); +} diff --git a/src/test/ui/nll/issue-57265-return-type-wf-check.stderr b/src/test/ui/nll/issue-57265-return-type-wf-check.stderr new file mode 100644 index 0000000000000..db01212597f5b --- /dev/null +++ b/src/test/ui/nll/issue-57265-return-type-wf-check.stderr @@ -0,0 +1,12 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/issue-57265-return-type-wf-check.rs:22:23 + | +LL | let (_, z) = foo(&"hello".to_string()); + | -----^^^^^^^^^^^^^^^^^^^-- temporary value is freed at the end of this statement + | | | + | | creates a temporary which is freed while still in use + | argument requires that borrow lasts for `'static` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0716`. From 00dc29b50ac5cc4a9b05aa9d29f43bfb131620c8 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Wed, 2 Jan 2019 21:28:08 +0000 Subject: [PATCH 08/13] Add missing 'static bound for the Machine trait --- src/librustc_mir/interpret/machine.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs index d7a3a27bbe8c2..39e816c3039da 100644 --- a/src/librustc_mir/interpret/machine.rs +++ b/src/librustc_mir/interpret/machine.rs @@ -86,7 +86,7 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized { type MemoryExtra: Default; /// Extra data stored in every allocation. - type AllocExtra: AllocationExtra; + type AllocExtra: AllocationExtra + 'static; /// Memory's allocation map type MemoryMap: From ebf5232b43c35b1b6c3c11b7c755e9be9bc0071f Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 24 Oct 2018 00:57:09 -0400 Subject: [PATCH 09/13] Ensure that Rusdoc discovers all necessary auto trait bounds Fixes #50159 This commit makes several improvements to AutoTraitFinder: * Call infcx.resolve_type_vars_if_possible before processing new predicates. This ensures that we eliminate inference variables wherever possible. * Process all nested obligations we get from a vtable, not just ones with depth=1. * The 'depth=1' check was a hack to work around issues processing certain predicates. The other changes in this commit allow us to properly process all predicates that we encounter, so the check is no longer necessary, * Ensure that we only display predicates *without* inference variables to the user, and only attempt to unify predicates that *have* an inference variable as their type. Additionally, the internal helper method is_of_param now operates directly on a type, rather than taking a Substs. This allows us to use the 'self_ty' method, rather than directly dealing with Substs. --- src/librustc/traits/auto_trait.rs | 68 +++++++++++++++++++++++-------- src/test/rustdoc/issue-50159.rs | 31 ++++++++++++++ 2 files changed, 82 insertions(+), 17 deletions(-) create mode 100644 src/test/rustdoc/issue-50159.rs diff --git a/src/librustc/traits/auto_trait.rs b/src/librustc/traits/auto_trait.rs index c3cca149c2c57..6279788adc019 100644 --- a/src/librustc/traits/auto_trait.rs +++ b/src/librustc/traits/auto_trait.rs @@ -334,7 +334,12 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { continue; } - let result = select.select(&Obligation::new(dummy_cause.clone(), new_env, pred)); + // Call infcx.resolve_type_vars_if_possible to see if we can + // get rid of any inference variables. + let obligation = infcx.resolve_type_vars_if_possible( + &Obligation::new(dummy_cause.clone(), new_env, pred) + ); + let result = select.select(&obligation); match &result { &Ok(Some(ref vtable)) => { @@ -369,7 +374,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { } &Ok(None) => {} &Err(SelectionError::Unimplemented) => { - if self.is_of_param(pred.skip_binder().trait_ref.substs) { + if self.is_of_param(pred.skip_binder().self_ty()) { already_visited.remove(&pred); self.add_user_pred( &mut user_computed_preds, @@ -631,14 +636,10 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { finished_map } - pub fn is_of_param(&self, substs: &Substs<'_>) -> bool { - if substs.is_noop() { - return false; - } - - return match substs.type_at(0).sty { + pub fn is_of_param(&self, ty: Ty<'_>) -> bool { + return match ty.sty { ty::Param(_) => true, - ty::Projection(p) => self.is_of_param(p.substs), + ty::Projection(p) => self.is_of_param(p.self_ty()), _ => false, }; } @@ -661,28 +662,61 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { ) -> bool { let dummy_cause = ObligationCause::misc(DUMMY_SP, ast::DUMMY_NODE_ID); - for (obligation, predicate) in nested - .filter(|o| o.recursion_depth == 1) + for (obligation, mut predicate) in nested .map(|o| (o.clone(), o.predicate.clone())) { let is_new_pred = fresh_preds.insert(self.clean_pred(select.infcx(), predicate.clone())); + // Resolve any inference variables that we can, to help selection succeed + predicate = select.infcx().resolve_type_vars_if_possible(&predicate); + + // We only add a predicate as a user-displayable bound if + // it involves a generic parameter, and doesn't contain + // any inference variables. + // + // Displaying a bound involving a concrete type (instead of a generic + // parameter) would be pointless, since it's always true + // (e.g. u8: Copy) + // Displaying an inference variable is impossible, since they're + // an internal compiler detail without a defined visual representation + // + // We check this by calling is_of_param on the relevant types + // from the various possible predicates match &predicate { &ty::Predicate::Trait(ref p) => { - let substs = &p.skip_binder().trait_ref.substs; + if self.is_of_param(p.skip_binder().self_ty()) + && !only_projections + && is_new_pred { - if self.is_of_param(substs) && !only_projections && is_new_pred { self.add_user_pred(computed_preds, predicate); } predicates.push_back(p.clone()); } &ty::Predicate::Projection(p) => { - // If the projection isn't all type vars, then - // we don't want to add it as a bound - if self.is_of_param(p.skip_binder().projection_ty.substs) && is_new_pred { + debug!("evaluate_nested_obligations: examining projection predicate {:?}", + predicate); + + // As described above, we only want to display + // bounds which include a generic parameter but don't include + // an inference variable. + // Additionally, we check if we've seen this predicate before, + // to avoid rendering duplicate bounds to the user. + if self.is_of_param(p.skip_binder().projection_ty.self_ty()) + && !p.ty().skip_binder().is_ty_infer() + && is_new_pred { + debug!("evaluate_nested_obligations: adding projection predicate\ + to computed_preds: {:?}", predicate); + self.add_user_pred(computed_preds, predicate); - } else { + } + + // We can only call poly_project_and_unify_type when our predicate's + // Ty is an inference variable - otherwise, there won't be anything to + // unify + if p.ty().skip_binder().is_ty_infer() { + debug!("Projecting and unifying projection predicate {:?}", + predicate); match poly_project_and_unify_type(select, &obligation.with(p.clone())) { Err(e) => { debug!( diff --git a/src/test/rustdoc/issue-50159.rs b/src/test/rustdoc/issue-50159.rs new file mode 100644 index 0000000000000..3055c72162452 --- /dev/null +++ b/src/test/rustdoc/issue-50159.rs @@ -0,0 +1,31 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +pub trait Signal { + type Item; +} + +pub trait Signal2 { + type Item2; +} + +impl Signal2 for B where B: Signal { + type Item2 = C; +} + +// @has issue_50159/struct.Switch.html +// @has - '//code' 'impl Send for Switch where ::Item: Send' +// @has - '//code' 'impl Sync for Switch where ::Item: Sync' +// @count - '//*[@id="implementations-list"]/*[@class="impl"]' 0 +// @count - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]' 2 +pub struct Switch { + pub inner: ::Item2, +} From 496c6740dd5059d655534cfe678eeaf5054af116 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 14 Nov 2018 16:36:48 -0500 Subject: [PATCH 10/13] Check all substitution parameters for inference variables --- src/librustc/traits/auto_trait.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/librustc/traits/auto_trait.rs b/src/librustc/traits/auto_trait.rs index 6279788adc019..f560772e6c73f 100644 --- a/src/librustc/traits/auto_trait.rs +++ b/src/librustc/traits/auto_trait.rs @@ -374,7 +374,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { } &Ok(None) => {} &Err(SelectionError::Unimplemented) => { - if self.is_of_param(pred.skip_binder().self_ty()) { + if self.is_param_no_infer(pred.skip_binder().trait_ref.substs) { already_visited.remove(&pred); self.add_user_pred( &mut user_computed_preds, @@ -636,6 +636,11 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { finished_map } + fn is_param_no_infer(&self, substs: &Substs<'_>) -> bool { + return self.is_of_param(substs.type_at(0)) && + !substs.types().any(|t| t.has_infer_types()); + } + pub fn is_of_param(&self, ty: Ty<'_>) -> bool { return match ty.sty { ty::Param(_) => true, @@ -685,7 +690,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { // from the various possible predicates match &predicate { &ty::Predicate::Trait(ref p) => { - if self.is_of_param(p.skip_binder().self_ty()) + if self.is_param_no_infer(p.skip_binder().trait_ref.substs) && !only_projections && is_new_pred { @@ -702,7 +707,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { // an inference variable. // Additionally, we check if we've seen this predicate before, // to avoid rendering duplicate bounds to the user. - if self.is_of_param(p.skip_binder().projection_ty.self_ty()) + if self.is_param_no_infer(p.skip_binder().projection_ty.substs) && !p.ty().skip_binder().is_ty_infer() && is_new_pred { debug!("evaluate_nested_obligations: adding projection predicate\ From 34f2e57c504a0b3affe18a1bada4b4668d449065 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 28 Nov 2018 21:15:06 -0500 Subject: [PATCH 11/13] Filter out self-referential projection predicates If we end up with a projection predicate that equates a type with itself (e.g. ::Value == ::Value), we can run into issues if we try to add it to our ParamEnv. --- src/librustc/traits/auto_trait.rs | 27 ++++++++++++- .../synthetic_auto/self-referential.rs | 40 +++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 src/test/rustdoc/synthetic_auto/self-referential.rs diff --git a/src/librustc/traits/auto_trait.rs b/src/librustc/traits/auto_trait.rs index f560772e6c73f..a0237348ea690 100644 --- a/src/librustc/traits/auto_trait.rs +++ b/src/librustc/traits/auto_trait.rs @@ -649,6 +649,15 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { }; } + fn is_self_referential_projection(&self, p: ty::PolyProjectionPredicate<'_>) -> bool { + match p.ty().skip_binder().sty { + ty::Projection(proj) if proj == p.skip_binder().projection_ty => { + true + }, + _ => false + } + } + pub fn evaluate_nested_obligations< 'b, 'c, @@ -713,7 +722,23 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { debug!("evaluate_nested_obligations: adding projection predicate\ to computed_preds: {:?}", predicate); - self.add_user_pred(computed_preds, predicate); + // Under unusual circumstances, we can end up with a self-refeential + // projection predicate. For example: + // ::Value == ::Value + // Not only is displaying this to the user pointless, + // having it in the ParamEnv will cause an issue if we try to call + // poly_project_and_unify_type on the predicate, since this kind of + // predicate will normally never end up in a ParamEnv. + // + // For these reasons, we ignore these weird predicates, + // ensuring that we're able to properly synthesize an auto trait impl + if self.is_self_referential_projection(p) { + debug!("evaluate_nested_obligations: encountered a projection + predicate equating a type with itself! Skipping"); + + } else { + self.add_user_pred(computed_preds, predicate); + } } // We can only call poly_project_and_unify_type when our predicate's diff --git a/src/test/rustdoc/synthetic_auto/self-referential.rs b/src/test/rustdoc/synthetic_auto/self-referential.rs new file mode 100644 index 0000000000000..077786b280fc3 --- /dev/null +++ b/src/test/rustdoc/synthetic_auto/self-referential.rs @@ -0,0 +1,40 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Some unusual code minimized from +// https://github.com/sile/handy_async/tree/7b619b762c06544fc67792c8ff8ebc24a88fdb98 + +pub trait Pattern { + type Value; +} + +pub struct Constrain(A, B, C); + +impl Pattern for Constrain + where A: Pattern, + B: Pattern, + C: Pattern, +{ + type Value = A::Value; +} + +pub struct Wrapper(T); + +impl Pattern for Wrapper { + type Value = T; +} + + +// @has self_referential/struct.WriteAndThen.html +// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl Send for \ +// WriteAndThen where ::Value: Send" +pub struct WriteAndThen(pub P1::Value, pub > as Pattern>::Value) + where P1: Pattern; + From 9d0deac475607571fdef06ad877937f71d182da0 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 28 Nov 2018 21:39:20 -0500 Subject: [PATCH 12/13] Fix Tidy error --- src/test/rustdoc/synthetic_auto/self-referential.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/rustdoc/synthetic_auto/self-referential.rs b/src/test/rustdoc/synthetic_auto/self-referential.rs index 077786b280fc3..516a3c9a516ab 100644 --- a/src/test/rustdoc/synthetic_auto/self-referential.rs +++ b/src/test/rustdoc/synthetic_auto/self-referential.rs @@ -35,6 +35,6 @@ impl Pattern for Wrapper { // @has self_referential/struct.WriteAndThen.html // @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl Send for \ // WriteAndThen where ::Value: Send" -pub struct WriteAndThen(pub P1::Value, pub > as Pattern>::Value) +pub struct WriteAndThen(pub P1::Value,pub > as Pattern>::Value) where P1: Pattern; From 443165d28f21f5105c9c4bd317f87caccb3f9b9b Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Fri, 14 Dec 2018 21:02:33 -0500 Subject: [PATCH 13/13] Call poly_project_and_unify_type on types that contain inference types Commit f57247c48cb59 (Ensure that Rusdoc discovers all necessary auto trait bounds) added a check to ensure that we only attempt to unify a projection predicatre with inference variables. However, the check it added was too strict - instead of checking that a type *contains* an inference variable (e.g. '&_', 'MyType<_>'), it required the type to *be* an inference variable (i.e. only '_' would match). This commit relaxes the check to use 'ty.has_infer_types', ensuring that we perform unification wherever possible. Fixes #56822 --- src/librustc/traits/auto_trait.rs | 4 ++-- src/test/rustdoc/issue-56822.rs | 34 +++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 src/test/rustdoc/issue-56822.rs diff --git a/src/librustc/traits/auto_trait.rs b/src/librustc/traits/auto_trait.rs index a0237348ea690..c590b34e6b7ab 100644 --- a/src/librustc/traits/auto_trait.rs +++ b/src/librustc/traits/auto_trait.rs @@ -742,9 +742,9 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { } // We can only call poly_project_and_unify_type when our predicate's - // Ty is an inference variable - otherwise, there won't be anything to + // Ty contains an inference variable - otherwise, there won't be anything to // unify - if p.ty().skip_binder().is_ty_infer() { + if p.ty().skip_binder().has_infer_types() { debug!("Projecting and unifying projection predicate {:?}", predicate); match poly_project_and_unify_type(select, &obligation.with(p.clone())) { diff --git a/src/test/rustdoc/issue-56822.rs b/src/test/rustdoc/issue-56822.rs new file mode 100644 index 0000000000000..41aba1a007ad8 --- /dev/null +++ b/src/test/rustdoc/issue-56822.rs @@ -0,0 +1,34 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Wrapper(T); + +trait MyTrait { + type Output; +} + +impl<'a, I, T: 'a> MyTrait for Wrapper + where I: MyTrait +{ + type Output = T; +} + +struct Inner<'a, T>(&'a T); + +impl<'a, T> MyTrait for Inner<'a, T> { + type Output = &'a T; +} + +// @has issue_56822/struct.Parser.html +// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl<'a> Send for \ +// Parser<'a>" +pub struct Parser<'a> { + field: > as MyTrait>::Output +}