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
This commit is contained in:
commit
485c5fb6e1
@ -24,4 +24,10 @@ elif isLinux && isGitHubActions; then
|
|||||||
mv "${current_dir}" /mnt/more-space/workspace
|
mv "${current_dir}" /mnt/more-space/workspace
|
||||||
ln -s /mnt/more-space/workspace "${current_dir}"
|
ln -s /mnt/more-space/workspace "${current_dir}"
|
||||||
cd "${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
|
fi
|
||||||
|
@ -352,9 +352,9 @@ are added.
|
|||||||
/// ```
|
/// ```
|
||||||
```
|
```
|
||||||
|
|
||||||
`edition2018` tells `rustdoc` that the code sample should be compiled the 2018
|
`edition2018` tells `rustdoc` that the code sample should be compiled using
|
||||||
edition of Rust. Similarly, you can specify `edition2015` to compile the code
|
the 2018 edition of Rust. Similarly, you can specify `edition2015` to compile
|
||||||
with the 2015 edition.
|
the code with the 2015 edition.
|
||||||
|
|
||||||
## Syntax reference
|
## Syntax reference
|
||||||
|
|
||||||
|
@ -653,11 +653,7 @@ impl<K: Ord, V> BTreeMap<K, V> {
|
|||||||
/// assert_eq!(map.first_key_value(), Some((&1, &"b")));
|
/// assert_eq!(map.first_key_value(), Some((&1, &"b")));
|
||||||
/// ```
|
/// ```
|
||||||
#[unstable(feature = "map_first_last", issue = "62924")]
|
#[unstable(feature = "map_first_last", issue = "62924")]
|
||||||
pub fn first_key_value<T: ?Sized>(&self) -> Option<(&K, &V)>
|
pub fn first_key_value(&self) -> Option<(&K, &V)> {
|
||||||
where
|
|
||||||
T: Ord,
|
|
||||||
K: Borrow<T>,
|
|
||||||
{
|
|
||||||
let front = self.root.as_ref()?.as_ref().first_leaf_edge();
|
let front = self.root.as_ref()?.as_ref().first_leaf_edge();
|
||||||
front.right_kv().ok().map(Handle::into_kv)
|
front.right_kv().ok().map(Handle::into_kv)
|
||||||
}
|
}
|
||||||
@ -667,7 +663,38 @@ impl<K: Ord, V> BTreeMap<K, V> {
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// Contrived way to `clear` a map:
|
/// ```
|
||||||
|
/// #![feature(map_first_last)]
|
||||||
|
/// use std::collections::BTreeMap;
|
||||||
|
///
|
||||||
|
/// let mut map = BTreeMap::new();
|
||||||
|
/// map.insert(1, "a");
|
||||||
|
/// map.insert(2, "b");
|
||||||
|
/// 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(&mut self) -> Option<OccupiedEntry<'_, K, V>> {
|
||||||
|
let front = self.root.as_mut()?.as_mut().first_leaf_edge();
|
||||||
|
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)]
|
/// #![feature(map_first_last)]
|
||||||
@ -676,27 +703,14 @@ impl<K: Ord, V> BTreeMap<K, V> {
|
|||||||
/// let mut map = BTreeMap::new();
|
/// let mut map = BTreeMap::new();
|
||||||
/// map.insert(1, "a");
|
/// map.insert(1, "a");
|
||||||
/// map.insert(2, "b");
|
/// map.insert(2, "b");
|
||||||
/// while let Some(entry) = map.first_entry() {
|
/// while let Some((key, _val)) = map.pop_first() {
|
||||||
/// let (key, val) = entry.remove_entry();
|
/// assert!(map.iter().all(|(k, _v)| *k > key));
|
||||||
/// assert!(!map.contains_key(&key));
|
|
||||||
/// }
|
/// }
|
||||||
|
/// assert!(map.is_empty());
|
||||||
/// ```
|
/// ```
|
||||||
#[unstable(feature = "map_first_last", issue = "62924")]
|
#[unstable(feature = "map_first_last", issue = "62924")]
|
||||||
pub fn first_entry<T: ?Sized>(&mut self) -> Option<OccupiedEntry<'_, K, V>>
|
pub fn pop_first(&mut self) -> Option<(K, V)> {
|
||||||
where
|
self.first_entry().map(|entry| entry.remove_entry())
|
||||||
T: Ord,
|
|
||||||
K: Borrow<T>,
|
|
||||||
{
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the last key-value pair in the map.
|
/// 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")));
|
/// assert_eq!(map.last_key_value(), Some((&2, &"a")));
|
||||||
/// ```
|
/// ```
|
||||||
#[unstable(feature = "map_first_last", issue = "62924")]
|
#[unstable(feature = "map_first_last", issue = "62924")]
|
||||||
pub fn last_key_value<T: ?Sized>(&self) -> Option<(&K, &V)>
|
pub fn last_key_value(&self) -> Option<(&K, &V)> {
|
||||||
where
|
|
||||||
T: Ord,
|
|
||||||
K: Borrow<T>,
|
|
||||||
{
|
|
||||||
let back = self.root.as_ref()?.as_ref().last_leaf_edge();
|
let back = self.root.as_ref()?.as_ref().last_leaf_edge();
|
||||||
back.left_kv().ok().map(Handle::into_kv)
|
back.left_kv().ok().map(Handle::into_kv)
|
||||||
}
|
}
|
||||||
@ -730,7 +740,38 @@ impl<K: Ord, V> BTreeMap<K, V> {
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// Contrived way to `clear` a map:
|
/// ```
|
||||||
|
/// #![feature(map_first_last)]
|
||||||
|
/// use std::collections::BTreeMap;
|
||||||
|
///
|
||||||
|
/// let mut map = BTreeMap::new();
|
||||||
|
/// map.insert(1, "a");
|
||||||
|
/// map.insert(2, "b");
|
||||||
|
/// 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(&mut self) -> Option<OccupiedEntry<'_, K, V>> {
|
||||||
|
let back = self.root.as_mut()?.as_mut().last_leaf_edge();
|
||||||
|
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)]
|
/// #![feature(map_first_last)]
|
||||||
@ -739,27 +780,14 @@ impl<K: Ord, V> BTreeMap<K, V> {
|
|||||||
/// let mut map = BTreeMap::new();
|
/// let mut map = BTreeMap::new();
|
||||||
/// map.insert(1, "a");
|
/// map.insert(1, "a");
|
||||||
/// map.insert(2, "b");
|
/// map.insert(2, "b");
|
||||||
/// while let Some(entry) = map.last_entry() {
|
/// while let Some((key, _val)) = map.pop_last() {
|
||||||
/// let (key, val) = entry.remove_entry();
|
/// assert!(map.iter().all(|(k, _v)| *k < key));
|
||||||
/// assert!(!map.contains_key(&key));
|
|
||||||
/// }
|
/// }
|
||||||
|
/// assert!(map.is_empty());
|
||||||
/// ```
|
/// ```
|
||||||
#[unstable(feature = "map_first_last", issue = "62924")]
|
#[unstable(feature = "map_first_last", issue = "62924")]
|
||||||
pub fn last_entry<T: ?Sized>(&mut self) -> Option<OccupiedEntry<'_, K, V>>
|
pub fn pop_last(&mut self) -> Option<(K, V)> {
|
||||||
where
|
self.last_entry().map(|entry| entry.remove_entry())
|
||||||
T: Ord,
|
|
||||||
K: Borrow<T>,
|
|
||||||
{
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if the map contains a value for the specified key.
|
/// Returns `true` if the map contains a value for the specified key.
|
||||||
|
@ -1,9 +1,4 @@
|
|||||||
You tried to move out of a value which was borrowed.
|
A borrowed value was moved out.
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
Erroneous code example:
|
Erroneous code example:
|
||||||
|
|
||||||
@ -32,6 +27,11 @@ you have three choices:
|
|||||||
* Somehow reclaim the ownership.
|
* Somehow reclaim the ownership.
|
||||||
* Implement the `Copy` trait on the type.
|
* 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:
|
Examples:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -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
|
Erroneous code example:
|
||||||
could cause the match to be non-exhaustive:
|
|
||||||
|
|
||||||
```compile_fail,E0510
|
```compile_fail,E0510
|
||||||
let mut x = Some(0);
|
let mut x = Some(0);
|
||||||
match x {
|
match x {
|
||||||
None => (),
|
None => {}
|
||||||
Some(_) if { x = None; false } => (),
|
Some(_) if { x = None; false } => {} // error!
|
||||||
Some(v) => (), // No longer matches
|
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
|
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!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
@ -355,6 +355,19 @@ impl From<UnusedDelimsCtx> for &'static str {
|
|||||||
trait UnusedDelimLint {
|
trait UnusedDelimLint {
|
||||||
const DELIM_STR: &'static str;
|
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.
|
// this cannot be a constant is it refers to a static.
|
||||||
fn lint(&self) -> &'static Lint;
|
fn lint(&self) -> &'static Lint;
|
||||||
|
|
||||||
@ -454,7 +467,10 @@ trait UnusedDelimLint {
|
|||||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
|
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
|
||||||
use rustc_ast::ast::ExprKind::*;
|
use rustc_ast::ast::ExprKind::*;
|
||||||
let (value, ctx, followed_by_block, left_pos, right_pos) = match e.kind {
|
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 left = e.span.lo() + rustc_span::BytePos(2);
|
||||||
let right = block.span.lo();
|
let right = block.span.lo();
|
||||||
(cond, UnusedDelimsCtx::IfCond, true, Some(left), Some(right))
|
(cond, UnusedDelimsCtx::IfCond, true, Some(left), Some(right))
|
||||||
@ -470,7 +486,7 @@ trait UnusedDelimLint {
|
|||||||
(cond, UnusedDelimsCtx::ForIterExpr, true, None, Some(block.span.lo()))
|
(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);
|
let left = e.span.lo() + rustc_span::BytePos(5);
|
||||||
(head, UnusedDelimsCtx::MatchScrutineeExpr, true, Some(left), None)
|
(head, UnusedDelimsCtx::MatchScrutineeExpr, true, Some(left), None)
|
||||||
}
|
}
|
||||||
@ -512,7 +528,7 @@ trait UnusedDelimLint {
|
|||||||
|
|
||||||
fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
|
fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
|
||||||
match s.kind {
|
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 {
|
if let Some(ref value) = local.init {
|
||||||
self.check_unused_delims_expr(
|
self.check_unused_delims_expr(
|
||||||
cx,
|
cx,
|
||||||
@ -565,6 +581,8 @@ declare_lint_pass!(UnusedParens => [UNUSED_PARENS]);
|
|||||||
impl UnusedDelimLint for UnusedParens {
|
impl UnusedDelimLint for UnusedParens {
|
||||||
const DELIM_STR: &'static str = "parentheses";
|
const DELIM_STR: &'static str = "parentheses";
|
||||||
|
|
||||||
|
const LINT_EXPR_IN_PATTERN_MATCHING_CTX: bool = true;
|
||||||
|
|
||||||
fn lint(&self) -> &'static Lint {
|
fn lint(&self) -> &'static Lint {
|
||||||
UNUSED_PARENS
|
UNUSED_PARENS
|
||||||
}
|
}
|
||||||
@ -736,6 +754,8 @@ declare_lint_pass!(UnusedBraces => [UNUSED_BRACES]);
|
|||||||
impl UnusedDelimLint for UnusedBraces {
|
impl UnusedDelimLint for UnusedBraces {
|
||||||
const DELIM_STR: &'static str = "braces";
|
const DELIM_STR: &'static str = "braces";
|
||||||
|
|
||||||
|
const LINT_EXPR_IN_PATTERN_MATCHING_CTX: bool = false;
|
||||||
|
|
||||||
fn lint(&self) -> &'static Lint {
|
fn lint(&self) -> &'static Lint {
|
||||||
UNUSED_BRACES
|
UNUSED_BRACES
|
||||||
}
|
}
|
||||||
|
@ -5,13 +5,15 @@ use rustc_data_structures::graph::{self, GraphPredecessors, GraphSuccessors};
|
|||||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||||
use rustc_index::vec::IndexVec;
|
use rustc_index::vec::IndexVec;
|
||||||
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
|
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
|
||||||
|
use smallvec::SmallVec;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::ops::{Deref, DerefMut, Index, IndexMut};
|
use std::ops::{Deref, DerefMut, Index, IndexMut};
|
||||||
use std::vec::IntoIter;
|
use std::vec::IntoIter;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Cache {
|
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 {
|
impl rustc_serialize::Encodable for Cache {
|
||||||
@ -44,7 +46,7 @@ impl Cache {
|
|||||||
|
|
||||||
pub fn ensure_predecessors(&mut self, body: &Body<'_>) {
|
pub fn ensure_predecessors(&mut self, body: &Body<'_>) {
|
||||||
if self.predecessors.is_none() {
|
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() {
|
for (bb, data) in body.basic_blocks().iter_enumerated() {
|
||||||
if let Some(ref term) = data.terminator {
|
if let Some(ref term) = data.terminator {
|
||||||
for &tgt in term.successors() {
|
for &tgt in term.successors() {
|
||||||
@ -58,7 +60,11 @@ impl Cache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// This will recompute the predecessors cache if it is not available
|
/// 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.ensure_predecessors(body);
|
||||||
self.predecessors.as_ref().unwrap()
|
self.predecessors.as_ref().unwrap()
|
||||||
}
|
}
|
||||||
@ -137,7 +143,7 @@ impl BodyAndCache<'tcx> {
|
|||||||
self.cache.ensure_predecessors(&self.body);
|
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)
|
self.cache.predecessors(&self.body)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,7 +205,7 @@ impl ReadOnlyBodyAndCache<'a, 'tcx> {
|
|||||||
Self { body, cache }
|
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()
|
self.cache.predecessors.as_ref().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ impl FlagComputation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn add_flags(&mut self, flags: TypeFlags) {
|
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`
|
/// indicates that `self` refers to something at binding level `binder`
|
||||||
|
@ -598,29 +598,6 @@ bitflags! {
|
|||||||
/// Does this value have parameters/placeholders/inference variables which could be
|
/// Does this value have parameters/placeholders/inference variables which could be
|
||||||
/// replaced later, in a way that would change the results of `impl` specialization?
|
/// replaced later, in a way that would change the results of `impl` specialization?
|
||||||
const STILL_FURTHER_SPECIALIZABLE = 1 << 18;
|
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,6 +134,152 @@ enum Elaborate {
|
|||||||
None,
|
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> {
|
impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
||||||
fn cause(&mut self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> {
|
fn cause(&mut self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> {
|
||||||
traits::ObligationCause::new(self.span, self.body_id, code)
|
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 cause = self.cause(traits::MiscObligation);
|
||||||
let param_env = self.param_env;
|
let param_env = self.param_env;
|
||||||
|
|
||||||
let item = &self.item;
|
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,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Elaborate::All = elaborate {
|
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 predicates = obligations.iter().map(|obligation| obligation.predicate).collect();
|
||||||
let implied_obligations = traits::elaborate_predicates(tcx, predicates);
|
let implied_obligations = traits::elaborate_predicates(tcx, predicates);
|
||||||
let implied_obligations = implied_obligations.map(|pred| {
|
let implied_obligations = implied_obligations.map(|pred| {
|
||||||
let mut cause = cause.clone();
|
let mut cause = cause.clone();
|
||||||
extend_cause_with_original_assoc_item_obligation(
|
extend_cause_with_original_assoc_item_obligation(
|
||||||
|
tcx,
|
||||||
|
trait_ref,
|
||||||
|
item,
|
||||||
&mut cause,
|
&mut cause,
|
||||||
&pred,
|
&pred,
|
||||||
&*trait_assoc_items,
|
tcx.associated_items(trait_ref.def_id).in_definition_order().copied(),
|
||||||
);
|
);
|
||||||
traits::Obligation::new(cause, param_env, pred)
|
traits::Obligation::new(cause, param_env, pred)
|
||||||
});
|
});
|
||||||
|
@ -1,29 +1,48 @@
|
|||||||
// check-pass
|
// check-pass
|
||||||
#![warn(unused_braces, unused_parens)]
|
#![warn(unused_braces, unused_parens)]
|
||||||
|
|
||||||
|
fn consume<T>(_: T) {}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let _ = (7);
|
let _ = (7);
|
||||||
//~^WARN unnecessary parentheses
|
//~^WARN unnecessary parentheses
|
||||||
|
|
||||||
let _ = { 7 };
|
// Do not emit a lint in these cases,
|
||||||
//~^ WARN unnecessary braces
|
// as we have to be careful with
|
||||||
|
// `ref` patterns.
|
||||||
|
{
|
||||||
|
let _ = { 7 };
|
||||||
|
|
||||||
if let 7 = { 7 } {
|
if let 7 = { 7 } { }
|
||||||
|
|
||||||
|
match { 7 } {
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if { true } {
|
||||||
|
//~^ WARN unnecessary braces
|
||||||
|
}
|
||||||
|
|
||||||
|
while { false } {
|
||||||
//~^ WARN unnecessary braces
|
//~^ WARN unnecessary braces
|
||||||
}
|
}
|
||||||
|
|
||||||
let _: [u8; { 3 }];
|
let _: [u8; { 3 }];
|
||||||
//~^ WARN unnecessary braces
|
//~^ WARN unnecessary braces
|
||||||
|
|
||||||
// do not emit error for multiline blocks.
|
consume({ 7 });
|
||||||
|
//~^ WARN unnecessary braces
|
||||||
|
|
||||||
|
// Do not emit lint for multiline blocks.
|
||||||
let _ = {
|
let _ = {
|
||||||
7
|
7
|
||||||
};
|
};
|
||||||
|
|
||||||
// do not emit error for unsafe blocks.
|
// Do not emit lint for unsafe blocks.
|
||||||
let _ = unsafe { 7 };
|
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`.
|
// be parsed as part of the `return`.
|
||||||
if { return } {
|
if { return } {
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
warning: unnecessary parentheses around assigned value
|
warning: unnecessary parentheses around assigned value
|
||||||
--> $DIR/unused_braces.rs:5:13
|
--> $DIR/unused_braces.rs:7:13
|
||||||
|
|
|
|
||||||
LL | let _ = (7);
|
LL | let _ = (7);
|
||||||
| ^^^ help: remove these parentheses
|
| ^^^ help: remove these parentheses
|
||||||
@ -10,11 +10,11 @@ note: the lint level is defined here
|
|||||||
LL | #![warn(unused_braces, unused_parens)]
|
LL | #![warn(unused_braces, unused_parens)]
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
||||||
warning: unnecessary braces around assigned value
|
warning: unnecessary braces around `if` condition
|
||||||
--> $DIR/unused_braces.rs:8:13
|
--> $DIR/unused_braces.rs:23:8
|
||||||
|
|
|
|
||||||
LL | let _ = { 7 };
|
LL | if { true } {
|
||||||
| ^^^^^ help: remove these braces
|
| ^^^^^^^^ help: remove these braces
|
||||||
|
|
|
|
||||||
note: the lint level is defined here
|
note: the lint level is defined here
|
||||||
--> $DIR/unused_braces.rs:2:9
|
--> $DIR/unused_braces.rs:2:9
|
||||||
@ -22,15 +22,21 @@ note: the lint level is defined here
|
|||||||
LL | #![warn(unused_braces, unused_parens)]
|
LL | #![warn(unused_braces, unused_parens)]
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
||||||
warning: unnecessary braces around `let` scrutinee expression
|
warning: unnecessary braces around `while` condition
|
||||||
--> $DIR/unused_braces.rs:11:16
|
--> $DIR/unused_braces.rs:27:11
|
||||||
|
|
|
|
||||||
LL | if let 7 = { 7 } {
|
LL | while { false } {
|
||||||
| ^^^^^ help: remove these braces
|
| ^^^^^^^^^ help: remove these braces
|
||||||
|
|
||||||
warning: unnecessary braces around const expression
|
warning: unnecessary braces around const expression
|
||||||
--> $DIR/unused_braces.rs:15:17
|
--> $DIR/unused_braces.rs:31:17
|
||||||
|
|
|
|
||||||
LL | let _: [u8; { 3 }];
|
LL | let _: [u8; { 3 }];
|
||||||
| ^^^^^ help: remove these braces
|
| ^^^^^ help: remove these braces
|
||||||
|
|
||||||
|
warning: unnecessary braces around function argument
|
||||||
|
--> $DIR/unused_braces.rs:34:13
|
||||||
|
|
|
||||||
|
LL | consume({ 7 });
|
||||||
|
| ^^^^^ help: remove these braces
|
||||||
|
|
||||||
|
@ -10,13 +10,15 @@ struct A {
|
|||||||
b: u32,
|
b: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn consume<T>(_: T) {}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let a = A {
|
let a = A {
|
||||||
a: 42,
|
a: 42,
|
||||||
b: 1729,
|
b: 1729,
|
||||||
};
|
};
|
||||||
|
|
||||||
let _ = &{ a.b };
|
consume(&{ a.b });
|
||||||
let _ = { a.b };
|
consume({ a.b });
|
||||||
//~^ WARN unnecessary braces
|
//~^ WARN unnecessary braces
|
||||||
}
|
}
|
@ -1,11 +1,11 @@
|
|||||||
warning: unnecessary braces around assigned value
|
warning: unnecessary braces around function argument
|
||||||
--> $DIR/unused_parens_borrow.rs:20:13
|
--> $DIR/unused_braces_borrow.rs:22:13
|
||||||
|
|
|
|
||||||
LL | let _ = { a.b };
|
LL | consume({ a.b });
|
||||||
| ^^^^^^^ help: remove these braces
|
| ^^^^^^^ help: remove these braces
|
||||||
|
|
|
|
||||||
note: the lint level is defined here
|
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)]
|
LL | #![warn(unused_braces)]
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
Loading…
Reference in New Issue
Block a user