about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-08-16 22:00:29 +0000
committerbors <bors@rust-lang.org>2020-08-16 22:00:29 +0000
commit7e6d6e5f535321c2223f044caba16f97b825009c (patch)
tree2543a4394a25a4fe49011ab4f6fefb32bff84449
parent9b4db695b0ab13885a61deb1b2e4d6599b8c5bbc (diff)
parente46b1efd39849196471c18a5b66d60bfc8ca20a0 (diff)
downloadrust-7e6d6e5f535321c2223f044caba16f97b825009c.tar.gz
rust-7e6d6e5f535321c2223f044caba16f97b825009c.zip
Auto merge of #75609 - tmandry:rollup-yrcmgke, r=tmandry
Rollup of 10 pull requests

Successful merges:

 - #74204 (Don't visit foreign function bodies when lowering ast to hir)
 - #74314 (rustc_typeck: construct {Closure,Generator}Substs more directly.)
 - #74346 (Use LocalDefId instead of HirId for reachable_set elements.)
 - #74399 (Move DelaySpanBugEmitted to ty::context)
 - #75177 (Add regression test for issue-66768)
 - #75223 (Add #[track_caller] to `Session::delay_span_bug`)
 - #75423 (Move to intra-doc links for /library/core/src/hint.rs)
 - #75485 (pin docs: add some forward references)
 - #75569 (Bump minor version of emsdk to 1.38.47)
 - #75596 (Switch to intra-doc links in /sys/windows/ext/{ffi,fs,process}.rs)

Failed merges:

