From f3d7645fb79d641de447d4af02d5f3cee91b4af3 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Tue, 28 Jul 2020 18:42:13 +0200 Subject: [PATCH 01/32] Add trailing comma support to matches macro --- library/core/src/macros/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 3b9057b7e837..c92ca22509af 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -255,7 +255,7 @@ macro_rules! debug_assert_ne { #[macro_export] #[stable(feature = "matches_macro", since = "1.42.0")] macro_rules! matches { - ($expression:expr, $( $pattern:pat )|+ $( if $guard: expr )?) => { + ($expression:expr, $( $pattern:pat )|+ $( if $guard: expr )? $(,)?) => { match $expression { $( $pattern )|+ $( if $guard )? => true, _ => false From cc3b2f9e1da2bb1bf2eda2e265687ed028cb0e22 Mon Sep 17 00:00:00 2001 From: Hanif Bin Ariffin Date: Sat, 29 Aug 2020 19:01:41 -0400 Subject: [PATCH 02/32] Add more examples to lexicographic cmp on Iterators. The most important rule of lexicographical comparison is that two arrays of equal length will be compared until the first difference occured. The examples provided only focuses on the second rule that says that the shorter array will be filled with some T2 that is less than every T. Which is only possible because of the first rule. --- library/core/src/iter/traits/iterator.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 81d8f27ec19b..e16d15952b77 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -3077,6 +3077,7 @@ pub trait Iterator { /// assert_eq!([1].iter().lt([1].iter()), false); /// assert_eq!([1].iter().lt([1, 2].iter()), true); /// assert_eq!([1, 2].iter().lt([1].iter()), false); + /// assert_eq!([1, 2].iter().lt([1, 2].iter()), false); /// ``` #[stable(feature = "iter_order", since = "1.5.0")] fn lt(self, other: I) -> bool @@ -3097,6 +3098,7 @@ pub trait Iterator { /// assert_eq!([1].iter().le([1].iter()), true); /// assert_eq!([1].iter().le([1, 2].iter()), true); /// assert_eq!([1, 2].iter().le([1].iter()), false); + /// assert_eq!([1, 2].iter().le([1, 2].iter()), true); /// ``` #[stable(feature = "iter_order", since = "1.5.0")] fn le(self, other: I) -> bool @@ -3117,6 +3119,7 @@ pub trait Iterator { /// assert_eq!([1].iter().gt([1].iter()), false); /// assert_eq!([1].iter().gt([1, 2].iter()), false); /// assert_eq!([1, 2].iter().gt([1].iter()), true); + /// assert_eq!([1, 2].iter().gt([1, 2].iter()), false); /// ``` #[stable(feature = "iter_order", since = "1.5.0")] fn gt(self, other: I) -> bool @@ -3137,6 +3140,7 @@ pub trait Iterator { /// assert_eq!([1].iter().ge([1].iter()), true); /// assert_eq!([1].iter().ge([1, 2].iter()), false); /// assert_eq!([1, 2].iter().ge([1].iter()), true); + /// assert_eq!([1, 2].iter().ge([1, 2].iter()), true); /// ``` #[stable(feature = "iter_order", since = "1.5.0")] fn ge(self, other: I) -> bool From 4aae7814075ffe94486e2cc04ff5d08351eb8fd3 Mon Sep 17 00:00:00 2001 From: Camelid <37223377+camelid@users.noreply.github.com> Date: Sat, 29 Aug 2020 19:53:06 -0700 Subject: [PATCH 03/32] Add info about `!` and `impl Trait` --- library/std/src/primitive_docs.rs | 37 +++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 2339ca527bd8..d88a9cbd0acf 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -194,14 +194,47 @@ mod prim_bool {} /// # `!` and traits /// /// When writing your own traits, `!` should have an `impl` whenever there is an obvious `impl` -/// which doesn't `panic!`. As it turns out, most traits can have an `impl` for `!`. Take [`Debug`] +/// which doesn't `panic!`. The reason is that functions returning an `impl Trait` cannot have +/// divergence, i.e., returning `!`, as their only possible code path. As an example, this code +/// doesn't compile: +/// +/// ```compile_fail +/// use core::ops::Add; +/// +/// fn foo() -> impl Add { +/// unimplemented!() +/// } +/// ``` +/// +/// While this code does: +/// +/// ``` +/// use core::ops::Add; +/// +/// fn foo() -> impl Add { +/// if true { +/// unimplemented!() +/// } else { +/// 0 +/// } +/// } +/// ``` +/// +/// The reason is that, in the first example, there are many possible types for `!` to coerce +/// to, because the function's return value is polymorphic. However, in the second example, the +/// other branch returns `0` which has a concrete type that `!` can be coerced to. See issue +/// [#36375] for more information on this quirk of `!`. +/// +/// [#36375]: https://github.com/rust-lang/rust/issues/36375 +/// +/// As it turns out, though, most traits can have an `impl` for `!`. Take [`Debug`] /// for example: /// /// ``` /// #![feature(never_type)] /// # use std::fmt; /// # trait Debug { -/// # fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result; +/// # fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result; /// # } /// impl Debug for ! { /// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { From fd985e29dd97f053f31a2e282fb59363f6b6db3f Mon Sep 17 00:00:00 2001 From: Camelid <37223377+camelid@users.noreply.github.com> Date: Sat, 29 Aug 2020 20:35:58 -0700 Subject: [PATCH 04/32] cannot have divergence -> cannot diverge --- library/std/src/primitive_docs.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index d88a9cbd0acf..a577a0a51c99 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -194,9 +194,9 @@ mod prim_bool {} /// # `!` and traits /// /// When writing your own traits, `!` should have an `impl` whenever there is an obvious `impl` -/// which doesn't `panic!`. The reason is that functions returning an `impl Trait` cannot have -/// divergence, i.e., returning `!`, as their only possible code path. As an example, this code -/// doesn't compile: +/// which doesn't `panic!`. The reason is that functions returning an `impl Trait` cannot diverge, +/// i.e., returning `!`, as their only possible code path. As an example, this code doesn't +/// compile: /// /// ```compile_fail /// use core::ops::Add; From 0d9a2abe698e84c8b3c473659db321606d7d5c02 Mon Sep 17 00:00:00 2001 From: Camelid <37223377+camelid@users.noreply.github.com> Date: Sat, 29 Aug 2020 20:41:36 -0700 Subject: [PATCH 05/32] It's only an issue without an `impl Trait for !` --- library/std/src/primitive_docs.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index a577a0a51c99..df64287bc7de 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -194,9 +194,9 @@ mod prim_bool {} /// # `!` and traits /// /// When writing your own traits, `!` should have an `impl` whenever there is an obvious `impl` -/// which doesn't `panic!`. The reason is that functions returning an `impl Trait` cannot diverge, -/// i.e., returning `!`, as their only possible code path. As an example, this code doesn't -/// compile: +/// which doesn't `panic!`. The reason is that functions returning an `impl Trait` where `!` +/// does not have an `impl` of `Trait` cannot diverge as their only possible code path. In other +/// words, they can't return `!` from every code path. As an example, this code doesn't compile: /// /// ```compile_fail /// use core::ops::Add; @@ -206,7 +206,7 @@ mod prim_bool {} /// } /// ``` /// -/// While this code does: +/// But this code does: /// /// ``` /// use core::ops::Add; From 26eab6a0d51b9a023471210e35fdec969c662363 Mon Sep 17 00:00:00 2001 From: Camelid <37223377+camelid@users.noreply.github.com> Date: Sat, 29 Aug 2020 20:48:53 -0700 Subject: [PATCH 06/32] Specify `0` of type `u32` --- library/std/src/primitive_docs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index df64287bc7de..710d91b6ee7d 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -222,8 +222,8 @@ mod prim_bool {} /// /// The reason is that, in the first example, there are many possible types for `!` to coerce /// to, because the function's return value is polymorphic. However, in the second example, the -/// other branch returns `0` which has a concrete type that `!` can be coerced to. See issue -/// [#36375] for more information on this quirk of `!`. +/// other branch returns a `0` of type `u32`, which is a concrete type that `!` can be coerced to. +/// See issue [#36375] for more information on this quirk of `!`. /// /// [#36375]: https://github.com/rust-lang/rust/issues/36375 /// From 80dcad9e5b060ba6f9e06499c799423037ce7733 Mon Sep 17 00:00:00 2001 From: Camelid <37223377+camelid@users.noreply.github.com> Date: Sat, 29 Aug 2020 20:52:09 -0700 Subject: [PATCH 07/32] Be more specific about polymorphic return types I no longer say "polymorphic" since it's a bit ambiguous here. --- library/std/src/primitive_docs.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 710d91b6ee7d..fc5036a18935 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -220,10 +220,10 @@ mod prim_bool {} /// } /// ``` /// -/// The reason is that, in the first example, there are many possible types for `!` to coerce -/// to, because the function's return value is polymorphic. However, in the second example, the -/// other branch returns a `0` of type `u32`, which is a concrete type that `!` can be coerced to. -/// See issue [#36375] for more information on this quirk of `!`. +/// The reason is that, in the first example, there are many possible types that `!` could coerce +/// to, because the function can return one of many concrete types. However, in the second example, +/// the other branch returns a `0` of type `u32`, which is a concrete type that `!` can be coerced +/// to. See issue [#36375] for more information on this quirk of `!`. /// /// [#36375]: https://github.com/rust-lang/rust/issues/36375 /// From bd3196282ba61ba284f4e176db3537f61b11892c Mon Sep 17 00:00:00 2001 From: Camelid <37223377+camelid@users.noreply.github.com> Date: Sat, 29 Aug 2020 20:53:40 -0700 Subject: [PATCH 08/32] other branch -> `else` branch --- library/std/src/primitive_docs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index fc5036a18935..dfc026fb84f6 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -222,7 +222,7 @@ mod prim_bool {} /// /// The reason is that, in the first example, there are many possible types that `!` could coerce /// to, because the function can return one of many concrete types. However, in the second example, -/// the other branch returns a `0` of type `u32`, which is a concrete type that `!` can be coerced +/// the `else` branch returns a `0` of type `u32`, which is a concrete type that `!` can be coerced /// to. See issue [#36375] for more information on this quirk of `!`. /// /// [#36375]: https://github.com/rust-lang/rust/issues/36375 From 7e2548fe69ff5ec4e5e06c8c28351cbf2ebf7eee Mon Sep 17 00:00:00 2001 From: Camelid <37223377+camelid@users.noreply.github.com> Date: Sun, 30 Aug 2020 11:39:45 -0700 Subject: [PATCH 09/32] Import `Debug` instead of redefining it --- library/std/src/primitive_docs.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index dfc026fb84f6..0a0aa6785ed1 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -232,10 +232,7 @@ mod prim_bool {} /// /// ``` /// #![feature(never_type)] -/// # use std::fmt; -/// # trait Debug { -/// # fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result; -/// # } +/// # use std::fmt::{self, Debug}; /// impl Debug for ! { /// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { /// *self From 37ea97cc10212711411e6dbb6b260e668b7ac2b5 Mon Sep 17 00:00:00 2001 From: Camelid <37223377+camelid@users.noreply.github.com> Date: Sun, 30 Aug 2020 11:43:16 -0700 Subject: [PATCH 10/32] Explain why the `0` is a `u32` --- library/std/src/primitive_docs.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 0a0aa6785ed1..79621d46f0e6 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -222,8 +222,9 @@ mod prim_bool {} /// /// The reason is that, in the first example, there are many possible types that `!` could coerce /// to, because the function can return one of many concrete types. However, in the second example, -/// the `else` branch returns a `0` of type `u32`, which is a concrete type that `!` can be coerced -/// to. See issue [#36375] for more information on this quirk of `!`. +/// the `else` branch returns a `0`, which the compiler infers from the return type to be of type +/// `u32`, which is a concrete type that `!` can be coerced to. See issue [#36375] for more +/// information on this quirk of `!`. /// /// [#36375]: https://github.com/rust-lang/rust/issues/36375 /// From 090b16717a3bfbc2a35b51032f3849f372c67fad Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 30 Aug 2020 18:38:32 -0400 Subject: [PATCH 11/32] Factor out StmtKind::MacCall fields into `MacCallStmt` struct In PR #76130, I add a fourth field, which makes using a tuple variant somewhat unwieldy. --- compiler/rustc_ast/src/ast.rs | 19 +++++++++++++++---- compiler/rustc_ast/src/attr/mod.rs | 9 ++------- compiler/rustc_ast/src/mut_visit.rs | 2 +- compiler/rustc_ast/src/visit.rs | 2 +- compiler/rustc_ast_pretty/src/pprust.rs | 7 +++---- compiler/rustc_expand/src/expand.rs | 4 ++-- compiler/rustc_expand/src/placeholders.rs | 8 ++++++-- compiler/rustc_parse/src/parser/stmt.rs | 4 ++-- 8 files changed, 32 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 127a53cad2b3..49aa1fc17357 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -922,9 +922,13 @@ impl Stmt { pub fn add_trailing_semicolon(mut self) -> Self { self.kind = match self.kind { StmtKind::Expr(expr) => StmtKind::Semi(expr), - StmtKind::MacCall(mac) => StmtKind::MacCall( - mac.map(|(mac, _style, attrs)| (mac, MacStmtStyle::Semicolon, attrs)), - ), + StmtKind::MacCall(mac) => { + StmtKind::MacCall(mac.map(|MacCallStmt { mac, style: _, attrs }| MacCallStmt { + mac, + style: MacStmtStyle::Semicolon, + attrs, + })) + } kind => kind, }; self @@ -958,7 +962,14 @@ pub enum StmtKind { /// Just a trailing semi-colon. Empty, /// Macro. - MacCall(P<(MacCall, MacStmtStyle, AttrVec)>), + MacCall(P), +} + +#[derive(Clone, Encodable, Decodable, Debug)] +pub struct MacCallStmt { + pub mac: MacCall, + pub style: MacStmtStyle, + pub attrs: AttrVec, } #[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug)] diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index edcbce3e2cfd..12d6f7cc33dd 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -16,7 +16,6 @@ use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; use std::iter; -use std::ops::DerefMut; pub struct MarkedAttrs(GrowableBitSet); @@ -634,10 +633,7 @@ impl HasAttrs for StmtKind { StmtKind::Local(ref local) => local.attrs(), StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => expr.attrs(), StmtKind::Empty | StmtKind::Item(..) => &[], - StmtKind::MacCall(ref mac) => { - let (_, _, ref attrs) = **mac; - attrs.attrs() - } + StmtKind::MacCall(ref mac) => mac.attrs.attrs(), } } @@ -647,8 +643,7 @@ impl HasAttrs for StmtKind { StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.visit_attrs(f), StmtKind::Empty | StmtKind::Item(..) => {} StmtKind::MacCall(mac) => { - let (_mac, _style, attrs) = mac.deref_mut(); - attrs.visit_attrs(f); + mac.attrs.visit_attrs(f); } } } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 965571aaa548..3ef83ef3fc97 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1305,7 +1305,7 @@ pub fn noop_flat_map_stmt_kind( StmtKind::Semi(expr) => vis.filter_map_expr(expr).into_iter().map(StmtKind::Semi).collect(), StmtKind::Empty => smallvec![StmtKind::Empty], StmtKind::MacCall(mut mac) => { - let (mac_, _semi, attrs) = mac.deref_mut(); + let MacCallStmt { mac: mac_, style: _, attrs } = mac.deref_mut(); vis.visit_mac(mac_); visit_thin_attrs(attrs, vis); smallvec![StmtKind::MacCall(mac)] diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index b65a88cb90e8..234ce280f97c 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -692,7 +692,7 @@ pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) { StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => visitor.visit_expr(expr), StmtKind::Empty => {} StmtKind::MacCall(ref mac) => { - let (ref mac, _, ref attrs) = **mac; + let MacCallStmt { ref mac, style: _, ref attrs } = **mac; visitor.visit_mac(mac); for attr in attrs.iter() { visitor.visit_attribute(attr); diff --git a/compiler/rustc_ast_pretty/src/pprust.rs b/compiler/rustc_ast_pretty/src/pprust.rs index cb48deb58863..53b6d536a4a4 100644 --- a/compiler/rustc_ast_pretty/src/pprust.rs +++ b/compiler/rustc_ast_pretty/src/pprust.rs @@ -1507,11 +1507,10 @@ impl<'a> State<'a> { self.s.word(";"); } ast::StmtKind::MacCall(ref mac) => { - let (ref mac, style, ref attrs) = **mac; self.space_if_not_bol(); - self.print_outer_attributes(attrs); - self.print_mac(mac); - if style == ast::MacStmtStyle::Semicolon { + self.print_outer_attributes(&mac.attrs); + self.print_mac(&mac.mac); + if mac.style == ast::MacStmtStyle::Semicolon { self.s.word(";"); } } diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 7a21caf255a3..8db16c169b09 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -13,7 +13,7 @@ use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{self, AssocCtxt, Visitor}; use rustc_ast::{self as ast, AttrItem, Block, LitKind, NodeId, PatKind, Path}; -use rustc_ast::{ItemKind, MacArgs, MacStmtStyle, StmtKind}; +use rustc_ast::{ItemKind, MacArgs, MacCallStmt, MacStmtStyle, StmtKind}; use rustc_ast_pretty::pprust; use rustc_attr::{self as attr, is_builtin_attr, HasAttrs}; use rustc_data_structures::map_in_place::MapInPlace; @@ -1363,7 +1363,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { } if let StmtKind::MacCall(mac) = stmt.kind { - let (mac, style, attrs) = mac.into_inner(); + let MacCallStmt { mac, style, attrs } = mac.into_inner(); self.check_attributes(&attrs); let mut placeholder = self.collect_bang(mac, stmt.span, AstFragmentKind::Stmts).make_stmts(); diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index 29fb4c95ec69..dbd2e70af6a7 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -92,7 +92,11 @@ pub fn placeholder( AstFragment::Ty(P(ast::Ty { id, span, kind: ast::TyKind::MacCall(mac_placeholder()) })) } AstFragmentKind::Stmts => AstFragment::Stmts(smallvec![{ - let mac = P((mac_placeholder(), ast::MacStmtStyle::Braces, ast::AttrVec::new())); + let mac = P(ast::MacCallStmt { + mac: mac_placeholder(), + style: ast::MacStmtStyle::Braces, + attrs: ast::AttrVec::new(), + }); ast::Stmt { id, span, kind: ast::StmtKind::MacCall(mac) } }]), AstFragmentKind::Arms => AstFragment::Arms(smallvec![ast::Arm { @@ -293,7 +297,7 @@ impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> { fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> { let (style, mut stmts) = match stmt.kind { - ast::StmtKind::MacCall(mac) => (mac.1, self.remove(stmt.id).make_stmts()), + ast::StmtKind::MacCall(mac) => (mac.style, self.remove(stmt.id).make_stmts()), _ => return noop_flat_map_stmt(stmt, self), }; diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index ac067cb0eab8..341590c622cf 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -10,7 +10,7 @@ use rustc_ast as ast; use rustc_ast::ptr::P; use rustc_ast::token::{self, TokenKind}; use rustc_ast::util::classify; -use rustc_ast::{AttrStyle, AttrVec, Attribute, MacCall, MacStmtStyle}; +use rustc_ast::{AttrStyle, AttrVec, Attribute, MacCall, MacCallStmt, MacStmtStyle}; use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, Local, Stmt, StmtKind, DUMMY_NODE_ID}; use rustc_errors::{Applicability, PResult}; use rustc_span::source_map::{BytePos, Span}; @@ -106,7 +106,7 @@ impl<'a> Parser<'a> { let kind = if delim == token::Brace || self.token == token::Semi || self.token == token::Eof { - StmtKind::MacCall(P((mac, style, attrs))) + StmtKind::MacCall(P(MacCallStmt { mac, style, attrs })) } else { // Since none of the above applied, this is an expression statement macro. let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac), AttrVec::new()); From ee1902157ec737626376e94ef2e6887ed5ac8329 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 30 Aug 2020 19:17:17 -0400 Subject: [PATCH 12/32] Fix clippy --- src/tools/clippy/clippy_lints/src/utils/ast_utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs b/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs index 7b419431c0f5..3c3f8b26e3ac 100644 --- a/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs +++ b/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs @@ -191,7 +191,7 @@ pub fn eq_stmt(l: &Stmt, r: &Stmt) -> bool { (Item(l), Item(r)) => eq_item(l, r, eq_item_kind), (Expr(l), Expr(r)) | (Semi(l), Semi(r)) => eq_expr(l, r), (Empty, Empty) => true, - (MacCall(l), MacCall(r)) => l.1 == r.1 && eq_mac_call(&l.0, &r.0) && over(&l.2, &r.2, |l, r| eq_attr(l, r)), + (MacCall(l), MacCall(r)) => l.style == r.style && eq_mac_call(&l.mac, &r.mac) && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r)), _ => false, } } From 23f0ccfe5d9999a54dfcc4f5ba953981ba092aa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Thu, 30 Jul 2020 22:10:48 +0200 Subject: [PATCH 13/32] Stabilise link-self-contained option --- compiler/rustc_codegen_ssa/src/back/link.rs | 6 +++--- compiler/rustc_interface/src/tests.rs | 1 + compiler/rustc_session/src/options.rs | 6 +++--- src/doc/rustc/src/codegen-options/index.md | 20 ++++++++++++++++---- 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index bfcf979d1254..8e272282f40f 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1084,7 +1084,7 @@ fn get_crt_libs_path(sess: &Session) -> Option { fn get_object_file_path(sess: &Session, name: &str, self_contained: bool) -> PathBuf { // prefer system {,dll}crt2.o libs, see get_crt_libs_path comment for more details - if sess.opts.debugging_opts.link_self_contained.is_none() + if sess.opts.cg.link_self_contained.is_none() && sess.target.target.llvm_target.contains("windows-gnu") { if let Some(compiler_libs_path) = get_crt_libs_path(sess) { @@ -1289,7 +1289,7 @@ fn link_output_kind(sess: &Session, crate_type: CrateType) -> LinkOutputKind { /// Whether we link to our own CRT objects instead of relying on gcc to pull them. /// We only provide such support for a very limited number of targets. fn crt_objects_fallback(sess: &Session, crate_type: CrateType) -> bool { - if let Some(self_contained) = sess.opts.debugging_opts.link_self_contained { + if let Some(self_contained) = sess.opts.cg.link_self_contained { return self_contained; } @@ -1499,7 +1499,7 @@ fn link_local_crate_native_libs_and_dependent_crate_libs<'a, B: ArchiveBuilder<' /// Add sysroot and other globally set directories to the directory search list. fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session, self_contained: bool) { // Prefer system mingw-w64 libs, see get_crt_libs_path comment for more details. - if sess.opts.debugging_opts.link_self_contained.is_none() + if sess.opts.cg.link_self_contained.is_none() && cfg!(windows) && sess.target.target.llvm_target.contains("windows-gnu") { diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index cb906b3d9116..ada8dc90494b 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -402,6 +402,7 @@ fn test_codegen_options_tracking_hash() { // `link_arg` is omitted because it just forwards to `link_args`. untracked!(link_args, vec![String::from("abc"), String::from("def")]); untracked!(link_dead_code, Some(true)); + untracked!(link_self_contained, Some(true)); untracked!(linker, Some(PathBuf::from("linker"))); untracked!(linker_flavor, Some(LinkerFlavor::Gcc)); untracked!(no_stack_check, true); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 82330d9a5331..25d988e87fdd 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -719,6 +719,9 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options, "extra arguments to append to the linker invocation (space separated)"), link_dead_code: Option = (None, parse_opt_bool, [UNTRACKED], "keep dead code at link time (useful for code coverage) (default: no)"), + link_self_contained: Option = (None, parse_opt_bool, [UNTRACKED], + "control whether to link Rust provided C objects/libraries or rely + on C toolchain installed in the system"), linker: Option = (None, parse_opt_pathbuf, [UNTRACKED], "system linker to link outputs with"), linker_flavor: Option = (None, parse_linker_flavor, [UNTRACKED], @@ -894,9 +897,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "keep hygiene data after analysis (default: no)"), link_native_libraries: bool = (true, parse_bool, [UNTRACKED], "link native libraries in the linker invocation (default: yes)"), - link_self_contained: Option = (None, parse_opt_bool, [TRACKED], - "control whether to link Rust provided C objects/libraries or rely - on C toolchain installed in the system"), link_only: bool = (false, parse_bool, [TRACKED], "link the `.rlink` file generated by `-Z no-link` (default: no)"), llvm_time_trace: bool = (false, parse_bool, [UNTRACKED], diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index 7b0280d5b78a..bed10ca16d32 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -44,13 +44,13 @@ incremental builds the default is 256 which allows caching to be more granular. ## control-flow-guard -This flag controls whether LLVM enables the Windows [Control Flow -Guard](https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard) -platform security feature. This flag is currently ignored for non-Windows targets. +This flag controls whether LLVM enables the Windows [Control Flow +Guard](https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard) +platform security feature. This flag is currently ignored for non-Windows targets. It takes one of the following values: * `y`, `yes`, `on`, `checks`, or no value: enable Control Flow Guard. -* `nochecks`: emit Control Flow Guard metadata without runtime enforcement checks (this +* `nochecks`: emit Control Flow Guard metadata without runtime enforcement checks (this should only be used for testing purposes as it does not provide security enforcement). * `n`, `no`, `off`: do not enable Control Flow Guard (the default). @@ -200,6 +200,18 @@ the following values: An example of when this flag might be useful is when trying to construct code coverage metrics. +## link-self-contained + +On targets that support it this flag controls whether the linker will use libraries and objects +shipped with Rust instead or those in the system. +It takes one of the following values: + +* no value: rustc will use heuristic to disable self-contained mode if system has necessary tools. +* `y`, `yes`, `on`: use only libraries/objects shipped with Rust. +* `n`, `no`, or `off`: rely on the user or the linker to provide non-Rust libraries/objects. + +This allows overriding cases when detection fails or user wants to use shipped libraries. + ## linker This flag controls which linker `rustc` invokes to link your code. It takes a From e13a70122d380579840cec13d151870495f776ac Mon Sep 17 00:00:00 2001 From: Camelid Date: Mon, 31 Aug 2020 16:32:56 -0700 Subject: [PATCH 14/32] Redefine `Debug` instead of importing it This reverts commit 7e2548fe69ff5ec4e5e06c8c28351cbf2ebf7eee. Now I know why it was redefined: it seems like it's potentially because of the orphan rule. Here are the error messages: error[E0119]: conflicting implementations of trait `std::fmt::Debug` for type `!`: --> src/primitive_docs.rs:236:1 | 6 | impl Debug for ! { | ^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `core`: - impl std::fmt::Debug for !; error[E0117]: only traits defined in the current crate can be implemented for arbitrary types --> src/primitive_docs.rs:236:1 | 6 | impl Debug for ! { | ^^^^^^^^^^^^^^^- | | | | | `!` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead --- library/std/src/primitive_docs.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 79621d46f0e6..4525d8a543a6 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -233,7 +233,10 @@ mod prim_bool {} /// /// ``` /// #![feature(never_type)] -/// # use std::fmt::{self, Debug}; +/// # use std::fmt; +/// # trait Debug { +/// # fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result; +/// # } /// impl Debug for ! { /// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { /// *self From cdd6f110125971a0d7ab1457c0ea7eb30304d5f3 Mon Sep 17 00:00:00 2001 From: Camelid Date: Mon, 31 Aug 2020 16:35:00 -0700 Subject: [PATCH 15/32] Remove empty comment --- library/std/src/primitive_docs.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 4525d8a543a6..cba39c3eb141 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -1,7 +1,6 @@ #[doc(primitive = "bool")] #[doc(alias = "true")] #[doc(alias = "false")] -// /// The boolean type. /// /// The `bool` represents a value, which could only be either `true` or `false`. If you cast From c4c058c7167c44eacbc2f7734619c26d68eb1426 Mon Sep 17 00:00:00 2001 From: Camelid <37223377+camelid@users.noreply.github.com> Date: Mon, 31 Aug 2020 19:30:03 -0700 Subject: [PATCH 16/32] Improve wording Co-authored-by: Joshua Nelson --- library/std/src/primitive_docs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index cba39c3eb141..2ca86a42bffa 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -220,9 +220,9 @@ mod prim_bool {} /// ``` /// /// The reason is that, in the first example, there are many possible types that `!` could coerce -/// to, because the function can return one of many concrete types. However, in the second example, +/// to, because many types implement `Add`. However, in the second example, /// the `else` branch returns a `0`, which the compiler infers from the return type to be of type -/// `u32`, which is a concrete type that `!` can be coerced to. See issue [#36375] for more +/// `u32`. Since `u32` is a concrete type, `!` can and will be coerced to it. See issue [#36375] for more /// information on this quirk of `!`. /// /// [#36375]: https://github.com/rust-lang/rust/issues/36375 From 913354b8463a82497ebe586cfb9f5a4a218767ad Mon Sep 17 00:00:00 2001 From: Camelid <37223377+camelid@users.noreply.github.com> Date: Mon, 31 Aug 2020 19:41:27 -0700 Subject: [PATCH 17/32] Improve `assert!` section in `bool` docs --- library/std/src/primitive_docs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 2ca86a42bffa..682ca3068ee2 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -11,8 +11,8 @@ /// `bool` implements various traits, such as [`BitAnd`], [`BitOr`], [`Not`], etc., /// which allow us to perform boolean operations using `&`, `|` and `!`. /// -/// `if` always demands a `bool` value. [`assert!`], being an important macro in testing, -/// checks whether an expression returns `true`. +/// `if` always demands a `bool` value. [`assert!`], which is an important macro in testing, +/// checks whether an expression returns `true` and panics if it isn't. /// /// ``` /// let bool_val = true & false | false; From 55637f566993e2f8659aa09288bfc00b9965c524 Mon Sep 17 00:00:00 2001 From: Camelid <37223377+camelid@users.noreply.github.com> Date: Mon, 31 Aug 2020 19:44:21 -0700 Subject: [PATCH 18/32] Break line at 100 characters --- library/std/src/primitive_docs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 682ca3068ee2..d00824cfb3e9 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -222,8 +222,8 @@ mod prim_bool {} /// The reason is that, in the first example, there are many possible types that `!` could coerce /// to, because many types implement `Add`. However, in the second example, /// the `else` branch returns a `0`, which the compiler infers from the return type to be of type -/// `u32`. Since `u32` is a concrete type, `!` can and will be coerced to it. See issue [#36375] for more -/// information on this quirk of `!`. +/// `u32`. Since `u32` is a concrete type, `!` can and will be coerced to it. See issue [#36375] +/// for more information on this quirk of `!`. /// /// [#36375]: https://github.com/rust-lang/rust/issues/36375 /// From 6b5869a0ae3488ee19c2c4cb30cd589f68a3d2a8 Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Sat, 29 Aug 2020 10:55:46 -0700 Subject: [PATCH 19/32] Add new `-Z dump-mir-spanview` option Similar to `-Z dump-mir-graphviz`, this adds the option to write HTML+CSS files that allow users to analyze the spans associated with MIR elements (by individual statement, just terminator, or overall basic block). This PR was split out from PR #76004, and exposes an API for spanview HTML+CSS files that is also used to analyze code regions chosen for coverage instrumentation (in a follow-on PR). Rust compiler MCP rust-lang/compiler-team#278 Relevant issue: #34701 - Implement support for LLVMs code coverage instrumentation --- compiler/rustc_mir/src/util/mod.rs | 1 + compiler/rustc_mir/src/util/pretty.rs | 11 + compiler/rustc_mir/src/util/spanview.rs | 461 ++++++++++++++++++ compiler/rustc_session/src/config.rs | 15 + compiler/rustc_session/src/options.rs | 36 ++ src/test/mir-opt/spanview-block.rs | 5 + src/test/mir-opt/spanview-statement.rs | 5 + src/test/mir-opt/spanview-terminator.rs | 5 + .../spanview_block.main.mir_map.0.html | 67 +++ .../spanview_statement.main.mir_map.0.html | 67 +++ .../spanview_terminator.main.mir_map.0.html | 66 +++ 11 files changed, 739 insertions(+) create mode 100644 compiler/rustc_mir/src/util/spanview.rs create mode 100644 src/test/mir-opt/spanview-block.rs create mode 100644 src/test/mir-opt/spanview-statement.rs create mode 100644 src/test/mir-opt/spanview-terminator.rs create mode 100644 src/test/mir-opt/spanview_block.main.mir_map.0.html create mode 100644 src/test/mir-opt/spanview_statement.main.mir_map.0.html create mode 100644 src/test/mir-opt/spanview_terminator.main.mir_map.0.html diff --git a/compiler/rustc_mir/src/util/mod.rs b/compiler/rustc_mir/src/util/mod.rs index 8bbe207c077e..ed0fafb1aac1 100644 --- a/compiler/rustc_mir/src/util/mod.rs +++ b/compiler/rustc_mir/src/util/mod.rs @@ -9,6 +9,7 @@ mod alignment; pub mod collect_writes; mod graphviz; pub(crate) mod pretty; +pub(crate) mod spanview; pub use self::aggregate::expand_aggregate; pub use self::alignment::is_disaligned; diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs index 2a9cbc7fc0e3..db57766620e8 100644 --- a/compiler/rustc_mir/src/util/pretty.rs +++ b/compiler/rustc_mir/src/util/pretty.rs @@ -6,6 +6,7 @@ use std::io::{self, Write}; use std::path::{Path, PathBuf}; use super::graphviz::write_mir_fn_graphviz; +use super::spanview::write_mir_fn_spanview; use crate::transform::MirSource; use either::Either; use rustc_data_structures::fx::FxHashMap; @@ -147,6 +148,16 @@ fn dump_matched_mir_node<'tcx, F>( write_mir_fn_graphviz(tcx, source.def_id(), body, false, &mut file)?; }; } + + if let Some(spanview) = tcx.sess.opts.debugging_opts.dump_mir_spanview { + let _: io::Result<()> = try { + let mut file = + create_dump_file(tcx, "html", pass_num, pass_name, disambiguator, source)?; + if source.def_id().is_local() { + write_mir_fn_spanview(tcx, source.def_id(), body, spanview, &mut file)?; + } + }; + } } /// Returns the path to the filename where we should dump a given MIR. diff --git a/compiler/rustc_mir/src/util/spanview.rs b/compiler/rustc_mir/src/util/spanview.rs new file mode 100644 index 000000000000..b2f2b5fc1e6f --- /dev/null +++ b/compiler/rustc_mir/src/util/spanview.rs @@ -0,0 +1,461 @@ +use rustc_hir::def_id::DefId; +use rustc_middle::hir; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; +use rustc_session::config::MirSpanview; +use rustc_span::{BytePos, Pos, Span}; + +use std::io::{self, Write}; +use std::iter::Peekable; + +pub const TOOLTIP_INDENT: &str = " "; + +const NEW_LINE_SPAN: &str = "\n"; +const HEADER: &str = r#" + + + coverage_of_if_else - Code Regions + + +"#; + +const FOOTER: &str = r#" + +"#; + +/// Metadata to highlight the span of a MIR BasicBlock, Statement, or Terminator. +pub struct SpanViewable { + pub span: Span, + pub title: String, + pub tooltip: String, +} + +/// Write a spanview HTML+CSS file to analyze MIR element spans. +pub fn write_mir_fn_spanview<'tcx, W>( + tcx: TyCtxt<'tcx>, + def_id: DefId, + body: &Body<'tcx>, + spanview: MirSpanview, + w: &mut W, +) -> io::Result<()> +where + W: Write, +{ + let body_span = hir_body(tcx, def_id).value.span; + let mut span_viewables = Vec::new(); + for (bb, data) in body.basic_blocks().iter_enumerated() { + match spanview { + MirSpanview::Statement => { + for (i, statement) in data.statements.iter().enumerate() { + if let Some(span_viewable) = + statement_span_viewable(tcx, body_span, bb, i, statement) + { + span_viewables.push(span_viewable); + } + } + if let Some(span_viewable) = terminator_span_viewable(tcx, body_span, bb, data) { + span_viewables.push(span_viewable); + } + } + MirSpanview::Terminator => { + if let Some(span_viewable) = terminator_span_viewable(tcx, body_span, bb, data) { + span_viewables.push(span_viewable); + } + } + MirSpanview::Block => { + if let Some(span_viewable) = block_span_viewable(tcx, body_span, bb, data) { + span_viewables.push(span_viewable); + } + } + } + } + write_spanview_document(tcx, def_id, span_viewables, w)?; + Ok(()) +} + +/// Generate a spanview HTML+CSS document for the given local function `def_id`, and a pre-generated +/// list `SpanViewable`s. +pub fn write_spanview_document<'tcx, W>( + tcx: TyCtxt<'tcx>, + def_id: DefId, + mut span_viewables: Vec, + w: &mut W, +) -> io::Result<()> +where + W: Write, +{ + let fn_span = fn_span(tcx, def_id); + writeln!(w, "{}", HEADER)?; + let mut next_pos = fn_span.lo(); + let end_pos = fn_span.hi(); + let source_map = tcx.sess.source_map(); + let start = source_map.lookup_char_pos(next_pos); + write!( + w, + r#"
{}"#, + start.line - 1, + " ".repeat(start.col.to_usize()) + )?; + span_viewables.sort_unstable_by(|a, b| { + let a = a.span; + let b = b.span; + if a.lo() == b.lo() { + // Sort hi() in reverse order so shorter spans are attempted after longer spans. + // This should give shorter spans a higher "layer", so they are not covered by + // the longer spans. + b.hi().partial_cmp(&a.hi()) + } else { + a.lo().partial_cmp(&b.lo()) + } + .unwrap() + }); + let mut ordered_span_viewables = span_viewables.iter().peekable(); + let mut alt = false; + while ordered_span_viewables.peek().is_some() { + next_pos = write_span_viewables(tcx, next_pos, &mut ordered_span_viewables, false, 1, w)?; + alt = !alt; + } + if next_pos < end_pos { + write_coverage_gap(tcx, next_pos, end_pos, w)?; + } + write!(w, r#"
"#)?; + writeln!(w, "{}", FOOTER)?; + Ok(()) +} + +/// Format a string showing the start line and column, and end line and column within a file. +pub fn source_range_no_file<'tcx>(tcx: TyCtxt<'tcx>, span: &Span) -> String { + let source_map = tcx.sess.source_map(); + let start = source_map.lookup_char_pos(span.lo()); + let end = source_map.lookup_char_pos(span.hi()); + format!("{}:{}-{}:{}", start.line, start.col.to_usize() + 1, end.line, end.col.to_usize() + 1) +} + +pub fn statement_kind_name(statement: &Statement<'_>) -> &'static str { + use StatementKind::*; + match statement.kind { + Assign(..) => "Assign", + FakeRead(..) => "FakeRead", + SetDiscriminant { .. } => "SetDiscriminant", + StorageLive(..) => "StorageLive", + StorageDead(..) => "StorageDead", + LlvmInlineAsm(..) => "LlvmInlineAsm", + Retag(..) => "Retag", + AscribeUserType(..) => "AscribeUserType", + Coverage(..) => "Coverage", + Nop => "Nop", + } +} + +pub fn terminator_kind_name(term: &Terminator<'_>) -> &'static str { + use TerminatorKind::*; + match term.kind { + Goto { .. } => "Goto", + SwitchInt { .. } => "SwitchInt", + Resume => "Resume", + Abort => "Abort", + Return => "Return", + Unreachable => "Unreachable", + Drop { .. } => "Drop", + DropAndReplace { .. } => "DropAndReplace", + Call { .. } => "Call", + Assert { .. } => "Assert", + Yield { .. } => "Yield", + GeneratorDrop => "GeneratorDrop", + FalseEdge { .. } => "FalseEdge", + FalseUnwind { .. } => "FalseUnwind", + InlineAsm { .. } => "InlineAsm", + } +} + +fn statement_span_viewable<'tcx>( + tcx: TyCtxt<'tcx>, + body_span: Span, + bb: BasicBlock, + i: usize, + statement: &Statement<'tcx>, +) -> Option { + let span = statement.source_info.span; + if !body_span.contains(span) { + return None; + } + let title = format!("bb{}[{}]", bb.index(), i); + let tooltip = tooltip(tcx, &title, span, vec![statement.clone()], &None); + Some(SpanViewable { span, title, tooltip }) +} + +fn terminator_span_viewable<'tcx>( + tcx: TyCtxt<'tcx>, + body_span: Span, + bb: BasicBlock, + data: &BasicBlockData<'tcx>, +) -> Option { + let term = data.terminator(); + let span = term.source_info.span; + if !body_span.contains(span) { + return None; + } + let title = format!("bb{}`{}`", bb.index(), terminator_kind_name(term)); + let tooltip = tooltip(tcx, &title, span, vec![], &data.terminator); + Some(SpanViewable { span, title, tooltip }) +} + +fn block_span_viewable<'tcx>( + tcx: TyCtxt<'tcx>, + body_span: Span, + bb: BasicBlock, + data: &BasicBlockData<'tcx>, +) -> Option { + let span = compute_block_span(data, body_span); + if !body_span.contains(span) { + return None; + } + let title = format!("bb{}", bb.index()); + let tooltip = tooltip(tcx, &title, span, data.statements.clone(), &data.terminator); + Some(SpanViewable { span, title, tooltip }) +} + +fn compute_block_span<'tcx>(data: &BasicBlockData<'tcx>, body_span: Span) -> Span { + let mut span = data.terminator().source_info.span; + for statement_span in data.statements.iter().map(|statement| statement.source_info.span) { + // Only combine Spans from the function's body_span. + if body_span.contains(statement_span) { + span = span.to(statement_span); + } + } + span +} + +/// Recursively process each ordered span. Spans that overlap will have progressively varying +/// styles, such as increased padding for each overlap. Non-overlapping adjacent spans will +/// have alternating style choices, to help distinguish between them if, visually adjacent. +/// The `layer` is incremented for each overlap, and the `alt` bool alternates between true +/// and false, for each adjacent non-overlapping span. Source code between the spans (code +/// that is not in any coverage region) has neutral styling. +fn write_span_viewables<'tcx, 'b, W>( + tcx: TyCtxt<'tcx>, + next_pos: BytePos, + ordered_span_viewables: &mut Peekable>, + alt: bool, + layer: usize, + w: &mut W, +) -> io::Result +where + W: Write, +{ + let span_viewable = + ordered_span_viewables.next().expect("ordered_span_viewables should have some"); + if next_pos < span_viewable.span.lo() { + write_coverage_gap(tcx, next_pos, span_viewable.span.lo(), w)?; + } + let mut remaining_span = span_viewable.span; + let mut subalt = false; + loop { + let next_span_viewable = match ordered_span_viewables.peek() { + None => break, + Some(span_viewable) => *span_viewable, + }; + if !next_span_viewable.span.overlaps(remaining_span) { + break; + } + write_span( + tcx, + remaining_span.until(next_span_viewable.span), + Some(span_viewable), + alt, + layer, + w, + )?; + let next_pos = write_span_viewables( + tcx, + next_span_viewable.span.lo(), + ordered_span_viewables, + subalt, + layer + 1, + w, + )?; + subalt = !subalt; + if next_pos < remaining_span.hi() { + remaining_span = remaining_span.with_lo(next_pos); + } else { + return Ok(next_pos); + } + } + write_span(tcx, remaining_span, Some(span_viewable), alt, layer, w) +} + +fn write_coverage_gap<'tcx, W>( + tcx: TyCtxt<'tcx>, + lo: BytePos, + hi: BytePos, + w: &mut W, +) -> io::Result +where + W: Write, +{ + write_span(tcx, Span::with_root_ctxt(lo, hi), None, false, 0, w) +} + +fn write_span<'tcx, W>( + tcx: TyCtxt<'tcx>, + span: Span, + span_viewable: Option<&SpanViewable>, + alt: bool, + layer: usize, + w: &mut W, +) -> io::Result +where + W: Write, +{ + let source_map = tcx.sess.source_map(); + let snippet = source_map + .span_to_snippet(span) + .unwrap_or_else(|err| bug!("span_to_snippet error for span {:?}: {:?}", span, err)); + let labeled_snippet = if let Some(SpanViewable { title, .. }) = span_viewable { + if span.is_empty() { + format!(r#"@{}"#, title) + } else { + format!(r#"@{}: {}"#, title, escape_html(&snippet)) + } + } else { + snippet + }; + let maybe_alt = if layer > 0 { + if alt { " odd" } else { " even" } + } else { + "" + }; + let maybe_tooltip = if let Some(SpanViewable { tooltip, .. }) = span_viewable { + format!(" title=\"{}\"", escape_attr(tooltip)) + } else { + "".to_owned() + }; + if layer == 1 { + write!(w, "")?; + } + for (i, line) in labeled_snippet.lines().enumerate() { + if i > 0 { + write!(w, "{}", NEW_LINE_SPAN)?; + } + write!( + w, + r#"{}"#, + maybe_alt, layer, maybe_tooltip, line + )?; + } + if layer == 1 { + write!(w, "")?; + } + Ok(span.hi()) +} + +fn tooltip<'tcx>( + tcx: TyCtxt<'tcx>, + title: &str, + span: Span, + statements: Vec>, + terminator: &Option>, +) -> String { + let source_map = tcx.sess.source_map(); + let mut text = Vec::new(); + text.push(format!("{}: {}:", title, &source_map.span_to_string(span))); + for statement in statements { + let source_range = source_range_no_file(tcx, &statement.source_info.span); + text.push(format!( + "\n{}{}: {}: {}", + TOOLTIP_INDENT, + source_range, + statement_kind_name(&statement), + format!("{:?}", statement) + )); + } + if let Some(term) = terminator { + let source_range = source_range_no_file(tcx, &term.source_info.span); + text.push(format!( + "\n{}{}: {}: {:?}", + TOOLTIP_INDENT, + source_range, + terminator_kind_name(term), + term.kind + )); + } + text.join("") +} + +fn fn_span<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Span { + let hir_id = + tcx.hir().local_def_id_to_hir_id(def_id.as_local().expect("expected DefId is local")); + tcx.hir().span(hir_id) +} + +fn hir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx rustc_hir::Body<'tcx> { + let hir_node = tcx.hir().get_if_local(def_id).expect("expected DefId is local"); + let fn_body_id = hir::map::associated_body(hir_node).expect("HIR node is a function with body"); + tcx.hir().body(fn_body_id) +} + +fn escape_html(s: &str) -> String { + s.replace("&", "&").replace("<", "<").replace(">", ">") +} + +fn escape_attr(s: &str) -> String { + s.replace("&", "&") + .replace("\"", """) + .replace("'", "'") + .replace("<", "<") + .replace(">", ">") +} diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 0a2a535598a2..6861314a88f6 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -163,6 +163,21 @@ pub enum LtoCli { Unspecified, } +/// The different settings that the `-Z dump_mir_spanview` flag can have. `Statement` generates a +/// document highlighting each span of every statement (including terminators). `Terminator` and +/// `Block` highlight a single span per `BasicBlock`: the span of the block's `Terminator`, or a +/// computed span for the block, representing the entire range, covering the block's terminator and +/// all of its statements. +#[derive(Clone, Copy, PartialEq, Hash, Debug)] +pub enum MirSpanview { + /// Default `-Z dump_mir_spanview` or `-Z dump_mir_spanview=statement` + Statement, + /// `-Z dump_mir_spanview=terminator` + Terminator, + /// `-Z dump_mir_spanview=block` + Block, +} + #[derive(Clone, PartialEq, Hash)] pub enum LinkerPluginLto { LinkerPlugin(PathBuf), diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index ee30c16108a0..bcf65a1c4d2b 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -255,6 +255,7 @@ macro_rules! options { pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`"; pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavor::one_of(); pub const parse_optimization_fuel: &str = "crate=integer"; + pub const parse_mir_spanview: &str = "`statement` (default), `terminator`, or `block`"; pub const parse_unpretty: &str = "`string` or `string=string`"; pub const parse_treat_err_as_bug: &str = "either no value or a number bigger than 0"; pub const parse_lto: &str = @@ -551,6 +552,36 @@ macro_rules! options { } } + fn parse_mir_spanview(slot: &mut Option, v: Option<&str>) -> bool { + if v.is_some() { + let mut bool_arg = None; + if parse_opt_bool(&mut bool_arg, v) { + *slot = if bool_arg.unwrap() { + Some(MirSpanview::Statement) + } else { + None + }; + return true + } + } + + let v = match v { + None => { + *slot = Some(MirSpanview::Statement); + return true; + } + Some(v) => v, + }; + + *slot = Some(match v.trim_end_matches("s") { + "statement" | "stmt" => MirSpanview::Statement, + "terminator" | "term" => MirSpanview::Terminator, + "block" | "basicblock" => MirSpanview::Block, + _ => return false, + }); + true + } + fn parse_treat_err_as_bug(slot: &mut Option, v: Option<&str>) -> bool { match v { Some(s) => { *slot = s.parse().ok().filter(|&x| x != 0); slot.unwrap_or(0) != 0 } @@ -849,6 +880,11 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "exclude the pass number when dumping MIR (used in tests) (default: no)"), dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED], "in addition to `.mir` files, create graphviz `.dot` files (default: no)"), + dump_mir_spanview: Option = (None, parse_mir_spanview, [UNTRACKED], + "in addition to `.mir` files, create `.html` files to view spans for \ + all `statement`s (including terminators), only `terminator` spans, or \ + computed `block` spans (one span encompassing a block's terminator and \ + all statements)."), emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED], "emit a section containing stack size metadata (default: no)"), fewer_names: bool = (false, parse_bool, [TRACKED], diff --git a/src/test/mir-opt/spanview-block.rs b/src/test/mir-opt/spanview-block.rs new file mode 100644 index 000000000000..fc1d6e0ede66 --- /dev/null +++ b/src/test/mir-opt/spanview-block.rs @@ -0,0 +1,5 @@ +// Test spanview block output +// compile-flags: -Z dump-mir-spanview=block + +// EMIT_MIR spanview_block.main.mir_map.0.html +fn main() {} diff --git a/src/test/mir-opt/spanview-statement.rs b/src/test/mir-opt/spanview-statement.rs new file mode 100644 index 000000000000..a43ad5e71a39 --- /dev/null +++ b/src/test/mir-opt/spanview-statement.rs @@ -0,0 +1,5 @@ +// Test spanview output (the default value for `-Z dump-mir-spanview` is "statement") +// compile-flags: -Z dump-mir-spanview + +// EMIT_MIR spanview_statement.main.mir_map.0.html +fn main() {} diff --git a/src/test/mir-opt/spanview-terminator.rs b/src/test/mir-opt/spanview-terminator.rs new file mode 100644 index 000000000000..92e1411eadbd --- /dev/null +++ b/src/test/mir-opt/spanview-terminator.rs @@ -0,0 +1,5 @@ +// Test spanview terminator output +// compile-flags: -Z dump-mir-spanview=terminator + +// EMIT_MIR spanview_terminator.main.mir_map.0.html +fn main() {} diff --git a/src/test/mir-opt/spanview_block.main.mir_map.0.html b/src/test/mir-opt/spanview_block.main.mir_map.0.html new file mode 100644 index 000000000000..7c1b7bc3b84b --- /dev/null +++ b/src/test/mir-opt/spanview_block.main.mir_map.0.html @@ -0,0 +1,67 @@ + + + + coverage_of_if_else - Code Regions + + + +
fn main() @bb0: {}@bb2
+ + diff --git a/src/test/mir-opt/spanview_statement.main.mir_map.0.html b/src/test/mir-opt/spanview_statement.main.mir_map.0.html new file mode 100644 index 000000000000..f8662a3277a0 --- /dev/null +++ b/src/test/mir-opt/spanview_statement.main.mir_map.0.html @@ -0,0 +1,67 @@ + + + + coverage_of_if_else - Code Regions + + + +
fn main() @bb0[0]: {}@bb0`Goto`@bb2`Return`
+ + diff --git a/src/test/mir-opt/spanview_terminator.main.mir_map.0.html b/src/test/mir-opt/spanview_terminator.main.mir_map.0.html new file mode 100644 index 000000000000..d0a11a8d2629 --- /dev/null +++ b/src/test/mir-opt/spanview_terminator.main.mir_map.0.html @@ -0,0 +1,66 @@ + + + + coverage_of_if_else - Code Regions + + + +
fn main() {}@bb0`Goto`@bb2`Return`
+ + From be2947d0b7cc7fb13601c41676285bb3f6d548c3 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 31 Aug 2020 00:04:01 -0400 Subject: [PATCH 20/32] Give a better error message for duplicate built-in macros Previously, this would say no such macro existed, but this was misleading, since the macro _did_ exist, it was just already seen. - Say where the macro was previously defined - Add long-form error message --- compiler/rustc_error_codes/src/error_codes.rs | 1 + .../src/error_codes/E0773.md | 38 +++++++++++++++++++ compiler/rustc_resolve/src/lib.rs | 8 +++- compiler/rustc_resolve/src/macros.rs | 22 +++++++++-- src/test/ui/macros/duplicate-builtin.rs | 17 +++++++++ src/test/ui/macros/duplicate-builtin.stderr | 21 ++++++++++ src/test/ui/macros/unknown-builtin.rs | 4 +- src/test/ui/macros/unknown-builtin.stderr | 9 ++++- 8 files changed, 112 insertions(+), 8 deletions(-) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0773.md create mode 100644 src/test/ui/macros/duplicate-builtin.rs create mode 100644 src/test/ui/macros/duplicate-builtin.stderr diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 4e5e77f80c28..789a1fc35a64 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -454,6 +454,7 @@ E0768: include_str!("./error_codes/E0768.md"), E0769: include_str!("./error_codes/E0769.md"), E0770: include_str!("./error_codes/E0770.md"), E0771: include_str!("./error_codes/E0771.md"), +E0773: include_str!("./error_codes/E0773.md"), ; // E0006, // merged with E0005 // E0008, // cannot bind by-move into a pattern guard diff --git a/compiler/rustc_error_codes/src/error_codes/E0773.md b/compiler/rustc_error_codes/src/error_codes/E0773.md new file mode 100644 index 000000000000..b19a58bf33d2 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0773.md @@ -0,0 +1,38 @@ +A builtin-macro was defined more than once. + +Erroneous code example: + +```compile_fail,E0773 +#![feature(decl_macro)] +#![feature(rustc_attrs)] + +#[rustc_builtin_macro] +pub macro test($item:item) { + /* compiler built-in */ +} + +mod inner { + #[rustc_builtin_macro] + pub macro test($item:item) { + /* compiler built-in */ + } +} +``` + +To fix the issue, remove the duplicate declaration: + +``` +#![feature(decl_macro)] +#![feature(rustc_attrs)] + +#[rustc_builtin_macro] +pub macro test($item:item) { + /* compiler built-in */ +} +``` + +In very rare edge cases, this may happen when loading `core` or `std` twice, +once with `check` metadata and once with `build` metadata. +For more information, see [#75176]. + +[#75176]: https://github.com/rust-lang/rust/pull/75176#issuecomment-683234468 diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 5892edf7652b..50729086ec6a 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -867,6 +867,12 @@ pub struct ExternPreludeEntry<'a> { pub introduced_by_item: bool, } +/// Used for better errors for E0773 +enum BuiltinMacroState { + NotYetSeen(SyntaxExtension), + AlreadySeen(Span), +} + /// The main resolver class. /// /// This is the visitor that walks the whole crate. @@ -960,7 +966,7 @@ pub struct Resolver<'a> { crate_loader: CrateLoader<'a>, macro_names: FxHashSet, - builtin_macros: FxHashMap, + builtin_macros: FxHashMap, registered_attrs: FxHashSet, registered_tools: FxHashSet, macro_use_prelude: FxHashMap>, diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 51518d63ae90..bea713896476 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -3,7 +3,7 @@ use crate::imports::ImportResolver; use crate::Namespace::*; -use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy}; +use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BuiltinMacroState, Determinacy}; use crate::{CrateLint, ParentScope, ResolutionError, Resolver, Scope, ScopeSet, Weak}; use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding}; use rustc_ast::{self as ast, NodeId}; @@ -11,6 +11,7 @@ use rustc_ast_lowering::ResolverAstLowering; use rustc_ast_pretty::pprust; use rustc_attr::StabilityLevel; use rustc_data_structures::fx::FxHashSet; +use rustc_errors::struct_span_err; use rustc_expand::base::{Indeterminate, InvocationRes, ResolverExpand, SyntaxExtension}; use rustc_expand::compile_declarative_macro; use rustc_expand::expand::{AstFragment, AstFragmentKind, Invocation, InvocationKind}; @@ -166,7 +167,7 @@ impl<'a> ResolverExpand for Resolver<'a> { } fn register_builtin_macro(&mut self, ident: Ident, ext: SyntaxExtension) { - if self.builtin_macros.insert(ident.name, ext).is_some() { + if self.builtin_macros.insert(ident.name, BuiltinMacroState::NotYetSeen(ext)).is_some() { self.session .span_err(ident.span, &format!("built-in macro `{}` was already defined", ident)); } @@ -1076,10 +1077,23 @@ impl<'a> Resolver<'a> { if result.is_builtin { // The macro was marked with `#[rustc_builtin_macro]`. - if let Some(ext) = self.builtin_macros.remove(&item.ident.name) { + if let Some(builtin_macro) = self.builtin_macros.get_mut(&item.ident.name) { // The macro is a built-in, replace its expander function // while still taking everything else from the source code. - result.kind = ext.kind; + // If we already loaded this builtin macro, give a better error message than 'no such builtin macro'. + match mem::replace(builtin_macro, BuiltinMacroState::AlreadySeen(item.span)) { + BuiltinMacroState::NotYetSeen(ext) => result.kind = ext.kind, + BuiltinMacroState::AlreadySeen(span) => { + struct_span_err!( + self.session, + item.span, + E0773, + "attempted to define built-in macro more than once" + ) + .span_note(span, "previously defined here") + .emit(); + } + } } else { let msg = format!("cannot find a built-in macro with name `{}`", item.ident); self.session.span_err(item.span, &msg); diff --git a/src/test/ui/macros/duplicate-builtin.rs b/src/test/ui/macros/duplicate-builtin.rs new file mode 100644 index 000000000000..35f0f429059a --- /dev/null +++ b/src/test/ui/macros/duplicate-builtin.rs @@ -0,0 +1,17 @@ +// compile-flags:--crate-type lib +#![feature(decl_macro)] +#![feature(rustc_attrs)] + +#[rustc_builtin_macro] +pub macro test($item:item) { +//~^ NOTE previously defined + /* compiler built-in */ +} + +mod inner { + #[rustc_builtin_macro] + pub macro test($item:item) { + //~^ ERROR attempted to define built-in macro more than once [E0773] + /* compiler built-in */ + } +} diff --git a/src/test/ui/macros/duplicate-builtin.stderr b/src/test/ui/macros/duplicate-builtin.stderr new file mode 100644 index 000000000000..58accea27bb9 --- /dev/null +++ b/src/test/ui/macros/duplicate-builtin.stderr @@ -0,0 +1,21 @@ +error[E0773]: attempted to define built-in macro more than once + --> $DIR/duplicate-builtin.rs:13:5 + | +LL | / pub macro test($item:item) { +LL | | +LL | | /* compiler built-in */ +LL | | } + | |_____^ + | +note: previously defined here + --> $DIR/duplicate-builtin.rs:6:1 + | +LL | / pub macro test($item:item) { +LL | | +LL | | /* compiler built-in */ +LL | | } + | |_^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0773`. diff --git a/src/test/ui/macros/unknown-builtin.rs b/src/test/ui/macros/unknown-builtin.rs index a96b99ae4ff7..16f9139e6479 100644 --- a/src/test/ui/macros/unknown-builtin.rs +++ b/src/test/ui/macros/unknown-builtin.rs @@ -1,4 +1,4 @@ -// error-pattern: cannot find a built-in macro with name `line` +// error-pattern: attempted to define built-in macro more than once #![feature(rustc_attrs)] @@ -6,7 +6,7 @@ macro_rules! unknown { () => () } //~ ERROR cannot find a built-in macro with name `unknown` #[rustc_builtin_macro] -macro_rules! line { () => () } +macro_rules! line { () => () } //~ NOTE previously defined here fn main() { line!(); diff --git a/src/test/ui/macros/unknown-builtin.stderr b/src/test/ui/macros/unknown-builtin.stderr index 4b650b2c4752..7b04e05293ea 100644 --- a/src/test/ui/macros/unknown-builtin.stderr +++ b/src/test/ui/macros/unknown-builtin.stderr @@ -4,7 +4,7 @@ error: cannot find a built-in macro with name `unknown` LL | macro_rules! unknown { () => () } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: cannot find a built-in macro with name `line` +error[E0773]: attempted to define built-in macro more than once --> $SRC_DIR/core/src/macros/mod.rs:LL:COL | LL | / macro_rules! line { @@ -13,6 +13,13 @@ LL | | /* compiler built-in */ LL | | }; LL | | } | |_____^ + | +note: previously defined here + --> $DIR/unknown-builtin.rs:9:1 + | +LL | macro_rules! line { () => () } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0773`. From 9c7fb6c44750af069bf382404adaa7a6287f9007 Mon Sep 17 00:00:00 2001 From: Denis Vasilik Date: Tue, 1 Sep 2020 17:35:56 +0200 Subject: [PATCH 21/32] Use intra-doc links --- library/core/src/panic.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs index 316ecafe572c..263f97e70f39 100644 --- a/library/core/src/panic.rs +++ b/library/core/src/panic.rs @@ -92,8 +92,6 @@ impl<'a> PanicInfo<'a> { /// If the `panic!` macro from the `core` crate (not from `std`) /// was used with a formatting string and some additional arguments, /// returns that message ready to be used for example with [`fmt::write`] - /// - /// [`fmt::write`]: ../fmt/fn.write.html #[unstable(feature = "panic_info_message", issue = "66745")] pub fn message(&self) -> Option<&fmt::Arguments<'_>> { self.message @@ -105,8 +103,6 @@ impl<'a> PanicInfo<'a> { /// This method will currently always return [`Some`], but this may change /// in future versions. /// - /// [`Some`]: ../../std/option/enum.Option.html#variant.Some - /// /// # Examples /// /// ```should_panic @@ -153,10 +149,7 @@ impl fmt::Display for PanicInfo<'_> { /// A struct containing information about the location of a panic. /// -/// This structure is created by the [`location`] method of [`PanicInfo`]. -/// -/// [`location`]: ../../std/panic/struct.PanicInfo.html#method.location -/// [`PanicInfo`]: ../../std/panic/struct.PanicInfo.html +/// This structure is created by the [`PanicInfo::location`] method of [`PanicInfo`]. /// /// # Examples /// From b639cb1e462757aa191060e68da5e0de54e9c016 Mon Sep 17 00:00:00 2001 From: Denis Vasilik Date: Tue, 1 Sep 2020 18:16:34 +0200 Subject: [PATCH 22/32] Enhance wording Co-authored-by: Joshua Nelson --- library/core/src/panic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs index 263f97e70f39..25ee73c626ea 100644 --- a/library/core/src/panic.rs +++ b/library/core/src/panic.rs @@ -149,7 +149,7 @@ impl fmt::Display for PanicInfo<'_> { /// A struct containing information about the location of a panic. /// -/// This structure is created by the [`PanicInfo::location`] method of [`PanicInfo`]. +/// This structure is created by [`PanicInfo::location()`]. /// /// # Examples /// From b31cc8f83e7f50f54bffa93e909d51cdabf9f5fa Mon Sep 17 00:00:00 2001 From: CDirkx Date: Tue, 1 Sep 2020 19:00:20 +0200 Subject: [PATCH 23/32] Make all methods of `std::net::Ipv6Addr` const Make the following methods of `std::net::Ipv6Addr` unstable const under the `const_ipv6` feature: - `segments` - `is_unspecified` - `is_loopback` - `is_global` (unstable) - `is_unique_local` - `is_unicast_link_local_strict` - `is_documentation` - `multicast_scope` - `is_multicast` - `to_ipv4_mapped` - `to_ipv4` Changed the implementation of `is_unspecified` and `is_loopback` to use a `match` instead of `==`. Part of #76205 --- library/std/src/lib.rs | 1 + library/std/src/net/ip.rs | 46 +++++++++++++++++++++++++-------------- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 0797585e3df3..3141b3b9526d 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -238,6 +238,7 @@ #![feature(concat_idents)] #![feature(const_cstr_unchecked)] #![feature(const_fn_transmute)] +#![feature(const_ipv6)] #![feature(const_raw_ptr_deref)] #![feature(container_error_extra)] #![feature(core_intrinsics)] diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index 10676b49d437..8e3dbf8fcb48 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -1102,8 +1102,9 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).segments(), /// [0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff]); /// ``` + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] #[stable(feature = "rust1", since = "1.0.0")] - pub fn segments(&self) -> [u16; 8] { + pub const fn segments(&self) -> [u16; 8] { // All elements in `s6_addr` must be big endian. // SAFETY: `[u8; 16]` is always safe to transmute to `[u16; 8]`. let [a, b, c, d, e, f, g, h] = unsafe { transmute::<_, [u16; 8]>(self.inner.s6_addr) }; @@ -1135,9 +1136,10 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unspecified(), false); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).is_unspecified(), true); /// ``` + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] - pub fn is_unspecified(&self) -> bool { - self.segments() == [0, 0, 0, 0, 0, 0, 0, 0] + pub const fn is_unspecified(&self) -> bool { + matches!(self.segments(), [0, 0, 0, 0, 0, 0, 0, 0]) } /// Returns [`true`] if this is a loopback address (::1). @@ -1155,9 +1157,10 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_loopback(), false); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_loopback(), true); /// ``` + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] - pub fn is_loopback(&self) -> bool { - self.segments() == [0, 0, 0, 0, 0, 0, 0, 1] + pub const fn is_loopback(&self) -> bool { + matches!(self.segments(), [0, 0, 0, 0, 0, 0, 0, 1]) } /// Returns [`true`] if the address appears to be globally routable. @@ -1182,7 +1185,8 @@ impl Ipv6Addr { /// 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 { + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + pub const fn is_global(&self) -> bool { match self.multicast_scope() { Some(Ipv6MulticastScope::Global) => true, None => self.is_unicast_global(), @@ -1208,7 +1212,8 @@ impl Ipv6Addr { /// 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 { + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + pub const fn is_unique_local(&self) -> bool { (self.segments()[0] & 0xfe00) == 0xfc00 } @@ -1263,7 +1268,8 @@ impl Ipv6Addr { /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 /// [IETF RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6 /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406 - pub fn is_unicast_link_local_strict(&self) -> bool { + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + pub const fn is_unicast_link_local_strict(&self) -> bool { (self.segments()[0] & 0xffff) == 0xfe80 && (self.segments()[1] & 0xffff) == 0 && (self.segments()[2] & 0xffff) == 0 @@ -1320,7 +1326,8 @@ impl Ipv6Addr { /// /// [IETF RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4 /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406 - pub fn is_unicast_link_local(&self) -> bool { + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + pub const fn is_unicast_link_local(&self) -> bool { (self.segments()[0] & 0xffc0) == 0xfe80 } @@ -1359,7 +1366,8 @@ impl Ipv6Addr { /// addresses. /// /// [RFC 3879]: https://tools.ietf.org/html/rfc3879 - pub fn is_unicast_site_local(&self) -> bool { + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + pub const fn is_unicast_site_local(&self) -> bool { (self.segments()[0] & 0xffc0) == 0xfec0 } @@ -1381,7 +1389,8 @@ impl Ipv6Addr { /// 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 { + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + pub const fn is_documentation(&self) -> bool { (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) } @@ -1416,7 +1425,8 @@ impl Ipv6Addr { /// 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 { + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + pub const fn is_unicast_global(&self) -> bool { !self.is_multicast() && !self.is_loopback() && !self.is_unicast_link_local() @@ -1440,7 +1450,8 @@ impl Ipv6Addr { /// ); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).multicast_scope(), None); /// ``` - pub fn multicast_scope(&self) -> Option { + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + pub const fn multicast_scope(&self) -> Option { if self.is_multicast() { match self.segments()[0] & 0x000f { 1 => Some(Ipv6MulticastScope::InterfaceLocal), @@ -1472,8 +1483,9 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_multicast(), true); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_multicast(), false); /// ``` + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] - pub fn is_multicast(&self) -> bool { + pub const fn is_multicast(&self) -> bool { (self.segments()[0] & 0xff00) == 0xff00 } @@ -1498,7 +1510,8 @@ impl Ipv6Addr { /// Some(Ipv4Addr::new(192, 10, 2, 255))); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4_mapped(), None); /// ``` - pub fn to_ipv4_mapped(&self) -> Option { + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + pub const fn to_ipv4_mapped(&self) -> Option { match self.octets() { [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, a, b, c, d] => { Some(Ipv4Addr::new(a, b, c, d)) @@ -1525,8 +1538,9 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4(), /// Some(Ipv4Addr::new(0, 0, 0, 1))); /// ``` + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] #[stable(feature = "rust1", since = "1.0.0")] - pub fn to_ipv4(&self) -> Option { + pub const fn to_ipv4(&self) -> Option { if let [0, 0, 0, 0, 0, 0 | 0xffff, ab, cd] = self.segments() { let [a, b] = ab.to_be_bytes(); let [c, d] = cd.to_be_bytes(); From e7d074392e560517546725e7e3ba5b3fe8978ee8 Mon Sep 17 00:00:00 2001 From: Denis Vasilik Date: Tue, 1 Sep 2020 19:20:15 +0200 Subject: [PATCH 24/32] Use intra-doc links --- library/core/src/clone.rs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index 7784ec687ea9..a5d20045a9b0 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -7,11 +7,7 @@ //! contain owned boxes or implement [`Drop`]), so the compiler considers //! them cheap and safe to copy. For other types copies must be made //! explicitly, by convention implementing the [`Clone`] trait and calling -//! the [`clone`][clone] method. -//! -//! [`Clone`]: trait.Clone.html -//! [clone]: trait.Clone.html#tymethod.clone -//! [`Drop`]: ../../std/ops/trait.Drop.html +//! the [`Clone::clone`] method. //! //! Basic usage example: //! @@ -51,7 +47,7 @@ /// ## Derivable /// /// This trait can be used with `#[derive]` if all fields are `Clone`. The `derive`d -/// implementation of [`clone`] calls [`clone`] on each field. +/// implementation of [`Clone::clone`] calls [`Clone::clone`] on each field. /// /// For a generic struct, `#[derive]` implements `Clone` conditionally by adding bound `Clone` on /// generic parameters. @@ -74,9 +70,6 @@ /// An example is a generic struct holding a function pointer. In this case, the /// implementation of `Clone` cannot be `derive`d, but can be implemented as: /// -/// [`Copy`]: ../../std/marker/trait.Copy.html -/// [`clone`]: trait.Clone.html#tymethod.clone -/// /// ``` /// struct Generate(fn() -> T); /// From 3510c568874eb1274805b25cfa5cc54aa1819030 Mon Sep 17 00:00:00 2001 From: Denis Vasilik Date: Tue, 1 Sep 2020 19:56:32 +0200 Subject: [PATCH 25/32] Improve readability --- library/core/src/clone.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index a5d20045a9b0..a953a3a4182b 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -7,7 +7,9 @@ //! contain owned boxes or implement [`Drop`]), so the compiler considers //! them cheap and safe to copy. For other types copies must be made //! explicitly, by convention implementing the [`Clone`] trait and calling -//! the [`Clone::clone`] method. +//! the [`clone`] method. +//! +//! [`clone`]: Clone::clone //! //! Basic usage example: //! @@ -47,7 +49,9 @@ /// ## Derivable /// /// This trait can be used with `#[derive]` if all fields are `Clone`. The `derive`d -/// implementation of [`Clone::clone`] calls [`Clone::clone`] on each field. +/// implementation of [`Clone`] calls [`clone`] on each field. +/// +/// [`clone`]: Clone::clone /// /// For a generic struct, `#[derive]` implements `Clone` conditionally by adding bound `Clone` on /// generic parameters. From 7eb4b1b4b96642197b1bdeac4998d4d5f725f0cf Mon Sep 17 00:00:00 2001 From: Jes Bak Hansen Date: Tue, 1 Sep 2020 20:45:21 +0200 Subject: [PATCH 26/32] Document lint missing_doc_code_examples is nightly-only --- src/doc/rustdoc/src/lints.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md index d1d6bc1c1fe6..8e2869fef553 100644 --- a/src/doc/rustdoc/src/lints.md +++ b/src/doc/rustdoc/src/lints.md @@ -51,7 +51,7 @@ warning: missing documentation for a function ## missing_doc_code_examples -This lint is **allowed by default**. It detects when a documentation block +This lint is **allowed by default** and is **nightly-only**. It detects when a documentation block is missing a code example. For example: ```rust From cd08deff3c9c0de3ecd78883a3df4c9089b715d1 Mon Sep 17 00:00:00 2001 From: CDirkx Date: Tue, 1 Sep 2020 20:59:46 +0200 Subject: [PATCH 27/32] Add test for `Ipv6Addr` methods in a const context --- src/test/ui/consts/std/net/ipv6.rs | 53 ++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 src/test/ui/consts/std/net/ipv6.rs diff --git a/src/test/ui/consts/std/net/ipv6.rs b/src/test/ui/consts/std/net/ipv6.rs new file mode 100644 index 000000000000..d9ea1064be80 --- /dev/null +++ b/src/test/ui/consts/std/net/ipv6.rs @@ -0,0 +1,53 @@ +// run-pass + +#![feature(ip)] +#![feature(const_ipv6)] + +use std::net::{Ipv4Addr, Ipv6Addr, Ipv6MulticastScope}; + +fn main() { + const IP_ADDRESS : Ipv6Addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); + assert_eq!(IP_ADDRESS, Ipv6Addr::LOCALHOST); + + const SEGMENTS : [u16; 8] = IP_ADDRESS.segments(); + assert_eq!(SEGMENTS, [0 ,0 ,0 ,0 ,0 ,0 ,0, 1]); + + const OCTETS : [u8; 16] = IP_ADDRESS.octets(); + assert_eq!(OCTETS, [0 ,0 ,0 ,0 ,0 ,0 ,0, 0 ,0 ,0 ,0 ,0 ,0 ,0, 0, 1]); + + const IS_UNSPECIFIED : bool = IP_ADDRESS.is_unspecified(); + assert!(!IS_UNSPECIFIED); + + const IS_LOOPBACK : bool = IP_ADDRESS.is_loopback(); + assert!(IS_LOOPBACK); + + const IS_GLOBAL : bool = IP_ADDRESS.is_global(); + assert!(!IS_GLOBAL); + + const IS_UNIQUE_LOCAL : bool = IP_ADDRESS.is_unique_local(); + assert!(!IS_UNIQUE_LOCAL); + + const IS_UNICAST_LINK_LOCAL_STRICT : bool = IP_ADDRESS.is_unicast_link_local_strict(); + assert!(!IS_UNICAST_LINK_LOCAL_STRICT); + + const IS_UNICAST_LINK_LOCAL : bool = IP_ADDRESS.is_unicast_link_local(); + assert!(!IS_UNICAST_LINK_LOCAL); + + const IS_UNICAST_SITE_LOCAL : bool = IP_ADDRESS.is_unicast_site_local(); + assert!(!IS_UNICAST_SITE_LOCAL); + + const IS_DOCUMENTATION : bool = IP_ADDRESS.is_documentation(); + assert!(!IS_DOCUMENTATION); + + const IS_UNICAST_GLOBAL : bool = IP_ADDRESS.is_unicast_global(); + assert!(!IS_UNICAST_GLOBAL); + + const MULTICAST_SCOPE : Option = IP_ADDRESS.multicast_scope(); + assert_eq!(MULTICAST_SCOPE, None); + + const IS_MULTICAST : bool = IP_ADDRESS.is_multicast(); + assert!(!IS_MULTICAST); + + const IP_V4 : Option = IP_ADDRESS.to_ipv4(); + assert_eq!(IP_V4.unwrap(), Ipv4Addr::new(0, 0, 0, 1)); +} \ No newline at end of file From a43dd4f4014af0f70c032eb23c5cbf4c2829b7c8 Mon Sep 17 00:00:00 2001 From: CDirkx Date: Tue, 1 Sep 2020 21:05:26 +0200 Subject: [PATCH 28/32] Change implementation of `Ipv6Addr::is_unspecified` and `is_loopback` from `matches!` to `u128` comparison Done because `matches!` doesn't optimize well with array comparisons --- library/std/src/net/ip.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index 8e3dbf8fcb48..341a112df71b 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -1139,7 +1139,7 @@ impl Ipv6Addr { #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] pub const fn is_unspecified(&self) -> bool { - matches!(self.segments(), [0, 0, 0, 0, 0, 0, 0, 0]) + u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::UNSPECIFIED.octets()) } /// Returns [`true`] if this is a loopback address (::1). @@ -1160,7 +1160,7 @@ impl Ipv6Addr { #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] pub const fn is_loopback(&self) -> bool { - matches!(self.segments(), [0, 0, 0, 0, 0, 0, 0, 1]) + u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets()) } /// Returns [`true`] if the address appears to be globally routable. From 9afe97c932ee964ee35d196c902870ab572f2544 Mon Sep 17 00:00:00 2001 From: CDirkx Date: Tue, 1 Sep 2020 21:36:45 +0200 Subject: [PATCH 29/32] Add trailing newline to `ipv6.rs` --- src/test/ui/consts/std/net/ipv6.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/consts/std/net/ipv6.rs b/src/test/ui/consts/std/net/ipv6.rs index d9ea1064be80..e3841c38c223 100644 --- a/src/test/ui/consts/std/net/ipv6.rs +++ b/src/test/ui/consts/std/net/ipv6.rs @@ -50,4 +50,4 @@ fn main() { const IP_V4 : Option = IP_ADDRESS.to_ipv4(); assert_eq!(IP_V4.unwrap(), Ipv4Addr::new(0, 0, 0, 1)); -} \ No newline at end of file +} From c86d249e94ae45fff1c882c98d85aaf49133f0b6 Mon Sep 17 00:00:00 2001 From: Camelid Date: Sun, 30 Aug 2020 13:45:17 -0700 Subject: [PATCH 30/32] Use "Fira Sans" for crate list font Fira Sans is what's used for module lists and other item lists. Previously, the default body font, "Source Serif Pro", was used for crate lists, which didn't visually match other item lists. --- src/librustdoc/html/render/mod.rs | 5 +++-- src/librustdoc/html/static/themes/ayu.css | 3 +++ src/test/rustdoc/index-page.rs | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 470e9d5ae768..e4aba8963c76 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1062,12 +1062,13 @@ themePicker.onblur = handleThemeButtonsBlur; let content = format!( "

\ List of all crates\ -

    {}
", + \ +
    {}
", krates .iter() .map(|s| { format!( - "
  • {}
  • ", + "
  • {}
  • ", ensure_trailing_slash(s), s ) diff --git a/src/librustdoc/html/static/themes/ayu.css b/src/librustdoc/html/static/themes/ayu.css index f910bfffc22f..b4571018270a 100644 --- a/src/librustdoc/html/static/themes/ayu.css +++ b/src/librustdoc/html/static/themes/ayu.css @@ -178,6 +178,9 @@ pre { .content span.externcrate, .content span.mod, .content a.mod { color: #acccf9; } +.content ul.crate a.crate { + font: 16px/1.6 "Fira Sans"; +} .content span.struct, .content a.struct { color: #ffa0a5; } diff --git a/src/test/rustdoc/index-page.rs b/src/test/rustdoc/index-page.rs index f0476f083b8a..be668a1276a0 100644 --- a/src/test/rustdoc/index-page.rs +++ b/src/test/rustdoc/index-page.rs @@ -6,6 +6,6 @@ // @has foo/../index.html // @has - '//span[@class="in-band"]' 'List of all crates' -// @has - '//ul[@class="mod"]//a[@href="foo/index.html"]' 'foo' -// @has - '//ul[@class="mod"]//a[@href="all_item_types/index.html"]' 'all_item_types' +// @has - '//ul[@class="crate mod"]//a[@href="foo/index.html"]' 'foo' +// @has - '//ul[@class="crate mod"]//a[@href="all_item_types/index.html"]' 'all_item_types' pub struct Foo; From b1491eacfc2f2ff05ff2a1d3b557c30e15c5f81f Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 2 Sep 2020 00:22:47 +0300 Subject: [PATCH 31/32] lexer: Tiny improvement to shebang detection Lexer now discerns between regular comments and doc comments, so use that. The change only affects the choice of reported errors. --- compiler/rustc_lexer/src/lib.rs | 14 +++++++++----- src/test/ui/parser/shebang/shebang-doc-comment.rs | 5 +---- .../ui/parser/shebang/shebang-doc-comment.stderr | 8 ++++---- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index b7d6194cd77c..44999bbe8571 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -191,12 +191,16 @@ pub fn strip_shebang(input: &str) -> Option { // For simplicity we consider any line starting with `#!` a shebang, // regardless of restrictions put on shebangs by specific platforms. if let Some(input_tail) = input.strip_prefix("#!") { - // Ok, this is a shebang but if the next non-whitespace token is `[` or maybe - // a doc comment (due to `TokenKind::(Line,Block)Comment` ambiguity at lexer level), + // Ok, this is a shebang but if the next non-whitespace token is `[`, // then it may be valid Rust code, so consider it Rust code. - let next_non_whitespace_token = tokenize(input_tail).map(|tok| tok.kind).find(|tok| - !matches!(tok, TokenKind::Whitespace | TokenKind::LineComment { .. } | TokenKind::BlockComment { .. }) - ); + let next_non_whitespace_token = tokenize(input_tail).map(|tok| tok.kind).find(|tok| { + !matches!( + tok, + TokenKind::Whitespace + | TokenKind::LineComment { doc_style: None } + | TokenKind::BlockComment { doc_style: None, .. } + ) + }); if next_non_whitespace_token != Some(TokenKind::OpenBracket) { // No other choice than to consider this a shebang. return Some(2 + input_tail.lines().next().unwrap_or_default().len()); diff --git a/src/test/ui/parser/shebang/shebang-doc-comment.rs b/src/test/ui/parser/shebang/shebang-doc-comment.rs index 7dbb9eebc757..72866753e0e6 100644 --- a/src/test/ui/parser/shebang/shebang-doc-comment.rs +++ b/src/test/ui/parser/shebang/shebang-doc-comment.rs @@ -1,6 +1,3 @@ #!///bin/bash [allow(unused_variables)] -//~^^ ERROR expected `[`, found doc comment - -// Doc comment is misinterpreted as a whitespace (regular comment) during shebang detection. -// Even if it wasn't, it would still result in an error, just a different one. +//~^ ERROR expected item, found `[` diff --git a/src/test/ui/parser/shebang/shebang-doc-comment.stderr b/src/test/ui/parser/shebang/shebang-doc-comment.stderr index f524f556837f..2227d45ec5a3 100644 --- a/src/test/ui/parser/shebang/shebang-doc-comment.stderr +++ b/src/test/ui/parser/shebang/shebang-doc-comment.stderr @@ -1,8 +1,8 @@ -error: expected `[`, found doc comment `///bin/bash` - --> $DIR/shebang-doc-comment.rs:1:3 +error: expected item, found `[` + --> $DIR/shebang-doc-comment.rs:2:1 | -LL | #!///bin/bash - | ^^^^^^^^^^^ expected `[` +LL | [allow(unused_variables)] + | ^ expected item error: aborting due to previous error From e5c17bff3514cf951ffb304ddd1d5fe1887cca65 Mon Sep 17 00:00:00 2001 From: Camelid Date: Tue, 1 Sep 2020 15:48:39 -0700 Subject: [PATCH 32/32] Clean up header in `iter` docs for `for` loops --- library/core/src/iter/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index 28b22f80e2c1..1be9c4de9168 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -135,7 +135,7 @@ //! methods like `nth` and `fold` if an iterator can compute them more efficiently without calling //! `next`. //! -//! # for Loops and IntoIterator +//! # `for` loops and `IntoIterator` //! //! Rust's `for` loop syntax is actually sugar for iterators. Here's a basic //! example of `for`: