diff --git a/.gitignore b/.gitignore index 87fec41415272..b53b06b03cac6 100644 --- a/.gitignore +++ b/.gitignore @@ -52,7 +52,6 @@ config.mk config.stamp keywords.md lexer.ml -mir_dump Session.vim src/etc/dl tmp.*.rs diff --git a/src/README.md b/src/README.md index 14e773286bc6a..32ca4a105741b 100644 --- a/src/README.md +++ b/src/README.md @@ -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 diff --git a/src/libcore/mem/maybe_uninit.rs b/src/libcore/mem/maybe_uninit.rs index ff063759cba62..8d064de6f4751 100644 --- a/src/libcore/mem/maybe_uninit.rs +++ b/src/libcore/mem/maybe_uninit.rs @@ -209,6 +209,8 @@ use crate::mem::ManuallyDrop; /// 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 { diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index cc09a0b20cfd5..c5c8639324358 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -365,6 +365,8 @@ language_item_table! { 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. diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index ca6603b58530d..dadc126eba48e 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -2347,10 +2347,9 @@ impl<'tcx> TyCtxt<'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 @@ impl<'tcx> TyCtxt<'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 @@ impl<'tcx> TyCtxt<'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)) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index a66a4ac66f3f5..1c9a5ad621854 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1368,6 +1368,27 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'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 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { 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::, _>>()?; - 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); diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 23b5889202874..6a3dfdbe31684 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -15,7 +15,7 @@ use syntax::print::pprust; 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 @@ declare_lint! { 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, + right_pos: Option) { 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 @@ impl UnusedParens { } 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 @@ impl UnusedParens { }, _ => 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 @@ impl UnusedParens { 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 @@ impl EarlyLintPass for UnusedParens { } 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 @@ impl EarlyLintPass for UnusedParens { 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); } } } diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index c767279dd8c7a..99899aa390c4a 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -177,7 +177,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { 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 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // FIXME turn this recursion into iteration self.append_place_to_string( PlaceRef { - base: &base, + base, projection: &proj.base, }, buf, @@ -210,7 +210,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { 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 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { buf.push_str(&"*"); self.append_place_to_string( PlaceRef { - base: &base, + base, projection: &proj.base, }, buf, @@ -236,7 +236,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { buf.push_str(&"*"); self.append_place_to_string( PlaceRef { - base: &base, + base, projection: &proj.base, }, buf, @@ -251,7 +251,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ProjectionElem::Downcast(..) => { self.append_place_to_string( PlaceRef { - base: &base, + base, projection: &proj.base, }, buf, @@ -273,12 +273,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { 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 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.append_place_to_string( PlaceRef { - base: &base, + base, projection: &proj.base, }, buf, @@ -313,7 +313,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // to avoid confusing the end-user self.append_place_to_string( PlaceRef { - base: &base, + base, projection: &proj.base, }, buf, diff --git a/src/librustc_mir/error_codes.rs b/src/librustc_mir/error_codes.rs index 2afffd71fe206..86c263a447bb6 100644 --- a/src/librustc_mir/error_codes.rs +++ b/src/librustc_mir/error_codes.rs @@ -2027,7 +2027,6 @@ Local variables, function parameters and temporaries are all dropped before the 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 @@ function which outlived the lifetime of the function. Example of erroneous code: ```compile_fail,E0712 -#![feature(nll)] #![feature(thread_local)] #[thread_local] @@ -2286,8 +2283,6 @@ not run while the string-data is borrowed; for example by taking `S` by reference: ``` -#![feature(nll)] - pub struct S<'a> { data: &'a mut String } impl<'a> Drop for S<'a> { @@ -2312,7 +2307,6 @@ while a borrow is still in active use. Erroneous code example: ```compile_fail,E0716 -# #![feature(nll)] fn foo() -> i32 { 22 } fn bar(x: &i32) -> &i32 { x } let p = bar(&foo()); diff --git a/src/test/run-pass/generator/niche-in-generator.rs b/src/test/run-pass/generator/niche-in-generator.rs new file mode 100644 index 0000000000000..9a644ed44a670 --- /dev/null +++ b/src/test/run-pass/generator/niche-in-generator.rs @@ -0,0 +1,17 @@ +// Test that niche finding works with captured generator upvars. + +#![feature(generators)] + +use std::mem::size_of_val; + +fn take(_: T) {} + +fn main() { + let x = false; + let gen1 = || { + yield; + take(x); + }; + + assert_eq!(size_of_val(&gen1), size_of_val(&Some(gen1))); +} diff --git a/src/test/ui/async-await/async-fn-size-moved-locals.rs b/src/test/ui/async-await/async-fn-size-moved-locals.rs index d0d4eb032fcb1..30b59d037d512 100644 --- a/src/test/ui/async-await/async-fn-size-moved-locals.rs +++ b/src/test/ui/async-await/async-fn-size-moved-locals.rs @@ -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())); } diff --git a/src/test/ui/async-await/drop-order/drop-order-for-locals-when-cancelled.rs b/src/test/ui/async-await/drop-order/drop-order-for-locals-when-cancelled.rs new file mode 100644 index 0000000000000..db396d3957e13 --- /dev/null +++ b/src/test/ui/async-await/drop-order/drop-order-for-locals-when-cancelled.rs @@ -0,0 +1,176 @@ +// 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) {} +} + +#[derive(Debug, Eq, PartialEq)] +enum DropOrder { + Function, + Val(&'static str), +} + +type DropOrderListPtr = Rc>>; + +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 { + 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>( + 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, + ); +} diff --git a/src/test/ui/async-await/drop-order/drop-order-when-cancelled.rs b/src/test/ui/async-await/drop-order/drop-order-when-cancelled.rs new file mode 100644 index 0000000000000..410a623681db5 --- /dev/null +++ b/src/test/ui/async-await/drop-order/drop-order-when-cancelled.rs @@ -0,0 +1,307 @@ +// 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) {} +} + +#[derive(Debug, Eq, PartialEq)] +enum DropOrder { + Function, + Val(&'static str), +} + +type DropOrderListPtr = Rc>>; + +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 { + 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>( + 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()), + ) + }, + ); +} diff --git a/src/test/ui/async-await/issues/issue-59972.rs b/src/test/ui/async-await/issues/issue-59972.rs index 1b843720102ab..8f4254b10ceaf 100644 --- a/src/test/ui/async-await/issues/issue-59972.rs +++ b/src/test/ui/async-await/issues/issue-59972.rs @@ -1,3 +1,7 @@ +// 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(); } diff --git a/src/test/ui/async-await/move-part-await-return-rest-struct.rs b/src/test/ui/async-await/move-part-await-return-rest-struct.rs new file mode 100644 index 0000000000000..9bd7a515cbdbf --- /dev/null +++ b/src/test/ui/async-await/move-part-await-return-rest-struct.rs @@ -0,0 +1,20 @@ +// build-pass +// edition:2018 +// compile-flags: --crate-type lib + +#![feature(async_await)] + +struct Small { + x: Vec, + y: Vec, +} + +// 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 { + let s = Small { x: vec![31], y: vec![19, 1441] }; + needs_vec(s.x).await; + s.y +} + +async fn needs_vec(_vec: Vec) {} diff --git a/src/test/ui/async-await/move-part-await-return-rest-tuple.rs b/src/test/ui/async-await/move-part-await-return-rest-tuple.rs new file mode 100644 index 0000000000000..69eee855e7594 --- /dev/null +++ b/src/test/ui/async-await/move-part-await-return-rest-tuple.rs @@ -0,0 +1,14 @@ +// build-pass +// edition:2018 +// compile-flags: --crate-type lib + +#![feature(async_await)] + +async fn move_part_await_return_rest_tuple() -> Vec { + let x = (vec![3], vec![4, 4]); + drop(x.1); + echo(x.0[0]).await; + x.0 +} + +async fn echo(x: usize) -> usize { x } diff --git a/src/test/ui/async-await/no-move-across-await-struct.rs b/src/test/ui/async-await/no-move-across-await-struct.rs new file mode 100644 index 0000000000000..58e094708979c --- /dev/null +++ b/src/test/ui/async-await/no-move-across-await-struct.rs @@ -0,0 +1,19 @@ +// compile-fail +// edition:2018 +// compile-flags: --crate-type lib + +#![feature(async_await)] + +async fn no_move_across_await_struct() -> Vec { + 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, + y: Vec, +} + +async fn needs_vec(_vec: Vec) {} diff --git a/src/test/ui/async-await/no-move-across-await-struct.stderr b/src/test/ui/async-await/no-move-across-await-struct.stderr new file mode 100644 index 0000000000000..121c7791bd98e --- /dev/null +++ b/src/test/ui/async-await/no-move-across-await-struct.stderr @@ -0,0 +1,13 @@ +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`, which does not implement the `Copy` trait + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/async-await/no-move-across-await-tuple.rs b/src/test/ui/async-await/no-move-across-await-tuple.rs new file mode 100644 index 0000000000000..5d3ed3da1e316 --- /dev/null +++ b/src/test/ui/async-await/no-move-across-await-tuple.rs @@ -0,0 +1,15 @@ +// compile-fail +// edition:2018 +// compile-flags: --crate-type lib + +#![feature(async_await)] + +async fn no_move_across_await_tuple() -> Vec { + let x = (vec![3], vec![4, 4]); + drop(x.1); + nothing().await; + x.1 + //~^ ERROR use of moved value: `x.1` +} + +async fn nothing() {} diff --git a/src/test/ui/async-await/no-move-across-await-tuple.stderr b/src/test/ui/async-await/no-move-across-await-tuple.stderr new file mode 100644 index 0000000000000..5da037ea5c0b6 --- /dev/null +++ b/src/test/ui/async-await/no-move-across-await-tuple.stderr @@ -0,0 +1,14 @@ +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`, which does not implement the `Copy` trait + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/lint/unused_parens_json_suggestion.fixed b/src/test/ui/lint/unused_parens_json_suggestion.fixed new file mode 100644 index 0000000000000..427407119102c --- /dev/null +++ b/src/test/ui/lint/unused_parens_json_suggestion.fixed @@ -0,0 +1,27 @@ +// 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 +} diff --git a/src/test/ui/lint/unused_parens_json_suggestion.rs b/src/test/ui/lint/unused_parens_json_suggestion.rs index 185bfacea8046..87192503986c4 100644 --- a/src/test/ui/lint/unused_parens_json_suggestion.rs +++ b/src/test/ui/lint/unused_parens_json_suggestion.rs @@ -1,5 +1,6 @@ // 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 diff --git a/src/test/ui/lint/unused_parens_json_suggestion.stderr b/src/test/ui/lint/unused_parens_json_suggestion.stderr index 396395a17f732..256c7555c908b 100644 --- a/src/test/ui/lint/unused_parens_json_suggestion.stderr +++ b/src/test/ui/lint/unused_parens_json_suggestion.stderr @@ -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)] | ^^^^^^^^^^^^^ diff --git a/src/test/ui/lint/unused_parens_remove_json_suggestion.fixed b/src/test/ui/lint/unused_parens_remove_json_suggestion.fixed new file mode 100644 index 0000000000000..2459eb1ac5cb8 --- /dev/null +++ b/src/test/ui/lint/unused_parens_remove_json_suggestion.fixed @@ -0,0 +1,62 @@ +// 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 +} diff --git a/src/test/ui/lint/unused_parens_remove_json_suggestion.rs b/src/test/ui/lint/unused_parens_remove_json_suggestion.rs new file mode 100644 index 0000000000000..0e9869b67d590 --- /dev/null +++ b/src/test/ui/lint/unused_parens_remove_json_suggestion.rs @@ -0,0 +1,62 @@ +// 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 +} diff --git a/src/test/ui/lint/unused_parens_remove_json_suggestion.stderr b/src/test/ui/lint/unused_parens_remove_json_suggestion.stderr new file mode 100644 index 0000000000000..b4eab200dd016 --- /dev/null +++ b/src/test/ui/lint/unused_parens_remove_json_suggestion.stderr @@ -0,0 +1,666 @@ +{ + "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 + +" +}