r? @ghost
-rw-r--r--library/core/src/hint.rs3
-rw-r--r--library/core/src/pin.rs13
-rw-r--r--library/std/src/sys/windows/ext/ffi.rs27
-rw-r--r--library/std/src/sys/windows/ext/fs.rs11
-rw-r--r--library/std/src/sys/windows/ext/process.rs4
-rw-r--r--src/ci/docker/scripts/emscripten.sh4
-rw-r--r--src/librustc_ast_lowering/item.rs14
-rw-r--r--src/librustc_codegen_ssa/back/symbol_export.rs8
-rw-r--r--src/librustc_middle/query/mod.rs3
-rw-r--r--src/librustc_middle/ty/consts/kind.rs2
-rw-r--r--src/librustc_middle/ty/context.rs13
-rw-r--r--src/librustc_middle/ty/mod.rs5
-rw-r--r--src/librustc_middle/ty/query/mod.rs2
-rw-r--r--src/librustc_middle/ty/sty.rs102
-rw-r--r--src/librustc_passes/reachable.rs99
-rw-r--r--src/librustc_session/session.rs1
-rw-r--r--src/librustc_typeck/check/closure.rs105
-rw-r--r--src/test/ui/foreign/issue-74120-lowering-of-ffi-block-bodies.rs11
-rw-r--r--src/test/ui/foreign/issue-74120-lowering-of-ffi-block-bodies.stderr19
-rw-r--r--src/test/ui/issues/issue-66768.rs205
20 files changed, 455 insertions, 196 deletions
diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs
index 3dc0ee2b555..461b4c79a1d 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 9bcacd8ddcf..960cccc0fb2 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<P>`] 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<P>`] 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<T>`] 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<T>`, 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 6e78119383f..1df2a0df143 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<u16>`; 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<u16> = 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 81b2bf99872..e0615f2d334 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 8c34a9faf1d..61e4c6a1d17 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 1be80741594..9f6a7f2e5db 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 5186e62fbf9..699f5c9778a 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 87d7f00c703..51cc1ada432 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 d364a464638..d874edf6274 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<LocalDefId> {
+            storage(ArenaCacheSelector<'tcx>)
             desc { "reachability" }
         }
 
diff --git a/src/librustc_middle/ty/consts/kind.rs b/src/librustc_middle/ty/consts/kind.rs
index a4c177160f5..ede28522000 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 784815f2720..d7eeaafbf46 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<Interned<'tcx, T>, ()>;
 
 pub struct CtxtInterners<'tcx> {
@@ -1171,7 +1177,7 @@ impl<'tcx> TyCtxt<'tcx> {
     #[track_caller]
     pub fn ty_error_with_message<S: Into<MultiSpan>>(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<T: Fn() -> String>(&self, msg: T) -> bool {
diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs
index 62a62085c66..3c79fe12255 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 b39c0b5190a..4d820f75c56 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 05cd1ae456b..82160681ee8 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 18fa4ada4da..8d5c980609c 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<LocalDefId>,
     // A worklist of item IDs. Each item ID in this worklist will be inlined
     // and will be scanned for further references.
-    worklist: Vec<hir::HirId>,
+    // FIXME(eddyb) benchmark if this would be faster as a `VecDeque`.
+    worklist: Vec<LocalDefId>,
     // 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<hir::HirId>,
+    worklist: &'a mut Vec<LocalDefId>,
 }
 
 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<LocalDefId> {
     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 66dbe53bac3..f10f9b2ce93 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<S: Into<MultiSpan>>(&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 255f611cfa3..c7f9e9d63e0 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 00000000000..a84065e0218
--- /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 00000000000..d4a9ca3e7c6
--- /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 00000000000..ce42c8b01cc
--- /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<Space>(material_surface_element: Edge2dElement)
+where
+    DefaultAllocator: FiniteElementAllocator<DimU1, Space>,
+{
+    let _: Point2<f64> = material_surface_element.map_reference_coords().into();
+}
+
+impl<T> ArrayLength<T> for UTerm {
+    type ArrayType = ();
+}
+impl<T, N: ArrayLength<T>> ArrayLength<T> for UInt<N, B0> {
+    type ArrayType = GenericArrayImplEven<T, N>;
+}
+impl<T, N: ArrayLength<T>> ArrayLength<T> for UInt<N, B1> {
+    type ArrayType = GenericArrayImplOdd<T, N>;
+}
+impl<U> Add<U> for UTerm {
+    type Output = U;
+    fn add(self, _: U) -> Self::Output {
+        unimplemented!()
+    }
+}
+impl<Ul, Ur> Add<UInt<Ur, B1>> for UInt<Ul, B0>
+where
+    Ul: Add<Ur>,
+{
+    type Output = UInt<Sum<Ul, Ur>, B1>;
+    fn add(self, _: UInt<Ur, B1>) -> Self::Output {
+        unimplemented!()
+    }
+}
+impl<U> Mul<U> for UTerm {
+    type Output = UTerm;
+    fn mul(self, _: U) -> Self {
+        unimplemented!()
+    }
+}
+impl<Ul, B, Ur> Mul<UInt<Ur, B>> for UInt<Ul, B0>
+where
+    Ul: Mul<UInt<Ur, B>>,
+{
+    type Output = UInt<Prod<Ul, UInt<Ur, B>>, B0>;
+    fn mul(self, _: UInt<Ur, B>) -> Self::Output {
+        unimplemented!()
+    }
+}
+impl<Ul, B, Ur> Mul<UInt<Ur, B>> for UInt<Ul, B1>
+where
+    Ul: Mul<UInt<Ur, B>>,
+    UInt<Prod<Ul, UInt<Ur, B>>, B0>: Add<UInt<Ur, B>>,
+{
+    type Output = Sum<UInt<Prod<Ul, UInt<Ur, B>>, B0>, UInt<Ur, B>>;
+    fn mul(self, _: UInt<Ur, B>) -> Self::Output {
+        unimplemented!()
+    }
+}
+impl<N, R, C> Allocator<N, R, C> for DefaultAllocator
+where
+    R: DimName,
+    C: DimName,
+    R::Value: Mul<C::Value>,
+    Prod<R::Value, C::Value>: ArrayLength<N>,
+{
+    type Buffer = ArrayStorage<N, R, C>;
+    fn allocate_uninitialized(_: R, _: C) -> Self::Buffer {
+        unimplemented!()
+    }
+    fn allocate_from_iterator<I>(_: R, _: C, _: I) -> Self::Buffer {
+        unimplemented!()
+    }
+}
+impl<N, C> Allocator<N, Dynamic, C> for DefaultAllocator {
+    type Buffer = VecStorage<N, Dynamic, C>;
+    fn allocate_uninitialized(_: Dynamic, _: C) -> Self::Buffer {
+        unimplemented!()
+    }
+    fn allocate_from_iterator<I>(_: 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<N, D> From<VectorN<N, D>> for Point<N, D>
+where
+    DefaultAllocator: Allocator<N, D>,
+{
+    fn from(_: VectorN<N, D>) -> Self {
+        unimplemented!()
+    }
+}
+impl<GeometryDim, NodalDim> FiniteElementAllocator<GeometryDim, NodalDim> for DefaultAllocator where
+    DefaultAllocator: Allocator<f64, GeometryDim> + Allocator<f64, NodalDim>
+{
+}
+impl ReferenceFiniteElement for Edge2dElement {
+    type NodalDim = DimU1;
+}
+impl FiniteElement<DimU2> for Edge2dElement {
+    fn map_reference_coords(&self) -> Vector2<f64> {
+        unimplemented!()
+    }
+}
+
+type Owned<N, R, C> = <DefaultAllocator as Allocator<N, R, C>>::Buffer;
+type MatrixMN<N, R, C> = Matrix<N, R, C, Owned<N, R, C>>;
+type VectorN<N, D> = MatrixMN<N, D, DimU1>;
+type Vector2<N> = VectorN<N, DimU2>;
+type Point2<N> = Point<N, DimU2>;
+type U1 = UInt<UTerm, B1>;
+type U2 = UInt<UInt<UTerm, B1>, B0>;
+type Sum<A, B> = <A as Add<B>>::Output;
+type Prod<A, B> = <A as Mul<B>>::Output;
+
+struct GenericArray<T, U: ArrayLength<T>> {
+    _data: U::ArrayType,
+}
+struct GenericArrayImplEven<T, U> {
+    _parent2: U,
+    _marker: T,
+}
+struct GenericArrayImplOdd<T, U> {
+    _parent2: U,
+    _data: T,
+}
+struct B0;
+struct B1;
+struct UTerm;
+struct UInt<U, B> {
+    _marker: PhantomData<(U, B)>,
+}
+struct DefaultAllocator;
+struct Dynamic;
+struct DimU1;
+struct DimU2;
+struct Matrix<N, R, C, S> {
+    _data: S,
+    _phantoms: PhantomData<(N, R, C)>,
+}
+struct ArrayStorage<N, R, C>
+where
+    R: DimName,
+    C: DimName,
+    R::Value: Mul<C::Value>,
+    Prod<R::Value, C::Value>: ArrayLength<N>,
+{
+    _data: GenericArray<N, Prod<R::Value, C::Value>>,
+}
+struct VecStorage<N, R, C> {
+    _data: N,
+    _nrows: R,
+    _ncols: C,
+}
+struct Point<N, D>
+where
+    DefaultAllocator: Allocator<N, D>,
+{
+    _coords: VectorN<N, D>,
+}
+struct Edge2dElement;
+
+trait ArrayLength<T> {
+    type ArrayType;
+}
+trait Allocator<Scalar, R, C = DimU1> {
+    type Buffer;
+    fn allocate_uninitialized(nrows: R, ncols: C) -> Self::Buffer;
+    fn allocate_from_iterator<I>(nrows: R, ncols: C, iter: I) -> Self::Buffer;
+}
+trait DimName {
+    type Value;
+    fn name() -> Self;
+}
+trait FiniteElementAllocator<GeometryDim, NodalDim>:
+    Allocator<f64, GeometryDim> + Allocator<f64, NodalDim>
+{
+}
+trait ReferenceFiniteElement {
+    type NodalDim;
+}
+trait FiniteElement<GeometryDim>: ReferenceFiniteElement
+where
+    DefaultAllocator: FiniteElementAllocator<GeometryDim, Self::NodalDim>,
+{
+    fn map_reference_coords(&self) -> VectorN<f64, GeometryDim>;
+}
+
+fn main() {}