From 5faae38851daea574b0b414618ec61a953bef2db Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 9 Aug 2019 19:30:00 +0200 Subject: [PATCH 01/32] apfloat: improve doc comments --- src/librustc_apfloat/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_apfloat/lib.rs b/src/librustc_apfloat/lib.rs index 9e6d5a6f62434..2df4d2a4e9de9 100644 --- a/src/librustc_apfloat/lib.rs +++ b/src/librustc_apfloat/lib.rs @@ -551,12 +551,13 @@ pub trait Float fn ilogb(self) -> ExpInt; /// Returns: self * 2exp for integral exponents. + /// Equivalent to C standard library function `ldexp`. fn scalbn_r(self, exp: ExpInt, round: Round) -> Self; fn scalbn(self, exp: ExpInt) -> Self { self.scalbn_r(exp, Round::NearestTiesToEven) } - /// Equivalent of C standard library function. + /// Equivalent to C standard library function with the same name. /// /// While the C standard says exp is an unspecified value for infinity and nan, /// this returns INT_MAX for infinities, and INT_MIN for NaNs (see `ilogb`). From a3639c68595e59a17884c70d9e1881a00e789bfc Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Mon, 23 Sep 2019 19:27:17 -0400 Subject: [PATCH 02/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 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 1a1067d1a537d6495f6aa9703e10119f05d578ad Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Mon, 30 Sep 2019 16:27:28 -0400 Subject: [PATCH 21/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 c9baaa70beab336c8fcb08b378d999f7309aaef9 Mon Sep 17 00:00:00 2001 From: Sam Radhakrishnan Date: Mon, 30 Sep 2019 17:45:31 -0400 Subject: [PATCH 22/32] Fixes #64919. Suggest fix based on operator precendence. --- src/librustc_typeck/check/mod.rs | 6 +++- src/test/ui/mismatched_types/abridged.rs | 9 ++++++ src/test/ui/mismatched_types/abridged.stderr | 30 +++++++++++++++++++- 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 5e3db1c7990d0..3c825712217e6 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4344,7 +4344,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let max_len = receiver.rfind(".").unwrap(); format!("{}{}", &receiver[..max_len], method_call) } else { - format!("{}{}", receiver, method_call) + match &expr.kind { + ExprKind::Binary(_,_,_) => format!("({}){}", receiver, method_call), + ExprKind::Unary(_,_) => format!("({}){}", receiver, method_call), + _ => format!("{}{}", receiver, method_call), + } }; Some(if is_struct_pat_shorthand_field { format!("{}: {}", receiver, sugg) diff --git a/src/test/ui/mismatched_types/abridged.rs b/src/test/ui/mismatched_types/abridged.rs index 41ab6d4c57844..9a5c183ca3428 100644 --- a/src/test/ui/mismatched_types/abridged.rs +++ b/src/test/ui/mismatched_types/abridged.rs @@ -50,4 +50,13 @@ fn e() -> X, String> { x //~ ERROR mismatched types } +fn f() -> String { + 1+2 //~ ERROR mismatched types +} + + +fn g() -> String { + -2 //~ ERROR mismatched types +} + fn main() {} diff --git a/src/test/ui/mismatched_types/abridged.stderr b/src/test/ui/mismatched_types/abridged.stderr index b7f3b3dde8a93..ded12d89c099d 100644 --- a/src/test/ui/mismatched_types/abridged.stderr +++ b/src/test/ui/mismatched_types/abridged.stderr @@ -66,6 +66,34 @@ LL | x = note: expected type `X, _>` found type `X, _>` -error: aborting due to 6 previous errors +error[E0308]: mismatched types + --> $DIR/abridged.rs:54:5 + | +LL | fn f() -> String { + | ------ expected `std::string::String` because of return type +LL | 1+2 + | ^^^ + | | + | expected struct `std::string::String`, found integer + | help: try using a conversion method: `(1+2).to_string()` + | + = note: expected type `std::string::String` + found type `{integer}` + +error[E0308]: mismatched types + --> $DIR/abridged.rs:59:5 + | +LL | fn g() -> String { + | ------ expected `std::string::String` because of return type +LL | -2 + | ^^ + | | + | expected struct `std::string::String`, found integer + | help: try using a conversion method: `(-2).to_string()` + | + = note: expected type `std::string::String` + found type `{integer}` + +error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0308`. From df298b49f2eeb8497805359e360232c4b1030f51 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 1 Oct 2019 05:13:42 +0200 Subject: [PATCH 23/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 24/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 25/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 26/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 27/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 9e4eb46790435c38a613d7f9d5d3e0eb5f77fca1 Mon Sep 17 00:00:00 2001 From: Sam Radhakrishnan Date: Tue, 1 Oct 2019 05:00:22 -0400 Subject: [PATCH 28/32] Change to use exprPrecedence instead of exprKind. --- src/librustc_typeck/check/mod.rs | 9 +++++---- src/test/ui/conversion-methods.stderr | 2 +- src/test/ui/infinite/infinite-autoderef.stderr | 2 +- src/test/ui/occurs-check-2.stderr | 2 +- src/test/ui/occurs-check.stderr | 2 +- src/test/ui/span/coerce-suggestions.stderr | 2 +- 6 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 3c825712217e6..aa443a69c5016 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -128,6 +128,7 @@ use syntax::attr; use syntax::feature_gate::{GateIssue, emit_feature_err}; use syntax::source_map::{DUMMY_SP, original_sp}; use syntax::symbol::{kw, sym}; +use syntax::util::parser::ExprPrecedence; use std::cell::{Cell, RefCell, Ref, RefMut}; use std::collections::hash_map::Entry; @@ -4344,10 +4345,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let max_len = receiver.rfind(".").unwrap(); format!("{}{}", &receiver[..max_len], method_call) } else { - match &expr.kind { - ExprKind::Binary(_,_,_) => format!("({}){}", receiver, method_call), - ExprKind::Unary(_,_) => format!("({}){}", receiver, method_call), - _ => format!("{}{}", receiver, method_call), + if expr.precedence().order() < ExprPrecedence::MethodCall.order() { + format!("({}){}", receiver, method_call) + } else { + format!("{}{}", receiver, method_call) } }; Some(if is_struct_pat_shorthand_field { diff --git a/src/test/ui/conversion-methods.stderr b/src/test/ui/conversion-methods.stderr index b9662e7607494..5c666afb89a33 100644 --- a/src/test/ui/conversion-methods.stderr +++ b/src/test/ui/conversion-methods.stderr @@ -41,7 +41,7 @@ LL | let _prove_piercing_earnest: Vec = &[1, 2, 3]; | ^^^^^^^^^^ | | | expected struct `std::vec::Vec`, found reference - | help: try using a conversion method: `&[1, 2, 3].to_vec()` + | help: try using a conversion method: `(&[1, 2, 3]).to_vec()` | = note: expected type `std::vec::Vec` found type `&[{integer}; 3]` diff --git a/src/test/ui/infinite/infinite-autoderef.stderr b/src/test/ui/infinite/infinite-autoderef.stderr index a2ad58a7e46fc..f4567554d0dbb 100644 --- a/src/test/ui/infinite/infinite-autoderef.stderr +++ b/src/test/ui/infinite/infinite-autoderef.stderr @@ -5,7 +5,7 @@ LL | x = box x; | ^^^^^ | | | cyclic type of infinite size - | help: try using a conversion method: `box x.to_string()` + | help: try using a conversion method: `(box x).to_string()` error[E0055]: reached the recursion limit while auto-dereferencing `Foo` --> $DIR/infinite-autoderef.rs:25:5 diff --git a/src/test/ui/occurs-check-2.stderr b/src/test/ui/occurs-check-2.stderr index 74e29a5aea728..7f93697c6f7a7 100644 --- a/src/test/ui/occurs-check-2.stderr +++ b/src/test/ui/occurs-check-2.stderr @@ -5,7 +5,7 @@ LL | f = box g; | ^^^^^ | | | cyclic type of infinite size - | help: try using a conversion method: `box g.to_string()` + | help: try using a conversion method: `(box g).to_string()` error: aborting due to previous error diff --git a/src/test/ui/occurs-check.stderr b/src/test/ui/occurs-check.stderr index 61ce61b1cbeb6..01e2b1f774910 100644 --- a/src/test/ui/occurs-check.stderr +++ b/src/test/ui/occurs-check.stderr @@ -5,7 +5,7 @@ LL | f = box f; | ^^^^^ | | | cyclic type of infinite size - | help: try using a conversion method: `box f.to_string()` + | help: try using a conversion method: `(box f).to_string()` error: aborting due to previous error diff --git a/src/test/ui/span/coerce-suggestions.stderr b/src/test/ui/span/coerce-suggestions.stderr index 996d80a07e058..0d15a2a753ed0 100644 --- a/src/test/ui/span/coerce-suggestions.stderr +++ b/src/test/ui/span/coerce-suggestions.stderr @@ -44,7 +44,7 @@ LL | f = box f; | ^^^^^ | | | cyclic type of infinite size - | help: try using a conversion method: `box f.to_string()` + | help: try using a conversion method: `(box f).to_string()` error[E0308]: mismatched types --> $DIR/coerce-suggestions.rs:21:9 From e1d9f8260541def74d35ce2f26830ac3aaf57cee Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 1 Oct 2019 13:53:17 +0200 Subject: [PATCH 29/32] Update cargo. --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index ab6fa8908c9b6..8b0561d68f12e 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit ab6fa8908c9b6c8f7e2249231c395eebfbc49891 +Subproject commit 8b0561d68f12eeb1d72e07ceef464ebf6032a1bc From 6c1b447f2e67f5eae89394344ade698aca3ec7e6 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Tue, 1 Oct 2019 11:55:46 +0000 Subject: [PATCH 30/32] Remove unneeded `fn main` blocks from docs --- src/liballoc/boxed.rs | 54 +++--- src/liballoc/collections/btree/map.rs | 2 - src/liballoc/rc.rs | 8 +- src/liballoc/slice.rs | 11 +- src/liballoc/str.rs | 6 +- src/liballoc/string.rs | 6 +- src/liballoc/sync.rs | 8 +- src/liballoc/vec.rs | 44 +++-- src/libcore/any.rs | 90 ++++------ src/libcore/char/convert.rs | 16 +- src/libcore/char/decode.rs | 50 +++--- src/libcore/fmt/mod.rs | 10 +- src/libcore/ptr/mod.rs | 48 +++--- src/libstd/collections/hash/map.rs | 11 +- src/libstd/collections/hash/set.rs | 8 +- src/libstd/net/addr.rs | 17 +- src/libstd/net/ip.rs | 237 +++++++++++--------------- src/libstd/primitive_docs.rs | 12 +- 18 files changed, 266 insertions(+), 372 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index c61e3183409f2..b2789a535fe49 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -29,10 +29,8 @@ //! Nil, //! } //! -//! fn main() { -//! let list: List = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Nil)))); -//! println!("{:?}", list); -//! } +//! let list: List = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Nil)))); +//! println!("{:?}", list); //! ``` //! //! This will print `Cons(1, Cons(2, Nil))`. @@ -375,14 +373,12 @@ impl Box { /// ``` /// #![feature(box_into_raw_non_null)] /// - /// fn main() { - /// let x = Box::new(5); - /// let ptr = Box::into_raw_non_null(x); + /// let x = Box::new(5); + /// let ptr = Box::into_raw_non_null(x); /// - /// // Clean up the memory by converting the NonNull pointer back - /// // into a Box and letting the Box be dropped. - /// let x = unsafe { Box::from_raw(ptr.as_ptr()) }; - /// } + /// // Clean up the memory by converting the NonNull pointer back + /// // into a Box and letting the Box be dropped. + /// let x = unsafe { Box::from_raw(ptr.as_ptr()) }; /// ``` #[unstable(feature = "box_into_raw_non_null", issue = "47336")] #[inline] @@ -428,23 +424,19 @@ impl Box { /// Simple usage: /// /// ``` - /// fn main() { - /// let x = Box::new(41); - /// let static_ref: &'static mut usize = Box::leak(x); - /// *static_ref += 1; - /// assert_eq!(*static_ref, 42); - /// } + /// let x = Box::new(41); + /// let static_ref: &'static mut usize = Box::leak(x); + /// *static_ref += 1; + /// assert_eq!(*static_ref, 42); /// ``` /// /// Unsized data: /// /// ``` - /// fn main() { - /// let x = vec![1, 2, 3].into_boxed_slice(); - /// let static_ref = Box::leak(x); - /// static_ref[0] = 4; - /// assert_eq!(*static_ref, [4, 2, 3]); - /// } + /// let x = vec![1, 2, 3].into_boxed_slice(); + /// let static_ref = Box::leak(x); + /// static_ref[0] = 4; + /// assert_eq!(*static_ref, [4, 2, 3]); /// ``` #[stable(feature = "box_leak", since = "1.26.0")] #[inline] @@ -780,11 +772,9 @@ impl Box { /// } /// } /// - /// fn main() { - /// let my_string = "Hello World".to_string(); - /// print_if_string(Box::new(my_string)); - /// print_if_string(Box::new(0i8)); - /// } + /// let my_string = "Hello World".to_string(); + /// print_if_string(Box::new(my_string)); + /// print_if_string(Box::new(0i8)); /// ``` pub fn downcast(self) -> Result, Box> { if self.is::() { @@ -814,11 +804,9 @@ impl Box { /// } /// } /// - /// fn main() { - /// let my_string = "Hello World".to_string(); - /// print_if_string(Box::new(my_string)); - /// print_if_string(Box::new(0i8)); - /// } + /// let my_string = "Hello World".to_string(); + /// print_if_string(Box::new(my_string)); + /// print_if_string(Box::new(0i8)); /// ``` pub fn downcast(self) -> Result, Box> { >::downcast(self).map_err(|s| unsafe { diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index ddf012d15029a..83fd4485f7321 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -2226,14 +2226,12 @@ impl<'a, K: Ord, V: Default> Entry<'a, K, V> { /// # Examples /// /// ``` - /// # fn main() { /// use std::collections::BTreeMap; /// /// let mut map: BTreeMap<&str, Option> = BTreeMap::new(); /// map.entry("poneyland").or_default(); /// /// assert_eq!(map["poneyland"], None); - /// # } /// ``` pub fn or_default(self) -> &'a mut V { match self { diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index f234ac5ebe51b..a28c6d22abb95 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -861,11 +861,9 @@ impl Rc { /// } /// } /// - /// fn main() { - /// let my_string = "Hello World".to_string(); - /// print_if_string(Rc::new(my_string)); - /// print_if_string(Rc::new(0i8)); - /// } + /// let my_string = "Hello World".to_string(); + /// print_if_string(Rc::new(my_string)); + /// print_if_string(Rc::new(0i8)); /// ``` pub fn downcast(self) -> Result, Rc> { if (*self).is::() { diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index 881d499c0745b..4e4a285c21dab 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -412,20 +412,15 @@ impl [T] { /// /// ``` /// #![feature(repeat_generic_slice)] - /// - /// fn main() { - /// assert_eq!([1, 2].repeat(3), vec![1, 2, 1, 2, 1, 2]); - /// } + /// assert_eq!([1, 2].repeat(3), vec![1, 2, 1, 2, 1, 2]); /// ``` /// /// A panic upon overflow: /// /// ```should_panic /// #![feature(repeat_generic_slice)] - /// fn main() { - /// // this will panic at runtime - /// b"0123456789abcdef".repeat(usize::max_value()); - /// } + /// // this will panic at runtime + /// b"0123456789abcdef".repeat(usize::max_value()); /// ``` #[unstable(feature = "repeat_generic_slice", reason = "it's on str, why not on slice?", diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index 9a1342c30d502..9231c2d3f1d56 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -500,10 +500,8 @@ impl str { /// A panic upon overflow: /// /// ```should_panic - /// fn main() { - /// // this will panic at runtime - /// "0123456789abcdef".repeat(usize::max_value()); - /// } + /// // this will panic at runtime + /// "0123456789abcdef".repeat(usize::max_value()); /// ``` #[stable(feature = "repeat_str", since = "1.16.0")] pub fn repeat(&self, n: usize) -> String { diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index abe50fdb7a396..639124e26cc20 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -164,10 +164,8 @@ use crate::vec::Vec; /// /// fn example_func(example_arg: A) {} /// -/// fn main() { -/// let example_string = String::from("example_string"); -/// example_func(&example_string); -/// } +/// let example_string = String::from("example_string"); +/// example_func(&example_string); /// ``` /// /// There are two options that would work instead. The first would be to diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index 45f98162e4cd5..5977e69b7fa0f 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -1244,11 +1244,9 @@ impl Arc { /// } /// } /// - /// fn main() { - /// let my_string = "Hello World".to_string(); - /// print_if_string(Arc::new(my_string)); - /// print_if_string(Arc::new(0i8)); - /// } + /// let my_string = "Hello World".to_string(); + /// print_if_string(Arc::new(my_string)); + /// print_if_string(Arc::new(0i8)); /// ``` pub fn downcast(self) -> Result, Self> where diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index e5672f8542ff6..47db9edc3ff49 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -389,28 +389,26 @@ impl Vec { /// use std::ptr; /// use std::mem; /// - /// fn main() { - /// let mut v = vec![1, 2, 3]; - /// - /// // Pull out the various important pieces of information about `v` - /// let p = v.as_mut_ptr(); - /// let len = v.len(); - /// let cap = v.capacity(); + /// let mut v = vec![1, 2, 3]; /// - /// unsafe { - /// // Cast `v` into the void: no destructor run, so we are in - /// // complete control of the allocation to which `p` points. - /// mem::forget(v); + /// // Pull out the various important pieces of information about `v` + /// let p = v.as_mut_ptr(); + /// let len = v.len(); + /// let cap = v.capacity(); /// - /// // Overwrite memory with 4, 5, 6 - /// for i in 0..len as isize { - /// ptr::write(p.offset(i), 4 + i); - /// } + /// unsafe { + /// // Cast `v` into the void: no destructor run, so we are in + /// // complete control of the allocation to which `p` points. + /// mem::forget(v); /// - /// // Put everything back together into a Vec - /// let rebuilt = Vec::from_raw_parts(p, len, cap); - /// assert_eq!(rebuilt, [4, 5, 6]); + /// // Overwrite memory with 4, 5, 6 + /// for i in 0..len as isize { + /// ptr::write(p.offset(i), 4 + i); /// } + /// + /// // Put everything back together into a Vec + /// let rebuilt = Vec::from_raw_parts(p, len, cap); + /// assert_eq!(rebuilt, [4, 5, 6]); /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -1391,12 +1389,10 @@ impl Vec { /// ``` /// #![feature(vec_leak)] /// - /// fn main() { - /// let x = vec![1, 2, 3]; - /// let static_ref: &'static mut [usize] = Vec::leak(x); - /// static_ref[0] += 1; - /// assert_eq!(static_ref, &[2, 2, 3]); - /// } + /// let x = vec![1, 2, 3]; + /// let static_ref: &'static mut [usize] = Vec::leak(x); + /// static_ref[0] += 1; + /// assert_eq!(static_ref, &[2, 2, 3]); /// ``` #[unstable(feature = "vec_leak", issue = "62195")] #[inline] diff --git a/src/libcore/any.rs b/src/libcore/any.rs index 0afbf4f134679..85b59162620fa 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -87,10 +87,8 @@ pub trait Any: 'static { /// TypeId::of::() == s.type_id() /// } /// - /// fn main() { - /// assert_eq!(is_string(&0), false); - /// assert_eq!(is_string(&"cookie monster".to_string()), true); - /// } + /// assert_eq!(is_string(&0), false); + /// assert_eq!(is_string(&"cookie monster".to_string()), true); /// ``` #[stable(feature = "get_type_id", since = "1.34.0")] fn type_id(&self) -> TypeId; @@ -145,10 +143,8 @@ impl dyn Any { /// } /// } /// - /// fn main() { - /// is_string(&0); - /// is_string(&"cookie monster".to_string()); - /// } + /// is_string(&0); + /// is_string(&"cookie monster".to_string()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -179,10 +175,8 @@ impl dyn Any { /// } /// } /// - /// fn main() { - /// print_if_string(&0); - /// print_if_string(&"cookie monster".to_string()); - /// } + /// print_if_string(&0); + /// print_if_string(&"cookie monster".to_string()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -210,16 +204,14 @@ impl dyn Any { /// } /// } /// - /// fn main() { - /// let mut x = 10u32; - /// let mut s = "starlord".to_string(); + /// let mut x = 10u32; + /// let mut s = "starlord".to_string(); /// - /// modify_if_u32(&mut x); - /// modify_if_u32(&mut s); + /// modify_if_u32(&mut x); + /// modify_if_u32(&mut s); /// - /// assert_eq!(x, 42); - /// assert_eq!(&s, "starlord"); - /// } + /// assert_eq!(x, 42); + /// assert_eq!(&s, "starlord"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -250,10 +242,8 @@ impl dyn Any+Send { /// } /// } /// - /// fn main() { - /// is_string(&0); - /// is_string(&"cookie monster".to_string()); - /// } + /// is_string(&0); + /// is_string(&"cookie monster".to_string()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -276,10 +266,8 @@ impl dyn Any+Send { /// } /// } /// - /// fn main() { - /// print_if_string(&0); - /// print_if_string(&"cookie monster".to_string()); - /// } + /// print_if_string(&0); + /// print_if_string(&"cookie monster".to_string()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -300,16 +288,14 @@ impl dyn Any+Send { /// } /// } /// - /// fn main() { - /// let mut x = 10u32; - /// let mut s = "starlord".to_string(); + /// let mut x = 10u32; + /// let mut s = "starlord".to_string(); /// - /// modify_if_u32(&mut x); - /// modify_if_u32(&mut s); + /// modify_if_u32(&mut x); + /// modify_if_u32(&mut s); /// - /// assert_eq!(x, 42); - /// assert_eq!(&s, "starlord"); - /// } + /// assert_eq!(x, 42); + /// assert_eq!(&s, "starlord"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -334,10 +320,8 @@ impl dyn Any+Send+Sync { /// } /// } /// - /// fn main() { - /// is_string(&0); - /// is_string(&"cookie monster".to_string()); - /// } + /// is_string(&0); + /// is_string(&"cookie monster".to_string()); /// ``` #[stable(feature = "any_send_sync_methods", since = "1.28.0")] #[inline] @@ -360,10 +344,8 @@ impl dyn Any+Send+Sync { /// } /// } /// - /// fn main() { - /// print_if_string(&0); - /// print_if_string(&"cookie monster".to_string()); - /// } + /// print_if_string(&0); + /// print_if_string(&"cookie monster".to_string()); /// ``` #[stable(feature = "any_send_sync_methods", since = "1.28.0")] #[inline] @@ -384,16 +366,14 @@ impl dyn Any+Send+Sync { /// } /// } /// - /// fn main() { - /// let mut x = 10u32; - /// let mut s = "starlord".to_string(); + /// let mut x = 10u32; + /// let mut s = "starlord".to_string(); /// - /// modify_if_u32(&mut x); - /// modify_if_u32(&mut s); + /// modify_if_u32(&mut x); + /// modify_if_u32(&mut s); /// - /// assert_eq!(x, 42); - /// assert_eq!(&s, "starlord"); - /// } + /// assert_eq!(x, 42); + /// assert_eq!(&s, "starlord"); /// ``` #[stable(feature = "any_send_sync_methods", since = "1.28.0")] #[inline] @@ -437,10 +417,8 @@ impl TypeId { /// TypeId::of::() == TypeId::of::() /// } /// - /// fn main() { - /// assert_eq!(is_string(&0), false); - /// assert_eq!(is_string(&"cookie monster".to_string()), true); - /// } + /// assert_eq!(is_string(&0), false); + /// assert_eq!(is_string(&"cookie monster".to_string()), true); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature="const_type_id")] diff --git a/src/libcore/char/convert.rs b/src/libcore/char/convert.rs index 0a870c67518c7..c456e14db12d4 100644 --- a/src/libcore/char/convert.rs +++ b/src/libcore/char/convert.rs @@ -111,11 +111,9 @@ impl From for u32 { /// ``` /// use std::mem; /// - /// fn main() { - /// let c = 'c'; - /// let u = u32::from(c); - /// assert!(4 == mem::size_of_val(&u)) - /// } + /// let c = 'c'; + /// let u = u32::from(c); + /// assert!(4 == mem::size_of_val(&u)) /// ``` #[inline] fn from(c: char) -> Self { @@ -150,11 +148,9 @@ impl From for char { /// ``` /// use std::mem; /// - /// fn main() { - /// let u = 32 as u8; - /// let c = char::from(u); - /// assert!(4 == mem::size_of_val(&c)) - /// } + /// let u = 32 as u8; + /// let c = char::from(u); + /// assert!(4 == mem::size_of_val(&c)) /// ``` #[inline] fn from(i: u8) -> Self { diff --git a/src/libcore/char/decode.rs b/src/libcore/char/decode.rs index 23059243c61d7..b71c9c2c40b37 100644 --- a/src/libcore/char/decode.rs +++ b/src/libcore/char/decode.rs @@ -31,21 +31,23 @@ pub struct DecodeUtf16Error { /// ``` /// use std::char::decode_utf16; /// -/// fn main() { -/// // 𝄞music -/// let v = [0xD834, 0xDD1E, 0x006d, 0x0075, -/// 0x0073, 0xDD1E, 0x0069, 0x0063, -/// 0xD834]; +/// // 𝄞music +/// let v = [ +/// 0xD834, 0xDD1E, 0x006d, 0x0075, 0x0073, 0xDD1E, 0x0069, 0x0063, 0xD834, +/// ]; /// -/// assert_eq!(decode_utf16(v.iter().cloned()) -/// .map(|r| r.map_err(|e| e.unpaired_surrogate())) -/// .collect::>(), -/// vec![Ok('𝄞'), -/// Ok('m'), Ok('u'), Ok('s'), -/// Err(0xDD1E), -/// Ok('i'), Ok('c'), -/// Err(0xD834)]); -/// } +/// assert_eq!( +/// decode_utf16(v.iter().cloned()) +/// .map(|r| r.map_err(|e| e.unpaired_surrogate())) +/// .collect::>(), +/// vec![ +/// Ok('𝄞'), +/// Ok('m'), Ok('u'), Ok('s'), +/// Err(0xDD1E), +/// Ok('i'), Ok('c'), +/// Err(0xD834) +/// ] +/// ); /// ``` /// /// A lossy decoder can be obtained by replacing `Err` results with the replacement character: @@ -53,17 +55,17 @@ pub struct DecodeUtf16Error { /// ``` /// use std::char::{decode_utf16, REPLACEMENT_CHARACTER}; /// -/// fn main() { -/// // 𝄞music -/// let v = [0xD834, 0xDD1E, 0x006d, 0x0075, -/// 0x0073, 0xDD1E, 0x0069, 0x0063, -/// 0xD834]; +/// // 𝄞music +/// let v = [ +/// 0xD834, 0xDD1E, 0x006d, 0x0075, 0x0073, 0xDD1E, 0x0069, 0x0063, 0xD834, +/// ]; /// -/// assert_eq!(decode_utf16(v.iter().cloned()) -/// .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER)) -/// .collect::(), -/// "𝄞mus�ic�"); -/// } +/// assert_eq!( +/// decode_utf16(v.iter().cloned()) +/// .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER)) +/// .collect::(), +/// "𝄞mus�ic�" +/// ); /// ``` #[stable(feature = "decode_utf16", since = "1.9.0")] #[inline] diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index aafa35873bb65..5dfdd1623061e 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1532,12 +1532,10 @@ impl<'a> Formatter<'a> { /// } /// } /// - /// fn main() { - /// assert_eq!(&format!("{:<}", Foo), "left"); - /// assert_eq!(&format!("{:>}", Foo), "right"); - /// assert_eq!(&format!("{:^}", Foo), "center"); - /// assert_eq!(&format!("{}", Foo), "into the void"); - /// } + /// assert_eq!(&format!("{:<}", Foo), "left"); + /// assert_eq!(&format!("{:>}", Foo), "right"); + /// assert_eq!(&format!("{:^}", Foo), "center"); + /// assert_eq!(&format!("{}", Foo), "into the void"); /// ``` #[stable(feature = "fmt_flags_align", since = "1.28.0")] pub fn align(&self) -> Option { diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs index 13ccc9b252a77..933919185956e 100644 --- a/src/libcore/ptr/mod.rs +++ b/src/libcore/ptr/mod.rs @@ -2732,31 +2732,29 @@ impl Eq for *mut T {} /// impl Trait for Wrapper {} /// impl Trait for i32 {} /// -/// fn main() { -/// let wrapper = Wrapper { member: 10 }; -/// -/// // Pointers have equal addresses. -/// assert!(std::ptr::eq( -/// &wrapper as *const Wrapper as *const u8, -/// &wrapper.member as *const i32 as *const u8 -/// )); -/// -/// // Objects have equal addresses, but `Trait` has different implementations. -/// assert!(!std::ptr::eq( -/// &wrapper as &dyn Trait, -/// &wrapper.member as &dyn Trait, -/// )); -/// assert!(!std::ptr::eq( -/// &wrapper as &dyn Trait as *const dyn Trait, -/// &wrapper.member as &dyn Trait as *const dyn Trait, -/// )); -/// -/// // Converting the reference to a `*const u8` compares by address. -/// assert!(std::ptr::eq( -/// &wrapper as &dyn Trait as *const dyn Trait as *const u8, -/// &wrapper.member as &dyn Trait as *const dyn Trait as *const u8, -/// )); -/// } +/// let wrapper = Wrapper { member: 10 }; +/// +/// // Pointers have equal addresses. +/// assert!(std::ptr::eq( +/// &wrapper as *const Wrapper as *const u8, +/// &wrapper.member as *const i32 as *const u8 +/// )); +/// +/// // Objects have equal addresses, but `Trait` has different implementations. +/// assert!(!std::ptr::eq( +/// &wrapper as &dyn Trait, +/// &wrapper.member as &dyn Trait, +/// )); +/// assert!(!std::ptr::eq( +/// &wrapper as &dyn Trait as *const dyn Trait, +/// &wrapper.member as &dyn Trait as *const dyn Trait, +/// )); +/// +/// // Converting the reference to a `*const u8` compares by address. +/// assert!(std::ptr::eq( +/// &wrapper as &dyn Trait as *const dyn Trait as *const u8, +/// &wrapper.member as &dyn Trait as *const dyn Trait as *const u8, +/// )); /// ``` #[stable(feature = "ptr_eq", since = "1.17.0")] #[inline] diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 69abbde9e6eba..ff50051ef5040 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -192,14 +192,9 @@ use crate::sys; /// ``` /// use std::collections::HashMap; /// -/// fn main() { -/// let timber_resources: HashMap<&str, i32> = -/// [("Norway", 100), -/// ("Denmark", 50), -/// ("Iceland", 10)] -/// .iter().cloned().collect(); -/// // use the values stored in map -/// } +/// let timber_resources: HashMap<&str, i32> = [("Norway", 100), ("Denmark", 50), ("Iceland", 10)] +/// .iter().cloned().collect(); +/// // use the values stored in map /// ``` #[derive(Clone)] diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index 26db651ef8911..092fb44346848 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -93,11 +93,9 @@ use super::map::{self, HashMap, Keys, RandomState}; /// ``` /// use std::collections::HashSet; /// -/// fn main() { -/// let viking_names: HashSet<&'static str> = -/// [ "Einar", "Olaf", "Harald" ].iter().cloned().collect(); -/// // use the values stored in the set -/// } +/// let viking_names: HashSet<&'static str> = +/// [ "Einar", "Olaf", "Harald" ].iter().cloned().collect(); +/// // use the values stored in the set /// ``` /// /// [`Cell`]: ../../std/cell/struct.Cell.html diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index ca86a175058b5..f9255b82fc83e 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -217,11 +217,9 @@ impl SocketAddr { /// ``` /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; /// - /// fn main() { - /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); - /// assert_eq!(socket.is_ipv4(), true); - /// assert_eq!(socket.is_ipv6(), false); - /// } + /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); + /// assert_eq!(socket.is_ipv4(), true); + /// assert_eq!(socket.is_ipv6(), false); /// ``` #[stable(feature = "sockaddr_checker", since = "1.16.0")] pub fn is_ipv4(&self) -> bool { @@ -244,12 +242,9 @@ impl SocketAddr { /// ``` /// use std::net::{IpAddr, Ipv6Addr, SocketAddr}; /// - /// fn main() { - /// let socket = SocketAddr::new( - /// IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 0, 1)), 8080); - /// assert_eq!(socket.is_ipv4(), false); - /// assert_eq!(socket.is_ipv6(), true); - /// } + /// let socket = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 0, 1)), 8080); + /// assert_eq!(socket.is_ipv4(), false); + /// assert_eq!(socket.is_ipv6(), true); /// ``` #[stable(feature = "sockaddr_checker", since = "1.16.0")] pub fn is_ipv6(&self) -> bool { diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 6b504056e5f87..70b68d1348550 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -197,11 +197,8 @@ impl IpAddr { /// /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// - /// fn main() { - /// assert_eq!(IpAddr::V4(Ipv4Addr::new(80, 9, 12, 3)).is_global(), true); - /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1)).is_global(), - /// true); - /// } + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(80, 9, 12, 3)).is_global(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1)).is_global(), true); /// ``` pub fn is_global(&self) -> bool { match self { @@ -251,11 +248,11 @@ impl IpAddr { /// /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// - /// fn main() { - /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_documentation(), true); - /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)) - /// .is_documentation(), true); - /// } + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_documentation(), true); + /// assert_eq!( + /// IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_documentation(), + /// true + /// ); /// ``` pub fn is_documentation(&self) -> bool { match self { @@ -275,11 +272,8 @@ impl IpAddr { /// ``` /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// - /// fn main() { - /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv4(), true); - /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv4(), - /// false); - /// } + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv4(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv4(), false); /// ``` #[stable(feature = "ipaddr_checker", since = "1.16.0")] pub fn is_ipv4(&self) -> bool { @@ -300,11 +294,8 @@ impl IpAddr { /// ``` /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// - /// fn main() { - /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv6(), false); - /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv6(), - /// true); - /// } + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv6(), false); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv6(), true); /// ``` #[stable(feature = "ipaddr_checker", since = "1.16.0")] pub fn is_ipv6(&self) -> bool { @@ -526,48 +517,46 @@ impl Ipv4Addr { /// /// use std::net::Ipv4Addr; /// - /// fn main() { - /// // private addresses are not global - /// assert_eq!(Ipv4Addr::new(10, 254, 0, 0).is_global(), false); - /// assert_eq!(Ipv4Addr::new(192, 168, 10, 65).is_global(), false); - /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_global(), false); + /// // private addresses are not global + /// assert_eq!(Ipv4Addr::new(10, 254, 0, 0).is_global(), false); + /// assert_eq!(Ipv4Addr::new(192, 168, 10, 65).is_global(), false); + /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_global(), false); /// - /// // the 0.0.0.0/8 block is not global - /// assert_eq!(Ipv4Addr::new(0, 1, 2, 3).is_global(), false); - /// // in particular, the unspecified address is not global - /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_global(), false); + /// // the 0.0.0.0/8 block is not global + /// assert_eq!(Ipv4Addr::new(0, 1, 2, 3).is_global(), false); + /// // in particular, the unspecified address is not global + /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_global(), false); /// - /// // the loopback address is not global - /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_global(), false); + /// // the loopback address is not global + /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_global(), false); /// - /// // link local addresses are not global - /// assert_eq!(Ipv4Addr::new(169, 254, 45, 1).is_global(), false); + /// // link local addresses are not global + /// assert_eq!(Ipv4Addr::new(169, 254, 45, 1).is_global(), false); /// - /// // the broadcast address is not global - /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_global(), false); + /// // the broadcast address is not global + /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_global(), false); /// - /// // the broadcast address is not global - /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_global(), false); - /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_global(), false); - /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_global(), false); + /// // the broadcast address is not global + /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_global(), false); + /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_global(), false); + /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_global(), false); /// - /// // shared addresses are not global - /// assert_eq!(Ipv4Addr::new(100, 100, 0, 0).is_global(), false); + /// // shared addresses are not global + /// assert_eq!(Ipv4Addr::new(100, 100, 0, 0).is_global(), false); /// - /// // addresses reserved for protocol assignment are not global - /// assert_eq!(Ipv4Addr::new(192, 0, 0, 0).is_global(), false); - /// assert_eq!(Ipv4Addr::new(192, 0, 0, 255).is_global(), false); + /// // addresses reserved for protocol assignment are not global + /// assert_eq!(Ipv4Addr::new(192, 0, 0, 0).is_global(), false); + /// assert_eq!(Ipv4Addr::new(192, 0, 0, 255).is_global(), false); /// - /// // addresses reserved for future use are not global - /// assert_eq!(Ipv4Addr::new(250, 10, 20, 30).is_global(), false); + /// // addresses reserved for future use are not global + /// assert_eq!(Ipv4Addr::new(250, 10, 20, 30).is_global(), false); /// - /// // addresses reserved for network devices benchmarking are not global - /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_global(), false); + /// // addresses reserved for network devices benchmarking are not global + /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_global(), false); /// - /// // All the other addresses are global - /// assert_eq!(Ipv4Addr::new(1, 1, 1, 1).is_global(), true); - /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true); - /// } + /// // All the other addresses are global + /// assert_eq!(Ipv4Addr::new(1, 1, 1, 1).is_global(), true); + /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true); /// ``` pub fn is_global(&self) -> bool { // check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two @@ -600,11 +589,9 @@ impl Ipv4Addr { /// #![feature(ip)] /// use std::net::Ipv4Addr; /// - /// fn main() { - /// assert_eq!(Ipv4Addr::new(100, 64, 0, 0).is_shared(), true); - /// assert_eq!(Ipv4Addr::new(100, 127, 255, 255).is_shared(), true); - /// assert_eq!(Ipv4Addr::new(100, 128, 0, 0).is_shared(), false); - /// } + /// assert_eq!(Ipv4Addr::new(100, 64, 0, 0).is_shared(), true); + /// assert_eq!(Ipv4Addr::new(100, 127, 255, 255).is_shared(), true); + /// assert_eq!(Ipv4Addr::new(100, 128, 0, 0).is_shared(), false); /// ``` pub fn is_shared(&self) -> bool { self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000) @@ -631,14 +618,12 @@ impl Ipv4Addr { /// #![feature(ip)] /// use std::net::Ipv4Addr; /// - /// fn main() { - /// assert_eq!(Ipv4Addr::new(192, 0, 0, 0).is_ietf_protocol_assignment(), true); - /// assert_eq!(Ipv4Addr::new(192, 0, 0, 8).is_ietf_protocol_assignment(), true); - /// assert_eq!(Ipv4Addr::new(192, 0, 0, 9).is_ietf_protocol_assignment(), true); - /// assert_eq!(Ipv4Addr::new(192, 0, 0, 255).is_ietf_protocol_assignment(), true); - /// assert_eq!(Ipv4Addr::new(192, 0, 1, 0).is_ietf_protocol_assignment(), false); - /// assert_eq!(Ipv4Addr::new(191, 255, 255, 255).is_ietf_protocol_assignment(), false); - /// } + /// assert_eq!(Ipv4Addr::new(192, 0, 0, 0).is_ietf_protocol_assignment(), true); + /// assert_eq!(Ipv4Addr::new(192, 0, 0, 8).is_ietf_protocol_assignment(), true); + /// assert_eq!(Ipv4Addr::new(192, 0, 0, 9).is_ietf_protocol_assignment(), true); + /// assert_eq!(Ipv4Addr::new(192, 0, 0, 255).is_ietf_protocol_assignment(), true); + /// assert_eq!(Ipv4Addr::new(192, 0, 1, 0).is_ietf_protocol_assignment(), false); + /// assert_eq!(Ipv4Addr::new(191, 255, 255, 255).is_ietf_protocol_assignment(), false); /// ``` pub fn is_ietf_protocol_assignment(&self) -> bool { self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0 @@ -658,12 +643,10 @@ impl Ipv4Addr { /// #![feature(ip)] /// use std::net::Ipv4Addr; /// - /// fn main() { - /// assert_eq!(Ipv4Addr::new(198, 17, 255, 255).is_benchmarking(), false); - /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_benchmarking(), true); - /// assert_eq!(Ipv4Addr::new(198, 19, 255, 255).is_benchmarking(), true); - /// assert_eq!(Ipv4Addr::new(198, 20, 0, 0).is_benchmarking(), false); - /// } + /// assert_eq!(Ipv4Addr::new(198, 17, 255, 255).is_benchmarking(), false); + /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_benchmarking(), true); + /// assert_eq!(Ipv4Addr::new(198, 19, 255, 255).is_benchmarking(), true); + /// assert_eq!(Ipv4Addr::new(198, 20, 0, 0).is_benchmarking(), false); /// ``` pub fn is_benchmarking(&self) -> bool { self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18 @@ -690,15 +673,12 @@ impl Ipv4Addr { /// #![feature(ip)] /// use std::net::Ipv4Addr; /// - /// fn main() { - /// assert_eq!(Ipv4Addr::new(240, 0, 0, 0).is_reserved(), true); - /// assert_eq!(Ipv4Addr::new(255, 255, 255, 254).is_reserved(), true); + /// assert_eq!(Ipv4Addr::new(240, 0, 0, 0).is_reserved(), true); + /// assert_eq!(Ipv4Addr::new(255, 255, 255, 254).is_reserved(), true); /// - /// assert_eq!(Ipv4Addr::new(239, 255, 255, 255).is_reserved(), false); - /// // The broadcast address is not considered as reserved for future use by this - /// // implementation - /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_reserved(), false); - /// } + /// assert_eq!(Ipv4Addr::new(239, 255, 255, 255).is_reserved(), false); + /// // The broadcast address is not considered as reserved for future use by this implementation + /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_reserved(), false); /// ``` pub fn is_reserved(&self) -> bool { self.octets()[0] & 240 == 240 && !self.is_broadcast() @@ -788,8 +768,10 @@ impl Ipv4Addr { /// ``` /// use std::net::{Ipv4Addr, Ipv6Addr}; /// - /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_compatible(), - /// Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 767)); + /// assert_eq!( + /// Ipv4Addr::new(192, 0, 2, 255).to_ipv6_compatible(), + /// Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 767) + /// ); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn to_ipv6_compatible(&self) -> Ipv6Addr { @@ -1161,11 +1143,9 @@ impl Ipv6Addr { /// /// use std::net::Ipv6Addr; /// - /// fn main() { - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_global(), true); - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_global(), false); - /// assert_eq!(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1).is_global(), true); - /// } + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_global(), true); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_global(), false); + /// assert_eq!(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1).is_global(), true); /// ``` pub fn is_global(&self) -> bool { match self.multicast_scope() { @@ -1189,11 +1169,8 @@ impl Ipv6Addr { /// /// use std::net::Ipv6Addr; /// - /// fn main() { - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unique_local(), - /// false); - /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).is_unique_local(), true); - /// } + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unique_local(), false); + /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).is_unique_local(), true); /// ``` pub fn is_unique_local(&self) -> bool { (self.segments()[0] & 0xfe00) == 0xfc00 @@ -1223,21 +1200,19 @@ impl Ipv6Addr { /// /// use std::net::Ipv6Addr; /// - /// fn main() { - /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0); - /// assert!(ip.is_unicast_link_local_strict()); + /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0); + /// assert!(ip.is_unicast_link_local_strict()); /// - /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff); - /// assert!(ip.is_unicast_link_local_strict()); + /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff); + /// assert!(ip.is_unicast_link_local_strict()); /// - /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0); - /// assert!(!ip.is_unicast_link_local_strict()); - /// assert!(ip.is_unicast_link_local()); + /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0); + /// assert!(!ip.is_unicast_link_local_strict()); + /// assert!(ip.is_unicast_link_local()); /// - /// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0); - /// assert!(!ip.is_unicast_link_local_strict()); - /// assert!(ip.is_unicast_link_local()); - /// } + /// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0); + /// assert!(!ip.is_unicast_link_local_strict()); + /// assert!(ip.is_unicast_link_local()); /// ``` /// /// # See also @@ -1284,21 +1259,19 @@ impl Ipv6Addr { /// /// use std::net::Ipv6Addr; /// - /// fn main() { - /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0); - /// assert!(ip.is_unicast_link_local()); + /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0); + /// assert!(ip.is_unicast_link_local()); /// - /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff); - /// assert!(ip.is_unicast_link_local()); + /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff); + /// assert!(ip.is_unicast_link_local()); /// - /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0); - /// assert!(ip.is_unicast_link_local()); - /// assert!(!ip.is_unicast_link_local_strict()); + /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0); + /// assert!(ip.is_unicast_link_local()); + /// assert!(!ip.is_unicast_link_local_strict()); /// - /// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0); - /// assert!(ip.is_unicast_link_local()); - /// assert!(!ip.is_unicast_link_local_strict()); - /// } + /// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0); + /// assert!(ip.is_unicast_link_local()); + /// assert!(!ip.is_unicast_link_local_strict()); /// ``` /// /// # See also @@ -1336,11 +1309,11 @@ impl Ipv6Addr { /// /// use std::net::Ipv6Addr; /// - /// fn main() { - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_site_local(), - /// false); - /// assert_eq!(Ipv6Addr::new(0xfec2, 0, 0, 0, 0, 0, 0, 0).is_unicast_site_local(), true); - /// } + /// assert_eq!( + /// Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_site_local(), + /// false + /// ); + /// assert_eq!(Ipv6Addr::new(0xfec2, 0, 0, 0, 0, 0, 0, 0).is_unicast_site_local(), true); /// ``` /// /// # Warning @@ -1369,11 +1342,8 @@ impl Ipv6Addr { /// /// use std::net::Ipv6Addr; /// - /// fn main() { - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_documentation(), - /// false); - /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true); - /// } + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_documentation(), false); + /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true); /// ``` pub fn is_documentation(&self) -> bool { (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) @@ -1407,11 +1377,8 @@ impl Ipv6Addr { /// /// use std::net::Ipv6Addr; /// - /// fn main() { - /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_global(), false); - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_global(), - /// true); - /// } + /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_global(), false); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_global(), true); /// ``` pub fn is_unicast_global(&self) -> bool { !self.is_multicast() @@ -1431,11 +1398,11 @@ impl Ipv6Addr { /// /// use std::net::{Ipv6Addr, Ipv6MulticastScope}; /// - /// fn main() { - /// assert_eq!(Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0).multicast_scope(), - /// Some(Ipv6MulticastScope::Global)); - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).multicast_scope(), None); - /// } + /// assert_eq!( + /// Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0).multicast_scope(), + /// Some(Ipv6MulticastScope::Global) + /// ); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).multicast_scope(), None); /// ``` pub fn multicast_scope(&self) -> Option { if self.is_multicast() { diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 3e389c40fbc01..a72951c034610 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -426,14 +426,12 @@ mod prim_unit { } /// /// use std::mem; /// -/// fn main() { -/// unsafe { -/// let my_num: *mut i32 = libc::malloc(mem::size_of::()) as *mut i32; -/// if my_num.is_null() { -/// panic!("failed to allocate memory"); -/// } -/// libc::free(my_num as *mut libc::c_void); +/// unsafe { +/// let my_num: *mut i32 = libc::malloc(mem::size_of::()) as *mut i32; +/// if my_num.is_null() { +/// panic!("failed to allocate memory"); /// } +/// libc::free(my_num as *mut libc::c_void); /// } /// ``` /// From 3173a09c525ace66200469918726ca7bf2545d0d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 1 Oct 2019 06:11:32 -0700 Subject: [PATCH 31/32] Update `Cargo.lock` for cargo update --- Cargo.lock | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cbedb552a068e..d75d193e06e63 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -265,7 +265,7 @@ dependencies = [ [[package]] name = "cargo" -version = "0.40.0" +version = "0.41.0" dependencies = [ "atty", "bytesize", @@ -600,7 +600,7 @@ checksum = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" [[package]] name = "crates-io" -version = "0.28.0" +version = "0.29.0" dependencies = [ "curl", "failure", @@ -730,25 +730,24 @@ dependencies = [ [[package]] name = "curl" -version = "0.4.21" +version = "0.4.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a85f2f95f2bd277d316d1aa8a477687ab4a6942258c7db7c89c187534669979c" +checksum = "d08ad3cb89d076a36b0ce5749eec2c9964f70c0c58480ab6b75a91ec4fc206d8" dependencies = [ "curl-sys", - "kernel32-sys", "libc", "openssl-probe", "openssl-sys", "schannel", "socket2", - "winapi 0.2.8", + "winapi 0.3.6", ] [[package]] name = "curl-sys" -version = "0.4.18" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d91a0052d5b982887d8e829bee0faffc7218ea3c6ebd3d6c2c8f678a93c9a42" +checksum = "520594da9914c1dc77ce3be450fc1c74fde67c82966d80f8e93c6d460eb0e9ae" dependencies = [ "cc", "libc", From d132a70bf42a6ea9bb5da352dfe33f379e75c3f5 Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Sun, 22 Sep 2019 17:45:47 +0200 Subject: [PATCH 32/32] BTreeSet intersection, difference & is_subnet optimizations --- src/liballoc/collections/btree/set.rs | 230 +++++++++++++++++--------- src/liballoc/tests/btree/set.rs | 110 ++++++++++-- 2 files changed, 247 insertions(+), 93 deletions(-) diff --git a/src/liballoc/collections/btree/set.rs b/src/liballoc/collections/btree/set.rs index 0cb91ba4c81da..8250fc38ccd1c 100644 --- a/src/liballoc/collections/btree/set.rs +++ b/src/liballoc/collections/btree/set.rs @@ -122,13 +122,16 @@ pub struct Difference<'a, T: 'a> { } enum DifferenceInner<'a, T: 'a> { Stitch { + // iterate all of self and some of other, spotting matches along the way self_iter: Iter<'a, T>, other_iter: Peekable>, }, Search { + // iterate a small set, look up in the large set self_iter: Iter<'a, T>, other_set: &'a BTreeSet, }, + Iterate(Iter<'a, T>), // simply stream self's elements } #[stable(feature = "collection_debug", since = "1.17.0")] @@ -147,6 +150,7 @@ impl fmt::Debug for Difference<'_, T> { self_iter, other_set: _, } => f.debug_tuple("Difference").field(&self_iter).finish(), + DifferenceInner::Iterate(iter) => f.debug_tuple("Difference").field(&iter).finish(), } } } @@ -187,13 +191,16 @@ pub struct Intersection<'a, T: 'a> { } enum IntersectionInner<'a, T: 'a> { Stitch { + // iterate similarly sized sets jointly, spotting matches along the way a: Iter<'a, T>, b: Iter<'a, T>, }, Search { + // iterate a small set, look up in the large set small_iter: Iter<'a, T>, large_set: &'a BTreeSet, }, + Answer(Option<&'a T>), // return a specific value or emptiness } #[stable(feature = "collection_debug", since = "1.17.0")] @@ -212,6 +219,9 @@ impl fmt::Debug for Intersection<'_, T> { small_iter, large_set: _, } => f.debug_tuple("Intersection").field(&small_iter).finish(), + IntersectionInner::Answer(answer) => { + f.debug_tuple("Intersection").field(&answer).finish() + } } } } @@ -314,24 +324,51 @@ impl BTreeSet { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn difference<'a>(&'a self, other: &'a BTreeSet) -> Difference<'a, T> { - if self.len() > other.len() / ITER_PERFORMANCE_TIPPING_SIZE_DIFF { - // Self is bigger than or not much smaller than other set. - // Iterate both sets jointly, spotting matches along the way. - Difference { - inner: DifferenceInner::Stitch { - self_iter: self.iter(), - other_iter: other.iter().peekable(), - }, - } + let (self_min, self_max) = if let (Some(self_min), Some(self_max)) = + (self.iter().next(), self.iter().next_back()) + { + (self_min, self_max) } else { - // Self is much smaller than other set, or both sets are empty. - // Iterate the small set, searching for matches in the large set. - Difference { - inner: DifferenceInner::Search { - self_iter: self.iter(), - other_set: other, - }, - } + return Difference { + inner: DifferenceInner::Iterate(self.iter()), + }; + }; + let (other_min, other_max) = if let (Some(other_min), Some(other_max)) = + (other.iter().next(), other.iter().next_back()) + { + (other_min, other_max) + } else { + return Difference { + inner: DifferenceInner::Iterate(self.iter()), + }; + }; + Difference { + inner: match (self_min.cmp(other_max), self_max.cmp(other_min)) { + (Greater, _) | (_, Less) => DifferenceInner::Iterate(self.iter()), + (Equal, _) => { + let mut self_iter = self.iter(); + self_iter.next(); + DifferenceInner::Iterate(self_iter) + } + (_, Equal) => { + let mut self_iter = self.iter(); + self_iter.next_back(); + DifferenceInner::Iterate(self_iter) + } + _ => { + if self.len() <= other.len() / ITER_PERFORMANCE_TIPPING_SIZE_DIFF { + DifferenceInner::Search { + self_iter: self.iter(), + other_set: other, + } + } else { + DifferenceInner::Stitch { + self_iter: self.iter(), + other_iter: other.iter().peekable(), + } + } + } + }, } } @@ -387,29 +424,48 @@ impl BTreeSet { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn intersection<'a>(&'a self, other: &'a BTreeSet) -> Intersection<'a, T> { - let (small, other) = if self.len() <= other.len() { - (self, other) + let (self_min, self_max) = if let (Some(self_min), Some(self_max)) = + (self.iter().next(), self.iter().next_back()) + { + (self_min, self_max) } else { - (other, self) + return Intersection { + inner: IntersectionInner::Answer(None), + }; }; - if small.len() > other.len() / ITER_PERFORMANCE_TIPPING_SIZE_DIFF { - // Small set is not much smaller than other set. - // Iterate both sets jointly, spotting matches along the way. - Intersection { - inner: IntersectionInner::Stitch { - a: small.iter(), - b: other.iter(), - }, - } + let (other_min, other_max) = if let (Some(other_min), Some(other_max)) = + (other.iter().next(), other.iter().next_back()) + { + (other_min, other_max) } else { - // Big difference in number of elements, or both sets are empty. - // Iterate the small set, searching for matches in the large set. - Intersection { - inner: IntersectionInner::Search { - small_iter: small.iter(), - large_set: other, - }, - } + return Intersection { + inner: IntersectionInner::Answer(None), + }; + }; + Intersection { + inner: match (self_min.cmp(other_max), self_max.cmp(other_min)) { + (Greater, _) | (_, Less) => IntersectionInner::Answer(None), + (Equal, _) => IntersectionInner::Answer(Some(self_min)), + (_, Equal) => IntersectionInner::Answer(Some(self_max)), + _ => { + if self.len() <= other.len() / ITER_PERFORMANCE_TIPPING_SIZE_DIFF { + IntersectionInner::Search { + small_iter: self.iter(), + large_set: other, + } + } else if other.len() <= self.len() / ITER_PERFORMANCE_TIPPING_SIZE_DIFF { + IntersectionInner::Search { + small_iter: other.iter(), + large_set: self, + } + } else { + IntersectionInner::Stitch { + a: self.iter(), + b: other.iter(), + } + } + } + }, } } @@ -544,43 +600,61 @@ impl BTreeSet { #[stable(feature = "rust1", since = "1.0.0")] pub fn is_subset(&self, other: &BTreeSet) -> bool { // Same result as self.difference(other).next().is_none() - // but the 3 paths below are faster (in order: hugely, 20%, 5%). + // but the code below is faster (hugely in some cases). if self.len() > other.len() { - false - } else if self.len() > other.len() / ITER_PERFORMANCE_TIPPING_SIZE_DIFF { - // Self is not much smaller than other set. - // Stolen from TreeMap - let mut x = self.iter(); - let mut y = other.iter(); - let mut a = x.next(); - let mut b = y.next(); - while a.is_some() { - if b.is_none() { + return false; + } + let (self_min, self_max) = if let (Some(self_min), Some(self_max)) = + (self.iter().next(), self.iter().next_back()) + { + (self_min, self_max) + } else { + return true; // self is empty + }; + let (other_min, other_max) = if let (Some(other_min), Some(other_max)) = + (other.iter().next(), other.iter().next_back()) + { + (other_min, other_max) + } else { + return false; // other is empty + }; + let mut self_iter = self.iter(); + match self_min.cmp(other_min) { + Less => return false, + Equal => { + self_iter.next(); + } + Greater => (), + } + match self_max.cmp(other_max) { + Greater => return false, + Equal => { + self_iter.next_back(); + } + Less => (), + } + if self_iter.len() <= other.len() / ITER_PERFORMANCE_TIPPING_SIZE_DIFF { + // Big difference in number of elements. + for next in self_iter { + if !other.contains(next) { return false; } - - let a1 = a.unwrap(); - let b1 = b.unwrap(); - - match b1.cmp(a1) { - Less => (), - Greater => return false, - Equal => a = x.next(), - } - - b = y.next(); } - true } else { - // Big difference in number of elements, or both sets are empty. - // Iterate the small set, searching for matches in the large set. - for next in self { - if !other.contains(next) { - return false; + // Self is not much smaller than other set. + let mut other_iter = other.iter(); + other_iter.next(); + other_iter.next_back(); + let mut self_next = self_iter.next(); + while let Some(self1) = self_next { + match other_iter.next().map_or(Less, |other1| self1.cmp(other1)) { + Less => return false, + Equal => self_next = self_iter.next(), + Greater => (), } } - true } + true } /// Returns `true` if the set is a superset of another, @@ -1120,6 +1194,7 @@ impl Clone for Difference<'_, T> { self_iter: self_iter.clone(), other_set, }, + DifferenceInner::Iterate(iter) => DifferenceInner::Iterate(iter.clone()), }, } } @@ -1138,7 +1213,7 @@ impl<'a, T: Ord> Iterator for Difference<'a, T> { loop { match other_iter .peek() - .map_or(Less, |other_next| Ord::cmp(self_next, other_next)) + .map_or(Less, |other_next| self_next.cmp(other_next)) { Less => return Some(self_next), Equal => { @@ -1160,6 +1235,7 @@ impl<'a, T: Ord> Iterator for Difference<'a, T> { return Some(self_next); } }, + DifferenceInner::Iterate(iter) => iter.next(), } } @@ -1167,12 +1243,13 @@ impl<'a, T: Ord> Iterator for Difference<'a, T> { let (self_len, other_len) = match &self.inner { DifferenceInner::Stitch { self_iter, - other_iter + other_iter, } => (self_iter.len(), other_iter.len()), DifferenceInner::Search { self_iter, - other_set + other_set, } => (self_iter.len(), other_set.len()), + DifferenceInner::Iterate(iter) => (iter.len(), 0), }; (self_len.saturating_sub(other_len), Some(self_len)) } @@ -1234,6 +1311,7 @@ impl Clone for Intersection<'_, T> { small_iter: small_iter.clone(), large_set, }, + IntersectionInner::Answer(answer) => IntersectionInner::Answer(answer.clone()), }, } } @@ -1251,7 +1329,7 @@ impl<'a, T: Ord> Iterator for Intersection<'a, T> { let mut a_next = a.next()?; let mut b_next = b.next()?; loop { - match Ord::cmp(a_next, b_next) { + match a_next.cmp(b_next) { Less => a_next = a.next()?, Greater => b_next = b.next()?, Equal => return Some(a_next), @@ -1267,15 +1345,17 @@ impl<'a, T: Ord> Iterator for Intersection<'a, T> { return Some(small_next); } }, + IntersectionInner::Answer(answer) => answer.take(), } } fn size_hint(&self) -> (usize, Option) { - let min_len = match &self.inner { - IntersectionInner::Stitch { a, b } => min(a.len(), b.len()), - IntersectionInner::Search { small_iter, .. } => small_iter.len(), - }; - (0, Some(min_len)) + match &self.inner { + IntersectionInner::Stitch { a, b } => (0, Some(min(a.len(), b.len()))), + IntersectionInner::Search { small_iter, .. } => (0, Some(small_iter.len())), + IntersectionInner::Answer(None) => (0, Some(0)), + IntersectionInner::Answer(Some(_)) => (1, Some(1)), + } } } diff --git a/src/liballoc/tests/btree/set.rs b/src/liballoc/tests/btree/set.rs index 35db18c39c83a..5c611fd21d21b 100644 --- a/src/liballoc/tests/btree/set.rs +++ b/src/liballoc/tests/btree/set.rs @@ -48,7 +48,9 @@ fn check(a: &[i32], b: &[i32], expected: &[i32], f: F) f(&set_a, &set_b, &mut |&x| { - assert_eq!(x, expected[i]); + if i < expected.len() { + assert_eq!(x, expected[i]); + } i += 1; true }); @@ -74,20 +76,20 @@ fn test_intersection() { return; } - let large = (0..1000).collect::>(); + let large = (0..100).collect::>(); check_intersection(&[], &large, &[]); check_intersection(&large, &[], &[]); check_intersection(&[-1], &large, &[]); check_intersection(&large, &[-1], &[]); check_intersection(&[0], &large, &[0]); check_intersection(&large, &[0], &[0]); - check_intersection(&[999], &large, &[999]); - check_intersection(&large, &[999], &[999]); - check_intersection(&[1000], &large, &[]); - check_intersection(&large, &[1000], &[]); - check_intersection(&[11, 5000, 1, 3, 77, 8924, 103], + check_intersection(&[99], &large, &[99]); + check_intersection(&large, &[99], &[99]); + check_intersection(&[100], &large, &[]); + check_intersection(&large, &[100], &[]); + check_intersection(&[11, 5000, 1, 3, 77, 8924], &large, - &[1, 3, 11, 77, 103]); + &[1, 3, 11, 77]); } #[test] @@ -95,10 +97,15 @@ fn test_intersection_size_hint() { let x: BTreeSet = [3, 4].iter().copied().collect(); let y: BTreeSet = [1, 2, 3].iter().copied().collect(); let mut iter = x.intersection(&y); - assert_eq!(iter.size_hint(), (0, Some(2))); + assert_eq!(iter.size_hint(), (1, Some(1))); assert_eq!(iter.next(), Some(&3)); assert_eq!(iter.size_hint(), (0, Some(0))); assert_eq!(iter.next(), None); + + iter = y.intersection(&y); + assert_eq!(iter.size_hint(), (0, Some(3))); + assert_eq!(iter.next(), Some(&1)); + assert_eq!(iter.size_hint(), (0, Some(2))); } #[test] @@ -111,6 +118,9 @@ fn test_difference() { check_difference(&[1, 12], &[], &[1, 12]); check_difference(&[], &[1, 2, 3, 9], &[]); check_difference(&[1, 3, 5, 9, 11], &[3, 9], &[1, 5, 11]); + check_difference(&[1, 3, 5, 9, 11], &[3, 6, 9], &[1, 5, 11]); + check_difference(&[1, 3, 5, 9, 11], &[0, 1], &[3, 5, 9, 11]); + check_difference(&[1, 3, 5, 9, 11], &[11, 12], &[1, 3, 5, 9]); check_difference(&[-5, 11, 22, 33, 40, 42], &[-12, -5, 14, 23, 34, 38, 39, 50], &[11, 22, 33, 40, 42]); @@ -119,18 +129,82 @@ fn test_difference() { return; } - let large = (0..1000).collect::>(); + let large = (0..100).collect::>(); check_difference(&[], &large, &[]); check_difference(&[-1], &large, &[-1]); check_difference(&[0], &large, &[]); - check_difference(&[999], &large, &[]); - check_difference(&[1000], &large, &[1000]); - check_difference(&[11, 5000, 1, 3, 77, 8924, 103], + check_difference(&[99], &large, &[]); + check_difference(&[100], &large, &[100]); + check_difference(&[11, 5000, 1, 3, 77, 8924], &large, &[5000, 8924]); check_difference(&large, &[], &large); check_difference(&large, &[-1], &large); - check_difference(&large, &[1000], &large); + check_difference(&large, &[100], &large); +} + +#[test] +fn test_difference_size_hint() { + let s246: BTreeSet = [2, 4, 6].iter().copied().collect(); + let s23456: BTreeSet = (2..=6).collect(); + let mut iter = s246.difference(&s23456); + assert_eq!(iter.size_hint(), (0, Some(3))); + assert_eq!(iter.next(), None); + + let s12345: BTreeSet = (1..=5).collect(); + iter = s246.difference(&s12345); + assert_eq!(iter.size_hint(), (0, Some(3))); + assert_eq!(iter.next(), Some(&6)); + assert_eq!(iter.size_hint(), (0, Some(0))); + assert_eq!(iter.next(), None); + + let s34567: BTreeSet = (3..=7).collect(); + iter = s246.difference(&s34567); + assert_eq!(iter.size_hint(), (0, Some(3))); + assert_eq!(iter.next(), Some(&2)); + assert_eq!(iter.size_hint(), (0, Some(2))); + assert_eq!(iter.next(), None); + + let s1: BTreeSet = (-9..=1).collect(); + iter = s246.difference(&s1); + assert_eq!(iter.size_hint(), (3, Some(3))); + + let s2: BTreeSet = (-9..=2).collect(); + iter = s246.difference(&s2); + assert_eq!(iter.size_hint(), (2, Some(2))); + assert_eq!(iter.next(), Some(&4)); + assert_eq!(iter.size_hint(), (1, Some(1))); + + let s23: BTreeSet = (2..=3).collect(); + iter = s246.difference(&s23); + assert_eq!(iter.size_hint(), (1, Some(3))); + assert_eq!(iter.next(), Some(&4)); + assert_eq!(iter.size_hint(), (1, Some(1))); + + let s4: BTreeSet = (4..=4).collect(); + iter = s246.difference(&s4); + assert_eq!(iter.size_hint(), (2, Some(3))); + assert_eq!(iter.next(), Some(&2)); + assert_eq!(iter.size_hint(), (1, Some(2))); + assert_eq!(iter.next(), Some(&6)); + assert_eq!(iter.size_hint(), (0, Some(0))); + assert_eq!(iter.next(), None); + + let s56: BTreeSet = (5..=6).collect(); + iter = s246.difference(&s56); + assert_eq!(iter.size_hint(), (1, Some(3))); + assert_eq!(iter.next(), Some(&2)); + assert_eq!(iter.size_hint(), (0, Some(2))); + + let s6: BTreeSet = (6..=19).collect(); + iter = s246.difference(&s6); + assert_eq!(iter.size_hint(), (2, Some(2))); + assert_eq!(iter.next(), Some(&2)); + assert_eq!(iter.size_hint(), (1, Some(1))); + + let s7: BTreeSet = (7..=19).collect(); + iter = s246.difference(&s7); + assert_eq!(iter.size_hint(), (3, Some(3))); } #[test] @@ -188,23 +262,23 @@ fn test_is_subset() { assert_eq!(is_subset(&[1, 2], &[1, 2]), true); assert_eq!(is_subset(&[1, 2], &[2, 3]), false); assert_eq!(is_subset(&[-5, 11, 22, 33, 40, 42], - &[-12, -5, 14, 23, 11, 34, 22, 38, 33, 42, 39, 40]), + &[-12, -5, 11, 14, 22, 23, 33, 34, 38, 39, 40, 42]), true); assert_eq!(is_subset(&[-5, 11, 22, 33, 40, 42], - &[-12, -5, 14, 23, 34, 38, 22, 11]), + &[-12, -5, 11, 14, 22, 23, 34, 38]), false); if cfg!(miri) { // Miri is too slow return; } - let large = (0..1000).collect::>(); + let large = (0..100).collect::>(); assert_eq!(is_subset(&[], &large), true); assert_eq!(is_subset(&large, &[]), false); assert_eq!(is_subset(&[-1], &large), false); assert_eq!(is_subset(&[0], &large), true); assert_eq!(is_subset(&[1, 2], &large), true); - assert_eq!(is_subset(&[999, 1000], &large), false); + assert_eq!(is_subset(&[99, 100], &large), false); } #[test]