about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-04-08 17:55:45 +0000
committerbors <bors@rust-lang.org>2020-04-08 17:55:45 +0000
commit485c5fb6e1bf12cd11a8fac5ee94962e17cff74b (patch)
treea576971dc9a95edc00323856e06505ee4dae5b00 /src
parent42abbd8878d3b67238f3611b0587c704ba94f39c (diff)
parent1498da87c274508f33aa878e39a8faa3659a4121 (diff)
downloadrust-485c5fb6e1bf12cd11a8fac5ee94962e17cff74b.tar.gz
rust-485c5fb6e1bf12cd11a8fac5ee94962e17cff74b.zip
Auto merge of #70931 - Dylan-DPC:rollup-f8orcao, r=Dylan-DPC
Rollup of 9 pull requests

Successful merges:

 - #70789 (remove false positives of unused_braces)
 - #70847 (ci: move /var/lib/docker to /mnt on GHA)
 - #70850 (BTreeMap first last proposal tweaks)
 - #70876 (Use a `SmallVec` for `Cache::predecessors`.)
 - #70883 (Clean up E0507 explanation)
 - #70892 (wf: refactor `compute_trait_ref`)
 - #70914 (Corrects a typo in rustdoc documentation.)
 - #70915 (Remove unnecessary TypeFlags::NOMINAL_FLAGS)
 - #70927 (Clean up E0510 explanation)

Failed merges:

r? @ghost
Diffstat (limited to 'src')
-rwxr-xr-xsrc/ci/scripts/symlink-build-dir.sh6
-rw-r--r--src/doc/rustdoc/src/documentation-tests.md6
-rw-r--r--src/liballoc/collections/btree/map.rs124
-rw-r--r--src/librustc_error_codes/error_codes/E0507.md12
-rw-r--r--src/librustc_error_codes/error_codes/E0510.md27
-rw-r--r--src/librustc_lint/unused.rs26
-rw-r--r--src/librustc_middle/mir/cache.rs16
-rw-r--r--src/librustc_middle/ty/flags.rs2
-rw-r--r--src/librustc_middle/ty/mod.rs23
-rw-r--r--src/librustc_trait_selection/traits/wf.rs306
-rw-r--r--src/test/ui/lint/unused_braces.rs31
-rw-r--r--src/test/ui/lint/unused_braces.stderr26
-rw-r--r--src/test/ui/lint/unused_braces_borrow.rs (renamed from src/test/ui/lint/unused_parens_borrow.rs)6
-rw-r--r--src/test/ui/lint/unused_braces_borrow.stderr (renamed from src/test/ui/lint/unused_parens_borrow.stderr)8
14 files changed, 346 insertions, 273 deletions
diff --git a/src/ci/scripts/symlink-build-dir.sh b/src/ci/scripts/symlink-build-dir.sh
index c77059c00ac..50178b9c33e 100755
--- a/src/ci/scripts/symlink-build-dir.sh
+++ b/src/ci/scripts/symlink-build-dir.sh
@@ -24,4 +24,10 @@ elif isLinux && isGitHubActions; then
     mv "${current_dir}" /mnt/more-space/workspace
     ln -s /mnt/more-space/workspace "${current_dir}"
     cd "${current_dir}"
+
+    # Move the Docker data directory to /mnt
+    sudo systemctl stop docker.service
+    sudo mv /var/lib/docker /mnt/docker
+    sudo ln -s /mnt/docker /var/lib/docker
+    sudo systemctl start docker.service
 fi
diff --git a/src/doc/rustdoc/src/documentation-tests.md b/src/doc/rustdoc/src/documentation-tests.md
index 78181156e25..efadae1c5fb 100644
--- a/src/doc/rustdoc/src/documentation-tests.md
+++ b/src/doc/rustdoc/src/documentation-tests.md
@@ -352,9 +352,9 @@ are added.
 /// ```
 ```
 
-`edition2018` tells `rustdoc` that the code sample should be compiled the 2018
-edition of Rust. Similarly, you can specify `edition2015` to compile the code
-with the 2015 edition.
+`edition2018` tells `rustdoc` that the code sample should be compiled using
+the 2018 edition of Rust. Similarly, you can specify `edition2015` to compile
+the code with the 2015 edition.
 
 ## Syntax reference
 
diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs
index 70968964f47..a1e59b2e6af 100644
--- a/src/liballoc/collections/btree/map.rs
+++ b/src/liballoc/collections/btree/map.rs
@@ -653,11 +653,7 @@ impl<K: Ord, V> BTreeMap<K, V> {
     /// assert_eq!(map.first_key_value(), Some((&1, &"b")));
     /// ```
     #[unstable(feature = "map_first_last", issue = "62924")]
