From 6fae7f807146e400fa2bbd1c44768d9bcaa57c4c Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Fri, 26 Jul 2019 19:36:26 -0700 Subject: [PATCH 01/16] Wrap promoted generator fields in MaybeUninit This prevents uninhabited fields from "infecting" the abi and largest_niche of the generator layout. This fixes a latent bug, where an uninhabited field could be promoted to the generator prefix and cause the entire generator to become uninhabited. --- src/libcore/mem/maybe_uninit.rs | 2 ++ src/librustc/middle/lang_items.rs | 2 ++ src/librustc/ty/context.rs | 21 ++++++++++++++----- src/librustc/ty/layout.rs | 7 ++----- src/test/ui/async-await/issues/issue-59972.rs | 15 +++++++++++++ 5 files changed, 37 insertions(+), 10 deletions(-) diff --git a/src/libcore/mem/maybe_uninit.rs b/src/libcore/mem/maybe_uninit.rs index 2e88db8df1163..1a37326c132f2 100644 --- a/src/libcore/mem/maybe_uninit.rs +++ b/src/libcore/mem/maybe_uninit.rs @@ -208,6 +208,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 46b8114030f29..57bababc101e4 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 3b4b814c92a90..03b95bc3a943d 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1406,24 +1406,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/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(); } From b12c20ccc30aebb2f5c90f04e2209ef12fe8b759 Mon Sep 17 00:00:00 2001 From: bravomikekilo Date: Wed, 31 Jul 2019 22:56:12 +0800 Subject: [PATCH 02/16] add a pair of whitespace after remove parentheses --- src/librustc_lint/unused.rs | 12 ++++++++++-- .../ui/lint/unused_parens_json_suggestion.stderr | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 4cccaa942b742..9ef34c201e19a 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -424,11 +424,19 @@ impl UnusedParens { }, _ => false, } - }).to_owned(); + }); + + let replace = { + let mut replace = String::from(" "); + replace.push_str(parens_removed); + replace.push(' '); + replace + }; + err.span_suggestion_short( span, "remove these parentheses", - parens_removed, + replace, Applicability::MachineApplicable, ); err.emit(); diff --git a/src/test/ui/lint/unused_parens_json_suggestion.stderr b/src/test/ui/lint/unused_parens_json_suggestion.stderr index 396395a17f732..54230b19cb480 100644 --- a/src/test/ui/lint/unused_parens_json_suggestion.stderr +++ b/src/test/ui/lint/unused_parens_json_suggestion.stderr @@ -81,7 +81,7 @@ } ], "label": null, - "suggested_replacement": "1 / (2 + 3)", + "suggested_replacement": " 1 / (2 + 3) ", "suggestion_applicability": "MachineApplicable", "expansion": null } From e64493e2d4f5e1e60c2599b0eea165a5bde0fdc6 Mon Sep 17 00:00:00 2001 From: bravomikekilo Date: Sat, 3 Aug 2019 01:46:09 +0800 Subject: [PATCH 03/16] add new test and add conditional whitespace --- src/librustc_lint/unused.rs | 95 ++- .../lint/unused_parens_json_suggestion.stderr | 2 +- .../used_parens_remove_json_suggestion.rs | 60 ++ .../used_parens_remove_json_suggestion.stderr | 666 ++++++++++++++++++ 4 files changed, 794 insertions(+), 29 deletions(-) create mode 100644 src/test/ui/lint/used_parens_remove_json_suggestion.rs create mode 100644 src/test/ui/lint/used_parens_remove_json_suggestion.stderr diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 9ef34c201e19a..5880e59350313 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,41 @@ 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 +404,11 @@ 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; @@ -427,9 +437,17 @@ impl UnusedParens { }); let replace = { - let mut replace = String::from(" "); - replace.push_str(parens_removed); - replace.push(' '); + 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 }; @@ -446,14 +464,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 { @@ -475,12 +514,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) { @@ -500,7 +539,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/test/ui/lint/unused_parens_json_suggestion.stderr b/src/test/ui/lint/unused_parens_json_suggestion.stderr index 54230b19cb480..396395a17f732 100644 --- a/src/test/ui/lint/unused_parens_json_suggestion.stderr +++ b/src/test/ui/lint/unused_parens_json_suggestion.stderr @@ -81,7 +81,7 @@ } ], "label": null, - "suggested_replacement": " 1 / (2 + 3) ", + "suggested_replacement": "1 / (2 + 3)", "suggestion_applicability": "MachineApplicable", "expansion": null } diff --git a/src/test/ui/lint/used_parens_remove_json_suggestion.rs b/src/test/ui/lint/used_parens_remove_json_suggestion.rs new file mode 100644 index 0000000000000..3189606aaa97f --- /dev/null +++ b/src/test/ui/lint/used_parens_remove_json_suggestion.rs @@ -0,0 +1,60 @@ +// compile-flags: --error-format pretty-json -Zunstable-options +// build-pass + +// 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)] + +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 i in (0 .. 3){ + println!("e~") + } + } + + for i in (0 .. 3) { + while (true && false) { + println!("e~") + } + } + + + loop { + if (break { return true }) { + } + } + false +} \ No newline at end of file diff --git a/src/test/ui/lint/used_parens_remove_json_suggestion.stderr b/src/test/ui/lint/used_parens_remove_json_suggestion.stderr new file mode 100644 index 0000000000000..d8b23ae544318 --- /dev/null +++ b/src/test/ui/lint/used_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/used_parens_remove_json_suggestion.rs", + "byte_start": 478, + "byte_end": 482, + "line_start": 16, + "line_end": 16, + "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/used_parens_remove_json_suggestion.rs", + "byte_start": 420, + "byte_end": 433, + "line_start": 10, + "line_end": 10, + "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/used_parens_remove_json_suggestion.rs", + "byte_start": 478, + "byte_end": 482, + "line_start": 16, + "line_end": 16, + "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/used_parens_remove_json_suggestion.rs:16:8 + | +LL | if (_b) { + | ^^^^ help: remove these parentheses + | +note: lint level defined here + --> $DIR/used_parens_remove_json_suggestion.rs:10:9 + | +LL | #![warn(unused_parens)] + | ^^^^^^^^^^^^^ + +" +} +{ + "message": "unnecessary parentheses around `if` condition", + "code": { + "code": "unused_parens", + "explanation": null + }, + "level": "warning", + "spans": [ + { + "file_name": "$DIR/used_parens_remove_json_suggestion.rs", + "byte_start": 575, + "byte_end": 578, + "line_start": 27, + "line_end": 27, + "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/used_parens_remove_json_suggestion.rs", + "byte_start": 575, + "byte_end": 578, + "line_start": 27, + "line_end": 27, + "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/used_parens_remove_json_suggestion.rs:27: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/used_parens_remove_json_suggestion.rs", + "byte_start": 621, + "byte_end": 624, + "line_start": 31, + "line_end": 31, + "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/used_parens_remove_json_suggestion.rs", + "byte_start": 621, + "byte_end": 624, + "line_start": 31, + "line_end": 31, + "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/used_parens_remove_json_suggestion.rs:31: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/used_parens_remove_json_suggestion.rs", + "byte_start": 669, + "byte_end": 684, + "line_start": 35, + "line_end": 35, + "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/used_parens_remove_json_suggestion.rs", + "byte_start": 669, + "byte_end": 684, + "line_start": 35, + "line_end": 35, + "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/used_parens_remove_json_suggestion.rs:35: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/used_parens_remove_json_suggestion.rs", + "byte_start": 697, + "byte_end": 700, + "line_start": 36, + "line_end": 36, + "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/used_parens_remove_json_suggestion.rs", + "byte_start": 697, + "byte_end": 700, + "line_start": 36, + "line_end": 36, + "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/used_parens_remove_json_suggestion.rs:36: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/used_parens_remove_json_suggestion.rs", + "byte_start": 760, + "byte_end": 775, + "line_start": 42, + "line_end": 42, + "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/used_parens_remove_json_suggestion.rs", + "byte_start": 760, + "byte_end": 775, + "line_start": 42, + "line_end": 42, + "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/used_parens_remove_json_suggestion.rs:42: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/used_parens_remove_json_suggestion.rs", + "byte_start": 795, + "byte_end": 803, + "line_start": 43, + "line_end": 43, + "column_start": 18, + "column_end": 26, + "is_primary": true, + "text": [ + { + "text": " for i 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/used_parens_remove_json_suggestion.rs", + "byte_start": 795, + "byte_end": 803, + "line_start": 43, + "line_end": 43, + "column_start": 18, + "column_end": 26, + "is_primary": true, + "text": [ + { + "text": " for i 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/used_parens_remove_json_suggestion.rs:43:18 + | +LL | for i 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/used_parens_remove_json_suggestion.rs", + "byte_start": 862, + "byte_end": 870, + "line_start": 48, + "line_end": 48, + "column_start": 14, + "column_end": 22, + "is_primary": true, + "text": [ + { + "text": " for i 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/used_parens_remove_json_suggestion.rs", + "byte_start": 862, + "byte_end": 870, + "line_start": 48, + "line_end": 48, + "column_start": 14, + "column_end": 22, + "is_primary": true, + "text": [ + { + "text": " for i 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/used_parens_remove_json_suggestion.rs:48:14 + | +LL | for i 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/used_parens_remove_json_suggestion.rs", + "byte_start": 887, + "byte_end": 902, + "line_start": 49, + "line_end": 49, + "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/used_parens_remove_json_suggestion.rs", + "byte_start": 887, + "byte_end": 902, + "line_start": 49, + "line_end": 49, + "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/used_parens_remove_json_suggestion.rs:49:15 + | +LL | while (true && false) { + | ^^^^^^^^^^^^^^^ help: remove these parentheses + +" +} From 4c1d892960d92005bcd7c492f777ca45f1d55cea Mon Sep 17 00:00:00 2001 From: bravomikekilo Date: Sat, 3 Aug 2019 02:17:20 +0800 Subject: [PATCH 04/16] fix tidy problem --- src/librustc_lint/unused.rs | 13 +++++++++++-- .../ui/lint/used_parens_remove_json_suggestion.rs | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 5880e59350313..634b06d9bb239 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -387,7 +387,12 @@ impl UnusedParens { 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, None, None); + self.check_unused_parens_expr( + cx, expr, + "`let` head expression", + followed_by_block, + None, None + ); } _ => {} } @@ -408,7 +413,11 @@ impl UnusedParens { } } - fn remove_outer_parens(cx: &EarlyContext<'_>, span: Span, pattern: &str, msg: &str, keep_space: (bool, bool)) { + 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; diff --git a/src/test/ui/lint/used_parens_remove_json_suggestion.rs b/src/test/ui/lint/used_parens_remove_json_suggestion.rs index 3189606aaa97f..3af11428b95ee 100644 --- a/src/test/ui/lint/used_parens_remove_json_suggestion.rs +++ b/src/test/ui/lint/used_parens_remove_json_suggestion.rs @@ -57,4 +57,4 @@ fn f() -> bool { } } false -} \ No newline at end of file +} From 9d4ca879b88e3a21354dcda458d7e7f7ff6370b2 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Fri, 2 Aug 2019 18:06:15 -0700 Subject: [PATCH 05/16] Add niche-in-generator test --- .../run-pass/generator/niche-in-generator.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/test/run-pass/generator/niche-in-generator.rs 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))); +} From 0a1bdd4a53c239ac412bc7031b8b6056fe80674a Mon Sep 17 00:00:00 2001 From: David Laban Date: Sun, 4 Aug 2019 16:08:31 +0100 Subject: [PATCH 06/16] test .await while holding variables of different sizes --- .../async-await/async-fn-size-moved-locals.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) 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())); } From f40190a6a541479e504d783cd984670c6fa6cb39 Mon Sep 17 00:00:00 2001 From: David Laban Date: Mon, 5 Aug 2019 15:26:08 +0100 Subject: [PATCH 07/16] test drop order for parameters when a future is dropped part-way through execution --- .../drop-order/drop-order-when-cancelled.rs | 307 ++++++++++++++++++ 1 file changed, 307 insertions(+) create mode 100644 src/test/ui/async-await/drop-order/drop-order-when-cancelled.rs 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..21600cfc139b2 --- /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()), + ) + }, + ); +} From 7c374cf7d2169e55c7cc267d4726b38cb068ede3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Aug 2019 22:30:13 +0200 Subject: [PATCH 08/16] don't ignore mir_dump folder --- .gitignore | 1 - 1 file changed, 1 deletion(-) 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 From f85fc7168c0fb3d3f52eb66fe601571d7b1e4e67 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 6 Aug 2019 00:41:16 +0200 Subject: [PATCH 09/16] PlaceRef's base is already a reference --- .../borrow_check/error_reporting.rs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) 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, From ef0f49054f15964aac63e48621567dad17bec97b Mon Sep 17 00:00:00 2001 From: Ryan Gorup Date: Mon, 5 Aug 2019 16:14:41 -0700 Subject: [PATCH 10/16] Tests around moving parts of structs and tuples across await points --- .../move-part-await-return-rest-struct.rs | 20 +++++++++++++++++++ .../move-part-await-return-rest-tuple.rs | 14 +++++++++++++ .../no-move-across-await-struct.rs | 19 ++++++++++++++++++ .../no-move-across-await-struct.stderr | 13 ++++++++++++ .../async-await/no-move-across-await-tuple.rs | 15 ++++++++++++++ .../no-move-across-await-tuple.stderr | 14 +++++++++++++ 6 files changed, 95 insertions(+) create mode 100644 src/test/ui/async-await/move-part-await-return-rest-struct.rs create mode 100644 src/test/ui/async-await/move-part-await-return-rest-tuple.rs create mode 100644 src/test/ui/async-await/no-move-across-await-struct.rs create mode 100644 src/test/ui/async-await/no-move-across-await-struct.stderr create mode 100644 src/test/ui/async-await/no-move-across-await-tuple.rs create mode 100644 src/test/ui/async-await/no-move-across-await-tuple.stderr 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`. From 48c734669c5febe80f80cd1ac6e67c621836e5c3 Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Tue, 6 Aug 2019 03:03:45 +0200 Subject: [PATCH 11/16] doc: the content has since been moved to the guide --- src/README.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) 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 From 3a95c716dcd0a846ae09725f4bdfab519c5743b8 Mon Sep 17 00:00:00 2001 From: bravomikekilo Date: Tue, 6 Aug 2019 16:00:13 +0800 Subject: [PATCH 12/16] Add rustfix test and fix test name. --- .../lint/unused_parens_json_suggestion.fixed | 27 +++ .../ui/lint/unused_parens_json_suggestion.rs | 2 + .../lint/unused_parens_json_suggestion.stderr | 28 +-- ...unused_parens_remove_json_suggestion.fixed | 62 +++++ ...> unused_parens_remove_json_suggestion.rs} | 6 +- ...used_parens_remove_json_suggestion.stderr} | 222 +++++++++--------- 6 files changed, 220 insertions(+), 127 deletions(-) create mode 100644 src/test/ui/lint/unused_parens_json_suggestion.fixed create mode 100644 src/test/ui/lint/unused_parens_remove_json_suggestion.fixed rename src/test/ui/lint/{used_parens_remove_json_suggestion.rs => unused_parens_remove_json_suggestion.rs} (91%) rename src/test/ui/lint/{used_parens_remove_json_suggestion.stderr => unused_parens_remove_json_suggestion.stderr} (75%) 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/used_parens_remove_json_suggestion.rs b/src/test/ui/lint/unused_parens_remove_json_suggestion.rs similarity index 91% rename from src/test/ui/lint/used_parens_remove_json_suggestion.rs rename to src/test/ui/lint/unused_parens_remove_json_suggestion.rs index 3af11428b95ee..0e9869b67d590 100644 --- a/src/test/ui/lint/used_parens_remove_json_suggestion.rs +++ b/src/test/ui/lint/unused_parens_remove_json_suggestion.rs @@ -1,5 +1,6 @@ // 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 @@ -8,6 +9,7 @@ // test of the JSON error format. #![warn(unused_parens)] +#![allow(unreachable_code)] fn main() { @@ -40,12 +42,12 @@ fn f() -> bool { } while(true && false) { - for i in (0 .. 3){ + for _ in (0 .. 3){ println!("e~") } } - for i in (0 .. 3) { + for _ in (0 .. 3) { while (true && false) { println!("e~") } diff --git a/src/test/ui/lint/used_parens_remove_json_suggestion.stderr b/src/test/ui/lint/unused_parens_remove_json_suggestion.stderr similarity index 75% rename from src/test/ui/lint/used_parens_remove_json_suggestion.stderr rename to src/test/ui/lint/unused_parens_remove_json_suggestion.stderr index d8b23ae544318..b4eab200dd016 100644 --- a/src/test/ui/lint/used_parens_remove_json_suggestion.stderr +++ b/src/test/ui/lint/unused_parens_remove_json_suggestion.stderr @@ -7,11 +7,11 @@ "level": "warning", "spans": [ { - "file_name": "$DIR/used_parens_remove_json_suggestion.rs", - "byte_start": 478, - "byte_end": 482, - "line_start": 16, - "line_end": 16, + "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, @@ -35,11 +35,11 @@ "level": "note", "spans": [ { - "file_name": "$DIR/used_parens_remove_json_suggestion.rs", - "byte_start": 420, - "byte_end": 433, - "line_start": 10, - "line_end": 10, + "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, @@ -65,11 +65,11 @@ "level": "help", "spans": [ { - "file_name": "$DIR/used_parens_remove_json_suggestion.rs", - "byte_start": 478, - "byte_end": 482, - "line_start": 16, - "line_end": 16, + "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, @@ -91,13 +91,13 @@ } ], "rendered": "warning: unnecessary parentheses around `if` condition - --> $DIR/used_parens_remove_json_suggestion.rs:16:8 + --> $DIR/unused_parens_remove_json_suggestion.rs:18:8 | LL | if (_b) { | ^^^^ help: remove these parentheses | note: lint level defined here - --> $DIR/used_parens_remove_json_suggestion.rs:10:9 + --> $DIR/unused_parens_remove_json_suggestion.rs:11:9 | LL | #![warn(unused_parens)] | ^^^^^^^^^^^^^ @@ -113,11 +113,11 @@ LL | #![warn(unused_parens)] "level": "warning", "spans": [ { - "file_name": "$DIR/used_parens_remove_json_suggestion.rs", - "byte_start": 575, - "byte_end": 578, - "line_start": 27, - "line_end": 27, + "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, @@ -141,11 +141,11 @@ LL | #![warn(unused_parens)] "level": "help", "spans": [ { - "file_name": "$DIR/used_parens_remove_json_suggestion.rs", - "byte_start": 575, - "byte_end": 578, - "line_start": 27, - "line_end": 27, + "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, @@ -167,7 +167,7 @@ LL | #![warn(unused_parens)] } ], "rendered": "warning: unnecessary parentheses around `if` condition - --> $DIR/used_parens_remove_json_suggestion.rs:27:7 + --> $DIR/unused_parens_remove_json_suggestion.rs:29:7 | LL | if(c) { | ^^^ help: remove these parentheses @@ -183,11 +183,11 @@ LL | if(c) { "level": "warning", "spans": [ { - "file_name": "$DIR/used_parens_remove_json_suggestion.rs", - "byte_start": 621, - "byte_end": 624, - "line_start": 31, - "line_end": 31, + "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, @@ -211,11 +211,11 @@ LL | if(c) { "level": "help", "spans": [ { - "file_name": "$DIR/used_parens_remove_json_suggestion.rs", - "byte_start": 621, - "byte_end": 624, - "line_start": 31, - "line_end": 31, + "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, @@ -237,7 +237,7 @@ LL | if(c) { } ], "rendered": "warning: unnecessary parentheses around `if` condition - --> $DIR/used_parens_remove_json_suggestion.rs:31:8 + --> $DIR/unused_parens_remove_json_suggestion.rs:33:8 | LL | if (c){ | ^^^ help: remove these parentheses @@ -253,11 +253,11 @@ LL | if (c){ "level": "warning", "spans": [ { - "file_name": "$DIR/used_parens_remove_json_suggestion.rs", - "byte_start": 669, - "byte_end": 684, - "line_start": 35, - "line_end": 35, + "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, @@ -281,11 +281,11 @@ LL | if (c){ "level": "help", "spans": [ { - "file_name": "$DIR/used_parens_remove_json_suggestion.rs", - "byte_start": 669, - "byte_end": 684, - "line_start": 35, - "line_end": 35, + "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, @@ -307,7 +307,7 @@ LL | if (c){ } ], "rendered": "warning: unnecessary parentheses around `while` condition - --> $DIR/used_parens_remove_json_suggestion.rs:35:11 + --> $DIR/unused_parens_remove_json_suggestion.rs:37:11 | LL | while (false && true){ | ^^^^^^^^^^^^^^^ help: remove these parentheses @@ -323,11 +323,11 @@ LL | while (false && true){ "level": "warning", "spans": [ { - "file_name": "$DIR/used_parens_remove_json_suggestion.rs", - "byte_start": 697, - "byte_end": 700, - "line_start": 36, - "line_end": 36, + "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, @@ -351,11 +351,11 @@ LL | while (false && true){ "level": "help", "spans": [ { - "file_name": "$DIR/used_parens_remove_json_suggestion.rs", - "byte_start": 697, - "byte_end": 700, - "line_start": 36, - "line_end": 36, + "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, @@ -377,7 +377,7 @@ LL | while (false && true){ } ], "rendered": "warning: unnecessary parentheses around `if` condition - --> $DIR/used_parens_remove_json_suggestion.rs:36:12 + --> $DIR/unused_parens_remove_json_suggestion.rs:38:12 | LL | if (c) { | ^^^ help: remove these parentheses @@ -393,11 +393,11 @@ LL | if (c) { "level": "warning", "spans": [ { - "file_name": "$DIR/used_parens_remove_json_suggestion.rs", - "byte_start": 760, - "byte_end": 775, - "line_start": 42, - "line_end": 42, + "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, @@ -421,11 +421,11 @@ LL | if (c) { "level": "help", "spans": [ { - "file_name": "$DIR/used_parens_remove_json_suggestion.rs", - "byte_start": 760, - "byte_end": 775, - "line_start": 42, - "line_end": 42, + "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, @@ -447,7 +447,7 @@ LL | if (c) { } ], "rendered": "warning: unnecessary parentheses around `while` condition - --> $DIR/used_parens_remove_json_suggestion.rs:42:10 + --> $DIR/unused_parens_remove_json_suggestion.rs:44:10 | LL | while(true && false) { | ^^^^^^^^^^^^^^^ help: remove these parentheses @@ -463,17 +463,17 @@ LL | while(true && false) { "level": "warning", "spans": [ { - "file_name": "$DIR/used_parens_remove_json_suggestion.rs", - "byte_start": 795, - "byte_end": 803, - "line_start": 43, - "line_end": 43, + "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 i in (0 .. 3){", + "text": " for _ in (0 .. 3){", "highlight_start": 18, "highlight_end": 26 } @@ -491,17 +491,17 @@ LL | while(true && false) { "level": "help", "spans": [ { - "file_name": "$DIR/used_parens_remove_json_suggestion.rs", - "byte_start": 795, - "byte_end": 803, - "line_start": 43, - "line_end": 43, + "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 i in (0 .. 3){", + "text": " for _ in (0 .. 3){", "highlight_start": 18, "highlight_end": 26 } @@ -517,9 +517,9 @@ LL | while(true && false) { } ], "rendered": "warning: unnecessary parentheses around `for` head expression - --> $DIR/used_parens_remove_json_suggestion.rs:43:18 + --> $DIR/unused_parens_remove_json_suggestion.rs:45:18 | -LL | for i in (0 .. 3){ +LL | for _ in (0 .. 3){ | ^^^^^^^^ help: remove these parentheses " @@ -533,17 +533,17 @@ LL | for i in (0 .. 3){ "level": "warning", "spans": [ { - "file_name": "$DIR/used_parens_remove_json_suggestion.rs", - "byte_start": 862, - "byte_end": 870, - "line_start": 48, - "line_end": 48, + "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 i in (0 .. 3) {", + "text": " for _ in (0 .. 3) {", "highlight_start": 14, "highlight_end": 22 } @@ -561,17 +561,17 @@ LL | for i in (0 .. 3){ "level": "help", "spans": [ { - "file_name": "$DIR/used_parens_remove_json_suggestion.rs", - "byte_start": 862, - "byte_end": 870, - "line_start": 48, - "line_end": 48, + "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 i in (0 .. 3) {", + "text": " for _ in (0 .. 3) {", "highlight_start": 14, "highlight_end": 22 } @@ -587,9 +587,9 @@ LL | for i in (0 .. 3){ } ], "rendered": "warning: unnecessary parentheses around `for` head expression - --> $DIR/used_parens_remove_json_suggestion.rs:48:14 + --> $DIR/unused_parens_remove_json_suggestion.rs:50:14 | -LL | for i in (0 .. 3) { +LL | for _ in (0 .. 3) { | ^^^^^^^^ help: remove these parentheses " @@ -603,11 +603,11 @@ LL | for i in (0 .. 3) { "level": "warning", "spans": [ { - "file_name": "$DIR/used_parens_remove_json_suggestion.rs", - "byte_start": 887, - "byte_end": 902, - "line_start": 49, - "line_end": 49, + "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, @@ -631,11 +631,11 @@ LL | for i in (0 .. 3) { "level": "help", "spans": [ { - "file_name": "$DIR/used_parens_remove_json_suggestion.rs", - "byte_start": 887, - "byte_end": 902, - "line_start": 49, - "line_end": 49, + "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, @@ -657,7 +657,7 @@ LL | for i in (0 .. 3) { } ], "rendered": "warning: unnecessary parentheses around `while` condition - --> $DIR/used_parens_remove_json_suggestion.rs:49:15 + --> $DIR/unused_parens_remove_json_suggestion.rs:51:15 | LL | while (true && false) { | ^^^^^^^^^^^^^^^ help: remove these parentheses From 3882ed4abcd86c0f6d4ad19beece83998e5685a8 Mon Sep 17 00:00:00 2001 From: David Laban Date: Tue, 6 Aug 2019 10:26:37 +0100 Subject: [PATCH 13/16] fixup! test drop order for parameters when a future is dropped part-way through execution --- src/test/ui/async-await/drop-order/drop-order-when-cancelled.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 21600cfc139b2..410a623681db5 100644 --- 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 @@ -199,7 +199,7 @@ fn assert_drop_order_after_cancel>( // 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())); From c4940e0f90d7d0e1784ade2b9e1ccc7ae7acfd4a Mon Sep 17 00:00:00 2001 From: David Laban Date: Tue, 6 Aug 2019 15:20:47 +0100 Subject: [PATCH 14/16] test drop order for locals when a future is dropped part-way through execution --- .../drop-order-for-locals-when-cancelled.rs | 176 ++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 src/test/ui/async-await/drop-order/drop-order-for-locals-when-cancelled.rs 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, + ); +} From c22cc1d67afe1c2f0c60a3cc4e6d8ba70c34bf99 Mon Sep 17 00:00:00 2001 From: Jethro Beekman Date: Tue, 6 Aug 2019 10:49:45 -0700 Subject: [PATCH 15/16] Remove unnecessary features from compiler error code list --- src/librustc_mir/error_codes.rs | 6 ------ 1 file changed, 6 deletions(-) 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()); From b40788e89fac38781ddb838bb4fb0d706a6a3546 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Fri, 26 Jul 2019 17:13:14 -0700 Subject: [PATCH 16/16] Fix generator size regressions due to optimization I tested the generator optimizations in #60187 and #61922 on the Fuchsia build, and noticed that some small generators (about 8% of the async fns in our build) increased in size slightly. This is because in #60187 we split the fields into two groups, a "prefix" non-overlap region and an overlap region, and lay them out separately. This can introduce unnecessary padding bytes between the two groups. In every single case in the Fuchsia build, it was due to there being only a single variant being used in the overlap region. This means that we aren't doing any overlapping, period. So it's better to combine the two regions into one and lay out all the fields at once, which is what this change does. --- src/librustc/ty/layout.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 03b95bc3a943d..1908cc6c1e828 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;