From 230393993ffc255d3f20d98400c8a376bd51d1c0 Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Thu, 9 Jul 2020 19:03:15 -0700 Subject: [PATCH 01/16] Don't visit foreign function bodies when lowering ast to hir Previously the existence of bodies inside a foreign function block would cause a panic in the hir `NodeCollector` during its collection of crate bodies to compute a crate hash: https://github.com/rust-lang/rust/blob/e59b08e62ea691916d2f063cac5aab4634128022/src/librustc_middle/hir/map/collector.rs#L154-L158 The collector walks the hir tree and creates a map of hir nodes, then attaching bodies in the crate to their owner in the map. For a code like ```rust extern "C" { fn f() { fn g() {} } } ``` The crate bodies include the body of the function `g`. But foreign functions cannot have bodies, and while the parser AST permits a foreign function to have a body, the hir doesn't. This means that the body of `f` is not present in the hir, and so neither is `g`. So when the `NodeCollector` finishes the walking the hir, it has no record of `g`, cannot find an owner for the body of `g` it sees in the crate bodies, and blows up. Why do the crate bodies include the body of `g`? The AST walker has a need a for walking function bodies, and FFIs share the same AST node as functions in other contexts. There are at least two options to fix this: - Don't unwrap the map entry for an hir node in the `NodeCollector` - Modifier the ast->hir lowering visitor to ignore foreign function blocks I don't think the first is preferrable, since we want to know when we can't find a body for an hir node that we thought had one (dropping this information may lead to an invalid hash). So this commit implements the second option. Closes #74120 --- src/librustc_ast_lowering/item.rs | 40 ++++++++++++++++++- ...ssue-74120-lowering-of-ffi-block-bodies.rs | 11 +++++ ...-74120-lowering-of-ffi-block-bodies.stderr | 19 +++++++++ 3 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/foreign/issue-74120-lowering-of-ffi-block-bodies.rs create mode 100644 src/test/ui/foreign/issue-74120-lowering-of-ffi-block-bodies.stderr diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs index 00665c4cafb6b..b2db9fe1d2666 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/src/librustc_ast_lowering/item.rs @@ -6,7 +6,8 @@ use rustc_ast::ast::*; use rustc_ast::attr; use rustc_ast::node_id::NodeMap; use rustc_ast::ptr::P; -use rustc_ast::visit::{self, AssocCtxt, Visitor}; +use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; +use rustc_ast::walk_list; use rustc_data_structures::fx::FxHashSet; use rustc_errors::struct_span_err; use rustc_hir as hir; @@ -76,6 +77,43 @@ impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> { } } + // Forked from the original method because we don't want to descend into foreign function + // blocks. Such blocks are semantically invalid and the hir does not preserve them, so lowering + // items contained in them may be unexpected by later passes. + fn visit_foreign_item(&mut self, item: &'a ForeignItem) { + let Item { id: _, span: _, ident, ref vis, ref attrs, ref kind, tokens: _ } = *item; + self.visit_vis(vis); + self.visit_ident(ident); + walk_list!(self, visit_attribute, attrs); + match kind { + ForeignItemKind::Static(ty, _, expr) => { + self.visit_ty(ty); + walk_list!(self, visit_expr, expr); + } + ForeignItemKind::Fn(_, sig, generics, body) => { + self.visit_generics(generics); + let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, body.as_deref()); + match kind { + FnKind::Fn(_, _, sig, _, _) => { + self.visit_fn_header(&sig.header); + visit::walk_fn_decl(self, &sig.decl); + } + FnKind::Closure(decl, _) => { + visit::walk_fn_decl(self, decl); + } + } + } + ForeignItemKind::TyAlias(_, generics, bounds, ty) => { + self.visit_generics(generics); + walk_list!(self, visit_param_bound, bounds); + walk_list!(self, visit_ty, ty); + } + ForeignItemKind::MacCall(mac) => { + self.visit_mac(mac); + } + } + } + fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) { self.lctx.with_hir_id_owner(item.id, |lctx| match ctxt { AssocCtxt::Trait => { diff --git a/src/test/ui/foreign/issue-74120-lowering-of-ffi-block-bodies.rs b/src/test/ui/foreign/issue-74120-lowering-of-ffi-block-bodies.rs new file mode 100644 index 0000000000000..a84065e021868 --- /dev/null +++ b/src/test/ui/foreign/issue-74120-lowering-of-ffi-block-bodies.rs @@ -0,0 +1,11 @@ +// Previously this ICE'd because `fn g()` would be lowered, but the block associated with `fn f()` +// wasn't. + +// compile-flags: --crate-type=lib + +extern "C" { + fn f() { + //~^ incorrect function inside `extern` block + fn g() {} + } +} diff --git a/src/test/ui/foreign/issue-74120-lowering-of-ffi-block-bodies.stderr b/src/test/ui/foreign/issue-74120-lowering-of-ffi-block-bodies.stderr new file mode 100644 index 0000000000000..d4a9ca3e7c66e --- /dev/null +++ b/src/test/ui/foreign/issue-74120-lowering-of-ffi-block-bodies.stderr @@ -0,0 +1,19 @@ +error: incorrect function inside `extern` block + --> $DIR/issue-74120-lowering-of-ffi-block-bodies.rs:7:8 + | +LL | extern "C" { + | ---------- `extern` blocks define existing foreign functions and functions inside of them cannot have a body +LL | fn f() { + | ________^___- + | | | + | | cannot have a body +LL | | +LL | | fn g() {} +LL | | } + | |_____- help: remove the invalid body: `;` + | + = help: you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: aborting due to previous error + From ab4275cddc3749caf9f20373eb812e6f09bd3309 Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Thu, 9 Jul 2020 22:32:49 -0700 Subject: [PATCH 02/16] fixup! Don't visit foreign function bodies when lowering ast to hir --- src/librustc_ast_lowering/item.rs | 43 +++++++++---------------------- 1 file changed, 12 insertions(+), 31 deletions(-) diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs index b2db9fe1d2666..21f1137c46e23 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/src/librustc_ast_lowering/item.rs @@ -77,39 +77,20 @@ impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> { } } - // Forked from the original method because we don't want to descend into foreign function - // blocks. Such blocks are semantically invalid and the hir does not preserve them, so lowering - // items contained in them may be unexpected by later passes. - fn visit_foreign_item(&mut self, item: &'a ForeignItem) { - let Item { id: _, span: _, ident, ref vis, ref attrs, ref kind, tokens: _ } = *item; - self.visit_vis(vis); - self.visit_ident(ident); - walk_list!(self, visit_attribute, attrs); - match kind { - ForeignItemKind::Static(ty, _, expr) => { - self.visit_ty(ty); - walk_list!(self, visit_expr, expr); + fn visit_fn(&mut self, fk: FnKind<'a>, _: Span, _: NodeId) { + match fk { + FnKind::Fn(FnCtxt::Foreign, _, sig, _, _) => { + self.visit_fn_header(&sig.header); + visit::walk_fn_decl(self, &sig.decl); } - ForeignItemKind::Fn(_, sig, generics, body) => { - self.visit_generics(generics); - let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, body.as_deref()); - match kind { - FnKind::Fn(_, _, sig, _, _) => { - self.visit_fn_header(&sig.header); - visit::walk_fn_decl(self, &sig.decl); - } - FnKind::Closure(decl, _) => { - visit::walk_fn_decl(self, decl); - } - } - } - ForeignItemKind::TyAlias(_, generics, bounds, ty) => { - self.visit_generics(generics); - walk_list!(self, visit_param_bound, bounds); - walk_list!(self, visit_ty, ty); + FnKind::Fn(_, _, sig, _, body) => { + self.visit_fn_header(&sig.header); + visit::walk_fn_decl(self, &sig.decl); + walk_list!(self, visit_block, body); } - ForeignItemKind::MacCall(mac) => { - self.visit_mac(mac); + FnKind::Closure(decl, body) => { + visit::walk_fn_decl(self, decl); + self.visit_expr(body); } } } From 68aca3baf6566cea3ad2f83a07726c9ee017b9fc Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Tue, 14 Jul 2020 18:13:51 -0700 Subject: [PATCH 03/16] fixup! fixup! Don't visit foreign function bodies when lowering ast to hir --- src/librustc_ast_lowering/item.rs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs index 21f1137c46e23..306b599e64b45 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/src/librustc_ast_lowering/item.rs @@ -77,21 +77,13 @@ impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> { } } - fn visit_fn(&mut self, fk: FnKind<'a>, _: Span, _: NodeId) { + fn visit_fn(&mut self, fk: FnKind<'a>, sp: Span, _: NodeId) { match fk { FnKind::Fn(FnCtxt::Foreign, _, sig, _, _) => { self.visit_fn_header(&sig.header); visit::walk_fn_decl(self, &sig.decl); } - FnKind::Fn(_, _, sig, _, body) => { - self.visit_fn_header(&sig.header); - visit::walk_fn_decl(self, &sig.decl); - walk_list!(self, visit_block, body); - } - FnKind::Closure(decl, body) => { - visit::walk_fn_decl(self, decl); - self.visit_expr(body); - } + _ => visit::walk_fn(self, fk, sp), } } From 0c64d32a4a439f373f388f7925048f6f349bd5b2 Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Tue, 14 Jul 2020 18:21:53 -0700 Subject: [PATCH 04/16] fixup! Don't visit foreign function bodies when lowering ast to hir --- src/librustc_ast_lowering/item.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs index 306b599e64b45..29021749365ad 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/src/librustc_ast_lowering/item.rs @@ -7,7 +7,6 @@ use rustc_ast::attr; use rustc_ast::node_id::NodeMap; use rustc_ast::ptr::P; use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; -use rustc_ast::walk_list; use rustc_data_structures::fx::FxHashSet; use rustc_errors::struct_span_err; use rustc_hir as hir; From d442bf7162647743f941977a5154676322a5614b Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Wed, 15 Jul 2020 17:22:41 -0700 Subject: [PATCH 05/16] fixup! Don't visit foreign function bodies when lowering ast to hir --- src/librustc_ast_lowering/item.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs index 29021749365ad..ca3cf11b1a3fe 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/src/librustc_ast_lowering/item.rs @@ -81,6 +81,8 @@ impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> { FnKind::Fn(FnCtxt::Foreign, _, sig, _, _) => { self.visit_fn_header(&sig.header); visit::walk_fn_decl(self, &sig.decl); + // Don't visit the foreign function body even if it has one, since lowering the + // body would have no meaning and will have already been caught as a parse error. } _ => visit::walk_fn(self, fk, sp), } From 50ead683e9c5dbf0cd22325875e9623b5e913486 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Wed, 5 Aug 2020 13:32:59 +0900 Subject: [PATCH 06/16] Add regression test for issue-66768 --- src/test/ui/issues/issue-66768.rs | 205 ++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 src/test/ui/issues/issue-66768.rs diff --git a/src/test/ui/issues/issue-66768.rs b/src/test/ui/issues/issue-66768.rs new file mode 100644 index 0000000000000..ce42c8b01cc32 --- /dev/null +++ b/src/test/ui/issues/issue-66768.rs @@ -0,0 +1,205 @@ +// Regression test for #66768. +// check-pass +#![allow(dead_code)] +//-^ "dead code" is needed to reproduce the issue. + +use std::marker::PhantomData; +use std::ops::{Add, Mul}; + +fn problematic_function(material_surface_element: Edge2dElement) +where + DefaultAllocator: FiniteElementAllocator, +{ + let _: Point2 = material_surface_element.map_reference_coords().into(); +} + +impl ArrayLength for UTerm { + type ArrayType = (); +} +impl> ArrayLength for UInt { + type ArrayType = GenericArrayImplEven; +} +impl> ArrayLength for UInt { + type ArrayType = GenericArrayImplOdd; +} +impl Add for UTerm { + type Output = U; + fn add(self, _: U) -> Self::Output { + unimplemented!() + } +} +impl Add> for UInt +where + Ul: Add, +{ + type Output = UInt, B1>; + fn add(self, _: UInt) -> Self::Output { + unimplemented!() + } +} +impl Mul for UTerm { + type Output = UTerm; + fn mul(self, _: U) -> Self { + unimplemented!() + } +} +impl Mul> for UInt +where + Ul: Mul>, +{ + type Output = UInt>, B0>; + fn mul(self, _: UInt) -> Self::Output { + unimplemented!() + } +} +impl Mul> for UInt +where + Ul: Mul>, + UInt>, B0>: Add>, +{ + type Output = Sum>, B0>, UInt>; + fn mul(self, _: UInt) -> Self::Output { + unimplemented!() + } +} +impl Allocator for DefaultAllocator +where + R: DimName, + C: DimName, + R::Value: Mul, + Prod: ArrayLength, +{ + type Buffer = ArrayStorage; + fn allocate_uninitialized(_: R, _: C) -> Self::Buffer { + unimplemented!() + } + fn allocate_from_iterator(_: R, _: C, _: I) -> Self::Buffer { + unimplemented!() + } +} +impl Allocator for DefaultAllocator { + type Buffer = VecStorage; + fn allocate_uninitialized(_: Dynamic, _: C) -> Self::Buffer { + unimplemented!() + } + fn allocate_from_iterator(_: Dynamic, _: C, _: I) -> Self::Buffer { + unimplemented!() + } +} +impl DimName for DimU1 { + type Value = U1; + fn name() -> Self { + unimplemented!() + } +} +impl DimName for DimU2 { + type Value = U2; + fn name() -> Self { + unimplemented!() + } +} +impl From> for Point +where + DefaultAllocator: Allocator, +{ + fn from(_: VectorN) -> Self { + unimplemented!() + } +} +impl FiniteElementAllocator for DefaultAllocator where + DefaultAllocator: Allocator + Allocator +{ +} +impl ReferenceFiniteElement for Edge2dElement { + type NodalDim = DimU1; +} +impl FiniteElement for Edge2dElement { + fn map_reference_coords(&self) -> Vector2 { + unimplemented!() + } +} + +type Owned = >::Buffer; +type MatrixMN = Matrix>; +type VectorN = MatrixMN; +type Vector2 = VectorN; +type Point2 = Point; +type U1 = UInt; +type U2 = UInt, B0>; +type Sum = >::Output; +type Prod = >::Output; + +struct GenericArray> { + _data: U::ArrayType, +} +struct GenericArrayImplEven { + _parent2: U, + _marker: T, +} +struct GenericArrayImplOdd { + _parent2: U, + _data: T, +} +struct B0; +struct B1; +struct UTerm; +struct UInt { + _marker: PhantomData<(U, B)>, +} +struct DefaultAllocator; +struct Dynamic; +struct DimU1; +struct DimU2; +struct Matrix { + _data: S, + _phantoms: PhantomData<(N, R, C)>, +} +struct ArrayStorage +where + R: DimName, + C: DimName, + R::Value: Mul, + Prod: ArrayLength, +{ + _data: GenericArray>, +} +struct VecStorage { + _data: N, + _nrows: R, + _ncols: C, +} +struct Point +where + DefaultAllocator: Allocator, +{ + _coords: VectorN, +} +struct Edge2dElement; + +trait ArrayLength { + type ArrayType; +} +trait Allocator { + type Buffer; + fn allocate_uninitialized(nrows: R, ncols: C) -> Self::Buffer; + fn allocate_from_iterator(nrows: R, ncols: C, iter: I) -> Self::Buffer; +} +trait DimName { + type Value; + fn name() -> Self; +} +trait FiniteElementAllocator: + Allocator + Allocator +{ +} +trait ReferenceFiniteElement { + type NodalDim; +} +trait FiniteElement: ReferenceFiniteElement +where + DefaultAllocator: FiniteElementAllocator, +{ + fn map_reference_coords(&self) -> VectorN; +} + +fn main() {} From 0d0546a2364641d8ca9c840b70b437be038b8c9b Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 6 Aug 2020 11:34:13 -0400 Subject: [PATCH 07/16] Add #[track_caller] to `Session::delay_span_bug` This forwards the caller span to `Handler::delay_span_bug` --- src/librustc_session/session.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc_session/session.rs b/src/librustc_session/session.rs index e9077f4085909..cf94ff8b929e3 100644 --- a/src/librustc_session/session.rs +++ b/src/librustc_session/session.rs @@ -432,6 +432,7 @@ impl Session { } } /// Delay a span_bug() call until abort_if_errors() + #[track_caller] pub fn delay_span_bug>(&self, sp: S, msg: &str) { self.diagnostic().delay_span_bug(sp, msg) } From 3c2eb18b9ba287284f5f08f8c256154354c55c64 Mon Sep 17 00:00:00 2001 From: Denis Vasilik Date: Tue, 11 Aug 2020 22:16:31 +0200 Subject: [PATCH 08/16] Use intra-doc links --- library/core/src/hint.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 3dc0ee2b55530..9ee50a9051013 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -24,7 +24,7 @@ use crate::intrinsics; /// Otherwise, consider using the [`unreachable!`] macro, which does not allow /// optimizations but will panic when executed. /// -/// [`unreachable!`]: ../macro.unreachable.html +/// [`unreachable!`]: unreachable /// /// # Example /// @@ -61,7 +61,7 @@ pub const unsafe fn unreachable_unchecked() -> ! { /// **Note**: On platforms that do not support receiving spin-loop hints this function does not /// do anything at all. /// -/// [`core::sync::atomic::spin_loop_hint`]: ../sync/atomic/fn.spin_loop_hint.html +/// [`core::sync::atomic::spin_loop_hint`]: crate::sync::atomic::spin_loop_hint #[inline] #[unstable(feature = "renamed_spin_loop", issue = "55002")] pub fn spin_loop() { @@ -99,7 +99,7 @@ pub fn spin_loop() { /// An identity function that *__hints__* to the compiler to be maximally pessimistic about what /// `black_box` could do. /// -/// [`std::convert::identity`]: https://doc.rust-lang.org/core/convert/fn.identity.html +/// [`std::convert::identity`]: crate::convert::identity /// /// Unlike [`std::convert::identity`], a Rust compiler is encouraged to assume that `black_box` can /// use `x` in any possible valid way that Rust code is allowed to without introducing undefined From c4923419c2570e2013e7b946f1a47001f8f9289a Mon Sep 17 00:00:00 2001 From: Denis Vasilik Date: Tue, 11 Aug 2020 23:54:51 +0200 Subject: [PATCH 09/16] Revert broken link --- library/core/src/hint.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 9ee50a9051013..6a14caebed017 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -99,7 +99,7 @@ pub fn spin_loop() { /// An identity function that *__hints__* to the compiler to be maximally pessimistic about what /// `black_box` could do. /// -/// [`std::convert::identity`]: crate::convert::identity +/// [`std::convert::identity`]: https://doc.rust-lang.org/core/convert/fn.identity.html /// /// Unlike [`std::convert::identity`], a Rust compiler is encouraged to assume that `black_box` can /// use `x` in any possible valid way that Rust code is allowed to without introducing undefined From 4c5896fbeb1a60d1e100c28fbe6cfe81ee2311fa Mon Sep 17 00:00:00 2001 From: Denis Vasilik Date: Wed, 12 Aug 2020 08:28:55 +0200 Subject: [PATCH 10/16] Remove intra-doc link as it resolves without reference link Co-authored-by: Joshua Nelson --- library/core/src/hint.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 6a14caebed017..461b4c79a1d1c 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -24,7 +24,6 @@ use crate::intrinsics; /// Otherwise, consider using the [`unreachable!`] macro, which does not allow /// optimizations but will panic when executed. /// -/// [`unreachable!`]: unreachable /// /// # Example /// From 7aac3e0400d29c79623e7fefb43f17b6a765a326 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 13 Aug 2020 14:41:04 +0200 Subject: [PATCH 11/16] pin docs: add some forward references --- library/core/src/pin.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 9bcacd8ddcf77..960cccc0fb211 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -6,9 +6,12 @@ //! as moving an object with pointers to itself will invalidate them, which could cause undefined //! behavior. //! -//! A [`Pin

