diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 3dc0ee2b55530..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!`]: ../macro.unreachable.html /// /// # Example /// @@ -61,7 +60,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() { diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 9bcacd8ddcf77..960cccc0fb211 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -6,9 +6,12 @@ //! as moving an object with pointers to itself will invalidate them, which could cause undefined //! behavior. //! -//! A [`Pin

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

`] ensures that the pointee of any pointer type +//! `P` has a stable location in memory, meaning it cannot be moved elsewhere +//! and its memory cannot be deallocated until it gets dropped. We say that the +//! pointee is "pinned". Things get more subtle when discussing types that +//! combine pinned with non-pinned data; [see below](#projections-and-structural-pinning) +//! for more details. //! //! By default, all types in Rust are movable. Rust allows passing all types by-value, //! and common smart-pointer types such as [`Box`] and `&mut T` allow replacing and @@ -61,6 +64,10 @@ //! //! # Example: self-referential struct //! +//! Before we go into more details to explain the guarantees and choices +//! associated with `Pin`, we discuss some examples for how it might be used. +//! Feel free to [skip to where the theoretical discussion continues](#drop-guarantee). +//! //! ```rust //! use std::pin::Pin; //! use std::marker::PhantomPinned; 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`. 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 diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs index 5186e62fbf9bc..699f5c9778a2f 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/src/librustc_ast_lowering/item.rs @@ -5,7 +5,7 @@ use crate::Arena; use rustc_ast::ast::*; 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_data_structures::fx::FxHashSet; use rustc_errors::struct_span_err; use rustc_hir as hir; @@ -75,6 +75,18 @@ impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> { } } + 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); + // 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), + } + } + 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/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/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 784815f27201f..d7eeaafbf46bf 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -65,6 +65,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> { @@ -1171,7 +1177,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. @@ -1179,10 +1185,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..3c79fe1225579 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}; @@ -72,8 +73,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/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_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs index 05cd1ae456b35..82160681ee8cf 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); @@ -325,24 +319,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 +372,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 +427,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 +489,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_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) { diff --git a/src/librustc_session/session.rs b/src/librustc_session/session.rs index 66dbe53bac387..f10f9b2ce93c5 100644 --- a/src/librustc_session/session.rs +++ b/src/librustc_session/session.rs @@ -437,6 +437,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) } 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); 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 + 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() {}