From a3639c68595e59a17884c70d9e1881a00e789bfc Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Mon, 23 Sep 2019 19:27:17 -0400 Subject: [PATCH 01/32] Make all alt builders produce parallel-enabled compilers We're not quite ready to ship parallel compilers by default, but the alt builders are not used too much (in theory), so we believe that shipping a possibly-broken compiler there is not too problematic. --- src/ci/run.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ci/run.sh b/src/ci/run.sh index 457ba97171207..0d5ea371245e4 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -55,6 +55,9 @@ if [ "$DEPLOY$DEPLOY_ALT" = "1" ]; then if [ "$NO_LLVM_ASSERTIONS" = "1" ]; then RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-llvm-assertions" elif [ "$DEPLOY_ALT" != "" ]; then + if [ "$NO_PARALLEL_COMPILER" = "" ]; then + RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.parallel-compiler" + fi RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-assertions" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.verify-llvm-ir" fi From d2c0d1022d39d357273c90d5f2b68dd52955eddd Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Sat, 14 Sep 2019 09:22:07 -0400 Subject: [PATCH 02/32] [const-prop] Handle MIR Rvalue::Repeat --- src/librustc_mir/transform/const_prop.rs | 2 +- src/test/mir-opt/const_prop/repeat.rs | 37 ++++++++++++++++++++++++ src/test/ui/consts/const-prop-ice.rs | 1 + src/test/ui/consts/const-prop-ice.stderr | 8 ++++- 4 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 src/test/mir-opt/const_prop/repeat.rs diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 612822b6d9d34..5a57c3b9afe47 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -461,13 +461,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // if this isn't a supported operation, then return None match rvalue { - Rvalue::Repeat(..) | Rvalue::Aggregate(..) | Rvalue::NullaryOp(NullOp::Box, _) | Rvalue::Discriminant(..) => return None, Rvalue::Use(_) | Rvalue::Len(_) | + Rvalue::Repeat(..) | Rvalue::Cast(..) | Rvalue::NullaryOp(..) | Rvalue::CheckedBinaryOp(..) | diff --git a/src/test/mir-opt/const_prop/repeat.rs b/src/test/mir-opt/const_prop/repeat.rs new file mode 100644 index 0000000000000..fb091ad2a3d53 --- /dev/null +++ b/src/test/mir-opt/const_prop/repeat.rs @@ -0,0 +1,37 @@ +// compile-flags: -O + +fn main() { + let x: u32 = [42; 8][2] + 0; +} + +// END RUST SOURCE +// START rustc.main.ConstProp.before.mir +// bb0: { +// ... +// _3 = [const 42u32; 8]; +// ... +// _4 = const 2usize; +// _5 = const 8usize; +// _6 = Lt(_4, _5); +// assert(move _6, "index out of bounds: the len is move _5 but the index is _4") -> bb1; +// } +// bb1: { +// _2 = _3[_4]; +// _1 = Add(move _2, const 0u32); +// ... +// return; +// } +// END rustc.main.ConstProp.before.mir +// START rustc.main.ConstProp.after.mir +// bb0: { +// ... +// _6 = const true; +// assert(const true, "index out of bounds: the len is move _5 but the index is _4") -> bb1; +// } +// bb1: { +// _2 = const 42u32; +// _1 = Add(move _2, const 0u32); +// ... +// return; +// } +// END rustc.main.ConstProp.after.mir diff --git a/src/test/ui/consts/const-prop-ice.rs b/src/test/ui/consts/const-prop-ice.rs index 13309f978b672..48c4b7da942e4 100644 --- a/src/test/ui/consts/const-prop-ice.rs +++ b/src/test/ui/consts/const-prop-ice.rs @@ -1,3 +1,4 @@ fn main() { [0; 3][3u64 as usize]; //~ ERROR the len is 3 but the index is 3 + //~| ERROR this expression will panic at runtime } diff --git a/src/test/ui/consts/const-prop-ice.stderr b/src/test/ui/consts/const-prop-ice.stderr index 4b3880198bf2d..8ecc6f4bc6b12 100644 --- a/src/test/ui/consts/const-prop-ice.stderr +++ b/src/test/ui/consts/const-prop-ice.stderr @@ -6,5 +6,11 @@ LL | [0; 3][3u64 as usize]; | = note: `#[deny(const_err)]` on by default -error: aborting due to previous error +error: this expression will panic at runtime + --> $DIR/const-prop-ice.rs:2:5 + | +LL | [0; 3][3u64 as usize]; + | ^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the len is 3 but the index is 3 + +error: aborting due to 2 previous errors From f2904674e8d0dbb6f7b02ae74aa81d930a0e8617 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 30 Sep 2019 00:20:03 +0200 Subject: [PATCH 03/32] syntax: cleanup method parsing. --- src/libsyntax/parse/diagnostics.rs | 2 +- src/libsyntax/parse/parser/item.rs | 138 ++++++++++++++--------------- 2 files changed, 66 insertions(+), 74 deletions(-) diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs index ec5d00e0952d7..e8d7b7663ed52 100644 --- a/src/libsyntax/parse/diagnostics.rs +++ b/src/libsyntax/parse/diagnostics.rs @@ -1180,7 +1180,7 @@ impl<'a> Parser<'a> { } } - crate fn expected_semi_or_open_brace(&mut self) -> PResult<'a, ast::TraitItem> { + crate fn expected_semi_or_open_brace(&mut self) -> PResult<'a, T> { let token_str = self.this_token_descr(); let mut err = self.fatal(&format!("expected `;` or `{{`, found {}", token_str)); err.span_label(self.token.span, "expected `;` or `{`"); diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index 64c494416ff34..69fbb343ff3b6 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -7,7 +7,7 @@ use crate::ast::{ Item, ItemKind, ImplItem, TraitItem, TraitItemKind, UseTree, UseTreeKind, PathSegment, IsAuto, Constness, IsAsync, Unsafety, Defaultness, - Visibility, VisibilityKind, Mutability, FnDecl, FnHeader, + Visibility, VisibilityKind, Mutability, FnDecl, FnHeader, MethodSig, Block, ForeignItem, ForeignItemKind, Ty, TyKind, Generics, GenericBounds, TraitRef, EnumDef, VariantData, StructField, AnonConst, @@ -848,29 +848,38 @@ impl<'a> Parser<'a> { } /// Parses a method or a macro invocation in a trait impl. - fn parse_impl_method(&mut self, vis: &Visibility, at_end: &mut bool) - -> PResult<'a, (Ident, Vec, Generics, ast::ImplItemKind)> { + fn parse_impl_method( + &mut self, + vis: &Visibility, + at_end: &mut bool + ) -> PResult<'a, (Ident, Vec, Generics, ast::ImplItemKind)> { // FIXME: code copied from `parse_macro_use_or_failure` -- use abstraction! if let Some(mac) = self.parse_assoc_macro_invoc("impl", Some(vis), at_end)? { // method macro - Ok((Ident::invalid(), vec![], Generics::default(), - ast::ImplItemKind::Macro(mac))) + Ok((Ident::invalid(), vec![], Generics::default(), ast::ImplItemKind::Macro(mac))) } else { - let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?; - let ident = self.parse_ident()?; - let mut generics = self.parse_generics()?; - let decl = self.parse_fn_decl_with_self(|_| true)?; - generics.where_clause = self.parse_where_clause()?; + let (ident, sig, generics) = self.parse_method_sig(|_| true)?; *at_end = true; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; - let header = ast::FnHeader { abi, unsafety, constness, asyncness }; - Ok((ident, inner_attrs, generics, ast::ImplItemKind::Method( - ast::MethodSig { header, decl }, - body - ))) + Ok((ident, inner_attrs, generics, ast::ImplItemKind::Method(sig, body))) } } + /// Parse the "signature", including the identifier, parameters, and generics + /// of a method. The body is not parsed as that differs between `trait`s and `impl`s. + fn parse_method_sig( + &mut self, + is_name_required: impl Copy + Fn(&token::Token) -> bool, + ) -> PResult<'a, (Ident, MethodSig, Generics)> { + let header = self.parse_fn_front_matter()?; + let ident = self.parse_ident()?; + let mut generics = self.parse_generics()?; + let decl = self.parse_fn_decl_with_self(is_name_required)?; + let sig = MethodSig { header, decl }; + generics.where_clause = self.parse_where_clause()?; + Ok((ident, sig, generics)) + } + /// Parses all the "front matter" for a `fn` declaration, up to /// and including the `fn` keyword: /// @@ -879,14 +888,7 @@ impl<'a> Parser<'a> { /// - `const unsafe fn` /// - `extern fn` /// - etc. - fn parse_fn_front_matter(&mut self) - -> PResult<'a, ( - Spanned, - Unsafety, - Spanned, - Abi - )> - { + fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> { let is_const_fn = self.eat_keyword(kw::Const); let const_span = self.prev_span; let asyncness = self.parse_asyncness(); @@ -911,7 +913,7 @@ impl<'a> Parser<'a> { // account for this. if !self.expect_one_of(&[], &[])? { unreachable!() } } - Ok((constness, unsafety, asyncness, abi)) + Ok(FnHeader { constness, unsafety, asyncness, abi }) } /// Parses `trait Foo { ... }` or `trait Foo = Bar;`. @@ -1025,59 +1027,12 @@ impl<'a> Parser<'a> { // trait item macro. (Ident::invalid(), ast::TraitItemKind::Macro(mac), Generics::default()) } else { - let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?; - - let ident = self.parse_ident()?; - let mut generics = self.parse_generics()?; - // This is somewhat dubious; We don't want to allow // argument names to be left off if there is a definition... // // We don't allow argument names to be left off in edition 2018. - let decl = self.parse_fn_decl_with_self(|t| t.span.rust_2018())?; - generics.where_clause = self.parse_where_clause()?; - - let sig = ast::MethodSig { - header: FnHeader { - unsafety, - constness, - abi, - asyncness, - }, - decl, - }; - - let body = match self.token.kind { - token::Semi => { - self.bump(); - *at_end = true; - debug!("parse_trait_methods(): parsing required method"); - None - } - token::OpenDelim(token::Brace) => { - debug!("parse_trait_methods(): parsing provided method"); - *at_end = true; - let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; - attrs.extend(inner_attrs.iter().cloned()); - Some(body) - } - token::Interpolated(ref nt) => { - match **nt { - token::NtBlock(..) => { - *at_end = true; - let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; - attrs.extend(inner_attrs.iter().cloned()); - Some(body) - } - _ => { - return self.expected_semi_or_open_brace(); - } - } - } - _ => { - return self.expected_semi_or_open_brace(); - } - }; + let (ident, sig, generics) = self.parse_method_sig(|t| t.span.rust_2018())?; + let body = self.parse_trait_method_body(at_end, &mut attrs)?; (ident, ast::TraitItemKind::Method(sig, body), generics) }; @@ -1092,6 +1047,43 @@ impl<'a> Parser<'a> { }) } + /// Parse the "body" of a method in a trait item definition. + /// This can either be `;` when there's no body, + /// or e.g. a block when the method is a provided one. + fn parse_trait_method_body( + &mut self, + at_end: &mut bool, + attrs: &mut Vec, + ) -> PResult<'a, Option>> { + Ok(match self.token.kind { + token::Semi => { + debug!("parse_trait_method_body(): parsing required method"); + self.bump(); + *at_end = true; + None + } + token::OpenDelim(token::Brace) => { + debug!("parse_trait_method_body(): parsing provided method"); + *at_end = true; + let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; + attrs.extend(inner_attrs.iter().cloned()); + Some(body) + } + token::Interpolated(ref nt) => { + match **nt { + token::NtBlock(..) => { + *at_end = true; + let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; + attrs.extend(inner_attrs.iter().cloned()); + Some(body) + } + _ => return self.expected_semi_or_open_brace(), + } + } + _ => return self.expected_semi_or_open_brace(), + }) + } + /// Parses the following grammar: /// /// TraitItemAssocTy = Ident ["<"...">"] [":" [GenericBounds]] ["where" ...] ["=" Ty] From 378cc98cd9dce625331503e8e439ce25671a4d3e Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 30 Sep 2019 01:19:37 +0200 Subject: [PATCH 04/32] syntax: `is_named_argument` -> `is_named_param`. --- src/libsyntax/parse/parser.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 2fb6f197dad7c..c183160168f84 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -954,7 +954,7 @@ impl<'a> Parser<'a> { } } - fn is_named_argument(&self) -> bool { + fn is_named_param(&self) -> bool { let offset = match self.token.kind { token::Interpolated(ref nt) => match **nt { token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon), @@ -993,7 +993,7 @@ impl<'a> Parser<'a> { } let is_name_required = is_name_required(&self.token); - let (pat, ty) = if is_name_required || self.is_named_argument() { + let (pat, ty) = if is_name_required || self.is_named_param() { debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required); let pat = self.parse_fn_param_pat()?; From 4fa9c3bca3b0b3fe7d33648bc6bc69df57deb7db Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 30 Sep 2019 01:21:42 +0200 Subject: [PATCH 05/32] syntax refactor `parse_fn_params` --- src/libsyntax/parse/parser.rs | 57 ++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index c183160168f84..a6694cea73138 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1031,13 +1031,10 @@ impl<'a> Parser<'a> { let pat = self.mk_pat_ident(ty.span, bm, ident); (pat, ty) } + // If this is a C-variadic argument and we hit an error, return the error. + Err(err) if self.token == token::DotDotDot => return Err(err), + // Recover from attempting to parse the argument as a type without pattern. Err(mut err) => { - // If this is a C-variadic argument and we hit an error, return the - // error. - if self.token == token::DotDotDot { - return Err(err); - } - // Recover from attempting to parse the argument as a type without pattern. err.cancel(); mem::replace(self, parser_snapshot_before_ty); self.recover_arg_parse()? @@ -1200,42 +1197,44 @@ impl<'a> Parser<'a> { } - fn parse_fn_params(&mut self, named_params: bool, allow_c_variadic: bool) - -> PResult<'a, Vec> { + fn parse_fn_params( + &mut self, + named_params: bool, + allow_c_variadic: bool, + ) -> PResult<'a, Vec> { let sp = self.token.span; + let do_not_enforce_named_params_for_c_variadic = |token: &token::Token| { + match token.kind { + token::DotDotDot => false, + _ => named_params, + } + }; let mut c_variadic = false; - let (params, _): (Vec>, _) = self.parse_paren_comma_seq(|p| { - let do_not_enforce_named_arguments_for_c_variadic = - |token: &token::Token| -> bool { - if token == &token::DotDotDot { - false - } else { - named_params - } - }; + let (params, _) = self.parse_paren_comma_seq(|p| { match p.parse_param_general( false, false, allow_c_variadic, - do_not_enforce_named_arguments_for_c_variadic + do_not_enforce_named_params_for_c_variadic, ) { - Ok(param) => { + Ok(param) => Ok( if let TyKind::CVarArgs = param.ty.kind { c_variadic = true; if p.token != token::CloseDelim(token::Paren) { - let span = p.token.span; - p.span_err(span, - "`...` must be the last argument of a C-variadic function"); + p.span_err( + p.token.span, + "`...` must be the last argument of a C-variadic function", + ); // FIXME(eddyb) this should probably still push `CVarArgs`. // Maybe AST validation/HIR lowering should emit the above error? - Ok(None) + None } else { - Ok(Some(param)) + Some(param) } } else { - Ok(Some(param)) + Some(param) } - }, + ), Err(mut e) => { e.emit(); let lo = p.prev_span; @@ -1251,8 +1250,10 @@ impl<'a> Parser<'a> { let params: Vec<_> = params.into_iter().filter_map(|x| x).collect(); if c_variadic && params.len() <= 1 { - self.span_err(sp, - "C-variadic function must be declared with at least one named argument"); + self.span_err( + sp, + "C-variadic function must be declared with at least one named argument", + ); } Ok(params) From 40dc9da44c146cb959a34700426d29d7037cfee6 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 30 Sep 2019 01:49:22 +0200 Subject: [PATCH 06/32] syntax refactor `parse_self_param` (1) --- src/libsyntax/parse/parser.rs | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a6694cea73138..93de890b222e2 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1259,6 +1259,11 @@ impl<'a> Parser<'a> { Ok(params) } + fn is_isolated_self(&self, n: usize) -> bool { + self.is_keyword_ahead(n, &[kw::SelfLower]) + && self.look_ahead(n + 1, |t| t != &token::ModSep) + } + /// Returns the parsed optional self parameter and whether a self shortcut was used. /// /// See `parse_self_param_with_attrs` to collect attributes. @@ -1269,10 +1274,6 @@ impl<'a> Parser<'a> { { let span = this.token.span; this.bump(); Ident::new(name, span) } _ => unreachable!() }; - let isolated_self = |this: &mut Self, n| { - this.look_ahead(n, |t| t.is_keyword(kw::SelfLower)) && - this.look_ahead(n + 1, |t| t != &token::ModSep) - }; // Parse optional `self` parameter of a method. // Only a limited set of initial token sequences is considered `self` parameters; anything @@ -1285,22 +1286,22 @@ impl<'a> Parser<'a> { // `&'lt self` // `&'lt mut self` // `¬_self` - (if isolated_self(self, 1) { + (if self.is_isolated_self(1) { self.bump(); SelfKind::Region(None, Mutability::Immutable) } else if self.is_keyword_ahead(1, &[kw::Mut]) && - isolated_self(self, 2) { + self.is_isolated_self(2) { self.bump(); self.bump(); SelfKind::Region(None, Mutability::Mutable) } else if self.look_ahead(1, |t| t.is_lifetime()) && - isolated_self(self, 2) { + self.is_isolated_self(2) { self.bump(); let lt = self.expect_lifetime(); SelfKind::Region(Some(lt), Mutability::Immutable) } else if self.look_ahead(1, |t| t.is_lifetime()) && self.is_keyword_ahead(2, &[kw::Mut]) && - isolated_self(self, 3) { + self.is_isolated_self(3) { self.bump(); let lt = self.expect_lifetime(); self.bump(); @@ -1316,14 +1317,14 @@ impl<'a> Parser<'a> { // `*not_self` // Emit special error for `self` cases. let msg = "cannot pass `self` by raw pointer"; - (if isolated_self(self, 1) { + (if self.is_isolated_self(1) { self.bump(); self.struct_span_err(self.token.span, msg) .span_label(self.token.span, msg) .emit(); SelfKind::Value(Mutability::Immutable) } else if self.look_ahead(1, |t| t.is_mutability()) && - isolated_self(self, 2) { + self.is_isolated_self(2) { self.bump(); self.bump(); self.struct_span_err(self.token.span, msg) @@ -1335,7 +1336,7 @@ impl<'a> Parser<'a> { }, expect_ident(self), self.prev_span) } token::Ident(..) => { - if isolated_self(self, 0) { + if self.is_isolated_self(0) { // `self` // `self: TYPE` let eself_ident = expect_ident(self); @@ -1347,7 +1348,7 @@ impl<'a> Parser<'a> { SelfKind::Value(Mutability::Immutable) }, eself_ident, eself_hi) } else if self.token.is_keyword(kw::Mut) && - isolated_self(self, 1) { + self.is_isolated_self(1) { // `mut self` // `mut self: TYPE` self.bump(); From f688f8aedffcd802012b355c182dafbdf5e819f5 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 30 Sep 2019 01:57:50 +0200 Subject: [PATCH 07/32] syntax refactor `parse_self_param` (2) --- src/libsyntax/parse/parser.rs | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 93de890b222e2..70a7b4b01d8a0 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1264,17 +1264,22 @@ impl<'a> Parser<'a> { && self.look_ahead(n + 1, |t| t != &token::ModSep) } + fn expect_self_ident(&mut self) -> Ident { + match self.token.kind { + // Preserve hygienic context. + token::Ident(name, _) => { + let span = self.token.span; + self.bump(); + Ident::new(name, span) + } + _ => unreachable!(), + } + } + /// Returns the parsed optional self parameter and whether a self shortcut was used. /// /// See `parse_self_param_with_attrs` to collect attributes. fn parse_self_param(&mut self) -> PResult<'a, Option> { - let expect_ident = |this: &mut Self| match this.token.kind { - // Preserve hygienic context. - token::Ident(name, _) => - { let span = this.token.span; this.bump(); Ident::new(name, span) } - _ => unreachable!() - }; - // Parse optional `self` parameter of a method. // Only a limited set of initial token sequences is considered `self` parameters; anything // else is parsed as a normal function parameter list, so some lookahead is required. @@ -1308,7 +1313,7 @@ impl<'a> Parser<'a> { SelfKind::Region(Some(lt), Mutability::Mutable) } else { return Ok(None); - }, expect_ident(self), self.prev_span) + }, self.expect_self_ident(), self.prev_span) } token::BinOp(token::Star) => { // `*self` @@ -1333,13 +1338,13 @@ impl<'a> Parser<'a> { SelfKind::Value(Mutability::Immutable) } else { return Ok(None); - }, expect_ident(self), self.prev_span) + }, self.expect_self_ident(), self.prev_span) } token::Ident(..) => { if self.is_isolated_self(0) { // `self` // `self: TYPE` - let eself_ident = expect_ident(self); + let eself_ident = self.expect_self_ident(); let eself_hi = self.prev_span; (if self.eat(&token::Colon) { let ty = self.parse_ty()?; @@ -1352,7 +1357,7 @@ impl<'a> Parser<'a> { // `mut self` // `mut self: TYPE` self.bump(); - let eself_ident = expect_ident(self); + let eself_ident = self.expect_self_ident(); let eself_hi = self.prev_span; (if self.eat(&token::Colon) { let ty = self.parse_ty()?; From ac454e9af9389bb41a06ab620599771dcb2e59b6 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 30 Sep 2019 02:06:55 +0200 Subject: [PATCH 08/32] syntax refactor `parse_self_param` (3) --- src/libsyntax/parse/parser.rs | 48 +++++++++++++++-------------------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 70a7b4b01d8a0..ae4f181a11940 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1276,6 +1276,18 @@ impl<'a> Parser<'a> { } } + /// Parse `self` or `self: TYPE`. We already know the current token is `self`. + fn parse_self_possibly_typed(&mut self, m: Mutability) -> PResult<'a, (SelfKind, Ident, Span)> { + let eself_ident = self.expect_self_ident(); + let eself_hi = self.prev_span; + let eself = if self.eat(&token::Colon) { + SelfKind::Explicit(self.parse_ty()?, m) + } else { + SelfKind::Value(m) + }; + Ok((eself, eself_ident, eself_hi)) + } + /// Returns the parsed optional self parameter and whether a self shortcut was used. /// /// See `parse_self_param_with_attrs` to collect attributes. @@ -1340,34 +1352,14 @@ impl<'a> Parser<'a> { return Ok(None); }, self.expect_self_ident(), self.prev_span) } - token::Ident(..) => { - if self.is_isolated_self(0) { - // `self` - // `self: TYPE` - let eself_ident = self.expect_self_ident(); - let eself_hi = self.prev_span; - (if self.eat(&token::Colon) { - let ty = self.parse_ty()?; - SelfKind::Explicit(ty, Mutability::Immutable) - } else { - SelfKind::Value(Mutability::Immutable) - }, eself_ident, eself_hi) - } else if self.token.is_keyword(kw::Mut) && - self.is_isolated_self(1) { - // `mut self` - // `mut self: TYPE` - self.bump(); - let eself_ident = self.expect_self_ident(); - let eself_hi = self.prev_span; - (if self.eat(&token::Colon) { - let ty = self.parse_ty()?; - SelfKind::Explicit(ty, Mutability::Mutable) - } else { - SelfKind::Value(Mutability::Mutable) - }, eself_ident, eself_hi) - } else { - return Ok(None); - } + // `self` and `self: TYPE` + token::Ident(..) if self.is_isolated_self(0) => { + self.parse_self_possibly_typed(Mutability::Immutable)? + } + // `mut self` and `mut self: TYPE` + token::Ident(..) if self.token.is_keyword(kw::Mut) && self.is_isolated_self(1) => { + self.bump(); + self.parse_self_possibly_typed(Mutability::Mutable)? } _ => return Ok(None), }; From 4306d0037e961825abc08bfa39af0b64d1ed52aa Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 30 Sep 2019 02:36:08 +0200 Subject: [PATCH 09/32] syntax refactor `parse_self_param` (4) --- src/libsyntax/parse/parser.rs | 59 +++++++++++++++++++------------- src/libsyntax/parse/parser/ty.rs | 8 ++--- 2 files changed, 37 insertions(+), 30 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index ae4f181a11940..fd6ffb800739d 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1063,6 +1063,17 @@ impl<'a> Parser<'a> { } } + /// Possibly parses mutability (`const` or `mut`). + fn parse_const_or_mut(&mut self) -> Option { + if self.eat_keyword(kw::Mut) { + Some(Mutability::Mutable) + } else if self.eat_keyword(kw::Const) { + Some(Mutability::Immutable) + } else { + None + } + } + fn parse_field_name(&mut self) -> PResult<'a, Ident> { if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) = self.token.kind { @@ -1276,6 +1287,17 @@ impl<'a> Parser<'a> { } } + /// Recover for the grammar `*self`, `*const self`, and `*mut self`. + fn recover_self_ptr(&mut self) -> PResult<'a, (ast::SelfKind, Ident, Span)> { + let msg = "cannot pass `self` by raw pointer"; + let span = self.token.span; + self.struct_span_err(span, msg) + .span_label(span, msg) + .emit(); + + Ok((SelfKind::Value(Mutability::Immutable), self.expect_self_ident(), self.prev_span)) + } + /// Parse `self` or `self: TYPE`. We already know the current token is `self`. fn parse_self_possibly_typed(&mut self, m: Mutability) -> PResult<'a, (SelfKind, Ident, Span)> { let eself_ident = self.expect_self_ident(); @@ -1327,30 +1349,19 @@ impl<'a> Parser<'a> { return Ok(None); }, self.expect_self_ident(), self.prev_span) } - token::BinOp(token::Star) => { - // `*self` - // `*const self` - // `*mut self` - // `*not_self` - // Emit special error for `self` cases. - let msg = "cannot pass `self` by raw pointer"; - (if self.is_isolated_self(1) { - self.bump(); - self.struct_span_err(self.token.span, msg) - .span_label(self.token.span, msg) - .emit(); - SelfKind::Value(Mutability::Immutable) - } else if self.look_ahead(1, |t| t.is_mutability()) && - self.is_isolated_self(2) { - self.bump(); - self.bump(); - self.struct_span_err(self.token.span, msg) - .span_label(self.token.span, msg) - .emit(); - SelfKind::Value(Mutability::Immutable) - } else { - return Ok(None); - }, self.expect_self_ident(), self.prev_span) + // `*self` + token::BinOp(token::Star) if self.is_isolated_self(1) => { + self.bump(); + self.recover_self_ptr()? + } + // `*mut self` and `*const self` + token::BinOp(token::Star) if + self.look_ahead(1, |t| t.is_mutability()) + && self.is_isolated_self(2) => + { + self.bump(); + self.bump(); + self.recover_self_ptr()? } // `self` and `self: TYPE` token::Ident(..) if self.is_isolated_self(0) => { diff --git a/src/libsyntax/parse/parser/ty.rs b/src/libsyntax/parse/parser/ty.rs index c52d3733b5e0a..41ee2a1599d74 100644 --- a/src/libsyntax/parse/parser/ty.rs +++ b/src/libsyntax/parse/parser/ty.rs @@ -231,11 +231,7 @@ impl<'a> Parser<'a> { } fn parse_ptr(&mut self) -> PResult<'a, MutTy> { - let mutbl = if self.eat_keyword(kw::Mut) { - Mutability::Mutable - } else if self.eat_keyword(kw::Const) { - Mutability::Immutable - } else { + let mutbl = self.parse_const_or_mut().unwrap_or_else(|| { let span = self.prev_span; let msg = "expected mut or const in raw pointer type"; self.struct_span_err(span, msg) @@ -243,7 +239,7 @@ impl<'a> Parser<'a> { .help("use `*mut T` or `*const T` as appropriate") .emit(); Mutability::Immutable - }; + }); let t = self.parse_ty_no_plus()?; Ok(MutTy { ty: t, mutbl }) } From 0492302dbdef106956545b3faaa4b9ee54d99526 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 30 Sep 2019 03:29:41 +0200 Subject: [PATCH 10/32] syntax refactor `parse_self_param` (5) --- src/libsyntax/parse/parser.rs | 43 +++++++++++++++++------------------ 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index fd6ffb800739d..5ba1d1a9f0323 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1197,15 +1197,12 @@ impl<'a> Parser<'a> { /// Evaluates the closure with restrictions in place. /// /// Afters the closure is evaluated, restrictions are reset. - fn with_res(&mut self, r: Restrictions, f: F) -> T - where F: FnOnce(&mut Self) -> T - { + fn with_res(&mut self, res: Restrictions, f: impl FnOnce(&mut Self) -> T) -> T { let old = self.restrictions; - self.restrictions = r; - let r = f(self); + self.restrictions = res; + let res = f(self); self.restrictions = old; - return r; - + res } fn parse_fn_params( @@ -1275,6 +1272,11 @@ impl<'a> Parser<'a> { && self.look_ahead(n + 1, |t| t != &token::ModSep) } + fn is_isolated_mut_self(&self, n: usize) -> bool { + self.is_keyword_ahead(n, &[kw::Mut]) + && self.is_isolated_self(n + 1) + } + fn expect_self_ident(&mut self) -> Ident { match self.token.kind { // Preserve hygienic context. @@ -1320,34 +1322,31 @@ impl<'a> Parser<'a> { let eself_lo = self.token.span; let (eself, eself_ident, eself_hi) = match self.token.kind { token::BinOp(token::And) => { - // `&self` - // `&mut self` - // `&'lt self` - // `&'lt mut self` - // `¬_self` - (if self.is_isolated_self(1) { + let eself = if self.is_isolated_self(1) { + // `&self` self.bump(); SelfKind::Region(None, Mutability::Immutable) - } else if self.is_keyword_ahead(1, &[kw::Mut]) && - self.is_isolated_self(2) { + } else if self.is_isolated_mut_self(1) { + // `&mut self` self.bump(); self.bump(); SelfKind::Region(None, Mutability::Mutable) - } else if self.look_ahead(1, |t| t.is_lifetime()) && - self.is_isolated_self(2) { + } else if self.look_ahead(1, |t| t.is_lifetime()) && self.is_isolated_self(2) { + // `&'lt self` self.bump(); let lt = self.expect_lifetime(); SelfKind::Region(Some(lt), Mutability::Immutable) - } else if self.look_ahead(1, |t| t.is_lifetime()) && - self.is_keyword_ahead(2, &[kw::Mut]) && - self.is_isolated_self(3) { + } else if self.look_ahead(1, |t| t.is_lifetime()) && self.is_isolated_mut_self(2) { + // `&'lt mut self` self.bump(); let lt = self.expect_lifetime(); self.bump(); SelfKind::Region(Some(lt), Mutability::Mutable) } else { + // `¬_self` return Ok(None); - }, self.expect_self_ident(), self.prev_span) + }; + (eself, self.expect_self_ident(), self.prev_span) } // `*self` token::BinOp(token::Star) if self.is_isolated_self(1) => { @@ -1368,7 +1367,7 @@ impl<'a> Parser<'a> { self.parse_self_possibly_typed(Mutability::Immutable)? } // `mut self` and `mut self: TYPE` - token::Ident(..) if self.token.is_keyword(kw::Mut) && self.is_isolated_self(1) => { + token::Ident(..) if self.is_isolated_mut_self(0) => { self.bump(); self.parse_self_possibly_typed(Mutability::Mutable)? } From 347deac455c5365e6e74de3ca44b83ed77de41f3 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 30 Sep 2019 05:32:46 +0200 Subject: [PATCH 11/32] syntax: reorder param parsing to make more sense. --- src/libsyntax/parse/parser.rs | 306 +++++++++++++++++----------------- 1 file changed, 153 insertions(+), 153 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 5ba1d1a9f0323..cbeaab5a4d328 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -954,106 +954,6 @@ impl<'a> Parser<'a> { } } - fn is_named_param(&self) -> bool { - let offset = match self.token.kind { - token::Interpolated(ref nt) => match **nt { - token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon), - _ => 0, - } - token::BinOp(token::And) | token::AndAnd => 1, - _ if self.token.is_keyword(kw::Mut) => 1, - _ => 0, - }; - - self.look_ahead(offset, |t| t.is_ident()) && - self.look_ahead(offset + 1, |t| t == &token::Colon) - } - - /// Skips unexpected attributes and doc comments in this position and emits an appropriate - /// error. - /// This version of parse param doesn't necessarily require identifier names. - fn parse_param_general( - &mut self, - is_self_allowed: bool, - is_trait_item: bool, - allow_c_variadic: bool, - is_name_required: impl Fn(&token::Token) -> bool, - ) -> PResult<'a, Param> { - let lo = self.token.span; - let attrs = self.parse_outer_attributes()?; - - // Possibly parse `self`. Recover if we parsed it and it wasn't allowed here. - if let Some(mut param) = self.parse_self_param()? { - param.attrs = attrs.into(); - return if is_self_allowed { - Ok(param) - } else { - self.recover_bad_self_param(param, is_trait_item) - }; - } - - let is_name_required = is_name_required(&self.token); - let (pat, ty) = if is_name_required || self.is_named_param() { - debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required); - - let pat = self.parse_fn_param_pat()?; - if let Err(mut err) = self.expect(&token::Colon) { - if let Some(ident) = self.parameter_without_type( - &mut err, - pat, - is_name_required, - is_trait_item, - ) { - err.emit(); - return Ok(dummy_arg(ident)); - } else { - return Err(err); - } - } - - self.eat_incorrect_doc_comment_for_param_type(); - (pat, self.parse_ty_common(true, true, allow_c_variadic)?) - } else { - debug!("parse_param_general ident_to_pat"); - let parser_snapshot_before_ty = self.clone(); - self.eat_incorrect_doc_comment_for_param_type(); - let mut ty = self.parse_ty_common(true, true, allow_c_variadic); - if ty.is_ok() && self.token != token::Comma && - self.token != token::CloseDelim(token::Paren) { - // This wasn't actually a type, but a pattern looking like a type, - // so we are going to rollback and re-parse for recovery. - ty = self.unexpected(); - } - match ty { - Ok(ty) => { - let ident = Ident::new(kw::Invalid, self.prev_span); - let bm = BindingMode::ByValue(Mutability::Immutable); - let pat = self.mk_pat_ident(ty.span, bm, ident); - (pat, ty) - } - // If this is a C-variadic argument and we hit an error, return the error. - Err(err) if self.token == token::DotDotDot => return Err(err), - // Recover from attempting to parse the argument as a type without pattern. - Err(mut err) => { - err.cancel(); - mem::replace(self, parser_snapshot_before_ty); - self.recover_arg_parse()? - } - } - }; - - let span = lo.to(self.token.span); - - Ok(Param { - attrs: attrs.into(), - id: ast::DUMMY_NODE_ID, - is_placeholder: false, - pat, - span, - ty, - }) - } - /// Parses mutability (`mut` or nothing). fn parse_mutability(&mut self) -> Mutability { if self.eat_keyword(kw::Mut) { @@ -1267,49 +1167,112 @@ impl<'a> Parser<'a> { Ok(params) } - fn is_isolated_self(&self, n: usize) -> bool { - self.is_keyword_ahead(n, &[kw::SelfLower]) - && self.look_ahead(n + 1, |t| t != &token::ModSep) - } + /// Parses the parameter list and result type of a function that may have a `self` parameter. + fn parse_fn_decl_with_self( + &mut self, + is_name_required: impl Copy + Fn(&token::Token) -> bool, + ) -> PResult<'a, P> { + // Parse the arguments, starting out with `self` being allowed... + let mut is_self_allowed = true; + let (mut inputs, _): (Vec<_>, _) = self.parse_paren_comma_seq(|p| { + let res = p.parse_param_general(is_self_allowed, true, false, is_name_required); + // ...but now that we've parsed the first argument, `self` is no longer allowed. + is_self_allowed = false; + res + })?; - fn is_isolated_mut_self(&self, n: usize) -> bool { - self.is_keyword_ahead(n, &[kw::Mut]) - && self.is_isolated_self(n + 1) + // Replace duplicated recovered params with `_` pattern to avoid unecessary errors. + self.deduplicate_recovered_params_names(&mut inputs); + + Ok(P(FnDecl { + inputs, + output: self.parse_ret_ty(true)?, + })) } - fn expect_self_ident(&mut self) -> Ident { - match self.token.kind { - // Preserve hygienic context. - token::Ident(name, _) => { - let span = self.token.span; - self.bump(); - Ident::new(name, span) - } - _ => unreachable!(), + /// Skips unexpected attributes and doc comments in this position and emits an appropriate + /// error. + /// This version of parse param doesn't necessarily require identifier names. + fn parse_param_general( + &mut self, + is_self_allowed: bool, + is_trait_item: bool, + allow_c_variadic: bool, + is_name_required: impl Fn(&token::Token) -> bool, + ) -> PResult<'a, Param> { + let lo = self.token.span; + let attrs = self.parse_outer_attributes()?; + + // Possibly parse `self`. Recover if we parsed it and it wasn't allowed here. + if let Some(mut param) = self.parse_self_param()? { + param.attrs = attrs.into(); + return if is_self_allowed { + Ok(param) + } else { + self.recover_bad_self_param(param, is_trait_item) + }; } - } - /// Recover for the grammar `*self`, `*const self`, and `*mut self`. - fn recover_self_ptr(&mut self) -> PResult<'a, (ast::SelfKind, Ident, Span)> { - let msg = "cannot pass `self` by raw pointer"; - let span = self.token.span; - self.struct_span_err(span, msg) - .span_label(span, msg) - .emit(); + let is_name_required = is_name_required(&self.token); + let (pat, ty) = if is_name_required || self.is_named_param() { + debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required); - Ok((SelfKind::Value(Mutability::Immutable), self.expect_self_ident(), self.prev_span)) - } + let pat = self.parse_fn_param_pat()?; + if let Err(mut err) = self.expect(&token::Colon) { + if let Some(ident) = self.parameter_without_type( + &mut err, + pat, + is_name_required, + is_trait_item, + ) { + err.emit(); + return Ok(dummy_arg(ident)); + } else { + return Err(err); + } + } - /// Parse `self` or `self: TYPE`. We already know the current token is `self`. - fn parse_self_possibly_typed(&mut self, m: Mutability) -> PResult<'a, (SelfKind, Ident, Span)> { - let eself_ident = self.expect_self_ident(); - let eself_hi = self.prev_span; - let eself = if self.eat(&token::Colon) { - SelfKind::Explicit(self.parse_ty()?, m) + self.eat_incorrect_doc_comment_for_param_type(); + (pat, self.parse_ty_common(true, true, allow_c_variadic)?) } else { - SelfKind::Value(m) + debug!("parse_param_general ident_to_pat"); + let parser_snapshot_before_ty = self.clone(); + self.eat_incorrect_doc_comment_for_param_type(); + let mut ty = self.parse_ty_common(true, true, allow_c_variadic); + if ty.is_ok() && self.token != token::Comma && + self.token != token::CloseDelim(token::Paren) { + // This wasn't actually a type, but a pattern looking like a type, + // so we are going to rollback and re-parse for recovery. + ty = self.unexpected(); + } + match ty { + Ok(ty) => { + let ident = Ident::new(kw::Invalid, self.prev_span); + let bm = BindingMode::ByValue(Mutability::Immutable); + let pat = self.mk_pat_ident(ty.span, bm, ident); + (pat, ty) + } + // If this is a C-variadic argument and we hit an error, return the error. + Err(err) if self.token == token::DotDotDot => return Err(err), + // Recover from attempting to parse the argument as a type without pattern. + Err(mut err) => { + err.cancel(); + mem::replace(self, parser_snapshot_before_ty); + self.recover_arg_parse()? + } + } }; - Ok((eself, eself_ident, eself_hi)) + + let span = lo.to(self.token.span); + + Ok(Param { + attrs: attrs.into(), + id: ast::DUMMY_NODE_ID, + is_placeholder: false, + pat, + span, + ty, + }) } /// Returns the parsed optional self parameter and whether a self shortcut was used. @@ -1378,27 +1341,64 @@ impl<'a> Parser<'a> { Ok(Some(Param::from_self(ThinVec::default(), eself, eself_ident))) } - /// Parses the parameter list and result type of a function that may have a `self` parameter. - fn parse_fn_decl_with_self( - &mut self, - is_name_required: impl Copy + Fn(&token::Token) -> bool, - ) -> PResult<'a, P> { - // Parse the arguments, starting out with `self` being allowed... - let mut is_self_allowed = true; - let (mut inputs, _): (Vec<_>, _) = self.parse_paren_comma_seq(|p| { - let res = p.parse_param_general(is_self_allowed, true, false, is_name_required); - // ...but now that we've parsed the first argument, `self` is no longer allowed. - is_self_allowed = false; - res - })?; + fn is_named_param(&self) -> bool { + let offset = match self.token.kind { + token::Interpolated(ref nt) => match **nt { + token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon), + _ => 0, + } + token::BinOp(token::And) | token::AndAnd => 1, + _ if self.token.is_keyword(kw::Mut) => 1, + _ => 0, + }; - // Replace duplicated recovered params with `_` pattern to avoid unecessary errors. - self.deduplicate_recovered_params_names(&mut inputs); + self.look_ahead(offset, |t| t.is_ident()) && + self.look_ahead(offset + 1, |t| t == &token::Colon) + } - Ok(P(FnDecl { - inputs, - output: self.parse_ret_ty(true)?, - })) + fn is_isolated_self(&self, n: usize) -> bool { + self.is_keyword_ahead(n, &[kw::SelfLower]) + && self.look_ahead(n + 1, |t| t != &token::ModSep) + } + + fn is_isolated_mut_self(&self, n: usize) -> bool { + self.is_keyword_ahead(n, &[kw::Mut]) + && self.is_isolated_self(n + 1) + } + + fn expect_self_ident(&mut self) -> Ident { + match self.token.kind { + // Preserve hygienic context. + token::Ident(name, _) => { + let span = self.token.span; + self.bump(); + Ident::new(name, span) + } + _ => unreachable!(), + } + } + + /// Recover for the grammar `*self`, `*const self`, and `*mut self`. + fn recover_self_ptr(&mut self) -> PResult<'a, (ast::SelfKind, Ident, Span)> { + let msg = "cannot pass `self` by raw pointer"; + let span = self.token.span; + self.struct_span_err(span, msg) + .span_label(span, msg) + .emit(); + + Ok((SelfKind::Value(Mutability::Immutable), self.expect_self_ident(), self.prev_span)) + } + + /// Parse `self` or `self: TYPE`. We already know the current token is `self`. + fn parse_self_possibly_typed(&mut self, m: Mutability) -> PResult<'a, (SelfKind, Ident, Span)> { + let eself_ident = self.expect_self_ident(); + let eself_hi = self.prev_span; + let eself = if self.eat(&token::Colon) { + SelfKind::Explicit(self.parse_ty()?, m) + } else { + SelfKind::Value(m) + }; + Ok((eself, eself_ident, eself_hi)) } fn is_crate_vis(&self) -> bool { From d9d0e5d36bb6b3e23b4869196788bd10b5220f31 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 30 Sep 2019 05:46:16 +0200 Subject: [PATCH 12/32] syntax: cleanup `parse_fn_decl`. --- src/libsyntax/parse/parser/item.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index 69fbb343ff3b6..2f353b65783ee 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -1274,14 +1274,11 @@ impl<'a> Parser<'a> { Ok((id, generics)) } - /// Parses the argument list and result type of a function declaration. + /// Parses the parameter list and result type of a function declaration. fn parse_fn_decl(&mut self, allow_c_variadic: bool) -> PResult<'a, P> { - let args = self.parse_fn_params(true, allow_c_variadic)?; - let ret_ty = self.parse_ret_ty(true)?; - Ok(P(FnDecl { - inputs: args, - output: ret_ty, + inputs: self.parse_fn_params(true, allow_c_variadic)?, + output: self.parse_ret_ty(true)?, })) } From 5b80ead489beab6ed1e8f0f4951b7d982bd789ab Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 30 Sep 2019 06:21:30 +0200 Subject: [PATCH 13/32] syntax: misc cleanup --- src/libsyntax/parse/parser.rs | 74 ++++++++++++++--------------------- 1 file changed, 30 insertions(+), 44 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index cbeaab5a4d328..4853da865645f 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -547,40 +547,38 @@ impl<'a> Parser<'a> { } } - crate fn check_ident(&mut self) -> bool { - if self.token.is_ident() { + fn check_or_expected(&mut self, ok: bool, mk_type: impl FnOnce() -> TokenType) -> bool { + if ok { true } else { - self.expected_tokens.push(TokenType::Ident); + self.expected_tokens.push(mk_type()); false } } + crate fn check_ident(&mut self) -> bool { + self.check_or_expected(self.token.is_ident(), || TokenType::Ident) + } + fn check_path(&mut self) -> bool { - if self.token.is_path_start() { - true - } else { - self.expected_tokens.push(TokenType::Path); - false - } + self.check_or_expected(self.token.is_path_start(), || TokenType::Path) } fn check_type(&mut self) -> bool { - if self.token.can_begin_type() { - true - } else { - self.expected_tokens.push(TokenType::Type); - false - } + self.check_or_expected(self.token.can_begin_type(), || TokenType::Type) } fn check_const_arg(&mut self) -> bool { - if self.token.can_begin_const_arg() { - true - } else { - self.expected_tokens.push(TokenType::Const); - false - } + self.check_or_expected(self.token.can_begin_const_arg(), || TokenType::Const) + } + + /// Checks to see if the next token is either `+` or `+=`. + /// Otherwise returns `false`. + fn check_plus(&mut self) -> bool { + self.check_or_expected( + self.token.is_like_plus(), + || TokenType::Token(token::BinOp(token::Plus)), + ) } /// Expects and consumes a `+`. if `+=` is seen, replaces it with a `=` @@ -604,18 +602,6 @@ impl<'a> Parser<'a> { } } - /// Checks to see if the next token is either `+` or `+=`. - /// Otherwise returns `false`. - fn check_plus(&mut self) -> bool { - if self.token.is_like_plus() { - true - } - else { - self.expected_tokens.push(TokenType::Token(token::BinOp(token::Plus))); - false - } - } - /// Expects and consumes an `&`. If `&&` is seen, replaces it with a single /// `&` and continues. If an `&` is not seen, signals an error. fn expect_and(&mut self) -> PResult<'a, ()> { @@ -910,15 +896,13 @@ impl<'a> Parser<'a> { self.expected_tokens.clear(); } - pub fn look_ahead(&self, dist: usize, f: F) -> R where - F: FnOnce(&Token) -> R, - { + pub fn look_ahead(&self, dist: usize, looker: impl FnOnce(&Token) -> R) -> R { if dist == 0 { - return f(&self.token); + return looker(&self.token); } let frame = &self.token_cursor.frame; - f(&match frame.tree_cursor.look_ahead(dist - 1) { + looker(&match frame.tree_cursor.look_ahead(dist - 1) { Some(tree) => match tree { TokenTree::Token(token) => token, TokenTree::Delimited(dspan, delim, _) => @@ -1008,9 +992,10 @@ impl<'a> Parser<'a> { Ok((delim, tts.into())) } - fn parse_or_use_outer_attributes(&mut self, - already_parsed_attrs: Option>) - -> PResult<'a, ThinVec> { + fn parse_or_use_outer_attributes( + &mut self, + already_parsed_attrs: Option>, + ) -> PResult<'a, ThinVec> { if let Some(attrs) = already_parsed_attrs { Ok(attrs) } else { @@ -1539,9 +1524,10 @@ impl<'a> Parser<'a> { } } - fn collect_tokens(&mut self, f: F) -> PResult<'a, (R, TokenStream)> - where F: FnOnce(&mut Self) -> PResult<'a, R> - { + fn collect_tokens( + &mut self, + f: impl FnOnce(&mut Self) -> PResult<'a, R>, + ) -> PResult<'a, (R, TokenStream)> { // Record all tokens we parse when parsing this item. let mut tokens = Vec::new(); let prev_collecting = match self.token_cursor.frame.last_token { From 66bf323a3bb8aaa6162cf02ce9e3db2aa44f4779 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 30 Sep 2019 06:42:56 +0200 Subject: [PATCH 14/32] syntax: cleanup `parse_visibility`. --- src/libsyntax/parse/parser.rs | 122 +++++++++++++++++++--------------- 1 file changed, 69 insertions(+), 53 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 4853da865645f..438466851856f 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1417,68 +1417,84 @@ impl<'a> Parser<'a> { // `()` or a tuple might be allowed. For example, `struct Struct(pub (), pub (usize));`. // Because of this, we only `bump` the `(` if we're assured it is appropriate to do so // by the following tokens. - if self.is_keyword_ahead(1, &[kw::Crate]) && - self.look_ahead(2, |t| t != &token::ModSep) // account for `pub(crate::foo)` + if self.is_keyword_ahead(1, &[kw::Crate]) + && self.look_ahead(2, |t| t != &token::ModSep) // account for `pub(crate::foo)` { - // `pub(crate)` - self.bump(); // `(` - self.bump(); // `crate` - self.expect(&token::CloseDelim(token::Paren))?; // `)` - let vis = respan( - lo.to(self.prev_span), - VisibilityKind::Crate(CrateSugar::PubCrate), - ); - return Ok(vis) + return self.parse_vis_pub_crate(lo); } else if self.is_keyword_ahead(1, &[kw::In]) { - // `pub(in path)` - self.bump(); // `(` - self.bump(); // `in` - let path = self.parse_path(PathStyle::Mod)?; // `path` - self.expect(&token::CloseDelim(token::Paren))?; // `)` - let vis = respan(lo.to(self.prev_span), VisibilityKind::Restricted { - path: P(path), - id: ast::DUMMY_NODE_ID, - }); - return Ok(vis) - } else if self.look_ahead(2, |t| t == &token::CloseDelim(token::Paren)) && - self.is_keyword_ahead(1, &[kw::Super, kw::SelfLower]) + return self.parse_vis_pub_in(lo); + } else if self.look_ahead(2, |t| t == &token::CloseDelim(token::Paren)) + && self.is_keyword_ahead(1, &[kw::Super, kw::SelfLower]) { - // `pub(self)` or `pub(super)` - self.bump(); // `(` - let path = self.parse_path(PathStyle::Mod)?; // `super`/`self` - self.expect(&token::CloseDelim(token::Paren))?; // `)` - let vis = respan(lo.to(self.prev_span), VisibilityKind::Restricted { - path: P(path), - id: ast::DUMMY_NODE_ID, - }); - return Ok(vis) - } else if !can_take_tuple { // Provide this diagnostic if this is not a tuple struct - // `pub(something) fn ...` or `struct X { pub(something) y: Z }` - self.bump(); // `(` - let msg = "incorrect visibility restriction"; - let suggestion = r##"some possible visibility restrictions are: -`pub(crate)`: visible only on the current crate -`pub(super)`: visible only in the current module's parent -`pub(in path::to::module)`: visible only on the specified path"##; - let path = self.parse_path(PathStyle::Mod)?; - let sp = path.span; - let help_msg = format!("make this visible only to module `{}` with `in`", path); - self.expect(&token::CloseDelim(token::Paren))?; // `)` - struct_span_err!(self.sess.span_diagnostic, sp, E0704, "{}", msg) - .help(suggestion) - .span_suggestion( - sp, - &help_msg, - format!("in {}", path), - Applicability::MachineApplicable, - ) - .emit(); // Emit diagnostic, but continue with public visibility. + return self.parse_vis_self_super(lo); + } else if !can_take_tuple { // Provide this diagnostic if this is not a tuple struct. + self.recover_incorrect_vis_restriction()?; + // Emit diagnostic, but continue with public visibility. } } Ok(respan(lo, VisibilityKind::Public)) } + /// Parse `pub(crate)`. + fn parse_vis_pub_crate(&mut self, lo: Span) -> PResult<'a, Visibility> { + self.bump(); // `(` + self.bump(); // `crate` + self.expect(&token::CloseDelim(token::Paren))?; // `)` + Ok(respan( + lo.to(self.prev_span), + VisibilityKind::Crate(CrateSugar::PubCrate), + )) + } + + /// Parse `pub(in path)`. + fn parse_vis_pub_in(&mut self, lo: Span) -> PResult<'a, Visibility> { + self.bump(); // `(` + self.bump(); // `in` + let path = self.parse_path(PathStyle::Mod)?; // `path` + self.expect(&token::CloseDelim(token::Paren))?; // `)` + Ok(respan(lo.to(self.prev_span), VisibilityKind::Restricted { + path: P(path), + id: ast::DUMMY_NODE_ID, + })) + } + + /// Parse `pub(self)` or `pub(super)`. + fn parse_vis_self_super(&mut self, lo: Span) -> PResult<'a, Visibility> { + self.bump(); // `(` + let path = self.parse_path(PathStyle::Mod)?; // `super`/`self` + self.expect(&token::CloseDelim(token::Paren))?; // `)` + Ok(respan(lo.to(self.prev_span), VisibilityKind::Restricted { + path: P(path), + id: ast::DUMMY_NODE_ID, + })) + } + + /// Recovery for e.g. `pub(something) fn ...` or `struct X { pub(something) y: Z }` + fn recover_incorrect_vis_restriction(&mut self) -> PResult<'a, ()> { + self.bump(); // `(` + let path = self.parse_path(PathStyle::Mod)?; + self.expect(&token::CloseDelim(token::Paren))?; // `)` + + let msg = "incorrect visibility restriction"; + let suggestion = r##"some possible visibility restrictions are: +`pub(crate)`: visible only on the current crate +`pub(super)`: visible only in the current module's parent +`pub(in path::to::module)`: visible only on the specified path"##; + + struct_span_err!(self.sess.span_diagnostic, path.span, E0704, "{}", msg) + .help(suggestion) + .span_suggestion( + path.span, + &format!("make this visible only to module `{}` with `in`", path), + format!("in {}", path), + Applicability::MachineApplicable, + ) + .emit(); + + Ok(()) + } + /// Parses a string as an ABI spec on an extern type or module. Consumes /// the `extern` keyword, if one is found. fn parse_opt_abi(&mut self) -> PResult<'a, Option> { From 573a8d8d30723592030c4eb22ebea637a58ac411 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 30 Sep 2019 06:47:35 +0200 Subject: [PATCH 15/32] syntax: extract `error_on_invalid_abi`. --- src/libsyntax/parse/parser.rs | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 438466851856f..722f8969fb09e 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1501,32 +1501,35 @@ impl<'a> Parser<'a> { match self.token.kind { token::Literal(token::Lit { kind: token::Str, symbol, suffix }) | token::Literal(token::Lit { kind: token::StrRaw(..), symbol, suffix }) => { - let sp = self.token.span; - self.expect_no_suffix(sp, "an ABI spec", suffix); + self.expect_no_suffix(self.token.span, "an ABI spec", suffix); self.bump(); match abi::lookup(&symbol.as_str()) { Some(abi) => Ok(Some(abi)), None => { - let prev_span = self.prev_span; - struct_span_err!( - self.sess.span_diagnostic, - prev_span, - E0703, - "invalid ABI: found `{}`", - symbol - ) - .span_label(prev_span, "invalid ABI") - .help(&format!("valid ABIs: {}", abi::all_names().join(", "))) - .emit(); + self.error_on_invalid_abi(symbol); Ok(None) } } } - _ => Ok(None), } } + /// Emit an error where `symbol` is an invalid ABI. + fn error_on_invalid_abi(&self, symbol: Symbol) { + let prev_span = self.prev_span; + struct_span_err!( + self.sess.span_diagnostic, + prev_span, + E0703, + "invalid ABI: found `{}`", + symbol + ) + .span_label(prev_span, "invalid ABI") + .help(&format!("valid ABIs: {}", abi::all_names().join(", "))) + .emit(); + } + /// We are parsing `async fn`. If we are on Rust 2015, emit an error. fn ban_async_in_2015(&self, async_span: Span) { if async_span.rust_2015() { From 258e86a5833588ffb2443a80b4e3c42300c4b278 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 30 Sep 2019 08:53:59 +0200 Subject: [PATCH 16/32] syntax: fuse more code paths together. --- src/libsyntax/parse/parser/item.rs | 99 +++++++++++++++--------------- 1 file changed, 51 insertions(+), 48 deletions(-) diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index 2f353b65783ee..eaa04668b7a47 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -18,7 +18,7 @@ use crate::parse::token; use crate::parse::parser::maybe_append; use crate::parse::diagnostics::Error; use crate::tokenstream::{TokenTree, TokenStream}; -use crate::source_map::{respan, Span, Spanned}; +use crate::source_map::{respan, Span}; use crate::symbol::{kw, sym}; use std::mem; @@ -122,12 +122,12 @@ impl<'a> Parser<'a> { if self.eat_keyword(kw::Fn) { // EXTERN FUNCTION ITEM let fn_span = self.prev_span; - let abi = opt_abi.unwrap_or(Abi::C); - let (ident, item_, extra_attrs) = - self.parse_item_fn(Unsafety::Normal, - respan(fn_span, IsAsync::NotAsync), - respan(fn_span, Constness::NotConst), - abi)?; + let (ident, item_, extra_attrs) = self.parse_item_fn(FnHeader { + unsafety: Unsafety::Normal, + asyncness: respan(fn_span, IsAsync::NotAsync), + constness: respan(fn_span, Constness::NotConst), + abi: opt_abi.unwrap_or(Abi::C), + })?; let prev_span = self.prev_span; let item = self.mk_item(lo.to(prev_span), ident, @@ -165,11 +165,12 @@ impl<'a> Parser<'a> { // CONST FUNCTION ITEM let unsafety = self.parse_unsafety(); self.bump(); - let (ident, item_, extra_attrs) = - self.parse_item_fn(unsafety, - respan(const_span, IsAsync::NotAsync), - respan(const_span, Constness::Const), - Abi::Rust)?; + let (ident, item_, extra_attrs) = self.parse_item_fn(FnHeader { + unsafety, + asyncness: respan(const_span, IsAsync::NotAsync), + constness: respan(const_span, Constness::Const), + abi: Abi::Rust, + })?; let prev_span = self.prev_span; let item = self.mk_item(lo.to(prev_span), ident, @@ -213,14 +214,16 @@ impl<'a> Parser<'a> { let unsafety = self.parse_unsafety(); // `unsafe`? self.expect_keyword(kw::Fn)?; // `fn` let fn_span = self.prev_span; - let (ident, item_, extra_attrs) = - self.parse_item_fn(unsafety, - respan(async_span, IsAsync::Async { - closure_id: DUMMY_NODE_ID, - return_impl_trait_id: DUMMY_NODE_ID, - }), - respan(fn_span, Constness::NotConst), - Abi::Rust)?; + let asyncness = respan(async_span, IsAsync::Async { + closure_id: DUMMY_NODE_ID, + return_impl_trait_id: DUMMY_NODE_ID, + }); + let (ident, item_, extra_attrs) = self.parse_item_fn(FnHeader { + unsafety, + asyncness, + constness: respan(fn_span, Constness::NotConst), + abi: Abi::Rust, + })?; let prev_span = self.prev_span; let item = self.mk_item(lo.to(prev_span), ident, @@ -271,11 +274,12 @@ impl<'a> Parser<'a> { // FUNCTION ITEM self.bump(); let fn_span = self.prev_span; - let (ident, item_, extra_attrs) = - self.parse_item_fn(Unsafety::Normal, - respan(fn_span, IsAsync::NotAsync), - respan(fn_span, Constness::NotConst), - Abi::Rust)?; + let (ident, item_, extra_attrs) = self.parse_item_fn(FnHeader { + unsafety: Unsafety::Normal, + asyncness: respan(fn_span, IsAsync::NotAsync), + constness: respan(fn_span, Constness::NotConst), + abi: Abi::Rust, + })?; let prev_span = self.prev_span; let item = self.mk_item(lo.to(prev_span), ident, @@ -297,11 +301,12 @@ impl<'a> Parser<'a> { }; self.expect_keyword(kw::Fn)?; let fn_span = self.prev_span; - let (ident, item_, extra_attrs) = - self.parse_item_fn(Unsafety::Unsafe, - respan(fn_span, IsAsync::NotAsync), - respan(fn_span, Constness::NotConst), - abi)?; + let (ident, item_, extra_attrs) = self.parse_item_fn(FnHeader { + unsafety: Unsafety::Unsafe, + asyncness: respan(fn_span, IsAsync::NotAsync), + constness: respan(fn_span, Constness::NotConst), + abi, + })?; let prev_span = self.prev_span; let item = self.mk_item(lo.to(prev_span), ident, @@ -872,8 +877,7 @@ impl<'a> Parser<'a> { is_name_required: impl Copy + Fn(&token::Token) -> bool, ) -> PResult<'a, (Ident, MethodSig, Generics)> { let header = self.parse_fn_front_matter()?; - let ident = self.parse_ident()?; - let mut generics = self.parse_generics()?; + let (ident, mut generics) = self.parse_fn_header()?; let decl = self.parse_fn_decl_with_self(is_name_required)?; let sig = MethodSig { header, decl }; generics.where_clause = self.parse_where_clause()?; @@ -1251,20 +1255,22 @@ impl<'a> Parser<'a> { } /// Parses an item-position function declaration. - fn parse_item_fn( + fn parse_item_fn(&mut self, header: FnHeader) -> PResult<'a, ItemInfo> { + let allow_c_variadic = header.abi == Abi::C && header.unsafety == Unsafety::Unsafe; + let (ident, decl, generics) = self.parse_fn_sig(allow_c_variadic)?; + let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; + Ok((ident, ItemKind::Fn(decl, header, generics, body), Some(inner_attrs))) + } + + /// Parse the "signature", including the identifier, parameters, and generics of a function. + fn parse_fn_sig( &mut self, - unsafety: Unsafety, - asyncness: Spanned, - constness: Spanned, - abi: Abi - ) -> PResult<'a, ItemInfo> { + allow_c_variadic: bool, + ) -> PResult<'a, (Ident, P, Generics)> { let (ident, mut generics) = self.parse_fn_header()?; - let allow_c_variadic = abi == Abi::C && unsafety == Unsafety::Unsafe; 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()?; - let header = FnHeader { unsafety, asyncness, constness, abi }; - Ok((ident, ItemKind::Fn(decl, header, generics, body), Some(inner_attrs))) + Ok((ident, decl, generics)) } /// Parses the name and optional generic types of a function header. @@ -1386,18 +1392,15 @@ impl<'a> Parser<'a> { extern_sp: Span, ) -> PResult<'a, ForeignItem> { self.expect_keyword(kw::Fn)?; - - let (ident, mut generics) = self.parse_fn_header()?; - let decl = self.parse_fn_decl(true)?; - generics.where_clause = self.parse_where_clause()?; - let hi = self.token.span; + let (ident, decl, generics) = self.parse_fn_sig(true)?; + let span = lo.to(self.token.span); self.parse_semi_or_incorrect_foreign_fn_body(&ident, extern_sp)?; Ok(ast::ForeignItem { ident, attrs, kind: ForeignItemKind::Fn(decl, generics), id: DUMMY_NODE_ID, - span: lo.to(hi), + span, vis, }) } From bea404f292f0ec60a990de28433b9eaa1dfecb4c Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 30 Sep 2019 09:13:42 +0200 Subject: [PATCH 17/32] syntax: stylistic cleanup in item parsing. --- src/libsyntax/parse/parser/item.rs | 154 +++++++++-------------------- 1 file changed, 47 insertions(+), 107 deletions(-) diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index eaa04668b7a47..68f0357abd03c 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -128,13 +128,9 @@ impl<'a> Parser<'a> { constness: respan(fn_span, Constness::NotConst), abi: opt_abi.unwrap_or(Abi::C), })?; - let prev_span = self.prev_span; - let item = self.mk_item(lo.to(prev_span), - ident, - item_, - visibility, - maybe_append(attrs, extra_attrs)); - return Ok(Some(item)); + let span = lo.to(self.prev_span); + let attrs = maybe_append(attrs, extra_attrs); + return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs))); } else if self.check(&token::OpenDelim(token::Brace)) { return Ok(Some( self.parse_item_foreign_mod(lo, opt_abi, visibility, attrs, extern_sp)?, @@ -149,13 +145,9 @@ impl<'a> Parser<'a> { // STATIC ITEM let m = self.parse_mutability(); let (ident, item_, extra_attrs) = self.parse_item_const(Some(m))?; - let prev_span = self.prev_span; - let item = self.mk_item(lo.to(prev_span), - ident, - item_, - visibility, - maybe_append(attrs, extra_attrs)); - return Ok(Some(item)); + let span = lo.to(self.prev_span); + let attrs = maybe_append(attrs, extra_attrs); + return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs))); } if self.eat_keyword(kw::Const) { let const_span = self.prev_span; @@ -171,13 +163,9 @@ impl<'a> Parser<'a> { constness: respan(const_span, Constness::Const), abi: Abi::Rust, })?; - let prev_span = self.prev_span; - let item = self.mk_item(lo.to(prev_span), - ident, - item_, - visibility, - maybe_append(attrs, extra_attrs)); - return Ok(Some(item)); + let span = lo.to(self.prev_span); + let attrs = maybe_append(attrs, extra_attrs); + return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs))); } // CONST ITEM @@ -194,13 +182,9 @@ impl<'a> Parser<'a> { .emit(); } let (ident, item_, extra_attrs) = self.parse_item_const(None)?; - let prev_span = self.prev_span; - let item = self.mk_item(lo.to(prev_span), - ident, - item_, - visibility, - maybe_append(attrs, extra_attrs)); - return Ok(Some(item)); + let span = lo.to(self.prev_span); + let attrs = maybe_append(attrs, extra_attrs); + return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs))); } // Parses `async unsafe? fn`. @@ -224,14 +208,10 @@ impl<'a> Parser<'a> { constness: respan(fn_span, Constness::NotConst), abi: Abi::Rust, })?; - let prev_span = self.prev_span; - let item = self.mk_item(lo.to(prev_span), - ident, - item_, - visibility, - maybe_append(attrs, extra_attrs)); self.ban_async_in_2015(async_span); - return Ok(Some(item)); + let span = lo.to(self.prev_span); + let attrs = maybe_append(attrs, extra_attrs); + return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs))); } } if self.check_keyword(kw::Unsafe) && @@ -246,15 +226,10 @@ impl<'a> Parser<'a> { self.expect_keyword(kw::Trait)?; IsAuto::Yes }; - let (ident, item_, extra_attrs) = - self.parse_item_trait(is_auto, Unsafety::Unsafe)?; - let prev_span = self.prev_span; - let item = self.mk_item(lo.to(prev_span), - ident, - item_, - visibility, - maybe_append(attrs, extra_attrs)); - return Ok(Some(item)); + let (ident, item_, extra_attrs) = self.parse_item_trait(is_auto, Unsafety::Unsafe)?; + let span = lo.to(self.prev_span); + let attrs = maybe_append(attrs, extra_attrs); + return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs))); } if self.check_keyword(kw::Impl) || self.check_keyword(kw::Unsafe) && @@ -265,10 +240,10 @@ impl<'a> Parser<'a> { let defaultness = self.parse_defaultness(); let unsafety = self.parse_unsafety(); self.expect_keyword(kw::Impl)?; - let (ident, item, extra_attrs) = self.parse_item_impl(unsafety, defaultness)?; + let (ident, item_, extra_attrs) = self.parse_item_impl(unsafety, defaultness)?; let span = lo.to(self.prev_span); - return Ok(Some(self.mk_item(span, ident, item, visibility, - maybe_append(attrs, extra_attrs)))); + let attrs = maybe_append(attrs, extra_attrs); + return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs))); } if self.check_keyword(kw::Fn) { // FUNCTION ITEM @@ -280,13 +255,9 @@ impl<'a> Parser<'a> { constness: respan(fn_span, Constness::NotConst), abi: Abi::Rust, })?; - let prev_span = self.prev_span; - let item = self.mk_item(lo.to(prev_span), - ident, - item_, - visibility, - maybe_append(attrs, extra_attrs)); - return Ok(Some(item)); + let span = lo.to(self.prev_span); + let attrs = maybe_append(attrs, extra_attrs); + return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs))); } if self.check_keyword(kw::Unsafe) && self.look_ahead(1, |t| *t != token::OpenDelim(token::Brace)) { @@ -307,25 +278,16 @@ impl<'a> Parser<'a> { constness: respan(fn_span, Constness::NotConst), abi, })?; - let prev_span = self.prev_span; - let item = self.mk_item(lo.to(prev_span), - ident, - item_, - visibility, - maybe_append(attrs, extra_attrs)); - return Ok(Some(item)); + let span = lo.to(self.prev_span); + let attrs = maybe_append(attrs, extra_attrs); + return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs))); } if self.eat_keyword(kw::Mod) { // MODULE ITEM - let (ident, item_, extra_attrs) = - self.parse_item_mod(&attrs[..])?; - let prev_span = self.prev_span; - let item = self.mk_item(lo.to(prev_span), - ident, - item_, - visibility, - maybe_append(attrs, extra_attrs)); - return Ok(Some(item)); + let (ident, item_, extra_attrs) = self.parse_item_mod(&attrs[..])?; + let span = lo.to(self.prev_span); + let attrs = maybe_append(attrs, extra_attrs); + return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs))); } if let Some(type_) = self.eat_type() { let (ident, alias, generics) = type_?; @@ -334,24 +296,15 @@ impl<'a> Parser<'a> { AliasKind::Weak(ty) => ItemKind::TyAlias(ty, generics), AliasKind::OpaqueTy(bounds) => ItemKind::OpaqueTy(bounds, generics), }; - let prev_span = self.prev_span; - let item = self.mk_item(lo.to(prev_span), - ident, - item_, - visibility, - attrs); - return Ok(Some(item)); + let span = lo.to(self.prev_span); + return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs))); } if self.eat_keyword(kw::Enum) { // ENUM ITEM let (ident, item_, extra_attrs) = self.parse_item_enum()?; - let prev_span = self.prev_span; - let item = self.mk_item(lo.to(prev_span), - ident, - item_, - visibility, - maybe_append(attrs, extra_attrs)); - return Ok(Some(item)); + let span = lo.to(self.prev_span); + let attrs = maybe_append(attrs, extra_attrs); + return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs))); } if self.check_keyword(kw::Trait) || (self.check_keyword(kw::Auto) @@ -365,38 +318,25 @@ impl<'a> Parser<'a> { IsAuto::Yes }; // TRAIT ITEM - let (ident, item_, extra_attrs) = - self.parse_item_trait(is_auto, Unsafety::Normal)?; - let prev_span = self.prev_span; - let item = self.mk_item(lo.to(prev_span), - ident, - item_, - visibility, - maybe_append(attrs, extra_attrs)); - return Ok(Some(item)); + let (ident, item_, extra_attrs) = self.parse_item_trait(is_auto, Unsafety::Normal)?; + let span = lo.to(self.prev_span); + let attrs = maybe_append(attrs, extra_attrs); + return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs))); } if self.eat_keyword(kw::Struct) { // STRUCT ITEM let (ident, item_, extra_attrs) = self.parse_item_struct()?; - let prev_span = self.prev_span; - let item = self.mk_item(lo.to(prev_span), - ident, - item_, - visibility, - maybe_append(attrs, extra_attrs)); - return Ok(Some(item)); + let span = lo.to(self.prev_span); + let attrs = maybe_append(attrs, extra_attrs); + return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs))); } if self.is_union_item() { // UNION ITEM self.bump(); let (ident, item_, extra_attrs) = self.parse_item_union()?; - let prev_span = self.prev_span; - let item = self.mk_item(lo.to(prev_span), - ident, - item_, - visibility, - maybe_append(attrs, extra_attrs)); - return Ok(Some(item)); + let span = lo.to(self.prev_span); + let attrs = maybe_append(attrs, extra_attrs); + return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs))); } if let Some(macro_def) = self.eat_macro_def(&attrs, &visibility, lo)? { return Ok(Some(macro_def)); From 151ce96e3e6c909ec071a313eaddc5e9f3b8f6bd Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 30 Sep 2019 09:32:51 +0200 Subject: [PATCH 18/32] syntax: reduce repetition in fn parsing. --- src/libsyntax/parse/parser/item.rs | 47 +++++++++++++----------------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index 68f0357abd03c..e8ca264f1c5ff 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -122,15 +122,12 @@ impl<'a> Parser<'a> { if self.eat_keyword(kw::Fn) { // EXTERN FUNCTION ITEM let fn_span = self.prev_span; - let (ident, item_, extra_attrs) = self.parse_item_fn(FnHeader { + return self.parse_item_fn(lo, visibility, attrs, FnHeader { unsafety: Unsafety::Normal, asyncness: respan(fn_span, IsAsync::NotAsync), constness: respan(fn_span, Constness::NotConst), abi: opt_abi.unwrap_or(Abi::C), - })?; - let span = lo.to(self.prev_span); - let attrs = maybe_append(attrs, extra_attrs); - return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs))); + }); } else if self.check(&token::OpenDelim(token::Brace)) { return Ok(Some( self.parse_item_foreign_mod(lo, opt_abi, visibility, attrs, extern_sp)?, @@ -157,15 +154,12 @@ impl<'a> Parser<'a> { // CONST FUNCTION ITEM let unsafety = self.parse_unsafety(); self.bump(); - let (ident, item_, extra_attrs) = self.parse_item_fn(FnHeader { + return self.parse_item_fn(lo, visibility, attrs, FnHeader { unsafety, asyncness: respan(const_span, IsAsync::NotAsync), constness: respan(const_span, Constness::Const), abi: Abi::Rust, - })?; - let span = lo.to(self.prev_span); - let attrs = maybe_append(attrs, extra_attrs); - return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs))); + }); } // CONST ITEM @@ -202,16 +196,14 @@ impl<'a> Parser<'a> { closure_id: DUMMY_NODE_ID, return_impl_trait_id: DUMMY_NODE_ID, }); - let (ident, item_, extra_attrs) = self.parse_item_fn(FnHeader { + let item = self.parse_item_fn(lo, visibility, attrs, FnHeader { unsafety, asyncness, constness: respan(fn_span, Constness::NotConst), abi: Abi::Rust, })?; self.ban_async_in_2015(async_span); - let span = lo.to(self.prev_span); - let attrs = maybe_append(attrs, extra_attrs); - return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs))); + return Ok(item); } } if self.check_keyword(kw::Unsafe) && @@ -249,15 +241,12 @@ impl<'a> Parser<'a> { // FUNCTION ITEM self.bump(); let fn_span = self.prev_span; - let (ident, item_, extra_attrs) = self.parse_item_fn(FnHeader { + return self.parse_item_fn(lo, visibility, attrs, FnHeader { unsafety: Unsafety::Normal, asyncness: respan(fn_span, IsAsync::NotAsync), constness: respan(fn_span, Constness::NotConst), abi: Abi::Rust, - })?; - let span = lo.to(self.prev_span); - let attrs = maybe_append(attrs, extra_attrs); - return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs))); + }); } if self.check_keyword(kw::Unsafe) && self.look_ahead(1, |t| *t != token::OpenDelim(token::Brace)) { @@ -272,15 +261,12 @@ impl<'a> Parser<'a> { }; self.expect_keyword(kw::Fn)?; let fn_span = self.prev_span; - let (ident, item_, extra_attrs) = self.parse_item_fn(FnHeader { + return self.parse_item_fn(lo, visibility, attrs, FnHeader { unsafety: Unsafety::Unsafe, asyncness: respan(fn_span, IsAsync::NotAsync), constness: respan(fn_span, Constness::NotConst), abi, - })?; - let span = lo.to(self.prev_span); - let attrs = maybe_append(attrs, extra_attrs); - return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs))); + }); } if self.eat_keyword(kw::Mod) { // MODULE ITEM @@ -1195,11 +1181,20 @@ impl<'a> Parser<'a> { } /// Parses an item-position function declaration. - fn parse_item_fn(&mut self, header: FnHeader) -> PResult<'a, ItemInfo> { + fn parse_item_fn( + &mut self, + lo: Span, + vis: Visibility, + attrs: Vec, + header: FnHeader, + ) -> PResult<'a, Option>> { let allow_c_variadic = header.abi == Abi::C && header.unsafety == Unsafety::Unsafe; let (ident, decl, generics) = self.parse_fn_sig(allow_c_variadic)?; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; - Ok((ident, ItemKind::Fn(decl, header, generics, body), Some(inner_attrs))) + let span = lo.to(self.prev_span); + let kind = ItemKind::Fn(decl, header, generics, body); + let attrs = maybe_append(attrs, Some(inner_attrs)); + Ok(Some(self.mk_item(span, ident, kind, vis, attrs))) } /// Parse the "signature", including the identifier, parameters, and generics of a function. From b0b073cdb07ccd392747fcaf1f1e949fe8921c1b Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 27 Sep 2019 14:03:09 +0200 Subject: [PATCH 19/32] Self-Profiling: Refactor SelfProfiler API to be RAII based where possible. --- src/librustc/session/mod.rs | 24 +-- src/librustc/ty/context.rs | 4 + src/librustc/util/profiling.rs | 326 ++++++++++++++++++++++++--------- 3 files changed, 244 insertions(+), 110 deletions(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 8e9c2735c3913..e52f2788e6b22 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -32,7 +32,7 @@ use syntax::source_map; use syntax::parse::{self, ParseSess}; use syntax::symbol::Symbol; use syntax_pos::{MultiSpan, Span}; -use crate::util::profiling::SelfProfiler; +use crate::util::profiling::{SelfProfiler, SelfProfilerRef}; use rustc_target::spec::{PanicStrategy, RelroLevel, Target, TargetTriple}; use rustc_data_structures::flock; @@ -129,7 +129,7 @@ pub struct Session { pub profile_channel: Lock>>, /// Used by `-Z self-profile`. - pub self_profiling: Option>, + pub prof: SelfProfilerRef, /// Some measurements that are being gathered during compilation. pub perf_stats: PerfStats, @@ -835,24 +835,6 @@ impl Session { } } - #[inline(never)] - #[cold] - fn profiler_active ()>(&self, f: F) { - match &self.self_profiling { - None => bug!("profiler_active() called but there was no profiler active"), - Some(profiler) => { - f(&profiler); - } - } - } - - #[inline(always)] - pub fn profiler ()>(&self, f: F) { - if unlikely!(self.self_profiling.is_some()) { - self.profiler_active(f) - } - } - pub fn print_perf_stats(&self) { println!( "Total time spent computing symbol hashes: {}", @@ -1257,7 +1239,7 @@ fn build_session_( imported_macro_spans: OneThread::new(RefCell::new(FxHashMap::default())), incr_comp_session: OneThread::new(RefCell::new(IncrCompSession::NotInitialized)), cgu_reuse_tracker, - self_profiling: self_profiler, + prof: SelfProfilerRef::new(self_profiler), profile_channel: Lock::new(None), perf_stats: PerfStats { symbol_hash_time: Lock::new(Duration::from_secs(0)), diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 6c5d9a6dfdf22..467f4c84ab3df 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -45,6 +45,7 @@ use crate::ty::CanonicalPolyFnSig; use crate::util::common::ErrorReported; use crate::util::nodemap::{DefIdMap, DefIdSet, ItemLocalMap, ItemLocalSet}; use crate::util::nodemap::{FxHashMap, FxHashSet}; +use crate::util::profiling::SelfProfilerRef; use errors::DiagnosticBuilder; use arena::SyncDroplessArena; @@ -995,6 +996,8 @@ pub struct GlobalCtxt<'tcx> { pub dep_graph: DepGraph, + pub prof: SelfProfilerRef, + /// Common objects. pub common: Common<'tcx>, @@ -1225,6 +1228,7 @@ impl<'tcx> TyCtxt<'tcx> { arena: WorkerLocal::new(|_| Arena::default()), interners, dep_graph, + prof: s.prof.clone(), common, types: common_types, lifetimes: common_lifetimes, diff --git a/src/librustc/util/profiling.rs b/src/librustc/util/profiling.rs index 8624856a4f55c..bd02e7f5a14a1 100644 --- a/src/librustc/util/profiling.rs +++ b/src/librustc/util/profiling.rs @@ -1,9 +1,9 @@ -use std::borrow::Cow; use std::error::Error; use std::fs; use std::mem::{self, Discriminant}; use std::path::Path; use std::process; +use std::sync::Arc; use std::thread::ThreadId; use std::u32; @@ -62,6 +62,206 @@ fn thread_id_to_u64(tid: ThreadId) -> u64 { unsafe { mem::transmute::(tid) } } + +/// A reference to the SelfProfiler. It can be cloned and sent across thread +/// boundaries at will. +#[derive(Clone)] +pub struct SelfProfilerRef { + // This field is `None` if self-profiling is disabled for the current + // compilation session. + profiler: Option>, + + // We store the filter mask directly in the reference because that doesn't + // cost anything and allows for filtering with checking if the profiler is + // actually enabled. + event_filter_mask: EventFilter, +} + +impl SelfProfilerRef { + + pub fn new(profiler: Option>) -> SelfProfilerRef { + // If there is no SelfProfiler then the filter mask is set to NONE, + // ensuring that nothing ever tries to actually access it. + let event_filter_mask = profiler + .as_ref() + .map(|p| p.event_filter_mask) + .unwrap_or(EventFilter::NONE); + + SelfProfilerRef { + profiler, + event_filter_mask, + } + } + + // This shim makes sure that calls only get executed if the filter mask + // lets them pass. It also contains some trickery to make sure that + // code is optimized for non-profiling compilation sessions, i.e. anything + // past the filter check is never inlined so it doesn't clutter the fast + // path. + #[inline(always)] + fn exec(&self, event_filter: EventFilter, f: F) -> TimingGuard<'_> + where F: for<'a> FnOnce(&'a SelfProfiler) -> TimingGuard<'a> + { + #[inline(never)] + fn cold_call(profiler_ref: &SelfProfilerRef, f: F) -> TimingGuard<'_> + where F: for<'a> FnOnce(&'a SelfProfiler) -> TimingGuard<'a> + { + let profiler = profiler_ref.profiler.as_ref().unwrap(); + f(&**profiler) + } + + if unlikely!(self.event_filter_mask.contains(event_filter)) { + cold_call(self, f) + } else { + TimingGuard::none() + } + } + + /// Start profiling a generic activity. Profiling continues until the + /// TimingGuard returned from this call is dropped. + #[inline(always)] + pub fn generic_activity(&self, event_id: &str) -> TimingGuard<'_> { + self.exec(EventFilter::GENERIC_ACTIVITIES, |profiler| { + let event_id = profiler.profiler.alloc_string(event_id); + TimingGuard::start( + profiler, + profiler.generic_activity_event_kind, + event_id + ) + }) + } + + /// Start profiling a generic activity. Profiling continues until + /// `generic_activity_end` is called. The RAII-based `generic_activity` + /// usually is the better alternative. + #[inline(always)] + pub fn generic_activity_start(&self, event_id: &str) { + self.non_guard_generic_event( + |profiler| profiler.generic_activity_event_kind, + |profiler| profiler.profiler.alloc_string(event_id), + EventFilter::GENERIC_ACTIVITIES, + TimestampKind::Start, + ); + } + + /// End profiling a generic activity that was started with + /// `generic_activity_start`. The RAII-based `generic_activity` usually is + /// the better alternative. + #[inline(always)] + pub fn generic_activity_end(&self, event_id: &str) { + self.non_guard_generic_event( + |profiler| profiler.generic_activity_event_kind, + |profiler| profiler.profiler.alloc_string(event_id), + EventFilter::GENERIC_ACTIVITIES, + TimestampKind::End, + ); + } + + /// Start profiling a query provider. Profiling continues until the + /// TimingGuard returned from this call is dropped. + #[inline(always)] + pub fn query_provider(&self, query_name: QueryName) -> TimingGuard<'_> { + self.exec(EventFilter::QUERY_PROVIDERS, |profiler| { + let event_id = SelfProfiler::get_query_name_string_id(query_name); + TimingGuard::start(profiler, profiler.query_event_kind, event_id) + }) + } + + /// Record a query in-memory cache hit. + #[inline(always)] + pub fn query_cache_hit(&self, query_name: QueryName) { + self.non_guard_query_event( + |profiler| profiler.query_cache_hit_event_kind, + query_name, + EventFilter::QUERY_CACHE_HITS, + TimestampKind::Instant, + ); + } + + /// Start profiling a query being blocked on a concurrent execution. + /// Profiling continues until `query_blocked_end` is called. + #[inline(always)] + pub fn query_blocked_start(&self, query_name: QueryName) { + self.non_guard_query_event( + |profiler| profiler.query_blocked_event_kind, + query_name, + EventFilter::QUERY_BLOCKED, + TimestampKind::Start, + ); + } + + /// End profiling a query being blocked on a concurrent execution. + #[inline(always)] + pub fn query_blocked_end(&self, query_name: QueryName) { + self.non_guard_query_event( + |profiler| profiler.query_blocked_event_kind, + query_name, + EventFilter::QUERY_BLOCKED, + TimestampKind::End, + ); + } + + /// Start profiling how long it takes to load a query result from the + /// incremental compilation on-disk cache. Profiling continues until the + /// TimingGuard returned from this call is dropped. + #[inline(always)] + pub fn incr_cache_loading(&self, query_name: QueryName) -> TimingGuard<'_> { + self.exec(EventFilter::INCR_CACHE_LOADS, |profiler| { + let event_id = SelfProfiler::get_query_name_string_id(query_name); + TimingGuard::start( + profiler, + profiler.incremental_load_result_event_kind, + event_id + ) + }) + } + + #[inline(always)] + fn non_guard_query_event( + &self, + event_kind: fn(&SelfProfiler) -> StringId, + query_name: QueryName, + event_filter: EventFilter, + timestamp_kind: TimestampKind + ) { + drop(self.exec(event_filter, |profiler| { + let event_id = SelfProfiler::get_query_name_string_id(query_name); + let thread_id = thread_id_to_u64(std::thread::current().id()); + + profiler.profiler.record_event( + event_kind(profiler), + event_id, + thread_id, + timestamp_kind, + ); + + TimingGuard::none() + })); + } + + #[inline(always)] + fn non_guard_generic_event StringId>( + &self, + event_kind: fn(&SelfProfiler) -> StringId, + event_id: F, + event_filter: EventFilter, + timestamp_kind: TimestampKind + ) { + drop(self.exec(event_filter, |profiler| { + let thread_id = thread_id_to_u64(std::thread::current().id()); + + profiler.profiler.record_event( + event_kind(profiler), + event_id(profiler), + thread_id, + timestamp_kind, + ); + + TimingGuard::none() + })); + } +} + pub struct SelfProfiler { profiler: Profiler, event_filter_mask: EventFilter, @@ -143,103 +343,51 @@ impl SelfProfiler { let id = SelfProfiler::get_query_name_string_id(query_name); self.profiler.alloc_string_with_reserved_id(id, query_name.as_str()); } +} - #[inline] - pub fn start_activity( - &self, - label: impl Into>, - ) { - if self.event_filter_mask.contains(EventFilter::GENERIC_ACTIVITIES) { - self.record(&label.into(), self.generic_activity_event_kind, TimestampKind::Start); - } - } - - #[inline] - pub fn end_activity( - &self, - label: impl Into>, - ) { - if self.event_filter_mask.contains(EventFilter::GENERIC_ACTIVITIES) { - self.record(&label.into(), self.generic_activity_event_kind, TimestampKind::End); - } - } - - #[inline] - pub fn record_query_hit(&self, query_name: QueryName) { - if self.event_filter_mask.contains(EventFilter::QUERY_CACHE_HITS) { - self.record_query(query_name, self.query_cache_hit_event_kind, TimestampKind::Instant); - } - } - - #[inline] - pub fn start_query(&self, query_name: QueryName) { - if self.event_filter_mask.contains(EventFilter::QUERY_PROVIDERS) { - self.record_query(query_name, self.query_event_kind, TimestampKind::Start); - } - } - - #[inline] - pub fn end_query(&self, query_name: QueryName) { - if self.event_filter_mask.contains(EventFilter::QUERY_PROVIDERS) { - self.record_query(query_name, self.query_event_kind, TimestampKind::End); - } - } - - #[inline] - pub fn incremental_load_result_start(&self, query_name: QueryName) { - if self.event_filter_mask.contains(EventFilter::INCR_CACHE_LOADS) { - self.record_query( - query_name, - self.incremental_load_result_event_kind, - TimestampKind::Start - ); - } - } - - #[inline] - pub fn incremental_load_result_end(&self, query_name: QueryName) { - if self.event_filter_mask.contains(EventFilter::INCR_CACHE_LOADS) { - self.record_query( - query_name, - self.incremental_load_result_event_kind, - TimestampKind::End - ); - } - } +#[must_use] +pub struct TimingGuard<'a>(Option>); - #[inline] - pub fn query_blocked_start(&self, query_name: QueryName) { - if self.event_filter_mask.contains(EventFilter::QUERY_BLOCKED) { - self.record_query(query_name, self.query_blocked_event_kind, TimestampKind::Start); - } - } +struct TimingGuardInternal<'a> { + raw_profiler: &'a Profiler, + event_id: StringId, + event_kind: StringId, + thread_id: u64, +} +impl<'a> TimingGuard<'a> { #[inline] - pub fn query_blocked_end(&self, query_name: QueryName) { - if self.event_filter_mask.contains(EventFilter::QUERY_BLOCKED) { - self.record_query(query_name, self.query_blocked_event_kind, TimestampKind::End); - } + pub fn start( + profiler: &'a SelfProfiler, + event_kind: StringId, + event_id: StringId, + ) -> TimingGuard<'a> { + let thread_id = thread_id_to_u64(std::thread::current().id()); + let raw_profiler = &profiler.profiler; + raw_profiler.record_event(event_kind, event_id, thread_id, TimestampKind::Start); + + TimingGuard(Some(TimingGuardInternal { + raw_profiler, + event_kind, + event_id, + thread_id, + })) } #[inline] - fn record(&self, event_id: &str, event_kind: StringId, timestamp_kind: TimestampKind) { - let thread_id = thread_id_to_u64(std::thread::current().id()); - - let event_id = self.profiler.alloc_string(event_id); - self.profiler.record_event(event_kind, event_id, thread_id, timestamp_kind); + pub fn none() -> TimingGuard<'a> { + TimingGuard(None) } +} +impl<'a> Drop for TimingGuardInternal<'a> { #[inline] - fn record_query( - &self, - query_name: QueryName, - event_kind: StringId, - timestamp_kind: TimestampKind, - ) { - let dep_node_name = SelfProfiler::get_query_name_string_id(query_name); - - let thread_id = thread_id_to_u64(std::thread::current().id()); - - self.profiler.record_event(event_kind, dep_node_name, thread_id, timestamp_kind); + fn drop(&mut self) { + self.raw_profiler.record_event( + self.event_kind, + self.event_id, + self.thread_id, + TimestampKind::End + ); } } From d94262272bbdc700689a012a2e8a34adbe2a0f18 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 27 Sep 2019 14:04:36 +0200 Subject: [PATCH 20/32] Self-Profiling: Make names of existing events more consistent and use new API. --- src/librustc/ty/query/plumbing.rs | 26 +++--- src/librustc_codegen_llvm/back/lto.rs | 105 +++++++++++++---------- src/librustc_codegen_llvm/back/write.rs | 25 +++--- src/librustc_codegen_llvm/base.rs | 2 + src/librustc_codegen_llvm/lib.rs | 4 +- src/librustc_codegen_ssa/back/write.rs | 78 +++-------------- src/librustc_codegen_ssa/base.rs | 5 +- src/librustc_codegen_ssa/lib.rs | 1 - src/librustc_incremental/persist/save.rs | 6 ++ src/librustc_interface/passes.rs | 24 +++--- src/librustc_typeck/lib.rs | 4 +- 11 files changed, 122 insertions(+), 158 deletions(-) diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index 32858d30b0cc4..955f1447c55b6 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -112,7 +112,7 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { let mut lock = cache.get_shard_by_value(key).lock(); if let Some(value) = lock.results.get(key) { profq_msg!(tcx, ProfileQueriesMsg::CacheHit); - tcx.sess.profiler(|p| p.record_query_hit(Q::NAME)); + tcx.prof.query_cache_hit(Q::NAME); let result = (value.value.clone(), value.index); #[cfg(debug_assertions)] { @@ -128,7 +128,7 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { // in another thread has completed. Record how long we wait in the // self-profiler. #[cfg(parallel_compiler)] - tcx.sess.profiler(|p| p.query_blocked_start(Q::NAME)); + tcx.prof.query_blocked_start(Q::NAME); job.clone() }, @@ -170,7 +170,7 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { #[cfg(parallel_compiler)] { let result = job.r#await(tcx, span); - tcx.sess.profiler(|p| p.query_blocked_end(Q::NAME)); + tcx.prof.query_blocked_end(Q::NAME); if let Err(cycle) = result { return TryGetJob::Cycle(Q::handle_cycle_error(tcx, cycle)); @@ -382,8 +382,9 @@ impl<'tcx> TyCtxt<'tcx> { } if Q::ANON { + profq_msg!(self, ProfileQueriesMsg::ProviderBegin); - self.sess.profiler(|p| p.start_query(Q::NAME)); + let prof_timer = self.prof.query_provider(Q::NAME); let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| { self.start_query(job.job.clone(), diagnostics, |tcx| { @@ -393,7 +394,7 @@ impl<'tcx> TyCtxt<'tcx> { }) }); - self.sess.profiler(|p| p.end_query(Q::NAME)); + drop(prof_timer); profq_msg!(self, ProfileQueriesMsg::ProviderEnd); self.dep_graph.read_index(dep_node_index); @@ -451,9 +452,8 @@ impl<'tcx> TyCtxt<'tcx> { // First we try to load the result from the on-disk cache. let result = if Q::cache_on_disk(self, key.clone(), None) && self.sess.opts.debugging_opts.incremental_queries { - self.sess.profiler(|p| p.incremental_load_result_start(Q::NAME)); + let _prof_timer = self.prof.incr_cache_loading(Q::NAME); let result = Q::try_load_from_disk(self, prev_dep_node_index); - self.sess.profiler(|p| p.incremental_load_result_end(Q::NAME)); // We always expect to find a cached result for things that // can be forced from `DepNode`. @@ -469,21 +469,17 @@ impl<'tcx> TyCtxt<'tcx> { let result = if let Some(result) = result { profq_msg!(self, ProfileQueriesMsg::CacheHit); - self.sess.profiler(|p| p.record_query_hit(Q::NAME)); - result } else { // We could not load a result from the on-disk cache, so // recompute. - - self.sess.profiler(|p| p.start_query(Q::NAME)); + let _prof_timer = self.prof.query_provider(Q::NAME); // The dep-graph for this computation is already in-place. let result = self.dep_graph.with_ignore(|| { Q::compute(self, key) }); - self.sess.profiler(|p| p.end_query(Q::NAME)); result }; @@ -551,7 +547,7 @@ impl<'tcx> TyCtxt<'tcx> { key, dep_node); profq_msg!(self, ProfileQueriesMsg::ProviderBegin); - self.sess.profiler(|p| p.start_query(Q::NAME)); + let prof_timer = self.prof.query_provider(Q::NAME); let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| { self.start_query(job.job.clone(), diagnostics, |tcx| { @@ -571,7 +567,7 @@ impl<'tcx> TyCtxt<'tcx> { }) }); - self.sess.profiler(|p| p.end_query(Q::NAME)); + drop(prof_timer); profq_msg!(self, ProfileQueriesMsg::ProviderEnd); if unlikely!(self.sess.opts.debugging_opts.query_dep_graph) { @@ -619,7 +615,7 @@ impl<'tcx> TyCtxt<'tcx> { let _ = self.get_query::(DUMMY_SP, key); } else { profq_msg!(self, ProfileQueriesMsg::CacheHit); - self.sess.profiler(|p| p.record_query_hit(Q::NAME)); + self.prof.query_cache_hit(Q::NAME); } } diff --git a/src/librustc_codegen_llvm/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs index a43fbb68dbaed..c4368d2cb8b45 100644 --- a/src/librustc_codegen_llvm/back/lto.rs +++ b/src/librustc_codegen_llvm/back/lto.rs @@ -62,11 +62,13 @@ fn prepare_lto(cgcx: &CodegenContext, }; let exported_symbols = cgcx.exported_symbols .as_ref().expect("needs exported symbols for LTO"); - let mut symbol_white_list = exported_symbols[&LOCAL_CRATE] - .iter() - .filter_map(symbol_filter) - .collect::>(); - let _timer = cgcx.profile_activity("generate_symbol_white_list_for_thinlto"); + let mut symbol_white_list = { + let _timer = cgcx.prof.generic_activity("LLVM_lto_generate_symbol_white_list"); + exported_symbols[&LOCAL_CRATE] + .iter() + .filter_map(symbol_filter) + .collect::>() + }; info!("{} symbols to preserve in this crate", symbol_white_list.len()); // If we're performing LTO for the entire crate graph, then for each of our @@ -95,14 +97,17 @@ fn prepare_lto(cgcx: &CodegenContext, } for &(cnum, ref path) in cgcx.each_linked_rlib_for_lto.iter() { - let _timer = cgcx.profile_activity(format!("load: {}", path.display())); let exported_symbols = cgcx.exported_symbols .as_ref().expect("needs exported symbols for LTO"); - symbol_white_list.extend( - exported_symbols[&cnum] - .iter() - .filter_map(symbol_filter)); + { + let _timer = cgcx.prof.generic_activity("LLVM_lto_generate_symbol_white_list"); + symbol_white_list.extend( + exported_symbols[&cnum] + .iter() + .filter_map(symbol_filter)); + } + let _timer = cgcx.prof.generic_activity("LLVM_lto_load_upstream_bitcode"); let archive = ArchiveRO::open(&path).expect("wanted an rlib"); let bytecodes = archive.iter().filter_map(|child| { child.ok().and_then(|c| c.name().map(|name| (name, c))) @@ -189,6 +194,7 @@ fn fat_lto(cgcx: &CodegenContext, symbol_white_list: &[*const libc::c_char]) -> Result, FatalError> { + let _timer = cgcx.prof.generic_activity("LLVM_fat_lto_build_monolithic_module"); info!("going for a fat lto"); // Sort out all our lists of incoming modules into two lists. @@ -287,6 +293,7 @@ fn fat_lto(cgcx: &CodegenContext, // save and persist everything with the original module. let mut linker = Linker::new(llmod); for (bc_decoded, name) in serialized_modules { + let _timer = cgcx.prof.generic_activity("LLVM_fat_lto_link_module"); info!("linking {:?}", name); time_ext(cgcx.time_passes, None, &format!("ll link {:?}", name), || { let data = bc_decoded.data(); @@ -388,6 +395,7 @@ fn thin_lto(cgcx: &CodegenContext, symbol_white_list: &[*const libc::c_char]) -> Result<(Vec>, Vec), FatalError> { + let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_global_analysis"); unsafe { info!("going for that thin, thin LTO"); @@ -601,16 +609,6 @@ impl ModuleBuffer { llvm::LLVMRustModuleBufferCreate(m) }) } - - pub fn parse<'a>( - &self, - name: &str, - cx: &'a llvm::Context, - handler: &Handler, - ) -> Result<&'a llvm::Module, FatalError> { - let name = CString::new(name).unwrap(); - parse_module(cx, &name, self.data(), handler) - } } impl ModuleBufferMethods for ModuleBuffer { @@ -723,7 +721,7 @@ pub unsafe fn optimize_thin_module( // Like with "fat" LTO, get some better optimizations if landing pads // are disabled by removing all landing pads. if cgcx.no_landing_pads { - let _timer = cgcx.profile_activity("LLVM_remove_landing_pads"); + let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_remove_landing_pads"); llvm::LLVMRustMarkAllFunctionsNounwind(llmod); save_temp_bitcode(&cgcx, &module, "thin-lto-after-nounwind"); } @@ -736,26 +734,41 @@ pub unsafe fn optimize_thin_module( // // You can find some more comments about these functions in the LLVM // bindings we've got (currently `PassWrapper.cpp`) - if !llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod) { - let msg = "failed to prepare thin LTO module"; - return Err(write::llvm_err(&diag_handler, msg)) + { + let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_rename"); + if !llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod) { + let msg = "failed to prepare thin LTO module"; + return Err(write::llvm_err(&diag_handler, msg)) + } + save_temp_bitcode(cgcx, &module, "thin-lto-after-rename"); } - save_temp_bitcode(cgcx, &module, "thin-lto-after-rename"); - if !llvm::LLVMRustPrepareThinLTOResolveWeak(thin_module.shared.data.0, llmod) { - let msg = "failed to prepare thin LTO module"; - return Err(write::llvm_err(&diag_handler, msg)) + + { + let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_resolve_weak"); + if !llvm::LLVMRustPrepareThinLTOResolveWeak(thin_module.shared.data.0, llmod) { + let msg = "failed to prepare thin LTO module"; + return Err(write::llvm_err(&diag_handler, msg)) + } + save_temp_bitcode(cgcx, &module, "thin-lto-after-resolve"); } - save_temp_bitcode(cgcx, &module, "thin-lto-after-resolve"); - if !llvm::LLVMRustPrepareThinLTOInternalize(thin_module.shared.data.0, llmod) { - let msg = "failed to prepare thin LTO module"; - return Err(write::llvm_err(&diag_handler, msg)) + + { + let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_internalize"); + if !llvm::LLVMRustPrepareThinLTOInternalize(thin_module.shared.data.0, llmod) { + let msg = "failed to prepare thin LTO module"; + return Err(write::llvm_err(&diag_handler, msg)) + } + save_temp_bitcode(cgcx, &module, "thin-lto-after-internalize"); } - save_temp_bitcode(cgcx, &module, "thin-lto-after-internalize"); - if !llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod) { - let msg = "failed to prepare thin LTO module"; - return Err(write::llvm_err(&diag_handler, msg)) + + { + let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_import"); + if !llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod) { + let msg = "failed to prepare thin LTO module"; + return Err(write::llvm_err(&diag_handler, msg)) + } + save_temp_bitcode(cgcx, &module, "thin-lto-after-import"); } - save_temp_bitcode(cgcx, &module, "thin-lto-after-import"); // Ok now this is a bit unfortunate. This is also something you won't // find upstream in LLVM's ThinLTO passes! This is a hack for now to @@ -786,18 +799,24 @@ pub unsafe fn optimize_thin_module( // not too much) but for now at least gets LLVM to emit valid DWARF (or // so it appears). Hopefully we can remove this once upstream bugs are // fixed in LLVM. - llvm::LLVMRustThinLTOPatchDICompileUnit(llmod, cu1); - save_temp_bitcode(cgcx, &module, "thin-lto-after-patch"); + { + let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_patch_debuginfo"); + llvm::LLVMRustThinLTOPatchDICompileUnit(llmod, cu1); + save_temp_bitcode(cgcx, &module, "thin-lto-after-patch"); + } // Alright now that we've done everything related to the ThinLTO // analysis it's time to run some optimizations! Here we use the same // `run_pass_manager` as the "fat" LTO above except that we tell it to // populate a thin-specific pass manager, which presumably LLVM treats a // little differently. - info!("running thin lto passes over {}", module.name); - let config = cgcx.config(module.kind); - run_pass_manager(cgcx, &module, config, true); - save_temp_bitcode(cgcx, &module, "thin-lto-after-pm"); + { + let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_optimize"); + info!("running thin lto passes over {}", module.name); + let config = cgcx.config(module.kind); + run_pass_manager(cgcx, &module, config, true); + save_temp_bitcode(cgcx, &module, "thin-lto-after-pm"); + } } Ok(module) } diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs index 253110dcb34c0..78db90b57b53d 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/src/librustc_codegen_llvm/back/write.rs @@ -306,6 +306,8 @@ pub(crate) unsafe fn optimize(cgcx: &CodegenContext, config: &ModuleConfig) -> Result<(), FatalError> { + let _timer = cgcx.prof.generic_activity("LLVM_module_optimize"); + let llmod = module.module_llvm.llmod(); let llcx = &*module.module_llvm.llcx; let tm = &*module.module_llvm.tm; @@ -423,7 +425,7 @@ pub(crate) unsafe fn optimize(cgcx: &CodegenContext, // Finally, run the actual optimization passes { - let _timer = cgcx.profile_activity("LLVM_function_passes"); + let _timer = cgcx.prof.generic_activity("LLVM_module_optimize_function_passes"); time_ext(config.time_passes, None, &format!("llvm function passes [{}]", module_name.unwrap()), @@ -432,7 +434,7 @@ pub(crate) unsafe fn optimize(cgcx: &CodegenContext, }); } { - let _timer = cgcx.profile_activity("LLVM_module_passes"); + let _timer = cgcx.prof.generic_activity("LLVM_module_optimize_module_passes"); time_ext(config.time_passes, None, &format!("llvm module passes [{}]", module_name.unwrap()), @@ -454,7 +456,7 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext, config: &ModuleConfig) -> Result { - let _timer = cgcx.profile_activity("codegen"); + let _timer = cgcx.prof.generic_activity("LLVM_module_codegen"); { let llmod = module.module_llvm.llmod(); let llcx = &*module.module_llvm.llcx; @@ -505,12 +507,12 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext, if write_bc || config.emit_bc_compressed || config.embed_bitcode { - let _timer = cgcx.profile_activity("LLVM_make_bitcode"); + let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_make_bitcode"); let thin = ThinBuffer::new(llmod); let data = thin.data(); if write_bc { - let _timer = cgcx.profile_activity("LLVM_emit_bitcode"); + let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_emit_bitcode"); if let Err(e) = fs::write(&bc_out, data) { let msg = format!("failed to write bytecode to {}: {}", bc_out.display(), e); diag_handler.err(&msg); @@ -518,12 +520,13 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext, } if config.embed_bitcode { - let _timer = cgcx.profile_activity("LLVM_embed_bitcode"); + let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_embed_bitcode"); embed_bitcode(cgcx, llcx, llmod, Some(data)); } if config.emit_bc_compressed { - let _timer = cgcx.profile_activity("LLVM_compress_bitcode"); + let _timer = + cgcx.prof.generic_activity("LLVM_module_codegen_emit_compressed_bitcode"); let dst = bc_out.with_extension(RLIB_BYTECODE_EXTENSION); let data = bytecode::encode(&module.name, data); if let Err(e) = fs::write(&dst, data) { @@ -538,7 +541,7 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext, time_ext(config.time_passes, None, &format!("codegen passes [{}]", module_name.unwrap()), || -> Result<(), FatalError> { if config.emit_ir { - let _timer = cgcx.profile_activity("LLVM_emit_ir"); + let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_emit_ir"); let out = cgcx.output_filenames.temp_path(OutputType::LlvmAssembly, module_name); let out_c = path_to_c_string(&out); @@ -585,7 +588,7 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext, } if config.emit_asm || asm_to_obj { - let _timer = cgcx.profile_activity("LLVM_emit_asm"); + let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_emit_asm"); let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name); // We can't use the same module for asm and binary output, because that triggers @@ -603,13 +606,13 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext, } if write_obj { - let _timer = cgcx.profile_activity("LLVM_emit_obj"); + let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_emit_obj"); with_codegen(tm, llmod, config.no_builtins, |cpm| { write_output_file(diag_handler, tm, cpm, llmod, &obj_out, llvm::FileType::ObjectFile) })?; } else if asm_to_obj { - let _timer = cgcx.profile_activity("LLVM_asm_to_obj"); + let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_asm_to_obj"); let assembly = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name); run_assembler(cgcx, diag_handler, &assembly, &obj_out); diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs index 5758cdbebf7d7..bd7d0d4017dce 100644 --- a/src/librustc_codegen_llvm/base.rs +++ b/src/librustc_codegen_llvm/base.rs @@ -108,6 +108,7 @@ pub fn compile_codegen_unit( cgu_name: InternedString, tx_to_llvm_workers: &std::sync::mpsc::Sender>, ) { + let prof_timer = tcx.prof.generic_activity("codegen_module"); let start_time = Instant::now(); let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx); @@ -119,6 +120,7 @@ pub fn compile_codegen_unit( dep_graph::hash_result, ); let time_to_codegen = start_time.elapsed(); + drop(prof_timer); // We assume that the cost to run LLVM on a CGU is proportional to // the time we needed for codegenning it. diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs index 2a63011c2f545..9bacd8a5f56ba 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -323,8 +323,9 @@ impl CodegenBackend for LlvmCodegenBackend { // Run the linker on any artifacts that resulted from the LLVM run. // This should produce either a finished executable or library. - sess.profiler(|p| p.start_activity("link_crate")); time(sess, "linking", || { + let _prof_timer = sess.prof.generic_activity("link_crate"); + use rustc_codegen_ssa::back::link::link_binary; use crate::back::archive::LlvmArchiveBuilder; @@ -337,7 +338,6 @@ impl CodegenBackend for LlvmCodegenBackend { target_cpu, ); }); - sess.profiler(|p| p.end_activity("link_crate")); // Now that we won't touch anything in the incremental compilation directory // any more, we can finalize it (which involves renaming it) diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index 3c5fbfd0f866f..f1cfac2703322 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/src/librustc_codegen_ssa/back/write.rs @@ -19,7 +19,7 @@ use rustc::util::nodemap::FxHashMap; use rustc::hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc::ty::TyCtxt; use rustc::util::common::{time_depth, set_time_depth, print_time_passes_entry}; -use rustc::util::profiling::SelfProfiler; +use rustc::util::profiling::SelfProfilerRef; use rustc_fs_util::link_or_copy; use rustc_data_structures::svh::Svh; use rustc_errors::{Handler, Level, FatalError, DiagnosticId}; @@ -31,7 +31,6 @@ use syntax_pos::symbol::{Symbol, sym}; use jobserver::{Client, Acquired}; use std::any::Any; -use std::borrow::Cow; use std::fs; use std::io; use std::mem; @@ -196,42 +195,13 @@ impl Clone for TargetMachineFactory { } } -pub struct ProfileGenericActivityTimer { - profiler: Option>, - label: Cow<'static, str>, -} - -impl ProfileGenericActivityTimer { - pub fn start( - profiler: Option>, - label: Cow<'static, str>, - ) -> ProfileGenericActivityTimer { - if let Some(profiler) = &profiler { - profiler.start_activity(label.clone()); - } - - ProfileGenericActivityTimer { - profiler, - label, - } - } -} - -impl Drop for ProfileGenericActivityTimer { - fn drop(&mut self) { - if let Some(profiler) = &self.profiler { - profiler.end_activity(self.label.clone()); - } - } -} - /// Additional resources used by optimize_and_codegen (not module specific) #[derive(Clone)] pub struct CodegenContext { // Resources needed when running LTO pub backend: B, pub time_passes: bool, - pub profiler: Option>, + pub prof: SelfProfilerRef, pub lto: Lto, pub no_landing_pads: bool, pub save_temps: bool, @@ -283,31 +253,6 @@ impl CodegenContext { ModuleKind::Allocator => &self.allocator_module_config, } } - - #[inline(never)] - #[cold] - fn profiler_active ()>(&self, f: F) { - match &self.profiler { - None => bug!("profiler_active() called but there was no profiler active"), - Some(profiler) => { - f(&*profiler); - } - } - } - - #[inline(always)] - pub fn profile ()>(&self, f: F) { - if unlikely!(self.profiler.is_some()) { - self.profiler_active(f) - } - } - - pub fn profile_activity( - &self, - label: impl Into>, - ) -> ProfileGenericActivityTimer { - ProfileGenericActivityTimer::start(self.profiler.clone(), label.into()) - } } fn generate_lto_work( @@ -316,7 +261,7 @@ fn generate_lto_work( needs_thin_lto: Vec<(String, B::ThinBuffer)>, import_only_modules: Vec<(SerializedModule, WorkProduct)> ) -> Vec<(WorkItem, u64)> { - cgcx.profile(|p| p.start_activity("codegen_run_lto")); + let _prof_timer = cgcx.prof.generic_activity("codegen_run_lto"); let (lto_modules, copy_jobs) = if !needs_fat_lto.is_empty() { assert!(needs_thin_lto.is_empty()); @@ -343,8 +288,6 @@ fn generate_lto_work( }), 0) })).collect(); - cgcx.profile(|p| p.end_activity("codegen_run_lto")); - result } @@ -380,6 +323,9 @@ pub fn start_async_codegen( ) -> OngoingCodegen { let (coordinator_send, coordinator_receive) = channel(); let sess = tcx.sess; + + sess.prof.generic_activity_start("codegen_and_optimize_crate"); + let crate_name = tcx.crate_name(LOCAL_CRATE); let crate_hash = tcx.crate_hash(LOCAL_CRATE); let no_builtins = attr::contains_name(&tcx.hir().krate().attrs, sym::no_builtins); @@ -1088,7 +1034,7 @@ fn start_executing_work( save_temps: sess.opts.cg.save_temps, opts: Arc::new(sess.opts.clone()), time_passes: sess.time_extended(), - profiler: sess.self_profiling.clone(), + prof: sess.prof.clone(), exported_symbols, plugin_passes: sess.plugin_llvm_passes.borrow().clone(), remark: sess.opts.cg.remark.clone(), @@ -1645,12 +1591,8 @@ fn spawn_work( // as a diagnostic was already sent off to the main thread - just // surface that there was an error in this worker. bomb.result = { - let label = work.name(); - cgcx.profile(|p| p.start_activity(label.clone())); - let result = execute_work_item(&cgcx, work).ok(); - cgcx.profile(|p| p.end_activity(label)); - - result + let _prof_timer = cgcx.prof.generic_activity(&work.name()); + execute_work_item(&cgcx, work).ok() }; }); } @@ -1835,6 +1777,8 @@ impl OngoingCodegen { self.backend.print_pass_timings() } + sess.prof.generic_activity_end("codegen_and_optimize_crate"); + (CodegenResults { crate_name: self.crate_name, crate_hash: self.crate_hash, diff --git a/src/librustc_codegen_ssa/base.rs b/src/librustc_codegen_ssa/base.rs index 90ed629bbc61e..250916d6279c4 100644 --- a/src/librustc_codegen_ssa/base.rs +++ b/src/librustc_codegen_ssa/base.rs @@ -559,7 +559,7 @@ pub fn codegen_crate( if need_metadata_module { // Codegen the encoded metadata. - tcx.sess.profiler(|p| p.start_activity("codegen crate metadata")); + let _prof_timer = tcx.prof.generic_activity("codegen_crate_metadata"); let metadata_cgu_name = cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], @@ -570,7 +570,6 @@ pub fn codegen_crate( backend.write_compressed_metadata(tcx, &ongoing_codegen.metadata, &mut metadata_llvm_module); }); - tcx.sess.profiler(|p| p.end_activity("codegen crate metadata")); let metadata_module = ModuleCodegen { name: metadata_cgu_name, @@ -599,11 +598,9 @@ pub fn codegen_crate( match cgu_reuse { CguReuse::No => { - tcx.sess.profiler(|p| p.start_activity(format!("codegen {}", cgu.name()))); let start_time = Instant::now(); backend.compile_codegen_unit(tcx, *cgu.name(), &ongoing_codegen.coordinator_send); total_codegen_time += start_time.elapsed(); - tcx.sess.profiler(|p| p.end_activity(format!("codegen {}", cgu.name()))); false } CguReuse::PreLto => { diff --git a/src/librustc_codegen_ssa/lib.rs b/src/librustc_codegen_ssa/lib.rs index 161d3ce61f0a6..5017a60ca699a 100644 --- a/src/librustc_codegen_ssa/lib.rs +++ b/src/librustc_codegen_ssa/lib.rs @@ -21,7 +21,6 @@ #[macro_use] extern crate log; #[macro_use] extern crate rustc; -#[macro_use] extern crate rustc_data_structures; #[macro_use] extern crate syntax; use std::path::PathBuf; diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index 13e2c5d1c574d..6af065513ee0d 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -28,6 +28,8 @@ pub fn save_dep_graph(tcx: TyCtxt<'_>) { join(move || { if tcx.sess.opts.debugging_opts.incremental_queries { + let _timer = tcx.prof.generic_activity("incr_comp_persist_result_cache"); + time(sess, "persist query result cache", || { save_in(sess, query_cache_path, @@ -36,6 +38,8 @@ pub fn save_dep_graph(tcx: TyCtxt<'_>) { } }, || { time(sess, "persist dep-graph", || { + let _timer = tcx.prof.generic_activity("incr_comp_persist_dep_graph"); + save_in(sess, dep_graph_path, |e| { @@ -135,6 +139,7 @@ fn encode_dep_graph(tcx: TyCtxt<'_>, encoder: &mut Encoder) { // Encode the graph data. let serialized_graph = time(tcx.sess, "getting serialized graph", || { + let _timer = tcx.prof.generic_activity("incr_comp_serialize_dep_graph"); tcx.dep_graph.serialize() }); @@ -214,6 +219,7 @@ fn encode_dep_graph(tcx: TyCtxt<'_>, encoder: &mut Encoder) { } time(tcx.sess, "encoding serialized graph", || { + let _timer = tcx.prof.generic_activity("incr_comp_encode_serialized_dep_graph"); serialized_graph.encode(encoder).unwrap(); }); } diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 8474bae5a71d2..13e95b0f72db7 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -59,15 +59,17 @@ use std::rc::Rc; pub fn parse<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> { sess.diagnostic() .set_continue_after_error(sess.opts.debugging_opts.continue_parse_after_error); - sess.profiler(|p| p.start_activity("parsing")); - let krate = time(sess, "parsing", || match *input { - Input::File(ref file) => parse::parse_crate_from_file(file, &sess.parse_sess), - Input::Str { - ref input, - ref name, - } => parse::parse_crate_from_source_str(name.clone(), input.clone(), &sess.parse_sess), + let krate = time(sess, "parsing", || { + let _prof_timer = sess.prof.generic_activity("parse_crate"); + + match *input { + Input::File(ref file) => parse::parse_crate_from_file(file, &sess.parse_sess), + Input::Str { + ref input, + ref name, + } => parse::parse_crate_from_source_str(name.clone(), input.clone(), &sess.parse_sess), + } })?; - sess.profiler(|p| p.end_activity("parsing")); sess.diagnostic().set_continue_after_error(true); @@ -355,8 +357,8 @@ fn configure_and_expand_inner<'a>( ); // Expand all macros - sess.profiler(|p| p.start_activity("macro expansion")); krate = time(sess, "expansion", || { + let _prof_timer = sess.prof.generic_activity("macro_expand_crate"); // Windows dlls do not have rpaths, so they don't know how to find their // dependencies. It's up to us to tell the system where to find all the // dependent dlls. Note that this uses cfg!(windows) as opposed to @@ -430,7 +432,6 @@ fn configure_and_expand_inner<'a>( } krate }); - sess.profiler(|p| p.end_activity("macro expansion")); time(sess, "maybe building test harness", || { syntax_ext::test_harness::inject( @@ -1071,11 +1072,10 @@ pub fn start_codegen<'tcx>( encode_and_write_metadata(tcx, outputs) }); - tcx.sess.profiler(|p| p.start_activity("codegen crate")); let codegen = time(tcx.sess, "codegen", move || { + let _prof_timer = tcx.prof.generic_activity("codegen_crate"); codegen_backend.codegen_crate(tcx, metadata, need_metadata_module) }); - tcx.sess.profiler(|p| p.end_activity("codegen crate")); if log_enabled!(::log::Level::Info) { println!("Post-codegen"); diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 00be1c84599a3..26a8f79b8d831 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -295,7 +295,7 @@ pub fn provide(providers: &mut Providers<'_>) { } pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorReported> { - tcx.sess.profiler(|p| p.start_activity("type-check crate")); + let _prof_timer = tcx.prof.generic_activity("type_check_crate"); // this ensures that later parts of type checking can assume that items // have valid types and not error @@ -347,8 +347,6 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorReported> { check_unused::check_crate(tcx); check_for_entry_fn(tcx); - tcx.sess.profiler(|p| p.end_activity("type-check crate")); - if tcx.sess.err_count() == 0 { Ok(()) } else { From 85f294537811c0e1a92f6bd42b521e7178ff2bb5 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Sat, 14 Sep 2019 14:11:31 -0400 Subject: [PATCH 21/32] [const-prop] Handle MIR Rvalue::Aggregates --- src/librustc_mir/transform/const_prop.rs | 8 +++++- src/test/compile-fail/consts/const-err3.rs | 1 + src/test/mir-opt/const_prop/aggregate.rs | 25 +++++++++++++++++++ src/test/run-fail/overflowing-rsh-5.rs | 1 + src/test/run-fail/overflowing-rsh-6.rs | 1 + src/test/ui/consts/const-err2.rs | 1 + src/test/ui/consts/const-err2.stderr | 8 +++++- src/test/ui/consts/const-err3.rs | 1 + src/test/ui/consts/const-err3.stderr | 8 +++++- src/test/ui/issues/issue-54348.rs | 2 ++ src/test/ui/issues/issue-54348.stderr | 16 ++++++++++-- src/test/ui/lint/lint-exceeding-bitshifts2.rs | 2 +- .../ui/lint/lint-exceeding-bitshifts2.stderr | 8 +++++- 13 files changed, 75 insertions(+), 7 deletions(-) create mode 100644 src/test/mir-opt/const_prop/aggregate.rs diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 5a57c3b9afe47..17389d2178003 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -461,13 +461,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // if this isn't a supported operation, then return None match rvalue { - Rvalue::Aggregate(..) | Rvalue::NullaryOp(NullOp::Box, _) | Rvalue::Discriminant(..) => return None, Rvalue::Use(_) | Rvalue::Len(_) | Rvalue::Repeat(..) | + Rvalue::Aggregate(..) | Rvalue::Cast(..) | Rvalue::NullaryOp(..) | Rvalue::CheckedBinaryOp(..) | @@ -560,6 +560,12 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { return None; } } + } else if let Rvalue::Aggregate(_, operands) = rvalue { + // FIXME(wesleywiser): const eval will turn this into a `const Scalar()` that + // `SimplifyLocals` doesn't know it can remove. + if operands.len() == 0 { + return None; + } } self.use_ecx(source_info, |this| { diff --git a/src/test/compile-fail/consts/const-err3.rs b/src/test/compile-fail/consts/const-err3.rs index fc10824f0c03c..add4eef13c784 100644 --- a/src/test/compile-fail/consts/const-err3.rs +++ b/src/test/compile-fail/consts/const-err3.rs @@ -14,6 +14,7 @@ fn main() { //~^ ERROR const_err let _e = [5u8][1]; //~^ ERROR const_err + //~| ERROR this expression will panic at runtime black_box(b); black_box(c); black_box(d); diff --git a/src/test/mir-opt/const_prop/aggregate.rs b/src/test/mir-opt/const_prop/aggregate.rs new file mode 100644 index 0000000000000..0937d37be6b6e --- /dev/null +++ b/src/test/mir-opt/const_prop/aggregate.rs @@ -0,0 +1,25 @@ +// compile-flags: -O + +fn main() { + let x = (0, 1, 2).1 + 0; +} + +// END RUST SOURCE +// START rustc.main.ConstProp.before.mir +// bb0: { +// ... +// _3 = (const 0i32, const 1i32, const 2i32); +// _2 = (_3.1: i32); +// _1 = Add(move _2, const 0i32); +// ... +// } +// END rustc.main.ConstProp.before.mir +// START rustc.main.ConstProp.after.mir +// bb0: { +// ... +// _3 = (const 0i32, const 1i32, const 2i32); +// _2 = const 1i32; +// _1 = Add(move _2, const 0i32); +// ... +// } +// END rustc.main.ConstProp.after.mir diff --git a/src/test/run-fail/overflowing-rsh-5.rs b/src/test/run-fail/overflowing-rsh-5.rs index 793f495240d57..58dfc5710ae4e 100644 --- a/src/test/run-fail/overflowing-rsh-5.rs +++ b/src/test/run-fail/overflowing-rsh-5.rs @@ -2,6 +2,7 @@ // compile-flags: -C debug-assertions #![warn(exceeding_bitshifts)] +#![warn(const_err)] fn main() { let _n = 1i64 >> [64][0]; diff --git a/src/test/run-fail/overflowing-rsh-6.rs b/src/test/run-fail/overflowing-rsh-6.rs index d6b2f8dc9f9af..c2fec5e4860af 100644 --- a/src/test/run-fail/overflowing-rsh-6.rs +++ b/src/test/run-fail/overflowing-rsh-6.rs @@ -2,6 +2,7 @@ // compile-flags: -C debug-assertions #![warn(exceeding_bitshifts)] +#![warn(const_err)] #![feature(const_indexing)] fn main() { diff --git a/src/test/ui/consts/const-err2.rs b/src/test/ui/consts/const-err2.rs index ecbcc2a4b496f..e5ee90fc9f11f 100644 --- a/src/test/ui/consts/const-err2.rs +++ b/src/test/ui/consts/const-err2.rs @@ -23,6 +23,7 @@ fn main() { //~^ ERROR const_err let _e = [5u8][1]; //~^ ERROR index out of bounds + //~| ERROR this expression will panic at runtime black_box(a); black_box(b); black_box(c); diff --git a/src/test/ui/consts/const-err2.stderr b/src/test/ui/consts/const-err2.stderr index 1d84d44dc27b3..0a09a7213dabc 100644 --- a/src/test/ui/consts/const-err2.stderr +++ b/src/test/ui/consts/const-err2.stderr @@ -34,5 +34,11 @@ error: index out of bounds: the len is 1 but the index is 1 LL | let _e = [5u8][1]; | ^^^^^^^^ -error: aborting due to 5 previous errors +error: this expression will panic at runtime + --> $DIR/const-err2.rs:24:14 + | +LL | let _e = [5u8][1]; + | ^^^^^^^^ index out of bounds: the len is 1 but the index is 1 + +error: aborting due to 6 previous errors diff --git a/src/test/ui/consts/const-err3.rs b/src/test/ui/consts/const-err3.rs index a9cf04cda7a5a..89373f99f75c2 100644 --- a/src/test/ui/consts/const-err3.rs +++ b/src/test/ui/consts/const-err3.rs @@ -23,6 +23,7 @@ fn main() { //~^ ERROR const_err let _e = [5u8][1]; //~^ ERROR const_err + //~| ERROR this expression will panic at runtime black_box(a); black_box(b); black_box(c); diff --git a/src/test/ui/consts/const-err3.stderr b/src/test/ui/consts/const-err3.stderr index 0602707be7040..42de247c8f7e0 100644 --- a/src/test/ui/consts/const-err3.stderr +++ b/src/test/ui/consts/const-err3.stderr @@ -34,5 +34,11 @@ error: index out of bounds: the len is 1 but the index is 1 LL | let _e = [5u8][1]; | ^^^^^^^^ -error: aborting due to 5 previous errors +error: this expression will panic at runtime + --> $DIR/const-err3.rs:24:14 + | +LL | let _e = [5u8][1]; + | ^^^^^^^^ index out of bounds: the len is 1 but the index is 1 + +error: aborting due to 6 previous errors diff --git a/src/test/ui/issues/issue-54348.rs b/src/test/ui/issues/issue-54348.rs index 68d838054776e..e7221e2cbb1e1 100644 --- a/src/test/ui/issues/issue-54348.rs +++ b/src/test/ui/issues/issue-54348.rs @@ -1,5 +1,7 @@ fn main() { [1][0u64 as usize]; [1][1.5 as usize]; //~ ERROR index out of bounds + //~| ERROR this expression will panic at runtime [1][1u64 as usize]; //~ ERROR index out of bounds + //~| ERROR this expression will panic at runtime } diff --git a/src/test/ui/issues/issue-54348.stderr b/src/test/ui/issues/issue-54348.stderr index fa77bd6fd7797..79320ef4f31c7 100644 --- a/src/test/ui/issues/issue-54348.stderr +++ b/src/test/ui/issues/issue-54348.stderr @@ -6,11 +6,23 @@ LL | [1][1.5 as usize]; | = note: `#[deny(const_err)]` on by default +error: this expression will panic at runtime + --> $DIR/issue-54348.rs:3:5 + | +LL | [1][1.5 as usize]; + | ^^^^^^^^^^^^^^^^^ index out of bounds: the len is 1 but the index is 1 + error: index out of bounds: the len is 1 but the index is 1 - --> $DIR/issue-54348.rs:4:5 + --> $DIR/issue-54348.rs:5:5 | LL | [1][1u64 as usize]; | ^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: this expression will panic at runtime + --> $DIR/issue-54348.rs:5:5 + | +LL | [1][1u64 as usize]; + | ^^^^^^^^^^^^^^^^^^ index out of bounds: the len is 1 but the index is 1 + +error: aborting due to 4 previous errors diff --git a/src/test/ui/lint/lint-exceeding-bitshifts2.rs b/src/test/ui/lint/lint-exceeding-bitshifts2.rs index 69b627355b801..2c213daddd752 100644 --- a/src/test/ui/lint/lint-exceeding-bitshifts2.rs +++ b/src/test/ui/lint/lint-exceeding-bitshifts2.rs @@ -8,7 +8,7 @@ fn main() { let n = 1u8 << (4+3); let n = 1u8 << (4+4); //~ ERROR: attempt to shift left with overflow let n = 1i64 >> [63][0]; - let n = 1i64 >> [64][0]; // should be linting, needs to wait for const propagation + let n = 1i64 >> [64][0]; //~ ERROR: attempt to shift right with overflow #[cfg(target_pointer_width = "32")] const BITS: usize = 32; diff --git a/src/test/ui/lint/lint-exceeding-bitshifts2.stderr b/src/test/ui/lint/lint-exceeding-bitshifts2.stderr index cb96982a78930..d9c76d233d03e 100644 --- a/src/test/ui/lint/lint-exceeding-bitshifts2.stderr +++ b/src/test/ui/lint/lint-exceeding-bitshifts2.stderr @@ -10,6 +10,12 @@ note: lint level defined here LL | #![deny(exceeding_bitshifts, const_err)] | ^^^^^^^^^^^^^^^^^^^ +error: attempt to shift right with overflow + --> $DIR/lint-exceeding-bitshifts2.rs:11:15 + | +LL | let n = 1i64 >> [64][0]; + | ^^^^^^^^^^^^^^^ + error: attempt to shift left with overflow --> $DIR/lint-exceeding-bitshifts2.rs:17:15 | @@ -22,5 +28,5 @@ error: attempt to shift left with overflow LL | let n = 1_usize << BITS; | ^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors From ea78010fe95126e2324eaecc1ce14f274a88c354 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Sun, 15 Sep 2019 00:05:19 -0400 Subject: [PATCH 22/32] [const-prop] Handle MIR Rvalue::Discriminant --- src/librustc_mir/transform/const_prop.rs | 4 +- src/test/mir-opt/const_prop/discriminant.rs | 53 +++++++++++++++++++++ 2 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 src/test/mir-opt/const_prop/discriminant.rs diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 17389d2178003..58d87b4e8ca19 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -461,13 +461,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // if this isn't a supported operation, then return None match rvalue { - Rvalue::NullaryOp(NullOp::Box, _) | - Rvalue::Discriminant(..) => return None, + Rvalue::NullaryOp(NullOp::Box, _) => return None, Rvalue::Use(_) | Rvalue::Len(_) | Rvalue::Repeat(..) | Rvalue::Aggregate(..) | + Rvalue::Discriminant(..) | Rvalue::Cast(..) | Rvalue::NullaryOp(..) | Rvalue::CheckedBinaryOp(..) | diff --git a/src/test/mir-opt/const_prop/discriminant.rs b/src/test/mir-opt/const_prop/discriminant.rs new file mode 100644 index 0000000000000..07bbd9202b940 --- /dev/null +++ b/src/test/mir-opt/const_prop/discriminant.rs @@ -0,0 +1,53 @@ +// compile-flags: -O + +fn main() { + let x = (if let Some(true) = Some(true) { 42 } else { 10 }) + 0; +} + +// END RUST SOURCE +// START rustc.main.ConstProp.before.mir +// bb0: { +// ... +// _3 = std::option::Option::::Some(const true,); +// _4 = discriminant(_3); +// switchInt(move _4) -> [1isize: bb3, otherwise: bb2]; +// } +// bb1: { +// _2 = const 42i32; +// goto -> bb4; +// } +// bb2: { +// _2 = const 10i32; +// goto -> bb4; +// } +// bb3: { +// switchInt(((_3 as Some).0: bool)) -> [false: bb2, otherwise: bb1]; +// } +// bb4: { +// _1 = Add(move _2, const 0i32); +// ... +// } +// END rustc.main.ConstProp.before.mir +// START rustc.main.ConstProp.after.mir +// bb0: { +// ... +// _3 = const Scalar(0x01) : std::option::Option; +// _4 = const 1isize; +// switchInt(const 1isize) -> [1isize: bb3, otherwise: bb2]; +// } +// bb1: { +// _2 = const 42i32; +// goto -> bb4; +// } +// bb2: { +// _2 = const 10i32; +// goto -> bb4; +// } +// bb3: { +// switchInt(const true) -> [false: bb2, otherwise: bb1]; +// } +// bb4: { +// _1 = Add(move _2, const 0i32); +// ... +// } +// END rustc.main.ConstProp.after.mir From b3234a34fd4f2c11f6a622800989d6178730253e Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Sun, 15 Sep 2019 12:03:52 -0400 Subject: [PATCH 23/32] [const-prop] Handle MIR Rvalue::Box --- src/librustc_mir/transform/const_prop.rs | 19 +-------- src/test/mir-opt/const_prop/boxes.rs | 53 ++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 18 deletions(-) create mode 100644 src/test/mir-opt/const_prop/boxes.rs diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 58d87b4e8ca19..c586e36412a4f 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -8,7 +8,7 @@ use rustc::hir::def::DefKind; use rustc::hir::def_id::DefId; use rustc::mir::{ AggregateKind, Constant, Location, Place, PlaceBase, Body, Operand, Rvalue, - Local, NullOp, UnOp, StatementKind, Statement, LocalKind, + Local, UnOp, StatementKind, Statement, LocalKind, TerminatorKind, Terminator, ClearCrossCrate, SourceInfo, BinOp, SourceScope, SourceScopeLocalData, LocalDecl, BasicBlock, }; @@ -459,23 +459,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { ) -> Option> { let span = source_info.span; - // if this isn't a supported operation, then return None - match rvalue { - Rvalue::NullaryOp(NullOp::Box, _) => return None, - - Rvalue::Use(_) | - Rvalue::Len(_) | - Rvalue::Repeat(..) | - Rvalue::Aggregate(..) | - Rvalue::Discriminant(..) | - Rvalue::Cast(..) | - Rvalue::NullaryOp(..) | - Rvalue::CheckedBinaryOp(..) | - Rvalue::Ref(..) | - Rvalue::UnaryOp(..) | - Rvalue::BinaryOp(..) => { } - } - // perform any special checking for specific Rvalue types if let Rvalue::UnaryOp(op, arg) = rvalue { trace!("checking UnaryOp(op = {:?}, arg = {:?})", op, arg); diff --git a/src/test/mir-opt/const_prop/boxes.rs b/src/test/mir-opt/const_prop/boxes.rs new file mode 100644 index 0000000000000..52a7f7ee79503 --- /dev/null +++ b/src/test/mir-opt/const_prop/boxes.rs @@ -0,0 +1,53 @@ +// compile-flags: -O + +#![feature(box_syntax)] + +// Note: this test verifies that we, in fact, do not const prop `box` + +fn main() { + let x = *(box 42) + 0; +} + +// END RUST SOURCE +// START rustc.main.ConstProp.before.mir +// bb0: { +// ... +// _4 = Box(i32); +// (*_4) = const 42i32; +// _3 = move _4; +// ... +// _2 = (*_3); +// _1 = Add(move _2, const 0i32); +// ... +// drop(_3) -> [return: bb2, unwind: bb1]; +// } +// bb1 (cleanup): { +// resume; +// } +// bb2: { +// ... +// _0 = (); +// ... +// } +// END rustc.main.ConstProp.before.mir +// START rustc.main.ConstProp.after.mir +// bb0: { +// ... +// _4 = Box(i32); +// (*_4) = const 42i32; +// _3 = move _4; +// ... +// _2 = (*_3); +// _1 = Add(move _2, const 0i32); +// ... +// drop(_3) -> [return: bb2, unwind: bb1]; +// } +// bb1 (cleanup): { +// resume; +// } +// bb2: { +// ... +// _0 = (); +// ... +// } +// END rustc.main.ConstProp.after.mir From 5804c3b2f83c53ea6fc1a95852e20f627128faf6 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Sun, 15 Sep 2019 12:08:09 -0400 Subject: [PATCH 24/32] Cleanup const_prop() some --- src/librustc_mir/transform/const_prop.rs | 147 ++++++++++++----------- 1 file changed, 75 insertions(+), 72 deletions(-) diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index c586e36412a4f..e9ede29bc486c 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -118,7 +118,7 @@ impl<'tcx> MirPass<'tcx> for ConstProp { struct ConstPropMachine; impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { - type MemoryKinds= !; + type MemoryKinds = !; type PointerTag = (); type ExtraFnVal = !; @@ -460,79 +460,80 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let span = source_info.span; // perform any special checking for specific Rvalue types - if let Rvalue::UnaryOp(op, arg) = rvalue { - trace!("checking UnaryOp(op = {:?}, arg = {:?})", op, arg); - let overflow_check = self.tcx.sess.overflow_checks(); - - self.use_ecx(source_info, |this| { - // We check overflow in debug mode already - // so should only check in release mode. - if *op == UnOp::Neg && !overflow_check { - let ty = arg.ty(&this.local_decls, this.tcx); - - if ty.is_integral() { - let arg = this.ecx.eval_operand(arg, None)?; - let prim = this.ecx.read_immediate(arg)?; - // Need to do overflow check here: For actual CTFE, MIR - // generation emits code that does this before calling the op. - if prim.to_bits()? == (1 << (prim.layout.size.bits() - 1)) { - throw_panic!(OverflowNeg) + match rvalue { + Rvalue::UnaryOp(UnOp::Neg, arg) => { + trace!("checking UnaryOp(op = Neg, arg = {:?})", arg); + let overflow_check = self.tcx.sess.overflow_checks(); + + self.use_ecx(source_info, |this| { + // We check overflow in debug mode already + // so should only check in release mode. + if !overflow_check { + let ty = arg.ty(&this.local_decls, this.tcx); + + if ty.is_integral() { + let arg = this.ecx.eval_operand(arg, None)?; + let prim = this.ecx.read_immediate(arg)?; + // Need to do overflow check here: For actual CTFE, MIR + // generation emits code that does this before calling the op. + if prim.to_bits()? == (1 << (prim.layout.size.bits() - 1)) { + throw_panic!(OverflowNeg) + } } } - } - Ok(()) - })?; - } else if let Rvalue::BinaryOp(op, left, right) = rvalue { - trace!("checking BinaryOp(op = {:?}, left = {:?}, right = {:?})", op, left, right); - - let r = self.use_ecx(source_info, |this| { - this.ecx.read_immediate(this.ecx.eval_operand(right, None)?) - })?; - if *op == BinOp::Shr || *op == BinOp::Shl { - let left_bits = place_layout.size.bits(); - let right_size = r.layout.size; - let r_bits = r.to_scalar().and_then(|r| r.to_bits(right_size)); - if r_bits.ok().map_or(false, |b| b >= left_bits as u128) { - let source_scope_local_data = match self.source_scope_local_data { - ClearCrossCrate::Set(ref data) => data, - ClearCrossCrate::Clear => return None, - }; - let dir = if *op == BinOp::Shr { - "right" - } else { - "left" - }; - let hir_id = source_scope_local_data[source_info.scope].lint_root; - self.tcx.lint_hir( - ::rustc::lint::builtin::EXCEEDING_BITSHIFTS, - hir_id, - span, - &format!("attempt to shift {} with overflow", dir)); - return None; - } + Ok(()) + })?; } - self.use_ecx(source_info, |this| { - let l = this.ecx.read_immediate(this.ecx.eval_operand(left, None)?)?; - let (_, overflow, _ty) = this.ecx.overflowing_binary_op(*op, l, r)?; - - // We check overflow in debug mode already - // so should only check in release mode. - if !this.tcx.sess.overflow_checks() && overflow { - let err = err_panic!(Overflow(*op)).into(); - return Err(err); + + Rvalue::BinaryOp(op, left, right) => { + trace!("checking BinaryOp(op = {:?}, left = {:?}, right = {:?})", op, left, right); + + let r = self.use_ecx(source_info, |this| { + this.ecx.read_immediate(this.ecx.eval_operand(right, None)?) + })?; + if *op == BinOp::Shr || *op == BinOp::Shl { + let left_bits = place_layout.size.bits(); + let right_size = r.layout.size; + let r_bits = r.to_scalar().and_then(|r| r.to_bits(right_size)); + if r_bits.ok().map_or(false, |b| b >= left_bits as u128) { + let source_scope_local_data = match self.source_scope_local_data { + ClearCrossCrate::Set(ref data) => data, + ClearCrossCrate::Clear => return None, + }; + let dir = if *op == BinOp::Shr { + "right" + } else { + "left" + }; + let hir_id = source_scope_local_data[source_info.scope].lint_root; + self.tcx.lint_hir( + ::rustc::lint::builtin::EXCEEDING_BITSHIFTS, + hir_id, + span, + &format!("attempt to shift {} with overflow", dir)); + return None; + } } + self.use_ecx(source_info, |this| { + let l = this.ecx.read_immediate(this.ecx.eval_operand(left, None)?)?; + let (_, overflow, _ty) = this.ecx.overflowing_binary_op(*op, l, r)?; + + // We check overflow in debug mode already + // so should only check in release mode. + if !this.tcx.sess.overflow_checks() && overflow { + let err = err_panic!(Overflow(*op)).into(); + return Err(err); + } - Ok(()) - })?; - } else if let Rvalue::Ref(_, _, place) = rvalue { - trace!("checking Ref({:?})", place); - // FIXME(wesleywiser) we don't currently handle the case where we try to make a ref - // from a function argument that hasn't been assigned to in this function. - if let Place { - base: PlaceBase::Local(local), - projection: box [] - } = place { + Ok(()) + })?; + } + + Rvalue::Ref(_, _, Place { base: PlaceBase::Local(local), projection: box [] }) => { + trace!("checking Ref({:?})", place); + // FIXME(wesleywiser) we don't currently handle the case where we try to make a ref + // from a function argument that hasn't been assigned to in this function. let alive = if let LocalValue::Live(_) = self.ecx.frame().locals[*local].value { true @@ -543,12 +544,14 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { return None; } } - } else if let Rvalue::Aggregate(_, operands) = rvalue { - // FIXME(wesleywiser): const eval will turn this into a `const Scalar()` that - // `SimplifyLocals` doesn't know it can remove. - if operands.len() == 0 { + + Rvalue::Aggregate(_, operands) if operands.len() == 0 => { + // FIXME(wesleywiser): const eval will turn this into a `const Scalar()` that + // `SimplifyLocals` doesn't know it can remove. return None; } + + _ => { } } self.use_ecx(source_info, |this| { From 1a1067d1a537d6495f6aa9703e10119f05d578ad Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Mon, 30 Sep 2019 16:27:28 -0400 Subject: [PATCH 25/32] Make the default parallelism 1 This changes the default parallelism for parallel compilers to one, instead of the previous default, which was "num cpus". This is likely not an optimal default long-term, but it is a good default for testing whether parallel compilers are not a significant regression over a sequential compiler. Notably, this in theory makes a parallel-enabled compiler behave exactly like a sequential compiler with respect to the jobserver. --- src/librustc/session/config.rs | 19 ++++++++++++++++--- src/librustc/session/mod.rs | 8 +------- src/librustc_interface/interface.rs | 5 ++++- src/librustc_interface/util.rs | 6 +++--- 4 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 5eda3df378126..ca8e503bdf0b3 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -813,6 +813,7 @@ macro_rules! options { pub const parse_list: Option<&str> = Some("a space-separated list of strings"); pub const parse_opt_list: Option<&str> = Some("a space-separated list of strings"); pub const parse_opt_comma_list: Option<&str> = Some("a comma-separated list of strings"); + pub const parse_threads: Option<&str> = Some("a number"); pub const parse_uint: Option<&str> = Some("a number"); pub const parse_passes: Option<&str> = Some("a space-separated list of passes, or `all`"); @@ -956,6 +957,14 @@ macro_rules! options { } } + fn parse_threads(slot: &mut usize, v: Option<&str>) -> bool { + match v.and_then(|s| s.parse().ok()) { + Some(0) => { *slot = ::num_cpus::get(); true }, + Some(i) => { *slot = i; true }, + None => false + } + } + fn parse_uint(slot: &mut usize, v: Option<&str>) -> bool { match v.and_then(|s| s.parse().ok()) { Some(i) => { *slot = i; true }, @@ -1259,7 +1268,11 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "prints the LLVM optimization passes being run"), ast_json: bool = (false, parse_bool, [UNTRACKED], "print the AST as JSON and halt"), - threads: Option = (None, parse_opt_uint, [UNTRACKED], + // We default to 1 here since we want to behave like + // a sequential compiler for now. This'll likely be adjusted + // in the future. Note that -Zthreads=0 is the way to get + // the num_cpus behavior. + threads: usize = (1, parse_threads, [UNTRACKED], "use a thread pool with N threads"), ast_json_noexpand: bool = (false, parse_bool, [UNTRACKED], "print the pre-expansion AST as JSON and halt"), @@ -2160,14 +2173,14 @@ pub fn build_session_options_and_crate_config( } } - if debugging_opts.threads == Some(0) { + if debugging_opts.threads == 0 { early_error( error_format, "value for threads must be a positive non-zero integer", ); } - if debugging_opts.threads.unwrap_or(1) > 1 && debugging_opts.fuel.is_some() { + if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() { early_error( error_format, "optimization fuel is incompatible with multiple threads", diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index a24fed8f21c5a..52f120ba4ca3f 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -897,16 +897,10 @@ impl Session { ret } - /// Returns the number of query threads that should be used for this - /// compilation - pub fn threads_from_count(query_threads: Option) -> usize { - query_threads.unwrap_or(::num_cpus::get()) - } - /// Returns the number of query threads that should be used for this /// compilation pub fn threads(&self) -> usize { - Self::threads_from_count(self.opts.debugging_opts.threads) + self.opts.debugging_opts.threads } /// Returns the number of codegen units that should be used for this diff --git a/src/librustc_interface/interface.rs b/src/librustc_interface/interface.rs index fef60a47dc4e7..dae8fb242d58c 100644 --- a/src/librustc_interface/interface.rs +++ b/src/librustc_interface/interface.rs @@ -147,5 +147,8 @@ where F: FnOnce() -> R + Send, R: Send, { - util::spawn_thread_pool(edition, None, &None, f) + // the 1 here is duplicating code in config.opts.debugging_opts.threads + // which also defaults to 1; it ultimately doesn't matter as the default + // isn't threaded, and just ignores this parameter + util::spawn_thread_pool(edition, 1, &None, f) } diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs index b81f814de0f4a..0439aaa9463e6 100644 --- a/src/librustc_interface/util.rs +++ b/src/librustc_interface/util.rs @@ -173,7 +173,7 @@ pub fn scoped_thread R + Send, R: Send>(cfg: thread::Builder, f: #[cfg(not(parallel_compiler))] pub fn spawn_thread_pool R + Send, R: Send>( edition: Edition, - _threads: Option, + _threads: usize, stderr: &Option>>>, f: F, ) -> R { @@ -198,7 +198,7 @@ pub fn spawn_thread_pool R + Send, R: Send>( #[cfg(parallel_compiler)] pub fn spawn_thread_pool R + Send, R: Send>( edition: Edition, - threads: Option, + threads: usize, stderr: &Option>>>, f: F, ) -> R { @@ -209,7 +209,7 @@ pub fn spawn_thread_pool R + Send, R: Send>( let mut config = ThreadPoolBuilder::new() .acquire_thread_handler(jobserver::acquire_thread) .release_thread_handler(jobserver::release_thread) - .num_threads(Session::threads_from_count(threads)) + .num_threads(threads) .deadlock_handler(|| unsafe { ty::query::handle_deadlock() }); if let Some(size) = get_stack_size() { From df298b49f2eeb8497805359e360232c4b1030f51 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 1 Oct 2019 05:13:42 +0200 Subject: [PATCH 26/32] syntax: document some methods. --- src/libsyntax/parse/parser.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 722f8969fb09e..75ab768d55df8 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -511,13 +511,15 @@ impl<'a> Parser<'a> { is_present } + /// If the next token is the given keyword, returns `true` without eating it. + /// An expectation is also added for diagnostics purposes. fn check_keyword(&mut self, kw: Symbol) -> bool { self.expected_tokens.push(TokenType::Keyword(kw)); self.token.is_keyword(kw) } - /// If the next token is the given keyword, eats it and returns - /// `true`. Otherwise, returns `false`. + /// If the next token is the given keyword, eats it and returns `true`. + /// Otherwise, returns `false`. An expectation is also added for diagnostics purposes. pub fn eat_keyword(&mut self, kw: Symbol) -> bool { if self.check_keyword(kw) { self.bump(); @@ -896,6 +898,8 @@ impl<'a> Parser<'a> { self.expected_tokens.clear(); } + /// Look-ahead `dist` tokens of `self.token` and get access to that token there. + /// When `dist == 0` then the current token is looked at. pub fn look_ahead(&self, dist: usize, looker: impl FnOnce(&Token) -> R) -> R { if dist == 0 { return looker(&self.token); From 30647d1a851336582fcc45f9460aab46371f98af Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 1 Oct 2019 05:45:41 +0200 Subject: [PATCH 27/32] syntax: put helpers of `parse_self_param` in the method. --- src/libsyntax/parse/parser.rs | 115 +++++++++++++++++----------------- 1 file changed, 57 insertions(+), 58 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 75ab768d55df8..a4420e4a0f394 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1268,27 +1268,71 @@ impl<'a> Parser<'a> { /// /// See `parse_self_param_with_attrs` to collect attributes. fn parse_self_param(&mut self) -> PResult<'a, Option> { + // Extract an identifier *after* having confirmed that the token is one. + let expect_self_ident = |this: &mut Self| { + match this.token.kind { + // Preserve hygienic context. + token::Ident(name, _) => { + let span = this.token.span; + this.bump(); + Ident::new(name, span) + } + _ => unreachable!(), + } + }; + // Is `self` `n` tokens ahead? + let is_isolated_self = |this: &Self, n| { + this.is_keyword_ahead(n, &[kw::SelfLower]) + && this.look_ahead(n + 1, |t| t != &token::ModSep) + }; + // Is `mut self` `n` tokens ahead? + let is_isolated_mut_self = |this: &Self, n| { + this.is_keyword_ahead(n, &[kw::Mut]) + && is_isolated_self(this, n + 1) + }; + // Parse `self` or `self: TYPE`. We already know the current token is `self`. + let parse_self_possibly_typed = |this: &mut Self, m| { + let eself_ident = expect_self_ident(this); + let eself_hi = this.prev_span; + let eself = if this.eat(&token::Colon) { + SelfKind::Explicit(this.parse_ty()?, m) + } else { + SelfKind::Value(m) + }; + Ok((eself, eself_ident, eself_hi)) + }; + // Recover for the grammar `*self`, `*const self`, and `*mut self`. + let recover_self_ptr = |this: &mut Self| { + let msg = "cannot pass `self` by raw pointer"; + let span = this.token.span; + this.struct_span_err(span, msg) + .span_label(span, msg) + .emit(); + + Ok((SelfKind::Value(Mutability::Immutable), expect_self_ident(this), this.prev_span)) + }; + // Parse optional `self` parameter of a method. // Only a limited set of initial token sequences is considered `self` parameters; anything // else is parsed as a normal function parameter list, so some lookahead is required. let eself_lo = self.token.span; let (eself, eself_ident, eself_hi) = match self.token.kind { token::BinOp(token::And) => { - let eself = if self.is_isolated_self(1) { + let eself = if is_isolated_self(self, 1) { // `&self` self.bump(); SelfKind::Region(None, Mutability::Immutable) - } else if self.is_isolated_mut_self(1) { + } else if is_isolated_mut_self(self, 1) { // `&mut self` self.bump(); self.bump(); SelfKind::Region(None, Mutability::Mutable) - } else if self.look_ahead(1, |t| t.is_lifetime()) && self.is_isolated_self(2) { + } else if self.look_ahead(1, |t| t.is_lifetime()) && is_isolated_self(self, 2) { // `&'lt self` self.bump(); let lt = self.expect_lifetime(); SelfKind::Region(Some(lt), Mutability::Immutable) - } else if self.look_ahead(1, |t| t.is_lifetime()) && self.is_isolated_mut_self(2) { + } else if self.look_ahead(1, |t| t.is_lifetime()) && is_isolated_mut_self(self, 2) { // `&'lt mut self` self.bump(); let lt = self.expect_lifetime(); @@ -1298,30 +1342,30 @@ impl<'a> Parser<'a> { // `¬_self` return Ok(None); }; - (eself, self.expect_self_ident(), self.prev_span) + (eself, expect_self_ident(self), self.prev_span) } // `*self` - token::BinOp(token::Star) if self.is_isolated_self(1) => { + token::BinOp(token::Star) if is_isolated_self(self, 1) => { self.bump(); - self.recover_self_ptr()? + recover_self_ptr(self)? } // `*mut self` and `*const self` token::BinOp(token::Star) if self.look_ahead(1, |t| t.is_mutability()) - && self.is_isolated_self(2) => + && is_isolated_self(self, 2) => { self.bump(); self.bump(); - self.recover_self_ptr()? + recover_self_ptr(self)? } // `self` and `self: TYPE` - token::Ident(..) if self.is_isolated_self(0) => { - self.parse_self_possibly_typed(Mutability::Immutable)? + token::Ident(..) if is_isolated_self(self, 0) => { + parse_self_possibly_typed(self, Mutability::Immutable)? } // `mut self` and `mut self: TYPE` - token::Ident(..) if self.is_isolated_mut_self(0) => { + token::Ident(..) if is_isolated_mut_self(self, 0) => { self.bump(); - self.parse_self_possibly_typed(Mutability::Mutable)? + parse_self_possibly_typed(self, Mutability::Mutable)? } _ => return Ok(None), }; @@ -1345,51 +1389,6 @@ impl<'a> Parser<'a> { self.look_ahead(offset + 1, |t| t == &token::Colon) } - fn is_isolated_self(&self, n: usize) -> bool { - self.is_keyword_ahead(n, &[kw::SelfLower]) - && self.look_ahead(n + 1, |t| t != &token::ModSep) - } - - fn is_isolated_mut_self(&self, n: usize) -> bool { - self.is_keyword_ahead(n, &[kw::Mut]) - && self.is_isolated_self(n + 1) - } - - fn expect_self_ident(&mut self) -> Ident { - match self.token.kind { - // Preserve hygienic context. - token::Ident(name, _) => { - let span = self.token.span; - self.bump(); - Ident::new(name, span) - } - _ => unreachable!(), - } - } - - /// Recover for the grammar `*self`, `*const self`, and `*mut self`. - fn recover_self_ptr(&mut self) -> PResult<'a, (ast::SelfKind, Ident, Span)> { - let msg = "cannot pass `self` by raw pointer"; - let span = self.token.span; - self.struct_span_err(span, msg) - .span_label(span, msg) - .emit(); - - Ok((SelfKind::Value(Mutability::Immutable), self.expect_self_ident(), self.prev_span)) - } - - /// Parse `self` or `self: TYPE`. We already know the current token is `self`. - fn parse_self_possibly_typed(&mut self, m: Mutability) -> PResult<'a, (SelfKind, Ident, Span)> { - let eself_ident = self.expect_self_ident(); - let eself_hi = self.prev_span; - let eself = if self.eat(&token::Colon) { - SelfKind::Explicit(self.parse_ty()?, m) - } else { - SelfKind::Value(m) - }; - Ok((eself, eself_ident, eself_hi)) - } - fn is_crate_vis(&self) -> bool { self.token.is_keyword(kw::Crate) && self.look_ahead(1, |t| t != &token::ModSep) } From 49780d21b63e0557627e185ed71c84e33eed0c4b Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 1 Oct 2019 05:53:23 +0200 Subject: [PATCH 28/32] syntax: merge things back into `parse_visibility`. --- src/libsyntax/parse/parser.rs | 62 ++++++++++++++--------------------- 1 file changed, 25 insertions(+), 37 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a4420e4a0f394..0369e0a9e153c 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1423,13 +1423,35 @@ impl<'a> Parser<'a> { if self.is_keyword_ahead(1, &[kw::Crate]) && self.look_ahead(2, |t| t != &token::ModSep) // account for `pub(crate::foo)` { - return self.parse_vis_pub_crate(lo); + // Parse `pub(crate)`. + self.bump(); // `(` + self.bump(); // `crate` + self.expect(&token::CloseDelim(token::Paren))?; // `)` + let vis = VisibilityKind::Crate(CrateSugar::PubCrate); + return Ok(respan(lo.to(self.prev_span), vis)); } else if self.is_keyword_ahead(1, &[kw::In]) { - return self.parse_vis_pub_in(lo); + // Parse `pub(in path)`. + self.bump(); // `(` + self.bump(); // `in` + let path = self.parse_path(PathStyle::Mod)?; // `path` + self.expect(&token::CloseDelim(token::Paren))?; // `)` + let vis = VisibilityKind::Restricted { + path: P(path), + id: ast::DUMMY_NODE_ID, + }; + return Ok(respan(lo.to(self.prev_span), vis)); } else if self.look_ahead(2, |t| t == &token::CloseDelim(token::Paren)) && self.is_keyword_ahead(1, &[kw::Super, kw::SelfLower]) { - return self.parse_vis_self_super(lo); + // Parse `pub(self)` or `pub(super)`. + self.bump(); // `(` + let path = self.parse_path(PathStyle::Mod)?; // `super`/`self` + self.expect(&token::CloseDelim(token::Paren))?; // `)` + let vis = VisibilityKind::Restricted { + path: P(path), + id: ast::DUMMY_NODE_ID, + }; + return Ok(respan(lo.to(self.prev_span), vis)); } else if !can_take_tuple { // Provide this diagnostic if this is not a tuple struct. self.recover_incorrect_vis_restriction()?; // Emit diagnostic, but continue with public visibility. @@ -1439,40 +1461,6 @@ impl<'a> Parser<'a> { Ok(respan(lo, VisibilityKind::Public)) } - /// Parse `pub(crate)`. - fn parse_vis_pub_crate(&mut self, lo: Span) -> PResult<'a, Visibility> { - self.bump(); // `(` - self.bump(); // `crate` - self.expect(&token::CloseDelim(token::Paren))?; // `)` - Ok(respan( - lo.to(self.prev_span), - VisibilityKind::Crate(CrateSugar::PubCrate), - )) - } - - /// Parse `pub(in path)`. - fn parse_vis_pub_in(&mut self, lo: Span) -> PResult<'a, Visibility> { - self.bump(); // `(` - self.bump(); // `in` - let path = self.parse_path(PathStyle::Mod)?; // `path` - self.expect(&token::CloseDelim(token::Paren))?; // `)` - Ok(respan(lo.to(self.prev_span), VisibilityKind::Restricted { - path: P(path), - id: ast::DUMMY_NODE_ID, - })) - } - - /// Parse `pub(self)` or `pub(super)`. - fn parse_vis_self_super(&mut self, lo: Span) -> PResult<'a, Visibility> { - self.bump(); // `(` - let path = self.parse_path(PathStyle::Mod)?; // `super`/`self` - self.expect(&token::CloseDelim(token::Paren))?; // `)` - Ok(respan(lo.to(self.prev_span), VisibilityKind::Restricted { - path: P(path), - id: ast::DUMMY_NODE_ID, - })) - } - /// Recovery for e.g. `pub(something) fn ...` or `struct X { pub(something) y: Z }` fn recover_incorrect_vis_restriction(&mut self) -> PResult<'a, ()> { self.bump(); // `(` From e04690440b6d77b4da9bfcf593a641133033ae44 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 1 Oct 2019 05:55:28 +0200 Subject: [PATCH 29/32] syntax: de-closure-ify `check_or_expected`. --- src/libsyntax/parse/parser.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 0369e0a9e153c..95f84d5cb3314 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -549,29 +549,29 @@ impl<'a> Parser<'a> { } } - fn check_or_expected(&mut self, ok: bool, mk_type: impl FnOnce() -> TokenType) -> bool { + fn check_or_expected(&mut self, ok: bool, typ: TokenType) -> bool { if ok { true } else { - self.expected_tokens.push(mk_type()); + self.expected_tokens.push(typ); false } } crate fn check_ident(&mut self) -> bool { - self.check_or_expected(self.token.is_ident(), || TokenType::Ident) + self.check_or_expected(self.token.is_ident(), TokenType::Ident) } fn check_path(&mut self) -> bool { - self.check_or_expected(self.token.is_path_start(), || TokenType::Path) + self.check_or_expected(self.token.is_path_start(), TokenType::Path) } fn check_type(&mut self) -> bool { - self.check_or_expected(self.token.can_begin_type(), || TokenType::Type) + self.check_or_expected(self.token.can_begin_type(), TokenType::Type) } fn check_const_arg(&mut self) -> bool { - self.check_or_expected(self.token.can_begin_const_arg(), || TokenType::Const) + self.check_or_expected(self.token.can_begin_const_arg(), TokenType::Const) } /// Checks to see if the next token is either `+` or `+=`. @@ -579,7 +579,7 @@ impl<'a> Parser<'a> { fn check_plus(&mut self) -> bool { self.check_or_expected( self.token.is_like_plus(), - || TokenType::Token(token::BinOp(token::Plus)), + TokenType::Token(token::BinOp(token::Plus)), ) } From 5c5dd8069d0aeeb97ef6b6099767f97aec1edee4 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 1 Oct 2019 06:10:06 +0200 Subject: [PATCH 30/32] syntax: reformat passing of `FnHeader` to `parse_item_fn`. --- src/libsyntax/parse/parser/item.rs | 28 +++++++++++-------- .../edition-deny-async-fns-2015.stderr | 12 ++++---- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index e8ca264f1c5ff..c00a5807d52c5 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -122,12 +122,13 @@ impl<'a> Parser<'a> { if self.eat_keyword(kw::Fn) { // EXTERN FUNCTION ITEM let fn_span = self.prev_span; - return self.parse_item_fn(lo, visibility, attrs, FnHeader { + let header = FnHeader { unsafety: Unsafety::Normal, asyncness: respan(fn_span, IsAsync::NotAsync), constness: respan(fn_span, Constness::NotConst), abi: opt_abi.unwrap_or(Abi::C), - }); + }; + return self.parse_item_fn(lo, visibility, attrs, header); } else if self.check(&token::OpenDelim(token::Brace)) { return Ok(Some( self.parse_item_foreign_mod(lo, opt_abi, visibility, attrs, extern_sp)?, @@ -154,12 +155,13 @@ impl<'a> Parser<'a> { // CONST FUNCTION ITEM let unsafety = self.parse_unsafety(); self.bump(); - return self.parse_item_fn(lo, visibility, attrs, FnHeader { + let header = FnHeader { unsafety, asyncness: respan(const_span, IsAsync::NotAsync), constness: respan(const_span, Constness::Const), abi: Abi::Rust, - }); + }; + return self.parse_item_fn(lo, visibility, attrs, header); } // CONST ITEM @@ -196,14 +198,14 @@ impl<'a> Parser<'a> { closure_id: DUMMY_NODE_ID, return_impl_trait_id: DUMMY_NODE_ID, }); - let item = self.parse_item_fn(lo, visibility, attrs, FnHeader { + self.ban_async_in_2015(async_span); + let header = FnHeader { unsafety, asyncness, constness: respan(fn_span, Constness::NotConst), abi: Abi::Rust, - })?; - self.ban_async_in_2015(async_span); - return Ok(item); + }; + return self.parse_item_fn(lo, visibility, attrs, header); } } if self.check_keyword(kw::Unsafe) && @@ -241,12 +243,13 @@ impl<'a> Parser<'a> { // FUNCTION ITEM self.bump(); let fn_span = self.prev_span; - return self.parse_item_fn(lo, visibility, attrs, FnHeader { + let header = FnHeader { unsafety: Unsafety::Normal, asyncness: respan(fn_span, IsAsync::NotAsync), constness: respan(fn_span, Constness::NotConst), abi: Abi::Rust, - }); + }; + return self.parse_item_fn(lo, visibility, attrs, header); } if self.check_keyword(kw::Unsafe) && self.look_ahead(1, |t| *t != token::OpenDelim(token::Brace)) { @@ -261,12 +264,13 @@ impl<'a> Parser<'a> { }; self.expect_keyword(kw::Fn)?; let fn_span = self.prev_span; - return self.parse_item_fn(lo, visibility, attrs, FnHeader { + let header = FnHeader { unsafety: Unsafety::Unsafe, asyncness: respan(fn_span, IsAsync::NotAsync), constness: respan(fn_span, Constness::NotConst), abi, - }); + }; + return self.parse_item_fn(lo, visibility, attrs, header); } if self.eat_keyword(kw::Mod) { // MODULE ITEM diff --git a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr index d3f88af09d134..7633825eb32ab 100644 --- a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr +++ b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr @@ -10,18 +10,18 @@ error[E0670]: `async fn` is not permitted in the 2015 edition LL | fn baz() { async fn foo() {} } | ^^^^^ -error[E0670]: `async fn` is not permitted in the 2015 edition - --> $DIR/edition-deny-async-fns-2015.rs:8:5 - | -LL | async fn bar() {} - | ^^^^^ - error[E0670]: `async fn` is not permitted in the 2015 edition --> $DIR/edition-deny-async-fns-2015.rs:7:1 | LL | async fn async_baz() { | ^^^^^ +error[E0670]: `async fn` is not permitted in the 2015 edition + --> $DIR/edition-deny-async-fns-2015.rs:8:5 + | +LL | async fn bar() {} + | ^^^^^ + error[E0670]: `async fn` is not permitted in the 2015 edition --> $DIR/edition-deny-async-fns-2015.rs:14:5 | From 3237dedf7ff51ca1342e8f2b01d60f7c599a127c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 12 Sep 2019 14:32:50 +0200 Subject: [PATCH 31/32] Add long error explanation for E0495 --- src/librustc/error_codes.rs | 43 +++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/src/librustc/error_codes.rs b/src/librustc/error_codes.rs index 968b0b9f2f2b7..8b9797f8025fd 100644 --- a/src/librustc/error_codes.rs +++ b/src/librustc/error_codes.rs @@ -1580,6 +1580,47 @@ where ``` "##, +E0495: r##" +A lifetime cannot be determined in the given situation. + +Erroneous code example: + +```compile_fail,E0495 +fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T { + match (&t,) { // error! + ((u,),) => u, + } +} + +let y = Box::new((42,)); +let x = transmute_lifetime(&y); +``` + +In this code, you have two ways to solve this issue: + 1. Enforce that `'a` lives at least as long as `'b`. + 2. Use the same lifetime requirement for both input and output values. + +So for the first solution, you can do it by replacing `'a` with `'a: 'b`: + +``` +fn transmute_lifetime<'a: 'b, 'b, T>(t: &'a (T,)) -> &'b T { + match (&t,) { // ok! + ((u,),) => u, + } +} +``` + +In the second you can do it by simply removing `'b` so they both use `'a`: + +``` +fn transmute_lifetime<'a, T>(t: &'a (T,)) -> &'a T { + match (&t,) { // ok! + ((u,),) => u, + } +} +``` +"##, + E0496: r##" A lifetime name is shadowing another lifetime name. Erroneous code example: @@ -2275,8 +2316,6 @@ rejected in your own crates. E0488, // lifetime of variable does not enclose its declaration E0489, // type/lifetime parameter not in scope here E0490, // a value of type `..` is borrowed for too long - E0495, // cannot infer an appropriate lifetime due to conflicting - // requirements E0566, // conflicting representation hints E0623, // lifetime mismatch where both parameters are anonymous regions E0628, // generators cannot have explicit parameters From be89e5225cd196fdc283e2d5aa7e80f9363627f1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 12 Sep 2019 15:00:44 +0200 Subject: [PATCH 32/32] update ui tests --- .../cache/project-fn-ret-contravariant.transmute.stderr | 1 + .../cache/project-fn-ret-invariant.transmute.stderr | 1 + src/test/ui/c-variadic/variadic-ffi-4.stderr | 3 ++- .../ui/error-codes/E0621-does-not-trigger-for-closures.stderr | 1 + src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr | 1 + src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr | 1 + src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr | 1 + src/test/ui/issues/issue-16683.stderr | 1 + src/test/ui/issues/issue-17758.stderr | 1 + src/test/ui/issues/issue-20831-debruijn.stderr | 3 ++- src/test/ui/issues/issue-52213.stderr | 1 + src/test/ui/issues/issue-55796.stderr | 1 + src/test/ui/nll/issue-55394.stderr | 1 + src/test/ui/nll/normalization-bounds-error.stderr | 1 + src/test/ui/nll/type-alias-free-regions.stderr | 1 + .../ui/nll/user-annotations/constant-in-expr-inherent-1.stderr | 1 + .../nll/user-annotations/constant-in-expr-trait-item-3.stderr | 1 + .../ui/object-lifetime/object-lifetime-default-elision.stderr | 1 + src/test/ui/regions/region-object-lifetime-2.stderr | 1 + src/test/ui/regions/region-object-lifetime-4.stderr | 1 + src/test/ui/regions/region-object-lifetime-in-coercion.stderr | 3 ++- src/test/ui/regions/regions-addr-of-self.stderr | 1 + src/test/ui/regions/regions-addr-of-upvar-self.stderr | 1 + .../regions-assoc-type-region-bound-in-trait-not-met.stderr | 1 + .../regions-assoc-type-static-bound-in-trait-not-met.stderr | 1 + src/test/ui/regions/regions-close-object-into-object-2.stderr | 1 + src/test/ui/regions/regions-close-object-into-object-4.stderr | 1 + .../regions/regions-close-over-type-parameter-multiple.stderr | 1 + src/test/ui/regions/regions-creating-enums4.stderr | 1 + src/test/ui/regions/regions-escape-method.stderr | 1 + src/test/ui/regions/regions-escape-via-trait-or-not.stderr | 1 + .../ui/regions/regions-free-region-ordering-incorrect.stderr | 1 + src/test/ui/regions/regions-infer-call-3.stderr | 1 + src/test/ui/regions/regions-nested-fns.stderr | 3 ++- .../ui/regions/regions-normalize-in-where-clause-list.stderr | 1 + src/test/ui/regions/regions-ret-borrowed-1.stderr | 1 + src/test/ui/regions/regions-ret-borrowed.stderr | 1 + .../ui/regions/regions-return-ref-to-upvar-issue-17403.stderr | 1 + src/test/ui/regions/regions-trait-object-subtyping.stderr | 2 +- src/test/ui/reject-specialized-drops-8142.stderr | 2 +- ...ait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr | 1 + src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr | 1 + src/test/ui/wf/wf-static-method.stderr | 2 +- 43 files changed, 47 insertions(+), 7 deletions(-) diff --git a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr index 15bebce47dd6a..4309373f123f9 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr @@ -23,3 +23,4 @@ LL | bar(foo, x) error: aborting due to previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr index 62b4cb10911fb..b8b1a979c363a 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr @@ -19,3 +19,4 @@ LL | fn baz<'a,'b>(x: Type<'a>) -> Type<'static> { error: aborting due to previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/c-variadic/variadic-ffi-4.stderr b/src/test/ui/c-variadic/variadic-ffi-4.stderr index b986d0c243506..3d552f88ba667 100644 --- a/src/test/ui/c-variadic/variadic-ffi-4.stderr +++ b/src/test/ui/c-variadic/variadic-ffi-4.stderr @@ -209,4 +209,5 @@ LL | | } error: aborting due to 8 previous errors -For more information about this error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0308, E0495. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.stderr b/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.stderr index f50c64780118b..feca7f10b706b 100644 --- a/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.stderr +++ b/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.stderr @@ -27,3 +27,4 @@ LL | invoke(&x, |a, b| if a > b { a } else { b }); error: aborting due to previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr b/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr index eb824def24687..af120fa977caa 100644 --- a/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr +++ b/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr @@ -19,3 +19,4 @@ LL | fn with_dyn_debug_static<'a>(x: Box) { error: aborting due to previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr index b50a926c63795..c1ec536ef4362 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr @@ -18,3 +18,4 @@ LL | | } error: aborting due to previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr index 80f15b7c5847f..4dee83d6eefe3 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr @@ -32,3 +32,4 @@ LL | x error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/issues/issue-16683.stderr b/src/test/ui/issues/issue-16683.stderr index 771a2ddf240f5..a047893a168a4 100644 --- a/src/test/ui/issues/issue-16683.stderr +++ b/src/test/ui/issues/issue-16683.stderr @@ -27,3 +27,4 @@ LL | trait T<'a> { error: aborting due to previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/issues/issue-17758.stderr b/src/test/ui/issues/issue-17758.stderr index 0ef3b98719d34..28a1be59840a1 100644 --- a/src/test/ui/issues/issue-17758.stderr +++ b/src/test/ui/issues/issue-17758.stderr @@ -28,3 +28,4 @@ LL | trait Foo<'a> { error: aborting due to previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/issues/issue-20831-debruijn.stderr b/src/test/ui/issues/issue-20831-debruijn.stderr index 64e3cdc64c112..dd895985c1430 100644 --- a/src/test/ui/issues/issue-20831-debruijn.stderr +++ b/src/test/ui/issues/issue-20831-debruijn.stderr @@ -94,4 +94,5 @@ LL | impl<'a> Publisher<'a> for MyStruct<'a> { error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0308, E0495. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/issues/issue-52213.stderr b/src/test/ui/issues/issue-52213.stderr index b4df10efc5d8d..8d74b8ecb881e 100644 --- a/src/test/ui/issues/issue-52213.stderr +++ b/src/test/ui/issues/issue-52213.stderr @@ -25,3 +25,4 @@ LL | ((u,),) => u, error: aborting due to previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/issues/issue-55796.stderr b/src/test/ui/issues/issue-55796.stderr index 9e67e5e125f62..7cf597d3a98f8 100644 --- a/src/test/ui/issues/issue-55796.stderr +++ b/src/test/ui/issues/issue-55796.stderr @@ -42,3 +42,4 @@ LL | Box::new(self.in_edges(u).map(|e| e.target())) error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/nll/issue-55394.stderr b/src/test/ui/nll/issue-55394.stderr index ffb94ed7dd7c0..e00e6f36f1af4 100644 --- a/src/test/ui/nll/issue-55394.stderr +++ b/src/test/ui/nll/issue-55394.stderr @@ -27,3 +27,4 @@ LL | impl Foo<'_> { error: aborting due to previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/nll/normalization-bounds-error.stderr b/src/test/ui/nll/normalization-bounds-error.stderr index 951e73e7fd765..77a372d9cf558 100644 --- a/src/test/ui/nll/normalization-bounds-error.stderr +++ b/src/test/ui/nll/normalization-bounds-error.stderr @@ -20,3 +20,4 @@ LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {} error: aborting due to previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/nll/type-alias-free-regions.stderr b/src/test/ui/nll/type-alias-free-regions.stderr index 00d58d34362e6..746517417520a 100644 --- a/src/test/ui/nll/type-alias-free-regions.stderr +++ b/src/test/ui/nll/type-alias-free-regions.stderr @@ -50,3 +50,4 @@ LL | impl<'a> FromTuple<'a> for C<'a> { error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr index 77e1339dc161d..f5657f9e4eada 100644 --- a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr +++ b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr @@ -21,3 +21,4 @@ LL | >::C error: aborting due to previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr index 77655fe091b62..f7db4038b8af4 100644 --- a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr +++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr @@ -21,3 +21,4 @@ LL | T::C error: aborting due to previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr b/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr index 2cdd6c5d890f2..217e8504aa3c9 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr @@ -50,3 +50,4 @@ LL | fn load3<'a,'b>(ss: &'a dyn SomeTrait) -> &'b dyn SomeTrait { error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/region-object-lifetime-2.stderr b/src/test/ui/regions/region-object-lifetime-2.stderr index 0c5e22ebae283..cc8d150d04cc5 100644 --- a/src/test/ui/regions/region-object-lifetime-2.stderr +++ b/src/test/ui/regions/region-object-lifetime-2.stderr @@ -27,3 +27,4 @@ LL | x.borrowed() error: aborting due to previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/region-object-lifetime-4.stderr b/src/test/ui/regions/region-object-lifetime-4.stderr index e737d27d5606f..23fd4d03628d9 100644 --- a/src/test/ui/regions/region-object-lifetime-4.stderr +++ b/src/test/ui/regions/region-object-lifetime-4.stderr @@ -27,3 +27,4 @@ LL | x.borrowed() error: aborting due to previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr index 8209fa1840d05..3ccb8866ca44b 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr @@ -48,4 +48,5 @@ LL | fn d<'a,'b>(v: &'a [u8]) -> Box { error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0621`. +Some errors have detailed explanations: E0495, E0621. +For more information about an error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-addr-of-self.stderr b/src/test/ui/regions/regions-addr-of-self.stderr index 2274e9341dbc9..a0b8b6b51e5a1 100644 --- a/src/test/ui/regions/regions-addr-of-self.stderr +++ b/src/test/ui/regions/regions-addr-of-self.stderr @@ -26,3 +26,4 @@ LL | let p: &'static mut usize = &mut self.cats_chased; error: aborting due to previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-addr-of-upvar-self.stderr b/src/test/ui/regions/regions-addr-of-upvar-self.stderr index d02caeb44f1a8..ac5e5e9aabc5b 100644 --- a/src/test/ui/regions/regions-addr-of-upvar-self.stderr +++ b/src/test/ui/regions/regions-addr-of-upvar-self.stderr @@ -23,3 +23,4 @@ LL | let p: &'static mut usize = &mut self.food; error: aborting due to previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr b/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr index 9732cd12ce15f..d01e991103923 100644 --- a/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr +++ b/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr @@ -46,3 +46,4 @@ LL | impl<'a,'b> Foo<'b> for &'a i64 { error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr b/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr index 2067bc3946c92..33a4ea01ce2e5 100644 --- a/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr +++ b/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr @@ -21,3 +21,4 @@ LL | impl<'a> Foo for &'a i32 { error: aborting due to previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-close-object-into-object-2.stderr b/src/test/ui/regions/regions-close-object-into-object-2.stderr index fa203debb3a1b..7af608d2c801d 100644 --- a/src/test/ui/regions/regions-close-object-into-object-2.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-2.stderr @@ -21,3 +21,4 @@ LL | box B(&*v) as Box error: aborting due to previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-close-object-into-object-4.stderr b/src/test/ui/regions/regions-close-object-into-object-4.stderr index f5e66f84a9ee7..ef47db18d392c 100644 --- a/src/test/ui/regions/regions-close-object-into-object-4.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-4.stderr @@ -21,3 +21,4 @@ LL | box B(&*v) as Box error: aborting due to previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr b/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr index 8b3dbc8b64902..6f7466a8b0edd 100644 --- a/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr +++ b/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr @@ -25,3 +25,4 @@ LL | fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box(x: &'a Ast<'a>, y: &'a Ast<'a>, z: &Ast) -> Ast<'b> { error: aborting due to previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-escape-method.stderr b/src/test/ui/regions/regions-escape-method.stderr index d867448e1372a..b93dd0d4c57c9 100644 --- a/src/test/ui/regions/regions-escape-method.stderr +++ b/src/test/ui/regions/regions-escape-method.stderr @@ -25,3 +25,4 @@ LL | s.f(|p| p) error: aborting due to previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-escape-via-trait-or-not.stderr b/src/test/ui/regions/regions-escape-via-trait-or-not.stderr index c8a02683d1000..a6b165e2d4444 100644 --- a/src/test/ui/regions/regions-escape-via-trait-or-not.stderr +++ b/src/test/ui/regions/regions-escape-via-trait-or-not.stderr @@ -25,3 +25,4 @@ LL | with(|o| o) error: aborting due to previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-free-region-ordering-incorrect.stderr b/src/test/ui/regions/regions-free-region-ordering-incorrect.stderr index 5fad6de2a62af..676e96a038b43 100644 --- a/src/test/ui/regions/regions-free-region-ordering-incorrect.stderr +++ b/src/test/ui/regions/regions-free-region-ordering-incorrect.stderr @@ -30,3 +30,4 @@ LL | | } error: aborting due to previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-infer-call-3.stderr b/src/test/ui/regions/regions-infer-call-3.stderr index 151c8307a14f6..1d6dbdb2c7b57 100644 --- a/src/test/ui/regions/regions-infer-call-3.stderr +++ b/src/test/ui/regions/regions-infer-call-3.stderr @@ -27,3 +27,4 @@ LL | let z = with(|y| { select(x, y) }); error: aborting due to previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-nested-fns.stderr b/src/test/ui/regions/regions-nested-fns.stderr index 904dee6998c9b..bc3c06d7ff3b3 100644 --- a/src/test/ui/regions/regions-nested-fns.stderr +++ b/src/test/ui/regions/regions-nested-fns.stderr @@ -57,4 +57,5 @@ LL | fn nested<'x>(x: &'x isize) { error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0312`. +Some errors have detailed explanations: E0312, E0495. +For more information about an error, try `rustc --explain E0312`. diff --git a/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr b/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr index 912e118316271..c44edf1f03bc3 100644 --- a/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr +++ b/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr @@ -23,3 +23,4 @@ LL | fn bar<'a, 'b>() error: aborting due to previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-ret-borrowed-1.stderr b/src/test/ui/regions/regions-ret-borrowed-1.stderr index 403af2a9e6a44..72e47cea094c5 100644 --- a/src/test/ui/regions/regions-ret-borrowed-1.stderr +++ b/src/test/ui/regions/regions-ret-borrowed-1.stderr @@ -25,3 +25,4 @@ LL | with(|o| o) error: aborting due to previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-ret-borrowed.stderr b/src/test/ui/regions/regions-ret-borrowed.stderr index 5d1f26da6c783..ce0c429ccb247 100644 --- a/src/test/ui/regions/regions-ret-borrowed.stderr +++ b/src/test/ui/regions/regions-ret-borrowed.stderr @@ -25,3 +25,4 @@ LL | with(|o| o) error: aborting due to previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.stderr b/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.stderr index 291b8367f7b75..be441bc48082e 100644 --- a/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.stderr +++ b/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.stderr @@ -27,3 +27,4 @@ LL | let y = f(); error: aborting due to previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-trait-object-subtyping.stderr b/src/test/ui/regions/regions-trait-object-subtyping.stderr index 6de92f13840b3..d88be05cb87e6 100644 --- a/src/test/ui/regions/regions-trait-object-subtyping.stderr +++ b/src/test/ui/regions/regions-trait-object-subtyping.stderr @@ -61,5 +61,5 @@ LL | fn foo4<'a:'b,'b>(x: Wrapper<&'a mut dyn Dummy>) -> Wrapper<&'b mut dyn Dum error: aborting due to 3 previous errors -Some errors have detailed explanations: E0308, E0478. +Some errors have detailed explanations: E0308, E0478, E0495. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/reject-specialized-drops-8142.stderr b/src/test/ui/reject-specialized-drops-8142.stderr index 08aca3bb14c26..16d27c9d961ee 100644 --- a/src/test/ui/reject-specialized-drops-8142.stderr +++ b/src/test/ui/reject-specialized-drops-8142.stderr @@ -111,5 +111,5 @@ LL | struct W<'l1, 'l2> { x: &'l1 i8, y: &'l2 u8 } error: aborting due to 8 previous errors -Some errors have detailed explanations: E0308, E0366, E0367. +Some errors have detailed explanations: E0308, E0366, E0367, E0495. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/traits/trait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr b/src/test/ui/traits/trait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr index fb417b82d15ce..4c63d6097758e 100644 --- a/src/test/ui/traits/trait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr +++ b/src/test/ui/traits/trait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr @@ -20,3 +20,4 @@ LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> { error: aborting due to previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr index 92e5ac282e4d6..d0475bf08c38d 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr @@ -24,3 +24,4 @@ LL | Box::new(items.iter()) error: aborting due to previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/wf/wf-static-method.stderr b/src/test/ui/wf/wf-static-method.stderr index 3ec90f00448a9..da4e8ebf9c05c 100644 --- a/src/test/ui/wf/wf-static-method.stderr +++ b/src/test/ui/wf/wf-static-method.stderr @@ -105,5 +105,5 @@ LL | ::static_evil(b) error: aborting due to 5 previous errors -Some errors have detailed explanations: E0312, E0478. +Some errors have detailed explanations: E0312, E0478, E0495. For more information about an error, try `rustc --explain E0312`.