From e6376a15b4f22bc296a832d232937add7e04511d Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 24 Jan 2018 13:14:58 +0000 Subject: [PATCH 01/29] Added test for #45157 --- src/test/ui/issue-45157.rs | 43 ++++++++++++++++++++++++++++++++++ src/test/ui/issue-45157.stderr | 20 ++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 src/test/ui/issue-45157.rs create mode 100644 src/test/ui/issue-45157.stderr diff --git a/src/test/ui/issue-45157.rs b/src/test/ui/issue-45157.rs new file mode 100644 index 0000000000000..cff338f76c507 --- /dev/null +++ b/src/test/ui/issue-45157.rs @@ -0,0 +1,43 @@ +// Copyright 2017 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. + +#![allow(unused)] +#![feature(nll)] + +#[derive(Clone, Copy, Default)] +struct S { + a: u8, + b: u8, +} +#[derive(Clone, Copy, Default)] +struct Z { + c: u8, + d: u8, +} + +union U { + s: S, + z: Z, +} + +fn main() { + unsafe { + let mut u = U { s: Default::default() }; + + let mref = &mut u.s.a; + *mref = 22; + + let nref = &u.z.c; + //~^ ERROR cannot borrow `u.z.c` as immutable because it is also borrowed as mutable [E0502] + println!("{} {}", mref, nref) + //~^ ERROR cannot borrow `u.s.a` as mutable because it is also borrowed as immutable [E0502] + } +} + diff --git a/src/test/ui/issue-45157.stderr b/src/test/ui/issue-45157.stderr new file mode 100644 index 0000000000000..e133aab31bc01 --- /dev/null +++ b/src/test/ui/issue-45157.stderr @@ -0,0 +1,20 @@ +error[E0502]: cannot borrow `u.z.c` as immutable because it is also borrowed as mutable + --> $DIR/issue-45157.rs:37:20 + | +34 | let mref = &mut u.s.a; + | ---------- mutable borrow occurs here +... +37 | let nref = &u.z.c; + | ^^^^^^ immutable borrow occurs here + +error[E0502]: cannot borrow `u.s.a` as mutable because it is also borrowed as immutable + --> $DIR/issue-45157.rs:39:27 + | +37 | let nref = &u.z.c; + | ------ immutable borrow occurs here +38 | //~^ ERROR cannot borrow `u.z.c` as immutable because it is also borrowed as mutable [E0502] +39 | println!("{} {}", mref, nref) + | ^^^^ mutable borrow occurs here + +error: aborting due to 2 previous errors + From 467b5cfcb70c6a0f4b681f90219ce7d490980a47 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 10 Feb 2018 01:26:19 +0100 Subject: [PATCH 02/29] stabilize (version: 1.26.0) Box::leak, cc #46179 --- src/liballoc/boxed.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index cdaad973a7123..a831391d16827 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -381,8 +381,7 @@ impl Box { /// assert_eq!(*static_ref, [4, 2, 3]); /// } /// ``` - #[unstable(feature = "box_leak", reason = "needs an FCP to stabilize", - issue = "46179")] + #[stable(feature = "box_leak", since = "1.26.0")] #[inline] pub fn leak<'a>(b: Box) -> &'a mut T where From 486160335c70c4a4b39ce8262314bc1bd63012ca Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 10 Feb 2018 01:39:22 +0100 Subject: [PATCH 03/29] stabilize Box::leak: remove #![feature(box_leak)] in docs --- src/liballoc/boxed.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index a831391d16827..75a59de337cef 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -359,8 +359,6 @@ impl Box { /// Simple usage: /// /// ``` - /// #![feature(box_leak)] - /// /// fn main() { /// let x = Box::new(41); /// let static_ref: &'static mut usize = Box::leak(x); @@ -372,8 +370,6 @@ impl Box { /// Unsized data: /// /// ``` - /// #![feature(box_leak)] - /// /// fn main() { /// let x = vec![1, 2, 3].into_boxed_slice(); /// let static_ref = Box::leak(x); From 3118cbe41c7ce50c3451fd4575ca04a83b0d3e05 Mon Sep 17 00:00:00 2001 From: bobtwinkles Date: Tue, 13 Feb 2018 20:28:10 -0500 Subject: [PATCH 04/29] Allow two-phase borrows of &mut self in ops We need two-phase borrows of ops to be in the initial NLL release since without them lots of existing code will break. Fixes #48129 --- src/librustc_typeck/check/op.rs | 14 +++-- .../borrowck/two-phase-nonrecv-autoref.rs | 53 ------------------- .../run-pass/borrowck/two-phase-bin-ops.rs | 49 +++++++++++++++++ 3 files changed, 55 insertions(+), 61 deletions(-) create mode 100644 src/test/run-pass/borrowck/two-phase-bin-ops.rs diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index a6776a0fe8612..a3dbf344ab7e0 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -201,10 +201,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mutbl = match mt.mutbl { hir::MutImmutable => AutoBorrowMutability::Immutable, hir::MutMutable => AutoBorrowMutability::Mutable { - // For initial two-phase borrow - // deployment, conservatively omit - // overloaded binary ops. - allow_two_phase_borrow: false, + // Allow two-phase borrows for binops in initial deployment + // since they desugar to methods + allow_two_phase_borrow: true, } }; let autoref = Adjustment { @@ -219,10 +218,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mutbl = match mt.mutbl { hir::MutImmutable => AutoBorrowMutability::Immutable, hir::MutMutable => AutoBorrowMutability::Mutable { - // For initial two-phase borrow - // deployment, conservatively omit - // overloaded binary ops. - allow_two_phase_borrow: false, + // Allow two-phase borrows for binops in initial deployment + // since they desugar to methods + allow_two_phase_borrow: true, } }; let autoref = Adjustment { diff --git a/src/test/compile-fail/borrowck/two-phase-nonrecv-autoref.rs b/src/test/compile-fail/borrowck/two-phase-nonrecv-autoref.rs index 795d45a776db5..a57e2fe1cc6d3 100644 --- a/src/test/compile-fail/borrowck/two-phase-nonrecv-autoref.rs +++ b/src/test/compile-fail/borrowck/two-phase-nonrecv-autoref.rs @@ -30,8 +30,6 @@ // #![feature(rustc_attrs)] use std::ops::{Index, IndexMut}; -use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign}; -use std::ops::{BitAndAssign, BitOrAssign, BitXorAssign, ShlAssign, ShrAssign}; // This is case outlined by Niko that we want to ensure we reject // (at least initially). @@ -186,56 +184,6 @@ fn coerce_index_op() { //[nll]~^^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502] } -struct A(i32); - -macro_rules! trivial_binop { - ($Trait:ident, $m:ident) => { - impl $Trait for A { fn $m(&mut self, rhs: i32) { self.0 = rhs; } } - } -} - -trivial_binop!(AddAssign, add_assign); -trivial_binop!(SubAssign, sub_assign); -trivial_binop!(MulAssign, mul_assign); -trivial_binop!(DivAssign, div_assign); -trivial_binop!(RemAssign, rem_assign); -trivial_binop!(BitAndAssign, bitand_assign); -trivial_binop!(BitOrAssign, bitor_assign); -trivial_binop!(BitXorAssign, bitxor_assign); -trivial_binop!(ShlAssign, shl_assign); -trivial_binop!(ShrAssign, shr_assign); - -fn overloaded_binops() { - let mut a = A(10); - a += a.0; - //[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed - //[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed - a -= a.0; - //[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed - //[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed - a *= a.0; - //[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed - //[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed - a /= a.0; - //[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed - //[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed - a &= a.0; - //[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed - //[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed - a |= a.0; - //[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed - //[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed - a ^= a.0; - //[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed - //[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed - a <<= a.0; - //[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed - //[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed - a >>= a.0; - //[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed - //[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed -} - fn main() { // As a reminder, this is the basic case we want to ensure we handle. @@ -256,5 +204,4 @@ fn main() { coerce_unsized(); coerce_index_op(); - overloaded_binops(); } diff --git a/src/test/run-pass/borrowck/two-phase-bin-ops.rs b/src/test/run-pass/borrowck/two-phase-bin-ops.rs new file mode 100644 index 0000000000000..9bded41e1f933 --- /dev/null +++ b/src/test/run-pass/borrowck/two-phase-bin-ops.rs @@ -0,0 +1,49 @@ +// 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. + +// revisions: lxl nll +//[lxl]compile-flags: -Z borrowck=mir -Z two-phase-borrows + +#![cfg_attr(nll, feature(nll))] + +use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign}; +use std::ops::{BitAndAssign, BitOrAssign, BitXorAssign, ShlAssign, ShrAssign}; + +struct A(i32); + +macro_rules! trivial_binop { + ($Trait:ident, $m:ident) => { + impl $Trait for A { fn $m(&mut self, rhs: i32) { self.0 = rhs; } } + } +} + +trivial_binop!(AddAssign, add_assign); +trivial_binop!(SubAssign, sub_assign); +trivial_binop!(MulAssign, mul_assign); +trivial_binop!(DivAssign, div_assign); +trivial_binop!(RemAssign, rem_assign); +trivial_binop!(BitAndAssign, bitand_assign); +trivial_binop!(BitOrAssign, bitor_assign); +trivial_binop!(BitXorAssign, bitxor_assign); +trivial_binop!(ShlAssign, shl_assign); +trivial_binop!(ShrAssign, shr_assign); + +fn main() { + let mut a = A(10); + a += a.0; + a -= a.0; + a *= a.0; + a /= a.0; + a &= a.0; + a |= a.0; + a ^= a.0; + a <<= a.0; + a >>= a.0; +} From 7062955ad9186c3a8cd785ecf90bc10f1949b16a Mon Sep 17 00:00:00 2001 From: bobtwinkles Date: Thu, 15 Feb 2018 01:25:29 -0500 Subject: [PATCH 05/29] Fix arguments specified by lxl in two-phase-bin-ops test --- src/test/run-pass/borrowck/two-phase-bin-ops.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/run-pass/borrowck/two-phase-bin-ops.rs b/src/test/run-pass/borrowck/two-phase-bin-ops.rs index 9bded41e1f933..1b2529d7875ab 100644 --- a/src/test/run-pass/borrowck/two-phase-bin-ops.rs +++ b/src/test/run-pass/borrowck/two-phase-bin-ops.rs @@ -9,7 +9,6 @@ // except according to those terms. // revisions: lxl nll -//[lxl]compile-flags: -Z borrowck=mir -Z two-phase-borrows #![cfg_attr(nll, feature(nll))] From cf6e2f53ba72888174224e30709c03128671252f Mon Sep 17 00:00:00 2001 From: boats Date: Tue, 20 Feb 2018 13:28:51 -0800 Subject: [PATCH 06/29] Add nonstandard_style alias for bad_style. --- src/librustc_lint/lib.rs | 6 ++ .../ui/lint/lint-group-nonstandard-style.rs | 36 ++++++++++ .../lint/lint-group-nonstandard-style.stderr | 67 +++++++++++++++++++ 3 files changed, 109 insertions(+) create mode 100644 src/test/ui/lint/lint-group-nonstandard-style.rs create mode 100644 src/test/ui/lint/lint-group-nonstandard-style.stderr diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 699765dde03ff..f3c6ff2f2b3a1 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -152,6 +152,12 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { NON_SNAKE_CASE, NON_UPPER_CASE_GLOBALS); + add_lint_group!(sess, + "nonstandard_style", + NON_CAMEL_CASE_TYPES, + NON_SNAKE_CASE, + NON_UPPER_CASE_GLOBALS); + add_lint_group!(sess, "unused", UNUSED_IMPORTS, diff --git a/src/test/ui/lint/lint-group-nonstandard-style.rs b/src/test/ui/lint/lint-group-nonstandard-style.rs new file mode 100644 index 0000000000000..14fcf6d821a96 --- /dev/null +++ b/src/test/ui/lint/lint-group-nonstandard-style.rs @@ -0,0 +1,36 @@ +// Copyright 2014–2017 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. + +#![deny(nonstandard_style)] +#![allow(dead_code)] + +fn CamelCase() {} //~ ERROR should have a snake + +#[allow(bad_style)] +mod test { + fn CamelCase() {} + + #[forbid(bad_style)] + mod bad { + fn CamelCase() {} //~ ERROR should have a snake + + static bad: isize = 1; //~ ERROR should have an upper + } + + mod warn { + #![warn(bad_style)] + + fn CamelCase() {} //~ WARN should have a snake + + struct snake_case; //~ WARN should have a camel + } +} + +fn main() {} diff --git a/src/test/ui/lint/lint-group-nonstandard-style.stderr b/src/test/ui/lint/lint-group-nonstandard-style.stderr new file mode 100644 index 0000000000000..3466bee74061f --- /dev/null +++ b/src/test/ui/lint/lint-group-nonstandard-style.stderr @@ -0,0 +1,67 @@ +error: function `CamelCase` should have a snake case name such as `camel_case` + --> $DIR/lint-group-style.rs:14:1 + | +14 | fn CamelCase() {} //~ ERROR should have a snake + | ^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/lint-group-style.rs:11:9 + | +11 | #![deny(nonstandard_style)] + | ^^^^^^^^^ + = note: #[deny(non_snake_case)] implied by #[deny(nonstandard_style)] + +error: function `CamelCase` should have a snake case name such as `camel_case` + --> $DIR/lint-group-style.rs:22:9 + | +22 | fn CamelCase() {} //~ ERROR should have a snake + | ^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/lint-group-style.rs:20:14 + | +20 | #[forbid(nonstandard_style)] + | ^^^^^^^^^ + = note: #[forbid(non_snake_case)] implied by #[forbid(nonstandard_style)] + +error: static variable `bad` should have an upper case name such as `BAD` + --> $DIR/lint-group-style.rs:24:9 + | +24 | static bad: isize = 1; //~ ERROR should have an upper + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/lint-group-style.rs:20:14 + | +20 | #[forbid(nonstandard_style)] + | ^^^^^^^^^ + = note: #[forbid(non_upper_case_globals)] implied by #[forbid(nonstandard_style)] + +warning: function `CamelCase` should have a snake case name such as `camel_case` + --> $DIR/lint-group-style.rs:30:9 + | +30 | fn CamelCase() {} //~ WARN should have a snake + | ^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/lint-group-style.rs:28:17 + | +28 | #![warn(nonstandard_style)] + | ^^^^^^^^^ + = note: #[warn(non_snake_case)] implied by #[warn(nonstandard_style)] + +warning: type `snake_case` should have a camel case name such as `SnakeCase` + --> $DIR/lint-group-style.rs:32:9 + | +32 | struct snake_case; //~ WARN should have a camel + | ^^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/lint-group-style.rs:28:17 + | +28 | #![warn(nonstandard_style)] + | ^^^^^^^^^ + = note: #[warn(non_camel_case_types)] implied by #[warn(nonstandard_style)] + +error: aborting due to 3 previous errors + From 6fe5f42e373997c1f5bea2f002c6d6fbe8762c72 Mon Sep 17 00:00:00 2001 From: boats Date: Tue, 20 Feb 2018 13:38:46 -0800 Subject: [PATCH 07/29] Fix carets. --- src/test/ui/lint/lint-group-nonstandard-style.stderr | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/ui/lint/lint-group-nonstandard-style.stderr b/src/test/ui/lint/lint-group-nonstandard-style.stderr index 3466bee74061f..1e055973bb2a6 100644 --- a/src/test/ui/lint/lint-group-nonstandard-style.stderr +++ b/src/test/ui/lint/lint-group-nonstandard-style.stderr @@ -8,7 +8,7 @@ note: lint level defined here --> $DIR/lint-group-style.rs:11:9 | 11 | #![deny(nonstandard_style)] - | ^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ = note: #[deny(non_snake_case)] implied by #[deny(nonstandard_style)] error: function `CamelCase` should have a snake case name such as `camel_case` @@ -21,7 +21,7 @@ note: lint level defined here --> $DIR/lint-group-style.rs:20:14 | 20 | #[forbid(nonstandard_style)] - | ^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ = note: #[forbid(non_snake_case)] implied by #[forbid(nonstandard_style)] error: static variable `bad` should have an upper case name such as `BAD` @@ -34,7 +34,7 @@ note: lint level defined here --> $DIR/lint-group-style.rs:20:14 | 20 | #[forbid(nonstandard_style)] - | ^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ = note: #[forbid(non_upper_case_globals)] implied by #[forbid(nonstandard_style)] warning: function `CamelCase` should have a snake case name such as `camel_case` @@ -47,7 +47,7 @@ note: lint level defined here --> $DIR/lint-group-style.rs:28:17 | 28 | #![warn(nonstandard_style)] - | ^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ = note: #[warn(non_snake_case)] implied by #[warn(nonstandard_style)] warning: type `snake_case` should have a camel case name such as `SnakeCase` @@ -60,7 +60,7 @@ note: lint level defined here --> $DIR/lint-group-style.rs:28:17 | 28 | #![warn(nonstandard_style)] - | ^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ = note: #[warn(non_camel_case_types)] implied by #[warn(nonstandard_style)] error: aborting due to 3 previous errors From 21e2a5e8d8bd09830a417b9801ff81b08b7c0c7e Mon Sep 17 00:00:00 2001 From: boats Date: Tue, 20 Feb 2018 14:44:39 -0800 Subject: [PATCH 08/29] Fix filepath in lint test. --- .../lint/lint-group-nonstandard-style.stderr | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/test/ui/lint/lint-group-nonstandard-style.stderr b/src/test/ui/lint/lint-group-nonstandard-style.stderr index 1e055973bb2a6..b0ce19e35eec7 100644 --- a/src/test/ui/lint/lint-group-nonstandard-style.stderr +++ b/src/test/ui/lint/lint-group-nonstandard-style.stderr @@ -1,63 +1,63 @@ error: function `CamelCase` should have a snake case name such as `camel_case` - --> $DIR/lint-group-style.rs:14:1 + --> $DIR/lint-group-nonstandard-style.rs:14:1 | 14 | fn CamelCase() {} //~ ERROR should have a snake | ^^^^^^^^^^^^^^^^^ | note: lint level defined here - --> $DIR/lint-group-style.rs:11:9 + --> $DIR/lint-group-nonstandard-style.rs:11:9 | 11 | #![deny(nonstandard_style)] | ^^^^^^^^^^^^^^^^^ = note: #[deny(non_snake_case)] implied by #[deny(nonstandard_style)] error: function `CamelCase` should have a snake case name such as `camel_case` - --> $DIR/lint-group-style.rs:22:9 + --> $DIR/lint-group-nonstandard-style.rs:22:9 | 22 | fn CamelCase() {} //~ ERROR should have a snake | ^^^^^^^^^^^^^^^^^ | note: lint level defined here - --> $DIR/lint-group-style.rs:20:14 + --> $DIR/lint-group-nonstandard-style.rs:20:14 | 20 | #[forbid(nonstandard_style)] | ^^^^^^^^^^^^^^^^^ = note: #[forbid(non_snake_case)] implied by #[forbid(nonstandard_style)] error: static variable `bad` should have an upper case name such as `BAD` - --> $DIR/lint-group-style.rs:24:9 + --> $DIR/lint-group-nonstandard-style.rs:24:9 | 24 | static bad: isize = 1; //~ ERROR should have an upper | ^^^^^^^^^^^^^^^^^^^^^^ | note: lint level defined here - --> $DIR/lint-group-style.rs:20:14 + --> $DIR/lint-group-nonstandard-style.rs:20:14 | 20 | #[forbid(nonstandard_style)] | ^^^^^^^^^^^^^^^^^ = note: #[forbid(non_upper_case_globals)] implied by #[forbid(nonstandard_style)] warning: function `CamelCase` should have a snake case name such as `camel_case` - --> $DIR/lint-group-style.rs:30:9 + --> $DIR/lint-group-nonstandard-style.rs:30:9 | 30 | fn CamelCase() {} //~ WARN should have a snake | ^^^^^^^^^^^^^^^^^ | note: lint level defined here - --> $DIR/lint-group-style.rs:28:17 + --> $DIR/lint-group-nonstandard-style.rs:28:17 | 28 | #![warn(nonstandard_style)] | ^^^^^^^^^^^^^^^^^ = note: #[warn(non_snake_case)] implied by #[warn(nonstandard_style)] warning: type `snake_case` should have a camel case name such as `SnakeCase` - --> $DIR/lint-group-style.rs:32:9 + --> $DIR/lint-group-nonstandard-style.rs:32:9 | 32 | struct snake_case; //~ WARN should have a camel | ^^^^^^^^^^^^^^^^^^ | note: lint level defined here - --> $DIR/lint-group-style.rs:28:17 + --> $DIR/lint-group-nonstandard-style.rs:28:17 | 28 | #![warn(nonstandard_style)] | ^^^^^^^^^^^^^^^^^ From 5949d8b2d7b2bd01cfa454b029e7d921aedd7e27 Mon Sep 17 00:00:00 2001 From: boats Date: Tue, 20 Feb 2018 15:57:16 -0800 Subject: [PATCH 09/29] Fix internal references to bad_style in test code. --- src/test/ui/lint/lint-group-nonstandard-style.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/ui/lint/lint-group-nonstandard-style.rs b/src/test/ui/lint/lint-group-nonstandard-style.rs index 14fcf6d821a96..55d6168e6e008 100644 --- a/src/test/ui/lint/lint-group-nonstandard-style.rs +++ b/src/test/ui/lint/lint-group-nonstandard-style.rs @@ -13,11 +13,11 @@ fn CamelCase() {} //~ ERROR should have a snake -#[allow(bad_style)] +#[allow(nonstandard_style)] mod test { fn CamelCase() {} - #[forbid(bad_style)] + #[forbid(nonstandard_style)] mod bad { fn CamelCase() {} //~ ERROR should have a snake @@ -25,7 +25,7 @@ mod test { } mod warn { - #![warn(bad_style)] + #![warn(nonstandard_style)] fn CamelCase() {} //~ WARN should have a snake From 20bc72e693372940183e97a32e7d07d2f9180182 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 20 Feb 2018 22:46:51 -0800 Subject: [PATCH 10/29] Handle custom diagnostic for `&str + String` --- src/librustc_typeck/check/op.rs | 69 ++++++++++++++++++----------- src/test/ui/span/issue-39018.rs | 3 ++ src/test/ui/span/issue-39018.stderr | 16 ++++++- 3 files changed, 61 insertions(+), 27 deletions(-) diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index a6776a0fe8612..646cd061a0712 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -13,7 +13,7 @@ use super::{FnCtxt, Needs}; use super::method::MethodCallee; use rustc::ty::{self, Ty, TypeFoldable, TypeVariants}; -use rustc::ty::TypeVariants::{TyStr, TyRef}; +use rustc::ty::TypeVariants::{TyStr, TyRef, TyAdt}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability}; use rustc::infer::type_variable::TypeVariableOrigin; use errors; @@ -301,7 +301,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(missing_trait) = missing_trait { if missing_trait == "std::ops::Add" && - self.check_str_addition(expr, lhs_expr, lhs_ty, + self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty, rhs_ty, &mut err) { // This has nothing here because it means we did string // concatenation (e.g. "Hello " + "World!"). This means @@ -330,37 +330,54 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn check_str_addition(&self, expr: &'gcx hir::Expr, lhs_expr: &'gcx hir::Expr, + rhs_expr: &'gcx hir::Expr, lhs_ty: Ty<'tcx>, rhs_ty: Ty<'tcx>, err: &mut errors::DiagnosticBuilder) -> bool { + let codemap = self.tcx.sess.codemap(); + let msg = "`to_owned()` can be used to create an owned `String` \ + from a string reference. String concatenation \ + appends the string on the right to the string \ + on the left and may require reallocation. This \ + requires ownership of the string on the left"; // If this function returns true it means a note was printed, so we don't need // to print the normal "implementation of `std::ops::Add` might be missing" note - let mut is_string_addition = false; - if let TyRef(_, l_ty) = lhs_ty.sty { - if let TyRef(_, r_ty) = rhs_ty.sty { - if l_ty.ty.sty == TyStr && r_ty.ty.sty == TyStr { - err.span_label(expr.span, - "`+` can't be used to concatenate two `&str` strings"); - let codemap = self.tcx.sess.codemap(); - let suggestion = - match codemap.span_to_snippet(lhs_expr.span) { - Ok(lstring) => format!("{}.to_owned()", lstring), - _ => format!("") - }; - err.span_suggestion(lhs_expr.span, - &format!("`to_owned()` can be used to create an owned `String` \ - from a string reference. String concatenation \ - appends the string on the right to the string \ - on the left and may require reallocation. This \ - requires ownership of the string on the left"), suggestion); - is_string_addition = true; - } - + match (&lhs_ty.sty, &rhs_ty.sty) { + (&TyRef(_, ref l_ty), &TyRef(_, ref r_ty)) + if l_ty.ty.sty == TyStr && r_ty.ty.sty == TyStr => { + err.span_label(expr.span, + "`+` can't be used to concatenate two `&str` strings"); + match codemap.span_to_snippet(lhs_expr.span) { + Ok(lstring) => err.span_suggestion(lhs_expr.span, + msg, + format!("{}.to_owned()", lstring)), + _ => err.help(msg), + }; + true } - + (&TyRef(_, ref l_ty), &TyAdt(..)) + if l_ty.ty.sty == TyStr && &format!("{:?}", rhs_ty) == "std::string::String" => { + err.span_label(expr.span, + "`+` can't be used to concatenate a `&str` with a `String`"); + match codemap.span_to_snippet(lhs_expr.span) { + Ok(lstring) => err.span_suggestion(lhs_expr.span, + msg, + format!("{}.to_owned()", lstring)), + _ => err.help(msg), + }; + match codemap.span_to_snippet(rhs_expr.span) { + Ok(rstring) => { + err.span_suggestion(rhs_expr.span, + "you also need to borrow the `String` on the right to \ + get a `&str`", + format!("&{}", rstring)); + } + _ => {} + }; + true + } + _ => false, } - - is_string_addition } pub fn check_user_unop(&self, diff --git a/src/test/ui/span/issue-39018.rs b/src/test/ui/span/issue-39018.rs index 4c9d10ba46bc8..7b3288fd29cc1 100644 --- a/src/test/ui/span/issue-39018.rs +++ b/src/test/ui/span/issue-39018.rs @@ -17,6 +17,9 @@ pub fn main() { // that won't output for the above string concatenation let y = World::Hello + World::Goodbye; //~^ ERROR cannot be applied to type + + let x = "Hello " + "World!".to_owned(); + //~^ ERROR cannot be applied to type } enum World { diff --git a/src/test/ui/span/issue-39018.stderr b/src/test/ui/span/issue-39018.stderr index db662a1df5972..70f8ecf42cb2d 100644 --- a/src/test/ui/span/issue-39018.stderr +++ b/src/test/ui/span/issue-39018.stderr @@ -16,5 +16,19 @@ error[E0369]: binary operation `+` cannot be applied to type `World` | = note: an implementation of `std::ops::Add` might be missing for `World` -error: aborting due to 2 previous errors +error[E0369]: binary operation `+` cannot be applied to type `&str` + --> $DIR/issue-39018.rs:21:13 + | +21 | let x = "Hello " + "World!".to_owned(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `+` can't be used to concatenate a `&str` with a `String` +help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + | +21 | let x = "Hello ".to_owned() + "World!".to_owned(); + | ^^^^^^^^^^^^^^^^^^^ +help: you also need to borrow the `String` on the right to get a `&str` + | +21 | let x = "Hello " + &"World!".to_owned(); + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors From ef48e0f2b91117898b71f5c85fddf6619c434753 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Wed, 21 Feb 2018 13:32:24 -0500 Subject: [PATCH 11/29] Update the book to promote second edition This updates the book repository, but mostly to include https://github.com/rust-lang/book/pull/1180 TL;DR: the second edition is close enough to done that we should universally recommend it over the first edition. --- src/doc/book | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/book b/src/doc/book index ec5660820dea9..98921e9de849a 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit ec5660820dea91df470dab0b9eb26ef798f20889 +Subproject commit 98921e9de849acdaeaed08cfad6758bb89769b7d From d98449d110fe49355ae265623a5bbf6796525c92 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Wed, 21 Feb 2018 17:44:49 -0600 Subject: [PATCH 12/29] manually release `cx.external_traits` while building the new trait --- src/librustdoc/clean/inline.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 9aba399b3b09f..c09c6eab4d25f 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -494,7 +494,11 @@ fn separate_supertrait_bounds(mut g: clean::Generics) } pub fn record_extern_trait(cx: &DocContext, did: DefId) { - cx.external_traits.borrow_mut().entry(did).or_insert_with(|| { - build_external_trait(cx, did) - }); + if cx.external_traits.borrow().contains_key(did) { + return; + } + + let trait_ = build_external_trait(cx, did); + + cx.external_traits.borrow_mut().insert(did, trait_); } From ef30a8fd1cd1efa1086a82976873490518fcb323 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Wed, 21 Feb 2018 18:33:42 -0600 Subject: [PATCH 13/29] track extern traits being inlined --- src/librustdoc/clean/inline.rs | 7 ++++++- src/librustdoc/core.rs | 4 ++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index c09c6eab4d25f..458c655df1d8a 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -494,11 +494,16 @@ fn separate_supertrait_bounds(mut g: clean::Generics) } pub fn record_extern_trait(cx: &DocContext, did: DefId) { - if cx.external_traits.borrow().contains_key(did) { + if cx.external_traits.borrow().contains_key(&did) && + cx.active_extern_traits.borrow().contains(&did) + { return; } + cx.active_extern_traits.borrow_mut().push(did); + let trait_ = build_external_trait(cx, did); cx.external_traits.borrow_mut().insert(did, trait_); + cx.active_extern_traits.borrow_mut().remove_item(&did); } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 81babd803a5e9..e5d696882ab80 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -58,6 +58,9 @@ pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a> { pub renderinfo: RefCell, /// Later on moved through `clean::Crate` into `html::render::CACHE_KEY` pub external_traits: RefCell>, + /// Used while populating `external_traits` to ensure we don't process the same trait twice at + /// the same time. + pub active_extern_traits: RefCell>, // The current set of type and lifetime substitutions, // for expanding type aliases at the HIR level: @@ -236,6 +239,7 @@ pub fn run_core(search_paths: SearchPaths, populated_all_crate_impls: Cell::new(false), access_levels: RefCell::new(access_levels), external_traits: Default::default(), + active_extern_traits: Default::default(), renderinfo: Default::default(), ty_substs: Default::default(), lt_substs: Default::default(), From bca3b31ab94c49ff32758690a0eeed29fe87ccf5 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Wed, 21 Feb 2018 19:57:48 -0600 Subject: [PATCH 14/29] proper early-bail condition --- src/librustdoc/clean/inline.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 458c655df1d8a..7b0073dc65c9b 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -494,7 +494,7 @@ fn separate_supertrait_bounds(mut g: clean::Generics) } pub fn record_extern_trait(cx: &DocContext, did: DefId) { - if cx.external_traits.borrow().contains_key(&did) && + if cx.external_traits.borrow().contains_key(&did) || cx.active_extern_traits.borrow().contains(&did) { return; From 8872e7b593e0e7a6c5fdf519beb878b74be994e8 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Wed, 21 Feb 2018 19:58:20 -0600 Subject: [PATCH 15/29] add test for issue 48414 ICE --- src/test/rustdoc/auxiliary/issue-48414.rs | 15 +++++++++++++++ src/test/rustdoc/issue-48414.rs | 21 +++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 src/test/rustdoc/auxiliary/issue-48414.rs create mode 100644 src/test/rustdoc/issue-48414.rs diff --git a/src/test/rustdoc/auxiliary/issue-48414.rs b/src/test/rustdoc/auxiliary/issue-48414.rs new file mode 100644 index 0000000000000..7e0edf76f6ac9 --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-48414.rs @@ -0,0 +1,15 @@ +// Copyright 2015 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. + +/// Woah, this trait links to [OtherTrait](OtherTrait)! +pub trait SomeTrait {} + +/// Woah, this trait links to [SomeTrait](SomeTrait)! +pub trait OtherTrait {} diff --git a/src/test/rustdoc/issue-48414.rs b/src/test/rustdoc/issue-48414.rs new file mode 100644 index 0000000000000..0136f9c4759c7 --- /dev/null +++ b/src/test/rustdoc/issue-48414.rs @@ -0,0 +1,21 @@ +// Copyright 2015 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. + +// aux-build:issue-48414.rs + +// ICE when resolving paths for a trait that linked to another trait, when both were in an external +// crate + +#![crate_name = "base"] + +extern crate issue_48414; + +#[doc(inline)] +pub use issue_48414::{SomeTrait, OtherTrait}; From 0e26bb728784c8e98c8e67eb2c60e88733167d03 Mon Sep 17 00:00:00 2001 From: Tatsuyuki Ishi Date: Sun, 18 Feb 2018 11:36:41 +0900 Subject: [PATCH 16/29] Revert "Implement Ord as necessary" This reverts commit c6772b4dcb95137e88d5cd1814ce0051f74a3c29. --- src/librustc/traits/project.rs | 2 +- src/librustc/ty/mod.rs | 30 +----------------------------- src/librustc/ty/sty.rs | 4 ++-- src/librustc/ty/subst.rs | 2 +- 4 files changed, 5 insertions(+), 33 deletions(-) diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index ae539f07336d5..7ae9691194158 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -101,7 +101,7 @@ pub struct MismatchedProjectionTypes<'tcx> { pub err: ty::error::TypeError<'tcx> } -#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)] +#[derive(PartialEq, Eq, Debug)] enum ProjectionTyCandidate<'tcx> { // from a where-clause in the env or object type ParamEnv(ty::PolyProjectionPredicate<'tcx>), diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index f52f2ea0f9fc8..14d33b0729aae 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -39,7 +39,6 @@ use util::nodemap::{NodeSet, DefIdMap, FxHashMap, FxHashSet}; use serialize::{self, Encodable, Encoder}; use std::cell::RefCell; use std::cmp; -use std::cmp::Ordering; use std::fmt; use std::hash::{Hash, Hasher}; use std::iter::FromIterator; @@ -498,20 +497,6 @@ impl<'tcx> Hash for TyS<'tcx> { } } -impl<'tcx> Ord for TyS<'tcx> { - #[inline] - fn cmp(&self, other: &TyS<'tcx>) -> Ordering { - // (self as *const _).cmp(other as *const _) - (self as *const TyS<'tcx>).cmp(&(other as *const TyS<'tcx>)) - } -} -impl<'tcx> PartialOrd for TyS<'tcx> { - #[inline] - fn partial_cmp(&self, other: &TyS<'tcx>) -> Option { - Some(self.cmp(other)) - } -} - impl<'tcx> TyS<'tcx> { pub fn is_primitive_ty(&self) -> bool { match self.sty { @@ -581,19 +566,6 @@ impl PartialEq for Slice { } impl Eq for Slice {} -impl Ord for Slice { - #[inline] - fn cmp(&self, other: &Slice) -> Ordering { - (&self.0 as *const [T]).cmp(&(&other.0 as *const [T])) - } -} -impl PartialOrd for Slice { - #[inline] - fn partial_cmp(&self, other: &Slice) -> Option { - Some(self.cmp(other)) - } -} - impl Hash for Slice { fn hash(&self, s: &mut H) { (self.as_ptr(), self.len()).hash(s) @@ -1128,7 +1100,7 @@ pub type PolySubtypePredicate<'tcx> = ty::Binder>; /// equality between arbitrary types. Processing an instance of /// Form #2 eventually yields one of these `ProjectionPredicate` /// instances to normalize the LHS. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct ProjectionPredicate<'tcx> { pub projection_ty: ProjectionTy<'tcx>, pub ty: Ty<'tcx>, diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 961c2650afdef..503418b044f4f 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -645,7 +645,7 @@ impl<'tcx> PolyExistentialTraitRef<'tcx> { /// erase, or otherwise "discharge" these bound regions, we change the /// type from `Binder` to just `T` (see /// e.g. `liberate_late_bound_regions`). -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct Binder(pub T); impl Binder { @@ -745,7 +745,7 @@ impl Binder { /// Represents the projection of an associated type. In explicit UFCS /// form this would be written `>::N`. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct ProjectionTy<'tcx> { /// The parameters of the associated item. pub substs: &'tcx Substs<'tcx>, diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 7c167f69ebd8c..80b113dfdf5a5 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -29,7 +29,7 @@ use std::mem; /// To reduce memory usage, a `Kind` is a interned pointer, /// with the lowest 2 bits being reserved for a tag to /// indicate the type (`Ty` or `Region`) it points to. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct Kind<'tcx> { ptr: NonZero, marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>)> From 93e6b0d643099beb95d16da91a833781ac6b8e95 Mon Sep 17 00:00:00 2001 From: Tatsuyuki Ishi Date: Sun, 18 Feb 2018 11:37:14 +0900 Subject: [PATCH 17/29] Remove needless dedup from projection --- src/librustc/traits/project.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 7ae9691194158..540f18343f546 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -835,16 +835,6 @@ fn project_type<'cx, 'gcx, 'tcx>( return Err(ProjectionTyError::TooManyCandidates); } - // Drop duplicates. - // - // Note: `candidates.vec` seems to be on the critical path of the - // compiler. Replacing it with an HashSet was also tried, which would - // render the following dedup unnecessary. The original comment indicated - // that it was 9% slower, but that data is now obsolete and a new - // benchmark should be performed. - candidates.vec.sort_unstable(); - candidates.vec.dedup(); - // Prefer where-clauses. As in select, if there are multiple // candidates, we prefer where-clause candidates over impls. This // may seem a bit surprising, since impls are the source of From 619ad716d1fad162d4cbc41f2b0ecf1b48181da6 Mon Sep 17 00:00:00 2001 From: Tatsuyuki Ishi Date: Sun, 18 Feb 2018 12:32:23 +0900 Subject: [PATCH 18/29] Fix exponential blowup on nested types --- src/librustc/traits/mod.rs | 6 +- src/librustc/traits/project.rs | 209 +++++++++++++++++---------------- 2 files changed, 114 insertions(+), 101 deletions(-) diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 41cc8ca601ac0..7f232b310c0b3 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -304,7 +304,7 @@ pub type SelectionResult<'tcx, T> = Result, SelectionError<'tcx>>; /// ### The type parameter `N` /// /// See explanation on `VtableImplData`. -#[derive(Clone, RustcEncodable, RustcDecodable)] +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub enum Vtable<'tcx, N> { /// Vtable identifying a particular impl. VtableImpl(VtableImplData<'tcx, N>), @@ -374,13 +374,13 @@ pub struct VtableClosureData<'tcx, N> { pub nested: Vec } -#[derive(Clone, RustcEncodable, RustcDecodable)] +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub struct VtableAutoImplData { pub trait_def_id: DefId, pub nested: Vec } -#[derive(Clone, RustcEncodable, RustcDecodable)] +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub struct VtableBuiltinData { pub nested: Vec } diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 540f18343f546..ca0f7a49f2023 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -16,6 +16,7 @@ use super::translate_substs; use super::Obligation; use super::ObligationCause; use super::PredicateObligation; +use super::Selection; use super::SelectionContext; use super::SelectionError; use super::VtableClosureData; @@ -110,12 +111,59 @@ enum ProjectionTyCandidate<'tcx> { TraitDef(ty::PolyProjectionPredicate<'tcx>), // from a "impl" (or a "pseudo-impl" returned by select) - Select, + Select(Selection<'tcx>), } -struct ProjectionTyCandidateSet<'tcx> { - vec: Vec>, - ambiguous: bool +enum ProjectionTyCandidateSet<'tcx> { + None, + Single(ProjectionTyCandidate<'tcx>), + Ambiguous, + Error(SelectionError<'tcx>), +} + +impl<'tcx> ProjectionTyCandidateSet<'tcx> { + fn mark_ambiguous(&mut self) { + *self = ProjectionTyCandidateSet::Ambiguous; + } + + fn mark_error(&mut self, err: SelectionError<'tcx>) { + *self = ProjectionTyCandidateSet::Error(err); + } + + // Returns true if the push was successful, or false if the candidate + // was discarded -- this could be because of ambiguity, or because + // a higher-priority candidate is already there. + fn push_candidate(&mut self, candidate: ProjectionTyCandidate<'tcx>) -> bool { + use self::ProjectionTyCandidateSet::*; + use self::ProjectionTyCandidate::*; + match self { + None => { + *self = Single(candidate); + true + } + Single(current) => { + // No duplicates are expected. + assert_ne!(current, &candidate); + // Prefer where-clauses. As in select, if there are multiple + // candidates, we prefer where-clause candidates over impls. This + // may seem a bit surprising, since impls are the source of + // "truth" in some sense, but in fact some of the impls that SEEM + // applicable are not, because of nested obligations. Where + // clauses are the safer choice. See the comment on + // `select::SelectionCandidate` and #21974 for more details. + match (current, candidate) { + (ParamEnv(..), ParamEnv(..)) => { *self = Ambiguous; } + (ParamEnv(..), _) => {} + (_, ParamEnv(..)) => { unreachable!(); } + (_, _) => { *self = Ambiguous; } + } + false + } + Ambiguous | Error(..) => { + false + } + } + } } /// Evaluates constraints of the form: @@ -803,11 +851,11 @@ fn project_type<'cx, 'gcx, 'tcx>( return Ok(ProjectedTy::Progress(Progress::error(selcx.tcx()))); } - let mut candidates = ProjectionTyCandidateSet { - vec: Vec::new(), - ambiguous: false, - }; + let mut candidates = ProjectionTyCandidateSet::None; + // Make sure that the following procedures are kept in order. ParamEnv + // needs to be first because it has highest priority, and Select checks + // the return value of push_candidate which assumes it's ran at last. assemble_candidates_from_param_env(selcx, obligation, &obligation_trait_ref, @@ -818,57 +866,27 @@ fn project_type<'cx, 'gcx, 'tcx>( &obligation_trait_ref, &mut candidates); - if let Err(e) = assemble_candidates_from_impls(selcx, - obligation, - &obligation_trait_ref, - &mut candidates) { - return Err(ProjectionTyError::TraitSelectionError(e)); - } - - debug!("{} candidates, ambiguous={}", - candidates.vec.len(), - candidates.ambiguous); - - // Inherent ambiguity that prevents us from even enumerating the - // candidates. - if candidates.ambiguous { - return Err(ProjectionTyError::TooManyCandidates); - } - - // Prefer where-clauses. As in select, if there are multiple - // candidates, we prefer where-clause candidates over impls. This - // may seem a bit surprising, since impls are the source of - // "truth" in some sense, but in fact some of the impls that SEEM - // applicable are not, because of nested obligations. Where - // clauses are the safer choice. See the comment on - // `select::SelectionCandidate` and #21974 for more details. - if candidates.vec.len() > 1 { - debug!("retaining param-env candidates only from {:?}", candidates.vec); - candidates.vec.retain(|c| match *c { - ProjectionTyCandidate::ParamEnv(..) => true, - ProjectionTyCandidate::TraitDef(..) | - ProjectionTyCandidate::Select => false, - }); - debug!("resulting candidate set: {:?}", candidates.vec); - if candidates.vec.len() != 1 { - return Err(ProjectionTyError::TooManyCandidates); - } - } - - assert!(candidates.vec.len() <= 1); + assemble_candidates_from_impls(selcx, + obligation, + &obligation_trait_ref, + &mut candidates); + + match candidates { + ProjectionTyCandidateSet::Single(candidate) => Ok(ProjectedTy::Progress( + confirm_candidate(selcx, + obligation, + &obligation_trait_ref, + candidate))), + ProjectionTyCandidateSet::None => Ok(ProjectedTy::NoProgress( + selcx.tcx().mk_projection( + obligation.predicate.item_def_id, + obligation.predicate.substs))), + // Error occurred while trying to processing impls. + ProjectionTyCandidateSet::Error(e) => Err(ProjectionTyError::TraitSelectionError(e)), + // Inherent ambiguity that prevents us from even enumerating the + // candidates. + ProjectionTyCandidateSet::Ambiguous => Err(ProjectionTyError::TooManyCandidates), - match candidates.vec.pop() { - Some(candidate) => { - Ok(ProjectedTy::Progress( - confirm_candidate(selcx, - obligation, - &obligation_trait_ref, - candidate))) - } - None => Ok(ProjectedTy::NoProgress( - selcx.tcx().mk_projection( - obligation.predicate.item_def_id, - obligation.predicate.substs))) } } @@ -918,7 +936,7 @@ fn assemble_candidates_from_trait_def<'cx, 'gcx, 'tcx>( ty::TyInfer(ty::TyVar(_)) => { // If the self-type is an inference variable, then it MAY wind up // being a projected type, so induce an ambiguity. - candidate_set.ambiguous = true; + candidate_set.mark_ambiguous(); return; } _ => { return; } @@ -952,7 +970,7 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>( debug!("assemble_candidates_from_predicates: predicate={:?}", predicate); match predicate { - ty::Predicate::Projection(ref data) => { + ty::Predicate::Projection(data) => { let same_def_id = data.0.projection_ty.item_def_id == obligation.predicate.item_def_id; @@ -975,10 +993,10 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>( data, is_match, same_def_id); if is_match { - candidate_set.vec.push(ctor(data.clone())); + candidate_set.push_candidate(ctor(data)); } } - _ => { } + _ => {} } } } @@ -988,37 +1006,36 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( obligation: &ProjectionTyObligation<'tcx>, obligation_trait_ref: &ty::TraitRef<'tcx>, candidate_set: &mut ProjectionTyCandidateSet<'tcx>) - -> Result<(), SelectionError<'tcx>> { // If we are resolving `>::Item == Type`, // start out by selecting the predicate `T as TraitRef<...>`: let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate()); - selcx.infcx().probe(|_| { + let _ = selcx.infcx().commit_if_ok(|_| { let vtable = match selcx.select(&trait_obligation) { Ok(Some(vtable)) => vtable, Ok(None) => { - candidate_set.ambiguous = true; - return Ok(()); + candidate_set.mark_ambiguous(); + return Err(()); } Err(e) => { debug!("assemble_candidates_from_impls: selection error {:?}", e); - return Err(e); + candidate_set.mark_error(e); + return Err(()); } }; - match vtable { + let eligible = match &vtable { super::VtableClosure(_) | super::VtableGenerator(_) | super::VtableFnPointer(_) | super::VtableObject(_) => { debug!("assemble_candidates_from_impls: vtable={:?}", vtable); - - candidate_set.vec.push(ProjectionTyCandidate::Select); + true } - super::VtableImpl(ref impl_data) => { + super::VtableImpl(impl_data) => { // We have to be careful when projecting out of an // impl because of specialization. If we are not in // trans (i.e., projection mode is not "any"), and the @@ -1062,27 +1079,25 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( node_item.item.defaultness.has_value() } else { node_item.item.defaultness.is_default() || - selcx.tcx().impl_is_default(node_item.node.def_id()) + selcx.tcx().impl_is_default(node_item.node.def_id()) }; // Only reveal a specializable default if we're past type-checking // and the obligations is monomorphic, otherwise passes such as // transmute checking and polymorphic MIR optimizations could // get a result which isn't correct for all monomorphizations. - let new_candidate = if !is_default { - Some(ProjectionTyCandidate::Select) + if !is_default { + true } else if obligation.param_env.reveal == Reveal::All { assert!(!poly_trait_ref.needs_infer()); if !poly_trait_ref.needs_subst() { - Some(ProjectionTyCandidate::Select) + true } else { - None + false } } else { - None - }; - - candidate_set.vec.extend(new_candidate); + false + } } super::VtableParam(..) => { // This case tell us nothing about the value of an @@ -1110,6 +1125,7 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( // in the compiler: a trait predicate (`T : SomeTrait`) and a // projection. And the projection where clause is handled // in `assemble_candidates_from_param_env`. + false } super::VtableAutoImpl(..) | super::VtableBuiltin(..) => { @@ -1119,10 +1135,18 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( "Cannot project an associated type from `{:?}`", vtable); } - } + }; - Ok(()) - }) + if eligible { + if candidate_set.push_candidate(ProjectionTyCandidate::Select(vtable)) { + Ok(()) + } else { + Err(()) + } + } else { + Err(()) + } + }); } fn confirm_candidate<'cx, 'gcx, 'tcx>( @@ -1142,8 +1166,8 @@ fn confirm_candidate<'cx, 'gcx, 'tcx>( confirm_param_env_candidate(selcx, obligation, poly_projection) } - ProjectionTyCandidate::Select => { - confirm_select_candidate(selcx, obligation, obligation_trait_ref) + ProjectionTyCandidate::Select(vtable) => { + confirm_select_candidate(selcx, obligation, obligation_trait_ref, vtable) } } } @@ -1151,21 +1175,10 @@ fn confirm_candidate<'cx, 'gcx, 'tcx>( fn confirm_select_candidate<'cx, 'gcx, 'tcx>( selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>) + obligation_trait_ref: &ty::TraitRef<'tcx>, + vtable: Selection<'tcx>) -> Progress<'tcx> { - let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); - let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate()); - let vtable = match selcx.select(&trait_obligation) { - Ok(Some(vtable)) => vtable, - _ => { - span_bug!( - obligation.cause.span, - "Failed to select `{:?}`", - trait_obligation); - } - }; - match vtable { super::VtableImpl(data) => confirm_impl_candidate(selcx, obligation, data), From 5a2bec9f453f94a64b3d62bb546eed666969d9cf Mon Sep 17 00:00:00 2001 From: Tatsuyuki Ishi Date: Sun, 18 Feb 2018 21:23:20 +0900 Subject: [PATCH 19/29] impl_or_trait_obligations: deduplicate obligations --- src/librustc/traits/mod.rs | 8 ++++---- src/librustc/traits/select.rs | 11 +++++++++-- src/librustc/ty/mod.rs | 2 +- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 7f232b310c0b3..2bc396eb04e75 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -73,7 +73,7 @@ pub enum IntercrateMode { /// either identifying an `impl` (e.g., `impl Eq for int`) that /// provides the required vtable, or else finding a bound that is in /// scope. The eventual result is usually a `Selection` (defined below). -#[derive(Clone, PartialEq, Eq)] +#[derive(Clone, PartialEq, Eq, Hash)] pub struct Obligation<'tcx, T> { pub cause: ObligationCause<'tcx>, pub param_env: ty::ParamEnv<'tcx>, @@ -85,7 +85,7 @@ pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>; pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>; /// Why did we incur this obligation? Used for error reporting. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct ObligationCause<'tcx> { pub span: Span, @@ -113,7 +113,7 @@ impl<'tcx> ObligationCause<'tcx> { } } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum ObligationCauseCode<'tcx> { /// Not well classified or should be obvious from span. MiscObligation, @@ -215,7 +215,7 @@ pub enum ObligationCauseCode<'tcx> { BlockTailExpression(ast::NodeId), } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct DerivedObligationCause<'tcx> { /// The trait reference of the parent obligation that led to the /// current obligation. Note that only trait obligations lead to diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 4ed25646d436d..90162c3deca02 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -53,7 +53,7 @@ use std::rc::Rc; use syntax::abi::Abi; use hir; use lint; -use util::nodemap::FxHashMap; +use util::nodemap::{FxHashMap, FxHashSet}; struct InferredObligationsSnapshotVecDelegate<'tcx> { phantom: PhantomData<&'tcx i32>, @@ -3282,7 +3282,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // that order. let predicates = tcx.predicates_of(def_id); assert_eq!(predicates.parent, None); - let predicates = predicates.predicates.iter().flat_map(|predicate| { + let mut predicates: Vec<_> = predicates.predicates.iter().flat_map(|predicate| { let predicate = normalize_with_depth(self, param_env, cause.clone(), recursion_depth, &predicate.subst(tcx, substs)); predicate.obligations.into_iter().chain( @@ -3293,6 +3293,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { predicate: predicate.value })) }).collect(); + // We are performing deduplication here to avoid exponential blowups + // (#38528) from happening, but the real cause of the duplication is + // unknown. What we know is that the deduplication avoids exponential + // amount of predicates being propogated when processing deeply nested + // types. + let mut seen = FxHashSet(); + predicates.retain(|i| seen.insert(i.clone())); self.infcx().plug_leaks(skol_map, snapshot, predicates) } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 14d33b0729aae..3ab2cd274b90e 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1504,7 +1504,7 @@ impl<'gcx> HashStable> for AdtDef { } } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub enum AdtKind { Struct, Union, Enum } bitflags! { From 98eb4ddbceb5bed5e83a9b5e91c173b190532333 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 23 Feb 2018 00:54:30 +0300 Subject: [PATCH 20/29] Fix parsing of extern paths in types and poly-traits --- src/libsyntax/parse/parser.rs | 2 +- .../rfc-2126-extern-absolute-paths/auxiliary/xcrate.rs | 4 +++- src/test/run-pass/rfc-2126-extern-absolute-paths/extern.rs | 4 ++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 7915109ce3af8..058d6ab0762f7 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1321,7 +1321,7 @@ impl<'a> Parser<'a> { pub fn token_is_bare_fn_keyword(&mut self) -> bool { self.check_keyword(keywords::Fn) || self.check_keyword(keywords::Unsafe) || - self.check_keyword(keywords::Extern) + self.check_keyword(keywords::Extern) && self.is_extern_non_path() } fn eat_label(&mut self) -> Option