summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-11-20 09:27:56 +0000
committerbors <bors@rust-lang.org>2024-11-20 09:27:56 +0000
commitfda68927475070696fcc9d1f5c9c990f0e1af87a (patch)
tree648a2d8ca6fafc7b16b07c0c6a38d0697c325015
parent70e814bd9e532a302763f870c665c5af59c2b632 (diff)
parentb9cd5eb1906b042dd3785f59c340d8b90ab9e144 (diff)
downloadrust-fda68927475070696fcc9d1f5c9c990f0e1af87a.tar.gz
rust-fda68927475070696fcc9d1f5c9c990f0e1af87a.zip
Auto merge of #133234 - jhpratt:rollup-42dmg4p, r=jhpratt
Rollup of 5 pull requests

Successful merges:

 - #132732 (Use attributes for `dangling_pointers_from_temporaries` lint)
 - #133108 (lints_that_dont_need_to_run: never skip future-compat-reported lints)
 - #133190 (CI: use free runner in dist-aarch64-msvc)
 - #133196 (Make rustc --explain compatible with BusyBox less)
 - #133216 (Implement `~const Fn` trait goal in the new solver)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs2
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs5
-rw-r--r--compiler/rustc_lint/src/dangling.rs27
-rw-r--r--compiler/rustc_lint/src/levels.rs22
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs14
-rw-r--r--compiler/rustc_middle/src/lint.rs7
-rw-r--r--compiler/rustc_middle/src/ty/context.rs6
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs70
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/effect_goals.rs55
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs10
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/trait_goals.rs10
-rw-r--r--compiler/rustc_passes/src/check_attr.rs3
-rw-r--r--compiler/rustc_span/src/symbol.rs3
-rw-r--r--compiler/rustc_type_ir/src/interner.rs3
-rw-r--r--library/alloc/src/boxed.rs2
-rw-r--r--library/alloc/src/vec/mod.rs2
-rw-r--r--library/core/src/cell.rs5
-rw-r--r--library/core/src/ffi/c_str.rs1
-rw-r--r--library/core/src/mem/maybe_uninit.rs2
-rw-r--r--library/core/src/slice/mod.rs2
-rw-r--r--library/core/src/str/mod.rs2
-rw-r--r--src/ci/github-actions/jobs.yml2
-rw-r--r--tests/ui/lint/dangling-pointers-from-temporaries/types.rs7
-rw-r--r--tests/ui/lint/dangling-pointers-from-temporaries/types.stderr54
-rw-r--r--tests/ui/traits/const-traits/const-fns-are-early-bound.rs90
-rw-r--r--tests/ui/traits/const-traits/effects/minicore-const-fn-early-bound.rs22
-rw-r--r--tests/ui/traits/const-traits/effects/minicore-fn-fail.rs21
-rw-r--r--tests/ui/traits/const-traits/effects/minicore-fn-fail.stderr9
-rw-r--r--tests/ui/traits/const-traits/effects/minicore-works.rs6
29 files changed, 305 insertions, 159 deletions
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index b6f7abed6f3..8dd043be6ad 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -577,7 +577,7 @@ fn show_md_content_with_pager(content: &str, color: ColorConfig) {
     let mut cmd = Command::new(&pager_name);
     // FIXME: find if other pagers accept color options
     let mut print_formatted = if pager_name == "less" {
-        cmd.arg("-r");
+        cmd.arg("-R");
         true
     } else {
         ["bat", "catbat", "delta"].iter().any(|v| *v == pager_name)
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index ce2b47ed1ea..fd08b35d242 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -880,6 +880,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         "lang items are subject to change",
     ),
     rustc_attr!(
+        rustc_as_ptr, Normal, template!(Word), ErrorFollowing,
+        EncodeCrossCrate::Yes,
+        "#[rustc_as_ptr] is used to mark functions returning pointers to their inner allocations."
+    ),
+    rustc_attr!(
         rustc_pass_by_value, Normal, template!(Word), ErrorFollowing,
         EncodeCrossCrate::Yes,
         "#[rustc_pass_by_value] is used to mark types that must be passed by value instead of reference."
diff --git a/compiler/rustc_lint/src/dangling.rs b/compiler/rustc_lint/src/dangling.rs
index a34c3e26778..e3e51ba263d 100644
--- a/compiler/rustc_lint/src/dangling.rs
+++ b/compiler/rustc_lint/src/dangling.rs
@@ -43,13 +43,10 @@ declare_lint! {
 }
 
 /// FIXME: false negatives (i.e. the lint is not emitted when it should be)
-/// 1. Method calls that are not checked for:
-///    - [`temporary_unsafe_cell.get()`][`core::cell::UnsafeCell::get()`]
-///    - [`temporary_sync_unsafe_cell.get()`][`core::cell::SyncUnsafeCell::get()`]
-/// 2. Ways to get a temporary that are not recognized:
+/// 1. Ways to get a temporary that are not recognized:
 ///    - `owning_temporary.field`
 ///    - `owning_temporary[index]`
-/// 3. No checks for ref-to-ptr conversions:
+/// 2. No checks for ref-to-ptr conversions:
 ///    - `&raw [mut] temporary`
 ///    - `&temporary as *(const|mut) _`
 ///    - `ptr::from_ref(&temporary)` and friends
@@ -133,10 +130,11 @@ impl DanglingPointerSearcher<'_, '_> {
 
 fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if let ExprKind::MethodCall(method, receiver, _args, _span) = expr.kind
-        && matches!(method.ident.name, sym::as_ptr | sym::as_mut_ptr)
+        && let Some(fn_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+        && cx.tcx.has_attr(fn_id, sym::rustc_as_ptr)
         && is_temporary_rvalue(receiver)
         && let ty = cx.typeck_results().expr_ty(receiver)
-        && is_interesting(cx.tcx, ty)
+        && owns_allocation(cx.tcx, ty)
     {
         // FIXME: use `emit_node_lint` when `#[primary_span]` is added.
         cx.tcx.emit_node_span_lint(
@@ -199,24 +197,25 @@ fn is_temporary_rvalue(expr: &Expr<'_>) -> bool {
     }
 }
 
-// Array, Vec, String, CString, MaybeUninit, Cell, Box<[_]>, Box<str>, Box<CStr>,
-// or any of the above in arbitrary many nested Box'es.
-fn is_interesting(tcx: TyCtxt<'_>, ty: Ty<'_>) -> bool {
+// Array, Vec, String, CString, MaybeUninit, Cell, Box<[_]>, Box<str>, Box<CStr>, UnsafeCell,
+// SyncUnsafeCell, or any of the above in arbitrary many nested Box'es.
+fn owns_allocation(tcx: TyCtxt<'_>, ty: Ty<'_>) -> bool {
     if ty.is_array() {
         true
     } else if let Some(inner) = ty.boxed_ty() {
         inner.is_slice()
             || inner.is_str()
             || inner.ty_adt_def().is_some_and(|def| tcx.is_lang_item(def.did(), LangItem::CStr))
-            || is_interesting(tcx, inner)
+            || owns_allocation(tcx, inner)
     } else if let Some(def) = ty.ty_adt_def() {
-        for lang_item in [LangItem::String, LangItem::MaybeUninit] {
+        for lang_item in [LangItem::String, LangItem::MaybeUninit, LangItem::UnsafeCell] {
             if tcx.is_lang_item(def.did(), lang_item) {
                 return true;
             }
         }
-        tcx.get_diagnostic_name(def.did())
-            .is_some_and(|name| matches!(name, sym::cstring_type | sym::Vec | sym::Cell))
+        tcx.get_diagnostic_name(def.did()).is_some_and(|name| {
+            matches!(name, sym::cstring_type | sym::Vec | sym::Cell | sym::SyncUnsafeCell)
+        })
     } else {
         false
     }
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 97a95787422..4b1dafbdbee 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -123,17 +123,19 @@ fn lints_that_dont_need_to_run(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LintId> {
     let dont_need_to_run: FxIndexSet<LintId> = store
         .get_lints()
         .into_iter()
+        .filter(|lint| {
+            // Lints that show up in future-compat reports must always be run.
+            let has_future_breakage =
+                lint.future_incompatible.is_some_and(|fut| fut.reason.has_future_breakage());
+            !has_future_breakage && !lint.eval_always
+        })
         .filter_map(|lint| {
-            if !lint.eval_always {
-                let lint_level = map.lint_level_id_at_node(tcx, LintId::of(lint), CRATE_HIR_ID);
-                if matches!(lint_level, (Level::Allow, ..))
-                    || (matches!(lint_level, (.., LintLevelSource::Default)))
-                        && lint.default_level(tcx.sess.edition()) == Level::Allow
-                {
-                    Some(LintId::of(lint))
-                } else {
-                    None
-                }
+            let lint_level = map.lint_level_id_at_node(tcx, LintId::of(lint), CRATE_HIR_ID);
+            if matches!(lint_level, (Level::Allow, ..))
+                || (matches!(lint_level, (.., LintLevelSource::Default)))
+                    && lint.default_level(tcx.sess.edition()) == Level::Allow
+            {
+                Some(LintId::of(lint))
             } else {
                 None
             }
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index eac4afee050..c74fceeedba 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -466,6 +466,20 @@ impl FutureIncompatibilityReason {
             | FutureIncompatibilityReason::Custom(_) => None,
         }
     }
+
+    pub fn has_future_breakage(self) -> bool {
+        match self {
+            FutureIncompatibilityReason::FutureReleaseErrorReportInDeps => true,
+
+            FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps
+            | FutureIncompatibilityReason::FutureReleaseSemanticsChange
+            | FutureIncompatibilityReason::EditionError(_)
+            | FutureIncompatibilityReason::EditionSemanticsChange(_)
+            | FutureIncompatibilityReason::EditionAndFutureReleaseError(_)
+            | FutureIncompatibilityReason::EditionAndFutureReleaseSemanticsChange(_)
+            | FutureIncompatibilityReason::Custom(_) => false,
+        }
+    }
 }
 
 impl FutureIncompatibleInfo {
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index 92ba6ceee93..971d036fa69 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -290,12 +290,7 @@ pub fn lint_level(
         let has_future_breakage = future_incompatible.map_or(
             // Default allow lints trigger too often for testing.
             sess.opts.unstable_opts.future_incompat_test && lint.default_level != Level::Allow,
-            |incompat| {
-                matches!(
-                    incompat.reason,
-                    FutureIncompatibilityReason::FutureReleaseErrorReportInDeps
-                )
-            },
+            |incompat| incompat.reason.has_future_breakage(),
         );
 
         // Convert lint level to error level.
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 68c3b064eee..ad42eacf823 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -376,7 +376,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
         self.explicit_implied_predicates_of(def_id).map_bound(|preds| preds.into_iter().copied())
     }
 
-    fn is_const_impl(self, def_id: DefId) -> bool {
+    fn impl_is_const(self, def_id: DefId) -> bool {
+        self.is_conditionally_const(def_id)
+    }
+
+    fn fn_is_const(self, def_id: DefId) -> bool {
         self.is_conditionally_const(def_id)
     }
 
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
index 5c1a7852dc0..a56febec48c 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
@@ -633,6 +633,76 @@ fn coroutine_closure_to_ambiguous_coroutine<I: Interner>(
     )
 }
 
+/// This duplicates `extract_tupled_inputs_and_output_from_callable` but needs
+/// to return different information (namely, the def id and args) so that we can
+/// create const conditions.
+///
+/// Doing so on all calls to `extract_tupled_inputs_and_output_from_callable`
+/// would be wasteful.
+pub(in crate::solve) fn extract_fn_def_from_const_callable<I: Interner>(
+    cx: I,
+    self_ty: I::Ty,
+) -> Result<(ty::Binder<I, (I::FnInputTys, I::Ty)>, I::DefId, I::GenericArgs), NoSolution> {
+    match self_ty.kind() {
+        ty::FnDef(def_id, args) => {
+            let sig = cx.fn_sig(def_id);
+            if sig.skip_binder().is_fn_trait_compatible()
+                && !cx.has_target_features(def_id)
+                && cx.fn_is_const(def_id)
+            {
+                Ok((
+                    sig.instantiate(cx, args).map_bound(|sig| (sig.inputs(), sig.output())),
+                    def_id,
+                    args,
+                ))
+            } else {
+                return Err(NoSolution);
+            }
+        }
+        // `FnPtr`s are not const for now.
+        ty::FnPtr(..) => {
+            return Err(NoSolution);
+        }
+        // `Closure`s are not const for now.
+        ty::Closure(..) => {
+            return Err(NoSolution);
+        }
+        // `CoroutineClosure`s are not const for now.
+        ty::CoroutineClosure(..) => {
+            return Err(NoSolution);
+        }
+
+        ty::Bool
+        | ty::Char
+        | ty::Int(_)
+        | ty::Uint(_)
+        | ty::Float(_)
+        | ty::Adt(_, _)
+        | ty::Foreign(_)
+        | ty::Str
+        | ty::Array(_, _)
+        | ty::Slice(_)
+        | ty::RawPtr(_, _)
+        | ty::Ref(_, _, _)
+        | ty::Dynamic(_, _, _)
+        | ty::Coroutine(_, _)
+        | ty::CoroutineWitness(..)
+        | ty::Never
+        | ty::Tuple(_)
+        | ty::Pat(_, _)
+        | ty::Alias(_, _)
+        | ty::Param(_)
+        | ty::Placeholder(..)
+        | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
+        | ty::Error(_) => return Err(NoSolution),
+
+        ty::Bound(..)
+        | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
+            panic!("unexpected type `{self_ty:?}`")
+        }
+    }
+}
+
 /// Assemble a list of predicates that would be present on a theoretical
 /// user impl for an object type. These predicates must be checked any time
 /// we assemble a built-in object candidate for an object type, since they
diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
index 0912e5effa6..282ca2fedbc 100644
--- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
@@ -3,15 +3,15 @@
 
 use rustc_type_ir::fast_reject::DeepRejectCtxt;
 use rustc_type_ir::inherent::*;
+use rustc_type_ir::lang_items::TraitSolverLangItem;
 use rustc_type_ir::{self as ty, Interner, elaborate};
 use tracing::instrument;
 
-use super::assembly::Candidate;
+use super::assembly::{Candidate, structural_traits};
 use crate::delegate::SolverDelegate;
-use crate::solve::assembly::{self};
 use crate::solve::{
     BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, NoSolution,
-    QueryResult,
+    QueryResult, assembly,
 };
 
 impl<D, I> assembly::GoalKind<D> for ty::HostEffectPredicate<I>
@@ -142,7 +142,7 @@ where
             ty::ImplPolarity::Positive => {}
         };
 
-        if !cx.is_const_impl(impl_def_id) {
+        if !cx.impl_is_const(impl_def_id) {
             return Err(NoSolution);
         }
 
@@ -207,7 +207,7 @@ where
         _ecx: &mut EvalCtxt<'_, D>,
         _goal: Goal<I, Self>,
     ) -> Result<Candidate<I>, NoSolution> {
-        todo!("Copy/Clone is not yet const")
+        Err(NoSolution)
     }
 
     fn consider_builtin_pointer_like_candidate(
@@ -225,11 +225,48 @@ where
     }
 
     fn consider_builtin_fn_trait_candidates(
-        _ecx: &mut EvalCtxt<'_, D>,
-        _goal: Goal<I, Self>,
+        ecx: &mut EvalCtxt<'_, D>,
+        goal: Goal<I, Self>,
         _kind: rustc_type_ir::ClosureKind,
     ) -> Result<Candidate<I>, NoSolution> {
-        todo!("Fn* are not yet const")
+        let cx = ecx.cx();
+
+        let self_ty = goal.predicate.self_ty();
+        let (inputs_and_output, def_id, args) =
+            structural_traits::extract_fn_def_from_const_callable(cx, self_ty)?;
+
+        // A built-in `Fn` impl only holds if the output is sized.
+        // (FIXME: technically we only need to check this if the type is a fn ptr...)
+        let output_is_sized_pred = inputs_and_output.map_bound(|(_, output)| {
+            ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [output])
+        });
+        let requirements = cx
+            .const_conditions(def_id)
+            .iter_instantiated(cx, args)
+            .map(|trait_ref| {
+                (
+                    GoalSource::ImplWhereBound,
+                    goal.with(cx, trait_ref.to_host_effect_clause(cx, goal.predicate.constness)),
+                )
+            })
+            .chain([(GoalSource::ImplWhereBound, goal.with(cx, output_is_sized_pred))]);
+
+        let pred = inputs_and_output
+            .map_bound(|(inputs, _)| {
+                ty::TraitRef::new(cx, goal.predicate.def_id(), [
+                    goal.predicate.self_ty(),
+                    Ty::new_tup(cx, inputs.as_slice()),
+                ])
+            })
+            .to_host_effect_clause(cx, goal.predicate.constness);
+
+        Self::probe_and_consider_implied_clause(
+            ecx,
+            CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
+            goal,
+            pred,
+            requirements,
+        )
     }
 
     fn consider_builtin_async_fn_trait_candidates(
@@ -314,7 +351,7 @@ where
         _ecx: &mut EvalCtxt<'_, D>,
         _goal: Goal<I, Self>,
     ) -> Result<Candidate<I>, NoSolution> {
-        unreachable!("Destruct is not const")
+        Err(NoSolution)
     }
 
     fn consider_builtin_transmute_candidate(
diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
index 129744b4db7..8a01659953d 100644
--- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
@@ -394,6 +394,9 @@ where
                     return ecx.forced_ambiguity(MaybeCause::Ambiguity);
                 }
             };
+
+        // A built-in `Fn` impl only holds if the output is sized.
+        // (FIXME: technically we only need to check this if the type is a fn ptr...)
         let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| {
             ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [output])
         });
@@ -408,8 +411,6 @@ where
             })
             .upcast(cx);
 
-        // A built-in `Fn` impl only holds if the output is sized.
-        // (FIXME: technically we only need to check this if the type is a fn ptr...)
         Self::probe_and_consider_implied_clause(
             ecx,
             CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
@@ -438,6 +439,9 @@ where
                 goal_kind,
                 env_region,
             )?;
+
+        // A built-in `AsyncFn` impl only holds if the output is sized.
+        // (FIXME: technically we only need to check this if the type is a fn ptr...)
         let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound(
             |AsyncCallableRelevantTypes { output_coroutine_ty: output_ty, .. }| {
                 ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [output_ty])
@@ -494,8 +498,6 @@ where
             )
             .upcast(cx);
 
-        // A built-in `AsyncFn` impl only holds if the output is sized.
-        // (FIXME: technically we only need to check this if the type is a fn ptr...)
         Self::probe_and_consider_implied_clause(
             ecx,
             CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index 5f740590712..e64d4eed9d8 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -326,6 +326,9 @@ where
                     return ecx.forced_ambiguity(MaybeCause::Ambiguity);
                 }
             };
+
+        // A built-in `Fn` impl only holds if the output is sized.
+        // (FIXME: technically we only need to check this if the type is a fn ptr...)
         let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| {
             ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [output])
         });
@@ -335,8 +338,6 @@ where
                 ty::TraitRef::new(cx, goal.predicate.def_id(), [goal.predicate.self_ty(), inputs])
             })
             .upcast(cx);
