From 734bfdeaf290a64f4170f79770dfac7151951942 Mon Sep 17 00:00:00 2001 From: Smitty Date: Thu, 8 Jul 2021 14:13:42 -0400 Subject: [PATCH 01/30] Disallow octal zeros in IPv4 addresses --- library/std/src/net/ip/tests.rs | 8 ++++++++ library/std/src/net/parser.rs | 26 +++++++++++++++++--------- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/library/std/src/net/ip/tests.rs b/library/std/src/net/ip/tests.rs index 2109980ad058d..5ff0bd697b142 100644 --- a/library/std/src/net/ip/tests.rs +++ b/library/std/src/net/ip/tests.rs @@ -20,6 +20,14 @@ fn test_from_str_ipv4() { // no number between dots let none: Option = "255.0..1".parse().ok(); assert_eq!(None, none); + // octal + let none: Option = "255.0.0.01".parse().ok(); + assert_eq!(None, none); + // octal zero + let none: Option = "255.0.0.00".parse().ok(); + assert_eq!(None, none); + let none: Option = "255.0.00.0".parse().ok(); + assert_eq!(None, none); } #[test] diff --git a/library/std/src/net/parser.rs b/library/std/src/net/parser.rs index 88a8cb76befbf..d43d40400abad 100644 --- a/library/std/src/net/parser.rs +++ b/library/std/src/net/parser.rs @@ -12,7 +12,7 @@ use crate::fmt; use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; use crate::str::FromStr; -trait ReadNumberHelper: crate::marker::Sized { +trait ReadNumberHelper: crate::marker::Sized + crate::cmp::PartialEq { const ZERO: Self; fn checked_mul(&self, other: u32) -> Option; fn checked_add(&self, other: u32) -> Option; @@ -111,10 +111,12 @@ impl<'a> Parser<'a> { &mut self, radix: u32, max_digits: Option, + allow_zero_prefix: bool, ) -> Option { self.read_atomically(move |p| { let mut result = T::ZERO; let mut digit_count = 0; + let has_leading_zero = p.peek_char() == Some('0'); while let Some(digit) = p.read_atomically(|p| p.read_char()?.to_digit(radix)) { result = result.checked_mul(radix)?; @@ -127,7 +129,16 @@ impl<'a> Parser<'a> { } } - if digit_count == 0 { None } else { Some(result) } + if digit_count == 0 { + None + } else if !allow_zero_prefix + && has_leading_zero + && (result != T::ZERO || result == T::ZERO && digit_count > 1) + { + None + } else { + Some(result) + } }) } @@ -140,10 +151,7 @@ impl<'a> Parser<'a> { *slot = p.read_separator('.', i, |p| { // Disallow octal number in IP string. // https://tools.ietf.org/html/rfc6943#section-3.1.1 - match (p.peek_char(), p.read_number(10, None)) { - (Some('0'), Some(number)) if number != 0 => None, - (_, number) => number, - } + p.read_number(10, None, false) })?; } @@ -175,7 +183,7 @@ impl<'a> Parser<'a> { } } - let group = p.read_separator(':', i, |p| p.read_number(16, Some(4))); + let group = p.read_separator(':', i, |p| p.read_number(16, Some(4), true)); match group { Some(g) => *slot = g, @@ -227,7 +235,7 @@ impl<'a> Parser<'a> { fn read_port(&mut self) -> Option { self.read_atomically(|p| { p.read_given_char(':')?; - p.read_number(10, None) + p.read_number(10, None, true) }) } @@ -235,7 +243,7 @@ impl<'a> Parser<'a> { fn read_scope_id(&mut self) -> Option { self.read_atomically(|p| { p.read_given_char('%')?; - p.read_number(10, None) + p.read_number(10, None, true) }) } From 69de693af96790a2414a6d37148b524fde457f53 Mon Sep 17 00:00:00 2001 From: Smitty Date: Fri, 9 Jul 2021 12:35:49 -0400 Subject: [PATCH 02/30] Clarify docs on what IPv4 octal addresses are The way octal literals are written in IP addresses differs from the way they are written in Rust code, so the way that octal/hex literals in IPs are written is explictly mentioned. --- library/std/src/net/ip.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index 4b6d60d121e13..7d0c84e17704d 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -59,7 +59,8 @@ pub enum IpAddr { /// /// `Ipv4Addr` provides a [`FromStr`] implementation. The four octets are in decimal /// notation, divided by `.` (this is called "dot-decimal notation"). -/// Notably, octal numbers and hexadecimal numbers are not allowed per [IETF RFC 6943]. +/// Notably, octal numbers (which are indicated with a leading `0`) and hexadecimal numbers (which +/// are indicated with a leading `0x`) are not allowed per [IETF RFC 6943]. /// /// [IETF RFC 6943]: https://tools.ietf.org/html/rfc6943#section-3.1.1 /// [`FromStr`]: crate::str::FromStr @@ -72,6 +73,8 @@ pub enum IpAddr { /// let localhost = Ipv4Addr::new(127, 0, 0, 1); /// assert_eq!("127.0.0.1".parse(), Ok(localhost)); /// assert_eq!(localhost.is_loopback(), true); +/// assert!("012.004.002.000".parse::().is_err()); // all octets are in octal +/// assert!("0xcb.0x0.0x71.0x00".parse::().is_err()); // all octets are in hex /// ``` #[derive(Copy)] #[stable(feature = "rust1", since = "1.0.0")] From b9b97bbb9d3503381de4b1beb5fcbf69e8e4c68d Mon Sep 17 00:00:00 2001 From: Smitty Date: Fri, 9 Jul 2021 12:54:02 -0400 Subject: [PATCH 03/30] Reject too-long IPs quicker Now that there can't be a bunch of leading zeros, parsing can be optimized a bit. --- library/std/src/net/parser.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/library/std/src/net/parser.rs b/library/std/src/net/parser.rs index d43d40400abad..df6bbdeab8994 100644 --- a/library/std/src/net/parser.rs +++ b/library/std/src/net/parser.rs @@ -289,7 +289,12 @@ impl FromStr for IpAddr { impl FromStr for Ipv4Addr { type Err = AddrParseError; fn from_str(s: &str) -> Result { - Parser::new(s).parse_with(|p| p.read_ipv4_addr()) + // don't try to parse if too long + if s.len() > 15 { + Err(AddrParseError(())) + } else { + Parser::new(s).parse_with(|p| p.read_ipv4_addr()) + } } } From a331e5fd2c925134b8a457ded7c34f9558bb8e26 Mon Sep 17 00:00:00 2001 From: Smitty Date: Sun, 11 Jul 2021 11:33:39 -0400 Subject: [PATCH 04/30] Simplify leading zero checks --- library/std/src/net/parser.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/library/std/src/net/parser.rs b/library/std/src/net/parser.rs index df6bbdeab8994..e233d605ce55a 100644 --- a/library/std/src/net/parser.rs +++ b/library/std/src/net/parser.rs @@ -12,7 +12,7 @@ use crate::fmt; use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; use crate::str::FromStr; -trait ReadNumberHelper: crate::marker::Sized + crate::cmp::PartialEq { +trait ReadNumberHelper: crate::marker::Sized { const ZERO: Self; fn checked_mul(&self, other: u32) -> Option; fn checked_add(&self, other: u32) -> Option; @@ -131,10 +131,7 @@ impl<'a> Parser<'a> { if digit_count == 0 { None - } else if !allow_zero_prefix - && has_leading_zero - && (result != T::ZERO || result == T::ZERO && digit_count > 1) - { + } else if !allow_zero_prefix && has_leading_zero && digit_count > 1 { None } else { Some(result) From ace518de9a28559ff8e062b67c6a4b55287ca1a9 Mon Sep 17 00:00:00 2001 From: Smitty Date: Sun, 11 Jul 2021 11:37:23 -0400 Subject: [PATCH 05/30] Add example with a bunch of leading zeos --- library/std/src/net/ip.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index 7d0c84e17704d..af1f72f0ae23b 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -74,6 +74,7 @@ pub enum IpAddr { /// assert_eq!("127.0.0.1".parse(), Ok(localhost)); /// assert_eq!(localhost.is_loopback(), true); /// assert!("012.004.002.000".parse::().is_err()); // all octets are in octal +/// assert!("0000000.0.0.0".parse::().is_err()); // first octet is a zero in octal /// assert!("0xcb.0x0.0x71.0x00".parse::().is_err()); // all octets are in hex /// ``` #[derive(Copy)] From d65ab29e2e67bfc329c606923130d6bf5a518800 Mon Sep 17 00:00:00 2001 From: twetzel59 Date: Sat, 24 Jul 2021 15:54:58 -0400 Subject: [PATCH 06/30] Remove unnecessary condition in Barrier::wait() --- library/std/src/sync/barrier.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sync/barrier.rs b/library/std/src/sync/barrier.rs index a17b82f82e8c2..bc560806051dc 100644 --- a/library/std/src/sync/barrier.rs +++ b/library/std/src/sync/barrier.rs @@ -129,7 +129,7 @@ impl Barrier { if lock.count < self.num_threads { // We need a while loop to guard against spurious wakeups. // https://en.wikipedia.org/wiki/Spurious_wakeup - while local_gen == lock.generation_id && lock.count < self.num_threads { + while local_gen == lock.generation_id { lock = self.cvar.wait(lock).unwrap(); } BarrierWaitResult(false) From 403d269f20c9b1d71efccf1e95ef76470dd7ebe5 Mon Sep 17 00:00:00 2001 From: Smittyvb Date: Tue, 10 Aug 2021 16:43:17 -0400 Subject: [PATCH 07/30] Specify maximum IP address length Co-authored-by: Cheng XU <3105373+xu-cheng@users.noreply.github.com> --- library/std/src/net/parser.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/net/parser.rs b/library/std/src/net/parser.rs index e233d605ce55a..4e16a55edece2 100644 --- a/library/std/src/net/parser.rs +++ b/library/std/src/net/parser.rs @@ -148,7 +148,7 @@ impl<'a> Parser<'a> { *slot = p.read_separator('.', i, |p| { // Disallow octal number in IP string. // https://tools.ietf.org/html/rfc6943#section-3.1.1 - p.read_number(10, None, false) + p.read_number(10, Some(3), false) })?; } From 85d6029c136f155a2b994be8ef7b2ed0876428bf Mon Sep 17 00:00:00 2001 From: Ethan Brierley Date: Sat, 4 Sep 2021 15:44:26 +0100 Subject: [PATCH 08/30] `AbstractConst::root`: Always run `subst` when `Node` is `Leaf` --- compiler/rustc_privacy/src/lib.rs | 9 +++---- .../src/traits/const_evaluatable.rs | 25 +++++++++---------- .../src/traits/object_safety.rs | 18 +++++++------ 3 files changed, 25 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 9c376c6c93e2e..96a398ddf0507 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -23,7 +23,7 @@ use rustc_middle::mir::abstract_const::Node as ACNode; use rustc_middle::span_bug; use rustc_middle::ty::fold::TypeVisitor; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::subst::{InternalSubsts, Subst}; +use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::{self, Const, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeFoldable}; use rustc_session::lint; use rustc_span::hygiene::Transparency; @@ -153,11 +153,8 @@ where tcx: TyCtxt<'tcx>, ct: AbstractConst<'tcx>, ) -> ControlFlow { - const_evaluatable::walk_abstract_const(tcx, ct, |node| match node.root() { - ACNode::Leaf(leaf) => { - let leaf = leaf.subst(tcx, ct.substs); - self.visit_const(leaf) - } + const_evaluatable::walk_abstract_const(tcx, ct, |node| match node.root(tcx, ct.substs) { + ACNode::Leaf(leaf) => self.visit_const(leaf), ACNode::Cast(_, _, ty) => self.visit_ty(ty), ACNode::Binop(..) | ACNode::UnaryOp(..) | ACNode::FunctionCall(_, _) => { ControlFlow::CONTINUE diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index ddabe5967d79c..f070e9dd5e5d5 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -8,6 +8,7 @@ //! In this case we try to build an abstract representation of this constant using //! `mir_abstract_const` which can then be checked for structural equality with other //! generic constants mentioned in the `caller_bounds` of the current environment. +use crate::traits::ty::subst::GenericArg; use rustc_errors::ErrorReported; use rustc_hir::def::DefKind; use rustc_index::bit_set::BitSet; @@ -80,9 +81,8 @@ pub fn is_const_evaluatable<'cx, 'tcx>( Concrete, } let mut failure_kind = FailureKind::Concrete; - walk_abstract_const::(tcx, ct, |node| match node.root() { + walk_abstract_const::(tcx, ct, |node| match node.root(tcx, ct.substs) { Node::Leaf(leaf) => { - let leaf = leaf.subst(tcx, ct.substs); if leaf.has_infer_types_or_consts() { failure_kind = FailureKind::MentionsInfer; } else if leaf.definitely_has_param_types_or_consts(tcx) { @@ -92,7 +92,6 @@ pub fn is_const_evaluatable<'cx, 'tcx>( ControlFlow::CONTINUE } Node::Cast(_, _, ty) => { - let ty = ty.subst(tcx, ct.substs); if ty.has_infer_types_or_consts() { failure_kind = FailureKind::MentionsInfer; } else if ty.definitely_has_param_types_or_consts(tcx) { @@ -218,8 +217,12 @@ impl<'tcx> AbstractConst<'tcx> { } #[inline] - pub fn root(self) -> Node<'tcx> { - self.inner.last().copied().unwrap() + pub fn root(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> Node<'tcx> { + let mut node = self.inner.last().copied().unwrap(); + if let Node::Leaf(leaf) = node { + node = Node::Leaf(leaf.subst(tcx, substs)); + } + node } } @@ -587,7 +590,7 @@ where f: &mut dyn FnMut(AbstractConst<'tcx>) -> ControlFlow, ) -> ControlFlow { f(ct)?; - let root = ct.root(); + let root = ct.root(tcx, ct.substs); match root { Node::Leaf(_) => ControlFlow::CONTINUE, Node::Binop(_, l, r) => { @@ -615,16 +618,14 @@ pub(super) fn try_unify<'tcx>( // We substitute generics repeatedly to allow AbstractConsts to unify where a // ConstKind::Unevalated could be turned into an AbstractConst that would unify e.g. // Param(N) should unify with Param(T), substs: [Unevaluated("T2", [Unevaluated("T3", [Param(N)])])] - while let Node::Leaf(a_ct) = a.root() { - let a_ct = a_ct.subst(tcx, a.substs); + while let Node::Leaf(a_ct) = a.root(tcx, a.substs) { match AbstractConst::from_const(tcx, a_ct) { Ok(Some(a_act)) => a = a_act, Ok(None) => break, Err(_) => return true, } } - while let Node::Leaf(b_ct) = b.root() { - let b_ct = b_ct.subst(tcx, b.substs); + while let Node::Leaf(b_ct) = b.root(tcx, b.substs) { match AbstractConst::from_const(tcx, b_ct) { Ok(Some(b_act)) => b = b_act, Ok(None) => break, @@ -632,10 +633,8 @@ pub(super) fn try_unify<'tcx>( } } - match (a.root(), b.root()) { + match (a.root(tcx, a.substs), b.root(tcx, b.substs)) { (Node::Leaf(a_ct), Node::Leaf(b_ct)) => { - let a_ct = a_ct.subst(tcx, a.substs); - let b_ct = b_ct.subst(tcx, b.substs); if a_ct.ty != b_ct.ty { return false; } diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 57b8a84300ff9..dee95a3be386c 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -838,14 +838,16 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( // constants which are not considered const evaluatable. use rustc_middle::mir::abstract_const::Node; if let Ok(Some(ct)) = AbstractConst::new(self.tcx, uv.shrink()) { - const_evaluatable::walk_abstract_const(self.tcx, ct, |node| match node.root() { - Node::Leaf(leaf) => { - let leaf = leaf.subst(self.tcx, ct.substs); - self.visit_const(leaf) - } - Node::Cast(_, _, ty) => self.visit_ty(ty), - Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => { - ControlFlow::CONTINUE + const_evaluatable::walk_abstract_const(self.tcx, ct, |node| { + match node.root(self.tcx, ct.substs) { + Node::Leaf(leaf) => { + // let leaf = leaf.subst(self.tcx, ct.substs); + self.visit_const(leaf) + } + Node::Cast(_, _, ty) => self.visit_ty(ty), + Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => { + ControlFlow::CONTINUE + } } }) } else { From 22c27385734808a69c5520a8417dd3e45f01b536 Mon Sep 17 00:00:00 2001 From: Ethan Brierley Date: Sat, 4 Sep 2021 15:47:00 +0100 Subject: [PATCH 09/30] Minor cleanup: make imports more consistent --- compiler/rustc_trait_selection/src/traits/const_evaluatable.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index f070e9dd5e5d5..5f7a9a17e03aa 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -8,7 +8,6 @@ //! In this case we try to build an abstract representation of this constant using //! `mir_abstract_const` which can then be checked for structural equality with other //! generic constants mentioned in the `caller_bounds` of the current environment. -use crate::traits::ty::subst::GenericArg; use rustc_errors::ErrorReported; use rustc_hir::def::DefKind; use rustc_index::bit_set::BitSet; @@ -17,7 +16,7 @@ use rustc_infer::infer::InferCtxt; use rustc_middle::mir::abstract_const::{Node, NodeId, NotConstEvaluatable}; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::mir::{self, Rvalue, StatementKind, TerminatorKind}; -use rustc_middle::ty::subst::{Subst, SubstsRef}; +use rustc_middle::ty::subst::{GenericArg, Subst, SubstsRef}; use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; use rustc_session::lint; use rustc_span::def_id::LocalDefId; From 6e4061819fa00c74c704507a72d4ee3ca60d60e5 Mon Sep 17 00:00:00 2001 From: Ethan Brierley Date: Sat, 4 Sep 2021 15:49:02 +0100 Subject: [PATCH 10/30] Remove left over comment --- compiler/rustc_trait_selection/src/traits/object_safety.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index dee95a3be386c..6c60394116b93 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -840,10 +840,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( if let Ok(Some(ct)) = AbstractConst::new(self.tcx, uv.shrink()) { const_evaluatable::walk_abstract_const(self.tcx, ct, |node| { match node.root(self.tcx, ct.substs) { - Node::Leaf(leaf) => { - // let leaf = leaf.subst(self.tcx, ct.substs); - self.visit_const(leaf) - } + Node::Leaf(leaf) => self.visit_const(leaf), Node::Cast(_, _, ty) => self.visit_ty(ty), Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => { ControlFlow::CONTINUE From fc5633fed6905b1dbf307cbce795e2545817e023 Mon Sep 17 00:00:00 2001 From: Ethan Brierley Date: Sat, 4 Sep 2021 16:28:55 +0100 Subject: [PATCH 11/30] Make fields on `AbstractConst` private --- compiler/rustc_privacy/src/lib.rs | 2 +- .../src/traits/const_evaluatable.rs | 22 +++++++++---------- .../src/traits/object_safety.rs | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 96a398ddf0507..e424a51d01c97 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -153,7 +153,7 @@ where tcx: TyCtxt<'tcx>, ct: AbstractConst<'tcx>, ) -> ControlFlow { - const_evaluatable::walk_abstract_const(tcx, ct, |node| match node.root(tcx, ct.substs) { + const_evaluatable::walk_abstract_const(tcx, ct, |node| match node.root(tcx) { ACNode::Leaf(leaf) => self.visit_const(leaf), ACNode::Cast(_, _, ty) => self.visit_ty(ty), ACNode::Binop(..) | ACNode::UnaryOp(..) | ACNode::FunctionCall(_, _) => { diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 5f7a9a17e03aa..1adcda41102d2 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -16,7 +16,7 @@ use rustc_infer::infer::InferCtxt; use rustc_middle::mir::abstract_const::{Node, NodeId, NotConstEvaluatable}; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::mir::{self, Rvalue, StatementKind, TerminatorKind}; -use rustc_middle::ty::subst::{GenericArg, Subst, SubstsRef}; +use rustc_middle::ty::subst::{Subst, SubstsRef}; use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; use rustc_session::lint; use rustc_span::def_id::LocalDefId; @@ -80,7 +80,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>( Concrete, } let mut failure_kind = FailureKind::Concrete; - walk_abstract_const::(tcx, ct, |node| match node.root(tcx, ct.substs) { + walk_abstract_const::(tcx, ct, |node| match node.root(tcx) { Node::Leaf(leaf) => { if leaf.has_infer_types_or_consts() { failure_kind = FailureKind::MentionsInfer; @@ -185,8 +185,8 @@ pub fn is_const_evaluatable<'cx, 'tcx>( pub struct AbstractConst<'tcx> { // FIXME: Consider adding something like `IndexSlice` // and use this here. - pub inner: &'tcx [Node<'tcx>], - pub substs: SubstsRef<'tcx>, + inner: &'tcx [Node<'tcx>], + substs: SubstsRef<'tcx>, } impl<'tcx> AbstractConst<'tcx> { @@ -216,10 +216,10 @@ impl<'tcx> AbstractConst<'tcx> { } #[inline] - pub fn root(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> Node<'tcx> { - let mut node = self.inner.last().copied().unwrap(); + pub fn root(self, tcx: TyCtxt<'tcx>) -> Node<'tcx> { + let node = self.inner.last().copied().unwrap(); if let Node::Leaf(leaf) = node { - node = Node::Leaf(leaf.subst(tcx, substs)); + return Node::Leaf(leaf.subst(tcx, self.substs)); } node } @@ -589,7 +589,7 @@ where f: &mut dyn FnMut(AbstractConst<'tcx>) -> ControlFlow, ) -> ControlFlow { f(ct)?; - let root = ct.root(tcx, ct.substs); + let root = ct.root(tcx); match root { Node::Leaf(_) => ControlFlow::CONTINUE, Node::Binop(_, l, r) => { @@ -617,14 +617,14 @@ pub(super) fn try_unify<'tcx>( // We substitute generics repeatedly to allow AbstractConsts to unify where a // ConstKind::Unevalated could be turned into an AbstractConst that would unify e.g. // Param(N) should unify with Param(T), substs: [Unevaluated("T2", [Unevaluated("T3", [Param(N)])])] - while let Node::Leaf(a_ct) = a.root(tcx, a.substs) { + while let Node::Leaf(a_ct) = a.root(tcx) { match AbstractConst::from_const(tcx, a_ct) { Ok(Some(a_act)) => a = a_act, Ok(None) => break, Err(_) => return true, } } - while let Node::Leaf(b_ct) = b.root(tcx, b.substs) { + while let Node::Leaf(b_ct) = b.root(tcx) { match AbstractConst::from_const(tcx, b_ct) { Ok(Some(b_act)) => b = b_act, Ok(None) => break, @@ -632,7 +632,7 @@ pub(super) fn try_unify<'tcx>( } } - match (a.root(tcx, a.substs), b.root(tcx, b.substs)) { + match (a.root(tcx), b.root(tcx)) { (Node::Leaf(a_ct), Node::Leaf(b_ct)) => { if a_ct.ty != b_ct.ty { return false; diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 6c60394116b93..4eaa3ea47325f 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -839,7 +839,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( use rustc_middle::mir::abstract_const::Node; if let Ok(Some(ct)) = AbstractConst::new(self.tcx, uv.shrink()) { const_evaluatable::walk_abstract_const(self.tcx, ct, |node| { - match node.root(self.tcx, ct.substs) { + match node.root(self.tcx) { Node::Leaf(leaf) => self.visit_const(leaf), Node::Cast(_, _, ty) => self.visit_ty(ty), Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => { From b7d99983f879696522a5c770241a2fb171071eab Mon Sep 17 00:00:00 2001 From: Ethan Brierley Date: Sat, 4 Sep 2021 23:13:15 +0100 Subject: [PATCH 12/30] Add line that was unintentionally removed --- compiler/rustc_trait_selection/src/traits/const_evaluatable.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 1adcda41102d2..4acde1b216535 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -91,6 +91,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>( ControlFlow::CONTINUE } Node::Cast(_, _, ty) => { + let ty = ty.subst(tcx, ct.substs); if ty.has_infer_types_or_consts() { failure_kind = FailureKind::MentionsInfer; } else if ty.definitely_has_param_types_or_consts(tcx) { From 4a37b9cbffdc9ba66e9e4b7a17cb0de157a647f8 Mon Sep 17 00:00:00 2001 From: Hans Kratz Date: Mon, 18 Oct 2021 13:15:45 +0200 Subject: [PATCH 13/30] Avoid overflow in `VecDeque::with_capacity_in()`. --- library/alloc/src/collections/vec_deque/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index c890ff4ac5e2b..de607c8fdab31 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -543,9 +543,9 @@ impl VecDeque { /// ``` #[unstable(feature = "allocator_api", issue = "32838")] pub fn with_capacity_in(capacity: usize, alloc: A) -> VecDeque { + assert!(capacity < 1_usize << usize::BITS - 1, "capacity overflow"); // +1 since the ringbuffer always leaves one space empty let cap = cmp::max(capacity + 1, MINIMUM_CAPACITY + 1).next_power_of_two(); - assert!(cap > capacity, "capacity overflow"); VecDeque { tail: 0, head: 0, buf: RawVec::with_capacity_in(cap, alloc) } } From 93f80bff940c4269e18836b3f4c5cefed19b361a Mon Sep 17 00:00:00 2001 From: Tyson Nottingham Date: Mon, 18 Oct 2021 16:25:21 -0700 Subject: [PATCH 14/30] Remove comment saying that we don't build debug rustc in CI, since we do --- src/test/ui/rustc-rust-log.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/test/ui/rustc-rust-log.rs b/src/test/ui/rustc-rust-log.rs index 8ceb24dd2afd2..52e7dcf4499a8 100644 --- a/src/test/ui/rustc-rust-log.rs +++ b/src/test/ui/rustc-rust-log.rs @@ -1,9 +1,6 @@ // run-pass // This test is just checking that we won't ICE if logging is turned -// on; don't bother trying to compare that (copious) output. (Note -// also that this test potentially silly, since we do not build+test -// debug versions of rustc as part of our continuous integration -// process...) +// on; don't bother trying to compare that (copious) output. // // dont-check-compiler-stdout // dont-check-compiler-stderr From aefbd401408769fbca1c486546b8dc3fce9e0d9b Mon Sep 17 00:00:00 2001 From: Tyson Nottingham Date: Mon, 18 Oct 2021 14:00:29 -0700 Subject: [PATCH 15/30] Add test for debug logging during incremental compilation Debug logging during incremental compilation had been broken for some time, until #89343 fixed it (among other things). Add a test so this is less likely to break without being noticed. This test is nearly a copy of the `src/test/ui/rustc-rust-log.rs` test, but tests debug logging in the incremental compliation code paths. --- .../incremental/auxiliary/rustc-rust-log-aux.rs | 8 ++++++++ src/test/incremental/rustc-rust-log.rs | 16 ++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/test/incremental/auxiliary/rustc-rust-log-aux.rs create mode 100644 src/test/incremental/rustc-rust-log.rs diff --git a/src/test/incremental/auxiliary/rustc-rust-log-aux.rs b/src/test/incremental/auxiliary/rustc-rust-log-aux.rs new file mode 100644 index 0000000000000..a361373dc1955 --- /dev/null +++ b/src/test/incremental/auxiliary/rustc-rust-log-aux.rs @@ -0,0 +1,8 @@ +// rustc-env:RUSTC_LOG=debug +#[cfg(rpass1)] +pub fn foo() {} + +#[cfg(rpass2)] +pub fn foo() { + println!(); +} diff --git a/src/test/incremental/rustc-rust-log.rs b/src/test/incremental/rustc-rust-log.rs new file mode 100644 index 0000000000000..566f0d96d9732 --- /dev/null +++ b/src/test/incremental/rustc-rust-log.rs @@ -0,0 +1,16 @@ +// revisions: rpass1 rpass2 +// This test is just checking that we won't ICE if logging is turned +// on; don't bother trying to compare that (copious) output. +// +// dont-check-compiler-stdout +// dont-check-compiler-stderr +// aux-build: rustc-rust-log-aux.rs +// rustc-env:RUSTC_LOG=debug + +#[cfg(rpass1)] +fn main() {} + +#[cfg(rpass2)] +fn main() { + println!(); +} From f2a234e63c6f5db70a363507bf940dbc51d4efda Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Mon, 18 Oct 2021 17:59:00 -0400 Subject: [PATCH 16/30] config: add the option to enable LLVM tests I'm working on some LLVM patches in concert with a Rust patch, and it's helping me quite a bit to have this as an option. It doesn't seem that hard, so I figured I'd formalize it in x.py and send it upstream. --- config.toml.example | 6 ++++++ src/bootstrap/config.rs | 5 +++++ src/bootstrap/native.rs | 3 ++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/config.toml.example b/config.toml.example index 61e57eee782b8..2128fdea2eb46 100644 --- a/config.toml.example +++ b/config.toml.example @@ -68,6 +68,12 @@ changelog-seen = 2 # Indicates whether the LLVM assertions are enabled or not #assertions = false +# Indicates whether the LLVM testsuite is enabled in the build or not. Does +# not execute the tests as part of the build as part of x.py build et al, +# just makes it possible to do `ninja check-llvm` in the staged LLVM build +# directory when doing LLVM development as part of Rust development. +#tests = false + # Indicates whether the LLVM plugin is enabled or not #plugins = false diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 9a48b768cb37d..8d03aade3413a 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -90,6 +90,7 @@ pub struct Config { // llvm codegen options pub llvm_skip_rebuild: bool, pub llvm_assertions: bool, + pub llvm_tests: bool, pub llvm_plugins: bool, pub llvm_optimize: bool, pub llvm_thin_lto: bool, @@ -422,6 +423,7 @@ struct Llvm { thin_lto: Option, release_debuginfo: Option, assertions: Option, + tests: Option, plugins: Option, ccache: Option, version_check: Option, @@ -715,6 +717,7 @@ impl Config { // Store off these values as options because if they're not provided // we'll infer default values for them later let mut llvm_assertions = None; + let mut llvm_tests = None; let mut llvm_plugins = None; let mut debug = None; let mut debug_assertions = None; @@ -740,6 +743,7 @@ impl Config { } set(&mut config.ninja_in_file, llvm.ninja); llvm_assertions = llvm.assertions; + llvm_tests = llvm.tests; llvm_plugins = llvm.plugins; llvm_skip_rebuild = llvm_skip_rebuild.or(llvm.skip_rebuild); set(&mut config.llvm_optimize, llvm.optimize); @@ -991,6 +995,7 @@ impl Config { config.llvm_skip_rebuild = llvm_skip_rebuild.unwrap_or(false); config.llvm_assertions = llvm_assertions.unwrap_or(false); + config.llvm_tests = llvm_tests.unwrap_or(false); config.llvm_plugins = llvm_plugins.unwrap_or(false); config.rust_optimize = optimize.unwrap_or(true); diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 27c9bb2504f6d..6bfaeffa80705 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -170,6 +170,7 @@ impl Step for Llvm { let assertions = if builder.config.llvm_assertions { "ON" } else { "OFF" }; let plugins = if builder.config.llvm_plugins { "ON" } else { "OFF" }; + let enable_tests = if builder.config.llvm_tests { "ON" } else { "OFF" }; cfg.out_dir(&out_dir) .profile(profile) @@ -180,7 +181,7 @@ impl Step for Llvm { .define("LLVM_INCLUDE_EXAMPLES", "OFF") .define("LLVM_INCLUDE_DOCS", "OFF") .define("LLVM_INCLUDE_BENCHMARKS", "OFF") - .define("LLVM_INCLUDE_TESTS", "OFF") + .define("LLVM_INCLUDE_TESTS", enable_tests) .define("LLVM_ENABLE_TERMINFO", "OFF") .define("LLVM_ENABLE_LIBEDIT", "OFF") .define("LLVM_ENABLE_BINDINGS", "OFF") From e8b5af1c0a5194ef2e46f2566e82b30bc1b8537b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 19 Oct 2021 11:25:39 +0200 Subject: [PATCH 17/30] Upgrade browser-ui-test version to 0.4.5 (it allows to have multi-line commands) --- src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile index adc970c66d688..ba4e1ca31148c 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile @@ -72,7 +72,7 @@ ENV PATH="/node-v14.4.0-linux-x64/bin:${PATH}" # https://github.com/puppeteer/puppeteer/issues/375 # # We also specify the version in case we need to update it to go around cache limitations. -RUN npm install -g browser-ui-test@0.4.3 --unsafe-perm=true +RUN npm install -g browser-ui-test@0.4.5 --unsafe-perm=true ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ From 05eb6f36f1e17aa00ef286c2dacc9d890fdc899c Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Tue, 19 Oct 2021 23:08:14 +0200 Subject: [PATCH 18/30] Cleanup dead code in hir::map::blocks. --- compiler/rustc_middle/src/hir/map/blocks.rs | 186 ++------------------ 1 file changed, 14 insertions(+), 172 deletions(-) diff --git a/compiler/rustc_middle/src/hir/map/blocks.rs b/compiler/rustc_middle/src/hir/map/blocks.rs index 8efec8ef5674d..1ba205903dcff 100644 --- a/compiler/rustc_middle/src/hir/map/blocks.rs +++ b/compiler/rustc_middle/src/hir/map/blocks.rs @@ -11,12 +11,9 @@ //! nested within a uniquely determined `FnLike`), and users can ask //! for the `Code` associated with a particular NodeId. -use crate::hir::map::Map; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; -use rustc_hir::{Expr, FnDecl, Node}; -use rustc_span::symbol::Ident; -use rustc_span::Span; +use rustc_hir::Node; /// An FnLikeNode is a Node that is like a fn, in that it has a decl /// and a body (as well as a NodeId, a span, etc). @@ -33,139 +30,21 @@ pub struct FnLikeNode<'a> { node: Node<'a>, } -/// MaybeFnLike wraps a method that indicates if an object -/// corresponds to some FnLikeNode. -trait MaybeFnLike { - fn is_fn_like(&self) -> bool; -} - -impl MaybeFnLike for hir::Item<'_> { - fn is_fn_like(&self) -> bool { - matches!(self.kind, hir::ItemKind::Fn(..)) - } -} - -impl MaybeFnLike for hir::ImplItem<'_> { - fn is_fn_like(&self) -> bool { - matches!(self.kind, hir::ImplItemKind::Fn(..)) - } -} - -impl MaybeFnLike for hir::TraitItem<'_> { - fn is_fn_like(&self) -> bool { - matches!(self.kind, hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_))) - } -} - -impl MaybeFnLike for hir::Expr<'_> { - fn is_fn_like(&self) -> bool { - matches!(self.kind, hir::ExprKind::Closure(..)) - } -} - -/// Carries either an FnLikeNode or an Expr, as these are the two -/// constructs that correspond to "code" (as in, something from which -/// we can construct a control-flow graph). -#[derive(Copy, Clone)] -pub enum Code<'a> { - FnLike(FnLikeNode<'a>), - Expr(&'a Expr<'a>), -} - -impl<'a> Code<'a> { - pub fn id(&self) -> hir::HirId { - match *self { - Code::FnLike(node) => node.id(), - Code::Expr(block) => block.hir_id, - } - } - - /// Attempts to construct a Code from presumed FnLike or Expr node input. - pub fn from_node(map: &Map<'a>, id: hir::HirId) -> Option> { - match map.get(id) { - Node::Block(_) => { - // Use the parent, hopefully an expression node. - Code::from_node(map, map.get_parent_node(id)) - } - Node::Expr(expr) => Some(Code::Expr(expr)), - node => FnLikeNode::from_node(node).map(Code::FnLike), - } - } -} - -/// These are all the components one can extract from a fn item for -/// use when implementing FnLikeNode operations. -struct ItemFnParts<'a> { - ident: Ident, - decl: &'a hir::FnDecl<'a>, - header: hir::FnHeader, - vis: &'a hir::Visibility<'a>, - generics: &'a hir::Generics<'a>, - body: hir::BodyId, - id: hir::HirId, - span: Span, -} - -/// These are all the components one can extract from a closure expr -/// for use when implementing FnLikeNode operations. -struct ClosureParts<'a> { - decl: &'a FnDecl<'a>, - body: hir::BodyId, - id: hir::HirId, - span: Span, -} - -impl<'a> ClosureParts<'a> { - fn new(d: &'a FnDecl<'a>, b: hir::BodyId, id: hir::HirId, s: Span) -> Self { - ClosureParts { decl: d, body: b, id, span: s } - } -} - impl<'a> FnLikeNode<'a> { /// Attempts to construct a FnLikeNode from presumed FnLike node input. pub fn from_node(node: Node<'_>) -> Option> { let fn_like = match node { - Node::Item(item) => item.is_fn_like(), - Node::TraitItem(tm) => tm.is_fn_like(), - Node::ImplItem(it) => it.is_fn_like(), - Node::Expr(e) => e.is_fn_like(), + Node::Item(item) => matches!(item.kind, hir::ItemKind::Fn(..)), + Node::TraitItem(tm) => { + matches!(tm.kind, hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_))) + } + Node::ImplItem(it) => matches!(it.kind, hir::ImplItemKind::Fn(..)), + Node::Expr(e) => matches!(e.kind, hir::ExprKind::Closure(..)), _ => false, }; fn_like.then_some(FnLikeNode { node }) } - pub fn body(self) -> hir::BodyId { - self.handle( - |i: ItemFnParts<'a>| i.body, - |_, _, _: &'a hir::FnSig<'a>, _, body: hir::BodyId, _| body, - |c: ClosureParts<'a>| c.body, - ) - } - - pub fn decl(self) -> &'a FnDecl<'a> { - self.handle( - |i: ItemFnParts<'a>| &*i.decl, - |_, _, sig: &'a hir::FnSig<'a>, _, _, _| &sig.decl, - |c: ClosureParts<'a>| c.decl, - ) - } - - pub fn span(self) -> Span { - self.handle( - |i: ItemFnParts<'_>| i.span, - |_, _, _: &'a hir::FnSig<'a>, _, _, span| span, - |c: ClosureParts<'_>| c.span, - ) - } - - pub fn id(self) -> hir::HirId { - self.handle( - |i: ItemFnParts<'_>| i.id, - |id, _, _: &'a hir::FnSig<'a>, _, _, _| id, - |c: ClosureParts<'_>| c.id, - ) - } - pub fn constness(self) -> hir::Constness { self.kind().header().map_or(hir::Constness::NotConst, |header| header.constness) } @@ -174,63 +53,26 @@ impl<'a> FnLikeNode<'a> { self.kind().header().map_or(hir::IsAsync::NotAsync, |header| header.asyncness) } - pub fn unsafety(self) -> hir::Unsafety { - self.kind().header().map_or(hir::Unsafety::Normal, |header| header.unsafety) - } - pub fn kind(self) -> FnKind<'a> { - let item = |p: ItemFnParts<'a>| -> FnKind<'a> { - FnKind::ItemFn(p.ident, p.generics, p.header, p.vis) - }; - let closure = |_: ClosureParts<'a>| FnKind::Closure; - let method = - |_, ident: Ident, sig: &'a hir::FnSig<'a>, vis, _, _| FnKind::Method(ident, sig, vis); - self.handle(item, method, closure) - } - - fn handle(self, item_fn: I, method: M, closure: C) -> A - where - I: FnOnce(ItemFnParts<'a>) -> A, - M: FnOnce( - hir::HirId, - Ident, - &'a hir::FnSig<'a>, - Option<&'a hir::Visibility<'a>>, - hir::BodyId, - Span, - ) -> A, - C: FnOnce(ClosureParts<'a>) -> A, - { match self.node { Node::Item(i) => match i.kind { - hir::ItemKind::Fn(ref sig, ref generics, block) => item_fn(ItemFnParts { - id: i.hir_id(), - ident: i.ident, - decl: &sig.decl, - body: block, - vis: &i.vis, - span: i.span, - header: sig.header, - generics, - }), + hir::ItemKind::Fn(ref sig, ref generics, _) => { + FnKind::ItemFn(i.ident, generics, sig.header, &i.vis) + } _ => bug!("item FnLikeNode that is not fn-like"), }, Node::TraitItem(ti) => match ti.kind { - hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { - method(ti.hir_id(), ti.ident, sig, None, body, ti.span) + hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(_)) => { + FnKind::Method(ti.ident, sig, None) } _ => bug!("trait method FnLikeNode that is not fn-like"), }, Node::ImplItem(ii) => match ii.kind { - hir::ImplItemKind::Fn(ref sig, body) => { - method(ii.hir_id(), ii.ident, sig, Some(&ii.vis), body, ii.span) - } + hir::ImplItemKind::Fn(ref sig, _) => FnKind::Method(ii.ident, sig, Some(&ii.vis)), _ => bug!("impl method FnLikeNode that is not fn-like"), }, Node::Expr(e) => match e.kind { - hir::ExprKind::Closure(_, ref decl, block, _fn_decl_span, _gen) => { - closure(ClosureParts::new(&decl, block, e.hir_id, e.span)) - } + hir::ExprKind::Closure(..) => FnKind::Closure, _ => bug!("expr FnLikeNode that is not fn-like"), }, _ => bug!("other FnLikeNode that is not fn-like"), From 99b8c016cea9b1f1917d287401b498abd4eabd29 Mon Sep 17 00:00:00 2001 From: Ethan Brierley Date: Tue, 19 Oct 2021 22:18:13 +0100 Subject: [PATCH 19/30] Address lcnr review --- .../rustc_trait_selection/src/traits/const_evaluatable.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 4acde1b216535..2cf7b6b1d9393 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -219,10 +219,12 @@ impl<'tcx> AbstractConst<'tcx> { #[inline] pub fn root(self, tcx: TyCtxt<'tcx>) -> Node<'tcx> { let node = self.inner.last().copied().unwrap(); - if let Node::Leaf(leaf) = node { - return Node::Leaf(leaf.subst(tcx, self.substs)); + match node { + Node::Leaf(leaf) => Node::Leaf(leaf.subst(tcx, self.substs)), + Node::Cast(kind, operand, ty) => Node::Cast(kind, operand, ty.subst(tcx, self.substs)), + // Don't perform substitution on the following as they can't directly contain generic params + Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => node, } - node } } From 6e98688e68affa283b8edeb8c61958436c74c1aa Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Tue, 19 Oct 2021 23:31:51 +0200 Subject: [PATCH 20/30] Replace FnLikeNode by FnKind. --- .../src/const_eval/fn_queries.rs | 5 +- compiler/rustc_hir/src/hir.rs | 27 +++++++ compiler/rustc_hir/src/intravisit.rs | 8 ++ .../error_reporting/nice_region_error/util.rs | 5 +- compiler/rustc_middle/src/hir/map/blocks.rs | 81 ------------------- compiler/rustc_middle/src/hir/map/mod.rs | 2 - compiler/rustc_mir_build/src/lints.rs | 5 +- .../rustc_mir_transform/src/const_prop.rs | 3 +- .../rustc_mir_transform/src/coverage/mod.rs | 5 +- compiler/rustc_mir_transform/src/lib.rs | 3 +- compiler/rustc_ty_utils/src/ty.rs | 5 +- 11 files changed, 47 insertions(+), 102 deletions(-) delete mode 100644 compiler/rustc_middle/src/hir/map/blocks.rs diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs index df4cc295fac5f..80551518d3c5d 100644 --- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs @@ -1,6 +1,5 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_middle::hir::map::blocks::FnLikeNode; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_span::symbol::Symbol; @@ -44,8 +43,8 @@ fn is_const_fn_raw(tcx: TyCtxt<'_>, def_id: DefId) -> bool { } else { false } - } else if let Some(fn_like) = FnLikeNode::from_node(node) { - if fn_like.constness() == hir::Constness::Const { + } else if let Some(fn_kind) = node.fn_kind() { + if fn_kind.constness() == hir::Constness::Const { return true; } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index b5c1e31c258ef..6f25715fbecc4 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1,6 +1,7 @@ use crate::def::{CtorKind, DefKind, Res}; use crate::def_id::DefId; crate use crate::hir_id::{HirId, ItemLocalId}; +use crate::intravisit::FnKind; use crate::LangItem; use rustc_ast::util::parser::ExprPrecedence; @@ -3258,6 +3259,32 @@ impl<'hir> Node<'hir> { _ => None, } } + + pub fn fn_kind(self) -> Option> { + match self { + Node::Item(i) => match i.kind { + ItemKind::Fn(ref sig, ref generics, _) => { + Some(FnKind::ItemFn(i.ident, generics, sig.header, &i.vis)) + } + _ => None, + }, + Node::TraitItem(ti) => match ti.kind { + TraitItemKind::Fn(ref sig, TraitFn::Provided(_)) => { + Some(FnKind::Method(ti.ident, sig, None)) + } + _ => None, + }, + Node::ImplItem(ii) => match ii.kind { + ImplItemKind::Fn(ref sig, _) => Some(FnKind::Method(ii.ident, sig, Some(&ii.vis))), + _ => None, + }, + Node::Expr(e) => match e.kind { + ExprKind::Closure(..) => Some(FnKind::Closure), + _ => None, + }, + _ => None, + } + } } // Some nodes are used a lot. Make sure they don't unintentionally get bigger. diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 3e58af1f167aa..cff543760f42a 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -117,6 +117,14 @@ impl<'a> FnKind<'a> { FnKind::Closure => None, } } + + pub fn constness(self) -> Constness { + self.header().map_or(Constness::NotConst, |header| header.constness) + } + + pub fn asyncness(self) -> IsAsync { + self.header().map_or(IsAsync::NotAsync, |header| header.asyncness) + } } /// An abstract representation of the HIR `rustc_middle::hir::map::Map`. diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs index 8dcdd4b149ea6..90bc5b3b2fed1 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs @@ -143,9 +143,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // similar to the asyncness fn in rustc_ty_utils::ty let hir_id = self.tcx().hir().local_def_id_to_hir_id(local_def_id); let node = self.tcx().hir().get(hir_id); - let fn_like = rustc_middle::hir::map::blocks::FnLikeNode::from_node(node)?; - - Some(fn_like.asyncness()) + let fn_kind = node.fn_kind()?; + Some(fn_kind.asyncness()) } // Here, we check for the case where the anonymous region diff --git a/compiler/rustc_middle/src/hir/map/blocks.rs b/compiler/rustc_middle/src/hir/map/blocks.rs deleted file mode 100644 index 1ba205903dcff..0000000000000 --- a/compiler/rustc_middle/src/hir/map/blocks.rs +++ /dev/null @@ -1,81 +0,0 @@ -//! This module provides a simplified abstraction for working with -//! code blocks identified by their integer `NodeId`. In particular, -//! it captures a common set of attributes that all "function-like -//! things" (represented by `FnLike` instances) share. For example, -//! all `FnLike` instances have a type signature (be it explicit or -//! inferred). And all `FnLike` instances have a body, i.e., the code -//! that is run when the function-like thing it represents is invoked. -//! -//! With the above abstraction in place, one can treat the program -//! text as a collection of blocks of code (and most such blocks are -//! nested within a uniquely determined `FnLike`), and users can ask -//! for the `Code` associated with a particular NodeId. - -use rustc_hir as hir; -use rustc_hir::intravisit::FnKind; -use rustc_hir::Node; - -/// An FnLikeNode is a Node that is like a fn, in that it has a decl -/// and a body (as well as a NodeId, a span, etc). -/// -/// More specifically, it is one of either: -/// -/// - A function item, -/// - A closure expr (i.e., an ExprKind::Closure), or -/// - The default implementation for a trait method. -/// -/// To construct one, use the `Code::from_node` function. -#[derive(Copy, Clone, Debug)] -pub struct FnLikeNode<'a> { - node: Node<'a>, -} - -impl<'a> FnLikeNode<'a> { - /// Attempts to construct a FnLikeNode from presumed FnLike node input. - pub fn from_node(node: Node<'_>) -> Option> { - let fn_like = match node { - Node::Item(item) => matches!(item.kind, hir::ItemKind::Fn(..)), - Node::TraitItem(tm) => { - matches!(tm.kind, hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_))) - } - Node::ImplItem(it) => matches!(it.kind, hir::ImplItemKind::Fn(..)), - Node::Expr(e) => matches!(e.kind, hir::ExprKind::Closure(..)), - _ => false, - }; - fn_like.then_some(FnLikeNode { node }) - } - - pub fn constness(self) -> hir::Constness { - self.kind().header().map_or(hir::Constness::NotConst, |header| header.constness) - } - - pub fn asyncness(self) -> hir::IsAsync { - self.kind().header().map_or(hir::IsAsync::NotAsync, |header| header.asyncness) - } - - pub fn kind(self) -> FnKind<'a> { - match self.node { - Node::Item(i) => match i.kind { - hir::ItemKind::Fn(ref sig, ref generics, _) => { - FnKind::ItemFn(i.ident, generics, sig.header, &i.vis) - } - _ => bug!("item FnLikeNode that is not fn-like"), - }, - Node::TraitItem(ti) => match ti.kind { - hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(_)) => { - FnKind::Method(ti.ident, sig, None) - } - _ => bug!("trait method FnLikeNode that is not fn-like"), - }, - Node::ImplItem(ii) => match ii.kind { - hir::ImplItemKind::Fn(ref sig, _) => FnKind::Method(ii.ident, sig, Some(&ii.vis)), - _ => bug!("impl method FnLikeNode that is not fn-like"), - }, - Node::Expr(e) => match e.kind { - hir::ExprKind::Closure(..) => FnKind::Closure, - _ => bug!("expr FnLikeNode that is not fn-like"), - }, - _ => bug!("other FnLikeNode that is not fn-like"), - } - } -} diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 38bc01b9b53d8..fad7e875fa1c0 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -20,8 +20,6 @@ use rustc_span::Span; use rustc_target::spec::abi::Abi; use std::collections::VecDeque; -pub mod blocks; - fn fn_decl<'hir>(node: Node<'hir>) -> Option<&'hir FnDecl<'hir>> { match node { Node::Item(Item { kind: ItemKind::Fn(sig, _, _), .. }) diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs index ef8bd20d51098..e4c2d2dce67c7 100644 --- a/compiler/rustc_mir_build/src/lints.rs +++ b/compiler/rustc_mir_build/src/lints.rs @@ -2,7 +2,6 @@ use rustc_data_structures::graph::iterate::{ NodeStatus, TriColorDepthFirstSearch, TriColorVisitor, }; use rustc_hir::intravisit::FnKind; -use rustc_middle::hir::map::blocks::FnLikeNode; use rustc_middle::mir::{BasicBlock, Body, Operand, TerminatorKind}; use rustc_middle::ty::subst::{GenericArg, InternalSubsts}; use rustc_middle::ty::{self, AssocItem, AssocItemContainer, Instance, TyCtxt}; @@ -14,8 +13,8 @@ crate fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { let def_id = body.source.def_id().expect_local(); let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - if let Some(fn_like_node) = FnLikeNode::from_node(tcx.hir().get(hir_id)) { - if let FnKind::Closure = fn_like_node.kind() { + if let Some(fn_kind) = tcx.hir().get(hir_id).fn_kind() { + if let FnKind::Closure = fn_kind { // closures can't recur, so they don't matter. return; } diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index 17790ec91c8a3..63c637af5c21a 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -68,11 +68,10 @@ impl<'tcx> MirPass<'tcx> for ConstProp { return; } - use rustc_middle::hir::map::blocks::FnLikeNode; let def_id = body.source.def_id().expect_local(); let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - let is_fn_like = FnLikeNode::from_node(tcx.hir().get(hir_id)).is_some(); + let is_fn_like = tcx.hir().get(hir_id).fn_kind().is_some(); let is_assoc_const = tcx.def_kind(def_id.to_def_id()) == DefKind::AssocConst; // Only run const prop on functions, methods, closures and associated constants diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index e980d3d884f56..4ac93f7161923 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -19,7 +19,6 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::Lrc; use rustc_index::vec::IndexVec; use rustc_middle::hir; -use rustc_middle::hir::map::blocks::FnLikeNode; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::coverage::*; use rustc_middle::mir::dump_enabled; @@ -64,7 +63,7 @@ impl<'tcx> MirPass<'tcx> for InstrumentCoverage { } let hir_id = tcx.hir().local_def_id_to_hir_id(mir_source.def_id().expect_local()); - let is_fn_like = FnLikeNode::from_node(tcx.hir().get(hir_id)).is_some(); + let is_fn_like = tcx.hir().get(hir_id).fn_kind().is_some(); // Only instrument functions, methods, and closures (not constants since they are evaluated // at compile time by Miri). @@ -74,7 +73,7 @@ impl<'tcx> MirPass<'tcx> for InstrumentCoverage { // be tricky if const expressions have no corresponding statements in the enclosing MIR. // Closures are carved out by their initial `Assign` statement.) if !is_fn_like { - trace!("InstrumentCoverage skipped for {:?} (not an FnLikeNode)", mir_source.def_id()); + trace!("InstrumentCoverage skipped for {:?} (not an fn-like)", mir_source.def_id()); return; } diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 9b11c8f0b24c0..269ad7f6bf482 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -428,8 +428,7 @@ fn mir_drops_elaborated_and_const_checked<'tcx>( } let hir_id = tcx.hir().local_def_id_to_hir_id(def.did); - use rustc_middle::hir::map::blocks::FnLikeNode; - let is_fn_like = FnLikeNode::from_node(tcx.hir().get(hir_id)).is_some(); + let is_fn_like = tcx.hir().get(hir_id).fn_kind().is_some(); if is_fn_like { let did = def.did.to_def_id(); let def = ty::WithOptConstParam::unknown(did); diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 3d3b274370091..bc77c94809eb5 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -1,7 +1,6 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_middle::hir::map as hir_map; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{ self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt, WithConstness, @@ -478,11 +477,11 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync { let node = tcx.hir().get(hir_id); - let fn_like = hir_map::blocks::FnLikeNode::from_node(node).unwrap_or_else(|| { + let fn_kind = node.fn_kind().unwrap_or_else(|| { bug!("asyncness: expected fn-like node but got `{:?}`", def_id); }); - fn_like.asyncness() + fn_kind.asyncness() } /// Don't call this directly: use ``tcx.conservative_is_privately_uninhabited`` instead. From aad48f71b309192882789f5d5187012bd060952f Mon Sep 17 00:00:00 2001 From: klensy Date: Sat, 9 Oct 2021 19:55:29 +0300 Subject: [PATCH 21/30] replace format!("") with String::new() use array explicitly instead of vec for const content (even if optimizer smart enought to remove allocation) --- compiler/rustc_typeck/src/check/upvar.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index caad28ff2b21f..2c03e0cfba9c1 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -1074,7 +1074,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>, ) -> (Vec, String) { let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) else { - return (Vec::new(), format!("")); + return (Vec::new(), String::new()); }; let mut need_migrations = Vec::new(); From f3fb821f3b5a762f8e053b56f1982aee18c82060 Mon Sep 17 00:00:00 2001 From: klensy Date: Sat, 9 Oct 2021 20:32:42 +0300 Subject: [PATCH 22/30] use array explicitly instead of vec for const content (even if optimizer smart enought to remove allocation) --- compiler/rustc_typeck/src/check/upvar.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 2c03e0cfba9c1..9c7b0b2cacb06 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -883,8 +883,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.get_diagnostic_item(sym::unwind_safe_trait), self.tcx.get_diagnostic_item(sym::ref_unwind_safe_trait), ]; - let auto_traits = - vec!["`Clone`", "`Sync`", "`Send`", "`Unpin`", "`UnwindSafe`", "`RefUnwindSafe`"]; + const AUTO_TRAITS: [&str; 6] = + ["`Clone`", "`Sync`", "`Send`", "`Unpin`", "`UnwindSafe`", "`RefUnwindSafe`"]; let root_var_min_capture_list = min_captures.and_then(|m| m.get(&var_hir_id))?; @@ -957,7 +957,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // by the root variable but not by the capture for (idx, _) in obligations_should_hold.iter().enumerate() { if !obligations_holds_for_capture[idx] && obligations_should_hold[idx] { - capture_problems.insert(auto_traits[idx]); + capture_problems.insert(AUTO_TRAITS[idx]); } } From 2fc780638e069155c87555da10ff234d1018fcaa Mon Sep 17 00:00:00 2001 From: woppopo Date: Wed, 20 Oct 2021 12:04:58 +0900 Subject: [PATCH 23/30] Make `From` impls of NonZero integer const. I also changed the feature gate added to `From` impls of Atomic integer to `const_num_from_num` from `const_convert`. --- library/core/src/convert/num.rs | 5 +++-- library/core/src/lib.rs | 1 + library/core/src/num/nonzero.rs | 2 +- library/core/src/sync/atomic.rs | 2 +- library/core/tests/nonzero.rs | 11 +++++++---- 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/library/core/src/convert/num.rs b/library/core/src/convert/num.rs index 75ef873abc965..2b6ea90bf0430 100644 --- a/library/core/src/convert/num.rs +++ b/library/core/src/convert/num.rs @@ -390,7 +390,8 @@ use crate::num::NonZeroUsize; macro_rules! nzint_impl_from { ($Small: ty, $Large: ty, #[$attr:meta], $doc: expr) => { #[$attr] - impl From<$Small> for $Large { + #[rustc_const_unstable(feature = "const_num_from_num", issue = "87852")] + impl const From<$Small> for $Large { // Rustdocs on the impl block show a "[+] show undocumented items" toggle. // Rustdocs on functions do not. #[doc = $doc] @@ -398,7 +399,7 @@ macro_rules! nzint_impl_from { fn from(small: $Small) -> Self { // SAFETY: input type guarantees the value is non-zero unsafe { - Self::new_unchecked(small.get().into()) + Self::new_unchecked(From::from(small.get())) } } } diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 13b80c05dbb30..58a170401e7c1 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -115,6 +115,7 @@ #![feature(const_likely)] #![feature(const_maybe_uninit_as_ptr)] #![feature(const_maybe_uninit_assume_init)] +#![feature(const_num_from_num)] #![feature(const_option)] #![feature(const_pin)] #![feature(const_replace)] diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index d28474c29232c..9b1a4de5d8037 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -82,7 +82,7 @@ macro_rules! nonzero_integers { } #[stable(feature = "from_nonzero", since = "1.31.0")] - #[rustc_const_unstable(feature = "const_convert", issue = "88674")] + #[rustc_const_unstable(feature = "const_num_from_num", issue = "87852")] impl const From<$Ty> for $Int { #[doc = concat!("Converts a `", stringify!($Ty), "` into an `", stringify!($Int), "`")] #[inline] diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 0915dcffe6ef0..1dd3b2d8e3c8d 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -1365,7 +1365,7 @@ macro_rules! atomic_int { } #[$stable_from] - #[rustc_const_unstable(feature = "const_convert", issue = "88674")] + #[rustc_const_unstable(feature = "const_num_from_num", issue = "87852")] impl const From<$int_type> for $atomic_type { #[doc = concat!("Converts an `", stringify!($int_type), "` into an `", stringify!($atomic_type), "`.")] #[inline] diff --git a/library/core/tests/nonzero.rs b/library/core/tests/nonzero.rs index 4817d86ca6eb0..a0ca919a851c3 100644 --- a/library/core/tests/nonzero.rs +++ b/library/core/tests/nonzero.rs @@ -204,9 +204,9 @@ fn nonzero_const() { // test that the methods of `NonZeroX>` are usable in a const context // Note: only tests NonZero8 - const NONZERO: NonZeroU8 = unsafe { NonZeroU8::new_unchecked(5) }; + const NONZERO_U8: NonZeroU8 = unsafe { NonZeroU8::new_unchecked(5) }; - const GET: u8 = NONZERO.get(); + const GET: u8 = NONZERO_U8.get(); assert_eq!(GET, 5); const ZERO: Option = NonZeroU8::new(0); @@ -215,8 +215,11 @@ fn nonzero_const() { const ONE: Option = NonZeroU8::new(1); assert!(ONE.is_some()); - const FROM_NONZERO: u8 = u8::from(NONZERO); - assert_eq!(FROM_NONZERO, 5); + const FROM_NONZERO_U8: u8 = u8::from(NONZERO_U8); + assert_eq!(FROM_NONZERO_U8, 5); + + const NONZERO_CONVERT: NonZeroU32 = NonZeroU32::from(NONZERO_U8); + assert_eq!(NONZERO_CONVERT.get(), 5); } #[test] From be30e602969cefee2785dc25f17c34ebc4f007b3 Mon Sep 17 00:00:00 2001 From: Ethan Brierley Date: Wed, 20 Oct 2021 10:21:06 +0100 Subject: [PATCH 24/30] remove duplicate subst --- compiler/rustc_trait_selection/src/traits/const_evaluatable.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 2cf7b6b1d9393..076597587f510 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -91,7 +91,6 @@ pub fn is_const_evaluatable<'cx, 'tcx>( ControlFlow::CONTINUE } Node::Cast(_, _, ty) => { - let ty = ty.subst(tcx, ct.substs); if ty.has_infer_types_or_consts() { failure_kind = FailureKind::MentionsInfer; } else if ty.definitely_has_param_types_or_consts(tcx) { From 457f5782f30b5ded5558d02f161ae7e71b5d4ad8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 19 Oct 2021 11:42:59 +0200 Subject: [PATCH 25/30] Add test for line-number setting --- .../docblock-code-block-line-number.goml | 22 +++++++++++++++++++ src/test/rustdoc-gui/src/test_docs/lib.rs | 1 + 2 files changed, 23 insertions(+) create mode 100644 src/test/rustdoc-gui/docblock-code-block-line-number.goml diff --git a/src/test/rustdoc-gui/docblock-code-block-line-number.goml b/src/test/rustdoc-gui/docblock-code-block-line-number.goml new file mode 100644 index 0000000000000..7e6607b55ea8b --- /dev/null +++ b/src/test/rustdoc-gui/docblock-code-block-line-number.goml @@ -0,0 +1,22 @@ +// Checks that the setting "line numbers" is working as expected. +goto: file://|DOC_PATH|/test_docs/fn.foo.html + +// We check that without this setting, there is no line number displayed. +assert-false: "pre.line-number" + +// We now set the setting to show the line numbers on code examples. +local-storage: {"rustdoc-line-numbers": "true" } +// We reload to make the line numbers appear. +reload: + +// We wait for them to be added into the DOM by the JS... +wait-for: "pre.line-number" +// If the test didn't fail, it means that it was found! +// Let's now check some CSS properties... +assert-css: ("pre.line-number", { + "margin": "0px", + "padding": "13px 8px", + "text-align": "right" +}) +// The first code block has two lines so let's check its `
` elements lists both of them.
+assert-text: ("pre.line-number", "1\n2")
diff --git a/src/test/rustdoc-gui/src/test_docs/lib.rs b/src/test/rustdoc-gui/src/test_docs/lib.rs
index 2a147e64d8bf2..76a36ccd6845c 100644
--- a/src/test/rustdoc-gui/src/test_docs/lib.rs
+++ b/src/test/rustdoc-gui/src/test_docs/lib.rs
@@ -12,6 +12,7 @@ use std::fmt;
 ///
 /// ```
 /// println!("nothing fancy");
+/// println!("but with two lines!");
 /// ```
 ///
 /// A failing to compile one:

From 0aa68a8db9dfffb2756279cc621b1b15a896423d Mon Sep 17 00:00:00 2001
From: Giacomo Stevanato 
Date: Wed, 20 Oct 2021 15:42:54 +0200
Subject: [PATCH 26/30] Prevent invalid values from existing in
 Vec::swap_remove

---
 library/alloc/src/vec/mod.rs | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 20a16869cb3f8..d52c78eedf3fa 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -1305,10 +1305,11 @@ impl Vec {
             // We replace self[index] with the last element. Note that if the
             // bounds check above succeeds there must be a last element (which
             // can be self[index] itself).
-            let last = ptr::read(self.as_ptr().add(len - 1));
-            let hole = self.as_mut_ptr().add(index);
+            let value = ptr::read(self.as_ptr().add(index));
+            let base_ptr = self.as_mut_ptr();
+            ptr::copy(base_ptr.add(len - 1), base_ptr.add(index), 1);
             self.set_len(len - 1);
-            ptr::replace(hole, last)
+            value
         }
     }
 

