diff --git a/.azure-pipelines/steps/run.yml b/.azure-pipelines/steps/run.yml index e7c6235a50444..cfa28a6a1d70f 100644 --- a/.azure-pipelines/steps/run.yml +++ b/.azure-pipelines/steps/run.yml @@ -118,6 +118,7 @@ steps: # bucket. - bash: | set -e + source src/ci/shared.sh if [ "$AGENT_OS" = "Linux" ]; then rm -rf obj/build/dist/doc upload_dir=obj/build/dist @@ -130,7 +131,7 @@ steps: if [ "$DEPLOY_ALT" == "1" ]; then deploy_dir=rustc-builds-alt fi - aws s3 cp --no-progress --recursive --acl public-read ./$upload_dir s3://$DEPLOY_BUCKET/$deploy_dir/$BUILD_SOURCEVERSION + retry aws s3 cp --no-progress --recursive --acl public-read ./$upload_dir s3://$DEPLOY_BUCKET/$deploy_dir/$BUILD_SOURCEVERSION env: AWS_SECRET_ACCESS_KEY: $(AWS_SECRET_ACCESS_KEY) condition: and(succeeded(), or(eq(variables.DEPLOY, '1'), eq(variables.DEPLOY_ALT, '1'))) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index d618654b129af..edeb07fda1d59 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -11,7 +11,6 @@ use std::process; use std::cmp; use build_helper::t; -use num_cpus; use toml; use serde::Deserialize; use crate::cache::{INTERNER, Interned}; @@ -401,7 +400,7 @@ impl Config { config.rustc_error_format = flags.rustc_error_format; config.on_fail = flags.on_fail; config.stage = flags.stage; - config.jobs = flags.jobs; + config.jobs = flags.jobs.map(threads_from_config); config.cmd = flags.cmd; config.incremental = flags.incremental; config.dry_run = flags.dry_run; @@ -583,13 +582,8 @@ impl Config { set(&mut config.rust_codegen_backends_dir, rust.codegen_backends_dir.clone()); - match rust.codegen_units { - Some(0) => config.rust_codegen_units = Some(num_cpus::get() as u32), - Some(n) => config.rust_codegen_units = Some(n), - None => {} - } - - config.rust_codegen_units_std = rust.codegen_units_std; + config.rust_codegen_units = rust.codegen_units.map(threads_from_config); + config.rust_codegen_units_std = rust.codegen_units_std.map(threads_from_config); } if let Some(ref t) = toml.target { @@ -688,3 +682,10 @@ fn set(field: &mut T, val: Option) { *field = v; } } + +fn threads_from_config(v: u32) -> u32 { + match v { + 0 => num_cpus::get() as u32, + n => n, + } +} diff --git a/src/ci/shared.sh b/src/ci/shared.sh index 1e667fca5875a..323d53f2bec85 100644 --- a/src/ci/shared.sh +++ b/src/ci/shared.sh @@ -35,6 +35,8 @@ function isOSX { function getCIBranch { if [ "$TRAVIS" = "true" ]; then echo "$TRAVIS_BRANCH" + elif [ "$APPVEYOR" = "True" ]; then + echo "$APPVEYOR_REPO_BRANCH" else echo "$BUILD_SOURCEBRANCHNAME" fi; diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index f66ff894ae865..0c7d2b837a39a 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -431,6 +431,13 @@ impl str { /// /// assert_eq!(new_year, new_year.to_uppercase()); /// ``` + /// + /// One character can become multiple: + /// ``` + /// let s = "tschüß"; + /// + /// assert_eq!("TSCHÜSS", s.to_uppercase()); + /// ``` #[stable(feature = "unicode_case_mapping", since = "1.2.0")] pub fn to_uppercase(&self) -> String { let mut s = String::with_capacity(self.len()); diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 5cb91395b7bf7..92fe0834dd029 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -2018,16 +2018,14 @@ impl Vec { /// with the given `replace_with` iterator and yields the removed items. /// `replace_with` does not need to be the same length as `range`. /// - /// Note 1: The element range is removed even if the iterator is not - /// consumed until the end. + /// The element range is removed even if the iterator is not consumed until the end. /// - /// Note 2: It is unspecified how many elements are removed from the vector, + /// It is unspecified how many elements are removed from the vector /// if the `Splice` value is leaked. /// - /// Note 3: The input iterator `replace_with` is only consumed - /// when the `Splice` value is dropped. + /// The input iterator `replace_with` is only consumed when the `Splice` value is dropped. /// - /// Note 4: This is optimal if: + /// This is optimal if: /// /// * The tail (elements in the vector after `range`) is empty, /// * or `replace_with` yields fewer elements than `range`’s length diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 8000666044a1a..9cf365addca9b 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -262,9 +262,6 @@ pub trait Visitor<'v> : Sized { fn visit_pat(&mut self, p: &'v Pat) { walk_pat(self, p) } - fn visit_argument_source(&mut self, s: &'v ArgSource) { - walk_argument_source(self, s) - } fn visit_anon_const(&mut self, c: &'v AnonConst) { walk_anon_const(self, c) } @@ -402,17 +399,10 @@ pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &'v Body) { for argument in &body.arguments { visitor.visit_id(argument.hir_id); visitor.visit_pat(&argument.pat); - visitor.visit_argument_source(&argument.source); } visitor.visit_expr(&body.value); } -pub fn walk_argument_source<'v, V: Visitor<'v>>(visitor: &mut V, source: &'v ArgSource) { - if let ArgSource::AsyncFn(pat) = source { - visitor.visit_pat(pat); - } -} - pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) { // Intentionally visiting the expr first - the initialization expr // dominates the local's definition. diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 08fbd0d20d74d..14a6e93341e32 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -50,6 +50,7 @@ use errors::Applicability; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::thin_vec::ThinVec; +use rustc_data_structures::sync::Lrc; use std::collections::{BTreeSet, BTreeMap}; use std::mem; @@ -58,17 +59,17 @@ use syntax::attr; use syntax::ast; use syntax::ast::*; use syntax::errors; -use syntax::ext::hygiene::Mark; +use syntax::ext::hygiene::{Mark, SyntaxContext}; use syntax::print::pprust; use syntax::ptr::P; -use syntax::source_map::{respan, CompilerDesugaringKind, Spanned}; +use syntax::source_map::{self, respan, CompilerDesugaringKind, Spanned}; use syntax::source_map::CompilerDesugaringKind::IfTemporary; use syntax::std_inject; use syntax::symbol::{kw, sym, Symbol}; use syntax::tokenstream::{TokenStream, TokenTree}; use syntax::parse::token::Token; use syntax::visit::{self, Visitor}; -use syntax_pos::Span; +use syntax_pos::{edition, Span}; const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF; @@ -465,32 +466,6 @@ impl<'a> LoweringContext<'a> { visit::walk_pat(self, p) } - fn visit_fn(&mut self, fk: visit::FnKind<'lcx>, fd: &'lcx FnDecl, s: Span, _: NodeId) { - if fk.header().map(|h| h.asyncness.node.is_async()).unwrap_or(false) { - // Don't visit the original pattern for async functions as it will be - // replaced. - for arg in &fd.inputs { - if let ArgSource::AsyncFn(pat) = &arg.source { self.visit_pat(pat); } - self.visit_ty(&arg.ty) - } - self.visit_fn_ret_ty(&fd.output); - - match fk { - visit::FnKind::ItemFn(_, decl, _, body) => { - self.visit_fn_header(decl); - self.visit_block(body) - }, - visit::FnKind::Method(_, sig, _, body) => { - self.visit_fn_header(&sig.header); - self.visit_block(body) - }, - visit::FnKind::Closure(body) => self.visit_expr(body), - } - } else { - visit::walk_fn(self, fk, fd, s) - } - } - fn visit_item(&mut self, item: &'lcx Item) { let hir_id = self.lctx.allocate_hir_id_counter(item.id); @@ -806,7 +781,7 @@ impl<'a> LoweringContext<'a> { }) } - fn record_body(&mut self, value: hir::Expr, arguments: HirVec) -> hir::BodyId { + fn record_body(&mut self, arguments: HirVec, value: hir::Expr) -> hir::BodyId { if self.is_generator && self.is_async_body { span_err!( self.sess, @@ -855,6 +830,27 @@ impl<'a> LoweringContext<'a> { self.sess.diagnostic() } + /// Reuses the span but adds information like the kind of the desugaring and features that are + /// allowed inside this span. + fn mark_span_with_reason( + &self, + reason: CompilerDesugaringKind, + span: Span, + allow_internal_unstable: Option>, + ) -> Span { + let mark = Mark::fresh(Mark::root()); + mark.set_expn_info(source_map::ExpnInfo { + call_site: span, + def_site: Some(span), + format: source_map::CompilerDesugaring(reason), + allow_internal_unstable, + allow_internal_unsafe: false, + local_inner_macros: false, + edition: edition::Edition::from_session(), + }); + span.with_ctxt(SyntaxContext::empty().apply_mark(mark)) + } + fn with_anonymous_lifetime_mode( &mut self, anonymous_lifetime_mode: AnonymousLifetimeMode, @@ -1125,27 +1121,21 @@ impl<'a> LoweringContext<'a> { span: Span, body: impl FnOnce(&mut LoweringContext<'_>) -> hir::Expr, ) -> hir::ExprKind { - let prev_is_generator = mem::replace(&mut self.is_generator, false); - let prev_is_async_body = mem::replace(&mut self.is_async_body, true); + let capture_clause = self.lower_capture_clause(capture_clause); let output = match ret_ty { Some(ty) => FunctionRetTy::Ty(P(ty.clone())), None => FunctionRetTy::Default(span), }; - let decl = FnDecl { + let ast_decl = FnDecl { inputs: vec![], output, c_variadic: false }; - // Lower the arguments before the body otherwise the body will call `lower_res` expecting - // the argument to have been assigned an id already. - let arguments = self.lower_args(Some(&decl)); - let body_expr = body(self); - let body_id = self.record_body(body_expr, arguments); - self.is_generator = prev_is_generator; - self.is_async_body = prev_is_async_body; - - let capture_clause = self.lower_capture_clause(capture_clause); - let decl = self.lower_fn_decl(&decl, None, /* impl trait allowed */ false, None); + let decl = self.lower_fn_decl(&ast_decl, None, /* impl trait allowed */ false, None); + let body_id = self.lower_fn_body(&ast_decl, |this| { + this.is_async_body = true; + body(this) + }); let generator = hir::Expr { hir_id: self.lower_node_id(closure_node_id), node: hir::ExprKind::Closure(capture_clause, decl, body_id, span, @@ -1154,7 +1144,7 @@ impl<'a> LoweringContext<'a> { attrs: ThinVec::new(), }; - let unstable_span = self.sess.source_map().mark_span_with_reason( + let unstable_span = self.mark_span_with_reason( CompilerDesugaringKind::Async, span, Some(vec![sym::gen_future].into()), @@ -1164,18 +1154,32 @@ impl<'a> LoweringContext<'a> { hir::ExprKind::Call(P(gen_future), hir_vec![generator]) } - fn lower_body(&mut self, decl: Option<&FnDecl>, f: F) -> hir::BodyId - where - F: FnOnce(&mut LoweringContext<'_>) -> hir::Expr, - { - let prev_generator = mem::replace(&mut self.is_generator, false); - let prev_async = mem::replace(&mut self.is_async_body, false); - let arguments = self.lower_args(decl); - let result = f(self); - let r = self.record_body(result, arguments); - self.is_generator = prev_generator; - self.is_async_body = prev_async; - return r; + fn lower_body( + &mut self, + f: impl FnOnce(&mut LoweringContext<'_>) -> (HirVec, hir::Expr), + ) -> hir::BodyId { + let prev_is_generator = mem::replace(&mut self.is_generator, false); + let prev_is_async_body = mem::replace(&mut self.is_async_body, false); + let (arguments, result) = f(self); + let body_id = self.record_body(arguments, result); + self.is_generator = prev_is_generator; + self.is_async_body = prev_is_async_body; + body_id + } + + fn lower_fn_body( + &mut self, + decl: &FnDecl, + body: impl FnOnce(&mut LoweringContext<'_>) -> hir::Expr, + ) -> hir::BodyId { + self.lower_body(|this| ( + decl.inputs.iter().map(|x| this.lower_arg(x)).collect(), + body(this), + )) + } + + fn lower_const_body(&mut self, expr: &Expr) -> hir::BodyId { + self.lower_body(|this| (hir_vec![], this.lower_expr(expr))) } fn with_loop_scope(&mut self, loop_id: NodeId, f: F) -> T @@ -1561,7 +1565,7 @@ impl<'a> LoweringContext<'a> { // desugaring that explicitly states that we don't want to track that. // Not tracking it makes lints in rustc and clippy very fragile as // frequently opened issues show. - let exist_ty_span = self.sess.source_map().mark_span_with_reason( + let exist_ty_span = self.mark_span_with_reason( CompilerDesugaringKind::ExistentialReturnType, span, None, @@ -2266,17 +2270,10 @@ impl<'a> LoweringContext<'a> { init: l.init.as_ref().map(|e| P(self.lower_expr(e))), span: l.span, attrs: l.attrs.clone(), - source: self.lower_local_source(l.source), + source: hir::LocalSource::Normal, }, ids) } - fn lower_local_source(&mut self, ls: LocalSource) -> hir::LocalSource { - match ls { - LocalSource::Normal => hir::LocalSource::Normal, - LocalSource::AsyncFn => hir::LocalSource::AsyncFn, - } - } - fn lower_mutability(&mut self, m: Mutability) -> hir::Mutability { match m { Mutability::Mutable => hir::MutMutable, @@ -2284,22 +2281,10 @@ impl<'a> LoweringContext<'a> { } } - fn lower_args(&mut self, decl: Option<&FnDecl>) -> HirVec { - decl.map_or(hir_vec![], |decl| decl.inputs.iter().map(|x| self.lower_arg(x)).collect()) - } - fn lower_arg(&mut self, arg: &Arg) -> hir::Arg { hir::Arg { hir_id: self.lower_node_id(arg.id), pat: self.lower_pat(&arg.pat), - source: self.lower_arg_source(&arg.source), - } - } - - fn lower_arg_source(&mut self, source: &ArgSource) -> hir::ArgSource { - match source { - ArgSource::Normal => hir::ArgSource::Normal, - ArgSource::AsyncFn(pat) => hir::ArgSource::AsyncFn(self.lower_pat(pat)), } } @@ -2435,7 +2420,7 @@ impl<'a> LoweringContext<'a> { ) -> hir::FunctionRetTy { let span = output.span(); - let exist_ty_span = self.sess.source_map().mark_span_with_reason( + let exist_ty_span = self.mark_span_with_reason( CompilerDesugaringKind::Async, span, None, @@ -2998,11 +2983,14 @@ impl<'a> LoweringContext<'a> { bounds.iter().map(|bound| self.lower_param_bound(bound, itctx.reborrow())).collect() } - fn lower_block(&mut self, b: &Block, targeted_by_break: bool) -> P { + fn lower_block_with_stmts( + &mut self, + b: &Block, + targeted_by_break: bool, + mut stmts: Vec, + ) -> P { let mut expr = None; - let mut stmts = vec![]; - for (index, stmt) in b.stmts.iter().enumerate() { if index == b.stmts.len() - 1 { if let StmtKind::Expr(ref e) = stmt.node { @@ -3025,56 +3013,136 @@ impl<'a> LoweringContext<'a> { }) } - fn lower_async_body( + fn lower_block(&mut self, b: &Block, targeted_by_break: bool) -> P { + self.lower_block_with_stmts(b, targeted_by_break, vec![]) + } + + fn lower_maybe_async_body( &mut self, decl: &FnDecl, - asyncness: &IsAsync, + asyncness: IsAsync, body: &Block, ) -> hir::BodyId { - self.lower_body(Some(&decl), |this| { - if let IsAsync::Async { closure_id, ref arguments, .. } = asyncness { - let mut body = body.clone(); + let closure_id = match asyncness { + IsAsync::Async { closure_id, .. } => closure_id, + IsAsync::NotAsync => return self.lower_fn_body(&decl, |this| { + let body = this.lower_block(body, false); + this.expr_block(body, ThinVec::new()) + }), + }; - // Async function arguments are lowered into the closure body so that they are - // captured and so that the drop order matches the equivalent non-async functions. - // - // async fn foo(: , : , : ) { - // async move { - // } - // } - // - // // ...becomes... - // fn foo(__arg0: , __arg1: , __arg2: ) { - // async move { - // let __arg2 = __arg2; - // let = __arg2; - // let __arg1 = __arg1; - // let = __arg1; - // let __arg0 = __arg0; - // let = __arg0; - // } - // } + self.lower_body(|this| { + let mut arguments: Vec = Vec::new(); + let mut statements: Vec = Vec::new(); + + // Async function arguments are lowered into the closure body so that they are + // captured and so that the drop order matches the equivalent non-async functions. + // + // from: + // + // async fn foo(: , : , : ) { + // async move { + // } + // } + // + // into: + // + // fn foo(__arg0: , __arg1: , __arg2: ) { + // async move { + // let __arg2 = __arg2; + // let = __arg2; + // let __arg1 = __arg1; + // let = __arg1; + // let __arg0 = __arg0; + // let = __arg0; + // } + // } + // + // If `` is a simple ident, then it is lowered to a single + // `let = ;` statement as an optimization. + for (index, argument) in decl.inputs.iter().enumerate() { + let argument = this.lower_arg(argument); + let span = argument.pat.span; + + // Check if this is a binding pattern, if so, we can optimize and avoid adding a + // `let = __argN;` statement. In this case, we do not rename the argument. + let (ident, is_simple_argument) = match argument.pat.node { + hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, ident, _) => + (ident, true), + _ => { + // Replace the ident for bindings that aren't simple. + let name = format!("__arg{}", index); + let ident = Ident::from_str(&name); + + (ident, false) + }, + }; + + let desugared_span = + this.mark_span_with_reason(CompilerDesugaringKind::Async, span, None); + + // Construct an argument representing `__argN: ` to replace the argument of the + // async function. // - // If `` is a simple ident, then it is lowered to a single - // `let = ;` statement as an optimization. - for a in arguments.iter().rev() { - if let Some(pat_stmt) = a.pat_stmt.clone() { - body.stmts.insert(0, pat_stmt); - } - body.stmts.insert(0, a.move_stmt.clone()); - } + // If this is the simple case, this argument will end up being the same as the + // original argument, but with a different pattern id. + let (new_argument_pat, new_argument_id) = this.pat_ident(desugared_span, ident); + let new_argument = hir::Arg { + hir_id: argument.hir_id, + pat: new_argument_pat, + }; - let async_expr = this.make_async_expr( - CaptureBy::Value, *closure_id, None, body.span, - |this| { - let body = this.lower_block(&body, false); - this.expr_block(body, ThinVec::new()) - }); - this.expr(body.span, async_expr, ThinVec::new()) - } else { - let body = this.lower_block(body, false); - this.expr_block(body, ThinVec::new()) + if is_simple_argument { + // If this is the simple case, then we only insert one statement that is + // `let = ;`. We re-use the original argument's pattern so that + // `HirId`s are densely assigned. + let expr = this.expr_ident(desugared_span, ident, new_argument_id); + let stmt = this.stmt_let_pat( + desugared_span, Some(P(expr)), argument.pat, hir::LocalSource::AsyncFn); + statements.push(stmt); + } else { + // If this is not the simple case, then we construct two statements: + // + // ``` + // let __argN = __argN; + // let = __argN; + // ``` + // + // The first statement moves the argument into the closure and thus ensures + // that the drop order is correct. + // + // The second statement creates the bindings that the user wrote. + + // Construct the `let mut __argN = __argN;` statement. It must be a mut binding + // because the user may have specified a `ref mut` binding in the next + // statement. + let (move_pat, move_id) = this.pat_ident_binding_mode( + desugared_span, ident, hir::BindingAnnotation::Mutable); + let move_expr = this.expr_ident(desugared_span, ident, new_argument_id); + let move_stmt = this.stmt_let_pat( + desugared_span, Some(P(move_expr)), move_pat, hir::LocalSource::AsyncFn); + + // Construct the `let = __argN;` statement. We re-use the original + // argument's pattern so that `HirId`s are densely assigned. + let pattern_expr = this.expr_ident(desugared_span, ident, move_id); + let pattern_stmt = this.stmt_let_pat( + desugared_span, Some(P(pattern_expr)), argument.pat, + hir::LocalSource::AsyncFn); + + statements.push(move_stmt); + statements.push(pattern_stmt); + }; + + arguments.push(new_argument); } + + let async_expr = this.make_async_expr( + CaptureBy::Value, closure_id, None, body.span, + |this| { + let body = this.lower_block_with_stmts(body, false, statements); + this.expr_block(body, ThinVec::new()) + }); + (HirVec::from(arguments), this.expr(body.span, async_expr, ThinVec::new())) }) } @@ -3098,7 +3166,6 @@ impl<'a> LoweringContext<'a> { self.lower_use_tree(use_tree, &prefix, id, vis, ident, attrs) } ItemKind::Static(ref t, m, ref e) => { - let value = self.lower_body(None, |this| this.lower_expr(e)); hir::ItemKind::Static( self.lower_ty( t, @@ -3109,11 +3176,10 @@ impl<'a> LoweringContext<'a> { } ), self.lower_mutability(m), - value, + self.lower_const_body(e), ) } ItemKind::Const(ref t, ref e) => { - let value = self.lower_body(None, |this| this.lower_expr(e)); hir::ItemKind::Const( self.lower_ty( t, @@ -3123,50 +3189,31 @@ impl<'a> LoweringContext<'a> { ImplTraitContext::Disallowed(ImplTraitPosition::Binding) } ), - value + self.lower_const_body(e) ) } - ItemKind::Fn(ref decl, ref header, ref generics, ref body) => { + ItemKind::Fn(ref decl, header, ref generics, ref body) => { let fn_def_id = self.resolver.definitions().local_def_id(id); self.with_new_scopes(|this| { this.current_item = Some(ident.span); - let mut lower_fn = |decl: &FnDecl| { - // Note: we don't need to change the return type from `T` to - // `impl Future` here because lower_body - // only cares about the input argument patterns in the function - // declaration (decl), not the return types. - let body_id = this.lower_async_body(&decl, &header.asyncness.node, body); - - let (generics, fn_decl) = this.add_in_band_defs( - generics, - fn_def_id, - AnonymousLifetimeMode::PassThrough, - |this, idty| this.lower_fn_decl( - &decl, - Some((fn_def_id, idty)), - true, - header.asyncness.node.opt_return_id() - ), - ); - (body_id, generics, fn_decl) - }; + // Note: we don't need to change the return type from `T` to + // `impl Future` here because lower_body + // only cares about the input argument patterns in the function + // declaration (decl), not the return types. + let body_id = this.lower_maybe_async_body(&decl, header.asyncness.node, body); - let (body_id, generics, fn_decl) = if let IsAsync::Async { - arguments, .. - } = &header.asyncness.node { - let mut decl = decl.clone(); - // Replace the arguments of this async function with the generated - // arguments that will be moved into the closure. - for (i, a) in arguments.clone().drain(..).enumerate() { - if let Some(arg) = a.arg { - decl.inputs[i] = arg; - } - } - lower_fn(&decl) - } else { - lower_fn(decl) - }; + let (generics, fn_decl) = this.add_in_band_defs( + generics, + fn_def_id, + AnonymousLifetimeMode::PassThrough, + |this, idty| this.lower_fn_decl( + &decl, + Some((fn_def_id, idty)), + true, + header.asyncness.node.opt_return_id() + ), + ); hir::ItemKind::Fn( fn_decl, @@ -3548,7 +3595,7 @@ impl<'a> LoweringContext<'a> { self.lower_ty(ty, ImplTraitContext::disallowed()), default .as_ref() - .map(|x| self.lower_body(None, |this| this.lower_expr(x))), + .map(|x| self.lower_const_body(x)), ), ), TraitItemKind::Method(ref sig, None) => { @@ -3563,7 +3610,7 @@ impl<'a> LoweringContext<'a> { (generics, hir::TraitItemKind::Method(sig, hir::TraitMethod::Required(names))) } TraitItemKind::Method(ref sig, Some(ref body)) => { - let body_id = self.lower_body(Some(&sig.decl), |this| { + let body_id = self.lower_fn_body(&sig.decl, |this| { let body = this.lower_block(body, false); this.expr_block(body, ThinVec::new()) }); @@ -3627,48 +3674,26 @@ impl<'a> LoweringContext<'a> { let impl_item_def_id = self.resolver.definitions().local_def_id(i.id); let (generics, node) = match i.node { - ImplItemKind::Const(ref ty, ref expr) => { - let body_id = self.lower_body(None, |this| this.lower_expr(expr)); - ( - self.lower_generics(&i.generics, ImplTraitContext::disallowed()), - hir::ImplItemKind::Const( - self.lower_ty(ty, ImplTraitContext::disallowed()), - body_id, - ), - ) - } + ImplItemKind::Const(ref ty, ref expr) => ( + self.lower_generics(&i.generics, ImplTraitContext::disallowed()), + hir::ImplItemKind::Const( + self.lower_ty(ty, ImplTraitContext::disallowed()), + self.lower_const_body(expr), + ), + ), ImplItemKind::Method(ref sig, ref body) => { - let mut lower_method = |sig: &MethodSig| { - let body_id = self.lower_async_body( - &sig.decl, &sig.header.asyncness.node, body - ); - let impl_trait_return_allow = !self.is_in_trait_impl; - let (generics, sig) = self.lower_method_sig( - &i.generics, - sig, - impl_item_def_id, - impl_trait_return_allow, - sig.header.asyncness.node.opt_return_id(), - ); - (body_id, generics, sig) - }; - - let (body_id, generics, sig) = if let IsAsync::Async { - ref arguments, .. - } = sig.header.asyncness.node { - let mut sig = sig.clone(); - // Replace the arguments of this async function with the generated - // arguments that will be moved into the closure. - for (i, a) in arguments.clone().drain(..).enumerate() { - if let Some(arg) = a.arg { - sig.decl.inputs[i] = arg; - } - } - lower_method(&sig) - } else { - lower_method(sig) - }; self.current_item = Some(i.span); + let body_id = self.lower_maybe_async_body( + &sig.decl, sig.header.asyncness.node, body + ); + let impl_trait_return_allow = !self.is_in_trait_impl; + let (generics, sig) = self.lower_method_sig( + &i.generics, + sig, + impl_item_def_id, + impl_trait_return_allow, + sig.header.asyncness.node.opt_return_id(), + ); (generics, hir::ImplItemKind::Method(sig, body_id)) } @@ -3860,7 +3885,7 @@ impl<'a> LoweringContext<'a> { impl_trait_return_allow: bool, is_async: Option, ) -> (hir::Generics, hir::MethodSig) { - let header = self.lower_fn_header(&sig.header); + let header = self.lower_fn_header(sig.header); let (generics, decl) = self.add_in_band_defs( generics, fn_def_id, @@ -3882,10 +3907,10 @@ impl<'a> LoweringContext<'a> { } } - fn lower_fn_header(&mut self, h: &FnHeader) -> hir::FnHeader { + fn lower_fn_header(&mut self, h: FnHeader) -> hir::FnHeader { hir::FnHeader { unsafety: self.lower_unsafety(h.unsafety), - asyncness: self.lower_asyncness(&h.asyncness.node), + asyncness: self.lower_asyncness(h.asyncness.node), constness: self.lower_constness(h.constness), abi: h.abi, } @@ -3905,7 +3930,7 @@ impl<'a> LoweringContext<'a> { } } - fn lower_asyncness(&mut self, a: &IsAsync) -> hir::IsAsync { + fn lower_asyncness(&mut self, a: IsAsync) -> hir::IsAsync { match a { IsAsync::Async { .. } => hir::IsAsync::Async, IsAsync::NotAsync => hir::IsAsync::NotAsync, @@ -4064,7 +4089,7 @@ impl<'a> LoweringContext<'a> { self.with_new_scopes(|this| { hir::AnonConst { hir_id: this.lower_node_id(c.id), - body: this.lower_body(None, |this| this.lower_expr(&c.value)), + body: this.lower_const_body(&c.value), } }) } @@ -4151,10 +4176,7 @@ impl<'a> LoweringContext<'a> { let else_arm = self.arm(hir_vec![else_pat], P(else_expr)); // Lower condition: - let span_block = self - .sess - .source_map() - .mark_span_with_reason(IfTemporary, cond.span, None); + let span_block = self.mark_span_with_reason(IfTemporary, cond.span, None); let cond = self.lower_expr(cond); // Wrap in a construct equivalent to `{ let _t = $cond; _t }` to preserve drop // semantics since `if cond { ... }` don't let temporaries live outside of `cond`. @@ -4184,7 +4206,7 @@ impl<'a> LoweringContext<'a> { }), ExprKind::TryBlock(ref body) => { self.with_catch_scope(body.id, |this| { - let unstable_span = this.sess.source_map().mark_span_with_reason( + let unstable_span = this.mark_span_with_reason( CompilerDesugaringKind::TryBlock, body.span, Some(vec![sym::try_trait].into()), @@ -4222,7 +4244,7 @@ impl<'a> LoweringContext<'a> { } ExprKind::Await(_origin, ref expr) => self.lower_await(e.span, expr), ExprKind::Closure( - capture_clause, ref asyncness, movability, ref decl, ref body, fn_decl_span + capture_clause, asyncness, movability, ref decl, ref body, fn_decl_span ) => { if let IsAsync::Async { closure_id, .. } = asyncness { let outer_decl = FnDecl { @@ -4255,12 +4277,12 @@ impl<'a> LoweringContext<'a> { // Transform `async |x: u8| -> X { ... }` into // `|x: u8| future_from_generator(|| -> X { ... })`. - let body_id = this.lower_body(Some(&outer_decl), |this| { + let body_id = this.lower_fn_body(&outer_decl, |this| { let async_ret_ty = if let FunctionRetTy::Ty(ty) = &decl.output { Some(&**ty) } else { None }; let async_body = this.make_async_expr( - capture_clause, *closure_id, async_ret_ty, body.span, + capture_clause, closure_id, async_ret_ty, body.span, |this| { this.with_new_scopes(|this| this.lower_expr(body)) }); @@ -4281,7 +4303,7 @@ impl<'a> LoweringContext<'a> { self.with_new_scopes(|this| { this.current_item = Some(fn_decl_span); let mut is_generator = false; - let body_id = this.lower_body(Some(decl), |this| { + let body_id = this.lower_fn_body(decl, |this| { let e = this.lower_expr(body); is_generator = this.is_generator; e @@ -4616,7 +4638,7 @@ impl<'a> LoweringContext<'a> { // expand let mut head = self.lower_expr(head); let head_sp = head.span; - let desugared_span = self.sess.source_map().mark_span_with_reason( + let desugared_span = self.mark_span_with_reason( CompilerDesugaringKind::ForLoop, head_sp, None, @@ -4770,13 +4792,13 @@ impl<'a> LoweringContext<'a> { // return Try::from_error(From::from(err)), // } - let unstable_span = self.sess.source_map().mark_span_with_reason( + let unstable_span = self.mark_span_with_reason( CompilerDesugaringKind::QuestionMark, e.span, Some(vec![sym::try_trait].into()), ); let try_span = self.sess.source_map().end_point(e.span); - let try_span = self.sess.source_map().mark_span_with_reason( + let try_span = self.mark_span_with_reason( CompilerDesugaringKind::QuestionMark, try_span, Some(vec![sym::try_trait].into()), @@ -5573,12 +5595,12 @@ impl<'a> LoweringContext<'a> { err.emit(); return hir::ExprKind::Err; } - let span = self.sess.source_map().mark_span_with_reason( + let span = self.mark_span_with_reason( CompilerDesugaringKind::Await, await_span, None, ); - let gen_future_span = self.sess.source_map().mark_span_with_reason( + let gen_future_span = self.mark_span_with_reason( CompilerDesugaringKind::Await, await_span, Some(vec![sym::gen_future].into()), diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index bde27c71f9a6d..a4484c8173898 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -64,17 +64,16 @@ impl<'a> DefCollector<'a> { id: NodeId, name: Name, span: Span, - header: &'a FnHeader, + header: &FnHeader, generics: &'a Generics, decl: &'a FnDecl, body: &'a Block, ) { - let (closure_id, return_impl_trait_id, arguments) = match &header.asyncness.node { + let (closure_id, return_impl_trait_id) = match header.asyncness.node { IsAsync::Async { closure_id, return_impl_trait_id, - arguments, - } => (closure_id, return_impl_trait_id, arguments), + } => (closure_id, return_impl_trait_id), _ => unreachable!(), }; @@ -83,38 +82,16 @@ impl<'a> DefCollector<'a> { let fn_def_data = DefPathData::ValueNs(name.as_interned_str()); let fn_def = self.create_def(id, fn_def_data, span); return self.with_parent(fn_def, |this| { - this.create_def(*return_impl_trait_id, DefPathData::ImplTrait, span); + this.create_def(return_impl_trait_id, DefPathData::ImplTrait, span); visit::walk_generics(this, generics); - - // Walk the generated arguments for the `async fn`. - for (i, a) in arguments.iter().enumerate() { - use visit::Visitor; - if let Some(arg) = &a.arg { - this.visit_ty(&arg.ty); - } else { - this.visit_ty(&decl.inputs[i].ty); - } - } - - // We do not invoke `walk_fn_decl` as this will walk the arguments that are being - // replaced. - visit::walk_fn_ret_ty(this, &decl.output); + visit::walk_fn_decl(this, decl); let closure_def = this.create_def( - *closure_id, DefPathData::ClosureExpr, span, + closure_id, DefPathData::ClosureExpr, span, ); this.with_parent(closure_def, |this| { - use visit::Visitor; - // Walk each of the generated statements before the regular block body. - for a in arguments { - this.visit_stmt(&a.move_stmt); - if let Some(pat_stmt) = &a.pat_stmt { - this.visit_stmt(&pat_stmt); - } - } - - visit::walk_block(this, &body); + visit::walk_block(this, body); }) }) } @@ -302,7 +279,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { match expr.node { ExprKind::Mac(..) => return self.visit_macro_invoc(expr.id), - ExprKind::Closure(_, ref asyncness, ..) => { + ExprKind::Closure(_, asyncness, ..) => { let closure_def = self.create_def(expr.id, DefPathData::ClosureExpr, expr.span); @@ -311,7 +288,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { // Async closures desugar to closures inside of closures, so // we must create two defs. if let IsAsync::Async { closure_id, .. } = asyncness { - let async_def = self.create_def(*closure_id, + let async_def = self.create_def(closure_id, DefPathData::ClosureExpr, expr.span); self.parent_def = Some(async_def); diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 210c0c9225a3d..65fc56f2c4878 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1929,26 +1929,6 @@ pub struct InlineAsm { pub struct Arg { pub pat: P, pub hir_id: HirId, - pub source: ArgSource, -} - -impl Arg { - /// Returns the pattern representing the original binding for this argument. - pub fn original_pat(&self) -> &P { - match &self.source { - ArgSource::Normal => &self.pat, - ArgSource::AsyncFn(pat) => &pat, - } - } -} - -/// Represents the source of an argument in a function header. -#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)] -pub enum ArgSource { - /// Argument as specified by the user. - Normal, - /// Generated argument from `async fn` lowering, contains the original binding pattern. - AsyncFn(P), } /// Represents the header (not the body) of a function declaration. diff --git a/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs b/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs index 944cc8a8b1999..ecdcb4bbf114a 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs @@ -86,12 +86,12 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> { let sub_is_ret_type = self.is_return_type_anon(scope_def_id_sub, bregion_sub, ty_fndecl_sub); - let span_label_var1 = match anon_arg_sup.original_pat().simple_ident() { + let span_label_var1 = match anon_arg_sup.pat.simple_ident() { Some(simple_ident) => format!(" from `{}`", simple_ident), None => String::new(), }; - let span_label_var2 = match anon_arg_sub.original_pat().simple_ident() { + let span_label_var2 = match anon_arg_sub.pat.simple_ident() { Some(simple_ident) => format!(" into `{}`", simple_ident), None => String::new(), }; diff --git a/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs index 2d7587b11b6f8..0efc124e31fee 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs @@ -95,7 +95,7 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> { } } - let (error_var, span_label_var) = match arg.original_pat().simple_ident() { + let (error_var, span_label_var) = match arg.pat.simple_ident() { Some(simple_ident) => ( format!("the type of `{}`", simple_ident), format!("the type of `{}`", simple_ident), diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index c6583dd7a27b7..c5c6c4b944700 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -1335,30 +1335,6 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> run_early_pass!(self, check_mac, mac); } - - fn visit_fn_header(&mut self, header: &'a ast::FnHeader) { - // Unlike in HIR lowering and name resolution, the `AsyncArgument` statements are not added - // to the function body and the arguments do not replace those in the declaration. They are - // still visited manually here so that buffered lints can be emitted. - if let ast::IsAsync::Async { ref arguments, .. } = header.asyncness.node { - for a in arguments { - // Visit the argument.. - if let Some(arg) = &a.arg { - self.visit_pat(&arg.pat); - if let ast::ArgSource::AsyncFn(pat) = &arg.source { - self.visit_pat(pat); - } - self.visit_ty(&arg.ty); - } - - // ..and the statement. - self.visit_stmt(&a.move_stmt); - if let Some(pat_stmt) = &a.pat_stmt { - self.visit_stmt(&pat_stmt); - } - } - } - } } struct LateLintPassObjects<'a> { diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 593a09b6866db..7c57c50595bc8 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -2414,9 +2414,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { have_bound_regions, } = info; - let help_name = if let Some(body) = parent { - let arg = &self.tcx.hir().body(body).arguments[index]; - format!("`{}`", self.tcx.hir().hir_to_pretty_string(arg.original_pat().hir_id)) + let help_name = if let Some(ident) = parent.and_then(|body| { + self.tcx.hir().body(body).arguments[index].pat.simple_ident() + }) { + format!("`{}`", ident) } else { format!("argument {}", index + 1) }; diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 6415122dd3905..8e2c3dd3d8ad9 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -666,7 +666,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { size, align, }); - debug!("generator layout: {:#?}", layout); + debug!("generator layout ({:?}): {:#?}", ty, layout); layout } diff --git a/src/librustc_mir/borrow_check/used_muts.rs b/src/librustc_mir/borrow_check/used_muts.rs index abfc2f9466c8e..4a4787337ab58 100644 --- a/src/librustc_mir/borrow_check/used_muts.rs +++ b/src/librustc_mir/borrow_check/used_muts.rs @@ -52,6 +52,19 @@ struct GatherUsedMutsVisitor<'visit, 'cx: 'visit, 'gcx: 'tcx, 'tcx: 'cx> { mbcx: &'visit mut MirBorrowckCtxt<'cx, 'gcx, 'tcx>, } +impl GatherUsedMutsVisitor<'_, '_, '_, '_> { + fn remove_never_initialized_mut_locals(&mut self, into: &Place<'_>) { + // Remove any locals that we found were initialized from the + // `never_initialized_mut_locals` set. At the end, the only remaining locals will + // be those that were never initialized - we will consider those as being used as + // they will either have been removed by unreachable code optimizations; or linted + // as unused variables. + if let Some(local) = into.base_local() { + let _ = self.never_initialized_mut_locals.remove(&local); + } + } +} + impl<'visit, 'cx, 'gcx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'gcx, 'tcx> { fn visit_terminator_kind( &mut self, @@ -61,14 +74,10 @@ impl<'visit, 'cx, 'gcx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'c debug!("visit_terminator_kind: kind={:?}", kind); match &kind { TerminatorKind::Call { destination: Some((into, _)), .. } => { - if let Some(local) = into.base_local() { - debug!( - "visit_terminator_kind: kind={:?} local={:?} \ - never_initialized_mut_locals={:?}", - kind, local, self.never_initialized_mut_locals - ); - let _ = self.never_initialized_mut_locals.remove(&local); - } + self.remove_never_initialized_mut_locals(&into); + }, + TerminatorKind::DropAndReplace { location, .. } => { + self.remove_never_initialized_mut_locals(&location); }, _ => {}, } @@ -81,19 +90,14 @@ impl<'visit, 'cx, 'gcx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'c ) { match &statement.kind { StatementKind::Assign(into, _) => { - // Remove any locals that we found were initialized from the - // `never_initialized_mut_locals` set. At the end, the only remaining locals will - // be those that were never initialized - we will consider those as being used as - // they will either have been removed by unreachable code optimizations; or linted - // as unused variables. if let Some(local) = into.base_local() { debug!( "visit_statement: statement={:?} local={:?} \ never_initialized_mut_locals={:?}", statement, local, self.never_initialized_mut_locals ); - let _ = self.never_initialized_mut_locals.remove(&local); } + self.remove_never_initialized_mut_locals(into); }, _ => {}, } diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs index cffd8fb2892f5..85423955ce545 100644 --- a/src/librustc_mir/build/expr/as_temp.rs +++ b/src/librustc_mir/build/expr/as_temp.rs @@ -1,7 +1,7 @@ //! See docs in build/expr/mod.rs use crate::build::{BlockAnd, BlockAndExtension, Builder}; -use crate::build::scope::{CachedBlock, DropKind}; +use crate::build::scope::DropKind; use crate::hair::*; use rustc::middle::region; use rustc::mir::*; @@ -103,9 +103,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { temp_lifetime, temp_place, expr_ty, - DropKind::Value { - cached_block: CachedBlock::default(), - }, + DropKind::Value, ); } diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 8c2ef082c339f..20d1423f8a8b6 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -5,7 +5,7 @@ //! This also includes code for pattern bindings in `let` statements and //! function parameters. -use crate::build::scope::{CachedBlock, DropKind}; +use crate::build::scope::DropKind; use crate::build::ForGuard::{self, OutsideGuard, RefWithinGuard}; use crate::build::{BlockAnd, BlockAndExtension, Builder}; use crate::build::{GuardFrame, GuardFrameLocal, LocalsForNode}; @@ -557,9 +557,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { region_scope, &Place::Base(PlaceBase::Local(local_id)), var_ty, - DropKind::Value { - cached_block: CachedBlock::default(), - }, + DropKind::Value, ); } diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 123b46cb04820..919d575f21fe6 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -1,5 +1,5 @@ use crate::build; -use crate::build::scope::{CachedBlock, DropKind}; +use crate::build::scope::DropKind; use crate::hair::cx::Cx; use crate::hair::{LintLevel, BindingMode, PatternKind}; use crate::shim; @@ -126,6 +126,7 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Body<' opt_ty_info = None; self_arg = None; } + ArgInfo(fn_sig.inputs()[index], opt_ty_info, Some(&*arg.pat), self_arg) }); @@ -614,10 +615,7 @@ fn should_abort_on_panic<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, /////////////////////////////////////////////////////////////////////////// /// the main entry point for building MIR for a function -struct ArgInfo<'gcx>(Ty<'gcx>, - Option, - Option<&'gcx hir::Pat>, - Option); +struct ArgInfo<'gcx>(Ty<'gcx>, Option, Option<&'gcx hir::Pat>, Option); fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, fn_id: hir::HirId, @@ -883,21 +881,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // debuginfo and so that error reporting knows that this is a user // variable. For any other pattern the pattern introduces new // variables which will be named instead. - let mut name = None; - if let Some(pat) = pattern { - match pat.node { - hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, ident, _) - | hir::PatKind::Binding(hir::BindingAnnotation::Mutable, _, ident, _) => { - name = Some(ident.name); - } - _ => (), - } - } - - let source_info = SourceInfo { - scope: OUTERMOST_SOURCE_SCOPE, - span: pattern.map_or(self.fn_span, |pat| pat.span) + let (name, span) = if let Some(pat) = pattern { + (pat.simple_ident().map(|ident| ident.name), pat.span) + } else { + (None, self.fn_span) }; + + let source_info = SourceInfo { scope: OUTERMOST_SOURCE_SCOPE, span, }; self.local_decls.push(LocalDecl { mutability: Mutability::Mut, ty, @@ -922,8 +912,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Make sure we drop (parts of) the argument even when not matched on. self.schedule_drop( pattern.as_ref().map_or(ast_body.span, |pat| pat.span), - argument_scope, &place, ty, - DropKind::Value { cached_block: CachedBlock::default() }, + argument_scope, &place, ty, DropKind::Value, ); if let Some(pattern) = pattern { @@ -932,7 +921,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { match *pattern.kind { // Don't introduce extra copies for simple bindings - PatternKind::Binding { mutability, var, mode: BindingMode::ByValue, .. } => { + PatternKind::Binding { + mutability, + var, + mode: BindingMode::ByValue, + subpattern: None, + .. + } => { self.local_decls[local].mutability = mutability; self.local_decls[local].is_user_variable = if let Some(kind) = self_binding { diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index 58339173c9e5d..b697b9884367c 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -88,7 +88,7 @@ use rustc::middle::region; use rustc::ty::Ty; use rustc::hir; use rustc::mir::*; -use syntax_pos::{Span, DUMMY_SP}; +use syntax_pos::{DUMMY_SP, Span}; use rustc_data_structures::fx::FxHashMap; use std::collections::hash_map::Entry; use std::mem; @@ -143,10 +143,13 @@ struct DropData<'tcx> { /// Whether this is a value Drop or a StorageDead. kind: DropKind, + + /// The cached blocks for unwinds. + cached_block: CachedBlock, } #[derive(Debug, Default, Clone, Copy)] -pub(crate) struct CachedBlock { +struct CachedBlock { /// The cached block for the cleanups-on-diverge path. This block /// contains code to run the current drop and all the preceding /// drops (i.e., those having lower index in Drop’s Scope drop @@ -164,10 +167,8 @@ pub(crate) struct CachedBlock { #[derive(Debug)] pub(crate) enum DropKind { - Value { - cached_block: CachedBlock, - }, - Storage + Value, + Storage, } #[derive(Clone, Debug)] @@ -210,7 +211,7 @@ impl CachedBlock { impl DropKind { fn may_panic(&self) -> bool { match *self { - DropKind::Value { .. } => true, + DropKind::Value => true, DropKind::Storage => false } } @@ -225,25 +226,24 @@ impl<'tcx> Scope<'tcx> { /// `storage_only` controls whether to invalidate only drop paths that run `StorageDead`. /// `this_scope_only` controls whether to invalidate only drop paths that refer to the current /// top-of-scope (as opposed to dependent scopes). - fn invalidate_cache(&mut self, storage_only: bool, this_scope_only: bool) { + fn invalidate_cache(&mut self, storage_only: bool, is_generator: bool, this_scope_only: bool) { // FIXME: maybe do shared caching of `cached_exits` etc. to handle functions // with lots of `try!`? // cached exits drop storage and refer to the top-of-scope self.cached_exits.clear(); - if !storage_only { - // the current generator drop and unwind ignore - // storage but refer to top-of-scope - self.cached_generator_drop = None; + // the current generator drop and unwind refer to top-of-scope + self.cached_generator_drop = None; + + let ignore_unwinds = storage_only && !is_generator; + if !ignore_unwinds { self.cached_unwind.invalidate(); } - if !storage_only && !this_scope_only { + if !ignore_unwinds && !this_scope_only { for drop_data in &mut self.drops { - if let DropKind::Value { ref mut cached_block } = drop_data.kind { - cached_block.invalidate(); - } + drop_data.cached_block.invalidate(); } } } @@ -388,6 +388,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { unpack!(block = build_scope_drops( &mut self.cfg, + self.is_generator, &scope, block, unwind_to, @@ -454,6 +455,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { unpack!(block = build_scope_drops( &mut self.cfg, + self.is_generator, scope, block, unwind_to, @@ -484,10 +486,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let result = block; while let Some(scope) = scopes.next() { - if !scope.needs_cleanup && !self.is_generator { - continue; - } - block = if let Some(b) = scope.cached_generator_drop { self.cfg.terminate(block, src_info, TerminatorKind::Goto { target: b }); @@ -508,6 +506,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { unpack!(block = build_scope_drops( &mut self.cfg, + self.is_generator, scope, block, unwind_to, @@ -642,16 +641,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { place: &Place<'tcx>, place_ty: Ty<'tcx>, ) { - self.schedule_drop( - span, region_scope, place, place_ty, - DropKind::Storage, - ); - self.schedule_drop( - span, region_scope, place, place_ty, - DropKind::Value { - cached_block: CachedBlock::default(), - }, - ); + self.schedule_drop(span, region_scope, place, place_ty, DropKind::Storage); + self.schedule_drop(span, region_scope, place, place_ty, DropKind::Value); } // Scheduling drops @@ -671,7 +662,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ) { let needs_drop = self.hir.needs_drop(place_ty); match drop_kind { - DropKind::Value { .. } => if !needs_drop { return }, + DropKind::Value => if !needs_drop { return }, DropKind::Storage => { match *place { Place::Base(PlaceBase::Local(index)) => if index.index() <= self.arg_count { @@ -736,9 +727,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // invalidating caches of each scope visited. This way bare minimum of the // caches gets invalidated. i.e., if a new drop is added into the middle scope, the // cache of outer scope stays intact. - scope.invalidate_cache(!needs_drop, this_scope); + scope.invalidate_cache(!needs_drop, self.is_generator, this_scope); if this_scope { - if let DropKind::Value { .. } = drop_kind { + if let DropKind::Value = drop_kind { scope.needs_cleanup = true; } @@ -750,7 +741,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { scope.drops.push(DropData { span: scope_end, location: place.clone(), - kind: drop_kind + kind: drop_kind, + cached_block: CachedBlock::default(), }); return; } @@ -797,6 +789,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // to left reading the cached results but never created anything. // Find the last cached block + debug!("diverge_cleanup_gen(self.scopes = {:?})", self.scopes); let (mut target, first_uncached) = if let Some(cached_index) = self.scopes.iter() .rposition(|scope| scope.cached_unwind.get(generator_drop).is_some()) { (self.scopes[cached_index].cached_unwind.get(generator_drop).unwrap(), cached_index + 1) @@ -890,7 +883,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { assert_eq!(top_scope.region_scope, region_scope); top_scope.drops.clear(); - top_scope.invalidate_cache(false, true); + top_scope.invalidate_cache(false, self.is_generator, true); } /// Drops the single variable provided @@ -941,7 +934,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } } - top_scope.invalidate_cache(true, true); + top_scope.invalidate_cache(true, self.is_generator, true); } } @@ -949,13 +942,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// Builds drops for pop_scope and exit_scope. fn build_scope_drops<'tcx>( cfg: &mut CFG<'tcx>, + is_generator: bool, scope: &Scope<'tcx>, mut block: BasicBlock, last_unwind_to: BasicBlock, arg_count: usize, generator_drop: bool, ) -> BlockAnd<()> { - debug!("build_scope_drops({:?} -> {:?}", block, scope); + debug!("build_scope_drops({:?} -> {:?})", block, scope); // Build up the drops in evaluation order. The end result will // look like: @@ -969,28 +963,20 @@ fn build_scope_drops<'tcx>( // The horizontal arrows represent the execution path when the drops return // successfully. The downwards arrows represent the execution path when the // drops panic (panicking while unwinding will abort, so there's no need for - // another set of arrows). The drops for the unwind path should have already - // been generated by `diverge_cleanup_gen`. - - let mut unwind_blocks = scope.drops.iter().rev().filter_map(|drop_data| { - if let DropKind::Value { cached_block } = drop_data.kind { - Some(cached_block.get(generator_drop).unwrap_or_else(|| { - span_bug!(drop_data.span, "cached block not present?") - })) - } else { - None - } - }); - - // When we unwind from a drop, we start cleaning up from the next one, so - // we don't need this block. - unwind_blocks.next(); + // another set of arrows). + // + // For generators, we unwind from a drop on a local to its StorageDead + // statement. For other functions we don't worry about StorageDead. The + // drops for the unwind path should have already been generated by + // `diverge_cleanup_gen`. - for drop_data in scope.drops.iter().rev() { + for drop_idx in (0..scope.drops.len()).rev() { + let drop_data = &scope.drops[drop_idx]; let source_info = scope.source_info(drop_data.span); match drop_data.kind { - DropKind::Value { .. } => { - let unwind_to = unwind_blocks.next().unwrap_or(last_unwind_to); + DropKind::Value => { + let unwind_to = get_unwind_to(scope, is_generator, drop_idx, generator_drop) + .unwrap_or(last_unwind_to); let next = cfg.start_new_block(); cfg.terminate(block, source_info, TerminatorKind::Drop { @@ -1018,6 +1004,31 @@ fn build_scope_drops<'tcx>( block.unit() } +fn get_unwind_to<'tcx>( + scope: &Scope<'tcx>, + is_generator: bool, + unwind_from: usize, + generator_drop: bool, +) -> Option { + for drop_idx in (0..unwind_from).rev() { + let drop_data = &scope.drops[drop_idx]; + match (is_generator, &drop_data.kind) { + (true, DropKind::Storage) => { + return Some(drop_data.cached_block.get(generator_drop).unwrap_or_else(|| { + span_bug!(drop_data.span, "cached block not present for {:?}", drop_data) + })); + } + (false, DropKind::Value) => { + return Some(drop_data.cached_block.get(generator_drop).unwrap_or_else(|| { + span_bug!(drop_data.span, "cached block not present for {:?}", drop_data) + })); + } + _ => (), + } + } + None +} + fn build_diverge_scope<'tcx>(cfg: &mut CFG<'tcx>, span: Span, scope: &mut Scope<'tcx>, @@ -1051,6 +1062,7 @@ fn build_diverge_scope<'tcx>(cfg: &mut CFG<'tcx>, // Build up the drops. Here we iterate the vector in // *forward* order, so that we generate drops[0] first (right to // left in diagram above). + debug!("build_diverge_scope({:?})", scope.drops); for (j, drop_data) in scope.drops.iter_mut().enumerate() { debug!("build_diverge_scope drop_data[{}]: {:?}", j, drop_data); // Only full value drops are emitted in the diverging path, @@ -1070,20 +1082,30 @@ fn build_diverge_scope<'tcx>(cfg: &mut CFG<'tcx>, source_info: source_info(drop_data.span), kind: StatementKind::StorageDead(index) }); + if !target_built_by_us { + // We cannot add statements to an existing block, so we create a new + // block for our StorageDead statements. + let block = cfg.start_new_cleanup_block(); + let source_info = SourceInfo { span: DUMMY_SP, scope: source_scope }; + cfg.terminate(block, source_info, + TerminatorKind::Goto { target: target }); + target = block; + target_built_by_us = true; + } } _ => unreachable!(), }; + *drop_data.cached_block.ref_mut(generator_drop) = Some(target); } DropKind::Storage => {} - DropKind::Value { ref mut cached_block } => { - let cached_block = cached_block.ref_mut(generator_drop); + DropKind::Value => { + let cached_block = drop_data.cached_block.ref_mut(generator_drop); target = if let Some(cached_block) = *cached_block { storage_deads.clear(); target_built_by_us = false; cached_block } else { - push_storage_deads( - cfg, &mut target, &mut storage_deads, target_built_by_us, source_scope); + push_storage_deads(cfg, target, &mut storage_deads); let block = cfg.start_new_cleanup_block(); cfg.terminate(block, source_info(drop_data.span), TerminatorKind::Drop { @@ -1098,7 +1120,7 @@ fn build_diverge_scope<'tcx>(cfg: &mut CFG<'tcx>, } }; } - push_storage_deads(cfg, &mut target, &mut storage_deads, target_built_by_us, source_scope); + push_storage_deads(cfg, target, &mut storage_deads); *scope.cached_unwind.ref_mut(generator_drop) = Some(target); assert!(storage_deads.is_empty()); @@ -1108,23 +1130,13 @@ fn build_diverge_scope<'tcx>(cfg: &mut CFG<'tcx>, } fn push_storage_deads(cfg: &mut CFG<'tcx>, - target: &mut BasicBlock, - storage_deads: &mut Vec>, - target_built_by_us: bool, - source_scope: SourceScope) { + target: BasicBlock, + storage_deads: &mut Vec>) { if storage_deads.is_empty() { return; } - if !target_built_by_us { - // We cannot add statements to an existing block, so we create a new - // block for our StorageDead statements. - let block = cfg.start_new_cleanup_block(); - let source_info = SourceInfo { span: DUMMY_SP, scope: source_scope }; - cfg.terminate(block, source_info, TerminatorKind::Goto { target: *target }); - *target = block; - } - let statements = &mut cfg.block_data_mut(*target).statements; + let statements = &mut cfg.block_data_mut(target).statements; storage_deads.reverse(); debug!("push_storage_deads({:?}), storage_deads={:?}, statements={:?}", - *target, storage_deads, statements); + target, storage_deads, statements); storage_deads.append(statements); mem::swap(statements, storage_deads); assert!(storage_deads.is_empty()); diff --git a/src/librustc_mir/dataflow/impls/storage_liveness.rs b/src/librustc_mir/dataflow/impls/storage_liveness.rs index 0fb66032a171d..9bf346f5f62d6 100644 --- a/src/librustc_mir/dataflow/impls/storage_liveness.rs +++ b/src/librustc_mir/dataflow/impls/storage_liveness.rs @@ -43,16 +43,9 @@ impl<'a, 'tcx> BitDenotation<'tcx> for MaybeStorageLive<'a, 'tcx> { } fn terminator_effect(&self, - sets: &mut BlockSets<'_, Local>, - loc: Location) { - match &self.mir[loc.block].terminator().kind { - TerminatorKind::Drop { location, .. } => { - if let Some(l) = location.local_or_deref_local() { - sets.kill(l); - } - } - _ => (), - } + _sets: &mut BlockSets<'_, Local>, + _loc: Location) { + // Terminators have no effect } fn propagate_call_return( diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index f1e23655741fc..ff7a9984da4ee 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -11,7 +11,7 @@ use rustc::mir::interpret::{ use rustc::mir::CastKind; use rustc_apfloat::Float; -use super::{InterpretCx, Machine, PlaceTy, OpTy, ImmTy, Immediate}; +use super::{InterpretCx, Machine, PlaceTy, OpTy, Immediate}; impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> { fn type_is_fat_ptr(&self, ty: Ty<'tcx>) -> bool { @@ -306,6 +306,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> src: OpTy<'tcx, M::PointerTag>, dest: PlaceTy<'tcx, M::PointerTag>, ) -> EvalResult<'tcx> { + trace!("Unsizing {:?} into {:?}", src, dest); match (&src.layout.ty.sty, &dest.layout.ty.sty) { (&ty::Ref(_, s, _), &ty::Ref(_, d, _)) | (&ty::Ref(_, s, _), &ty::RawPtr(TypeAndMut { ty: d, .. })) | @@ -335,20 +336,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> if dst_field.layout.is_zst() { continue; } - let src_field = match src.try_as_mplace() { - Ok(mplace) => { - let src_field = self.mplace_field(mplace, i as u64)?; - src_field.into() - } - Err(..) => { - let src_field_layout = src.layout.field(self, i)?; - // this must be a field covering the entire thing - assert_eq!(src.layout.fields.offset(i).bytes(), 0); - assert_eq!(src_field_layout.size, src.layout.size); - // just sawp out the layout - OpTy::from(ImmTy { imm: src.to_immediate(), layout: src_field_layout }) - } - }; + let src_field = self.operand_field(src, i as u64)?; if src_field.layout.ty == dst_field.layout.ty { self.copy_op(src_field, dst_field)?; } else { diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 2afcbe8a15137..89c4a9106a477 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -222,7 +222,7 @@ impl<'a> AstValidator<'a> { } } - fn check_trait_fn_not_async(&self, span: Span, asyncness: &IsAsync) { + fn check_trait_fn_not_async(&self, span: Span, asyncness: IsAsync) { if asyncness.is_async() { struct_span_err!(self.session, span, E0706, "trait fns cannot be declared `async`").emit() @@ -561,7 +561,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.invalid_visibility(&impl_item.vis, None); if let ImplItemKind::Method(ref sig, _) = impl_item.node { self.check_trait_fn_not_const(sig.header.constness); - self.check_trait_fn_not_async(impl_item.span, &sig.header.asyncness.node); + self.check_trait_fn_not_async(impl_item.span, sig.header.asyncness.node); } } } @@ -633,7 +633,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.no_questions_in_bounds(bounds, "supertraits", true); for trait_item in trait_items { if let TraitItemKind::Method(ref sig, ref block) = trait_item.node { - self.check_trait_fn_not_async(trait_item.span, &sig.header.asyncness.node); + self.check_trait_fn_not_async(trait_item.span, sig.header.asyncness.node); self.check_trait_fn_not_const(sig.header.constness); if block.is_none() { self.check_decl_no_pat(&sig.decl, |span, mut_ident| { diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 20e18d60f076b..f084d3b9f28c3 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -948,16 +948,6 @@ impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> { intravisit::walk_pat(self, pat); } - - fn visit_argument_source(&mut self, s: &'tcx hir::ArgSource) { - match s { - // Don't visit the pattern in `ArgSource::AsyncFn`, it contains a pattern which has - // a `NodeId` w/out a type, as it is only used for getting the name of the original - // pattern for diagnostics where only an `hir::Arg` is present. - hir::ArgSource::AsyncFn(..) => {}, - _ => intravisit::walk_argument_source(self, s), - } - } } //////////////////////////////////////////////////////////////////////////////////////////// @@ -1147,16 +1137,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { intravisit::walk_pat(self, pattern); } - fn visit_argument_source(&mut self, s: &'tcx hir::ArgSource) { - match s { - // Don't visit the pattern in `ArgSource::AsyncFn`, it contains a pattern which has - // a `NodeId` w/out a type, as it is only used for getting the name of the original - // pattern for diagnostics where only an `hir::Arg` is present. - hir::ArgSource::AsyncFn(..) => {}, - _ => intravisit::walk_argument_source(self, s), - } - } - fn visit_local(&mut self, local: &'tcx hir::Local) { if let Some(ref init) = local.init { if self.check_expr_pat_type(init.hir_id, init.span) { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 21e759ccc650e..99abe69017da7 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -855,15 +855,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { _: NodeId) { debug!("(resolving function) entering function"); - let (rib_kind, asyncness) = match function_kind { - FnKind::ItemFn(_, ref header, ..) => - (FnItemRibKind, &header.asyncness.node), - FnKind::Method(_, ref sig, _, _) => - (AssocItemRibKind, &sig.header.asyncness.node), - FnKind::Closure(_) => - // Async closures aren't resolved through `visit_fn`-- they're - // processed separately - (NormalRibKind, &IsAsync::NotAsync), + let rib_kind = match function_kind { + FnKind::ItemFn(..) => FnItemRibKind, + FnKind::Method(..) => AssocItemRibKind, + FnKind::Closure(_) => NormalRibKind, }; // Create a value rib for the function. @@ -874,45 +869,20 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { // Add each argument to the rib. let mut bindings_list = FxHashMap::default(); - let mut add_argument = |argument: &ast::Arg| { + for argument in &declaration.inputs { self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list); + self.visit_ty(&argument.ty); - debug!("(resolving function) recorded argument"); - }; - // Walk the generated async arguments if this is an `async fn`, otherwise walk the - // normal arguments. - if let IsAsync::Async { ref arguments, .. } = asyncness { - for (i, a) in arguments.iter().enumerate() { - if let Some(arg) = &a.arg { - add_argument(&arg); - } else { - add_argument(&declaration.inputs[i]); - } - } - } else { - for a in &declaration.inputs { add_argument(a); } + debug!("(resolving function) recorded argument"); } - visit::walk_fn_ret_ty(self, &declaration.output); // Resolve the function body, potentially inside the body of an async closure match function_kind { - FnKind::ItemFn(.., body) | FnKind::Method(.., body) => { - if let IsAsync::Async { ref arguments, .. } = asyncness { - let mut body = body.clone(); - // Insert the generated statements into the body before attempting to - // resolve names. - for a in arguments.iter().rev() { - if let Some(pat_stmt) = a.pat_stmt.clone() { - body.stmts.insert(0, pat_stmt); - } - body.stmts.insert(0, a.move_stmt.clone()); - } - self.visit_block(&body); - } else { - self.visit_block(body); - } + FnKind::ItemFn(.., body) | + FnKind::Method(.., body) => { + self.visit_block(body); } FnKind::Closure(body) => { self.visit_expr(body); @@ -4178,7 +4148,7 @@ impl<'a> Resolver<'a> { let add_module_candidates = |module: Module<'_>, names: &mut Vec| { for (&(ident, _), resolution) in module.resolutions.borrow().iter() { if let Some(binding) = resolution.borrow().binding { - if !ident.is_gensymed() && filter_fn(binding.res()) { + if filter_fn(binding.res()) { names.push(TypoSuggestion { candidate: ident.name, article: binding.res().article(), @@ -4196,7 +4166,7 @@ impl<'a> Resolver<'a> { for rib in self.ribs[ns].iter().rev() { // Locals and type parameters for (ident, &res) in &rib.bindings { - if !ident.is_gensymed() && filter_fn(res) { + if filter_fn(res) { names.push(TypoSuggestion { candidate: ident.name, article: res.article(), @@ -4226,7 +4196,7 @@ impl<'a> Resolver<'a> { }, ); - if !ident.is_gensymed() && filter_fn(crate_mod) { + if filter_fn(crate_mod) { Some(TypoSuggestion { candidate: ident.name, article: "a", @@ -4249,15 +4219,13 @@ impl<'a> Resolver<'a> { // Add primitive types to the mix if filter_fn(Res::PrimTy(Bool)) { names.extend( - self.primitive_type_table.primitive_types - .iter() - .map(|(name, _)| { - TypoSuggestion { - candidate: *name, - article: "a", - kind: "primitive type", - } - }) + self.primitive_type_table.primitive_types.iter().map(|(name, _)| { + TypoSuggestion { + candidate: *name, + article: "a", + kind: "primitive type", + } + }) ) } } else { diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index 109863f8a56b2..db8b5eacd94d9 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -374,7 +374,7 @@ impl Sig for ast::Item { Ok(extend_sig(ty, text, defs, vec![])) } - ast::ItemKind::Fn(ref decl, ref header, ref generics, _) => { + ast::ItemKind::Fn(ref decl, header, ref generics, _) => { let mut text = String::new(); if header.constness.node == ast::Constness::Const { text.push_str("const "); diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 9ef6112a94591..f05e0d31582fa 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -324,6 +324,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ); } } + if let ty::RawPtr(_) = &actual.sty { + err.note("try using `<*const T>::as_ref()` to get a reference to the \ + type behind the pointer: https://doc.rust-lang.org/std/\ + primitive.pointer.html#method.as_ref"); + } err } } else { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 82d198f0b78f7..3ada80b3e8b70 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1009,16 +1009,6 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> { // Don't descend into the bodies of nested closures fn visit_fn(&mut self, _: intravisit::FnKind<'gcx>, _: &'gcx hir::FnDecl, _: hir::BodyId, _: Span, _: hir::HirId) { } - - fn visit_argument_source(&mut self, s: &'gcx hir::ArgSource) { - match s { - // Don't visit the pattern in `ArgSource::AsyncFn`, it contains a pattern which has - // a `NodeId` w/out a type, as it is only used for getting the name of the original - // pattern for diagnostics where only an `hir::Arg` is present. - hir::ArgSource::AsyncFn(..) => {}, - _ => intravisit::walk_argument_source(self, s), - } - } } /// When `check_fn` is invoked on a generator (i.e., a body that diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index a535f776dfe60..6f8682e64671c 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -311,16 +311,6 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { let ty = self.resolve(&ty, &hir_ty.span); self.write_ty_to_tables(hir_ty.hir_id, ty); } - - fn visit_argument_source(&mut self, s: &'gcx hir::ArgSource) { - match s { - // Don't visit the pattern in `ArgSource::AsyncFn`, it contains a pattern which has - // a `NodeId` w/out a type, as it is only used for getting the name of the original - // pattern for diagnostics where only an `hir::Arg` is present. - hir::ArgSource::AsyncFn(..) => {}, - _ => intravisit::walk_argument_source(self, s), - } - } } impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index c516fbc3bb940..3034cacf6253f 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1335,88 +1335,97 @@ pub fn checked_type_of<'a, 'tcx>( Node::Ty(&hir::Ty { node: hir::TyKind::Path(_), .. }) | Node::Expr(&hir::Expr { node: ExprKind::Struct(..), .. }) | - Node::Expr(&hir::Expr { node: ExprKind::Path(_), .. }) => { + Node::Expr(&hir::Expr { node: ExprKind::Path(_), .. }) | + Node::TraitRef(..) => { let path = match parent_node { - Node::Ty(&hir::Ty { node: hir::TyKind::Path(ref path), .. }) | - Node::Expr(&hir::Expr { node: ExprKind::Path(ref path), .. }) => { - path + Node::Ty(&hir::Ty { + node: hir::TyKind::Path(QPath::Resolved(_, ref path)), + .. + }) + | Node::Expr(&hir::Expr { + node: ExprKind::Path(QPath::Resolved(_, ref path)), + .. + }) => { + Some(&**path) } Node::Expr(&hir::Expr { node: ExprKind::Struct(ref path, ..), .. }) => { - &*path + if let QPath::Resolved(_, ref path) = **path { + Some(&**path) + } else { + None + } } - _ => unreachable!(), + Node::TraitRef(&hir::TraitRef { ref path, .. }) => Some(path), + _ => None, }; - match path { - QPath::Resolved(_, ref path) => { - let arg_index = path.segments.iter() - .filter_map(|seg| seg.args.as_ref()) - .map(|generic_args| generic_args.args.as_ref()) - .find_map(|args| { - args.iter() - .filter(|arg| arg.is_const()) - .enumerate() - .filter(|(_, arg)| arg.id() == hir_id) - .map(|(index, _)| index) - .next() - }) - .or_else(|| { - if !fail { - None - } else { - bug!("no arg matching AnonConst in path") - } - })?; - - // We've encountered an `AnonConst` in some path, so we need to - // figure out which generic parameter it corresponds to and return - // the relevant type. - let generics = match path.res { - Res::Def(DefKind::Ctor(..), def_id) => - tcx.generics_of(tcx.parent(def_id).unwrap()), - Res::Def(_, def_id) => - tcx.generics_of(def_id), - Res::Err => - return Some(tcx.types.err), - _ if !fail => - return None, - x => { - tcx.sess.delay_span_bug( - DUMMY_SP, - &format!( - "unexpected const parent path def {:?}", x - ), - ); - return Some(tcx.types.err); + if let Some(path) = path { + let arg_index = path.segments.iter() + .filter_map(|seg| seg.args.as_ref()) + .map(|generic_args| generic_args.args.as_ref()) + .find_map(|args| { + args.iter() + .filter(|arg| arg.is_const()) + .enumerate() + .filter(|(_, arg)| arg.id() == hir_id) + .map(|(index, _)| index) + .next() + }) + .or_else(|| { + if !fail { + None + } else { + bug!("no arg matching AnonConst in path") } - }; - - generics.params.iter() - .filter(|param| { - if let ty::GenericParamDefKind::Const = param.kind { - true - } else { - false - } - }) - .nth(arg_index) - .map(|param| tcx.type_of(param.def_id)) - // This is no generic parameter associated with the arg. This is - // probably from an extra arg where one is not needed. - .unwrap_or(tcx.types.err) - } - x => { - if !fail { - return None; + })?; + + // We've encountered an `AnonConst` in some path, so we need to + // figure out which generic parameter it corresponds to and return + // the relevant type. + let generics = match path.res { + Res::Def(DefKind::Ctor(..), def_id) => { + tcx.generics_of(tcx.parent(def_id).unwrap()) } - tcx.sess.delay_span_bug( - DUMMY_SP, - &format!( - "unexpected const parent path {:?}", x - ), - ); - tcx.types.err + Res::Def(_, def_id) => tcx.generics_of(def_id), + Res::Err => return Some(tcx.types.err), + _ if !fail => return None, + res => { + tcx.sess.delay_span_bug( + DUMMY_SP, + &format!( + "unexpected const parent path def {:?}", + res, + ), + ); + return Some(tcx.types.err); + } + }; + + generics.params.iter() + .filter(|param| { + if let ty::GenericParamDefKind::Const = param.kind { + true + } else { + false + } + }) + .nth(arg_index) + .map(|param| tcx.type_of(param.def_id)) + // This is no generic parameter associated with the arg. This is + // probably from an extra arg where one is not needed. + .unwrap_or(tcx.types.err) + } else { + if !fail { + return None; } + tcx.sess.delay_span_bug( + DUMMY_SP, + &format!( + "unexpected const parent path {:?}", + parent_node, + ), + ); + return Some(tcx.types.err); } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e68ad6a7c3b4b..0c00b3b20b5b3 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2019,7 +2019,7 @@ impl<'a> Clean for (&'a [hir::Ty], hir::BodyId) { Arguments { values: self.0.iter().enumerate().map(|(i, ty)| { Argument { - name: name_from_pat(&body.arguments[i].original_pat()), + name: name_from_pat(&body.arguments[i].pat), type_: ty.clean(cx), } }).collect() diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 75e83bd9f9c74..b8a10d90c3c0a 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -879,17 +879,6 @@ pub struct Local { pub id: NodeId, pub span: Span, pub attrs: ThinVec, - /// Origin of this local variable. - pub source: LocalSource, -} - -#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)] -pub enum LocalSource { - /// Local was parsed from source. - Normal, - /// Within `ast::IsAsync::Async`, a local is generated that will contain the moved arguments - /// of an `async fn`. - AsyncFn, } /// An arm of a 'match'. @@ -1770,16 +1759,6 @@ pub struct Arg { pub ty: P, pub pat: P, pub id: NodeId, - pub source: ArgSource, -} - -/// The source of an argument in a function header. -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] -pub enum ArgSource { - /// Argument as written by the user. - Normal, - /// Argument from `async fn` lowering, contains the original binding pattern. - AsyncFn(P), } /// Alternative representation for `Arg`s describing `self` parameter of methods. @@ -1839,7 +1818,6 @@ impl Arg { }), ty, id: DUMMY_NODE_ID, - source: ArgSource::Normal, }; match eself.node { SelfKind::Explicit(ty, mutbl) => arg(mutbl, ty), @@ -1894,39 +1872,18 @@ pub enum Unsafety { Normal, } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] -pub struct AsyncArgument { - /// `__arg0` - pub ident: Ident, - /// `__arg0: ` argument to replace existing function argument `: `. Only if - /// argument is not a simple binding. - pub arg: Option, - /// `let __arg0 = __arg0;` statement to be inserted at the start of the block. - pub move_stmt: Stmt, - /// `let = __arg0;` statement to be inserted at the start of the block, after matching - /// move statement. Only if argument is not a simple binding. - pub pat_stmt: Option, -} - -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug)] pub enum IsAsync { Async { closure_id: NodeId, return_impl_trait_id: NodeId, - /// This field stores the arguments and statements that are used in HIR lowering to - /// ensure that `async fn` arguments are dropped at the correct time. - /// - /// The argument and statements here are generated at parse time as they are required in - /// both the hir lowering, def collection and name resolution and this stops them needing - /// to be created in each place. - arguments: Vec, }, NotAsync, } impl IsAsync { - pub fn is_async(&self) -> bool { - if let IsAsync::Async { .. } = *self { + pub fn is_async(self) -> bool { + if let IsAsync::Async { .. } = self { true } else { false @@ -1934,12 +1891,12 @@ impl IsAsync { } /// In ths case this is an `async` return, the `NodeId` for the generated `impl Trait` item. - pub fn opt_return_id(&self) -> Option { + pub fn opt_return_id(self) -> Option { match self { IsAsync::Async { return_impl_trait_id, .. - } => Some(*return_impl_trait_id), + } => Some(return_impl_trait_id), IsAsync::NotAsync => None, } } @@ -2279,7 +2236,7 @@ impl Item { /// /// All the information between the visibility and the name of the function is /// included in this struct (e.g., `async unsafe fn` or `const extern "C" fn`). -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)] pub struct FnHeader { pub unsafety: Unsafety, pub asyncness: Spanned, diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 9c0ffc1f6e8cb..47c79f8466a95 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -516,7 +516,6 @@ impl<'a> AstBuilder for ExtCtxt<'a> { id: ast::DUMMY_NODE_ID, span: sp, attrs: ThinVec::new(), - source: ast::LocalSource::Normal, }); ast::Stmt { id: ast::DUMMY_NODE_ID, @@ -545,7 +544,6 @@ impl<'a> AstBuilder for ExtCtxt<'a> { id: ast::DUMMY_NODE_ID, span: sp, attrs: ThinVec::new(), - source: ast::LocalSource::Normal, }); ast::Stmt { id: ast::DUMMY_NODE_ID, @@ -563,7 +561,6 @@ impl<'a> AstBuilder for ExtCtxt<'a> { id: ast::DUMMY_NODE_ID, span, attrs: ThinVec::new(), - source: ast::LocalSource::Normal, }); ast::Stmt { id: ast::DUMMY_NODE_ID, @@ -971,8 +968,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { ast::Arg { ty, pat: arg_pat, - id: ast::DUMMY_NODE_ID, - source: ast::ArgSource::Normal, + id: ast::DUMMY_NODE_ID } } diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index 8f24d11cfd5b0..c56c156182bd6 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -101,13 +101,6 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> { fn remove(&mut self, id: ast::NodeId) -> AstFragment { self.expanded_fragments.remove(&id).unwrap() } - - fn next_id(&mut self, id: &mut ast::NodeId) { - if self.monotonic { - assert_eq!(*id, ast::DUMMY_NODE_ID); - *id = self.cx.resolver.next_node_id() - } - } } impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> { @@ -189,19 +182,9 @@ impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> { noop_visit_block(block, self); for stmt in block.stmts.iter_mut() { - self.next_id(&mut stmt.id); - } - } - - fn visit_asyncness(&mut self, a: &mut ast::IsAsync) { - noop_visit_asyncness(a, self); - - if let ast::IsAsync::Async { ref mut arguments, .. } = a { - for argument in arguments.iter_mut() { - self.next_id(&mut argument.move_stmt.id); - if let Some(ref mut pat_stmt) = &mut argument.pat_stmt { - self.next_id(&mut pat_stmt.id); - } + if self.monotonic { + assert_eq!(stmt.id, ast::DUMMY_NODE_ID); + stmt.id = self.cx.resolver.next_node_id(); } } } diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 0016c0d4d7e2b..757513098995b 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -207,10 +207,6 @@ pub trait MutVisitor: Sized { noop_visit_local(l, self); } - fn visit_local_source(&mut self, l: &mut LocalSource) { - noop_visit_local_source(l, self); - } - fn visit_mac(&mut self, _mac: &mut Mac) { panic!("visit_mac disabled by default"); // N.B., see note about macros above. If you really want a visitor that @@ -234,10 +230,6 @@ pub trait MutVisitor: Sized { noop_visit_arg(a, self); } - fn visit_arg_source(&mut self, a: &mut ArgSource) { - noop_visit_arg_source(a, self); - } - fn visit_generics(&mut self, generics: &mut Generics) { noop_visit_generics(generics, self); } @@ -522,17 +514,13 @@ pub fn noop_visit_parenthesized_parameter_data(args: &mut Parenth } pub fn noop_visit_local(local: &mut P, vis: &mut T) { - let Local { id, pat, ty, init, span, attrs, source } = local.deref_mut(); + let Local { id, pat, ty, init, span, attrs } = local.deref_mut(); vis.visit_id(id); vis.visit_pat(pat); visit_opt(ty, |ty| vis.visit_ty(ty)); visit_opt(init, |init| vis.visit_expr(init)); vis.visit_span(span); visit_thin_attrs(attrs, vis); - vis.visit_local_source(source); -} - -pub fn noop_visit_local_source(_local_source: &mut LocalSource, _vis: &mut T) { } pub fn noop_visit_attribute(attr: &mut Attribute, vis: &mut T) { @@ -571,18 +559,10 @@ pub fn noop_visit_meta_item(mi: &mut MetaItem, vis: &mut T) { vis.visit_span(span); } -pub fn noop_visit_arg(Arg { id, pat, ty, source }: &mut Arg, vis: &mut T) { +pub fn noop_visit_arg(Arg { id, pat, ty }: &mut Arg, vis: &mut T) { vis.visit_id(id); vis.visit_pat(pat); vis.visit_ty(ty); - vis.visit_arg_source(source); -} - -pub fn noop_visit_arg_source(source: &mut ArgSource, vis: &mut T) { - match source { - ArgSource::Normal => {}, - ArgSource::AsyncFn(pat) => vis.visit_pat(pat), - } } pub fn noop_visit_tt(tt: &mut TokenTree, vis: &mut T) { @@ -690,25 +670,9 @@ pub fn noop_visit_interpolated(nt: &mut token::Nonterminal, vis: pub fn noop_visit_asyncness(asyncness: &mut IsAsync, vis: &mut T) { match asyncness { - IsAsync::Async { closure_id, return_impl_trait_id, ref mut arguments } => { + IsAsync::Async { closure_id, return_impl_trait_id } => { vis.visit_id(closure_id); vis.visit_id(return_impl_trait_id); - for AsyncArgument { ident, arg, pat_stmt, move_stmt } in arguments.iter_mut() { - vis.visit_ident(ident); - if let Some(arg) = arg { - vis.visit_arg(arg); - } - visit_clobber(move_stmt, |stmt| { - vis.flat_map_stmt(stmt) - .expect_one("expected visitor to produce exactly one item") - }); - visit_opt(pat_stmt, |stmt| { - visit_clobber(stmt, |stmt| { - vis.flat_map_stmt(stmt) - .expect_one("expected visitor to produce exactly one item") - }) - }); - } } IsAsync::NotAsync => {} } diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs index af9092dd5b05a..5df22f28797a4 100644 --- a/src/libsyntax/parse/diagnostics.rs +++ b/src/libsyntax/parse/diagnostics.rs @@ -27,7 +27,7 @@ crate fn dummy_arg(ident: Ident) -> Arg { span: ident.span, id: ast::DUMMY_NODE_ID }; - Arg { ty: P(ty), pat: pat, id: ast::DUMMY_NODE_ID, source: ast::ArgSource::Normal } + Arg { ty: P(ty), pat: pat, id: ast::DUMMY_NODE_ID } } pub enum Error { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index f200d3ec8d5c1..ae1e5116c676e 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1,9 +1,9 @@ // ignore-tidy-filelength -use crate::ast::{AngleBracketedArgs, AsyncArgument, ParenthesizedArgs, AttrStyle, BareFnTy}; +use crate::ast::{AngleBracketedArgs, ParenthesizedArgs, AttrStyle, BareFnTy}; use crate::ast::{GenericBound, TraitBoundModifier}; use crate::ast::Unsafety; -use crate::ast::{Mod, AnonConst, Arg, ArgSource, Arm, Guard, Attribute, BindingMode, TraitItemKind}; +use crate::ast::{Mod, AnonConst, Arg, Arm, Guard, Attribute, BindingMode, TraitItemKind}; use crate::ast::Block; use crate::ast::{BlockCheckMode, CaptureBy, Movability}; use crate::ast::{Constness, Crate}; @@ -16,7 +16,7 @@ use crate::ast::{GenericParam, GenericParamKind}; use crate::ast::GenericArg; use crate::ast::{Ident, ImplItem, IsAsync, IsAuto, Item, ItemKind}; use crate::ast::{Label, Lifetime}; -use crate::ast::{Local, LocalSource}; +use crate::ast::Local; use crate::ast::MacStmtStyle; use crate::ast::{Mac, Mac_, MacDelimiter}; use crate::ast::{MutTy, Mutability}; @@ -51,7 +51,7 @@ use crate::parse::diagnostics::{Error, dummy_arg}; use errors::{Applicability, DiagnosticBuilder, DiagnosticId, FatalError}; use rustc_target::spec::abi::{self, Abi}; -use syntax_pos::{Span, BytePos, DUMMY_SP, FileName, hygiene::CompilerDesugaringKind}; +use syntax_pos::{Span, BytePos, DUMMY_SP, FileName}; use log::debug; use std::borrow::Cow; @@ -1126,7 +1126,6 @@ impl<'a> Parser<'a> { IsAsync::Async { closure_id: ast::DUMMY_NODE_ID, return_impl_trait_id: ast::DUMMY_NODE_ID, - arguments: Vec::new(), } } else { IsAsync::NotAsync @@ -1185,12 +1184,12 @@ impl<'a> Parser<'a> { // trait item macro. (Ident::invalid(), ast::TraitItemKind::Macro(mac), ast::Generics::default()) } else { - let (constness, unsafety, mut asyncness, abi) = self.parse_fn_front_matter()?; + let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?; let ident = self.parse_ident()?; let mut generics = self.parse_generics()?; - let mut decl = self.parse_fn_decl_with_self(|p: &mut Parser<'a>| { + let decl = self.parse_fn_decl_with_self(|p: &mut Parser<'a>| { // This is somewhat dubious; We don't want to allow // argument names to be left off if there is a // definition... @@ -1199,7 +1198,6 @@ impl<'a> Parser<'a> { p.parse_arg_general(p.span.rust_2018(), true, false) })?; generics.where_clause = self.parse_where_clause()?; - self.construct_async_arguments(&mut asyncness, &mut decl); let sig = ast::MethodSig { header: FnHeader { @@ -1563,7 +1561,7 @@ impl<'a> Parser<'a> { } }; - Ok(Arg { ty, pat, id: ast::DUMMY_NODE_ID, source: ast::ArgSource::Normal }) + Ok(Arg { ty, pat, id: ast::DUMMY_NODE_ID }) } /// Parses an argument in a lambda header (e.g., `|arg, arg|`). @@ -1581,8 +1579,7 @@ impl<'a> Parser<'a> { Ok(Arg { ty: t, pat, - id: ast::DUMMY_NODE_ID, - source: ast::ArgSource::Normal, + id: ast::DUMMY_NODE_ID }) } @@ -4213,7 +4210,6 @@ impl<'a> Parser<'a> { id: ast::DUMMY_NODE_ID, span: lo.to(hi), attrs, - source: LocalSource::Normal, })) } @@ -5244,9 +5240,13 @@ impl<'a> Parser<'a> { // FIXME(const_generics): to distinguish between idents for types and consts, // we should introduce a GenericArg::Ident in the AST and distinguish when // lowering to the HIR. For now, idents for const args are not permitted. - return Err( - self.fatal("identifiers may currently not be used for const generics") - ); + if self.token.is_keyword(kw::True) || self.token.is_keyword(kw::False) { + self.parse_literal_maybe_minus()? + } else { + return Err( + self.fatal("identifiers may currently not be used for const generics") + ); + } } else { self.parse_literal_maybe_minus()? }; @@ -5660,16 +5660,15 @@ impl<'a> Parser<'a> { /// Parses an item-position function declaration. fn parse_item_fn(&mut self, unsafety: Unsafety, - mut asyncness: Spanned, + asyncness: Spanned, constness: Spanned, abi: Abi) -> PResult<'a, ItemInfo> { let (ident, mut generics) = self.parse_fn_header()?; let allow_c_variadic = abi == Abi::C && unsafety == Unsafety::Unsafe; - let mut decl = self.parse_fn_decl(allow_c_variadic)?; + let decl = self.parse_fn_decl(allow_c_variadic)?; generics.where_clause = self.parse_where_clause()?; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; - self.construct_async_arguments(&mut asyncness, &mut decl); let header = FnHeader { unsafety, asyncness, constness, abi }; Ok((ident, ItemKind::Fn(decl, header, generics, body), Some(inner_attrs))) } @@ -5849,14 +5848,13 @@ impl<'a> Parser<'a> { Ok((Ident::invalid(), vec![], ast::Generics::default(), ast::ImplItemKind::Macro(mac))) } else { - let (constness, unsafety, mut asyncness, abi) = self.parse_fn_front_matter()?; + let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?; let ident = self.parse_ident()?; let mut generics = self.parse_generics()?; - let mut decl = self.parse_fn_decl_with_self(|p| { + let decl = self.parse_fn_decl_with_self(|p| { p.parse_arg_general(true, true, false) })?; generics.where_clause = self.parse_where_clause()?; - self.construct_async_arguments(&mut asyncness, &mut decl); *at_end = true; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; let header = ast::FnHeader { abi, unsafety, constness, asyncness }; @@ -7218,7 +7216,6 @@ impl<'a> Parser<'a> { respan(async_span, IsAsync::Async { closure_id: ast::DUMMY_NODE_ID, return_impl_trait_id: ast::DUMMY_NODE_ID, - arguments: Vec::new(), }), respan(fn_span, Constness::NotConst), Abi::Rust)?; @@ -7849,116 +7846,6 @@ impl<'a> Parser<'a> { Applicability::MaybeIncorrect, ).emit(); } - - /// When lowering a `async fn` to the HIR, we need to move all of the arguments of the function - /// into the generated closure so that they are dropped when the future is polled and not when - /// it is created. - /// - /// The arguments of the function are replaced in HIR lowering with the arguments created by - /// this function and the statements created here are inserted at the top of the closure body. - fn construct_async_arguments(&mut self, asyncness: &mut Spanned, decl: &mut FnDecl) { - // FIXME(davidtwco): This function should really live in the HIR lowering but because - // the types constructed here need to be used in parts of resolve so that the correct - // locals are considered upvars, it is currently easier for it to live here in the parser, - // where it can be constructed once. - if let IsAsync::Async { ref mut arguments, .. } = asyncness.node { - for (index, input) in decl.inputs.iter_mut().enumerate() { - let id = ast::DUMMY_NODE_ID; - let span = input.pat.span; - let desugared_span = self.sess.source_map() - .mark_span_with_reason(CompilerDesugaringKind::Async, span, None); - - // Construct a name for our temporary argument. - let name = format!("__arg{}", index); - let ident = Ident::from_str(&name).gensym(); - - // Check if this is a ident pattern, if so, we can optimize and avoid adding a - // `let = __argN;` statement, instead just adding a `let = ;` - // statement. - let (binding_mode, ident, is_simple_pattern) = match input.pat.node { - PatKind::Ident(binding_mode @ BindingMode::ByValue(_), ident, _) => { - // Simple patterns like this don't have a generated argument, but they are - // moved into the closure with a statement, so any `mut` bindings on the - // argument will be unused. This binding mode can't be removed, because - // this would affect the input to procedural macros, but they can have - // their span marked as being the result of a compiler desugaring so - // that they aren't linted against. - input.pat.span = desugared_span; - - (binding_mode, ident, true) - } - _ => (BindingMode::ByValue(Mutability::Mutable), ident, false), - }; - - // Construct an argument representing `__argN: ` to replace the argument of the - // async function if it isn't a simple pattern. - let arg = if is_simple_pattern { - None - } else { - Some(Arg { - ty: input.ty.clone(), - id, - pat: P(Pat { - id, - node: PatKind::Ident( - BindingMode::ByValue(Mutability::Immutable), ident, None, - ), - span: desugared_span, - }), - source: ArgSource::AsyncFn(input.pat.clone()), - }) - }; - - // Construct a `let __argN = __argN;` statement to insert at the top of the - // async closure. This makes sure that the argument is captured by the closure and - // that the drop order is correct. - let move_local = Local { - pat: P(Pat { - id, - node: PatKind::Ident(binding_mode, ident, None), - span: desugared_span, - }), - // We explicitly do not specify the type for this statement. When the user's - // argument type is `impl Trait` then this would require the - // `impl_trait_in_bindings` feature to also be present for that same type to - // be valid in this binding. At the time of writing (13 Mar 19), - // `impl_trait_in_bindings` is not stable. - ty: None, - init: Some(P(Expr { - id, - node: ExprKind::Path(None, ast::Path { - span, - segments: vec![PathSegment { ident, id, args: None }], - }), - span, - attrs: ThinVec::new(), - })), - id, - span, - attrs: ThinVec::new(), - source: LocalSource::AsyncFn, - }; - - // Construct a `let = __argN;` statement to insert at the top of the - // async closure if this isn't a simple pattern. - let pat_stmt = if is_simple_pattern { - None - } else { - Some(Stmt { - id, - node: StmtKind::Local(P(Local { - pat: input.pat.clone(), - ..move_local.clone() - })), - span, - }) - }; - - let move_stmt = Stmt { id, node: StmtKind::Local(P(move_local)), span }; - arguments.push(AsyncArgument { ident, arg, pat_stmt, move_stmt }); - } - } - } } pub fn emit_unclosed_delims(unclosed_delims: &mut Vec, handler: &errors::Handler) { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index cf546332c2c9d..b81dc53ef6836 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -357,7 +357,7 @@ pub fn vis_to_string(v: &ast::Visibility) -> String { } pub fn fun_to_string(decl: &ast::FnDecl, - header: &ast::FnHeader, + header: ast::FnHeader, name: ast::Ident, generics: &ast::Generics) -> String { @@ -1040,7 +1040,7 @@ impl<'a> State<'a> { match item.node { ast::ForeignItemKind::Fn(ref decl, ref generics) => { self.head("")?; - self.print_fn(decl, &ast::FnHeader::default(), + self.print_fn(decl, ast::FnHeader::default(), Some(item.ident), generics, &item.vis)?; self.end()?; // end head-ibox @@ -1170,7 +1170,7 @@ impl<'a> State<'a> { self.s.word(";")?; self.end()?; // end the outer cbox } - ast::ItemKind::Fn(ref decl, ref header, ref param_names, ref body) => { + ast::ItemKind::Fn(ref decl, header, ref param_names, ref body) => { self.head("")?; self.print_fn( decl, @@ -1522,7 +1522,7 @@ impl<'a> State<'a> { vis: &ast::Visibility) -> io::Result<()> { self.print_fn(&m.decl, - &m.header, + m.header, Some(ident), &generics, vis) @@ -2113,7 +2113,7 @@ impl<'a> State<'a> { self.bclose_(expr.span, INDENT_UNIT)?; } ast::ExprKind::Closure( - capture_clause, ref asyncness, movability, ref decl, ref body, _) => { + capture_clause, asyncness, movability, ref decl, ref body, _) => { self.print_movability(movability)?; self.print_asyncness(asyncness)?; self.print_capture_clause(capture_clause)?; @@ -2710,7 +2710,7 @@ impl<'a> State<'a> { pub fn print_fn(&mut self, decl: &ast::FnDecl, - header: &ast::FnHeader, + header: ast::FnHeader, name: Option, generics: &ast::Generics, vis: &ast::Visibility) -> io::Result<()> { @@ -2765,7 +2765,8 @@ impl<'a> State<'a> { } } - pub fn print_asyncness(&mut self, asyncness: &ast::IsAsync) -> io::Result<()> { + pub fn print_asyncness(&mut self, asyncness: ast::IsAsync) + -> io::Result<()> { if asyncness.is_async() { self.word_nbsp("async")?; } @@ -3037,7 +3038,7 @@ impl<'a> State<'a> { span: syntax_pos::DUMMY_SP, }; self.print_fn(decl, - &ast::FnHeader { unsafety, abi, ..ast::FnHeader::default() }, + ast::FnHeader { unsafety, abi, ..ast::FnHeader::default() }, name, &generics, &source_map::dummy_spanned(ast::VisibilityKind::Inherited))?; @@ -3100,7 +3101,7 @@ impl<'a> State<'a> { } pub fn print_fn_header_info(&mut self, - header: &ast::FnHeader, + header: ast::FnHeader, vis: &ast::Visibility) -> io::Result<()> { self.s.word(visibility_qualified(vis, ""))?; @@ -3109,7 +3110,7 @@ impl<'a> State<'a> { ast::Constness::Const => self.word_nbsp("const")? } - self.print_asyncness(&header.asyncness.node)?; + self.print_asyncness(header.asyncness.node)?; self.print_unsafety(header.unsafety)?; if header.abi != Abi::Rust { @@ -3158,7 +3159,7 @@ mod tests { assert_eq!( fun_to_string( &decl, - &ast::FnHeader { + ast::FnHeader { unsafety: ast::Unsafety::Normal, constness: source_map::dummy_spanned(ast::Constness::NotConst), asyncness: source_map::dummy_spanned(ast::IsAsync::NotAsync), diff --git a/src/libsyntax/source_map.rs b/src/libsyntax/source_map.rs index 4b6893b242337..a21d2df416206 100644 --- a/src/libsyntax/source_map.rs +++ b/src/libsyntax/source_map.rs @@ -935,27 +935,6 @@ impl SourceMap { None } - - /// Reuses the span but adds information like the kind of the desugaring and features that are - /// allowed inside this span. - pub fn mark_span_with_reason( - &self, - reason: hygiene::CompilerDesugaringKind, - span: Span, - allow_internal_unstable: Option>, - ) -> Span { - let mark = Mark::fresh(Mark::root()); - mark.set_expn_info(ExpnInfo { - call_site: span, - def_site: Some(span), - format: CompilerDesugaring(reason), - allow_internal_unstable, - allow_internal_unsafe: false, - local_inner_macros: false, - edition: edition::Edition::from_session(), - }); - span.with_ctxt(SyntaxContext::empty().apply_mark(mark)) - } } impl SourceMapper for SourceMap { diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 4e096d68235b5..eb516b5c7c62f 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -544,9 +544,6 @@ pub fn walk_fn_ret_ty<'a, V: Visitor<'a>>(visitor: &mut V, ret_ty: &'a FunctionR pub fn walk_fn_decl<'a, V: Visitor<'a>>(visitor: &mut V, function_declaration: &'a FnDecl) { for argument in &function_declaration.inputs { visitor.visit_pat(&argument.pat); - if let ArgSource::AsyncFn(pat) = &argument.source { - visitor.visit_pat(pat); - } visitor.visit_ty(&argument.ty) } visitor.visit_fn_ret_ty(&function_declaration.output) diff --git a/src/libsyntax_ext/deriving/debug.rs b/src/libsyntax_ext/deriving/debug.rs index dec4c2dfc3b5e..44ddbb98809b4 100644 --- a/src/libsyntax_ext/deriving/debug.rs +++ b/src/libsyntax_ext/deriving/debug.rs @@ -129,7 +129,6 @@ fn stmt_let_undescore(cx: &mut ExtCtxt<'_>, sp: Span, expr: P) -> ast id: ast::DUMMY_NODE_ID, span: sp, attrs: ThinVec::new(), - source: ast::LocalSource::Normal, }); ast::Stmt { id: ast::DUMMY_NODE_ID, diff --git a/src/test/mir-opt/generator-storage-dead-unwind.rs b/src/test/mir-opt/generator-storage-dead-unwind.rs new file mode 100644 index 0000000000000..883748a73e626 --- /dev/null +++ b/src/test/mir-opt/generator-storage-dead-unwind.rs @@ -0,0 +1,104 @@ +// Test that we generate StorageDead on unwind paths for generators. +// +// Basic block and local names can safely change, but the StorageDead statements +// should not go away. + +#![feature(generators, generator_trait)] + +struct Foo(i32); + +impl Drop for Foo { + fn drop(&mut self) {} +} + +struct Bar(i32); + +fn take(_x: T) {} + +fn main() { + let _gen = || { + let a = Foo(5); + let b = Bar(6); + yield; + take(a); + take(b); + }; +} + +// END RUST SOURCE + +// START rustc.main-{{closure}}.StateTransform.before.mir +// ... +// let _2: Foo; +// ... +// let mut _7: Foo; +// ... +// let mut _9: Bar; +// scope 1 { +// let _3: Bar; +// scope 2 { +// } +// } +// bb0: { +// StorageLive(_2); +// _2 = Foo(const 5i32,); +// StorageLive(_3); +// _3 = Bar(const 6i32,); +// ... +// _1 = suspend(move _5) -> [resume: bb2, drop: bb4]; +// } +// bb1 (cleanup): { +// resume; +// } +// bb2: { +// ... +// StorageLive(_7); +// _7 = move _2; +// _6 = const take::(move _7) -> [return: bb9, unwind: bb8]; +// } +// bb3 (cleanup): { +// StorageDead(_2); +// drop(_1) -> bb1; +// } +// bb4: { +// ... +// StorageDead(_3); +// drop(_2) -> [return: bb5, unwind: bb3]; +// } +// bb5: { +// StorageDead(_2); +// drop(_1) -> [return: bb6, unwind: bb1]; +// } +// bb6: { +// generator_drop; +// } +// bb7 (cleanup): { +// StorageDead(_3); +// StorageDead(_2); +// drop(_1) -> bb1; +// } +// bb8 (cleanup): { +// StorageDead(_7); +// goto -> bb7; +// } +// bb9: { +// StorageDead(_7); +// StorageLive(_9); +// _9 = move _3; +// _8 = const take::(move _9) -> [return: bb10, unwind: bb11]; +// } +// bb10: { +// StorageDead(_9); +// ... +// StorageDead(_3); +// StorageDead(_2); +// drop(_1) -> [return: bb12, unwind: bb1]; +// } +// bb11 (cleanup): { +// StorageDead(_9); +// goto -> bb7; +// } +// bb12: { +// return; +// } +// END rustc.main-{{closure}}.StateTransform.before.mir diff --git a/src/test/run-pass/generator/drop-and-replace.rs b/src/test/run-pass/generator/drop-and-replace.rs new file mode 100644 index 0000000000000..042e1276db5c6 --- /dev/null +++ b/src/test/run-pass/generator/drop-and-replace.rs @@ -0,0 +1,44 @@ +// Regression test for incorrect DropAndReplace behavior introduced in #60840 +// and fixed in #61373. When combined with the optimization implemented in +// #60187, this produced incorrect code for generators when a saved local was +// re-assigned. + +#![feature(generators, generator_trait)] + +use std::ops::{Generator, GeneratorState}; +use std::pin::Pin; + +#[derive(Debug, PartialEq)] +struct Foo(i32); + +impl Drop for Foo { + fn drop(&mut self) { } +} + +fn main() { + let mut a = || { + let mut x = Foo(4); + yield; + assert_eq!(x.0, 4); + + // At one point this tricked our dataflow analysis into thinking `x` was + // StorageDead after the assignment. + x = Foo(5); + assert_eq!(x.0, 5); + + { + let y = Foo(6); + yield; + assert_eq!(y.0, 6); + } + + assert_eq!(x.0, 5); + }; + + loop { + match Pin::new(&mut a).resume() { + GeneratorState::Complete(()) => break, + _ => (), + } + } +} diff --git a/src/test/ui/async-await/issues/issue-61187.rs b/src/test/ui/async-await/issues/issue-61187.rs new file mode 100644 index 0000000000000..8b939b43b8bd4 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-61187.rs @@ -0,0 +1,9 @@ +// edition:2018 +#![feature(async_await)] + +fn main() { +} + +async fn response(data: Vec) { + data.reverse(); //~ ERROR E0596 +} diff --git a/src/test/ui/async-await/issues/issue-61187.stderr b/src/test/ui/async-await/issues/issue-61187.stderr new file mode 100644 index 0000000000000..a03142263202e --- /dev/null +++ b/src/test/ui/async-await/issues/issue-61187.stderr @@ -0,0 +1,11 @@ +error[E0596]: cannot borrow `data` as mutable, as it is not declared as mutable + --> $DIR/issue-61187.rs:8:5 + | +LL | async fn response(data: Vec) { + | ---- help: consider changing this to be mutable: `mut data` +LL | data.reverse(); + | ^^^^ cannot borrow as mutable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/const-generics/condition-in-trait-const-arg.rs b/src/test/ui/const-generics/condition-in-trait-const-arg.rs new file mode 100644 index 0000000000000..091fe904826d4 --- /dev/null +++ b/src/test/ui/const-generics/condition-in-trait-const-arg.rs @@ -0,0 +1,12 @@ +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +trait IsZeroTrait{} + +impl IsZeroTrait<{0u8 == 0u8}> for () {} + +impl IsZeroTrait for ((),) {} + +fn main() {} diff --git a/src/test/ui/const-generics/condition-in-trait-const-arg.stderr b/src/test/ui/const-generics/condition-in-trait-const-arg.stderr new file mode 100644 index 0000000000000..7c85651e7082f --- /dev/null +++ b/src/test/ui/const-generics/condition-in-trait-const-arg.stderr @@ -0,0 +1,6 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/condition-in-trait-const-arg.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + diff --git a/src/test/ui/impl-trait/infinite-impl-trait-issue-38064.rs b/src/test/ui/impl-trait/issues/infinite-impl-trait-issue-38064.rs similarity index 100% rename from src/test/ui/impl-trait/infinite-impl-trait-issue-38064.rs rename to src/test/ui/impl-trait/issues/infinite-impl-trait-issue-38064.rs diff --git a/src/test/ui/impl-trait/infinite-impl-trait-issue-38064.stderr b/src/test/ui/impl-trait/issues/infinite-impl-trait-issue-38064.stderr similarity index 100% rename from src/test/ui/impl-trait/infinite-impl-trait-issue-38064.stderr rename to src/test/ui/impl-trait/issues/infinite-impl-trait-issue-38064.stderr diff --git a/src/test/ui/impl-trait/issue-21659-show-relevant-trait-impls-3.rs b/src/test/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.rs similarity index 100% rename from src/test/ui/impl-trait/issue-21659-show-relevant-trait-impls-3.rs rename to src/test/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.rs diff --git a/src/test/ui/impl-trait/issue-21659-show-relevant-trait-impls-3.stderr b/src/test/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.stderr similarity index 100% rename from src/test/ui/impl-trait/issue-21659-show-relevant-trait-impls-3.stderr rename to src/test/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.stderr diff --git a/src/test/ui/impl-trait/issue-42479.rs b/src/test/ui/impl-trait/issues/issue-42479.rs similarity index 100% rename from src/test/ui/impl-trait/issue-42479.rs rename to src/test/ui/impl-trait/issues/issue-42479.rs diff --git a/src/test/ui/impl-trait/issue-49376.rs b/src/test/ui/impl-trait/issues/issue-49376.rs similarity index 100% rename from src/test/ui/impl-trait/issue-49376.rs rename to src/test/ui/impl-trait/issues/issue-49376.rs diff --git a/src/test/ui/impl-trait/issue-52128.rs b/src/test/ui/impl-trait/issues/issue-52128.rs similarity index 100% rename from src/test/ui/impl-trait/issue-52128.rs rename to src/test/ui/impl-trait/issues/issue-52128.rs diff --git a/src/test/ui/impl-trait/issues/issue-53457.rs b/src/test/ui/impl-trait/issues/issue-53457.rs new file mode 100644 index 0000000000000..3f6a4fb278715 --- /dev/null +++ b/src/test/ui/impl-trait/issues/issue-53457.rs @@ -0,0 +1,15 @@ +// run-pass + +#![feature(existential_type)] + +existential type X: Clone; + +fn bar(f: F) -> F { + f +} + +fn foo() -> X { + bar(|x| ()) +} + +fn main() {} diff --git a/src/test/ui/impl-trait/issue-55608-captures-empty-region.rs b/src/test/ui/impl-trait/issues/issue-55608-captures-empty-region.rs similarity index 100% rename from src/test/ui/impl-trait/issue-55608-captures-empty-region.rs rename to src/test/ui/impl-trait/issues/issue-55608-captures-empty-region.rs diff --git a/src/test/ui/impl-trait/issue-57464-unexpected-regions.rs b/src/test/ui/impl-trait/issues/issue-57464-unexpected-regions.rs similarity index 100% rename from src/test/ui/impl-trait/issue-57464-unexpected-regions.rs rename to src/test/ui/impl-trait/issues/issue-57464-unexpected-regions.rs diff --git a/src/test/ui/impl-trait/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs b/src/test/ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs similarity index 100% rename from src/test/ui/impl-trait/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs rename to src/test/ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs diff --git a/src/test/ui/impl-trait/issue-57979-deeply-nested-impl-trait-in-assoc-proj.stderr b/src/test/ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.stderr similarity index 100% rename from src/test/ui/impl-trait/issue-57979-deeply-nested-impl-trait-in-assoc-proj.stderr rename to src/test/ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.stderr diff --git a/src/test/ui/impl-trait/issue-57979-impl-trait-in-path.rs b/src/test/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs similarity index 100% rename from src/test/ui/impl-trait/issue-57979-impl-trait-in-path.rs rename to src/test/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs diff --git a/src/test/ui/impl-trait/issue-57979-impl-trait-in-path.stderr b/src/test/ui/impl-trait/issues/issue-57979-impl-trait-in-path.stderr similarity index 100% rename from src/test/ui/impl-trait/issue-57979-impl-trait-in-path.stderr rename to src/test/ui/impl-trait/issues/issue-57979-impl-trait-in-path.stderr diff --git a/src/test/ui/impl-trait/issue-57979-nested-impl-trait-in-assoc-proj.rs b/src/test/ui/impl-trait/issues/issue-57979-nested-impl-trait-in-assoc-proj.rs similarity index 100% rename from src/test/ui/impl-trait/issue-57979-nested-impl-trait-in-assoc-proj.rs rename to src/test/ui/impl-trait/issues/issue-57979-nested-impl-trait-in-assoc-proj.rs diff --git a/src/test/ui/impl-trait/issue-57979-nested-impl-trait-in-assoc-proj.stderr b/src/test/ui/impl-trait/issues/issue-57979-nested-impl-trait-in-assoc-proj.stderr similarity index 100% rename from src/test/ui/impl-trait/issue-57979-nested-impl-trait-in-assoc-proj.stderr rename to src/test/ui/impl-trait/issues/issue-57979-nested-impl-trait-in-assoc-proj.stderr diff --git a/src/test/ui/impl-trait/universal-issue-48703.rs b/src/test/ui/impl-trait/issues/universal-issue-48703.rs similarity index 100% rename from src/test/ui/impl-trait/universal-issue-48703.rs rename to src/test/ui/impl-trait/issues/universal-issue-48703.rs diff --git a/src/test/ui/impl-trait/universal-issue-48703.stderr b/src/test/ui/impl-trait/issues/universal-issue-48703.stderr similarity index 100% rename from src/test/ui/impl-trait/universal-issue-48703.stderr rename to src/test/ui/impl-trait/issues/universal-issue-48703.stderr diff --git a/src/test/ui/impl-trait/universal-turbofish-in-method-issue-50950.rs b/src/test/ui/impl-trait/issues/universal-turbofish-in-method-issue-50950.rs similarity index 100% rename from src/test/ui/impl-trait/universal-turbofish-in-method-issue-50950.rs rename to src/test/ui/impl-trait/issues/universal-turbofish-in-method-issue-50950.rs diff --git a/src/test/ui/impl-trait/universal-turbofish-in-method-issue-50950.stderr b/src/test/ui/impl-trait/issues/universal-turbofish-in-method-issue-50950.stderr similarity index 100% rename from src/test/ui/impl-trait/universal-turbofish-in-method-issue-50950.stderr rename to src/test/ui/impl-trait/issues/universal-turbofish-in-method-issue-50950.stderr diff --git a/src/test/ui/issues/issue-21596.rs b/src/test/ui/issues/issue-21596.rs new file mode 100644 index 0000000000000..79f6c91d9ac97 --- /dev/null +++ b/src/test/ui/issues/issue-21596.rs @@ -0,0 +1,5 @@ +fn main() { + let x = 8u8; + let z: *const u8 = &x; + println!("{}", z.to_string()); //~ ERROR E0599 +} diff --git a/src/test/ui/issues/issue-21596.stderr b/src/test/ui/issues/issue-21596.stderr new file mode 100644 index 0000000000000..07d29f30e988a --- /dev/null +++ b/src/test/ui/issues/issue-21596.stderr @@ -0,0 +1,13 @@ +error[E0599]: no method named `to_string` found for type `*const u8` in the current scope + --> $DIR/issue-21596.rs:4:22 + | +LL | println!("{}", z.to_string()); + | ^^^^^^^^^ + | + = note: try using `<*const T>::as_ref()` to get a reference to the type behind the pointer: https://doc.rust-lang.org/std/primitive.pointer.html#method.as_ref + = note: the method `to_string` exists but the following trait bounds were not satisfied: + `*const u8 : std::string::ToString` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/nll/issue-61424.rs b/src/test/ui/nll/issue-61424.rs new file mode 100644 index 0000000000000..44c8e9f7256f5 --- /dev/null +++ b/src/test/ui/nll/issue-61424.rs @@ -0,0 +1,7 @@ +#![deny(unused_mut)] + +fn main() { + let mut x; //~ ERROR: variable does not need to be mutable + x = String::new(); + dbg!(x); +} diff --git a/src/test/ui/nll/issue-61424.stderr b/src/test/ui/nll/issue-61424.stderr new file mode 100644 index 0000000000000..ae336b2fe1c03 --- /dev/null +++ b/src/test/ui/nll/issue-61424.stderr @@ -0,0 +1,16 @@ +error: variable does not need to be mutable + --> $DIR/issue-61424.rs:4:9 + | +LL | let mut x; + | ----^ + | | + | help: remove this `mut` + | +note: lint level defined here + --> $DIR/issue-61424.rs:1:9 + | +LL | #![deny(unused_mut)] + | ^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr index 654f4285f655f..ef9e7e39df0bc 100644 --- a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr +++ b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr @@ -30,7 +30,7 @@ error[E0106]: missing lifetime specifier LL | fn foo2(_: &'_ u8, y: &'_ u8) -> &'_ u8 { y } | ^^ expected lifetime parameter | - = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `_` or `y` + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or `y` error: aborting due to 5 previous errors diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs index 837be69f7cadd..d4a6cf73bf98c 100644 --- a/src/tools/tidy/src/pal.rs +++ b/src/tools/tidy/src/pal.rs @@ -204,7 +204,7 @@ fn parse_cfgs<'a>(contents: &'a str) -> Vec<(usize, &'a str)> { succeeds_non_ident && preceeds_whitespace_and_paren }); - cfgs.map(|i| { + cfgs.flat_map(|i| { let mut depth = 0; let contents_from = &contents[i..]; for (j, byte) in contents_from.bytes().enumerate() { @@ -215,13 +215,15 @@ fn parse_cfgs<'a>(contents: &'a str) -> Vec<(usize, &'a str)> { b')' => { depth -= 1; if depth == 0 { - return (i, &contents_from[..=j]); + return Some((i, &contents_from[..=j])); } } _ => { } } } - unreachable!() + // if the parentheses are unbalanced just ignore this cfg -- it'll be caught when attempting + // to run the compiler, and there's no real reason to lint it separately here + None }).collect() }