Auto merge of #108920 - matthiaskrgr:rollup-qrr9a0u, r=matthiaskrgr

Rollup of 8 pull requests

Successful merges:

 - #108754 (Retry `pred_known_to_hold_modulo_regions` with fulfillment if ambiguous)
 - #108759 (1.41.1 supported 32-bit Apple targets)
 - #108839 (Canonicalize root var when making response from new solver)
 - #108856 (Remove DropAndReplace terminator)
 - #108882 (Tweak E0740)
 - #108898 (Set `LIBC_CHECK_CFG=1` when building Rust code in bootstrap)
 - #108911 (Improve rustdoc-gui/tester.js code a bit)
 - #108916 (Remove an unused return value in `rustc_hir_typeck`)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2023-03-09 08:21:17 +00:00
commit 39f2657d11
71 changed files with 284 additions and 461 deletions

View File

@ -3861,6 +3861,8 @@ Version 1.41.1 (2020-02-27)
* [Always check types of static items][69145]
* [Always check lifetime bounds of `Copy` impls][69145]
* [Fix miscompilation in callers of `Layout::repeat`][69225]
* [Rust 1.41.0 was announced as the last Rust release with tier 1 or tier 2 support for 32-bit Apple targets][apple-32bit-drop].
That announcement did not expect a patch release. 1.41.1 also includes release binaries for these targets.
[69225]: https://github.com/rust-lang/rust/issues/69225
[69145]: https://github.com/rust-lang/rust/pull/69145
@ -3953,7 +3955,7 @@ Misc
Compatibility Notes
-------------------
- [As previously announced 1.41.0 will be the last tier 1 release for 32-bit
- [As previously announced 1.41 will be the last tier 1 release for 32-bit
Apple targets.][apple-32bit-drop] This means that the source code is still
available to build, but the targets are no longer being tested and release
binaries for those platforms will no longer be distributed by the Rust project.

View File

@ -118,15 +118,6 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
LocalMutationIsAllowed::Yes,
);
}
TerminatorKind::DropAndReplace {
place: drop_place,
value: new_value,
target: _,
unwind: _,
} => {
self.mutate_place(location, *drop_place, Deep);
self.consume_operand(location, new_value);
}
TerminatorKind::Call {
func,
args,

View File

@ -743,15 +743,6 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
flow_state,
);
}
TerminatorKind::DropAndReplace {
place: drop_place,
value: new_value,
target: _,
unwind: _,
} => {
self.mutate_place(loc, (*drop_place, span), Deep, flow_state);
self.consume_operand(loc, (new_value, span), flow_state);
}
TerminatorKind::Call {
func,
args,
@ -866,7 +857,6 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
| TerminatorKind::Assert { .. }
| TerminatorKind::Call { .. }
| TerminatorKind::Drop { .. }
| TerminatorKind::DropAndReplace { .. }
| TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ }
| TerminatorKind::FalseUnwind { real_target: _, unwind: _ }
| TerminatorKind::Goto { .. }

View File

@ -435,8 +435,7 @@ impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> {
//
// What we *actually* generate is a store to a temporary
// for the call (`TMP = call()...`) and then a
// `DropAndReplace` to swap that with `X`
// (`DropAndReplace` has very particular semantics).
// `Drop(X)` followed by `X = TMP` to swap that with `X`.
}
}

View File