From 50dc319ef0adc304ce51317a6ed1bdc6cc369822 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez 
Date: Wed, 20 Oct 2021 15:44:16 +0200
Subject: [PATCH 27/30] Add test for duplicated sidebar entries for reexported
 macro

---
 src/test/rustdoc-gui/sidebar-macro-reexport.goml |  5 +++++
 src/test/rustdoc-gui/sidebar.goml                | 13 +++++++------
 src/test/rustdoc-gui/src/test_docs/lib.rs        |  7 +++++++
 3 files changed, 19 insertions(+), 6 deletions(-)
 create mode 100644 src/test/rustdoc-gui/sidebar-macro-reexport.goml

diff --git a/src/test/rustdoc-gui/sidebar-macro-reexport.goml b/src/test/rustdoc-gui/sidebar-macro-reexport.goml
new file mode 100644
index 0000000000000..a3a62fe54465e
--- /dev/null
+++ b/src/test/rustdoc-gui/sidebar-macro-reexport.goml
@@ -0,0 +1,5 @@
+// This test ensures that the reexport of a macro doesn't make the original macro
+// displayed twice in the sidebar.
+goto: file://|DOC_PATH|/test_docs/macro.repro.html
+wait-for: ".sidebar-elems .macro .macro"
+assert-count: ("//*[@class='sidebar-elems']//*[@class='block macro']//a[text()='repro']", 1)
diff --git a/src/test/rustdoc-gui/sidebar.goml b/src/test/rustdoc-gui/sidebar.goml
index c8ebb8c56f535..62dc76a40bcf5 100644
--- a/src/test/rustdoc-gui/sidebar.goml
+++ b/src/test/rustdoc-gui/sidebar.goml
@@ -7,12 +7,13 @@ assert-text: (".sidebar-elems > #all-types", "See all test_docs's items")
 assert-text: (".sidebar-elems > .crate > ul > li > a.current", "test_docs")
 // And we're also supposed to have the list of items in the current module.
 assert-text: (".sidebar-elems > .items > ul > li:nth-child(1)", "Modules")
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(2)", "Structs")
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(3)", "Enums")
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(4)", "Traits")
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(5)", "Functions")
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(6)", "Type Definitions")
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(7)", "Keywords")
+assert-text: (".sidebar-elems > .items > ul > li:nth-child(2)", "Macros")
+assert-text: (".sidebar-elems > .items > ul > li:nth-child(3)", "Structs")
+assert-text: (".sidebar-elems > .items > ul > li:nth-child(4)", "Enums")
+assert-text: (".sidebar-elems > .items > ul > li:nth-child(5)", "Traits")
+assert-text: (".sidebar-elems > .items > ul > li:nth-child(6)", "Functions")
+assert-text: (".sidebar-elems > .items > ul > li:nth-child(7)", "Type Definitions")
+assert-text: (".sidebar-elems > .items > ul > li:nth-child(8)", "Keywords")
 assert-text: ("#structs + .item-table .item-left > a", "Foo")
 click: "#structs + .item-table .item-left > a"
 
