summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_const_eval/src/transform
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 09:26:03 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 09:26:03 +0000
commit9918693037dce8aa4bb6f08741b6812923486c18 (patch)
tree21d2b40bec7e6a7ea664acee056eb3d08e15a1cf /compiler/rustc_const_eval/src/transform
parentReleasing progress-linux version 1.75.0+dfsg1-5~progress7.99u1. (diff)
downloadrustc-9918693037dce8aa4bb6f08741b6812923486c18.tar.xz
rustc-9918693037dce8aa4bb6f08741b6812923486c18.zip
Merging upstream version 1.76.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_const_eval/src/transform')
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs53
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/mod.rs6
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/ops.rs5
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs7
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs22
-rw-r--r--compiler/rustc_const_eval/src/transform/promote_consts.rs42
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs28
7 files changed, 81 insertions, 82 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 76116e339..949606ed6 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -12,7 +12,7 @@ use rustc_middle::traits::BuiltinImplSource;
use rustc_middle::ty::GenericArgs;
use rustc_middle::ty::{self, adjustment::PointerCoercion, Instance, InstanceDef, Ty, TyCtxt};
use rustc_middle::ty::{TraitRef, TypeVisitableExt};
-use rustc_mir_dataflow::{self, Analysis};
+use rustc_mir_dataflow::Analysis;
use rustc_span::{sym, Span, Symbol};
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt, SelectionContext};
@@ -22,7 +22,7 @@ use std::mem;
use std::ops::{ControlFlow, Deref};
use super::ops::{self, NonConstOp, Status};
-use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop};
+use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop, NeedsNonConstDrop};
use super::resolver::FlowSensitiveAnalysis;
use super::{ConstCx, Qualif};
use crate::const_eval::is_unstable_const_fn;
@@ -35,7 +35,7 @@ type QualifResults<'mir, 'tcx, Q> =
pub struct Qualifs<'mir, 'tcx> {
has_mut_interior: Option<QualifResults<'mir, 'tcx, HasMutInterior>>,
needs_drop: Option<QualifResults<'mir, 'tcx, NeedsDrop>>,
- // needs_non_const_drop: Option<QualifResults<'mir, 'tcx, NeedsNonConstDrop>>,
+ needs_non_const_drop: Option<QualifResults<'mir, 'tcx, NeedsNonConstDrop>>,
}
impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
@@ -60,9 +60,9 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
let ConstCx { tcx, body, .. } = *ccx;
FlowSensitiveAnalysis::new(NeedsDrop, ccx)
- .into_engine(tcx, &body)
+ .into_engine(tcx, body)
.iterate_to_fixpoint()
- .into_results_cursor(&body)
+ .into_results_cursor(body)
});
needs_drop.seek_before_primary_effect(location);
@@ -78,27 +78,25 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
local: Local,
location: Location,
) -> bool {
- // FIXME(effects) replace with `NeedsNonconstDrop` after const traits work again
- /*
let ty = ccx.body.local_decls[local].ty;
- if !NeedsDrop::in_any_value_of_ty(ccx, ty) {
+ // Peeking into opaque types causes cycles if the current function declares said opaque
+ // type. Thus we avoid short circuiting on the type and instead run the more expensive
+ // analysis that looks at the actual usage within this function
+ if !ty.has_opaque_types() && !NeedsNonConstDrop::in_any_value_of_ty(ccx, ty) {
return false;
}
let needs_non_const_drop = self.needs_non_const_drop.get_or_insert_with(|| {
let ConstCx { tcx, body, .. } = *ccx;
- FlowSensitiveAnalysis::new(NeedsDrop, ccx)
- .into_engine(tcx, &body)
+ FlowSensitiveAnalysis::new(NeedsNonConstDrop, ccx)
+ .into_engine(tcx, body)
.iterate_to_fixpoint()
- .into_results_cursor(&body)
+ .into_results_cursor(body)
});
needs_non_const_drop.seek_before_primary_effect(location);
needs_non_const_drop.get().contains(local)
- */
-
- self.needs_drop(ccx, local, location)
}
/// Returns `true` if `local` is `HasMutInterior` at the given `Location`.
@@ -122,9 +120,9 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
let ConstCx { tcx, body, .. } = *ccx;
FlowSensitiveAnalysis::new(HasMutInterior, ccx)
- .into_engine(tcx, &body)
+ .into_engine(tcx, body)
.iterate_to_fixpoint()
- .into_results_cursor(&body)
+ .into_results_cursor(body)
});
has_mut_interior.seek_before_primary_effect(location);
@@ -170,9 +168,9 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
hir::ConstContext::Const { .. } | hir::ConstContext::Static(_) => {
let mut cursor = FlowSensitiveAnalysis::new(CustomEq, ccx)
- .into_engine(ccx.tcx, &ccx.body)
+ .into_engine(ccx.tcx, ccx.body)
.iterate_to_fixpoint()
- .into_results_cursor(&ccx.body);
+ .into_results_cursor(ccx.body);
cursor.seek_after_primary_effect(return_loc);
cursor.get().contains(RETURN_PLACE)
@@ -225,7 +223,7 @@ impl<'mir, 'tcx> Deref for Checker<'mir, 'tcx> {
type Target = ConstCx<'mir, 'tcx>;
fn deref(&self) -> &Self::Target {
- &self.ccx
+ self.ccx
}
}
@@ -248,7 +246,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
// `async` functions cannot be `const fn`. This is checked during AST lowering, so there's
// no need to emit duplicate errors here.
if self.ccx.is_async() || body.coroutine.is_some() {
- tcx.sess.delay_span_bug(body.span, "`async` functions cannot be `const fn`");
+ tcx.sess.span_delayed_bug(body.span, "`async` functions cannot be `const fn`");
return;
}
@@ -272,15 +270,15 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
}
if !tcx.has_attr(def_id, sym::rustc_do_not_const_check) {
- self.visit_body(&body);
+ self.visit_body(body);
}
// If we got through const-checking without emitting any "primary" errors, emit any
// "secondary" errors if they occurred.
let secondary_errors = mem::take(&mut self.secondary_errors);
if self.error_emitted.is_none() {
- for mut error in secondary_errors {
- self.tcx.sess.diagnostic().emit_diagnostic(&mut error);
+ for error in secondary_errors {
+ self.tcx.sess.dcx().emit_diagnostic(error);
}
} else {
assert!(self.tcx.sess.has_errors().is_some());
@@ -357,7 +355,9 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
fn check_static(&mut self, def_id: DefId, span: Span) {
if self.tcx.is_thread_local_static(def_id) {
- self.tcx.sess.delay_span_bug(span, "tls access is checked in `Rvalue::ThreadLocalRef`");
+ self.tcx
+ .sess
+ .span_delayed_bug(span, "tls access is checked in `Rvalue::ThreadLocalRef`");
}
self.check_op_spanned(ops::StaticAccess, span)
}
@@ -503,7 +503,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Fake, place)
| Rvalue::AddressOf(Mutability::Not, place) => {
let borrowed_place_has_mut_interior = qualifs::in_place::<HasMutInterior, _>(
- &self.ccx,
+ self.ccx,
&mut |local| self.qualifs.has_mut_interior(self.ccx, local, location),
place.as_ref(),
);
@@ -1011,9 +1011,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
let mut err_span = self.span;
let ty_of_dropped_place = dropped_place.ty(self.body, self.tcx).ty;
- // FIXME(effects) replace with `NeedsNonConstDrop` once we fix const traits
let ty_needs_non_const_drop =
- qualifs::NeedsDrop::in_any_value_of_ty(self.ccx, ty_of_dropped_place);
+ qualifs::NeedsNonConstDrop::in_any_value_of_ty(self.ccx, ty_of_dropped_place);
debug!(?ty_of_dropped_place, ?ty_needs_non_const_drop);
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
index e51082e1e..4f7e165c5 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
@@ -82,8 +82,8 @@ pub fn rustc_allow_const_fn_unstable(
def_id: LocalDefId,
feature_gate: Symbol,
) -> bool {
- let attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(def_id));
- attr::rustc_allow_const_fn_unstable(&tcx.sess, attrs).any(|name| name == feature_gate)
+ let attrs = tcx.hir().attrs(tcx.local_def_id_to_hir_id(def_id));
+ attr::rustc_allow_const_fn_unstable(tcx.sess, attrs).any(|name| name == feature_gate)
}
/// Returns `true` if the given `const fn` is "const-stable".
@@ -112,7 +112,7 @@ pub fn is_const_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
None if is_parent_const_stable_trait(tcx, def_id) => {
// Remove this when `#![feature(const_trait_impl)]` is stabilized,
// returning `true` unconditionally.
- tcx.sess.delay_span_bug(
+ tcx.sess.span_delayed_bug(
tcx.def_span(def_id),
"trait implementations cannot be const stable yet",
);
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
index 40183bacc..2de6362b9 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
@@ -119,8 +119,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
match self_ty.kind() {
Param(param_ty) => {
debug!(?param_ty);
- let caller_hir_id = tcx.hir().local_def_id_to_hir_id(caller);
- if let Some(generics) = tcx.hir().get(caller_hir_id).generics() {
+ if let Some(generics) = tcx.hir_node_by_def_id(caller).generics() {
let constraint = with_no_trimmed_paths!(format!(
"~const {}",
trait_ref.print_only_trait_path()
@@ -129,7 +128,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
tcx,
generics,
err,
- &param_ty.name.as_str(),
+ param_ty.name.as_str(),
&constraint,
None,
None,
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs b/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs
index aff256b3e..5cd13783c 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs
@@ -5,7 +5,7 @@ use rustc_span::{symbol::sym, Span};
use super::check::Qualifs;
use super::ops::{self, NonConstOp};
-use super::qualifs::{NeedsDrop, Qualif};
+use super::qualifs::{NeedsNonConstDrop, Qualif};
use super::ConstCx;
/// Returns `true` if we should use the more precise live drop checker that runs after drop
@@ -54,7 +54,7 @@ impl<'mir, 'tcx> std::ops::Deref for CheckLiveDrops<'mir, 'tcx> {
type Target = ConstCx<'mir, 'tcx>;
fn deref(&self) -> &Self::Target {
- &self.ccx
+ self.ccx
}
}
@@ -83,8 +83,7 @@ impl<'tcx> Visitor<'tcx> for CheckLiveDrops<'_, 'tcx> {
mir::TerminatorKind::Drop { place: dropped_place, .. } => {
let dropped_ty = dropped_place.ty(self.body, self.tcx).ty;
- // FIXME(effects) use `NeedsNonConstDrop`
- if !NeedsDrop::in_any_value_of_ty(self.ccx, dropped_ty) {
+ if !NeedsNonConstDrop::in_any_value_of_ty(self.ccx, dropped_ty) {
// Instead of throwing a bug, we just return here. This is because we have to
// run custom `const Drop` impls.
return;
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
index de3186a53..7e1cbfe66 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -23,8 +23,7 @@ pub fn in_any_value_of_ty<'tcx>(
ConstQualifs {
has_mut_interior: HasMutInterior::in_any_value_of_ty(cx, ty),
needs_drop: NeedsDrop::in_any_value_of_ty(cx, ty),
- // FIXME(effects)
- needs_non_const_drop: NeedsDrop::in_any_value_of_ty(cx, ty),
+ needs_non_const_drop: NeedsNonConstDrop::in_any_value_of_ty(cx, ty),
custom_eq: CustomEq::in_any_value_of_ty(cx, ty),
tainted_by_errors,
}
@@ -155,12 +154,27 @@ impl Qualif for NeedsNonConstDrop {
return false;
}
- // FIXME(effects) constness
+ // FIXME(effects): If `destruct` is not a `const_trait`,
+ // or effects are disabled in this crate, then give up.
+ let destruct_def_id = cx.tcx.require_lang_item(LangItem::Destruct, Some(cx.body.span));
+ if cx.tcx.generics_of(destruct_def_id).host_effect_index.is_none()
+ || !cx.tcx.features().effects
+ {
+ return NeedsDrop::in_any_value_of_ty(cx, ty);
+ }
+
let obligation = Obligation::new(
cx.tcx,
ObligationCause::dummy_with_span(cx.body.span),
cx.param_env,
- ty::TraitRef::from_lang_item(cx.tcx, LangItem::Destruct, cx.body.span, [ty]),
+ ty::TraitRef::new(
+ cx.tcx,
+ destruct_def_id,
+ [
+ ty::GenericArg::from(ty),
+ ty::GenericArg::from(cx.tcx.expected_host_effect_param_for_body(cx.def_id())),
+ ],
+ ),
);
let infcx = cx.tcx.infer_ctxt().build();
diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs
index 32af537e2..8b2ea2dc2 100644
--- a/compiler/rustc_const_eval/src/transform/promote_consts.rs
+++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs
@@ -188,7 +188,7 @@ impl<'a, 'tcx> std::ops::Deref for Validator<'a, 'tcx> {
type Target = ConstCx<'a, 'tcx>;
fn deref(&self) -> &Self::Target {
- &self.ccx
+ self.ccx
}
}
@@ -229,7 +229,7 @@ impl<'tcx> Validator<'_, 'tcx> {
let statement = &self.body[loc.block].statements[loc.statement_index];
match &statement.kind {
StatementKind::Assign(box (_, rhs)) => qualifs::in_rvalue::<Q, _>(
- &self.ccx,
+ self.ccx,
&mut |l| self.qualif_local::<Q>(l),
rhs,
),
@@ -246,7 +246,7 @@ impl<'tcx> Validator<'_, 'tcx> {
match &terminator.kind {
TerminatorKind::Call { .. } => {
let return_ty = self.body.local_decls[local].ty;
- Q::in_any_value_of_ty(&self.ccx, return_ty)
+ Q::in_any_value_of_ty(self.ccx, return_ty)
}
kind => {
span_bug!(terminator.source_info.span, "{:?} not promotable", kind);
@@ -864,6 +864,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
};
// Use the underlying local for this (necessarily interior) borrow.
+ debug_assert!(region.is_erased());
let ty = local_decls[place.local].ty;
let span = statement.source_info.span;
@@ -873,8 +874,6 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
ty::TypeAndMut { ty, mutbl: borrow_kind.to_mutbl_lossy() },
);
- *region = tcx.lifetimes.re_erased;
-
let mut projection = vec![PlaceElem::Deref];
projection.extend(place.projection);
place.projection = tcx.mk_place_elems(&projection);
@@ -1024,36 +1023,3 @@ pub fn promote_candidates<'tcx>(
promotions
}
-
-/// This function returns `true` if the function being called in the array
-/// repeat expression is a `const` function.
-pub fn is_const_fn_in_array_repeat_expression<'tcx>(
- ccx: &ConstCx<'_, 'tcx>,
- place: &Place<'tcx>,
- body: &Body<'tcx>,
-) -> bool {
- match place.as_local() {
- // rule out cases such as: `let my_var = some_fn(); [my_var; N]`
- Some(local) if body.local_decls[local].is_user_variable() => return false,
- None => return false,
- _ => {}
- }
-
- for block in body.basic_blocks.iter() {
- if let Some(Terminator { kind: TerminatorKind::Call { func, destination, .. }, .. }) =
- &block.terminator
- {
- if let Operand::Constant(box ConstOperand { const_, .. }) = func {
- if let ty::FnDef(def_id, _) = *const_.ty().kind() {
- if destination == place {
- if ccx.tcx.is_const_fn(def_id) {
- return true;
- }
- }
- }
- }
- }
- }
-
- false
-}
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index 5922922d4..cca5b90ab 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -128,9 +128,9 @@ impl<'a, 'tcx> CfgChecker<'a, 'tcx> {
#[track_caller]
fn fail(&self, location: Location, msg: impl AsRef<str>) {
let span = self.body.source_info(location).span;
- // We use `delay_span_bug` as we might see broken MIR when other errors have already
+ // We use `span_delayed_bug` as we might see broken MIR when other errors have already
// occurred.
- self.tcx.sess.diagnostic().delay_span_bug(
+ self.tcx.sess.dcx().span_delayed_bug(
span,
format!(
"broken MIR in {:?} ({}) at {:?}:\n{}",
@@ -285,6 +285,12 @@ impl<'a, 'tcx> CfgChecker<'a, 'tcx> {
UnwindAction::Unreachable | UnwindAction::Terminate(UnwindTerminateReason::Abi) => (),
}
}
+
+ fn is_critical_call_edge(&self, target: Option<BasicBlock>, unwind: UnwindAction) -> bool {
+ let Some(target) = target else { return false };
+ matches!(unwind, UnwindAction::Cleanup(_) | UnwindAction::Terminate(_))
+ && self.body.basic_blocks.predecessors()[target].len() > 1
+ }
}
impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
@@ -425,6 +431,22 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
}
self.check_unwind_edge(location, *unwind);
+ // The code generation assumes that there are no critical call edges. The assumption
+ // is used to simplify inserting code that should be executed along the return edge
+ // from the call. FIXME(tmiasko): Since this is a strictly code generation concern,
+ // the code generation should be responsible for handling it.
+ if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Optimized)
+ && self.is_critical_call_edge(*target, *unwind)
+ {
+ self.fail(
+ location,
+ format!(
+ "encountered critical edge in `Call` terminator {:?}",
+ terminator.kind,
+ ),
+ );
+ }
+
// The call destination place and Operand::Move place used as an argument might be
// passed by a reference to the callee. Consequently they must be non-overlapping
// and cannot be packed. Currently this simply checks for duplicate places.
@@ -549,7 +571,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
fn visit_source_scope(&mut self, scope: SourceScope) {
if self.body.source_scopes.get(scope).is_none() {
- self.tcx.sess.diagnostic().delay_span_bug(
+ self.tcx.sess.dcx().span_delayed_bug(
self.body.span,
format!(
"broken MIR in {:?} ({}):\ninvalid source scope {:?}",