From 230393993ffc255d3f20d98400c8a376bd51d1c0 Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Thu, 9 Jul 2020 19:03:15 -0700 Subject: [PATCH 01/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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 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 11/24] 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 764dc3dc2f8a2a421fa9d9c6144ad75310a26b99 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 4 Aug 2020 10:27:35 +0100 Subject: [PATCH 12/24] lang_items: add support for lang items on variants This commit adds support for lang items (`#[lang = "..."]` attributes) on enum variants. Signed-off-by: David Wood --- src/librustc_hir/target.rs | 2 ++ src/librustc_passes/lang_items.rs | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/librustc_hir/target.rs b/src/librustc_hir/target.rs index 3a4485a1b17fd..1efc8bc3124b6 100644 --- a/src/librustc_hir/target.rs +++ b/src/librustc_hir/target.rs @@ -29,6 +29,7 @@ pub enum Target { TyAlias, OpaqueTy, Enum, + Variant, Struct, Union, Trait, @@ -62,6 +63,7 @@ impl Display for Target { Target::TyAlias => "type alias", Target::OpaqueTy => "opaque type", Target::Enum => "enum", + Target::Variant => "enum variant", Target::Struct => "struct", Target::Union => "union", Target::Trait => "trait", diff --git a/src/librustc_passes/lang_items.rs b/src/librustc_passes/lang_items.rs index 07415870549f1..9ec47d2d9ab5c 100644 --- a/src/librustc_passes/lang_items.rs +++ b/src/librustc_passes/lang_items.rs @@ -30,7 +30,13 @@ struct LanguageItemCollector<'tcx> { impl ItemLikeVisitor<'v> for LanguageItemCollector<'tcx> { fn visit_item(&mut self, item: &hir::Item<'_>) { - self.check_for_lang(Target::from_item(item), item.hir_id, item.attrs) + self.check_for_lang(Target::from_item(item), item.hir_id, item.attrs); + + if let hir::ItemKind::Enum(def, ..) = &item.kind { + for variant in def.variants { + self.check_for_lang(Target::Variant, variant.id, variant.attrs); + } + } } fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) { From 734441c1ae5f0766842d37db68f606a1bca49836 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 4 Aug 2020 10:47:07 +0100 Subject: [PATCH 13/24] tests: add test for #61019's current behaviour This commit adds a test for #61019 where a extern crate is imported as `std` which results in name resolution to fail due to the uses of `std` types introduced from lowering. Signed-off-by: David Wood --- src/test/ui/hygiene/hir-res-hygiene.rs | 41 ++++++++++++++++++ src/test/ui/hygiene/hir-res-hygiene.stderr | 49 ++++++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 src/test/ui/hygiene/hir-res-hygiene.rs create mode 100644 src/test/ui/hygiene/hir-res-hygiene.stderr diff --git a/src/test/ui/hygiene/hir-res-hygiene.rs b/src/test/ui/hygiene/hir-res-hygiene.rs new file mode 100644 index 0000000000000..e5af1000dd53e --- /dev/null +++ b/src/test/ui/hygiene/hir-res-hygiene.rs @@ -0,0 +1,41 @@ +//~ ERROR failed to resolve: could not find `future` in `std` [E0433] +//~^ ERROR failed to resolve: could not find `pin` in `std` [E0433] +//~^^ ERROR failed to resolve: could not find `future` in `std` [E0433] +//~^^^ ERROR failed to resolve: could not find `future` in `std` [E0433] +//~^^^^ ERROR failed to resolve: could not find `task` in `std` [E0433] +//~^^^^^ ERROR failed to resolve: could not find `task` in `std` [E0433] +//~^^^^^^ ERROR failed to resolve: could not find `future` in `std` [E0433] +//~^^^^^^^ ERROR failed to resolve: could not find `future` in `std` [E0433] +//~^^^^^^^^ ERROR failed to resolve: could not find `ops` in `std` [E0433] +//~^^^^^^^^^ ERROR failed to resolve: could not find `option` in `std` [E0433] +//~^^^^^^^^^^ ERROR failed to resolve: could not find `option` in `std` [E0433] +//~^^^^^^^^^^^ ERROR failed to resolve: could not find `iter` in `std` [E0433] +//~^^^^^^^^^^^^ ERROR failed to resolve: could not find `iter` in `std` [E0433] +//~^^^^^^^^^^^^^ ERROR failed to resolve: could not find `ops` in `std` [E0433] +//~^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `option` in `std` [E0433] +//~^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `option` in `std` [E0433] +//~^^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `iter` in `std` [E0433] +//~^^^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `iter` in `std` [E0433] +//~^^^^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `ops` in `std` [E0433] +//~^^^^^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `result` in `std` [E0433] +//~^^^^^^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `convert` in `std` [E0433] +//~^^^^^^^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `ops` in `std` [E0433] +//~^^^^^^^^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `result` in `std` [E0433] + +// edition:2018 +// aux-build:not-libstd.rs + +// Check that paths created in HIR are not affected by in scope names. + +extern crate not_libstd as std; + +async fn the_future() { + async {}.await; +} + +fn main() -> Result<(), ()> { + for i in 0..10 {} + for j in 0..=10 {} + Ok(())?; + Ok(()) +} diff --git a/src/test/ui/hygiene/hir-res-hygiene.stderr b/src/test/ui/hygiene/hir-res-hygiene.stderr new file mode 100644 index 0000000000000..73a1bd5c62632 --- /dev/null +++ b/src/test/ui/hygiene/hir-res-hygiene.stderr @@ -0,0 +1,49 @@ +error[E0433]: failed to resolve: could not find `future` in `std` + +error[E0433]: failed to resolve: could not find `pin` in `std` + +error[E0433]: failed to resolve: could not find `future` in `std` + +error[E0433]: failed to resolve: could not find `future` in `std` + +error[E0433]: failed to resolve: could not find `task` in `std` + +error[E0433]: failed to resolve: could not find `task` in `std` + +error[E0433]: failed to resolve: could not find `future` in `std` + +error[E0433]: failed to resolve: could not find `future` in `std` + +error[E0433]: failed to resolve: could not find `ops` in `std` + +error[E0433]: failed to resolve: could not find `option` in `std` + +error[E0433]: failed to resolve: could not find `option` in `std` + +error[E0433]: failed to resolve: could not find `iter` in `std` + +error[E0433]: failed to resolve: could not find `iter` in `std` + +error[E0433]: failed to resolve: could not find `ops` in `std` + +error[E0433]: failed to resolve: could not find `option` in `std` + +error[E0433]: failed to resolve: could not find `option` in `std` + +error[E0433]: failed to resolve: could not find `iter` in `std` + +error[E0433]: failed to resolve: could not find `iter` in `std` + +error[E0433]: failed to resolve: could not find `ops` in `std` + +error[E0433]: failed to resolve: could not find `result` in `std` + +error[E0433]: failed to resolve: could not find `convert` in `std` + +error[E0433]: failed to resolve: could not find `ops` in `std` + +error[E0433]: failed to resolve: could not find `result` in `std` + +error: aborting due to 23 previous errors + +For more information about this error, try `rustc --explain E0433`. From 7dee5f824dad65d9edffb4de22aad248bd83faf9 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 4 Aug 2020 14:04:25 +0100 Subject: [PATCH 14/24] hir: introduce lang items for AST lowering This commit adds new lang items which will be used in AST lowering once `QPath::LangItem` is introduced. Co-authored-by: Matthew Jasper Signed-off-by: David Wood --- library/core/src/convert/mod.rs | 1 + library/core/src/future/future.rs | 1 + library/core/src/future/mod.rs | 2 ++ library/core/src/iter/traits/collect.rs | 1 + library/core/src/iter/traits/iterator.rs | 1 + library/core/src/ops/range.rs | 7 +++++ library/core/src/ops/try.rs | 3 ++ library/core/src/option.rs | 2 ++ library/core/src/pin.rs | 1 + library/core/src/result.rs | 2 ++ library/core/src/task/poll.rs | 2 ++ src/librustc_hir/lang_items.rs | 36 +++++++++++++++++++++++- src/librustc_span/symbol.rs | 2 ++ 13 files changed, 60 insertions(+), 1 deletion(-) diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index 03b798d57db9b..fcd07befae504 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -385,6 +385,7 @@ pub trait Into: Sized { ))] pub trait From: Sized { /// Performs the conversion. + #[cfg_attr(not(bootstrap), lang = "from")] #[stable(feature = "rust1", since = "1.0.0")] fn from(_: T) -> Self; } diff --git a/library/core/src/future/future.rs b/library/core/src/future/future.rs index 733ebdc0e97f2..8169c146137c2 100644 --- a/library/core/src/future/future.rs +++ b/library/core/src/future/future.rs @@ -96,6 +96,7 @@ pub trait Future { /// [`Context`]: ../task/struct.Context.html /// [`Waker`]: ../task/struct.Waker.html /// [`Waker::wake`]: ../task/struct.Waker.html#method.wake + #[cfg_attr(not(bootstrap), lang = "poll")] #[stable(feature = "futures_api", since = "1.36.0")] fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll; } diff --git a/library/core/src/future/mod.rs b/library/core/src/future/mod.rs index 6d1ad9db74435..d44ef857c133a 100644 --- a/library/core/src/future/mod.rs +++ b/library/core/src/future/mod.rs @@ -53,6 +53,7 @@ unsafe impl Sync for ResumeTy {} /// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give /// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`). // This is `const` to avoid extra errors after we recover from `const async fn` +#[cfg_attr(not(bootstrap), lang = "from_generator")] #[doc(hidden)] #[unstable(feature = "gen_future", issue = "50547")] #[inline] @@ -85,6 +86,7 @@ where GenFuture(gen) } +#[cfg_attr(not(bootstrap), lang = "get_context")] #[doc(hidden)] #[unstable(feature = "gen_future", issue = "50547")] #[inline] diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs index 9d20022b6ed6d..84c7787a18fd1 100644 --- a/library/core/src/iter/traits/collect.rs +++ b/library/core/src/iter/traits/collect.rs @@ -235,6 +235,7 @@ pub trait IntoIterator { /// assert_eq!(Some(3), iter.next()); /// assert_eq!(None, iter.next()); /// ``` + #[cfg_attr(not(bootstrap), lang = "into_iter")] #[stable(feature = "rust1", since = "1.0.0")] fn into_iter(self) -> Self::IntoIter; } diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index f89b616c4e23b..81d8f27ec19b0 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -129,6 +129,7 @@ pub trait Iterator { /// assert_eq!(None, iter.next()); /// assert_eq!(None, iter.next()); /// ``` + #[cfg_attr(not(bootstrap), lang = "next")] #[stable(feature = "rust1", since = "1.0.0")] fn next(&mut self) -> Option; diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index 179038d1977c8..e9ab82b539849 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -38,6 +38,7 @@ use crate::hash::Hash; /// [`IntoIterator`]: ../iter/trait.Iterator.html /// [`Iterator`]: ../iter/trait.IntoIterator.html /// [slicing index]: ../slice/trait.SliceIndex.html +#[cfg_attr(not(bootstrap), lang = "RangeFull")] #[doc(alias = "..")] #[derive(Copy, Clone, Default, PartialEq, Eq, Hash)] #[stable(feature = "rust1", since = "1.0.0")] @@ -70,6 +71,7 @@ impl fmt::Debug for RangeFull { /// assert_eq!(arr[1.. 3], [ 1,2 ]); // Range /// assert_eq!(arr[1..=3], [ 1,2,3 ]); /// ``` +#[cfg_attr(not(bootstrap), lang = "Range")] #[doc(alias = "..")] #[derive(Clone, Default, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[stable(feature = "rust1", since = "1.0.0")] @@ -178,6 +180,7 @@ impl> Range { /// ``` /// /// [`Iterator`]: ../iter/trait.IntoIterator.html +#[cfg_attr(not(bootstrap), lang = "RangeFrom")] #[doc(alias = "..")] #[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[stable(feature = "rust1", since = "1.0.0")] @@ -260,6 +263,7 @@ impl> RangeFrom { /// [`IntoIterator`]: ../iter/trait.Iterator.html /// [`Iterator`]: ../iter/trait.IntoIterator.html /// [slicing index]: ../slice/trait.SliceIndex.html +#[cfg_attr(not(bootstrap), lang = "RangeTo")] #[doc(alias = "..")] #[derive(Copy, Clone, PartialEq, Eq, Hash)] #[stable(feature = "rust1", since = "1.0.0")] @@ -328,6 +332,7 @@ impl> RangeTo { /// assert_eq!(arr[1.. 3], [ 1,2 ]); /// assert_eq!(arr[1..=3], [ 1,2,3 ]); // RangeInclusive /// ``` +#[cfg_attr(not(bootstrap), lang = "RangeInclusive")] #[doc(alias = "..=")] #[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[stable(feature = "inclusive_range", since = "1.26.0")] @@ -359,6 +364,7 @@ impl RangeInclusive { /// /// assert_eq!(3..=5, RangeInclusive::new(3, 5)); /// ``` + #[cfg_attr(not(bootstrap), lang = "range_inclusive_new")] #[stable(feature = "inclusive_range_methods", since = "1.27.0")] #[inline] #[rustc_promotable] @@ -555,6 +561,7 @@ impl> RangeInclusive { /// [`IntoIterator`]: ../iter/trait.Iterator.html /// [`Iterator`]: ../iter/trait.IntoIterator.html /// [slicing index]: ../slice/trait.SliceIndex.html +#[cfg_attr(not(bootstrap), lang = "RangeToInclusive")] #[doc(alias = "..=")] #[derive(Copy, Clone, PartialEq, Eq, Hash)] #[stable(feature = "inclusive_range", since = "1.26.0")] diff --git a/library/core/src/ops/try.rs b/library/core/src/ops/try.rs index 9bc35ae1f5c28..e6b05cc641e35 100644 --- a/library/core/src/ops/try.rs +++ b/library/core/src/ops/try.rs @@ -43,16 +43,19 @@ pub trait Try { /// in the return type of the enclosing scope (which must itself implement /// `Try`). Specifically, the value `X::from_error(From::from(e))` /// is returned, where `X` is the return type of the enclosing function. + #[cfg_attr(not(bootstrap), lang = "into_result")] #[unstable(feature = "try_trait", issue = "42327")] fn into_result(self) -> Result; /// Wrap an error value to construct the composite result. For example, /// `Result::Err(x)` and `Result::from_error(x)` are equivalent. + #[cfg_attr(not(bootstrap), lang = "from_error")] #[unstable(feature = "try_trait", issue = "42327")] fn from_error(v: Self::Error) -> Self; /// Wrap an OK value to construct the composite result. For example, /// `Result::Ok(x)` and `Result::from_ok(x)` are equivalent. + #[cfg_attr(not(bootstrap), lang = "from_ok")] #[unstable(feature = "try_trait", issue = "42327")] fn from_ok(v: Self::Ok) -> Self; } diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 6d078fb0a54d6..b6aa2c6697123 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -144,9 +144,11 @@ use crate::{ #[stable(feature = "rust1", since = "1.0.0")] pub enum Option { /// No value + #[cfg_attr(not(bootstrap), lang = "None")] #[stable(feature = "rust1", since = "1.0.0")] None, /// Some value `T` + #[cfg_attr(not(bootstrap), lang = "Some")] #[stable(feature = "rust1", since = "1.0.0")] Some(#[stable(feature = "rust1", since = "1.0.0")] T), } diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 9bcacd8ddcf77..c1a90a1fd8042 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -562,6 +562,7 @@ impl Pin

{ /// ``` /// /// [`mem::swap`]: ../../std/mem/fn.swap.html + #[cfg_attr(not(bootstrap), lang = "new_unchecked")] #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] pub unsafe fn new_unchecked(pointer: P) -> Pin

{ diff --git a/library/core/src/result.rs b/library/core/src/result.rs index e68dbf5215f6d..5eddcb2172abe 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -246,10 +246,12 @@ use crate::{convert, fmt}; #[stable(feature = "rust1", since = "1.0.0")] pub enum Result { /// Contains the success value + #[cfg_attr(not(bootstrap), lang = "Ok")] #[stable(feature = "rust1", since = "1.0.0")] Ok(#[stable(feature = "rust1", since = "1.0.0")] T), /// Contains the error value + #[cfg_attr(not(bootstrap), lang = "Err")] #[stable(feature = "rust1", since = "1.0.0")] Err(#[stable(feature = "rust1", since = "1.0.0")] E), } diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs index b3a4bd20b8f04..fea396d20ff4b 100644 --- a/library/core/src/task/poll.rs +++ b/library/core/src/task/poll.rs @@ -10,6 +10,7 @@ use crate::result::Result; #[stable(feature = "futures_api", since = "1.36.0")] pub enum Poll { /// Represents that a value is immediately ready. + #[cfg_attr(not(bootstrap), lang = "Ready")] #[stable(feature = "futures_api", since = "1.36.0")] Ready(#[stable(feature = "futures_api", since = "1.36.0")] T), @@ -18,6 +19,7 @@ pub enum Poll { /// When a function returns `Pending`, the function *must* also /// ensure that the current task is scheduled to be awoken when /// progress can be made. + #[cfg_attr(not(bootstrap), lang = "Pending")] #[stable(feature = "futures_api", since = "1.36.0")] Pending, } diff --git a/src/librustc_hir/lang_items.rs b/src/librustc_hir/lang_items.rs index b09657bd9b4a4..d6c295f0ddb61 100644 --- a/src/librustc_hir/lang_items.rs +++ b/src/librustc_hir/lang_items.rs @@ -10,7 +10,7 @@ pub use self::LangItem::*; use crate::def_id::DefId; -use crate::Target; +use crate::{MethodKind, Target}; use rustc_ast::ast; use rustc_data_structures::fx::FxHashMap; @@ -307,4 +307,38 @@ language_item_table! { CountCodeRegionFnLangItem, sym::count_code_region, count_code_region_fn, Target::Fn; CoverageCounterAddFnLangItem, sym::coverage_counter_add, coverage_counter_add_fn, Target::Fn; CoverageCounterSubtractFnLangItem, sym::coverage_counter_subtract, coverage_counter_subtract_fn, Target::Fn; + + // Language items from AST lowering + TryFromError, sym::from_error, from_error_fn, Target::Method(MethodKind::Trait { body: false }); + TryFromOk, sym::from_ok, from_ok_fn, Target::Method(MethodKind::Trait { body: false }); + TryIntoResult, sym::into_result, into_result_fn, Target::Method(MethodKind::Trait { body: false }); + + PollReady, sym::Ready, poll_ready_variant, Target::Variant; + PollPending, sym::Pending, poll_pending_variant, Target::Variant; + + FromGenerator, sym::from_generator, from_generator_fn, Target::Fn; + GetContext, sym::get_context, get_context_fn, Target::Fn; + + FuturePoll, sym::poll, future_poll_fn, Target::Method(MethodKind::Trait { body: false }); + + FromFrom, sym::from, from_fn, Target::Method(MethodKind::Trait { body: false }); + + OptionSome, sym::Some, option_some_variant, Target::Variant; + OptionNone, sym::None, option_none_variant, Target::Variant; + + ResultOk, sym::Ok, result_ok_variant, Target::Variant; + ResultErr, sym::Err, result_err_variant, Target::Variant; + + IntoIterIntoIter, sym::into_iter, into_iter_fn, Target::Method(MethodKind::Trait { body: false }); + IteratorNext, sym::next, next_fn, Target::Method(MethodKind::Trait { body: false}); + + PinNewUnchecked, sym::new_unchecked, new_unchecked_fn, Target::Method(MethodKind::Inherent); + + RangeFrom, sym::RangeFrom, range_from_struct, Target::Struct; + RangeFull, sym::RangeFull, range_full_struct, Target::Struct; + RangeInclusiveStruct, sym::RangeInclusive, range_inclusive_struct, Target::Struct; + RangeInclusiveNew, sym::range_inclusive_new, range_inclusive_new_method, Target::Method(MethodKind::Inherent); + Range, sym::Range, range_struct, Target::Struct; + RangeToInclusive, sym::RangeToInclusive, range_to_inclusive_struct, Target::Struct; + RangeTo, sym::RangeTo, range_to_struct, Target::Struct; } diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index 7843c04f25596..bc7efd26f467b 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -706,6 +706,7 @@ symbols! { never_type, never_type_fallback, new, + new_unchecked, next, nll, no, @@ -828,6 +829,7 @@ symbols! { quad_precision_float, question_mark, quote, + range_inclusive_new, raw_dylib, raw_identifiers, raw_ref_op, From 762137e2121ac8998b5bb916453eb24ec6523450 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 4 Aug 2020 14:34:24 +0100 Subject: [PATCH 15/24] hir: introduce `QPath::LangItem` This commit introduces `QPath::LangItem` to the HIR and uses it in AST lowering instead of constructing a `hir::Path` from a slice of symbols. This might be better for performance, but is also much cleaner as the previous approach is fragile. In addition, it resolves a bug (#61019) where an extern crate imported as "std" would result in the paths created during AST lowering being resolved incorrectly (or not at all). Co-authored-by: Matthew Jasper Signed-off-by: David Wood --- src/librustc_ast_lowering/expr.rs | 161 ++++++++------------- src/librustc_ast_lowering/lib.rs | 110 +++++--------- src/librustc_hir/hir.rs | 50 ++++++- src/librustc_hir/intravisit.rs | 5 + src/librustc_hir_pretty/lib.rs | 10 ++ src/librustc_lint/builtin.rs | 2 +- src/librustc_lint/context.rs | 2 +- src/librustc_middle/ty/context.rs | 2 +- src/librustc_passes/liveness.rs | 6 +- src/librustc_privacy/lib.rs | 6 +- src/librustc_resolve/lib.rs | 31 ---- src/librustc_save_analysis/dump_visitor.rs | 4 + src/librustc_save_analysis/lib.rs | 3 + src/librustc_save_analysis/sig.rs | 1 + src/librustc_typeck/astconv.rs | 46 ++++++ src/librustc_typeck/check/expr.rs | 18 ++- src/librustc_typeck/check/mod.rs | 38 ++++- src/librustc_typeck/check/pat.rs | 8 +- src/librustc_typeck/collect.rs | 26 ++++ src/test/ui/hygiene/hir-res-hygiene.rs | 25 +--- src/test/ui/hygiene/hir-res-hygiene.stderr | 49 ------- 21 files changed, 289 insertions(+), 314 deletions(-) delete mode 100644 src/test/ui/hygiene/hir-res-hygiene.stderr diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs index f9e54903a661a..65c9cd2e203d1 100644 --- a/src/librustc_ast_lowering/expr.rs +++ b/src/librustc_ast_lowering/expr.rs @@ -449,7 +449,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // `::std::ops::Try::from_ok($tail_expr)` block.expr = Some(this.wrap_in_try_constructor( - sym::from_ok, + hir::LangItem::TryFromOk, try_span, tail_expr, ok_wrapped_span, @@ -461,14 +461,13 @@ impl<'hir> LoweringContext<'_, 'hir> { fn wrap_in_try_constructor( &mut self, - method: Symbol, + lang_item: hir::LangItem, method_span: Span, expr: &'hir hir::Expr<'hir>, overall_span: Span, ) -> &'hir hir::Expr<'hir> { - let path = &[sym::ops, sym::Try, method]; let constructor = - self.arena.alloc(self.expr_std_path(method_span, path, None, ThinVec::new())); + self.arena.alloc(self.expr_lang_item_path(method_span, lang_item, ThinVec::new())); self.expr_call(overall_span, constructor, std::slice::from_ref(expr)) } @@ -558,12 +557,8 @@ impl<'hir> LoweringContext<'_, 'hir> { // `future::from_generator`: let unstable_span = self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone()); - let gen_future = self.expr_std_path( - unstable_span, - &[sym::future, sym::from_generator], - None, - ThinVec::new(), - ); + let gen_future = + self.expr_lang_item_path(unstable_span, hir::LangItem::FromGenerator, ThinVec::new()); // `future::from_generator(generator)`: hir::ExprKind::Call(self.arena.alloc(gen_future), arena_vec![self; generator]) @@ -630,23 +625,19 @@ impl<'hir> LoweringContext<'_, 'hir> { // Use of `await` outside of an async context, we cannot use `task_context` here. self.expr_err(span) }; - let pin_ty_id = self.next_id(); - let new_unchecked_expr_kind = self.expr_call_std_assoc_fn( - pin_ty_id, + let new_unchecked = self.expr_call_lang_item_fn_mut( span, - &[sym::pin, sym::Pin], - "new_unchecked", + hir::LangItem::PinNewUnchecked, arena_vec![self; ref_mut_pinned], ); - let new_unchecked = self.expr(span, new_unchecked_expr_kind, ThinVec::new()); - let get_context = self.expr_call_std_path_mut( + let get_context = self.expr_call_lang_item_fn_mut( gen_future_span, - &[sym::future, sym::get_context], + hir::LangItem::GetContext, arena_vec![self; task_context], ); - let call = self.expr_call_std_path( + let call = self.expr_call_lang_item_fn( span, - &[sym::future, sym::Future, sym::poll], + hir::LangItem::FuturePoll, arena_vec![self; new_unchecked, get_context], ); self.arena.alloc(self.expr_unsafe(call)) @@ -659,11 +650,8 @@ impl<'hir> LoweringContext<'_, 'hir> { let x_ident = Ident::with_dummy_span(sym::result); let (x_pat, x_pat_hid) = self.pat_ident(span, x_ident); let x_expr = self.expr_ident(span, x_ident, x_pat_hid); - let ready_pat = self.pat_std_enum( - span, - &[sym::task, sym::Poll, sym::Ready], - arena_vec![self; x_pat], - ); + let ready_field = self.single_pat_field(span, x_pat); + let ready_pat = self.pat_lang_item_variant(span, hir::LangItem::PollReady, ready_field); let break_x = self.with_loop_scope(loop_node_id, move |this| { let expr_break = hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr)); @@ -674,7 +662,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // `::std::task::Poll::Pending => {}` let pending_arm = { - let pending_pat = self.pat_std_enum(span, &[sym::task, sym::Poll, sym::Pending], &[]); + let pending_pat = self.pat_lang_item_variant(span, hir::LangItem::PollPending, &[]); let empty_block = self.expr_block_empty(span); self.arm(pending_pat, empty_block) }; @@ -842,16 +830,12 @@ impl<'hir> LoweringContext<'_, 'hir> { /// Desugar `..=` into `std::ops::RangeInclusive::new(, )`. fn lower_expr_range_closed(&mut self, span: Span, e1: &Expr, e2: &Expr) -> hir::ExprKind<'hir> { - let id = self.next_id(); let e1 = self.lower_expr_mut(e1); let e2 = self.lower_expr_mut(e2); - self.expr_call_std_assoc_fn( - id, - span, - &[sym::ops, sym::RangeInclusive], - "new", - arena_vec![self; e1, e2], - ) + let fn_path = hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, span); + let fn_expr = + self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path), ThinVec::new())); + hir::ExprKind::Call(fn_expr, arena_vec![self; e1, e2]) } fn lower_expr_range( @@ -863,12 +847,12 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> hir::ExprKind<'hir> { use rustc_ast::ast::RangeLimits::*; - let path = match (e1, e2, lims) { - (None, None, HalfOpen) => sym::RangeFull, - (Some(..), None, HalfOpen) => sym::RangeFrom, - (None, Some(..), HalfOpen) => sym::RangeTo, - (Some(..), Some(..), HalfOpen) => sym::Range, - (None, Some(..), Closed) => sym::RangeToInclusive, + let lang_item = match (e1, e2, lims) { + (None, None, HalfOpen) => hir::LangItem::RangeFull, + (Some(..), None, HalfOpen) => hir::LangItem::RangeFrom, + (None, Some(..), HalfOpen) => hir::LangItem::RangeTo, + (Some(..), Some(..), HalfOpen) => hir::LangItem::Range, + (None, Some(..), Closed) => hir::LangItem::RangeToInclusive, (Some(..), Some(..), Closed) => unreachable!(), (_, None, Closed) => { self.diagnostic().span_fatal(span, "inclusive range with no end").raise() @@ -883,16 +867,7 @@ impl<'hir> LoweringContext<'_, 'hir> { }), ); - let is_unit = fields.is_empty(); - let struct_path = [sym::ops, path]; - let struct_path = self.std_path(span, &struct_path, None, is_unit); - let struct_path = hir::QPath::Resolved(None, struct_path); - - if is_unit { - hir::ExprKind::Path(struct_path) - } else { - hir::ExprKind::Struct(self.arena.alloc(struct_path), fields, None) - } + hir::ExprKind::Struct(self.arena.alloc(hir::QPath::LangItem(lang_item, span)), fields, None) } fn lower_loop_destination(&mut self, destination: Option<(NodeId, Label)>) -> hir::Destination { @@ -1412,9 +1387,11 @@ impl<'hir> LoweringContext<'_, 'hir> { let match_expr = { let iter = self.expr_ident(desugared_span, iter, iter_pat_nid); let ref_mut_iter = self.expr_mut_addr_of(desugared_span, iter); - let next_path = &[sym::iter, sym::Iterator, sym::next]; - let next_expr = - self.expr_call_std_path(desugared_span, next_path, arena_vec![self; ref_mut_iter]); + let next_expr = self.expr_call_lang_item_fn( + desugared_span, + hir::LangItem::IteratorNext, + arena_vec![self; ref_mut_iter], + ); let arms = arena_vec![self; pat_arm, break_arm]; self.expr_match(desugared_span, next_expr, arms, hir::MatchSource::ForLoopDesugar) @@ -1472,8 +1449,11 @@ impl<'hir> LoweringContext<'_, 'hir> { // `match ::std::iter::IntoIterator::into_iter() { ... }` let into_iter_expr = { - let into_iter_path = &[sym::iter, sym::IntoIterator, sym::into_iter]; - self.expr_call_std_path(into_iter_span, into_iter_path, arena_vec![self; head]) + self.expr_call_lang_item_fn( + into_iter_span, + hir::LangItem::IntoIterIntoIter, + arena_vec![self; head], + ) }; let match_expr = self.arena.alloc(self.expr_match( @@ -1521,8 +1501,11 @@ impl<'hir> LoweringContext<'_, 'hir> { // expand let sub_expr = self.lower_expr_mut(sub_expr); - let path = &[sym::ops, sym::Try, sym::into_result]; - self.expr_call_std_path(unstable_span, path, arena_vec![self; sub_expr]) + self.expr_call_lang_item_fn( + unstable_span, + hir::LangItem::TryIntoResult, + arena_vec![self; sub_expr], + ) }; // `#[allow(unreachable_code)]` @@ -1558,12 +1541,19 @@ impl<'hir> LoweringContext<'_, 'hir> { let err_ident = Ident::with_dummy_span(sym::err); let (err_local, err_local_nid) = self.pat_ident(try_span, err_ident); let from_expr = { - let from_path = &[sym::convert, sym::From, sym::from]; let err_expr = self.expr_ident_mut(try_span, err_ident, err_local_nid); - self.expr_call_std_path(try_span, from_path, arena_vec![self; err_expr]) + self.expr_call_lang_item_fn( + try_span, + hir::LangItem::FromFrom, + arena_vec![self; err_expr], + ) }; - let from_err_expr = - self.wrap_in_try_constructor(sym::from_error, unstable_span, from_expr, try_span); + let from_err_expr = self.wrap_in_try_constructor( + hir::LangItem::TryFromError, + unstable_span, + from_expr, + try_span, + ); let thin_attrs = ThinVec::from(attrs); let catch_scope = self.catch_scopes.last().copied(); let ret_expr = if let Some(catch_node) = catch_scope { @@ -1674,63 +1664,32 @@ impl<'hir> LoweringContext<'_, 'hir> { self.arena.alloc(self.expr_call_mut(span, e, args)) } - // Note: associated functions must use `expr_call_std_path`. - fn expr_call_std_path_mut( + fn expr_call_lang_item_fn_mut( &mut self, span: Span, - path_components: &[Symbol], + lang_item: hir::LangItem, args: &'hir [hir::Expr<'hir>], ) -> hir::Expr<'hir> { - let path = - self.arena.alloc(self.expr_std_path(span, path_components, None, ThinVec::new())); + let path = self.arena.alloc(self.expr_lang_item_path(span, lang_item, ThinVec::new())); self.expr_call_mut(span, path, args) } - fn expr_call_std_path( + fn expr_call_lang_item_fn( &mut self, span: Span, - path_components: &[Symbol], + lang_item: hir::LangItem, args: &'hir [hir::Expr<'hir>], ) -> &'hir hir::Expr<'hir> { - self.arena.alloc(self.expr_call_std_path_mut(span, path_components, args)) - } - - // Create an expression calling an associated function of an std type. - // - // Associated functions cannot be resolved through the normal `std_path` function, - // as they are resolved differently and so cannot use `expr_call_std_path`. - // - // This function accepts the path component (`ty_path_components`) separately from - // the name of the associated function (`assoc_fn_name`) in order to facilitate - // separate resolution of the type and creation of a path referring to its associated - // function. - fn expr_call_std_assoc_fn( - &mut self, - ty_path_id: hir::HirId, - span: Span, - ty_path_components: &[Symbol], - assoc_fn_name: &str, - args: &'hir [hir::Expr<'hir>], - ) -> hir::ExprKind<'hir> { - let ty_path = self.std_path(span, ty_path_components, None, false); - let ty = - self.arena.alloc(self.ty_path(ty_path_id, span, hir::QPath::Resolved(None, ty_path))); - let fn_seg = self.arena.alloc(hir::PathSegment::from_ident(Ident::from_str(assoc_fn_name))); - let fn_path = hir::QPath::TypeRelative(ty, fn_seg); - let fn_expr = - self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path), ThinVec::new())); - hir::ExprKind::Call(fn_expr, args) + self.arena.alloc(self.expr_call_lang_item_fn_mut(span, lang_item, args)) } - fn expr_std_path( + fn expr_lang_item_path( &mut self, span: Span, - components: &[Symbol], - params: Option<&'hir hir::GenericArgs<'hir>>, + lang_item: hir::LangItem, attrs: AttrVec, ) -> hir::Expr<'hir> { - let path = self.std_path(span, components, params, true); - self.expr(span, hir::ExprKind::Path(hir::QPath::Resolved(None, path)), attrs) + self.expr(span, hir::ExprKind::Path(hir::QPath::LangItem(lang_item, span)), attrs) } pub(super) fn expr_ident( diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index 7cfde3fc6d2dc..a2962008a6bd4 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -85,8 +85,6 @@ const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF; rustc_hir::arena_types!(rustc_arena::declare_arena, [], 'tcx); struct LoweringContext<'a, 'hir: 'a> { - crate_root: Option, - /// Used to assign IDs to HIR nodes that do not directly correspond to AST nodes. sess: &'a Session, @@ -189,16 +187,6 @@ pub trait ResolverAstLowering { /// This should only return `None` during testing. fn definitions(&mut self) -> &mut Definitions; - /// Given suffix `["b", "c", "d"]`, creates an AST path for `[::crate_root]::b::c::d` and - /// resolves it based on `is_value`. - fn resolve_str_path( - &mut self, - span: Span, - crate_root: Option, - components: &[Symbol], - ns: Namespace, - ) -> (ast::Path, Res); - fn lint_buffer(&mut self) -> &mut LintBuffer; fn next_node_id(&mut self) -> NodeId; @@ -305,7 +293,6 @@ pub fn lower_crate<'a, 'hir>( let _prof_timer = sess.prof.verbose_generic_activity("hir_lowering"); LoweringContext { - crate_root: sess.parse_sess.injected_crate_name.get().copied(), sess, resolver, nt_to_tokenstream, @@ -2064,23 +2051,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }; // "" - let future_params = self.arena.alloc(hir::GenericArgs { + let future_args = self.arena.alloc(hir::GenericArgs { args: &[], bindings: arena_vec![self; self.output_ty_binding(span, output_ty)], parenthesized: false, }); - // ::std::future::Future - let future_path = - self.std_path(span, &[sym::future, sym::Future], Some(future_params), false); - - hir::GenericBound::Trait( - hir::PolyTraitRef { - trait_ref: hir::TraitRef { path: future_path, hir_ref_id: self.next_id() }, - bound_generic_params: &[], - span, - }, - hir::TraitBoundModifier::None, + hir::GenericBound::LangItemTrait( + // ::std::future::Future + hir::LangItem::FutureTraitLangItem, + span, + self.next_id(), + future_args, ) } @@ -2480,35 +2462,47 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } fn pat_ok(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> { - self.pat_std_enum(span, &[sym::result, sym::Result, sym::Ok], arena_vec![self; pat]) + let field = self.single_pat_field(span, pat); + self.pat_lang_item_variant(span, hir::LangItem::ResultOk, field) } fn pat_err(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> { - self.pat_std_enum(span, &[sym::result, sym::Result, sym::Err], arena_vec![self; pat]) + let field = self.single_pat_field(span, pat); + self.pat_lang_item_variant(span, hir::LangItem::ResultErr, field) } fn pat_some(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> { - self.pat_std_enum(span, &[sym::option, sym::Option, sym::Some], arena_vec![self; pat]) + let field = self.single_pat_field(span, pat); + self.pat_lang_item_variant(span, hir::LangItem::OptionSome, field) } fn pat_none(&mut self, span: Span) -> &'hir hir::Pat<'hir> { - self.pat_std_enum(span, &[sym::option, sym::Option, sym::None], &[]) + self.pat_lang_item_variant(span, hir::LangItem::OptionNone, &[]) } - fn pat_std_enum( + fn single_pat_field( &mut self, span: Span, - components: &[Symbol], - subpats: &'hir [&'hir hir::Pat<'hir>], - ) -> &'hir hir::Pat<'hir> { - let path = self.std_path(span, components, None, true); - let qpath = hir::QPath::Resolved(None, path); - let pt = if subpats.is_empty() { - hir::PatKind::Path(qpath) - } else { - hir::PatKind::TupleStruct(qpath, subpats, None) + pat: &'hir hir::Pat<'hir>, + ) -> &'hir [hir::FieldPat<'hir>] { + let field = hir::FieldPat { + hir_id: self.next_id(), + ident: Ident::new(sym::integer(0), span), + is_shorthand: false, + pat, + span, }; - self.pat(span, pt) + arena_vec![self; field] + } + + fn pat_lang_item_variant( + &mut self, + span: Span, + lang_item: hir::LangItem, + fields: &'hir [hir::FieldPat<'hir>], + ) -> &'hir hir::Pat<'hir> { + let qpath = hir::QPath::LangItem(lang_item, span); + self.pat(span, hir::PatKind::Struct(qpath, fields, false)) } fn pat_ident(&mut self, span: Span, ident: Ident) -> (&'hir hir::Pat<'hir>, hir::HirId) { @@ -2541,42 +2535,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.arena.alloc(hir::Pat { hir_id: self.next_id(), kind, span }) } - /// Given a suffix `["b", "c", "d"]`, returns path `::std::b::c::d` when - /// `fld.cx.use_std`, and `::core::b::c::d` otherwise. - /// The path is also resolved according to `is_value`. - fn std_path( - &mut self, - span: Span, - components: &[Symbol], - params: Option<&'hir hir::GenericArgs<'hir>>, - is_value: bool, - ) -> &'hir hir::Path<'hir> { - let ns = if is_value { Namespace::ValueNS } else { Namespace::TypeNS }; - let (path, res) = self.resolver.resolve_str_path(span, self.crate_root, components, ns); - - let mut segments: Vec<_> = path - .segments - .iter() - .map(|segment| { - let res = self.expect_full_res(segment.id); - hir::PathSegment { - ident: segment.ident, - hir_id: Some(self.lower_node_id(segment.id)), - res: Some(self.lower_res(res)), - infer_args: true, - args: None, - } - }) - .collect(); - segments.last_mut().unwrap().args = params; - - self.arena.alloc(hir::Path { - span, - res: res.map_id(|_| panic!("unexpected `NodeId`")), - segments: self.arena.alloc_from_iter(segments), - }) - } - fn ty_path( &mut self, mut hir_id: hir::HirId, diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index 928235adac30c..e1ec60bcc0a2c 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -1,7 +1,7 @@ use crate::def::{DefKind, Namespace, Res}; use crate::def_id::DefId; crate use crate::hir_id::HirId; -use crate::itemlikevisit; +use crate::{itemlikevisit, LangItem}; use rustc_ast::ast::{self, CrateSugar, LlvmAsmDialect}; use rustc_ast::ast::{AttrVec, Attribute, FloatTy, IntTy, Label, LitKind, StrStyle, UintTy}; @@ -363,6 +363,8 @@ pub enum TraitBoundModifier { #[derive(Debug, HashStable_Generic)] pub enum GenericBound<'hir> { Trait(PolyTraitRef<'hir>, TraitBoundModifier), + // FIXME(davidtwco): Introduce `PolyTraitRef::LangItem` + LangItemTrait(LangItem, Span, HirId, &'hir GenericArgs<'hir>), Outlives(Lifetime), } @@ -377,6 +379,7 @@ impl GenericBound<'_> { pub fn span(&self) -> Span { match self { &GenericBound::Trait(ref t, ..) => t.span, + &GenericBound::LangItemTrait(_, span, ..) => span, &GenericBound::Outlives(ref l) => l.span, } } @@ -1419,10 +1422,10 @@ impl Expr<'_> { self.is_place_expr(|_| true) } - // Whether this is a place expression. - // `allow_projections_from` should return `true` if indexing a field or - // index expression based on the given expression should be considered a - // place expression. + /// Whether this is a place expression. + /// + /// `allow_projections_from` should return `true` if indexing a field or index expression based + /// on the given expression should be considered a place expression. pub fn is_place_expr(&self, mut allow_projections_from: impl FnMut(&Self) -> bool) -> bool { match self.kind { ExprKind::Path(QPath::Resolved(_, ref path)) => match path.res { @@ -1441,6 +1444,9 @@ impl Expr<'_> { allow_projections_from(base) || base.is_place_expr(allow_projections_from) } + // Lang item paths cannot currently be local variables or statics. + ExprKind::Path(QPath::LangItem(..)) => false, + // Partially qualified paths in expressions can only legally // refer to associated items which are always rvalues. ExprKind::Path(QPath::TypeRelative(..)) @@ -1677,6 +1683,40 @@ pub enum QPath<'hir> { /// `::new`, and `T::X::Y::method` into `<<::X>::Y>::method`, /// the `X` and `Y` nodes each being a `TyKind::Path(QPath::TypeRelative(..))`. TypeRelative(&'hir Ty<'hir>, &'hir PathSegment<'hir>), + + /// Reference to a `#[lang = "foo"]` item. + LangItem(LangItem, Span), +} + +impl<'hir> QPath<'hir> { + /// Returns the span of this `QPath`. + pub fn span(&self) -> Span { + match *self { + QPath::Resolved(_, path) => path.span, + QPath::TypeRelative(_, ps) => ps.ident.span, + QPath::LangItem(_, span) => span, + } + } + + /// Returns the span of the qself of this `QPath`. For example, `()` in + /// `<() as Trait>::method`. + pub fn qself_span(&self) -> Span { + match *self { + QPath::Resolved(_, path) => path.span, + QPath::TypeRelative(qself, _) => qself.span, + QPath::LangItem(_, span) => span, + } + } + + /// Returns the span of the last segment of this `QPath`. For example, `method` in + /// `<() as Trait>::method`. + pub fn last_segment_span(&self) -> Span { + match *self { + QPath::Resolved(_, path) => path.segments.last().unwrap().ident.span, + QPath::TypeRelative(_, segment) => segment.ident.span, + QPath::LangItem(_, span) => span, + } + } } /// Hints at the original code for a let statement. diff --git a/src/librustc_hir/intravisit.rs b/src/librustc_hir/intravisit.rs index 23d642731da4d..66ef017713447 100644 --- a/src/librustc_hir/intravisit.rs +++ b/src/librustc_hir/intravisit.rs @@ -724,6 +724,7 @@ pub fn walk_qpath<'v, V: Visitor<'v>>( visitor.visit_ty(qself); visitor.visit_path_segment(span, segment); } + QPath::LangItem(..) => {} } } @@ -838,6 +839,10 @@ pub fn walk_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v GenericB GenericBound::Trait(ref typ, modifier) => { visitor.visit_poly_trait_ref(typ, modifier); } + GenericBound::LangItemTrait(_, span, hir_id, args) => { + visitor.visit_id(hir_id); + visitor.visit_generic_args(span, args); + } GenericBound::Outlives(ref lifetime) => visitor.visit_lifetime(lifetime), } } diff --git a/src/librustc_hir_pretty/lib.rs b/src/librustc_hir_pretty/lib.rs index 2298a80ae4f1f..e124db9e355dd 100644 --- a/src/librustc_hir_pretty/lib.rs +++ b/src/librustc_hir_pretty/lib.rs @@ -1729,6 +1729,11 @@ impl<'a> State<'a> { colons_before_params, ) } + hir::QPath::LangItem(lang_item, span) => { + self.s.word("#[lang = \""); + self.print_ident(Ident::new(lang_item.name(), span)); + self.s.word("\"]"); + } } } @@ -2142,6 +2147,11 @@ impl<'a> State<'a> { } self.print_poly_trait_ref(tref); } + GenericBound::LangItemTrait(lang_item, span, ..) => { + self.s.word("#[lang = \""); + self.print_ident(Ident::new(lang_item.name(), *span)); + self.s.word("\"]"); + } GenericBound::Outlives(lt) => { self.print_lifetime(lt); } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 3859d0f163ad5..97830e6c86f39 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1057,7 +1057,7 @@ impl TypeAliasBounds { _ => false, } } - hir::QPath::Resolved(..) => false, + hir::QPath::Resolved(..) | hir::QPath::LangItem(..) => false, } } diff --git a/src/librustc_lint/context.rs b/src/librustc_lint/context.rs index 31d30a264a59e..5b91b77e4f02d 100644 --- a/src/librustc_lint/context.rs +++ b/src/librustc_lint/context.rs @@ -703,7 +703,7 @@ impl<'tcx> LateContext<'tcx> { pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res { match *qpath { hir::QPath::Resolved(_, ref path) => path.res, - hir::QPath::TypeRelative(..) => self + hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self .maybe_typeck_results() .and_then(|typeck_results| typeck_results.type_dependent_def(id)) .map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)), diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index 6887f72932267..3b10cb5388506 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -445,7 +445,7 @@ impl<'tcx> TypeckResults<'tcx> { pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res { match *qpath { hir::QPath::Resolved(_, ref path) => path.res, - hir::QPath::TypeRelative(..) => self + hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self .type_dependent_def(id) .map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)), } diff --git a/src/librustc_passes/liveness.rs b/src/librustc_passes/liveness.rs index 6477f8da008ad..62c8680a85798 100644 --- a/src/librustc_passes/liveness.rs +++ b/src/librustc_passes/liveness.rs @@ -526,7 +526,8 @@ fn visit_expr<'tcx>(ir: &mut IrMaps<'tcx>, expr: &'tcx Expr<'tcx>) { | hir::ExprKind::Yield(..) | hir::ExprKind::Type(..) | hir::ExprKind::Err - | hir::ExprKind::Path(hir::QPath::TypeRelative(..)) => { + | hir::ExprKind::Path(hir::QPath::TypeRelative(..)) + | hir::ExprKind::Path(hir::QPath::LangItem(..)) => { intravisit::walk_expr(ir, expr); } } @@ -1310,7 +1311,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprKind::Lit(..) | hir::ExprKind::Err - | hir::ExprKind::Path(hir::QPath::TypeRelative(..)) => succ, + | hir::ExprKind::Path(hir::QPath::TypeRelative(..)) + | hir::ExprKind::Path(hir::QPath::LangItem(..)) => succ, // Note that labels have been resolved, so we don't need to look // at the label ident diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index a3f2668691fd8..deb4277cb3854 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -1325,7 +1325,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { Res::Def(kind, def_id) => Some((kind, def_id)), _ => None, }, - hir::QPath::TypeRelative(..) => self + hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self .maybe_typeck_results .and_then(|typeck_results| typeck_results.type_dependent_def(id)), }; @@ -1340,7 +1340,9 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { let sess = self.tcx.sess; let sm = sess.source_map(); let name = match qpath { - hir::QPath::Resolved(_, path) => sm.span_to_snippet(path.span).ok(), + hir::QPath::Resolved(..) | hir::QPath::LangItem(..) => { + sm.span_to_snippet(qpath.span()).ok() + } hir::QPath::TypeRelative(_, segment) => Some(segment.ident.to_string()), }; let kind = kind.descr(def_id); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 339a5ae6675e7..32b8ea410ad22 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1076,37 +1076,6 @@ impl ResolverAstLowering for Resolver<'_> { self.cstore().item_generics_num_lifetimes(def_id, sess) } - fn resolve_str_path( - &mut self, - span: Span, - crate_root: Option, - components: &[Symbol], - ns: Namespace, - ) -> (ast::Path, Res) { - let root = if crate_root.is_some() { kw::PathRoot } else { kw::Crate }; - let segments = iter::once(Ident::with_dummy_span(root)) - .chain( - crate_root - .into_iter() - .chain(components.iter().cloned()) - .map(Ident::with_dummy_span), - ) - .map(|i| self.new_ast_path_segment(i)) - .collect::>(); - - let path = ast::Path { span, segments }; - - let parent_scope = &ParentScope::module(self.graph_root); - let res = match self.resolve_ast_path(&path, ns, parent_scope) { - Ok(res) => res, - Err((span, error)) => { - self.report_error(span, error); - Res::Err - } - }; - (path, res) - } - fn get_partial_res(&mut self, id: NodeId) -> Option { self.partial_res_map.get(&id).cloned() } diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index f33d2f46aa269..c1c165a9901f8 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -705,6 +705,7 @@ impl<'tcx> DumpVisitor<'tcx> { let trait_ref = match *super_bound { hir::GenericBound::Trait(ref trait_ref, _) => trait_ref, hir::GenericBound::Outlives(..) => continue, + hir::GenericBound::LangItemTrait(..) => unimplemented!(), }; let trait_ref = &trait_ref.trait_ref; @@ -765,6 +766,7 @@ impl<'tcx> DumpVisitor<'tcx> { let span = match path { hir::QPath::Resolved(_, path) => path.span, hir::QPath::TypeRelative(_, segment) => segment.ident.span, + hir::QPath::LangItem(..) => unimplemented!(), }; if self.span.filter_generated(span) { return; @@ -783,6 +785,7 @@ impl<'tcx> DumpVisitor<'tcx> { self.visit_ty(ty); std::slice::from_ref(*segment) } + hir::QPath::LangItem(..) => unimplemented!(), }; for seg in segments { if let Some(ref generic_args) = seg.args { @@ -1358,6 +1361,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> { let sub_span = match path { hir::QPath::Resolved(_, path) => path.segments.last().unwrap().ident.span, hir::QPath::TypeRelative(_, segment) => segment.ident.span, + hir::QPath::LangItem(..) => unimplemented!(), }; let span = self.span_from_span(sub_span); self.dumper.dump_ref(Ref { diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index ca98ada4e5729..a7eb344ff09f7 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -555,6 +555,7 @@ impl<'tcx> SaveContext<'tcx> { let segment = match qpath { hir::QPath::Resolved(_, path) => path.segments.last().unwrap(), hir::QPath::TypeRelative(_, segment) => segment, + hir::QPath::LangItem(..) => unimplemented!(), }; match ty.kind { ty::Adt(def, _) => { @@ -639,6 +640,7 @@ impl<'tcx> SaveContext<'tcx> { hir::QPath::TypeRelative(..) => self .maybe_typeck_results .map_or(Res::Err, |typeck_results| typeck_results.qpath_res(qpath, hir_id)), + hir::QPath::LangItem(..) => unimplemented!(), }, Node::Binding(&hir::Pat { @@ -653,6 +655,7 @@ impl<'tcx> SaveContext<'tcx> { let segment = match path { hir::QPath::Resolved(_, path) => path.segments.last(), hir::QPath::TypeRelative(_, segment) => Some(*segment), + hir::QPath::LangItem(..) => unimplemented!(), }; segment.and_then(|seg| { self.get_path_segment_data(seg).or_else(|| self.get_path_segment_data_with_id(seg, id)) diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index 33355c4c558fb..6a9ad3c38f496 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -286,6 +286,7 @@ impl<'hir> Sig for hir::Ty<'hir> { refs: vec![SigElement { id, start, end }], }) } + hir::TyKind::Path(hir::QPath::LangItem(..)) => unimplemented!(), hir::TyKind::TraitObject(bounds, ..) => { // FIXME recurse into bounds let bounds: Vec> = bounds diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 5170a060c5fe0..5e52a5ef16fb5 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1202,6 +1202,36 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ) } + pub fn instantiate_lang_item_trait_ref( + &self, + lang_item: hir::LangItem, + span: Span, + hir_id: hir::HirId, + args: &GenericArgs<'_>, + self_ty: Ty<'tcx>, + bounds: &mut Bounds<'tcx>, + ) { + let trait_def_id = self.tcx().require_lang_item(lang_item, Some(span)); + + let (substs, assoc_bindings, _) = + self.create_substs_for_ast_path(span, trait_def_id, &[], args, false, Some(self_ty)); + let poly_trait_ref = ty::Binder::bind(ty::TraitRef::new(trait_def_id, substs)); + bounds.trait_bounds.push((poly_trait_ref, span, Constness::NotConst)); + + let mut dup_bindings = FxHashMap::default(); + for binding in assoc_bindings { + let _: Result<_, ErrorReported> = self.add_predicates_for_ast_type_binding( + hir_id, + poly_trait_ref, + &binding, + bounds, + false, + &mut dup_bindings, + span, + ); + } + } + fn ast_path_to_mono_trait_ref( &self, span: Span, @@ -1392,6 +1422,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { trait_bounds.push((b, Constness::NotConst)) } hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => {} + hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => self + .instantiate_lang_item_trait_ref( + lang_item, span, hir_id, args, param_ty, bounds, + ), hir::GenericBound::Outlives(ref l) => region_bounds.push(l), } } @@ -2960,6 +2994,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .map(|(ty, _, _)| ty) .unwrap_or_else(|_| tcx.ty_error()) } + hir::TyKind::Path(hir::QPath::LangItem(lang_item, span)) => { + let def_id = tcx.require_lang_item(lang_item, Some(span)); + let (substs, _, _) = self.create_substs_for_ast_path( + span, + def_id, + &[], + &GenericArgs::none(), + true, + None, + ); + self.normalize_ty(span, tcx.at(span).type_of(def_id).subst(tcx, substs)) + } hir::TyKind::Array(ref ty, ref length) => { let length_def_id = tcx.hir().local_def_id(length.hir_id); let length = ty::Const::from_anon_const(tcx, length_def_id); diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index e88f13a1f3ab6..e2c90cce178fe 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -236,6 +236,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ExprKind::AddrOf(kind, mutbl, ref oprnd) => { self.check_expr_addr_of(kind, mutbl, oprnd, expected, expr) } + ExprKind::Path(QPath::LangItem(lang_item, _)) => { + self.check_lang_item_path(lang_item, expr) + } ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr), ExprKind::InlineAsm(asm) => self.check_expr_asm(asm), ExprKind::LlvmInlineAsm(ref asm) => { @@ -447,6 +450,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + fn check_lang_item_path( + &self, + lang_item: hir::LangItem, + expr: &'tcx hir::Expr<'tcx>, + ) -> Ty<'tcx> { + self.resolve_lang_item_path(lang_item, expr.span, expr.hir_id).1 + } + fn check_expr_path(&self, qpath: &hir::QPath<'_>, expr: &'tcx hir::Expr<'tcx>) -> Ty<'tcx> { let tcx = self.tcx; let (res, opt_ty, segs) = self.resolve_ty_and_res_ufcs(qpath, expr.hir_id, expr.span); @@ -1077,11 +1088,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return self.tcx.ty_error(); }; - let path_span = match *qpath { - QPath::Resolved(_, ref path) => path.span, - QPath::TypeRelative(ref qself, _) => qself.span, - }; - // Prohibit struct expressions when non-exhaustive flag is set. let adt = adt_ty.ty_adt_def().expect("`check_struct_path` returned non-ADT type"); if !adt.did.is_local() && variant.is_field_list_non_exhaustive() { @@ -1099,7 +1105,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { adt_ty, expected, expr.hir_id, - path_span, + qpath.span(), variant, fields, base_expr.is_none(), diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index a625b5ea40567..c46d2388f3d93 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -122,10 +122,9 @@ use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::{self, InternalSubsts, Subst, SubstsRef}; use rustc_middle::ty::subst::{GenericArgKind, UserSelfTy, UserSubsts}; use rustc_middle::ty::util::{Discr, IntTypeExt, Representability}; -use rustc_middle::ty::{ - self, AdtKind, CanonicalUserType, Const, GenericParamDefKind, RegionKind, ToPolyTraitRef, - ToPredicate, Ty, TyCtxt, UserType, WithConstness, -}; +use rustc_middle::ty::WithConstness; +use rustc_middle::ty::{self, AdtKind, CanonicalUserType, Const, DefIdTree, GenericParamDefKind}; +use rustc_middle::ty::{RegionKind, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, UserType}; use rustc_session::config::{self, EntryFnType}; use rustc_session::lint; use rustc_session::parse::feature_err; @@ -4430,10 +4429,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { qpath: &QPath<'_>, hir_id: hir::HirId, ) -> Option<(&'tcx ty::VariantDef, Ty<'tcx>)> { - let path_span = match *qpath { - QPath::Resolved(_, ref path) => path.span, - QPath::TypeRelative(ref qself, _) => qself.span, - }; + let path_span = qpath.qself_span(); let (def, ty) = self.finish_resolving_struct_path(qpath, path_span, hir_id); let variant = match def { Res::Err => { @@ -4511,9 +4507,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err), ty) } + QPath::LangItem(lang_item, span) => { + self.resolve_lang_item_path(lang_item, span, hir_id) + } } } + fn resolve_lang_item_path( + &self, + lang_item: hir::LangItem, + span: Span, + hir_id: hir::HirId, + ) -> (Res, Ty<'tcx>) { + let def_id = self.tcx.require_lang_item(lang_item, Some(span)); + let def_kind = self.tcx.def_kind(def_id); + + let item_ty = if let DefKind::Variant = def_kind { + self.tcx.type_of(self.tcx.parent(def_id).expect("variant w/out parent")) + } else { + self.tcx.type_of(def_id) + }; + let substs = self.infcx.fresh_substs_for_item(span, def_id); + let ty = item_ty.subst(self.tcx, substs); + + self.write_resolution(hir_id, Ok((def_kind, def_id))); + self.add_required_obligations(span, def_id, &substs); + (Res::Def(def_kind, def_id), ty) + } + /// Resolves an associated value path into a base type and associated constant, or method /// resolution. The newly resolved definition is written into `type_dependent_defs`. pub fn resolve_ty_and_res_ufcs<'b>( @@ -4532,6 +4553,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } QPath::TypeRelative(ref qself, ref segment) => (self.to_ty(qself), qself, segment), + QPath::LangItem(..) => bug!("`resolve_ty_and_res_ufcs` called on `LangItem`"), }; if let Some(&cached_result) = self.typeck_results.borrow().type_dependent_defs().get(hir_id) { diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index 1c78bef98527a..35c7b7a703cc0 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -947,13 +947,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // | // L | let A(()) = A(()); // | ^ ^ - [] => { - let qpath_span = match qpath { - hir::QPath::Resolved(_, path) => path.span, - hir::QPath::TypeRelative(_, ps) => ps.ident.span, - }; - (qpath_span.shrink_to_hi(), pat_span) - } + [] => (qpath.span().shrink_to_hi(), pat_span), // Easy case. Just take the "lo" of the first sub-pattern and the "hi" of the // last sub-pattern. In the case of `A(x)` the first and last may coincide. // This looks like: diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index da1f3ea62f239..15743b0643662 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1959,6 +1959,20 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat predicates.extend(bounds.predicates(tcx, ty)); } + &hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => { + let mut bounds = Bounds::default(); + AstConv::instantiate_lang_item_trait_ref( + &icx, + lang_item, + span, + hir_id, + args, + ty, + &mut bounds, + ); + predicates.extend(bounds.predicates(tcx, ty)); + } + &hir::GenericBound::Outlives(ref lifetime) => { let region = AstConv::ast_region_to_region(&icx, lifetime, None); predicates.push(( @@ -2108,6 +2122,18 @@ fn predicates_from_bound<'tcx>( let _ = astconv.instantiate_poly_trait_ref(tr, constness, param_ty, &mut bounds); bounds.predicates(astconv.tcx(), param_ty) } + hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => { + let mut bounds = Bounds::default(); + astconv.instantiate_lang_item_trait_ref( + lang_item, + span, + hir_id, + args, + param_ty, + &mut bounds, + ); + bounds.predicates(astconv.tcx(), param_ty) + } hir::GenericBound::Outlives(ref lifetime) => { let region = astconv.ast_region_to_region(lifetime, None); let pred = ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(param_ty, region)) diff --git a/src/test/ui/hygiene/hir-res-hygiene.rs b/src/test/ui/hygiene/hir-res-hygiene.rs index e5af1000dd53e..c26cf5fdb5b05 100644 --- a/src/test/ui/hygiene/hir-res-hygiene.rs +++ b/src/test/ui/hygiene/hir-res-hygiene.rs @@ -1,27 +1,4 @@ -//~ ERROR failed to resolve: could not find `future` in `std` [E0433] -//~^ ERROR failed to resolve: could not find `pin` in `std` [E0433] -//~^^ ERROR failed to resolve: could not find `future` in `std` [E0433] -//~^^^ ERROR failed to resolve: could not find `future` in `std` [E0433] -//~^^^^ ERROR failed to resolve: could not find `task` in `std` [E0433] -//~^^^^^ ERROR failed to resolve: could not find `task` in `std` [E0433] -//~^^^^^^ ERROR failed to resolve: could not find `future` in `std` [E0433] -//~^^^^^^^ ERROR failed to resolve: could not find `future` in `std` [E0433] -//~^^^^^^^^ ERROR failed to resolve: could not find `ops` in `std` [E0433] -//~^^^^^^^^^ ERROR failed to resolve: could not find `option` in `std` [E0433] -//~^^^^^^^^^^ ERROR failed to resolve: could not find `option` in `std` [E0433] -//~^^^^^^^^^^^ ERROR failed to resolve: could not find `iter` in `std` [E0433] -//~^^^^^^^^^^^^ ERROR failed to resolve: could not find `iter` in `std` [E0433] -//~^^^^^^^^^^^^^ ERROR failed to resolve: could not find `ops` in `std` [E0433] -//~^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `option` in `std` [E0433] -//~^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `option` in `std` [E0433] -//~^^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `iter` in `std` [E0433] -//~^^^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `iter` in `std` [E0433] -//~^^^^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `ops` in `std` [E0433] -//~^^^^^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `result` in `std` [E0433] -//~^^^^^^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `convert` in `std` [E0433] -//~^^^^^^^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `ops` in `std` [E0433] -//~^^^^^^^^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `result` in `std` [E0433] - +// check-pass // edition:2018 // aux-build:not-libstd.rs diff --git a/src/test/ui/hygiene/hir-res-hygiene.stderr b/src/test/ui/hygiene/hir-res-hygiene.stderr deleted file mode 100644 index 73a1bd5c62632..0000000000000 --- a/src/test/ui/hygiene/hir-res-hygiene.stderr +++ /dev/null @@ -1,49 +0,0 @@ -error[E0433]: failed to resolve: could not find `future` in `std` - -error[E0433]: failed to resolve: could not find `pin` in `std` - -error[E0433]: failed to resolve: could not find `future` in `std` - -error[E0433]: failed to resolve: could not find `future` in `std` - -error[E0433]: failed to resolve: could not find `task` in `std` - -error[E0433]: failed to resolve: could not find `task` in `std` - -error[E0433]: failed to resolve: could not find `future` in `std` - -error[E0433]: failed to resolve: could not find `future` in `std` - -error[E0433]: failed to resolve: could not find `ops` in `std` - -error[E0433]: failed to resolve: could not find `option` in `std` - -error[E0433]: failed to resolve: could not find `option` in `std` - -error[E0433]: failed to resolve: could not find `iter` in `std` - -error[E0433]: failed to resolve: could not find `iter` in `std` - -error[E0433]: failed to resolve: could not find `ops` in `std` - -error[E0433]: failed to resolve: could not find `option` in `std` - -error[E0433]: failed to resolve: could not find `option` in `std` - -error[E0433]: failed to resolve: could not find `iter` in `std` - -error[E0433]: failed to resolve: could not find `iter` in `std` - -error[E0433]: failed to resolve: could not find `ops` in `std` - -error[E0433]: failed to resolve: could not find `result` in `std` - -error[E0433]: failed to resolve: could not find `convert` in `std` - -error[E0433]: failed to resolve: could not find `ops` in `std` - -error[E0433]: failed to resolve: could not find `result` in `std` - -error: aborting due to 23 previous errors - -For more information about this error, try `rustc --explain E0433`. From 1e2f350d921e73d7165fe9d7a5f0f6cfe613e3df Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 4 Aug 2020 14:36:09 +0100 Subject: [PATCH 16/24] save_analysis: support `QPath::LangItem` This commit implements support for `QPath::LangItem` and `GenericBound::LangItemTrait` in save analysis. Signed-off-by: David Wood --- src/librustc_save_analysis/dump_visitor.rs | 30 +++++++--------- src/librustc_save_analysis/lib.rs | 42 +++++++++------------- src/librustc_save_analysis/sig.rs | 4 ++- 3 files changed, 32 insertions(+), 44 deletions(-) diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index c1c165a9901f8..6e56e3b9ebb70 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -702,15 +702,18 @@ impl<'tcx> DumpVisitor<'tcx> { // super-traits for super_bound in trait_refs.iter() { - let trait_ref = match *super_bound { - hir::GenericBound::Trait(ref trait_ref, _) => trait_ref, + let (def_id, sub_span) = match *super_bound { + hir::GenericBound::Trait(ref trait_ref, _) => ( + self.lookup_def_id(trait_ref.trait_ref.hir_ref_id), + trait_ref.trait_ref.path.segments.last().unwrap().ident.span, + ), + hir::GenericBound::LangItemTrait(lang_item, span, _, _) => { + (Some(self.tcx.require_lang_item(lang_item, Some(span))), span) + } hir::GenericBound::Outlives(..) => continue, - hir::GenericBound::LangItemTrait(..) => unimplemented!(), }; - let trait_ref = &trait_ref.trait_ref; - if let Some(id) = self.lookup_def_id(trait_ref.hir_ref_id) { - let sub_span = trait_ref.path.segments.last().unwrap().ident.span; + if let Some(id) = def_id { if !self.span.filter_generated(sub_span) { let span = self.span_from_span(sub_span); self.dumper.dump_ref(Ref { @@ -763,12 +766,7 @@ impl<'tcx> DumpVisitor<'tcx> { } fn process_path(&mut self, id: hir::HirId, path: &hir::QPath<'tcx>) { - let span = match path { - hir::QPath::Resolved(_, path) => path.span, - hir::QPath::TypeRelative(_, segment) => segment.ident.span, - hir::QPath::LangItem(..) => unimplemented!(), - }; - if self.span.filter_generated(span) { + if self.span.filter_generated(path.span()) { return; } self.dump_path_ref(id, path); @@ -785,7 +783,7 @@ impl<'tcx> DumpVisitor<'tcx> { self.visit_ty(ty); std::slice::from_ref(*segment) } - hir::QPath::LangItem(..) => unimplemented!(), + hir::QPath::LangItem(..) => return, }; for seg in segments { if let Some(ref generic_args) = seg.args { @@ -1358,11 +1356,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> { } if let Some(id) = self.lookup_def_id(t.hir_id) { - let sub_span = match path { - hir::QPath::Resolved(_, path) => path.segments.last().unwrap().ident.span, - hir::QPath::TypeRelative(_, segment) => segment.ident.span, - hir::QPath::LangItem(..) => unimplemented!(), - }; + let sub_span = path.last_segment_span(); let span = self.span_from_span(sub_span); self.dumper.dump_ref(Ref { kind: RefKind::Type, diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index a7eb344ff09f7..fc8a5384739de 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -551,29 +551,22 @@ impl<'tcx> SaveContext<'tcx> { } } } - hir::ExprKind::Struct(qpath, ..) => { - let segment = match qpath { - hir::QPath::Resolved(_, path) => path.segments.last().unwrap(), - hir::QPath::TypeRelative(_, segment) => segment, - hir::QPath::LangItem(..) => unimplemented!(), - }; - match ty.kind { - ty::Adt(def, _) => { - let sub_span = segment.ident.span; - filter!(self.span_utils, sub_span); - let span = self.span_from_span(sub_span); - Some(Data::RefData(Ref { - kind: RefKind::Type, - span, - ref_id: id_from_def_id(def.did), - })) - } - _ => { - debug!("expected adt, found {:?}", ty); - None - } + hir::ExprKind::Struct(qpath, ..) => match ty.kind { + ty::Adt(def, _) => { + let sub_span = qpath.last_segment_span(); + filter!(self.span_utils, sub_span); + let span = self.span_from_span(sub_span); + Some(Data::RefData(Ref { + kind: RefKind::Type, + span, + ref_id: id_from_def_id(def.did), + })) } - } + _ => { + debug!("expected adt, found {:?}", ty); + None + } + }, hir::ExprKind::MethodCall(ref seg, ..) => { let method_id = match self.typeck_results().type_dependent_def_id(expr.hir_id) { Some(id) => id, @@ -637,10 +630,9 @@ impl<'tcx> SaveContext<'tcx> { }) | Node::Ty(&hir::Ty { kind: hir::TyKind::Path(ref qpath), .. }) => match qpath { hir::QPath::Resolved(_, path) => path.res, - hir::QPath::TypeRelative(..) => self + hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self .maybe_typeck_results .map_or(Res::Err, |typeck_results| typeck_results.qpath_res(qpath, hir_id)), - hir::QPath::LangItem(..) => unimplemented!(), }, Node::Binding(&hir::Pat { @@ -655,7 +647,7 @@ impl<'tcx> SaveContext<'tcx> { let segment = match path { hir::QPath::Resolved(_, path) => path.segments.last(), hir::QPath::TypeRelative(_, segment) => Some(*segment), - hir::QPath::LangItem(..) => unimplemented!(), + hir::QPath::LangItem(..) => None, }; segment.and_then(|seg| { self.get_path_segment_data(seg).or_else(|| self.get_path_segment_data_with_id(seg, id)) diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index 6a9ad3c38f496..f6869cbbfd2aa 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -286,7 +286,9 @@ impl<'hir> Sig for hir::Ty<'hir> { refs: vec![SigElement { id, start, end }], }) } - hir::TyKind::Path(hir::QPath::LangItem(..)) => unimplemented!(), + hir::TyKind::Path(hir::QPath::LangItem(lang_item, _)) => { + Ok(text_sig(format!("#[lang = \"{}\"]", lang_item.name()))) + } hir::TyKind::TraitObject(bounds, ..) => { // FIXME recurse into bounds let bounds: Vec> = bounds From 664ecf1085b1bab9d7444eb54dccfeeabd99446e Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 4 Aug 2020 14:18:11 +0100 Subject: [PATCH 17/24] hir: simplify `is_range_literal` This commit simplifies `is_range_literal` by checking for `QPath::LangItem` containing range-related lang items, rather than using a heuristic. Co-authored-by: Matthew Jasper Signed-off-by: David Wood --- src/librustc_hir/hir.rs | 60 ++++++++--------------------- src/librustc_lint/types.rs | 4 +- src/librustc_typeck/check/demand.rs | 2 +- src/test/ui/range/range-1.stderr | 6 ++- 4 files changed, 23 insertions(+), 49 deletions(-) diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index e1ec60bcc0a2c..bfcb506f1326f 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -13,7 +13,7 @@ use rustc_ast::util::parser::ExprPrecedence; use rustc_data_structures::sync::{par_for_each_in, Send, Sync}; use rustc_macros::HashStable_Generic; use rustc_span::def_id::LocalDefId; -use rustc_span::source_map::{SourceMap, Spanned}; +use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{MultiSpan, Span, DUMMY_SP}; use rustc_target::asm::InlineAsmRegOrRegClass; @@ -1495,58 +1495,28 @@ impl Expr<'_> { /// Checks if the specified expression is a built-in range literal. /// (See: `LoweringContext::lower_expr()`). -/// -/// FIXME(#60607): This function is a hack. If and when we have `QPath::Lang(...)`, -/// we can use that instead as simpler, more reliable mechanism, as opposed to using `SourceMap`. -pub fn is_range_literal(sm: &SourceMap, expr: &Expr<'_>) -> bool { - // Returns whether the given path represents a (desugared) range, - // either in std or core, i.e. has either a `::std::ops::Range` or - // `::core::ops::Range` prefix. - fn is_range_path(path: &Path<'_>) -> bool { - let segs: Vec<_> = path.segments.iter().map(|seg| seg.ident.to_string()).collect(); - let segs: Vec<_> = segs.iter().map(|seg| &**seg).collect(); - - // "{{root}}" is the equivalent of `::` prefix in `Path`. - if let ["{{root}}", std_core, "ops", range] = segs.as_slice() { - (*std_core == "std" || *std_core == "core") && range.starts_with("Range") - } else { - false - } - }; - - // Check whether a span corresponding to a range expression is a - // range literal, rather than an explicit struct or `new()` call. - fn is_lit(sm: &SourceMap, span: &Span) -> bool { - sm.span_to_snippet(*span).map(|range_src| range_src.contains("..")).unwrap_or(false) - }; - +pub fn is_range_literal(expr: &Expr<'_>) -> bool { match expr.kind { // All built-in range literals but `..=` and `..` desugar to `Struct`s. - ExprKind::Struct(ref qpath, _, _) => { - if let QPath::Resolved(None, ref path) = **qpath { - return is_range_path(&path) && is_lit(sm, &expr.span); - } - } - - // `..` desugars to its struct path. - ExprKind::Path(QPath::Resolved(None, ref path)) => { - return is_range_path(&path) && is_lit(sm, &expr.span); - } + ExprKind::Struct(ref qpath, _, _) => matches!( + **qpath, + QPath::LangItem( + LangItem::Range + | LangItem::RangeTo + | LangItem::RangeFrom + | LangItem::RangeFull + | LangItem::RangeToInclusive, + _, + ) + ), // `..=` desugars into `::std::ops::RangeInclusive::new(...)`. ExprKind::Call(ref func, _) => { - if let ExprKind::Path(QPath::TypeRelative(ref ty, ref segment)) = func.kind { - if let TyKind::Path(QPath::Resolved(None, ref path)) = ty.kind { - let new_call = segment.ident.name == sym::new; - return is_range_path(&path) && is_lit(sm, &expr.span) && new_call; - } - } + matches!(func.kind, ExprKind::Path(QPath::LangItem(LangItem::RangeInclusiveNew, _))) } - _ => {} + _ => false, } - - false } #[derive(Debug, HashStable_Generic)] diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 5891abcfd9cd1..a1c9b05a684dd 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -258,7 +258,7 @@ fn lint_int_literal<'tcx>( let par_id = cx.tcx.hir().get_parent_node(e.hir_id); if let Node::Expr(par_e) = cx.tcx.hir().get(par_id) { if let hir::ExprKind::Struct(..) = par_e.kind { - if is_range_literal(cx.sess().source_map(), par_e) + if is_range_literal(par_e) && lint_overflowing_range_endpoint(cx, lit, v, max, e, par_e, t.name_str()) { // The overflowing literal lint was overridden. @@ -317,7 +317,7 @@ fn lint_uint_literal<'tcx>( return; } } - hir::ExprKind::Struct(..) if is_range_literal(cx.sess().source_map(), par_e) => { + hir::ExprKind::Struct(..) if is_range_literal(par_e) => { let t = t.name_str(); if lint_overflowing_range_endpoint(cx, lit, lit_val, max, e, par_e, t) { // The overflowing literal lint was overridden. diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 4ea76a4a9e2ab..ad97dbe63d8b3 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -485,7 +485,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // parenthesize if needed (Issue #46756) hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true, // parenthesize borrows of range literals (Issue #54505) - _ if is_range_literal(self.tcx.sess.source_map(), expr) => true, + _ if is_range_literal(expr) => true, _ => false, }; let sugg_expr = if needs_parens { format!("({})", src) } else { src }; diff --git a/src/test/ui/range/range-1.stderr b/src/test/ui/range/range-1.stderr index e179feba7a799..11cb72fa2b6f8 100644 --- a/src/test/ui/range/range-1.stderr +++ b/src/test/ui/range/range-1.stderr @@ -17,9 +17,13 @@ error[E0277]: the size for values of type `[{integer}]` cannot be known at compi | LL | let range = *arr..; | ^^^^^^ doesn't have a size known at compile-time + | + ::: $SRC_DIR/core/src/ops/range.rs:LL:COL + | +LL | pub struct RangeFrom { + | --- required by this bound in `std::ops::RangeFrom` | = help: the trait `std::marker::Sized` is not implemented for `[{integer}]` - = note: required by `std::ops::RangeFrom` error: aborting due to 3 previous errors From 8367af469b9005c8f5c1777a48548a80e4658076 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 4 Aug 2020 14:19:28 +0100 Subject: [PATCH 18/24] resolve: support `GenericBound::LangItemTrait` This commit modifies name resolution to ensure that new scopes are introduced from lang-item generic bounds. Co-authored-by: Matthew Jasper Signed-off-by: David Wood --- src/librustc_resolve/late/lifetimes.rs | 28 ++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/librustc_resolve/late/lifetimes.rs b/src/librustc_resolve/late/lifetimes.rs index e2f0d388f7e53..31360d474736a 100644 --- a/src/librustc_resolve/late/lifetimes.rs +++ b/src/librustc_resolve/late/lifetimes.rs @@ -941,6 +941,24 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } } + fn visit_param_bound(&mut self, bound: &'tcx hir::GenericBound<'tcx>) { + match bound { + hir::GenericBound::LangItemTrait { .. } if !self.trait_ref_hack => { + let scope = Scope::Binder { + lifetimes: FxHashMap::default(), + s: self.scope, + next_early_index: self.next_early_index(), + track_lifetime_uses: true, + opaque_type_parent: false, + }; + self.with(scope, |_, this| { + intravisit::walk_param_bound(this, bound); + }); + } + _ => intravisit::walk_param_bound(self, bound), + } + } + fn visit_poly_trait_ref( &mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>, @@ -2296,6 +2314,16 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { self.outer_index.shift_out(1); } + fn visit_param_bound(&mut self, bound: &hir::GenericBound<'_>) { + if let hir::GenericBound::LangItemTrait { .. } = bound { + self.outer_index.shift_in(1); + intravisit::walk_param_bound(self, bound); + self.outer_index.shift_out(1); + } else { + intravisit::walk_param_bound(self, bound); + } + } + fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) { if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.hir_id) { match lifetime { From dde93c9ba61e441bcafab84a1e42cddb32aa0178 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 4 Aug 2020 14:22:16 +0100 Subject: [PATCH 19/24] rustdoc: clean `QPath::LangItem` This commit adds support for cleaning `QPath::LangItem` and `hir::GenericBound::LangItemTrait` in rustdoc. `QPath::LangItem` does not require lowering, and `hir::GenericBound::LangItemTrait` is lowered to a `GenericBound::TraitBound`. Signed-off-by: David Wood --- src/librustdoc/clean/mod.rs | 20 ++++++++++++++++++++ src/librustdoc/clean/utils.rs | 1 + 2 files changed, 21 insertions(+) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 3ad357e583cf1..bf385fd79b0f2 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -17,6 +17,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX}; use rustc_index::vec::{Idx, IndexVec}; use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData}; +use rustc_middle::bug; use rustc_middle::middle::resolve_lifetime as rl; use rustc_middle::middle::stability; use rustc_middle::ty::fold::TypeFolder; @@ -291,6 +292,22 @@ impl Clean for hir::GenericBound<'_> { fn clean(&self, cx: &DocContext<'_>) -> GenericBound { match *self { hir::GenericBound::Outlives(lt) => GenericBound::Outlives(lt.clean(cx)), + hir::GenericBound::LangItemTrait(lang_item, span, _, generic_args) => { + let def_id = cx.tcx.require_lang_item(lang_item, Some(span)); + + let trait_ref = ty::TraitRef::identity(cx.tcx, def_id); + + let generic_args = generic_args.clean(cx); + let bindings = match generic_args { + GenericArgs::AngleBracketed { bindings, .. } => bindings, + _ => bug!("clean: parenthesized `GenericBound::LangItemTrait`"), + }; + + GenericBound::TraitBound( + PolyTrait { trait_: (trait_ref, &*bindings).clean(cx), generic_params: vec![] }, + hir::TraitBoundModifier::None, + ) + } hir::GenericBound::Trait(ref t, modifier) => { GenericBound::TraitBound(t.clean(cx), modifier) } @@ -1504,6 +1521,9 @@ impl Clean for hir::Ty<'_> { trait_: box resolve_type(cx, trait_path.clean(cx), self.hir_id), } } + TyKind::Path(hir::QPath::LangItem(..)) => { + bug!("clean: requiring documentation of lang item") + } TyKind::TraitObject(ref bounds, ref lifetime) => { match bounds[0].clean(cx).trait_ { ResolvedPath { path, param_names: None, did, is_generic } => { diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index a7d03fcabf546..a502a27948e29 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -335,6 +335,7 @@ pub fn qpath_to_string(p: &hir::QPath<'_>) -> String { let segments = match *p { hir::QPath::Resolved(_, ref path) => &path.segments, hir::QPath::TypeRelative(_, ref segment) => return segment.ident.to_string(), + hir::QPath::LangItem(lang_item, ..) => return lang_item.name().to_string(), }; let mut s = String::new(); From bde529fb773fa227e9bcaecd08754fd3a51b04c8 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 4 Aug 2020 14:24:13 +0100 Subject: [PATCH 20/24] clippy: support `QPath::LangItem` This commit updates clippy with the introduction of `QPath::LangItem` so that it still compiles. Signed-off-by: David Wood --- src/tools/clippy/clippy_lints/src/default_trait_access.rs | 2 +- src/tools/clippy/clippy_lints/src/types.rs | 1 + src/tools/clippy/clippy_lints/src/utils/author.rs | 1 + src/tools/clippy/clippy_lints/src/utils/hir_utils.rs | 6 ++++++ src/tools/clippy/clippy_lints/src/utils/inspector.rs | 6 ++++++ src/tools/clippy/clippy_lints/src/utils/mod.rs | 5 ++++- 6 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/default_trait_access.rs b/src/tools/clippy/clippy_lints/src/default_trait_access.rs index 874e19d9e9fb3..067ea903bdd96 100644 --- a/src/tools/clippy/clippy_lints/src/default_trait_access.rs +++ b/src/tools/clippy/clippy_lints/src/default_trait_access.rs @@ -68,7 +68,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultTraitAccess { ); } }, - QPath::TypeRelative(..) => {}, + QPath::TypeRelative(..) | QPath::LangItem(..) => {}, } } } diff --git a/src/tools/clippy/clippy_lints/src/types.rs b/src/tools/clippy/clippy_lints/src/types.rs index c3dea44752133..d1a7886a47eff 100644 --- a/src/tools/clippy/clippy_lints/src/types.rs +++ b/src/tools/clippy/clippy_lints/src/types.rs @@ -475,6 +475,7 @@ impl Types { } } }, + QPath::LangItem(..) => {}, } }, TyKind::Rptr(ref lt, ref mut_ty) => self.check_ty_rptr(cx, hir_ty, is_local, lt, mut_ty), diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 128fa87a16212..01850bb3df6ad 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -760,5 +760,6 @@ fn print_path(path: &QPath<'_>, first: &mut bool) { }, ref other => print!("/* unimplemented: {:?}*/", other), }, + QPath::LangItem(lang_item, ..) => print!("#[lang = \"{}\"]", lang_item.name()), } } diff --git a/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs b/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs index 28fb6ed12a05a..0ce402ee7fa86 100644 --- a/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs +++ b/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs @@ -601,6 +601,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { QPath::TypeRelative(_, ref path) => { self.hash_name(path.ident.name); }, + QPath::LangItem(lang_item, ..) => { + lang_item.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s); + } } // self.maybe_typeck_results.unwrap().qpath_res(p, id).hash(&mut self.s); } @@ -710,6 +713,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_ty(ty); segment.ident.name.hash(&mut self.s); }, + QPath::LangItem(lang_item, ..) => { + lang_item.hash(&mut self.s); + } }, TyKind::OpaqueDef(_, arg_list) => { self.hash_generic_args(arg_list); diff --git a/src/tools/clippy/clippy_lints/src/utils/inspector.rs b/src/tools/clippy/clippy_lints/src/utils/inspector.rs index d8fa1fa278e29..4701a3f26e6f7 100644 --- a/src/tools/clippy/clippy_lints/src/utils/inspector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/inspector.rs @@ -266,6 +266,9 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) { println!("{}Relative Path, {:?}", ind, ty); println!("{}seg: {:?}", ind, seg); }, + hir::ExprKind::Path(hir::QPath::LangItem(lang_item, ..)) => { + println!("{}Lang Item Path, {:?}", ind, lang_item.name()); + }, hir::ExprKind::AddrOf(kind, ref muta, ref e) => { println!("{}AddrOf", ind); println!("kind: {:?}", kind); @@ -488,6 +491,9 @@ fn print_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, indent: usize) { println!("{}Relative Path, {:?}", ind, ty); println!("{}seg: {:?}", ind, seg); }, + hir::PatKind::Path(hir::QPath::LangItem(lang_item, ..)) => { + println!("{}Lang Item Path, {:?}", ind, lang_item.name()); + }, hir::PatKind::Tuple(pats, opt_dots_position) => { println!("{}Tuple", ind); if let Some(dot_position) = opt_dots_position { diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs index 223628cc610da..d3c99eaa9cf9c 100644 --- a/src/tools/clippy/clippy_lints/src/utils/mod.rs +++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs @@ -163,6 +163,7 @@ pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> { match *path { QPath::Resolved(_, ref path) => path.segments.last().expect("A path must have at least one segment"), QPath::TypeRelative(_, ref seg) => seg, + QPath::LangItem(..) => panic!("last_path_segment: lang item has no path segments"), } } @@ -170,6 +171,7 @@ pub fn single_segment_path<'tcx>(path: &QPath<'tcx>) -> Option<&'tcx PathSegment match *path { QPath::Resolved(_, ref path) => path.segments.get(0), QPath::TypeRelative(_, ref seg) => Some(seg), + QPath::LangItem(..) => panic!("single_segment_path: lang item has no path segments"), } } @@ -196,6 +198,7 @@ pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool { }, _ => false, }, + QPath::LangItem(..) => panic!("match_qpath: lang item has no path segments"), } } @@ -277,7 +280,7 @@ pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Option { pub fn qpath_res(cx: &LateContext<'_>, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res { match qpath { hir::QPath::Resolved(_, path) => path.res, - hir::QPath::TypeRelative(..) => { + hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => { if cx.tcx.has_typeck_results(id.owner.to_def_id()) { cx.tcx.typeck(id.owner.to_def_id().expect_local()).qpath_res(qpath, id) } else { 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 21/24] 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 22/24] 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 23/24] 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 24/24] 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);