-    pub fn first_key_value<T: ?Sized>(&self) -> Option<(&K, &V)>
-    where
-        T: Ord,
-        K: Borrow<T>,
-    {
+    pub fn first_key_value(&self) -> Option<(&K, &V)> {
         let front = self.root.as_ref()?.as_ref().first_leaf_edge();
         front.right_kv().ok().map(Handle::into_kv)
     }
@@ -667,8 +663,6 @@ impl<K: Ord, V> BTreeMap<K, V> {
     ///
     /// # Examples
     ///
-    /// Contrived way to `clear` a map:
-    ///
     /// ```
     /// #![feature(map_first_last)]
     /// use std::collections::BTreeMap;
@@ -676,27 +670,47 @@ impl<K: Ord, V> BTreeMap<K, V> {
     /// let mut map = BTreeMap::new();
     /// map.insert(1, "a");
     /// map.insert(2, "b");
-    /// while let Some(entry) = map.first_entry() {
-    ///     let (key, val) = entry.remove_entry();
-    ///     assert!(!map.contains_key(&key));
+    /// if let Some(mut entry) = map.first_entry() {
+    ///     if *entry.key() > 0 {
+    ///         entry.insert("first");
+    ///     }
     /// }
+    /// assert_eq!(*map.get(&1).unwrap(), "first");
+    /// assert_eq!(*map.get(&2).unwrap(), "b");
     /// ```
     #[unstable(feature = "map_first_last", issue = "62924")]
-    pub fn first_entry<T: ?Sized>(&mut self) -> Option<OccupiedEntry<'_, K, V>>
-    where
-        T: Ord,
-        K: Borrow<T>,
-    {
+    pub fn first_entry(&mut self) -> Option<OccupiedEntry<'_, K, V>> {
         let front = self.root.as_mut()?.as_mut().first_leaf_edge();
-        if let Ok(kv) = front.right_kv() {
-            Some(OccupiedEntry {
-                handle: kv.forget_node_type(),
-                length: &mut self.length,
-                _marker: PhantomData,
-            })
-        } else {
-            None
-        }
+        let kv = front.right_kv().ok()?;
+        Some(OccupiedEntry {
+            handle: kv.forget_node_type(),
+            length: &mut self.length,
+            _marker: PhantomData,
+        })
+    }
+
+    /// Removes and returns the first element in the map.
+    /// The key of this element is the minimum key that was in the map.
+    ///
+    /// # Examples
+    ///
+    /// Draining elements in ascending order, while keeping a usable map each iteration.
+    ///
+    /// ```
+    /// #![feature(map_first_last)]
+    /// use std::collections::BTreeMap;
+    ///
+    /// let mut map = BTreeMap::new();
+    /// map.insert(1, "a");
+    /// map.insert(2, "b");
+    /// while let Some((key, _val)) = map.pop_first() {
+    ///     assert!(map.iter().all(|(k, _v)| *k > key));
+    /// }
+    /// assert!(map.is_empty());
+    /// ```
+    #[unstable(feature = "map_first_last", issue = "62924")]
+    pub fn pop_first(&mut self) -> Option<(K, V)> {
+        self.first_entry().map(|entry| entry.remove_entry())
     }
 
     /// Returns the last key-value pair in the map.
@@ -716,11 +730,7 @@ impl<K: Ord, V> BTreeMap<K, V> {
     /// assert_eq!(map.last_key_value(), Some((&2, &"a")));
     /// ```
     #[unstable(feature = "map_first_last", issue = "62924")]
-    pub fn last_key_value<T: ?Sized>(&self) -> Option<(&K, &V)>
-    where
-        T: Ord,
-        K: Borrow<T>,
-    {
+    pub fn last_key_value(&self) -> Option<(&K, &V)> {
         let back = self.root.as_ref()?.as_ref().last_leaf_edge();
         back.left_kv().ok().map(Handle::into_kv)
     }
@@ -730,8 +740,6 @@ impl<K: Ord, V> BTreeMap<K, V> {
     ///
     /// # Examples
     ///
-    /// Contrived way to `clear` a map:
-    ///
     /// ```
     /// #![feature(map_first_last)]
     /// use std::collections::BTreeMap;
@@ -739,27 +747,47 @@ impl<K: Ord, V> BTreeMap<K, V> {
     /// let mut map = BTreeMap::new();
     /// map.insert(1, "a");
     /// map.insert(2, "b");
-    /// while let Some(entry) = map.last_entry() {
-    ///     let (key, val) = entry.remove_entry();
-    ///     assert!(!map.contains_key(&key));
+    /// if let Some(mut entry) = map.last_entry() {
+    ///     if *entry.key() > 0 {
+    ///         entry.insert("last");
+    ///     }
     /// }
+    /// assert_eq!(*map.get(&1).unwrap(), "a");
+    /// assert_eq!(*map.get(&2).unwrap(), "last");
     /// ```
     #[unstable(feature = "map_first_last", issue = "62924")]
-    pub fn last_entry<T: ?Sized>(&mut self) -> Option<OccupiedEntry<'_, K, V>>
-    where
-        T: Ord,
-        K: Borrow<T>,
-    {
+    pub fn last_entry(&mut self) -> Option<OccupiedEntry<'_, K, V>> {
         let back = self.root.as_mut()?.as_mut().last_leaf_edge();
-        if let Ok(kv) = back.left_kv() {
-            Some(OccupiedEntry {
-                handle: kv.forget_node_type(),
-                length: &mut self.length,
-                _marker: PhantomData,
-            })
-        } else {
-            None
-        }
+        let kv = back.left_kv().ok()?;
+        Some(OccupiedEntry {
+            handle: kv.forget_node_type(),
+            length: &mut self.length,
+            _marker: PhantomData,
+        })
+    }
+
+    /// Removes and returns the last element in the map.
+    /// The key of this element is the maximum key that was in the map.
+    ///
+    /// # Examples
+    ///
+    /// Draining elements in descending order, while keeping a usable map each iteration.
+    ///
+    /// ```
+    /// #![feature(map_first_last)]
+    /// use std::collections::BTreeMap;
+    ///
+    /// let mut map = BTreeMap::new();
+    /// map.insert(1, "a");
+    /// map.insert(2, "b");
+    /// while let Some((key, _val)) = map.pop_last() {
+    ///     assert!(map.iter().all(|(k, _v)| *k < key));
+    /// }
+    /// assert!(map.is_empty());
+    /// ```
+    #[unstable(feature = "map_first_last", issue = "62924")]
+    pub fn pop_last(&mut self) -> Option<(K, V)> {
+        self.last_entry().map(|entry| entry.remove_entry())
     }
 
     /// Returns `true` if the map contains a value for the specified key.
diff --git a/src/librustc_error_codes/error_codes/E0507.md b/src/librustc_error_codes/error_codes/E0507.md
index 1e3457e96c5..254751fc45e 100644
--- a/src/librustc_error_codes/error_codes/E0507.md
+++ b/src/librustc_error_codes/error_codes/E0507.md
@@ -1,9 +1,4 @@
-You tried to move out of a value which was borrowed.
-
-This can also happen when using a type implementing `Fn` or `FnMut`, as neither
-allows moving out of them (they usually represent closures which can be called
-more than once). Much of the text following applies equally well to non-`FnOnce`
-closure bodies.
+A borrowed value was moved out.
 
 Erroneous code example:
 
@@ -32,6 +27,11 @@ you have three choices:
 * Somehow reclaim the ownership.
 * Implement the `Copy` trait on the type.
 
+This can also happen when using a type implementing `Fn` or `FnMut`, as neither
+allows moving out of them (they usually represent closures which can be called
+more than once). Much of the text following applies equally well to non-`FnOnce`
+closure bodies.
+
 Examples:
 
 ```
diff --git a/src/librustc_error_codes/error_codes/E0510.md b/src/librustc_error_codes/error_codes/E0510.md
index d5be417888b..e045e04bdbe 100644
--- a/src/librustc_error_codes/error_codes/E0510.md
+++ b/src/librustc_error_codes/error_codes/E0510.md
@@ -1,16 +1,29 @@
-Cannot mutate place in this match guard.
+The matched value was assigned in a match guard.
 
-When matching on a variable it cannot be mutated in the match guards, as this
-could cause the match to be non-exhaustive:
+Erroneous code example:
 
 ```compile_fail,E0510
 let mut x = Some(0);
 match x {
-    None => (),
-    Some(_) if { x = None; false } => (),
-    Some(v) => (), // No longer matches
+    None => {}
+    Some(_) if { x = None; false } => {} // error!
+    Some(_) => {}
 }
 ```
 
+When matching on a variable it cannot be mutated in the match guards, as this
+could cause the match to be non-exhaustive.
+
 Here executing `x = None` would modify the value being matched and require us
-to go "back in time" to the `None` arm.
+to go "back in time" to the `None` arm. To fix it, change the value in the match
+arm:
+
+```
+let mut x = Some(0);
+match x {
+    None => {}
+    Some(_) => {
+        x = None; // ok!
+    }
+}
+```
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index c74b399555a..aa7c87e9f7b 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -355,6 +355,19 @@ impl From<UnusedDelimsCtx> for &'static str {
 trait UnusedDelimLint {
     const DELIM_STR: &'static str;
 
+    /// Due to `ref` pattern, there can be a difference between using
+    /// `{ expr }` and `expr` in pattern-matching contexts. This means
+    /// that we should only lint `unused_parens` and not `unused_braces`
+    /// in this case.
+    ///
+    /// ```rust
+    /// let mut a = 7;
+    /// let ref b = { a }; // We actually borrow a copy of `a` here.
+    /// a += 1; // By mutating `a` we invalidate any borrows of `a`.
+    /// assert_eq!(b + 1, a); // `b` does not borrow `a`, so we can still use it here.
+    /// ```
+    const LINT_EXPR_IN_PATTERN_MATCHING_CTX: bool;
+
     // this cannot be a constant is it refers to a static.
     fn lint(&self) -> &'static Lint;
 
@@ -454,7 +467,10 @@ trait UnusedDelimLint {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
         use rustc_ast::ast::ExprKind::*;
         let (value, ctx, followed_by_block, left_pos, right_pos) = match e.kind {
-            If(ref cond, ref block, ..) => {
+            // Do not lint `unused_braces` in `if let` expressions.
+            If(ref cond, ref block, ..)
+                if !matches!(cond.kind, Let(_, _)) || Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX =>
+            {
                 let left = e.span.lo() + rustc_span::BytePos(2);
                 let right = block.span.lo();
                 (cond, UnusedDelimsCtx::IfCond, true, Some(left), Some(right))
@@ -470,7 +486,7 @@ trait UnusedDelimLint {
                 (cond, UnusedDelimsCtx::ForIterExpr, true, None, Some(block.span.lo()))
             }
 
-            Match(ref head, _) => {
+            Match(ref head, _) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => {
                 let left = e.span.lo() + rustc_span::BytePos(5);
                 (head, UnusedDelimsCtx::MatchScrutineeExpr, true, Some(left), None)
             }
@@ -512,7 +528,7 @@ trait UnusedDelimLint {
 
     fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
         match s.kind {
-            StmtKind::Local(ref local) => {
+            StmtKind::Local(ref local) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => {
                 if let Some(ref value) = local.init {
                     self.check_unused_delims_expr(
                         cx,
@@ -565,6 +581,8 @@ declare_lint_pass!(UnusedParens => [UNUSED_PARENS]);
 impl UnusedDelimLint for UnusedParens {
     const DELIM_STR: &'static str = "parentheses";
 
+    const LINT_EXPR_IN_PATTERN_MATCHING_CTX: bool = true;
+
     fn lint(&self) -> &'static Lint {
         UNUSED_PARENS
     }
@@ -736,6 +754,8 @@ declare_lint_pass!(UnusedBraces => [UNUSED_BRACES]);
 impl UnusedDelimLint for UnusedBraces {
     const DELIM_STR: &'static str = "braces";
 
+    const LINT_EXPR_IN_PATTERN_MATCHING_CTX: bool = false;
+
     fn lint(&self) -> &'static Lint {
         UNUSED_BRACES
     }
diff --git a/src/librustc_middle/mir/cache.rs b/src/librustc_middle/mir/cache.rs
index 00ecc7a7a0a..af0f7efc3e3 100644
--- a/src/librustc_middle/mir/cache.rs
+++ b/src/librustc_middle/mir/cache.rs
@@ -5,13 +5,15 @@ use rustc_data_structures::graph::{self, GraphPredecessors, GraphSuccessors};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_index::vec::IndexVec;
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
+use smallvec::SmallVec;
 use std::iter;
 use std::ops::{Deref, DerefMut, Index, IndexMut};
 use std::vec::IntoIter;
 
 #[derive(Clone, Debug)]
 pub struct Cache {
-    predecessors: Option<IndexVec<BasicBlock, Vec<BasicBlock>>>,
+    // Typically 95%+ of the inner vectors have 4 or fewer elements.
+    predecessors: Option<IndexVec<BasicBlock, SmallVec<[BasicBlock; 4]>>>,
 }
 
 impl rustc_serialize::Encodable for Cache {
@@ -44,7 +46,7 @@ impl Cache {
 
     pub fn ensure_predecessors(&mut self, body: &Body<'_>) {
         if self.predecessors.is_none() {
-            let mut result = IndexVec::from_elem(vec![], body.basic_blocks());
+            let mut result = IndexVec::from_elem(smallvec![], body.basic_blocks());
             for (bb, data) in body.basic_blocks().iter_enumerated() {
                 if let Some(ref term) = data.terminator {
                     for &tgt in term.successors() {
@@ -58,7 +60,11 @@ impl Cache {
     }
 
     /// This will recompute the predecessors cache if it is not available
-    fn predecessors(&mut self, body: &Body<'_>) -> &IndexVec<BasicBlock, Vec<BasicBlock>> {
+    // njn: typedef?
+    fn predecessors(
+        &mut self,
+        body: &Body<'_>,
+    ) -> &IndexVec<BasicBlock, SmallVec<[BasicBlock; 4]>> {
         self.ensure_predecessors(body);
         self.predecessors.as_ref().unwrap()
     }
@@ -137,7 +143,7 @@ impl BodyAndCache<'tcx> {
         self.cache.ensure_predecessors(&self.body);
     }
 
-    pub fn predecessors(&mut self) -> &IndexVec<BasicBlock, Vec<BasicBlock>> {
+    pub fn predecessors(&mut self) -> &IndexVec<BasicBlock, SmallVec<[BasicBlock; 4]>> {
         self.cache.predecessors(&self.body)
     }
 
@@ -199,7 +205,7 @@ impl ReadOnlyBodyAndCache<'a, 'tcx> {
         Self { body, cache }
     }
 
-    pub fn predecessors(&self) -> &IndexVec<BasicBlock, Vec<BasicBlock>> {
+    pub fn predecessors(&self) -> &IndexVec<BasicBlock, SmallVec<[BasicBlock; 4]>> {
         self.cache.predecessors.as_ref().unwrap()
     }
 
diff --git a/src/librustc_middle/ty/flags.rs b/src/librustc_middle/ty/flags.rs
index 99a6511b297..7c3c96348b5 100644
--- a/src/librustc_middle/ty/flags.rs
+++ b/src/librustc_middle/ty/flags.rs
@@ -28,7 +28,7 @@ impl FlagComputation {
     }
 
     fn add_flags(&mut self, flags: TypeFlags) {
-        self.flags = self.flags | (flags & TypeFlags::NOMINAL_FLAGS);
+        self.flags = self.flags | flags;
     }
 
     /// indicates that `self` refers to something at binding level `binder`
diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs
index 1870856150f..57ac18185d0 100644
--- a/src/librustc_middle/ty/mod.rs
+++ b/src/librustc_middle/ty/mod.rs
@@ -598,29 +598,6 @@ bitflags! {
         /// Does this value have parameters/placeholders/inference variables which could be
         /// replaced later, in a way that would change the results of `impl` specialization?
         const STILL_FURTHER_SPECIALIZABLE = 1 << 18;
-
-        /// Flags representing the nominal content of a type,
-        /// computed by FlagsComputation. If you add a new nominal
-        /// flag, it should be added here too.
-        const NOMINAL_FLAGS               = TypeFlags::HAS_TY_PARAM.bits
-                                          | TypeFlags::HAS_RE_PARAM.bits
-                                          | TypeFlags::HAS_CT_PARAM.bits
-                                          | TypeFlags::HAS_TY_INFER.bits
-                                          | TypeFlags::HAS_RE_INFER.bits
-                                          | TypeFlags::HAS_CT_INFER.bits
-                                          | TypeFlags::HAS_TY_PLACEHOLDER.bits
-                                          | TypeFlags::HAS_RE_PLACEHOLDER.bits
-                                          | TypeFlags::HAS_CT_PLACEHOLDER.bits
-                                          | TypeFlags::HAS_FREE_LOCAL_REGIONS.bits
-                                          | TypeFlags::HAS_TY_PROJECTION.bits
-                                          | TypeFlags::HAS_TY_OPAQUE.bits
-                                          | TypeFlags::HAS_CT_PROJECTION.bits
-                                          | TypeFlags::KEEP_IN_LOCAL_TCX.bits
-                                          | TypeFlags::HAS_TY_ERR.bits
-                                          | TypeFlags::HAS_FREE_REGIONS.bits
-                                          | TypeFlags::HAS_RE_LATE_BOUND.bits
-                                          | TypeFlags::HAS_RE_ERASED.bits
-                                          | TypeFlags::STILL_FURTHER_SPECIALIZABLE.bits;
     }
 }
 
diff --git a/src/librustc_trait_selection/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs
index 6b38749e1e7..d506ddab909 100644
--- a/src/librustc_trait_selection/traits/wf.rs
+++ b/src/librustc_trait_selection/traits/wf.rs
@@ -134,6 +134,152 @@ enum Elaborate {
     None,
 }
 
+fn extend_cause_with_original_assoc_item_obligation<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    trait_ref: &ty::TraitRef<'tcx>,
+    item: Option<&hir::Item<'tcx>>,
+    cause: &mut traits::ObligationCause<'tcx>,
+    pred: &ty::Predicate<'_>,
+    mut trait_assoc_items: impl Iterator<Item = ty::AssocItem>,
+) {
+    let trait_item =
+        tcx.hir().as_local_hir_id(trait_ref.def_id).and_then(|trait_id| tcx.hir().find(trait_id));
+    let (trait_name, trait_generics) = match trait_item {
+        Some(hir::Node::Item(hir::Item {
+            ident,
+            kind: hir::ItemKind::Trait(.., generics, _, _),
+            ..
+        }))
+        | Some(hir::Node::Item(hir::Item {
+            ident,
+            kind: hir::ItemKind::TraitAlias(generics, _),
+            ..
+        })) => (Some(ident), Some(generics)),
+        _ => (None, None),
+    };
+
+    let item_span = item.map(|i| tcx.sess.source_map().guess_head_span(i.span));
+    match pred {
+        ty::Predicate::Projection(proj) => {
+            // The obligation comes not from the current `impl` nor the `trait` being
+            // implemented, but rather from a "second order" obligation, like in
+            // `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs`:
+            //
+            //   error[E0271]: type mismatch resolving `<Foo2 as Bar2>::Ok == ()`
+            //     --> $DIR/point-at-type-on-obligation-failure.rs:13:5
+            //      |
+            //   LL |     type Ok;
+            //      |          -- associated type defined here
+            //   ...
+            //   LL | impl Bar for Foo {
+            //      | ---------------- in this `impl` item
+            //   LL |     type Ok = ();
+            //      |     ^^^^^^^^^^^^^ expected `u32`, found `()`
+            //      |
+            //      = note: expected type `u32`
+            //                 found type `()`
+            //
+            // FIXME: we would want to point a span to all places that contributed to this
+            // obligation. In the case above, it should be closer to:
+            //
+            //   error[E0271]: type mismatch resolving `<Foo2 as Bar2>::Ok == ()`
+            //     --> $DIR/point-at-type-on-obligation-failure.rs:13:5
+            //      |
+            //   LL |     type Ok;
+            //      |          -- associated type defined here
+            //   LL |     type Sibling: Bar2<Ok=Self::Ok>;
+            //      |     -------------------------------- obligation set here
+            //   ...
+            //   LL | impl Bar for Foo {
+            //      | ---------------- in this `impl` item
+            //   LL |     type Ok = ();
+            //      |     ^^^^^^^^^^^^^ expected `u32`, found `()`
+            //   ...
+            //   LL | impl Bar2 for Foo2 {
+            //      | ---------------- in this `impl` item
+            //   LL |     type Ok = u32;
+            //      |     -------------- obligation set here
+            //      |
+            //      = note: expected type `u32`
+            //                 found type `()`
+            if let Some(hir::ItemKind::Impl { items, .. }) = item.map(|i| &i.kind) {
+                let trait_assoc_item = tcx.associated_item(proj.projection_def_id());
+                if let Some(impl_item) =
+                    items.iter().find(|item| item.ident == trait_assoc_item.ident)
+                {
+                    cause.span = impl_item.span;
+                    cause.code = traits::AssocTypeBound(Box::new(AssocTypeBoundData {
+                        impl_span: item_span,
+                        original: trait_assoc_item.ident.span,
+                        bounds: vec![],
+                    }));
+                }
+            }
+        }
+        ty::Predicate::Trait(proj, _) => {
+            // An associated item obligation born out of the `trait` failed to be met.
+            // Point at the `impl` that failed the obligation, the associated item that
+            // needed to meet the obligation, and the definition of that associated item,
+            // which should hold the obligation in most cases. An example can be seen in
+            // `src/test/ui/associated-types/point-at-type-on-obligation-failure-2.rs`:
+            //
+            //   error[E0277]: the trait bound `bool: Bar` is not satisfied
+            //     --> $DIR/point-at-type-on-obligation-failure-2.rs:8:5
+            //      |
+            //   LL |     type Assoc: Bar;
+            //      |          ----- associated type defined here
+            //   ...
+            //   LL | impl Foo for () {
+            //      | --------------- in this `impl` item
+            //   LL |     type Assoc = bool;
+            //      |     ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
+            //
+            // If the obligation comes from the where clause in the `trait`, we point at it:
+            //
+            //   error[E0277]: the trait bound `bool: Bar` is not satisfied
+            //     --> $DIR/point-at-type-on-obligation-failure-2.rs:8:5
+            //      |
+            //      | trait Foo where <Self as Foo>>::Assoc: Bar {
+            //      |                 -------------------------- restricted in this bound
+            //   LL |     type Assoc;
+            //      |          ----- associated type defined here
+            //   ...
+            //   LL | impl Foo for () {
+            //      | --------------- in this `impl` item
+            //   LL |     type Assoc = bool;
+            //      |     ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
+            if let (
+                ty::Projection(ty::ProjectionTy { item_def_id, .. }),
+                Some(hir::ItemKind::Impl { items, .. }),
+            ) = (&proj.skip_binder().self_ty().kind, item.map(|i| &i.kind))
+            {
+                if let Some((impl_item, trait_assoc_item)) = trait_assoc_items
+                    .find(|i| i.def_id == *item_def_id)
+                    .and_then(|trait_assoc_item| {
+                        items
+                            .iter()
+                            .find(|i| i.ident == trait_assoc_item.ident)
+                            .map(|impl_item| (impl_item, trait_assoc_item))
+                    })
+                {
+                    let bounds = trait_generics
+                        .map(|generics| {
+                            get_generic_bound_spans(&generics, trait_name, trait_assoc_item.ident)
+                        })
+                        .unwrap_or_else(Vec::new);
+                    cause.span = impl_item.span;
+                    cause.code = traits::AssocTypeBound(Box::new(AssocTypeBoundData {
+                        impl_span: item_span,
+                        original: trait_assoc_item.ident.span,
+                        bounds,
+                    }));
+                }
+            }
+        }
+        _ => {}
+    }
+}
+
 impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
     fn cause(&mut self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> {
         traits::ObligationCause::new(self.span, self.body_id, code)
@@ -163,170 +309,20 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
         let cause = self.cause(traits::MiscObligation);
         let param_env = self.param_env;
 
-        let item = &self.item;
-        let extend_cause_with_original_assoc_item_obligation =
-            |cause: &mut traits::ObligationCause<'_>,
-             pred: &ty::Predicate<'_>,
-             trait_assoc_items: &[ty::AssocItem]| {
-                let trait_item = tcx
-                    .hir()
-                    .as_local_hir_id(trait_ref.def_id)
-                    .and_then(|trait_id| tcx.hir().find(trait_id));
-                let (trait_name, trait_generics) = match trait_item {
-                    Some(hir::Node::Item(hir::Item {
-                        ident,
-                        kind: hir::ItemKind::Trait(.., generics, _, _),
-                        ..
-                    }))
-                    | Some(hir::Node::Item(hir::Item {
-                        ident,
-                        kind: hir::ItemKind::TraitAlias(generics, _),
-                        ..
-                    })) => (Some(ident), Some(generics)),
-                    _ => (None, None),
-                };
-
-                let item_span = item.map(|i| tcx.sess.source_map().guess_head_span(i.span));
-                match pred {
-                    ty::Predicate::Projection(proj) => {
-                        // The obligation comes not from the current `impl` nor the `trait` being
-                        // implemented, but rather from a "second order" obligation, like in
-                        // `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs`:
-                        //
-                        //   error[E0271]: type mismatch resolving `<Foo2 as Bar2>::Ok == ()`
-                        //     --> $DIR/point-at-type-on-obligation-failure.rs:13:5
-                        //      |
-                        //   LL |     type Ok;
-                        //      |          -- associated type defined here
-                        //   ...
-                        //   LL | impl Bar for Foo {
-                        //      | ---------------- in this `impl` item
-                        //   LL |     type Ok = ();
-                        //      |     ^^^^^^^^^^^^^ expected `u32`, found `()`
-                        //      |
-                        //      = note: expected type `u32`
-                        //                 found type `()`
-                        //
-                        // FIXME: we would want to point a span to all places that contributed to this
-                        // obligation. In the case above, it should be closer to:
-                        //
-                        //   error[E0271]: type mismatch resolving `<Foo2 as Bar2>::Ok == ()`
-                        //     --> $DIR/point-at-type-on-obligation-failure.rs:13:5
-                        //      |
-                        //   LL |     type Ok;
-                        //      |          -- associated type defined here
-                        //   LL |     type Sibling: Bar2<Ok=Self::Ok>;
-                        //      |     -------------------------------- obligation set here
-                        //   ...
-                        //   LL | impl Bar for Foo {
-                        //      | ---------------- in this `impl` item
-                        //   LL |     type Ok = ();
-                        //      |     ^^^^^^^^^^^^^ expected `u32`, found `()`
-                        //   ...
-                        //   LL | impl Bar2 for Foo2 {
-                        //      | ---------------- in this `impl` item
-                        //   LL |     type Ok = u32;
-                        //      |     -------------- obligation set here
-                        //      |
-                        //      = note: expected type `u32`
-                        //                 found type `()`
-                        if let Some(hir::ItemKind::Impl { items, .. }) = item.map(|i| &i.kind) {
-                            let trait_assoc_item = tcx.associated_item(proj.projection_def_id());
-                            if let Some(impl_item) =
-                                items.iter().find(|item| item.ident == trait_assoc_item.ident)
-                            {
-                                cause.span = impl_item.span;
-                                cause.code = traits::AssocTypeBound(Box::new(AssocTypeBoundData {
-                                    impl_span: item_span,
-                                    original: trait_assoc_item.ident.span,
-                                    bounds: vec![],
-                                }));
-                            }
-                        }
-                    }
-                    ty::Predicate::Trait(proj, _) => {
-                        // An associated item obligation born out of the `trait` failed to be met.
-                        // Point at the `impl` that failed the obligation, the associated item that
-                        // needed to meet the obligation, and the definition of that associated item,
-                        // which should hold the obligation in most cases. An example can be seen in
-                        // `src/test/ui/associated-types/point-at-type-on-obligation-failure-2.rs`:
-                        //
-                        //   error[E0277]: the trait bound `bool: Bar` is not satisfied
-                        //     --> $DIR/point-at-type-on-obligation-failure-2.rs:8:5
-                        //      |
-                        //   LL |     type Assoc: Bar;
-                        //      |          ----- associated type defined here
-                        //   ...
-                        //   LL | impl Foo for () {
-                        //      | --------------- in this `impl` item
-                        //   LL |     type Assoc = bool;
-                        //      |     ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
-                        //
-                        // If the obligation comes from the where clause in the `trait`, we point at it:
-                        //
-                        //   error[E0277]: the trait bound `bool: Bar` is not satisfied
-                        //     --> $DIR/point-at-type-on-obligation-failure-2.rs:8:5
-                        //      |
-                        //      | trait Foo where <Self as Foo>>::Assoc: Bar {
-                        //      |                 -------------------------- restricted in this bound
-                        //   LL |     type Assoc;
-                        //      |          ----- associated type defined here
-                        //   ...
-                        //   LL | impl Foo for () {
-                        //      | --------------- in this `impl` item
-                        //   LL |     type Assoc = bool;
-                        //      |     ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
-                        if let (
-                            ty::Projection(ty::ProjectionTy { item_def_id, .. }),
-                            Some(hir::ItemKind::Impl { items, .. }),
-                        ) = (&proj.skip_binder().self_ty().kind, item.map(|i| &i.kind))
-                        {
-                            if let Some((impl_item, trait_assoc_item)) = trait_assoc_items
-                                .iter()
-                                .find(|i| i.def_id == *item_def_id)
-                                .and_then(|trait_assoc_item| {
-                                    items
-                                        .iter()
-                                        .find(|i| i.ident == trait_assoc_item.ident)
-                                        .map(|impl_item| (impl_item, trait_assoc_item))
-                                })
-                            {
-                                let bounds = trait_generics
-                                    .map(|generics| {
-                                        get_generic_bound_spans(
-                                            &generics,
-                                            trait_name,
-                                            trait_assoc_item.ident,
-                                        )
-                                    })
-                                    .unwrap_or_else(Vec::new);
-                                cause.span = impl_item.span;
-                                cause.code = traits::AssocTypeBound(Box::new(AssocTypeBoundData {
-                                    impl_span: item_span,
-                                    original: trait_assoc_item.ident.span,
-                                    bounds,
-                                }));
-                            }
-                        }
-                    }
-                    _ => {}
-                }
-            };
+        let item = self.item;
 
         if let Elaborate::All = elaborate {
-            // FIXME: Make `extend_cause_with_original_assoc_item_obligation` take an iterator
-            // instead of a slice.
-            let trait_assoc_items: Vec<_> =
-                tcx.associated_items(trait_ref.def_id).in_definition_order().copied().collect();
-
             let predicates = obligations.iter().map(|obligation| obligation.predicate).collect();
             let implied_obligations = traits::elaborate_predicates(tcx, predicates);
             let implied_obligations = implied_obligations.map(|pred| {
                 let mut cause = cause.clone();
                 extend_cause_with_original_assoc_item_obligation(
+                    tcx,
+                    trait_ref,
+                    item,
                     &mut cause,
                     &pred,
-                    &*trait_assoc_items,
+                    tcx.associated_items(trait_ref.def_id).in_definition_order().copied(),
                 );
                 traits::Obligation::new(cause, param_env, pred)
             });
diff --git a/src/test/ui/lint/unused_braces.rs b/src/test/ui/lint/unused_braces.rs
index de456ee6c23..952398ef068 100644
--- a/src/test/ui/lint/unused_braces.rs
+++ b/src/test/ui/lint/unused_braces.rs
@@ -1,29 +1,48 @@
 // check-pass
 #![warn(unused_braces, unused_parens)]
 
+fn consume<T>(_: T) {}
+
 fn main() {
     let _ = (7);
     //~^WARN unnecessary parentheses
 
-    let _ = { 7 };
-    //~^ WARN unnecessary braces
+    // Do not emit a lint in these cases,
+    // as we have to be careful with
+    // `ref` patterns.
+    {
+        let _ = { 7 };
+
+        if let 7 = { 7 } { }
+
+        match { 7 } {
+            _ => (),
+        }
+    }
 
-    if let 7 = { 7 } {
+    if { true } {
+        //~^ WARN unnecessary braces
+    }
+
+    while { false } {
         //~^ WARN unnecessary braces
     }
 
     let _: [u8; { 3 }];
     //~^ WARN unnecessary braces
 
-    // do not emit error for multiline blocks.
+    consume({ 7 });
+    //~^ WARN unnecessary braces
+
+    // Do not emit lint for multiline blocks.
     let _ = {
         7
     };
 
-    // do not emit error for unsafe blocks.
+    // Do not emit lint for unsafe blocks.
     let _ = unsafe { 7 };
 
-    // do not emit error, as the `{` would then
+    // Do not emit lint, as the `{` would then
     // be parsed as part of the `return`.
     if { return } {
 
diff --git a/src/test/ui/lint/unused_braces.stderr b/src/test/ui/lint/unused_braces.stderr
index 72f425ffc3e..f195c002418 100644
--- a/src/test/ui/lint/unused_braces.stderr
+++ b/src/test/ui/lint/unused_braces.stderr
@@ -1,5 +1,5 @@
 warning: unnecessary parentheses around assigned value
-  --> $DIR/unused_braces.rs:5:13
+  --> $DIR/unused_braces.rs:7:13
    |
 LL |     let _ = (7);
    |             ^^^ help: remove these parentheses
@@ -10,11 +10,11 @@ note: the lint level is defined here
 LL | #![warn(unused_braces, unused_parens)]
    |                        ^^^^^^^^^^^^^
 
-warning: unnecessary braces around assigned value
-  --> $DIR/unused_braces.rs:8:13
+warning: unnecessary braces around `if` condition
+  --> $DIR/unused_braces.rs:23:8
    |
-LL |     let _ = { 7 };
-   |             ^^^^^ help: remove these braces
+LL |     if { true } {
+   |        ^^^^^^^^ help: remove these braces
    |
 note: the lint level is defined here
   --> $DIR/unused_braces.rs:2:9
@@ -22,15 +22,21 @@ note: the lint level is defined here
 LL | #![warn(unused_braces, unused_parens)]
    |         ^^^^^^^^^^^^^
 
-warning: unnecessary braces around `let` scrutinee expression
-  --> $DIR/unused_braces.rs:11:16
+warning: unnecessary braces around `while` condition
+  --> $DIR/unused_braces.rs:27:11
    |
-LL |     if let 7 = { 7 } {
-   |                ^^^^^ help: remove these braces
+LL |     while { false } {
+   |           ^^^^^^^^^ help: remove these braces
 
 warning: unnecessary braces around const expression
-  --> $DIR/unused_braces.rs:15:17
+  --> $DIR/unused_braces.rs:31:17
    |
 LL |     let _: [u8; { 3 }];
    |                 ^^^^^ help: remove these braces
 
+warning: unnecessary braces around function argument
+  --> $DIR/unused_braces.rs:34:13
+   |
+LL |     consume({ 7 });
+   |             ^^^^^ help: remove these braces
+
diff --git a/src/test/ui/lint/unused_parens_borrow.rs b/src/test/ui/lint/unused_braces_borrow.rs
index 98dbbecfedd..d0b059744e1 100644
--- a/src/test/ui/lint/unused_parens_borrow.rs
+++ b/src/test/ui/lint/unused_braces_borrow.rs
@@ -10,13 +10,15 @@ struct A {
     b: u32,
 }
 
+fn consume<T>(_: T) {}
+
 fn main() {
     let a = A {
         a: 42,
         b: 1729,
     };
 
-    let _ = &{ a.b };
-    let _ = { a.b };
+    consume(&{ a.b });
+    consume({ a.b });
     //~^ WARN unnecessary braces
 }
diff --git a/src/test/ui/lint/unused_parens_borrow.stderr b/src/test/ui/lint/unused_braces_borrow.stderr
index 7e3839ae4e0..82fb4375611 100644
--- a/src/test/ui/lint/unused_parens_borrow.stderr
+++ b/src/test/ui/lint/unused_braces_borrow.stderr
@@ -1,11 +1,11 @@
-warning: unnecessary braces around assigned value
-  --> $DIR/unused_parens_borrow.rs:20:13
+warning: unnecessary braces around function argument
+  --> $DIR/unused_braces_borrow.rs:22:13
    |
-LL |     let _ = { a.b };
+LL |     consume({ a.b });
    |             ^^^^^^^ help: remove these braces
    |
 note: the lint level is defined here
-  --> $DIR/unused_parens_borrow.rs:2:9
+  --> $DIR/unused_braces_borrow.rs:2:9
    |
 LL | #![warn(unused_braces)]
    |         ^^^^^^^^^^^^^