@ -1312,24 +1312,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// no checks needed for these
}
TerminatorKind::DropAndReplace { place, value, target: _, unwind: _ } => {
let place_ty = place.ty(body, tcx).ty;
let rv_ty = value.ty(body, tcx);
let locations = term_location.to_locations();
if let Err(terr) =
self.sub_types(rv_ty, place_ty, locations, ConstraintCategory::Assignment)
{
span_mirbug!(
self,
term,
"bad DropAndReplace ({:?} = {:?}): {:?}",
place_ty,
rv_ty,
terr
);
}
}
TerminatorKind::SwitchInt { discr, .. } => {
self.check_operand(discr, term_location);
@ -1629,7 +1611,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
TerminatorKind::Unreachable => {}
TerminatorKind::Drop { target, unwind, .. }
| TerminatorKind::DropAndReplace { target, unwind, .. }
| TerminatorKind::Assert { target, cleanup: unwind, .. } => {
self.assert_iscleanup(body, block_data, target, is_cleanup);
if let Some(unwind) = unwind {

View File

@ -71,9 +71,6 @@ impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tc
TerminatorKind::Call { destination, .. } => {
self.remove_never_initialized_mut_locals(*destination);
}
TerminatorKind::DropAndReplace { place, .. } => {
self.remove_never_initialized_mut_locals(*place);
}
_ => {}
}

View File

@ -499,7 +499,6 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
TerminatorKind::Yield { .. }
| TerminatorKind::FalseEdge { .. }
| TerminatorKind::FalseUnwind { .. }
| TerminatorKind::DropAndReplace { .. }
| TerminatorKind::GeneratorDrop => {
bug!("shouldn't exist at codegen {:?}", bb_data.terminator());
}

View File

@ -543,8 +543,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
| TerminatorKind::Unreachable
| TerminatorKind::Drop { .. }
| TerminatorKind::Assert { .. } => {}
TerminatorKind::DropAndReplace { .. }
| TerminatorKind::Yield { .. }
TerminatorKind::Yield { .. }
| TerminatorKind::GeneratorDrop
| TerminatorKind::FalseEdge { .. }
| TerminatorKind::FalseUnwind { .. } => unreachable!(),

View File

@ -295,7 +295,6 @@ pub fn cleanup_kinds(mir: &mir::Body<'_>) -> IndexVec<mir::BasicBlock, CleanupKi
TerminatorKind::Call { cleanup: unwind, .. }
| TerminatorKind::InlineAsm { cleanup: unwind, .. }
| TerminatorKind::Assert { cleanup: unwind, .. }
| TerminatorKind::DropAndReplace { unwind, .. }
| TerminatorKind::Drop { unwind, .. } => {
if let Some(unwind) = unwind {
debug!(

View File

@ -1305,10 +1305,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
mergeable_succ(),
),
mir::TerminatorKind::DropAndReplace { .. } => {
bug!("undesugared DropAndReplace in codegen: {:?}", terminator);
}
mir::TerminatorKind::Call {
ref func,
ref args,

View File

@ -171,11 +171,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Unreachable => throw_ub!(Unreachable),
// These should never occur for MIR we actually run.
DropAndReplace { .. }
| FalseEdge { .. }
| FalseUnwind { .. }
| Yield { .. }
| GeneratorDrop => span_bug!(
FalseEdge { .. } | FalseUnwind { .. } | Yield { .. } | GeneratorDrop => span_bug!(
terminator.source_info.span,
"{:#?} should have been eliminated by MIR pass",
terminator.kind

View File

@ -985,8 +985,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
// Forbid all `Drop` terminators unless the place being dropped is a local with no
// projections that cannot be `NeedsNonConstDrop`.
TerminatorKind::Drop { place: dropped_place, .. }
| TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
TerminatorKind::Drop { place: dropped_place, .. } => {
// If we are checking live drops after drop-elaboration, don't emit duplicate
// errors here.
if super::post_drop_elaboration::checking_enabled(self.ccx) {

View File

@ -80,8 +80,7 @@ impl<'tcx> Visitor<'tcx> for CheckLiveDrops<'_, 'tcx> {
trace!("visit_terminator: terminator={:?} location={:?}", terminator, location);
match &terminator.kind {
mir::TerminatorKind::Drop { place: dropped_place, .. }
| mir::TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
mir::TerminatorKind::Drop { place: dropped_place, .. } => {
let dropped_ty = dropped_place.ty(self.body, self.tcx).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

View File

@ -222,23 +222,8 @@ where
// The effect of assignment to the return place in `TerminatorKind::Call` is not applied
// here; that occurs in `apply_call_return_effect`.
if let mir::TerminatorKind::DropAndReplace { value, place, .. } = &terminator.kind {
let qualif = qualifs::in_operand::<Q, _>(
self.ccx,
&mut |l| self.state.qualif.contains(l),
value,
);
if !place.is_indirect() {
self.assign_qualif_direct(place, qualif);
}
}
// We ignore borrow on drop because custom drop impls are not allowed in consts.
// FIXME: Reconsider if accounting for borrows in drops is necessary for const drop.
// We need to assign qualifs to the dropped location before visiting the operand that
// replaces it since qualifs can be cleared on move.
self.super_terminator(terminator, location);
}
}

View File

@ -846,18 +846,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
self.check_edge(location, *unwind, EdgeKind::Unwind);
}
}
TerminatorKind::DropAndReplace { target, unwind, .. } => {
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(
location,
"`DropAndReplace` should have been removed during drop elaboration",
);
}
self.check_edge(location, *target, EdgeKind::Normal);
if let Some(unwind) = unwind {
self.check_edge(location, *unwind, EdgeKind::Unwind);
}
}
TerminatorKind::Call { func, args, destination, target, cleanup, .. } => {
let func_ty = func.ty(&self.body.local_decls, self.tcx);
match func_ty.kind() {

View File

@ -163,3 +163,10 @@ hir_analysis_pass_to_variadic_function = can't pass `{$ty}` to variadic function
.help = cast the value to `{$cast_ty}`
hir_analysis_cast_thin_pointer_to_fat_pointer = cannot cast thin pointer `{$expr_ty}` to fat pointer `{$cast_ty}`
hir_analysis_invalid_union_field =
field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
.note = union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
hir_analysis_invalid_union_field_sugg =
wrap the field type in `ManuallyDrop<...>`

View File

@ -1,5 +1,5 @@
use crate::check::intrinsicck::InlineAsmCtxt;
use crate::errors::LinkageType;
use crate::errors::{self, LinkageType};
use super::compare_impl_item::check_type_bounds;
use super::compare_impl_item::{compare_impl_method, compare_impl_ty};
@ -114,9 +114,11 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b
allowed_union_field(*elem, tcx, param_env)
}
_ => {
// Fallback case: allow `ManuallyDrop` and things that are `Copy`.
// Fallback case: allow `ManuallyDrop` and things that are `Copy`,
// also no need to report an error if the type is unresolved.
ty.ty_adt_def().is_some_and(|adt_def| adt_def.is_manually_drop())
|| ty.is_copy_modulo_regions(tcx, param_env)
|| ty.references_error()
}
}
}
@ -131,26 +133,14 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b
Some(Node::Field(field)) => (field.span, field.ty.span),
_ => unreachable!("mir field has to correspond to hir field"),
};
struct_span_err!(
tcx.sess,
tcx.sess.emit_err(errors::InvalidUnionField {
field_span,
E0740,
"unions cannot contain fields that may need dropping"
)
.note(
"a type is guaranteed not to need dropping \
when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type",
)
.multipart_suggestion_verbose(
"when the type does not implement `Copy`, \
wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped",
vec![
(ty_span.shrink_to_lo(), "std::mem::ManuallyDrop<".into()),
(ty_span.shrink_to_hi(), ">".into()),
],
Applicability::MaybeIncorrect,
)
.emit();
sugg: errors::InvalidUnionFieldSuggestion {
lo: ty_span.shrink_to_lo(),
hi: ty_span.shrink_to_hi(),
},
note: (),
});
return false;
} else if field_ty.needs_drop(tcx, param_env) {
// This should never happen. But we can get here e.g. in case of name resolution errors.

View File

@ -5,7 +5,7 @@ use rustc_errors::{
error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic,
MultiSpan,
};
use rustc_macros::Diagnostic;
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_middle::ty::Ty;
use rustc_span::{symbol::Ident, Span, Symbol};
@ -430,3 +430,23 @@ pub(crate) struct CastThinPointerToFatPointer<'tcx> {
pub expr_ty: Ty<'tcx>,
pub cast_ty: String,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_invalid_union_field, code = "E0740")]
pub(crate) struct InvalidUnionField {
#[primary_span]
pub field_span: Span,
#[subdiagnostic]
pub sugg: InvalidUnionFieldSuggestion,
#[note]
pub note: (),
}
#[derive(Subdiagnostic)]
#[multipart_suggestion(hir_analysis_invalid_union_field_sugg, applicability = "machine-applicable")]
pub(crate) struct InvalidUnionFieldSuggestion {
#[suggestion_part(code = "std::mem::ManuallyDrop<")]
pub lo: Span,
#[suggestion_part(code = ">")]
pub hi: Span,
}

View File

@ -301,16 +301,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span: Span,
def_id: DefId,
substs: SubstsRef<'tcx>,
) -> (ty::InstantiatedPredicates<'tcx>, Vec<Span>) {
) -> ty::InstantiatedPredicates<'tcx> {
let bounds = self.tcx.predicates_of(def_id);
let spans: Vec<Span> = bounds.predicates.iter().map(|(_, span)| *span).collect();
let result = bounds.instantiate(self.tcx, substs);
let result = self.normalize(span, result);
debug!(
"instantiate_bounds(bounds={:?}, substs={:?}) = {:?}, {:?}",
bounds, substs, result, spans,
);
(result, spans)
debug!("instantiate_bounds(bounds={:?}, substs={:?}) = {:?}", bounds, substs, result);
result
}
pub(in super::super) fn normalize<T>(&self, span: Span, value: T) -> T
@ -1389,7 +1385,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
_ => false,
};
let (bounds, _) = self.instantiate_bounds(span, def_id, &substs);
let bounds = self.instantiate_bounds(span, def_id, &substs);
for mut obligation in traits::predicates_for_generics(
|idx, predicate_span| {

View File

@ -374,9 +374,18 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
}
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
fn fold_ty(&mut self, mut t: Ty<'tcx>) -> Ty<'tcx> {
match *t.kind() {
ty::Infer(ty::TyVar(vid)) => {
ty::Infer(ty::TyVar(mut vid)) => {
// We need to canonicalize the *root* of our ty var.
// This is so that our canonical response correctly reflects
// any equated inference vars correctly!
let root_vid = self.infcx.root_var(vid);
if root_vid != vid {
t = self.infcx.tcx.mk_ty_var(root_vid);
vid = root_vid;
}
debug!("canonical: type var found with vid {:?}", vid);
match self.infcx.probe_ty_var(vid) {
// `t` could be a float / int variable; canonicalize that instead.
@ -467,9 +476,18 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
}
}
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
fn fold_const(&mut self, mut ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
match ct.kind() {
ty::ConstKind::Infer(InferConst::Var(vid)) => {
ty::ConstKind::Infer(InferConst::Var(mut vid)) => {
// We need to canonicalize the *root* of our const var.
// This is so that our canonical response correctly reflects
// any equated inference vars correctly!
let root_vid = self.infcx.root_const_var(vid);
if root_vid != vid {
ct = self.infcx.tcx.mk_const(ty::InferConst::Var(root_vid), ct.ty());
vid = root_vid;
}
debug!("canonical: const var found with vid {:?}", vid);
match self.infcx.probe_const_var(vid) {
Ok(c) => {

View File

@ -1359,6 +1359,10 @@ impl<'tcx> InferCtxt<'tcx> {
self.inner.borrow_mut().type_variables().root_var(var)
}
pub fn root_const_var(&self, var: ty::ConstVid<'tcx>) -> ty::ConstVid<'tcx> {
self.inner.borrow_mut().const_unification_table().find(var)
}
/// Where possible, replaces type/const variables in
/// `value` with their final value. Note that region variables
/// are unaffected. If a type/const variable has not been unified, it

View File

@ -265,7 +265,6 @@ pub fn terminator_kind_name(term: &Terminator<'_>) -> &'static str {
Return => "Return",
Unreachable => "Unreachable",
Drop { .. } => "Drop",
DropAndReplace { .. } => "DropAndReplace",
Call { .. } => "Call",
Assert { .. } => "Assert",
Yield { .. } => "Yield",

View File

@ -133,7 +133,6 @@ pub enum AnalysisPhase {
pub enum RuntimePhase {
/// In addition to the semantic changes, beginning with this phase, the following variants are
/// disallowed:
/// * [`TerminatorKind::DropAndReplace`]
/// * [`TerminatorKind::Yield`]
/// * [`TerminatorKind::GeneratorDrop`]
/// * [`Rvalue::Aggregate`] for any `AggregateKind` except `Array`
@ -596,43 +595,6 @@ pub enum TerminatorKind<'tcx> {
/// > consider indirect assignments.
Drop { place: Place<'tcx>, target: BasicBlock, unwind: Option<BasicBlock> },
/// Drops the place and assigns a new value to it.
///
/// This first performs the exact same operation as the pre drop-elaboration `Drop` terminator;
/// it then additionally assigns the `value` to the `place` as if by an assignment statement.
/// This assignment occurs both in the unwind and the regular code paths. The semantics are best
/// explained by the elaboration:
///
/// ```ignore (MIR)
/// BB0 {
/// DropAndReplace(P <- V, goto BB1, unwind BB2)
/// }
/// ```
///
/// becomes
///
/// ```ignore (MIR)
/// BB0 {
/// Drop(P, goto BB1, unwind BB2)
/// }
/// BB1 {
/// // P is now uninitialized
/// P <- V
/// }
/// BB2 {
/// // P is now uninitialized -- its dtor panicked
/// P <- V
/// }
/// ```
///
/// Disallowed after drop elaboration.
DropAndReplace {
place: Place<'tcx>,
value: Operand<'tcx>,
target: BasicBlock,
unwind: Option<BasicBlock>,
},
/// Roughly speaking, evaluates the `func` operand and the arguments, and starts execution of
/// the referred to function. The operand types must match the argument types of the function.
/// The return place type must match the return type. The type of the `func` operand must be

View File

@ -148,7 +148,6 @@ impl<'tcx> TerminatorKind<'tcx> {
| Call { target: None, cleanup: Some(t), .. }
| Call { target: Some(t), cleanup: None, .. }
| Yield { resume: t, drop: None, .. }
| DropAndReplace { target: t, unwind: None, .. }
| Drop { target: t, unwind: None, .. }
| Assert { target: t, cleanup: None, .. }
| FalseUnwind { real_target: t, unwind: None }
@ -158,7 +157,6 @@ impl<'tcx> TerminatorKind<'tcx> {
}
Call { target: Some(t), cleanup: Some(ref u), .. }
| Yield { resume: t, drop: Some(ref u), .. }
| DropAndReplace { target: t, unwind: Some(ref u), .. }
| Drop { target: t, unwind: Some(ref u), .. }
| Assert { target: t, cleanup: Some(ref u), .. }
| FalseUnwind { real_target: t, unwind: Some(ref u) }
@ -188,7 +186,6 @@ impl<'tcx> TerminatorKind<'tcx> {
| Call { target: None, cleanup: Some(ref mut t), .. }
| Call { target: Some(ref mut t), cleanup: None, .. }
| Yield { resume: ref mut t, drop: None, .. }
| DropAndReplace { target: ref mut t, unwind: None, .. }
| Drop { target: ref mut t, unwind: None, .. }
| Assert { target: ref mut t, cleanup: None, .. }
| FalseUnwind { real_target: ref mut t, unwind: None }
@ -198,7 +195,6 @@ impl<'tcx> TerminatorKind<'tcx> {
}
Call { target: Some(ref mut t), cleanup: Some(ref mut u), .. }
| Yield { resume: ref mut t, drop: Some(ref mut u), .. }
| DropAndReplace { target: ref mut t, unwind: Some(ref mut u), .. }
| Drop { target: ref mut t, unwind: Some(ref mut u), .. }
| Assert { target: ref mut t, cleanup: Some(ref mut u), .. }
| FalseUnwind { real_target: ref mut t, unwind: Some(ref mut u) }
@ -225,7 +221,6 @@ impl<'tcx> TerminatorKind<'tcx> {
| TerminatorKind::FalseEdge { .. } => None,
TerminatorKind::Call { cleanup: ref unwind, .. }
| TerminatorKind::Assert { cleanup: ref unwind, .. }
| TerminatorKind::DropAndReplace { ref unwind, .. }
| TerminatorKind::Drop { ref unwind, .. }
| TerminatorKind::FalseUnwind { ref unwind, .. }
| TerminatorKind::InlineAsm { cleanup: ref unwind, .. } => Some(unwind),
@ -245,7 +240,6 @@ impl<'tcx> TerminatorKind<'tcx> {
| TerminatorKind::FalseEdge { .. } => None,
TerminatorKind::Call { cleanup: ref mut unwind, .. }
| TerminatorKind::Assert { cleanup: ref mut unwind, .. }
| TerminatorKind::DropAndReplace { ref mut unwind, .. }
| TerminatorKind::Drop { ref mut unwind, .. }
| TerminatorKind::FalseUnwind { ref mut unwind, .. }
| TerminatorKind::InlineAsm { cleanup: ref mut unwind, .. } => Some(unwind),
@ -309,9 +303,6 @@ impl<'tcx> TerminatorKind<'tcx> {
Yield { value, resume_arg, .. } => write!(fmt, "{:?} = yield({:?})", resume_arg, value),
Unreachable => write!(fmt, "unreachable"),
Drop { place, .. } => write!(fmt, "drop({:?})", place),
DropAndReplace { place, value, .. } => {
write!(fmt, "replace({:?} <- {:?})", place, value)
}
Call { func, args, destination, .. } => {
write!(fmt, "{:?} = ", destination)?;
write!(fmt, "{:?}(", func)?;
@ -403,10 +394,10 @@ impl<'tcx> TerminatorKind<'tcx> {
Call { target: None, cleanup: None, .. } => vec![],
Yield { drop: Some(_), .. } => vec!["resume".into(), "drop".into()],
Yield { drop: None, .. } => vec!["resume".into()],
DropAndReplace { unwind: None, .. } | Drop { unwind: None, .. } => {
Drop { unwind: None, .. } => {
vec!["return".into()]
}
DropAndReplace { unwind: Some(_), .. } | Drop { unwind: Some(_), .. } => {
Drop { unwind: Some(_), .. } => {
vec!["return".into(), "unwind".into()]
}
Assert { cleanup: None, .. } => vec!["".into()],

View File

@ -495,20 +495,6 @@ macro_rules! make_mir_visitor {
);
}
TerminatorKind::DropAndReplace {
place,
value,
target: _,
unwind: _,
} => {
self.visit_place(
place,
PlaceContext::MutatingUse(MutatingUseContext::Drop),
location
);
self.visit_operand(value, location);
}
TerminatorKind::Call {
func,
args,

View File

@ -59,14 +59,6 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
unwind: None,
})
},
@call("mir_drop_and_replace", args) => {
Ok(TerminatorKind::DropAndReplace {
place: self.parse_place(args[0])?,
value: self.parse_operand(args[1])?,
target: self.parse_block(args[2])?,
unwind: None,
})
},
@call("mir_call", args) => {
let destination = self.parse_place(args[0])?;
let target = self.parse_block(args[1])?;

View File

@ -1072,7 +1072,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
TerminatorKind::Assert { .. }
| TerminatorKind::Call { .. }
| TerminatorKind::Drop { .. }
| TerminatorKind::DropAndReplace { .. }
| TerminatorKind::FalseUnwind { .. }
| TerminatorKind::InlineAsm { .. }
),
@ -1432,8 +1431,7 @@ impl<'tcx> DropTreeBuilder<'tcx> for Unwind {
*unwind = Some(to);
}
}
TerminatorKind::DropAndReplace { unwind, .. }
| TerminatorKind::FalseUnwind { unwind, .. }
TerminatorKind::FalseUnwind { unwind, .. }
| TerminatorKind::Call { cleanup: unwind, .. }
| TerminatorKind::Assert { cleanup: unwind, .. }
| TerminatorKind::InlineAsm { cleanup: unwind, .. } => {

View File

@ -128,7 +128,6 @@ impl<'mir, 'tcx> TriColorVisitor<BasicBlocks<'tcx>> for Search<'mir, 'tcx> {
TerminatorKind::Assert { .. }
| TerminatorKind::Call { .. }
| TerminatorKind::Drop { .. }
| TerminatorKind::DropAndReplace { .. }
| TerminatorKind::FalseEdge { .. }
| TerminatorKind::FalseUnwind { .. }
| TerminatorKind::Goto { .. }

View File

@ -480,7 +480,6 @@ impl Direction for Forward {
Assert { target, cleanup: unwind, expected: _, msg: _, cond: _ }
| Drop { target, unwind, place: _ }
| DropAndReplace { target, unwind, value: _, place: _ }
| FalseUnwind { real_target: target, unwind } => {
if let Some(unwind) = unwind {
propagate(unwind, exit_state);

View File

@ -111,8 +111,7 @@ where
self.super_terminator(terminator, location);
match terminator.kind {
mir::TerminatorKind::Drop { place: dropped_place, .. }
| mir::TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
mir::TerminatorKind::Drop { place: dropped_place, .. } => {
// Drop terminators may call custom drop glue (`Drop::drop`), which takes `&mut
// self` as a parameter. In the general case, a drop impl could launder that
// reference into the surrounding environment through a raw pointer, thus creating

View File

@ -202,7 +202,6 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
TerminatorKind::Abort
| TerminatorKind::Assert { .. }
| TerminatorKind::Drop { .. }
| TerminatorKind::DropAndReplace { .. }
| TerminatorKind::FalseEdge { .. }
| TerminatorKind::FalseUnwind { .. }
| TerminatorKind::GeneratorDrop
@ -240,7 +239,6 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
| TerminatorKind::Abort
| TerminatorKind::Assert { .. }
| TerminatorKind::Drop { .. }
| TerminatorKind::DropAndReplace { .. }
| TerminatorKind::FalseEdge { .. }
| TerminatorKind::FalseUnwind { .. }
| TerminatorKind::GeneratorDrop

View File

@ -392,11 +392,6 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
self.create_move_path(place);
self.gather_init(place.as_ref(), InitKind::Deep);
}
TerminatorKind::DropAndReplace { place, ref value, .. } => {
self.create_move_path(place);
self.gather_operand(value);
self.gather_init(place.as_ref(), InitKind::Deep);
}
TerminatorKind::Call {
ref func,
ref args,

View File

@ -230,7 +230,7 @@ pub trait ValueAnalysis<'tcx> {
TerminatorKind::Drop { place, .. } => {
state.flood_with(place.as_ref(), self.map(), Self::Value::bottom());
}
TerminatorKind::DropAndReplace { .. } | TerminatorKind::Yield { .. } => {
TerminatorKind::Yield { .. } => {
// They would have an effect, but are not allowed in this phase.
bug!("encountered disallowed terminator");
}

View File

@ -74,7 +74,7 @@ impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls {
};
layout::fn_can_unwind(tcx, fn_def_id, sig.abi())
}
TerminatorKind::Drop { .. } | TerminatorKind::DropAndReplace { .. } => {
TerminatorKind::Drop { .. } => {
tcx.sess.opts.unstable_opts.panic_in_drop == PanicStrategy::Unwind
&& layout::fn_can_unwind(tcx, None, Abi::Rust)
}

View File

@ -64,9 +64,6 @@ fn add_moves_for_packed_drops_patch<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>)
{
add_move_for_packed_drop(tcx, body, &mut patch, terminator, loc, data.is_cleanup);
}
TerminatorKind::DropAndReplace { .. } => {
span_bug!(terminator.source_info.span, "replace in AddMovesForPackedDrops");
}
_ => {}
}
}

View File

@ -100,7 +100,7 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
}
// `Drop` is also a call, but it doesn't return anything so we are good.
TerminatorKind::Drop { .. } | TerminatorKind::DropAndReplace { .. } => None,
TerminatorKind::Drop { .. } => None,
// Not a block ending in a Call -> ignore.
_ => None,
}

View File

@ -55,7 +55,6 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
| TerminatorKind::Drop { .. }
| TerminatorKind::Yield { .. }
| TerminatorKind::Assert { .. }
| TerminatorKind::DropAndReplace { .. }
| TerminatorKind::GeneratorDrop
| TerminatorKind::Resume
| TerminatorKind::Abort

View File

@ -1007,7 +1007,6 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
| TerminatorKind::Return
| TerminatorKind::Unreachable
| TerminatorKind::Drop { .. }
| TerminatorKind::DropAndReplace { .. }
| TerminatorKind::Yield { .. }
| TerminatorKind::GeneratorDrop
| TerminatorKind::FalseEdge { .. }

View File

@ -686,7 +686,6 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
| TerminatorKind::Return
| TerminatorKind::Unreachable
| TerminatorKind::Drop { .. }
| TerminatorKind::DropAndReplace { .. }
| TerminatorKind::Yield { .. }
| TerminatorKind::GeneratorDrop
| TerminatorKind::FalseEdge { .. }

View File

@ -822,7 +822,6 @@ pub(super) fn term_type(kind: &TerminatorKind<'_>) -> &'static str {
TerminatorKind::Return => "Return",
TerminatorKind::Unreachable => "Unreachable",
TerminatorKind::Drop { .. } => "Drop",
TerminatorKind::DropAndReplace { .. } => "DropAndReplace",
TerminatorKind::Call { .. } => "Call",
TerminatorKind::Assert { .. } => "Assert",
TerminatorKind::Yield { .. } => "Yield",

View File

@ -156,7 +156,6 @@ impl CoverageGraph {
| TerminatorKind::Resume
| TerminatorKind::Unreachable
| TerminatorKind::Drop { .. }
| TerminatorKind::DropAndReplace { .. }
| TerminatorKind::Call { .. }
| TerminatorKind::GeneratorDrop
| TerminatorKind::Assert { .. }

View File

@ -850,7 +850,6 @@ pub(super) fn filtered_terminator_span(terminator: &Terminator<'_>) -> Option<Sp
TerminatorKind::Unreachable // Unreachable blocks are not connected to the MIR CFG
| TerminatorKind::Assert { .. }
| TerminatorKind::Drop { .. }
| TerminatorKind::DropAndReplace { .. }
| TerminatorKind::SwitchInt { .. }
// For `FalseEdge`, only the `real` branch is taken, so it is similar to a `Goto`.
| TerminatorKind::FalseEdge { .. }

View File

@ -86,7 +86,6 @@ impl<'tcx> MockBlocks<'tcx> {
TerminatorKind::Assert { ref mut target, .. }
| TerminatorKind::Call { target: Some(ref mut target), .. }
| TerminatorKind::Drop { ref mut target, .. }
| TerminatorKind::DropAndReplace { ref mut target, .. }
| TerminatorKind::FalseEdge { real_target: ref mut target, .. }
| TerminatorKind::FalseUnwind { real_target: ref mut target, .. }
| TerminatorKind::Goto { ref mut target }
@ -184,7 +183,6 @@ fn debug_basic_blocks(mir_body: &Body<'_>) -> String {
TerminatorKind::Assert { target, .. }
| TerminatorKind::Call { target: Some(target), .. }
| TerminatorKind::Drop { target, .. }
| TerminatorKind::DropAndReplace { target, .. }
| TerminatorKind::FalseEdge { real_target: target, .. }
| TerminatorKind::FalseUnwind { real_target: target, .. }
| TerminatorKind::Goto { target }

View File

@ -650,8 +650,7 @@ impl WriteInfo {
TerminatorKind::Drop { .. } => {
// `Drop`s create a `&mut` and so are not considered
}
TerminatorKind::DropAndReplace { .. }
| TerminatorKind::Yield { .. }
TerminatorKind::Yield { .. }
| TerminatorKind::GeneratorDrop
| TerminatorKind::FalseEdge { .. }
| TerminatorKind::FalseUnwind { .. } => {

View File

@ -18,15 +18,14 @@ use rustc_span::{DesugaringKind, Span};
use rustc_target::abi::VariantIdx;
use std::fmt;
/// During MIR building, Drop and DropAndReplace terminators are inserted in every place where a drop may occur.
/// During MIR building, Drop terminators are inserted in every place where a drop may occur.
/// However, in this phase, the presence of these terminators does not guarantee that a destructor will run,
/// as the target of the drop may be uninitialized.
/// In general, the compiler cannot determine at compile time whether a destructor will run or not.
///
/// At a high level, this pass refines Drop and DropAndReplace to only run the destructor if the
/// At a high level, this pass refines Drop to only run the destructor if the
/// target is initialized. The way this is achievied is by inserting drop flags for every variable
/// that may be dropped, and then using those flags to determine whether a destructor should run.
/// This pass also removes DropAndReplace, replacing it with a Drop paired with an assign statement.
/// Once this is complete, Drop terminators in the MIR correspond to a call to the "drop glue" or
/// "drop shim" for the type of the dropped place.
///
@ -121,8 +120,7 @@ fn remove_dead_unwinds<'tcx>(
.into_results_cursor(body);
for (bb, bb_data) in body.basic_blocks.iter_enumerated() {
let place = match bb_data.terminator().kind {
TerminatorKind::Drop { ref place, unwind: Some(_), .. }
| TerminatorKind::DropAndReplace { ref place, unwind: Some(_), .. } => {
TerminatorKind::Drop { ref place, unwind: Some(_), .. } => {
und.derefer(place.as_ref(), body).unwrap_or(*place)
}
_ => continue,
@ -343,8 +341,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
}
let terminator = data.terminator();
let place = match terminator.kind {
TerminatorKind::Drop { ref place, .. }
| TerminatorKind::DropAndReplace { ref place, .. } => {
TerminatorKind::Drop { ref place, .. } => {
self.un_derefer.derefer(place.as_ref(), self.body).unwrap_or(*place)
}
_ => continue,
@ -441,103 +438,11 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
}
}
}
TerminatorKind::DropAndReplace { mut place, ref value, target, unwind } => {
assert!(!data.is_cleanup);
if let Some(new_place) = self.un_derefer.derefer(place.as_ref(), self.body) {
place = new_place;
}
self.elaborate_replace(loc, place, value, target, unwind);
}
_ => continue,
}
}
}
/// Elaborate a MIR `replace` terminator. This instruction
/// is not directly handled by codegen, and therefore
/// must be desugared.
///
/// The desugaring drops the location if needed, and then writes
/// the value (including setting the drop flag) over it in *both* arms.
///
/// The `replace` terminator can also be called on places that
/// are not tracked by elaboration (for example,
/// `replace x[i] <- tmp0`). The borrow checker requires that
/// these locations are initialized before the assignment,
/// so we just generate an unconditional drop.
fn elaborate_replace(
&mut self,
loc: Location,
place: Place<'tcx>,
value: &Operand<'tcx>,
target: BasicBlock,
unwind: Option<BasicBlock>,
) {
let bb = loc.block;
let data = &self.body[bb];
let terminator = data.terminator();
assert!(!data.is_cleanup, "DropAndReplace in unwind path not supported");
let assign = Statement {
kind: StatementKind::Assign(Box::new((place, Rvalue::Use(value.clone())))),
source_info: terminator.source_info,
};
let unwind = unwind.unwrap_or_else(|| self.patch.resume_block());
let unwind = self.patch.new_block(BasicBlockData {
statements: vec![assign.clone()],
terminator: Some(Terminator {
kind: TerminatorKind::Goto { target: unwind },
..*terminator
}),
is_cleanup: true,
});
let target = self.patch.new_block(BasicBlockData {
statements: vec![assign],
terminator: Some(Terminator { kind: TerminatorKind::Goto { target }, ..*terminator }),
is_cleanup: false,
});
match self.move_data().rev_lookup.find(place.as_ref()) {
LookupResult::Exact(path) => {
debug!("elaborate_drop_and_replace({:?}) - tracked {:?}", terminator, path);
self.init_data.seek_before(loc);
elaborate_drop(
&mut Elaborator { ctxt: self },
terminator.source_info,
place,
path,
target,
Unwind::To(unwind),
bb,
);
on_all_children_bits(self.tcx, self.body, self.move_data(), path, |child| {
self.set_drop_flag(
Location { block: target, statement_index: 0 },
child,
DropFlagState::Present,
);
self.set_drop_flag(
Location { block: unwind, statement_index: 0 },
child,
DropFlagState::Present,
);
});
}
LookupResult::Parent(parent) => {
// drop and replace behind a pointer/array/whatever. The location
// must be initialized.
debug!("elaborate_drop_and_replace({:?}) - untracked {:?}", terminator, parent);
self.patch.patch_terminator(
bb,
TerminatorKind::Drop { place, target, unwind: Some(unwind) },
);
}
}
}
fn constant_bool(&self, span: Span, val: bool) -> Rvalue<'tcx> {
Rvalue::Use(Operand::Constant(Box::new(Constant {
span,
@ -609,22 +514,12 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
debug!("drop_flags_for_locs({:?})", data);
for i in 0..(data.statements.len() + 1) {
debug!("drop_flag_for_locs: stmt {}", i);
let mut allow_initializations = true;
if i == data.statements.len() {
match data.terminator().kind {
TerminatorKind::Drop { .. } => {
// drop elaboration should handle that by itself
continue;
}
TerminatorKind::DropAndReplace { .. } => {
// this contains the move of the source and
// the initialization of the destination. We
// only want the former - the latter is handled
// by the elaboration code and must be done
// *after* the destination is dropped.
assert!(self.patch.is_patched(bb));
allow_initializations = false;
}
TerminatorKind::Resume => {
// It is possible for `Resume` to be patched
// (in particular it can be patched to be replaced with
@ -641,11 +536,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
self.body,
self.env,
loc,
|path, ds| {
if ds == DropFlagState::Absent || allow_initializations {
self.set_drop_flag(loc, path, ds)
}
},
|path, ds| self.set_drop_flag(loc, path, ds),
)
}

View File

@ -1199,7 +1199,6 @@ fn can_unwind<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool {
// These may unwind.
TerminatorKind::Drop { .. }
| TerminatorKind::DropAndReplace { .. }
| TerminatorKind::Call { .. }
| TerminatorKind::InlineAsm { .. }
| TerminatorKind::Assert { .. } => return true,
@ -1691,7 +1690,6 @@ impl<'tcx> Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
| TerminatorKind::Return
| TerminatorKind::Unreachable
| TerminatorKind::Drop { .. }
| TerminatorKind::DropAndReplace { .. }
| TerminatorKind::Assert { .. }
| TerminatorKind::GeneratorDrop
| TerminatorKind::FalseEdge { .. }

View File

@ -453,9 +453,7 @@ impl<'tcx> Inliner<'tcx> {
checker.visit_basic_block_data(bb, blk);
let term = blk.terminator();
if let TerminatorKind::Drop { ref place, target, unwind }
| TerminatorKind::DropAndReplace { ref place, target, unwind, .. } = term.kind
{
if let TerminatorKind::Drop { ref place, target, unwind } = term.kind {
work_list.push(target);
// If the place doesn't actually need dropping, treat it like a regular goto.
@ -815,8 +813,7 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
let tcx = self.tcx;
match terminator.kind {
TerminatorKind::Drop { ref place, unwind, .. }
| TerminatorKind::DropAndReplace { ref place, unwind, .. } => {
TerminatorKind::Drop { ref place, unwind, .. } => {
// If the place doesn't actually need dropping, treat it like a regular goto.
let ty = self.instance.subst_mir(tcx, &place.ty(self.callee_body, tcx).ty);
if ty.needs_drop(tcx, self.param_env) {
@ -1120,8 +1117,7 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> {
*tgt = self.map_block(*tgt);
}
}
TerminatorKind::Drop { ref mut target, ref mut unwind, .. }
| TerminatorKind::DropAndReplace { ref mut target, ref mut unwind, .. } => {
TerminatorKind::Drop { ref mut target, ref mut unwind, .. } => {
*target = self.map_block(*target);
*unwind = self.map_unwind(*unwind);
}

View File

@ -75,7 +75,6 @@ impl RemoveNoopLandingPads {
| TerminatorKind::Unreachable
| TerminatorKind::Call { .. }
| TerminatorKind::Assert { .. }
| TerminatorKind::DropAndReplace { .. }
| TerminatorKind::Drop { .. }
| TerminatorKind::InlineAsm { .. } => false,
}

View File

@ -1,5 +1,5 @@
use rustc_index::bit_set::ChunkedBitSet;
use rustc_middle::mir::{Body, Field, Rvalue, Statement, StatementKind, TerminatorKind};
use rustc_middle::mir::{Body, Field, TerminatorKind};
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, VariantDef};
use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
@ -8,7 +8,7 @@ use rustc_mir_dataflow::{self, move_path_children_matching, Analysis, MoveDataPa
use crate::MirPass;
/// Removes `Drop` and `DropAndReplace` terminators whose target is known to be uninitialized at
/// Removes `Drop` terminators whose target is known to be uninitialized at
/// that point.
///
/// This is redundant with drop elaboration, but we need to do it prior to const-checking, and
@ -37,8 +37,7 @@ impl<'tcx> MirPass<'tcx> for RemoveUninitDrops {
let mut to_remove = vec![];
for (bb, block) in body.basic_blocks.iter_enumerated() {
let terminator = block.terminator();
let (TerminatorKind::Drop { place, .. } | TerminatorKind::DropAndReplace { place, .. })
= &terminator.kind
let TerminatorKind::Drop { place, .. } = &terminator.kind
else { continue };
maybe_inits.seek_before_primary_effect(body.terminator_loc(bb));
@ -64,24 +63,12 @@ impl<'tcx> MirPass<'tcx> for RemoveUninitDrops {
for bb in to_remove {
let block = &mut body.basic_blocks_mut()[bb];
let (TerminatorKind::Drop { target, .. } | TerminatorKind::DropAndReplace { target, .. })
let TerminatorKind::Drop { target, .. }
= &block.terminator().kind
else { unreachable!() };
// Replace block terminator with `Goto`.
let target = *target;
let old_terminator_kind = std::mem::replace(
&mut block.terminator_mut().kind,
TerminatorKind::Goto { target },
);
// If this is a `DropAndReplace`, we need to emulate the assignment to the return place.
if let TerminatorKind::DropAndReplace { place, value, .. } = old_terminator_kind {
block.statements.push(Statement {
source_info: block.terminator().source_info,
kind: StatementKind::Assign(Box::new((place, Rvalue::Use(value)))),
});
}
block.terminator_mut().kind = TerminatorKind::Goto { target: *target };
}
}
}

View File

@ -108,7 +108,6 @@ pub fn separate_const_switch(body: &mut Body<'_>) -> usize {
// The following terminators are not allowed
TerminatorKind::Resume
| TerminatorKind::Drop { .. }
| TerminatorKind::DropAndReplace { .. }
| TerminatorKind::Call { .. }
| TerminatorKind::Assert { .. }
| TerminatorKind::FalseUnwind { .. }
@ -170,7 +169,6 @@ pub fn separate_const_switch(body: &mut Body<'_>) -> usize {
| TerminatorKind::Unreachable
| TerminatorKind::GeneratorDrop
| TerminatorKind::Assert { .. }
| TerminatorKind::DropAndReplace { .. }
| TerminatorKind::FalseUnwind { .. }
| TerminatorKind::Drop { .. }
| TerminatorKind::Call { .. }

View File

@ -808,8 +808,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
let callee_ty = self.monomorphize(callee_ty);
visit_fn_use(self.tcx, callee_ty, true, source, &mut self.output)
}
mir::TerminatorKind::Drop { ref place, .. }
| mir::TerminatorKind::DropAndReplace { ref place, .. } => {
mir::TerminatorKind::Drop { ref place, .. } => {
let ty = place.ty(self.body, self.tcx).ty;
let ty = self.monomorphize(ty);
visit_drop_use(self.tcx, ty, true, source, self.output);

View File

@ -261,12 +261,23 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
self.interner().mk_re_late_bound(self.binder_index, br)
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
fn fold_ty(&mut self, mut t: Ty<'tcx>) -> Ty<'tcx> {
let kind = match *t.kind() {
ty::Infer(ty::TyVar(vid)) => match self.infcx.probe_ty_var(vid) {
Ok(t) => return self.fold_ty(t),
Err(ui) => CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)),
},
ty::Infer(ty::TyVar(mut vid)) => {
// We need to canonicalize the *root* of our ty var.
// This is so that our canonical response correctly reflects
// any equated inference vars correctly!
let root_vid = self.infcx.root_var(vid);
if root_vid != vid {
t = self.infcx.tcx.mk_ty_var(root_vid);
vid = root_vid;
}
match self.infcx.probe_ty_var(vid) {
Ok(t) => return self.fold_ty(t),
Err(ui) => CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)),
}
}
ty::Infer(ty::IntVar(_)) => {
let nt = self.infcx.shallow_resolve(t);
if nt != t {
@ -338,13 +349,23 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
self.interner().mk_bound(self.binder_index, bt)
}
fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
fn fold_const(&mut self, mut c: ty::Const<'tcx>) -> ty::Const<'tcx> {
let kind = match c.kind() {
ty::ConstKind::Infer(ty::InferConst::Var(vid)) => match self.infcx.probe_const_var(vid)
{
Ok(c) => return self.fold_const(c),
Err(universe) => CanonicalVarKind::Const(universe, c.ty()),
},
ty::ConstKind::Infer(ty::InferConst::Var(mut vid)) => {
// We need to canonicalize the *root* of our const var.
// This is so that our canonical response correctly reflects
// any equated inference vars correctly!
let root_vid = self.infcx.root_const_var(vid);
if root_vid != vid {
c = self.infcx.tcx.mk_const(ty::InferConst::Var(root_vid), c.ty());
vid = root_vid;
}
match self.infcx.probe_const_var(vid) {
Ok(c) => return self.fold_const(c),
Err(universe) => CanonicalVarKind::Const(universe, c.ty()),
}
}
ty::ConstKind::Infer(ty::InferConst::Fresh(_)) => {
bug!("fresh var during canonicalization: {c:?}")
}

View File

@ -238,6 +238,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
&& has_changed
&& !self.in_projection_eq_hack
&& !self.search_graph.in_cycle()
&& false
{
let (_orig_values, canonical_goal) = self.canonicalize_goal(goal);
let canonical_response =

View File

@ -155,10 +155,12 @@ fn pred_known_to_hold_modulo_regions<'tcx>(
predicate: pred.to_predicate(infcx.tcx),
};
let result = infcx.predicate_must_hold_modulo_regions(&obligation);
let result = infcx.evaluate_obligation_no_overflow(&obligation);
debug!(?result);
if result && has_non_region_infer {
if result.must_apply_modulo_regions() && !has_non_region_infer {
true
} else if result.may_apply() {
// Because of inference "guessing", selection can sometimes claim
// to succeed while the success requires a guess. To ensure
// this function's result remains infallible, we must confirm
@ -179,7 +181,7 @@ fn pred_known_to_hold_modulo_regions<'tcx>(
}
}
} else {
result
false
}
}

View File

@ -227,7 +227,7 @@
//! are no resume and abort terminators, and terminators that might unwind do not have any way to
//! indicate the unwind block.
//!
//! - [`Goto`], [`Return`], [`Unreachable`], [`Drop`](Drop()), and [`DropAndReplace`] have associated functions.
//! - [`Goto`], [`Return`], [`Unreachable`] and [`Drop`](Drop()) have associated functions.
//! - `match some_int_operand` becomes a `SwitchInt`. Each arm should be `literal => basic_block`
//! - The exception is the last arm, which must be `_ => basic_block` and corresponds to the
//! otherwise branch.
@ -259,7 +259,6 @@ define!("mir_return", fn Return() -> BasicBlock);
define!("mir_goto", fn Goto(destination: BasicBlock) -> BasicBlock);
define!("mir_unreachable", fn Unreachable() -> BasicBlock);
define!("mir_drop", fn Drop<T>(place: T, goto: BasicBlock));
define!("mir_drop_and_replace", fn DropAndReplace<T>(place: T, value: T, goto: BasicBlock));
define!("mir_call", fn Call<T>(place: T, goto: BasicBlock, call: T));
define!("mir_storage_live", fn StorageLive<T>(local: T));
define!("mir_storage_dead", fn StorageDead<T>(local: T));

View File

@ -1721,6 +1721,15 @@ impl<'a> Builder<'a> {
cargo.env("RUSTC_VERBOSE", self.verbosity.to_string());
// Downstream forks of the Rust compiler might want to use a custom libc to add support for
// targets that are not yet available upstream. Adding a patch to replace libc with a
// custom one would cause compilation errors though, because Cargo would interpret the
// custom libc as part of the workspace, and apply the check-cfg lints on it.
//
// The libc build script emits check-cfg flags only when this environment variable is set,
// so this line allows the use of custom libcs.
cargo.env("LIBC_CHECK_CFG", "1");
if source_type == SourceType::InTree {
let mut lint_flags = Vec::new();
// When extending this list, add the new lints to the RUSTFLAGS of the

View File

@ -299,10 +299,6 @@ fn check_terminator<'tcx>(
| TerminatorKind::Unreachable => Ok(()),
TerminatorKind::Drop { place, .. } => check_place(tcx, *place, span, body),
TerminatorKind::DropAndReplace { place, value, .. } => {
check_place(tcx, *place, span, body)?;
check_operand(tcx, value, span, body)
},
TerminatorKind::SwitchInt { discr, targets: _ } => check_operand(tcx, discr, span, body),

View File

@ -31,7 +31,7 @@ function isNumeric(s) {
}
function parseOptions(args) {
var opts = {
const opts = {
"doc_folder": "",
"tests_folder": "",
"files": [],
@ -42,7 +42,7 @@ function parseOptions(args) {
"executable_path": null,
"no_sandbox": false,
};
var correspondances = {
const correspondances = {
"--doc-folder": "doc_folder",
"--tests-folder": "tests_folder",
"--debug": "debug",
@ -52,39 +52,41 @@ function parseOptions(args) {
"--no-sandbox": "no_sandbox",
};
for (var i = 0; i < args.length; ++i) {
if (args[i] === "--doc-folder"
|| args[i] === "--tests-folder"
|| args[i] === "--file"
|| args[i] === "--jobs"
|| args[i] === "--executable-path") {
for (let i = 0; i < args.length; ++i) {
const arg = args[i];
if (arg === "--doc-folder"
|| arg === "--tests-folder"
|| arg === "--file"
|| arg === "--jobs"
|| arg === "--executable-path") {
i += 1;
if (i >= args.length) {
console.log("Missing argument after `" + args[i - 1] + "` option.");
console.log("Missing argument after `" + arg + "` option.");
return null;
}
if (args[i - 1] === "--jobs") {
if (!isNumeric(args[i])) {
const arg_value = args[i];
if (arg === "--jobs") {
if (!isNumeric(arg_value)) {
console.log(
"`--jobs` option expects a positive number, found `" + args[i] + "`");
"`--jobs` option expects a positive number, found `" + arg_value + "`");
return null;
}
opts["jobs"] = parseInt(args[i]);
} else if (args[i - 1] !== "--file") {
opts[correspondances[args[i - 1]]] = args[i];
opts["jobs"] = parseInt(arg_value);
} else if (arg !== "--file") {
opts[correspondances[arg]] = arg_value;
} else {
opts["files"].push(args[i]);
opts["files"].push(arg_value);
}
} else if (args[i] === "--help") {
} else if (arg === "--help") {
showHelp();
process.exit(0);
} else if (args[i] === "--no-sandbox") {
} else if (arg === "--no-sandbox") {
console.log("`--no-sandbox` is being used. Be very careful!");
opts[correspondances[args[i]]] = true;
} else if (correspondances[args[i]]) {
opts[correspondances[args[i]]] = true;
opts[correspondances[arg]] = true;
} else if (correspondances[arg]) {
opts[correspondances[arg]] = true;
} else {
console.log("Unknown option `" + args[i] + "`.");
console.log("Unknown option `" + arg + "`.");
console.log("Use `--help` to see the list of options");
return null;
}
@ -186,7 +188,7 @@ function createEmptyResults() {
}
async function main(argv) {
let opts = parseOptions(argv.slice(2));
const opts = parseOptions(argv.slice(2));
if (opts === null) {
process.exit(1);
}

View File

@ -4,10 +4,11 @@ fn drop_first(_1: WriteOnDrop<'_>, _2: WriteOnDrop<'_>) -> () {
let mut _0: (); // return place in scope 0 at $DIR/terminators.rs:+0:59: +0:59
bb0: {
replace(_1 <- move _2) -> bb1; // scope 0 at $DIR/terminators.rs:+3:13: +3:49
drop(_1) -> bb1; // scope 0 at $DIR/terminators.rs:+3:13: +3:30
}
bb1: {
return; // scope 0 at $DIR/terminators.rs:+7:13: +7:21
_1 = move _2; // scope 0 at $DIR/terminators.rs:+7:13: +7:24
return; // scope 0 at $DIR/terminators.rs:+8:13: +8:21
}
}

View File

@ -48,10 +48,11 @@ impl<'a> Drop for WriteOnDrop<'a> {
fn drop_first<'a>(a: WriteOnDrop<'a>, b: WriteOnDrop<'a>) {
mir!(
{
DropAndReplace(a, Move(b), retblock)
Drop(a, retblock)
}
retblock = {
a = Move(b);
Return()
}
)

View File

@ -0,0 +1,39 @@
// check-pass
// compile-flags: -Ztrait-solver=next
trait Mirror {
type Item;
}
struct Wrapper<T>(T);
impl<T> Mirror for Wrapper<T> {
type Item = T;
}
fn mirror<T>()
where
Wrapper<T>: Mirror<Item = i32>,
{
}
fn main() {
mirror::<_ /* ?0 */>();
// Solving `<Wrapper<?0> as Mirror>::Item = i32`
// First, we replace the term with a fresh infer var:
// `<Wrapper<?0> as Mirror>::Item = ?1`
// We select the impl candidate on line #6, which leads us to learn that
// `?0 == ?1`.
// That should be reflected in our canonical response, which should have
// `^0 = ^0, ^1 = ^0`
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// !! We used to return a totally unconstrained response here :< !!
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Then, during the "equate term" part of the projection solving, we
// instantiate the response from the unconstrained projection predicate,
// and equate `?0 == i32`.
}

View File

@ -0,0 +1,6 @@
// check-pass
// compile-flags: -Ztrait-solver=next
fn main() {
let x: Box<dyn Iterator<Item = ()>> = Box::new(std::iter::empty());
}

View File

@ -21,15 +21,15 @@ union U24<T> { // OK
}
union U3 {
a: String, //~ ERROR unions cannot contain fields that may need dropping
a: String, //~ ERROR field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
}
union U32 { // field that does not drop but is not `Copy`, either
a: std::cell::RefCell<i32>, //~ ERROR unions cannot contain fields that may need dropping
a: std::cell::RefCell<i32>, //~ ERROR field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
}
union U4<T> {
a: T, //~ ERROR unions cannot contain fields that may need dropping
a: T, //~ ERROR field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
}
union U5 { // Having a drop impl is OK
@ -41,11 +41,11 @@ impl Drop for U5 {
}
union U5Nested { // a nested union that drops is NOT OK
nest: U5, //~ ERROR unions cannot contain fields that may need dropping
nest: U5, //~ ERROR field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
}
union U5Nested2 { // for now we don't special-case empty arrays
nest: [U5; 0], //~ ERROR unions cannot contain fields that may need dropping
nest: [U5; 0], //~ ERROR field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
}
union U6 { // OK

View File

@ -1,59 +1,59 @@
error[E0740]: unions cannot contain fields that may need dropping
error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
--> $DIR/field_checks.rs:24:5
|
LL | a: String,
| ^^^^^^^^^
|
= note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
= note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
help: wrap the field type in `ManuallyDrop<...>`
|
LL | a: std::mem::ManuallyDrop<String>,
| +++++++++++++++++++++++ +
error[E0740]: unions cannot contain fields that may need dropping
error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
--> $DIR/field_checks.rs:28:5
|
LL | a: std::cell::RefCell<i32>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
= note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
help: wrap the field type in `ManuallyDrop<...>`
|
LL | a: std::mem::ManuallyDrop<std::cell::RefCell<i32>>,
| +++++++++++++++++++++++ +
error[E0740]: unions cannot contain fields that may need dropping
error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
--> $DIR/field_checks.rs:32:5
|
LL | a: T,
| ^^^^
|
= note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
= note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
help: wrap the field type in `ManuallyDrop<...>`
|
LL | a: std::mem::ManuallyDrop<T>,
| +++++++++++++++++++++++ +
error[E0740]: unions cannot contain fields that may need dropping
error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
--> $DIR/field_checks.rs:44:5
|
LL | nest: U5,
| ^^^^^^^^
|
= note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
= note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
help: wrap the field type in `ManuallyDrop<...>`
|
LL | nest: std::mem::ManuallyDrop<U5>,
| +++++++++++++++++++++++ +
error[E0740]: unions cannot contain fields that may need dropping
error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
--> $DIR/field_checks.rs:48:5
|
LL | nest: [U5; 0],
| ^^^^^^^^^^^^^
|
= note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
= note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
help: wrap the field type in `ManuallyDrop<...>`
|
LL | nest: std::mem::ManuallyDrop<[U5; 0]>,
| +++++++++++++++++++++++ +

View File

@ -1,5 +1,5 @@
union Test {
a: A, //~ ERROR unions cannot contain fields that may need dropping
a: A, //~ ERROR field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
b: B
}

View File

@ -1,11 +1,11 @@
error[E0740]: unions cannot contain fields that may need dropping
error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
--> $DIR/issue-41073.rs:2:5
|
LL | a: A,
| ^^^^
|
= note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
= note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
help: wrap the field type in `ManuallyDrop<...>`
|
LL | a: std::mem::ManuallyDrop<A>,
| +++++++++++++++++++++++ +

View File

@ -1,35 +1,35 @@
error[E0740]: unions cannot contain fields that may need dropping
error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
--> $DIR/union-with-drop-fields.rs:11:5
|
LL | a: String,
| ^^^^^^^^^
|
= note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
= note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
help: wrap the field type in `ManuallyDrop<...>`
|
LL | a: std::mem::ManuallyDrop<String>,
| +++++++++++++++++++++++ +
error[E0740]: unions cannot contain fields that may need dropping
error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
--> $DIR/union-with-drop-fields.rs:19:5
|
LL | a: S,
| ^^^^
|
= note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
= note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
help: wrap the field type in `ManuallyDrop<...>`
|
LL | a: std::mem::ManuallyDrop<S>,
| +++++++++++++++++++++++ +
error[E0740]: unions cannot contain fields that may need dropping
error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
--> $DIR/union-with-drop-fields.rs:24:5
|
LL | a: T,
| ^^^^
|
= note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
= note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
help: wrap the field type in `ManuallyDrop<...>`
|
LL | a: std::mem::ManuallyDrop<T>,
| +++++++++++++++++++++++ +

View File

@ -8,7 +8,7 @@ union U {
}
union W {
a: String, //~ ERROR unions cannot contain fields that may need dropping
a: String, //~ ERROR field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
b: String, // OK, only one field is reported
}
@ -16,12 +16,12 @@ struct S(String);
// `S` doesn't implement `Drop` trait, but still has non-trivial destructor
union Y {
a: S, //~ ERROR unions cannot contain fields that may need dropping
a: S, //~ ERROR field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
}
// We don't know if `T` is trivially-destructable or not until trans
union J<T> {
a: T, //~ ERROR unions cannot contain fields that may need dropping
a: T, //~ ERROR field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
}
union H<T: Copy> {

View File

@ -1,35 +1,35 @@
error[E0740]: unions cannot contain fields that may need dropping
error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
--> $DIR/union-with-drop-fields.rs:11:5
|
LL | a: String,
| ^^^^^^^^^
|
= note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
= note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
help: wrap the field type in `ManuallyDrop<...>`
|
LL | a: std::mem::ManuallyDrop<String>,
| +++++++++++++++++++++++ +
error[E0740]: unions cannot contain fields that may need dropping
error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
--> $DIR/union-with-drop-fields.rs:19:5
|
LL | a: S,
| ^^^^
|
= note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
= note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
help: wrap the field type in `ManuallyDrop<...>`
|
LL | a: std::mem::ManuallyDrop<S>,
| +++++++++++++++++++++++ +
error[E0740]: unions cannot contain fields that may need dropping
error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
--> $DIR/union-with-drop-fields.rs:24:5
|
LL | a: T,
| ^^^^
|
= note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
= note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
help: wrap the field type in `ManuallyDrop<...>`
|
LL | a: std::mem::ManuallyDrop<T>,
| +++++++++++++++++++++++ +

View File

@ -0,0 +1,8 @@
// Unresolved fields are not copy, but also shouldn't report an extra E0740.
pub union Foo {
x: *const Missing,
//~^ ERROR cannot find type `Missing` in this scope
}
fn main() {}

View File

@ -0,0 +1,9 @@
error[E0412]: cannot find type `Missing` in this scope
--> $DIR/unresolved-field-isnt-copy.rs:4:15
|
LL | x: *const Missing,
| ^^^^^^^ not found in this scope
error: aborting due to previous error
For more information about this error, try `rustc --explain E0412`.