diff --git a/src/test/rustdoc-gui/src/test_docs/lib.rs b/src/test/rustdoc-gui/src/test_docs/lib.rs
index 2a147e64d8bf2..315ccb6a2b9f9 100644
--- a/src/test/rustdoc-gui/src/test_docs/lib.rs
+++ b/src/test/rustdoc-gui/src/test_docs/lib.rs
@@ -123,3 +123,10 @@ pub mod huge_amount_of_consts {
 
 /// Very long code text `hereIgoWithLongTextBecauseWhyNotAndWhyWouldntI`.
 pub mod long_code_block {}
+
+#[macro_export]
+macro_rules! repro {
+    () => {};
+}
+
+pub use crate::repro as repro2;

From 69ca324a53c35bb9cd77c5635a9ecc4f201eaa1c Mon Sep 17 00:00:00 2001
From: Guillaume Gomez 
Date: Wed, 20 Oct 2021 15:57:44 +0200
Subject: [PATCH 28/30] Add test to ensure that the missing_doc_code_examples
 is not triggered on foreign trait implementations

---
 src/test/rustdoc-ui/doc-without-codeblock.rs     | 9 +++++++++
 src/test/rustdoc-ui/doc-without-codeblock.stderr | 2 +-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/src/test/rustdoc-ui/doc-without-codeblock.rs b/src/test/rustdoc-ui/doc-without-codeblock.rs
index 6812a454157b9..315fca195873a 100644
--- a/src/test/rustdoc-ui/doc-without-codeblock.rs
+++ b/src/test/rustdoc-ui/doc-without-codeblock.rs
@@ -11,3 +11,12 @@ pub mod foo {
     //~^ ERROR missing code example in this documentation
     pub fn bar() {}
 }
+
+// This impl is here to ensure the lint isn't emitted for foreign traits implementations.
+impl std::ops::Neg for Foo {
+    type Output = Self;
+
+    fn neg(self) -> Self::Output {
+        Self
+    }
+}
diff --git a/src/test/rustdoc-ui/doc-without-codeblock.stderr b/src/test/rustdoc-ui/doc-without-codeblock.stderr
index aac537e9783cd..1c138044165f2 100644
--- a/src/test/rustdoc-ui/doc-without-codeblock.stderr
+++ b/src/test/rustdoc-ui/doc-without-codeblock.stderr
@@ -6,7 +6,7 @@ LL | |
 LL | | /// Some docs.
 LL | |
 ...  |
-LL | |     pub fn bar() {}
+LL | |     }
 LL | | }
    | |_^
    |

