diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 5210241d5e49e..edddd393d17d2 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -11,7 +11,6 @@ use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, LangItem}; use rustc_index::bit_set::BitSet; use rustc_infer::infer::TyCtxtInferExt; -use rustc_infer::traits::ObligationCause; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; use rustc_middle::span_bug; @@ -20,9 +19,11 @@ use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TypeVisitableExt, Typin use rustc_mir_dataflow::Analysis; use rustc_mir_dataflow::impls::MaybeStorageLive; use rustc_mir_dataflow::storage::always_storage_live_locals; -use rustc_span::{DUMMY_SP, Span, Symbol, sym}; +use rustc_span::{Span, Symbol, sym}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; -use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt}; +use rustc_trait_selection::traits::{ + Obligation, ObligationCause, ObligationCauseCode, ObligationCtxt, +}; use tracing::{debug, instrument, trace}; use super::ops::{self, NonConstOp, Status}; @@ -360,6 +361,73 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { // end of evaluation. !is_transient } + + fn revalidate_conditional_constness( + &mut self, + callee: DefId, + callee_args: ty::GenericArgsRef<'tcx>, + call_source: CallSource, + call_span: Span, + ) { + let tcx = self.tcx; + if !tcx.is_conditionally_const(callee) { + return; + } + + let const_conditions = tcx.const_conditions(callee).instantiate(tcx, callee_args); + // If there are any const conditions on this fn and `const_trait_impl` + // is not enabled, simply bail. We shouldn't be able to call conditionally + // const functions on stable. + if !const_conditions.is_empty() && !tcx.features().const_trait_impl() { + self.check_op(ops::FnCallNonConst { + callee, + args: callee_args, + span: call_span, + call_source, + feature: Some(sym::const_trait_impl), + }); + return; + } + + let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(self.param_env)); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); + + let body_id = self.body.source.def_id().expect_local(); + let host_polarity = match self.const_kind() { + hir::ConstContext::ConstFn => ty::BoundConstness::Maybe, + hir::ConstContext::Static(_) | hir::ConstContext::Const { .. } => { + ty::BoundConstness::Const + } + }; + let const_conditions = ocx.normalize( + &ObligationCause::misc(call_span, body_id), + self.param_env, + const_conditions, + ); + ocx.register_obligations(const_conditions.into_iter().map(|(trait_ref, span)| { + Obligation::new( + tcx, + ObligationCause::new( + call_span, + body_id, + ObligationCauseCode::WhereClause(callee, span), + ), + self.param_env, + trait_ref.to_host_effect_clause(tcx, host_polarity), + ) + })); + + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { + // FIXME(effects): Soon this should be unconditionally delaying a bug. + if matches!(call_source, CallSource::Normal) && tcx.features().effects() { + tcx.dcx() + .span_delayed_bug(call_span, "this should have reported a ~const error in HIR"); + } else { + infcx.err_ctxt().report_fulfillment_errors(errors); + } + } + } } impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { @@ -566,7 +634,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { }; let ConstCx { tcx, body, param_env, .. } = *self.ccx; - let caller = self.def_id(); let fn_ty = func.ty(body, tcx); @@ -584,31 +651,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } }; - // Check that all trait bounds that are marked as `~const` can be satisfied. - // - // Typeck only does a "non-const" check since it operates on HIR and cannot distinguish - // which path expressions are getting called on and which path expressions are only used - // as function pointers. This is required for correctness. - let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env)); - let ocx = ObligationCtxt::new_with_diagnostics(&infcx); - - let predicates = tcx.predicates_of(callee).instantiate(tcx, fn_args); - let cause = ObligationCause::new( - terminator.source_info.span, - self.body.source.def_id().expect_local(), - ObligationCauseCode::WhereClause(callee, DUMMY_SP), - ); - let normalized_predicates = ocx.normalize(&cause, param_env, predicates); - ocx.register_obligations(traits::predicates_for_generics( - |_, _| cause.clone(), - self.param_env, - normalized_predicates, - )); - - let errors = ocx.select_all_or_error(); - if !errors.is_empty() { - infcx.err_ctxt().report_fulfillment_errors(errors); - } + self.revalidate_conditional_constness(callee, fn_args, call_source, *fn_span); let mut is_trait = false; // Attempting to call a trait method? @@ -648,7 +691,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { None }; self.check_op(ops::FnCallNonConst { - caller, callee, args: fn_args, span: *fn_span, @@ -738,7 +780,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // Trait functions are not `const fn` so we have to skip them here. if !tcx.is_const_fn(callee) && !is_trait { self.check_op(ops::FnCallNonConst { - caller, callee, args: fn_args, span: *fn_span, diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index 3f977dc4b05aa..eb1ee934d8b44 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -1,6 +1,5 @@ //! Concrete error types for all operations which may be invalid in a certain const context. -use hir::def_id::LocalDefId; use hir::{ConstContext, LangItem}; use rustc_errors::Diag; use rustc_errors::codes::*; @@ -74,7 +73,6 @@ impl<'tcx> NonConstOp<'tcx> for FnCallIndirect { /// A function call where the callee is not marked as `const`. #[derive(Debug, Clone, Copy)] pub(crate) struct FnCallNonConst<'tcx> { - pub caller: LocalDefId, pub callee: DefId, pub args: GenericArgsRef<'tcx>, pub span: Span, @@ -87,8 +85,9 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { #[allow(rustc::diagnostic_outside_of_impl)] #[allow(rustc::untranslatable_diagnostic)] fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> Diag<'tcx> { - let FnCallNonConst { caller, callee, args, span, call_source, feature } = *self; - let ConstCx { tcx, param_env, body, .. } = *ccx; + let FnCallNonConst { callee, args, span, call_source, feature } = *self; + let ConstCx { tcx, param_env, .. } = *ccx; + let caller = ccx.def_id(); let diag_trait = |err, self_ty: Ty<'_>, trait_id| { let trait_ref = TraitRef::from_method(tcx, trait_id, args); @@ -289,7 +288,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { if let Some(feature) = feature { ccx.tcx.disabled_nightly_features( &mut err, - body.source.def_id().as_local().map(|local| ccx.tcx.local_def_id_to_hir_id(local)), + Some(ccx.tcx.local_def_id_to_hir_id(caller)), [(String::new(), feature)], ); } diff --git a/tests/ui/traits/const-traits/const-drop-fail-2.stderr b/tests/ui/traits/const-traits/const-drop-fail-2.stderr index 82d6412ded0c4..102dbb1a5999e 100644 --- a/tests/ui/traits/const-traits/const-drop-fail-2.stderr +++ b/tests/ui/traits/const-traits/const-drop-fail-2.stderr @@ -29,6 +29,12 @@ LL | const fn check(_: T) {} | | | the destructor for this type cannot be evaluated in constant functions +error[E0277]: the trait bound `T: ~const A` is not satisfied + --> $DIR/const-drop-fail-2.rs:41:9 + | +LL | T::a(); + | ^^^^^^ + error[E0015]: cannot call non-const fn `::a` in constant functions --> $DIR/const-drop-fail-2.rs:41:9 | @@ -41,7 +47,7 @@ help: add `#![feature(effects)]` to the crate attributes to enable LL + #![feature(effects)] | -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors -Some errors have detailed explanations: E0015, E0493. +Some errors have detailed explanations: E0015, E0277, E0493. For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/const-drop.precise.stderr b/tests/ui/traits/const-traits/const-drop.precise.stderr index 381e4d78c2856..7471b200c3378 100644 --- a/tests/ui/traits/const-traits/const-drop.precise.stderr +++ b/tests/ui/traits/const-traits/const-drop.precise.stderr @@ -78,6 +78,12 @@ error[E0493]: destructor of `T` cannot be evaluated at compile-time LL | const fn a(_: T) {} | ^ the destructor for this type cannot be evaluated in constant functions +error[E0277]: the trait bound `T: ~const SomeTrait` is not satisfied + --> $DIR/const-drop.rs:69:13 + | +LL | T::foo(); + | ^^^^^^^^ + error[E0015]: cannot call non-const fn `::foo` in constant functions --> $DIR/const-drop.rs:69:13 | @@ -90,7 +96,7 @@ help: add `#![feature(effects)]` to the crate attributes to enable LL + #![feature(effects)] | -error: aborting due to 10 previous errors +error: aborting due to 11 previous errors Some errors have detailed explanations: E0015, E0277, E0493. For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/const-drop.stock.stderr b/tests/ui/traits/const-traits/const-drop.stock.stderr index 399e784967357..7137834916167 100644 --- a/tests/ui/traits/const-traits/const-drop.stock.stderr +++ b/tests/ui/traits/const-traits/const-drop.stock.stderr @@ -80,6 +80,12 @@ LL | const fn a(_: T) {} | | | the destructor for this type cannot be evaluated in constant functions +error[E0277]: the trait bound `T: ~const SomeTrait` is not satisfied + --> $DIR/const-drop.rs:69:13 + | +LL | T::foo(); + | ^^^^^^^^ + error[E0015]: cannot call non-const fn `::foo` in constant functions --> $DIR/const-drop.rs:69:13 | @@ -92,7 +98,7 @@ help: add `#![feature(effects)]` to the crate attributes to enable LL + #![feature(effects)] | -error: aborting due to 10 previous errors +error: aborting due to 11 previous errors Some errors have detailed explanations: E0015, E0277, E0493. For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/cross-crate.rs b/tests/ui/traits/const-traits/cross-crate.rs index cfcada9c828d4..30d2260a7449a 100644 --- a/tests/ui/traits/const-traits/cross-crate.rs +++ b/tests/ui/traits/const-traits/cross-crate.rs @@ -18,10 +18,11 @@ const fn const_context() { #[cfg(any(stocknc, gatednc))] NonConst.func(); //[stocknc]~^ ERROR: cannot call - //[gatednc]~^^ ERROR: the trait bound + //[stocknc]~| ERROR: cannot call + //[gatednc]~^^^ ERROR: the trait bound Const.func(); - //[stock]~^ ERROR: cannot call - //[stocknc]~^^ ERROR: cannot call + //[stock,stocknc]~^ ERROR: cannot call + //[stock,stocknc]~| ERROR: cannot call } fn main() {} diff --git a/tests/ui/traits/const-traits/cross-crate.stock.stderr b/tests/ui/traits/const-traits/cross-crate.stock.stderr index b481bdc470ce3..b35891071b0f0 100644 --- a/tests/ui/traits/const-traits/cross-crate.stock.stderr +++ b/tests/ui/traits/const-traits/cross-crate.stock.stderr @@ -1,5 +1,5 @@ error[E0015]: cannot call non-const fn `::func` in constant functions - --> $DIR/cross-crate.rs:22:11 + --> $DIR/cross-crate.rs:23:11 | LL | Const.func(); | ^^^^^^ @@ -10,6 +10,19 @@ help: add `#![feature(const_trait_impl)]` to the crate attributes to enable LL + #![feature(const_trait_impl)] | -error: aborting due to 1 previous error +error[E0015]: cannot call non-const fn `::func` in constant functions + --> $DIR/cross-crate.rs:23:11 + | +LL | Const.func(); + | ^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + | +LL + #![feature(const_trait_impl)] + | + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/cross-crate.stocknc.stderr b/tests/ui/traits/const-traits/cross-crate.stocknc.stderr index 5c3e3b6ff4008..89de89159dbf1 100644 --- a/tests/ui/traits/const-traits/cross-crate.stocknc.stderr +++ b/tests/ui/traits/const-traits/cross-crate.stocknc.stderr @@ -10,18 +10,44 @@ help: add `#![feature(const_trait_impl)]` to the crate attributes to enable LL + #![feature(const_trait_impl)] | +error[E0015]: cannot call non-const fn `::func` in constant functions + --> $DIR/cross-crate.rs:19:14 + | +LL | NonConst.func(); + | ^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + | +LL + #![feature(const_trait_impl)] + | + +error[E0015]: cannot call non-const fn `::func` in constant functions + --> $DIR/cross-crate.rs:23:11 + | +LL | Const.func(); + | ^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + | +LL + #![feature(const_trait_impl)] + | + error[E0015]: cannot call non-const fn `::func` in constant functions - --> $DIR/cross-crate.rs:22:11 + --> $DIR/cross-crate.rs:23:11 | LL | Const.func(); | ^^^^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: add `#![feature(const_trait_impl)]` to the crate attributes to enable | LL + #![feature(const_trait_impl)] | -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/default-method-body-is-const-body-checking.rs b/tests/ui/traits/const-traits/default-method-body-is-const-body-checking.rs index b534d23b1076a..96acdc300e0dd 100644 --- a/tests/ui/traits/const-traits/default-method-body-is-const-body-checking.rs +++ b/tests/ui/traits/const-traits/default-method-body-is-const-body-checking.rs @@ -1,6 +1,3 @@ -//@ known-bug: #110395 -//@ check-pass - #![feature(const_trait_impl)] #[const_trait] @@ -13,7 +10,7 @@ const fn foo() where T: ~const Tr {} pub trait Foo { fn foo() { foo::<()>(); - //FIXME ~^ ERROR the trait bound `(): Tr` is not satisfied + //~^ ERROR the trait bound `(): ~const Tr` is not satisfied } } diff --git a/tests/ui/traits/const-traits/default-method-body-is-const-body-checking.stderr b/tests/ui/traits/const-traits/default-method-body-is-const-body-checking.stderr new file mode 100644 index 0000000000000..308a60c08d316 --- /dev/null +++ b/tests/ui/traits/const-traits/default-method-body-is-const-body-checking.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `(): ~const Tr` is not satisfied + --> $DIR/default-method-body-is-const-body-checking.rs:12:9 + | +LL | foo::<()>(); + | ^^^^^^^^^^^ + | +note: required by a bound in `foo` + --> $DIR/default-method-body-is-const-body-checking.rs:7:28 + | +LL | const fn foo() where T: ~const Tr {} + | ^^^^^^ required by this bound in `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/specializing-constness-2.stderr b/tests/ui/traits/const-traits/specializing-constness-2.stderr index 8e6f6945a1b85..98a9de2324af1 100644 --- a/tests/ui/traits/const-traits/specializing-constness-2.stderr +++ b/tests/ui/traits/const-traits/specializing-constness-2.stderr @@ -1,3 +1,9 @@ +error[E0277]: the trait bound `T: ~const A` is not satisfied + --> $DIR/specializing-constness-2.rs:27:5 + | +LL | ::a(); + | ^^^^^^^^^^^^^ + error[E0015]: cannot call non-const fn `::a` in constant functions --> $DIR/specializing-constness-2.rs:27:5 | @@ -10,6 +16,7 @@ help: add `#![feature(effects)]` to the crate attributes to enable LL + #![feature(effects)] | -error: aborting due to 1 previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0015`. +Some errors have detailed explanations: E0015, E0277. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/staged-api-user-crate.rs b/tests/ui/traits/const-traits/staged-api-user-crate.rs index c4ecb8f67a187..c820d1ff47cb4 100644 --- a/tests/ui/traits/const-traits/staged-api-user-crate.rs +++ b/tests/ui/traits/const-traits/staged-api-user-crate.rs @@ -11,6 +11,7 @@ fn non_const_context() { const fn stable_const_context() { Unstable::func(); //~^ ERROR cannot call non-const fn `::func` in constant functions + //~| ERROR cannot call non-const fn `::func` in constant functions } fn main() {} diff --git a/tests/ui/traits/const-traits/staged-api-user-crate.stderr b/tests/ui/traits/const-traits/staged-api-user-crate.stderr index 781191ec97cd1..24cdb1d3d5a30 100644 --- a/tests/ui/traits/const-traits/staged-api-user-crate.stderr +++ b/tests/ui/traits/const-traits/staged-api-user-crate.stderr @@ -10,6 +10,19 @@ help: add `#![feature(const_trait_impl)]` to the crate attributes to enable LL + #![feature(const_trait_impl)] | -error: aborting due to 1 previous error +error[E0015]: cannot call non-const fn `::func` in constant functions + --> $DIR/staged-api-user-crate.rs:12:5 + | +LL | Unstable::func(); + | ^^^^^^^^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + | +LL + #![feature(const_trait_impl)] + | + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0015`.