`] ensures that the pointee of any pointer type `P` has a stable location in memory, -//! meaning it cannot be moved elsewhere and its memory cannot be deallocated -//! until it gets dropped. We say that the pointee is "pinned". +//! At a high level, a [`Pin

`] ensures that the pointee of any pointer type +//! `P` has a stable location in memory, meaning it cannot be moved elsewhere +//! and its memory cannot be deallocated until it gets dropped. We say that the +//! pointee is "pinned". Things get more subtle when discussing types that +//! combine pinned with non-pinned data; [see below](#projections-and-structural-pinning) +//! for more details. //! //! By default, all types in Rust are movable. Rust allows passing all types by-value, //! and common smart-pointer types such as [`Box`] and `&mut T` allow replacing and @@ -61,6 +64,10 @@ //! //! # Example: self-referential struct //! +//! Before we go into more details to explain the guarantees and choices +//! associated with `Pin`, we discuss some examples for how it might be used. +//! Feel free to [skip to where the theoretical discussion continues](#drop-guarantee). +//! //! ```rust //! use std::pin::Pin; //! use std::marker::PhantomPinned; From 8de63eb964ffd465f826d487421ca34606bbfdbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Sat, 15 Aug 2020 00:00:00 +0000 Subject: [PATCH 12/16] Bump minor version of emsdk to 1.38.47 Release Notes: ``` v1.38.47: 10/02/2019 -------------------- - Add support for FETCH API in WASM backend. This doesn't support FETCH in the main thread (`USE_FETCH_WORKER=0` is enforced). #9490 - Redefine errno values to be consistent with wasi. This will let us avoid needing to convert the values back and forth as we use more wasi APIs. This is an ABI change, which should not be noticeable from user code unless you use errno defines (like EAGAIN) *and* keep around binaries compiled with an older version that you link against. In that case, you should rebuild them. See #9545. - Removed build option `-s ONLY_MY_CODE` as we now have much better solutions for that, like building to a wasm object file or using `STANDALONE_WASM` etc. (see https://github.com/emscripten-core/emscripten/wiki/WebAssembly-Standalone). - Emscripten now supports the config file (.emscripten) being placed in the emscripten directory rather that the current user's home directory. See #9543 ``` --- src/ci/docker/scripts/emscripten.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ci/docker/scripts/emscripten.sh b/src/ci/docker/scripts/emscripten.sh index 1be80741594cc..9f6a7f2e5db44 100644 --- a/src/ci/docker/scripts/emscripten.sh +++ b/src/ci/docker/scripts/emscripten.sh @@ -19,5 +19,5 @@ exit 1 git clone https://github.com/emscripten-core/emsdk.git /emsdk-portable cd /emsdk-portable -hide_output ./emsdk install 1.38.46-upstream -./emsdk activate 1.38.46-upstream +hide_output ./emsdk install 1.38.47-upstream +./emsdk activate 1.38.47-upstream From 0a96e089bade29e1b19d5a5aacd97fbdfff222fd Mon Sep 17 00:00:00 2001 From: Prabakaran Kumaresshan <4676330+nixphix@users.noreply.github.com> Date: Sun, 16 Aug 2020 22:28:45 +0530 Subject: [PATCH 13/16] Switch to intra-doc links in /sys/windows/ext/{ffi,fs,process}.rs --- library/std/src/sys/windows/ext/ffi.rs | 27 +++++----------------- library/std/src/sys/windows/ext/fs.rs | 11 ++------- library/std/src/sys/windows/ext/process.rs | 4 ---- 3 files changed, 8 insertions(+), 34 deletions(-) diff --git a/library/std/src/sys/windows/ext/ffi.rs b/library/std/src/sys/windows/ext/ffi.rs index 6e78119383f43..1df2a0df143b3 100644 --- a/library/std/src/sys/windows/ext/ffi.rs +++ b/library/std/src/sys/windows/ext/ffi.rs @@ -30,13 +30,13 @@ //! [`OsString`] is the Rust wrapper for owned strings in the //! preferred representation of the operating system. On Windows, //! this struct gets augmented with an implementation of the -//! [`OsStringExt`] trait, which has a [`from_wide`] method. This +//! [`OsStringExt`] trait, which has a [`OsStringExt::from_wide`] method. This //! lets you create an [`OsString`] from a `&[u16]` slice; presumably //! you get such a slice out of a `WCHAR` Windows API. //! //! Similarly, [`OsStr`] is the Rust wrapper for borrowed strings from //! preferred representation of the operating system. On Windows, the -//! [`OsStrExt`] trait provides the [`encode_wide`] method, which +//! [`OsStrExt`] trait provides the [`OsStrExt::encode_wide`] method, which //! outputs an [`EncodeWide`] iterator. You can [`collect`] this //! iterator, for example, to obtain a `Vec`; you can later get a //! pointer to this vector's contents and feed it to Windows APIs. @@ -47,15 +47,8 @@ //! ill-formed UTF-16. //! //! [ill-formed-utf-16]: https://simonsapin.github.io/wtf-8/#ill-formed-utf-16 -//! [`OsString`]: ../../../ffi/struct.OsString.html -//! [`OsStr`]: ../../../ffi/struct.OsStr.html -//! [`OsStringExt`]: trait.OsStringExt.html -//! [`OsStrExt`]: trait.OsStrExt.html -//! [`EncodeWide`]: struct.EncodeWide.html -//! [`from_wide`]: trait.OsStringExt.html#tymethod.from_wide -//! [`encode_wide`]: trait.OsStrExt.html#tymethod.encode_wide -//! [`collect`]: ../../../iter/trait.Iterator.html#method.collect -//! [U+FFFD]: ../../../char/constant.REPLACEMENT_CHARACTER.html +//! [`collect`]: crate::iter::Iterator::collect +//! [U+FFFD]: crate::char::REPLACEMENT_CHARACTER #![stable(feature = "rust1", since = "1.0.0")] @@ -68,14 +61,12 @@ use crate::sys_common::{AsInner, FromInner}; pub use crate::sys_common::wtf8::EncodeWide; /// Windows-specific extensions to [`OsString`]. -/// -/// [`OsString`]: ../../../../std/ffi/struct.OsString.html #[stable(feature = "rust1", since = "1.0.0")] pub trait OsStringExt { /// Creates an `OsString` from a potentially ill-formed UTF-16 slice of /// 16-bit code units. /// - /// This is lossless: calling [`encode_wide`] on the resulting string + /// This is lossless: calling [`OsStrExt::encode_wide`] on the resulting string /// will always return the original code units. /// /// # Examples @@ -89,8 +80,6 @@ pub trait OsStringExt { /// /// let string = OsString::from_wide(&source[..]); /// ``` - /// - /// [`encode_wide`]: ./trait.OsStrExt.html#tymethod.encode_wide #[stable(feature = "rust1", since = "1.0.0")] fn from_wide(wide: &[u16]) -> Self; } @@ -103,14 +92,12 @@ impl OsStringExt for OsString { } /// Windows-specific extensions to [`OsStr`]. -/// -/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html #[stable(feature = "rust1", since = "1.0.0")] pub trait OsStrExt { /// Re-encodes an `OsStr` as a wide character sequence, i.e., potentially /// ill-formed UTF-16. /// - /// This is lossless: calling [`OsString::from_wide`] and then + /// This is lossless: calling [`OsStringExt::from_wide`] and then /// `encode_wide` on the result will yield the original code units. /// Note that the encoding does not add a final null terminator. /// @@ -128,8 +115,6 @@ pub trait OsStrExt { /// let result: Vec = string.encode_wide().collect(); /// assert_eq!(&source[..], &result[..]); /// ``` - /// - /// [`OsString::from_wide`]: ./trait.OsStringExt.html#tymethod.from_wide #[stable(feature = "rust1", since = "1.0.0")] fn encode_wide(&self) -> EncodeWide<'_>; } diff --git a/library/std/src/sys/windows/ext/fs.rs b/library/std/src/sys/windows/ext/fs.rs index 81b2bf9987200..e0615f2d33431 100644 --- a/library/std/src/sys/windows/ext/fs.rs +++ b/library/std/src/sys/windows/ext/fs.rs @@ -8,9 +8,7 @@ use crate::path::Path; use crate::sys; use crate::sys_common::{AsInner, AsInnerMut}; -/// Windows-specific extensions to [`File`]. -/// -/// [`File`]: ../../../fs/struct.File.html +/// Windows-specific extensions to [`fs::File`]. #[stable(feature = "file_offset", since = "1.15.0")] pub trait FileExt { /// Seeks to a given position and reads a number of bytes. @@ -94,8 +92,6 @@ impl FileExt for fs::File { } /// Windows-specific extensions to [`fs::OpenOptions`]. -/// -/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html #[stable(feature = "open_options_ext", since = "1.10.0")] pub trait OpenOptionsExt { /// Overrides the `dwDesiredAccess` argument to the call to [`CreateFile`] @@ -295,7 +291,6 @@ impl OpenOptionsExt for OpenOptions { /// The data members that this trait exposes correspond to the members /// of the [`BY_HANDLE_FILE_INFORMATION`] structure. /// -/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html /// [`BY_HANDLE_FILE_INFORMATION`]: /// https://docs.microsoft.com/en-us/windows/win32/api/fileapi/ns-fileapi-by_handle_file_information #[stable(feature = "metadata_ext", since = "1.1.0")] @@ -499,11 +494,9 @@ impl MetadataExt for Metadata { } } -/// Windows-specific extensions to [`FileType`]. +/// Windows-specific extensions to [`fs::FileType`]. /// /// On Windows, a symbolic link knows whether it is a file or directory. -/// -/// [`FileType`]: ../../../../std/fs/struct.FileType.html #[unstable(feature = "windows_file_type_ext", issue = "none")] pub trait FileTypeExt { /// Returns `true` if this file type is a symbolic link that is also a directory. diff --git a/library/std/src/sys/windows/ext/process.rs b/library/std/src/sys/windows/ext/process.rs index 8c34a9faf1d4a..61e4c6a1d1718 100644 --- a/library/std/src/sys/windows/ext/process.rs +++ b/library/std/src/sys/windows/ext/process.rs @@ -73,8 +73,6 @@ impl IntoRawHandle for process::ChildStderr { } /// Windows-specific extensions to [`process::ExitStatus`]. -/// -/// [`process::ExitStatus`]: ../../../../std/process/struct.ExitStatus.html #[stable(feature = "exit_status_from", since = "1.12.0")] pub trait ExitStatusExt { /// Creates a new `ExitStatus` from the raw underlying `u32` return value of @@ -91,8 +89,6 @@ impl ExitStatusExt for process::ExitStatus { } /// Windows-specific extensions to the [`process::Command`] builder. -/// -/// [`process::Command`]: ../../../../std/process/struct.Command.html #[stable(feature = "windows_process_extensions", since = "1.16.0")] pub trait CommandExt { /// Sets the [process creation flags][1] to be passed to `CreateProcess`. From 8b86b28f50d7c8fdbbd5f045fe5fefdd314632dc Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 15 Jul 2020 02:51:46 +0300 Subject: [PATCH 14/16] Use LocalDefId instead of HirId for reachable_set elements. --- .../back/symbol_export.rs | 8 +- src/librustc_middle/query/mod.rs | 3 +- src/librustc_middle/ty/query/mod.rs | 2 +- src/librustc_passes/reachable.rs | 99 +++++++++---------- 4 files changed, 55 insertions(+), 57 deletions(-) diff --git a/src/librustc_codegen_ssa/back/symbol_export.rs b/src/librustc_codegen_ssa/back/symbol_export.rs index 87d7f00c703a5..51cc1ada432dc 100644 --- a/src/librustc_codegen_ssa/back/symbol_export.rs +++ b/src/librustc_codegen_ssa/back/symbol_export.rs @@ -61,7 +61,7 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap< let mut reachable_non_generics: DefIdMap<_> = tcx .reachable_set(LOCAL_CRATE) .iter() - .filter_map(|&hir_id| { + .filter_map(|&def_id| { // We want to ignore some FFI functions that are not exposed from // this crate. Reachable FFI functions can be lumped into two // categories: @@ -75,9 +75,8 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap< // // As a result, if this id is an FFI item (foreign item) then we only // let it through if it's included statically. - match tcx.hir().get(hir_id) { + match tcx.hir().get(tcx.hir().local_def_id_to_hir_id(def_id)) { Node::ForeignItem(..) => { - let def_id = tcx.hir().local_def_id(hir_id); tcx.is_statically_included_foreign_item(def_id).then_some(def_id) } @@ -87,7 +86,6 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap< .. }) | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) => { - let def_id = tcx.hir().local_def_id(hir_id); let generics = tcx.generics_of(def_id); if !generics.requires_monomorphization(tcx) // Functions marked with #[inline] are codegened with "internal" @@ -361,7 +359,7 @@ fn upstream_drop_glue_for_provider<'tcx>( fn is_unreachable_local_definition_provider(tcx: TyCtxt<'_>, def_id: DefId) -> bool { if let Some(def_id) = def_id.as_local() { - !tcx.reachable_set(LOCAL_CRATE).contains(&tcx.hir().local_def_id_to_hir_id(def_id)) + !tcx.reachable_set(LOCAL_CRATE).contains(&def_id) } else { bug!("is_unreachable_local_definition called with non-local DefId: {:?}", def_id) } diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs index d364a46463821..d874edf627472 100644 --- a/src/librustc_middle/query/mod.rs +++ b/src/librustc_middle/query/mod.rs @@ -740,7 +740,8 @@ rustc_queries! { } Other { - query reachable_set(_: CrateNum) -> &'tcx HirIdSet { + query reachable_set(_: CrateNum) -> FxHashSet { + storage(ArenaCacheSelector<'tcx>) desc { "reachability" } } diff --git a/src/librustc_middle/ty/query/mod.rs b/src/librustc_middle/ty/query/mod.rs index b39c0b5190a6d..4d820f75c56c4 100644 --- a/src/librustc_middle/ty/query/mod.rs +++ b/src/librustc_middle/ty/query/mod.rs @@ -43,7 +43,7 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId}; use rustc_hir::lang_items::{LangItem, LanguageItems}; -use rustc_hir::{Crate, HirIdSet, ItemLocalId, TraitCandidate}; +use rustc_hir::{Crate, ItemLocalId, TraitCandidate}; use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec}; use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion}; use rustc_session::utils::NativeLibKind; diff --git a/src/librustc_passes/reachable.rs b/src/librustc_passes/reachable.rs index 18fa4ada4dadd..8d5c980609cd9 100644 --- a/src/librustc_passes/reachable.rs +++ b/src/librustc_passes/reachable.rs @@ -12,11 +12,11 @@ use rustc_hir::def_id::LOCAL_CRATE; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::itemlikevisit::ItemLikeVisitor; -use rustc_hir::{HirIdSet, Node}; +use rustc_hir::Node; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::middle::privacy; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, DefIdTree, TyCtxt}; use rustc_session::config::CrateType; use rustc_target::spec::abi::Abi; @@ -65,10 +65,11 @@ struct ReachableContext<'tcx> { tcx: TyCtxt<'tcx>, maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>, // The set of items which must be exported in the linkage sense. - reachable_symbols: HirIdSet, + reachable_symbols: FxHashSet, // A worklist of item IDs. Each item ID in this worklist will be inlined // and will be scanned for further references. - worklist: Vec, + // FIXME(eddyb) benchmark if this would be faster as a `VecDeque`. + worklist: Vec, // Whether any output of this compilation is a library any_library: bool, } @@ -100,37 +101,27 @@ impl<'tcx> Visitor<'tcx> for ReachableContext<'tcx> { _ => None, }; - match res { - Some(Res::Local(hir_id)) => { - self.reachable_symbols.insert(hir_id); - } - Some(res) => { - if let Some((hir_id, def_id)) = res.opt_def_id().and_then(|def_id| { - def_id - .as_local() - .map(|def_id| (self.tcx.hir().local_def_id_to_hir_id(def_id), def_id)) - }) { - if self.def_id_represents_local_inlined_item(def_id.to_def_id()) { - self.worklist.push(hir_id); - } else { - match res { - // If this path leads to a constant, then we need to - // recurse into the constant to continue finding - // items that are reachable. - Res::Def(DefKind::Const | DefKind::AssocConst, _) => { - self.worklist.push(hir_id); - } + if let Some(res) = res { + if let Some(def_id) = res.opt_def_id().and_then(|def_id| def_id.as_local()) { + if self.def_id_represents_local_inlined_item(def_id.to_def_id()) { + self.worklist.push(def_id); + } else { + match res { + // If this path leads to a constant, then we need to + // recurse into the constant to continue finding + // items that are reachable. + Res::Def(DefKind::Const | DefKind::AssocConst, _) => { + self.worklist.push(def_id); + } - // If this wasn't a static, then the destination is - // surely reachable. - _ => { - self.reachable_symbols.insert(hir_id); - } + // If this wasn't a static, then the destination is + // surely reachable. + _ => { + self.reachable_symbols.insert(def_id); } } } } - _ => {} } intravisit::walk_expr(self, expr) @@ -209,13 +200,15 @@ impl<'tcx> ReachableContext<'tcx> { continue; } - if let Some(ref item) = self.tcx.hir().find(search_item) { + if let Some(ref item) = + self.tcx.hir().find(self.tcx.hir().local_def_id_to_hir_id(search_item)) + { self.propagate_node(item, search_item); } } } - fn propagate_node(&mut self, node: &Node<'tcx>, search_item: hir::HirId) { + fn propagate_node(&mut self, node: &Node<'tcx>, search_item: LocalDefId) { if !self.any_library { // If we are building an executable, only explicitly extern // types need to be exported. @@ -297,8 +290,9 @@ impl<'tcx> ReachableContext<'tcx> { self.visit_nested_body(body); } hir::ImplItemKind::Fn(_, body) => { - let did = self.tcx.hir().get_parent_did(search_item); - if method_might_be_inlined(self.tcx, impl_item, did) { + let impl_def_id = + self.tcx.parent(search_item.to_def_id()).unwrap().expect_local(); + if method_might_be_inlined(self.tcx, impl_item, impl_def_id) { self.visit_nested_body(body) } } @@ -317,7 +311,9 @@ impl<'tcx> ReachableContext<'tcx> { _ => { bug!( "found unexpected node kind in worklist: {} ({:?})", - self.tcx.hir().node_to_string(search_item), + self.tcx + .hir() + .node_to_string(self.tcx.hir().local_def_id_to_hir_id(search_item)), node, ); } @@ -336,7 +332,7 @@ impl<'tcx> ReachableContext<'tcx> { struct CollectPrivateImplItemsVisitor<'a, 'tcx> { tcx: TyCtxt<'tcx>, access_levels: &'a privacy::AccessLevels, - worklist: &'a mut Vec, + worklist: &'a mut Vec, } impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, 'tcx> { @@ -349,13 +345,16 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, 'tcx if codegen_attrs.contains_extern_indicator() || codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) { - self.worklist.push(item.hir_id); + self.worklist.push(def_id); } // We need only trait impls here, not inherent impls, and only non-exported ones if let hir::ItemKind::Impl { of_trait: Some(ref trait_ref), ref items, .. } = item.kind { if !self.access_levels.is_reachable(item.hir_id) { - self.worklist.extend(items.iter().map(|ii_ref| ii_ref.id.hir_id)); + // FIXME(#53488) remove `let` + let tcx = self.tcx; + self.worklist + .extend(items.iter().map(|ii_ref| tcx.hir().local_def_id(ii_ref.id.hir_id))); let trait_def_id = match trait_ref.path.res { Res::Def(DefKind::Trait, def_id) => def_id, @@ -366,12 +365,10 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, 'tcx return; } - // FIXME(#53488) remove `let` - let tcx = self.tcx; - self.worklist - .extend(tcx.provided_trait_methods(trait_def_id).map(|assoc| { - tcx.hir().local_def_id_to_hir_id(assoc.def_id.expect_local()) - })); + self.worklist.extend( + tcx.provided_trait_methods(trait_def_id) + .map(|assoc| assoc.def_id.expect_local()), + ); } } } @@ -383,7 +380,7 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, 'tcx } } -fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, crate_num: CrateNum) -> &'tcx HirIdSet { +fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, crate_num: CrateNum) -> FxHashSet { debug_assert!(crate_num == LOCAL_CRATE); let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE); @@ -405,11 +402,13 @@ fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, crate_num: CrateNum) -> &'tcx HirIdSet // If other crates link to us, they're going to expect to be able to // use the lang items, so we need to be sure to mark them as // exported. - reachable_context.worklist.extend(access_levels.map.iter().map(|(id, _)| *id)); + reachable_context + .worklist + .extend(access_levels.map.iter().map(|(id, _)| tcx.hir().local_def_id(*id))); for item in tcx.lang_items().items().iter() { - if let Some(did) = *item { - if let Some(hir_id) = did.as_local().map(|did| tcx.hir().local_def_id_to_hir_id(did)) { - reachable_context.worklist.push(hir_id); + if let Some(def_id) = *item { + if let Some(def_id) = def_id.as_local() { + reachable_context.worklist.push(def_id); } } } @@ -428,7 +427,7 @@ fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, crate_num: CrateNum) -> &'tcx HirIdSet debug!("Inline reachability shows: {:?}", reachable_context.reachable_symbols); // Return the set of reachable symbols. - tcx.arena.alloc(reachable_context.reachable_symbols) + reachable_context.reachable_symbols } pub fn provide(providers: &mut Providers) { From 5d44d5456f2bc93beef26372b752d5b8613894a6 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Mon, 13 Jul 2020 17:12:07 +0300 Subject: [PATCH 15/16] rustc_typeck: construct {Closure,Generator}Substs more directly. --- src/librustc_middle/ty/mod.rs | 1 + src/librustc_middle/ty/sty.rs | 94 +++++++++++++++++------- src/librustc_typeck/check/closure.rs | 105 +++++++++++++-------------- 3 files changed, 118 insertions(+), 82 deletions(-) diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 62a62085c6664..dacf242118122 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -60,6 +60,7 @@ pub use self::sty::{Binder, BoundTy, BoundTyKind, BoundVar, DebruijnIndex, INNER pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region}; pub use self::sty::{CanonicalPolyFnSig, FnSig, GenSig, PolyFnSig, PolyGenSig}; pub use self::sty::{ClosureSubsts, GeneratorSubsts, TypeAndMut, UpvarSubsts}; +pub use self::sty::{ClosureSubstsParts, GeneratorSubstsParts}; pub use self::sty::{ConstVid, FloatVid, IntVid, RegionVid, TyVid}; pub use self::sty::{ExistentialPredicate, InferTy, ParamConst, ParamTy, ProjectionTy}; pub use self::sty::{ExistentialProjection, PolyExistentialProjection}; diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs index 05cd1ae456b35..71da5506315af 100644 --- a/src/librustc_middle/ty/sty.rs +++ b/src/librustc_middle/ty/sty.rs @@ -325,24 +325,39 @@ pub struct ClosureSubsts<'tcx> { pub substs: SubstsRef<'tcx>, } -/// Struct returned by `split()`. Note that these are subslices of the -/// parent slice and not canonical substs themselves. -struct SplitClosureSubsts<'tcx> { - parent: &'tcx [GenericArg<'tcx>], - closure_kind_ty: GenericArg<'tcx>, - closure_sig_as_fn_ptr_ty: GenericArg<'tcx>, - tupled_upvars_ty: GenericArg<'tcx>, +/// Struct returned by `split()`. +pub struct ClosureSubstsParts<'tcx, T> { + pub parent_substs: &'tcx [GenericArg<'tcx>], + pub closure_kind_ty: T, + pub closure_sig_as_fn_ptr_ty: T, + pub tupled_upvars_ty: T, } impl<'tcx> ClosureSubsts<'tcx> { - /// Divides the closure substs into their respective - /// components. Single source of truth with respect to the - /// ordering. - fn split(self) -> SplitClosureSubsts<'tcx> { + /// Construct `ClosureSubsts` from `ClosureSubstsParts`, containing `Substs` + /// for the closure parent, alongside additional closure-specific components. + pub fn new( + tcx: TyCtxt<'tcx>, + parts: ClosureSubstsParts<'tcx, Ty<'tcx>>, + ) -> ClosureSubsts<'tcx> { + ClosureSubsts { + substs: tcx.mk_substs( + parts.parent_substs.iter().copied().chain( + [parts.closure_kind_ty, parts.closure_sig_as_fn_ptr_ty, parts.tupled_upvars_ty] + .iter() + .map(|&ty| ty.into()), + ), + ), + } + } + + /// Divides the closure substs into their respective components. + /// The ordering assumed here must match that used by `ClosureSubsts::new` above. + fn split(self) -> ClosureSubstsParts<'tcx, GenericArg<'tcx>> { match self.substs[..] { - [ref parent @ .., closure_kind_ty, closure_sig_as_fn_ptr_ty, tupled_upvars_ty] => { - SplitClosureSubsts { - parent, + [ref parent_substs @ .., closure_kind_ty, closure_sig_as_fn_ptr_ty, tupled_upvars_ty] => { + ClosureSubstsParts { + parent_substs, closure_kind_ty, closure_sig_as_fn_ptr_ty, tupled_upvars_ty, @@ -363,7 +378,7 @@ impl<'tcx> ClosureSubsts<'tcx> { /// Returns the substitutions of the closure's parent. pub fn parent_substs(self) -> &'tcx [GenericArg<'tcx>] { - self.split().parent + self.split().parent_substs } #[inline] @@ -418,21 +433,46 @@ pub struct GeneratorSubsts<'tcx> { pub substs: SubstsRef<'tcx>, } -struct SplitGeneratorSubsts<'tcx> { - parent: &'tcx [GenericArg<'tcx>], - resume_ty: GenericArg<'tcx>, - yield_ty: GenericArg<'tcx>, - return_ty: GenericArg<'tcx>, - witness: GenericArg<'tcx>, - tupled_upvars_ty: GenericArg<'tcx>, +pub struct GeneratorSubstsParts<'tcx, T> { + pub parent_substs: &'tcx [GenericArg<'tcx>], + pub resume_ty: T, + pub yield_ty: T, + pub return_ty: T, + pub witness: T, + pub tupled_upvars_ty: T, } impl<'tcx> GeneratorSubsts<'tcx> { - fn split(self) -> SplitGeneratorSubsts<'tcx> { + /// Construct `GeneratorSubsts` from `GeneratorSubstsParts`, containing `Substs` + /// for the generator parent, alongside additional generator-specific components. + pub fn new( + tcx: TyCtxt<'tcx>, + parts: GeneratorSubstsParts<'tcx, Ty<'tcx>>, + ) -> GeneratorSubsts<'tcx> { + GeneratorSubsts { + substs: tcx.mk_substs( + parts.parent_substs.iter().copied().chain( + [ + parts.resume_ty, + parts.yield_ty, + parts.return_ty, + parts.witness, + parts.tupled_upvars_ty, + ] + .iter() + .map(|&ty| ty.into()), + ), + ), + } + } + + /// Divides the generator substs into their respective components. + /// The ordering assumed here must match that used by `GeneratorSubsts::new` above. + fn split(self) -> GeneratorSubstsParts<'tcx, GenericArg<'tcx>> { match self.substs[..] { - [ref parent @ .., resume_ty, yield_ty, return_ty, witness, tupled_upvars_ty] => { - SplitGeneratorSubsts { - parent, + [ref parent_substs @ .., resume_ty, yield_ty, return_ty, witness, tupled_upvars_ty] => { + GeneratorSubstsParts { + parent_substs, resume_ty, yield_ty, return_ty, @@ -455,7 +495,7 @@ impl<'tcx> GeneratorSubsts<'tcx> { /// Returns the substitutions of the generator's parent. pub fn parent_substs(self) -> &'tcx [GenericArg<'tcx>] { - self.split().parent + self.split().parent_substs } /// This describes the types that can be contained in a generator. diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 255f611cfa357..c7f9e9d63e03c 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -11,7 +11,7 @@ use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_infer::infer::{InferOk, InferResult}; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::InternalSubsts; -use rustc_middle::ty::{self, GenericParamDefKind, Ty}; +use rustc_middle::ty::{self, Ty}; use rustc_span::source_map::Span; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::error_reporting::ArgKind; @@ -76,60 +76,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let generator_types = check_fn(self, self.param_env, liberated_sig, decl, expr.hir_id, body, gen).1; - let base_substs = InternalSubsts::identity_for_item( + let parent_substs = InternalSubsts::identity_for_item( self.tcx, self.tcx.closure_base_def_id(expr_def_id.to_def_id()), ); - // HACK(eddyb) this hardcodes indices into substs but it should rely on - // `ClosureSubsts` and `GeneratorSubsts` providing constructors, instead. - // That would also remove the need for most of the inference variables, - // as they immediately unified with the actual type below, including - // the `InferCtxt::closure_sig` and `ClosureSubsts::sig_ty` methods. - let tupled_upvars_idx = base_substs.len() + if generator_types.is_some() { 4 } else { 2 }; - let substs = - base_substs.extend_to(self.tcx, expr_def_id.to_def_id(), |param, _| match param.kind { - GenericParamDefKind::Lifetime => span_bug!(expr.span, "closure has lifetime param"), - GenericParamDefKind::Type { .. } => if param.index as usize == tupled_upvars_idx { - self.tcx.mk_tup(self.tcx.upvars_mentioned(expr_def_id).iter().flat_map( - |upvars| { - upvars.iter().map(|(&var_hir_id, _)| { - // Create type variables (for now) to represent the transformed - // types of upvars. These will be unified during the upvar - // inference phase (`upvar.rs`). - self.infcx.next_ty_var(TypeVariableOrigin { - // FIXME(eddyb) distinguish upvar inference variables from the rest. - kind: TypeVariableOriginKind::ClosureSynthetic, - span: self.tcx.hir().span(var_hir_id), - }) - }) - }, - )) - } else { - // Create type variables (for now) to represent the various - // pieces of information kept in `{Closure,Generic}Substs`. - // They will either be unified below, or later during the upvar - // inference phase (`upvar.rs`) + + let tupled_upvars_ty = + self.tcx.mk_tup(self.tcx.upvars_mentioned(expr_def_id).iter().flat_map(|upvars| { + upvars.iter().map(|(&var_hir_id, _)| { + // Create type variables (for now) to represent the transformed + // types of upvars. These will be unified during the upvar + // inference phase (`upvar.rs`). self.infcx.next_ty_var(TypeVariableOrigin { + // FIXME(eddyb) distinguish upvar inference variables from the rest. kind: TypeVariableOriginKind::ClosureSynthetic, - span: expr.span, + span: self.tcx.hir().span(var_hir_id), }) - } - .into(), - GenericParamDefKind::Const => span_bug!(expr.span, "closure has const param"), - }); + }) + })); + if let Some(GeneratorTypes { resume_ty, yield_ty, interior, movability }) = generator_types { - let generator_substs = substs.as_generator(); - self.demand_eqtype(expr.span, resume_ty, generator_substs.resume_ty()); - self.demand_eqtype(expr.span, yield_ty, generator_substs.yield_ty()); - self.demand_eqtype(expr.span, liberated_sig.output(), generator_substs.return_ty()); - self.demand_eqtype(expr.span, interior, generator_substs.witness()); - - // HACK(eddyb) this forces the types equated above into `substs` but - // it should rely on `GeneratorSubsts` providing a constructor, instead. - let substs = self.resolve_vars_if_possible(&substs); + let generator_substs = ty::GeneratorSubsts::new( + self.tcx, + ty::GeneratorSubstsParts { + parent_substs, + resume_ty, + yield_ty, + return_ty: liberated_sig.output(), + witness: interior, + tupled_upvars_ty, + }, + ); - return self.tcx.mk_generator(expr_def_id.to_def_id(), substs, movability); + return self.tcx.mk_generator( + expr_def_id.to_def_id(), + generator_substs.substs, + movability, + ); } // Tuple up the arguments and insert the resulting function type into @@ -149,18 +133,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr_def_id, sig, opt_kind ); - let sig_fn_ptr_ty = self.tcx.mk_fn_ptr(sig); - self.demand_eqtype(expr.span, sig_fn_ptr_ty, substs.as_closure().sig_as_fn_ptr_ty()); + let closure_kind_ty = match opt_kind { + Some(kind) => kind.to_ty(self.tcx), - if let Some(kind) = opt_kind { - self.demand_eqtype(expr.span, kind.to_ty(self.tcx), substs.as_closure().kind_ty()); - } + // Create a type variable (for now) to represent the closure kind. + // It will be unified during the upvar inference phase (`upvar.rs`) + None => self.infcx.next_ty_var(TypeVariableOrigin { + // FIXME(eddyb) distinguish closure kind inference variables from the rest. + kind: TypeVariableOriginKind::ClosureSynthetic, + span: expr.span, + }), + }; - // HACK(eddyb) this forces the types equated above into `substs` but - // it should rely on `ClosureSubsts` providing a constructor, instead. - let substs = self.resolve_vars_if_possible(&substs); + let closure_substs = ty::ClosureSubsts::new( + self.tcx, + ty::ClosureSubstsParts { + parent_substs, + closure_kind_ty, + closure_sig_as_fn_ptr_ty: self.tcx.mk_fn_ptr(sig), + tupled_upvars_ty, + }, + ); - let closure_type = self.tcx.mk_closure(expr_def_id.to_def_id(), substs); + let closure_type = self.tcx.mk_closure(expr_def_id.to_def_id(), closure_substs.substs); debug!("check_closure: expr.hir_id={:?} closure_type={:?}", expr.hir_id, closure_type); From e1cd1853c8e29e7d951edc603726add1ea64f513 Mon Sep 17 00:00:00 2001 From: mark Date: Thu, 16 Jul 2020 10:21:10 -0500 Subject: [PATCH 16/16] move DelaySpanBugEmitted to ty::context --- src/librustc_middle/ty/consts/kind.rs | 2 +- src/librustc_middle/ty/context.rs | 13 ++++++++----- src/librustc_middle/ty/mod.rs | 4 ++-- src/librustc_middle/ty/sty.rs | 8 +------- 4 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/librustc_middle/ty/consts/kind.rs b/src/librustc_middle/ty/consts/kind.rs index a4c177160f5d0..ede28522000af 100644 --- a/src/librustc_middle/ty/consts/kind.rs +++ b/src/librustc_middle/ty/consts/kind.rs @@ -34,7 +34,7 @@ pub enum ConstKind<'tcx> { /// A placeholder for a const which could not be computed; this is /// propagated to avoid useless error messages. - Error(ty::sty::DelaySpanBugEmitted), + Error(ty::DelaySpanBugEmitted), } #[cfg(target_arch = "x86_64")] diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index 6887f72932267..206f6a270e4c3 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -64,6 +64,12 @@ use std::mem; use std::ops::{Bound, Deref}; use std::sync::Arc; +/// A type that is not publicly constructable. This prevents people from making `TyKind::Error` +/// except through `tcx.err*()`, which are in this module. +#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] +#[derive(TyEncodable, TyDecodable, HashStable)] +pub struct DelaySpanBugEmitted(()); + type InternedSet<'tcx, T> = ShardedHashMap, ()>; pub struct CtxtInterners<'tcx> { @@ -1170,7 +1176,7 @@ impl<'tcx> TyCtxt<'tcx> { #[track_caller] pub fn ty_error_with_message>(self, span: S, msg: &str) -> Ty<'tcx> { self.sess.delay_span_bug(span, msg); - self.mk_ty(Error(super::sty::DelaySpanBugEmitted(()))) + self.mk_ty(Error(DelaySpanBugEmitted(()))) } /// Like `err` but for constants. @@ -1178,10 +1184,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn const_error(self, ty: Ty<'tcx>) -> &'tcx Const<'tcx> { self.sess .delay_span_bug(DUMMY_SP, "ty::ConstKind::Error constructed but no error reported."); - self.mk_const(ty::Const { - val: ty::ConstKind::Error(super::sty::DelaySpanBugEmitted(())), - ty, - }) + self.mk_const(ty::Const { val: ty::ConstKind::Error(DelaySpanBugEmitted(())), ty }) } pub fn consider_optimizing String>(&self, msg: T) -> bool { diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 62a62085c6664..142978c1687fe 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -72,8 +72,8 @@ pub use self::binding::BindingMode::*; pub use self::context::{tls, FreeRegionInfo, TyCtxt}; pub use self::context::{ - CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, ResolvedOpaqueTy, - UserType, UserTypeAnnotationIndex, + CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, + DelaySpanBugEmitted, ResolvedOpaqueTy, UserType, UserTypeAnnotationIndex, }; pub use self::context::{ CtxtInterners, GeneratorInteriorTypeCause, GlobalCtxt, Lift, TypeckResults, diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs index 05cd1ae456b35..1bcdf2dc0421f 100644 --- a/src/librustc_middle/ty/sty.rs +++ b/src/librustc_middle/ty/sty.rs @@ -10,7 +10,7 @@ use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef}; use crate::ty::{ self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable, WithConstness, }; -use crate::ty::{List, ParamEnv, TyS}; +use crate::ty::{DelaySpanBugEmitted, List, ParamEnv, TyS}; use polonius_engine::Atom; use rustc_ast::ast; use rustc_data_structures::captures::Captures; @@ -212,12 +212,6 @@ impl TyKind<'tcx> { } } -/// A type that is not publicly constructable. This prevents people from making `TyKind::Error` -/// except through `tcx.err*()`. -#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] -#[derive(TyEncodable, TyDecodable, HashStable)] -pub struct DelaySpanBugEmitted(pub(super) ()); - // `TyKind` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] static_assert_size!(TyKind<'_>, 24);