-        // A built-in `Fn` impl only holds if the output is sized.
-        // (FIXME: technically we only need to check this if the type is a fn ptr...)
         Self::probe_and_consider_implied_clause(
             ecx,
             CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
@@ -364,6 +365,9 @@ where
                 // This region doesn't matter because we're throwing away the coroutine type
                 Region::new_static(cx),
             )?;
+
+        // A built-in `AsyncFn` impl only holds if the output is sized.
+        // (FIXME: technically we only need to check this if the type is a fn ptr...)
         let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound(
             |AsyncCallableRelevantTypes { output_coroutine_ty, .. }| {
                 ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [
@@ -380,8 +384,6 @@ where
                 ])
             })
             .upcast(cx);
-        // A built-in `AsyncFn` impl only holds if the output is sized.
-        // (FIXME: technically we only need to check this if the type is a fn ptr...)
         Self::probe_and_consider_implied_clause(
             ecx,
             CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 836511325f4..87069e0b057 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -162,6 +162,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     self.check_rustc_std_internal_symbol(attr, span, target)
                 }
                 [sym::naked, ..] => self.check_naked(hir_id, attr, span, target, attrs),
+                [sym::rustc_as_ptr, ..] => {
+                    self.check_applied_to_fn_or_method(hir_id, attr, span, target)
+                }
                 [sym::rustc_never_returns_null_ptr, ..] => {
                     self.check_applied_to_fn_or_method(hir_id, attr, span, target)
                 }
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index e4261822040..a2d9859645f 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -316,6 +316,7 @@ symbols! {
         SubdiagMessage,
         Subdiagnostic,
         Sync,
+        SyncUnsafeCell,
         T,
         Target,
         ToOwned,
@@ -409,7 +410,6 @@ symbols! {
         arm,
         arm_target_feature,
         array,
-        as_mut_ptr,
         as_ptr,
         as_ref,
         as_str,
@@ -1655,6 +1655,7 @@ symbols! {
         rustc_allow_const_fn_unstable,
         rustc_allow_incoherent_impl,
         rustc_allowed_through_unstable_modules,
+        rustc_as_ptr,
         rustc_attrs,
         rustc_autodiff,
         rustc_box,
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index f988f003c0f..6e6cf91d855 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -223,7 +223,8 @@ pub trait Interner:
         def_id: Self::DefId,
     ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = (Self::Clause, Self::Span)>>;
 
-    fn is_const_impl(self, def_id: Self::DefId) -> bool;
+    fn impl_is_const(self, def_id: Self::DefId) -> bool;
+    fn fn_is_const(self, def_id: Self::DefId) -> bool;
     fn const_conditions(
         self,
         def_id: Self::DefId,
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index bb6dd1d2d30..ac3e4626ee5 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -1500,6 +1500,7 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
     /// [`as_ptr`]: Self::as_ptr
     #[unstable(feature = "box_as_ptr", issue = "129090")]
     #[rustc_never_returns_null_ptr]
+    #[cfg_attr(not(bootstrap), rustc_as_ptr)]
     #[inline]
     pub fn as_mut_ptr(b: &mut Self) -> *mut T {
         // This is a primitive deref, not going through `DerefMut`, and therefore not materializing
@@ -1548,6 +1549,7 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
     /// [`as_ptr`]: Self::as_ptr
     #[unstable(feature = "box_as_ptr", issue = "129090")]
     #[rustc_never_returns_null_ptr]
+    #[cfg_attr(not(bootstrap), rustc_as_ptr)]
     #[inline]
     pub fn as_ptr(b: &Self) -> *const T {
         // This is a primitive deref, not going through `DerefMut`, and therefore not materializing
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 07a1bd49321..990b7e8f761 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -1662,6 +1662,7 @@ impl<T, A: Allocator> Vec<T, A> {
     #[stable(feature = "vec_as_ptr", since = "1.37.0")]
     #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
     #[rustc_never_returns_null_ptr]
+    #[cfg_attr(not(bootstrap), rustc_as_ptr)]
     #[inline]
     pub const fn as_ptr(&self) -> *const T {
         // We shadow the slice method of the same name to avoid going through
@@ -1724,6 +1725,7 @@ impl<T, A: Allocator> Vec<T, A> {
     #[stable(feature = "vec_as_ptr", since = "1.37.0")]
     #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
     #[rustc_never_returns_null_ptr]
+    #[cfg_attr(not(bootstrap), rustc_as_ptr)]
     #[inline]
     pub const fn as_mut_ptr(&mut self) -> *mut T {
         // We shadow the slice method of the same name to avoid going through
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index 1a461987c76..bfd2a71f97b 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -587,6 +587,7 @@ impl<T: ?Sized> Cell<T> {
     #[inline]
     #[stable(feature = "cell_as_ptr", since = "1.12.0")]
     #[rustc_const_stable(feature = "const_cell_as_ptr", since = "1.32.0")]
+    #[cfg_attr(not(bootstrap), rustc_as_ptr)]
     #[rustc_never_returns_null_ptr]
     pub const fn as_ptr(&self) -> *mut T {
         self.value.get()
@@ -1149,6 +1150,7 @@ impl<T: ?Sized> RefCell<T> {
     /// ```
     #[inline]
     #[stable(feature = "cell_as_ptr", since = "1.12.0")]
+    #[cfg_attr(not(bootstrap), rustc_as_ptr)]
     #[rustc_never_returns_null_ptr]
     pub fn as_ptr(&self) -> *mut T {
         self.value.get()
@@ -2158,6 +2160,7 @@ impl<T: ?Sized> UnsafeCell<T> {
     #[inline(always)]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_unsafecell_get", since = "1.32.0")]
+    #[cfg_attr(not(bootstrap), rustc_as_ptr)]
     #[rustc_never_returns_null_ptr]
     pub const fn get(&self) -> *mut T {
         // We can just cast the pointer from `UnsafeCell<T>` to `T` because of
@@ -2271,6 +2274,7 @@ impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<UnsafeCell<U>> for UnsafeCell<T>
 /// See [`UnsafeCell`] for details.
 #[unstable(feature = "sync_unsafe_cell", issue = "95439")]
 #[repr(transparent)]
+#[rustc_diagnostic_item = "SyncUnsafeCell"]
 #[rustc_pub_transparent]
 pub struct SyncUnsafeCell<T: ?Sized> {
     value: UnsafeCell<T>,
@@ -2304,6 +2308,7 @@ impl<T: ?Sized> SyncUnsafeCell<T> {
     /// when casting to `&mut T`, and ensure that there are no mutations
     /// or mutable aliases going on when casting to `&T`
     #[inline]
+    #[cfg_attr(not(bootstrap), rustc_as_ptr)]
     #[rustc_never_returns_null_ptr]
     pub const fn get(&self) -> *mut T {
         self.value.get()
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index 85571222b5c..9e32f74227c 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -500,6 +500,7 @@ impl CStr {
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_str_as_ptr", since = "1.32.0")]
+    #[cfg_attr(not(bootstrap), rustc_as_ptr)]
     #[rustc_never_returns_null_ptr]
     pub const fn as_ptr(&self) -> *const c_char {
         self.inner.as_ptr()
diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs
index 8c6cdf57c58..58315cb74f0 100644
--- a/library/core/src/mem/maybe_uninit.rs
+++ b/library/core/src/mem/maybe_uninit.rs
@@ -525,6 +525,7 @@ impl<T> MaybeUninit<T> {
     /// until they are, it is advisable to avoid them.)
     #[stable(feature = "maybe_uninit", since = "1.36.0")]
     #[rustc_const_stable(feature = "const_maybe_uninit_as_ptr", since = "1.59.0")]
+    #[cfg_attr(not(bootstrap), rustc_as_ptr)]
     #[inline(always)]
     pub const fn as_ptr(&self) -> *const T {
         // `MaybeUninit` and `ManuallyDrop` are both `repr(transparent)` so we can cast the pointer.
@@ -566,6 +567,7 @@ impl<T> MaybeUninit<T> {
     /// until they are, it is advisable to avoid them.)
     #[stable(feature = "maybe_uninit", since = "1.36.0")]
     #[rustc_const_stable(feature = "const_maybe_uninit_as_mut_ptr", since = "1.83.0")]
+    #[cfg_attr(not(bootstrap), rustc_as_ptr)]
     #[inline(always)]
     pub const fn as_mut_ptr(&mut self) -> *mut T {
         // `MaybeUninit` and `ManuallyDrop` are both `repr(transparent)` so we can cast the pointer.
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index ef52cc44126..c855f963771 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -735,6 +735,7 @@ impl<T> [T] {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_slice_as_ptr", since = "1.32.0")]
     #[rustc_never_returns_null_ptr]
+    #[cfg_attr(not(bootstrap), rustc_as_ptr)]
     #[inline(always)]
     #[must_use]
     pub const fn as_ptr(&self) -> *const T {
@@ -765,6 +766,7 @@ impl<T> [T] {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
     #[rustc_never_returns_null_ptr]
+    #[cfg_attr(not(bootstrap), rustc_as_ptr)]
     #[inline(always)]
     #[must_use]
     pub const fn as_mut_ptr(&mut self) -> *mut T {
diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs
index 5aecbf303f9..4629b770cb4 100644
--- a/library/core/src/str/mod.rs
+++ b/library/core/src/str/mod.rs
@@ -373,6 +373,7 @@ impl str {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "rustc_str_as_ptr", since = "1.32.0")]
     #[rustc_never_returns_null_ptr]
+    #[cfg_attr(not(bootstrap), rustc_as_ptr)]
     #[must_use]
     #[inline(always)]
     pub const fn as_ptr(&self) -> *const u8 {
@@ -390,6 +391,7 @@ impl str {
     #[stable(feature = "str_as_mut_ptr", since = "1.36.0")]
     #[rustc_const_stable(feature = "const_str_as_mut", since = "1.83.0")]
     #[rustc_never_returns_null_ptr]
+    #[cfg_attr(not(bootstrap), rustc_as_ptr)]
     #[must_use]
     #[inline(always)]
     pub const fn as_mut_ptr(&mut self) -> *mut u8 {
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index 80ae62d7ac0..9a51a3f4268 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -477,7 +477,7 @@ auto:
         --enable-profiler
       SCRIPT: python x.py dist bootstrap --include-default-paths
       DIST_REQUIRE_ALL_TOOLS: 1
-    <<: *job-windows-8c
+    <<: *job-windows
 
   - image: dist-i686-mingw
     env:
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/types.rs b/tests/ui/lint/dangling-pointers-from-temporaries/types.rs
index 2b515d3e6d5..17c3eca89e2 100644
--- a/tests/ui/lint/dangling-pointers-from-temporaries/types.rs
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/types.rs
@@ -1,6 +1,7 @@
 #![deny(dangling_pointers_from_temporaries)]
+#![feature(sync_unsafe_cell)]
 
-use std::cell::Cell;
+use std::cell::{Cell, SyncUnsafeCell, UnsafeCell};
 use std::ffi::{CStr, CString};
 use std::mem::MaybeUninit;
 
@@ -47,6 +48,10 @@ fn main() {
     //~^ ERROR a dangling pointer will be produced because the temporary `MaybeUninit<u8>` will be dropped
     declval::<Vec<AsPtrFake>>().as_ptr();
     //~^ ERROR a dangling pointer will be produced because the temporary `Vec<AsPtrFake>` will be dropped
+    declval::<UnsafeCell<u8>>().get();
+    //~^ ERROR a dangling pointer will be produced because the temporary `UnsafeCell<u8>` will be dropped
+    declval::<SyncUnsafeCell<u8>>().get();
+    //~^ ERROR a dangling pointer will be produced because the temporary `SyncUnsafeCell<u8>` will be dropped
     declval::<Box<AsPtrFake>>().as_ptr();
     declval::<AsPtrFake>().as_ptr();
 }
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr
index c582a4c6540..250ed6dc9e3 100644
--- a/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr
@@ -1,5 +1,5 @@
 error: a dangling pointer will be produced because the temporary `CString` will be dropped
-  --> $DIR/types.rs:20:26
+  --> $DIR/types.rs:21:26
    |
 LL |     declval::<CString>().as_ptr();
    |     -------------------- ^^^^^^ this pointer will immediately be invalid
@@ -15,7 +15,7 @@ LL | #![deny(dangling_pointers_from_temporaries)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: a dangling pointer will be produced because the temporary `String` will be dropped
-  --> $DIR/types.rs:22:25
+  --> $DIR/types.rs:23:25
    |
 LL |     declval::<String>().as_ptr();
    |     ------------------- ^^^^^^ this pointer will immediately be invalid
@@ -26,7 +26,7 @@ LL |     declval::<String>().as_ptr();
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
-  --> $DIR/types.rs:24:26
+  --> $DIR/types.rs:25:26
    |
 LL |     declval::<Vec<u8>>().as_ptr();
    |     -------------------- ^^^^^^ this pointer will immediately be invalid
@@ -37,7 +37,7 @@ LL |     declval::<Vec<u8>>().as_ptr();
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `Box<CString>` will be dropped
-  --> $DIR/types.rs:26:31
+  --> $DIR/types.rs:27:31
    |
 LL |     declval::<Box<CString>>().as_ptr();
    |     ------------------------- ^^^^^^ this pointer will immediately be invalid
@@ -48,7 +48,7 @@ LL |     declval::<Box<CString>>().as_ptr();
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `Box<[u8]>` will be dropped
-  --> $DIR/types.rs:28:28
+  --> $DIR/types.rs:29:28
    |
 LL |     declval::<Box<[u8]>>().as_ptr();
    |     ---------------------- ^^^^^^ this pointer will immediately be invalid
@@ -59,7 +59,7 @@ LL |     declval::<Box<[u8]>>().as_ptr();
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `Box<str>` will be dropped
-  --> $DIR/types.rs:30:27
+  --> $DIR/types.rs:31:27
    |
 LL |     declval::<Box<str>>().as_ptr();
    |     --------------------- ^^^^^^ this pointer will immediately be invalid
@@ -70,7 +70,7 @@ LL |     declval::<Box<str>>().as_ptr();
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `Box<CStr>` will be dropped
-  --> $DIR/types.rs:32:28
+  --> $DIR/types.rs:33:28
    |
 LL |     declval::<Box<CStr>>().as_ptr();
    |     ---------------------- ^^^^^^ this pointer will immediately be invalid
@@ -81,7 +81,7 @@ LL |     declval::<Box<CStr>>().as_ptr();
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `[u8; 10]` will be dropped
-  --> $DIR/types.rs:34:27
+  --> $DIR/types.rs:35:27
    |
 LL |     declval::<[u8; 10]>().as_ptr();
    |     --------------------- ^^^^^^ this pointer will immediately be invalid
@@ -92,7 +92,7 @@ LL |     declval::<[u8; 10]>().as_ptr();
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `Box<[u8; 10]>` will be dropped
-  --> $DIR/types.rs:36:32
+  --> $DIR/types.rs:37:32
    |
 LL |     declval::<Box<[u8; 10]>>().as_ptr();
    |     -------------------------- ^^^^^^ this pointer will immediately be invalid
@@ -103,7 +103,7 @@ LL |     declval::<Box<[u8; 10]>>().as_ptr();
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `Box<Vec<u8>>` will be dropped
-  --> $DIR/types.rs:38:31
+  --> $DIR/types.rs:39:31
    |
 LL |     declval::<Box<Vec<u8>>>().as_ptr();
    |     ------------------------- ^^^^^^ this pointer will immediately be invalid
@@ -114,7 +114,7 @@ LL |     declval::<Box<Vec<u8>>>().as_ptr();
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `Box<String>` will be dropped
-  --> $DIR/types.rs:40:30
+  --> $DIR/types.rs:41:30
    |
 LL |     declval::<Box<String>>().as_ptr();
    |     ------------------------ ^^^^^^ this pointer will immediately be invalid
@@ -125,7 +125,7 @@ LL |     declval::<Box<String>>().as_ptr();
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `Box<Box<Box<Box<[u8]>>>>` will be dropped
-  --> $DIR/types.rs:42:43
+  --> $DIR/types.rs:43:43
    |
 LL |     declval::<Box<Box<Box<Box<[u8]>>>>>().as_ptr();
    |     ------------------------------------- ^^^^^^ this pointer will immediately be invalid
@@ -136,7 +136,7 @@ LL |     declval::<Box<Box<Box<Box<[u8]>>>>>().as_ptr();
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `Cell<u8>` will be dropped
-  --> $DIR/types.rs:44:27
+  --> $DIR/types.rs:45:27
    |
 LL |     declval::<Cell<u8>>().as_ptr();
    |     --------------------- ^^^^^^ this pointer will immediately be invalid
@@ -147,7 +147,7 @@ LL |     declval::<Cell<u8>>().as_ptr();
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `MaybeUninit<u8>` will be dropped
-  --> $DIR/types.rs:46:34
+  --> $DIR/types.rs:47:34
    |
 LL |     declval::<MaybeUninit<u8>>().as_ptr();
    |     ---------------------------- ^^^^^^ this pointer will immediately be invalid
@@ -158,7 +158,7 @@ LL |     declval::<MaybeUninit<u8>>().as_ptr();
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `Vec<AsPtrFake>` will be dropped
-  --> $DIR/types.rs:48:33
+  --> $DIR/types.rs:49:33
    |
 LL |     declval::<Vec<AsPtrFake>>().as_ptr();
    |     --------------------------- ^^^^^^ this pointer will immediately be invalid
@@ -168,5 +168,27 @@ LL |     declval::<Vec<AsPtrFake>>().as_ptr();
    = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<AsPtrFake>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
-error: aborting due to 15 previous errors
+error: a dangling pointer will be produced because the temporary `UnsafeCell<u8>` will be dropped
+  --> $DIR/types.rs:51:33
+   |
+LL |     declval::<UnsafeCell<u8>>().get();
+   |     --------------------------- ^^^ this pointer will immediately be invalid
+   |     |
+   |     this `UnsafeCell<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `get` the `UnsafeCell<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `SyncUnsafeCell<u8>` will be dropped
+  --> $DIR/types.rs:53:37
+   |
+LL |     declval::<SyncUnsafeCell<u8>>().get();
+   |     ------------------------------- ^^^ this pointer will immediately be invalid
+   |     |
+   |     this `SyncUnsafeCell<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `get` the `SyncUnsafeCell<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: aborting due to 17 previous errors
 
diff --git a/tests/ui/traits/const-traits/const-fns-are-early-bound.rs b/tests/ui/traits/const-traits/const-fns-are-early-bound.rs
deleted file mode 100644
index c26eaf67454..00000000000
--- a/tests/ui/traits/const-traits/const-fns-are-early-bound.rs
+++ /dev/null
@@ -1,90 +0,0 @@
-//@ known-bug: #110395
-//@ failure-status: 101
-//@ dont-check-compiler-stderr
-// FIXME(const_trait_impl) check-pass
-//@ compile-flags: -Znext-solver
-
-#![crate_type = "lib"]
-#![allow(internal_features, incomplete_features)]
-#![no_std]
-#![no_core]
-#![feature(
-    auto_traits,
-    const_trait_impl,
-    effects,
-    lang_items,
-    no_core,
-    staged_api,
-    unboxed_closures,
-    rustc_attrs,
-    marker_trait_attr,
-)]
-#![stable(feature = "minicore", since = "1.0.0")]
-
-fn test() {
-    fn is_const_fn<F>(_: F)
-    where
-        F: const FnOnce<()>,
-    {
-    }
-
-    const fn foo() {}
-
-    is_const_fn(foo);
-}
-
-/// ---------------------------------------------------------------------- ///
-/// Const fn trait definitions
-
-#[const_trait]
-#[lang = "fn"]
-#[rustc_paren_sugar]
-trait Fn<Args: Tuple>: ~const FnMut<Args> {
-    extern "rust-call" fn call(&self, args: Args) -> Self::Output;
-}
-
-#[const_trait]
-#[lang = "fn_mut"]
-#[rustc_paren_sugar]
-trait FnMut<Args: Tuple>: ~const FnOnce<Args> {
-    extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
-}
-
-#[const_trait]
-#[lang = "fn_once"]
-#[rustc_paren_sugar]
-trait FnOnce<Args: Tuple> {
-    #[lang = "fn_once_output"]
-    type Output;
-
-    extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
-}
-
-/// ---------------------------------------------------------------------- ///
-/// All this other stuff needed for core. Unrelated to test.
-
-#[lang = "destruct"]
-#[const_trait]
-trait Destruct {}
-
-#[lang = "freeze"]
-unsafe auto trait Freeze {}
-
-#[lang = "drop"]
-#[const_trait]
-trait Drop {
-    fn drop(&mut self);
-}
-
-#[lang = "sized"]
-trait Sized {}
-#[lang = "copy"]
-trait Copy {}
-
-#[lang = "tuple_trait"]
-trait Tuple {}
-
-#[lang = "legacy_receiver"]
-trait LegacyReceiver {}
-
-impl<T: ?Sized> LegacyReceiver for &T {}
diff --git a/tests/ui/traits/const-traits/effects/minicore-const-fn-early-bound.rs b/tests/ui/traits/const-traits/effects/minicore-const-fn-early-bound.rs
new file mode 100644
index 00000000000..ee47f92a0bc
--- /dev/null
+++ b/tests/ui/traits/const-traits/effects/minicore-const-fn-early-bound.rs
@@ -0,0 +1,22 @@
+//@ aux-build:minicore.rs
+//@ compile-flags: --crate-type=lib -Znext-solver -Cpanic=abort
+//@ check-pass
+
+#![feature(no_core, const_trait_impl)]
+#![no_std]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+fn is_const_fn<F>(_: F)
+where
+    F: const FnOnce(),
+{
+}
+
+const fn foo() {}
+
+fn test() {
+    is_const_fn(foo);
+}
diff --git a/tests/ui/traits/const-traits/effects/minicore-fn-fail.rs b/tests/ui/traits/const-traits/effects/minicore-fn-fail.rs
new file mode 100644
index 00000000000..ae1cbc6ca58
--- /dev/null
+++ b/tests/ui/traits/const-traits/effects/minicore-fn-fail.rs
@@ -0,0 +1,21 @@
+//@ aux-build:minicore.rs
+//@ compile-flags: --crate-type=lib -Znext-solver
+
+#![feature(no_core, const_trait_impl)]
+#![no_std]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+const fn call_indirect<T: ~const Fn()>(t: &T) { t() }
+
+#[const_trait]
+trait Foo {}
+impl Foo for () {}
+const fn foo<T: ~const Foo>() {}
+
+const fn test() {
+    call_indirect(&foo::<()>);
+    //~^ ERROR the trait bound `(): ~const Foo` is not satisfied
+}
diff --git a/tests/ui/traits/const-traits/effects/minicore-fn-fail.stderr b/tests/ui/traits/const-traits/effects/minicore-fn-fail.stderr
new file mode 100644
index 00000000000..cf158643b34
--- /dev/null
+++ b/tests/ui/traits/const-traits/effects/minicore-fn-fail.stderr
@@ -0,0 +1,9 @@
+error[E0277]: the trait bound `(): ~const Foo` is not satisfied
+  --> $DIR/minicore-fn-fail.rs:19:5
+   |
+LL |     call_indirect(&foo::<()>);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/const-traits/effects/minicore-works.rs b/tests/ui/traits/const-traits/effects/minicore-works.rs
index bfbfa8b2d05..c79b4fc07df 100644
--- a/tests/ui/traits/const-traits/effects/minicore-works.rs
+++ b/tests/ui/traits/const-traits/effects/minicore-works.rs
@@ -20,3 +20,9 @@ const fn test_op() {
     let _x = Add::add(1, 2);
     let _y = Custom + Custom;
 }
+
+const fn call_indirect<T: ~const Fn()>(t: &T) { t() }
+
+const fn call() {
+    call_indirect(&call);
+}