summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_const_eval/src/transform/check_consts/check.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs89
1 files changed, 68 insertions, 21 deletions
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index 0adb88a18..22a61774e 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -13,8 +13,11 @@ use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty,
use rustc_middle::ty::{Binder, TraitPredicate, TraitRef, TypeVisitable};
use rustc_mir_dataflow::{self, Analysis};
use rustc_span::{sym, Span, Symbol};
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
-use rustc_trait_selection::traits::SelectionContext;
+use rustc_trait_selection::infer::InferCtxtExt;
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
+use rustc_trait_selection::traits::{
+ self, ObligationCauseCode, SelectionContext, TraitEngine, TraitEngineExt,
+};
use std::mem;
use std::ops::Deref;
@@ -135,7 +138,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
// qualifs for the return type.
let return_block = ccx
.body
- .basic_blocks()
+ .basic_blocks
.iter_enumerated()
.find(|(_, block)| matches!(block.terminator().kind, TerminatorKind::Return))
.map(|(bb, _)| bb);
@@ -546,7 +549,11 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
// Since no pointer can ever get exposed (rejected above), this is easy to support.
}
- Rvalue::Cast(CastKind::Misc, _, _) => {}
+ Rvalue::Cast(CastKind::DynStar, _, _) => {
+ unimplemented!()
+ }
+
+ Rvalue::Cast(_, _, _) => {}
Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {}
Rvalue::ShallowInitBox(_, _) => {}
@@ -652,6 +659,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Downcast(..)
+ | ProjectionElem::OpaqueCast(..)
| ProjectionElem::Subslice { .. }
| ProjectionElem::Field(..)
| ProjectionElem::Index(_) => {}
@@ -678,7 +686,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
| StatementKind::Retag { .. }
| StatementKind::AscribeUserType(..)
| StatementKind::Coverage(..)
- | StatementKind::CopyNonOverlapping(..)
+ | StatementKind::Intrinsic(..)
| StatementKind::Nop => {}
}
}
@@ -729,10 +737,49 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
let obligation =
Obligation::new(ObligationCause::dummy(), param_env, poly_trait_pred);
- let implsrc = tcx.infer_ctxt().enter(|infcx| {
+ let implsrc = {
+ let infcx = tcx.infer_ctxt().build();
let mut selcx = SelectionContext::new(&infcx);
selcx.select(&obligation)
- });
+ };
+
+ // do a well-formedness check on the trait method being called. This is because typeck only does a
+ // "non-const" check. This is required for correctness here.
+ {
+ let infcx = tcx.infer_ctxt().build();
+ let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
+ let predicates = tcx.predicates_of(callee).instantiate(tcx, substs);
+ let hir_id = tcx
+ .hir()
+ .local_def_id_to_hir_id(self.body.source.def_id().expect_local());
+ let cause = || {
+ ObligationCause::new(
+ terminator.source_info.span,
+ hir_id,
+ ObligationCauseCode::ItemObligation(callee),
+ )
+ };
+ let normalized = infcx.partially_normalize_associated_types_in(
+ cause(),
+ param_env,
+ predicates,
+ );
+
+ for p in normalized.obligations {
+ fulfill_cx.register_predicate_obligation(&infcx, p);
+ }
+ for obligation in traits::predicates_for_generics(
+ |_, _| cause(),
+ self.param_env,
+ normalized.value,
+ ) {
+ fulfill_cx.register_predicate_obligation(&infcx, obligation);
+ }
+ let errors = fulfill_cx.select_all_or_error(&infcx);
+ if !errors.is_empty() {
+ infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ }
+ }
match implsrc {
Ok(Some(ImplSource::Param(_, ty::BoundConstness::ConstIfConst))) => {
@@ -790,16 +837,15 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
// improve diagnostics by showing what failed. Our requirements are stricter this time
// as we are going to error again anyways.
- tcx.infer_ctxt().enter(|infcx| {
- if let Err(e) = implsrc {
- infcx.report_selection_error(
- obligation.clone(),
- &obligation,
- &e,
- false,
- );
- }
- });
+ let infcx = tcx.infer_ctxt().build();
+ if let Err(e) = implsrc {
+ infcx.err_ctxt().report_selection_error(
+ obligation.clone(),
+ &obligation,
+ &e,
+ false,
+ );
+ }
self.check_op(ops::FnCallNonConst {
caller,
@@ -863,8 +909,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
return;
}
- let is_intrinsic = tcx.is_intrinsic(callee);
-
if !tcx.is_const_fn_raw(callee) {
if !tcx.is_const_default_method(callee) {
// To get to here we must have already found a const impl for the
@@ -924,7 +968,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
// We do not use `const` modifiers for intrinsic "functions", as intrinsics are
// `extern` functions, and these have no way to get marked `const`. So instead we
// use `rustc_const_(un)stable` attributes to mean that the intrinsic is `const`
- if self.ccx.is_const_stable_const_fn() || is_intrinsic {
+ if self.ccx.is_const_stable_const_fn() || tcx.is_intrinsic(callee) {
self.check_op(ops::FnCallUnstable(callee, None));
return;
}
@@ -964,7 +1008,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
if needs_non_const_drop {
self.check_op_spanned(
- ops::LiveDrop { dropped_at: Some(terminator.source_info.span) },
+ ops::LiveDrop {
+ dropped_at: Some(terminator.source_info.span),
+ dropped_ty: ty_of_dropped_place,
+ },
err_span,
);
}