From 86b3dd9e0abb0126f0718a8cade40d14b63fcb46 Mon Sep 17 00:00:00 2001
From: Nathan Stocks 
Date: Sun, 26 Sep 2021 15:38:51 -0600
Subject: [PATCH 29/30] stabilize CString::from_vec_with_nul[_unchecked]

---
 library/std/src/ffi/c_str.rs | 20 ++++++++------------
 library/std/src/ffi/mod.rs   |  2 +-
 2 files changed, 9 insertions(+), 13 deletions(-)

diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs
index 6827d3a8d2448..cb09717bde577 100644
--- a/library/std/src/ffi/c_str.rs
+++ b/library/std/src/ffi/c_str.rs
@@ -251,13 +251,12 @@ pub struct FromBytesWithNulError {
 /// # Examples
 ///
 /// ```
-/// #![feature(cstring_from_vec_with_nul)]
 /// use std::ffi::{CString, FromVecWithNulError};
 ///
 /// let _: FromVecWithNulError = CString::from_vec_with_nul(b"f\0oo".to_vec()).unwrap_err();
 /// ```
 #[derive(Clone, PartialEq, Eq, Debug)]
-#[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")]
+#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
 pub struct FromVecWithNulError {
     error_kind: FromBytesWithNulErrorKind,
     bytes: Vec,
@@ -278,7 +277,7 @@ impl FromBytesWithNulError {
     }
 }
 
-#[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")]
+#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
 impl FromVecWithNulError {
     /// Returns a slice of [`u8`]s bytes that were attempted to convert to a [`CString`].
     ///
@@ -287,7 +286,6 @@ impl FromVecWithNulError {
     /// Basic usage:
     ///
     /// ```
-    /// #![feature(cstring_from_vec_with_nul)]
     /// use std::ffi::CString;
     ///
     /// // Some invalid bytes in a vector
@@ -298,6 +296,7 @@ impl FromVecWithNulError {
     /// assert_eq!(&bytes[..], value.unwrap_err().as_bytes());
     /// ```
     #[must_use]
+    #[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
     pub fn as_bytes(&self) -> &[u8] {
         &self.bytes[..]
     }
@@ -313,7 +312,6 @@ impl FromVecWithNulError {
     /// Basic usage:
     ///
     /// ```
-    /// #![feature(cstring_from_vec_with_nul)]
     /// use std::ffi::CString;
     ///
     /// // Some invalid bytes in a vector
@@ -324,6 +322,7 @@ impl FromVecWithNulError {
     /// assert_eq!(bytes, value.unwrap_err().into_bytes());
     /// ```
     #[must_use = "`self` will be dropped if the result is not used"]
+    #[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
     pub fn into_bytes(self) -> Vec {
         self.bytes
     }
@@ -704,7 +703,6 @@ impl CString {
     /// # Example
     ///
     /// ```
-    /// #![feature(cstring_from_vec_with_nul)]
     /// use std::ffi::CString;
     /// assert_eq!(
     ///     unsafe { CString::from_vec_with_nul_unchecked(b"abc\0".to_vec()) },
@@ -712,7 +710,7 @@ impl CString {
     /// );
     /// ```
     #[must_use]
-    #[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")]
+    #[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
     pub unsafe fn from_vec_with_nul_unchecked(v: Vec) -> Self {
         Self { inner: v.into_boxed_slice() }
     }
@@ -733,7 +731,6 @@ impl CString {
     /// when called without the ending nul byte.
     ///
     /// ```
-    /// #![feature(cstring_from_vec_with_nul)]
     /// use std::ffi::CString;
     /// assert_eq!(
     ///     CString::from_vec_with_nul(b"abc\0".to_vec())
@@ -745,14 +742,13 @@ impl CString {
     /// An incorrectly formatted [`Vec`] will produce an error.
     ///
     /// ```
-    /// #![feature(cstring_from_vec_with_nul)]
     /// use std::ffi::{CString, FromVecWithNulError};
     /// // Interior nul byte
     /// let _: FromVecWithNulError = CString::from_vec_with_nul(b"a\0bc".to_vec()).unwrap_err();
     /// // No nul byte
     /// let _: FromVecWithNulError = CString::from_vec_with_nul(b"abc".to_vec()).unwrap_err();
     /// ```
-    #[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")]
+    #[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
     pub fn from_vec_with_nul(v: Vec) -> Result {
         let nul_pos = memchr::memchr(0, &v);
         match nul_pos {
@@ -1084,10 +1080,10 @@ impl fmt::Display for FromBytesWithNulError {
     }
 }
 
-#[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")]
+#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
 impl Error for FromVecWithNulError {}
 
-#[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")]
+#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
 impl fmt::Display for FromVecWithNulError {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self.error_kind {
diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs
index 82a76aa73c583..b72b8031fbdce 100644
--- a/library/std/src/ffi/mod.rs
+++ b/library/std/src/ffi/mod.rs
@@ -145,7 +145,7 @@
 
 #[stable(feature = "cstr_from_bytes", since = "1.10.0")]
 pub use self::c_str::FromBytesWithNulError;
-#[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")]
+#[stable(feature = "cstring_from_vec_with_nul", since = "1.57.0")]
 pub use self::c_str::FromVecWithNulError;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::c_str::{CStr, CString, IntoStringError, NulError};

From 39af41ed65d7b5c3f9e4d6405b332642fbb431e6 Mon Sep 17 00:00:00 2001
From: Nathan Stocks 
Date: Wed, 20 Oct 2021 15:36:55 -0600
Subject: [PATCH 30/30] fix 'since' version number

Co-authored-by: Yuki Okushi 
---
 library/std/src/ffi/mod.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs
index b72b8031fbdce..7f3bb836754ed 100644
--- a/library/std/src/ffi/mod.rs
+++ b/library/std/src/ffi/mod.rs
@@ -145,7 +145,7 @@
 
 #[stable(feature = "cstr_from_bytes", since = "1.10.0")]
 pub use self::c_str::FromBytesWithNulError;
-#[stable(feature = "cstring_from_vec_with_nul", since = "1.57.0")]
+#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
 pub use self::c_str::FromVecWithNulError;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::c_str::{CStr, CString, IntoStringError, NulError};