提交 615c4608 编写于 作者: B bors

Auto merge of #63341 - Centril:rollup-hkhxahb, r=Centril

Rollup of 9 pull requests

Successful merges:

 - #63034 (Fix generator size regressions due to optimization)
 - #63035 (Use MaybeUninit to produce more correct layouts)
 - #63163 (add a pair of whitespace after remove parentheses)
 - #63294 (tests for async/await drop order)
 - #63307 (don't ignore mir_dump folder)
 - #63308 (PlaceRef's base is already a reference)
 - #63310 (Tests around moving parts of structs and tuples across await points)
 - #63314 (doc: the content has since been moved to the guide)
 - #63333 (Remove unnecessary features from compiler error code list)

Failed merges:

r? @ghost
......@@ -52,7 +52,6 @@ config.mk
config.stamp
keywords.md
lexer.ml
mir_dump
Session.vim
src/etc/dl
tmp.*.rs
......
......@@ -5,10 +5,7 @@ This directory contains the source code of the rust project, including:
For more information on how various parts of the compiler work, see the [rustc guide].
There is also useful content in the following READMEs, which are gradually being moved over to the guide:
- https://github.com/rust-lang/rust/tree/master/src/librustc/ty/query
- https://github.com/rust-lang/rust/tree/master/src/librustc/dep_graph
- https://github.com/rust-lang/rust/tree/master/src/librustc/infer/higher_ranked
- https://github.com/rust-lang/rust/tree/master/src/librustc/infer/lexical_region_resolve
There is also useful content in this README:
https://github.com/rust-lang/rust/tree/master/src/librustc/infer/lexical_region_resolve.
[rustc guide]: https://rust-lang.github.io/rustc-guide/about-this-guide.html
......@@ -209,6 +209,8 @@
/// guarantee may evolve.
#[allow(missing_debug_implementations)]
#[stable(feature = "maybe_uninit", since = "1.36.0")]
// Lang item so we can wrap other types in it. This is useful for generators.
#[cfg_attr(not(bootstrap), lang = "maybe_uninit")]
#[derive(Copy)]
#[repr(transparent)]
pub union MaybeUninit<T> {
......
......@@ -365,6 +365,8 @@ pub fn collect<'tcx>(tcx: TyCtxt<'tcx>) -> LanguageItems {
ManuallyDropItem, "manually_drop", manually_drop, Target::Struct;
MaybeUninitLangItem, "maybe_uninit", maybe_uninit, Target::Union;
DebugTraitLangItem, "debug_trait", debug_trait, Target::Trait;
// Align offset for stride != 1, must not panic.
......
......@@ -2347,10 +2347,9 @@ pub fn mk_foreign(self, def_id: DefId) -> Ty<'tcx> {
self.mk_ty(Foreign(def_id))
}
pub fn mk_box(self, ty: Ty<'tcx>) -> Ty<'tcx> {
let def_id = self.require_lang_item(lang_items::OwnedBoxLangItem);
let adt_def = self.adt_def(def_id);
let substs = InternalSubsts::for_item(self, def_id, |param, substs| {
fn mk_generic_adt(self, wrapper_def_id: DefId, ty_param: Ty<'tcx>) -> Ty<'tcx> {
let adt_def = self.adt_def(wrapper_def_id);
let substs = InternalSubsts::for_item(self, wrapper_def_id, |param, substs| {
match param.kind {
GenericParamDefKind::Lifetime |
GenericParamDefKind::Const => {
......@@ -2358,7 +2357,7 @@ pub fn mk_box(self, ty: Ty<'tcx>) -> Ty<'tcx> {
}
GenericParamDefKind::Type { has_default, .. } => {
if param.index == 0 {
ty.into()
ty_param.into()
} else {
assert!(has_default);
self.type_of(param.def_id).subst(self, substs).into()
......@@ -2369,6 +2368,18 @@ pub fn mk_box(self, ty: Ty<'tcx>) -> Ty<'tcx> {
self.mk_ty(Adt(adt_def, substs))
}
#[inline]
pub fn mk_box(self, ty: Ty<'tcx>) -> Ty<'tcx> {
let def_id = self.require_lang_item(lang_items::OwnedBoxLangItem);
self.mk_generic_adt(def_id, ty)
}
#[inline]
pub fn mk_maybe_uninit(self, ty: Ty<'tcx>) -> Ty<'tcx> {
let def_id = self.require_lang_item(lang_items::MaybeUninitLangItem);
self.mk_generic_adt(def_id, ty)
}
#[inline]
pub fn mk_ptr(self, tm: TypeAndMut<'tcx>) -> Ty<'tcx> {
self.mk_ty(RawPtr(tm))
......
......@@ -1368,6 +1368,27 @@ fn generator_saved_local_eligibility(&self, info: &GeneratorLayout<'tcx>)
}
}
// Count the number of variants in use. If only one of them, then it is
// impossible to overlap any locals in our layout. In this case it's
// always better to make the remaining locals ineligible, so we can
// lay them out with the other locals in the prefix and eliminate
// unnecessary padding bytes.
{
let mut used_variants = BitSet::new_empty(info.variant_fields.len());
for assignment in &assignments {
match assignment {
Assigned(idx) => { used_variants.insert(*idx); }
_ => {}
}
}
if used_variants.count() < 2 {
for assignment in assignments.iter_mut() {
*assignment = Ineligible(None);
}
ineligible_locals.insert_all();
}
}
// Write down the order of our locals that will be promoted to the prefix.
{
let mut idx = 0u32;
......@@ -1406,24 +1427,21 @@ fn generator_layout(
Abi::Scalar(s) => s.clone(),
_ => bug!(),
};
// FIXME(eddyb) wrap each promoted type in `MaybeUninit` so that they
// don't poison the `largest_niche` or `abi` fields of `prefix`.
let promoted_layouts = ineligible_locals.iter()
.map(|local| subst_field(info.field_tys[local]))
.map(|ty| tcx.mk_maybe_uninit(ty))
.map(|ty| self.layout_of(ty));
let prefix_layouts = substs.prefix_tys(def_id, tcx)
.map(|ty| self.layout_of(ty))
.chain(iter::once(Ok(discr_layout)))
.chain(promoted_layouts)
.collect::<Result<Vec<_>, _>>()?;
let mut prefix = self.univariant_uninterned(
let prefix = self.univariant_uninterned(
ty,
&prefix_layouts,
&ReprOptions::default(),
StructKind::AlwaysSized,
)?;
// FIXME(eddyb) need `MaybeUninit` around promoted types (see above).
prefix.largest_niche = None;
let (prefix_size, prefix_align) = (prefix.size, prefix.align);
......
......@@ -15,7 +15,7 @@
use syntax::symbol::{kw, sym};
use syntax::symbol::Symbol;
use syntax::util::parser;
use syntax_pos::Span;
use syntax_pos::{Span, BytePos};
use rustc::hir;
......@@ -353,31 +353,46 @@ fn check_attribute(&mut self, cx: &LateContext<'_, '_>, attr: &ast::Attribute) {
declare_lint_pass!(UnusedParens => [UNUSED_PARENS]);
impl UnusedParens {
fn is_expr_parens_necessary(inner: &ast::Expr, followed_by_block: bool) -> bool {
followed_by_block && match inner.node {
ast::ExprKind::Ret(_) | ast::ExprKind::Break(..) => true,
_ => parser::contains_exterior_struct_lit(&inner),
}
}
fn check_unused_parens_expr(&self,
cx: &EarlyContext<'_>,
value: &ast::Expr,
msg: &str,
followed_by_block: bool) {
cx: &EarlyContext<'_>,
value: &ast::Expr,
msg: &str,
followed_by_block: bool,
left_pos: Option<BytePos>,
right_pos: Option<BytePos>) {
match value.node {
ast::ExprKind::Paren(ref inner) => {
let necessary = followed_by_block && match inner.node {
ast::ExprKind::Ret(_) | ast::ExprKind::Break(..) => true,
_ => parser::contains_exterior_struct_lit(&inner),
};
if !necessary {
if !Self::is_expr_parens_necessary(inner, followed_by_block) {
let expr_text = if let Ok(snippet) = cx.sess().source_map()
.span_to_snippet(value.span) {
snippet
} else {
pprust::expr_to_string(value)
};
Self::remove_outer_parens(cx, value.span, &expr_text, msg);
let keep_space = (
left_pos.map(|s| s >= value.span.lo()).unwrap_or(false),
right_pos.map(|s| s <= value.span.hi()).unwrap_or(false),
);
Self::remove_outer_parens(cx, value.span, &expr_text, msg, keep_space);
}
}
ast::ExprKind::Let(_, ref expr) => {
// FIXME(#60336): Properly handle `let true = (false && true)`
// actually needing the parenthesis.
self.check_unused_parens_expr(cx, expr, "`let` head expression", followed_by_block);
self.check_unused_parens_expr(
cx, expr,
"`let` head expression",
followed_by_block,
None, None
);
}
_ => {}
}
......@@ -394,11 +409,15 @@ fn check_unused_parens_pat(&self,
} else {
pprust::pat_to_string(value)
};
Self::remove_outer_parens(cx, value.span, &pattern_text, msg);
Self::remove_outer_parens(cx, value.span, &pattern_text, msg, (false, false));
}
}
fn remove_outer_parens(cx: &EarlyContext<'_>, span: Span, pattern: &str, msg: &str) {
fn remove_outer_parens(cx: &EarlyContext<'_>,
span: Span,
pattern: &str,
msg: &str,
keep_space: (bool, bool)) {
let span_msg = format!("unnecessary parentheses around {}", msg);
let mut err = cx.struct_span_lint(UNUSED_PARENS, span, &span_msg);
let mut ate_left_paren = false;
......@@ -424,11 +443,27 @@ fn remove_outer_parens(cx: &EarlyContext<'_>, span: Span, pattern: &str, msg: &s
},
_ => false,
}
}).to_owned();
});
let replace = {
let mut replace = if keep_space.0 {
let mut s = String::from(" ");
s.push_str(parens_removed);
s
} else {
String::from(parens_removed)
};
if keep_space.1 {
replace.push(' ');
}
replace
};
err.span_suggestion_short(
span,
"remove these parentheses",
parens_removed,
replace,
Applicability::MachineApplicable,
);
err.emit();
......@@ -438,14 +473,35 @@ fn remove_outer_parens(cx: &EarlyContext<'_>, span: Span, pattern: &str, msg: &s
impl EarlyLintPass for UnusedParens {
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
use syntax::ast::ExprKind::*;
let (value, msg, followed_by_block) = match e.node {
If(ref cond, ..) => (cond, "`if` condition", true),
While(ref cond, ..) => (cond, "`while` condition", true),
ForLoop(_, ref cond, ..) => (cond, "`for` head expression", true),
Match(ref head, _) => (head, "`match` head expression", true),
Ret(Some(ref value)) => (value, "`return` value", false),
Assign(_, ref value) => (value, "assigned value", false),
AssignOp(.., ref value) => (value, "assigned value", false),
let (value, msg, followed_by_block, left_pos, right_pos) = match e.node {
If(ref cond, ref block, ..) => {
let left = e.span.lo() + syntax_pos::BytePos(2);
let right = block.span.lo();
(cond, "`if` condition", true, Some(left), Some(right))
}
While(ref cond, ref block, ..) => {
let left = e.span.lo() + syntax_pos::BytePos(5);
let right = block.span.lo();
(cond, "`while` condition", true, Some(left), Some(right))
},
ForLoop(_, ref cond, ref block, ..) => {
(cond, "`for` head expression", true, None, Some(block.span.lo()))
}
Match(ref head, _) => {
let left = e.span.lo() + syntax_pos::BytePos(5);
(head, "`match` head expression", true, Some(left), None)
}
Ret(Some(ref value)) => {
let left = e.span.lo() + syntax_pos::BytePos(3);
(value, "`return` value", false, Some(left), None)
}
Assign(_, ref value) => (value, "assigned value", false, None, None),
AssignOp(.., ref value) => (value, "assigned value", false, None, None),
// either function/method call, or something this lint doesn't care about
ref call_or_other => {
let (args_to_check, call_kind) = match *call_or_other {
......@@ -467,12 +523,12 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
}
let msg = format!("{} argument", call_kind);
for arg in args_to_check {
self.check_unused_parens_expr(cx, arg, &msg, false);
self.check_unused_parens_expr(cx, arg, &msg, false, None, None);
}
return;
}
};
self.check_unused_parens_expr(cx, &value, msg, followed_by_block);
self.check_unused_parens_expr(cx, &value, msg, followed_by_block, left_pos, right_pos);
}
fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &ast::Pat) {
......@@ -492,7 +548,7 @@ fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &ast::Pat) {
fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
if let ast::StmtKind::Local(ref local) = s.node {
if let Some(ref value) = local.init {
self.check_unused_parens_expr(cx, &value, "assigned value", false);
self.check_unused_parens_expr(cx, &value, "assigned value", false, None, None);
}
}
}
......
......@@ -177,7 +177,7 @@ fn append_place_to_string(
buf.push_str(&self.infcx.tcx.item_name(*def_id).to_string());
}
PlaceRef {
ref base,
base,
projection: Some(ref proj),
} => {
match proj.elem {
......@@ -197,7 +197,7 @@ fn append_place_to_string(
// FIXME turn this recursion into iteration
self.append_place_to_string(
PlaceRef {
base: &base,
base,
projection: &proj.base,
},
buf,
......@@ -210,7 +210,7 @@ fn append_place_to_string(
if self.body.local_decls[*local].is_ref_for_guard() {
self.append_place_to_string(
PlaceRef {
base: &base,
base,
projection: &proj.base,
},
buf,
......@@ -222,7 +222,7 @@ fn append_place_to_string(
buf.push_str(&"*");
self.append_place_to_string(
PlaceRef {
base: &base,
base,
projection: &proj.base,
},
buf,
......@@ -236,7 +236,7 @@ fn append_place_to_string(
buf.push_str(&"*");
self.append_place_to_string(
PlaceRef {
base: &base,
base,
projection: &proj.base,
},
buf,
......@@ -251,7 +251,7 @@ fn append_place_to_string(
ProjectionElem::Downcast(..) => {
self.append_place_to_string(
PlaceRef {
base: &base,
base,
projection: &proj.base,
},
buf,
......@@ -273,12 +273,12 @@ fn append_place_to_string(
buf.push_str(&name);
} else {
let field_name = self.describe_field(PlaceRef {
base: base,
base,
projection: &proj.base,
}, field);
self.append_place_to_string(
PlaceRef {
base: &base,
base,
projection: &proj.base,
},
buf,
......@@ -293,7 +293,7 @@ fn append_place_to_string(
self.append_place_to_string(
PlaceRef {
base: &base,
base,
projection: &proj.base,
},
buf,
......@@ -313,7 +313,7 @@ fn append_place_to_string(
// to avoid confusing the end-user
self.append_place_to_string(
PlaceRef {
base: &base,
base,
projection: &proj.base,
},
buf,
......
......@@ -2027,7 +2027,6 @@ fn main() {
end of the function body. So a reference to them cannot be returned.
```compile_fail,E0515
#![feature(nll)]
fn get_dangling_reference() -> &'static i32 {
let x = 0;
&x
......@@ -2035,7 +2034,6 @@ fn get_dangling_reference() -> &'static i32 {
```
```compile_fail,E0515
#![feature(nll)]
use std::slice::Iter;
fn get_dangling_iterator<'a>() -> Iter<'a, i32> {
let v = vec![1, 2, 3];
......@@ -2233,7 +2231,6 @@ struct Foo<'a> {
Example of erroneous code:
```compile_fail,E0712
#![feature(nll)]
#![feature(thread_local)]
#[thread_local]
......@@ -2286,8 +2283,6 @@ impl<'a> Drop for S<'a> {
by reference:
```
#![feature(nll)]
pub struct S<'a> { data: &'a mut String }
impl<'a> Drop for S<'a> {
......@@ -2312,7 +2307,6 @@ impl<'a> Drop for S<'a> {
Erroneous code example:
```compile_fail,E0716
# #![feature(nll)]
fn foo() -> i32 { 22 }
fn bar(x: &i32) -> &i32 { x }
let p = bar(&foo());
......
// Test that niche finding works with captured generator upvars.
#![feature(generators)]
use std::mem::size_of_val;
fn take<T>(_: T) {}
fn main() {
let x = false;
let gen1 = || {
yield;
take(x);
};
assert_eq!(size_of_val(&gen1), size_of_val(&Some(gen1)));
}
......@@ -93,9 +93,27 @@ async fn joined_with_noop() {
joiner.await
}
async fn mixed_sizes() {
let a = BigFut::new();
let b = BigFut::new();
let c = BigFut::new();
let d = BigFut::new();
let e = BigFut::new();
let joiner = Joiner {
a: Some(a),
b: Some(b),
c: Some(c),
};
d.await;
e.await;
joiner.await;
}
fn main() {
assert_eq!(1028, std::mem::size_of_val(&single()));
assert_eq!(1032, std::mem::size_of_val(&single_with_noop()));
assert_eq!(3084, std::mem::size_of_val(&joined()));
assert_eq!(3084, std::mem::size_of_val(&joined_with_noop()));
assert_eq!(7188, std::mem::size_of_val(&mixed_sizes()));
}
// aux-build:arc_wake.rs
// edition:2018
// run-pass
#![allow(unused_variables)]
#![deny(dead_code)]
#![feature(async_await)]
// Test that the drop order for locals in a fn and async fn matches up.
extern crate arc_wake;
use arc_wake::ArcWake;
use std::cell::RefCell;
use std::future::Future;
use std::marker::PhantomData;
use std::pin::Pin;
use std::rc::Rc;
use std::sync::Arc;
use std::task::{Context, Poll};
struct EmptyWaker;
impl ArcWake for EmptyWaker {
fn wake(self: Arc<Self>) {}
}
#[derive(Debug, Eq, PartialEq)]
enum DropOrder {
Function,
Val(&'static str),
}
type DropOrderListPtr = Rc<RefCell<Vec<DropOrder>>>;
struct D(&'static str, DropOrderListPtr);
impl Drop for D {
fn drop(&mut self) {
self.1.borrow_mut().push(DropOrder::Val(self.0));
}
}
struct NeverReady;
impl Future for NeverReady {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
Poll::Pending
}
}
async fn simple_variable_declaration_async(l: DropOrderListPtr) {
l.borrow_mut().push(DropOrder::Function);
let x = D("x", l.clone());
let y = D("y", l.clone());
NeverReady.await;
}
fn simple_variable_declaration_sync(l: DropOrderListPtr) {
l.borrow_mut().push(DropOrder::Function);
let x = D("x", l.clone());
let y = D("y", l.clone());
}
async fn varable_completely_contained_within_block_async(l: DropOrderListPtr) {
l.borrow_mut().push(DropOrder::Function);
async {
let x = D("x", l.clone());
}
.await;
let y = D("y", l.clone());
NeverReady.await;
}
fn varable_completely_contained_within_block_sync(l: DropOrderListPtr) {
l.borrow_mut().push(DropOrder::Function);
{
let x = D("x", l.clone());
}
let y = D("y", l.clone());
}
async fn variables_moved_into_separate_blocks_async(l: DropOrderListPtr) {
l.borrow_mut().push(DropOrder::Function);
let x = D("x", l.clone());
let y = D("y", l.clone());
async move { x }.await;
async move { y }.await;
NeverReady.await;
}
fn variables_moved_into_separate_blocks_sync(l: DropOrderListPtr) {
l.borrow_mut().push(DropOrder::Function);
let x = D("x", l.clone());
let y = D("y", l.clone());
{
x
};
{
y
};
}
async fn variables_moved_into_same_block_async(l: DropOrderListPtr) {
l.borrow_mut().push(DropOrder::Function);
let x = D("x", l.clone());
let y = D("y", l.clone());
async move {
x;
y;
};
NeverReady.await;
}
fn variables_moved_into_same_block_sync(l: DropOrderListPtr) {
l.borrow_mut().push(DropOrder::Function);
let x = D("x", l.clone());
let y = D("y", l.clone());
{
x;
y;
};
return;
}
async fn move_after_current_await_doesnt_affect_order(l: DropOrderListPtr) {
l.borrow_mut().push(DropOrder::Function);
let x = D("x", l.clone());
let y = D("y", l.clone());
NeverReady.await;
async move {
x;
y;
};
}
fn assert_drop_order_after_cancel<Fut: Future<Output = ()>>(
f: impl FnOnce(DropOrderListPtr) -> Fut,
g: impl FnOnce(DropOrderListPtr),
) {
let empty = Arc::new(EmptyWaker);
let waker = ArcWake::into_waker(empty);
let mut cx = Context::from_waker(&waker);
let actual_order = Rc::new(RefCell::new(Vec::new()));
let mut fut = Box::pin(f(actual_order.clone()));
let _ = fut.as_mut().poll(&mut cx);
drop(fut);
let expected_order = Rc::new(RefCell::new(Vec::new()));
g(expected_order.clone());
assert_eq!(*actual_order.borrow(), *expected_order.borrow());
}
fn main() {
assert_drop_order_after_cancel(
simple_variable_declaration_async,
simple_variable_declaration_sync,
);
assert_drop_order_after_cancel(
varable_completely_contained_within_block_async,
varable_completely_contained_within_block_sync,
);
assert_drop_order_after_cancel(
variables_moved_into_separate_blocks_async,
variables_moved_into_separate_blocks_sync,
);
assert_drop_order_after_cancel(
variables_moved_into_same_block_async,
variables_moved_into_same_block_sync,
);
assert_drop_order_after_cancel(
move_after_current_await_doesnt_affect_order,
simple_variable_declaration_sync,
);
}
// aux-build:arc_wake.rs
// edition:2018
// run-pass
#![allow(unused_variables)]
#![feature(async_await)]
// Test that the drop order for parameters in a fn and async fn matches up. Also test that
// parameters (used or unused) are not dropped until the async fn is cancelled.
// This file is mostly copy-pasted from drop-order-for-async-fn-parameters.rs
extern crate arc_wake;
use arc_wake::ArcWake;
use std::cell::RefCell;
use std::future::Future;
use std::marker::PhantomData;
use std::pin::Pin;
use std::rc::Rc;
use std::sync::Arc;
use std::task::{Context, Poll};
struct EmptyWaker;
impl ArcWake for EmptyWaker {
fn wake(self: Arc<Self>) {}
}
#[derive(Debug, Eq, PartialEq)]
enum DropOrder {
Function,
Val(&'static str),
}
type DropOrderListPtr = Rc<RefCell<Vec<DropOrder>>>;
struct D(&'static str, DropOrderListPtr);
impl Drop for D {
fn drop(&mut self) {
self.1.borrow_mut().push(DropOrder::Val(self.0));
}
}
struct NeverReady;
impl Future for NeverReady {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
Poll::Pending
}
}
/// Check that unused bindings are dropped after the function is polled.
async fn foo_async(x: D, _y: D) {
x.1.borrow_mut().push(DropOrder::Function);
NeverReady.await;
}
fn foo_sync(x: D, _y: D) {
x.1.borrow_mut().push(DropOrder::Function);
}
/// Check that underscore patterns are dropped after the function is polled.
async fn bar_async(x: D, _: D) {
x.1.borrow_mut().push(DropOrder::Function);
NeverReady.await;
}
fn bar_sync(x: D, _: D) {
x.1.borrow_mut().push(DropOrder::Function);
}
/// Check that underscore patterns within more complex patterns are dropped after the function
/// is polled.
async fn baz_async((x, _): (D, D)) {
x.1.borrow_mut().push(DropOrder::Function);
NeverReady.await;
}
fn baz_sync((x, _): (D, D)) {
x.1.borrow_mut().push(DropOrder::Function);
}
/// Check that underscore and unused bindings within and outwith more complex patterns are dropped
/// after the function is polled.
async fn foobar_async(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
x.1.borrow_mut().push(DropOrder::Function);
NeverReady.await;
}
fn foobar_sync(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
x.1.borrow_mut().push(DropOrder::Function);
}
struct Foo;
impl Foo {
/// Check that unused bindings are dropped after the method is polled.
async fn foo_async(x: D, _y: D) {
x.1.borrow_mut().push(DropOrder::Function);
NeverReady.await;
}
fn foo_sync(x: D, _y: D) {
x.1.borrow_mut().push(DropOrder::Function);
}
/// Check that underscore patterns are dropped after the method is polled.
async fn bar_async(x: D, _: D) {
x.1.borrow_mut().push(DropOrder::Function);
NeverReady.await;
}
fn bar_sync(x: D, _: D) {
x.1.borrow_mut().push(DropOrder::Function);
}
/// Check that underscore patterns within more complex patterns are dropped after the method
/// is polled.
async fn baz_async((x, _): (D, D)) {
x.1.borrow_mut().push(DropOrder::Function);
NeverReady.await;
}
fn baz_sync((x, _): (D, D)) {
x.1.borrow_mut().push(DropOrder::Function);
}
/// Check that underscore and unused bindings within and outwith more complex patterns are
/// dropped after the method is polled.
async fn foobar_async(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
x.1.borrow_mut().push(DropOrder::Function);
NeverReady.await;
}
fn foobar_sync(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
x.1.borrow_mut().push(DropOrder::Function);
}
}
struct Bar<'a>(PhantomData<&'a ()>);
impl<'a> Bar<'a> {
/// Check that unused bindings are dropped after the method with self is polled.
async fn foo_async(&'a self, x: D, _y: D) {
x.1.borrow_mut().push(DropOrder::Function);
NeverReady.await;
}
fn foo_sync(&'a self, x: D, _y: D) {
x.1.borrow_mut().push(DropOrder::Function);
}
/// Check that underscore patterns are dropped after the method with self is polled.
async fn bar_async(&'a self, x: D, _: D) {
x.1.borrow_mut().push(DropOrder::Function);
NeverReady.await;
}
fn bar_sync(&'a self, x: D, _: D) {
x.1.borrow_mut().push(DropOrder::Function);
}
/// Check that underscore patterns within more complex patterns are dropped after the method
/// with self is polled.
async fn baz_async(&'a self, (x, _): (D, D)) {
x.1.borrow_mut().push(DropOrder::Function);
NeverReady.await;
}
fn baz_sync(&'a self, (x, _): (D, D)) {
x.1.borrow_mut().push(DropOrder::Function);
}
/// Check that underscore and unused bindings within and outwith more complex patterns are
/// dropped after the method with self is polled.
async fn foobar_async(&'a self, x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
x.1.borrow_mut().push(DropOrder::Function);
NeverReady.await;
}
fn foobar_sync(&'a self, x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
x.1.borrow_mut().push(DropOrder::Function);
}
}
fn assert_drop_order_after_cancel<Fut: Future<Output = ()>>(
f: impl FnOnce(DropOrderListPtr) -> Fut,
g: impl FnOnce(DropOrderListPtr),
) {
let empty = Arc::new(EmptyWaker);
let waker = ArcWake::into_waker(empty);
let mut cx = Context::from_waker(&waker);
let actual_order = Rc::new(RefCell::new(Vec::new()));
let mut fut = Box::pin(f(actual_order.clone()));
let _ = fut.as_mut().poll(&mut cx);
// Parameters are never dropped until the future completes.
assert_eq!(*actual_order.borrow(), vec![DropOrder::Function]);
drop(fut);
let expected_order = Rc::new(RefCell::new(Vec::new()));
g(expected_order.clone());
assert_eq!(*actual_order.borrow(), *expected_order.borrow());
}
fn main() {
// Free functions (see doc comment on function for what it tests).
assert_drop_order_after_cancel(
|l| foo_async(D("x", l.clone()), D("_y", l.clone())),
|l| foo_sync(D("x", l.clone()), D("_y", l.clone())),
);
assert_drop_order_after_cancel(
|l| bar_async(D("x", l.clone()), D("_", l.clone())),
|l| bar_sync(D("x", l.clone()), D("_", l.clone())),
);
assert_drop_order_after_cancel(
|l| baz_async((D("x", l.clone()), D("_", l.clone()))),
|l| baz_sync((D("x", l.clone()), D("_", l.clone()))),
);
assert_drop_order_after_cancel(
|l| {
foobar_async(
D("x", l.clone()),
(D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
D("_", l.clone()),
D("_y", l.clone()),
)
},
|l| {
foobar_sync(
D("x", l.clone()),
(D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
D("_", l.clone()),
D("_y", l.clone()),
)
},
);
// Methods w/out self (see doc comment on function for what it tests).
assert_drop_order_after_cancel(
|l| Foo::foo_async(D("x", l.clone()), D("_y", l.clone())),
|l| Foo::foo_sync(D("x", l.clone()), D("_y", l.clone())),
);
assert_drop_order_after_cancel(
|l| Foo::bar_async(D("x", l.clone()), D("_", l.clone())),
|l| Foo::bar_sync(D("x", l.clone()), D("_", l.clone())),
);
assert_drop_order_after_cancel(
|l| Foo::baz_async((D("x", l.clone()), D("_", l.clone()))),
|l| Foo::baz_sync((D("x", l.clone()), D("_", l.clone()))),
);
assert_drop_order_after_cancel(
|l| {
Foo::foobar_async(
D("x", l.clone()),
(D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
D("_", l.clone()),
D("_y", l.clone()),
)
},
|l| {
Foo::foobar_sync(
D("x", l.clone()),
(D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
D("_", l.clone()),
D("_y", l.clone()),
)
},
);
// Methods (see doc comment on function for what it tests).
let b = Bar(Default::default());
assert_drop_order_after_cancel(
|l| b.foo_async(D("x", l.clone()), D("_y", l.clone())),
|l| b.foo_sync(D("x", l.clone()), D("_y", l.clone())),
);
assert_drop_order_after_cancel(
|l| b.bar_async(D("x", l.clone()), D("_", l.clone())),
|l| b.bar_sync(D("x", l.clone()), D("_", l.clone())),
);
assert_drop_order_after_cancel(
|l| b.baz_async((D("x", l.clone()), D("_", l.clone()))),
|l| b.baz_sync((D("x", l.clone()), D("_", l.clone()))),
);
assert_drop_order_after_cancel(
|l| {
b.foobar_async(
D("x", l.clone()),
(D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
D("_", l.clone()),
D("_y", l.clone()),
)
},
|l| {
b.foobar_sync(
D("x", l.clone()),
(D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
D("_", l.clone()),
D("_y", l.clone()),
)
},
);
}
// Incorrect handling of uninhabited types could cause us to mark generator
// types as entirely uninhabited, when they were in fact constructible. This
// caused us to hit "unreachable" code (illegal instruction on x86).
// run-pass
// compile-flags: --edition=2018
......@@ -19,7 +23,18 @@ async fn contains_never() {
let error2 = error;
}
#[allow(unused)]
async fn overlap_never() {
let error1 = uninhabited_async();
noop().await;
let error2 = uninhabited_async();
drop(error1);
noop().await;
drop(error2);
}
#[allow(unused_must_use)]
fn main() {
contains_never();
overlap_never();
}
// build-pass
// edition:2018
// compile-flags: --crate-type lib
#![feature(async_await)]
struct Small {
x: Vec<usize>,
y: Vec<usize>,
}
// You are allowed to move out part of a struct to an async fn, you still
// have access to remaining parts after awaiting
async fn move_part_await_return_rest_struct() -> Vec<usize> {
let s = Small { x: vec![31], y: vec![19, 1441] };
needs_vec(s.x).await;
s.y
}
async fn needs_vec(_vec: Vec<usize>) {}
// build-pass
// edition:2018
// compile-flags: --crate-type lib
#![feature(async_await)]
async fn move_part_await_return_rest_tuple() -> Vec<usize> {
let x = (vec![3], vec![4, 4]);
drop(x.1);
echo(x.0[0]).await;
x.0
}
async fn echo(x: usize) -> usize { x }
// compile-fail
// edition:2018
// compile-flags: --crate-type lib
#![feature(async_await)]
async fn no_move_across_await_struct() -> Vec<usize> {
let s = Small { x: vec![31], y: vec![19, 1441] };
needs_vec(s.x).await;
s.x
//~^ ERROR use of moved value: `s.x`
}
struct Small {
x: Vec<usize>,
y: Vec<usize>,
}
async fn needs_vec(_vec: Vec<usize>) {}
error[E0382]: use of moved value: `s.x`
--> $DIR/no-move-across-await-struct.rs:10:5
|
LL | needs_vec(s.x).await;
| --- value moved here
LL | s.x
| ^^^ value used here after move
|
= note: move occurs because `s.x` has type `std::vec::Vec<usize>`, which does not implement the `Copy` trait
error: aborting due to previous error
For more information about this error, try `rustc --explain E0382`.
// compile-fail
// edition:2018
// compile-flags: --crate-type lib
#![feature(async_await)]
async fn no_move_across_await_tuple() -> Vec<usize> {
let x = (vec![3], vec![4, 4]);
drop(x.1);
nothing().await;
x.1
//~^ ERROR use of moved value: `x.1`
}
async fn nothing() {}
error[E0382]: use of moved value: `x.1`
--> $DIR/no-move-across-await-tuple.rs:11:5
|
LL | drop(x.1);
| --- value moved here
LL | nothing().await;
LL | x.1
| ^^^ value used here after move
|
= note: move occurs because `x.1` has type `std::vec::Vec<usize>`, which does not implement the `Copy` trait
error: aborting due to previous error
For more information about this error, try `rustc --explain E0382`.
// compile-flags: --error-format pretty-json -Zunstable-options
// build-pass (FIXME(62277): could be check-pass?)
// run-rustfix
// The output for humans should just highlight the whole span without showing
// the suggested replacement, but we also want to test that suggested
// replacement only removes one set of parentheses, rather than naïvely
// stripping away any starting or ending parenthesis characters—hence this
// test of the JSON error format.
#![warn(unused_parens)]
#![allow(unreachable_code)]
fn main() {
// We want to suggest the properly-balanced expression `1 / (2 + 3)`, not
// the malformed `1 / (2 + 3`
let _a = 1 / (2 + 3);
f();
}
fn f() -> bool {
loop {
if (break { return true }) {
}
}
false
}
// compile-flags: --error-format pretty-json -Zunstable-options
// build-pass (FIXME(62277): could be check-pass?)
// run-rustfix
// The output for humans should just highlight the whole span without showing
// the suggested replacement, but we also want to test that suggested
......@@ -8,6 +9,7 @@
// test of the JSON error format.
#![warn(unused_parens)]
#![allow(unreachable_code)]
fn main() {
// We want to suggest the properly-balanced expression `1 / (2 + 3)`, not
......
......@@ -8,10 +8,10 @@
"spans": [
{
"file_name": "$DIR/unused_parens_json_suggestion.rs",
"byte_start": 611,
"byte_end": 624,
"line_start": 15,
"line_end": 15,
"byte_start": 654,
"byte_end": 667,
"line_start": 17,
"line_end": 17,
"column_start": 14,
"column_end": 27,
"is_primary": true,
......@@ -36,10 +36,10 @@
"spans": [
{
"file_name": "$DIR/unused_parens_json_suggestion.rs",
"byte_start": 457,
"byte_end": 470,
"line_start": 10,
"line_end": 10,
"byte_start": 472,
"byte_end": 485,
"line_start": 11,
"line_end": 11,
"column_start": 9,
"column_end": 22,
"is_primary": true,
......@@ -66,10 +66,10 @@
"spans": [
{
"file_name": "$DIR/unused_parens_json_suggestion.rs",
"byte_start": 611,
"byte_end": 624,
"line_start": 15,
"line_end": 15,
"byte_start": 654,
"byte_end": 667,
"line_start": 17,
"line_end": 17,
"column_start": 14,
"column_end": 27,
"is_primary": true,
......@@ -91,13 +91,13 @@
}
],
"rendered": "warning: unnecessary parentheses around assigned value
--> $DIR/unused_parens_json_suggestion.rs:15:14
--> $DIR/unused_parens_json_suggestion.rs:17:14
|
LL | let _a = (1 / (2 + 3));
| ^^^^^^^^^^^^^ help: remove these parentheses
|
note: lint level defined here
--> $DIR/unused_parens_json_suggestion.rs:10:9
--> $DIR/unused_parens_json_suggestion.rs:11:9
|
LL | #![warn(unused_parens)]
| ^^^^^^^^^^^^^
......
// compile-flags: --error-format pretty-json -Zunstable-options
// build-pass
// run-rustfix
// The output for humans should just highlight the whole span without showing
// the suggested replacement, but we also want to test that suggested
// replacement only removes one set of parentheses, rather than naïvely
// stripping away any starting or ending parenthesis characters—hence this
// test of the JSON error format.
#![warn(unused_parens)]
#![allow(unreachable_code)]
fn main() {
let _b = false;
if _b {
println!("hello");
}
f();
}
fn f() -> bool {
let c = false;
if c {
println!("next");
}
if c {
println!("prev");
}
while false && true {
if c {
println!("norm");
}
}
while true && false {
for _ in 0 .. 3 {
println!("e~")
}
}
for _ in 0 .. 3 {
while true && false {
println!("e~")
}
}
loop {
if (break { return true }) {
}
}
false
}
// compile-flags: --error-format pretty-json -Zunstable-options
// build-pass
// run-rustfix
// The output for humans should just highlight the whole span without showing
// the suggested replacement, but we also want to test that suggested
// replacement only removes one set of parentheses, rather than naïvely
// stripping away any starting or ending parenthesis characters—hence this
// test of the JSON error format.
#![warn(unused_parens)]
#![allow(unreachable_code)]
fn main() {
let _b = false;
if (_b) {
println!("hello");
}
f();
}
fn f() -> bool {
let c = false;
if(c) {
println!("next");
}
if (c){
println!("prev");
}
while (false && true){
if (c) {
println!("norm");
}
}
while(true && false) {
for _ in (0 .. 3){
println!("e~")
}
}
for _ in (0 .. 3) {
while (true && false) {
println!("e~")
}
}
loop {
if (break { return true }) {
}
}
false
}
{
"message": "unnecessary parentheses around `if` condition",
"code": {
"code": "unused_parens",
"explanation": null
},
"level": "warning",
"spans": [
{
"file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
"byte_start": 521,
"byte_end": 525,
"line_start": 18,
"line_end": 18,
"column_start": 8,
"column_end": 12,
"is_primary": true,
"text": [
{
"text": " if (_b) {",
"highlight_start": 8,
"highlight_end": 12
}
],
"label": null,
"suggested_replacement": null,
"suggestion_applicability": null,
"expansion": null
}
],
"children": [
{
"message": "lint level defined here",
"code": null,
"level": "note",
"spans": [
{
"file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
"byte_start": 435,
"byte_end": 448,
"line_start": 11,
"line_end": 11,
"column_start": 9,
"column_end": 22,
"is_primary": true,
"text": [
{
"text": "#![warn(unused_parens)]",
"highlight_start": 9,
"highlight_end": 22
}
],
"label": null,
"suggested_replacement": null,
"suggestion_applicability": null,
"expansion": null
}
],
"children": [],
"rendered": null
},
{
"message": "remove these parentheses",
"code": null,
"level": "help",
"spans": [
{
"file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
"byte_start": 521,
"byte_end": 525,
"line_start": 18,
"line_end": 18,
"column_start": 8,
"column_end": 12,
"is_primary": true,
"text": [
{
"text": " if (_b) {",
"highlight_start": 8,
"highlight_end": 12
}
],
"label": null,
"suggested_replacement": "_b",
"suggestion_applicability": "MachineApplicable",
"expansion": null
}
],
"children": [],
"rendered": null
}
],
"rendered": "warning: unnecessary parentheses around `if` condition
--> $DIR/unused_parens_remove_json_suggestion.rs:18:8
|
LL | if (_b) {
| ^^^^ help: remove these parentheses
|
note: lint level defined here
--> $DIR/unused_parens_remove_json_suggestion.rs:11:9
|
LL | #![warn(unused_parens)]
| ^^^^^^^^^^^^^
"
}
{
"message": "unnecessary parentheses around `if` condition",
"code": {
"code": "unused_parens",
"explanation": null
},
"level": "warning",
"spans": [
{
"file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
"byte_start": 618,
"byte_end": 621,
"line_start": 29,
"line_end": 29,
"column_start": 7,
"column_end": 10,
"is_primary": true,
"text": [
{
"text": " if(c) {",
"highlight_start": 7,
"highlight_end": 10
}
],
"label": null,
"suggested_replacement": null,
"suggestion_applicability": null,
"expansion": null
}
],
"children": [
{
"message": "remove these parentheses",
"code": null,
"level": "help",
"spans": [
{
"file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
"byte_start": 618,
"byte_end": 621,
"line_start": 29,
"line_end": 29,
"column_start": 7,
"column_end": 10,
"is_primary": true,
"text": [
{
"text": " if(c) {",
"highlight_start": 7,
"highlight_end": 10
}
],
"label": null,
"suggested_replacement": " c",
"suggestion_applicability": "MachineApplicable",
"expansion": null
}
],
"children": [],
"rendered": null
}
],
"rendered": "warning: unnecessary parentheses around `if` condition
--> $DIR/unused_parens_remove_json_suggestion.rs:29:7
|
LL | if(c) {
| ^^^ help: remove these parentheses
"
}
{
"message": "unnecessary parentheses around `if` condition",
"code": {
"code": "unused_parens",
"explanation": null
},
"level": "warning",
"spans": [
{
"file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
"byte_start": 664,
"byte_end": 667,
"line_start": 33,
"line_end": 33,
"column_start": 8,
"column_end": 11,
"is_primary": true,
"text": [
{
"text": " if (c){",
"highlight_start": 8,
"highlight_end": 11
}
],
"label": null,
"suggested_replacement": null,
"suggestion_applicability": null,
"expansion": null
}
],
"children": [
{
"message": "remove these parentheses",
"code": null,
"level": "help",
"spans": [
{
"file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
"byte_start": 664,
"byte_end": 667,
"line_start": 33,
"line_end": 33,
"column_start": 8,
"column_end": 11,
"is_primary": true,
"text": [
{
"text": " if (c){",
"highlight_start": 8,
"highlight_end": 11
}
],
"label": null,
"suggested_replacement": "c ",
"suggestion_applicability": "MachineApplicable",
"expansion": null
}
],
"children": [],
"rendered": null
}
],
"rendered": "warning: unnecessary parentheses around `if` condition
--> $DIR/unused_parens_remove_json_suggestion.rs:33:8
|
LL | if (c){
| ^^^ help: remove these parentheses
"
}
{
"message": "unnecessary parentheses around `while` condition",
"code": {
"code": "unused_parens",
"explanation": null
},
"level": "warning",
"spans": [
{
"file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
"byte_start": 712,
"byte_end": 727,
"line_start": 37,
"line_end": 37,
"column_start": 11,
"column_end": 26,
"is_primary": true,
"text": [
{
"text": " while (false && true){",
"highlight_start": 11,
"highlight_end": 26
}
],
"label": null,
"suggested_replacement": null,
"suggestion_applicability": null,
"expansion": null
}
],
"children": [
{
"message": "remove these parentheses",
"code": null,
"level": "help",
"spans": [
{
"file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
"byte_start": 712,
"byte_end": 727,
"line_start": 37,
"line_end": 37,
"column_start": 11,
"column_end": 26,
"is_primary": true,
"text": [
{
"text": " while (false && true){",
"highlight_start": 11,
"highlight_end": 26
}
],
"label": null,
"suggested_replacement": "false && true ",
"suggestion_applicability": "MachineApplicable",
"expansion": null
}
],
"children": [],
"rendered": null
}
],
"rendered": "warning: unnecessary parentheses around `while` condition
--> $DIR/unused_parens_remove_json_suggestion.rs:37:11
|
LL | while (false && true){
| ^^^^^^^^^^^^^^^ help: remove these parentheses
"
}
{
"message": "unnecessary parentheses around `if` condition",
"code": {
"code": "unused_parens",
"explanation": null
},
"level": "warning",
"spans": [
{
"file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
"byte_start": 740,
"byte_end": 743,
"line_start": 38,
"line_end": 38,
"column_start": 12,
"column_end": 15,
"is_primary": true,
"text": [
{
"text": " if (c) {",
"highlight_start": 12,
"highlight_end": 15
}
],
"label": null,
"suggested_replacement": null,
"suggestion_applicability": null,
"expansion": null
}
],
"children": [
{
"message": "remove these parentheses",
"code": null,
"level": "help",
"spans": [
{
"file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
"byte_start": 740,
"byte_end": 743,
"line_start": 38,
"line_end": 38,
"column_start": 12,
"column_end": 15,
"is_primary": true,
"text": [
{
"text": " if (c) {",
"highlight_start": 12,
"highlight_end": 15
}
],
"label": null,
"suggested_replacement": "c",
"suggestion_applicability": "MachineApplicable",
"expansion": null
}
],
"children": [],
"rendered": null
}
],
"rendered": "warning: unnecessary parentheses around `if` condition
--> $DIR/unused_parens_remove_json_suggestion.rs:38:12
|
LL | if (c) {
| ^^^ help: remove these parentheses
"
}
{
"message": "unnecessary parentheses around `while` condition",
"code": {
"code": "unused_parens",
"explanation": null
},
"level": "warning",
"spans": [
{
"file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
"byte_start": 803,
"byte_end": 818,
"line_start": 44,
"line_end": 44,
"column_start": 10,
"column_end": 25,
"is_primary": true,
"text": [
{
"text": " while(true && false) {",
"highlight_start": 10,
"highlight_end": 25
}
],
"label": null,
"suggested_replacement": null,
"suggestion_applicability": null,
"expansion": null
}
],
"children": [
{
"message": "remove these parentheses",
"code": null,
"level": "help",
"spans": [
{
"file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
"byte_start": 803,
"byte_end": 818,
"line_start": 44,
"line_end": 44,
"column_start": 10,
"column_end": 25,
"is_primary": true,
"text": [
{
"text": " while(true && false) {",
"highlight_start": 10,
"highlight_end": 25
}
],
"label": null,
"suggested_replacement": " true && false",
"suggestion_applicability": "MachineApplicable",
"expansion": null
}
],
"children": [],
"rendered": null
}
],
"rendered": "warning: unnecessary parentheses around `while` condition
--> $DIR/unused_parens_remove_json_suggestion.rs:44:10
|
LL | while(true && false) {
| ^^^^^^^^^^^^^^^ help: remove these parentheses
"
}
{
"message": "unnecessary parentheses around `for` head expression",
"code": {
"code": "unused_parens",
"explanation": null
},
"level": "warning",
"spans": [
{
"file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
"byte_start": 838,
"byte_end": 846,
"line_start": 45,
"line_end": 45,
"column_start": 18,
"column_end": 26,
"is_primary": true,
"text": [
{
"text": " for _ in (0 .. 3){",
"highlight_start": 18,
"highlight_end": 26
}
],
"label": null,
"suggested_replacement": null,
"suggestion_applicability": null,
"expansion": null
}
],
"children": [
{
"message": "remove these parentheses",
"code": null,
"level": "help",
"spans": [
{
"file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
"byte_start": 838,
"byte_end": 846,
"line_start": 45,
"line_end": 45,
"column_start": 18,
"column_end": 26,
"is_primary": true,
"text": [
{
"text": " for _ in (0 .. 3){",
"highlight_start": 18,
"highlight_end": 26
}
],
"label": null,
"suggested_replacement": "0 .. 3 ",
"suggestion_applicability": "MachineApplicable",
"expansion": null
}
],
"children": [],
"rendered": null
}
],
"rendered": "warning: unnecessary parentheses around `for` head expression
--> $DIR/unused_parens_remove_json_suggestion.rs:45:18
|
LL | for _ in (0 .. 3){
| ^^^^^^^^ help: remove these parentheses
"
}
{
"message": "unnecessary parentheses around `for` head expression",
"code": {
"code": "unused_parens",
"explanation": null
},
"level": "warning",
"spans": [
{
"file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
"byte_start": 905,
"byte_end": 913,
"line_start": 50,
"line_end": 50,
"column_start": 14,
"column_end": 22,
"is_primary": true,
"text": [
{
"text": " for _ in (0 .. 3) {",
"highlight_start": 14,
"highlight_end": 22
}
],
"label": null,
"suggested_replacement": null,
"suggestion_applicability": null,
"expansion": null
}
],
"children": [
{
"message": "remove these parentheses",
"code": null,
"level": "help",
"spans": [
{
"file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
"byte_start": 905,
"byte_end": 913,
"line_start": 50,
"line_end": 50,
"column_start": 14,
"column_end": 22,
"is_primary": true,
"text": [
{
"text": " for _ in (0 .. 3) {",
"highlight_start": 14,
"highlight_end": 22
}
],
"label": null,
"suggested_replacement": "0 .. 3",
"suggestion_applicability": "MachineApplicable",
"expansion": null
}
],
"children": [],
"rendered": null
}
],
"rendered": "warning: unnecessary parentheses around `for` head expression
--> $DIR/unused_parens_remove_json_suggestion.rs:50:14
|
LL | for _ in (0 .. 3) {
| ^^^^^^^^ help: remove these parentheses
"
}
{
"message": "unnecessary parentheses around `while` condition",
"code": {
"code": "unused_parens",
"explanation": null
},
"level": "warning",
"spans": [
{
"file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
"byte_start": 930,
"byte_end": 945,
"line_start": 51,
"line_end": 51,
"column_start": 15,
"column_end": 30,
"is_primary": true,
"text": [
{
"text": " while (true && false) {",
"highlight_start": 15,
"highlight_end": 30
}
],
"label": null,
"suggested_replacement": null,
"suggestion_applicability": null,
"expansion": null
}
],
"children": [
{
"message": "remove these parentheses",
"code": null,
"level": "help",
"spans": [
{
"file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
"byte_start": 930,
"byte_end": 945,
"line_start": 51,
"line_end": 51,
"column_start": 15,
"column_end": 30,
"is_primary": true,
"text": [
{
"text": " while (true && false) {",
"highlight_start": 15,
"highlight_end": 30
}
],
"label": null,
"suggested_replacement": "true && false",
"suggestion_applicability": "MachineApplicable",
"expansion": null
}
],
"children": [],
"rendered": null
}
],
"rendered": "warning: unnecessary parentheses around `while` condition
--> $DIR/unused_parens_remove_json_suggestion.rs:51:15
|
LL | while (true && false) {
| ^^^^^^^^^^^^^^^ help: remove these parentheses
"
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册